From 55f4f2ab44bf6bf098b0b697d8ad30692794cd8f Mon Sep 17 00:00:00 2001 From: Yasuyuki Tanaka Date: Mon, 26 Mar 2018 20:51:02 +0200 Subject: [PATCH 001/485] 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/485] 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 d0aea6d0a1aef6d806bd512b992188e7b54d51d0 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Thu, 5 Apr 2018 21:40:16 +0200 Subject: [PATCH 003/485] sicslowpan: removing unused option SICSLOWPAN_USE_FIXED_HDRLEN --- os/net/ipv6/sicslowpan.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/os/net/ipv6/sicslowpan.c b/os/net/ipv6/sicslowpan.c index 4708acca7..688a45a6b 100644 --- a/os/net/ipv6/sicslowpan.c +++ b/os/net/ipv6/sicslowpan.c @@ -140,9 +140,7 @@ #endif /* SICSLOWPAN_CONF_MAC_MAX_PAYLOAD */ /** \brief Fixed size of a frame header. This value is - * used in case framer returns an error or if SICSLOWPAN_USE_FIXED_HDRLEN - * is defined. - */ + * used in case framer returns an error */ #ifndef SICSLOWPAN_FIXED_HDRLEN #define SICSLOWPAN_FIXED_HDRLEN 21 #endif @@ -1528,21 +1526,18 @@ output(const linkaddr_t *localdest) #if SICSLOWPAN_COMPRESSION >= SICSLOWPAN_COMPRESSION_IPHC compress_hdr_iphc(&dest); #endif /* SICSLOWPAN_COMPRESSION >= SICSLOWPAN_COMPRESSION_IPHC */ - LOG_INFO("output: header of len %d\n", packetbuf_hdr_len); + + LOG_INFO("output: header len %d -> %d\n", uncomp_hdr_len, 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) { From bf3d93decc10db764f801f299e032548b87924af Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Thu, 5 Apr 2018 21:42:37 +0200 Subject: [PATCH 004/485] sicslowpan: rename SICSLOWPAN_FIXED_HDRLEN to MAC_MAX_HEADER --- os/net/ipv6/sicslowpan.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/os/net/ipv6/sicslowpan.c b/os/net/ipv6/sicslowpan.c index 688a45a6b..b2e6fffba 100644 --- a/os/net/ipv6/sicslowpan.c +++ b/os/net/ipv6/sicslowpan.c @@ -139,11 +139,13 @@ #define MAC_MAX_PAYLOAD (127 - 2) #endif /* SICSLOWPAN_CONF_MAC_MAX_PAYLOAD */ -/** \brief Fixed size of a frame header. This value is +/** \brief Maximum size of a frame header. This value is * used in case framer returns an error */ -#ifndef SICSLOWPAN_FIXED_HDRLEN -#define SICSLOWPAN_FIXED_HDRLEN 21 -#endif +#ifdef SICSLOWPAN_CONF_MAC_MAX_HEADER +#define MAC_MAX_HEADER SICSLOWPAN_CONF_MAC_MAX_HEADER +#else /* SICSLOWPAN_CONF_MAC_MAX_HEADER */ +#define MAC_MAX_HEADER 21 +#endif /* SICSLOWPAN_CONF_MAC_MAX_HEADER */ /* set this to zero if not compressing EXT_HDR - for backwards compatibility */ #ifdef SICSLOWPAN_CONF_COMPRESS_EXT_HDR @@ -1536,7 +1538,7 @@ output(const linkaddr_t *localdest) framer_hdrlen = NETSTACK_FRAMER.length(); if(framer_hdrlen < 0) { /* Framing failed, we assume the maximum header length */ - framer_hdrlen = SICSLOWPAN_FIXED_HDRLEN; + framer_hdrlen = MAC_MAX_HEADER; } max_payload = MAC_MAX_PAYLOAD - framer_hdrlen; From 6c309825f99e8dc2b1ffb5b93ca29329e962c7a0 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Thu, 5 Apr 2018 23:39:44 +0200 Subject: [PATCH 005/485] sicslowpan: rework fragment output. Minimizes #frags. Fixes early #frag estimate. Clearer logs. --- os/net/ipv6/sicslowpan.c | 178 ++++++++++++++++++++++----------------- 1 file changed, 101 insertions(+), 77 deletions(-) diff --git a/os/net/ipv6/sicslowpan.c b/os/net/ipv6/sicslowpan.c index b2e6fffba..4db73db76 100644 --- a/os/net/ipv6/sicslowpan.c +++ b/os/net/ipv6/sicslowpan.c @@ -1464,6 +1464,46 @@ send_packet(linkaddr_t *dest) watchdog_periodic(); } /*--------------------------------------------------------------------*/ +/** + * \brief This function is called by the 6lowpan code to copy a fragment's + * payload from uIP and send it down the stack.. + * \param uip_offset the offset in the uIP buffer where to copy the payload from + * \param dest the link layer destination address of the packet + * \return 1 if success, 0 otherwise + */ +static int +fragment_copy_payload_and_send(uint16_t uip_offset, linkaddr_t *dest) { + struct queuebuf *q; + + /* Now copy fragment payload from uip_buf */ + memcpy(packetbuf_ptr + packetbuf_hdr_len, + (uint8_t *)UIP_IP_BUF + uip_offset, packetbuf_payload_len); + packetbuf_set_datalen(packetbuf_payload_len + packetbuf_hdr_len); + + /* Backup packetbuf to queuebuf. Enables preserving attributes for all framgnets */ + q = queuebuf_new_from_packetbuf(); + if(q == NULL) { + LOG_WARN("output: could not allocate queuebuf, dropping fragment\n"); + return 0; + } + + /* Send fragment */ + send_packet(dest); + + /* Restore packetbuf from queuebuf */ + queuebuf_to_packetbuf(q); + queuebuf_free(q); + + /* Check tx result. */ + if((last_tx_status == MAC_TX_COLLISION) || + (last_tx_status == MAC_TX_ERR) || + (last_tx_status == MAC_TX_ERR_FATAL)) { + LOG_ERR("output: error in fragment tx, dropping subsequent fragments.\n"); + return 0; + } + return 1; +} +/*--------------------------------------------------------------------*/ /** \brief Take an IP packet and format it to be sent on an 802.15.4 * network using 6lowpan. * \param localdest The MAC address of the destination @@ -1507,7 +1547,7 @@ output(const linkaddr_t *localdest) linkaddr_copy(&dest, localdest); } - LOG_INFO("output: sending packet len %d\n", uip_len); + LOG_INFO("output: sending packet with len %d\n", uip_len); /* copy over the retransmission count from uipbuf attributes */ packetbuf_set_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS, @@ -1546,116 +1586,100 @@ output(const linkaddr_t *localdest) #if SICSLOWPAN_CONF_FRAG /* Number of bytes processed. */ uint16_t processed_ip_out_len; - - struct queuebuf *q; uint16_t frag_tag; + int curr_frag = 0; /* * The outbound IPv6 packet is too large to fit into a single 15.4 * packet, so we fragment it into multiple packets and send them. - * The first fragment contains frag1 dispatch, then - * IPv6/IPHC/HC_UDP dispatchs/headers. - * The following fragments contain only the fragn dispatch. + * The first fragment contains frag1 dispatch, then IPv6/IPHC/HC_UDP + * dispatchs/headers and IPv6 payload (with len multiple of 8 bytes). + * The subsequent fragments contain the FRAGN dispatch and more of the + * IPv6 payload (still multiple of 8 bytes, except for the last fragment) */ - int estimated_fragments = ((int)uip_len) / (max_payload - SICSLOWPAN_FRAGN_HDR_LEN) + 1; + /* Total IPv6 payload */ + int total_payload = (uip_len - uncomp_hdr_len); + /* IPv6 payload that goes to first fragment */ + int frag1_payload = (max_payload - packetbuf_hdr_len - SICSLOWPAN_FRAG1_HDR_LEN) & 0xfffffff8; + /* max IPv6 payload in each FRAGN. Must be multiple of 8 bytes */ + int fragn_max_payload = (max_payload - SICSLOWPAN_FRAGN_HDR_LEN) & 0xfffffff8; + /* max IPv6 payload in the last fragment. Needs not be multiple of 8 bytes */ + int last_fragn_max_payload = max_payload - SICSLOWPAN_FRAGN_HDR_LEN; + /* IPv6 payload that goes to non-first and non-last fragments */ + int middle_fragn_total_payload = MAX(total_payload - frag1_payload - last_fragn_max_payload, 0); + /* Ceiling of: 2 + middle_fragn_total_payload / fragn_max_payload */ + int fragment_count = 2 + + 1 + (middle_fragn_total_payload - 1) / fragn_max_payload; + 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) { - LOG_WARN("Dropping packet, not enough free bufs\n"); + LOG_INFO("output: fragmentation required. uip_len: %d (%d + %d), MAC max payload %d, fragments: %d, free bufs: %d\n", + uip_len, uncomp_hdr_len, uip_len-uncomp_hdr_len, max_payload, fragment_count, freebuf); + + if(freebuf < fragment_count) { + LOG_WARN("output: dropping packet, not enough free bufs\n"); return 0; } - LOG_INFO("Fragmentation sending packet len %d\n", uip_len); - - /* Create 1st Fragment */ - LOG_INFO("output: 1st fragment "); - - /* Reset last tx status to ok in case the fragment transmissions are deferred */ + /* Reset last tx status -- MAC layers most often call packet_sent asynchrously */ last_tx_status = MAC_TX_OK; + /* Update fragment tag */ + frag_tag = my_tag++; - /* move IPHC/IPv6 header */ + /* Move IPHC/IPv6 header to make room for FRAG1 header */ memmove(packetbuf_ptr + SICSLOWPAN_FRAG1_HDR_LEN, packetbuf_ptr, packetbuf_hdr_len); + packetbuf_hdr_len += SICSLOWPAN_FRAG1_HDR_LEN; - /* - * FRAG1 dispatch + header - * Note that the length is in units of 8 bytes - */ + /* Set FRAG1 header */ SET16(PACKETBUF_FRAG_PTR, PACKETBUF_FRAG_DISPATCH_SIZE, ((SICSLOWPAN_DISPATCH_FRAG1 << 8) | uip_len)); - frag_tag = my_tag++; SET16(PACKETBUF_FRAG_PTR, PACKETBUF_FRAG_TAG, frag_tag); - /* Copy payload and send */ - packetbuf_hdr_len += SICSLOWPAN_FRAG1_HDR_LEN; - packetbuf_payload_len = (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); - packetbuf_set_datalen(packetbuf_payload_len + packetbuf_hdr_len); - q = queuebuf_new_from_packetbuf(); - if(q == NULL) { - LOG_WARN("could not allocate queuebuf for first fragment, dropping packet\n"); - return 0; - } - send_packet(&dest); - queuebuf_to_packetbuf(q); - queuebuf_free(q); - q = NULL; - - /* Check tx result. */ - if((last_tx_status == MAC_TX_COLLISION) || - (last_tx_status == MAC_TX_ERR) || - (last_tx_status == MAC_TX_ERR_FATAL)) { - LOG_ERR("error in fragment tx, dropping subsequent fragments.\n"); + /* Set frag1 payload len. Was already caulcated earlier as frag1_payload */ + packetbuf_payload_len = frag1_payload; + /* Copy payload from uIP and send fragment */ + /* Send fragment */ + LOG_INFO("output: fragment %d/%d (tag %d, IPv6 payload len %d)\n", + curr_frag + 1, fragment_count, + frag_tag, packetbuf_payload_len); + if(fragment_copy_payload_and_send(uncomp_hdr_len, &dest) == 0) { return 0; } - /* set processed_ip_out_len to what we already sent from the IP payload*/ - processed_ip_out_len = packetbuf_payload_len + uncomp_hdr_len; + /* Now prepare for subsequent fragments. */ - /* - * Create following fragments - * Datagram tag is already in the buffer, we need to set the - * FRAGN dispatch and for each fragment, the offset - */ + /* FRAGN header: tag was already set at FRAG1. Now set dispatch for all FRAGN */ packetbuf_hdr_len = SICSLOWPAN_FRAGN_HDR_LEN; -/* PACKETBUF_FRAG_BUF->dispatch_size = */ -/* 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; + + /* Keep track of the total length of data sent */ + processed_ip_out_len = uncomp_hdr_len + packetbuf_payload_len; + + /* Create and send subsequent fragments. */ while(processed_ip_out_len < uip_len) { - LOG_INFO("output: fragment "); + curr_frag++; + /* FRAGN header: set offset for this fragment */ PACKETBUF_FRAG_PTR[PACKETBUF_FRAG_OFFSET] = processed_ip_out_len >> 3; - /* Copy payload and send */ - if(uip_len - processed_ip_out_len < packetbuf_payload_len) { + /* Calculate fragment len */ + if(uip_len - processed_ip_out_len > last_fragn_max_payload) { + /* Not last fragment, send max FRAGN payload */ + packetbuf_payload_len = fragn_max_payload; + } else { /* last fragment */ packetbuf_payload_len = uip_len - processed_ip_out_len; } - LOG_INFO_("(offset %d, len %d, tag %d)\n", - processed_ip_out_len >> 3, packetbuf_payload_len, frag_tag); - memcpy(packetbuf_ptr + packetbuf_hdr_len, - (uint8_t *)UIP_IP_BUF + processed_ip_out_len, packetbuf_payload_len); - packetbuf_set_datalen(packetbuf_payload_len + packetbuf_hdr_len); - q = queuebuf_new_from_packetbuf(); - if(q == NULL) { - LOG_WARN("could not allocate queuebuf, dropping fragment\n"); - return 0; - } - send_packet(&dest); - queuebuf_to_packetbuf(q); - queuebuf_free(q); - q = NULL; - processed_ip_out_len += packetbuf_payload_len; - /* Check tx result. */ - if((last_tx_status == MAC_TX_COLLISION) || - (last_tx_status == MAC_TX_ERR) || - (last_tx_status == MAC_TX_ERR_FATAL)) { - LOG_ERR("error in fragment tx, dropping subsequent fragments.\n"); + /* Copy payload from uIP and send fragment */ + /* Send fragment */ + LOG_INFO("output: fragment %d/%d (tag %d, IPv6 payload len %d, offset %d)\n", + curr_frag + 1, fragment_count, + frag_tag, packetbuf_payload_len, processed_ip_out_len); + if(fragment_copy_payload_and_send(processed_ip_out_len, &dest) == 0) { return 0; } + + processed_ip_out_len += packetbuf_payload_len; } #else /* SICSLOWPAN_CONF_FRAG */ LOG_ERR("output: Packet too large to be sent without fragmentation support; dropping packet\n"); From b10274d042de04f46c968999f12257dcc5c44529 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 6 Apr 2018 02:40:32 -0700 Subject: [PATCH 006/485] sicslowpan: neater logs --- os/net/ipv6/sicslowpan.c | 145 ++++++++++++++++++++------------------- 1 file changed, 74 insertions(+), 71 deletions(-) diff --git a/os/net/ipv6/sicslowpan.c b/os/net/ipv6/sicslowpan.c index 4db73db76..8768f4576 100644 --- a/os/net/ipv6/sicslowpan.c +++ b/os/net/ipv6/sicslowpan.c @@ -330,8 +330,6 @@ store_fragment(uint8_t index, uint8_t offset) frag_buf[i].index = index; memcpy(frag_buf[i].data, packetbuf_ptr + packetbuf_hdr_len, packetbuf_datalen() - packetbuf_hdr_len); - - LOG_INFO("Fragsize: %d\n", frag_buf[i].len); /* return the length of the stored fragment */ return frag_buf[i].len; } @@ -365,7 +363,7 @@ add_fragment(uint16_t tag, uint16_t frag_size, uint8_t offset) } if(found < 0) { - LOG_WARN("*** Failed to store new fragment session - tag: %d\n", tag); + LOG_WARN("reassembly: failed to store new fragment session - tag: %d\n", tag); return -1; } @@ -392,7 +390,7 @@ add_fragment(uint16_t tag, uint16_t frag_size, uint8_t offset) if(found < 0) { /* no entry found for storing the new fragment */ - LOG_WARN("*** Failed to store N-fragment - could not find session - tag: %d offset: %d\n", tag, offset); + LOG_WARN("reassembly: failed to store N-fragment - could not find session - tag: %d offset: %d\n", tag, offset); return -1; } @@ -407,7 +405,7 @@ add_fragment(uint16_t tag, uint16_t frag_size, uint8_t offset) } else { /* should we also clear all fragments since we failed to store this fragment? */ - LOG_WARN("*** Failed to store fragment - packet reassembly will fail tag:%d l\n", frag_info[i].tag); + LOG_WARN("reassembly: failed to store fragment - packet reassembly will fail tag:%d l\n", frag_info[i].tag); return -1; } } @@ -604,7 +602,7 @@ uncompress_addr(uip_ipaddr_t *ipaddr, uint8_t const prefix[], prefcount = prefcount == 15 ? 16 : prefcount; postcount = postcount == 15 ? 16 : postcount; - LOG_INFO("Uncompressing %d + %d => ", prefcount, postcount); + LOG_DBG("uncompression: address %d %d", prefcount, postcount); if(prefcount > 0) { memcpy(ipaddr, prefix, prefcount); @@ -625,8 +623,8 @@ uncompress_addr(uip_ipaddr_t *ipaddr, uint8_t const prefix[], uip_ds6_set_addr_iid(ipaddr, lladdr); } - LOG_INFO_6ADDR(ipaddr); - LOG_INFO_("\n"); + LOG_DBG_6ADDR(ipaddr); + LOG_DBG_("\n"); } /*--------------------------------------------------------------------*/ @@ -673,7 +671,7 @@ compress_hdr_iphc(linkaddr_t *link_destaddr) if(LOG_DBG_ENABLED) { uint16_t ndx; - LOG_DBG("before compression (%d): ", UIP_IP_BUF->len[1]); + LOG_DBG("compression: before (%d): ", UIP_IP_BUF->len[1]); for(ndx = 0; ndx < UIP_IP_BUF->len[1] + 40; ndx++) { uint8_t data = ((uint8_t *) (UIP_IP_BUF))[ndx]; LOG_DBG_("%02x", data); @@ -706,7 +704,7 @@ compress_hdr_iphc(linkaddr_t *link_destaddr) if(addr_context_lookup_by_prefix(&UIP_IP_BUF->destipaddr) != NULL || addr_context_lookup_by_prefix(&UIP_IP_BUF->srcipaddr) != NULL) { /* set context flag and increase hc06_ptr */ - LOG_INFO("IPHC: compressing dest or src ipaddr - setting CID\n"); + LOG_DBG("compression: dest or src ipaddr - setting CID\n"); iphc1 |= SICSLOWPAN_IPHC_CID; hc06_ptr++; } @@ -793,13 +791,13 @@ compress_hdr_iphc(linkaddr_t *link_destaddr) /* source address - cannot be multicast */ if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) { - LOG_INFO("IPHC: compressing unspecified - setting SAC\n"); + LOG_DBG("compression: addr unspecified - setting SAC\n"); iphc1 |= SICSLOWPAN_IPHC_SAC; iphc1 |= SICSLOWPAN_IPHC_SAM_00; } else if((context = addr_context_lookup_by_prefix(&UIP_IP_BUF->srcipaddr)) != NULL) { /* elide the prefix - indicate by CID and set context + SAC */ - LOG_INFO("IPHC: compressing src with context - setting CID & SAC ctx: %d\n", + LOG_DBG("compression: src with context - setting CID & SAC ctx: %d\n", context->number); iphc1 |= SICSLOWPAN_IPHC_CID | SICSLOWPAN_IPHC_SAC; PACKETBUF_IPHC_BUF[2] |= context->number << 4; @@ -882,9 +880,9 @@ compress_hdr_iphc(linkaddr_t *link_destaddr) next_nhc = hc06_ptr; /* here we set the next header is compressed. */ ext_hdr_len = 0; /* reserve the write place of this next header position */ - LOG_INFO("Compressing first header: %d\n", *next_hdr); + LOG_DBG("compression: first header: %d\n", *next_hdr); while(next_hdr != NULL && IS_COMPRESSABLE_PROTO(*next_hdr)) { - LOG_INFO("Compressing next header: %d\n", *next_hdr); + LOG_DBG("compression: next header: %d\n", *next_hdr); int proto = -1; /* used for the specific ext hdr */ /* UDP and EXT header compression */ switch(*next_hdr) { @@ -903,7 +901,7 @@ compress_hdr_iphc(linkaddr_t *link_destaddr) proto = proto == -1 ? SICSLOWPAN_NHC_ETX_HDR_DESTO : proto; /* Len is defined to be in octets from the length byte */ len = (ext_hdr->len << 3) + 8; - LOG_INFO("Handling next header: %d (len:%d)\n", *next_hdr, len); + LOG_DBG("compression: next header %d (len:%d)\n", *next_hdr, len); /* pick up the next header */ next_hdr = &ext_hdr->next; /* If the next header is not compressable we need to reserve the @@ -911,7 +909,7 @@ compress_hdr_iphc(linkaddr_t *link_destaddr) next not being elided in that case. */ if(!IS_COMPRESSABLE_PROTO(*next_hdr)) { hc06_ptr++; - LOG_INFO("Keeping the next header in this ext hdr: %d\n", + LOG_DBG("compression: keeping the next header in this ext hdr: %d\n", ext_hdr->next); } /* copy the ext-hdr into the hc06 buffer */ @@ -936,14 +934,14 @@ compress_hdr_iphc(linkaddr_t *link_destaddr) /* allocate a byte for the next header posision as UDP has no next */ hc06_ptr++; udp_buf = UIP_UDP_BUF(ext_hdr_len); - LOG_INFO("IPHC: Uncompressed UDP ports on send side: %x, %x\n", + LOG_DBG("compression: inlined UDP ports on send side: %x, %x\n", UIP_HTONS(udp_buf->srcport), UIP_HTONS(udp_buf->destport)); /* Mask out the last 4 bits can be used as a mask */ if(((UIP_HTONS(udp_buf->srcport) & 0xfff0) == SICSLOWPAN_UDP_4_BIT_PORT_MIN) && ((UIP_HTONS(udp_buf->destport) & 0xfff0) == SICSLOWPAN_UDP_4_BIT_PORT_MIN)) { /* 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"); + LOG_DBG("compression: remove 12 bits of both source & dest with prefix 0xFOB\n"); *hc06_ptr = (uint8_t)((UIP_HTONS(udp_buf->srcport) - SICSLOWPAN_UDP_4_BIT_PORT_MIN) << 4) + @@ -953,7 +951,7 @@ compress_hdr_iphc(linkaddr_t *link_destaddr) } else if((UIP_HTONS(udp_buf->destport) & 0xff00) == SICSLOWPAN_UDP_8_BIT_PORT_MIN) { /* 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"); + LOG_DBG("compression: leave source, remove 8 bits of dest with prefix 0xF0\n"); memcpy(hc06_ptr, &udp_buf->srcport, 2); *(hc06_ptr + 2) = (uint8_t)((UIP_HTONS(udp_buf->destport) - @@ -962,7 +960,7 @@ compress_hdr_iphc(linkaddr_t *link_destaddr) } else if((UIP_HTONS(udp_buf->srcport) & 0xff00) == SICSLOWPAN_UDP_8_BIT_PORT_MIN) { /* 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); + LOG_DBG("compression: remove 8 bits of source with prefix 0xF0, leave dest. hch: %i\n", *next_nhc); *hc06_ptr = (uint8_t)((UIP_HTONS(udp_buf->srcport) - SICSLOWPAN_UDP_8_BIT_PORT_MIN)); @@ -971,7 +969,7 @@ compress_hdr_iphc(linkaddr_t *link_destaddr) } else { /* we cannot compress. Copy uncompressed ports, full checksum */ *next_nhc = SICSLOWPAN_NHC_UDP_CS_P_00; - LOG_INFO("IPHC: cannot compress UDP headers\n"); + LOG_DBG("compression: cannot compress UDP headers\n"); memcpy(hc06_ptr, &udp_buf->srcport, 4); hc06_ptr += 4; } @@ -983,13 +981,13 @@ compress_hdr_iphc(linkaddr_t *link_destaddr) next_hdr = NULL; break; default: - LOG_ERR("IPHC: could not handle compression of header"); + LOG_ERR("compression: could not handle compression of header"); } } if(next_hdr != NULL) { /* Last header could not be compressed - we assume that this is then OK!*/ /* as the last EXT_HDR should be "uncompressed" and have the next there */ - LOG_INFO("IPHC: last header could is not compressed: %d\n", *next_hdr); + LOG_DBG("compression: last header could is not compressed: %d\n", *next_hdr); } /* before the packetbuf_hdr_len operation */ PACKETBUF_IPHC_BUF[0] = iphc0; @@ -997,7 +995,7 @@ compress_hdr_iphc(linkaddr_t *link_destaddr) if(LOG_DBG_ENABLED) { uint16_t ndx; - LOG_DBG("after compression %d: ", (int)(hc06_ptr - packetbuf_ptr)); + LOG_DBG("compression: after (%d): ", (int)(hc06_ptr - packetbuf_ptr)); for(ndx = 0; ndx < hc06_ptr - packetbuf_ptr; ndx++) { uint8_t data = ((uint8_t *) packetbuf_ptr)[ndx]; LOG_DBG_("%02x", data); @@ -1042,7 +1040,7 @@ uncompress_hdr_iphc(uint8_t *buf, uint16_t ip_len) /* another if the CID flag is set */ if(iphc1 & SICSLOWPAN_IPHC_CID) { - LOG_INFO("IPHC: CID flag set - increase header with one\n"); + LOG_DBG("uncompression: CID flag set - increase header with one\n"); hc06_ptr++; } @@ -1090,7 +1088,7 @@ uncompress_hdr_iphc(uint8_t *buf, uint16_t ip_len) if((iphc0 & SICSLOWPAN_IPHC_NH_C) == 0) { /* Next header is carried inline */ SICSLOWPAN_IP_BUF(buf)->proto = *hc06_ptr; - LOG_INFO("IPHC: next header inline: %d\n", SICSLOWPAN_IP_BUF(buf)->proto); + LOG_DBG("uncompression: next header inline: %d\n", SICSLOWPAN_IP_BUF(buf)->proto); hc06_ptr += 1; } @@ -1114,7 +1112,7 @@ uncompress_hdr_iphc(uint8_t *buf, uint16_t ip_len) if (tmp != 0) { context = addr_context_lookup_by_number(sci); if(context == NULL) { - LOG_ERR("uncompress_hdr: error context not found\n"); + LOG_ERR("uncompression: error context not found\n"); return; } } @@ -1161,7 +1159,7 @@ uncompress_hdr_iphc(uint8_t *buf, uint16_t ip_len) /* all valid cases below need the context! */ if(context == NULL) { - LOG_ERR("uncompress_hdr: error context not found\n"); + LOG_ERR("uncompression: error context not found\n"); return; } uncompress_addr(&SICSLOWPAN_IP_BUF(buf)->destipaddr, context->prefix, @@ -1196,12 +1194,12 @@ uncompress_hdr_iphc(uint8_t *buf, uint16_t ip_len) if(!nh) { next = *hc06_ptr; hc06_ptr++; - LOG_INFO("Next header is not compressed... next: %d\n", next); + LOG_DBG("uncompression: next header is inlined. Next: %d\n", next); } len = *hc06_ptr; hc06_ptr++; - LOG_INFO("IPHC: Found extension-header id=%d next=%d len=%d\n", eid, next, len); + LOG_DBG("uncompression: found ext header id: %d next: %d len: %d\n", eid, next, len); switch(eid) { case SICSLOWPAN_NHC_ETX_HDR_HBHO: proto = UIP_PROTO_HBHO; @@ -1216,7 +1214,7 @@ uncompress_hdr_iphc(uint8_t *buf, uint16_t ip_len) proto = UIP_PROTO_DESTO; break; default: - LOG_INFO("IPHC: error unsupported extension-header\n"); + LOG_DBG("uncompression: error unsupported ext header\n"); return; } *last_nextheader = proto; @@ -1231,7 +1229,7 @@ uncompress_hdr_iphc(uint8_t *buf, uint16_t ip_len) ip_payload += (exthdr->len + 1) * 8; ext_hdr_len += (exthdr->len + 1) * 8; - LOG_INFO("Uncompressed EXT hdr: %d len:%d exhdrlen:%d (calc: %d)\n", + LOG_DBG("uncompression: %d len: %d exhdrlen: %d (calc: %d)\n", proto, len, exthdr->len, (exthdr->len + 1) * 8); } @@ -1242,13 +1240,13 @@ uncompress_hdr_iphc(uint8_t *buf, uint16_t ip_len) uint8_t checksum_compressed; *last_nextheader = UIP_PROTO_UDP; checksum_compressed = *hc06_ptr & SICSLOWPAN_NHC_UDP_CHECKSUMC; - LOG_INFO("IPHC: Incoming header value: %i\n", *hc06_ptr); + LOG_DBG("uncompression: incoming header value: %i\n", *hc06_ptr); switch(*hc06_ptr & SICSLOWPAN_NHC_UDP_CS_P_11) { case SICSLOWPAN_NHC_UDP_CS_P_00: /* 1 byte for NHC, 4 byte for ports, 2 bytes chksum */ memcpy(&udp_buf->srcport, hc06_ptr + 1, 2); memcpy(&udp_buf->destport, hc06_ptr + 3, 2); - LOG_INFO("IPHC: Uncompressed UDP ports (ptr+5): %x, %x\n", + LOG_DBG("uncompression: UDP ports (ptr+5): %x, %x\n", UIP_HTONS(udp_buf->srcport), UIP_HTONS(udp_buf->destport)); hc06_ptr += 5; @@ -1256,21 +1254,21 @@ uncompress_hdr_iphc(uint8_t *buf, uint16_t ip_len) case SICSLOWPAN_NHC_UDP_CS_P_01: /* 1 byte for NHC + source 16bit inline, dest = 0xF0 + 8 bit inline */ - LOG_INFO("IPHC: Decompressing destination\n"); + LOG_DBG("uncompression: destination address\n"); memcpy(&udp_buf->srcport, hc06_ptr + 1, 2); udp_buf->destport = UIP_HTONS(SICSLOWPAN_UDP_8_BIT_PORT_MIN + (*(hc06_ptr + 3))); - LOG_INFO("IPHC: Uncompressed UDP ports (ptr+4): %x, %x\n", + LOG_DBG("uncompression: UDP ports (ptr+4): %x, %x\n", UIP_HTONS(udp_buf->srcport), UIP_HTONS(udp_buf->destport)); hc06_ptr += 4; break; case SICSLOWPAN_NHC_UDP_CS_P_10: /* 1 byte for NHC + source = 0xF0 + 8bit inline, dest = 16 bit inline*/ - LOG_INFO("IPHC: Decompressing source\n"); + LOG_DBG("uncompression: source address\n"); udp_buf->srcport = UIP_HTONS(SICSLOWPAN_UDP_8_BIT_PORT_MIN + (*(hc06_ptr + 1))); memcpy(&udp_buf->destport, hc06_ptr + 2, 2); - LOG_INFO("IPHC: Uncompressed UDP ports (ptr+4): %x, %x\n", + LOG_DBG("uncompression: UDP ports (ptr+4): %x, %x\n", UIP_HTONS(udp_buf->srcport), UIP_HTONS(udp_buf->destport)); hc06_ptr += 4; break; @@ -1281,27 +1279,27 @@ uncompress_hdr_iphc(uint8_t *buf, uint16_t ip_len) (*(hc06_ptr + 1) >> 4)); udp_buf->destport = UIP_HTONS(SICSLOWPAN_UDP_4_BIT_PORT_MIN + ((*(hc06_ptr + 1)) & 0x0F)); - LOG_INFO("IPHC: Uncompressed UDP ports (ptr+2): %x, %x\n", + LOG_DBG("uncompression: UDP ports (ptr+2): %x, %x\n", UIP_HTONS(udp_buf->srcport), UIP_HTONS(udp_buf->destport)); hc06_ptr += 2; break; default: - LOG_INFO("sicslowpan uncompress_hdr: error unsupported UDP compression\n"); + LOG_DBG("uncompression: error unsupported UDP compression\n"); return; } if(!checksum_compressed) { /* has_checksum, default */ memcpy(&udp_buf->udpchksum, hc06_ptr, 2); hc06_ptr += 2; - LOG_INFO("IPHC: sicslowpan uncompress_hdr: checksum included\n"); + LOG_DBG("uncompression: checksum included\n"); } else { - LOG_INFO("IPHC: sicslowpan uncompress_hdr: checksum *NOT* included\n"); + LOG_DBG("uncompression: checksum *NOT* included\n"); } /* length field in UDP header (8 byte header + payload) */ udp_len = 8 + packetbuf_datalen() - (hc06_ptr - packetbuf_ptr); udp_buf->udplen = UIP_HTONS(ip_len == 0 ? udp_len : ip_len - UIP_IPH_LEN - ext_hdr_len); - LOG_INFO("Setting UDP length: %u (ext: %u) ip_len: %d udp_len:%d\n", + LOG_DBG("uncompression: UDP length: %u (ext: %u) ip_len: %d udp_len: %d\n", UIP_HTONS(udp_buf->udplen), ext_hdr_len, ip_len, udp_len); uncomp_hdr_len += UIP_UDPH_LEN; @@ -1312,7 +1310,7 @@ uncompress_hdr_iphc(uint8_t *buf, uint16_t ip_len) /* IP length field. */ if(ip_len == 0) { int len = packetbuf_datalen() - packetbuf_hdr_len + uncomp_hdr_len - UIP_IPH_LEN; - LOG_INFO("IP payload length: %d. %u - %u + %u - %u\n", len, + LOG_DBG("uncompression: IP payload length: %d. %u - %u + %u - %u\n", len, packetbuf_datalen(), packetbuf_hdr_len, uncomp_hdr_len, UIP_IPH_LEN); /* This is not a fragmented packet */ @@ -1518,6 +1516,7 @@ output(const linkaddr_t *localdest) { int framer_hdrlen; int max_payload; + int frag_needed; /* The MAC address of the destination of the packet */ linkaddr_t dest; @@ -1547,7 +1546,7 @@ output(const linkaddr_t *localdest) linkaddr_copy(&dest, localdest); } - LOG_INFO("output: sending packet with len %d\n", uip_len); + LOG_INFO("output: sending IPv6 packet with len %d\n", uip_len); /* copy over the retransmission count from uipbuf attributes */ packetbuf_set_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS, @@ -1569,8 +1568,6 @@ output(const linkaddr_t *localdest) compress_hdr_iphc(&dest); #endif /* SICSLOWPAN_COMPRESSION >= SICSLOWPAN_COMPRESSION_IPHC */ - LOG_INFO("output: header len %d -> %d\n", uncomp_hdr_len, 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. */ @@ -1582,7 +1579,13 @@ output(const linkaddr_t *localdest) } max_payload = MAC_MAX_PAYLOAD - framer_hdrlen; - if((int)uip_len - (int)uncomp_hdr_len > max_payload - (int)packetbuf_hdr_len) { + frag_needed = (int)uip_len - (int)uncomp_hdr_len + (int)packetbuf_hdr_len > max_payload; + LOG_INFO("output: header len %d -> %d, total len %d -> %d, MAC max payload %d, frag_needed %d\n", + uncomp_hdr_len, packetbuf_hdr_len, + uip_len, uip_len - uncomp_hdr_len + packetbuf_hdr_len, + max_payload, frag_needed); + + if(frag_needed) { #if SICSLOWPAN_CONF_FRAG /* Number of bytes processed. */ uint16_t processed_ip_out_len; @@ -1612,8 +1615,8 @@ output(const linkaddr_t *localdest) 1 + (middle_fragn_total_payload - 1) / fragn_max_payload; int freebuf = queuebuf_numfree() - 1; - LOG_INFO("output: fragmentation required. uip_len: %d (%d + %d), MAC max payload %d, fragments: %d, free bufs: %d\n", - uip_len, uncomp_hdr_len, uip_len-uncomp_hdr_len, max_payload, fragment_count, freebuf); + LOG_INFO("output: fragmentation needed, fragments: %d, free queuebufs: %d\n", + fragment_count, freebuf); if(freebuf < fragment_count) { LOG_WARN("output: dropping packet, not enough free bufs\n"); @@ -1638,7 +1641,7 @@ output(const linkaddr_t *localdest) packetbuf_payload_len = frag1_payload; /* Copy payload from uIP and send fragment */ /* Send fragment */ - LOG_INFO("output: fragment %d/%d (tag %d, IPv6 payload len %d)\n", + LOG_INFO("output: fragment %d/%d (tag %d, payload %d)\n", curr_frag + 1, fragment_count, frag_tag, packetbuf_payload_len); if(fragment_copy_payload_and_send(uncomp_hdr_len, &dest) == 0) { @@ -1672,7 +1675,7 @@ output(const linkaddr_t *localdest) /* Copy payload from uIP and send fragment */ /* Send fragment */ - LOG_INFO("output: fragment %d/%d (tag %d, IPv6 payload len %d, offset %d)\n", + LOG_INFO("output: fragment %d/%d (tag %d, payload %d, offset %d)\n", curr_frag + 1, fragment_count, frag_tag, packetbuf_payload_len, processed_ip_out_len); if(fragment_copy_payload_and_send(processed_ip_out_len, &dest) == 0) { @@ -1740,7 +1743,7 @@ input(void) packetbuf_ptr = packetbuf_dataptr(); if(packetbuf_datalen() == 0) { - LOG_WARN("empty packet\n"); + LOG_WARN("input: empty packet\n"); return; } @@ -1759,20 +1762,21 @@ input(void) */ switch((GET16(PACKETBUF_FRAG_PTR, PACKETBUF_FRAG_DISPATCH_SIZE) >> 8) & SICSLOWPAN_DISPATCH_FRAG_MASK) { case SICSLOWPAN_DISPATCH_FRAG1: - LOG_INFO("input: FRAG1 "); frag_offset = 0; frag_size = GET16(PACKETBUF_FRAG_PTR, PACKETBUF_FRAG_DISPATCH_SIZE) & 0x07ff; frag_tag = GET16(PACKETBUF_FRAG_PTR, PACKETBUF_FRAG_TAG); - LOG_INFO_ ("size %d, tag %d, offset %d)\n", - frag_size, frag_tag, frag_offset); packetbuf_hdr_len += SICSLOWPAN_FRAG1_HDR_LEN; first_fragment = 1; is_fragment = 1; + LOG_INFO("input: received first element of a fragmented packet (tag %d, len %d)\n", + frag_tag, frag_size); + /* Add the fragment to the fragmentation context */ frag_context = add_fragment(frag_tag, frag_size, frag_offset); if(frag_context == -1) { + LOG_ERR("input: failed to allocate new reassembly context\n"); return; } @@ -1784,24 +1788,17 @@ input(void) * set offset, tag, size * Offset is in units of 8 bytes */ - LOG_INFO("input: FRAGN "); frag_offset = PACKETBUF_FRAG_PTR[PACKETBUF_FRAG_OFFSET]; frag_tag = GET16(PACKETBUF_FRAG_PTR, PACKETBUF_FRAG_TAG); frag_size = GET16(PACKETBUF_FRAG_PTR, PACKETBUF_FRAG_DISPATCH_SIZE) & 0x07ff; - LOG_INFO_("size %d, tag %d, offset %d)\n", - frag_size, frag_tag, frag_offset); packetbuf_hdr_len += SICSLOWPAN_FRAGN_HDR_LEN; - /* If this is the last fragment, we may shave off any extrenous - bytes at the end. We must be liberal in what we accept. */ - LOG_INFO_("last_fragment?: packetbuf_payload_len %d frag_size %d\n", - packetbuf_datalen() - packetbuf_hdr_len, frag_size); - /* Add the fragment to the fragmentation context (this will also copy the payload) */ frag_context = add_fragment(frag_tag, frag_size, frag_offset); if(frag_context == -1) { + LOG_ERR("input: reassembly context not found (tag %d)\n", frag_tag); return; } @@ -1837,10 +1834,10 @@ input(void) /* Process next dispatch and headers */ if((PACKETBUF_6LO_PTR[PACKETBUF_6LO_DISPATCH] & SICSLOWPAN_DISPATCH_IPHC_MASK) == SICSLOWPAN_DISPATCH_IPHC) { - LOG_INFO("input: IPHC\n"); + LOG_DBG("uncompression: IPHC dispatch\n"); uncompress_hdr_iphc(buffer, frag_size); } else if(PACKETBUF_6LO_PTR[PACKETBUF_6LO_DISPATCH] == SICSLOWPAN_DISPATCH_IPV6) { - LOG_INFO("input: IPV6\n"); + LOG_DBG("uncompression: IPV6 dispatch\n"); packetbuf_hdr_len += SICSLOWPAN_IPV6_HDR_LEN; /* Put uncompressed IP header in sicslowpan_buf. */ @@ -1850,7 +1847,7 @@ input(void) packetbuf_hdr_len += UIP_IPH_LEN; uncomp_hdr_len += UIP_IPH_LEN; } else { - LOG_ERR("input: unknown dispatch: 0x%02x\n", + LOG_ERR("uncompression: unknown dispatch: 0x%02x\n", PACKETBUF_6LO_PTR[PACKETBUF_6LO_DISPATCH]); return; } @@ -1866,18 +1863,24 @@ input(void) * If this is a subsequent fragment, this is the contrary. */ if(packetbuf_datalen() < packetbuf_hdr_len) { - LOG_ERR("packet dropped due to header > total packet\n"); + LOG_ERR("input: packet dropped due to header > total packet\n"); return; } packetbuf_payload_len = packetbuf_datalen() - packetbuf_hdr_len; + if(is_fragment) { + LOG_INFO("input: fragment (tag %d, payload %d, offset %d)\n", + frag_tag, packetbuf_payload_len, frag_offset << 3); + } + + /* Sanity-check size of incoming packet to avoid buffer overflow */ { int req_size = UIP_LLH_LEN + uncomp_hdr_len + (uint16_t)(frag_offset << 3) + packetbuf_payload_len; if(req_size > sizeof(uip_buf)) { LOG_ERR( - "packet dropped, minimum required IP_BUF size: %d+%d+%d+%d=%d (current size: %u)\n", + "input: packet dropped, minimum required IP_BUF size: %d+%d+%d+%d=%d (current size: %u)\n", UIP_LLH_LEN, uncomp_hdr_len, (uint16_t)(frag_offset << 3), packetbuf_payload_len, req_size, (unsigned)sizeof(uip_buf)); return; @@ -1922,12 +1925,12 @@ input(void) #else uip_len = packetbuf_payload_len + uncomp_hdr_len; #endif /* SICSLOWPAN_CONF_FRAG */ - LOG_INFO("input: IP packet ready (length %d)\n", + LOG_INFO("input: received IPv6 packet with len %d\n", uip_len); if(LOG_DBG_ENABLED) { uint16_t ndx; - LOG_DBG("after decompression %u:", UIP_IP_BUF->len[1]); + LOG_DBG("uncompression: after (%u):", UIP_IP_BUF->len[1]); for (ndx = 0; ndx < UIP_IP_BUF->len[1] + 40; ndx++) { uint8_t data = ((uint8_t *) (UIP_IP_BUF))[ndx]; LOG_DBG_("%02x", data); From 07c3e411ea6e73ff050df8c2ec1124a240b892d9 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 6 Apr 2018 04:36:09 -0700 Subject: [PATCH 007/485] Fix typos in comments --- os/net/ipv6/sicslowpan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/os/net/ipv6/sicslowpan.c b/os/net/ipv6/sicslowpan.c index 8768f4576..d2ad63df4 100644 --- a/os/net/ipv6/sicslowpan.c +++ b/os/net/ipv6/sicslowpan.c @@ -977,7 +977,7 @@ compress_hdr_iphc(linkaddr_t *link_destaddr) memcpy(hc06_ptr, &udp_buf->udpchksum, 2); hc06_ptr += 2; uncomp_hdr_len += UIP_UDPH_LEN; - /* this is the final header... */ + /* this is the final header. */ next_hdr = NULL; break; default: @@ -1464,7 +1464,7 @@ send_packet(linkaddr_t *dest) /*--------------------------------------------------------------------*/ /** * \brief This function is called by the 6lowpan code to copy a fragment's - * payload from uIP and send it down the stack.. + * payload from uIP and send it down the stack. * \param uip_offset the offset in the uIP buffer where to copy the payload from * \param dest the link layer destination address of the packet * \return 1 if success, 0 otherwise From b45276775e6657d9201acb438294fadb2dc3d92a Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 6 Apr 2018 09:27:31 -0700 Subject: [PATCH 008/485] sicslowpan: fix compilation with fragmentation disabled --- os/net/ipv6/sicslowpan.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/os/net/ipv6/sicslowpan.c b/os/net/ipv6/sicslowpan.c index d2ad63df4..0fa7e26ce 100644 --- a/os/net/ipv6/sicslowpan.c +++ b/os/net/ipv6/sicslowpan.c @@ -1461,6 +1461,7 @@ send_packet(linkaddr_t *dest) watchdog know that we are still alive. */ watchdog_periodic(); } +#if SICSLOWPAN_CONF_FRAG /*--------------------------------------------------------------------*/ /** * \brief This function is called by the 6lowpan code to copy a fragment's @@ -1501,6 +1502,7 @@ fragment_copy_payload_and_send(uint16_t uip_offset, linkaddr_t *dest) { } return 1; } +#endif /* SICSLOWPAN_CONF_FRAG */ /*--------------------------------------------------------------------*/ /** \brief Take an IP packet and format it to be sent on an 802.15.4 * network using 6lowpan. @@ -1868,11 +1870,12 @@ input(void) } packetbuf_payload_len = packetbuf_datalen() - packetbuf_hdr_len; +#if SICSLOWPAN_CONF_FRAG if(is_fragment) { LOG_INFO("input: fragment (tag %d, payload %d, offset %d)\n", frag_tag, packetbuf_payload_len, frag_offset << 3); } - +#endif /*SICSLOWPAN_CONF_FRAG*/ /* Sanity-check size of incoming packet to avoid buffer overflow */ { From 826624c8dd5df2f0c4ae7f5ec3f46975238dfddf Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 6 Apr 2018 12:19:23 -0700 Subject: [PATCH 009/485] Added ping with 6lowpan fragmentation test --- arch/platform/cooja/contiki-conf.h | 5 + .../08-border-router-cooja-frag.csc | 252 ++++++++++++++++++ .../08-border-router-cooja-frag.sh | 9 + tests/17-tun-rpl-br/test-border-router.sh | 8 +- 4 files changed, 273 insertions(+), 1 deletion(-) create mode 100644 tests/17-tun-rpl-br/08-border-router-cooja-frag.csc create mode 100644 tests/17-tun-rpl-br/08-border-router-cooja-frag.sh diff --git a/arch/platform/cooja/contiki-conf.h b/arch/platform/cooja/contiki-conf.h index 75a37f866..cf7bdbbd3 100644 --- a/arch/platform/cooja/contiki-conf.h +++ b/arch/platform/cooja/contiki-conf.h @@ -91,6 +91,11 @@ #define NBR_TABLE_CONF_MAX_NEIGHBORS 300 #endif /* NBR_TABLE_CONF_MAX_NEIGHBORS */ +/* configure queues */ +#ifndef QUEUEBUF_CONF_NUM +#define QUEUEBUF_CONF_NUM 64 +#endif /* QUEUEBUF_CONF_NUM */ + #ifndef UIP_CONF_IPV6_QUEUE_PKT #define UIP_CONF_IPV6_QUEUE_PKT 1 #endif /* UIP_CONF_IPV6_QUEUE_PKT */ diff --git a/tests/17-tun-rpl-br/08-border-router-cooja-frag.csc b/tests/17-tun-rpl-br/08-border-router-cooja-frag.csc new file mode 100644 index 000000000..b0d95600a --- /dev/null +++ b/tests/17-tun-rpl-br/08-border-router-cooja-frag.csc @@ -0,0 +1,252 @@ + + + [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 + mtype295 + Cooja Mote Type #1 + [CONTIKI_DIR]/examples/rpl-border-router/border-router.c + make TARGET=cooja clean +make -j border-router.cooja TARGET=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.contikimote.ContikiMoteType + mtype686 + Cooja Mote Type #2 + [CONTIKI_DIR]/examples/hello-world/hello-world.c + make TARGET=cooja clean +make -j hello-world.cooja TARGET=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 + 54.36775767371176 + 24.409055040864118 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 1 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype295 + + + + org.contikios.cooja.interfaces.Position + 83.54989222799365 + 52.63050856506214 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 2 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype686 + + + + org.contikios.cooja.interfaces.Position + 108.91767775240822 + 78.59778809170032 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 3 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype686 + + + + org.contikios.cooja.interfaces.Position + 139.91021061864723 + 98.34190023350419 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 4 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype686 + + + + org.contikios.cooja.plugins.SimControl + 280 + 1 + 160 + 400 + 0 + + + org.contikios.cooja.plugins.Visualizer + + true + org.contikios.cooja.plugins.skins.UDGMVisualizerSkin + org.contikios.cooja.plugins.skins.IDVisualizerSkin + 1.9798610460263038 0.0 0.0 1.9798610460263038 -61.112037797038525 -1.2848438586294648 + + 400 + 4 + 400 + 1 + 1 + + + org.contikios.cooja.plugins.LogListener + + ID:4 + + + + 1404 + 2 + 240 + 400 + 160 + + + org.contikios.cooja.plugins.TimeLine + + 0 + 1 + 2 + 3 + + + + 500.0 + + 1804 + 6 + 166 + 0 + 753 + + + org.contikios.cooja.plugins.Notes + + Enter notes here + true + + 1124 + 5 + 160 + 680 + 0 + + + org.contikios.cooja.serialsocket.SerialSocketServer + 0 + + 60001 + true + + 362 + 3 + 116 + 13 + 414 + + + org.contikios.cooja.plugins.ScriptRunner + + + true + + 600 + 0 + 700 + 1037 + 40 + + diff --git a/tests/17-tun-rpl-br/08-border-router-cooja-frag.sh b/tests/17-tun-rpl-br/08-border-router-cooja-frag.sh new file mode 100644 index 000000000..53b867644 --- /dev/null +++ b/tests/17-tun-rpl-br/08-border-router-cooja-frag.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +# Contiki directory +CONTIKI=$1 + +# Simulation file +BASENAME=01-border-router-cooja + +bash test-border-router.sh $CONTIKI $BASENAME fd00::204:4:4:4 60 600 2 diff --git a/tests/17-tun-rpl-br/test-border-router.sh b/tests/17-tun-rpl-br/test-border-router.sh index 6bfb8cf62..f98ca81f4 100755 --- a/tests/17-tun-rpl-br/test-border-router.sh +++ b/tests/17-tun-rpl-br/test-border-router.sh @@ -12,6 +12,12 @@ IPADDR=$3 # Time allocated for convergence WAIT_TIME=$4 +# Payload len. Default is ping6's default, 56. +PING_SIZE=${5:-56} + +# Inter-ping delay. Default is ping6's default, 1s. +PING_DELAY=${6:-1} + # ICMP request-reply count COUNT=5 @@ -31,7 +37,7 @@ sleep $WAIT_TIME # Do ping echo "Pinging" -ping6 $IPADDR -c $COUNT | tee $BASENAME.scriptlog +ping6 $IPADDR -c $COUNT -s $PING_SIZE -i $PING_DELAY | tee $BASENAME.scriptlog # Fetch ping6 status code (not $? because this is piped) STATUS=${PIPESTATUS[0]} REPLIES=`grep -c 'icmp_seq=' $BASENAME.scriptlog` From f9c91ce5275b4db0f8e2419c55b83a2cfa16443d Mon Sep 17 00:00:00 2001 From: "carlosgp143@gmail.com" Date: Thu, 12 Apr 2018 13:39:37 +0200 Subject: [PATCH 010/485] 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 011/485] 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 012/485] 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 013/485] 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 cc37c1a558972dbf930a1b087aa52de2dbc1ab83 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Thu, 5 Apr 2018 05:35:27 -0700 Subject: [PATCH 014/485] 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 015/485] 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 016/485] 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 017/485] 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 018/485] 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 019/485] 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 020/485] 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 021/485] 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 022/485] 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 023/485] 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 024/485] 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 025/485] 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 026/485] 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 ff7c3ee0429fea758a9bde8ce86ea5b19f0512ad Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 20 Apr 2018 02:44:58 -0700 Subject: [PATCH 027/485] 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 028/485] 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 8806fd2aca14654878b47d0cbc5d89d747b79372 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 21 Apr 2018 13:28:27 -0700 Subject: [PATCH 029/485] 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 030/485] 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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

&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 031/485] 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 032/485] 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 ab2b1f46936528ebe310006699591b1f821bd06f Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 24 Apr 2018 09:04:01 -0700 Subject: [PATCH 033/485] 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 4da9202d22693a71568093d48773bf5a60c9cf0b Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 25 Apr 2018 01:55:53 -0700 Subject: [PATCH 034/485] 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 2996569585e3dd200c2049c9f74a422c69914d55 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 27 Apr 2018 11:59:46 -0700 Subject: [PATCH 035/485] 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 fc76683eef792f9eaf29fad35497e96ef7bd801b Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 28 Apr 2018 14:09:41 +0100 Subject: [PATCH 036/485] 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 037/485] 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 038/485] 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 039/485] 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 040/485] 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 650a278e72cbb5a43856c9f2bfcc60d35929293e Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Mon, 30 Apr 2018 03:14:37 -0700 Subject: [PATCH 041/485] 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 042/485] 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 043/485] 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 044/485] 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 045/485] 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 65015761833b874115d1c5f0456489f0f5185c48 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 24 Apr 2018 11:42:26 -0700 Subject: [PATCH 046/485] 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 047/485] 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 f2394720c8842cb91f5c1879de5f94cc78b69642 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sun, 6 May 2018 04:13:49 -0700 Subject: [PATCH 048/485] 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 049/485] 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 050/485] 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 051/485] 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 052/485] 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 053/485] 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 21dd6209ff72538fe3cbef304a678470737e4c24 Mon Sep 17 00:00:00 2001 From: kkrentz Date: Tue, 24 Apr 2018 08:56:11 -0700 Subject: [PATCH 054/485] 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 055/485] 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 056/485] 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 057/485] 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 058/485] 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 059/485] 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 060/485] 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 From a0d7f1d0418986d0f533adecc5bde8dd6956dcc2 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 25 Apr 2018 01:21:58 -0700 Subject: [PATCH 061/485] CoAP: enable reaching link-local endpoints regardless of routing reachability --- os/net/app-layer/coap/coap-uip.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/os/net/app-layer/coap/coap-uip.c b/os/net/app-layer/coap/coap-uip.c index 8db2bbbbf..4f2331170 100644 --- a/os/net/app-layer/coap/coap-uip.c +++ b/os/net/app-layer/coap/coap-uip.c @@ -49,6 +49,7 @@ #include "contiki.h" #include "net/ipv6/uip-udp-packet.h" #include "net/ipv6/uiplib.h" +#include "net/routing/routing.h" #include "coap.h" #include "coap-engine.h" #include "coap-endpoint.h" @@ -58,10 +59,6 @@ #include "coap-keystore.h" #include "coap-keystore-simple.h" -#if UIP_CONF_IPV6_RPL -#include "rpl.h" -#endif /* UIP_CONF_IPV6_RPL */ - /* Log configuration */ #include "coap-log.h" #define LOG_MODULE "coap-uip" @@ -263,13 +260,12 @@ coap_endpoint_is_secure(const coap_endpoint_t *ep) int coap_endpoint_is_connected(const coap_endpoint_t *ep) { -#if UIP_CONF_IPV6_RPL #ifndef CONTIKI_TARGET_NATIVE - if(rpl_get_any_dag() == NULL) { + if(!uip_is_addr_linklocal(&ep->ipaddr) + && NETSTACK_ROUTING.node_is_reachable() == 0) { return 0; } #endif -#endif /* UIP_CONF_IPV6_RPL */ #ifdef WITH_DTLS if(ep != NULL && ep->secure != 0) { From 981c8fbe308d6e3781966dfd6e4b3d56e7c6958d Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sun, 13 May 2018 06:41:35 -0700 Subject: [PATCH 062/485] Fix uip6 log --- os/net/ipv6/uip6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/net/ipv6/uip6.c b/os/net/ipv6/uip6.c index e913a83e1..dfbec52b7 100644 --- a/os/net/ipv6/uip6.c +++ b/os/net/ipv6/uip6.c @@ -1089,7 +1089,7 @@ uip_process(uint8_t flag) if((UIP_IP_BUF->vtc & 0xf0) != 0x60) { /* IP version and header length. */ UIP_STAT(++uip_stat.ip.drop); UIP_STAT(++uip_stat.ip.vhlerr); - LOG_ERR("invalid version."); + LOG_ERR("invalid version\n"); goto drop; } /* From 3488a605c0acad64fd530647532581c76e7b7b33 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sun, 13 May 2018 06:41:48 -0700 Subject: [PATCH 063/485] BR MAC: add log --- os/services/rpl-border-router/native/border-router-mac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 83debbab6..1d6cbce97 100644 --- a/os/services/rpl-border-router/native/border-router-mac.c +++ b/os/services/rpl-border-router/native/border-router-mac.c @@ -111,7 +111,8 @@ send_packet(mac_callback_t sent, void *ptr) /* Will make it send only DATA packets... for now */ packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME); - /* printf("Sending packet of type: %s \n", get_frame_type(packetbuf_attr(PACKETBUF_ATTR_FRAME_TYPE))); */ + + LOG_INFO("br-rdc: sending packet (%u bytes)\n", packetbuf_datalen()); if(NETSTACK_FRAMER.create() < 0) { /* Failed to allocate space for headers */ From d22ab9413dcfd03c577a849e9a511a723aec2a62 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Mon, 14 May 2018 03:02:12 -0700 Subject: [PATCH 064/485] Various logging improvements --- examples/slip-radio/slip-radio.c | 4 ++-- os/net/ipv6/sicslowpan.c | 7 ++++--- .../rpl-border-router/native/border-router-mac.c | 10 +++++----- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/examples/slip-radio/slip-radio.c b/examples/slip-radio/slip-radio.c index d4e9db1cf..a20bd8676 100644 --- a/examples/slip-radio/slip-radio.c +++ b/examples/slip-radio/slip-radio.c @@ -143,7 +143,7 @@ slip_radio_cmd_handler(const uint8_t *data, int len) packetbuf_clear(); pos = packetutils_deserialize_atts(&data[3], len - 3); if(pos < 0) { - LOG_ERR("slip-radio: illegal packet attributes\n"); + LOG_ERR("illegal packet attributes\n"); return 1; } pos += 3; @@ -154,7 +154,7 @@ slip_radio_cmd_handler(const uint8_t *data, int len) memcpy(packetbuf_dataptr(), &data[pos], len); packetbuf_set_datalen(len); - LOG_DBG("slip-radio: sending %u (%d bytes)\n", + LOG_DBG("sending %u (%d bytes)\n", data[2], packetbuf_datalen()); /* parse frame before sending to get addresses, etc. */ diff --git a/os/net/ipv6/sicslowpan.c b/os/net/ipv6/sicslowpan.c index 200068b03..9e4e3a8b4 100644 --- a/os/net/ipv6/sicslowpan.c +++ b/os/net/ipv6/sicslowpan.c @@ -1664,11 +1664,12 @@ output(const linkaddr_t *localdest) } int freebuf = queuebuf_numfree() - 1; - LOG_INFO("output: fragmentation needed, fragments: %d, free queuebufs: %d\n", + LOG_INFO("output: fragmentation needed, fragments: %u, free queuebufs: %u\n", + fragment_count, freebuf); - fragment_count, freebuf); if(freebuf < fragment_count) { - LOG_WARN("output: dropping packet, not enough free bufs\n"); + LOG_WARN("output: dropping packet, not enough free bufs (needed: %u, free: %u)\n", + fragment_count, freebuf); return 0; } 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 1d6cbce97..fbf8b6496 100644 --- a/os/services/rpl-border-router/native/border-router-mac.c +++ b/os/services/rpl-border-router/native/border-router-mac.c @@ -47,7 +47,7 @@ /*---------------------------------------------------------------------------*/ /* Log configuration */ #include "sys/log.h" -#define LOG_MODULE "BR" +#define LOG_MODULE "BR-MAC" #define LOG_LEVEL LOG_LEVEL_NONE #define MAX_CALLBACKS 16 @@ -112,11 +112,11 @@ send_packet(mac_callback_t sent, void *ptr) /* Will make it send only DATA packets... for now */ packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME); - LOG_INFO("br-rdc: sending packet (%u bytes)\n", packetbuf_datalen()); + LOG_INFO("sending packet (%u bytes)\n", packetbuf_datalen()); if(NETSTACK_FRAMER.create() < 0) { /* Failed to allocate space for headers */ - LOG_WARN("br-rdc: send failed, too large header\n"); + LOG_WARN("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 */ @@ -125,7 +125,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)) { - LOG_WARN("br-rdc: send failed, too large header\n"); + LOG_WARN("send failed, too large header\n"); mac_call_sent_callback(sent, ptr, MAC_TX_ERR_FATAL, 1); } else { sid = setup_callback(sent, ptr); @@ -146,7 +146,7 @@ static void packet_input(void) { if(NETSTACK_FRAMER.parse() < 0) { - LOG_DBG("br-rdc: failed to parse %u\n", packetbuf_datalen()); + LOG_DBG("failed to parse %u\n", packetbuf_datalen()); } else { NETSTACK_NETWORK.input(); } From a5a2a0510181de24f269e25bffe7f2c376f6b2fd Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Mon, 26 Mar 2018 11:15:17 -0700 Subject: [PATCH 065/485] TSCH: implement burst mode --- os/net/mac/tsch/tsch-const.h | 1 + os/net/mac/tsch/tsch-packet.c | 14 ++++++++ os/net/mac/tsch/tsch-packet.h | 4 +++ os/net/mac/tsch/tsch-slot-operation.c | 49 ++++++++++++++++++++++++--- os/net/mac/tsch/tsch-slot-operation.h | 2 ++ 5 files changed, 65 insertions(+), 5 deletions(-) diff --git a/os/net/mac/tsch/tsch-const.h b/os/net/mac/tsch/tsch-const.h index 81ca7ffa8..51e7d0625 100644 --- a/os/net/mac/tsch/tsch-const.h +++ b/os/net/mac/tsch/tsch-const.h @@ -53,6 +53,7 @@ #define LINK_OPTION_RX 2 #define LINK_OPTION_SHARED 4 #define LINK_OPTION_TIME_KEEPING 8 +#define LINK_OPTION_BURST 16 /* Default IEEE 802.15.4e hopping sequences, obtained from https://gist.github.com/twatteyne/2e22ee3c1a802b685695 */ /* 16 channels, sequence length 16 */ diff --git a/os/net/mac/tsch/tsch-packet.c b/os/net/mac/tsch/tsch-packet.c index 64f03b588..5f6cb6b54 100644 --- a/os/net/mac/tsch/tsch-packet.c +++ b/os/net/mac/tsch/tsch-packet.c @@ -459,4 +459,18 @@ tsch_packet_parse_eb(const uint8_t *buf, int buf_size, return curr_len; } /*---------------------------------------------------------------------------*/ +/* Set frame pending bit in a packet (whose header was already build) */ +void +tsch_packet_set_frame_pending(uint8_t *buf, int buf_size) +{ + buf[0] |= (1 << 4); +} +/*---------------------------------------------------------------------------*/ +/* Get frame pending bit from a packet */ +int +tsch_packet_get_frame_pending(uint8_t *buf, int buf_size) +{ + return (buf[0] >> 4) & 1; +} +/*---------------------------------------------------------------------------*/ /** @} */ diff --git a/os/net/mac/tsch/tsch-packet.h b/os/net/mac/tsch/tsch-packet.h index 6b05d6653..a7426ebac 100644 --- a/os/net/mac/tsch/tsch-packet.h +++ b/os/net/mac/tsch/tsch-packet.h @@ -101,6 +101,10 @@ int tsch_packet_update_eb(uint8_t *buf, int buf_size, uint8_t tsch_sync_ie_offse 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); +/* Set frame pending bit in a packet (whose header was already build) */ +void tsch_packet_set_frame_pending(uint8_t *buf, int buf_size); +/* Get frame pending bit from a packet */ +int tsch_packet_get_frame_pending(uint8_t *buf, int buf_size); #endif /* __TSCH_PACKET_H__ */ /** @} */ diff --git a/os/net/mac/tsch/tsch-slot-operation.c b/os/net/mac/tsch/tsch-slot-operation.c index c4bb25e88..6b47b4ebf 100644 --- a/os/net/mac/tsch/tsch-slot-operation.c +++ b/os/net/mac/tsch/tsch-slot-operation.c @@ -167,6 +167,11 @@ static struct tsch_link *backup_link = NULL; static struct tsch_packet *current_packet = NULL; static struct tsch_neighbor *current_neighbor = NULL; +/* Indicates whether an extra link is needed to handle the current burst */ +static int burst_link_scheduled = 0; +/* Counts the length of the current burst */ +int tsch_current_burst_count = 0; + /* Protothread for association */ PT_THREAD(tsch_scan(struct pt *pt)); /* Protothread for slot operation, called from rtimer interrupt @@ -456,6 +461,8 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t)) /* is this a broadcast packet? (wait for ack?) */ static uint8_t is_broadcast; static rtimer_clock_t tx_start_time; + /* Did we set the frame pending bit to request an extra burst link? */ + static int burst_link_requested; #if CCA_ENABLED static uint8_t cca_status; @@ -466,6 +473,13 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t)) packet_len = queuebuf_datalen(current_packet->qb); /* is this a broadcast packet? (wait for ack?) */ is_broadcast = current_neighbor->is_broadcast; + /* Unicast. More packets in queue for the neighbor? */ + burst_link_requested = 0; + if(!is_broadcast && (current_link->link_options & LINK_OPTION_BURST) + && tsch_queue_packet_count(¤t_neighbor->addr) > 1) { + burst_link_requested = 1; + tsch_packet_set_frame_pending(packet, packet_len); + } /* read seqno from payload */ seqno = ((uint8_t *)(packet))[2]; /* if this is an EB, then update its Sync-IE */ @@ -618,6 +632,12 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t)) tsch_schedule_keepalive(); } mac_tx_status = MAC_TX_OK; + + /* We requested an extra slot and got an ack. This means + the extra slot will be scheduled at the received */ + if(burst_link_requested) { + burst_link_scheduled = 1; + } } else { mac_tx_status = MAC_TX_NOACK; } @@ -844,6 +864,9 @@ PT_THREAD(tsch_rx_slot(struct pt *pt, struct rtimer *t)) TSCH_DEBUG_RX_EVENT(); NETSTACK_RADIO.transmit(ack_len); tsch_radio_off(TSCH_RADIO_CMD_OFF_WITHIN_TIMESLOT); + + /* Schedule a burst link iff the frame pending bit was set */ + burst_link_scheduled = tsch_packet_get_frame_pending(current_input->payload, current_input->len); } } @@ -930,6 +953,8 @@ PT_THREAD(tsch_slot_operation(struct rtimer *t, void *ptr)) /* Reset drift correction */ drift_correction = 0; is_drift_correction_used = 0; + /* For the packet burst mechanism */ + burst_link_scheduled = 0; /* Get a packet ready to be sent */ current_packet = get_packet_and_neighbor_for_link(current_link, ¤t_neighbor); /* There is no packet to send, and this link does not have Rx flag. Instead of doing @@ -993,13 +1018,27 @@ PT_THREAD(tsch_slot_operation(struct rtimer *t, void *ptr)) tsch_queue_update_all_backoff_windows(¤t_link->addr); } - /* Get next active link */ - current_link = tsch_schedule_get_next_active_link(&tsch_current_asn, ×lot_diff, &backup_link); - if(current_link == NULL) { - /* There is no next link. Fall back to default - * behavior: wake up at the next slot. */ + /* A burst link was scheduled. Replay the current link at the + next time offset */ + if(burst_link_scheduled) { timeslot_diff = 1; + backup_link = NULL; + /* Keep track of the number of repetitions */ + tsch_current_burst_count++; + } else { + /* Get next active link */ + current_link = tsch_schedule_get_next_active_link(&tsch_current_asn, ×lot_diff, &backup_link); + if(current_link == NULL) { + /* There is no next link. Fall back to default + * behavior: wake up at the next slot. */ + timeslot_diff = 1; + } else { + /* Reset burst index now that the link was scheduled from + normal schedule (as opposed to from ongoing burst) */ + tsch_current_burst_count = 0; + } } + /* Update ASN */ TSCH_ASN_INC(tsch_current_asn, timeslot_diff); /* Time to next wake up */ diff --git a/os/net/mac/tsch/tsch-slot-operation.h b/os/net/mac/tsch/tsch-slot-operation.h index 1c71c5587..b1c05697b 100644 --- a/os/net/mac/tsch/tsch-slot-operation.h +++ b/os/net/mac/tsch/tsch-slot-operation.h @@ -57,6 +57,8 @@ extern struct ringbufindex input_ringbuf; extern struct input_packet input_array[TSCH_MAX_INCOMING_PACKETS]; /* Last clock_time_t where synchronization happened */ extern clock_time_t last_sync_time; +/* Counts the length of the current burst */ +extern int tsch_current_burst_count; /********** Functions *********/ From c41057fc1be9720087ce0a10fb1f9af74c8aa622 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Mon, 26 Mar 2018 11:15:45 -0700 Subject: [PATCH 066/485] TSCH: cleaner logging of burst mode --- os/net/mac/tsch/tsch-log.c | 6 ++++-- os/net/mac/tsch/tsch-log.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/os/net/mac/tsch/tsch-log.c b/os/net/mac/tsch/tsch-log.c index d27dac064..5aa6f1e69 100644 --- a/os/net/mac/tsch/tsch-log.c +++ b/os/net/mac/tsch/tsch-log.c @@ -82,9 +82,10 @@ tsch_log_process_pending(void) printf("[INFO: TSCH-LOG ] {asn %02x.%08lx link-NULL} ", log->asn.ms1b, log->asn.ls4b); } else { struct tsch_slotframe *sf = tsch_schedule_get_slotframe_by_handle(log->link->slotframe_handle); - printf("[INFO: TSCH-LOG ] {asn %02x.%08lx link %2u %3u %3u %2u ch %2u} ", + printf("[INFO: TSCH-LOG ] {asn %02x.%08lx link %2u %3u %3u %2u %2u ch %2u} ", log->asn.ms1b, log->asn.ls4b, - log->link->slotframe_handle, sf ? sf->size.val : 0, log->link->timeslot, log->link->channel_offset, + log->link->slotframe_handle, sf ? sf->size.val : 0, + log->burst_count, log->link->timeslot + log->burst_count, log->link->channel_offset, tsch_calculate_channel(&log->asn, log->link->channel_offset)); } switch(log->type) { @@ -135,6 +136,7 @@ tsch_log_prepare_add(void) struct tsch_log_t *log = &log_array[log_index]; log->asn = tsch_current_asn; log->link = current_link; + log->burst_count = tsch_current_burst_count; return log; } else { log_dropped++; diff --git a/os/net/mac/tsch/tsch-log.h b/os/net/mac/tsch/tsch-log.h index 468eff869..8064922fd 100644 --- a/os/net/mac/tsch/tsch-log.h +++ b/os/net/mac/tsch/tsch-log.h @@ -80,6 +80,7 @@ struct tsch_log_t { } type; struct tsch_asn_t asn; struct tsch_link *link; + uint8_t burst_count; union { char message[48]; struct { From d3b8b80b2808c29dcb37532cc7f675453ad42e27 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Mon, 26 Mar 2018 11:22:31 -0700 Subject: [PATCH 067/485] TSCH: add option to run 6TiSCH minimal with burst mode enabled --- os/net/mac/tsch/tsch-conf.h | 7 +++++++ os/net/mac/tsch/tsch-schedule.c | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/os/net/mac/tsch/tsch-conf.h b/os/net/mac/tsch/tsch-conf.h index 3ee47b9cb..934e0884f 100644 --- a/os/net/mac/tsch/tsch-conf.h +++ b/os/net/mac/tsch/tsch-conf.h @@ -317,6 +317,13 @@ #define TSCH_SCHEDULE_WITH_6TISCH_MINIMAL (!(BUILD_WITH_ORCHESTRA)) #endif +/* Add burst mode to 6TiSCH minimal schedule */ +#ifdef TSCH_SCHEDULE_CONF_WITH_6TISCH_MINIMAL_WITH_BURST +#define TSCH_SCHEDULE_WITH_6TISCH_MINIMAL_WITH_BURST TSCH_SCHEDULE_CONF_WITH_6TISCH_MINIMAL_WITH_BURST +#else +#define TSCH_SCHEDULE_WITH_6TISCH_MINIMAL_WITH_BURST 0 +#endif + /* 6TiSCH Minimal schedule slotframe length */ #ifdef TSCH_SCHEDULE_CONF_DEFAULT_LENGTH #define TSCH_SCHEDULE_DEFAULT_LENGTH TSCH_SCHEDULE_CONF_DEFAULT_LENGTH diff --git a/os/net/mac/tsch/tsch-schedule.c b/os/net/mac/tsch/tsch-schedule.c index 70a6b92ae..d5bf49653 100644 --- a/os/net/mac/tsch/tsch-schedule.c +++ b/os/net/mac/tsch/tsch-schedule.c @@ -423,7 +423,8 @@ tsch_schedule_create_minimal(void) * but is required according to 802.15.4e if also used for EB transmission. * Timeslot: 0, channel offset: 0. */ tsch_schedule_add_link(sf_min, - LINK_OPTION_RX | LINK_OPTION_TX | LINK_OPTION_SHARED | LINK_OPTION_TIME_KEEPING, + LINK_OPTION_RX | LINK_OPTION_TX | LINK_OPTION_SHARED | LINK_OPTION_TIME_KEEPING + | (TSCH_SCHEDULE_WITH_6TISCH_MINIMAL_WITH_BURST ? LINK_OPTION_BURST : 0), LINK_TYPE_ADVERTISING, &tsch_broadcast_address, 0, 0); } From 3fe846dbada52ef4b1a738340ff073514bb65a2e Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Mon, 26 Mar 2018 11:35:35 -0700 Subject: [PATCH 068/485] TSCH burst mode: bounded burst lengths --- os/net/mac/tsch/tsch-conf.h | 13 ++++++++++--- os/net/mac/tsch/tsch-schedule.c | 2 +- os/net/mac/tsch/tsch-slot-operation.c | 1 + 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/os/net/mac/tsch/tsch-conf.h b/os/net/mac/tsch/tsch-conf.h index 934e0884f..afd90aaef 100644 --- a/os/net/mac/tsch/tsch-conf.h +++ b/os/net/mac/tsch/tsch-conf.h @@ -318,10 +318,17 @@ #endif /* Add burst mode to 6TiSCH minimal schedule */ -#ifdef TSCH_SCHEDULE_CONF_WITH_6TISCH_MINIMAL_WITH_BURST -#define TSCH_SCHEDULE_WITH_6TISCH_MINIMAL_WITH_BURST TSCH_SCHEDULE_CONF_WITH_6TISCH_MINIMAL_WITH_BURST +#ifdef TSCH_CONF_WITH_6TISCH_MINIMAL_WITH_BURST +#define TSCH_WITH_6TISCH_MINIMAL_WITH_BURST TSCH_CONF_WITH_6TISCH_MINIMAL_WITH_BURST #else -#define TSCH_SCHEDULE_WITH_6TISCH_MINIMAL_WITH_BURST 0 +#define TSCH_WITH_6TISCH_MINIMAL_WITH_BURST 0 +#endif + +/* Set an upper bound on burst length */ +#ifdef TSCH_CONF_BURST_MAX_LEN +#define TSCH_BURST_MAX_LEN TSCH_CONF_BURST_MAX_LEN +#else +#define TSCH_BURST_MAX_LEN 32 #endif /* 6TiSCH Minimal schedule slotframe length */ diff --git a/os/net/mac/tsch/tsch-schedule.c b/os/net/mac/tsch/tsch-schedule.c index d5bf49653..a03363eb9 100644 --- a/os/net/mac/tsch/tsch-schedule.c +++ b/os/net/mac/tsch/tsch-schedule.c @@ -424,7 +424,7 @@ tsch_schedule_create_minimal(void) * Timeslot: 0, channel offset: 0. */ tsch_schedule_add_link(sf_min, LINK_OPTION_RX | LINK_OPTION_TX | LINK_OPTION_SHARED | LINK_OPTION_TIME_KEEPING - | (TSCH_SCHEDULE_WITH_6TISCH_MINIMAL_WITH_BURST ? LINK_OPTION_BURST : 0), + | (TSCH_WITH_6TISCH_MINIMAL_WITH_BURST ? LINK_OPTION_BURST : 0), LINK_TYPE_ADVERTISING, &tsch_broadcast_address, 0, 0); } diff --git a/os/net/mac/tsch/tsch-slot-operation.c b/os/net/mac/tsch/tsch-slot-operation.c index 6b47b4ebf..a2e9982fe 100644 --- a/os/net/mac/tsch/tsch-slot-operation.c +++ b/os/net/mac/tsch/tsch-slot-operation.c @@ -476,6 +476,7 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t)) /* Unicast. More packets in queue for the neighbor? */ burst_link_requested = 0; if(!is_broadcast && (current_link->link_options & LINK_OPTION_BURST) + && tsch_current_burst_count + 1 < TSCH_BURST_MAX_LEN && tsch_queue_packet_count(¤t_neighbor->addr) > 1) { burst_link_requested = 1; tsch_packet_set_frame_pending(packet, packet_len); From 5607308eed2540cc3fe10edf7c5902b6152ef64e Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sun, 15 Apr 2018 04:18:33 -0700 Subject: [PATCH 069/485] Added doxygen for TSCH frame pending bit functions --- os/net/mac/tsch/tsch-packet.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/os/net/mac/tsch/tsch-packet.h b/os/net/mac/tsch/tsch-packet.h index a7426ebac..cdf7c7bed 100644 --- a/os/net/mac/tsch/tsch-packet.h +++ b/os/net/mac/tsch/tsch-packet.h @@ -101,9 +101,18 @@ int tsch_packet_update_eb(uint8_t *buf, int buf_size, uint8_t tsch_sync_ie_offse 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); -/* Set frame pending bit in a packet (whose header was already build) */ +/** + * \brief Set frame pending bit in a packet (whose header was already build) + * \param buf The buffer where the packet resides + * \param buf_size The buffer size + */ void tsch_packet_set_frame_pending(uint8_t *buf, int buf_size); -/* Get frame pending bit from a packet */ +/** + * \brief Get frame pending bit from a packet + * \param buf The buffer where the packet resides + * \param buf_size The buffer size + * \return The value of the frame pending bit, 1 or 0 + */ int tsch_packet_get_frame_pending(uint8_t *buf, int buf_size); #endif /* __TSCH_PACKET_H__ */ From 243386044158d4b792976d8dce48526b13846ede Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 12 May 2018 10:49:44 -0700 Subject: [PATCH 070/485] TSCH burst mode: do not channel hop within burst --- os/net/mac/tsch/tsch-slot-operation.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/os/net/mac/tsch/tsch-slot-operation.c b/os/net/mac/tsch/tsch-slot-operation.c index a2e9982fe..7a26e4d81 100644 --- a/os/net/mac/tsch/tsch-slot-operation.c +++ b/os/net/mac/tsch/tsch-slot-operation.c @@ -171,6 +171,8 @@ static struct tsch_neighbor *current_neighbor = NULL; static int burst_link_scheduled = 0; /* Counts the length of the current burst */ int tsch_current_burst_count = 0; +/* The physical channel of the current burst */ +static uint16_t burst_current_channel = 0; /* Protothread for association */ PT_THREAD(tsch_scan(struct pt *pt)); @@ -954,8 +956,6 @@ PT_THREAD(tsch_slot_operation(struct rtimer *t, void *ptr)) /* Reset drift correction */ drift_correction = 0; is_drift_correction_used = 0; - /* For the packet burst mechanism */ - burst_link_scheduled = 0; /* Get a packet ready to be sent */ current_packet = get_packet_and_neighbor_for_link(current_link, ¤t_neighbor); /* There is no packet to send, and this link does not have Rx flag. Instead of doing @@ -966,8 +966,15 @@ PT_THREAD(tsch_slot_operation(struct rtimer *t, void *ptr)) } is_active_slot = current_packet != NULL || (current_link->link_options & LINK_OPTION_RX); if(is_active_slot) { - /* Hop channel */ - current_channel = tsch_calculate_channel(&tsch_current_asn, current_link->channel_offset); + /* If we are in a burst, we stick to current channel instead of + * doing channel hopping, as per IEEE 802.15.4-2015 */ + if(burst_link_scheduled) { + current_channel = burst_current_channel; + burst_link_scheduled = 0; + } else { + /* Hop channel */ + current_channel = tsch_calculate_channel(&tsch_current_asn, current_link->channel_offset); + } NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, current_channel); /* Turn the radio on already here if configured so; necessary for radios with slow startup */ tsch_radio_on(TSCH_RADIO_CMD_ON_START_OF_TIMESLOT); @@ -986,6 +993,10 @@ PT_THREAD(tsch_slot_operation(struct rtimer *t, void *ptr)) static struct pt slot_rx_pt; PT_SPAWN(&slot_operation_pt, &slot_rx_pt, tsch_rx_slot(&slot_rx_pt, t)); } + } else { + /* Make sure to end the burst in cast, for some reason, we were + * in a burst but now without any more packet to send. */ + burst_link_scheduled = 0; } TSCH_DEBUG_SLOT_END(); } @@ -1023,6 +1034,7 @@ PT_THREAD(tsch_slot_operation(struct rtimer *t, void *ptr)) next time offset */ if(burst_link_scheduled) { timeslot_diff = 1; + burst_current_channel = current_channel; backup_link = NULL; /* Keep track of the number of repetitions */ tsch_current_burst_count++; From 0153566b928cb59ff02004dfb37033a560e5716f Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 12 May 2018 10:53:24 -0700 Subject: [PATCH 071/485] TSCH burst mode: fix logging --- os/net/mac/tsch/tsch-log.c | 3 ++- os/net/mac/tsch/tsch-log.h | 1 + os/net/mac/tsch/tsch-slot-operation.c | 14 +++++++------- os/net/mac/tsch/tsch.h | 2 ++ 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/os/net/mac/tsch/tsch-log.c b/os/net/mac/tsch/tsch-log.c index 5aa6f1e69..e705f50ab 100644 --- a/os/net/mac/tsch/tsch-log.c +++ b/os/net/mac/tsch/tsch-log.c @@ -86,7 +86,7 @@ tsch_log_process_pending(void) log->asn.ms1b, log->asn.ls4b, log->link->slotframe_handle, sf ? sf->size.val : 0, log->burst_count, log->link->timeslot + log->burst_count, log->link->channel_offset, - tsch_calculate_channel(&log->asn, log->link->channel_offset)); + log->channel); } switch(log->type) { case tsch_log_tx: @@ -137,6 +137,7 @@ tsch_log_prepare_add(void) log->asn = tsch_current_asn; log->link = current_link; log->burst_count = tsch_current_burst_count; + log->channel = tsch_current_channel; return log; } else { log_dropped++; diff --git a/os/net/mac/tsch/tsch-log.h b/os/net/mac/tsch/tsch-log.h index 8064922fd..186cda120 100644 --- a/os/net/mac/tsch/tsch-log.h +++ b/os/net/mac/tsch/tsch-log.h @@ -81,6 +81,7 @@ struct tsch_log_t { struct tsch_asn_t asn; struct tsch_link *link; uint8_t burst_count; + uint8_t channel; union { char message[48]; struct { diff --git a/os/net/mac/tsch/tsch-slot-operation.c b/os/net/mac/tsch/tsch-slot-operation.c index 7a26e4d81..bc76b526e 100644 --- a/os/net/mac/tsch/tsch-slot-operation.c +++ b/os/net/mac/tsch/tsch-slot-operation.c @@ -155,7 +155,7 @@ static rtimer_clock_t volatile current_slot_start; static volatile int tsch_in_slot_operation = 0; /* If we are inside a slot, this tells the current channel */ -static uint8_t current_channel; +uint8_t tsch_current_channel; /* Info about the link, packet and neighbor of * the current (or next) slot */ @@ -172,7 +172,7 @@ static int burst_link_scheduled = 0; /* Counts the length of the current burst */ int tsch_current_burst_count = 0; /* The physical channel of the current burst */ -static uint16_t burst_current_channel = 0; +static uint16_t burst_tsch_current_channel = 0; /* Protothread for association */ PT_THREAD(tsch_scan(struct pt *pt)); @@ -772,7 +772,7 @@ PT_THREAD(tsch_rx_slot(struct pt *pt, struct rtimer *t)) NETSTACK_RADIO.get_value(RADIO_PARAM_LAST_RSSI, &radio_last_rssi); current_input->rx_asn = tsch_current_asn; current_input->rssi = (signed)radio_last_rssi; - current_input->channel = current_channel; + current_input->channel = tsch_current_channel; header_len = frame802154_parse((uint8_t *)current_input->payload, current_input->len, &frame); frame_valid = header_len > 0 && frame802154_check_dest_panid(&frame) && @@ -969,13 +969,13 @@ PT_THREAD(tsch_slot_operation(struct rtimer *t, void *ptr)) /* If we are in a burst, we stick to current channel instead of * doing channel hopping, as per IEEE 802.15.4-2015 */ if(burst_link_scheduled) { - current_channel = burst_current_channel; + tsch_current_channel = burst_tsch_current_channel; burst_link_scheduled = 0; } else { /* Hop channel */ - current_channel = tsch_calculate_channel(&tsch_current_asn, current_link->channel_offset); + tsch_current_channel = tsch_calculate_channel(&tsch_current_asn, current_link->channel_offset); } - NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, current_channel); + NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, tsch_current_channel); /* Turn the radio on already here if configured so; necessary for radios with slow startup */ tsch_radio_on(TSCH_RADIO_CMD_ON_START_OF_TIMESLOT); /* Decide whether it is a TX/RX/IDLE or OFF slot */ @@ -1034,7 +1034,7 @@ PT_THREAD(tsch_slot_operation(struct rtimer *t, void *ptr)) next time offset */ if(burst_link_scheduled) { timeslot_diff = 1; - burst_current_channel = current_channel; + burst_tsch_current_channel = tsch_current_channel; backup_link = NULL; /* Keep track of the number of repetitions */ tsch_current_burst_count++; diff --git a/os/net/mac/tsch/tsch.h b/os/net/mac/tsch/tsch.h index 0f108bd93..93b6e0d88 100644 --- a/os/net/mac/tsch/tsch.h +++ b/os/net/mac/tsch/tsch.h @@ -164,6 +164,8 @@ extern const linkaddr_t tsch_eb_address; extern struct tsch_asn_t tsch_current_asn; extern uint8_t tsch_join_priority; extern struct tsch_link *current_link; +/* If we are inside a slot, this tells the current channel */ +extern uint8_t tsch_current_channel; /* TSCH channel hopping sequence */ extern uint8_t tsch_hopping_sequence[TSCH_HOPPING_SEQUENCE_MAX_LEN]; extern struct tsch_asn_divisor_t tsch_hopping_sequence_length; From 9569519bbe933b3d33ab7ab027cde6222efe6616 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 12 May 2018 11:20:14 -0700 Subject: [PATCH 072/485] TSCH: burst mode is in the standard, remove custom link option --- os/net/mac/tsch/tsch-conf.h | 11 +++-------- os/net/mac/tsch/tsch-const.h | 1 - os/net/mac/tsch/tsch-schedule.c | 3 +-- os/net/mac/tsch/tsch-slot-operation.c | 2 +- 4 files changed, 5 insertions(+), 12 deletions(-) diff --git a/os/net/mac/tsch/tsch-conf.h b/os/net/mac/tsch/tsch-conf.h index afd90aaef..8613eb0e3 100644 --- a/os/net/mac/tsch/tsch-conf.h +++ b/os/net/mac/tsch/tsch-conf.h @@ -317,14 +317,9 @@ #define TSCH_SCHEDULE_WITH_6TISCH_MINIMAL (!(BUILD_WITH_ORCHESTRA)) #endif -/* Add burst mode to 6TiSCH minimal schedule */ -#ifdef TSCH_CONF_WITH_6TISCH_MINIMAL_WITH_BURST -#define TSCH_WITH_6TISCH_MINIMAL_WITH_BURST TSCH_CONF_WITH_6TISCH_MINIMAL_WITH_BURST -#else -#define TSCH_WITH_6TISCH_MINIMAL_WITH_BURST 0 -#endif - -/* Set an upper bound on burst length */ +/* Set an upper bound on burst length. Set to 0 to never set the frame pending + * bit, i.e., never trigger a burst. Note that receiver-side support for burst + * is always enabled, as it is part of IEEE 802.1.5.4-2015 (Section 7.2.1.3)*/ #ifdef TSCH_CONF_BURST_MAX_LEN #define TSCH_BURST_MAX_LEN TSCH_CONF_BURST_MAX_LEN #else diff --git a/os/net/mac/tsch/tsch-const.h b/os/net/mac/tsch/tsch-const.h index 51e7d0625..81ca7ffa8 100644 --- a/os/net/mac/tsch/tsch-const.h +++ b/os/net/mac/tsch/tsch-const.h @@ -53,7 +53,6 @@ #define LINK_OPTION_RX 2 #define LINK_OPTION_SHARED 4 #define LINK_OPTION_TIME_KEEPING 8 -#define LINK_OPTION_BURST 16 /* Default IEEE 802.15.4e hopping sequences, obtained from https://gist.github.com/twatteyne/2e22ee3c1a802b685695 */ /* 16 channels, sequence length 16 */ diff --git a/os/net/mac/tsch/tsch-schedule.c b/os/net/mac/tsch/tsch-schedule.c index a03363eb9..4f94b8e30 100644 --- a/os/net/mac/tsch/tsch-schedule.c +++ b/os/net/mac/tsch/tsch-schedule.c @@ -423,8 +423,7 @@ tsch_schedule_create_minimal(void) * but is required according to 802.15.4e if also used for EB transmission. * Timeslot: 0, channel offset: 0. */ tsch_schedule_add_link(sf_min, - LINK_OPTION_RX | LINK_OPTION_TX | LINK_OPTION_SHARED | LINK_OPTION_TIME_KEEPING - | (TSCH_WITH_6TISCH_MINIMAL_WITH_BURST ? LINK_OPTION_BURST : 0), + (LINK_OPTION_RX | LINK_OPTION_TX | LINK_OPTION_SHARED | LINK_OPTION_TIME_KEEPING), LINK_TYPE_ADVERTISING, &tsch_broadcast_address, 0, 0); } diff --git a/os/net/mac/tsch/tsch-slot-operation.c b/os/net/mac/tsch/tsch-slot-operation.c index bc76b526e..de4dec676 100644 --- a/os/net/mac/tsch/tsch-slot-operation.c +++ b/os/net/mac/tsch/tsch-slot-operation.c @@ -477,7 +477,7 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t)) is_broadcast = current_neighbor->is_broadcast; /* Unicast. More packets in queue for the neighbor? */ burst_link_requested = 0; - if(!is_broadcast && (current_link->link_options & LINK_OPTION_BURST) + if(!is_broadcast && tsch_current_burst_count + 1 < TSCH_BURST_MAX_LEN && tsch_queue_packet_count(¤t_neighbor->addr) > 1) { burst_link_requested = 1; From 359ae59499760f17ca1bc73ac4b4da895f6056d4 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sun, 13 May 2018 06:47:37 -0700 Subject: [PATCH 073/485] tsch-packet: define constant for frame pending bit offset --- os/net/mac/tsch/tsch-packet.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/os/net/mac/tsch/tsch-packet.c b/os/net/mac/tsch/tsch-packet.c index 5f6cb6b54..133e9a668 100644 --- a/os/net/mac/tsch/tsch-packet.c +++ b/os/net/mac/tsch/tsch-packet.c @@ -70,6 +70,9 @@ */ static struct packetbuf_attr eackbuf_attrs[PACKETBUF_NUM_ATTRS]; +/* The offset of the frame pending bit flag within the first byte of FCF */ +#define IEEE802154_FRAME_PENDING_BIT_OFFSET 4 + /*---------------------------------------------------------------------------*/ static int tsch_packet_eackbuf_set_attr(uint8_t type, const packetbuf_attr_t val) @@ -463,14 +466,14 @@ tsch_packet_parse_eb(const uint8_t *buf, int buf_size, void tsch_packet_set_frame_pending(uint8_t *buf, int buf_size) { - buf[0] |= (1 << 4); + buf[0] |= (1 << IEEE802154_FRAME_PENDING_BIT_OFFSET); } /*---------------------------------------------------------------------------*/ /* Get frame pending bit from a packet */ int tsch_packet_get_frame_pending(uint8_t *buf, int buf_size) { - return (buf[0] >> 4) & 1; + return (buf[0] >> IEEE802154_FRAME_PENDING_BIT_OFFSET) & 1; } /*---------------------------------------------------------------------------*/ /** @} */ From 2bf79a98ce9727c2c547b4ba3ed0bcea1778d3ef Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sun, 13 May 2018 06:49:52 -0700 Subject: [PATCH 074/485] TSCH burst mode: remove unnecessary variable burst_tsch_current_channel --- os/net/mac/tsch/tsch-slot-operation.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/os/net/mac/tsch/tsch-slot-operation.c b/os/net/mac/tsch/tsch-slot-operation.c index de4dec676..917d13816 100644 --- a/os/net/mac/tsch/tsch-slot-operation.c +++ b/os/net/mac/tsch/tsch-slot-operation.c @@ -171,8 +171,6 @@ static struct tsch_neighbor *current_neighbor = NULL; static int burst_link_scheduled = 0; /* Counts the length of the current burst */ int tsch_current_burst_count = 0; -/* The physical channel of the current burst */ -static uint16_t burst_tsch_current_channel = 0; /* Protothread for association */ PT_THREAD(tsch_scan(struct pt *pt)); @@ -969,7 +967,7 @@ PT_THREAD(tsch_slot_operation(struct rtimer *t, void *ptr)) /* If we are in a burst, we stick to current channel instead of * doing channel hopping, as per IEEE 802.15.4-2015 */ if(burst_link_scheduled) { - tsch_current_channel = burst_tsch_current_channel; + /* Reset burst_link_scheduled flag. Will be set again if burst continue. */ burst_link_scheduled = 0; } else { /* Hop channel */ @@ -1034,7 +1032,6 @@ PT_THREAD(tsch_slot_operation(struct rtimer *t, void *ptr)) next time offset */ if(burst_link_scheduled) { timeslot_diff = 1; - burst_tsch_current_channel = tsch_current_channel; backup_link = NULL; /* Keep track of the number of repetitions */ tsch_current_burst_count++; From 08d4c9f594a9b23af8035133f0fa2532d1b85d6e Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 12 May 2018 11:35:38 -0700 Subject: [PATCH 075/485] rpl-udp example: remove uipbuf tuning of MAC max retries --- examples/rpl-udp/udp-client.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/examples/rpl-udp/udp-client.c b/examples/rpl-udp/udp-client.c index a10d188ac..1fb030034 100644 --- a/examples/rpl-udp/udp-client.c +++ b/examples/rpl-udp/udp-client.c @@ -33,10 +33,7 @@ udp_rx_callback(struct simple_udp_connection *c, uint16_t datalen) { unsigned count = *(unsigned *)data; - /* If tagging of traffic class is enabled tc will print number of - transmission - otherwise it will be 0 */ - LOG_INFO("Received response %u (tc:%d) from ", count, - uipbuf_get_attr(UIPBUF_ATTR_MAX_MAC_TRANSMISSIONS)); + LOG_INFO("Received response %u from ", count); LOG_INFO_6ADDR(sender_addr); LOG_INFO_("\n"); } @@ -62,12 +59,6 @@ PROCESS_THREAD(udp_client_process, ev, data) LOG_INFO("Sending request %u to ", count); LOG_INFO_6ADDR(&dest_ipaddr); LOG_INFO_("\n"); - /* Set the number of transmissions to use for this packet - - this can be used to create more reliable transmissions or - less reliable than the default. Works end-to-end if - UIP_CONF_TAG_TC_WITH_VARIABLE_RETRANSMISSIONS is set to 1. - */ - uipbuf_set_attr(UIPBUF_ATTR_MAX_MAC_TRANSMISSIONS, 1 + count % 5); simple_udp_sendto(&udp_conn, &count, sizeof(count), &dest_ipaddr); count++; } else { From 251a9d187fc09f902e41c8d165e8f4c88c6ce4fd Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sun, 13 May 2018 04:52:47 -0700 Subject: [PATCH 076/485] Added example for uipbuf attributes --- examples/libs/ipv6-uipbuf/Makefile | 5 + examples/libs/ipv6-uipbuf/README.md | 5 + .../libs/ipv6-uipbuf/ipv6-uipbuf-cooja.csc | 180 ++++++++++++++++++ examples/libs/ipv6-uipbuf/ipv6-uipbuf-sky.csc | 170 +++++++++++++++++ examples/libs/ipv6-uipbuf/project-conf.h | 37 ++++ examples/libs/ipv6-uipbuf/udp-client.c | 85 +++++++++ examples/libs/ipv6-uipbuf/udp-server.c | 84 ++++++++ 7 files changed, 566 insertions(+) create mode 100644 examples/libs/ipv6-uipbuf/Makefile create mode 100644 examples/libs/ipv6-uipbuf/README.md create mode 100644 examples/libs/ipv6-uipbuf/ipv6-uipbuf-cooja.csc create mode 100644 examples/libs/ipv6-uipbuf/ipv6-uipbuf-sky.csc create mode 100644 examples/libs/ipv6-uipbuf/project-conf.h create mode 100644 examples/libs/ipv6-uipbuf/udp-client.c create mode 100644 examples/libs/ipv6-uipbuf/udp-server.c diff --git a/examples/libs/ipv6-uipbuf/Makefile b/examples/libs/ipv6-uipbuf/Makefile new file mode 100644 index 000000000..b7500284e --- /dev/null +++ b/examples/libs/ipv6-uipbuf/Makefile @@ -0,0 +1,5 @@ +CONTIKI_PROJECT = udp-client udp-server +all: $(CONTIKI_PROJECT) + +CONTIKI=../../.. +include $(CONTIKI)/Makefile.include diff --git a/examples/libs/ipv6-uipbuf/README.md b/examples/libs/ipv6-uipbuf/README.md new file mode 100644 index 000000000..6f028202e --- /dev/null +++ b/examples/libs/ipv6-uipbuf/README.md @@ -0,0 +1,5 @@ +This example is meant to showcase the capabilities of uipbuf. It currently +focuses only on UIPBUF_ATTR_MAX_MAC_TRANSMISSIONS, which lets an application +set a custom max number of MAC transmissions. Optionally, this information +can be passed on over multiple hops, so that the attribute applies along +the full path. This requires setting UIP_CONF_TAG_TC_WITH_VARIABLE_RETRANSMISSIONS. diff --git a/examples/libs/ipv6-uipbuf/ipv6-uipbuf-cooja.csc b/examples/libs/ipv6-uipbuf/ipv6-uipbuf-cooja.csc new file mode 100644 index 000000000..71adabb74 --- /dev/null +++ b/examples/libs/ipv6-uipbuf/ipv6-uipbuf-cooja.csc @@ -0,0 +1,180 @@ + + + [APPS_DIR]/mrm + [APPS_DIR]/mspsim + [APPS_DIR]/avrora + [APPS_DIR]/serial_socket + [APPS_DIR]/powertracker + + IPv6 uipbuf Example + 123456 + 1000000 + + org.contikios.cooja.radiomediums.UDGM + 50.0 + 100.0 + 1.0 + 1.0 + + + 40000 + + + org.contikios.cooja.contikimote.ContikiMoteType + mtype829 + Cooja Mote Type #1 + [CONTIKI_DIR]/examples/libs/ipv6-uipbuf/udp-server.c + make udp-server.cooja TARGET=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.contikimote.ContikiMoteType + mtype405 + Cooja Mote Type #2 + [CONTIKI_DIR]/examples/libs/ipv6-uipbuf/udp-client.c + make udp-client.cooja TARGET=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 + 43.291897546941804 + 7.17470867058031 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 1 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype829 + + + + org.contikios.cooja.interfaces.Position + 41.0074953544532 + 42.15996473110367 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 2 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype405 + + + + org.contikios.cooja.plugins.SimControl + 229 + 3 + 157 + 11 + 6 + + + org.contikios.cooja.plugins.Visualizer + + true + org.contikios.cooja.plugins.skins.IDVisualizerSkin + org.contikios.cooja.plugins.skins.UDGMVisualizerSkin + 1.1719333465234514 0.0 0.0 1.1719333465234514 -4.934308660658031 20.209777273580123 + + 234 + 1 + 257 + 10 + 170 + + + org.contikios.cooja.plugins.LogListener + + App + + + + 1074 + 0 + 713 + 844 + 3 + + + org.contikios.cooja.plugins.TimeLine + + 0 + 1 + + + + 140.4158108891898 + + 1920 + 2 + 384 + 1 + 716 + + + org.contikios.cooja.plugins.RadioLogger + + 407 + + false + false + + 595 + 4 + 706 + 245 + 4 + + diff --git a/examples/libs/ipv6-uipbuf/ipv6-uipbuf-sky.csc b/examples/libs/ipv6-uipbuf/ipv6-uipbuf-sky.csc new file mode 100644 index 000000000..30fc54e14 --- /dev/null +++ b/examples/libs/ipv6-uipbuf/ipv6-uipbuf-sky.csc @@ -0,0 +1,170 @@ + + + [APPS_DIR]/mrm + [APPS_DIR]/mspsim + [APPS_DIR]/avrora + [APPS_DIR]/serial_socket + [APPS_DIR]/powertracker + + IPv6 uipbuf Example + generated + 5000000 + + org.contikios.cooja.radiomediums.UDGM + 50.0 + 50.0 + 1.0 + 1.0 + + + 40000 + + + org.contikios.cooja.mspmote.SkyMoteType + sky1 + Sky Mote Type #sky1 + [CONTIKI_DIR]/examples/libs/ipv6-uipbuf/udp-server.c + make udp-server.sky TARGET=sky + [CONTIKI_DIR]/examples/libs/ipv6-uipbuf/udp-server.sky + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.interfaces.IPAddress + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + org.contikios.cooja.mspmote.interfaces.MspClock + org.contikios.cooja.mspmote.interfaces.MspMoteID + org.contikios.cooja.mspmote.interfaces.SkyButton + org.contikios.cooja.mspmote.interfaces.SkyFlash + org.contikios.cooja.mspmote.interfaces.SkyCoffeeFilesystem + org.contikios.cooja.mspmote.interfaces.Msp802154Radio + org.contikios.cooja.mspmote.interfaces.MspSerial + org.contikios.cooja.mspmote.interfaces.SkyLED + org.contikios.cooja.mspmote.interfaces.MspDebugOutput + org.contikios.cooja.mspmote.interfaces.SkyTemperature + + + org.contikios.cooja.mspmote.SkyMoteType + sky2 + Sky Mote Type #sky2 + [CONTIKI_DIR]/examples/libs/ipv6-uipbuf/udp-client.c + make udp-client.sky TARGET=sky + [CONTIKI_DIR]/examples/libs/ipv6-uipbuf/udp-client.sky + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.interfaces.IPAddress + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + org.contikios.cooja.mspmote.interfaces.MspClock + org.contikios.cooja.mspmote.interfaces.MspMoteID + org.contikios.cooja.mspmote.interfaces.SkyButton + org.contikios.cooja.mspmote.interfaces.SkyFlash + org.contikios.cooja.mspmote.interfaces.SkyCoffeeFilesystem + org.contikios.cooja.mspmote.interfaces.Msp802154Radio + org.contikios.cooja.mspmote.interfaces.MspSerial + org.contikios.cooja.mspmote.interfaces.SkyLED + org.contikios.cooja.mspmote.interfaces.MspDebugOutput + org.contikios.cooja.mspmote.interfaces.SkyTemperature + + + + + org.contikios.cooja.interfaces.Position + 30.051578821079996 + -64.69428746901113 + 0.0 + + + org.contikios.cooja.mspmote.interfaces.MspClock + 1.0 + + + org.contikios.cooja.mspmote.interfaces.MspMoteID + 1 + + sky1 + + + + + org.contikios.cooja.interfaces.Position + 21.31366587648077 + -34.91404431659299 + 0.0 + + + org.contikios.cooja.mspmote.interfaces.MspClock + 1.0 + + + org.contikios.cooja.mspmote.interfaces.MspMoteID + 2 + + sky2 + + + + org.contikios.cooja.plugins.SimControl + 249 + 4 + 184 + 3 + 15 + + + org.contikios.cooja.plugins.Visualizer + + org.contikios.cooja.plugins.skins.IDVisualizerSkin + org.contikios.cooja.plugins.skins.UDGMVisualizerSkin + org.contikios.cooja.plugins.skins.AttributeVisualizerSkin + 1.3598488697820064 0.0 0.0 1.3598488697820064 6.142207908179105 118.20877091196155 + + 234 + 1 + 227 + 14 + 210 + + + org.contikios.cooja.plugins.LogListener + + + + + + 1011 + 0 + 556 + 759 + 7 + + + org.contikios.cooja.plugins.TimeLine + + 0 + 1 + + + + 681.712557066089 + + 1804 + 3 + 352 + 0 + 567 + + + org.contikios.cooja.plugins.RadioLogger + + 150 + + false + false + + 500 + 2 + 546 + 259 + 12 + + diff --git a/examples/libs/ipv6-uipbuf/project-conf.h b/examples/libs/ipv6-uipbuf/project-conf.h new file mode 100644 index 000000000..dfbf0d329 --- /dev/null +++ b/examples/libs/ipv6-uipbuf/project-conf.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018, RISE SICS. + * 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. + */ + +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ + +/* Include max MAC Tx in the IPv6 Traffic Class field */ +#define UIP_CONF_TAG_TC_WITH_VARIABLE_RETRANSMISSIONS 1 + +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/libs/ipv6-uipbuf/udp-client.c b/examples/libs/ipv6-uipbuf/udp-client.c new file mode 100644 index 000000000..bee1cda83 --- /dev/null +++ b/examples/libs/ipv6-uipbuf/udp-client.c @@ -0,0 +1,85 @@ +#include "contiki.h" +#include "net/routing/routing.h" +#include "random.h" +#include "net/netstack.h" +#include "net/ipv6/simple-udp.h" + +#include "sys/log.h" +#define LOG_MODULE "App" +#define LOG_LEVEL LOG_LEVEL_INFO + +#define WITH_SERVER_REPLY 1 +#define UDP_CLIENT_PORT 8765 +#define UDP_SERVER_PORT 5678 + +static struct simple_udp_connection udp_conn; + +#define START_INTERVAL (15 * CLOCK_SECOND) +#define SEND_INTERVAL (60 * CLOCK_SECOND) + +static struct simple_udp_connection udp_conn; + +/*---------------------------------------------------------------------------*/ +PROCESS(udp_client_process, "UDP client"); +AUTOSTART_PROCESSES(&udp_client_process); +/*---------------------------------------------------------------------------*/ +static void +udp_rx_callback(struct simple_udp_connection *c, + const uip_ipaddr_t *sender_addr, + uint16_t sender_port, + const uip_ipaddr_t *receiver_addr, + uint16_t receiver_port, + const uint8_t *data, + uint16_t datalen) +{ + unsigned count = *(unsigned *)data; + /* If tagging of traffic class is enabled tc will print number of + transmission - otherwise it will be 0 */ + LOG_INFO("Received response %u (Max MAC Tx: %d) from ", count, + uipbuf_get_attr(UIPBUF_ATTR_MAX_MAC_TRANSMISSIONS)); + LOG_INFO_6ADDR(sender_addr); + LOG_INFO_("\n"); +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(udp_client_process, ev, data) +{ + static struct etimer periodic_timer; + static unsigned count; + uip_ipaddr_t dest_ipaddr; + + PROCESS_BEGIN(); + + /* Initialize UDP connection */ + simple_udp_register(&udp_conn, UDP_CLIENT_PORT, NULL, + UDP_SERVER_PORT, udp_rx_callback); + + etimer_set(&periodic_timer, random_rand() % SEND_INTERVAL); + while(1) { + PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&periodic_timer)); + + if(NETSTACK_ROUTING.node_is_reachable() && NETSTACK_ROUTING.get_root_ipaddr(&dest_ipaddr)) { + /* Set the number of transmissions to use for this packet - + this can be used to create more reliable transmissions or + less reliable than the default. Works end-to-end if + UIP_CONF_TAG_TC_WITH_VARIABLE_RETRANSMISSIONS is set to 1. + */ + uipbuf_set_attr(UIPBUF_ATTR_MAX_MAC_TRANSMISSIONS, 1 + count % 5); + /* Send to DAG root */ + LOG_INFO("Sending request %u (Max MAC Tx: %d) to ", count, + uipbuf_get_attr(UIPBUF_ATTR_MAX_MAC_TRANSMISSIONS)); + LOG_INFO_6ADDR(&dest_ipaddr); + LOG_INFO_("\n"); + simple_udp_sendto(&udp_conn, &count, sizeof(count), &dest_ipaddr); + count++; + } else { + LOG_INFO("Not reachable yet\n"); + } + + /* Add some jitter */ + etimer_set(&periodic_timer, SEND_INTERVAL + - CLOCK_SECOND + (random_rand() % (2 * CLOCK_SECOND))); + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/examples/libs/ipv6-uipbuf/udp-server.c b/examples/libs/ipv6-uipbuf/udp-server.c new file mode 100644 index 000000000..288a0cba9 --- /dev/null +++ b/examples/libs/ipv6-uipbuf/udp-server.c @@ -0,0 +1,84 @@ +/* + * 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. + * + */ + +#include "contiki.h" +#include "net/routing/routing.h" +#include "net/netstack.h" +#include "net/ipv6/simple-udp.h" + +#include "sys/log.h" +#define LOG_MODULE "App" +#define LOG_LEVEL LOG_LEVEL_INFO + +#define WITH_SERVER_REPLY 1 +#define UDP_CLIENT_PORT 8765 +#define UDP_SERVER_PORT 5678 + +static struct simple_udp_connection udp_conn; + +PROCESS(udp_server_process, "UDP server"); +AUTOSTART_PROCESSES(&udp_server_process); +/*---------------------------------------------------------------------------*/ +static void +udp_rx_callback(struct simple_udp_connection *c, + const uip_ipaddr_t *sender_addr, + uint16_t sender_port, + const uip_ipaddr_t *receiver_addr, + uint16_t receiver_port, + const uint8_t *data, + uint16_t datalen) +{ + unsigned count = *(unsigned *)data; + LOG_INFO("Received request %u (Max MAC Tx: %d) from ", count, + uipbuf_get_attr(UIPBUF_ATTR_MAX_MAC_TRANSMISSIONS)); + LOG_INFO_6ADDR(sender_addr); + LOG_INFO_("\n"); +#if WITH_SERVER_REPLY + LOG_INFO("Sending response %u (Max MAC Tx: %d) to ", count, + uipbuf_get_attr(UIPBUF_ATTR_MAX_MAC_TRANSMISSIONS)); + LOG_INFO_6ADDR(sender_addr); + LOG_INFO_("\n"); + simple_udp_sendto(&udp_conn, &count, sizeof(count), sender_addr); +#endif /* WITH_SERVER_REPLY */ +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(udp_server_process, ev, data) +{ + PROCESS_BEGIN(); + + /* Initialize DAG root */ + NETSTACK_ROUTING.root_start(); + + /* Initialize UDP connection */ + simple_udp_register(&udp_conn, UDP_SERVER_PORT, NULL, + UDP_CLIENT_PORT, udp_rx_callback); + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ From af3f1a05f80465c52b189a9642c473778c129ca7 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sun, 13 May 2018 05:04:03 -0700 Subject: [PATCH 077/485] Link-stats no-ACK penalty: add to actual tx count rather than use a fixed number --- os/net/link-stats.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/os/net/link-stats.c b/os/net/link-stats.c index fbb7677da..8ec372f4e 100644 --- a/os/net/link-stats.c +++ b/os/net/link-stats.c @@ -63,8 +63,8 @@ /* 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 20 +/* In case of no-ACK, add ETX_NOACK_PENALTY to the real Tx count, as a penalty */ +#define ETX_NOACK_PENALTY 12 /* Initial ETX value */ #define ETX_DEFAULT 2 @@ -156,9 +156,13 @@ link_stats_packet_sent(const linkaddr_t *lladdr, int status, int numtx) stats->last_tx_time = clock_time(); stats->freshness = MIN(stats->freshness + numtx, FRESHNESS_MAX); + /* Add penalty in case of no-ACK */ + if(status == MAC_TX_NOACK) { + numtx += ETX_NOACK_PENALTY; + } + #if LINK_STATS_ETX_FROM_PACKET_COUNT /* Compute ETX from packet and ACK count */ - numtx = (status == MAC_TX_NOACK) ? ETX_NOACK_PENALTY : numtx; /* Halve both counter after TX_COUNT_MAX */ if(stats->tx_count + numtx > TX_COUNT_MAX) { stats->tx_count /= 2; @@ -179,7 +183,7 @@ link_stats_packet_sent(const linkaddr_t *lladdr, int status, int numtx) /* Compute ETX using an EWMA */ /* ETX used for this update */ - packet_etx = ((status == MAC_TX_NOACK) ? ETX_NOACK_PENALTY : numtx) * ETX_DIVISOR; + packet_etx = numtx * ETX_DIVISOR; /* ETX alpha used for this update */ ewma_alpha = link_stats_is_fresh(stats) ? EWMA_ALPHA : EWMA_BOOTSTRAP_ALPHA; From e99f2a73d638b78a034873dddf7d0d0c1fd6570e Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Mon, 14 May 2018 08:32:40 -0700 Subject: [PATCH 078/485] Added CI compile test of example ipv6-uipbuf (platform Zoul) --- tests/03-compile-arm-ports-02/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/03-compile-arm-ports-02/Makefile b/tests/03-compile-arm-ports-02/Makefile index db016afaa..defd10a96 100644 --- a/tests/03-compile-arm-ports-02/Makefile +++ b/tests/03-compile-arm-ports-02/Makefile @@ -34,6 +34,7 @@ libs/timers/zoul \ libs/energest/zoul \ libs/trickle-library/zoul \ libs/data-structures/zoul \ +libs/ipv6-uipbuf/zoul \ nullnet/zoul \ slip-radio/zoul \ dev/gpio-hal/zoul:BOARD=remote-reva \ From c89a513ad17ee3d030545795be740937a53408da Mon Sep 17 00:00:00 2001 From: kkrentz Date: Mon, 14 May 2018 05:38:52 -0700 Subject: [PATCH 079/485] uip-ds6.c: Avoid compilation warning --- os/net/ipv6/uip-ds6.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/os/net/ipv6/uip-ds6.c b/os/net/ipv6/uip-ds6.c index 879f47881..4e82b3745 100644 --- a/os/net/ipv6/uip-ds6.c +++ b/os/net/ipv6/uip-ds6.c @@ -91,7 +91,9 @@ static uip_ds6_maddr_t *locmaddr; static uip_ds6_aaddr_t *locaaddr; #endif /* UIP_DS6_AADDR_NB */ static uip_ds6_prefix_t *locprefix; +#if (UIP_LLADDR_LEN == 2) static const uint8_t iid_prefix[] = { 0x00, 0x00 , 0x00 , 0xff , 0xfe , 0x00 }; +#endif /* (UIP_LLADDR_LEN == 2) */ /*---------------------------------------------------------------------------*/ void From 15a3f32b293eda508da0da05409a7ffc0739c53a Mon Sep 17 00:00:00 2001 From: kkrentz Date: Mon, 14 May 2018 09:22:07 -0700 Subject: [PATCH 080/485] Do not warn us about unused constants --- Makefile.include | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.include b/Makefile.include index 4de7e7dbb..c11aea699 100644 --- a/Makefile.include +++ b/Makefile.include @@ -49,6 +49,7 @@ CFLAGS += -DCONTIKI_BOARD_$(TARGET_BOARD_UPPERCASE)=1 CFLAGS += -DCONTIKI_BOARD_STRING=\"$(BOARD)\" endif +CFLAGS += -Wno-unused-const-variable LDFLAGS = -Wl,--fatal-warnings MODULES += os os/sys os/dev os/lib os/services From 92018b0df02fdac4f39d3d27293c5521653fd2ff Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Mon, 14 May 2018 13:45:37 -0700 Subject: [PATCH 081/485] RPL Native Border Router: fix SLIP bug that may occur whenever there is more bytes left in tx buffer than what we just sent --- os/services/rpl-border-router/native/slip-dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/services/rpl-border-router/native/slip-dev.c b/os/services/rpl-border-router/native/slip-dev.c index 63b6f1638..7ea764836 100644 --- a/os/services/rpl-border-router/native/slip-dev.c +++ b/os/services/rpl-border-router/native/slip-dev.c @@ -336,7 +336,7 @@ slip_flushbuf(int fd) if(slip_begin == slip_packet_end) { slip_packet_count--; if(slip_end > slip_packet_end) { - memcpy(slip_buf, slip_buf + slip_packet_end, + memmove(slip_buf, slip_buf + slip_packet_end, slip_end - slip_packet_end); } slip_end -= slip_packet_end; From 5d7b4410d525287416ae1dd3751ab1d9b6c93390 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Mon, 14 May 2018 13:46:07 -0700 Subject: [PATCH 082/485] Add native border router fragmentation test --- .../17-tun-rpl-br/09-native-border-router-cooja-frag.sh | 9 +++++++++ tests/17-tun-rpl-br/test-native-border-router.sh | 8 +++++++- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100755 tests/17-tun-rpl-br/09-native-border-router-cooja-frag.sh diff --git a/tests/17-tun-rpl-br/09-native-border-router-cooja-frag.sh b/tests/17-tun-rpl-br/09-native-border-router-cooja-frag.sh new file mode 100755 index 000000000..b1aa1351b --- /dev/null +++ b/tests/17-tun-rpl-br/09-native-border-router-cooja-frag.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +# Contiki directory +CONTIKI=$1 + +# Simulation file +BASENAME=07-native-border-router-cooja + +bash test-native-border-router.sh $CONTIKI $BASENAME fd00::204:4:4:4 60 600 2 diff --git a/tests/17-tun-rpl-br/test-native-border-router.sh b/tests/17-tun-rpl-br/test-native-border-router.sh index 38dce1bae..636b6b973 100644 --- a/tests/17-tun-rpl-br/test-native-border-router.sh +++ b/tests/17-tun-rpl-br/test-native-border-router.sh @@ -12,6 +12,12 @@ IPADDR=$3 # Time allocated for convergence WAIT_TIME=$4 +# Payload len. Default is ping6's default, 56. +PING_SIZE=${5:-56} + +# Inter-ping delay. Default is ping6's default, 1s. +PING_DELAY=${6:-1} + # ICMP request-reply count COUNT=5 @@ -30,7 +36,7 @@ sleep $WAIT_TIME # Do ping echo "Pinging" -ping6 $IPADDR -c $COUNT | tee $BASENAME.scriptlog +ping6 $IPADDR -c $COUNT -s $PING_SIZE -i $PING_DELAY | tee $BASENAME.scriptlog # Fetch ping6 status code (not $? because this is piped) STATUS=${PIPESTATUS[0]} REPLIES=`grep -c 'icmp_seq=' $BASENAME.scriptlog` From 2cb4e275996f0bd24a4ea0bf666ba20e1575961b Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Tue, 15 May 2018 00:50:24 +0200 Subject: [PATCH 083/485] Added a configurable linker flag to enable linker warnings as errors since OSX requires a diffent linker flag. --- Makefile.include | 7 ++++++- arch/cpu/native/Makefile.native | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Makefile.include b/Makefile.include index c11aea699..de0606ad4 100644 --- a/Makefile.include +++ b/Makefile.include @@ -50,7 +50,12 @@ CFLAGS += -DCONTIKI_BOARD_STRING=\"$(BOARD)\" endif CFLAGS += -Wno-unused-const-variable -LDFLAGS = -Wl,--fatal-warnings + +LDFLAGS_WERROR ?= -Wl,--fatal-warnings + +ifeq ($(WERROR),1) + LDFLAGS += $(LDFLAGS_WERROR) +endif MODULES += os os/sys os/dev os/lib os/services diff --git a/arch/cpu/native/Makefile.native b/arch/cpu/native/Makefile.native index af7328b31..d7832d358 100644 --- a/arch/cpu/native/Makefile.native +++ b/arch/cpu/native/Makefile.native @@ -22,6 +22,7 @@ CFLAGS += $(CFLAGSNO) ifeq ($(HOST_OS),Darwin) AROPTS = -rc +LDFLAGS_WERROR := -Wl,-fatal_warnings LDFLAGS += -Wl,-flat_namespace,-map,$(CONTIKI_NG_PROJECT_MAP) CFLAGS += -DHAVE_SNPRINTF=1 -U__ASSERT_USE_STDERR else From ce22b0b518db71e3b457f96970b84d05a6354f8a Mon Sep 17 00:00:00 2001 From: Rehan MALAK Date: Tue, 24 Apr 2018 13:55:40 +0200 Subject: [PATCH 084/485] warning-- : excess elements in struct initializer make -C "examples/platform-specific/cc26xx/ble-ipv6" \ TARGET=srf06-cc26xx BOARD=sensortag/cc2650 --- os/net/mac/ble/ble-l2cap.c | 1 - 1 file changed, 1 deletion(-) diff --git a/os/net/mac/ble/ble-l2cap.c b/os/net/mac/ble/ble-l2cap.c index f12fbb369..076d919e8 100644 --- a/os/net/mac/ble/ble-l2cap.c +++ b/os/net/mac/ble/ble-l2cap.c @@ -512,7 +512,6 @@ const struct mac_driver ble_l2cap_driver = { input, on, off, - NULL, }; /*---------------------------------------------------------------------------*/ PROCESS_THREAD(ble_l2cap_tx_process, ev, data) From 555242c8c23beeeab72f7d0251809bfac7d10d94 Mon Sep 17 00:00:00 2001 From: Rehan MALAK Date: Tue, 24 Apr 2018 14:17:28 +0200 Subject: [PATCH 085/485] warning-- : defined but not used make -C "examples/ip64-router" \ TARGET=zoul BOARD=orion --- os/services/ip64/ip64-arp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/os/services/ip64/ip64-arp.c b/os/services/ip64/ip64-arp.c index 5f3cff29a..75197558d 100644 --- a/os/services/ip64/ip64-arp.c +++ b/os/services/ip64/ip64-arp.c @@ -94,7 +94,6 @@ struct arp_entry { static const struct ip64_eth_addr broadcast_ethaddr = {{0xff,0xff,0xff,0xff,0xff,0xff}}; -static const uint16_t broadcast_ipaddr[2] = {0xffff,0xffff}; static struct arp_entry arp_table[UIP_ARPTAB_SIZE]; From 8cae7a9a9131496eb24cf173503edafd6b7863b5 Mon Sep 17 00:00:00 2001 From: Rehan MALAK Date: Thu, 26 Apr 2018 18:27:23 +0200 Subject: [PATCH 086/485] Fix neighbor discovery bug return value of memcmp is positive or negative or null and should not be cast in an uint8_t make -C "tests/09-ipv6" works now on 64bits --- os/net/ipv6/uip-nd6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/net/ipv6/uip-nd6.c b/os/net/ipv6/uip-nd6.c index 7a5724308..87869145b 100644 --- a/os/net/ipv6/uip-nd6.c +++ b/os/net/ipv6/uip-nd6.c @@ -530,7 +530,7 @@ na_input(void) if(nd6_opt_llao != NULL) { is_llchange = memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], lladdr, - UIP_LLADDR_LEN); + UIP_LLADDR_LEN) ? 1 : 0; } if(nbr->state == NBR_INCOMPLETE) { if(nd6_opt_llao == NULL || !extract_lladdr_from_llao_aligned(&lladdr_aligned)) { From 29061e9885d963db30c43b90ad737701d045bf40 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 15 May 2018 12:04:39 -0700 Subject: [PATCH 087/485] Rework uiplib_ipaddr_snprint, and use it from logging module and shell --- os/net/ipv6/uiplib.c | 101 +++++++++++++------------------------- os/net/ipv6/uiplib.h | 20 ++++---- os/services/shell/shell.c | 33 ++----------- os/sys/log.c | 33 ++----------- 4 files changed, 51 insertions(+), 136 deletions(-) diff --git a/os/net/ipv6/uiplib.c b/os/net/ipv6/uiplib.c index afe6de42b..b83bfe05c 100644 --- a/os/net/ipv6/uiplib.c +++ b/os/net/ipv6/uiplib.c @@ -3,17 +3,17 @@ * 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. + * 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. The name of the author may not be used to endorse or promote * products derived from this software without specific prior - * written permission. + * written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -25,7 +25,7 @@ * 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. + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This file is part of the uIP TCP/IP stack and the Contiki operating system. * @@ -117,7 +117,7 @@ uiplib_ip6addrconv(const char *addrstr, uip_ip6addr_t *ipaddr) } #endif /* NETSTACK_CONF_WITH_IPV6 */ /*---------------------------------------------------------------------------*/ -/* Parse a IPv4-address from a string. Returns the number of characters read +/* Parse a IPv4-address from a string. Returns the number of characters read * for the address. */ int uiplib_ip4addrconv(const char *addrstr, uip_ip4addr_t *ipaddr) @@ -156,48 +156,9 @@ uiplib_ip4addrconv(const char *addrstr, uip_ip4addr_t *ipaddr) void uiplib_ipaddr_print(const uip_ipaddr_t *addr) { - uint16_t a; - unsigned int i; - int f; - - if(addr == NULL) { - printf("(NULL IP addr)"); - return; - } - - if(ip64_addr_is_ipv4_mapped_addr(addr)) { - /* - * Printing IPv4-mapped addresses is done according to RFC 4291 [1] - * - * "An alternative form that is sometimes more - * convenient when dealing with a mixed environment - * of IPv4 and IPv6 nodes is x:x:x:x:x:x:d.d.d.d, - * where the 'x's are the hexadecimal values of the - * six high-order 16-bit pieces of the address, and - * the 'd's are the decimal values of the four - * low-order 8-bit pieces of the address (standard - * IPv4 representation)." - * - * [1] https://tools.ietf.org/html/rfc4291#page-4 - */ - printf("::FFFF:%u.%u.%u.%u", addr->u8[12], addr->u8[13], addr->u8[14], addr->u8[15]); - } else { - for(i = 0, f = 0; i < sizeof(uip_ipaddr_t); i += 2) { - a = (addr->u8[i] << 8) + addr->u8[i + 1]; - if(a == 0 && f >= 0) { - if(f++ == 0) { - printf("::"); - } - } else { - if(f > 0) { - f = -1; - } else if(i > 0) { - printf(":"); - } - printf("%x", a); - } - } - } + char buf[40]; + uiplib_ipaddr_snprint(buf, sizeof(buf), addr); + printf("%s", buf); } /*---------------------------------------------------------------------------*/ int @@ -205,15 +166,16 @@ uiplib_ipaddr_snprint(char *buf, size_t size, const uip_ipaddr_t *addr) { uint16_t a; unsigned int i; - int f, n; + int f; + int n = 0; if(size == 0) { return 0; } if(addr == NULL) { - n = snprintf(buf, size - 1, "(NULL IP addr)"); - + n = snprintf(buf, size, "(NULL IP addr)"); + return n; } else if(ip64_addr_is_ipv4_mapped_addr(addr)) { /* * Printing IPv4-mapped addresses is done according to RFC 4291 [1] @@ -229,32 +191,35 @@ uiplib_ipaddr_snprint(char *buf, size_t size, const uip_ipaddr_t *addr) * * [1] https://tools.ietf.org/html/rfc4291#page-4 */ - n = snprintf(buf, size - 1, "::FFFF:%u.%u.%u.%u", addr->u8[12], + n = snprintf(buf, size, "::FFFF:%u.%u.%u.%u", addr->u8[12], addr->u8[13], addr->u8[14], addr->u8[15]); + return n; } else { - for(n = 0, i = 0, f = 0; i < sizeof(uip_ipaddr_t) && n < size - 1; i += 2) { + for(i = 0, f = 0; i < sizeof(uip_ipaddr_t); i += 2) { a = (addr->u8[i] << 8) + addr->u8[i + 1]; if(a == 0 && f >= 0) { if(f++ == 0) { - buf[n++] = ':'; - buf[n++] = ':'; + n += snprintf(buf+n, size-n, "::"); + if(n >= size) { + return n; + } } } else { if(f > 0) { f = -1; } else if(i > 0) { - buf[n++] = ':'; + n += snprintf(buf+n, size-n, ":"); + if(n >= size) { + return n; + } + } + n += snprintf(buf+n, size-n, "%x", a); + if(n >= size) { + return n; } - n += snprintf(&buf[n], size - n - 1, "%x", a); } } } - - /* - * Make sure the output string is always null-terminated. - */ - buf[MIN(n, size - 1)] = '\0'; - return n; } /*---------------------------------------------------------------------------*/ diff --git a/os/net/ipv6/uiplib.h b/os/net/ipv6/uiplib.h index 6a122033e..a09ae9671 100644 --- a/os/net/ipv6/uiplib.h +++ b/os/net/ipv6/uiplib.h @@ -1,19 +1,19 @@ /* * Copyright (c) 2002, Adam Dunkels. - * 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. + * 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. + * with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior - * written permission. + * written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -25,7 +25,7 @@ * 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. + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This file is part of the Contiki desktop environment for the C64. * @@ -65,7 +65,7 @@ * the numerical representation of the address. * * \retval 0 If the IP address could not be parsed. - * \retval Non-zero If the IP address was parsed. + * \retval Non-zero If the IP address was parsed. */ #if NETSTACK_CONF_WITH_IPV6 #define uiplib_ipaddrconv uiplib_ip6addrconv diff --git a/os/services/shell/shell.c b/os/services/shell/shell.c index 1e344dc1a..6788e5235 100644 --- a/os/services/shell/shell.c +++ b/os/services/shell/shell.c @@ -50,40 +50,15 @@ #include "shell-commands.h" #include "net/ipv6/uip.h" #include "net/ipv6/ip64-addr.h" +#include "net/ipv6/uiplib.h" /*---------------------------------------------------------------------------*/ void shell_output_6addr(shell_output_func output, const uip_ipaddr_t *ipaddr) { - uint16_t a; - unsigned int i; - int f; - - if(ipaddr == NULL) { - SHELL_OUTPUT(output, "(NULL IP addr)"); - return; - } - - if(ip64_addr_is_ipv4_mapped_addr(ipaddr)) { - /* Printing IPv4-mapped addresses is done according to RFC 4291 */ - SHELL_OUTPUT(output, "::FFFF:%u.%u.%u.%u", ipaddr->u8[12], ipaddr->u8[13], ipaddr->u8[14], ipaddr->u8[15]); - } else { - for(i = 0, f = 0; i < sizeof(uip_ipaddr_t); i += 2) { - a = (ipaddr->u8[i] << 8) + ipaddr->u8[i + 1]; - if(a == 0 && f >= 0) { - if(f++ == 0) { - SHELL_OUTPUT(output, "::"); - } - } else { - if(f > 0) { - f = -1; - } else if(i > 0) { - SHELL_OUTPUT(output, ":"); - } - SHELL_OUTPUT(output, "%x", a); - } - } - } + char buf[40]; + uiplib_ipaddr_snprint(buf, sizeof(buf), ipaddr); + SHELL_OUTPUT(output, "%s", buf); } /*---------------------------------------------------------------------------*/ void diff --git a/os/sys/log.c b/os/sys/log.c index 05613e5c6..c237bd097 100644 --- a/os/sys/log.c +++ b/os/sys/log.c @@ -50,6 +50,7 @@ #include "sys/log.h" #include "net/ipv6/ip64-addr.h" +#include "net/ipv6/uiplib.h" int curr_log_level_rpl = LOG_CONF_LEVEL_RPL; int curr_log_level_tcpip = LOG_CONF_LEVEL_TCPIP; @@ -84,35 +85,9 @@ struct log_module all_modules[] = { void log_6addr(const uip_ipaddr_t *ipaddr) { - uint16_t a; - unsigned int i; - int f; - - if(ipaddr == NULL) { - LOG_OUTPUT("(NULL IP addr)"); - return; - } - - if(ip64_addr_is_ipv4_mapped_addr(ipaddr)) { - /* Printing IPv4-mapped addresses is done according to RFC 4291 */ - LOG_OUTPUT("::FFFF:%u.%u.%u.%u", ipaddr->u8[12], ipaddr->u8[13], ipaddr->u8[14], ipaddr->u8[15]); - } else { - for(i = 0, f = 0; i < sizeof(uip_ipaddr_t); i += 2) { - a = (ipaddr->u8[i] << 8) + ipaddr->u8[i + 1]; - if(a == 0 && f >= 0) { - if(f++ == 0) { - LOG_OUTPUT("::"); - } - } else { - if(f > 0) { - f = -1; - } else if(i > 0) { - LOG_OUTPUT(":"); - } - LOG_OUTPUT("%x", a); - } - } - } + char buf[40]; + uiplib_ipaddr_snprint(buf, sizeof(buf), ipaddr); + LOG_OUTPUT("%s", buf); } /*---------------------------------------------------------------------------*/ void From 97a9d7707c2dfcd69f4d7c013af7c4ae480a749d Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 15 May 2018 12:05:29 -0700 Subject: [PATCH 088/485] Introduce rpl_neighbor_snprint, for consistent printing of a RPL neighbor to a string --- os/net/routing/rpl-lite/rpl-neighbor.c | 83 ++++++++++++++++++-------- os/net/routing/rpl-lite/rpl-neighbor.h | 11 ++++ 2 files changed, 68 insertions(+), 26 deletions(-) diff --git a/os/net/routing/rpl-lite/rpl-neighbor.c b/os/net/routing/rpl-lite/rpl-neighbor.c index bd0632778..b33e4dad7 100644 --- a/os/net/routing/rpl-lite/rpl-neighbor.c +++ b/os/net/routing/rpl-lite/rpl-neighbor.c @@ -46,6 +46,7 @@ #include "net/routing/rpl-lite/rpl.h" #include "net/link-stats.h" #include "net/nbr-table.h" +#include "net/ipv6/uiplib.h" /* Log configuration */ #include "sys/log.h" @@ -85,6 +86,59 @@ acceptable_rank(rpl_rank_t rank) && rank <= max_acceptable_rank(); } /*---------------------------------------------------------------------------*/ +int +rpl_neighbor_snprint(char *buf, int buflen, rpl_nbr_t *nbr) +{ + int index = 0; + rpl_nbr_t *best = best_parent(0); + const struct link_stats *stats = rpl_neighbor_get_link_stats(nbr); + clock_time_t clock_now = clock_time(); + + index += snprintf(buf+index, buflen-index, "nbr: "); + if(index >= buflen) { + return index; + } + index += uiplib_ipaddr_snprint(buf+index, buflen-index, rpl_neighbor_get_ipaddr(nbr)); + if(index >= buflen) { + return index; + } + index += snprintf(buf+index, buflen-index, + "%5u, %5u => %5u -- %2u %c%c%c%c%c", + nbr->rank, + rpl_neighbor_get_link_metric(nbr), + rpl_neighbor_rank_via_nbr(nbr), + stats != NULL ? stats->freshness : 0, + (nbr->rank == ROOT_RANK) ? 'r' : ' ', + nbr == best ? 'b' : ' ', + (acceptable_rank(rpl_neighbor_rank_via_nbr(nbr)) && rpl_neighbor_is_acceptable_parent(nbr)) ? 'a' : ' ', + link_stats_is_fresh(stats) ? 'f' : ' ', + nbr == curr_instance.dag.preferred_parent ? 'p' : ' ' + ); + if(index >= buflen) { + return index; + } + if(stats->last_tx_time > 0) { + index += snprintf(buf+index, buflen-index, + " (last tx %u min ago", + (unsigned)((clock_now - stats->last_tx_time) / (60 * CLOCK_SECOND))); + } else { + index += snprintf(buf+index, buflen-index, + " (no tx"); + } + if(index >= buflen) { + return index; + } + if(nbr->better_parent_since > 0) { + index += snprintf(buf+index, buflen-index, + ", better since %u min)", + (unsigned)((clock_now - nbr->better_parent_since) / (60 * CLOCK_SECOND))); + } else { + index += snprintf(buf+index, buflen-index, + ")"); + } + return index; +} +/*---------------------------------------------------------------------------*/ void rpl_neighbor_print_list(const char *str) { @@ -92,8 +146,6 @@ rpl_neighbor_print_list(const char *str) int curr_dio_interval = curr_instance.dag.dio_intcurrent; int curr_rank = curr_instance.dag.rank; rpl_nbr_t *nbr = nbr_table_head(rpl_neighbors); - rpl_nbr_t *best = best_parent(0); - clock_time_t clock_now = clock_time(); LOG_INFO("nbr: own state, addr "); LOG_INFO_6ADDR(rpl_get_global_address()); @@ -103,30 +155,9 @@ rpl_neighbor_print_list(const char *str) max_acceptable_rank(), curr_dio_interval, rpl_neighbor_count(), str); while(nbr != NULL) { - const struct link_stats *stats = rpl_neighbor_get_link_stats(nbr); - LOG_INFO("nbr: "); - LOG_INFO_6ADDR(rpl_neighbor_get_ipaddr(nbr)); - LOG_INFO_(" %5u, %5u => %5u -- %2u %c%c%c%c%c", - nbr->rank, - rpl_neighbor_get_link_metric(nbr), - rpl_neighbor_rank_via_nbr(nbr), - stats != NULL ? stats->freshness : 0, - (nbr->rank == ROOT_RANK) ? 'r' : ' ', - nbr == best ? 'b' : ' ', - (acceptable_rank(rpl_neighbor_rank_via_nbr(nbr)) && rpl_neighbor_is_acceptable_parent(nbr)) ? 'a' : ' ', - link_stats_is_fresh(stats) ? 'f' : ' ', - nbr == curr_instance.dag.preferred_parent ? 'p' : ' ' - ); - if(stats->last_tx_time > 0) { - LOG_INFO_(" (last tx %u min ago", (unsigned)((clock_now - stats->last_tx_time) / (60 * CLOCK_SECOND))); - } else { - LOG_INFO_(" (no tx"); - } - if(nbr->better_parent_since > 0) { - LOG_INFO_(", better since %u min)\n", (unsigned)((clock_now - nbr->better_parent_since) / (60 * CLOCK_SECOND))); - } else { - LOG_INFO_(")\n"); - } + char buf[120]; + rpl_neighbor_snprint(buf, sizeof(buf), nbr); + LOG_INFO("%s\n", buf); nbr = nbr_table_next(rpl_neighbors, nbr); } LOG_INFO("nbr: end of list\n"); diff --git a/os/net/routing/rpl-lite/rpl-neighbor.h b/os/net/routing/rpl-lite/rpl-neighbor.h index 028d089c7..aee409a83 100644 --- a/os/net/routing/rpl-lite/rpl-neighbor.h +++ b/os/net/routing/rpl-lite/rpl-neighbor.h @@ -192,6 +192,17 @@ void rpl_neighbor_remove_all(void); */ rpl_nbr_t *rpl_neighbor_select_best(void); +/** +* Print a textual description of RPL neighbor into a string +* +* \param buf The buffer where to write content +* \param len The buffer len +* \param addr A pointer to a RPL neighbor that will be written to the buffer +* \return Identical to snprintf: number of bytes written excluding ending null +* byte. A value >= buflen if the buffer was too small. +*/ +int rpl_neighbor_snprint(char *buf, int buflen, rpl_nbr_t *nbr); + typedef rpl_nbr_t rpl_parent_t; #define rpl_parent_get_from_ipaddr(addr) rpl_neighbor_get_from_ipaddr(addr) #define rpl_parent_get_ipaddr(nbr) rpl_neighbor_get_ipaddr(nbr) From e301df95139f0621af2cd72cbc35604dc3367d81 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 15 May 2018 12:21:51 -0700 Subject: [PATCH 089/485] Added shell command rpl-nbr --- os/services/shell/shell-commands.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/os/services/shell/shell-commands.c b/os/services/shell/shell-commands.c index 3dbce09f2..fedbc06c6 100644 --- a/os/services/shell/shell-commands.c +++ b/os/services/shell/shell-commands.c @@ -146,6 +146,27 @@ rpl_ocp_to_str(int ocp) } /*---------------------------------------------------------------------------*/ static +PT_THREAD(cmd_rpl_nbr(struct pt *pt, shell_output_func output, char *args)) +{ + PT_BEGIN(pt); + + if(!curr_instance.used || rpl_neighbor_count() == 0) { + SHELL_OUTPUT(output, "RPL neighbors: none\n"); + } else { + rpl_nbr_t *nbr = nbr_table_head(rpl_neighbors); + SHELL_OUTPUT(output, "RPL neighbors:\n"); + while(nbr != NULL) { + char buf[120]; + rpl_neighbor_snprint(buf, sizeof(buf), nbr); + SHELL_OUTPUT(output, "%s\n", buf); + nbr = nbr_table_next(rpl_neighbors, nbr); + } + } + + PT_END(pt); +} +/*---------------------------------------------------------------------------*/ +static PT_THREAD(cmd_rpl_status(struct pt *pt, shell_output_func output, char *args)) { PT_BEGIN(pt); @@ -745,6 +766,7 @@ struct shell_command_t shell_commands[] = { #endif /* UIP_CONF_IPV6_RPL */ #if ROUTING_CONF_RPL_LITE { "rpl-status", cmd_rpl_status, "'> rpl-status': Shows a summary of the current RPL state" }, + { "rpl-nbr", cmd_rpl_nbr, "'> rpl-nbr': Shows the RPL neighbor table" }, #endif /* ROUTING_CONF_RPL_LITE */ { "routes", cmd_routes, "'> routes': Shows the route entries" }, #if MAC_CONF_WITH_TSCH From 5eaaa4d6b6c8f0b88888b06d573d4e75c5e23a3b Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 15 May 2018 13:12:03 -0700 Subject: [PATCH 090/485] Doxygen fixes --- os/net/routing/rpl-lite/rpl-neighbor.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/os/net/routing/rpl-lite/rpl-neighbor.h b/os/net/routing/rpl-lite/rpl-neighbor.h index aee409a83..31ed02cd2 100644 --- a/os/net/routing/rpl-lite/rpl-neighbor.h +++ b/os/net/routing/rpl-lite/rpl-neighbor.h @@ -196,8 +196,8 @@ rpl_nbr_t *rpl_neighbor_select_best(void); * Print a textual description of RPL neighbor into a string * * \param buf The buffer where to write content -* \param len The buffer len -* \param addr A pointer to a RPL neighbor that will be written to the buffer +* \param buflen The buffer len +* \param nbr A pointer to a RPL neighbor that will be written to the buffer * \return Identical to snprintf: number of bytes written excluding ending null * byte. A value >= buflen if the buffer was too small. */ From ff1f57509a627afb43de07c377697ef342faab04 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 15 May 2018 13:39:49 -0700 Subject: [PATCH 091/485] Introduce UIPLIB_IPV6_MAX_STR_LEN --- os/net/ipv6/uiplib.c | 2 +- os/net/ipv6/uiplib.h | 4 ++++ os/services/shell/shell.c | 2 +- os/sys/log.c | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/os/net/ipv6/uiplib.c b/os/net/ipv6/uiplib.c index b83bfe05c..cd6d15c8b 100644 --- a/os/net/ipv6/uiplib.c +++ b/os/net/ipv6/uiplib.c @@ -156,7 +156,7 @@ uiplib_ip4addrconv(const char *addrstr, uip_ip4addr_t *ipaddr) void uiplib_ipaddr_print(const uip_ipaddr_t *addr) { - char buf[40]; + char buf[UIPLIB_IPV6_MAX_STR_LEN]; uiplib_ipaddr_snprint(buf, sizeof(buf), addr); printf("%s", buf); } diff --git a/os/net/ipv6/uiplib.h b/os/net/ipv6/uiplib.h index a09ae9671..3a935f51b 100644 --- a/os/net/ipv6/uiplib.h +++ b/os/net/ipv6/uiplib.h @@ -82,6 +82,10 @@ int uiplib_ip6addrconv(const char *addrstr, uip_ip6addr_t *addr); * @{ */ +/* The maxium length of an IPv6 string, including terminating null bytes + * fd01:0002:0003:0004:0005:0006:0007:0008 => 39 + 1 bytes */ +#define UIPLIB_IPV6_MAX_STR_LEN 40 + /** * Print an IP address using printf(). * diff --git a/os/services/shell/shell.c b/os/services/shell/shell.c index 6788e5235..fcf419880 100644 --- a/os/services/shell/shell.c +++ b/os/services/shell/shell.c @@ -56,7 +56,7 @@ void shell_output_6addr(shell_output_func output, const uip_ipaddr_t *ipaddr) { - char buf[40]; + char buf[UIPLIB_IPV6_MAX_STR_LEN]; uiplib_ipaddr_snprint(buf, sizeof(buf), ipaddr); SHELL_OUTPUT(output, "%s", buf); } diff --git a/os/sys/log.c b/os/sys/log.c index c237bd097..9a02087a2 100644 --- a/os/sys/log.c +++ b/os/sys/log.c @@ -85,7 +85,7 @@ struct log_module all_modules[] = { void log_6addr(const uip_ipaddr_t *ipaddr) { - char buf[40]; + char buf[UIPLIB_IPV6_MAX_STR_LEN]; uiplib_ipaddr_snprint(buf, sizeof(buf), ipaddr); LOG_OUTPUT("%s", buf); } From 38c372b222a915bfce6eb527e0fe4378ef2afc19 Mon Sep 17 00:00:00 2001 From: Rehan MALAK Date: Thu, 17 May 2018 15:43:35 +0200 Subject: [PATCH 092/485] ignore files produced during coap-lwm2m tests --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index a67ff3f50..f59be6e16 100644 --- a/.gitignore +++ b/.gitignore @@ -58,6 +58,8 @@ COOJA.testlog *.err summary tests/[0-9][0-9]-*/org/ +tests/18-coap-lwm2m/Californium.properties +tests/18-coap-lwm2m/leshan-server-demo-1.0.0-SNAPSHOT-jar-with-dependencies.jar # x86 UEFI files cpu/x86/uefi/Makefile.uefi From dc46ae20331f78a0fae0dda963742ddde7b0a622 Mon Sep 17 00:00:00 2001 From: Rehan MALAK Date: Fri, 18 May 2018 00:57:26 +0200 Subject: [PATCH 093/485] better clarity of memcmp test --- os/net/ipv6/uip-nd6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/net/ipv6/uip-nd6.c b/os/net/ipv6/uip-nd6.c index 87869145b..2765c593d 100644 --- a/os/net/ipv6/uip-nd6.c +++ b/os/net/ipv6/uip-nd6.c @@ -530,7 +530,7 @@ na_input(void) if(nd6_opt_llao != NULL) { is_llchange = memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], lladdr, - UIP_LLADDR_LEN) ? 1 : 0; + UIP_LLADDR_LEN) == 0 ? 0 : 1; } if(nbr->state == NBR_INCOMPLETE) { if(nd6_opt_llao == NULL || !extract_lladdr_from_llao_aligned(&lladdr_aligned)) { From 90b5d2a1499bd6e4afa10bc2de97c3886ee2fba6 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 18 May 2018 15:05:24 +0100 Subject: [PATCH 094/485] Differentiate flash part across sensortag/cc2650 versions Older CC2650 sensortags have a Winbond W25X40CL 4MBit SPI flash. Newer ones have a Macronix MX25R8035F 8MBit part. The parts have almost identical instruction sets and are both supported by our generic external flash driver. The key difference between the two parts is that they have different Manufacturer and Device IDs. This commit allows us to switch between the two: We default to the new revision, and allow users to build for the older one by defining `SENSORTAG_CC2650_REV_1_2_0` to 1. Current tags are version 1.5.1. Older tags are version 1.2.0. To identify older tags, look for "Rev: 1.2" printed on the PCB. They should also have a sticker that reads "Rev: 1.3.0" and "HW Rev 1.2.0". --- arch/platform/srf06-cc26xx/sensortag/cc2650/board.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/platform/srf06-cc26xx/sensortag/cc2650/board.h b/arch/platform/srf06-cc26xx/sensortag/cc2650/board.h index 7da0e9458..dda3e46e5 100644 --- a/arch/platform/srf06-cc26xx/sensortag/cc2650/board.h +++ b/arch/platform/srf06-cc26xx/sensortag/cc2650/board.h @@ -149,8 +149,13 @@ #define EXT_FLASH_SPI_PIN_MISO 18 #define EXT_FLASH_SPI_PIN_CS 14 +#if SENSORTAG_CC2650_REV_1_2_0 +#define EXT_FLASH_DEVICE_ID 0x12 +#define EXT_FLASH_MID 0xEF +#else #define EXT_FLASH_DEVICE_ID 0x14 #define EXT_FLASH_MID 0xC2 +#endif #define EXT_FLASH_PROGRAM_PAGE_SIZE 256 #define EXT_FLASH_ERASE_SECTOR_SIZE 4096 From 4e5608ef7215da7a83ec73cad187d62030e9f5e8 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 18 May 2018 15:14:08 +0100 Subject: [PATCH 095/485] Allow easy-switch between tag versions for the cc26xx-web-demo --- .../cc26xx/cc26xx-web-demo/project-conf.h | 10 ++++++++++ 1 file changed, 10 insertions(+) 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 ccd0bf8fb..36114eeb7 100644 --- a/examples/platform-specific/cc26xx/cc26xx-web-demo/project-conf.h +++ b/examples/platform-specific/cc26xx/cc26xx-web-demo/project-conf.h @@ -53,6 +53,16 @@ */ #define CC26XX_WEB_DEMO_CONF_ADC_DEMO 0 /*---------------------------------------------------------------------------*/ +/* + * Change to 1 if you are using an older CC2650 Sensortag (look for Rev: 1.2 + * printed on the PCB, or for a sticker reading "HW Rev 1.2.0"). + * + * This may be the case if you are getting this error: + * "Could not open flash to load config" + * when your sensortag is starting up. + */ +#define SENSORTAG_CC2650_REV_1_2_0 0 +/*---------------------------------------------------------------------------*/ /* Enable the ROM bootloader */ #define ROM_BOOTLOADER_ENABLE 1 /*---------------------------------------------------------------------------*/ From c55dc06b33473eb260e6d2b88bab591f8333c2a5 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 18 May 2018 15:25:29 +0100 Subject: [PATCH 096/485] Update the cc26xx-web-demo readme --- .../cc26xx/cc26xx-web-demo/README.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/README.md b/examples/platform-specific/cc26xx/cc26xx-web-demo/README.md index 9a4617b3c..912fcb72a 100644 --- a/examples/platform-specific/cc26xx/cc26xx-web-demo/README.md +++ b/examples/platform-specific/cc26xx/cc26xx-web-demo/README.md @@ -10,11 +10,17 @@ demonstrate the CC26xx capability. The applications are: * A web server which can be used to display sensor readings but also to configure MQTT functionality -The example has been configured to run for all CC26xx-based boards: i) The -SensorTag 2.0 and ii) The Srf06EB with a CC26xx or CC13xx EM mounted on it. +The example has been configured to run for all CC26xx-based boards. -To change between target boards, follow the instructions in the platform's -REDME file. Do not forget to `make clean` when switching between the boards. +To change between target boards, follow the instructions in the wiki. +Do not forget to `make clean` when switching between the boards. + +Specifically for some older CC2650 SensorTags, you may also need to change +`project-conf.h` such that `SENSORTAG_CC2650_REV_1_2_0` is defined as 1. To +check if your sensortag is one of those older ones, look for "REV: 1.2" +printed on the PCB. There may also be a sticker that reads "HW Rev 1.2.0". An +indication that you may need to do this is if you get a "Could not open flash +to load config" error on device startup. You can disable some of those individual components by changing the respective defines in `project-conf.h`. For instance, to disable the CoAP functionality, From bc9934ee5a9cc511a10c9e383dd86229c58d0de0 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 18 May 2018 05:52:09 -0700 Subject: [PATCH 097/485] Implement function uip_sr_link_snprint --- os/net/ipv6/uip-sr.c | 46 ++++++++++++++++++++++++++++++++++++++++++++ os/net/ipv6/uip-sr.h | 11 +++++++++++ 2 files changed, 57 insertions(+) diff --git a/os/net/ipv6/uip-sr.c b/os/net/ipv6/uip-sr.c index 15b123552..a82491827 100644 --- a/os/net/ipv6/uip-sr.c +++ b/os/net/ipv6/uip-sr.c @@ -41,6 +41,7 @@ #include "contiki.h" #include "net/ipv6/uip-sr.h" +#include "net/ipv6/uiplib.h" #include "net/routing/routing.h" #include "lib/list.h" #include "lib/memb.h" @@ -246,4 +247,49 @@ uip_sr_free_all(void) num_nodes--; } } +/*---------------------------------------------------------------------------*/ +int +uip_sr_link_snprint(char *buf, int buflen, uip_sr_node_t *link) +{ + int index = 0; + uip_ipaddr_t child_ipaddr; + uip_ipaddr_t parent_ipaddr; + + NETSTACK_ROUTING.get_sr_node_ipaddr(&child_ipaddr, link); + NETSTACK_ROUTING.get_sr_node_ipaddr(&parent_ipaddr, link->parent); + + index += uiplib_ipaddr_snprint(buf+index, buflen-index, &child_ipaddr); + if(index >= buflen) { + return index; + } + + if(link->parent == NULL) { + index += snprintf(buf+index, buflen-index, " (DODAG root)"); + if(index >= buflen) { + return index; + } + } else { + index += snprintf(buf+index, buflen-index, " to "); + if(index >= buflen) { + return index; + } + index += uiplib_ipaddr_snprint(buf+index, buflen-index, &parent_ipaddr); + if(index >= buflen) { + return index; + } + } + if(link->lifetime != UIP_SR_INFINITE_LIFETIME) { + index += snprintf(buf+index, buflen-index, + " (lifetime: %lu seconds)", (unsigned long)link->lifetime); + if(index >= buflen) { + return index; + } + } else { + index += snprintf(buf+index, buflen-index, " (lifetime: infinite)"); + if(index >= buflen) { + return index; + } + } + return index; +} /** @} */ diff --git a/os/net/ipv6/uip-sr.h b/os/net/ipv6/uip-sr.h index 7224cea14..01ed57c1c 100644 --- a/os/net/ipv6/uip-sr.h +++ b/os/net/ipv6/uip-sr.h @@ -180,6 +180,17 @@ void uip_sr_init(void); */ void uip_sr_free_all(void); +/** +* Print a textual description of a source routing link +* +* \param buf The buffer where to write content +* \param buflen The buffer len +* \param link A pointer to the source routing link +* \return Identical to snprintf: number of bytes written excluding ending null +* byte. A value >= buflen if the buffer was too small. +*/ +int uip_sr_link_snprint(char *buf, int buflen, uip_sr_node_t *link); + /** @} */ #endif /* UIP_SR_H */ From 59e8d059c265c5487f23a2520a6d6ed44c6cd5fd Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 18 May 2018 05:52:33 -0700 Subject: [PATCH 098/485] RPL: print links at root periodically --- os/net/routing/rpl-lite/rpl-dag-root.c | 23 +++++++++++++++++++++++ os/net/routing/rpl-lite/rpl-dag-root.h | 6 ++++++ os/net/routing/rpl-lite/rpl-timers.c | 1 + 3 files changed, 30 insertions(+) diff --git a/os/net/routing/rpl-lite/rpl-dag-root.c b/os/net/routing/rpl-lite/rpl-dag-root.c index 0d5cebe92..c96fd6656 100644 --- a/os/net/routing/rpl-lite/rpl-dag-root.c +++ b/os/net/routing/rpl-lite/rpl-dag-root.c @@ -42,12 +42,35 @@ #include "net/routing/rpl-lite/rpl.h" #include "net/ipv6/uip-ds6-route.h" +#include "net/ipv6/uip-sr.h" /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "RPL" #define LOG_LEVEL LOG_LEVEL_RPL +/*---------------------------------------------------------------------------*/ +void +rpl_dag_root_print_links(const char *str) +{ + if(rpl_dag_root_is_root()) { + if(uip_sr_num_nodes() > 0) { + uip_sr_node_t *link; + /* Our routing links */ + LOG_INFO("links: %u routing links in total (%s)\n", uip_sr_num_nodes(), str); + link = uip_sr_node_head(); + while(link != NULL) { + char buf[100]; + uip_sr_link_snprint(buf, sizeof(buf), link); + LOG_INFO("links: %s\n", buf); + link = uip_sr_node_next(link); + } + LOG_INFO("links: end of list\n"); + } else { + LOG_INFO("No routing links\n"); + } + } +} /*---------------------------------------------------------------------------*/ static void set_global_address(uip_ipaddr_t *prefix, uip_ipaddr_t *iid) diff --git a/os/net/routing/rpl-lite/rpl-dag-root.h b/os/net/routing/rpl-lite/rpl-dag-root.h index af0048c4d..71b999765 100644 --- a/os/net/routing/rpl-lite/rpl-dag-root.h +++ b/os/net/routing/rpl-lite/rpl-dag-root.h @@ -63,6 +63,12 @@ int rpl_dag_root_start(void); * \return 1 if we are dag root, 0 otherwise */ int rpl_dag_root_is_root(void); +/** + * Prints a summary of all routing links + * + * \param str A descriptive text on the caller +*/ +void rpl_dag_root_print_links(const char *str); /** @} */ diff --git a/os/net/routing/rpl-lite/rpl-timers.c b/os/net/routing/rpl-lite/rpl-timers.c index 6fb00ca17..c41b92948 100644 --- a/os/net/routing/rpl-lite/rpl-timers.c +++ b/os/net/routing/rpl-lite/rpl-timers.c @@ -521,6 +521,7 @@ handle_periodic_timer(void *ptr) if(LOG_INFO_ENABLED) { rpl_neighbor_print_list("Periodic"); + rpl_dag_root_print_links("Periodic"); } ctimer_reset(&periodic_timer); From 96c3bff6a9086b071298994302513dc7a5a793ea Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 18 May 2018 05:52:55 -0700 Subject: [PATCH 099/485] Shell rpl-routes command: use uip_sr_link_snprint --- os/services/shell/shell-commands.c | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/os/services/shell/shell-commands.c b/os/services/shell/shell-commands.c index fedbc06c6..f2f036eda 100644 --- a/os/services/shell/shell-commands.c +++ b/os/services/shell/shell-commands.c @@ -615,24 +615,9 @@ PT_THREAD(cmd_routes(struct pt *pt, shell_output_func output, char *args)) SHELL_OUTPUT(output, "Routing links (%u in total):\n", uip_sr_num_nodes()); link = uip_sr_node_head(); while(link != NULL) { - uip_ipaddr_t child_ipaddr; - uip_ipaddr_t parent_ipaddr; - NETSTACK_ROUTING.get_sr_node_ipaddr(&child_ipaddr, link); - NETSTACK_ROUTING.get_sr_node_ipaddr(&parent_ipaddr, link->parent); - SHELL_OUTPUT(output, "-- "); - shell_output_6addr(output, &child_ipaddr); - if(link->parent == NULL) { - memset(&parent_ipaddr, 0, sizeof(parent_ipaddr)); - SHELL_OUTPUT(output, " (DODAG root)"); - } else { - SHELL_OUTPUT(output, " to "); - shell_output_6addr(output, &parent_ipaddr); - } - if(link->lifetime != UIP_SR_INFINITE_LIFETIME) { - SHELL_OUTPUT(output, " (lifetime: %lu seconds)\n", (unsigned long)link->lifetime); - } else { - SHELL_OUTPUT(output, " (lifetime: infinite)\n"); - } + char buf[100]; + uip_sr_link_snprint(buf, sizeof(buf), link); + SHELL_OUTPUT(output, "-- %s\n", buf); link = uip_sr_node_next(link); } } else { From d1940450873ea44232c00bb53cd5120171c9c17d Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 18 May 2018 05:53:22 -0700 Subject: [PATCH 100/485] rpl_neighbor_snprint: do not add prefix --- os/net/routing/rpl-lite/rpl-neighbor.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/os/net/routing/rpl-lite/rpl-neighbor.c b/os/net/routing/rpl-lite/rpl-neighbor.c index b33e4dad7..5f2f7f69a 100644 --- a/os/net/routing/rpl-lite/rpl-neighbor.c +++ b/os/net/routing/rpl-lite/rpl-neighbor.c @@ -94,10 +94,6 @@ rpl_neighbor_snprint(char *buf, int buflen, rpl_nbr_t *nbr) const struct link_stats *stats = rpl_neighbor_get_link_stats(nbr); clock_time_t clock_now = clock_time(); - index += snprintf(buf+index, buflen-index, "nbr: "); - if(index >= buflen) { - return index; - } index += uiplib_ipaddr_snprint(buf+index, buflen-index, rpl_neighbor_get_ipaddr(nbr)); if(index >= buflen) { return index; @@ -157,7 +153,7 @@ rpl_neighbor_print_list(const char *str) while(nbr != NULL) { char buf[120]; rpl_neighbor_snprint(buf, sizeof(buf), nbr); - LOG_INFO("%s\n", buf); + LOG_INFO("nbr: %s\n", buf); nbr = nbr_table_next(rpl_neighbors, nbr); } LOG_INFO("nbr: end of list\n"); From d744e8306af916b22d389f82a9f972df77e2f56b Mon Sep 17 00:00:00 2001 From: "carlosgp143@gmail.com" Date: Tue, 13 Mar 2018 09:34:11 +0100 Subject: [PATCH 101/485] Added Queue Mode implementation in LwM2M --- examples/ipso-objects/zoul/module-macros.h | 34 +++ examples/lwm2m-ipso-objects/Makefile | 3 + examples/lwm2m-ipso-objects/project-conf.h | 10 +- os/net/app-layer/coap/coap-observe.c | 14 + os/net/app-layer/coap/coap-observe.h | 2 + os/services/lwm2m/lwm2m-engine.c | 146 ++++++++- os/services/lwm2m/lwm2m-engine.h | 10 + os/services/lwm2m/lwm2m-notification-queue.c | 239 +++++++++++++++ os/services/lwm2m/lwm2m-notification-queue.h | 67 +++++ os/services/lwm2m/lwm2m-qmode-conf.h | 85 ++++++ os/services/lwm2m/lwm2m-qmode-object.c | 301 +++++++++++++++++++ os/services/lwm2m/lwm2m-qmode-object.h | 65 ++++ os/services/lwm2m/lwm2m-rd-client.c | 131 +++++++- os/services/lwm2m/lwm2m-rd-client.h | 9 + tests/01-compile-base/Makefile | 2 + tests/02-compile-arm-ports-01/Makefile | 2 + tests/03-compile-arm-ports-02/Makefile | 2 + 17 files changed, 1115 insertions(+), 7 deletions(-) create mode 100644 examples/ipso-objects/zoul/module-macros.h create mode 100644 os/services/lwm2m/lwm2m-notification-queue.c create mode 100644 os/services/lwm2m/lwm2m-notification-queue.h create mode 100644 os/services/lwm2m/lwm2m-qmode-conf.h create mode 100644 os/services/lwm2m/lwm2m-qmode-object.c create mode 100644 os/services/lwm2m/lwm2m-qmode-object.h diff --git a/examples/ipso-objects/zoul/module-macros.h b/examples/ipso-objects/zoul/module-macros.h new file mode 100644 index 000000000..5091ff08b --- /dev/null +++ b/examples/ipso-objects/zoul/module-macros.h @@ -0,0 +1,34 @@ +/* + * 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. + */ + +/*---------------------------------------------------------------------------*/ +/* Only sleep mode 1 on Zoul to enable full 32 KiB RAM */ +#define LPM_CONF_MAX_PM 1 +/*---------------------------------------------------------------------------*/ diff --git a/examples/lwm2m-ipso-objects/Makefile b/examples/lwm2m-ipso-objects/Makefile index 7fa79d1ee..c2cef2cfd 100644 --- a/examples/lwm2m-ipso-objects/Makefile +++ b/examples/lwm2m-ipso-objects/Makefile @@ -11,4 +11,7 @@ MODULES += os/services/lwm2m MODULES += os/services/ipso-objects CONTIKI=../.. +include $(CONTIKI)/Makefile.identify-target +MODULES_REL += $(TARGET) + include $(CONTIKI)/Makefile.include diff --git a/examples/lwm2m-ipso-objects/project-conf.h b/examples/lwm2m-ipso-objects/project-conf.h index a7ad8b3ea..affe626b0 100644 --- a/examples/lwm2m-ipso-objects/project-conf.h +++ b/examples/lwm2m-ipso-objects/project-conf.h @@ -30,9 +30,6 @@ #ifndef PROJECT_CONF_H_ #define PROJECT_CONF_H_ -/* No sleep on CC2538 to enable full 32 KiB RAM */ -#define LPM_CONF_ENABLE 0 - #ifdef BOARD_STRING #define LWM2M_DEVICE_MODEL_NUMBER BOARD_STRING #elif defined(CONTIKI_TARGET_WISMOTE) @@ -62,4 +59,11 @@ /* Enable client-side support for COAP observe */ #define COAP_OBSERVE_CLIENT 1 +/* Definitions to enable Queue Mode, include the dynamic adaptation and change the default parameters */ +/* #define LWM2M_Q_MODE_CONF_ENABLED 1 + #define LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION 1 + #define LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_AWAKE_TIME 2000 + #define LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_SLEEP_TIME 10000 + #define LWM2M_Q_MODE_CONF_DEFAULT_DYNAMIC_ADAPTATION_FLAG 1 */ + #endif /* PROJECT_CONF_H_ */ diff --git a/os/net/app-layer/coap/coap-observe.c b/os/net/app-layer/coap/coap-observe.c index 83f5edf4a..d6ef3887e 100644 --- a/os/net/app-layer/coap/coap-observe.c +++ b/os/net/app-layer/coap/coap-observe.c @@ -353,4 +353,18 @@ coap_observe_handler(coap_resource_t *resource, coap_message_t *coap_req, } } /*---------------------------------------------------------------------------*/ +uint8_t +coap_has_observers(char *path) +{ + coap_observer_t *obs = NULL; + + for(obs = (coap_observer_t *)list_head(observers_list); obs; + obs = obs->next) { + if((strncmp(obs->url, path, strlen(path))) == 0) { + return 1; + } + } + return 0; +} +/*---------------------------------------------------------------------------*/ /** @} */ diff --git a/os/net/app-layer/coap/coap-observe.h b/os/net/app-layer/coap/coap-observe.h index c276522c5..93898f954 100644 --- a/os/net/app-layer/coap/coap-observe.h +++ b/os/net/app-layer/coap/coap-observe.h @@ -80,5 +80,7 @@ void coap_notify_observers_sub(coap_resource_t *resource, const char *subpath); void coap_observe_handler(coap_resource_t *resource, coap_message_t *request, coap_message_t *response); +uint8_t coap_has_observers(char *path); + #endif /* COAP_OBSERVE_H_ */ /** @} */ diff --git a/os/services/lwm2m/lwm2m-engine.c b/os/services/lwm2m/lwm2m-engine.c index 6f2aeefd8..3c038deec 100644 --- a/os/services/lwm2m/lwm2m-engine.c +++ b/os/services/lwm2m/lwm2m-engine.c @@ -39,6 +39,7 @@ * \author * Joakim Eriksson * Niclas Finne + * Carlos Gonzalo Peces */ #include "lwm2m-engine.h" @@ -56,7 +57,6 @@ #include #include #include - #ifndef LWM2M_ENGINE_CLIENT_ENDPOINT_NAME #include "net/ipv6/uip-ds6.h" #endif /* LWM2M_ENGINE_CLIENT_ENDPOINT_NAME */ @@ -80,10 +80,24 @@ #define USE_RD_CLIENT 1 #endif /* LWM2M_ENGINE_CONF_USE_RD_CLIENT */ + +#if LWM2M_Q_MODE_ENABLED + /* Queue Mode is handled using the RD Client and the Q-Mode object */ +#define USE_RD_CLIENT 1 +/* Queue Mode dynamic adaptation masks */ +#define FIRST_REQUEST_MASK 0x01 +#define HANDLER_FROM_NOTIFICATION_MASK 0x02 +#endif + #if USE_RD_CLIENT #include "lwm2m-rd-client.h" #endif +#if LWM2M_Q_MODE_ENABLED +#include "lwm2m-qmode-object.h" +#include "lwm2m-notification-queue.h" +#endif + /* MACRO for getting out resource ID from resource array ID + flags */ #define RSC_ID(x) ((uint16_t)(x & 0xffff)) #define RSC_READABLE(x) ((x & LWM2M_RESOURCE_READ) > 0) @@ -129,6 +143,18 @@ static struct { /* in the future also a timeout */ } created; +#if LWM2M_Q_MODE_ENABLED +static uint8_t waked_up_by_notification; +/* For the dynamic adaptation of the awake time */ +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION +static uint8_t dynamic_adaptation_params = 0x00; /* bit0: first_request, bit1: handler from notification */ +static uint64_t previous_request_time; +static inline void clear_first_request(); +static inline uint8_t is_first_request(); +static inline void clear_handler_from_notification(); +static inline uint8_t get_handler_from_notification(); +#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ +#endif /* LWM2M_Q_MODE_ENABLED */ COAP_HANDLER(lwm2m_handler, lwm2m_handler_callback); LIST(object_list); @@ -554,6 +580,10 @@ lwm2m_engine_init(void) #if USE_RD_CLIENT lwm2m_rd_client_init(endpoint); #endif + +#if LWM2M_Q_MODE_ENABLED + lwm2m_q_object_init(); +#endif } /*---------------------------------------------------------------------------*/ /* @@ -1373,6 +1403,31 @@ lwm2m_handler_callback(coap_message_t *request, coap_message_t *response, context.inbuf->size = coap_get_payload(request, (const uint8_t **)&context.inbuf->buffer); context.inbuf->pos = 0; + /*If Queue Mode, restart the client awake timer */ +#if LWM2M_Q_MODE_ENABLED + if(lwm2m_rd_client_is_client_awake()) { + lwm2m_rd_client_restart_client_awake_timer(); + } + +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION + if(lwm2m_q_object_get_dynamic_adaptation_flag() && !get_handler_from_notification()) { + if(is_first_request()) { + previous_request_time = coap_timer_uptime(); + clear_first_request(); + }else{ + if(coap_timer_uptime()-previous_request_time >= 0) { + lwm2m_q_object_add_time_object(coap_timer_uptime()-previous_request_time); + + } + previous_request_time = coap_timer_uptime(); + } + } + if(get_handler_from_notification()) { + clear_handler_from_notification(); + } +#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ +#endif /* LWM2M_Q_MODE_ENABLED */ + /* Maybe this should be part of CoAP itself - this seems not to be working with the leshan server */ #define LWM2M_CONF_ENTITY_TOO_LARGE_BLOCK1 0 @@ -1632,14 +1687,99 @@ lwm2m_handler_callback(coap_message_t *request, coap_message_t *response, return COAP_HANDLER_STATUS_PROCESSED; } /*---------------------------------------------------------------------------*/ -void lwm2m_notify_object_observers(lwm2m_object_instance_t *obj, +static void +lwm2m_send_notification(char* path) +{ +#if LWM2M_Q_MODE_ENABLED && LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION + if(lwm2m_q_object_get_dynamic_adaptation_flag()){ + lwm2m_engine_set_handler_from_notification(); + } +#endif + coap_notify_observers_sub(NULL, path); +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_notify_object_observers(lwm2m_object_instance_t *obj, uint16_t resource) { char path[20]; /* 60000/60000/60000 */ if(obj != NULL) { snprintf(path, 20, "%d/%d/%d", obj->object_id, obj->instance_id, resource); - coap_notify_observers_sub(NULL, path); } + +#if LWM2M_Q_MODE_ENABLED + + if(coap_has_observers(path)) { + /* Client is sleeping -> add the notification to the list */ + if(!lwm2m_rd_client_is_client_awake()) { + lwm2m_notification_queue_add_notification_path(path); + + /* if it is the first notification -> wake up and send update */ + if(!waked_up_by_notification) { + waked_up_by_notification = 1; + lwm2m_rd_client_fsm_execute_q_mode_update(); + } + /* Client is awake -> send the notification */ + } else { + lwm2m_send_notification(path); + } + } +#else + lwm2m_send_notification(path); +#endif } /*---------------------------------------------------------------------------*/ +/* Queue Mode Support and dynamic adaptation of the client awake time */ +#if LWM2M_Q_MODE_ENABLED +uint8_t +lwm2m_engine_is_waked_up_by_notification() +{ + return waked_up_by_notification; +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_engine_clear_waked_up_by_notification() +{ + waked_up_by_notification = 0; +} +/*---------------------------------------------------------------------------*/ +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION +void +lwm2m_engine_set_first_request() +{ + dynamic_adaptation_params |= FIRST_REQUEST_MASK; +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_engine_set_handler_from_notification() +{ + dynamic_adaptation_params |= HANDLER_FROM_NOTIFICATION_MASK; +} +/*---------------------------------------------------------------------------*/ +static inline uint8_t +is_first_request() +{ + return dynamic_adaptation_params & FIRST_REQUEST_MASK; +} +/*---------------------------------------------------------------------------*/ +static inline uint8_t +get_handler_from_notification() +{ + return (dynamic_adaptation_params & HANDLER_FROM_NOTIFICATION_MASK) != 0; +} +/*---------------------------------------------------------------------------*/ +static inline void +clear_first_request() +{ + dynamic_adaptation_params &= ~FIRST_REQUEST_MASK; +} +/*---------------------------------------------------------------------------*/ +static inline void +clear_handler_from_notification() +{ + dynamic_adaptation_params &= ~HANDLER_FROM_NOTIFICATION_MASK; +} +#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ +#endif /* LWM2M_Q_MODE_ENABLED */ +/*---------------------------------------------------------------------------*/ /** @} */ diff --git a/os/services/lwm2m/lwm2m-engine.h b/os/services/lwm2m/lwm2m-engine.h index 62a667e99..61d0353af 100644 --- a/os/services/lwm2m/lwm2m-engine.h +++ b/os/services/lwm2m/lwm2m-engine.h @@ -39,12 +39,14 @@ * \author * Joakim Eriksson * Niclas Finne + * Carlos Gonzalo Peces */ #ifndef LWM2M_ENGINE_H #define LWM2M_ENGINE_H #include "lwm2m-object.h" +#include "lwm2m-qmode-conf.h" #define LWM2M_FLOAT32_BITS 10 #define LWM2M_FLOAT32_FRAC (1L << LWM2M_FLOAT32_BITS) @@ -114,6 +116,14 @@ void lwm2m_notify_object_observers(lwm2m_object_instance_t *obj, void lwm2m_engine_set_opaque_callback(lwm2m_context_t *ctx, lwm2m_write_opaque_callback cb); +#if LWM2M_Q_MODE_ENABLED +uint8_t lwm2m_engine_is_waked_up_by_notification(); +void lwm2m_engine_clear_waked_up_by_notification(); +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION +void lwm2m_engine_set_first_request(); +void lwm2m_engine_set_handler_from_notification(); +#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ +#endif /* LWM2M_Q_MODE_ENABLED */ #endif /* LWM2M_ENGINE_H */ /** @} */ diff --git a/os/services/lwm2m/lwm2m-notification-queue.c b/os/services/lwm2m/lwm2m-notification-queue.c new file mode 100644 index 000000000..c3150a879 --- /dev/null +++ b/os/services/lwm2m/lwm2m-notification-queue.c @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2017, 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. + */ + +/** + * \addtogroup lwm2m + * @{ + */ + +/** + * \file + * Implementation of functions to manage the queue of notifications + * \author + * Carlos Gonzalo Peces + */ +/*---------------------------------------------------------------------------*/ +#include "lwm2m-notification-queue.h" + +#if LWM2M_Q_MODE_ENABLED + +#include "lwm2m-qmode-object.h" +#include "lwm2m-engine.h" +#include "coap-engine.h" +#include "lib/memb.h" +#include "lib/list.h" +#include +#include +#include +#include + +/* Log configuration */ +#include "coap-log.h" +#define LOG_MODULE "lwm2m-notification-queue" +#define LOG_LEVEL LOG_LEVEL_LWM2M + +#ifdef LWM2M_NOTIFICATION_QUEUE_CONF_LENGTH +#define LWM2M_NOTIFICATION_QUEUE_LENGTH LWM2M_NOTIFICATION_QUEUE_CONF_LENGTH +#else +#define LWM2M_NOTIFICATION_QUEUE_LENGTH 3 +#endif + +/*---------------------------------------------------------------------------*/ +/* Queue to store the notifications in the period when the client has woken up, sent the update and it's waiting for the server response*/ +MEMB(notification_memb, notification_path_t, LWM2M_NOTIFICATION_QUEUE_LENGTH + 1); /* Length + 1 to allocate the new path to add */ +LIST(notification_paths_queue); +/*---------------------------------------------------------------------------*/ +void +lwm2m_notification_queue_init(void) +{ + list_init(notification_paths_queue); +} +/*---------------------------------------------------------------------------*/ +static void +reduce_path(notification_path_t *path_object, char *path) +{ + char *cut = strtok(path, "/"); + int i; + for(i = 0; i < 3; i++) { + if(cut != NULL) { + path_object->reduced_path[i] = (uint16_t)atoi(cut); + cut = strtok(NULL, "/"); + } else { + break; + } + } + path_object->level = i; +} +/*---------------------------------------------------------------------------*/ +static void +extend_path(notification_path_t *path_object, char *path) +{ + switch(path_object->level) { + case 1: + snprintf(path, sizeof(path) - 1, "%u", path_object->reduced_path[0]); + break; + case 2: + snprintf(path, sizeof(path) - 1, "%u/%u", path_object->reduced_path[0], path_object->reduced_path[1]); + break; + case 3: + snprintf(path, sizeof(path) - 1, "%u/%u/%u", path_object->reduced_path[0], path_object->reduced_path[1], path_object->reduced_path[2]); + break; + } +} +/*---------------------------------------------------------------------------*/ +static void +add_notification_path_object_ordered(notification_path_t *path) +{ + notification_path_t *iteration_path = (notification_path_t *)list_head(notification_paths_queue); + if(list_length(notification_paths_queue) == 0) { + list_add(notification_paths_queue, path); + } else if(path->level < iteration_path->level) { + list_push(notification_paths_queue, path); + } else if(memcmp((path->reduced_path), (iteration_path->reduced_path), (path->level) * sizeof(uint16_t)) <= 0) { + list_push(notification_paths_queue, path); + } else { + notification_path_t *previous_path = iteration_path; + while(iteration_path != NULL) { + if(path->level < iteration_path->level) { + path->next = iteration_path; + previous_path->next = path; + return; + } + if(memcmp((path->reduced_path), (iteration_path->reduced_path), (path->level) * sizeof(uint16_t)) <= 0) { + path->next = iteration_path; + previous_path->next = path; + return; + } + previous_path = iteration_path; + iteration_path = iteration_path->next; + } + list_add(notification_paths_queue, path); + } +} +/*---------------------------------------------------------------------------*/ +static void +remove_notification_path(notification_path_t *path) +{ + list_remove(notification_paths_queue, path); + memb_free(¬ification_memb, path); +} +/*---------------------------------------------------------------------------*/ +static void +notification_queue_remove_policy(uint16_t *reduced_path, uint8_t level) +{ + uint8_t path_removed_flag = 0; + + notification_path_t *path_object = NULL; + notification_path_t *iteration_path = NULL; + notification_path_t *previous = NULL; + notification_path_t *next_next = NULL; + notification_path_t *path_to_remove = NULL; + + for(iteration_path = (notification_path_t *)list_head(notification_paths_queue); iteration_path != NULL; + iteration_path = iteration_path->next) { + /* 1. check if there is one event of the same path -> remove it and add the new one */ + if((level == iteration_path->level) && memcmp(iteration_path->reduced_path, reduced_path, level * sizeof(uint16_t)) == 0) { + remove_notification_path(iteration_path); + path_object = memb_alloc(¬ification_memb); + memcpy(path_object->reduced_path, reduced_path, level * sizeof(uint16_t)); + path_object->level = level; + add_notification_path_object_ordered(path_object); + return; + } + /* 2. If there is no event of the same type, look for repeated events of the same resource and remove the oldest one */ + if(iteration_path->next != NULL && (iteration_path->level == iteration_path->next->level) + && (memcmp(iteration_path->reduced_path, (iteration_path->next)->reduced_path, iteration_path->level * sizeof(uint16_t)) == 0)) { + path_removed_flag = 1; + next_next = iteration_path->next->next; + path_to_remove = iteration_path->next; + previous = iteration_path; + } + } + /* 3. If there are no events for the same path, we remove a the oldest repeated event of another resource */ + if(path_removed_flag) { + memb_free(¬ification_memb, path_to_remove); + previous->next = next_next; + path_object = memb_alloc(¬ification_memb); + memcpy(path_object->reduced_path, reduced_path, level * sizeof(uint16_t)); + path_object->level = level; + add_notification_path_object_ordered(path_object); + } else { + /* 4. If all the events are from different resources, remove the last one */ + list_chop(notification_paths_queue); + path_object = memb_alloc(¬ification_memb); + memcpy(path_object->reduced_path, reduced_path, level * sizeof(uint16_t)); + path_object->level = level; + add_notification_path_object_ordered(path_object); + } + return; +} +/*---------------------------------------------------------------------------*/ +/* For adding objects to the list in an ordered way, depending on the path*/ +void +lwm2m_notification_queue_add_notification_path(char *path) +{ + notification_path_t *path_object = memb_alloc(¬ification_memb); + if(path_object == NULL) { + LOG_DBG("Could not allocate new notification in the queue\n"); + return; + } + reduce_path(path_object, path); + if(list_length(notification_paths_queue) >= LWM2M_NOTIFICATION_QUEUE_LENGTH) { + /* The queue is full, apply policy to remove */ + notification_queue_remove_policy(path_object->reduced_path, path_object->level); + } else { + add_notification_path_object_ordered(path_object); + } + LOG_DBG("Notification path added to the list: %s\n", path); +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_notification_queue_send_notifications() +{ + char path[20]; + notification_path_t *iteration_path = (notification_path_t *)list_head(notification_paths_queue); + notification_path_t *aux = iteration_path; + + while(iteration_path != NULL) { + extend_path(iteration_path, path); +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION + if(lwm2m_q_object_get_dynamic_adaptation_flag()) { + lwm2m_engine_set_handler_from_notification(); + } +#endif + LOG_DBG("Sending stored notification with path: %s\n", path); + coap_notify_observers_sub(NULL, path); + aux = iteration_path; + iteration_path = iteration_path->next; + remove_notification_path(aux); + } +} +#endif /* LWM2M_Q_MODE_ENABLED */ +/** @} */ \ No newline at end of file diff --git a/os/services/lwm2m/lwm2m-notification-queue.h b/os/services/lwm2m/lwm2m-notification-queue.h new file mode 100644 index 000000000..3364d3a77 --- /dev/null +++ b/os/services/lwm2m/lwm2m-notification-queue.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2017, 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. + */ + +/** + * \addtogroup lwm2m + * @{ + */ + +/** + * \file + * Header file for functions to manage the queue of notifications + * \author + * Carlos Gonzalo Peces + */ + +#ifndef LWM2M_NOTIFICATION_QUEUE_H +#define LWM2M_NOTIFICATION_QUEUE_H + +#include "contiki.h" +#include "lwm2m-qmode-conf.h" + +#if LWM2M_Q_MODE_ENABLED +#include + +typedef struct notification_path { + struct notification_path *next; + uint16_t reduced_path[3]; + uint8_t level; /* The depth level of the path: 1. object, 2. object/instance, 3. object/instance/resource */ +} notification_path_t; + +void lwm2m_notification_queue_init(void); + +/* For adding objects to the list in an ordered way, depending on the path*/ +void lwm2m_notification_queue_add_notification_path(char *path); + +void lwm2m_notification_queue_send_notifications(); + +#endif /* LWM2M_Q_MODE_ENABLED */ +#endif /* LWM2M_NOTIFICATION_QUEUE_H */ +/** @} */ \ No newline at end of file diff --git a/os/services/lwm2m/lwm2m-qmode-conf.h b/os/services/lwm2m/lwm2m-qmode-conf.h new file mode 100644 index 000000000..1220d0584 --- /dev/null +++ b/os/services/lwm2m/lwm2m-qmode-conf.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2017, 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. + */ + +/** + * \addtogroup lwm2m + * @{ + */ + +/** + * \file + * Queue Mode Configuration Parameters + * \author + * Carlos Gonzalo Peces + */ + +#ifndef LWM2M_QMODE_CONF_H +#define LWM2M_QMODE_CONF_H + +/* Enable the Queue Mode */ +#ifdef LWM2M_Q_MODE_CONF_ENABLED +#define LWM2M_Q_MODE_ENABLED LWM2M_Q_MODE_CONF_ENABLED +#else +#define LWM2M_Q_MODE_ENABLED 0 +#endif /* LWM2M_Q_MODE_CONF_ENABLED */ + +/* Default Sleeping Time */ +#ifdef LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_SLEEP_TIME +#define LWM2M_Q_MODE_DEFAULT_CLIENT_SLEEP_TIME LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_SLEEP_TIME +#else +#define LWM2M_Q_MODE_DEFAULT_CLIENT_SLEEP_TIME 10000 /* msec */ +#endif /* LWM2M_Q_MODE_DEFAULT_CLIENT_SLEEPING_TIME */ + +/* Default Awake Time */ +#ifdef LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_AWAKE_TIME +#define LWM2M_Q_MODE_DEFAULT_CLIENT_AWAKE_TIME LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_AWAKE_TIME +#else +#define LWM2M_Q_MODE_DEFAULT_CLIENT_AWAKE_TIME 5000 /* msec */ +#endif /* LWM2M_Q_MODE_DEFAULT_CLIENT_AWAKE_TIME */ + +/* Include the possibility to do the dynamic adaptation of the client awake time */ +#ifdef LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION +#define LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION +#else +#define LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION 0 /* not included */ +#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ + +/* Default value for the dynamic adaptation flag */ +#ifdef LWM2M_Q_MODE_CONF_DEFAULT_DYNAMIC_ADAPTATION_FLAG +#define LWM2M_Q_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG LWM2M_Q_MODE_CONF_DEFAULT_DYNAMIC_ADAPTATION_FLAG +#else +#define LWM2M_Q_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG 0 /* disabled */ +#endif /* LWM2M_Q_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG */ + +/* Length of the list of times for the dynamic adaptation */ +#define LWM2M_Q_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH 10 + +#endif /* LWM2M_QMODE_CONF_H */ +/** @} */ diff --git a/os/services/lwm2m/lwm2m-qmode-object.c b/os/services/lwm2m/lwm2m-qmode-object.c new file mode 100644 index 000000000..77a12e460 --- /dev/null +++ b/os/services/lwm2m/lwm2m-qmode-object.c @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2017, 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. + */ + +/** + * \addtogroup lwm2m + * @{ + */ + +/** + * \file + * Implementation of the Contiki OMA LWM2M Queue Object for managing the queue mode + * \author + * Carlos Gonzalo Peces + */ + +#include "lwm2m-qmode-object.h" + +#if LWM2M_Q_MODE_ENABLED + +#include "lwm2m-object.h" +#include "lwm2m-engine.h" +#include "lwm2m-rd-client.h" +#include "lib/memb.h" +#include "lib/list.h" +#include + +/* Log configuration */ +#include "coap-log.h" +#define LOG_MODULE "lwm2m-qmode-object" +#define LOG_LEVEL LOG_LEVEL_LWM2M + +#define LWM2M_Q_OBJECT_ID 6000 +#define LWM2M_AWAKE_TIME_ID 3000 +#define LWM2M_SLEEP_TIME_ID 3001 + +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION +#define LWM2M_DYNAMIC_ADAPTATION_FLAG_ID 3002 +#define UPDATE_WITH_MEAN 0 /* 1-mean time 0-maximum time */ +#endif + +static const lwm2m_resource_id_t resources[] = +{ RW(LWM2M_AWAKE_TIME_ID), + RW(LWM2M_SLEEP_TIME_ID), +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION + RW(LWM2M_DYNAMIC_ADAPTATION_FLAG_ID), +#endif +}; + +static uint16_t q_mode_awake_time = LWM2M_Q_MODE_DEFAULT_CLIENT_AWAKE_TIME; +static uint32_t q_mode_sleep_time = LWM2M_Q_MODE_DEFAULT_CLIENT_SLEEP_TIME; +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION +static uint8_t q_mode_dynamic_adaptation_flag = LWM2M_Q_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG; + +typedef struct time_object { + struct times_object *next; + uint64_t time; +} time_object_t; + +/* Window to save the times and do the dynamic adaptation of the awake time*/ +MEMB(times_memb, time_object_t, LWM2M_Q_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH); +LIST(time_object_list); + +#endif +/*---------------------------------------------------------------------------*/ +uint16_t +lwm2m_q_object_get_awake_time() +{ + LOG_DBG("Client Awake Time: %d ms\n", (int)q_mode_awake_time); + return q_mode_awake_time; +} +/*---------------------------------------------------------------------------*/ +static void +lwm2m_q_object_set_awake_time(uint16_t time) +{ + q_mode_awake_time = time; +} +/*---------------------------------------------------------------------------*/ +uint32_t +lwm2m_q_object_get_sleep_time() +{ + LOG_DBG("Client Sleep Time: %d ms\n", (int)q_mode_sleep_time); + return q_mode_sleep_time; +} +/*---------------------------------------------------------------------------*/ +static void +lwm2m_q_object_set_sleep_time(uint32_t time) +{ + q_mode_sleep_time = time; +} +/*---------------------------------------------------------------------------*/ +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION +uint8_t +lwm2m_q_object_get_dynamic_adaptation_flag() +{ + LOG_DBG("Dynamic Adaptation Flag: %d ms\n", (int)q_mode_dynamic_adaptation_flag); + return q_mode_dynamic_adaptation_flag; +} +/*---------------------------------------------------------------------------*/ +static void +lwm2m_q_object_set_dynamic_adaptation_flag(uint8_t flag) +{ + q_mode_dynamic_adaptation_flag = flag; +} +/*---------------------------------------------------------------------------*/ +#if !UPDATE_WITH_MEAN +static uint64_t +get_maximum_time() +{ + uint64_t max_time = 0; + time_object_t *iteration_time = NULL; + for(iteration_time = (time_object_t *)list_head(time_object_list); iteration_time; + iteration_time = (time_object_t *)iteration_time->next) { + + if(iteration_time->time > max_time) { + max_time = iteration_time->time; + } + } + return max_time; +} +#endif +/*---------------------------------------------------------------------------*/ +#if UPDATE_WITH_MEAN +static uint64_t +get_mean_time() +{ + uint64_t mean_time = 0; + time_object_t *iteration_time = NULL; + for(iteration_time = (time_object_t *)list_head(time_object_list); iteration_time; + (time_object_t *)iteration_time = iteration_time->next) { + + if(mean_time == 0) { + mean_time = iteration_time->time; + } else { + mean_time = (mean_time + iteration_time->time) / 2; + } + } + return mean_time; +} +#endif +/*---------------------------------------------------------------------------*/ +static void +update_awake_time() +{ +#if UPDATE_WITH_MEAN + uint64_t mean_time = get_mean_time(); + LOG_DBG("Dynamic Adaptation: updated awake time: %d ms\n", (int)mean_time); + lwm2m_q_object_set_awake_time(mean_time + (mean_time >> 1)); /* 50% margin */ + return; +#else + uint64_t max_time = get_maximum_time(); + LOG_DBG("Dynamic Adaptation: updated awake time: %d ms\n", (int)max_time); + lwm2m_q_object_set_awake_time(max_time + (max_time >> 1)); /* 50% margin */ + return; +#endif +} +/*---------------------------------------------------------------------------*/ +static void +remove_time_object(time_object_t *time_object) +{ + memb_free(×_memb, time_object); + list_remove(time_object_list, time_object); +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_q_object_add_time_object(uint64_t time) +{ + time_object_t *time_object; + time_object = memb_alloc(×_memb); + if(time_object != NULL) { + time_object->time = time; + list_add(time_object_list, time_object); + } else { + remove_time_object((time_object_t *)list_head(time_object_list)); + time_object = memb_alloc(×_memb); + time_object->time = time; + list_add(time_object_list, time_object); + } + update_awake_time(); +} +#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ +/*---------------------------------------------------------------------------*/ +static lwm2m_status_t +lwm2m_callback(lwm2m_object_instance_t *object, lwm2m_context_t *ctx) +{ + if(ctx->operation == LWM2M_OP_READ) { + switch(ctx->resource_id) { + case LWM2M_AWAKE_TIME_ID: + lwm2m_object_write_int(ctx, (int32_t)q_mode_awake_time); + return LWM2M_STATUS_OK; + case LWM2M_SLEEP_TIME_ID: + lwm2m_object_write_int(ctx, (int32_t)q_mode_sleep_time); + return LWM2M_STATUS_OK; +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION + case LWM2M_DYNAMIC_ADAPTATION_FLAG_ID: + lwm2m_object_write_int(ctx, (int32_t)q_mode_dynamic_adaptation_flag); + return LWM2M_STATUS_OK; +#endif + } + } else if(ctx->operation == LWM2M_OP_WRITE) { + switch(ctx->resource_id) { + int32_t value_read; + size_t len; + + case LWM2M_AWAKE_TIME_ID: + + len = lwm2m_object_read_int(ctx, ctx->inbuf->buffer, ctx->inbuf->size, + &value_read); + LOG_DBG("Client Awake Time write request value: %d\n", (int)value_read); + if(len == 0) { + LOG_WARN("FAIL: could not write awake time\n"); + return LWM2M_STATUS_WRITE_ERROR; + } else { + lwm2m_q_object_set_awake_time(value_read); + return LWM2M_STATUS_OK; + } + + case LWM2M_SLEEP_TIME_ID: + len = lwm2m_object_read_int(ctx, ctx->inbuf->buffer, ctx->inbuf->size, + &value_read); + LOG_DBG("Client Sleep Time write request value: %d\n", (int)value_read); + if(len == 0) { + LOG_WARN("FAIL: could not write sleep time\n"); + return LWM2M_STATUS_WRITE_ERROR; + } else { + lwm2m_q_object_set_sleep_time(value_read); + return LWM2M_STATUS_OK; + } +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION + case LWM2M_DYNAMIC_ADAPTATION_FLAG_ID: + len = lwm2m_object_read_int(ctx, ctx->inbuf->buffer, ctx->inbuf->size, + &value_read); + LOG_DBG("Dynamic Adaptation Flag request value: %d\n", (int)value_read); + if(len == 0) { + LOG_WARN("FAIL: could not write dynamic flag\n"); + return LWM2M_STATUS_WRITE_ERROR; + } else { + lwm2m_q_object_set_dynamic_adaptation_flag(value_read); + return LWM2M_STATUS_OK; + } +#endif + } + } + + return LWM2M_STATUS_OPERATION_NOT_ALLOWED; +} +/*---------------------------------------------------------------------------*/ +static lwm2m_object_instance_t queue_object = { + .object_id = LWM2M_Q_OBJECT_ID, + .instance_id = 0, + .resource_ids = resources, + .resource_count = sizeof(resources) / sizeof(lwm2m_resource_id_t), + .resource_dim_callback = NULL, + .callback = lwm2m_callback, +}; +/*---------------------------------------------------------------------------*/ +void +lwm2m_q_object_init(void) +{ + lwm2m_engine_add_object(&queue_object); +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_q_object_send_notifications() +{ + lwm2m_notify_object_observers(&queue_object, LWM2M_AWAKE_TIME_ID); + lwm2m_notify_object_observers(&queue_object, LWM2M_SLEEP_TIME_ID); +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION + lwm2m_notify_object_observers(&queue_object, LWM2M_DYNAMIC_ADAPTATION_FLAG_ID); +#endif +} +/*---------------------------------------------------------------------------*/ +#endif /* LWM2M_Q_MODE_ENABLED */ +/** @} */ + diff --git a/os/services/lwm2m/lwm2m-qmode-object.h b/os/services/lwm2m/lwm2m-qmode-object.h new file mode 100644 index 000000000..68427a59c --- /dev/null +++ b/os/services/lwm2m/lwm2m-qmode-object.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2017, 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. + */ + +/** + * \addtogroup oma-lwm2m + * @{ + */ + +/** + * \file + * Header file for the Contiki OMA LWM2M Queue Object for managing the queue mode + * \author + * Carlos Gonzalo Peces + */ + +#ifndef LWM2M_Q_OBJECT_H_ +#define LWM2M_Q_OBJECT_H_ + +#include "contiki.h" +#include "lwm2m-qmode-conf.h" + +#if LWM2M_Q_MODE_ENABLED +#include + +uint16_t lwm2m_q_object_get_awake_time(); +uint32_t lwm2m_q_object_get_sleep_time(); +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION +uint8_t lwm2m_q_object_get_dynamic_adaptation_flag(); +void lwm2m_q_object_add_time_object(uint64_t time); +#endif + +void lwm2m_q_object_send_notifications(); + +void lwm2m_q_object_init(void); + +#endif /* LWM2M_Q_MODE_ENABLED */ +#endif /* LWM2M_Q_OBJECT_H_ */ +/** @} */ diff --git a/os/services/lwm2m/lwm2m-rd-client.c b/os/services/lwm2m/lwm2m-rd-client.c index 03d21e33e..61273797a 100644 --- a/os/services/lwm2m/lwm2m-rd-client.c +++ b/os/services/lwm2m/lwm2m-rd-client.c @@ -41,6 +41,7 @@ * Joakim Eriksson * Niclas Finne * Joel Hoglund + * Carlos Gonzalo Peces */ #include "lwm2m-engine.h" @@ -57,6 +58,10 @@ #include #include #include +#if LWM2M_Q_MODE_ENABLED +#include "lwm2m-qmode-object.h" +#include "lwm2m-notification-queue.h" +#endif #if UIP_CONF_IPV6_RPL #include "rpl.h" @@ -100,6 +105,10 @@ static coap_message_t request[1]; /* This way the message can be treated as #define DEREGISTER_SENT 11 #define DEREGISTER_FAILED 12 #define DEREGISTERED 13 +#if LWM2M_Q_MODE_ENABLED +#define Q_MODE_AWAKE 14 +#define Q_MODE_SEND_UPDATE 15 +#endif #define FLAG_RD_DATA_DIRTY 0x01 #define FLAG_RD_DATA_UPDATE_TRIGGERED 0x02 @@ -121,6 +130,13 @@ static void (*rd_callback)(coap_request_state_t *state); static coap_timer_t block1_timer; +#if LWM2M_Q_MODE_ENABLED +static coap_timer_t q_mode_client_awake_timer; /* Timer to control the client awake time */ +static uint8_t q_mode_client_awake; /* 1 - client is awake, 0 - client is sleeping */ +static uint16_t q_mode_client_awake_time; /* The time to be awake */ +static void q_mode_awake_timer_callback(coap_timer_t *timer); /* Callback for the client awake timer */ +#endif + static void check_periodic_observations(); static void update_callback(coap_request_state_t *state); @@ -147,7 +163,8 @@ set_rd_data(coap_message_t *request) } /*---------------------------------------------------------------------------*/ static void -prepare_update(coap_message_t *request, int triggered) { +prepare_update(coap_message_t *request, int triggered) +{ coap_init_message(request, COAP_TYPE_CON, COAP_POST, 0); coap_set_header_uri_path(request, session_info.assigned_ep); @@ -423,7 +440,16 @@ registration_callback(coap_request_state_t *state) state->response->location_path_len); session_info.assigned_ep[state->response->location_path_len] = 0; /* if we decide to not pass the lt-argument on registration, we should force an initial "update" to register lifetime with server */ +#if LWM2M_Q_MODE_ENABLED +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION + if(lwm2m_q_object_get_dynamic_adaptation_flag()) { + lwm2m_engine_set_first_request(); + } +#endif + lwm2m_rd_client_fsm_execute_q_mode_awake(); /* Avoid 500 ms delay and move directly to the state*/ +#else rd_state = REGISTRATION_DONE; +#endif /* remember the last reg time */ last_update = coap_timer_uptime(); LOG_DBG_("Done (assigned EP='%s')!\n", session_info.assigned_ep); @@ -468,8 +494,23 @@ update_callback(coap_request_state_t *state) LOG_DBG_("Done!\n"); /* remember the last reg time */ last_update = coap_timer_uptime(); +#if LWM2M_Q_MODE_ENABLED + /* If it has been waked up by a notification, send the stored notifications in queue */ + if(lwm2m_engine_is_waked_up_by_notification()) { + + lwm2m_engine_clear_waked_up_by_notification(); + lwm2m_notification_queue_send_notifications(); + } +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION + if(lwm2m_q_object_get_dynamic_adaptation_flag()) { + lwm2m_engine_set_first_request(); + } +#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ + lwm2m_rd_client_fsm_execute_q_mode_awake(); /* Avoid 500 ms delay and move directly to the state*/ +#else rd_state = REGISTRATION_DONE; rd_flags &= ~FLAG_RD_DATA_UPDATE_TRIGGERED; +#endif /* LWM2M_Q_MODE_ENABLED */ } else { /* Possible error response codes are 4.00 Bad request & 4.04 Not Found */ LOG_DBG_("Failed with code %d. Retrying registration\n", @@ -516,7 +557,15 @@ periodic_process(coap_timer_t *timer) uint64_t now; /* reschedule the CoAP timer */ +#if LWM2M_Q_MODE_ENABLED + /* In Queue Mode, the machine is not executed periodically, but with the awake/sleeping times */ + if(!((rd_state & 0xF) == 0xE)) { + coap_timer_reset(&rd_timer, STATE_MACHINE_UPDATE_INTERVAL); + } +#else coap_timer_reset(&rd_timer, STATE_MACHINE_UPDATE_INTERVAL); +#endif + now = coap_timer_uptime(); LOG_DBG("RD Client - state: %d, ms: %lu\n", rd_state, @@ -685,6 +734,24 @@ periodic_process(coap_timer_t *timer) rd_state = UPDATE_SENT; } break; +#if LWM2M_Q_MODE_ENABLED + case Q_MODE_AWAKE: + LOG_DBG("Queue Mode: Client is AWAKE at %lu\n", (unsigned long)coap_timer_uptime()); + q_mode_client_awake = 1; + q_mode_client_awake_time = lwm2m_q_object_get_awake_time(); + coap_timer_set(&q_mode_client_awake_timer, q_mode_client_awake_time); + break; + case Q_MODE_SEND_UPDATE: +#if !STANDALONE + NETSTACK_MAC.on(); +#endif + prepare_update(request, rd_flags & FLAG_RD_DATA_UPDATE_TRIGGERED); + coap_send_request(&rd_request_state, &session_info.server_ep, request, + update_callback); + last_rd_progress = coap_timer_uptime(); + rd_state = UPDATE_SENT; + break; +#endif case UPDATE_SENT: /* just wait until the callback kicks us to the next state... */ @@ -718,15 +785,26 @@ lwm2m_rd_client_init(const char *ep) { session_info.ep = ep; /* default binding U = UDP, UQ = UDP Q-mode*/ +#if LWM2M_Q_MODE_ENABLED + session_info.binding = "UQ"; + session_info.lifetime = (LWM2M_Q_MODE_DEFAULT_CLIENT_SLEEP_TIME / 1000) * 2; /* Enough margin to ensure that the client is not unregistered (we + * do not know the time it can stay awake) + */ +#else session_info.binding = "U"; if(session_info.lifetime == 0) { session_info.lifetime = LWM2M_DEFAULT_CLIENT_LIFETIME; } +#endif + rd_state = INIT; /* call the RD client periodically */ coap_timer_set_callback(&rd_timer, periodic_process); coap_timer_set(&rd_timer, STATE_MACHINE_UPDATE_INTERVAL); +#if LWM2M_Q_MODE_ENABLED + coap_timer_set_callback(&q_mode_client_awake_timer, q_mode_awake_timer_callback); +#endif } /*---------------------------------------------------------------------------*/ static void @@ -735,4 +813,55 @@ check_periodic_observations(void) /* TODO */ } /*---------------------------------------------------------------------------*/ +/* + *Queue Mode Support + */ +#if LWM2M_Q_MODE_ENABLED +/*---------------------------------------------------------------------------*/ +void +lwm2m_rd_client_restart_client_awake_timer(void) +{ + coap_timer_set(&q_mode_client_awake_timer, q_mode_client_awake_time); +} +/*---------------------------------------------------------------------------*/ +uint8_t +lwm2m_rd_client_is_client_awake(void) +{ + return q_mode_client_awake; +} +/*---------------------------------------------------------------------------*/ +static void +q_mode_awake_timer_callback(coap_timer_t *timer) +{ + /* Timer has expired, no requests has been received, client can go to sleep */ + LOG_DBG("Queue Mode: Client is SLEEPING at %lu\n", (unsigned long)coap_timer_uptime()); + q_mode_client_awake = 0; +#if !STANDALONE + /* Turn off the radio and start sleeping timer. LPM will be entered since the radio + and the peripherals are off, and there is a sleep timer started for waking up */ + NETSTACK_MAC.off(); + rtimer_arch_schedule(RTIMER_NOW() + ((lwm2m_q_object_get_sleep_time() / 1000) * RTIMER_SECOND)); +#endif + rd_state = Q_MODE_SEND_UPDATE; + coap_timer_set(&rd_timer, lwm2m_q_object_get_sleep_time()); +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_rd_client_fsm_execute_q_mode_awake() +{ + coap_timer_stop(&rd_timer); + rd_state = Q_MODE_AWAKE; + periodic_process(&rd_timer); +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_rd_client_fsm_execute_q_mode_update() +{ + coap_timer_stop(&rd_timer); + rd_state = Q_MODE_SEND_UPDATE; + periodic_process(&rd_timer); +} +/*---------------------------------------------------------------------------*/ +#endif +/*---------------------------------------------------------------------------*/ /** @} */ diff --git a/os/services/lwm2m/lwm2m-rd-client.h b/os/services/lwm2m/lwm2m-rd-client.h index 7fba7e0ae..85946235d 100644 --- a/os/services/lwm2m/lwm2m-rd-client.h +++ b/os/services/lwm2m/lwm2m-rd-client.h @@ -40,6 +40,7 @@ * \author * Joakim Eriksson * Niclas Finne + * Carlos Gonzalo Peces */ #ifndef LWM2M_RD_CLIENT_H_ @@ -52,6 +53,7 @@ #define LWM2M_RD_CLIENT_DISCONNECTED 5 #include "lwm2m-object.h" +#include "lwm2m-qmode-conf.h" struct lwm2m_session_info; typedef void (*session_callback_t)(struct lwm2m_session_info *session, int status); @@ -75,6 +77,13 @@ void lwm2m_rd_client_init(const char *ep); void lwm2m_rd_client_set_session_callback(session_callback_t cb); +#if LWM2M_Q_MODE_ENABLED +uint8_t lwm2m_rd_client_is_client_awake(void); +void lwm2m_rd_client_restart_client_awake_timer(void); +void lwm2m_rd_client_fsm_execute_q_mode_awake(); +void lwm2m_rd_client_fsm_execute_q_mode_update(); +#endif + #ifndef LWM2M_RD_CLIENT_ASSIGNED_ENDPOINT_MAX_LEN #define LWM2M_RD_CLIENT_ASSIGNED_ENDPOINT_MAX_LEN 15 #endif /* LWM2M_RD_CLIENT_ASSIGNED_ENDPOINT_MAX_LEN */ diff --git a/tests/01-compile-base/Makefile b/tests/01-compile-base/Makefile index eae930138..d9ef0ba58 100644 --- a/tests/01-compile-base/Makefile +++ b/tests/01-compile-base/Makefile @@ -15,6 +15,8 @@ libs/data-structures/sky \ libs/stack-check/sky \ lwm2m-ipso-objects/native \ lwm2m-ipso-objects/native:MAKE_WITH_DTLS=1 \ +lwm2m-ipso-objects/native:DEFINES=LWM2M_Q_MODE_CONF_ENABLED=1 \ +lwm2m-ipso-objects/native:DEFINES=LWM2M_Q_MODE_CONF_ENABLED=1,LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION=1\ rpl-udp/sky \ rpl-border-router/native \ rpl-border-router/native:MAKE_ROUTING=MAKE_ROUTING_RPL_CLASSIC \ diff --git a/tests/02-compile-arm-ports-01/Makefile b/tests/02-compile-arm-ports-01/Makefile index 5e73c4ecb..4bb1e9269 100644 --- a/tests/02-compile-arm-ports-01/Makefile +++ b/tests/02-compile-arm-ports-01/Makefile @@ -43,6 +43,8 @@ coap/coap-example-client/cc2538dk \ coap/coap-example-server/cc2538dk \ slip-radio/cc2538dk \ lwm2m-ipso-objects/cc2538dk \ +lwm2m-ipso-objects/cc2538dk:DEFINES=LWM2M_Q_MODE_CONF_ENABLED=1 \ +lwm2m-ipso-objects/native:DEFINES=LWM2M_Q_MODE_CONF_ENABLED=1,LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION=1\ 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 defd10a96..62120eba3 100644 --- a/tests/03-compile-arm-ports-02/Makefile +++ b/tests/03-compile-arm-ports-02/Makefile @@ -17,6 +17,8 @@ coap/coap-example-server/zoul \ multicast/zoul \ lwm2m-ipso-objects/zoul \ lwm2m-ipso-objects/zoul:MAKE_WITH_DTLS=1 \ +lwm2m-ipso-objects/zoul:DEFINES=LWM2M_Q_MODE_CONF_ENABLED=1 \ +lwm2m-ipso-objects/zoul:DEFINES=LWM2M_Q_MODE_CONF_ENABLED=1,LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION=1\ hello-world/zoul \ sensniff/zoul \ sensniff/zoul:ZOUL_CONF_SUB_GHZ_SNIFFER=1 \ From 1f8754766a751c3f9c548340ca361577acd43269 Mon Sep 17 00:00:00 2001 From: "carlosgp143@gmail.com" Date: Fri, 6 Apr 2018 15:16:42 +0200 Subject: [PATCH 102/485] Added macros for defining wake up/sleep behaviour depending on the platform --- examples/ipso-objects/zoul/module-macros.h | 16 ++++++- os/services/lwm2m/lwm2m-rd-client.c | 52 +++++++++++++--------- 2 files changed, 45 insertions(+), 23 deletions(-) diff --git a/examples/ipso-objects/zoul/module-macros.h b/examples/ipso-objects/zoul/module-macros.h index 5091ff08b..4db4e82fe 100644 --- a/examples/ipso-objects/zoul/module-macros.h +++ b/examples/ipso-objects/zoul/module-macros.h @@ -27,8 +27,22 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ - /*---------------------------------------------------------------------------*/ /* Only sleep mode 1 on Zoul to enable full 32 KiB RAM */ #define LPM_CONF_MAX_PM 1 /*---------------------------------------------------------------------------*/ +/* Macros to enter sleep mode and wake up in the Zoul module. Sleep consists + * on turn off the radio and start a RTIMER to wake up, and wake up consists on + * turn on the radio again + */ +#define LWM2M_Q_MODE_WAKE_UP() do { \ + NETSTACK_MAC.on(); \ +} while(0) + +#define LWM2M_Q_MODE_SLEEP_MS(TIME_MS) do { \ + uint64_t aux = TIME_MS * RTIMER_SECOND; \ + NETSTACK_MAC.off(); \ + rtimer_arch_schedule(RTIMER_NOW() + (rtimer_clock_t)(aux / 1000)); \ +} while(0) + + diff --git a/os/services/lwm2m/lwm2m-rd-client.c b/os/services/lwm2m/lwm2m-rd-client.c index 61273797a..cf7c5deb3 100644 --- a/os/services/lwm2m/lwm2m-rd-client.c +++ b/os/services/lwm2m/lwm2m-rd-client.c @@ -43,7 +43,6 @@ * Joel Hoglund * Carlos Gonzalo Peces */ - #include "lwm2m-engine.h" #include "lwm2m-object.h" #include "lwm2m-device.h" @@ -58,15 +57,16 @@ #include #include #include -#if LWM2M_Q_MODE_ENABLED -#include "lwm2m-qmode-object.h" -#include "lwm2m-notification-queue.h" -#endif #if UIP_CONF_IPV6_RPL #include "rpl.h" #endif /* UIP_CONF_IPV6_RPL */ +#if LWM2M_Q_MODE_ENABLED +#include "lwm2m-qmode-object.h" +#include "lwm2m-notification-queue.h" +#endif /* LWM2M_Q_MODE_ENABLED */ + /* Log configuration */ #include "coap-log.h" #define LOG_MODULE "lwm2m-rd" @@ -131,10 +131,15 @@ static void (*rd_callback)(coap_request_state_t *state); static coap_timer_t block1_timer; #if LWM2M_Q_MODE_ENABLED -static coap_timer_t q_mode_client_awake_timer; /* Timer to control the client awake time */ -static uint8_t q_mode_client_awake; /* 1 - client is awake, 0 - client is sleeping */ +static coap_timer_t q_mode_client_awake_timer; /* Timer to control the client's + * awake time + */ +static uint8_t q_mode_client_awake; /* 1 - client is awake, + * 0 - client is sleeping + */ static uint16_t q_mode_client_awake_time; /* The time to be awake */ -static void q_mode_awake_timer_callback(coap_timer_t *timer); /* Callback for the client awake timer */ +/* Callback for the client awake timer */ +static void q_mode_awake_timer_callback(coap_timer_t *timer); #endif static void check_periodic_observations(); @@ -742,16 +747,19 @@ periodic_process(coap_timer_t *timer) coap_timer_set(&q_mode_client_awake_timer, q_mode_client_awake_time); break; case Q_MODE_SEND_UPDATE: -#if !STANDALONE - NETSTACK_MAC.on(); -#endif +/* Define this macro to make the necessary actions for waking up, + * depending on the platform + */ +#ifdef LWM2M_Q_MODE_WAKE_UP + LWM2M_Q_MODE_WAKE_UP(); +#endif /* LWM2M_Q_MODE_WAKE_UP */ prepare_update(request, rd_flags & FLAG_RD_DATA_UPDATE_TRIGGERED); coap_send_request(&rd_request_state, &session_info.server_ep, request, update_callback); last_rd_progress = coap_timer_uptime(); rd_state = UPDATE_SENT; break; -#endif +#endif /* LWM2M_Q_MODE_ENABLED */ case UPDATE_SENT: /* just wait until the callback kicks us to the next state... */ @@ -787,9 +795,10 @@ lwm2m_rd_client_init(const char *ep) /* default binding U = UDP, UQ = UDP Q-mode*/ #if LWM2M_Q_MODE_ENABLED session_info.binding = "UQ"; - session_info.lifetime = (LWM2M_Q_MODE_DEFAULT_CLIENT_SLEEP_TIME / 1000) * 2; /* Enough margin to ensure that the client is not unregistered (we - * do not know the time it can stay awake) - */ + /* Enough margin to ensure that the client is not unregistered (we + * do not know the time it can stay awake) + */ + session_info.lifetime = (LWM2M_Q_MODE_DEFAULT_CLIENT_SLEEP_TIME / 1000) * 2; #else session_info.binding = "U"; if(session_info.lifetime == 0) { @@ -836,12 +845,11 @@ q_mode_awake_timer_callback(coap_timer_t *timer) /* Timer has expired, no requests has been received, client can go to sleep */ LOG_DBG("Queue Mode: Client is SLEEPING at %lu\n", (unsigned long)coap_timer_uptime()); q_mode_client_awake = 0; -#if !STANDALONE - /* Turn off the radio and start sleeping timer. LPM will be entered since the radio - and the peripherals are off, and there is a sleep timer started for waking up */ - NETSTACK_MAC.off(); - rtimer_arch_schedule(RTIMER_NOW() + ((lwm2m_q_object_get_sleep_time() / 1000) * RTIMER_SECOND)); -#endif + +/* Define this macro to enter sleep mode depending on the platform */ +#ifdef LWM2M_Q_MODE_SLEEP_MS + LWM2M_Q_MODE_SLEEP_MS(lwm2m_q_object_get_sleep_time()); +#endif /* LWM2M_Q_MODE_SLEEP_MS */ rd_state = Q_MODE_SEND_UPDATE; coap_timer_set(&rd_timer, lwm2m_q_object_get_sleep_time()); } @@ -862,6 +870,6 @@ lwm2m_rd_client_fsm_execute_q_mode_update() periodic_process(&rd_timer); } /*---------------------------------------------------------------------------*/ -#endif +#endif /* LWM2M_Q_MODE_ENABLED */ /*---------------------------------------------------------------------------*/ /** @} */ From 1dfa62fc88d58ef136b897e6bfe56cdf54cbf093 Mon Sep 17 00:00:00 2001 From: "carlosgp143@gmail.com" Date: Mon, 9 Apr 2018 14:16:26 +0200 Subject: [PATCH 103/485] Added Q-Mode regression tests working with Leshan Server --- .../zoul/module-macros.h | 0 .../18-coap-lwm2m/08-lwm2m-qmode-ipso-test.sh | 69 +++++++++++++++++++ .../09-lwm2m-qmode-standalone-test.sh | 68 ++++++++++++++++++ .../18-coap-lwm2m/pytests/test-qmode-awake.py | 20 ++++++ .../18-coap-lwm2m/pytests/test-qmode-sleep.py | 19 +++++ 5 files changed, 176 insertions(+) rename examples/{ipso-objects => lwm2m-ipso-objects}/zoul/module-macros.h (100%) create mode 100755 tests/18-coap-lwm2m/08-lwm2m-qmode-ipso-test.sh create mode 100755 tests/18-coap-lwm2m/09-lwm2m-qmode-standalone-test.sh create mode 100644 tests/18-coap-lwm2m/pytests/test-qmode-awake.py create mode 100644 tests/18-coap-lwm2m/pytests/test-qmode-sleep.py diff --git a/examples/ipso-objects/zoul/module-macros.h b/examples/lwm2m-ipso-objects/zoul/module-macros.h similarity index 100% rename from examples/ipso-objects/zoul/module-macros.h rename to examples/lwm2m-ipso-objects/zoul/module-macros.h diff --git a/tests/18-coap-lwm2m/08-lwm2m-qmode-ipso-test.sh b/tests/18-coap-lwm2m/08-lwm2m-qmode-ipso-test.sh new file mode 100755 index 000000000..142fb253d --- /dev/null +++ b/tests/18-coap-lwm2m/08-lwm2m-qmode-ipso-test.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +# Contiki directory +CONTIKI=$1 +# Test basename +BASENAME=08-lwm2m-qmode-ipso-test + +IPADDR=fd00::302:304:506:708 + +# Starting Contiki-NG native node +echo "Starting native node - lwm2m/ipso objects with Q-Mode" +make -C $CONTIKI/examples/lwm2m-ipso-objects clean >/dev/null +make -C $CONTIKI/examples/lwm2m-ipso-objects DEFINES=LWM2M_Q_MODE_CONF_ENABLED=1,LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION=1 > make.log 2> make.err +sudo $CONTIKI/examples/lwm2m-ipso-objects/example-ipso-objects.native > node.log 2> node.err & +CPID=$! +sleep 10 + +echo "Downloading leshan with Q-Mode support" +wget -nc https://carlosgp143.github.io/resources/leshan-server-demo-qmode-support1.0.0-SNAPSHOT-jar-with-dependencies.jar +echo "Starting leshan server with Q-Mode enabled" +java -jar leshan-server-demo-qmode-support1.0.0-SNAPSHOT-jar-with-dependencies.jar >leshan.log 2>leshan.err & +LESHID=$! + +COUNTER=10 +while [ $COUNTER -gt 0 ]; do + sleep 5 + aux=$(grep -c 'OK' leshan.err) + if [ $aux -eq 2 ] ; then + break + fi + let COUNTER-=1 +done + +echo "Closing native node" +sleep 1 +pgrep ipso | sudo xargs kill -9 + +echo "Closing leshan" +sleep 1 +pgrep java | sudo xargs kill -9 + +#Two OKs needed: awake and sleeping +aux=$(grep -c 'OK' leshan.err) +if [ $aux -eq 2 ] +then + cp leshan.err $BASENAME.testlog; + printf "%-32s TEST OK\n" "$BASENAME" | tee $BASENAME.testlog; +else + echo "==== make.log ====" ; cat make.log; + echo "==== make.err ====" ; cat make.err; + echo "==== node.log ====" ; cat node.log; + echo "==== node.err ====" ; cat node.err; + echo "==== leshan.log ====" ; cat leshan.log; + echo "==== leshan.err ====" ; cat leshan.err; + echo "==== $BASENAME.log ====" ; cat $BASENAME.log; + + printf "%-32s TEST FAIL\n" "$BASENAME" | tee $BASENAME.testlog; +fi + +rm make.log +rm make.err +rm node.log +rm node.err +rm leshan.log +rm leshan.err + +# We do not want Make to stop -> Return 0 +# The Makefile will check if a log contains FAIL at the end +exit 0 diff --git a/tests/18-coap-lwm2m/09-lwm2m-qmode-standalone-test.sh b/tests/18-coap-lwm2m/09-lwm2m-qmode-standalone-test.sh new file mode 100755 index 000000000..f22b20bef --- /dev/null +++ b/tests/18-coap-lwm2m/09-lwm2m-qmode-standalone-test.sh @@ -0,0 +1,68 @@ +#!/bin/bash + +# Contiki directory +CONTIKI=$1 +# Test basename +BASENAME=09-lwm2m-qmode-standalone-test + +# Building standalone posix example +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 DEFINES=LWM2M_Q_MODE_CONF_ENABLED=1,LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION=1 >make.log 2>make.err + +echo "Downloading leshan with Q-Mode support" +wget -nc https://carlosgp143.github.io/resources/leshan-server-demo-qmode-support1.0.0-SNAPSHOT-jar-with-dependencies.jar +echo "Starting leshan server with Q-Mode enabled" +java -jar leshan-server-demo-1.0.0-SNAPSHOT-jar-with-dependencies.jar -lp 5686 -slp 5687 >leshan.log 2>leshan.err & +LESHID=$! + +echo "Starting lwm2m standalone example" +example-lwm2m-standalone/lwm2m/lwm2m-example coap://127.0.0.1:5686 > node.log 2> node.err & + +CPID=$! + +COUNTER=10 +while [ $COUNTER -gt 0 ]; do + sleep 5 + aux=$(grep -c 'OK' leshan.err) + if [ $aux -eq 2 ] ; then + break + fi + let COUNTER-=1 +done + +echo "Closing standalone example" +sleep 1 +pgrep lwm2m-example | sudo xargs kill -9 + +echo "Closing leshan" +sleep 1 +pgrep java | sudo xargs kill -9 + +aux=$(grep -c 'OK' leshan.err) +if [ $aux -eq 2 ] +then + cp leshan.err $BASENAME.testlog; + printf "%-32s TEST OK\n" "$BASENAME" | tee $BASENAME.testlog; +else + echo "==== make.log ====" ; cat make.log; + echo "==== make.err ====" ; cat make.err; + echo "==== node.log ====" ; cat node.log; + echo "==== node.err ====" ; cat node.err; + echo "==== leshan.log ====" ; cat leshan.log; + echo "==== leshan.err ====" ; cat leshan.err; + echo "==== $BASENAME.log ====" ; cat $BASENAME.log; + + printf "%-32s TEST FAIL\n" "$BASENAME" | tee $BASENAME.testlog; +fi + +rm make.log +rm make.err +rm node.log +rm node.err +rm leshan.log +rm leshan.err + +# We do not want Make to stop -> Return 0 +# The Makefile will check if a log contains FAIL at the end +exit 0 diff --git a/tests/18-coap-lwm2m/pytests/test-qmode-awake.py b/tests/18-coap-lwm2m/pytests/test-qmode-awake.py new file mode 100644 index 000000000..775e1cff0 --- /dev/null +++ b/tests/18-coap-lwm2m/pytests/test-qmode-awake.py @@ -0,0 +1,20 @@ +import unittest, array, time + +class TestQueueModeAwake(unittest.TestCase): + global respAwakeTime + global respSleepTime + + def test_read_awake_time(self): + self.assertEqual(respAwakeTime.getCode().getName(), "CONTENT") + + def test_read_sleep_time(self): + self.assertEqual(respSleepTime.getCode().getName(), "CONTENT") + + +print "----------------------------------------" +print "LWM2M Queue Mode Awake State Tester" +print "----------------------------------------" + + +suite = unittest.TestLoader().loadTestsFromTestCase(TestQueueModeAwake) +unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/tests/18-coap-lwm2m/pytests/test-qmode-sleep.py b/tests/18-coap-lwm2m/pytests/test-qmode-sleep.py new file mode 100644 index 000000000..da9a2ffe8 --- /dev/null +++ b/tests/18-coap-lwm2m/pytests/test-qmode-sleep.py @@ -0,0 +1,19 @@ +from __future__ import with_statement +import unittest, array, time + +class TestQueueModeSleep(unittest.TestCase): + global client + + def test_read_awake_time(self): + self.assertIsNone(client.read("6000/0/3000")) + + def test_read_sleep_time(self): + self.assertIsNone(client.read("6000/0/3001")) + + +print "----------------------------------------" +print "LWM2M Queue Mode Sleep State Tester - name of client: ", client.endpoint +print "----------------------------------------" + +suite = unittest.TestLoader().loadTestsFromTestCase(TestQueueModeSleep) +unittest.TextTestRunner(verbosity=2).run(suite) From 18714f2cad672fb73fee92e59843343cfa36d6b4 Mon Sep 17 00:00:00 2001 From: "carlosgp143@gmail.com" Date: Fri, 27 Apr 2018 16:31:22 +0200 Subject: [PATCH 104/485] Simplified awake time adaptation with array and other small fixes --- examples/lwm2m-ipso-objects/project-conf.h | 2 +- os/services/lwm2m/lwm2m-engine.c | 10 +-- os/services/lwm2m/lwm2m-notification-queue.c | 10 +-- os/services/lwm2m/lwm2m-qmode-object.c | 66 +++++++------------- os/services/lwm2m/lwm2m-qmode-object.h | 2 +- 5 files changed, 36 insertions(+), 54 deletions(-) diff --git a/examples/lwm2m-ipso-objects/project-conf.h b/examples/lwm2m-ipso-objects/project-conf.h index affe626b0..53d149617 100644 --- a/examples/lwm2m-ipso-objects/project-conf.h +++ b/examples/lwm2m-ipso-objects/project-conf.h @@ -64,6 +64,6 @@ #define LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION 1 #define LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_AWAKE_TIME 2000 #define LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_SLEEP_TIME 10000 - #define LWM2M_Q_MODE_CONF_DEFAULT_DYNAMIC_ADAPTATION_FLAG 1 */ + #define LWM2M_Q_MODE_CONF_DEFAULT_DYNAMIC_ADAPTATION_FLAG 0 */ #endif /* PROJECT_CONF_H_ */ diff --git a/os/services/lwm2m/lwm2m-engine.c b/os/services/lwm2m/lwm2m-engine.c index 3c038deec..b80e6f5a4 100644 --- a/os/services/lwm2m/lwm2m-engine.c +++ b/os/services/lwm2m/lwm2m-engine.c @@ -1414,10 +1414,12 @@ lwm2m_handler_callback(coap_message_t *request, coap_message_t *response, if(is_first_request()) { previous_request_time = coap_timer_uptime(); clear_first_request(); - }else{ + } else { if(coap_timer_uptime()-previous_request_time >= 0) { - lwm2m_q_object_add_time_object(coap_timer_uptime()-previous_request_time); - + if(coap_timer_uptime()-previous_request_time > 0xffff) { + lwm2m_q_object_add_time_to_window(0xffff); + } + lwm2m_q_object_add_time_to_window(coap_timer_uptime()-previous_request_time); } previous_request_time = coap_timer_uptime(); } @@ -1691,7 +1693,7 @@ static void lwm2m_send_notification(char* path) { #if LWM2M_Q_MODE_ENABLED && LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION - if(lwm2m_q_object_get_dynamic_adaptation_flag()){ + if(lwm2m_q_object_get_dynamic_adaptation_flag()) { lwm2m_engine_set_handler_from_notification(); } #endif diff --git a/os/services/lwm2m/lwm2m-notification-queue.c b/os/services/lwm2m/lwm2m-notification-queue.c index c3150a879..dab243ec1 100644 --- a/os/services/lwm2m/lwm2m-notification-queue.c +++ b/os/services/lwm2m/lwm2m-notification-queue.c @@ -93,17 +93,17 @@ reduce_path(notification_path_t *path_object, char *path) } /*---------------------------------------------------------------------------*/ static void -extend_path(notification_path_t *path_object, char *path) +extend_path(notification_path_t *path_object, char *path, int path_size) { switch(path_object->level) { case 1: - snprintf(path, sizeof(path) - 1, "%u", path_object->reduced_path[0]); + snprintf(path, path_size, "%u", path_object->reduced_path[0]); break; case 2: - snprintf(path, sizeof(path) - 1, "%u/%u", path_object->reduced_path[0], path_object->reduced_path[1]); + snprintf(path, path_size, "%u/%u", path_object->reduced_path[0], path_object->reduced_path[1]); break; case 3: - snprintf(path, sizeof(path) - 1, "%u/%u/%u", path_object->reduced_path[0], path_object->reduced_path[1], path_object->reduced_path[2]); + snprintf(path, path_size, "%u/%u/%u", path_object->reduced_path[0], path_object->reduced_path[1], path_object->reduced_path[2]); break; } } @@ -222,7 +222,7 @@ lwm2m_notification_queue_send_notifications() notification_path_t *aux = iteration_path; while(iteration_path != NULL) { - extend_path(iteration_path, path); + extend_path(iteration_path, path, sizeof(path)); #if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION if(lwm2m_q_object_get_dynamic_adaptation_flag()) { lwm2m_engine_set_handler_from_notification(); diff --git a/os/services/lwm2m/lwm2m-qmode-object.c b/os/services/lwm2m/lwm2m-qmode-object.c index 77a12e460..be5bc7674 100644 --- a/os/services/lwm2m/lwm2m-qmode-object.c +++ b/os/services/lwm2m/lwm2m-qmode-object.c @@ -78,14 +78,9 @@ static uint32_t q_mode_sleep_time = LWM2M_Q_MODE_DEFAULT_CLIENT_SLEEP_TIME; #if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION static uint8_t q_mode_dynamic_adaptation_flag = LWM2M_Q_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG; -typedef struct time_object { - struct times_object *next; - uint64_t time; -} time_object_t; - /* Window to save the times and do the dynamic adaptation of the awake time*/ -MEMB(times_memb, time_object_t, LWM2M_Q_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH); -LIST(time_object_list); +uint16_t times_window[LWM2M_Q_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH] = { 0 }; +uint8_t times_window_index = 0; #endif /*---------------------------------------------------------------------------*/ @@ -130,16 +125,14 @@ lwm2m_q_object_set_dynamic_adaptation_flag(uint8_t flag) } /*---------------------------------------------------------------------------*/ #if !UPDATE_WITH_MEAN -static uint64_t +static uint16_t get_maximum_time() { - uint64_t max_time = 0; - time_object_t *iteration_time = NULL; - for(iteration_time = (time_object_t *)list_head(time_object_list); iteration_time; - iteration_time = (time_object_t *)iteration_time->next) { - - if(iteration_time->time > max_time) { - max_time = iteration_time->time; + uint16_t max_time = 0; + uint8_t i; + for(i = 0; i < LWM2M_Q_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH; i++) { + if(times_window[i] > max_time) { + max_time = times_window[i]; } } return max_time; @@ -147,18 +140,18 @@ get_maximum_time() #endif /*---------------------------------------------------------------------------*/ #if UPDATE_WITH_MEAN -static uint64_t +static uint16_t get_mean_time() { - uint64_t mean_time = 0; - time_object_t *iteration_time = NULL; - for(iteration_time = (time_object_t *)list_head(time_object_list); iteration_time; - (time_object_t *)iteration_time = iteration_time->next) { - + uint16_t mean_time = 0; + uint8_t i; + for(i = 0; i < LWM2M_Q_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH; i++) { if(mean_time == 0) { - mean_time = iteration_time->time; + mean_time = times_window[i]; } else { - mean_time = (mean_time + iteration_time->time) / 2; + if(times_window[i] != 0) { + mean_time = (mean_time + times_window[i]) / 2; + } } } return mean_time; @@ -169,39 +162,26 @@ static void update_awake_time() { #if UPDATE_WITH_MEAN - uint64_t mean_time = get_mean_time(); + uint16_t mean_time = get_mean_time(); LOG_DBG("Dynamic Adaptation: updated awake time: %d ms\n", (int)mean_time); lwm2m_q_object_set_awake_time(mean_time + (mean_time >> 1)); /* 50% margin */ return; #else - uint64_t max_time = get_maximum_time(); + uint16_t max_time = get_maximum_time(); LOG_DBG("Dynamic Adaptation: updated awake time: %d ms\n", (int)max_time); lwm2m_q_object_set_awake_time(max_time + (max_time >> 1)); /* 50% margin */ return; #endif } /*---------------------------------------------------------------------------*/ -static void -remove_time_object(time_object_t *time_object) -{ - memb_free(×_memb, time_object); - list_remove(time_object_list, time_object); -} -/*---------------------------------------------------------------------------*/ void -lwm2m_q_object_add_time_object(uint64_t time) +lwm2m_q_object_add_time_to_window(uint16_t time) { - time_object_t *time_object; - time_object = memb_alloc(×_memb); - if(time_object != NULL) { - time_object->time = time; - list_add(time_object_list, time_object); - } else { - remove_time_object((time_object_t *)list_head(time_object_list)); - time_object = memb_alloc(×_memb); - time_object->time = time; - list_add(time_object_list, time_object); + if(times_window_index == LWM2M_Q_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH) { + times_window_index = 0; } + times_window[times_window_index] = time; + times_window_index++; update_awake_time(); } #endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ diff --git a/os/services/lwm2m/lwm2m-qmode-object.h b/os/services/lwm2m/lwm2m-qmode-object.h index 68427a59c..61ac35ff3 100644 --- a/os/services/lwm2m/lwm2m-qmode-object.h +++ b/os/services/lwm2m/lwm2m-qmode-object.h @@ -53,7 +53,7 @@ uint16_t lwm2m_q_object_get_awake_time(); uint32_t lwm2m_q_object_get_sleep_time(); #if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION uint8_t lwm2m_q_object_get_dynamic_adaptation_flag(); -void lwm2m_q_object_add_time_object(uint64_t time); +void lwm2m_q_object_add_time_to_window(uint16_t time); #endif void lwm2m_q_object_send_notifications(); From 3889ffe7502b33f131b9ef66dcb0052d0bb432e9 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 16 May 2018 11:25:14 -0700 Subject: [PATCH 105/485] Simplify and homogenize node-id across all platforms --- arch/platform/cooja/platform.c | 14 ++-- arch/platform/jn516x/Makefile.jn516x | 2 +- arch/platform/jn516x/dev/node-id.c | 61 -------------- arch/platform/jn516x/platform.c | 34 +------- arch/platform/native/platform.c | 14 +--- arch/platform/sky/Makefile.common | 2 +- arch/platform/sky/apps/burn-nodeid.c | 80 ------------------- arch/platform/sky/node-id.c | 71 ---------------- arch/platform/sky/platform.c | 35 +------- arch/platform/srf06-cc26xx/platform.c | 7 -- examples/6tisch/etsi-plugtest-2017/node.c | 2 +- examples/6tisch/simple-node/node.c | 2 +- examples/6tisch/sixtop/node-sixtop.c | 2 +- .../tsch/simple-sensor-network/node/node.c | 2 +- os/contiki-main.c | 11 ++- .../cooja/sys/node-id.h => os/sys/node-id.c | 26 ++++-- os/sys/node-id.h | 23 ++++-- 17 files changed, 64 insertions(+), 324 deletions(-) delete mode 100644 arch/platform/jn516x/dev/node-id.c delete mode 100644 arch/platform/sky/apps/burn-nodeid.c delete mode 100644 arch/platform/sky/node-id.c rename arch/platform/cooja/sys/node-id.h => os/sys/node-id.c (75%) diff --git a/arch/platform/cooja/platform.c b/arch/platform/cooja/platform.c index 9ef310bce..591abe67e 100644 --- a/arch/platform/cooja/platform.c +++ b/arch/platform/cooja/platform.c @@ -64,6 +64,7 @@ #include "dev/button-sensor.h" #include "dev/pir-sensor.h" #include "dev/vib-sensor.h" +#include "dev/moteid.h" #include "sys/node-id.h" #include "services/rpl-border-router/rpl-border-router.h" @@ -151,13 +152,13 @@ set_lladdr(void) { int i; for(i = 0; i < sizeof(uip_lladdr.addr); i += 2) { - addr.u8[i + 1] = node_id & 0xff; - addr.u8[i + 0] = node_id >> 8; + addr.u8[i + 1] = simMoteID & 0xff; + addr.u8[i + 0] = simMoteID >> 8; } } #else /* NETSTACK_CONF_WITH_IPV6 */ - addr.u8[0] = node_id & 0xff; - addr.u8[1] = node_id >> 8; + addr.u8[0] = simMoteID & 0xff; + addr.u8[1] = simMoteID >> 8; #endif /* NETSTACK_CONF_WITH_IPV6 */ linkaddr_set_node_addr(&addr); } @@ -177,11 +178,6 @@ platform_init_stage_two() void platform_init_stage_three() { - if(node_id > 0) { - LOG_INFO("Node id is set to %u.\n", node_id); - } else { - LOG_INFO("Node id is not set.\n"); - } /* Initialize eeprom */ eeprom_init(); /* Start serial process */ diff --git a/arch/platform/jn516x/Makefile.jn516x b/arch/platform/jn516x/Makefile.jn516x index bb40b5638..93ba5f296 100644 --- a/arch/platform/jn516x/Makefile.jn516x +++ b/arch/platform/jn516x/Makefile.jn516x @@ -82,7 +82,7 @@ OBJDUMP:=$(CROSS_COMPILE)-objdump ARCH = jn516x-ccm-star.c exceptions.c rtimer-arch.c rtimer-arch-slow.c \ slip_uart0.c clock.c micromac-radio.c int-master.c \ - node-id.c watchdog.c slip.c dbg.c + watchdog.c slip.c dbg.c # Default uart0 for printf and slip TARGET_WITH_UART0 ?= 1 TARGET_WITH_UART1 ?= 0 diff --git a/arch/platform/jn516x/dev/node-id.c b/arch/platform/jn516x/dev/node-id.c deleted file mode 100644 index c29aa8282..000000000 --- a/arch/platform/jn516x/dev/node-id.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2014, SICS Swedish ICT. - * 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 - * For compatibility with Contiki node-id interface - * - * \author - * Beshr Al Nahas - */ - -#include "contiki.h" -#include "sys/node-id.h" -#include "contiki.h" - -/*---------------------------------------------------------------------------*/ -extern unsigned char node_mac[8]; -unsigned short node_id = 0; -/*---------------------------------------------------------------------------*/ -void -node_id_restore(void) -{ - /* base node-id on MAC address */ - node_id = (node_mac[6] << 8) | node_mac[7]; -} -/*---------------------------------------------------------------------------*/ -void -node_id_burn(unsigned short id) -{ - /* does not burn anything */ - node_id = id; -} diff --git a/arch/platform/jn516x/platform.c b/arch/platform/jn516x/platform.c index 20dabfb61..9d44444e8 100644 --- a/arch/platform/jn516x/platform.c +++ b/arch/platform/jn516x/platform.c @@ -113,8 +113,7 @@ static uint32_t sleep_start_ticks; #define LOG_LEVEL LOG_LEVEL_MAIN /*---------------------------------------------------------------------------*/ /* Reads MAC from SoC - * Must be called before node_id_restore() - * and network addresses initialization */ + * Must be called before network addresses initialization */ static void init_node_mac(void) { @@ -139,14 +138,9 @@ set_linkaddr(void) #if NETSTACK_CONF_WITH_IPV6 memcpy(addr.u8, node_mac, sizeof(addr.u8)); #else - if(node_id == 0) { - int i; - for(i = 0; i < LINKADDR_SIZE; ++i) { - addr.u8[i] = node_mac[LINKADDR_SIZE - 1 - i]; - } - } else { - addr.u8[0] = node_id & 0xff; - addr.u8[1] = node_id >> 8; + int i; + for(i = 0; i < LINKADDR_SIZE; ++i) { + addr.u8[i] = node_mac[LINKADDR_SIZE - 1 - i]; } #endif linkaddr_set_node_addr(&addr); @@ -194,20 +188,6 @@ platform_init_stage_one(void) leds_init(); leds_on(LEDS_ALL); init_node_mac(); - - node_id_restore(); - -#if WITH_TINYOS_AUTO_IDS - node_id = TOS_NODE_ID; -#endif /* WITH_TINYOS_AUTO_IDS */ - /* for setting "hardcoded" IEEE 802.15.4 MAC addresses */ -#ifdef IEEE_802154_MAC_ADDRESS - { - uint8_t ieee[] = IEEE_802154_MAC_ADDRESS; - memcpy(node_mac, ieee, sizeof(uip_lladdr.addr)); - node_mac[7] = node_id & 0xff; - } -#endif } /*---------------------------------------------------------------------------*/ void @@ -225,12 +205,6 @@ platform_init_stage_two(void) void platform_init_stage_three(void) { - if(node_id > 0) { - LOG_INFO("Node id is set to %u.\n", node_id); - } else { - LOG_INFO("Node id is not set.\n"); - } - #ifndef UIP_FALLBACK_INTERFACE uart0_set_input(serial_line_input_byte); serial_line_init(); diff --git a/arch/platform/native/platform.c b/arch/platform/native/platform.c index c5c4f23e7..d00efaac1 100644 --- a/arch/platform/native/platform.c +++ b/arch/platform/native/platform.c @@ -120,9 +120,6 @@ static uint8_t mac_addr[] = PLATFORM_CONF_MAC_ADDR; static uint8_t mac_addr[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; #endif /* PLATFORM_CONF_MAC_ADDR */ -#if !NETSTACK_CONF_WITH_IPV6 -static uint16_t node_id = 0x0102; -#endif /* !NETSTACK_CONF_WITH_IPV6 */ /*---------------------------------------------------------------------------*/ int select_set_callback(int fd, const struct select_callback *callback) @@ -187,14 +184,9 @@ set_lladdr(void) #if NETSTACK_CONF_WITH_IPV6 memcpy(addr.u8, mac_addr, sizeof(addr.u8)); #else - if(node_id == 0) { - int i; - for(i = 0; i < sizeof(linkaddr_t); ++i) { - addr.u8[i] = mac_addr[7 - i]; - } - } else { - addr.u8[0] = node_id & 0xff; - addr.u8[1] = node_id >> 8; + int i; + for(i = 0; i < sizeof(linkaddr_t); ++i) { + addr.u8[i] = mac_addr[7 - i]; } #endif linkaddr_set_node_addr(&addr); diff --git a/arch/platform/sky/Makefile.common b/arch/platform/sky/Makefile.common index 3d688b573..c8de6d6ad 100644 --- a/arch/platform/sky/Makefile.common +++ b/arch/platform/sky/Makefile.common @@ -1,6 +1,6 @@ # $Id: Makefile.common,v 1.3 2010/08/24 16:24:11 joxe Exp $ -ARCH=spi-legacy.c ds2411.c xmem.c i2c.c node-id.c sensors.c cfs-coffee.c \ +ARCH=spi-legacy.c ds2411.c xmem.c i2c.c sensors.c cfs-coffee.c \ cc2420.c cc2420-arch.c cc2420-arch-sfd.c \ sky-sensors.c uip-ipchksum.c \ uart1.c slip_uart1.c uart1-putchar.c platform.c diff --git a/arch/platform/sky/apps/burn-nodeid.c b/arch/platform/sky/apps/burn-nodeid.c deleted file mode 100644 index 128ba2ba9..000000000 --- a/arch/platform/sky/apps/burn-nodeid.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2006, 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 program for burning a node ID into the flash ROM of a Tmote Sky node. - * \author - * Adam Dunkels - */ - -#include "dev/leds.h" -#include "dev/watchdog.h" -#include "sys/node-id.h" -#include "contiki.h" -#include "sys/etimer.h" - -#include - -static struct etimer etimer; - -PROCESS(burn_process, "Burn node id"); -AUTOSTART_PROCESSES(&burn_process); -/*---------------------------------------------------------------------------*/ -PROCESS_THREAD(burn_process, ev, data) -{ - PROCESS_BEGIN(); - - etimer_set(&etimer, 5*CLOCK_SECOND); - PROCESS_WAIT_UNTIL(etimer_expired(&etimer)); - - watchdog_stop(); - leds_on(LEDS_RED); -#if NODEID - printf("Burning node id %d\n", NODEID); - node_id_burn(NODEID); - leds_on(LEDS_BLUE); - node_id_restore(); - printf("Restored node id %d\n", node_id); -#else -#error "burn-nodeid must be compiled with nodeid=" - node_id_restore(); - printf("Restored node id %d\n", node_id); -#endif - leds_off(LEDS_RED + LEDS_BLUE); - watchdog_start(); - while(1) { - PROCESS_WAIT_EVENT(); - } - PROCESS_END(); -} -/*---------------------------------------------------------------------------*/ diff --git a/arch/platform/sky/node-id.c b/arch/platform/sky/node-id.c deleted file mode 100644 index ce6f68f85..000000000 --- a/arch/platform/sky/node-id.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2006, 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 - * Utility to store a node id in the external flash - * \author - * Adam Dunkels - */ - -#include "sys/node-id.h" -#include "contiki.h" -#include "dev/xmem.h" - -unsigned short node_id = 0; - -/*---------------------------------------------------------------------------*/ -void -node_id_restore(void) -{ - unsigned char buf[4]; - xmem_pread(buf, 4, NODE_ID_XMEM_OFFSET); - if(buf[0] == 0xad && - buf[1] == 0xde) { - node_id = (buf[2] << 8) | buf[3]; - } else { - node_id = 0; - } -} -/*---------------------------------------------------------------------------*/ -void -node_id_burn(unsigned short id) -{ - unsigned char buf[4]; - buf[0] = 0xad; - buf[1] = 0xde; - buf[2] = id >> 8; - buf[3] = id & 0xff; - xmem_erase(XMEM_ERASE_UNIT_SIZE, NODE_ID_XMEM_OFFSET); - xmem_pwrite(buf, 4, NODE_ID_XMEM_OFFSET); -} -/*---------------------------------------------------------------------------*/ diff --git a/arch/platform/sky/platform.c b/arch/platform/sky/platform.c index deaa53b5a..670e5443d 100644 --- a/arch/platform/sky/platform.c +++ b/arch/platform/sky/platform.c @@ -103,14 +103,9 @@ set_lladdr(void) #if NETSTACK_CONF_WITH_IPV6 memcpy(addr.u8, ds2411_id, sizeof(addr.u8)); #else - if(node_id == 0) { - int i; - for(i = 0; i < sizeof(linkaddr_t); ++i) { - addr.u8[i] = ds2411_id[7 - i]; - } - } else { - addr.u8[0] = node_id & 0xff; - addr.u8[1] = node_id >> 8; + int i; + for(i = 0; i < sizeof(linkaddr_t); ++i) { + addr.u8[i] = ds2411_id[7 - i]; } #endif linkaddr_set_node_addr(&addr); @@ -153,23 +148,7 @@ platform_init_stage_two(void) * Hardware initialization done! */ -#if WITH_TINYOS_AUTO_IDS - node_id = TOS_NODE_ID; -#else /* WITH_TINYOS_AUTO_IDS */ - /* Restore node id if such has been stored in external mem */ - node_id_restore(); -#endif /* WITH_TINYOS_AUTO_IDS */ - - /* for setting "hardcoded" IEEE 802.15.4 MAC addresses */ -#ifdef IEEE_802154_MAC_ADDRESS - { - uint8_t ieee[] = IEEE_802154_MAC_ADDRESS; - memcpy(ds2411_id, ieee, sizeof(uip_lladdr.addr)); - ds2411_id[7] = node_id & 0xff; - } -#endif - - random_init(ds2411_id[0] + node_id); + random_init(ds2411_id[0]); leds_off(LEDS_BLUE); @@ -198,12 +177,6 @@ platform_init_stage_three(void) cc2420_set_pan_addr(IEEE802154_PANID, shortaddr, longaddr); - if(node_id > 0) { - LOG_INFO("Node id: %u\n", node_id); - } else { - LOG_INFO("Node id: N/A\n"); - } - LOG_INFO("CC2420 CCA threshold %i\n", CC2420_CONF_CCA_THRESH); #if !NETSTACK_CONF_WITH_IPV6 diff --git a/arch/platform/srf06-cc26xx/platform.c b/arch/platform/srf06-cc26xx/platform.c index 362b9614e..d71e597f1 100644 --- a/arch/platform/srf06-cc26xx/platform.c +++ b/arch/platform/srf06-cc26xx/platform.c @@ -81,8 +81,6 @@ #define LOG_MODULE "CC26xx/CC13xx" #define LOG_LEVEL LOG_LEVEL_MAIN /*---------------------------------------------------------------------------*/ -unsigned short node_id = 0; -/*---------------------------------------------------------------------------*/ /** \brief Board specific iniatialisation */ void board_init(void); /*---------------------------------------------------------------------------*/ @@ -130,9 +128,6 @@ set_rf_params(void) NETSTACK_RADIO.set_value(RADIO_PARAM_16BIT_ADDR, short_addr); 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 */ - node_id = short_addr; #endif } /*---------------------------------------------------------------------------*/ @@ -227,8 +222,6 @@ platform_init_stage_three() } LOG_INFO_("\n"); - LOG_INFO(" Node ID: %d\n", node_id); - #if BOARD_HAS_SENSORS process_start(&sensors_process, NULL); #endif diff --git a/examples/6tisch/etsi-plugtest-2017/node.c b/examples/6tisch/etsi-plugtest-2017/node.c index 3046bb291..32d0429c0 100644 --- a/examples/6tisch/etsi-plugtest-2017/node.c +++ b/examples/6tisch/etsi-plugtest-2017/node.c @@ -37,7 +37,7 @@ */ #include "contiki.h" -#include "node-id.h" +#include "sys/node-id.h" #include "sys/log.h" #include "net/ipv6/uip-ds6-route.h" #include "net/mac/tsch/tsch.h" diff --git a/examples/6tisch/simple-node/node.c b/examples/6tisch/simple-node/node.c index d2f75ae33..381d81f8e 100644 --- a/examples/6tisch/simple-node/node.c +++ b/examples/6tisch/simple-node/node.c @@ -37,7 +37,7 @@ */ #include "contiki.h" -#include "node-id.h" +#include "sys/node-id.h" #include "sys/log.h" #include "net/ipv6/uip-ds6-route.h" #include "net/ipv6/uip-sr.h" diff --git a/examples/6tisch/sixtop/node-sixtop.c b/examples/6tisch/sixtop/node-sixtop.c index 67bee378a..e2dfe08c2 100755 --- a/examples/6tisch/sixtop/node-sixtop.c +++ b/examples/6tisch/sixtop/node-sixtop.c @@ -38,7 +38,7 @@ */ #include "contiki.h" -#include "node-id.h" +#include "sys/node-id.h" #include "sys/log.h" #include "net/ipv6/uip-ds6-route.h" #include "net/mac/tsch/tsch.h" diff --git a/examples/platform-specific/jn516x/tsch/simple-sensor-network/node/node.c b/examples/platform-specific/jn516x/tsch/simple-sensor-network/node/node.c index 42fa11fb7..df72b69b3 100644 --- a/examples/platform-specific/jn516x/tsch/simple-sensor-network/node/node.c +++ b/examples/platform-specific/jn516x/tsch/simple-sensor-network/node/node.c @@ -38,7 +38,7 @@ #include "net/routing/routing.h" #include "net/ipv6/uip-debug.h" #include "lib/random.h" -#include "node-id.h" +#include "sys/node-id.h" #include "waveform.h" #include "leds.h" #include "net/ipv6/uiplib.h" diff --git a/os/contiki-main.c b/os/contiki-main.c index b9aea5cd6..6252df828 100644 --- a/os/contiki-main.c +++ b/os/contiki-main.c @@ -42,6 +42,7 @@ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "contiki-net.h" +#include "sys/node-id.h" #include "sys/platform.h" #include "sys/energest.h" #include "sys/stack-check.h" @@ -86,6 +87,9 @@ main(void) platform_init_stage_two(); + netstack_init(); + node_id_init(); + LOG_INFO("Starting " CONTIKI_VERSION_STRING "\n"); LOG_INFO("- Routing: %s\n", NETSTACK_ROUTING.name); LOG_INFO("- Net: %s\n", NETSTACK_NETWORK.name); @@ -97,9 +101,8 @@ main(void) LOG_INFO("- 802.15.4 Default channel: %u\n", IEEE802154_DEFAULT_CHANNEL); #endif /* MAC_CONF_WITH_TSCH */ - netstack_init(); - - LOG_INFO("Link-layer address "); + LOG_INFO("Node ID: %u\n", node_id); + LOG_INFO("Link-layer address: "); LOG_INFO_LLADDR(&linkaddr_node_addr); LOG_INFO_("\n"); @@ -110,7 +113,7 @@ main(void) process_start(&tcpip_process, NULL); lladdr = uip_ds6_get_link_local(-1); - LOG_INFO("Tentative link-local IPv6 address "); + LOG_INFO("Tentative link-local IPv6 address: "); LOG_INFO_6ADDR(lladdr != NULL ? &lladdr->ipaddr : NULL); LOG_INFO_("\n"); } diff --git a/arch/platform/cooja/sys/node-id.h b/os/sys/node-id.c similarity index 75% rename from arch/platform/cooja/sys/node-id.h rename to os/sys/node-id.c index a6876bd1f..7914256e9 100644 --- a/arch/platform/cooja/sys/node-id.h +++ b/os/sys/node-id.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Swedish Institute of Computer Science. + * Copyright (c) 2018, RISE SICS. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,14 +26,26 @@ * 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. + * */ -#ifndef NODE_ID_H_ -#define NODE_ID_H_ +/** + * \file + * Node-id management + * \author + * Simon Duquennoy + */ -#include "dev/moteid.h" +#include "contiki.h" +#include "sys/node-id.h" +#include "net/linkaddr.h" -#define node_id simMoteID +uint16_t node_id = 0; -#endif /* NODE_ID_H_ */ +void +node_id_init(void) { + /* Initialize with a default value derived from linkaddr */ + node_id = linkaddr_node_addr.u8[LINKADDR_SIZE - 1] + + (linkaddr_node_addr.u8[LINKADDR_SIZE - 2] << 8); +} diff --git a/os/sys/node-id.h b/os/sys/node-id.h index 0b6ebe6b1..5718269eb 100644 --- a/os/sys/node-id.h +++ b/os/sys/node-id.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, Swedish Institute of Computer Science. + * Copyright (c) 2018, RISE SICS. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,16 +28,25 @@ * * This file is part of the Contiki operating system. * - * Author: Adam Dunkels - * */ + /** + * \addtogroup node-id + * @{ + * + * \file Node-id (simple 16-bit identifiers) handling + * \author Simon Duquennoy + * + */ + #ifndef NODE_ID_H_ #define NODE_ID_H_ -void node_id_restore(void); -void node_id_burn(unsigned short node_id); - -extern unsigned short node_id; +/* A global variable that hosts the node ID */ +extern uint16_t node_id; +/** + * Initialize the node ID. Must be called after initialized of linkaddr + */ +void node_id_init(void); #endif /* NODE_ID_H_ */ From 9531b02a3ad59af633a664cbce8401040ba3d4ac Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 18 May 2018 07:27:25 -0700 Subject: [PATCH 106/485] Doxygen fix --- os/sys/node-id.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/os/sys/node-id.h b/os/sys/node-id.h index 5718269eb..58909ddaa 100644 --- a/os/sys/node-id.h +++ b/os/sys/node-id.h @@ -34,7 +34,8 @@ * \addtogroup node-id * @{ * - * \file Node-id (simple 16-bit identifiers) handling + * \file + * Node-id (simple 16-bit identifiers) handling * \author Simon Duquennoy * */ @@ -50,3 +51,5 @@ extern uint16_t node_id; void node_id_init(void); #endif /* NODE_ID_H_ */ + /** @} */ + From 21657d1b37997c7d3532e62ed3dc2065a1040e05 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 18 May 2018 14:07:53 -0700 Subject: [PATCH 107/485] Fix ipv6 test: use new node-id log string --- tests/09-ipv6/js/ping-test-lla.js | 2 +- tests/09-ipv6/js/ping-test-ula.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/09-ipv6/js/ping-test-lla.js b/tests/09-ipv6/js/ping-test-lla.js index 1823d87b2..d9beedf8b 100644 --- a/tests/09-ipv6/js/ping-test-lla.js +++ b/tests/09-ipv6/js/ping-test-lla.js @@ -8,7 +8,7 @@ while(1) { YIELD(); log.log(time + " " + id + " "+ msg + "\n"); - if(msg.contains("Node id is set to")) { + if(msg.contains("Node ID: ")) { if(id == 1) { write(sim.getMoteWithID(1), "rpl-set-root 1"); } diff --git a/tests/09-ipv6/js/ping-test-ula.js b/tests/09-ipv6/js/ping-test-ula.js index b78f0342a..adbd22ccf 100644 --- a/tests/09-ipv6/js/ping-test-ula.js +++ b/tests/09-ipv6/js/ping-test-ula.js @@ -9,7 +9,7 @@ while(1) { YIELD(); log.log(time + " " + id + " "+ msg + "\n"); - if(msg.contains("Node id is set to")) { + if(msg.contains("Node ID: ")) { if(id == 1) { write(sim.getMoteWithID(1), "rpl-set-root 1"); } From 5f0dd15f1ed1431d3678ccacccabea11e3db21b2 Mon Sep 17 00:00:00 2001 From: Rehan MALAK Date: Wed, 25 Apr 2018 14:22:23 +0200 Subject: [PATCH 108/485] node killed at the end of 08-native-runs tests pgrep pattern shoud be smaller than 15 characters --- tests/08-native-runs/01-test-data-structures.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/08-native-runs/01-test-data-structures.sh b/tests/08-native-runs/01-test-data-structures.sh index 790235638..4885a4c8f 100755 --- a/tests/08-native-runs/01-test-data-structures.sh +++ b/tests/08-native-runs/01-test-data-structures.sh @@ -16,7 +16,7 @@ sleep 2 echo "Closing native node" sleep 2 -pgrep $CODE | xargs kill -9 +pgrep ${CODE:0:15} | xargs kill -9 if grep -q "=check-me= FAILED" $CODE.log ; then echo "==== make.log ====" ; cat make.log; From 083c37802ab7335cd8d7f87f4c2601f98953a069 Mon Sep 17 00:00:00 2001 From: Rehan MALAK Date: Fri, 18 May 2018 02:38:31 +0200 Subject: [PATCH 109/485] node killed with a simple "kill -9" only sudo commands need the "pgrep ... | sudo xargs kill -9" trick --- tests/08-native-runs/01-test-data-structures.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/08-native-runs/01-test-data-structures.sh b/tests/08-native-runs/01-test-data-structures.sh index 4885a4c8f..6ea908869 100755 --- a/tests/08-native-runs/01-test-data-structures.sh +++ b/tests/08-native-runs/01-test-data-structures.sh @@ -16,7 +16,7 @@ sleep 2 echo "Closing native node" sleep 2 -pgrep ${CODE:0:15} | xargs kill -9 +kill -9 ${CPID} if grep -q "=check-me= FAILED" $CODE.log ; then echo "==== make.log ====" ; cat make.log; From 08c28f251349ea460f93d1eb2f477f4364facfbb Mon Sep 17 00:00:00 2001 From: Rehan MALAK Date: Sat, 19 May 2018 17:50:10 +0200 Subject: [PATCH 110/485] homogenize the way we kill background processes kill_bg : -takes the PID of the process to kill -differentiates the sudo case from the non-sudo case --- .../08-native-runs/01-test-data-structures.sh | 3 ++- .../04-border-router-traceroute.sh | 5 +++-- tests/17-tun-rpl-br/05-native-ping.sh | 3 ++- tests/17-tun-rpl-br/06-native-coap.sh | 3 ++- tests/17-tun-rpl-br/test-border-router.sh | 5 +++-- .../test-native-border-router.sh | 5 +++-- tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh | 5 +++-- .../18-coap-lwm2m/07-lwm2m-standalone-test.sh | 5 +++-- tests/utils.sh | 20 +++++++++++++++++++ 9 files changed, 41 insertions(+), 13 deletions(-) create mode 100755 tests/utils.sh diff --git a/tests/08-native-runs/01-test-data-structures.sh b/tests/08-native-runs/01-test-data-structures.sh index 6ea908869..2343756fe 100755 --- a/tests/08-native-runs/01-test-data-structures.sh +++ b/tests/08-native-runs/01-test-data-structures.sh @@ -1,4 +1,5 @@ #!/bin/bash +source ../utils.sh # Contiki directory CONTIKI=$1 @@ -16,7 +17,7 @@ sleep 2 echo "Closing native node" sleep 2 -kill -9 ${CPID} +kill_bg $CPID if grep -q "=check-me= FAILED" $CODE.log ; then echo "==== make.log ====" ; cat make.log; diff --git a/tests/17-tun-rpl-br/04-border-router-traceroute.sh b/tests/17-tun-rpl-br/04-border-router-traceroute.sh index e1e9d6cdd..fe1333aab 100755 --- a/tests/17-tun-rpl-br/04-border-router-traceroute.sh +++ b/tests/17-tun-rpl-br/04-border-router-traceroute.sh @@ -1,4 +1,5 @@ #!/bin/bash +source ../utils.sh # Contiki directory CONTIKI=$1 @@ -38,8 +39,8 @@ HOPS=`wc $BASENAME.scriptlog -l | cut -f 1 -d ' '` echo "Closing simulation and tunslip6" sleep 1 -kill -9 $JPID -kill -9 $MPID +kill_bg $JPID +kill_bg $MPID sleep 1 rm COOJA.testlog rm COOJA.log diff --git a/tests/17-tun-rpl-br/05-native-ping.sh b/tests/17-tun-rpl-br/05-native-ping.sh index 9e677c16e..ea416aac4 100755 --- a/tests/17-tun-rpl-br/05-native-ping.sh +++ b/tests/17-tun-rpl-br/05-native-ping.sh @@ -1,4 +1,5 @@ #!/bin/bash +source ../utils.sh # Contiki directory CONTIKI=$1 @@ -22,7 +23,7 @@ STATUS=${PIPESTATUS[0]} echo "Closing native node" sleep 2 -pgrep hello-world | sudo xargs kill -9 +kill_bg $CPID if [ $STATUS -eq 0 ] ; then cp $BASENAME.log $BASENAME.testlog diff --git a/tests/17-tun-rpl-br/06-native-coap.sh b/tests/17-tun-rpl-br/06-native-coap.sh index 88627ec19..216d104f4 100755 --- a/tests/17-tun-rpl-br/06-native-coap.sh +++ b/tests/17-tun-rpl-br/06-native-coap.sh @@ -1,4 +1,5 @@ #!/bin/bash +source ../utils.sh # Contiki directory CONTIKI=$1 @@ -38,7 +39,7 @@ done echo "Closing native node" sleep 2 -pgrep coap-example | sudo xargs kill -9 +kill_bg $CPID if [ $TESTCOUNT -eq $OKCOUNT ] ; then printf "%-32s TEST OK %3d/%d\n" "$BASENAME" "$OKCOUNT" "$TESTCOUNT" | tee $BASENAME.testlog; diff --git a/tests/17-tun-rpl-br/test-border-router.sh b/tests/17-tun-rpl-br/test-border-router.sh index f98ca81f4..c5653d480 100755 --- a/tests/17-tun-rpl-br/test-border-router.sh +++ b/tests/17-tun-rpl-br/test-border-router.sh @@ -1,4 +1,5 @@ #!/bin/bash +source ../utils.sh # Contiki directory CONTIKI=$1 @@ -44,8 +45,8 @@ REPLIES=`grep -c 'icmp_seq=' $BASENAME.scriptlog` echo "Closing simulation and tunslip6" sleep 1 -kill -9 $JPID -kill -9 $MPID +kill_bg $JPID +kill_bg $MPID sleep 1 rm COOJA.testlog rm COOJA.log diff --git a/tests/17-tun-rpl-br/test-native-border-router.sh b/tests/17-tun-rpl-br/test-native-border-router.sh index 636b6b973..50ea18179 100644 --- a/tests/17-tun-rpl-br/test-native-border-router.sh +++ b/tests/17-tun-rpl-br/test-native-border-router.sh @@ -1,4 +1,5 @@ #!/bin/bash +source ../utils.sh # Contiki directory CONTIKI=$1 @@ -43,8 +44,8 @@ REPLIES=`grep -c 'icmp_seq=' $BASENAME.scriptlog` echo "Closing simulation and nbr" sleep 1 -kill -9 $JPID -kill -9 $MPID +kill_bg $JPID +kill_bg $MPID sleep 1 rm COOJA.testlog rm COOJA.log diff --git a/tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh b/tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh index 9aacc2976..ec7502a21 100755 --- a/tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh +++ b/tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh @@ -1,4 +1,5 @@ #!/bin/bash +source ../utils.sh # Contiki directory CONTIKI=$1 @@ -32,11 +33,11 @@ done echo "Closing native node" sleep 1 -pgrep ipso | sudo xargs kill -9 +kill_bg $CPID echo "Closing leshan" sleep 1 -pgrep java | sudo xargs kill -9 +kill_bg $LESHID if grep -q 'OK' leshan.err ; then diff --git a/tests/18-coap-lwm2m/07-lwm2m-standalone-test.sh b/tests/18-coap-lwm2m/07-lwm2m-standalone-test.sh index b13352447..a1257f36e 100755 --- a/tests/18-coap-lwm2m/07-lwm2m-standalone-test.sh +++ b/tests/18-coap-lwm2m/07-lwm2m-standalone-test.sh @@ -1,4 +1,5 @@ #!/bin/bash +source ../utils.sh # Contiki directory CONTIKI=$1 @@ -33,11 +34,11 @@ done echo "Closing standalone example" sleep 1 -pgrep lwm2m-example | sudo xargs kill -9 +kill_bg $CPID echo "Closing leshan" sleep 1 -pgrep java | sudo xargs kill -9 +kill_bg $LESHID if grep -q 'OK' leshan.err ; then diff --git a/tests/utils.sh b/tests/utils.sh new file mode 100755 index 000000000..bd00ca539 --- /dev/null +++ b/tests/utils.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +function echo_run( ) +{ + echo $@ + $@ +} + +function kill_bg( ) +{ + PID=$1 + CMD=$(ps -p $PID -o cmd=) + SUDO= + TOKILL=$PID + if [[ ${CMD:0:5} == "sudo " ]] ; then + SUDO="sudo " + TOKILL=$(ps --ppid $PID -o pid=) + fi + echo_run ${SUDO}kill -9 $TOKILL +} From 2e84d2abbec1742e217182f8664c3cefed8240a2 Mon Sep 17 00:00:00 2001 From: "carlosgp143@gmail.com" Date: Fri, 18 May 2018 18:22:14 +0200 Subject: [PATCH 111/485] Separated Queue Mode implementation and Queue Mode object. Changes in the naming --- os/services/lwm2m/lwm2m-engine.c | 54 ++-- os/services/lwm2m/lwm2m-engine.h | 10 +- os/services/lwm2m/lwm2m-notification-queue.c | 10 +- os/services/lwm2m/lwm2m-notification-queue.h | 4 +- os/services/lwm2m/lwm2m-qmode-object.c | 281 ------------------ ...m-qmode-conf.h => lwm2m-queue-mode-conf.h} | 59 ++-- os/services/lwm2m/lwm2m-queue-mode-object.c | 152 ++++++++++ ...ode-object.h => lwm2m-queue-mode-object.h} | 27 +- os/services/lwm2m/lwm2m-queue-mode.c | 173 +++++++++++ os/services/lwm2m/lwm2m-queue-mode.h | 61 ++++ os/services/lwm2m/lwm2m-rd-client.c | 102 +++---- os/services/lwm2m/lwm2m-rd-client.h | 8 +- .../18-coap-lwm2m/08-lwm2m-qmode-ipso-test.sh | 2 +- .../09-lwm2m-qmode-standalone-test.sh | 2 +- .../18-coap-lwm2m/pytests/test-qmode-sleep.py | 4 +- 15 files changed, 527 insertions(+), 422 deletions(-) delete mode 100644 os/services/lwm2m/lwm2m-qmode-object.c rename os/services/lwm2m/{lwm2m-qmode-conf.h => lwm2m-queue-mode-conf.h} (53%) create mode 100644 os/services/lwm2m/lwm2m-queue-mode-object.c rename os/services/lwm2m/{lwm2m-qmode-object.h => lwm2m-queue-mode-object.h} (74%) create mode 100644 os/services/lwm2m/lwm2m-queue-mode.c create mode 100644 os/services/lwm2m/lwm2m-queue-mode.h diff --git a/os/services/lwm2m/lwm2m-engine.c b/os/services/lwm2m/lwm2m-engine.c index b80e6f5a4..36f6fae44 100644 --- a/os/services/lwm2m/lwm2m-engine.c +++ b/os/services/lwm2m/lwm2m-engine.c @@ -81,7 +81,7 @@ #endif /* LWM2M_ENGINE_CONF_USE_RD_CLIENT */ -#if LWM2M_Q_MODE_ENABLED +#if LWM2M_QUEUE_MODE_ENABLED /* Queue Mode is handled using the RD Client and the Q-Mode object */ #define USE_RD_CLIENT 1 /* Queue Mode dynamic adaptation masks */ @@ -93,10 +93,13 @@ #include "lwm2m-rd-client.h" #endif -#if LWM2M_Q_MODE_ENABLED -#include "lwm2m-qmode-object.h" +#if LWM2M_QUEUE_MODE_ENABLED +#include "lwm2m-queue-mode.h" #include "lwm2m-notification-queue.h" -#endif +#if LWM2M_QUEUE_MODE_OBJECT_ENABLED +#include "lwm2m-queue-mode-object.h" +#endif /* LWM2M_QUEUE_MODE_OBJECT_ENABLED */ +#endif /* LWM2M_QUEUE_MODE_ENABLED */ /* MACRO for getting out resource ID from resource array ID + flags */ #define RSC_ID(x) ((uint16_t)(x & 0xffff)) @@ -143,18 +146,18 @@ static struct { /* in the future also a timeout */ } created; -#if LWM2M_Q_MODE_ENABLED +#if LWM2M_QUEUE_MODE_ENABLED static uint8_t waked_up_by_notification; /* For the dynamic adaptation of the awake time */ -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION static uint8_t dynamic_adaptation_params = 0x00; /* bit0: first_request, bit1: handler from notification */ static uint64_t previous_request_time; static inline void clear_first_request(); static inline uint8_t is_first_request(); static inline void clear_handler_from_notification(); static inline uint8_t get_handler_from_notification(); -#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ -#endif /* LWM2M_Q_MODE_ENABLED */ +#endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ +#endif /* LWM2M_QUEUE_MODE_ENABLED */ COAP_HANDLER(lwm2m_handler, lwm2m_handler_callback); LIST(object_list); @@ -581,8 +584,8 @@ lwm2m_engine_init(void) lwm2m_rd_client_init(endpoint); #endif -#if LWM2M_Q_MODE_ENABLED - lwm2m_q_object_init(); +#if LWM2M_QUEUE_MODE_ENABLED && LWM2M_QUEUE_MODE_OBJECT_ENABLED + lwm2m_queue_mode_object_init(); #endif } /*---------------------------------------------------------------------------*/ @@ -1404,22 +1407,23 @@ lwm2m_handler_callback(coap_message_t *request, coap_message_t *response, context.inbuf->pos = 0; /*If Queue Mode, restart the client awake timer */ -#if LWM2M_Q_MODE_ENABLED +#if LWM2M_QUEUE_MODE_ENABLED if(lwm2m_rd_client_is_client_awake()) { lwm2m_rd_client_restart_client_awake_timer(); } -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION - if(lwm2m_q_object_get_dynamic_adaptation_flag() && !get_handler_from_notification()) { +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION + if(lwm2m_queue_mode_get_dynamic_adaptation_flag() && !get_handler_from_notification()) { if(is_first_request()) { previous_request_time = coap_timer_uptime(); clear_first_request(); } else { if(coap_timer_uptime()-previous_request_time >= 0) { if(coap_timer_uptime()-previous_request_time > 0xffff) { - lwm2m_q_object_add_time_to_window(0xffff); + lwm2m_queue_mode_add_time_to_window(0xffff); + } else { + lwm2m_queue_mode_add_time_to_window(coap_timer_uptime()-previous_request_time); } - lwm2m_q_object_add_time_to_window(coap_timer_uptime()-previous_request_time); } previous_request_time = coap_timer_uptime(); } @@ -1427,8 +1431,8 @@ lwm2m_handler_callback(coap_message_t *request, coap_message_t *response, if(get_handler_from_notification()) { clear_handler_from_notification(); } -#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ -#endif /* LWM2M_Q_MODE_ENABLED */ +#endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ +#endif /* LWM2M_QUEUE_MODE_ENABLED */ /* Maybe this should be part of CoAP itself - this seems not to be working with the leshan server */ @@ -1692,8 +1696,8 @@ lwm2m_handler_callback(coap_message_t *request, coap_message_t *response, static void lwm2m_send_notification(char* path) { -#if LWM2M_Q_MODE_ENABLED && LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION - if(lwm2m_q_object_get_dynamic_adaptation_flag()) { +#if LWM2M_QUEUE_MODE_ENABLED && LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION + if(lwm2m_queue_mode_get_dynamic_adaptation_flag()) { lwm2m_engine_set_handler_from_notification(); } #endif @@ -1709,7 +1713,7 @@ lwm2m_notify_object_observers(lwm2m_object_instance_t *obj, snprintf(path, 20, "%d/%d/%d", obj->object_id, obj->instance_id, resource); } -#if LWM2M_Q_MODE_ENABLED +#if LWM2M_QUEUE_MODE_ENABLED if(coap_has_observers(path)) { /* Client is sleeping -> add the notification to the list */ @@ -1719,7 +1723,7 @@ lwm2m_notify_object_observers(lwm2m_object_instance_t *obj, /* if it is the first notification -> wake up and send update */ if(!waked_up_by_notification) { waked_up_by_notification = 1; - lwm2m_rd_client_fsm_execute_q_mode_update(); + lwm2m_rd_client_fsm_execute_queue_mode_update(); } /* Client is awake -> send the notification */ } else { @@ -1732,7 +1736,7 @@ lwm2m_notify_object_observers(lwm2m_object_instance_t *obj, } /*---------------------------------------------------------------------------*/ /* Queue Mode Support and dynamic adaptation of the client awake time */ -#if LWM2M_Q_MODE_ENABLED +#if LWM2M_QUEUE_MODE_ENABLED uint8_t lwm2m_engine_is_waked_up_by_notification() { @@ -1745,7 +1749,7 @@ lwm2m_engine_clear_waked_up_by_notification() waked_up_by_notification = 0; } /*---------------------------------------------------------------------------*/ -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION void lwm2m_engine_set_first_request() { @@ -1781,7 +1785,7 @@ clear_handler_from_notification() { dynamic_adaptation_params &= ~HANDLER_FROM_NOTIFICATION_MASK; } -#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ -#endif /* LWM2M_Q_MODE_ENABLED */ +#endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ +#endif /* LWM2M_QUEUE_MODE_ENABLED */ /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/os/services/lwm2m/lwm2m-engine.h b/os/services/lwm2m/lwm2m-engine.h index 61d0353af..0f6d35734 100644 --- a/os/services/lwm2m/lwm2m-engine.h +++ b/os/services/lwm2m/lwm2m-engine.h @@ -46,7 +46,7 @@ #define LWM2M_ENGINE_H #include "lwm2m-object.h" -#include "lwm2m-qmode-conf.h" +#include "lwm2m-queue-mode-conf.h" #define LWM2M_FLOAT32_BITS 10 #define LWM2M_FLOAT32_FRAC (1L << LWM2M_FLOAT32_BITS) @@ -116,14 +116,14 @@ void lwm2m_notify_object_observers(lwm2m_object_instance_t *obj, void lwm2m_engine_set_opaque_callback(lwm2m_context_t *ctx, lwm2m_write_opaque_callback cb); -#if LWM2M_Q_MODE_ENABLED +#if LWM2M_QUEUE_MODE_ENABLED uint8_t lwm2m_engine_is_waked_up_by_notification(); void lwm2m_engine_clear_waked_up_by_notification(); -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION void lwm2m_engine_set_first_request(); void lwm2m_engine_set_handler_from_notification(); -#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ -#endif /* LWM2M_Q_MODE_ENABLED */ +#endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ +#endif /* LWM2M_QUEUE_MODE_ENABLED */ #endif /* LWM2M_ENGINE_H */ /** @} */ diff --git a/os/services/lwm2m/lwm2m-notification-queue.c b/os/services/lwm2m/lwm2m-notification-queue.c index dab243ec1..e7c57a03c 100644 --- a/os/services/lwm2m/lwm2m-notification-queue.c +++ b/os/services/lwm2m/lwm2m-notification-queue.c @@ -42,9 +42,9 @@ /*---------------------------------------------------------------------------*/ #include "lwm2m-notification-queue.h" -#if LWM2M_Q_MODE_ENABLED +#if LWM2M_QUEUE_MODE_ENABLED -#include "lwm2m-qmode-object.h" +#include "lwm2m-queue-mode.h" #include "lwm2m-engine.h" #include "coap-engine.h" #include "lib/memb.h" @@ -223,8 +223,8 @@ lwm2m_notification_queue_send_notifications() while(iteration_path != NULL) { extend_path(iteration_path, path, sizeof(path)); -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION - if(lwm2m_q_object_get_dynamic_adaptation_flag()) { +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION + if(lwm2m_queue_mode_get_dynamic_adaptation_flag()) { lwm2m_engine_set_handler_from_notification(); } #endif @@ -235,5 +235,5 @@ lwm2m_notification_queue_send_notifications() remove_notification_path(aux); } } -#endif /* LWM2M_Q_MODE_ENABLED */ +#endif /* LWM2M_QUEUE_MODE_ENABLED */ /** @} */ \ No newline at end of file diff --git a/os/services/lwm2m/lwm2m-notification-queue.h b/os/services/lwm2m/lwm2m-notification-queue.h index 3364d3a77..805002cc2 100644 --- a/os/services/lwm2m/lwm2m-notification-queue.h +++ b/os/services/lwm2m/lwm2m-notification-queue.h @@ -44,9 +44,8 @@ #define LWM2M_NOTIFICATION_QUEUE_H #include "contiki.h" -#include "lwm2m-qmode-conf.h" +#include "lwm2m-queue-mode-conf.h" -#if LWM2M_Q_MODE_ENABLED #include typedef struct notification_path { @@ -62,6 +61,5 @@ void lwm2m_notification_queue_add_notification_path(char *path); void lwm2m_notification_queue_send_notifications(); -#endif /* LWM2M_Q_MODE_ENABLED */ #endif /* LWM2M_NOTIFICATION_QUEUE_H */ /** @} */ \ No newline at end of file diff --git a/os/services/lwm2m/lwm2m-qmode-object.c b/os/services/lwm2m/lwm2m-qmode-object.c deleted file mode 100644 index be5bc7674..000000000 --- a/os/services/lwm2m/lwm2m-qmode-object.c +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Copyright (c) 2017, 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. - */ - -/** - * \addtogroup lwm2m - * @{ - */ - -/** - * \file - * Implementation of the Contiki OMA LWM2M Queue Object for managing the queue mode - * \author - * Carlos Gonzalo Peces - */ - -#include "lwm2m-qmode-object.h" - -#if LWM2M_Q_MODE_ENABLED - -#include "lwm2m-object.h" -#include "lwm2m-engine.h" -#include "lwm2m-rd-client.h" -#include "lib/memb.h" -#include "lib/list.h" -#include - -/* Log configuration */ -#include "coap-log.h" -#define LOG_MODULE "lwm2m-qmode-object" -#define LOG_LEVEL LOG_LEVEL_LWM2M - -#define LWM2M_Q_OBJECT_ID 6000 -#define LWM2M_AWAKE_TIME_ID 3000 -#define LWM2M_SLEEP_TIME_ID 3001 - -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION -#define LWM2M_DYNAMIC_ADAPTATION_FLAG_ID 3002 -#define UPDATE_WITH_MEAN 0 /* 1-mean time 0-maximum time */ -#endif - -static const lwm2m_resource_id_t resources[] = -{ RW(LWM2M_AWAKE_TIME_ID), - RW(LWM2M_SLEEP_TIME_ID), -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION - RW(LWM2M_DYNAMIC_ADAPTATION_FLAG_ID), -#endif -}; - -static uint16_t q_mode_awake_time = LWM2M_Q_MODE_DEFAULT_CLIENT_AWAKE_TIME; -static uint32_t q_mode_sleep_time = LWM2M_Q_MODE_DEFAULT_CLIENT_SLEEP_TIME; -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION -static uint8_t q_mode_dynamic_adaptation_flag = LWM2M_Q_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG; - -/* Window to save the times and do the dynamic adaptation of the awake time*/ -uint16_t times_window[LWM2M_Q_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH] = { 0 }; -uint8_t times_window_index = 0; - -#endif -/*---------------------------------------------------------------------------*/ -uint16_t -lwm2m_q_object_get_awake_time() -{ - LOG_DBG("Client Awake Time: %d ms\n", (int)q_mode_awake_time); - return q_mode_awake_time; -} -/*---------------------------------------------------------------------------*/ -static void -lwm2m_q_object_set_awake_time(uint16_t time) -{ - q_mode_awake_time = time; -} -/*---------------------------------------------------------------------------*/ -uint32_t -lwm2m_q_object_get_sleep_time() -{ - LOG_DBG("Client Sleep Time: %d ms\n", (int)q_mode_sleep_time); - return q_mode_sleep_time; -} -/*---------------------------------------------------------------------------*/ -static void -lwm2m_q_object_set_sleep_time(uint32_t time) -{ - q_mode_sleep_time = time; -} -/*---------------------------------------------------------------------------*/ -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION -uint8_t -lwm2m_q_object_get_dynamic_adaptation_flag() -{ - LOG_DBG("Dynamic Adaptation Flag: %d ms\n", (int)q_mode_dynamic_adaptation_flag); - return q_mode_dynamic_adaptation_flag; -} -/*---------------------------------------------------------------------------*/ -static void -lwm2m_q_object_set_dynamic_adaptation_flag(uint8_t flag) -{ - q_mode_dynamic_adaptation_flag = flag; -} -/*---------------------------------------------------------------------------*/ -#if !UPDATE_WITH_MEAN -static uint16_t -get_maximum_time() -{ - uint16_t max_time = 0; - uint8_t i; - for(i = 0; i < LWM2M_Q_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH; i++) { - if(times_window[i] > max_time) { - max_time = times_window[i]; - } - } - return max_time; -} -#endif -/*---------------------------------------------------------------------------*/ -#if UPDATE_WITH_MEAN -static uint16_t -get_mean_time() -{ - uint16_t mean_time = 0; - uint8_t i; - for(i = 0; i < LWM2M_Q_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH; i++) { - if(mean_time == 0) { - mean_time = times_window[i]; - } else { - if(times_window[i] != 0) { - mean_time = (mean_time + times_window[i]) / 2; - } - } - } - return mean_time; -} -#endif -/*---------------------------------------------------------------------------*/ -static void -update_awake_time() -{ -#if UPDATE_WITH_MEAN - uint16_t mean_time = get_mean_time(); - LOG_DBG("Dynamic Adaptation: updated awake time: %d ms\n", (int)mean_time); - lwm2m_q_object_set_awake_time(mean_time + (mean_time >> 1)); /* 50% margin */ - return; -#else - uint16_t max_time = get_maximum_time(); - LOG_DBG("Dynamic Adaptation: updated awake time: %d ms\n", (int)max_time); - lwm2m_q_object_set_awake_time(max_time + (max_time >> 1)); /* 50% margin */ - return; -#endif -} -/*---------------------------------------------------------------------------*/ -void -lwm2m_q_object_add_time_to_window(uint16_t time) -{ - if(times_window_index == LWM2M_Q_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH) { - times_window_index = 0; - } - times_window[times_window_index] = time; - times_window_index++; - update_awake_time(); -} -#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ -/*---------------------------------------------------------------------------*/ -static lwm2m_status_t -lwm2m_callback(lwm2m_object_instance_t *object, lwm2m_context_t *ctx) -{ - if(ctx->operation == LWM2M_OP_READ) { - switch(ctx->resource_id) { - case LWM2M_AWAKE_TIME_ID: - lwm2m_object_write_int(ctx, (int32_t)q_mode_awake_time); - return LWM2M_STATUS_OK; - case LWM2M_SLEEP_TIME_ID: - lwm2m_object_write_int(ctx, (int32_t)q_mode_sleep_time); - return LWM2M_STATUS_OK; -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION - case LWM2M_DYNAMIC_ADAPTATION_FLAG_ID: - lwm2m_object_write_int(ctx, (int32_t)q_mode_dynamic_adaptation_flag); - return LWM2M_STATUS_OK; -#endif - } - } else if(ctx->operation == LWM2M_OP_WRITE) { - switch(ctx->resource_id) { - int32_t value_read; - size_t len; - - case LWM2M_AWAKE_TIME_ID: - - len = lwm2m_object_read_int(ctx, ctx->inbuf->buffer, ctx->inbuf->size, - &value_read); - LOG_DBG("Client Awake Time write request value: %d\n", (int)value_read); - if(len == 0) { - LOG_WARN("FAIL: could not write awake time\n"); - return LWM2M_STATUS_WRITE_ERROR; - } else { - lwm2m_q_object_set_awake_time(value_read); - return LWM2M_STATUS_OK; - } - - case LWM2M_SLEEP_TIME_ID: - len = lwm2m_object_read_int(ctx, ctx->inbuf->buffer, ctx->inbuf->size, - &value_read); - LOG_DBG("Client Sleep Time write request value: %d\n", (int)value_read); - if(len == 0) { - LOG_WARN("FAIL: could not write sleep time\n"); - return LWM2M_STATUS_WRITE_ERROR; - } else { - lwm2m_q_object_set_sleep_time(value_read); - return LWM2M_STATUS_OK; - } -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION - case LWM2M_DYNAMIC_ADAPTATION_FLAG_ID: - len = lwm2m_object_read_int(ctx, ctx->inbuf->buffer, ctx->inbuf->size, - &value_read); - LOG_DBG("Dynamic Adaptation Flag request value: %d\n", (int)value_read); - if(len == 0) { - LOG_WARN("FAIL: could not write dynamic flag\n"); - return LWM2M_STATUS_WRITE_ERROR; - } else { - lwm2m_q_object_set_dynamic_adaptation_flag(value_read); - return LWM2M_STATUS_OK; - } -#endif - } - } - - return LWM2M_STATUS_OPERATION_NOT_ALLOWED; -} -/*---------------------------------------------------------------------------*/ -static lwm2m_object_instance_t queue_object = { - .object_id = LWM2M_Q_OBJECT_ID, - .instance_id = 0, - .resource_ids = resources, - .resource_count = sizeof(resources) / sizeof(lwm2m_resource_id_t), - .resource_dim_callback = NULL, - .callback = lwm2m_callback, -}; -/*---------------------------------------------------------------------------*/ -void -lwm2m_q_object_init(void) -{ - lwm2m_engine_add_object(&queue_object); -} -/*---------------------------------------------------------------------------*/ -void -lwm2m_q_object_send_notifications() -{ - lwm2m_notify_object_observers(&queue_object, LWM2M_AWAKE_TIME_ID); - lwm2m_notify_object_observers(&queue_object, LWM2M_SLEEP_TIME_ID); -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION - lwm2m_notify_object_observers(&queue_object, LWM2M_DYNAMIC_ADAPTATION_FLAG_ID); -#endif -} -/*---------------------------------------------------------------------------*/ -#endif /* LWM2M_Q_MODE_ENABLED */ -/** @} */ - diff --git a/os/services/lwm2m/lwm2m-qmode-conf.h b/os/services/lwm2m/lwm2m-queue-mode-conf.h similarity index 53% rename from os/services/lwm2m/lwm2m-qmode-conf.h rename to os/services/lwm2m/lwm2m-queue-mode-conf.h index 1220d0584..3432c112a 100644 --- a/os/services/lwm2m/lwm2m-qmode-conf.h +++ b/os/services/lwm2m/lwm2m-queue-mode-conf.h @@ -40,46 +40,57 @@ * Carlos Gonzalo Peces */ -#ifndef LWM2M_QMODE_CONF_H -#define LWM2M_QMODE_CONF_H +#ifndef LWM2M_QUEUE_MODE_CONF_H +#define LWM2M_QUEUE_MODE_CONF_H + +#include "contiki.h" /* Enable the Queue Mode */ -#ifdef LWM2M_Q_MODE_CONF_ENABLED -#define LWM2M_Q_MODE_ENABLED LWM2M_Q_MODE_CONF_ENABLED +#ifdef LWM2M_QUEUE_MODE_CONF_ENABLED +#define LWM2M_QUEUE_MODE_ENABLED LWM2M_QUEUE_MODE_CONF_ENABLED #else -#define LWM2M_Q_MODE_ENABLED 0 -#endif /* LWM2M_Q_MODE_CONF_ENABLED */ +#define LWM2M_QUEUE_MODE_ENABLED 0 +#endif /* LWM2M_QUEUE_MODE_CONF_ENABLED */ /* Default Sleeping Time */ -#ifdef LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_SLEEP_TIME -#define LWM2M_Q_MODE_DEFAULT_CLIENT_SLEEP_TIME LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_SLEEP_TIME +#ifdef LWM2M_QUEUE_MODE_CONF_DEFAULT_CLIENT_SLEEP_TIME +#define LWM2M_QUEUE_MODE_DEFAULT_CLIENT_SLEEP_TIME LWM2M_QUEUE_MODE_CONF_DEFAULT_CLIENT_SLEEP_TIME #else -#define LWM2M_Q_MODE_DEFAULT_CLIENT_SLEEP_TIME 10000 /* msec */ -#endif /* LWM2M_Q_MODE_DEFAULT_CLIENT_SLEEPING_TIME */ +#define LWM2M_QUEUE_MODE_DEFAULT_CLIENT_SLEEP_TIME 10000 /* msec */ +#endif /* LWM2M_QUEUE_MODE_DEFAULT_CLIENT_SLEEPING_TIME */ /* Default Awake Time */ -#ifdef LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_AWAKE_TIME -#define LWM2M_Q_MODE_DEFAULT_CLIENT_AWAKE_TIME LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_AWAKE_TIME +#ifdef LWM2M_QUEUE_MODE_CONF_DEFAULT_CLIENT_AWAKE_TIME +#define LWM2M_QUEUE_MODE_DEFAULT_CLIENT_AWAKE_TIME LWM2M_QUEUE_MODE_CONF_DEFAULT_CLIENT_AWAKE_TIME #else -#define LWM2M_Q_MODE_DEFAULT_CLIENT_AWAKE_TIME 5000 /* msec */ -#endif /* LWM2M_Q_MODE_DEFAULT_CLIENT_AWAKE_TIME */ +#define LWM2M_QUEUE_MODE_DEFAULT_CLIENT_AWAKE_TIME 5000 /* msec */ +#endif /* LWM2M_QUEUE_MODE_DEFAULT_CLIENT_AWAKE_TIME */ /* Include the possibility to do the dynamic adaptation of the client awake time */ -#ifdef LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION -#define LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION +#ifdef LWM2M_QUEUE_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION +#define LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION LWM2M_QUEUE_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION #else -#define LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION 0 /* not included */ -#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ +#define LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION 0 /* not included */ +#endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ /* Default value for the dynamic adaptation flag */ -#ifdef LWM2M_Q_MODE_CONF_DEFAULT_DYNAMIC_ADAPTATION_FLAG -#define LWM2M_Q_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG LWM2M_Q_MODE_CONF_DEFAULT_DYNAMIC_ADAPTATION_FLAG +#ifdef LWM2M_QUEUE_MODE_CONF_DEFAULT_DYNAMIC_ADAPTATION_FLAG +#define LWM2M_QUEUE_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG LWM2M_QUEUE_MODE_CONF_DEFAULT_DYNAMIC_ADAPTATION_FLAG #else -#define LWM2M_Q_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG 0 /* disabled */ -#endif /* LWM2M_Q_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG */ +#define LWM2M_QUEUE_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG 0 /* disabled */ +#endif /* LWM2M_QUEUE_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG */ /* Length of the list of times for the dynamic adaptation */ -#define LWM2M_Q_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH 10 +#define LWM2M_QUEUE_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH 10 -#endif /* LWM2M_QMODE_CONF_H */ +/* Enable and disable the Queue Mode Object */ +#ifdef LWM2M_QUEUE_MODE_OBJECT_CONF_ENABLED +#define LWM2M_QUEUE_MODE_OBJECT_ENABLED LWM2M_QUEUE_MODE_OBJECT_CONF_ENABLED +#else +#define LWM2M_QUEUE_MODE_OBJECT_ENABLED 0 /* not included */ +#endif /* LWM2M_QUEUE_MODE_OBJECT_ENABLED */ + + + +#endif /* LWM2M_QUEUE_MODE_CONF_H */ /** @} */ diff --git a/os/services/lwm2m/lwm2m-queue-mode-object.c b/os/services/lwm2m/lwm2m-queue-mode-object.c new file mode 100644 index 000000000..a3c000d69 --- /dev/null +++ b/os/services/lwm2m/lwm2m-queue-mode-object.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2017, 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. + */ + +/** + * \addtogroup lwm2m + * @{ + */ + +/** + * \file + * Implementation of the Contiki OMA LWM2M Queue Mode object + to manage the parameters from the server side + * \author + * Carlos Gonzalo Peces + */ + +#include "lwm2m-object.h" +#include "lwm2m-queue-mode.h" + +/* Log configuration */ +#include "coap-log.h" +#define LOG_MODULE "lwm2m-qmode-object" +#define LOG_LEVEL LOG_LEVEL_LWM2M + +#if LWM2M_QUEUE_MODE_ENABLED && LWM2M_QUEUE_MODE_OBJECT_ENABLED + +#define LWM2M_QUEUE_MODE_OBJECT_ID 30000 +#define LWM2M_AWAKE_TIME_ID 30000 +#define LWM2M_SLEEP_TIME_ID 30001 + +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION +#define LWM2M_DYNAMIC_ADAPTATION_FLAG_ID 30002 +#define UPDATE_WITH_MEAN 0 /* 1-mean time 0-maximum time */ +#endif + +static const lwm2m_resource_id_t resources[] = +{ RW(LWM2M_AWAKE_TIME_ID), + RW(LWM2M_SLEEP_TIME_ID), +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION + RW(LWM2M_DYNAMIC_ADAPTATION_FLAG_ID), +#endif +}; + +/*---------------------------------------------------------------------------*/ +static lwm2m_status_t +lwm2m_callback(lwm2m_object_instance_t *object, lwm2m_context_t *ctx) +{ + if(ctx->operation == LWM2M_OP_READ) { + switch(ctx->resource_id) { + case LWM2M_AWAKE_TIME_ID: + lwm2m_object_write_int(ctx, (int32_t)lwm2m_queue_mode_get_awake_time()); + return LWM2M_STATUS_OK; + case LWM2M_SLEEP_TIME_ID: + lwm2m_object_write_int(ctx, (int32_t)lwm2m_queue_mode_get_sleep_time()); + return LWM2M_STATUS_OK; +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION + case LWM2M_DYNAMIC_ADAPTATION_FLAG_ID: + lwm2m_object_write_int(ctx, (int32_t)lwm2m_queue_mode_get_dynamic_adaptation_flag()); + return LWM2M_STATUS_OK; +#endif + } + } else if(ctx->operation == LWM2M_OP_WRITE) { + switch(ctx->resource_id) { + int32_t value_read; + size_t len; + + case LWM2M_AWAKE_TIME_ID: + + len = lwm2m_object_read_int(ctx, ctx->inbuf->buffer, ctx->inbuf->size, + &value_read); + LOG_DBG("Client Awake Time write request value: %d\n", (int)value_read); + if(len == 0) { + LOG_WARN("FAIL: could not write awake time\n"); + return LWM2M_STATUS_WRITE_ERROR; + } else { + lwm2m_queue_mode_set_awake_time(value_read); + return LWM2M_STATUS_OK; + } + + case LWM2M_SLEEP_TIME_ID: + len = lwm2m_object_read_int(ctx, ctx->inbuf->buffer, ctx->inbuf->size, + &value_read); + LOG_DBG("Client Sleep Time write request value: %d\n", (int)value_read); + if(len == 0) { + LOG_WARN("FAIL: could not write sleep time\n"); + return LWM2M_STATUS_WRITE_ERROR; + } else { + lwm2m_queue_mode_set_sleep_time(value_read); + return LWM2M_STATUS_OK; + } +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION + case LWM2M_DYNAMIC_ADAPTATION_FLAG_ID: + len = lwm2m_object_read_int(ctx, ctx->inbuf->buffer, ctx->inbuf->size, + &value_read); + LOG_DBG("Dynamic Adaptation Flag request value: %d\n", (int)value_read); + if(len == 0) { + LOG_WARN("FAIL: could not write dynamic flag\n"); + return LWM2M_STATUS_WRITE_ERROR; + } else { + lwm2m_queue_mode_set_dynamic_adaptation_flag(value_read); + return LWM2M_STATUS_OK; + } +#endif + } + } + + return LWM2M_STATUS_OPERATION_NOT_ALLOWED; +} +/*---------------------------------------------------------------------------*/ +static lwm2m_object_instance_t queue_object = { + .object_id = LWM2M_QUEUE_MODE_OBJECT_ID, + .instance_id = 0, + .resource_ids = resources, + .resource_count = sizeof(resources) / sizeof(lwm2m_resource_id_t), + .resource_dim_callback = NULL, + .callback = lwm2m_callback, +}; +/*---------------------------------------------------------------------------*/ +void +lwm2m_queue_mode_object_init(void) +{ + lwm2m_engine_add_object(&queue_object); +} +#endif /* LWM2M_QUEUE_MODE_ENABLED && LWM2M_QUEUE_MODE_OBJECT_ENABLED */ +/** @} */ \ No newline at end of file diff --git a/os/services/lwm2m/lwm2m-qmode-object.h b/os/services/lwm2m/lwm2m-queue-mode-object.h similarity index 74% rename from os/services/lwm2m/lwm2m-qmode-object.h rename to os/services/lwm2m/lwm2m-queue-mode-object.h index 61ac35ff3..017b797fc 100644 --- a/os/services/lwm2m/lwm2m-qmode-object.h +++ b/os/services/lwm2m/lwm2m-queue-mode-object.h @@ -35,31 +35,18 @@ /** * \file - * Header file for the Contiki OMA LWM2M Queue Object for managing the queue mode + * Header file for the Contiki OMA LWM2M Queue Mode object + to manage the parameters from the server side * \author * Carlos Gonzalo Peces */ -#ifndef LWM2M_Q_OBJECT_H_ -#define LWM2M_Q_OBJECT_H_ +#ifndef LWM2M_QUEUE_MODE_OBJECT_H_ +#define LWM2M_QUEUE_MODE_OBJECT_H_ -#include "contiki.h" -#include "lwm2m-qmode-conf.h" +#include "lwm2m-queue-mode-conf.h" -#if LWM2M_Q_MODE_ENABLED -#include +void lwm2m_queue_mode_object_init(void); -uint16_t lwm2m_q_object_get_awake_time(); -uint32_t lwm2m_q_object_get_sleep_time(); -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION -uint8_t lwm2m_q_object_get_dynamic_adaptation_flag(); -void lwm2m_q_object_add_time_to_window(uint16_t time); -#endif - -void lwm2m_q_object_send_notifications(); - -void lwm2m_q_object_init(void); - -#endif /* LWM2M_Q_MODE_ENABLED */ #endif /* LWM2M_Q_OBJECT_H_ */ -/** @} */ +/** @} */ \ No newline at end of file diff --git a/os/services/lwm2m/lwm2m-queue-mode.c b/os/services/lwm2m/lwm2m-queue-mode.c new file mode 100644 index 000000000..30c8dd6cc --- /dev/null +++ b/os/services/lwm2m/lwm2m-queue-mode.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2017, 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. + */ + +/** + * \addtogroup lwm2m + * @{ + */ + +/** + * \file + * Implementation of the Contiki OMA LWM2M Queue Mode for managing the parameters + * \author + * Carlos Gonzalo Peces + */ + +#include "lwm2m-queue-mode.h" + +#if LWM2M_QUEUE_MODE_ENABLED + +#include "lwm2m-engine.h" +#include "lwm2m-rd-client.h" +#include "lib/memb.h" +#include "lib/list.h" +#include + +/* Log configuration */ +#include "coap-log.h" +#define LOG_MODULE "lwm2m-queue-mode" +#define LOG_LEVEL LOG_LEVEL_LWM2M + + +static uint16_t queue_mode_awake_time = LWM2M_QUEUE_MODE_DEFAULT_CLIENT_AWAKE_TIME; +static uint32_t queue_mode_sleep_time = LWM2M_QUEUE_MODE_DEFAULT_CLIENT_SLEEP_TIME; +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION +static uint8_t queue_mode_dynamic_adaptation_flag = LWM2M_QUEUE_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG; + +/* Window to save the times and do the dynamic adaptation of the awake time*/ +uint16_t times_window[LWM2M_QUEUE_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH] = { 0 }; +uint8_t times_window_index = 0; + +#endif +/*---------------------------------------------------------------------------*/ +uint16_t +lwm2m_queue_mode_get_awake_time() +{ + LOG_DBG("Client Awake Time: %d ms\n", (int)queue_mode_awake_time); + return queue_mode_awake_time; +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_queue_mode_set_awake_time(uint16_t time) +{ + queue_mode_awake_time = time; +} +/*---------------------------------------------------------------------------*/ +uint32_t +lwm2m_queue_mode_get_sleep_time() +{ + LOG_DBG("Client Sleep Time: %d ms\n", (int)queue_mode_sleep_time); + return queue_mode_sleep_time; +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_queue_mode_set_sleep_time(uint32_t time) +{ + queue_mode_sleep_time = time; +} +/*---------------------------------------------------------------------------*/ +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION +uint8_t +lwm2m_queue_mode_get_dynamic_adaptation_flag() +{ + LOG_DBG("Dynamic Adaptation Flag: %d ms\n", (int)queue_mode_dynamic_adaptation_flag); + return queue_mode_dynamic_adaptation_flag; +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_queue_mode_set_dynamic_adaptation_flag(uint8_t flag) +{ + queue_mode_dynamic_adaptation_flag = flag; +} +/*---------------------------------------------------------------------------*/ +#if !UPDATE_WITH_MEAN +static uint16_t +get_maximum_time() +{ + uint16_t max_time = 0; + uint8_t i; + for(i = 0; i < LWM2M_QUEUE_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH; i++) { + if(times_window[i] > max_time) { + max_time = times_window[i]; + } + } + return max_time; +} +#endif +/*---------------------------------------------------------------------------*/ +#if UPDATE_WITH_MEAN +static uint16_t +get_mean_time() +{ + uint16_t mean_time = 0; + uint8_t i; + for(i = 0; i < LWM2M_QUEUE_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH; i++) { + if(mean_time == 0) { + mean_time = times_window[i]; + } else { + if(times_window[i] != 0) { + mean_time = (mean_time + times_window[i]) / 2; + } + } + } + return mean_time; +} +#endif +/*---------------------------------------------------------------------------*/ +static void +update_awake_time() +{ +#if UPDATE_WITH_MEAN + uint16_t mean_time = get_mean_time(); + LOG_DBG("Dynamic Adaptation: updated awake time: %d ms\n", (int)mean_time); + lwm2m_queue_mode_set_awake_time(mean_time + (mean_time >> 1)); /* 50% margin */ + return; +#else + uint16_t max_time = get_maximum_time(); + LOG_DBG("Dynamic Adaptation: updated awake time: %d ms\n", (int)max_time); + lwm2m_queue_mode_set_awake_time(max_time + (max_time >> 1)); /* 50% margin */ + return; +#endif +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_queue_mode_add_time_to_window(uint16_t time) +{ + if(times_window_index == LWM2M_QUEUE_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH) { + times_window_index = 0; + } + times_window[times_window_index] = time; + times_window_index++; + update_awake_time(); +} +#endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ +#endif /* LWM2M_QUEUE_MODE_ENABLED */ +/** @} */ + diff --git a/os/services/lwm2m/lwm2m-queue-mode.h b/os/services/lwm2m/lwm2m-queue-mode.h new file mode 100644 index 000000000..cc3bd3290 --- /dev/null +++ b/os/services/lwm2m/lwm2m-queue-mode.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2017, 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. + */ + +/** + * \addtogroup oma-lwm2m + * @{ + */ + +/** + * \file + * Header file for the Contiki OMA LWM2M Queue Mode implementation + to manage the parameters + * \author + * Carlos Gonzalo Peces + */ + +#ifndef LWM2M_QUEUE_MODE_H_ +#define LWM2M_QUEUE_MODE_H_ + +#include "lwm2m-queue-mode-conf.h" +#include + +uint16_t lwm2m_queue_mode_get_awake_time(); +void lwm2m_queue_mode_set_awake_time(uint16_t time); +uint32_t lwm2m_queue_mode_get_sleep_time(); +void lwm2m_queue_mode_set_sleep_time(uint32_t time); +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION +uint8_t lwm2m_queue_mode_get_dynamic_adaptation_flag(); +void lwm2m_queue_mode_set_dynamic_adaptation_flag(uint8_t flag); +void lwm2m_queue_mode_add_time_to_window(uint16_t time); +#endif + +#endif /* LWM2M_QUEUE_MODE_H_ */ +/** @} */ diff --git a/os/services/lwm2m/lwm2m-rd-client.c b/os/services/lwm2m/lwm2m-rd-client.c index cf7c5deb3..da8d276d0 100644 --- a/os/services/lwm2m/lwm2m-rd-client.c +++ b/os/services/lwm2m/lwm2m-rd-client.c @@ -62,10 +62,10 @@ #include "rpl.h" #endif /* UIP_CONF_IPV6_RPL */ -#if LWM2M_Q_MODE_ENABLED -#include "lwm2m-qmode-object.h" +#if LWM2M_QUEUE_MODE_ENABLED +#include "lwm2m-queue-mode.h" #include "lwm2m-notification-queue.h" -#endif /* LWM2M_Q_MODE_ENABLED */ +#endif /* LWM2M_QUEUE_MODE_ENABLED */ /* Log configuration */ #include "coap-log.h" @@ -105,9 +105,9 @@ static coap_message_t request[1]; /* This way the message can be treated as #define DEREGISTER_SENT 11 #define DEREGISTER_FAILED 12 #define DEREGISTERED 13 -#if LWM2M_Q_MODE_ENABLED -#define Q_MODE_AWAKE 14 -#define Q_MODE_SEND_UPDATE 15 +#if LWM2M_QUEUE_MODE_ENABLED +#define QUEUE_MODE_AWAKE 14 +#define QUEUE_MODE_SEND_UPDATE 15 #endif #define FLAG_RD_DATA_DIRTY 0x01 @@ -130,16 +130,16 @@ static void (*rd_callback)(coap_request_state_t *state); static coap_timer_t block1_timer; -#if LWM2M_Q_MODE_ENABLED -static coap_timer_t q_mode_client_awake_timer; /* Timer to control the client's +#if LWM2M_QUEUE_MODE_ENABLED +static coap_timer_t queue_mode_client_awake_timer; /* Timer to control the client's * awake time */ -static uint8_t q_mode_client_awake; /* 1 - client is awake, +static uint8_t queue_mode_client_awake; /* 1 - client is awake, * 0 - client is sleeping */ -static uint16_t q_mode_client_awake_time; /* The time to be awake */ +static uint16_t queue_mode_client_awake_time; /* The time to be awake */ /* Callback for the client awake timer */ -static void q_mode_awake_timer_callback(coap_timer_t *timer); +static void queue_mode_awake_timer_callback(coap_timer_t *timer); #endif static void check_periodic_observations(); @@ -445,13 +445,13 @@ registration_callback(coap_request_state_t *state) state->response->location_path_len); session_info.assigned_ep[state->response->location_path_len] = 0; /* if we decide to not pass the lt-argument on registration, we should force an initial "update" to register lifetime with server */ -#if LWM2M_Q_MODE_ENABLED -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION - if(lwm2m_q_object_get_dynamic_adaptation_flag()) { +#if LWM2M_QUEUE_MODE_ENABLED +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION + if(lwm2m_queue_mode_get_dynamic_adaptation_flag()) { lwm2m_engine_set_first_request(); } #endif - lwm2m_rd_client_fsm_execute_q_mode_awake(); /* Avoid 500 ms delay and move directly to the state*/ + lwm2m_rd_client_fsm_execute_queue_mode_awake(); /* Avoid 500 ms delay and move directly to the state*/ #else rd_state = REGISTRATION_DONE; #endif @@ -499,23 +499,23 @@ update_callback(coap_request_state_t *state) LOG_DBG_("Done!\n"); /* remember the last reg time */ last_update = coap_timer_uptime(); -#if LWM2M_Q_MODE_ENABLED +#if LWM2M_QUEUE_MODE_ENABLED /* If it has been waked up by a notification, send the stored notifications in queue */ if(lwm2m_engine_is_waked_up_by_notification()) { lwm2m_engine_clear_waked_up_by_notification(); lwm2m_notification_queue_send_notifications(); } -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION - if(lwm2m_q_object_get_dynamic_adaptation_flag()) { +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION + if(lwm2m_queue_mode_get_dynamic_adaptation_flag()) { lwm2m_engine_set_first_request(); } -#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ - lwm2m_rd_client_fsm_execute_q_mode_awake(); /* Avoid 500 ms delay and move directly to the state*/ +#endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ + lwm2m_rd_client_fsm_execute_queue_mode_awake(); /* Avoid 500 ms delay and move directly to the state*/ #else rd_state = REGISTRATION_DONE; rd_flags &= ~FLAG_RD_DATA_UPDATE_TRIGGERED; -#endif /* LWM2M_Q_MODE_ENABLED */ +#endif /* LWM2M_QUEUE_MODE_ENABLED */ } else { /* Possible error response codes are 4.00 Bad request & 4.04 Not Found */ LOG_DBG_("Failed with code %d. Retrying registration\n", @@ -562,7 +562,7 @@ periodic_process(coap_timer_t *timer) uint64_t now; /* reschedule the CoAP timer */ -#if LWM2M_Q_MODE_ENABLED +#if LWM2M_QUEUE_MODE_ENABLED /* In Queue Mode, the machine is not executed periodically, but with the awake/sleeping times */ if(!((rd_state & 0xF) == 0xE)) { coap_timer_reset(&rd_timer, STATE_MACHINE_UPDATE_INTERVAL); @@ -739,27 +739,27 @@ periodic_process(coap_timer_t *timer) rd_state = UPDATE_SENT; } break; -#if LWM2M_Q_MODE_ENABLED - case Q_MODE_AWAKE: +#if LWM2M_QUEUE_MODE_ENABLED + case QUEUE_MODE_AWAKE: LOG_DBG("Queue Mode: Client is AWAKE at %lu\n", (unsigned long)coap_timer_uptime()); - q_mode_client_awake = 1; - q_mode_client_awake_time = lwm2m_q_object_get_awake_time(); - coap_timer_set(&q_mode_client_awake_timer, q_mode_client_awake_time); + queue_mode_client_awake = 1; + queue_mode_client_awake_time = lwm2m_queue_mode_get_awake_time(); + coap_timer_set(&queue_mode_client_awake_timer, queue_mode_client_awake_time); break; - case Q_MODE_SEND_UPDATE: + case QUEUE_MODE_SEND_UPDATE: /* Define this macro to make the necessary actions for waking up, * depending on the platform */ -#ifdef LWM2M_Q_MODE_WAKE_UP - LWM2M_Q_MODE_WAKE_UP(); -#endif /* LWM2M_Q_MODE_WAKE_UP */ +#ifdef LWM2M_QUEUE_MODE_WAKE_UP + LWM2M_QUEUE_MODE_WAKE_UP(); +#endif /* LWM2M_QUEUE_MODE_WAKE_UP */ prepare_update(request, rd_flags & FLAG_RD_DATA_UPDATE_TRIGGERED); coap_send_request(&rd_request_state, &session_info.server_ep, request, update_callback); last_rd_progress = coap_timer_uptime(); rd_state = UPDATE_SENT; break; -#endif /* LWM2M_Q_MODE_ENABLED */ +#endif /* LWM2M_QUEUE_MODE_ENABLED */ case UPDATE_SENT: /* just wait until the callback kicks us to the next state... */ @@ -793,12 +793,12 @@ lwm2m_rd_client_init(const char *ep) { session_info.ep = ep; /* default binding U = UDP, UQ = UDP Q-mode*/ -#if LWM2M_Q_MODE_ENABLED +#if LWM2M_QUEUE_MODE_ENABLED session_info.binding = "UQ"; /* Enough margin to ensure that the client is not unregistered (we * do not know the time it can stay awake) */ - session_info.lifetime = (LWM2M_Q_MODE_DEFAULT_CLIENT_SLEEP_TIME / 1000) * 2; + session_info.lifetime = (LWM2M_QUEUE_MODE_DEFAULT_CLIENT_SLEEP_TIME / 1000) * 2; #else session_info.binding = "U"; if(session_info.lifetime == 0) { @@ -811,8 +811,8 @@ lwm2m_rd_client_init(const char *ep) /* call the RD client periodically */ coap_timer_set_callback(&rd_timer, periodic_process); coap_timer_set(&rd_timer, STATE_MACHINE_UPDATE_INTERVAL); -#if LWM2M_Q_MODE_ENABLED - coap_timer_set_callback(&q_mode_client_awake_timer, q_mode_awake_timer_callback); +#if LWM2M_QUEUE_MODE_ENABLED + coap_timer_set_callback(&queue_mode_client_awake_timer, queue_mode_awake_timer_callback); #endif } /*---------------------------------------------------------------------------*/ @@ -825,51 +825,51 @@ check_periodic_observations(void) /* *Queue Mode Support */ -#if LWM2M_Q_MODE_ENABLED +#if LWM2M_QUEUE_MODE_ENABLED /*---------------------------------------------------------------------------*/ void lwm2m_rd_client_restart_client_awake_timer(void) { - coap_timer_set(&q_mode_client_awake_timer, q_mode_client_awake_time); + coap_timer_set(&queue_mode_client_awake_timer, queue_mode_client_awake_time); } /*---------------------------------------------------------------------------*/ uint8_t lwm2m_rd_client_is_client_awake(void) { - return q_mode_client_awake; + return queue_mode_client_awake; } /*---------------------------------------------------------------------------*/ static void -q_mode_awake_timer_callback(coap_timer_t *timer) +queue_mode_awake_timer_callback(coap_timer_t *timer) { /* Timer has expired, no requests has been received, client can go to sleep */ LOG_DBG("Queue Mode: Client is SLEEPING at %lu\n", (unsigned long)coap_timer_uptime()); - q_mode_client_awake = 0; + queue_mode_client_awake = 0; /* Define this macro to enter sleep mode depending on the platform */ -#ifdef LWM2M_Q_MODE_SLEEP_MS - LWM2M_Q_MODE_SLEEP_MS(lwm2m_q_object_get_sleep_time()); -#endif /* LWM2M_Q_MODE_SLEEP_MS */ - rd_state = Q_MODE_SEND_UPDATE; - coap_timer_set(&rd_timer, lwm2m_q_object_get_sleep_time()); +#ifdef LWM2M_QUEUE_MODE_SLEEP_MS + LWM2M_QUEUE_MODE_SLEEP_MS(lwm2m_queue_mode_get_sleep_time()); +#endif /* LWM2M_QUEUE_MODE_SLEEP_MS */ + rd_state = QUEUE_MODE_SEND_UPDATE; + coap_timer_set(&rd_timer, lwm2m_queue_mode_get_sleep_time()); } /*---------------------------------------------------------------------------*/ void -lwm2m_rd_client_fsm_execute_q_mode_awake() +lwm2m_rd_client_fsm_execute_queue_mode_awake() { coap_timer_stop(&rd_timer); - rd_state = Q_MODE_AWAKE; + rd_state = QUEUE_MODE_AWAKE; periodic_process(&rd_timer); } /*---------------------------------------------------------------------------*/ void -lwm2m_rd_client_fsm_execute_q_mode_update() +lwm2m_rd_client_fsm_execute_queue_mode_update() { coap_timer_stop(&rd_timer); - rd_state = Q_MODE_SEND_UPDATE; + rd_state = QUEUE_MODE_SEND_UPDATE; periodic_process(&rd_timer); } /*---------------------------------------------------------------------------*/ -#endif /* LWM2M_Q_MODE_ENABLED */ +#endif /* LWM2M_QUEUE_MODE_ENABLED */ /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/os/services/lwm2m/lwm2m-rd-client.h b/os/services/lwm2m/lwm2m-rd-client.h index 85946235d..cfc5c549d 100644 --- a/os/services/lwm2m/lwm2m-rd-client.h +++ b/os/services/lwm2m/lwm2m-rd-client.h @@ -53,7 +53,7 @@ #define LWM2M_RD_CLIENT_DISCONNECTED 5 #include "lwm2m-object.h" -#include "lwm2m-qmode-conf.h" +#include "lwm2m-queue-mode-conf.h" struct lwm2m_session_info; typedef void (*session_callback_t)(struct lwm2m_session_info *session, int status); @@ -77,11 +77,11 @@ void lwm2m_rd_client_init(const char *ep); void lwm2m_rd_client_set_session_callback(session_callback_t cb); -#if LWM2M_Q_MODE_ENABLED +#if LWM2M_QUEUE_MODE_ENABLED uint8_t lwm2m_rd_client_is_client_awake(void); void lwm2m_rd_client_restart_client_awake_timer(void); -void lwm2m_rd_client_fsm_execute_q_mode_awake(); -void lwm2m_rd_client_fsm_execute_q_mode_update(); +void lwm2m_rd_client_fsm_execute_queue_mode_awake(); +void lwm2m_rd_client_fsm_execute_queue_mode_update(); #endif #ifndef LWM2M_RD_CLIENT_ASSIGNED_ENDPOINT_MAX_LEN diff --git a/tests/18-coap-lwm2m/08-lwm2m-qmode-ipso-test.sh b/tests/18-coap-lwm2m/08-lwm2m-qmode-ipso-test.sh index 142fb253d..2b3d52c3e 100755 --- a/tests/18-coap-lwm2m/08-lwm2m-qmode-ipso-test.sh +++ b/tests/18-coap-lwm2m/08-lwm2m-qmode-ipso-test.sh @@ -10,7 +10,7 @@ IPADDR=fd00::302:304:506:708 # Starting Contiki-NG native node echo "Starting native node - lwm2m/ipso objects with Q-Mode" make -C $CONTIKI/examples/lwm2m-ipso-objects clean >/dev/null -make -C $CONTIKI/examples/lwm2m-ipso-objects DEFINES=LWM2M_Q_MODE_CONF_ENABLED=1,LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION=1 > make.log 2> make.err +make -C $CONTIKI/examples/lwm2m-ipso-objects DEFINES=LWM2M_QUEUE_MODE_CONF_ENABLED=1,LWM2M_QUEUE_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION=1,LWM2M_QUEUE_MODE_OBJECT_CONF_ENABLED=1 > make.log 2> make.err sudo $CONTIKI/examples/lwm2m-ipso-objects/example-ipso-objects.native > node.log 2> node.err & CPID=$! sleep 10 diff --git a/tests/18-coap-lwm2m/09-lwm2m-qmode-standalone-test.sh b/tests/18-coap-lwm2m/09-lwm2m-qmode-standalone-test.sh index f22b20bef..57f0e3f71 100755 --- a/tests/18-coap-lwm2m/09-lwm2m-qmode-standalone-test.sh +++ b/tests/18-coap-lwm2m/09-lwm2m-qmode-standalone-test.sh @@ -8,7 +8,7 @@ BASENAME=09-lwm2m-qmode-standalone-test # Building standalone posix example 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 DEFINES=LWM2M_Q_MODE_CONF_ENABLED=1,LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION=1 >make.log 2>make.err +make CONTIKI_NG=../../$CONTIKI -C example-lwm2m-standalone/lwm2m DEFINES=LWM2M_QUEUE_MODE_CONF_ENABLED=1,LWM2M_QUEUE_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION=1,LWM2M_QUEUE_MODE_OBJECT_CONF_ENABLED=1 >make.log 2>make.err echo "Downloading leshan with Q-Mode support" wget -nc https://carlosgp143.github.io/resources/leshan-server-demo-qmode-support1.0.0-SNAPSHOT-jar-with-dependencies.jar diff --git a/tests/18-coap-lwm2m/pytests/test-qmode-sleep.py b/tests/18-coap-lwm2m/pytests/test-qmode-sleep.py index da9a2ffe8..66dc061ff 100644 --- a/tests/18-coap-lwm2m/pytests/test-qmode-sleep.py +++ b/tests/18-coap-lwm2m/pytests/test-qmode-sleep.py @@ -5,10 +5,10 @@ class TestQueueModeSleep(unittest.TestCase): global client def test_read_awake_time(self): - self.assertIsNone(client.read("6000/0/3000")) + self.assertIsNone(client.read("30000/0/30000")) def test_read_sleep_time(self): - self.assertIsNone(client.read("6000/0/3001")) + self.assertIsNone(client.read("30000/0/30001")) print "----------------------------------------" From eba756e340e4f64fd12e98d428dc06b5e0c8acac Mon Sep 17 00:00:00 2001 From: "carlosgp143@gmail.com" Date: Mon, 21 May 2018 16:13:29 +0200 Subject: [PATCH 112/485] Code of notification queue simplified --- os/services/lwm2m/lwm2m-engine.c | 2 +- os/services/lwm2m/lwm2m-notification-queue.c | 130 ++++--------------- os/services/lwm2m/lwm2m-notification-queue.h | 6 +- 3 files changed, 29 insertions(+), 109 deletions(-) diff --git a/os/services/lwm2m/lwm2m-engine.c b/os/services/lwm2m/lwm2m-engine.c index 36f6fae44..015e1cea9 100644 --- a/os/services/lwm2m/lwm2m-engine.c +++ b/os/services/lwm2m/lwm2m-engine.c @@ -1718,7 +1718,7 @@ lwm2m_notify_object_observers(lwm2m_object_instance_t *obj, if(coap_has_observers(path)) { /* Client is sleeping -> add the notification to the list */ if(!lwm2m_rd_client_is_client_awake()) { - lwm2m_notification_queue_add_notification_path(path); + lwm2m_notification_queue_add_notification_path(obj->object_id, obj->instance_id, resource); /* if it is the first notification -> wake up and send update */ if(!waked_up_by_notification) { diff --git a/os/services/lwm2m/lwm2m-notification-queue.c b/os/services/lwm2m/lwm2m-notification-queue.c index e7c57a03c..4bbb860c1 100644 --- a/os/services/lwm2m/lwm2m-notification-queue.c +++ b/os/services/lwm2m/lwm2m-notification-queue.c @@ -35,7 +35,8 @@ /** * \file - * Implementation of functions to manage the queue of notifications + * Implementation of functions to manage the queue to store notifications + when waiting for the response to the update message in Queue Mode. * \author * Carlos Gonzalo Peces */ @@ -62,12 +63,12 @@ #ifdef LWM2M_NOTIFICATION_QUEUE_CONF_LENGTH #define LWM2M_NOTIFICATION_QUEUE_LENGTH LWM2M_NOTIFICATION_QUEUE_CONF_LENGTH #else -#define LWM2M_NOTIFICATION_QUEUE_LENGTH 3 +#define LWM2M_NOTIFICATION_QUEUE_LENGTH COAP_MAX_OBSERVERS #endif /*---------------------------------------------------------------------------*/ /* Queue to store the notifications in the period when the client has woken up, sent the update and it's waiting for the server response*/ -MEMB(notification_memb, notification_path_t, LWM2M_NOTIFICATION_QUEUE_LENGTH + 1); /* Length + 1 to allocate the new path to add */ +MEMB(notification_memb, notification_path_t, LWM2M_NOTIFICATION_QUEUE_LENGTH); /* Length + 1 to allocate the new path to add */ LIST(notification_paths_queue); /*---------------------------------------------------------------------------*/ void @@ -77,22 +78,6 @@ lwm2m_notification_queue_init(void) } /*---------------------------------------------------------------------------*/ static void -reduce_path(notification_path_t *path_object, char *path) -{ - char *cut = strtok(path, "/"); - int i; - for(i = 0; i < 3; i++) { - if(cut != NULL) { - path_object->reduced_path[i] = (uint16_t)atoi(cut); - cut = strtok(NULL, "/"); - } else { - break; - } - } - path_object->level = i; -} -/*---------------------------------------------------------------------------*/ -static void extend_path(notification_path_t *path_object, char *path, int path_size) { switch(path_object->level) { @@ -108,34 +93,18 @@ extend_path(notification_path_t *path_object, char *path, int path_size) } } /*---------------------------------------------------------------------------*/ -static void -add_notification_path_object_ordered(notification_path_t *path) +static int +is_notification_path_present(uint16_t object_id, uint16_t instance_id, uint16_t resource_id) { notification_path_t *iteration_path = (notification_path_t *)list_head(notification_paths_queue); - if(list_length(notification_paths_queue) == 0) { - list_add(notification_paths_queue, path); - } else if(path->level < iteration_path->level) { - list_push(notification_paths_queue, path); - } else if(memcmp((path->reduced_path), (iteration_path->reduced_path), (path->level) * sizeof(uint16_t)) <= 0) { - list_push(notification_paths_queue, path); - } else { - notification_path_t *previous_path = iteration_path; - while(iteration_path != NULL) { - if(path->level < iteration_path->level) { - path->next = iteration_path; - previous_path->next = path; - return; - } - if(memcmp((path->reduced_path), (iteration_path->reduced_path), (path->level) * sizeof(uint16_t)) <= 0) { - path->next = iteration_path; - previous_path->next = path; - return; - } - previous_path = iteration_path; - iteration_path = iteration_path->next; + while(iteration_path != NULL) { + if(iteration_path->reduced_path[0] == object_id && iteration_path->reduced_path[1] == instance_id + && iteration_path->reduced_path[2] == resource_id) { + return 1; } - list_add(notification_paths_queue, path); + iteration_path = iteration_path->next; } + return 0; } /*---------------------------------------------------------------------------*/ static void @@ -145,73 +114,24 @@ remove_notification_path(notification_path_t *path) memb_free(¬ification_memb, path); } /*---------------------------------------------------------------------------*/ -static void -notification_queue_remove_policy(uint16_t *reduced_path, uint8_t level) -{ - uint8_t path_removed_flag = 0; - - notification_path_t *path_object = NULL; - notification_path_t *iteration_path = NULL; - notification_path_t *previous = NULL; - notification_path_t *next_next = NULL; - notification_path_t *path_to_remove = NULL; - - for(iteration_path = (notification_path_t *)list_head(notification_paths_queue); iteration_path != NULL; - iteration_path = iteration_path->next) { - /* 1. check if there is one event of the same path -> remove it and add the new one */ - if((level == iteration_path->level) && memcmp(iteration_path->reduced_path, reduced_path, level * sizeof(uint16_t)) == 0) { - remove_notification_path(iteration_path); - path_object = memb_alloc(¬ification_memb); - memcpy(path_object->reduced_path, reduced_path, level * sizeof(uint16_t)); - path_object->level = level; - add_notification_path_object_ordered(path_object); - return; - } - /* 2. If there is no event of the same type, look for repeated events of the same resource and remove the oldest one */ - if(iteration_path->next != NULL && (iteration_path->level == iteration_path->next->level) - && (memcmp(iteration_path->reduced_path, (iteration_path->next)->reduced_path, iteration_path->level * sizeof(uint16_t)) == 0)) { - path_removed_flag = 1; - next_next = iteration_path->next->next; - path_to_remove = iteration_path->next; - previous = iteration_path; - } - } - /* 3. If there are no events for the same path, we remove a the oldest repeated event of another resource */ - if(path_removed_flag) { - memb_free(¬ification_memb, path_to_remove); - previous->next = next_next; - path_object = memb_alloc(¬ification_memb); - memcpy(path_object->reduced_path, reduced_path, level * sizeof(uint16_t)); - path_object->level = level; - add_notification_path_object_ordered(path_object); - } else { - /* 4. If all the events are from different resources, remove the last one */ - list_chop(notification_paths_queue); - path_object = memb_alloc(¬ification_memb); - memcpy(path_object->reduced_path, reduced_path, level * sizeof(uint16_t)); - path_object->level = level; - add_notification_path_object_ordered(path_object); - } - return; -} -/*---------------------------------------------------------------------------*/ -/* For adding objects to the list in an ordered way, depending on the path*/ void -lwm2m_notification_queue_add_notification_path(char *path) +lwm2m_notification_queue_add_notification_path(uint16_t object_id, uint16_t instance_id, uint16_t resource_id) { - notification_path_t *path_object = memb_alloc(¬ification_memb); - if(path_object == NULL) { - LOG_DBG("Could not allocate new notification in the queue\n"); + if(is_notification_path_present(object_id, instance_id, resource_id)) { + LOG_DBG("Notification path already present, not queueing it\n"); return; } - reduce_path(path_object, path); - if(list_length(notification_paths_queue) >= LWM2M_NOTIFICATION_QUEUE_LENGTH) { - /* The queue is full, apply policy to remove */ - notification_queue_remove_policy(path_object->reduced_path, path_object->level); - } else { - add_notification_path_object_ordered(path_object); + notification_path_t *path_object = memb_alloc(¬ification_memb); + if(path_object == NULL) { + LOG_DBG("Queue is full, could not allocate new notification\n"); + return; } - LOG_DBG("Notification path added to the list: %s\n", path); + path_object->reduced_path[0] = object_id; + path_object->reduced_path[1] = instance_id; + path_object->reduced_path[2] = resource_id; + path_object->level = 3; + list_add(notification_paths_queue, path_object); + LOG_DBG("Notification path added to the list: %u/%u/%u\n", object_id, instance_id, resource_id); } /*---------------------------------------------------------------------------*/ void diff --git a/os/services/lwm2m/lwm2m-notification-queue.h b/os/services/lwm2m/lwm2m-notification-queue.h index 805002cc2..e3f4719ac 100644 --- a/os/services/lwm2m/lwm2m-notification-queue.h +++ b/os/services/lwm2m/lwm2m-notification-queue.h @@ -35,7 +35,8 @@ /** * \file - * Header file for functions to manage the queue of notifications + * Header file for functions to manage the queue to store notifications + when waiting for the response to the update message in Queue Mode. * \author * Carlos Gonzalo Peces */ @@ -56,8 +57,7 @@ typedef struct notification_path { void lwm2m_notification_queue_init(void); -/* For adding objects to the list in an ordered way, depending on the path*/ -void lwm2m_notification_queue_add_notification_path(char *path); +void lwm2m_notification_queue_add_notification_path(uint16_t object_id, uint16_t instance_id, uint16_t resource_id); void lwm2m_notification_queue_send_notifications(); From ec8fe6eb22a5e48a4358a2d30c5dc8b765689ca6 Mon Sep 17 00:00:00 2001 From: "carlosgp143@gmail.com" Date: Tue, 22 May 2018 15:34:30 +0200 Subject: [PATCH 113/485] Code moved frome lwm2m-engine to lwm2m-queue-mode to have a clearer separation --- examples/lwm2m-ipso-objects/project-conf.h | 11 +- os/services/lwm2m/lwm2m-engine.c | 101 +------------------ os/services/lwm2m/lwm2m-engine.h | 9 -- os/services/lwm2m/lwm2m-notification-queue.c | 2 +- os/services/lwm2m/lwm2m-queue-mode.c | 101 ++++++++++++++++++- os/services/lwm2m/lwm2m-queue-mode.h | 12 ++- os/services/lwm2m/lwm2m-rd-client.c | 8 +- 7 files changed, 125 insertions(+), 119 deletions(-) diff --git a/examples/lwm2m-ipso-objects/project-conf.h b/examples/lwm2m-ipso-objects/project-conf.h index 53d149617..01f919866 100644 --- a/examples/lwm2m-ipso-objects/project-conf.h +++ b/examples/lwm2m-ipso-objects/project-conf.h @@ -60,10 +60,11 @@ #define COAP_OBSERVE_CLIENT 1 /* Definitions to enable Queue Mode, include the dynamic adaptation and change the default parameters */ -/* #define LWM2M_Q_MODE_CONF_ENABLED 1 - #define LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION 1 - #define LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_AWAKE_TIME 2000 - #define LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_SLEEP_TIME 10000 - #define LWM2M_Q_MODE_CONF_DEFAULT_DYNAMIC_ADAPTATION_FLAG 0 */ +/* #define LWM2M_QUEUE_MODE_CONF_ENABLED 1 + #define LWM2M_QUEUE_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION 1 + #define LWM2M_QUEUE_MODE_CONF_DEFAULT_CLIENT_AWAKE_TIME 2000 + #define LWM2M_QUEUE_MODE_CONF_DEFAULT_CLIENT_SLEEP_TIME 10000 + #define LWM2M_QUEUE_MODE_CONF_DEFAULT_DYNAMIC_ADAPTATION_FLAG 1 + #define LWM2M_QUEUE_MODE_OBJECT_CONF_ENABLED 0 */ #endif /* PROJECT_CONF_H_ */ diff --git a/os/services/lwm2m/lwm2m-engine.c b/os/services/lwm2m/lwm2m-engine.c index 015e1cea9..0c4d9f5fd 100644 --- a/os/services/lwm2m/lwm2m-engine.c +++ b/os/services/lwm2m/lwm2m-engine.c @@ -84,9 +84,6 @@ #if LWM2M_QUEUE_MODE_ENABLED /* Queue Mode is handled using the RD Client and the Q-Mode object */ #define USE_RD_CLIENT 1 -/* Queue Mode dynamic adaptation masks */ -#define FIRST_REQUEST_MASK 0x01 -#define HANDLER_FROM_NOTIFICATION_MASK 0x02 #endif #if USE_RD_CLIENT @@ -146,19 +143,6 @@ static struct { /* in the future also a timeout */ } created; -#if LWM2M_QUEUE_MODE_ENABLED -static uint8_t waked_up_by_notification; -/* For the dynamic adaptation of the awake time */ -#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION -static uint8_t dynamic_adaptation_params = 0x00; /* bit0: first_request, bit1: handler from notification */ -static uint64_t previous_request_time; -static inline void clear_first_request(); -static inline uint8_t is_first_request(); -static inline void clear_handler_from_notification(); -static inline uint8_t get_handler_from_notification(); -#endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ -#endif /* LWM2M_QUEUE_MODE_ENABLED */ - COAP_HANDLER(lwm2m_handler, lwm2m_handler_callback); LIST(object_list); LIST(generic_object_list); @@ -1406,32 +1390,8 @@ lwm2m_handler_callback(coap_message_t *request, coap_message_t *response, context.inbuf->size = coap_get_payload(request, (const uint8_t **)&context.inbuf->buffer); context.inbuf->pos = 0; - /*If Queue Mode, restart the client awake timer */ #if LWM2M_QUEUE_MODE_ENABLED - if(lwm2m_rd_client_is_client_awake()) { - lwm2m_rd_client_restart_client_awake_timer(); - } - -#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION - if(lwm2m_queue_mode_get_dynamic_adaptation_flag() && !get_handler_from_notification()) { - if(is_first_request()) { - previous_request_time = coap_timer_uptime(); - clear_first_request(); - } else { - if(coap_timer_uptime()-previous_request_time >= 0) { - if(coap_timer_uptime()-previous_request_time > 0xffff) { - lwm2m_queue_mode_add_time_to_window(0xffff); - } else { - lwm2m_queue_mode_add_time_to_window(coap_timer_uptime()-previous_request_time); - } - } - previous_request_time = coap_timer_uptime(); - } - } - if(get_handler_from_notification()) { - clear_handler_from_notification(); - } -#endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ +lwm2m_queue_mode_request_received(); #endif /* LWM2M_QUEUE_MODE_ENABLED */ /* Maybe this should be part of CoAP itself - this seems not to be working @@ -1698,7 +1658,7 @@ lwm2m_send_notification(char* path) { #if LWM2M_QUEUE_MODE_ENABLED && LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION if(lwm2m_queue_mode_get_dynamic_adaptation_flag()) { - lwm2m_engine_set_handler_from_notification(); + lwm2m_queue_mode_set_handler_from_notification(); } #endif coap_notify_observers_sub(NULL, path); @@ -1721,8 +1681,8 @@ lwm2m_notify_object_observers(lwm2m_object_instance_t *obj, lwm2m_notification_queue_add_notification_path(obj->object_id, obj->instance_id, resource); /* if it is the first notification -> wake up and send update */ - if(!waked_up_by_notification) { - waked_up_by_notification = 1; + if(!lwm2m_queue_mode_is_waked_up_by_notification()) { + lwm2m_queue_mode_set_waked_up_by_notification(); lwm2m_rd_client_fsm_execute_queue_mode_update(); } /* Client is awake -> send the notification */ @@ -1735,57 +1695,4 @@ lwm2m_notify_object_observers(lwm2m_object_instance_t *obj, #endif } /*---------------------------------------------------------------------------*/ -/* Queue Mode Support and dynamic adaptation of the client awake time */ -#if LWM2M_QUEUE_MODE_ENABLED -uint8_t -lwm2m_engine_is_waked_up_by_notification() -{ - return waked_up_by_notification; -} -/*---------------------------------------------------------------------------*/ -void -lwm2m_engine_clear_waked_up_by_notification() -{ - waked_up_by_notification = 0; -} -/*---------------------------------------------------------------------------*/ -#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION -void -lwm2m_engine_set_first_request() -{ - dynamic_adaptation_params |= FIRST_REQUEST_MASK; -} -/*---------------------------------------------------------------------------*/ -void -lwm2m_engine_set_handler_from_notification() -{ - dynamic_adaptation_params |= HANDLER_FROM_NOTIFICATION_MASK; -} -/*---------------------------------------------------------------------------*/ -static inline uint8_t -is_first_request() -{ - return dynamic_adaptation_params & FIRST_REQUEST_MASK; -} -/*---------------------------------------------------------------------------*/ -static inline uint8_t -get_handler_from_notification() -{ - return (dynamic_adaptation_params & HANDLER_FROM_NOTIFICATION_MASK) != 0; -} -/*---------------------------------------------------------------------------*/ -static inline void -clear_first_request() -{ - dynamic_adaptation_params &= ~FIRST_REQUEST_MASK; -} -/*---------------------------------------------------------------------------*/ -static inline void -clear_handler_from_notification() -{ - dynamic_adaptation_params &= ~HANDLER_FROM_NOTIFICATION_MASK; -} -#endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ -#endif /* LWM2M_QUEUE_MODE_ENABLED */ -/*---------------------------------------------------------------------------*/ /** @} */ diff --git a/os/services/lwm2m/lwm2m-engine.h b/os/services/lwm2m/lwm2m-engine.h index 0f6d35734..0ca24fb90 100644 --- a/os/services/lwm2m/lwm2m-engine.h +++ b/os/services/lwm2m/lwm2m-engine.h @@ -116,14 +116,5 @@ void lwm2m_notify_object_observers(lwm2m_object_instance_t *obj, void lwm2m_engine_set_opaque_callback(lwm2m_context_t *ctx, lwm2m_write_opaque_callback cb); -#if LWM2M_QUEUE_MODE_ENABLED -uint8_t lwm2m_engine_is_waked_up_by_notification(); -void lwm2m_engine_clear_waked_up_by_notification(); -#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION -void lwm2m_engine_set_first_request(); -void lwm2m_engine_set_handler_from_notification(); -#endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ -#endif /* LWM2M_QUEUE_MODE_ENABLED */ - #endif /* LWM2M_ENGINE_H */ /** @} */ diff --git a/os/services/lwm2m/lwm2m-notification-queue.c b/os/services/lwm2m/lwm2m-notification-queue.c index 4bbb860c1..c901bef82 100644 --- a/os/services/lwm2m/lwm2m-notification-queue.c +++ b/os/services/lwm2m/lwm2m-notification-queue.c @@ -145,7 +145,7 @@ lwm2m_notification_queue_send_notifications() extend_path(iteration_path, path, sizeof(path)); #if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION if(lwm2m_queue_mode_get_dynamic_adaptation_flag()) { - lwm2m_engine_set_handler_from_notification(); + lwm2m_queue_mode_set_handler_from_notification(); } #endif LOG_DBG("Sending stored notification with path: %s\n", path); diff --git a/os/services/lwm2m/lwm2m-queue-mode.c b/os/services/lwm2m/lwm2m-queue-mode.c index 30c8dd6cc..aad80ce3e 100644 --- a/os/services/lwm2m/lwm2m-queue-mode.c +++ b/os/services/lwm2m/lwm2m-queue-mode.c @@ -55,17 +55,30 @@ #define LOG_MODULE "lwm2m-queue-mode" #define LOG_LEVEL LOG_LEVEL_LWM2M +/* Queue Mode dynamic adaptation masks */ +#define FIRST_REQUEST_MASK 0x01 +#define HANDLER_FROM_NOTIFICATION_MASK 0x02 static uint16_t queue_mode_awake_time = LWM2M_QUEUE_MODE_DEFAULT_CLIENT_AWAKE_TIME; static uint32_t queue_mode_sleep_time = LWM2M_QUEUE_MODE_DEFAULT_CLIENT_SLEEP_TIME; + +/* Flag for notifications */ +static uint8_t waked_up_by_notification; + +/* For the dynamic adaptation of the awake time */ #if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION static uint8_t queue_mode_dynamic_adaptation_flag = LWM2M_QUEUE_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG; /* Window to save the times and do the dynamic adaptation of the awake time*/ uint16_t times_window[LWM2M_QUEUE_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH] = { 0 }; uint8_t times_window_index = 0; - -#endif +static uint8_t dynamic_adaptation_params = 0x00; /* bit0: first_request, bit1: handler from notification */ +static uint64_t previous_request_time; +static inline void clear_first_request(); +static inline uint8_t is_first_request(); +static inline void clear_handler_from_notification(); +static inline uint8_t get_handler_from_notification(); +#endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ /*---------------------------------------------------------------------------*/ uint16_t lwm2m_queue_mode_get_awake_time() @@ -106,6 +119,7 @@ lwm2m_queue_mode_set_dynamic_adaptation_flag(uint8_t flag) { queue_mode_dynamic_adaptation_flag = flag; } +#endif /*---------------------------------------------------------------------------*/ #if !UPDATE_WITH_MEAN static uint16_t @@ -167,6 +181,89 @@ lwm2m_queue_mode_add_time_to_window(uint16_t time) times_window_index++; update_awake_time(); } +/*---------------------------------------------------------------------------*/ +uint8_t +lwm2m_queue_mode_is_waked_up_by_notification() +{ + return waked_up_by_notification; +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_queue_mode_clear_waked_up_by_notification() +{ + waked_up_by_notification = 0; +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_queue_mode_set_waked_up_by_notification() +{ + waked_up_by_notification = 1; +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_queue_mode_request_received() +{ + if(lwm2m_rd_client_is_client_awake()) { + lwm2m_rd_client_restart_client_awake_timer(); + } +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION + if(lwm2m_queue_mode_get_dynamic_adaptation_flag() && !get_handler_from_notification()) { + if(is_first_request()) { + previous_request_time = coap_timer_uptime(); + clear_first_request(); + } else { + if(coap_timer_uptime() - previous_request_time >= 0) { + if(coap_timer_uptime() - previous_request_time > 0xffff) { + lwm2m_queue_mode_add_time_to_window(0xffff); + } else { + lwm2m_queue_mode_add_time_to_window(coap_timer_uptime() - previous_request_time); + } + } + previous_request_time = coap_timer_uptime(); + } + } + if(get_handler_from_notification()) { + clear_handler_from_notification(); + } +#endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ +} +/*---------------------------------------------------------------------------*/ +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION +void +lwm2m_queue_mode_set_first_request() +{ + dynamic_adaptation_params |= FIRST_REQUEST_MASK; +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_queue_mode_set_handler_from_notification() +{ + dynamic_adaptation_params |= HANDLER_FROM_NOTIFICATION_MASK; +} +/*---------------------------------------------------------------------------*/ +static inline uint8_t +is_first_request() +{ + return dynamic_adaptation_params & FIRST_REQUEST_MASK; +} +/*---------------------------------------------------------------------------*/ +static inline uint8_t +get_handler_from_notification() +{ + return (dynamic_adaptation_params & HANDLER_FROM_NOTIFICATION_MASK) != 0; +} +/*---------------------------------------------------------------------------*/ +static inline void +clear_first_request() +{ + dynamic_adaptation_params &= ~FIRST_REQUEST_MASK; +} +/*---------------------------------------------------------------------------*/ +static inline void +clear_handler_from_notification() +{ + dynamic_adaptation_params &= ~HANDLER_FROM_NOTIFICATION_MASK; +} #endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ #endif /* LWM2M_QUEUE_MODE_ENABLED */ /** @} */ diff --git a/os/services/lwm2m/lwm2m-queue-mode.h b/os/services/lwm2m/lwm2m-queue-mode.h index cc3bd3290..5c65face5 100644 --- a/os/services/lwm2m/lwm2m-queue-mode.h +++ b/os/services/lwm2m/lwm2m-queue-mode.h @@ -36,7 +36,7 @@ /** * \file * Header file for the Contiki OMA LWM2M Queue Mode implementation - to manage the parameters + to manage the parameters * \author * Carlos Gonzalo Peces */ @@ -51,11 +51,21 @@ uint16_t lwm2m_queue_mode_get_awake_time(); void lwm2m_queue_mode_set_awake_time(uint16_t time); uint32_t lwm2m_queue_mode_get_sleep_time(); void lwm2m_queue_mode_set_sleep_time(uint32_t time); + #if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION uint8_t lwm2m_queue_mode_get_dynamic_adaptation_flag(); void lwm2m_queue_mode_set_dynamic_adaptation_flag(uint8_t flag); void lwm2m_queue_mode_add_time_to_window(uint16_t time); #endif +uint8_t lwm2m_queue_mode_is_waked_up_by_notification(); +void lwm2m_queue_mode_clear_waked_up_by_notification(); +void lwm2m_queue_mode_set_waked_up_by_notification(); + +void lwm2m_queue_mode_set_first_request(); +void lwm2m_queue_mode_set_handler_from_notification(); + +void lwm2m_queue_mode_request_received(); + #endif /* LWM2M_QUEUE_MODE_H_ */ /** @} */ diff --git a/os/services/lwm2m/lwm2m-rd-client.c b/os/services/lwm2m/lwm2m-rd-client.c index da8d276d0..63c9443e1 100644 --- a/os/services/lwm2m/lwm2m-rd-client.c +++ b/os/services/lwm2m/lwm2m-rd-client.c @@ -448,7 +448,7 @@ registration_callback(coap_request_state_t *state) #if LWM2M_QUEUE_MODE_ENABLED #if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION if(lwm2m_queue_mode_get_dynamic_adaptation_flag()) { - lwm2m_engine_set_first_request(); + lwm2m_queue_mode_set_first_request(); } #endif lwm2m_rd_client_fsm_execute_queue_mode_awake(); /* Avoid 500 ms delay and move directly to the state*/ @@ -501,14 +501,14 @@ update_callback(coap_request_state_t *state) last_update = coap_timer_uptime(); #if LWM2M_QUEUE_MODE_ENABLED /* If it has been waked up by a notification, send the stored notifications in queue */ - if(lwm2m_engine_is_waked_up_by_notification()) { + if(lwm2m_queue_mode_is_waked_up_by_notification()) { - lwm2m_engine_clear_waked_up_by_notification(); + lwm2m_queue_mode_clear_waked_up_by_notification(); lwm2m_notification_queue_send_notifications(); } #if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION if(lwm2m_queue_mode_get_dynamic_adaptation_flag()) { - lwm2m_engine_set_first_request(); + lwm2m_queue_mode_set_first_request(); } #endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ lwm2m_rd_client_fsm_execute_queue_mode_awake(); /* Avoid 500 ms delay and move directly to the state*/ From f7ab2750a0184e9f9600005f43f4f882cb8df6ce Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Thu, 17 May 2018 02:56:34 -0700 Subject: [PATCH 114/485] Added simple-energest --- os/contiki-main.c | 5 + os/services/simple-energest/module-macros.h | 2 + os/services/simple-energest/simple-energest.c | 132 ++++++++++++++++++ os/services/simple-energest/simple-energest.h | 60 ++++++++ 4 files changed, 199 insertions(+) create mode 100644 os/services/simple-energest/module-macros.h create mode 100644 os/services/simple-energest/simple-energest.c create mode 100644 os/services/simple-energest/simple-energest.h diff --git a/os/contiki-main.c b/os/contiki-main.c index b9aea5cd6..a6c063d1d 100644 --- a/os/contiki-main.c +++ b/os/contiki-main.c @@ -51,6 +51,7 @@ #include "services/rpl-border-router/rpl-border-router.h" #include "services/orchestra/orchestra.h" #include "services/shell/serial-shell.h" +#include "services/simple-energest/simple-energest.h" #include #include @@ -138,6 +139,10 @@ main(void) LOG_DBG("With CoAP\n"); #endif /* BUILD_WITH_SHELL */ +#if BUILD_WITH_SIMPLE_ENERGEST + simple_energest_init(); +#endif /* BUILD_WITH_SIMPLE_ENERGEST */ + autostart_start(autostart_processes); watchdog_start(); diff --git a/os/services/simple-energest/module-macros.h b/os/services/simple-energest/module-macros.h new file mode 100644 index 000000000..f5ae1e890 --- /dev/null +++ b/os/services/simple-energest/module-macros.h @@ -0,0 +1,2 @@ +#define BUILD_WITH_SIMPLE_ENERGEST 1 +#define ENERGEST_CONF_ON 1 diff --git a/os/services/simple-energest/simple-energest.c b/os/services/simple-energest/simple-energest.c new file mode 100644 index 000000000..fc7393bc6 --- /dev/null +++ b/os/services/simple-energest/simple-energest.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2018, RISE SICS. + * 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. + * + */ + +/** +* \addtogroup simple-energest +* @{ +*/ + +/** + * \file + * A process that periodically prints out the time spent in + * radio tx, radio rx, total time and duty cycle. + * + * \author Simon Duquennoy + */ + +#include "contiki.h" +#include "sys/energest.h" +#include "simple-energest.h" +#include +#include + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Energest" +#define LOG_LEVEL LOG_LEVEL_INFO + +static unsigned long last_tx, last_rx, last_time, last_cpu, last_lpm, last_deep_lpm; +static unsigned long delta_tx, delta_rx, delta_time, delta_cpu, delta_lpm, delta_deep_lpm; +static unsigned long curr_tx, curr_rx, curr_time, curr_cpu, curr_lpm, curr_deep_lpm; + +PROCESS(simple_energest_process, "Simple Energest"); +/*---------------------------------------------------------------------------*/ +static unsigned long +to_permil(unsigned long delta_metric, unsigned long delta_time) +{ + return (1000ul * (delta_metric)) / delta_time; +} +/*---------------------------------------------------------------------------*/ +static void +simple_energest_step(void) +{ + static unsigned count = 0; + + energest_flush(); + + curr_time = ENERGEST_GET_TOTAL_TIME(); + curr_cpu = energest_type_time(ENERGEST_TYPE_CPU); + curr_lpm = energest_type_time(ENERGEST_TYPE_LPM); + curr_deep_lpm = energest_type_time(ENERGEST_TYPE_DEEP_LPM); + curr_tx = energest_type_time(ENERGEST_TYPE_TRANSMIT); + curr_rx = energest_type_time(ENERGEST_TYPE_LISTEN); + + delta_time = curr_time - last_time; + delta_cpu = curr_cpu - last_cpu; + delta_lpm = curr_lpm - last_lpm; + delta_deep_lpm = curr_deep_lpm - last_deep_lpm; + delta_tx = curr_tx - last_tx; + delta_rx = curr_rx - last_rx; + + last_time = curr_time; + last_cpu = curr_cpu; + last_lpm = curr_lpm; + last_deep_lpm = curr_deep_lpm; + last_tx = curr_tx; + last_rx = curr_rx; + + LOG_INFO("--- Period summary #%u (%lu seconds)\n", count++, delta_time/ENERGEST_SECOND); + LOG_INFO("Total time : %10lu\n", delta_time); + LOG_INFO("CPU : %10lu/%10lu (%lu permil)\n", delta_cpu, delta_time, to_permil(delta_cpu, delta_time)); + LOG_INFO("LPM : %10lu/%10lu (%lu permil)\n", delta_lpm, delta_time, to_permil(delta_lpm, delta_time)); + LOG_INFO("Deep LPM : %10lu/%10lu (%lu permil)\n", delta_deep_lpm, delta_time, to_permil(delta_deep_lpm, delta_time)); + LOG_INFO("Radio Tx : %10lu/%10lu (%lu permil)\n", delta_tx, delta_time, to_permil(delta_tx, delta_time)); + LOG_INFO("Radio Rx : %10lu/%10lu (%lu permil)\n", delta_rx, delta_time, to_permil(delta_rx, delta_time)); + LOG_INFO("Radio total : %10lu/%10lu (%lu permil)\n", delta_tx+delta_rx, delta_time, to_permil(delta_tx+delta_rx, delta_time)); +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(simple_energest_process, ev, data) +{ + static struct etimer periodic_timer; + PROCESS_BEGIN(); + + etimer_set(&periodic_timer, SIMPLE_ENERGEST_PERIOD); + while(1) { + PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&periodic_timer)); + etimer_reset(&periodic_timer); + simple_energest_step(); + } + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +void +simple_energest_init(void) +{ + energest_flush(); + last_time = ENERGEST_GET_TOTAL_TIME(); + last_cpu = energest_type_time(ENERGEST_TYPE_CPU); + last_lpm = energest_type_time(ENERGEST_TYPE_LPM); + curr_tx = energest_type_time(ENERGEST_TYPE_TRANSMIT); + last_deep_lpm = energest_type_time(ENERGEST_TYPE_DEEP_LPM); + last_rx = energest_type_time(ENERGEST_TYPE_LISTEN); + process_start(&simple_energest_process, NULL); +} + +/** @} */ diff --git a/os/services/simple-energest/simple-energest.h b/os/services/simple-energest/simple-energest.h new file mode 100644 index 000000000..4f7281e9c --- /dev/null +++ b/os/services/simple-energest/simple-energest.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2018, RISE SICS. + * 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. + * + */ + + /** + * \addtogroup simple-energest + * @{ + */ + + /** + * \file + * A process that periodically prints out the time spent in + * radio tx, radio rx, total time and duty cycle. + * + * \author Simon Duquennoy + */ + +#ifndef SIMPLE_ENERGEST_H_ +#define SIMPLE_ENERGEST_H_ + +/** \brief The period at which Energest statistics will be logged */ +#ifdef SIMPLE_ENERGEST_CONF_PERIOD +#define SIMPLE_ENERGEST_PERIOD SIMPLE_ENERGEST_CONF_PERIOD +#else /* SIMPLE_ENERGEST_CONF_PERIOD */ +#define SIMPLE_ENERGEST_PERIOD (CLOCK_SECOND * 60) +#endif /* SIMPLE_ENERGEST_CONF_PERIOD */ + +/** + * Initialize the deployment module + */ +void simple_energest_init(void); + +#endif /* SIMPLE_ENERGEST_H_ */ +/** @} */ From e0e58f6eec5d14b5076af8a6a4dd30455d844375 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 23 May 2018 12:46:32 -0700 Subject: [PATCH 115/485] Added example for simple-energest --- examples/libs/simple-energest/Makefile | 6 +++ examples/libs/simple-energest/README.md | 1 + examples/libs/simple-energest/example.c | 56 +++++++++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 examples/libs/simple-energest/Makefile create mode 100644 examples/libs/simple-energest/README.md create mode 100644 examples/libs/simple-energest/example.c diff --git a/examples/libs/simple-energest/Makefile b/examples/libs/simple-energest/Makefile new file mode 100644 index 000000000..056aa5c43 --- /dev/null +++ b/examples/libs/simple-energest/Makefile @@ -0,0 +1,6 @@ +CONTIKI_PROJECT = example +all: $(CONTIKI_PROJECT) + +MODULES += os/services/simple-energest +CONTIKI = ../../.. +include $(CONTIKI)/Makefile.include diff --git a/examples/libs/simple-energest/README.md b/examples/libs/simple-energest/README.md new file mode 100644 index 000000000..42e382b5f --- /dev/null +++ b/examples/libs/simple-energest/README.md @@ -0,0 +1 @@ +This is a minimal example for the module simple-energest. diff --git a/examples/libs/simple-energest/example.c b/examples/libs/simple-energest/example.c new file mode 100644 index 000000000..e9d6d585c --- /dev/null +++ b/examples/libs/simple-energest/example.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2018, 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 very simple example of simple-energest + * \author + * Simon Duquennoy + */ + +#include "contiki.h" + +#include /* For printf() */ +/*---------------------------------------------------------------------------*/ +PROCESS(example_process, "Example process: simple-energest"); +AUTOSTART_PROCESSES(&example_process); +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(example_process, ev, data) +{ + PROCESS_BEGIN(); + + /* Do nothing, just let simple-energest write its summary + * at a period of SIMPLE_ENERGEST_CONF_PERIOD */ + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ From 77939f421cf6beba20ee27ae858048a3ac73d344 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 23 May 2018 12:49:25 -0700 Subject: [PATCH 116/485] Added example for the shell --- examples/libs/shell/Makefile | 6 ++++ examples/libs/shell/README.md | 1 + examples/libs/shell/example.c | 56 +++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 examples/libs/shell/Makefile create mode 100644 examples/libs/shell/README.md create mode 100644 examples/libs/shell/example.c diff --git a/examples/libs/shell/Makefile b/examples/libs/shell/Makefile new file mode 100644 index 000000000..b44069cf8 --- /dev/null +++ b/examples/libs/shell/Makefile @@ -0,0 +1,6 @@ +CONTIKI_PROJECT = example +all: $(CONTIKI_PROJECT) + +MODULES += os/services/shell +CONTIKI = ../../.. +include $(CONTIKI)/Makefile.include diff --git a/examples/libs/shell/README.md b/examples/libs/shell/README.md new file mode 100644 index 000000000..a76aa8c05 --- /dev/null +++ b/examples/libs/shell/README.md @@ -0,0 +1 @@ +This is a minimal example for the shell. diff --git a/examples/libs/shell/example.c b/examples/libs/shell/example.c new file mode 100644 index 000000000..9d2320c58 --- /dev/null +++ b/examples/libs/shell/example.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2018, 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 very simple example using the shell + * \author + * Simon Duquennoy + */ + +#include "contiki.h" + +#include /* For printf() */ +/*---------------------------------------------------------------------------*/ +PROCESS(example_process, "Example process: shell"); +AUTOSTART_PROCESSES(&example_process); +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(example_process, ev, data) +{ + PROCESS_BEGIN(); + + /* This process does nothing. Connect to the node with `make login` + * to use the shell. */ + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ From d972dc607e29a9cfe611e95c88e4a328adbf4571 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 23 May 2018 12:50:20 -0700 Subject: [PATCH 117/485] Added compile test for the shell and simple-energest examples --- tests/03-compile-arm-ports-02/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/03-compile-arm-ports-02/Makefile b/tests/03-compile-arm-ports-02/Makefile index defd10a96..f0c7155ae 100644 --- a/tests/03-compile-arm-ports-02/Makefile +++ b/tests/03-compile-arm-ports-02/Makefile @@ -62,6 +62,8 @@ dev/gpio-hal/openmote-cc2538 \ dev/leds/openmote-cc2538 \ rpl-border-router/openmote-cc2538 \ libs/ipv6-hooks/openmote-cc2538 \ +libs/shell/openmote-cc2538 \ +libs/simple-energest/openmote-cc2538 \ TOOLS= From 262cea11f1168afb3fe5320db07e421c106b73fe Mon Sep 17 00:00:00 2001 From: "carlosgp143@gmail.com" Date: Wed, 23 May 2018 15:59:43 +0200 Subject: [PATCH 118/485] Implemented instant feedback in CoAp_send_request --- os/net/app-layer/coap/coap-callback-api.c | 8 +++++--- os/net/app-layer/coap/coap-callback-api.h | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/os/net/app-layer/coap/coap-callback-api.c b/os/net/app-layer/coap/coap-callback-api.c index b1b05597e..0f0ab2c99 100644 --- a/os/net/app-layer/coap/coap-callback-api.c +++ b/os/net/app-layer/coap/coap-callback-api.c @@ -65,7 +65,7 @@ static void coap_request_callback(void *callback_data, coap_message_t *response) /*---------------------------------------------------------------------------*/ -static void +static int progress_request(coap_request_state_t *state) { coap_message_t *request = state->request; request->mid = coap_get_mid(); @@ -83,7 +83,9 @@ progress_request(coap_request_state_t *state) { coap_send_transaction(state->transaction); LOG_DBG("Requested #%"PRIu32" (MID %u)\n", state->block_num, request->mid); + return 1; } + return 0; } /*---------------------------------------------------------------------------*/ @@ -134,7 +136,7 @@ coap_request_callback(void *callback_data, coap_message_t *response) /*---------------------------------------------------------------------------*/ -void +int coap_send_request(coap_request_state_t *state, coap_endpoint_t *endpoint, coap_message_t *request, void (*callback)(coap_request_state_t *state)) @@ -151,7 +153,7 @@ coap_send_request(coap_request_state_t *state, coap_endpoint_t *endpoint, state->remote_endpoint = endpoint; state->callback = callback; - progress_request(state); + return progress_request(state); } /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/os/net/app-layer/coap/coap-callback-api.h b/os/net/app-layer/coap/coap-callback-api.h index 6de7ab587..7f144af96 100644 --- a/os/net/app-layer/coap/coap-callback-api.h +++ b/os/net/app-layer/coap/coap-callback-api.h @@ -65,7 +65,7 @@ struct coap_request_state { void (*callback)(coap_request_state_t *state); }; -void coap_send_request(coap_request_state_t *state, coap_endpoint_t *endpoint, +int coap_send_request(coap_request_state_t *state, coap_endpoint_t *endpoint, coap_message_t *request, void (*callback)(coap_request_state_t *state)); From b50d143966d89895117dd67974833b76f56d3758 Mon Sep 17 00:00:00 2001 From: "carlosgp143@gmail.com" Date: Thu, 24 May 2018 08:53:33 +0200 Subject: [PATCH 119/485] Added doxygen annotation to the prototype --- os/net/app-layer/coap/coap-callback-api.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/os/net/app-layer/coap/coap-callback-api.h b/os/net/app-layer/coap/coap-callback-api.h index 7f144af96..69ceea4f5 100644 --- a/os/net/app-layer/coap/coap-callback-api.h +++ b/os/net/app-layer/coap/coap-callback-api.h @@ -65,6 +65,14 @@ struct coap_request_state { void (*callback)(coap_request_state_t *state); }; +/** + * \brief Send a CoAP request to a remote endpoint + * \param state The state to handle the CoAP request + * \param endpoint The destination endpoint + * \param request The request to be sent + * \param callback callback to execute when the response arrives or the timeout expires + * \return 1 if there is a transaction available to send, 0 otherwise + */ int coap_send_request(coap_request_state_t *state, coap_endpoint_t *endpoint, coap_message_t *request, void (*callback)(coap_request_state_t *state)); From fcb246d4bf283d7d57e8628837bdb0690c5d0c1f Mon Sep 17 00:00:00 2001 From: Joakim Eriksson Date: Fri, 25 May 2018 16:20:47 +0200 Subject: [PATCH 120/485] fixed endpoint name to have Contiki-NG as prefix --- os/services/lwm2m/lwm2m-engine.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/os/services/lwm2m/lwm2m-engine.c b/os/services/lwm2m/lwm2m-engine.c index 6f2aeefd8..7977e8921 100644 --- a/os/services/lwm2m/lwm2m-engine.c +++ b/os/services/lwm2m/lwm2m-engine.c @@ -68,9 +68,9 @@ #ifndef LWM2M_ENGINE_CLIENT_ENDPOINT_PREFIX #ifdef LWM2M_DEVICE_MODEL_NUMBER -#define LWM2M_ENGINE_CLIENT_ENDPOINT_PREFIX LWM2M_DEVICE_MODEL_NUMBER +#define LWM2M_ENGINE_CLIENT_ENDPOINT_PREFIX "Contiki-NG-"LWM2M_DEVICE_MODEL_NUMBER #else /* LWM2M_DEVICE_MODEL_NUMBER */ -#define LWM2M_ENGINE_CLIENT_ENDPOINT_PREFIX "Contiki-" +#define LWM2M_ENGINE_CLIENT_ENDPOINT_PREFIX "Contiki-NG" #endif /* LWM2M_DEVICE_MODEL_NUMBER */ #endif /* LWM2M_ENGINE_CLIENT_ENDPOINT_PREFIX */ From bcb4548519f620c2111a9d1917e6415dec5ffe69 Mon Sep 17 00:00:00 2001 From: Joakim Eriksson Date: Fri, 25 May 2018 16:21:45 +0200 Subject: [PATCH 121/485] ensured initialization of success variable --- os/services/lwm2m/lwm2m-engine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/services/lwm2m/lwm2m-engine.c b/os/services/lwm2m/lwm2m-engine.c index 7977e8921..dd76212a9 100644 --- a/os/services/lwm2m/lwm2m-engine.c +++ b/os/services/lwm2m/lwm2m-engine.c @@ -746,7 +746,7 @@ perform_multi_resource_read_op(lwm2m_object_t *object, } /* ---------- Read operation ------------- */ } else if(ctx->operation == LWM2M_OP_READ) { - lwm2m_status_t success; + lwm2m_status_t success = 0; uint8_t lv; lv = ctx->level; From 1f5d109f336e5f48d5e4db40f79d215278747472 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 25 May 2018 12:29:26 -0700 Subject: [PATCH 122/485] Remove left-over instances of WITH_TINYOS_AUTO_IDS --- arch/platform/jn516x/platform.c | 4 ---- arch/platform/sky/platform.c | 4 ---- 2 files changed, 8 deletions(-) diff --git a/arch/platform/jn516x/platform.c b/arch/platform/jn516x/platform.c index 9d44444e8..bc9d7b955 100644 --- a/arch/platform/jn516x/platform.c +++ b/arch/platform/jn516x/platform.c @@ -158,10 +158,6 @@ xosc_init(void) return bAHI_Set32KhzClockMode(E_AHI_XTAL); } /*---------------------------------------------------------------------------*/ -#if WITH_TINYOS_AUTO_IDS -uint16_t TOS_NODE_ID = 0x1234; /* non-zero */ -uint16_t TOS_LOCAL_ADDRESS = 0x1234; /* non-zero */ -#endif /* WITH_TINYOS_AUTO_IDS */ void platform_init_stage_one(void) { diff --git a/arch/platform/sky/platform.c b/arch/platform/sky/platform.c index 670e5443d..89d18d3e8 100644 --- a/arch/platform/sky/platform.c +++ b/arch/platform/sky/platform.c @@ -111,10 +111,6 @@ set_lladdr(void) linkaddr_set_node_addr(&addr); } /*---------------------------------------------------------------------------*/ -#if WITH_TINYOS_AUTO_IDS -uint16_t TOS_NODE_ID = 0x1234; /* non-zero */ -uint16_t TOS_LOCAL_ADDRESS = 0x1234; /* non-zero */ -#endif /* WITH_TINYOS_AUTO_IDS */ void platform_init_stage_one(void) { From 3d88ba35dd8958e274199857644b406090094bbc Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 25 May 2018 12:33:30 -0700 Subject: [PATCH 123/485] TSCH: keep track of max/min observed drift and log it periodically --- os/net/mac/tsch/tsch-adaptive-timesync.c | 6 +++++- os/net/mac/tsch/tsch.c | 4 ++++ os/net/mac/tsch/tsch.h | 2 ++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/os/net/mac/tsch/tsch-adaptive-timesync.c b/os/net/mac/tsch/tsch-adaptive-timesync.c index a23a4f1b0..6508a8752 100644 --- a/os/net/mac/tsch/tsch-adaptive-timesync.c +++ b/os/net/mac/tsch/tsch-adaptive-timesync.c @@ -109,7 +109,9 @@ timesync_learn_drift_ticks(uint32_t time_delta_asn, int32_t drift_ticks) TSCH_LOG_ADD(tsch_log_message, snprintf(log->message, sizeof(log->message), - "drift %ld", tsch_adaptive_timesync_get_drift_ppm())); + "drift %ld (min/max delta seen: %"PRId32"/%"PRId32")", + tsch_adaptive_timesync_get_drift_ppm(), + min_drift_seen, max_drift_seen)); } /*---------------------------------------------------------------------------*/ /* Either reset or update the neighbor's drift */ @@ -136,6 +138,8 @@ tsch_timesync_update(struct tsch_neighbor *n, uint16_t time_delta_asn, int32_t d compensated_ticks += drift_correction; } } + min_drift_seen = MIN(drift_correction, min_drift_seen); + max_drift_seen = MAX(drift_correction, max_drift_seen); } /*---------------------------------------------------------------------------*/ /* Error-accumulation free compensation algorithm */ diff --git a/os/net/mac/tsch/tsch.c b/os/net/mac/tsch/tsch.c index dea750120..45df20e6f 100644 --- a/os/net/mac/tsch/tsch.c +++ b/os/net/mac/tsch/tsch.c @@ -160,6 +160,8 @@ static struct ctimer keepalive_timer; unsigned long tx_count; unsigned long rx_count; unsigned long sync_count; +int32_t min_drift_seen; +int32_t max_drift_seen; /* TSCH processes and protothreads */ PT_THREAD(tsch_scan(struct pt *pt)); @@ -648,6 +650,8 @@ tsch_associate(const struct input_packet *input_eb, rtimer_clock_t timestamp) tx_count = 0; rx_count = 0; sync_count = 0; + min_drift_seen = 0; + max_drift_seen = 0; /* Start sending keep-alives now that tsch_is_associated is set */ tsch_schedule_keepalive(); diff --git a/os/net/mac/tsch/tsch.h b/os/net/mac/tsch/tsch.h index 93b6e0d88..88ebb4db6 100644 --- a/os/net/mac/tsch/tsch.h +++ b/os/net/mac/tsch/tsch.h @@ -175,6 +175,8 @@ extern rtimer_clock_t tsch_timing[tsch_ts_elements_count]; extern unsigned long tx_count; extern unsigned long rx_count; extern unsigned long sync_count; +extern int32_t min_drift_seen; +extern int32_t max_drift_seen; /* TSCH processes */ PROCESS_NAME(tsch_process); From 2271fdfd7b8fc4588836eed63f3fb2cdbc2fcf32 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 25 May 2018 12:33:51 -0700 Subject: [PATCH 124/485] TSCH: minor logging fix --- os/net/mac/tsch/tsch-adaptive-timesync.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/net/mac/tsch/tsch-adaptive-timesync.c b/os/net/mac/tsch/tsch-adaptive-timesync.c index 6508a8752..cf10e9cf1 100644 --- a/os/net/mac/tsch/tsch-adaptive-timesync.c +++ b/os/net/mac/tsch/tsch-adaptive-timesync.c @@ -109,7 +109,7 @@ timesync_learn_drift_ticks(uint32_t time_delta_asn, int32_t drift_ticks) TSCH_LOG_ADD(tsch_log_message, snprintf(log->message, sizeof(log->message), - "drift %ld (min/max delta seen: %"PRId32"/%"PRId32")", + "drift %ld ppm (min/max delta seen: %"PRId32"/%"PRId32")", tsch_adaptive_timesync_get_drift_ppm(), min_drift_seen, max_drift_seen)); } From 9aa08fd3024a37ec739c01be13c693f3d6686614 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 26 May 2018 02:04:22 +0100 Subject: [PATCH 125/485] Reposition the generic flash driver in the doxygen tree --- arch/dev/ext-flash/ext-flash.c | 4 ++-- arch/dev/ext-flash/ext-flash.h | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/arch/dev/ext-flash/ext-flash.c b/arch/dev/ext-flash/ext-flash.c index 10e953ffa..c9378d2aa 100644 --- a/arch/dev/ext-flash/ext-flash.c +++ b/arch/dev/ext-flash/ext-flash.c @@ -29,11 +29,11 @@ */ /*---------------------------------------------------------------------------*/ /** - * \addtogroup sensortag-cc26xx-ext-flash + * \addtogroup ext-flash * @{ * * \file - * Sensortag/LaunchPad External Flash Driver + * Implementation of a generic external SPI flash driver */ /*---------------------------------------------------------------------------*/ #include "contiki.h" diff --git a/arch/dev/ext-flash/ext-flash.h b/arch/dev/ext-flash/ext-flash.h index 20748a2f0..73b7320f8 100644 --- a/arch/dev/ext-flash/ext-flash.h +++ b/arch/dev/ext-flash/ext-flash.h @@ -29,14 +29,23 @@ */ /*---------------------------------------------------------------------------*/ /** - * \addtogroup common-cc26xx-peripherals + * \addtogroup dev * @{ * - * \defgroup sensortag-cc26xx-ext-flash SensorTag/LaunchPad External Flash + * \defgroup ext-flash Generic external SPI flash driver + * + * This is a generic driver for external SPI flash memories. The driver has + * been tested and works with multiple external SPI flash parts. The list of + * parts the driver has been tested against is shown in the README in this + * directory. + * + * If you successfully use this driver with a part that is not listed in the + * README, please let us know so we can update it. + * * @{ * * \file - * Header file for the Sensortag/LaunchPad External Flash Driver + * Header file for the external SPI flash API */ /*---------------------------------------------------------------------------*/ #ifndef EXT_FLASH_H_ From 92e4ff3ef457ef1cc790324ada49b5e1a2cbc73b Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 26 May 2018 02:04:42 +0100 Subject: [PATCH 126/485] Tidy-up doxygen for uiplib --- os/net/ipv6/uiplib.c | 8 +++++++- os/net/ipv6/uiplib.h | 31 +++++++++++++++---------------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/os/net/ipv6/uiplib.c b/os/net/ipv6/uiplib.c index cd6d15c8b..a6d8b4f0c 100644 --- a/os/net/ipv6/uiplib.c +++ b/os/net/ipv6/uiplib.c @@ -33,8 +33,11 @@ */ /** + * \addtogroup uip-addr-lib + * @{ + * * \file - * Various uIP library functions. + * Implementation of the IP address manipulation library * \author * Nicolas Tsiftes * Niclas Finne @@ -223,3 +226,6 @@ uiplib_ipaddr_snprint(char *buf, size_t size, const uip_ipaddr_t *addr) return n; } /*---------------------------------------------------------------------------*/ +/** + * @} + */ diff --git a/os/net/ipv6/uiplib.h b/os/net/ipv6/uiplib.h index 3a935f51b..b30a1bcb5 100644 --- a/os/net/ipv6/uiplib.h +++ b/os/net/ipv6/uiplib.h @@ -31,23 +31,24 @@ * * */ - -/** - * \file - * Various uIP library functions. - * \author - * Adam Dunkels - * - */ - #ifndef UIPLIB_H_ #define UIPLIB_H_ #include "net/ipv6/uip.h" /** - * \addtogroup uipconvfunc + * \addtogroup uip * @{ + * + * \defgroup uip-addr-lib uIP address manipulation library + * + * A library with various IP address manipulation functions + * @{ + * + * \file + * Header file for the IP address manipulation library + * \author + * Adam Dunkels */ /** @@ -77,10 +78,6 @@ int uiplib_ip4addrconv(const char *addrstr, uip_ip4addr_t *addr); int uiplib_ip6addrconv(const char *addrstr, uip_ip6addr_t *addr); /** @} */ -/** - * \addtogroup uiplib - * @{ - */ /* The maxium length of an IPv6 string, including terminating null bytes * fd01:0002:0003:0004:0005:0006:0007:0008 => 39 + 1 bytes */ @@ -103,6 +100,8 @@ void uiplib_ipaddr_print(const uip_ipaddr_t *addr); */ int uiplib_ipaddr_snprint(char *buffer, size_t size, const uip_ipaddr_t *addr); -/** @} */ - #endif /* UIPLIB_H_ */ +/** + * @} + * @} + */ From 9610adb5e17e4cde044ce54917df59b48b853e34 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 25 May 2018 12:38:09 -0700 Subject: [PATCH 127/485] RPL Lite urgent probing logs: from WARN to INFO --- os/net/routing/rpl-lite/rpl-neighbor.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/os/net/routing/rpl-lite/rpl-neighbor.c b/os/net/routing/rpl-lite/rpl-neighbor.c index 5f2f7f69a..a066af313 100644 --- a/os/net/routing/rpl-lite/rpl-neighbor.c +++ b/os/net/routing/rpl-lite/rpl-neighbor.c @@ -405,9 +405,9 @@ rpl_neighbor_select_best(void) /* The best is not fresh. Probe it (unless there is already an urgent probing target). We will be called back after the probing anyway. */ if(curr_instance.dag.urgent_probing_target == NULL) { - LOG_WARN("best parent is not fresh, schedule urgent probing to "); - LOG_WARN_6ADDR(rpl_neighbor_get_ipaddr(best)); - LOG_WARN_("\n"); + LOG_INFO("best parent is not fresh, schedule urgent probing to "); + LOG_INFO_6ADDR(rpl_neighbor_get_ipaddr(best)); + LOG_INFO_("\n"); curr_instance.dag.urgent_probing_target = best; rpl_schedule_probing_now(); } From 471a7093b9a2a015c0a89d7fea1947b321c691ce Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 25 May 2018 12:40:00 -0700 Subject: [PATCH 128/485] nbr-policy: fix typo in logs --- os/net/routing/rpl-lite/rpl-nbr-policy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/os/net/routing/rpl-lite/rpl-nbr-policy.c b/os/net/routing/rpl-lite/rpl-nbr-policy.c index 3db84f3a8..9adbc3b90 100644 --- a/os/net/routing/rpl-lite/rpl-nbr-policy.c +++ b/os/net/routing/rpl-lite/rpl-nbr-policy.c @@ -127,12 +127,12 @@ find_removable_dio(uip_ipaddr_t *from, rpl_dio_t *dio) /* Add the new neighbor only if it is better than the current worst. */ if(dio->rank + curr_instance.min_hoprankinc < worst_rank - curr_instance.min_hoprankinc / 2) { /* Found *great* neighbor - add! */ - LOG_INFO("nbr-policy: DIO rank %u, worse_rank %u -- add to cache\n", + LOG_INFO("nbr-policy: DIO rank %u, worst_rank %u -- add to cache\n", dio->rank, worst_rank); return worst_rank_nbr_lladdr; } - LOG_INFO("nbr-policy: DIO rank %u, worse_rank %u -- do not add to cache\n", + LOG_INFO("nbr-policy: DIO rank %u, worst_rank %u -- do not add to cache\n", dio->rank, worst_rank); return NULL; } From 361725038390648907530feb74e25d1ad230daa9 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 25 May 2018 12:41:31 -0700 Subject: [PATCH 129/485] nbr-policy: change log level from INFO to DBG for most logs --- os/net/routing/rpl-lite/rpl-nbr-policy.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/os/net/routing/rpl-lite/rpl-nbr-policy.c b/os/net/routing/rpl-lite/rpl-nbr-policy.c index 9adbc3b90..9752b1446 100644 --- a/os/net/routing/rpl-lite/rpl-nbr-policy.c +++ b/os/net/routing/rpl-lite/rpl-nbr-policy.c @@ -104,7 +104,7 @@ update_state(void) /* how many more IP neighbors can be have? */ num_free = NBR_TABLE_MAX_NEIGHBORS - num_used; - LOG_INFO("nbr-policy: free: %d, parents: %d\n", num_free, num_parents); + LOG_DBG("nbr-policy: free: %d, parents: %d\n", num_free, num_parents); } /*---------------------------------------------------------------------------*/ static const linkaddr_t * @@ -127,12 +127,12 @@ find_removable_dio(uip_ipaddr_t *from, rpl_dio_t *dio) /* Add the new neighbor only if it is better than the current worst. */ if(dio->rank + curr_instance.min_hoprankinc < worst_rank - curr_instance.min_hoprankinc / 2) { /* Found *great* neighbor - add! */ - LOG_INFO("nbr-policy: DIO rank %u, worst_rank %u -- add to cache\n", + LOG_DBG("nbr-policy: DIO rank %u, worst_rank %u -- add to cache\n", dio->rank, worst_rank); return worst_rank_nbr_lladdr; } - LOG_INFO("nbr-policy: DIO rank %u, worst_rank %u -- do not add to cache\n", + LOG_DBG("nbr-policy: DIO rank %u, worst_rank %u -- do not add to cache\n", dio->rank, worst_rank); return NULL; } From 857c7f51b2fcabd641b075757903cda9dc923762 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 25 May 2018 12:51:46 -0700 Subject: [PATCH 130/485] rpl-dag-root: more readable logging of DAG root node IPv6 addresses --- os/net/routing/rpl-lite/rpl-dag-root.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/os/net/routing/rpl-lite/rpl-dag-root.c b/os/net/routing/rpl-lite/rpl-dag-root.c index c96fd6656..c3e356828 100644 --- a/os/net/routing/rpl-lite/rpl-dag-root.c +++ b/os/net/routing/rpl-lite/rpl-dag-root.c @@ -94,11 +94,12 @@ set_global_address(uip_ipaddr_t *prefix, uip_ipaddr_t *iid) uip_ds6_addr_add(&root_ipaddr, 0, ADDR_AUTOCONF); - LOG_INFO("IPv6 addresses: "); + LOG_INFO("IPv6 addresses:\n"); for(i = 0; i < UIP_DS6_ADDR_NB; i++) { state = uip_ds6_if.addr_list[i].state; if(uip_ds6_if.addr_list[i].isused && (state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) { + LOG_INFO("-- "); LOG_INFO_6ADDR(&uip_ds6_if.addr_list[i].ipaddr); LOG_INFO_("\n"); } From cf8d2b6f135811479aebb6f7071b494ce3bd17c3 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 12 May 2018 16:13:44 +0100 Subject: [PATCH 131/485] Remove jn516x serialdump source, makefile and binaries --- tools/jn516x/Makefile | 30 --- tools/jn516x/serialdump-linux | Bin 12663 -> 0 bytes tools/jn516x/serialdump.c | 396 ---------------------------------- 3 files changed, 426 deletions(-) delete mode 100644 tools/jn516x/Makefile delete mode 100644 tools/jn516x/serialdump-linux delete mode 100644 tools/jn516x/serialdump.c diff --git a/tools/jn516x/Makefile b/tools/jn516x/Makefile deleted file mode 100644 index 2c4254a71..000000000 --- a/tools/jn516x/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -ifndef HOST_OS - ifeq ($(OS),Windows_NT) - HOST_OS := Windows - else - HOST_OS := $(shell uname) - endif -endif - -ifeq ($(HOST_OS),Windows) - SERIALDUMP = serialdump-windows -endif - -ifeq ($(HOST_OS),Darwin) - SERIALDUMP = serialdump-macos -endif - -ifndef SERIALDUMP - # Assume Linux - SERIALDUMP = serialdump-linux -endif - -all: $(SERIALDUMP) - -CFLAGS += -Wall -Werror - -$(SERIALDUMP): serialdump.c - $(CC) -O2 -o $@ $< - -clean: - rm -f $(SERIALDUMP) diff --git a/tools/jn516x/serialdump-linux b/tools/jn516x/serialdump-linux deleted file mode 100644 index 69fd8cfdbb5347bfc6e91999ffc9685af6722e94..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12663 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#define BAUDRATE B115200 -#define BAUDRATE_S "115200" -#ifdef linux -#define MODEMDEVICE "/dev/ttyS0" -#else -#define MODEMDEVICE "/dev/com1" -#endif /* linux */ - -#define SLIP_END 0300 -#define SLIP_ESC 0333 -#define SLIP_ESC_END 0334 -#define SLIP_ESC_ESC 0335 - -#define CSNA_INIT 0x01 - -#define BUFSIZE 40 -#define HCOLS 20 -#define ICOLS 18 - -#define MODE_START_DATE 0 -#define MODE_DATE 1 -#define MODE_START_TEXT 2 -#define MODE_TEXT 3 -#define MODE_INT 4 -#define MODE_HEX 5 -#define MODE_SLIP_AUTO 6 -#define MODE_SLIP 7 -#define MODE_SLIP_HIDE 8 - -static unsigned char rxbuf[2048]; - -static int -usage(int result) -{ - printf("Usage: serialdump [-x] [-s[on]] [-i] [-bSPEED] [SERIALDEVICE]\n"); - printf(" -x for hexadecimal output\n"); - printf(" -i for decimal output\n"); - printf(" -s for automatic SLIP mode\n"); - printf(" -so for SLIP only mode (all data is SLIP packets)\n"); - printf(" -sn to hide SLIP packages\n"); - printf(" -T[format] to add time for each text line\n"); - printf(" (see man page for strftime() for format description)\n"); - return result; -} - -static void -print_hex_line(unsigned char *prefix, unsigned char *outbuf, int index) -{ - int i; - - printf("\r%s", prefix); - for(i = 0; i < index; i++) { - if((i % 4) == 0) { - printf(" "); - } - printf("%02X", outbuf[i] & 0xFF); - } - printf(" "); - for(i = index; i < HCOLS; i++) { - if((i % 4) == 0) { - printf(" "); - } - printf(" "); - } - for(i = 0; i < index; i++) { - if(outbuf[i] < 30 || outbuf[i] > 126) { - printf("."); - } else { - printf("%c", outbuf[i]); - } - } -} - -int -main(int argc, char **argv) -{ - struct termios options; - fd_set mask, smask; - int fd; - speed_t speed = BAUDRATE; - char *speedname = BAUDRATE_S; - char *device = MODEMDEVICE; - char *timeformat = NULL; - unsigned char buf[BUFSIZE], outbuf[HCOLS]; - unsigned char mode = MODE_START_TEXT; - int nfound, flags = 0; - unsigned char lastc = '\0'; - - int index = 1; - while(index < argc) { - if(argv[index][0] == '-') { - switch(argv[index][1]) { - case 'b': - /* set speed */ - if(strcmp(&argv[index][2], "38400") == 0) { - speed = B38400; - speedname = "38400"; - } else if(strcmp(&argv[index][2], "19200") == 0) { - speed = B19200; - speedname = "19200"; - } else if(strcmp(&argv[index][2], "57600") == 0) { - speed = B57600; - speedname = "57600"; - } else if(strcmp(&argv[index][2], "115200") == 0) { - speed = B115200; - speedname = "115200"; - } else if(strcmp(&argv[index][2], "230400") == 0) { - speed = B230400; - speedname = "230400"; - } else if(strcmp(&argv[index][2], "460800") == 0) { - speed = B460800; - speedname = "460800"; - } else if(strcmp(&argv[index][2], "500000") == 0) { - speed = B500000; - speedname = "500000"; - } else if(strcmp(&argv[index][2], "576000") == 0) { - speed = B576000; - speedname = "576000"; - } else if(strcmp(&argv[index][2], "921600") == 0) { - speed = B921600; - speedname = "921600"; - } else if(strcmp(&argv[index][2], "1000000") == 0) { - speed = B1000000; - speedname = "1000000"; - } else { - fprintf(stderr, "unsupported speed: %s\n", &argv[index][2]); - return usage(1); - } - break; - case 'x': - mode = MODE_HEX; - break; - case 'i': - mode = MODE_INT; - break; - case 's': - switch(argv[index][2]) { - case 'n': - mode = MODE_SLIP_HIDE; - break; - case 'o': - mode = MODE_SLIP; - break; - default: - mode = MODE_SLIP_AUTO; - break; - } - break; - case 'T': - if(strlen(&argv[index][2]) == 0) { - timeformat = "%Y-%m-%d %H:%M:%S"; - } else { - timeformat = &argv[index][2]; - } - mode = MODE_START_DATE; - break; - case 'h': - return usage(0); - default: - fprintf(stderr, "unknown option '%c'\n", argv[index][1]); - return usage(1); - } - index++; - } else { - device = argv[index++]; - if(index < argc) { - fprintf(stderr, "too many arguments\n"); - return usage(1); - } - } - } - fprintf(stderr, "connecting to %s (%s)", device, speedname); - -#ifdef O_SYNC - fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY /*| O_DIRECT*/ | O_SYNC); - if(fd < 0 && errno == EINVAL){ // O_SYNC not supported (e.g. raspberian) - fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY | O_DIRECT); - } -#else - fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY | O_SYNC ); -#endif - if(fd < 0) { - fprintf(stderr, "\n"); - perror("open"); - exit(-1); - } - fprintf(stderr, " [OK]\n"); - - if(fcntl(fd, F_SETFL, 0) < 0) { - perror("could not set fcntl"); - exit(-1); - } - - if(tcgetattr(fd, &options) < 0) { - perror("could not get options"); - exit(-1); - } - /* fprintf(stderr, "serial options set\n"); */ - cfsetispeed(&options, speed); - cfsetospeed(&options, speed); - /* Enable the receiver and set local mode */ - options.c_cflag |= (CLOCAL | CREAD); - /* Mask the character size bits and turn off (odd) parity */ - options.c_cflag &= ~(CSIZE | PARENB | PARODD); - /* Select 8 data bits */ - options.c_cflag |= CS8; - - /* Raw input */ - options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); - /* Raw output */ - options.c_oflag &= ~OPOST; - - if(tcsetattr(fd, TCSANOW, &options) < 0) { - perror("could not set options"); - exit(-1); - } - - /* Make read() return immediately */ - /* if (fcntl(fd, F_SETFL, FNDELAY) < 0) { */ - /* perror("\ncould not set fcntl"); */ - /* exit(-1); */ - /* } */ - - FD_ZERO(&mask); - FD_SET(fd, &mask); - FD_SET(fileno(stdin), &mask); - - index = 0; - for(;;) { - smask = mask; - nfound = select(FD_SETSIZE, &smask, (fd_set *) 0, (fd_set *) 0, (struct timeval *) 0); - if(nfound < 0) { - if(errno == EINTR) { - fprintf(stderr, "interrupted system call\n"); - continue; - } - /* something is very wrong! */ - perror("select"); - exit(1); - } - - if(FD_ISSET(fileno(stdin), &smask)) { - /* data from standard in */ - int n = read(fileno(stdin), buf, sizeof(buf)); - if(n < 0) { - perror("could not read"); - exit(-1); - } else if(n > 0) { - /* because commands might need parameters, lines needs to be - separated which means the terminating LF must be sent */ - /* while(n > 0 && buf[n - 1] < 32) { */ - /* n--; */ - /* } */ - if(n > 0) { - int i; - /* fprintf(stderr, "SEND %d bytes\n", n);*/ - /* write slowly */ - for(i = 0; i < n; i++) { - if(write(fd, &buf[i], 1) <= 0) { - perror("write"); - exit(1); - } else { - fflush(NULL); - usleep(6000); - } - } - } - } else { - /* End of input, exit. */ - exit(0); - } - } - - if(FD_ISSET(fd, &smask)) { - int i, j, n = read(fd, buf, sizeof(buf)); - if(n < 0) { - perror("could not read"); - exit(-1); - } - - for(i = 0; i < n; i++) { - switch(mode) { - case MODE_START_TEXT: - case MODE_TEXT: - printf("%c", buf[i]); - break; - case MODE_START_DATE: { - time_t t; - t = time(&t); - strftime(outbuf, HCOLS, timeformat, localtime(&t)); - printf("%s|", outbuf); - mode = MODE_DATE; - } - /* continue into the MODE_DATE */ - case MODE_DATE: - printf("%c", buf[i]); - if(buf[i] == '\n') { - mode = MODE_START_DATE; - } - break; - case MODE_INT: - printf("%03d ", buf[i]); - if(++index >= ICOLS) { - index = 0; - printf("\n"); - } - break; - case MODE_HEX: - rxbuf[index++] = buf[i]; - if(index >= HCOLS) { - print_hex_line("", rxbuf, index); - index = 0; - printf("\n"); - } - break; - - case MODE_SLIP_AUTO: - case MODE_SLIP_HIDE: - if(!flags && (buf[i] != SLIP_END)) { - /* Not a SLIP packet? */ - printf("%c", buf[i]); - break; - } - /* continue to slip only mode */ - case MODE_SLIP: - switch(buf[i]) { - case SLIP_ESC: - lastc = SLIP_ESC; - break; - - case SLIP_END: - if(index > 0) { - if(flags != 2 && mode != MODE_SLIP_HIDE) { - /* not overflowed: show packet */ - print_hex_line("SLIP: ", rxbuf, index > HCOLS ? HCOLS : index); - printf("\n"); - } - lastc = '\0'; - index = 0; - flags = 0; - } else { - flags = !flags; - } - break; - - default: - if(lastc == SLIP_ESC) { - lastc = '\0'; - - /* Previous read byte was an escape byte, so this byte will be - interpreted differently from others. */ - switch(buf[i]) { - case SLIP_ESC_END: - buf[i] = SLIP_END; - break; - case SLIP_ESC_ESC: - buf[i] = SLIP_ESC; - break; - } - } - - rxbuf[index++] = buf[i]; - if(index >= sizeof(rxbuf)) { - fprintf(stderr, "**** slip overflow\n"); - index = 0; - flags = 2; - } - break; - } - break; - } - } - - /* after processing for some output modes */ - if(index > 0) { - switch(mode) { - case MODE_HEX: - print_hex_line("", rxbuf, index); - break; - } - } - fflush(stdout); - } - } -} From 31ceb23f3adb470e29c1d56a83573c150e5e2102 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 12 May 2018 16:15:29 +0100 Subject: [PATCH 132/485] Remove sky serialdump makefile and binaries --- tools/sky/Makefile | 30 ------------------------------ tools/sky/serialdump-linux | Bin 12728 -> 0 bytes tools/sky/serialdump-macos | Bin 14008 -> 0 bytes tools/sky/serialdump-windows.exe | Bin 24342 -> 0 bytes 4 files changed, 30 deletions(-) delete mode 100644 tools/sky/Makefile delete mode 100755 tools/sky/serialdump-linux delete mode 100755 tools/sky/serialdump-macos delete mode 100755 tools/sky/serialdump-windows.exe diff --git a/tools/sky/Makefile b/tools/sky/Makefile deleted file mode 100644 index 2c4254a71..000000000 --- a/tools/sky/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -ifndef HOST_OS - ifeq ($(OS),Windows_NT) - HOST_OS := Windows - else - HOST_OS := $(shell uname) - endif -endif - -ifeq ($(HOST_OS),Windows) - SERIALDUMP = serialdump-windows -endif - -ifeq ($(HOST_OS),Darwin) - SERIALDUMP = serialdump-macos -endif - -ifndef SERIALDUMP - # Assume Linux - SERIALDUMP = serialdump-linux -endif - -all: $(SERIALDUMP) - -CFLAGS += -Wall -Werror - -$(SERIALDUMP): serialdump.c - $(CC) -O2 -o $@ $< - -clean: - rm -f $(SERIALDUMP) diff --git a/tools/sky/serialdump-linux b/tools/sky/serialdump-linux deleted file mode 100755 index 4d3e616a9554d698c9b826be0e4ce45cf5a8940c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12728 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 diff --git a/tools/sky/serialdump-macos b/tools/sky/serialdump-macos deleted file mode 100755 index 775f88707f25032d7f8835e8d4dc7a09bb07647b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14008 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 diff --git a/tools/sky/serialdump-windows.exe b/tools/sky/serialdump-windows.exe deleted file mode 100755 index 11ac7cae668a1c98aa16e2016c8cd4bf8f8fa487..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24342 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

&YTNNEplw)aD0|;sK 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 diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/img/quickstart-sensortag.png b/examples/platform-specific/cc26xx/cc26xx-web-demo/img/quickstart-sensortag.png deleted file mode 100644 index a7ce7dabeb979afdf8a31a5803265281fb10636f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 158808 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 MIn&AxK&B#q%BQyt^9Mm;?p>DPv~0V;+Nskt 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 diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/img/sensor-readings-config.png b/examples/platform-specific/cc26xx/cc26xx-web-demo/img/sensor-readings-config.png deleted file mode 100644 index 79c8e61e3f410f2500dda37b87466863464e2b8c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33000 zcmce+QVNOE&%Wcn-}N$cW@bcW##kdG z;+q*ND=h*8i3te+001K{KB>-URoF09XU!8q@0zGj1{Wt(pRjkyc9-l2&-N9TT>Ahe8 zkb>;7@x9U_uLFj4L3xq@@VI5?l_SW~_Vi<6gpPa(&ocIROxY<117=-ZN=O)20e3_I zzmQQS5}*Ox&=*hDE({ysf_&>5ef!aJCiqq}Ck^amr-WCzxV=`1@q|{{Zgt*>zcr?X z%w$l1tBuWHGoXOzcn8x(Hr{=2M1A9&n(d{UoaBk^h644IsW?uXDf;K4-2AN)Z5p{}X)8uf78_{`-I>o53uT`sOG`u4OHZciL zoa)(qdlPfwPiW9iIiYYS z3xptb<6>fz-zy11CG2IiL$VFcUB1P!$k)nDy1B8b7F_pkL&|6AnMC0jLVlIAoTLR< z*9Qzm#H7*j0V|V65N|kpQF6ws5EnG(oK%BqENzJ{9*qhgP%Y=z!VF_2c!VD)M<$Ui zXjTs#h@UJx#9j|#4;WVrtdK6KDvUipAUV)_kF+e{lOJ#nDmLh34on8naW9E2%!A+h z4nd4B!3|=BKb$VMKR%aGkZBBN0SpG8aSZi<24~Q)GOgD>nj8o;MlOm5sZE8yFhk!Eyx>`n)KFiRS+()%h6Z^k-N99%pDk8 zFnD1myNtJ>FPkq!FZC~2F9aWCK&d%WH6$-cdk{bZxVaIsGHik^{I1gIWMc?0e`y9} z2}4@qS`uAjR`@%lu?eH%55$CtS>=f-f)XSs$(ZA4;&5ZPVn+?N>KNSsQ)RSeXvpx0 zbV%W1comSzi;(fg2*Xn9g6vc5qwKTqqQna^<+)357bMS6&2b)q9w8p%p{0i8gDLuB z)yNbm<|!Qnj~c1umiU$=oI@?6EK@J+R?q9I5B}N*+w<5{wKm!(+LIk#jYW>mA6Oj- z9?l>+T*f{}2zRlq^nC_6 zW=(LZaLW*7Brqm7ra_u|8ep2hftitr-^@4ZR=z`%HiMij4=L=Yi%S+kC-Rj-^ z-+q9zzIr{3D@HR`H?uP%bVIiBdg;40v1JJJx06pPkLd=JnUkPL%ttQN<94IEz!;)|p!En^+!<9#x;( z?;fyBA#Skg*c>=r>>TW2*jP9s84sC=8D$w)49FOI5&A<$CKdI~_Z-IxQ`uVBS`1og zT3^nMwo*=&E;v~hOv#+jI~)A0TC7PLjp+lKS6Mq<+gf|M`@MH1x2|WU$D_Ag2d^9B z1HT8)|1MkDSlGn6gg=Ymp=C4k9D5>c18fUyYx9D3lXpXQlYO;)jefy=H`M=H-m2(nKP_Ta2%P&D9ohgROyP_3fca-nTMZ;mlGZ4a@C&cz`4hrWKE$>*+zvF zNX_LGzze|$qK1370<`8|@gD=7?z8Gs32_mbAxsip5b^x`5Ve8%N;k$Pj=hLMjnzrs zM)PJ6VIwIPLA*riEOpVy_Q>X~>A}Ur!|^5iu_DkN#EAw=ZLg|Wb26o$Ke!rRO(mxj z*L3h8zgk#PIE+*SK@af=p`(^tfw`ng$XH8hmvGs?HRwHhdyrr+++w|fcy&+QTo6~V zYuJ2%GfKn-r;TxqvK^w+>l2TdQb&7eU~YQ0yAaxt(op0m;4bhc=I4*EG}9<)q4reg zots+2N3M2N=Xrc5Cs%VK3zksJmd~w#z|6+2Z*VJo%a`P#Y_wF2GW$EqWZVR*&OQUX)YHw}I$^HCp8Kx3WRVQ6yOltCzdzzz~ z`1&(A1qSCe?e+W~oE6N{l01e29%WEzE`D!zGopi<7q<#2l4e>QDBd!f%%Yti{4}(7yA#TUY$E1rA`)auRWXTZVzDtk&vywTaq2r-o;N>Hy-cLnFe|WGCT!7 z=-;X@VwVb+CPT+pwDdYz(bX?u-|AnJ2O7iAJJ->qb7Z7}R0tMhkocy3VqyRt+!1eq zYyhTS05OI|Ubl*T^V;5FJ<+afoH9W~0E_2uVVklU{Qs2C^~+5&8>F;T`Cjm&@uAA-rq^_A}imHyPQj#17HdZuxhBo>}G_F>*KiMn*0GBJrPt(fC zQ4inM%F^0_!9CGXzAJ6*=gw*Xc-u&e`ZiSxLG^uxl&s@ z5dD{u|D#99$icwg%+}G&#v1>hUOjyqCr55V!heST=l5UhG;%fjzm}{W{(DIa= zLQ79WNBcjze?+WCXxf)rj3Yl3MSv&mL;9+2(pPYeWC#t^f4?xQhppi}rt9&jX3Ye@zJhzy}~E#INWIc+m-?s(F~o z`XvDcRsl~SKv+r=TOctvSrfM$ZfQ}6^Ux?}#dv{PEB8QPh5ZihByDOW~bGAx|aGf$!LN$Ct+TEj-6T7neN; zYJ-bGqgwo!Zyr~cI0QZ+jwQ)-Be0*%f_3a23?%Sr8I-0jk5+zd)72QA2n|c=9C0`J z;pUeCcKe`K)LEu~t|;b>cW<>EtW@_ZAexkWHYZrU375IRQzk`LOf;D>QPgJ>&cghu zb*`Om2NZkyQ`@z<*@&B)${*M#cO7(I>4A!OuDVZs8=(urj0cz+PH6bCs^+J|QHNb&apcynWi~F^WRt=hjG76A z(@Fc{(XY%z)+Ky;u&%WP93SL~i_mXezVE|DrDPLXPJ4EIQE0ju2y6ANAoofd4L)&R z7NKbOFX3n*$~2aI5S~4apcV#S3|*k}U)>nB-5$Burv47i88!FVu9F&mOcvh`-51Ze zj7wjv#vR1}0ohn5pq+Id@sRF0b)2&v!L;mpx8BH%JsS=Pt<{6p!WW1PkI;@vF#Jl2 z&M%*hK%454`YIG{fA_u^5nYlEfn|FZdj5@Tv8p zWrFs$6_d>kGA*ws`i-|z!vY~^tt}-DguvsOPEq~2vWvG%o9l;FA3AMPE8dSXDPqxQN!;jJI%!;2m!WTf@P! zfY`xRsA-_q+}7I1yQXzsZ(1n#3KFAiKS|i@}U|hVU=h=K9p$RC9s-V_sU?P>v0DjoJzKS2fW-&MJ#ts|8^wL=@Ii|p;U@guvYFemT1fr zh+tw?E7X_5Wp!0a*G=WW3teyjlxV$Bz?PQ6gBT_O#mI*|-zi@ArAr1J}bg3b6G3?`t@mf6+x zp7NsV1OO(8+q&RU>?P_(s>L8vCG~jTC;l|oXnL#I`+D>`uGoaJ}V4IBr54QOun6WO2tY^pq$){#c=5$qNsTwj;0s>MX#@)uIrqVt?&?tw& z!u^!-urp67;D7|xdY|84rB&ORXFc~QU3*~ejfDA~sRq_zk64@WvgbH$vZCK+(-Fm4 z*Tsj2y!(X!9=Xgx9Z{5U(f= zl2#0Jm*w1Kb?3yXk!^WsaUN*~XzU--?lrhoR{oBt>F$ww!2ivF2%av&v`Q3{(FHuL zPJ)S=8e5K`PBC!2UCa*PmH5&9D$E44y4$d>TMzoO>J##Ww=NDF$gKS~?O=Vh)z_e^hM!Y*?N+z%sddSvPnQgDjm<^=ly=Is>kHSsnJg5f`m6%Rcug1T zgs^%TvOADvB_sB4Sg4?;rms$f`NmftV=E|T{Hl8Gh;4r2SR9fU^Hv$w)v`#E2pVL(XNTX-R<3IP!2o_C5 zF-%1T(#e`hroFE#Hk$6IAA-6ZkkU3h0OcS`R~$}|HJf-8-y+XDp?-;bAG)h`kny-~ z90Z!DZX%W6xw5m+)4MomCpQ)WERsqr_HqxH)QbycVub= zmgR8VTi&W`6)oWj?D(c-2%5r>6Nu9zp>r3%yrxBmG}meCLtni*r*iN=X~6D#ka>9S zkqx`c+77#OCDh~4LbsBA@gOro4cwXQPwtyOpB56uv{~V$O{{sRq8T>ts>T*UDawqr zVoZfMtRJ4+TinO&c@29anGhkjDkj_sZT{vd{4-EEmnW0I{mVew)#pm^dBz=`q@fw9 zwVmcf_PxJ*WZJgi6~DAfIIk+ZA26wZLEyr{q|2`ql_FK0dPxffPWOBZ=}I8t#rX@C zcz6&$xR{=v9`{phTYV$f?4CoHBA4j%X*hE;4aaBeRHam-gkeUwN~qAo+vw7~O)m7w zfZNQRL(sa`(AqrCe7y6u{&y#(^5$WeI(f#j;^~qT(j(_5HRj);^241**P9aK(lze2 zD&^bJXH0>(F$|{_9;>R$dvocPwZ^sE!MT_+&CmvthF3rxD->ooHt%ZZaQ?C<57>O3 zG$d`o-Jh^MhmQAqn!3G0opL(y@lUvhp;fYVWK)b}`fsJ>q|q~_f?XnVu}yJ`VUNi~ zPbRU`&iiAnCPO)l(l#KqsPabL48I1YUqHmHDr1wA$#?g!D#R!#C}M*~iSk|&#fBs> zNQ09R%i>ozRbORV-ausCzC|DQrJe0Ebx~2`OMcd&q&Ga06O~Vp5yj?_Qw7PZU9^q4 zBUI(EtCjK+R<+qQ86zTX>4{RCag)Z0X_Q`%IEnT!tAp|i&+uj#?x51rjADsL(q_Jj zu2j^EJaEcxZV4>!r}%MZ^2ae!m^h}lv)=_<8^ea9JPQ0u?0zp6F=6HDhFf5-s^r%qH5O{&AFCPk)!ZHF zYx}gePtt0vw9WG7W~GUDz*_~$rCPgn)wtocfniJeb8r3|by{Z8EvgO72G?|R5?K#yZ< z&PnBs;h&T+*tx2*DJSC@IF19d6rglT_@DhZZq-$rMpm;C_8rfa$~Z=#XG!|oaMhmE zq@`PZ32SiK&z*9v3R|DbJ+onPQ_CA`&Y=x^0z59M&4P$hr~-4P<4W%q;28_8<4Yur zdyQ#+1RoM?k(A2pb?fF=eRUC5qLK0WWMo5nI2_SXc;3I(^7>c6@%D!Ti8t!pQBHG$ znsw<;(FM29KXWQN zx??D(oyu+3iz2<_jjb}HYWX|1-c2&Te-%&)!*uI`E^Q|XJNVyRscCFU_Qmf9xZd*e z4xlj_aSq(Z@@IIwdue}$EWV*tsQX~C#CfTcvodbU=(c=2bud4nQND2y7h3X($C-=C zC=sj!b$uOayg=2Sv|+{9=oyHsLIRf&8c%aBg-r}_&azA*-k*ct^mE#+c4U>U0RXWo zp>k^-_biS9f~WoN3b=ev{DXuP7AA%yvaVSSV^uip6&P0mJJUApVo&>ig^L9Yg@rU+K=Z>M?$gVq`uXK}E+1+`(_V$vLz}&3_kO+eF&5@P zt35g|-v=Fb8tj9Z6nmeE^-^H5m&(#9pm_$8)0uek(73Ew?JZ_*9BR{L(m@yTb255A z_VV59$b{c!JSOsN_zTWYlmwh4^%6vD$2dLT-Ax4$oRp5?#RU566?@D3TC1a)fjFv@ z0wTNhP`RL>O3+?lM`^jW15j({D6ZXol>?j!d*;{{Gx&r*6WC$&|J4mD-4D-Q;-E|O z5A*z6xyG??FmPLs8G0VL6YK;DxT9aX#MPP6IrfY#9~v8s;6u)oU+cjS9da1e>a@%R z#)LfqD%SgpyTDGDj6DNtP19PQT~W8#Js(<2>p_)v(-a`gkCk~kA-FT_6p0^otjQaT<4f#0yFXU`|6R1-D?5XbLg~+D zat?diue(BedmYd*+|bZyBEk<2$M<6r92w>1mv)ZQRm|%pF>rBk25)ZY64`;$CrMBC z_xDRDh>6L_i0J9<#u$v#`R4m)37i}wrsGH?K77pD?H&vng-MOuAsm#lfXQ6ITi_-; zFRRW{%fU_#gGc?oKV+c1@6%Z_xZf!uhS+#+LrM0Ay`%P-ic+IIJ|CB77Z-z~dES1V zFIDz8S*;I5e_{`tNiuFr6WPkG*c~tlYlQvbj4-;i6{A_P5~Sk=K|Zn^E(0&a_wgyR zK6AApN_)rA?hEB-VtMxHcerRb1hp?;r#E-#GqVZ_J!eeN8#(o#Tno9go}@*M(`p zB~Pfy-CnE#7*!DafUhJI^xcXhG)xwOB_+u=*ZaEz*U^FZKyU{NJkm4=$-J(E1|q|ZWydQo@EtZnny{h zSh4X_L~M<`*{7DG3vQxU1FVyX%ecK zYvdsiZz_;1UN{L#Y1(ux948PT^Tn5a$dxvY5U&xh$*vMNE~9z$jZ`LZa8Als?MO5k z+N~8NiNE5e@U(YmGc3EGTC@U{wa$%P!sT~vkYYu?2DN;tGXC-*?Rs0n&^4lb*-2w7YYc-m~ZW6M500GnTA zp;-XeywDT(&22bwKsP?Br)b41UFXTT<(i8?+ra{T7Wn7Y2R*94Y7a3crcZS%w5-Ew zrH&Dgm<}6ILkX9G!8vCK!8#fkP0Ma%f-{0)5AZJC)_hy~V#Vq2QNIx~AlEyP%#6WJ zjT^Gy(y{T9w%lCbYkzqx*MI`{v#IdDGL;Ul%(Z03O}Phqk&-f9BG=mQ>1XSXTVX55 z8M=A=3bXd{C4r^o!*jh?r>>o6Q&$Zf)kAyG;Yj9kJX5vTF8^_D}~ov z;NHhj5|hL)@uoEFes?w-G;>9t!)}07U_&sP!^1Bx`-gPt=_e*bX`<%O1>r)YCh(Dk zdtk|P6UxqGUSs_izo;~%4=ZEWCy*f=XE?(Pv`9sSB!S}M_cjPV^A3H-3vH2Q-y0o! z`^G$JRo!!5QV$>$rP=JpJdjeJ;+~I)5E)`rVj}n1nb|lU{Z8WPw;T{})9rOBZ9<4Y zv7OXrW4e$1!tX;nqXdPyYAlMkm$QPeaa~3WA#E);l(ESfaw;Ftv#dH{r&Ysb>+MK4 z(~BW3x7=BsE$=fgZ?OeV$58Zck5aOtHC$SaB&&xk0@9vWT~BpR4_^jtOkY5+I$0$) zdK{)Ri(WU$xLF1JdCoosd@7QtHG<)IUhprtS$>YY`$K^z+cjZNwleK3$DP&dgO~}$ zz2o;L_)@6r?D->rq`A7PwZS$tef@o9c}Fa9pN(8`=N!u4Fw?LeD##sPp#rFW?YKNb zfKa$?_XIg_y)jTk;xw+w?uv4;s{FZgeZzDmap%3kTo;}l(-JQ1JnQTWvR@603y%=2 zfWv`h3@#V?9XCZ!KA*|geIo+{Bp)Xt!-LVEXImj=>@wudp09Uil^l1FB*&?=XtFz` zJTI~fHa~bxawgfkkH0)PQlz$3Hfz`O{>mxg%G+!$t9M$%W5)fCb45l_eEd|w^a7Lk zH9jPed()=?r8D33WnM=p^(c95W`6#!!e=%ZbzP5U3yK=JOkRFI21#n|N_!rNjzs9) z-{G3*m~cY)*gFzMllpC6V3+D-qT)A?FYHiqcFcKq?dOum7P9O;szOx{7r--2OxrkR zqU9|YT#{BS3cn}()9Sm}U*ru5Q=iEuRD6O{O=MUzv|ShtDDoq~W1d`ZhlXt&vdx^B zwX-hyN)>_jTZ8AS0mP(7VA+c!Sk^84mWuaa%Hv-Zg)FipUJ z9klmanRenw`qyLF%mVV?lC3}GQ}$$hVRhF?e3q8-@5EzFp%u~J(Q%y`73yIhtBZ5w zm4BL$Z_SC4&EnK68l+cMXlFeq6oLu5lTKV4XD+m<6XwGvy|Oq^qAN3%0bsg*M~SCB zap*o(p@zM|kdAWolm{PV03%lRyRHEkN>B?*j~ZDe-wlQl7Go5Sp@uKWPnFj(RF91*)ZjPPTTx94QC5>BPDD53248AoNA6KZBDpm_qmM4uR z&c6&d?6x=@Pl=gKWyEfIJ#Xe5WDGG$a%NjYs0h7N) zIRJT#LD-@zMk9$lB&eF2 z-_dZr!Jfu>uT@stcsI|BWlg*VA0)zU0%*j61y@+wkEe`FZ9c)q1dEeE9CpN(Mq(X%za0#U86Gx!+s|Xu?1r*KTGPkN2%Y>cO6JY z>ii-21Y1@2UvBQlE&J(QW&M+4yEyUUbvi*s0KX;hOn`InaQ*VIWQf~$ObQyUGmD)Z zZ1RmVW2h9dZ5{Z@UQbyN6Kkc!xq@>HAvrc8Hq9)d$IMbqk-=)eoM2h;P=-ox%a`|3 zZ6!B9!)FYNb^vTV&r?VT3M{bZ18>!|`6TEmqHD*k`*Lwg>$1OuNo@K{ixBTHW(>Um zIYoUKV>FzWn`aiZY2sEEWbC|Msm1-hGf}}+R~#kdLH*47rn!Mqqrd8FvIV6`IEK8o zgR;OFcqVE4n+kUN2mbz&?{AxhVc(s)ieBE+sKSMe{z(iM=%rFrpn&EFK48J&r$m`40gFJA_}dc86jcEfe?x8>zX^iRPAKV^9k#OM?xmn?N!; z7xTlA3xFgNjrb5#ZYrE!8da!PxQU8)x@B@k3CaGEL+|;Wl$>7L#Y!s@r^^*Sx%r!s zJY24Obbwx3&qNC8G^AvFrk-xvKmji~k+~YA-7-%4Op=CwcVzylc|kS0Bbzq}xmPrDPlvW_RaFv6tkY*xpGP*{uE4Xrb8x?g|7;3dqA3_eNBIH7~_dj=S zP^rbFkUH9o>U_2J$mI?qUPvZ;G?he>!czfJg;59bgcVkST~ zb*C=4_|UYQtR?|5wO@J?N4W~)r?epGSK;kI6~km0FBxxrqb#JgDgJeuLh8pW%x_T5 zE{QaxmRlIf7eg3D&mnS=2emw0Eg&FyGilok{UauimQP@`z+|iD&)^hG^5X}UQ{e75 zdZ{Y;AuZs^G^oSFa)kMVw7Qoojx^zw6d*0cKr?@$^|)$36)~H|5>q}_n`8OG3J#L&WtqrsOTxfaej5+#; z-ef&W5+&Hk{CNrqrCLf}xV&L(qtHy`W* z&659c@_Xg$lh6`EkG;}MuZ^;<#;qH}=u#Q`WgQ**xpDVzZy=J8s-(nM$ODNF^*E}f zD-BDRj?bqPG%RcwQS}QpAWvV)=F3Y9o6SysG*4cBwS0|Uf3Vx(IWiDy=un4fiYnxY zzy#MqB+jUUsczuv$5z=U-9;ro`(wuY2KTX$4N4x2hnQIl;?ojW?l8Ks9mgv37$E3; zV0v{EwCr}2{gjLF(4}5xPJiFiQMwHwGc(HQ=%{WA^kIV1920Q1H76HW#MhVihWmNt zJ*8vrv8_QjsouDV1QH&xWp8fr`l2Vk7AZ$bZ7VFOT58D|K@U7^GfNIWBa#Rfrd-_M zUsbmgm{K7;)4S(w*Y;*$C2$v_>N1Q-M^Qq?ih|Tgk>QyhlQ5`;N+x7QCL})piy`;3 z7_r;bg)An414_2l-((Tb@)~n7NvS~-Oybk!`RvDZly_{Bjsm-`AR;a%gpBc1)a0f) z`ADa^6FD#(3;yqVfp)V$2a4ob85fA)D{D+Eb^6qeVdNX6<0#~#zx|#kulC0v5}UPk z0NeG#D~q?19bQy(W9|(P(w17Ua>ntgt)o+Ft=7^CGBTRMnm&yfo zWp8Nbx?RV!yPn_YkjM2rL|!O)=oUDTpl=}y((tp*a3@NH5`(`%I&R;QGZs$SY}i>y za{l9GcwWbr$@6|qC%|T9@$I>Z`RvjwEa__9yU4aM*6LY?NA_u)?al(@NFJQT`YIH$ z^}egonpIA{>~?%m$Fo(_^{f^-ES0ci{0{eq5Un^I?QkeIk2@>G>m!x@PwdWUU(S(L zyhHUY-#ORL8Y;{`(JA}G*6j_Tq*Q6kfd#KyIT&wJO%UKtbOtdR(>Pds`LD4nHu zaWLFeuzN~kZfEG}V=qvzyV2lyS`=OqcZuh3^dd9J6872G%9P3lVqXgAssH8Ljsh$n zeG0_dR(~nDMOAhLj_qcP(lUx~0xk?h?T#JWtojqce(x%>8u}eGDF*R5P?uE?$d`Z3=w{a0%m_;aGTGmEswLz3KWNZ7tWn$h0)_hjukaMKI8fVQpdhxEP zUXA`ZbN;Y}^P&2Cku*KKjYL-&9YWBI{jJ>vrw@6_;s~{fCRGlT$AV$b@A}9~z}}NW zn*B0>2nPd|Jlm3p%4Ushck#VCea7v;nI&wSC403u7(UNo8VhH1@KfRV|JwMK#e!3u zycAJgbud3Qve}42QQnkabHtYAdD~vVmVsOs={@s{za;+K97oS@WGIJUv}2Z1H5gh7 zH4WTgxHfsF?ufI+;Tr;bdNpj{WYQLA-7k>(UH7sBVl^F4U_JCx)nkv@alJg|3YE>J z_^6UB!6uAFbI5Hl*IbLq%p4o3kyjH8M8g##(dQ>5CZbVN@5Ic_&inS0_qjY@<`-{sdo9V$&YrSw#Z}_4{^(4Ey6BwzHuvn8ASqh#;b1H()w5~yq-wchj zx!ydFY^Z=HHzNJv!sh-$ZZmUTRdPZ`W4RP4Hw4C5k?(`(c;WD(*mRJvfh%5drVZLt zpoA=k>AyRRfo;sOrG8KvWBPpVOROz{e!3|6irs&^i1(h zk`{x>{2njJc9^se_n%VrFd)fQg4FQqeU9M>^MP{lic=Je$78a<4NL?-ILUKv;ty%4 z>**`Evcm?r_s(~QyFlJof4sIOEJ&C*9qb=rIGCT}ivg)6V5}9afFZsa+rYZeu+T`% z`KilYDKiH8wGrezmuWc=~!66+BbQw zfA0S-f?kbv7`Rtr!cGL;)kT@*>DB$f>zWldcv}tKT6+F&olM~S!GFX*eBPa#1N`p~ zi$AUQoAPt}hw$%5EITPPf%zRNyfFGxNCS6qgrs8VrG#T!SU}S*ska3lVy67yu~Wj8 z#w-x^{a|=Z(B=pH;@b^k6_EVj6B4vmBNg0Eb3-2%KzsdKS3=s=2~dl$~A)M^s@0ndLIxGk4>65^wh zlvEpn$%SOp;jv|zq*jDT85jgo_C}UIBm%Sd*(%G=QRuALr2SM?yS=%uTJ~XY5}Czc zilYqB!HP0vSc7_`@-Az!Te+EyT=i6EQ=eJrNsX|g6minPeBl#otDv{H>p>yx9K)nO ziVZK~n8)E|D3$EQN?i}Y8&!`h1)iy8VQ=W_nxC2NTyiB1{|hQ(Tf}xeE@{xAL#wts zQ$yGl`0mTz)zCR$7ysuE^JNEPF&>!Sv1TcmuVCDdgJ_&Aj9kwwdYbSF&YdRvYn3r)%UfJ zNiOBm!AToH#wZdC@$~xtu)jbbDPp+aDCjkXxVmfSHrj%>$F})(vk3KL;P|5St|)5x zf0>2=6li1}@-S>TU}r*$IZz?&4#PN^EBx2+tosvQwObw}S>w6pDRiXDJF?E$?xyjI zLW}gXcaADu3_`#-gZQ~RfsRRZ9@T{RIL;&SNACp4O7fJpUS#TD-;661CC8M^+FY*K zd*Gp1(wmd_(YkYY(ORCjsN`OMz#XaHOF=P#Au;3>(ipWy6SO5sOv(t}c`43+_$gpW z!hN_|o-ad*b*geK`dd!J4Lx+7XX~b}Ag(jdRxyZI)f60Wfo%mPjXdmZU0w9OB5M>c z(+q=yGlz1Em?IS;p7f-fF1-L12z<+HFVij8LY&^aO5dz2tN;OKZ*)z~k0pPJ% zmRw*woh^4g$pbZt!-NQysmr_+6c!_6Utrm8YcQ-EzE0;$KOFsk2v;^y&rqS|EO(;8 ze@@FI&syvw;Q0ZKec#rV05Snqs$Si=31DkSq+?&jsy^o2Dp7NcJ*MIXMN)$VTU-UZ z$^~m0m;Dr5jMuo`(+C%=ULAoR%k z3gkB+qWcO*r+L9{IH&vdcq5*=mO229X{x;)gCb@f-_qS3r2_{5f?7=ea3j#D(bxN9 zdOAA%;3&y)bh7beS~N=Sh&Hb6t1`5fRo#&nUGOX(Wuma3G8sI{#|SD8NNmGWu_&3I z2)2e#N~NTz>@Vn<_%EdrXKF}4PF}94hd5Fu1j$#Crsmr$EB~&Hwt*mb`iF+r-5w?0 zko5HRC5c6LTO&4jU5%YFCZTGj;~xEgH}}JLDbAl=7j1RL{nB$_4q{^wA|fKenfMNY zX@!MdPkCCf@NfriQtF6sGNff@*=uIl;T>UF={NlLJ~iaVibrE|aZgOOod+8;U#_a4 zYb&;#>Hu2VhxOl%rKYl&}?)LpAcj=pf z(9+U+ImwR>OiN+gkC|dOY^0CcZ+Hz>*=c&UfnsaBiPm^lkY{Q0@%n|uU4ASly6pzC zd01^Q|Ap;&J|)H0Xu^C&%-Dd*iPKoLQM%0xyAF%p&(i&JDjczY0Bm7*aldKEzmvV( z$OO~){q~E6^p^S$eyq|JRc#ABX)wUBeoXE0JGsZ}YmA`IxBO#D>k$AH;(lU{!3Sca z!8>aczAT*-TO{jfvAwxu{K0{tkdTn;#nlTF4r<%(uHM7*INmi37K^0PK}F&FqwVK3 zH)#ZSJ>E3~voPFI$x>+jOFeun*a<)KMr|Ik{PywzelA zgvYPi7w#FY`}8xf;rK!N3kf`d0vw$Su02%2)kAv>0`KmyI=S=0#g{{zH-}0ZvFaS+ zf`-4xmKX3%&dnDdWqRJsu_&+B!_%6OR=Qf@o4*~%%t0jsAVO~~=s#Sx1wFjzQ~%-( zyGY-9E`{=be_>>p*5^20(-R-F=EhC47d=##dyAq5UC=;6agVRMaFf;(s(%x)X8RGKK^pPnh@;g>x7R$itZNOLk*eeAjE+6s}By8P8ry#|4v3# zxs%Ik{uAL8AGw`V-zL?<=)|tCT-l3BNtgr;g|r8BF7Vbg#k=qre~nZI0WtWRJUjCO zUiX${mgTzZ^zVkFLZ%V29^d$h+67@su-0H<9xH2-%l=4}q~+?Xmf}2oTje5QNWPu*RxFyVj4>oM=q;B)sZe3RWuyMXGTd*aQIsMa5yn9A0)?#;6vR)OE`3rJ=@qao&D?aC20nWXwR2qKg^z{G$_X~-{2AF0#e#J@^gf<-E=Ju?snYz8EGO{}{4;qCWw zhi#fR|4&`-7#vyHt_x4BiEZ1qZQGpKnb@{DNoHc(wr$(Cb$VvMd!K!(zOO1jy1KhM z&+1z1>5KOwu{GfC<0s#x=KlGt1p~PpvVAa@5%>G9gH^LRjbir|fx6MB;22R0uGm3l z-iKDV`da2%(ky{o<3oAijW&bC_r(xveg=5!X3renFZN|Oku-Pw-Aj3zw?XdJ7#3@;{mH(kx0FpxR}$CluIglj5S*cwAvcM^Tr+biB^?Q!>rXI*(+gPMt* zH^u?l^VK$1oba~GL-e~wsg^D_*PKYdm`Qnj4g0eW_|^gLS1p>=_g`CaH$_K}s4|In zN8&yFgY1ehAafy+7Q2+r&{N4nEa4J8JC~N0X4sc9Gyct01G z(%ebg9G_T-i0W4Tfqnlm3)^E4cg2A+6W04EJ_hC>S6?9VrF)+0E z-r^%=*T;RdQP5g1AfhL!Vi(B5+CkKaO(w48U`|haiSotFq_GKU$w1D9Hlw+Ts^vQJ z8q86R!6^F-gFMX{x>`U4w%cvKKZWq|UCF_l-56io9~N1D^2MbdQqT{^VPOA4DbLT(N!QR)K4514cjKur zrK<&A0l0g{_S1yeJlhfSQrA}v>p{qHfG}Trf4@a+L++eo?QuPhC#iLXd$ysu#BtCF zR1|k+SWM1>#P5+=5*#8u?a&nC!hbVa&A}YF_+L&d>do{uodu%FNw*3l_LEV|K zIgRMMI7g-cwk_{V;`X0(;8YKTO&-t1ovvWt*@*WZtJykH-GTumG>-H|%0&^69|RIH zJDg)Xu%hp1O!ft<|5}<-URPlcK^mk8V6e>dBq>b+$BAXmMR2BlF z=y2QVEC)mzq>ydv`#}<9YfjJ@eFzJ25*QMeftcbi5Ef3N;}(xwT-wL3h(k#H`5k+& zAbFo#WT76v7oiTg&$BL*`pRf*e)N=T2R>0hjX!ic&3>Q(CkixO?vsO|t_)h}zYFuG z9Xns_l^^Yyt@=SvYjbbn(oylB^V{U2w*ttHcxI)A8bBoDJPh8#xt_CE@>j;u>L z<3B^>7mdSxjwUx}QR|XhWsQ>+LT$mrpc`jYPuKX>C^N`nV96s2#WTqJ9!hMRyTs4u zta9u1dE$FV-Ct-*L~9H5ioySI%!erQeS@J%ZOzJndiz;$*t#5@jORs0`ymQc}=|bF073emhE>9Dkr{x&j3cWp`PVu7~a0 zP}or(dLSOCN~0J~{VvwNo-nEn=dLzQ39>=bC6~|DFQ_V?KX|^ACb4!#b9+KK&zCi} zp+}cAy$}wHG#ZKc9H7np!!1DcET_NYCj1|*=$bWjyKk}~#n#~!jPBKicOc$+E_EkD2-CZd> zRBfjn!R0vk*)!O;oO#DW2aa$(d}bW4`$>E*Azzs2ED?Dirs+g-s(fPr8^0gTeVuo! zL-9(&Y#Wr#NC4r6F~W=8W?-p%`Y&zvA7KELeNSW-M6x9>;&>sZwER z0h)ivi3p!o#%M7w8jeTnMv?B^AW+VFgr?Qh3G{x!h<@$(2I?iAIZ_{QMKRS%bbUFM zArrAWM@UGZ<|RG8VWA33B+HOJx||x02$^9bOZ}o@)7w~@`V3+HQz$k}^`eTDXuYBG zJrasJ&G%fTkx@_m)+yc*psP?)Z++BTHaXDp-;A7ZZCHvzZscvTi#aiH(J1;qdRb4f zFvZn31m%BGb74696OeOZIn)!tv`L3`_It{UW3MRrZ-8RKV9XVK>#&9S&grxBp&Nw& zBUk~Z;n`ZZOn^B`yI&_|LQGBr#1%ZsUo=Y?aQy7bYIqS==Z}goA)c zmIfR@R5@EsUsaJh>Ilo^{jhbsu+2#6`)Iz0{ zcK6n_EMR?H)67+X1~VrEaS; zB}%wF)<0FkfAQdC1*DIjN3<;buXjM9hDz^@hknD#DZc};GPEt24{!sC!Upj5aS-f+ zN2_UpTz{A%mkPsfx~=)!0ISdbT6`HeNAV$Me zO@s&QQ}A6$i2XPb~Yu7TMVk1{=zU#Y&h_`7G6FGQQDmt>l}z#yX~*b9iQV4 zRpdu>gW{l>&2R?q+%;E{YIor{mL}(|4no^Usz6V6*s_l2bAze2v*}qUa+mFS$ui(Q zJEw9Q+#8|+=^A@6Doitd!RdizPW=aRYoiV%9Tc9{AeXsm#}`#4;uk$_IikW5&Na=a zJ5K<~HYb+N)3brf`zg(R8$5|4k_5BrO=>XY^Tl_aRfeovRcdu->Ab2gz z2CZ0F@VBz0z2eCgc;Od0^SA1>`>NbD2OpZ?;>(0orJ`t%-H;UQ4}s0K44kvxFH#%? z;}=8r@>USL---IHn;ZbIfGD-{u(x8E%MA$^cYhTDv!)s?1!W!fVu}_^b27vI#Q#(vjUyNO@uEta6>%y(c=r+xybuCE(95ybnhvUEJa|-00=wwi&L%b(A?;o}nMEL;dUD26BI0#j%%SMr8V) ztK-Zu&>le@xF!Cw*;>x^q#9!Ro7$XskweQ;@~&*(CA*d$2PrivGEu7-Rs<;+Djh2X z9AUi+vRZ_v=`4Z%T^aWPbpAe8+-MSuo(KgS%sYywen%5t1pEF{gebxwA>m7EGc7}k zWJ)L5RcQ&Kwk4LMR9@CC5%e5N%Z;=O`@v(3)I!VVf@&daS_Em0xdckjsjKFiYFWNm zNrHp?s5_##Epk(r_J){n=e&)RaeK3c2_Q(NOM~G6*i=+g&;zu@iZs+*nm)BU@9#5F zsgq9^BuwK)S{$*y(%5jsQ#O@%Gbr5101+y>?+bJuq=(%#K81k-3K*9Jf20Z;CnX^a z-{r$#Eog1SQdF?B3BDt%lPn;A0~VCVX7R#&cuSG&Gd#`t-Le&+1}ub$?+VuKze7lB z(@&2?fU-!CZnHoKwiHC$j*Q0FA86ru`!i z70=i`Snao&3eT9k@zODd!ia$->-?F0SncKQ`pO*)=o-N)#bl7T@M2;>D;03frv{TW zAp&tA`3-wMtd@+EOUx{JMHT6ArSNfMFBYn%R)uF_v@meC|6fTcoHW0_UF4ZFX0A6_ zU4f&Q0Y*1}a%h>foQ&+=Uy?rUKgoK!Z7NfBQ8czI_Pk-9AmU4>?RRW8F|;x9>(7hW z5U|khA4MA-r*i$X?khzgTAIqR$bshX6@b2K!K-@F5RC*}HGzvu2hk;MT6$Ej73Sp$ zCv>5trDdtWQAAkSwFXHX7CPC;xQUw^#>dA;Gr(myLY1J{j=Oy=s9p5A&3HzD*Br!y z65LKiLG;bzpkBkf2US+u^){f5@$UQuI!RuJr|}0T4XzLh2Di+&LML6qK)_lMX}N?^ z77*;7dPW31sBF9Bni;D(MgKbNdx4{5Wu=1Xv&yB!0QKyjkr!6N;-WK@iDB7KR>`TU z0h-{AI@fr>hn=+ z@Q3bl?;#c|yTPyF|Cd3r4cHq5LJoV9K4G4IX$>D6mB$j~o;SYnG zt=l!?`as6&Gv(BEV1X)xhIZbSr-5L>Pb+pL+0xMU6<=_A1>nvLSm`}L zVZcl`Aggr){h(0z#!v4IqFmeQZ!N{F$`{x!(|BhjP0#d7X)At4Si8BI5G}quU15X4 z#`G4U*#K^Rg7PaZ3>5gnWZ-jNm*3xIIO6yD?2&VS4A>E!&b5~3-9(K&X0-N5DYxFY zrdoYkdmfy9KP*Xp((){w{reA7b@nx4?XZ^>+h zgJ3Cu932mQ8D?E^p=>`d#-k+(Y_b_C9y8lsamko8OTf5Q-xE46{%8H0K#z64H`A#< z*bvYl%Z{q>0A(84(NruF&P#FkKdAuVd)ltln(pq;DX^T@zYMZKHA|JSNJMkz_D8e$ zK$NXshB`<2`E)UdpxV!6Qe1v%%j2E4zbCaI-FU)T027Kq<@V>^)1ABSDUV z;u0584lCu^@Vs#JW0V~nq;pe9)ogZid&pzkgeuFw z(Q+Wq=E&S5!s2$<@-%}n>(}VHaCY5j)cP53U{m;Yv5UI_yqatzFmcxqIeFBAot?2P6I5PYA42P*`neq5| z@vrW~Cy^UJlvVY7(yst-A(3D9@fWb~T;1R|Ux6m3#VgPIRT^t9tBaha6ui}x37;<+*4DuA~r9u=f*THm~ ziUA5r3$ZAw8_u;|l6ePWl{HhE2E`S9I9N#LU{Hys@0UZ;3vY*HdiEm3!}Uh_0dE?l zNOR!Cfrz`u8!3mc6w=dZl_@gBlKu#i-$w_zdeNC-^qm9Vzj4}xUGP-@?W)({F_NR+ z)aU1I(S|c`pDMt>RnXI$P9y7^Al2x|l20%m(q6u;X6b6g=3h^~^#4E`dBx8HiA(~i zW6L-B

|o5g&{DrX4M<6Wzs@Pc-S8(k!u3z6GdrrGwN_*>eFl`(qr)iN7J#oVw!@ zE(mA1@g%@@Kau3*!IuTXye$Cf|0{pu5^=QwKb5@{O4-2+G4nY0aHpRGlM*geEyX43 zJF<09uGL<*!50CKpo?Lv{?RuFfdoNGyDZd{3*wRr|`iCp>ogVDwx^t4@VYGN~sa9%&fX z0)_ILn&u>HEi0~Yna{hH<@#C3*X0*Cn_NAi%c^CHcdhHMpNVZXKR>i^uHb0%>$VoH zxjjw6l|-?||f?hn2VJ#xJmQ(wFm zyy1ke_J~*!4q6#3-4ViZvu=FVe|sLaGn_}pL;@%O>R+wYrf>LM5$F}-KNV;S^3O%e zI)3@}t{n94@zR5)c{YE%?fl0$_oDl5P^g~0Vg)5`83<$`{f&$;BEWR{c0yQ7PDc8gKbUXb7hh^q z%7M!!G!W&d$66?9l7DqJOiUq~quImTa=~^p0H=|HRAP`(uHUr@KNqChfgvH$!?MGJ z&GxKSPjN6lu+SA6*#ah3W2YO|UygL&3=byLd`9q!XJ$CZ@wB8H{s6j>rRK58cz%lm zS*cJ`CCQG-f2GlAxIHT%1&CFA2-^UpR|CC#ENdc?xnm5M0nI%x>xtu9xy5;Q~GYeV@ zXpT*|Pz;ZXs3I(f4awn%X_=w@{9#I1ww=!*`ZFQqxQ*FjINMzTXSzAffYhycn1l2@ z;6$->?q7!sU=B4{EfFy>De-8N!ox5QIb`%0bZgsnke0(F-M4hU!r)|izCIY=DnK3f zEhk}w2aR7V?)ut#Q$`MbQf(Z1q;U|FhuQ4JKW&o;IeQ_x zKGo5%CYyOR6xrnlJTzgW06wg>9Ao5;NVuJ^Fw7_kG!uPaOEoW>!$}>W1WmfJi)!%!GvEO`t{Sj7Eyv zbqsN9XV2D(-%z_4s)RPCgq@|9QX({*R)O{hs`exGYB)e;NKI6yxaLyDqLy^|N$nY) zi*j0D;{9A9Cd*tt>lRf9Woo<-?D3@Km^r-MEM8jIG8aV5@=By@-2?TiD8})eAo1VN zO=#NI2GbWOglgDDS%%bdN2*4|`AP<9=!WWbd0Dx-xgN9$!}ub`YcknOZ`*gT_Dg;i z!rUF1_0DNCNF(!oa&=XRZ34Bi!L4s*JUsd69bkD`KjK4YJHwdUZ&=#bV*_NC1u_1F zCQ3(2j`Y{m$!X0~BoL1WYkbJVvT!JKBe%9q&Ms}fot>7cAdg3M)fSEw#njP7A{0&s zw|S}akssKX7j+T6sWZYqWUP!n!d@#humAK1jMm_7Ir^!0gvruJynh)b_w=&6`SYbu zOr*dIb)kOOn36XlRWe0fORiffDNP>aHrzuDYbv*}5);Eu(+zJ9tHsN5!!D@7{(uSibN%$Y#DIexZpj&xORu!_8g` zw54L$PN5PTVVyxal)2t{Kti=<>mA{8XXMvt4eYj&Js`W*FTYKc>YXvj9Yn48>x}x->yJA-8UJ$}r6K-@fR6VUV0tvlL}DD6Ym~I z!hL+R5?Y3jl~ZblX*fkW9};GY05ix6aXlollBw!ovv~%RO#|qfie+9+rSp>PlGdbt zJt&z*ids@mJx*stOencZw;bsix~Y`XOg!ZG#ZfnW=OisU+_ZQLGLKSHbg#H?)90~2k^3kTe)AG@%o8~UUro8ZJ^Q3~jaG8!GJ)EopZw6C8wcuuQ!|&&QFG})% z-XJTfE+`ZF{w@5HClM>CpNyw7&$eBK6z(wr0M%dp?%N?JGDZ<`!S3<)3Di)tAJ4Ze zk3@tc?sG!_7OIVYP#0E2#jspO+^m&vTtkK_xIF?<%1v0v;y;|^XCb+bp!c+VmmzKA z^3EuXB9V5iH;7rx=c9FGs*z5k?Of~%4?_bikS-1JgoTCc^`Gb#%Qc06AeO73AKa8N z%BofAU4;L(lKx>HB;brfm*s~G&23u{HztMJRB8v@YIBhautam>v#-f(t_Zeyz zwK)8PsNwv37Kv&3 zDU+C?KD2K03#t$bRyuFjR0g?MD4tOk$wVe`LYh?!GC#55Uoud%I7xKCS89_$ukQN| zOMbMp)BrJm@j&a#ev;l&xszXLJXe3Os=o!&-vT%2Bf`39{<+XXr}K9?upDHMJD1QP(7c~2i*7%1 zW7)?7<(BHKWwr2=%W^>_gk8_PAKOix&k!~ACUhs)!YD27*7uYR#fw+lAkBGhW&gwk zr{)5tq#2_PidFs-&iIX~I_+8v_|_|hSo23hjWo(ouPKYIsLpycQN#!Tn`XxlS{s6eL4Yna&>Q3!wgW9kULgK<<3-@s=834gBk+f$7gdqx^|HIioPihf95o zg(Fv$UFh8GOd+AzbN$zv{dS{-GT(YxUYfF~y0HZeGKysm>M_W3sD4M+PiS8a#@KY$ zbx5)W<$ax-MHmttf$#Fm?nzk>O6l)|lWKP9fkP}~b(>*7ZHwJTZcSgqtb5v}P&~98 z$thnwO3K6j?=T<2B_8%a&D@7~eIXo>SDhbF*K@d2Fvh8b?z+b>Q`a0MR;vkruEeC{pnXA}F3dDlV~NK-gT@3DQYv`Q3Du)|GH%3p zn^QTV7wbkww%3{%EjuCDpeUSu@pbwRJYB|G0BNK`qbA_`=ea@TWywDQHJ$w^^uS)# zAj3_Y)qw8ND3T#1T(F0M5DSpfyByRb3_;Xw?8bA@Tq_DUOrS^1s5L3M-_0C80PM*| z?Px2sWbKFt*+;Ldb53do89}|QJ1n1!HXN7hEl&Sey!7K;ZwR$u;$suz#kUEon>;f0 zD)lI7UY%>NIH4TCR(WF6 zXp_2nS*}dzqhspC{k;dykm^T?zYNO;A-J#aYp~+mPEv6-K9gxBW`k`*)-!$B25Hiv zY$b~`++uCGJRNgJGb&hgx7Rayj{pAJr1NX z9D7ItX}HF!&5*zIOH{q)QExv1oR2%L)Y>}f+{#$tMC`T$S2~MDF24BJ4I;|oaQNW6 z$NTHDT+R#Q*~K(WyAdE?ZQ~E9Zkb5=JKblCl>4KkLS?K;POm#P*|LXMmf~1%j!ECO z96PDHC*|YvqJkoJ;y0jS|FrpD(e5#@iP5o(37Fr))``hwXm77j99na#rjz-;S$(kv z2qWIih~vj+Xh5@BFEi}@oFdu#@BWjV{S0_oXlqU1Q`}YhJSNc;Nd~-a@1v3$MhX~@ zQ8iG!)s-;mL$$lpLSKk^d^SrH4j`7+oMK?c6oF{jTy#W{MpjZ%0-Qx15TjtE&Gj>X zP_&3j7Mi8%|Eu(*jLEtXAS~Y$Dfaf6E+DSz5AjS&TlQ@taFjAUXVyzPUKnv%?fnWt z9CeW=$d`sQB8$ZONmqsP&7+LttWPb zmd92dti>ZjMuT0al<33inu{?aEh+A|7p4G(Pmzx(fW7D8#woX7T_TNid$xi$7&VlA z_MjjO_l4z(*Z8OXuuWoTM7Q_Ip_~SLWo?m=Nn}-}F_RJdO0+<+vasTXA1Y7e%;-Ne z7UCGi&p1}G9oS%b>B-&RIls)1qyMrh9h#JU_DBlU*Fq9-H$K4IXcB6(h zDrgEs2=BTnO_XTpok6AZg5oNl_Fbz}(MVSoS7#gXV^vJHSqvkJb^p#aa4}S_+t0WI zly0-d*#e4WhvM~Z#3mOjmZiG7zVwib?}%J+*wuQBnp}kQI76Zd-0B_Z;6Jyo#M}aO$2vC9v zQ)!1aOAZzRvN38b5p-;A`-9TxxAq6rG7MHO>N{*A1`gRn_MI8{=Jz|(@$q(lr#!~1 z4bQEQ=PlRU%{Kh5w>L?4e5K7^wOdV315C@1l4`J{!Bj>bAGz>p)r^owMt1k|4jr#v z9U#^r5$|)m1|FAow>BT%B{%6Q?X)#HJ~dsvE6P;rRE@dZ)pd?eDP(RHjn za3M`ev>@4{nxYRMwqqd_ zL+oO&(kTsRBY3~1#3xy4@>4r>J=}P&!E0#+^T83P1Z}b44_EF8;>SOs9#nH*i%w~4 zS9Dn0l~Fz@-lDqC12qeB3B=^u$vk0t0lgV`Z&Bzlt1$Nrr(GeNnv7if?8$0h{;qPjQ9@`0}sDC+TOk&ibTJksl5OiaD;ja2(42RmjP?(Kpi zCJJ_WLky~=Ud=2suyvmV=_oBJbH%4Pd&JNf!m@&d9yULY%SMCfN<#h!QYYbihP^|H zgEbP(^$&G7bxoKDn`RHf+=B}tHPhAHp&i=2Uhdvdo96#|Umrl_2Q;R`{I5nvBoXRB zJ)bTIE;rgX)Utqt`k58ko&imIdu(!qY-|&Ie~OI!7F86;{&~948O&(0{{H^*^7li# zMopt_hKfknIjF)K2hWHeo8&gFy@&7p`=+!^vi;jEKEzTtY^lJupD8c;^5rbYrJ2{yh~$O`&1|z z+_SgqTnXLTkskGNXs4$7a=YSq++&DwB9Bq`hX4MZf&y$aTs$3K#wp+>?FJfW&>`T$ z3l0V})`BUr4y=a4nixt3Rs)AGXSZlPL2z*Q;q(rJBP-_?zELM(OAN56bh4dDjXx#5 z-t;J|EVgBRRYky@iX7nbjWKK2(8L84HceAS`Rk!rv3YDAP+h3TYsYWA`6p0DJ*uAu z%(CXaP7iLON)ajTd&h^SuF4k@lox$3sgXJ5>;+3xjvfy(R99-WP>!_CnW2He0UGue z1%M5k2szfUI$XUqhJczG`!I+HB@0_zEGo~QJ={bnr*FwTR@q^vyjx9##_f^?ig1pk zr5SFtbq+Cr$AopKsHN;|4NcaL%nnLhKXnO5(o7!Aj@3k}%b_3RvefoS0j zw0J@+ZWs^TQL|SxyX)QIL~{7(<}PQi8#i?)na1QE;AS1^WZ!9DKc}!11h1FM$HliJ zd|3Mj!fU|J;Gi7&EXxC4m$!_H)x#iev3%!#Mj!1!p>q|6=lO93hYS5^+8>z788LgK z4g>Ry42iPHZOx;pTT=Zo8OnpuHLBnMmsoeLD1ZPXr48s|?>he0X<<3uHRdm{8xz6` zTl(>vbh*6QUd@1-2u(+iQn-)Bq1D2iJnPk(85WEIHgUSHfKp<#GJb_rj>skkd2{aV zdWW7WSl04RFvZN{(M-l!6nG0Q(<@!F!!71UWyxxlia`- zvuRhW1jypH^1H0Su7wnkAdPt`XFh|rpud2O9$J5|TC-Dr3;-p9>2&V2_a_l33ZOJw zf%R`+Y6(dSpj_(%F>-u0B&6kb>rxYdyDlL~0q6RCL5KCcR3-PLfL&?<#U`dMP{PcK zRD|F_2>AV#M8Dm#E^eUkGcQ79e-{!uPq{lSk!dym#(kmFK~Pna2__A=m&GB0O+zN}ENxXe z^eAE?j8TM;D#EwhE}K>*3ijnlfqL+8p6S<)NE%sX1qOhc5@oxekf>2WtHh*lYMCtF zQj>K^Wsm3*x=h?JQd9e$ZPi{eUuv0g!efI0gy&h69D@uB(XXBK^KODWfhRs+kXbJRE+~{e_D!_jx$TKC2`oFt8q(Qxu)IP~Fx7ZICKITk19j-x zePJ4omj4kzHbO1z%^h2C#Hs}R3zH4nqiF42T5E62TWV7j*tp0w9KZ=*m> z_YTTf*OkGRPjD}8Ry^zUlyso^!=jmq-@!e>OPPx$V2zv=80K^$8B8@TkXJP9dww6j zs3|#O7#2nIPQ*^b1tt2sz4Cxd&?^*vuAeE$+8DYuF6M5oV^~3c<*2bfhDbX#)>jK- z5J1g$)GqOfN@aE)JrOLh#|Dp4aS&d2ld>uqoU2| zvR_BEjQ18Jd7@Iu^auJ(tdTcZC76EX5pZL#9Qu2 zb=%sLc)Xs{L&>42*7IasfgC!42%)D7lG$<<0>yW-w6z)s>L8IyzI= zTTm}axQxt@y6rvT$v*sb_kz#-k?J42eAr<3Dnnl`Sx28M@Jd(~BY7z}ywYF&7dvYh z)*G>)?yTDom^Y&hBl4f$Wi?HrR1cmfqSO-ucdn7miTX^J zmhOD*Ly?fa2g>4Cd{N6FpLeG+S-alhZ*}af>%}v2c%KKpbWQ(%?}rsZJo zjM{NnOKd1(fxR%U1zztk+BqsaOe>E4sE}M{l!fD0lp~RFoM)V2G7!cprY>t!_cr6+ zjQ9Aya6fE8IU-`Aj@RkXJythRjSQ{RY6UrW+B76@M-@(ben0)d`Gr=iB&8q%dblp) z!A5qtYm{|ik?C5ErA#*f_yQvduy{}lq1Yn`F{d8bDJPUO(4t>2XOhXYTr9wa`x;5N zCa01(yo$t5_(f(~^5g{6wYljHR(=Y64epi1Fukq?_;T*K;bsaxRjr1-tom2ARLdld znftXdy(-?Ly6m7+0pG2y*?uDVz$rlz;=F_=r>PU85DCxZSU7_bdjpw` zS(fLK=2d&FyDAV7Y=DKQ8UocbgJGrhXUZ@VEOXie#7O>dL#CMOQ5vl`Q*TCq(EaM< zw0bg>t`aO+Qc>Za%Mu=iFH1?cnn}j9&W(+3#?U*?#=yM|DyC^S9K1Qmm;i57kx|X^ zTmF`ES$T@P%oMG{s#yOJC-(KmCSibKvo=_ulQ#i)C$3v?hv$>g)8&RO^=%IX{`T#` znBWl2GYdykfs5N@Y|aP&E26hK`{&t=49_%wXd+#{iMYxOHME-&0fKTHj#yJk8d(aV zM`;0rVkC}ilh&UTHM~|HYlnS(#qL00|Frh@mozdK3_j-@TAdGP^ca);S&D2901~+_ z?B3{5@{rc-6#-H-hz7O-?_BCffCs#?%mBbBY%)@k5-8UdfIZwUnk0mx+7P;Y68|xd zgjtrRU0c=!wwKS^O=HE?(iIz8c%2FHwCDw{Iib`BZkUsjUxIa4G+V3u8u`@ApW-|6-T35zAi zlQ+q~##6Y|vt4Weu*WVdQz<4&-o_NSEu%-rc%kwStu^103{Bo3qGOE)`mq zC&a`fZ)YghgoOJA2bxEu>GVg;FaCP;Ybz4|4%^LkNqLr7dTlAfuiMlvgSAE*xAz<8 zjFfX-P@NpUXE`?t#Ed^GbC9*_v7<)|Fzx zc7!{|R_~N|AqHg?;r)H=r*Yn2{C@$!|9YA`)q-4-Oh5_%JdE`tLxc>k&j7hYN*`gAf2<3mE zzkA1ghD!@&EFgpLX93*5^TuzbkU>v<7teaf4(s3$rr1dKbFO!{z#VK}1MH!u3+(BE z_Lwf~L1&K+*Y|zVtIs0cVz)SMvd6u-p*3b5k<7PG9DtD(v@KEqa6b0G;k<%;-~Dc{ z0N@pSVhaGib-eozme<7+C4`+ntDBl#D(0x5u0}wb0X0x$U(=>*xu^{kQ%EpK*sppjR7Vv7p<{v6>zW! z=he24V=IH~Q&2Cqdg#@vA}YsP>PLX~Zi8W%@m!YFf0rXbKt^u|DB?57daa8h(Lgs- zY~Ll%l6KyeFvw;;#4#&&hXT9)u;)WcH2_>V_G;ZW^aV~RoXB7z{?SST-)-}flAJ|= z_))Gc?AIswMbXojuf_~(-;a{VHK@zTknG&t@Om695le~P&1q^ha} zRi->mcTGpm|1n5Ooz~3!3-G1S?--k(krKdacg+i{->}0B{i_W#7>o!>7exlm`ddCF zY36F3^)fmcHe!XZ8WfDN-0flsT1?m7>_A@tR)Du5Vr1mI_TcUM9~*pbDpAd$u8112 z5?0{&2{ogPa_?S5qnzm^acQ182cK6~ll}@R>oDm7<}SP*e3zGJlLhW>@g>HFBDg8U zX>-#oO4_805;{;~IXC%0t%Ym{Ai5}$t{&*(bTY22yNh813O%kq$Pj=3rsT}7ds5Rn zi>d;923a^fp5_pX-nJ74iD5ueBPd{mMe`1}h__$pFGt89T{g$R`QH=)2;whAs7`xr zO6ww!JA=Nq+CM(VPcrh*PCSI%`%68CWRT60(`3lb*P7tDvTVT!`j;r*a1!uC9dKgC zmO#f^Ff#uk9rvq^3$C2Gi1ctq85tP^I1ifX8orNEj*c!E8(rPu_e;XJ!tnZ_Sul$_ND6IKdo`x|NoIr<+;(RqTh<%KEGN4DEmD-k>&$#%XLrj zF26_cVkf7YLMM7?El}B7L zSSQOdsbz5-X7bLCOthPVc-F4?Y+q7><{=$Tdt4sXMZWAXN46MkiJa?%w&7y zBgVX(g}NG)wjp`s;SF3E<7j6Nq9PQAclg%>hzpi?uvz*t%%XaL#;Sry)zX@;SQ?Xi ztOJ04ux#cI+A&gQYx!3Uv)r`skgp@ayh~x4#&PPMVr!2Lo%-9!Zz;h6!m_8SJ5$|H z04fr_q}#XI;n@SSahaK6kq{TRO(!Mr?uC`Pqytv7t%?VAFAoH`Sc{NBYqpCNkS2=$ z{p10Lt0D9UOkqnBg#lZFU0x_|F~B+y}Oa;djV~--B3dNv*~`D(-x3wxbAt?(R|hUR_*=vbKPl*S8j|& zNS$fKotk?45jzGpYKU_A7{IZ?@@6nnuxM#$w)^1uRidJYjF-O+gahZObYD;(4B`8h zV_;WB!Kxb@E4G~LKn%@sB?(Dy=6<8zp4m1sQu7Djp+j8?{vs!mLxF4nwuOzsMDnrQ zG1euD+T@{u3(+gK+9&g^gjtfzq(HC)TgO`e@!R`Qyd~vY&54u9*#j`9uCI8hM`s0U zjR+Gyl^(VS$8fN_)m6Iw4<{usD@anL3pnouZ`zF$W~Q&pt%B_h8W@`dP!sr2M^fkd z>~Yu5OoE~%=q{sUP40_xhLZA$vfSDdy<+FwT z=lqCp;Vvz-bsAu`lfUOvQ~7hv&3Nj`!Q=0@V*0RmQ`SQ z_+lKiq7cY{doFnN8v=r z18^gKajsc~*X6PM)>fIYb~c@lb3v7kIl(0aTf=b0%&u2e-~_=TqK9u zC$>uY&OjK`bd7gmTqUF^3Jz}2W1Yo3(F>iD7hud0n1z-wW{fy5)HiZD&9x3Uy zIzz$pzgPQ0Pj@#B2wmfK0D*(;*Lh&hH4qVx@XX`uKN?U6YmPV{Bhyk`#+;%gAxV;H zD*`piH&fIGw6t)3-4g^doiEo6E7W6QrWn=U%Dz4G05I4i zhi)z8V9I5OD;yb2sKQS>&}lpm2Men=8k=26chKc%%Jhh<+G*ZmBYY${w;P<|??zB0 zcysPy_I4vXhU|-L-3>d;Od-jzXAeMr%Pmgicy8N32T((iO8>PbRP=B{_lNu_;B#eb zwEq=(yv)m-z(+JNjYCW2D_r5H9th*IL*lDwP)7;)XxlnfrBh;Pb5Ve7SWzF8WGqcV k0NzBJp-EMO3igRlY>Vo#Kk8=i_m;1cqH-dYLIwf<2kI3m*8l(j diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/img/well-known-core.png b/examples/platform-specific/cc26xx/cc26xx-web-demo/img/well-known-core.png deleted file mode 100644 index 93552e502e404a2eb261e138835223a881ae0a02..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9102 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 z Date: Wed, 25 Jul 2018 15:04:11 +0200 Subject: [PATCH 296/485] Added SimpleLink examples folder --- .../cc13xx-cc26xx/start-demo/Makefile | 10 + .../cc13xx-cc26xx/start-demo/README.md | 14 + .../cc13xx-cc26xx/start-demo/project-conf.h | 43 + .../cc13xx-cc26xx/start-demo/start-demo.c | 425 ++++++ .../cc13xx-cc26xx/very-sleepy-demo/Makefile | 10 + .../cc13xx-cc26xx/very-sleepy-demo/README.md | 91 ++ .../very-sleepy-demo/project-conf.h | 55 + .../very-sleepy-demo/very-sleepy-demo.c | 424 ++++++ .../cc13xx-cc26xx/web-demo/Makefile | 19 + .../cc13xx-cc26xx/web-demo/README.md | 185 +++ .../web-demo/cetic-6lbr-client.c | 204 +++ .../cc13xx-cc26xx/web-demo/coap-server.c | 167 ++ .../cc13xx-cc26xx/web-demo/coap-server.h | 52 + .../cc13xx-cc26xx/web-demo/httpd-simple.c | 1349 +++++++++++++++++ .../cc13xx-cc26xx/web-demo/httpd-simple.h | 101 ++ .../cc13xx-cc26xx/web-demo/mqtt-client.c | 925 +++++++++++ .../cc13xx-cc26xx/web-demo/mqtt-client.h | 71 + .../cc13xx-cc26xx/web-demo/net-uart.c | 321 ++++ .../cc13xx-cc26xx/web-demo/net-uart.h | 48 + .../cc13xx-cc26xx/web-demo/project-conf.h | 79 + .../web-demo/resources/res-ble-advd.c | 114 ++ .../web-demo/resources/res-device.c | 212 +++ .../web-demo/resources/res-leds.c | 111 ++ .../web-demo/resources/res-net.c | 130 ++ .../web-demo/resources/res-sensors.c | 301 ++++ .../web-demo/resources/res-toggle-leds.c | 118 ++ .../cc13xx-cc26xx/web-demo/web-demo.c | 1062 +++++++++++++ .../cc13xx-cc26xx/web-demo/web-demo.h | 234 +++ 28 files changed, 6875 insertions(+) create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/Makefile create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/README.md create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/project-conf.h create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/start-demo.c create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/Makefile create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/README.md create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/project-conf.h create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/very-sleepy-demo.c create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/Makefile create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/README.md create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/cetic-6lbr-client.c create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/coap-server.c create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/coap-server.h create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/httpd-simple.c create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/httpd-simple.h create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/mqtt-client.c create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/mqtt-client.h create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/net-uart.c create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/net-uart.h create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/project-conf.h create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-ble-advd.c create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-device.c create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-leds.c create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-net.c create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-sensors.c create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-toggle-leds.c create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.c create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.h diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/Makefile b/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/Makefile new file mode 100644 index 000000000..ebc6d5f1b --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/Makefile @@ -0,0 +1,10 @@ +CONTIKI_PROJECT = start-demo + +PROJECT_SOURCEFILES = start-demo.c + +PLATFORMS_ONLY = simplelink + +all: $(CONTIKI_PROJECT).$(TARGET) + +CONTIKI = ../../../../.. +include $(CONTIKI)/Makefile.include diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/README.md b/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/README.md new file mode 100644 index 000000000..af20f6e3f --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/README.md @@ -0,0 +1,14 @@ +CC26xx Demo +=========== +This example demonstrates basic functionality for the two supported CC26xx +boards. More specifically, the example demonstrates: + +* How to take sensor readings +* How to use buttons and the reed relay (triggered by holding a magnet near S3 + on the SensorTag). +* How to send out BLE advertisements, if the chip has BLE capability. The + device will periodically send out BLE beacons with the platform name as + payload. Those beacons/BLE ADV packets can be captured with any BLE-capable + device. Two such applications for iOS are the TI Multitool and the TI + Sensortag app. They can be found in the Apple App Store. If you have a + BLE-capable Mac, you can also use LightBlue for OS X. diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/project-conf.h b/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/project-conf.h new file mode 100644 index 000000000..17bd2ce29 --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/project-conf.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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 PROJECT_CONF_H_ +#define PROJECT_CONF_H_ +/*---------------------------------------------------------------------------*/ +/* Enable the ROM bootloader */ +#define ROM_BOOTLOADER_ENABLE 1 +/*---------------------------------------------------------------------------*/ +/* Change to match your configuration */ +#define IEEE802154_CONF_PANID 0xABCD +#define IEEE802154_CONF_DEFAULT_CHANNEL 25 +#define RF_BLE_CONF_ENABLED 1 +/*---------------------------------------------------------------------------*/ +#endif /* PROJECT_CONF_H_ */ +/*---------------------------------------------------------------------------*/ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/start-demo.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/start-demo.c new file mode 100644 index 000000000..9ed3f32cb --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/start-demo.c @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup cc26xx-platforms + * @{ + * + * \defgroup cc26xx-examples CC26xx Example Projects + * + * Example projects for CC26xx-based platforms. + * @{ + * + * \defgroup cc26xx-demo CC26xx Demo Project + * + * Example project demonstrating the CC13xx/CC26xx platforms + * + * This example will work for the following boards: + * - srf06-cc26xx: SmartRF06EB + CC13xx/CC26xx EM + * - CC2650 and CC1350 SensorTag + * - CC1310, CC1350, CC2650 LaunchPads + * + * This is an IPv6/RPL-enabled example. Thus, if you have a border router in + * your installation (same RDC layer, same PAN ID and RF channel), you should + * be able to ping6 this demo node. + * + * This example also demonstrates CC26xx BLE operation. The process starts + * the BLE beacon daemon (implemented in the RF driver). The daemon will + * send out a BLE beacon periodically. Use any BLE-enabled application (e.g. + * LightBlue on OS X or the TI BLE Multitool smartphone app) and after a few + * seconds the cc26xx device will be discovered. + * + * - etimer/clock : Every CC26XX_DEMO_LOOP_INTERVAL clock ticks the LED defined + * as CC26XX_DEMO_LEDS_PERIODIC will toggle and the device + * will print out readings from some supported sensors + * - sensors : Some sensortag sensors are read asynchronously (see sensor + * documentation). For those, this example will print out + * readings in a staggered fashion at a random interval + * - Buttons : CC26XX_DEMO_TRIGGER_1 button will toggle CC26XX_DEMO_LEDS_BUTTON + * - CC26XX_DEMO_TRIGGER_2 turns on LEDS_REBOOT and causes a + * watchdog reboot + * - The remaining buttons will just print something + * - The example also shows how to retrieve the duration of a + * button press (in ticks). The driver will generate a + * sensors_changed event upon button release + * - Reed Relay : Will toggle the sensortag buzzer on/off + * + * @{ + * + * \file + * Example demonstrating the cc26xx platforms + */ +#include "contiki.h" +#include "sys/etimer.h" +#include "sys/ctimer.h" +#include "dev/leds.h" +#include "dev/watchdog.h" +#include "dev/button-hal.h" +#include "random.h" +#include "button-sensor.h" +#include "batmon-sensor.h" +#include "board-peripherals.h" + +#include "rf/ble-beacond.h" + +#include +#include +/*---------------------------------------------------------------------------*/ +#define CC26XX_DEMO_LOOP_INTERVAL (CLOCK_SECOND * 20) +#define CC26XX_DEMO_LEDS_PERIODIC LEDS_YELLOW +#define CC26XX_DEMO_LEDS_BUTTON LEDS_RED +#define CC26XX_DEMO_LEDS_REBOOT LEDS_ALL +/*---------------------------------------------------------------------------*/ +#define CC26XX_DEMO_TRIGGER_1 BUTTON_HAL_ID_KEY_LEFT +#define CC26XX_DEMO_TRIGGER_2 BUTTON_HAL_ID_KEY_RIGHT + +#if BOARD_SENSORTAG +#define CC26XX_DEMO_TRIGGER_3 BUTTON_HAL_ID_REED_RELAY +#endif +/*---------------------------------------------------------------------------*/ +static struct etimer et; +/*---------------------------------------------------------------------------*/ +PROCESS(cc26xx_demo_process, "cc26xx demo process"); +AUTOSTART_PROCESSES(&cc26xx_demo_process); +/*---------------------------------------------------------------------------*/ +#if BOARD_SENSORTAG +/*---------------------------------------------------------------------------*/ +/* + * Update sensor readings in a staggered fashion every SENSOR_READING_PERIOD + * ticks + a random interval between 0 and SENSOR_READING_RANDOM ticks + */ +#define SENSOR_READING_PERIOD (CLOCK_SECOND * 20) +#define SENSOR_READING_RANDOM (CLOCK_SECOND << 4) + +static struct ctimer bmp_timer, opt_timer, hdc_timer, tmp_timer, mpu_timer; +/*---------------------------------------------------------------------------*/ +static void init_bmp_reading(void *not_used); +static void init_opt_reading(void *not_used); +static void init_hdc_reading(void *not_used); +static void init_tmp_reading(void *not_used); +static void init_mpu_reading(void *not_used); +/*---------------------------------------------------------------------------*/ +static void +print_mpu_reading(int reading) +{ + if(reading < 0) { + printf("-"); + reading = -reading; + } + + printf("%d.%02d", reading / 100, reading % 100); +} +/*---------------------------------------------------------------------------*/ +static void +get_bmp_reading() +{ + int value; + clock_time_t next = SENSOR_READING_PERIOD + + (random_rand() % SENSOR_READING_RANDOM); + + value = bmp_280_sensor.value(BMP_280_SENSOR_TYPE_PRESS); + if(value != CC26XX_SENSOR_READING_ERROR) { + printf("BAR: Pressure=%d.%02d hPa\n", value / 100, value % 100); + } else { + printf("BAR: Pressure Read Error\n"); + } + + value = bmp_280_sensor.value(BMP_280_SENSOR_TYPE_TEMP); + if(value != CC26XX_SENSOR_READING_ERROR) { + printf("BAR: Temp=%d.%02d C\n", value / 100, value % 100); + } else { + printf("BAR: Temperature Read Error\n"); + } + + SENSORS_DEACTIVATE(bmp_280_sensor); + + ctimer_set(&bmp_timer, next, init_bmp_reading, NULL); +} +/*---------------------------------------------------------------------------*/ +static void +get_tmp_reading() +{ + int value; + clock_time_t next = SENSOR_READING_PERIOD + + (random_rand() % SENSOR_READING_RANDOM); + + value = tmp_007_sensor.value(TMP_007_SENSOR_TYPE_ALL); + + if(value == CC26XX_SENSOR_READING_ERROR) { + printf("TMP: Ambient Read Error\n"); + return; + } + + value = tmp_007_sensor.value(TMP_007_SENSOR_TYPE_AMBIENT); + printf("TMP: Ambient=%d.%03d C\n", value / 1000, value % 1000); + + value = tmp_007_sensor.value(TMP_007_SENSOR_TYPE_OBJECT); + printf("TMP: Object=%d.%03d C\n", value / 1000, value % 1000); + + SENSORS_DEACTIVATE(tmp_007_sensor); + + ctimer_set(&tmp_timer, next, init_tmp_reading, NULL); +} +/*---------------------------------------------------------------------------*/ +static void +get_hdc_reading() +{ + int value; + clock_time_t next = SENSOR_READING_PERIOD + + (random_rand() % SENSOR_READING_RANDOM); + + value = hdc_1000_sensor.value(HDC_1000_SENSOR_TYPE_TEMP); + if(value != CC26XX_SENSOR_READING_ERROR) { + printf("HDC: Temp=%d.%02d C\n", value / 100, value % 100); + } else { + printf("HDC: Temp Read Error\n"); + } + + value = hdc_1000_sensor.value(HDC_1000_SENSOR_TYPE_HUMIDITY); + if(value != CC26XX_SENSOR_READING_ERROR) { + printf("HDC: Humidity=%d.%02d %%RH\n", value / 100, value % 100); + } else { + printf("HDC: Humidity Read Error\n"); + } + + ctimer_set(&hdc_timer, next, init_hdc_reading, NULL); +} +/*---------------------------------------------------------------------------*/ +static void +get_light_reading() +{ + int value; + clock_time_t next = SENSOR_READING_PERIOD + + (random_rand() % SENSOR_READING_RANDOM); + + value = opt_3001_sensor.value(0); + if(value != CC26XX_SENSOR_READING_ERROR) { + printf("OPT: Light=%d.%02d lux\n", value / 100, value % 100); + } else { + printf("OPT: Light Read Error\n"); + } + + /* The OPT will turn itself off, so we don't need to call its DEACTIVATE */ + ctimer_set(&opt_timer, next, init_opt_reading, NULL); +} +/*---------------------------------------------------------------------------*/ +static void +get_mpu_reading() +{ + int value; + clock_time_t next = SENSOR_READING_PERIOD + + (random_rand() % SENSOR_READING_RANDOM); + + printf("MPU Gyro: X="); + value = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_GYRO_X); + print_mpu_reading(value); + printf(" deg/sec\n"); + + printf("MPU Gyro: Y="); + value = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_GYRO_Y); + print_mpu_reading(value); + printf(" deg/sec\n"); + + printf("MPU Gyro: Z="); + value = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_GYRO_Z); + print_mpu_reading(value); + printf(" deg/sec\n"); + + printf("MPU Acc: X="); + value = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_ACC_X); + print_mpu_reading(value); + printf(" G\n"); + + printf("MPU Acc: Y="); + value = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_ACC_Y); + print_mpu_reading(value); + printf(" G\n"); + + printf("MPU Acc: Z="); + value = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_ACC_Z); + print_mpu_reading(value); + printf(" G\n"); + + SENSORS_DEACTIVATE(mpu_9250_sensor); + + ctimer_set(&mpu_timer, next, init_mpu_reading, NULL); +} +/*---------------------------------------------------------------------------*/ +static void +init_bmp_reading(void *not_used) +{ + SENSORS_ACTIVATE(bmp_280_sensor); +} +/*---------------------------------------------------------------------------*/ +static void +init_opt_reading(void *not_used) +{ + SENSORS_ACTIVATE(opt_3001_sensor); +} +/*---------------------------------------------------------------------------*/ +static void +init_hdc_reading(void *not_used) +{ + SENSORS_ACTIVATE(hdc_1000_sensor); +} +/*---------------------------------------------------------------------------*/ +static void +init_tmp_reading(void *not_used) +{ + SENSORS_ACTIVATE(tmp_007_sensor); +} +/*---------------------------------------------------------------------------*/ +static void +init_mpu_reading(void *not_used) +{ + mpu_9250_sensor.configure(SENSORS_ACTIVE, MPU_9250_SENSOR_TYPE_ALL); +} +#endif +/*---------------------------------------------------------------------------*/ +static void +get_sync_sensor_readings(void) +{ + int value; + + printf("-----------------------------------------\n"); + + value = batmon_sensor.value(BATMON_SENSOR_TYPE_TEMP); + printf("Bat: Temp=%d C\n", value); + + value = batmon_sensor.value(BATMON_SENSOR_TYPE_VOLT); + printf("Bat: Volt=%d mV\n", (value * 125) >> 5); + +#if BOARD_SMARTRF06EB + SENSORS_ACTIVATE(als_sensor); + + value = als_sensor.value(0); + printf("ALS: %d raw\n", value); + + SENSORS_DEACTIVATE(als_sensor); +#endif + + return; +} +/*---------------------------------------------------------------------------*/ +static void +init_sensors(void) +{ + SENSORS_ACTIVATE(batmon_sensor); +} +/*---------------------------------------------------------------------------*/ +static void +init_sensor_readings(void) +{ +#if BOARD_SENSORTAG + SENSORS_ACTIVATE(hdc_1000_sensor); + SENSORS_ACTIVATE(tmp_007_sensor); + SENSORS_ACTIVATE(opt_3001_sensor); + SENSORS_ACTIVATE(bmp_280_sensor); + + init_mpu_reading(NULL); +#endif +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(cc26xx_demo_process, ev, data) +{ + + PROCESS_BEGIN(); + + printf("CC26XX demo\n"); + + init_sensors(); + + /* Init the BLE advertisement daemon */ + rf_ble_beacond_start(0, BOARD_STRING); + + etimer_set(&et, CC26XX_DEMO_LOOP_INTERVAL); + get_sync_sensor_readings(); + init_sensor_readings(); + + while(1) { + + PROCESS_YIELD(); + + if(ev == PROCESS_EVENT_TIMER) { + if(data == &et) { + leds_toggle(CC26XX_DEMO_LEDS_PERIODIC); + + get_sync_sensor_readings(); + + etimer_set(&et, CC26XX_DEMO_LOOP_INTERVAL); + } + } else if(ev == button_hal_periodic_event) { + button_hal_button_t *button = data; + + printf("%s periodic event, duration %d seconds\n", + BUTTON_HAL_GET_DESCRIPTION(button), + button->press_duration_seconds); + } else if(ev == button_hal_release_event) { + button_hal_button_t *btn = (button_hal_button_t *)data; + + printf("%s release event\n", BUTTON_HAL_GET_DESCRIPTION(btn)); + + if(btn->unique_id== CC26XX_DEMO_TRIGGER_1) { + leds_toggle(CC26XX_DEMO_LEDS_BUTTON); + } else if(btn->unique_id == CC26XX_DEMO_TRIGGER_2) { + leds_on(CC26XX_DEMO_LEDS_REBOOT); + watchdog_reboot(); +#if BOARD_SENSORTAG + } else if(btn->unique_id == CC26XX_DEMO_TRIGGER_3) { + if(buzzer_state()) { + buzzer_stop(); + } else { + buzzer_start(1000); + } + } + } else if(ev == sensors_event) { + if(data == &bmp_280_sensor) { + get_bmp_reading(); + } else if(data == &opt_3001_sensor) { + get_light_reading(); + } else if(data == &hdc_1000_sensor) { + get_hdc_reading(); + } else if(data == &tmp_007_sensor) { + get_tmp_reading(); + } else if(data == &mpu_9250_sensor) { + get_mpu_reading(); +#endif + } + } + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + * @} + */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/Makefile b/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/Makefile new file mode 100644 index 000000000..46da822d3 --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/Makefile @@ -0,0 +1,10 @@ +CONTIKI_PROJECT = very-sleepy-demo + +PLATFORMS_ONLY = srf06-cc26xx + +all: $(CONTIKI_PROJECT) + +MODULES += os/net/app-layer/coap + +CONTIKI = ../../../.. +include $(CONTIKI)/Makefile.include diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/README.md b/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/README.md new file mode 100644 index 000000000..851150432 --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/README.md @@ -0,0 +1,91 @@ +# CC13xx/CC26xx Very Sleepy Demo + +This example demonstrates a way of deploying a very low-consuming, very sleepy +node. The node has two modes of operation: + +* Normal: ContikiMAC duty-cycles the radio as usual. The node is reachable. +* Very Sleepy: Radio cycling mostly off, except when we need to perform network + maintenance tasks. In this mode, the node is unreachable for most of the time. + +The node will operate in RPL leaf mode. This means that it will be reachable +downwards, but it will not advertise the DODAG and it will not participate in +routing. + +After booting, the node will enter "normal" mode. + +The node exposes an OBSERVEable CoAP resource. It will notify subscribers with +a new value for this resource every `interval` seconds. It will then stay in +normal mode for `duration` seconds. During this time window, it will be +reachable over the network in order to e.g. receive a new configuration. +When this time window expires, the node will switch back to very sleepy mode. +This will only happen if very sleepy mode has been enabled by setting `mode=1` +as per the instructions below. + +When the node is duty-cycling the radio, either because it is in normal mode or +because network maintenance is taking place, it will keep its green LED on thus +providing an indication that it is reachable (red LED for the CC1350 tag). + +A normal mode stint can be manually triggered by pressing the left button. + +## Requirements + +To run this example you will need: + +* A border router operating with the same RDC, same channel, same radio mode + (e.g. IEEE or sub-ghz), same PAN ID. Alternatively, you can + use [6lbr](https://github.com/cetic/6lbr) with a suitable slip-radio. +* The [Copper (Cu)](https://addons.mozilla.org/en-US/firefox/addon/copper-270430/) + addon for Firefox + +## Configuration + +To configure the node, send a CoAP POST message to the `very_sleepy_config` +resource. The POST message's payload must specify _at least one_ of: + +* `mode=0|1`: Send `mode=1` to enable very sleepy mode, `mode=0` to disable it. +* `interval=n` where `n` is the number of seconds between two consecutive normal + mode periods. This interval also dictates the OBSERVEr notification period. +* `duration=n` where `n` is the number of seconds that the node will stay in + normal mode before dropping to very sleepy mode. This value is only relevant + if `mode==1`. + +A POST request must contain at least one of the above, but they are otherwise +all optional. So, for example, a POST may simply specify `interval=n`. To send +multiple values, delimit them with `&`. So you can send something like +`mode=1&interval=60&duration=20` + +The current running configuration can be retrieved by sending a GET request to +the same CoAP resource. + +## Running the example + +* Deploy your border router or 6lbr +* Turn on the very sleepy node. +* Fire up the Copper addon +* Select `.well-known/core` and hit `GET` +* Configure very sleepy operation: + * Select the `very_sleepy_config` resource + * In the `Outgoing` pane, type your POST payload as per the instructions + above. For example, you can type: `mode=1&interval=30&duration=10` + * Hit `POST` +* Select the `sen/readings` resource and hit `OBSERVE` + +## Caveats + +If you click on a resource in the Copper resources tree while you are observing +a different resource, the OBSERVEr for the latter will be stopped without +notifying the CoAP server. This will result in the server sending out OBSERVE +notifications that will be responded to with port unreachable ICMPv6 messages. +This will continue for quite a while, until the server detects that the +OBSERVEr has been lost (a test currently performed once every 20 notifications). +In order to prevent this from happening, hit the "Cancel" button for the +OBSERVE before switching views to a different resource. This will unregister +the observer. + +In very sleepy mode, the radio is not truly always off. The contiki core needs +to perform other periodic tasks in order to maintain network connectivity. For +that reason, this example will allow the radio to turn on periodically even +while in very sleepy mode. Thus, you may see that the node becomes briefly +reachable every now and then. However, do not count on those periods of +reachability to perform any tasks, as they will be brief and will be disrupted +without warning. diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/project-conf.h b/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/project-conf.h new file mode 100644 index 000000000..f22fb2685 --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/project-conf.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ + * 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 PROJECT_CONF_H_ +#define PROJECT_CONF_H_ +/*---------------------------------------------------------------------------*/ +/* Change to match your configuration */ +#define IEEE802154_CONF_PANID 0xABCD +#define IEEE802154_CONF_DEFAULT_CHANNEL 25 +/*---------------------------------------------------------------------------*/ + +/* Enable the ROM bootloader */ +#define ROM_BOOTLOADER_ENABLE 1 +/*---------------------------------------------------------------------------*/ +/* For very sleepy operation */ +#define RF_BLE_CONF_ENABLED 0 +#define UIP_DS6_CONF_PERIOD CLOCK_SECOND +#define UIP_CONF_TCP 0 +#define RPL_CONF_LEAF_ONLY 1 + +/* + * We'll fail without RPL probing, so turn it on explicitly even though it's + * on by default + */ +#define RPL_CONF_WITH_PROBING 1 +/*---------------------------------------------------------------------------*/ +#endif /* PROJECT_CONF_H_ */ +/*---------------------------------------------------------------------------*/ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/very-sleepy-demo.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/very-sleepy-demo.c new file mode 100644 index 000000000..d707f3cd1 --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/very-sleepy-demo.c @@ -0,0 +1,424 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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/etimer.h" +#include "sys/stimer.h" +#include "sys/process.h" +#include "dev/leds.h" +#include "dev/watchdog.h" +#include "dev/button-hal.h" +#include "batmon-sensor.h" +#include "board-peripherals.h" +#include "net/netstack.h" +#include "net/ipv6/uip-ds6-nbr.h" +#include "net/ipv6/uip-ds6-route.h" +#include "net/routing/routing.h" +#include "coap-engine.h" +#include "coap.h" + +#include "ti-lib.h" + +#include +#include +#include +/*---------------------------------------------------------------------------*/ +/* Normal mode duration params in seconds */ +#define NORMAL_OP_DURATION_DEFAULT 10 +#define NORMAL_OP_DURATION_MIN 10 +#define NORMAL_OP_DURATION_MAX 60 +/*---------------------------------------------------------------------------*/ +/* Observer notification period params in seconds */ +#define PERIODIC_INTERVAL_DEFAULT 30 +#define PERIODIC_INTERVAL_MIN 30 +#define PERIODIC_INTERVAL_MAX 86400 /* 1 day */ +/*---------------------------------------------------------------------------*/ +#define VERY_SLEEPY_MODE_OFF 0 +#define VERY_SLEEPY_MODE_ON 1 +/*---------------------------------------------------------------------------*/ +#define BUTTON_TRIGGER BUTTON_HAL_ID_KEY_LEFT +/*---------------------------------------------------------------------------*/ +#define MAC_CAN_BE_TURNED_OFF 0 +#define MAC_MUST_STAY_ON 1 + +#define KEEP_MAC_ON_MIN_PERIOD 10 /* secs */ +/*---------------------------------------------------------------------------*/ +#define PERIODIC_INTERVAL CLOCK_SECOND +/*---------------------------------------------------------------------------*/ +#define POST_STATUS_BAD 0x80 +#define POST_STATUS_HAS_MODE 0x40 +#define POST_STATUS_HAS_DURATION 0x20 +#define POST_STATUS_HAS_INTERVAL 0x10 +#define POST_STATUS_NONE 0x00 +/*---------------------------------------------------------------------------*/ +typedef struct sleepy_config_s { + unsigned long interval; + unsigned long duration; + uint8_t mode; +} sleepy_config_t; + +sleepy_config_t config; +/*---------------------------------------------------------------------------*/ +#define STATE_NORMAL 0 +#define STATE_NOTIFY_OBSERVERS 1 +#define STATE_VERY_SLEEPY 2 +/*---------------------------------------------------------------------------*/ +static struct stimer st_duration; +static struct stimer st_interval; +static struct stimer st_min_mac_on_duration; +static struct etimer et_periodic; +static process_event_t event_new_config; +static uint8_t state; +/*---------------------------------------------------------------------------*/ +const char *not_supported_msg = "Supported:text/plain,application/json"; +/*---------------------------------------------------------------------------*/ +PROCESS(very_sleepy_demo_process, "CC13xx/CC26xx very sleepy process"); +AUTOSTART_PROCESSES(&very_sleepy_demo_process); +/*---------------------------------------------------------------------------*/ +static void +readings_get_handler(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + unsigned int accept = -1; + int temp; + int voltage; + + if(request != NULL) { + coap_get_header_accept(request, &accept); + } + + temp = batmon_sensor.value(BATMON_SENSOR_TYPE_TEMP); + + voltage = batmon_sensor.value(BATMON_SENSOR_TYPE_VOLT); + + if(accept == -1 || accept == APPLICATION_JSON) { + coap_set_header_content_format(response, APPLICATION_JSON); + snprintf((char *)buffer, COAP_MAX_CHUNK_SIZE, + "{\"temp\":{\"v\":%d,\"u\":\"C\"}," + "\"voltage\":{\"v\":%d,\"u\":\"mV\"}}", + temp, (voltage * 125) >> 5); + + coap_set_payload(response, buffer, strlen((char *)buffer)); + } else if(accept == TEXT_PLAIN) { + coap_set_header_content_format(response, TEXT_PLAIN); + snprintf((char *)buffer, COAP_MAX_CHUNK_SIZE, "Temp=%dC, Voltage=%dmV", + temp, (voltage * 125) >> 5); + + coap_set_payload(response, buffer, strlen((char *)buffer)); + } else { + coap_set_status_code(response, NOT_ACCEPTABLE_4_06); + coap_set_payload(response, not_supported_msg, + strlen(not_supported_msg)); + } +} +/*---------------------------------------------------------------------------*/ +RESOURCE(readings_resource, "title=\"Sensor Readings\";obs", + readings_get_handler, NULL, NULL, NULL); +/*---------------------------------------------------------------------------*/ +static void +conf_get_handler(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + unsigned int accept = -1; + + if(request != NULL) { + coap_get_header_accept(request, &accept); + } + + if(accept == -1 || accept == APPLICATION_JSON) { + coap_set_header_content_format(response, APPLICATION_JSON); + snprintf((char *)buffer, COAP_MAX_CHUNK_SIZE, + "{\"config\":{\"mode\":%u,\"duration\":%lu,\"interval\":%lu}}", + config.mode, config.duration, config.interval); + + coap_set_payload(response, buffer, strlen((char *)buffer)); + } else if(accept == TEXT_PLAIN) { + coap_set_header_content_format(response, TEXT_PLAIN); + snprintf((char *)buffer, COAP_MAX_CHUNK_SIZE, + "Mode=%u, Duration=%lusecs, Interval=%lusecs", + config.mode, config.duration, config.interval); + + coap_set_payload(response, buffer, strlen((char *)buffer)); + } else { + coap_set_status_code(response, NOT_ACCEPTABLE_4_06); + coap_set_payload(response, not_supported_msg, + strlen(not_supported_msg)); + } +} +/*---------------------------------------------------------------------------*/ +static void +conf_post_handler(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + const char *ptr = NULL; + char tmp_buf[16]; + unsigned long interval = 0; + unsigned long duration = 0; + uint8_t mode = VERY_SLEEPY_MODE_OFF; + uint8_t post_status = POST_STATUS_NONE; + int rv; + + rv = coap_get_post_variable(request, "mode", &ptr); + if(rv && rv < 16) { + memset(tmp_buf, 0, sizeof(tmp_buf)); + memcpy(tmp_buf, ptr, rv); + rv = atoi(tmp_buf); + + if(rv == 1) { + mode = VERY_SLEEPY_MODE_ON; + post_status |= POST_STATUS_HAS_MODE; + } else if(rv == 0) { + mode = VERY_SLEEPY_MODE_OFF; + post_status |= POST_STATUS_HAS_MODE; + } else { + post_status = POST_STATUS_BAD; + } + } + + rv = coap_get_post_variable(request, "duration", &ptr); + if(rv && rv < 16) { + memset(tmp_buf, 0, sizeof(tmp_buf)); + memcpy(tmp_buf, ptr, rv); + rv = atoi(tmp_buf); + + duration = (unsigned long)rv; + if(duration < NORMAL_OP_DURATION_MIN || duration > NORMAL_OP_DURATION_MAX) { + post_status = POST_STATUS_BAD; + } else { + post_status |= POST_STATUS_HAS_DURATION; + } + } + + rv = coap_get_post_variable(request, "interval", &ptr); + if(rv && rv < 16) { + memset(tmp_buf, 0, sizeof(tmp_buf)); + memcpy(tmp_buf, ptr, rv); + rv = atoi(tmp_buf); + interval = (unsigned long)rv; + if(interval < PERIODIC_INTERVAL_MIN || interval > PERIODIC_INTERVAL_MAX) { + post_status = POST_STATUS_BAD; + } else { + post_status |= POST_STATUS_HAS_INTERVAL; + } + } + + if((post_status & POST_STATUS_BAD) == POST_STATUS_BAD || + post_status == POST_STATUS_NONE) { + coap_set_status_code(response, BAD_REQUEST_4_00); + snprintf((char *)buffer, COAP_MAX_CHUNK_SIZE, + "mode=0|1&duration=[%u,%u]&interval=[%u,%u]", + NORMAL_OP_DURATION_MIN, NORMAL_OP_DURATION_MAX, + PERIODIC_INTERVAL_MIN, PERIODIC_INTERVAL_MAX); + + coap_set_payload(response, buffer, strlen((char *)buffer)); + return; + } + + /* Values are sane. Update the config and notify the process */ + if(post_status & POST_STATUS_HAS_MODE) { + config.mode = mode; + } + + if(post_status & POST_STATUS_HAS_INTERVAL) { + config.interval = interval; + } + + if(post_status & POST_STATUS_HAS_DURATION) { + config.duration = duration; + } + + process_post(&very_sleepy_demo_process, event_new_config, NULL); +} +/*---------------------------------------------------------------------------*/ +RESOURCE(very_sleepy_conf, + "title=\"Very sleepy conf: " + "GET|POST mode=0|1&interval=&duration=\";rt=\"Control\"", + conf_get_handler, conf_post_handler, NULL, NULL); +/*---------------------------------------------------------------------------*/ +/* + * If our preferred parent is not NBR_REACHABLE in the ND cache, NUD will send + * a unicast NS and wait for NA. If NA fails then the neighbour will be removed + * from the ND cache and the default route will be deleted. To prevent this, + * keep the MAC on until the parent becomes NBR_REACHABLE. We also keep the MAC + * on if we are about to do RPL probing. + * + * In all cases, the radio will be locked on for KEEP_MAC_ON_MIN_PERIOD secs + */ +static uint8_t +keep_mac_on(void) +{ + uip_ds6_nbr_t *nbr; + uint8_t rv = MAC_CAN_BE_TURNED_OFF; + + if(!stimer_expired(&st_min_mac_on_duration)) { + return MAC_MUST_STAY_ON; + } + +#if RPL_WITH_PROBING + /* Determine if we are about to send a RPL probe */ + if(CLOCK_LT(etimer_expiration_time( + &rpl_get_default_instance()->dag.probing_timer.etimer), + (clock_time() + PERIODIC_INTERVAL))) { + rv = MAC_MUST_STAY_ON; + } +#endif + + /* It's OK to pass a NULL pointer, the callee checks and returns NULL */ + nbr = uip_ds6_nbr_lookup(uip_ds6_defrt_choose()); + + if(nbr == NULL) { + /* We don't have a default route, or it's not reachable (NUD likely). */ + rv = MAC_MUST_STAY_ON; + } else { + if(nbr->state != NBR_REACHABLE) { + rv = MAC_MUST_STAY_ON; + } + } + + if(rv == MAC_MUST_STAY_ON && stimer_expired(&st_min_mac_on_duration)) { + stimer_set(&st_min_mac_on_duration, KEEP_MAC_ON_MIN_PERIOD); + } + + return rv; +} +/*---------------------------------------------------------------------------*/ +static void +switch_to_normal(void) +{ + state = STATE_NOTIFY_OBSERVERS; + + /* + * Stay in normal mode for 'duration' secs. + * Transition back to normal in 'interval' secs, _including_ 'duration' + */ + stimer_set(&st_duration, config.duration); + stimer_set(&st_interval, config.interval); +} +/*---------------------------------------------------------------------------*/ +static void +switch_to_very_sleepy(void) +{ + state = STATE_VERY_SLEEPY; +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(very_sleepy_demo_process, ev, data) +{ + uint8_t mac_keep_on; + + PROCESS_BEGIN(); + + SENSORS_ACTIVATE(batmon_sensor); + + config.mode = VERY_SLEEPY_MODE_OFF; + config.interval = PERIODIC_INTERVAL_DEFAULT; + config.duration = NORMAL_OP_DURATION_DEFAULT; + + state = STATE_NORMAL; + + event_new_config = process_alloc_event(); + + readings_resource.flags += IS_OBSERVABLE; + coap_activate_resource(&readings_resource, "sen/readings"); + coap_activate_resource(&very_sleepy_conf, "very_sleepy_config"); + + printf("Very Sleepy Demo Process\n"); + + switch_to_normal(); + + etimer_set(&et_periodic, PERIODIC_INTERVAL); + + while(1) { + + PROCESS_YIELD(); + + if(ev == button_hal_release_event && + ((button_hal_button_t *)data)->unique_id == BUTTON_TRIGGER) { + switch_to_normal(); + } + + if(ev == event_new_config) { + stimer_set(&st_interval, config.interval); + stimer_set(&st_duration, config.duration); + } + + if((ev == PROCESS_EVENT_TIMER && data == &et_periodic) || + (ev == button_hal_release_event && + ((button_hal_button_t *)data)->unique_id == BUTTON_TRIGGER) || + (ev == event_new_config)) { + + /* + * Determine if the stack is about to do essential network maintenance + * and, if so, keep the MAC layer on + */ + mac_keep_on = keep_mac_on(); + + if(mac_keep_on == MAC_MUST_STAY_ON || state != STATE_VERY_SLEEPY) { + leds_on(LEDS_GREEN); + NETSTACK_MAC.on(); + } + + /* + * Next, switch between normal and very sleepy mode depending on config, + * send notifications to observers as required. + */ + if(state == STATE_NOTIFY_OBSERVERS) { + coap_notify_observers(&readings_resource); + state = STATE_NORMAL; + } + + if(state == STATE_NORMAL) { + if(stimer_expired(&st_duration)) { + stimer_set(&st_duration, config.duration); + if(config.mode == VERY_SLEEPY_MODE_ON) { + switch_to_very_sleepy(); + } + } + } else if(state == STATE_VERY_SLEEPY) { + if(stimer_expired(&st_interval)) { + switch_to_normal(); + } + } + + if(mac_keep_on == MAC_CAN_BE_TURNED_OFF && state == STATE_VERY_SLEEPY) { + leds_off(LEDS_GREEN); + NETSTACK_MAC.off(); + } else { + leds_on(LEDS_GREEN); + NETSTACK_MAC.on(); + } + + /* Schedule next pass */ + etimer_set(&et_periodic, PERIODIC_INTERVAL); + } + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/Makefile b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/Makefile new file mode 100644 index 000000000..a295c03fe --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/Makefile @@ -0,0 +1,19 @@ +CONTIKI_PROJECT = web-demo +all: $(CONTIKI_PROJECT) + +MODULES_REL += ./resources + +PROJECT_SOURCEFILES += web-demo.c 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 + +CONTIKI=../../../.. +include $(CONTIKI)/Makefile.include diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/README.md b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/README.md new file mode 100644 index 000000000..912fcb72a --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/README.md @@ -0,0 +1,185 @@ +CC26xx Web Demo Readme +====================== +This demo project combines a number of web-based applications aiming to +demonstrate the CC26xx capability. The applications are: + +* A network-based UART +* A client for [6lbr](http://cetic.github.io/6lbr/) +* A CoAP server +* An MQTT client +* A web server which can be used to display sensor readings but also to + configure MQTT functionality + +The example has been configured to run for all CC26xx-based boards. + +To change between target boards, follow the instructions in the wiki. +Do not forget to `make clean` when switching between the boards. + +Specifically for some older CC2650 SensorTags, you may also need to change +`project-conf.h` such that `SENSORTAG_CC2650_REV_1_2_0` is defined as 1. To +check if your sensortag is one of those older ones, look for "REV: 1.2" +printed on the PCB. There may also be a sticker that reads "HW Rev 1.2.0". An +indication that you may need to do this is if you get a "Could not open flash +to load config" error on device startup. + +You can disable some of those individual components by changing the respective +defines in `project-conf.h`. For instance, to disable the CoAP functionality, +set `#define CC26XX_WEB_DEMO_CONF_COAP_SERVER 0`. The web server cannot be +disabled, all other aforementioned applications can. + +Network UART (net-uart) +----------------------- +This example only makes sense if you are using the Srf or if you have taken +the sensortag out of its case and you have it connected over JTAG to the Srf. + +The net-uart does two things: + +* When you type a string to the UART console, the string will be sent verbatim + to a remote UDP port 7777 listener. This can be for example a netcat listener + on a linux or OS X PC: + `nc -6ulkw 1 7777` +* The net-uart also listens to UDP port 7777 and when it receives a string over + UDP, it will print it verbatim over UART. + +The example will initially send packets to a hard-coded IPv6 address. This can +be changed very easily by entering a different IPv6 address to the console. +Thus, when the serial input string is an IPv6 address, it will not be sent as +any other string would, but instead it will configure the example to send to a +different remote address. This new IPv6 address is not persistent across +device reboots. + +6lbr Client +----------- +This will periodically send a UDP packet to your 6lbr, containing network +information, which will be used by 6lbr to construct a network graph. To see +this in action, fire up a browser and navigate to the 6lbr web page. The +default address is http://[bbbb::100]. Once the page loads, click the 'sensors' +tab, as per the image below. + +![6lbr](img/6lbr-web.png) + +CoAP Server +----------- +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). + +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-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 various CC13x0/CC26x0 boards. + +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 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 +the CoAP engine will return 4.03 forbidden. The values of `name` and `interval` +persist across BLE on/off cycles, so you only have to set them once. The values +do _not_ persist through device powercycles. + +HTTPD +----- +Back on the 6lbr page, hit the 'web' link corresponding to your device. This +will take you to a web page served by the CC26xx. The HTTPD serves two pages: + +* index.html: Provides sensor readings and network information +* config.html: Can be used to configure the MQTT client (more below) + +In the navigation bar at the top there is also a third link, which will take +you directly to your device's page on IBM's quickstart service. + +IBM Quickstart / MQTT Client +---------------------------- +The MQTT client can be used to: + +* Publish sensor readings to an MQTT broker. +* Subscribe to a topic and as a result receive commands from an MQTT broker + +The device will 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. If this is not an option for you, you can +configure the device to publish to a local MQTT broker over end-to-end IPv6. +See below on how to change the destination broker's address. + +By default the device will publish readings to IBM's quickstart service. The +publish messages include sensor readings but also some other information such +as device uptime in seconds and a message sequence number. Click the "IBM +Quickstart" link in the web page to go directly to your device's page +on Quickstart. After a few seconds, you will see something like this: + +![A SensorTag on IBM Quickstart](img/quickstart-sensortag.png) + +Sensor readings are only published if they have changed since the previous +reading (BatMon is an exception and always gets published). Additionally, you +can turn on/off individual readings from the config.html web page, as per the +figure below. + +![Sensor Readings Configuration](img/sensor-readings-config.png) + +Some of the MQTT client functionality can be configured even further: + +* You can change the broker IP and port. This is useful if you want to use your + own MQTT broker instead of IBM's quickstart. The example has been tested + successfully with [mosquitto](http://mosquitto.org/) +* You can change the publish interval. Recommended values are 10secs or higher. + You will not be allowed to set this to anything less than 5 seconds. +* If you want to use IBM's cloud service with a registered device, change + 'Org ID' and provide an 'Auth Token', which acts as a 'password', but bear in + mind that it gets transported in clear text, both over the web configuration + page as well as inside MQTT messages. +* The remaining configuration options are related to the content of MQTT + messages and in general you won't have to modify them. + +For the SensorTag, changes to the MQTT configuration get saved in external +flash and persist across device restarts. The same does not hold true for +Srf+EM builds. + +You can also subscribe to topics and receive commands, but this will only +work if you use "Org ID" != 'quickstart'. Thus, if you provide a different +Org ID (do not forget the auth token!), the device will subscribe to: + +`iot-2/cmd/+/fmt/json` + +You can then use this to toggle LEDs or to turn the buzzer on and off. +The buzzer is only available on the SensorTag. To do this, you can for example +use mosquitto client to publish to `iot-2/cmd/leds/fmt/json`. So, to turn +the buzzer on, you would do this: + +`mosquitto_pub -h -m "1" -t iot-2/cmd/buzz/fmt/json` + +Where `broker IP` should be replaced with the IP address of your mosquitto +broker (the one where you device has subscribed). Replace `-m "1'` with `-m "0"` +to turn the buzzer back off. Replace `buzz` with `leds` in the topic to change +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) diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/cetic-6lbr-client.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/cetic-6lbr-client.c new file mode 100644 index 000000000..569a36a89 --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/cetic-6lbr-client.c @@ -0,0 +1,204 @@ +/* + * 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. + */ +/** + * \addtogroup cc26xx-web-demo + * @{ + * + * \file + * An implementation of a 6LBR UDP client. Is used to populate the 6LBR + * web server's 'sensors' tab + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "contiki-lib.h" +#include "contiki-net.h" +#include "net/routing/routing.h" +#include "net/ipv6/uip.h" +#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 +#include +/*---------------------------------------------------------------------------*/ +#define DEBUG 0 +#include "net/ipv6/uip-debug.h" +/*---------------------------------------------------------------------------*/ +#ifndef CETIC_6LBR_NODE_INFO_PORT +#define CETIC_6LBR_NODE_INFO_PORT 3000 +#endif + +#define MAX_PAYLOAD_LEN 40 +#define MSG_INTERVAL (60 * CLOCK_SECOND) +/*---------------------------------------------------------------------------*/ +static struct uip_udp_conn *client_conn = NULL; +static struct etimer et; +static uip_ip6addr_t dest_addr; +/*---------------------------------------------------------------------------*/ +PROCESS(cetic_6lbr_client_process, "6LBR Client Process"); +/*---------------------------------------------------------------------------*/ +static void +tcpip_handler(void) +{ + char *str; + + if(uip_newdata()) { + str = uip_appdata; + str[uip_datalen()] = '\0'; + PRINTF("Response from the server: '%s'\n", str); + } +} +/*---------------------------------------------------------------------------*/ +static char * +add_ipaddr(char *buf, const uip_ipaddr_t *addr) +{ + uint16_t a; + unsigned int i; + int f; + char *p = buf; + + for(i = 0, f = 0; i < sizeof(uip_ipaddr_t); i += 2) { + a = (addr->u8[i] << 8) + addr->u8[i + 1]; + if(a == 0 && f >= 0) { + if(f++ == 0) { + p += sprintf(p, "::"); + } + } else { + if(f > 0) { + f = -1; + } else if(i > 0) { + p += sprintf(p, ":"); + } + p += sprintf(p, "%04x", a); + } + } + return p; +} +/*---------------------------------------------------------------------------*/ +static void +timeout_handler(void) +{ + static int seq_id; + char buf[MAX_PAYLOAD_LEN]; + int i; + uip_ip6addr_t *globaladdr = NULL; + uint16_t dest_port = CETIC_6LBR_NODE_INFO_PORT; + int has_dest = 0; + rpl_instance_t *instance; + rpl_dag_t *dag; + + uip_ds6_addr_t *addr_desc = uip_ds6_get_global(ADDR_PREFERRED); + if(addr_desc != NULL) { + globaladdr = &addr_desc->ipaddr; + dag = rpl_get_any_dag(); + if(dag) { + uip_ipaddr_copy(&dest_addr, globaladdr); + memcpy(&dest_addr.u8[8], &dag->dag_id.u8[8], sizeof(uip_ipaddr_t) / 2); + has_dest = 1; + } + } + + if(has_dest) { + if(client_conn == NULL) { + PRINTF("UDP-CLIENT: address destination: "); + PRINT6ADDR(&dest_addr); + PRINTF("\n"); + client_conn = udp_new(&dest_addr, UIP_HTONS(dest_port), NULL); + + if(client_conn != NULL) { + PRINTF("Created a connection with the server "); + PRINT6ADDR(&client_conn->ripaddr); + PRINTF(" local/remote port %u/%u\n", + UIP_HTONS(client_conn->lport), UIP_HTONS(client_conn->rport)); + } else { + PRINTF("Could not open connection\n"); + } + } else { + if(memcmp(&client_conn->ripaddr, &dest_addr, sizeof(uip_ipaddr_t)) != 0) { + PRINTF("UDP-CLIENT: new address destination: "); + PRINT6ADDR(&dest_addr); + PRINTF("\n"); + uip_udp_remove(client_conn); + client_conn = udp_new(&dest_addr, UIP_HTONS(dest_port), NULL); + if(client_conn != NULL) { + PRINTF("Created a connection with the server "); + PRINT6ADDR(&client_conn->ripaddr); + PRINTF(" local/remote port %u/%u\n", + UIP_HTONS(client_conn->lport), UIP_HTONS(client_conn->rport)); + } else { + PRINTF("Could not open connection\n"); + } + } + } + if(client_conn != NULL) { + PRINTF("Client sending to: "); + PRINT6ADDR(&client_conn->ripaddr); + i = sprintf(buf, "%d | ", ++seq_id); + instance = rpl_get_default_instance(); + 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)"); + } + PRINTF(" (msg: %s)\n", buf); + uip_udp_packet_send(client_conn, buf, strlen(buf)); + } else { + PRINTF("No connection created\n"); + } + } else { + PRINTF("No address configured\n"); + } +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(cetic_6lbr_client_process, ev, data) +{ + + PROCESS_BEGIN(); + + printf("6LBR Client Process\n"); + + memset(&dest_addr, 0, sizeof(uip_ipaddr_t)); + + etimer_set(&et, MSG_INTERVAL); + while(1) { + PROCESS_YIELD(); + if(etimer_expired(&et)) { + timeout_handler(); + etimer_set(&et, MSG_INTERVAL); + } else if(ev == tcpip_event) { + tcpip_handler(); + } + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +/** + * @} + */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/coap-server.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/coap-server.c new file mode 100644 index 000000000..37b9a295d --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/coap-server.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/** + * \addtogroup cc26xx-web-demo + * @{ + * + * \file + * A CC26XX-specific CoAP server + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "contiki-net.h" +#include "coap-engine.h" +#include "board-peripherals.h" +#include "rf-core/rf-ble.h" +#include "cc26xx-web-demo.h" + +#include +#include +#include +/*---------------------------------------------------------------------------*/ +/* Common resources */ +extern coap_resource_t res_leds; + +extern coap_resource_t res_batmon_temp; +extern coap_resource_t res_batmon_volt; + +extern coap_resource_t res_device_sw; +extern coap_resource_t res_device_hw; +extern coap_resource_t res_device_uptime; +extern coap_resource_t res_device_cfg_reset; + +extern coap_resource_t res_parent_rssi; +extern coap_resource_t res_parent_ip; + +#if RF_BLE_ENABLED +extern coap_resource_t res_ble_advd; +#endif + +extern coap_resource_t res_toggle_red; +extern coap_resource_t res_toggle_green; + +/* Board-specific resources */ +#if BOARD_SENSORTAG +extern coap_resource_t res_bmp280_temp; +extern coap_resource_t res_bmp280_press; +extern coap_resource_t res_tmp007_amb; +extern coap_resource_t res_tmp007_obj; +extern coap_resource_t res_hdc1000_temp; +extern coap_resource_t res_hdc1000_hum; +extern coap_resource_t res_opt3001_light; +extern coap_resource_t res_mpu_acc_x; +extern coap_resource_t res_mpu_acc_y; +extern coap_resource_t res_mpu_acc_z; +extern coap_resource_t res_mpu_gyro_x; +extern coap_resource_t res_mpu_gyro_y; +extern coap_resource_t res_mpu_gyro_z; +#else +extern coap_resource_t res_toggle_orange; +extern coap_resource_t res_toggle_yellow; +#endif + +#if CC26XX_WEB_DEMO_ADC_DEMO +extern coap_resource_t res_adc_dio23; +#endif +/*---------------------------------------------------------------------------*/ +const char *coap_server_not_found_msg = "Resource not found"; +const char *coap_server_supported_msg = "Supported:" + "text/plain," + "application/json," + "application/xml"; +/*---------------------------------------------------------------------------*/ +static void +start_board_resources(void) +{ + + coap_activate_resource(&res_toggle_green, "lt/g"); + coap_activate_resource(&res_toggle_red, "lt/r"); + coap_activate_resource(&res_leds, "lt"); + +#if BOARD_SENSORTAG + coap_activate_resource(&res_bmp280_temp, "sen/bar/temp"); + coap_activate_resource(&res_bmp280_press, "sen/bar/pres"); + coap_activate_resource(&res_tmp007_amb, "sen/tmp/amb"); + coap_activate_resource(&res_tmp007_obj, "sen/tmp/obj"); + coap_activate_resource(&res_hdc1000_temp, "sen/hdc/t"); + coap_activate_resource(&res_hdc1000_hum, "sen/hdc/h"); + coap_activate_resource(&res_opt3001_light, "sen/opt/light"); + coap_activate_resource(&res_mpu_acc_x, "sen/mpu/acc/x"); + coap_activate_resource(&res_mpu_acc_y, "sen/mpu/acc/y"); + coap_activate_resource(&res_mpu_acc_z, "sen/mpu/acc/z"); + coap_activate_resource(&res_mpu_gyro_x, "sen/mpu/gyro/x"); + coap_activate_resource(&res_mpu_gyro_y, "sen/mpu/gyro/y"); + coap_activate_resource(&res_mpu_gyro_z, "sen/mpu/gyro/z"); +#elif BOARD_SMARTRF06EB + coap_activate_resource(&res_toggle_yellow, "lt/y"); + coap_activate_resource(&res_toggle_orange, "lt/o"); +#endif +} +/*---------------------------------------------------------------------------*/ +PROCESS(coap_server_process, "CC26XX CoAP Server"); +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(coap_server_process, ev, data) +{ + PROCESS_BEGIN(); + + printf("CC26XX CoAP Server\n"); + + coap_activate_resource(&res_batmon_temp, "sen/batmon/temp"); + coap_activate_resource(&res_batmon_volt, "sen/batmon/voltage"); + +#if CC26XX_WEB_DEMO_ADC_DEMO + coap_activate_resource(&res_adc_dio23, "sen/adc/dio23"); +#endif + + coap_activate_resource(&res_device_hw, "dev/mdl/hw"); + coap_activate_resource(&res_device_sw, "dev/mdl/sw"); + coap_activate_resource(&res_device_uptime, "dev/uptime"); + coap_activate_resource(&res_device_cfg_reset, "dev/cfg_reset"); + + coap_activate_resource(&res_parent_rssi, "net/parent/RSSI"); + coap_activate_resource(&res_parent_ip, "net/parent/IPv6"); + +#if RF_BLE_ENABLED + coap_activate_resource(&res_ble_advd, "dev/ble_advd"); +#endif + + start_board_resources(); + + /* Define application-specific events here. */ + while(1) { + PROCESS_WAIT_EVENT(); + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +/** + * @} + */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/coap-server.h b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/coap-server.h new file mode 100644 index 000000000..7399597c8 --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/coap-server.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/** + * \addtogroup cc26xx-web-demo + * @{ + * + * \file + * Header file for the CC26xx web demo CoAP functionality + */ +/*---------------------------------------------------------------------------*/ +#include "sys/process.h" +/*---------------------------------------------------------------------------*/ +#ifndef COAP_SERVER_H_ +#define COAP_SERVER_H_ +/*---------------------------------------------------------------------------*/ +extern const char *coap_server_not_found_msg; +extern const char *coap_server_supported_msg; +/*---------------------------------------------------------------------------*/ +PROCESS_NAME(coap_server_process); +/*---------------------------------------------------------------------------*/ +#endif /* COAP_SERVER_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/httpd-simple.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/httpd-simple.c new file mode 100644 index 000000000..e23e78efe --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/httpd-simple.c @@ -0,0 +1,1349 @@ +/* + * Copyright (c) 2010, Swedish Institute of Computer Science. + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + * + */ +/** + * \addtogroup cc26xx-web-demo + * @{ + * + * \file + * A simple web server which displays network and sensor information + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "httpd-simple.h" +#include "net/ipv6/uip-ds6-route.h" +#include "batmon-sensor.h" +#include "lib/sensors.h" +#include "lib/list.h" +#include "cc26xx-web-demo.h" +#include "mqtt-client.h" +#include "net-uart.h" + +#include +#include +#include +#include +#include +#include +#include +#include +/*---------------------------------------------------------------------------*/ +#define SEND_STRING(s, str) PSOCK_SEND(s, (uint8_t *)str, strlen(str)) +/*---------------------------------------------------------------------------*/ +#define CONNS 2 +#define CONTENT_LENGTH_MAX 256 +#define STATE_WAITING 0 +#define STATE_OUTPUT 1 +#define IPADDR_BUF_LEN 64 +/*---------------------------------------------------------------------------*/ +#define RETURN_CODE_OK 0 +#define RETURN_CODE_NF 1 /* Not Found */ +#define RETURN_CODE_SU 2 /* Service Unavailable */ +#define RETURN_CODE_BR 3 /* Bad Request */ +#define RETURN_CODE_LR 4 /* Length Required */ +#define RETURN_CODE_TL 5 /* Content Length too Large */ +/*---------------------------------------------------------------------------*/ +/* POST request machine states */ +#define PARSE_POST_STATE_INIT 0 +#define PARSE_POST_STATE_MORE 1 +#define PARSE_POST_STATE_READING_KEY 2 +#define PARSE_POST_STATE_READING_VAL 3 +#define PARSE_POST_STATE_ERROR 0xFFFFFFFF +/*---------------------------------------------------------------------------*/ +#define PARSE_POST_BUF_SIZES 64 + +/* Last byte always used to null terminate */ +#define PARSE_POST_MAX_POS (PARSE_POST_BUF_SIZES - 2) + +static char key[PARSE_POST_BUF_SIZES]; +static char val_escaped[PARSE_POST_BUF_SIZES]; +static char val[PARSE_POST_BUF_SIZES]; +static int key_len; +static int val_len; +static int state; +/*---------------------------------------------------------------------------*/ +/* Stringified min/max intervals */ +#define STRINGIFY(x) XSTR(x) +#define XSTR(x) #x + +#define RSSI_INT_MAX STRINGIFY(CC26XX_WEB_DEMO_RSSI_MEASURE_INTERVAL_MAX) +#define RSSI_INT_MIN STRINGIFY(CC26XX_WEB_DEMO_RSSI_MEASURE_INTERVAL_MIN) +#define PUB_INT_MAX STRINGIFY(MQTT_CLIENT_PUBLISH_INTERVAL_MAX) +#define PUB_INT_MIN STRINGIFY(MQTT_CLIENT_PUBLISH_INTERVAL_MIN) +/*---------------------------------------------------------------------------*/ +/* + * We can only handle a single POST request at a time. Since a second POST + * request cannot interrupt us while obtaining a lock, we don't really need + * this lock to be atomic. + * + * An HTTP connection will first request a lock before it starts processing + * a POST request. We maintain a global lock which is either NULL or points + * to the http conn which currently has the lock + */ +static struct httpd_state *lock; +/*---------------------------------------------------------------------------*/ +PROCESS(httpd_simple_process, "CC26XX Web Server"); +/*---------------------------------------------------------------------------*/ +#define ISO_nl 0x0A +#define ISO_space 0x20 +#define ISO_slash 0x2F +#define ISO_amp 0x26 +#define ISO_column 0x3A +#define ISO_equal 0x3D +/*---------------------------------------------------------------------------*/ +#define HTTP_200_OK "HTTP/1.0 200 OK\r\n" +#define HTTP_302_FO "HTTP/1.0 302 Found\r\n" +#define HTTP_400_BR "HTTP/1.0 400 Bad Request\r\n" +#define HTTP_404_NF "HTTP/1.0 404 Not Found\r\n" +#define HTTP_411_LR "HTTP/1.0 411 Length Required\r\n" +#define HTTP_413_TL "HTTP/1.0 413 Request Entity Too Large\r\n" +#define HTTP_503_SU "HTTP/1.0 503 Service Unavailable\r\n" +#define CONN_CLOSE "Connection: close\r\n" +/*---------------------------------------------------------------------------*/ +#define SECTION_TAG "div" +#define SECTION_OPEN "<" SECTION_TAG ">" +#define SECTION_CLOSE "" + +#define CONTENT_OPEN "

"
+#define CONTENT_CLOSE "
" +/*---------------------------------------------------------------------------*/ +#define REQUEST_TYPE_GET 1 +#define REQUEST_TYPE_POST 2 +/*---------------------------------------------------------------------------*/ +static const char *NOT_FOUND = "" + "
" + "

404 - file not found

" + "
" + "" + ""; +/*---------------------------------------------------------------------------*/ +/* Page template */ +static const char http_doctype[] = ""; +static const char http_header_200[] = HTTP_200_OK; +static const char http_header_302[] = HTTP_302_FO; +static const char http_header_400[] = HTTP_400_BR; +static const char http_header_404[] = HTTP_404_NF; +static const char http_header_411[] = HTTP_411_LR; +static const char http_header_413[] = HTTP_413_TL; +static const char http_header_503[] = HTTP_503_SU; +static const char http_get[] = "GET "; +static const char http_post[] = "POST "; +static const char http_index_html[] = "/index.html"; +static const char http_html_start[] = ""; +static const char *http_header_srv_str[] = { + "Server: Contiki, ", + BOARD_STRING "\r\n", + NULL +}; + +static const char *http_header_con_close[] = { + CONN_CLOSE, + NULL +}; + +static const char *http_config_css[] = { + "", + NULL +}; +static const char http_head_charset[] = ""; +static const char http_title_start[] = ""; +static const char http_title_end[] = ""; +static const char http_head_end[] = ""; +static const char http_body_start[] = ""; +static const char http_bottom[] = ""; +/*---------------------------------------------------------------------------*/ +static const char http_content_type_html[] = "text/html"; +static const char http_content_type_plain[] = "text/plain"; +/*---------------------------------------------------------------------------*/ +/* For the config page */ +static const char config_div_left[] = "
"; +static const char config_div_right[] = "
"; +static const char config_div_close[] = "
"; +/*---------------------------------------------------------------------------*/ +static char generate_index(struct httpd_state *s); +static char generate_config(struct httpd_state *s); +/*---------------------------------------------------------------------------*/ +typedef struct page { + struct page *next; + char *filename; + char *title; + char (*script)(struct httpd_state *s); +} page_t; + +static page_t http_index_page = { + NULL, + "index.html", + "Index", + generate_index, +}; + +static page_t http_dev_cfg_page = { + NULL, + "config.html", + "Device Config", + generate_config, +}; + +#if CC26XX_WEB_DEMO_NET_UART +static char generate_net_uart_config(struct httpd_state *s); + +static page_t http_net_cfg_page = { + NULL, + "netu.html", + "Net-UART Config", + generate_net_uart_config, +}; +#endif + +#if CC26XX_WEB_DEMO_MQTT_CLIENT +static char generate_mqtt_config(struct httpd_state *s); + +static page_t http_mqtt_cfg_page = { + NULL, + "mqtt.html", + "MQTT/IBM Cloud Config", + generate_mqtt_config, +}; +#endif +/*---------------------------------------------------------------------------*/ +#define IBM_QUICKSTART_LINK_LEN 128 +static char http_mqtt_a[IBM_QUICKSTART_LINK_LEN]; +/*---------------------------------------------------------------------------*/ +static uint16_t numtimes; +static const httpd_simple_post_handler_t *handler; +/*---------------------------------------------------------------------------*/ +static uint8_t config_ok; +process_event_t httpd_simple_event_new_config; +/*---------------------------------------------------------------------------*/ +struct httpd_state; +typedef char (*httpd_simple_script_t)(struct httpd_state *s); + +struct httpd_state { + char buf[HTTPD_SIMPLE_MAIN_BUF_SIZE]; + char tmp_buf[TMP_BUF_SIZE]; + struct timer timer; + struct psock sin, sout; + int blen; + const char **ptr; + const cc26xx_web_demo_sensor_reading_t *reading; + const page_t *page; + uip_ds6_route_t *r; + uip_ds6_nbr_t *nbr; + httpd_simple_script_t script; + int content_length; + int tmp_buf_len; + int tmp_buf_copied; + char filename[HTTPD_PATHLEN]; + char inputbuf[HTTPD_INBUF_LEN]; + struct pt outputpt; + struct pt generate_pt; + struct pt top_matter_pt; + char state; + char request_type; + char return_code; +}; +/*---------------------------------------------------------------------------*/ +LIST(post_handlers); +LIST(pages_list); +MEMB(conns, struct httpd_state, CONNS); +/*---------------------------------------------------------------------------*/ +#define HEX_TO_INT(x) (isdigit(x) ? x - '0' : x - 'W') +static size_t +url_unescape(const char *src, size_t srclen, char *dst, size_t dstlen) +{ + size_t i, j; + int a, b; + + for(i = j = 0; i < srclen && j < dstlen - 1; i++, j++) { + if(src[i] == '%' && isxdigit(*(unsigned char *)(src + i + 1)) + && isxdigit(*(unsigned char *)(src + i + 2))) { + a = tolower(*(unsigned char *)(src + i + 1)); + b = tolower(*(unsigned char *)(src + i + 2)); + dst[j] = ((HEX_TO_INT(a) << 4) | HEX_TO_INT(b)) & 0xff; + i += 2; + } else if(src[i] == '+') { + dst[j] = ' '; + } else { + dst[j] = src[i]; + } + } + + dst[j] = '\0'; + + return i == srclen; +} +/*---------------------------------------------------------------------------*/ +void +httpd_simple_register_post_handler(httpd_simple_post_handler_t *h) +{ + list_add(post_handlers, h); +} +/*---------------------------------------------------------------------------*/ +static void +get_neighbour_state_text(char *buf, uint8_t state) +{ + switch(state) { + case NBR_INCOMPLETE: + memcpy(buf, "INCOMPLETE", strlen("INCOMPLETE")); + break; + case NBR_REACHABLE: + memcpy(buf, "REACHABLE", strlen("REACHABLE")); + break; + case NBR_STALE: + memcpy(buf, "STALE", strlen("STALE")); + break; + case NBR_DELAY: + memcpy(buf, "DELAY", strlen("DELAY")); + break; + case NBR_PROBE: + memcpy(buf, "NBR_PROBE", strlen("NBR_PROBE")); + break; + } +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(enqueue_chunk(struct httpd_state *s, uint8_t immediate, + const char *format, ...)) +{ + va_list ap; + + PSOCK_BEGIN(&s->sout); + + va_start(ap, format); + + s->tmp_buf_len = vsnprintf(s->tmp_buf, TMP_BUF_SIZE, format, ap); + + va_end(ap); + + if(s->blen + s->tmp_buf_len < HTTPD_SIMPLE_MAIN_BUF_SIZE) { + /* Enough space for the entire chunk. Copy over */ + memcpy(&s->buf[s->blen], s->tmp_buf, s->tmp_buf_len); + s->blen += s->tmp_buf_len; + } else { + memcpy(&s->buf[s->blen], s->tmp_buf, HTTPD_SIMPLE_MAIN_BUF_SIZE - s->blen); + s->tmp_buf_copied = HTTPD_SIMPLE_MAIN_BUF_SIZE - s->blen; + s->blen = HTTPD_SIMPLE_MAIN_BUF_SIZE; + PSOCK_SEND(&s->sout, (uint8_t *)s->buf, s->blen); + s->blen = 0; + if(s->tmp_buf_copied < s->tmp_buf_len) { + memcpy(s->buf, &s->tmp_buf[s->tmp_buf_copied], + s->tmp_buf_len - s->tmp_buf_copied); + s->blen += s->tmp_buf_len - s->tmp_buf_copied; + } + } + + if(immediate != 0 && s->blen > 0) { + PSOCK_SEND(&s->sout, (uint8_t *)s->buf, s->blen); + s->blen = 0; + } + + PSOCK_END(&s->sout); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(generate_top_matter(struct httpd_state *s, const char *title, + const char **css)) +{ + + PT_BEGIN(&s->top_matter_pt); + + PT_WAIT_THREAD(&s->top_matter_pt, enqueue_chunk(s, 0, http_doctype)); + PT_WAIT_THREAD(&s->top_matter_pt, enqueue_chunk(s, 0, http_html_start)); + PT_WAIT_THREAD(&s->top_matter_pt, enqueue_chunk(s, 0, http_title_start)); + + PT_WAIT_THREAD(&s->top_matter_pt, enqueue_chunk(s, 0, title)); + PT_WAIT_THREAD(&s->top_matter_pt, enqueue_chunk(s, 0, http_title_end)); + + if(css != NULL) { + for(s->ptr = css; *(s->ptr) != NULL; s->ptr++) { + PT_WAIT_THREAD(&s->top_matter_pt, enqueue_chunk(s, 0, *(s->ptr))); + } + } + + PT_WAIT_THREAD(&s->top_matter_pt, enqueue_chunk(s, 0, http_head_charset)); + PT_WAIT_THREAD(&s->top_matter_pt, enqueue_chunk(s, 0, http_head_end)); + PT_WAIT_THREAD(&s->top_matter_pt, enqueue_chunk(s, 0, http_body_start)); + + /* Links */ + PT_WAIT_THREAD(&s->top_matter_pt, + enqueue_chunk(s, 0, SECTION_OPEN "

")); + + s->page = list_head(pages_list); + PT_WAIT_THREAD(&s->top_matter_pt, + enqueue_chunk(s, 0, "[ %s ]", + s->page->filename, s->page->title)); + + for(s->page = s->page->next; s->page != NULL; s->page = s->page->next) { + PT_WAIT_THREAD(&s->top_matter_pt, + enqueue_chunk(s, 0, " | [ %s ]", + s->page->filename, s->page->title)); + } + +#if CC26XX_WEB_DEMO_MQTT_CLIENT + PT_WAIT_THREAD(&s->top_matter_pt, + enqueue_chunk(s, 0, " | %s", http_mqtt_a)); +#endif + PT_WAIT_THREAD(&s->top_matter_pt, + enqueue_chunk(s, 0, "

" SECTION_CLOSE)); + + PT_END(&s->top_matter_pt); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(generate_index(struct httpd_state *s)) +{ + char ipaddr_buf[IPADDR_BUF_LEN]; /* Intentionally on stack */ + + PT_BEGIN(&s->generate_pt); + + /* Generate top matter (doctype, title, nav links etc) */ + PT_WAIT_THREAD(&s->generate_pt, + generate_top_matter(s, http_index_page.title, NULL)); + + /* ND Cache */ + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, SECTION_OPEN "Neighbors" CONTENT_OPEN)); + + for(s->nbr = nbr_table_head(ds6_neighbors); s->nbr != NULL; + s->nbr = nbr_table_next(ds6_neighbors, s->nbr)) { + + PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "\n")); + + memset(ipaddr_buf, 0, IPADDR_BUF_LEN); + cc26xx_web_demo_ipaddr_sprintf(ipaddr_buf, IPADDR_BUF_LEN, &s->nbr->ipaddr); + PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "%s", ipaddr_buf)); + + memset(ipaddr_buf, 0, IPADDR_BUF_LEN); + get_neighbour_state_text(ipaddr_buf, s->nbr->state); + PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, " %s", ipaddr_buf)); + } + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, CONTENT_CLOSE SECTION_CLOSE)); + + /* Default Route */ + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, + SECTION_OPEN "Default Route" CONTENT_OPEN)); + + memset(ipaddr_buf, 0, IPADDR_BUF_LEN); + cc26xx_web_demo_ipaddr_sprintf(ipaddr_buf, IPADDR_BUF_LEN, + uip_ds6_defrt_choose()); + PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "%s", ipaddr_buf)); + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, CONTENT_CLOSE SECTION_CLOSE)); + + /* Routes */ + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, SECTION_OPEN "Routes" CONTENT_OPEN)); + + for(s->r = uip_ds6_route_head(); s->r != NULL; + s->r = uip_ds6_route_next(s->r)) { + PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "\n")); + + memset(ipaddr_buf, 0, IPADDR_BUF_LEN); + cc26xx_web_demo_ipaddr_sprintf(ipaddr_buf, IPADDR_BUF_LEN, &s->r->ipaddr); + PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "%s", ipaddr_buf)); + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, " / %u via ", s->r->length)); + + memset(ipaddr_buf, 0, IPADDR_BUF_LEN); + cc26xx_web_demo_ipaddr_sprintf(ipaddr_buf, IPADDR_BUF_LEN, + uip_ds6_route_nexthop(s->r)); + PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "%s", ipaddr_buf)); + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, + ", lifetime=%lus", s->r->state.lifetime)); + } + + PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, + CONTENT_CLOSE SECTION_CLOSE)); + + /* Sensors */ + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, SECTION_OPEN "Sensors" CONTENT_OPEN)); + + for(s->reading = cc26xx_web_demo_sensor_first(); + s->reading != NULL; s->reading = s->reading->next) { + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "\n%s = %s %s", s->reading->descr, + s->reading->publish ? s->reading->converted : "N/A", + s->reading->units)); + } + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, CONTENT_CLOSE SECTION_CLOSE)); + + /* Footer */ + PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, SECTION_OPEN)); + PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "Page hits: %u
", + ++numtimes)); + PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "Uptime: %lu secs
", + clock_seconds())); + PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, SECTION_CLOSE)); + + PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 1, http_bottom)); + + PT_END(&s->generate_pt); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(generate_config(struct httpd_state *s)) +{ + PT_BEGIN(&s->generate_pt); + + /* Generate top matter (doctype, title, nav links etc) */ + PT_WAIT_THREAD(&s->generate_pt, + generate_top_matter(s, http_dev_cfg_page.title, + http_config_css)); + + /* Sensor Settings */ + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "

Sensors

")); + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, + "
generate_pt, + enqueue_chunk(s, 0, "method=\"post\" enctype=\"")); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "application/x-www-form-urlencoded\" ")); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "accept-charset=\"UTF-8\">")); + + for(s->reading = cc26xx_web_demo_sensor_first(); + s->reading != NULL; s->reading = s->reading->next) { + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "%s%s:%s%s", config_div_left, + s->reading->descr, config_div_close, + config_div_right)); + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "generate_pt, + enqueue_chunk(s, 0, "title=\"On\" name=\"%s\"%s>", + s->reading->form_field, + s->reading->publish ? " Checked" : "")); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "generate_pt, + enqueue_chunk(s, 0, "title=\"Off\" name=\"%s\"%s>%s", + s->reading->form_field, + s->reading->publish ? "" : " Checked", + config_div_close)); + } + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, + "")); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "
")); + + /* RSSI measurements */ +#if CC26XX_WEB_DEMO_READ_PARENT_RSSI + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "

RSSI Probing

")); + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, + "
generate_pt, + enqueue_chunk(s, 0, "method=\"post\" enctype=\"")); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "application/x-www-form-urlencoded\" ")); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "accept-charset=\"UTF-8\">")); + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "%sPeriod (secs):%s", + config_div_left, config_div_close)); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "%sgenerate_pt, + enqueue_chunk(s, 0, "value=\"%lu\" ", + (clock_time_t) + (cc26xx_web_demo_config.def_rt_ping_interval + / CLOCK_SECOND))); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, + "min=\"" RSSI_INT_MIN "\" " + "max=\"" RSSI_INT_MAX "\" " + "name=\"ping_interval\">%s", + config_div_close)); + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, + "")); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "
")); +#endif + + /* Actions */ + PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "

Actions

")); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, + "
generate_pt, + enqueue_chunk(s, 0, "method=\"post\" enctype=\"")); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "application/x-www-form-urlencoded\" ")); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "accept-charset=\"UTF-8\">")); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "")); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "")); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "
")); + + PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 1, http_bottom)); + + PT_END(&s->generate_pt); +} +/*---------------------------------------------------------------------------*/ +#if CC26XX_WEB_DEMO_MQTT_CLIENT +static +PT_THREAD(generate_mqtt_config(struct httpd_state *s)) +{ + PT_BEGIN(&s->generate_pt); + + /* Generate top matter (doctype, title, nav links etc) */ + PT_WAIT_THREAD(&s->generate_pt, + generate_top_matter(s, http_mqtt_cfg_page.title, + http_config_css)); + + /* MQTT client settings */ + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "

%s

", http_mqtt_cfg_page.title)); + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, + "
generate_pt, + enqueue_chunk(s, 0, "method=\"post\" enctype=\"")); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "application/x-www-form-urlencoded\" ")); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "accept-charset=\"UTF-8\">")); + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "%sType ID:%s", config_div_left, + config_div_close)); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "%sgenerate_pt, + enqueue_chunk(s, 0, "value=\"%s\" ", + cc26xx_web_demo_config.mqtt_config.type_id)); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "name=\"type_id\">%s", config_div_close)); + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "%sOrg ID:%s", config_div_left, + config_div_close)); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "%sgenerate_pt, + enqueue_chunk(s, 0, "value=\"%s\" ", + cc26xx_web_demo_config.mqtt_config.org_id)); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "name=\"org_id\">%s", config_div_close)); + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "%sAuth Token:%s", config_div_left, + config_div_close)); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "%sgenerate_pt, + enqueue_chunk(s, 0, "value=\"\" ")); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "name=\"auth_token\">%s", + config_div_close)); + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "%sCommand Type:%s", config_div_left, + config_div_close)); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "%sgenerate_pt, + enqueue_chunk(s, 0, "value=\"%s\" ", + cc26xx_web_demo_config.mqtt_config.cmd_type)); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "name=\"cmd_type\">%s", + config_div_close)); + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "%sEvent Type ID:%s", config_div_left, + config_div_close)); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "%sgenerate_pt, + enqueue_chunk(s, 0, "value=\"%s\" ", + cc26xx_web_demo_config.mqtt_config.event_type_id)); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "name=\"event_type_id\">%s", + config_div_close)); + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "%sInterval (secs):%s", + config_div_left, config_div_close)); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "%sgenerate_pt, + enqueue_chunk(s, 0, "value=\"%lu\" ", + (clock_time_t) + (cc26xx_web_demo_config.mqtt_config.pub_interval + / CLOCK_SECOND))); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, + "min=\"" PUB_INT_MIN "\" " + "max=\"" PUB_INT_MAX "\" " + "name=\"interval\">%s", + config_div_close)); + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "%sBroker IP:%s", config_div_left, + config_div_close)); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "%sgenerate_pt, + enqueue_chunk(s, 0, "value=\"%s\" ", + cc26xx_web_demo_config.mqtt_config.broker_ip)); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "name=\"broker_ip\">%s", + config_div_close)); + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "%sBroker Port:%s", config_div_left, + config_div_close)); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "%sgenerate_pt, + enqueue_chunk(s, 0, "value=\"%d\" ", + cc26xx_web_demo_config.mqtt_config.broker_port)); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "min=\"1\" max=\"65535\" " + "name=\"broker_port\">%s", + config_div_close)); + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, + "")); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "
")); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, + "
generate_pt, + enqueue_chunk(s, 0, "method=\"post\" enctype=\"")); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "application/x-www-form-urlencoded\" ")); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "accept-charset=\"UTF-8\">")); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "")); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "")); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "
")); + + PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 1, http_bottom)); + + PT_END(&s->generate_pt); +} +#endif +/*---------------------------------------------------------------------------*/ +#if CC26XX_WEB_DEMO_NET_UART +static +PT_THREAD(generate_net_uart_config(struct httpd_state *s)) +{ + + PT_BEGIN(&s->generate_pt); + + /* Generate top matter (doctype, title, nav links etc) */ + PT_WAIT_THREAD(&s->generate_pt, + generate_top_matter(s, http_net_cfg_page.title, + http_config_css)); + + /* Net-UART settings */ + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "

%s

", http_net_cfg_page.title)); + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, + "
generate_pt, + enqueue_chunk(s, 0, "method=\"post\" enctype=\"")); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "application/x-www-form-urlencoded\" ")); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "accept-charset=\"UTF-8\">")); + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "%sRemote IPv6:%s", config_div_left, + config_div_close)); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "%sgenerate_pt, + enqueue_chunk(s, 0, "value=\"%s\" ", + cc26xx_web_demo_config.net_uart.remote_address)); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "name=\"net_uart_ip\">%s", + config_div_close)); + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "%sRemote Port:%s", config_div_left, + config_div_close)); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "%sgenerate_pt, + enqueue_chunk(s, 0, "value=\"%u\" ", + cc26xx_web_demo_config.net_uart.remote_port)); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "min=\"1\" max=\"65535\" " + "name=\"net_uart_port\">%s", + config_div_close)); + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "%s%s:%s%s", config_div_left, + "Enable", config_div_close, + config_div_right)); + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "generate_pt, + enqueue_chunk(s, 0, "title=\"On\" name=\"net_uart_on\"%s>", + cc26xx_web_demo_config.net_uart.enable ? + " Checked" : "")); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "generate_pt, + enqueue_chunk(s, 0, "title=\"Off\" name=\"net_uart_on\"" + "%s>%s", + cc26xx_web_demo_config.net_uart.enable ? + "" : " Checked", config_div_close)); + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, + "")); + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "
")); + + PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 1, http_bottom)); + + PT_END(&s->generate_pt); +} +#endif +/*---------------------------------------------------------------------------*/ +static void +lock_obtain(struct httpd_state *s) +{ + if(lock == NULL) { + lock = s; + } +} +/*---------------------------------------------------------------------------*/ +static void +lock_release(struct httpd_state *s) +{ + if(lock == s) { + lock = NULL; + } +} +/*---------------------------------------------------------------------------*/ +static void +parse_post_request_chunk(char *buf, int buf_len, int last_chunk) +{ + int i; + int finish; + + for(i = 0; i < buf_len; i++) { + switch(state) { + case PARSE_POST_STATE_INIT: + state = PARSE_POST_STATE_MORE; + /* continue */ + case PARSE_POST_STATE_MORE: + memset(key, 0, PARSE_POST_BUF_SIZES); + memset(val, 0, PARSE_POST_BUF_SIZES); + memset(val_escaped, 0, PARSE_POST_BUF_SIZES); + key_len = 0; + val_len = 0; + state = PARSE_POST_STATE_READING_KEY; + /* continue */ + case PARSE_POST_STATE_READING_KEY: + if(buf[i] == ISO_equal) { + state = PARSE_POST_STATE_READING_VAL; + } else if(buf[i] == ISO_amp) { + /* Don't accept an amp while reading a key */ + state = PARSE_POST_STATE_ERROR; + } else { + /* Make sure we don't overshoot key's boundary */ + if(key_len <= PARSE_POST_MAX_POS) { + key[key_len] = buf[i]; + key_len++; + } else { + /* Not enough space for the key. Abort */ + state = PARSE_POST_STATE_ERROR; + } + } + break; + case PARSE_POST_STATE_READING_VAL: + finish = 0; + if(buf[i] == ISO_amp) { + finish = 1; + } else if(buf[i] == ISO_equal) { + /* Don't accept an '=' while reading a val */ + state = PARSE_POST_STATE_ERROR; + } else { + /* Make sure we don't overshoot key's boundary */ + if(val_len <= PARSE_POST_MAX_POS) { + val[val_len] = buf[i]; + val_len++; + /* Last character of the last chunk */ + if((i == buf_len - 1) && (last_chunk == 1)) { + finish = 1; + } + } else { + /* Not enough space for the value. Abort */ + state = PARSE_POST_STATE_ERROR; + } + } + + if(finish == 1) { + /* + * Done reading a key=value pair, either because we encountered an amp + * or because we reached the end of the message body. + * + * First, unescape the value. + * + * Then invoke handlers. We will bail out with PARSE_POST_STATE_ERROR, + * unless the key-val gets correctly processed + */ + url_unescape(val, val_len, val_escaped, PARSE_POST_BUF_SIZES); + val_len = strlen(val_escaped); + + for(handler = list_head(post_handlers); handler != NULL; + handler = list_item_next((void *)handler)) { + if(handler->handler != NULL) { + finish = handler->handler(key, key_len, val_escaped, val_len); + } + if(finish == HTTPD_SIMPLE_POST_HANDLER_ERROR) { + state = PARSE_POST_STATE_ERROR; + break; + } else if(finish == HTTPD_SIMPLE_POST_HANDLER_OK) { + /* Restart the state machine to expect the next pair */ + state = PARSE_POST_STATE_MORE; + + /* + * At least one handler returned OK, therefore we must generate a + * new config event when we're done. + */ + config_ok = 1; + break; + } + /* Else, continue */ + } + } + break; + case PARSE_POST_STATE_ERROR: + /* If we entered the error state earlier, do nothing */ + return; + default: + break; + } + } +} +/*---------------------------------------------------------------------------*/ +static httpd_simple_script_t +get_script(const char *name) +{ + page_t *page; + + for(page = list_head(pages_list); page != NULL; + page = list_item_next(page)) { + if(strncmp(name, page->filename, strlen(page->filename)) == 0) { + return page->script; + } + } + + return NULL; +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(send_string(struct httpd_state *s, const char *str)) +{ + PSOCK_BEGIN(&s->sout); + + SEND_STRING(&s->sout, str); + + PSOCK_END(&s->sout); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(send_headers(struct httpd_state *s, const char *statushdr, + const char *content_type, const char *redir, + const char **additional)) +{ + PT_BEGIN(&s->generate_pt); + + PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, statushdr)); + + for(s->ptr = http_header_srv_str; *(s->ptr) != NULL; s->ptr++) { + PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, *(s->ptr))); + } + + if(redir) { + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "Location: %s\r\n", redir)); + } + + if(additional) { + for(s->ptr = additional; *(s->ptr) != NULL; s->ptr++) { + PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, *(s->ptr))); + } + } + + PT_WAIT_THREAD(&s->generate_pt, + enqueue_chunk(s, 0, "Content-type: %s; ", content_type)); + + PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 1, "charset=UTF-8\r\n\r\n")); + + PT_END(&s->generate_pt); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(handle_output(struct httpd_state *s)) +{ + PT_BEGIN(&s->outputpt); + + s->script = NULL; + + PT_INIT(&s->generate_pt); + PT_INIT(&s->top_matter_pt); + + if(s->request_type == REQUEST_TYPE_POST) { + if(s->return_code == RETURN_CODE_OK) { + PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_302, + http_content_type_plain, + s->filename, + NULL)); + } else if(s->return_code == RETURN_CODE_LR) { + PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_411, + http_content_type_plain, + NULL, + http_header_con_close)); + PT_WAIT_THREAD(&s->outputpt, send_string(s, "Content-Length Required\n")); + } else if(s->return_code == RETURN_CODE_TL) { + PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_413, + http_content_type_plain, + NULL, + http_header_con_close)); + PT_WAIT_THREAD(&s->outputpt, send_string(s, "Content-Length too Large\n")); + } else if(s->return_code == RETURN_CODE_SU) { + PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_503, + http_content_type_plain, + NULL, + http_header_con_close)); + PT_WAIT_THREAD(&s->outputpt, send_string(s, "Service Unavailable\n")); + } else { + PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_400, + http_content_type_plain, + NULL, + http_header_con_close)); + PT_WAIT_THREAD(&s->outputpt, send_string(s, "Bad Request\n")); + } + } else if(s->request_type == REQUEST_TYPE_GET) { + s->script = get_script(&s->filename[1]); + if(s->script == NULL) { + strncpy(s->filename, "/notfound.html", sizeof(s->filename)); + PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_404, + http_content_type_html, + NULL, + http_header_con_close)); + PT_WAIT_THREAD(&s->outputpt, + send_string(s, NOT_FOUND)); + uip_close(); + PT_EXIT(&s->outputpt); + } else { + PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_200, + http_content_type_html, + NULL, + http_header_con_close)); + PT_WAIT_THREAD(&s->outputpt, s->script(s)); + } + } + s->script = NULL; + PSOCK_CLOSE(&s->sout); + PT_END(&s->outputpt); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(handle_input(struct httpd_state *s)) +{ + PSOCK_BEGIN(&s->sin); + + PSOCK_READTO(&s->sin, ISO_space); + + if(strncasecmp(s->inputbuf, http_get, 4) == 0) { + s->request_type = REQUEST_TYPE_GET; + PSOCK_READTO(&s->sin, ISO_space); + + if(s->inputbuf[0] != ISO_slash) { + PSOCK_CLOSE_EXIT(&s->sin); + } + + if(s->inputbuf[1] == ISO_space) { + strncpy(s->filename, http_index_html, sizeof(s->filename)); + } else { + s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0; + strncpy(s->filename, s->inputbuf, sizeof(s->filename)); + } + } else if(strncasecmp(s->inputbuf, http_post, 5) == 0) { + s->request_type = REQUEST_TYPE_POST; + PSOCK_READTO(&s->sin, ISO_space); + + if(s->inputbuf[0] != ISO_slash) { + PSOCK_CLOSE_EXIT(&s->sin); + } + + s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0; + strncpy(s->filename, s->inputbuf, sizeof(s->filename)); + + /* POST: Read out the rest of the line and ignore it */ + PSOCK_READTO(&s->sin, ISO_nl); + + /* + * Start parsing headers. We look for Content-Length and ignore everything + * else until we hit the start of the message body. + * + * We will return 411 if the client doesn't send Content-Length and 413 + * if Content-Length is too high + */ + s->content_length = 0; + s->return_code = RETURN_CODE_LR; + do { + s->inputbuf[PSOCK_DATALEN(&s->sin)] = 0; + /* We anticipate a content length */ + if((PSOCK_DATALEN(&s->sin) > 14) && + strncasecmp(s->inputbuf, "Content-Length:", 15) == 0) { + char *val_start = &s->inputbuf[15]; + s->content_length = atoi(val_start); + + /* So far so good */ + s->return_code = RETURN_CODE_OK; + } + PSOCK_READTO(&s->sin, ISO_nl); + } while(PSOCK_DATALEN(&s->sin) != 2); + + /* + * Done reading headers. + * Reject content length greater than CONTENT_LENGTH_MAX bytes + */ + if(s->content_length > CONTENT_LENGTH_MAX) { + s->content_length = 0; + s->return_code = RETURN_CODE_TL; + } + + if(s->return_code == RETURN_CODE_OK) { + /* Acceptable Content Length. Try to obtain a lock */ + lock_obtain(s); + + if(lock == s) { + state = PARSE_POST_STATE_INIT; + } else { + s->return_code = RETURN_CODE_SU; + } + } + + /* Parse the message body, unless we have detected an error. */ + while(s->content_length > 0 && lock == s && + s->return_code == RETURN_CODE_OK) { + PSOCK_READBUF_LEN(&s->sin, s->content_length); + s->content_length -= PSOCK_DATALEN(&s->sin); + + /* Parse the message body */ + parse_post_request_chunk(s->inputbuf, PSOCK_DATALEN(&s->sin), + (s->content_length == 0)); + if(state == PARSE_POST_STATE_ERROR) { + /* Could not parse: Bad Request and stop parsing */ + s->return_code = RETURN_CODE_BR; + } + } + + /* + * Done. If our return code is OK but the state machine is not in + * STATE_MORE, it means that the message body ended half-way reading a key + * or value. Set 'Bad Request' + */ + if(s->return_code == RETURN_CODE_OK && state != PARSE_POST_STATE_MORE) { + s->return_code = RETURN_CODE_BR; + } + + /* If the flag is set, we had at least 1 configuration value accepted */ + if(config_ok) { + process_post(PROCESS_BROADCAST, httpd_simple_event_new_config, NULL); + } + config_ok = 0; + + lock_release(s); + } else { + PSOCK_CLOSE_EXIT(&s->sin); + } + + s->state = STATE_OUTPUT; + + while(1) { + PSOCK_READTO(&s->sin, ISO_nl); + } + + PSOCK_END(&s->sin); +} +/*---------------------------------------------------------------------------*/ +static void +handle_connection(struct httpd_state *s) +{ + handle_input(s); + if(s->state == STATE_OUTPUT) { + handle_output(s); + } +} +/*---------------------------------------------------------------------------*/ +static void +appcall(void *state) +{ + struct httpd_state *s = (struct httpd_state *)state; + + if(uip_closed() || uip_aborted() || uip_timedout()) { + if(s != NULL) { + memset(s, 0, sizeof(struct httpd_state)); + memb_free(&conns, s); + } + } else if(uip_connected()) { + s = (struct httpd_state *)memb_alloc(&conns); + if(s == NULL) { + uip_abort(); + return; + } + tcp_markconn(uip_conn, s); + PSOCK_INIT(&s->sin, (uint8_t *)s->inputbuf, sizeof(s->inputbuf) - 1); + PSOCK_INIT(&s->sout, (uint8_t *)s->inputbuf, sizeof(s->inputbuf) - 1); + PT_INIT(&s->outputpt); + s->script = NULL; + s->state = STATE_WAITING; + timer_set(&s->timer, CLOCK_SECOND * 10); + handle_connection(s); + } else if(s != NULL) { + if(uip_poll()) { + if(timer_expired(&s->timer)) { + uip_abort(); + memset(s, 0, sizeof(struct httpd_state)); + memb_free(&conns, s); + } + } else { + timer_restart(&s->timer); + } + handle_connection(s); + } else { + uip_abort(); + } +} +/*---------------------------------------------------------------------------*/ +static void +init(void) +{ + tcp_listen(UIP_HTONS(80)); + memb_init(&conns); + + list_add(pages_list, &http_index_page); + list_add(pages_list, &http_dev_cfg_page); + +#if CC26XX_WEB_DEMO_NET_UART + list_add(pages_list, &http_net_cfg_page); +#endif + +#if CC26XX_WEB_DEMO_MQTT_CLIENT + list_add(pages_list, &http_mqtt_cfg_page); +#endif +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(httpd_simple_process, ev, data) +{ + PROCESS_BEGIN(); + + printf("CC26XX Web Server\n"); + + httpd_simple_event_new_config = process_alloc_event(); + + init(); + + snprintf(http_mqtt_a, IBM_QUICKSTART_LINK_LEN, + "[ IBM Quickstart ]", + linkaddr_node_addr.u8[0], linkaddr_node_addr.u8[1], + linkaddr_node_addr.u8[2], linkaddr_node_addr.u8[5], + linkaddr_node_addr.u8[6], linkaddr_node_addr.u8[7]); + + while(1) { + PROCESS_WAIT_EVENT_UNTIL(ev == tcpip_event); + appcall(data); + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +/** + * @} + */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/httpd-simple.h b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/httpd-simple.h new file mode 100644 index 000000000..25b8db3e5 --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/httpd-simple.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2010, Swedish Institute of Computer Science. + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + * + */ +/*---------------------------------------------------------------------------*/ +/** + * \file + * Header file for the HTTPD of the cc26xx web demo example. + * \author + * Adam Dunkels + * Niclas Finne + * Joakim Eriksson + * Texas Instruments Incorporated - http://www.ti.com/ + */ +/*---------------------------------------------------------------------------*/ +#ifndef HTTPD_SIMPLE_H_ +#define HTTPD_SIMPLE_H_ +/*---------------------------------------------------------------------------*/ +#include "contiki-net.h" +#include "sys/process.h" +#include "cc26xx-web-demo.h" +/*---------------------------------------------------------------------------*/ +/* Ideally a multiple of TCP_MSS */ +#ifdef HTTPD_SIMPLE_CONF_MAIN_BUF_SIZE +#define HTTPD_SIMPLE_MAIN_BUF_SIZE HTTPD_SIMPLE_CONF_MAIN_BUF_SIZE +#else +#define HTTPD_SIMPLE_MAIN_BUF_SIZE UIP_TCP_MSS +#endif +/*---------------------------------------------------------------------------*/ +#define HTTPD_PATHLEN 16 +#define HTTPD_INBUF_LEN (HTTPD_PATHLEN + 10) + +#define TMP_BUF_SIZE (UIP_TCP_MSS + 1) +/*---------------------------------------------------------------------------*/ +/* POST request handlers */ +#define HTTPD_SIMPLE_POST_HANDLER_OK 1 +#define HTTPD_SIMPLE_POST_HANDLER_UNKNOWN 0 +#define HTTPD_SIMPLE_POST_HANDLER_ERROR 0xFFFFFFFF + +/** + * \brief Datatype for a handler which can process incoming POST requests + * \param key The configuration key to be updated + * \param key_len The length of the key argument + * \param val The new configuration value for key + * \param val_len The length of the value argument + * + * \return 1: HTTPD_SIMPLE_POST_HANDLER_OK if the function can handle the + * request, HTTPD_SIMPLE_POST_HANDLER_UNKNOWN if it does not know how to handle + * it. HTTPD_SIMPLE_POST_HANDLER_ERROR if it does know how to handle it but + * the request was malformed. + */ +typedef struct httpd_simple_post_handler { + struct httpd_simple_post_handler *next; + int (*handler)(char *key, int key_len, char *val, int val_len); +} httpd_simple_post_handler_t; + +/* Declare a handler */ +#define HTTPD_SIMPLE_POST_HANDLER(name, fp) \ + httpd_simple_post_handler_t name##_handler = { NULL, fp } + +/** + * \brief Register a handler for POST requests + * \param h A pointer to the handler structure + */ +void httpd_simple_register_post_handler(httpd_simple_post_handler_t *h); +/*---------------------------------------------------------------------------*/ +/* + * An event generated by the HTTPD when a new configuration request has been + * received + */ +extern process_event_t httpd_simple_event_new_config; +/*---------------------------------------------------------------------------*/ +PROCESS_NAME(httpd_simple_process); +/*---------------------------------------------------------------------------*/ +#endif /* HTTPD_SIMPLE_H_ */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/mqtt-client.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/mqtt-client.c new file mode 100644 index 000000000..7562fb89a --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/mqtt-client.c @@ -0,0 +1,925 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/** + * \addtogroup cc26xx-web-demo + * @{ + * + * \file + * MQTT/IBM cloud service client for the CC26XX web demo. + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "net/routing/routing.h" +#include "mqtt.h" +#include "net/ipv6/uip.h" +#include "net/ipv6/uip-icmp6.h" +#include "sys/etimer.h" +#include "sys/ctimer.h" +#include "lib/sensors.h" +#include "dev/button-hal.h" +#include "board-peripherals.h" +#include "cc26xx-web-demo.h" +#include "dev/leds.h" +#include "mqtt-client.h" +#include "httpd-simple.h" + +#include +#include +/*---------------------------------------------------------------------------*/ +/* + * 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. + * + * If the node has a broker IP setting saved on flash, this value here will + * get ignored + */ +static const char *broker_ip = "0064:ff9b:0000:0000:0000:0000:b8ac:7cbd"; +/*---------------------------------------------------------------------------*/ +/* + * A timeout used when waiting for something to happen (e.g. to connect or to + * disconnect) + */ +#define STATE_MACHINE_PERIODIC (CLOCK_SECOND >> 1) +/*---------------------------------------------------------------------------*/ +/* Provide visible feedback via LEDS during various states */ +/* When connecting to broker */ +#define CONNECTING_LED_DURATION (CLOCK_SECOND >> 3) + +/* Each time we try to publish */ +#define PUBLISH_LED_ON_DURATION (CLOCK_SECOND) +/*---------------------------------------------------------------------------*/ +/* Connections and reconnections */ +#define RETRY_FOREVER 0xFF +#define RECONNECT_INTERVAL (CLOCK_SECOND * 2) + +/* + * Number of times to try reconnecting to the broker. + * Can be a limited number (e.g. 3, 10 etc) or can be set to RETRY_FOREVER + */ +#define RECONNECT_ATTEMPTS 5 +#define CONNECTION_STABLE_TIME (CLOCK_SECOND * 5) +#define NEW_CONFIG_WAIT_INTERVAL (CLOCK_SECOND * 20) +static struct timer connection_life; +static uint8_t connect_attempt; +/*---------------------------------------------------------------------------*/ +/* Various states */ +static uint8_t state; +#define MQTT_CLIENT_STATE_INIT 0 +#define MQTT_CLIENT_STATE_REGISTERED 1 +#define MQTT_CLIENT_STATE_CONNECTING 2 +#define MQTT_CLIENT_STATE_CONNECTED 3 +#define MQTT_CLIENT_STATE_PUBLISHING 4 +#define MQTT_CLIENT_STATE_DISCONNECTED 5 +#define MQTT_CLIENT_STATE_NEWCONFIG 6 +#define MQTT_CLIENT_STATE_CONFIG_ERROR 0xFE +#define MQTT_CLIENT_STATE_ERROR 0xFF +/*---------------------------------------------------------------------------*/ +/* Maximum TCP segment size for outgoing segments of our socket */ +#define MQTT_CLIENT_MAX_SEGMENT_SIZE 32 +/*---------------------------------------------------------------------------*/ +/* + * Buffers for Client ID and Topic. + * Make sure they are large enough to hold the entire respective string + * + * d:quickstart:status:EUI64 is 32 bytes long + * iot-2/evt/status/fmt/json is 25 bytes + * We also need space for the null termination + */ +#define BUFFER_SIZE 64 +static char client_id[BUFFER_SIZE]; +static char pub_topic[BUFFER_SIZE]; +static char sub_topic[BUFFER_SIZE]; +/*---------------------------------------------------------------------------*/ +/* + * The main MQTT buffers. + * We will need to increase if we start publishing more data. + */ +#define APP_BUFFER_SIZE 512 +static struct mqtt_connection conn; +static char app_buffer[APP_BUFFER_SIZE]; +/*---------------------------------------------------------------------------*/ +#define QUICKSTART "quickstart" +/*---------------------------------------------------------------------------*/ +static struct mqtt_message *msg_ptr = 0; +static struct etimer publish_periodic_timer; +static struct ctimer ct; +static char *buf_ptr; +static uint16_t seq_nr_value = 0; +/*---------------------------------------------------------------------------*/ +static uip_ip6addr_t def_route; +/*---------------------------------------------------------------------------*/ +/* Parent RSSI functionality */ +extern int def_rt_rssi; +/*---------------------------------------------------------------------------*/ +const static cc26xx_web_demo_sensor_reading_t *reading; +/*---------------------------------------------------------------------------*/ +mqtt_client_config_t *conf; +/*---------------------------------------------------------------------------*/ +PROCESS(mqtt_client_process, "CC26XX MQTT Client"); +/*---------------------------------------------------------------------------*/ +static void +publish_led_off(void *d) +{ + leds_off(CC26XX_WEB_DEMO_STATUS_LED); +} +/*---------------------------------------------------------------------------*/ +static void +new_net_config(void) +{ + /* + * We got a new configuration over the net. + * + * Disconnect from the current broker and stop the periodic timer. + * + * When the source of the new configuration is done, we will get notified + * via an event. + */ + if(state == MQTT_CLIENT_STATE_NEWCONFIG) { + return; + } + + state = MQTT_CLIENT_STATE_NEWCONFIG; + + etimer_stop(&publish_periodic_timer); + mqtt_disconnect(&conn); +} +/*---------------------------------------------------------------------------*/ +static int +org_id_post_handler(char *key, int key_len, char *val, int val_len) +{ + int rv = HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; + if(key_len != strlen("org_id") || + strncasecmp(key, "org_id", strlen("org_id")) != 0) { + /* Not ours */ + return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; + } + + if(val_len > MQTT_CLIENT_CONFIG_ORG_ID_LEN) { + /* Ours but bad value */ + rv = HTTPD_SIMPLE_POST_HANDLER_ERROR; + } else { + memset(conf->org_id, 0, MQTT_CLIENT_CONFIG_ORG_ID_LEN); + memcpy(conf->org_id, val, val_len); + + rv = HTTPD_SIMPLE_POST_HANDLER_OK; + } + + new_net_config(); + + return rv; +} +/*---------------------------------------------------------------------------*/ +static int +type_id_post_handler(char *key, int key_len, char *val, int val_len) +{ + int rv = HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; + if(key_len != strlen("type_id") || + strncasecmp(key, "type_id", strlen("type_id")) != 0) { + /* Not ours */ + return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; + } + + if(val_len > MQTT_CLIENT_CONFIG_TYPE_ID_LEN) { + /* Ours but bad value */ + rv = HTTPD_SIMPLE_POST_HANDLER_ERROR; + } else { + memset(conf->type_id, 0, MQTT_CLIENT_CONFIG_TYPE_ID_LEN); + memcpy(conf->type_id, val, val_len); + + rv = HTTPD_SIMPLE_POST_HANDLER_OK; + } + + new_net_config(); + + return rv; +} +/*---------------------------------------------------------------------------*/ +static int +event_type_id_post_handler(char *key, int key_len, char *val, int val_len) +{ + int rv = HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; + if(key_len != strlen("event_type_id") || + strncasecmp(key, "event_type_id", strlen("event_type_id")) != 0) { + /* Not ours */ + return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; + } + + if(val_len > MQTT_CLIENT_CONFIG_EVENT_TYPE_ID_LEN) { + /* Ours but bad value */ + rv = HTTPD_SIMPLE_POST_HANDLER_ERROR; + } else { + memset(conf->event_type_id, 0, MQTT_CLIENT_CONFIG_EVENT_TYPE_ID_LEN); + memcpy(conf->event_type_id, val, val_len); + + rv = HTTPD_SIMPLE_POST_HANDLER_OK; + } + + new_net_config(); + + return rv; +} +/*---------------------------------------------------------------------------*/ +static int +cmd_type_post_handler(char *key, int key_len, char *val, int val_len) +{ + int rv = HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; + if(key_len != strlen("cmd_type") || + strncasecmp(key, "cmd_type", strlen("cmd_type")) != 0) { + /* Not ours */ + return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; + } + + if(val_len > MQTT_CLIENT_CONFIG_CMD_TYPE_LEN) { + /* Ours but bad value */ + rv = HTTPD_SIMPLE_POST_HANDLER_ERROR; + } else { + memset(conf->cmd_type, 0, MQTT_CLIENT_CONFIG_CMD_TYPE_LEN); + memcpy(conf->cmd_type, val, val_len); + + rv = HTTPD_SIMPLE_POST_HANDLER_OK; + } + + new_net_config(); + + return rv; +} +/*---------------------------------------------------------------------------*/ +static int +auth_token_post_handler(char *key, int key_len, char *val, int val_len) +{ + int rv = HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; + if(key_len != strlen("auth_token") || + strncasecmp(key, "auth_token", strlen("auth_token")) != 0) { + /* Not ours */ + return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; + } + + if(val_len > MQTT_CLIENT_CONFIG_AUTH_TOKEN_LEN) { + /* Ours but bad value */ + rv = HTTPD_SIMPLE_POST_HANDLER_ERROR; + } else { + memset(conf->auth_token, 0, MQTT_CLIENT_CONFIG_AUTH_TOKEN_LEN); + memcpy(conf->auth_token, val, val_len); + + rv = HTTPD_SIMPLE_POST_HANDLER_OK; + } + + new_net_config(); + + return rv; +} +/*---------------------------------------------------------------------------*/ +static int +interval_post_handler(char *key, int key_len, char *val, int val_len) +{ + int rv = 0; + + if(key_len != strlen("interval") || + strncasecmp(key, "interval", strlen("interval")) != 0) { + /* Not ours */ + return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; + } + + rv = atoi(val); + + if(rv < MQTT_CLIENT_PUBLISH_INTERVAL_MIN || + rv > MQTT_CLIENT_PUBLISH_INTERVAL_MAX) { + return HTTPD_SIMPLE_POST_HANDLER_ERROR; + } + + conf->pub_interval = rv * CLOCK_SECOND; + + return HTTPD_SIMPLE_POST_HANDLER_OK; +} +/*---------------------------------------------------------------------------*/ +static int +port_post_handler(char *key, int key_len, char *val, int val_len) +{ + int rv = 0; + + if(key_len != strlen("broker_port") || + strncasecmp(key, "broker_port", strlen("broker_port")) != 0) { + /* Not ours */ + return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; + } + + rv = atoi(val); + + if(rv <= 65535 && rv > 0) { + conf->broker_port = rv; + } else { + return HTTPD_SIMPLE_POST_HANDLER_ERROR; + } + + new_net_config(); + + return HTTPD_SIMPLE_POST_HANDLER_OK; +} +/*---------------------------------------------------------------------------*/ +static int +ip_addr_post_handler(char *key, int key_len, char *val, int val_len) +{ + int rv = HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; + + if(key_len != strlen("broker_ip") || + strncasecmp(key, "broker_ip", strlen("broker_ip")) != 0) { + /* Not ours */ + return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; + } + + if(val_len > MQTT_CLIENT_CONFIG_IP_ADDR_STR_LEN) { + /* Ours but bad value */ + rv = HTTPD_SIMPLE_POST_HANDLER_ERROR; + } else { + memset(conf->broker_ip, 0, MQTT_CLIENT_CONFIG_IP_ADDR_STR_LEN); + memcpy(conf->broker_ip, val, val_len); + + rv = HTTPD_SIMPLE_POST_HANDLER_OK; + } + + new_net_config(); + + return rv; +} +/*---------------------------------------------------------------------------*/ +static int +reconnect_post_handler(char *key, int key_len, char *val, int val_len) +{ + if(key_len != strlen("reconnect") || + strncasecmp(key, "reconnect", strlen("reconnect")) != 0) { + /* Not ours */ + return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; + } + + new_net_config(); + + return HTTPD_SIMPLE_POST_HANDLER_OK; +} +/*---------------------------------------------------------------------------*/ +HTTPD_SIMPLE_POST_HANDLER(org_id, org_id_post_handler); +HTTPD_SIMPLE_POST_HANDLER(type_id, type_id_post_handler); +HTTPD_SIMPLE_POST_HANDLER(event_type_id, event_type_id_post_handler); +HTTPD_SIMPLE_POST_HANDLER(cmd_type, cmd_type_post_handler); +HTTPD_SIMPLE_POST_HANDLER(auth_token, auth_token_post_handler); +HTTPD_SIMPLE_POST_HANDLER(ip_addr, ip_addr_post_handler); +HTTPD_SIMPLE_POST_HANDLER(port, port_post_handler); +HTTPD_SIMPLE_POST_HANDLER(interval, interval_post_handler); +HTTPD_SIMPLE_POST_HANDLER(reconnect, reconnect_post_handler); +/*---------------------------------------------------------------------------*/ +static void +pub_handler(const char *topic, uint16_t topic_len, const uint8_t *chunk, + uint16_t chunk_len) +{ + DBG("Pub Handler: topic='%s' (len=%u), chunk_len=%u\n", topic, topic_len, + chunk_len); + + /* If we don't like the length, ignore */ + if(topic_len != 23 || chunk_len != 1) { + printf("Incorrect topic or chunk len. Ignored\n"); + return; + } + + /* If the format != json, ignore */ + if(strncmp(&topic[topic_len - 4], "json", 4) != 0) { + printf("Incorrect format\n"); + } + + if(strncmp(&topic[10], "leds", 4) == 0) { + if(chunk[0] == '1') { + leds_on(LEDS_RED); + } else if(chunk[0] == '0') { + leds_off(LEDS_RED); + } + return; + } + +#if BOARD_SENSORTAG + if(strncmp(&topic[10], "buzz", 4) == 0) { + if(chunk[0] == '1') { + buzzer_start(1000); + } else if(chunk[0] == '0') { + buzzer_stop(); + } + return; + } +#endif +} +/*---------------------------------------------------------------------------*/ +static void +mqtt_event(struct mqtt_connection *m, mqtt_event_t event, void *data) +{ + switch(event) { + case MQTT_EVENT_CONNECTED: { + DBG("APP - Application has a MQTT connection\n"); + timer_set(&connection_life, CONNECTION_STABLE_TIME); + state = MQTT_CLIENT_STATE_CONNECTED; + break; + } + case MQTT_EVENT_DISCONNECTED: { + DBG("APP - MQTT Disconnect. Reason %u\n", *((mqtt_event_t *)data)); + + /* Do nothing if the disconnect was the result of an incoming config */ + if(state != MQTT_CLIENT_STATE_NEWCONFIG) { + state = MQTT_CLIENT_STATE_DISCONNECTED; + process_poll(&mqtt_client_process); + } + break; + } + case MQTT_EVENT_PUBLISH: { + msg_ptr = data; + + /* Implement first_flag in publish message? */ + if(msg_ptr->first_chunk) { + msg_ptr->first_chunk = 0; + DBG("APP - Application received a publish on topic '%s'. Payload " + "size is %i bytes. Content:\n\n", + msg_ptr->topic, msg_ptr->payload_length); + } + + pub_handler(msg_ptr->topic, strlen(msg_ptr->topic), msg_ptr->payload_chunk, + msg_ptr->payload_length); + break; + } + case MQTT_EVENT_SUBACK: { + DBG("APP - Application is subscribed to topic successfully\n"); + break; + } + case MQTT_EVENT_UNSUBACK: { + DBG("APP - Application is unsubscribed to topic successfully\n"); + break; + } + case MQTT_EVENT_PUBACK: { + DBG("APP - Publishing complete.\n"); + break; + } + default: + DBG("APP - Application got a unhandled MQTT event: %i\n", event); + break; + } +} +/*---------------------------------------------------------------------------*/ +static int +construct_pub_topic(void) +{ + int len = snprintf(pub_topic, BUFFER_SIZE, "iot-2/evt/%s/fmt/json", + conf->event_type_id); + + /* len < 0: Error. Len >= BUFFER_SIZE: Buffer too small */ + if(len < 0 || len >= BUFFER_SIZE) { + printf("Pub Topic: %d, Buffer %d\n", len, BUFFER_SIZE); + return 0; + } + + return 1; +} +/*---------------------------------------------------------------------------*/ +static int +construct_sub_topic(void) +{ + int len = snprintf(sub_topic, BUFFER_SIZE, "iot-2/cmd/%s/fmt/json", + conf->cmd_type); + + /* len < 0: Error. Len >= BUFFER_SIZE: Buffer too small */ + if(len < 0 || len >= BUFFER_SIZE) { + printf("Sub Topic: %d, Buffer %d\n", len, BUFFER_SIZE); + return 0; + } + + return 1; +} +/*---------------------------------------------------------------------------*/ +static int +construct_client_id(void) +{ + int len = snprintf(client_id, BUFFER_SIZE, "d:%s:%s:%02x%02x%02x%02x%02x%02x", + conf->org_id, conf->type_id, + linkaddr_node_addr.u8[0], linkaddr_node_addr.u8[1], + linkaddr_node_addr.u8[2], linkaddr_node_addr.u8[5], + linkaddr_node_addr.u8[6], linkaddr_node_addr.u8[7]); + + /* len < 0: Error. Len >= BUFFER_SIZE: Buffer too small */ + if(len < 0 || len >= BUFFER_SIZE) { + printf("Client ID: %d, Buffer %d\n", len, BUFFER_SIZE); + return 0; + } + + return 1; +} +/*---------------------------------------------------------------------------*/ +static void +update_config(void) +{ + if(construct_client_id() == 0) { + /* Fatal error. Client ID larger than the buffer */ + state = MQTT_CLIENT_STATE_CONFIG_ERROR; + return; + } + + if(construct_sub_topic() == 0) { + /* Fatal error. Topic larger than the buffer */ + state = MQTT_CLIENT_STATE_CONFIG_ERROR; + return; + } + + if(construct_pub_topic() == 0) { + /* Fatal error. Topic larger than the buffer */ + state = MQTT_CLIENT_STATE_CONFIG_ERROR; + return; + } + + /* Reset the counter */ + seq_nr_value = 0; + + state = MQTT_CLIENT_STATE_INIT; + + /* + * Schedule next timer event ASAP + * + * If we entered an error state then we won't do anything when it fires. + * + * Since the error at this stage is a config error, we will only exit this + * error state if we get a new config. + */ + etimer_set(&publish_periodic_timer, 0); + + return; +} +/*---------------------------------------------------------------------------*/ +static int +init_config() +{ + /* Populate configuration with default values */ + memset(conf, 0, sizeof(mqtt_client_config_t)); + + memcpy(conf->org_id, CC26XX_WEB_DEMO_DEFAULT_ORG_ID, 11); + memcpy(conf->type_id, CC26XX_WEB_DEMO_DEFAULT_TYPE_ID, 7); + memcpy(conf->event_type_id, CC26XX_WEB_DEMO_DEFAULT_EVENT_TYPE_ID, 7); + memcpy(conf->broker_ip, broker_ip, strlen(broker_ip)); + memcpy(conf->cmd_type, CC26XX_WEB_DEMO_DEFAULT_SUBSCRIBE_CMD_TYPE, 1); + + conf->broker_port = CC26XX_WEB_DEMO_DEFAULT_BROKER_PORT; + conf->pub_interval = CC26XX_WEB_DEMO_DEFAULT_PUBLISH_INTERVAL; + + return 1; +} +/*---------------------------------------------------------------------------*/ +static void +register_http_post_handlers(void) +{ + httpd_simple_register_post_handler(&org_id_handler); + httpd_simple_register_post_handler(&type_id_handler); + httpd_simple_register_post_handler(&event_type_id_handler); + httpd_simple_register_post_handler(&cmd_type_handler); + httpd_simple_register_post_handler(&auth_token_handler); + httpd_simple_register_post_handler(&interval_handler); + httpd_simple_register_post_handler(&port_handler); + httpd_simple_register_post_handler(&ip_addr_handler); + httpd_simple_register_post_handler(&reconnect_handler); +} +/*---------------------------------------------------------------------------*/ +static void +subscribe(void) +{ + /* Publish MQTT topic in IBM quickstart format */ + mqtt_status_t status; + + status = mqtt_subscribe(&conn, NULL, sub_topic, MQTT_QOS_LEVEL_0); + + DBG("APP - Subscribing!\n"); + if(status == MQTT_STATUS_OUT_QUEUE_FULL) { + DBG("APP - Tried to subscribe but command queue was full!\n"); + } +} +/*---------------------------------------------------------------------------*/ +static void +publish(void) +{ + /* Publish MQTT topic in IBM quickstart format */ + int len; + int remaining = APP_BUFFER_SIZE; + char def_rt_str[64]; + + seq_nr_value++; + + buf_ptr = app_buffer; + + len = snprintf(buf_ptr, remaining, + "{" + "\"d\":{" + "\"myName\":\"%s\"," + "\"Seq #\":%d," + "\"Uptime (sec)\":%lu", + BOARD_STRING, seq_nr_value, clock_seconds()); + + if(len < 0 || len >= remaining) { + printf("Buffer too short. Have %d, need %d + \\0\n", remaining, len); + return; + } + + remaining -= len; + buf_ptr += len; + + /* Put our Default route's string representation in a buffer */ + memset(def_rt_str, 0, sizeof(def_rt_str)); + cc26xx_web_demo_ipaddr_sprintf(def_rt_str, sizeof(def_rt_str), + uip_ds6_defrt_choose()); + + len = snprintf(buf_ptr, remaining, ",\"Def Route\":\"%s\",\"RSSI (dBm)\":%d", + def_rt_str, def_rt_rssi); + + if(len < 0 || len >= remaining) { + printf("Buffer too short. Have %d, need %d + \\0\n", remaining, len); + return; + } + remaining -= len; + buf_ptr += len; + + memcpy(&def_route, uip_ds6_defrt_choose(), sizeof(uip_ip6addr_t)); + + for(reading = cc26xx_web_demo_sensor_first(); + reading != NULL; reading = reading->next) { + if(reading->publish && reading->raw != CC26XX_SENSOR_READING_ERROR) { + len = snprintf(buf_ptr, remaining, + ",\"%s (%s)\":%s", reading->descr, reading->units, + reading->converted); + + if(len < 0 || len >= remaining) { + printf("Buffer too short. Have %d, need %d + \\0\n", remaining, len); + return; + } + remaining -= len; + buf_ptr += len; + } + } + + len = snprintf(buf_ptr, remaining, "}}"); + + if(len < 0 || len >= remaining) { + printf("Buffer too short. Have %d, need %d + \\0\n", remaining, len); + return; + } + + mqtt_publish(&conn, NULL, pub_topic, (uint8_t *)app_buffer, + strlen(app_buffer), MQTT_QOS_LEVEL_0, MQTT_RETAIN_OFF); + + DBG("APP - Publish!\n"); +} +/*---------------------------------------------------------------------------*/ +static void +connect_to_broker(void) +{ + /* Connect to MQTT server */ + mqtt_status_t conn_attempt_result = mqtt_connect(&conn, conf->broker_ip, + conf->broker_port, + conf->pub_interval * 3); + + if(conn_attempt_result == MQTT_STATUS_OK) { + state = MQTT_CLIENT_STATE_CONNECTING; + } else { + state = MQTT_CLIENT_STATE_CONFIG_ERROR; + } +} +/*---------------------------------------------------------------------------*/ +static void +state_machine(void) +{ + switch(state) { + case MQTT_CLIENT_STATE_INIT: + /* If we have just been configured register MQTT connection */ + mqtt_register(&conn, &mqtt_client_process, client_id, mqtt_event, + MQTT_CLIENT_MAX_SEGMENT_SIZE); + + /* + * If we are not using the quickstart service (thus we are an IBM + * registered device), we need to provide user name and password + */ + if(strncasecmp(conf->org_id, QUICKSTART, strlen(conf->org_id)) != 0) { + if(strlen(conf->auth_token) == 0) { + printf("User name set, but empty auth token\n"); + state = MQTT_CLIENT_STATE_ERROR; + break; + } else { + mqtt_set_username_password(&conn, "use-token-auth", + conf->auth_token); + } + } + + /* _register() will set auto_reconnect. We don't want that. */ + conn.auto_reconnect = 0; + connect_attempt = 1; + + /* + * Wipe out the default route so we'll republish it every time we switch to + * a new broker + */ + memset(&def_route, 0, sizeof(def_route)); + + state = MQTT_CLIENT_STATE_REGISTERED; + DBG("Init\n"); + /* Continue */ + case MQTT_CLIENT_STATE_REGISTERED: + if(uip_ds6_get_global(ADDR_PREFERRED) != NULL) { + /* Registered and with a public IP. Connect */ + DBG("Registered. Connect attempt %u\n", connect_attempt); + connect_to_broker(); + } + etimer_set(&publish_periodic_timer, CC26XX_WEB_DEMO_NET_CONNECT_PERIODIC); + return; + break; + case MQTT_CLIENT_STATE_CONNECTING: + leds_on(CC26XX_WEB_DEMO_STATUS_LED); + ctimer_set(&ct, CONNECTING_LED_DURATION, publish_led_off, NULL); + /* Not connected yet. Wait */ + DBG("Connecting (%u)\n", connect_attempt); + break; + case MQTT_CLIENT_STATE_CONNECTED: + /* Don't subscribe unless we are a registered device */ + if(strncasecmp(conf->org_id, QUICKSTART, strlen(conf->org_id)) == 0) { + DBG("Using 'quickstart': Skipping subscribe\n"); + state = MQTT_CLIENT_STATE_PUBLISHING; + } + /* Continue */ + case MQTT_CLIENT_STATE_PUBLISHING: + /* If the timer expired, the connection is stable. */ + if(timer_expired(&connection_life)) { + /* + * Intentionally using 0 here instead of 1: We want RECONNECT_ATTEMPTS + * attempts if we disconnect after a successful connect + */ + connect_attempt = 0; + } + + if(mqtt_ready(&conn) && conn.out_buffer_sent) { + /* Connected. Publish */ + if(state == MQTT_CLIENT_STATE_CONNECTED) { + subscribe(); + state = MQTT_CLIENT_STATE_PUBLISHING; + } else { + leds_on(CC26XX_WEB_DEMO_STATUS_LED); + ctimer_set(&ct, PUBLISH_LED_ON_DURATION, publish_led_off, NULL); + publish(); + } + etimer_set(&publish_periodic_timer, conf->pub_interval); + + DBG("Publishing\n"); + /* Return here so we don't end up rescheduling the timer */ + return; + } else { + /* + * Our publish timer fired, but some MQTT packet is already in flight + * (either not sent at all, or sent but not fully ACKd). + * + * This can mean that we have lost connectivity to our broker or that + * simply there is some network delay. In both cases, we refuse to + * trigger a new message and we wait for TCP to either ACK the entire + * packet after retries, or to timeout and notify us. + */ + DBG("Publishing... (MQTT state=%d, q=%u)\n", conn.state, + conn.out_queue_full); + } + break; + case MQTT_CLIENT_STATE_DISCONNECTED: + DBG("Disconnected\n"); + if(connect_attempt < RECONNECT_ATTEMPTS || + RECONNECT_ATTEMPTS == RETRY_FOREVER) { + /* Disconnect and backoff */ + clock_time_t interval; + mqtt_disconnect(&conn); + connect_attempt++; + + interval = connect_attempt < 3 ? RECONNECT_INTERVAL << connect_attempt : + RECONNECT_INTERVAL << 3; + + DBG("Disconnected. Attempt %u in %lu ticks\n", connect_attempt, interval); + + etimer_set(&publish_periodic_timer, interval); + + state = MQTT_CLIENT_STATE_REGISTERED; + return; + } else { + /* Max reconnect attempts reached. Enter error state */ + state = MQTT_CLIENT_STATE_ERROR; + DBG("Aborting connection after %u attempts\n", connect_attempt - 1); + } + break; + case MQTT_CLIENT_STATE_NEWCONFIG: + /* Only update config after we have disconnected or in the case of an error */ + if(conn.state == MQTT_CONN_STATE_NOT_CONNECTED || conn.state == MQTT_CONN_STATE_ERROR) { + update_config(); + DBG("New config\n"); + + /* update_config() scheduled next pass. Return */ + return; + } + break; + case MQTT_CLIENT_STATE_CONFIG_ERROR: + /* Idle away. The only way out is a new config */ + printf("Bad configuration.\n"); + return; + case MQTT_CLIENT_STATE_ERROR: + default: + leds_on(CC26XX_WEB_DEMO_STATUS_LED); + /* + * 'default' should never happen. + * + * If we enter here it's because of some error. Stop timers. The only thing + * that can bring us out is a new config event + */ + printf("Default case: State=0x%02x\n", state); + return; + } + + /* If we didn't return so far, reschedule ourselves */ + etimer_set(&publish_periodic_timer, STATE_MACHINE_PERIODIC); +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(mqtt_client_process, ev, data) +{ + + PROCESS_BEGIN(); + + printf("CC26XX MQTT Client Process\n"); + + conf = &cc26xx_web_demo_config.mqtt_config; + if(init_config() != 1) { + PROCESS_EXIT(); + } + + register_http_post_handlers(); + + update_config(); + + /* Main loop */ + while(1) { + + PROCESS_YIELD(); + + if(ev == button_hal_release_event) { + button_hal_button_t *btn = (button_hal_button_t *)data; + + if(btn->unique_id == CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER) { + if(state == MQTT_CLIENT_STATE_ERROR) { + connect_attempt = 1; + state = MQTT_CLIENT_STATE_REGISTERED; + } + } + } + + if(ev == httpd_simple_event_new_config) { + /* + * Schedule next pass in a while. When HTTPD sends us this event, it is + * also in the process of sending the config page. Wait a little before + * reconnecting, so as to not cause congestion. + */ + etimer_set(&publish_periodic_timer, NEW_CONFIG_WAIT_INTERVAL); + } + + if((ev == PROCESS_EVENT_TIMER && data == &publish_periodic_timer) || + ev == PROCESS_EVENT_POLL || + ev == cc26xx_web_demo_publish_event || + (ev == button_hal_release_event && + ((button_hal_button_t *)data)->unique_id == + CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER)) { + state_machine(); + } + + if(ev == cc26xx_web_demo_load_config_defaults) { + init_config(); + etimer_set(&publish_periodic_timer, NEW_CONFIG_WAIT_INTERVAL); + } + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +/** + * @} + */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/mqtt-client.h b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/mqtt-client.h new file mode 100644 index 000000000..ab7c08227 --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/mqtt-client.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/** + * \addtogroup cc26xx-web-demo + * @{ + * + * \file + * Header file for the CC26xx web demo MQTT client functionality + */ +/*---------------------------------------------------------------------------*/ +#ifndef MQTT_CLIENT_H_ +#define MQTT_CLIENT_H_ +/*---------------------------------------------------------------------------*/ +#define MQTT_CLIENT_CONFIG_ORG_ID_LEN 32 +#define MQTT_CLIENT_CONFIG_TYPE_ID_LEN 32 +#define MQTT_CLIENT_CONFIG_AUTH_TOKEN_LEN 32 +#define MQTT_CLIENT_CONFIG_EVENT_TYPE_ID_LEN 32 +#define MQTT_CLIENT_CONFIG_CMD_TYPE_LEN 8 +#define MQTT_CLIENT_CONFIG_IP_ADDR_STR_LEN 64 +/*---------------------------------------------------------------------------*/ +#define MQTT_CLIENT_PUBLISH_INTERVAL_MAX 86400 /* secs: 1 day */ +#define MQTT_CLIENT_PUBLISH_INTERVAL_MIN 5 /* secs */ +/*---------------------------------------------------------------------------*/ +PROCESS_NAME(mqtt_client_process); +/*---------------------------------------------------------------------------*/ +/** + * \brief Data structure declaration for the MQTT client configuration + */ +typedef struct mqtt_client_config { + char org_id[MQTT_CLIENT_CONFIG_ORG_ID_LEN]; + char type_id[MQTT_CLIENT_CONFIG_TYPE_ID_LEN]; + char auth_token[MQTT_CLIENT_CONFIG_AUTH_TOKEN_LEN]; + char event_type_id[MQTT_CLIENT_CONFIG_EVENT_TYPE_ID_LEN]; + char broker_ip[MQTT_CLIENT_CONFIG_IP_ADDR_STR_LEN]; + char cmd_type[MQTT_CLIENT_CONFIG_CMD_TYPE_LEN]; + clock_time_t pub_interval; + uint16_t broker_port; +} mqtt_client_config_t; +/*---------------------------------------------------------------------------*/ +#endif /* MQTT_CLIENT_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/net-uart.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/net-uart.c new file mode 100644 index 000000000..ca3bf8c82 --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/net-uart.c @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/** + * \addtogroup cc26xx-web-demo + * @{ + * + * \file + * A process which receives data over UART and transmits them over UDP + * to a pre-defined IPv6 address and port. It also listens on the same UDP + * port for messages, which it prints out over UART. + * + * For this example to work, you will have to modify the destination IPv6 + * address by adjusting the set_dest_addr() macro below. + * + * To listen on your linux or OS X box: + * nc -6ulkw 1 REMOTE_PORT + * + * (REMOTE_PORT should be the actual value of the define below, e.g. 7777) + * + * Once netcat is up and listening, type something to the CC26xx's terminal + * Bear in mind that the datagram will only be sent after a 0x0a (LF) char + * has been received. Therefore, if you are on Win, do NOT use PuTTY for + * this purpose, since it does not send 0x0a as part of the line end. On + * Win XP use hyperterm. On Win 7 use some other software (e.g. Tera Term, + * which can be configured to send CRLF on enter keystrokes). + * + * To send data in the other direction from your linux or OS X box: + * + * nc -6u \ REMOTE_PORT + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "sys/process.h" +#include "dev/serial-line.h" +#include "dev/cc26xx-uart.h" +#include "net/ipv6/uip.h" +#include "net/ipv6/uip-udp-packet.h" +#include "net/ipv6/uiplib.h" +#include "net-uart.h" +#include "httpd-simple.h" +#include "sys/cc.h" + +#include "ti-lib.h" + +#include +#include +#include +#include +#include +/*---------------------------------------------------------------------------*/ +#define DEBUG DEBUG_NONE +#include "net/ipv6/uip-debug.h" +/*---------------------------------------------------------------------------*/ +#define REMOTE_PORT 7777 +#define MAX_MSG_SIZE 100 + +#define set_dest_addr() uip_ip6addr(&remote_addr, \ + 0xBBBB, 0x0000, 0x0000, 0x0000, \ + 0x3E07, 0x54FF, 0xFE74, 0x4885); +/*---------------------------------------------------------------------------*/ +#define ADDRESS_CONVERSION_OK 1 +#define ADDRESS_CONVERSION_ERROR 0 +/*---------------------------------------------------------------------------*/ +static struct uip_udp_conn *udp_conn = NULL; + +static uint8_t buffer[MAX_MSG_SIZE]; +static uint8_t msg_len; +static uip_ip6addr_t remote_addr; +/*---------------------------------------------------------------------------*/ +#define IPV6_ADDR_STR_LEN 64 +/*---------------------------------------------------------------------------*/ +PROCESS(net_uart_process, "Net UART Process"); +/*---------------------------------------------------------------------------*/ +/* + * \brief Attempts to convert a string representation of an IPv6 address to a + * numeric one. + * \param buf The buffer with the string to be converted. + * \return ADDRESS_CONVERSION_OK or ADDRESS_CONVERSION_ERROR + * + * ToDo: Add support for NAT64 conversion in case the incoming address is a v4 + * This is now supported in the current master, so when we pull it in this will + * be very straightforward. + */ +static int +set_new_ip_address(char *buf) +{ + /* + * uiplib_ip6addrconv will immediately start writing into the supplied buffer + * even if it subsequently fails. Thus, pass an intermediate buffer + */ + uip_ip6addr_t tmp_addr; + + int rv = uiplib_ip6addrconv(buf, &tmp_addr); + + if(rv == ADDRESS_CONVERSION_OK) { + /* Conversion OK, copy to our main buffer */ + memcpy(&remote_addr, &tmp_addr, sizeof(remote_addr)); + + PRINTF("Updated remote address "); + PRINT6ADDR(&remote_addr); + PRINTF("\n"); + } + + return rv; +} +/*---------------------------------------------------------------------------*/ +static void +net_input(void) +{ + if(uip_newdata()) { + memset(buffer, 0, MAX_MSG_SIZE); + msg_len = MIN(uip_datalen(), MAX_MSG_SIZE - 1); + + /* Copy data */ + memcpy(buffer, uip_appdata, msg_len); + printf("%s", (char *)buffer); + } + + return; +} +/*---------------------------------------------------------------------------*/ +static void +release_uart(void) +{ + cc26xx_uart_set_input(NULL); +} +/*---------------------------------------------------------------------------*/ +static void +keep_uart_on(void) +{ + cc26xx_uart_set_input(serial_line_input_byte); +} +/*---------------------------------------------------------------------------*/ +static int +remote_port_post_handler(char *key, int key_len, char *val, int val_len) +{ + int rv; + + if(key_len != strlen("net_uart_port") || + strncasecmp(key, "net_uart_port", strlen("net_uart_port")) != 0) { + /* Not ours */ + return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; + } + + rv = atoi(val); + + if(rv <= 65535 && rv > 0) { + cc26xx_web_demo_config.net_uart.remote_port = (uint16_t)rv; + } else { + return HTTPD_SIMPLE_POST_HANDLER_ERROR; + } + + return HTTPD_SIMPLE_POST_HANDLER_OK; +} +/*---------------------------------------------------------------------------*/ +static int +remote_ipv6_post_handler(char *key, int key_len, char *val, int val_len) +{ + int rv = HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; + + if(key_len != strlen("net_uart_ip") || + strncasecmp(key, "net_uart_ip", strlen("net_uart_ip")) != 0) { + /* Not ours */ + return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; + } + + if(val_len > IPV6_ADDR_STR_LEN) { + /* Ours but bad value */ + rv = HTTPD_SIMPLE_POST_HANDLER_ERROR; + } else { + if(set_new_ip_address(val)) { + memset(cc26xx_web_demo_config.net_uart.remote_address, 0, + NET_UART_IP_ADDR_STRLEN); + memcpy(cc26xx_web_demo_config.net_uart.remote_address, val, val_len); + rv = HTTPD_SIMPLE_POST_HANDLER_OK; + } + } + + return rv; +} +/*---------------------------------------------------------------------------*/ +static int +on_off_post_handler(char *key, int key_len, char *val, int val_len) +{ + int rv; + + if(key_len != strlen("net_uart_on") || + strncasecmp(key, "net_uart_on", strlen("net_uart_on")) != 0) { + /* Not ours */ + return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; + } + + rv = atoi(val); + + /* Be pedantic: only accept 0 and 1, not just any non-zero value */ + if(rv == 0) { + cc26xx_web_demo_config.net_uart.enable = 0; + release_uart(); + } else if(rv == 1) { + cc26xx_web_demo_config.net_uart.enable = 1; + keep_uart_on(); + } else { + return HTTPD_SIMPLE_POST_HANDLER_ERROR; + } + + return HTTPD_SIMPLE_POST_HANDLER_OK; +} +/*---------------------------------------------------------------------------*/ +HTTPD_SIMPLE_POST_HANDLER(remote_port, remote_port_post_handler); +HTTPD_SIMPLE_POST_HANDLER(remote_ipv6, remote_ipv6_post_handler); +HTTPD_SIMPLE_POST_HANDLER(on_off, on_off_post_handler); +/*---------------------------------------------------------------------------*/ +static void +set_config_defaults(void) +{ + /* Set a hard-coded destination address to start with */ + set_dest_addr(); + + /* Set config defaults */ + cc26xx_web_demo_ipaddr_sprintf(cc26xx_web_demo_config.net_uart.remote_address, + NET_UART_IP_ADDR_STRLEN, &remote_addr); + cc26xx_web_demo_config.net_uart.remote_port = REMOTE_PORT; + cc26xx_web_demo_config.net_uart.enable = 1; +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(net_uart_process, ev, data) +{ + PROCESS_BEGIN(); + + printf("CC26XX Net UART Process\n"); + + set_config_defaults(); + + udp_conn = udp_new(NULL, UIP_HTONS(0), NULL); + udp_bind(udp_conn, UIP_HTONS(REMOTE_PORT)); + + if(udp_conn == NULL) { + printf("No UDP connection available, exiting the process!\n"); + PROCESS_EXIT(); + } + + httpd_simple_register_post_handler(&remote_port_handler); + httpd_simple_register_post_handler(&remote_ipv6_handler); + httpd_simple_register_post_handler(&on_off_handler); + + while(1) { + + PROCESS_YIELD(); + + if(ev == serial_line_event_message) { + /* + * If the message contains a new IP address, save it and go back to + * waiting. + */ + if(set_new_ip_address((char *)data) == ADDRESS_CONVERSION_ERROR) { + /* Not an IP address in the message. Send to current destination */ + memset(buffer, 0, MAX_MSG_SIZE); + + /* We need to add a line feed, thus never fill the entire buffer */ + msg_len = MIN(strlen(data), MAX_MSG_SIZE - 1); + memcpy(buffer, data, msg_len); + + /* Add a line feed */ + buffer[msg_len] = 0x0A; + msg_len++; + + uip_udp_packet_sendto( + udp_conn, buffer, msg_len, &remote_addr, + UIP_HTONS(cc26xx_web_demo_config.net_uart.remote_port)); + } + } else if(ev == tcpip_event) { + net_input(); + } else if(ev == cc26xx_web_demo_config_loaded_event) { + /* + * New config. Check if it's possible to update the remote address. + * The port will have been updated already + */ + set_new_ip_address(cc26xx_web_demo_config.net_uart.remote_address); + + if(cc26xx_web_demo_config.net_uart.enable == 1) { + keep_uart_on(); + } + } else if(ev == cc26xx_web_demo_load_config_defaults) { + set_config_defaults(); + } + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/net-uart.h b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/net-uart.h new file mode 100644 index 000000000..663e81eaa --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/net-uart.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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 NET_UART_H_ +#define NET_UART_H_ +/*---------------------------------------------------------------------------*/ +#include "net/ipv6/uip.h" + +#include +/*---------------------------------------------------------------------------*/ +#define NET_UART_IP_ADDR_STRLEN 64 +/*---------------------------------------------------------------------------*/ +PROCESS_NAME(net_uart_process); +/*---------------------------------------------------------------------------*/ +typedef struct net_uart_config_s { + char remote_address[NET_UART_IP_ADDR_STRLEN]; + uint16_t remote_port; + uint8_t enable; +} net_uart_config_t; +/*---------------------------------------------------------------------------*/ +#endif /* NET_UART_H_ */ +/*---------------------------------------------------------------------------*/ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/project-conf.h b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/project-conf.h new file mode 100644 index 000000000..36114eeb7 --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/project-conf.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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 PROJECT_CONF_H_ +#define PROJECT_CONF_H_ +/*---------------------------------------------------------------------------*/ +/* Change to match your configuration */ +#define IEEE802154_CONF_PANID 0xABCD +#define IEEE802154_CONF_DEFAULT_CHANNEL 26 +#define RF_BLE_CONF_ENABLED 1 +/*---------------------------------------------------------------------------*/ + +/* Enable TCP */ +#define UIP_CONF_TCP 1 + +/* Enable/Disable Components of this Demo */ +#define CC26XX_WEB_DEMO_CONF_MQTT_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 + +/* + * ADC sensor functionality. To test this, an external voltage source should be + * connected to DIO23 + * Enable/Disable DIO23 ADC reading by setting CC26XX_WEB_DEMO_CONF_ADC_DEMO + */ +#define CC26XX_WEB_DEMO_CONF_ADC_DEMO 0 +/*---------------------------------------------------------------------------*/ +/* + * Change to 1 if you are using an older CC2650 Sensortag (look for Rev: 1.2 + * printed on the PCB, or for a sticker reading "HW Rev 1.2.0"). + * + * This may be the case if you are getting this error: + * "Could not open flash to load config" + * when your sensortag is starting up. + */ +#define SENSORTAG_CC2650_REV_1_2_0 0 +/*---------------------------------------------------------------------------*/ +/* Enable the ROM bootloader */ +#define ROM_BOOTLOADER_ENABLE 1 +/*---------------------------------------------------------------------------*/ +/* + * Shrink the size of the uIP buffer, routing table and ND cache. + * Set the TCP MSS + */ +#define UIP_CONF_BUFFER_SIZE 500 +#define NETSTACK_MAX_ROUTE_ENTRIES 5 +#define NBR_TABLE_CONF_MAX_NEIGHBORS 5 +#define UIP_CONF_TCP_MSS 128 +/*---------------------------------------------------------------------------*/ +#endif /* PROJECT_CONF_H_ */ +/*---------------------------------------------------------------------------*/ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-ble-advd.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-ble-advd.c new file mode 100644 index 000000000..a94a0b7a0 --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-ble-advd.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup cc26xx-web-demo + * @{ + * + * \file + * CoAP resource to start/stop/configure BLE advertisements + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "coap-engine.h" +#include "coap.h" +#include "rf-core/rf-ble.h" + +#include +#include +/*---------------------------------------------------------------------------*/ +#define BLE_NAME_BUF_LEN 32 +/*---------------------------------------------------------------------------*/ +const char *forbidden_payload = "Name to advertise unspecified.\n" + "Use name= in the request"; +/*---------------------------------------------------------------------------*/ +static void +res_ble_post_put_handler(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + size_t len = 0; + const char *text = NULL; + char name[BLE_NAME_BUF_LEN]; + int success = 0; + int rv; + + memset(name, 0, BLE_NAME_BUF_LEN); + + len = coap_get_post_variable(request, "name", &text); + + if(len > 0 && len < BLE_NAME_BUF_LEN) { + memcpy(name, text, len); + rf_ble_beacond_config(0, name); + success = 1; + } + + len = coap_get_post_variable(request, "interval", &text); + + rv = atoi(text); + + if(rv > 0) { + rf_ble_beacond_config((clock_time_t)(rv * CLOCK_SECOND), NULL); + success = 1; + } + + len = coap_get_post_variable(request, "mode", &text); + + if(len) { + if(strncmp(text, "on", len) == 0) { + if(rf_ble_beacond_start()) { + success = 1; + } else { + coap_set_status_code(response, FORBIDDEN_4_03); + coap_set_payload(response, forbidden_payload, + strlen(forbidden_payload)); + return; + } + } else if(strncmp(text, "off", len) == 0) { + rf_ble_beacond_stop(); + success = 1; + } else { + success = 0; + } + } + + if(!success) { + coap_set_status_code(response, BAD_REQUEST_4_00); + } +} +/*---------------------------------------------------------------------------*/ +RESOURCE(res_ble_advd, + "title=\"BLE advd config: POST/PUT name=&mode=on|off" + "&interval=\";rt=\"Control\"", + NULL, + res_ble_post_put_handler, + res_ble_post_put_handler, + NULL); +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-device.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-device.c new file mode 100644 index 000000000..46344d1ef --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-device.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup cc26xx-web-demo + * @{ + * + * \file + * CoAP resource handler for CC26XX software and hardware version + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "coap-engine.h" +#include "coap.h" +#include "sys/clock.h" +#include "coap-server.h" +#include "cc26xx-web-demo.h" + +#include "ti-lib.h" + +#include +#include +/*---------------------------------------------------------------------------*/ +static uint16_t +detect_chip(void) +{ + if(ti_lib_chipinfo_chip_family_is_cc26xx()) { + if(ti_lib_chipinfo_supports_ieee_802_15_4() == true) { + if(ti_lib_chipinfo_supports_ble() == true) { + return 2650; + } else { + return 2630; + } + } else { + return 2640; + } + } else if(ti_lib_chipinfo_chip_family_is_cc13xx()) { + if(ti_lib_chipinfo_supports_ble() == false && + ti_lib_chipinfo_supports_ieee_802_15_4() == false) { + return 1310; + } else if(ti_lib_chipinfo_supports_ble() == true && + ti_lib_chipinfo_supports_ieee_802_15_4() == true) { + return 1350; + } + } + + return 0; +} +/*---------------------------------------------------------------------------*/ +static void +res_get_handler_hw(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + unsigned int accept = -1; + uint16_t chip = detect_chip(); + + coap_get_header_accept(request, &accept); + + if(accept == -1 || accept == TEXT_PLAIN) { + coap_set_header_content_format(response, TEXT_PLAIN); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%s on CC%u", BOARD_STRING, + chip); + + coap_set_payload(response, (uint8_t *)buffer, strlen((char *)buffer)); + } else if(accept == APPLICATION_JSON) { + coap_set_header_content_format(response, APPLICATION_JSON); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{\"HW Ver\":\"%s on CC%u\"}", + BOARD_STRING, chip); + + coap_set_payload(response, buffer, strlen((char *)buffer)); + } else if(accept == APPLICATION_XML) { + coap_set_header_content_format(response, APPLICATION_XML); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, + "", BOARD_STRING, + chip); + + coap_set_payload(response, buffer, strlen((char *)buffer)); + } else { + coap_set_status_code(response, NOT_ACCEPTABLE_4_06); + coap_set_payload(response, coap_server_supported_msg, + strlen(coap_server_supported_msg)); + } +} +/*---------------------------------------------------------------------------*/ +static void +res_get_handler_sw(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + unsigned int accept = -1; + + coap_get_header_accept(request, &accept); + + if(accept == -1 || accept == TEXT_PLAIN) { + coap_set_header_content_format(response, TEXT_PLAIN); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%s", CONTIKI_VERSION_STRING); + + coap_set_payload(response, (uint8_t *)buffer, strlen((char *)buffer)); + } else if(accept == APPLICATION_JSON) { + coap_set_header_content_format(response, APPLICATION_JSON); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{\"SW Ver\":\"%s\"}", + CONTIKI_VERSION_STRING); + + coap_set_payload(response, buffer, strlen((char *)buffer)); + } else if(accept == APPLICATION_XML) { + coap_set_header_content_format(response, APPLICATION_XML); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, + "", CONTIKI_VERSION_STRING); + + coap_set_payload(response, buffer, strlen((char *)buffer)); + } else { + coap_set_status_code(response, NOT_ACCEPTABLE_4_06); + coap_set_payload(response, coap_server_supported_msg, + strlen(coap_server_supported_msg)); + } +} +/*---------------------------------------------------------------------------*/ +static void +res_get_handler_uptime(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + unsigned int accept = -1; + + coap_get_header_accept(request, &accept); + + if(accept == -1 || accept == TEXT_PLAIN) { + coap_set_header_content_format(response, TEXT_PLAIN); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%lu", clock_seconds()); + + coap_set_payload(response, (uint8_t *)buffer, strlen((char *)buffer)); + } else if(accept == APPLICATION_JSON) { + coap_set_header_content_format(response, APPLICATION_JSON); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{\"uptime\":%lu}", + clock_seconds()); + + coap_set_payload(response, buffer, strlen((char *)buffer)); + } else if(accept == APPLICATION_XML) { + coap_set_header_content_format(response, APPLICATION_XML); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, + "", clock_seconds()); + + coap_set_payload(response, buffer, strlen((char *)buffer)); + } else { + coap_set_status_code(response, NOT_ACCEPTABLE_4_06); + coap_set_payload(response, coap_server_supported_msg, + strlen(coap_server_supported_msg)); + } +} +/*---------------------------------------------------------------------------*/ +static void +res_post_handler_cfg_reset(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + cc26xx_web_demo_restore_defaults(); +} +/*---------------------------------------------------------------------------*/ +RESOURCE(res_device_sw, + "title=\"Software version\";rt=\"text\"", + res_get_handler_sw, + NULL, + NULL, + NULL); +/*---------------------------------------------------------------------------*/ +RESOURCE(res_device_uptime, + "title=\"Uptime\";rt=\"seconds\"", + res_get_handler_uptime, + NULL, + NULL, + NULL); +/*---------------------------------------------------------------------------*/ +RESOURCE(res_device_hw, + "title=\"Hardware version\";rt=\"text\"", + res_get_handler_hw, + NULL, + NULL, + NULL); +/*---------------------------------------------------------------------------*/ +RESOURCE(res_device_cfg_reset, + "title=\"Reset Device Config: POST\";rt=\"Control\"", + NULL, res_post_handler_cfg_reset, NULL, NULL); +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-leds.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-leds.c new file mode 100644 index 000000000..6c396145c --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-leds.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup cc26xx-web-demo + * @{ + * + * \file + * CoAP resource handler for the CC26xx LEDs. Slightly modified copy of + * the one found in Contiki's original CoAP example. + * \author + * Matthias Kovatsch (original) + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "coap-engine.h" +#include "dev/leds.h" + +#include +/*---------------------------------------------------------------------------*/ +static void +res_post_put_handler(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + size_t len = 0; + const char *color = NULL; + const char *mode = NULL; + uint8_t led = 0; + int success = 1; + + if((len = coap_get_query_variable(request, "color", &color))) { + if(strncmp(color, "r", len) == 0) { + led = LEDS_RED; + } else if(strncmp(color, "g", len) == 0) { + led = LEDS_GREEN; +#if BOARD_SMARTRF06EB + } else if(strncmp(color, "y", len) == 0) { + led = LEDS_YELLOW; + } else if(strncmp(color, "o", len) == 0) { + led = LEDS_ORANGE; +#endif + } else { + success = 0; + } + } else { + success = 0; + } + + if(success && (len = coap_get_post_variable(request, "mode", &mode))) { + if(strncmp(mode, "on", len) == 0) { + leds_on(led); + } else if(strncmp(mode, "off", len) == 0) { + leds_off(led); + } else { + success = 0; + } + } else { + success = 0; + } + + if(!success) { + coap_set_status_code(response, BAD_REQUEST_4_00); + } +} +/*---------------------------------------------------------------------------*/ +/* + * A simple actuator example, depending on the color query parameter and post + * variable mode, corresponding led is activated or deactivated + */ +#if BOARD_SENSORTAG || BOARD_LAUNCHPAD +#define RESOURCE_PARAMS "r|g" +#elif BOARD_SMARTRF06EB +#define RESOURCE_PARAMS "r|g|y|o" +#endif + +RESOURCE(res_leds, + "title=\"LEDs: ?color=" RESOURCE_PARAMS ", POST/PUT mode=on|off\";rt=\"Control\"", + NULL, + res_post_put_handler, + res_post_put_handler, + NULL); +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-net.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-net.c new file mode 100644 index 000000000..81575f345 --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-net.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup cc26xx-web-demo + * @{ + * + * \file + * CoAP resource handler for network-related resources + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "coap-engine.h" +#include "coap.h" +#include "net/ipv6/uip-ds6.h" +#include "coap-server.h" +#include "cc26xx-web-demo.h" + +#include "ti-lib.h" + +#include +#include +/*---------------------------------------------------------------------------*/ +extern int def_rt_rssi; +/*---------------------------------------------------------------------------*/ +static void +res_get_handler_parent_rssi(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + unsigned int accept = -1; + + coap_get_header_accept(request, &accept); + + if(accept == -1 || accept == TEXT_PLAIN) { + coap_set_header_content_format(response, TEXT_PLAIN); + snprintf((char *)buffer, COAP_MAX_CHUNK_SIZE, "%d", def_rt_rssi); + + coap_set_payload(response, (uint8_t *)buffer, strlen((char *)buffer)); + } else if(accept == APPLICATION_JSON) { + coap_set_header_content_format(response, APPLICATION_JSON); + snprintf((char *)buffer, COAP_MAX_CHUNK_SIZE, "{\"Parent RSSI\":\"%d\"}", + def_rt_rssi); + + coap_set_payload(response, buffer, strlen((char *)buffer)); + } else if(accept == APPLICATION_XML) { + coap_set_header_content_format(response, APPLICATION_XML); + snprintf((char *)buffer, COAP_MAX_CHUNK_SIZE, + "", def_rt_rssi); + + coap_set_payload(response, buffer, strlen((char *)buffer)); + } else { + coap_set_status_code(response, NOT_ACCEPTABLE_4_06); + coap_set_payload(response, coap_server_supported_msg, + strlen(coap_server_supported_msg)); + } +} +/*---------------------------------------------------------------------------*/ +static void +res_get_handler_pref_parent(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + unsigned int accept = -1; + char def_rt_str[64]; + + coap_get_header_accept(request, &accept); + + memset(def_rt_str, 0, sizeof(def_rt_str)); + cc26xx_web_demo_ipaddr_sprintf(def_rt_str, sizeof(def_rt_str), + uip_ds6_defrt_choose()); + + if(accept == -1 || accept == TEXT_PLAIN) { + coap_set_header_content_format(response, TEXT_PLAIN); + snprintf((char *)buffer, COAP_MAX_CHUNK_SIZE, "%s", def_rt_str); + + coap_set_payload(response, (uint8_t *)buffer, strlen((char *)buffer)); + } else if(accept == APPLICATION_JSON) { + coap_set_header_content_format(response, APPLICATION_JSON); + snprintf((char *)buffer, COAP_MAX_CHUNK_SIZE, "{\"Parent\":\"%s\"}", + def_rt_str); + + coap_set_payload(response, buffer, strlen((char *)buffer)); + } else if(accept == APPLICATION_XML) { + coap_set_header_content_format(response, APPLICATION_XML); + snprintf((char *)buffer, COAP_MAX_CHUNK_SIZE, + "", def_rt_str); + + coap_set_payload(response, buffer, strlen((char *)buffer)); + } else { + coap_set_status_code(response, NOT_ACCEPTABLE_4_06); + coap_set_payload(response, coap_server_supported_msg, + strlen(coap_server_supported_msg)); + } +} +/*---------------------------------------------------------------------------*/ +RESOURCE(res_parent_rssi, "title=\"Parent RSSI\";rt=\"dBm\"", + res_get_handler_parent_rssi, NULL, NULL, NULL); +/*---------------------------------------------------------------------------*/ +RESOURCE(res_parent_ip, "title=\"Preferred Parent\";rt=\"IPv6 address\"", + res_get_handler_pref_parent, NULL, NULL, NULL); +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-sensors.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-sensors.c new file mode 100644 index 000000000..9ccc79e97 --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-sensors.c @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup cc26xx-web-demo + * @{ + * + * \file + * CoAP resource handler for the Sensortag-CC26xx sensors + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "coap-engine.h" +#include "coap.h" +#include "cc26xx-web-demo.h" +#include "coap-server.h" + +#include +#include +#include +/*---------------------------------------------------------------------------*/ +/* + * Generic resource handler for any sensor in this example. Ultimately gets + * called by all handlers and populates the CoAP response + */ +static void +res_get_handler_all(int sens_type, coap_message_t *request, + coap_message_t *response, + uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + unsigned int accept = -1; + const cc26xx_web_demo_sensor_reading_t *reading; + + reading = cc26xx_web_demo_sensor_lookup(sens_type); + + if(reading == NULL) { + coap_set_status_code(response, NOT_FOUND_4_04); + coap_set_payload(response, coap_server_not_found_msg, + strlen(coap_server_not_found_msg)); + return; + } + + coap_get_header_accept(request, &accept); + + if(accept == -1 || accept == TEXT_PLAIN) { + coap_set_header_content_format(response, TEXT_PLAIN); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%s", reading->converted); + + coap_set_payload(response, (uint8_t *)buffer, + strlen((char *)buffer)); + } else if(accept == APPLICATION_JSON) { + coap_set_header_content_format(response, APPLICATION_JSON); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{\"%s\":%s}", + reading->descr, reading->converted); + + coap_set_payload(response, buffer, strlen((char *)buffer)); + } else if(accept == APPLICATION_XML) { + coap_set_header_content_format(response, APPLICATION_XML); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, + "<%s val=\"%s\" unit=\"%s\"/>", reading->xml_element, + reading->converted, reading->units); + + coap_set_payload(response, buffer, strlen((char *)buffer)); + } else { + coap_set_status_code(response, NOT_ACCEPTABLE_4_06); + coap_set_payload(response, coap_server_supported_msg, + strlen(coap_server_supported_msg)); + } +} +/*---------------------------------------------------------------------------*/ +/* BatMon resources and handler: Temperature, Voltage */ +static void +res_get_handler_batmon_temp(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_BATMON_TEMP, request, response, + buffer, preferred_size, offset); +} +/*---------------------------------------------------------------------------*/ +static void +res_get_handler_batmon_volt(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_BATMON_VOLT, request, response, + buffer, preferred_size, offset); +} +/*---------------------------------------------------------------------------*/ +RESOURCE(res_batmon_temp, "title=\"Battery Temp\";rt=\"C\"", + res_get_handler_batmon_temp, NULL, NULL, NULL); +/*---------------------------------------------------------------------------*/ +RESOURCE(res_batmon_volt, "title=\"Battery Voltage\";rt=\"mV\"", + res_get_handler_batmon_volt, NULL, NULL, NULL); +/*---------------------------------------------------------------------------*/ +#if CC26XX_WEB_DEMO_ADC_DEMO +/*---------------------------------------------------------------------------*/ +static void +res_get_handler_adc_dio23(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_ADC_DIO23, request, response, + buffer, preferred_size, offset); +} +/*---------------------------------------------------------------------------*/ +RESOURCE(res_adc_dio23, "title=\"ADC DIO23\";rt=\"mV\"", + res_get_handler_adc_dio23, NULL, NULL, NULL); +/*---------------------------------------------------------------------------*/ +#endif +/*---------------------------------------------------------------------------*/ +#if BOARD_SENSORTAG +/*---------------------------------------------------------------------------*/ +/* MPU resources and handler: Accelerometer and Gyro */ +static void +res_get_handler_mpu_acc_x(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_MPU_ACC_X, request, response, + buffer, preferred_size, offset); +} +/*---------------------------------------------------------------------------*/ +static void +res_get_handler_mpu_acc_y(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_MPU_ACC_Y, request, response, + buffer, preferred_size, offset); +} +/*---------------------------------------------------------------------------*/ +static void +res_get_handler_mpu_acc_z(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_MPU_ACC_Z, request, response, + buffer, preferred_size, offset); +} +/*---------------------------------------------------------------------------*/ +static void +res_get_handler_mpu_gyro_x(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_MPU_GYRO_X, request, response, + buffer, preferred_size, offset); +} +/*---------------------------------------------------------------------------*/ +static void +res_get_handler_mpu_gyro_y(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_MPU_GYRO_Y, request, response, + buffer, preferred_size, offset); +} +/*---------------------------------------------------------------------------*/ +static void +res_get_handler_mpu_gyro_z(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_MPU_GYRO_Z, request, response, + buffer, preferred_size, offset); +} +/*---------------------------------------------------------------------------*/ +RESOURCE(res_mpu_acc_x, "title=\"Acc X\";rt=\"G\"", res_get_handler_mpu_acc_x, + NULL, NULL, NULL); +RESOURCE(res_mpu_acc_y, "title=\"Acc Y\";rt=\"G\"", res_get_handler_mpu_acc_y, + NULL, NULL, NULL); +RESOURCE(res_mpu_acc_z, "title=\"Acc Z\";rt=\"G\"", res_get_handler_mpu_acc_z, + NULL, NULL, NULL); + +RESOURCE(res_mpu_gyro_x, "title=\"Gyro X\";rt=\"deg/sec\"", + res_get_handler_mpu_gyro_x, NULL, NULL, NULL); +RESOURCE(res_mpu_gyro_y, "title=\"Gyro Y\";rt=\"deg/sec\"", + res_get_handler_mpu_gyro_y, NULL, NULL, NULL); +RESOURCE(res_mpu_gyro_z, "title=\"Gyro Z\";rt=\"deg/sec\"", + res_get_handler_mpu_gyro_z, NULL, NULL, NULL); +/*---------------------------------------------------------------------------*/ +/* TMP sensor resources and handlers: Object, Ambient */ +static void +res_get_handler_obj_temp(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_TMP_OBJECT, request, response, + buffer, preferred_size, offset); +} +/*---------------------------------------------------------------------------*/ +static void +res_get_handler_amb_temp(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_TMP_AMBIENT, request, response, + buffer, preferred_size, offset); +} +/*---------------------------------------------------------------------------*/ +RESOURCE(res_tmp007_obj, "title=\"Temperature (Object)\";rt=\"C\"", + res_get_handler_obj_temp, NULL, NULL, NULL); + +RESOURCE(res_tmp007_amb, "title=\"Temperature (Ambient)\";rt=\"C\"", + res_get_handler_amb_temp, NULL, NULL, NULL); +/*---------------------------------------------------------------------------*/ +/* BMP sensor resources: Temperature, Pressure */ +static void +res_get_handler_bmp_temp(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_BMP_TEMP, request, response, + buffer, preferred_size, offset); +} +/*---------------------------------------------------------------------------*/ +static void +res_get_handler_bmp_press(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_BMP_PRES, request, response, + buffer, preferred_size, offset); +} +/*---------------------------------------------------------------------------*/ +RESOURCE(res_bmp280_temp, "title=\"Barometer (Temperature)\";rt=\"C\"", + res_get_handler_bmp_temp, NULL, NULL, NULL); + +RESOURCE(res_bmp280_press, + "title=\"Barometer (Pressure)\";rt=\"hPa (hectopascal / millibar)\"", + res_get_handler_bmp_press, NULL, NULL, NULL); +/*---------------------------------------------------------------------------*/ +/* HDC1000 sensor resources and handler: Temperature, Pressure */ +static void +res_get_handler_hdc_temp(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_HDC_TEMP, request, response, + buffer, preferred_size, offset); +} +/*---------------------------------------------------------------------------*/ +static void +res_get_handler_hdc_humidity(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_HDC_HUMIDITY, request, response, + buffer, preferred_size, offset); +} +/*---------------------------------------------------------------------------*/ +RESOURCE(res_hdc1000_temp, "title=\"Temperature\";rt=\"C\"", + res_get_handler_hdc_temp, NULL, NULL, NULL); + +RESOURCE(res_hdc1000_hum, "title=\"Humidity\";rt=\"%RH\"", + res_get_handler_hdc_humidity, NULL, NULL, NULL); +/*---------------------------------------------------------------------------*/ +/* Illuminance resources and handler */ +static void +res_get_handler_opt(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_OPT_LIGHT, request, response, + buffer, preferred_size, offset); +} +/*---------------------------------------------------------------------------*/ +RESOURCE(res_opt3001_light, "title=\"Illuminance\";rt=\"Lux\"", + res_get_handler_opt, NULL, NULL, NULL); +/*---------------------------------------------------------------------------*/ +#endif /* BOARD_SENSORTAG */ +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-toggle-leds.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-toggle-leds.c new file mode 100644 index 000000000..1c708b539 --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-toggle-leds.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup cc26xx-web-demo + * @{ + * + * \file + * CoAP resource to toggle LEDs. Slightly modified copy of the one found + * in Contiki's original CoAP example. + * \author + * Matthias Kovatsch (original) + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "coap-engine.h" +#include "dev/leds.h" + +#include +/*---------------------------------------------------------------------------*/ +static void +res_post_handler_red(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + leds_toggle(LEDS_RED); +} +/*---------------------------------------------------------------------------*/ +static void +res_post_handler_green(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + leds_toggle(LEDS_GREEN); +} +/*---------------------------------------------------------------------------*/ +/* Toggles the red led */ +RESOURCE(res_toggle_red, + "title=\"Red LED\";rt=\"Control\"", + NULL, + res_post_handler_red, + NULL, + NULL); + +/* Toggles the green led */ +RESOURCE(res_toggle_green, + "title=\"Green LED\";rt=\"Control\"", + NULL, + res_post_handler_green, + NULL, + NULL); +/*---------------------------------------------------------------------------*/ +/* An additional 2 LEDs on the Srf */ +#if BOARD_SMARTRF06EB +/*---------------------------------------------------------------------------*/ +static void +res_post_handler_yellow(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + leds_toggle(LEDS_YELLOW); +} +/*---------------------------------------------------------------------------*/ +static void +res_post_handler_orange(coap_message_t *request, coap_message_t *response, + uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + leds_toggle(LEDS_ORANGE); +} +/*---------------------------------------------------------------------------*/ +/* Toggles the yellow led */ +RESOURCE(res_toggle_yellow, + "title=\"Yellow LED\";rt=\"Control\"", + NULL, + res_post_handler_yellow, + NULL, + NULL); + +/* Toggles the orange led */ +RESOURCE(res_toggle_orange, + "title=\"Orange LED\";rt=\"Control\"", + NULL, + res_post_handler_orange, + NULL, + NULL); +#endif +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.c new file mode 100644 index 000000000..f69a19478 --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.c @@ -0,0 +1,1062 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/** + * \addtogroup cc26xx-web-demo + * @{ + * + * \file + * Main module for the CC26XX web demo. Activates on-device resources, + * takes sensor readings periodically and caches them for all other modules + * to use. + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "contiki-net.h" +#include "coap-engine.h" +#include "board-peripherals.h" +#include "lib/sensors.h" +#include "lib/list.h" +#include "sys/process.h" +#include "net/ipv6/sicslowpan.h" +#include "dev/button-hal.h" +#include "batmon-sensor.h" +#include "httpd-simple.h" +#include "cc26xx-web-demo.h" +#include "mqtt-client.h" +#include "coap-server.h" + +#include +#include +#include +#include + +#include "ti-lib.h" +/*---------------------------------------------------------------------------*/ +PROCESS_NAME(cetic_6lbr_client_process); +PROCESS(cc26xx_web_demo_process, "CC26XX Web Demo"); +/*---------------------------------------------------------------------------*/ +/* + * Update sensor readings in a staggered fashion every SENSOR_READING_PERIOD + * ticks + a random interval between 0 and SENSOR_READING_RANDOM ticks + */ +#define SENSOR_READING_PERIOD (CLOCK_SECOND * 20) +#define SENSOR_READING_RANDOM (CLOCK_SECOND << 4) + +struct ctimer batmon_timer; + +#if BOARD_SENSORTAG +struct ctimer bmp_timer, hdc_timer, tmp_timer, opt_timer, mpu_timer; +#endif +/*---------------------------------------------------------------------------*/ +/* Provide visible feedback via LEDS while searching for a network */ +#define NO_NET_LED_DURATION (CC26XX_WEB_DEMO_NET_CONNECT_PERIODIC >> 1) + +static struct etimer et; +static struct ctimer ct; +/*---------------------------------------------------------------------------*/ +/* Parent RSSI functionality */ +#if CC26XX_WEB_DEMO_READ_PARENT_RSSI +static struct uip_icmp6_echo_reply_notification echo_reply_notification; +static struct etimer echo_request_timer; +int def_rt_rssi = 0; +#endif +/*---------------------------------------------------------------------------*/ +#if CC26XX_WEB_DEMO_ADC_DEMO +PROCESS(adc_process, "ADC process"); + +static uint16_t single_adc_sample; +static struct etimer et_adc; +#endif +/*---------------------------------------------------------------------------*/ +process_event_t cc26xx_web_demo_publish_event; +process_event_t cc26xx_web_demo_config_loaded_event; +process_event_t cc26xx_web_demo_load_config_defaults; +/*---------------------------------------------------------------------------*/ +/* Saved settings on flash: store, offset, magic */ +#define CONFIG_FLASH_OFFSET 0 +#define CONFIG_MAGIC 0xCC265002 + +cc26xx_web_demo_config_t cc26xx_web_demo_config; +/*---------------------------------------------------------------------------*/ +/* A cache of sensor values. Updated periodically or upon key press */ +LIST(sensor_list); +/*---------------------------------------------------------------------------*/ +/* The objects representing sensors used in this demo */ +#define DEMO_SENSOR(name, type, descr, xml_element, form_field, units) \ + cc26xx_web_demo_sensor_reading_t name##_reading = \ + { NULL, 0, 0, descr, xml_element, form_field, units, type, 1, 1 } + +/* CC26xx sensors */ +DEMO_SENSOR(batmon_temp, CC26XX_WEB_DEMO_SENSOR_BATMON_TEMP, + "Battery Temp", "battery-temp", "batmon_temp", + CC26XX_WEB_DEMO_UNIT_TEMP); +DEMO_SENSOR(batmon_volt, CC26XX_WEB_DEMO_SENSOR_BATMON_VOLT, + "Battery Volt", "battery-volt", "batmon_volt", + CC26XX_WEB_DEMO_UNIT_VOLT); + +#if CC26XX_WEB_DEMO_ADC_DEMO +DEMO_SENSOR(adc_dio23, CC26XX_WEB_DEMO_SENSOR_ADC_DIO23, + "ADC DIO23", "adc-dio23", "adc_dio23", + CC26XX_WEB_DEMO_UNIT_VOLT); +#endif + +/* Sensortag sensors */ +#if BOARD_SENSORTAG +DEMO_SENSOR(bmp_pres, CC26XX_WEB_DEMO_SENSOR_BMP_PRES, + "Air Pressure", "air-pressure", "bmp_pres", + CC26XX_WEB_DEMO_UNIT_PRES); +DEMO_SENSOR(bmp_temp, CC26XX_WEB_DEMO_SENSOR_BMP_TEMP, + "Air Temp", "air-temp", "bmp_temp", + CC26XX_WEB_DEMO_UNIT_TEMP); +DEMO_SENSOR(hdc_temp, CC26XX_WEB_DEMO_SENSOR_HDC_TEMP, + "HDC Temp", "hdc-temp", "hdc_temp", + CC26XX_WEB_DEMO_UNIT_TEMP); +DEMO_SENSOR(hdc_hum, CC26XX_WEB_DEMO_SENSOR_HDC_HUMIDITY, + "HDC Humidity", "hdc-humidity", "hdc_hum", + CC26XX_WEB_DEMO_UNIT_HUMIDITY); +DEMO_SENSOR(tmp_amb, CC26XX_WEB_DEMO_SENSOR_TMP_AMBIENT, + "Ambient Temp", "ambient-temp", "tmp_amb", + CC26XX_WEB_DEMO_UNIT_TEMP); +DEMO_SENSOR(tmp_obj, CC26XX_WEB_DEMO_SENSOR_TMP_OBJECT, + "Object Temp", "object-temp", "tmp_obj", + CC26XX_WEB_DEMO_UNIT_TEMP); +DEMO_SENSOR(opt, CC26XX_WEB_DEMO_SENSOR_OPT_LIGHT, + "Light", "light", "light", + CC26XX_WEB_DEMO_UNIT_LIGHT); + +/* MPU Readings */ +DEMO_SENSOR(mpu_acc_x, CC26XX_WEB_DEMO_SENSOR_MPU_ACC_X, + "Acc X", "acc-x", "acc_x", + CC26XX_WEB_DEMO_UNIT_ACC); +DEMO_SENSOR(mpu_acc_y, CC26XX_WEB_DEMO_SENSOR_MPU_ACC_Y, + "Acc Y", "acc-y", "acc_y", + CC26XX_WEB_DEMO_UNIT_ACC); +DEMO_SENSOR(mpu_acc_z, CC26XX_WEB_DEMO_SENSOR_MPU_ACC_Z, + "Acc Z", "acc-z", "acc_z", + CC26XX_WEB_DEMO_UNIT_ACC); + +DEMO_SENSOR(mpu_gyro_x, CC26XX_WEB_DEMO_SENSOR_MPU_GYRO_X, + "Gyro X", "gyro-x", "gyro_x", + CC26XX_WEB_DEMO_UNIT_GYRO); +DEMO_SENSOR(mpu_gyro_y, CC26XX_WEB_DEMO_SENSOR_MPU_GYRO_Y, + "Gyro Y", "gyro-y", "gyro_y", + CC26XX_WEB_DEMO_UNIT_GYRO); +DEMO_SENSOR(mpu_gyro_z, CC26XX_WEB_DEMO_SENSOR_MPU_GYRO_Z, + "Gyro Z", "gyro-z", "gyro_Z", + CC26XX_WEB_DEMO_UNIT_GYRO); +#endif +/*---------------------------------------------------------------------------*/ +#if BOARD_SENSORTAG +static void init_bmp_reading(void *data); +static void init_light_reading(void *data); +static void init_hdc_reading(void *data); +static void init_tmp_reading(void *data); +static void init_mpu_reading(void *data); +#endif +/*---------------------------------------------------------------------------*/ +static void +publish_led_off(void *d) +{ + leds_off(CC26XX_WEB_DEMO_STATUS_LED); +} +/*---------------------------------------------------------------------------*/ +static void +save_config() +{ + /* Dump current running config to flash */ +#if BOARD_SENSORTAG || BOARD_LAUNCHPAD + int rv; + cc26xx_web_demo_sensor_reading_t *reading = NULL; + + rv = ext_flash_open(NULL); + + if(!rv) { + printf("Could not open flash to save config\n"); + ext_flash_close(NULL); + return; + } + + rv = ext_flash_erase(NULL, CONFIG_FLASH_OFFSET, sizeof(cc26xx_web_demo_config_t)); + + if(!rv) { + printf("Error erasing flash\n"); + } else { + cc26xx_web_demo_config.magic = CONFIG_MAGIC; + cc26xx_web_demo_config.len = sizeof(cc26xx_web_demo_config_t); + cc26xx_web_demo_config.sensors_bitmap = 0; + + for(reading = list_head(sensor_list); + reading != NULL; + reading = list_item_next(reading)) { + if(reading->publish) { + cc26xx_web_demo_config.sensors_bitmap |= (1 << reading->type); + } + } + + rv = ext_flash_write(NULL, CONFIG_FLASH_OFFSET, sizeof(cc26xx_web_demo_config_t), + (uint8_t *)&cc26xx_web_demo_config); + if(!rv) { + printf("Error saving config\n"); + } + } + + ext_flash_close(NULL); +#endif +} +/*---------------------------------------------------------------------------*/ +static void +load_config() +{ +#if BOARD_SENSORTAG || BOARD_LAUNCHPAD + /* Read from flash into a temp buffer */ + cc26xx_web_demo_config_t tmp_cfg; + cc26xx_web_demo_sensor_reading_t *reading = NULL; + + int rv = ext_flash_open(NULL); + + if(!rv) { + printf("Could not open flash to load config\n"); + ext_flash_close(NULL); + return; + } + + rv = ext_flash_read(NULL, CONFIG_FLASH_OFFSET, sizeof(tmp_cfg), + (uint8_t *)&tmp_cfg); + + ext_flash_close(NULL); + + if(!rv) { + printf("Error loading config\n"); + return; + } + + if(tmp_cfg.magic == CONFIG_MAGIC && tmp_cfg.len == sizeof(tmp_cfg)) { + memcpy(&cc26xx_web_demo_config, &tmp_cfg, sizeof(cc26xx_web_demo_config)); + } + + for(reading = list_head(sensor_list); + reading != NULL; + reading = list_item_next(reading)) { + if(cc26xx_web_demo_config.sensors_bitmap & (1 << reading->type)) { + reading->publish = 1; + } else { + reading->publish = 0; + snprintf(reading->converted, CC26XX_WEB_DEMO_CONVERTED_LEN, "\"N/A\""); + } + } +#endif +} +/*---------------------------------------------------------------------------*/ +/* Don't start everything here, we need to dictate order of initialisation */ +AUTOSTART_PROCESSES(&cc26xx_web_demo_process); +/*---------------------------------------------------------------------------*/ +int +cc26xx_web_demo_ipaddr_sprintf(char *buf, uint8_t buf_len, + const uip_ipaddr_t *addr) +{ + uint16_t a; + uint8_t len = 0; + int i, f; + for(i = 0, f = 0; i < sizeof(uip_ipaddr_t); i += 2) { + a = (addr->u8[i] << 8) + addr->u8[i + 1]; + if(a == 0 && f >= 0) { + if(f++ == 0) { + len += snprintf(&buf[len], buf_len - len, "::"); + } + } else { + if(f > 0) { + f = -1; + } else if(i > 0) { + len += snprintf(&buf[len], buf_len - len, ":"); + } + len += snprintf(&buf[len], buf_len - len, "%x", a); + } + } + + return len; +} +/*---------------------------------------------------------------------------*/ +const cc26xx_web_demo_sensor_reading_t * +cc26xx_web_demo_sensor_lookup(int sens_type) +{ + cc26xx_web_demo_sensor_reading_t *reading = NULL; + + for(reading = list_head(sensor_list); + reading != NULL; + reading = list_item_next(reading)) { + if(reading->type == sens_type) { + return reading; + } + } + + return NULL; +} +/*---------------------------------------------------------------------------*/ +const cc26xx_web_demo_sensor_reading_t * +cc26xx_web_demo_sensor_first() +{ + return list_head(sensor_list); +} +/*---------------------------------------------------------------------------*/ +void +cc26xx_web_demo_restore_defaults(void) +{ + cc26xx_web_demo_sensor_reading_t *reading = NULL; + + leds_on(LEDS_ALL); + + for(reading = list_head(sensor_list); + reading != NULL; + reading = list_item_next(reading)) { + reading->publish = 1; + } + +#if CC26XX_WEB_DEMO_MQTT_CLIENT + process_post_synch(&mqtt_client_process, + cc26xx_web_demo_load_config_defaults, NULL); +#endif + +#if CC26XX_WEB_DEMO_NET_UART + process_post_synch(&net_uart_process, cc26xx_web_demo_load_config_defaults, + NULL); +#endif + + save_config(); + + leds_off(LEDS_ALL); +} +/*---------------------------------------------------------------------------*/ +static int +defaults_post_handler(char *key, int key_len, char *val, int val_len) +{ + if(key_len != strlen("defaults") || + strncasecmp(key, "defaults", strlen("defaults")) != 0) { + /* Not ours */ + return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; + } + + cc26xx_web_demo_restore_defaults(); + + return HTTPD_SIMPLE_POST_HANDLER_OK; +} +/*---------------------------------------------------------------------------*/ +static int +sensor_readings_handler(char *key, int key_len, char *val, int val_len) +{ + cc26xx_web_demo_sensor_reading_t *reading = NULL; + int rv; + + for(reading = list_head(sensor_list); + reading != NULL; + reading = list_item_next(reading)) { + if(key_len == strlen(reading->form_field) && + strncmp(reading->form_field, key, strlen(key)) == 0) { + + rv = atoi(val); + + /* Be pedantic: only accept 0 and 1, not just any non-zero value */ + if(rv == 0) { + reading->publish = 0; + snprintf(reading->converted, CC26XX_WEB_DEMO_CONVERTED_LEN, "\"N/A\""); + } else if(rv == 1) { + reading->publish = 1; + } else { + return HTTPD_SIMPLE_POST_HANDLER_ERROR; + } + + return HTTPD_SIMPLE_POST_HANDLER_OK; + } + } + + return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; +} +/*---------------------------------------------------------------------------*/ +#if CC26XX_WEB_DEMO_READ_PARENT_RSSI +static int +ping_interval_post_handler(char *key, int key_len, char *val, int val_len) +{ + int rv = 0; + + if(key_len != strlen("ping_interval") || + strncasecmp(key, "ping_interval", strlen("ping_interval")) != 0) { + /* Not ours */ + return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; + } + + rv = atoi(val); + + if(rv < CC26XX_WEB_DEMO_RSSI_MEASURE_INTERVAL_MIN || + rv > CC26XX_WEB_DEMO_RSSI_MEASURE_INTERVAL_MAX) { + return HTTPD_SIMPLE_POST_HANDLER_ERROR; + } + + cc26xx_web_demo_config.def_rt_ping_interval = rv * CLOCK_SECOND; + + return HTTPD_SIMPLE_POST_HANDLER_OK; +} +#endif +/*---------------------------------------------------------------------------*/ +HTTPD_SIMPLE_POST_HANDLER(sensor, sensor_readings_handler); +HTTPD_SIMPLE_POST_HANDLER(defaults, defaults_post_handler); + +#if CC26XX_WEB_DEMO_READ_PARENT_RSSI +HTTPD_SIMPLE_POST_HANDLER(ping_interval, ping_interval_post_handler); +/*---------------------------------------------------------------------------*/ +static void +echo_reply_handler(uip_ipaddr_t *source, uint8_t ttl, uint8_t *data, + uint16_t datalen) +{ + if(uip_ip6addr_cmp(source, uip_ds6_defrt_choose())) { + def_rt_rssi = sicslowpan_get_last_rssi(); + } +} +/*---------------------------------------------------------------------------*/ +static void +ping_parent(void) +{ + if(uip_ds6_get_global(ADDR_PREFERRED) == NULL) { + return; + } + + uip_icmp6_send(uip_ds6_defrt_choose(), ICMP6_ECHO_REQUEST, 0, + CC26XX_WEB_DEMO_ECHO_REQ_PAYLOAD_LEN); +} +#endif +/*---------------------------------------------------------------------------*/ +static void +get_batmon_reading(void *data) +{ + int value; + char *buf; + clock_time_t next = SENSOR_READING_PERIOD + + (random_rand() % SENSOR_READING_RANDOM); + + if(batmon_temp_reading.publish) { + value = batmon_sensor.value(BATMON_SENSOR_TYPE_TEMP); + if(value != CC26XX_SENSOR_READING_ERROR) { + batmon_temp_reading.raw = value; + + buf = batmon_temp_reading.converted; + memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); + snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d", value); + } + } + + if(batmon_volt_reading.publish) { + value = batmon_sensor.value(BATMON_SENSOR_TYPE_VOLT); + if(value != CC26XX_SENSOR_READING_ERROR) { + batmon_volt_reading.raw = value; + + buf = batmon_volt_reading.converted; + memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); + snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d", (value * 125) >> 5); + } + } + + ctimer_set(&batmon_timer, next, get_batmon_reading, NULL); +} +/*---------------------------------------------------------------------------*/ +#if CC26XX_WEB_DEMO_ADC_DEMO +static void +get_adc_reading(void *data) +{ + int value; + char *buf; + + if(adc_dio23_reading.publish) { + value = single_adc_sample; + buf = adc_dio23_reading.converted; + memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); + snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d", (value * 4300) >> 12); + } +} +#endif +/*---------------------------------------------------------------------------*/ +#if BOARD_SENSORTAG +/*---------------------------------------------------------------------------*/ +static void +compare_and_update(cc26xx_web_demo_sensor_reading_t *reading) +{ + if(reading->last == reading->raw) { + reading->changed = 0; + } else { + reading->last = reading->raw; + reading->changed = 1; + } +} +/*---------------------------------------------------------------------------*/ +static void +print_mpu_reading(int reading, char *buf) +{ + char *loc_buf = buf; + + if(reading < 0) { + sprintf(loc_buf, "-"); + reading = -reading; + loc_buf++; + } + + sprintf(loc_buf, "%d.%02d", reading / 100, reading % 100); +} +/*---------------------------------------------------------------------------*/ +static void +get_bmp_reading() +{ + int value; + char *buf; + clock_time_t next = SENSOR_READING_PERIOD + + (random_rand() % SENSOR_READING_RANDOM); + + if(bmp_pres_reading.publish) { + value = bmp_280_sensor.value(BMP_280_SENSOR_TYPE_PRESS); + if(value != CC26XX_SENSOR_READING_ERROR) { + bmp_pres_reading.raw = value; + + compare_and_update(&bmp_pres_reading); + + buf = bmp_pres_reading.converted; + memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); + snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d.%02d", value / 100, + value % 100); + } + } + + if(bmp_temp_reading.publish) { + value = bmp_280_sensor.value(BMP_280_SENSOR_TYPE_TEMP); + if(value != CC26XX_SENSOR_READING_ERROR) { + bmp_temp_reading.raw = value; + + compare_and_update(&bmp_temp_reading); + + buf = bmp_temp_reading.converted; + memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); + snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d.%02d", value / 100, + value % 100); + } + } + + SENSORS_DEACTIVATE(bmp_280_sensor); + + ctimer_set(&bmp_timer, next, init_bmp_reading, NULL); +} +/*---------------------------------------------------------------------------*/ +static void +get_tmp_reading() +{ + int value; + char *buf; + clock_time_t next = SENSOR_READING_PERIOD + + (random_rand() % SENSOR_READING_RANDOM); + + if(tmp_amb_reading.publish || tmp_obj_reading.publish) { + if(tmp_007_sensor.value(TMP_007_SENSOR_TYPE_ALL) == + CC26XX_SENSOR_READING_ERROR) { + + SENSORS_DEACTIVATE(tmp_007_sensor); + ctimer_set(&tmp_timer, next, init_tmp_reading, NULL); + } + } + + if(tmp_amb_reading.publish) { + value = tmp_007_sensor.value(TMP_007_SENSOR_TYPE_AMBIENT); + tmp_amb_reading.raw = value; + + compare_and_update(&tmp_amb_reading); + + buf = tmp_amb_reading.converted; + memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); + snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d.%03d", value / 1000, + value % 1000); + } + + if(tmp_obj_reading.publish) { + value = tmp_007_sensor.value(TMP_007_SENSOR_TYPE_OBJECT); + tmp_obj_reading.raw = value; + + compare_and_update(&tmp_obj_reading); + + buf = tmp_obj_reading.converted; + memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); + snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d.%03d", value / 1000, + value % 1000); + } + + SENSORS_DEACTIVATE(tmp_007_sensor); + + ctimer_set(&tmp_timer, next, init_tmp_reading, NULL); +} +/*---------------------------------------------------------------------------*/ +static void +get_hdc_reading() +{ + int value; + char *buf; + clock_time_t next = SENSOR_READING_PERIOD + + (random_rand() % SENSOR_READING_RANDOM); + + if(hdc_temp_reading.publish) { + value = hdc_1000_sensor.value(HDC_1000_SENSOR_TYPE_TEMP); + if(value != CC26XX_SENSOR_READING_ERROR) { + hdc_temp_reading.raw = value; + + compare_and_update(&hdc_temp_reading); + + buf = hdc_temp_reading.converted; + memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); + snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d.%02d", value / 100, + value % 100); + } + } + + if(hdc_hum_reading.publish) { + value = hdc_1000_sensor.value(HDC_1000_SENSOR_TYPE_HUMIDITY); + if(value != CC26XX_SENSOR_READING_ERROR) { + hdc_hum_reading.raw = value; + + compare_and_update(&hdc_hum_reading); + + buf = hdc_hum_reading.converted; + memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); + snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d.%02d", value / 100, + value % 100); + } + } + + ctimer_set(&hdc_timer, next, init_hdc_reading, NULL); +} +/*---------------------------------------------------------------------------*/ +static void +get_light_reading() +{ + int value; + char *buf; + clock_time_t next = SENSOR_READING_PERIOD + + (random_rand() % SENSOR_READING_RANDOM); + + value = opt_3001_sensor.value(0); + + if(value != CC26XX_SENSOR_READING_ERROR) { + opt_reading.raw = value; + + compare_and_update(&opt_reading); + + buf = opt_reading.converted; + memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); + snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d.%02d", value / 100, + value % 100); + } + + /* The OPT will turn itself off, so we don't need to call its DEACTIVATE */ + ctimer_set(&opt_timer, next, init_light_reading, NULL); +} +/*---------------------------------------------------------------------------*/ +static void +get_mpu_reading() +{ + clock_time_t next = SENSOR_READING_PERIOD + + (random_rand() % SENSOR_READING_RANDOM); + int raw; + + if(mpu_gyro_x_reading.publish) { + raw = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_GYRO_X); + if(raw != CC26XX_SENSOR_READING_ERROR) { + mpu_gyro_x_reading.raw = raw; + } + } + + if(mpu_gyro_y_reading.publish) { + raw = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_GYRO_Y); + if(raw != CC26XX_SENSOR_READING_ERROR) { + mpu_gyro_y_reading.raw = raw; + } + } + + if(mpu_gyro_z_reading.publish) { + raw = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_GYRO_Z); + if(raw != CC26XX_SENSOR_READING_ERROR) { + mpu_gyro_z_reading.raw = raw; + } + } + + if(mpu_acc_x_reading.publish) { + raw = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_ACC_X); + if(raw != CC26XX_SENSOR_READING_ERROR) { + mpu_acc_x_reading.raw = raw; + } + } + + if(mpu_acc_y_reading.publish) { + raw = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_ACC_Y); + if(raw != CC26XX_SENSOR_READING_ERROR) { + mpu_acc_y_reading.raw = raw; + } + } + + if(mpu_acc_z_reading.publish) { + raw = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_ACC_Z); + if(raw != CC26XX_SENSOR_READING_ERROR) { + mpu_acc_z_reading.raw = raw; + } + } + + SENSORS_DEACTIVATE(mpu_9250_sensor); + + if(mpu_gyro_x_reading.publish) { + compare_and_update(&mpu_gyro_x_reading); + memset(mpu_gyro_x_reading.converted, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); + print_mpu_reading(mpu_gyro_x_reading.raw, mpu_gyro_x_reading.converted); + } + + if(mpu_gyro_y_reading.publish) { + compare_and_update(&mpu_gyro_y_reading); + memset(mpu_gyro_y_reading.converted, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); + print_mpu_reading(mpu_gyro_y_reading.raw, mpu_gyro_y_reading.converted); + } + + if(mpu_gyro_z_reading.publish) { + compare_and_update(&mpu_gyro_z_reading); + memset(mpu_gyro_z_reading.converted, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); + print_mpu_reading(mpu_gyro_z_reading.raw, mpu_gyro_z_reading.converted); + } + + if(mpu_acc_x_reading.publish) { + compare_and_update(&mpu_acc_x_reading); + memset(mpu_acc_x_reading.converted, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); + print_mpu_reading(mpu_acc_x_reading.raw, mpu_acc_x_reading.converted); + } + + if(mpu_acc_y_reading.publish) { + compare_and_update(&mpu_acc_y_reading); + memset(mpu_acc_y_reading.converted, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); + print_mpu_reading(mpu_acc_y_reading.raw, mpu_acc_y_reading.converted); + } + + if(mpu_acc_z_reading.publish) { + compare_and_update(&mpu_acc_z_reading); + memset(mpu_acc_z_reading.converted, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); + print_mpu_reading(mpu_acc_z_reading.raw, mpu_acc_z_reading.converted); + } + + /* We only use the single timer */ + ctimer_set(&mpu_timer, next, init_mpu_reading, NULL); +} +/*---------------------------------------------------------------------------*/ +static void +init_tmp_reading(void *data) +{ + if(tmp_amb_reading.publish || tmp_obj_reading.publish) { + SENSORS_ACTIVATE(tmp_007_sensor); + } else { + ctimer_set(&tmp_timer, CLOCK_SECOND, init_tmp_reading, NULL); + } +} +/*---------------------------------------------------------------------------*/ +static void +init_bmp_reading(void *data) +{ + if(bmp_pres_reading.publish || bmp_temp_reading.publish) { + SENSORS_ACTIVATE(bmp_280_sensor); + } else { + ctimer_set(&bmp_timer, CLOCK_SECOND, init_bmp_reading, NULL); + } +} +/*---------------------------------------------------------------------------*/ +static void +init_hdc_reading(void *data) +{ + if(hdc_hum_reading.publish || hdc_temp_reading.publish) { + SENSORS_ACTIVATE(hdc_1000_sensor); + } else { + ctimer_set(&hdc_timer, CLOCK_SECOND, init_hdc_reading, NULL); + } +} +/*---------------------------------------------------------------------------*/ +static void +init_light_reading(void *data) +{ + if(opt_reading.publish) { + SENSORS_ACTIVATE(opt_3001_sensor); + } else { + ctimer_set(&opt_timer, CLOCK_SECOND, init_light_reading, NULL); + } +} +/*---------------------------------------------------------------------------*/ +static void +init_mpu_reading(void *data) +{ + int readings_bitmap = 0; + + if(mpu_acc_x_reading.publish || mpu_acc_y_reading.publish || + mpu_acc_z_reading.publish) { + readings_bitmap |= MPU_9250_SENSOR_TYPE_ACC; + } + + if(mpu_gyro_x_reading.publish || mpu_gyro_y_reading.publish || + mpu_gyro_z_reading.publish) { + readings_bitmap |= MPU_9250_SENSOR_TYPE_GYRO; + } + + if(readings_bitmap) { + mpu_9250_sensor.configure(SENSORS_ACTIVE, readings_bitmap); + } else { + ctimer_set(&mpu_timer, CLOCK_SECOND, init_mpu_reading, NULL); + } +} +#endif +/*---------------------------------------------------------------------------*/ +static void +init_sensor_readings(void) +{ + /* + * Make a first pass and get all initial sensor readings. This will also + * trigger periodic value updates + */ + get_batmon_reading(NULL); + +#if BOARD_SENSORTAG + init_bmp_reading(NULL); + init_light_reading(NULL); + init_hdc_reading(NULL); + init_tmp_reading(NULL); + init_mpu_reading(NULL); +#endif /* BOARD_SENSORTAG */ + + return; +} +/*---------------------------------------------------------------------------*/ +static void +init_sensors(void) +{ + + list_add(sensor_list, &batmon_temp_reading); + list_add(sensor_list, &batmon_volt_reading); + +#if CC26XX_WEB_DEMO_ADC_DEMO + list_add(sensor_list, &adc_dio23_reading); +#endif + + SENSORS_ACTIVATE(batmon_sensor); + +#if BOARD_SENSORTAG + list_add(sensor_list, &bmp_pres_reading); + list_add(sensor_list, &bmp_temp_reading); + + list_add(sensor_list, &tmp_obj_reading); + list_add(sensor_list, &tmp_amb_reading); + + list_add(sensor_list, &opt_reading); + + list_add(sensor_list, &hdc_hum_reading); + list_add(sensor_list, &hdc_temp_reading); + + list_add(sensor_list, &mpu_acc_x_reading); + list_add(sensor_list, &mpu_acc_y_reading); + list_add(sensor_list, &mpu_acc_z_reading); + list_add(sensor_list, &mpu_gyro_x_reading); + list_add(sensor_list, &mpu_gyro_y_reading); + list_add(sensor_list, &mpu_gyro_z_reading); +#endif +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(cc26xx_web_demo_process, ev, data) +{ + PROCESS_BEGIN(); + + printf("CC26XX Web Demo Process\n"); + + init_sensors(); + + cc26xx_web_demo_publish_event = process_alloc_event(); + cc26xx_web_demo_config_loaded_event = process_alloc_event(); + cc26xx_web_demo_load_config_defaults = process_alloc_event(); + + /* Start all other (enabled) processes first */ + process_start(&httpd_simple_process, NULL); + +#if CC26XX_WEB_DEMO_COAP_SERVER + process_start(&coap_server_process, NULL); +#endif + +#if CC26XX_WEB_DEMO_6LBR_CLIENT + process_start(&cetic_6lbr_client_process, NULL); +#endif + +#if CC26XX_WEB_DEMO_MQTT_CLIENT + process_start(&mqtt_client_process, NULL); +#endif + +#if CC26XX_WEB_DEMO_NET_UART + process_start(&net_uart_process, NULL); +#endif + +#if CC26XX_WEB_DEMO_ADC_DEMO + process_start(&adc_process, NULL); +#endif + + /* + * Now that processes have set their own config default values, set our + * own defaults and restore saved config from flash... + */ + cc26xx_web_demo_config.sensors_bitmap = 0xFFFFFFFF; /* all on by default */ + cc26xx_web_demo_config.def_rt_ping_interval = + CC26XX_WEB_DEMO_DEFAULT_RSSI_MEAS_INTERVAL; + load_config(); + + /* + * Notify all other processes (basically the ones in this demo) that the + * configuration has been loaded from flash, in case they care + */ + process_post(PROCESS_BROADCAST, cc26xx_web_demo_config_loaded_event, NULL); + + init_sensor_readings(); + + httpd_simple_register_post_handler(&sensor_handler); + httpd_simple_register_post_handler(&defaults_handler); + +#if CC26XX_WEB_DEMO_READ_PARENT_RSSI + httpd_simple_register_post_handler(&ping_interval_handler); + + def_rt_rssi = 0x8000000; + uip_icmp6_echo_reply_callback_add(&echo_reply_notification, + echo_reply_handler); + etimer_set(&echo_request_timer, CC26XX_WEB_DEMO_NET_CONNECT_PERIODIC); +#endif + + etimer_set(&et, CC26XX_WEB_DEMO_NET_CONNECT_PERIODIC); + + /* + * Update all sensor readings on a configurable sensors_event + * (e.g a button press / or reed trigger) + */ + while(1) { + if(ev == PROCESS_EVENT_TIMER && etimer_expired(&et)) { + if(uip_ds6_get_global(ADDR_PREFERRED) == NULL) { + leds_on(CC26XX_WEB_DEMO_STATUS_LED); + ctimer_set(&ct, NO_NET_LED_DURATION, publish_led_off, NULL); + etimer_set(&et, CC26XX_WEB_DEMO_NET_CONNECT_PERIODIC); + } + } + +#if CC26XX_WEB_DEMO_READ_PARENT_RSSI + if(ev == PROCESS_EVENT_TIMER && etimer_expired(&echo_request_timer)) { + if(uip_ds6_get_global(ADDR_PREFERRED) == NULL) { + etimer_set(&echo_request_timer, CC26XX_WEB_DEMO_NET_CONNECT_PERIODIC); + } else { + ping_parent(); + etimer_set(&echo_request_timer, cc26xx_web_demo_config.def_rt_ping_interval); + } + } +#endif + + if(ev == button_hal_release_event && + ((button_hal_button_t *)data)->unique_id == + CC26XX_WEB_DEMO_SENSOR_READING_TRIGGER) { + init_sensor_readings(); + process_post(PROCESS_BROADCAST, cc26xx_web_demo_publish_event, NULL); + } else if(ev == button_hal_periodic_event && + ((button_hal_button_t *)data)->unique_id == + CC26XX_WEB_DEMO_SENSOR_READING_TRIGGER) { + printf("Restoring defaults!\n"); + cc26xx_web_demo_restore_defaults(); + } else if(ev == httpd_simple_event_new_config) { + save_config(); +#if BOARD_SENSORTAG + } else if(ev == sensors_event && data == &bmp_280_sensor) { + get_bmp_reading(); + } else if(ev == sensors_event && data == &opt_3001_sensor) { + get_light_reading(); + } else if(ev == sensors_event && data == &hdc_1000_sensor) { + get_hdc_reading(); + } else if(ev == sensors_event && data == &tmp_007_sensor) { + get_tmp_reading(); + } else if(ev == sensors_event && data == &mpu_9250_sensor) { + get_mpu_reading(); +#endif + } + + PROCESS_YIELD(); + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +#if CC26XX_WEB_DEMO_ADC_DEMO +PROCESS_THREAD(adc_process, ev, data) +{ + PROCESS_BEGIN(); + + etimer_set(&et_adc, CLOCK_SECOND * 5); + + while(1) { + + PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et_adc)); + + /* intialisation of ADC */ + ti_lib_aon_wuc_aux_wakeup_event(AONWUC_AUX_WAKEUP); + while(!(ti_lib_aon_wuc_power_status_get() & AONWUC_AUX_POWER_ON)); + + /* + * Enable clock for ADC digital and analog interface (not currently enabled + * in driver) + */ + ti_lib_aux_wuc_clock_enable(AUX_WUC_ADI_CLOCK | AUX_WUC_ANAIF_CLOCK | + AUX_WUC_SMPH_CLOCK); + while(ti_lib_aux_wuc_clock_status(AUX_WUC_ADI_CLOCK | AUX_WUC_ANAIF_CLOCK | + AUX_WUC_SMPH_CLOCK) + != AUX_WUC_CLOCK_READY); + + /* Connect AUX IO7 (DIO23, but also DP2 on XDS110) as analog input. */ + ti_lib_aux_adc_select_input(ADC_COMPB_IN_AUXIO7); + + /* Set up ADC range, AUXADC_REF_FIXED = nominally 4.3 V */ + ti_lib_aux_adc_enable_sync(AUXADC_REF_FIXED, AUXADC_SAMPLE_TIME_2P7_US, + AUXADC_TRIGGER_MANUAL); + + /* Trigger ADC converting */ + ti_lib_aux_adc_gen_manual_trigger(); + + /* Read value */ + single_adc_sample = ti_lib_aux_adc_read_fifo(); + + /* Shut the adc down */ + ti_lib_aux_adc_disable(); + + get_adc_reading(NULL); + + etimer_reset(&et_adc); + } + + PROCESS_END(); +} +#endif +/*---------------------------------------------------------------------------*/ +/** + * @} + */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.h b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.h new file mode 100644 index 000000000..1840c31b1 --- /dev/null +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.h @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/** + * \addtogroup cc26xx-examples + * @{ + * + * \defgroup cc26xx-web-demo CC26xx Web Demo + * @{ + * + * An example demonstrating: + * * how to use a CC26XX-powered node in a deployment driven by a 6LBR + * * how to expose on-device sensors as CoAP resources + * * how to build a small web page which reports networking and sensory data + * * how to configure functionality through the aforementioned web page using + * HTTP POST requests + * * a network-based UART + * + * \file + * Main header file for the CC26XX web demo. + */ +/*---------------------------------------------------------------------------*/ +#ifndef CC26XX_WEB_DEMO_H_ +#define CC26XX_WEB_DEMO_H_ +/*---------------------------------------------------------------------------*/ +#include "dev/leds.h" +#include "sys/process.h" +#include "mqtt-client.h" +#include "net-uart.h" + +#include +/*---------------------------------------------------------------------------*/ +#ifdef CC26XX_WEB_DEMO_CONF_MQTT_CLIENT +#define CC26XX_WEB_DEMO_MQTT_CLIENT CC26XX_WEB_DEMO_CONF_MQTT_CLIENT +#else +#define CC26XX_WEB_DEMO_MQTT_CLIENT 1 +#endif + +#ifdef CC26XX_WEB_DEMO_CONF_6LBR_CLIENT +#define CC26XX_WEB_DEMO_6LBR_CLIENT CC26XX_WEB_DEMO_CONF_6LBR_CLIENT +#else +#define CC26XX_WEB_DEMO_6LBR_CLIENT 1 +#endif + +#ifdef CC26XX_WEB_DEMO_CONF_COAP_SERVER +#define CC26XX_WEB_DEMO_COAP_SERVER CC26XX_WEB_DEMO_CONF_COAP_SERVER +#else +#define CC26XX_WEB_DEMO_COAP_SERVER 1 +#endif + +#ifdef CC26XX_WEB_DEMO_CONF_NET_UART +#define CC26XX_WEB_DEMO_NET_UART CC26XX_WEB_DEMO_CONF_NET_UART +#else +#define CC26XX_WEB_DEMO_NET_UART 1 +#endif + +#ifdef CC26XX_WEB_DEMO_CONF_ADC_DEMO +#define CC26XX_WEB_DEMO_ADC_DEMO CC26XX_WEB_DEMO_CONF_ADC_DEMO +#else +#define CC26XX_WEB_DEMO_ADC_DEMO 0 +#endif +/*---------------------------------------------------------------------------*/ +/* Active probing of RSSI from our preferred parent */ +#if (CC26XX_WEB_DEMO_COAP_SERVER || CC26XX_WEB_DEMO_MQTT_CLIENT) +#define CC26XX_WEB_DEMO_READ_PARENT_RSSI 1 +#else +#define CC26XX_WEB_DEMO_READ_PARENT_RSSI 0 +#endif + +#define CC26XX_WEB_DEMO_RSSI_MEASURE_INTERVAL_MAX 86400 /* secs: 1 day */ +#define CC26XX_WEB_DEMO_RSSI_MEASURE_INTERVAL_MIN 5 /* secs */ +/*---------------------------------------------------------------------------*/ +/* User configuration */ +/* Take a sensor reading on button press */ +#define CC26XX_WEB_DEMO_SENSOR_READING_TRIGGER BUTTON_HAL_ID_KEY_LEFT + +/* Payload length of ICMPv6 echo requests used to measure RSSI with def rt */ +#define CC26XX_WEB_DEMO_ECHO_REQ_PAYLOAD_LEN 20 + +#if BOARD_SENSORTAG +/* Force an MQTT publish on sensor event */ +#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BUTTON_HAL_ID_REED_RELAY +#elif BOARD_LAUNCHPAD +#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BUTTON_HAL_ID_KEY_LEFT +#else +#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BUTTON_HAL_ID_KEY_DOWN +#endif + +#define CC26XX_WEB_DEMO_STATUS_LED LEDS_GREEN +/*---------------------------------------------------------------------------*/ +/* A timeout used when waiting to connect to a network */ +#define CC26XX_WEB_DEMO_NET_CONNECT_PERIODIC (CLOCK_SECOND >> 3) +/*---------------------------------------------------------------------------*/ +/* Default configuration values */ +#define CC26XX_WEB_DEMO_DEFAULT_ORG_ID "quickstart" +#if CPU_FAMILY_CC13XX +#define CC26XX_WEB_DEMO_DEFAULT_TYPE_ID "cc13xx" +#else +#define CC26XX_WEB_DEMO_DEFAULT_TYPE_ID "cc26xx" +#endif +#define CC26XX_WEB_DEMO_DEFAULT_EVENT_TYPE_ID "status" +#define CC26XX_WEB_DEMO_DEFAULT_SUBSCRIBE_CMD_TYPE "+" +#define CC26XX_WEB_DEMO_DEFAULT_BROKER_PORT 1883 +#define CC26XX_WEB_DEMO_DEFAULT_PUBLISH_INTERVAL (30 * CLOCK_SECOND) +#define CC26XX_WEB_DEMO_DEFAULT_KEEP_ALIVE_TIMER 60 +#define CC26XX_WEB_DEMO_DEFAULT_RSSI_MEAS_INTERVAL (CLOCK_SECOND * 30) +/*---------------------------------------------------------------------------*/ +/* + * You normally won't have to change anything from here onwards unless you are + * extending the example + */ +/*---------------------------------------------------------------------------*/ +/* Sensor types */ +#define CC26XX_WEB_DEMO_SENSOR_BATMON_TEMP 0 +#define CC26XX_WEB_DEMO_SENSOR_BATMON_VOLT 1 +#define CC26XX_WEB_DEMO_SENSOR_BMP_PRES 2 +#define CC26XX_WEB_DEMO_SENSOR_BMP_TEMP 3 +#define CC26XX_WEB_DEMO_SENSOR_TMP_AMBIENT 4 +#define CC26XX_WEB_DEMO_SENSOR_TMP_OBJECT 5 +#define CC26XX_WEB_DEMO_SENSOR_HDC_TEMP 6 +#define CC26XX_WEB_DEMO_SENSOR_HDC_HUMIDITY 7 +#define CC26XX_WEB_DEMO_SENSOR_OPT_LIGHT 8 +#define CC26XX_WEB_DEMO_SENSOR_MPU_ACC_X 9 +#define CC26XX_WEB_DEMO_SENSOR_MPU_ACC_Y 10 +#define CC26XX_WEB_DEMO_SENSOR_MPU_ACC_Z 11 +#define CC26XX_WEB_DEMO_SENSOR_MPU_GYRO_X 12 +#define CC26XX_WEB_DEMO_SENSOR_MPU_GYRO_Y 13 +#define CC26XX_WEB_DEMO_SENSOR_MPU_GYRO_Z 14 +#define CC26XX_WEB_DEMO_SENSOR_ADC_DIO23 15 +/*---------------------------------------------------------------------------*/ +extern process_event_t cc26xx_web_demo_publish_event; +extern process_event_t cc26xx_web_demo_config_loaded_event; +extern process_event_t cc26xx_web_demo_load_config_defaults; +/*---------------------------------------------------------------------------*/ +#define CC26XX_WEB_DEMO_UNIT_TEMP "C" +#define CC26XX_WEB_DEMO_UNIT_VOLT "mV" +#define CC26XX_WEB_DEMO_UNIT_PRES "hPa" +#define CC26XX_WEB_DEMO_UNIT_HUMIDITY "%RH" +#define CC26XX_WEB_DEMO_UNIT_LIGHT "lux" +#define CC26XX_WEB_DEMO_UNIT_ACC "G" +#define CC26XX_WEB_DEMO_UNIT_GYRO "deg per sec" +/*---------------------------------------------------------------------------*/ +/* A data type for sensor readings, internally stored in a linked list */ +#define CC26XX_WEB_DEMO_CONVERTED_LEN 12 + +typedef struct cc26xx_web_demo_sensor_reading { + struct cc26xx_web_demo_sensor_reading *next; + int raw; + int last; + const char *descr; + const char *xml_element; + const char *form_field; + char *units; + uint8_t type; + uint8_t publish; + uint8_t changed; + char converted[CC26XX_WEB_DEMO_CONVERTED_LEN]; +} cc26xx_web_demo_sensor_reading_t; +/*---------------------------------------------------------------------------*/ +/* Global configuration */ +typedef struct cc26xx_web_demo_config_s { + uint32_t magic; + int len; + uint32_t sensors_bitmap; + int def_rt_ping_interval; + mqtt_client_config_t mqtt_config; + net_uart_config_t net_uart; +} cc26xx_web_demo_config_t; + +extern cc26xx_web_demo_config_t cc26xx_web_demo_config; +/*---------------------------------------------------------------------------*/ +/** + * \brief Performs a lookup for a reading of a specific type of sensor + * \param sens_type CC26XX_WEB_DEMO_SENSOR_BATMON_TEMP... + * \return A pointer to the reading data structure or NULL + */ +const cc26xx_web_demo_sensor_reading_t *cc26xx_web_demo_sensor_lookup(int sens_type); + +/** + * \brief Returns the first available sensor reading + * \return A pointer to the reading data structure or NULL + */ +const cc26xx_web_demo_sensor_reading_t *cc26xx_web_demo_sensor_first(void); + +/** + * \brief Print an IPv6 address into a buffer + * \param buf A pointer to the buffer where this function will print the IPv6 + * address + * \param buf_len the length of the buffer + * \param addr A pointer to the IPv6 address + * \return The number of bytes written to the buffer + * + * It is the caller's responsibility to allocate enough space for buf + */ +int cc26xx_web_demo_ipaddr_sprintf(char *buf, uint8_t buf_len, + const uip_ipaddr_t *addr); + +/** + * \brief Resets the example to a default configuration + */ +void cc26xx_web_demo_restore_defaults(void); +/*---------------------------------------------------------------------------*/ +#endif /* CC26XX_WEB_DEMO_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ From 813543b5694b22afaa2b5e411c68e25865e69874 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Wed, 25 Jul 2018 15:05:08 +0200 Subject: [PATCH 297/485] Implented SPI HAL for CC13xx/CC26xx --- arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 1 + arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h | 41 +++ arch/cpu/cc13xx-cc26xx/dev/spi-arch.c | 265 ++++++++++++++++++ .../cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 4 +- .../cc13xx-cc26xx/launchpad/board-conf.h | 11 + .../cc13xx-cc26xx/sensortag/board-conf.h | 11 + .../cc13xx-cc26xx/srf06/Makefile.srf06 | 2 +- os/dev/spi.h | 1 + 8 files changed, 333 insertions(+), 3 deletions(-) create mode 100644 arch/cpu/cc13xx-cc26xx/dev/spi-arch.c diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index 6322e9a1b..581422d56 100644 --- a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -73,6 +73,7 @@ CONTIKI_CPU_SOURCEFILES += watchdog-arch.c dbg-arch.c CONTIKI_CPU_SOURCEFILES += uart0-arch.c slip-arch.c CONTIKI_CPU_SOURCEFILES += gpio-hal-arch.c int-master-arch.c CONTIKI_CPU_SOURCEFILES += random.c trng-arch.c +CONTIKI_CPU_SOURCEFILES += spi-arch.c # RF source files CONTIKI_CPU_SOURCEFILES += sched.c data-queue.c diff --git a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h index fad5bcf5e..09790cebc 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h +++ b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h @@ -410,6 +410,47 @@ #endif /** @} */ /*---------------------------------------------------------------------------*/ +/** + * \name SPI HAL configuration. + * + * CC13x0/CC26x0 has one SPI interface, while CC13x2/CC26x2 has two + * SPI interfaces. Some additional checks has to be made for the + * SPI_CONF_CONTROLLER_COUNT configuration, as this relies on whether the + * available SPI interfaces are enabled or not, as well as if the SPI driver + * is enabled at all. + * + * @{ + */ +#if TI_SPI_CONF_ENABLE +/* + * The SPI driver is enabled. Therefore, the number of SPI interfaces depends + * on which Device family parent the device falls under and if any of its + * corresponding SPI interfaces are enabled or not. + */ + +#define SPI0_IS_ENABLED ((TI_SPI_CONF_SPI0_ENABLE) ? 1 : 0) +#define SPI1_IS_ENABLED ((TI_SPI_CONF_SPI1_ENABLE) ? 1 : 0) + +#if (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0) + +/* CC13x0/CC26x0 only has one SPI interface: SPI0. */ +#define SPI_CONF_CONTROLLER_COUNT (SPI0_IS_ENABLED) + +#elif (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X2_CC26X2) + +/* CC13x0/CC26x0 only has two SPI interface: SPI0 and SPI1. */ +#define SPI_CONF_CONTROLLER_COUNT (SPI0_ENABLED + SPI1_IS_ENABLED) + +#endif /* DeviceFamily_PARENT */ + +#else /* TI_SPI_CONF_ENABLE */ +/* + * If the SPI driver is disabled then there are 0 available + * SPI interfaces. */ +#define SPI_CONF_CONTROLLER_COUNT 0 +#endif /* TI_SPI_CONF_ENABLE */ +/** @} */ +/*---------------------------------------------------------------------------*/ /** * \name Slip configuration * diff --git a/arch/cpu/cc13xx-cc26xx/dev/spi-arch.c b/arch/cpu/cc13xx-cc26xx/dev/spi-arch.c new file mode 100644 index 000000000..7fe41762b --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/dev/spi-arch.c @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/** + * \addtogroup cc13xx-cc26xx-cpu + * @{ + * + * \defgroup cc13xx-cc26xx-spi CC13xx/CC26xx SPI HAL + * + * @{ + * \file + * Implementation of the SPI HAL driver for CC13xx/CC26xx. + * \author + * Edvard Pettersen + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "sys/cc.h" +#include "dev/spi.h" +/*---------------------------------------------------------------------------*/ +#include +#include +#include +/*---------------------------------------------------------------------------*/ +#include +#include +#include +/*---------------------------------------------------------------------------*/ +typedef struct { + SPI_Handle handle; + spi_device_t *owner; +} spi_arch_t; +/*---------------------------------------------------------------------------*/ +#if (SPI_CONTROLLER_COUNT > 0) +static spi_arch_t spi_arches[SPI_CONTROLLER_COUNT]; +#else +static spi_arch_t *spi_arches = NULL; +#endif +/*---------------------------------------------------------------------------*/ +static inline spi_arch_t* +get_handle(uint8_t spi_controller) +{ + if(spi_controller < SPI_CONTROLLER_COUNT) { + return &spi_arches[spi_controller]; + } else { + return NULL; + } +} +/*---------------------------------------------------------------------------*/ +static SPI_FrameFormat +convert_frame_format(uint8_t pol, uint8_t pha) +{ + pol = (pol) ? 1 : 0; + pha = (pha) ? 1 : 0; + /* + * Convert pol/pha to a single byte on the following format: + * xxxA xxxB + * where A is the polarity bit and B is the phase bit. + * Note that any other value deviating from this format will + * default to the SPI_POL1_PHA1 format. + */ + uint8_t pol_pha = (pol << 4) | (pha << 0); + switch(pol_pha) { + case 0x00: return SPI_POL0_PHA0; + case 0x01: return SPI_POL0_PHA1; + case 0x10: return SPI_POL1_PHA0; + default: /* fallthrough */ + case 0x11: return SPI_POL1_PHA1; + } +} +/*---------------------------------------------------------------------------*/ +bool +spi_arch_has_lock(spi_device_t *dev) +{ + /* + * The SPI device is the owner if the SPI controller returns a valid + * SPI arch object and the SPI device is owner of that object. + */ + spi_arch_t *spi_arch = get_handle(dev->spi_controller); + return (spi_arch != NULL) && (spi_arch->owner == dev); +} +/*---------------------------------------------------------------------------*/ +bool +spi_arch_is_bus_locked(spi_device_t *dev) +{ + /* + * The SPI controller is locked by any device if the SPI controller returns + * a valid SPI arch object and the SPI handle of that object is valid. + */ + spi_arch_t *spi_arch = get_handle(dev->spi_controller); + return (spi_arch != NULL) && (spi_arch->handle != NULL); +} +/*---------------------------------------------------------------------------*/ +spi_status_t +spi_arch_lock_and_open(spi_device_t *dev) +{ + uint_least8_t spi_index; + spi_arch_t *spi_arch; + SPI_Params spi_params; + + const uintptr_t hwi_key = HwiP_disable(); + + spi_index = dev->spi_controller; + spi_arch = get_handle(spi_index); + + /* Ensure the provided SPI index is valid. */ + if(spi_arch == NULL) { + HwiP_restore(hwi_key); + return SPI_DEV_STATUS_EINVAL; + } + + /* Ensure the corresponding SPI interface is not already locked. */ + if(spi_arch_is_bus_locked(dev)) { + HwiP_restore(hwi_key); + return SPI_DEV_STATUS_BUS_LOCKED; + } + + SPI_Params_init(&spi_params); + + spi_params.transferMode = SPI_MODE_BLOCKING; + spi_params.mode = SPI_MASTER; + spi_params.bitRate = dev->spi_bit_rate; + spi_params.dataSize = 8; + spi_params.frameFormat = convert_frame_format(dev->spi_pol, dev->spi_pha); + + /* + * Try to open the SPI driver. Accessing the SPI driver also ensures + * atomic access to the SPI interface. + */ + spi_arch->handle = SPI_open(spi_index, &spi_params); + + if(spi_arch->handle == NULL) { + HwiP_restore(hwi_key); + return SPI_DEV_STATUS_BUS_LOCKED; + } + + spi_arch->owner = dev; + + HwiP_restore(hwi_key); + return SPI_DEV_STATUS_OK; +} +/*---------------------------------------------------------------------------*/ +spi_status_t +spi_arch_close_and_unlock(spi_device_t *dev) +{ + spi_arch_t *spi_arch; + + const uintptr_t hwi_key = HwiP_disable(); + + /* Ensure the provided SPI index is valid. */ + spi_arch = get_handle(dev->spi_controller); + if(spi_arch == NULL) { + HwiP_restore(hwi_key); + return SPI_DEV_STATUS_EINVAL; + } + + /* Ensure the corresponding SPI device owns the SPI controller. */ + if(!spi_arch_has_lock(dev)) { + HwiP_restore(hwi_key); + return SPI_DEV_STATUS_BUS_NOT_OWNED; + } + + SPI_close(spi_arch->handle); + + spi_arch->handle = NULL; + spi_arch->owner = NULL; + + HwiP_restore(hwi_key); + return SPI_DEV_STATUS_OK; +} +/*---------------------------------------------------------------------------*/ +spi_status_t +spi_arch_transfer(spi_device_t *dev, + const uint8_t *write_buf, int wlen, + uint8_t *inbuf, int rlen, int ignore_len) +{ + spi_arch_t *spi_arch; + size_t totlen; + SPI_Transaction spi_transaction; + bool transfer_ok; + + /* Ensure the provided SPI index is valid. */ + spi_arch = get_handle(dev->spi_controller); + if(spi_arch == NULL) { + return SPI_DEV_STATUS_EINVAL; + } + + if(!spi_arch_has_lock(dev)) { + return SPI_DEV_STATUS_BUS_NOT_OWNED; + } + + totlen = MAX((size_t)(rlen + ignore_len), (size_t)wlen); + + if(totlen == 0) { + /* Nothing to do */ + return SPI_DEV_STATUS_OK; + } + + spi_transaction.count = totlen; + spi_transaction.txBuf = (void *)write_buf; + spi_transaction.rxBuf = (void *)inbuf; + + transfer_ok = SPI_transfer(spi_arch->handle, &spi_transaction); + + if(!transfer_ok) { + return SPI_DEV_STATUS_TRANSFER_ERR; + } + + return SPI_DEV_STATUS_OK; +} +/*---------------------------------------------------------------------------*/ +spi_status_t +spi_arch_select(spi_device_t *dev) +{ + if(!spi_arch_has_lock(dev)) { + return SPI_DEV_STATUS_BUS_NOT_OWNED; + } + + PINCC26XX_setOutputValue(dev->pin_spi_cs, 0); + + return SPI_DEV_STATUS_OK; +} +/*---------------------------------------------------------------------------*/ +spi_status_t +spi_arch_deselect(spi_device_t *dev) +{ + if(!spi_arch_has_lock(dev)) { + return SPI_DEV_STATUS_BUS_NOT_OWNED; + } + + PINCC26XX_setOutputValue(dev->pin_spi_cs, 1); + + return SPI_DEV_STATUS_OK; +} +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ \ No newline at end of file diff --git a/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index dc681a5eb..959e19105 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -6,8 +6,8 @@ BOARD_PLATFORMS = launchpad sensortag srf06 # All supported boards for this SimpleLink family -BOARDS := $(foreach BOARD_TYPE, $(BOARD_PLATFORMS), \ - $(shell cd $(FAMILY_PATH); find $(BOARD_TYPE)/* -type d -print)) +BOARDS := $(foreach BOARD, $(BOARD_PLATFORMS), \ + $(shell cd $(FAMILY_PATH); find $(BOARD)/* -type d -print)) ################################################################################ # Directory and source configurations diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-conf.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-conf.h index f700baa08..a096f0072 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-conf.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-conf.h @@ -50,6 +50,8 @@ #ifndef BOARD_CONF_H_ #define BOARD_CONF_H_ /*---------------------------------------------------------------------------*/ +#include "contiki-conf.h" +/*---------------------------------------------------------------------------*/ /** * \name LED configurations for the dev/leds.h API. * @@ -83,6 +85,15 @@ #define BOARD_CONF_HAS_SENSORS 0 /** @} */ /*---------------------------------------------------------------------------*/ +/** + * \name The external flash SPI CS pin, defined in Board.h. + * + * Those values are not meant to be modified by the user + * @{ + */ +#define EXT_FLASH_SPI_PIN_CS Board_SPI_FLASH_CS +/** @} */ +/*---------------------------------------------------------------------------*/ #endif /* BOARD_CONF_H_ */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h index fa3c4e406..d676f3375 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h @@ -50,6 +50,8 @@ #ifndef BOARD_CONF_H_ #define BOARD_CONF_H_ /*---------------------------------------------------------------------------*/ +#include "contiki-conf.h" +/*---------------------------------------------------------------------------*/ #include "leds-arch.h" /*---------------------------------------------------------------------------*/ /** @@ -81,6 +83,15 @@ #define BOARD_SENSORS_ENABLE (!(BOARD_CONF_SENSORS_DISABLE)) /** @} */ /*---------------------------------------------------------------------------*/ +/** + * \name The external flash SPI CS pin, defined in Board.h. + * + * Those values are not meant to be modified by the user + * @{ + */ +#define EXT_FLASH_SPI_PIN_CS Board_SPI_FLASH_CS +/** @} */ +/*---------------------------------------------------------------------------*/ #endif /* BOARD_CONF_H_ */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/Makefile.srf06 b/arch/platform/simplelink/cc13xx-cc26xx/srf06/Makefile.srf06 index 500b8414d..d6686e10a 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/Makefile.srf06 +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/Makefile.srf06 @@ -1,7 +1,7 @@ ################################################################################ # SimpleLink LaunchPad makefile -BOARD_TYPE = BOARD_SRF06 +BOARD_TYPE = BOARD_SMARTRF06EB # leds-arch.c etc. BOARD_SOURCEFILES += srf06-sensors.c diff --git a/os/dev/spi.h b/os/dev/spi.h index 0c9aadc73..70faa6b5b 100644 --- a/os/dev/spi.h +++ b/os/dev/spi.h @@ -80,6 +80,7 @@ typedef enum { SPI_DEV_STATUS_OK, /* Everything OK */ SPI_DEV_STATUS_EINVAL, /* Erroneous input value */ + SPI_DEV_STATUS_TRANSFER_ERR, /* Error during SPI transfer */ SPI_DEV_STATUS_BUS_LOCKED, /* SPI bus is already locked */ SPI_DEV_STATUS_BUS_NOT_OWNED, /* SPI bus is locked by someone else */ SPI_DEV_STATUS_CLOSED /* SPI bus has not opened properly */ From 210db77835c4bc7059410d570721b370f1a1444e Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Wed, 25 Jul 2018 15:16:45 +0200 Subject: [PATCH 298/485] Cleaned up CCFG file handling --- arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 15 +++--- .../{ccfg-conf.h => ccfg-conf.c} | 25 +++++++--- arch/cpu/cc13xx-cc26xx/ccfg.c | 50 ------------------- 3 files changed, 25 insertions(+), 65 deletions(-) rename arch/cpu/cc13xx-cc26xx/{ccfg-conf.h => ccfg-conf.c} (91%) delete mode 100644 arch/cpu/cc13xx-cc26xx/ccfg.c diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index 581422d56..fc7ef5b62 100644 --- a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -25,9 +25,9 @@ endif # Clean up the path. CORE_SDK := $(realpath $(CORE_SDK)) -# Both ccfg.c and startup_cc13xx_cc26xx_gcc.c is located locally in +# Both ccfg-conf.c and startup_cc13xx_cc26xx_gcc.c is located locally in # the arch/cpu/cc13xx-cc26xx folder. -CPU_START_SOURCEFILES += ccfg.c startup_cc13xx_cc26xx_gcc.c +CPU_START_SOURCEFILES += ccfg-conf.c startup_cc13xx_cc26xx_gcc.c ################################################################################ ### Device Family @@ -107,7 +107,7 @@ CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES) $(DEBUG_IO_SOURCEFILES) ################################################################################ ### Linker configuration -# Linker flag +# Linker flags LDFLAGS += --entry resetISR LDFLAGS += -static LDFLAGS += --specs=nano.specs @@ -117,16 +117,17 @@ LDSCRIPT := $(CONTIKI_CPU)/$(SUBFAMILY)/$(SUBFAMILY).lds ################################################################################ ### Specialized build targets -# Always re-build ieee-addr.o in case the command line passes a new NODEID +.PHONY: FORCE FORCE: +# Always re-build ieee-addr.o in case the command line passes a new NODEID $(OBJECTDIR)/ieee-addr.o: ieee-addr.c FORCE | $(OBJECTDIR) $(TRACE_CC) $(Q)$(CC) $(CFLAGS) -c $< -o $@ -# Always re-build ccfg.c so changes to ccfg-conf.h will apply without having -# to make clean first -$(OBJECTDIR)/ccfg.o: ccfg.c FORCE | $(OBJECTDIR) +# Always re-build ccfg-conf.c so any changes to CCFG configuration +# always applies +$(OBJECTDIR)/ccfg-conf.o: ccfg-conf.c FORCE | $(OBJECTDIR) $(TRACE_CC) $(Q)$(CC) $(CFLAGS) -c $< -o $@ diff --git a/arch/cpu/cc13xx-cc26xx/ccfg-conf.h b/arch/cpu/cc13xx-cc26xx/ccfg-conf.c similarity index 91% rename from arch/cpu/cc13xx-cc26xx/ccfg-conf.h rename to arch/cpu/cc13xx-cc26xx/ccfg-conf.c index 23bc5dc9a..fecdca7c1 100644 --- a/arch/cpu/cc13xx-cc26xx/ccfg-conf.h +++ b/arch/cpu/cc13xx-cc26xx/ccfg-conf.c @@ -27,19 +27,20 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/** + /** * \addtogroup cc13xx-cc26xx-cpu * @{ * + * \defgroupt cc13xx-cc26xx-ccfg Customer Configuration (CCFG) + * + * @{ + * * \file - * Customer Configuration (CCFG) for the CC13xx/CC26xx CPU family. + * Configuration of CCFG. * \author * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ -#ifndef CCFG_CONF_H_ -#define CCFG_CONF_H_ -/*---------------------------------------------------------------------------*/ #include "contiki-conf.h" /*---------------------------------------------------------------------------*/ /** @@ -58,7 +59,7 @@ #define SET_CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE 0x00 #define SET_CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE 0x00 #define SET_CCFG_CCFG_TAP_DAP_1_WUC_TAP_ENABLE 0x00 -#endif +#endif /* CCFG_CONF_JTAG_INTERFACE_DISABLE */ /** @} */ /*---------------------------------------------------------------------------*/ /** @@ -92,11 +93,19 @@ #define SET_CCFG_BL_CONFIG_BL_PIN_NUMBER CCFG_CONF_BL_PIN_NUMBER #endif #define SET_CCFG_BL_CONFIG_BL_ENABLE 0xC5 -#endif +#endif /* CCFG_CONF_ROM_BOOTLOADER_ENABLE */ /** @} */ /*---------------------------------------------------------------------------*/ -#endif /* CCFG_CONF_H_ */ +/** + * \name Include the device-specific CCFG file from the SDK. + * + * @{ + */ +#include +#include DeviceFamily_constructPath(startup_files/ccfg.c) +/** @} */ /*---------------------------------------------------------------------------*/ /** + * @} * @} */ diff --git a/arch/cpu/cc13xx-cc26xx/ccfg.c b/arch/cpu/cc13xx-cc26xx/ccfg.c deleted file mode 100644 index 764b80196..000000000 --- a/arch/cpu/cc13xx-cc26xx/ccfg.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ - /** - * \addtogroup cc13xx-cc26xx-cpu - * @{ - * - * \file - * Customer Configuration (CCFG). - * \author - * Edvard Pettersen - */ -/*---------------------------------------------------------------------------*/ -/** - * Customer Configuration for CC13xx/CC26xx devices. This file is used to - * configure Boot ROM, start-up code, and SW radio behaviour. - * - * Configuration is done in ccfg-conf.h. - */ -#include "ccfg-conf.h" - -#include -#include DeviceFamily_constructPath(startup_files/ccfg.c) -/*---------------------------------------------------------------------------*/ From 08bda8bed790b440f74878271eb2c9e1f2eec4a1 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Wed, 25 Jul 2018 16:59:28 +0200 Subject: [PATCH 299/485] Fixed compiler errors --- .../rf-settings/cc13x0/ble-tx-power.c | 2 +- arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c | 9 +++---- arch/cpu/cc13xx-cc26xx/rf/prop-mode.c | 25 ++++++++++--------- arch/cpu/cc13xx-cc26xx/rf/sched.c | 17 +++++++++++-- arch/cpu/cc13xx-cc26xx/rf/settings.h | 13 +++++----- .../launchpad/cc1350-4/CC1350_LAUNCHXL_433.c | 23 +++++++++++++++++ .../launchpad/cc1350-4/CC1350_LAUNCHXL_433.h | 10 ++++++++ .../launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h | 10 ++++---- .../cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c | 1 - .../cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c | 1 - 10 files changed, 78 insertions(+), 33 deletions(-) diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-tx-power.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-tx-power.c index 16a5b37b7..a0ae346c5 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-tx-power.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-tx-power.c @@ -82,7 +82,7 @@ tx_power_table_t rf_ble_tx_power_table_empty[] = }; /*---------------------------------------------------------------------------*/ /* TX power table, based on which board is used. */ -#elif defined(DEVICE_CC1350) || defined(DEVICE_CC1350_4) +#if defined(DEVICE_CC1350) || defined(DEVICE_CC1350_4) #define TX_POWER_TABLE rf_ble_tx_power_table_cc1350 #else diff --git a/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c b/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c index f4b693aa8..22b1a9658 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c +++ b/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c @@ -62,11 +62,10 @@ #include #include /*---------------------------------------------------------------------------*/ -#if 0 -#define PRINTF(...) printf(__VA_ARGS__) -#else -#define PRINTF(...) -#endif +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Radio" +#define LOG_LEVEL LOG_LEVEL_NONE /*---------------------------------------------------------------------------*/ #if RF_BLE_BEACON_ENABLE /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c b/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c index a2ff18635..7aa906a3a 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c +++ b/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c @@ -250,8 +250,8 @@ set_channel(uint16_t channel) rf_result_t res; if(!dot_15_4g_chan_in_range(channel)) { - PRINTF("set_channel: illegal channel %d, defaults to %d\n", - (int)channel, DOT_15_4G_DEFAULT_CHAN); + LOG_WARN("Supplied hannel %d is illegal, defaults to %d\n", + (int)channel, DOT_15_4G_DEFAULT_CHAN); channel = DOT_15_4G_DEFAULT_CHAN; } @@ -264,7 +264,7 @@ set_channel(uint16_t channel) const uint16_t freq = (uint16_t)(new_freq / 1000); const uint16_t frac = (uint16_t)(((new_freq - (freq * 1000)) * 0x10000) / 1000); - PRINTF("set_channel: %u = 0x%04x.0x%04x (%lu)\n", + LOG_DBG("Set channel to %d, frequency 0x%04X.0x%04X (%lu)\n", (int)channel, freq, frac, new_freq); cmd_fs.frequency = freq; @@ -315,7 +315,7 @@ transmit(unsigned short transmit_len) rf_result_t res; if(tx_is_active()) { - PRINTF("transmit: not allowed while transmitting\n"); + LOG_ERR("A transmission is already active\n"); return RADIO_TX_ERR; } @@ -392,7 +392,7 @@ read(void *buf, unsigned short buf_len) /* Sanity check that Frame is at least Frame Shave bytes long */ if(frame_len < FRAME_SHAVE) { - PRINTF("read: frame too short len=%d\n", frame_len); + LOG_ERR("Received rame is too short, len=%d\n", frame_len); data_queue_release_entry(); return 0; @@ -403,7 +403,8 @@ read(void *buf, unsigned short buf_len) /* Sanity check that Payload fits in Buffer */ if(payload_len > buf_len) { - PRINTF("read: payload too large for buffer len=%d buf_len=%d\n", payload_len, buf_len); + LOG_ERR("Payload of received frame is too large for local buffer, len=%d buf_len=%d\n", + payload_len, buf_len); data_queue_release_entry(); return 0; @@ -441,7 +442,7 @@ static int channel_clear(void) { if(tx_is_active()) { - PRINTF("channel_clear: called while in TX\n"); + LOG_ERR("Channel clear called while in TX\n"); return 0; } @@ -497,7 +498,7 @@ on(void) rf_result_t res; if(prop_radio.rf_is_on) { - PRINTF("on: Radio already on\n"); + LOG_WARN("Radio is already on\n"); return RF_RESULT_OK; } @@ -517,7 +518,7 @@ static int off(void) { if(!prop_radio.rf_is_on) { - PRINTF("off: Radio already off\n"); + LOG_WARN("Radio is already off\n"); return RF_RESULT_OK; } @@ -649,7 +650,7 @@ static int init(void) { if(prop_radio.rf_handle) { - PRINTF("init: Radio already initialized\n"); + LOG_WARN("Radio is already initialized\n"); return RF_RESULT_OK; } @@ -657,7 +658,7 @@ init(void) prop_radio.rf_is_on = false; /* Set configured RSSI threshold */ - prop_radio.rssi_threshold = PROP_MODE_RSSI_THRESHOLD; + prop_radio.rssi_threshold = PROP_MODE_CCA_RSSI_THRESHOLD; init_rf_params(); @@ -670,7 +671,7 @@ init(void) prop_radio.rf_handle = netstack_open(&rf_params); if(prop_radio.rf_handle == NULL) { - PRINTF("init: unable to open RF driver\n"); + LOG_ERR("Unable to open RF driver during initialization\n"); return RF_RESULT_ERROR; } diff --git a/arch/cpu/cc13xx-cc26xx/rf/sched.c b/arch/cpu/cc13xx-cc26xx/rf/sched.c index 85e7f5e7e..73957e33b 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/sched.c +++ b/arch/cpu/cc13xx-cc26xx/rf/sched.c @@ -83,14 +83,17 @@ #define EVENTS_CMD_DONE(events) (((events) & RF_EVENTS_CMD_DONE) != 0) /*---------------------------------------------------------------------------*/ /* Synth re-calibration every 3 minutes */ -#define SYNTH_RECAL_INTERVAL (CLOCK_SECOND * 60 * 3) +#define SYNTH_RECAL_INTERVAL (CLOCK_SECOND * 60 * 3) /* Set re-calibration interval with a jitter of 10 seconds */ -#define SYNTH_RECAL_JITTER (CLOCK_SECOND * 10) +#define SYNTH_RECAL_JITTER (CLOCK_SECOND * 10) static struct etimer synth_recal_timer; /*---------------------------------------------------------------------------*/ static RF_Object rf_netstack; + +#if RF_BLE_BEACON_ENABLE static RF_Object rf_ble; +#endif static RF_CmdHandle cmd_rx_handle; @@ -476,12 +479,18 @@ netstack_stop_rx(void) RF_Handle ble_open(RF_Params *params) { +#if RF_BLE_BEACON_ENABLE return RF_open(&rf_ble, &ble_mode, (RF_RadioSetup*)&ble_cmd_radio_setup, params); + +#else + return (RF_Handle)NULL; +#endif } /*---------------------------------------------------------------------------*/ rf_result_t ble_sched_beacon(RF_Callback cb, RF_EventMask bm_event) { +#if RF_BLE_BEACON_ENABLE RF_ScheduleCmdParams sched_params; RF_ScheduleCmdParams_init(&sched_params); @@ -518,6 +527,10 @@ ble_sched_beacon(RF_Callback cb, RF_EventMask bm_event) cmd_rx_restore(rx_key); return RF_RESULT_OK; + +#else + return RF_RESULT_ERROR; +#endif } /*---------------------------------------------------------------------------*/ PROCESS(rf_sched_process, "RF Scheduler Process"); diff --git a/arch/cpu/cc13xx-cc26xx/rf/settings.h b/arch/cpu/cc13xx-cc26xx/rf/settings.h index 4f6eab1c2..4d8df6d23 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf/settings.h @@ -48,6 +48,8 @@ /*---------------------------------------------------------------------------*/ #include /*---------------------------------------------------------------------------*/ +/* Netstack RF command configuration */ + #if SUPPORTS_PROP_MODE #include "prop-settings.h" #endif @@ -56,12 +58,6 @@ #include "ieee-settings.h" #endif -#if SUPPORTS_BLE_BEACON -#include "ble-settings.h" -#endif -/*---------------------------------------------------------------------------*/ -/* Netstack RF command configuration */ - /* Prop-mode RF settings */ #if (RF_MODE == RF_MODE_SUB_1_GHZ) @@ -83,6 +79,9 @@ #endif /* RF_MODE */ /*---------------------------------------------------------------------------*/ /* BLE Beacon RF command configuration */ +#if SUPPORTS_BLE_BEACON + +#include "ble-settings.h" /* CC13x0/CC26x0 devices */ #if (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0) @@ -101,6 +100,8 @@ #define ble_cmd_beacon rf_cmd_ble5_adv_aux #endif /* DeviceFamily_PARENT */ + +#endif /* SUPPORTS_BLE_BEACON */ /*---------------------------------------------------------------------------*/ #endif /* NETSTACK_SETTINGS_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.c index fda5b5b9f..b4d34a54b 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.c @@ -687,6 +687,29 @@ const uint_least8_t SPI_count = CC1350_LAUNCHXL_433_SPICOUNT; #endif /* TI_SPI_CONF_ENABLE */ + +/* + * =============================== TRNG =============================== + */ +#include +#include + +TRNGCC26X0_Object trngCC26X0Object[CC1350_LAUNCHXL_433_TRNGCOUNT]; + +const TRNGCC26X0_HWAttrs trngCC26X0HWAttrs[CC1350_LAUNCHXL_433_TRNGCOUNT] = { + { + .swiPriority = 0, + .intPriority = ~0, + } +}; + +const TRNG_Config TRNG_config[] = { + { &trngCC26X0Object[0], &trngCC26X0HWAttrs[0] }, +}; + +const uint8_t TRNG_count = CC1350_LAUNCHXL_433_TRNGCOUNT; + + /* * =============================== UART =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h index 80352e30e..479b81a71 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h @@ -328,6 +328,16 @@ typedef enum CC1350_LAUNCHXL_433_SPIName { CC1350_LAUNCHXL_433_SPICOUNT } CC1350_LAUNCHXL_433_SPIName; +/*! + * @def CC1350_LAUNCHXL_433_TRNGName + * @brief Enum of TRNGs + */ +typedef enum CC1350_LAUNCHXL_433_TRNGName { + CC1350_LAUNCHXL_433_TRNG0 = 0, + + CC1350_LAUNCHXL_433_TRNGCOUNT +} CC1350_LAUNCHXL_433_TRNGName; + /*! * @def CC1350_LAUNCHXL_433_UARTName * @brief Enum of UARTs diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h index 40f01ef03..29e089cfb 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h @@ -400,14 +400,14 @@ typedef enum CC1352P_2_LAUNCHXL_SPIName { } CC1352P_2_LAUNCHXL_SPIName; /*! - * @def CC1352p_2_LAUNCHXL_TRNGName + * @def CC1352P_2_LAUNCHXL_TRNGName * @brief Enum of TRNGs */ -typedef enum CC1352p_2_LAUNCHXL_TRNGName { - CC1352p_2_LAUNCHXL_TRNG0 = 0, +typedef enum CC1352P_2_LAUNCHXL_TRNGName { + CC1352P_2_LAUNCHXL_TRNG0 = 0, - CC1352p_2_LAUNCHXL_TRNGCOUNT -} CC1352p_2_LAUNCHXL_TRNGName; + CC1352P_2_LAUNCHXL_TRNGCOUNT +} CC1352P_2_LAUNCHXL_TRNGName; /*! * @def CC1352P_2_LAUNCHXL_UARTName diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c index f9e1f8fe5..2040a7582 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c @@ -394,7 +394,6 @@ const PIN_Config BoardGpioInitTable[] = { CC1350DK_7XD_PIN_KEY_LEFT | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ CC1350DK_7XD_PIN_KEY_UP | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ CC1350DK_7XD_SDCARD_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ - CC1350DK_7XD_LCD_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ CC1350DK_7XD_ACC_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ CC1350DK_7XD_UART_RX | PIN_INPUT_EN | PIN_PULLDOWN, /* UART RX via debugger back channel */ CC1350DK_7XD_UART_TX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* UART TX via debugger back channel */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c index 1f7ed1ab1..4d0115d38 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c @@ -395,7 +395,6 @@ const PIN_Config BoardGpioInitTable[] = { CC2650DK_7ID_PIN_KEY_LEFT | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ CC2650DK_7ID_PIN_KEY_UP | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ CC2650DK_7ID_SDCARD_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ - CC2650DK_7ID_LCD_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ CC2650DK_7ID_ACC_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ CC2650DK_7ID_UART_RX | PIN_INPUT_EN | PIN_PULLDOWN, /* UART RX via debugger back channel */ CC2650DK_7ID_UART_TX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* UART TX via debugger back channel */ From 7cf843f601883808d4c5b572b577bcf0d1344606 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Wed, 25 Jul 2018 18:16:27 +0200 Subject: [PATCH 300/485] Uncrustify --- arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h | 2 +- arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-def.h | 4 +- arch/cpu/cc13xx-cc26xx/ccfg-conf.c | 2 +- arch/cpu/cc13xx-cc26xx/dev/clock-arch.c | 4 +- arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c | 2 +- arch/cpu/cc13xx-cc26xx/dev/random.c | 3 +- arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c | 8 +- arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.h | 24 ++-- arch/cpu/cc13xx-cc26xx/dev/slip-arch.c | 1 - arch/cpu/cc13xx-cc26xx/dev/spi-arch.c | 10 +- .../dev/startup_cc13xx_cc26xx_gcc.c | 6 +- .../dev/startup_cc13xx_cc26xx_iar.c | 18 +-- arch/cpu/cc13xx-cc26xx/dev/trng-arch.c | 7 +- arch/cpu/cc13xx-cc26xx/dev/trng-arch.h | 1 - arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c | 19 +-- arch/cpu/cc13xx-cc26xx/dev/uart0-arch.h | 2 +- arch/cpu/cc13xx-cc26xx/dev/watchdog-arch.c | 10 +- arch/cpu/cc13xx-cc26xx/rf/ble-addr.c | 12 +- arch/cpu/cc13xx-cc26xx/rf/ble-addr.h | 2 +- arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c | 44 ++++-- arch/cpu/cc13xx-cc26xx/rf/data-queue.c | 34 ++--- arch/cpu/cc13xx-cc26xx/rf/data-queue.h | 6 +- arch/cpu/cc13xx-cc26xx/rf/ieee-addr.c | 6 +- arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c | 99 ++++++------- arch/cpu/cc13xx-cc26xx/rf/prop-mode.c | 44 +++--- arch/cpu/cc13xx-cc26xx/rf/rf.h | 5 +- arch/cpu/cc13xx-cc26xx/rf/sched.c | 132 ++++++++---------- arch/cpu/cc13xx-cc26xx/rf/settings.h | 2 +- arch/cpu/cc13xx-cc26xx/rf/tx-power.h | 10 +- .../simplelink/cc13xx-cc26xx/platform.c | 24 ++-- .../cc13xx-cc26xx/sensortag/bmp-280-sensor.c | 107 ++++---------- .../cc13xx-cc26xx/sensortag/bmp-280-sensor.h | 6 +- .../cc13xx-cc26xx/sensortag/buzzer.c | 6 +- .../cc13xx-cc26xx/sensortag/hdc-1000-sensor.c | 14 +- .../cc13xx-cc26xx/sensortag/hdc-1000-sensor.h | 2 +- .../cc13xx-cc26xx/sensortag/mpu-9250-sensor.c | 44 +++--- .../cc13xx-cc26xx/sensortag/mpu-9250-sensor.h | 42 +++--- .../cc13xx-cc26xx/sensortag/opt-3001-sensor.c | 14 +- .../cc13xx-cc26xx/sensortag/opt-3001-sensor.h | 2 +- .../cc13xx-cc26xx/sensortag/tmp-007-sensor.c | 38 +++-- .../cc13xx-cc26xx/sensortag/tmp-007-sensor.h | 9 +- 41 files changed, 397 insertions(+), 430 deletions(-) diff --git a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h index 09790cebc..256032d2d 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h +++ b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h @@ -150,7 +150,7 @@ #define RF_CONF_BLE_BEACON_ENABLE 0 #endif -#if (RF_BLE_BEACON_ENABLE) && !(SUPPORTS_BLE_BEACON) +#if (RF_CONF_BLE_BEACON_ENABLE) && !(SUPPORTS_BLE_BEACON) #error "Device does not support BLE for BLE beacon" #endif diff --git a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-def.h b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-def.h index f51ee3c2b..44ac92cf7 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-def.h +++ b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-def.h @@ -67,8 +67,8 @@ /* Timer conversion; radio is running at 4 MHz */ #define RAT_SECOND 4000000u -#define RAT_TO_RTIMER(X) ((uint32_t)(((uint64_t)(X) * (RTIMER_SECOND / 256)) / (RAT_SECOND / 256))) -#define USEC_TO_RAT(X) ((X) * 4) +#define RAT_TO_RTIMER(x) ((uint32_t)(((uint64_t)(x)*(RTIMER_SECOND / 256)) / (RAT_SECOND / 256))) +#define USEC_TO_RAT(x) ((x) * 4) #if (RTIMER_SECOND % 256) || (RAT_SECOND % 256) #error RAT_TO_RTIMER macro must be fixed! diff --git a/arch/cpu/cc13xx-cc26xx/ccfg-conf.c b/arch/cpu/cc13xx-cc26xx/ccfg-conf.c index fecdca7c1..be6c1ed9b 100644 --- a/arch/cpu/cc13xx-cc26xx/ccfg-conf.c +++ b/arch/cpu/cc13xx-cc26xx/ccfg-conf.c @@ -27,7 +27,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ - /** +/** * \addtogroup cc13xx-cc26xx-cpu * @{ * diff --git a/arch/cpu/cc13xx-cc26xx/dev/clock-arch.c b/arch/cpu/cc13xx-cc26xx/dev/clock-arch.c index 516d51cdb..ef2d4e1c9 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/clock-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/clock-arch.c @@ -94,10 +94,10 @@ clock_init(void) ClockP_Params params; ClockP_Params_init(¶ms); - params.period = clockp_ticks_second; + params.period = clockp_ticks_second; params.startFlag = true; - ClockP_construct(&etimer_clock, (ClockP_Fxn)&clock_update_cb, + ClockP_construct(&etimer_clock, (ClockP_Fxn)clock_update_cb, clockp_ticks_second, ¶ms); } /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c b/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c index 9da458899..841627ec4 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c @@ -51,7 +51,7 @@ #include /*---------------------------------------------------------------------------*/ static PIN_Config pin_config[] = { PIN_TERMINATE }; -static PIN_State pin_state; +static PIN_State pin_state; static PIN_Handle pin_handle; /*---------------------------------------------------------------------------*/ static void diff --git a/arch/cpu/cc13xx-cc26xx/dev/random.c b/arch/cpu/cc13xx-cc26xx/dev/random.c index 1a244742b..4286bfe89 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/random.c +++ b/arch/cpu/cc13xx-cc26xx/dev/random.c @@ -10,7 +10,6 @@ * 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. @@ -28,7 +27,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/** + /** * \addtogroup cc13xx-cc26xx-cpu * @{ * diff --git a/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c b/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c index d63adc36c..7fd768008 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c @@ -10,7 +10,6 @@ * 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. @@ -62,7 +61,12 @@ static hwi_dispatch_fxn_t hwi_dispatch_fxn; /** * \brief Stub function used when creating the dummy clock object. */ -static void rtimer_clock_stub(uintptr_t unused) { (void)unused; /* do nothing */ } +static void +rtimer_clock_stub(uintptr_t unused) +{ + (void)unused; + /* do nothing */ +} /*---------------------------------------------------------------------------*/ /** * \brief The Man-in-the-Middle ISR hook for the HWI dispatch ISR. This diff --git a/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.h b/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.h index 341f09393..c42fcbd41 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.h +++ b/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.h @@ -10,7 +10,6 @@ * 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. @@ -58,24 +57,25 @@ rtimer_clock_t rtimer_arch_now(void); * returns an odd value; US_TO_RTIMERTICKS always rounds to the nearest * even number. */ -#define US_TO_RTIMERTICKS(us) (2 * ( \ - ((us) >= 0) \ - ? (((int32_t)(us) * (RTIMER_ARCH_SECOND / 2) + 500000) / 1000000L) \ - : (((int32_t)(us) * (RTIMER_ARCH_SECOND / 2) - 500000) / 1000000L) \ - )) +#define US_TO_RTIMERTICKS(us) ( \ + (((us) >= 0) \ + ? (((int32_t)(us) * (RTIMER_ARCH_SECOND / 2) + 500000) / 1000000L) \ + : (((int32_t)(us) * (RTIMER_ARCH_SECOND / 2) - 500000) / 1000000L) \ + ) * 2) -#define RTIMERTICKS_TO_US(rt) ( \ - ((rt) >= 0) \ - ? (((int32_t)(rt) * 1000000L + (RTIMER_ARCH_SECOND / 2)) / RTIMER_ARCH_SECOND) \ - : (((int32_t)(rt) * 1000000L - (RTIMER_ARCH_SECOND / 2)) / RTIMER_ARCH_SECOND) \ +#define RTIMERTICKS_TO_US(rt) ( \ + ((rt) >= 0) \ + ? (((int32_t)(rt) * 1000000L + (RTIMER_ARCH_SECOND / 2)) / RTIMER_ARCH_SECOND) \ + : (((int32_t)(rt) * 1000000L - (RTIMER_ARCH_SECOND / 2)) / RTIMER_ARCH_SECOND) \ ) /* * A 64-bit version because the 32-bit one cannot handle T >= 4295 ticks. * Intended only for positive values of T. */ -#define RTIMERTICKS_TO_US_64(rt) ((uint32_t)( \ - ((uint64_t)(rt) * 1000000 + (RTIMER_ARCH_SECOND / 2)) / RTIMER_ARCH_SECOND \ +#define RTIMERTICKS_TO_US_64(rt) ( \ + (uint32_t)( \ + ((uint64_t)(rt) * 1000000 + (RTIMER_ARCH_SECOND / 2)) / RTIMER_ARCH_SECOND \ )) /*---------------------------------------------------------------------------*/ #endif /* RTIMER_ARCH_H_ */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/slip-arch.c b/arch/cpu/cc13xx-cc26xx/dev/slip-arch.c index f1f877e98..d15148428 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/slip-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/slip-arch.c @@ -10,7 +10,6 @@ * 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. diff --git a/arch/cpu/cc13xx-cc26xx/dev/spi-arch.c b/arch/cpu/cc13xx-cc26xx/dev/spi-arch.c index 7fe41762b..6950b7baf 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/spi-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/spi-arch.c @@ -63,7 +63,7 @@ static spi_arch_t spi_arches[SPI_CONTROLLER_COUNT]; static spi_arch_t *spi_arches = NULL; #endif /*---------------------------------------------------------------------------*/ -static inline spi_arch_t* +static inline spi_arch_t * get_handle(uint8_t spi_controller) { if(spi_controller < SPI_CONTROLLER_COUNT) { @@ -144,10 +144,10 @@ spi_arch_lock_and_open(spi_device_t *dev) SPI_Params_init(&spi_params); spi_params.transferMode = SPI_MODE_BLOCKING; - spi_params.mode = SPI_MASTER; - spi_params.bitRate = dev->spi_bit_rate; - spi_params.dataSize = 8; - spi_params.frameFormat = convert_frame_format(dev->spi_pol, dev->spi_pha); + spi_params.mode = SPI_MASTER; + spi_params.bitRate = dev->spi_bit_rate; + spi_params.dataSize = 8; + spi_params.frameFormat = convert_frame_format(dev->spi_pol, dev->spi_pha); /* * Try to open the SPI driver. Accessing the SPI driver also ensures diff --git a/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c b/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c index b5bb2c13c..4c47a9ad6 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c +++ b/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c @@ -73,7 +73,7 @@ extern unsigned long _stack_end; __attribute__((section(".resetVecs"))) __attribute__((used)) static void(*const resetVectors[16])(void) = { - (void (*)(void))((uint32_t)&_stack_end), + (void(*)(void))((uint32_t)&_stack_end), /* The initial stack pointer */ resetISR, /* The reset handler */ nmiISR, /* The NMI handler */ @@ -126,8 +126,8 @@ localProgramStart(void) uint32_t *dl; uint32_t *ds; uint32_t *de; - uint32_t count; - uint32_t i; + uint32_t count; + uint32_t i; #if defined(__ARM_ARCH_7EM__) && defined(__VFP_FP__) && !defined(__SOFTFP__) volatile uint32_t *pui32Cpacr = (uint32_t *)0xE000ED88; diff --git a/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_iar.c b/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_iar.c index 3624c20ac..84b17ac76 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_iar.c +++ b/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_iar.c @@ -49,10 +49,10 @@ #include DeviceFamily_constructPath(driverlib/interrupt.h) /*---------------------------------------------------------------------------*/ /* Forward declaration of the reset ISR and the default fault handlers. */ -static void nmiISR( void ); -static void faultISR( void ); -static void intDefaultHandler( void ); -extern int main( void ); +static void nmiISR(void); +static void faultISR(void); +static void intDefaultHandler(void); +extern int main(void); extern void MPUFaultIntHandler(void); extern void BusFaultIntHandler(void); @@ -141,22 +141,22 @@ extern void TRNGIntHandler(void); extern void __iar_program_start(void); /* Get stack start (highest address) symbol from linker file. */ -extern const void* STACK_TOP; +extern const void *STACK_TOP; /*---------------------------------------------------------------------------*/ /* * It is required to place something in the CSTACK segment to get the stack * check feature in IAR to work as expected */ -__root static void* dummy_stack @ ".stack"; +__root static void *dummy_stack @ ".stack"; /* * The vector table. Note that the proper constructs must be placed on this to * ensure that it ends up at physical address 0x0000.0000 or at the start of * the program if located at a start address other than 0. */ -__root void (* const __vector_table[])(void) @ ".intvec" = +__root void(*const __vector_table[])(void) @ ".intvec" = { - (void (*)(void))&STACK_TOP, /* 0 The initial stack pointer */ + (void (*)(void)) & STACK_TOP, /* 0 The initial stack pointer */ __iar_program_start, /* 1 The reset handler */ nmiISR, /* 2 The NMI handler */ faultISR, /* 3 The hard fault handler */ @@ -209,7 +209,7 @@ __root void (* const __vector_table[])(void) @ ".intvec" = AUXADCIntHandler, /* 48 AUX ADC new sample or ADC DMA */ /* done, ADC underflow, ADC overflow */ TRNGIntHandler /* 49 TRNG event */ -}; +} /*---------------------------------------------------------------------------*/ /* * \brief Setup trim device. diff --git a/arch/cpu/cc13xx-cc26xx/dev/trng-arch.c b/arch/cpu/cc13xx-cc26xx/dev/trng-arch.c index 8f7cb2627..5196c5c6e 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/trng-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/trng-arch.c @@ -10,7 +10,6 @@ * 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. @@ -60,9 +59,9 @@ bool trng_rand(uint8_t *entropy_buf, size_t entropy_len, uint32_t timeout_us) { - TRNG_Params trng_params; - TRNG_Handle trng_handle; - CryptoKey entropy_key; + TRNG_Params trng_params; + TRNG_Handle trng_handle; + CryptoKey entropy_key; int_fast16_t result; TRNG_Params_init(&trng_params); diff --git a/arch/cpu/cc13xx-cc26xx/dev/trng-arch.h b/arch/cpu/cc13xx-cc26xx/dev/trng-arch.h index ac220bd25..fc25b9169 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/trng-arch.h +++ b/arch/cpu/cc13xx-cc26xx/dev/trng-arch.h @@ -10,7 +10,6 @@ * 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. diff --git a/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c b/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c index ec1f85265..4bf529ddd 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c @@ -10,7 +10,6 @@ * 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. @@ -60,7 +59,9 @@ static void uart0_cb(UART_Handle handle, void *buf, size_t count) { /* Simply return if the current callback is NULL. */ - if(!curr_input_cb) { return; } + if(!curr_input_cb) { + return; + } /* * Save the current callback function locally, as it might be overwritten @@ -81,16 +82,18 @@ uart0_cb(UART_Handle handle, void *buf, size_t count) void uart0_init(void) { - if(initialized) { return; } + if(initialized) { + return; + } UART_Params uart_params; UART_Params_init(&uart_params); - uart_params.baudRate = TI_UART_CONF_BAUD_RATE; - uart_params.readMode = UART_MODE_CALLBACK; - uart_params.writeMode = UART_MODE_BLOCKING; - uart_params.readCallback = uart0_cb; - uart_params.readDataMode = UART_DATA_TEXT; + uart_params.baudRate = TI_UART_CONF_BAUD_RATE; + uart_params.readMode = UART_MODE_CALLBACK; + uart_params.writeMode = UART_MODE_BLOCKING; + uart_params.readCallback = uart0_cb; + uart_params.readDataMode = UART_DATA_TEXT; uart_params.readReturnMode = UART_RETURN_NEWLINE; /* No error handling. */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.h b/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.h index 68b7a18c5..17a93519a 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.h +++ b/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/arch/cpu/cc13xx-cc26xx/dev/watchdog-arch.c b/arch/cpu/cc13xx-cc26xx/dev/watchdog-arch.c index 825b835bf..6cba086b4 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/watchdog-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/watchdog-arch.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,7 +27,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/** + /** * \addtogroup cc13xx-cc26xx-cpu * @{ * @@ -76,7 +76,7 @@ watchdog_init(void) Watchdog_Params wdt_params; Watchdog_Params_init(&wdt_params); - wdt_params.resetMode = Watchdog_RESET_ON; + wdt_params.resetMode = Watchdog_RESET_ON; wdt_params.debugStallMode = Watchdog_DEBUG_STALL_ON; wdt_handle = Watchdog_open(Board_WATCHDOG0, &wdt_params); @@ -133,7 +133,9 @@ watchdog_reboot(void) } watchdog_start(); - while(1); + + /* Busy loop until watchdog times out */ + for (;;) { /* hang */ } } /*---------------------------------------------------------------------------*/ /** diff --git a/arch/cpu/cc13xx-cc26xx/rf/ble-addr.c b/arch/cpu/cc13xx-cc26xx/rf/ble-addr.c index d4753e1a5..357e7e7c5 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/ble-addr.c +++ b/arch/cpu/cc13xx-cc26xx/rf/ble-addr.c @@ -52,13 +52,13 @@ #include /*---------------------------------------------------------------------------*/ #define BLE_MAC_PRIMARY_ADDRESS (FCFG1_BASE + FCFG1_O_MAC_BLE_0) -#define BLE_MAC_SECONDARY_ADDRESS (CCFG_BASE + CCFG_O_IEEE_BLE_0) +#define BLE_MAC_SECONDARY_ADDRESS (CCFG_BASE + CCFG_O_IEEE_BLE_0) /*---------------------------------------------------------------------------*/ -uint8_t* +uint8_t * ble_addr_ptr(void) { - volatile const uint8_t * const primary = (uint8_t *)BLE_MAC_PRIMARY_ADDRESS; - volatile const uint8_t * const secondary = (uint8_t *)BLE_MAC_SECONDARY_ADDRESS; + volatile const uint8_t *const primary = (uint8_t *)BLE_MAC_PRIMARY_ADDRESS; + volatile const uint8_t *const secondary = (uint8_t *)BLE_MAC_SECONDARY_ADDRESS; /* * Reading from primary location... @@ -72,12 +72,12 @@ ble_addr_ptr(void) for(i = 0; i < BLE_ADDR_SIZE; i++) { if(secondary[i] != 0xFF) { /* A byte in secondary is not 0xFF. Use secondary address. */ - return (uint8_t*)secondary; + return (uint8_t *)secondary; } } /* All bytes in secondary is 0xFF. Use primary address. */ - return (uint8_t*)primary; + return (uint8_t *)primary; } /*---------------------------------------------------------------------------*/ int diff --git a/arch/cpu/cc13xx-cc26xx/rf/ble-addr.h b/arch/cpu/cc13xx-cc26xx/rf/ble-addr.h index 0b4028269..7fb45b1f2 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/ble-addr.h +++ b/arch/cpu/cc13xx-cc26xx/rf/ble-addr.h @@ -55,7 +55,7 @@ * This function will return the primary address from info page, unless a * valid address is found in the secondary address from CCFG. */ -uint8_t* ble_addr_ptr(void); +uint8_t *ble_addr_ptr(void); /*---------------------------------------------------------------------------*/ /** * \brief Copy the node's factory BLE address to a destination memory area diff --git a/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c b/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c index 22b1a9658..79c0f4e62 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c +++ b/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c @@ -67,7 +67,7 @@ #define LOG_MODULE "Radio" #define LOG_LEVEL LOG_LEVEL_NONE /*---------------------------------------------------------------------------*/ -#if RF_BLE_BEACON_ENABLE +#if RF_CONF_BLE_BEACON_ENABLE /*---------------------------------------------------------------------------*/ /* BLE Advertisement channels. Not to be changed by the user. */ typedef enum { @@ -75,9 +75,9 @@ typedef enum { BLE_ADV_CHANNEL_38 = (1 << 1), BLE_ADV_CHANNEL_39 = (1 << 2), - BLE_ADV_CHANNEL_MASK = BLE_ADV_CHANNEL_37 - | BLE_ADV_CHANNEL_38 - | BLE_ADV_CHANNEL_39, + BLE_ADV_CHANNEL_MASK = (BLE_ADV_CHANNEL_37 | + BLE_ADV_CHANNEL_38 | + BLE_ADV_CHANNEL_39), } ble_adv_channel_t; #define BLE_ADV_CHANNEL_MIN 37 @@ -210,7 +210,7 @@ rf_ble_get_tx_power(void) rf_result_t res; int8_t dbm; - res = rf_get_tx_power(ble_beacond.rf_handle, TX_POWER_TABLE, &dbm) + res = rf_get_tx_power(ble_beacond.rf_handle, TX_POWER_TABLE, &dbm); if(res != RF_RESULT_OK) { return RF_TxPowerTable_INVALID_DBM; @@ -290,26 +290,44 @@ PROCESS_THREAD(ble_beacond_process, ev, data) PROCESS_END(); } /*---------------------------------------------------------------------------*/ -#else /* RF_BLE_BEACON_ENABLE */ +#else /* RF_CONF_BLE_BEACON_ENABLE */ /*---------------------------------------------------------------------------*/ rf_ble_beacond_result_t -rf_ble_beacond_init(void) { return RF_BLE_BEACOND_DISABLED; } +rf_ble_beacond_init(void) +{ + return RF_BLE_BEACOND_DISABLED; +} /*---------------------------------------------------------------------------*/ rf_ble_beacond_result_t -rf_ble_beacond_start(clock_time_t interval, const char *name) { return RF_BLE_BEACOND_DISABLED; } +rf_ble_beacond_start(clock_time_t interval, const char *name) +{ + return RF_BLE_BEACOND_DISABLED; +} /*---------------------------------------------------------------------------*/ rf_ble_beacond_result_t -rf_ble_beacond_stop(void) { return RF_BLE_BEACOND_DISABLED; } +rf_ble_beacond_stop(void) +{ + return RF_BLE_BEACOND_DISABLED; +} /*---------------------------------------------------------------------------*/ int8_t -rf_ble_is_active(void) { return -1; } +rf_ble_is_active(void) +{ + return -1; +} /*---------------------------------------------------------------------------*/ rf_ble_beacond_result_t -rf_ble_set_tx_power(int8_t power) { return RF_BLE_BEACOND_DISABLED; } +rf_ble_set_tx_power(int8_t power) +{ + return RF_BLE_BEACOND_DISABLED; +} /*---------------------------------------------------------------------------*/ int8_t -rf_ble_get_tx_power(void) { return ~(int8_t)(0); } +rf_ble_get_tx_power(void) +{ + return ~(int8_t)(0); +} /*---------------------------------------------------------------------------*/ -#endif /* RF_BLE_BEACON_ENABLE */ +#endif /* RF_CONF_BLE_BEACON_ENABLE */ /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/cpu/cc13xx-cc26xx/rf/data-queue.c b/arch/cpu/cc13xx-cc26xx/rf/data-queue.c index 27e383557..a5f03a8d7 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/data-queue.c +++ b/arch/cpu/cc13xx-cc26xx/rf/data-queue.c @@ -39,13 +39,13 @@ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "sys/cc.h" - -#include "rf/data-queue.h" /*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_data_entry.h) /*---------------------------------------------------------------------------*/ +#include "rf/data-queue.h" +/*---------------------------------------------------------------------------*/ #include #include #include @@ -57,18 +57,18 @@ /* Receive buffer entries with room for 1 IEEE 802.15.4 frame in each */ typedef union { data_entry_t data_entry; - uint8_t buf[RX_BUF_SIZE]; -} rx_buf_t CC_ALIGN(4); + uint8_t buf[RX_BUF_SIZE]; +} rx_buf_t CC_ALIGN (4); /*---------------------------------------------------------------------------*/ typedef struct { /* RX bufs */ - rx_buf_t bufs[RX_BUF_CNT]; + rx_buf_t bufs[RX_BUF_CNT]; /* RFC data queue object */ - data_queue_t data_queue; + data_queue_t data_queue; /* Current data entry in use by RF */ - data_entry_t* curr_entry; + data_entry_t *curr_entry; /* Size in bytes of length field in data entry */ - size_t lensz; + size_t lensz; } rx_data_queue_t; static rx_data_queue_t rx_data_queue; @@ -82,14 +82,14 @@ rx_bufs_init(void) for(i = 0; i < RX_BUF_CNT; ++i) { data_entry = &(rx_data_queue.bufs[i].data_entry); - data_entry->status = DATA_ENTRY_PENDING; - data_entry->config.type = DATA_ENTRY_TYPE_GEN; + data_entry->status = DATA_ENTRY_PENDING; + data_entry->config.type = DATA_ENTRY_TYPE_GEN; data_entry->config.lenSz = rx_data_queue.lensz; - data_entry->length = RX_BUF_SIZE - sizeof(data_entry_t); /* TODO: is this sizeof sound? */ + data_entry->length = RX_BUF_SIZE - sizeof(data_entry_t); /* Point to fist entry if this is last entry, else point to next entry */ - data_entry->pNextEntry = ((i + 1) == RX_BUF_CNT) + data_entry->pNextEntry = ((i + 1) == RX_BUF_CNT) ? rx_data_queue.bufs[0].buf - : rx_data_queue.bufs[i+1].buf; + : rx_data_queue.bufs[i + 1].buf; } } /*---------------------------------------------------------------------------*/ @@ -107,7 +107,7 @@ rx_bufs_reset(void) } } /*---------------------------------------------------------------------------*/ -data_queue_t* +data_queue_t * data_queue_init(size_t lensz) { rx_data_queue.lensz = lensz; @@ -137,7 +137,7 @@ data_queue_reset(void) rx_data_queue.curr_entry = &(rx_data_queue.bufs[0].data_entry); } /*---------------------------------------------------------------------------*/ -data_entry_t* +data_entry_t * data_queue_current_entry(void) { return rx_data_queue.curr_entry; @@ -147,7 +147,7 @@ void data_queue_release_entry(void) { data_entry_t *const curr_entry = rx_data_queue.curr_entry; - uint8_t *const frame_ptr = (uint8_t*)&(curr_entry->data); + uint8_t *const frame_ptr = (uint8_t *)&(curr_entry->data); /* Clear length bytes */ memset(frame_ptr, 0x0, rx_data_queue.lensz); @@ -155,7 +155,7 @@ data_queue_release_entry(void) curr_entry->status = DATA_ENTRY_PENDING; /* Move current entry to the next entry */ - rx_data_queue.curr_entry = (data_entry_t*)(curr_entry->pNextEntry); + rx_data_queue.curr_entry = (data_entry_t *)(curr_entry->pNextEntry); } /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/cpu/cc13xx-cc26xx/rf/data-queue.h b/arch/cpu/cc13xx-cc26xx/rf/data-queue.h index c0b6913a8..049cf78d1 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/data-queue.h +++ b/arch/cpu/cc13xx-cc26xx/rf/data-queue.h @@ -52,12 +52,12 @@ /*---------------------------------------------------------------------------*/ #include /*---------------------------------------------------------------------------*/ -typedef dataQueue_t data_queue_t; +typedef dataQueue_t data_queue_t; typedef rfc_dataEntryGeneral_t data_entry_t; /*---------------------------------------------------------------------------*/ -data_queue_t* data_queue_init(size_t lensz); +data_queue_t *data_queue_init(size_t lensz); void data_queue_reset(void); -data_entry_t* data_queue_current_entry(void); +data_entry_t *data_queue_current_entry(void); void data_queue_release_entry(void); /*---------------------------------------------------------------------------*/ #endif /* RF_DATA_QUEUE_H_ */ diff --git a/arch/cpu/cc13xx-cc26xx/rf/ieee-addr.c b/arch/cpu/cc13xx-cc26xx/rf/ieee-addr.c index bdea2782e..4ce39a241 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/ieee-addr.c +++ b/arch/cpu/cc13xx-cc26xx/rf/ieee-addr.c @@ -54,7 +54,7 @@ #define IEEE_ADDR_ADDRESS IEEE_ADDR_CONF_ADDRESS /*---------------------------------------------------------------------------*/ #define IEEE_MAC_PRIMARY_ADDRESS (FCFG1_BASE + FCFG1_O_MAC_15_4_0) -#define IEEE_MAC_SECONDARY_ADDRESS (CCFG_BASE + CCFG_O_IEEE_MAC_0) +#define IEEE_MAC_SECONDARY_ADDRESS (CCFG_BASE + CCFG_O_IEEE_MAC_0) /*---------------------------------------------------------------------------*/ int ieee_addr_cpy_to(uint8_t *dst, uint8_t len) @@ -70,8 +70,8 @@ ieee_addr_cpy_to(uint8_t *dst, uint8_t len) } else { int i; - volatile const uint8_t * const primary = (uint8_t *)IEEE_MAC_PRIMARY_ADDRESS; - volatile const uint8_t * const secondary = (uint8_t *)IEEE_MAC_SECONDARY_ADDRESS; + volatile const uint8_t *const primary = (uint8_t *)IEEE_MAC_PRIMARY_ADDRESS; + volatile const uint8_t *const secondary = (uint8_t *)IEEE_MAC_SECONDARY_ADDRESS; /* Reading from primary location... */ volatile const uint8_t *ieee_addr = primary; diff --git a/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c b/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c index ef7408b21..5f4a54982 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c +++ b/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c @@ -118,53 +118,53 @@ #define TX_BUF_SIZE 180 /*---------------------------------------------------------------------------*/ /* Size of the Length representation in Data Entry, one byte in this case */ -typedef uint8_t lensz_t; +typedef uint8_t lensz_t; #define FRAME_OFFSET sizeof(lensz_t) #define FRAME_SHAVE 8 /* FCS (2) + RSSI (1) + Status (1) + Timestamp (4) */ /*---------------------------------------------------------------------------*/ /* Used for checking result of CCA_REQ command */ typedef enum { - CCA_STATE_IDLE = 0, - CCA_STATE_BUSY = 1, + CCA_STATE_IDLE = 0, + CCA_STATE_BUSY = 1, CCA_STATE_INVALID = 2 } cca_state_t; /*---------------------------------------------------------------------------*/ /* RF Core typedefs */ -typedef rfc_ieeeRxOutput_t rx_output_t; +typedef rfc_ieeeRxOutput_t rx_output_t; typedef rfc_CMD_IEEE_MOD_FILT_t cmd_mod_filt_t; -typedef rfc_CMD_IEEE_CCA_REQ_t cmd_cca_req_t; +typedef rfc_CMD_IEEE_CCA_REQ_t cmd_cca_req_t; typedef struct { /* Outgoing frame buffer */ - uint8_t tx_buf[TX_BUF_SIZE] CC_ALIGN(4); + uint8_t tx_buf[TX_BUF_SIZE] CC_ALIGN(4); /* RF Statistics struct */ - rx_output_t rx_stats; + rx_output_t rx_stats; /* Indicates RF is supposed to be on or off */ - bool rf_is_on; + bool rf_is_on; /* Enable/disable CCA before sending */ - bool send_on_cca; + bool send_on_cca; /* Are we currently in poll mode? */ - bool poll_mode; + bool poll_mode; /* Last RX operation stats */ struct { - int8_t rssi; - uint8_t corr_lqi; - uint32_t timestamp; + int8_t rssi; + uint8_t corr_lqi; + uint32_t timestamp; } last; /* RAT Overflow Upkeep */ struct { - struct ctimer overflow_timer; - rtimer_clock_t last_overflow; + struct ctimer overflow_timer; + rtimer_clock_t last_overflow; volatile uint32_t overflow_count; } rat; /* RF driver */ - RF_Handle rf_handle; + RF_Handle rf_handle; } ieee_radio_t; static ieee_radio_t ieee_radio; @@ -173,11 +173,11 @@ static ieee_radio_t ieee_radio; static cmd_mod_filt_t cmd_mod_filt; /*---------------------------------------------------------------------------*/ /* RF Command volatile objects */ -#define cmd_radio_setup (*(volatile rfc_CMD_RADIO_SETUP_t*)&rf_cmd_ieee_radio_setup) -#define cmd_fs (*(volatile rfc_CMD_FS_t*) &rf_cmd_ieee_fs) -#define cmd_tx (*(volatile rfc_CMD_IEEE_TX_t*) &rf_cmd_ieee_tx) -#define cmd_rx (*(volatile rfc_CMD_IEEE_RX_t*) &rf_cmd_ieee_rx) -#define cmd_rx_ack (*(volatile rfc_CMD_IEEE_RX_ACK_t*)&rf_cmd_ieee_rx_ack) +#define cmd_radio_setup (*(volatile rfc_CMD_RADIO_SETUP_t *)&rf_cmd_ieee_radio_setup) +#define cmd_fs (*(volatile rfc_CMD_FS_t *) &rf_cmd_ieee_fs) +#define cmd_tx (*(volatile rfc_CMD_IEEE_TX_t *) &rf_cmd_ieee_tx) +#define cmd_rx (*(volatile rfc_CMD_IEEE_RX_t *) &rf_cmd_ieee_rx) +#define cmd_rx_ack (*(volatile rfc_CMD_IEEE_RX_ACK_t *)&rf_cmd_ieee_rx_ack) /*---------------------------------------------------------------------------*/ static inline bool rx_is_active(void) @@ -191,19 +191,19 @@ static uint32_t rat_to_timestamp(const uint32_t); /*---------------------------------------------------------------------------*/ /* Forward declarations of Radio driver functions */ static int init(void); -static int prepare(const void*, unsigned short); +static int prepare(const void *, unsigned short); static int transmit(unsigned short); -static int send(const void*, unsigned short); -static int read(void*, unsigned short); +static int send(const void *, unsigned short); +static int read(void *, unsigned short); static int channel_clear(void); static int receiving_packet(void); static int pending_packet(void); static int on(void); static int off(void); -static radio_result_t get_value(radio_param_t, radio_value_t*); +static radio_result_t get_value(radio_param_t, radio_value_t *); static radio_result_t set_value(radio_param_t, radio_value_t); -static radio_result_t get_object(radio_param_t, void*, size_t); -static radio_result_t set_object(radio_param_t, const void*, size_t); +static radio_result_t get_object(radio_param_t, void *, size_t); +static radio_result_t set_object(radio_param_t, const void *, size_t); /*---------------------------------------------------------------------------*/ static void rat_overflow_cb(void *arg) @@ -219,7 +219,7 @@ init_rf_params(void) { data_queue_t *rx_q = data_queue_init(sizeof(lensz_t)); - cmd_rx.pRxQ = rx_q; + cmd_rx.pRxQ = rx_q; cmd_rx.pOutput = &ieee_radio.rx_stats; #if IEEE_MODE_PROMISCOUS @@ -236,7 +236,7 @@ init_rf_params(void) cmd_rx.ccaRssiThr = IEEE_MODE_CCA_RSSI_THRESHOLD; - cmd_tx.pNextOp = (RF_Op*)&cmd_rx_ack; + cmd_tx.pNextOp = (RF_Op *)&cmd_rx_ack; cmd_tx.condition.rule = COND_NEVER; /* Initially ACK turned off */ /* @@ -248,13 +248,13 @@ init_rf_params(void) * of 11 bytes. 11 bytes x 32 us/byte equals 352 us of ACK transmission time. */ cmd_rx_ack.startTrigger.triggerType = TRIG_NOW; - cmd_rx_ack.endTrigger.triggerType = TRIG_REL_START; + cmd_rx_ack.endTrigger.triggerType = TRIG_REL_START; cmd_rx_ack.endTime = RF_convertUsToRatTicks(700); /* Initialize address filter command */ cmd_mod_filt.commandNo = CMD_IEEE_MOD_FILT; memcpy(&(cmd_mod_filt.newFrameFiltOpt), &(rf_cmd_ieee_rx.frameFiltOpt), sizeof(rf_cmd_ieee_rx.frameFiltOpt)); - memcpy(&(cmd_mod_filt.newFrameTypes), &(rf_cmd_ieee_rx.frameTypes), sizeof(rf_cmd_ieee_rx.frameTypes)); + memcpy(&(cmd_mod_filt.newFrameTypes), &(rf_cmd_ieee_rx.frameTypes), sizeof(rf_cmd_ieee_rx.frameTypes)); } /*---------------------------------------------------------------------------*/ static rf_result_t @@ -279,11 +279,11 @@ set_channel(uint8_t channel) cmd_rx.channel = channel; const uint32_t new_freq = dot_15_4g_freq(channel); - const uint16_t freq = (uint16_t)(new_freq / 1000); - const uint16_t frac = (uint16_t)(((new_freq - (freq * 1000)) * 0x10000) / 1000); + const uint16_t freq = (uint16_t)(new_freq / 1000); + const uint16_t frac = (uint16_t)(((new_freq - (freq * 1000)) * 0x10000) / 1000); LOG_DBG("Set channel to %d, frequency 0x%04X.0x%04X (%lu)\n", - (int)channel, freq, frac, new_freq); + (int)channel, freq, frac, new_freq); cmd_fs.frequency = freq; cmd_fs.fractFreq = frac; @@ -502,8 +502,8 @@ read(void *buf, unsigned short buf_len) * Length = N + 8 * N = Length - 8 */ - uint8_t *const frame_ptr = (uint8_t*)&data_entry->data; - const lensz_t frame_len = *(lensz_t*)frame_ptr; + uint8_t *const frame_ptr = (uint8_t *)&data_entry->data; + const lensz_t frame_len = *(lensz_t *)frame_ptr; /* Sanity check that Frame is at least Frame Shave bytes long */ if(frame_len < FRAME_SHAVE) { @@ -532,14 +532,14 @@ read(void *buf, unsigned short buf_len) /* LQI retrieved from Status byte, FCS (2) + RSSI (1) bytes after payload. */ ieee_radio.last.corr_lqi = (uint8_t)(payload_ptr[payload_len + 3] & STATUS_CORRELATION); /* Timestamp stored FCS (2) + RSSI (1) + Status (1) bytes after payload. */ - const uint32_t rat_ticks = *(uint32_t*)(payload_ptr + payload_len + 4); + const uint32_t rat_ticks = *(uint32_t *)(payload_ptr + payload_len + 4); ieee_radio.last.timestamp = rat_to_timestamp(rat_ticks); if(!ieee_radio.poll_mode) { /* Not in poll mode: packetbuf should not be accessed in interrupt context. */ /* In poll mode, the last packet RSSI and link quality can be obtained through */ /* RADIO_PARAM_LAST_RSSI and RADIO_PARAM_LAST_LINK_QUALITY */ - packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (packetbuf_attr_t)ieee_radio.last.rssi); + packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (packetbuf_attr_t)ieee_radio.last.rssi); packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, (packetbuf_attr_t)ieee_radio.last.corr_lqi); } @@ -567,7 +567,7 @@ cca_request(cmd_cca_req_t *cmd_cca_req) RF_Stat stat = RF_StatRadioInactiveError; if(rx_is_active()) { - stat = RF_runImmediateCmd(ieee_radio.rf_handle, (uint32_t*)&cmd_cca_req); + stat = RF_runImmediateCmd(ieee_radio.rf_handle, (uint32_t *)&cmd_cca_req); } if(rx_is_idle) { @@ -738,7 +738,7 @@ get_value(radio_param_t param, radio_value_t *value) /* TX power */ case RADIO_PARAM_TXPOWER: - res = rf_get_tx_power(ieee_radio.rf_handle, rf_tx_power_table, (int8_t*)&value); + res = rf_get_tx_power(ieee_radio.rf_handle, rf_tx_power_table, (int8_t *)&value); return ((res == RF_RESULT_OK) && (*value != RF_TxPowerTable_INVALID_DBM)) ? RADIO_RESULT_OK @@ -848,18 +848,19 @@ set_value(radio_param_t param, radio_value_t value) /* RX Mode */ case RADIO_PARAM_RX_MODE: { if(value & ~(RADIO_RX_MODE_ADDRESS_FILTER | - RADIO_RX_MODE_AUTOACK | RADIO_RX_MODE_POLL_MODE)) { + RADIO_RX_MODE_AUTOACK | + RADIO_RX_MODE_POLL_MODE)) { return RADIO_RESULT_INVALID_VALUE; } - cmd_rx.frameFiltOpt.frameFiltEn = (value & RADIO_RX_MODE_ADDRESS_FILTER) != 0; - cmd_rx.frameFiltOpt.frameFiltStop = 1; - cmd_rx.frameFiltOpt.autoAckEn = (value & RADIO_RX_MODE_AUTOACK) != 0; - cmd_rx.frameFiltOpt.slottedAckEn = 0; - cmd_rx.frameFiltOpt.autoPendEn = 0; - cmd_rx.frameFiltOpt.defaultPend = 0; + cmd_rx.frameFiltOpt.frameFiltEn = (value & RADIO_RX_MODE_ADDRESS_FILTER) != 0; + cmd_rx.frameFiltOpt.frameFiltStop = 1; + cmd_rx.frameFiltOpt.autoAckEn = (value & RADIO_RX_MODE_AUTOACK) != 0; + cmd_rx.frameFiltOpt.slottedAckEn = 0; + cmd_rx.frameFiltOpt.autoPendEn = 0; + cmd_rx.frameFiltOpt.defaultPend = 0; cmd_rx.frameFiltOpt.bPendDataReqOnly = 0; - cmd_rx.frameFiltOpt.bPanCoord = 0; + cmd_rx.frameFiltOpt.bPanCoord = 0; cmd_rx.frameFiltOpt.bStrictLenFilter = 0; const bool old_poll_mode = ieee_radio.poll_mode; @@ -867,7 +868,7 @@ set_value(radio_param_t param, radio_value_t value) if(old_poll_mode == ieee_radio.poll_mode) { /* Do not turn the radio off and on, just send an update command */ memcpy(&cmd_mod_filt.newFrameFiltOpt, &(rf_cmd_ieee_rx.frameFiltOpt), sizeof(rf_cmd_ieee_rx.frameFiltOpt)); - const RF_Stat stat = RF_runImmediateCmd(ieee_radio.rf_handle, (uint32_t*)&cmd_mod_filt); + const RF_Stat stat = RF_runImmediateCmd(ieee_radio.rf_handle, (uint32_t *)&cmd_mod_filt); if(stat != RF_StatCmdDoneSuccess) { LOG_ERR("Setting address filter failed, stat=0x%02X\n", stat); return RADIO_RESULT_ERROR; diff --git a/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c b/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c index 7aa906a3a..76475d154 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c +++ b/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c @@ -79,14 +79,16 @@ #define LOG_LEVEL LOG_LEVEL_NONE /*---------------------------------------------------------------------------*/ /* Configuration parameters */ -#define PROP_MODE_DW PROP_MODE_CONF_DW +#define PROP_MODE_DYN_WHITENER PROP_MODE_CONF_DW #define PROP_MODE_USE_CRC16 PROP_MODE_CONF_USE_CRC16 +#define PROP_MODE_CENTER_FREQ PROP_MODE_CONF_CENTER_FREQ +#define PROP_MODE_LO_DIVIDER PROP_MODE_CONF_LO_DIVIDER #define PROP_MODE_CCA_RSSI_THRESHOLD PROP_MODE_CONF_CCA_RSSI_THRESHOLD /*---------------------------------------------------------------------------*/ /* Used for checking result of CCA_REQ command */ typedef enum { - CCA_STATE_IDLE = 0, - CCA_STATE_BUSY = 1, + CCA_STATE_IDLE = 0, + CCA_STATE_BUSY = 1, CCA_STATE_INVALID = 2 } cca_state_t; /*---------------------------------------------------------------------------*/ @@ -108,7 +110,7 @@ typedef enum { #define CRC_LEN 4 #endif /* PROP_MODE_USE_CRC16 */ -#if PROP_MODE_DW +#if PROP_MODE_DYN_WHITENER #define DOT_4G_PHR_DW_BIT DOT_4G_PHR_DW #else #define DOT_4G_PHR_DW_BIT 0 @@ -127,7 +129,7 @@ typedef enum { #define TX_BUF_SIZE (TX_BUF_HDR_LEN + TX_BUF_PAYLOAD_LEN) /*---------------------------------------------------------------------------*/ /* Size of the Length field in Data Entry, two bytes in this case */ -typedef uint16_t lensz_t; +typedef uint16_t lensz_t; #define FRAME_OFFSET sizeof(lensz_t) #define FRAME_SHAVE 2 /**< RSSI (1) + Status (1) */ @@ -142,24 +144,24 @@ typedef uint16_t lensz_t; #define ED_RF_POWER_MAX_DBM RX_SATURATION_DBM /*---------------------------------------------------------------------------*/ /* RF Core typedefs */ -typedef rfc_propRxOutput_t rx_output_t; +typedef rfc_propRxOutput_t rx_output_t; typedef struct { /* Outgoing frame buffer */ - uint8_t tx_buf[TX_BUF_SIZE] CC_ALIGN(4); + uint8_t tx_buf[TX_BUF_SIZE] CC_ALIGN(4); /* RX Statistics struct */ rx_output_t rx_stats; /* RSSI Threshold */ - int8_t rssi_threshold; - uint16_t channel; + int8_t rssi_threshold; + uint16_t channel; /* Indicates RF is supposed to be on or off */ - uint8_t rf_is_on; + uint8_t rf_is_on; /* RF driver */ - RF_Handle rf_handle; + RF_Handle rf_handle; } prop_radio_t; static prop_radio_t prop_radio; @@ -188,14 +190,14 @@ static int off(void); static void init_rf_params(void) { - cmd_radio_setup.centerFreq = PROP_MODE_CONF_CENTER_FREQ; - cmd_radio_setup.loDivider = PROP_MODE_CONF_LO_DIVIDER; + cmd_radio_setup.centerFreq = PROP_MODE_CENTER_FREQ; + cmd_radio_setup.loDivider = PROP_MODE_LO_DIVIDER; data_queue_t *data_queue = data_queue_init(sizeof(lensz_t)); cmd_rx.maxPktLen = DOT_4G_MAX_FRAME_LEN - cmd_rx.lenOffset; - cmd_rx.pQueue = data_queue; - cmd_rx.pOutput = (uint8_t *)&prop_radio.rx_stats; + cmd_rx.pQueue = data_queue; + cmd_rx.pOutput = (uint8_t *)&prop_radio.rx_stats; } /*---------------------------------------------------------------------------*/ static int8_t @@ -265,7 +267,7 @@ set_channel(uint16_t channel) const uint16_t frac = (uint16_t)(((new_freq - (freq * 1000)) * 0x10000) / 1000); LOG_DBG("Set channel to %d, frequency 0x%04X.0x%04X (%lu)\n", - (int)channel, freq, frac, new_freq); + (int)channel, freq, frac, new_freq); cmd_fs.frequency = freq; cmd_fs.fractFreq = frac; @@ -387,8 +389,8 @@ read(void *buf, unsigned short buf_len) * = N + 2 * N = Length - 2 */ - uint8_t *const frame_ptr = (uint8_t*)&data_entry->data; - const lensz_t frame_len = *(lensz_t*)frame_ptr; + uint8_t *const frame_ptr = (uint8_t *)&data_entry->data; + const lensz_t frame_len = *(lensz_t *)frame_ptr; /* Sanity check that Frame is at least Frame Shave bytes long */ if(frame_len < FRAME_SHAVE) { @@ -417,7 +419,7 @@ read(void *buf, unsigned short buf_len) /* LQI calculated from RSSI */ const uint8_t lqi = calculate_lqi(rssi); - packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (packetbuf_attr_t)rssi); + packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (packetbuf_attr_t)rssi); packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, (packetbuf_attr_t)lqi); data_queue_release_entry(); @@ -551,7 +553,7 @@ get_value(radio_param_t param, radio_value_t *value) return RADIO_RESULT_OK; case RADIO_PARAM_TXPOWER: - res = rf_get_tx_power(prop_radio.rf_handle, rf_tx_power_table, (int8_t*)&value); + res = rf_get_tx_power(prop_radio.rf_handle, rf_tx_power_table, (int8_t *)&value); return ((res == RF_RESULT_OK) && (*value != RF_TxPowerTable_INVALID_DBM)) ? RADIO_RESULT_OK @@ -663,7 +665,7 @@ init(void) init_rf_params(); /* Init RF params and specify non-default params */ - RF_Params rf_params; + RF_Params rf_params; RF_Params_init(&rf_params); rf_params.nInactivityTimeout = 2000; /* 2 ms */ diff --git a/arch/cpu/cc13xx-cc26xx/rf/rf.h b/arch/cpu/cc13xx-cc26xx/rf/rf.h index a0c38513f..cfc6b2277 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/rf.h +++ b/arch/cpu/cc13xx-cc26xx/rf/rf.h @@ -56,9 +56,8 @@ #define RF_MODE_2_4_GHZ (1 << 1) /* Bitmask of supported RF modes */ -#define RF_MODE_BM ( RF_MODE_SUB_1_GHZ \ - | RF_MODE_2_4_GHZ \ - ) +#define RF_MODE_BM (RF_MODE_SUB_1_GHZ | \ + RF_MODE_2_4_GHZ) /** @} */ /*---------------------------------------------------------------------------*/ #endif /* RF_CORE_H_ */ diff --git a/arch/cpu/cc13xx-cc26xx/rf/sched.c b/arch/cpu/cc13xx-cc26xx/rf/sched.c index 73957e33b..44387c138 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/sched.c +++ b/arch/cpu/cc13xx-cc26xx/rf/sched.c @@ -72,7 +72,7 @@ /*---------------------------------------------------------------------------*/ #define CMD_FS_RETRIES 3 -#define RF_EVENTS_CMD_DONE (RF_EventCmdDone | RF_EventLastCmdDone | \ +#define RF_EVENTS_CMD_DONE (RF_EventCmdDone | RF_EventLastCmdDone | \ RF_EventFGCmdDone | RF_EventLastFGCmdDone) #define CMD_STATUS(cmd) (CC_ACCESS_NOW(RF_Op, cmd).status) @@ -91,7 +91,7 @@ static struct etimer synth_recal_timer; /*---------------------------------------------------------------------------*/ static RF_Object rf_netstack; -#if RF_BLE_BEACON_ENABLE +#if RF_CONF_BLE_BEACON_ENABLE static RF_Object rf_ble; #endif @@ -165,22 +165,22 @@ cmd_rx_restore(uint_fast8_t rx_key) RF_ScheduleCmdParams sched_params; RF_ScheduleCmdParams_init(&sched_params); - sched_params.priority = RF_PriorityNormal; - sched_params.endTime = 0; + sched_params.priority = RF_PriorityNormal; + sched_params.endTime = 0; sched_params.allowDelay = RF_AllowDelayAny; CMD_STATUS(netstack_cmd_rx) = PENDING; - cmd_rx_handle = RF_scheduleCmd(&rf_netstack, - (RF_Op*)&netstack_cmd_rx, - &sched_params, - cmd_rx_cb, - RF_EventRxEntryDone | RF_EventRxBufFull - ); + cmd_rx_handle = RF_scheduleCmd( + &rf_netstack, + (RF_Op *)&netstack_cmd_rx, + &sched_params, + cmd_rx_cb, + RF_EventRxEntryDone | RF_EventRxBufFull); if(!CMD_HANDLE_OK(cmd_rx_handle)) { LOG_ERR("Unable to restore RX command, handle=%d status=0x%04x", - cmd_rx_handle, CMD_STATUS(netstack_cmd_rx)); + cmd_rx_handle, CMD_STATUS(netstack_cmd_rx)); return RF_RESULT_ERROR; } @@ -192,13 +192,13 @@ rf_yield(void) { /* Force abort of any ongoing RF operation */ RF_flushCmd(&rf_netstack, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY); -#if RF_BLE_BEACON_ENABLE - RF_flushCmd(&rf_ble, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY); +#if RF_CONF_BLE_BEACON_ENABLE + RF_flushCmd(&rf_ble, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY); #endif /* Trigger a manual power-down */ RF_yield(&rf_netstack); -#if RF_BLE_BEACON_ENABLE +#if RF_CONF_BLE_BEACON_ENABLE RF_yield(&rf_ble); #endif @@ -213,9 +213,7 @@ rf_yield(void) rf_result_t rf_set_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8_t dbm) { - const RF_Stat stat = RF_setTxPower(handle, - RF_TxPowerTable_findValue(table, dbm) - ); + const RF_Stat stat = RF_setTxPower(handle, RF_TxPowerTable_findValue(table, dbm)); return (stat == RF_StatSuccess) ? RF_RESULT_OK @@ -225,9 +223,7 @@ rf_set_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8_t dbm) rf_result_t rf_get_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8_t *dbm) { - *dbm = RF_TxPowerTable_findPowerLevel(table, - RF_getTxPower(handle) - ); + *dbm = RF_TxPowerTable_findPowerLevel(table, RF_getTxPower(handle)); return (*dbm != RF_TxPowerTable_INVALID_DBM) ? RF_RESULT_OK @@ -237,11 +233,7 @@ rf_get_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8_t *dbm) RF_Handle netstack_open(RF_Params *params) { - return RF_open(&rf_netstack, - &netstack_mode, - (RF_RadioSetup*)&netstack_cmd_radio_setup, - params - ); + return RF_open(&rf_netstack, &netstack_mode, (RF_RadioSetup *)&netstack_cmd_radio_setup, params); } /*---------------------------------------------------------------------------*/ rf_result_t @@ -271,15 +263,15 @@ netstack_sched_fs(void) do { CMD_STATUS(netstack_cmd_fs) = PENDING; - events = RF_runCmd(&rf_netstack, - (RF_Op*)&netstack_cmd_fs, - RF_PriorityNormal, - NULL, - 0 - ); + events = RF_runCmd( + &rf_netstack, + (RF_Op *)&netstack_cmd_fs, + RF_PriorityNormal, + NULL, + 0); + + synth_error = (EVENTS_CMD_DONE(events)) && (CMD_STATUS(netstack_cmd_fs) == ERROR_SYNTH_PROG); - synth_error = (EVENTS_CMD_DONE(events)) - && (CMD_STATUS(netstack_cmd_fs) == ERROR_SYNTH_PROG); } while(synth_error && (num_tries++ < CMD_FS_RETRIES)); cmd_rx_restore(rx_key); @@ -297,8 +289,8 @@ netstack_sched_ieee_tx(bool ack_request) RF_ScheduleCmdParams sched_params; RF_ScheduleCmdParams_init(&sched_params); - sched_params.priority = RF_PriorityNormal; - sched_params.endTime = 0; + sched_params.priority = RF_PriorityNormal; + sched_params.endTime = 0; sched_params.allowDelay = RF_AllowDelayAny; const bool rx_is_active = cmd_rx_is_active(); @@ -318,16 +310,16 @@ netstack_sched_ieee_tx(bool ack_request) CMD_STATUS(netstack_cmd_tx) = PENDING; - RF_CmdHandle tx_handle = RF_scheduleCmd(&rf_netstack, - (RF_Op*)&netstack_cmd_tx, - &sched_params, - NULL, - 0 - ); + RF_CmdHandle tx_handle = RF_scheduleCmd( + &rf_netstack, + (RF_Op *)&netstack_cmd_tx, + &sched_params, + NULL, + 0); if(!CMD_HANDLE_OK(tx_handle)) { LOG_ERR("Unable to schedule TX command, handle=%d status=0x%04x\n", - tx_handle, CMD_STATUS(netstack_cmd_tx)); + tx_handle, CMD_STATUS(netstack_cmd_tx)); return RF_RESULT_ERROR; } @@ -353,7 +345,7 @@ netstack_sched_ieee_tx(bool ack_request) if(!EVENTS_CMD_DONE(tx_events)) { LOG_ERR("Pending on TX comand generated error, events=0x%08llx status=0x%04x\n", - tx_events, CMD_STATUS(netstack_cmd_tx)); + tx_events, CMD_STATUS(netstack_cmd_tx)); return RF_RESULT_ERROR; } @@ -366,18 +358,18 @@ netstack_sched_prop_tx(void) RF_ScheduleCmdParams sched_params; RF_ScheduleCmdParams_init(&sched_params); - sched_params.priority = RF_PriorityNormal; - sched_params.endTime = 0; + sched_params.priority = RF_PriorityNormal; + sched_params.endTime = 0; sched_params.allowDelay = RF_AllowDelayAny; CMD_STATUS(netstack_cmd_tx) = PENDING; - RF_CmdHandle tx_handle = RF_scheduleCmd(&rf_netstack, - (RF_Op*)&netstack_cmd_tx, - &sched_params, - NULL, - 0 - ); + RF_CmdHandle tx_handle = RF_scheduleCmd( + &rf_netstack, + (RF_Op *)&netstack_cmd_tx, + &sched_params, + NULL, + 0); if(!CMD_HANDLE_OK(tx_handle)) { LOG_ERR("Unable to schedule TX command, handle=%d status=0x%04x\n", @@ -428,18 +420,18 @@ netstack_sched_rx(bool start) RF_ScheduleCmdParams sched_params; RF_ScheduleCmdParams_init(&sched_params); - sched_params.priority = RF_PriorityNormal; - sched_params.endTime = 0; + sched_params.priority = RF_PriorityNormal; + sched_params.endTime = 0; sched_params.allowDelay = RF_AllowDelayAny; CMD_STATUS(netstack_cmd_rx) = PENDING; - cmd_rx_handle = RF_scheduleCmd(&rf_netstack, - (RF_Op*)&netstack_cmd_rx, - &sched_params, - cmd_rx_cb, - RF_EventRxEntryDone | RF_EventRxBufFull - ); + cmd_rx_handle = RF_scheduleCmd( + &rf_netstack, + (RF_Op *)&netstack_cmd_rx, + &sched_params, + cmd_rx_cb, + RF_EventRxEntryDone | RF_EventRxBufFull); if(!CMD_HANDLE_OK(cmd_rx_handle)) { LOG_ERR("Unable to schedule RX command, handle=%d status=0x%04x\n", @@ -479,8 +471,8 @@ netstack_stop_rx(void) RF_Handle ble_open(RF_Params *params) { -#if RF_BLE_BEACON_ENABLE - return RF_open(&rf_ble, &ble_mode, (RF_RadioSetup*)&ble_cmd_radio_setup, params); +#if RF_CONF_BLE_BEACON_ENABLE + return RF_open(&rf_ble, &ble_mode, (RF_RadioSetup *)&ble_cmd_radio_setup, params); #else return (RF_Handle)NULL; @@ -490,22 +482,22 @@ ble_open(RF_Params *params) rf_result_t ble_sched_beacon(RF_Callback cb, RF_EventMask bm_event) { -#if RF_BLE_BEACON_ENABLE +#if RF_CONF_BLE_BEACON_ENABLE RF_ScheduleCmdParams sched_params; RF_ScheduleCmdParams_init(&sched_params); - sched_params.priority = RF_PriorityNormal; - sched_params.endTime = 0; + sched_params.priority = RF_PriorityNormal; + sched_params.endTime = 0; sched_params.allowDelay = RF_AllowDelayAny; CMD_STATUS(ble_cmd_beacon) = PENDING; - RF_CmdHandle beacon_handle = RF_scheduleCmd(&rf_ble, - (RF_Op*)&ble_cmd_beacon, - &sched_params, - cb, - bm_event - ); + RF_CmdHandle beacon_handle = RF_scheduleCmd( + &rf_ble, + (RF_Op *)&ble_cmd_beacon, + &sched_params, + cb, + bm_event); if(!CMD_HANDLE_OK(beacon_handle)) { LOG_ERR("Unable to schedule BLE Beacon command, handle=%d status=0x%04x\n", diff --git a/arch/cpu/cc13xx-cc26xx/rf/settings.h b/arch/cpu/cc13xx-cc26xx/rf/settings.h index 4d8df6d23..0f4da3376 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf/settings.h @@ -27,7 +27,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ - /** +/** * \addtogroup cc13xx-cc26xx-cpu * @{ * diff --git a/arch/cpu/cc13xx-cc26xx/rf/tx-power.h b/arch/cpu/cc13xx-cc26xx/rf/tx-power.h index a6104275e..91bab7d6b 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/tx-power.h +++ b/arch/cpu/cc13xx-cc26xx/rf/tx-power.h @@ -81,20 +81,18 @@ extern const size_t ble_tx_power_table_size; static inline int8_t tx_power_min(tx_power_table_t *table) { - return table[0].power; + return table[0].power; } - static inline int8_t tx_power_max(tx_power_table_t *table, size_t size) { - return table[size - 1].power; + return table[size - 1].power; } - static inline bool tx_power_in_range(int8_t dbm, tx_power_table_t *table, size_t size) { - return (dbm >= tx_power_min(table)) && - (dbm <= tx_power_max(table, size)); + return (dbm >= tx_power_min(table)) && + (dbm <= tx_power_max(table, size)); } /** @} */ /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/platform.c b/arch/platform/simplelink/cc13xx-cc26xx/platform.c index bf295e762..50b8ad2c8 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/platform.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/platform.c @@ -108,9 +108,13 @@ fade(PIN_Id pin) j = (k > pivot_half) ? pivot - k : k; PINCC26XX_setOutputValue(pin, 1); - for(i = 0; i < j; ++i) { __asm__ __volatile__ ("nop"); } + for(i = 0; i < j; ++i) { + __asm__ __volatile__ ("nop"); + } PINCC26XX_setOutputValue(pin, 0); - for(i = 0; i < pivot_half - j; ++i) { __asm__ __volatile__ ("nop"); } + for(i = 0; i < pivot_half - j; ++i) { + __asm__ __volatile__ ("nop"); + } } } /*---------------------------------------------------------------------------*/ @@ -128,8 +132,8 @@ set_rf_params(void) ieee_addr_cpy_to(ext_addr, sizeof(ext_addr)); /* Short address is the last two bytes of the MAC address */ - short_addr = ((uint16_t)ext_addr[7] << 0) - | ((uint16_t)ext_addr[6] << 8); + short_addr = (((uint16_t)ext_addr[7] << 0) | + ((uint16_t)ext_addr[6] << 8)); NETSTACK_RADIO.set_value(RADIO_PARAM_PAN_ID, IEEE802154_PANID); NETSTACK_RADIO.set_value(RADIO_PARAM_16BIT_ADDR, short_addr); @@ -203,7 +207,7 @@ platform_init_stage_two(void) /* Use TRNG to seed PRNG. If TRNG fails, use a hard-coded seed. */ unsigned short seed = 0; - if(!trng_rand((uint8_t*)&seed, sizeof(seed), TRNG_WAIT_FOREVER)) { + if(!trng_rand((uint8_t *)&seed, sizeof(seed), TRNG_WAIT_FOREVER)) { /* Default to some hard-coded seed. */ seed = 0x1234; } @@ -220,7 +224,7 @@ platform_init_stage_two(void) void platform_init_stage_three(void) { -#if RF_BLE_BEACON_ENABLE +#if RF_CONF_BLE_BEACON_ENABLE rf_ble_beacond_init(); #endif @@ -236,12 +240,12 @@ platform_init_stage_three(void) DRIVERLIB_RELEASE_BUILD); LOG_DBG("IEEE 802.15.4: %s, Sub-1 GHz: %s, BLE: %s\n", ChipInfo_SupportsIEEE_802_15_4() ? "Yes" : "No", - ChipInfo_SupportsPROPRIETARY() ? "Yes" : "No", - ChipInfo_SupportsBLE() ? "Yes" : "No"); + ChipInfo_SupportsPROPRIETARY() ? "Yes" : "No", + ChipInfo_SupportsBLE() ? "Yes" : "No"); -#if(RF_MODE == RF_MODE_SUB_1_GHZ) +#if (RF_MODE == RF_MODE_SUB_1_GHZ) LOG_INFO("Operating frequency on Sub-1 GHz\n"); -#elif(RF_MODE == RF_MODE_2_4_GHZ) +#elif (RF_MODE == RF_MODE_2_4_GHZ) LOG_INFO("Operating frequency on 2.4 GHz\n"); #endif LOG_INFO("RF: Channel %d, PANID 0x%04X\n", chan, pan); diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c index 830506fac..7c6b0f2f1 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c @@ -67,7 +67,7 @@ #if BOARD_SENSORS_ENABLE /*---------------------------------------------------------------------------*/ #ifndef Board_BMP280_ADDR -# error "Board file doesn't define I2C address Board_BMP280_ADDR" +#error "Board file doesn't define I2C address Board_BMP280_ADDR" #endif /* Sensor I2C address */ #define BMP280_I2C_ADDRESS Board_BMP280_ADDR @@ -122,17 +122,17 @@ /*---------------------------------------------------------------------------*/ typedef struct { uint16_t dig_t1; - int16_t dig_t2; - int16_t dig_t3; + int16_t dig_t2; + int16_t dig_t3; uint16_t dig_p1; - int16_t dig_p2; - int16_t dig_p3; - int16_t dig_p4; - int16_t dig_p5; - int16_t dig_p6; - int16_t dig_p7; - int16_t dig_p8; - int16_t dig_p9; + int16_t dig_p2; + int16_t dig_p3; + int16_t dig_p4; + int16_t dig_p5; + int16_t dig_p6; + int16_t dig_p7; + int16_t dig_p8; + int16_t dig_p9; } BMP_280_Calibration; /*---------------------------------------------------------------------------*/ static BMP_280_Calibration calib_data; @@ -175,7 +175,6 @@ i2c_write_read(void *writeBuf, size_t writeCount, void *readBuf, size_t readCoun return I2C_transfer(i2c_handle, &i2cTransaction); } - #define i2c_write(writeBuf, writeCount) i2c_write_read(writeBuf, writeCount, NULL, 0) #define i2c_read(readBuf, readCount) i2c_write_read(NULL, 0, readBuf, readCount) /*---------------------------------------------------------------------------*/ @@ -209,8 +208,8 @@ init(void) uint8_t calib_reg = ADDR_CALIB; /* Read and store calibration data */ return i2c_write_read(&calib_reg, sizeof(calib_reg), &calib_data, sizeof(calib_data)) - /* then reset the sensor */ - && i2c_write(reset_data, sizeof(reset_data)); + /* then reset the sensor */ + && i2c_write(reset_data, sizeof(reset_data)); } /*---------------------------------------------------------------------------*/ /** @@ -264,30 +263,20 @@ convert(uint8_t *data, int32_t *temp, uint32_t *press) /* Pressure */ const int32_t upress = (int32_t)( - (((uint32_t)data[0]) << 12) | - (((uint32_t)data[1]) << 4) | - (((uint32_t)data[2]) >> 4) - ); + (((uint32_t)data[0]) << 12) | + (((uint32_t)data[1]) << 4) | + (((uint32_t)data[2]) >> 4) + ); /* Temperature */ const int32_t utemp = (int32_t)( - (((uint32_t)data[3]) << 12) | - (((uint32_t)data[4]) << 4) | - (((uint32_t)data[5]) >> 4) - ); + (((uint32_t)data[3]) << 12) | + (((uint32_t)data[4]) << 4) | + (((uint32_t)data[5]) >> 4) + ); /* Compensate temperature */ - int32_t v_x1_u32r = ( ( - (utemp >> 3) - ((int32_t)p->dig_t1 << 1) - ) * (int32_t)p->dig_t2 - ) >> 11; - int32_t v_x2_u32r = ( ( ( ( - (utemp >> 4) - (int32_t)p->dig_t1 - ) * ( - (utemp >> 4) - (int32_t)p->dig_t1 - ) - ) >> 12 - ) * (int32_t)p->dig_t3 - ) >> 14; + int32_t v_x1_u32r = (((utemp >> 3) - ((int32_t)p->dig_t1 << 1)) * (int32_t)p->dig_t2) >> 11; + int32_t v_x2_u32r = (((((utemp >> 4) - (int32_t)p->dig_t1) * ((utemp >> 4) - (int32_t)p->dig_t1)) >> 12) * (int32_t)p->dig_t3) >> 14; const uint32_t t_fine = v_x1_u32r + v_x2_u32r; const int32_t temperature = (t_fine * 5 + 128) >> 8; @@ -295,28 +284,11 @@ convert(uint8_t *data, int32_t *temp, uint32_t *press) /* Compensate pressure */ v_x1_u32r = ((int32_t)t_fine >> 1) - (int32_t)64000; - v_x2_u32r = ( ( - (v_x1_u32r >> 2) * (v_x1_u32r >> 2) - ) >> 11 - ) * (int32_t)p->dig_p6; - v_x2_u32r = ( ( - v_x1_u32r * (int32_t)p->dig_p5 - ) << 1 - ) + v_x2_u32r; + v_x2_u32r = (((v_x1_u32r >> 2) * (v_x1_u32r >> 2)) >> 11) * (int32_t)p->dig_p6; + v_x2_u32r = ((v_x1_u32r * (int32_t)p->dig_p5) << 1) + v_x2_u32r; v_x2_u32r = (v_x2_u32r >> 2) + ((int32_t)p->dig_p4 << 16); - v_x1_u32r = ( ( ( ( ( - (v_x1_u32r >> 2) * (v_x1_u32r >> 2) - ) >> 13 - ) * p->dig_p3 - ) >> 3 - ) + ( ( - (int32_t)p->dig_p2 * v_x1_u32r - ) >> 1 - ) - ) >> 18; - v_x1_u32r = ( - (32768 + v_x1_u32r) * (int32_t)p->dig_p1 - ) >> 15; + v_x1_u32r = ((((((v_x1_u32r >> 2) * (v_x1_u32r >> 2)) >> 13) * p->dig_p3) >> 3) + (((int32_t)p->dig_p2 * v_x1_u32r) >> 1)) >> 18; + v_x1_u32r = ((32768 + v_x1_u32r) * (int32_t)p->dig_p1) >> 15; if(v_x1_u32r == 0) { /* Avoid exception caused by division by zero */ @@ -324,33 +296,16 @@ convert(uint8_t *data, int32_t *temp, uint32_t *press) return; } - uint32_t pressure = ( ( - (uint32_t)((int32_t)1048576 - upress) - ) - ( - v_x2_u32r >> 12 - ) - ) * 3125; + uint32_t pressure = (((uint32_t)((int32_t)1048576 - upress)) - (v_x2_u32r >> 12)) * 3125; if((int32_t)pressure < 0) { pressure = (pressure << 1) / (uint32_t)v_x1_u32r; } else { pressure = (pressure / (uint32_t)v_x1_u32r) * 2; } - v_x1_u32r = ( ( - (int32_t)( ( - (pressure >> 3) * (pressure >> 3) - ) >> 13 - ) - ) * (int32_t)p->dig_p9 - ) >> 12; - v_x2_u32r = ( - (int32_t)(pressure >> 2) * (int32_t)p->dig_p8 - ) >> 13; - pressure = (uint32_t)( ( ( - v_x1_u32r + v_x2_u32r + p->dig_p7 - ) >> 4 - ) + (int32_t)pressure - ); + v_x1_u32r = (((int32_t)(((pressure >> 3) * (pressure >> 3)) >> 13)) * (int32_t)p->dig_p9) >> 12; + v_x2_u32r = ((int32_t)(pressure >> 2) * (int32_t)p->dig_p8) >> 13; + pressure = (uint32_t)(((v_x1_u32r + v_x2_u32r + p->dig_p7) >> 4) + (int32_t)pressure); *press = pressure; } diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.h index f2c160947..02b2034b1 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.h @@ -64,13 +64,13 @@ /* The BMP-280 driver uses the I2C0 peripheral to access the senssor */ #if BOARD_SENSORS_ENABLE #if (TI_I2C_CONF_ENABLE == 0) || (TI_I2C_CONF_I2C0_ENABLE == 0) -# error "The BMP280 requires the I2C driver (TI_I2C_CONF_ENABLE = 1)" +#error "The BMP280 requires the I2C driver (TI_I2C_CONF_ENABLE = 1)" #endif #endif /*---------------------------------------------------------------------------*/ typedef enum { - BMP_280_SENSOR_TYPE_TEMP, - BMP_280_SENSOR_TYPE_PRESS + BMP_280_SENSOR_TYPE_TEMP, + BMP_280_SENSOR_TYPE_PRESS } BMP_280_SENSOR_TYPE; /*---------------------------------------------------------------------------*/ #define BMP_280_READING_ERROR -1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.c index 84d760278..1815a370d 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.c @@ -54,7 +54,7 @@ /*---------------------------------------------------------------------------*/ /* Configure BUZZER pin */ #ifndef Board_BUZZER -# error "Board file doesn't define pin Board_BUZZER" +#error "Board file doesn't define pin Board_BUZZER" #endif #define BUZZER_PIN Board_BUZZER /*---------------------------------------------------------------------------*/ @@ -126,8 +126,8 @@ buzzer_start(uint32_t freq) PINCC26XX_setMux(pin_handle, BUZZER_PIN, GPT_PIN_0A); - // MCU runs at 48 MHz - GPTimerCC26XX_Value load_value = 48000000 / freq; + /* MCU runs at 48 MHz */ + GPTimerCC26XX_Value load_value = (48 * 1000 * 1000) / freq; GPTimerCC26XX_setLoadValue(gpt_handle, load_value); GPTimerCC26XX_start(gpt_handle); diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.c index 2f3e6fa6e..85840605d 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.c @@ -68,7 +68,7 @@ #if BOARD_SENSORS_ENABLE /*---------------------------------------------------------------------------*/ #ifndef Board_HDC1000_ADDR -# error "Board file doesn't define the I2C address Board_HDC1000_ADDR" +#error "Board file doesn't define the I2C address Board_HDC1000_ADDR" #endif /* Sensor I2C address */ #define HDC1000_I2C_ADDRESS Board_HDC1000_ADDR @@ -136,16 +136,15 @@ static bool i2c_write_read(void *wbuf, size_t wcount, void *rbuf, size_t rcount) { I2C_Transaction i2c_transaction = { - .writeBuf = wbuf, - .writeCount = wcount, - .readBuf = rbuf, - .readCount = rcount, + .writeBuf = wbuf, + .writeCount = wcount, + .readBuf = rbuf, + .readCount = rcount, .slaveAddress = HDC1000_I2C_ADDRESS, }; return I2C_transfer(i2c_handle, &i2c_transaction); } - /** * \brief Peform a write only I2C transaction. * \param wbuf Output buffer during the I2C transation. @@ -158,7 +157,6 @@ i2c_write(void *wbuf, size_t wcount) { return i2c_write_read(wbuf, wcount, NULL, 0); } - /** * \brief Peform a read only I2C transaction. * \param rbuf Input buffer during the I2C transation. @@ -194,7 +192,7 @@ sensor_init(void) return false; } - // Enable reading data in one operation + /* Enable reading data in one operation */ uint8_t config_data[] = { HDC1000_REG_CONFIG, LSB16(HDC1000_VAL_CONFIG) }; return i2c_write(config_data, sizeof(config_data)); diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.h index b6bd7ca4f..4dcab02c2 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.h @@ -71,7 +71,7 @@ /*---------------------------------------------------------------------------*/ #if BOARD_SENSORS_ENABLE #if (TI_I2C_CONF_ENABLE == 0) || (TI_I2C_CONF_I2C0_ENABLE == 0) -# error "The HDC-1000 requires the I2C driver (TI_I2C_CONF_ENABLE = 1)" +#error "The HDC-1000 requires the I2C driver (TI_I2C_CONF_ENABLE = 1)" #endif #endif /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c index f849c6735..825a4043c 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c @@ -47,7 +47,7 @@ #include #include -#include DeviceFamily_constructPath(driverlib/cpu.h) +#include DeviceFamily_constructPath(driverlib / cpu.h) #include #include @@ -72,10 +72,10 @@ #if BOARD_SENSORS_ENABLE /*---------------------------------------------------------------------------*/ #ifndef Board_MPU9250_ADDR -# error "Board file doesn't define I2C address Board_MPU9250_ADDR" +#error "Board file doesn't define I2C address Board_MPU9250_ADDR" #endif #ifndef Board_MPU9250_MAG_ADDR -# error "Board file doesn't define I2C address Board_MPU9250_MAG_ADDR" +#error "Board file doesn't define I2C address Board_MPU9250_MAG_ADDR" #endif /* Sensor I2C address */ @@ -190,20 +190,20 @@ #define BIT_STBY_XYZG (BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG) /*---------------------------------------------------------------------------*/ static PIN_Config mpu_9250_pin_table[] = { - Board_MPU_INT | PIN_INPUT_EN | PIN_PULLDOWN | PIN_HYSTERESIS, + Board_MPU_INT | PIN_INPUT_EN | PIN_PULLDOWN | PIN_HYSTERESIS, Board_MPU_POWER | PIN_GPIO_OUTPUT_EN | PIN_DRVSTR_MAX | PIN_GPIO_LOW, PIN_TERMINATE }; -static PIN_State pin_state; +static PIN_State pin_state; static PIN_Handle pin_handle; static I2C_Handle i2c_handle; /*---------------------------------------------------------------------------*/ typedef struct { - volatile MPU_9250_SENSOR_STATUS status; - volatile MPU_9250_SENSOR_TYPE type; - MPU_9250_SENSOR_ACC_RANGE acc_range; + volatile MPU_9250_SENSOR_STATUS status; + volatile MPU_9250_SENSOR_TYPE type; + MPU_9250_SENSOR_ACC_RANGE acc_range; } MPU_9250_Object; static MPU_9250_Object mpu_9250; @@ -247,16 +247,15 @@ static bool i2c_write_read(void *wbuf, size_t wcount, void *rbuf, size_t rcount) { I2C_Transaction i2c_transaction = { - .writeBuf = wbuf, - .writeCount = wcount, - .readBuf = rbuf, - .readCount = rcount, + .writeBuf = wbuf, + .writeCount = wcount, + .readBuf = rbuf, + .readCount = rcount, .slaveAddress = MPU_9250_I2C_ADDRESS, }; return I2C_transfer(i2c_handle, &i2c_transaction); } - /** * \brief Peform a write only I2C transaction. * \param wbuf Output buffer during the I2C transation. @@ -269,7 +268,6 @@ i2c_write(void *wbuf, size_t wcount) { return i2c_write_read(wbuf, wcount, NULL, 0); } - /** * \brief Peform a read only I2C transaction. * \param rbuf Input buffer during the I2C transation. @@ -392,7 +390,7 @@ convert_to_le(uint8_t *data, uint8_t len) * us to determine whether a new sensor reading is available. */ static bool -sensor_data_ready(uint8_t* int_status) +sensor_data_ready(uint8_t *int_status) { uint8_t int_status_data[] = { REG_INT_STATUS }; const bool spi_ok = i2c_write_read(int_status_data, sizeof(int_status_data), int_status, 1); @@ -418,7 +416,7 @@ acc_read(uint8_t int_status, uint16_t *data) return false; } - convert_to_le((uint8_t*)data, DATA_SIZE); + convert_to_le((uint8_t *)data, DATA_SIZE); return true; } @@ -441,7 +439,7 @@ gyro_read(uint8_t int_status, uint16_t *data) return false; } - convert_to_le((uint8_t*)data, DATA_SIZE); + convert_to_le((uint8_t *)data, DATA_SIZE); return true; } @@ -455,9 +453,9 @@ static int32_t acc_convert(int32_t raw_data) { switch(mpu_9250.acc_range) { - case MPU_9250_SENSOR_ACC_RANGE_2G: return raw_data * 100 * 2 / 32768; - case MPU_9250_SENSOR_ACC_RANGE_4G: return raw_data * 100 * 4 / 32768; - case MPU_9250_SENSOR_ACC_RANGE_8G: return raw_data * 100 * 8 / 32768; + case MPU_9250_SENSOR_ACC_RANGE_2G: return raw_data * 100 * 2 / 32768; + case MPU_9250_SENSOR_ACC_RANGE_4G: return raw_data * 100 * 4 / 32768; + case MPU_9250_SENSOR_ACC_RANGE_8G: return raw_data * 100 * 8 / 32768; case MPU_9250_SENSOR_ACC_RANGE_16G: return raw_data * 100 * 16 / 32768; } return 0; @@ -555,7 +553,7 @@ value(int type) default: return MPU_9250_READING_ERROR; } - /* Read gyro data */ + /* Read gyro data */ } else if((type & MPU_9250_SENSOR_TYPE_GYRO) != 0) { if(!gyro_read(int_status, sensor_value)) { @@ -573,7 +571,7 @@ value(int type) default: return MPU_9250_READING_ERROR; } - /* Invalid sensor type */ + /* Invalid sensor type */ } else { PRINTF("MPU: Invalid type\n"); return MPU_9250_READING_ERROR; @@ -591,7 +589,7 @@ value(int type) static int configure(int type, int enable) { - // Mask enable + /* Mask enable */ const MPU_9250_SENSOR_TYPE enable_type = enable & MPU_9250_SENSOR_TYPE_ALL; switch(type) { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.h index 846e6beb2..d66e91977 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.h @@ -79,7 +79,7 @@ /*---------------------------------------------------------------------------*/ #if BOARD_SENSORS_ENABLE #if (TI_I2C_CONF_ENABLE == 0) || (TI_I2C_CONF_I2C0_ENABLE == 0) -# error "The MPU-9250 requires the I2C driver (TI_I2C_CONF_ENABLE = 1)" +#error "The MPU-9250 requires the I2C driver (TI_I2C_CONF_ENABLE = 1)" #endif #endif /*---------------------------------------------------------------------------*/ @@ -87,31 +87,31 @@ /*---------------------------------------------------------------------------*/ /* Accelerometer / Gyro Axes */ typedef enum { - MPU_9250_SENSOR_TYPE_NONE = (0), /**< 0b000000 = 0x00 */ + MPU_9250_SENSOR_TYPE_NONE = (0), /**< 0b000000 = 0x00 */ MPU_9250_SENSOR_TYPE_GYRO_X = (1 << 0), /**< 0b000001 = 0x01 */ MPU_9250_SENSOR_TYPE_GYRO_Y = (1 << 1), /**< 0b000010 = 0x02 */ MPU_9250_SENSOR_TYPE_GYRO_Z = (1 << 2), /**< 0b000100 = 0x04 */ - MPU_9250_SENSOR_TYPE_ACC_X = (1 << 3), /**< 0b001000 = 0x08 */ - MPU_9250_SENSOR_TYPE_ACC_Y = (1 << 4), /**< 0b010000 = 0x10 */ - MPU_9250_SENSOR_TYPE_ACC_Z = (1 << 5), /**< 0b100000 = 0x20 */ - MPU_9250_SENSOR_TYPE_GYRO = MPU_9250_SENSOR_TYPE_GYRO_X - | MPU_9250_SENSOR_TYPE_GYRO_Y - | MPU_9250_SENSOR_TYPE_GYRO_Z, - /**< 0b000111 = 0x07 */ - MPU_9250_SENSOR_TYPE_ACC = MPU_9250_SENSOR_TYPE_ACC_X - | MPU_9250_SENSOR_TYPE_ACC_Y - | MPU_9250_SENSOR_TYPE_ACC_Z, - /**< 0b111000 = 0x38 */ - MPU_9250_SENSOR_TYPE_ALL = MPU_9250_SENSOR_TYPE_GYRO - | MPU_9250_SENSOR_TYPE_ACC - /**< 0b111111 = 0x3F */ + MPU_9250_SENSOR_TYPE_ACC_X = (1 << 3), /**< 0b001000 = 0x08 */ + MPU_9250_SENSOR_TYPE_ACC_Y = (1 << 4), /**< 0b010000 = 0x10 */ + MPU_9250_SENSOR_TYPE_ACC_Z = (1 << 5), /**< 0b100000 = 0x20 */ + MPU_9250_SENSOR_TYPE_GYRO = MPU_9250_SENSOR_TYPE_GYRO_X + | MPU_9250_SENSOR_TYPE_GYRO_Y + | MPU_9250_SENSOR_TYPE_GYRO_Z, + /**< 0b000111 = 0x07 */ + MPU_9250_SENSOR_TYPE_ACC = MPU_9250_SENSOR_TYPE_ACC_X + | MPU_9250_SENSOR_TYPE_ACC_Y + | MPU_9250_SENSOR_TYPE_ACC_Z, + /**< 0b111000 = 0x38 */ + MPU_9250_SENSOR_TYPE_ALL = MPU_9250_SENSOR_TYPE_GYRO + | MPU_9250_SENSOR_TYPE_ACC + /**< 0b111111 = 0x3F */ } MPU_9250_SENSOR_TYPE; /*---------------------------------------------------------------------------*/ /* Accelerometer range */ typedef enum { - MPU_9250_SENSOR_ACC_RANGE_2G = 0, - MPU_9250_SENSOR_ACC_RANGE_4G = 1, - MPU_9250_SENSOR_ACC_RANGE_8G = 2, + MPU_9250_SENSOR_ACC_RANGE_2G = 0, + MPU_9250_SENSOR_ACC_RANGE_4G = 1, + MPU_9250_SENSOR_ACC_RANGE_8G = 2, MPU_9250_SENSOR_ACC_RANGE_16G = 3 } MPU_9250_SENSOR_ACC_RANGE; /*---------------------------------------------------------------------------*/ @@ -125,9 +125,9 @@ typedef enum { /*---------------------------------------------------------------------------*/ /* Accelerometer range configuration, type MPU_9250_SENSOR_ACC_RANGE */ #ifdef MPU_9250_SENSOR_CONF_ACC_RANGE_ARG -# define MPU_9250_SENSOR_ACC_RANGE_ARG MPU_9250_SENSOR_CONF_ACC_RANGE +#define MPU_9250_SENSOR_ACC_RANGE_ARG MPU_9250_SENSOR_CONF_ACC_RANGE #else -# define MPU_9250_SENSOR_ACC_RANGE_ARG MPU_9250_SENSOR_ACC_RANGE_2G +#define MPU_9250_SENSOR_ACC_RANGE_ARG MPU_9250_SENSOR_ACC_RANGE_2G #endif /*---------------------------------------------------------------------------*/ extern const struct sensors_sensor mpu_9250_sensor; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.c index 086c61165..885fefe88 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.c @@ -68,7 +68,7 @@ #if BOARD_SENSORS_ENABLE /*---------------------------------------------------------------------------*/ #ifndef Board_OPT3001_ADDR -# error "Board file doesn't define I2C address Board_OPT3001_ADDR" +#error "Board file doesn't define I2C address Board_OPT3001_ADDR" #endif /* Slave address */ #define OPT_3001_I2C_ADDRESS Board_OPT3001_ADDR @@ -160,16 +160,15 @@ static bool i2c_write_read(void *wbuf, size_t wcount, void *rbuf, size_t rcount) { I2C_Transaction i2c_transaction = { - .writeBuf = wbuf, - .writeCount = wcount, - .readBuf = rbuf, - .readCount = rcount, + .writeBuf = wbuf, + .writeCount = wcount, + .readBuf = rbuf, + .readCount = rcount, .slaveAddress = OPT_3001_I2C_ADDRESS, }; return I2C_transfer(i2c_handle, &i2c_transaction); } - /** * \brief Peform a write only I2C transaction. * \param wbuf Output buffer during the I2C transation. @@ -182,7 +181,6 @@ i2c_write(void *wbuf, size_t wcount) { return i2c_write_read(wbuf, wcount, NULL, 0); } - /** * \brief Peform a read only I2C transaction. * \param rbuf Input buffer during the I2C transation. @@ -305,7 +303,7 @@ value(int type) result_value = SWAP16(result_value); - uint32_t e = (result_value & 0x0FFF) >> 0; + uint32_t e = (result_value & 0x0FFF) >> 0; uint32_t m = (result_value & 0xF000) >> 12; uint32_t converted = m * 100 * (1 << e); diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.h index 7f4e132c5..221ea041f 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.h @@ -67,7 +67,7 @@ /*---------------------------------------------------------------------------*/ #if BOARD_SENSORS_ENABLE #if (TI_I2C_CONF_ENABLE == 0) || (TI_I2C_CONF_I2C0_ENABLE == 0) -# error "The OPT-3001 requires the I2C driver (TI_I2C_CONF_ENABLE = 1)" +#error "The OPT-3001 requires the I2C driver (TI_I2C_CONF_ENABLE = 1)" #endif #endif /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c index 92033c5a8..68bd4669a 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c @@ -69,13 +69,13 @@ /*---------------------------------------------------------------------------*/ /* Slave address */ #ifndef Board_TMP_ADDR -# error "Board file doesn't define I2C address Board_TMP_ADDR" +#error "Board file doesn't define I2C address Board_TMP_ADDR" #endif #define TMP_007_I2C_ADDRESS Board_TMP_ADDR /* Sensor Interrupt pin */ #ifndef Board_TMP_RDY -# error "Board file doesn't define interrupt pin Board_TMP_RDY" +#error "Board file doesn't define interrupt pin Board_TMP_RDY" #endif #define TMP_007_TMP_RDY Board_TMP_RDY /*---------------------------------------------------------------------------*/ @@ -116,16 +116,16 @@ static const PIN_Config pin_table[] = { PIN_TERMINATE }; -static PIN_State pin_state; +static PIN_State pin_state; static PIN_Handle pin_handle; static I2C_Handle i2c_handle; /*---------------------------------------------------------------------------*/ typedef struct { - TMP_007_TYPE type; + TMP_007_TYPE type; volatile TMP_007_STATUS status; - uint16_t local_tmp_latched; - uint16_t obj_tmp_latched; + uint16_t local_tmp_latched; + uint16_t obj_tmp_latched; } TMP_007_Object; static TMP_007_Object tmp_007; @@ -148,16 +148,15 @@ static bool i2c_write_read(void *wbuf, size_t wcount, void *rbuf, size_t rcount) { I2C_Transaction i2c_transaction = { - .writeBuf = wbuf, - .writeCount = wcount, - .readBuf = rbuf, - .readCount = rcount, + .writeBuf = wbuf, + .writeCount = wcount, + .readBuf = rbuf, + .readCount = rcount, .slaveAddress = TMP_007_I2C_ADDRESS, }; return I2C_transfer(i2c_handle, &i2c_transaction); } - /** * \brief Peform a write only I2C transaction. * \param wbuf Output buffer during the I2C transation. @@ -170,7 +169,6 @@ i2c_write(void *wbuf, size_t wcount) { return i2c_write_read(wbuf, wcount, NULL, 0); } - /** * \brief Peform a read only I2C transaction. * \param rbuf Input buffer during the I2C transation. @@ -301,16 +299,16 @@ read_data(uint16_t *local_tmp, uint16_t *obj_tmp) * from sensor. */ static void -convert(uint16_t* local_tmp, uint16_t* obj_tmp) +convert(uint16_t *local_tmp, uint16_t *obj_tmp) { uint32_t local = (uint32_t)*local_tmp; - uint32_t obj = (uint32_t)*obj_tmp; + uint32_t obj = (uint32_t)*obj_tmp; local = (local >> 2) * 3125 / 100; - obj = (obj >> 2) * 3125 / 100; + obj = (obj >> 2) * 3125 / 100; *local_tmp = (uint16_t)local; - *obj_tmp = (uint16_t)obj; + *obj_tmp = (uint16_t)obj; } /*---------------------------------------------------------------------------*/ /** @@ -322,7 +320,7 @@ static int value(int type) { uint16_t raw_local_tmp = 0, local_tmp = 0; - uint16_t raw_obj_tmp = 0, obj_tmp = 0; + uint16_t raw_obj_tmp = 0, obj_tmp = 0; if(tmp_007.status != TMP_007_STATUS_READY) { PRINTF("Sensor disabled or starting up (%d)\n", tmp_007.status); @@ -339,14 +337,14 @@ value(int type) } local_tmp = raw_local_tmp; - obj_tmp = raw_obj_tmp; + obj_tmp = raw_obj_tmp; convert(&local_tmp, &obj_tmp); PRINTF("TMP: %04X %04X o=%d a=%d\n", raw_local_tmp, raw_obj_tmp, - (int)(local_tmp), (int)(obj_tmp)); + (int)(local_tmp), (int)(obj_tmp)); tmp_007.local_tmp_latched = (int)(local_tmp); - tmp_007.obj_tmp_latched = (int)(obj_tmp); + tmp_007.obj_tmp_latched = (int)(obj_tmp); return 0; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.h index cb810e703..1c806abe8 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.h @@ -72,15 +72,16 @@ /*---------------------------------------------------------------------------*/ #if BOARD_SENSORS_ENABLE #if (TI_I2C_CONF_ENABLE == 0) || (TI_I2C_CONF_I2C0_ENABLE == 0) -# error "The BMP280 requires the I2C driver to be enabled (TI_I2C_CONF_ENABLE = 1)" +#error "The BMP280 requires the I2C driver to be enabled (TI_I2C_CONF_ENABLE = 1)" #endif #endif /*---------------------------------------------------------------------------*/ typedef enum { - TMP_007_TYPE_OBJECT = (1 << 0), + TMP_007_TYPE_OBJECT = (1 << 0), TMP_007_TYPE_AMBIENT = (1 << 1), - TMP_007_TYPE_ALL = TMP_007_TYPE_OBJECT - | TMP_007_TYPE_AMBIENT, + + TMP_007_TYPE_ALL = (TMP_007_TYPE_OBJECT | + TMP_007_TYPE_AMBIENT), } TMP_007_TYPE; /*---------------------------------------------------------------------------*/ typedef enum { From 3ac27dc7c9b6ab112f22081086bdcf27c20d0384 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Thu, 26 Jul 2018 08:26:02 +0200 Subject: [PATCH 301/485] Cleanup of global Makefiles --- Makefile.include | 18 +++++++++--------- arch/cpu/arm/Makefile.arm | 8 ++------ 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/Makefile.include b/Makefile.include index 7643455b5..27a65a0f6 100644 --- a/Makefile.include +++ b/Makefile.include @@ -39,16 +39,10 @@ ifdef CI endif endif -# Prevent Make from remaking any makefiles. This was particularly an -# issue when you had a Makefile with a suffix equal to that of $(TARGET), -# as it managed to match with the %.$(TARGET) rule, which in turn screwed -# everything up. -Makefile.%: ; - OBJECTDIR := obj_$(TARGET) -LOWERCASE := -abcdefghijklmnopqrstuvwxyz/ -UPPERCASE := _ABCDEFGHIJKLMNOPQRSTUVWXYZ_ +LOWERCASE = -abcdefghijklmnopqrstuvwxyz/ +UPPERCASE = _ABCDEFGHIJKLMNOPQRSTUVWXYZ_ TARGET_UPPERCASE := ${strip ${shell echo $(TARGET) | sed y!$(LOWERCASE)!$(UPPERCASE)!}} CFLAGS += -DCONTIKI=1 CFLAGS += -DCONTIKI_TARGET_$(TARGET_UPPERCASE)=1 @@ -270,7 +264,7 @@ CONTIKI_CPU_DIRS_CONCAT = ${addprefix $(CONTIKI_CPU)/, \ $(CONTIKI_CPU_DIRS)} CONTIKI_ARCH_DIRS = ${addprefix $(CONTIKI)/, arch} -SOURCEDIRS = $(CONTIKI) $(PROJECTDIRS) $(CONTIKI_TARGET_DIRS_CONCAT) \ +SOURCEDIRS = . $(PROJECTDIRS) $(CONTIKI_TARGET_DIRS_CONCAT) \ $(CONTIKI_ARCH_DIRS) $(CONTIKI_CPU_DIRS_CONCAT) \ $(CONTIKIDIRS) $(MODULEDIRS) $(EXTERNALDIRS) \ $(dir $(target_makefile)) @@ -494,6 +488,12 @@ endif # the match-anything rule below instead. %: %.c +# Prevent Make from remaking any makefiles. This was particularly an +# issue when you had a Makefile with a suffix equal to that of $(TARGET), +# as it managed to match with the %.$(TARGET) rule, which in turn screwed +# everything up. +Makefile.%: ; + ifeq ($(PLATFORM_ACTION),skip) # Skip this target. $(CONTIKI_PROJECT): diff --git a/arch/cpu/arm/Makefile.arm b/arch/cpu/arm/Makefile.arm index 2c1a4bf7b..9918fa053 100644 --- a/arch/cpu/arm/Makefile.arm +++ b/arch/cpu/arm/Makefile.arm @@ -1,6 +1,3 @@ -MAKEFILE := $(lastword $(MAKEFILE_LIST)) -BASE_DIR := $(realpath $(dir $(MAKEFILE))) - CC = arm-none-eabi-gcc CPP = arm-none-eabi-cpp LD = arm-none-eabi-gcc @@ -36,9 +33,8 @@ else endif ### Use CMSIS and the existing dbg-io from arch/cpu/arm/common -CONTIKI_ARM_DIRS += . -CONTIKI_ARM_DIRS += ../common/dbg-io -CONTIKI_CPU_DIRS += $(realpath $(addprefix $(BASE_DIR)/, $(CONTIKI_ARM_DIRS))) +CONTIKI_ARM_DIRS += . common/dbg-io +CONTIKI_CPU_DIRS += $(addprefix ../arm/, $(CONTIKI_ARM_DIRS)) ### CPU-dependent cleanup files CLEAN += *.elf *.bin *.lst *.hex *.i16hex From aaa9c43fe46b9534e1269950436073136344e2b6 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Thu, 26 Jul 2018 11:54:24 +0200 Subject: [PATCH 302/485] Don't rename cc26xx examples folder --- .../platform-specific/{srf06-cc26xx => cc26xx}/Makefile | 0 .../platform-specific/{srf06-cc26xx => cc26xx}/README.md | 0 .../{srf06-cc26xx => cc26xx}/ble-ipv6/Makefile | 0 .../{srf06-cc26xx => cc26xx}/ble-ipv6/README.md | 0 .../{srf06-cc26xx => cc26xx}/ble-ipv6/client.c | 0 .../{srf06-cc26xx => cc26xx}/ble-ipv6/project-conf.h | 0 .../{srf06-cc26xx => cc26xx}/cc26xx-demo.c | 6 +++--- .../{srf06-cc26xx => cc26xx}/cc26xx-web-demo/Makefile | 0 .../{srf06-cc26xx => cc26xx}/cc26xx-web-demo/README.md | 0 .../cc26xx-web-demo/cc26xx-web-demo.c | 0 .../cc26xx-web-demo/cc26xx-web-demo.h | 8 ++++---- .../cc26xx-web-demo/cetic-6lbr-client.c | 0 .../cc26xx-web-demo/coap-server.c | 0 .../cc26xx-web-demo/coap-server.h | 0 .../cc26xx-web-demo/httpd-simple.c | 0 .../cc26xx-web-demo/httpd-simple.h | 0 .../cc26xx-web-demo/mqtt-client.c | 0 .../cc26xx-web-demo/mqtt-client.h | 0 .../{srf06-cc26xx => cc26xx}/cc26xx-web-demo/net-uart.c | 0 .../{srf06-cc26xx => cc26xx}/cc26xx-web-demo/net-uart.h | 0 .../cc26xx-web-demo/project-conf.h | 0 .../cc26xx-web-demo/resources/res-ble-advd.c | 0 .../cc26xx-web-demo/resources/res-device.c | 0 .../cc26xx-web-demo/resources/res-leds.c | 0 .../cc26xx-web-demo/resources/res-net.c | 0 .../cc26xx-web-demo/resources/res-sensors.c | 0 .../cc26xx-web-demo/resources/res-toggle-leds.c | 0 .../{srf06-cc26xx => cc26xx}/project-conf.h | 0 .../{srf06-cc26xx => cc26xx}/very-sleepy-demo/Makefile | 0 .../{srf06-cc26xx => cc26xx}/very-sleepy-demo/README.md | 0 .../very-sleepy-demo/project-conf.h | 0 .../very-sleepy-demo/very-sleepy-demo.c | 2 +- 32 files changed, 8 insertions(+), 8 deletions(-) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/Makefile (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/README.md (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/ble-ipv6/Makefile (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/ble-ipv6/README.md (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/ble-ipv6/client.c (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/ble-ipv6/project-conf.h (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/cc26xx-demo.c (98%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/cc26xx-web-demo/Makefile (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/cc26xx-web-demo/README.md (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/cc26xx-web-demo/cc26xx-web-demo.c (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/cc26xx-web-demo/cc26xx-web-demo.h (96%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/cc26xx-web-demo/cetic-6lbr-client.c (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/cc26xx-web-demo/coap-server.c (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/cc26xx-web-demo/coap-server.h (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/cc26xx-web-demo/httpd-simple.c (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/cc26xx-web-demo/httpd-simple.h (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/cc26xx-web-demo/mqtt-client.c (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/cc26xx-web-demo/mqtt-client.h (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/cc26xx-web-demo/net-uart.c (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/cc26xx-web-demo/net-uart.h (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/cc26xx-web-demo/project-conf.h (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/cc26xx-web-demo/resources/res-ble-advd.c (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/cc26xx-web-demo/resources/res-device.c (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/cc26xx-web-demo/resources/res-leds.c (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/cc26xx-web-demo/resources/res-net.c (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/cc26xx-web-demo/resources/res-sensors.c (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/cc26xx-web-demo/resources/res-toggle-leds.c (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/project-conf.h (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/very-sleepy-demo/Makefile (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/very-sleepy-demo/README.md (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/very-sleepy-demo/project-conf.h (100%) rename examples/platform-specific/{srf06-cc26xx => cc26xx}/very-sleepy-demo/very-sleepy-demo.c (99%) diff --git a/examples/platform-specific/srf06-cc26xx/Makefile b/examples/platform-specific/cc26xx/Makefile similarity index 100% rename from examples/platform-specific/srf06-cc26xx/Makefile rename to examples/platform-specific/cc26xx/Makefile diff --git a/examples/platform-specific/srf06-cc26xx/README.md b/examples/platform-specific/cc26xx/README.md similarity index 100% rename from examples/platform-specific/srf06-cc26xx/README.md rename to examples/platform-specific/cc26xx/README.md diff --git a/examples/platform-specific/srf06-cc26xx/ble-ipv6/Makefile b/examples/platform-specific/cc26xx/ble-ipv6/Makefile similarity index 100% rename from examples/platform-specific/srf06-cc26xx/ble-ipv6/Makefile rename to examples/platform-specific/cc26xx/ble-ipv6/Makefile diff --git a/examples/platform-specific/srf06-cc26xx/ble-ipv6/README.md b/examples/platform-specific/cc26xx/ble-ipv6/README.md similarity index 100% rename from examples/platform-specific/srf06-cc26xx/ble-ipv6/README.md rename to examples/platform-specific/cc26xx/ble-ipv6/README.md diff --git a/examples/platform-specific/srf06-cc26xx/ble-ipv6/client.c b/examples/platform-specific/cc26xx/ble-ipv6/client.c similarity index 100% rename from examples/platform-specific/srf06-cc26xx/ble-ipv6/client.c rename to examples/platform-specific/cc26xx/ble-ipv6/client.c diff --git a/examples/platform-specific/srf06-cc26xx/ble-ipv6/project-conf.h b/examples/platform-specific/cc26xx/ble-ipv6/project-conf.h similarity index 100% rename from examples/platform-specific/srf06-cc26xx/ble-ipv6/project-conf.h rename to examples/platform-specific/cc26xx/ble-ipv6/project-conf.h diff --git a/examples/platform-specific/srf06-cc26xx/cc26xx-demo.c b/examples/platform-specific/cc26xx/cc26xx-demo.c similarity index 98% rename from examples/platform-specific/srf06-cc26xx/cc26xx-demo.c rename to examples/platform-specific/cc26xx/cc26xx-demo.c index acc3ca823..8c90905af 100644 --- a/examples/platform-specific/srf06-cc26xx/cc26xx-demo.c +++ b/examples/platform-specific/cc26xx/cc26xx-demo.c @@ -98,11 +98,11 @@ #define CC26XX_DEMO_LEDS_BUTTON LEDS_RED #define CC26XX_DEMO_LEDS_REBOOT LEDS_ALL /*---------------------------------------------------------------------------*/ -#define CC26XX_DEMO_TRIGGER_1 BUTTON_HAL_ID_KEY_LEFT -#define CC26XX_DEMO_TRIGGER_2 BUTTON_HAL_ID_KEY_RIGHT +#define CC26XX_DEMO_TRIGGER_1 BOARD_BUTTON_HAL_INDEX_KEY_LEFT +#define CC26XX_DEMO_TRIGGER_2 BOARD_BUTTON_HAL_INDEX_KEY_RIGHT #if BOARD_SENSORTAG -#define CC26XX_DEMO_TRIGGER_3 BUTTON_HAL_ID_REED_RELAY +#define CC26XX_DEMO_TRIGGER_3 BOARD_BUTTON_HAL_INDEX_REED_RELAY #endif /*---------------------------------------------------------------------------*/ static struct etimer et; diff --git a/examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/Makefile b/examples/platform-specific/cc26xx/cc26xx-web-demo/Makefile similarity index 100% rename from examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/Makefile rename to examples/platform-specific/cc26xx/cc26xx-web-demo/Makefile diff --git a/examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/README.md b/examples/platform-specific/cc26xx/cc26xx-web-demo/README.md similarity index 100% rename from examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/README.md rename to examples/platform-specific/cc26xx/cc26xx-web-demo/README.md diff --git a/examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/cc26xx-web-demo.c b/examples/platform-specific/cc26xx/cc26xx-web-demo/cc26xx-web-demo.c similarity index 100% rename from examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/cc26xx-web-demo.c rename to examples/platform-specific/cc26xx/cc26xx-web-demo/cc26xx-web-demo.c diff --git a/examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/cc26xx-web-demo.h b/examples/platform-specific/cc26xx/cc26xx-web-demo/cc26xx-web-demo.h similarity index 96% rename from examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/cc26xx-web-demo.h rename to examples/platform-specific/cc26xx/cc26xx-web-demo/cc26xx-web-demo.h index 1840c31b1..0761725c7 100644 --- a/examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/cc26xx-web-demo.h +++ b/examples/platform-specific/cc26xx/cc26xx-web-demo/cc26xx-web-demo.h @@ -98,18 +98,18 @@ /*---------------------------------------------------------------------------*/ /* User configuration */ /* Take a sensor reading on button press */ -#define CC26XX_WEB_DEMO_SENSOR_READING_TRIGGER BUTTON_HAL_ID_KEY_LEFT +#define CC26XX_WEB_DEMO_SENSOR_READING_TRIGGER BOARD_BUTTON_HAL_INDEX_KEY_LEFT /* Payload length of ICMPv6 echo requests used to measure RSSI with def rt */ #define CC26XX_WEB_DEMO_ECHO_REQ_PAYLOAD_LEN 20 #if BOARD_SENSORTAG /* Force an MQTT publish on sensor event */ -#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BUTTON_HAL_ID_REED_RELAY +#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BOARD_BUTTON_HAL_INDEX_REED_RELAY #elif BOARD_LAUNCHPAD -#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BUTTON_HAL_ID_KEY_LEFT +#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BOARD_BUTTON_HAL_INDEX_KEY_LEFT #else -#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BUTTON_HAL_ID_KEY_DOWN +#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BOARD_BUTTON_HAL_INDEX_KEY_DOWN #endif #define CC26XX_WEB_DEMO_STATUS_LED LEDS_GREEN diff --git a/examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/cetic-6lbr-client.c b/examples/platform-specific/cc26xx/cc26xx-web-demo/cetic-6lbr-client.c similarity index 100% rename from examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/cetic-6lbr-client.c rename to examples/platform-specific/cc26xx/cc26xx-web-demo/cetic-6lbr-client.c diff --git a/examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/coap-server.c b/examples/platform-specific/cc26xx/cc26xx-web-demo/coap-server.c similarity index 100% rename from examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/coap-server.c rename to examples/platform-specific/cc26xx/cc26xx-web-demo/coap-server.c diff --git a/examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/coap-server.h b/examples/platform-specific/cc26xx/cc26xx-web-demo/coap-server.h similarity index 100% rename from examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/coap-server.h rename to examples/platform-specific/cc26xx/cc26xx-web-demo/coap-server.h diff --git a/examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/httpd-simple.c b/examples/platform-specific/cc26xx/cc26xx-web-demo/httpd-simple.c similarity index 100% rename from examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/httpd-simple.c rename to examples/platform-specific/cc26xx/cc26xx-web-demo/httpd-simple.c diff --git a/examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/httpd-simple.h b/examples/platform-specific/cc26xx/cc26xx-web-demo/httpd-simple.h similarity index 100% rename from examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/httpd-simple.h rename to examples/platform-specific/cc26xx/cc26xx-web-demo/httpd-simple.h diff --git a/examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/mqtt-client.c b/examples/platform-specific/cc26xx/cc26xx-web-demo/mqtt-client.c similarity index 100% rename from examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/mqtt-client.c rename to examples/platform-specific/cc26xx/cc26xx-web-demo/mqtt-client.c diff --git a/examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/mqtt-client.h b/examples/platform-specific/cc26xx/cc26xx-web-demo/mqtt-client.h similarity index 100% rename from examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/mqtt-client.h rename to examples/platform-specific/cc26xx/cc26xx-web-demo/mqtt-client.h diff --git a/examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/net-uart.c b/examples/platform-specific/cc26xx/cc26xx-web-demo/net-uart.c similarity index 100% rename from examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/net-uart.c rename to examples/platform-specific/cc26xx/cc26xx-web-demo/net-uart.c diff --git a/examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/net-uart.h b/examples/platform-specific/cc26xx/cc26xx-web-demo/net-uart.h similarity index 100% rename from examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/net-uart.h rename to examples/platform-specific/cc26xx/cc26xx-web-demo/net-uart.h diff --git a/examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/project-conf.h b/examples/platform-specific/cc26xx/cc26xx-web-demo/project-conf.h similarity index 100% rename from examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/project-conf.h rename to examples/platform-specific/cc26xx/cc26xx-web-demo/project-conf.h diff --git a/examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/resources/res-ble-advd.c b/examples/platform-specific/cc26xx/cc26xx-web-demo/resources/res-ble-advd.c similarity index 100% rename from examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/resources/res-ble-advd.c rename to examples/platform-specific/cc26xx/cc26xx-web-demo/resources/res-ble-advd.c diff --git a/examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/resources/res-device.c b/examples/platform-specific/cc26xx/cc26xx-web-demo/resources/res-device.c similarity index 100% rename from examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/resources/res-device.c rename to examples/platform-specific/cc26xx/cc26xx-web-demo/resources/res-device.c diff --git a/examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/resources/res-leds.c b/examples/platform-specific/cc26xx/cc26xx-web-demo/resources/res-leds.c similarity index 100% rename from examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/resources/res-leds.c rename to examples/platform-specific/cc26xx/cc26xx-web-demo/resources/res-leds.c diff --git a/examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/resources/res-net.c b/examples/platform-specific/cc26xx/cc26xx-web-demo/resources/res-net.c similarity index 100% rename from examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/resources/res-net.c rename to examples/platform-specific/cc26xx/cc26xx-web-demo/resources/res-net.c diff --git a/examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/resources/res-sensors.c b/examples/platform-specific/cc26xx/cc26xx-web-demo/resources/res-sensors.c similarity index 100% rename from examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/resources/res-sensors.c rename to examples/platform-specific/cc26xx/cc26xx-web-demo/resources/res-sensors.c diff --git a/examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/resources/res-toggle-leds.c b/examples/platform-specific/cc26xx/cc26xx-web-demo/resources/res-toggle-leds.c similarity index 100% rename from examples/platform-specific/srf06-cc26xx/cc26xx-web-demo/resources/res-toggle-leds.c rename to examples/platform-specific/cc26xx/cc26xx-web-demo/resources/res-toggle-leds.c diff --git a/examples/platform-specific/srf06-cc26xx/project-conf.h b/examples/platform-specific/cc26xx/project-conf.h similarity index 100% rename from examples/platform-specific/srf06-cc26xx/project-conf.h rename to examples/platform-specific/cc26xx/project-conf.h diff --git a/examples/platform-specific/srf06-cc26xx/very-sleepy-demo/Makefile b/examples/platform-specific/cc26xx/very-sleepy-demo/Makefile similarity index 100% rename from examples/platform-specific/srf06-cc26xx/very-sleepy-demo/Makefile rename to examples/platform-specific/cc26xx/very-sleepy-demo/Makefile diff --git a/examples/platform-specific/srf06-cc26xx/very-sleepy-demo/README.md b/examples/platform-specific/cc26xx/very-sleepy-demo/README.md similarity index 100% rename from examples/platform-specific/srf06-cc26xx/very-sleepy-demo/README.md rename to examples/platform-specific/cc26xx/very-sleepy-demo/README.md diff --git a/examples/platform-specific/srf06-cc26xx/very-sleepy-demo/project-conf.h b/examples/platform-specific/cc26xx/very-sleepy-demo/project-conf.h similarity index 100% rename from examples/platform-specific/srf06-cc26xx/very-sleepy-demo/project-conf.h rename to examples/platform-specific/cc26xx/very-sleepy-demo/project-conf.h diff --git a/examples/platform-specific/srf06-cc26xx/very-sleepy-demo/very-sleepy-demo.c b/examples/platform-specific/cc26xx/very-sleepy-demo/very-sleepy-demo.c similarity index 99% rename from examples/platform-specific/srf06-cc26xx/very-sleepy-demo/very-sleepy-demo.c rename to examples/platform-specific/cc26xx/very-sleepy-demo/very-sleepy-demo.c index d707f3cd1..ebd55712b 100644 --- a/examples/platform-specific/srf06-cc26xx/very-sleepy-demo/very-sleepy-demo.c +++ b/examples/platform-specific/cc26xx/very-sleepy-demo/very-sleepy-demo.c @@ -63,7 +63,7 @@ #define VERY_SLEEPY_MODE_OFF 0 #define VERY_SLEEPY_MODE_ON 1 /*---------------------------------------------------------------------------*/ -#define BUTTON_TRIGGER BUTTON_HAL_ID_KEY_LEFT +#define BUTTON_TRIGGER BOARD_BUTTON_HAL_INDEX_KEY_LEFT /*---------------------------------------------------------------------------*/ #define MAC_CAN_BE_TURNED_OFF 0 #define MAC_MUST_STAY_ON 1 From 7b221dd09fdb01d730c4cc99914b27d0d06a1b40 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Thu, 26 Jul 2018 11:54:57 +0200 Subject: [PATCH 303/485] Added missing standard header --- os/net/app-layer/coap/coap-callback-api.c | 1 + os/net/app-layer/coap/coap.c | 1 + 2 files changed, 2 insertions(+) diff --git a/os/net/app-layer/coap/coap-callback-api.c b/os/net/app-layer/coap/coap-callback-api.c index 41a2ef846..74585ccb3 100644 --- a/os/net/app-layer/coap/coap-callback-api.c +++ b/os/net/app-layer/coap/coap-callback-api.c @@ -48,6 +48,7 @@ #include "sys/cc.h" #include #include +#include /* Log configuration */ #include "coap-log.h" diff --git a/os/net/app-layer/coap/coap.c b/os/net/app-layer/coap/coap.c index c28e2d8b5..8bc2f90f9 100644 --- a/os/net/app-layer/coap/coap.c +++ b/os/net/app-layer/coap/coap.c @@ -47,6 +47,7 @@ #include #include +#include #include "sys/cc.h" #include "coap.h" From 45287759c2ace711c0dc7a9cf0115a23c61049ad Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Thu, 26 Jul 2018 11:55:53 +0200 Subject: [PATCH 304/485] Removed change --- arch/cpu/arm/Makefile.arm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/cpu/arm/Makefile.arm b/arch/cpu/arm/Makefile.arm index 9918fa053..ab3c5116f 100644 --- a/arch/cpu/arm/Makefile.arm +++ b/arch/cpu/arm/Makefile.arm @@ -29,7 +29,7 @@ SMALL ?= 1 ifeq ($(SMALL),1) CFLAGS += -Os else - CFLAGS += -O0 + CFLAGS += -O2 endif ### Use CMSIS and the existing dbg-io from arch/cpu/arm/common From 844f01de350c3b006f97b61c75ca9d4b3a908e11 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Thu, 26 Jul 2018 11:56:27 +0200 Subject: [PATCH 305/485] Fixed compile errors and made examples compile --- arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h | 6 +- .../rf-settings/cc26x0/ble-settings.h | 2 +- .../rf-settings/cc26x2/ble-settings.c | 44 ++- .../rf-settings/cc26x2/ble-settings.h | 16 +- arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c | 100 +++-- arch/cpu/cc13xx-cc26xx/rf/ble-beacond.h | 13 +- arch/cpu/cc13xx-cc26xx/rf/settings.h | 6 +- arch/dev/ext-flash/ext-flash.c | 2 +- .../simplelink/cc13xx-cc26xx/batmon-sensor.c | 4 +- .../simplelink/cc13xx-cc26xx/batmon-sensor.h | 2 + .../cc13xx-cc26xx/launchpad/board-conf.h | 16 +- .../cc13xx-cc26xx/sensortag/board-conf.h | 13 +- .../cc13xx-cc26xx/start-demo/Makefile | 4 +- .../cc13xx-cc26xx/very-sleepy-demo/Makefile | 8 +- .../very-sleepy-demo/project-conf.h | 28 +- .../very-sleepy-demo/very-sleepy-demo.c | 14 +- .../very-sleepy-demo.simplelink | Bin 0 -> 592244 bytes .../cc13xx-cc26xx/web-demo/Makefile | 10 +- .../web-demo/cetic-6lbr-client.c | 14 +- .../cc13xx-cc26xx/web-demo/coap-server.c | 26 +- .../cc13xx-cc26xx/web-demo/coap-server.h | 4 +- .../cc13xx-cc26xx/web-demo/httpd-simple.c | 72 ++-- .../cc13xx-cc26xx/web-demo/httpd-simple.h | 5 +- .../cc13xx-cc26xx/web-demo/mqtt-client.c | 68 ++-- .../cc13xx-cc26xx/web-demo/mqtt-client.h | 4 +- .../cc13xx-cc26xx/web-demo/net-uart.c | 46 +-- .../cc13xx-cc26xx/web-demo/net-uart.h | 2 +- .../cc13xx-cc26xx/web-demo/project-conf.h | 27 +- .../web-demo/resources/res-ble-advd.c | 11 +- .../web-demo/resources/res-device.c | 63 ++- .../web-demo/resources/res-leds.c | 8 +- .../web-demo/resources/res-net.c | 15 +- .../web-demo/resources/res-sensors.c | 51 +-- .../web-demo/resources/res-toggle-leds.c | 6 +- .../cc13xx-cc26xx/web-demo/web-demo.c | 372 +++++++++--------- .../cc13xx-cc26xx/web-demo/web-demo.h | 171 ++++---- .../web-demo/web-demo.simplelink | Bin 0 -> 749528 bytes 37 files changed, 668 insertions(+), 585 deletions(-) create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/very-sleepy-demo.simplelink create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.simplelink diff --git a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h index 256032d2d..68289d4e4 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h +++ b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h @@ -350,7 +350,7 @@ * \brief Enable or disable SPI driver. */ #ifndef TI_SPI_CONF_ENABLE -#define TI_SPI_CONF_ENABLE 0 +#define TI_SPI_CONF_ENABLE 1 #endif /** @@ -371,7 +371,7 @@ * \brief Enable or disable I2C driver. */ #ifndef TI_I2C_CONF_ENABLE -#define TI_I2C_CONF_ENABLE 0 +#define TI_I2C_CONF_ENABLE 1 #endif /** @@ -439,7 +439,7 @@ #elif (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X2_CC26X2) /* CC13x0/CC26x0 only has two SPI interface: SPI0 and SPI1. */ -#define SPI_CONF_CONTROLLER_COUNT (SPI0_ENABLED + SPI1_IS_ENABLED) +#define SPI_CONF_CONTROLLER_COUNT (SPI0_IS_ENABLED + SPI1_IS_ENABLED) #endif /* DeviceFamily_PARENT */ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.h index 5776fc407..c89304105 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.h @@ -43,7 +43,7 @@ extern RF_Mode rf_ble_mode; /*---------------------------------------------------------------------------*/ /* RF Core API commands */ extern rfc_CMD_RADIO_SETUP_t rf_ble_cmd_radio_setup; -extern rfc_CMD_FS_t rf_ble_cmd_fs; +extern rfc_bleAdvPar_t rf_ble_adv_par; extern rfc_CMD_BLE_ADV_NC_t rf_ble_cmd_ble_adv_nc; /*---------------------------------------------------------------------------*/ /* RF Core API Overrides */ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.c index ba322e99b..8ee2b2684 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.c @@ -122,7 +122,7 @@ uint32_t rf_ble_overrides_coded[] CC_ALIGN(4) = }; /*---------------------------------------------------------------------------*/ /* CMD_BLE5_RADIO_SETUP: Bluetooth 5 Radio Setup Command for all PHYs */ -rfc_CMD_BLE5_RADIO_SETUP_t RF_cmdBle5RadioSetup = +rfc_CMD_BLE5_RADIO_SETUP_t rf_ble_cmd_radio_setup = { .commandNo = CMD_BLE5_RADIO_SETUP, .status = IDLE, @@ -148,8 +148,8 @@ rfc_CMD_BLE5_RADIO_SETUP_t RF_cmdBle5RadioSetup = .pRegOverrideCoded = rf_ble_overrides_coded, }; /*---------------------------------------------------------------------------*/ -/* Structure for CMD_BLE5_ADV_AUX.pParams */ -rfc_ble5AdvAuxPar_t rf_ble5_adv_aux_par = +/* Structure for CMD_BLE5_ADV_NC.pParams */ +rfc_bleAdvPar_t rf_ble_adv_par = { .pRxQ = 0, .rxConfig.bAutoFlushIgnored = 0x0, @@ -162,32 +162,36 @@ rfc_ble5AdvAuxPar_t rf_ble5_adv_aux_par = .rxConfig.bAppendTimestamp = 0x0, .advConfig.advFilterPolicy = 0x0, .advConfig.deviceAddrType = 0x0, - .advConfig.targetAddrType = 0x0, + .advConfig.peerAddrType = 0x0, .advConfig.bStrictLenFilter = 0x0, - .advConfig.bDirected = 0x0, - .advConfig.privIgnMode = 0x0, .advConfig.rpaMode = 0x0, - .__dummy0 = 0x00, - .auxPtrTargetType = 0x00, - .auxPtrTargetTime = 0x00000000, - .pAdvPkt = 0, - .pRspPkt = 0, + .advLen = 0x18, + .scanRspLen = 0x00, + .pAdvData = 0, + .pScanRspData = 0, .pDeviceAddress = 0, .pWhiteList = 0, + .__dummy0 = 0x0000, + .__dummy1 = 0x00, + .endTrigger.triggerType = TRIG_NEVER, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, }; /*---------------------------------------------------------------------------*/ -/* CMD_BLE5_ADV_AUX: Bluetooth 5 Secondary Channel Advertiser Command */ -rfc_CMD_BLE5_ADV_AUX_t rf_cmd_ble5_adv_aux = +/* CMD_BLE5_ADV_NC: Bluetooth 5 Non-Connectable Advertiser Command */ +rfc_CMD_BLE5_ADV_NC_t rf_ble_cmd_ble_adv_nc = { - .commandNo = CMD_BLE5_ADV_AUX, - .status = IDLE, - .pNextOp = 0, + .commandNo = 0x182D, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, + .startTrigger.triggerType = 0x0, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, + .condition.rule = 0x1, .condition.nSkip = 0x0, .channel = 0x8C, .whitening.init = 0x51, @@ -196,8 +200,8 @@ rfc_CMD_BLE5_ADV_AUX_t rf_cmd_ble5_adv_aux = .phyMode.coding = 0x0, .rangeDelay = 0x00, .txPower = 0x0000, - .pParams = &rf_ble5_adv_aux_par, - .pOutput = 0, + .pParams = &rf_ble_adv_par, + .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx .tx20Power = 0x00000000, }; /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.h index a41902956..2e6defa71 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.h @@ -39,18 +39,18 @@ #include /*---------------------------------------------------------------------------*/ /* TI-RTOS RF Mode Object */ -extern RF_Mode rf_ble_mode; +extern RF_Mode rf_ble_mode; /*---------------------------------------------------------------------------*/ /* RF Core API commands */ -extern rfc_CMD_BLE5_RADIO_SETUP_t rf_cmd_ble5_radio_setup; -extern rfc_ble5AdvAuxPar_t rf_ble5_adv_aux_par; -extern rfc_CMD_BLE5_ADV_AUX_t rf_cmd_ble5_adv_aux; +extern rfc_CMD_BLE5_RADIO_SETUP_t rf_ble_cmd_radio_setup; +extern rfc_bleAdvPar_t rf_ble_adv_par; +extern rfc_CMD_BLE5_ADV_NC_t rf_ble_cmd_ble_adv_nc; /*---------------------------------------------------------------------------*/ /* RF Core API Overrides */ -extern uint32_t rf_ble_overrides_common[]; -extern uint32_t rf_ble_overrides_1mbps[]; -extern uint32_t rf_ble_overrides_2mbps[]; -extern uint32_t rf_ble_overrides_coded[]; +extern uint32_t rf_ble_overrides_common[]; +extern uint32_t rf_ble_overrides_1mbps[]; +extern uint32_t rf_ble_overrides_2mbps[]; +extern uint32_t rf_ble_overrides_coded[]; /*---------------------------------------------------------------------------*/ #endif /* BLE_SETTINGS_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c b/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c index 79c0f4e62..383d168be 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c +++ b/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c @@ -52,9 +52,10 @@ #include /*---------------------------------------------------------------------------*/ -#include "rf/rf.h" +#include "rf/sched.h" #include "rf/ble-addr.h" #include "rf/ble-beacond.h" +#include "rf/tx-power.h" #include "rf/settings.h" /*---------------------------------------------------------------------------*/ #include @@ -75,9 +76,9 @@ typedef enum { BLE_ADV_CHANNEL_38 = (1 << 1), BLE_ADV_CHANNEL_39 = (1 << 2), - BLE_ADV_CHANNEL_MASK = (BLE_ADV_CHANNEL_37 | - BLE_ADV_CHANNEL_38 | - BLE_ADV_CHANNEL_39), + BLE_ADV_CHANNEL_ALL = (BLE_ADV_CHANNEL_37 | + BLE_ADV_CHANNEL_38 | + BLE_ADV_CHANNEL_39), } ble_adv_channel_t; #define BLE_ADV_CHANNEL_MIN 37 @@ -133,9 +134,9 @@ rf_ble_beacond_init(void) /* Should immediately turn off radio if possible */ rf_params.nInactivityTimeout = 0; - ble_beacond.handle = ble_open(&rf_params); + ble_beacond.rf_handle = ble_open(&rf_params); - if(ble_beacond.handle == NULL) { + if(ble_beacond.rf_handle == NULL) { return RF_BLE_BEACOND_ERROR; } @@ -143,28 +144,39 @@ rf_ble_beacond_init(void) } /*---------------------------------------------------------------------------*/ rf_ble_beacond_result_t -rf_ble_beacond_start(clock_time_t interval, const char *name) +rf_ble_beacond_config(clock_time_t interval, const char *name) { - if(interval == 0) { - return RF_BLE_BEACOND_ERROR; + rf_ble_beacond_result_t res; + + res = RF_BLE_BEACOND_ERROR; + + if(interval > 0) { + ble_beacond.ble_adv_interval = interval; + + res = RF_BLE_BEACOND_OK; } - if(name == NULL) { - return RF_BLE_BEACOND_ERROR; + if(name != NULL) { + const size_t name_len = strlen(name); + + if((name_len == 0) || (name_len >= BLE_ADV_NAME_BUF_LEN)) { + ble_beacond.adv_name_len = name_len; + memcpy(ble_beacond.adv_name, name, name_len); + + res = RF_BLE_BEACOND_OK; + } } - ble_beacond.ble_adv_interval = interval; - - const size_t name_len = strlen(name); - - if((name_len == 0) || - (name_len >= BLE_ADV_NAME_BUF_LEN)) { - return RF_BLE_BEACOND_ERROR; + return res; +} +/*---------------------------------------------------------------------------*/ +rf_ble_beacond_result_t +rf_ble_beacond_start(void) +{ + if(ble_beacond.is_active) { + return RF_BLE_BEACOND_OK; } - ble_beacond.adv_name_len = name_len; - memcpy(ble_beacond.adv_name, name, name_len); - ble_beacond.is_active = true; process_start(&ble_beacond_process, NULL); @@ -175,6 +187,10 @@ rf_ble_beacond_start(clock_time_t interval, const char *name) rf_ble_beacond_result_t rf_ble_beacond_stop(void) { + if(!ble_beacond.is_active) { + return RF_BLE_BEACOND_OK; + } + ble_beacond.is_active = false; process_exit(&ble_beacond_process); @@ -197,7 +213,7 @@ rf_ble_set_tx_power(int8_t dbm) return RADIO_RESULT_INVALID_VALUE; } - res = rf_set_tx_power(ble_beacond.rf_handle, TX_POWER_TABLE, dbm); + res = rf_set_tx_power(ble_beacond.rf_handle, ble_tx_power_table, dbm); return (res == RF_RESULT_OK) ? RF_BLE_BEACOND_OK @@ -210,7 +226,7 @@ rf_ble_get_tx_power(void) rf_result_t res; int8_t dbm; - res = rf_get_tx_power(ble_beacond.rf_handle, TX_POWER_TABLE, &dbm); + res = rf_get_tx_power(ble_beacond.rf_handle, ble_tx_power_table, &dbm); if(res != RF_RESULT_OK) { return RF_TxPowerTable_INVALID_DBM; @@ -254,8 +270,8 @@ PROCESS_THREAD(ble_beacond_process, ev, data) PROCESS_BEGIN(); while(1) { - etimer_set(&beacond_config.ble_adv_et, beacond_config.ble_adv_interval); - PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&beacond_config.ble_adv_et) || + etimer_set(&ble_beacond.ble_adv_et, ble_beacond.ble_adv_interval); + PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&ble_beacond.ble_adv_et) || (ev == PROCESS_EVENT_EXIT)); if(ev == PROCESS_EVENT_EXIT) { @@ -266,25 +282,25 @@ PROCESS_THREAD(ble_beacond_process, ev, data) len = 0; /* Device info */ - beacond_config.tx_buf[len++] = (uint8_t)0x02; /* 2 bytes */ - beacond_config.tx_buf[len++] = (uint8_t)BLE_ADV_TYPE_DEVINFO; - beacond_config.tx_buf[len++] = (uint8_t)0x1A; /* LE general discoverable + BR/EDR */ - beacond_config.tx_buf[len++] = (uint8_t)beacond_config.adv_name_len; - beacond_config.tx_buf[len++] = (uint8_t)BLE_ADV_TYPE_NAME; + ble_beacond.tx_buf[len++] = (uint8_t)0x02; /* 2 bytes */ + ble_beacond.tx_buf[len++] = (uint8_t)BLE_ADV_TYPE_DEVINFO; + ble_beacond.tx_buf[len++] = (uint8_t)0x1A; /* LE general discoverable + BR/EDR */ + ble_beacond.tx_buf[len++] = (uint8_t)ble_beacond.adv_name_len; + ble_beacond.tx_buf[len++] = (uint8_t)BLE_ADV_TYPE_NAME; - memcpy(beacond_config.tx_buf + len, beacond_config.adv_name, beacond_config.adv_name_len); - len += beacond_config.adv_name_len; + memcpy(ble_beacond.tx_buf + len, ble_beacond.adv_name, ble_beacond.adv_name_len); + len += ble_beacond.adv_name_len; /* * Send BLE_ADV_MESSAGES beacon bursts. Each burst on all three * channels, with a BLE_ADV_DUTY_CYCLE interval between bursts */ - ble_beacon_burst(BLE_ADV_CHANNEL_ALL, beacond_config.tx_buf, len); + ble_beacon_burst(BLE_ADV_CHANNEL_ALL, ble_beacond.tx_buf, len); for(i = 1; i < BLE_ADV_MESSAGES; ++i) { - etimer_set(&beacond_config.ble_adv_et, BLE_ADV_DUTY_CYCLE); - PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&ble_adv_et)); + etimer_set(&ble_beacond.ble_adv_et, BLE_ADV_DUTY_CYCLE); + PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&ble_beacond.ble_adv_et)); - ble_beacon_burst(BLE_ADV_CHANNEL_ALL, beacond_config.tx_buf, len); + ble_beacon_burst(BLE_ADV_CHANNEL_ALL, ble_beacond.tx_buf, len); } } PROCESS_END(); @@ -299,10 +315,19 @@ rf_ble_beacond_init(void) } /*---------------------------------------------------------------------------*/ rf_ble_beacond_result_t -rf_ble_beacond_start(clock_time_t interval, const char *name) +rf_ble_beacond_config(clock_time_t interval, const char *name) +{ + (void)interval; + (void)name; + return RF_BLE_BEACOND_DISABLED; +} +/*---------------------------------------------------------------------------*/ +rf_ble_beacond_result_t +rf_ble_beacond_start(void) { return RF_BLE_BEACOND_DISABLED; } + /*---------------------------------------------------------------------------*/ rf_ble_beacond_result_t rf_ble_beacond_stop(void) @@ -319,6 +344,7 @@ rf_ble_is_active(void) rf_ble_beacond_result_t rf_ble_set_tx_power(int8_t power) { + (void)power; return RF_BLE_BEACOND_DISABLED; } /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.h b/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.h index 87e2ccc74..c273ad1c1 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.h +++ b/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.h @@ -65,6 +65,17 @@ typedef enum { */ rf_ble_beacond_result_t rf_ble_beacond_init(void); +/** + * \brief Set the device name to use with the BLE advertisement/beacon daemon + * \param interval The interval (ticks) between two consecutive beacon bursts + * \param name The device name to advertise + * + * If name is NULL it will be ignored. If interval==0 it will be ignored. Thus, + * this function can be used to configure a single parameter at a time if so + * desired. + */ +rf_ble_beacond_result_t rf_ble_beacond_config(clock_time_t interval, const char *name); + /** * \brief Start the BLE advertisement/beacon daemon * \return RF_CORE_CMD_OK: Success, RF_CORE_CMD_ERROR: Failure @@ -73,7 +84,7 @@ rf_ble_beacond_result_t rf_ble_beacond_init(void); * calling rf_ble_beacond_config(). Otherwise, this function will return an * error. */ -rf_ble_beacond_result_t rf_ble_beacond_start(clock_time_t interval, const char *name); +rf_ble_beacond_result_t rf_ble_beacond_start(void); /** * \brief Stop the BLE advertisement/beacon daemon diff --git a/arch/cpu/cc13xx-cc26xx/rf/settings.h b/arch/cpu/cc13xx-cc26xx/rf/settings.h index 0f4da3376..174114bfb 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf/settings.h @@ -95,9 +95,9 @@ #elif (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X2_CC26X2) #define ble_mode rf_ble_mode -#define ble_cmd_radio_setup rf_cmd_ble5_radio_setup -#define ble_adv_par rf_ble5_adv_aux_par -#define ble_cmd_beacon rf_cmd_ble5_adv_aux +#define ble_cmd_radio_setup rf_ble_cmd_radio_setup +#define ble_adv_par rf_ble_adv_par +#define ble_cmd_beacon rf_ble_cmd_ble_adv_nc #endif /* DeviceFamily_PARENT */ diff --git a/arch/dev/ext-flash/ext-flash.c b/arch/dev/ext-flash/ext-flash.c index c9378d2aa..eebaaf1be 100644 --- a/arch/dev/ext-flash/ext-flash.c +++ b/arch/dev/ext-flash/ext-flash.c @@ -323,7 +323,7 @@ ext_flash_open(spi_device_t *conf) flash_spi_configuration = get_spi_conf(conf); /* Check if platform has ext-flash */ - if(flash_spi_configuration->pin_spi_sck == GPIO_HAL_PIN_UNKNOWN) { + if(flash_spi_configuration->pin_spi_cs == GPIO_HAL_PIN_UNKNOWN) { return false; } diff --git a/arch/platform/simplelink/cc13xx-cc26xx/batmon-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/batmon-sensor.c index 14c5ae5fe..b0433405d 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/batmon-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/batmon-sensor.c @@ -69,7 +69,7 @@ value(int type) { if(enabled == SENSOR_STATUS_DISABLED) { PRINTF("Sensor Disabled\n"); - return 0; + return BATMON_SENSOR_READING_ERROR; } switch(type) { @@ -77,7 +77,7 @@ value(int type) case BATMON_SENSOR_TYPE_VOLT: return (int)AONBatMonBatteryVoltageGet(); default: PRINTF("Invalid type\n"); - return 0; + return BATMON_SENSOR_READING_ERROR; } } /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/batmon-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/batmon-sensor.h index 2bfd82ae0..569671d8c 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/batmon-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/batmon-sensor.h @@ -46,6 +46,8 @@ #define BATMON_SENSOR_TYPE_TEMP 1 #define BATMON_SENSOR_TYPE_VOLT 2 /*---------------------------------------------------------------------------*/ +#define BATMON_SENSOR_READING_ERROR -1 +/*---------------------------------------------------------------------------*/ extern const struct sensors_sensor batmon_sensor; /*---------------------------------------------------------------------------*/ #endif /* BATMON_SENSOR_H_ */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-conf.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-conf.h index a096f0072..c7461f92a 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-conf.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-conf.h @@ -88,10 +88,24 @@ /** * \name The external flash SPI CS pin, defined in Board.h. * + * Note that SPI SCK, MOSI and MISO does not need to be defined, as they are + * implicitly defined via the Board_SPI0 controller. + * * Those values are not meant to be modified by the user * @{ */ -#define EXT_FLASH_SPI_PIN_CS Board_SPI_FLASH_CS +#define EXT_FLASH_SPI_CONTROLLER Board_SPI0 + +#define EXT_FLASH_SPI_PIN_SCK GPIO_HAL_PIN_UNKNOWN +#define EXT_FLASH_SPI_PIN_MOSI GPIO_HAL_PIN_UNKNOWN +#define EXT_FLASH_SPI_PIN_MISO GPIO_HAL_PIN_UNKNOWN +#define EXT_FLASH_SPI_PIN_CS Board_SPI_FLASH_CS + +#define EXT_FLASH_DEVICE_ID 0x14 +#define EXT_FLASH_MID 0xC2 + +#define EXT_FLASH_PROGRAM_PAGE_SIZE 256 +#define EXT_FLASH_ERASE_SECTOR_SIZE 4096 /** @} */ /*---------------------------------------------------------------------------*/ #endif /* BOARD_CONF_H_ */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h index d676f3375..85dfbb6bf 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h @@ -89,7 +89,18 @@ * Those values are not meant to be modified by the user * @{ */ -#define EXT_FLASH_SPI_PIN_CS Board_SPI_FLASH_CS +#define EXT_FLASH_SPI_CONTROLLER Board_SPI0 + +#define EXT_FLASH_SPI_PIN_SCK GPIO_HAL_PIN_UNKNOWN +#define EXT_FLASH_SPI_PIN_MOSI GPIO_HAL_PIN_UNKNOWN +#define EXT_FLASH_SPI_PIN_MISO GPIO_HAL_PIN_UNKNOWN +#define EXT_FLASH_SPI_PIN_CS Board_SPI_FLASH_CS + +#define EXT_FLASH_DEVICE_ID 0x14 +#define EXT_FLASH_MID 0xC2 + +#define EXT_FLASH_PROGRAM_PAGE_SIZE 256 +#define EXT_FLASH_ERASE_SECTOR_SIZE 4096 /** @} */ /*---------------------------------------------------------------------------*/ #endif /* BOARD_CONF_H_ */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/Makefile b/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/Makefile index ebc6d5f1b..bffecb99c 100644 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/Makefile +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/Makefile @@ -1,10 +1,8 @@ CONTIKI_PROJECT = start-demo -PROJECT_SOURCEFILES = start-demo.c - PLATFORMS_ONLY = simplelink -all: $(CONTIKI_PROJECT).$(TARGET) +all: $(CONTIKI_PROJECT) CONTIKI = ../../../../.. include $(CONTIKI)/Makefile.include diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/Makefile b/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/Makefile index 46da822d3..07da8daf8 100644 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/Makefile +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/Makefile @@ -1,10 +1,12 @@ CONTIKI_PROJECT = very-sleepy-demo -PLATFORMS_ONLY = srf06-cc26xx +PLATFORMS_ONLY = simplelink -all: $(CONTIKI_PROJECT) +all: $(CONTIKI_PROJECT).$(TARGET) + +SMALL = 1 MODULES += os/net/app-layer/coap -CONTIKI = ../../../.. +CONTIKI = ../../../../.. include $(CONTIKI)/Makefile.include diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/project-conf.h b/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/project-conf.h index f22fb2685..784a0e9ee 100644 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/project-conf.h +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/project-conf.h @@ -31,25 +31,31 @@ #ifndef PROJECT_CONF_H_ #define PROJECT_CONF_H_ /*---------------------------------------------------------------------------*/ -/* Change to match your configuration */ -#define IEEE802154_CONF_PANID 0xABCD -#define IEEE802154_CONF_DEFAULT_CHANNEL 25 +/* Platform configuration */ +#define BOARD_CONF_SENSORS_DISABLE 1 +#define WATCHDOG_CONF_DISABLE 1 /*---------------------------------------------------------------------------*/ - -/* Enable the ROM bootloader */ -#define ROM_BOOTLOADER_ENABLE 1 +/* Nestack configuration */ +#define IEEE802154_CONF_PANID 0xABCD +#define IEEE802154_CONF_DEFAULT_CHANNEL 25 +//#define RF_CONF_MODE RF_MODE_SUB_1_GHZ +#define RF_CONF_MODE RF_MODE_2_4_GHZ +#define RF_CONF_BLE_BEACON_ENABLE 0 +/*---------------------------------------------------------------------------*/ +/* TI drivers configuration */ +#define TI_SPI_CONF_ENABLE 0 +#define TI_I2C_CONF_ENABLE 0 /*---------------------------------------------------------------------------*/ /* For very sleepy operation */ -#define RF_BLE_CONF_ENABLED 0 -#define UIP_DS6_CONF_PERIOD CLOCK_SECOND -#define UIP_CONF_TCP 0 -#define RPL_CONF_LEAF_ONLY 1 +#define UIP_DS6_CONF_PERIOD CLOCK_SECOND +#define UIP_CONF_TCP 0 +#define RPL_CONF_LEAF_ONLY 1 /* * We'll fail without RPL probing, so turn it on explicitly even though it's * on by default */ -#define RPL_CONF_WITH_PROBING 1 +#define RPL_CONF_WITH_PROBING 1 /*---------------------------------------------------------------------------*/ #endif /* PROJECT_CONF_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/very-sleepy-demo.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/very-sleepy-demo.c index d707f3cd1..711746f7c 100644 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/very-sleepy-demo.c +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/very-sleepy-demo.c @@ -32,20 +32,20 @@ #include "sys/etimer.h" #include "sys/stimer.h" #include "sys/process.h" +#include "lib/sensors.h" #include "dev/leds.h" #include "dev/watchdog.h" #include "dev/button-hal.h" -#include "batmon-sensor.h" -#include "board-peripherals.h" #include "net/netstack.h" #include "net/ipv6/uip-ds6-nbr.h" #include "net/ipv6/uip-ds6-route.h" #include "net/routing/routing.h" -#include "coap-engine.h" -#include "coap.h" - -#include "ti-lib.h" - +#include "net/app-layer/coap/coap.h" +#include "net/app-layer/coap/coap-engine.h" +/*---------------------------------------------------------------------------*/ +#include "board-peripherals.h" +#include "batmon-sensor.h" +/*---------------------------------------------------------------------------*/ #include #include #include diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/very-sleepy-demo.simplelink b/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/very-sleepy-demo.simplelink new file mode 100644 index 0000000000000000000000000000000000000000..a405a2444edd79e75e3e58269ce3b74b87b469fd GIT binary patch literal 592244 zcmeGEi+@u^`Uj5Bx#XU-=>_Nw$fbp}p%N%)1y(~EPA@4Gfprme4T2hl)d2e0fV&bd zY5{etWp{z|_>k%Ki%HmH$~27Wx`sO7GBMHW;t*`S~g$eoMf=!1#IJ%R`tl=RKzcqQVM z#PoJGLk94chHuCJ|11A;{=-{2a(JsE8&)DO4YYoj;|G*H83276=-Z`NenX!=%RdjT(uGU>^gEOD!#n%9AidUXc1NXR*|TP zRXodHuU_!rIY#l&IY#;5NaMvrBM)DEXr%Gd^CJ&mdaUoOsQ4PC%Ze&?b|^=4$2o>8 z3Q197@;5T|{zg)(49^v~dR6@dk;zv@8OMa7;8r$F@5irY9H2l`g_rlW^pR?HnAj@9 zZDM8?f`f<;^!+BG*8kv3{x3vSN~a}0cKS=!%6I!4Yrhm59})5dUQj

`SA&U6X|M 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%0DZB>VN+&uUWzOZ*47*hI6BTHn=WDlK%yIF@UE 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

g|^YxT`_;&!p>oh?lWHcdYhi5 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 Sz5Mq-lzoG5?Z%(j-~R&^;Q2oQ literal 0 HcmV?d00001 diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/Makefile b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/Makefile index a295c03fe..feae0b36d 100644 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/Makefile +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/Makefile @@ -1,9 +1,10 @@ CONTIKI_PROJECT = web-demo -all: $(CONTIKI_PROJECT) + +all: $(CONTIKI_PROJECT).$(TARGET) MODULES_REL += ./resources -PROJECT_SOURCEFILES += web-demo.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) @@ -11,9 +12,12 @@ ifeq ($(MAKE_ROUTING),MAKE_ROUTING_RPL_CLASSIC) PROJECT_SOURCEFILES += cetic-6lbr-client.c endif +SMALL = 1 + # REST Engine shall use Erbium CoAP implementation MODULES += os/net/app-layer/mqtt MODULES += os/net/app-layer/coap +MODULES += arch/dev/ext-flash -CONTIKI=../../../.. +CONTIKI = ../../../../.. include $(CONTIKI)/Makefile.include diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/cetic-6lbr-client.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/cetic-6lbr-client.c index 569a36a89..7c4cbdfff 100644 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/cetic-6lbr-client.c +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/cetic-6lbr-client.c @@ -24,7 +24,7 @@ * SUCH DAMAGE. */ /** - * \addtogroup cc26xx-web-demo + * \addtogroup cc13xx-cc26xx-web-demo * @{ * * \file @@ -35,21 +35,21 @@ #include "contiki.h" #include "contiki-lib.h" #include "contiki-net.h" -#include "net/routing/routing.h" #include "net/ipv6/uip.h" -#if ROUTING_CONF_RPL_CLASSIC +#include "net/routing/routing.h" #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 #include /*---------------------------------------------------------------------------*/ #define DEBUG 0 #include "net/ipv6/uip-debug.h" /*---------------------------------------------------------------------------*/ +#if (ROUTING_CONF_RPL_CLASSIC == 0) +#error "The 6LBR client is only meant for RPL Classic. Set MAKE_ROUTING accordingly." +#endif +/*---------------------------------------------------------------------------*/ #ifndef CETIC_6LBR_NODE_INFO_PORT #define CETIC_6LBR_NODE_INFO_PORT 3000 #endif diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/coap-server.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/coap-server.c index 37b9a295d..5a53fb1ae 100644 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/coap-server.c +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/coap-server.c @@ -28,20 +28,22 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /** - * \addtogroup cc26xx-web-demo + * \addtogroup cc13xx-cc26xx-web-demo * @{ * * \file - * A CC26XX-specific CoAP server + * A CC13xx/CC26xx-specific CoAP server */ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "contiki-net.h" -#include "coap-engine.h" +#include "net/app-layer/coap/coap-engine.h" +/*---------------------------------------------------------------------------*/ #include "board-peripherals.h" -#include "rf-core/rf-ble.h" -#include "cc26xx-web-demo.h" - +#include "rf/ble-beacond.h" +/*---------------------------------------------------------------------------*/ +#include "web-demo.h" +/*---------------------------------------------------------------------------*/ #include #include #include @@ -60,7 +62,7 @@ extern coap_resource_t res_device_cfg_reset; extern coap_resource_t res_parent_rssi; extern coap_resource_t res_parent_ip; -#if RF_BLE_ENABLED +#if RF_CONF_BLE_BEACON_ENABLE extern coap_resource_t res_ble_advd; #endif @@ -87,7 +89,7 @@ extern coap_resource_t res_toggle_orange; extern coap_resource_t res_toggle_yellow; #endif -#if CC26XX_WEB_DEMO_ADC_DEMO +#if WEB_DEMO_ADC_DEMO extern coap_resource_t res_adc_dio23; #endif /*---------------------------------------------------------------------------*/ @@ -125,18 +127,18 @@ start_board_resources(void) #endif } /*---------------------------------------------------------------------------*/ -PROCESS(coap_server_process, "CC26XX CoAP Server"); +PROCESS(coap_server_process, "CC13xx/CC26xx CoAP Server"); /*---------------------------------------------------------------------------*/ PROCESS_THREAD(coap_server_process, ev, data) { PROCESS_BEGIN(); - printf("CC26XX CoAP Server\n"); + printf("CC13xx/CC26xx CoAP Server\n"); coap_activate_resource(&res_batmon_temp, "sen/batmon/temp"); coap_activate_resource(&res_batmon_volt, "sen/batmon/voltage"); -#if CC26XX_WEB_DEMO_ADC_DEMO +#if WEB_DEMO_ADC_DEMO coap_activate_resource(&res_adc_dio23, "sen/adc/dio23"); #endif @@ -148,7 +150,7 @@ PROCESS_THREAD(coap_server_process, ev, data) coap_activate_resource(&res_parent_rssi, "net/parent/RSSI"); coap_activate_resource(&res_parent_ip, "net/parent/IPv6"); -#if RF_BLE_ENABLED +#if RF_CONF_BLE_BEACON_ENABLE coap_activate_resource(&res_ble_advd, "dev/ble_advd"); #endif diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/coap-server.h b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/coap-server.h index 7399597c8..839928871 100644 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/coap-server.h +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/coap-server.h @@ -28,11 +28,11 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /** - * \addtogroup cc26xx-web-demo + * \addtogroup cc13xx-cc26xx-web-demo * @{ * * \file - * Header file for the CC26xx web demo CoAP functionality + * Header file for the CC13xx/CC26xx web demo CoAP functionality */ /*---------------------------------------------------------------------------*/ #include "sys/process.h" diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/httpd-simple.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/httpd-simple.c index e23e78efe..46f247ac8 100644 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/httpd-simple.c +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/httpd-simple.c @@ -29,7 +29,7 @@ * */ /** - * \addtogroup cc26xx-web-demo + * \addtogroup cc13xx-cc26xx-web-demo * @{ * * \file @@ -37,15 +37,17 @@ */ /*---------------------------------------------------------------------------*/ #include "contiki.h" -#include "httpd-simple.h" #include "net/ipv6/uip-ds6-route.h" -#include "batmon-sensor.h" #include "lib/sensors.h" #include "lib/list.h" -#include "cc26xx-web-demo.h" +/*---------------------------------------------------------------------------*/ +#include "batmon-sensor.h" +/*---------------------------------------------------------------------------*/ +#include "web-demo.h" #include "mqtt-client.h" +#include "httpd-simple.h" #include "net-uart.h" - +/*---------------------------------------------------------------------------*/ #include #include #include @@ -93,8 +95,8 @@ static int state; #define STRINGIFY(x) XSTR(x) #define XSTR(x) #x -#define RSSI_INT_MAX STRINGIFY(CC26XX_WEB_DEMO_RSSI_MEASURE_INTERVAL_MAX) -#define RSSI_INT_MIN STRINGIFY(CC26XX_WEB_DEMO_RSSI_MEASURE_INTERVAL_MIN) +#define RSSI_INT_MAX STRINGIFY(WEB_DEMO_RSSI_MEASURE_INTERVAL_MAX) +#define RSSI_INT_MIN STRINGIFY(WEB_DEMO_RSSI_MEASURE_INTERVAL_MIN) #define PUB_INT_MAX STRINGIFY(MQTT_CLIENT_PUBLISH_INTERVAL_MAX) #define PUB_INT_MIN STRINGIFY(MQTT_CLIENT_PUBLISH_INTERVAL_MIN) /*---------------------------------------------------------------------------*/ @@ -109,7 +111,7 @@ static int state; */ static struct httpd_state *lock; /*---------------------------------------------------------------------------*/ -PROCESS(httpd_simple_process, "CC26XX Web Server"); +PROCESS(httpd_simple_process, "CC13xx/CC26xx Web Server"); /*---------------------------------------------------------------------------*/ #define ISO_nl 0x0A #define ISO_space 0x20 @@ -216,7 +218,7 @@ static page_t http_dev_cfg_page = { generate_config, }; -#if CC26XX_WEB_DEMO_NET_UART +#if WEB_DEMO_NET_UART static char generate_net_uart_config(struct httpd_state *s); static page_t http_net_cfg_page = { @@ -227,7 +229,7 @@ static page_t http_net_cfg_page = { }; #endif -#if CC26XX_WEB_DEMO_MQTT_CLIENT +#if WEB_DEMO_MQTT_CLIENT static char generate_mqtt_config(struct httpd_state *s); static page_t http_mqtt_cfg_page = { @@ -257,7 +259,7 @@ struct httpd_state { struct psock sin, sout; int blen; const char **ptr; - const cc26xx_web_demo_sensor_reading_t *reading; + const web_demo_sensor_reading_t *reading; const page_t *page; uip_ds6_route_t *r; uip_ds6_nbr_t *nbr; @@ -411,7 +413,7 @@ PT_THREAD(generate_top_matter(struct httpd_state *s, const char *title, s->page->filename, s->page->title)); } -#if CC26XX_WEB_DEMO_MQTT_CLIENT +#if WEB_DEMO_MQTT_CLIENT PT_WAIT_THREAD(&s->top_matter_pt, enqueue_chunk(s, 0, " | %s", http_mqtt_a)); #endif @@ -442,7 +444,7 @@ PT_THREAD(generate_index(struct httpd_state *s)) PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "\n")); memset(ipaddr_buf, 0, IPADDR_BUF_LEN); - cc26xx_web_demo_ipaddr_sprintf(ipaddr_buf, IPADDR_BUF_LEN, &s->nbr->ipaddr); + web_demo_ipaddr_sprintf(ipaddr_buf, IPADDR_BUF_LEN, &s->nbr->ipaddr); PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "%s", ipaddr_buf)); memset(ipaddr_buf, 0, IPADDR_BUF_LEN); @@ -459,7 +461,7 @@ PT_THREAD(generate_index(struct httpd_state *s)) SECTION_OPEN "Default Route" CONTENT_OPEN)); memset(ipaddr_buf, 0, IPADDR_BUF_LEN); - cc26xx_web_demo_ipaddr_sprintf(ipaddr_buf, IPADDR_BUF_LEN, + web_demo_ipaddr_sprintf(ipaddr_buf, IPADDR_BUF_LEN, uip_ds6_defrt_choose()); PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "%s", ipaddr_buf)); @@ -475,14 +477,14 @@ PT_THREAD(generate_index(struct httpd_state *s)) PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "\n")); memset(ipaddr_buf, 0, IPADDR_BUF_LEN); - cc26xx_web_demo_ipaddr_sprintf(ipaddr_buf, IPADDR_BUF_LEN, &s->r->ipaddr); + web_demo_ipaddr_sprintf(ipaddr_buf, IPADDR_BUF_LEN, &s->r->ipaddr); PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "%s", ipaddr_buf)); PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, " / %u via ", s->r->length)); memset(ipaddr_buf, 0, IPADDR_BUF_LEN); - cc26xx_web_demo_ipaddr_sprintf(ipaddr_buf, IPADDR_BUF_LEN, + web_demo_ipaddr_sprintf(ipaddr_buf, IPADDR_BUF_LEN, uip_ds6_route_nexthop(s->r)); PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "%s", ipaddr_buf)); @@ -498,7 +500,7 @@ PT_THREAD(generate_index(struct httpd_state *s)) PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, SECTION_OPEN "Sensors" CONTENT_OPEN)); - for(s->reading = cc26xx_web_demo_sensor_first(); + for(s->reading = web_demo_sensor_first(); s->reading != NULL; s->reading = s->reading->next) { PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "\n%s = %s %s", s->reading->descr, @@ -547,7 +549,7 @@ PT_THREAD(generate_config(struct httpd_state *s)) PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "accept-charset=\"UTF-8\">")); - for(s->reading = cc26xx_web_demo_sensor_first(); + for(s->reading = web_demo_sensor_first(); s->reading != NULL; s->reading = s->reading->next) { PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "%s%s:%s%s", config_div_left, @@ -576,7 +578,7 @@ PT_THREAD(generate_config(struct httpd_state *s)) enqueue_chunk(s, 0, "")); /* RSSI measurements */ -#if CC26XX_WEB_DEMO_READ_PARENT_RSSI +#if WEB_DEMO_READ_PARENT_RSSI PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "

RSSI Probing

")); @@ -600,7 +602,7 @@ PT_THREAD(generate_config(struct httpd_state *s)) PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "value=\"%lu\" ", (clock_time_t) - (cc26xx_web_demo_config.def_rt_ping_interval + (web_demo_config.def_rt_ping_interval / CLOCK_SECOND))); PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, @@ -641,7 +643,7 @@ PT_THREAD(generate_config(struct httpd_state *s)) PT_END(&s->generate_pt); } /*---------------------------------------------------------------------------*/ -#if CC26XX_WEB_DEMO_MQTT_CLIENT +#if WEB_DEMO_MQTT_CLIENT static PT_THREAD(generate_mqtt_config(struct httpd_state *s)) { @@ -675,7 +677,7 @@ PT_THREAD(generate_mqtt_config(struct httpd_state *s)) config_div_right)); PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "value=\"%s\" ", - cc26xx_web_demo_config.mqtt_config.type_id)); + web_demo_config.mqtt_config.type_id)); PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "name=\"type_id\">%s", config_div_close)); @@ -687,7 +689,7 @@ PT_THREAD(generate_mqtt_config(struct httpd_state *s)) config_div_right)); PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "value=\"%s\" ", - cc26xx_web_demo_config.mqtt_config.org_id)); + web_demo_config.mqtt_config.org_id)); PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "name=\"org_id\">%s", config_div_close)); @@ -711,7 +713,7 @@ PT_THREAD(generate_mqtt_config(struct httpd_state *s)) config_div_right)); PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "value=\"%s\" ", - cc26xx_web_demo_config.mqtt_config.cmd_type)); + web_demo_config.mqtt_config.cmd_type)); PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "name=\"cmd_type\">%s", config_div_close)); @@ -724,7 +726,7 @@ PT_THREAD(generate_mqtt_config(struct httpd_state *s)) config_div_right)); PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "value=\"%s\" ", - cc26xx_web_demo_config.mqtt_config.event_type_id)); + web_demo_config.mqtt_config.event_type_id)); PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "name=\"event_type_id\">%s", config_div_close)); @@ -738,7 +740,7 @@ PT_THREAD(generate_mqtt_config(struct httpd_state *s)) PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "value=\"%lu\" ", (clock_time_t) - (cc26xx_web_demo_config.mqtt_config.pub_interval + (web_demo_config.mqtt_config.pub_interval / CLOCK_SECOND))); PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, @@ -755,7 +757,7 @@ PT_THREAD(generate_mqtt_config(struct httpd_state *s)) config_div_right)); PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "value=\"%s\" ", - cc26xx_web_demo_config.mqtt_config.broker_ip)); + web_demo_config.mqtt_config.broker_ip)); PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "name=\"broker_ip\">%s", config_div_close)); @@ -768,7 +770,7 @@ PT_THREAD(generate_mqtt_config(struct httpd_state *s)) config_div_right)); PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "value=\"%d\" ", - cc26xx_web_demo_config.mqtt_config.broker_port)); + web_demo_config.mqtt_config.broker_port)); PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "min=\"1\" max=\"65535\" " "name=\"broker_port\">%s", @@ -803,7 +805,7 @@ PT_THREAD(generate_mqtt_config(struct httpd_state *s)) } #endif /*---------------------------------------------------------------------------*/ -#if CC26XX_WEB_DEMO_NET_UART +#if WEB_DEMO_NET_UART static PT_THREAD(generate_net_uart_config(struct httpd_state *s)) { @@ -838,7 +840,7 @@ PT_THREAD(generate_net_uart_config(struct httpd_state *s)) config_div_right)); PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "value=\"%s\" ", - cc26xx_web_demo_config.net_uart.remote_address)); + web_demo_config.net_uart.remote_address)); PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "name=\"net_uart_ip\">%s", config_div_close)); @@ -851,7 +853,7 @@ PT_THREAD(generate_net_uart_config(struct httpd_state *s)) config_div_right)); PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "value=\"%u\" ", - cc26xx_web_demo_config.net_uart.remote_port)); + web_demo_config.net_uart.remote_port)); PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "min=\"1\" max=\"65535\" " "name=\"net_uart_port\">%s", @@ -866,14 +868,14 @@ PT_THREAD(generate_net_uart_config(struct httpd_state *s)) enqueue_chunk(s, 0, "generate_pt, enqueue_chunk(s, 0, "title=\"On\" name=\"net_uart_on\"%s>", - cc26xx_web_demo_config.net_uart.enable ? + web_demo_config.net_uart.enable ? " Checked" : "")); PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "generate_pt, enqueue_chunk(s, 0, "title=\"Off\" name=\"net_uart_on\"" "%s>%s", - cc26xx_web_demo_config.net_uart.enable ? + web_demo_config.net_uart.enable ? "" : " Checked", config_div_close)); PT_WAIT_THREAD(&s->generate_pt, @@ -1310,11 +1312,11 @@ init(void) list_add(pages_list, &http_index_page); list_add(pages_list, &http_dev_cfg_page); -#if CC26XX_WEB_DEMO_NET_UART +#if WEB_DEMO_NET_UART list_add(pages_list, &http_net_cfg_page); #endif -#if CC26XX_WEB_DEMO_MQTT_CLIENT +#if WEB_DEMO_MQTT_CLIENT list_add(pages_list, &http_mqtt_cfg_page); #endif } diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/httpd-simple.h b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/httpd-simple.h index 25b8db3e5..810fd4782 100644 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/httpd-simple.h +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/httpd-simple.h @@ -31,7 +31,7 @@ /*---------------------------------------------------------------------------*/ /** * \file - * Header file for the HTTPD of the cc26xx web demo example. + * Header file for the HTTPD of the CC13xx/CC26xx web demo example. * \author * Adam Dunkels * Niclas Finne @@ -44,7 +44,8 @@ /*---------------------------------------------------------------------------*/ #include "contiki-net.h" #include "sys/process.h" -#include "cc26xx-web-demo.h" +/*---------------------------------------------------------------------------*/ +#include "web-demo.h" /*---------------------------------------------------------------------------*/ /* Ideally a multiple of TCP_MSS */ #ifdef HTTPD_SIMPLE_CONF_MAIN_BUF_SIZE diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/mqtt-client.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/mqtt-client.c index 7562fb89a..3be86ffd8 100644 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/mqtt-client.c +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/mqtt-client.c @@ -28,28 +28,30 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /** - * \addtogroup cc26xx-web-demo + * \addtogroup cc13xx-cc26xx-web-demo * @{ * * \file - * MQTT/IBM cloud service client for the CC26XX web demo. + * MQTT/IBM cloud service client for the CC13xx/CC26xx web demo. */ /*---------------------------------------------------------------------------*/ #include "contiki.h" -#include "net/routing/routing.h" -#include "mqtt.h" -#include "net/ipv6/uip.h" -#include "net/ipv6/uip-icmp6.h" +#include "dev/button-hal.h" +#include "dev/leds.h" #include "sys/etimer.h" #include "sys/ctimer.h" +#include "net/routing/routing.h" +#include "net/ipv6/uip.h" +#include "net/ipv6/uip-icmp6.h" +#include "net/app-layer/mqtt/mqtt.h" #include "lib/sensors.h" -#include "dev/button-hal.h" +/*---------------------------------------------------------------------------*/ #include "board-peripherals.h" -#include "cc26xx-web-demo.h" -#include "dev/leds.h" -#include "mqtt-client.h" +/*---------------------------------------------------------------------------*/ +#include "web-demo.h" #include "httpd-simple.h" - +#include "mqtt-client.h" +/*---------------------------------------------------------------------------*/ #include #include /*---------------------------------------------------------------------------*/ @@ -139,16 +141,16 @@ static uip_ip6addr_t def_route; /* Parent RSSI functionality */ extern int def_rt_rssi; /*---------------------------------------------------------------------------*/ -const static cc26xx_web_demo_sensor_reading_t *reading; +const static web_demo_sensor_reading_t *reading; /*---------------------------------------------------------------------------*/ mqtt_client_config_t *conf; /*---------------------------------------------------------------------------*/ -PROCESS(mqtt_client_process, "CC26XX MQTT Client"); +PROCESS(mqtt_client_process, "CC13xx/CC26xx MQTT Client"); /*---------------------------------------------------------------------------*/ static void publish_led_off(void *d) { - leds_off(CC26XX_WEB_DEMO_STATUS_LED); + leds_off(WEB_DEMO_STATUS_LED); } /*---------------------------------------------------------------------------*/ static void @@ -579,14 +581,14 @@ init_config() /* Populate configuration with default values */ memset(conf, 0, sizeof(mqtt_client_config_t)); - memcpy(conf->org_id, CC26XX_WEB_DEMO_DEFAULT_ORG_ID, 11); - memcpy(conf->type_id, CC26XX_WEB_DEMO_DEFAULT_TYPE_ID, 7); - memcpy(conf->event_type_id, CC26XX_WEB_DEMO_DEFAULT_EVENT_TYPE_ID, 7); + memcpy(conf->org_id, WEB_DEMO_DEFAULT_ORG_ID, 11); + memcpy(conf->type_id, WEB_DEMO_DEFAULT_TYPE_ID, 7); + memcpy(conf->event_type_id, WEB_DEMO_DEFAULT_EVENT_TYPE_ID, 7); memcpy(conf->broker_ip, broker_ip, strlen(broker_ip)); - memcpy(conf->cmd_type, CC26XX_WEB_DEMO_DEFAULT_SUBSCRIBE_CMD_TYPE, 1); + memcpy(conf->cmd_type, WEB_DEMO_DEFAULT_SUBSCRIBE_CMD_TYPE, 1); - conf->broker_port = CC26XX_WEB_DEMO_DEFAULT_BROKER_PORT; - conf->pub_interval = CC26XX_WEB_DEMO_DEFAULT_PUBLISH_INTERVAL; + conf->broker_port = WEB_DEMO_DEFAULT_BROKER_PORT; + conf->pub_interval = WEB_DEMO_DEFAULT_PUBLISH_INTERVAL; return 1; } @@ -649,7 +651,7 @@ publish(void) /* Put our Default route's string representation in a buffer */ memset(def_rt_str, 0, sizeof(def_rt_str)); - cc26xx_web_demo_ipaddr_sprintf(def_rt_str, sizeof(def_rt_str), + web_demo_ipaddr_sprintf(def_rt_str, sizeof(def_rt_str), uip_ds6_defrt_choose()); len = snprintf(buf_ptr, remaining, ",\"Def Route\":\"%s\",\"RSSI (dBm)\":%d", @@ -664,9 +666,9 @@ publish(void) memcpy(&def_route, uip_ds6_defrt_choose(), sizeof(uip_ip6addr_t)); - for(reading = cc26xx_web_demo_sensor_first(); + for(reading = web_demo_sensor_first(); reading != NULL; reading = reading->next) { - if(reading->publish && reading->raw != CC26XX_SENSOR_READING_ERROR) { + if(reading->publish && reading->raw != -1) { len = snprintf(buf_ptr, remaining, ",\"%s (%s)\":%s", reading->descr, reading->units, reading->converted); @@ -751,11 +753,11 @@ state_machine(void) DBG("Registered. Connect attempt %u\n", connect_attempt); connect_to_broker(); } - etimer_set(&publish_periodic_timer, CC26XX_WEB_DEMO_NET_CONNECT_PERIODIC); + etimer_set(&publish_periodic_timer, WEB_DEMO_NET_CONNECT_PERIODIC); return; break; case MQTT_CLIENT_STATE_CONNECTING: - leds_on(CC26XX_WEB_DEMO_STATUS_LED); + leds_on(WEB_DEMO_STATUS_LED); ctimer_set(&ct, CONNECTING_LED_DURATION, publish_led_off, NULL); /* Not connected yet. Wait */ DBG("Connecting (%u)\n", connect_attempt); @@ -783,7 +785,7 @@ state_machine(void) subscribe(); state = MQTT_CLIENT_STATE_PUBLISHING; } else { - leds_on(CC26XX_WEB_DEMO_STATUS_LED); + leds_on(WEB_DEMO_STATUS_LED); ctimer_set(&ct, PUBLISH_LED_ON_DURATION, publish_led_off, NULL); publish(); } @@ -846,7 +848,7 @@ state_machine(void) return; case MQTT_CLIENT_STATE_ERROR: default: - leds_on(CC26XX_WEB_DEMO_STATUS_LED); + leds_on(WEB_DEMO_STATUS_LED); /* * 'default' should never happen. * @@ -866,9 +868,9 @@ PROCESS_THREAD(mqtt_client_process, ev, data) PROCESS_BEGIN(); - printf("CC26XX MQTT Client Process\n"); + printf("CC13xx/CC26xx MQTT Client Process\n"); - conf = &cc26xx_web_demo_config.mqtt_config; + conf = &web_demo_config.mqtt_config; if(init_config() != 1) { PROCESS_EXIT(); } @@ -885,7 +887,7 @@ PROCESS_THREAD(mqtt_client_process, ev, data) if(ev == button_hal_release_event) { button_hal_button_t *btn = (button_hal_button_t *)data; - if(btn->unique_id == CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER) { + if(btn->unique_id == WEB_DEMO_MQTT_PUBLISH_TRIGGER) { if(state == MQTT_CLIENT_STATE_ERROR) { connect_attempt = 1; state = MQTT_CLIENT_STATE_REGISTERED; @@ -904,14 +906,14 @@ PROCESS_THREAD(mqtt_client_process, ev, data) if((ev == PROCESS_EVENT_TIMER && data == &publish_periodic_timer) || ev == PROCESS_EVENT_POLL || - ev == cc26xx_web_demo_publish_event || + ev == web_demo_publish_event || (ev == button_hal_release_event && ((button_hal_button_t *)data)->unique_id == - CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER)) { + WEB_DEMO_MQTT_PUBLISH_TRIGGER)) { state_machine(); } - if(ev == cc26xx_web_demo_load_config_defaults) { + if(ev == web_demo_load_config_defaults) { init_config(); etimer_set(&publish_periodic_timer, NEW_CONFIG_WAIT_INTERVAL); } diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/mqtt-client.h b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/mqtt-client.h index ab7c08227..d37c31fbc 100644 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/mqtt-client.h +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/mqtt-client.h @@ -28,11 +28,11 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /** - * \addtogroup cc26xx-web-demo + * \addtogroup cc13xx-cc26xx-web-demo * @{ * * \file - * Header file for the CC26xx web demo MQTT client functionality + * Header file for the CC13xx/CC26xx web demo MQTT client functionality */ /*---------------------------------------------------------------------------*/ #ifndef MQTT_CLIENT_H_ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/net-uart.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/net-uart.c index ca3bf8c82..564abe27d 100644 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/net-uart.c +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/net-uart.c @@ -28,7 +28,7 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /** - * \addtogroup cc26xx-web-demo + * \addtogroup cc13xx-cc26xx-web-demo * @{ * * \file @@ -44,7 +44,7 @@ * * (REMOTE_PORT should be the actual value of the define below, e.g. 7777) * - * Once netcat is up and listening, type something to the CC26xx's terminal + * Once netcat is up and listening, type something to the CC13xx/CC26xx's terminal * Bear in mind that the datagram will only be sent after a 0x0a (LF) char * has been received. Therefore, if you are on Win, do NOT use PuTTY for * this purpose, since it does not send 0x0a as part of the line end. On @@ -57,18 +57,18 @@ */ /*---------------------------------------------------------------------------*/ #include "contiki.h" +#include "sys/cc.h" #include "sys/process.h" #include "dev/serial-line.h" -#include "dev/cc26xx-uart.h" #include "net/ipv6/uip.h" #include "net/ipv6/uip-udp-packet.h" #include "net/ipv6/uiplib.h" +/*---------------------------------------------------------------------------*/ +#include "uart0-arch.h" +/*---------------------------------------------------------------------------*/ #include "net-uart.h" #include "httpd-simple.h" -#include "sys/cc.h" - -#include "ti-lib.h" - +/*---------------------------------------------------------------------------*/ #include #include #include @@ -149,13 +149,13 @@ net_input(void) static void release_uart(void) { - cc26xx_uart_set_input(NULL); + uart0_set_callback(NULL); } /*---------------------------------------------------------------------------*/ static void keep_uart_on(void) { - cc26xx_uart_set_input(serial_line_input_byte); + uart0_set_callback(serial_line_input_byte); } /*---------------------------------------------------------------------------*/ static int @@ -172,7 +172,7 @@ remote_port_post_handler(char *key, int key_len, char *val, int val_len) rv = atoi(val); if(rv <= 65535 && rv > 0) { - cc26xx_web_demo_config.net_uart.remote_port = (uint16_t)rv; + web_demo_config.net_uart.remote_port = (uint16_t)rv; } else { return HTTPD_SIMPLE_POST_HANDLER_ERROR; } @@ -196,9 +196,9 @@ remote_ipv6_post_handler(char *key, int key_len, char *val, int val_len) rv = HTTPD_SIMPLE_POST_HANDLER_ERROR; } else { if(set_new_ip_address(val)) { - memset(cc26xx_web_demo_config.net_uart.remote_address, 0, + memset(web_demo_config.net_uart.remote_address, 0, NET_UART_IP_ADDR_STRLEN); - memcpy(cc26xx_web_demo_config.net_uart.remote_address, val, val_len); + memcpy(web_demo_config.net_uart.remote_address, val, val_len); rv = HTTPD_SIMPLE_POST_HANDLER_OK; } } @@ -221,10 +221,10 @@ on_off_post_handler(char *key, int key_len, char *val, int val_len) /* Be pedantic: only accept 0 and 1, not just any non-zero value */ if(rv == 0) { - cc26xx_web_demo_config.net_uart.enable = 0; + web_demo_config.net_uart.enable = 0; release_uart(); } else if(rv == 1) { - cc26xx_web_demo_config.net_uart.enable = 1; + web_demo_config.net_uart.enable = 1; keep_uart_on(); } else { return HTTPD_SIMPLE_POST_HANDLER_ERROR; @@ -244,17 +244,17 @@ set_config_defaults(void) set_dest_addr(); /* Set config defaults */ - cc26xx_web_demo_ipaddr_sprintf(cc26xx_web_demo_config.net_uart.remote_address, + web_demo_ipaddr_sprintf(web_demo_config.net_uart.remote_address, NET_UART_IP_ADDR_STRLEN, &remote_addr); - cc26xx_web_demo_config.net_uart.remote_port = REMOTE_PORT; - cc26xx_web_demo_config.net_uart.enable = 1; + web_demo_config.net_uart.remote_port = REMOTE_PORT; + web_demo_config.net_uart.enable = 1; } /*---------------------------------------------------------------------------*/ PROCESS_THREAD(net_uart_process, ev, data) { PROCESS_BEGIN(); - printf("CC26XX Net UART Process\n"); + printf("CC13xx/CC26xx Net UART Process\n"); set_config_defaults(); @@ -293,21 +293,21 @@ PROCESS_THREAD(net_uart_process, ev, data) uip_udp_packet_sendto( udp_conn, buffer, msg_len, &remote_addr, - UIP_HTONS(cc26xx_web_demo_config.net_uart.remote_port)); + UIP_HTONS(web_demo_config.net_uart.remote_port)); } } else if(ev == tcpip_event) { net_input(); - } else if(ev == cc26xx_web_demo_config_loaded_event) { + } else if(ev == web_demo_config_loaded_event) { /* * New config. Check if it's possible to update the remote address. * The port will have been updated already */ - set_new_ip_address(cc26xx_web_demo_config.net_uart.remote_address); + set_new_ip_address(web_demo_config.net_uart.remote_address); - if(cc26xx_web_demo_config.net_uart.enable == 1) { + if(web_demo_config.net_uart.enable == 1) { keep_uart_on(); } - } else if(ev == cc26xx_web_demo_load_config_defaults) { + } else if(ev == web_demo_load_config_defaults) { set_config_defaults(); } } diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/net-uart.h b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/net-uart.h index 663e81eaa..362bc79ff 100644 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/net-uart.h +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/net-uart.h @@ -31,7 +31,7 @@ #define NET_UART_H_ /*---------------------------------------------------------------------------*/ #include "net/ipv6/uip.h" - +/*---------------------------------------------------------------------------*/ #include /*---------------------------------------------------------------------------*/ #define NET_UART_IP_ADDR_STRLEN 64 diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/project-conf.h b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/project-conf.h index 36114eeb7..06cd4ed09 100644 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/project-conf.h +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/project-conf.h @@ -31,27 +31,36 @@ #ifndef PROJECT_CONF_H_ #define PROJECT_CONF_H_ /*---------------------------------------------------------------------------*/ +/* Platform configuration */ +#define BOARD_CONF_SENSORS_DISABLE 1 +#define WATCHDOG_CONF_DISABLE 1 +/*---------------------------------------------------------------------------*/ /* Change to match your configuration */ -#define IEEE802154_CONF_PANID 0xABCD -#define IEEE802154_CONF_DEFAULT_CHANNEL 26 -#define RF_BLE_CONF_ENABLED 1 +#define IEEE802154_CONF_PANID 0xABCD +#define IEEE802154_CONF_DEFAULT_CHANNEL 25 +#define RF_CONF_MODE RF_MODE_2_4_GHZ +#define RF_CONF_BLE_BEACON_ENABLE 1 +/*---------------------------------------------------------------------------*/ +/* TI drivers configuration */ +#define TI_SPI_CONF_ENABLE 1 +#define TI_I2C_CONF_ENABLE 0 /*---------------------------------------------------------------------------*/ /* Enable TCP */ #define UIP_CONF_TCP 1 /* Enable/Disable Components of this Demo */ -#define CC26XX_WEB_DEMO_CONF_MQTT_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 +#define WEB_DEMO_CONF_MQTT_CLIENT 1 +#define WEB_DEMO_CONF_6LBR_CLIENT ROUTING_CONF_RPL_CLASSIC +#define WEB_DEMO_CONF_COAP_SERVER 1 +#define WEB_DEMO_CONF_NET_UART 1 /* * ADC sensor functionality. To test this, an external voltage source should be * connected to DIO23 - * Enable/Disable DIO23 ADC reading by setting CC26XX_WEB_DEMO_CONF_ADC_DEMO + * Enable/Disable DIO23 ADC reading by setting WEB_DEMO_CONF_ADC_DEMO */ -#define CC26XX_WEB_DEMO_CONF_ADC_DEMO 0 +#define WEB_DEMO_CONF_ADC_DEMO 0 /*---------------------------------------------------------------------------*/ /* * Change to 1 if you are using an older CC2650 Sensortag (look for Rev: 1.2 diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-ble-advd.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-ble-advd.c index a94a0b7a0..8c79067d3 100644 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-ble-advd.c +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-ble-advd.c @@ -28,7 +28,7 @@ */ /*---------------------------------------------------------------------------*/ /** - * \addtogroup cc26xx-web-demo + * \addtogroup cc13xx-cc26xx-web-demo * @{ * * \file @@ -36,10 +36,11 @@ */ /*---------------------------------------------------------------------------*/ #include "contiki.h" -#include "coap-engine.h" -#include "coap.h" -#include "rf-core/rf-ble.h" - +#include "net/app-layer/coap/coap.h" +#include "net/app-layer/coap/coap-engine.h" +/*---------------------------------------------------------------------------*/ +#include "rf/ble-beacond.h" +/*---------------------------------------------------------------------------*/ #include #include /*---------------------------------------------------------------------------*/ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-device.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-device.c index 46344d1ef..a0485867b 100644 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-device.c +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-device.c @@ -29,49 +29,44 @@ */ /*---------------------------------------------------------------------------*/ /** - * \addtogroup cc26xx-web-demo + * \addtogroup cc13xx-cc26xx-web-demo * @{ * * \file - * CoAP resource handler for CC26XX software and hardware version + * CoAP resource handler for CC13xx/CC26xx software and hardware version */ /*---------------------------------------------------------------------------*/ #include "contiki.h" -#include "coap-engine.h" -#include "coap.h" #include "sys/clock.h" +#include "net/app-layer/coap/coap.h" +#include "net/app-layer/coap/coap-engine.h" +/*---------------------------------------------------------------------------*/ +#include +#include DeviceFamily_constructPath(driverlib/chipinfo.h) +/*---------------------------------------------------------------------------*/ +#include "web-demo.h" #include "coap-server.h" -#include "cc26xx-web-demo.h" - -#include "ti-lib.h" - +/*---------------------------------------------------------------------------*/ #include #include /*---------------------------------------------------------------------------*/ -static uint16_t +static const char * detect_chip(void) { - if(ti_lib_chipinfo_chip_family_is_cc26xx()) { - if(ti_lib_chipinfo_supports_ieee_802_15_4() == true) { - if(ti_lib_chipinfo_supports_ble() == true) { - return 2650; - } else { - return 2630; - } - } else { - return 2640; - } - } else if(ti_lib_chipinfo_chip_family_is_cc13xx()) { - if(ti_lib_chipinfo_supports_ble() == false && - ti_lib_chipinfo_supports_ieee_802_15_4() == false) { - return 1310; - } else if(ti_lib_chipinfo_supports_ble() == true && - ti_lib_chipinfo_supports_ieee_802_15_4() == true) { - return 1350; - } + switch(ChipInfo_GetChipType()) { + case CHIP_TYPE_CC1310: return "CC1310"; + case CHIP_TYPE_CC1350: return "CC1350"; + case CHIP_TYPE_CC2620: return "CC2620"; + case CHIP_TYPE_CC2630: return "CC2630"; + case CHIP_TYPE_CC2640: return "CC2640"; + case CHIP_TYPE_CC2650: return "CC2650"; + case CHIP_TYPE_CC2642: return "CC2642"; + case CHIP_TYPE_CC2652: return "CC2652"; + case CHIP_TYPE_CC1312: return "CC1312"; + case CHIP_TYPE_CC1352: return "CC1352"; + case CHIP_TYPE_CC1352P: return "CC1352P"; + default: return "Unknown"; } - - return 0; } /*---------------------------------------------------------------------------*/ static void @@ -80,26 +75,26 @@ res_get_handler_hw(coap_message_t *request, coap_message_t *response, uint16_t preferred_size, int32_t *offset) { unsigned int accept = -1; - uint16_t chip = detect_chip(); + const char *chip = detect_chip(); coap_get_header_accept(request, &accept); if(accept == -1 || accept == TEXT_PLAIN) { coap_set_header_content_format(response, TEXT_PLAIN); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%s on CC%u", BOARD_STRING, + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%s on %s", BOARD_STRING, chip); coap_set_payload(response, (uint8_t *)buffer, strlen((char *)buffer)); } else if(accept == APPLICATION_JSON) { coap_set_header_content_format(response, APPLICATION_JSON); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{\"HW Ver\":\"%s on CC%u\"}", + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{\"HW Ver\":\"%s on %s\"}", BOARD_STRING, chip); coap_set_payload(response, buffer, strlen((char *)buffer)); } else if(accept == APPLICATION_XML) { coap_set_header_content_format(response, APPLICATION_XML); snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, - "", BOARD_STRING, + "", BOARD_STRING, chip); coap_set_payload(response, buffer, strlen((char *)buffer)); @@ -181,7 +176,7 @@ res_post_handler_cfg_reset(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - cc26xx_web_demo_restore_defaults(); + web_demo_restore_defaults(); } /*---------------------------------------------------------------------------*/ RESOURCE(res_device_sw, diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-leds.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-leds.c index 6c396145c..5e4da11da 100644 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-leds.c +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-leds.c @@ -29,20 +29,20 @@ */ /*---------------------------------------------------------------------------*/ /** - * \addtogroup cc26xx-web-demo + * \addtogroup cc13xx-cc26xx-web-demo * @{ * * \file - * CoAP resource handler for the CC26xx LEDs. Slightly modified copy of + * CoAP resource handler for the CC13xx/CC26xx LEDs. Slightly modified copy of * the one found in Contiki's original CoAP example. * \author * Matthias Kovatsch (original) */ /*---------------------------------------------------------------------------*/ #include "contiki.h" -#include "coap-engine.h" #include "dev/leds.h" - +#include "net/app-layer/coap/coap-engine.h" +/*---------------------------------------------------------------------------*/ #include /*---------------------------------------------------------------------------*/ static void diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-net.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-net.c index 81575f345..b1f6b8725 100644 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-net.c +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-net.c @@ -29,7 +29,7 @@ */ /*---------------------------------------------------------------------------*/ /** - * \addtogroup cc26xx-web-demo + * \addtogroup cc13xx-cc26xx-web-demo * @{ * * \file @@ -37,14 +37,13 @@ */ /*---------------------------------------------------------------------------*/ #include "contiki.h" -#include "coap-engine.h" -#include "coap.h" #include "net/ipv6/uip-ds6.h" +#include "net/app-layer/coap/coap.h" +#include "net/app-layer/coap/coap-engine.h" +/*---------------------------------------------------------------------------*/ #include "coap-server.h" -#include "cc26xx-web-demo.h" - -#include "ti-lib.h" - +#include "web-demo.h" +/*---------------------------------------------------------------------------*/ #include #include /*---------------------------------------------------------------------------*/ @@ -94,7 +93,7 @@ res_get_handler_pref_parent(coap_message_t *request, coap_message_t *response, coap_get_header_accept(request, &accept); memset(def_rt_str, 0, sizeof(def_rt_str)); - cc26xx_web_demo_ipaddr_sprintf(def_rt_str, sizeof(def_rt_str), + web_demo_ipaddr_sprintf(def_rt_str, sizeof(def_rt_str), uip_ds6_defrt_choose()); if(accept == -1 || accept == TEXT_PLAIN) { diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-sensors.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-sensors.c index 9ccc79e97..27f93f8f2 100644 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-sensors.c +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-sensors.c @@ -29,19 +29,20 @@ */ /*---------------------------------------------------------------------------*/ /** - * \addtogroup cc26xx-web-demo + * \addtogroup cc13xx-cc26xx-web-demo * @{ * * \file - * CoAP resource handler for the Sensortag-CC26xx sensors + * CoAP resource handler for the Sensortag sensors */ /*---------------------------------------------------------------------------*/ #include "contiki.h" -#include "coap-engine.h" -#include "coap.h" -#include "cc26xx-web-demo.h" +#include "net/app-layer/coap/coap.h" +#include "net/app-layer/coap/coap-engine.h" +/*---------------------------------------------------------------------------*/ +#include "web-demo.h" #include "coap-server.h" - +/*---------------------------------------------------------------------------*/ #include #include #include @@ -56,9 +57,9 @@ res_get_handler_all(int sens_type, coap_message_t *request, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { unsigned int accept = -1; - const cc26xx_web_demo_sensor_reading_t *reading; + const web_demo_sensor_reading_t *reading; - reading = cc26xx_web_demo_sensor_lookup(sens_type); + reading = web_demo_sensor_lookup(sens_type); if(reading == NULL) { coap_set_status_code(response, NOT_FOUND_4_04); @@ -101,7 +102,7 @@ res_get_handler_batmon_temp(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_BATMON_TEMP, request, response, + res_get_handler_all(WEB_DEMO_SENSOR_BATMON_TEMP, request, response, buffer, preferred_size, offset); } /*---------------------------------------------------------------------------*/ @@ -110,7 +111,7 @@ res_get_handler_batmon_volt(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_BATMON_VOLT, request, response, + res_get_handler_all(WEB_DEMO_SENSOR_BATMON_VOLT, request, response, buffer, preferred_size, offset); } /*---------------------------------------------------------------------------*/ @@ -120,14 +121,14 @@ RESOURCE(res_batmon_temp, "title=\"Battery Temp\";rt=\"C\"", RESOURCE(res_batmon_volt, "title=\"Battery Voltage\";rt=\"mV\"", res_get_handler_batmon_volt, NULL, NULL, NULL); /*---------------------------------------------------------------------------*/ -#if CC26XX_WEB_DEMO_ADC_DEMO +#if WEB_DEMO_ADC_DEMO /*---------------------------------------------------------------------------*/ static void res_get_handler_adc_dio23(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_ADC_DIO23, request, response, + res_get_handler_all(WEB_DEMO_SENSOR_ADC_DIO23, request, response, buffer, preferred_size, offset); } /*---------------------------------------------------------------------------*/ @@ -144,7 +145,7 @@ res_get_handler_mpu_acc_x(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_MPU_ACC_X, request, response, + res_get_handler_all(WEB_DEMO_SENSOR_MPU_ACC_X, request, response, buffer, preferred_size, offset); } /*---------------------------------------------------------------------------*/ @@ -153,7 +154,7 @@ res_get_handler_mpu_acc_y(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_MPU_ACC_Y, request, response, + res_get_handler_all(WEB_DEMO_SENSOR_MPU_ACC_Y, request, response, buffer, preferred_size, offset); } /*---------------------------------------------------------------------------*/ @@ -162,7 +163,7 @@ res_get_handler_mpu_acc_z(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_MPU_ACC_Z, request, response, + res_get_handler_all(WEB_DEMO_SENSOR_MPU_ACC_Z, request, response, buffer, preferred_size, offset); } /*---------------------------------------------------------------------------*/ @@ -171,7 +172,7 @@ res_get_handler_mpu_gyro_x(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_MPU_GYRO_X, request, response, + res_get_handler_all(WEB_DEMO_SENSOR_MPU_GYRO_X, request, response, buffer, preferred_size, offset); } /*---------------------------------------------------------------------------*/ @@ -180,7 +181,7 @@ res_get_handler_mpu_gyro_y(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_MPU_GYRO_Y, request, response, + res_get_handler_all(WEB_DEMO_SENSOR_MPU_GYRO_Y, request, response, buffer, preferred_size, offset); } /*---------------------------------------------------------------------------*/ @@ -189,7 +190,7 @@ res_get_handler_mpu_gyro_z(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_MPU_GYRO_Z, request, response, + res_get_handler_all(WEB_DEMO_SENSOR_MPU_GYRO_Z, request, response, buffer, preferred_size, offset); } /*---------------------------------------------------------------------------*/ @@ -213,7 +214,7 @@ res_get_handler_obj_temp(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_TMP_OBJECT, request, response, + res_get_handler_all(WEB_DEMO_SENSOR_TMP_OBJECT, request, response, buffer, preferred_size, offset); } /*---------------------------------------------------------------------------*/ @@ -222,7 +223,7 @@ res_get_handler_amb_temp(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_TMP_AMBIENT, request, response, + res_get_handler_all(WEB_DEMO_SENSOR_TMP_AMBIENT, request, response, buffer, preferred_size, offset); } /*---------------------------------------------------------------------------*/ @@ -238,7 +239,7 @@ res_get_handler_bmp_temp(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_BMP_TEMP, request, response, + res_get_handler_all(WEB_DEMO_SENSOR_BMP_TEMP, request, response, buffer, preferred_size, offset); } /*---------------------------------------------------------------------------*/ @@ -247,7 +248,7 @@ res_get_handler_bmp_press(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_BMP_PRES, request, response, + res_get_handler_all(WEB_DEMO_SENSOR_BMP_PRES, request, response, buffer, preferred_size, offset); } /*---------------------------------------------------------------------------*/ @@ -264,7 +265,7 @@ res_get_handler_hdc_temp(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_HDC_TEMP, request, response, + res_get_handler_all(WEB_DEMO_SENSOR_HDC_TEMP, request, response, buffer, preferred_size, offset); } /*---------------------------------------------------------------------------*/ @@ -273,7 +274,7 @@ res_get_handler_hdc_humidity(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_HDC_HUMIDITY, request, response, + res_get_handler_all(WEB_DEMO_SENSOR_HDC_HUMIDITY, request, response, buffer, preferred_size, offset); } /*---------------------------------------------------------------------------*/ @@ -289,7 +290,7 @@ res_get_handler_opt(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_OPT_LIGHT, request, response, + res_get_handler_all(WEB_DEMO_SENSOR_OPT_LIGHT, request, response, buffer, preferred_size, offset); } /*---------------------------------------------------------------------------*/ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-toggle-leds.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-toggle-leds.c index 1c708b539..0ba4c2881 100644 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-toggle-leds.c +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-toggle-leds.c @@ -31,7 +31,7 @@ */ /*---------------------------------------------------------------------------*/ /** - * \addtogroup cc26xx-web-demo + * \addtogroup cc13xx-cc26xx-web-demo * @{ * * \file @@ -42,9 +42,9 @@ */ /*---------------------------------------------------------------------------*/ #include "contiki.h" -#include "coap-engine.h" #include "dev/leds.h" - +#include "net/app-layer/coap/coap-engine.h" +/*---------------------------------------------------------------------------*/ #include /*---------------------------------------------------------------------------*/ static void diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.c index f69a19478..54ae61066 100644 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.c +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.c @@ -28,39 +28,43 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /** - * \addtogroup cc26xx-web-demo + * \addtogroup cc13xx-cc26xx-web-demo * @{ * * \file - * Main module for the CC26XX web demo. Activates on-device resources, + * Main module for the CC13xx/CC26xx web demo. Activates on-device resources, * takes sensor readings periodically and caches them for all other modules * to use. */ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "contiki-net.h" -#include "coap-engine.h" -#include "board-peripherals.h" -#include "lib/sensors.h" -#include "lib/list.h" +#include "dev/button-hal.h" +#include "dev/ext-flash/ext-flash.h" #include "sys/process.h" #include "net/ipv6/sicslowpan.h" -#include "dev/button-hal.h" +#include "net/app-layer/coap/coap-engine.h" +#include "lib/sensors.h" +#include "lib/list.h" +/*---------------------------------------------------------------------------*/ +#include +#include +/*---------------------------------------------------------------------------*/ +#include "board-peripherals.h" #include "batmon-sensor.h" +/*---------------------------------------------------------------------------*/ +#include "web-demo.h" #include "httpd-simple.h" -#include "cc26xx-web-demo.h" #include "mqtt-client.h" #include "coap-server.h" - +/*---------------------------------------------------------------------------*/ #include #include #include #include - -#include "ti-lib.h" /*---------------------------------------------------------------------------*/ PROCESS_NAME(cetic_6lbr_client_process); -PROCESS(cc26xx_web_demo_process, "CC26XX Web Demo"); +PROCESS(web_demo_process, "CC13xx/CC26xx Web Demo"); /*---------------------------------------------------------------------------*/ /* * Update sensor readings in a staggered fashion every SENSOR_READING_PERIOD @@ -76,101 +80,101 @@ struct ctimer bmp_timer, hdc_timer, tmp_timer, opt_timer, mpu_timer; #endif /*---------------------------------------------------------------------------*/ /* Provide visible feedback via LEDS while searching for a network */ -#define NO_NET_LED_DURATION (CC26XX_WEB_DEMO_NET_CONNECT_PERIODIC >> 1) +#define NO_NET_LED_DURATION (WEB_DEMO_NET_CONNECT_PERIODIC >> 1) static struct etimer et; static struct ctimer ct; /*---------------------------------------------------------------------------*/ /* Parent RSSI functionality */ -#if CC26XX_WEB_DEMO_READ_PARENT_RSSI +#if WEB_DEMO_READ_PARENT_RSSI static struct uip_icmp6_echo_reply_notification echo_reply_notification; static struct etimer echo_request_timer; int def_rt_rssi = 0; #endif /*---------------------------------------------------------------------------*/ -#if CC26XX_WEB_DEMO_ADC_DEMO +#if WEB_DEMO_ADC_DEMO PROCESS(adc_process, "ADC process"); -static uint16_t single_adc_sample; +static uint_fast16_t single_adc_sample; static struct etimer et_adc; #endif /*---------------------------------------------------------------------------*/ -process_event_t cc26xx_web_demo_publish_event; -process_event_t cc26xx_web_demo_config_loaded_event; -process_event_t cc26xx_web_demo_load_config_defaults; +process_event_t web_demo_publish_event; +process_event_t web_demo_config_loaded_event; +process_event_t web_demo_load_config_defaults; /*---------------------------------------------------------------------------*/ /* Saved settings on flash: store, offset, magic */ #define CONFIG_FLASH_OFFSET 0 #define CONFIG_MAGIC 0xCC265002 -cc26xx_web_demo_config_t cc26xx_web_demo_config; +web_demo_config_t web_demo_config; /*---------------------------------------------------------------------------*/ /* A cache of sensor values. Updated periodically or upon key press */ LIST(sensor_list); /*---------------------------------------------------------------------------*/ /* The objects representing sensors used in this demo */ #define DEMO_SENSOR(name, type, descr, xml_element, form_field, units) \ - cc26xx_web_demo_sensor_reading_t name##_reading = \ + web_demo_sensor_reading_t name##_reading = \ { NULL, 0, 0, descr, xml_element, form_field, units, type, 1, 1 } -/* CC26xx sensors */ -DEMO_SENSOR(batmon_temp, CC26XX_WEB_DEMO_SENSOR_BATMON_TEMP, +/* CC13xx/CC26xx sensors */ +DEMO_SENSOR(batmon_temp, WEB_DEMO_SENSOR_BATMON_TEMP, "Battery Temp", "battery-temp", "batmon_temp", - CC26XX_WEB_DEMO_UNIT_TEMP); -DEMO_SENSOR(batmon_volt, CC26XX_WEB_DEMO_SENSOR_BATMON_VOLT, + WEB_DEMO_UNIT_TEMP); +DEMO_SENSOR(batmon_volt, WEB_DEMO_SENSOR_BATMON_VOLT, "Battery Volt", "battery-volt", "batmon_volt", - CC26XX_WEB_DEMO_UNIT_VOLT); + WEB_DEMO_UNIT_VOLT); -#if CC26XX_WEB_DEMO_ADC_DEMO -DEMO_SENSOR(adc_dio23, CC26XX_WEB_DEMO_SENSOR_ADC_DIO23, +#if WEB_DEMO_ADC_DEMO +DEMO_SENSOR(adc_dio23, WEB_DEMO_SENSOR_ADC_DIO23, "ADC DIO23", "adc-dio23", "adc_dio23", - CC26XX_WEB_DEMO_UNIT_VOLT); + WEB_DEMO_UNIT_VOLT); #endif /* Sensortag sensors */ #if BOARD_SENSORTAG -DEMO_SENSOR(bmp_pres, CC26XX_WEB_DEMO_SENSOR_BMP_PRES, +DEMO_SENSOR(bmp_pres, WEB_DEMO_SENSOR_BMP_PRES, "Air Pressure", "air-pressure", "bmp_pres", - CC26XX_WEB_DEMO_UNIT_PRES); -DEMO_SENSOR(bmp_temp, CC26XX_WEB_DEMO_SENSOR_BMP_TEMP, + WEB_DEMO_UNIT_PRES); +DEMO_SENSOR(bmp_temp, WEB_DEMO_SENSOR_BMP_TEMP, "Air Temp", "air-temp", "bmp_temp", - CC26XX_WEB_DEMO_UNIT_TEMP); -DEMO_SENSOR(hdc_temp, CC26XX_WEB_DEMO_SENSOR_HDC_TEMP, + WEB_DEMO_UNIT_TEMP); +DEMO_SENSOR(hdc_temp, WEB_DEMO_SENSOR_HDC_TEMP, "HDC Temp", "hdc-temp", "hdc_temp", - CC26XX_WEB_DEMO_UNIT_TEMP); -DEMO_SENSOR(hdc_hum, CC26XX_WEB_DEMO_SENSOR_HDC_HUMIDITY, + WEB_DEMO_UNIT_TEMP); +DEMO_SENSOR(hdc_hum, WEB_DEMO_SENSOR_HDC_HUMIDITY, "HDC Humidity", "hdc-humidity", "hdc_hum", - CC26XX_WEB_DEMO_UNIT_HUMIDITY); -DEMO_SENSOR(tmp_amb, CC26XX_WEB_DEMO_SENSOR_TMP_AMBIENT, + WEB_DEMO_UNIT_HUMIDITY); +DEMO_SENSOR(tmp_amb, WEB_DEMO_SENSOR_TMP_AMBIENT, "Ambient Temp", "ambient-temp", "tmp_amb", - CC26XX_WEB_DEMO_UNIT_TEMP); -DEMO_SENSOR(tmp_obj, CC26XX_WEB_DEMO_SENSOR_TMP_OBJECT, + WEB_DEMO_UNIT_TEMP); +DEMO_SENSOR(tmp_obj, WEB_DEMO_SENSOR_TMP_OBJECT, "Object Temp", "object-temp", "tmp_obj", - CC26XX_WEB_DEMO_UNIT_TEMP); -DEMO_SENSOR(opt, CC26XX_WEB_DEMO_SENSOR_OPT_LIGHT, + WEB_DEMO_UNIT_TEMP); +DEMO_SENSOR(opt, WEB_DEMO_SENSOR_OPT_LIGHT, "Light", "light", "light", - CC26XX_WEB_DEMO_UNIT_LIGHT); + WEB_DEMO_UNIT_LIGHT); /* MPU Readings */ -DEMO_SENSOR(mpu_acc_x, CC26XX_WEB_DEMO_SENSOR_MPU_ACC_X, +DEMO_SENSOR(mpu_acc_x, WEB_DEMO_SENSOR_MPU_ACC_X, "Acc X", "acc-x", "acc_x", - CC26XX_WEB_DEMO_UNIT_ACC); -DEMO_SENSOR(mpu_acc_y, CC26XX_WEB_DEMO_SENSOR_MPU_ACC_Y, + WEB_DEMO_UNIT_ACC); +DEMO_SENSOR(mpu_acc_y, WEB_DEMO_SENSOR_MPU_ACC_Y, "Acc Y", "acc-y", "acc_y", - CC26XX_WEB_DEMO_UNIT_ACC); -DEMO_SENSOR(mpu_acc_z, CC26XX_WEB_DEMO_SENSOR_MPU_ACC_Z, + WEB_DEMO_UNIT_ACC); +DEMO_SENSOR(mpu_acc_z, WEB_DEMO_SENSOR_MPU_ACC_Z, "Acc Z", "acc-z", "acc_z", - CC26XX_WEB_DEMO_UNIT_ACC); + WEB_DEMO_UNIT_ACC); -DEMO_SENSOR(mpu_gyro_x, CC26XX_WEB_DEMO_SENSOR_MPU_GYRO_X, +DEMO_SENSOR(mpu_gyro_x, WEB_DEMO_SENSOR_MPU_GYRO_X, "Gyro X", "gyro-x", "gyro_x", - CC26XX_WEB_DEMO_UNIT_GYRO); -DEMO_SENSOR(mpu_gyro_y, CC26XX_WEB_DEMO_SENSOR_MPU_GYRO_Y, + WEB_DEMO_UNIT_GYRO); +DEMO_SENSOR(mpu_gyro_y, WEB_DEMO_SENSOR_MPU_GYRO_Y, "Gyro Y", "gyro-y", "gyro_y", - CC26XX_WEB_DEMO_UNIT_GYRO); -DEMO_SENSOR(mpu_gyro_z, CC26XX_WEB_DEMO_SENSOR_MPU_GYRO_Z, + WEB_DEMO_UNIT_GYRO); +DEMO_SENSOR(mpu_gyro_z, WEB_DEMO_SENSOR_MPU_GYRO_Z, "Gyro Z", "gyro-z", "gyro_Z", - CC26XX_WEB_DEMO_UNIT_GYRO); + WEB_DEMO_UNIT_GYRO); #endif /*---------------------------------------------------------------------------*/ #if BOARD_SENSORTAG @@ -184,7 +188,7 @@ static void init_mpu_reading(void *data); static void publish_led_off(void *d) { - leds_off(CC26XX_WEB_DEMO_STATUS_LED); + leds_off(WEB_DEMO_STATUS_LED); } /*---------------------------------------------------------------------------*/ static void @@ -193,7 +197,7 @@ save_config() /* Dump current running config to flash */ #if BOARD_SENSORTAG || BOARD_LAUNCHPAD int rv; - cc26xx_web_demo_sensor_reading_t *reading = NULL; + web_demo_sensor_reading_t *reading = NULL; rv = ext_flash_open(NULL); @@ -203,25 +207,25 @@ save_config() return; } - rv = ext_flash_erase(NULL, CONFIG_FLASH_OFFSET, sizeof(cc26xx_web_demo_config_t)); + rv = ext_flash_erase(NULL, CONFIG_FLASH_OFFSET, sizeof(web_demo_config_t)); if(!rv) { printf("Error erasing flash\n"); } else { - cc26xx_web_demo_config.magic = CONFIG_MAGIC; - cc26xx_web_demo_config.len = sizeof(cc26xx_web_demo_config_t); - cc26xx_web_demo_config.sensors_bitmap = 0; + web_demo_config.magic = CONFIG_MAGIC; + web_demo_config.len = sizeof(web_demo_config_t); + web_demo_config.sensors_bitmap = 0; for(reading = list_head(sensor_list); reading != NULL; reading = list_item_next(reading)) { if(reading->publish) { - cc26xx_web_demo_config.sensors_bitmap |= (1 << reading->type); + web_demo_config.sensors_bitmap |= (1 << reading->type); } } - rv = ext_flash_write(NULL, CONFIG_FLASH_OFFSET, sizeof(cc26xx_web_demo_config_t), - (uint8_t *)&cc26xx_web_demo_config); + rv = ext_flash_write(NULL, CONFIG_FLASH_OFFSET, sizeof(web_demo_config_t), + (uint8_t *)&web_demo_config); if(!rv) { printf("Error saving config\n"); } @@ -236,8 +240,8 @@ load_config() { #if BOARD_SENSORTAG || BOARD_LAUNCHPAD /* Read from flash into a temp buffer */ - cc26xx_web_demo_config_t tmp_cfg; - cc26xx_web_demo_sensor_reading_t *reading = NULL; + web_demo_config_t tmp_cfg; + web_demo_sensor_reading_t *reading = NULL; int rv = ext_flash_open(NULL); @@ -258,27 +262,27 @@ load_config() } if(tmp_cfg.magic == CONFIG_MAGIC && tmp_cfg.len == sizeof(tmp_cfg)) { - memcpy(&cc26xx_web_demo_config, &tmp_cfg, sizeof(cc26xx_web_demo_config)); + memcpy(&web_demo_config, &tmp_cfg, sizeof(web_demo_config)); } for(reading = list_head(sensor_list); reading != NULL; reading = list_item_next(reading)) { - if(cc26xx_web_demo_config.sensors_bitmap & (1 << reading->type)) { + if(web_demo_config.sensors_bitmap & (1 << reading->type)) { reading->publish = 1; } else { reading->publish = 0; - snprintf(reading->converted, CC26XX_WEB_DEMO_CONVERTED_LEN, "\"N/A\""); + snprintf(reading->converted, WEB_DEMO_CONVERTED_LEN, "\"N/A\""); } } #endif } /*---------------------------------------------------------------------------*/ /* Don't start everything here, we need to dictate order of initialisation */ -AUTOSTART_PROCESSES(&cc26xx_web_demo_process); +AUTOSTART_PROCESSES(&web_demo_process); /*---------------------------------------------------------------------------*/ int -cc26xx_web_demo_ipaddr_sprintf(char *buf, uint8_t buf_len, +web_demo_ipaddr_sprintf(char *buf, uint8_t buf_len, const uip_ipaddr_t *addr) { uint16_t a; @@ -303,10 +307,10 @@ cc26xx_web_demo_ipaddr_sprintf(char *buf, uint8_t buf_len, return len; } /*---------------------------------------------------------------------------*/ -const cc26xx_web_demo_sensor_reading_t * -cc26xx_web_demo_sensor_lookup(int sens_type) +const web_demo_sensor_reading_t * +web_demo_sensor_lookup(int sens_type) { - cc26xx_web_demo_sensor_reading_t *reading = NULL; + web_demo_sensor_reading_t *reading = NULL; for(reading = list_head(sensor_list); reading != NULL; @@ -319,16 +323,16 @@ cc26xx_web_demo_sensor_lookup(int sens_type) return NULL; } /*---------------------------------------------------------------------------*/ -const cc26xx_web_demo_sensor_reading_t * -cc26xx_web_demo_sensor_first() +const web_demo_sensor_reading_t * +web_demo_sensor_first() { return list_head(sensor_list); } /*---------------------------------------------------------------------------*/ void -cc26xx_web_demo_restore_defaults(void) +web_demo_restore_defaults(void) { - cc26xx_web_demo_sensor_reading_t *reading = NULL; + web_demo_sensor_reading_t *reading = NULL; leds_on(LEDS_ALL); @@ -338,13 +342,13 @@ cc26xx_web_demo_restore_defaults(void) reading->publish = 1; } -#if CC26XX_WEB_DEMO_MQTT_CLIENT +#if WEB_DEMO_MQTT_CLIENT process_post_synch(&mqtt_client_process, - cc26xx_web_demo_load_config_defaults, NULL); + web_demo_load_config_defaults, NULL); #endif -#if CC26XX_WEB_DEMO_NET_UART - process_post_synch(&net_uart_process, cc26xx_web_demo_load_config_defaults, +#if WEB_DEMO_NET_UART + process_post_synch(&net_uart_process, web_demo_load_config_defaults, NULL); #endif @@ -362,7 +366,7 @@ defaults_post_handler(char *key, int key_len, char *val, int val_len) return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; } - cc26xx_web_demo_restore_defaults(); + web_demo_restore_defaults(); return HTTPD_SIMPLE_POST_HANDLER_OK; } @@ -370,7 +374,7 @@ defaults_post_handler(char *key, int key_len, char *val, int val_len) static int sensor_readings_handler(char *key, int key_len, char *val, int val_len) { - cc26xx_web_demo_sensor_reading_t *reading = NULL; + web_demo_sensor_reading_t *reading = NULL; int rv; for(reading = list_head(sensor_list); @@ -384,7 +388,7 @@ sensor_readings_handler(char *key, int key_len, char *val, int val_len) /* Be pedantic: only accept 0 and 1, not just any non-zero value */ if(rv == 0) { reading->publish = 0; - snprintf(reading->converted, CC26XX_WEB_DEMO_CONVERTED_LEN, "\"N/A\""); + snprintf(reading->converted, WEB_DEMO_CONVERTED_LEN, "\"N/A\""); } else if(rv == 1) { reading->publish = 1; } else { @@ -398,7 +402,7 @@ sensor_readings_handler(char *key, int key_len, char *val, int val_len) return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; } /*---------------------------------------------------------------------------*/ -#if CC26XX_WEB_DEMO_READ_PARENT_RSSI +#if WEB_DEMO_READ_PARENT_RSSI static int ping_interval_post_handler(char *key, int key_len, char *val, int val_len) { @@ -412,12 +416,12 @@ ping_interval_post_handler(char *key, int key_len, char *val, int val_len) rv = atoi(val); - if(rv < CC26XX_WEB_DEMO_RSSI_MEASURE_INTERVAL_MIN || - rv > CC26XX_WEB_DEMO_RSSI_MEASURE_INTERVAL_MAX) { + if(rv < WEB_DEMO_RSSI_MEASURE_INTERVAL_MIN || + rv > WEB_DEMO_RSSI_MEASURE_INTERVAL_MAX) { return HTTPD_SIMPLE_POST_HANDLER_ERROR; } - cc26xx_web_demo_config.def_rt_ping_interval = rv * CLOCK_SECOND; + web_demo_config.def_rt_ping_interval = rv * CLOCK_SECOND; return HTTPD_SIMPLE_POST_HANDLER_OK; } @@ -426,7 +430,7 @@ ping_interval_post_handler(char *key, int key_len, char *val, int val_len) HTTPD_SIMPLE_POST_HANDLER(sensor, sensor_readings_handler); HTTPD_SIMPLE_POST_HANDLER(defaults, defaults_post_handler); -#if CC26XX_WEB_DEMO_READ_PARENT_RSSI +#if WEB_DEMO_READ_PARENT_RSSI HTTPD_SIMPLE_POST_HANDLER(ping_interval, ping_interval_post_handler); /*---------------------------------------------------------------------------*/ static void @@ -446,7 +450,7 @@ ping_parent(void) } uip_icmp6_send(uip_ds6_defrt_choose(), ICMP6_ECHO_REQUEST, 0, - CC26XX_WEB_DEMO_ECHO_REQ_PAYLOAD_LEN); + WEB_DEMO_ECHO_REQ_PAYLOAD_LEN); } #endif /*---------------------------------------------------------------------------*/ @@ -460,30 +464,30 @@ get_batmon_reading(void *data) if(batmon_temp_reading.publish) { value = batmon_sensor.value(BATMON_SENSOR_TYPE_TEMP); - if(value != CC26XX_SENSOR_READING_ERROR) { + if(value != BATMON_SENSOR_READING_ERROR) { batmon_temp_reading.raw = value; buf = batmon_temp_reading.converted; - memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); - snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d", value); + memset(buf, 0, WEB_DEMO_CONVERTED_LEN); + snprintf(buf, WEB_DEMO_CONVERTED_LEN, "%d", value); } } if(batmon_volt_reading.publish) { value = batmon_sensor.value(BATMON_SENSOR_TYPE_VOLT); - if(value != CC26XX_SENSOR_READING_ERROR) { + if(value != BATMON_SENSOR_READING_ERROR) { batmon_volt_reading.raw = value; buf = batmon_volt_reading.converted; - memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); - snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d", (value * 125) >> 5); + memset(buf, 0, WEB_DEMO_CONVERTED_LEN); + snprintf(buf, WEB_DEMO_CONVERTED_LEN, "%d", (value * 125) >> 5); } } ctimer_set(&batmon_timer, next, get_batmon_reading, NULL); } /*---------------------------------------------------------------------------*/ -#if CC26XX_WEB_DEMO_ADC_DEMO +#if WEB_DEMO_ADC_DEMO static void get_adc_reading(void *data) { @@ -493,8 +497,8 @@ get_adc_reading(void *data) if(adc_dio23_reading.publish) { value = single_adc_sample; buf = adc_dio23_reading.converted; - memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); - snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d", (value * 4300) >> 12); + memset(buf, 0, WEB_DEMO_CONVERTED_LEN); + snprintf(buf, WEB_DEMO_CONVERTED_LEN, "%d", (value * 4300) >> 12); } } #endif @@ -502,7 +506,7 @@ get_adc_reading(void *data) #if BOARD_SENSORTAG /*---------------------------------------------------------------------------*/ static void -compare_and_update(cc26xx_web_demo_sensor_reading_t *reading) +compare_and_update(web_demo_sensor_reading_t *reading) { if(reading->last == reading->raw) { reading->changed = 0; @@ -536,28 +540,28 @@ get_bmp_reading() if(bmp_pres_reading.publish) { value = bmp_280_sensor.value(BMP_280_SENSOR_TYPE_PRESS); - if(value != CC26XX_SENSOR_READING_ERROR) { + if(value != BMP_280_READING_ERROR) { bmp_pres_reading.raw = value; compare_and_update(&bmp_pres_reading); buf = bmp_pres_reading.converted; - memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); - snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d.%02d", value / 100, + memset(buf, 0, WEB_DEMO_CONVERTED_LEN); + snprintf(buf, WEB_DEMO_CONVERTED_LEN, "%d.%02d", value / 100, value % 100); } } if(bmp_temp_reading.publish) { value = bmp_280_sensor.value(BMP_280_SENSOR_TYPE_TEMP); - if(value != CC26XX_SENSOR_READING_ERROR) { + if(value != BMP_280_READING_ERROR) { bmp_temp_reading.raw = value; compare_and_update(&bmp_temp_reading); buf = bmp_temp_reading.converted; - memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); - snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d.%02d", value / 100, + memset(buf, 0, WEB_DEMO_CONVERTED_LEN); + snprintf(buf, WEB_DEMO_CONVERTED_LEN, "%d.%02d", value / 100, value % 100); } } @@ -577,7 +581,7 @@ get_tmp_reading() if(tmp_amb_reading.publish || tmp_obj_reading.publish) { if(tmp_007_sensor.value(TMP_007_SENSOR_TYPE_ALL) == - CC26XX_SENSOR_READING_ERROR) { + TMP_007_READING_ERROR) { SENSORS_DEACTIVATE(tmp_007_sensor); ctimer_set(&tmp_timer, next, init_tmp_reading, NULL); @@ -591,8 +595,8 @@ get_tmp_reading() compare_and_update(&tmp_amb_reading); buf = tmp_amb_reading.converted; - memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); - snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d.%03d", value / 1000, + memset(buf, 0, WEB_DEMO_CONVERTED_LEN); + snprintf(buf, WEB_DEMO_CONVERTED_LEN, "%d.%03d", value / 1000, value % 1000); } @@ -603,8 +607,8 @@ get_tmp_reading() compare_and_update(&tmp_obj_reading); buf = tmp_obj_reading.converted; - memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); - snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d.%03d", value / 1000, + memset(buf, 0, WEB_DEMO_CONVERTED_LEN); + snprintf(buf, WEB_DEMO_CONVERTED_LEN, "%d.%03d", value / 1000, value % 1000); } @@ -623,28 +627,28 @@ get_hdc_reading() if(hdc_temp_reading.publish) { value = hdc_1000_sensor.value(HDC_1000_SENSOR_TYPE_TEMP); - if(value != CC26XX_SENSOR_READING_ERROR) { + if(value != HDC_1000_READING_ERROR) { hdc_temp_reading.raw = value; compare_and_update(&hdc_temp_reading); buf = hdc_temp_reading.converted; - memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); - snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d.%02d", value / 100, + memset(buf, 0, WEB_DEMO_CONVERTED_LEN); + snprintf(buf, WEB_DEMO_CONVERTED_LEN, "%d.%02d", value / 100, value % 100); } } if(hdc_hum_reading.publish) { value = hdc_1000_sensor.value(HDC_1000_SENSOR_TYPE_HUMIDITY); - if(value != CC26XX_SENSOR_READING_ERROR) { + if(value != HDC_1000_READING_ERROR) { hdc_hum_reading.raw = value; compare_and_update(&hdc_hum_reading); buf = hdc_hum_reading.converted; - memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); - snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d.%02d", value / 100, + memset(buf, 0, WEB_DEMO_CONVERTED_LEN); + snprintf(buf, WEB_DEMO_CONVERTED_LEN, "%d.%02d", value / 100, value % 100); } } @@ -662,14 +666,14 @@ get_light_reading() value = opt_3001_sensor.value(0); - if(value != CC26XX_SENSOR_READING_ERROR) { + if(value != OPT_3001_READING_ERROR) { opt_reading.raw = value; compare_and_update(&opt_reading); buf = opt_reading.converted; - memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); - snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d.%02d", value / 100, + memset(buf, 0, WEB_DEMO_CONVERTED_LEN); + snprintf(buf, WEB_DEMO_CONVERTED_LEN, "%d.%02d", value / 100, value % 100); } @@ -686,42 +690,42 @@ get_mpu_reading() if(mpu_gyro_x_reading.publish) { raw = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_GYRO_X); - if(raw != CC26XX_SENSOR_READING_ERROR) { + if(raw != MPU_9250_READING_ERROR) { mpu_gyro_x_reading.raw = raw; } } if(mpu_gyro_y_reading.publish) { raw = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_GYRO_Y); - if(raw != CC26XX_SENSOR_READING_ERROR) { + if(raw != MPU_9250_READING_ERROR) { mpu_gyro_y_reading.raw = raw; } } if(mpu_gyro_z_reading.publish) { raw = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_GYRO_Z); - if(raw != CC26XX_SENSOR_READING_ERROR) { + if(raw != MPU_9250_READING_ERROR) { mpu_gyro_z_reading.raw = raw; } } if(mpu_acc_x_reading.publish) { raw = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_ACC_X); - if(raw != CC26XX_SENSOR_READING_ERROR) { + if(raw != MPU_9250_READING_ERROR) { mpu_acc_x_reading.raw = raw; } } if(mpu_acc_y_reading.publish) { raw = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_ACC_Y); - if(raw != CC26XX_SENSOR_READING_ERROR) { + if(raw != MPU_9250_READING_ERROR) { mpu_acc_y_reading.raw = raw; } } if(mpu_acc_z_reading.publish) { raw = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_ACC_Z); - if(raw != CC26XX_SENSOR_READING_ERROR) { + if(raw != MPU_9250_READING_ERROR) { mpu_acc_z_reading.raw = raw; } } @@ -730,37 +734,37 @@ get_mpu_reading() if(mpu_gyro_x_reading.publish) { compare_and_update(&mpu_gyro_x_reading); - memset(mpu_gyro_x_reading.converted, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); + memset(mpu_gyro_x_reading.converted, 0, WEB_DEMO_CONVERTED_LEN); print_mpu_reading(mpu_gyro_x_reading.raw, mpu_gyro_x_reading.converted); } if(mpu_gyro_y_reading.publish) { compare_and_update(&mpu_gyro_y_reading); - memset(mpu_gyro_y_reading.converted, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); + memset(mpu_gyro_y_reading.converted, 0, WEB_DEMO_CONVERTED_LEN); print_mpu_reading(mpu_gyro_y_reading.raw, mpu_gyro_y_reading.converted); } if(mpu_gyro_z_reading.publish) { compare_and_update(&mpu_gyro_z_reading); - memset(mpu_gyro_z_reading.converted, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); + memset(mpu_gyro_z_reading.converted, 0, WEB_DEMO_CONVERTED_LEN); print_mpu_reading(mpu_gyro_z_reading.raw, mpu_gyro_z_reading.converted); } if(mpu_acc_x_reading.publish) { compare_and_update(&mpu_acc_x_reading); - memset(mpu_acc_x_reading.converted, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); + memset(mpu_acc_x_reading.converted, 0, WEB_DEMO_CONVERTED_LEN); print_mpu_reading(mpu_acc_x_reading.raw, mpu_acc_x_reading.converted); } if(mpu_acc_y_reading.publish) { compare_and_update(&mpu_acc_y_reading); - memset(mpu_acc_y_reading.converted, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); + memset(mpu_acc_y_reading.converted, 0, WEB_DEMO_CONVERTED_LEN); print_mpu_reading(mpu_acc_y_reading.raw, mpu_acc_y_reading.converted); } if(mpu_acc_z_reading.publish) { compare_and_update(&mpu_acc_z_reading); - memset(mpu_acc_z_reading.converted, 0, CC26XX_WEB_DEMO_CONVERTED_LEN); + memset(mpu_acc_z_reading.converted, 0, WEB_DEMO_CONVERTED_LEN); print_mpu_reading(mpu_acc_z_reading.raw, mpu_acc_z_reading.converted); } @@ -858,7 +862,7 @@ init_sensors(void) list_add(sensor_list, &batmon_temp_reading); list_add(sensor_list, &batmon_volt_reading); -#if CC26XX_WEB_DEMO_ADC_DEMO +#if WEB_DEMO_ADC_DEMO list_add(sensor_list, &adc_dio23_reading); #endif @@ -885,38 +889,38 @@ init_sensors(void) #endif } /*---------------------------------------------------------------------------*/ -PROCESS_THREAD(cc26xx_web_demo_process, ev, data) +PROCESS_THREAD(web_demo_process, ev, data) { PROCESS_BEGIN(); - printf("CC26XX Web Demo Process\n"); + printf("CC13xx/CC26xx Web Demo Process\n"); init_sensors(); - cc26xx_web_demo_publish_event = process_alloc_event(); - cc26xx_web_demo_config_loaded_event = process_alloc_event(); - cc26xx_web_demo_load_config_defaults = process_alloc_event(); + web_demo_publish_event = process_alloc_event(); + web_demo_config_loaded_event = process_alloc_event(); + web_demo_load_config_defaults = process_alloc_event(); /* Start all other (enabled) processes first */ process_start(&httpd_simple_process, NULL); -#if CC26XX_WEB_DEMO_COAP_SERVER +#if WEB_DEMO_COAP_SERVER process_start(&coap_server_process, NULL); #endif -#if CC26XX_WEB_DEMO_6LBR_CLIENT +#if WEB_DEMO_6LBR_CLIENT process_start(&cetic_6lbr_client_process, NULL); #endif -#if CC26XX_WEB_DEMO_MQTT_CLIENT +#if WEB_DEMO_MQTT_CLIENT process_start(&mqtt_client_process, NULL); #endif -#if CC26XX_WEB_DEMO_NET_UART +#if WEB_DEMO_NET_UART process_start(&net_uart_process, NULL); #endif -#if CC26XX_WEB_DEMO_ADC_DEMO +#if WEB_DEMO_ADC_DEMO process_start(&adc_process, NULL); #endif @@ -924,32 +928,32 @@ PROCESS_THREAD(cc26xx_web_demo_process, ev, data) * Now that processes have set their own config default values, set our * own defaults and restore saved config from flash... */ - cc26xx_web_demo_config.sensors_bitmap = 0xFFFFFFFF; /* all on by default */ - cc26xx_web_demo_config.def_rt_ping_interval = - CC26XX_WEB_DEMO_DEFAULT_RSSI_MEAS_INTERVAL; + web_demo_config.sensors_bitmap = 0xFFFFFFFF; /* all on by default */ + web_demo_config.def_rt_ping_interval = + WEB_DEMO_DEFAULT_RSSI_MEAS_INTERVAL; load_config(); /* * Notify all other processes (basically the ones in this demo) that the * configuration has been loaded from flash, in case they care */ - process_post(PROCESS_BROADCAST, cc26xx_web_demo_config_loaded_event, NULL); + process_post(PROCESS_BROADCAST, web_demo_config_loaded_event, NULL); init_sensor_readings(); httpd_simple_register_post_handler(&sensor_handler); httpd_simple_register_post_handler(&defaults_handler); -#if CC26XX_WEB_DEMO_READ_PARENT_RSSI +#if WEB_DEMO_READ_PARENT_RSSI httpd_simple_register_post_handler(&ping_interval_handler); def_rt_rssi = 0x8000000; uip_icmp6_echo_reply_callback_add(&echo_reply_notification, echo_reply_handler); - etimer_set(&echo_request_timer, CC26XX_WEB_DEMO_NET_CONNECT_PERIODIC); + etimer_set(&echo_request_timer, WEB_DEMO_NET_CONNECT_PERIODIC); #endif - etimer_set(&et, CC26XX_WEB_DEMO_NET_CONNECT_PERIODIC); + etimer_set(&et, WEB_DEMO_NET_CONNECT_PERIODIC); /* * Update all sensor readings on a configurable sensors_event @@ -958,33 +962,33 @@ PROCESS_THREAD(cc26xx_web_demo_process, ev, data) while(1) { if(ev == PROCESS_EVENT_TIMER && etimer_expired(&et)) { if(uip_ds6_get_global(ADDR_PREFERRED) == NULL) { - leds_on(CC26XX_WEB_DEMO_STATUS_LED); + leds_on(WEB_DEMO_STATUS_LED); ctimer_set(&ct, NO_NET_LED_DURATION, publish_led_off, NULL); - etimer_set(&et, CC26XX_WEB_DEMO_NET_CONNECT_PERIODIC); + etimer_set(&et, WEB_DEMO_NET_CONNECT_PERIODIC); } } -#if CC26XX_WEB_DEMO_READ_PARENT_RSSI +#if WEB_DEMO_READ_PARENT_RSSI if(ev == PROCESS_EVENT_TIMER && etimer_expired(&echo_request_timer)) { if(uip_ds6_get_global(ADDR_PREFERRED) == NULL) { - etimer_set(&echo_request_timer, CC26XX_WEB_DEMO_NET_CONNECT_PERIODIC); + etimer_set(&echo_request_timer, WEB_DEMO_NET_CONNECT_PERIODIC); } else { ping_parent(); - etimer_set(&echo_request_timer, cc26xx_web_demo_config.def_rt_ping_interval); + etimer_set(&echo_request_timer, web_demo_config.def_rt_ping_interval); } } #endif if(ev == button_hal_release_event && ((button_hal_button_t *)data)->unique_id == - CC26XX_WEB_DEMO_SENSOR_READING_TRIGGER) { + WEB_DEMO_SENSOR_READING_TRIGGER) { init_sensor_readings(); - process_post(PROCESS_BROADCAST, cc26xx_web_demo_publish_event, NULL); + process_post(PROCESS_BROADCAST, web_demo_publish_event, NULL); } else if(ev == button_hal_periodic_event && ((button_hal_button_t *)data)->unique_id == - CC26XX_WEB_DEMO_SENSOR_READING_TRIGGER) { + WEB_DEMO_SENSOR_READING_TRIGGER) { printf("Restoring defaults!\n"); - cc26xx_web_demo_restore_defaults(); + web_demo_restore_defaults(); } else if(ev == httpd_simple_event_new_config) { save_config(); #if BOARD_SENSORTAG @@ -1007,48 +1011,36 @@ PROCESS_THREAD(cc26xx_web_demo_process, ev, data) PROCESS_END(); } /*---------------------------------------------------------------------------*/ -#if CC26XX_WEB_DEMO_ADC_DEMO +#if WEB_DEMO_ADC_DEMO PROCESS_THREAD(adc_process, ev, data) { + static ADC_Params adc_params; + ADC_Handle adc_handle; + int_fast16_t res; + uint_fast16_t adc_value; + PROCESS_BEGIN(); + ADC_init(); + ADC_Params_init(&adc_params); + etimer_set(&et_adc, CLOCK_SECOND * 5); while(1) { - PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et_adc)); - /* intialisation of ADC */ - ti_lib_aon_wuc_aux_wakeup_event(AONWUC_AUX_WAKEUP); - while(!(ti_lib_aon_wuc_power_status_get() & AONWUC_AUX_POWER_ON)); + adc_handle = ADC_open(Board_ADC0, &adc_params); - /* - * Enable clock for ADC digital and analog interface (not currently enabled - * in driver) - */ - ti_lib_aux_wuc_clock_enable(AUX_WUC_ADI_CLOCK | AUX_WUC_ANAIF_CLOCK | - AUX_WUC_SMPH_CLOCK); - while(ti_lib_aux_wuc_clock_status(AUX_WUC_ADI_CLOCK | AUX_WUC_ANAIF_CLOCK | - AUX_WUC_SMPH_CLOCK) - != AUX_WUC_CLOCK_READY); + if(adc_handle != NULL) { + res = ADC_convert(adc_handle, &single_adc_sample); - /* Connect AUX IO7 (DIO23, but also DP2 on XDS110) as analog input. */ - ti_lib_aux_adc_select_input(ADC_COMPB_IN_AUXIO7); + if(res == ADC_STATUS_SUCCESS) { + single_adc_sample = adc_value; + get_adc_reading(NULL); + } - /* Set up ADC range, AUXADC_REF_FIXED = nominally 4.3 V */ - ti_lib_aux_adc_enable_sync(AUXADC_REF_FIXED, AUXADC_SAMPLE_TIME_2P7_US, - AUXADC_TRIGGER_MANUAL); - - /* Trigger ADC converting */ - ti_lib_aux_adc_gen_manual_trigger(); - - /* Read value */ - single_adc_sample = ti_lib_aux_adc_read_fifo(); - - /* Shut the adc down */ - ti_lib_aux_adc_disable(); - - get_adc_reading(NULL); + ADC_close(adc_handle); + } etimer_reset(&et_adc); } diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.h b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.h index 1840c31b1..ab2c88342 100644 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.h +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.h @@ -28,14 +28,14 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /** - * \addtogroup cc26xx-examples + * \addtogroup cc13xx-cc26xx-examples * @{ * - * \defgroup cc26xx-web-demo CC26xx Web Demo + * \defgroup cc13xx-cc26xx-web-demo CC13xx/CC26xx Web Demo * @{ * * An example demonstrating: - * * how to use a CC26XX-powered node in a deployment driven by a 6LBR + * * how to use a CC13xx/CC26xx-powered node in a deployment driven by a 6LBR * * how to expose on-device sensors as CoAP resources * * how to build a small web page which reports networking and sensory data * * how to configure functionality through the aforementioned web page using @@ -43,93 +43,94 @@ * * a network-based UART * * \file - * Main header file for the CC26XX web demo. + * Main header file for the CC13xx/CC26xx web demo. */ /*---------------------------------------------------------------------------*/ -#ifndef CC26XX_WEB_DEMO_H_ -#define CC26XX_WEB_DEMO_H_ +#ifndef WEB_DEMO_H_ +#define WEB_DEMO_H_ /*---------------------------------------------------------------------------*/ #include "dev/leds.h" #include "sys/process.h" +/*---------------------------------------------------------------------------*/ #include "mqtt-client.h" #include "net-uart.h" - +/*---------------------------------------------------------------------------*/ #include /*---------------------------------------------------------------------------*/ -#ifdef CC26XX_WEB_DEMO_CONF_MQTT_CLIENT -#define CC26XX_WEB_DEMO_MQTT_CLIENT CC26XX_WEB_DEMO_CONF_MQTT_CLIENT +#ifdef WEB_DEMO_CONF_MQTT_CLIENT +#define WEB_DEMO_MQTT_CLIENT WEB_DEMO_CONF_MQTT_CLIENT #else -#define CC26XX_WEB_DEMO_MQTT_CLIENT 1 +#define WEB_DEMO_MQTT_CLIENT 1 #endif -#ifdef CC26XX_WEB_DEMO_CONF_6LBR_CLIENT -#define CC26XX_WEB_DEMO_6LBR_CLIENT CC26XX_WEB_DEMO_CONF_6LBR_CLIENT +#ifdef WEB_DEMO_CONF_6LBR_CLIENT +#define WEB_DEMO_6LBR_CLIENT WEB_DEMO_CONF_6LBR_CLIENT #else -#define CC26XX_WEB_DEMO_6LBR_CLIENT 1 +#define WEB_DEMO_6LBR_CLIENT 1 #endif -#ifdef CC26XX_WEB_DEMO_CONF_COAP_SERVER -#define CC26XX_WEB_DEMO_COAP_SERVER CC26XX_WEB_DEMO_CONF_COAP_SERVER +#ifdef WEB_DEMO_CONF_COAP_SERVER +#define WEB_DEMO_COAP_SERVER WEB_DEMO_CONF_COAP_SERVER #else -#define CC26XX_WEB_DEMO_COAP_SERVER 1 +#define WEB_DEMO_COAP_SERVER 1 #endif -#ifdef CC26XX_WEB_DEMO_CONF_NET_UART -#define CC26XX_WEB_DEMO_NET_UART CC26XX_WEB_DEMO_CONF_NET_UART +#ifdef WEB_DEMO_CONF_NET_UART +#define WEB_DEMO_NET_UART WEB_DEMO_CONF_NET_UART #else -#define CC26XX_WEB_DEMO_NET_UART 1 +#define WEB_DEMO_NET_UART 1 #endif -#ifdef CC26XX_WEB_DEMO_CONF_ADC_DEMO -#define CC26XX_WEB_DEMO_ADC_DEMO CC26XX_WEB_DEMO_CONF_ADC_DEMO +#ifdef WEB_DEMO_CONF_ADC_DEMO +#define WEB_DEMO_ADC_DEMO WEB_DEMO_CONF_ADC_DEMO #else -#define CC26XX_WEB_DEMO_ADC_DEMO 0 +#define WEB_DEMO_ADC_DEMO 0 #endif /*---------------------------------------------------------------------------*/ /* Active probing of RSSI from our preferred parent */ -#if (CC26XX_WEB_DEMO_COAP_SERVER || CC26XX_WEB_DEMO_MQTT_CLIENT) -#define CC26XX_WEB_DEMO_READ_PARENT_RSSI 1 +#if (WEB_DEMO_COAP_SERVER || WEB_DEMO_MQTT_CLIENT) +#define WEB_DEMO_READ_PARENT_RSSI 1 #else -#define CC26XX_WEB_DEMO_READ_PARENT_RSSI 0 +#define WEB_DEMO_READ_PARENT_RSSI 0 #endif -#define CC26XX_WEB_DEMO_RSSI_MEASURE_INTERVAL_MAX 86400 /* secs: 1 day */ -#define CC26XX_WEB_DEMO_RSSI_MEASURE_INTERVAL_MIN 5 /* secs */ +#define WEB_DEMO_RSSI_MEASURE_INTERVAL_MAX 86400 /* secs: 1 day */ +#define WEB_DEMO_RSSI_MEASURE_INTERVAL_MIN 5 /* secs */ /*---------------------------------------------------------------------------*/ /* User configuration */ /* Take a sensor reading on button press */ -#define CC26XX_WEB_DEMO_SENSOR_READING_TRIGGER BUTTON_HAL_ID_KEY_LEFT +#define WEB_DEMO_SENSOR_READING_TRIGGER BUTTON_HAL_ID_KEY_LEFT /* Payload length of ICMPv6 echo requests used to measure RSSI with def rt */ -#define CC26XX_WEB_DEMO_ECHO_REQ_PAYLOAD_LEN 20 +#define WEB_DEMO_ECHO_REQ_PAYLOAD_LEN 20 #if BOARD_SENSORTAG /* Force an MQTT publish on sensor event */ -#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BUTTON_HAL_ID_REED_RELAY +#define WEB_DEMO_MQTT_PUBLISH_TRIGGER BUTTON_HAL_ID_REED_RELAY #elif BOARD_LAUNCHPAD -#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BUTTON_HAL_ID_KEY_LEFT +#define WEB_DEMO_MQTT_PUBLISH_TRIGGER BUTTON_HAL_ID_KEY_LEFT #else -#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BUTTON_HAL_ID_KEY_DOWN +#define WEB_DEMO_MQTT_PUBLISH_TRIGGER BUTTON_HAL_ID_KEY_DOWN #endif -#define CC26XX_WEB_DEMO_STATUS_LED LEDS_GREEN +#define WEB_DEMO_STATUS_LED LEDS_GREEN /*---------------------------------------------------------------------------*/ /* A timeout used when waiting to connect to a network */ -#define CC26XX_WEB_DEMO_NET_CONNECT_PERIODIC (CLOCK_SECOND >> 3) +#define WEB_DEMO_NET_CONNECT_PERIODIC (CLOCK_SECOND >> 3) /*---------------------------------------------------------------------------*/ /* Default configuration values */ -#define CC26XX_WEB_DEMO_DEFAULT_ORG_ID "quickstart" -#if CPU_FAMILY_CC13XX -#define CC26XX_WEB_DEMO_DEFAULT_TYPE_ID "cc13xx" -#else -#define CC26XX_WEB_DEMO_DEFAULT_TYPE_ID "cc26xx" +#define WEB_DEMO_DEFAULT_ORG_ID "quickstart" +#if defined(DEVICE_LINE_CC13XX) +#define WEB_DEMO_DEFAULT_TYPE_ID "cc13xx" +#elif defined(DEVICE_LINE_CC26XX) +#define WEB_DEMO_DEFAULT_TYPE_ID "cc26xx" #endif -#define CC26XX_WEB_DEMO_DEFAULT_EVENT_TYPE_ID "status" -#define CC26XX_WEB_DEMO_DEFAULT_SUBSCRIBE_CMD_TYPE "+" -#define CC26XX_WEB_DEMO_DEFAULT_BROKER_PORT 1883 -#define CC26XX_WEB_DEMO_DEFAULT_PUBLISH_INTERVAL (30 * CLOCK_SECOND) -#define CC26XX_WEB_DEMO_DEFAULT_KEEP_ALIVE_TIMER 60 -#define CC26XX_WEB_DEMO_DEFAULT_RSSI_MEAS_INTERVAL (CLOCK_SECOND * 30) +#define WEB_DEMO_DEFAULT_EVENT_TYPE_ID "status" +#define WEB_DEMO_DEFAULT_SUBSCRIBE_CMD_TYPE "+" +#define WEB_DEMO_DEFAULT_BROKER_PORT 1883 +#define WEB_DEMO_DEFAULT_PUBLISH_INTERVAL (30 * CLOCK_SECOND) +#define WEB_DEMO_DEFAULT_KEEP_ALIVE_TIMER 60 +#define WEB_DEMO_DEFAULT_RSSI_MEAS_INTERVAL (CLOCK_SECOND * 30) /*---------------------------------------------------------------------------*/ /* * You normally won't have to change anything from here onwards unless you are @@ -137,40 +138,40 @@ */ /*---------------------------------------------------------------------------*/ /* Sensor types */ -#define CC26XX_WEB_DEMO_SENSOR_BATMON_TEMP 0 -#define CC26XX_WEB_DEMO_SENSOR_BATMON_VOLT 1 -#define CC26XX_WEB_DEMO_SENSOR_BMP_PRES 2 -#define CC26XX_WEB_DEMO_SENSOR_BMP_TEMP 3 -#define CC26XX_WEB_DEMO_SENSOR_TMP_AMBIENT 4 -#define CC26XX_WEB_DEMO_SENSOR_TMP_OBJECT 5 -#define CC26XX_WEB_DEMO_SENSOR_HDC_TEMP 6 -#define CC26XX_WEB_DEMO_SENSOR_HDC_HUMIDITY 7 -#define CC26XX_WEB_DEMO_SENSOR_OPT_LIGHT 8 -#define CC26XX_WEB_DEMO_SENSOR_MPU_ACC_X 9 -#define CC26XX_WEB_DEMO_SENSOR_MPU_ACC_Y 10 -#define CC26XX_WEB_DEMO_SENSOR_MPU_ACC_Z 11 -#define CC26XX_WEB_DEMO_SENSOR_MPU_GYRO_X 12 -#define CC26XX_WEB_DEMO_SENSOR_MPU_GYRO_Y 13 -#define CC26XX_WEB_DEMO_SENSOR_MPU_GYRO_Z 14 -#define CC26XX_WEB_DEMO_SENSOR_ADC_DIO23 15 +#define WEB_DEMO_SENSOR_BATMON_TEMP 0 +#define WEB_DEMO_SENSOR_BATMON_VOLT 1 +#define WEB_DEMO_SENSOR_BMP_PRES 2 +#define WEB_DEMO_SENSOR_BMP_TEMP 3 +#define WEB_DEMO_SENSOR_TMP_AMBIENT 4 +#define WEB_DEMO_SENSOR_TMP_OBJECT 5 +#define WEB_DEMO_SENSOR_HDC_TEMP 6 +#define WEB_DEMO_SENSOR_HDC_HUMIDITY 7 +#define WEB_DEMO_SENSOR_OPT_LIGHT 8 +#define WEB_DEMO_SENSOR_MPU_ACC_X 9 +#define WEB_DEMO_SENSOR_MPU_ACC_Y 10 +#define WEB_DEMO_SENSOR_MPU_ACC_Z 11 +#define WEB_DEMO_SENSOR_MPU_GYRO_X 12 +#define WEB_DEMO_SENSOR_MPU_GYRO_Y 13 +#define WEB_DEMO_SENSOR_MPU_GYRO_Z 14 +#define WEB_DEMO_SENSOR_ADC_DIO23 15 /*---------------------------------------------------------------------------*/ -extern process_event_t cc26xx_web_demo_publish_event; -extern process_event_t cc26xx_web_demo_config_loaded_event; -extern process_event_t cc26xx_web_demo_load_config_defaults; +extern process_event_t web_demo_publish_event; +extern process_event_t web_demo_config_loaded_event; +extern process_event_t web_demo_load_config_defaults; /*---------------------------------------------------------------------------*/ -#define CC26XX_WEB_DEMO_UNIT_TEMP "C" -#define CC26XX_WEB_DEMO_UNIT_VOLT "mV" -#define CC26XX_WEB_DEMO_UNIT_PRES "hPa" -#define CC26XX_WEB_DEMO_UNIT_HUMIDITY "%RH" -#define CC26XX_WEB_DEMO_UNIT_LIGHT "lux" -#define CC26XX_WEB_DEMO_UNIT_ACC "G" -#define CC26XX_WEB_DEMO_UNIT_GYRO "deg per sec" +#define WEB_DEMO_UNIT_TEMP "C" +#define WEB_DEMO_UNIT_VOLT "mV" +#define WEB_DEMO_UNIT_PRES "hPa" +#define WEB_DEMO_UNIT_HUMIDITY "%RH" +#define WEB_DEMO_UNIT_LIGHT "lux" +#define WEB_DEMO_UNIT_ACC "G" +#define WEB_DEMO_UNIT_GYRO "deg per sec" /*---------------------------------------------------------------------------*/ /* A data type for sensor readings, internally stored in a linked list */ -#define CC26XX_WEB_DEMO_CONVERTED_LEN 12 +#define WEB_DEMO_CONVERTED_LEN 12 -typedef struct cc26xx_web_demo_sensor_reading { - struct cc26xx_web_demo_sensor_reading *next; +typedef struct web_demo_sensor_reading { + struct web_demo_sensor_reading *next; int raw; int last; const char *descr; @@ -180,33 +181,33 @@ typedef struct cc26xx_web_demo_sensor_reading { uint8_t type; uint8_t publish; uint8_t changed; - char converted[CC26XX_WEB_DEMO_CONVERTED_LEN]; -} cc26xx_web_demo_sensor_reading_t; + char converted[WEB_DEMO_CONVERTED_LEN]; +} web_demo_sensor_reading_t; /*---------------------------------------------------------------------------*/ /* Global configuration */ -typedef struct cc26xx_web_demo_config_s { +typedef struct web_demo_config_s { uint32_t magic; int len; uint32_t sensors_bitmap; int def_rt_ping_interval; mqtt_client_config_t mqtt_config; net_uart_config_t net_uart; -} cc26xx_web_demo_config_t; +} web_demo_config_t; -extern cc26xx_web_demo_config_t cc26xx_web_demo_config; +extern web_demo_config_t web_demo_config; /*---------------------------------------------------------------------------*/ /** * \brief Performs a lookup for a reading of a specific type of sensor - * \param sens_type CC26XX_WEB_DEMO_SENSOR_BATMON_TEMP... + * \param sens_type WEB_DEMO_SENSOR_BATMON_TEMP... * \return A pointer to the reading data structure or NULL */ -const cc26xx_web_demo_sensor_reading_t *cc26xx_web_demo_sensor_lookup(int sens_type); +const web_demo_sensor_reading_t *web_demo_sensor_lookup(int sens_type); /** * \brief Returns the first available sensor reading * \return A pointer to the reading data structure or NULL */ -const cc26xx_web_demo_sensor_reading_t *cc26xx_web_demo_sensor_first(void); +const web_demo_sensor_reading_t *web_demo_sensor_first(void); /** * \brief Print an IPv6 address into a buffer @@ -218,15 +219,15 @@ const cc26xx_web_demo_sensor_reading_t *cc26xx_web_demo_sensor_first(void); * * It is the caller's responsibility to allocate enough space for buf */ -int cc26xx_web_demo_ipaddr_sprintf(char *buf, uint8_t buf_len, +int web_demo_ipaddr_sprintf(char *buf, uint8_t buf_len, const uip_ipaddr_t *addr); /** * \brief Resets the example to a default configuration */ -void cc26xx_web_demo_restore_defaults(void); +void web_demo_restore_defaults(void); /*---------------------------------------------------------------------------*/ -#endif /* CC26XX_WEB_DEMO_H_ */ +#endif /* WEB_DEMO_H_ */ /*---------------------------------------------------------------------------*/ /** * @} diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.simplelink b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.simplelink new file mode 100644 index 0000000000000000000000000000000000000000..32213ecddb0cc3c412d15e5216777613f560f521 GIT binary patch literal 749528 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%0Abns5W(_3MBXFSB8$8&s# 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

&YTNNEplw)aD0|;sK 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 literal 0 HcmV?d00001 diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/img/quickstart-sensortag.png b/examples/platform-specific/cc26xx/cc26xx-web-demo/img/quickstart-sensortag.png new file mode 100644 index 0000000000000000000000000000000000000000..a7ce7dabeb979afdf8a31a5803265281fb10636f GIT binary patch literal 158808 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 MIn&AxK&B#q%BQyt^9Mm;?p>DPv~0V;+Nskt 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 literal 0 HcmV?d00001 diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/img/sensor-readings-config.png b/examples/platform-specific/cc26xx/cc26xx-web-demo/img/sensor-readings-config.png new file mode 100644 index 0000000000000000000000000000000000000000..79c8e61e3f410f2500dda37b87466863464e2b8c GIT binary patch literal 33000 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 literal 0 HcmV?d00001 diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/img/well-known-core.png b/examples/platform-specific/cc26xx/cc26xx-web-demo/img/well-known-core.png new file mode 100644 index 0000000000000000000000000000000000000000..93552e502e404a2eb261e138835223a881ae0a02 GIT binary patch literal 9102 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 z Date: Thu, 26 Jul 2018 12:00:02 +0200 Subject: [PATCH 307/485] Added missing img folder for cc13xx-cc26xx/web-demo example --- .../cc13xx-cc26xx/web-demo/img/6lbr-web.png | Bin 0 -> 81741 bytes .../ibm-watson-iot-platform-tls-optional.png | Bin 0 -> 86462 bytes .../web-demo/img/quickstart-sensortag.png | Bin 0 -> 158808 bytes .../web-demo/img/sensor-readings-config.png | Bin 0 -> 33000 bytes .../web-demo/img/well-known-core.png | Bin 0 -> 9102 bytes 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/6lbr-web.png create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/ibm-watson-iot-platform-tls-optional.png create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/quickstart-sensortag.png create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/sensor-readings-config.png create mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/well-known-core.png diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/6lbr-web.png b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/6lbr-web.png new file mode 100644 index 0000000000000000000000000000000000000000..5308c412bc183fe3f62930fec950a1029ebc036b GIT binary patch literal 81741 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 LdQl>7^!EP%AFu2O literal 0 HcmV?d00001 diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/ibm-watson-iot-platform-tls-optional.png b/examples/platform-specific/simplelink/cc13xx-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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

&YTNNEplw)aD0|;sK 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 literal 0 HcmV?d00001 diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/quickstart-sensortag.png b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/quickstart-sensortag.png new file mode 100644 index 0000000000000000000000000000000000000000..a7ce7dabeb979afdf8a31a5803265281fb10636f GIT binary patch literal 158808 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 MIn&AxK&B#q%BQyt^9Mm;?p>DPv~0V;+Nskt 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 literal 0 HcmV?d00001 diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/sensor-readings-config.png b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/sensor-readings-config.png new file mode 100644 index 0000000000000000000000000000000000000000..79c8e61e3f410f2500dda37b87466863464e2b8c GIT binary patch literal 33000 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 literal 0 HcmV?d00001 diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/well-known-core.png b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/well-known-core.png new file mode 100644 index 0000000000000000000000000000000000000000..93552e502e404a2eb261e138835223a881ae0a02 GIT binary patch literal 9102 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 z Date: Thu, 26 Jul 2018 12:06:53 +0200 Subject: [PATCH 308/485] Added RF inactivity timeout configuration --- arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h | 16 +++++++--------- arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c | 2 +- arch/cpu/cc13xx-cc26xx/rf/prop-mode.c | 2 +- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h index 68289d4e4..2dbb0b8b9 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h +++ b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h @@ -91,14 +91,12 @@ */ /* - * If set, the systems keeps the HF crystal oscillator on even when the - * radio is off. You need to set this to 1 to use TSCH with its default 2.2ms - * or larger guard time. + * Set the inactivity timeout peroid for the RF driver. This determines how + * long the RF driver will wait when inactive until turning off the RF Core. + * Specified in microseconds. */ -#ifndef RF_CONF_FAST_RADIO_STARTUP -#define RF_FAST_RADIO_STARTUP (MAC_CONF_WITH_TSCH) -#else -#define RF_FAST_RADIO_STARTUP RF_CONF_FAST_RADIO_STARTUP +#ifndef RF_CONF_INACTIVITY_TIMEOUT +#define RF_CONF_INACTIVITY_TIMEOUT 2000 /**< 2 ms */ #endif /* @@ -106,7 +104,7 @@ * default PA. */ #ifndef RF_CONF_TXPOWER_HIGH_PA -#define RF_CONF_TXPOWER_HIGH_PA 0 +#define RF_CONF_TXPOWER_HIGH_PA 0 #endif #if (RF_CONF_TXPOWER_HIGH_PA) && !(SUPPORTS_HIGH_PA) @@ -119,7 +117,7 @@ * consumption. */ #ifndef RF_CONF_TXPOWER_BOOST_MODE -#define RF_CONF_TXPOWER_BOOST_MODE 0 +#define RF_CONF_TXPOWER_BOOST_MODE 0 #endif /* diff --git a/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c b/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c index 5f4a54982..d9f3a5acf 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c +++ b/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c @@ -369,7 +369,7 @@ init(void) /* Init RF params and specify non-default params */ RF_Params rf_params; RF_Params_init(&rf_params); - rf_params.nInactivityTimeout = 2000; /* 2 ms */ + rf_params.nInactivityTimeout = RF_CONF_INACTIVITY_TIMEOUT; ieee_radio.rf_handle = netstack_open(&rf_params); diff --git a/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c b/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c index 76475d154..16877f333 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c +++ b/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c @@ -667,7 +667,7 @@ init(void) /* Init RF params and specify non-default params */ RF_Params rf_params; RF_Params_init(&rf_params); - rf_params.nInactivityTimeout = 2000; /* 2 ms */ + rf_params.nInactivityTimeout = RF_CONF_INACTIVITY_TIMEOUT; /* Open RF Driver */ prop_radio.rf_handle = netstack_open(&rf_params); From 6b91fa17386e85aa6d536fbeddfa8f14248d21a9 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Thu, 26 Jul 2018 12:08:04 +0200 Subject: [PATCH 309/485] Cleaned up examples Makefile --- .../simplelink/cc13xx-cc26xx/very-sleepy-demo/Makefile | 4 +--- .../simplelink/cc13xx-cc26xx/web-demo/Makefile | 6 +++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/Makefile b/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/Makefile index 07da8daf8..97272c9a7 100644 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/Makefile +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/Makefile @@ -2,9 +2,7 @@ CONTIKI_PROJECT = very-sleepy-demo PLATFORMS_ONLY = simplelink -all: $(CONTIKI_PROJECT).$(TARGET) - -SMALL = 1 +all: $(CONTIKI_PROJECT) MODULES += os/net/app-layer/coap diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/Makefile b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/Makefile index feae0b36d..aa310465d 100644 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/Makefile +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/Makefile @@ -1,6 +1,8 @@ CONTIKI_PROJECT = web-demo -all: $(CONTIKI_PROJECT).$(TARGET) +PLATFORMS_ONLY = simplelink + +all: $(CONTIKI_PROJECT) MODULES_REL += ./resources @@ -12,8 +14,6 @@ ifeq ($(MAKE_ROUTING),MAKE_ROUTING_RPL_CLASSIC) PROJECT_SOURCEFILES += cetic-6lbr-client.c endif -SMALL = 1 - # REST Engine shall use Erbium CoAP implementation MODULES += os/net/app-layer/mqtt MODULES += os/net/app-layer/coap From 7debfe830f912332810cd0b2c614ff7e79823148 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Thu, 26 Jul 2018 14:07:10 +0200 Subject: [PATCH 310/485] Fixed issue with SPI0 and SPI HAL, and fixed bug in Makefile.cm3 --- arch/cpu/arm/cortex-m/cm3/Makefile.cm3 | 2 +- .../cc13xx-cc26xx/launchpad/board-conf.h | 2 ++ .../cc13xx-cc26xx/sensortag/board-conf.h | 2 ++ .../cc13xx-cc26xx/web-demo/web-demo.simplelink | Bin 749528 -> 0 bytes 4 files changed, 5 insertions(+), 1 deletion(-) delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.simplelink diff --git a/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 b/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 index 29adac8e8..1c9ffc04a 100644 --- a/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 +++ b/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 @@ -24,7 +24,7 @@ CUSTOM_RULE_LINK = 1 .SECONDEXPANSION: -%.elf: $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) +%.elf: $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(TARGET_LIBS) $(TRACE_LD) $(Q)$(LD) $(LDFLAGS) ${filter %.o %.a,$^} $(TARGET_LIBFLAGS) -o $@ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-conf.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-conf.h index c7461f92a..d949062bc 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-conf.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-conf.h @@ -94,6 +94,7 @@ * Those values are not meant to be modified by the user * @{ */ +#if TI_SPI_CONF_SPI0_ENABLE #define EXT_FLASH_SPI_CONTROLLER Board_SPI0 #define EXT_FLASH_SPI_PIN_SCK GPIO_HAL_PIN_UNKNOWN @@ -106,6 +107,7 @@ #define EXT_FLASH_PROGRAM_PAGE_SIZE 256 #define EXT_FLASH_ERASE_SECTOR_SIZE 4096 +#endif /* TI_SPI_CONF_SPI0_ENABLE */ /** @} */ /*---------------------------------------------------------------------------*/ #endif /* BOARD_CONF_H_ */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h index 85dfbb6bf..fedc82f17 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h @@ -89,6 +89,7 @@ * Those values are not meant to be modified by the user * @{ */ +#if TI_SPI_CONF_SPI0_ENABLE #define EXT_FLASH_SPI_CONTROLLER Board_SPI0 #define EXT_FLASH_SPI_PIN_SCK GPIO_HAL_PIN_UNKNOWN @@ -101,6 +102,7 @@ #define EXT_FLASH_PROGRAM_PAGE_SIZE 256 #define EXT_FLASH_ERASE_SECTOR_SIZE 4096 +#endif /* TI_SPI_CONF_SPI0_ENABLE */ /** @} */ /*---------------------------------------------------------------------------*/ #endif /* BOARD_CONF_H_ */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.simplelink b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.simplelink deleted file mode 100644 index 32213ecddb0cc3c412d15e5216777613f560f521..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 749528 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%0Abns5W(_3MBXFSB8$8&s# z#Q^x0zx^rz?*cH|aJwfQ?RFr^+0tzx9-uO0<;p5CZ3;AW6k}G4G1mjvIb1C{JjEPd zMRMkl^%;QA0gQ&0PFOs%5V^)Vxkl_ zDf*^sYsZ{R#GDDhwK*t-eC?b`V%^RLYo>@b?=@I6Rjg^&21YQsSVMsB?@Zti z*0hPEANWxce27ccf7_7L0Ldv6nshY`lAP**>v9j4oL+32lN3QJnhO6PSuSJY@+He` z$#OpW2VJ;)$?`j>)UMB$uq;n^Oz0sdtOBl0C=?Uk1l~~C{~r^w`?J(tMET1LPRQK{fD*6ZLiI|>?E#I&HoCn=WoJ%CoL%Mk z6>E+(kTYyAnYc-4w<;;qP~f@!=^2;Y!SljN7zRMw&0f$vsy~ujBpaZbA zzzXsJ+y?+v*bOPpApi3rPMaEqF^#3Y4m9& z;`L?pdWo!}U4ApbO6=o)g@kAkx8_sx*TBt)C^(aW-dnWJr&io^`uswlpHFeclAVi9 z)CDV%{&*4@m9r<+8EUeq>`Rxf!_3=hQ8*4>5eIH|T>3ZxI{8fiWsd{s#|qitE z#Q(OLXhi=8P)Xnu0Fwc<-wuro=d9fTx+6CBYA@?Mu95Y)O+M(5Q->RAM%LeLGFM;2 z;~saqkPq18(+(N$P9gmn$mP%-LPo3~YzCQi8ngkRb=NdK1VEK~+_$5NcH#%okn-Ar z%0-Y&c`?Eu6*O8(d?B16o~Z}X63?(S;+Y*Np9I^#2+%XX11O+pI-n;lqj$>anliej zj4tWC9ct`2<8np>8vYH1S@<^$I~_Q)oBl)no!L#Cs@9)tmwEXuRpspX7@u3kwbQbG zx_=dCZh6J$RB^VISA6$|ReIKhDh|AO#pg9FJTsaZM~Q{|&}7 z@PKJNft_;nGv9_D9lmc+-`C?t!aFX|nRqJ@{s!G+p^;pTWk4YT9$WdJ2}I?S2jRm{DYC zc%CKBkCe=m-oy_R|1Vf(+9-njXvs{!fFR$^n_1}74S6?jX0HY4#eAFL=2lH+@eZ=| zbnfE>y+u%1@-RUU!Jf?AektUW*WTXY7b3aE-6y>xsL8s>2XG{*IKCCXyyBRy4SXl_ zpuVZpE!d2_u>nY#(=@Zj=*HMvAo(+8i_&P-j;2YRb0N)@|bpeV1 zNdfG20KUN%D0;Ig-@IDDl96w|7#3#d<`etPFu%R>Eu>-iT8htuzD0c?AK)%izE$+A zPtNqUhCKv|7-0=>Fv1!kM#$kT*2uMxNcxUR&=o?smgmYxC1j&Z0pjEja;-}^p&81? zk7cd&yWx^CB(I{l5$5rt)>UyJn?|z)lYBX**ILb0e1SZQ-Vy@UCkM0m%lZKp!~Eq9 zhWRT<)!rEcNW5bo%;N9W7L<@YeER3!4mix6u>JG2clhw>7f+euDZhBi3jaWvh0MV| zY{kEb^RppYA`*A`A?o3CXWUYPMwm-P;+7FM5ghm7zbp}nTTU<}OGM(X^qG+45|OwS z1dTA4h{UZV%v5hN6-DD#eMIn@76`yOZNN=1xsz-%7gALK2y)S?#GM^{PnW>;@fR-z zFWe6uWBeu5WrY9T8t|o*w!+VJ0lXvyB7yMYY`~Y%10lnG9Pi}gFQ?wK(gK~fQU{w) zpff>uf$iWyfZ|nq?QWpUHI&Z^bpL_!%kUG(r=Stx0Udz?CNRU?x;4;)jV(RwLf;-J zWT@C{cLPP-z*W}n26|GBtldq>Vs9jCcN69lOyPNoiF)mBb2DK_6&j~?D}EAookNf> zOA_uT)$mjMSU_T`+c?WgxZ_fwVQ$@;a2Mm-2y^S!gnK%IY_Hu-xR*&}?QX(@zmsc9 zhrkuQ!Q`8fMsL>|?D7+Jal6)FSAs_5{Fz3u8`YX&z97-C73OxW8V-awK21Ym?gy3R=M))h*Rx663 zfPtX*X${`;5AY*+GZNe^k`cTa3EnD#5xf}*))TbC9cj#MlK}_9+^03Tg>YhohbIQN zc7l#jxHV#W5b97~CXcWicL}7`#c{4o+ok8x?F-ocZY+dqYw)=~$TK~>Vg}$B<^s+Pk7Rwkya{ktnESK_UwHsd^3WZ z)9rC4v31=oadC&xc-rEZ&>Du*WqN2|xEk#9zV z^69B-S%HzUCb!m(lQCY`QW zjb_Zv9A*d-i1F~mV2vQr*hyCQ1(H5Bwve0)CGYguYNnYfVwtfzYMUiUcI+@soGnN} ztb$g}5u_}}!xMuS3DQ>&hiYJ$6xwH;!^0C3Oi~g|*;k%@gH$aD7Yn%+{E=Ytj+DsO z?F7S4VcsaePeCMYF}-`2V%M6+x7xuS8s?jk;7$$m%}CJaX0WF5%}CI4vst8Zp>FVO zH}41TVHo0sia5-2=VLWQxSU6egxUi%!*e?T4&Rc6pLyRf#0_^R%<+UP@<4BO4#1EZ zzU0~lp-V+5yc0eMFCpv-Uz7=W>A7L5+m10(co{cQwZe;X0k7s%Q6PLA4-(-uX^=_4 zV@Mkyl{YejLVzh|_@PV;;I$PGH_2dklMEhflEI!P8T@@9l-e2mV*@jgp>OzEJ`yE{ zS9OKrmk9^M9R>n^?+M6+!oA>=@cYys33p-XKj62(Snc^525RBnIk2ZyDm(<^zW4}; zHttI%Fm&m^B5arb+a|`HXky$+6GL^|xYPXrCxoBH^Jw@trcDel?*RCB!lBp$n0XGH zic>R@SRV`x!yZMmlVXF3cm;{ZMicP~(kwQKh^43?*>LY-QTu(Jh}ER)07lL5wQ4GI zi%IRS5iuhsHMdp}S4^sIof7L~Qg`c>m>-kMyG7kX`(sjjx2ca=0BzeAQIHtBsV(x{ zDrqpteLo#o6}J;@{X9TeaJTxb!Ge35T5xYu3m#}{!GldL*sBtf8Z3B9jRIm@u&=2F ze{(GOxeF|q^c^ku0H9@tSGsc%f!YVF+;o)@dzyZ`%1!sWba_?_;*Kq1ja)6KFJj<2 z4*?LKT#EFm;{clB4el8Y$~M}{B&xQ$m%}ud;r^sOlFXRTBy$l-X83*g=7uC6*hwV# zJ`@B=ytJm~E=aZhI$v!5!p&BrZT`|uBO&pXP7|BXApP3SCT$vLsqk{PtTsi3pkBdJ zDHA7FbYnBSQc&eK+I-8Vxl&LUJ|hjXu2yL-Qb5Vo41+fP7>Cz1D7k}e<64bEEWu=d z0pY!DYC6Zq8-yjtC$vr{$EO5s$Z?KvbDThux3Z%`sRKBG~Jxx%lqX|@@~s(FnS z=yE3*ZC+&Q4hyORMw=_pQ-$9U)ay0cd_l9{(Oh&@2_{_yv%g~_)MkI*kfWIWgEq`D z`zJvg%>G$(wb`fGNVVC&G$;|Xf7PfKJHy74UYr9<3~8`R`Hb{u>0g(|y)Y_6g*Qmc zN|)-}s5z*=bTMm_oziWjO9kGjaTt~^HF%TFN0!jES(;0_)Zwj-n#8tx8`qK#Nn6r+ zKHMlNdG5A#I(a^-@rFDfv-w)n3B|^u z1d;EgY|+>%a(+{nfYU5ij#d>3yY2*%9AnQANq7AYBqhc+AIWerB+riVjuUC?VqD|= z&rkD!_1l3Gw0<67rWwh0(H>o%u98M~+>vgA=#D#*=W6V@Bi&t%9e1Rsi(fj}<*9IS zhfBLWgIxQ7*yS1J`Wc8_p3$zuu+1*dR9ALNLwV|4V}aP^xz_b45W75UnwDp+E>CQK zR}|-Z;iSbZR8VB2>tm>H9a}}tjgn6~!Zq@`cv^xma;PzM7=)33X`BJTz>gf!xD$kt zH*7vbOGS=KHAxUg{@tjFK^Qq^8~ zY(jl-e~9=sE;hI#5ebQO_M(v_n}c$*8;vx#H3f`x_M?#&8b?Q(&W<$F+UBDtg|G7^ zo^-7hNM-VNBi&V`hsGOftw`eywN`BNwO>jl7Vr)*2YNK>slMDt!b#Wi5jMkbffKDc3!=x9QbTLUUHtAxLUYGQ`i%B}- zN;#WdOwVq}<~>&hkVI+iN$-oJg3=czeedE4z9H!glYWqVBC%i5y(j%BeMdC*AN2i6 zKMRr)Yk|RK(n-5lNky|u`bCg5L}AiPlBGmp(#v+N*io4DipHHNOnS|(E&HaKbkOEY z6eb-KdnF2!{?(|7QJ8et#)`>RaDg*wut&?rUmGpsY4@xTamh_=^ zD0>;Uwxs`P9HSO#ZAqVN+^M&u6E>fk%;>+|C#WfihpFgcJ>pA7kMIt9ndn;@$CeD~ z*P>lVk7^wENNmiAs))YhrWqNY=m|H^D~$C+KN0=j{VW8Gm_i28pG3VfQf^0BM1OXl zhJ0K7vLSlLeJ&D3ccB`L=m{jnE-gpFk49t^Xl8_>F>?d;7NS3jwlsMIF=AO5;Y80d z<#j`>qBD>*L9Ez#BCP}o7%82IwKhjUfs_?XU#*jOcii55s1M(Jb-= zlg-oYa1W7clfxUc!)6xYe3K&*(`XmM({Xg7$%kswDdtjh2Q6QR9~FHQzpiKz`9{iI zTD8ht3Ct0`-+T>NbOGv9MT_YfBjq?<_n5gGjFfh))2C#Bo083}_iMNhybwKTehlw; zzN6r27Ue%?BJK^X=ff2*TG4n<0kBvq0y^5}+e+Sc8D$g3r`Sva@I1l;B~#HuXo0TigQ!k-v;yNmGx|^H^%yA+(b#i6tC66S6&>VBK^%6T zQe#91OU1VD!MGeE{%b#rRXJ2lY2T6A4ioYA>lxz1J(&<~|1E7FAw@L&bPlO9e}#7p ztkZ%;+?E40>C6uLDP~tM>K{k>*Jim*qi3}5)<43Dx`;*CCBV{i=v)hvaUV_y7sc~2AGa~PKSWq)I zk5%`+=Tj8IGE#OR5~Ck@_E0xfw)L5adn5X(CmUFFCZg8pavY&{27k=?8_y)>EVcNp zU0$ih6H<$2EQ#s96AtuW#2d&@q6~?D^=x6{SCCuuw4Im}Owr$LXNjiYMH3QlAnS~0 zHqx~9sGhXT=RE{0`#Ko8G`a$}9V5zcQPJV}bv1O4N#2t*<5~8C(Y9#h&7v#tn;d-( zr9aC^*^H=&riw17?X~e{;C>MO8c!oe^igzWDmo8wg?@Dq%aG|c!FGhRy#pwGBLpy^ zg_eVR<@ZH^bG%)fi1qSbOR<9@b`q{u(f@+riau7%_S_43nbB8Z3)=HWH124XcXX5F zBfYOP`7tr(NBp{?iI8$fGo>SFjef`z9SPVQy$HWP9Dc7Ze<+nDBMvoK?aDu7HEUwL8`42&7#1#hfB?-?~xN~m4NqFvy9hiU`Si@Z}C z)Xr_HcAl+vmId+ovYG_7IEYPYp*IIb++)O27~o5!u<+v`+Hsk8 zF2w9wZ&sx^t&!av@vtp^ix-w|(Kh+DoV>Vpn%^lbe4qAwwT zE7}az?~kUSs^X%TLMA>ML8?G>Bs3&MZ$f<}8c73jXVDEn^|=T+c1dK-8Ae%`4RoGi zq(!er|KW-rMs%4`wi>HzC)BH9cD)d3fi2^|P}f$l-bm|u9_qs=>-q}}F_szb0nn+2 zu`FJyPr}M^dku#g`5@pZ&c?*=op85`J^{V1=w)bu?r1sU9aE1-8ENB|GU;(Ixm=uZ5)qWke{Mn8uQRbG!vno?>r5V^@=F)nXMMoTf* zt=P&;32!{?)4NtoR!Mpko19-}+Lc$)k#VteS)V?|A!aC+K-(;tB0#5q4l+^!wS$>H zfr_kAL3La*MFYk*l!Vc85F;uqlLZrF7t?tWMbjt6jv%73r{rNElMR1cNORGt{Sq!^ zC47z(=S{dQ^(80_sTOKD5N%!z$0o5zvh`<6H5|5@v0IqcIbxm_JMTOoX^O+PKO@%fORd%}ymPAdJsn!DP@J}z;9pn{++2Li}{#8fCS1B0gRx^h# z>K2HlUXA`NO?6W)7#ADNTFy}kCX9+bL;bmeSh2_9Q>Ux{iCICU4gi)?I;x`_GjMNgs16-QV` zjAJHMp*T9SVm`)wFOdqxwzJJtN;u%PAzM>#@qbpVkOk-?NGHS3d*DjwwFg%@(`okr z#pP2TcghGOEoTtRI7D%|na6zqt3Y$Q(u9$=%mB(f!T=d#%X~nY8%ddfFD96(hLl^_ z3@%U)r;#!j-=g?gT0ZOBFD7&H*%%kA?_iF{J){HDOsB6dmdf(D*HB9{mTQUP5+{#) z8S`F;5~!sTX&(0;e2$XiK|4`bD7H$EdmmE`V%4lvj5?3|K2lb);jWgZgYRClK#8!D zu2ttVR@??PU(Ue1P9=yv1x(ewCn)PB?y#(uG6Q)(++b5qQ)UH9q&C`={iJ-t-bqi3 zd)$w~!n6X~bE`^#={fxF6Wd-gd_C^H;O0)IB_&ZlRWIzWjAf{4RX-gC&pV6$D2Wn2 z57~78gkCO*K1+$A`DcigNxHkiEy#>uK{!@2_eaEIV?B`A5ArcP_fxttT@nV6MU7pTQwXW3qu$Upvt^2$+$(9nMk5lE_|x1!k*7Q7ytUPkNeTN$ij&Lo}cB z1M1x*n!=3oMezrc@(tpzvqnBi;&a(eNMHDIFW3x~7D}O#qEkUDGAi-?0)ZdF{1`w1 zxy1pHOTLF}^?a;Y$713|_{F(&9eZNAZ`>JoPpmtXBi{<#sJe+u`0^p|IBWz?&X2gXOL|DUG!!yFfh8>#tCs=nA)jFN5qu;0d)QR_ zCGpPiF!?puqGE`se;sJyscFpJFm}NUYC_UjWYH@!9rf?U&&QA`CwDO_v>#aXAIgC^ zg3s(okaCf59S99lO{LVJ$)PoBPb!u;$NogPl0CR_|PZ~o?6-9;U#c{s_%)=qlZ_D zhu;B~m&5LHWrTwp3pYdU(Q74Ld*Irm*NI100Iz(S9p?H7HT9-6uRer5d9R|+1x}u; z8}N;=2KZCJy8zdXs9LPCI}_Edr|UATidRGN-_)N`B$#}vOECEymHS2pRLuNS=G~Z? zWIj_eAJ5Dr^O+IyE^EkqreuE4|0DCRf0a3({rbGl4!k3<&mz)eOcA zDdStf&gGCkBf>Gg8d`Y-{!|?!9NP6g2Yna+&J2=Mp+-?5fE)tZ0EPnS=ZIAe z1?4hO`o0W+e_mWF-&OP}@SRNaHh|{<@GrLoYhq{E>5?kZg{bQlQPU3Pyd{DA| zQj$-**igH%W(Z&SVGLbX6UNyN@J&AFS=4c1{0zolG>+!b$%X)fqy@6y==2w~^1q<* zF}i8mmymXj(1xmPG+vkWVx!V48igh1nUS3sam{(g1d}t0xlh4RwN{+54ma#{n62u4 zC?0$L66b+P*;--fQ!)JG;p)AiZ`bS8veW3`0MEI;4 zj-<~THC2Ll2VPR~M{CesZACKW4{yuC`JiINo%8^5^@|bHkV@aE zf>O8l059DIVY&7118@`(%1~kf7h&`;_!AHrw&lOrzN9wlM{PKDU9@F}E1 z=15M3*h!WnM)Ka_-RD$@l9Pc~$OOfy5GT{GBwyxEwB9>`_h2oY39%Ml2U@rhI{7yQ zVX0in`-$h#Vz7VvL4?>CNgtN`D3ND`4rr4{=seN?!n` zlzs#OmVO3+0*W;${mn@Er_xi|c!>U~^#50}hwQ||FpgVbbt}4SD9X7`$~lxZv`%as zDCTRaVKTtKEyONg-}JVHc)P%3R#)gaEpJMeWGmU`UDfl6pT0XS?>sgVlgK$8WaK;y zTu097AS1^tCZE1L9c1Ke1+IN}THdPs9k|Z)Opuw%(*(9JL{Pp*mfW6Hh_|zR6Va_K zvHuKsy2Ztd-4`G_dcOl3$6|o~CF-NH9>%DlQlEvcF}Rs@RmT31&<-;KlR#UIR0Skf zodayQL|EY);|yaDgpX3VCbS#MiarDFLkg2v^*yjUG^*m?0TjlM*Ya48XQ)G-TFPgF zb|)l?QUSaJpn%-rxxifOM^%;Kf7enpvsaPNFd$=)$f?+2d`>C3q?_iDdNG4tLVg&> z-{@Ns!Tkiyql>xsL?da=#Tmqwf)kzEGJHeUC`=^#!iO>Pg9`2DlEZzsc*q z`+@7|+%M5tNGGg=G3yu{`-4$fQ$Sc8@FApa4;P?hyD0Ncun01x6~M*A)d0l9rPo1? z^yrTQpnFC`khN8ZdVL)Z$8OA0gF`-7?5G>6GEcICofO(YG z+knyMJTz0)A_z&N4*GER6*RJQXd%@z8TtzL$2*zyl1yF%vFrm7-$lF7!_#)++*k#i zR|f~nA4dGDUGQzhK+#6fhJjghHGoS16mUC@s;$8809JJ`fL96Z1@K=0Bb*U;98@XO z^>=FFsJmG&033B^0%#n;O5jS-m^A_DaPD6bAgX7u3!5|VUq#fx``0J}?7=StAj5u& z7W2hQ@ge*m(}sJP%+)m7Wl?A6;Ca+ZyDp3a*VamBaznmzu5$8uK}0>vZzzhvd!6 zbko%{f&Md%zQbMgr!>^!)W=dM0r&T2KMu;d8)%eCgl89D!n%9|JHE zfEylWSGB&LjEVL)Vlh z`mJci$K=?r0+~c@(I*^Hh8RVwMD(uYM$t5gu7TE19Z`mz z*fR!QFYT!nwXEeV$le6m5F8_M&RC?{Tv0nRrqxok0HSw5w4EcmNus%@P44NC`Ch~* zxf$dKAPuFmI$;DK?k)!rcMe0nmN*;YMf*X^>H|V~A-uy#U#_*tjba68d{*9O(-vmZ zF#W{5%_zSP>?e`KlbY>bxF4B;Z83KlJD@jIf_cP z!!g1(N_N|VB2=$L=&@#h6f(*~kU9i)-4TM2guOcN(iAY{ma+w9mF{+IDaUr#BpyaN z=Qekq)cHCg@9A#B;nVFHxFJs_=C6?;uLWND8AdQ_t)v{q1oM&ns849}?%@sy$-9TW z01C(%&UX)LNXZqD{NLU_7~^h$|J4G~uQ;bTPz+j-NP`A`ilz%DVQt7_5j4hL(}r0j zayDlZb`u`Y3a#&oM#;P55a|rwU}@ypeTbAM=Um`!w$ve_@OqojtiQmG&qCuef(R7O{0CWH_o>DJEDhe}%-QQu)B71BTcGWl_Ye6k} z9SPn=^|9&@+xRQp29k_fb^~C=1t3iRLPXE=HZ84@R`Q8Wvt^8Nty#})q&zrp6&@4^ zw2=Z0l)|@>!cVBYfn&t>!obb|cVpC(x}dQ$XwI!UOc@mIQXL+hDXz1#C&+ zLuhNASdk+(fnud5M5N-z1EAa9f}pMx zv`Klw7$)sg&VekS52?>l^*?B-hCW?&Gs-Uqk5%u37HYr~N%@mDtwj@>h1SLJDbuth z%$T`M{3vs=k=+?b5+o;~zl0E#jc80*G7L1D=$JQ5b!ET95F9&~?QN9!zc0dI7oAhj z`xnDtl!U=t6j(Q_QBsdPiGP_U=@cR2Cvp1{XR`pbbA ztn;CPZ^!|$Mu>$RVa|sI4}qaBOh|(XQaxWlTI$il>jl9L<1m1Hy*Wd;nPT+npofiO%B;4+Xwn~|;OG+375##)p?U3?R zKvh4%CbcP`egS!)3@J7RIHVXljpU2c@q)2ZMiP4h97zmYh^+?Ha{)fBS3bxh{VTwD zuY8&v>0zNy`~tcvchYIw16)!F6|doWO1&3gF8ISY>v(dT6vt-SGyXWXH<@b!tgjvf z?}`yU<7q@&xS;}u^o*w=Q^D13tSp|A$BA$3hJ@wuY*QTv1K&ctLhydX*Rp)Q1fKz1 zcY&3HUjn?WCJ_T@w3_@aX%KuQp3@AUg38txnLbbO<>-0^3AH%jM%BM)yQ9zPE~D=_#CBeeMT$iAP0SG@%0 zKxnFZ1HeQ82!tqv*#M`c0Vsz!RI6O0oQc=~MrsnHeDW2b!GPH|NnVWOmR)jB7Ixl4 zFzKX5??J$Er#9Y#VC8g}qF#w-O_mM=L+-EB0q`-hd=&sT=;yW0h6as8SS_Pu4Y)Ld z#bq-q+XdfjL_5j9wFp|91rCF_00rs&2_!>6(#aIZc?0zK^I%T>5lp22qtguW)jqJq zS7u-&lJ;|O@ztkDEWSDk0LEf(F`OHLM?FYFnO?zyO7OV5%3zOg@=9|d#JVVX5kM2K zl%)i*IXj}Rhs60pu|0k$Zj}#WJpUPlvmu}c26nPt6Rz3^MlmF+UIb7}(ZCEX%5A=s z&-)V$DQXVd4PY9D-=ppS2t~`twY*7e@@GK1N4Rm*FyiTqT@}e~>FvX82v@ZL<7tTW zdmdag7NeLH{7u^i)dN6$h)MFih38je4i)%|#529MP%(WLXkJ<4vehW}f=Lh6gY!oZ z>EW<=h#Jp=5G?*Lvh4%(I28^H{7j2O!_XIkUStCJ0YCw{RjI&yxQa9JGj%c&xob@? zypLCj`n?3EiBNb6s~WKB`w09EJ9vAT0}`LmGHg=0QMv@AHXI?WvU%k;4^MBKYz-r9 zQl3$|8zjzt8-;787{(UlwIAWADg$wYaHIHmtftX{s?xm%>3aPLn&#|)G}oO17I z;LNxUdOm=T;adQ>)=#av2mjlme1+jj7y%>Aapo}CeG+L32p6{mV@4)^3^=8@J%G{! zu#3-x_$%3sGzSoUjP>yV*^y^hN-k z2ZJ&eDjCqF`)mMx>{8s8s{fk>+git~)zGZ__tw(2vVU(a-KtT&qa$Q)jZ+^q$lMy| z+yicnYjO{`Kd$i}@K#*oJ>b(g_8fLEe2U$*DB_}(FTs?BE0rTq$G<~@3s+oVv*r=ggRNFd z7Oohj`@v=0_Adj;UJHSV1EVktwVDiO0hK@MA4laqK${Gm1teDW28M@9qiQIC`vD*f zu0RSIvTX*?8ChMbbM?68nX+UX$WEudm?{eAJ6J07^I{{$)Y+psJB9O}FR z&F5W=j$|T40uAudXZoG(MJrOlua1VgLvNI zy??$`i&5?A2Be=~b#{dMH4z%1g=*SRQ?7qBp0F_(fPr<8u9!p`HF`#3M&?2=*^cIb z)wCVqW;u8ccyj-};J=-byuCjiqbjXwk7$B%?L}27R8>ss>Yx*WmUe@1Zxqi+0vRg3LQ?qd9z|iJ4qBNv~h!A(jT- z&`A&uDTm78_FmaitCGv+mEYey4ZaE>@Kl_iA59oFNiBf9VeLcqYs3xh5M>;|zG3k> zW;t!2A}9?wOcW-(VKL5s1g2ZeQHw1mza@UuN5V_Ra6_I*K7nR92=A+`uVCSypGX|G zJdso)kvx%{Mj|g0*-s>+z>tybA^`ZCe30&{HIiVg4u1A-7@XK%@%(^&7_$)l2psnI ztUOMqm7&A~Irw_sdeq6Hegc%}VdC=^8|7-`(f>)X*?^D|uRM*KpHW`5$2x)7px>|> zq9N5DNp&|=fL$%3jiqG0NS)Yom=v!08~P#jf$vU4|1t=wdOjl1uOHx)5jYE0>L;I%eQdX5 ziML~#&wPxt*}yA@wg&zm!Sma*o{kHAEqLX-p?Ey(UJkX)Jdnm$XXVF1rafD2vaJ6` zNincbGy2D&%lj*9$8}{D?Dw%w6$7YJ9@(DtvHz(YiSnrDeHH8pcew@=SavPdNn9|5bZ_dWJifHG-fh}G5Sz*YoLy+CG&8ol#Mi95XFIx=4wJE-&Ck} zzQZhV^)ZgY+&)Fi^|YT`Vn$1OMQWJn_G{hMW7$oA;#IuoSMno&^_iEAr!tux#D6r* zTZK9sbF=OmO28Os^?=y zo}{_d%h}yqf#+P62G-@G1N&p=FJaM_3i<@uGca0LD@BoO{ea5et$HAN5Py z0yb(dD*pg-c!)V%c6xbNIFb&Ad@?o{&>JA;OFUvWRuv{t7Y(2#1aNDh=#Ydxe_N~(39gK*cd3l?JCp@`sqE%${7 zQlVzBe0Wgri3xG>pN^5Lj@Z|s`*2eWN zhVmm~nc{@bz`Iy%O&GX?x7Z`5yhGxS&Ne)u^4qh4925J|W!~Be*a1`VnQh=2*8c&` zIzL3yA2Ze17z?<>>yt?{Iu(@6#J$D*JHm`CdYn-&rgMI z__IRLxyr0X`l7c$+dL5gLSog&z#afL<7)r~q2$8H(=X zABJOiL^i_{p|!vBQ#1*gmef^($!u)7UfZSraIV=B2TA~%E~iYSrb|I%2#+> zEHb%VUq3JQG?@rfJWHssugR|nG^f9LgdFrh+*UEc%njkL?`O1RNVdvE*#=5=XGnEd z?q|?tnnC1d%&ujeoUJ9RTebpn#;y2xG7Jw0E}>7*!Qd5J5q|k?A$8OpK*#(LRH*u| zCL@3#{*LT5^C}V-)cBnk`oPT?Dp*Z|ypa3M&G&$XOca5NZD6R++=qbn`VBt?BvkpQ zVA2nYW;6pJlw<%d@C!LkWWxPS_^|s3q-30!4yIAaabhyKN6Fpo{+`?%(BwP@dEuG@ z?g?@qcUL2cyipwkpch}b%FEU|NHDa7b#ViWFIpXze$fh6$ubDrFIp{}znhkY!?uvt z7{S-J*MJ!TqV~I=gRm&vMu2%e3PAGP04a`Zh5drVew%FO>98fwZ$K@*(asZTN{0dF zZ5w|jivj=D69XdRM)nVPiR%@|Gdg1LlFHHbvP+l~D*5r7dO)fY={B-Uo9LEj4bJEe zlws9Gx4bl$q1Y5*GF&c{M0U8$5!Dka7x6}RrEn_0Z3Xx$4VSbAyw=Xf7}qWhXt~aZ zpY=@8W4^vxSTgD-T-fwQ56E^F{fdu@vNX1{o3|08<`jGGQ?7-roZByZuRLj=r(6t0 zg%rBGJ1u*A6#y@L9R7aK&CN@fqD$wG;#y(UVNBABEDj{0_4|`rSiD%Mxp}3@``~)@Ao>mCPbZA45iP5 zz|k9K;{maU8cZ2|t2&!cb1&$kQTIT(6};f$O@+1cvXpW{B|jNd2W>?Baa0mP?YJr3 zzKzN2T{6bKo*v^EcRPT74p+vxkAWiN+!q0qevgFqICoq}c3BgoAc|AJ z1AQ3{gnnI}1RcBCt`tpbe1zF2w}^1A|Q6-?bjqIPj{NzZe+xEYbK>GBc{rS|~UBPt9pzb55p%lc?N$de@vp z&6#r)zIMIs9u3AtqU>$aHRr!5pX(Vn<6qOC(e!Fq>3Y=7NdirORMRK62Ysh|TLXQk z(C230+10h#J@=mO_`lpeFB=Up?iKpL{VHX70=&kJdEcVh$2};#f;PX$m5;H+tAhgSmVw+B+}%Ztx~P;nZ6 z+T*AHe$X2_UHj1+6FAEtI-jr1Uj%=yXm5Q1qJ17n!=be3G5|{f$m@#_AjB=nRk!$~ zP%5u4?xhsJyESo@{|E`bzBmB3JZ#l)6S0Mm&Sa)C>syrE>xGQ|M!K+ z@&=GLA*Z6-0lWfW28H@Uzfis+i!uqQ_!;-wtg8C}^Z=#maRAc+6dwQ}uV?2#e+^51 zM_dv!VCk=igfZ)Nh?p((1bk<(st$p$ldNeR#&-j29TWZ$1S*q z6ja&Jts?XYc{^=h)h+<#U)1;3v?fa#dZ1o(u}Z2T#456z47|@r+Y!ha6LpASehE~R1yTa5wgAAn z1S$d40O&mnl2J%Lh)k-6f_gQmCG$aDgRG&op;=S!GSIUi-4$9FQL8zfDy90SQzxKd zTgR`2GDoy{1Ca7nNXWPTZX|3}TD}Hk7CTv!Ri06@8KghAR=NXLO$Uol%#8|+`CMs# zALz#+pz5>dpln=L|2Gzr3++EAz@_(btW>VApA10O*vsp#zauUBcSCIp{fDmN0=yep z!(4=SF99yZ`#XSsj;Or)Is}Tm`g#)zEGn>HeVt$$F2_$qx$#%J4+1x#0HwK@Q`!!o zybM4;+_$5!7G-f?ydVFDvi~U^V9S(_c7RznV9e*VBL4!oRQ*5}m5UczF`xN-!FmF7 zwyTBN?jkUgL8<_=suh4K02WZlO2D%+(~^A?s0E}HUjS17RLlVU+4t_Ue(Zh=`AVWK z_-T+aK+Mo04U*USi)}gTS%dVELu4eGn}KaO={3yi~Wa{Ip;x$ zkAJ0O0r2I5F`v)B1KK+`vBJ41$88|Jh`c)hsp2bv!^n2{Jpk}YZPgz9_svEl;OOic zq>Mt1dfvO6PT`CBY%t}{Rtuo~Mo93^w#BilM%Gu?gZ!sETj^BLIQ%W21%T7U|I}&t zA#ZsdXbkbs{-CFP8OZdh3${wJo#}Bb;93P9N72ce$1pE>z*Zx&Vv136CusMB2^uzL zFcx#A#y-%n`~#8j`8*WoYmlyIxlRFi3BUph9Z$e(3x_>vj?LZzV1|3JW*3_P7KHF) zB^t&ddNd5=JIIWW0r(yH#KD18ErFO9p=-6UU=NnSTHZ#uj-Bf`?H;xe%mDp;dEB?q zC0$$!QW?{B;eONy+%#mPu85OYodbXu5MLP=qnTVMl}+hFj_L-1JA~X-aYf`#1+6!^ zBRCkWc5=EpZVb76l{1#y@?$WWy~-?*=`wga6~ZJfwMkfP)EXo%pxBXug%ryvf#fZ{BG1rV_9cV_FK<-UzUW0e!sTtD>YVd2eTQnf&YhRnP_+w8Lc-;nlULly+7#3tulVJvc2g8XOkBPcReMECJfP!p4OMk>Q9xeS zsk*CCf4t)EsJ$}}FEVktU?Go+=H-8`c6LWhsNr(us@e}=DKFPNRr`;&hQTX&q^tH} z%p604umW{hKuJ}Ew?w=?EFYnKF+nQm@3zz@tIv%Ue%l}KQb55$yQgu6EDKFnA z#(PL(8Y5caSH+_@3h-;OQMe|8&%YNcVTAG;F8-4PO6^lg?W0KT^G9*cX-kS&vW2K~ z+^Ifr)Z~GquHzR$n|&OrnF5M?*i=$1^LykA-9DuEtOm(zx|HiiU_PF2>0gBjdBc(e z9L>vL1MKGkj^z9oS-EKIGR_wk%ONHIGQU68h#$&Xs#s8 zREL?0qUNgi0LG_zI-v(L{QQF2)0rR~vk5;v04A^;KEt$71Wy;dGBM(_Jl!v&{4&I_ zC!c~wB9Bw_6flA5=W&Xj9!!_+=W&Xj!YsgeclWNTGA>z#{hlqJ2 zsNVSmgFH^rH%(DX$n@?w0?F{Lh+*%py9x3*Mep6D8Ubqm1dy2OHsUSs9Ugj;$0>U6 zqB{*gk5lyC^BAN|!(4_C_1?=Q<_4;Ka5cakDp_01N4?~Gy z(m{fx8bVT#a|~-gl&`Ty-b!`ivGWKTejcZ2jbf&zpT{X$qq)f6^7A-FYs}+-SHm~d z6nGdvyljA%iod8Z_5E3@DHWlErb&jd8(qd_3z+@{H-aojq)jeo~meV zUx6%A4bSIbG`km+iPl0zT5>mv)+x#w$vjojx=h^%0W*0HIU2E&TQzb5$xq{^Vl9<4 zp=6$_Xf4MK7>b^}pH8|`I4Q|zSkje(q$WR0WR;v=mv$CURkT(s6H3#Qr?U{(sAfPi zlhK{Qb&@74nWrjR*9(%JJe3O8Nj|yBVcNC<%l|M^PUfkK)<#7Wi<5b(qP0oH%944i zqIHw%22N%2HY(Vv=0Un|GEY^swn<4xB!9@zx?S~z*y!YBs@^UN#-oDRIz050H3ZN) z>#-+bq14iz##-9jSWAyLsih~H)Y6kpYU!yawY0BEEj=x@@lC zp6UJ-GXTGUV}*=NKTlP(Ud{lV<>#r2)+?oevlDr$qIHn^a{m3 zsZfO|V<4HQDq6i2pT|Nt%@_YnWM-S&Y$wu%tkJ3uXvsWP(Hf_uXHV`y!^hhu`DoGv z;aJHXm{+wV3BWRnH5hiT$$K?;(2s-iVVkh0`lid`f~ zUn8&@g=Qd1p?${LJXJByBqh$IGg`23kg5eCPMEvJ>AW$uVC!~*p+K1Jn_EvHFX*d-J#(W(syc@rz%=Lw=}*>30v-KU|%ZZ)H>VE+k)?QD2SWFD2{QAskZLR zcQ&p0394Gk?EY4QqvitT{I%N3K}e79+Pw)*D#MefTnGB@_5L}gBCM0BgUr& zHE(Kz_Pq_-=TZAJNUuvUkJ`QS9qkLKeFo69Iga)fj&|Crwevwljm-t#S!_>7p4#@Y z)V>nwTMouBR*j|hmx-R+fMzamG8@m#W&=$tb22;6$!xNdS!)j4RS6XZK+BX2S2Sc; z!VIs4jy6&urIb@6w5!Uf|8DA!+WOPl+G^9X9sMyrp{PzjcE@LtqMOyG3)6|ZUuZD5 z3)THVb*CXLwHxPXNp~Iq{f9CZAdq<3Nl;N+UABW#E z!gsd<&D9al7k?V;yRVCY)ME%4E?)&A)E@V{2az=R0{;HhBY>$N0qk+VyAAZaQy6aU zbh9^8o|#N0$qeKo2LuQZAmIuj9N`WSZh|Q2 zD&m2nB7!KQf*i7l3W|4BWEJtg6%kigQBE&FK|EGbSJw5uuXX?5@2j36`rqI0|Ig<$ zo%de7_p0hub@i+2de!V*^vvCAvZ*jVbGP?b03DZ}xm!cYGMApY+lO`cKXmTa{t84s zbnf=28u`$9u;M6E>6r)T5RA|>51gc_CF%q>tO92SJ@eqk6A02X58g$p3Q~I$AStY^ z0-@kvo(AgDGY{UuYActXdGPKtK=wa$9=wMl@}cwK19bpn&YQUUQ>IM9w(-*04CbTf zp{|3`NUrhH397Jo>CD1$jh9Y1sIQp+1Bi*LdlKL+%XNB-EF1)HPl@;kawObixVOci=`!NIvdK~(Jr6bhiRz4( zPEfhVOJ}BzdkZL`DKfgd#!Fua$_m(qnu7Ci;ZJN+4C)0ya$*jRW4?VJns+BiuJO_d zD%W`Fq8}3M8|K^Rp&MGlgkka0g)=N(x-f>tOD7m|jhEgZaMU$kI^kH@c3ivW zVdg~A_tGWjr0=B@DNOoa`g3Tkk`}&~z8y$e()ZHe1X7;#y>!Y{Bz-TPNM+LZ(wR?> zr0=Ew9WuR>zL)+HkiJRZOD9`h()ZH8N6L_-@1^%d73!0|m(Kc3O8Q>9g<*F}()ZG- zU>X{TjG45Q`Sy9}u?z9+mR5TFNGmjhAktDwSd5rBigp5huWokQ7D*LdmV zU!_{|AB&vJ`sA`Axin`k=`blRC_K;no<~rh=RNSpoZHAb86Yd#OdCllZM#z1Xn-R; zkp2QGGWfE3a*tXD?~uYVj{9EvM3gj<^3qR3deZmO39F> zeJ|Y<$@kKk5=#1BIz^%=8HtIMmwq4h_+C2OL?wMMoz3VZeJ`CzH0gWkL=wp#S*V$s z@`Xv?OK09?N#9E+TY1v=(uq_i_wt!=h9=TG>3iu!>XN>fPNZH1`7nDLilx#)l}9f< z=8zI|XpDT04brqAye#B%L5?|mFy-^^PIZP~CGlT!jpJJ2d+8in3w$qKVBbp@*!R-e zSqpqGeGFmWOXp*ukY2iXA}!YHtN!R#j6qQ0Ti2kZMb!iFTrS#L2Ll$3!ZlQsjcdH< zI9yALe!;a)+24aHykRQ%2;}KKl${NFDEvZq%C2HAFPa<=peo^Q zHn& zQ{e;sL4@7_$!}6$@os>6`h8&FAKC{Kkljcq=`0BZ-MN^wtg0j59-w+WOhN52XA{_q zN0G5Hr2#iMG{oTS8V!xq(4HEWP(veY2@S0~5gSIS0pM*TxeX(4o82hC9!9=4G`}9k zTvXXZgu7EfpPiQIPKmZMtO#`4u`A z!b#iW>My;cmALe-uoBI`g3)yHjyUG_e{szJi#KkMJr2VEn>TKALEb*R%&@h=ogW_E98wPWWCR(ZJb!{~2M}Y+w$1o{G{$fpeq>M{mpmJeMpXD3KQeHsu2IegSI+ z-wgzK9=6J$s4G(T^Mg==I^Hnh69ATko?QwB(E#Ak->6GPPMtqfg`WEyAbKR3LeKvR z3E}Yr0fx5kCVw}=J6H}CZAW#pz&QH4T!0B?qi-M;I`%_H@>R;5H>0;!LqOC`c^JxCh{So6 zKrD)CDgAi?yTwYNxh%K7fQ&nciq3`9`8CkIbI^UShdR0OR=fpr{vwbH=0UvROeAo( zcHu<;9wvDyfWH#B0>BO?QJ6`sZU^u>fFiz=#^9Riu+56k8HDV|v2YF;j+at%PFV6% zCK4ue2amO8nkn?eWk~LdtWBXOvCyM|mPnx+S!g{eA=RBsjip0y=?%4;5=c3t8fshf zY`!+c%ccUF1?keaKquF$m{6ur_O-y;b_bAR$1-$&18}nC z*8#W_0RBod0QZ5;!_>K+K4pG8ke(u6K7hUCYj-)IVcJHH?;MT;kGIFw zJOcXGn@7MRE(GE4&G9JJ|KB6PK0b-DWAsswYQ8pO|3BAe{HMWc5e)v}X%L`A-SxQG z)1lv~XdpNa7so8vm`B7i5d23((0@ey08&WappJfmpm{`)s=T1asD@vdnf~z+u@AI} z|9}_?rl@&9JV(h4^MIg2C&N4-$nwVrL>_1{^MJSrtU)f)7rGNxl2sOuCZ>zzPLd+o zWN{l$0Y@g6hKyI|&VK}iI0k)Oxx|eFahU2ZxCZn{B`6_x*$03#jwX3I*;NJ)e{e7T z5U``NvK^+|(_#mFA4qtT^c!GY<51qYF8Y}Fl**s8m-DH0s4 zK#5dfAdClRUjR7c3X;!$4iYM3J8s|L9KwzmEO?G+&G?2qa|uV4P2u3Y{*cYtG6dNV zw5~%!&IdyQH(F#0T*btT2ZL~*^#I_+4Z|QB+G>3WB-ucz7p(6At7Id^UKBAW`7n`f z)^kV*shp9-9B#`{RICDbk+o|Skl3%t%6gf#N%V$H$T~}} z1wF}!w{@Yp!;}2@skKCt%TYPxvzF>vU<;5p2D0+Rgs~~m9G-k92>Ais7XKm}z5z=C zj}*Q*K2pm0GVG$`4J<=EgsUBY0EKYk{Xoa3I(@m3db$I_ynYnaU7;#Iq&o$l#?^{9 zfnvwytCVtnd>|ggXyV4@tCaB_olupye3ddTU!{!8S1IH2Rm!-0l`?L=N?CXVOEW^6 z(=KmRC54Zokh;MT_D#auKN@Z=$|4=CNEO~ehOtXQ3E0n`qDoq|riuxV3t=rJvYlHX z;$4R_?>-{eN|UW|i?Ce}wpJry6g?$|ejczlk#HIbQ`wmV_O~RQOOfMvTL$a{AjGa@ z8=tTaCN0`baJ6&*WQ4gP(55W`I0o_I>vRk{!O%SK5T zDp~LcCC{amED$AMP|17Em0VzzehEBImq8W%nQeMjS_!0460Yu=lAI+oY3hWVYC zHdwi^_6mZvJNvC)k;iu5OD7t}pP7y`91GK6G4FN?| zBwb^QpWUG_fWXAN6~7FL#r-C2k0Ua z)gsYVxceGoc0PF+SSqBJdICA6aurg!E?-e^g{bK={Rpgzt|QV`5}NvJ)qp&4+d$kD zt*vDA9g5PL3&ctMdU({5zG|9Ga+b-oGC@#2)y;L zem@lVG+~wUV}d)7fF`+(c6CJQ@hFW^`q#8lN0h!zrD85eEY#uxC}k@wU zptJ^;YNVES1~3{xhfBc1L-NoI?S}qk%=3Fz!F%KG% zf0D<4bSaH^B@&?IHFnW&G#_*o$f5^my6J2x5i@?HIXeAuBix#2|eE|#r0Mub_hb6ZU`{CqZvNk!Gb(`D{OKx+)YjQg* zx!q5EtC6I;^$PIT6QT51s3@U|&vfZ&z`sO7>7M}D7osnvQp@InQVL3293^PR(Lw;J zar7Xqc<2vS9Kj;Vt#L?-&;#PF7ef#K#EKv2(lx*vk$}LOPpM?D-kK^<)5>(6_DY>j z1z&fJEBhp)4hO+V7LF-%p`hq_DtJl^GX-h0KtnhJI<+y(Q=()Il$cUIC8hchcnQal zDf;#@V!DsPfFe*l3x-R z+uka*urEd}co(!r=C86A59!xXtX{km^yF&Z3oM=73)NumFzmmSk_RTJo)%Kh!~^nk zzgqHGM;#bJ&>z}x;T03BWgtAE?eB)MlV5Lm-kA(*a+U&EgFB9S%xxOt-Lu-PZ4`LUJsY!1|) z^0qJQgF>U0y6F~lh(7W#{FK$a1qG-@H9zAmz6D6%vuUl*i54!#%89Imd@&y4_L?mh zw_1T*^_QFuSZnJ09vB4dEAk!(-V*AbgPdlw-bsBK+}a+5`|XswO1g1wEdo%OUXM=! zzzTdEZiTRP;{yPCFjczozkuP6u7t*=sBqif09FI&`7VGa0RMmj)K}Nw@Dh+Vf@DEm z+5|8e0;_uVMwYa1o}Xs!gPzksegq<244KtaJ!gUVR}ha$>7iFiJ#`(qw(%L(Gdkj1 zP{KP0ygR^qrs0J_RL`ZL?E`IXN}f(Ad#%T`U6@}^Clm# zoZadp;;L>5``doaq7RgNX+H=1LE>QSzZV<>48;sdUo=bxEyaY`x;%g{ApQz+<74!I!Xge0=YWDWLC1{osG)rHPJ?cr)){-_3 zv|3rx+e$5;fY$bUlt3KWhXHT^9`c(Hv~|!(l9UU;ADaiSVYx5)6xJz(3VeSJNoBwAPcUbuG~?tlKHoKp!S5kH%B^WPF<_r=of$XQDp?ZTlcH`VK`Hz7GIzO^)#O zQ@~^;v`zn7d?_H*&}ANM37C0xr@gEe0;~GZnc!)gKD3eWjKmI<1__i{!!BCyO^{eC9Uo`*w*^mrfVQQ$oiVCt455+J#NV@Z}W+6(ms>4 zx_2n^vCU_%p?@sBj-G(^u@tB7Zi>HU^I2(F-XhCDKEAED*f~Z@9Zkm^@g@tuM+(SU ziILc23No3Q4U@DdkT&Q%A5)_^mhewJji!A_EW011jAfvW;*;bsp6``FbW;J^K}OR` zB+B@D8Uc>D*8=DehWG7{ulR`Dc(fKj=>|1)Px*(g12ycKrSwprfRH$++!-X!DVfTD z=bScdMUD9jyf(Vol3hb8&cywyAr+Y6{xmujauO}jqf>!4k(2c3)bd^Qpl)EW2!HPF z4M$e;8jh^wHKbxyg4Z{sVpW1m8X~Zu{5CbDVn~9YHl#v6f-k6Vin!$PUMF150$}3^ zvjEsTm(_xMFcodkYymLzU)}-9=B!Zj%~`S*7#ckt3YxD4hQ{(n_8WcNN?Wb>A1Hg9oR&@+3Y#v#e8oJj^Q3wje)6XcezaKAqj3=r&3?e>4r zuHkyg$h=xI>xK~?Ty56EBBNgdqpTZ7#*nH!^eO~|L6CCkb;AHj@_s2YmN6`mRQyPk zOMsE(%sTiTz_RGXRY;eWw&W3AK%&uApMxA*O8D}l0IJwrJo=(nkj2U5U>Uvg0ARd_6@k@HgDFGeSu!qS&`gZ+ zEEyLQR58Z0WGo`=AkO0_u-atJSWGa3K`Nn)C6g${c$SQ%1XYajEE&rPQ>qOAZL(%8 z?@DkLY#p018(`cy7uPKNOz_8Ml47qc0C?u*l6W<)*&jgRy#VC%=Q%97TvWz0{V>Og zo&Qgy#YS|%WdSo%u{T@ea>3^SL$SYg1-$SQ(4#S)Z56wa3gUR%*b2x+)SKAZK*J2u zg*F!ADsaghtk;7}C7&4yWQdHbmTE!1%%S>Q$OOonP3!grki+IjT{;8yC^-Ruw3@5D z>45nY+yd9BK(Z+@AAk|fSP0ee_?+FK#LAFq{QQ%Ui;6u5qs6bB57>#-j{tlV^9#jB zVdRN#Wd70E0$4Nt5aEnick0D<%C!_PS`Si1ck7qAO$9lfIpBLu@nQ9nYbBr^Y%G-br{?Yz_H$5uP3Un)Ka- z=f>_K{1V~wVv|{+mkBS7Jw^Uk2rr5)A^a-grLlL&^BOC$B1We>zK3O76-!djUeZ^` z9wyH|!fRrekpB95@LU!9mGB#+UmZJ{I`>m{ZR}mr50HMnG2WYmZ-`C9xDY=`_{P|7 z>U?Vua=a;4PuX{9s`asI!hdI*ZZZw>J{x4KY3hDpk)};3n+A>_dK-)_OR_p2OFMIQ zKdTEtbPe9GXQcRpN;ZaOb>-%cmK9mO9wPrD2mIA!RGHiun$?>EPK+BvvufCD%3>B8 zKdbr1(5zbSZIO+kS^cR-Hil+bOb5Gc49%WHumv}U=A5LdCD+N`5OUF#xG^+)<2$&9 zxG^;QE>e|OO&&l}HCwd|W&foHXv{+SvhUysrefR}ntk^_A&M8*i;$Xq4@G2SX!ZkK z8ja(t#2|1pXrcwj`ixyLPHv*>Bh5o1W84gC z;CLoBgC@Fj6HEem9FPBABQ87elL8|n*$kSf9s~t3ZU#-%m_lfK@IfIcxEVAtkZ_60`xt#Aq!S~# zbtlHnpovigRg9ZK6AgqH<$pkU49l!^J~x9V#uIV0=_FTyNh(sTGM)u}Rig0~suPP% zCa7ZE44OEKnL06U22D(P9rRF)n?Vyte*}01Y(q^R$5j%1m2rnw$ykLlgc9?(7b(VF zpowz{su*{HCgzJ`C}2m(kXWt64U3SHiCv(H8-+6yyFe2+31cR9fhL*=hGLyqn49|p zj>fnPG;s^zSSELYCT{%~vW~}ElV=_Ib7R~Enpppk2TQ6z3ub-~D90z}YSLsEXyQCg zUb71{aiM+_YZ_)3sE?Rkpgv-DfhH~%8M6yCu~?5~QDhfrVu_^W$}Z5vGC|BP(8O}x zDFdxoz+Iq;6}k$D*#(+dsRscuyFe4GM8@m_O;g@!7X{PMK+9mU z04Hc;VJ(; zkDxx!Pzc4HFc`A;AY)dvnKqJA+Io;g@+lb&dHf#SSn-X$Sq!w!X!09UgMG%-MzMxlVaKofNW zn_ZxZfr6M_pou~F?k(r2XQWU7(36`W$NHF3`kOEknBO0!>Ww zixlLjbgZP9U7(5ML?numk=^V9O-$D<(8pyLXyPR4;$|0U;$+QcG`m0(rwC$pfhJBB z#Owl1%oKUE3p8<>p(8O7S)EiH{9SSCu z4yr=F9Edxl#2p%=6~_i?S`ey*{C6=rpGd8Ecc(hTNs>58uIEFt=v+3!9hyUH5qE(m zHW)aU^g9jAXGS7uv$Ga)7ic16KS5X?fcZ9`2T{HWPELN9EmkxdPnDzhLs{`haB1{3 z`X~Y0DaFgxa!|iS?oyM43cLrnxQYT7lN_*D-Ge3cSq&hpbLc4OGA_J5Fg{ICt%r;P za*?A)BBf1RB8wb)P-U{XvslDb+pSDEQ;@ZoQzxja=^BW%6J;jl`(>Ck@5WlrwP1m* zu&2>!zZG~BaCCg7=Q^tG@l-X$`2hIwp!X0}S(xCryQ90L(ARId9K%ju)?}D)&LK|s zUk`Wa|F0%4$J^FBoCDlWTq2}KIGm_#0^VUE)MKFtul2Z$hxtO=rlaboyAtD9NOGr?i#PO!rTV5yLGt1KxDZnaKN zjX=t0_SQPBo)xB_;&?wNOrO~-@eeGqT>-8yZ0fDL6nIxkeJS`5;9b~UhoPbyRs3p? zf{v~!ys`?3M}e!dAAr*URDBB8I41p7Ujrxr(9InvXACDG$mP;*s(TC+He7q3RHwRO zq);$YjZf*0<0wFB4|!VeT;#2K(nzgAoz9Z{V0TTyl_QXFAESzU-WU(kd}F{a z=9>gS%r^r7*7qht+Be@UP-woBeG<$!$1t7eQ@X1@3qhgzR4q@|(DzA}3Pf}x6s8nQ zTIC(s)DK9?o9V(lD22&i0dp3?oNM9zf5_NFF z!a8)X0KhVEe-Q+@O4*~gPxEnAdkVYqEv9(L$1KB6g9JMqvl?xr(Q$hD6xspzY3(-@ zy+*n!Q{?t;x*qK9e&%>%QpTVrYyj2WbSA96jf3pRyq#91vo*5ML)P3NtHcUtL00t} z!7<tm_$-GeqTTs2s43nV)Pj zulfPxgm*%V={pld>-WH`UIn|@{UCrw zC|UzfHk6FiTqd4}Ts}mibd0#eg^t>PpmniFgJWUE5WLwyEp^jW5ZgV;8eVFBj+Ej* zqq}hDp#HOP9!*@v#+8CUNPHb@b(!GBD}k?|Jyu!l+p~yY$&v4J(f2CxW7$YoSR8qN zC4MpauaxxumjSPOsVzNqU#{>J;c`v?~lOS z^V>u(qIzLuhSP8BegXa~@Gr?1wg)=s>c0UGq1AMT{Q^diL0Ox(1BAG0sKeaiE=t#Of6Q#+w8TQ`H-Qp5XK0ZGZPoz?XpUVxOflHNf$WWHsx2 zO`6;91JwsXy~C#>uj)^LKW=agi;k+MX||;ZArNv==>10|y0i8y@h66+d#I{DAYIAY z)cI*H+KabpZ`FMaNH-!a-;nsCv1$TncYs!Pnh$he2!K@?=?h{+!7~$M3#-y&B~ocv z8i+ehYVRHe>yDEC22`DjpKj`e25omAd&em0Ig?=WcAMEV8?2weF%P)u$zw$FTHvN< zjWs=s(GJLgz4i;FwLcYY%Rgz`$(Hm5;s@As&a$cq%Uwr+H`Z@{9nXa+NTZpuz)Vwg zQ^Nlc*ywZ!zu(|EW{l&^VCLiRH5mt~!3SB(!4_ADFmTm!(Oz3p^o4^{2aHceziii! zmA0hPZ7xS8Z|3dhSnHwgRN`Fm!C3*s9|vADbB5Bc+%fxz%9AK4^$uTwuF5-PH*(m> zdbYFbc);dt8dSuJ+m4g5Uff74Z~0E=BW0~m<{`2C~$ zIpD`M!>Q!7BY5|J0B2n;@@ex>zh6P4MXGU7hPv(ubB8$aRL863Az%6;srzbpZS0x4 zN#~~wd6Crp(R5`NNoC#xZtA{R>i!Mzs_RqU-xdI3*jk=crcV^*vp_5p<;$sDo@Xa& zKF`Lj2F_)6Jwr0PhPe3JGcLKeW%7*sumCS}|HYp26JKy3Vqo~$yk&l7)79OJ?tT!wtJy4_w78a0 z_GFfSq7Fj1R}pY@apw0wyOw!od>87s2>i1|G)O9(o-UFt(0= z1H}$3XJ+>JQG}0XianuiCv=Y+?Fs%l+Y>WTD0jTJCsbl=4t``$e5e6VV4-7Ax(z8# zOL0r=iS0=ZSa$1=2n^OX{pr$OPz*$>H0dHBb}l*uvl$9D`+mET$9QM#;uO*z3yCqD zQyN?~@)+-o2PExurt!p-j0Xr}p@45+8hMy^#&x3c@-)YF!ZF#6DYX$67$+9^5Xs_} ztb*B(V%k2W;h*{&Ql`*h!C9x9Kzj{1d+A)<;?Dx7`%<+Xz$XCI(QJ%DSUW0eC$mw@ z)5hmmHfS11uOSz8%vO|7==H3xIShk49cILbj;@< z@uwS)Ii@u<;g|8_)MaP_{_HdL)Y0ez{ADh(j^P1;{Iz&yYBuuV&+V*_sYT=S*K+AG zsj~xH{5SNx+eZgPGKc*H&P)Gct5q(T$24=kYMb{mZdP5$$ zW@-$j;Lo0@)kk48vZ}4Z)x7rpVzmF-8?D2?4^Kju(*Hx~qx~Hm2fG@DQ2tqj@&??l znJN@Hp2RlMFlUhB1UM$jNhS7JYyku1zZ_QRpH$*U!)!2Y={MkhY~&Bf*(vEyb*nMd zIc4lBeq_vag2bIlbOiGX+?j9_z&`{}=Ak?L!IN(y)eoK|RRww2Ab%kiApM5h51#y< zx=bXbXQEryf)bWj$?ipSAQs`PWcOl%DpH5x#$80%!NDY>@n2pgyNd~i-}I<5x(g4USN$vky6rM zWYwb)zUcL~Rf4B7!WX^XcESx2zUcLKybS(RBYe^8?Ib)a!WX^XF2b`Te9`OeCOkL7 z7rov~gwKocMX&cV;e`>t==EM9yePsKz22*Ymqz%a*L#hXSP|iiUT+V}wkpCGz208Z zS4a4w*V{*UO@uFcz1L~?t0H{S>%Bqx)e*kv_4ZSCZG}03chylRk_p-km85xLOPPo`5Yv`oq!R65+!1(@s`nc)@o z8Mq7K1_K{Uc(mbPMR<(Kp~Xxh z8%63k%D$nurBb^vwQvtIx(#FbL6BR)+v%?g4}f$ZNT2znZmK9Bd1FeO?+TOgqFQn4 z+KS7Ji*zeEjMc5U%n0U=WS*}E{;$l~cu2N+>Wu%!W`$-`Wsj7~uMIDcAweP2`Qveo z0yJml1H6c~fad4_7jDR?qG5*btN(@16oFccCmHVlDSv8ICGsTiq;(})E%_MxL1$@C zReC;=mkLK20!LP70+z+&XP2U#+aS(J{y%uO$3UAv6 zSo~^C8tTBoz62kfoqaOU6>RFyz5+-7iy*ZDTRCZM_WMn@VusEllbaC|h`=KVociF7snxUQYDLoph^QmDv z09CXPEHF$tlK1x%KOtvs*3l;R+u0GM%~2GOYVk4C`P-Tpv&FREfvxo zyis>c9rPVsth>`U=P&SDx0FwgVDN5SYvC{WxbBwPHyS*sRZS+{sGqvyY8>5_6O5yK zyzl4^n}tG}GxFrXJL^C-%H=o`hwYftv>mfS(lP$9V@~0AtUxDnn$!5;yf*W37Z??? zi7*t*LvihH<8WCq5edGFdKSSRpaxp302sK1_*dfr^M&BY0P*iWv4i*SFr)nroYNle5ZoNKY@>6lpC$AljIX8=Y7NSrUK^4KKt57#);RLzq%D|x@H(ePx8sw%c1IHtB0^b-&CXnBE z$RqR#F2{i&g-1rR=_*vcpBZt}Rj9^PfSayDeN0Z~1U|x{AU9ow`Vx)?Kf{A7Bn=!7 za?@3)Kk11eH(iAW5Y7#n6Zi-h2F(e4giDT`z}FJYL2kMVjUuRm+;kOcAe=gZk7b5y zRz*9EC*ol6WIt#RCaK7g6ZmFOomgx#K@~J7@G(;-Xinfe4fIfuo327fF9y5&TxQUKuLU(9 z43TW>-;gYx07+GR0j|3E-(%r-6hDotUHl|Co#HR(Q58=E?5gMbyybt1$_I~cGAsHzbB-DZvyhsN@qDgwzkqRk8Joz1Ex=2bwMK>^? zO3Q=l=v=1MSQi4$be7E<-=cDMkgg|8xiv9vVzhVO{e!jN&8kA5K*MN@2fW9op zAnOLQmH_ry>#bkN8WkJliwz#f)hgbKt6jVl!cOrZ+CW90$G^yUi@to(1i-$EW36^r zCoWzhxxEe5$jya;BQvca5)wayR1!JI+6W}sk_mG~LM8W7;XLbV6w^t*&w9?c7$_e~ z9t~3DJgG)B`3{N_IbYb~$q|%UAV?zlIV*L6R3SH6PPT<&!a^0TV$wxcH)I-M&e0qS zF120&oayYsHUAA<#EvRDo7^j{Ly~wH*OpJB1R9;m7MA=mGdg^-6Vg;OJ2@CXy#lnV?6Pfb3l>sE0yp}RgS~Wo8$%n|c#bSo&VV9Bb zY3p=g0qVz{k8AXPO6;|Gdj;MFA@m6@KjT-T0$<=?tBb*)D@bWo4u!h&T_{iKOq5ht zK8oT5?Dy`$Cw<3|t(FzUNinCWk~TBQd>MFg8v$yXnSsGgf<7;!$-Y~QSsPQ^VH=Qa zSZY5NCDco(VpW5`v!v;t zBL8WU|M+Z#K8h*uzp_g?_LSwI9JRF5xc4wAZ4mWqpuPj*!6#7p$q?@#yAmee4|D<0 zj{g8_+f1x(WJB$x;6~LfeATm}1b8J9uwR39t7muRpRw*YEVdM^o(200RCPY_47{hW zXGh)&wCpAprJf_?M?jm~-Zxu2EWt?NW}8QtL)`%s#b{@NjP^Qecdvu|yGTv9U6<6P zI{aGK)TBC$lk0UG^jCFiFI>&!xz}Vfd47-0g1^URW9Vu2mdO2|f+OAL!I9112f58p zM{{OE=kLE@74WC#Tr_YGv)%FTDE(3>C}ENECMalvA<=DBP!2|O9|q{~BC(Lc2`dS@ zm`aEGEg{HRb*Mj82A$7w4SDgvDQI~W{x_-_m`PBDdo%(*jj$8G9K&4T^ry)iUNH&q zEW%O9GdeP2pGCPdzW~kc3WBUBcn74=W(6TCN3(?+<{~wNQ~2;`7BGWuRd@`kh-1W+ zzf8*g{smNcEKeGUJ6Uo#Tlnl9z_R&_3eVXFW)mjaM zd<5sxpeM30CHIrxu`5Z;*($N37d$|27oxiw>9c_ z0l7nA6Y+Tz=+Ur=_@sh##3%J;EysNy%AEQs;OtXps?2GuiprjKmdZSqAk0jb%;R=| z10x?mskt2I8n0^tA&(ASR)&=ar!VO6{ZYO+bXhyCNk9td&}HqmPGLtV7&#EgE7rB> zD^39&x~x6c8Au7KLgUbJy(uf(;&Gx$ap;ob&?Uv8ONv966o)P;4qehXba`~>vhpRv zd~xWq%B-K5I~}^Lb{1aw1EE8g)!xsY4qaBcAfZ;gS+Y6^5-p%ZmsKHUh!@bI%jzO2 z36)2O4!!ecsLrE9msMkBfjj85#I>kBF1h?}doCeRS%gC4&`HGxSPe)>ibIz)4qYA{ zx~xG~XCxFFhfY}QE%_*sICM#I=#t{lCB>mjibIz)4qYA{x~%aQXJ>`Rp%WFyTAP`h zICM$l(B;vg%bIC%4K80Cx~y}ozPM=%=+I@&6$w>9hc0WLB|V^k4qeuKD*%yD0q@4F z^Q0Ql0y=bA=L=iBfDT>O0znc5bm+1!kSgRB(4os(C?+gad35NqF0x*Px;*-FSxc=+ zC_vCT2G^pKa1j%#Jo<83E3LC7aXzkcJFHGIn0tafN#)U(%UUCP^61NDU1x0+F|LiZ zWQ*|hG}APMkQ*zVM_(@MW@{hdpmPw{mK+IX8hxZ0^XSWE-7ebm#h1&v$C`{zTR>kf z>prWV8Vl&lWj$!I0!{&axvWPl7B*BsUoPu$s|iT7fWBPTlh$@1@dEmCSz9b-h|Wb{ zF6(LQXJ8KX2c7A1JqOp~Je~#V47B8y`(P;GMzM7skAZaVvpCS^%Q2A7R*TcY0-n9$ zykPwuuqxoeJI;$D;S}%~NN1b14GAHfrLip!4)EoN zp(ktnKor5+z8vH*k9M|pkgUS(2=C<5uM_6c&eks0I}n~h`ul|aqn)ioBOvQgK~{7S zm3{mam2sf44omL{bDXjM$zcY=+51fR;zjTToojJzJ>V!5=`R*dUHC8_>ZWQr_gg<8 zHF*I$eDVuC)V0cEa?V560VL#4oB}iC{L|Wu;jw^4&-s^FR~4|lIiE>GIRz|m&M$%l z3NqRN(Kf3XDqt0JY@2nA7IbDI0`{Fqi52w6t(X%Ows^srOz{Ls6#R@#b0Rj|Ah+NU zyo#I*LGlU?ql7t`g5(#pqfC|{1qGR?K~6#x;O=9wbMOfPl-gm@^QWUuALbO=o!}zK zAdpjJbJ#G0Ku)oJ4PZwGft(Wi$RLnYYI7_zgFsHXu$e(1r-LA75Xk9ha~#WU#lyXG zI@_0Nn7P$CM7r2~2=^{{ltu4q)5Dlm@EGgf&F1*Iq9Bv@?rwANUR7`}E7e1g)deq5 zrl-v&T5GD?TdI3a!6I6v)@DDxzTkEueQkEb+Y16j2H5N#8w>7aK7(xD?)MhFOw~ih z`u7)HOQhar*Lkp@7xNh*$fE^kP-djfhwi3=cbGCtklh7OQD(ILDrDX(2%sD0j1|@I zt328_XPmtYwzfZl@%12@-KmDTbLK;#9=ZeuZnIrLzDWt#a1u&#s?ltEn56B13O&rE zRWfY~^47y8?a!!`9&Xa&c}R1aRxfEuW>;_0aQbRV*=|%_9~-dMz1S}I9J1YqQivCX zkbtd#+pxFmQ%DZj^(ihMoF-fW<$OXej_&#lk^^=nxn@JG1g=m@R~&GgUCjOhk^^=* zxZ13PmGm-0C?TPdgey#LxgfON$J$)!u=L}`nk{|0iF=?-eA|@{J7fFnfN!W2&TYW! ziOU|_D;?r9fwwQFrZo;n@s+^KkAb@VC777iV#;XdLmj7*XQ;zIptC{lBr~m{B2>Wv z1OarUS8xD9@LVq8;bK&$2ykc2_(sS~0%Hm9pP(}c*VrO-w=PH*YdEUQS8Ts>N6!My z4r(_JdEHQKpTOn zsOmbF-Sk^~;~0NOa1+URaY_m0fq4orO<0Fz=-VMN8^UitH zrltzu)iM?Ts|_l4(1)qD#{qi-Sl^z-2u*;@@t|6#>6$UX$yPH6z~=y{croA&U^@GLjHNqtHRf)y5}vQ{_>RJ^+b*Xg+dRy*11g19deGaLB%bWr@+C zEK5Fsj{x*xYHd4U{{hx_DymrmnRT@6a$PeQIN54W1<>*)>Q$91{lZqVRhehi9sp04 z;7lsy(SaNJWG$-uWN7*V>D`a>3x_+F!{dM=-l6?u$euC@Jp+#--Sm1+sw?)Bu2_le z+DT{YC!OtS;HGm8kOy8EZb|#QIsDey^iax)pEd>fK+$|Map}r~q$@8cE}eO>bmo_U z_uh*Zco#)DuMl$Q+V5uJJ-{cR)%+co#LX}eQ)<5h)(u$YA@E8={RZG?)NKPK*eZzF z2_v4L=GbgVvJ3jO$%gGEpRETreE1~OyePwMupDJqvkd3kJRhy*KG04^hN|~qKov;c z$ka7<8+bc4(?DB*)S7Vst`N39t(000wr9z9kc)d6mzrsS?gL-lFaUkXQ+o=a zH$WOV2Y|I^QtgHK|4$HVR{$u!1;Et+CIT2V6WM$T<c{)U0dEf=dZ~Rhn!b+riQFR#k!Al>s@x+t zfl?U)znH!Rz<$`d6jH{BRqcFI51)j4q{1f+_er=%dV`d@N9H1DRe87HoRyCPU{d8i zAE=_uf6Rw@jXbtxv0`U~WfD>z18>!I0B&og?(tcmvuYt|9HgJ|X}A~5m->9XH|J7~ zuEgnqoB23=%;G41Jf4=Tq*h4!r%AFFz_e%jw92I^U|kA04{L5@ue>4!-0lPDPhS<`wgU=> zOX;Xx&q9ZbG38qa;5Q_;0iY`9pkC}kmCFH0b8iLE0a~ke1K3}J6ICH9P79yJRU43d zPb6OsDqC+2%KcZ+>OgzYr_C+w#zQyn!x-0%fj3~;3YJk|+1gC(0BDmz`#2@m8-~DH zohUWrDOUM5SWW;-)wcl70FZ~?K&#E&O{?i1lF@jSlo`zf<48!K55_Jj#!peX<3LC)h9 zfE&-E#-bmyi?|HleI)B|iA%?=l`P6{Ls#V}Qiw-SZUM5GZrzGJxuHdEg(#5c}gpQ`Vd znm6h);1!D+A^Mem82tTSLhpVQ>MW}JN%zS`l|KRPX)xBj3*a>XsvrH9$5U)S>tn%I z7cT(|eU=Z&(z_L)EnwM1D{5;gHT44R2Wp}R6!{C;PRCtz0Bo<4t(CQpYzsjvMrzFp z0J8w}VQTGKU>5`H+Y-6I4VlBBT4QugIq<8f4JD(0_6gGD;ZSV-LVfhlHc%h^v(01_ z|L|L|@ePzNu_omqmHy$&WTSuh0f0VC760&iVB#O9WK#a2cRTp$9~J_@Uq9Bz!eEc# zS0PSyBNekgUCGG$oDHCVibLwO43tr<6R8&DQgyl>3HXyb#gHa->R`P>ovhQn)X6$M zOGc?vF4%Her;b)R`hwJHAK6%^?*a5-s?^E5!>?0HCRHc0nL2@kiuu6p2*s6D9JYp0 z@mkO-nJ(E@Aaxv5W7e&yY=8pR9y#7LP>AdYa3uI zbOGJ80UfEG3=22QZL%MV>t$HDMQ#&4-b_coz6k6}U}*I_QHushNfkfVHO~USn-Y%#_^a>? zJ)b!Z(tE%k$BgTG{MSvhVL0?QX!6r0c}5MVPuZ}V$JQX zD!&Fzo^8JYIE2Jry$jDw>^2|EA#|_6oM;E{?Qg-#iN7ZZ3+AMs9jDx#{vKF>*7ET*r%13u~B` zHCLzdtUBI+?CpM%VDs^8I1QoGZmQ^K(fq2*267f#cB_&USFzD&p=wAlW!p^T zJ8ch6bA4xOAY2AU5FvHFrR|w%uD6OhmZ+r-Fx)vZhx zYg@bB5UT}09RC~+rK<6|;fMpm&)I4>@#9!@=<0@N>Si8u<|*{<5d(##G2f?4X{UI-fiI z)8th2arm0asq?v`*H2EJ&mCRTcn;c(KPz81e$!1U{$fY#$ptHzsy~#HU2s3>pr-eO)vwFF`HnfV8G=cKedwDlwx+P zq_?m*Uu&dk38QvO6M#FR!-5j}jR}4P$ragvYi2RQ1e5q1WSlW1ja|lTDqvcINdhHy zXFPtD#Q54>2x8>jgbRP6w#4v}SBHCm?XFh?4OG~@e#3uvkpogS*|1Rr$L-p^Hv@EB zzCX8XC|Tw*3dHuKK%C7KsC|J<=h^`KQ;qXASe%M;2wn@SGlyV=Q6PbnWQ%*$aW-J} zL1pj_w6n1zLAnXfU8JfY&2SPRDXgsmA?Gj4fx7Z4@Qwq)@mr)?@lrFf2Tt!Cf#6*F(%k^cby@>*GS7^FVCJMw| zsn-KBQ6TOrkugyq?v;X=C=hqG#<(pFxU= z0&#EEzrkiE3dCI}HJy}vAMNGdrrD`X6o|WC6ih<{ahq2rEoGuW+{cDNURvq#Bdzqr zkyhH&td&d@h-szG&06WHX05cPSt~swt>iKa#C@LQR*8GU48SkUK%Qmp(o+C$y8>{z z%N^tH&W8b4xQqgEckKpT8DgZfo|e4>^=Abr}WXenfsm zf$$%ToXh&;vLdbqbqdEg&L|MKSQnzCCJMxDqr0PG5(VP671%_9xb37TnkW#rz4VX(F%{I%By|FtC=eXJ$pklf!Z2J1=~<|$i2`wl>QzAEDoENIF!{wb zQ6TOVy_Xt!0#2gwUpJRhGEvj=J;FvQ2ndhMW5A` zKqO)(`ka<}NyJX{1)V2_EBPLhreUME>qamaUj#{A+=Q!Dd;+eHigd!i=p&*lvYlD& z)n`an=ir*Z0+-zHQHqmK;Vc?@1=+bI8&6^$AFDlC#j= zqldKES0YWKA4y@OD$+=y!}<#FWl~E)goH2j+ki{o$3=Gz*yFHGrS(TBn66$i8LNOO zfNo;MNE>-6R!#8fyQNsvp&n?>YCYB$S2IhvWvZDaaOs(U3m4N-{T~ig`u!mqaNDGu~uT#LwAv?LNw$%fTXaDQ4jrv6E=xa58c6P zD~VAL-7TK9k{I>SJrt1`_0R*00cJY+7?u3lNr14#sCzBgj%Ie^bzKUwL|l7S1SLk@ z>&7fhjJknMjJknMjJkm(M&0Ya5|WHjufqROJ6vwWPYREWWOm|J=U||e7_ocEi7XhKEHyjv8rM-B=X2g1+Xl7UfWv)fK80L_cHaH7^>X7)&;W@{$r7IS)W{1B$wSImvoqv78D+g+|79mYIsV)pXqQ~(egUTv!czk zk(AOFMUrTv0gmuMn&&Rb;LGaCJ&G804#uaYa12VEop{B1ElO%;Cte$U57K3J;UK2cH(U?FlQ&;od)LY#0%Q&tTH?CLbCf@W+z_0&BsEaA8Pj~ z#N?x7;n7c{rD7)3j#N{NtyIgVE5O=j9PaSgHK4@(2s^ImM@)p>cJQd6iLj$4Cukz< z$dZn*YemeDuzLl1icEyvpTS=!5o?jUq2Q1LMFyq|6d6RSDNrLIDUctr78%?cl(*8J(XEFStaea3#&+{GtmeWu|b^ zW!yC#gio!a%gL^SoWeyfMy&Tor%;sqH%-i+9!CWG^L<^4 z1T)LaJfy|$GRw>SNGcIkQO@!*56dUW0@Nb2yv#3j6X5vN>gjpDmXz-NaGjMOrc=M zKLNhzC(xt8U#A1Um~cGUaw@Kim`Nh|9O;XxGB@}YWiMg>C=5P9`Vv~CB*^%#_)=E5 zEchL)8ehgCq8z5W4?1iXE57^?l8b&j4$)CPcxx9;LMB-~1w0!vS=B*OKSq(VYB=O& z6lU*u1=+@aJ^^p=cK#ps-UB|XBKse{_dX?0lIKZJNS*`;(gFks2@#}*UZf-;G(i`! zz*EYAD!xAD&9wUnMBwUVa)_C5|BxH&Tgv)xfz< zq#sJ7;FVtk6C*k`w&1mFbQMb6>k<@ke=7%8iDO8_jZxzI7#QE>{+i<6c%R~k&btK# zG`Qfs`3PsPbPE1OgW?Y~oPzfms&FFvqSy-lJrwaV66HMthK7O<&e04zXfk2=kfBN^ z@+?c|qeI9*qP)$37ZiN*fM)oVMiGY37^=ZEd2cX${%bOjDDQ1lpH&54exMn?Vz!0h zYlh%ezgPfYh3{o} zstUWLpQ*xsq4^iMPm=e1rn|^pOWyC${tA|;@V}YX(JH)^I-I1!&r{}EZeQyEH>P`` zyF2BaPW-P_xGUvfqr!8U?j{vJ52aRchtjz>@%JlzzM~G0sc=4dpHty^r2mTw=aK$R zrSsp2-=_4*p`IVAa3#ZEsc@V$o+tSl#c;Ow74@9Qv?>h45NVtN@QrGa<{}iC9`a+6dr8reEC<~$2;7{W$1VV(Ne&|+{5CGP_1t3kRoR8y z{Ki0n&bzg$4&n-C~RpdSMLNq<2X-fOCW;}2yA+j+ks`yRlJ0^I-; z(Qh0uhf+in0;>?HWfVo!@u&$}5pbWcdB<-Dby?*-Oko)yx(FQ3z;a0uNp(i-=^lq* zPAhP4gA8J@Pgzjc1C@o`iDVkPj=RZ8T!-D{%dxqe;oCvgNl|%;0Rbn^SomIsX^O!e zBcCxjhid*6!jW8cLqw9meix2LoLNZX6p#%5D@-hVI>m4g0gbNlXcSLw^feS(&wEjC z-I6v%eRKy?)Fo2X8(;%f)Fo2X?-Q1yE|H=haFZ$O4xyqhm7-pOSih)wD3Y7@Mq#Uw z6!pc3>`SB+^+oIgqs}>Q5C)wX5$fxlC9SjG?0LA-M0U8+#}QQ`B=b{|^-P;UHbEFPBBj|i1CnNU00OlqfWF;kw-FHy6qMl&rXZHZN^q#McoeY< z7@OnOuR)m2jt80OvbYi`HoKD)$|{R}ag2s(cGrW7&F&IK#j@C)f^XOG&bHm-MMSe1 z1$K3YtltNEye#H)>AZ%DKYUrNI81!qD`GKc$m{!p@)<=*V=2mKEXrqvav0ymxX;Nb z-5D~NTn{O(eSEHmEUt$wu16Ht@NsOz>)mhWxX%7kz>R5B!0UzeY#6h*sP`LTzYFjP z+4p*_`xZF<47ksgl~}cah%Y)q+9vlaBwybE8$1OYaL>H&)13P8K>r!&cMY07k5fBE zqlHrW)&6nd-UMm?QUu;dpuQ4;&k?AEl57^stDO2Cz!NpK(6KQtqybf`ltA2z%P43$++DC_ga$ze7MV%0`G!3 zy`}t?h@e9et&DVp80jp+(qkPd_5KFH%4kc)X!il`a~+Jf02;hOqh078QI6`*aKo*L zz~@8tryw#7opTVw++HxnsXrgM?!XOEIKRrGR-(SfB3I*`TAli6seUbJYd|~8(9*7O zH8?}7_9`7G_GS?PkL{57^{+t`&0c>X0z<)nu1SB6Q-2I_ zIQ=(*qzNSTHzP0~foBvgOXd!ZdPAeeIQ91d#gh3%OFRnA{f`>QTmwdj!MTK>;}PDowlGcMYVBrMuxh<3jKEQ#?Tp*GqC>5Tn`>98egBk-$@abkpRw84>( zGG2VpKiQ{T1aQK=WO?s?#7=y(5_kNtu!#>GM}oI{dnKwU$ec+Bb;cdPwNSwQa9>1D zUICPtqALo+*|U&${B9=2r}Ye;2Z}R63XL)H(oI8R&VpUmF-C0^R+;11CMt7N$gP6T z*xCgU_}l_iFDx{mwo(<9tLK=jKlr)Y!d$)U=jwSsSBt?bxq7h}yppT@+rTQhT879~ z)OqV5M5q*R9Ex;AZ)yPXJhNV4iEbHQ(F3F~gdGDkmjT5qn zznfvqH%BZ4aP2l!<%s~@)}l&eN~o_TMR%w-PKxSUW~vEb_s91F;dLbRE?7MNLQ324 zC1{U9aJA~+s*83?O|fNqc{3jrC<*!QT^C67W> zH^_BcuSA@(^d+?PwN#4hxvqe(0#w!MQtJ30fc0B++dLkeu#XyZBW3JndX zybTm6WMJ$xJ-Yx>*SOO*^SRW00Cegj-epOo=ZtOI7x+W20*?pKZG962&GMPxA=C^X zOwDN68;04(jeL!$q1@sRK#V=@Xqd|TEW)CkE)kyzzG*5su8lN3#`w!3Ev#5Iuv85t zw$1|iOxE%ESG=#A#V;Wicf@dNH3E6JgUD&&IPMy-3=|d)ttNB0-|rpV`h%qQX+-)X zF4I9|euupmX4iW1!#Ui@&a3bach1E{_$wJ)S*7lrZ}Tx8z?D_$&Ne&clV8pbc8bq7 z+ryI^W#&>h-FzC%loO&o+EPf7RyPkl-PgIJbBrEqxZ|5f%+ zNq8AJo{})m1;;AnGd_r9=9B~%=pQ{LAqgUVN&>~~+9?U#GN(^TID$d$kI%S)SoO!; z*n*^#Ri`9yYf3w(BpeSk7W=tBKI2BR=u;9J5zLMLld<}g1cuu=C1D0CwLT?*LD_-w zlTS&Q3r_Apq5nvHiiCcNfLI!BS$3c#2K^l<*@5zZ{FDUl{nn=>FsOE*B&INIPD!B7 zjyWZP0C%9U9@K(JGGcb1BxW8?aomBDn8jdwrz9)~-kg$fHp1M2LP?2JapR>$=0?u~ zfE_3_jyWaaPN4KD2@E8dfQxYyj8fphh_>_b>c)f}pDBM8fpOQda zyQd_qLgn>ONg$whpd^l$uSMHGCE+cYS?xgi!BY}mNMI^e@{2?9|NU!R{wbS(O2R(@ zs2wPYv*ojs_D@M*I{qmMAArX{CE-&5{wWD0^G`{Lqj>#O62>7v{wWE}oZ5ksxY{iM znSV+G1#kySH3}t0OPNy=&Ozf;rz8ZW^ixksuu3U(N`jPUN$7>JIVFL-?VXaqlL^cz30o01rzFso zsU0YZcj&wIDG5}$l=&%TMoMW;^H=t?pq!HMT$n~cih$X7fIc^R3n>pokQue45oM&k zVx-Xk0S&mnLyVk~!0bsI)u$xvVPL$@)2Aft2TlD`5{^NQp>m^? z>7SDD1O;#h3QkF2SnWVbj1oZYK*1r&`y!&fQxdjA$TNw}YKxC13|fXg!RPf1`g`lloi@J~q~;GdE}{`OBvAenzk0s;S&1Oomk z2?W#*l*Hj!aY9{l670-)Vv1zi-+@9*Zj{DI(>F-b0>Kj#a-*jKof~DxlxFKTl_806 zZj|RHV`fwVG2BB+MNsI3+>C+<}5q5?EQyDGB>9d^hV)I>K%tH+mo#%qa;p zTsx;E9DN`>!xirNqQj-Q7i|G1nSH&-e-c!uBy98^!?J=tCE+HIZ9|`uaI?1nR0$`! z^#F+3;QmF#yoP)FBiu?);Z537HJF@EcY#cw03)Ye>!Md=Bt91z_JrkaDj} z)=nMw^GTm`hmrK9{YknAcaWx;;7e{tM0DyGkiO$CBIzAMngQ7$eGSps+uVsHofs(a zxqBf=%aNwjxkQm}rqr+8r6g?yO6%%+Pm*+!==vdb?febyUgs8IB2F@&Y;lj9*gHKL zD3kKI`J{7$D03CroaDOzvh%!`NcwxAbP6530ofouRZ=*XS?v5T2=Y1)0ZpXyFLB3V ztS>Sr9X$u6Mc09}8%~YL!Rm7HLyV~MXi=xQD`IeH1Od0WoayzJ;}4?6!x+;?fJAXC zW2&W?lf{n{=qo^8abJ@4^Jw&<;#EjGyT3=X78n15F*O2|6kkMOfJZBKD4s#GS`l4Z z+>_Gk#Ap@8w~=h1n4)9xX;idcGTTWVz_7d2r%ET8%fcVz4M*l;%v5qL5yQPc2xDh4 z?&)E;Nu6?%y_wz^Z=ys_!@UF6%$-Gsp!9A)QuCbT1x$02$Vtv8+jQ?lVLO#ju4K}Sz3n366C)yp)})#S zTaWroCV4P(d$^D$H<4|Hh$xx{aaGyJdpycO9qMqR$IbuxP>0nXjiL{AIMt&8^q~%G zyrlq=#otlbS>8GTdBx34*1By|n+~~u&Cl{0b7LOhz_B0TQt+;K&Rq4d|7Odl;km6Po)A3!1 z&<8>6fC_F+8i~dt3ov<52SJQJl42tF;mv8+*%0hv=>gLsTyE>^9H=3Sl((_y_QNE+ zJ7fLB1bQwb$HqsA#7}YE?Q?A;*D2uYb{{p`$RfCw;J@K|-5aaH@>m<0Z4Wr;xe8Wv z*E5B?_R>p7t>w8!uk}pfAASn!#YO(kq_CbT^a9xZ0q}-To(PUmIEyJJ*VmEb!f>vC>vLU5u7jzBr&G_pSypEy~Lqc0&x@w72l!cy9J)@>2zNk3CbGSbQ<$1fIn0|U7w-W69VZ}NJ*bS z>F>AU$0}B^q!c=KBfA%Sn?H@gU42W`aHv|CDcz0Iu?%=V7iQ!bjPNH#SiIr)Cf1(| z=`^!A9JoH86k^<8ro~ zxDjnWn?bd1b1H-C97~a<)@=lzW2a8qx_X;eNg+i4Tc&jKx~CT38KsG4XIRb@MEV&;vYC{){N zt3i?2|8pRU)*?$z@jDT2r!D-DoG!~Saa1vqC@MhEDYCZHCXOLjj(icBICUIo@~{x= zBu*o_lgI6}iPOj99(78xql}kbwTU&A2o}_n^ztbP#$_*ZX2Yoni`to^e6=%26RRwI z2|{9Fy%#xi%tBytWG`~&lGhNFnc~ z7kzq0_6d|5{}dW@OU}3rVX;=S#kW>+Cb7y|zeh-{)zyiRB{}PSU~*1F&JxLaA0nKK zvp16J?2TNUy^*xf-bn8AEGQx$$G~_v7ZIiO)d3`t&(LotS59EzzY1d}lV?whLd#Pa zK8MxQ$yYBjug$DrI;BFEzx8k0B9Jkb5-bkO?4gpTN znr*N?r#8FqBC<$k8%1iiQOemy>Ry+uc1w zZ$HyYQt!CKV67sVZ4{~5Mk!|-scmjYM3k%9hDiO~T|`ouZ4{~5Mk!|-sju9LBvrEw zA$7egNh-6ABAIOz$!w!Y%{EFo+epQ|rDRjH4Pi@pPm)b$8%1iiQOemyD$m?%9>LWlR&Dln(T8cTDew;vG0rJwEZKV3i@g_xS&Nfp0J({&R z&Dln(Mu3tuXB(*j9j`H6KI=qF*D}36Z zN|$Dkbe@owa-xx1sFLGEBemFjKtw!hM6kK2Rv{s26-X1)8m>EaiaGDv~0gYZor54J6nQ%Z6k^}b7PUwK}0EYAOvZA=xGF${**p?#{ombZcaph|dGM*{_F?TyK zMF$>C(w7&(i4`4zSg&X>$RkD90~0M84ou7`C0qU$_f9aB4gy2|n{GUddF89wWCd=j z4$-wcomN0V{@X4Kp==Arg;n|a-us|Q*TP@pL?xk0^U#s}LII*_9#oQFl zf!VO%EQrc0`Umh{(Su-)7QFyf6Gc}+6SwFw$VTd9%Wv@h0}-89Afn36pWyLBjP%vi zWRfSnr1;MK$=Y4gcjoUYfG55)e~Q-~!j$jKpDKXzo%z!&-vqD-nHQU-trq*ha*5l$d*!LTn*o zE?G974_m|{_j8ry0@%R4Q6U}xqT8pix7!kDn|1fd!OZho%)5YK_3SQ(qO`>6F}urw zC@So9YoM5-IIFsQD!F8#rYO$7PyKyuNu2l|vgxlw{49o#BU5RdXIu8fB)d!wPK5hm z{rsL-HZSIO7qOW4~-Labx-G3k89szF+kpq4S=w(2)BS3b1Ps}eT zQyc=n0`Wj>LBkgK7N9N$3ZSP(&B-k3*1>S_%6=un z{snT;TNav1M8qsCXY>{^B_d`u;GthivB%hnc^CX*sBDHR6Z5()L&dmhF|IqO`Y=}c za$(&JR#h|=QZyd`9=4_nkkFyJC-by>jJ3AkJuv#QFzIPf^DYp$qhh;ZZr%TM;6@>` zhR6XI0-6h`_I!|u8Cwy!3Kq@-u{Qd3KpCSirx}JXMw#9YEUGBhTw;?b_$1(tf~fw> z5jY0{XE+PJ(*gSLTlR_Z%nT{?s}VcGL`cEkO&xXvsp!xT0T%qlfeyO^WpqHvg1T92 zReK}?!gc}zo51#hV)IrY12~`J7f#*Tn)Y2Cb2Mt#%fQ_UYEJZ!(a5s3F37R#wGRJM z;yi*FE&#BiA-(#v#wnO`X^D|LAVia3=PxVAmgusD&>oR)>)Jw7F}6h6KL3JTs?vKQ z%7)eRUQ`4r`9DS3X5ALmtX_<=)ixq___;9V8VCfpWDofv-TU zl*6_tPul3e8MxJm^#iJHZU$Kc>%qUHUyzJ#^AeJ=eQu;QX`?rTY!1mjjy6GiDXs?) zTSKH2)t>>?J^?bZ`HKj!s78VqhF}|g9Vk;&QeA3SYwB9+%BVVO^S929bG%~1o?>m% z-FF~{XKz55YO-Hw9;aaqtM^0Ex1j4YpinLLA+fA#u@6N#&{r+?VL4RR8Ioq>sTZb3 zl;IBAvGuEBQ!w?y{t5D=T5P?DD7eqG*xf};4PaGpgQei60ahMy4=K3SfK{U%B1PxU zu6}kA5}F{#R^3SI!KX#vpd>sX1_ymJoKxP zt)S@q0AN|Del0Q%2Hg{|svK`b*s6~rEFS&M2;24LfK_GsdxTzK6Jh!5_HB_<0Y3=1 zb|R9e&Fc?Bz!WeYU$36*I4+EQgJy9)V7K+f4o1HVMZbavjr@y6{v^Q4%UmM*7%y|F zXfq$N!`XRf?S~!q6nIsn3=+jb9D_)45a%P{)RN?{P^zvI0_^p62O&yX%Agx?9FR;7 zaJ8d>dxs2@5%>^+#VRtg>>D7Pf&2!@;|+2xig_WB8C8yRp+Rl~@*p4!fZSk^s8zLx z0V&mTB?2_jpw$R;1X=x=2vCUBKvW)Q^dlVfeCx6NzStWtSUg(pk+iX#in#{4>@DAO zeCz!(1A`O5s-zsT78LAjEbTKH8k&t3==M3jKbJ;%l)`*2LIx?pWwx0~#ZVy?35r$&GEJQUR zYQRDSW*{*BFa(gufMf7H5D4iW&V)paAsx48dbauT_ftw54tcaC3lrSZjfrG?1UPoPm+uK=nyWT?1(L z1IPsaHj&dyTZ|-!EMAMZ{pP! z_}n2T(KA7KJ_sjk=4Hd2y0yUl3b>_)c^i0eppR($Ch8%Xk<;4SLCA(udlv#?qX!V6 zjq097U;||Q#>k*Ed_yDeGDx(N+V?bz)9V9P!B@P8pd-p0HT_G_sUhks(gr?4i7FrU znnxd1_%O(N^v|(kg5RRDg}I7=V2Qm|Bqa=4%EGF9WRV^ac@QT+8(y9o;2} zt>()I_Xe4K-v(I5gx4bhNJeMw-BXUr#)-f`5IMp`NZ<1vFtwXON_*7Zg8;jn>%oAs z;Xvb2pp0u=32|zmL+p|+5dM4bO$z5grz4aXKUT|Jhz{?AY&Ys~i#Gzghz{csJHkYW z4*LL8`w2)z2M?n?>QD^^twW9;S+cquO&w}41@*10FcdULQOZbWWQ86qE(h6!X1ehY z-8HDT@4E=Lva3?v$cHYqJPx-Wa`ex~?h?S&^EtfyM8bbVoGQLgWuiI%_kg8~`OKx| zk0H#Z1vlz#0PkADw}@X7_$$B@H|^`<1RWfE)Da1-qwqY5?E7L@bV`WaQ3+hi>xB6J z?*P~JQBe222cdfqn@1bxc!Lq!?{VOqx~C}+JsSU+o%T?Jx?>P#_l|)f;+ILc+gx;% zlc-$jRLJcpr+1a>lwe3V@eq(SKvtv^6h4!^@e$s3z@w3Lwdi=Hz>5IaovG8?(r$XA zc;E>~>2+6ujw5{@@CUtuk$(NgKqEB6QO_YuGOiz1h0ql0Aj7r`rTQMjG)vI!a@aB$ zk<8Z$J#0ZblWGvhVTFuKq{yA&rQKkCl(C0Qxc_mNf~|i&aOXf+|6T}Ojes-!BN*@+ zL-wtEDaiU|Bewr{h`603V)q9?a#tlJb@6VeB-;IPiDj8>MeG*FR(j7;0L#o7o`e~a z$Y(VGcdA#2YSxdYkz0Qrg7yj|j4&hv>Vb*>0e);00+XlWhHO(bi?#>2>Gd#6YSC70 z5R_%rx*dq&NT5Z<(4u>O3miW{VZB(6dy@UY1nPjn#z!S^#O88#OD{7xL)I8yVR2%mldG>y^QgmP5w2?}!p8!_$Az%vw=CZWxyBk{ zSJW)U^&opar|JNtYa6XZogWRp*Mf>1hD!>Ci88+qN2sgtvLx=&RR%zgJqnb1IW zX3tEn_HIR!j3dTvWnb3+GoaR?#AbO|2z8rgJg}WALLxE_!jB0XM!K9OJi70-&6nr8aJpLaN?V0a~ZxG(Cv~)F?joNx+1p$_aJl_ z6L<`Pvk@5o0s`Iz3#9jG09#EZEc`hUfqCq0J^wTP9W!$gwFJa99}k^tO9{0ow?$C*zu z6L9L5fF#ljqXp!OIX@mlxhsI<3}t2nIe7yB7DG^NI2`U@1k~XaQHj6}3{)fVM+D}Q z`aMu5K)n~~qC)g9LzH|9CGZglSWGhE!+5C~#Pc5Y)OVg4&(AksOJ<+s&Np9lX5_l_ z&G)3)cewM;K-K1z*EDY+=R&wL-=AkbK23Z$|M%HAn+R93%ANoISalvzPH|+u`CJsc z|L2)6PBX5WXFe#+Ja=AR9Aa@LHq84I^1&;4)BG1J)iFicbG`X*kHP=*;L7>bo6n<| zc;(J_=bH~kvtM@Sna@u%zMN-1Kh3ygp84i9bL~9y&1vSz^DCeyuVl76uO&G1GjC61n^)!^=0~9eubkPD`Oo9YD`!z;{*#c! zD_P{ue*(GUl`MDXEy0sl;>&rBNP}12dGnf3Rd}JCG9nP@JUo%F2l;Q|$>?EfJLD5= z^7x(FiaM_TTD{%Pk9x-=c1(6c+4_ew$x%uX^?j?}O&R50#K_kDAyn^0)c@Y?x!$GV zjm^X@dK&sOC(alDrC#;F5YAwS=k;aK$vC?K;eN=4{%X|g&u}7xdkVZ7hLaiGQ{W9? zI4^^H3cOl|i=0HX8qer_WYDYo2Ej!1Qrt6X6n8n3U5k~&@p!teOJRyE=}VV?2t?nf z0CLlZyPPui1eh(|+fmHTApn!yV&|?TcqYKqdWiZM`AKa-;9CZ^>VT6u9U8d%F+u(? zheU#Z^%LBW3I5toaKC>6d=j8a@BpUp4}dx4lyV@YxGgAo9Ph_wIH+>(HwbwxG^8~zYrz$f4Jb{ROJt5nFBQ-M+ zDLa27&BrkKVH5NmC@kt^fSBx-jWz!rv2u1iyp z2wWzum*FyBv7>floh(2Qdq-hkbRUe39TNo}AId;X?9^t2lXHnajpR;}+hk*>&p>FO9W#P zjI=5X_`jZRwL&Z-;)wY`^m_?>F;ot)@IOA?8mb(N%mGEA{25;D*&^dX>@6tbUl+Jd zV;7l`${&$lvG|JSn?SV%HM?XAVsC-K4hs>u4}sFf2t0wng`h6uUr$iDQ+gQCe**dj zgQiwa=`xLe$e^h`zV^}5oT3#Ap~T>~(L5F)P5k#BWE9GZ_8u=ockhDvN~IxGDf$dl z+74Q(RQeSHuOm>#3&Vs9=3{dg1pgB-PaE^KE5l@OOc@tv-vmn;7iU3Q3erzNw!n~5 zHIfc+N-K5T@g|PBK^zBW>1wS!(_8_q%A59u<^$h=Y~&Jopmr7VB4*%vA{w2JrXk0l z?_?TsJlE}LI{f%m9ZfGE+tAT;)$uPonyxy2Nk`Mo#;$ShK>|_dKJMYX%X5*@G;bG`kTwfHim?!+(0-HQ*yJsSTN zToHB~R}r=NBt?7O8>FflgLz?mGP|w#vtyxkde zza&}wF=R6m?}BjDNlYVZsf(p0>ifFOW*ASx0w>0=LCIvrH{+fiKNXmw_<6V&$7kVQ z5?_FOhxkFbmpX}2l=2VvS76S(iw0) z5YJ!lYasQ<2ePWm{z6uJsKk!ydO|e~|vruxD4?9=~_;in>8kYz|#j z-!mDET#POuejb7us847%DCMa0hd`;m=qsqyL%LK`8^X$Y9XWPsSGfp3)AB~nX1w*8 zmNyD>ja~B8R5?;q4eAKL&WdzKWpmWW+nRVgACJpR z7wcvE)btn0M#h6RcBC;N2oPZnIKoWNs0KR`Lq(L8u z-`$sXzmn!8&ZPv5G|cRRVoyS{Sz^Tyk)Tdtp;QAL8d>=MYUHW&LVOPaS3ojobM!WB-Om00aYBq0#=`4hN|94 z{*qMZS1YQnPNma~aXwC4p5{04_m`{Iw1nl4-w`)3AHg|lQM)xoKCJ^|FU*e|`$)BD zAB>uT$rueyrHw^L9!iYW#-gK66ihp71bPZ&Mni04G1bOCM{=>U5nzFqUHS!_joM&E*=>l;wIaRoyfA4K#%xFNIaBDCMzN9R6=fq61+jedfX#_ zJsR|*t3eQp*5aPU$VdieT=B8QMg|;(;CO!f7>ja}BLeXzN{fjc40jrzD5SrKapRMj zc4Qv0Q~%1~4(J=7ey#|(*a*0Z0_1iVXcD|ZJ|B_un1dM)2>qjmekpco5|r%wYDE_%gcdmOU?Dik_sDcq7pN3X?nnH}K~z0iLHyC95l$xi zF?OzOJxR0b zp9oha_ovL0K0&xT*}(AXEM%u9+05|C%#3g-Jo$aCjNfh4;k+MUaAG&!Gmj)Rcz z9+2nGV;El<63=)0{2+2T8TOtDIjJo47G7P1M3J1WY{QEX)T{3Af+BY|i5HQeVhg|_ z6eQpffY{qh_-sb=SB=YUt%w>viI@Yz{E5i4doJlPK*+mhGM>`IkgHX=P9oP=Q%uCc z;3{~9T${*s2Ek7V-o#wA5?sr)H#7G401K~$y8Kna!MHa&IXReJxv$JY-$jq(wqAz> zib!-IPzXEj-<{M6&?Hjo-Uir=|B4qP%aMU@B=0bys$xjFkVe_glsh~R z@F9X95bO=GhzXqyhCHV6Rna{FuLLMVp|3^F>i{-%L+rOs$*EMczo06grUU z8^hGaEv4SxFR=}TT-~sEp25=XhYE$N!*p6N1zXv*3QH3Whbrk_G|>Q;sx<<3%D0lB z!6gBIgK@d76QEkzXp*X!{Xklg$xMwAR=2657uqTQdzO5$Bbnd&}{RF{e0Ml(E zaJLaR$>1gum%f*{Jq33%RT@kU_7b?2@Mae3Jb`};xFdE$&KKwrKu-DdRAZ6L{)WFK zF1K|x6@HwIi-gp90fJVdExBh1TnN}H=i3JNV#xtn2MR0yOe*~pNiUU{p&;$F9y3$- zGJ(^7pnhv5ycfluOZakuj|berR5KJ1HZQq8jOK}tAzY{YG77&_7=Y5lj+dj#G@cr=r`SK!A1JNfr82ftv8k43P7r_#9_!Kia%BkpSEF#zSlG3pl7 z3;u4|gnDB2su8E=(9dO~rx(Le5~4iAkM+KhqcTn`(e(DG+3t(Z}S@d}S@@1$8$>?f_eMKPcpF zAR3>6qm;biZX|1;JrKA(@)w`rb|FX|ibW20GQ-tqka;b@p`5OVkxjLzJ-4WQEM8gmZ+o8oA3}FRJrZ3SEpFtS@L=~Ri@b4>N zBS16|tQV@z)+5m2ntC8FI_(TIV@aI}4c&D#=o%nzpj@0zP$cRM zYxW!O7ssl`y8s2o-#<2^cBsbtL$k^$AhlbpH%hlQCJ=rr)@H=3rjnz;ucwkT5R5H^ z8ZN$7jq>>?*Ui{M6aLfvGa?gL5cyBqEORP@|B_$_2H$7U$@mk)-??#QGjX+qPXapY zRR%qmG+A#^V8kWf$==L}?(WmD&|Toct|{D;50Iq0kRJkzrljZUDX=>;Cl3~S0%W(9}1hO$mZl-5Bc6fsPk+AQ{mC!LvIJ}dXN?nS@V{ju{R0_d-q z&xgP@kzDKC;=coS_bMP*_-};&LHaKd$bAtvRHm0fT!}z#SEjyEQtykn-1i9IC~$+& zb{Is=l2hP~)`G!pEtPy8Nvq5UMcIeU_ELg;X+1c>8gk(bzlI!mf~q0sLl^$G-n)_D~8^^^y?II$0)hSx*NFY+)D@sTJ7AgFi7O3b&gns*YyPGT9$ z=Mhgb#C6!X3PXaF~%3{}0Dn!N;jQoqHeEfI-+Z5$UpHd+*lB9f3 zQ`VF6Yel)-r&NfH`>EQ0Br@YG5`L?>#v^xb--zgZqtB%f87-vjFOiC?M#A{Ed=(<5 zDlRTks+=lBMwB9_Ysy;*EKro30w_v_$k?4?7HZ1%%uI>WzatuRhE%9hrDtXe)8R-H zdXZ`hJgVXl*8wvs72o@0OG7=1nK&F3E4ht&A5CyIz*HBq9CH%M8d7Ren_jR5MeWR}4r7YU_``4FVV7tu0z31##pz**29Ln(^tK)96fJpvy< zSPXZsz|R1t*LE6k755I(NC}tXa$DCy2_@t|5)-47C}HXGM{#Z| z-=^i~Az#&uEZjhg_f}=)(|qpBsg{^=AXS;^EAWBBdOBIB`m9AFz83w5QenEp9PP6< z3VemI{&N*rm-wvv3+w%0Es~a}Vs0XT9BZMP>$tU5# z2;f)vXPUEIIRe0{iuFL7EIy32qoc%}K;ja*HvXz{VS_DbI-Ca7S;>852)P`ozMQa9sv;{MaZZY8zVG}v@ANs zKos^p{yh?w zKeY;otA$KefhRy#^s8xtWn!^cajTffwlY=>z*>Q0E5xCV6<<;clH#{WF<#&)ghgF7 zu=xeyn&S|!1~x|$?n-!)(4P;uBfAIwM&NR}oadp@;@B_(@}jL@;(pRLa=F^jh)3&?h!T{72*gsFd+)fWSYrqjPi5cQXf{j1F>3 zB-V2Zw2gU@talg~<3>It%TtpDprM`EEsUv%MzXti0Pl<>mhuJz@3!*&T(U0&xid)l z8`vvF_B>L+8tz=_^LhY;(J;eyGB=+DyL}XiT@6u@gWO0g0`_Rajby(KE!~4a<}4s> z>xU4Y`xKFfQ1~4Xo_h+xLkYeFFo)^$$425FlQT|(Xia$2>VuN>33*om%b$QJy#U($ zTL5C_kwYu-Cvr~CnWp7P<2>CdFwsenxUGd(!-8H1FXbTzW}DkIDCYHni3+BGX5Coi zxEfO2*0(^Fe3CX_M~38U#$qxN>r8O?NsMKth6BvKl}5gr;5>k-#}JqZadT+TYf_g1 zoC0tO!3{ZFaJmAZWciM~zX03>Q1W=+?~q{8+d$z3EBW3-3{cq1ox|t*hVZqVB7l{L z=`S5Vbh39)rEfv1%VJ>!dS0}eNGf(16f2g7hBZmRCjl-Y^(F>>^F8HQr8;^|1gbh5%SK}_>H>`jpG$sA{;5OIe~ z@nQ-aEL!EfPT{25L*OoiMe88~4M1;bzRE-0_OfZABr&H|Bs!D7!Kc72X%y}4{edJ*LXuA-u2 zmY^($0qM5>1NZpef>egfIF-OS0xOY|jEe}4CwM8rg9uI_cpvkbfcc!yab@xrf%B7B zT3LINY)CGQ5R2se!F95kPS#Rlhjtfimccr1zS}*gFgub{o-?yUzMIzphUw;HXO931 zGE1-`J|uf+_M}4CQsXf_iw*SgBg=-BAs10Mk~1PZ8-yfxL5>fGBRSlDnUN->J>=TP^cTyoUk=ezW zRM?-n27%U+M#$E7j)?_2Sd#Fk$;Mj9b=Z=*#%6hfj~NT+2Rwr@HY-pTF6@D{;d6W$ zF=|w-X^}D&!M_lRUK;FB?Di~Es+Y!uy{r)Wu*B1hqJ(l?7r>(GLPfn$c5GWmI&}!u zgU&lwnMzY-x=0{}F;^hOLz#6Q=uD6bMxYxDP>d6!l720~7aD%;K#Y&4vOQ1-SfQaT zYe&yOcY;*_St>fVS5S9)hiYFRUw(Fw@};VtR_hc{nJKcbl>vbLbP77QKg6Qe4Uo!F zb0%uIS9-x{=^uGPd13~k@7%9V`VigQYkk)$T0?H;Wjt2AJPfw*g#1%)TnGk&FnyJ zMoZ$b!kD&AbZiKLy8V;dtg4r>z>WRHHme$Xwr(OQLbjNs-E>oS)6EH*Aw~{9Vcrx=cknXuWjPEe)D(nQFRe({#&C)2+}&LecFoSYz76fSr@ljlWh`ckMvxY}sh3N|tVq^|q8Y?QwVLXgMNj zo@_Q~o}%O6Yn2p|xuWv90LWo^(F@ZaY+M}hIJsyZ#?HOrgnDIcuj0ZB6Z~2+S0^?h9m2XkQ z0e`@yT#Y|ED6n)v_6n76`9Cl$2ntP&6FP>+1D)FXkIrT^P#JKtqIU5M-1i>41yvk_ z1Uuf;9Nj>>1%zz;-F2PR?bY%-jI~Aw@I2wR+{-wF-gauL`mrtcK|-dL(aY>irN^~> zEsc=5em3ExLe(((TWW%)#-~9W4AuAnT9|HQwVF?Zb(S5W(?B~%)VaPRTmj|L&EOw5 z2RSW91E$B{_q2H^N0dDG`i2-3tf-i~imYeFu@#Od;zY$rnt>}h=S z6lE2vHZ?3<<$qd`DaV z2WomGgv#^(zsXflY1;RqR^DOu&eFjkVEIsZ&_D=V7Y1sG~v9yWouWaF%by1~jqov%FOg2|QN*VJpT0Zri}Ewz#JL3SG%Yyb??{G3~(Chb6m z1YU^7!_><6d;o{pnW3SEn~rCM5>K2Sy1{MQ>4bU)jN8=M%=8%K8?Ck1{ll1@xwWqt zYsV<>H7-z_&ec>J$sb+Qgtop64z|tQZ<6smY2DQ4% zavfZX@fS+C7$X3NS#6s~wIvQsyl+qoSts?I<0sbGWh(X;85B`I^E4!lu zv)4e|t`C|4e5P8W$g+*v#!+Sm?T+rkS}rv$+boz`gecn_fR_Dp!^L4Qld8hiqqYKN zYYi1zMN$;xk#(ook`J&XWJ#F5LkRIBro|F-M42LNR&8#qO#j3YfpQH0moMFfmuG^- z)^I`Y#)4{h01%p3h1`QZtwQ0q9S`Wbru+7ux~Aw!7Z+WvCE4#^bhV_Q;#V6dKqu1I zs+avjHMYOsl+b~RhiM~e!th#bTVFZS%v59%7PBm4Qj84j6wEYqOyE&4 z+X_;`Tq}s7FTh+&xqdZ|VYWHf((Xs*T5X2{X1cM{P+-rW;x~Tim6h@*akWH}5ng*p z1ZyIANn=)Lvdrp?yqtos4N5_I^_213Ic7x_Z=X0UY`X#zi06caD=^v?1Pgb55mIE9 zK8n@qOi8eq+reH}Dzz7%%k0JHba+9z+|mHPx5Dp^WW?N2$D&12p-x&q4R$u`#%2xy zyvlzUC1#E5uQlyvV?=h>Am!}rRCY3(DRc`G43OP*&V;RpwHhRdo)+6IuO0&H_S4F@KP{&buRS%IymB6-4whEhP7F<}*XEdLc_5f?lJP&2 zrS&7BJwv{GitmK{$=B4tN?585^x>+|bd@VTRB5!CjR$KA@`b;;3yg`C6ytzeY#o`q znPEX8&p#_X+O(HckiR)rZYT+BD!x@w#Cw@;W~Yv6o*kp6Tl3B03>I6sRJ2b(q6mHw z9_cQ~cA4b90a-}#g-W%HMwgOmKLs(kzaQZ^2QYW0?{b_2&2(*%dR6B*i`z=qL(gBf z#Z&S@v@px*V3h>^#>wP~(T4{5tF^Dgv=CY9BE{jl?9sP5&XVv*{)m9sl=YE2%{P}S zy(w#%(m|FemNQ>eY(>DKd-kK+c0MaZ2=E*oMjVD7=;zKERL>MwL)8pjw~<-pYky=H zh3Sd1?d~CIda{)1$@osv>Uwemr;1L??mw(O1n98Boyq^$+eyDAqE3W{J)MH8L4Va* zH#9v8(vw%ZFgSV@8p%sfZC0H4*6kRM31=^NK4% zzK&I|RDW)j2oFxJO7TOl4*emWY$#|u)zt$av_WO508v%2a0id!D2|;AwOq8{@iJxYCn1- zn%d^37C>O#L9|c>EP+?bW?sQz*njb|L<`dWK2|^2h)4Jt23}=%WI!k{O_cjFO>>ks z2FQb{kN|i?Vn{>dkFgm%mN0*Tsb|`tq8yN2pEP$Z@VY&Q>XRw_}c*(>b z<(7p9wrQ)Egz>m&qN_4htT5{!9gW-R6jWU0=Q!}>3>lSWWEnk3W#INrnVNA3T9S-H z!j-@bJ0%t_!YCk{S`BHN&aCaG*6^gXo%L0Cpf(;OP%~7oxtUd4fVtsb6$7GT+b>$h zTlF`-t;YB^?qk(GHea(MVLj#4uUVB#;Kn%pLPyq1se|5w;xqX#S6T4~`%Sv7`)RvE zqSDuGFIYF-*`IT>3Uttv!`ZUhF*m)572_KV?_h(vKquA^o;#1S{Wx=g6&BS!m_=3X zSc5mMmWp~d8rm|~rVfk`Y932!LIBd!7?u5b6SvJ-NJ|+00xocWbYFW~AS7ewoT=i> zXZt%_0v0UGgcIUxIP7!L*7X&V5p+{9sb_1!5>0?0I3rjiAlMRsiX2NdO1EI$+1mG_ z7bj-hs}6Id4}z?@{ZJlOaqdMG?LpYQ5aPdZtv_vWA6Q#?n5?iD}q390;er*C-5}f$A-bba9GLD%KhaP+~}pb2B4*i7hp;J1ua@ z5Z|mUu{i`oe0#LS7!LHsHxTG(jdD8qu7NR~eMp>c(0ElAf<1$Njnj>aTL-Pq+W231 za8~|q#-m}UplYw&+@d{NPpeVOz_LmWcd(a*;|~4J034ovPi-=cAwH`e-%gtyHAv2{ ze9R7ZADeQ;cx>ltjlIZ0JlqHb13N>gWas0lUO^j)Ig!_ zX8E9Iv{~vhuUd5l?XK!Qx-Cpct=7@g7SN`0nGt~&!L3(T3((b;^|Ox>&Kkwnt*G|8 zdo%+9Edkpq!p<_hvErvXOI640?=2~n zTls=MV0hb}ZiMM;@Rd~1f0?$cyQ>D(b6`U>x+7>KTcN40`EqNFDgx%6vr=@Ocvsh+ zKwY5Y?H8XDbR&}Pdty*TOlgvm1`j~llYNLL-_yXsg4#Pl|n)I_XL!JnZXI2RDBOM>N4}9N_F5A~wE3#~U|95`Q zu?roac*CIM+u4ty8w{LIXhlBM0Etz zP?7E0hq^l#ZdcZjZtQ#bnT_t7=}F9IHj)An!C+Hu>zY`Utn(6|P;Vc<=$n5$h!jdbm2P9~l^)+lN;-l`~@6dNa5TnFtTIdPM!* zo*qsO*|~qjP7af8^c+Dhv8Tg!=AmX{KB&>g(7QZz8nVZW#>R)X`ZL=g)sUDm;q@b| zNT|YVGZ3}+e8Hgh0tCSD0)*8)h)`@X+N4#~Sn_=tC^65H&5(N_8pI z?JlK}TO_R21X)V}ff?q)4ES_L8QAnmEj#ruGo>d7?JTq5VRqZzWKIZy{s!v^Y&GUz z1%7Nl!2eFQe!~9>>_U$t?KkLg=zRWns>7jeaaGzk!?eRw*X3DhF%-&4Ql4c^3 zQj7F$|FA+&Tj2OPZpsT!+45EYQxJ3(s{i@H{gGydRidVZ_C(8`VX1|Fe}-ii`r#?5 zNcqm47Y|Z&IIW4b$IFNe`)dKE0xEb(ensh)s_E#K3fr!F(*Vrf=+l$yAVQbdy0Q&AdoYWBA#W z$p}n4%ye=;Fw0W9*dI;F=!2S#vbySEE3`E@(X%lw-dl6QvG!bQTu>3DcU1GW;Inpr z2CHRFRHF_iA567qSlJ!v?~PjTvx6v|XYP0AYT}7BEiuAB}dwIPER+^531peSkIFZFjC4a-K4p%Q6dK*o|m^_QYKy zx}wqTnwJ!&_uw~4I$9M9I|w~wBYk@v1T9t=@DVKfUIX&og&6{(3`$h(V;OW%K|NM3 zRqaSMqB6^srA-9-jG*d=3aLW71Qt7#>DacAI)xDbMIqt%Sby7n+;oE(8Y?|h!tMbx z+rBKzq9V%P!TT9hTibfZ$uUOQG$(Hz2{>06+ySN%VWdtuj~0t>!Ml7Hr5Y2u??Rb9=3f%PRWykppgDL=z)%88%hT4OD% z%VSH*vlmKGsAl9;04}TJlHz35=c0eR9UcqJys1Z(;4ZroRsZEXT$2&g&M^u1wSpRD z;Rc;@~t_b4|)fE+4Jr&vjK7m$){1UT(*ul1(Z|oowY@4>RVf&x! zpMw0GJ~kfY9u-|DD#i-jy0}_pXlsDLatVEd9=KVn(o=ccr2{k;)?O&buFkBI@Maus z*p%>BzTMjN1=dy+CU2^^E;)EEGxrdWCFKD!Y%piC_O27;Fs({6|2RSmWL3br7 z%Yj2^j+HflrcG$#kYl241J@L6oMO58Ib&Afnpgy!$+ayhQv-q)5^A}|A?c=CW*3I( zKmMDx(sl&NESdJAE3auW+5+t?ep&4p4L4hlFQAtE)cL|X*rJj6TjG!1#&rfdCE+?} z;Q}om8ztDn#}-^++BLxJD(%IfU55*D`M6zzGx@kvVei7@QHAB>afLN%ZOL$*zvBWs zAJo!y{46l`4T){y;~fb$^U*AXv-ntyi~2XMV`!O*;Df?cgh}mnaDIPkEug0eSN^|R zc)kKdTu_aC*f}qM3{wY5Evx+Tje?w*wxQ@^MeY8yh z8;-V7zi{>q)^+waLGx@EzCvRGHVdkek7Fd*!pHFn%g0)U<%7vtg%Pkf1?;l}_NIV+wqXyK zL?EG=5)KmiGY`W<=`u4A)*J})%VQb{{|o&W21#CspvtH(Jcykg#C}gc0@{{f7DFf*-RXWM*X*wBS^@)c<});DO_iXjO;jggRcmN}nSf8IUW zFgn-yynCm}j!LI8PE5JqtPHIssU4K%%zuo~x8nSy>+FLI416rW6;}R72_}MNnv%dr zqc4G>*(!n$3JQz<`JDUXMeyOckQ^Va5}e7$Rk&0t3~f^p##Z<;{pYZ)0NV*7sgVzr z+AKcSDJ+w^P6hc;sq$O~`K<=(OclEkj~7+Y#BKt3JFYm+k~-3F_$6RB z$uReq;_{rDbNx{^TEk;izxFF-n~DH2{HIK?@v)BtXY#QSSD1DRFuO|I z4B8f4kjsaX+rr1b3TyN=&+pUQ_kLkr0ydu@8GI-mW|BuK>wDbAS#UzQkU>6Zn{Yt|1Wh(UP$1WU?RJsS z!pGebY~ABKN}i=zU~Yz+`deWg$@0e!_fhOZKMg}}^{Qfd~tJzVsNBn{H`i;MYu z0T-G#ABu5~DT)(-qI~4pB*XTl#afm)4MZvn%J(vSCN8E-56UnlWC1oV(@4y6R`@t0 z+NLwgya9ftUyEgJ+mEjR#WA>`7#|Nwa1I}TR9HTgh`B}tGlBf5!kS|W3s@Sf02hLM zs4|;tE3;jM`oj?Fr%=BAzQ{xYsHFK=j4ND2Nsu7~O?>Px!8v>w+Mu$Mwg52^C-b{? z4D2P;v-u#k;EjF>AV@>)@u-ks3m?4|mX8Jr&g5gf1Y7uMlwcztEfSo`#{z{l@+owL zpoB-M;+ulP2ja?bmL=mWQT_ym2)RE}{X4Sr5iX>{2XlwCjr>;uz86Nl0C1~9@u7JA zihK`H_o-Mu9+hAVA5SQ(k-Qn;?Fz+*A`IFhP-m)GJ}#D^ud|V1DGK!s);z7)c2HKo z2A43bcQ6bIh^Wl`&f?<}T;W<4&^D3Q5Cm2031D|s*vp`O z16SMGK^qy*g2d{JkAwR@6BpFwqZLpXJua$BxlVsvki$o#1ZVPb z4X&`rYG8Jib`EIw!G$pc9}94yAD8ET2*;dcX=P@EDWSnY4Z#Hk_*f;u7Cuf^SVK4h zU;{2Y3wr^cFJyjB4az3lA0&sgVI{n>4el_Fvqn2xV6>0KmQ8%nX0%LD-d_Nl11v@` ze57$@ImbB--Hvq{x_4Pu0l1Tj=7aopw8`9dNFi(7nRiii{zXxS$%?^H6`$lYafXK} z7YI#_BtsgGhug+OGa~}Qonsq=Sl?$bE0k?97?f?;O;F)3Tqry~p2ZceH@i&G+xetB zwu3m%`6u8Hw@N=tbT2Oe<~#g|Eh*|-g@W%Y?Q;F(W$^@ zS4sM!i|sgHv~OA^2=7kGQ!HS#>sG zu+sN~L99Q}XPE^f=YYWHv8sWIwX1<0Hu08e=uUnom8p@BYs8)Tu0Duu3S#}iK@i)_ z*iS^vOg?%*Od%DId{XID;#t#As>nJ{G~1Le|K~tr86K>c=*j*swPV*qd#F_6oeE- z)VJ*4K7p-ub)M_g;{p>O!*GR}NKh*TO?()FzzrsWEfj)AK1y+gCG5Z%fnVc75_}|t zwuKL}ejja9Ks$@H*|=gT^v14H1`TVVN03Z&z&bO`ny^^|(|+<3G~8t?TP=rq3>0lg zg5^TO_6TUL7TJz}@EbJNxD1bZTJ^!I!dB4kIxJ1v<@f8JMc4xKtyBff$3_XZ@UdB8 z`FKQO`FK@fjeN5IKkU5?n3dIe@4aW9aU97=h!RQ&!ptxdqA)WcA(W0dB^*i#F?-MK z84#%=f}%kr!-#|+5<@Aq)KW_<$5_XDsE1MxrPNwtsfX86%VnwIO|7*#*4JZseLcow zIfNQ&t-k-?TKisW?P23b64T~tp6mMW|Gn<}UibQV*0Y|^{XEw>RRP-J#2$zczVDD8 zc7_7vBZPh+!mm1OCuG?=`;okF=pcNTINvVFm)4Er0U^u%`oew$pDRowm=REm})2Ow*t+T^W7d&!H|vBt^zF7LlH8Y<*W+Fu?d`i9meQ%S}QZ!Tnf$7yqs znsN1OIu5Je zuA+m6sr|6NPaw~5VJez0aprN(+zAmg%k@_E$EacDzo@GJZy{;+OG=(_sv<<=600>O zQN5QTy+cuc&qsp3<-{WNoKQZbcS`eKefP+Bub}EcK5jSkH(qP?H7=`nn1;(M5Pd`M zCkHsunv9>Y5|hq&*HfNwZV^L<8bwv5QnqR*_}hM;2yJm~4RwgtLbQg1x@hghI?Uzm zhGq!#L}x$JY;S<(1_P2WE!6ZO1=;260(on=!ZKJHd=Wk5%?n9i?o@_-0$l~~ck;x3 z_%SC>>W2?G`I3HEe~6I(<~ZK3D(t+n43~e`{Fo zw+6Y$WYv&_$X2I*_D0J}wp{{i0HzYk0Ffyj!}Ur}b>=)oq2=2R4pW>%VOhx`Ioh)9 zX~>PA(&a@#eF5zkd`P4}_Xgp*JtYj*4NRTAPHMg-*Hk<0!Z2L6 z$+k=QNYYp5&@Eo=Yg2?C7Cw~gqQB0`b;?eqo)XS2^vEJiTkPxR*1pE)^<>q7lrEFCH?R* zLH9|&+K=Gt&+3Z0xB0!3@+?{_V$d@c(|oJl8J)OtOWRyTE2me-RiO<`D>H7Tfq>RtOD zhj(1n$y`vrrW1n|oVF>w2%heEQyTi*X?A!Ai?&(GU-c^JE}=Y6bSR__am;N{ zmS6M{piQSmhz^C+Ax4<3ELZvn(Bjh~M2AA^P#&SjMd*YqLY&r!@SYsb(Z)J?#O&s_ zmVS#ghzYW!vu+!&ct7h3%tM4P@3!brNF8F8ahUERbV3#(R{1?UP~}O!$`;90xui?0 zj6G>#nfrhiK5$7@?!O8eOwbEX?1qjBzOhInT^qU~YFyq6`{eM5pdgSB(gXd2*Ak)D zMd*R*oS27v+#YDO*IGl2%eK#Oq?TyQ>yk_}F+$iI;2T#?bO;kW4sqo~hcLI{5T7$Q z2kmK1)Y(VeMW=dmNUENQW*wBf-#sd&^h(niS8z|7n^?=cWTkrlD}F^l+niX0e$#8A z?SjvS^nf#j-i{FpM8Jw~?8)fRnL5Otj1FC?L+nW$s1iK}Qww_1YLoWl9kOi})MCu{ zdeM3bE9y!;ndD5}->pl`cU_yNQ9%Vmi(J9s^ekEnSf3PV0sNfcdkpDV$pTMN3~xaq zVmf|e$W9AcmAfL1*x66S0~4v#70_Lie8A3rq=y6)egvXu zxI?2RM8SXpPe&ob-B#>N~x)Ly3P4M<#bG;x-pN50z><(^|4Zow`n7y}(-p z)jIZ7m>bM9%hfgXZp>03lM8t{WeN{FxIWxBI|aN6R&{il;mCp)jA+}c<1nD7S zIK8dVZF1i0^5r2PVm@@(Yawzam$S%2d5URa#$BktSP047?b4S^XAjaNuXpL>4~<)auFlZT9_YEr#{=H zxn58Wpohn}Ef;!J@Y@H{{msq*JtTMo(oSc{Lu}{eTNKf2T*v}6(uwmR3sUGuB4^Sa zWIN_6)d@AYZ1W+@)|q4rhiYW|u=DMLd|SGy{YF>GZs;z7N_O=lZ56WIEi3yGd>gyd zHg+ZDgfT;%d^w%5^5JBIYF^}Ok%xRO=2MG5^;+m&6{krP`Yk8sAzy*ep7l~uWj)+F zvmarTpbZS7@~+}GURHig=L3RPB(%+mVH&}@&Z!E}W+xUQ9O;jE*uP$yJA`xuqD!J< zPPX)Iqx2tkL1jaGoY)OLBKRSJ^td-bPX+_hbKU?Q4+d*lj9wu6%g%QmWWKTP(YG`D z_N2aX*K74tL###;pASWJTef8D+$rlHxC-PU8l{aKI_R|!Es_>G;%v9;lN{v(?Sl32F

qZIhn7i-d(OvZT&FyOAgNSN?zquMQD*wt@p;j6smqBz)B|;psijD-S5P1 z=n=1l{?3U7=(yL~v`z7)?BsdyOxAhP8jh4-zDTD+7rV6v-QmP;=uW|}K%`yHkcXZO z2Bg382I!SwKx!UO)Nbf}ddi92(0rY2c^~Wf*n0(fZ-byUYrQA& zPHDC{Z2_Xgq=kIH6(HZjBJ{hi0R^bV6Xe+CUCBLlve0447Mhc###!@2WVysy!)|P>EUeWe!w7{N z<;u-NeoW1yHZOQB^bbz#q<+5WdC){(&V12TUW6DCiXT^G7``i&{VPJX9$1HcS>aB2 zwKAUPGIv2k1$ow6*L5n#H9q%nm}nZ5v78X7MHaj@xmo5mCFeL*n4RgKkpg!G;U?Er zUC=l|PwcPnN1zM!n#V8ZYO@1cPqibXWPjAOQjV$0-}TiV4xbc~u0E(FE=j!}SMoWh z3iaC4qGKsxbnerWvRx{1TXjcs$JlIV5IJ0H~uha*B#IRd{W=;FuQ;rtmzwfxGIQ%Z5D0)d_s(&J=(@*ubP zjJio7IDXd%sy^hi+!|g!wohgIX&`?@;?qJ>-I)!Vx&^KLjz%412ogI*MK3N8E%c&w zz*hO+H3WtO6U`kbMYZo6hR*m zs&k(T?R`S&7X-BzdR_Rq-v7Wb%ck}VM=S&WT)FGZB9{8yCa)N3NwYz#2q059Ux3Z%jp+oSIk!A|& zM2J?G7a1cKh-eO{7ik-hdDZ5=oBdPu_^^?DyHuar+=Abz(OV^~WJ_E3y&}K!T#drT zt~aHsma1Mu==A4R%$kgYhn3+GLEQj7DwMbC_-I9Ja1KztQ0~z732jV*B0$H5$_{KE zcytSc^eU!F&A*;&s%sl*&6z1ZcDEUo{Hk-ShF7xp$i7}sp%024@nR)UBHr)JSKvwY zbcAsxPam@z+9>GCN>%?R2}E#-7$ckr?Un6e;p|-R@Y-|!bwodjM}=D5)F+L6P|!?c zLSSlUIkHTjkcPY=Lu=fT#e(h4yc)_(#OJ12Di{#Yjm`=Nl@dVxt~M~$C~#@^`PJm zhY*H1`;{X_7kP2Ah+K>wTa#paL(sj#U;MU|xHk)yPW^~VUihSwb--HkPwQ?~Nz2(S z{{t>hd`{!VQk-+$e%1b{9jbOnW?XdOYNaH{uvq`XS-T({xmRqS>HYj8CA&J#%o43- zhh@bhQ613S`e%Yv5L0dWSUxPxlimS3=ENfO|9Pzi=L+ce{1rT?Ue@wRr=&f*JP&`D zJuawp=#=2|Aie1gP%iEhB-IMa0ZopEQauQHz~wAJ7P8QfL>vx_lALk&A*ZiQXIhy~ zmvgYo*$G*h@q)=t<$O`l!3%Uk&Dbs<(a!IFe$wjCv;;oFp6AZR^p=wBmYlO?P&)1;Uw zXlOyRgtKzmImI139v$ApGLd}eOr7$eU@BwfrWLEC+aUitgk%)lspNg7FjhFaua&#q zUBM0A0JnRj+FqWMs|H{8XROc>e|icX75rR-#9?VNzBWj;O;A-KpRF7Erq{+iVTQo* z&j(t=X7H>mF9;f$t3J})kNApkt_G^Dda11sh;@%Zmr~TzCE4r`>kjr){y`Mzs8DK) zq^G?BdL|fodDFW-hoyeTdE}wo+)kR~S`te7Ea2&&&5MK~Iz{QwzfwLuWOL`|wm74a$YVEZBSUZdvTxWQ7>8>R>+aawYmDLs=+m3Rn*CC zm~-udMhY6sHR@@^NkW!eJubNSO5qz4DyNhFJ&%L$>*Kgd=)rrw;Q#v+ZE-z9?n6dbN2%~g87pmkZuon0GN z&H?GZEx0v?@RE>Rr#-1;sm}V)SdK!ID>hhZ3Tw&C=^DfCySfPZKwajUtT9T(If+eQ zFL1@>p@o89O-PHq0ool5)_!s>bq)o{9OAYY9XeBoc*4-9Y^#N{^@?&`eIM0NVy#ds z1!?3vgk<)lm_P9zD4OR*GJe5}R$20#6x>nUKxJ~yVSdRibySB0_Pa1) zl2!bSlFtj3AB`|;63*zalG4$ zIPUVIIbz)^d{l?%6>f=O`kF9Ie~PWGU{AwPn}NGrs`a#>x?!b2e(yf9F5VzFJ z`-Yr<=W-UH<4!C>7NpQ0gA@p|*~KeDTT1Z?{YZCt1GF_5khTf6dO(A#$;jJLGQV4+&RF5f^`S=wtLS7Vd`qgcrP8A(Ve+1)^ekcE zm)j%bR8wEwE&gDA7^v^#(t{1c>p=E+!lSnsu1GFL-Y|zAuJn&A5#FIo{> zmHf|M1?_fXH?&vq^+ek54G^^|Z)^-wh(U@3`F+8?iW0#h7W!kvA`$<@ybvsWY{9+K zl3y(#BTf>n1xu8?$*Z6ZPV9y@3cjL9Tf70HzU3{5K?*TQksx0cN-woUw3vnd7_&&s zUlUwQ5v+jNh85D1Ulk`KPDvXkD|wk$L7h(QfqDdARivxD0a_dk))6sCAqMFtNVlLH zc#bV#p+5%fCg3%KYXE{pj}3^?J7e@>TE)&JVlk~^JjUrzXey(oQ#vIjy-=^@`CbK4 zVzNgZs^o>%kBLnrj`_^zV~)~C)ac-XA2r35b=}qGze`i&Xv^Uma*|s1DM4Z-8h|c|FPb73WZZ%psOWggbWYD&*w7n-uQ<|K${_YW z(y1EV-GT-mbdR7f%lXNU#P*V+Y_hvgN&+Rj!x!4M>IJnO8t$y!&`2ldp$5S>ABnz6 z4g`qsmWxn;e1skdXEiG32?urcvUta^hAW1dS20Yupg&n*rU+-}Zq@UHt8z^w<_k&n znpLMsu6lWhVg^{-oT>n=c486QC(!0XKhi;OfDQ)(l8+Z!F-5A`0;_7dm`KRxny$ij z*@}YJ#zN6`UL@C6FFq)G$cr|JwkUa@Qx&MopL=njm1EJ{|Kj?7tFEO}Kg!@L?<76M z*F?gH?Y2B=Cr#6tj-W9D(WAQj5`sx}w?Nb2dxdipINM&#HH_>hxu;}?pA|GCy()UW zq=t(>gSz{m=&%#Rg~VoAPY+OhP+oXbY|K?8GZjobnh5htWx)%b{P}*EFuDc|Jz9ze z`^cY8BF`i8QzaMJmohQz*{4c3qhzj3-VmH+5#4c#Ppa)YO-z~XL z)6C}08>%KXKc>`SK}~_4EHhH_32&t2Om&Yrt$*rdq3)$7&_Le=bD)OPgb!;A|6=YF zD{~_{W;XL|DayIgusRq}=7oBlFMcs-(G&%q=}-^_pnk`MQsfxGie4?_T9;*&9<(G2 zDcXFNKJua@Z6-=7Nn_uLNg7RiN>+>dfYiGMRTBCGCoUxKzj|%G^8Az_2g~!SP7hxf zq=M))KPb%MgtY(c9Kul-=jFfeRC$OH<$0n*A$5p*o&Cykz(;_NIWf%OW@S6W{ERaf zp9`L0N<1vpQD^Of{@RJ5ZBZ2tY^_!9(E0X?ht3=;=iH%s9;z06>zw2bH6qSB%9~Bj zTIW!J&T(QMGT+z(_D- z2+*5?cR+gE8z7ojp7XG@-}Da93r_5Yh*|FYv^38+hdktci_kxKtu{+R2^uG ztUeObcJB*OczF@z>=c-$;9n3F1-jpf-HVmy1|I^t(TUwFMH{_nWu!+Ggl&--9X!Rk z<{{!~yg|gm!-63bbdz(*Lj;$1T81?w8MG8PQ=SBXXSrN?Xn_-5E7IZ!f;W7hcS$?* zZUw{)`wCw%u)^zIt}7tw%m9Xcg|Dbw;qbSN*^29{Gu5>ocRr_LZ9`7$v!YZVxIw^nqVMFycXHwzzjr~mA1&2vV0Gvh;>P}I>#tO| zUCO^#(4d0|mmCb#w}Y56b-^mopE2Td3uWeY!yRl4SB*8u@HNkoqrW03 zJG9G*MTo%V*`Jg41?P}ICHfaHLT?E?evn?)yhpn2-UYf>&_1-PAK?+NhrS{3wpv{{ zYZ~)l)hkN=leZGI#@7})TSy$O$9K!?S(l*)qJHNQY*KS}*Y9b^zO8!D+xm_sagTd9 z=#-$xy!7u82^3T*4|;kb>Fv9vqG9ST$Xmk&tF0Zn5hlnA?Q>!g;;^Q?Gq+3gC(a?P ziwBf^(5bqh9fJO4Th))S+v}k{PXEQPS0NC*PTkj+YZ~+QDpCXu{q%M1ko~e;>UDzZ z2Hoz&0<=-^bwk?h40(v=lvkP{Yn?*@A`oBOuzZ`io-rPl1ktoE9Y;)_0~$~Z$%4?wd8-#Vnr1sR~CP~PmFI!ygzf7A*c zaAFZUBzRw>m%ITw6%4il#wqN0L8U-#!Z|we%xW6BCPI=5mKVJ7=d?)*WiJlR&DMM& zr2DX<(u)V^M*h4G0|gZb@P*0=?7U*mFi zJ|+5=6T6_-g__)|4fXvolakcwYz>1Bz0e{Y|GbYbw1(4_ zLw$oPbRO2Zg2quiLNFzl0w1W4&p{o~IQmOLH9aZ%XD?boJC#JuW(L3I+r4)%ewR|r=U7O4?3|M+AWk<2j5$rLjf{}Se=#9`Uv6V zJ*s-J{Eo{W*1~!vH+U7~^M>oWJ1^HBL{QzJy+V0~aQJ=aP=L%KR>&go@CPAwJLfz^ z2E8YDTm0Pbx=#J$LQrwgE+@`|dQ>-GGSUK9;du}}QeLHva&K`C#poM)<8E0yoi&^u zv@6-+RGrY}!uh$ZZFsI>r4Ecb<}{aH7K4GT!@M!eeJt0I+HE-AsUp56FsS7I3xY(m z-XqIHLi)(gqe}nZf?ff!GaPcEd`w8@JX6);S34#=O=J4AOZxEG4+ZTL(iitdU7yv- zm2=qnO$^g7WqV!pBmL9>zo?6T&&a3VwL2W$MpZcRd_i8v1@#W(Gla26lJ0h$g3#>} zE02d-<1t>)A;FN^zM-}8-;-t;*ioiGt)u1_HJJ;l3Ur6yM-|dWZ-6!h1Jdt$19Z@d z^Pods3vKQu%R;G|vrqEAie3^wwqlYnbxD}I@-THtn7Sm4eGwz~yh&1`6@)8HFUxvL&IbyQ>4McRpe(d|$3(5nU47pGeb(HiEH zUS;@2pZ9U)`*W8!OuWy^lJnteMR+7#i}is#svfK}oVDjh(QYqV6{6$3=r}JrhWQJ} z7X%KD;8&bHu^)cR$&>ow!77#c86M{3$^Gz1!JWWU%y0oGxXH;A`{8j;p41PwIr)-) znEIz*+I>{%$AzTDQ58;4=e6+>g4PMToG>wFInp`HIkBp)@-qj`bGklY*|q z&F-h9$zBi56G}PKqI~VU2tU#}cR>UxbuD4Yn;hmmEayjDz2X#Vy5!Uam;FMbI-ul} z19C>)DyvxTIr%*AvUWnWShMENDr@>V8iDySHML`QR$23%J?VgW7(%cYU9d3ML{&I- zF%{?gw!ETTCxzacxoURJR;`OF5z{{(`9*E#SSSJvnM$jKJ zhFEn>m#iRDrM*B84|iGP>W;eD3k)1qz?s(s9t}b=mZBf#uTrd|j6Bu=2IIe4SWVcyU8;41;EtR7B;SM|o{2 z76AQRA?X}b`K~NGcfqqqNShvYaa$Rpv&CkA@(7J}Cyy$)A8C>|K$C+3Den!?JSTQR zn*`r)NSmD@58V|ENMCb?E{N0E@_Cf{Om_|i$U+wSk;tu44_VH*LnEiJOlMk|PM6b{ z*_oCZuO$pq&K)jv*y$0B{$QtN{Zg7)$4X6)V6vVmnXGFtS>I^r*I9R47P|espx>M>cHUuxYLK>9^FoSK>_cgU?d_^m$y5p2GTZrz${gPK<+9$)Q5Jt&;;?GG}w*vDKd;K->Kp0`!1TUPY^ysuRUf zV7YH{@LO((Im1pOxj&9?+(nY<{BAaO%Jqag+f$AH?zOl$l@YHV0*F>Yvo zRK0s=M&Ga#iK^2grYk?X{bcR27Y#>&?_sF^+poPvSLhK!LBkO`>cnp7X~Az|NY8l# z^ky*FswYUFb0|PQ$hKFG9rE z-pIOos4CJbXnjG{tGx8+P{3ia^X)z)dfJPSWsAK(URocw6FTC2L#bHTIaM)63WFD` z4<1(66sZ=u40(u5nggLHycY6#!pwMVo?iJQu&;wp3dtVj1trh+nXNN+Xjk%x+q2}M zL#ORoaQKFEC_v^An~lR>=g;1$bH?ePoD{0VEXR1cKdD>gjFXAJd`(4% z(33hTpC9IrXsLkaR!3|KfZL5FUyi9m5QO<1kqniEy*?>^4u- z)>ekplP+c+deMp9&_8%BM7;7=lkJ<%p#Ygf9GFL>^})j6n4((Db~WjO<_PHxC^~De zGw1h-4tVh~(P1w_N1Yf#S}T%HDzE4Ja0tCegxHW6AskZS5I3a#3-q}=L3My06Uyrl z9SW&KEFwB|rVg=)y^8rqz6j`%(~5|d44Ybc9iqec+svIR^uPH!KzmNBLv$#l4zZch zp)+-e&D^4x+k6qwJx(k__X@h?va%oH0iRgZk3i7!rp}gTv7q$MnpAJSXi0L@%#2Bg`7GDG=butvn_1)^Kd zLO&Aj$&ib_ovCkU;u|KlX$t0R?R-03<+`Cof^LA{-jA@&>z^0B;6Dfr?+W3P9H2g|W)Ffnek>>wg~BUl6zwg3$jP5M}@NIF-@7~JtU{+ z1$EA2>DZ?RM+G$>!X@c^2H-Wm>!6P7u!h6%Xe~r*xMv%!ozWV$#l;HO>mx%)oOtC? z(Fj+_mCYhwUU;?n{NPx`ahP)~wgtzq?O!MBje?%Z(05y^M)Z@|DkM$Yr=%}+ek^r< zEH%`0lN@&l1AC5m+XVF-gi8|sfRcxWvK3>>YW-8xmU>m6CR=!FK$9$OezbPDpyD9k zOGUiLdM!l8SEClgup?M!|3t;ygUCbF?otrpa`5C!|o$KhFy8B#599$^5?QIc56c21mj!CfCk zpsDPC;Tz3>Kt>F3pBWG+JKbZm@z-AKx))mS#2)Al!S^)M7H_bgTA}2vP8D{p)k^y8 z-7!O$3kJzLT+kGFB2Iy(O}Fw>zo2_dSGgKNLl>2GL9`aI_BqFH=%uTDeGC0aK3gna z4j*&A`Ter~sh|Oc9f(XoQ{ppLs9_s3q)vw~l#R*pI7 zq`SsE)HP;iy?;%R3VOwf-OzWu7J60iQIXiiC$mV5P#^+UeB(j*{nGll^J4aJ3FBT_ z9}rXlXqOXvaQv>jz8&Yig=vZ z+VT&JpDoF+!!F#FP*K2TvG~Q3{E|55qFo8q3%F3oM zX0vEr5UpW9`;hV;6tp%V--f=aRCcf+HFaI?Md+8E*hN1*>b1~c3OawEYAr}s?k{a_G!DOD!xf!ybe=vznY3j_ful4{?(6DbV*$ z7^T}(rF(_+(LmEBCE`N=Br4YHi$b+-T-!q9hWj$1i-at<=JtMssa|ic*u5%l=GraX zCund&H472Dp*q12IHU$|ut;0v`+&<20;;9P7SERte{vv)#k%#LuE(|1Gnm>%I?uZMOx zF&xCKtE-*NT=)S%-iO>xk8fsTyp?U)>1a=v-U`*uTPoG&BV;=U?}k4gK9+$|&BJa@|l zj+(}teQR!1eaDOs=SF?+!dr&dx-V~xSrRf%Q>N*HRws1WiQ%{f>t#+=fV?$q%^gxL z5Xz4iO`Be%T_Ud=h4b}ETt6c}d-{x=I5l{u<7akCqf-Ymm)FCzsplSf4QRv*QoSUo z1E7}$Kc10Z^9JbkV6Z+Xr*|l%4siwI@P7n7O$1qlxZ%Yj&JY2IcZ{%ICt|4x z83a$s{;D9=anT!Id`nd09qUAcyjU+HM3VhkIi3*s3u?z_nn(QHh5h8kGf`Q)jLV(~ zN}`=fZ}}3}%3^d3Lt~t(a*>c8O{1G4BqyISXBeST6*hyY3L92(jJ)1yz>o z9TL{7?jpw9bQSV{aL(`CmubhP@()_Yic?DH>Et3+g@P)mlFN?K8n$#(@yF#=xse|W zy{==VTuhl;`L*Pvf6mf>U_0Wrm{`u3Wxod6Avf54T)mUk6nv{1lVS`lT@f<<%E+ws#fNxKp;y+D$v ztsLIe(lOvGp`pjjsX_;^9bPhG;P*vO%gKB^=xx2Z$U+%^*lounR^~pk;na7p9})j% zYYr94ba^gQp8A7tznOb)c`AhYDK>)K+avUHpyMMNdvi0J8+CBg9IH^Fo05$$Rxqq@ z_no6x}T65mVQ}1Ak-lt7`wR-ZsSFa3-E}{5y)Sz=-e3MEAmkKKCIOupbV)BI@s^hHpUB?O` zKez$&epf(+$|b6bhnc5sjAa?Zc37qj>oS=P${Z?ZtE^3eCF1+>t(48i&Dok*Do)bw z#Y4Ky+7RbP%ab&vf-0FV6URgw^PD!olMK--seYK)qBZQX>u=KS1ffEV@&S0-8Z9@6 zO1W!?v7n%zsX`W&7ldl5Qx%{|E2u`e(;2Ou(HicX43_f)p$`UYf;g`) z7d}p6fs8BkO+{5`Yhq2r7%mLMs0x*dstTK|b+2f*7cCE#EnWrP zEii1eL4U5h&0(j9n#{?reY_&*YkOM4g9Nz-m(JzJiQCWS%2HhVBv$8M(49W7?U0@P zGsO$V4~U7$GTc+Ht;CbXM@s&vEbdUrN2PyQys=KV(=ci=JMuB1I(NbOradaZdJI|` zgy)prDc*Pvf5yz^wv~8?xLN7LVyj1k(x;SODPA^6$G+lmAJQdk@oe!3G0StE9JYH4ZAJtz7E&u>9bI zVykC+$q(8sRO_vtR4bV@k(2{^d}4Y+0w&B@n)1-)acxE zN}C_`J6_6PKg9bF7t=l#;*M9EerB=uAdeTSbC0NNytZ9_N2RO(i1!~UrhHr0Nzk9g zuQ&g3va^2MN`CEP8yE0=rL8>t7A9%*iF}OVePB$Uk|g zuXj;A+iCswg=p-psQPWjc0)Ep@;Uf{Qb-Qt(!$LER{ z5>HIK>PPE>gZO}$c*n&~-=Jq?l)tah*T23=&%?>iQZGEKbly*pxi#_|ccE{`!{Rlv zj~}aXAbr~>{5-<#9PJ9O0&#Vd5%4W@ko1F z$j3teuo$oNN!MP)1H!|KdsMvfQ@-8xQ`DbI_lY-%ZJ8;dI`_GMvhl+A7a5;?!*QIL zk2kXY^I^^LV!nt8^L0;ax00ppy0t29eSSS*vwGK&C@sXO&K=e)sZQ6zH~g6YYNqPY zMa(A$shcgYN~q5LrM4pP&$kz_zbd95_@aY`oLh$Im+wX>Lyk|3&>wtchH=5CZI+Aq zL{Nj6h3);A(zC^Us)=#Pf}T%FSvz6Apj9vClVEejeBi+Bixy7W491;vNzo6!X60onqeHJ6_C7lABdG-X*)w$i8ihMp^kZ9`xenDw`cq`;gF)xdx9=y*o^^?ji8}(c5o-Fk7ct6E( zwRiXD{CvPa%sb`7TMD*|`3pMj-76;kN%2B){`20Sw?A!By?I;EUDESHz*oh*p-cPu zP34~}9sggUT>jQVTX%|6KmMdddj9~uRKXAVfKZ)V^k-Hc&qOjFc^-xQJTBBB<~gB- zVji+#eerM$%yTjHC6A|chTVA)@@drhjX`zd4!Vw;xR||H~FQ0eWydex z)9)X)%Wqc64;nA%*|LAMcrVD#xHu+WB%XP_Z;wQ`&{p|>*Zffq5w^*XdT>9O^~0TB z`hlfgSoF(&d^<%+r%x7q&*H3*o&IHEJ**y(UavHITZT%g&VA{WXQnj1Pb zV(#MLZwqzOxH{Y7aZ6{v#veCIwwsffF|BvmonwC7_t+pE_a;_~Sr&Q<^SqT~Z2iBa z}S$j{xjK4Pu;o3VgATm>i}Hq09@+; zT*c#a*eGlg?i98NwhYW~`WNK$qHsbuDV!3{J6HP%fombQ4D>VoB>7AhrVAa3{~XD4 zg$2UGM1Q&Dys%bSm*|&BzD`&sEKl^QZcU;;A^D^*c(C>t!U&;3uw|;`c43AvN0=+D z6l_61v!u@_`dN}^3+ReMkFY?n#dM3MyDrf`F8K-Ju<)dCM0iTD1u4b%t7lByR|40t zz*B<7<~kPZ4RGzs^vGPp0{aBhpNSuq57)53$;994og1S4wooT{M_X=FgvITpeuuj+@;I~!4 z??J(q-jC^je!?1Iov>cGL$Kuq$uA182(Jro2yY2t8KL7aVURFHuw}O7%Y{yXYiG7B zlf3ccT3^B*VV}S?HCtB5zEbEF`h?ZOI$?uwhhWPj<(nqV5M~LsERlSjaHFtX=oPHI zJ0;sP(8u(HRhQ}u)c3-9!Z3kreYU(L`^&gyTG+gTkz`;>ZEH<^mC+Jk4?JSLZ^`COXFHzi=XDPa!x3g)dPQ9 z?vVV1a8%%0t1aj^3Y&#Hg{{Kf!ZzU^0sp53Tb`BtZQ(iLdEuDwieQV`(52;!P?_U} zSpwH~ZCN3Cov>kmzE|l!VXa{HJ0x!uHVL*gkJ0h6@ThPv7p_VR={}|J7E(PPm0HEg2uY~6Xu2tKzDbd#@`unASKzK;lCD^hf(e07ESJ;=>Q{5wp{t3y? z3NH!A6a5sGIaSyz>=Pap4hptln3U3G_KPi7??(V`hD`9EWgKvrxO4BCGRikUJyUrqIE0Svin`^ z#ConmzBCs1SZsMozAp z&6Z=5PYACIr-V0zw**_(P0@BDJTJT?*ut?e_iDiuf%~=Gs|Ak=+^^+cE#O`)aQA9; ztjfJw!0|2MUM=8WE#O`);9f1@coT432{?WO+^YrLs|DPv1>CCz9A^RU)q;8*Qvi-j z0Q+^oew>y8WbV;g8ku{wfP1xo{U1190{3bG_i6$2FJPVp%nN{fv=$ec@eI}q+^^+c zEm$FNzm|Kn=8w$1TEM+puvp-JE%$1{CV~64cM06D<=(30|6wsP89#t~wSarIfP1pG zAP@Sq>;m^@!D4~?v)r2n+?xfj3bvf7o@SpqRr?L0LzpAjf__>_KO@nj!ynzOM9+QP zYNff4%ROAcy;@tA|FqVFuu|AB92TAvP6#K3Hw1U@wv=I;())xn*?XsHJqzoFI|N&X z|BQ|ugcf14Fjbf)vz!_rwAB!~yLA+!F`f3pamc z?ui5Lg_|Ckd*PNw=AJm=-aWC7_@0G26PyVcqGli#wZwa=fx~CKUw`XX4 z2`>mQ3AP;hjA95!g{K8uQr$C&eqcS#|IL}2*M;i;q;p}x7Ie9ij!#Y7GD>oT&?Gb` zdirF6!2Nyh?E~)Z1McmEQzdY3AB-%4d;5TU`+$4;R$pZ9?E~)Z1Mcku?(GA2Z(n`G zy?wyFec->GTs}_Gac>`RZy)4l#qzA&Gcms0+Xvjkw}mga?hqal_=2k~e7LniXcEQ> z_Tg5uKP%la;bq~tU`x->t1ZF;VW+T5*emQ44hZ(eQS*ONx+B6%LQA|%_`~gi5{KBBabcg1WBvL`~uG| z0G?d{Ji7qy7R=A`Px_pWD}-r6yD&qTDa;Z02!$;?r|_ommXP~=)DMzeFW5`$&EGx} zWnYN0&qJAgWT*N=u+IdUo{s}=7w#4A6CMyA5^OQuPU-k8;v>R-;Zfl+!4~qE&%Q)I zxJ%ckgrUMPp+RU8#tP#FTMkHmOn6-2dpfo}EBQs?nDBC6S^C`UIcdEd}S$j-tX6L`B;|^3OtX*vq<3O z5?HrZjxjo(MFOl>(<47y0?#4=o<#yYiv)P4$o!419+o!7muHUv&mIAuJp#Oi*!+0@ zh&Lni{Ly2H-s~2i=ZEeRwhH$M_X)fo$(D{^&>Sqx5@ri|fme{&GFS5D!b0IH!QOUa zc6?Kt=`UKOV_%_7m@3#}I(yly>3MJ2_%~!%q!In+ZZx-w=u%=%vpS6O$X4CY%EAuhopumeXZK=Ob z*F=P7f!AHy!gFUla|WIlcJ{RuzS*GSLH0tO4b17NCP z3vUhJfBpmW5u0b!0MDY?GO#_S$A@Rt0MCF8^!v9?TRn%UZs!R@g<-;QVU%FYY{_$k z%Y~jqKR40MPxQ2vXWIt04;{~}4b%@zTetI{HyP}RC* zaqH^7-la=hm*23s_nO`>wUSuXdegNlZ*V^oE@_$4*3veyrLC=X>6(={_x7!7z4qqb zrK^^F;p%Izop{NbHKIvVM3-DWrS0mriC4?<3rl-fEM4B(cSCRA&8u2hUUTgiuDM=8 zuU~OXYu`1!*DqC!YkF^LrOZ{WH>_CIcg^zU6INW)cf;zX7$&T^dBxHRORrgcgN)ZM zzh%kN)|;-mcG(Rpmgat3>bvSot3IH*uDbb_-fNetZ(Eo2s=s2=rKvb^u=zAvp@x~gRvYx?R{eM@dw(Wiul!Dp7=eC-$Vk~2NDed`S+ zscY#?*Q{Kobz4f8LN4>e=q&eyWj3Me{Km#njg1r9s?XLy%9Yfgu4-tUIH9p|d}Cvy z8F-8``?Flt`PJ3(+;KQ1e_Y#=UOvE*j0faN!=xTg2!*6Xjmc0$?c zo$%=iliDVJdcqecPq^ut8*lDqyyG=sjDNaiQp-de=|46d@xhJoANuU^0rhF+E%AdH z$fuQ+%f-$0>J^%nZ(gO1pACKB#;@&G+rG4ZduP*^R3lHD9wckhcasC^FjFWYS%X&o z+ImYfg`V(_Ma!aem`^0OAe#4RrUjoaIs#<#UrpXGfiKHFSX)iCk0i5I&W$mXiwtg6ad8nVs?_uIm6PkXkq zAsf<=t!$Z?4VhCG<9FoVpqe#g4K1o4@{;y!aYHt`VRW`w{-c9G4^C%)SQQ)VD)DGl z)kn)Ja7Z4b8$VlJ<7>)e)!C7%s`l(d4cRR%`kmX+);4NXQ(Ja!!>CJCCs(tETy;%V zt^aL89@R8q%w?@(E^VC{T(Xb0jGErqI{FjSFU#i5$r|TW>stl%I*)8;zg%6_(A+ky zsqr!ws$IX;?X^GKIN{>U8YfsEyDI;7b=6Q;<$ux|t*k{=&u0mtAJ= zuEtMRRjI6nI=Cza=C2mn-)ROurzN|!LAwI~+m@|v&(3YR?1C|4F3UdB-j-c+U3PJM zc5QpxxLMia_UuzF7MA~LWcO58O__M{7|rZtAJj6sG3#w``7~+gIBYwkC!}p`i%R}8l6@>=Z*ElZwo7)<$ zY_)N~-%qmtQ(ZMC+qk|x`)c+4tiB=ZYxvB_iKE7ho;~z0veb(`Xw0ypsK{G?SWCe)H!|zYzWY)RVupWRKTW4Gnuf{@{}RWsOcL zY<0O&@Ygj}+3&1t$o^+GpN4%xqbEJr_>RoKx~?kwE_?1@mEWnXA^X%F+2ezl(X~*}sZpZh}+QNT? zrz^?av~=|i*XoqnonlY&r`VIOUOlmN(x+px59pxwhko$=<9q7BXX~UTIk5?QVr|-Gd*agGS7$5(_pAKV zDtofJ>Z3K)*+mVSPO*5RRVtTUPc|`OcBQXJtC+xG)>k_f?x7 z-9-1_s;U&@m(HqEkgt5XWuX##Ypzq`*)O+fx2@#98j4cVCP@C^fl*+~-UwJ*1{W>>e{?tp)UWv6sfbm1k+@=rN}|H|zRA6H^tL-t>) z+I@P4_7YP4O@{sV)**lWcI3ayHC%F$QZFQyf2p369lot0+h5%vZfR_7lVb;Ywz)k2 zJE!g`9Xq&I|35k(YHOTyfgKX?x3uh;T-6jEe>BW!8{d?Dc+O>ok&SH^UwCm_Yxasx z2k*JPVfuu&*6~WTG-ki0GrnWe-lvnptJ}3lZ5)%`tBlpE+9bjVfyJx9h3( z?^ZQr|LZo=&*yZO*P@2DWPk5WJE~gRYN{`;shT{U?A0UuzJPzoWq+HiYR*0}$99IU z?wnALxnN9|Z^@=yS7v!oqvW$?Yj>|sqQY*{<^D!;gvOuivj0miS6C+gW|uuzU6ozc zkTtcq-v)liH7vXEYj!~7;+&MzIke|5Tq7QKZGFz#D*f7q?5}jRGK3+aCN|YnUr*&_j#_2Y>@Q2-O ztJ^94*R0B>H~zkxZFkx~bo2f<*R|N(&0l)62XsAajAotR$QmqbH-=N7(xorw_NSUt(^DX))GjXM<^RChbBTgK250}TPAx|^UwYx^-Ko)>+Ru!= zVD!XKUedatHLtUz)=^D5%lnhtTgFxoNsjNgatUnYq$#ZnKBd!uOPg)(<*&urZcWdP zjh}5ZrK`w(=IqiL8-F;?4l0Bi`zzJ#X8z^2mh6A5Z^?E#-D_3t=2|~QuHQ`Nd;Xl9 z{jGKqE6N(rNxN3USUZR0Kg-$cv1M|Ez4*78qIOa6o2QTz|QpZSrU zmfX^J!}1^54cs4Dt3J5TP= zYm+UXxpLx9kKqE_MJS`zyEu%KhoWOjy+b{v=PoLnJxxCE28ZoP9gEcQ&Kqblw9eWsx&;Fv$Nz(^MbaGjCPRc8kvVYWmxUIEqqIvQ@rR?phs*dd3 zIoZt(&3>O>dnwlzM>kKpXms{q)ttH7{r8Q!@Z*h*qnlelJFzvpp*=glA-ky|8`*Mc zc4++^y94*Y`HJ>ms;e5OC$|H6MN{_soFkTza$W~Cc+uYHUe{O33y{?Ra&zwA>N(&K?!fDZeo*@(o#%f< zPaU@Y8=M&b_#B2MGeqh3X76=BvQbbv;qIJOI@`WU4}jnBxto_P_0NR&UdL_JstWu3 z>U5v41AuS}p*?+gMk(&zC6zt?N!mZ7B&l?ktx4I=vUS2;x_ZsAg*|cVi}BB->O9;I zD5UPa?&_PaxncR@o7ed2D*gYn_a^Xh9Yy~5j5>Di5OM;stQkqRlh~R|l5>sj!`7`x zvLnY1lhJ5Knpm2d%wb8!j=@P-U;`u^0XA&7!kKXI0?TqO@Z(y}Ci@9q3G!mfJ$7d?pg>q9iXJT@1s9_)%^_kQB_2H(VS*N%-1vYAR zKCn^k3qiS8d+`gW(NMh#m-ll$+sbSk@%_BA%9mA7K(&SBH=ue3>(vK+<(gCV>c$u` z>aKIJh#3Wi!D7^}PxWuP2)Rm|$s)cnzEM3XP`^WELQyt^_wL$;=m?yj zxHY)qcv~^njQYsqAr=@r0fWw{FFxMie9>4#;|=PQ#pzqs+l~#Y&tv2CU1uJT)~dsU zEm5@;LRHboj);{n7^Ftse6GL#+Qts`xLw4disTfkhpU1Nb|*PyGiT{x%maO$s=U&yRUQ>>%2jGYNigG}G z2Y>&j3@_&g;EeW)a!7sS^guAEo$%U%SA+T*8`OD&Bkk(6!DvvO_N}I1=ToB1!P@Zl zEmzisw+Dk^^`TNoee{gM*e3PvQb2v;jL^kP4cpa2PZ?D2g}0je;3)wT5l0rP#6jncYT%e=z3M7n=1=X2f+SC}lWXmN@TQ92Hx(%ZS5QD+!j!UE1{!*`A z79dtb^Uagv>h9%`deg}P)iRA42sd%7elX;c`ogLH^VEehSZYrGL=?znA+*%d(Seq0 z8>~#r$V}?FK@cT0g%_scb}A04?{B&f*i(-mytGrDT^{M!5{+iVst0c6SBBI`2s6D2 zGd&c|?utTTu)ArD@T5Mw$sg!47Dw7212Oepka5SL+8@9K%DYubfO*lz&@^tFQX#HSoeG1=QOQhTtp-T7;B7h>ogvAESfCGY?NA z6L-Jv*$`JhIWMC=dT?;0cBD3{{^2~h>kq2i4#w5@&I^rjdc5FZ-0r|J{*?L`X}z{# zq;nLigV`NqL@M=;$NSG)*=&=}2q5X+bNyZFD~ChDh8sJsr*HgQH-t6?qg&J&ck2l= zC^MzK^FVZ@wsvc@qeFFM)UH5#<9_-`Hn(r9??4wWj;c2nGIQ$7j|-^R7eeZNfa@0< zzSMz_;G>vvAkx)ZZbi{u?)c1N1EE zZ)k=GOR%vay1k>mlkS<%N5)S9oi*w;M?&g06#uEX+}w|C)Ef1wBXOj~%|0K4Zz)72 zZoX_wBTZE`d$DZ9JFkpfsk%ZfEw{F+8$#-WK&SdSSoU*IfotfG@$evM^LEha3ows< z03yI&!AM|ZC;F`p9dD80J9N7p15u)Wa0YgMEyHJ&FZHroEELUJgC$ODrZ;BQIU$vc zw_p%KWI%0gG}aRiZf?NouZ9k6uAUXRsJ<>%UmvNDG-eO9UlklvXCGHjI|2{Y+J+eB zWp`~9>S3^LKOBjJ`?A?wcUuR|<8bMO@*fTc8#mWA)YjK;!jVCBr-^18b^2hG+^1{klp(lFx3z6iKc0`Phb{<#-CL!e zq0-cEPxAL}QIE^0d`N8yT%@k&^u&TtU#lkXjs_c-uT%A0_qQrAU*PBLfL+WOVNHGc zEdO{t9HhXBj)mHX)cJ!WYAK^W0Ad{r>7yJR^qSB{b!xmLvN_TV;<~L!&!?ZB8Q6-K zcNYU{7)&fg`DI%`?F*P$e&?Cf;zjji-|aCqi^%~2;Uj7~b}i~t>Q_gmI}LR*#GCr= z+5RYMd;5(6%o)`F-m?M?#DI#3C-iB7XhTQr(%7XC99BXx9HbGj)U^Q>8*CqqU8QnZ zNON&i@w^*Z{zqrQE+cQ`I6pp%U+$JK-#m*GL_dG~tawMmc8gHPnNuG>$G@d^1bZ## z1v;^gsl|}`$&qRGJjK6o(uP0qe;*0lsh*>bM@umxmCxlP>kk@o1O& zm!-IR*(qi9I8GMz;7Ul{zAD4z2QthoU}E+;uwWG+Z%R*Ee*D-UmOa}sryeE zr1SdWkmWjzm#5x#o*$+hbv~TxF!KKh-a$SUz)XrhJ<>4JaUj+>(gs-QJ%(< z2aI7U1ty<)9%=0Ch37R8PM$U}`yc8bY3!UQpSuv48MZyOzH2sSiyl3?C@Y`Vde zif@cS7Q6k)4IMpPLpy4>ZYM+OP*ZU%hi^F+Z&SCTPW7>+X#(-?Q;t8q8>8B~sj)7& zDYkW?J~&Dr?*{dBboqC_c$C1X22PP7{?v6vPx*>^Gv?YCFB}xkJ7EoOo3I z`X*HWoI?BxE_ok4J5)=@mM>(9*4JM^*FSmXqJfkL#0l^DhbTkKE7t4AP2q;Ii^jnH zUy8-_7aIpLV(M!fFt-kKRQ{{XoIg05&o9Wck_XQY4XclAjDvTLMmi(R4&&%@0LL*x z7su4nAXm{l^KreDLMD++V z%%b|cbNuJ3Q>W1zD@F_p3OL6{sB{_2wgB ze(_7|YJ1fiFrz+=ne|n$&M*1U)|ZcjE>Ukr>gzyZ7lJC=uL%ctL@teO-i$@6p{_ns zi^C(4QE;2~QLv@$(asoT>%qF<4)t|k+|Fi3epGL-!_hZL4d1}Ax>sBjP~V&l+@(Hx zQCwXUr|>f~xP75E+B^^>KJag1dvsG|M=XL>qv6t_x>krCuR0v+R`+iRb#98G6}PJl zD5-u}=fAN2%3ytsQMedgQa!{r&w^Om7};rw^5)rc$6e|NX!y6jP$!Na4({3?Yr>iy z>czii&iG0wwyR-Bd)wwnbjObR=I;6H)HfEV)xGC@>)IWd2b-4FTW%Okz~HMc7<~EF z>Phh)tV-mG-wcDfW_{yMq+Q}jHyJZ|XdGU?$?tgyo)77iaFRRks>NN)kk>e-l z#jy%vz?TC};U+u~I8v>j)>0hfxN9Y&ez-9{j-~a|4ixyW8{+EIIM(sA$CulhcEv0U zVdzYSxZf8-{us0>A>(MO??Vc0zGREYJNNrCRaEgS^X)}o1wVAZG2W(nW<6&(WQxOq z%eQTBh^lik>WoY$==^%i6!&*@O^m>#54p~8T}J3sAFRhQq|hA}3P$TxUy!t$Z5ktY zs_)eMx7=)X62|aU|5NY3&}LyUPxaIWH-S+-)w3J?J4c|MTB%Wp`?U>l_&p74P5tp8 zk3s&x7wCioGp5-$!0+Id%#;{epfEls;f+Z6jIXTTiX17EsVfw`?qcv=ECiQ^qy53F zFA8pIXl~$!1=O3`#@dF>5zLaYhRxv}vF*VK6zY2QLg7qWl+6M4D*XMA&4K;urOCMZ*5*LN$Sbi#c3#RQ zeJe0n4qdUe*-kELJL%qDg zBvY>DV&~+8`=0tIV8Ti04#isZe2s4$AA&wI2xogsen_}inhaU^dPC~!xN3$X6}M&x z0TMyhsm>Gw4Uj|CxuF;yw@z%up|Zv&H)EdFYz$0e8|Q3Dq>zeZ>V|k{ZBy)W^-GN3 zZ4lLdioefhzq}3_>~rdQfVb0*DTBkRpKbN?R9&E}VcV_-@SFWyg~VE< ze_$wK!Z?3am}i;e`x}gz1@9B;wBzdi$ENXFK{=r~rMQMFy=!8hC7nhT)vWHpn)h`e zc0nrMheZDX*cSipkQY0j7_?S>bsHVY8`R2RE7oLn&U9EkE-(an>N-lkZ7}{!gw(l% z>VJTyzdgOIz6T?~T@Z-BjrYGfJ>*yr82MJ+bFsf+=&E2k8onGY>9zK`S`a92#F}R3 zD8u8b_g?IO0(uW6Vy+Zyif(5K?pW14cVs&_;Q50c;!`uogVvk1yXg`PlDK{pM#42a zJ}1&F{fKW2Jhr*+1d3T}G53t*U$Wu<#JSo%;^b(o_9@>VvpHZ4{FsSSU(?3ubiM=pGSP`A7e!hD|*Cnt7+gbnTf4W+P)s4 z_@VU5_(GBgS(eNCgv-OnpK*PPFoV4Ni;goA*v0w`#j`c&unulaS{SgEhuubU68?%0 zV{r2p%Pb`A3-BCls7m>Fq-cinZjmX1{9WxuGP{^OLDSf?>OJO3@_)~h#525}Q_hc; zhlch8c(hu3R3?eWqR+Rdccjb9YAR?Q^Pdh3f5?&12q0iHUYCYymjLh)PYbKh3XsL{ zq73x`pZ`fP-u-6{jdw3P>i8P+_6+E>3{?_@*BUH@u*KI0+rvBRk^Q)WWnDIZ{!z|T z{|=TkysLk@iT1#!-V|!LiX(5|P`^ZAmKgV(PUS&?<z8d`G;3l-}u0&mz}t;e=1LTc!wy| zsU;LI+tGnL5yK@>OfRI9r8KfY9rCy4ta2sQ+M)1X#+K0uA*CnlA~`EvW`! zg4Ed=Yh2+SGU{o5{{`5pXs|4W7s?=Xk^jPrU>3b`;-cE#TG;NeKZl@u*baYOAgm8Z ztOQV@zo+FE21VM`*uF2aTptP7)`vHP6-D8S6Ay>gIk2q;BH}xvM&mnGZH7BjhvJv( zoDJ6YE3(%&amKjW!p3`S)PEt+-Nn&nb=J4q>l)|P)U=8W(!(PXVwGwmK~Ni;TAy)g za=>6?=*j%d%#w6rkpz9)f6Wtity0uXpfNsoScd8vGO4vX@ zgwiiQ79XmsxkPWP@D?8RgBpLRb^rc>FcBuZf;Ahjfc-4kc+r;HhI+)k3N)$*ZVGK? zGeFv1e)g+I{rgSFu^ZE_7USyifp(m#j;nvYX)tUDiZ}bHmnuJvklZMH;r?N)0PV2m zVXG7VHtIKk=J+wh^!N>Wc{A*(NH}19yLlgwdbjeQYf4|!fMG-EuHmif&YQ~WM}BOP z-UK&nII;(@V_tFMCGi3w2A#U_5-eVY?rK?C(J|yFM;W8!j+#L`mb_y~eb=@%xbfOX zYy>0Y&yNPKj6AI#nV(w|azerKCL;CU-rUIgBZTB&oyYBNw@}P)q`e2Fz2~{@UC$bB zKFJ@HzD={et=PyO3|fGs@N*DLN-_{2G;zN)@yeQMOO(9wNWFv+r-Bh@M~L?yse1s+ z6WP_b9G%AFXKMmMyu4W|_*_kZ`+oPy%jfas%81I`Zk>C0ZIZedb=GO%*!Gp-YQWxc zlK+W+bluOZ+LZYyY95;pb3gLbfVJN8N+$JXZ*SFaj|8sWQQriArr%-@&>Jx8n%eUXjx2MUsr>**S>jq1H zG7b=0_*Z@KDHv;cdjCm-LmZl?9*x%p@#U%F3-eTjZt*J!Me>Do@iZ0K)L7Mx=bEbP zOr7s?>ijsOiMYk>DQ_ zs2)2(@MjhL{v0O=9`Q4QYcc3y8z;izS9K;`EcM!-AF6M@Wa6W_r_@ua%v>>@q`N#a zRG+YCNVRPK_k>h)ZFMk;Ikq~mO4o+($g+@4*F9HXtye=ybrWI$3JJ#8hbEje0lGPT zCII}|8vc;Hp1h2Xxu*=BXaZEyc`Ki~;}m$p8;1{G&j&9db8ZYdcu$}D@F@^<;SCnw z+PM?X%MhYZcUC!G;HQ3sDzF;80M5Zrq_gYSPIkWYVn6lrQ=Jtb9!=+zqj3C%8+;Vr zk5PEMSm}Tl0IIur%o*nztY zs_*Z>M)hqg_i-^l`EKii&dUqc%aos51pM=3(P(|g_J;7jp_5LclRbgSQC9ZD{nUsI zuZ5g@ekj_~fzWml2-&KnH@9t6Io^e+zK1He(erdWqQXWUka;&E%qFnP_|?*v7-GE0 zO=o&B@i>IIk0S&FHq@aS#ja@B5e_ylp_Us?+5q{Tg2>DL@S)tGz6!}1Z?8r)HTvhA z6_28K-?`~Ne7g78?O}ZSwI7Js2M@T=e(R~u8yVGce1n@Yd`Qsa+J^m&`p>Rjt5EE3pboMq!k^K3z8k)cJNg8SnqgSVKnl5iUn%<)`Fcp>IYRl?mT`-Ah% zju76D2H$uxLM30(K&m<%xE0;KYeT$ayN=!*wfYOM;8Y($&hD1RO`V)=#)QjMjOn@0ywM>Vm*wu z!OIb@Y%Q(o^YHR61sdS`e<-xQWjoeQn0{KH@eJ{8gVCz9VS5xF`&jc(u6Ap!)YcA9 z?0|aau{e%oMb%UN8Dwc_fF(29u$A^quxI$v!4E{G1GK@x<(uVN)aF6waei=D$0B?< z%Q#(S%3_D)y^s#DlOhFsE`w-fZCjgJR>|CIRE5J2yfD7x^}cb>nZ;>|p7fK4Viu;aiVyzw3v>VoHO zcxO|6-Mw2b+5+IhI4bhE_y_KJn|kGu`zF+@)nHHfsiLUIP~#rleVoiQkq^g*sIzK^W8*(A1#6QTD!W&}Ag*Qq^b1X;V!;8tepY0qP7h&~do&;W1&Q0w`gynAB z&V@nU!JliIJx>0^$nzba|9mnHoQ=AA6UFk=vAOhguupRV5$`xxzxMfqj)y;QJ6AVD zN3}L>Y5cEk!r&QXH{YaKyV^6SRLDMRtM#Me;PB_N2Cta}CkU;NS)Kpl817%rYQBbu zrvHF!X7j8iPwn2C(f^DEgs3!xhiUh3^;meEvU*Ni^l8{wIax%+OY!b zpm732(i%kx3Xf~e#zNvOpKz~m*4?TwuvLy6FjE^7GoFlU1;e!HPyhmLJE|2jxT+Py z%bc#4c**7UE5V{x)ya9^nOX^Z0awGj6}`u9$;I|v(l`Vuof7`3Fe)C3Ukyvt(3YnD z*gi`6Ovh=&L-8Ky1YZ-Q+MD4SR--;A2DP_9jl#>PA3S+_3@9BOT7!vG*|T88!Ybu@O|T%;2?WO^=MUher`6!C2VO z9z~uH;!=vU{IDcnyj8VNH><8dTUfOP)E?+djoU{W)V0&<;=u5mvr!xv#br&ZISy}( z5uBqBAYy~MB4p)&*Ri&rp6q|3wW+;@3B2{`)W9v9yF2jDv3>rOpI&>4AE14Eg)Rzr zZ5)*60NfoAh?h3Vn@JPScs(Vzt9p}gq$_Ac3XTz7|f&e2)eD_GG&EogS1S)#-$-ICChV4Lf0@(WS zVOm^2v4NO-hn!r#AKr@!7S)jY8A9LJsPDm;tkjEzqCQei@xLN$38B=_&N`y&G|joc6lVCjdds#K$K7z?LI_ zF#ApmR2ZhDQDOvq6)1T%Oe&{}WxqnJ#`z&w{Tph<6{>fd5iq;dJ%?pDSK2!P_-7;< z%q>8WQV&U=Z`mM`S%Pe$PMyO!`S~N{9d85dif75?8G&yCYBZ$k@4Iyfv!YqO*e`F2aC&!eb(@Bl7;`h?0-^pq(InYOVP6C>k%!DYr-G z#M_#l;*Pe7(OuehvPR&84aJy6ASybJ1r!@S7hqe*0-daHw+3HuB}M%~U#Ei)RWcz& z%2h{?1RUqO>u2l*-`xqvfIzTKZ`+HjS=V}IjB+tIcj5`;&t+S9#OKmuuKSMb{v(cC zO@@CtjCu`QcvN-%_0L6~7&&51Pft9@F#D8`4tp|62Iy*kpHDS7D4xfm%pm5L}WwYi56kQvj_T^k&aQC)Vyzk-r|Euvo zVYK}stIU3wX)nM*_H9stwno}Vwp+#ed;D?_&W2pN<&rJ?hTAvQw;yP?dXZS)Z>hl< zfM8?$^0nb6t6#~77r_9qsc~2#1_(Xn@E<}-#o;z3@#VfPmWF%$@lDr8cG%cXk!#S} zJJ6cwrGZV`=xY^iY-qQhao01$r~Q7!(1EJ+Jdy2xg1gkPA&J;3rw$^qkMjQI@f};X zSGmN0*B1H}bT26Q$3olGz@WMchwfMkN-|Ra#V3Z3x5~>G5mx4K;K@VnSK7l8_ptSU zMVR@{=6cvu+Ai6-Z;QpnSNQEqHU6!eBN4`nwWm_9;InLk)NYMAL5|LwM(!Wh_*-!S zcIe_Tezt9aRzlThqr~Lv-xh}91iEEYBkv(qFRBSd#1f#sb2Jodn;$xW>q|q?w)PHn z{a_muIqRVG5Nmz~j6!hSVi>wD>YLa_eg%BCzJUb#ZhiA8q6WSUg-6;t>Nhtusm~ro z97Nm4>-P~d<&UU6h*KL<*Mtxq5Nd4!*fXKW+vnTm`N5;~dc0k9 z{bwJg?)Gy@f0pF`MNOzFY<>EKL~u`dgb_m3hk@(&z)rDQp57=#hV~ zLQTAiJ>-OE6@WfVfPM#p`W*mzngGNno|<_Ye8b?ScrBd7em_7sRDq5km&Ww-Gv)ag zFasdao}wA!1p?5ICH)S`|6nyhZ>8F~e&8BeH2!kd-A7#Tcuc4}(L&v$uut$PDxWx_ z-8C`w=h-@!mYuzGVKE=|Y?Vs_F2{2AvmYY&{5EDf?)U7S zzm6$zXL8z-#-Ha&cnfp#k$~ENWqP=OcEk=?we< zE)!qdfH0%MP0^rp#ONzbzVmed`Bs;FfC;FNCBGSKx!VFC*~fEtlBM z#lU`Ky#HkEr265fx^0WvI^CkC5keSo$Y%rEJGkQp-tl%gfOv0kP7Uy8llr)=;0P;t z$nSrGO}K>#Kk_8p#)P-ax$&>na1$8ekpb4%pgQn5-h!7e%FDe+14Gwdo9INsyZy5N zwGpbKXlm*sa6rcX?hlXNtzK9&or7w!6PwvqSq&UO8_&cR_i2IQ&Ftr)(8UpT2$#D+ zCC2puX9g^I*E8p9k@IxF=*ojF5!9tsz%!0B8a=kZ<=2+Dhb5rJn-b8E4u_h9_*tNG zM4aOM69dNM*W&-{Ec5Leh8Ja2WJHUGA20*!uLPa~ui)|ERXosQ4vy`(4w=6Kc;Ga^ zO=7qX1n5BkG~9QXip;-bpSMQ6O!j=gDbJrjL>>B#*bhY4fk+-^(g`Mnv)O( z`Y9~)mQ&-M;V{ArY+tHH6#o6{A1l-9`?UTFfbqF)dJ4{>o?(^frjAr`noMa`Ck~ZzrVWyR)@gBV4b=PcR_sbwCQMF zAJkacYv12;hq|?LpZd*d(|4#l4`aVQd{yv3J7NT06>RSAZfm$Ii1574*~3BAAD0Dx1ov=c4?rTiMrgt9W35Z$*+i$)E+J0aM_nhIy z@F^7s=~=tm#j~jU&ePyIfU(dU!YeuDcuZd-yIKm*C?!BgNCBH=XN@Dv(e?msC5b}8c+-xx(mkq(dvW8()$ zgD|zkVQ4w7`r`HK=}Q^uN2B`RQ{uP=1CvAj!?A$n1LJ9c_>NOFVV{W`4(R3Z5KL2l zb#e&Eco0$jw*!Dqb=%2t+?ctk6DW9=gu}Q?tQ+4J>&9Ieo-Lri1MoS>Y*Ftz7Qzic zO*sF`8!SG!90zu`srTdZocAna5B@DD#|1;%VXm$59l;jeT7BZtylvep1pVb0Ue?NT zRJxtzT%-_pZPz=P`Y1IV7w&J2iPo4+Ag2TvNioJ=#Zg%>I}4>yJD_SHvt zBsz@6$C{d1Sp73DT(vGzlJI%xyJ2fKm6Wfo&Vrytfmmdy-ihG)Vz%`&ofgmKHuW&WjM(u3)trR#LZoE}?23D{!Fv2G}l5vi(V;oOkJHJBVkp0hzyx>b+d7zvBgUQmLk7aj_|v&!wBv z$(d|ZOX7;ASR~qdWAlNk4+pZj)Iw!8ePA((IB2=_qt_t)l-$^BGJ2j!Y(UT-97~Rp z@V*ZVH#9=`3pfO@2c9Qf)Le*h9}~ar!=@Ni4cy;#s&iG)$M^*YWEd>+!=h0AKPXfy zff$2ROhd#9H(ZS~j)T}Nfzw#!#UtVIwoPp299KJe zCYt%M6u3jA&IgZ*Phg9%^%s#Ie7GRxF{%)%C{*;0^B+Y5IieP^$1kvYozTQnab&a= zX-X>>hnVR@NV|MhzGp%I^W?jU`939S=Sf+_Wx&uN)Y#gg`M*6kEiVF7a@o<^NeRTb z3>MST$?F7JO!3@+?|NZ;JJ-YGx-I?RMy`(myo<$3q5LNh`Yoi*AN#~^a)Ff(pD>Ta zmw>QO3)}!rMQ@W|+3JLF>*aTZv$@co2$b3JNhX}7r-mea4Gsg*+7{GMvj@)bRebK} ze*eWoO~HND0_R`DXW`{lQ|>OLM6cEV9~q8T)&J4o^X-3}Z!C4D2dclp9{g$k)`ope zFdH1gWr6|QZ2|fpVFzP#EOrKp#YK3%@i7`Zz{PdFX+;sknV~)jVkIjt!&4Q@=BjEP z+KLl|%ZqCQYN@$dG&&ftaC-9}2*|J=E~(=&P#SS#BepA~@$W#;j^A zh4e!DEEvEL%|{MB+-jfq!K$;hE(ob>P;Rk<^aUFAk4JD}VB=6*T}#_SOf6<`JEzhg**Ds>*MYIR~7A^_6OHs<*A?5HKG}4E3@=Y`vQdP%4 z-q#kXuQXYxB*O<#-%iFCxG}H^zW+FEv4~565IU8TMMo9FzKaDa=yyzeQv3y&D`)YZ zLO^qe5-hn!R$R+Sv<2HR$EzBBC#TSk<~Et|G2zj$aIRhJ)+44zPgeZ%2&atoCbQ#@ zzr_8IxJI2)>y9kw=M#`oF;@4>A&xg3bIxJK`SE_u=9%FEKW$O>+$8cMUAF$!Pg=Vd z!ImtWo@EiJ_D^cu6ihd?*R|J$>zji34?78l%Rilq$MgM;KJyH| zBSFhy-^2{>MAS2Dcz6#Rfe1^O3WVT74e}33FTU7gR3lv1S4x*Fg+F0c|0L1+>KcEn zt0`EQ<7u(;16{as7FR<0a1|Vb4*we-UU@9k(SZxTk$SwDrtaFfO3Ai@Xf!>E_V%VN zvFs5n-aD=y8Xi~Qy(zTiqF@U`%fQ4R-U+K^M;lJ7J-I`D^rq=>e>56vZx-@JnkWC?^SZn9pz_xHx)waSPvaS9qT=0&F-{&}&$H@}&Yvq4J3o`F?Bd8%=-FcG#2~Mza$@m6@U50_b zYR&qTN%OY_J%PKxgX?hT6NpVZ2h;T^s!uRCnf$ND1~_($b8cw{BK9@;Y$K zc%{gv5VCG9P!H(T)2c!JH$P7$2AZ(7G8$HIsks{)p8@rJxRieNXkZ!MsYCcT+_|Z7 ztnJBd76;%?;V_V(S_Cppx7No>>j*73Hnk?{WK?Q3fUBorWq zmcm0%AIT=R!WIfxwxSDfr$^hh7}Z+iaM9DiMc{H z4^bMq+(@x_`J?#78H`>~TL%D!uvyJ-6Pee(Q4Nq^rmk8u7{1d8X}1in(G z6#ggdmYWtMmo;C4bI-Td(KGaYd*|!g{e^Ji$z7_t* z*lYDui2v11p=@{LORikN0*fAb>*i|wipX@gp9iEk1^YhRT7^8*`sLil4V({QaP zv09_yZ{f@yfg!LdxVipfOzo@NH%HpS0}cDDCe9mb9EnLL(mQHI)edisT-!9<6syD1 zT7PM*J{-Yr_OP`AOU@tH_|J`C_dFsx@{>6^e2y9Uj$;FZ{k*MH%b1YHzEuyS%G(RylHkp`9mwWQLO!h<_AT+x&Ilz}M;j~O{ zE+9XIHO0d-QxDrcUuh{jkSmW?7Ja)$_XK*P(ZFTcGl&8|(aR!NL|OtDn`=)l3GBy( z(c$#sOnP=UJ==6y6M`V-QuBc#d_POsd@c}cZH+}*t_w6RBE)lB3ecpNn-*K}UY@Tk z&fsrmA)hQaVP~NYr-o*kfQ*^Kp_Zmnp=ma{6Dj&tWipjqs*E<8 zN@@9vubJ6oIq7}R<(sml`~m_qHo-`SJ&b&%)Ko~8=Sxkq>0&yAf4Njzqh~f>nOR8t zD!Ed2E|;DSqyUdEJG+qXNiHnRBvS`HSadS28hSJ4nk=d^aZ4xx#Eu)x8Zv;4XUIS& zfQsEiN}AZZ2S&Rl_W2Us*qM=?;6yr?B%}#bM^y!|s?fPtnw!m*BqO3z>JAhPNiJqf zDPIDXn)GtEoJbbuO6Dk3VzOMUq{_a;QmUL^oMB~UG*oQ49OfFJCApB8sbqYKg_%q# zdl+9b3rQ4C0J*um7xLZ795AQB$mRwnCu{=(UZsF(QOYDT$%AQ{fpGh#FEKpUGnAO< z>)A6gIk2}cG384v&J-8YISWLlkS}2pB{DfQn9Ao5X4BplQwW$|PIqT>$>NGLVu|kT z9ET{8C@&_KW|J%EOS)89sG6@+10#K7d(a*;&F3pcJf-p#6kAL#_sD~MT7;V-!A2eE z9Z=#KsRBF^Y~6{2zC^MFnp{k4Y$Zzl1H*kl>TC&f?_mEj>(NR1Oa>&N@dU`qIGg6n zFXhsJA-$L`&Vf8vd_*;SPWV9VzEWi-U%)WW>7*6uSC#-IIJ42kRHazT9!e(`E0}LA zx;Rq;BUnn63^s)Yn87CO1G({H9x>-jWLSri3l)rQp%pKlK90@Y;O(*(;UpL~fM)D) zErLYt*m)|M#f3>EDfVSi00&(qIG1I-38Sf@;FKbnv0p^NQfl6Z`1dm7--Z3OlC{7EI7B2pTQKxJixrRost>n!(MmTQ=48Fz-{zE znlPNlbk&oKqmo6i+{0;5D>(`T zQ}Aqnfq|WIdXQZ#RElXcn&{t38obz3&DapI1SSSjPggI#nkvDe^5A;T6y!Krd}K>q zn45<%dZ|NY&?st3E^}%o7IwBIWyTW9#4MHzZ=0I8Cp2BnEF9Df5ZIT-Fz0hZme^7+ z14SASnp4{mpDpDR^O`ZTZE{jVDBKV701%NTC$)ekXE~!w!f@v}BNxHP^Bl60yn?zw zWd{=rNli4Kxud&J0tGvCxw}ignOu3LkVc<%FTjR4tT|~5>sBG1%4V|ZSyK->oyoIZ zmt_-9&HZDTk5E&VF^Hu!hn3thk;ARBC?Ufj%nRQRdeND(Q_z>FNVDGB!D)>Y)?ZBD zxcjgV1XYG)k@j6(NmtV2x_Xmk&CHlz%Hncc?2KKLFCOeCYoRPxn#xb6i-)qP#1vdI zpLo&KcEX)Q&>Lp!UZ+Za)JjLweBGy%kkSfZQujJ@) zg8bfm#>^^~MTFcl**9TRMHa+*v$MrlO3kNdD+}paU8`xrm&-3neHF0(5`9|0XFnu$mP!_mIUy~MDk}X$R z>tktSUTMv}{f8iGLuqY9EKlaRQ$70dk)u6!89h=mxU!YKMJ`N+_9#Zp$)Ff21 zCQPh?uWM|S2VUTuh5!?LDWy(Ac!n5sXlfp^>wJD;*0)ql7KEu(M0UnnV8E+nn`100 z<$UyTLnUsNGw@lP?K^~V@6md>3zu7YF1_TwNI!JtS}GtFXi?q}qo?z|avIV!*J~6r z^WCg00wCmrTzaA8^Sqcs8aBv`MIlhFn0R2Ys74J`y)>@0$mt9whsL5;FM5;Z%8aj+ zJd_q@WBW|*1Ig6jTTcfs+IIo%WI#H5rJg6wpUT`X?gt8`G(V5%%^|&mG@0(AzzM16;ik z{zUl`<4-exTKTh+KbQFiC<7#D8Dgo{YWW99J(htif zM)wZ%h%)4MYEQ0cyCt<7aonBUXuicaxqE!V*WKSW;p-ycS#9!>0)`^x84Lph3IMI* z;ecU=k#IN1fFRb=H8250GpYBo7LA>34oj+_tJ(EdqIF4fUEbrHoa))D%S5{jo*hYb zpa(!A1FB~BDB2mA>;hi+8pBR6d zg@oD1)dW0`G++j$@HLTx%qZYPnwpvbqh~sbp^CcH} zZQP2Xk6APc3KJ*{Ney&?G)G2&6@VV8hIdxyq*_{ZNo8cO5IcT}Z43rs$0+nNS)MUw z@)wC(>*0z5C7^`GHJ=;C>PI6+ZlYYwE{>*`fIg6#7({QVl*$8SR^%m8Rz@P`vJ#+j zDU;PwsI`xXfM!Tqc!LkB-f+J}_)YMLrLQ0=Ho1UaW*~!rt3$#r`DP~48G0vsTQf_# zn>3xUOKK4uNQ^Se@MRi@uubV9MX`f3HrK;Gk%Lv$rx$*`?yp;^86Ov2SaM3`BEiH2 zKj?!|8-r#lnCKbNaz%MIg;YZCr4>tH zWIDlM-W>|*BgSm93`Io4p)2Qzm6O>8Pe-I%f@bNZ^vkr`mCx-dP-zy!`rd(&Nke37 z1_Y8M6+%ZggmzK3Z;)XZdt_C$pG)#E>tt9gKw~iBw->#Ed~e>C(Xj1{4(V74)Um8A0$;9eW6i9=hNkeF=;f!dvcsW z7C3jRc|ib-ut^aiW-XFu0Zhn8UfnABWGlo$1YNRPg4C61S!T-UJCa6V1TY!^W?(pz zRL*aCn1y<4@$WRKKg~O0hvdw|Mn#BMxm3 zTFIq)X7~h1Aa+*@20A9~62qfN zs4_a`WtrAs0R>p)eJHU=yCHIB)9Lg?`o;>_YX2NW%0&z`)6rXklkgP^+B`?lHE$Rd z=0)C6DCP^WEgoWl)Z%OvK2ied!0a+x>zQvI)0XwZSfL+WzdH*_?@+o}0&f$xNcAyW z0wi6j6s+FHB&Y!)F;q$kwt~8LVT(qOgVr42!-wSAY<{ee0F(2)Ne4B?1Qi%C}B2FrGk?^g?>;`3AQ4B#SH41KZrU9 za>Ch=lv${h=83|YahN_q5vyvMUcMdn*e4h^+VefU3N;;SOG0f>fghLjnuaLnyzxWSlSztE@A^k51$!Pjt?vEpVai1 z!s(=Re~GB^QkTfzLWN_MGH8QvgUEfL8M7vHruNIcK!1f@h(XO=%7xGH(LhYt~WA z7qJO zMslCe76xGJPROLs7Hk8vGwFo|_J1tb1s%UI1!IIp$^YM2&pXgdxAOLx+Km3c;LTu0@$wD8b9P)o|JkZ>U4OHFj$qM!eK&*Oz zDToUD6+R#=Pq=5mwi8!1acFy*E@ zYGQ+cyBGUIlNDJ#$V7LGROQy@88Yx7ND4r%5VWy{vzz3DC+5KO+T-TMjAmve=@KNJ zTqU_MEpvDhBn;sW0AajbUZI8J5(FA+386{F44B2{?j=eqGq42kgJrf8UA+Ti5uTk72#k?qGE?Xw!y9fCM3?H;aAF^1$L^dNzwWZXj4S(wMNO2VmVayJFGL zCQEw#F^m!HJI6;*v_qEFgoV1VW;HJVgFph43*|*S^v;;esKN#{Gg6xAr&fiYN_&}n zaSseRAJuPhxVaYhp@xjXNBxJ`jC9GMvV&Bbz~(yeZ1ZhPnX(_%S&o z8v5}dA@Ou|GsEqaklCfosXcyqKbfpB|E;?39i@gKF`oMe* zYaQi=GxEE{Cv5|7!pl*4#8&|3#xkfKJEX{3wTkwpGf8+MjCW~nZ^WZ)35|pFrg1TC zVs}4F*$KTnJGW}3=2y%|vV%e&goznn&h#Jq6?!E>4j4V==74QcMrb+(E1OTJD1r8u zPz+1Au-D0Air?%6Ncf7&-5^Y7G`$~*FcBO@Sg=K$RFN4_va7ggP|L!y1c63?&;pG4 zX4Tb_1U_d=rApe7bh%_=Ds!^TdK4)SpBDBk<}W_M9e+_M5;aLBqV#}smY`|MLMNl2 z;aYl-)GNUabx;Q>qS|UGm1W#+X?N7MG$C;JVMC-7Q?%}>xFpc$i`I=82?rX=v zw~);pByB&^rRG-tuDxCv+8ZfhHGB5PZ$lw=~OB1-WjNMog$w5m_uD+o8 zwCSI2FDq&oELZ4HR|a|?bg)C%lgj7Hn7)F81pG|0@K4Dl7SoF*tX+nLg&AgO&lCB* zkd#q%z@p$gc^E92TKVoA1T3S*i2!Jfr*uWivK6@Zm?3o+6O4r!glZg81Q!w=1}m0@ z3EDAhcSwmmtQ+P*J;6DMTo??~)uN5=IB_L}EP^0jIR3Jy=3&1nAfpI}Mu)_;PK0H= z3u2|%Sqq*ega{IXK)vA30v#a}&Z*51j!fUPdtf{a(nMD{IFuh8Y8DO*%T3e*(=PXk$ z+tI4>L?*SXkd3+|C(@3W;sBUkc?MvoqG)S1C`)ritU>g`@~lF3KCw@FaxA92RslP> z=7%c}YcuvFL!qrm9 z`$hd8@oFjFR7&*Pd^A2WHf|RXQEOzq^Qf&te<^E%r;TTZr+2}r*CBtG&v0<;tR1Cxv7jdev*Qz2x5=K}eZ6~z`w}Bv<4hw0y@sNR za?0$MWYQ@?Si$8URm&;GLI{z`R0`%%QU1on;1tGnPqrGlQH!={ zcCR9BE(z6`B3dSJa6xM-hK^-8Fb^RQik_^8M`}Z@28V!L69YsDErr7biqF7;MxEHv zX7**%3*>nCf)WFcMu2zERP?O7Scr%lL{tD)V0DVRk890n8gT_HEc(O<%(h4$J;MWi zqac%O2Bt8HMt3FX_70&_>eqd;P6Ng`l*IxB3ot8yw7E)gM#uE*;R|kv_(ns;w%PV)&mia#4tBef9j zDs-8W=*P0|vJnxBo$({;#w!c536X%IMYF7u0m@k^IiqAUEh4`;!%#i1S}a{uEiod& z$?67&89jI|5(&*f?hwtwnrCWJX|;V}1pcntw&Cfm>~v`HO*r-n*(h58rvP=x#5Cp( z2qM^yvBr)f&}wW0dd0v(DNe)z+-5qvJIJTLzY2C4e zK0QGPE;&XKwGZ%@*D1}bR-;v1GPV<35}VIiE#9EFuE<46%k1EYz>SYst+WKjJ`4ZU zXmR)ybd`i{T8k!*sz+2qTEkW|un84~gXHiPnaO)5Cb*4eq!c5Jp;eS5QF#=*WTCLI zGLa$kmWjz>(gSXlacyPPI^K+4>x5EQn`^WX#p2aQT7g#RV7(8*%hvlKB%3X1nje!h zR;U};f(Brvd3r0eKhBJhoi?o&dPb{~!)ih;u?(!ku8&nzqf0Df>7uMlvYo?QJ}t9oN=)U!er0#ew5Y{pj&|8e2Se3LIjeOg z2y7>7-eGj|Rd2#2Joch&N^7NFrXs4xc$FY)6%wRcK4WyjM8!jXJy610W8>^>at23g z(OW(PX|BXQm7n7Z0oO~oK45>YV!B}{U4R$qLyIqRS^#x`q#^U!?Mx3kDU-Qtz@FSe zoPU5rhMrAgF4YjY44;Qi2$|-{7#_>1yh^Vu8Egg|4OZt7Yr0|*U~##u_Ce5$M0?On zb&kHM4J0!OJ}vD}3l!0V^HBWGLe31fR{2yA_TPcMXhA^-WK?Wycrj+z7TsvkvO< z0<{JpH#4i3CSd~-z}y-WsAZC_nI2f(f>h6t!OiY|f`CW>G!_aLE;nbwB7uz$!2GoA z`PMz$H9C|S>e~m4*hHWE!L6PxcP}J!2dkQ2rwEg}hsV0zO4ud#HX+t-88e(u?{r@ zXek0LN0x-V-b&ijJJMyuGvlm-HO+Of_k1?xt?K3Zf`xVf`Y3EV71Sn-T`w0}j*vus zEPi$|8FmW-7w!v|VtU|s5)AEnQm`s8Dnqt32EEanRWC^1gBhdnVdpuGZgk(9lO%v0 zSXt(&I=j3=A9V1vrrDmiuy|oqh%t>ziwh=sp8*aH=xm!@tYF@?6S*{PP!7#VdkSHP z9Y?v+v*T0-;bn{~W=s~qIF5B>fIbmgkij?3RK1=U^@3@8Mkn`-kB?1E_4WF2q++OR zS6{*|25x zix-y%a3_P?KfyHG1_86B(Xj-mv~O~f@W4=POpY3%NGgdu1HL!w*mx}5ZVw!!T(*2! z;_4_p)5YD0gzKUKz!2Y6*hLG@0q5$h*q(-w0Nq8FJq4Vs>V_-3hB>uRq@sqIk=6$Q z*b&no<7Z+=sdbr0PXwW>##v7a^UXUvF2EQCL;f?1$N?NuO@LHNBAtV5$>?6b+_x;Z2rg3P z!}6CWyGIKhs24& zj$uRB^h}Oxv!Kuo496ONDQ!v5t=P zo96GxU7D{Tn95R4L}O4S=P9IZx_=D!%XZ4u@cQD(ejLy6t`WIBj6b?*SM!r2I__Bu z*$z)R<^*sV@y6#;uHg^_Vv&*62A`eY5NHt>yk~rf91+H`k24*k3#Vxxx~A3&=wX_e z&m_cR1Jx7yg#Iv&BQeAIq^QZZ%Q7z*hB&(b{N#%aIRgwp>g=J%ucxhPPg`Jp2=b&| z4v1FnH0n8T`aNkdY8LY>oQmWKmOf!*M?^ZpS>PUf((v^3^zWL$d67i#z+__A_(azT zHm9&*tZ}3#aM71aW#)!6Jqri9os5Csote}YFP`Oc`#lT*p|;D>WDO+q!qf^gI<3c* zf>w#-b_-y0pjV_5!vh^qCVPg5Kw62h@u`8aQ4eBbG6}`S&I|@UN4+ggfyIsG=ryRv zeu`wnqnZO_JyaVH(*al9B(>5Fnk8An|s$jt|vT`p< zt4Ts1hw@n}oP_k{P_Lf2=rejQjSlBaC81g~3D`uh^@Qhe@lKP&?;)yUo@s$ABxDr+IR2PBtSBlw`Z3w}+;)$;!-RIyI03 zQQ^dj?593Mzb4tMSClPAqq^}=?NSo=|&hGW>1N3Cj}?EMkldmC;H)G4>45I zOsgzyA@DZH{kw4lkE$x)(>2=DXKMiYmeMRv_09s3GU36*T*{5XGIyI<$;dT6MmCaA zO*ax+bR}i8!@!VMO#RPk&gE1r6sV7t{UX zitOaz0s*N=s_2o)o6yx+jE(n=_9l8JATV3JVstXceUL zhGW}k$nYe%3c*f_z)nb_hEHrcwr)FivW$a7d&IYsS!Ap*DNDNc?g(UbboZ?dMKsjl&zeD z*xTnBMp1WJa)gA1L*~QXkeuO`=#mM)nrW*mGi^$bECBN2F=3?Wtmo=t#bsl-utp$M zs-jP7hy;Z*p?LERo)h%*z(o+7G&-=)~^@haG{0YDUoQu^vkFeQgJ$zrTYtElm~} zq@;{E7RlMkWX9vsPO$@P<(#(V*umjOoSYbzVb#oMa=>FcGGG$nTnw?*S~Wh=otPj* z4+hjABDq-Z1tXireBc4bs_eE|U*S+Mr1RXYSOICOLU}Xeq(yN?m@?#4U57D&Wpg;_ zD~F97g+dfwERuVSdauDU)#?{*{i}jWrl$1V5WqU)CQ<|GRCJcA;$&Yi-c?Z8FdeFz z(1|S+=#TjT5YSVDCM1Ww6=C9fU-de;CS_pES4JIPI;U#SJ|ZfDOoR2P#8v;P5FpI# z9t59THIy>nXV^iEni+QE*@Mt|`87kY*U!QsC?R$rtH8Bmt(l@PRm!mn!@sAl=T-?$&ivmnoV#LXV)TJ_Bjb5V51r1 zp^JS*DAcKWFALRnrS&G2JuimNxscN7*^b4-(Gtc`Z&!;vBC~+7WR2)jg%f*VH44cp z1HfTel!&v{^pY}?kvI|uwT5$EPF5swkPIpe zUs-3)L*10(!nZ7CO-;bd&7z2(CBe*Hc{XdENGy^71qv!|cX~dFa0|tRE>SI_cnj+9 z)rBODt9DgYI;U>Wl!6=S#Au?sZ+F+;0SM5LtA;7)X*gDWbXMzizdAyqeAR>tsc;d8 zg)l~i71F-eB5~OzBI3fpg++W99Hq2c1f9`jBaw~5U2DAg@|HxBM;5vkaLc1`NgRhs z77*`R4q#J=WNWg{#S(>sNt|Aye<$qy4yvISQqAk181t>UWs|2(F)_ilT>Xa?y6cX> z(He^ajv4wdz}SGkKn}{yh25rsX~`IC-HD9O>77!&UlKVY7}*w zbt?tDPNi#+149M9_c#GPwdpc$ZD!o6IunbvB&rjD7)?}$qq#8XjujBX2J)(5B`_?w zSk!%9UBCsv{h~qBRhePb)08iELOSDMa7jWVyl#b6!xD>XxV4Vu{RF^QQJ*0@jHccQ zF+zev4{j4K={y_>8k#oP9Y%DBDM$*Y1<*7s31sk$mF%g^J7f-(bQO!qm9B*a&J5T? zhPp80#I&d7LufxbvI;}OYdNUo8E;KJGhX7-nDaEdl!P*xXP6=yIGp~vBVnU zbso+uoyX#pVg&KJ7DzaPqp#J|R38>MDB5MtQ6k>jCyb0CT=@n>k&4wzxA)!pEa%}SyHC_Y5e)q`&!F;uCYc62m{$pQom7nyq0TrxEUWdbAmiFes{K-9T4 zjidk7^h@euKfGXbKrN{J4ld>WY@kFA11Q%S4~&|rc?Vpl%(!#N#Trq8PI>E3VZE}m zPDU03L`lpuvBH&Biv?41<1;OaLdC&qevkLz_*Olg5jP$!`17gfvV0u)LwHF@?!1^Xm^2TF@Kqy9UCa$xL|q_V$gM z994DemW=I0>YBiJ2i)GSsjh^%Fv6g^Dz9#>f6wr+uAETnr)nX$3TT~S*ae6(vWsAh zAT^m| zqU-ijApp^ddL5E-ma&)*V!o9R=wHH+Hy)} zfzdhjJTv$Zd^%c#ArxynmRAqWYe>j%O1dhIg#Ld0CT0f7Lm=(!m4qH^1ND4y$iyX} zYdD!#Hz-i(7FgP_jNiewtk7I9hj+QRxe?3V0bl6nb5*4j`odgS)A2;wYW@`IaMz453>*$ajmC`j{57= zvi7vEKvS472RB^b(TVo*;1bQ**sl-E%WuXuaRaxl3lW!FgE&~$Q;*m7+@MU5s!{*q_s%&}+ z7`kK*+GP@EFuXb4={dF+w1QnoO))h7x^vnPp2L1MWsCN%Cqy5E3c^FdTQ!??xtaHi z9#%_qb~xZ%NKw#CpNH>sZ(n~GwpYCs%5WGSV2lA1Y#r6*B{HSg(G{+>s#%=qO)$BO10lUMcY0?=mP0744hMCNigY8FN z6IfveruKQb$Usgv3)*)mFJ>_4?T1wBO@IJtI!3_4ZkHiaSx~{)uwh#@qkVbt5$0&h zaIjuDG4Q;*Gmo(aV26wbDrwrRu{gn%E%hUU4iLk|PFsBRsgw!Bc3n^s*7O<^$N{gh z5LpsIOPchx6TL}B53sJ1#lfhjzvErN^%TSbOa0BJ0Wes+on91p0gC-*R(Y>qcM126 zrD;|W13@XgMj-$gIITD})-yKTja_$K*aQs-E>4JjvV^T6I%30Cn=kHOLa0k$Kh}rg zeG>U%nUOEFO`>O2fV+NNe6q0O%fJIEIu2!9%v;_}QkmT428kTU@hOixRY#kb;iduy zu4M$&M$P<+?QgdXUYM?1!HZK8MIu#iQ4KpG*Fa3+8i--KgcVl?O0aOC9Zz#`x?3m@ zWcFs|a<^G&MFRJ^%?*^Qi@439o``SWizVyAEO;OcDGjx6_carJdmRsFjizG0oKHcn z!T`tv1h2jDUIK^+2<{o6fxf=J#O0A#BHEfjsBft$mO#jO^VIA-!RlhlIZfG2h=*>n zBapnOas=QJAZ0-0n!Z3w=!#G?FX?NIw8pM@*h~6a5?8FfrZ0Bc6_;JcYx?Z9e2g>H z2Gj4M%hFAYNMC(@-ygoVZw`zqn<_WWE+vZ@eQh7E=)-MqZK*4+z+HW~o6qFHHYThl zxS{ZmyVNfU&mfJIC}NV>r>Jkeo8`kC$SeYsVDiZ5aTgC0g=8Z10#2x}W*C?ivgM&R zowFwu#R*MMz7cnFt(_;6(7EB_4DWhF6^ZV>K9937XTp^S2Gcp*KTN-(0|RY zV!l#n>J^7Q(E0&hNQ9_bsq}$GIbK>ipj}uGq*9nL%ZcP%GJ!th@NxOTtabA{fSW50 z%%yPV!vm}7rh#*O4^L=-TafQNX*fHDc#afMA^Vw)7Q{$@7(5m#K%rBXwiliuSQqCG zXz*i}!}2Iu$QXZRYeNU~9f#{W08_D;TW6OmBx2f|^u zM9_wFoIGe7p()K~kjYaV33}OGQ)3l4EU2r#+_vaeVpfiI5sL^sr(wT_9} z#gvuwk59o>3NAT_ATj}`-zl9kIn~>{w`&-$>lGwu^jj5g7c9Qw`$kycqUkGR9D37p zJ-Q-jWqlKS`+8eYRT+B?^jRFsC3^Pi&%Ir^{h<#by?B9ytbKHJz&-?aZKWp3pUH@; zAU9jIpQ{}BgOMn?I1VeA{6%;t`P*FGZZoQeQ?Ue4hwxcd!Mei-_#9dXx)NQpyr_U+ z?9Sjosu=a1o}fm!SF<;|*Sri2@(2`EBb~!MXL*bZ*HkZ-6@zGtA7Y-Fc}B;ck8AcJ zB(J7s8K#l0X+0(>fumRM9@8N>x_aeioNjS!$G-gkN7?xRW?9zj{}~LJ@Uo^&oi_E= zrcE6=b=a(_8w?yeb>h&eLxv6=i8^%{>a>~Tk2(#F3T+nFEHo_CS?HOCH9crVSX5+q z!lKhGEbL$hPguX}y6@-vKG%EmdQQJvdG~&v>wACi@BR0=pXdGOe!>f{>|kHw9b~$3 zPD2x_g)2C`{)QiZ!FPNt44F$HhMz5x>bakXmqEppDZx^sQCTqRi( zyh#lAvEa*Bj_+&1drEi-;Y_IGLx#{Zt=@7H-~QcjrT-$88zWaqyzO-XD;U4yGSe#f z0);E$f#}}l>IDp25uz*S^OBhNJy7$kVUrog_}x78Jo<wr{&4Kq;@FI#W8^6ap9_PMNGpD-g=c~+lf$wpSTWE$h5GKlbvu5J6O88`g|3Vk| z$LYy;2giEj{A=(9Stm_)v*cgvc)Y*by;s`5We`)EpYPG;$1i8>Gd}TY`(VW4WA?$3 zs(p@3jxcNRO;+}8dp_pBDZViiCo}v6nEQedd@c~5?L@2NJEgI}`%{uTY2m{$IGibr zUv`iXzu_Pueyu@5C%a)bo!fbAWBtCJUm7^ay_Fd)ho6p_agM!h<^un|6Bdad)4)d_ z+*)--*MbP&M01V%>cXjbU$r}Gd8pt;`1yFdG2V220~#00+f-!n{eu$<)@R6mS7o_o z`ZsXHj@kD0?%!}e{f6tV;U_NmZF$KN_l_R-1$te03jkIgOvbC&Y5bYyf5{hy8=Bz4 zDQDsW?n?K`js+((4pyA8`0{2<2-jOhG)KMi@My0Hmr&`H*m3Y zPA|mk!?9y+7YsEX#SE*%XH{>;*OA`nias&7QT^o$Zs68oI=(4#9$(_cCwi{KvVPUP z=%)GC;Fnhx@Fr?yG@sveEbl4zMeuypaV3m=?WB8>F#I`fIxe;`Au-$CGU!it8WK9y zeZGLj;iWRX*oXZG-j9J+fP`xi)#966p0Y7r*_x-MeyL=nEPn{^Jg(BMND zMRwyia$Cl)MC6FW*D24x;f7D$fEQxsUzZvCSm9A7Clh)F8(yn|?}Vh^q~-p%{$cxa zn4o>71+tftWNO=F$7sNBgW>J2ZcZ}EORnvRa{=U=fe<>{-8E#3$#AX!l-|G7~{1+M~YjOA&>`(IR!3^Ab)Gk0b zV~xjGktLrQkq%0RO+176vrcY|_-37nuaHb;DozUQt*O`*Ux%OOtLI)bUN!J_Sh$aM z)jYO#bQ3xfpEvRca1<|)#AW*5jha(GwSMZHcuhlJ_^)HZtN-yUS9o`4GcW1r$NdJD zD=C_L-L+Hji!$yp{$L8CZNeQy{{E)D>C4^9vX3vi9lV9&8ZkMmWQBxgGBf{OJBeNH z^TW;f?PHXV343M}zVsdw#(mt&eUnK&<{3X|mHpu?yUM*BzmAZ(NIOXG zYiIfWTv68*zQ&6%s$3wMW_4B7$?sd#EoXkejV_HowGeMH>cSRj&Q0zP6+R7moqIE1 zcAeu7IbJlstD}xzD6?;)TFe$^=B&>XQImhUT|WmHcfwWpj0HoU({)|^b``&N`lGm_ zTjalu7K@DSSXWroo4a`|e+@mlDk z@V6BI$o1e>{H-f2xpQpqn8o=^MlYp5(^o;SaC)kD^kOK}3ro%}OhsuNV}2&ag;?&) z_ZBlYy*T{CLL4(6w5fD9v5#qmCFjD2>Q$k1o2ojJa+bjpN`ZEr!I%Omk$G~QQW%7p3uNv?9k zep;P}a^Z`%tQVOnjem881-&SJN@00pVL^P1`Zn0Fc6z2CrxsRzy08ex=!Z7F`{hN- zD`IAwQy&1Ac^}sPu0N=4facph<3FPzOO*EcGGmC$e0z|u6VIm22Gpb?yrk6MT`%7*VOqnn(i!AQ)33+k(`Mr5FhB;guv-}2Vhk~U~&ayFO`DuTE zvvF-ZeG^=;|CzrX`FrtvN?}Rw*u`U(VOuXsmEOm~)V0($xpd=hOT+$mDB{?aWUbSo^vYOik-t1(tTn z)B}g3YW$n(%Q$yD8${|!y$k=sd2VG>&$Vu_>|O}nh$W5Z^@ZrK>At_1ms)=uH|t1V z13n7RG4Ag~ySqB@I1|TX8UB$s!>$F-rxX_3%5zWN72|)zp;H*uO-RRfJ~tjj8GKHE^t~SJ`!sv}S-Zo`%{i&N%O9>k zv+^5Lm_&KRgyK=<``b8QBPmT9yN=V9o_ zxB-6nye#(H3|@xkbxHrbRr0Fwg~fFfd>gTRrjO!ZuCYsf8~iW^D~I;%gEan8-<63! zvkqp>VcMjMd~D{U1k7<^jHg*`TLInXs>Nviu6@JtI6Mx02>Z==o?}h@WYz)+8qe`)R;oe{InpS)zNIVoYow= z^#kqOpdSwZGL{>49-B|i!+8F$JU#Gh>#_N;zSH)pfUl(wY8&rQep4ni_$Ow|yd3M&w>Ssc7QjDALua{6?2CAvZH&)V(`;Qa z8>#o%)Y8a9t*ZF_$5B~q(+ryiS4L*eBOZ5R$?98}IKN>Vki)Ulhe6Q~zbn=6(!2%Z z?SwTo^USp=?W+#-`)$TWt_F8&{`>NhHpOw4OS?hXac)(`JOu8;^Y`iR+sAME(JQj) za$|;m8V<7kz3cx=ZC_yV3_$O3elvR|o*}Q>6rY9D(CDY^;LJYL_KTS{v?8`?fQ=uM zInKG***3bft#5Do+y(m{caGj?9=h>Mo6bWr<=Xtow9yJ^Y#)np1DNA=y59p`5ZCpr z!f1FC=NkQ0A8P*G-lTC8u2eXNskK7mehrr=x^EnHe`e!YH^FT4OY@?p9JbwJ%Q;NH z&4>AYj_v=f?bqP=2yEV`PcwbE;&AK3efJ3TzYDs|6?cA4$7QFE$cxsxGWOleo6Qhx z*p4!HFR(Sr#^Wy7unZfIsdQe{f%*sMBE?VY3MKLAzzjt2hSdSXW+V-I`ih zf_-XH-Gocrqu=MVK9wJ_Yp@*it-i4GI?lJuy5Jkf#@;UEUFPD*T(@Js#OpPVSI2c) zRGt@Y!SnaqN00Jb=;>~1pXDdGmC<;toj=^#Q(stg@%X}mx(VnxJSJrf!LA~^&Z92Q zEY@dbp4Dfb`SS;2lLuCRKx&v&-vvw5_j((hGl&Flv6aAPt@AJ!GtUL8BI{B0-u z{5GFD!5rUph4H-=3@o&7Y6|+2Jw6rpQOuTg{l9E&uB?LJKIb=Up3aeB-)ghl*4BzD zTZi&_uchd$!u-rS-T=+-E4?;DwDwFsjFZKAGZ?wmw+EW-G1=eCVzx4ugE`*n3ccU6 z;g{fI7^4EDRuM0Lku&LMUyqj=Ve(|M$--P3AN8M|&+&#s(o<+WJ?`m4= zV|i{|%Q?$2^Ho9f*Nd6@C40a6WZz2LcG$9A#LqdIb+Fzqh@3yPUH<=JI|N%l*D~vC z;#ck~YQ5PGyAH$y5}zCIgfC_4HYd!!Ahr+v)uI9SAV2R>aGsF!tMj5ZJP+1PoKr6^ zWcyadcI~jM$Max3VnNQF*3Xvb`}8Bn?Ru2AI`$Kk=j^HPgihO<*uLOYFy<{ze7X<2 zq%hs>7V{?e=$3c6qvzX;{+NpJkM$szeH_l-e~oP#^_*K|&$qSO;x4Pni-zDMjNA0> z&==*<({Z^ir{zTp@cc}_ADzQ}=#=;#AlsR-4a0`^@qN2S+OV&!9vF6RT_Nv)Z3DP5 zxbIJ`;&i`<3-dBR^)~2!JSO+#tPCEve9K|S=f?fuMzHxAiTzkT%nl|lHf7Em&#fQG9H;Ky(avL zhr=&o@u8n^&U76TMJrjCWL%&;l_Pr)G zn+?&9Eto=G#~yXoN6OFiaWp-1-y?Iq zoQ5s^HbATK`K>FkIWg&ejYv z6FH54Ytb)Ri@XFt)VqS2r4uy5_nI|mC0l4+gL5DxNZ?@^hr4_dCW8JotM z25*M_3fPxmjODoh=*9$X)|}(_`7ED21fGfK+UJaiTG6@wni}V+tk-Z^KK0emIlj!- zT5!Gdg?hI6dZuIB-OyU`e45U~hQjho3X9!(Mt@D``Pi&as^h$EINs;R%06>vYGL)L zjqZZ|O83~{9+8i04t?%CKQFou&x3Pqr`%4#UL$$^&hmB7%!_vJn{U*7F`i=iU{@BG z*KvWhK~|e(u4#BqWL#@tw+7GSem{S_zpQF?f9obR#ypFMxyCb3OEb>3Xovb-uRWn9 z8gW_f*R%~Uzw#q&399$KfqSW3_vsj79~P%^9dw~zU#0}F$Ehv*zZSNuV2g0v*dh;r z@yGom4};k*GB?h(xxwSK8G#MYp}3y(ukvGac1dB%t<5-%y0Jw&rW*W<_cP6Q-`2DR z&}0nH*L9ONl^6MaO1+$+9j;C|uy_uD_6~|eZVE;SIw!h_Z{^Az9j~A?w)ua4Y74K&-pL=23?tEs}p;o!A z;m*5^sqJE%hhP`Xhnr+ryZxNicZajhy6?nyJd8RocyWp2`u{f%$5A-0Rvv|eNVe`N zr*WLT7jhfo=xztue%T+dGrM@=M*98o-_st*HwfDnO zv>y36_voLzHTK72EJU`oyq4PQJ89TM~rG8D#wLVkthHmG7a&OEWGvq$-3OvXD z)y`eF=$Ofr)9Pag#;cn@^wS2t-ucN|^ZZ^Im*Q650PMJ?2k~C$_RM0p4R&1fg7W6t z{76G%xfQeh`*E_)_0w>N?##ks&OzF2hYc=M_#O%O+BC;0kMF_p(ou{hcrOpnC_i>L zYjNGicl0EEQ{3jqhWRK3FMuA*CERn4&nLLyVNbaZu-s+Hvonu*a=yMcYIE>{iknX)pcBWv%y$g>>f$~+lWD;;dU`>wDxVW0EsHRCtMFaPl32fi#%c{}ct zxOxQbhpYWj*tVhNW?1`KJWccL-e%6ayE&k9gmYl^F<4iw^m7FF;(GJW!URAvtp(cY zU|IW}ALe7q$3M<3V`f&SZocqzpZzcA0Q0UyIn(hx7?bY0A z{f10geqPYl{M6vNwx{K3yDNKtmMfMPROVXP*}6k!8jF9lC*Smc=(j^R`>?L-kiQo? z+m`hqmvq?mpIl4EwY@&+?}N~{`eI#Iz^-&bUetr1%LEm`HRusb$Fjm=AFf(78MpxaXW;}`N3>` zJ+jB5Y4oXe#@2&%&fMc*9krimTQdoDzsBBw%h(3gnA-5q<_vwXT9}-7UEf>&HssCam+PU$hNtms!P#{-A8F`ey~xEM#rqSi+D^>h4t)*$SznWxjMbiPw*vZe@bBN3m3yAhZU}Z;VaI))wngY~2kia~yHjAN z_ej-_ai&hd_50mPoT{@;E1(ad9z(9Y?DZnFZGkOQ6aMKqV%*dgUFYvzyR< zI6sV+2&+BoQF0>oZupCAQBz^jeWTCZlzHF0+NPn`!?p;q{T9x1-E)J<`=-$mG9p!$ zxUPssy9lGGHp8QR-a|~!cU+X=F^+4!74mb(g!3Be#xyz_=l-TM_MD|iA2xsf4Rg(# z&3?R-SAW|39UV<@yftIb*26xy!}3pbY!9Q|E7?XY{{so&*=RTGlS8AU{S$CH->I0S z(a{GJz_ZbA6-*9|j^Y$k^yKJnjc(%TYfEe~Uz?zlX$M6ZlI(dBtMS z{CrP}Pd=W0$xnalg=wFpJXijr3afT1nv;mw@A&rNJ!GH8M%UuW=fNd7WbrS@{bJKu z9`7eB^M0~2?;#sAo&jOz=RIW87vsreV2)I4Pu^2D{cCvgB)DF5-d8sL2YB)hnEN1$ zw;uP7O=o$$$87vMo}3RZ#9u3q_nJ*-yc^F?_)p*`;`_F=|0nn@==b3-`GYW>AK(8q zf4u+flkYFyS2m{qHrN|8KHfhzroLL3I`12sPUbyfW7_xPeyXyqFO0AP61fNl9M!b9 z^@cO-Oz32B2OyeAv2(N@hW`F0! zdRp|aLno_VF8Wi@$*Nb1{ypequIuK%LG*7-#{OOMzXE$pHXmy30Q&b=IrQzKvpvgk zPVnjA=ubK9dA{(;uLrjNMtCO$^EXTWcQUqYeLp{U$EO9ZFL_*;;$-?B(Tj5EKalm| zL(qQ+z63sOy!OfZ!gzKFbG+>qre5Pu7kK8!cdan>UBb*?dV^I8>u-+uiv4NK`QvLH z2ZAd>jL(%PI{noPUy6lz8rarj+Bb{t=8N!o*l1o1R{!0iGkRW}WZx^OM5^%u@NqgUec*xe?{R})# zHr{ti{>Pxd1?GIW@!}Q-m&dnXJ{OCapJsi*E2#54jA-IleaMsP6(P|8?lsfVmH`_*aO|cvcCsyzRo&cM4O_ zk3UCY<1Hmjy+QatQGQ2jl;(`K`9KCD`T0>L_4^C#$y)zv(cgnkHvRiY;(QwTCp-7> zzh7ppOV-ElN&6oH{rg~6(Z+j=#LxP43bQ?WgsE>3roL5}`c}Vf#xp;@wh2?;8*uTV z7Jor>G~y%s`WE>0P1>UpdX2OP{nd*83Fu_*FWLUnz?N)&6!>jC4*T`9QkeCr5~lyA zfE%T}bK#%t&+n;dR*v#og8U1FSzf0w%j*@UzD$^Ufxqm)GvB^N!Y*E6=5H3JzEYU_ z;Wy^tk;(h35pF|$?tdcBU76T^p;hWXA3B-iiS6B$qyGI;UN`iI!7Z@2`ME>%d!WAq zu8DQVw_9|^Up^5JF8O#Xg+Gt{CxR_M?b}4BzXih72ZX7&O8v=;0v;55=3g&N`;EfX zE4i6=$;VqQOnsFw^RE-8zEha`9%1U;nafJ=f0^(A+T$+pPS{y{w{ft#8~eX zyWZvcH4J~`4X|T>Zw7xdSdYlgJ@j8ezdF##rn9^fng8T=8DGCgezMIk>Z{6<{QnJ| zZ1GUf%jtVTqHi2Yo?(cL=k+cM8*gY34HBw_jSAdbu$3R|r#Y3b;$^ zdkEqqHz8oQ??-aP+Z^OyE_`wh`<0@z{I$ZT=dd3Vo%SOE51*K{ZzJ-PyJ5$8TXOi@ zCHdQ-zYQ*hy^Y6$%xw|wr{)eBG}IZ^P0l^-y}Ng)1JAF5|4l3 zDIbcWg80nusykTBbCbLKXak9S1)N%(sc+$H5V z@}{&)-o90M_4Fv34c7i@J2=~Zf$%W=Ujt6V#M+}*bjI5!{4g5sUT{k4*Tv1SOFo{J z!du|~L9oW3AHPr3&W~S^^TAHoe-T^-e~gFar^Nn$picy^h;_E#3ejo*iun5@+T%xH z4q5ZJP4v;Yc6=So`}bD=+LK&!;7BSehEBHgG0W?}2bFheTy!M#Q;xFzso!5UNd9W* zWQ6VJGxIl!-T8@`nI z{{;Mz>tp}4@B3<^&w%b26Ttd+SKu%Dkd^P-zbN3UfYCm2yamxL__t*JQ7P?lIrJ03 z%V1>vF(5koW1a9q*gp$iF80+la>@5cgK!`0XMop0H~(8j=hFkatUbm?UxEDx!JN-# zze?)E_8Shk?{UjNE_x36$u+RE_8bZ9Q>97!{1En*tbKM%e4C)Z1J?R3;ES6s#n)rv z?{_);^@{yl&=-UIkl*UJS9BI#bcFZL^?N^zoBhH4V&5-1+oM^^Cod8{8u=|*{nkkS zlc7HWUJoOSrzLGUe19G!{c|qt4+f`Vd&YZ|=%0lCVbK{+zr;gcFT5m2d>! z_!uc~K^oxF*yvH{*QB%eKfPd|eEeuE!xO|F`1*@6dk-K1%fbg*LwNdeld8 zzYB~aGWp9ypMZ7bXz;nB-yr(I&~F5D3t{E=NPO&{Az`-9u<#`0e-Ydf=cj#H86I33 z8(oHbE0e&s{xW}s=(Mj1cu<)3>xF4weKa0iiu+5L`Zi(a-!AO(bMUz2^VbSfZxv?# zcHvV|-+AC_Tmx8tZaLO_v;9^6aS7Ak<`WX8zn#L=^Q*G;Qeo=lAIsM3g{k)m(|^A( z_1(hM_X<;AP>lzde0$t2hw*(=pp#86 zh5o5PC!2l>^hJSAHl6K%bHEjcnO+c`i~P3)`N^8UQTnd~_GIfn`mdAu#qlvkxEuDC z?0hjSSGrr@sU@EPW!E&z=KPEK5iGLzM3Z+m%N@1{M841dBE2O+#B!%0Y4t_`hYhD9NnB< zzmtR+e~pY^@~y#m{qii=9Z*uy6tq7Xr%$)uoC~&O<8esZqZRt|VD9&9ecmlP+k1~N z%WpWtJo@%*6sEqpE?eIvOnt+YY<;^h^^&RCdRmxzlQ83J7pA^In0kHCo=q~puR;CE zHotqo-NE`mh8rZmUN=kr&%&N;`B{F8=--4+=Kh`QKXshH()fdvik^i|HvJ{ACF`$F zsSoon6K4IE3sWBwroLX7da51|F8Tf|5~kiR%={g~)cb|0uM(!-F%1tc`Tc#z(Mf%O zj{1?)dA>c~0^f%A9SwVHAF|Ky+pAW_|2VuhLgxONuWGTpwbGskK_}-sJry07c`YS* zeXL93n+AO$xE1l(_}?(ym(KkO{WnVab94CHEcVwze-+I5%->eg*3_E{^*zGW z%g@AvOTNDaoplfHvnAnFDonjynEGzvoha`rj0e5`yHdu7Yd^7P{-U$+;F6zD z8>N1HZIi6+(If3~1avanpY#1hJh=no$?VSsFGqWG0kQU`?#uJ*2X*85bQC9BUyCKa zF6ak>2Vi64X@%&l-z`CX9}0MV!0RMG+he^j{S6Dd_6~TJoZml-_{eO3tM6uM&*^A; zvb7KW^+|gsuLURT;U4roKa%dg^>Uxa8w26{cP*%=`_))Vl)SBICPaBFYcO z_n`C#-!HQ`IRB907AX~-hWwVSf4Zf->CkTj*Tcx#d!6WvcfBy<-5^YTqwq}l`!RTp z`0JVpaLKpNB4M77ZwA*wxANDDPX8S;f5^84+!yed170Wo82_*^{cRAYz9-cjw68 zDfTO%Uk~ObDf??R_%U!#%;(_mfY`HrS4)39Lwhin4d!>c*fW2+84oUby^ksogHl5{dm+?&A5%7rcPvMW;ljqOR zBjCFN|77$3SLl{({13|bVEe3-`m+3O0e75|`1?Ejk!`+>%e;3eIlpWV@<$h11irls zgjrs_Fym& z@x@!2WbL_IbbQf5^bWWRRu*siBFhrbFX8K9e=N9D?E6Ij9P}r_?Xk}GStEyPAMo8WzNmLg`#*Jo;e?3wy%<^i4Szf0w^)6xRYlW$=6Q;gXczcfa*)95?p}zy}M?M=b-IoAd^5bK< zF#T^3X8Bu$UHQWMe*o`~LI3r@&ibDWMDo{56K7}ha%taEqo5ZeKS#9r zC)2z6Un%}7VNbU4bt?D+uUQol)aaQy*hw_E#_UTQgf`;`f^ zeJX_6e*L#GdM0nbKHy5RXZ}^f%s(JZeU~ux-NMw1Tk+tMFRw(HdR4&v(tgy3gwI3! zkZW+<+OObnYrleM4s^0#e+#1PbF^o4ds6?~pyz>$;g9Xf_-iGed!g5X)3MHYT12OP zvH0tU{ej?vVteYxiM|H<@!)FF+r-~G=ySofvCi^VicWv4gkOREBVZj58$_r5Mq&CJ z5vIOVn0oPSJhMVe0k5)VqbLFB7J|QkZ(bF!jyC)VB&#kLL1$ z$=5$6Og$~k{1w8~n}n&i2vhG8rrs?~eWftN^Aeo?QQ~#CRl+f}PEe^`gHr8?QHFe&vZy1|s?WM4OE7ufQL<2depdP5d#Q zKMFqyd$N_k4s6Nh-|is(g3Haq_ji#n{g(){JxYbCw+K^T7OcN*qSL-tnD%|b)Yl19 zUm^aem&tngL)4FK>)|WlZ=gMGzqJj#9qpG!KDHk}tMC=k>5q&*NWT4P?=a?_(!P27 zqyNEeSkSFMDkYv`=wyqB{uz(?I~=+t>yII+FYWWMFpGHo5vJZAFi!qypCc7bqJMIp zkMFb`<#h!4JB8Wa>uyJ8mwfq`eLCT@;cpJO7rO0lek(fjyC2e#{3rD!`Kdn;@G*B} z>s=BL>${@eIm3frf2;8RY<~prH$^<;Q8>W+$!$66+b90_n~nWE_-@!+{0Ds|yZn_> zUMKuL2;LmqGoIFYcyP(L&qI=b<*E2S2Jl$u=6{vwx53{dqSN0Nd3|ab^lxLlFd`dY zWFS&1`u>qv?*g6dWay9NsQ=fce0~<@8(>U>One_ihDu3Gc`e-x|qJe;Wg?m-hS%@{{vn$MO4K4u4xE|Ih29=vUwr z>^Z*Zf4k_ezQX*x&hG>JoubozkFHd7xEcw3#ooxBP0e({Qe-GRqES`{(}D5BFz3Ce>mY}iT$wXwBI1i_37oneuwCH;9loD-8e_b{+NHK=#Qejx4>MoEWY}M z0GE7yT7(zO#ODRU{o@k*b)U+%-zCiUY`rC0?-r)M5%Kxt%iAqXz4o?jy-9c&@t+Uo zEnSPhU-ZLpe6{e;VE-6c`=jdiZ2#55zk~g$;8F~6^WXUCZ2M;6?h~SD7MS1pVfMA3 z$+qtiX8qdk%+}k5sdp^S*87F2?-XWz_X<;Awj?|Ma$)K#1FrgbvL1Bc#75Tjs#^42 zXdklbHKL!}gtiFuTG96)KiTr<732NQ!TLn@HNf|OKz}LF$)>YDd*pn2DD3|oI&SM{ z);qG=H(r`>Iqb={zS3X4#CrmCvc*fiLG;t0lT~jN{Q~+I{c`ZDh^KK(5+7OPYm)p| z!=7yZZv}rD`!CPqq9x$NuE<{B$?C6J{H=sNxiim~|5dOhTmSoId^`^QVQ?voYg7xE;F6#JmBQ4Ug_*xqn0kjW^##JzdxWX?3R7PrOnsg34^iJ| zmu2s#2f#l0c-INj-wt8=+bR4@_0P@-X0H3!@1CjjuWjkt&aeX}p?GG-3O8eb8#?NtbzUJq} zjtA3>^=G`Ni=KC26rB<11^2+nrLobn$#}mPxDjma*C;yuH4Bf2zgggNv0o%Q?Yo6P z2>aW>!_q&M_rk~}A8)NN+jo^P{jCwEzDt<;9%1Sg_u;`M?|-JW2krX;t`d9ZZxx=5 z_>Z_Ed;XK1`*?ra9rWiS>CZakC)@gRKG>422Llq%iFMeofU{n2k$75=e=fKgPOQJy zh|c;A3SSNTXTZZ^-|<k9bpfYXwn{?-Vyyg^~=+k~la7p6YI&5BFDy{m%poiF2YJ;n!F z=Tm{`^cPKu(#{>umoIZXfz^I;=wIxAM*o5RG8wPGhEBHq63Z)){NxVdKd}5b+5A}_ z)OVXO+h>O`{p}H^9zDtjrg(e`Q?D0h{w87S&BD}|2~+PAroK{``i5XU9J4qNN16P1 zIxgTEVfyQn{mVOOpXFfRo_>EyrZ?_a$K#D6E79JUfNVcYrpo(whw+UhakBR9mv~v; zT4Bb2y2L}C67ckZ&kFe5fY*tCmNz0y|GR{#r@xK|mwbDb2~+PDX8vAbS07>OgTmCe z2fRw!a}wH%Z1+>o0H1>SFbetDzWlDHMHs)eG1DIze~|q7koFE^UMKpeke{3n1NyrU zY{~j(hs5^~^xuOy#BG1M=o^;9x6d-+Z^HgA@J6w(S)Fa)EX??q3A4TWgsHC(roK{` z`i95w;F6DLM3{Qh$5Z9VX5C#_#pKSVEa5ct% z9#oER+LQ4I$@50Zf5JSBRmtCp{Fbc!c1ip*d>gf$@^O_I_=B9?Zk{;B}~0hnEqOXsSgTMUoT93cfgyay*`inldZkK0zMV( zI|lizy~#i%-`-m!|I@H1FM?|JjZ+i*7on5QKjYafxAD41blUF~X8C1L;=v^!Z;#Zc4CUVu)aNsz(_gvd zr@v*wu0F!l2ZgDx6Q-Vi3J)&%c*=#TR|Y()H5pIT3%+UdXx8Lq6{fyTnEI|~ z@Zgef{ND-2f2-)U-z!Y}{Acmt zl3$;S0><}eq`jVst}XG;_-Ny?II!;!rvF94EPtCY_3gsccL#ic%%9s(KDh{XoG86#VEq;8()ac zZ^t6e^8kEmVmd({^S7EkF5LI5z&u=PF8)l=pThn zRy{f*N~2h$g6QMW$*P|w?az2m7oJZ0INAD9EA4x89X=ldMt8dYVE!FaznRGYdoath z{@N)z?Wc&pPr`mGSjTs>=(j+h73f!rejoI!z_!1p|6NjEKlHc3)e=wHzXM$I{e7SK z`xfj!3qBk=E(Ujs{jliFpOXIi8SE`t`)?5Y zv)l3h5^x`ktbJ=YSPma=voQUy4EQKnuXmt4GW#l5`j|s8 z-bLRZY{}vukn+>e9|h}t-YPoVZ@Vz#*(vP$SD1SK%T}VVe}ORdVqxZABmGT&F5nFT zmq>p0=ON(b$Y<@pN_6^LEzI(VgsHC=roLC0dj2bTaLJ$VD}ixph zR|!*J6L6)B$4c~971*E8{rx;LvLO{j)1a?I|CfVo{E(?~6==yZ9tNendC;E$x4_!k zGyg{}Gakl9H$gvkV={jje@gVF&?kaRC4ZUdv@aK4MStLJV!vB-+UKJ@pTJh0g(Z3RCYAroKX$dcQFBZNk(?gsGQp z!h=gb-q)o4XkRHh?MH;E?-Hh7^b>mU-i~V-dX}?pL482HrUo5`cMBNHb?uBTjc%-;MHrA6q+Q(AZ)?2iODN__32bG$APz8Ut{fV*Y9_Oo&>dH*BA55oRUa65FX zfBmmw^LV~D3O@z=bHGhvze04z(=YrZ*gp(z6Z>7F{|5S0j30!X8DC@|lHZSSllEnQ z3`&3V`{Bqs{>x;4{|ERd+jwC9o#L+!7drJQkM+0lO$H+Q@^_0p^Y0b@FZj1)io&Hw{&&7ey2ll%}r~Mw`ZX9?wuy6jY3kDB9 zo>t)pU_TqI@vIY_{?`jXjsq_Q_NBke_FpFaeb^rj*7HlV==9$r{4B=j#o!hkxAs{r zI_=jA--q@3$-sWE=8xLV+Sp(3r2;Mv zxHRAj;SV96V}tU@THY3^@A0rFXSJ93V|+EjC&T_Y_^ZWnYY#FI$**5q#XrxtP^Y4-TlZ!Dwg81qs9>!NM{fp1aIfna8e0#+o?Hhyq%>hSeCiOWB z@sr!ed4IFu-;%ArWwQRZLq8h47e*Za7*0{a4$Cn%x&iur;8p}^^P}QF6P@<$!b@O3 z54;oQn|=RCw*7!G>$mq$*?P~;gsJEMIboL9B>W|mcRqOQ=%l?SO_=en+>@=32)_z{Z-Oht-#Fucuhwzm$kk zKd|qE{dlqOO~d~4Gde?jyI=wv^>eftcF-h36VH%0$D?8gn|MH9r|mh;VDD*E7&IDdn! zJ&yq&0DBCJ$l7PC*q;KOZ1$&vPlSDWY=18JV(=Krzd_==2s+uu6Wa%MPU8N<}|{{_Q{~ zI~n?G(ANe!*>sjSBK`3u>@8XQZI*awzg3v=Zxj9p^1lvVjpKH{Xx}d{cInS&y~6aj zT$uh=2vc7rOnpF@`miwd4Z_rS3sc`COuc=4c6=Se)XOGh>*d1K>xJpRA>ejl+V2pi z{fIF2O8%ItOTN8o0h`4+l1+VfiTPO6sEo?;BB%V6d#5D2K)6W6&(wHG8kWE zxIyyk@!De(u7N#y6;zwgBjW!o=w!b>`uw{@Z-!2`^@#EAlJR>bbW1jVyMy|y5N7@R zh3Rj#F!eP7Zx*I~dSZ5el?zkv6{f!d;cmqHC>j6Td|6bO?QbC9!GPBbyY>ipx3u31 zlte7H0mEfGdPq zUUk65Gn4jy5A8+X3Ok!W(UGPXL`B?)#L3#bCh)ggnDM0c&yKf5n0l!&<0}hzr^I(O z$|u|Ss?HHlx#Xw+%7AMEZV9+G;I@E!gd1{{zg+YSq2CX->u=Vt<$$C;7C?XGgW2Do z+9x{W?+5=+464#4+iCvksZmeXKmli^N9WAUtv$S{pgsoSi&EhU;WZPheCfCyb`*t zXO#zd=Ko82IEhry=q0L{|4dD!*B*z z_m?B0(|(umH(>uZxCbFve>5MG9Z#q5)3CoDZ1K?F3ejJM@Of~R#JgT}+HVkk6ZS8I zJH@{E(4_o#p}%a1-h`(CY-zQ&wqwr<0KL@Pyd#&g! ze@K|+uf}{=e}luFB3|5pYAm?ZV98EzJ7#1iUQZ<-*LrR+#w*1MZ!i#7FyrQxc|qN|<`5F!e5B z>bnB2z935DFj6YI5#xni39|hPeh(>4mHI8v$z1PEZ#pi~?}1KUj}T4oll)(RPEJey zHKKnRI=M*nA<@4Mos82_#{YWJ2ceTy9~S*Z=wz;s7T=x@-!6X;|oLuY>!RV2LMM?81nxW$Jzdu8kof=(_Ly;$@z=wyqJ{!2uk z44usVf%$I~eF}84>OG>L3!QA`&jo)ss2>^bk$n9+Wxx7q*pq$xj*FIqE!lo`w~S9W zzCV^1o5cImfZGFJ9`KOx7ju-iQ}m~D=zBzGJo(j0JZ#?+f6ADCMz^I!V$M5le3FzYiV;H{qs>}wLH z{bphM+b&GK;k3k_dW$giL1F5{0q+o|efsole-*;iTZHMaO_=&JVd~2R?iZ&0HeuS2 z2vaXQBRifFVd_l*uaNolXY>zQ=j%$*{|TM!U;ps)X`Sc?l;iy)U|p}ah|co23LgS{ zvfA$!{TS$Eo&V*tqBPtf`SQ<~@xk_(DLe`JE!li-k@|lE`o&b+-Y>%+n?=7@Kz=qzu$F#V+)v;9>FQ*RSy{!U@)%Y>=-3I7Q3tPA!Z zWSAlO^=kV!t^9G(uX4n{>_XH1{qX*Po7R{8)5iW=Qo8ShqueiwKkFQUK&w%}jVD9%Vo+i=hzfJf; z*v|#)ex+Y@+7Ad{1N%q8x?XPwty?- z{B|$mCF}XILG;zo$*Q-D{$1!~)t{B|$npAIFkZ--9Qpq((8*4Q{u}6)Y`xeU z)Tic>?D{tdv;N(}Y`;EX>I1^mR|mW{;B~^R-%t=g8E%mLd~B2X^q)EEvtIl$p3TB; zyac>m_`l%q4R9^;*?2C!G`l_0!t}pLnEtzkCme_Gj|CUR{;2ng{vqg#1HDi53h4KO zSH$^QUTJF(kML=*KN4Ik_N}6`{5IipVLunF^Kq5vv>y<@4EB$LtHu9T(P_U;_$JuD z4%Yop+3f82D}?Wd{Uq?9_}?Hp{cjh39QJR34~p%n?-8BtwQEjxdBttnTq;caUSaxM zCQQBK^6dOw!qoQ&GymRz`>sgx(>~pvFzw5QsW;Bc)|-T>*Ib$C&!Rn^59SXUW=N^% zC(yqa=wv6y^Q%|p7yYjh{yp-O{r#13?*7A&=)0hkxnH*TTWuEo@6gF(Mc*p=xZ|;& z2l{r=4~9W@Jiw7Ir488o#*p6zfxaRcf;AmcsczVVDdgzP6+CC-XpZ;ouUHb@AZweT1R!sZy_lxdi`QWYi z!*?Olegpc%r-P%<<%q8(@YgBK^1FqdKVj-SgsGRz&u*U{Ip05s^2vU_`12dyKNP2f zqp#T86lFS#p;m%J?CZv{Lg`CWSiyb*KWr-P$4IqI`f z><6L$7`zT4*!j2m>g;%Wg<0P2fLk(U931^B^BmVL(cAxIeM%Q3{+Pc{n0mjk^B?d) z#^=G&?=#O6|EX)T{Z|Rof4wmMS6`cL-#7^eT{<}0mBW8$VBasi7xv>{^!GowJ{DHs z_mhQLUfD-u_juQK8oDKGpEcr-_Ui)flKjW!$UhX=cV3rWzZEk6>3?OwH78g^2S?R8 z{4WapZ4bCZ@}H3-|IWa^pffwZ0$$9xbZ~TLj{K>>zA4};$v-Pc{^r2G_4=fIj*m8B zwohlkgW~_P9R63_knQga0k0IkHb?%4M87$Q{*vg7_Z8uLa@cPY{fjyDk9H;TJ_h{+ zFwf7N|MXua`uCtu7M<<0qclq650bw>QgB$pKhII#%v+N3-pHX}Df*QYyk|bz{CG)p z#+T@g5g& zeZb8DUmkFe@VhzUTOvB+`+C5e0{)+X54tUhH<|5|(SbSqt-9UxvC)Te=-1wr=q&H1fNvLO`5m&~IWmX8rvm$WS>MZZ z*gqH84~YGVIqbIv_8Z0ij2!lV4(xY}{fr#;Wp^j-aSrNRD(nBu9QIX#eVeSOtvT#3 z3+(&E{>mKoy<*S)St88%_DKF~gZ$KcDxx(0Ao=~^P$s{>-Wm?Lp*7onRgiygz#D`7 zTLa!6@}zA4(LL7QKAwVrD+8_xxFO)KfO~~MlcRn5M87YGUjMo5_!@-2oWs8D5UXE7 z^fYvGGg_Zlndji|py)%;$*LC|n&f{ehyRUo|NbXA^v$Agg-&jh@+*%@{O`z-fAy!w zz?x}7v@6i_GjqqEzs`Zx8krw1Tl~QFFeUapd}zST{|{Ne$X7p+-QKqb+#T?30pA|* z{Q-Y9;8UbMSpLTX{%&C3@$KyRo(}lTwb}aD1O9Eme+ziv$?W{U5BP5Z?+y3^Pi5yH z2L9UGnX9UBLW&uj>4KuQEU1 ztIW^$D)aNY%KW^oGCwb?%+Jdz^YgIE{Jg6&Kkur{&$}w~^QFrCe5f)%AF9mHe=76y zpUV9FrZPXDsm#w`D)aM~%KZGK^0fi;^OCCbdRUp)!^#H;ABFYq)ERgU2L=b=`r}ma zMYsCbpU4g1XD{*BC*%vj`+vY+Z_2N`J^*VyzrTv* zGoE9>&!c?HUkiQ#^(l$%o4~V|CjKu4PrEs(-wohdt8vdFw*L(H`jh?Zf2>a*cpm(> z#QFgE=m&7mA?7E+i|hRR+iCwY_|*d5$@KOACAjf0|NcP6`zP>;;}X3Pd#B&y{%Kom zKN*~k&(B4$uLnf0OfS;Y2=y!nM zYQ;U~SYH7?;>M)B0dRd<;s;ObPR7Rz;H6m4d4HDvUj@&_`(B9VDfG8KmW+>E!KdAid!DiV-QXv1|JvgF26(f~&tKGFu1WpB2c5qc#TA0_z7Fok zev{*Uf80;|Gnl{M#`d88H!#1izbV$oo{ahW<77M?4xYUZ_uQegK9%4}=wHr9@>K90 z`}^OEcl8BdkM*J?);qwHznzSSF7RJ)eRN8!cZ2gK{(HbTf0l3Y^!`5&e*W?#o^ONC zS)2G@559kDGCqDo`x_JeFW_D9@5g^Zl*fS_ry}eZPXxbxc+$R4qCJ0u{>RrOxcZ$5 z{m5CkCmnM$xOFpImt%B%)CRu4Hd$X6foDw5%h*2vetBA6l!iUq=P~d_7$2N(xYexm!ZGag4Zl!`(J{uz(}EoK=^0GRzJId*o(Eozczyo2 z|9Lt1)WM{EZU9eyIvIa=gD-y0e;*qCKMuCU{&@}j`t)Qy|0DR*m=9QDT|DoCPsaJL zFy^s1cP_;G*%Nabd_2}S>yKl>cOV|C&nLi#p}(xXTfi@V(0~4c@mvl*_Nk;ly1=z1 zN&OasAHLqd--h-p!1Eu#e8jjUuL4i|Niv_m2VQ~x%0qk{zgxkR8gb7zj`t7X7jV9? z`iw%L7h^r>i1h=&M_-!6b1e9t*2Lcw@WW^iETOLa3u#}I7Y)Tc2iz$Ae?539+SAti zW#C!0$^PJr;2l-T_!e}Io)oQ&7QPR08CA-p9l&OaH<-`}(LI}?0Y8@@j%_SXttc)9=l z5B=W=KIaUy`DkBW4|q2Eo9i3(KJe#y{QE7)Uje_oG->~5z=wP*IiJ4>o`(6lGS0sl z{LI&q_5Cm4_vR%1Gv?!n57!%hJslSnf%*Fx2-)@j;ou18ORuM*zZATGTN2-c;MZ`!(yyPX=rQmt z%oiJf&wyVTNXG9l__S0q|2Bj9eWB)m8@O%^%4GRy&%c5Bd!(jEpNOL0eLC5X91h<8 zxF2sk-yR1(_Q|Bab>Qn!p3Toz@Z5{>{Y|m|>%m{beyA+w9D1<|*` zlN$Z|Ul`vy@cvj2Z2kQS_zAq8#rB~73-FIImlwo50_N{Ewt+c+_kv%*`Ni6+7$?5T z#Yz22!MDv#+OGkaUaTN8d4{5Gx!OJjZP>G=H_tX~{&v@Zoe z^HS13$Ae$M{)_!heFpe`jCUJ-0{Wl+c7v7&~?SBgx%UASUbTH@lQZVlaw!q*1 zxF2{Q_^s=b{nHn~Td zhk>8Re%!|2vEWC>CF8pu{4DC%8J9O3{4UPtRWbK~PsL#GiTMF=57zrMnCsso;QP-^ z;(HSOD#ior%k~=v&qsZ%{O#bmxIVS{^Cxhz#Jd;F*JJ#69~X_U#rbu=r2P*A-;4cD zQSAR@Fz;WY$=&!q9gOds&aBTDfZxFRbrE#Nb1C@dXOs2oS}^Zl(;w%@ZQw~o$@sbt zJnbrfJ;D5g;EC7x>kslvWZ0)7?|(D+g_o24)?dN={b^sHRP-MB4a_eaPla_@FPf6` z@rS@;5TDhr9Q-=wgYBoP!2{U8alEnpo50Pof4>aO-?!eKM;*Wa1bz$7tUo^ue&*{* ze|!Oao)}c)kVqv|0OVg&pOYQpNckv^Da*In_I#2uSop;1w0D# zm-S&hqo!ay)h6@tF!0?nzdr_k1ntB6vHW`Q+{=^kH52^sf@J^q8SvzDlJ)li@Wf94 zere|aGWgN`lJn2E!0&=PWB)IK$1O?j|NI*K&fH`_`zH8h*jL8({675tQ*8XFqH$O& zuE)Q0te4{XAkNpLz^rc>xUw`EkCVX9V({0-_NRkKWW3_H3!^6%NPWS5(%*Bzhh31g z_X6;nSf86?f46}r%}K^jANXyom$u%00la@b-a{ALKLtJ#>sedOKL^*MJe)?{`1%8w zzjti?_Yd$=>|bp>rr>Kf3a8HYPJ>^@_26YOp8}qX{daN9r-6U}L^3|k0+&nuE(YIU zmGoCT_$>^^bez8v%-1vWz?`qQfbW34#d9zCL7We#$Mz3`??rHJF+T=AAM5{jVjcp| z!}X4}-z(rbh~M_hzX6}PDT>y|_J0Lm-;CpXL&Xo*n+SA**xo-bK`Ie6X-?9XHUbntB_PT(MKig0?*Jcy^}izKhrp*{y{L})Yv9K&N&4>z@N8+1=fNl9{-@=~cPB>& zVts6n^KS>g`55*@G5-bp=mE+4{2sUtb29k; z)06f5OmHX0r|B)=NoY^&-;>c${Qi3kF|=1f)DC^B^v|cjd25sP_a5*RSwB~UkHy6n z_ebpCb>J(yll|#1_=$Uy`$fM5KYM##^mUX+`?tW8uzp)SV;iFA0-P_ft#|rC;7Y0A zN5J<&xA9jEzFF=+Hh}qhc7dzUxablvU*E}(`AYEfEy?`t0l$j<#9&r#VUR&p3NqhbU`V5SR;@E#4#v;CqG}GQC;7J9^diwtw zI~Op^uBy(T&VzIyk%S>gB4G+m7=lz;UFq&5N`_Qdcc%;bQB+kY9Y9ZR-FvF)()ZQ( z+}mBn5apFg0?A0m!4VWmfH=s22#6R%G*JN&F%TyTLi~t`g2Jb0m@#T}e*d-iK6~Hl z>T&A(y6dd7-)pb;Ui;J!0PFmmSB~F+@2*ApvMV-+?@Mim(4>;4`m`^7I|RIzJEd`2g^3iM;v*@Ley;#$H8x z@!RKsAA1irv+wUufZv+z-?xFc+!OKnB=BX(|1n>G>r1oj%eO@P`y$|J=%?k&CxAb6 zTa-6@fggom!g?2g-wFNi_w{SQHzfXe8@TyYcVAHJe-rTGvm*b!4ft04C7Q!eTeEiq zf0O-X8x5bo0etMuaX&r>d??XRUj)7x;UIoe|6d1w2zr_F@IM2;9eTgS!)N2WJb=8E zzajix2z)jCC;hATKLq@9iT-^F@cJJ{eR3V}+u)~jeEkM+FTwW^_zCdyK41Pu;BCJb z?Ss334<+M$82H2J-!Q-51fHg?el(v?0bhLMmTEt~0{k<`Ta};3EWQDJ{^w)=XR{Ia zvfrS@+Ft}b3;hKD>iNJotVVr#HSontkv?t!{u}r`&}SX^^=C)@{|4aCv44TT{yXs9 z5G%iIym#|(2l6xQ$49Y$^!Hf=OWu8m^80@~&hK}Czm|;mF!1owNPk}iUP$))+rXb> zPq+K=o&Y{4*{`*E_6vV$;LFcC!1>)>alYRRe9!kpf8qteKl;|lKih#nli2TvfWLlq zv=8gRA3Hbd<72?L!5=|i+$K1oj}HQm!yjS34*-WB>5nI|?fxN=Uw=pW{U49`JnbO( z_*|5C-w%BFnQ=Zp1pF54v8U3h=;dnQ?-DN!_Q-zV9muyA`tn6!<-42%to>L~d+Zmv zg=)VByu$vCdH7AhS0k?_&sBaWaPgyY|Ly|*S?q_f{*M4ZknG2A0pH1bUgX<94E%+= zqkZr-;QQF$Nnidg;GFq}{vHQbe$*J{;@7heLBH5*VZIjte-QcgJ-+=o@LPsapX~$w z_QTQMzY+KX_$ko$8t~(ZeBTExzbM&{H&On~Pi>)h@!NO)^}hn&jX!$3AMa;@YwUj* z{~=($**&K93cp_i-U5Gz^*;{$1Tr|t&-3Ppue>-L6Mjt|0bktOlD*FNe>w1T>(PID z3Gki&IqK6Rz-NNbYkd7K@H=me_Wm1yU;pMT8}sG=MdkaEAs+sD;0w^tL0zC4ci2(bQskuak9ehc_M*8f~z|L=i!{Bq=v(`b7S@^jIbzYauwBf;-; zDF5#1$`$7CND}{eA@Kd@NB;hgz~M*u?*MPv8|nYez^?;;uVX@*&wm5H^cSN2{tLj$ zS5g16r#}RIe=W}Mw}3yK*pm+fpZ#lbz89a1f0oSmFDTdFvw=+LZ)^5l;2**sX4!_X zr-8VeCbwjN&Vb^Vi-33B746S);G55m^6?trs}uk0<-oi5;Q#sc)PV23h0cN1UkUsW z{2s=;3HTW8ukqu*19+D8?Dp_`fp3PNw0^b!2yhqu805o)z<0i%GeTef$G{IFAA`L5 zHn8#oUqHF=_piV;?5p#9{qylH!;ki78u)hjmFZHSzuyR4pnn3ruK<4+`Tq&Op4S3j zK>Q%^&uzdL-x&Aj9l+sdjEDCFKLPy*{q}L-pJF}FrcCSm1K>;Vi}L&%z`AdG3FVsq zKLP9S7lr+MI)thF_@YmhU&Og12b^8AWsLt>16U_^awPHJo(22_b5=FgzYMsz zGSbrz1E2Y;;LNY*rNE#31TiLG|3=_1VK1EF%U=V0_?&3Z-46UH$||h)J-}~E_~9eK zPafG)`D^#9J@FYx&gS!J;4ghY`1Snt5b&++hknjuzF!5tm-9Y`wEBMwd_VDjrfBd# z0*}F8W5A-%v#v|+sdKYu0oM*8-+lit0Df#&{j%Mce--##=qrr>P2fG)f6w&gPXZUT5BqTmB=N;W-aX@b=sS`3&jY^r zShPo`fZNEsz`y%}zk~f5#;*aNeIqi&kJkr&2z-R`UJHEnd0Vp2`|_U#zG0rumweEmNL{%i326c0ZJ{2=k9(>(l_z&9WRg1mSf_{pU$ z_V;+TKW84vvX^0>pW*9Y1pLGuQJ+o#A4Wdh>dUVN9#7=kOMx$BJpsRmf%W|y^(T6( z1K;^ekzbAjZ+j)*X!HHu0er_&lsE4I=5Kh634fxmdx4doE&7(c`XumoX@7}t|3|>D zdr_qCKLfrRe|^lCKMs7y`=UO-0RQ#gmqz$9;E%DMupd_d?|545e+Kx)(1%;k*6cdq z+b9qCXanE*ib#)d0-i-jhW+{}VC8qa_Wb=4;M<=Y`};Lu<&%c;-v-v-2Mpsq3Vbg9 zrT9(z^^d@ByApdD8$$5;jD2n*k1qjM{&i?S3H%T5ckPA0UBKV@-AE6w0=@l*p9H?_T=#uo&F^90n~%ox%3o*i9-+PHS>@lL{1^8{|8485SPwEP%;zs) ztQPd*=D#(2F6BFrZxg=#3xV~$4bWr!HVyoVgn#CM5By4`$EQ!j|BO$!HhztA-Jf^+ zcUCq8{_rQW>;YfS*+casdGzbRPqIIu{iDFT&ld3cE#M1Z67xBq1Rk{AiHzX*KuFGTtC8^Bv$7vm{k0KVXi7{B=%@aO11(8vD)z6|~h^7nM;BR#); zD)7IaUOSbIG>%jjD{tfFp27K{dk^bKZyr&Jm zJb(NQ@ZVk(>E*q^U)>($0e>F}csiN?eZX(0zia$>4+9S&w!mLs20pV7|N8Q80FNd5 z@p0f;{Nd;N^3$=+-vxbP@)-V~0sL4O8S3YEDexojj{g2mVEujDt<=~4y%hM~Uy1U! z0KSmT6n%&wMn}!#jX=e}*ly{yqSFM?L0SJP7<4{JP)w_j|x! z$36)3^f$oG-BEr#?MC|6LD!G4fdZrTKP&WBlseYzTaS z_LunbHv?au;Paip_p+WK?|&8ej#ota`)S|{uou6Px&FTZd~Kq?{~UN5^ccqf4)D!8 zqW*s05qN1V>eqjzd_sEcp&!wcHrl|GV=2WfNx^I zR(<@Ov+_H{55d+8ROxffe-v%wD&Jqg8u(7+5hD_M@3Q!Sj~qBde@I?v|0U}`PJAHj|INTpoF3`xcHsYs z|N1OH-aWuyx-06}dx6jUzNk+=4}353B+%QJfunr=o^1GH>~Zu%kXL_3`KOch{R{9n z-x%fdISp`;*r#K_=Ry->em;}HkNpTf&uMLTzUXTi_n(vV{b4Hm_OAsVtY%}vhwS0IfptGJ@XH5*?@HGDo4|A6Q~N7?J`DUZ)_;bd-=6}{ z!e4Q2bv^Jm z_r!QZ8~B<;UcCkQ2{z}gzQ1<^FEC&6pYZh&;3t1M?(gpae+C(Ji7)>$@R`_`&-d^X ztmm9$J%6e8S492$(bL)Mi=uveobqoHZ=Uq+PeXBj68Rp+e>U**ptmsIB=DDRjP}GH z;BLb2i)w#$qar@hs;#450ZO2Yz`G&$Djy<6uYm73Bjy)n<)GFd410OKzU}h0HGWO)x{lDH+fetJJm!Q?b<@GIXS;J)9noU-PU4l zsa5RZaXs@zi>EBwcIsB!PSNV%u+?HDaHQ_7y??d_dS33=+Qr^(zg-(-t>#i*8*dlw z`f7ioo8`5lw$#jrtw!^ByW8Lm71-7(wjpmEZ#VKmt8{N^Ru1~Dq664#)dtISNUh~s zqsW$OgLbzwUKX9Q+vla*v|+!T*>_}rzP#2csoEbj+eLr8 z)~~NtP+o6!>qql)FkJHGIop`8cDqM2wj^&f%U*3zUsWHO)eY@eiUAZe>@$tvfoM!eZduh|`6t+hg1 z!PK;Ry=KQ#Yo-Gy#u7Or2M**9Udm2U6W!~*%bj*VD zWr!#%*E@q%#;Mm@xgkr{)UzMRF9?Lz#*Yn)VWFk0<$`mAxdK-d=uTbr`bDqC0+A#+JJIPBtxVf_yw)1Bx}wu)c2@Ep(=P^A&|P{p636N% zkFGkngMj+ALEb%H^p{)R6JR|8w%hd@i)G^FV1lWY0}$0?3;ftnN>S@)CTH4BiMV>v zJf2KJSYhhqRa^=2uQm<=b}T+qDg@sNUOHWbbFw+6U?&OC8O&Yb%9{=x5uG?b%X%o>Ms@ zsp!L*+NjOu(O+ht20P;Dn%Kw-O-CcmOUd{DG|rz$(%g~-~+2AW^d zslzd>uU&)e;0a{%3f3!p+scdMek$P7^NL$x-Wx8pn&m2asNKGVBn(y;rDlVA&k4Ki zXi@a?TB~^+i5c`ND{ACj5QUsT-)1NJ(0IPIK9GnS^fmsVn`>%_Ie`-X>N=<2jY7$) z1%ae`6IblGe48ySZ*+5HJ~r+Obo&;}&K>vhgn z4eUSAS?jUu`ei~JE@0CPgz!ov0>s%(-l9%dioA`*)f{>6glWHN+QQmP)Vh}WDmsJR z^{=VaYQE;=uFE2n)cXC}x^FzeJO&fnHa1SHm`W8FwVMsAHxA72QFu@)DL=xemnN-C-Y@#H1udd{tiekmkk2&K*}>p0&}4h(Q5UZrtvY>T6*C)Gu?) zp{44-P2W44Vzfn4adfxFnZx*rqSYEd3Ym1q>*#I9)0^DhzZj;pTp7%>%BGg%{>&;X5q@M5iA6pf-0wT|x~^zE9Vt6NpqjbaHqANCIl z9QzULw+|K65Q^cgZ)uCFUiR9x@@QqtGZQD*##^Hj$y?H{5OVJn)#&{-nawhNF@fbW z1T%AD$JF-Av)-W317DG#NN=vft?C@bf2s|{V(Lro4UkCR3O$Gp9b(jWmiprZ32JJi zw%Yk}zuQIzHi|WDP5yT;juz`FsG4euNJL*_v?f(sEg9xkDn&qPV)ah4&CQinEQ4IN zG%3fEj$!4Eu{-Tr@8o(Xzlq$esn{xVChFz$u=G92TCqYR2E%ss=v@@8yBE;Sv?4n> zt44?wIW1%SU{%T~0Fd#r(veX+TxJh4b4#kKLN&mK#ieh24gBSkE2S?->SgU(9SfSV zAV((UJOx(CyH2-s?zc0-DP3+Bt%giCHA5tIax|iO=>74kQXK(>m1VE9RW`(%cxuup zJ6^g$D+r}ET%b-5%WL2^P`$5}&|7Z@X#-?q4a1 zA^OA^z#_q0+rFKf(Dkxij)jOdt!i>xhxmA2fnYVu##FclH_DN% zZA&)5ckFfwbo8KRP9#`e8ii6K9H|y*%uT{zPX|@m5^`OkfTT)Q#&X!4iJjY~wnqw% zL{_nb&1nR3UAUe%DG+HSwu(kT9+Ys9kkhP}_@eAOfH|1jxotOr0mvPUE%-)9n8Rm9AtEaN*S^< z?OuJyLO({fTA$pRi;*lM(!-MS?Q&0)BU37~_BwpLlJKM2I`l(o)tp5A<{Co+l7i@K z&C6mhBJp-@E!52hgO&>cpsXr352IVFW@ou8C&sJ>y2HEaq42wnW?eprH=H~X809*H zb$d{zLCaVlLFTB(ac!IT2}K)BTU=mbe}jh7K(2Pxfp<7|%ENI*k-ji-c0vNf9y85b zwRQfluO2OjZJ9KNTxXZ#sJgIDMhnU2yk9?_ci{PESsD&|cylTQzv|E)JpBNSH%g6z z0B?(U^x&z5r|^alM$evogK^|Gjc7{5$f<==5=Dv$@sqw4wTD)HWPs$KH=hjb8~>d2 zCgq`16sqTuq7mecH|uS~U{PP~qV#*Mb??La7iQ7;SA#a5lUrd@J@^}mY8h!8EQq8@ zc;&>Ohm!VSg7B%^hVf2AnD5AQK{8ekl@UU@{HGkn+|2^eU0znyLMSb@2QvI%2f{V@ zH`*g?97nyVY_z7z(VzS;M5kySeJ5<{O+;cSx3Pwe-ne5B#_adZI3pUC+a6l5jqs~l z1UyPsL6ByZc!CO~VjN8X0rae(iRlgPRa?d|Z>H;@DYgKB407T?Eb&7s|2?HZ%Hz%)v&kC>9Y#mT?{m&s(- zp(`nH0*A^9R4B$#ysJH^6=ooz~ zk`zYFHIUWODNYb~v2Z#bdaac?9NIgp6kZHF&AI}ssytF4#Gmv+J38_bYP2}+$V;iA z!XFoeakQr+m7-daI}@rQp_eQSW-m_^OL*q(E(;3rC&G?7jE(R`AG6gulQA3IPEE`i zRoo2K!s$r>BRQ2d#p7HvMaZB@ua4`qh1wDz+Hj}UB-ZSeTW0XUQTd~X z8g!7WgQ`an9{bkp9mh^dBEUwG6i7Rc77!m`FGk?y6L9a1hHrqXObBm6-1t^XoB50*R8j2+uPYMuWGlo4?{TLK&O-!m4}cQd?at9I>I7I?ka9kW&O3sL>XXy9HF6t(PtwUd!y+O+lNl z!^g64ZH1X} zJZKK^1W#IKf(JkUI{dG0T#&#_D&Ym|$?O{EZCRH~T_Q;Bv`~s9UB=XgW$fVVh}cS! zWo4`=|JFfnk`?IptLz_V;s|*me*^&>esdg=a*_{iq?6dbZ5zia>*nZ>zQ5dci2`sB zZlfa(9dVDKwb88$^{&33-{q52*}?Ao;-Lk^(*kEfy;c0XIjpq)fV78^cZokrAaIWz z$qBL3T$-Q*jIP8UJzklo1%3O{3NNA6Svg1$-*86%K zl@b-mOrz{2;+PQ#s+V&`-v(Q3aw=_4b1oAkj_%%S3!DoQ%wPZBv8!*JlO3?&92H-j z&cweOo$XmUR5rg?X$CW^M`zlNS&m(hXT0(aXTl*Oukcrg#k`Kb z+5KW>N!9ADqw~eFY3x);Pd%-7>aGNx(OREho)JmQ`%&rYiRQi&R*ejtvaKf_)7AQo zIhdF6^~O%;{By|xetmVi)0oFUB=j{meF#&f-y~s$nmS`=be;e2U76{&+eAwAez|NP zIkYh2Q0L%jLjT8$>J1Z_=@pYRY|=_Gx4Q0IEfi!(Rh8(bs!+W=Q9D`;dzNVwj3`D> zZUa;HjI~qU^@p9^P1N>amPlly$u9aep%dqsF?vJ2lOth>1Cg^Goy#0=4s1G>V{oXq zoA{bTDD4dIu91c)13LY3jC?&_>CeE!J-;>&RST)N8@oM!h^tg9@XJ9wF+W+~vqPWi z;B(i9&Mb*?Gb5vpvZDAH=9}rS_Xb@A&74${ zqJmC%QgoP%xeAz@J(xagS{d)eQTpx5bZ9W!omnQ2%pEMwH9O2f&I(?~wIn(@$Vot6 z?V~lnD&1p%dW^!6iO48iHyyB-kRw5e9`tJmxBFl?kG|?4~tQ3{*4V zt$1?Z-mF{J31!!aWh%8W8A`O(Tw*_p`5CG*GCYI;a_>afq!seEStDGwY=0X z!@?8*RMYK~!q-V&JD;mlYXy;}w7}TPHhT1pg0Op(0N7i%iuiTLwtMFfRT``sHD9U` z8U~>oy47JNiF;s-(|ngcGL;T17r!jy4kRrdBj3EXSeaLBuma?Vr{@=0xPDc1 zVtF2W(JCeJ{N3HKZhWL#gFY(Q>YemraZTBmdzFUi4l8zZROS}2&AN#2R0U7Xqj`1_ z$F!Wy%ZXSc=3GyE92FgPMcb39nynF%Id@pH-W;Z~&*qe~IKSq|B=VEqE}ryOVcq>M zm8MrC%Vm90Hdo(Pvdi*a-18y{cI9ff)lf*ix2s9$evnjh&#_WiR6Uz}*>s@&3eEM^ zCX}|UaDln?eNOy&p6v{FkLJi?W-oWlJK_kp@lo zo9*dk{H7VE%DBbgdec68IZ0et9S(Mrn&2wq?I|sh1E9Q4h9{4;A%XezvZ+YbN`9zM zY6y;4eyAs{uQ&FfS6!8Hl-0uApmL|y>2h8!NHGDTNjkJHm-}_ zv=h?sjqXawhHNZVkKlyv6xj-ebWxSE595RG$_g258&kW`a}q9a9U(~Eiqu@sv2}5M zaG@a-NP#KH+r<0OBl!UQuYd@@kS2fXZrGalJR>e*}_RQQfUg5508` ze1~cdr1+S7Vk3AkR0K41sH;MmZ2WeTD9M%Ooz@pnAj@TZutw+(E0i*SsO~~Jp^|ex z@Cfzb{7Q2oavI=rBT=gdcaB}hl_OQ9qdjl*v3L5&PVi^v>AVxpY~~iGDs!?YRur^R z&`NTeBSUwhm85qFnR(0@Gq!cGv#Nc5hRZXxR83iDWj@tj>Os%!A*bH@l^r}Zf9ODt zYS`WF_Ls<{S-@yoBvw2yUqyxR9X=ykX$Mz@W zc2;LmICk9pw-s!}GA}r+vU-*XnB?qPUD?dl9QU1of3GbD)7W*OufI`T*(`}^)G%-i zaf$}IL<_GQ6_w8|UX6Uy@qug&^ci+WH428uVAVvMv9ekWJEB`?+g^vw+g-@Q+5C#U#mb6oh$#?$kt-qBC0%VM}9RuV2hs;()D#$qKjbC(ze& zL&#wh;*=|?Bl3__Psj}0G9(1CaU!j_=&&WmT1NIR@k!z=LtrE(j z5SC-sA8Uk6v35{7%JS8kp>dNcJ|jUn$m9;Ih@)n-qI~?YQO)H*PPWBq5JEVr>ZxDH zTW+_S!~~5Yg@H|MSkvgcS{y{kh4x1a*tR+r_0&Iu)|^Fa<}jI__tx4?oi16vdLl=* znH&idCUDkdpOoMtHc=dyxw)il!V^XA#GXxDu`!)jw3O}Y-wQTz!;wbFa^T3p>T!}~ z^G26;L&kxqLIfci4WR(HoVa-$F_5mtVZJhKY-CQ_3^875WIkLR_Ed{u2^?MNq&%dZ z=)9*fQsv8`%ejkWO~s?=lf(kUPfnY!}ji>dP*JL?#kkk>~%O=psBxraPNMuMtlJp0UcPdqh8ZliHL<~xRSyXNTfiLg=Ic|?mf$2HI zhL}Jr2o!L}$y!N_Z)8Z9mSXk__MvPu$6&^G*g3p36kj{HI60k9?_Z2a)@*B?bvqRn z35%!nE;#@;RGKWXeC53CuUZvTo~zy7CWN}lm8yhLjRc$xA!|O!m$}27mDi9c&hT@a zwwY8XxWMfc6DLwxn)ZsB<6x^-YxWb$fP}r&kV9ved5nsT8?2#rt2!$8bU2wWdO9TI zak#RNaF?b18qz&O*|1(Rk%k^*lRxM@*_z8I^Bvo+BIiq(bhIb8&WQ;$POl5Y3Q1l) zMadM7iqe$DR0SuAnjsU@j<(YJ^t%kvt(p=tnvdsGLCRG|4uLic0D>{7)N#EOqy-a# zJQ4amhlo8SyPW|Zn2_OQ=!;Q^TsdaxuO(WQz4JQCsV0BM=jNVr)QBQ;IVC4)9TKa! z4Oel6QNHm>!b`a4C||kz$xE}8XKJJodK+Pjy_z=4L>#2l4UZrl zbyZVS3K&T{QB#j;5VU=?TYhcy^)#fAHk(2d4qMX?kB} z0h__&SQsLo4_;VMQ^CmeX1p#F@0cQA6<@JdKQ<)pZF@&jk`!Jz+5vY5YHLDVObc*a z9pVR7+Fy1&WWa+y;iStT3}7q;bvI zR5o5R@l8xk%T=(-M$4R+TheN^cWx^U#VH>0eCVzwH=5g7qkbG!sv7WqSE(Ne+4cilv=wGHiBtJ24qRtua)foc)qH-mXu~sEUYoH9Ivf ze`_XUBhOo=HJ$iS=){>I`d?8sGiQpmUem>FH*zYf%PXB)1CktF3w(LbmQH*yG zQgzOL#LP(+0+x+J1PU)mKkBf#%3uo-FHT0lTV+6->uF;JvJefCW$q0?sWli$;bo}= zchS?*1#JIK`LldOiwr$8@*EK;)@8S#+1N%|(cm1Oh{Cd)#2*5arQrw1Z;0C&VwyTo zaUE6GRz($IQ?QbepJ0QSIcub*s<_YAZ=@CSS3t=MRW+ru3Zw<65R?Hm0#u zwNWl=XBfsrN%fkvmcNdmHQ6C=)N#)8qRt}WxRTTTZf8HPreaEo%@@o=f1NQ(MJUIz zd*l*h{1x8LUJy3^tspf=Qri+sm2(V|Xe@rp1A-?=T20QhgV*#YYOSN@XYF3^5FfDQ zXcFoKOBbKgs~`58n+3XH@I5}rrQ?jsYt+>x3%gcy<^)OD zOtalh;whL>Iq@!@bh3r)O=otTJtDwwy(+)i5S(%Z-#~B?x_Mo#)}hR#4-U(Kak7I7 zIIN?m;P_;_pd*Dv6BY<0uBbKH^_nm^JYESHc|*}v71P_A6pb>{4_TZw4g&CpnL(2mO&L>oOkC`jse^?;lv&l z`Fl!dB+F%VSL2KzP26Fkpq}9)nBP;7X#vNm-rTB0CDIA3`;W}n_Ic;PM6w^{188Pnqu@Wn|3ui%ywl%0S@~Xl@xw*K*-I1pNkLMD8=8K$d&0~ z6cU6(wGU1Tg)BsqoZ*tLrfd#GyttLf4uTz(4Puy5Fl=>1wMaVnK$CMEPmM(s3%;^f z4uLkDCCWfhn|*9cl;$jM%hSmhhyBi>&JpqxqT#1Jc$;+akzq84jUU!sw}5Ow2x#sWD|4gxN*mft*c-` zV4(%eWsJD=R+gr*5vL=)yZCe>H8{R8e#e`F_eMWZmN>aWVKCpr8P`VsO77t}-j)@j zL_CDQjs|q=0RPSWV@nOtQ^amG7(ZDZb_FnqB2yay#B#JQ8AT%`#tO1jvUnD%qHraym1V zs0?)OM_-T|w=gJr*I~gb?})?9Qb?BxHlCHM8GDW|iV#Ub6Q@uswB0O4D?Hq4B$q z4kwZ2Do2Feh{*WCNcAg%N@sdQ(x{K6egFcMEuC)3lsTn1O=Bcb5ZOc_$vH)nHYMmS zQtO=FvS1E+Y(u&UoFPMT#FQld2_j<_P{qRDqLI6%Tn~mxd_SF`di8GDgrM}fPB$?$ zV7y@$D1#MP1}}fs)@GNkq1q%Rcfd)cK67`QQ`~!5J8JxJ=w*RYp{{a?D-U3_u2h!3 zn-;jv!T>}VojYP@6D&n>7y{<-u4fg=Nh~dW!%O~@nVRfRxL^{ph5A8NnCgevAS4ch z6l%cc9+9)wu@RizLy*lF$i$t>*=KC*1QV*@Bcw`4N=3JH06i0!G6f372YK&|q3Od% z7H(LW-Rp8s-Q5a;X|_#TL!hM)cyXT$t6m%9W3bv3Wr-$g&6y}nz>^f-`r(*77&>-| zY2J3%OYsoj(P{Hp9DM`DGpv*OpnAbah!B%0gM{v!-1gli)Y<6E(J&lYq%_qAthUow zTE{%#&h{w&1ATb;egG45VR3rqWec;f*i)T$D8s?!H=3d}wzDTiVwxe8>9rOCe6NHY zDTj%>0EM5pyd+;}O0HxGC);-;YzoQ`^hf##f1ltN^4A^fhSW2$ zyM@wC4=nmKK?@W+nYtjuT?YGZ`wr{K;Mxbfc;@fWC`Z*vTjq^w6bkt&1)l^m9qprx z(mN(Krp(BODaop>zHJcLQhNcapmLujl>{#NrnA%7s^qO93{;QpQCoU}4{dMqUF;2h ztl!ThGfG0GifPE?aG7e%rXe%Ji#<5`z|g*{R3(34n&|KeU(vZ9j%2-c<{81gqw!1? zoecJ^`w~o*z--#kU#mPqKzZ6?N=dLY3em(aYK{arob4Xa6J)egE_@qD7tTk*yv}Si z_yx1d)tdMZSGh&NwnJr2CD2-KGRd9ad8v3zcO%m=eCEp}INBup zKH*q|ZrQWSo_DbpPq6MdmnlmR25-yq9)scOk3tDT994Q%z)0X3aw3?DeTCXgmYD93 zbEC@A>awg&U>fO2qz4rm#BZwbof4`>s?N=-3nn3w!u@j*wVgm}tNQ`w#UNEr1W{G#V|ngy(~$JARG+y9qgn((5;?`LB%7I;L?jYv9d<}x zPV)KN6;8U%5*Jo_)SdO2@=r}KGm353169OSmXKp-_Z4L+GicD`aaB4Sk$L82DRs;p zBr(NuCMd!#mU!?dCnFAlljddtRV?O?A!MTG#}Tg*(NG|XA4npz%G3Fe7~HmMMR*s{OI#k zS|Iwo$rTT|Uo1zdh9|nChWv>B3qpi$TXPEYv zPvZ6E$XChtqGGtQiiTMf&ZRPwND+07+YzDL6iO8-tKtT3Wno3;1Ntz8Io>`RYT*Q{0M@8XpbUn4RT=vjH>e$mPvSgjTvQ>}#Ts z{a%KoTQfj$ltxvkJf~{)8Us1CF~{99TD+N~4xI2z4{hcUity>8?gCpU;z2!lS0H|W zFpQCV3qj0uuV8ew| z{PCMmwu!wS+HLyhZ+yGWE*xbO`sP74(eFwx(~JH;&g?j{#jwpLrsoe#Sf*VzVVR>7 z8;RpHSL-SEel{y%iUaodM#{G}+Jd`Cs+;(_7i(v$L_uXP;?* zpUevRFVx$`bEtO>^{zQZy&p^JWfx{+*@c_;_nM^MdDJ`a6!m`E*Lw=Tud#ppJxBgV zSNJ*4Kl~iO^;YZE-{8CT&8KB=;cvZ#pRkVi@*=EbjB&>T9-{ixon{M-fW zQUCsge~j7Vm;Joj{Tia$)fe|eU$?tVhO{|y+PRq~;2XJzyJed_QN z%Ff^+JgaQWZD(Z<{b{Hb%lNZ+BlSMNvNij)r=MK!xf|-;dSYw#RS~)W31huzL%r3X z-;#-`G3%soB_fv+N??KZQRKsQyIzBHgsV{ii)GJ8hMh{wMVJe*p{a3ex}p From 537f9a5baf4077d9e764d5436792df5e4424e7be Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Thu, 26 Jul 2018 16:39:37 +0200 Subject: [PATCH 311/485] Minor fixes --- arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds | 4 ---- arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds | 4 ---- .../simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c | 2 +- .../cc26xx/cc26xx-web-demo/cc26xx-web-demo.h | 8 ++++---- .../simplelink/cc13xx-cc26xx/web-demo/web-demo.c | 8 ++++---- 5 files changed, 9 insertions(+), 17 deletions(-) diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds index 4d71d6b45..83e834f13 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds +++ b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds @@ -29,10 +29,6 @@ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* - * ======== CC1310_LAUNCHXL_NoRTOS.lds ======== - * Default Linker script for the Texas Instruments CC1310 - */ MIN_STACKSIZE = 0x800; /* 2048 bytes */ HEAPSIZE = 0x100; /* 256 bytes */ diff --git a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds index d8699f651..2c663d6b2 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds +++ b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds @@ -29,10 +29,6 @@ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* - * ======== CC26X2R1_LAUNCHXL_NoRTOS.lds ======== - * Default Linker script for the Texas Instruments CC1352 - */ MIN_STACKSIZE = 0x800; /* 2048 bytes */ HEAPSIZE = 0x100; /* 256 bytes */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c index 825a4043c..8842d4177 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c @@ -47,7 +47,7 @@ #include #include -#include DeviceFamily_constructPath(driverlib / cpu.h) +#include DeviceFamily_constructPath(driverlib/cpu.h) #include #include diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/cc26xx-web-demo.h b/examples/platform-specific/cc26xx/cc26xx-web-demo/cc26xx-web-demo.h index 0761725c7..1840c31b1 100644 --- a/examples/platform-specific/cc26xx/cc26xx-web-demo/cc26xx-web-demo.h +++ b/examples/platform-specific/cc26xx/cc26xx-web-demo/cc26xx-web-demo.h @@ -98,18 +98,18 @@ /*---------------------------------------------------------------------------*/ /* User configuration */ /* Take a sensor reading on button press */ -#define CC26XX_WEB_DEMO_SENSOR_READING_TRIGGER BOARD_BUTTON_HAL_INDEX_KEY_LEFT +#define CC26XX_WEB_DEMO_SENSOR_READING_TRIGGER BUTTON_HAL_ID_KEY_LEFT /* Payload length of ICMPv6 echo requests used to measure RSSI with def rt */ #define CC26XX_WEB_DEMO_ECHO_REQ_PAYLOAD_LEN 20 #if BOARD_SENSORTAG /* Force an MQTT publish on sensor event */ -#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BOARD_BUTTON_HAL_INDEX_REED_RELAY +#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BUTTON_HAL_ID_REED_RELAY #elif BOARD_LAUNCHPAD -#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BOARD_BUTTON_HAL_INDEX_KEY_LEFT +#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BUTTON_HAL_ID_KEY_LEFT #else -#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BOARD_BUTTON_HAL_INDEX_KEY_DOWN +#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BUTTON_HAL_ID_KEY_DOWN #endif #define CC26XX_WEB_DEMO_STATUS_LED LEDS_GREEN diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.c index 54ae61066..8e729576d 100644 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.c +++ b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.c @@ -580,7 +580,7 @@ get_tmp_reading() (random_rand() % SENSOR_READING_RANDOM); if(tmp_amb_reading.publish || tmp_obj_reading.publish) { - if(tmp_007_sensor.value(TMP_007_SENSOR_TYPE_ALL) == + if(tmp_007_sensor.value(TMP_007_TYPE_ALL) == TMP_007_READING_ERROR) { SENSORS_DEACTIVATE(tmp_007_sensor); @@ -589,7 +589,7 @@ get_tmp_reading() } if(tmp_amb_reading.publish) { - value = tmp_007_sensor.value(TMP_007_SENSOR_TYPE_AMBIENT); + value = tmp_007_sensor.value(TMP_007_TYPE_AMBIENT); tmp_amb_reading.raw = value; compare_and_update(&tmp_amb_reading); @@ -601,7 +601,7 @@ get_tmp_reading() } if(tmp_obj_reading.publish) { - value = tmp_007_sensor.value(TMP_007_SENSOR_TYPE_OBJECT); + value = tmp_007_sensor.value(TMP_007_TYPE_OBJECT); tmp_obj_reading.raw = value; compare_and_update(&tmp_obj_reading); @@ -640,7 +640,7 @@ get_hdc_reading() } if(hdc_hum_reading.publish) { - value = hdc_1000_sensor.value(HDC_1000_SENSOR_TYPE_HUMIDITY); + value = hdc_1000_sensor.value(HDC_1000_SENSOR_TYPE_HUMID); if(value != HDC_1000_READING_ERROR) { hdc_hum_reading.raw = value; From 9d7710ef17c84ccc88dddb82111b5cbbb2d838c4 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Thu, 26 Jul 2018 16:48:20 +0200 Subject: [PATCH 312/485] Core SDK should initially point to my personal repo --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 9fbee3575..8fdbdbe63 100644 --- a/.gitmodules +++ b/.gitmodules @@ -24,4 +24,4 @@ url = https://github.com/contiki-ng/motelist [submodule "arch/cpu/cc13xx-cc26xx/lib/coresdk_cc13xx_cc26xx"] path = arch/cpu/cc13xx-cc26xx/lib/coresdk_cc13xx_cc26xx - url = https://github.com/contiki-ng/coresdk_cc13xx_cc26xx.git + url = https://github.com/tiepettersen/coresdk_cc13xx_cc26xx.git From f2ff81a0e3635920d3e5ac6e6b848f1be47ac934 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Wed, 1 Aug 2018 09:06:51 +0200 Subject: [PATCH 313/485] Fixed CORE_SDK checks, and some grammar fixes --- arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 15 +++++++-------- arch/platform/simplelink/Makefile.simplelink | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index fc7ef5b62..c6eeae9d1 100644 --- a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -5,10 +5,11 @@ CC13x2_CC26x2_PRE_RTM ?= 1 # Core SDK is placed as a submodule under arch/cpu/cc13xx-cc26xx/lib. # Do a sanity check that Core SDK submodule has been initialized. -ifeq ($(CORE_SDK),) +ifndef CORE_SDK CORE_SDK := $(CONTIKI_CPU)/lib/coresdk_cc13xx_cc26xx CORE_SDK_INIT := $(shell [ -f $(CORE_SDK)/.git ] && echo 1) - ifeq ($(CORE_SDK_INIT),) + + ifneq ($(CORE_SDK_INIT),1) $(error The Core SDK submodule is not available. Please run 'git submodule update --init --recursive') endif # Note that Core SDK can be overriden with a user-specified SimpleLink SDK. @@ -17,14 +18,12 @@ ifeq ($(CORE_SDK),) else # Do a sanity check the path exists. CORE_SDK_VALID := $(shell [ -d $(CORE_SDK) ] && echo 1) - ifeq ($(CORE_SDK_VALID),) - $(error Supplied CORE_SDK is not a valid path.) + + ifneq ($(CORE_SDK_VALID),1) + $(error User-specified CORE_SDK is not a valid path.) endif endif -# Clean up the path. -CORE_SDK := $(realpath $(CORE_SDK)) - # Both ccfg-conf.c and startup_cc13xx_cc26xx_gcc.c is located locally in # the arch/cpu/cc13xx-cc26xx folder. CPU_START_SOURCEFILES += ccfg-conf.c startup_cc13xx_cc26xx_gcc.c @@ -47,7 +46,7 @@ ifeq ($(SUBFAMILY),cc13x2-cc26x2) SDK_LIB_NAME := $(DEVICE_FAMILY_LC)_v2 endif # CC13x0/CC26x0 does not have this, with both its devices name and library -# name he same as its own device family name. +# name the same as its own device family name. else SDK_DEVICES_NAME := $(DEVICE_FAMILY_LC) SDK_LIB_NAME := $(DEVICE_FAMILY_LC) diff --git a/arch/platform/simplelink/Makefile.simplelink b/arch/platform/simplelink/Makefile.simplelink index 1895c4d71..929bbc8b7 100644 --- a/arch/platform/simplelink/Makefile.simplelink +++ b/arch/platform/simplelink/Makefile.simplelink @@ -27,7 +27,7 @@ FAMILY := $(foreach FAMILY, $(SIMPLELINK_FAMILIES), $(call verify_family,$(FAMIL ifeq ($(FAMILY),) $(error Board '$(BOARD)' does not corresponding to any SimpleLink family. Make sure your BOARD variable is correct.) endif -# If multiple families are found, only the first one is chosen. If this every +# If multiple families are found, only the first one is chosen. If this ever # happens something is not correct. ifneq ($(words $(FAMILY)),1) FAMILY := $(firstword $(FAMILY)) From 405cb7ecd155f5301a10b607c928e5fc3ff4c2d6 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Fri, 3 Aug 2018 10:53:41 +0200 Subject: [PATCH 314/485] Fixed GPIO HAL arch compiler errors for native --- arch/cpu/native/dev/gpio-hal-arch.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/cpu/native/dev/gpio-hal-arch.c b/arch/cpu/native/dev/gpio-hal-arch.c index 553a23444..bd6ad1842 100644 --- a/arch/cpu/native/dev/gpio-hal-arch.c +++ b/arch/cpu/native/dev/gpio-hal-arch.c @@ -43,14 +43,22 @@ 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) +gpio_hal_arch_init(void) +{ + LOG_DBG("Initialized\n"); +} +/*---------------------------------------------------------------------------*/ +void +gpio_hal_arch_interrupt_enable(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; } - LOG_DBG("Pin %u: Enabled interrupt\n", pin); + pin_cfg[pin] &= ~(gpio_hal_pin_cfg_t)GPIO_HAL_PIN_BM_INT; + pin_cfg[pin] |= cfg; + LOG_DBG("Pin %u: Enabled interrupt, config=0x%02x\n", pin, pin_cfg[pin]); } /*---------------------------------------------------------------------------*/ void From b20f38196a6c7faa3d04f59d2dd9e0efe697a1eb Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Fri, 3 Aug 2018 14:08:51 +0200 Subject: [PATCH 315/485] Added missing target dependency for .elf --- arch/cpu/arm/cortex-m/cm3/Makefile.cm3 | 4 ++-- arch/cpu/arm/cortex-m/cm4/Makefile.cm4 | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 b/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 index 1c9ffc04a..24add9c07 100644 --- a/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 +++ b/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 @@ -3,12 +3,12 @@ CONTIKI_ARM_DIRS += cortex-m/cm3 CFLAGS += -mcpu=cortex-m3 LDFLAGS += -mcpu=cortex-m3 -nostartfiles -LDFLAGS += -T $(LDSCRIPT) LDFLAGS += -Wl,--gc-sections LDFLAGS += -Wl,--sort-section=alignment LDFLAGS += -Wl,-Map=$(@:.elf=-$(TARGET).map) LDFLAGS += -Wl,--cref LDFLAGS += -Wl,--no-warn-mismatch +LDFLAGS += -T $(LDSCRIPT) TARGET_LIBFLAGS := -Wl,--start-group $(TARGET_LIBFILES) -lc -lgcc -lm -lnosys -Wl,--end-group @@ -24,7 +24,7 @@ CUSTOM_RULE_LINK = 1 .SECONDEXPANSION: -%.elf: $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(TARGET_LIBS) +%.elf: $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(TARGET_LIBS) $(LDSCRIPT) $(TRACE_LD) $(Q)$(LD) $(LDFLAGS) ${filter %.o %.a,$^} $(TARGET_LIBFLAGS) -o $@ diff --git a/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 b/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 index 180c5cd5a..f6548fd41 100644 --- a/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 +++ b/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 @@ -3,12 +3,12 @@ CONTIKI_ARM_DIRS += cortex-m/cm4 CFLAGS += -mcpu=cortex-m4 LDFLAGS += -mcpu=cortex-m4 -nostartfiles -LDFLAGS += -T $(LDSCRIPT) LDFLAGS += -Wl,--gc-sections LDFLAGS += -Wl,--sort-section=alignment LDFLAGS += -Wl,-Map=$(@:.elf=-$(TARGET).map) LDFLAGS += -Wl,--cref LDFLAGS += -Wl,--no-warn-mismatch +LDFLAGS += -T $(LDSCRIPT) TARGET_LIBFLAGS := -Wl,--start-group $(TARGET_LIBFILES) -lc -lgcc -lm -lnosys -Wl,--end-group @@ -24,7 +24,7 @@ CUSTOM_RULE_LINK = 1 .SECONDEXPANSION: -%.elf: $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(TARGET_LIBS) +%.elf: $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(TARGET_LIBS) $(LDSCRIPT) $(TRACE_LD) $(Q)$(LD) $(LDFLAGS) ${filter %.o %.a,$^} $(TARGET_LIBFLAGS) -o $@ From c53ab05aea41b8b71b2d8966a1b10777e0034c91 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Fri, 3 Aug 2018 14:10:27 +0200 Subject: [PATCH 316/485] Fixed missing changes for GPIO-HAL --- arch/cpu/cc2538/dev/gpio-hal-arch.c | 70 ++++++++----------- arch/cpu/cc2538/dev/gpio-hal-arch.h | 7 +- arch/platform/cc2538dk/dev/board-buttons.c | 11 +-- .../srf06-cc26xx/launchpad/board-buttons.c | 1 + .../srf06-cc26xx/sensortag/board-buttons.c | 8 +-- .../srf06-cc26xx/srf06/board-buttons.c | 11 +-- examples/dev/gpio-hal/gpio-hal-example.c | 6 +- .../platform-specific/cc26xx/cc26xx-demo.c | 6 +- .../very-sleepy-demo/very-sleepy-demo.c | 2 +- 9 files changed, 60 insertions(+), 62 deletions(-) diff --git a/arch/cpu/cc2538/dev/gpio-hal-arch.c b/arch/cpu/cc2538/dev/gpio-hal-arch.c index bd2dfb92d..14c992fe9 100644 --- a/arch/cpu/cc2538/dev/gpio-hal-arch.c +++ b/arch/cpu/cc2538/dev/gpio-hal-arch.c @@ -57,39 +57,35 @@ gpio_hal_arch_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg) gpio_hal_pin_cfg_t tmp; - tmp = cfg & GPIO_HAL_PIN_CFG_EDGE_BOTH; - if(tmp == GPIO_HAL_PIN_CFG_EDGE_NONE) { - GPIO_DISABLE_INTERRUPT(port_base, pin_mask); - } else if(tmp == GPIO_HAL_PIN_CFG_EDGE_RISING) { - GPIO_DETECT_EDGE(port_base, pin_mask); - GPIO_TRIGGER_SINGLE_EDGE(port_base, pin_mask); - GPIO_DETECT_RISING(port_base, pin_mask); - } else if(tmp == GPIO_HAL_PIN_CFG_EDGE_FALLING) { - GPIO_DETECT_EDGE(port_base, pin_mask); - GPIO_TRIGGER_SINGLE_EDGE(port_base, pin_mask); - GPIO_DETECT_FALLING(port_base, pin_mask); - } else if(tmp == GPIO_HAL_PIN_CFG_EDGE_BOTH) { - GPIO_DETECT_EDGE(port_base, pin_mask); - GPIO_TRIGGER_BOTH_EDGES(port_base, pin_mask); - } - - tmp = cfg & GPIO_HAL_PIN_CFG_PULL_MASK; - if(tmp == GPIO_HAL_PIN_CFG_PULL_NONE) { - ioc_set_over(port, pin_num, IOC_OVERRIDE_DIS); - } else if(tmp == GPIO_HAL_PIN_CFG_PULL_DOWN) { - ioc_set_over(port, pin_num, IOC_OVERRIDE_PDE); - } else if(tmp == GPIO_HAL_PIN_CFG_PULL_UP) { - ioc_set_over(port, pin_num, IOC_OVERRIDE_PUE); - } - - tmp = cfg & GPIO_HAL_PIN_CFG_INT_MASK; + tmp = cfg & GPIO_HAL_PIN_BM_INT; if(tmp == GPIO_HAL_PIN_CFG_INT_DISABLE) { GPIO_DISABLE_INTERRUPT(port_base, pin_mask); - } else if(tmp == GPIO_HAL_PIN_CFG_INT_ENABLE) { + } else { + if(tmp == GPIO_HAL_PIN_CFG_INT_RISING) { + GPIO_DETECT_EDGE(port_base, pin_mask); + GPIO_TRIGGER_SINGLE_EDGE(port_base, pin_mask); + GPIO_DETECT_RISING(port_base, pin_mask); + } else if(tmp == GPIO_HAL_PIN_CFG_INT_FALLING) { + GPIO_DETECT_EDGE(port_base, pin_mask); + GPIO_TRIGGER_SINGLE_EDGE(port_base, pin_mask); + GPIO_DETECT_FALLING(port_base, pin_mask); + } else if(tmp == GPIO_HAL_PIN_CFG_INT_BOTH) { + GPIO_DETECT_EDGE(port_base, pin_mask); + GPIO_TRIGGER_BOTH_EDGES(port_base, pin_mask); + } GPIO_ENABLE_INTERRUPT(port_base, pin_mask); NVIC_EnableIRQ(port); } + tmp = cfg & GPIO_HAL_PIN_BM_INPUT; + if(tmp == GPIO_HAL_PIN_CFG_INPUT_NOPULL) { + ioc_set_over(port, pin_num, IOC_OVERRIDE_DIS); + } else if(tmp == GPIO_HAL_PIN_CFG_INPUT_PULLDOWN) { + ioc_set_over(port, pin_num, IOC_OVERRIDE_PDE); + } else if(tmp == GPIO_HAL_PIN_CFG_INPUT_PULLUP) { + ioc_set_over(port, pin_num, IOC_OVERRIDE_PUE); + } + GPIO_SOFTWARE_CONTROL(port_base, pin_mask); } /*---------------------------------------------------------------------------*/ @@ -111,11 +107,11 @@ gpio_hal_arch_pin_cfg_get(gpio_hal_pin_t pin) /* Pull */ tmp = ioc_get_over(port, pin_num); if(tmp == IOC_OVERRIDE_PUE) { - cfg |= GPIO_HAL_PIN_CFG_PULL_UP; + cfg |= GPIO_HAL_PIN_CFG_INPUT_PULLUP; } else if(tmp == IOC_OVERRIDE_PDE) { - cfg |= GPIO_HAL_PIN_CFG_PULL_DOWN; + cfg |= GPIO_HAL_PIN_CFG_INPUT_PULLDOWN; } else { - cfg |= GPIO_HAL_PIN_CFG_PULL_NONE; + cfg |= GPIO_HAL_PIN_CFG_INPUT_NOPULL; } /* Interrupt enable/disable */ @@ -123,20 +119,14 @@ gpio_hal_arch_pin_cfg_get(gpio_hal_pin_t pin) if(tmp == 0) { cfg |= GPIO_HAL_PIN_CFG_INT_DISABLE; } else { - cfg |= GPIO_HAL_PIN_CFG_INT_ENABLE; - } - - /* Edge detection */ - if(REG((port_base) + GPIO_IS) & pin_mask) { - cfg |= GPIO_HAL_PIN_CFG_EDGE_NONE; - } else { + /* Edge detection */ if(REG((port_base) + GPIO_IBE) & pin_mask) { - cfg |= GPIO_HAL_PIN_CFG_EDGE_BOTH; + cfg |= GPIO_HAL_PIN_CFG_INT_BOTH; } else { if(REG((port_base) + GPIO_IEV) & pin_mask) { - cfg |= GPIO_HAL_PIN_CFG_EDGE_RISING; + cfg |= GPIO_HAL_PIN_CFG_INT_RISING; } else { - cfg |= GPIO_HAL_PIN_CFG_EDGE_FALLING; + cfg |= GPIO_HAL_PIN_CFG_INT_FALLING; } } } diff --git a/arch/cpu/cc2538/dev/gpio-hal-arch.h b/arch/cpu/cc2538/dev/gpio-hal-arch.h index 25abb3eb4..761a182a7 100644 --- a/arch/cpu/cc2538/dev/gpio-hal-arch.h +++ b/arch/cpu/cc2538/dev/gpio-hal-arch.h @@ -56,7 +56,12 @@ #define PIN_TO_NUM(pin) (pin % 8) #define PIN_TO_PORT_BASE(pin) GPIO_PORT_TO_BASE(PIN_TO_PORT(pin)) /*---------------------------------------------------------------------------*/ -#define gpio_hal_arch_interrupt_enable(p) do { \ +#define gpio_hal_arch_init() do { \ + /* do nothing */ \ +} while(0); + +#define gpio_hal_arch_interrupt_enable(p, cfg) do { \ + gpio_hal_arch_pin_cfg_set((p), (cfg) & GPIO_HAL_PIN_BM_INT); \ GPIO_ENABLE_INTERRUPT(PIN_TO_PORT_BASE(p), GPIO_PIN_MASK((p) % 8)); \ NVIC_EnableIRQ(PIN_TO_PORT(p)); \ } while(0); diff --git a/arch/platform/cc2538dk/dev/board-buttons.c b/arch/platform/cc2538dk/dev/board-buttons.c index 6afc915df..5701d6f99 100644 --- a/arch/platform/cc2538dk/dev/board-buttons.c +++ b/arch/platform/cc2538dk/dev/board-buttons.c @@ -44,22 +44,23 @@ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "dev/button-hal.h" +#include "dev/gpio-hal.h" /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTON(key_left, "Key Left", \ GPIO_PORT_PIN_TO_GPIO_HAL_PIN(BUTTON_LEFT_PORT, BUTTON_LEFT_PIN), \ - GPIO_HAL_PIN_CFG_PULL_UP, BUTTON_HAL_ID_BUTTON_ZERO, true); + GPIO_HAL_PIN_CFG_INPUT_PULLUP, BUTTON_HAL_ID_BUTTON_ZERO, true); BUTTON_HAL_BUTTON(key_right, "Key Right", \ GPIO_PORT_PIN_TO_GPIO_HAL_PIN(BUTTON_RIGHT_PORT, BUTTON_RIGHT_PIN), \ - GPIO_HAL_PIN_CFG_PULL_UP, BUTTON_HAL_ID_BUTTON_ONE, true); + GPIO_HAL_PIN_CFG_INPUT_PULLUP, BUTTON_HAL_ID_BUTTON_ONE, true); BUTTON_HAL_BUTTON(key_up, "Key Up", \ GPIO_PORT_PIN_TO_GPIO_HAL_PIN(BUTTON_UP_PORT, BUTTON_UP_PIN), \ - GPIO_HAL_PIN_CFG_PULL_UP, BUTTON_HAL_ID_BUTTON_TWO, true); + GPIO_HAL_PIN_CFG_INPUT_PULLUP, BUTTON_HAL_ID_BUTTON_TWO, true); BUTTON_HAL_BUTTON(key_down, "Key Down", \ GPIO_PORT_PIN_TO_GPIO_HAL_PIN(BUTTON_DOWN_PORT, BUTTON_DOWN_PIN), \ - GPIO_HAL_PIN_CFG_PULL_UP, BUTTON_HAL_ID_BUTTON_THREE, true); + GPIO_HAL_PIN_CFG_INPUT_PULLUP, BUTTON_HAL_ID_BUTTON_THREE, true); BUTTON_HAL_BUTTON(key_select, "Key Select", \ GPIO_PORT_PIN_TO_GPIO_HAL_PIN(BUTTON_SELECT_PORT, BUTTON_SELECT_PIN), \ - GPIO_HAL_PIN_CFG_PULL_UP, BUTTON_HAL_ID_BUTTON_FOUR, true); + GPIO_HAL_PIN_CFG_INPUT_PULLUP, BUTTON_HAL_ID_BUTTON_FOUR, true); /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTONS(&key_left, &key_right, &key_up, &key_down, &key_select); /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/srf06-cc26xx/launchpad/board-buttons.c b/arch/platform/srf06-cc26xx/launchpad/board-buttons.c index 1850684c3..0fa6907c6 100644 --- a/arch/platform/srf06-cc26xx/launchpad/board-buttons.c +++ b/arch/platform/srf06-cc26xx/launchpad/board-buttons.c @@ -39,6 +39,7 @@ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "dev/button-hal.h" +#include "dev/gpio-hal.h" #include "ti-lib.h" /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/srf06-cc26xx/sensortag/board-buttons.c b/arch/platform/srf06-cc26xx/sensortag/board-buttons.c index 73fc178bd..bdf481359 100644 --- a/arch/platform/srf06-cc26xx/sensortag/board-buttons.c +++ b/arch/platform/srf06-cc26xx/sensortag/board-buttons.c @@ -38,23 +38,23 @@ */ /*---------------------------------------------------------------------------*/ #include "contiki.h" -#include "dev/gpio-hal.h" #include "dev/button-hal.h" +#include "dev/gpio-hal.h" #include "ti-lib.h" #include /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTON(reed_relay, "Reed Relay", BOARD_IOID_REED_RELAY, \ - GPIO_HAL_PIN_CFG_PULL_DOWN, \ + GPIO_HAL_PIN_CFG_INPUT_PULLDOWN, \ BUTTON_HAL_ID_REED_RELAY, true); BUTTON_HAL_BUTTON(key_left, "Key Left", BOARD_IOID_KEY_LEFT, \ - GPIO_HAL_PIN_CFG_PULL_UP, BUTTON_HAL_ID_KEY_LEFT, \ + GPIO_HAL_PIN_CFG_INPUT_PULLUP, BUTTON_HAL_ID_KEY_LEFT, \ true); BUTTON_HAL_BUTTON(key_right, "Key Right", BOARD_IOID_KEY_RIGHT, \ - GPIO_HAL_PIN_CFG_PULL_UP, BUTTON_HAL_ID_KEY_RIGHT, \ + GPIO_HAL_PIN_CFG_INPUT_PULLUP, BUTTON_HAL_ID_KEY_RIGHT, \ true); /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTONS(&reed_relay, &key_left, &key_right); diff --git a/arch/platform/srf06-cc26xx/srf06/board-buttons.c b/arch/platform/srf06-cc26xx/srf06/board-buttons.c index db06cfcc0..68562f15a 100644 --- a/arch/platform/srf06-cc26xx/srf06/board-buttons.c +++ b/arch/platform/srf06-cc26xx/srf06/board-buttons.c @@ -39,23 +39,24 @@ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "dev/button-hal.h" +#include "dev/gpio-hal.h" #include "ti-lib.h" /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTON(key_left, "Key Left", BOARD_IOID_KEY_LEFT, \ - GPIO_HAL_PIN_CFG_PULL_UP, BUTTON_HAL_ID_KEY_LEFT, \ + GPIO_HAL_PIN_CFG_INPUT_PULLUP, BUTTON_HAL_ID_KEY_LEFT, \ true); BUTTON_HAL_BUTTON(key_right, "Key Right", BOARD_IOID_KEY_RIGHT, \ - GPIO_HAL_PIN_CFG_PULL_UP, BUTTON_HAL_ID_KEY_RIGHT, \ + GPIO_HAL_PIN_CFG_INPUT_PULLUP, BUTTON_HAL_ID_KEY_RIGHT, \ true); BUTTON_HAL_BUTTON(key_up, "Key Up", BOARD_IOID_KEY_UP, \ - GPIO_HAL_PIN_CFG_PULL_UP, BUTTON_HAL_ID_KEY_UP, \ + GPIO_HAL_PIN_CFG_INPUT_PULLUP, BUTTON_HAL_ID_KEY_UP, \ true); BUTTON_HAL_BUTTON(key_down, "Key Down", BOARD_IOID_KEY_DOWN, \ - GPIO_HAL_PIN_CFG_PULL_UP, BUTTON_HAL_ID_KEY_DOWN, \ + GPIO_HAL_PIN_CFG_INPUT_PULLUP, BUTTON_HAL_ID_KEY_DOWN, \ true); BUTTON_HAL_BUTTON(key_select, "Key Select", BOARD_IOID_KEY_SELECT, \ - GPIO_HAL_PIN_CFG_PULL_UP, \ + GPIO_HAL_PIN_CFG_INPUT_PULLUP, \ BUTTON_HAL_ID_KEY_SELECT, true); /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTONS(&key_left, &key_right, &key_up, &key_down, &key_select); diff --git a/examples/dev/gpio-hal/gpio-hal-example.c b/examples/dev/gpio-hal/gpio-hal-example.c index 380c06388..aa6a063d7 100644 --- a/examples/dev/gpio-hal/gpio-hal-example.c +++ b/examples/dev/gpio-hal/gpio-hal-example.c @@ -115,11 +115,11 @@ PROCESS_THREAD(gpio_hal_example, ev, data) gpio_hal_pin_cfg_t interrupt; interrupt = gpio_hal_arch_pin_cfg_get(btn_pin) & - GPIO_HAL_PIN_CFG_INT_ENABLE; + GPIO_HAL_PIN_BM_INT; - if(interrupt == 0) { + if(interrupt != GPIO_HAL_PIN_CFG_INT_DISABLE) { printf("Enabling button interrupt\n"); - gpio_hal_arch_interrupt_enable(btn_pin); + gpio_hal_arch_interrupt_enable(btn_pin, GPIO_HAL_PIN_CFG_INT_BOTH); } else { printf("Disabling button interrupt\n"); gpio_hal_arch_interrupt_disable(btn_pin); diff --git a/examples/platform-specific/cc26xx/cc26xx-demo.c b/examples/platform-specific/cc26xx/cc26xx-demo.c index 8c90905af..acc3ca823 100644 --- a/examples/platform-specific/cc26xx/cc26xx-demo.c +++ b/examples/platform-specific/cc26xx/cc26xx-demo.c @@ -98,11 +98,11 @@ #define CC26XX_DEMO_LEDS_BUTTON LEDS_RED #define CC26XX_DEMO_LEDS_REBOOT LEDS_ALL /*---------------------------------------------------------------------------*/ -#define CC26XX_DEMO_TRIGGER_1 BOARD_BUTTON_HAL_INDEX_KEY_LEFT -#define CC26XX_DEMO_TRIGGER_2 BOARD_BUTTON_HAL_INDEX_KEY_RIGHT +#define CC26XX_DEMO_TRIGGER_1 BUTTON_HAL_ID_KEY_LEFT +#define CC26XX_DEMO_TRIGGER_2 BUTTON_HAL_ID_KEY_RIGHT #if BOARD_SENSORTAG -#define CC26XX_DEMO_TRIGGER_3 BOARD_BUTTON_HAL_INDEX_REED_RELAY +#define CC26XX_DEMO_TRIGGER_3 BUTTON_HAL_ID_REED_RELAY #endif /*---------------------------------------------------------------------------*/ static struct etimer et; 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 ebd55712b..d707f3cd1 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 @@ -63,7 +63,7 @@ #define VERY_SLEEPY_MODE_OFF 0 #define VERY_SLEEPY_MODE_ON 1 /*---------------------------------------------------------------------------*/ -#define BUTTON_TRIGGER BOARD_BUTTON_HAL_INDEX_KEY_LEFT +#define BUTTON_TRIGGER BUTTON_HAL_ID_KEY_LEFT /*---------------------------------------------------------------------------*/ #define MAC_CAN_BE_TURNED_OFF 0 #define MAC_MUST_STAY_ON 1 From fff8e832e27ffb3a508007a2cd222cf49df8b296 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Fri, 3 Aug 2018 14:15:59 +0200 Subject: [PATCH 317/485] Conditionally print PANID if successfully received --- arch/platform/simplelink/cc13xx-cc26xx/platform.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/arch/platform/simplelink/cc13xx-cc26xx/platform.c b/arch/platform/simplelink/cc13xx-cc26xx/platform.c index 50b8ad2c8..c78fe1946 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/platform.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/platform.c @@ -233,9 +233,6 @@ platform_init_stage_three(void) set_rf_params(); - NETSTACK_RADIO.get_value(RADIO_PARAM_CHANNEL, &chan); - NETSTACK_RADIO.get_value(RADIO_PARAM_PAN_ID, &pan); - LOG_DBG("With DriverLib v%u.%u\n", DRIVERLIB_RELEASE_GROUP, DRIVERLIB_RELEASE_BUILD); LOG_DBG("IEEE 802.15.4: %s, Sub-1 GHz: %s, BLE: %s\n", @@ -248,7 +245,15 @@ platform_init_stage_three(void) #elif (RF_MODE == RF_MODE_2_4_GHZ) LOG_INFO("Operating frequency on 2.4 GHz\n"); #endif - LOG_INFO("RF: Channel %d, PANID 0x%04X\n", chan, pan); + + NETSTACK_RADIO.get_value(RADIO_PARAM_CHANNEL, &chan); + LOG_INFO("RF: Channel %d", chan); + + if(NETSTACK_RADIO.get_value(RADIO_PARAM_PAN_ID, &pan) == RADIO_RESULT_OK) { + LOG_INFO(", PANID 0x%04X", pan); + } + LOG_INFO("\n"); + LOG_INFO("Node ID: %d\n", node_id); #if BOARD_CONF_SENSORS_ENABLE From b8b1385c1ffa90956a67207583c91f36971125e9 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Fri, 3 Aug 2018 15:34:20 +0200 Subject: [PATCH 318/485] Extract changes to cpu/cc13xx-cc26xx --- Makefile.identify-target | 2 - Makefile.include | 23 ++------- arch/cpu/arm/Makefile.arm | 6 --- arch/cpu/arm/cortex-m/cm3/Makefile.cm3 | 19 ++++--- arch/cpu/arm/cortex-m/cm4/Makefile.cm4 | 19 ++++--- arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 49 +++++++++++++------ os/sys/timer.c | 4 +- 7 files changed, 57 insertions(+), 65 deletions(-) diff --git a/Makefile.identify-target b/Makefile.identify-target index 22b897421..86e06c093 100644 --- a/Makefile.identify-target +++ b/Makefile.identify-target @@ -11,6 +11,4 @@ ifeq ($(TARGET),) else ${info using saved target '$(TARGET)'} endif -else - ${info using set target '$(TARGET)'} endif diff --git a/Makefile.include b/Makefile.include index 27a65a0f6..319ae29d7 100644 --- a/Makefile.include +++ b/Makefile.include @@ -39,15 +39,13 @@ ifdef CI endif endif -OBJECTDIR := obj_$(TARGET) +OBJECTDIR = obj_$(TARGET) LOWERCASE = -abcdefghijklmnopqrstuvwxyz/ UPPERCASE = _ABCDEFGHIJKLMNOPQRSTUVWXYZ_ TARGET_UPPERCASE := ${strip ${shell echo $(TARGET) | sed y!$(LOWERCASE)!$(UPPERCASE)!}} -CFLAGS += -DCONTIKI=1 -CFLAGS += -DCONTIKI_TARGET_$(TARGET_UPPERCASE)=1 +CFLAGS += -DCONTIKI=1 -DCONTIKI_TARGET_$(TARGET_UPPERCASE)=1 CFLAGS += -DCONTIKI_TARGET_STRING=\"$(TARGET)\" - ifneq ($(BOARD),) TARGET_BOARD_UPPERCASE := ${strip ${shell echo $(BOARD) | sed y!$(LOWERCASE)!$(UPPERCASE)!}} CFLAGS += -DCONTIKI_BOARD_$(TARGET_BOARD_UPPERCASE)=1 @@ -264,10 +262,8 @@ CONTIKI_CPU_DIRS_CONCAT = ${addprefix $(CONTIKI_CPU)/, \ $(CONTIKI_CPU_DIRS)} CONTIKI_ARCH_DIRS = ${addprefix $(CONTIKI)/, arch} -SOURCEDIRS = . $(PROJECTDIRS) $(CONTIKI_TARGET_DIRS_CONCAT) \ - $(CONTIKI_ARCH_DIRS) $(CONTIKI_CPU_DIRS_CONCAT) \ - $(CONTIKIDIRS) $(MODULEDIRS) $(EXTERNALDIRS) \ - $(dir $(target_makefile)) +SOURCEDIRS = . $(PROJECTDIRS) $(CONTIKI_TARGET_DIRS_CONCAT) $(CONTIKI_ARCH_DIRS) \ + $(CONTIKI_CPU_DIRS_CONCAT) $(CONTIKIDIRS) $(MODULEDIRS) $(EXTERNALDIRS) ${dir $(target_makefile)} vpath %.c $(SOURCEDIRS) vpath %.S $(SOURCEDIRS) @@ -323,10 +319,7 @@ distclean: $(MAKE) TARGET=$$TARG clean; \ done -custom_rules := $(CONTIKI)/arch/platform/$(TARGET)/Makefile.customrules-$(TARGET) -ifneq ("$(wildcard $(custom_rules))","") --include $(custom_rules) -endif +-include $(CONTIKI)/arch/platform/$(TARGET)/Makefile.customrules-$(TARGET) ifndef CUSTOM_RULE_C_TO_OBJECTDIR_O $(OBJECTDIR)/%.o: %.c | $(OBJECTDIR) @@ -488,12 +481,6 @@ endif # the match-anything rule below instead. %: %.c -# Prevent Make from remaking any makefiles. This was particularly an -# issue when you had a Makefile with a suffix equal to that of $(TARGET), -# as it managed to match with the %.$(TARGET) rule, which in turn screwed -# everything up. -Makefile.%: ; - ifeq ($(PLATFORM_ACTION),skip) # Skip this target. $(CONTIKI_PROJECT): diff --git a/arch/cpu/arm/Makefile.arm b/arch/cpu/arm/Makefile.arm index ab3c5116f..0b2662423 100644 --- a/arch/cpu/arm/Makefile.arm +++ b/arch/cpu/arm/Makefile.arm @@ -12,12 +12,6 @@ CFLAGS += -mthumb -mabi=aapcs -mlittle-endian CFLAGS += -Werror -Wall CFLAGS += -std=c99 CFLAGS += -ffunction-sections -fdata-sections -fno-strict-aliasing -# A weird behaviour of GCC garbage collection has been observed, where unitialized -# global variables put in the COMMON section weren't analyzed by the garbage collector -# at all. No idea why. The fix is to dissallow the common section, which subsequently -# places all unitialized global variables in the .bss section and enables the -# garbage collector to analyze the variables. -CFLAGS += -fno-common CFLAGS += -fshort-enums -fomit-frame-pointer -fno-builtin LDFLAGS += -mthumb -mlittle-endian diff --git a/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 b/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 index 24add9c07..6bd76135c 100644 --- a/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 +++ b/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 @@ -3,29 +3,28 @@ CONTIKI_ARM_DIRS += cortex-m/cm3 CFLAGS += -mcpu=cortex-m3 LDFLAGS += -mcpu=cortex-m3 -nostartfiles -LDFLAGS += -Wl,--gc-sections -LDFLAGS += -Wl,--sort-section=alignment -LDFLAGS += -Wl,-Map=$(@:.elf=-$(TARGET).map) -LDFLAGS += -Wl,--cref -LDFLAGS += -Wl,--no-warn-mismatch LDFLAGS += -T $(LDSCRIPT) - -TARGET_LIBFLAGS := -Wl,--start-group $(TARGET_LIBFILES) -lc -lgcc -lm -lnosys -Wl,--end-group +LDFLAGS += -Wl,--gc-sections,--sort-section=alignment +LDFLAGS += -Wl,-Map=$(CONTIKI_NG_PROJECT_MAP),--cref,--no-warn-mismatch OBJCOPY_FLAGS += --gap-fill 0xff ### Build syscalls for newlib MODULES += os/lib/newlib -CPU_STARTFILES := ${addprefix $(OBJECTDIR)/,${call oname, $(CPU_START_SOURCEFILES)}} +CPU_STARTFILES = ${addprefix $(OBJECTDIR)/,${call oname, $(CPU_START_SOURCEFILES)}} ### Compilation rules CUSTOM_RULE_LINK = 1 +### Resolve any potential circular dependencies between the linked libraries +### See: https://stackoverflow.com/questions/5651869/gcc-what-are-the-start-group-and-end-group-command-line-options/5651895 +TARGET_LIBFLAGS := -Wl,--start-group $(TARGET_LIBFILES) -lm -Wl,--end-group + .SECONDEXPANSION: -%.elf: $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(TARGET_LIBS) $(LDSCRIPT) +%.elf: $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(LDSCRIPT) $(TRACE_LD) - $(Q)$(LD) $(LDFLAGS) ${filter %.o %.a,$^} $(TARGET_LIBFLAGS) -o $@ + $(Q)$(LD) $(LDFLAGS) ${filter-out $(LDSCRIPT) %.a,$^} ${filter %.a,$^} $(TARGET_LIBFLAGS) -o $@ include $(CONTIKI)/arch/cpu/arm/cortex-m/Makefile.cortex-m diff --git a/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 b/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 index f6548fd41..0635a3148 100644 --- a/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 +++ b/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 @@ -3,29 +3,28 @@ CONTIKI_ARM_DIRS += cortex-m/cm4 CFLAGS += -mcpu=cortex-m4 LDFLAGS += -mcpu=cortex-m4 -nostartfiles -LDFLAGS += -Wl,--gc-sections -LDFLAGS += -Wl,--sort-section=alignment -LDFLAGS += -Wl,-Map=$(@:.elf=-$(TARGET).map) -LDFLAGS += -Wl,--cref -LDFLAGS += -Wl,--no-warn-mismatch LDFLAGS += -T $(LDSCRIPT) - -TARGET_LIBFLAGS := -Wl,--start-group $(TARGET_LIBFILES) -lc -lgcc -lm -lnosys -Wl,--end-group +LDFLAGS += -Wl,--gc-sections,--sort-section=alignment +LDFLAGS += -Wl,-Map=$(CONTIKI_NG_PROJECT_MAP),--cref,--no-warn-mismatch OBJCOPY_FLAGS += --gap-fill 0xff ### Build syscalls for newlib MODULES += os/lib/newlib -CPU_STARTFILES := ${addprefix $(OBJECTDIR)/,${call oname, $(CPU_START_SOURCEFILES)}} +CPU_STARTFILES = ${addprefix $(OBJECTDIR)/,${call oname, $(CPU_START_SOURCEFILES)}} ### Compilation rules CUSTOM_RULE_LINK = 1 +### Resolve any potential circular dependencies between the linked libraries +### See: https://stackoverflow.com/questions/5651869/gcc-what-are-the-start-group-and-end-group-command-line-options/5651895 +TARGET_LIBFLAGS := -Wl,--start-group $(TARGET_LIBFILES) -lm -Wl,--end-group + .SECONDEXPANSION: -%.elf: $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(TARGET_LIBS) $(LDSCRIPT) +%.elf: $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(LDSCRIPT) $(TRACE_LD) - $(Q)$(LD) $(LDFLAGS) ${filter %.o %.a,$^} $(TARGET_LIBFLAGS) -o $@ + $(Q)$(LD) $(LDFLAGS) ${filter-out $(LDSCRIPT) %.a,$^} ${filter %.a,$^} $(TARGET_LIBFLAGS) -o $@ include $(CONTIKI)/arch/cpu/arm/cortex-m/Makefile.cortex-m diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index c6eeae9d1..19b3689e8 100644 --- a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -24,10 +24,6 @@ else endif endif -# Both ccfg-conf.c and startup_cc13xx_cc26xx_gcc.c is located locally in -# the arch/cpu/cc13xx-cc26xx folder. -CPU_START_SOURCEFILES += ccfg-conf.c startup_cc13xx_cc26xx_gcc.c - ################################################################################ ### Device Family @@ -52,20 +48,13 @@ else SDK_LIB_NAME := $(DEVICE_FAMILY_LC) endif -################################################################################ -### Core SDK paths - -SDK_NORTOS := $(CORE_SDK)/kernel/nortos -SDK_SOURCE := $(CORE_SDK)/source -SDK_DRIVERS := $(CORE_SDK)/source/ti/drivers -SDK_DEVICES := $(CORE_SDK)/source/ti/devices/$(SDK_DEVICES_NAME) - -EXTERNALDIRS += $(SDK_SOURCE) -EXTERNALDIRS += $(SDK_NORTOS) - ################################################################################ ### CC13xx/CC26xx CPU files +# Both ccfg-conf.c and startup_cc13xx_cc26xx_gcc.c is located locally in +# the arch/cpu/cc13xx-cc26xx folder. +CPU_START_SOURCEFILES += ccfg-conf.c startup_cc13xx_cc26xx_gcc.c + # CPU-dependent source files CONTIKI_CPU_SOURCEFILES += rtimer-arch.c clock-arch.c CONTIKI_CPU_SOURCEFILES += watchdog-arch.c dbg-arch.c @@ -94,6 +83,14 @@ endif ################################################################################ ### Modules and paths +# Core SDK paths +SDK_NORTOS := $(CORE_SDK)/kernel/nortos +SDK_SOURCE := $(CORE_SDK)/source +SDK_DRIVERS := $(CORE_SDK)/source/ti/drivers +SDK_DEVICES := $(CORE_SDK)/source/ti/devices/$(SDK_DEVICES_NAME) + +EXTERNALDIRS += $(SDK_SOURCE) $(SDK_NORTOS) + # CPU-dependent debug source files MODULES += os/lib/dbg-io @@ -103,6 +100,19 @@ CONTIKI_CPU_DIRS += rf rf-settings rf-settings/$(DEVICE_FAMILY_LC) CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES) $(DEBUG_IO_SOURCEFILES) +################################################################################ +### Compiler configuration + +# A weird behaviour of GCC garbage collector has been observed, where +# unitialized global variables with global linkage (aka non-static) put in the +# COMMON section weren't analyzed by the garbage collector at all. No idea why. +# The solution is to disable the common section, which subsequently places all +# unitialized global variables with global linkage in the .bss section, +# allowing the GC to analyze the variables. This is especially an issue with +# Board.h files, as they rely heavily on global variables placed in COMMON to +# be garbage collected if unused. +CFLAGS += -fno-common + ################################################################################ ### Linker configuration @@ -111,8 +121,12 @@ LDFLAGS += --entry resetISR LDFLAGS += -static LDFLAGS += --specs=nano.specs +# Linker script LDSCRIPT := $(CONTIKI_CPU)/$(SUBFAMILY)/$(SUBFAMILY).lds +# Globally linked libraries +TARGET_LIBFILES += -lc -lgcc -lnosys + ################################################################################ ### Specialized build targets @@ -130,5 +144,8 @@ $(OBJECTDIR)/ccfg-conf.o: ccfg-conf.c FORCE | $(OBJECTDIR) $(TRACE_CC) $(Q)$(CC) $(CFLAGS) -c $< -o $@ -# Include the Sub-family specific Makefile +################################################################################ +### Sub-family Makefile + +# Include the Sub-family Makefile specific for the specified device include $(CONTIKI_CPU)/$(SUBFAMILY)/Makefile.$(SUBFAMILY) diff --git a/os/sys/timer.c b/os/sys/timer.c index 068d57777..1eeae64de 100644 --- a/os/sys/timer.c +++ b/os/sys/timer.c @@ -84,9 +84,7 @@ timer_set(struct timer *t, clock_time_t interval) void timer_reset(struct timer *t) { - if(timer_expired(t)) { - t->start += t->interval; - } + t->start += t->interval; } /*---------------------------------------------------------------------------*/ /** From 32d9bb3021bc24fd9437eb3f85357fcaaddef9bb Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Thu, 30 Aug 2018 17:02:08 +0200 Subject: [PATCH 319/485] Removed simplelink examples for now --- .../cc13xx-cc26xx/start-demo/Makefile | 8 - .../cc13xx-cc26xx/start-demo/README.md | 14 - .../cc13xx-cc26xx/start-demo/project-conf.h | 43 - .../cc13xx-cc26xx/start-demo/start-demo.c | 425 ------ .../cc13xx-cc26xx/very-sleepy-demo/Makefile | 10 - .../cc13xx-cc26xx/very-sleepy-demo/README.md | 91 -- .../very-sleepy-demo/project-conf.h | 61 - .../very-sleepy-demo/very-sleepy-demo.c | 424 ------ .../very-sleepy-demo.simplelink | Bin 592244 -> 0 bytes .../cc13xx-cc26xx/web-demo/Makefile | 23 - .../cc13xx-cc26xx/web-demo/README.md | 185 --- .../web-demo/cetic-6lbr-client.c | 204 --- .../cc13xx-cc26xx/web-demo/coap-server.c | 169 --- .../cc13xx-cc26xx/web-demo/coap-server.h | 52 - .../cc13xx-cc26xx/web-demo/httpd-simple.c | 1351 ----------------- .../cc13xx-cc26xx/web-demo/httpd-simple.h | 102 -- .../cc13xx-cc26xx/web-demo/img/6lbr-web.png | Bin 81741 -> 0 bytes .../ibm-watson-iot-platform-tls-optional.png | Bin 86462 -> 0 bytes .../web-demo/img/quickstart-sensortag.png | Bin 158808 -> 0 bytes .../web-demo/img/sensor-readings-config.png | Bin 33000 -> 0 bytes .../web-demo/img/well-known-core.png | Bin 9102 -> 0 bytes .../cc13xx-cc26xx/web-demo/mqtt-client.c | 927 ----------- .../cc13xx-cc26xx/web-demo/mqtt-client.h | 71 - .../cc13xx-cc26xx/web-demo/net-uart.c | 321 ---- .../cc13xx-cc26xx/web-demo/net-uart.h | 48 - .../cc13xx-cc26xx/web-demo/project-conf.h | 88 -- .../web-demo/resources/res-ble-advd.c | 115 -- .../web-demo/resources/res-device.c | 207 --- .../web-demo/resources/res-leds.c | 111 -- .../web-demo/resources/res-net.c | 129 -- .../web-demo/resources/res-sensors.c | 302 ---- .../web-demo/resources/res-toggle-leds.c | 118 -- .../cc13xx-cc26xx/web-demo/web-demo.c | 1054 ------------- .../cc13xx-cc26xx/web-demo/web-demo.h | 235 --- 34 files changed, 6888 deletions(-) delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/Makefile delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/README.md delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/project-conf.h delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/start-demo.c delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/Makefile delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/README.md delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/project-conf.h delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/very-sleepy-demo.c delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/very-sleepy-demo.simplelink delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/Makefile delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/README.md delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/cetic-6lbr-client.c delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/coap-server.c delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/coap-server.h delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/httpd-simple.c delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/httpd-simple.h delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/6lbr-web.png delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/ibm-watson-iot-platform-tls-optional.png delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/quickstart-sensortag.png delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/sensor-readings-config.png delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/well-known-core.png delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/mqtt-client.c delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/mqtt-client.h delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/net-uart.c delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/net-uart.h delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/project-conf.h delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-ble-advd.c delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-device.c delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-leds.c delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-net.c delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-sensors.c delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-toggle-leds.c delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.c delete mode 100644 examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.h diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/Makefile b/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/Makefile deleted file mode 100644 index bffecb99c..000000000 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -CONTIKI_PROJECT = start-demo - -PLATFORMS_ONLY = simplelink - -all: $(CONTIKI_PROJECT) - -CONTIKI = ../../../../.. -include $(CONTIKI)/Makefile.include diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/README.md b/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/README.md deleted file mode 100644 index af20f6e3f..000000000 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/README.md +++ /dev/null @@ -1,14 +0,0 @@ -CC26xx Demo -=========== -This example demonstrates basic functionality for the two supported CC26xx -boards. More specifically, the example demonstrates: - -* How to take sensor readings -* How to use buttons and the reed relay (triggered by holding a magnet near S3 - on the SensorTag). -* How to send out BLE advertisements, if the chip has BLE capability. The - device will periodically send out BLE beacons with the platform name as - payload. Those beacons/BLE ADV packets can be captured with any BLE-capable - device. Two such applications for iOS are the TI Multitool and the TI - Sensortag app. They can be found in the Apple App Store. If you have a - BLE-capable Mac, you can also use LightBlue for OS X. diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/project-conf.h b/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/project-conf.h deleted file mode 100644 index 17bd2ce29..000000000 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/project-conf.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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 PROJECT_CONF_H_ -#define PROJECT_CONF_H_ -/*---------------------------------------------------------------------------*/ -/* Enable the ROM bootloader */ -#define ROM_BOOTLOADER_ENABLE 1 -/*---------------------------------------------------------------------------*/ -/* Change to match your configuration */ -#define IEEE802154_CONF_PANID 0xABCD -#define IEEE802154_CONF_DEFAULT_CHANNEL 25 -#define RF_BLE_CONF_ENABLED 1 -/*---------------------------------------------------------------------------*/ -#endif /* PROJECT_CONF_H_ */ -/*---------------------------------------------------------------------------*/ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/start-demo.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/start-demo.c deleted file mode 100644 index 9ed3f32cb..000000000 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/start-demo/start-demo.c +++ /dev/null @@ -1,425 +0,0 @@ -/* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/*---------------------------------------------------------------------------*/ -/** - * \addtogroup cc26xx-platforms - * @{ - * - * \defgroup cc26xx-examples CC26xx Example Projects - * - * Example projects for CC26xx-based platforms. - * @{ - * - * \defgroup cc26xx-demo CC26xx Demo Project - * - * Example project demonstrating the CC13xx/CC26xx platforms - * - * This example will work for the following boards: - * - srf06-cc26xx: SmartRF06EB + CC13xx/CC26xx EM - * - CC2650 and CC1350 SensorTag - * - CC1310, CC1350, CC2650 LaunchPads - * - * This is an IPv6/RPL-enabled example. Thus, if you have a border router in - * your installation (same RDC layer, same PAN ID and RF channel), you should - * be able to ping6 this demo node. - * - * This example also demonstrates CC26xx BLE operation. The process starts - * the BLE beacon daemon (implemented in the RF driver). The daemon will - * send out a BLE beacon periodically. Use any BLE-enabled application (e.g. - * LightBlue on OS X or the TI BLE Multitool smartphone app) and after a few - * seconds the cc26xx device will be discovered. - * - * - etimer/clock : Every CC26XX_DEMO_LOOP_INTERVAL clock ticks the LED defined - * as CC26XX_DEMO_LEDS_PERIODIC will toggle and the device - * will print out readings from some supported sensors - * - sensors : Some sensortag sensors are read asynchronously (see sensor - * documentation). For those, this example will print out - * readings in a staggered fashion at a random interval - * - Buttons : CC26XX_DEMO_TRIGGER_1 button will toggle CC26XX_DEMO_LEDS_BUTTON - * - CC26XX_DEMO_TRIGGER_2 turns on LEDS_REBOOT and causes a - * watchdog reboot - * - The remaining buttons will just print something - * - The example also shows how to retrieve the duration of a - * button press (in ticks). The driver will generate a - * sensors_changed event upon button release - * - Reed Relay : Will toggle the sensortag buzzer on/off - * - * @{ - * - * \file - * Example demonstrating the cc26xx platforms - */ -#include "contiki.h" -#include "sys/etimer.h" -#include "sys/ctimer.h" -#include "dev/leds.h" -#include "dev/watchdog.h" -#include "dev/button-hal.h" -#include "random.h" -#include "button-sensor.h" -#include "batmon-sensor.h" -#include "board-peripherals.h" - -#include "rf/ble-beacond.h" - -#include -#include -/*---------------------------------------------------------------------------*/ -#define CC26XX_DEMO_LOOP_INTERVAL (CLOCK_SECOND * 20) -#define CC26XX_DEMO_LEDS_PERIODIC LEDS_YELLOW -#define CC26XX_DEMO_LEDS_BUTTON LEDS_RED -#define CC26XX_DEMO_LEDS_REBOOT LEDS_ALL -/*---------------------------------------------------------------------------*/ -#define CC26XX_DEMO_TRIGGER_1 BUTTON_HAL_ID_KEY_LEFT -#define CC26XX_DEMO_TRIGGER_2 BUTTON_HAL_ID_KEY_RIGHT - -#if BOARD_SENSORTAG -#define CC26XX_DEMO_TRIGGER_3 BUTTON_HAL_ID_REED_RELAY -#endif -/*---------------------------------------------------------------------------*/ -static struct etimer et; -/*---------------------------------------------------------------------------*/ -PROCESS(cc26xx_demo_process, "cc26xx demo process"); -AUTOSTART_PROCESSES(&cc26xx_demo_process); -/*---------------------------------------------------------------------------*/ -#if BOARD_SENSORTAG -/*---------------------------------------------------------------------------*/ -/* - * Update sensor readings in a staggered fashion every SENSOR_READING_PERIOD - * ticks + a random interval between 0 and SENSOR_READING_RANDOM ticks - */ -#define SENSOR_READING_PERIOD (CLOCK_SECOND * 20) -#define SENSOR_READING_RANDOM (CLOCK_SECOND << 4) - -static struct ctimer bmp_timer, opt_timer, hdc_timer, tmp_timer, mpu_timer; -/*---------------------------------------------------------------------------*/ -static void init_bmp_reading(void *not_used); -static void init_opt_reading(void *not_used); -static void init_hdc_reading(void *not_used); -static void init_tmp_reading(void *not_used); -static void init_mpu_reading(void *not_used); -/*---------------------------------------------------------------------------*/ -static void -print_mpu_reading(int reading) -{ - if(reading < 0) { - printf("-"); - reading = -reading; - } - - printf("%d.%02d", reading / 100, reading % 100); -} -/*---------------------------------------------------------------------------*/ -static void -get_bmp_reading() -{ - int value; - clock_time_t next = SENSOR_READING_PERIOD + - (random_rand() % SENSOR_READING_RANDOM); - - value = bmp_280_sensor.value(BMP_280_SENSOR_TYPE_PRESS); - if(value != CC26XX_SENSOR_READING_ERROR) { - printf("BAR: Pressure=%d.%02d hPa\n", value / 100, value % 100); - } else { - printf("BAR: Pressure Read Error\n"); - } - - value = bmp_280_sensor.value(BMP_280_SENSOR_TYPE_TEMP); - if(value != CC26XX_SENSOR_READING_ERROR) { - printf("BAR: Temp=%d.%02d C\n", value / 100, value % 100); - } else { - printf("BAR: Temperature Read Error\n"); - } - - SENSORS_DEACTIVATE(bmp_280_sensor); - - ctimer_set(&bmp_timer, next, init_bmp_reading, NULL); -} -/*---------------------------------------------------------------------------*/ -static void -get_tmp_reading() -{ - int value; - clock_time_t next = SENSOR_READING_PERIOD + - (random_rand() % SENSOR_READING_RANDOM); - - value = tmp_007_sensor.value(TMP_007_SENSOR_TYPE_ALL); - - if(value == CC26XX_SENSOR_READING_ERROR) { - printf("TMP: Ambient Read Error\n"); - return; - } - - value = tmp_007_sensor.value(TMP_007_SENSOR_TYPE_AMBIENT); - printf("TMP: Ambient=%d.%03d C\n", value / 1000, value % 1000); - - value = tmp_007_sensor.value(TMP_007_SENSOR_TYPE_OBJECT); - printf("TMP: Object=%d.%03d C\n", value / 1000, value % 1000); - - SENSORS_DEACTIVATE(tmp_007_sensor); - - ctimer_set(&tmp_timer, next, init_tmp_reading, NULL); -} -/*---------------------------------------------------------------------------*/ -static void -get_hdc_reading() -{ - int value; - clock_time_t next = SENSOR_READING_PERIOD + - (random_rand() % SENSOR_READING_RANDOM); - - value = hdc_1000_sensor.value(HDC_1000_SENSOR_TYPE_TEMP); - if(value != CC26XX_SENSOR_READING_ERROR) { - printf("HDC: Temp=%d.%02d C\n", value / 100, value % 100); - } else { - printf("HDC: Temp Read Error\n"); - } - - value = hdc_1000_sensor.value(HDC_1000_SENSOR_TYPE_HUMIDITY); - if(value != CC26XX_SENSOR_READING_ERROR) { - printf("HDC: Humidity=%d.%02d %%RH\n", value / 100, value % 100); - } else { - printf("HDC: Humidity Read Error\n"); - } - - ctimer_set(&hdc_timer, next, init_hdc_reading, NULL); -} -/*---------------------------------------------------------------------------*/ -static void -get_light_reading() -{ - int value; - clock_time_t next = SENSOR_READING_PERIOD + - (random_rand() % SENSOR_READING_RANDOM); - - value = opt_3001_sensor.value(0); - if(value != CC26XX_SENSOR_READING_ERROR) { - printf("OPT: Light=%d.%02d lux\n", value / 100, value % 100); - } else { - printf("OPT: Light Read Error\n"); - } - - /* The OPT will turn itself off, so we don't need to call its DEACTIVATE */ - ctimer_set(&opt_timer, next, init_opt_reading, NULL); -} -/*---------------------------------------------------------------------------*/ -static void -get_mpu_reading() -{ - int value; - clock_time_t next = SENSOR_READING_PERIOD + - (random_rand() % SENSOR_READING_RANDOM); - - printf("MPU Gyro: X="); - value = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_GYRO_X); - print_mpu_reading(value); - printf(" deg/sec\n"); - - printf("MPU Gyro: Y="); - value = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_GYRO_Y); - print_mpu_reading(value); - printf(" deg/sec\n"); - - printf("MPU Gyro: Z="); - value = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_GYRO_Z); - print_mpu_reading(value); - printf(" deg/sec\n"); - - printf("MPU Acc: X="); - value = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_ACC_X); - print_mpu_reading(value); - printf(" G\n"); - - printf("MPU Acc: Y="); - value = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_ACC_Y); - print_mpu_reading(value); - printf(" G\n"); - - printf("MPU Acc: Z="); - value = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_ACC_Z); - print_mpu_reading(value); - printf(" G\n"); - - SENSORS_DEACTIVATE(mpu_9250_sensor); - - ctimer_set(&mpu_timer, next, init_mpu_reading, NULL); -} -/*---------------------------------------------------------------------------*/ -static void -init_bmp_reading(void *not_used) -{ - SENSORS_ACTIVATE(bmp_280_sensor); -} -/*---------------------------------------------------------------------------*/ -static void -init_opt_reading(void *not_used) -{ - SENSORS_ACTIVATE(opt_3001_sensor); -} -/*---------------------------------------------------------------------------*/ -static void -init_hdc_reading(void *not_used) -{ - SENSORS_ACTIVATE(hdc_1000_sensor); -} -/*---------------------------------------------------------------------------*/ -static void -init_tmp_reading(void *not_used) -{ - SENSORS_ACTIVATE(tmp_007_sensor); -} -/*---------------------------------------------------------------------------*/ -static void -init_mpu_reading(void *not_used) -{ - mpu_9250_sensor.configure(SENSORS_ACTIVE, MPU_9250_SENSOR_TYPE_ALL); -} -#endif -/*---------------------------------------------------------------------------*/ -static void -get_sync_sensor_readings(void) -{ - int value; - - printf("-----------------------------------------\n"); - - value = batmon_sensor.value(BATMON_SENSOR_TYPE_TEMP); - printf("Bat: Temp=%d C\n", value); - - value = batmon_sensor.value(BATMON_SENSOR_TYPE_VOLT); - printf("Bat: Volt=%d mV\n", (value * 125) >> 5); - -#if BOARD_SMARTRF06EB - SENSORS_ACTIVATE(als_sensor); - - value = als_sensor.value(0); - printf("ALS: %d raw\n", value); - - SENSORS_DEACTIVATE(als_sensor); -#endif - - return; -} -/*---------------------------------------------------------------------------*/ -static void -init_sensors(void) -{ - SENSORS_ACTIVATE(batmon_sensor); -} -/*---------------------------------------------------------------------------*/ -static void -init_sensor_readings(void) -{ -#if BOARD_SENSORTAG - SENSORS_ACTIVATE(hdc_1000_sensor); - SENSORS_ACTIVATE(tmp_007_sensor); - SENSORS_ACTIVATE(opt_3001_sensor); - SENSORS_ACTIVATE(bmp_280_sensor); - - init_mpu_reading(NULL); -#endif -} -/*---------------------------------------------------------------------------*/ -PROCESS_THREAD(cc26xx_demo_process, ev, data) -{ - - PROCESS_BEGIN(); - - printf("CC26XX demo\n"); - - init_sensors(); - - /* Init the BLE advertisement daemon */ - rf_ble_beacond_start(0, BOARD_STRING); - - etimer_set(&et, CC26XX_DEMO_LOOP_INTERVAL); - get_sync_sensor_readings(); - init_sensor_readings(); - - while(1) { - - PROCESS_YIELD(); - - if(ev == PROCESS_EVENT_TIMER) { - if(data == &et) { - leds_toggle(CC26XX_DEMO_LEDS_PERIODIC); - - get_sync_sensor_readings(); - - etimer_set(&et, CC26XX_DEMO_LOOP_INTERVAL); - } - } else if(ev == button_hal_periodic_event) { - button_hal_button_t *button = data; - - printf("%s periodic event, duration %d seconds\n", - BUTTON_HAL_GET_DESCRIPTION(button), - button->press_duration_seconds); - } else if(ev == button_hal_release_event) { - button_hal_button_t *btn = (button_hal_button_t *)data; - - printf("%s release event\n", BUTTON_HAL_GET_DESCRIPTION(btn)); - - if(btn->unique_id== CC26XX_DEMO_TRIGGER_1) { - leds_toggle(CC26XX_DEMO_LEDS_BUTTON); - } else if(btn->unique_id == CC26XX_DEMO_TRIGGER_2) { - leds_on(CC26XX_DEMO_LEDS_REBOOT); - watchdog_reboot(); -#if BOARD_SENSORTAG - } else if(btn->unique_id == CC26XX_DEMO_TRIGGER_3) { - if(buzzer_state()) { - buzzer_stop(); - } else { - buzzer_start(1000); - } - } - } else if(ev == sensors_event) { - if(data == &bmp_280_sensor) { - get_bmp_reading(); - } else if(data == &opt_3001_sensor) { - get_light_reading(); - } else if(data == &hdc_1000_sensor) { - get_hdc_reading(); - } else if(data == &tmp_007_sensor) { - get_tmp_reading(); - } else if(data == &mpu_9250_sensor) { - get_mpu_reading(); -#endif - } - } - } - - PROCESS_END(); -} -/*---------------------------------------------------------------------------*/ -/** - * @} - * @} - * @} - */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/Makefile b/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/Makefile deleted file mode 100644 index 97272c9a7..000000000 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -CONTIKI_PROJECT = very-sleepy-demo - -PLATFORMS_ONLY = simplelink - -all: $(CONTIKI_PROJECT) - -MODULES += os/net/app-layer/coap - -CONTIKI = ../../../../.. -include $(CONTIKI)/Makefile.include diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/README.md b/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/README.md deleted file mode 100644 index 851150432..000000000 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/README.md +++ /dev/null @@ -1,91 +0,0 @@ -# CC13xx/CC26xx Very Sleepy Demo - -This example demonstrates a way of deploying a very low-consuming, very sleepy -node. The node has two modes of operation: - -* Normal: ContikiMAC duty-cycles the radio as usual. The node is reachable. -* Very Sleepy: Radio cycling mostly off, except when we need to perform network - maintenance tasks. In this mode, the node is unreachable for most of the time. - -The node will operate in RPL leaf mode. This means that it will be reachable -downwards, but it will not advertise the DODAG and it will not participate in -routing. - -After booting, the node will enter "normal" mode. - -The node exposes an OBSERVEable CoAP resource. It will notify subscribers with -a new value for this resource every `interval` seconds. It will then stay in -normal mode for `duration` seconds. During this time window, it will be -reachable over the network in order to e.g. receive a new configuration. -When this time window expires, the node will switch back to very sleepy mode. -This will only happen if very sleepy mode has been enabled by setting `mode=1` -as per the instructions below. - -When the node is duty-cycling the radio, either because it is in normal mode or -because network maintenance is taking place, it will keep its green LED on thus -providing an indication that it is reachable (red LED for the CC1350 tag). - -A normal mode stint can be manually triggered by pressing the left button. - -## Requirements - -To run this example you will need: - -* A border router operating with the same RDC, same channel, same radio mode - (e.g. IEEE or sub-ghz), same PAN ID. Alternatively, you can - use [6lbr](https://github.com/cetic/6lbr) with a suitable slip-radio. -* The [Copper (Cu)](https://addons.mozilla.org/en-US/firefox/addon/copper-270430/) - addon for Firefox - -## Configuration - -To configure the node, send a CoAP POST message to the `very_sleepy_config` -resource. The POST message's payload must specify _at least one_ of: - -* `mode=0|1`: Send `mode=1` to enable very sleepy mode, `mode=0` to disable it. -* `interval=n` where `n` is the number of seconds between two consecutive normal - mode periods. This interval also dictates the OBSERVEr notification period. -* `duration=n` where `n` is the number of seconds that the node will stay in - normal mode before dropping to very sleepy mode. This value is only relevant - if `mode==1`. - -A POST request must contain at least one of the above, but they are otherwise -all optional. So, for example, a POST may simply specify `interval=n`. To send -multiple values, delimit them with `&`. So you can send something like -`mode=1&interval=60&duration=20` - -The current running configuration can be retrieved by sending a GET request to -the same CoAP resource. - -## Running the example - -* Deploy your border router or 6lbr -* Turn on the very sleepy node. -* Fire up the Copper addon -* Select `.well-known/core` and hit `GET` -* Configure very sleepy operation: - * Select the `very_sleepy_config` resource - * In the `Outgoing` pane, type your POST payload as per the instructions - above. For example, you can type: `mode=1&interval=30&duration=10` - * Hit `POST` -* Select the `sen/readings` resource and hit `OBSERVE` - -## Caveats - -If you click on a resource in the Copper resources tree while you are observing -a different resource, the OBSERVEr for the latter will be stopped without -notifying the CoAP server. This will result in the server sending out OBSERVE -notifications that will be responded to with port unreachable ICMPv6 messages. -This will continue for quite a while, until the server detects that the -OBSERVEr has been lost (a test currently performed once every 20 notifications). -In order to prevent this from happening, hit the "Cancel" button for the -OBSERVE before switching views to a different resource. This will unregister -the observer. - -In very sleepy mode, the radio is not truly always off. The contiki core needs -to perform other periodic tasks in order to maintain network connectivity. For -that reason, this example will allow the radio to turn on periodically even -while in very sleepy mode. Thus, you may see that the node becomes briefly -reachable every now and then. However, do not count on those periods of -reachability to perform any tasks, as they will be brief and will be disrupted -without warning. diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/project-conf.h b/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/project-conf.h deleted file mode 100644 index 784a0e9ee..000000000 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/project-conf.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ - * 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 PROJECT_CONF_H_ -#define PROJECT_CONF_H_ -/*---------------------------------------------------------------------------*/ -/* Platform configuration */ -#define BOARD_CONF_SENSORS_DISABLE 1 -#define WATCHDOG_CONF_DISABLE 1 -/*---------------------------------------------------------------------------*/ -/* Nestack configuration */ -#define IEEE802154_CONF_PANID 0xABCD -#define IEEE802154_CONF_DEFAULT_CHANNEL 25 -//#define RF_CONF_MODE RF_MODE_SUB_1_GHZ -#define RF_CONF_MODE RF_MODE_2_4_GHZ -#define RF_CONF_BLE_BEACON_ENABLE 0 -/*---------------------------------------------------------------------------*/ -/* TI drivers configuration */ -#define TI_SPI_CONF_ENABLE 0 -#define TI_I2C_CONF_ENABLE 0 -/*---------------------------------------------------------------------------*/ -/* For very sleepy operation */ -#define UIP_DS6_CONF_PERIOD CLOCK_SECOND -#define UIP_CONF_TCP 0 -#define RPL_CONF_LEAF_ONLY 1 - -/* - * We'll fail without RPL probing, so turn it on explicitly even though it's - * on by default - */ -#define RPL_CONF_WITH_PROBING 1 -/*---------------------------------------------------------------------------*/ -#endif /* PROJECT_CONF_H_ */ -/*---------------------------------------------------------------------------*/ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/very-sleepy-demo.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/very-sleepy-demo.c deleted file mode 100644 index 711746f7c..000000000 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/very-sleepy-demo.c +++ /dev/null @@ -1,424 +0,0 @@ -/* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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/etimer.h" -#include "sys/stimer.h" -#include "sys/process.h" -#include "lib/sensors.h" -#include "dev/leds.h" -#include "dev/watchdog.h" -#include "dev/button-hal.h" -#include "net/netstack.h" -#include "net/ipv6/uip-ds6-nbr.h" -#include "net/ipv6/uip-ds6-route.h" -#include "net/routing/routing.h" -#include "net/app-layer/coap/coap.h" -#include "net/app-layer/coap/coap-engine.h" -/*---------------------------------------------------------------------------*/ -#include "board-peripherals.h" -#include "batmon-sensor.h" -/*---------------------------------------------------------------------------*/ -#include -#include -#include -/*---------------------------------------------------------------------------*/ -/* Normal mode duration params in seconds */ -#define NORMAL_OP_DURATION_DEFAULT 10 -#define NORMAL_OP_DURATION_MIN 10 -#define NORMAL_OP_DURATION_MAX 60 -/*---------------------------------------------------------------------------*/ -/* Observer notification period params in seconds */ -#define PERIODIC_INTERVAL_DEFAULT 30 -#define PERIODIC_INTERVAL_MIN 30 -#define PERIODIC_INTERVAL_MAX 86400 /* 1 day */ -/*---------------------------------------------------------------------------*/ -#define VERY_SLEEPY_MODE_OFF 0 -#define VERY_SLEEPY_MODE_ON 1 -/*---------------------------------------------------------------------------*/ -#define BUTTON_TRIGGER BUTTON_HAL_ID_KEY_LEFT -/*---------------------------------------------------------------------------*/ -#define MAC_CAN_BE_TURNED_OFF 0 -#define MAC_MUST_STAY_ON 1 - -#define KEEP_MAC_ON_MIN_PERIOD 10 /* secs */ -/*---------------------------------------------------------------------------*/ -#define PERIODIC_INTERVAL CLOCK_SECOND -/*---------------------------------------------------------------------------*/ -#define POST_STATUS_BAD 0x80 -#define POST_STATUS_HAS_MODE 0x40 -#define POST_STATUS_HAS_DURATION 0x20 -#define POST_STATUS_HAS_INTERVAL 0x10 -#define POST_STATUS_NONE 0x00 -/*---------------------------------------------------------------------------*/ -typedef struct sleepy_config_s { - unsigned long interval; - unsigned long duration; - uint8_t mode; -} sleepy_config_t; - -sleepy_config_t config; -/*---------------------------------------------------------------------------*/ -#define STATE_NORMAL 0 -#define STATE_NOTIFY_OBSERVERS 1 -#define STATE_VERY_SLEEPY 2 -/*---------------------------------------------------------------------------*/ -static struct stimer st_duration; -static struct stimer st_interval; -static struct stimer st_min_mac_on_duration; -static struct etimer et_periodic; -static process_event_t event_new_config; -static uint8_t state; -/*---------------------------------------------------------------------------*/ -const char *not_supported_msg = "Supported:text/plain,application/json"; -/*---------------------------------------------------------------------------*/ -PROCESS(very_sleepy_demo_process, "CC13xx/CC26xx very sleepy process"); -AUTOSTART_PROCESSES(&very_sleepy_demo_process); -/*---------------------------------------------------------------------------*/ -static void -readings_get_handler(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - unsigned int accept = -1; - int temp; - int voltage; - - if(request != NULL) { - coap_get_header_accept(request, &accept); - } - - temp = batmon_sensor.value(BATMON_SENSOR_TYPE_TEMP); - - voltage = batmon_sensor.value(BATMON_SENSOR_TYPE_VOLT); - - if(accept == -1 || accept == APPLICATION_JSON) { - coap_set_header_content_format(response, APPLICATION_JSON); - snprintf((char *)buffer, COAP_MAX_CHUNK_SIZE, - "{\"temp\":{\"v\":%d,\"u\":\"C\"}," - "\"voltage\":{\"v\":%d,\"u\":\"mV\"}}", - temp, (voltage * 125) >> 5); - - coap_set_payload(response, buffer, strlen((char *)buffer)); - } else if(accept == TEXT_PLAIN) { - coap_set_header_content_format(response, TEXT_PLAIN); - snprintf((char *)buffer, COAP_MAX_CHUNK_SIZE, "Temp=%dC, Voltage=%dmV", - temp, (voltage * 125) >> 5); - - coap_set_payload(response, buffer, strlen((char *)buffer)); - } else { - coap_set_status_code(response, NOT_ACCEPTABLE_4_06); - coap_set_payload(response, not_supported_msg, - strlen(not_supported_msg)); - } -} -/*---------------------------------------------------------------------------*/ -RESOURCE(readings_resource, "title=\"Sensor Readings\";obs", - readings_get_handler, NULL, NULL, NULL); -/*---------------------------------------------------------------------------*/ -static void -conf_get_handler(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - unsigned int accept = -1; - - if(request != NULL) { - coap_get_header_accept(request, &accept); - } - - if(accept == -1 || accept == APPLICATION_JSON) { - coap_set_header_content_format(response, APPLICATION_JSON); - snprintf((char *)buffer, COAP_MAX_CHUNK_SIZE, - "{\"config\":{\"mode\":%u,\"duration\":%lu,\"interval\":%lu}}", - config.mode, config.duration, config.interval); - - coap_set_payload(response, buffer, strlen((char *)buffer)); - } else if(accept == TEXT_PLAIN) { - coap_set_header_content_format(response, TEXT_PLAIN); - snprintf((char *)buffer, COAP_MAX_CHUNK_SIZE, - "Mode=%u, Duration=%lusecs, Interval=%lusecs", - config.mode, config.duration, config.interval); - - coap_set_payload(response, buffer, strlen((char *)buffer)); - } else { - coap_set_status_code(response, NOT_ACCEPTABLE_4_06); - coap_set_payload(response, not_supported_msg, - strlen(not_supported_msg)); - } -} -/*---------------------------------------------------------------------------*/ -static void -conf_post_handler(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - const char *ptr = NULL; - char tmp_buf[16]; - unsigned long interval = 0; - unsigned long duration = 0; - uint8_t mode = VERY_SLEEPY_MODE_OFF; - uint8_t post_status = POST_STATUS_NONE; - int rv; - - rv = coap_get_post_variable(request, "mode", &ptr); - if(rv && rv < 16) { - memset(tmp_buf, 0, sizeof(tmp_buf)); - memcpy(tmp_buf, ptr, rv); - rv = atoi(tmp_buf); - - if(rv == 1) { - mode = VERY_SLEEPY_MODE_ON; - post_status |= POST_STATUS_HAS_MODE; - } else if(rv == 0) { - mode = VERY_SLEEPY_MODE_OFF; - post_status |= POST_STATUS_HAS_MODE; - } else { - post_status = POST_STATUS_BAD; - } - } - - rv = coap_get_post_variable(request, "duration", &ptr); - if(rv && rv < 16) { - memset(tmp_buf, 0, sizeof(tmp_buf)); - memcpy(tmp_buf, ptr, rv); - rv = atoi(tmp_buf); - - duration = (unsigned long)rv; - if(duration < NORMAL_OP_DURATION_MIN || duration > NORMAL_OP_DURATION_MAX) { - post_status = POST_STATUS_BAD; - } else { - post_status |= POST_STATUS_HAS_DURATION; - } - } - - rv = coap_get_post_variable(request, "interval", &ptr); - if(rv && rv < 16) { - memset(tmp_buf, 0, sizeof(tmp_buf)); - memcpy(tmp_buf, ptr, rv); - rv = atoi(tmp_buf); - interval = (unsigned long)rv; - if(interval < PERIODIC_INTERVAL_MIN || interval > PERIODIC_INTERVAL_MAX) { - post_status = POST_STATUS_BAD; - } else { - post_status |= POST_STATUS_HAS_INTERVAL; - } - } - - if((post_status & POST_STATUS_BAD) == POST_STATUS_BAD || - post_status == POST_STATUS_NONE) { - coap_set_status_code(response, BAD_REQUEST_4_00); - snprintf((char *)buffer, COAP_MAX_CHUNK_SIZE, - "mode=0|1&duration=[%u,%u]&interval=[%u,%u]", - NORMAL_OP_DURATION_MIN, NORMAL_OP_DURATION_MAX, - PERIODIC_INTERVAL_MIN, PERIODIC_INTERVAL_MAX); - - coap_set_payload(response, buffer, strlen((char *)buffer)); - return; - } - - /* Values are sane. Update the config and notify the process */ - if(post_status & POST_STATUS_HAS_MODE) { - config.mode = mode; - } - - if(post_status & POST_STATUS_HAS_INTERVAL) { - config.interval = interval; - } - - if(post_status & POST_STATUS_HAS_DURATION) { - config.duration = duration; - } - - process_post(&very_sleepy_demo_process, event_new_config, NULL); -} -/*---------------------------------------------------------------------------*/ -RESOURCE(very_sleepy_conf, - "title=\"Very sleepy conf: " - "GET|POST mode=0|1&interval=&duration=\";rt=\"Control\"", - conf_get_handler, conf_post_handler, NULL, NULL); -/*---------------------------------------------------------------------------*/ -/* - * If our preferred parent is not NBR_REACHABLE in the ND cache, NUD will send - * a unicast NS and wait for NA. If NA fails then the neighbour will be removed - * from the ND cache and the default route will be deleted. To prevent this, - * keep the MAC on until the parent becomes NBR_REACHABLE. We also keep the MAC - * on if we are about to do RPL probing. - * - * In all cases, the radio will be locked on for KEEP_MAC_ON_MIN_PERIOD secs - */ -static uint8_t -keep_mac_on(void) -{ - uip_ds6_nbr_t *nbr; - uint8_t rv = MAC_CAN_BE_TURNED_OFF; - - if(!stimer_expired(&st_min_mac_on_duration)) { - return MAC_MUST_STAY_ON; - } - -#if RPL_WITH_PROBING - /* Determine if we are about to send a RPL probe */ - if(CLOCK_LT(etimer_expiration_time( - &rpl_get_default_instance()->dag.probing_timer.etimer), - (clock_time() + PERIODIC_INTERVAL))) { - rv = MAC_MUST_STAY_ON; - } -#endif - - /* It's OK to pass a NULL pointer, the callee checks and returns NULL */ - nbr = uip_ds6_nbr_lookup(uip_ds6_defrt_choose()); - - if(nbr == NULL) { - /* We don't have a default route, or it's not reachable (NUD likely). */ - rv = MAC_MUST_STAY_ON; - } else { - if(nbr->state != NBR_REACHABLE) { - rv = MAC_MUST_STAY_ON; - } - } - - if(rv == MAC_MUST_STAY_ON && stimer_expired(&st_min_mac_on_duration)) { - stimer_set(&st_min_mac_on_duration, KEEP_MAC_ON_MIN_PERIOD); - } - - return rv; -} -/*---------------------------------------------------------------------------*/ -static void -switch_to_normal(void) -{ - state = STATE_NOTIFY_OBSERVERS; - - /* - * Stay in normal mode for 'duration' secs. - * Transition back to normal in 'interval' secs, _including_ 'duration' - */ - stimer_set(&st_duration, config.duration); - stimer_set(&st_interval, config.interval); -} -/*---------------------------------------------------------------------------*/ -static void -switch_to_very_sleepy(void) -{ - state = STATE_VERY_SLEEPY; -} -/*---------------------------------------------------------------------------*/ -PROCESS_THREAD(very_sleepy_demo_process, ev, data) -{ - uint8_t mac_keep_on; - - PROCESS_BEGIN(); - - SENSORS_ACTIVATE(batmon_sensor); - - config.mode = VERY_SLEEPY_MODE_OFF; - config.interval = PERIODIC_INTERVAL_DEFAULT; - config.duration = NORMAL_OP_DURATION_DEFAULT; - - state = STATE_NORMAL; - - event_new_config = process_alloc_event(); - - readings_resource.flags += IS_OBSERVABLE; - coap_activate_resource(&readings_resource, "sen/readings"); - coap_activate_resource(&very_sleepy_conf, "very_sleepy_config"); - - printf("Very Sleepy Demo Process\n"); - - switch_to_normal(); - - etimer_set(&et_periodic, PERIODIC_INTERVAL); - - while(1) { - - PROCESS_YIELD(); - - if(ev == button_hal_release_event && - ((button_hal_button_t *)data)->unique_id == BUTTON_TRIGGER) { - switch_to_normal(); - } - - if(ev == event_new_config) { - stimer_set(&st_interval, config.interval); - stimer_set(&st_duration, config.duration); - } - - if((ev == PROCESS_EVENT_TIMER && data == &et_periodic) || - (ev == button_hal_release_event && - ((button_hal_button_t *)data)->unique_id == BUTTON_TRIGGER) || - (ev == event_new_config)) { - - /* - * Determine if the stack is about to do essential network maintenance - * and, if so, keep the MAC layer on - */ - mac_keep_on = keep_mac_on(); - - if(mac_keep_on == MAC_MUST_STAY_ON || state != STATE_VERY_SLEEPY) { - leds_on(LEDS_GREEN); - NETSTACK_MAC.on(); - } - - /* - * Next, switch between normal and very sleepy mode depending on config, - * send notifications to observers as required. - */ - if(state == STATE_NOTIFY_OBSERVERS) { - coap_notify_observers(&readings_resource); - state = STATE_NORMAL; - } - - if(state == STATE_NORMAL) { - if(stimer_expired(&st_duration)) { - stimer_set(&st_duration, config.duration); - if(config.mode == VERY_SLEEPY_MODE_ON) { - switch_to_very_sleepy(); - } - } - } else if(state == STATE_VERY_SLEEPY) { - if(stimer_expired(&st_interval)) { - switch_to_normal(); - } - } - - if(mac_keep_on == MAC_CAN_BE_TURNED_OFF && state == STATE_VERY_SLEEPY) { - leds_off(LEDS_GREEN); - NETSTACK_MAC.off(); - } else { - leds_on(LEDS_GREEN); - NETSTACK_MAC.on(); - } - - /* Schedule next pass */ - etimer_set(&et_periodic, PERIODIC_INTERVAL); - } - } - - PROCESS_END(); -} -/*---------------------------------------------------------------------------*/ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/very-sleepy-demo.simplelink b/examples/platform-specific/simplelink/cc13xx-cc26xx/very-sleepy-demo/very-sleepy-demo.simplelink deleted file mode 100644 index a405a2444edd79e75e3e58269ce3b74b87b469fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 592244 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

g|^YxT`_;&!p>oh?lWHcdYhi5 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 Sz5Mq-lzoG5?Z%(j-~R&^;Q2oQ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/Makefile b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/Makefile deleted file mode 100644 index aa310465d..000000000 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -CONTIKI_PROJECT = web-demo - -PLATFORMS_ONLY = simplelink - -all: $(CONTIKI_PROJECT) - -MODULES_REL += ./resources - -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 -MODULES += arch/dev/ext-flash - -CONTIKI = ../../../../.. -include $(CONTIKI)/Makefile.include diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/README.md b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/README.md deleted file mode 100644 index 912fcb72a..000000000 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/README.md +++ /dev/null @@ -1,185 +0,0 @@ -CC26xx Web Demo Readme -====================== -This demo project combines a number of web-based applications aiming to -demonstrate the CC26xx capability. The applications are: - -* A network-based UART -* A client for [6lbr](http://cetic.github.io/6lbr/) -* A CoAP server -* An MQTT client -* A web server which can be used to display sensor readings but also to - configure MQTT functionality - -The example has been configured to run for all CC26xx-based boards. - -To change between target boards, follow the instructions in the wiki. -Do not forget to `make clean` when switching between the boards. - -Specifically for some older CC2650 SensorTags, you may also need to change -`project-conf.h` such that `SENSORTAG_CC2650_REV_1_2_0` is defined as 1. To -check if your sensortag is one of those older ones, look for "REV: 1.2" -printed on the PCB. There may also be a sticker that reads "HW Rev 1.2.0". An -indication that you may need to do this is if you get a "Could not open flash -to load config" error on device startup. - -You can disable some of those individual components by changing the respective -defines in `project-conf.h`. For instance, to disable the CoAP functionality, -set `#define CC26XX_WEB_DEMO_CONF_COAP_SERVER 0`. The web server cannot be -disabled, all other aforementioned applications can. - -Network UART (net-uart) ------------------------ -This example only makes sense if you are using the Srf or if you have taken -the sensortag out of its case and you have it connected over JTAG to the Srf. - -The net-uart does two things: - -* When you type a string to the UART console, the string will be sent verbatim - to a remote UDP port 7777 listener. This can be for example a netcat listener - on a linux or OS X PC: - `nc -6ulkw 1 7777` -* The net-uart also listens to UDP port 7777 and when it receives a string over - UDP, it will print it verbatim over UART. - -The example will initially send packets to a hard-coded IPv6 address. This can -be changed very easily by entering a different IPv6 address to the console. -Thus, when the serial input string is an IPv6 address, it will not be sent as -any other string would, but instead it will configure the example to send to a -different remote address. This new IPv6 address is not persistent across -device reboots. - -6lbr Client ------------ -This will periodically send a UDP packet to your 6lbr, containing network -information, which will be used by 6lbr to construct a network graph. To see -this in action, fire up a browser and navigate to the 6lbr web page. The -default address is http://[bbbb::100]. Once the page loads, click the 'sensors' -tab, as per the image below. - -![6lbr](img/6lbr-web.png) - -CoAP Server ------------ -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). - -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-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 various CC13x0/CC26x0 boards. - -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 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 -the CoAP engine will return 4.03 forbidden. The values of `name` and `interval` -persist across BLE on/off cycles, so you only have to set them once. The values -do _not_ persist through device powercycles. - -HTTPD ------ -Back on the 6lbr page, hit the 'web' link corresponding to your device. This -will take you to a web page served by the CC26xx. The HTTPD serves two pages: - -* index.html: Provides sensor readings and network information -* config.html: Can be used to configure the MQTT client (more below) - -In the navigation bar at the top there is also a third link, which will take -you directly to your device's page on IBM's quickstart service. - -IBM Quickstart / MQTT Client ----------------------------- -The MQTT client can be used to: - -* Publish sensor readings to an MQTT broker. -* Subscribe to a topic and as a result receive commands from an MQTT broker - -The device will 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. If this is not an option for you, you can -configure the device to publish to a local MQTT broker over end-to-end IPv6. -See below on how to change the destination broker's address. - -By default the device will publish readings to IBM's quickstart service. The -publish messages include sensor readings but also some other information such -as device uptime in seconds and a message sequence number. Click the "IBM -Quickstart" link in the web page to go directly to your device's page -on Quickstart. After a few seconds, you will see something like this: - -![A SensorTag on IBM Quickstart](img/quickstart-sensortag.png) - -Sensor readings are only published if they have changed since the previous -reading (BatMon is an exception and always gets published). Additionally, you -can turn on/off individual readings from the config.html web page, as per the -figure below. - -![Sensor Readings Configuration](img/sensor-readings-config.png) - -Some of the MQTT client functionality can be configured even further: - -* You can change the broker IP and port. This is useful if you want to use your - own MQTT broker instead of IBM's quickstart. The example has been tested - successfully with [mosquitto](http://mosquitto.org/) -* You can change the publish interval. Recommended values are 10secs or higher. - You will not be allowed to set this to anything less than 5 seconds. -* If you want to use IBM's cloud service with a registered device, change - 'Org ID' and provide an 'Auth Token', which acts as a 'password', but bear in - mind that it gets transported in clear text, both over the web configuration - page as well as inside MQTT messages. -* The remaining configuration options are related to the content of MQTT - messages and in general you won't have to modify them. - -For the SensorTag, changes to the MQTT configuration get saved in external -flash and persist across device restarts. The same does not hold true for -Srf+EM builds. - -You can also subscribe to topics and receive commands, but this will only -work if you use "Org ID" != 'quickstart'. Thus, if you provide a different -Org ID (do not forget the auth token!), the device will subscribe to: - -`iot-2/cmd/+/fmt/json` - -You can then use this to toggle LEDs or to turn the buzzer on and off. -The buzzer is only available on the SensorTag. To do this, you can for example -use mosquitto client to publish to `iot-2/cmd/leds/fmt/json`. So, to turn -the buzzer on, you would do this: - -`mosquitto_pub -h -m "1" -t iot-2/cmd/buzz/fmt/json` - -Where `broker IP` should be replaced with the IP address of your mosquitto -broker (the one where you device has subscribed). Replace `-m "1'` with `-m "0"` -to turn the buzzer back off. Replace `buzz` with `leds` in the topic to change -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) diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/cetic-6lbr-client.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/cetic-6lbr-client.c deleted file mode 100644 index 7c4cbdfff..000000000 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/cetic-6lbr-client.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * 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. - */ -/** - * \addtogroup cc13xx-cc26xx-web-demo - * @{ - * - * \file - * An implementation of a 6LBR UDP client. Is used to populate the 6LBR - * web server's 'sensors' tab - */ -/*---------------------------------------------------------------------------*/ -#include "contiki.h" -#include "contiki-lib.h" -#include "contiki-net.h" -#include "net/ipv6/uip.h" -#include "net/routing/routing.h" -#include "net/routing/rpl-classic/rpl.h" -#include "net/routing/rpl-classic/rpl-private.h" -/*---------------------------------------------------------------------------*/ -#include -#include -/*---------------------------------------------------------------------------*/ -#define DEBUG 0 -#include "net/ipv6/uip-debug.h" -/*---------------------------------------------------------------------------*/ -#if (ROUTING_CONF_RPL_CLASSIC == 0) -#error "The 6LBR client is only meant for RPL Classic. Set MAKE_ROUTING accordingly." -#endif -/*---------------------------------------------------------------------------*/ -#ifndef CETIC_6LBR_NODE_INFO_PORT -#define CETIC_6LBR_NODE_INFO_PORT 3000 -#endif - -#define MAX_PAYLOAD_LEN 40 -#define MSG_INTERVAL (60 * CLOCK_SECOND) -/*---------------------------------------------------------------------------*/ -static struct uip_udp_conn *client_conn = NULL; -static struct etimer et; -static uip_ip6addr_t dest_addr; -/*---------------------------------------------------------------------------*/ -PROCESS(cetic_6lbr_client_process, "6LBR Client Process"); -/*---------------------------------------------------------------------------*/ -static void -tcpip_handler(void) -{ - char *str; - - if(uip_newdata()) { - str = uip_appdata; - str[uip_datalen()] = '\0'; - PRINTF("Response from the server: '%s'\n", str); - } -} -/*---------------------------------------------------------------------------*/ -static char * -add_ipaddr(char *buf, const uip_ipaddr_t *addr) -{ - uint16_t a; - unsigned int i; - int f; - char *p = buf; - - for(i = 0, f = 0; i < sizeof(uip_ipaddr_t); i += 2) { - a = (addr->u8[i] << 8) + addr->u8[i + 1]; - if(a == 0 && f >= 0) { - if(f++ == 0) { - p += sprintf(p, "::"); - } - } else { - if(f > 0) { - f = -1; - } else if(i > 0) { - p += sprintf(p, ":"); - } - p += sprintf(p, "%04x", a); - } - } - return p; -} -/*---------------------------------------------------------------------------*/ -static void -timeout_handler(void) -{ - static int seq_id; - char buf[MAX_PAYLOAD_LEN]; - int i; - uip_ip6addr_t *globaladdr = NULL; - uint16_t dest_port = CETIC_6LBR_NODE_INFO_PORT; - int has_dest = 0; - rpl_instance_t *instance; - rpl_dag_t *dag; - - uip_ds6_addr_t *addr_desc = uip_ds6_get_global(ADDR_PREFERRED); - if(addr_desc != NULL) { - globaladdr = &addr_desc->ipaddr; - dag = rpl_get_any_dag(); - if(dag) { - uip_ipaddr_copy(&dest_addr, globaladdr); - memcpy(&dest_addr.u8[8], &dag->dag_id.u8[8], sizeof(uip_ipaddr_t) / 2); - has_dest = 1; - } - } - - if(has_dest) { - if(client_conn == NULL) { - PRINTF("UDP-CLIENT: address destination: "); - PRINT6ADDR(&dest_addr); - PRINTF("\n"); - client_conn = udp_new(&dest_addr, UIP_HTONS(dest_port), NULL); - - if(client_conn != NULL) { - PRINTF("Created a connection with the server "); - PRINT6ADDR(&client_conn->ripaddr); - PRINTF(" local/remote port %u/%u\n", - UIP_HTONS(client_conn->lport), UIP_HTONS(client_conn->rport)); - } else { - PRINTF("Could not open connection\n"); - } - } else { - if(memcmp(&client_conn->ripaddr, &dest_addr, sizeof(uip_ipaddr_t)) != 0) { - PRINTF("UDP-CLIENT: new address destination: "); - PRINT6ADDR(&dest_addr); - PRINTF("\n"); - uip_udp_remove(client_conn); - client_conn = udp_new(&dest_addr, UIP_HTONS(dest_port), NULL); - if(client_conn != NULL) { - PRINTF("Created a connection with the server "); - PRINT6ADDR(&client_conn->ripaddr); - PRINTF(" local/remote port %u/%u\n", - UIP_HTONS(client_conn->lport), UIP_HTONS(client_conn->rport)); - } else { - PRINTF("Could not open connection\n"); - } - } - } - if(client_conn != NULL) { - PRINTF("Client sending to: "); - PRINT6ADDR(&client_conn->ripaddr); - i = sprintf(buf, "%d | ", ++seq_id); - instance = rpl_get_default_instance(); - 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)"); - } - PRINTF(" (msg: %s)\n", buf); - uip_udp_packet_send(client_conn, buf, strlen(buf)); - } else { - PRINTF("No connection created\n"); - } - } else { - PRINTF("No address configured\n"); - } -} -/*---------------------------------------------------------------------------*/ -PROCESS_THREAD(cetic_6lbr_client_process, ev, data) -{ - - PROCESS_BEGIN(); - - printf("6LBR Client Process\n"); - - memset(&dest_addr, 0, sizeof(uip_ipaddr_t)); - - etimer_set(&et, MSG_INTERVAL); - while(1) { - PROCESS_YIELD(); - if(etimer_expired(&et)) { - timeout_handler(); - etimer_set(&et, MSG_INTERVAL); - } else if(ev == tcpip_event) { - tcpip_handler(); - } - } - - PROCESS_END(); -} -/*---------------------------------------------------------------------------*/ -/** - * @} - */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/coap-server.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/coap-server.c deleted file mode 100644 index 5a53fb1ae..000000000 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/coap-server.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/** - * \addtogroup cc13xx-cc26xx-web-demo - * @{ - * - * \file - * A CC13xx/CC26xx-specific CoAP server - */ -/*---------------------------------------------------------------------------*/ -#include "contiki.h" -#include "contiki-net.h" -#include "net/app-layer/coap/coap-engine.h" -/*---------------------------------------------------------------------------*/ -#include "board-peripherals.h" -#include "rf/ble-beacond.h" -/*---------------------------------------------------------------------------*/ -#include "web-demo.h" -/*---------------------------------------------------------------------------*/ -#include -#include -#include -/*---------------------------------------------------------------------------*/ -/* Common resources */ -extern coap_resource_t res_leds; - -extern coap_resource_t res_batmon_temp; -extern coap_resource_t res_batmon_volt; - -extern coap_resource_t res_device_sw; -extern coap_resource_t res_device_hw; -extern coap_resource_t res_device_uptime; -extern coap_resource_t res_device_cfg_reset; - -extern coap_resource_t res_parent_rssi; -extern coap_resource_t res_parent_ip; - -#if RF_CONF_BLE_BEACON_ENABLE -extern coap_resource_t res_ble_advd; -#endif - -extern coap_resource_t res_toggle_red; -extern coap_resource_t res_toggle_green; - -/* Board-specific resources */ -#if BOARD_SENSORTAG -extern coap_resource_t res_bmp280_temp; -extern coap_resource_t res_bmp280_press; -extern coap_resource_t res_tmp007_amb; -extern coap_resource_t res_tmp007_obj; -extern coap_resource_t res_hdc1000_temp; -extern coap_resource_t res_hdc1000_hum; -extern coap_resource_t res_opt3001_light; -extern coap_resource_t res_mpu_acc_x; -extern coap_resource_t res_mpu_acc_y; -extern coap_resource_t res_mpu_acc_z; -extern coap_resource_t res_mpu_gyro_x; -extern coap_resource_t res_mpu_gyro_y; -extern coap_resource_t res_mpu_gyro_z; -#else -extern coap_resource_t res_toggle_orange; -extern coap_resource_t res_toggle_yellow; -#endif - -#if WEB_DEMO_ADC_DEMO -extern coap_resource_t res_adc_dio23; -#endif -/*---------------------------------------------------------------------------*/ -const char *coap_server_not_found_msg = "Resource not found"; -const char *coap_server_supported_msg = "Supported:" - "text/plain," - "application/json," - "application/xml"; -/*---------------------------------------------------------------------------*/ -static void -start_board_resources(void) -{ - - coap_activate_resource(&res_toggle_green, "lt/g"); - coap_activate_resource(&res_toggle_red, "lt/r"); - coap_activate_resource(&res_leds, "lt"); - -#if BOARD_SENSORTAG - coap_activate_resource(&res_bmp280_temp, "sen/bar/temp"); - coap_activate_resource(&res_bmp280_press, "sen/bar/pres"); - coap_activate_resource(&res_tmp007_amb, "sen/tmp/amb"); - coap_activate_resource(&res_tmp007_obj, "sen/tmp/obj"); - coap_activate_resource(&res_hdc1000_temp, "sen/hdc/t"); - coap_activate_resource(&res_hdc1000_hum, "sen/hdc/h"); - coap_activate_resource(&res_opt3001_light, "sen/opt/light"); - coap_activate_resource(&res_mpu_acc_x, "sen/mpu/acc/x"); - coap_activate_resource(&res_mpu_acc_y, "sen/mpu/acc/y"); - coap_activate_resource(&res_mpu_acc_z, "sen/mpu/acc/z"); - coap_activate_resource(&res_mpu_gyro_x, "sen/mpu/gyro/x"); - coap_activate_resource(&res_mpu_gyro_y, "sen/mpu/gyro/y"); - coap_activate_resource(&res_mpu_gyro_z, "sen/mpu/gyro/z"); -#elif BOARD_SMARTRF06EB - coap_activate_resource(&res_toggle_yellow, "lt/y"); - coap_activate_resource(&res_toggle_orange, "lt/o"); -#endif -} -/*---------------------------------------------------------------------------*/ -PROCESS(coap_server_process, "CC13xx/CC26xx CoAP Server"); -/*---------------------------------------------------------------------------*/ -PROCESS_THREAD(coap_server_process, ev, data) -{ - PROCESS_BEGIN(); - - printf("CC13xx/CC26xx CoAP Server\n"); - - coap_activate_resource(&res_batmon_temp, "sen/batmon/temp"); - coap_activate_resource(&res_batmon_volt, "sen/batmon/voltage"); - -#if WEB_DEMO_ADC_DEMO - coap_activate_resource(&res_adc_dio23, "sen/adc/dio23"); -#endif - - coap_activate_resource(&res_device_hw, "dev/mdl/hw"); - coap_activate_resource(&res_device_sw, "dev/mdl/sw"); - coap_activate_resource(&res_device_uptime, "dev/uptime"); - coap_activate_resource(&res_device_cfg_reset, "dev/cfg_reset"); - - coap_activate_resource(&res_parent_rssi, "net/parent/RSSI"); - coap_activate_resource(&res_parent_ip, "net/parent/IPv6"); - -#if RF_CONF_BLE_BEACON_ENABLE - coap_activate_resource(&res_ble_advd, "dev/ble_advd"); -#endif - - start_board_resources(); - - /* Define application-specific events here. */ - while(1) { - PROCESS_WAIT_EVENT(); - } - - PROCESS_END(); -} -/*---------------------------------------------------------------------------*/ -/** - * @} - */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/coap-server.h b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/coap-server.h deleted file mode 100644 index 839928871..000000000 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/coap-server.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/** - * \addtogroup cc13xx-cc26xx-web-demo - * @{ - * - * \file - * Header file for the CC13xx/CC26xx web demo CoAP functionality - */ -/*---------------------------------------------------------------------------*/ -#include "sys/process.h" -/*---------------------------------------------------------------------------*/ -#ifndef COAP_SERVER_H_ -#define COAP_SERVER_H_ -/*---------------------------------------------------------------------------*/ -extern const char *coap_server_not_found_msg; -extern const char *coap_server_supported_msg; -/*---------------------------------------------------------------------------*/ -PROCESS_NAME(coap_server_process); -/*---------------------------------------------------------------------------*/ -#endif /* COAP_SERVER_H_ */ -/*---------------------------------------------------------------------------*/ -/** - * @} - */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/httpd-simple.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/httpd-simple.c deleted file mode 100644 index 46f247ac8..000000000 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/httpd-simple.c +++ /dev/null @@ -1,1351 +0,0 @@ -/* - * Copyright (c) 2010, Swedish Institute of Computer Science. - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - * - */ -/** - * \addtogroup cc13xx-cc26xx-web-demo - * @{ - * - * \file - * A simple web server which displays network and sensor information - */ -/*---------------------------------------------------------------------------*/ -#include "contiki.h" -#include "net/ipv6/uip-ds6-route.h" -#include "lib/sensors.h" -#include "lib/list.h" -/*---------------------------------------------------------------------------*/ -#include "batmon-sensor.h" -/*---------------------------------------------------------------------------*/ -#include "web-demo.h" -#include "mqtt-client.h" -#include "httpd-simple.h" -#include "net-uart.h" -/*---------------------------------------------------------------------------*/ -#include -#include -#include -#include -#include -#include -#include -#include -/*---------------------------------------------------------------------------*/ -#define SEND_STRING(s, str) PSOCK_SEND(s, (uint8_t *)str, strlen(str)) -/*---------------------------------------------------------------------------*/ -#define CONNS 2 -#define CONTENT_LENGTH_MAX 256 -#define STATE_WAITING 0 -#define STATE_OUTPUT 1 -#define IPADDR_BUF_LEN 64 -/*---------------------------------------------------------------------------*/ -#define RETURN_CODE_OK 0 -#define RETURN_CODE_NF 1 /* Not Found */ -#define RETURN_CODE_SU 2 /* Service Unavailable */ -#define RETURN_CODE_BR 3 /* Bad Request */ -#define RETURN_CODE_LR 4 /* Length Required */ -#define RETURN_CODE_TL 5 /* Content Length too Large */ -/*---------------------------------------------------------------------------*/ -/* POST request machine states */ -#define PARSE_POST_STATE_INIT 0 -#define PARSE_POST_STATE_MORE 1 -#define PARSE_POST_STATE_READING_KEY 2 -#define PARSE_POST_STATE_READING_VAL 3 -#define PARSE_POST_STATE_ERROR 0xFFFFFFFF -/*---------------------------------------------------------------------------*/ -#define PARSE_POST_BUF_SIZES 64 - -/* Last byte always used to null terminate */ -#define PARSE_POST_MAX_POS (PARSE_POST_BUF_SIZES - 2) - -static char key[PARSE_POST_BUF_SIZES]; -static char val_escaped[PARSE_POST_BUF_SIZES]; -static char val[PARSE_POST_BUF_SIZES]; -static int key_len; -static int val_len; -static int state; -/*---------------------------------------------------------------------------*/ -/* Stringified min/max intervals */ -#define STRINGIFY(x) XSTR(x) -#define XSTR(x) #x - -#define RSSI_INT_MAX STRINGIFY(WEB_DEMO_RSSI_MEASURE_INTERVAL_MAX) -#define RSSI_INT_MIN STRINGIFY(WEB_DEMO_RSSI_MEASURE_INTERVAL_MIN) -#define PUB_INT_MAX STRINGIFY(MQTT_CLIENT_PUBLISH_INTERVAL_MAX) -#define PUB_INT_MIN STRINGIFY(MQTT_CLIENT_PUBLISH_INTERVAL_MIN) -/*---------------------------------------------------------------------------*/ -/* - * We can only handle a single POST request at a time. Since a second POST - * request cannot interrupt us while obtaining a lock, we don't really need - * this lock to be atomic. - * - * An HTTP connection will first request a lock before it starts processing - * a POST request. We maintain a global lock which is either NULL or points - * to the http conn which currently has the lock - */ -static struct httpd_state *lock; -/*---------------------------------------------------------------------------*/ -PROCESS(httpd_simple_process, "CC13xx/CC26xx Web Server"); -/*---------------------------------------------------------------------------*/ -#define ISO_nl 0x0A -#define ISO_space 0x20 -#define ISO_slash 0x2F -#define ISO_amp 0x26 -#define ISO_column 0x3A -#define ISO_equal 0x3D -/*---------------------------------------------------------------------------*/ -#define HTTP_200_OK "HTTP/1.0 200 OK\r\n" -#define HTTP_302_FO "HTTP/1.0 302 Found\r\n" -#define HTTP_400_BR "HTTP/1.0 400 Bad Request\r\n" -#define HTTP_404_NF "HTTP/1.0 404 Not Found\r\n" -#define HTTP_411_LR "HTTP/1.0 411 Length Required\r\n" -#define HTTP_413_TL "HTTP/1.0 413 Request Entity Too Large\r\n" -#define HTTP_503_SU "HTTP/1.0 503 Service Unavailable\r\n" -#define CONN_CLOSE "Connection: close\r\n" -/*---------------------------------------------------------------------------*/ -#define SECTION_TAG "div" -#define SECTION_OPEN "<" SECTION_TAG ">" -#define SECTION_CLOSE "" - -#define CONTENT_OPEN "

"
-#define CONTENT_CLOSE "
" -/*---------------------------------------------------------------------------*/ -#define REQUEST_TYPE_GET 1 -#define REQUEST_TYPE_POST 2 -/*---------------------------------------------------------------------------*/ -static const char *NOT_FOUND = "" - "
" - "

404 - file not found

" - "
" - "" - ""; -/*---------------------------------------------------------------------------*/ -/* Page template */ -static const char http_doctype[] = ""; -static const char http_header_200[] = HTTP_200_OK; -static const char http_header_302[] = HTTP_302_FO; -static const char http_header_400[] = HTTP_400_BR; -static const char http_header_404[] = HTTP_404_NF; -static const char http_header_411[] = HTTP_411_LR; -static const char http_header_413[] = HTTP_413_TL; -static const char http_header_503[] = HTTP_503_SU; -static const char http_get[] = "GET "; -static const char http_post[] = "POST "; -static const char http_index_html[] = "/index.html"; -static const char http_html_start[] = ""; -static const char *http_header_srv_str[] = { - "Server: Contiki, ", - BOARD_STRING "\r\n", - NULL -}; - -static const char *http_header_con_close[] = { - CONN_CLOSE, - NULL -}; - -static const char *http_config_css[] = { - "", - NULL -}; -static const char http_head_charset[] = ""; -static const char http_title_start[] = ""; -static const char http_title_end[] = ""; -static const char http_head_end[] = ""; -static const char http_body_start[] = ""; -static const char http_bottom[] = ""; -/*---------------------------------------------------------------------------*/ -static const char http_content_type_html[] = "text/html"; -static const char http_content_type_plain[] = "text/plain"; -/*---------------------------------------------------------------------------*/ -/* For the config page */ -static const char config_div_left[] = "
"; -static const char config_div_right[] = "
"; -static const char config_div_close[] = "
"; -/*---------------------------------------------------------------------------*/ -static char generate_index(struct httpd_state *s); -static char generate_config(struct httpd_state *s); -/*---------------------------------------------------------------------------*/ -typedef struct page { - struct page *next; - char *filename; - char *title; - char (*script)(struct httpd_state *s); -} page_t; - -static page_t http_index_page = { - NULL, - "index.html", - "Index", - generate_index, -}; - -static page_t http_dev_cfg_page = { - NULL, - "config.html", - "Device Config", - generate_config, -}; - -#if WEB_DEMO_NET_UART -static char generate_net_uart_config(struct httpd_state *s); - -static page_t http_net_cfg_page = { - NULL, - "netu.html", - "Net-UART Config", - generate_net_uart_config, -}; -#endif - -#if WEB_DEMO_MQTT_CLIENT -static char generate_mqtt_config(struct httpd_state *s); - -static page_t http_mqtt_cfg_page = { - NULL, - "mqtt.html", - "MQTT/IBM Cloud Config", - generate_mqtt_config, -}; -#endif -/*---------------------------------------------------------------------------*/ -#define IBM_QUICKSTART_LINK_LEN 128 -static char http_mqtt_a[IBM_QUICKSTART_LINK_LEN]; -/*---------------------------------------------------------------------------*/ -static uint16_t numtimes; -static const httpd_simple_post_handler_t *handler; -/*---------------------------------------------------------------------------*/ -static uint8_t config_ok; -process_event_t httpd_simple_event_new_config; -/*---------------------------------------------------------------------------*/ -struct httpd_state; -typedef char (*httpd_simple_script_t)(struct httpd_state *s); - -struct httpd_state { - char buf[HTTPD_SIMPLE_MAIN_BUF_SIZE]; - char tmp_buf[TMP_BUF_SIZE]; - struct timer timer; - struct psock sin, sout; - int blen; - const char **ptr; - const web_demo_sensor_reading_t *reading; - const page_t *page; - uip_ds6_route_t *r; - uip_ds6_nbr_t *nbr; - httpd_simple_script_t script; - int content_length; - int tmp_buf_len; - int tmp_buf_copied; - char filename[HTTPD_PATHLEN]; - char inputbuf[HTTPD_INBUF_LEN]; - struct pt outputpt; - struct pt generate_pt; - struct pt top_matter_pt; - char state; - char request_type; - char return_code; -}; -/*---------------------------------------------------------------------------*/ -LIST(post_handlers); -LIST(pages_list); -MEMB(conns, struct httpd_state, CONNS); -/*---------------------------------------------------------------------------*/ -#define HEX_TO_INT(x) (isdigit(x) ? x - '0' : x - 'W') -static size_t -url_unescape(const char *src, size_t srclen, char *dst, size_t dstlen) -{ - size_t i, j; - int a, b; - - for(i = j = 0; i < srclen && j < dstlen - 1; i++, j++) { - if(src[i] == '%' && isxdigit(*(unsigned char *)(src + i + 1)) - && isxdigit(*(unsigned char *)(src + i + 2))) { - a = tolower(*(unsigned char *)(src + i + 1)); - b = tolower(*(unsigned char *)(src + i + 2)); - dst[j] = ((HEX_TO_INT(a) << 4) | HEX_TO_INT(b)) & 0xff; - i += 2; - } else if(src[i] == '+') { - dst[j] = ' '; - } else { - dst[j] = src[i]; - } - } - - dst[j] = '\0'; - - return i == srclen; -} -/*---------------------------------------------------------------------------*/ -void -httpd_simple_register_post_handler(httpd_simple_post_handler_t *h) -{ - list_add(post_handlers, h); -} -/*---------------------------------------------------------------------------*/ -static void -get_neighbour_state_text(char *buf, uint8_t state) -{ - switch(state) { - case NBR_INCOMPLETE: - memcpy(buf, "INCOMPLETE", strlen("INCOMPLETE")); - break; - case NBR_REACHABLE: - memcpy(buf, "REACHABLE", strlen("REACHABLE")); - break; - case NBR_STALE: - memcpy(buf, "STALE", strlen("STALE")); - break; - case NBR_DELAY: - memcpy(buf, "DELAY", strlen("DELAY")); - break; - case NBR_PROBE: - memcpy(buf, "NBR_PROBE", strlen("NBR_PROBE")); - break; - } -} -/*---------------------------------------------------------------------------*/ -static -PT_THREAD(enqueue_chunk(struct httpd_state *s, uint8_t immediate, - const char *format, ...)) -{ - va_list ap; - - PSOCK_BEGIN(&s->sout); - - va_start(ap, format); - - s->tmp_buf_len = vsnprintf(s->tmp_buf, TMP_BUF_SIZE, format, ap); - - va_end(ap); - - if(s->blen + s->tmp_buf_len < HTTPD_SIMPLE_MAIN_BUF_SIZE) { - /* Enough space for the entire chunk. Copy over */ - memcpy(&s->buf[s->blen], s->tmp_buf, s->tmp_buf_len); - s->blen += s->tmp_buf_len; - } else { - memcpy(&s->buf[s->blen], s->tmp_buf, HTTPD_SIMPLE_MAIN_BUF_SIZE - s->blen); - s->tmp_buf_copied = HTTPD_SIMPLE_MAIN_BUF_SIZE - s->blen; - s->blen = HTTPD_SIMPLE_MAIN_BUF_SIZE; - PSOCK_SEND(&s->sout, (uint8_t *)s->buf, s->blen); - s->blen = 0; - if(s->tmp_buf_copied < s->tmp_buf_len) { - memcpy(s->buf, &s->tmp_buf[s->tmp_buf_copied], - s->tmp_buf_len - s->tmp_buf_copied); - s->blen += s->tmp_buf_len - s->tmp_buf_copied; - } - } - - if(immediate != 0 && s->blen > 0) { - PSOCK_SEND(&s->sout, (uint8_t *)s->buf, s->blen); - s->blen = 0; - } - - PSOCK_END(&s->sout); -} -/*---------------------------------------------------------------------------*/ -static -PT_THREAD(generate_top_matter(struct httpd_state *s, const char *title, - const char **css)) -{ - - PT_BEGIN(&s->top_matter_pt); - - PT_WAIT_THREAD(&s->top_matter_pt, enqueue_chunk(s, 0, http_doctype)); - PT_WAIT_THREAD(&s->top_matter_pt, enqueue_chunk(s, 0, http_html_start)); - PT_WAIT_THREAD(&s->top_matter_pt, enqueue_chunk(s, 0, http_title_start)); - - PT_WAIT_THREAD(&s->top_matter_pt, enqueue_chunk(s, 0, title)); - PT_WAIT_THREAD(&s->top_matter_pt, enqueue_chunk(s, 0, http_title_end)); - - if(css != NULL) { - for(s->ptr = css; *(s->ptr) != NULL; s->ptr++) { - PT_WAIT_THREAD(&s->top_matter_pt, enqueue_chunk(s, 0, *(s->ptr))); - } - } - - PT_WAIT_THREAD(&s->top_matter_pt, enqueue_chunk(s, 0, http_head_charset)); - PT_WAIT_THREAD(&s->top_matter_pt, enqueue_chunk(s, 0, http_head_end)); - PT_WAIT_THREAD(&s->top_matter_pt, enqueue_chunk(s, 0, http_body_start)); - - /* Links */ - PT_WAIT_THREAD(&s->top_matter_pt, - enqueue_chunk(s, 0, SECTION_OPEN "

")); - - s->page = list_head(pages_list); - PT_WAIT_THREAD(&s->top_matter_pt, - enqueue_chunk(s, 0, "[ %s ]", - s->page->filename, s->page->title)); - - for(s->page = s->page->next; s->page != NULL; s->page = s->page->next) { - PT_WAIT_THREAD(&s->top_matter_pt, - enqueue_chunk(s, 0, " | [ %s ]", - s->page->filename, s->page->title)); - } - -#if WEB_DEMO_MQTT_CLIENT - PT_WAIT_THREAD(&s->top_matter_pt, - enqueue_chunk(s, 0, " | %s", http_mqtt_a)); -#endif - PT_WAIT_THREAD(&s->top_matter_pt, - enqueue_chunk(s, 0, "

" SECTION_CLOSE)); - - PT_END(&s->top_matter_pt); -} -/*---------------------------------------------------------------------------*/ -static -PT_THREAD(generate_index(struct httpd_state *s)) -{ - char ipaddr_buf[IPADDR_BUF_LEN]; /* Intentionally on stack */ - - PT_BEGIN(&s->generate_pt); - - /* Generate top matter (doctype, title, nav links etc) */ - PT_WAIT_THREAD(&s->generate_pt, - generate_top_matter(s, http_index_page.title, NULL)); - - /* ND Cache */ - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, SECTION_OPEN "Neighbors" CONTENT_OPEN)); - - for(s->nbr = nbr_table_head(ds6_neighbors); s->nbr != NULL; - s->nbr = nbr_table_next(ds6_neighbors, s->nbr)) { - - PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "\n")); - - memset(ipaddr_buf, 0, IPADDR_BUF_LEN); - web_demo_ipaddr_sprintf(ipaddr_buf, IPADDR_BUF_LEN, &s->nbr->ipaddr); - PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "%s", ipaddr_buf)); - - memset(ipaddr_buf, 0, IPADDR_BUF_LEN); - get_neighbour_state_text(ipaddr_buf, s->nbr->state); - PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, " %s", ipaddr_buf)); - } - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, CONTENT_CLOSE SECTION_CLOSE)); - - /* Default Route */ - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, - SECTION_OPEN "Default Route" CONTENT_OPEN)); - - memset(ipaddr_buf, 0, IPADDR_BUF_LEN); - web_demo_ipaddr_sprintf(ipaddr_buf, IPADDR_BUF_LEN, - uip_ds6_defrt_choose()); - PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "%s", ipaddr_buf)); - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, CONTENT_CLOSE SECTION_CLOSE)); - - /* Routes */ - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, SECTION_OPEN "Routes" CONTENT_OPEN)); - - for(s->r = uip_ds6_route_head(); s->r != NULL; - s->r = uip_ds6_route_next(s->r)) { - PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "\n")); - - memset(ipaddr_buf, 0, IPADDR_BUF_LEN); - web_demo_ipaddr_sprintf(ipaddr_buf, IPADDR_BUF_LEN, &s->r->ipaddr); - PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "%s", ipaddr_buf)); - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, " / %u via ", s->r->length)); - - memset(ipaddr_buf, 0, IPADDR_BUF_LEN); - web_demo_ipaddr_sprintf(ipaddr_buf, IPADDR_BUF_LEN, - uip_ds6_route_nexthop(s->r)); - PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "%s", ipaddr_buf)); - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, - ", lifetime=%lus", s->r->state.lifetime)); - } - - PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, - CONTENT_CLOSE SECTION_CLOSE)); - - /* Sensors */ - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, SECTION_OPEN "Sensors" CONTENT_OPEN)); - - for(s->reading = web_demo_sensor_first(); - s->reading != NULL; s->reading = s->reading->next) { - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "\n%s = %s %s", s->reading->descr, - s->reading->publish ? s->reading->converted : "N/A", - s->reading->units)); - } - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, CONTENT_CLOSE SECTION_CLOSE)); - - /* Footer */ - PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, SECTION_OPEN)); - PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "Page hits: %u
", - ++numtimes)); - PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "Uptime: %lu secs
", - clock_seconds())); - PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, SECTION_CLOSE)); - - PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 1, http_bottom)); - - PT_END(&s->generate_pt); -} -/*---------------------------------------------------------------------------*/ -static -PT_THREAD(generate_config(struct httpd_state *s)) -{ - PT_BEGIN(&s->generate_pt); - - /* Generate top matter (doctype, title, nav links etc) */ - PT_WAIT_THREAD(&s->generate_pt, - generate_top_matter(s, http_dev_cfg_page.title, - http_config_css)); - - /* Sensor Settings */ - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "

Sensors

")); - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, - "
generate_pt, - enqueue_chunk(s, 0, "method=\"post\" enctype=\"")); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "application/x-www-form-urlencoded\" ")); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "accept-charset=\"UTF-8\">")); - - for(s->reading = web_demo_sensor_first(); - s->reading != NULL; s->reading = s->reading->next) { - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "%s%s:%s%s", config_div_left, - s->reading->descr, config_div_close, - config_div_right)); - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "generate_pt, - enqueue_chunk(s, 0, "title=\"On\" name=\"%s\"%s>", - s->reading->form_field, - s->reading->publish ? " Checked" : "")); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "generate_pt, - enqueue_chunk(s, 0, "title=\"Off\" name=\"%s\"%s>%s", - s->reading->form_field, - s->reading->publish ? "" : " Checked", - config_div_close)); - } - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, - "")); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "
")); - - /* RSSI measurements */ -#if WEB_DEMO_READ_PARENT_RSSI - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "

RSSI Probing

")); - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, - "
generate_pt, - enqueue_chunk(s, 0, "method=\"post\" enctype=\"")); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "application/x-www-form-urlencoded\" ")); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "accept-charset=\"UTF-8\">")); - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "%sPeriod (secs):%s", - config_div_left, config_div_close)); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "%sgenerate_pt, - enqueue_chunk(s, 0, "value=\"%lu\" ", - (clock_time_t) - (web_demo_config.def_rt_ping_interval - / CLOCK_SECOND))); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, - "min=\"" RSSI_INT_MIN "\" " - "max=\"" RSSI_INT_MAX "\" " - "name=\"ping_interval\">%s", - config_div_close)); - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, - "")); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "
")); -#endif - - /* Actions */ - PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, "

Actions

")); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, - "
generate_pt, - enqueue_chunk(s, 0, "method=\"post\" enctype=\"")); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "application/x-www-form-urlencoded\" ")); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "accept-charset=\"UTF-8\">")); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "")); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "")); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "
")); - - PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 1, http_bottom)); - - PT_END(&s->generate_pt); -} -/*---------------------------------------------------------------------------*/ -#if WEB_DEMO_MQTT_CLIENT -static -PT_THREAD(generate_mqtt_config(struct httpd_state *s)) -{ - PT_BEGIN(&s->generate_pt); - - /* Generate top matter (doctype, title, nav links etc) */ - PT_WAIT_THREAD(&s->generate_pt, - generate_top_matter(s, http_mqtt_cfg_page.title, - http_config_css)); - - /* MQTT client settings */ - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "

%s

", http_mqtt_cfg_page.title)); - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, - "
generate_pt, - enqueue_chunk(s, 0, "method=\"post\" enctype=\"")); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "application/x-www-form-urlencoded\" ")); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "accept-charset=\"UTF-8\">")); - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "%sType ID:%s", config_div_left, - config_div_close)); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "%sgenerate_pt, - enqueue_chunk(s, 0, "value=\"%s\" ", - web_demo_config.mqtt_config.type_id)); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "name=\"type_id\">%s", config_div_close)); - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "%sOrg ID:%s", config_div_left, - config_div_close)); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "%sgenerate_pt, - enqueue_chunk(s, 0, "value=\"%s\" ", - web_demo_config.mqtt_config.org_id)); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "name=\"org_id\">%s", config_div_close)); - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "%sAuth Token:%s", config_div_left, - config_div_close)); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "%sgenerate_pt, - enqueue_chunk(s, 0, "value=\"\" ")); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "name=\"auth_token\">%s", - config_div_close)); - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "%sCommand Type:%s", config_div_left, - config_div_close)); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "%sgenerate_pt, - enqueue_chunk(s, 0, "value=\"%s\" ", - web_demo_config.mqtt_config.cmd_type)); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "name=\"cmd_type\">%s", - config_div_close)); - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "%sEvent Type ID:%s", config_div_left, - config_div_close)); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "%sgenerate_pt, - enqueue_chunk(s, 0, "value=\"%s\" ", - web_demo_config.mqtt_config.event_type_id)); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "name=\"event_type_id\">%s", - config_div_close)); - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "%sInterval (secs):%s", - config_div_left, config_div_close)); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "%sgenerate_pt, - enqueue_chunk(s, 0, "value=\"%lu\" ", - (clock_time_t) - (web_demo_config.mqtt_config.pub_interval - / CLOCK_SECOND))); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, - "min=\"" PUB_INT_MIN "\" " - "max=\"" PUB_INT_MAX "\" " - "name=\"interval\">%s", - config_div_close)); - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "%sBroker IP:%s", config_div_left, - config_div_close)); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "%sgenerate_pt, - enqueue_chunk(s, 0, "value=\"%s\" ", - web_demo_config.mqtt_config.broker_ip)); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "name=\"broker_ip\">%s", - config_div_close)); - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "%sBroker Port:%s", config_div_left, - config_div_close)); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "%sgenerate_pt, - enqueue_chunk(s, 0, "value=\"%d\" ", - web_demo_config.mqtt_config.broker_port)); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "min=\"1\" max=\"65535\" " - "name=\"broker_port\">%s", - config_div_close)); - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, - "")); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "
")); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, - "
generate_pt, - enqueue_chunk(s, 0, "method=\"post\" enctype=\"")); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "application/x-www-form-urlencoded\" ")); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "accept-charset=\"UTF-8\">")); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "")); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "")); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "
")); - - PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 1, http_bottom)); - - PT_END(&s->generate_pt); -} -#endif -/*---------------------------------------------------------------------------*/ -#if WEB_DEMO_NET_UART -static -PT_THREAD(generate_net_uart_config(struct httpd_state *s)) -{ - - PT_BEGIN(&s->generate_pt); - - /* Generate top matter (doctype, title, nav links etc) */ - PT_WAIT_THREAD(&s->generate_pt, - generate_top_matter(s, http_net_cfg_page.title, - http_config_css)); - - /* Net-UART settings */ - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "

%s

", http_net_cfg_page.title)); - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, - "
generate_pt, - enqueue_chunk(s, 0, "method=\"post\" enctype=\"")); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "application/x-www-form-urlencoded\" ")); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "accept-charset=\"UTF-8\">")); - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "%sRemote IPv6:%s", config_div_left, - config_div_close)); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "%sgenerate_pt, - enqueue_chunk(s, 0, "value=\"%s\" ", - web_demo_config.net_uart.remote_address)); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "name=\"net_uart_ip\">%s", - config_div_close)); - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "%sRemote Port:%s", config_div_left, - config_div_close)); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "%sgenerate_pt, - enqueue_chunk(s, 0, "value=\"%u\" ", - web_demo_config.net_uart.remote_port)); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "min=\"1\" max=\"65535\" " - "name=\"net_uart_port\">%s", - config_div_close)); - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "%s%s:%s%s", config_div_left, - "Enable", config_div_close, - config_div_right)); - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "generate_pt, - enqueue_chunk(s, 0, "title=\"On\" name=\"net_uart_on\"%s>", - web_demo_config.net_uart.enable ? - " Checked" : "")); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "generate_pt, - enqueue_chunk(s, 0, "title=\"Off\" name=\"net_uart_on\"" - "%s>%s", - web_demo_config.net_uart.enable ? - "" : " Checked", config_div_close)); - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, - "")); - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "
")); - - PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 1, http_bottom)); - - PT_END(&s->generate_pt); -} -#endif -/*---------------------------------------------------------------------------*/ -static void -lock_obtain(struct httpd_state *s) -{ - if(lock == NULL) { - lock = s; - } -} -/*---------------------------------------------------------------------------*/ -static void -lock_release(struct httpd_state *s) -{ - if(lock == s) { - lock = NULL; - } -} -/*---------------------------------------------------------------------------*/ -static void -parse_post_request_chunk(char *buf, int buf_len, int last_chunk) -{ - int i; - int finish; - - for(i = 0; i < buf_len; i++) { - switch(state) { - case PARSE_POST_STATE_INIT: - state = PARSE_POST_STATE_MORE; - /* continue */ - case PARSE_POST_STATE_MORE: - memset(key, 0, PARSE_POST_BUF_SIZES); - memset(val, 0, PARSE_POST_BUF_SIZES); - memset(val_escaped, 0, PARSE_POST_BUF_SIZES); - key_len = 0; - val_len = 0; - state = PARSE_POST_STATE_READING_KEY; - /* continue */ - case PARSE_POST_STATE_READING_KEY: - if(buf[i] == ISO_equal) { - state = PARSE_POST_STATE_READING_VAL; - } else if(buf[i] == ISO_amp) { - /* Don't accept an amp while reading a key */ - state = PARSE_POST_STATE_ERROR; - } else { - /* Make sure we don't overshoot key's boundary */ - if(key_len <= PARSE_POST_MAX_POS) { - key[key_len] = buf[i]; - key_len++; - } else { - /* Not enough space for the key. Abort */ - state = PARSE_POST_STATE_ERROR; - } - } - break; - case PARSE_POST_STATE_READING_VAL: - finish = 0; - if(buf[i] == ISO_amp) { - finish = 1; - } else if(buf[i] == ISO_equal) { - /* Don't accept an '=' while reading a val */ - state = PARSE_POST_STATE_ERROR; - } else { - /* Make sure we don't overshoot key's boundary */ - if(val_len <= PARSE_POST_MAX_POS) { - val[val_len] = buf[i]; - val_len++; - /* Last character of the last chunk */ - if((i == buf_len - 1) && (last_chunk == 1)) { - finish = 1; - } - } else { - /* Not enough space for the value. Abort */ - state = PARSE_POST_STATE_ERROR; - } - } - - if(finish == 1) { - /* - * Done reading a key=value pair, either because we encountered an amp - * or because we reached the end of the message body. - * - * First, unescape the value. - * - * Then invoke handlers. We will bail out with PARSE_POST_STATE_ERROR, - * unless the key-val gets correctly processed - */ - url_unescape(val, val_len, val_escaped, PARSE_POST_BUF_SIZES); - val_len = strlen(val_escaped); - - for(handler = list_head(post_handlers); handler != NULL; - handler = list_item_next((void *)handler)) { - if(handler->handler != NULL) { - finish = handler->handler(key, key_len, val_escaped, val_len); - } - if(finish == HTTPD_SIMPLE_POST_HANDLER_ERROR) { - state = PARSE_POST_STATE_ERROR; - break; - } else if(finish == HTTPD_SIMPLE_POST_HANDLER_OK) { - /* Restart the state machine to expect the next pair */ - state = PARSE_POST_STATE_MORE; - - /* - * At least one handler returned OK, therefore we must generate a - * new config event when we're done. - */ - config_ok = 1; - break; - } - /* Else, continue */ - } - } - break; - case PARSE_POST_STATE_ERROR: - /* If we entered the error state earlier, do nothing */ - return; - default: - break; - } - } -} -/*---------------------------------------------------------------------------*/ -static httpd_simple_script_t -get_script(const char *name) -{ - page_t *page; - - for(page = list_head(pages_list); page != NULL; - page = list_item_next(page)) { - if(strncmp(name, page->filename, strlen(page->filename)) == 0) { - return page->script; - } - } - - return NULL; -} -/*---------------------------------------------------------------------------*/ -static -PT_THREAD(send_string(struct httpd_state *s, const char *str)) -{ - PSOCK_BEGIN(&s->sout); - - SEND_STRING(&s->sout, str); - - PSOCK_END(&s->sout); -} -/*---------------------------------------------------------------------------*/ -static -PT_THREAD(send_headers(struct httpd_state *s, const char *statushdr, - const char *content_type, const char *redir, - const char **additional)) -{ - PT_BEGIN(&s->generate_pt); - - PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, statushdr)); - - for(s->ptr = http_header_srv_str; *(s->ptr) != NULL; s->ptr++) { - PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, *(s->ptr))); - } - - if(redir) { - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "Location: %s\r\n", redir)); - } - - if(additional) { - for(s->ptr = additional; *(s->ptr) != NULL; s->ptr++) { - PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 0, *(s->ptr))); - } - } - - PT_WAIT_THREAD(&s->generate_pt, - enqueue_chunk(s, 0, "Content-type: %s; ", content_type)); - - PT_WAIT_THREAD(&s->generate_pt, enqueue_chunk(s, 1, "charset=UTF-8\r\n\r\n")); - - PT_END(&s->generate_pt); -} -/*---------------------------------------------------------------------------*/ -static -PT_THREAD(handle_output(struct httpd_state *s)) -{ - PT_BEGIN(&s->outputpt); - - s->script = NULL; - - PT_INIT(&s->generate_pt); - PT_INIT(&s->top_matter_pt); - - if(s->request_type == REQUEST_TYPE_POST) { - if(s->return_code == RETURN_CODE_OK) { - PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_302, - http_content_type_plain, - s->filename, - NULL)); - } else if(s->return_code == RETURN_CODE_LR) { - PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_411, - http_content_type_plain, - NULL, - http_header_con_close)); - PT_WAIT_THREAD(&s->outputpt, send_string(s, "Content-Length Required\n")); - } else if(s->return_code == RETURN_CODE_TL) { - PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_413, - http_content_type_plain, - NULL, - http_header_con_close)); - PT_WAIT_THREAD(&s->outputpt, send_string(s, "Content-Length too Large\n")); - } else if(s->return_code == RETURN_CODE_SU) { - PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_503, - http_content_type_plain, - NULL, - http_header_con_close)); - PT_WAIT_THREAD(&s->outputpt, send_string(s, "Service Unavailable\n")); - } else { - PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_400, - http_content_type_plain, - NULL, - http_header_con_close)); - PT_WAIT_THREAD(&s->outputpt, send_string(s, "Bad Request\n")); - } - } else if(s->request_type == REQUEST_TYPE_GET) { - s->script = get_script(&s->filename[1]); - if(s->script == NULL) { - strncpy(s->filename, "/notfound.html", sizeof(s->filename)); - PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_404, - http_content_type_html, - NULL, - http_header_con_close)); - PT_WAIT_THREAD(&s->outputpt, - send_string(s, NOT_FOUND)); - uip_close(); - PT_EXIT(&s->outputpt); - } else { - PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_200, - http_content_type_html, - NULL, - http_header_con_close)); - PT_WAIT_THREAD(&s->outputpt, s->script(s)); - } - } - s->script = NULL; - PSOCK_CLOSE(&s->sout); - PT_END(&s->outputpt); -} -/*---------------------------------------------------------------------------*/ -static -PT_THREAD(handle_input(struct httpd_state *s)) -{ - PSOCK_BEGIN(&s->sin); - - PSOCK_READTO(&s->sin, ISO_space); - - if(strncasecmp(s->inputbuf, http_get, 4) == 0) { - s->request_type = REQUEST_TYPE_GET; - PSOCK_READTO(&s->sin, ISO_space); - - if(s->inputbuf[0] != ISO_slash) { - PSOCK_CLOSE_EXIT(&s->sin); - } - - if(s->inputbuf[1] == ISO_space) { - strncpy(s->filename, http_index_html, sizeof(s->filename)); - } else { - s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0; - strncpy(s->filename, s->inputbuf, sizeof(s->filename)); - } - } else if(strncasecmp(s->inputbuf, http_post, 5) == 0) { - s->request_type = REQUEST_TYPE_POST; - PSOCK_READTO(&s->sin, ISO_space); - - if(s->inputbuf[0] != ISO_slash) { - PSOCK_CLOSE_EXIT(&s->sin); - } - - s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0; - strncpy(s->filename, s->inputbuf, sizeof(s->filename)); - - /* POST: Read out the rest of the line and ignore it */ - PSOCK_READTO(&s->sin, ISO_nl); - - /* - * Start parsing headers. We look for Content-Length and ignore everything - * else until we hit the start of the message body. - * - * We will return 411 if the client doesn't send Content-Length and 413 - * if Content-Length is too high - */ - s->content_length = 0; - s->return_code = RETURN_CODE_LR; - do { - s->inputbuf[PSOCK_DATALEN(&s->sin)] = 0; - /* We anticipate a content length */ - if((PSOCK_DATALEN(&s->sin) > 14) && - strncasecmp(s->inputbuf, "Content-Length:", 15) == 0) { - char *val_start = &s->inputbuf[15]; - s->content_length = atoi(val_start); - - /* So far so good */ - s->return_code = RETURN_CODE_OK; - } - PSOCK_READTO(&s->sin, ISO_nl); - } while(PSOCK_DATALEN(&s->sin) != 2); - - /* - * Done reading headers. - * Reject content length greater than CONTENT_LENGTH_MAX bytes - */ - if(s->content_length > CONTENT_LENGTH_MAX) { - s->content_length = 0; - s->return_code = RETURN_CODE_TL; - } - - if(s->return_code == RETURN_CODE_OK) { - /* Acceptable Content Length. Try to obtain a lock */ - lock_obtain(s); - - if(lock == s) { - state = PARSE_POST_STATE_INIT; - } else { - s->return_code = RETURN_CODE_SU; - } - } - - /* Parse the message body, unless we have detected an error. */ - while(s->content_length > 0 && lock == s && - s->return_code == RETURN_CODE_OK) { - PSOCK_READBUF_LEN(&s->sin, s->content_length); - s->content_length -= PSOCK_DATALEN(&s->sin); - - /* Parse the message body */ - parse_post_request_chunk(s->inputbuf, PSOCK_DATALEN(&s->sin), - (s->content_length == 0)); - if(state == PARSE_POST_STATE_ERROR) { - /* Could not parse: Bad Request and stop parsing */ - s->return_code = RETURN_CODE_BR; - } - } - - /* - * Done. If our return code is OK but the state machine is not in - * STATE_MORE, it means that the message body ended half-way reading a key - * or value. Set 'Bad Request' - */ - if(s->return_code == RETURN_CODE_OK && state != PARSE_POST_STATE_MORE) { - s->return_code = RETURN_CODE_BR; - } - - /* If the flag is set, we had at least 1 configuration value accepted */ - if(config_ok) { - process_post(PROCESS_BROADCAST, httpd_simple_event_new_config, NULL); - } - config_ok = 0; - - lock_release(s); - } else { - PSOCK_CLOSE_EXIT(&s->sin); - } - - s->state = STATE_OUTPUT; - - while(1) { - PSOCK_READTO(&s->sin, ISO_nl); - } - - PSOCK_END(&s->sin); -} -/*---------------------------------------------------------------------------*/ -static void -handle_connection(struct httpd_state *s) -{ - handle_input(s); - if(s->state == STATE_OUTPUT) { - handle_output(s); - } -} -/*---------------------------------------------------------------------------*/ -static void -appcall(void *state) -{ - struct httpd_state *s = (struct httpd_state *)state; - - if(uip_closed() || uip_aborted() || uip_timedout()) { - if(s != NULL) { - memset(s, 0, sizeof(struct httpd_state)); - memb_free(&conns, s); - } - } else if(uip_connected()) { - s = (struct httpd_state *)memb_alloc(&conns); - if(s == NULL) { - uip_abort(); - return; - } - tcp_markconn(uip_conn, s); - PSOCK_INIT(&s->sin, (uint8_t *)s->inputbuf, sizeof(s->inputbuf) - 1); - PSOCK_INIT(&s->sout, (uint8_t *)s->inputbuf, sizeof(s->inputbuf) - 1); - PT_INIT(&s->outputpt); - s->script = NULL; - s->state = STATE_WAITING; - timer_set(&s->timer, CLOCK_SECOND * 10); - handle_connection(s); - } else if(s != NULL) { - if(uip_poll()) { - if(timer_expired(&s->timer)) { - uip_abort(); - memset(s, 0, sizeof(struct httpd_state)); - memb_free(&conns, s); - } - } else { - timer_restart(&s->timer); - } - handle_connection(s); - } else { - uip_abort(); - } -} -/*---------------------------------------------------------------------------*/ -static void -init(void) -{ - tcp_listen(UIP_HTONS(80)); - memb_init(&conns); - - list_add(pages_list, &http_index_page); - list_add(pages_list, &http_dev_cfg_page); - -#if WEB_DEMO_NET_UART - list_add(pages_list, &http_net_cfg_page); -#endif - -#if WEB_DEMO_MQTT_CLIENT - list_add(pages_list, &http_mqtt_cfg_page); -#endif -} -/*---------------------------------------------------------------------------*/ -PROCESS_THREAD(httpd_simple_process, ev, data) -{ - PROCESS_BEGIN(); - - printf("CC26XX Web Server\n"); - - httpd_simple_event_new_config = process_alloc_event(); - - init(); - - snprintf(http_mqtt_a, IBM_QUICKSTART_LINK_LEN, - "[ IBM Quickstart ]", - linkaddr_node_addr.u8[0], linkaddr_node_addr.u8[1], - linkaddr_node_addr.u8[2], linkaddr_node_addr.u8[5], - linkaddr_node_addr.u8[6], linkaddr_node_addr.u8[7]); - - while(1) { - PROCESS_WAIT_EVENT_UNTIL(ev == tcpip_event); - appcall(data); - } - - PROCESS_END(); -} -/*---------------------------------------------------------------------------*/ -/** - * @} - */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/httpd-simple.h b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/httpd-simple.h deleted file mode 100644 index 810fd4782..000000000 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/httpd-simple.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2010, Swedish Institute of Computer Science. - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - * - */ -/*---------------------------------------------------------------------------*/ -/** - * \file - * Header file for the HTTPD of the CC13xx/CC26xx web demo example. - * \author - * Adam Dunkels - * Niclas Finne - * Joakim Eriksson - * Texas Instruments Incorporated - http://www.ti.com/ - */ -/*---------------------------------------------------------------------------*/ -#ifndef HTTPD_SIMPLE_H_ -#define HTTPD_SIMPLE_H_ -/*---------------------------------------------------------------------------*/ -#include "contiki-net.h" -#include "sys/process.h" -/*---------------------------------------------------------------------------*/ -#include "web-demo.h" -/*---------------------------------------------------------------------------*/ -/* Ideally a multiple of TCP_MSS */ -#ifdef HTTPD_SIMPLE_CONF_MAIN_BUF_SIZE -#define HTTPD_SIMPLE_MAIN_BUF_SIZE HTTPD_SIMPLE_CONF_MAIN_BUF_SIZE -#else -#define HTTPD_SIMPLE_MAIN_BUF_SIZE UIP_TCP_MSS -#endif -/*---------------------------------------------------------------------------*/ -#define HTTPD_PATHLEN 16 -#define HTTPD_INBUF_LEN (HTTPD_PATHLEN + 10) - -#define TMP_BUF_SIZE (UIP_TCP_MSS + 1) -/*---------------------------------------------------------------------------*/ -/* POST request handlers */ -#define HTTPD_SIMPLE_POST_HANDLER_OK 1 -#define HTTPD_SIMPLE_POST_HANDLER_UNKNOWN 0 -#define HTTPD_SIMPLE_POST_HANDLER_ERROR 0xFFFFFFFF - -/** - * \brief Datatype for a handler which can process incoming POST requests - * \param key The configuration key to be updated - * \param key_len The length of the key argument - * \param val The new configuration value for key - * \param val_len The length of the value argument - * - * \return 1: HTTPD_SIMPLE_POST_HANDLER_OK if the function can handle the - * request, HTTPD_SIMPLE_POST_HANDLER_UNKNOWN if it does not know how to handle - * it. HTTPD_SIMPLE_POST_HANDLER_ERROR if it does know how to handle it but - * the request was malformed. - */ -typedef struct httpd_simple_post_handler { - struct httpd_simple_post_handler *next; - int (*handler)(char *key, int key_len, char *val, int val_len); -} httpd_simple_post_handler_t; - -/* Declare a handler */ -#define HTTPD_SIMPLE_POST_HANDLER(name, fp) \ - httpd_simple_post_handler_t name##_handler = { NULL, fp } - -/** - * \brief Register a handler for POST requests - * \param h A pointer to the handler structure - */ -void httpd_simple_register_post_handler(httpd_simple_post_handler_t *h); -/*---------------------------------------------------------------------------*/ -/* - * An event generated by the HTTPD when a new configuration request has been - * received - */ -extern process_event_t httpd_simple_event_new_config; -/*---------------------------------------------------------------------------*/ -PROCESS_NAME(httpd_simple_process); -/*---------------------------------------------------------------------------*/ -#endif /* HTTPD_SIMPLE_H_ */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/6lbr-web.png b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/6lbr-web.png deleted file mode 100644 index 5308c412bc183fe3f62930fec950a1029ebc036b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 81741 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 LdQl>7^!EP%AFu2O diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/ibm-watson-iot-platform-tls-optional.png b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/ibm-watson-iot-platform-tls-optional.png deleted file mode 100644 index 93c98624fddeefc38f66885bb184589c6a6c31e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 86462 zcmdqIhd-O&`#-K#RaJBtt=UplT2zTyqZG9_H4<&L_TDQ}RkT&q-g^sDH9|xbwOV3E z5TjON2eC(d)7R_s`MiJcf8lpO9>}?!oOAATjdNYk>v@0D*Hve@%zl}Qii$zw`7=W* zDq0W~)%oK~7b$muB?4)bKj*v*)s?BL(45PZ#s#~lI!~#ns$=O-UeQq6bneg1y{M?J zrvLppSBwsUQBj>0X*_#s>_JTD9PwxX@;jp`YaF7-y= zO<*9Mx4#liqS*n)b&e)U56sZI=eErXAu)%MxBeM6*Zwmz-tz~6Xf8va zFoF8$E6fvSFIM`jj2Ns>)ET3K1N4yT(&^yr^4ZtQ}hts2(omE&1;;HlL z5yN$hr?<_g6+7}`|9yu06G;8rJ7TO={O6Rs8)abU!_Bj4V5?XdcCI68$`GoPE@4Vp zmkGjKP!3=hv`?N*jsaG`4!5+ZSB+vV2R7AbU0z@y#a1uxt&JDF{hjQ9t9SAJD|yQG zIqX-`gVm3GG5Tqb-%h@}ZTkF2-Ce3~b6$c;?l-M~&7&?J$WkN^nGjJVY+0|Z;eauL znmQ~G6_p#8eYb$SRvH$~F}a8O2l(-&cO8-la@H3jp%!(H8`A%d&&*W(=y~9gP@N-2 z=mF>kJ^Ky4Y)Ja)@HRoGKv`Mx$76c|%iG_X4%($;BiQ-~>>? zFXj#`6_Tg}_af+$4gM-871jL+$C1)m5M-z7Mn~KKt+wG4J2IWA&u<1yn64fu#~AoJ zJJva2M}hSLTy16xEV?KEuIS@F`!#Gl)oq1L(NOnmVP>M<^0Ob%lo9i|GNiPZvFI$h z8z^2q_c_{s`o9w>aZpJK0Ax19FzI3kT zD%$P-kuoC;%vy2(+P{x_|Gw|~L=hXvzja+3^0eM{N>(RF0SId$BS0aCZ{f#F1+hD% zenp%N6;*f#gVba$giOluEj`ds6~xb3TtE72XB%?XHMY^XEdM#WjStUs(jIp(Y*aOE z$YQF1xR|~y%3x}{t60A#WApECs(p#m1*4Ug&^JBtzRu+FMz0do!RvC%q-}IoDCGJB z^mkp+aO zUiX2J4@+<%n}Q|YHAXjV$Yp1HIJez)CdDzaa}=8z-s<9kZ7=@Di8a>v%n$>e55Y$s z>Msw~&74at)29oB_?f&S|J}Onp<W3D-(a!c0md$ zftFo;m<8S&cZK9rR-P{FyH={gBySwa>G|B0ps{B$)SD*0J0Gh!k>?I@9MQ*C0ZDH- z&MCR3dbKnf6nYWRt|_INXlQtrV1@0It)Dj>Cu+-ZIoQrGw+h1P*&H|jv}zEX%f9&$ zL6xB9iBs2y26OsJ56v|xR%x>ME6Jo-`<7pJZ?Cosu3jf-Z*33-hS;Bx6{qHNU$sXF z0TH!wdgZAny(fBKGwx~WNZONQH@`PLs{l5c?yg{JRAhb&ZKY?U3@I+5UgeWm-s-TP z;yT$Y?z5ythJ?c$G7jK-A23>BzH0jFVP7ad8m7#b~`zGuG45`egjw&~=L3zRB zmbF{xIeQQCu&k>G3=tLzEpVxcY?(yWAOakKHCROH74*^=qd} zrXcO`&0SA&+;*iY>elcB{~%@-LB;-tuB}Jl#9y%rslP80lhm%{Wj^NPfGU&sBQ;t@9^ud;tFNu$2MSH|0$6-)4R3 zp_{_jKueCP@$vG3JMPB`1_f$9c9AaVU7&9qr{AQ9kV$!B29jWR;HU{h9j!P`RNItT zw$%mg8+nrt2~Gbt#r+_uG~Y6Pa^AOi=8O1n?~}vVd!^k^ zO=`CeZ=2d@ZolN!icnz3)A)r}bzA)rUCPtEJlfAGenYArn;Wz-D8Fx&&xme7%9+0V z=^?H?9kr7tg#)Mhd5X6bYw7R*ONFtWl^Qz#}5j{v*=c?G?DKB4{&>UQZ^g# z_7&%f`_LQrv}8Xp7) z5rO@h@U!3Zkbz1aqL19LTdG6Z{ap*`zEOgguTUk<-0@}Co1TN`!$S{BPs{F^YVmu; z1r*{(mMViL|A-6#<5yC8o<2}T6uN7OsmM698M<3MI!1xvdqQ_J zD2|@lfIL)1cF)ZP!nV)bd981KxS{*;Mdj-$gwNEY(MNauhKfJ}v7c{Ah;Vym+{2My zhUR`>92S!B{7iA(?p?OhyniIaLR&0)$ovb2VkoVr_PcIUG7 z)Sre$>0RJL5R@#7XFAIvksKRXPkg|ugE^f_fa9T|1dYwI+~+7H}@ z>lXwt45x8qQo^uBUl18j>^;E;sG%sKiwJR|&Z&`aF3Btp+I6ATw%JfnvE9szwr#B1 zW-3H<@{6%w?Jc|FzYz-8-unsUbz$$_tEh|QYAL^1EATGn={h`pOBA{J9(R})(2K-B zTWX;f7bv!PHUFUN5WFeK@h<;fX8=RlwZr3A^{jS(_WqeIt~sAK9(c-8Bx1)(gdu!MLO4B>h%h0fQ<5w<#3yV zAl=a)Czsf|z6`zD9pV4<#)JBv%qjsH<<^cxBe6YjRcm60Xp9j;TyKe$&PExVtOpIJ z3swnhV{Okmm7HX|&uVqgn;}saST-;j^rMiPms<6H8@8>467g&llts2+f2?_*oA=oKVfDiToX8S>KmaLDa>26yJP_jFQ!M4rZ z$PT`Y@Y6$m#%C@tBLY7M9XO(1uuIrqH6Fq|ItML#Ep6yCVLQzZaAcko<%hFlpJNCU z;&Lxt|eCi(00!|rxdm-FJ%bmL_6tenT79_AWS+g(hG{Q z76~obV*)P1U}piL^dyfIcTa1nAoDyES=;82f#B&?ntJP){<`+Ow&Et-7`z|(_E@t1 z7^RLL)Frr~yMOHDuJEbs85KIphE2zUPb;>>_PmmB!s6zS!kufrE&Gm#w)?z(nVkZn z=V5!*bdl@Et6>%B#23#s^%qswf{|%pX2cWqCpfex(KOoI($OCCG>_CUtmC8EY61wT zp)tu}UZnMPXVH=|n`Jh2F&XouUcJ8O`+XF{7=&D@b!OY2YP^HHSMeD-;KDXrS2NL1 zXA#+ru~vmD{~jNV>vy_Ch_^qUIjuOv(?iuHtLEtO=Y$RPyDoi4 z_CMQmIx>53AkG{h|D6V+_y#ufj9}R-2mg{N9_6KZ>7jV=jSnfBj3GJKM(=bs_K8je zd8F{HPcB%Rjs_2++imapS^SaT$P|D4D5vI%pZT?Yy@S;TTgb*kKAkBvuP+VN?UuAn zcS_vmdp}h$^J?Y0_W`;>Vd`E}?M}XehTj}J1NuZ&5o+-q#hYz^gL8pw|F%lgLF2Af z7y26)jbWgvb>zz*+Tx_tfIhEYujcbt5BnZ8Tfji_`(msl?kh%%?i+Oje6c&mM-6Oz zw9z&ZOAbJo`q9Lz*jqW-#j66UOiZ-e?3LNedQQ)gEsdUUt0N{Q%^k2zdf(V5IzE4G zL|8o8{#Y|Tzw>&5A^(n^7BK^;UEb6yN*Q8(;SP(IiR0gA2^Dr#by?;H#Y}dEbFYz6v>o(ZME44#zclj9gVL; zWT$f3)A2xOU#)zM{ugEaaqW-rT%XZnl)z?Zd)U>QsTw>-;U3Enz+>zYLz7#&}09yAY zAlO_6sTQ;9N72lTks#NX)6wXyl)65bq#vQ}7*iH-N73xOa{2rfg@~XBeaIAPUo~`p zlsj^2ScgMBovK>^o^wr+KvnW&WGc@Oy$Y*N4EV$?*dEd-_d;EqJN&w z0^F;s_Dy2FdrCVI!X?(P@7>?sFs|7He4TCVnzFYzPgsa{&?lO+zc-; z$9ChqU;WG-cv<-V3FYt|w@_mY=gY)S{&1e_tgxB(u4KD1TpR6svESJ!eC%CCKpUFF zgG;@-|Jt}R-U~79fX8S2Sxo!px-iFzn#ZNVB1kfq())uMSxbFJpG*fldP1e0lX{vS z+8A;_gjPw2C0_TXFFQ?(+vGCr3%Z$n?ul5GJWdLh_xdA9* zQ2WQ#leG4IJ>LARNO>+1x{5H8n_c)`*m;tS+xPY|^zn4#3&jtv{&sHRGu{goZX+2v zR8&f!$7~Hc{`Q)l>1dw9boxK=nUE%2nqfA#c&t=QfNQx(yxp4%WDonXZ?9e)tb|wD zrqA|eJcRslZqx7rcGh;;wgJz4ZVtP3ra9Phi*`%ohmRieXFtMZbXjF+|9Urz0L4)c zi51*yGC7CbP)`_(0$Y!@lyhQ5hg6(3sPOC{?iDLu8I;iKbXsf6m=*Vd_k2qy! zajWKfyXhW}+dxRPCQxT+R?O9R>E+q#z_~s)PlndSOTL}7jv4j8qmo~$`@2P1Ocp2W z(EhQfzaBA^MBdvV;UJ+g_#@D(NVeVXUwno7u6WM-RY`lydr zqbAwhyH3jV-+0t~O1M+5uy|Fzeon#fAY-Pashy1eBHsJNcI=73{?G`{FSNeZoO%S+ zrYp?Yay}!qcKRt>Wqb1Rs@l3YNUq63=LQ}W?{f#sfZOQd-s=VZIY~$wm2IP$nKT2Z zZVld)+SzoYm8z(5`%!yXav5OU#c;S$!ynI^DC8ycn=WLYeE{{|SA=}$uJ&d>0lDvr z7G)#RjD;xqzMGmg-amiXX`OJEmp+PP`=Smk(Z6+M|HVteRk0f`x{fFoy+r4#Jnfg9 z83TI;;xjHJ$o8VV+DrPq{6n1YrFMf{X@RfLr*mQjV+iA4g_rzEc+&4#@#{GQO)qHe z;}4T=CIOAN5%3z6@OQ%(`_x z&-(?72|DPPg+4t4 zil&d*bNVAm`tv@gK`SK2)4QP%UbEvZyvevZULYYRzjGi-qIr*TFemg4?0(BR&f?gG za?R6$`$}{2TmhN;>>4{nS~vx=lWz}oVX5O<+I-uvu6DeiK@8%X_OjHSQT*hQoRC2P z*q5-P0|L;5Ry(-T0HdvgW-7GZB$|j!OEzc8^Xh-Bm(gMhb@5vguM~7r<}b z=MNdPPuJ0;@lrvsZ638_DH)Viq7u>J7(re;$MVBf@1Z3 zPoyTIw*&efEF*l^E%wFOZy*ATY!VnjSu^}*dp;peA0(Yul6}8eg}eFVGU93nw$N9W z(Qe_$*Y98LBJZy5J3PF%B+j;_gB?n=h&K3K(~$&DV%@Wp)<;NIJ;Iy{XW~ypog;6| zA$3J--nX_qoto+2&_SrQg%ot*lP)uYKvA;^BT@&+8;`cu2~?uJAZFwcJL<7#58==5 zr;yV-^-ILQlVY`%R1%5B%qq^EaE2Bm9G*8HxZi<%?`2f19eoRxK7er&`hGj{n*@d- zgWZh5h}x+8VSYqqL~f@Sk9Yq2%PJ2O4b7(UYh1&4}8e!(OaJz_rAc5zIR;y7?m;A zv|>n&h^DQ z>(pF(wy`OnsnXmh(i0wu!&^z+P9HwAP&IU!G4}UAt?=cx=~)giaN~BzjtfZT#OcRv zyykNM6zKTX-_P;XOkvY2mE0@Pc_fBq9^s!-3K;G5mND(xxBv@7K9a0#vJcd0z5zo|9(O@q{k zE=stxk=e+k>Uve16i;KTdwR|1t;$z=kmW(@SbLA(H;dFQuVDG)Ra_71Fd|)to{jJW z)o3lI(`fs~mcatE1WtpIMVb)Hk_Z=i=>>$6(jO_mrRa_gK-inb-$B&ZZOWm$>7XyH zs3R3Kaae%v(?4~)M;&a#lU>H!?~O<|KlRWTyp52NmolkpnDdmv3Vq`T71Z6B#eRRQ z1%#aL`ab`Q$Z`j7wthgEfdW*yWEX-Ddn)vL;`!J0or@2e%4DVEs#K%a5`rj+*px>= z-tENe03L-K`1D+{cc>YuQDAFNH^p> zD0*0A({-9@M;&-1k_y+@ODJl9jlxr||6@*tchq;>(!HU5G;p6uQtz!TM+R zXq3C_U2wL$K^O)0;u$CiyK~&GW^`Es&Kq8wHw)dj7%b1(foV}r$sk-Sy>-EsvRV5R zfpM&E#JKOY!r{)aUfs*q^Y9rPO+@-oH|WzC1@Lc*?V&e@$%#N;85xQA6YUY#o2{i40_rB+ zDIV!y;cbuIg1nL34+`|2=rga4%sLBpEa%q67pJ%VlxV&w987^C%)*qhndu(Adc|2r zHXWZ?1eti6IS|M${m_ip`FbQpe9|!y^224dSt;4S(zLR?=G^2gXPO$Rc@rbS>s-#E zaI{n~zcDvOWgBT+#R;k7z?7RrHHo`4iCEV6g0tBWogCYpP@68Lug9nR0Y)v7+cAfR z+vPhN9}Wi%tWY2GJ)m!|RCW%68YEpHlq~PwLVjJ2gA+_$dS=UNVk$%Wg69>O7#v zE%du=?CYT}i8gYwOW2)!dm*O+<)#$b4m&@T>dEgW;!M+)Po#V^=x6YAjg+E5SMPkE zTlOlG{SB7&M)D@+BL;8%7)BKPy;*)G#>WUL)z_Qx8LMLocb%GyuSiQv+mH-8Tuj*| z9}}B!t~*PEPcc{fv*e_z&Oh3E1la4o7#9^eS==L5zR57+E}?5Kb+YI^k}rItzVSN_o%6Dl4ZT_VFL zajEdsRm_$z{$w%B`gFaSm5rj*T_4ibp3(yujHHL0HXfVkF#2mdm>RvtJg8%5&p#>& zKn5Tk%F0!x*b}7EUGxVUhzRF#Pgj=mt?ft{<-DVF+y|IYYFqPFX60#3z1l%l#b7M* zGBA2$DyU)C31)qkVVUKotNjuDC`u(`<%5x57jV`VrEgkk!BQjpim0m=o8~v)8Qrn+ z`#uslr1azJ`dn~W4MOJ3R!ubTroB^DGcWcrC-mo7=eHHxDJp5L=PccEsZ>(6EhuOZc@rP*{2>@5RU`$wY zJhI-U8x8X@rFl?F(xjOcNaUY51|S`JP()*~RTAWEAL8mhD~A1~ebp&df7D9+pJEx> zic?SHz!8e&0(73>AJ<*!dVY)c3U=3FIZ(ECRyRki`J$s|l~!RV{$jg>hUxJt+4jqB z5Ij6WaqeWoD`YKg#`lv+6Q_Tba=BYf6kTwZO9t?0tjlHP-kYrUkl&FXdg^yv4z}kS z=wxC}Ij^otL2lpG)4;Ul#Rs@`8<9DjKHE?Lh)7rnjhOdtrl+Rg{vh-DUM=!f3{S(+ zF-g{5_~B&bOR~(17KQ2u-T_>w^xaRpOs1|2W|S1CGpTvSpjXkT*gmi@9`?5`^m(gg zZvslGtcvq6YT_@ZLMC)}pHSdfdodQ|Uz85Ge>J$sDZfR?s0KYODVrmZlbUnQ?l{#^%WIM; z0q||>>l%+nRAec3czH!8(D1yXNP!pbiYCNDIOs6sn+$AlOmU4s{y}dp(3J`jp7Qm% z_x3apuDF@Kv3UGcPObT(Y|GloWYi^e6X)1(HoVB_*G}pzzYW3@?4(9Y9jN$Mr34`$ zIt(YbvdEyGz0sSST&z*3;bE%EV)TWS9)$K_?E6ISuNRzJ$y8te`a4AA^!RdV6;A%$p)?n(_mBJgZ zaE!6cdx5XEQXMpz=+bSbPAJ@#&#_UWDCw0tX`}PME_{khC8QFHKkv&8z~ZZl*?gkW`Blfu=ORq~axVWZ{aZ#=n0*GYyCME6wzL-oFF)OYwNzoJn;{K+ z^GRm2P;;gl1xhW0Us1)Zf81`r=jdH}{<75cfu1GLfib0~`Zv-ut=>%sI5o!7h6#!g zS<=-1j7hGSr8dc&QqnlCOtPF(A0;>YJHx=Q%jdMa2~A7fE=a!0{o9yS+fG`M@+xu-uA^rGI)>bG*h$HHDk>OCMq4pQyr*1zD~GhrZy{} z75%7#eV(S5-wncU3fnDkVwSk_5Z$%Y?8Y`0d!Cc~K1QDFQuruFSxn`7i2>BBQ9y{1 zyaSQ_&N{P*{_4UC6(cLw>F0}g?%vuOcSDK2h;m7 zbAqmZR7K?F>dqL!u=u;-ZI{-3#ECA3*5ZRs`IipE2LO+6)Pj7+i(Jhp*4AzecXE^f zpbmJOJ}(&GH~*d}WLmMHkSqf1WH4bM$>X<<{u;)aOxZ}G#*O{K55I{>QVgqz)y)w~ znZ0#gxhn(ROAH@6G$5_sNlOcw(oAWg&>x!SD0K}lfxB%yi1gc%<5Z686FwHzuNx_Z znm1i{`!8f2-a;Jdq&}LSs+RM+n3BDdD)dQb`NfS9Jiph=DIYA*wdGI%Mk$-I%Xq%g z|Kk`F`ZVmK0|mcB2kN269I^K}W^3;@)1BBqmByo8Z#)s_e zhZ`fgPyfUh9(GNiw7YFoNZ=mF*^t*{rgr*>!|VFNy3!TUd$l>Xk&Kc?*WL1&1rvK& zjD9&4vchjN=V|^jZeex5nr7(gYHxM(ec)YzQA(vU?lUoRZl5b*Yw%ID)gD8y#oy76Wb$fuAWk<685Mt_5RfW9oF|Tm6>(4ln1w&H2;Jk~WWU$@ zTSh|F!&cdUzjOV`74WrQt7Az*5FaJ=)+J!te!da-Q~`mSRytcdrk!+FP$Ctb>^GkL z34N(wimh8hHlE;v9@hem5+L%&Yc=IBs^3oslZ53YWyEcRi^@%)vNJ|+r-*7s(ckvD z8huuY=vt-L9$`yKsAf|8_lXaH;XWH%Jh$BhtIx7$yqvX=KTZISbV<8EY#PKn?m%a! zN@UpK&c{H-Ju%!Wx#wmqHWY2|eW1*fpA|2sNN!O2%Meo;G9GV|8kRYi=uMRT-9Lb_ zpGGzY?yVKIGeYNz&+sn+IH*QKC;DL6hoS&-awqn3e$!$+mtmoANlX=okI0lHV&hxa zm5ePi#9im=YD-w&H!)&RUpio8Pd8DfUQglh4g4&UC&V2dwM@xy@yWpe>*uy-_kPMi z`p2H=1TkHhIPBIax^5y-*yAFLFeFRb^GsQsJ_47KR*N$x_(O8k8perEJ8kXWM~eav zyghF5G*^n&*9}^eJqr!}B&iri#PcM>|eDHWu3wal|;SF2R z5=y&X$xR9@{`S6+{2GLvyy;dhKiwPzmz%nfinn<4#I(w48RWJja-|FLBfGb*&_DIt zgjE=@-Z_l}mCkXZWAgJ577@sBD|aT+x|H7Sz*KnSG{X?I^SXD&yR(~bXAZ7n*y7B5 z$Hsd&{0wtVWoCFrT7NrQCNe|WoRA&lTBV7&=Lr(-<_=hRB~>BO_#8PE!O+r3gEL&G zI6^PDO-l#?aVx%umm;iX)>O+z&v15$Ql4t694WUZ->#)Go7g&=goLz4Ecl8sN3hcI zKGBbx$%CX=GoyokJMjo+D(pW0wXEmW85z8RgpeC&(CER2^CM3T@q z3Dn5em`_!vmFZ|jIQ2+#P_75Q?dM6@noj^Y<@J_|pz&=<(k=7cQSy+D>!-)VBEmTw zRJ7_phpH$9Nt&;MbdH+1^jv@igH3T_^0K!6RkuxxubRj}ZTFMqk{kqEk)GnIx7^;J z7f%X3a(`L3OE@Li@xL^fOta}ThGhcJQ%*z>pD1(Eby#udkeM~OkFldG@p<1WyS9P* zU5h!ueScs}NOST-^GyA^vNBt;gX1(Z+)@WuMG>W7cYB# zQ;F3InGOUk`{)_}RJS5K{`SAJ9Ei>EB?ysD~UD^$#H z!zxM8Xrj{aZcAFZmCn|pF-y4GR)^y6e>tF=SCQwH9Iqks8=gz}%a177imlUCSnfkD z7u`Z0!{8qC#bG1a{~u=Q0_er2BYQExPw=7DK>~#{>ez*^oPo@&pr*yTI1>b-x2gXf znDSc*beSF$O(76B&8|w#^o~$m$@&=b6$Kc&Na|Zn!_pXrJ5mT7f3K_m#c)-<0%8yi z1~$0oQA)MhTp1P=Qf&?dq`CAtk(9F}v;6NAw?}t*|B_4y(gTA!`(pT}s!8;!$om#!~pFinSi|YL!-v zhLl+iqgaLi0kK)0H&fFxzVVUs+b|A1(xebIr*!}F;VHY}@$xcQ!gX@2xys@Ec^G{M zg_`_P4@n_X-+$5MTS?*k*+qJ?`faY5QwX)gZ|zBV;c`oOl_R#Q$aC>m<8ZkdY&N)| zS5c6{QstQPX!0YD9__X`P_Wf<3VyYMb^GJJJLNzrD4yL7ilqd`cB6{u=?48^v40QMgdg;l$ubMgzug~Z7E5O=OvDQ@paey-!By1({1 zYyX5`2vO8$UbNh#@aXf-ZmS=)Jv#9GcSZLzJrUD4j&9QbrCZlg_TdqqKMn849sX;w zF`}3L>GQ5lFnjgMC#&OGi|g;^L@<<24Y&POtC^Q`>`-_A9p-Wg5;fXR*~|_Gg8Xg2 z|K|2b7M8$x{r?rf-|p}3a(YgN?^Bfi-!D_3ZFfpuR1K!uHtHFA>tgL3Iidc)|DwoD zx2Ka?tc2i@}E}xv(5h@*Z;kz@!zZa z|NC_Lmt;)bP#!Q;&>v&D%s>aQ2<9hbrjppZ`b1nGxbFXd+r;b^$>}#MPwNa3sU7%c zcX4TAQ(>G-wQ z_n)h;r@W_{SNsQWf)AU-?ce{7%A9?Eu9U95SHjwFMP){)K+}t%ab6ktVgk*!@~!wN z=uF7>_A^qAk4MzD@9kv8otd{8SzW&z$BK<#ChDEFLumpTp;c%Mb@Mo*86gneIa#Ms z&T-Cr z{!l|Ecq5mdW|2%IglgBzQZ}Sjeb$1@Jjc1I)bM}Mj)XSt9T zRnK?h+L)xeu;`njyDmN0pPC3Ywy~Uh{$P#%aSxgA$Jz#(9TzouiK7DhPbz~z zw^pj4yuy6nPFAWlm;dnrbHm>%H#Tt30qeQdvn6gmXNe5H-Gni8;NCNb$r^D$N6hxl zQc(SoV_X&2eiWCH5u24aQudfQ3tG?F_~eDMhporJu8}h@5g+(xUxIN6wFNd1Yw~Ir zR_Q1}SIm{`;Ko)Qzz=49Rf0GO42vy)8F`-9g~`n_99Nb$U%ax8@qILe@>I>%Gl=Q` zvFg$*tJa1U4@$Ql3v>k*U32R-8UUXeU%Hskq(A|%TyQEC0 zBLe39l*W!aUsSO;$V?N2kE%I=quab|zq^m`wmmKYgKh*8X*7^CGTHVygiC9ZTT$RO zb?F?|1ux~x`g1JO(sROF7WpAK*Zm3d-I0N1yIRw9$>kb7)^6d+)S@!?5Ha)sn$&kK_;!M$(gQ?e1;_JrhBou2_Jcf(lObB(>x`@emG%Tr$jSCvhmJ-aw2r0r;REk zh13G#dIKj$-U1>&eHag93&3F%suFZztDJJUVy8)7@q2sKtT_@{!-Sh$D5;^x=YNax zyaoSb&mNE2O!Q#TFED{66cc1rU?y!tj|)61hWIv}bM&UVtnOEdt4h}RbBhyT#N@Fn zIKAG!igjWs2rY6d-ETgPT0wjHQWVT+$7*SNlKw|m=~RR&VlUclebvnX6VtV{UB6fx zJRRur-AgUlCCFgR>Jo}bKl6QE^|0>_admUpVx^6B+H?J=aX8ZzD8q%#FT}@YRCFoS z%=1>b5r==R{umu{G?r}J^Dr40bm1sn+jjH8rJm6Ux2$SZdheiecC&&S`J`ZwO`5j$ zsnFBq%BGrF(I;Csxy&4*ieY1K3AJ56CC^a12$my{jI5qgLv^6aOw+J1Y~L=}U;+P8J@4i01$?pi zPBKwmo24d3*a@gM`du529rtZL=JQwl0Ev*tj0}!PSgc#47=o1dh|_^xr9=k?V;^9* zg2<)(wf2w4xW~uq(|bh{!)Kg?nu*n&m=$(UB<sq(mxG`MQE2A88HnOJ^*WUmMexf=Id60*nI$F|}Lkq7@w1lrXg%zXH zUUe;5zaiD`FoSvW~76Twc*W_G7B^1;IM2sn3%X#2*D67G>CX zb75DF++^G)iyYcvBLg6xEbJB2#`Rl)4r9VcD**AC=A)xUj-63V7UoIqXImr9ku>tw z*O(Q>h4hNI{U`g;fvZFp<8gFyrlI5Xs%W6o!TQkzkl3_~@xrbawE(mRw~Z>ifxth` zQ5vE%EXXW9dX(3%MDNp$Xe}Q^nX7DNRM!4wU;;pRz|~~|yo~I`m^r@RXWvV07(9#= zGJa`pw$yn8-7_7*l*yjDgoC6^do~v%9r1O?xGBh@cjpWkMp~(4U+r~DSNZ!w;Jdcj zOAPgSZ{3%ZtR?2gRV{|T6cF^ym(W_WvCOHKWD0U^K68)H+>yZJ=dprcc-_Q_PN+jlB2s&^dGHzVfnvjcDd+rJAhb96^pa z9fb0V8Mew{^YmETU&1|ZtLBjw`0_vq$E=j+r5}d<)fc#wrwiEWD&`M7%vy7d2rF96 zE4wveQvFE;H82VsIN{8~R@6$OGxA@x!f$nMMiy6z!3Kq^c84^aQZb+o$A=V%sTG?=RUQ&bjES1E`w(Q3DRYq#=cZiJp~0>0KL@ z;h4Ibw{;M?_EP~_Xx320%2()8dXvZijl=QIVvVni$}|P7O&Xb>^xBCH+|aIi%thYd#i&(jQhD2}d!l6X7t`@~Ib^N-~L=SkE zsP)=p_j*n(Ic2$s6g!Zo7?K+Tky<4+R2?ozVWb0cr<;qwFYGhT%9F*O?weMAIh-#} zCI=ATBI?I^j@A}SeB#Gx&7y~(tG}RK;VH|FuH&x`z5LSlU*jI29TTMW0iG`{YQg61 z<0&aC6Oxhk$@}bKGXs{llDzl6wg&DcZu*8#8P3TwE%m8q4}G#Fe|3!RBg^fT>|=|#P61MJJ|KC@l-<=n+)!&U` zT@3hY(_RX2;=7O+`c)#(CqmucedakE23($KMvcp0N9|@cwVD(DC_S>{s6~BD+$%E| zG(GJWtPLz_`xTGCq29+xKbDqQ9xROzKa2QKUh{>_c>`Uj@Lc!Mw`P_gswhWny)YEO z{zldCDaJ5KhsPLAj=6f_qU)crLYX+_H~VUz2j(B8d0CtfA@kq8&p7$a<~lt@4WApl5CWE^Q?UO z7S;9(G7Zd}|58m;KT%dgr(SqSynP0n*zAkC^jMJ_rm`GN^*Kr*y zPHm4lA?9KR18tUF{j~9TRd!itlxcElUILnwoRu)|9c&@!V*W%&h45CC@F_^Gl)xbB z_|w8Kv7j;nIAoP1Zo9JGWowTLqNXT@%boz@AT6i1GKBW@H+>=4_w*#Z>eRj{L>%Ws zlms8Fz3DqT)dwgPN6OOJ_GGQttyGJzIAW0=h?fibKep>ENs8>1^a>Wx?aCng7i@m$ zC&rp}2w*Ox_C6H&0KXcZ>f>@!EWi`2Vs-^=uGc$#5B_~63%c7`FbwcB3*ZXU+LJRRG3wXcYL_6k^ipOQ6+TynIbm zyF`t}#4AM2Z93k*;cdCJOBo)@rpnNntZlvs8X*R)kC!$1b9>*Jxj0;jyY~(3SneBI zku7u$q=Yf-2jOIhDyRq+Slo0?OB@{c{Ab&9;vW%?)K9|Hl%IR?HwPp=#eHlj@8Z}80K3{oF+}6>S1j-P$FwrA;D>vRh6T1$8|7;A4oI@ zI{r&pG9g8#<;aOF&wQ=~c5{iUUSkj84dP_;{z0$o$kCR20$*kPzqb=*-nKMb-Gd$Y@JjEu|3+r?#dRdNJN zox5pS=TG7;3zosaZT<xTPx00`<)M`?4T^NwI{sLXh(>{5BBJK#Ehk;L^NfAR>icy7?Tv;{vyLN>Y$Z_- zCiT3V7Vp=3zb#afb)zX~VKmmtZkE3s@WSLpL#y8(f6idz@KSz;)A#7``X)Iwed5%Q z`0_`J%U<>hn!7>$Oq4TI!T)TpvdTKM-(FMGobcI!gn=t~WbdE5oy6$M0h2RZJygd_ zTi;Le@jR<(Z&PXMb>MN_W-sfZ2os%srTNSekrn@u#=^GzUKPmFPMS$rZj_Sowk+cu zHlB5Hf}8M6NoC{RE=@IWqsq$*`z)k8uqbGO_U~*;$fYyxf}|MqY5(=ev%P7{>*j6PE^5$!==*gKFhQZ zo)?|O%m4!9w8QL$-NbbU2kWxJyN+^wxPT-ZsfUlIU$z9-ARv$RRoW9_A2Y=G-iaqr zP+@M(^sYS-b$7Lq+7de{&yg5m>E@DuV#0Tx@OCaPu>BTG@+C)oo=4!p)3fesvH44~ zw@zmop=#()?e}`T?{J{aaoauV?tsaSN1r)gB*$!%N6($dmhlM!IaPoa&B{vBHDdRw zX|+Izmq~}`!hFB(4ijs8o+-0Hi+_6%fD}yrvu$+pUbR}W?m9v!=cQMtTTaWy%O-4r&MO1kNBv;h~k~Wo^;7474+VjX|X+j+4G#TIqe>)7gg^7)RA9} zGHd7#J|2*K`7;I@ry_nn1N5#+dW7-LCh5brq4Y7)L^<&b;Yj>C>Ca9!gJ`}--Cwah zL6$J&y?(Jkr6f#Rm@A}UFX}kQ(pKG&%EOlkKmr!Mp^yh8#^=hIvQGHR>||Axk$m-9N5P1dCLTCtLmoN@Hkj?NFbA3w zrg2|(Gr871s#EB3+OaQ{z{=GBM&yuZV;OuALW z$3(+{F(@2m*44){(z!@5T{+klMZNF8_lejw^L=siUP>n?n~fT}IkHY1esQEYEXQih z5DAfzo#}Ok%;}#Lt<1Q$fI8c06(-Q>OggTg!#jS^7&qcRS6_Sr^5m6j#Z9yRVqtCn z#EulksT@NreRh6v;B$6P!dA^)zRbY73$fSr*OTKzR_5MZmZrl#2HnM6_R{q)m5{wY zYBqBI&Kf_Wm;j=;4Yjyc5maK43 zfaY)3Jk|keLq%s!Rt(LsNY}dXCCiwG1q1M_FbO84Fy&t1`rWo5w&IUg(2r`{ zL1M(G$%hnNgWjzy-aW6448%hmgsr86ho<*;XSb51!rWF?`#5K+vz>@b6#t}(f!Eats`02P9cbO+=XPA7;25R9pq??hwl8h@5Ni z6i)HNe7MnNTT;Wu0eFj8;H&AN>d=d!5r*#yHl>F8eIlfN4)`$PPjrjtB<9JcGdO+6}}*K0lIJ2iFf!c%~w-LZL{ zQKrf2Cr{^{zNsZ3)Ef;RXJ(X{&855}T(Q23XM}$8Loaab%Rj+2{@5Srd%Ma-etp7`%w`$>ky+cf(FJ`Ez%&kogN)1 zAiVXOL@tgz(cp~22S-i^f8N)y;@y`gOd3cpv#ZOFBvtwq_;pCHZbG$?UlBv_^^Slm zdR23dBVRu$#(9vA-M!8!nG;kjGt2Z{S@S-1)5DVM)cYQ0c}@dY4d1jrZMAH}fD4)- zeSg`^d$z}WDp8&%=RYd{Lw%<1StU!yq;*gN;Ks zeg2u}>z>`h1wb?8F$}`Nt9~rMQ^xbkQwZ}z$u)@e$7P$L*mh~*L+XsGq2QqvC+Klv zmxw%B0>$5;C)M7jN6&LsPFZ^ou+D%#oz{nBoFTwU!68{uT^;T7Cc;>&FKos=c=22 z;tzdDQmhT?(SdhHN46J*u3+L=h!Uv4qbxyH?3-%|K{;;)4@#w2=IoqCz|3sp2EPQH zv)hSw9$HRq6-myTVOAKw1!e=ZnHbQDVwC?Jl!ayzcu5(kR(A$k=d|rZVjN_4#*91p zdv+$p_**<{tHBItSD4wF1P3zMStR*F!lZo5>X&{3vOr#}~FGRq(8VCGnv-Csjgz~vKP z!}#8@Dgmk;TNd(ojLiMGp5;Y@v@?ssrN)$pBlkweG9vmaZ0$LNZ^?H+*IcaRIjXT) zq$;u`^Bter20ts;M;#z`w#LpDU8PbiltSa5vnUdD3)ChO*yZM0d&mS+T50D=$N9E* z#05$vEXmkS$g_)Y+0(Zk>8_wcB(r)?|;fZUHg$1y%SP+tGh7v z>a9ca?3*62bFiG8zjB$6&p#di7Vc;F;$j=S-^A|skKx|ma;X1*X7mSD{oG-xOFrm%xi!0#izu-f(j zg9dezz!i=Kre8Y^0JIkiu>Ggxf6K9}9iHcd<6r@h1BUbeaW8Pw2VhrgN~l@Dc#ZV< zOVM(b+eYk8N&kLtseYg-V8NZXdZl}`%WQ9R#(zxA*mbOHFZw^J^q3_@@53hCY9MrZ z5C$@i43GA@c>4$$)%^bKLnQfCZ!l!=N_F)r>%-G+DdZRA6T4GV;W8B8=|9M6ASqQ? zE*wU45C7WIle}>@6O;Y4sOgOGukM78_r_Iz z*#oeymC3u{Eiw9^@Po^T?D9=fuFS6nV)v{>97uWp~Ffh zf!^nhPt??{G+a>J9?YWmb+Pr9)@b}~}WIXEDM(HNG%7xNb zk!GF{O`DhgMu_j9bkC0!C(w-TmBY61AR(X4q@9$!7?qt?{nu9fqZYx+jH9_qCinu2 zLb8xR#?VSosY$5Om(vGM{#u3Q^FpFq#(*ybafKHlAdr<8IiZkUHAWk#Vpo(Q#Gauy ziRw2q@=JV&v`6UcN8nWa$&ub-b9?X9lz&ksY&e;H-ClH{f9e+%mDTw>@&WXBlyH_{ z-~!YK9wRBxnDg`X+56#UoK!ui5sn#Yd8R7mBcvRjD_b7;hY}m`Lmb-~UlSr?-=S~eG&#IUy6_oxj*RBLxq235<=h2L`NLT;R zlG8Iu?9HYbs%62U!!2|^x#}OCCBKbs*gd7Qw7K%tn^B^k6u*$wVtUi2!i+=dl;{+^ zce$mKFF5#LJH6j9WU@^LGV$PSgd$1aV%vV z%lLPzu)7Q1WWPZUn5dP;mpvyvl-pz~*WDpm}}zJZXq?DkjT-h6a;Od>YRC zYTWq6{QqpogLaWIyHD0|@7s&s*R)%CEVx)j+39JsErAp*e*L#=#fCT3>g(*%?7!V$ zx)*(*Fv|Rt3Ba55(f@d(npJXt!cy~{B60sxUXMTrc-v|V3QFr?Y&qlQ@ z37C6cWiR@9v8+e{>dqBqb1$-B*)-W;+u zpR4GF_M@Cu3W{!K3$$948}q@)L$5A`5brxZNew<1cg_uD8~BjNjiMXq-tu!Ek3+zp zk2um_Tz02hcqlcy7Us8%7D&hA3yGp0fSUQy3~-{8X+He4()o1lJtsfNnRPsZ?R|86 z$;y2%<$f?^(n1;kA-eT~(AWtZ*?PU>`rXUzZ=JrRJlPPn{Kq3;KS%8ix9cX)91zxe z2o54i6kQny&NROia@?&XiB({^M&f|=9p z{0Ltv;yK{t;%Kq)kpvGzvkXfgm9cBrBFvnc*@`3t-};ycg|?DD!1SZhU9WIH1BtMg zhfF6qz#{(`WtwQ=x;_vuqzyH`i%ZdhrhEy8;|Cm zYrY8IcgdT!)AXXw`H;uJ@e2o-4a66?xi=NizXL~C-QYDP_)iUL=SmC=&c2on{2a(Z z9~OR!J^-jfpp5R4aB^nH*yG!0!-oLJALok)nsBf{bAsJc&^Gqb?C)MJTRAtu}3qLXJqio3Y)uo zq=mfn-)uiFryo+RMXt7qRS)kQo9&yjU9AjG9aSHB>t(L=u4(wRSJ%;$hxTHP_kX_J ztI8K}@O$r$kp!l8>)Jpu6X!bj@#>RHhjIm7 z0k84LrTT|jNpa<JQx@+WAyFON=(=M`*s+sT6@awFneUAxu< zhO(_k#9oS{-Y}C#NX2g9sQ&!LE1yjCWvON+Lp19MU8T~!XpK}P_qcP41H78a_bGZf zY9(#{R^sNU`gE}2rS{rBVl&9~^dF)0;YUiJ?$~E%W92PCn6LQNh^rL;Ph=}f&2;uD z@1Izx@$pCMgoC}j$V4+x_T^y0<|A9kt$rPM&11b!#~T3o7fyYpYr}uadF8?ek3p%IT;SOea;_u!?Yh<|x#nw!mDtQv zABN8P8x%pl3x)!MQ!>sXD3Wr98fxjglm$0nOsTdelA0A@jFfFL7!e?s~~LF0e_V6{ksYzKVQK3~@TQ)Z++xcbj+1rK z-Lm2>(|48Uo}Bbfw_BISX{st<73Xftma$4?_+->vP?(}R=5Dvid-i-KKj-!*!z!P8 z+0AORN#4q}<$-hukEWXk#%D&2hR7IJ!)EY?o8=8{K8lilfwb`@Aws39#XjW+x^~yDj}jGfIwn&dh7yT6W^FC>yM19m_m;iXLY)J5yGC|OrHWJX zk`@vjj+i92kKeC&nvegB(9-8}CyIK2^o*vgM!fju_@DOkY7h5bhh#9k)&^h}h6<3tuiv$dZc#&Z2w zvd4pmVJhRc{uQBNRXL0KU**O5mZG>ij+CMotxqm`OFy}i1N>Z)a3I9oe3lwEeRQ7= zFq=EuYQWt zZxEiRa=)CSU4P#Fccs}|@YVYh0E&Dyac$Q?=hLy&p9M-#FpoB?A;M#IOQpMr4no7bS=V&iW63LMOFi8HnQBh7ae%MDMLElD+%(7`U~*Tr{N>x8nRiPEmZC zFT;Slz`r5bMXwkO)|iQ!>uXiqXyCkyL7B6=LVIA;|4?5L$l+4iVE;{6C$>AbL<;pV z6b^ei+*`V+w>8XpckV2;T#`$tc6)uum3-jWtG&4Ew*;p-?eXqA%|pug7_EZATgMfT z6<0&L*?u1|yg|Y;zNk;ClEj%U_{*bWHybf)4JA&8=gze+*v`K)Mc()0;O!=I?%SIB zYQ4&;c?J_5SM5^ClN2Biotq<9sp3**f{$>6NbL$RQTi|ImOaqGO}7cc(>xxIDy97X ze77;^daZmFOOPFo{CAdy7L#{h5ZgLcwS=`}J;TLgrT9#D4>*!QvVXXDPykRHvKh=B z`w~h`S&(NtHh&}~+`RHzyyWq)qA0j#I_!`elM~m&ev$w9pSItURh98R0YU*%;0+Lf zM!AHK0@-zdYnX`XuwDF0gl=|F>MZe>;Hqf015ehl|)f{=-rQ;Q8C~e&yuar6qiSIs~lrOJVFf zoDjfer#GwU(CR2b!T#($zja zrEzCTY_Tlx)0Je8`b@p<06OM|yf%R|zko|qC8KQzUPO-a+SEJ7951^-v-$O8L*Ji# zQFk@lTBwH3EB{!Qt)}#RZfqv2q$)NFsGRvHK!~gWljQ(K{Jy`1-6K*%Pt?E>LaEa# zl9urcDuTMdtHMX(2BE~2PDQ{BLt&&)(|3vj-RwG$Hfe#vXeC5%g7DJAhOiM2K3Pbw zOf7x81qK}bJv{r$S{T*u0YlRaE}O(H>6zQT|8}@RKC#F=@&cmrraPO2s~yQ3u%dhB z_5rDac(3O`Q)S(@Ug`e4Ac2&=vLs&lyxhBebtPU?QGDCW=Hvu8yT{MBvSoo^R5k49 z2MU=`)*WL8#yXWvOq>I91zG6+4fBzlqTr3{?TULPMY#2v0Xv^5WMU7vuQuw6Aj zu~T5ir@g0R#EnZu+BhkAY&yDaxZ1ozdG#eZ`0H{D?mwbklXsV_FxtY5hvaAhcC_n= zLtE@+n#v|1|AgxvC^+AsQh!%b$vSucEK?SZW+t|zwFAZz`oHzTZ64#$LhLdhw{Ygy@;%l}}tc_72vO6y4 zsgtw%+13-CHY_xr|qeDrq9FO(=~l&w5!g$eK!*Jbn*%e=NLl#7_B=E_gUSHNLR@BOC4_a=JCH?{gHN zt5Y*6?;IHQyC7m;{;f>p_93O%4mLE+p^sbXRDm-cC1!#v7ih%>?*wVr?7q_t*9)4$ z^IoOO7mkU?iCG)9qz(cq>;sZ1B!$Nz?j!v^(3wi%&1FWQ@h4*xc~z9V~RByee};wYhx#iX5?dltTv&F0z?_0Q8%R;V^ejTF!| z=}HJORNSl2V3X4KY;!V~U{&LgAU98P$-U#$mcTwdLAJjNY)z*T?6geFPd+{)7Zt1# zIBK1xI`64=2)fxO3&$GBD%sS~EabG_x?Jh$Z#rvL<>WCqQ^Xcj{Z&n$DFYi80zMA_ zaV34Pxa0zhKpv?XmP6Hl15kcEQTPc{K*di@`8Z_4kooS~3|&RmncdX~X3qlSVboz2 z_AljbL%MzD24($ux`W+Xf)wa+$8=t}&m+o)&fGV+&O;%TkLtY2Ih_0xnNQ?;NeUj69(#xHSqq-S_Ez?DsgIzPR20z z(`q1?Y`;~Iw2IwdTXrkyLhSpOT`CgWk1{0#+<8BP?38fPR&nJlm28xm@gA}e1P_C7 zu?ilD_5J?jie)Q{o@S7Wm7-CC@>VVPq~g{mvnnuGt=GieavzJoqk`w{IBf47unC{b zObT=L+yR_O=t)dqnJ{4Dj^Re9rX+oz zjpZz(^Sb;&4JaN-0J5l4Ig9N9xMmDM-A^w~dsVns)uk!hJJxBNJeRcVhy;wm~coxX(vRMNBP+ZB!|MkQZpqQ8xvw^$S8Y zOi*&NVU0NiX?>IOLRQJR&|-BB)>E>2sHl`0UyZpUXi8}75N zW=k$jwg!74aavSl^+DSsMJ&=z?!QHdlS(1xlUW^`OVraO=kQX29K4-h;`Zn$&(_n+ zS>>ZVvn3{+WsT8qrus`wcxvGw4_R!MVgCbQUqQ_3sIk&>8>=Erk~`XFyAkAvX1yP3U=%VW4v0-0}f`QJ_i)fdD;4}9PK#l zM#g+8$(?(9PDHGzHG~mRSdC`hii`%L`MPLD6MRi81-f9wPN8Nn=JuH6=zD;*bQ$W3 zq;*{laG)T|1n1rTp-9Uqp*#wRfYiAna>(Zlh({I(6Sc{y%4av%vZUy(@^eJwjIVL6c{fuoQT!+m zDa5Lh6CLDh@~ro0727@m~ULvWch1*(|YMoKa>EZQsKTOrqmNVv9r2$+|U`)Sa z&$8R_L_kz+WwyYh_8m1=c*l{;90DGvo1V?Rd!hAS%r%==B(*RG?dlP3+{M2qEpRnd z#WFcVm=ETbWbX8E?i$LnDk9pAtj*R~zL@+}SHNfIopwT{r79(I!#cLas{%H(qKzz_ z^0uI(6te^U{}H~ol|3)e5|X21_}83XeI(ytULQg3d#g&I_Hly-5FdiLRKmRAK_6;} z;Zz}$pbGWnLj{YESj;u~)kk3hZUV$bMP(uyArK+ixA79@qms34-0v57f>yQ%fU zd@`*HBqM*(J5HNA340h;q&dWi+jcM!UOxNqSy5tsU2nH_7_zHaYPGolvpK|*e%2pG z>!qwt!6#H5q0QsD-o&TEB!^sK_YoqFfhBs6tf$el*q1T4yQib@Zd>bI(E2DeXiHH^ z#ptr#Htwv@EDDs`zfY>YckmhB4Qe(EWD7uA_3BFRGx*vwBZ^;#&L$%{1!l#$_Fy)W zXy2yW3^x0xJ8#!ZhJMdZVg{$ zIchdZ7w zJGuip_KB>w>?0tD#-9r916?-h8-ee2yXpEJ04A zF{`8}@^FD=D#>q;8$+QQbXSAfA8EaG-wVDPb%{wOmusT#63mh&z#cZOd2qS~;Dn2{ z{DgoleDPG&4nat?x!5QF5?;xSM`Zh*R>;IlB5W%~}j>uz_a zzDi@(L(RQEx2?#y_yLbd z@*AR_7oAZ0Y61&H;Jp7;nTERTu;kbS_k$iI>@xvTuwFu*=3hJNBkPp&tP|$zGZpqA zX9GeMTI!DIbJ8Zu9PVWsa4si^Y1BAo4>|DVZR-^Jo8}5GzI4mFTH#aws!#LmTw)Kl z9Uc|z9AejT$2W@_168H0&E!slO?> zE01ulQsqb)XR|+EJmK>haO-dnjvrek6cDhgrF!=0gZZ`TojqEpx3nK2p~qh$#!qid zx)hE)@MpEg>sQjclO>3t#ZE4+Zf!H;7!?<4NA7m^;%KG$SZzS(!N+5btG~kF@d9v<_R8mkJ_us9Buwhym~&iGdG83(z7XkL<*}uccEh&_ z;%0p}d)~VXyHA?lE5qEfOV~fq=q--{Onk5q>f_E$fmElj*`738jZQRl!uc5P+{w0+ zKu3&r)gcPCMiJ?43%*t&wrlB~RaB0scUy1env4RVqtzxdidVcPGJsl7`S!zgAyX=>wlz@oT;Q8qS*2*Z|wm-{imf7CF`Y_E++c-PS z#Bm}y+ks{yl0|D$-@Q2E&GUY!B*+cdmjtPvUvtf$TOFXg2V?ggnQqC0_?G2tt%L5o zm}vBdw_ve9W04V3Y%TbfMN05JS84Mpc@s0L%jH+{1_14WhSHbpN%?+IvYh)63OKrP zRQa!RwB+FJR z?qg3$1kX(h$q38TTq8R#5#S&2V6g$?@YI>PA#pP0dG|5Twl3b4IcKHu#9X7a_u+sU ztCFct@Rhn1Z!@Nq+&!r*3I};sN}h9|Oc}KqQt<{AIC-36O5~g_JMY*2)D5X~K#=d8 zZj8g2kd+I$jOI1chXZ|)>d~oR*s$7R0d*`+e~7bAdrw^8RM;Qwjy~eCl>`BU$9&>h zn?a-mgj0BFdunE|)IkY~m6b?paH8F|zd1C|F<;1M%^+(nm-1O_bKhcG@9BP|x+9?? z^gv&EST_!@P#C@$wMX)x%A))#F) zXlL~I1K`*BxX*vwOXA$rs_uT(B1X0f?E+;e!n#*l-lWN@bf!})Q)luFV!MmMMCZ>m zQHoEt$g#|9=Z#1iKZx&@!7u$~ve#R&m-~v+isnus`f0=hzp~Ih%|oi7O>S~pHcoO~ z$4A4Cc1>|@i<4r642fRo*N{?$mR%b5OYL+ObP}3EX8N_?HqNp2Q1);9bXna2<&&Sfxop4w{d z-K830e(I{1EF)nl69Z0y8n)j-tM3uu<8Ix`**G$huZRt(0%D~?nopaKtT~hOQx2K> zBi>A*ZHlV!L)%vX(1xpe;NS-$a)knB!UbjpN5tYP9}R^q-7C;k7T_BQdT+qi;}b8E zWWORz2%X}~euk$y94{fRbyQQIILOZuR-*fR!i9N1>?f7gPNXcYIlFAtNEVcXkke5F zX|qAg+LCBa9Vef;aQh%Es~O0O72IBQZ*MO_l}x)mI_-cG=+%x9U_{<*ivtWm#3 zgJYO08c2EQol@Mj9^$9!illXMBN3k|iW`-KGv6)6#|;l?Pnpnd0vD*?N4(sx!sh@y z2U}>JX<&ylni*5R38Go-I;gP}k?GXqv8izDI-vBne*LHe`{1m#&4Qsbf`17YVS9l? zqc@Jvd`*D#pCBg{mQtontKDd=p8@3y$%I^%Z4_H1+Kke1PZHO)OfzsgW8y&?}n(_(O*d z>Sv#)!HDm4$f~?tY&VRVY@LjtQGPrgfBey7?6((Yzaoi(@X#Q4&T2_%pP@ciY zR`FMY2O@EcdcpO7?E0v=6cNxXbN@r8>W-pX;{|e;cp*M+S?EM!ihqN8#jUJ&Lei(HGUf?=UA=lcHFvs{10pY}_=ML5 zO*lv4>F%~{PXgx_#iH)DT}4$4s2b=!*c|4P3^N`Su{P&t`O0du;5g#!)9F zYQJ1I?Xk<-x-FIUOCfspMg0uySRW2t{Z2UMyCHcvCW?1wRLiQ)00nIZ!|Bmpgn@y6 zbL{48MS6r5lzBEMyfx}u z(YMy@Hq~xvrFLXmtuBvD^`%D{(w3VG$zY*~kZU3`fP`-QlV|f~8^z%@Zdm81X3E3! z2kCC^%pb2^%d5DSEWY|toNHF9$EsV*Tyx6Z#w-?y({jI;Y7g81H z77oEgV{|L6Md&rw6SO}MbFrzAL}}?a2a(gj370xHt+usw9IcDGL;^C~iu_H@YgKgS zGO{Jb6F9{&aW9)OAadRLba&)I@+Cc=Z~cSXG#I{8)d#hnl^)lY=HYIly&HO)_+h5Q z6{)F!mA5uJeSWKDsIq0_cuWd^wF9evK(cZ8u0_V5<@;><d$3|$Sz+HIUm6%{q{vQJAV zw#$?2MiA0dCv80^baTBSBah8{4nJJ(TnMPY*5a&(~>Y!ncGYWT&Gx;6bl0+upd- zRrcbw!9ly%XjEEIK_?P;U<+2*V-mwjZ0ZVp-!)Uvb4jXTXgSHOJ+Vk+L8$1+=v{M* z?W}8xD+SV_C}G+_(d%2Kp@Z2##+B~pK0H)&rP<4b8l=9Ias4e5DA-#3%DUaw#@?vs zmS3)$M5>-a>e#bxSKL@ea%&y#C6yEA95NOz)v`uS3(M5&b<^cFFT^h-tU(B?che{# z=VGXvJKOHLGr9LY+Y6Xh3>C$@i-m2H!nm0VC-{6%uJ@X)2WYZRG@ zm;q9Uz&zs$vLnX;WT|$<<$Vg-)7A4s8WlN)(7279Gan)=^NwQ1ZHx|q@wLg^3s|u^* z9?Zx@*6QC-d>{g`&fU?o${xBYGIl~SgLT(b`a3WoBD{Uat-nxR7EVw>-WTDh3O1x@ zD^lD!u2($i#V4ILCG~*S`^|-y@in|JvdWor9_F(5`SLRW0^z0)=T%zdSsv$Zdg}MF zZrP9V2?~|JOeRZ4;W%tgu1fjXjQ6N2``UU8%x;E;YDZ76+SROChuWz=@ZTi+a@g9L z&5)aW#v(bwwA$ZX8ztUzu^QOCO(L$?_l^a$9kN9aL)gt{*`mdKXbrdBn{~m|k2+Xk z9qHULKr_H+N=xF+1*9I~^3#YL2EiFVK|=z9+t(?{zPN3I#Km0{SjaZQtbx-q$CM_0 zVHM4ocKvjTPl`5_DJ-qpW9t*$$5*E&HvSjK4JNw_?G+iNnKLQeywO!;=gOi@hIa?& zp)qcD5MWlIQFbK*tXP}9XcWMA z618@MWD8bH*A`3&6gSw1-2RNi;_u$w*I>P~TyL@o#3~pQYMA9JESK6<3R7_>n%yR2 zqkTig$Kwh~aM_Dk3F4u11!l2zFgo|?0VbJSw{Jtf7Afx{*@L!h(wD}#VZ8Wjwh^7x zpv=)vo}7{{{&)uEjIy%Gt;@sCA`~eHTFe50xFc}-IwY8$T4sVr@W~3M9>WH&%}eAf z-lXICky%M$L1*~!tUPPMZM8Jkd?5GywMC(9EuIH~iidMfgohDDU!|WU%Nq%hg_f$D z>naSzX|M7h>`7stJM|r5Ao^w?5a|%Q*#A*OX}Fu7W-ywe0;QFke#N{1-omvwHQcfm zUY?i%(hu?tq_B86-2c*X3~gxG*xal>3Z3JtqFBqn<7@+5EeSrYSHp=|?<#uOE}N-7c35aEQOOgYD`ZznpOao{S1U)r9M7 zgAL#%A!kn%T-QyivJcA0S8u3jOQuN&K|N<{!SzJ=gZsW`n<=%O{jUZx{2lRfJEevU zRaOm-JO#r~1&-`YZ5H>o#aa6doPOPq9FOsSV8K^_r$#xzlt&y*K^(>G$FqFI@K{G6Np4my;FMs4vu|SSDtxW2rSz3NAi(cGW*{Hyo^Im+! zK9p7`vDuY>Ql^p9IX_2*CpEpuL7ro9VlBRf_DINF$SbQkqWf|AOWc~Wp7JfZ4=+-Z zG-?h#AV>J&9P=2K#cf+o6)XFx$dr^^HK3V#2iODa%>f+?C)RQ^IV(7|P@p@7d;Qn; z3oV`|^CMG{*WZ1&GY%Ik&rNvGywak7Mg@wISFdmgJj8EiPc3)MvUz{dGR1p^^`yI# zFnxF=0J5j!jLUAUoMMUNokK$#(sVsd5$Kw-a1w_Tn>}olt+|rAi^}HG(yuP+>_Ica zv7M{+DY4tz{tM9eejwr<4vKj7N8RxaNcUOv{u#=2fm%sa(E|A{f*v?YHC2Fwy4Nr2 z@b0j#Ap0H;O_01{Nn_Tva-PeB9Ct%W&dSy)DS*576HTLLx%G7no+{Hvw=eMvTy3*N z&!50Tk}7U43j3yfk=<5y(Ms_TG)zJVE^s|>TC3Ns z)%^+BMip>p|7n3Q!yw^&N`qIl>1id4KV=sR>^d4l7ym8?BxE@Tj%w%YByno2ZGBJ0 z+?(GROWK@KweMaX%f{snrw4Q4&1_dP--GhJO};|o1sUcdY(5<8Dwe(jR`M~mYWCSA zO~Wp|(qV*0-R#9EGLbh)Shouu_W6X??%AYJ`>w*x0ieHzz5K8=VI1LhD9*cs!-wxF z$Qm7F_-TCjaN!zbdAGhF@e zsQNEY>|!@X^0zHuK;|=3F<-bowhk!TR1CvY>{L`WKUiQfMK#P5%A_nvay{g3wt#=B z<|vPN`&&g;VS*$o$vr)`EHkh@)`;ZBGduEm545cW08n}D-tU)Y>z|S#zqpXgFTM0M z<`1n;kAPznM{8Lh$NHt4!>;r#@Vo3>^z1BV&S3H~e9zJ=w{DFL$c0bE6}*?;kyA6@ zT(~6u4u#xt5_y(zRNpW+I$W!Wb5xXUD3Yo+|2+yFQG~JQB%b!E%NAnr=S&>n=;N!P z8{6@Cb4VJIKA9Jy(JR_OobV;-)eha0SiSCcOXGxz%u}k+P(rdyx0*d2Gn8VEkTGl^ zyp#rf={)1m(0CKB5>u*D@f0jcSCD+~oomfo`9yz~zp{A7j9GojFdNNK@sN|9LK8r$!XgEqluAJtw`4a!KJA2SO?0L(jHF=iLC#Nwdd`DVB;r5~69TOs<| zkv@%N$9uifdoBp=5ks~D=4Ws_LvUuIHNBx}Swhvb^URm|v{c-ei)F#B`<{KAt^~gu zxWi&zZxaw~*?u@cALa|6rPZhOixif6D0ft~4DC-*oJ;gSKpkB;uHDXk8(KZL?64bmuP9SL#a#DH4)bl5nAQWwVsPoO!fP)#siuwyF{w%XX7@K#LV@v8Ya7TeQoJw zM@Q^Mz@_S`y^1TPWT=O{(swyy_*`_eF)W8aSZmh*Afm-KOm&>T66Z^gpQ&S5YAeb6 z@b$A|RQGp`*PjWu$PmnvWYvpat5w0JkfOAa9Lim}d#eYYJUQ{|tTqFX#TR9*4J{5p z3vA(>;f9xuTsGwegev;Tvy|64PxFIEv|OPUN;$|W$eyTT^o%!T{EWgZT{_!|zTGj@ zwSv1T<(4X4+r^3jr3aAL+~%fRx&WjrGnj==+X)PWk9|hfCuo8TcI+PXY8#_DI5@dX zRq^tOWf#8ol&CDfD_*YHZnW|*a8b8)j8DIO9r0n~*sF;H2ZV&}B-q%MUH7gK@gBkI zQsKiRmNSzEAVA3tUA9?6)R@~El#xG8=p88eZ=HK}mFU)tTmB{Sup$o|wh|})f<{(j3xl#(9e`cLU zJ>8kej4c{+w_nsa;ad~wQ#uO!(N5mePCNazBdvqq_dOdFchOXq?cHRGezU|1gOB5W zK(W-Kzvb=KUKu;JAswttY_}OYbW&5H#t+fCYnMV6${`XJ_C471jfvP$Tk&Q1sAVqB zVa7;H4&(UUfcf?{-BZ!E9z+m(aw7d3ithJ%z~WZMIEGywhug^!hqgdNhd=w+`C5eT zPoDS@wEA|xn!`7o-!d&`plK$BwzfE2OO{xMGohiTY`~Ha`vA(HpHp%hf;BMJVLY@y8OGAWD~ z1EQCtpydKv%w!j24l4Y5fppJLjB)yWpFT`T_1)?-=K3cd`)Y@IHi=;2db`M#H;ZQc5l1W$8Xft!3%}q4irMx=S>U-*x;<$+61A#77u0h^D||V z)HL33Y3QHZ3DmgI^0M!wRNa)BtPLAN4*&d_4E1iiFx*?DiS+dim3Kn`iEcVc~E`fgK)mK^H+O^U@aB~qyXoi(%$5`p0MYt)Oj?OKU zLcd_I5$vD;^xKR6V}rK_(OX2uF7_YssL96h5J=8`0?%1OX4b5GX72f&NN>q)s&VvxOq29#L_F^nlau_IQNNIWRrb~Y zX`NTTl`Q(L?5t6OEB-M+gP-j7vEEj9$8Fv-bM$NczXj>xuSEf`F(@)_p&>5oksm5l z?p}?z6WR=#Ia1>FZ-KG$=Op4c_f)N`_?shdDz(kZYwT}}-?cqzcp0s?FwhbIuW8a> zNGI<%3RtDvWt>HSl{02V!E0x{32X)T82$18`ek8s1f~Q4f%ST`mnJCEdg7x!mv_(- zJ1C7hf6($^wX)%S!n1_5gH4C!aTv>pyaH&{XK76bC1rdifSS7qV|0#t_DViQvBlz| z24jcO8dJ5HuNIw*n4*_=W2R&t>MLe7jXQVu%stFV zAjz)mUExUp-9@9K8RjN#9OARfz{yMYQAbVZK7HRlQkL)ZeRY`o7ms=7F$-GFq!*aq z)6Xq|HV5J!R#)_ym;KQrdaE<;;r(-80B88$AGe))k;V}_R=L2CBDmQr=GtA83Y2DU zVhcaNvSp3*cv~lA(@TE&N)iH3lV;W)Jll7^f|)Rw+>3Di@r9DQwjl$&!^>}++yB@z zr?vtbyW<{EkWy(v`#qBfEf2FQ`d0n1Plp))Yucny# z%opHZoMyf0?fCKe5AupJmF>`0TI-~moyZf$C@67ZcmGV7&O)#i;&3;I3T$%e2mIps z%2l+}aalzpVbN`q_+GCvNZ70gDS@$U06vgQBtFq+QQVsLLCvgeZ&MkjZCR*Cz0jrF zdasN79Og;dMjWE7~&G%V|Em0$_&^b~Ym#)a0qxWm?nPg-b|Toq~9WPG;aF=CV7q@wqM7M3^)-wA!Hh*9<>UTt>lR=+_^Q9oTb`m{+xq*RubM9$0b^$xS9=!^LVB5PF;nCv&mkX` z-kwE2_C>$Mc4BvzT^3_>5FPB{lrxy!2WeRkh~<&XK5Z}iThQdji9Z`WThT59ul>eQ zGTf>@%SG46tplSDL5+SQaEkq*I5T3T5kPA55s3&yjz2#J! zPcgxqKjaT%r!eOU2{N2{(Ul2;IWvkyn_`dCSP`Os{iO6$dOo}=G^iF8dP{g9>@$v` zbg>^9ZZGoVLMr!KAq18H)51*MXKR`$y~ndSzoF*F>hm@yR4rJ*T}D^pQ1Zz4a!7@; zm5;9f6IMCS)TU<}fx7Z|Gp@DUuEFd3tLOD+yt6(J)y^*#-W8SqI3@4XlGb!T@GyM| zY67LSZR)pHiuW@JNj(5YGN)%YkML>0!qC=@T;+1L03tL7K3l&UJDivEo4Qc7OLJa?e{XxT|aOOGd$&a<^Bkl;W_NfvZNLx zaQ39)iYy4ncQ}I=U)gITb+>~%ljI;ac^!|necv-iB82$AvRvBJ2PZe^eWrBE3 zZr=a_9JTlSu6{oV4Ru4S7KS{f6J8jA`+S14LWxR5X&Xri(hJ{Ns)ay&#IrR|)onN$ zV$%58%q#T;@EhBYfw@7f9$n(lxWNR%uIeW`w73A<^5d}mjgy1?RmDadVfA&=r z*`E$O%4HfU!h?Hb{j;SBZ0M!JHXzIri2zDdOTH2!w_sbRQa%rW0GV=1TlO;;I20St&Yz6Z)*hUZ zk9v|cR)arHCig!{dSkzM;u-|O0gS%|pZ%au%To3c9c{eJdGffG3xE7v zuW4feYfb4@zh>pDZY61Eu(`-y772xx=;<<3sjwCI-TESoWBQFVZ>(A1t{g`UeODJP zUxXZt=NHJpax3S6(hVoPMLNszpP_$C#)gRiIE?s3f`6RmdqGyG<;NTUH(DUbp8?>z8WA7_g6Yk$n zQx6Uj{w{i-lsX zE+-MTsTN}yP-t&Puh%@5DD$D_H(B|$&AGwNfr3HRh2?4qLh||f#(461hUU>UtaZ5)vr9PKm^8 z#9pxi3Ks9!^i@#$e&Lf6pxiZ+81d)g+!fu92uKx);ugpaL)c7CZd5LhRkybcB0O;B zg0MzmC@vye-|8q#6vjF+ZinIK4)!cdLX;-ma0Ec^5%5Xblc}r1eYx=GN8Q1$bGYN~0296pn3E`ixb5U-aM3#+5mG;5U zPJq11x2t4~RFA?%=JeIikLnN}(syRw8=}Sn^z=1*I>26`iOzE&w&Gh=rp2Hh13Sz$%RT{A}7DH^)$%n->J2xKo_RIoWKkw~Vuq z&G^;Tr+3wwP;CUvw5#JeW&2Ag$w{%WtNx`|X-SfkUg2}an#akS5DR21vlR5(bLW-C ztmNYxx?^8#W%}38p{3y%87m-v%aac^*9=Q6SjP@m>U*$~^Ebt%3e5RCK7G}eSR>b; z{1Uy)F>X*>ox~O6RqfHL)m#p!xlrg(BR5G-db1T5ko@ra+G(cU6yUwU`~cL0WGzBh zV9#jbiwbW=(d_#wU9YtBG3^w13gsc>$t7K{IVLIfOVb-=;FRos00bl1k zCr26bw5LWWaLsOSVzR3p2plKkoBWY{OO)gMPmnoM33MCy@_;}y0;j*Ln;1a<=_30C zB4cYcB)unj;iRSfumgzyfC&RYX`;S=+huS_0M`I16XKDzC@9W)JMJWmYa?HUf2BMNwd_FM`(N~m`fD-9g&8J7<(U};J4kDvGV9) z4-rX~p(r?sOWzx6m7I5k%&m{l8b5999*Od)s-h}3#@S#PYV{|GAEAz<{efO<=Ncgu zp|iMUh56-UpBs*V-niY8aIg37FKR>CG*!oQ16ZCk74lhB5)p~B)Hyvf{*XVa(6l@b z*B+JfN(`I~0c;TUUl)Jo1Koa`gaMg`-W1z%bn&K{PqqdA~GdoSkJ2h;cQtQA{z54X@2uY z%PTbZ_X~z;Yp$VvaY73E+q&7$*oCy6w|6FIQjD`aJ&Puv!J+3Jg5VG&e^0bipY3SA ztXXq{Eq^;(Q_sE9n#vf)-pgh@5kRa)QC~sR!^(zkwo?HH1$PDS_{eDD1X7?sYy7i= zXiC|G#l5~A#Hh4tdQT)kw(?g1^tzySPr08EP`JAAm(&mPda|bXrJ^yj5;f`h&|%pSn5R^9%C6Yt zu#arsfL}{`jDTR~msyX2YPlbkS04D))e19@HzsTs5Po3q=7KtkeYcHdUc-2RTxxaJ>vL+_p?mZ1dJewJuF zZ2yg^ahUNGusy+9j;2=;SYt0UxR#?_(M++nQtU$M!N+kK`Uq;guXSTwrYAhNG5$jd zZ*BJFpDXC)ns2;DHq>&F)N>dam<5JxpWa!-E(wsw#JgaAB%%+({Y3UZ_I-mt96YRv z$lark*FlkCW!ra}I_OI3VD_{so?2zNXGd%e#>+Cg;bA1S6cur(vu(?^L4(fRQUjEJ zSPWPNdq2Z1E6$g1u7+uxb&=x<(6zR#AN13$YrAcE+Wc#EYLEi@$$NKz)*@u|?Ri8Y zfP-ZF<8c41^k@a?`%Azz-|z6eBLSJw%s=4Az=SdTZ~X@E^p&W99uM%V^!LvG~Jf&&WAq6aQ!IWJ+LVdf2sN3BC+Forg?2(iT{ z3s&y;RM@$QJngrh{&s8Ar))c6gb~+5rdffYB2|oet0*{|qa?#~AuP+{(|*lXP-6yGOP*;(NxC`KjG6v{xo7 zuqy{zrLj-BvZ<%-|H4=Ao(D1>RCrC+m`sAU6&A+}Vm74LUy4hPHB(w)MQAYHxBs4G zktsC~4t5(Kp9$my#$E}aIGmmth43=8hQ!<$Hu5M>jgxEE0u(7>!d;D5s}3W$e8a_g zRNKtrQ&^#Im$tn=#G`_X!qMs`=wI3O&eD} zZFY2qhr=9>hh&Y&``i~aahjJwA zvI3+4%?lXSEkABDiS|t;L{0FRvUs)jEvILd4R064KHIVDe4W%uuk}&@3;w4jebl=* ztzz)A>S>wvcPmahz8aj9HhWtl9+5g`_PEX(U0JPf-+;yR(a^%YQCuwNJNTg?-2Bi$ zj}QGNtWs*Sz|_16?}!?w&m~s%1^l7q6R}yk_5;G!}AZxBjdmgjt zHgS9fxZq!P#s30#gMCq;nk>)U3hYtPWcOV!NKpiH(#cuBHIa_yI4B~pdUCfq)Ztpq z!HoWFt!n&6pT_oG+|2U>`Lcu9>|1pH4v_OUR$8b`(c9`Ze%so1kB8CnEZ%G`phl_G13vqP+5J7dBBvPv!xG5$y8uPrq;r413BOPVttPKTH43$wjW zo3T%Yi#5JF(KCE6jRL=u!lKtNl3sQqveFl+LOo+17MnB4rL(2Eg>cSMAzzx1ES0C6 z=7Rb}JHCb|fkM05Tw^F_-$zuwByff1vqIUHS-JNwj5*-e9YS znaosPptVIIkdf#t2h98}RFJWVEeY|KF-XNKI7CS>U|5(iyHmp|lMXP_^29-bs^WCw zVxN_MNEK(2@9ppYNfFGNsgIyD2eGj%|5DF9Z4aZZ@a2Nj%8z-S_uaDs(<;oPE%1<1 zzU%JJ4oC#BwI$a}XgKr8E{g6)B(VogqH#OxBP1ShJ_6h?abnzp zNwcXBHAsG-8G1lYmoQo&P@&WolJ{k4i?Yp+*R=A8LfmCW@TyKBV#7v02;cq~#(r`U}h4UVl683(aHY$jOU#yR{m7~FXeyATY{ZIAyjY13~F40Wi;daAO0BDw zchr&3IK>|8)Aga+vCQ-Edu2k!nrRkg48YU?j4UD>(*nnCaZFA+jC$6>SAGuKOs48m zEO0(m@czqn2grl6`5`dG)y*a4qLZSP68Vk-jpuf-c-}Hme(&**!+4zRUeKe3|IuQF zZ}BB7+BSF-L@vg0%zo8_<_Fq|ic5YJ(46r7X5r9@N0+j{Ro+;0%lnt_WN@Iwh;MPS zA}e%#v1qXBP^sp&CLuGc!6P-md$>1*0(stX%%%6tzl=`#i&gE2p5IYi_i#!yoh6PN zb4nbONr40~px)!)*<>({3zS!>^4G}^R7dz13fvnIdFD3uY50HqJ7oQP1(A3~nnx7M z#bhojkUUw@3AW1>ecBn%HJcd0JbHW_yl`~cld~Yw^OWty6EOP0`S+<)!ZO+(zZ4WO za86mfEL%u{rl0oH>4B1fW9X4l`CK-yDzW_G%y`lxF{;N=J$7bTa=Yb=m|}S@QER}r zwsz;eHO&6JYub$L#r{S`dJ-%>$Jy*@9DDpdeWFV(<#dQ#N5i11bS?N~LBDlYQb|eT z=L2+lhATHG!e+S1Jzh{@LZ{O_i@>)#XsMWMi6c7Hu0qsj4@0i}{qKb1z6uU74flbR zOW${N4Z_PDv2Tt$d05rhPL{KlR9JaO3a4)O_8|;Qs_H>A%O9K^+#A%FD#(e5ixs>N z@*|9oOT8s4t15>-COpwodiiSWW&8=xXS#3uDpqbMU$e*+Pe|2{W{(@KD6Iaq*I=-; zTkghi0@?Q0s;bg&ufCU5JssV(?^2}R(=u?3bSz`T+@1M*W`M_Csa0*Q)7n1Y`(0T% z(-l;t9);;*UP3}K`1Nci)+&Rwg#fN=OczlEWhKyt_Cnq%?UaqRS$NvHqj6T`RO zeih7&v#B56cCPop`_1kE$H%}c3;olB3$f6|e`0lXjvr%yi@TTg<)YI(?>Lqob2b_!Ov<|-FQ z+S_=H8eSz(u3yNJ+(l|i7hWui+edSiB>Z0WeCp1j!1$EF>wWfX=2gLhdXGdMLu}PZ z*)+}Iv;(bc)ew+jjSjmgt(TmGkt|Y>$6XqTWKzH{yfq{(haCB&%_Of`|r zM%j6Gq@=CQyPI$^luYh4MlA$7Ogo@%<%D$Shg>MkQS>?3xc!-&N9GVEgvjGKJZZ@* z?zKw2WfgvIhvtNq_Im7O;0nnnH1m_sw`});7tUP$Yk6s8LR5F98Mj@hOD54M-yKQ| zzJx0(*|K^-sY!C+Ei{K5gn=tu6EpH`hKi#|=Gx}Ygiua9+zJ654J#^4=c%%GKH$vR ztmBUEv}44CC(hj56oc+YK`D{8re6;+n6TPhJetdnHr{|T=;RNkWp4WMTV{0twnfF; zNpVA!Ipj4_oaoffS={8;Ifnr+a!NymFQ|$KcMcWjXf9VUhl+mhkNqv*=wUN_(Uop4meQ6X0 zQJ!@YkF#jVIq=rHo*oS5aF|!%t=;gg;kPUDdK{N}*YSLxtW^U0TQNWX{ldX%!H%9j z-Vm!9*lE0Uy*5UK3#0J^1IZufo14yzg2%y)E_)}M=vv%$bh=SwGc%0POCR@H3$T%` zH0U{yYA7wz-n>-HNir~~|1KAY*nOn7d}zLD|4OGcYXx!EiSUtHPKh;i$Di=3v+ys` zAO)}tb(Vn^?C;!b1uby|jXu0z=_zdGMLul<#C!-Qr0O&(s}BpO$SHVQ^N*A!eARy4 zyZja^XGb%Do}3HVLMF83IB=ZY5Uz>mGRv*q47dn1b=MU2W}l8!FG+p8NRnBhU${b_ zdEf=;*EWYz_coHG4S&1I(L0pHQi~pFUuVcu`eC>3;Ttf8AMi16GrD?vTgL}ZNi+dI zAG*64aKBq7a|`k0!@ec^53o&NApu*AxuG$IpPa!k+8w>AoJ%NyHLGmY%*WuR%EHh$OGaNkOiv^a&AE;E@D(PQiN`6XA3UzK z`;DuN?_V@@L|JWqyeqYMGt4+oqnT39~gf{7BZas)jZWER&d03IIXa4i0usf;_V6#yEU@`1;djA9z% zGD=$jr_Vbzo#eXh4fhsUpnPqj` zDL<1E3^J~}fp->-4aIfgFAZpAsv9cxl|nymfakbT_Ls+6OQc}$9=1F}Nz zEqNkMQ4$fZ+I~5*L$zJa0QLU*i2Dye)4cLiQlpK91My>J)^| z`DFY)cz2TLAnG_G7cmRqwZgO(mH7{=Oc3(jw2{KjBEYOn0{Vl%KPC*TCMCTDfFWUMy}TG zoM$mxcQ63TBTEJ=YocjBcqR|6M%i`WW&nNOhzqJ3k&v_`T7BMl)E*45BD$9z3+%wm ze28#(vk91PWCV$ugktG}Jf{E{+@H|fU#^0sPbSS@BM>!r0x)Q%L{NgayVBxKH|uds zgt4J*JFoTa;p)Zau#&Cy!;kl$C@%)l{Q5%=9bQ(d+ntujlU?@2+VUH6ob^zFJm3m{ zGl$hs;N5csOzWI^8Tkb<6@fJGoVbH={&WED3Te?uPC(x!g!w}nG-pD)mxGfVmuHDD zj=2-mY0Kwb8&W!L-cX=_4?%}lU+Fz}gwTtohL_joVaV>$o7KKy24Np^Jet7gS~G$_ zjNLWMia`1R8lI(d2Ba&;IM-iD)J!kss1Xn}YfV#^OjC8{yC=Xeq$6HsPf)I}y;-g? zc;SLl0P9dwwcBZLd+JN>mF2uUq_XiZKLY$jgk4eMx5C+Ph7vM3-c@sa-|BCht`UDt z-Oh;Ss!B3CGnh_~1P*I=1nJ zamppo4X@C}mc3m6c^WKXGOE%&ojOoZrCJ=D?N1mQeJnH-rY&ka-x;=FK+f_qPrlw38=KP&kMk!zgWt31Y zlJrp-##Oa)H@O^5H4iD=XE7-hJFq_Y0??UcL);$`{t^vr)eM=mfNZ_x3S>bB{=H}? zGMs>QwdG5_8qBNZHI{i`^g<7RNAteQLR#Kj{TUrF+1lsB>~mq4>tNK7qsAUFH`ekm6pq+tSe!+d8osWx1prSs_q``w70C}>mr*e zM)3;SeGj1uFA|0<`1a<*WWVhNrB(XXVw+&)wRQoQWQKHjQh&}01TF;U_g(7C+b`GW z(dQrBX@`2w;j> zPl@%4JPk`0U7pYs55Y0L9{aYpB=KSfRj>4W!UHIM(1Pl|Gt`OVO$ePN+Axw>3l8w? z?XFempJzNXeePKn4o;-i30@e(L~hg+opgAHRd&vcdXGFnB^VAfb5G3K9IX2(=mCO> zFEWYR3&eWp=QPbJfrHq-RdlvftD+iRX6XS-*O;H~^|os$F%2~_j`eDbXb?k=HIGMZ z+WbhFYz=)}bAkAdW=ZBdP|!{l2A&voqZx;Mobu`sTGGjfa7Ka~G=b0zk)lK;lB0N9nG!L^+Q`Uu^FPEnwRRH4`U>LiuMzaK+v?3R^zpov==7oZv4d6rK0WQcH?O z?ouxLmK-7sogT)w44_^FILD0|cRk}X>XP4fNL@N444%11x||r@`_TmsDqntnrI0gQ zE}|RteuLqBDA-9D`2w+`y(R{p8RUnCCVSs7b1Gb+3ae!~@b-gb?>^x}0EXCA=bJ9q zQ!aq*huxB+OZ)75I8e8U@kTx3i%pI>&9$F((<+joH~hVJ7dPScU?;dz*+@BIzsm37 zM8Jj7t2a^dx2WIHx?Bo2 zycOO1wCv3n0Z@xe?7Om~YCG!rg71LGbskk+#(zRyTbm`QdcU*!=c0sWUxR|vP|q6i zkXBOjv-h>*>5C}8{64CuJ9_Tzv~cwG8VcuLhfBn;dZWRgBj~_?T}KPAMaSE>uy8rq+bhaByfh1dpAp9d@EUKJ2CTI zgIX||)C}a`la-(+D!?3n5*6U<=5ClORCK{o)a`1&>3bit$R2aP#EzHhnDi-kM~S7K zEt`KG~fBYL5Yo)SN7+W-3L)M4um| zN~`a?S6{BolJ>6L+`qx{a@m3`K9M}aMu*N0cI^*%Xlq8+J3iNeOs572tn~cPHnCZR zze14^F`tgz&FNZ6hmQhEZaw`0u81ff5zKEaZeX`>H91Ojd&_s7qZq50-WPCxF_426 zx@Jp!BH#}mZmauGd<%6)^(h*TD{9c^zB-XhnK_elB%@$;HXhY33hV7)M zq=xBMvO}twx{&pip!fGB{|EQ;-@pGrRhjmMMmCbFO`7nacj#k{G7{UDM9%ECm}FD~ zpG#4BM2;W#KPne^r@ealj|&_?&MBO#&^p7mxx)X4_q-j_-1ZnLJ9P?MJ>#daKVYxl zWpX60y~H8a6Bq?85r5%Mx-r*bvE9Y9(rBQyM`yYEgAyk`J#Az1lOD0kWcX6swa@<3 zJTR+jdlII=q@?53vPTaG4j_xns8mW^E-%Dp{mq0}!0Ua|ueY*88(RRKlBFGvo?tou8L+s@zp6vHQ;v@#iz6$Et($=@lSp1&`>;OMs;a zcG})#vkt3ZsuwUxP~ry&%c!JZH9bI%mV;GS!lvwGh|_|O!w|4hT5wq>p;6rZ(LHhhKys!EmNb#kyG^yjfX~zX`TXV5+p{c^mlGoS{kU zV2kQ(FCUla+>qC=3|JW;Sa;I8%^-Mt>6Ty)$hHURlbP{vz5X%F^cDtNlS`XF&1}$G>0^DyM(D>qD47WRqXn2$=#6@-wX&rb)D>;Q+cwUj}wDwG4lVkRVcHadF#*1 z{`0ultX~cyV`t8QAXHN>>j365vG$%0UCPqYNTZLEyndJuDO6^CwcX($QWsHIMTK-S zarw^+{rBs~j@3DV&bE{uS_7=;Q^s7e7RwTM+CaIFM@`D`*w=L2HXFA=YZwh-BrtjS#e*yXJAipEt226 zm6{_W-cng{5U*RC-xS_T2eQ!yxx5S;df4W=opaK0D+v8Rii*!A#lTub{um9Ub+u-LWOX0bY9N|! zyUJx#e?0{D(=3};0ah%b+Mnly+8v}WpDTITo-she6M`LNcpU8G`s8U>*kzsL*ii}A zoc}5DrHk*=L67!SKyQ?;?*UzI!)MbM#M;HfsB#v;1ZytygWrMZv^F8oW34t|4Sl4& zs(zV2WmGNw#vz6(+S>}LOmQsBNme=8mLJvjqLo6|G0f2M{=&k?^QPM$G-FJAJ34y` ze#EN#S&4d&Mh}lxNVV@805CTVG50tBhhrYQ$we25fFofib6CnNW!>HT0}hsTr_8ji zSlj|FN7KnTii*mo=Q-AKYN@`s0M@zheo>2qKLo}~d#(ryJZ&C1<(MG9{{XKf6u#w> z-)GfqDT(5Cjr9BE>-!i;D#nhAjZO;W_5BYaSC(DB7GzQoA=SG5YM*>~j!U9q2hZCy z6InKwnMGU>!bEY0JkC_ydy>v!iwI4P<@QNiIlc8s54u5%$_abV^n;1R7h$Zl8_RwA z6TB>CtyIGAsJmt?_J97uh5649$O0EW(LmsJ0J=A?txc7Cm!{-j6+lnhEMQ>Jm(i#& zE=h;PmNrnC2ew`}XP=~C__9l7z4e20cb24fieqLJw*>hUw8LS3Y$+FSA@< zU#?h6anz)ob=Hsj_cx?@ZpA!HZhHC(#c$(rNh)K841JPHDpv`>ufM%H2Zbo8|IaZ*HHh;Lfx;Tjrk@4O-67X;=u( zA2A$nHPy|ji=U4s7x3he*SVPwxAa5xOFbXLbS-Wf{=tV~A@d|}9(+zEXm=d9*gRGn zr-}P7K7Fjt5p=OdBy_<*X7%gI*?7QsMkQ(K##}wAayX-0U}3z~ovoxi%&?M^cCu+L zzIhHI2;udEG(1IdgcYs~!MzUD@yyF@wn5lF7SG6YvvKqa5R;>l(%ACN;`^5O+x-XJ z!gUaJ#%@Fc@&~Hw-ym)EwNlV zKaFpG=GH5cs2QwMGR~(PaNe=f+8xbT1+%;w%SjKVjK2;Gd8>c!<0N}$F=l`gx`Y(^ zBZ3uJ$NeM6y`?~}Yv#m+6#;ZfsyGLRECOLUITH6Px8uZ>HmlP3-IQ#;FvV7RR>xO# z4p$Fq{E$r>4(40ti8_bSV<~w#Ukm($kLFxot{;U5zZ375V7G&BKY>(n{n!1~f#`x3 zDD7LViV;aa*ut9?>g`nT@00?1=2dU|J0 zqPD2CnO6?g3Qr)#)vi4Bdu;XPb*$KmrCgUwY^LYwiWOs@ia+>Kd7_(Htoz#fRYPlF zU zk>~Q*V2q9dthTPoLwzHO2vf#59*lq6^;ui24Ia^wnKQiT?7&bEP zddH3mt2`o-e5IK_Y(u)XWnPjk9@CG0Cl;udGr?YSBsaDM$Bf6f19(6~6S za|f9i=T^c4;@0uG`#Qnf@>(K0s0UpBt*aAue@>0s6_B!Xb7?u|cEUno1dJqw^qh>V zca9szln8ZJPl{C@6ltesJZ7lsnfTU_c`m~WPp?-UKmLg8Nkz^|$dP%5Yrj;6LHbxm z%2wUCj7t6yk3>uAaGw6>E82O(MdEEA*p_bk2vse2&%<$i2HrA~H(fF+GCS0%eP!MT zJRcAjEf_ByI6{mlc^l@`oYE7+=jD$FUH!3@_6f*iW>AqX6){?ypALr&U7Y@>BlKAK z)+dV-u%5zg#esuH#oazCeQA25Xy#@AaO=I=#Tv9CtqYK*cuTMxV+{IDKWWe{=RGZ| zSI!Uf|GEK@R*?uab?JYfYG@^4j`DX5FV$)Pw9O~XRVHptcJ-GmT55juxUK5p#kg;; zFtHaB#e4t2uBHA}P#bnMr|#vAURJIjsCTUwbC&h4DyJFpiywC|*$Q;}5TYcUsHqm* zQ!b4Bp4p&egh}~SPs<2MlhIZGXm(rsn!`VgRRi~0*9U~fey=z>-CtR2E;<#TFmJLu zBy5z=JJe9bkCkj(BxfXL1q@OVbGJZh%)-g<`5U@&ZAVT<+k&5lxeA*J(-YPt_N`zo zH*Dp0$0)yEgRVzr^PG>kB5KlXY4cP48j=v4Z>>bwd*h+~y=COK9Y;2((8XS=Na5u8 zcSXk6MEkaD!;0@p={Hd(6Gd~!uL4s2O=hQ`kJwLskJ^x~JAE=A)-zE~&psx>P-^8PLN=Oj@z3M;Ht2gGZOb zOPYnn9kh7)9#EA=W%vJa12+SWr$k>o6SnWouSdpgkZ@|FBL%Eu7q%*L`x0d^*?fE% zzh~1le}d844c-<*=w}Hrvvm~-y`nr~9A&TH9EWL~N0tIZtR-_pKY%C~WQuyJz73>S zfhtfS7_b`+I^g5;PSwC4?{*CAeZ#-qjX)BTh7ccpyhcfZN(433LyEpRg!$@C@Pr$u zv!y%uPN)^4X%wJjO?Er&G$P-2_n@!w0j$MTG>f*C8fHbBoBL|-R#qO;zx^7{b7%+^3@8(|4XwHrl(tWhnVA>&94+v z-}B&++j6+`#?8#7HY105V~qT8Xi<6Mv=19%??l|wZO8GO;zdF_UGpa7+w_vs6jj^M zpZ;btFG%FKZ+Qh?a%6R&vURi0z0`hTm1ahdS<>^FGDVQnS4z029nwmpn)QvFC2ERb zrX#r?_1Kn2SH%qIef3?fLhUIhY-@Ot!U(13RC&a4vBg2dlFVt;yLxR7OqxxidfQhZ zhokZMjeqvW*VO`AP8u}R(x(XGmq?kSWd=Vv^%X6&qQ)b5`FhxBzz_YKFzh!pD>|9v z+?VJ}Abn`ri+`G)JVzozUDV%&mKDQ#gv4;$r7hNNCVSvV++FgEEwytJAY0SoO+ytz zXG4!GTYn-6EjO6+m6$4QWg_`8wD&^iD5MPTp@i>P@q~{OHRV8B&ESKY6!+ zzkl=;*^9oieeq0{CBlN1hokC;#J}pyHT_0e_-1p8p7nOJOTU=I%^X@<(-zb5lzb(b z-&G;fggLFiooC||e7Sspu|$|-_IyoT3dp@kv${Fg9O}s~YU0sm=4f9!m5~|tis?Z| zjktzr$~61r+*zrj7bZ=qP|Mfa>U|jK9Qf1T#lEe93 ziX4@qWSW*DoETR-)IFs;3iu~B4sVU`iEW`fmI<31qio84TDzs4qCD%T=aW)Dnaog< zo$I|)omXl*nrj~7soM8B%ETYdz&yqBl0hw%wunsy6+PLtQ;V1aTQ__eca5hkX?-P1 zN5)o89K+3aD_q*YI3<@YksVjyp5%dbteFN~m5#mSD(_Pqdc;R;di_N`U1U&I2}G~Z zCiBuMu}4_vszi9R8q7I9M<6j>+cQ46Q+&`VW@EWm{aqiP^_uS9d_XmJNQM)d19WRn zsL~@Tr~NxVG(*tlBZ~$&?21)c(d&WgV-1~W4TINB>1|;oI%IZC<$)L!S z>W!T-dAYt8Y;$cZ7;0D2Gf{dOzV)&^zk;8&EXw5Anw5anuN)xN4BDqg=c)MJ`2-bz z`nW=GebA^uIj4fkPw`sB;JTnwhGPTlHkd>im7n0|Jqw*HX^wtIue?uW|ZsVN+ zGPZ%&iiT`?!E@RE5pfTZz|Dr_&*NLUHrbv5JKGQ8H+=?YvpnV$RiWJya$?^IP;&@?&Izg$6K$=xjh=;aRgdyG%=ohib zwsZ|Ew7FjFzIV1dR@*2?(xcVdIKz%!lsrN1({}8%q;98hFnwtdHZxW)k&2NTd&Ylc zT64LnyF^DXu%jCI!feqg$Em}T2r1K<8nR*kbX>(%YRI{QD<696r>R^BfwEP)A&t*O z!BMhbxg80oemO>}jW(TVOR#KK#3D)^1IiliJw=2)WqW1zNv&AX*{rwY%t3LzQz;r3 z7cAGptaafZ*kg?3fuBCF*DAo1|1Pd$;qXa9ikD4&&%DFg^3qw-jMZFS%=Gc5-29$r zBga)ue5Djy52~~~wyM%H}z2a8QPup0nRrvLf^*X3-(fx;5K?LT2 z_Bm*E)PaYwR{Q(CBCQ{zy-ErszXqMgpE+$d0%Ia_9@-C;02y`~kDGqyP;T>ZDpasG!nqYQYU)61sCcD(lU~X)sOda~+$tdze zG!EY3oKCMo#0(GLVPIfz`tJafV|B6u&kD6yWsTE{p?0MuUx{sM>967#j7@-_1wR&x zi<0`4(~-fJyQPablh&iPu^8X+hP@s{XKuO|p$3r9ig~1u-Zy4kRx8p@VAZcXNzc)2 zk_2n?kW1&iO26iFZL}!fD*Lr*i77Jj$~qT6**YTUO_2_<6?jH=75`bA<5lSj9`cvN zwju?jcN@#;*_&UPRp{xx44}ydqC-orOlLai!7#2vq;d{K@LnSaiWUjCke-X|Nr$@9RD9lxWdl-1=O~1^di@Phlm}k&@MaIa*fkB z(OPQFP~5@jIOb2@@KFB9%;|rdLI)#7{?y}-aZ_7|5R|K0RWmd z88`cAl@*$9=TDHaDs?{N0$ZI#yzn}K=p z{)zBVQH@Gf8q7e}cTy4HYVFfWw+qw}zrpdNiIq=gbWa%u(K6k}Cd0DX1Xm}u>)D=P z7i!$9XZvN^;@7Ag{D*1tW>v}ZQI4tayDLDi`7CD66TXWGAq$WGv)=&P_0Jo1t8vG8 za~iHH9(3~<(w7};G8q{bP2l;}bhC|bYyN1qAa*Y99UNcy0iM15d%Du1H%DJoxlMqM&}A8$!HD$mhJv7S4;z2P*KPxhdA^w@bx|N8DV2LLSq zc(uV$Yi1V!Mp$g&f^Np5vsN-RkB>%HH-8V6Bq{>nOk9e4`SD5hLZMSqc94|&^7Vkz zzRD>+OHi4@+^Ci#uURWY$|c61TwE$Dq6YLFl9pNc$$BHjOCndByAIEAISU-lu@EDa zoEDVoBL)B#ZIlCRk|o*w_hIiHkNm?_h&1&Caa53s+xna#Sf@gq+&Jg8hnbc(IUdp| zJsEIzW!~@bd1(y*16QrgYg)F7^r1fR6{A0+ff1+;92{{oq)73P)ciL0R9*$}TG^e^ z%fd@txEG57!>@+t`3T$GM}*gh|7KPIH*5SolCZhzffu-1?mXC_1z_|4_1sc(ctSmW~THFi;1^Isz{ z;2lpwL-Yee(AM9Zo1^{V_V=heSzpcg4>Xb^w|X9eVmILPf2_FsL2pdUdOt5t{9b$D zWcIZx)Dl??;;CRW6=MJJxkY0?Ta6!Q6*y3)$6IWA3+~x>K5+ENPs3&5Vx#4dM8M*K zzf4vJW2z9)ivP69Z%MI@?|E{cEJa7`-Uy1F>uKiL7e2T+=i659qDc*3c~{kAA}U z6E1!1juF_M48m!X!GTJ{6lk6)n|L@_3}$cIQPL-eal{WoglpzJgtzpEwKW4N3wfyR)@SYe>*GpLbI@$t;liR41O)m(^;7w%r`C@DY~G*zX}azz?M7DgN~-s=k7`S67=N6#I+=Tp4(w3Co;Gq-bW@l zZqHQFa~lz=@vxVH{M@l!u5x^$)Pfhsi~hI4`SPvW;p|!Hzi8UaD+eAAtYwLNf1s}K)8tnM23eaC@madMmoGiu2oJ&Vn#Ndi=>HY@M5HBV&-}a zerrWg)J2YGdBX6$YFKP=FVjtsRGat0za39i8@c&judu`i8cljl2cZ zE~iXllcg3YHB)gk1-y$i`jec^-aH$PgX_uFu$#pnyv~i?2n|1a*4wb9=`vsL1tn2) zFXyjCWjiEV5w!cd-Y~C6I0q-Br~X`bO3^pJzt<}=N_8ASNuvQttLb(;^Hk-d>`A0r z{#39+chsnW(Uh@3JP5>i4H;_Nt{UDEzEl{8m3vR)5luSCP!~Sxl|yN%+~QvKiSW#) ztMOAmA}iG`G(iTIX_IKis!UQqFYvqMk%Wss?};hEbghR>^yxG0$&Z!xN)J!P$_aR? zq#O*Le@@&OSMqgl^)x&TVqU0gD2ZqgTIOzF2b)&?B3;bZ2|+ z%g5I1&J#FHt!w8m2B|i`hT%_)X@(t*i(5^VaAO7yQ4JeP6d6>sCi6lc+#?QsNo7&5 zf_3-2%uq;0Ues42F;8hoxCN0LziS)|k8PpdpcfLExFn{F+M!|2>OB8`jZca0+7(Q^ zW{)JOn0a{}>{){(g~K~GrtSp%ydJ^h>mh9LD<$SsYc5h8mh!eXVz+X{jS)FCY<%Lq z*EptSNUtOeF0l72G`Wq?Ef9~^t?29;7GvSELVXG8m4y2yjvqE*2!jd3rn~zu>c9u$ z3k6C*E{U~3$zEc{BGFuFw51Jahpykh+hK{dTn(sK~bLW%Atks zoXQM71U1sOF1U?o)$YjMF}64zU9j)b-!fjjyAa7;(HZ}9YH+yfufH~&;@k9a>TX}` z6mYgIPj`n}P$n?-dcfp-jbjA7(J}=*=V!4Imb z-%FvbUOT6*b4x!B|NH_z@eyAzTTUwKhnlO-UZnJhG|MlRp4`^4iy}DT@AM^p_GVYf zfQ~oe`Ao=g6W+sVMgb#hPm0u*7qYE1tAfQsMVWiqD}u#3#g^UYHcn3DS3K?clO?0U zF#c3~am~<7!+1I4;{`#@5=nUIPAT?1SQT;Eknuphji0`mB}Ww4s20W7RK5}pBE;I2 z2*!7%#&>R>FzoEfx5TpRE-_o}*xNdS%RpjTM zbPW&8{SZu) z&0c;r;b`~e+DK|71;6fPbf^O)p2Dl?-wO9M9%;!I$81?z{o~&TjN1nd3Nu%W#+L$n z%0Ek^X*UG9ze>``JgO&^gT$S-)skuYIyf{Pfc}hlB2M}?%HA=?%`Qljc=rzNeUn4- zj(m?FJ{b&(=<2af<79+hr`s-I}NiDp68{V}c zmhf=V?-6O;5Z2@8@ChBf;JIx~I*5&5=#76({gPeoNWbn-JiJ4p*)-DR`|!Lg>DKiC z*TH&^Tm1empPrc@VQFGWPCn^}CRRZQ6v9N2Lj}$~&}T!(N$|VWk&g!3`7SSkHQx4w zoN*c_)H$aQSV1Rb`Q1u~7D9YQ(a{rTR8KY2CokcPm!az(;ay+HnqxbURKNd} zy&VI`dP|p~SQ7Ulk$EEm6i?;hinB&DWUYhl&poP*ju?RJm4D`@LMt2C)KLv*XR zo%n$@5obA^x*of6xMT%&jej!8r`f4{4%ErtPzhq-aRU^r7?+J?cyzoN#&r<2k9x$| zyhA-UEn?zVvJ)YM$QcJiTyXeJDC|HZ^k6Xz>N0pvitvh;hPD5*w4H-w*NXgmna`V< zh9wm5uK2Uvt_~Fkj-PKrk?WUbGRKLVZ#_B}HQ%6l*ICkK!lZDj!aEN{(vZ95#u9j0 z5^8(n9c+0mq6e1}?+w?zarr1ctd(_ZApjot{+2)N-)XbI3Gdqd$=n+dXcqleCHixJ z9FnDMY*@~)Gxt1@Bu39Si>j>GE#GnuGO!RUis)=MzM<)B8z>Kn(QYQoAf!HqGm0JH zJoc#Su+yxBwiq){8$Ik)D=a`gVze-&==Ub1z(F_~>gC2G;m|gjE zOZmKMGk|$v{A*x0euiGFKI)$=cixh_4%ts zCPBTzb034FX-s0-vRrV47Av>D(kt4*DborriE_(KhDwZHQ)Y}K5ReGV%qNb8a@XFN zNYDniQo^&(_0Mrz5Js;jThOaXZh>l2i&P>p#x+jxXMuGU;?X>mIAcAQ^kkR(j3m+J z`%XqaBe!?usz=U$y>JbdeQ>|kccQtSs%|!EJ?bODAt(7J_G+L8r_3Qv$z@toBW9lC z)_L|)kYP`mai>_YME9s{Gr1Z1H z`|CQ4&kU}c(EUv_Nt8>A7HzgzIJn5Mn4Y_>n$^DI(z3I?SfBoOU?YNJL8)YWW#;d* zIizjXJH(Ds;JnGI$;{czW^zlR7^2*tq2midk+v$d>EcakBu})%7C#jSq5i&z?Sjei z#j;u3tI#BI$))Z)kj$G;@;qUDEd8jrdDUCEwE_u5_@%p;m({S2$Wfd~4b7Uv)EZH! z;sygpk`Nr@9_@5qMthyI=&`^TS^ONfsDw7a@5ef(SloCL{t(*<@C6O5!$1wf6 z$cVg3Vbk5naI0PnZb5HT9dPOm|uO<(qtT z=<8lZ{ zH#RlWcM9Ap_-(!gP`O_{*FUl#^L@P0h=E52Zz&R!l7&i%)2w#--v-DrrsMU}->r-d zF}iOaZC}RL1IUnmHqlS*neFKHU-&)Mb?qK4+dY7{*z?rO)I?thz=~`Gw}SucBa1TM z>udh|L!djqA$3&3S9reXmm7n8ypw&G?e!P8=@w3ithesgbetg?q(OBw0QU*aGBzx# zn+ZHB?d0e+7Hw6=*qzg=Z-DVp$YOk-uhoXDmQ)DrHMD56D)|rf&*mMM)8rbFEp^?| zR@Ii*@?~#dd)!Mjpxj=YND(gzl?^8l(xJuXj%UyjA;npBa)QDQz17?Tuuu%DxU6T7 z^+eq_;b|w~1LU{V8ls0ZOyk3>wS?T(mLc8o{rEH$9-@CQc&`Vx!BOGY#)N?Oo#kPx zc_3B{d&(92;oF}&BG?moyi6Rb=;Ao5%cnn-btEQS(6XcGV@BNrAn8m@MPe@_#F@MA zJkL|9bM*}f`A{}qA9qaB8znjbj2gqEVTTzdPO9gP$49y2WT zjV^-E63Uh3R9IEO40aEEk5zmDFqP~!9y-Egy_`y_i+w`H4bE_-foflpnw|IpYU^0Y6Top#MhLj*d)_}g~)IU(y1LjA7 zkzB#Qq_Z&O_}GKZsISHLmrTO!3%dcCyY5(dnaxlOfzK;PQna-S`{+up|ML`K|?4EtTKy@vhQxf*{-1YBY58An+@MSXe;#ZgumtHMgXL z?dirf$S^8DW!;Fb`3hP89CUI;yKn%LlCr3PP~5I|o*{DD@ySfd(iddcPTTbjHWaeh zYrigazeoNi+Wghx_OSG8;kvbz`EBQF(Wx-6pE>#QAde>XF*UXv3zaeFg9?fpMzpLyUl$uVOzwUmX+gr1^`r(yp$ibuS1yk*B;A-Fi)>mj;9%$8LQ2#0tB+HmD%NCnZxo)u3i z*iAe_I%kUp_&>skH(K<|HCtjXxf|z-xyu^O(;YdRU%<|gBVgU!aG8lG2=R;|NiIiW z99Up*-_%5U{gGy#_lC;>I_~dwt{-Dq;O|d-&w~u$UaNs!28LSM`%a>q@4#2Oy1y-P zMG2-?Kj6ChZe@O0EkhVgAW!N&A#FV@v*GPxI_A5C3PVI}cT^agI=bc6wJVEgi)V!<{C(e#$l~r$SF+pi9Le{0E;jgRuN*bksa4h)Wu7f*qThM67GH|q!141-`8df895$ZZxL9l{SL1lrz7vr#U^gZ zw=4zQ!RexG?U;2^i8hSTbcpe2`%yPvq3hVbuOtc*dhTfb$9nkyrv#MH!S&zxrxNe1 zDpoZqubfMJvmGb6P2)vBUEt_tf?Hv5A6m0HA-=?vdUG`^m!@w*+X6s zv^vTKarITei2U@P$Fv{Ib#NTP`Bd}v6NmT>uEZv2Bk|En0X-Y^2%uVtw>!B=E#mTJ z91va!fJ}AyQ?=An1L4o(N(vf`NYSmw5MW)Hb>t%}VhgoIt|@5Lbe1Wu;vT;b_DVDl z1~=<xCOu!2a=)}NE1B_niTBfAPWpuTOQ47wJ3h=jR)@TR#orV62}D{U`TpR;tYH^J zfCsXaJ8885+`7rBsfQ`9e6wB)vN;@us_GUQRU2osN+|iQP1&4>W;c_-CTe#$-DR;a zkCeu+jHym37NhJ3y#&JN2GGIuMQLpL$CB`yRiVWF_!wFu7~O@izM~_b0q}mpvPOl6o6f9EONVZ^di&&UbG$STK#rLOQj_9h)4vlViDGDV+7|$S!^I`?)3Tfkg?2%Qvk&XLp_WyXYDZO~T^9e>$3wh%)@7H+Gogp$Z`^FKWR@qtg6U04p$TQ z^w}wkHS??LE5bdP^b$$Rz7+i#XI~=cdM_CFFbP(qGGr76IpzPc3lHI%X+M2p$C-7D zaqdC~=0x?e$U9sLmULc_;>7HbVeMVm*(?L5EYsx27e`t<_aNikw+BV_ z%cqaN5uv8NHJ0e3C{sP}pi^W(;+)ooLB&&+kJ8_F1_}-aDV?4M@04A-6^d)7t!@vm zdBXTkInGGS;AL{nh_iiQMp=m}i6INtL&Eu_-0Hbky<$kA-qsv@@6m z$KQd-%~{`9G=^$C~%~IP7ek&rZ6i|g558rQ?$UR${`OH-8;}YfwDmm@qMhRCuWdh5ZS4T|U zm$DcorK>y@bCaCD8+G)Zi`6}_z%;D)NhNi3-fL2wp(E-~J5a-mH%wsgmsNIgOYP?- zsGcg$D4pq`1l3HOz>iT|#Ligq(y%@z;cM5TRU9GWoqdJ*K;&Wh%_{joMk>jfr3Q26 z+jLn$kZi-Vou+6UOB`!dc7KSr_Uc_D(li%#siuC+PUV?mN7q>lL$!~kdtEDa#zX%% zF*mJKR-#gP8@|PigzUy64C%r5wY5YadJ;_+>>j@}S=FPFN(z}xvixI=%<*i0Oe3;H zBvPRvOp$#49XQ@=zw`VHl_aiMlv<&Io`uy+_#Y=%9=zq*O<1bG?|)M_aLi;&iovDg zC}VBAyRRlD%H#<0V8m!k%9}`9^r2H}>($dkd&0%sPEX&}iI|qwYn1%{_{l?-_bNEHXC9lJ=21%I=L25Hz%!&svJwQWNy3_rwz^3%rIw_ za197p;<*D;lvTP@DQUkE>DnajWkn-|q;%%FBpHe@hFzW{m%F$~t13Fw+-fpq%UZBb zNQz2SMz>D%mn6&y&f9f842-$B)6p)5aQ#w|3Tgh-8>*bMX8s;RhhbP!EWmQr|L}JG zDj}}JGg|s7K>v+{jvJNL+wSE2llJQmBD9N1TzwL?duMT!!+{=~fp)zwBu9bv%X@^g zQbKs#Tk%9Snu6pRSRk5Ou1fA!x_UP5&`(I!V)t=fZzkWKNzqlLRJ{F{Q zoAF*t{%GPlv@VAIkmSh9_t~&^s)@B|QO)oMV24r}j_Zfq#Rg&b0EgtA*Q?JKY>%gH zM3U3&8Z7b^43Xbdk@@Ek_||IGh%9})ntFGj23abwPLNAZQ?2x_-r1=+GVKcx-{iKq z?kTNP4TQT1wG;0~$}ZM*`@{*8d@qkTEmaJ{Ld(d`7ihU?;78x_+exNITESbe+uygh zOhGn>e(q1g_l@JfI=F+dH(3&Y^jzgV0IZjV9Qy8Ns}}K2F7ezbEZ?Q?0Blo1+8O#? z-xZ*@J@f#x8K4k(uFoD0Y`{6|HUL{64I8Av({(+=d`I8b{XV2}W_RL^JZgq|fjRMP zd?KDG+2HiFEl(}tlrVC9Sbsc5(L`{Bwh2R?Cf7ev(8~fvKf?*Dzn`R3uUL^(XnOzB zH$u2XlnKL^0_&zqI$uMeqg)W_JlK+~tecc1r#l{UY^++b4ycv4d$e8d*@O1t%8>o~ zhr;!l?SavT^h~27V`X|qQdrYHG2ZOQV3P-a>Q**Aw|90f8wuu5d>jm0YFxdh?4E(K zoLYr`J=sJo<2-})_Bq-+l^ow*uTnAI{_*S|tyn`-amBd$UV>UN&6%Al+fx3`8s&s6 zfq?3Ec(QVB;D<|}7L@}OM(Ro9W`H%T)f0t-^LNLxsxEdJ6}X!KmZgKm>wU#L7@1Z` zOXr@-r3q&9Wa`T%s65`prLp26+{bZ6tJ?bA;6{Nmb~(~1w&~fAYe!GE!+@ehZu;go zG|dJ91OiQvMO%oQXX{63%SFbE?83Q@PJ&jY{ez&D#vw zT8=c zm$fj;C5a<v^=n3<0G? z7~~j_W|%ewr?dk6Q$Op>E~C|u93M+jYHvo}d~I+7sY3M3zr+Ra0N^uk1eI1U;ydk( zrp5Z^0LIjV?WeGX3)&RfICYf#%44&QkNe#^Fjj`}b6tmA|6($07yd-<1Kc{l34_X) zkwe47okMxrJwM4x6(c z9-y4&{QrOTvW6by{C)@dao~Ja(nvX*gsz047crGTxW}yEsrC(dvXO&>Oq-J9x(Z|J z$d36)M|Xv0WV-9fhgrQxH9aIC`R{xU_r8H{`&&D*h@@VEc5ygr*>)*ONT#niqLMat z#8ak&dAiAF)|HQdRaIqCs;fUejw|l{rsp9O`US30iM9Jj{P=)be&#BEh$*k6;;;Y{ zVM=wvyXZd%OSv=N79lw)NKg|9G8HjRVJ&FLREW`#*G`tzVxfyzQm8 zvl}aV(((jRGa|WeU1N4n6Rfw$L%x%`J%t-X_!fx-hz03zf$AB{9L73~25D!uCBD&G zy-NBq&rzj8{wLGty>&)~r&_B0J4$&g*{*`UsZb(EuF?P=vKon$tF)y2RZng>w@TIs zcP&zqmJ-MnLgvn2@jfUeUAQ?s2-~iP#sO|Pd6>TT6`^7+3OhU;jPM_O*F>O83b*l~ zBse9dg5jJ_@q72C2+qX$7hp`Z^}yKJn@v(Jy4_R}T1B|0jA?%?*%Vdcy64O=(QLjo zuc2J!pfZYc_L2bP??r_XE}}(p1;sa7H(w}2&Ik5NaoNL?E$&S9PR)NKOl7tQMA~{$ z#tjg8Dsp}7c8$d&9K&T%KF#fWVY>#*%bUdV{OrAHX7eKj4Z@>V}d}QYgI=2-6=U8(ubYZMIrv1TOStcObd}1HG=Y=(!UUt|D*L3F} zn~#QRyn&zg#3t@}-BS)v{^U@$EcS|ZFh#74jVCqJKK(!MND2w0pQ0%Vz6m{Q9hY138io z$i5Wm8!u7f@`3byYr(D?S_JMEA{xLQo1jS%$1)}ZB-nVZ&Y@>*o5%t?81`nn+u}_R za=2i${o$|F+vX{3@3t%3lWVZ<+ovhMM+e3&Q;>VO1z#DnTD(lRWIMV&#i_qZxvBSE31&VCvRP7Ks5sz$cDnivexQWBTcFyHyBNkG!{UBE zP(W&+sT|9U3_C#{s?ZRO%%(G7SDh=nR6Tt;=rV@enJsc$o~~gU9ENxUZRIR%9&3KL z{Yrp)?A|(27#CI9Bk->MT`M%zF8LBs;SD7#NCtQ9)p@T!SXB>q|EPQ$mjRofE`H;# zQJ$PKFO+K%5H7S!Ub7H(HgzU?UmD?TExTOlXlraQmC zAL%`$yx2rKI*$u&8l1U?eGZaI)j{bU;1`Tizf)K%lWq;xVlP+AQIG!zj$gSkf3+t~ zE5Cr;k(p>h$%~6Yl~)xkmdo;Pe_7uhn5;2WUNPf|Q_S1Vbc|7XTj13FEIuUiSiAN{ zu2CMSd#!HjqD=CbV+%6#UzR2@4&~V$n`shzK}GY003y1|CKZsGS^6~7QJz215)h6G zzeuX09WHo*;1>-Iy{XVRupwS;pI}E;>arSfu`5UwM&-vyVS{TZI*C2EW5-FmIUOH2 ztD&85&K;{yS1T(FeYU@mxn3HtQnL0-3vSy*Aa=+3o*pC3TlO{2+wH8hzMVzjdOLWS zI4Zc#-=RLiyAh9=OKhttyghWdvraQi_x)Z$&)gTZ#N_-sV5=EFs=zOW%r92#QVOr=pEn*LV6O+eM zqbrQys;UB3rJib{=H#O~k(c5)yY7Igm7tjC*iuMR!ffuBT{08&WBuovULwRHuBs#R zCQHM!Fx6(jlZEnUeA11U;6m8&a*rFIdri);X?#Pt3Cw=K7&B5YP*tpsP=-;$kZ>7? z*=D`ds-r?D&>EUXx1rbKWZaTS_tS_!Q%|f)&f8f)di4y*_saiF4cKRK zfi2}hv{N@)RQ+>j+o`CYeN=w@P)Ap)C=#)2kQ$sqtR7#mCP9Q8uCFm8{I3A^u@#>p?$TE+Wd0q4-QePf|PKkQ#s8$fxAgo`p~jz|;uc!nlxUdNm(>$k^37tuAfBMPCWe@ye^4p_YSNmVR*5=w1 z{tCG)!r(?0?dbkC1sUX&F$#_{)v`~?9;mtP8&KaQXsRJ{Sc)pkmZxc;u8qGccpWfl z>ypfYPn=>jOJ=sls7a{r3PX5|9RMk~&MA;io-yJ16A2VQNmZ*2&B1!Ol{%Q!g^WsS zgwJ6ZHyaP5au`!YX34NdBw_(bPnbXXW@GwgyVXtjyNR7XKJqAkOp`y2W3g2&Tx2-s z&P>ovQ_{HjzQNfStlY|pl3&1nlniz|IAS*BF@?pAa$WxD_6=goC9-rW%BF#B#V3Wk zj%!@b=lx;EyCJ;&M#JOA#Zf=@+i$+%=y@qnFs$(cdHt#t{GX$<>kb0+$45?J5-~z# zVFXt^LPszTm1mB*S8JJ@hCBB0w5YN-wqpx!dwg~wYoY0(eR<7VVUndv))&Jj@zxU(l?&`>mIk-en)DU%#keC??+ zsJ(HbqsS(=~qO+27LkquqS9@tI9VF;1pW1?IX>wi=u(k_ zMsbb#bYo>H<)2B)&#mgo3}NnDhGlC@b9{p@tkHO9(sf5(22|&n9@4x=w&ty5l>969 zb(6%0aK9`Qcg@M`)hJrih=Vq#H|K9FSUr>6zU*3I7(b?qh^^1Gk7HDN=q6_Kf@fsn z&*>%Ofrnb!?Th8ElcZK!t3zg#FC;Z6(5(5!@n`A&>+CPb?Wp-_VJ1=I*-)mPvy z%Uw>?M5qeQ?G|6Ei?_xPohwABqGLQYw3mIwvwQ}xHo*s{9l3L3AWN{Xb}t+)%aaZJ zQzh~$pxYHrYKG%(3VY|Dh;!U~`W04;dR$QGtIbPs!76bxT8GqgHgILfe`6l$1yJco z*!mTQY;V~6o5@h@vKKRPvcRy<`NulzM?9ve*O(h5yC7IkKAh8pM0-H0D^*p9ETIP!Bh<4kbOzSJl2D*O&_o2~{^H@gd(CBP?Nql1d!Dw36teI_+UP)zeV2 z>u^?|)0Ta(iLm$!Mz==VcbL21B-a&CTeP{?&&%+ED;8e-F3Z%D4rPPH~SY2{Of?D4R-**{9zxt7V(qlwWy8j}uVIs5Y zplUF4bh2dr$~P;zK|X+qfCE4{g{^7IE1a{jlM@&{Q z-XT#3>kG>|53&So+Y5z_d+uhj*CT;sw~VDA+I<5T8u3Sfn?zAiZErY`FQTLTs>&WL zo4!pexl~*g=5ST#tOWN^_4AD)2tF0aU9qw$r$_^5woP-Z4BLPyS+Yy_3h^y-)AX=J zy>p;v?=zEiardwUzg$x|m~?}z|IW?0J`cJd_HHr24PiALlz;hN$W8OqT@Yvcb29H$ zsTqf6?qsX1M)=^Jk7|}L?3uGwb;l|_$y~AFFpIm`!rB^F;3UWE>W;+4L&m>Kr;A+O zJiE3kv+YZ(1k21^fN9GPulnqgbE@*P&}{goPiKFKK62Zc>0+gFkLjQ;u8in)p}<;rV^6wM4;=8?=h34p5^w zt?hl0)dYua{$gC9IG}5=`H!vvP(W>IT5XK^XVT-i>G5Ifsk*0}Wj@>fvr(^P=t_Jg^(F&kFQrg=F&A z!JF0&n~yF7p;Ps2g~c{l?!BG2Y{6`N(02|0T?Xfp4v=2> zj@`)s@3PKWPQV-oG$jkzOreY^#-|MFHb!)5@oEu2T+)6t{#eK(Yzn`-DQsfuiBV!l zalpMFIU-?AYvYX=q%Fp28fLY1L@qm+k!r~TNI(ne?fHwVpeb9^9vR`^R3;0LDlCyi ziKUmMsaz)%kyUDeCJ4JyXO(h~ z=#$0VI07VMY##mo$qN(a;8pDVv-Q5@!~jcdZ}Qfs7S)ADy6TR^3rCSMM>R^8sW7*^ z7r(mwWzjJc2C@@5V17igY^D$gPv~BCD>{I^?fxL9%tdii<6o}#-gT@aA2xS%H_)%{ z!nRi2Nj_*niPFIn1M`2cd;Mgt0{S{dC>^rt+jsV4e7zl7FuAVYqFrOG-XYO#0uCpw z(Dl)suje(P!}F8z4JAJH6cH$aAl_r}TXSH?)-3)beeUZqK(0^h<>2sWlLimeu23R> zU*k?WOMkk&S--Bt%AUnyfA1+EXCbw#I$T!lpJ1FH-;+k@^q$d$ZZ1}By#*{Ji`hKN z0GH3#CHZ~mw6ubRrTAzR1Totdn%MpO?|FCNt7IG5({TF}qejHs*r+UT40Hw+oi;>T=HGjKv|6>DGRD*!q zk3Uth@cKwr$sIo~P_a>`Db`4Cg8t&GQ9aLr{ZmrAJc`fQ`P-*H``{Akvj>nvIoZ%@ zlsGl)KU(E9ghTJMqxIwIW$OVypU-hcTm2csTPO^61--RcRpgWib~X`5nx`ykXlqAb zxpL*hjbHcGK^>4(#afVAILMt4@TA60mc!LN7${GNd)PUhj4A$k#2aDl&$s>Q=P96ju6WXt+Mz+>d&tv^mXfn z;95=dAgTYT8t>5om=yiKqFPj9d=Zu_6c(Uc1TJr%Vp@KeH+H>h1YQ;DO>$3bJ@(N) z5>t`!(62!Ezf6w5Fc1<;EMu6TpzeP@j5cJqgp3e6|IwTGvt9I5sK`%|{KM#*PyC_`SKTvD%_@91_m;LqcWjv}|1I$X2 z;o6?r`DY^9*os4#8|*jT@}iE-!@PQ;J7BF?yCyHbf;M&v>Lr}LW^-Vb(+EpA-Pb-Pwy}Sj z<{J#~moHnivBS-pu;(PtZJ*(dX05_cY(ERPB;O|CWHnOLVy7%VlbdufGbX0}vXHI- zZtqE1CD?p4YofIew8{W`WPlTOlFFK5pr7^$*nO)xu>JK<=p>JS)956vHIpW0ZwkxO zKINbS={4A?_r!d~93H}$7o{uSRyn-HFl%^wj`z>mm(Y(aof&domIEg_s7_4nd7Wr3A|RBZ&kev@q1X)2DnXZ7~UJ@Y0-X|*%Bk`M!`aP!C_M(5j+?vh@n$W00mEQErTB_Gwz10&?yVH_PUyFD zPQc3N!+^}Q#;3McZ)3O-@gA(Kz4i4a9Gg~qIUdENvc6BFu1AntvPI*fhka+kCeoNI zucW*zrT#!QC$j8;1&LPvay5U{C~jG(^BiZ-vq zjyEN3DSYeb%2xdiiT%BTUFjF6ch{iDXj##&nt^?wfZftMqssx*+cCUR*$@eyIL7gM zWe^E9U{jkX26RDfrv zMPjM9Ort}bV`2hq(Nw8|brU)Yz*Bk4_`mV<3){*v8-B3MrJ+++hBtfKg}P*EKWLWQ z7~?Ez%A8myld4~(ibvLbX4`OtAIVk)1yr|)_QDG}?c>LSnqaFoLaNJ6cUsPn`^0-W z>`iv0Crik^9KjWIbEsEgoqo>61doxP$tM48jZu$Hg0kmiC48>Fw)%$o5qEK7v&kdO z6vt+5Sv!KH@N)2tMH}Vtns*}wvpR-0$3&L0#CPCU5_33xn)f)X5iny3TwJZgq17$H z!MW)sKf*BP$~{4`lJD-im&QjfjnkfSU@7HiXiz^n{<$jj3~p9VPd=W}+*@6WD@i`Z zS@sY%i{v%~eZ^jMnRqOr2)h(-9z5dM1SRLZ8*qQP{q5uw^L3K*x(OUE^~N!k^VO8> zXFRyXdsPe)7WuXMd$n`E#UNjo7$=*D>={($vh$M6#V}0T_JD+Yqr)64)@kEwwYv1- zWn$#f-j8|LOh~?sFJUrQwe5-XF;MlL<_L)G1oG~I)Webq8UP0@+SQSZ5GH3@_fl)= ziuDX?zUX`d;A$yd%-$o;3vU7B%d+z8dBVk{25e0 z1w|qbgD-X^pJSY%h$q8apIB3(JY<0woR7x|5L1v%HaQNfl;NdjP4`5t66V z?e3&g*Uf}h%3t5KHuuENgIVLlN&Bc_{PcAvu@B}Pgt8ZS>f!iOJJ^tHZs|CGmFx)g z8QXNp#hM#Fsl`B|1v3&~IQ}XULYt6&egFP8vfVK?G=4{;!~Wg7QXyNt!kFjNcO`9! zC+%Q85By3YXJo=zQWj~C&CdP^FTl)9DuT$Td!+l=Uo>X-)mY&(}xbs#)E(Cir*bi*-0#R^c0~z(lbw0gN^2gq1EYP*FLH4I?4L71 zT?b^9T;n8FL!Xg4In^kb=CaY1zjE!|Z?r4eMG#35!4Bord7CrY`=1{Ngj~B69=4Bq zt3;vA445wKJAn<-U^so$|D(Y0bAJ!eOdk&vD#NtJftt;7eth^$cnm^}q;*d*?sQ== zck~VF*81s!uO!K_Kh|gdP8N76JaBUP(}NEqL)jAAyjM?PVob9UXP@7vL`ZBuiDeyr zzX066GY=j|1;b|Ps|Cjj?Y5sjL~luM5ICf%$N5O%yb}ZV-X4mLy}1xduKcO@+4s6K z6^coF!bA~zcY)zCBOov0jo67W%ZJ^CBNgGhurj5nwdb4*#ua?$bDiDwDrwIL?i_t! z9y4zKGXA-Dd2rs1tC01I=5n;C@YTPW08;6M!%Cl5cxksWoC{2baUzmZRL4Ld4w&Z4 zi_gM>N3JJt-|)cbXi45rVO>M1=srXPw(K(PZ3E6ca1ujKg-y@yZUpTS zc6g!wDv3mBGk7^}(eMB?_ugv>%e@~(7x!NvPFdft7zna?rGlyxi9ePk3|L8Va>FpN z@ET;A$(%zyxAqr729Kr!ISF#M!LW?@iY%M9_4(ZM)mI$o^VA2e9bYw6FuRSsfu>MT z9pZqTt1D=AC07xbC7tPeBVt*xHr6NqN|7DXNex?qS}KRdekXn>lzlsf8!3n$#s*_2Yp5cP=i63|D-oP#*n|5>f8?RLhu1ZI}LFeEO!-P<+GCrWA zu$3MuC2UZqii+2TuJ6+QCrs?fT>0#f+SkJ*HKZ?RdB8ym)f@P9powaaYo8>} zp2s8gy)&XHCu)JINaZzGXYmCY^hw$9HQrNoJTfW3u>`O|DD4y71xKy4+|^|S6(mo< zuA{rldNpy|xUDn1cUXLr-Uy0(0lRz$5`4ruf#;tW!JZ)-c|0j!8g`HJWQqS_Rk$$s z8j<%WI=paU>3Px=DFWj#kotC5oYOLEmHn+J;29l%GpwtwI@V~Tlc@CQy=}(ojm0e?o%{pG0;%p@w6R+--Q=Z71`zMXAdQRSzmT>O@@%hthy?t?~F=hdTMc(CX0 z>u+xgBPD|~40F2+P6_Ar4mVF9#~?i0aw*ZT1}jRS@Pt?%WE8C`EFm~^m?zh8;rN2-h5wXGf&o9lA?z$+{r9nyJA z(O^4ax!Z_fWB}|w)-$Y2h}QZBgB>BmHgQRn<89*%bGC`^T#AxAU*J=h{cRwH23Y?F zp^hi`Z%SNOi{3YbcOFGLpS!sh|0j7!k|sXvvZh?vu!2RQtKccflpqtos_{k{YOxI! zzM44dRkxYgKTEz@mh3GkR9QWVWVr?G7oiK@CfQccrbcs)a~sge0@bW9qE6%k9SjRg z46US`^@`dP+%@HkR|s0|vBTAKO{WE7UKBVayWYqE76iBd)!ui8HMMo?#9f)X)(EL8OBadg!5r79c_hJ;`0c-M;gj zd;Z)X_s>~B@{otM)|{DZ%{j+-#~AOM3k_zf@g8gpai>=pM*}ywUX+xf@9gc!WaHUB zxP4>FBx^0b<+(flHl#Lk_$#U~S^W!iwaYm)Fhx@xl@RW#$&VhjG>v7t@r%g+Zc9lW z<6pEA9;CG%?dW$Rha85oxtn=cUc=vU+BpUxunReMME(gd=yoIYX7aUHUv~{of6|zIAGjM%>Q?{? zxB~u-EOv1ouJqgd;>YUe#1Q#Mk?g;7e7f%bTUp@0R5I%3^jvlPkCHm^e?y1oH2z@+ z1A+eMZ-4PmnL~X&0=;A4nwpxrj~-dP9R!NJ5-*S>HCb%t4GRcX!q0B%-Y%#5KOpN# zNkC(*?>-`l1{pb!S)jH%yLUgF4gtp2D}bD|pttba;=|4dTtudCoOKrV8<-RV9}4g+5el`@*&RlJdOZs(@!Hos=G zp8R}GR}_d=UNDM#%E`l9rTaG9c?*%9{@L!+5h|N{u6J8BbkRO%JuLqDi)3a}@;AG5 zeIrw9wUyQCX2ll}%zKyG+lXwc@TRNj??x9{74wOO_L8tPZ}GqQo-?D2GlD7RR{(nJ zxT$$jj~+(_JMzISAS==ss8QQv{inQ}rhfT@te^v}aSmVsQlaDGtI^G)LY$e zBM8Al3~f|N9Q5Cny4Y>-BLc{rt!e_Ys!n7ksr2cM62#ScwAggBjhde-6|+R>Z#otuirCq#nX^>7vye{p>UX zknFE+&d&vQD12(r;r<}iystlQCPa6;#LDe$wvyA`xVhj`rqzl5zma5Bc-Ms&gfL$D zCIW8dE)l>&Uk=%YZ(_Gw^Sbt}WYPp1;XJrxW?hdtgAi2${~& zR5yQs>)NH{3qZ#E72Pu3gD9lG@f^ zgSc-{xT+on+13$Kad|aBaq>U6CbRuA8%LaLd*y$c zti4(;gswkR$}9gbe5rpA7HBZO(xy_Ya&_Ge=Qk1C~ap{Q0J-z4Uo=auHG2wGq7aQri`RiV*kAx5042#Y1nt@4(q2q*KZb_W9{ z)1_}@1#=qQhmq5Nw6+x(3kYvqrw1K!_sC%p!9}LG8qLjY-uf4Jp#MWa9AmKHHrwV9 z!j<%XafsA%_SyR+8doj{bVmO5{Wh-y7 zHM3bAWL+v;#(esD6{wh&I*D!=S#Hh#5k9*v3cjl6K^YZGZP1GBg@UF3Rk97}rNn;A zF7%rm(q#mjP6471PhS}J8j)kQ<-saOHwUg6fzkY0fdH#&{JlA#T3B4&x2?@J4bUo3 z+O5<0H9RJ%fU-;U%U2v-Oe7E+p(F8p0c2*hE%-|WCteZ5KVM!OX9LKiY%$HT9%LXX z^{?Y&Negt0Mi(=sG1++g)tS}K-S90WsTdP=f6o3gIlyP>d4@Ba{l6}dZUtg=@G^1T zWfekGSdxNe`fHhIK1N_)k~`fj`WV=&F?8!wvdFx&bZFP=@?{oXpbJ%+RIpO}SDQef zkDDc)(t|~d;?_NQuU38Zjb~8|df%POV#Wz1jBbBBQlIH;1V&=Hj(Y=dp&#Z@OO|)^ zs!IF60DVwyD=rD8ymWx7Xe+Kv;St(yuy@&%@DmeBLDYnlIMMUf`Ft0g2dbcDzB|q6 zuAeDoR?R20o1Ncc^$0KXa$dTVP!f?DGQH7lHU< zco?t3zolrL+WsO9h+{2vD{Pb~R>*=MLet=Vtu*tarf`G83DHmTxwuG3IFCgd8TdSo z=EbeW5brygr+U|Cw45M%^~!Qx|Ea-xb-J)KI@6q;1Nki4L7OWo{}K1l9|b7+-A_nF z=ME`Hs%0C^TQ~rZwp9Xyd&p*h!7geUZ*-*kR8T?{HJ-)E-(08qR7o=^+R7JM5m1&& z(blQ8o)?3@7yolIvR59^v3_@&2**11ujcJc*>=;u4*6Zv(c0`fD7oVn7RJv zRX{DeOaiZhXA7WX#gd-sNe=+1{D8G8I~kq{5P1FbiiC#(;T~ZL4B|G6zEN9(k?Z$` zVGha6mBReJdIELf=>tHhHf#82thVrt+ogojFR>XYtvL~K zwka2swy}Ih`tbxHXmtxHJaUJia~n5eD)be|k?-+`W~A&2MQ>QHV00U@X)4%T4lEi{ ze=9>pTGWo+u|sDL3lQmqAEOC4110w&(LsRHe5%in zE1a3hS^&e5$zht>29TL&dZP`eWr_-tjK~raJL&6W7iB_2j=b&Hd;>5uAU94l?FSW0 zLYFG;w9Ar3iIeipPVaK=O`E&K?Cj{ko4_`Cu@Q;jQFoj17ktqvGw$2ndhR2}F5~9y zG6&!z6ScYcY)rMdCu6P5r7?udrDnFXi=JQW)4TezUO9@X34l3pJzKAplv&MGTKgiqE>=#9#9o4UEA8|1!IUJPwSLW|l{qb5 zeicRjJcBfRbH5z6Z7RFL?HRVyVuIdA4$4>SEDV?HJ;N>DD7TroBbQ+$A!RrfPtNP+ z%0J2(Lfw@JrJM~=v0|@oOXBN3kU@Z6}I!S@f&0++h9x58EUB$Yh$L&=fYsoFOWGqyx=k^A{r3yJd9%eFY|t;W zzMY58@YP>g9 zYUUFrQFne7X zjB_FN^UvCAvlwy4d1YDzh?A!uJ`aiV&MM9?H_pSI+^inUl+Y*jviv*+Y>PO|9$Bzb zUFw$j7$RE*sYuJy39B0Lu0n}hIudsbAuBl&nFYE+-BzznP{pv8eX3_=fav&Q3G8BGOr! z=Q*|{;Ur_Ji7vN7D?LX-)8R#HLrl;}PrlTvTzs0wy?K?5fHqk8F{z&I1$@dWk+vfs zyEmheq4QD?Y+r*fQy;2NJZ?5sQU)gzgf1>TBDo|H#4B4*e@Cp!%hkTGpBJH#qkc2& z*7SSKEu$<-@=M;%-qr1u_`-^j-`%7k<4|RgHhih|xs`XH};kryR@rRH8{A?n9W&LtWM7J9K@jX<+h1>U-`V~ATA75qrsqiW32KlT< z>BO3)qv?ZkmOx%rayXO$nHM!KmeOjzPly$Awfz~d^4tVT znEDxYL_!+*ErIMer7|nFB-yAF!maB-Kg(3iCw$Ux>59{A0S3i3CNmx^l4gPgvn1@# z{;&=6UNT9Zp|XKG@^ZbW#C3J^W}77sAm9#-RlnqrdjB}|XxYs8-_d{txye16h0wLOB8B(j38{&K}U zRFOV>kL$WHgRw`Y>K2aJePp9o@gg(Il?2aA>pmvKFc(a*Ik58s5YHh?O<;xlH&63^ z?YTLrr&dqMokB})4qF{Yjdk`GW}#tpv(}>WLG;x1&59D)^)-|%Nk5`&)WbT%1QUzh z`l>X8HQZJd!N1-w$Ju*hi2>d>ljJy%IcVa9Mo+l}hVZ**<(MQ^AV)5uWWUGLhisbG znBrCX@~2PE&amt+2C<+s-mr>Ib!a-OJCyZQNAsDC`%OQ8Of!sy*+Z8%3#AeT$97X(3S z`Y2Hc?yU1EhqzHXTrh@8ZiJHO)4$}S7s@C&n+I?cYanNImboX>`2CJxaW|V|_({wr zs&oI{Dyyiu;0uN?>u6(y=b$kIOY`ja&Rc5-amh!+aaosOMN-xId8R_1quCEY8iU3~ znPnQ9V^Kc_&jkZ)@e0{xWjxts142b4AH^80OiPez!gB|2(S2QhUthl5!%ZB#5-ObC zeIm!b@Ik6oM8)+3>jDbj2)2Me-DnhFm>4AbVpvtB&LLD-#m`%Fy{@T_znko_Y#V|F z@*tu_e&@}&bve>LgO=teEgeL@4k-euCq#gLzpadvE|cE2=)Y` z7kPUEs>SpvaEW>Fojl!|G(+&XQKh`YeH3J-4^culT_u|=F1_#7Q@r zm%4`zKAVT!6q%MfcRF#!*Z`+%5OH@Sv17=v>`_ZErrc5hvt#{^vlo(64Ko9Qj&t&j z=pDj`#$rR2p6Sm;j@LXyeNWBxOuMNGd%yvYg|P+qR!HMG-N!w`uU{E6c8^V(lN-AN z-3z&Ak6V=&UI5ssBw=f{U9ASf8<{J5ZO~(BcF?M%gL}NlkG5M3`YQxc(z@C$9r|%v&j>$tT!#@dw&V(l^ORvV{cw8WJhV> zsiuPC?3|AYEgA4*BUT{8pIeXa+lsZzDuP4e{-B8{p(!f8n2#gIIC_O}y5!Th^OMrc zB~Pe#1;q*>!9v1OGH7{>DdbRVMjV6*Xk^Wwewk-YUN?oDoJ8XGs={q!Pp!o|3S$hb z^E~p(&J*-{(d3Y>jqP6k!M>8mkeOUU52nZxBUYBTJg;P5(6_9s0LqHt-@aQ!ZLB_S zV$*MM>ao%)`^(=`P6*0o*KNNnQ6cIl7-%|A%b91j9MB*hps7_;p)e?JiJxx|$b#$n zpeiKOyw`KqI76l5xE#Vl8y09{Fmc0JCOhjoMp3k^V(VdU#geF8Edgd9634*j#Tuj( zwy!#j97-|gA;S!F6NC|oA?7#whhj6AQrDgog}7=(+&o*=n!VLpdtt^;<`re1bG9MY zW@8pIrF~XAy4y^^KQ+rF>0SdgtJH94&R%9)8U`s1tniq-5DWG#Si-xb=a$svC~ zesi}7uHyq$@Ur0>wqYTP+m0i65q}TW=ru9nD4fqX@exzA4~p-&=NQIk2*kTDRK7`YyLg)Bg8PZysc+A^xsd#V)OQyz`9QegqY1)`IO3{KqFye+}C ziB}lM>H5OY2H=*f;!8sByv-TfM=iT$sT-V_E0{_CJdwigd z9sTfvom?G3Q)z!;CxuNhIU>aGF$xvCVZfE2g?WU&lYeM%WWH`cJX!cv9rqcUCzhjA z4f9^=6u%f}fn$prX~x!|NtizTSyIB1d;;n8sNB2y=&DwXirlh(^d9(|lIPF?A3q01 zfn>Robw}pYDiz1GlS7|pW|~)5^HK);9;;;USxhaZ$LS@ymw1&D!0YU4DZ<&wp_s{a zSd~nlMDFNi4%qe9V{jkzqAywgOQl)b=UX@SYi3*Z_r=pp>OBv?k41RIxy~fXQ{Cr# zjV?zWXW-wm%U>O;f_s*a&A%*~Zp&U{m7B^y|e#Z5_e`JTifcYmE)F%dV@Cenub z289FEQlLQ@13_=Vuhv84j&et`m^0V>1b@yS4J$n+(bqGZV;DW+W2O^vH2+2pM1mi& zQ}FQXf~1hrf3pbAwV5 z7MWhY=eCP_pkltoi(zSaDa%`Kd3z+nSjwiUmP1i>SDT@!=v1?pQ|L`2R@}~M^aP

|o5g&{DrX4M<6Wzs@Pc-S8(k!u3z6GdrrGwN_*>eFl`(qr)iN7J#oVw!@ zE(mA1@g%@@Kau3*!IuTXye$Cf|0{pu5^=QwKb5@{O4-2+G4nY0aHpRGlM*geEyX43 zJF<09uGL<*!50CKpo?Lv{?RuFfdoNGyDZd{3*wRr|`iCp>ogVDwx^t4@VYGN~sa9%&fX z0)_ILn&u>HEi0~Yna{hH<@#C3*X0*Cn_NAi%c^CHcdhHMpNVZXKR>i^uHb0%>$VoH zxjjw6l|-?||f?hn2VJ#xJmQ(wFm zyy1ke_J~*!4q6#3-4ViZvu=FVe|sLaGn_}pL;@%O>R+wYrf>LM5$F}-KNV;S^3O%e zI)3@}t{n94@zR5)c{YE%?fl0$_oDl5P^g~0Vg)5`83<$`{f&$;BEWR{c0yQ7PDc8gKbUXb7hh^q z%7M!!G!W&d$66?9l7DqJOiUq~quImTa=~^p0H=|HRAP`(uHUr@KNqChfgvH$!?MGJ z&GxKSPjN6lu+SA6*#ah3W2YO|UygL&3=byLd`9q!XJ$CZ@wB8H{s6j>rRK58cz%lm zS*cJ`CCQG-f2GlAxIHT%1&CFA2-^UpR|CC#ENdc?xnm5M0nI%x>xtu9xy5;Q~GYeV@ zXpT*|Pz;ZXs3I(f4awn%X_=w@{9#I1ww=!*`ZFQqxQ*FjINMzTXSzAffYhycn1l2@ z;6$->?q7!sU=B4{EfFy>De-8N!ox5QIb`%0bZgsnke0(F-M4hU!r)|izCIY=DnK3f zEhk}w2aR7V?)ut#Q$`MbQf(Z1q;U|FhuQ4JKW&o;IeQ_x zKGo5%CYyOR6xrnlJTzgW06wg>9Ao5;NVuJ^Fw7_kG!uPaOEoW>!$}>W1WmfJi)!%!GvEO`t{Sj7Eyv zbqsN9XV2D(-%z_4s)RPCgq@|9QX({*R)O{hs`exGYB)e;NKI6yxaLyDqLy^|N$nY) zi*j0D;{9A9Cd*tt>lRf9Woo<-?D3@Km^r-MEM8jIG8aV5@=By@-2?TiD8})eAo1VN zO=#NI2GbWOglgDDS%%bdN2*4|`AP<9=!WWbd0Dx-xgN9$!}ub`YcknOZ`*gT_Dg;i z!rUF1_0DNCNF(!oa&=XRZ34Bi!L4s*JUsd69bkD`KjK4YJHwdUZ&=#bV*_NC1u_1F zCQ3(2j`Y{m$!X0~BoL1WYkbJVvT!JKBe%9q&Ms}fot>7cAdg3M)fSEw#njP7A{0&s zw|S}akssKX7j+T6sWZYqWUP!n!d@#humAK1jMm_7Ir^!0gvruJynh)b_w=&6`SYbu zOr*dIb)kOOn36XlRWe0fORiffDNP>aHrzuDYbv*}5);Eu(+zJ9tHsN5!!D@7{(uSibN%$Y#DIexZpj&xORu!_8g` zw54L$PN5PTVVyxal)2t{Kti=<>mA{8XXMvt4eYj&Js`W*FTYKc>YXvj9Yn48>x}x->yJA-8UJ$}r6K-@fR6VUV0tvlL}DD6Ym~I z!hL+R5?Y3jl~ZblX*fkW9};GY05ix6aXlollBw!ovv~%RO#|qfie+9+rSp>PlGdbt zJt&z*ids@mJx*stOencZw;bsix~Y`XOg!ZG#ZfnW=OisU+_ZQLGLKSHbg#H?)90~2k^3kTe)AG@%o8~UUro8ZJ^Q3~jaG8!GJ)EopZw6C8wcuuQ!|&&QFG})% z-XJTfE+`ZF{w@5HClM>CpNyw7&$eBK6z(wr0M%dp?%N?JGDZ<`!S3<)3Di)tAJ4Ze zk3@tc?sG!_7OIVYP#0E2#jspO+^m&vTtkK_xIF?<%1v0v;y;|^XCb+bp!c+VmmzKA z^3EuXB9V5iH;7rx=c9FGs*z5k?Of~%4?_bikS-1JgoTCc^`Gb#%Qc06AeO73AKa8N z%BofAU4;L(lKx>HB;brfm*s~G&23u{HztMJRB8v@YIBhautam>v#-f(t_Zeyz zwK)8PsNwv37Kv&3 zDU+C?KD2K03#t$bRyuFjR0g?MD4tOk$wVe`LYh?!GC#55Uoud%I7xKCS89_$ukQN| zOMbMp)BrJm@j&a#ev;l&xszXLJXe3Os=o!&-vT%2Bf`39{<+XXr}K9?upDHMJD1QP(7c~2i*7%1 zW7)?7<(BHKWwr2=%W^>_gk8_PAKOix&k!~ACUhs)!YD27*7uYR#fw+lAkBGhW&gwk zr{)5tq#2_PidFs-&iIX~I_+8v_|_|hSo23hjWo(ouPKYIsLpycQN#!Tn`XxlS{s6eL4Yna&>Q3!wgW9kULgK<<3-@s=834gBk+f$7gdqx^|HIioPihf95o zg(Fv$UFh8GOd+AzbN$zv{dS{-GT(YxUYfF~y0HZeGKysm>M_W3sD4M+PiS8a#@KY$ zbx5)W<$ax-MHmttf$#Fm?nzk>O6l)|lWKP9fkP}~b(>*7ZHwJTZcSgqtb5v}P&~98 z$thnwO3K6j?=T<2B_8%a&D@7~eIXo>SDhbF*K@d2Fvh8b?z+b>Q`a0MR;vkruEeC{pnXA}F3dDlV~NK-gT@3DQYv`Q3Du)|GH%3p zn^QTV7wbkww%3{%EjuCDpeUSu@pbwRJYB|G0BNK`qbA_`=ea@TWywDQHJ$w^^uS)# zAj3_Y)qw8ND3T#1T(F0M5DSpfyByRb3_;Xw?8bA@Tq_DUOrS^1s5L3M-_0C80PM*| z?Px2sWbKFt*+;Ldb53do89}|QJ1n1!HXN7hEl&Sey!7K;ZwR$u;$suz#kUEon>;f0 zD)lI7UY%>NIH4TCR(WF6 zXp_2nS*}dzqhspC{k;dykm^T?zYNO;A-J#aYp~+mPEv6-K9gxBW`k`*)-!$B25Hiv zY$b~`++uCGJRNgJGb&hgx7Rayj{pAJr1NX z9D7ItX}HF!&5*zIOH{q)QExv1oR2%L)Y>}f+{#$tMC`T$S2~MDF24BJ4I;|oaQNW6 z$NTHDT+R#Q*~K(WyAdE?ZQ~E9Zkb5=JKblCl>4KkLS?K;POm#P*|LXMmf~1%j!ECO z96PDHC*|YvqJkoJ;y0jS|FrpD(e5#@iP5o(37Fr))``hwXm77j99na#rjz-;S$(kv z2qWIih~vj+Xh5@BFEi}@oFdu#@BWjV{S0_oXlqU1Q`}YhJSNc;Nd~-a@1v3$MhX~@ zQ8iG!)s-;mL$$lpLSKk^d^SrH4j`7+oMK?c6oF{jTy#W{MpjZ%0-Qx15TjtE&Gj>X zP_&3j7Mi8%|Eu(*jLEtXAS~Y$Dfaf6E+DSz5AjS&TlQ@taFjAUXVyzPUKnv%?fnWt z9CeW=$d`sQB8$ZONmqsP&7+LttWPb zmd92dti>ZjMuT0al<33inu{?aEh+A|7p4G(Pmzx(fW7D8#woX7T_TNid$xi$7&VlA z_MjjO_l4z(*Z8OXuuWoTM7Q_Ip_~SLWo?m=Nn}-}F_RJdO0+<+vasTXA1Y7e%;-Ne z7UCGi&p1}G9oS%b>B-&RIls)1qyMrh9h#JU_DBlU*Fq9-H$K4IXcB6(h zDrgEs2=BTnO_XTpok6AZg5oNl_Fbz}(MVSoS7#gXV^vJHSqvkJb^p#aa4}S_+t0WI zly0-d*#e4WhvM~Z#3mOjmZiG7zVwib?}%J+*wuQBnp}kQI76Zd-0B_Z;6Jyo#M}aO$2vC9v zQ)!1aOAZzRvN38b5p-;A`-9TxxAq6rG7MHO>N{*A1`gRn_MI8{=Jz|(@$q(lr#!~1 z4bQEQ=PlRU%{Kh5w>L?4e5K7^wOdV315C@1l4`J{!Bj>bAGz>p)r^owMt1k|4jr#v z9U#^r5$|)m1|FAow>BT%B{%6Q?X)#HJ~dsvE6P;rRE@dZ)pd?eDP(RHjn za3M`ev>@4{nxYRMwqqd_ zL+oO&(kTsRBY3~1#3xy4@>4r>J=}P&!E0#+^T83P1Z}b44_EF8;>SOs9#nH*i%w~4 zS9Dn0l~Fz@-lDqC12qeB3B=^u$vk0t0lgV`Z&Bzlt1$Nrr(GeNnv7if?8$0h{;qPjQ9@`0}sDC+TOk&ibTJksl5OiaD;ja2(42RmjP?(Kpi zCJJ_WLky~=Ud=2suyvmV=_oBJbH%4Pd&JNf!m@&d9yULY%SMCfN<#h!QYYbihP^|H zgEbP(^$&G7bxoKDn`RHf+=B}tHPhAHp&i=2Uhdvdo96#|Umrl_2Q;R`{I5nvBoXRB zJ)bTIE;rgX)Utqt`k58ko&imIdu(!qY-|&Ie~OI!7F86;{&~948O&(0{{H^*^7li# zMopt_hKfknIjF)K2hWHeo8&gFy@&7p`=+!^vi;jEKEzTtY^lJupD8c;^5rbYrJ2{yh~$O`&1|z z+_SgqTnXLTkskGNXs4$7a=YSq++&DwB9Bq`hX4MZf&y$aTs$3K#wp+>?FJfW&>`T$ z3l0V})`BUr4y=a4nixt3Rs)AGXSZlPL2z*Q;q(rJBP-_?zELM(OAN56bh4dDjXx#5 z-t;J|EVgBRRYky@iX7nbjWKK2(8L84HceAS`Rk!rv3YDAP+h3TYsYWA`6p0DJ*uAu z%(CXaP7iLON)ajTd&h^SuF4k@lox$3sgXJ5>;+3xjvfy(R99-WP>!_CnW2He0UGue z1%M5k2szfUI$XUqhJczG`!I+HB@0_zEGo~QJ={bnr*FwTR@q^vyjx9##_f^?ig1pk zr5SFtbq+Cr$AopKsHN;|4NcaL%nnLhKXnO5(o7!Aj@3k}%b_3RvefoS0j zw0J@+ZWs^TQL|SxyX)QIL~{7(<}PQi8#i?)na1QE;AS1^WZ!9DKc}!11h1FM$HliJ zd|3Mj!fU|J;Gi7&EXxC4m$!_H)x#iev3%!#Mj!1!p>q|6=lO93hYS5^+8>z788LgK z4g>Ry42iPHZOx;pTT=Zo8OnpuHLBnMmsoeLD1ZPXr48s|?>he0X<<3uHRdm{8xz6` zTl(>vbh*6QUd@1-2u(+iQn-)Bq1D2iJnPk(85WEIHgUSHfKp<#GJb_rj>skkd2{aV zdWW7WSl04RFvZN{(M-l!6nG0Q(<@!F!!71UWyxxlia`- zvuRhW1jypH^1H0Su7wnkAdPt`XFh|rpud2O9$J5|TC-Dr3;-p9>2&V2_a_l33ZOJw zf%R`+Y6(dSpj_(%F>-u0B&6kb>rxYdyDlL~0q6RCL5KCcR3-PLfL&?<#U`dMP{PcK zRD|F_2>AV#M8Dm#E^eUkGcQ79e-{!uPq{lSk!dym#(kmFK~Pna2__A=m&GB0O+zN}ENxXe z^eAE?j8TM;D#EwhE}K>*3ijnlfqL+8p6S<)NE%sX1qOhc5@oxekf>2WtHh*lYMCtF zQj>K^Wsm3*x=h?JQd9e$ZPi{eUuv0g!efI0gy&h69D@uB(XXBK^KODWfhRs+kXbJRE+~{e_D!_jx$TKC2`oFt8q(Qxu)IP~Fx7ZICKITk19j-x zePJ4omj4kzHbO1z%^h2C#Hs}R3zH4nqiF42T5E62TWV7j*tp0w9KZ=*m> z_YTTf*OkGRPjD}8Ry^zUlyso^!=jmq-@!e>OPPx$V2zv=80K^$8B8@TkXJP9dww6j zs3|#O7#2nIPQ*^b1tt2sz4Cxd&?^*vuAeE$+8DYuF6M5oV^~3c<*2bfhDbX#)>jK- z5J1g$)GqOfN@aE)JrOLh#|Dp4aS&d2ld>uqoU2| zvR_BEjQ18Jd7@Iu^auJ(tdTcZC76EX5pZL#9Qu2 zb=%sLc)Xs{L&>42*7IasfgC!42%)D7lG$<<0>yW-w6z)s>L8IyzI= zTTm}axQxt@y6rvT$v*sb_kz#-k?J42eAr<3Dnnl`Sx28M@Jd(~BY7z}ywYF&7dvYh z)*G>)?yTDom^Y&hBl4f$Wi?HrR1cmfqSO-ucdn7miTX^J zmhOD*Ly?fa2g>4Cd{N6FpLeG+S-alhZ*}af>%}v2c%KKpbWQ(%?}rsZJo zjM{NnOKd1(fxR%U1zztk+BqsaOe>E4sE}M{l!fD0lp~RFoM)V2G7!cprY>t!_cr6+ zjQ9Aya6fE8IU-`Aj@RkXJythRjSQ{RY6UrW+B76@M-@(ben0)d`Gr=iB&8q%dblp) z!A5qtYm{|ik?C5ErA#*f_yQvduy{}lq1Yn`F{d8bDJPUO(4t>2XOhXYTr9wa`x;5N zCa01(yo$t5_(f(~^5g{6wYljHR(=Y64epi1Fukq?_;T*K;bsaxRjr1-tom2ARLdld znftXdy(-?Ly6m7+0pG2y*?uDVz$rlz;=F_=r>PU85DCxZSU7_bdjpw` zS(fLK=2d&FyDAV7Y=DKQ8UocbgJGrhXUZ@VEOXie#7O>dL#CMOQ5vl`Q*TCq(EaM< zw0bg>t`aO+Qc>Za%Mu=iFH1?cnn}j9&W(+3#?U*?#=yM|DyC^S9K1Qmm;i57kx|X^ zTmF`ES$T@P%oMG{s#yOJC-(KmCSibKvo=_ulQ#i)C$3v?hv$>g)8&RO^=%IX{`T#` znBWl2GYdykfs5N@Y|aP&E26hK`{&t=49_%wXd+#{iMYxOHME-&0fKTHj#yJk8d(aV zM`;0rVkC}ilh&UTHM~|HYlnS(#qL00|Frh@mozdK3_j-@TAdGP^ca);S&D2901~+_ z?B3{5@{rc-6#-H-hz7O-?_BCffCs#?%mBbBY%)@k5-8UdfIZwUnk0mx+7P;Y68|xd zgjtrRU0c=!wwKS^O=HE?(iIz8c%2FHwCDw{Iib`BZkUsjUxIa4G+V3u8u`@ApW-|6-T35zAi zlQ+q~##6Y|vt4Weu*WVdQz<4&-o_NSEu%-rc%kwStu^103{Bo3qGOE)`mq zC&a`fZ)YghgoOJA2bxEu>GVg;FaCP;Ybz4|4%^LkNqLr7dTlAfuiMlvgSAE*xAz<8 zjFfX-P@NpUXE`?t#Ed^GbC9*_v7<)|Fzx zc7!{|R_~N|AqHg?;r)H=r*Yn2{C@$!|9YA`)q-4-Oh5_%JdE`tLxc>k&j7hYN*`gAf2<3mE zzkA1ghD!@&EFgpLX93*5^TuzbkU>v<7teaf4(s3$rr1dKbFO!{z#VK}1MH!u3+(BE z_Lwf~L1&K+*Y|zVtIs0cVz)SMvd6u-p*3b5k<7PG9DtD(v@KEqa6b0G;k<%;-~Dc{ z0N@pSVhaGib-eozme<7+C4`+ntDBl#D(0x5u0}wb0X0x$U(=>*xu^{kQ%EpK*sppjR7Vv7p<{v6>zW! z=he24V=IH~Q&2Cqdg#@vA}YsP>PLX~Zi8W%@m!YFf0rXbKt^u|DB?57daa8h(Lgs- zY~Ll%l6KyeFvw;;#4#&&hXT9)u;)WcH2_>V_G;ZW^aV~RoXB7z{?SST-)-}flAJ|= z_))Gc?AIswMbXojuf_~(-;a{VHK@zTknG&t@Om695le~P&1q^ha} zRi->mcTGpm|1n5Ooz~3!3-G1S?--k(krKdacg+i{->}0B{i_W#7>o!>7exlm`ddCF zY36F3^)fmcHe!XZ8WfDN-0flsT1?m7>_A@tR)Du5Vr1mI_TcUM9~*pbDpAd$u8112 z5?0{&2{ogPa_?S5qnzm^acQ182cK6~ll}@R>oDm7<}SP*e3zGJlLhW>@g>HFBDg8U zX>-#oO4_805;{;~IXC%0t%Ym{Ai5}$t{&*(bTY22yNh813O%kq$Pj=3rsT}7ds5Rn zi>d;923a^fp5_pX-nJ74iD5ueBPd{mMe`1}h__$pFGt89T{g$R`QH=)2;whAs7`xr zO6ww!JA=Nq+CM(VPcrh*PCSI%`%68CWRT60(`3lb*P7tDvTVT!`j;r*a1!uC9dKgC zmO#f^Ff#uk9rvq^3$C2Gi1ctq85tP^I1ifX8orNEj*c!E8(rPu_e;XJ!tnZ_Sul$_ND6IKdo`x|NoIr<+;(RqTh<%KEGN4DEmD-k>&$#%XLrj zF26_cVkf7YLMM7?El}B7L zSSQOdsbz5-X7bLCOthPVc-F4?Y+q7><{=$Tdt4sXMZWAXN46MkiJa?%w&7y zBgVX(g}NG)wjp`s;SF3E<7j6Nq9PQAclg%>hzpi?uvz*t%%XaL#;Sry)zX@;SQ?Xi ztOJ04ux#cI+A&gQYx!3Uv)r`skgp@ayh~x4#&PPMVr!2Lo%-9!Zz;h6!m_8SJ5$|H z04fr_q}#XI;n@SSahaK6kq{TRO(!Mr?uC`Pqytv7t%?VAFAoH`Sc{NBYqpCNkS2=$ z{p10Lt0D9UOkqnBg#lZFU0x_|F~B+y}Oa;djV~--B3dNv*~`D(-x3wxbAt?(R|hUR_*=vbKPl*S8j|& zNS$fKotk?45jzGpYKU_A7{IZ?@@6nnuxM#$w)^1uRidJYjF-O+gahZObYD;(4B`8h zV_;WB!Kxb@E4G~LKn%@sB?(Dy=6<8zp4m1sQu7Djp+j8?{vs!mLxF4nwuOzsMDnrQ zG1euD+T@{u3(+gK+9&g^gjtfzq(HC)TgO`e@!R`Qyd~vY&54u9*#j`9uCI8hM`s0U zjR+Gyl^(VS$8fN_)m6Iw4<{usD@anL3pnouZ`zF$W~Q&pt%B_h8W@`dP!sr2M^fkd z>~Yu5OoE~%=q{sUP40_xhLZA$vfSDdy<+FwT z=lqCp;Vvz-bsAu`lfUOvQ~7hv&3Nj`!Q=0@V*0RmQ`SQ z_+lKiq7cY{doFnN8v=r z18^gKajsc~*X6PM)>fIYb~c@lb3v7kIl(0aTf=b0%&u2e-~_=TqK9u zC$>uY&OjK`bd7gmTqUF^3Jz}2W1Yo3(F>iD7hud0n1z-wW{fy5)HiZD&9x3Uy zIzz$pzgPQ0Pj@#B2wmfK0D*(;*Lh&hH4qVx@XX`uKN?U6YmPV{Bhyk`#+;%gAxV;H zD*`piH&fIGw6t)3-4g^doiEo6E7W6QrWn=U%Dz4G05I4i zhi)z8V9I5OD;yb2sKQS>&}lpm2Men=8k=26chKc%%Jhh<+G*ZmBYY${w;P<|??zB0 zcysPy_I4vXhU|-L-3>d;Od-jzXAeMr%Pmgicy8N32T((iO8>PbRP=B{_lNu_;B#eb zwEq=(yv)m-z(+JNjYCW2D_r5H9th*IL*lDwP)7;)XxlnfrBh;Pb5Ve7SWzF8WGqcV k0NzBJp-EMO3igRlY>Vo#Kk8=i_m;1cqH-dYLIwf<2kI3m*8l(j diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/well-known-core.png b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/well-known-core.png deleted file mode 100644 index 93552e502e404a2eb261e138835223a881ae0a02..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9102 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 z -#include -/*---------------------------------------------------------------------------*/ -/* - * 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. - * - * If the node has a broker IP setting saved on flash, this value here will - * get ignored - */ -static const char *broker_ip = "0064:ff9b:0000:0000:0000:0000:b8ac:7cbd"; -/*---------------------------------------------------------------------------*/ -/* - * A timeout used when waiting for something to happen (e.g. to connect or to - * disconnect) - */ -#define STATE_MACHINE_PERIODIC (CLOCK_SECOND >> 1) -/*---------------------------------------------------------------------------*/ -/* Provide visible feedback via LEDS during various states */ -/* When connecting to broker */ -#define CONNECTING_LED_DURATION (CLOCK_SECOND >> 3) - -/* Each time we try to publish */ -#define PUBLISH_LED_ON_DURATION (CLOCK_SECOND) -/*---------------------------------------------------------------------------*/ -/* Connections and reconnections */ -#define RETRY_FOREVER 0xFF -#define RECONNECT_INTERVAL (CLOCK_SECOND * 2) - -/* - * Number of times to try reconnecting to the broker. - * Can be a limited number (e.g. 3, 10 etc) or can be set to RETRY_FOREVER - */ -#define RECONNECT_ATTEMPTS 5 -#define CONNECTION_STABLE_TIME (CLOCK_SECOND * 5) -#define NEW_CONFIG_WAIT_INTERVAL (CLOCK_SECOND * 20) -static struct timer connection_life; -static uint8_t connect_attempt; -/*---------------------------------------------------------------------------*/ -/* Various states */ -static uint8_t state; -#define MQTT_CLIENT_STATE_INIT 0 -#define MQTT_CLIENT_STATE_REGISTERED 1 -#define MQTT_CLIENT_STATE_CONNECTING 2 -#define MQTT_CLIENT_STATE_CONNECTED 3 -#define MQTT_CLIENT_STATE_PUBLISHING 4 -#define MQTT_CLIENT_STATE_DISCONNECTED 5 -#define MQTT_CLIENT_STATE_NEWCONFIG 6 -#define MQTT_CLIENT_STATE_CONFIG_ERROR 0xFE -#define MQTT_CLIENT_STATE_ERROR 0xFF -/*---------------------------------------------------------------------------*/ -/* Maximum TCP segment size for outgoing segments of our socket */ -#define MQTT_CLIENT_MAX_SEGMENT_SIZE 32 -/*---------------------------------------------------------------------------*/ -/* - * Buffers for Client ID and Topic. - * Make sure they are large enough to hold the entire respective string - * - * d:quickstart:status:EUI64 is 32 bytes long - * iot-2/evt/status/fmt/json is 25 bytes - * We also need space for the null termination - */ -#define BUFFER_SIZE 64 -static char client_id[BUFFER_SIZE]; -static char pub_topic[BUFFER_SIZE]; -static char sub_topic[BUFFER_SIZE]; -/*---------------------------------------------------------------------------*/ -/* - * The main MQTT buffers. - * We will need to increase if we start publishing more data. - */ -#define APP_BUFFER_SIZE 512 -static struct mqtt_connection conn; -static char app_buffer[APP_BUFFER_SIZE]; -/*---------------------------------------------------------------------------*/ -#define QUICKSTART "quickstart" -/*---------------------------------------------------------------------------*/ -static struct mqtt_message *msg_ptr = 0; -static struct etimer publish_periodic_timer; -static struct ctimer ct; -static char *buf_ptr; -static uint16_t seq_nr_value = 0; -/*---------------------------------------------------------------------------*/ -static uip_ip6addr_t def_route; -/*---------------------------------------------------------------------------*/ -/* Parent RSSI functionality */ -extern int def_rt_rssi; -/*---------------------------------------------------------------------------*/ -const static web_demo_sensor_reading_t *reading; -/*---------------------------------------------------------------------------*/ -mqtt_client_config_t *conf; -/*---------------------------------------------------------------------------*/ -PROCESS(mqtt_client_process, "CC13xx/CC26xx MQTT Client"); -/*---------------------------------------------------------------------------*/ -static void -publish_led_off(void *d) -{ - leds_off(WEB_DEMO_STATUS_LED); -} -/*---------------------------------------------------------------------------*/ -static void -new_net_config(void) -{ - /* - * We got a new configuration over the net. - * - * Disconnect from the current broker and stop the periodic timer. - * - * When the source of the new configuration is done, we will get notified - * via an event. - */ - if(state == MQTT_CLIENT_STATE_NEWCONFIG) { - return; - } - - state = MQTT_CLIENT_STATE_NEWCONFIG; - - etimer_stop(&publish_periodic_timer); - mqtt_disconnect(&conn); -} -/*---------------------------------------------------------------------------*/ -static int -org_id_post_handler(char *key, int key_len, char *val, int val_len) -{ - int rv = HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; - if(key_len != strlen("org_id") || - strncasecmp(key, "org_id", strlen("org_id")) != 0) { - /* Not ours */ - return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; - } - - if(val_len > MQTT_CLIENT_CONFIG_ORG_ID_LEN) { - /* Ours but bad value */ - rv = HTTPD_SIMPLE_POST_HANDLER_ERROR; - } else { - memset(conf->org_id, 0, MQTT_CLIENT_CONFIG_ORG_ID_LEN); - memcpy(conf->org_id, val, val_len); - - rv = HTTPD_SIMPLE_POST_HANDLER_OK; - } - - new_net_config(); - - return rv; -} -/*---------------------------------------------------------------------------*/ -static int -type_id_post_handler(char *key, int key_len, char *val, int val_len) -{ - int rv = HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; - if(key_len != strlen("type_id") || - strncasecmp(key, "type_id", strlen("type_id")) != 0) { - /* Not ours */ - return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; - } - - if(val_len > MQTT_CLIENT_CONFIG_TYPE_ID_LEN) { - /* Ours but bad value */ - rv = HTTPD_SIMPLE_POST_HANDLER_ERROR; - } else { - memset(conf->type_id, 0, MQTT_CLIENT_CONFIG_TYPE_ID_LEN); - memcpy(conf->type_id, val, val_len); - - rv = HTTPD_SIMPLE_POST_HANDLER_OK; - } - - new_net_config(); - - return rv; -} -/*---------------------------------------------------------------------------*/ -static int -event_type_id_post_handler(char *key, int key_len, char *val, int val_len) -{ - int rv = HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; - if(key_len != strlen("event_type_id") || - strncasecmp(key, "event_type_id", strlen("event_type_id")) != 0) { - /* Not ours */ - return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; - } - - if(val_len > MQTT_CLIENT_CONFIG_EVENT_TYPE_ID_LEN) { - /* Ours but bad value */ - rv = HTTPD_SIMPLE_POST_HANDLER_ERROR; - } else { - memset(conf->event_type_id, 0, MQTT_CLIENT_CONFIG_EVENT_TYPE_ID_LEN); - memcpy(conf->event_type_id, val, val_len); - - rv = HTTPD_SIMPLE_POST_HANDLER_OK; - } - - new_net_config(); - - return rv; -} -/*---------------------------------------------------------------------------*/ -static int -cmd_type_post_handler(char *key, int key_len, char *val, int val_len) -{ - int rv = HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; - if(key_len != strlen("cmd_type") || - strncasecmp(key, "cmd_type", strlen("cmd_type")) != 0) { - /* Not ours */ - return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; - } - - if(val_len > MQTT_CLIENT_CONFIG_CMD_TYPE_LEN) { - /* Ours but bad value */ - rv = HTTPD_SIMPLE_POST_HANDLER_ERROR; - } else { - memset(conf->cmd_type, 0, MQTT_CLIENT_CONFIG_CMD_TYPE_LEN); - memcpy(conf->cmd_type, val, val_len); - - rv = HTTPD_SIMPLE_POST_HANDLER_OK; - } - - new_net_config(); - - return rv; -} -/*---------------------------------------------------------------------------*/ -static int -auth_token_post_handler(char *key, int key_len, char *val, int val_len) -{ - int rv = HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; - if(key_len != strlen("auth_token") || - strncasecmp(key, "auth_token", strlen("auth_token")) != 0) { - /* Not ours */ - return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; - } - - if(val_len > MQTT_CLIENT_CONFIG_AUTH_TOKEN_LEN) { - /* Ours but bad value */ - rv = HTTPD_SIMPLE_POST_HANDLER_ERROR; - } else { - memset(conf->auth_token, 0, MQTT_CLIENT_CONFIG_AUTH_TOKEN_LEN); - memcpy(conf->auth_token, val, val_len); - - rv = HTTPD_SIMPLE_POST_HANDLER_OK; - } - - new_net_config(); - - return rv; -} -/*---------------------------------------------------------------------------*/ -static int -interval_post_handler(char *key, int key_len, char *val, int val_len) -{ - int rv = 0; - - if(key_len != strlen("interval") || - strncasecmp(key, "interval", strlen("interval")) != 0) { - /* Not ours */ - return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; - } - - rv = atoi(val); - - if(rv < MQTT_CLIENT_PUBLISH_INTERVAL_MIN || - rv > MQTT_CLIENT_PUBLISH_INTERVAL_MAX) { - return HTTPD_SIMPLE_POST_HANDLER_ERROR; - } - - conf->pub_interval = rv * CLOCK_SECOND; - - return HTTPD_SIMPLE_POST_HANDLER_OK; -} -/*---------------------------------------------------------------------------*/ -static int -port_post_handler(char *key, int key_len, char *val, int val_len) -{ - int rv = 0; - - if(key_len != strlen("broker_port") || - strncasecmp(key, "broker_port", strlen("broker_port")) != 0) { - /* Not ours */ - return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; - } - - rv = atoi(val); - - if(rv <= 65535 && rv > 0) { - conf->broker_port = rv; - } else { - return HTTPD_SIMPLE_POST_HANDLER_ERROR; - } - - new_net_config(); - - return HTTPD_SIMPLE_POST_HANDLER_OK; -} -/*---------------------------------------------------------------------------*/ -static int -ip_addr_post_handler(char *key, int key_len, char *val, int val_len) -{ - int rv = HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; - - if(key_len != strlen("broker_ip") || - strncasecmp(key, "broker_ip", strlen("broker_ip")) != 0) { - /* Not ours */ - return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; - } - - if(val_len > MQTT_CLIENT_CONFIG_IP_ADDR_STR_LEN) { - /* Ours but bad value */ - rv = HTTPD_SIMPLE_POST_HANDLER_ERROR; - } else { - memset(conf->broker_ip, 0, MQTT_CLIENT_CONFIG_IP_ADDR_STR_LEN); - memcpy(conf->broker_ip, val, val_len); - - rv = HTTPD_SIMPLE_POST_HANDLER_OK; - } - - new_net_config(); - - return rv; -} -/*---------------------------------------------------------------------------*/ -static int -reconnect_post_handler(char *key, int key_len, char *val, int val_len) -{ - if(key_len != strlen("reconnect") || - strncasecmp(key, "reconnect", strlen("reconnect")) != 0) { - /* Not ours */ - return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; - } - - new_net_config(); - - return HTTPD_SIMPLE_POST_HANDLER_OK; -} -/*---------------------------------------------------------------------------*/ -HTTPD_SIMPLE_POST_HANDLER(org_id, org_id_post_handler); -HTTPD_SIMPLE_POST_HANDLER(type_id, type_id_post_handler); -HTTPD_SIMPLE_POST_HANDLER(event_type_id, event_type_id_post_handler); -HTTPD_SIMPLE_POST_HANDLER(cmd_type, cmd_type_post_handler); -HTTPD_SIMPLE_POST_HANDLER(auth_token, auth_token_post_handler); -HTTPD_SIMPLE_POST_HANDLER(ip_addr, ip_addr_post_handler); -HTTPD_SIMPLE_POST_HANDLER(port, port_post_handler); -HTTPD_SIMPLE_POST_HANDLER(interval, interval_post_handler); -HTTPD_SIMPLE_POST_HANDLER(reconnect, reconnect_post_handler); -/*---------------------------------------------------------------------------*/ -static void -pub_handler(const char *topic, uint16_t topic_len, const uint8_t *chunk, - uint16_t chunk_len) -{ - DBG("Pub Handler: topic='%s' (len=%u), chunk_len=%u\n", topic, topic_len, - chunk_len); - - /* If we don't like the length, ignore */ - if(topic_len != 23 || chunk_len != 1) { - printf("Incorrect topic or chunk len. Ignored\n"); - return; - } - - /* If the format != json, ignore */ - if(strncmp(&topic[topic_len - 4], "json", 4) != 0) { - printf("Incorrect format\n"); - } - - if(strncmp(&topic[10], "leds", 4) == 0) { - if(chunk[0] == '1') { - leds_on(LEDS_RED); - } else if(chunk[0] == '0') { - leds_off(LEDS_RED); - } - return; - } - -#if BOARD_SENSORTAG - if(strncmp(&topic[10], "buzz", 4) == 0) { - if(chunk[0] == '1') { - buzzer_start(1000); - } else if(chunk[0] == '0') { - buzzer_stop(); - } - return; - } -#endif -} -/*---------------------------------------------------------------------------*/ -static void -mqtt_event(struct mqtt_connection *m, mqtt_event_t event, void *data) -{ - switch(event) { - case MQTT_EVENT_CONNECTED: { - DBG("APP - Application has a MQTT connection\n"); - timer_set(&connection_life, CONNECTION_STABLE_TIME); - state = MQTT_CLIENT_STATE_CONNECTED; - break; - } - case MQTT_EVENT_DISCONNECTED: { - DBG("APP - MQTT Disconnect. Reason %u\n", *((mqtt_event_t *)data)); - - /* Do nothing if the disconnect was the result of an incoming config */ - if(state != MQTT_CLIENT_STATE_NEWCONFIG) { - state = MQTT_CLIENT_STATE_DISCONNECTED; - process_poll(&mqtt_client_process); - } - break; - } - case MQTT_EVENT_PUBLISH: { - msg_ptr = data; - - /* Implement first_flag in publish message? */ - if(msg_ptr->first_chunk) { - msg_ptr->first_chunk = 0; - DBG("APP - Application received a publish on topic '%s'. Payload " - "size is %i bytes. Content:\n\n", - msg_ptr->topic, msg_ptr->payload_length); - } - - pub_handler(msg_ptr->topic, strlen(msg_ptr->topic), msg_ptr->payload_chunk, - msg_ptr->payload_length); - break; - } - case MQTT_EVENT_SUBACK: { - DBG("APP - Application is subscribed to topic successfully\n"); - break; - } - case MQTT_EVENT_UNSUBACK: { - DBG("APP - Application is unsubscribed to topic successfully\n"); - break; - } - case MQTT_EVENT_PUBACK: { - DBG("APP - Publishing complete.\n"); - break; - } - default: - DBG("APP - Application got a unhandled MQTT event: %i\n", event); - break; - } -} -/*---------------------------------------------------------------------------*/ -static int -construct_pub_topic(void) -{ - int len = snprintf(pub_topic, BUFFER_SIZE, "iot-2/evt/%s/fmt/json", - conf->event_type_id); - - /* len < 0: Error. Len >= BUFFER_SIZE: Buffer too small */ - if(len < 0 || len >= BUFFER_SIZE) { - printf("Pub Topic: %d, Buffer %d\n", len, BUFFER_SIZE); - return 0; - } - - return 1; -} -/*---------------------------------------------------------------------------*/ -static int -construct_sub_topic(void) -{ - int len = snprintf(sub_topic, BUFFER_SIZE, "iot-2/cmd/%s/fmt/json", - conf->cmd_type); - - /* len < 0: Error. Len >= BUFFER_SIZE: Buffer too small */ - if(len < 0 || len >= BUFFER_SIZE) { - printf("Sub Topic: %d, Buffer %d\n", len, BUFFER_SIZE); - return 0; - } - - return 1; -} -/*---------------------------------------------------------------------------*/ -static int -construct_client_id(void) -{ - int len = snprintf(client_id, BUFFER_SIZE, "d:%s:%s:%02x%02x%02x%02x%02x%02x", - conf->org_id, conf->type_id, - linkaddr_node_addr.u8[0], linkaddr_node_addr.u8[1], - linkaddr_node_addr.u8[2], linkaddr_node_addr.u8[5], - linkaddr_node_addr.u8[6], linkaddr_node_addr.u8[7]); - - /* len < 0: Error. Len >= BUFFER_SIZE: Buffer too small */ - if(len < 0 || len >= BUFFER_SIZE) { - printf("Client ID: %d, Buffer %d\n", len, BUFFER_SIZE); - return 0; - } - - return 1; -} -/*---------------------------------------------------------------------------*/ -static void -update_config(void) -{ - if(construct_client_id() == 0) { - /* Fatal error. Client ID larger than the buffer */ - state = MQTT_CLIENT_STATE_CONFIG_ERROR; - return; - } - - if(construct_sub_topic() == 0) { - /* Fatal error. Topic larger than the buffer */ - state = MQTT_CLIENT_STATE_CONFIG_ERROR; - return; - } - - if(construct_pub_topic() == 0) { - /* Fatal error. Topic larger than the buffer */ - state = MQTT_CLIENT_STATE_CONFIG_ERROR; - return; - } - - /* Reset the counter */ - seq_nr_value = 0; - - state = MQTT_CLIENT_STATE_INIT; - - /* - * Schedule next timer event ASAP - * - * If we entered an error state then we won't do anything when it fires. - * - * Since the error at this stage is a config error, we will only exit this - * error state if we get a new config. - */ - etimer_set(&publish_periodic_timer, 0); - - return; -} -/*---------------------------------------------------------------------------*/ -static int -init_config() -{ - /* Populate configuration with default values */ - memset(conf, 0, sizeof(mqtt_client_config_t)); - - memcpy(conf->org_id, WEB_DEMO_DEFAULT_ORG_ID, 11); - memcpy(conf->type_id, WEB_DEMO_DEFAULT_TYPE_ID, 7); - memcpy(conf->event_type_id, WEB_DEMO_DEFAULT_EVENT_TYPE_ID, 7); - memcpy(conf->broker_ip, broker_ip, strlen(broker_ip)); - memcpy(conf->cmd_type, WEB_DEMO_DEFAULT_SUBSCRIBE_CMD_TYPE, 1); - - conf->broker_port = WEB_DEMO_DEFAULT_BROKER_PORT; - conf->pub_interval = WEB_DEMO_DEFAULT_PUBLISH_INTERVAL; - - return 1; -} -/*---------------------------------------------------------------------------*/ -static void -register_http_post_handlers(void) -{ - httpd_simple_register_post_handler(&org_id_handler); - httpd_simple_register_post_handler(&type_id_handler); - httpd_simple_register_post_handler(&event_type_id_handler); - httpd_simple_register_post_handler(&cmd_type_handler); - httpd_simple_register_post_handler(&auth_token_handler); - httpd_simple_register_post_handler(&interval_handler); - httpd_simple_register_post_handler(&port_handler); - httpd_simple_register_post_handler(&ip_addr_handler); - httpd_simple_register_post_handler(&reconnect_handler); -} -/*---------------------------------------------------------------------------*/ -static void -subscribe(void) -{ - /* Publish MQTT topic in IBM quickstart format */ - mqtt_status_t status; - - status = mqtt_subscribe(&conn, NULL, sub_topic, MQTT_QOS_LEVEL_0); - - DBG("APP - Subscribing!\n"); - if(status == MQTT_STATUS_OUT_QUEUE_FULL) { - DBG("APP - Tried to subscribe but command queue was full!\n"); - } -} -/*---------------------------------------------------------------------------*/ -static void -publish(void) -{ - /* Publish MQTT topic in IBM quickstart format */ - int len; - int remaining = APP_BUFFER_SIZE; - char def_rt_str[64]; - - seq_nr_value++; - - buf_ptr = app_buffer; - - len = snprintf(buf_ptr, remaining, - "{" - "\"d\":{" - "\"myName\":\"%s\"," - "\"Seq #\":%d," - "\"Uptime (sec)\":%lu", - BOARD_STRING, seq_nr_value, clock_seconds()); - - if(len < 0 || len >= remaining) { - printf("Buffer too short. Have %d, need %d + \\0\n", remaining, len); - return; - } - - remaining -= len; - buf_ptr += len; - - /* Put our Default route's string representation in a buffer */ - memset(def_rt_str, 0, sizeof(def_rt_str)); - web_demo_ipaddr_sprintf(def_rt_str, sizeof(def_rt_str), - uip_ds6_defrt_choose()); - - len = snprintf(buf_ptr, remaining, ",\"Def Route\":\"%s\",\"RSSI (dBm)\":%d", - def_rt_str, def_rt_rssi); - - if(len < 0 || len >= remaining) { - printf("Buffer too short. Have %d, need %d + \\0\n", remaining, len); - return; - } - remaining -= len; - buf_ptr += len; - - memcpy(&def_route, uip_ds6_defrt_choose(), sizeof(uip_ip6addr_t)); - - for(reading = web_demo_sensor_first(); - reading != NULL; reading = reading->next) { - if(reading->publish && reading->raw != -1) { - len = snprintf(buf_ptr, remaining, - ",\"%s (%s)\":%s", reading->descr, reading->units, - reading->converted); - - if(len < 0 || len >= remaining) { - printf("Buffer too short. Have %d, need %d + \\0\n", remaining, len); - return; - } - remaining -= len; - buf_ptr += len; - } - } - - len = snprintf(buf_ptr, remaining, "}}"); - - if(len < 0 || len >= remaining) { - printf("Buffer too short. Have %d, need %d + \\0\n", remaining, len); - return; - } - - mqtt_publish(&conn, NULL, pub_topic, (uint8_t *)app_buffer, - strlen(app_buffer), MQTT_QOS_LEVEL_0, MQTT_RETAIN_OFF); - - DBG("APP - Publish!\n"); -} -/*---------------------------------------------------------------------------*/ -static void -connect_to_broker(void) -{ - /* Connect to MQTT server */ - mqtt_status_t conn_attempt_result = mqtt_connect(&conn, conf->broker_ip, - conf->broker_port, - conf->pub_interval * 3); - - if(conn_attempt_result == MQTT_STATUS_OK) { - state = MQTT_CLIENT_STATE_CONNECTING; - } else { - state = MQTT_CLIENT_STATE_CONFIG_ERROR; - } -} -/*---------------------------------------------------------------------------*/ -static void -state_machine(void) -{ - switch(state) { - case MQTT_CLIENT_STATE_INIT: - /* If we have just been configured register MQTT connection */ - mqtt_register(&conn, &mqtt_client_process, client_id, mqtt_event, - MQTT_CLIENT_MAX_SEGMENT_SIZE); - - /* - * If we are not using the quickstart service (thus we are an IBM - * registered device), we need to provide user name and password - */ - if(strncasecmp(conf->org_id, QUICKSTART, strlen(conf->org_id)) != 0) { - if(strlen(conf->auth_token) == 0) { - printf("User name set, but empty auth token\n"); - state = MQTT_CLIENT_STATE_ERROR; - break; - } else { - mqtt_set_username_password(&conn, "use-token-auth", - conf->auth_token); - } - } - - /* _register() will set auto_reconnect. We don't want that. */ - conn.auto_reconnect = 0; - connect_attempt = 1; - - /* - * Wipe out the default route so we'll republish it every time we switch to - * a new broker - */ - memset(&def_route, 0, sizeof(def_route)); - - state = MQTT_CLIENT_STATE_REGISTERED; - DBG("Init\n"); - /* Continue */ - case MQTT_CLIENT_STATE_REGISTERED: - if(uip_ds6_get_global(ADDR_PREFERRED) != NULL) { - /* Registered and with a public IP. Connect */ - DBG("Registered. Connect attempt %u\n", connect_attempt); - connect_to_broker(); - } - etimer_set(&publish_periodic_timer, WEB_DEMO_NET_CONNECT_PERIODIC); - return; - break; - case MQTT_CLIENT_STATE_CONNECTING: - leds_on(WEB_DEMO_STATUS_LED); - ctimer_set(&ct, CONNECTING_LED_DURATION, publish_led_off, NULL); - /* Not connected yet. Wait */ - DBG("Connecting (%u)\n", connect_attempt); - break; - case MQTT_CLIENT_STATE_CONNECTED: - /* Don't subscribe unless we are a registered device */ - if(strncasecmp(conf->org_id, QUICKSTART, strlen(conf->org_id)) == 0) { - DBG("Using 'quickstart': Skipping subscribe\n"); - state = MQTT_CLIENT_STATE_PUBLISHING; - } - /* Continue */ - case MQTT_CLIENT_STATE_PUBLISHING: - /* If the timer expired, the connection is stable. */ - if(timer_expired(&connection_life)) { - /* - * Intentionally using 0 here instead of 1: We want RECONNECT_ATTEMPTS - * attempts if we disconnect after a successful connect - */ - connect_attempt = 0; - } - - if(mqtt_ready(&conn) && conn.out_buffer_sent) { - /* Connected. Publish */ - if(state == MQTT_CLIENT_STATE_CONNECTED) { - subscribe(); - state = MQTT_CLIENT_STATE_PUBLISHING; - } else { - leds_on(WEB_DEMO_STATUS_LED); - ctimer_set(&ct, PUBLISH_LED_ON_DURATION, publish_led_off, NULL); - publish(); - } - etimer_set(&publish_periodic_timer, conf->pub_interval); - - DBG("Publishing\n"); - /* Return here so we don't end up rescheduling the timer */ - return; - } else { - /* - * Our publish timer fired, but some MQTT packet is already in flight - * (either not sent at all, or sent but not fully ACKd). - * - * This can mean that we have lost connectivity to our broker or that - * simply there is some network delay. In both cases, we refuse to - * trigger a new message and we wait for TCP to either ACK the entire - * packet after retries, or to timeout and notify us. - */ - DBG("Publishing... (MQTT state=%d, q=%u)\n", conn.state, - conn.out_queue_full); - } - break; - case MQTT_CLIENT_STATE_DISCONNECTED: - DBG("Disconnected\n"); - if(connect_attempt < RECONNECT_ATTEMPTS || - RECONNECT_ATTEMPTS == RETRY_FOREVER) { - /* Disconnect and backoff */ - clock_time_t interval; - mqtt_disconnect(&conn); - connect_attempt++; - - interval = connect_attempt < 3 ? RECONNECT_INTERVAL << connect_attempt : - RECONNECT_INTERVAL << 3; - - DBG("Disconnected. Attempt %u in %lu ticks\n", connect_attempt, interval); - - etimer_set(&publish_periodic_timer, interval); - - state = MQTT_CLIENT_STATE_REGISTERED; - return; - } else { - /* Max reconnect attempts reached. Enter error state */ - state = MQTT_CLIENT_STATE_ERROR; - DBG("Aborting connection after %u attempts\n", connect_attempt - 1); - } - break; - case MQTT_CLIENT_STATE_NEWCONFIG: - /* Only update config after we have disconnected or in the case of an error */ - if(conn.state == MQTT_CONN_STATE_NOT_CONNECTED || conn.state == MQTT_CONN_STATE_ERROR) { - update_config(); - DBG("New config\n"); - - /* update_config() scheduled next pass. Return */ - return; - } - break; - case MQTT_CLIENT_STATE_CONFIG_ERROR: - /* Idle away. The only way out is a new config */ - printf("Bad configuration.\n"); - return; - case MQTT_CLIENT_STATE_ERROR: - default: - leds_on(WEB_DEMO_STATUS_LED); - /* - * 'default' should never happen. - * - * If we enter here it's because of some error. Stop timers. The only thing - * that can bring us out is a new config event - */ - printf("Default case: State=0x%02x\n", state); - return; - } - - /* If we didn't return so far, reschedule ourselves */ - etimer_set(&publish_periodic_timer, STATE_MACHINE_PERIODIC); -} -/*---------------------------------------------------------------------------*/ -PROCESS_THREAD(mqtt_client_process, ev, data) -{ - - PROCESS_BEGIN(); - - printf("CC13xx/CC26xx MQTT Client Process\n"); - - conf = &web_demo_config.mqtt_config; - if(init_config() != 1) { - PROCESS_EXIT(); - } - - register_http_post_handlers(); - - update_config(); - - /* Main loop */ - while(1) { - - PROCESS_YIELD(); - - if(ev == button_hal_release_event) { - button_hal_button_t *btn = (button_hal_button_t *)data; - - if(btn->unique_id == WEB_DEMO_MQTT_PUBLISH_TRIGGER) { - if(state == MQTT_CLIENT_STATE_ERROR) { - connect_attempt = 1; - state = MQTT_CLIENT_STATE_REGISTERED; - } - } - } - - if(ev == httpd_simple_event_new_config) { - /* - * Schedule next pass in a while. When HTTPD sends us this event, it is - * also in the process of sending the config page. Wait a little before - * reconnecting, so as to not cause congestion. - */ - etimer_set(&publish_periodic_timer, NEW_CONFIG_WAIT_INTERVAL); - } - - if((ev == PROCESS_EVENT_TIMER && data == &publish_periodic_timer) || - ev == PROCESS_EVENT_POLL || - ev == web_demo_publish_event || - (ev == button_hal_release_event && - ((button_hal_button_t *)data)->unique_id == - WEB_DEMO_MQTT_PUBLISH_TRIGGER)) { - state_machine(); - } - - if(ev == web_demo_load_config_defaults) { - init_config(); - etimer_set(&publish_periodic_timer, NEW_CONFIG_WAIT_INTERVAL); - } - } - - PROCESS_END(); -} -/*---------------------------------------------------------------------------*/ -/** - * @} - */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/mqtt-client.h b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/mqtt-client.h deleted file mode 100644 index d37c31fbc..000000000 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/mqtt-client.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/** - * \addtogroup cc13xx-cc26xx-web-demo - * @{ - * - * \file - * Header file for the CC13xx/CC26xx web demo MQTT client functionality - */ -/*---------------------------------------------------------------------------*/ -#ifndef MQTT_CLIENT_H_ -#define MQTT_CLIENT_H_ -/*---------------------------------------------------------------------------*/ -#define MQTT_CLIENT_CONFIG_ORG_ID_LEN 32 -#define MQTT_CLIENT_CONFIG_TYPE_ID_LEN 32 -#define MQTT_CLIENT_CONFIG_AUTH_TOKEN_LEN 32 -#define MQTT_CLIENT_CONFIG_EVENT_TYPE_ID_LEN 32 -#define MQTT_CLIENT_CONFIG_CMD_TYPE_LEN 8 -#define MQTT_CLIENT_CONFIG_IP_ADDR_STR_LEN 64 -/*---------------------------------------------------------------------------*/ -#define MQTT_CLIENT_PUBLISH_INTERVAL_MAX 86400 /* secs: 1 day */ -#define MQTT_CLIENT_PUBLISH_INTERVAL_MIN 5 /* secs */ -/*---------------------------------------------------------------------------*/ -PROCESS_NAME(mqtt_client_process); -/*---------------------------------------------------------------------------*/ -/** - * \brief Data structure declaration for the MQTT client configuration - */ -typedef struct mqtt_client_config { - char org_id[MQTT_CLIENT_CONFIG_ORG_ID_LEN]; - char type_id[MQTT_CLIENT_CONFIG_TYPE_ID_LEN]; - char auth_token[MQTT_CLIENT_CONFIG_AUTH_TOKEN_LEN]; - char event_type_id[MQTT_CLIENT_CONFIG_EVENT_TYPE_ID_LEN]; - char broker_ip[MQTT_CLIENT_CONFIG_IP_ADDR_STR_LEN]; - char cmd_type[MQTT_CLIENT_CONFIG_CMD_TYPE_LEN]; - clock_time_t pub_interval; - uint16_t broker_port; -} mqtt_client_config_t; -/*---------------------------------------------------------------------------*/ -#endif /* MQTT_CLIENT_H_ */ -/*---------------------------------------------------------------------------*/ -/** - * @} - */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/net-uart.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/net-uart.c deleted file mode 100644 index 564abe27d..000000000 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/net-uart.c +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/** - * \addtogroup cc13xx-cc26xx-web-demo - * @{ - * - * \file - * A process which receives data over UART and transmits them over UDP - * to a pre-defined IPv6 address and port. It also listens on the same UDP - * port for messages, which it prints out over UART. - * - * For this example to work, you will have to modify the destination IPv6 - * address by adjusting the set_dest_addr() macro below. - * - * To listen on your linux or OS X box: - * nc -6ulkw 1 REMOTE_PORT - * - * (REMOTE_PORT should be the actual value of the define below, e.g. 7777) - * - * Once netcat is up and listening, type something to the CC13xx/CC26xx's terminal - * Bear in mind that the datagram will only be sent after a 0x0a (LF) char - * has been received. Therefore, if you are on Win, do NOT use PuTTY for - * this purpose, since it does not send 0x0a as part of the line end. On - * Win XP use hyperterm. On Win 7 use some other software (e.g. Tera Term, - * which can be configured to send CRLF on enter keystrokes). - * - * To send data in the other direction from your linux or OS X box: - * - * nc -6u \ REMOTE_PORT - */ -/*---------------------------------------------------------------------------*/ -#include "contiki.h" -#include "sys/cc.h" -#include "sys/process.h" -#include "dev/serial-line.h" -#include "net/ipv6/uip.h" -#include "net/ipv6/uip-udp-packet.h" -#include "net/ipv6/uiplib.h" -/*---------------------------------------------------------------------------*/ -#include "uart0-arch.h" -/*---------------------------------------------------------------------------*/ -#include "net-uart.h" -#include "httpd-simple.h" -/*---------------------------------------------------------------------------*/ -#include -#include -#include -#include -#include -/*---------------------------------------------------------------------------*/ -#define DEBUG DEBUG_NONE -#include "net/ipv6/uip-debug.h" -/*---------------------------------------------------------------------------*/ -#define REMOTE_PORT 7777 -#define MAX_MSG_SIZE 100 - -#define set_dest_addr() uip_ip6addr(&remote_addr, \ - 0xBBBB, 0x0000, 0x0000, 0x0000, \ - 0x3E07, 0x54FF, 0xFE74, 0x4885); -/*---------------------------------------------------------------------------*/ -#define ADDRESS_CONVERSION_OK 1 -#define ADDRESS_CONVERSION_ERROR 0 -/*---------------------------------------------------------------------------*/ -static struct uip_udp_conn *udp_conn = NULL; - -static uint8_t buffer[MAX_MSG_SIZE]; -static uint8_t msg_len; -static uip_ip6addr_t remote_addr; -/*---------------------------------------------------------------------------*/ -#define IPV6_ADDR_STR_LEN 64 -/*---------------------------------------------------------------------------*/ -PROCESS(net_uart_process, "Net UART Process"); -/*---------------------------------------------------------------------------*/ -/* - * \brief Attempts to convert a string representation of an IPv6 address to a - * numeric one. - * \param buf The buffer with the string to be converted. - * \return ADDRESS_CONVERSION_OK or ADDRESS_CONVERSION_ERROR - * - * ToDo: Add support for NAT64 conversion in case the incoming address is a v4 - * This is now supported in the current master, so when we pull it in this will - * be very straightforward. - */ -static int -set_new_ip_address(char *buf) -{ - /* - * uiplib_ip6addrconv will immediately start writing into the supplied buffer - * even if it subsequently fails. Thus, pass an intermediate buffer - */ - uip_ip6addr_t tmp_addr; - - int rv = uiplib_ip6addrconv(buf, &tmp_addr); - - if(rv == ADDRESS_CONVERSION_OK) { - /* Conversion OK, copy to our main buffer */ - memcpy(&remote_addr, &tmp_addr, sizeof(remote_addr)); - - PRINTF("Updated remote address "); - PRINT6ADDR(&remote_addr); - PRINTF("\n"); - } - - return rv; -} -/*---------------------------------------------------------------------------*/ -static void -net_input(void) -{ - if(uip_newdata()) { - memset(buffer, 0, MAX_MSG_SIZE); - msg_len = MIN(uip_datalen(), MAX_MSG_SIZE - 1); - - /* Copy data */ - memcpy(buffer, uip_appdata, msg_len); - printf("%s", (char *)buffer); - } - - return; -} -/*---------------------------------------------------------------------------*/ -static void -release_uart(void) -{ - uart0_set_callback(NULL); -} -/*---------------------------------------------------------------------------*/ -static void -keep_uart_on(void) -{ - uart0_set_callback(serial_line_input_byte); -} -/*---------------------------------------------------------------------------*/ -static int -remote_port_post_handler(char *key, int key_len, char *val, int val_len) -{ - int rv; - - if(key_len != strlen("net_uart_port") || - strncasecmp(key, "net_uart_port", strlen("net_uart_port")) != 0) { - /* Not ours */ - return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; - } - - rv = atoi(val); - - if(rv <= 65535 && rv > 0) { - web_demo_config.net_uart.remote_port = (uint16_t)rv; - } else { - return HTTPD_SIMPLE_POST_HANDLER_ERROR; - } - - return HTTPD_SIMPLE_POST_HANDLER_OK; -} -/*---------------------------------------------------------------------------*/ -static int -remote_ipv6_post_handler(char *key, int key_len, char *val, int val_len) -{ - int rv = HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; - - if(key_len != strlen("net_uart_ip") || - strncasecmp(key, "net_uart_ip", strlen("net_uart_ip")) != 0) { - /* Not ours */ - return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; - } - - if(val_len > IPV6_ADDR_STR_LEN) { - /* Ours but bad value */ - rv = HTTPD_SIMPLE_POST_HANDLER_ERROR; - } else { - if(set_new_ip_address(val)) { - memset(web_demo_config.net_uart.remote_address, 0, - NET_UART_IP_ADDR_STRLEN); - memcpy(web_demo_config.net_uart.remote_address, val, val_len); - rv = HTTPD_SIMPLE_POST_HANDLER_OK; - } - } - - return rv; -} -/*---------------------------------------------------------------------------*/ -static int -on_off_post_handler(char *key, int key_len, char *val, int val_len) -{ - int rv; - - if(key_len != strlen("net_uart_on") || - strncasecmp(key, "net_uart_on", strlen("net_uart_on")) != 0) { - /* Not ours */ - return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; - } - - rv = atoi(val); - - /* Be pedantic: only accept 0 and 1, not just any non-zero value */ - if(rv == 0) { - web_demo_config.net_uart.enable = 0; - release_uart(); - } else if(rv == 1) { - web_demo_config.net_uart.enable = 1; - keep_uart_on(); - } else { - return HTTPD_SIMPLE_POST_HANDLER_ERROR; - } - - return HTTPD_SIMPLE_POST_HANDLER_OK; -} -/*---------------------------------------------------------------------------*/ -HTTPD_SIMPLE_POST_HANDLER(remote_port, remote_port_post_handler); -HTTPD_SIMPLE_POST_HANDLER(remote_ipv6, remote_ipv6_post_handler); -HTTPD_SIMPLE_POST_HANDLER(on_off, on_off_post_handler); -/*---------------------------------------------------------------------------*/ -static void -set_config_defaults(void) -{ - /* Set a hard-coded destination address to start with */ - set_dest_addr(); - - /* Set config defaults */ - web_demo_ipaddr_sprintf(web_demo_config.net_uart.remote_address, - NET_UART_IP_ADDR_STRLEN, &remote_addr); - web_demo_config.net_uart.remote_port = REMOTE_PORT; - web_demo_config.net_uart.enable = 1; -} -/*---------------------------------------------------------------------------*/ -PROCESS_THREAD(net_uart_process, ev, data) -{ - PROCESS_BEGIN(); - - printf("CC13xx/CC26xx Net UART Process\n"); - - set_config_defaults(); - - udp_conn = udp_new(NULL, UIP_HTONS(0), NULL); - udp_bind(udp_conn, UIP_HTONS(REMOTE_PORT)); - - if(udp_conn == NULL) { - printf("No UDP connection available, exiting the process!\n"); - PROCESS_EXIT(); - } - - httpd_simple_register_post_handler(&remote_port_handler); - httpd_simple_register_post_handler(&remote_ipv6_handler); - httpd_simple_register_post_handler(&on_off_handler); - - while(1) { - - PROCESS_YIELD(); - - if(ev == serial_line_event_message) { - /* - * If the message contains a new IP address, save it and go back to - * waiting. - */ - if(set_new_ip_address((char *)data) == ADDRESS_CONVERSION_ERROR) { - /* Not an IP address in the message. Send to current destination */ - memset(buffer, 0, MAX_MSG_SIZE); - - /* We need to add a line feed, thus never fill the entire buffer */ - msg_len = MIN(strlen(data), MAX_MSG_SIZE - 1); - memcpy(buffer, data, msg_len); - - /* Add a line feed */ - buffer[msg_len] = 0x0A; - msg_len++; - - uip_udp_packet_sendto( - udp_conn, buffer, msg_len, &remote_addr, - UIP_HTONS(web_demo_config.net_uart.remote_port)); - } - } else if(ev == tcpip_event) { - net_input(); - } else if(ev == web_demo_config_loaded_event) { - /* - * New config. Check if it's possible to update the remote address. - * The port will have been updated already - */ - set_new_ip_address(web_demo_config.net_uart.remote_address); - - if(web_demo_config.net_uart.enable == 1) { - keep_uart_on(); - } - } else if(ev == web_demo_load_config_defaults) { - set_config_defaults(); - } - } - - PROCESS_END(); -} -/*---------------------------------------------------------------------------*/ -/** - * @} - * @} - */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/net-uart.h b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/net-uart.h deleted file mode 100644 index 362bc79ff..000000000 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/net-uart.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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 NET_UART_H_ -#define NET_UART_H_ -/*---------------------------------------------------------------------------*/ -#include "net/ipv6/uip.h" -/*---------------------------------------------------------------------------*/ -#include -/*---------------------------------------------------------------------------*/ -#define NET_UART_IP_ADDR_STRLEN 64 -/*---------------------------------------------------------------------------*/ -PROCESS_NAME(net_uart_process); -/*---------------------------------------------------------------------------*/ -typedef struct net_uart_config_s { - char remote_address[NET_UART_IP_ADDR_STRLEN]; - uint16_t remote_port; - uint8_t enable; -} net_uart_config_t; -/*---------------------------------------------------------------------------*/ -#endif /* NET_UART_H_ */ -/*---------------------------------------------------------------------------*/ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/project-conf.h b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/project-conf.h deleted file mode 100644 index 06cd4ed09..000000000 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/project-conf.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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 PROJECT_CONF_H_ -#define PROJECT_CONF_H_ -/*---------------------------------------------------------------------------*/ -/* Platform configuration */ -#define BOARD_CONF_SENSORS_DISABLE 1 -#define WATCHDOG_CONF_DISABLE 1 -/*---------------------------------------------------------------------------*/ -/* Change to match your configuration */ -#define IEEE802154_CONF_PANID 0xABCD -#define IEEE802154_CONF_DEFAULT_CHANNEL 25 -#define RF_CONF_MODE RF_MODE_2_4_GHZ -#define RF_CONF_BLE_BEACON_ENABLE 1 -/*---------------------------------------------------------------------------*/ -/* TI drivers configuration */ -#define TI_SPI_CONF_ENABLE 1 -#define TI_I2C_CONF_ENABLE 0 -/*---------------------------------------------------------------------------*/ - -/* Enable TCP */ -#define UIP_CONF_TCP 1 - -/* Enable/Disable Components of this Demo */ -#define WEB_DEMO_CONF_MQTT_CLIENT 1 -#define WEB_DEMO_CONF_6LBR_CLIENT ROUTING_CONF_RPL_CLASSIC -#define WEB_DEMO_CONF_COAP_SERVER 1 -#define WEB_DEMO_CONF_NET_UART 1 - -/* - * ADC sensor functionality. To test this, an external voltage source should be - * connected to DIO23 - * Enable/Disable DIO23 ADC reading by setting WEB_DEMO_CONF_ADC_DEMO - */ -#define WEB_DEMO_CONF_ADC_DEMO 0 -/*---------------------------------------------------------------------------*/ -/* - * Change to 1 if you are using an older CC2650 Sensortag (look for Rev: 1.2 - * printed on the PCB, or for a sticker reading "HW Rev 1.2.0"). - * - * This may be the case if you are getting this error: - * "Could not open flash to load config" - * when your sensortag is starting up. - */ -#define SENSORTAG_CC2650_REV_1_2_0 0 -/*---------------------------------------------------------------------------*/ -/* Enable the ROM bootloader */ -#define ROM_BOOTLOADER_ENABLE 1 -/*---------------------------------------------------------------------------*/ -/* - * Shrink the size of the uIP buffer, routing table and ND cache. - * Set the TCP MSS - */ -#define UIP_CONF_BUFFER_SIZE 500 -#define NETSTACK_MAX_ROUTE_ENTRIES 5 -#define NBR_TABLE_CONF_MAX_NEIGHBORS 5 -#define UIP_CONF_TCP_MSS 128 -/*---------------------------------------------------------------------------*/ -#endif /* PROJECT_CONF_H_ */ -/*---------------------------------------------------------------------------*/ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-ble-advd.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-ble-advd.c deleted file mode 100644 index 8c79067d3..000000000 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-ble-advd.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/*---------------------------------------------------------------------------*/ -/** - * \addtogroup cc13xx-cc26xx-web-demo - * @{ - * - * \file - * CoAP resource to start/stop/configure BLE advertisements - */ -/*---------------------------------------------------------------------------*/ -#include "contiki.h" -#include "net/app-layer/coap/coap.h" -#include "net/app-layer/coap/coap-engine.h" -/*---------------------------------------------------------------------------*/ -#include "rf/ble-beacond.h" -/*---------------------------------------------------------------------------*/ -#include -#include -/*---------------------------------------------------------------------------*/ -#define BLE_NAME_BUF_LEN 32 -/*---------------------------------------------------------------------------*/ -const char *forbidden_payload = "Name to advertise unspecified.\n" - "Use name= in the request"; -/*---------------------------------------------------------------------------*/ -static void -res_ble_post_put_handler(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - size_t len = 0; - const char *text = NULL; - char name[BLE_NAME_BUF_LEN]; - int success = 0; - int rv; - - memset(name, 0, BLE_NAME_BUF_LEN); - - len = coap_get_post_variable(request, "name", &text); - - if(len > 0 && len < BLE_NAME_BUF_LEN) { - memcpy(name, text, len); - rf_ble_beacond_config(0, name); - success = 1; - } - - len = coap_get_post_variable(request, "interval", &text); - - rv = atoi(text); - - if(rv > 0) { - rf_ble_beacond_config((clock_time_t)(rv * CLOCK_SECOND), NULL); - success = 1; - } - - len = coap_get_post_variable(request, "mode", &text); - - if(len) { - if(strncmp(text, "on", len) == 0) { - if(rf_ble_beacond_start()) { - success = 1; - } else { - coap_set_status_code(response, FORBIDDEN_4_03); - coap_set_payload(response, forbidden_payload, - strlen(forbidden_payload)); - return; - } - } else if(strncmp(text, "off", len) == 0) { - rf_ble_beacond_stop(); - success = 1; - } else { - success = 0; - } - } - - if(!success) { - coap_set_status_code(response, BAD_REQUEST_4_00); - } -} -/*---------------------------------------------------------------------------*/ -RESOURCE(res_ble_advd, - "title=\"BLE advd config: POST/PUT name=&mode=on|off" - "&interval=\";rt=\"Control\"", - NULL, - res_ble_post_put_handler, - res_ble_post_put_handler, - NULL); -/*---------------------------------------------------------------------------*/ -/** @} */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-device.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-device.c deleted file mode 100644 index a0485867b..000000000 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-device.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/*---------------------------------------------------------------------------*/ -/** - * \addtogroup cc13xx-cc26xx-web-demo - * @{ - * - * \file - * CoAP resource handler for CC13xx/CC26xx software and hardware version - */ -/*---------------------------------------------------------------------------*/ -#include "contiki.h" -#include "sys/clock.h" -#include "net/app-layer/coap/coap.h" -#include "net/app-layer/coap/coap-engine.h" -/*---------------------------------------------------------------------------*/ -#include -#include DeviceFamily_constructPath(driverlib/chipinfo.h) -/*---------------------------------------------------------------------------*/ -#include "web-demo.h" -#include "coap-server.h" -/*---------------------------------------------------------------------------*/ -#include -#include -/*---------------------------------------------------------------------------*/ -static const char * -detect_chip(void) -{ - switch(ChipInfo_GetChipType()) { - case CHIP_TYPE_CC1310: return "CC1310"; - case CHIP_TYPE_CC1350: return "CC1350"; - case CHIP_TYPE_CC2620: return "CC2620"; - case CHIP_TYPE_CC2630: return "CC2630"; - case CHIP_TYPE_CC2640: return "CC2640"; - case CHIP_TYPE_CC2650: return "CC2650"; - case CHIP_TYPE_CC2642: return "CC2642"; - case CHIP_TYPE_CC2652: return "CC2652"; - case CHIP_TYPE_CC1312: return "CC1312"; - case CHIP_TYPE_CC1352: return "CC1352"; - case CHIP_TYPE_CC1352P: return "CC1352P"; - default: return "Unknown"; - } -} -/*---------------------------------------------------------------------------*/ -static void -res_get_handler_hw(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - unsigned int accept = -1; - const char *chip = detect_chip(); - - coap_get_header_accept(request, &accept); - - if(accept == -1 || accept == TEXT_PLAIN) { - coap_set_header_content_format(response, TEXT_PLAIN); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%s on %s", BOARD_STRING, - chip); - - coap_set_payload(response, (uint8_t *)buffer, strlen((char *)buffer)); - } else if(accept == APPLICATION_JSON) { - coap_set_header_content_format(response, APPLICATION_JSON); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{\"HW Ver\":\"%s on %s\"}", - BOARD_STRING, chip); - - coap_set_payload(response, buffer, strlen((char *)buffer)); - } else if(accept == APPLICATION_XML) { - coap_set_header_content_format(response, APPLICATION_XML); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, - "", BOARD_STRING, - chip); - - coap_set_payload(response, buffer, strlen((char *)buffer)); - } else { - coap_set_status_code(response, NOT_ACCEPTABLE_4_06); - coap_set_payload(response, coap_server_supported_msg, - strlen(coap_server_supported_msg)); - } -} -/*---------------------------------------------------------------------------*/ -static void -res_get_handler_sw(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - unsigned int accept = -1; - - coap_get_header_accept(request, &accept); - - if(accept == -1 || accept == TEXT_PLAIN) { - coap_set_header_content_format(response, TEXT_PLAIN); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%s", CONTIKI_VERSION_STRING); - - coap_set_payload(response, (uint8_t *)buffer, strlen((char *)buffer)); - } else if(accept == APPLICATION_JSON) { - coap_set_header_content_format(response, APPLICATION_JSON); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{\"SW Ver\":\"%s\"}", - CONTIKI_VERSION_STRING); - - coap_set_payload(response, buffer, strlen((char *)buffer)); - } else if(accept == APPLICATION_XML) { - coap_set_header_content_format(response, APPLICATION_XML); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, - "", CONTIKI_VERSION_STRING); - - coap_set_payload(response, buffer, strlen((char *)buffer)); - } else { - coap_set_status_code(response, NOT_ACCEPTABLE_4_06); - coap_set_payload(response, coap_server_supported_msg, - strlen(coap_server_supported_msg)); - } -} -/*---------------------------------------------------------------------------*/ -static void -res_get_handler_uptime(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - unsigned int accept = -1; - - coap_get_header_accept(request, &accept); - - if(accept == -1 || accept == TEXT_PLAIN) { - coap_set_header_content_format(response, TEXT_PLAIN); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%lu", clock_seconds()); - - coap_set_payload(response, (uint8_t *)buffer, strlen((char *)buffer)); - } else if(accept == APPLICATION_JSON) { - coap_set_header_content_format(response, APPLICATION_JSON); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{\"uptime\":%lu}", - clock_seconds()); - - coap_set_payload(response, buffer, strlen((char *)buffer)); - } else if(accept == APPLICATION_XML) { - coap_set_header_content_format(response, APPLICATION_XML); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, - "", clock_seconds()); - - coap_set_payload(response, buffer, strlen((char *)buffer)); - } else { - coap_set_status_code(response, NOT_ACCEPTABLE_4_06); - coap_set_payload(response, coap_server_supported_msg, - strlen(coap_server_supported_msg)); - } -} -/*---------------------------------------------------------------------------*/ -static void -res_post_handler_cfg_reset(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - web_demo_restore_defaults(); -} -/*---------------------------------------------------------------------------*/ -RESOURCE(res_device_sw, - "title=\"Software version\";rt=\"text\"", - res_get_handler_sw, - NULL, - NULL, - NULL); -/*---------------------------------------------------------------------------*/ -RESOURCE(res_device_uptime, - "title=\"Uptime\";rt=\"seconds\"", - res_get_handler_uptime, - NULL, - NULL, - NULL); -/*---------------------------------------------------------------------------*/ -RESOURCE(res_device_hw, - "title=\"Hardware version\";rt=\"text\"", - res_get_handler_hw, - NULL, - NULL, - NULL); -/*---------------------------------------------------------------------------*/ -RESOURCE(res_device_cfg_reset, - "title=\"Reset Device Config: POST\";rt=\"Control\"", - NULL, res_post_handler_cfg_reset, NULL, NULL); -/*---------------------------------------------------------------------------*/ -/** @} */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-leds.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-leds.c deleted file mode 100644 index 5e4da11da..000000000 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-leds.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/*---------------------------------------------------------------------------*/ -/** - * \addtogroup cc13xx-cc26xx-web-demo - * @{ - * - * \file - * CoAP resource handler for the CC13xx/CC26xx LEDs. Slightly modified copy of - * the one found in Contiki's original CoAP example. - * \author - * Matthias Kovatsch (original) - */ -/*---------------------------------------------------------------------------*/ -#include "contiki.h" -#include "dev/leds.h" -#include "net/app-layer/coap/coap-engine.h" -/*---------------------------------------------------------------------------*/ -#include -/*---------------------------------------------------------------------------*/ -static void -res_post_put_handler(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - size_t len = 0; - const char *color = NULL; - const char *mode = NULL; - uint8_t led = 0; - int success = 1; - - if((len = coap_get_query_variable(request, "color", &color))) { - if(strncmp(color, "r", len) == 0) { - led = LEDS_RED; - } else if(strncmp(color, "g", len) == 0) { - led = LEDS_GREEN; -#if BOARD_SMARTRF06EB - } else if(strncmp(color, "y", len) == 0) { - led = LEDS_YELLOW; - } else if(strncmp(color, "o", len) == 0) { - led = LEDS_ORANGE; -#endif - } else { - success = 0; - } - } else { - success = 0; - } - - if(success && (len = coap_get_post_variable(request, "mode", &mode))) { - if(strncmp(mode, "on", len) == 0) { - leds_on(led); - } else if(strncmp(mode, "off", len) == 0) { - leds_off(led); - } else { - success = 0; - } - } else { - success = 0; - } - - if(!success) { - coap_set_status_code(response, BAD_REQUEST_4_00); - } -} -/*---------------------------------------------------------------------------*/ -/* - * A simple actuator example, depending on the color query parameter and post - * variable mode, corresponding led is activated or deactivated - */ -#if BOARD_SENSORTAG || BOARD_LAUNCHPAD -#define RESOURCE_PARAMS "r|g" -#elif BOARD_SMARTRF06EB -#define RESOURCE_PARAMS "r|g|y|o" -#endif - -RESOURCE(res_leds, - "title=\"LEDs: ?color=" RESOURCE_PARAMS ", POST/PUT mode=on|off\";rt=\"Control\"", - NULL, - res_post_put_handler, - res_post_put_handler, - NULL); -/*---------------------------------------------------------------------------*/ -/** @} */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-net.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-net.c deleted file mode 100644 index b1f6b8725..000000000 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-net.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/*---------------------------------------------------------------------------*/ -/** - * \addtogroup cc13xx-cc26xx-web-demo - * @{ - * - * \file - * CoAP resource handler for network-related resources - */ -/*---------------------------------------------------------------------------*/ -#include "contiki.h" -#include "net/ipv6/uip-ds6.h" -#include "net/app-layer/coap/coap.h" -#include "net/app-layer/coap/coap-engine.h" -/*---------------------------------------------------------------------------*/ -#include "coap-server.h" -#include "web-demo.h" -/*---------------------------------------------------------------------------*/ -#include -#include -/*---------------------------------------------------------------------------*/ -extern int def_rt_rssi; -/*---------------------------------------------------------------------------*/ -static void -res_get_handler_parent_rssi(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - unsigned int accept = -1; - - coap_get_header_accept(request, &accept); - - if(accept == -1 || accept == TEXT_PLAIN) { - coap_set_header_content_format(response, TEXT_PLAIN); - snprintf((char *)buffer, COAP_MAX_CHUNK_SIZE, "%d", def_rt_rssi); - - coap_set_payload(response, (uint8_t *)buffer, strlen((char *)buffer)); - } else if(accept == APPLICATION_JSON) { - coap_set_header_content_format(response, APPLICATION_JSON); - snprintf((char *)buffer, COAP_MAX_CHUNK_SIZE, "{\"Parent RSSI\":\"%d\"}", - def_rt_rssi); - - coap_set_payload(response, buffer, strlen((char *)buffer)); - } else if(accept == APPLICATION_XML) { - coap_set_header_content_format(response, APPLICATION_XML); - snprintf((char *)buffer, COAP_MAX_CHUNK_SIZE, - "", def_rt_rssi); - - coap_set_payload(response, buffer, strlen((char *)buffer)); - } else { - coap_set_status_code(response, NOT_ACCEPTABLE_4_06); - coap_set_payload(response, coap_server_supported_msg, - strlen(coap_server_supported_msg)); - } -} -/*---------------------------------------------------------------------------*/ -static void -res_get_handler_pref_parent(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - unsigned int accept = -1; - char def_rt_str[64]; - - coap_get_header_accept(request, &accept); - - memset(def_rt_str, 0, sizeof(def_rt_str)); - web_demo_ipaddr_sprintf(def_rt_str, sizeof(def_rt_str), - uip_ds6_defrt_choose()); - - if(accept == -1 || accept == TEXT_PLAIN) { - coap_set_header_content_format(response, TEXT_PLAIN); - snprintf((char *)buffer, COAP_MAX_CHUNK_SIZE, "%s", def_rt_str); - - coap_set_payload(response, (uint8_t *)buffer, strlen((char *)buffer)); - } else if(accept == APPLICATION_JSON) { - coap_set_header_content_format(response, APPLICATION_JSON); - snprintf((char *)buffer, COAP_MAX_CHUNK_SIZE, "{\"Parent\":\"%s\"}", - def_rt_str); - - coap_set_payload(response, buffer, strlen((char *)buffer)); - } else if(accept == APPLICATION_XML) { - coap_set_header_content_format(response, APPLICATION_XML); - snprintf((char *)buffer, COAP_MAX_CHUNK_SIZE, - "", def_rt_str); - - coap_set_payload(response, buffer, strlen((char *)buffer)); - } else { - coap_set_status_code(response, NOT_ACCEPTABLE_4_06); - coap_set_payload(response, coap_server_supported_msg, - strlen(coap_server_supported_msg)); - } -} -/*---------------------------------------------------------------------------*/ -RESOURCE(res_parent_rssi, "title=\"Parent RSSI\";rt=\"dBm\"", - res_get_handler_parent_rssi, NULL, NULL, NULL); -/*---------------------------------------------------------------------------*/ -RESOURCE(res_parent_ip, "title=\"Preferred Parent\";rt=\"IPv6 address\"", - res_get_handler_pref_parent, NULL, NULL, NULL); -/*---------------------------------------------------------------------------*/ -/** @} */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-sensors.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-sensors.c deleted file mode 100644 index 27f93f8f2..000000000 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-sensors.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/*---------------------------------------------------------------------------*/ -/** - * \addtogroup cc13xx-cc26xx-web-demo - * @{ - * - * \file - * CoAP resource handler for the Sensortag sensors - */ -/*---------------------------------------------------------------------------*/ -#include "contiki.h" -#include "net/app-layer/coap/coap.h" -#include "net/app-layer/coap/coap-engine.h" -/*---------------------------------------------------------------------------*/ -#include "web-demo.h" -#include "coap-server.h" -/*---------------------------------------------------------------------------*/ -#include -#include -#include -/*---------------------------------------------------------------------------*/ -/* - * Generic resource handler for any sensor in this example. Ultimately gets - * called by all handlers and populates the CoAP response - */ -static void -res_get_handler_all(int sens_type, coap_message_t *request, - coap_message_t *response, - uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - unsigned int accept = -1; - const web_demo_sensor_reading_t *reading; - - reading = web_demo_sensor_lookup(sens_type); - - if(reading == NULL) { - coap_set_status_code(response, NOT_FOUND_4_04); - coap_set_payload(response, coap_server_not_found_msg, - strlen(coap_server_not_found_msg)); - return; - } - - coap_get_header_accept(request, &accept); - - if(accept == -1 || accept == TEXT_PLAIN) { - coap_set_header_content_format(response, TEXT_PLAIN); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%s", reading->converted); - - coap_set_payload(response, (uint8_t *)buffer, - strlen((char *)buffer)); - } else if(accept == APPLICATION_JSON) { - coap_set_header_content_format(response, APPLICATION_JSON); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{\"%s\":%s}", - reading->descr, reading->converted); - - coap_set_payload(response, buffer, strlen((char *)buffer)); - } else if(accept == APPLICATION_XML) { - coap_set_header_content_format(response, APPLICATION_XML); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, - "<%s val=\"%s\" unit=\"%s\"/>", reading->xml_element, - reading->converted, reading->units); - - coap_set_payload(response, buffer, strlen((char *)buffer)); - } else { - coap_set_status_code(response, NOT_ACCEPTABLE_4_06); - coap_set_payload(response, coap_server_supported_msg, - strlen(coap_server_supported_msg)); - } -} -/*---------------------------------------------------------------------------*/ -/* BatMon resources and handler: Temperature, Voltage */ -static void -res_get_handler_batmon_temp(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - res_get_handler_all(WEB_DEMO_SENSOR_BATMON_TEMP, request, response, - buffer, preferred_size, offset); -} -/*---------------------------------------------------------------------------*/ -static void -res_get_handler_batmon_volt(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - res_get_handler_all(WEB_DEMO_SENSOR_BATMON_VOLT, request, response, - buffer, preferred_size, offset); -} -/*---------------------------------------------------------------------------*/ -RESOURCE(res_batmon_temp, "title=\"Battery Temp\";rt=\"C\"", - res_get_handler_batmon_temp, NULL, NULL, NULL); -/*---------------------------------------------------------------------------*/ -RESOURCE(res_batmon_volt, "title=\"Battery Voltage\";rt=\"mV\"", - res_get_handler_batmon_volt, NULL, NULL, NULL); -/*---------------------------------------------------------------------------*/ -#if WEB_DEMO_ADC_DEMO -/*---------------------------------------------------------------------------*/ -static void -res_get_handler_adc_dio23(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - res_get_handler_all(WEB_DEMO_SENSOR_ADC_DIO23, request, response, - buffer, preferred_size, offset); -} -/*---------------------------------------------------------------------------*/ -RESOURCE(res_adc_dio23, "title=\"ADC DIO23\";rt=\"mV\"", - res_get_handler_adc_dio23, NULL, NULL, NULL); -/*---------------------------------------------------------------------------*/ -#endif -/*---------------------------------------------------------------------------*/ -#if BOARD_SENSORTAG -/*---------------------------------------------------------------------------*/ -/* MPU resources and handler: Accelerometer and Gyro */ -static void -res_get_handler_mpu_acc_x(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - res_get_handler_all(WEB_DEMO_SENSOR_MPU_ACC_X, request, response, - buffer, preferred_size, offset); -} -/*---------------------------------------------------------------------------*/ -static void -res_get_handler_mpu_acc_y(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - res_get_handler_all(WEB_DEMO_SENSOR_MPU_ACC_Y, request, response, - buffer, preferred_size, offset); -} -/*---------------------------------------------------------------------------*/ -static void -res_get_handler_mpu_acc_z(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - res_get_handler_all(WEB_DEMO_SENSOR_MPU_ACC_Z, request, response, - buffer, preferred_size, offset); -} -/*---------------------------------------------------------------------------*/ -static void -res_get_handler_mpu_gyro_x(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - res_get_handler_all(WEB_DEMO_SENSOR_MPU_GYRO_X, request, response, - buffer, preferred_size, offset); -} -/*---------------------------------------------------------------------------*/ -static void -res_get_handler_mpu_gyro_y(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - res_get_handler_all(WEB_DEMO_SENSOR_MPU_GYRO_Y, request, response, - buffer, preferred_size, offset); -} -/*---------------------------------------------------------------------------*/ -static void -res_get_handler_mpu_gyro_z(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - res_get_handler_all(WEB_DEMO_SENSOR_MPU_GYRO_Z, request, response, - buffer, preferred_size, offset); -} -/*---------------------------------------------------------------------------*/ -RESOURCE(res_mpu_acc_x, "title=\"Acc X\";rt=\"G\"", res_get_handler_mpu_acc_x, - NULL, NULL, NULL); -RESOURCE(res_mpu_acc_y, "title=\"Acc Y\";rt=\"G\"", res_get_handler_mpu_acc_y, - NULL, NULL, NULL); -RESOURCE(res_mpu_acc_z, "title=\"Acc Z\";rt=\"G\"", res_get_handler_mpu_acc_z, - NULL, NULL, NULL); - -RESOURCE(res_mpu_gyro_x, "title=\"Gyro X\";rt=\"deg/sec\"", - res_get_handler_mpu_gyro_x, NULL, NULL, NULL); -RESOURCE(res_mpu_gyro_y, "title=\"Gyro Y\";rt=\"deg/sec\"", - res_get_handler_mpu_gyro_y, NULL, NULL, NULL); -RESOURCE(res_mpu_gyro_z, "title=\"Gyro Z\";rt=\"deg/sec\"", - res_get_handler_mpu_gyro_z, NULL, NULL, NULL); -/*---------------------------------------------------------------------------*/ -/* TMP sensor resources and handlers: Object, Ambient */ -static void -res_get_handler_obj_temp(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - res_get_handler_all(WEB_DEMO_SENSOR_TMP_OBJECT, request, response, - buffer, preferred_size, offset); -} -/*---------------------------------------------------------------------------*/ -static void -res_get_handler_amb_temp(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - res_get_handler_all(WEB_DEMO_SENSOR_TMP_AMBIENT, request, response, - buffer, preferred_size, offset); -} -/*---------------------------------------------------------------------------*/ -RESOURCE(res_tmp007_obj, "title=\"Temperature (Object)\";rt=\"C\"", - res_get_handler_obj_temp, NULL, NULL, NULL); - -RESOURCE(res_tmp007_amb, "title=\"Temperature (Ambient)\";rt=\"C\"", - res_get_handler_amb_temp, NULL, NULL, NULL); -/*---------------------------------------------------------------------------*/ -/* BMP sensor resources: Temperature, Pressure */ -static void -res_get_handler_bmp_temp(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - res_get_handler_all(WEB_DEMO_SENSOR_BMP_TEMP, request, response, - buffer, preferred_size, offset); -} -/*---------------------------------------------------------------------------*/ -static void -res_get_handler_bmp_press(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - res_get_handler_all(WEB_DEMO_SENSOR_BMP_PRES, request, response, - buffer, preferred_size, offset); -} -/*---------------------------------------------------------------------------*/ -RESOURCE(res_bmp280_temp, "title=\"Barometer (Temperature)\";rt=\"C\"", - res_get_handler_bmp_temp, NULL, NULL, NULL); - -RESOURCE(res_bmp280_press, - "title=\"Barometer (Pressure)\";rt=\"hPa (hectopascal / millibar)\"", - res_get_handler_bmp_press, NULL, NULL, NULL); -/*---------------------------------------------------------------------------*/ -/* HDC1000 sensor resources and handler: Temperature, Pressure */ -static void -res_get_handler_hdc_temp(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - res_get_handler_all(WEB_DEMO_SENSOR_HDC_TEMP, request, response, - buffer, preferred_size, offset); -} -/*---------------------------------------------------------------------------*/ -static void -res_get_handler_hdc_humidity(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - res_get_handler_all(WEB_DEMO_SENSOR_HDC_HUMIDITY, request, response, - buffer, preferred_size, offset); -} -/*---------------------------------------------------------------------------*/ -RESOURCE(res_hdc1000_temp, "title=\"Temperature\";rt=\"C\"", - res_get_handler_hdc_temp, NULL, NULL, NULL); - -RESOURCE(res_hdc1000_hum, "title=\"Humidity\";rt=\"%RH\"", - res_get_handler_hdc_humidity, NULL, NULL, NULL); -/*---------------------------------------------------------------------------*/ -/* Illuminance resources and handler */ -static void -res_get_handler_opt(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - res_get_handler_all(WEB_DEMO_SENSOR_OPT_LIGHT, request, response, - buffer, preferred_size, offset); -} -/*---------------------------------------------------------------------------*/ -RESOURCE(res_opt3001_light, "title=\"Illuminance\";rt=\"Lux\"", - res_get_handler_opt, NULL, NULL, NULL); -/*---------------------------------------------------------------------------*/ -#endif /* BOARD_SENSORTAG */ -/*---------------------------------------------------------------------------*/ -/** @} */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-toggle-leds.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-toggle-leds.c deleted file mode 100644 index 0ba4c2881..000000000 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/resources/res-toggle-leds.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/*---------------------------------------------------------------------------*/ -/** - * \addtogroup cc13xx-cc26xx-web-demo - * @{ - * - * \file - * CoAP resource to toggle LEDs. Slightly modified copy of the one found - * in Contiki's original CoAP example. - * \author - * Matthias Kovatsch (original) - */ -/*---------------------------------------------------------------------------*/ -#include "contiki.h" -#include "dev/leds.h" -#include "net/app-layer/coap/coap-engine.h" -/*---------------------------------------------------------------------------*/ -#include -/*---------------------------------------------------------------------------*/ -static void -res_post_handler_red(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - leds_toggle(LEDS_RED); -} -/*---------------------------------------------------------------------------*/ -static void -res_post_handler_green(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - leds_toggle(LEDS_GREEN); -} -/*---------------------------------------------------------------------------*/ -/* Toggles the red led */ -RESOURCE(res_toggle_red, - "title=\"Red LED\";rt=\"Control\"", - NULL, - res_post_handler_red, - NULL, - NULL); - -/* Toggles the green led */ -RESOURCE(res_toggle_green, - "title=\"Green LED\";rt=\"Control\"", - NULL, - res_post_handler_green, - NULL, - NULL); -/*---------------------------------------------------------------------------*/ -/* An additional 2 LEDs on the Srf */ -#if BOARD_SMARTRF06EB -/*---------------------------------------------------------------------------*/ -static void -res_post_handler_yellow(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - leds_toggle(LEDS_YELLOW); -} -/*---------------------------------------------------------------------------*/ -static void -res_post_handler_orange(coap_message_t *request, coap_message_t *response, - uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - leds_toggle(LEDS_ORANGE); -} -/*---------------------------------------------------------------------------*/ -/* Toggles the yellow led */ -RESOURCE(res_toggle_yellow, - "title=\"Yellow LED\";rt=\"Control\"", - NULL, - res_post_handler_yellow, - NULL, - NULL); - -/* Toggles the orange led */ -RESOURCE(res_toggle_orange, - "title=\"Orange LED\";rt=\"Control\"", - NULL, - res_post_handler_orange, - NULL, - NULL); -#endif -/*---------------------------------------------------------------------------*/ -/** @} */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.c b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.c deleted file mode 100644 index 8e729576d..000000000 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.c +++ /dev/null @@ -1,1054 +0,0 @@ -/* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/** - * \addtogroup cc13xx-cc26xx-web-demo - * @{ - * - * \file - * Main module for the CC13xx/CC26xx web demo. Activates on-device resources, - * takes sensor readings periodically and caches them for all other modules - * to use. - */ -/*---------------------------------------------------------------------------*/ -#include "contiki.h" -#include "contiki-net.h" -#include "dev/button-hal.h" -#include "dev/ext-flash/ext-flash.h" -#include "sys/process.h" -#include "net/ipv6/sicslowpan.h" -#include "net/app-layer/coap/coap-engine.h" -#include "lib/sensors.h" -#include "lib/list.h" -/*---------------------------------------------------------------------------*/ -#include -#include -/*---------------------------------------------------------------------------*/ -#include "board-peripherals.h" -#include "batmon-sensor.h" -/*---------------------------------------------------------------------------*/ -#include "web-demo.h" -#include "httpd-simple.h" -#include "mqtt-client.h" -#include "coap-server.h" -/*---------------------------------------------------------------------------*/ -#include -#include -#include -#include -/*---------------------------------------------------------------------------*/ -PROCESS_NAME(cetic_6lbr_client_process); -PROCESS(web_demo_process, "CC13xx/CC26xx Web Demo"); -/*---------------------------------------------------------------------------*/ -/* - * Update sensor readings in a staggered fashion every SENSOR_READING_PERIOD - * ticks + a random interval between 0 and SENSOR_READING_RANDOM ticks - */ -#define SENSOR_READING_PERIOD (CLOCK_SECOND * 20) -#define SENSOR_READING_RANDOM (CLOCK_SECOND << 4) - -struct ctimer batmon_timer; - -#if BOARD_SENSORTAG -struct ctimer bmp_timer, hdc_timer, tmp_timer, opt_timer, mpu_timer; -#endif -/*---------------------------------------------------------------------------*/ -/* Provide visible feedback via LEDS while searching for a network */ -#define NO_NET_LED_DURATION (WEB_DEMO_NET_CONNECT_PERIODIC >> 1) - -static struct etimer et; -static struct ctimer ct; -/*---------------------------------------------------------------------------*/ -/* Parent RSSI functionality */ -#if WEB_DEMO_READ_PARENT_RSSI -static struct uip_icmp6_echo_reply_notification echo_reply_notification; -static struct etimer echo_request_timer; -int def_rt_rssi = 0; -#endif -/*---------------------------------------------------------------------------*/ -#if WEB_DEMO_ADC_DEMO -PROCESS(adc_process, "ADC process"); - -static uint_fast16_t single_adc_sample; -static struct etimer et_adc; -#endif -/*---------------------------------------------------------------------------*/ -process_event_t web_demo_publish_event; -process_event_t web_demo_config_loaded_event; -process_event_t web_demo_load_config_defaults; -/*---------------------------------------------------------------------------*/ -/* Saved settings on flash: store, offset, magic */ -#define CONFIG_FLASH_OFFSET 0 -#define CONFIG_MAGIC 0xCC265002 - -web_demo_config_t web_demo_config; -/*---------------------------------------------------------------------------*/ -/* A cache of sensor values. Updated periodically or upon key press */ -LIST(sensor_list); -/*---------------------------------------------------------------------------*/ -/* The objects representing sensors used in this demo */ -#define DEMO_SENSOR(name, type, descr, xml_element, form_field, units) \ - web_demo_sensor_reading_t name##_reading = \ - { NULL, 0, 0, descr, xml_element, form_field, units, type, 1, 1 } - -/* CC13xx/CC26xx sensors */ -DEMO_SENSOR(batmon_temp, WEB_DEMO_SENSOR_BATMON_TEMP, - "Battery Temp", "battery-temp", "batmon_temp", - WEB_DEMO_UNIT_TEMP); -DEMO_SENSOR(batmon_volt, WEB_DEMO_SENSOR_BATMON_VOLT, - "Battery Volt", "battery-volt", "batmon_volt", - WEB_DEMO_UNIT_VOLT); - -#if WEB_DEMO_ADC_DEMO -DEMO_SENSOR(adc_dio23, WEB_DEMO_SENSOR_ADC_DIO23, - "ADC DIO23", "adc-dio23", "adc_dio23", - WEB_DEMO_UNIT_VOLT); -#endif - -/* Sensortag sensors */ -#if BOARD_SENSORTAG -DEMO_SENSOR(bmp_pres, WEB_DEMO_SENSOR_BMP_PRES, - "Air Pressure", "air-pressure", "bmp_pres", - WEB_DEMO_UNIT_PRES); -DEMO_SENSOR(bmp_temp, WEB_DEMO_SENSOR_BMP_TEMP, - "Air Temp", "air-temp", "bmp_temp", - WEB_DEMO_UNIT_TEMP); -DEMO_SENSOR(hdc_temp, WEB_DEMO_SENSOR_HDC_TEMP, - "HDC Temp", "hdc-temp", "hdc_temp", - WEB_DEMO_UNIT_TEMP); -DEMO_SENSOR(hdc_hum, WEB_DEMO_SENSOR_HDC_HUMIDITY, - "HDC Humidity", "hdc-humidity", "hdc_hum", - WEB_DEMO_UNIT_HUMIDITY); -DEMO_SENSOR(tmp_amb, WEB_DEMO_SENSOR_TMP_AMBIENT, - "Ambient Temp", "ambient-temp", "tmp_amb", - WEB_DEMO_UNIT_TEMP); -DEMO_SENSOR(tmp_obj, WEB_DEMO_SENSOR_TMP_OBJECT, - "Object Temp", "object-temp", "tmp_obj", - WEB_DEMO_UNIT_TEMP); -DEMO_SENSOR(opt, WEB_DEMO_SENSOR_OPT_LIGHT, - "Light", "light", "light", - WEB_DEMO_UNIT_LIGHT); - -/* MPU Readings */ -DEMO_SENSOR(mpu_acc_x, WEB_DEMO_SENSOR_MPU_ACC_X, - "Acc X", "acc-x", "acc_x", - WEB_DEMO_UNIT_ACC); -DEMO_SENSOR(mpu_acc_y, WEB_DEMO_SENSOR_MPU_ACC_Y, - "Acc Y", "acc-y", "acc_y", - WEB_DEMO_UNIT_ACC); -DEMO_SENSOR(mpu_acc_z, WEB_DEMO_SENSOR_MPU_ACC_Z, - "Acc Z", "acc-z", "acc_z", - WEB_DEMO_UNIT_ACC); - -DEMO_SENSOR(mpu_gyro_x, WEB_DEMO_SENSOR_MPU_GYRO_X, - "Gyro X", "gyro-x", "gyro_x", - WEB_DEMO_UNIT_GYRO); -DEMO_SENSOR(mpu_gyro_y, WEB_DEMO_SENSOR_MPU_GYRO_Y, - "Gyro Y", "gyro-y", "gyro_y", - WEB_DEMO_UNIT_GYRO); -DEMO_SENSOR(mpu_gyro_z, WEB_DEMO_SENSOR_MPU_GYRO_Z, - "Gyro Z", "gyro-z", "gyro_Z", - WEB_DEMO_UNIT_GYRO); -#endif -/*---------------------------------------------------------------------------*/ -#if BOARD_SENSORTAG -static void init_bmp_reading(void *data); -static void init_light_reading(void *data); -static void init_hdc_reading(void *data); -static void init_tmp_reading(void *data); -static void init_mpu_reading(void *data); -#endif -/*---------------------------------------------------------------------------*/ -static void -publish_led_off(void *d) -{ - leds_off(WEB_DEMO_STATUS_LED); -} -/*---------------------------------------------------------------------------*/ -static void -save_config() -{ - /* Dump current running config to flash */ -#if BOARD_SENSORTAG || BOARD_LAUNCHPAD - int rv; - web_demo_sensor_reading_t *reading = NULL; - - rv = ext_flash_open(NULL); - - if(!rv) { - printf("Could not open flash to save config\n"); - ext_flash_close(NULL); - return; - } - - rv = ext_flash_erase(NULL, CONFIG_FLASH_OFFSET, sizeof(web_demo_config_t)); - - if(!rv) { - printf("Error erasing flash\n"); - } else { - web_demo_config.magic = CONFIG_MAGIC; - web_demo_config.len = sizeof(web_demo_config_t); - web_demo_config.sensors_bitmap = 0; - - for(reading = list_head(sensor_list); - reading != NULL; - reading = list_item_next(reading)) { - if(reading->publish) { - web_demo_config.sensors_bitmap |= (1 << reading->type); - } - } - - rv = ext_flash_write(NULL, CONFIG_FLASH_OFFSET, sizeof(web_demo_config_t), - (uint8_t *)&web_demo_config); - if(!rv) { - printf("Error saving config\n"); - } - } - - ext_flash_close(NULL); -#endif -} -/*---------------------------------------------------------------------------*/ -static void -load_config() -{ -#if BOARD_SENSORTAG || BOARD_LAUNCHPAD - /* Read from flash into a temp buffer */ - web_demo_config_t tmp_cfg; - web_demo_sensor_reading_t *reading = NULL; - - int rv = ext_flash_open(NULL); - - if(!rv) { - printf("Could not open flash to load config\n"); - ext_flash_close(NULL); - return; - } - - rv = ext_flash_read(NULL, CONFIG_FLASH_OFFSET, sizeof(tmp_cfg), - (uint8_t *)&tmp_cfg); - - ext_flash_close(NULL); - - if(!rv) { - printf("Error loading config\n"); - return; - } - - if(tmp_cfg.magic == CONFIG_MAGIC && tmp_cfg.len == sizeof(tmp_cfg)) { - memcpy(&web_demo_config, &tmp_cfg, sizeof(web_demo_config)); - } - - for(reading = list_head(sensor_list); - reading != NULL; - reading = list_item_next(reading)) { - if(web_demo_config.sensors_bitmap & (1 << reading->type)) { - reading->publish = 1; - } else { - reading->publish = 0; - snprintf(reading->converted, WEB_DEMO_CONVERTED_LEN, "\"N/A\""); - } - } -#endif -} -/*---------------------------------------------------------------------------*/ -/* Don't start everything here, we need to dictate order of initialisation */ -AUTOSTART_PROCESSES(&web_demo_process); -/*---------------------------------------------------------------------------*/ -int -web_demo_ipaddr_sprintf(char *buf, uint8_t buf_len, - const uip_ipaddr_t *addr) -{ - uint16_t a; - uint8_t len = 0; - int i, f; - for(i = 0, f = 0; i < sizeof(uip_ipaddr_t); i += 2) { - a = (addr->u8[i] << 8) + addr->u8[i + 1]; - if(a == 0 && f >= 0) { - if(f++ == 0) { - len += snprintf(&buf[len], buf_len - len, "::"); - } - } else { - if(f > 0) { - f = -1; - } else if(i > 0) { - len += snprintf(&buf[len], buf_len - len, ":"); - } - len += snprintf(&buf[len], buf_len - len, "%x", a); - } - } - - return len; -} -/*---------------------------------------------------------------------------*/ -const web_demo_sensor_reading_t * -web_demo_sensor_lookup(int sens_type) -{ - web_demo_sensor_reading_t *reading = NULL; - - for(reading = list_head(sensor_list); - reading != NULL; - reading = list_item_next(reading)) { - if(reading->type == sens_type) { - return reading; - } - } - - return NULL; -} -/*---------------------------------------------------------------------------*/ -const web_demo_sensor_reading_t * -web_demo_sensor_first() -{ - return list_head(sensor_list); -} -/*---------------------------------------------------------------------------*/ -void -web_demo_restore_defaults(void) -{ - web_demo_sensor_reading_t *reading = NULL; - - leds_on(LEDS_ALL); - - for(reading = list_head(sensor_list); - reading != NULL; - reading = list_item_next(reading)) { - reading->publish = 1; - } - -#if WEB_DEMO_MQTT_CLIENT - process_post_synch(&mqtt_client_process, - web_demo_load_config_defaults, NULL); -#endif - -#if WEB_DEMO_NET_UART - process_post_synch(&net_uart_process, web_demo_load_config_defaults, - NULL); -#endif - - save_config(); - - leds_off(LEDS_ALL); -} -/*---------------------------------------------------------------------------*/ -static int -defaults_post_handler(char *key, int key_len, char *val, int val_len) -{ - if(key_len != strlen("defaults") || - strncasecmp(key, "defaults", strlen("defaults")) != 0) { - /* Not ours */ - return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; - } - - web_demo_restore_defaults(); - - return HTTPD_SIMPLE_POST_HANDLER_OK; -} -/*---------------------------------------------------------------------------*/ -static int -sensor_readings_handler(char *key, int key_len, char *val, int val_len) -{ - web_demo_sensor_reading_t *reading = NULL; - int rv; - - for(reading = list_head(sensor_list); - reading != NULL; - reading = list_item_next(reading)) { - if(key_len == strlen(reading->form_field) && - strncmp(reading->form_field, key, strlen(key)) == 0) { - - rv = atoi(val); - - /* Be pedantic: only accept 0 and 1, not just any non-zero value */ - if(rv == 0) { - reading->publish = 0; - snprintf(reading->converted, WEB_DEMO_CONVERTED_LEN, "\"N/A\""); - } else if(rv == 1) { - reading->publish = 1; - } else { - return HTTPD_SIMPLE_POST_HANDLER_ERROR; - } - - return HTTPD_SIMPLE_POST_HANDLER_OK; - } - } - - return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; -} -/*---------------------------------------------------------------------------*/ -#if WEB_DEMO_READ_PARENT_RSSI -static int -ping_interval_post_handler(char *key, int key_len, char *val, int val_len) -{ - int rv = 0; - - if(key_len != strlen("ping_interval") || - strncasecmp(key, "ping_interval", strlen("ping_interval")) != 0) { - /* Not ours */ - return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; - } - - rv = atoi(val); - - if(rv < WEB_DEMO_RSSI_MEASURE_INTERVAL_MIN || - rv > WEB_DEMO_RSSI_MEASURE_INTERVAL_MAX) { - return HTTPD_SIMPLE_POST_HANDLER_ERROR; - } - - web_demo_config.def_rt_ping_interval = rv * CLOCK_SECOND; - - return HTTPD_SIMPLE_POST_HANDLER_OK; -} -#endif -/*---------------------------------------------------------------------------*/ -HTTPD_SIMPLE_POST_HANDLER(sensor, sensor_readings_handler); -HTTPD_SIMPLE_POST_HANDLER(defaults, defaults_post_handler); - -#if WEB_DEMO_READ_PARENT_RSSI -HTTPD_SIMPLE_POST_HANDLER(ping_interval, ping_interval_post_handler); -/*---------------------------------------------------------------------------*/ -static void -echo_reply_handler(uip_ipaddr_t *source, uint8_t ttl, uint8_t *data, - uint16_t datalen) -{ - if(uip_ip6addr_cmp(source, uip_ds6_defrt_choose())) { - def_rt_rssi = sicslowpan_get_last_rssi(); - } -} -/*---------------------------------------------------------------------------*/ -static void -ping_parent(void) -{ - if(uip_ds6_get_global(ADDR_PREFERRED) == NULL) { - return; - } - - uip_icmp6_send(uip_ds6_defrt_choose(), ICMP6_ECHO_REQUEST, 0, - WEB_DEMO_ECHO_REQ_PAYLOAD_LEN); -} -#endif -/*---------------------------------------------------------------------------*/ -static void -get_batmon_reading(void *data) -{ - int value; - char *buf; - clock_time_t next = SENSOR_READING_PERIOD + - (random_rand() % SENSOR_READING_RANDOM); - - if(batmon_temp_reading.publish) { - value = batmon_sensor.value(BATMON_SENSOR_TYPE_TEMP); - if(value != BATMON_SENSOR_READING_ERROR) { - batmon_temp_reading.raw = value; - - buf = batmon_temp_reading.converted; - memset(buf, 0, WEB_DEMO_CONVERTED_LEN); - snprintf(buf, WEB_DEMO_CONVERTED_LEN, "%d", value); - } - } - - if(batmon_volt_reading.publish) { - value = batmon_sensor.value(BATMON_SENSOR_TYPE_VOLT); - if(value != BATMON_SENSOR_READING_ERROR) { - batmon_volt_reading.raw = value; - - buf = batmon_volt_reading.converted; - memset(buf, 0, WEB_DEMO_CONVERTED_LEN); - snprintf(buf, WEB_DEMO_CONVERTED_LEN, "%d", (value * 125) >> 5); - } - } - - ctimer_set(&batmon_timer, next, get_batmon_reading, NULL); -} -/*---------------------------------------------------------------------------*/ -#if WEB_DEMO_ADC_DEMO -static void -get_adc_reading(void *data) -{ - int value; - char *buf; - - if(adc_dio23_reading.publish) { - value = single_adc_sample; - buf = adc_dio23_reading.converted; - memset(buf, 0, WEB_DEMO_CONVERTED_LEN); - snprintf(buf, WEB_DEMO_CONVERTED_LEN, "%d", (value * 4300) >> 12); - } -} -#endif -/*---------------------------------------------------------------------------*/ -#if BOARD_SENSORTAG -/*---------------------------------------------------------------------------*/ -static void -compare_and_update(web_demo_sensor_reading_t *reading) -{ - if(reading->last == reading->raw) { - reading->changed = 0; - } else { - reading->last = reading->raw; - reading->changed = 1; - } -} -/*---------------------------------------------------------------------------*/ -static void -print_mpu_reading(int reading, char *buf) -{ - char *loc_buf = buf; - - if(reading < 0) { - sprintf(loc_buf, "-"); - reading = -reading; - loc_buf++; - } - - sprintf(loc_buf, "%d.%02d", reading / 100, reading % 100); -} -/*---------------------------------------------------------------------------*/ -static void -get_bmp_reading() -{ - int value; - char *buf; - clock_time_t next = SENSOR_READING_PERIOD + - (random_rand() % SENSOR_READING_RANDOM); - - if(bmp_pres_reading.publish) { - value = bmp_280_sensor.value(BMP_280_SENSOR_TYPE_PRESS); - if(value != BMP_280_READING_ERROR) { - bmp_pres_reading.raw = value; - - compare_and_update(&bmp_pres_reading); - - buf = bmp_pres_reading.converted; - memset(buf, 0, WEB_DEMO_CONVERTED_LEN); - snprintf(buf, WEB_DEMO_CONVERTED_LEN, "%d.%02d", value / 100, - value % 100); - } - } - - if(bmp_temp_reading.publish) { - value = bmp_280_sensor.value(BMP_280_SENSOR_TYPE_TEMP); - if(value != BMP_280_READING_ERROR) { - bmp_temp_reading.raw = value; - - compare_and_update(&bmp_temp_reading); - - buf = bmp_temp_reading.converted; - memset(buf, 0, WEB_DEMO_CONVERTED_LEN); - snprintf(buf, WEB_DEMO_CONVERTED_LEN, "%d.%02d", value / 100, - value % 100); - } - } - - SENSORS_DEACTIVATE(bmp_280_sensor); - - ctimer_set(&bmp_timer, next, init_bmp_reading, NULL); -} -/*---------------------------------------------------------------------------*/ -static void -get_tmp_reading() -{ - int value; - char *buf; - clock_time_t next = SENSOR_READING_PERIOD + - (random_rand() % SENSOR_READING_RANDOM); - - if(tmp_amb_reading.publish || tmp_obj_reading.publish) { - if(tmp_007_sensor.value(TMP_007_TYPE_ALL) == - TMP_007_READING_ERROR) { - - SENSORS_DEACTIVATE(tmp_007_sensor); - ctimer_set(&tmp_timer, next, init_tmp_reading, NULL); - } - } - - if(tmp_amb_reading.publish) { - value = tmp_007_sensor.value(TMP_007_TYPE_AMBIENT); - tmp_amb_reading.raw = value; - - compare_and_update(&tmp_amb_reading); - - buf = tmp_amb_reading.converted; - memset(buf, 0, WEB_DEMO_CONVERTED_LEN); - snprintf(buf, WEB_DEMO_CONVERTED_LEN, "%d.%03d", value / 1000, - value % 1000); - } - - if(tmp_obj_reading.publish) { - value = tmp_007_sensor.value(TMP_007_TYPE_OBJECT); - tmp_obj_reading.raw = value; - - compare_and_update(&tmp_obj_reading); - - buf = tmp_obj_reading.converted; - memset(buf, 0, WEB_DEMO_CONVERTED_LEN); - snprintf(buf, WEB_DEMO_CONVERTED_LEN, "%d.%03d", value / 1000, - value % 1000); - } - - SENSORS_DEACTIVATE(tmp_007_sensor); - - ctimer_set(&tmp_timer, next, init_tmp_reading, NULL); -} -/*---------------------------------------------------------------------------*/ -static void -get_hdc_reading() -{ - int value; - char *buf; - clock_time_t next = SENSOR_READING_PERIOD + - (random_rand() % SENSOR_READING_RANDOM); - - if(hdc_temp_reading.publish) { - value = hdc_1000_sensor.value(HDC_1000_SENSOR_TYPE_TEMP); - if(value != HDC_1000_READING_ERROR) { - hdc_temp_reading.raw = value; - - compare_and_update(&hdc_temp_reading); - - buf = hdc_temp_reading.converted; - memset(buf, 0, WEB_DEMO_CONVERTED_LEN); - snprintf(buf, WEB_DEMO_CONVERTED_LEN, "%d.%02d", value / 100, - value % 100); - } - } - - if(hdc_hum_reading.publish) { - value = hdc_1000_sensor.value(HDC_1000_SENSOR_TYPE_HUMID); - if(value != HDC_1000_READING_ERROR) { - hdc_hum_reading.raw = value; - - compare_and_update(&hdc_hum_reading); - - buf = hdc_hum_reading.converted; - memset(buf, 0, WEB_DEMO_CONVERTED_LEN); - snprintf(buf, WEB_DEMO_CONVERTED_LEN, "%d.%02d", value / 100, - value % 100); - } - } - - ctimer_set(&hdc_timer, next, init_hdc_reading, NULL); -} -/*---------------------------------------------------------------------------*/ -static void -get_light_reading() -{ - int value; - char *buf; - clock_time_t next = SENSOR_READING_PERIOD + - (random_rand() % SENSOR_READING_RANDOM); - - value = opt_3001_sensor.value(0); - - if(value != OPT_3001_READING_ERROR) { - opt_reading.raw = value; - - compare_and_update(&opt_reading); - - buf = opt_reading.converted; - memset(buf, 0, WEB_DEMO_CONVERTED_LEN); - snprintf(buf, WEB_DEMO_CONVERTED_LEN, "%d.%02d", value / 100, - value % 100); - } - - /* The OPT will turn itself off, so we don't need to call its DEACTIVATE */ - ctimer_set(&opt_timer, next, init_light_reading, NULL); -} -/*---------------------------------------------------------------------------*/ -static void -get_mpu_reading() -{ - clock_time_t next = SENSOR_READING_PERIOD + - (random_rand() % SENSOR_READING_RANDOM); - int raw; - - if(mpu_gyro_x_reading.publish) { - raw = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_GYRO_X); - if(raw != MPU_9250_READING_ERROR) { - mpu_gyro_x_reading.raw = raw; - } - } - - if(mpu_gyro_y_reading.publish) { - raw = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_GYRO_Y); - if(raw != MPU_9250_READING_ERROR) { - mpu_gyro_y_reading.raw = raw; - } - } - - if(mpu_gyro_z_reading.publish) { - raw = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_GYRO_Z); - if(raw != MPU_9250_READING_ERROR) { - mpu_gyro_z_reading.raw = raw; - } - } - - if(mpu_acc_x_reading.publish) { - raw = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_ACC_X); - if(raw != MPU_9250_READING_ERROR) { - mpu_acc_x_reading.raw = raw; - } - } - - if(mpu_acc_y_reading.publish) { - raw = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_ACC_Y); - if(raw != MPU_9250_READING_ERROR) { - mpu_acc_y_reading.raw = raw; - } - } - - if(mpu_acc_z_reading.publish) { - raw = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_ACC_Z); - if(raw != MPU_9250_READING_ERROR) { - mpu_acc_z_reading.raw = raw; - } - } - - SENSORS_DEACTIVATE(mpu_9250_sensor); - - if(mpu_gyro_x_reading.publish) { - compare_and_update(&mpu_gyro_x_reading); - memset(mpu_gyro_x_reading.converted, 0, WEB_DEMO_CONVERTED_LEN); - print_mpu_reading(mpu_gyro_x_reading.raw, mpu_gyro_x_reading.converted); - } - - if(mpu_gyro_y_reading.publish) { - compare_and_update(&mpu_gyro_y_reading); - memset(mpu_gyro_y_reading.converted, 0, WEB_DEMO_CONVERTED_LEN); - print_mpu_reading(mpu_gyro_y_reading.raw, mpu_gyro_y_reading.converted); - } - - if(mpu_gyro_z_reading.publish) { - compare_and_update(&mpu_gyro_z_reading); - memset(mpu_gyro_z_reading.converted, 0, WEB_DEMO_CONVERTED_LEN); - print_mpu_reading(mpu_gyro_z_reading.raw, mpu_gyro_z_reading.converted); - } - - if(mpu_acc_x_reading.publish) { - compare_and_update(&mpu_acc_x_reading); - memset(mpu_acc_x_reading.converted, 0, WEB_DEMO_CONVERTED_LEN); - print_mpu_reading(mpu_acc_x_reading.raw, mpu_acc_x_reading.converted); - } - - if(mpu_acc_y_reading.publish) { - compare_and_update(&mpu_acc_y_reading); - memset(mpu_acc_y_reading.converted, 0, WEB_DEMO_CONVERTED_LEN); - print_mpu_reading(mpu_acc_y_reading.raw, mpu_acc_y_reading.converted); - } - - if(mpu_acc_z_reading.publish) { - compare_and_update(&mpu_acc_z_reading); - memset(mpu_acc_z_reading.converted, 0, WEB_DEMO_CONVERTED_LEN); - print_mpu_reading(mpu_acc_z_reading.raw, mpu_acc_z_reading.converted); - } - - /* We only use the single timer */ - ctimer_set(&mpu_timer, next, init_mpu_reading, NULL); -} -/*---------------------------------------------------------------------------*/ -static void -init_tmp_reading(void *data) -{ - if(tmp_amb_reading.publish || tmp_obj_reading.publish) { - SENSORS_ACTIVATE(tmp_007_sensor); - } else { - ctimer_set(&tmp_timer, CLOCK_SECOND, init_tmp_reading, NULL); - } -} -/*---------------------------------------------------------------------------*/ -static void -init_bmp_reading(void *data) -{ - if(bmp_pres_reading.publish || bmp_temp_reading.publish) { - SENSORS_ACTIVATE(bmp_280_sensor); - } else { - ctimer_set(&bmp_timer, CLOCK_SECOND, init_bmp_reading, NULL); - } -} -/*---------------------------------------------------------------------------*/ -static void -init_hdc_reading(void *data) -{ - if(hdc_hum_reading.publish || hdc_temp_reading.publish) { - SENSORS_ACTIVATE(hdc_1000_sensor); - } else { - ctimer_set(&hdc_timer, CLOCK_SECOND, init_hdc_reading, NULL); - } -} -/*---------------------------------------------------------------------------*/ -static void -init_light_reading(void *data) -{ - if(opt_reading.publish) { - SENSORS_ACTIVATE(opt_3001_sensor); - } else { - ctimer_set(&opt_timer, CLOCK_SECOND, init_light_reading, NULL); - } -} -/*---------------------------------------------------------------------------*/ -static void -init_mpu_reading(void *data) -{ - int readings_bitmap = 0; - - if(mpu_acc_x_reading.publish || mpu_acc_y_reading.publish || - mpu_acc_z_reading.publish) { - readings_bitmap |= MPU_9250_SENSOR_TYPE_ACC; - } - - if(mpu_gyro_x_reading.publish || mpu_gyro_y_reading.publish || - mpu_gyro_z_reading.publish) { - readings_bitmap |= MPU_9250_SENSOR_TYPE_GYRO; - } - - if(readings_bitmap) { - mpu_9250_sensor.configure(SENSORS_ACTIVE, readings_bitmap); - } else { - ctimer_set(&mpu_timer, CLOCK_SECOND, init_mpu_reading, NULL); - } -} -#endif -/*---------------------------------------------------------------------------*/ -static void -init_sensor_readings(void) -{ - /* - * Make a first pass and get all initial sensor readings. This will also - * trigger periodic value updates - */ - get_batmon_reading(NULL); - -#if BOARD_SENSORTAG - init_bmp_reading(NULL); - init_light_reading(NULL); - init_hdc_reading(NULL); - init_tmp_reading(NULL); - init_mpu_reading(NULL); -#endif /* BOARD_SENSORTAG */ - - return; -} -/*---------------------------------------------------------------------------*/ -static void -init_sensors(void) -{ - - list_add(sensor_list, &batmon_temp_reading); - list_add(sensor_list, &batmon_volt_reading); - -#if WEB_DEMO_ADC_DEMO - list_add(sensor_list, &adc_dio23_reading); -#endif - - SENSORS_ACTIVATE(batmon_sensor); - -#if BOARD_SENSORTAG - list_add(sensor_list, &bmp_pres_reading); - list_add(sensor_list, &bmp_temp_reading); - - list_add(sensor_list, &tmp_obj_reading); - list_add(sensor_list, &tmp_amb_reading); - - list_add(sensor_list, &opt_reading); - - list_add(sensor_list, &hdc_hum_reading); - list_add(sensor_list, &hdc_temp_reading); - - list_add(sensor_list, &mpu_acc_x_reading); - list_add(sensor_list, &mpu_acc_y_reading); - list_add(sensor_list, &mpu_acc_z_reading); - list_add(sensor_list, &mpu_gyro_x_reading); - list_add(sensor_list, &mpu_gyro_y_reading); - list_add(sensor_list, &mpu_gyro_z_reading); -#endif -} -/*---------------------------------------------------------------------------*/ -PROCESS_THREAD(web_demo_process, ev, data) -{ - PROCESS_BEGIN(); - - printf("CC13xx/CC26xx Web Demo Process\n"); - - init_sensors(); - - web_demo_publish_event = process_alloc_event(); - web_demo_config_loaded_event = process_alloc_event(); - web_demo_load_config_defaults = process_alloc_event(); - - /* Start all other (enabled) processes first */ - process_start(&httpd_simple_process, NULL); - -#if WEB_DEMO_COAP_SERVER - process_start(&coap_server_process, NULL); -#endif - -#if WEB_DEMO_6LBR_CLIENT - process_start(&cetic_6lbr_client_process, NULL); -#endif - -#if WEB_DEMO_MQTT_CLIENT - process_start(&mqtt_client_process, NULL); -#endif - -#if WEB_DEMO_NET_UART - process_start(&net_uart_process, NULL); -#endif - -#if WEB_DEMO_ADC_DEMO - process_start(&adc_process, NULL); -#endif - - /* - * Now that processes have set their own config default values, set our - * own defaults and restore saved config from flash... - */ - web_demo_config.sensors_bitmap = 0xFFFFFFFF; /* all on by default */ - web_demo_config.def_rt_ping_interval = - WEB_DEMO_DEFAULT_RSSI_MEAS_INTERVAL; - load_config(); - - /* - * Notify all other processes (basically the ones in this demo) that the - * configuration has been loaded from flash, in case they care - */ - process_post(PROCESS_BROADCAST, web_demo_config_loaded_event, NULL); - - init_sensor_readings(); - - httpd_simple_register_post_handler(&sensor_handler); - httpd_simple_register_post_handler(&defaults_handler); - -#if WEB_DEMO_READ_PARENT_RSSI - httpd_simple_register_post_handler(&ping_interval_handler); - - def_rt_rssi = 0x8000000; - uip_icmp6_echo_reply_callback_add(&echo_reply_notification, - echo_reply_handler); - etimer_set(&echo_request_timer, WEB_DEMO_NET_CONNECT_PERIODIC); -#endif - - etimer_set(&et, WEB_DEMO_NET_CONNECT_PERIODIC); - - /* - * Update all sensor readings on a configurable sensors_event - * (e.g a button press / or reed trigger) - */ - while(1) { - if(ev == PROCESS_EVENT_TIMER && etimer_expired(&et)) { - if(uip_ds6_get_global(ADDR_PREFERRED) == NULL) { - leds_on(WEB_DEMO_STATUS_LED); - ctimer_set(&ct, NO_NET_LED_DURATION, publish_led_off, NULL); - etimer_set(&et, WEB_DEMO_NET_CONNECT_PERIODIC); - } - } - -#if WEB_DEMO_READ_PARENT_RSSI - if(ev == PROCESS_EVENT_TIMER && etimer_expired(&echo_request_timer)) { - if(uip_ds6_get_global(ADDR_PREFERRED) == NULL) { - etimer_set(&echo_request_timer, WEB_DEMO_NET_CONNECT_PERIODIC); - } else { - ping_parent(); - etimer_set(&echo_request_timer, web_demo_config.def_rt_ping_interval); - } - } -#endif - - if(ev == button_hal_release_event && - ((button_hal_button_t *)data)->unique_id == - WEB_DEMO_SENSOR_READING_TRIGGER) { - init_sensor_readings(); - process_post(PROCESS_BROADCAST, web_demo_publish_event, NULL); - } else if(ev == button_hal_periodic_event && - ((button_hal_button_t *)data)->unique_id == - WEB_DEMO_SENSOR_READING_TRIGGER) { - printf("Restoring defaults!\n"); - web_demo_restore_defaults(); - } else if(ev == httpd_simple_event_new_config) { - save_config(); -#if BOARD_SENSORTAG - } else if(ev == sensors_event && data == &bmp_280_sensor) { - get_bmp_reading(); - } else if(ev == sensors_event && data == &opt_3001_sensor) { - get_light_reading(); - } else if(ev == sensors_event && data == &hdc_1000_sensor) { - get_hdc_reading(); - } else if(ev == sensors_event && data == &tmp_007_sensor) { - get_tmp_reading(); - } else if(ev == sensors_event && data == &mpu_9250_sensor) { - get_mpu_reading(); -#endif - } - - PROCESS_YIELD(); - } - - PROCESS_END(); -} -/*---------------------------------------------------------------------------*/ -#if WEB_DEMO_ADC_DEMO -PROCESS_THREAD(adc_process, ev, data) -{ - static ADC_Params adc_params; - ADC_Handle adc_handle; - int_fast16_t res; - uint_fast16_t adc_value; - - PROCESS_BEGIN(); - - ADC_init(); - ADC_Params_init(&adc_params); - - etimer_set(&et_adc, CLOCK_SECOND * 5); - - while(1) { - PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et_adc)); - - adc_handle = ADC_open(Board_ADC0, &adc_params); - - if(adc_handle != NULL) { - res = ADC_convert(adc_handle, &single_adc_sample); - - if(res == ADC_STATUS_SUCCESS) { - single_adc_sample = adc_value; - get_adc_reading(NULL); - } - - ADC_close(adc_handle); - } - - etimer_reset(&et_adc); - } - - PROCESS_END(); -} -#endif -/*---------------------------------------------------------------------------*/ -/** - * @} - */ diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.h b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.h deleted file mode 100644 index ab2c88342..000000000 --- a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/web-demo.h +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/** - * \addtogroup cc13xx-cc26xx-examples - * @{ - * - * \defgroup cc13xx-cc26xx-web-demo CC13xx/CC26xx Web Demo - * @{ - * - * An example demonstrating: - * * how to use a CC13xx/CC26xx-powered node in a deployment driven by a 6LBR - * * how to expose on-device sensors as CoAP resources - * * how to build a small web page which reports networking and sensory data - * * how to configure functionality through the aforementioned web page using - * HTTP POST requests - * * a network-based UART - * - * \file - * Main header file for the CC13xx/CC26xx web demo. - */ -/*---------------------------------------------------------------------------*/ -#ifndef WEB_DEMO_H_ -#define WEB_DEMO_H_ -/*---------------------------------------------------------------------------*/ -#include "dev/leds.h" -#include "sys/process.h" -/*---------------------------------------------------------------------------*/ -#include "mqtt-client.h" -#include "net-uart.h" -/*---------------------------------------------------------------------------*/ -#include -/*---------------------------------------------------------------------------*/ -#ifdef WEB_DEMO_CONF_MQTT_CLIENT -#define WEB_DEMO_MQTT_CLIENT WEB_DEMO_CONF_MQTT_CLIENT -#else -#define WEB_DEMO_MQTT_CLIENT 1 -#endif - -#ifdef WEB_DEMO_CONF_6LBR_CLIENT -#define WEB_DEMO_6LBR_CLIENT WEB_DEMO_CONF_6LBR_CLIENT -#else -#define WEB_DEMO_6LBR_CLIENT 1 -#endif - -#ifdef WEB_DEMO_CONF_COAP_SERVER -#define WEB_DEMO_COAP_SERVER WEB_DEMO_CONF_COAP_SERVER -#else -#define WEB_DEMO_COAP_SERVER 1 -#endif - -#ifdef WEB_DEMO_CONF_NET_UART -#define WEB_DEMO_NET_UART WEB_DEMO_CONF_NET_UART -#else -#define WEB_DEMO_NET_UART 1 -#endif - -#ifdef WEB_DEMO_CONF_ADC_DEMO -#define WEB_DEMO_ADC_DEMO WEB_DEMO_CONF_ADC_DEMO -#else -#define WEB_DEMO_ADC_DEMO 0 -#endif -/*---------------------------------------------------------------------------*/ -/* Active probing of RSSI from our preferred parent */ -#if (WEB_DEMO_COAP_SERVER || WEB_DEMO_MQTT_CLIENT) -#define WEB_DEMO_READ_PARENT_RSSI 1 -#else -#define WEB_DEMO_READ_PARENT_RSSI 0 -#endif - -#define WEB_DEMO_RSSI_MEASURE_INTERVAL_MAX 86400 /* secs: 1 day */ -#define WEB_DEMO_RSSI_MEASURE_INTERVAL_MIN 5 /* secs */ -/*---------------------------------------------------------------------------*/ -/* User configuration */ -/* Take a sensor reading on button press */ -#define WEB_DEMO_SENSOR_READING_TRIGGER BUTTON_HAL_ID_KEY_LEFT - -/* Payload length of ICMPv6 echo requests used to measure RSSI with def rt */ -#define WEB_DEMO_ECHO_REQ_PAYLOAD_LEN 20 - -#if BOARD_SENSORTAG -/* Force an MQTT publish on sensor event */ -#define WEB_DEMO_MQTT_PUBLISH_TRIGGER BUTTON_HAL_ID_REED_RELAY -#elif BOARD_LAUNCHPAD -#define WEB_DEMO_MQTT_PUBLISH_TRIGGER BUTTON_HAL_ID_KEY_LEFT -#else -#define WEB_DEMO_MQTT_PUBLISH_TRIGGER BUTTON_HAL_ID_KEY_DOWN -#endif - -#define WEB_DEMO_STATUS_LED LEDS_GREEN -/*---------------------------------------------------------------------------*/ -/* A timeout used when waiting to connect to a network */ -#define WEB_DEMO_NET_CONNECT_PERIODIC (CLOCK_SECOND >> 3) -/*---------------------------------------------------------------------------*/ -/* Default configuration values */ -#define WEB_DEMO_DEFAULT_ORG_ID "quickstart" -#if defined(DEVICE_LINE_CC13XX) -#define WEB_DEMO_DEFAULT_TYPE_ID "cc13xx" -#elif defined(DEVICE_LINE_CC26XX) -#define WEB_DEMO_DEFAULT_TYPE_ID "cc26xx" -#endif -#define WEB_DEMO_DEFAULT_EVENT_TYPE_ID "status" -#define WEB_DEMO_DEFAULT_SUBSCRIBE_CMD_TYPE "+" -#define WEB_DEMO_DEFAULT_BROKER_PORT 1883 -#define WEB_DEMO_DEFAULT_PUBLISH_INTERVAL (30 * CLOCK_SECOND) -#define WEB_DEMO_DEFAULT_KEEP_ALIVE_TIMER 60 -#define WEB_DEMO_DEFAULT_RSSI_MEAS_INTERVAL (CLOCK_SECOND * 30) -/*---------------------------------------------------------------------------*/ -/* - * You normally won't have to change anything from here onwards unless you are - * extending the example - */ -/*---------------------------------------------------------------------------*/ -/* Sensor types */ -#define WEB_DEMO_SENSOR_BATMON_TEMP 0 -#define WEB_DEMO_SENSOR_BATMON_VOLT 1 -#define WEB_DEMO_SENSOR_BMP_PRES 2 -#define WEB_DEMO_SENSOR_BMP_TEMP 3 -#define WEB_DEMO_SENSOR_TMP_AMBIENT 4 -#define WEB_DEMO_SENSOR_TMP_OBJECT 5 -#define WEB_DEMO_SENSOR_HDC_TEMP 6 -#define WEB_DEMO_SENSOR_HDC_HUMIDITY 7 -#define WEB_DEMO_SENSOR_OPT_LIGHT 8 -#define WEB_DEMO_SENSOR_MPU_ACC_X 9 -#define WEB_DEMO_SENSOR_MPU_ACC_Y 10 -#define WEB_DEMO_SENSOR_MPU_ACC_Z 11 -#define WEB_DEMO_SENSOR_MPU_GYRO_X 12 -#define WEB_DEMO_SENSOR_MPU_GYRO_Y 13 -#define WEB_DEMO_SENSOR_MPU_GYRO_Z 14 -#define WEB_DEMO_SENSOR_ADC_DIO23 15 -/*---------------------------------------------------------------------------*/ -extern process_event_t web_demo_publish_event; -extern process_event_t web_demo_config_loaded_event; -extern process_event_t web_demo_load_config_defaults; -/*---------------------------------------------------------------------------*/ -#define WEB_DEMO_UNIT_TEMP "C" -#define WEB_DEMO_UNIT_VOLT "mV" -#define WEB_DEMO_UNIT_PRES "hPa" -#define WEB_DEMO_UNIT_HUMIDITY "%RH" -#define WEB_DEMO_UNIT_LIGHT "lux" -#define WEB_DEMO_UNIT_ACC "G" -#define WEB_DEMO_UNIT_GYRO "deg per sec" -/*---------------------------------------------------------------------------*/ -/* A data type for sensor readings, internally stored in a linked list */ -#define WEB_DEMO_CONVERTED_LEN 12 - -typedef struct web_demo_sensor_reading { - struct web_demo_sensor_reading *next; - int raw; - int last; - const char *descr; - const char *xml_element; - const char *form_field; - char *units; - uint8_t type; - uint8_t publish; - uint8_t changed; - char converted[WEB_DEMO_CONVERTED_LEN]; -} web_demo_sensor_reading_t; -/*---------------------------------------------------------------------------*/ -/* Global configuration */ -typedef struct web_demo_config_s { - uint32_t magic; - int len; - uint32_t sensors_bitmap; - int def_rt_ping_interval; - mqtt_client_config_t mqtt_config; - net_uart_config_t net_uart; -} web_demo_config_t; - -extern web_demo_config_t web_demo_config; -/*---------------------------------------------------------------------------*/ -/** - * \brief Performs a lookup for a reading of a specific type of sensor - * \param sens_type WEB_DEMO_SENSOR_BATMON_TEMP... - * \return A pointer to the reading data structure or NULL - */ -const web_demo_sensor_reading_t *web_demo_sensor_lookup(int sens_type); - -/** - * \brief Returns the first available sensor reading - * \return A pointer to the reading data structure or NULL - */ -const web_demo_sensor_reading_t *web_demo_sensor_first(void); - -/** - * \brief Print an IPv6 address into a buffer - * \param buf A pointer to the buffer where this function will print the IPv6 - * address - * \param buf_len the length of the buffer - * \param addr A pointer to the IPv6 address - * \return The number of bytes written to the buffer - * - * It is the caller's responsibility to allocate enough space for buf - */ -int web_demo_ipaddr_sprintf(char *buf, uint8_t buf_len, - const uip_ipaddr_t *addr); - -/** - * \brief Resets the example to a default configuration - */ -void web_demo_restore_defaults(void); -/*---------------------------------------------------------------------------*/ -#endif /* WEB_DEMO_H_ */ -/*---------------------------------------------------------------------------*/ -/** - * @} - * @} - */ From 1ddbedaaccea3f504a146d15ed4f3a7470f84ebb Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Thu, 30 Aug 2018 17:09:25 +0200 Subject: [PATCH 320/485] Renamed cpu dir to simplelink-cc13xx-cc26xx --- .gitmodules | 5 +++-- .../Makefile.cc13xx-cc26xx | 0 .../cc13x0-cc26x0/Makefile.cc13x0-cc26x0 | 0 .../cc13x0-cc26x0/cc13x0-cc26x0-cm3.h | 0 .../cc13x0-cc26x0/cc13x0-cc26x0.icf | 0 .../cc13x0-cc26x0/cc13x0-cc26x0.lds | 0 .../cc13x0-cc26x0/driverlib/rf_ieee_cmd.h | 0 .../cc13x0-cc26x0/driverlib/rf_ieee_mailbox.h | 0 .../rf_patches/rf_patch_cpe_ieee.h | 0 .../cc13x2-cc26x2/Makefile.cc13x2-cc26x2 | 0 .../cc13x2-cc26x2/cc13x2-cc26x2-cm4.h | 0 .../cc13x2-cc26x2/cc13x2-cc26x2.icf | 0 .../cc13x2-cc26x2/cc13x2-cc26x2.lds | 0 .../cc13xx-cc26xx-conf.h | 0 .../cc13xx-cc26xx-def.h | 0 .../ccfg-conf.c | 0 .../dev/clock-arch.c | 0 .../dev/dbg-arch.c | 0 .../dev/gpio-hal-arch.c | 0 .../dev/gpio-hal-arch.h | 0 .../dev/int-master-arch.c | 0 .../dev/random.c | 0 .../dev/rtimer-arch.c | 0 .../dev/rtimer-arch.h | 0 .../dev/slip-arch.c | 0 .../dev/spi-arch.c | 0 .../dev/startup_cc13xx_cc26xx_gcc.c | 19 +++++++++---------- .../dev/startup_cc13xx_cc26xx_iar.c | 0 .../dev/trng-arch.c | 3 ++- .../dev/trng-arch.h | 0 .../dev/uart0-arch.c | 9 +++++++++ .../dev/uart0-arch.h | 8 ++++++++ .../dev/watchdog-arch.c | 0 .../doxygen-group.txt | 0 .../lib/coresdk_cc13xx_cc26xx | 0 .../rf-settings/cc13x0/ble-settings.c | 0 .../rf-settings/cc13x0/ble-settings.h | 0 .../rf-settings/cc13x0/ble-tx-power.c | 0 .../rf-settings/cc13x0/ieee-settings.c | 0 .../rf-settings/cc13x0/ieee-settings.h | 0 .../rf-settings/cc13x0/ieee-tx-power.c | 0 .../rf-settings/cc13x0/prop-settings.c | 0 .../rf-settings/cc13x0/prop-settings.h | 0 .../rf-settings/cc13x0/prop-tx-power.c | 0 .../rf-settings/cc13x2/ble-settings.c | 0 .../rf-settings/cc13x2/ble-settings.h | 0 .../rf-settings/cc13x2/ble-tx-power.c | 0 .../rf-settings/cc13x2/ieee-settings.c | 0 .../rf-settings/cc13x2/ieee-settings.h | 0 .../rf-settings/cc13x2/ieee-tx-power.c | 0 .../rf-settings/cc13x2/prop-settings.c | 0 .../rf-settings/cc13x2/prop-settings.h | 0 .../rf-settings/cc13x2/prop-tx-power.c | 0 .../rf-settings/cc26x0/ble-settings.c | 0 .../rf-settings/cc26x0/ble-settings.h | 0 .../rf-settings/cc26x0/ble-tx-power.c | 0 .../rf-settings/cc26x0/ieee-settings.c | 0 .../rf-settings/cc26x0/ieee-settings.h | 0 .../rf-settings/cc26x0/ieee-tx-power.c | 0 .../rf-settings/cc26x2/ble-settings.c | 0 .../rf-settings/cc26x2/ble-settings.h | 0 .../rf-settings/cc26x2/ble-tx-power.c | 0 .../rf-settings/cc26x2/ieee-settings.c | 0 .../rf-settings/cc26x2/ieee-settings.h | 0 .../rf-settings/cc26x2/ieee-tx-power.c | 0 .../rf/ble-addr.c | 0 .../rf/ble-addr.h | 0 .../rf/ble-beacond.c | 0 .../rf/ble-beacond.h | 0 .../rf/data-queue.c | 0 .../rf/data-queue.h | 0 .../rf/dot-15-4g.h | 0 .../rf/ieee-addr.c | 0 .../rf/ieee-addr.h | 0 .../rf/ieee-mode.c | 0 .../rf/prop-mode.c | 3 +++ .../rf/rf.h | 0 .../rf/sched.c | 0 .../rf/sched.h | 0 .../rf/settings.h | 0 .../rf/tx-power.h | 0 .../cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 6 +++--- 82 files changed, 37 insertions(+), 16 deletions(-) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/Makefile.cc13xx-cc26xx (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/cc13x0-cc26x0/Makefile.cc13x0-cc26x0 (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/cc13x0-cc26x0/cc13x0-cc26x0-cm3.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/cc13x0-cc26x0/cc13x0-cc26x0.icf (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/cc13x0-cc26x0/cc13x0-cc26x0.lds (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/cc13x0-cc26x0/driverlib/rf_ieee_cmd.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/cc13x0-cc26x0/driverlib/rf_ieee_mailbox.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/cc13x0-cc26x0/rf_patches/rf_patch_cpe_ieee.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/cc13x2-cc26x2/Makefile.cc13x2-cc26x2 (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/cc13x2-cc26x2/cc13x2-cc26x2-cm4.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/cc13x2-cc26x2/cc13x2-cc26x2.icf (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/cc13x2-cc26x2/cc13x2-cc26x2.lds (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/cc13xx-cc26xx-conf.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/cc13xx-cc26xx-def.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/ccfg-conf.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/dev/clock-arch.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/dev/dbg-arch.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/dev/gpio-hal-arch.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/dev/gpio-hal-arch.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/dev/int-master-arch.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/dev/random.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/dev/rtimer-arch.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/dev/rtimer-arch.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/dev/slip-arch.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/dev/spi-arch.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/dev/startup_cc13xx_cc26xx_gcc.c (97%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/dev/startup_cc13xx_cc26xx_iar.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/dev/trng-arch.c (95%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/dev/trng-arch.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/dev/uart0-arch.c (95%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/dev/uart0-arch.h (91%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/dev/watchdog-arch.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/doxygen-group.txt (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/lib/coresdk_cc13xx_cc26xx (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc13x0/ble-settings.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc13x0/ble-settings.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc13x0/ble-tx-power.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc13x0/ieee-settings.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc13x0/ieee-settings.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc13x0/ieee-tx-power.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc13x0/prop-settings.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc13x0/prop-settings.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc13x0/prop-tx-power.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc13x2/ble-settings.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc13x2/ble-settings.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc13x2/ble-tx-power.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc13x2/ieee-settings.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc13x2/ieee-settings.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc13x2/ieee-tx-power.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc13x2/prop-settings.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc13x2/prop-settings.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc13x2/prop-tx-power.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc26x0/ble-settings.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc26x0/ble-settings.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc26x0/ble-tx-power.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc26x0/ieee-settings.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc26x0/ieee-settings.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc26x0/ieee-tx-power.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc26x2/ble-settings.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc26x2/ble-settings.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc26x2/ble-tx-power.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc26x2/ieee-settings.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc26x2/ieee-settings.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf-settings/cc26x2/ieee-tx-power.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf/ble-addr.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf/ble-addr.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf/ble-beacond.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf/ble-beacond.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf/data-queue.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf/data-queue.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf/dot-15-4g.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf/ieee-addr.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf/ieee-addr.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf/ieee-mode.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf/prop-mode.c (99%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf/rf.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf/sched.c (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf/sched.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf/settings.h (100%) rename arch/cpu/{cc13xx-cc26xx => simplelink-cc13xx-cc26xx}/rf/tx-power.h (100%) diff --git a/.gitmodules b/.gitmodules index 8fdbdbe63..22742f302 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,6 +22,7 @@ [submodule "tools/motelist"] path = tools/motelist url = https://github.com/contiki-ng/motelist -[submodule "arch/cpu/cc13xx-cc26xx/lib/coresdk_cc13xx_cc26xx"] - path = arch/cpu/cc13xx-cc26xx/lib/coresdk_cc13xx_cc26xx +[submodule "arch/cpu/simplelink-cc13xx-cc26xx/lib/coresdk_cc13xx_cc26xx"] + path = arch/cpu/simplelink-cc13xx-cc26xx/lib/coresdk_cc13xx_cc26xx url = https://github.com/tiepettersen/coresdk_cc13xx_cc26xx.git + diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/cpu/simplelink-cc13xx-cc26xx/Makefile.cc13xx-cc26xx similarity index 100% rename from arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx rename to arch/cpu/simplelink-cc13xx-cc26xx/Makefile.cc13xx-cc26xx diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/Makefile.cc13x0-cc26x0 b/arch/cpu/simplelink-cc13xx-cc26xx/cc13x0-cc26x0/Makefile.cc13x0-cc26x0 similarity index 100% rename from arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/Makefile.cc13x0-cc26x0 rename to arch/cpu/simplelink-cc13xx-cc26xx/cc13x0-cc26x0/Makefile.cc13x0-cc26x0 diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0-cm3.h b/arch/cpu/simplelink-cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0-cm3.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0-cm3.h rename to arch/cpu/simplelink-cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0-cm3.h diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.icf b/arch/cpu/simplelink-cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.icf similarity index 100% rename from arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.icf rename to arch/cpu/simplelink-cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.icf diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds b/arch/cpu/simplelink-cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds similarity index 100% rename from arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds rename to arch/cpu/simplelink-cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/driverlib/rf_ieee_cmd.h b/arch/cpu/simplelink-cc13xx-cc26xx/cc13x0-cc26x0/driverlib/rf_ieee_cmd.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/driverlib/rf_ieee_cmd.h rename to arch/cpu/simplelink-cc13xx-cc26xx/cc13x0-cc26x0/driverlib/rf_ieee_cmd.h diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/driverlib/rf_ieee_mailbox.h b/arch/cpu/simplelink-cc13xx-cc26xx/cc13x0-cc26x0/driverlib/rf_ieee_mailbox.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/driverlib/rf_ieee_mailbox.h rename to arch/cpu/simplelink-cc13xx-cc26xx/cc13x0-cc26x0/driverlib/rf_ieee_mailbox.h diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf_patches/rf_patch_cpe_ieee.h b/arch/cpu/simplelink-cc13xx-cc26xx/cc13x0-cc26x0/rf_patches/rf_patch_cpe_ieee.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf_patches/rf_patch_cpe_ieee.h rename to arch/cpu/simplelink-cc13xx-cc26xx/cc13x0-cc26x0/rf_patches/rf_patch_cpe_ieee.h diff --git a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/Makefile.cc13x2-cc26x2 b/arch/cpu/simplelink-cc13xx-cc26xx/cc13x2-cc26x2/Makefile.cc13x2-cc26x2 similarity index 100% rename from arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/Makefile.cc13x2-cc26x2 rename to arch/cpu/simplelink-cc13xx-cc26xx/cc13x2-cc26x2/Makefile.cc13x2-cc26x2 diff --git a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2-cm4.h b/arch/cpu/simplelink-cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2-cm4.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2-cm4.h rename to arch/cpu/simplelink-cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2-cm4.h diff --git a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.icf b/arch/cpu/simplelink-cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.icf similarity index 100% rename from arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.icf rename to arch/cpu/simplelink-cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.icf diff --git a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds b/arch/cpu/simplelink-cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds similarity index 100% rename from arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds rename to arch/cpu/simplelink-cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds diff --git a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h b/arch/cpu/simplelink-cc13xx-cc26xx/cc13xx-cc26xx-conf.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h rename to arch/cpu/simplelink-cc13xx-cc26xx/cc13xx-cc26xx-conf.h diff --git a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-def.h b/arch/cpu/simplelink-cc13xx-cc26xx/cc13xx-cc26xx-def.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-def.h rename to arch/cpu/simplelink-cc13xx-cc26xx/cc13xx-cc26xx-def.h diff --git a/arch/cpu/cc13xx-cc26xx/ccfg-conf.c b/arch/cpu/simplelink-cc13xx-cc26xx/ccfg-conf.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/ccfg-conf.c rename to arch/cpu/simplelink-cc13xx-cc26xx/ccfg-conf.c diff --git a/arch/cpu/cc13xx-cc26xx/dev/clock-arch.c b/arch/cpu/simplelink-cc13xx-cc26xx/dev/clock-arch.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/dev/clock-arch.c rename to arch/cpu/simplelink-cc13xx-cc26xx/dev/clock-arch.c diff --git a/arch/cpu/cc13xx-cc26xx/dev/dbg-arch.c b/arch/cpu/simplelink-cc13xx-cc26xx/dev/dbg-arch.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/dev/dbg-arch.c rename to arch/cpu/simplelink-cc13xx-cc26xx/dev/dbg-arch.c diff --git a/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c b/arch/cpu/simplelink-cc13xx-cc26xx/dev/gpio-hal-arch.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c rename to arch/cpu/simplelink-cc13xx-cc26xx/dev/gpio-hal-arch.c diff --git a/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.h b/arch/cpu/simplelink-cc13xx-cc26xx/dev/gpio-hal-arch.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.h rename to arch/cpu/simplelink-cc13xx-cc26xx/dev/gpio-hal-arch.h diff --git a/arch/cpu/cc13xx-cc26xx/dev/int-master-arch.c b/arch/cpu/simplelink-cc13xx-cc26xx/dev/int-master-arch.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/dev/int-master-arch.c rename to arch/cpu/simplelink-cc13xx-cc26xx/dev/int-master-arch.c diff --git a/arch/cpu/cc13xx-cc26xx/dev/random.c b/arch/cpu/simplelink-cc13xx-cc26xx/dev/random.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/dev/random.c rename to arch/cpu/simplelink-cc13xx-cc26xx/dev/random.c diff --git a/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c b/arch/cpu/simplelink-cc13xx-cc26xx/dev/rtimer-arch.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c rename to arch/cpu/simplelink-cc13xx-cc26xx/dev/rtimer-arch.c diff --git a/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.h b/arch/cpu/simplelink-cc13xx-cc26xx/dev/rtimer-arch.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.h rename to arch/cpu/simplelink-cc13xx-cc26xx/dev/rtimer-arch.h diff --git a/arch/cpu/cc13xx-cc26xx/dev/slip-arch.c b/arch/cpu/simplelink-cc13xx-cc26xx/dev/slip-arch.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/dev/slip-arch.c rename to arch/cpu/simplelink-cc13xx-cc26xx/dev/slip-arch.c diff --git a/arch/cpu/cc13xx-cc26xx/dev/spi-arch.c b/arch/cpu/simplelink-cc13xx-cc26xx/dev/spi-arch.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/dev/spi-arch.c rename to arch/cpu/simplelink-cc13xx-cc26xx/dev/spi-arch.c diff --git a/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c b/arch/cpu/simplelink-cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c similarity index 97% rename from arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c rename to arch/cpu/simplelink-cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c index 4c47a9ad6..7c542084b 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c +++ b/arch/cpu/simplelink-cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c @@ -129,13 +129,6 @@ localProgramStart(void) uint32_t count; uint32_t i; -#if defined(__ARM_ARCH_7EM__) && defined(__VFP_FP__) && !defined(__SOFTFP__) - volatile uint32_t *pui32Cpacr = (uint32_t *)0xE000ED88; - - /* Enable Coprocessor Access Control (CPAC) */ - *pui32Cpacr |= (0xF << 20); -#endif - IntMasterDisable(); /* Final trim of device */ @@ -193,7 +186,10 @@ resetISR(void) "movt r0, #:upper16:resetVectors \n" "ldr r0, [r0] \n" "mov sp, r0 \n" - "bl localProgramStart \n" + "bx %0 \n" + : /* output */ + : /* input */ + "r"(localProgramStart) ); } /*---------------------------------------------------------------------------*/ @@ -217,7 +213,7 @@ nmiISR(void) * * Provide a view into the CPU state from the provided stack pointer. */ -void +static void debugHardfault(uint32_t *sp) { volatile uint32_t r0; /**< R0 register */ @@ -259,7 +255,10 @@ faultISR(void) "ite eq \n" "mrseq r0, msp \n" "mrsne r0, psp \n" - "b debugHardfault \n" + "bx %0 \n" + : /* output */ + : /* input */ + "r"(debugHardfault) ); } /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_iar.c b/arch/cpu/simplelink-cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_iar.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_iar.c rename to arch/cpu/simplelink-cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_iar.c diff --git a/arch/cpu/cc13xx-cc26xx/dev/trng-arch.c b/arch/cpu/simplelink-cc13xx-cc26xx/dev/trng-arch.c similarity index 95% rename from arch/cpu/cc13xx-cc26xx/dev/trng-arch.c rename to arch/cpu/simplelink-cc13xx-cc26xx/dev/trng-arch.c index 5196c5c6e..5371bdcb4 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/trng-arch.c +++ b/arch/cpu/simplelink-cc13xx-cc26xx/dev/trng-arch.c @@ -46,7 +46,8 @@ /*---------------------------------------------------------------------------*/ /* * Very dirty workaround because the pre-compiled TI drivers library for - * CC13x0/CC26x0 is missing the CryptoKey object file. + * CC13x0/CC26x0 is missing the CryptoKey object file. This can be removed + * when the pre-compiled library includes the missing object file. */ #include #if (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0) diff --git a/arch/cpu/cc13xx-cc26xx/dev/trng-arch.h b/arch/cpu/simplelink-cc13xx-cc26xx/dev/trng-arch.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/dev/trng-arch.h rename to arch/cpu/simplelink-cc13xx-cc26xx/dev/trng-arch.h diff --git a/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c b/arch/cpu/simplelink-cc13xx-cc26xx/dev/uart0-arch.c similarity index 95% rename from arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c rename to arch/cpu/simplelink-cc13xx-cc26xx/dev/uart0-arch.c index 4bf529ddd..d9dbfb30a 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c +++ b/arch/cpu/simplelink-cc13xx-cc26xx/dev/uart0-arch.c @@ -112,6 +112,15 @@ uart0_write(const void *buf, size_t buf_size) } /*---------------------------------------------------------------------------*/ int_fast32_t +uart0_write_byte(uint8_t byte) +{ + if(!initialized) { + return UART_STATUS_ERROR; + } + return UART_write(uart_handle, &byte, 1); +} +/*---------------------------------------------------------------------------*/ +int_fast32_t uart0_set_callback(uart0_input_fxn_t input_cb) { if(!initialized) { diff --git a/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.h b/arch/cpu/simplelink-cc13xx-cc26xx/dev/uart0-arch.h similarity index 91% rename from arch/cpu/cc13xx-cc26xx/dev/uart0-arch.h rename to arch/cpu/simplelink-cc13xx-cc26xx/dev/uart0-arch.h index 17a93519a..9d4a69fe1 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.h +++ b/arch/cpu/simplelink-cc13xx-cc26xx/dev/uart0-arch.h @@ -65,6 +65,14 @@ void uart0_init(void); */ int_fast32_t uart0_write(const void *buf, size_t buf_size); +/** + * \brief Writes a single byte to the UART interface. + * \param byte Byte to write. + * \return Number of bytes that has been written to the UART. If an + * error occurs, a negative value is returned. + */ +int_fast32_t uart0_write_byte(uint8_t byte); + /** * \brief Set the callback function for when bytes are received * on UART0. diff --git a/arch/cpu/cc13xx-cc26xx/dev/watchdog-arch.c b/arch/cpu/simplelink-cc13xx-cc26xx/dev/watchdog-arch.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/dev/watchdog-arch.c rename to arch/cpu/simplelink-cc13xx-cc26xx/dev/watchdog-arch.c diff --git a/arch/cpu/cc13xx-cc26xx/doxygen-group.txt b/arch/cpu/simplelink-cc13xx-cc26xx/doxygen-group.txt similarity index 100% rename from arch/cpu/cc13xx-cc26xx/doxygen-group.txt rename to arch/cpu/simplelink-cc13xx-cc26xx/doxygen-group.txt diff --git a/arch/cpu/cc13xx-cc26xx/lib/coresdk_cc13xx_cc26xx b/arch/cpu/simplelink-cc13xx-cc26xx/lib/coresdk_cc13xx_cc26xx similarity index 100% rename from arch/cpu/cc13xx-cc26xx/lib/coresdk_cc13xx_cc26xx rename to arch/cpu/simplelink-cc13xx-cc26xx/lib/coresdk_cc13xx_cc26xx diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.c rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.c diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.h b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.h rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.h diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-tx-power.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x0/ble-tx-power.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-tx-power.c rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x0/ble-tx-power.c diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-tx-power.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x0/ieee-tx-power.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-tx-power.c rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x0/ieee-tx-power.c diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-tx-power.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x0/prop-tx-power.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-tx-power.c rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x0/prop-tx-power.c diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.c rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.c diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.h b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.h rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.h diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-tx-power.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x2/ble-tx-power.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-tx-power.c rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x2/ble-tx-power.c diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-tx-power.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x2/ieee-tx-power.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-tx-power.c rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x2/ieee-tx-power.c diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-tx-power.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x2/prop-tx-power.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-tx-power.c rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x2/prop-tx-power.c diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.c rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.c diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.h b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.h rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.h diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-tx-power.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc26x0/ble-tx-power.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-tx-power.c rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc26x0/ble-tx-power.c diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-tx-power.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc26x0/ieee-tx-power.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-tx-power.c rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc26x0/ieee-tx-power.c diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.c rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.c diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.h b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.h rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.h diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-tx-power.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc26x2/ble-tx-power.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-tx-power.c rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc26x2/ble-tx-power.c diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-tx-power.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc26x2/ieee-tx-power.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-tx-power.c rename to arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc26x2/ieee-tx-power.c diff --git a/arch/cpu/cc13xx-cc26xx/rf/ble-addr.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf/ble-addr.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf/ble-addr.c rename to arch/cpu/simplelink-cc13xx-cc26xx/rf/ble-addr.c diff --git a/arch/cpu/cc13xx-cc26xx/rf/ble-addr.h b/arch/cpu/simplelink-cc13xx-cc26xx/rf/ble-addr.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf/ble-addr.h rename to arch/cpu/simplelink-cc13xx-cc26xx/rf/ble-addr.h diff --git a/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf/ble-beacond.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c rename to arch/cpu/simplelink-cc13xx-cc26xx/rf/ble-beacond.c diff --git a/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.h b/arch/cpu/simplelink-cc13xx-cc26xx/rf/ble-beacond.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf/ble-beacond.h rename to arch/cpu/simplelink-cc13xx-cc26xx/rf/ble-beacond.h diff --git a/arch/cpu/cc13xx-cc26xx/rf/data-queue.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf/data-queue.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf/data-queue.c rename to arch/cpu/simplelink-cc13xx-cc26xx/rf/data-queue.c diff --git a/arch/cpu/cc13xx-cc26xx/rf/data-queue.h b/arch/cpu/simplelink-cc13xx-cc26xx/rf/data-queue.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf/data-queue.h rename to arch/cpu/simplelink-cc13xx-cc26xx/rf/data-queue.h diff --git a/arch/cpu/cc13xx-cc26xx/rf/dot-15-4g.h b/arch/cpu/simplelink-cc13xx-cc26xx/rf/dot-15-4g.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf/dot-15-4g.h rename to arch/cpu/simplelink-cc13xx-cc26xx/rf/dot-15-4g.h diff --git a/arch/cpu/cc13xx-cc26xx/rf/ieee-addr.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf/ieee-addr.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf/ieee-addr.c rename to arch/cpu/simplelink-cc13xx-cc26xx/rf/ieee-addr.c diff --git a/arch/cpu/cc13xx-cc26xx/rf/ieee-addr.h b/arch/cpu/simplelink-cc13xx-cc26xx/rf/ieee-addr.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf/ieee-addr.h rename to arch/cpu/simplelink-cc13xx-cc26xx/rf/ieee-addr.h diff --git a/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf/ieee-mode.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c rename to arch/cpu/simplelink-cc13xx-cc26xx/rf/ieee-mode.c diff --git a/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf/prop-mode.c similarity index 99% rename from arch/cpu/cc13xx-cc26xx/rf/prop-mode.c rename to arch/cpu/simplelink-cc13xx-cc26xx/rf/prop-mode.c index 16877f333..a100f262a 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c +++ b/arch/cpu/simplelink-cc13xx-cc26xx/rf/prop-mode.c @@ -78,6 +78,9 @@ #define LOG_MODULE "Radio" #define LOG_LEVEL LOG_LEVEL_NONE /*---------------------------------------------------------------------------*/ +#undef CLAMP +#define CLAMP(v, vmin, vmax) (MAX(MIN(v, vmax), vmin)) +/*---------------------------------------------------------------------------*/ /* Configuration parameters */ #define PROP_MODE_DYN_WHITENER PROP_MODE_CONF_DW #define PROP_MODE_USE_CRC16 PROP_MODE_CONF_USE_CRC16 diff --git a/arch/cpu/cc13xx-cc26xx/rf/rf.h b/arch/cpu/simplelink-cc13xx-cc26xx/rf/rf.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf/rf.h rename to arch/cpu/simplelink-cc13xx-cc26xx/rf/rf.h diff --git a/arch/cpu/cc13xx-cc26xx/rf/sched.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf/sched.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf/sched.c rename to arch/cpu/simplelink-cc13xx-cc26xx/rf/sched.c diff --git a/arch/cpu/cc13xx-cc26xx/rf/sched.h b/arch/cpu/simplelink-cc13xx-cc26xx/rf/sched.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf/sched.h rename to arch/cpu/simplelink-cc13xx-cc26xx/rf/sched.h diff --git a/arch/cpu/cc13xx-cc26xx/rf/settings.h b/arch/cpu/simplelink-cc13xx-cc26xx/rf/settings.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf/settings.h rename to arch/cpu/simplelink-cc13xx-cc26xx/rf/settings.h diff --git a/arch/cpu/cc13xx-cc26xx/rf/tx-power.h b/arch/cpu/simplelink-cc13xx-cc26xx/rf/tx-power.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf/tx-power.h rename to arch/cpu/simplelink-cc13xx-cc26xx/rf/tx-power.h diff --git a/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index 959e19105..5c34a233f 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -6,7 +6,7 @@ BOARD_PLATFORMS = launchpad sensortag srf06 # All supported boards for this SimpleLink family -BOARDS := $(foreach BOARD, $(BOARD_PLATFORMS), \ +BOARDS = $(foreach BOARD, $(BOARD_PLATFORMS), \ $(shell cd $(FAMILY_PATH); find $(BOARD)/* -type d -print)) ################################################################################ @@ -34,7 +34,7 @@ DEFINES += SUPPORTS_IEEE_MODE=$(SUPPORTS_IEEE_MODE) DEFINES += SUPPORTS_BLE_BEACON=$(SUPPORTS_BLE_BEACON) DEFINES += SUPPORTS_HIGH_PA=$(SUPPORTS_HIGH_PA) -### If the user-specified a Node ID, pass a define +# If the user-specified a Node ID, pass a define ifdef NODEID DEFINES += IEEE_ADDR_NODE_ID=$(NODEID) endif @@ -49,7 +49,7 @@ CONTIKI_SOURCEFILES += $(CONTIKI_TARGET_SOURCEFILES) CPU_FAMILY = cc13xx-cc26xx # Define the CPU directory and pull in the correct CPU Makefile -CONTIKI_CPU := $(realpath $(CONTIKI)/arch/cpu/$(CPU_FAMILY)) +CONTIKI_CPU := $(realpath $(CONTIKI)/arch/cpu/simplelink-$(CPU_FAMILY)) include $(CONTIKI_CPU)/Makefile.$(CPU_FAMILY) MODULES += os/net os/net/mac os/net/mac/framer From f0419b21bcea27a63eb67d83ec642f4dd5c8ec41 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Thu, 30 Aug 2018 17:10:43 +0200 Subject: [PATCH 321/485] Removed unused custom board --- .../simplelink/cc13xx-cc26xx/custom/Makefile.custom | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 arch/platform/simplelink/cc13xx-cc26xx/custom/Makefile.custom diff --git a/arch/platform/simplelink/cc13xx-cc26xx/custom/Makefile.custom b/arch/platform/simplelink/cc13xx-cc26xx/custom/Makefile.custom deleted file mode 100644 index 0b953bea8..000000000 --- a/arch/platform/simplelink/cc13xx-cc26xx/custom/Makefile.custom +++ /dev/null @@ -1,6 +0,0 @@ -################################################################################ -# SimpleLink Custom makefile - -BOARD_TYPE = BOARD_CUSTOM - -TARGET_FAMILY_DIRS += custom From eda0a9b9629198ce37c2f74595ebcd2475278719 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Thu, 30 Aug 2018 17:11:42 +0200 Subject: [PATCH 322/485] Added SPI pin declarations to Board files --- arch/dev/ext-flash/ext-flash.c | 2 +- .../simplelink/cc13xx-cc26xx/launchpad/board-conf.h | 6 +++--- .../simplelink/cc13xx-cc26xx/launchpad/cc1310/Board.h | 8 ++++++++ .../simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Board.h | 8 ++++++++ .../simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Board.h | 8 ++++++++ .../simplelink/cc13xx-cc26xx/launchpad/cc1350/Board.h | 8 ++++++++ .../simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/Board.h | 8 ++++++++ .../simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/Board.h | 8 ++++++++ .../simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Board.h | 8 ++++++++ .../simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h | 8 ++++++++ .../simplelink/cc13xx-cc26xx/launchpad/cc2650/Board.h | 8 ++++++++ .../simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Board.h | 8 ++++++++ .../simplelink/cc13xx-cc26xx/sensortag/board-conf.h | 6 +++--- .../simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h | 8 ++++++++ .../simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h | 8 ++++++++ .../simplelink/cc13xx-cc26xx/srf06/cc13x0/Board.h | 8 ++++++++ .../simplelink/cc13xx-cc26xx/srf06/cc26x0/Board.h | 8 ++++++++ 17 files changed, 119 insertions(+), 7 deletions(-) diff --git a/arch/dev/ext-flash/ext-flash.c b/arch/dev/ext-flash/ext-flash.c index eebaaf1be..c9378d2aa 100644 --- a/arch/dev/ext-flash/ext-flash.c +++ b/arch/dev/ext-flash/ext-flash.c @@ -323,7 +323,7 @@ ext_flash_open(spi_device_t *conf) flash_spi_configuration = get_spi_conf(conf); /* Check if platform has ext-flash */ - if(flash_spi_configuration->pin_spi_cs == GPIO_HAL_PIN_UNKNOWN) { + if(flash_spi_configuration->pin_spi_sck == GPIO_HAL_PIN_UNKNOWN) { return false; } diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-conf.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-conf.h index d949062bc..4e8ba08d8 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-conf.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-conf.h @@ -97,9 +97,9 @@ #if TI_SPI_CONF_SPI0_ENABLE #define EXT_FLASH_SPI_CONTROLLER Board_SPI0 -#define EXT_FLASH_SPI_PIN_SCK GPIO_HAL_PIN_UNKNOWN -#define EXT_FLASH_SPI_PIN_MOSI GPIO_HAL_PIN_UNKNOWN -#define EXT_FLASH_SPI_PIN_MISO GPIO_HAL_PIN_UNKNOWN +#define EXT_FLASH_SPI_PIN_SCK Board_SPI0_SCK +#define EXT_FLASH_SPI_PIN_MOSI Board_SPI0_MOSI +#define EXT_FLASH_SPI_PIN_MISO Board_SPI0_MISO #define EXT_FLASH_SPI_PIN_CS Board_SPI_FLASH_CS #define EXT_FLASH_DEVICE_ID 0x14 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Board.h index 67b79dc2a..6b3c762d7 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Board.h @@ -114,7 +114,15 @@ extern "C" { #define Board_SD0 CC1310_LAUNCHXL_SDSPI0 #define Board_SPI0 CC1310_LAUNCHXL_SPI0 +#define Board_SPI0_MISO CC1310_LAUNCHXL_SPI0_MISO +#define Board_SPI0_MOSI CC1310_LAUNCHXL_SPI0_MOSI +#define Board_SPI0_CLK CC1310_LAUNCHXL_SPI0_CLK +#define Board_SPI0_CSN CC1310_LAUNCHXL_SPI0_CSN #define Board_SPI1 CC1310_LAUNCHXL_SPI1 +#define Board_SPI1_MISO CC1310_LAUNCHXL_SPI1_MISO +#define Board_SPI1_MOSI CC1310_LAUNCHXL_SPI1_MOSI +#define Board_SPI1_CLK CC1310_LAUNCHXL_SPI1_CLK +#define Board_SPI1_CSN CC1310_LAUNCHXL_SPI1_CSN #define Board_SPI_FLASH_CS CC1310_LAUNCHXL_SPI_FLASH_CS #define Board_FLASH_CS_ON 0 #define Board_FLASH_CS_OFF 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Board.h index 92ddab790..c3763b019 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Board.h @@ -119,7 +119,15 @@ extern "C" { #define Board_SD0 CC1312R1_LAUNCHXL_SDSPI0 #define Board_SPI0 CC1312R1_LAUNCHXL_SPI0 +#define Board_SPI0_MISO CC1312R1_LAUNCHXL_SPI0_MISO +#define Board_SPI0_MOSI CC1312R1_LAUNCHXL_SPI0_MOSI +#define Board_SPI0_CLK CC1312R1_LAUNCHXL_SPI0_CLK +#define Board_SPI0_CSN CC1312R1_LAUNCHXL_SPI0_CSN #define Board_SPI1 CC1312R1_LAUNCHXL_SPI1 +#define Board_SPI1_MISO CC1312R1_LAUNCHXL_SPI1_MISO +#define Board_SPI1_MOSI CC1312R1_LAUNCHXL_SPI1_MOSI +#define Board_SPI1_CLK CC1312R1_LAUNCHXL_SPI1_CLK +#define Board_SPI1_CSN CC1312R1_LAUNCHXL_SPI1_CSN #define Board_SPI_FLASH_CS CC1312R1_LAUNCHXL_SPI_FLASH_CS #define Board_FLASH_CS_ON 0 #define Board_FLASH_CS_OFF 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Board.h index a10c225c8..c8094432a 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Board.h @@ -131,7 +131,15 @@ extern "C" { #define Board_SD0 CC1350_LAUNCHXL_433_SDSPI0 #define Board_SPI0 CC1350_LAUNCHXL_433_SPI0 +#define Board_SPI0_MISO CC1350_LAUNCHXL_433_SPI0_MISO +#define Board_SPI0_MOSI CC1350_LAUNCHXL_433_SPI0_MOSI +#define Board_SPI0_CLK CC1350_LAUNCHXL_433_SPI0_CLK +#define Board_SPI0_CSN CC1350_LAUNCHXL_433_SPI0_CSN #define Board_SPI1 CC1350_LAUNCHXL_433_SPI1 +#define Board_SPI1_MISO CC1350_LAUNCHXL_433_SPI1_MISO +#define Board_SPI1_MOSI CC1350_LAUNCHXL_433_SPI1_MOSI +#define Board_SPI1_CLK CC1350_LAUNCHXL_433_SPI1_CLK +#define Board_SPI1_CSN CC1350_LAUNCHXL_433_SPI1_CSN #define Board_SPI_FLASH_CS CC1350_LAUNCHXL_433_SPI_FLASH_CS #define Board_FLASH_CS_ON (0) #define Board_FLASH_CS_OFF (1) diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Board.h index e3aea2847..2099b1845 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Board.h @@ -131,7 +131,15 @@ extern "C" { #define Board_SD0 CC1350_LAUNCHXL_SDSPI0 #define Board_SPI0 CC1350_LAUNCHXL_SPI0 +#define Board_SPI0_MISO CC1350_LAUNCHXL_SPI0_MISO +#define Board_SPI0_MOSI CC1350_LAUNCHXL_SPI0_MOSI +#define Board_SPI0_CLK CC1350_LAUNCHXL_SPI0_CLK +#define Board_SPI0_CSN CC1350_LAUNCHXL_SPI0_CSN #define Board_SPI1 CC1350_LAUNCHXL_SPI1 +#define Board_SPI1_MISO CC1350_LAUNCHXL_SPI1_MISO +#define Board_SPI1_MOSI CC1350_LAUNCHXL_SPI1_MOSI +#define Board_SPI1_CLK CC1350_LAUNCHXL_SPI1_CLK +#define Board_SPI1_CSN CC1350_LAUNCHXL_SPI1_CSN #define Board_SPI_FLASH_CS CC1350_LAUNCHXL_SPI_FLASH_CS #define Board_FLASH_CS_ON (0) #define Board_FLASH_CS_OFF (1) diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/Board.h index 51b9fc4c2..d22d73c17 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/Board.h @@ -137,7 +137,15 @@ extern "C" { #define Board_SD0 CC1352P_2_LAUNCHXL_SDSPI0 #define Board_SPI0 CC1352P_2_LAUNCHXL_SPI0 +#define Board_SPI0_MISO CC1352P_2_LAUNCHXL_SPI0_MISO +#define Board_SPI0_MOSI CC1352P_2_LAUNCHXL_SPI0_MOSI +#define Board_SPI0_CLK CC1352P_2_LAUNCHXL_SPI0_CLK +#define Board_SPI0_CSN CC1352P_2_LAUNCHXL_SPI0_CSN #define Board_SPI1 CC1352P_2_LAUNCHXL_SPI1 +#define Board_SPI1_MISO CC1352P_2_LAUNCHXL_SPI1_MISO +#define Board_SPI1_MOSI CC1352P_2_LAUNCHXL_SPI1_MOSI +#define Board_SPI1_CLK CC1352P_2_LAUNCHXL_SPI1_CLK +#define Board_SPI1_CSN CC1352P_2_LAUNCHXL_SPI1_CSN #define Board_SPI_FLASH_CS CC1352P_2_LAUNCHXL_SPI_FLASH_CS #define Board_FLASH_CS_ON 0 #define Board_FLASH_CS_OFF 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/Board.h index db91700f8..381651708 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/Board.h @@ -137,7 +137,15 @@ extern "C" { #define Board_SD0 CC1352P_4_LAUNCHXL_SDSPI0 #define Board_SPI0 CC1352P_4_LAUNCHXL_SPI0 +#define Board_SPI0_MISO CC1352P_4_LAUNCHXL_SPI0_MISO +#define Board_SPI0_MOSI CC1352P_4_LAUNCHXL_SPI0_MOSI +#define Board_SPI0_CLK CC1352P_4_LAUNCHXL_SPI0_CLK +#define Board_SPI0_CSN CC1352P_4_LAUNCHXL_SPI0_CSN #define Board_SPI1 CC1352P_4_LAUNCHXL_SPI1 +#define Board_SPI1_MISO CC1352P_4_LAUNCHXL_SPI1_MISO +#define Board_SPI1_MOSI CC1352P_4_LAUNCHXL_SPI1_MOSI +#define Board_SPI1_CLK CC1352P_4_LAUNCHXL_SPI1_CLK +#define Board_SPI1_CSN CC1352P_4_LAUNCHXL_SPI1_CSN #define Board_SPI_FLASH_CS CC1352P_4_LAUNCHXL_SPI_FLASH_CS #define Board_FLASH_CS_ON 0 #define Board_FLASH_CS_OFF 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Board.h index f0a8f0042..1fef09180 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Board.h @@ -137,7 +137,15 @@ extern "C" { #define Board_SD0 CC1352P1_LAUNCHXL_SDSPI0 #define Board_SPI0 CC1352P1_LAUNCHXL_SPI0 +#define Board_SPI0_MISO CC1352P1_LAUNCHXL_SPI0_MISO +#define Board_SPI0_MOSI CC1352P1_LAUNCHXL_SPI0_MOSI +#define Board_SPI0_CLK CC1352P1_LAUNCHXL_SPI0_CLK +#define Board_SPI0_CSN CC1352P1_LAUNCHXL_SPI0_CSN #define Board_SPI1 CC1352P1_LAUNCHXL_SPI1 +#define Board_SPI1_MISO CC1352P1_LAUNCHXL_SPI1_MISO +#define Board_SPI1_MOSI CC1352P1_LAUNCHXL_SPI1_MOSI +#define Board_SPI1_CLK CC1352P1_LAUNCHXL_SPI1_CLK +#define Board_SPI1_CSN CC1352P1_LAUNCHXL_SPI1_CSN #define Board_SPI_FLASH_CS CC1352P1_LAUNCHXL_SPI_FLASH_CS #define Board_FLASH_CS_ON 0 #define Board_FLASH_CS_OFF 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h index a70dc6568..8bf0ee002 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h @@ -133,7 +133,15 @@ extern "C" { #define Board_SD0 CC1352R1_LAUNCHXL_SDSPI0 #define Board_SPI0 CC1352R1_LAUNCHXL_SPI0 +#define Board_SPI0_MISO CC1352R1_LAUNCHXL_SPI0_MISO +#define Board_SPI0_MOSI CC1352R1_LAUNCHXL_SPI0_MOSI +#define Board_SPI0_CLK CC1352R1_LAUNCHXL_SPI0_CLK +#define Board_SPI0_CSN CC1352R1_LAUNCHXL_SPI0_CSN #define Board_SPI1 CC1352R1_LAUNCHXL_SPI1 +#define Board_SPI1_MISO CC1352R1_LAUNCHXL_SPI1_MISO +#define Board_SPI1_MOSI CC1352R1_LAUNCHXL_SPI1_MOSI +#define Board_SPI1_CLK CC1352R1_LAUNCHXL_SPI1_CLK +#define Board_SPI1_CSN CC1352R1_LAUNCHXL_SPI1_CSN #define Board_SPI_FLASH_CS CC1352R1_LAUNCHXL_SPI_FLASH_CS #define Board_FLASH_CS_ON 0 #define Board_FLASH_CS_OFF 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Board.h index 38cc87207..8f3e437f0 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Board.h @@ -123,7 +123,15 @@ extern "C" { #define Board_SD0 CC2650_LAUNCHXL_SDSPI0 #define Board_SPI0 CC2650_LAUNCHXL_SPI0 +#define Board_SPI0_MISO CC2650_LAUNCHXL_SPI0_MISO +#define Board_SPI0_MOSI CC2650_LAUNCHXL_SPI0_MOSI +#define Board_SPI0_CLK CC2650_LAUNCHXL_SPI0_CLK +#define Board_SPI0_CSN CC2650_LAUNCHXL_SPI0_CSN #define Board_SPI1 CC2650_LAUNCHXL_SPI1 +#define Board_SPI1_MISO CC2650_LAUNCHXL_SPI1_MISO +#define Board_SPI1_MOSI CC2650_LAUNCHXL_SPI1_MOSI +#define Board_SPI1_CLK CC2650_LAUNCHXL_SPI1_CLK +#define Board_SPI1_CSN CC2650_LAUNCHXL_SPI1_CSN #define Board_SPI_FLASH_CS CC2650_LAUNCHXL_SPI_FLASH_CS #define Board_FLASH_CS_ON 0 #define Board_FLASH_CS_OFF 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Board.h index e44623aa0..a19145b2c 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Board.h @@ -131,7 +131,15 @@ extern "C" { #define Board_SD0 CC26X2R1_LAUNCHXL_SDSPI0 #define Board_SPI0 CC26X2R1_LAUNCHXL_SPI0 +#define Board_SPI0_MISO CC26X2R1_LAUNCHXL_SPI0_MISO +#define Board_SPI0_MOSI CC26X2R1_LAUNCHXL_SPI0_MOSI +#define Board_SPI0_CLK CC26X2R1_LAUNCHXL_SPI0_CLK +#define Board_SPI0_CSN CC26X2R1_LAUNCHXL_SPI0_CSN #define Board_SPI1 CC26X2R1_LAUNCHXL_SPI1 +#define Board_SPI1_MISO CC26X2R1_LAUNCHXL_SPI1_MISO +#define Board_SPI1_MOSI CC26X2R1_LAUNCHXL_SPI1_MOSI +#define Board_SPI1_CLK CC26X2R1_LAUNCHXL_SPI1_CLK +#define Board_SPI1_CSN CC26X2R1_LAUNCHXL_SPI1_CSN #define Board_SPI_FLASH_CS CC26X2R1_LAUNCHXL_SPI_FLASH_CS #define Board_FLASH_CS_ON 0 #define Board_FLASH_CS_OFF 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h index fedc82f17..8297edd7e 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h @@ -92,9 +92,9 @@ #if TI_SPI_CONF_SPI0_ENABLE #define EXT_FLASH_SPI_CONTROLLER Board_SPI0 -#define EXT_FLASH_SPI_PIN_SCK GPIO_HAL_PIN_UNKNOWN -#define EXT_FLASH_SPI_PIN_MOSI GPIO_HAL_PIN_UNKNOWN -#define EXT_FLASH_SPI_PIN_MISO GPIO_HAL_PIN_UNKNOWN +#define EXT_FLASH_SPI_PIN_SCK Board_SPI0_SCK +#define EXT_FLASH_SPI_PIN_MOSI Board_SPI0_MOSI +#define EXT_FLASH_SPI_PIN_MISO Board_SPI0_MISO #define EXT_FLASH_SPI_PIN_CS Board_SPI_FLASH_CS #define EXT_FLASH_DEVICE_ID 0x14 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h index 283dfe9a5..a6aeb1116 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h @@ -111,7 +111,15 @@ extern "C" { #define Board_PWM7 CC1350STK_PWM7 #define Board_SPI0 CC1350STK_SPI0 +#define Board_SPI0_MISO CC1350STK_SPI0_MISO +#define Board_SPI0_MOSI CC1350STK_SPI0_MOSI +#define Board_SPI0_CLK CC1350STK_SPI0_CLK +#define Board_SPI0_CSN CC1350STK_SPI0_CSN #define Board_SPI1 CC1350STK_SPI1 +#define Board_SPI1_MISO CC1350STK_SPI1_MISO +#define Board_SPI1_MOSI CC1350STK_SPI1_MOSI +#define Board_SPI1_CLK CC1350STK_SPI1_CLK +#define Board_SPI1_CSN CC1350STK_SPI1_CSN #define Board_SPI_FLASH_CS CC1350STK_SPI_FLASH_CS #define Board_FLASH_CS_ON CC1350STK_FLASH_CS_ON #define Board_FLASH_CS_OFF CC1350STK_FLASH_CS_OFF diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h index b1b84e0eb..a09723a73 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h @@ -111,7 +111,15 @@ extern "C" { #define Board_PWM7 CC2650STK_PWM7 #define Board_SPI0 CC2650STK_SPI0 +#define Board_SPI0_MISO CC2650STK_SPI0_MISO +#define Board_SPI0_MOSI CC2650STK_SPI0_MOSI +#define Board_SPI0_CLK CC2650STK_SPI0_CLK +#define Board_SPI0_CSN CC2650STK_SPI0_CSN #define Board_SPI1 CC2650STK_SPI1 +#define Board_SPI1_MISO CC2650STK_SPI1_MISO +#define Board_SPI1_MOSI CC2650STK_SPI1_MOSI +#define Board_SPI1_CLK CC2650STK_SPI1_CLK +#define Board_SPI1_CSN CC2650STK_SPI1_CSN #define Board_SPI_FLASH_CS CC2650STK_SPI_FLASH_CS #define Board_FLASH_CS_ON CC2650STK_FLASH_CS_ON #define Board_FLASH_CS_OFF CC2650STK_FLASH_CS_OFF diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Board.h index 6d352a9dc..0941b222f 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Board.h @@ -135,7 +135,15 @@ extern "C" { #define Board_SD0 CC1350DK_7XD_SDSPI0 #define Board_SPI0 CC1350DK_7XD_SPI0 +#define Board_SPI0_MISO CC1350DK_7XD_SPI0_MISO +#define Board_SPI0_MOSI CC1350DK_7XD_SPI0_MOSI +#define Board_SPI0_CLK CC1350DK_7XD_SPI0_CLK +#define Board_SPI0_CSN CC1350DK_7XD_SPI0_CSN #define Board_SPI1 CC1350DK_7XD_SPI1 +#define Board_SPI1_MISO CC1350DK_7XD_SPI1_MISO +#define Board_SPI1_MOSI CC1350DK_7XD_SPI1_MOSI +#define Board_SPI1_CLK CC1350DK_7XD_SPI1_CLK +#define Board_SPI1_CSN CC1350DK_7XD_SPI1_CSN #define Board_FLASH_CS_ON 0 #define Board_FLASH_CS_OFF 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Board.h index df2a32790..c42d3a169 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Board.h @@ -135,7 +135,15 @@ extern "C" { #define Board_SD0 CC2650DK_7ID_SDSPI0 #define Board_SPI0 CC2650DK_7ID_SPI0 +#define Board_SPI0_MISO CC2650DK_7ID_SPI0_MISO +#define Board_SPI0_MOSI CC2650DK_7ID_SPI0_MOSI +#define Board_SPI0_CLK CC2650DK_7ID_SPI0_CLK +#define Board_SPI0_CSN CC2650DK_7ID_SPI0_CSN #define Board_SPI1 CC2650DK_7ID_SPI1 +#define Board_SPI1_MISO CC2650DK_7ID_SPI1_MISO +#define Board_SPI1_MOSI CC2650DK_7ID_SPI1_MOSI +#define Board_SPI1_CLK CC2650DK_7ID_SPI1_CLK +#define Board_SPI1_CSN CC2650DK_7ID_SPI1_CSN #define Board_FLASH_CS_ON 0 #define Board_FLASH_CS_OFF 1 From aa5b5bce6d6be4f760917b20dae819a494735745 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Thu, 30 Aug 2018 17:17:09 +0200 Subject: [PATCH 323/485] Removed unecessary edits --- os/dev/button-hal.h | 1 - os/sys/cc.h | 6 ------ 2 files changed, 7 deletions(-) diff --git a/os/dev/button-hal.h b/os/dev/button-hal.h index 0be0c9d40..c1822ff8e 100644 --- a/os/dev/button-hal.h +++ b/os/dev/button-hal.h @@ -83,7 +83,6 @@ #include "dev/gpio-hal.h" #include "sys/clock.h" #include "sys/ctimer.h" -#include "sys/process.h" #include #include diff --git a/os/sys/cc.h b/os/sys/cc.h index cb9fb109d..6670eca46 100644 --- a/os/sys/cc.h +++ b/os/sys/cc.h @@ -103,8 +103,6 @@ #ifdef CC_CONF_ALIGN #define CC_ALIGN(n) CC_CONF_ALIGN(n) -#else -#define CC_ALIGN(n) #endif /* CC_CONF_INLINE */ /** @@ -147,10 +145,6 @@ #define ABS(n) (((n) < 0) ? -(n) : (n)) #endif -#ifndef CLAMP -#define CLAMP(v, vmin, vmax) (MAX(MIN(v, vmax), vmin)) -#endif - #define CC_CONCAT2(s1, s2) s1##s2 /** From d0124e3de7222fd20f9040ad5bed6d4a650f8a2d Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Fri, 31 Aug 2018 09:19:15 +0200 Subject: [PATCH 324/485] Reverting API change to GPIO HAL --- arch/cpu/cc2538/dev/gpio-hal-arch.c | 66 +++++---- arch/cpu/cc2538/dev/gpio-hal-arch.h | 7 +- arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c | 75 +++++----- arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h | 11 +- arch/cpu/native/dev/gpio-hal-arch.c | 8 +- .../dev/gpio-hal-arch.c | 128 ++++++------------ arch/platform/cc2538dk/dev/board-buttons.c | 11 +- .../launchpad/button-sensor-arch.c | 28 ++-- .../sensortag/button-sensor-arch.c | 42 +++--- .../cc13xx-cc26xx/srf06/button-sensor-arch.c | 70 +++++----- .../srf06-cc26xx/launchpad/board-buttons.c | 5 +- .../srf06-cc26xx/launchpad/cc1310/board.h | 4 +- .../srf06-cc26xx/launchpad/cc1350/board.h | 4 +- .../srf06-cc26xx/launchpad/cc2650/board.h | 4 +- .../srf06-cc26xx/sensortag/board-buttons.c | 10 +- .../srf06-cc26xx/sensortag/cc1350/board.h | 6 +- .../srf06-cc26xx/sensortag/cc2650/board.h | 6 +- .../srf06-cc26xx/srf06/board-buttons.c | 13 +- .../srf06-cc26xx/srf06/cc13xx/board.h | 10 +- .../srf06-cc26xx/srf06/cc26xx/board.h | 10 +- examples/dev/gpio-hal/gpio-hal-example.c | 6 +- .../platform-specific/cc26xx/cc26xx-demo.c | 6 +- .../cc26xx/cc26xx-web-demo/cc26xx-web-demo.h | 8 +- .../very-sleepy-demo/very-sleepy-demo.c | 2 +- os/dev/button-hal.c | 5 +- os/dev/gpio-hal.h | 81 +++-------- 26 files changed, 278 insertions(+), 348 deletions(-) diff --git a/arch/cpu/cc2538/dev/gpio-hal-arch.c b/arch/cpu/cc2538/dev/gpio-hal-arch.c index 14c992fe9..bd2dfb92d 100644 --- a/arch/cpu/cc2538/dev/gpio-hal-arch.c +++ b/arch/cpu/cc2538/dev/gpio-hal-arch.c @@ -57,35 +57,39 @@ gpio_hal_arch_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg) gpio_hal_pin_cfg_t tmp; - tmp = cfg & GPIO_HAL_PIN_BM_INT; - if(tmp == GPIO_HAL_PIN_CFG_INT_DISABLE) { + tmp = cfg & GPIO_HAL_PIN_CFG_EDGE_BOTH; + if(tmp == GPIO_HAL_PIN_CFG_EDGE_NONE) { GPIO_DISABLE_INTERRUPT(port_base, pin_mask); - } else { - if(tmp == GPIO_HAL_PIN_CFG_INT_RISING) { - GPIO_DETECT_EDGE(port_base, pin_mask); - GPIO_TRIGGER_SINGLE_EDGE(port_base, pin_mask); - GPIO_DETECT_RISING(port_base, pin_mask); - } else if(tmp == GPIO_HAL_PIN_CFG_INT_FALLING) { - GPIO_DETECT_EDGE(port_base, pin_mask); - GPIO_TRIGGER_SINGLE_EDGE(port_base, pin_mask); - GPIO_DETECT_FALLING(port_base, pin_mask); - } else if(tmp == GPIO_HAL_PIN_CFG_INT_BOTH) { - GPIO_DETECT_EDGE(port_base, pin_mask); - GPIO_TRIGGER_BOTH_EDGES(port_base, pin_mask); - } - GPIO_ENABLE_INTERRUPT(port_base, pin_mask); - NVIC_EnableIRQ(port); + } else if(tmp == GPIO_HAL_PIN_CFG_EDGE_RISING) { + GPIO_DETECT_EDGE(port_base, pin_mask); + GPIO_TRIGGER_SINGLE_EDGE(port_base, pin_mask); + GPIO_DETECT_RISING(port_base, pin_mask); + } else if(tmp == GPIO_HAL_PIN_CFG_EDGE_FALLING) { + GPIO_DETECT_EDGE(port_base, pin_mask); + GPIO_TRIGGER_SINGLE_EDGE(port_base, pin_mask); + GPIO_DETECT_FALLING(port_base, pin_mask); + } else if(tmp == GPIO_HAL_PIN_CFG_EDGE_BOTH) { + GPIO_DETECT_EDGE(port_base, pin_mask); + GPIO_TRIGGER_BOTH_EDGES(port_base, pin_mask); } - tmp = cfg & GPIO_HAL_PIN_BM_INPUT; - if(tmp == GPIO_HAL_PIN_CFG_INPUT_NOPULL) { + tmp = cfg & GPIO_HAL_PIN_CFG_PULL_MASK; + if(tmp == GPIO_HAL_PIN_CFG_PULL_NONE) { ioc_set_over(port, pin_num, IOC_OVERRIDE_DIS); - } else if(tmp == GPIO_HAL_PIN_CFG_INPUT_PULLDOWN) { + } else if(tmp == GPIO_HAL_PIN_CFG_PULL_DOWN) { ioc_set_over(port, pin_num, IOC_OVERRIDE_PDE); - } else if(tmp == GPIO_HAL_PIN_CFG_INPUT_PULLUP) { + } else if(tmp == GPIO_HAL_PIN_CFG_PULL_UP) { ioc_set_over(port, pin_num, IOC_OVERRIDE_PUE); } + tmp = cfg & GPIO_HAL_PIN_CFG_INT_MASK; + if(tmp == GPIO_HAL_PIN_CFG_INT_DISABLE) { + GPIO_DISABLE_INTERRUPT(port_base, pin_mask); + } else if(tmp == GPIO_HAL_PIN_CFG_INT_ENABLE) { + GPIO_ENABLE_INTERRUPT(port_base, pin_mask); + NVIC_EnableIRQ(port); + } + GPIO_SOFTWARE_CONTROL(port_base, pin_mask); } /*---------------------------------------------------------------------------*/ @@ -107,11 +111,11 @@ gpio_hal_arch_pin_cfg_get(gpio_hal_pin_t pin) /* Pull */ tmp = ioc_get_over(port, pin_num); if(tmp == IOC_OVERRIDE_PUE) { - cfg |= GPIO_HAL_PIN_CFG_INPUT_PULLUP; + cfg |= GPIO_HAL_PIN_CFG_PULL_UP; } else if(tmp == IOC_OVERRIDE_PDE) { - cfg |= GPIO_HAL_PIN_CFG_INPUT_PULLDOWN; + cfg |= GPIO_HAL_PIN_CFG_PULL_DOWN; } else { - cfg |= GPIO_HAL_PIN_CFG_INPUT_NOPULL; + cfg |= GPIO_HAL_PIN_CFG_PULL_NONE; } /* Interrupt enable/disable */ @@ -119,14 +123,20 @@ gpio_hal_arch_pin_cfg_get(gpio_hal_pin_t pin) if(tmp == 0) { cfg |= GPIO_HAL_PIN_CFG_INT_DISABLE; } else { - /* Edge detection */ + cfg |= GPIO_HAL_PIN_CFG_INT_ENABLE; + } + + /* Edge detection */ + if(REG((port_base) + GPIO_IS) & pin_mask) { + cfg |= GPIO_HAL_PIN_CFG_EDGE_NONE; + } else { if(REG((port_base) + GPIO_IBE) & pin_mask) { - cfg |= GPIO_HAL_PIN_CFG_INT_BOTH; + cfg |= GPIO_HAL_PIN_CFG_EDGE_BOTH; } else { if(REG((port_base) + GPIO_IEV) & pin_mask) { - cfg |= GPIO_HAL_PIN_CFG_INT_RISING; + cfg |= GPIO_HAL_PIN_CFG_EDGE_RISING; } else { - cfg |= GPIO_HAL_PIN_CFG_INT_FALLING; + cfg |= GPIO_HAL_PIN_CFG_EDGE_FALLING; } } } diff --git a/arch/cpu/cc2538/dev/gpio-hal-arch.h b/arch/cpu/cc2538/dev/gpio-hal-arch.h index 761a182a7..ad2f24219 100644 --- a/arch/cpu/cc2538/dev/gpio-hal-arch.h +++ b/arch/cpu/cc2538/dev/gpio-hal-arch.h @@ -56,12 +56,9 @@ #define PIN_TO_NUM(pin) (pin % 8) #define PIN_TO_PORT_BASE(pin) GPIO_PORT_TO_BASE(PIN_TO_PORT(pin)) /*---------------------------------------------------------------------------*/ -#define gpio_hal_arch_init() do { \ - /* do nothing */ \ -} while(0); +#define gpio_hal_arch_init() do { /* Do nothing */ } while(0) -#define gpio_hal_arch_interrupt_enable(p, cfg) do { \ - gpio_hal_arch_pin_cfg_set((p), (cfg) & GPIO_HAL_PIN_BM_INT); \ +#define gpio_hal_arch_interrupt_enable(p) do { \ GPIO_ENABLE_INTERRUPT(PIN_TO_PORT_BASE(p), GPIO_PIN_MASK((p) % 8)); \ NVIC_EnableIRQ(PIN_TO_PORT(p)); \ } while(0); diff --git a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c index 5f90529ed..a7b025800 100644 --- a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c +++ b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c @@ -47,18 +47,6 @@ #define CONFIG_MASK (IOC_IOPULL_M | IOC_INT_M | IOC_IOMODE_OPEN_SRC_INV) /*---------------------------------------------------------------------------*/ void -gpio_hal_arch_interrupt_enable(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg) -{ - gpio_hal_pin_cfg_t config = gpio_hal_arch_pin_cfg_get(pin); - config &= ~GPIO_HAL_PIN_BM_INT; - config |= cfg; - gpio_hal_arch_pin_cfg_set(pin, cfg); - - ti_lib_gpio_clear_event_dio(pin); - ti_lib_rom_ioc_int_enable(pin); -} -/*---------------------------------------------------------------------------*/ -void gpio_hal_arch_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg) { uint32_t config; @@ -68,26 +56,33 @@ gpio_hal_arch_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg) config = ti_lib_rom_ioc_port_configure_get(pin); config &= ~CONFIG_MASK; - tmp = cfg & GPIO_HAL_PIN_BM_INT; - if(tmp == GPIO_HAL_PIN_CFG_INT_DISABLE) { - config |= (IOC_NO_EDGE | IOC_INT_DISABLE); - } else if(tmp == GPIO_HAL_PIN_CFG_INT_RISING) { - config |= (IOC_RISING_EDGE | IOC_INT_ENABLE); - } else if(tmp == GPIO_HAL_PIN_CFG_INT_FALLING) { - config |= (IOC_FALLING_EDGE | IOC_INT_ENABLE); - } else if(tmp == GPIO_HAL_PIN_CFG_INT_BOTH) { - config |= (IOC_BOTH_EDGES | IOC_INT_ENABLE); + tmp = cfg & GPIO_HAL_PIN_CFG_EDGE_BOTH; + if(tmp == GPIO_HAL_PIN_CFG_EDGE_NONE) { + config |= IOC_NO_EDGE; + } else if(tmp == GPIO_HAL_PIN_CFG_EDGE_RISING) { + config |= IOC_RISING_EDGE; + } else if(tmp == GPIO_HAL_PIN_CFG_EDGE_FALLING) { + config |= IOC_FALLING_EDGE; + } else if(tmp == GPIO_HAL_PIN_CFG_EDGE_BOTH) { + config |= IOC_BOTH_EDGES; } - tmp = cfg & GPIO_HAL_PIN_BM_INPUT; - if(tmp == GPIO_HAL_PIN_CFG_INPUT_NOPULL) { + tmp = cfg & GPIO_HAL_PIN_CFG_PULL_MASK; + if(tmp == GPIO_HAL_PIN_CFG_PULL_NONE) { config |= IOC_NO_IOPULL; - } else if(tmp == GPIO_HAL_PIN_CFG_INPUT_PULLDOWN) { + } else if(tmp == GPIO_HAL_PIN_CFG_PULL_DOWN) { config |= IOC_IOPULL_DOWN; - } else if(tmp == GPIO_HAL_PIN_CFG_INPUT_PULLUP) { + } else if(tmp == GPIO_HAL_PIN_CFG_PULL_UP) { config |= IOC_IOPULL_UP; } + tmp = cfg & GPIO_HAL_PIN_CFG_INT_MASK; + if(tmp == GPIO_HAL_PIN_CFG_INT_DISABLE) { + config |= IOC_INT_DISABLE; + } else if(tmp == GPIO_HAL_PIN_CFG_INT_ENABLE) { + config |= IOC_INT_ENABLE; + } + ti_lib_rom_ioc_port_configure_set(pin, IOC_PORT_GPIO, config); } /*---------------------------------------------------------------------------*/ @@ -104,27 +99,31 @@ gpio_hal_arch_pin_cfg_get(gpio_hal_pin_t pin) /* Pull */ tmp = config & IOC_IOPULL_M; if(tmp == IOC_IOPULL_UP) { - cfg |= GPIO_HAL_PIN_CFG_INPUT_PULLUP; + cfg |= GPIO_HAL_PIN_CFG_PULL_UP; } else if(tmp == IOC_IOPULL_DOWN) { - cfg |= GPIO_HAL_PIN_CFG_INPUT_PULLDOWN; + cfg |= GPIO_HAL_PIN_CFG_PULL_DOWN; } else if(tmp == IOC_NO_IOPULL) { - cfg |= GPIO_HAL_PIN_CFG_INPUT_NOPULL; + cfg |= GPIO_HAL_PIN_CFG_PULL_NONE; } /* Interrupt enable/disable */ tmp = config & IOC_INT_ENABLE; if(tmp == IOC_INT_DISABLE) { cfg |= GPIO_HAL_PIN_CFG_INT_DISABLE; - } else { - /* Edge detection */ - tmp = config & IOC_BOTH_EDGES; - if(tmp == IOC_FALLING_EDGE) { - cfg |= GPIO_HAL_PIN_CFG_INT_FALLING; - } else if(tmp == IOC_RISING_EDGE) { - cfg |= GPIO_HAL_PIN_CFG_INT_RISING; - } else if(tmp == IOC_BOTH_EDGES) { - cfg |= GPIO_HAL_PIN_CFG_INT_BOTH; - } + } else if(tmp == IOC_INT_ENABLE) { + cfg |= GPIO_HAL_PIN_CFG_INT_ENABLE; + } + + /* Edge detection */ + tmp = config & IOC_BOTH_EDGES; + if(tmp == IOC_NO_EDGE) { + cfg |= GPIO_HAL_PIN_CFG_EDGE_NONE; + } else if(tmp == IOC_FALLING_EDGE) { + cfg |= GPIO_HAL_PIN_CFG_EDGE_FALLING; + } else if(tmp == IOC_RISING_EDGE) { + cfg |= GPIO_HAL_PIN_CFG_EDGE_RISING; + } else if(tmp == IOC_BOTH_EDGES) { + cfg |= GPIO_HAL_PIN_CFG_EDGE_BOTH; } return cfg; diff --git a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h index f24fa0828..65243df83 100644 --- a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h +++ b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h @@ -53,7 +53,9 @@ #include /*---------------------------------------------------------------------------*/ -#define gpio_hal_arch_init() do { /* do nothing */ } while (0) +#define gpio_hal_arch_init() do { /* Do nothing */ } while(0) + +#define gpio_hal_arch_interrupt_enable(p) interrupt_enable(p) #define gpio_hal_arch_interrupt_disable(p) ti_lib_rom_ioc_int_disable(p) #define gpio_hal_arch_pin_set_input(p) ti_lib_rom_ioc_pin_type_gpio_input(p) @@ -69,6 +71,13 @@ #define gpio_hal_arch_toggle_pins(p) ti_lib_gpio_toggle_multi_dio(p) #define gpio_hal_arch_write_pins(p, v) ti_lib_gpio_write_multi_dio(p, v) /*---------------------------------------------------------------------------*/ +static inline void +interrupt_enable(gpio_hal_pin_t pin) +{ + ti_lib_gpio_clear_event_dio(pin); + ti_lib_rom_ioc_int_enable(pin); +} +/*---------------------------------------------------------------------------*/ #endif /* GPIO_HAL_ARCH_H_ */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/cpu/native/dev/gpio-hal-arch.c b/arch/cpu/native/dev/gpio-hal-arch.c index bd6ad1842..366141d77 100644 --- a/arch/cpu/native/dev/gpio-hal-arch.c +++ b/arch/cpu/native/dev/gpio-hal-arch.c @@ -45,20 +45,18 @@ static uint8_t pin_state[GPIO_HAL_PIN_COUNT]; void gpio_hal_arch_init(void) { - LOG_DBG("Initialized\n"); + /* Do nothing */ } /*---------------------------------------------------------------------------*/ void -gpio_hal_arch_interrupt_enable(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg) +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; } - pin_cfg[pin] &= ~(gpio_hal_pin_cfg_t)GPIO_HAL_PIN_BM_INT; - pin_cfg[pin] |= cfg; - LOG_DBG("Pin %u: Enabled interrupt, config=0x%02x\n", pin, pin_cfg[pin]); + LOG_DBG("Pin %u: Enabled interrupt\n", pin); } /*---------------------------------------------------------------------------*/ void diff --git a/arch/cpu/simplelink-cc13xx-cc26xx/dev/gpio-hal-arch.c b/arch/cpu/simplelink-cc13xx-cc26xx/dev/gpio-hal-arch.c index 841627ec4..e219faa93 100644 --- a/arch/cpu/simplelink-cc13xx-cc26xx/dev/gpio-hal-arch.c +++ b/arch/cpu/simplelink-cc13xx-cc26xx/dev/gpio-hal-arch.c @@ -57,60 +57,36 @@ static PIN_Handle pin_handle; static void from_hal_cfg(gpio_hal_pin_cfg_t cfg, PIN_Config *pin_cfg, PIN_Config *pin_mask) { - cfg &= GPIO_HAL_PIN_BM_ALL; + /* Pulling config */ + *pin_mask |= PIN_BM_PULLING; - /* Input config */ - if(cfg & GPIO_HAL_PIN_BM_INPUT) { - *pin_mask |= PIN_BM_INPUT_MODE; - - /* Hysteresis config */ - if((cfg & GPIO_HAL_PIN_BM_INPUT_HYSTERESIS) == GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS) { - *pin_cfg |= PIN_HYSTERESIS; - } - - /* Pulling config */ - switch(cfg & GPIO_HAL_PIN_BM_INPUT_PULLING) { - case GPIO_HAL_PIN_CFG_INPUT_NOPULL: *pin_cfg |= PIN_NOPULL; break; - case GPIO_HAL_PIN_CFG_INPUT_PULLUP: *pin_cfg |= PIN_PULLUP; break; - case GPIO_HAL_PIN_CFG_INPUT_PULLDOWN: *pin_cfg |= PIN_PULLDOWN; break; - } + switch(cfg & GPIO_HAL_PIN_CFG_PULL_MASK) { + default: /* Default to no pullup/pulldown */ + case GPIO_HAL_PIN_CFG_PULL_NONE: *pin_cfg |= PIN_NOPULL; break; + case GPIO_HAL_PIN_CFG_PULL_UP: *pin_cfg |= PIN_PULLUP; break; + case GPIO_HAL_PIN_CFG_PULL_DOWN: *pin_cfg |= PIN_PULLDOWN; break; } - /* Output config */ - if(cfg & GPIO_HAL_PIN_BM_OUTPUT) { - *pin_mask |= PIN_BM_OUTPUT_MODE; + /* Hysteresis config */ + *pin_mask |= PIN_BM_HYSTERESIS; - /* Output buffer type config */ - switch(cfg & GPIO_HAL_PIN_BM_OUTPUT_BUF) { - case GPIO_HAL_PIN_CFG_OUTPUT_PUSHPULL: *pin_cfg |= PIN_PUSHPULL; break; - case GPIO_HAL_PIN_CFG_OUTPUT_OPENDRAIN: *pin_cfg |= PIN_OPENDRAIN; break; - case GPIO_HAL_PIN_CFG_OUTPUT_OPENSOURCE: *pin_cfg |= PIN_OPENSOURCE; break; - } - - /* Slew control config */ - if((cfg & GPIO_HAL_PIN_BM_OUTPUT_SLEWCTRL) == GPIO_HAL_PIN_CFG_OUTPUT_SLEWCTRL) { - *pin_cfg |= PIN_SLEWCTRL; - } - - /* Drive strength config */ - switch(cfg & GPIO_HAL_PIN_BM_OUTPUT_DRVSTR) { - case GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MIN: *pin_cfg |= PIN_DRVSTR_MIN; break; - case GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MED: *pin_cfg |= PIN_DRVSTR_MED; break; - case GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MAX: *pin_cfg |= PIN_DRVSTR_MAX; break; - } + if(cfg & GPIO_HAL_PIN_CFG_HYSTERESIS) { + *pin_cfg |= PIN_HYSTERESIS; } /* Interrupt config */ - if(cfg & GPIO_HAL_PIN_BM_INT) { - *pin_mask |= PIN_BM_IRQ; + *pin_mask |= PIN_BM_IRQ; + if((cfg & GPIO_HAL_PIN_CFG_INT_MASK) == GPIO_HAL_PIN_CFG_INT_ENABLE) { /* Interrupt edge config */ - switch(cfg & GPIO_HAL_PIN_BM_INT) { - case GPIO_HAL_PIN_CFG_INT_DISABLE: *pin_cfg |= PIN_IRQ_DIS; break; - case GPIO_HAL_PIN_CFG_INT_FALLING: *pin_cfg |= PIN_IRQ_NEGEDGE; break; - case GPIO_HAL_PIN_CFG_INT_RISING: *pin_cfg |= PIN_IRQ_POSEDGE; break; - case GPIO_HAL_PIN_CFG_INT_BOTH: *pin_cfg |= PIN_IRQ_BOTHEDGES; break; + switch(cfg & GPIO_HAL_PIN_CFG_EDGE_BOTH) { + case GPIO_HAL_PIN_CFG_EDGE_NONE: *pin_cfg |= PIN_IRQ_DIS; break; + case GPIO_HAL_PIN_CFG_EDGE_FALLING: *pin_cfg |= PIN_IRQ_NEGEDGE; break; + case GPIO_HAL_PIN_CFG_EDGE_RISING: *pin_cfg |= PIN_IRQ_POSEDGE; break; + case GPIO_HAL_PIN_CFG_EDGE_BOTH: *pin_cfg |= PIN_IRQ_BOTHEDGES; break; } + } else { + *pin_cfg |= PIN_IRQ_DIS; } } /*---------------------------------------------------------------------------*/ @@ -121,36 +97,14 @@ to_hal_cfg(PIN_Config pin_cfg, gpio_hal_pin_cfg_t *cfg) if(pin_cfg & PIN_BM_INPUT_MODE) { /* Hysteresis config */ if((pin_cfg & PIN_BM_HYSTERESIS) == PIN_HYSTERESIS) { - *cfg |= GPIO_HAL_PIN_BM_INPUT_HYSTERESIS; + *cfg |= GPIO_HAL_PIN_CFG_HYSTERESIS; } /* Pulling config */ switch(pin_cfg & PIN_BM_PULLING) { - case PIN_NOPULL: *cfg |= GPIO_HAL_PIN_CFG_INPUT_NOPULL; break; - case PIN_PULLUP: *cfg |= GPIO_HAL_PIN_CFG_INPUT_PULLUP; break; - case PIN_PULLDOWN: *cfg |= GPIO_HAL_PIN_CFG_INPUT_PULLDOWN; break; - } - } - - /* Output config */ - if(pin_cfg & PIN_BM_OUTPUT_MODE) { - /* Output buffer type config */ - switch(pin_cfg & PIN_BM_OUTPUT_BUF) { - case PIN_PUSHPULL: *cfg |= GPIO_HAL_PIN_CFG_OUTPUT_PUSHPULL; break; - case PIN_OPENDRAIN: *cfg |= GPIO_HAL_PIN_CFG_OUTPUT_OPENDRAIN; break; - case PIN_OPENSOURCE: *cfg |= GPIO_HAL_PIN_CFG_OUTPUT_OPENSOURCE; break; - } - - /* Slew control config */ - if((pin_cfg & PIN_BM_SLEWCTRL) == PIN_SLEWCTRL) { - *cfg |= GPIO_HAL_PIN_CFG_OUTPUT_SLEWCTRL; - } - - /* Drive strength config */ - switch(pin_cfg & PIN_BM_DRVSTR) { - case PIN_DRVSTR_MIN: *cfg |= GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MIN; break; - case PIN_DRVSTR_MED: *cfg |= GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MED; break; - case PIN_DRVSTR_MAX: *cfg |= GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MAX; break; + case PIN_NOPULL: *cfg |= GPIO_HAL_PIN_CFG_PULL_NONE; break; + case PIN_PULLUP: *cfg |= GPIO_HAL_PIN_CFG_PULL_UP; break; + case PIN_PULLDOWN: *cfg |= GPIO_HAL_PIN_CFG_PULL_DOWN; break; } } @@ -158,10 +112,18 @@ to_hal_cfg(PIN_Config pin_cfg, gpio_hal_pin_cfg_t *cfg) if(pin_cfg & PIN_BM_IRQ) { /* Interrupt edge config */ switch(pin_cfg & PIN_BM_IRQ) { - case PIN_IRQ_DIS: *cfg |= GPIO_HAL_PIN_CFG_INT_DISABLE; break; - case PIN_IRQ_NEGEDGE: *cfg |= GPIO_HAL_PIN_CFG_INT_FALLING; break; - case PIN_IRQ_POSEDGE: *cfg |= GPIO_HAL_PIN_CFG_INT_RISING; break; - case PIN_IRQ_BOTHEDGES: *cfg |= GPIO_HAL_PIN_CFG_INT_BOTH; break; + case PIN_IRQ_DIS: *cfg |= GPIO_HAL_PIN_CFG_EDGE_NONE; + *cfg |= GPIO_HAL_PIN_CFG_INT_DISABLE; + break; + case PIN_IRQ_NEGEDGE: *cfg |= GPIO_HAL_PIN_CFG_EDGE_FALLING; + *cfg |= GPIO_HAL_PIN_CFG_INT_ENABLE; + break; + case PIN_IRQ_POSEDGE: *cfg |= GPIO_HAL_PIN_CFG_EDGE_RISING; + *cfg |= GPIO_HAL_PIN_CFG_INT_ENABLE; + break; + case PIN_IRQ_BOTHEDGES: *cfg |= GPIO_HAL_PIN_CFG_EDGE_BOTH; + *cfg |= GPIO_HAL_PIN_CFG_INT_ENABLE; + break; } } } @@ -185,20 +147,16 @@ gpio_hal_arch_init(void) } /*---------------------------------------------------------------------------*/ void -gpio_hal_arch_interrupt_enable(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg) +gpio_hal_arch_interrupt_enable(gpio_hal_pin_t pin) { - PIN_add(pin_handle, PIN_getConfig(pin)); + PIN_Config pin_cfg; + PIN_Config irq_cfg; - cfg &= GPIO_HAL_PIN_BM_INT; + pin_cfg = PIN_getConfig(pin); + PIN_add(pin_handle, pin_cfg); - PIN_Config int_cfg = PIN_IRQ_DIS; - switch(cfg) { - case GPIO_HAL_PIN_CFG_INT_FALLING: int_cfg |= PIN_IRQ_NEGEDGE; break; - case GPIO_HAL_PIN_CFG_INT_RISING: int_cfg |= PIN_IRQ_POSEDGE; break; - case GPIO_HAL_PIN_CFG_INT_BOTH: int_cfg |= PIN_IRQ_BOTHEDGES; break; - } - - PIN_setInterrupt(pin_handle, pin | int_cfg); + irq_cfg = pin_cfg & PIN_BM_IRQ; + PIN_setInterrupt(pin_handle, pin | irq_cfg); } /*---------------------------------------------------------------------------*/ void diff --git a/arch/platform/cc2538dk/dev/board-buttons.c b/arch/platform/cc2538dk/dev/board-buttons.c index 5701d6f99..6afc915df 100644 --- a/arch/platform/cc2538dk/dev/board-buttons.c +++ b/arch/platform/cc2538dk/dev/board-buttons.c @@ -44,23 +44,22 @@ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "dev/button-hal.h" -#include "dev/gpio-hal.h" /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTON(key_left, "Key Left", \ GPIO_PORT_PIN_TO_GPIO_HAL_PIN(BUTTON_LEFT_PORT, BUTTON_LEFT_PIN), \ - GPIO_HAL_PIN_CFG_INPUT_PULLUP, BUTTON_HAL_ID_BUTTON_ZERO, true); + GPIO_HAL_PIN_CFG_PULL_UP, BUTTON_HAL_ID_BUTTON_ZERO, true); BUTTON_HAL_BUTTON(key_right, "Key Right", \ GPIO_PORT_PIN_TO_GPIO_HAL_PIN(BUTTON_RIGHT_PORT, BUTTON_RIGHT_PIN), \ - GPIO_HAL_PIN_CFG_INPUT_PULLUP, BUTTON_HAL_ID_BUTTON_ONE, true); + GPIO_HAL_PIN_CFG_PULL_UP, BUTTON_HAL_ID_BUTTON_ONE, true); BUTTON_HAL_BUTTON(key_up, "Key Up", \ GPIO_PORT_PIN_TO_GPIO_HAL_PIN(BUTTON_UP_PORT, BUTTON_UP_PIN), \ - GPIO_HAL_PIN_CFG_INPUT_PULLUP, BUTTON_HAL_ID_BUTTON_TWO, true); + GPIO_HAL_PIN_CFG_PULL_UP, BUTTON_HAL_ID_BUTTON_TWO, true); BUTTON_HAL_BUTTON(key_down, "Key Down", \ GPIO_PORT_PIN_TO_GPIO_HAL_PIN(BUTTON_DOWN_PORT, BUTTON_DOWN_PIN), \ - GPIO_HAL_PIN_CFG_INPUT_PULLUP, BUTTON_HAL_ID_BUTTON_THREE, true); + GPIO_HAL_PIN_CFG_PULL_UP, BUTTON_HAL_ID_BUTTON_THREE, true); BUTTON_HAL_BUTTON(key_select, "Key Select", \ GPIO_PORT_PIN_TO_GPIO_HAL_PIN(BUTTON_SELECT_PORT, BUTTON_SELECT_PIN), \ - GPIO_HAL_PIN_CFG_INPUT_PULLUP, BUTTON_HAL_ID_BUTTON_FOUR, true); + GPIO_HAL_PIN_CFG_PULL_UP, BUTTON_HAL_ID_BUTTON_FOUR, true); /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTONS(&key_left, &key_right, &key_up, &key_down, &key_select); /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c index 239869616..41bfef92e 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c @@ -45,23 +45,23 @@ /*---------------------------------------------------------------------------*/ /* Key left button, AKA BTN-1. */ BUTTON_HAL_BUTTON( - key_left, /**< Name */ - "Key Left", /**< Description */ - Board_PIN_BTN1, /**< Board PIN */ - GPIO_HAL_PIN_CFG_INPUT_PULLUP | - GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ - BUTTON_HAL_ID_KEY_LEFT, /**< Unique ID */ - true); /**< Negative logic */ + key_left, /**< Name */ + "Key Left", /**< Description */ + Board_PIN_BTN1, /**< Board PIN */ + GPIO_HAL_PIN_CFG_PULL_UP | + GPIO_HAL_PIN_CFG_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_KEY_LEFT, /**< Unique ID */ + true); /**< Negative logic */ /* Key right button, AKA BTN-2. */ BUTTON_HAL_BUTTON( - key_right, /**< Name */ - "Key Right", /**< Description */ - Board_PIN_BTN2, /**< Board PIN */ - GPIO_HAL_PIN_CFG_INPUT_PULLUP | - GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ - BUTTON_HAL_ID_KEY_RIGHT, /**< Unique ID */ - true); /**< Negative logic */ + key_right, /**< Name */ + "Key Right", /**< Description */ + Board_PIN_BTN2, /**< Board PIN */ + GPIO_HAL_PIN_CFG_PULL_UP | + GPIO_HAL_PIN_CFG_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_KEY_RIGHT, /**< Unique ID */ + true); /**< Negative logic */ /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTONS(&key_left, &key_right); /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor-arch.c index 63c177656..4b2ccba9b 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor-arch.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor-arch.c @@ -45,33 +45,33 @@ /*---------------------------------------------------------------------------*/ /* Key left button, AKA BTN-1 */ BUTTON_HAL_BUTTON( - key_left, /**< Name */ - "Key Left", /**< Description */ - Board_KEY_LEFT, /**< PIN */ - GPIO_HAL_PIN_CFG_INPUT_PULLUP | - GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ - BUTTON_HAL_ID_KEY_LEFT, /**< Unique ID */ - true); /**< Negative logic */ + key_left, /**< Name */ + "Key Left", /**< Description */ + Board_KEY_LEFT, /**< PIN */ + GPIO_HAL_PIN_CFG_PULL_UP | + GPIO_HAL_PIN_CFG_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_KEY_LEFT, /**< Unique ID */ + true); /**< Negative logic */ /* Key right button, AKA BTN-2 */ BUTTON_HAL_BUTTON( - key_right, /**< Name */ - "Key Right", /**< Description */ - Board_KEY_RIGHT, /**< PIN */ - GPIO_HAL_PIN_CFG_INPUT_PULLUP | - GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ - BUTTON_HAL_ID_KEY_RIGHT, /**< Unique ID */ - true); /**< Negative logic */ + key_right, /**< Name */ + "Key Right", /**< Description */ + Board_KEY_RIGHT, /**< PIN */ + GPIO_HAL_PIN_CFG_PULL_UP | + GPIO_HAL_PIN_CFG_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_KEY_RIGHT, /**< Unique ID */ + true); /**< Negative logic */ /* Reed Relay button */ BUTTON_HAL_BUTTON( - reed_relay, /**< Name */ - "Reed Relay", /**< Description */ - Board_RELAY, /**< PIN */ - GPIO_HAL_PIN_CFG_INPUT_PULLDOWN | - GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ - BUTTON_HAL_ID_REED_RELAY, /**< Unique ID */ - true); /**< Negative logic */ + reed_relay, /**< Name */ + "Reed Relay", /**< Description */ + Board_RELAY, /**< PIN */ + GPIO_HAL_PIN_CFG_PULL_DOWN | + GPIO_HAL_PIN_CFG_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_REED_RELAY, /**< Unique ID */ + true); /**< Negative logic */ /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTONS(&key_left, &key_right, &reed_relay); /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor-arch.c index 7c1f04df0..9c3df6abb 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor-arch.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor-arch.c @@ -45,53 +45,53 @@ /*---------------------------------------------------------------------------*/ /* Key select button */ BUTTON_HAL_BUTTON( - key_select, /**< Name */ - "Key Select", /**< Description */ - Board_KEY_SELECT, /**< PIN */ - GPIO_HAL_PIN_CFG_INPUT_PULLUP | - GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ - BUTTON_HAL_ID_KEY_SELECT, /**< Unique ID */ - true); /**< Negative logic */ + key_select, /**< Name */ + "Key Select", /**< Description */ + Board_KEY_SELECT, /**< PIN */ + GPIO_HAL_PIN_CFG_PULL_UP | + GPIO_HAL_PIN_CFG_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_KEY_SELECT, /**< Unique ID */ + true); /**< Negative logic */ /* Key up button */ BUTTON_HAL_BUTTON( - key_up, /**< Name */ - "Key Up", /**< Description */ - Board_KEY_UP, /**< PIN */ - GPIO_HAL_PIN_CFG_INPUT_PULLUP | - GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ - BUTTON_HAL_ID_KEY_UP, /**< Unique ID */ - true); /**< Negative logic */ + key_up, /**< Name */ + "Key Up", /**< Description */ + Board_KEY_UP, /**< PIN */ + GPIO_HAL_PIN_CFG_PULL_UP | + GPIO_HAL_PIN_CFG_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_KEY_UP, /**< Unique ID */ + true); /**< Negative logic */ /* Key down button */ BUTTON_HAL_BUTTON( - key_down, /**< Name */ - "Key Down", /**< Description */ - Board_KEY_DOWN, /**< PIN */ - GPIO_HAL_PIN_CFG_INPUT_PULLUP | - GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ - BUTTON_HAL_ID_KEY_DOWN, /**< Unique ID */ - true); /**< Negative logic */ + key_down, /**< Name */ + "Key Down", /**< Description */ + Board_KEY_DOWN, /**< PIN */ + GPIO_HAL_PIN_CFG_PULL_UP | + GPIO_HAL_PIN_CFG_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_KEY_DOWN, /**< Unique ID */ + true); /**< Negative logic */ /* Key left button */ BUTTON_HAL_BUTTON( - key_left, /**< Name */ - "Key Left", /**< Description */ - Board_KEY_LEFT, /**< PIN */ - GPIO_HAL_PIN_CFG_INPUT_PULLUP | - GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ - BUTTON_HAL_ID_KEY_LEFT, /**< Unique ID */ - true); /**< Negative logic */ + key_left, /**< Name */ + "Key Left", /**< Description */ + Board_KEY_LEFT, /**< PIN */ + GPIO_HAL_PIN_CFG_PULL_UP | + GPIO_HAL_PIN_CFG_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_KEY_LEFT, /**< Unique ID */ + true); /**< Negative logic */ /* Key right button */ BUTTON_HAL_BUTTON( - key_right, /**< Name */ - "Key Right", /**< Description */ - Board_KEY_RIGHT, /**< PIN */ - GPIO_HAL_PIN_CFG_INPUT_PULLUP | - GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ - BUTTON_HAL_ID_KEY_RIGHT, /**< Unique ID */ - true); /**< Negative logic */ + key_right, /**< Name */ + "Key Right", /**< Description */ + Board_KEY_RIGHT, /**< PIN */ + GPIO_HAL_PIN_CFG_PULL_UP | + GPIO_HAL_PIN_CFG_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_KEY_RIGHT, /**< Unique ID */ + true); /**< Negative logic */ /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTONS(&key_select, &key_up, &key_down, &key_left, &key_right); /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/srf06-cc26xx/launchpad/board-buttons.c b/arch/platform/srf06-cc26xx/launchpad/board-buttons.c index 0fa6907c6..f07fff09e 100644 --- a/arch/platform/srf06-cc26xx/launchpad/board-buttons.c +++ b/arch/platform/srf06-cc26xx/launchpad/board-buttons.c @@ -39,16 +39,15 @@ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "dev/button-hal.h" -#include "dev/gpio-hal.h" #include "ti-lib.h" /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTON(key_left, "Key Left", BOARD_IOID_KEY_LEFT, \ - GPIO_HAL_PIN_CFG_INPUT_PULLUP, BUTTON_HAL_ID_KEY_LEFT, \ + GPIO_HAL_PIN_CFG_PULL_UP, BOARD_BUTTON_HAL_INDEX_KEY_LEFT, \ true); BUTTON_HAL_BUTTON(key_right, "Key Right", BOARD_IOID_KEY_RIGHT, \ - GPIO_HAL_PIN_CFG_INPUT_PULLUP, BUTTON_HAL_ID_KEY_RIGHT, \ + GPIO_HAL_PIN_CFG_PULL_UP, BOARD_BUTTON_HAL_INDEX_KEY_RIGHT, \ true); /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTONS(&key_left, &key_right); diff --git a/arch/platform/srf06-cc26xx/launchpad/cc1310/board.h b/arch/platform/srf06-cc26xx/launchpad/cc1310/board.h index 2363ccf79..41e929571 100644 --- a/arch/platform/srf06-cc26xx/launchpad/cc1310/board.h +++ b/arch/platform/srf06-cc26xx/launchpad/cc1310/board.h @@ -198,8 +198,8 @@ * Those values are not meant to be modified by the user * @{ */ -#define BUTTON_HAL_ID_KEY_LEFT 0x00 -#define BUTTON_HAL_ID_KEY_RIGHT 0x01 +#define BOARD_BUTTON_HAL_INDEX_KEY_LEFT 0x00 +#define BOARD_BUTTON_HAL_INDEX_KEY_RIGHT 0x01 /** @} */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/srf06-cc26xx/launchpad/cc1350/board.h b/arch/platform/srf06-cc26xx/launchpad/cc1350/board.h index cca7e0b1a..643d69e0b 100644 --- a/arch/platform/srf06-cc26xx/launchpad/cc1350/board.h +++ b/arch/platform/srf06-cc26xx/launchpad/cc1350/board.h @@ -214,8 +214,8 @@ * Those values are not meant to be modified by the user * @{ */ -#define BUTTON_HAL_ID_KEY_LEFT 0x00 -#define BUTTON_HAL_ID_KEY_RIGHT 0x01 +#define BOARD_BUTTON_HAL_INDEX_KEY_LEFT 0x00 +#define BOARD_BUTTON_HAL_INDEX_KEY_RIGHT 0x01 /** @} */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/srf06-cc26xx/launchpad/cc2650/board.h b/arch/platform/srf06-cc26xx/launchpad/cc2650/board.h index 5ea73c692..822e776b8 100644 --- a/arch/platform/srf06-cc26xx/launchpad/cc2650/board.h +++ b/arch/platform/srf06-cc26xx/launchpad/cc2650/board.h @@ -199,8 +199,8 @@ * Those values are not meant to be modified by the user * @{ */ -#define BUTTON_HAL_ID_KEY_LEFT 0x00 -#define BUTTON_HAL_ID_KEY_RIGHT 0x01 +#define BOARD_BUTTON_HAL_INDEX_KEY_LEFT 0x00 +#define BOARD_BUTTON_HAL_INDEX_KEY_RIGHT 0x01 /** @} */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/srf06-cc26xx/sensortag/board-buttons.c b/arch/platform/srf06-cc26xx/sensortag/board-buttons.c index bdf481359..4a1b02ed5 100644 --- a/arch/platform/srf06-cc26xx/sensortag/board-buttons.c +++ b/arch/platform/srf06-cc26xx/sensortag/board-buttons.c @@ -38,23 +38,23 @@ */ /*---------------------------------------------------------------------------*/ #include "contiki.h" -#include "dev/button-hal.h" #include "dev/gpio-hal.h" +#include "dev/button-hal.h" #include "ti-lib.h" #include /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTON(reed_relay, "Reed Relay", BOARD_IOID_REED_RELAY, \ - GPIO_HAL_PIN_CFG_INPUT_PULLDOWN, \ - BUTTON_HAL_ID_REED_RELAY, true); + GPIO_HAL_PIN_CFG_PULL_DOWN, \ + BOARD_BUTTON_HAL_INDEX_REED_RELAY, true); BUTTON_HAL_BUTTON(key_left, "Key Left", BOARD_IOID_KEY_LEFT, \ - GPIO_HAL_PIN_CFG_INPUT_PULLUP, BUTTON_HAL_ID_KEY_LEFT, \ + GPIO_HAL_PIN_CFG_PULL_UP, BOARD_BUTTON_HAL_INDEX_KEY_LEFT, \ true); BUTTON_HAL_BUTTON(key_right, "Key Right", BOARD_IOID_KEY_RIGHT, \ - GPIO_HAL_PIN_CFG_INPUT_PULLUP, BUTTON_HAL_ID_KEY_RIGHT, \ + GPIO_HAL_PIN_CFG_PULL_UP, BOARD_BUTTON_HAL_INDEX_KEY_RIGHT, \ true); /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTONS(&reed_relay, &key_left, &key_right); diff --git a/arch/platform/srf06-cc26xx/sensortag/cc1350/board.h b/arch/platform/srf06-cc26xx/sensortag/cc1350/board.h index 140838605..6fdab1295 100644 --- a/arch/platform/srf06-cc26xx/sensortag/cc1350/board.h +++ b/arch/platform/srf06-cc26xx/sensortag/cc1350/board.h @@ -248,9 +248,9 @@ * Those values are not meant to be modified by the user * @{ */ -#define BUTTON_HAL_ID_KEY_LEFT 0x00 -#define BUTTON_HAL_ID_KEY_RIGHT 0x01 -#define BUTTON_HAL_ID_REED_RELAY 0xFF +#define BOARD_BUTTON_HAL_INDEX_KEY_LEFT 0x00 +#define BOARD_BUTTON_HAL_INDEX_KEY_RIGHT 0x01 +#define BOARD_BUTTON_HAL_INDEX_REED_RELAY 0xFF /** @} */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/srf06-cc26xx/sensortag/cc2650/board.h b/arch/platform/srf06-cc26xx/sensortag/cc2650/board.h index d0109db42..dda3e46e5 100644 --- a/arch/platform/srf06-cc26xx/sensortag/cc2650/board.h +++ b/arch/platform/srf06-cc26xx/sensortag/cc2650/board.h @@ -229,9 +229,9 @@ * Those values are not meant to be modified by the user * @{ */ -#define BUTTON_HAL_ID_KEY_LEFT 0x00 -#define BUTTON_HAL_ID_KEY_RIGHT 0x01 -#define BUTTON_HAL_ID_REED_RELAY 0xFF +#define BOARD_BUTTON_HAL_INDEX_KEY_LEFT 0x00 +#define BOARD_BUTTON_HAL_INDEX_KEY_RIGHT 0x01 +#define BOARD_BUTTON_HAL_INDEX_REED_RELAY 0xFF /** @} */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/srf06-cc26xx/srf06/board-buttons.c b/arch/platform/srf06-cc26xx/srf06/board-buttons.c index 68562f15a..c0db8daaa 100644 --- a/arch/platform/srf06-cc26xx/srf06/board-buttons.c +++ b/arch/platform/srf06-cc26xx/srf06/board-buttons.c @@ -39,25 +39,24 @@ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "dev/button-hal.h" -#include "dev/gpio-hal.h" #include "ti-lib.h" /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTON(key_left, "Key Left", BOARD_IOID_KEY_LEFT, \ - GPIO_HAL_PIN_CFG_INPUT_PULLUP, BUTTON_HAL_ID_KEY_LEFT, \ + GPIO_HAL_PIN_CFG_PULL_UP, BOARD_BUTTON_HAL_INDEX_KEY_LEFT, \ true); BUTTON_HAL_BUTTON(key_right, "Key Right", BOARD_IOID_KEY_RIGHT, \ - GPIO_HAL_PIN_CFG_INPUT_PULLUP, BUTTON_HAL_ID_KEY_RIGHT, \ + GPIO_HAL_PIN_CFG_PULL_UP, BOARD_BUTTON_HAL_INDEX_KEY_RIGHT, \ true); BUTTON_HAL_BUTTON(key_up, "Key Up", BOARD_IOID_KEY_UP, \ - GPIO_HAL_PIN_CFG_INPUT_PULLUP, BUTTON_HAL_ID_KEY_UP, \ + GPIO_HAL_PIN_CFG_PULL_UP, BOARD_BUTTON_HAL_INDEX_KEY_UP, \ true); BUTTON_HAL_BUTTON(key_down, "Key Down", BOARD_IOID_KEY_DOWN, \ - GPIO_HAL_PIN_CFG_INPUT_PULLUP, BUTTON_HAL_ID_KEY_DOWN, \ + GPIO_HAL_PIN_CFG_PULL_UP, BOARD_BUTTON_HAL_INDEX_KEY_DOWN, \ true); BUTTON_HAL_BUTTON(key_select, "Key Select", BOARD_IOID_KEY_SELECT, \ - GPIO_HAL_PIN_CFG_INPUT_PULLUP, \ - BUTTON_HAL_ID_KEY_SELECT, true); + GPIO_HAL_PIN_CFG_PULL_UP, \ + BOARD_BUTTON_HAL_INDEX_KEY_SELECT, true); /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTONS(&key_left, &key_right, &key_up, &key_down, &key_select); /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/srf06-cc26xx/srf06/cc13xx/board.h b/arch/platform/srf06-cc26xx/srf06/cc13xx/board.h index 431aac628..9fece9180 100644 --- a/arch/platform/srf06-cc26xx/srf06/cc13xx/board.h +++ b/arch/platform/srf06-cc26xx/srf06/cc13xx/board.h @@ -238,11 +238,11 @@ * Those values are not meant to be modified by the user * @{ */ -#define BUTTON_HAL_ID_KEY_LEFT 0x00 -#define BUTTON_HAL_ID_KEY_RIGHT 0x01 -#define BUTTON_HAL_ID_KEY_UP 0x02 -#define BUTTON_HAL_ID_KEY_DOWN 0x03 -#define BUTTON_HAL_ID_KEY_SELECT 0x04 +#define BOARD_BUTTON_HAL_INDEX_KEY_LEFT 0x00 +#define BOARD_BUTTON_HAL_INDEX_KEY_RIGHT 0x01 +#define BOARD_BUTTON_HAL_INDEX_KEY_UP 0x02 +#define BOARD_BUTTON_HAL_INDEX_KEY_DOWN 0x03 +#define BOARD_BUTTON_HAL_INDEX_KEY_SELECT 0x04 /** @} */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/srf06-cc26xx/srf06/cc26xx/board.h b/arch/platform/srf06-cc26xx/srf06/cc26xx/board.h index 39db0374f..b9171388a 100644 --- a/arch/platform/srf06-cc26xx/srf06/cc26xx/board.h +++ b/arch/platform/srf06-cc26xx/srf06/cc26xx/board.h @@ -238,11 +238,11 @@ * Those values are not meant to be modified by the user * @{ */ -#define BUTTON_HAL_ID_KEY_LEFT 0x00 -#define BUTTON_HAL_ID_KEY_RIGHT 0x01 -#define BUTTON_HAL_ID_KEY_UP 0x02 -#define BUTTON_HAL_ID_KEY_DOWN 0x03 -#define BUTTON_HAL_ID_KEY_SELECT 0x04 +#define BOARD_BUTTON_HAL_INDEX_KEY_LEFT 0x00 +#define BOARD_BUTTON_HAL_INDEX_KEY_RIGHT 0x01 +#define BOARD_BUTTON_HAL_INDEX_KEY_UP 0x02 +#define BOARD_BUTTON_HAL_INDEX_KEY_DOWN 0x03 +#define BOARD_BUTTON_HAL_INDEX_KEY_SELECT 0x04 /** @} */ /*---------------------------------------------------------------------------*/ /** diff --git a/examples/dev/gpio-hal/gpio-hal-example.c b/examples/dev/gpio-hal/gpio-hal-example.c index aa6a063d7..380c06388 100644 --- a/examples/dev/gpio-hal/gpio-hal-example.c +++ b/examples/dev/gpio-hal/gpio-hal-example.c @@ -115,11 +115,11 @@ PROCESS_THREAD(gpio_hal_example, ev, data) gpio_hal_pin_cfg_t interrupt; interrupt = gpio_hal_arch_pin_cfg_get(btn_pin) & - GPIO_HAL_PIN_BM_INT; + GPIO_HAL_PIN_CFG_INT_ENABLE; - if(interrupt != GPIO_HAL_PIN_CFG_INT_DISABLE) { + if(interrupt == 0) { printf("Enabling button interrupt\n"); - gpio_hal_arch_interrupt_enable(btn_pin, GPIO_HAL_PIN_CFG_INT_BOTH); + gpio_hal_arch_interrupt_enable(btn_pin); } else { printf("Disabling button interrupt\n"); gpio_hal_arch_interrupt_disable(btn_pin); diff --git a/examples/platform-specific/cc26xx/cc26xx-demo.c b/examples/platform-specific/cc26xx/cc26xx-demo.c index acc3ca823..8c90905af 100644 --- a/examples/platform-specific/cc26xx/cc26xx-demo.c +++ b/examples/platform-specific/cc26xx/cc26xx-demo.c @@ -98,11 +98,11 @@ #define CC26XX_DEMO_LEDS_BUTTON LEDS_RED #define CC26XX_DEMO_LEDS_REBOOT LEDS_ALL /*---------------------------------------------------------------------------*/ -#define CC26XX_DEMO_TRIGGER_1 BUTTON_HAL_ID_KEY_LEFT -#define CC26XX_DEMO_TRIGGER_2 BUTTON_HAL_ID_KEY_RIGHT +#define CC26XX_DEMO_TRIGGER_1 BOARD_BUTTON_HAL_INDEX_KEY_LEFT +#define CC26XX_DEMO_TRIGGER_2 BOARD_BUTTON_HAL_INDEX_KEY_RIGHT #if BOARD_SENSORTAG -#define CC26XX_DEMO_TRIGGER_3 BUTTON_HAL_ID_REED_RELAY +#define CC26XX_DEMO_TRIGGER_3 BOARD_BUTTON_HAL_INDEX_REED_RELAY #endif /*---------------------------------------------------------------------------*/ static struct etimer et; diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/cc26xx-web-demo.h b/examples/platform-specific/cc26xx/cc26xx-web-demo/cc26xx-web-demo.h index 1840c31b1..0761725c7 100644 --- a/examples/platform-specific/cc26xx/cc26xx-web-demo/cc26xx-web-demo.h +++ b/examples/platform-specific/cc26xx/cc26xx-web-demo/cc26xx-web-demo.h @@ -98,18 +98,18 @@ /*---------------------------------------------------------------------------*/ /* User configuration */ /* Take a sensor reading on button press */ -#define CC26XX_WEB_DEMO_SENSOR_READING_TRIGGER BUTTON_HAL_ID_KEY_LEFT +#define CC26XX_WEB_DEMO_SENSOR_READING_TRIGGER BOARD_BUTTON_HAL_INDEX_KEY_LEFT /* Payload length of ICMPv6 echo requests used to measure RSSI with def rt */ #define CC26XX_WEB_DEMO_ECHO_REQ_PAYLOAD_LEN 20 #if BOARD_SENSORTAG /* Force an MQTT publish on sensor event */ -#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BUTTON_HAL_ID_REED_RELAY +#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BOARD_BUTTON_HAL_INDEX_REED_RELAY #elif BOARD_LAUNCHPAD -#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BUTTON_HAL_ID_KEY_LEFT +#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BOARD_BUTTON_HAL_INDEX_KEY_LEFT #else -#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BUTTON_HAL_ID_KEY_DOWN +#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BOARD_BUTTON_HAL_INDEX_KEY_DOWN #endif #define CC26XX_WEB_DEMO_STATUS_LED LEDS_GREEN 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 d707f3cd1..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 @@ -63,7 +63,7 @@ #define VERY_SLEEPY_MODE_OFF 0 #define VERY_SLEEPY_MODE_ON 1 /*---------------------------------------------------------------------------*/ -#define BUTTON_TRIGGER BUTTON_HAL_ID_KEY_LEFT +#define BUTTON_TRIGGER BOARD_BUTTON_HAL_INDEX_KEY_LEFT /*---------------------------------------------------------------------------*/ #define MAC_CAN_BE_TURNED_OFF 0 #define MAC_MUST_STAY_ON 1 diff --git a/os/dev/button-hal.c b/os/dev/button-hal.c index a1255e7f7..58cded790 100644 --- a/os/dev/button-hal.c +++ b/os/dev/button-hal.c @@ -178,10 +178,11 @@ button_hal_init() button_event_handler.handler = press_release_handler; for(button = button_hal_buttons; *button != NULL; button++) { - cfg = (*button)->pull; + cfg = GPIO_HAL_PIN_CFG_EDGE_BOTH | GPIO_HAL_PIN_CFG_INT_ENABLE | + (*button)->pull; gpio_hal_arch_pin_set_input((*button)->pin); gpio_hal_arch_pin_cfg_set((*button)->pin, cfg); - gpio_hal_arch_interrupt_enable((*button)->pin, GPIO_HAL_PIN_CFG_INT_BOTH); + gpio_hal_arch_interrupt_enable((*button)->pin); button_event_handler.pin_mask |= gpio_hal_pin_to_mask((*button)->pin); } diff --git a/os/dev/gpio-hal.h b/os/dev/gpio-hal.h index 49b4e5344..9fe541772 100644 --- a/os/dev/gpio-hal.h +++ b/os/dev/gpio-hal.h @@ -74,7 +74,7 @@ /** * \brief GPIO pin number representation */ -typedef uint_fast8_t gpio_hal_pin_t; +typedef uint8_t gpio_hal_pin_t; /** * \brief GPIO pin configuration @@ -82,7 +82,7 @@ typedef uint_fast8_t gpio_hal_pin_t; * A logical representation of a pin's configuration. It is an OR combination * of GPIO_HAL_PIN_CFG_xyz macros. */ -typedef uint_least32_t gpio_hal_pin_cfg_t; +typedef uint32_t gpio_hal_pin_cfg_t; #ifdef GPIO_HAL_CONF_PIN_COUNT #define GPIO_HAL_PIN_COUNT GPIO_HAL_CONF_PIN_COUNT @@ -90,73 +90,34 @@ typedef uint_least32_t gpio_hal_pin_cfg_t; #define GPIO_HAL_PIN_COUNT 32 #endif +#if GPIO_HAL_PIN_COUNT > 32 +typedef uint64_t gpio_hal_pin_mask_t; +#else /** * \brief GPIO pin mask representation */ -#if GPIO_HAL_PIN_COUNT > 32 -typedef uint_least64_t gpio_hal_pin_mask_t; -#else -typedef uint_least32_t gpio_hal_pin_mask_t; +typedef uint32_t gpio_hal_pin_mask_t; #endif typedef void (*gpio_hal_callback_t)(gpio_hal_pin_mask_t pin_mask); /*---------------------------------------------------------------------------*/ -/* - * Configuration bits - * bit 8 -> bit 0 -> - * xxxxxxff eedccbba - * - * Input config: - * a - 1 bit - hystersis - * b - 2 bits - pulling - * - * Output config: - * c - 2 bits - output buffer - * d - 1 bit - slew control - * e - 2 bits - drive strength - * - * Interrupt config: - * f - 2 bits - interrupt mode - * - * Unused config: - * x: unused - */ +#define GPIO_HAL_PIN_CFG_PULL_NONE 0x00 +#define GPIO_HAL_PIN_CFG_PULL_UP 0x01 +#define GPIO_HAL_PIN_CFG_PULL_DOWN 0x02 +#define GPIO_HAL_PIN_CFG_PULL_MASK (GPIO_HAL_PIN_CFG_PULL_UP | \ + GPIO_HAL_PIN_CFG_PULL_DOWN) -#define GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS (1 << 0) -#define GPIO_HAL_PIN_CFG_INPUT_NOPULL (0 << 1) -#define GPIO_HAL_PIN_CFG_INPUT_PULLUP (1 << 1) -#define GPIO_HAL_PIN_CFG_INPUT_PULLDOWN (2 << 1) +#define GPIO_HAL_PIN_CFG_HYSTERESIS 0x10 -#define GPIO_HAL_PIN_BM_INPUT_HYSTERESIS (0x01 << 0) /**< 0b00000001 */ -#define GPIO_HAL_PIN_BM_INPUT_PULLING (0x06 << 0) /**< 0b00000110 */ -#define GPIO_HAL_PIN_BM_INPUT ( GPIO_HAL_PIN_BM_INPUT_HYSTERESIS \ - | GPIO_HAL_PIN_BM_INPUT_PULLING) +#define GPIO_HAL_PIN_CFG_EDGE_NONE 0x00 +#define GPIO_HAL_PIN_CFG_EDGE_RISING 0x04 +#define GPIO_HAL_PIN_CFG_EDGE_FALLING 0x08 +#define GPIO_HAL_PIN_CFG_EDGE_BOTH (GPIO_HAL_PIN_CFG_EDGE_RISING | \ + GPIO_HAL_PIN_CFG_EDGE_FALLING) -#define GPIO_HAL_PIN_CFG_OUTPUT_PUSHPULL (0 << 3) -#define GPIO_HAL_PIN_CFG_OUTPUT_OPENDRAIN (1 << 3) -#define GPIO_HAL_PIN_CFG_OUTPUT_OPENSOURCE (2 << 3) -#define GPIO_HAL_PIN_CFG_OUTPUT_SLEWCTRL (1 << 5) -#define GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MIN (0 << 6) -#define GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MED (1 << 6) -#define GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MAX (2 << 6) - -#define GPIO_HAL_PIN_BM_OUTPUT_BUF (0x18 << 0) /**< 0b00011000 */ -#define GPIO_HAL_PIN_BM_OUTPUT_SLEWCTRL (0x20 << 0) /**< 0b00100000 */ -#define GPIO_HAL_PIN_BM_OUTPUT_DRVSTR (0xC0 << 0) /**< 0b11000000 */ -#define GPIO_HAL_PIN_BM_OUTPUT ( GPIO_HAL_PIN_BM_OUTPUT_BUF \ - | GPIO_HAL_PIN_BM_OUTPUT_SLEWCTRL \ - | GPIO_HAL_PIN_BM_OUTPUT_DRVSTR) - -#define GPIO_HAL_PIN_CFG_INT_DISABLE (0 << 8) -#define GPIO_HAL_PIN_CFG_INT_FALLING (1 << 8) -#define GPIO_HAL_PIN_CFG_INT_RISING (2 << 8) -#define GPIO_HAL_PIN_CFG_INT_BOTH (3 << 8) - -#define GPIO_HAL_PIN_BM_INT (0x03 << 8) /**< 0b00000011 */ - -#define GPIO_HAL_PIN_BM_ALL ( GPIO_HAL_PIN_BM_INPUT \ - | GPIO_HAL_PIN_BM_OUTPUT \ - | GPIO_HAL_PIN_BM_INT) +#define GPIO_HAL_PIN_CFG_INT_DISABLE 0x00 +#define GPIO_HAL_PIN_CFG_INT_ENABLE 0x80 +#define GPIO_HAL_PIN_CFG_INT_MASK 0x80 /*---------------------------------------------------------------------------*/ /** * \brief Datatype for GPIO event handlers @@ -296,7 +257,7 @@ void gpio_hal_arch_init(void); * The implementation can be provided as a global symbol, an inline function * or a function-like macro, as described above. */ -void gpio_hal_arch_interrupt_enable(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg); +void gpio_hal_arch_interrupt_enable(gpio_hal_pin_t pin); #endif /*---------------------------------------------------------------------------*/ #ifndef gpio_hal_arch_interrupt_disable From c8edacdd6dc8c2db364c846637ca8bb2dd47fde3 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Fri, 31 Aug 2018 10:56:41 +0200 Subject: [PATCH 325/485] Added doxygen exclude of Core SDK --- tools/doxygen/Doxyfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/doxygen/Doxyfile b/tools/doxygen/Doxyfile index a7dc79fab..db2efa697 100644 --- a/tools/doxygen/Doxyfile +++ b/tools/doxygen/Doxyfile @@ -809,6 +809,10 @@ EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = */cpu/cc26xx-cc13xx/lib/* \ */cpu/cc26xx-cc13xx/rf-core/api/* \ + */cpu/cc13xx-cc26xx/lib/* \ + */cpu/cc13xx-cc26xx/rf-settings/* \ + */cpu/cc13xx-cc26xx/cc13x0-cc26x0/driverlib/* \ + */cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf_patches/* \ */platform/stm32nucleo-spirit1/stm32cube-lib/* \ */os/net/security/tinydtls/* From 322b6b26d2ba0c79c7913430416ded9ffa4a565a Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Fri, 31 Aug 2018 10:58:24 +0200 Subject: [PATCH 326/485] Added simplelink PLATFORMS_ONLY/EXCLUDE to examples --- examples/6tisch/6p-packet/Makefile | 2 +- examples/6tisch/etsi-plugtest-2017/Makefile | 2 +- examples/6tisch/simple-node/Makefile | 2 +- examples/6tisch/sixtop/Makefile | 2 +- examples/dev/button-hal/Makefile | 2 +- examples/dev/gpio-hal/Makefile | 2 +- examples/mqtt-client/Makefile | 2 +- examples/sensniff/Makefile | 2 +- .../pool/simplelink-cc13xx-cc26xx-io.h | 43 +++++++++++++++++++ examples/sensniff/simplelink/target-conf.h | 40 +++++++++++++++++ 10 files changed, 91 insertions(+), 8 deletions(-) create mode 100644 examples/sensniff/pool/simplelink-cc13xx-cc26xx-io.h create mode 100644 examples/sensniff/simplelink/target-conf.h diff --git a/examples/6tisch/6p-packet/Makefile b/examples/6tisch/6p-packet/Makefile index 7dcf9ccd3..ac92805ae 100644 --- a/examples/6tisch/6p-packet/Makefile +++ b/examples/6tisch/6p-packet/Makefile @@ -1,7 +1,7 @@ CONTIKI_PROJECT = sixp-node PROJECT_SOURCEFILES += test-sf.c -PLATFORMS_EXCLUDE = sky nrf52dk native +PLATFORMS_EXCLUDE = sky nrf52dk native simplelink BOARDS_EXCLUDE = srf06/cc13xx launchpad/cc1310 launchpad/cc1350 sensortag/cc2650 sensortag/cc1350 CONTIKI = ../../../ diff --git a/examples/6tisch/etsi-plugtest-2017/Makefile b/examples/6tisch/etsi-plugtest-2017/Makefile index 3279b6ebc..b5aeb66f5 100644 --- a/examples/6tisch/etsi-plugtest-2017/Makefile +++ b/examples/6tisch/etsi-plugtest-2017/Makefile @@ -1,7 +1,7 @@ CONTIKI_PROJECT = node all: $(CONTIKI_PROJECT) -PLATFORMS_EXCLUDE = sky nrf52dk native +PLATFORMS_EXCLUDE = sky nrf52dk native simplelink BOARDS_EXCLUDE = srf06/cc13xx launchpad/cc1310 launchpad/cc1350 sensortag/cc2650 sensortag/cc1350 MAKE_WITH_SECURITY ?= 0 # force Security from command line diff --git a/examples/6tisch/simple-node/Makefile b/examples/6tisch/simple-node/Makefile index 63ce8ecbd..c2e976b4e 100644 --- a/examples/6tisch/simple-node/Makefile +++ b/examples/6tisch/simple-node/Makefile @@ -1,7 +1,7 @@ CONTIKI_PROJECT = node all: $(CONTIKI_PROJECT) -PLATFORMS_EXCLUDE = sky nrf52dk native +PLATFORMS_EXCLUDE = sky nrf52dk native simplelink BOARDS_EXCLUDE = srf06/cc13xx launchpad/cc1310 launchpad/cc1350 sensortag/cc2650 sensortag/cc1350 CONTIKI=../../.. diff --git a/examples/6tisch/sixtop/Makefile b/examples/6tisch/sixtop/Makefile index 5ca6be853..2469cd445 100644 --- a/examples/6tisch/sixtop/Makefile +++ b/examples/6tisch/sixtop/Makefile @@ -1,7 +1,7 @@ CONTIKI_PROJECT = node-sixtop all: $(CONTIKI_PROJECT) -PLATFORMS_EXCLUDE = sky nrf52dk native +PLATFORMS_EXCLUDE = sky nrf52dk native simplelink BOARDS_EXCLUDE = srf06/cc13xx launchpad/cc1310 launchpad/cc1350 sensortag/cc2650 sensortag/cc1350 PROJECT_SOURCEFILES += sf-simple.c diff --git a/examples/dev/button-hal/Makefile b/examples/dev/button-hal/Makefile index 0c209918c..b2a73fe3c 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 native +PLATFORMS_ONLY = srf06-cc26xx cc2538dk openmote-cc2538 zoul native simplelink include $(CONTIKI)/Makefile.include diff --git a/examples/dev/gpio-hal/Makefile b/examples/dev/gpio-hal/Makefile index 016f53377..70f38a11a 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 native +PLATFORMS_ONLY = srf06-cc26xx cc2538dk openmote-cc2538 zoul native simplelink include $(CONTIKI)/Makefile.identify-target diff --git a/examples/mqtt-client/Makefile b/examples/mqtt-client/Makefile index d315cfea3..a9ab11613 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 native +PLATFORMS_ONLY = srf06-cc26xx cc2538dk openmote-cc2538 zoul native simplelink include $(CONTIKI)/Makefile.include diff --git a/examples/sensniff/Makefile b/examples/sensniff/Makefile index e207590bb..090bc694d 100644 --- a/examples/sensniff/Makefile +++ b/examples/sensniff/Makefile @@ -1,7 +1,7 @@ CONTIKI_PROJECT = sensniff CONTIKI = ../.. -PLATFORMS_ONLY = cc2538dk openmote-cc2538 zoul srf06-cc26xx jn516x +PLATFORMS_ONLY = cc2538dk openmote-cc2538 zoul srf06-cc26xx jn516x simplelink PROJECT_SOURCEFILES += sensniff-mac.c netstack.c MODULES_REL += pool $(TARGET) diff --git a/examples/sensniff/pool/simplelink-cc13xx-cc26xx-io.h b/examples/sensniff/pool/simplelink-cc13xx-cc26xx-io.h new file mode 100644 index 000000000..a77f9eb76 --- /dev/null +++ b/examples/sensniff/pool/simplelink-cc13xx-cc26xx-io.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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 SIMPLELINK_CC13XX_CC26XX_IO_H_ +#define SIMPLELINK_CC13XX_CC26XX_IO_H_ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +/*---------------------------------------------------------------------------*/ +#include "dev/uart0-arch.h" +/*---------------------------------------------------------------------------*/ +#define sensniff_io_byte_out(b) uart0_write_byte(b) +#define sensniff_io_flush() +#define sensniff_io_set_input(f) uart0_set_callback(f) +/*---------------------------------------------------------------------------*/ +#endif /* SIMPLELINK_CC13XX_CC26XX_IO_H_ */ +/*---------------------------------------------------------------------------*/ diff --git a/examples/sensniff/simplelink/target-conf.h b/examples/sensniff/simplelink/target-conf.h new file mode 100644 index 000000000..043e5a08f --- /dev/null +++ b/examples/sensniff/simplelink/target-conf.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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 TARGET_CONF_H_ +#define TARGET_CONF_H_ +/*---------------------------------------------------------------------------*/ +#define TI_UART_CONF_BAUD_RATE 460800 +#define RF_CONF_BLE_BEACON_ENABLE 0 +/*---------------------------------------------------------------------------*/ +#define SENSNIFF_IO_DRIVER_H "pool/simplelink-cc13xx-cc26xx-io.h" +/*---------------------------------------------------------------------------*/ +#endif /* TARGET_CONF_H_ */ +/*---------------------------------------------------------------------------*/ From b2eef99c7c665f9dd43614859b604788a47358cc Mon Sep 17 00:00:00 2001 From: Olav Frengstad Date: Thu, 14 Jun 2018 18:33:48 +0200 Subject: [PATCH 327/485] Use LOG_ constants infavour of PRINTF for rpl-classic Debugging could only be enabled pr. file at compile time. Refactor to use sys/log.h module. --- os/net/routing/rpl-classic/rpl-dag-root.c | 32 ++- os/net/routing/rpl-classic/rpl-dag.c | 303 ++++++++++---------- os/net/routing/rpl-classic/rpl-ext-header.c | 76 ++--- os/net/routing/rpl-classic/rpl-icmp6.c | 263 +++++++++-------- os/net/routing/rpl-classic/rpl-mrhof.c | 14 +- os/net/routing/rpl-classic/rpl-nbr-policy.c | 42 +-- os/net/routing/rpl-classic/rpl-of0.c | 10 +- os/net/routing/rpl-classic/rpl-timers.c | 45 +-- os/net/routing/rpl-classic/rpl.c | 58 ++-- 9 files changed, 434 insertions(+), 409 deletions(-) diff --git a/os/net/routing/rpl-classic/rpl-dag-root.c b/os/net/routing/rpl-classic/rpl-dag-root.c index 05adff4de..17ac24d33 100644 --- a/os/net/routing/rpl-classic/rpl-dag-root.c +++ b/os/net/routing/rpl-classic/rpl-dag-root.c @@ -36,18 +36,18 @@ #include "net/routing/rpl-classic/rpl-private.h" #include "net/ipv6/uip-ds6-route.h" +#include "sys/log.h" + #include -#define DEBUG DEBUG_NONE -#include "net/ipv6/uip-debug.h" +#define LOG_MODULE "RPL" +#define LOG_LEVEL LOG_LEVEL_RPL /*---------------------------------------------------------------------------*/ static void set_global_address(uip_ipaddr_t *prefix, uip_ipaddr_t *iid) { static uip_ipaddr_t root_ipaddr; - int i; - uint8_t state; /* Assign a unique local address (RFC4193, http://tools.ietf.org/html/rfc4193). */ @@ -64,13 +64,17 @@ set_global_address(uip_ipaddr_t *prefix, uip_ipaddr_t *iid) uip_ds6_addr_add(&root_ipaddr, 0, ADDR_AUTOCONF); - printf("IPv6 addresses: "); - for(i = 0; i < UIP_DS6_ADDR_NB; i++) { - state = uip_ds6_if.addr_list[i].state; - if(uip_ds6_if.addr_list[i].isused && - (state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) { - uip_debug_ipaddr_print(&uip_ds6_if.addr_list[i].ipaddr); - printf("\n"); + if(LOG_DBG_ENABLED) { + uint8_t state; + + LOG_DBG("IPv6 addresses: "); + for(int i = 0; i < UIP_DS6_ADDR_NB; i++) { + state = uip_ds6_if.addr_list[i].state; + if(uip_ds6_if.addr_list[i].isused && + (state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) { + LOG_DBG_6ADDR(&uip_ds6_if.addr_list[i].ipaddr); + LOG_DBG_("\n"); + } } } } @@ -126,14 +130,14 @@ rpl_dag_root_start(void) uip_ip6addr(&prefix, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 0); rpl_set_prefix(dag, &prefix, 64); - PRINTF("rpl_dag_root_set_prefix_dag: created a new RPL dag\n"); + LOG_INFO("root_set_prefix: created a new RPL dag\n"); return 0; } else { - PRINTF("rpl_dag_root_set_prefix_dag: failed to create a new RPL DAG\n"); + LOG_ERR("root_set_prefix: failed to create a new RPL DAG\n"); return -1; } } else { - PRINTF("rpl_dag_root_set_prefix_dag: failed to create a new RPL DAG, no preferred IP address found\n"); + LOG_ERR("root_set_prefix_dag: failed to create a new RPL DAG, no preferred IP address found\n"); return -2; } } diff --git a/os/net/routing/rpl-classic/rpl-dag.c b/os/net/routing/rpl-classic/rpl-dag.c index 670a54f3f..cbaee6959 100644 --- a/os/net/routing/rpl-classic/rpl-dag.c +++ b/os/net/routing/rpl-classic/rpl-dag.c @@ -56,12 +56,13 @@ #include "lib/list.h" #include "lib/memb.h" #include "sys/ctimer.h" +#include "sys/log.h" #include #include -#define DEBUG DEBUG_NONE -#include "net/ipv6/uip-debug.h" +#define LOG_MODULE "RPL" +#define LOG_LEVEL LOG_LEVEL_RPL /* A configurable function called after every RPL parent switch */ #ifdef RPL_CALLBACK_PARENT_SWITCH @@ -233,19 +234,19 @@ static void rpl_set_preferred_parent(rpl_dag_t *dag, rpl_parent_t *p) { if(dag != NULL && dag->preferred_parent != p) { - PRINTF("RPL: rpl_set_preferred_parent "); + LOG_INFO("rpl_set_preferred_parent "); if(p != NULL) { - PRINT6ADDR(rpl_parent_get_ipaddr(p)); + LOG_INFO_6ADDR(rpl_parent_get_ipaddr(p)); } else { - PRINTF("NULL"); + LOG_INFO_("NULL"); } - PRINTF(" used to be "); + LOG_INFO_(" used to be "); if(dag->preferred_parent != NULL) { - PRINT6ADDR(rpl_parent_get_ipaddr(dag->preferred_parent)); + LOG_INFO_6ADDR(rpl_parent_get_ipaddr(dag->preferred_parent)); } else { - PRINTF("NULL"); + LOG_INFO_("NULL"); } - PRINTF("\n"); + LOG_INFO_("\n"); #ifdef RPL_CALLBACK_PARENT_SWITCH RPL_CALLBACK_PARENT_SWITCH(dag->preferred_parent, p); @@ -281,8 +282,7 @@ remove_parents(rpl_dag_t *dag, rpl_rank_t minimum_rank) { rpl_parent_t *p; - PRINTF("RPL: Removing parents (minimum rank %u)\n", - minimum_rank); + LOG_INFO("Removing parents (minimum rank %u)\n", minimum_rank); p = nbr_table_head(rpl_parents); while(p != NULL) { @@ -298,8 +298,7 @@ nullify_parents(rpl_dag_t *dag, rpl_rank_t minimum_rank) { rpl_parent_t *p; - PRINTF("RPL: Nullifying parents (minimum rank %u)\n", - minimum_rank); + LOG_INFO("Nullifying parents (minimum rank %u)\n", minimum_rank); p = nbr_table_head(rpl_parents); while(p != NULL) { @@ -371,11 +370,11 @@ rpl_set_root(uint8_t instance_id, uip_ipaddr_t *dag_id) RPL_LOLLIPOP_INCREMENT(version); } if(dag == dag->instance->current_dag) { - PRINTF("RPL: Dropping a joined DAG when setting this node as root"); + LOG_INFO("Dropping a joined DAG when setting this node as root\n"); rpl_set_default_route(instance, NULL); dag->instance->current_dag = NULL; } else { - PRINTF("RPL: Dropping a DAG when setting this node as root"); + LOG_INFO("Dropping a DAG when setting this node as root\n"); } rpl_free_dag(dag); } @@ -384,7 +383,7 @@ rpl_set_root(uint8_t instance_id, uip_ipaddr_t *dag_id) dag = rpl_alloc_dag(instance_id, dag_id); if(dag == NULL) { - PRINTF("RPL: Failed to allocate a DAG\n"); + LOG_ERR("Failed to allocate a DAG\n"); return NULL; } @@ -397,7 +396,7 @@ rpl_set_root(uint8_t instance_id, uip_ipaddr_t *dag_id) instance->mop = RPL_MOP_DEFAULT; instance->of = rpl_find_of(RPL_OF_OCP); if(instance->of == NULL) { - PRINTF("RPL: OF with OCP %u not supported\n", RPL_OF_OCP); + LOG_WARN("OF with OCP %u not supported\n", RPL_OF_OCP); return NULL; } @@ -433,11 +432,11 @@ rpl_set_root(uint8_t instance_id, uip_ipaddr_t *dag_id) instance->of->update_metric_container(instance); default_instance = instance; - PRINTF("RPL: Node set to be a DAG root with DAG ID "); - PRINT6ADDR(&dag->dag_id); - PRINTF("\n"); + LOG_INFO("Node set to be a DAG root with DAG ID "); + LOG_INFO_6ADDR(&dag->dag_id); + LOG_INFO_("\n"); - ANNOTATE("#A root=%u\n", dag->dag_id.u8[sizeof(dag->dag_id) - 1]); + LOG_ANNOTATE("#A root=%u\n", dag->dag_id.u8[sizeof(dag->dag_id) - 1]); rpl_reset_dio_timer(instance); @@ -452,14 +451,14 @@ rpl_repair_root(uint8_t instance_id) instance = rpl_get_instance(instance_id); if(instance == NULL || instance->current_dag->rank != ROOT_RANK(instance)) { - PRINTF("RPL: rpl_repair_root triggered but not root\n"); + LOG_WARN("rpl_repair_root triggered but not root\n"); return 0; } RPL_STAT(rpl_stats.root_repairs++); RPL_LOLLIPOP_INCREMENT(instance->current_dag->version); RPL_LOLLIPOP_INCREMENT(instance->dtsn_out); - PRINTF("RPL: rpl_repair_root initiating global repair with version %d\n", instance->current_dag->version); + LOG_INFO("rpl_repair_root initiating global repair with version %d\n", instance->current_dag->version); rpl_reset_dio_timer(instance); return 1; } @@ -490,9 +489,9 @@ check_prefix(rpl_prefix_t *last_prefix, rpl_prefix_t *new_prefix) set_ip_from_prefix(&ipaddr, last_prefix); rep = uip_ds6_addr_lookup(&ipaddr); if(rep != NULL) { - PRINTF("RPL: removing global IP address "); - PRINT6ADDR(&ipaddr); - PRINTF("\n"); + LOG_DBG("removing global IP address "); + LOG_DBG_6ADDR(&ipaddr); + LOG_DBG_("\n"); uip_ds6_addr_rm(rep); } } @@ -500,9 +499,9 @@ check_prefix(rpl_prefix_t *last_prefix, rpl_prefix_t *new_prefix) if(new_prefix != NULL) { set_ip_from_prefix(&ipaddr, new_prefix); if(uip_ds6_addr_lookup(&ipaddr) == NULL) { - PRINTF("RPL: adding global IP address "); - PRINT6ADDR(&ipaddr); - PRINTF("\n"); + LOG_DBG("adding global IP address "); + LOG_DBG_6ADDR(&ipaddr); + LOG_DBG_("\n"); uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF); } } @@ -524,15 +523,15 @@ rpl_set_prefix(rpl_dag_t *dag, uip_ipaddr_t *prefix, unsigned len) memcpy(&dag->prefix_info.prefix, prefix, (len + 7) / 8); dag->prefix_info.length = len; dag->prefix_info.flags = UIP_ND6_RA_FLAG_AUTONOMOUS; - PRINTF("RPL: Prefix set - will announce this in DIOs\n"); + LOG_INFO("Prefix set - will announce this in DIOs\n"); if(dag->rank != ROOT_RANK(dag->instance)) { /* Autoconfigure an address if this node does not already have an address with this prefix. Otherwise, update the prefix */ if(last_len == 0) { - PRINTF("rpl_set_prefix - prefix NULL\n"); + LOG_INFO("rpl_set_prefix - prefix NULL\n"); check_prefix(NULL, &dag->prefix_info); } else { - PRINTF("rpl_set_prefix - prefix NON-NULL\n"); + LOG_INFO("rpl_set_prefix - prefix NON-NULL\n"); check_prefix(&last_prefix, &dag->prefix_info); } } @@ -543,17 +542,17 @@ int rpl_set_default_route(rpl_instance_t *instance, uip_ipaddr_t *from) { if(instance->def_route != NULL) { - PRINTF("RPL: Removing default route through "); - PRINT6ADDR(&instance->def_route->ipaddr); - PRINTF("\n"); + LOG_DBG("Removing default route through "); + LOG_DBG_6ADDR(&instance->def_route->ipaddr); + LOG_DBG_("\n"); uip_ds6_defrt_rm(instance->def_route); instance->def_route = NULL; } if(from != NULL) { - PRINTF("RPL: Adding default route through "); - PRINT6ADDR(from); - PRINTF("\n"); + LOG_DBG("Adding default route through "); + LOG_DBG_6ADDR(from); + LOG_DBG("\n"); instance->def_route = uip_ds6_defrt_add(from, RPL_DEFAULT_ROUTE_INFINITE_LIFETIME ? 0 : RPL_LIFETIME(instance, instance->default_lifetime)); if(instance->def_route == NULL) { @@ -632,7 +631,7 @@ rpl_free_instance(rpl_instance_t *instance) rpl_dag_t *dag; rpl_dag_t *end; - PRINTF("RPL: Leaving the instance %u\n", instance->instance_id); + LOG_INFO("Leaving the instance %u\n", instance->instance_id); /* Remove any DAG inside this instance */ for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DAG_PER_INSTANCE; dag < end; ++dag) { @@ -661,9 +660,9 @@ void rpl_free_dag(rpl_dag_t *dag) { if(dag->joined) { - PRINTF("RPL: Leaving the DAG "); - PRINT6ADDR(&dag->dag_id); - PRINTF("\n"); + LOG_INFO("Leaving the DAG "); + LOG_INFO_6ADDR(&dag->dag_id); + LOG_INFO_("\n"); dag->joined = 0; /* Remove routes installed by DAOs. */ @@ -693,15 +692,15 @@ rpl_add_parent(rpl_dag_t *dag, rpl_dio_t *dio, uip_ipaddr_t *addr) * Typically, the parent is added upon receiving a DIO. */ const uip_lladdr_t *lladdr = uip_ds6_nbr_lladdr_from_ipaddr(addr); - PRINTF("RPL: rpl_add_parent lladdr %p ", lladdr); - PRINT6ADDR(addr); - PRINTF("\n"); + LOG_DBG("rpl_add_parent lladdr %p ", lladdr); + LOG_DBG_6ADDR(addr); + LOG_DBG_("\n"); if(lladdr != NULL) { /* Add parent in rpl_parents - again this is due to DIO */ p = nbr_table_add_lladdr(rpl_parents, (linkaddr_t *)lladdr, NBR_TABLE_REASON_RPL_DIO, dio); if(p == NULL) { - PRINTF("RPL: rpl_add_parent p NULL\n"); + LOG_DBG("rpl_add_parent p NULL\n"); } else { p->dag = dag; p->rank = dio->rank; @@ -792,9 +791,9 @@ rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p) rpl_remove_routes(instance->current_dag); } - PRINTF("RPL: New preferred DAG: "); - PRINT6ADDR(&best_dag->dag_id); - PRINTF("\n"); + LOG_INFO("New preferred DAG: "); + LOG_INFO_6ADDR(&best_dag->dag_id); + LOG_INFO_("\n"); if(best_dag->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) { check_prefix(&instance->current_dag->prefix_info, &best_dag->prefix_info); @@ -817,7 +816,7 @@ rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p) } if(!acceptable_rank(best_dag, best_dag->rank)) { - PRINTF("RPL: New rank unacceptable!\n"); + LOG_WARN("New rank unacceptable!\n"); rpl_set_preferred_parent(instance->current_dag, NULL); if(RPL_IS_STORING(instance) && last_parent != NULL) { /* Send a No-Path DAO to the removed preferred parent. */ @@ -828,7 +827,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", + LOG_INFO("Changed preferred parent, rank changed from %u to %u\n", (unsigned)old_rank, best_dag->rank); RPL_STAT(rpl_stats.parent_switch++); if(RPL_IS_STORING(instance)) { @@ -843,11 +842,11 @@ rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p) /* The DAO parent set changed - schedule a DAO transmission. */ rpl_schedule_dao(instance); rpl_reset_dio_timer(instance); -#if DEBUG - rpl_print_neighbor_list(); -#endif + if(LOG_DBG_ENABLED) { + rpl_print_neighbor_list(); + } } else if(best_dag->rank != old_rank) { - PRINTF("RPL: Preferred parent update, rank changed from %u to %u\n", + LOG_DBG("RPL: Preferred parent update, rank changed from %u to %u\n", (unsigned)old_rank, best_dag->rank); } return best_dag; @@ -871,7 +870,7 @@ best_parent(rpl_dag_t *dag, int fresh_only) /* Exclude parents from other DAGs or announcing an infinite rank */ if(p->dag != dag || p->rank == RPL_INFINITE_RANK || p->rank < ROOT_RANK(dag->instance)) { if(p->rank < ROOT_RANK(dag->instance)) { - PRINTF("RPL: Parent has invalid rank\n"); + LOG_WARN("Parent has invalid rank\n"); } continue; } @@ -939,9 +938,9 @@ rpl_select_parent(rpl_dag_t *dag) void rpl_remove_parent(rpl_parent_t *parent) { - PRINTF("RPL: Removing parent "); - PRINT6ADDR(rpl_parent_get_ipaddr(parent)); - PRINTF("\n"); + LOG_INFO("Removing parent "); + LOG_INFO_6ADDR(rpl_parent_get_ipaddr(parent)); + LOG_INFO_("\n"); rpl_nullify_parent(parent); @@ -958,9 +957,9 @@ rpl_nullify_parent(rpl_parent_t *parent) dag->rank = RPL_INFINITE_RANK; if(dag->joined) { if(dag->instance->def_route != NULL) { - PRINTF("RPL: Removing default route "); - PRINT6ADDR(rpl_parent_get_ipaddr(parent)); - PRINTF("\n"); + LOG_DBG("Removing default route "); + LOG_DBG_6ADDR(rpl_parent_get_ipaddr(parent)); + LOG_DBG_("\n"); uip_ds6_defrt_rm(dag->instance->def_route); dag->instance->def_route = NULL; } @@ -974,9 +973,9 @@ rpl_nullify_parent(rpl_parent_t *parent) } } - PRINTF("RPL: Nullifying parent "); - PRINT6ADDR(rpl_parent_get_ipaddr(parent)); - PRINTF("\n"); + LOG_INFO("Nullifying parent "); + LOG_INFO_6ADDR(rpl_parent_get_ipaddr(parent)); + LOG_INFO_("\n"); } /*---------------------------------------------------------------------------*/ void @@ -986,10 +985,10 @@ rpl_move_parent(rpl_dag_t *dag_src, rpl_dag_t *dag_dst, rpl_parent_t *parent) rpl_set_preferred_parent(dag_src, NULL); dag_src->rank = RPL_INFINITE_RANK; if(dag_src->joined && dag_src->instance->def_route != NULL) { - PRINTF("RPL: Removing default route "); - PRINT6ADDR(rpl_parent_get_ipaddr(parent)); - PRINTF("\n"); - PRINTF("rpl_move_parent\n"); + LOG_DBG("Removing default route "); + LOG_DBG_6ADDR(rpl_parent_get_ipaddr(parent)); + LOG_DBG_("\n"); + LOG_DBG("rpl_move_parent\n"); uip_ds6_defrt_rm(dag_src->instance->def_route); dag_src->instance->def_route = NULL; } @@ -1000,9 +999,9 @@ rpl_move_parent(rpl_dag_t *dag_src, rpl_dag_t *dag_dst, rpl_parent_t *parent) } } - PRINTF("RPL: Moving parent "); - PRINT6ADDR(rpl_parent_get_ipaddr(parent)); - PRINTF("\n"); + LOG_INFO("Moving parent "); + LOG_INFO_6ADDR(rpl_parent_get_ipaddr(parent)); + LOG_INFO_("\n"); parent->dag = dag_dst; } @@ -1100,7 +1099,7 @@ rpl_join_instance(uip_ipaddr_t *from, rpl_dio_t *dio) if((!RPL_WITH_NON_STORING && dio->mop == RPL_MOP_NON_STORING) || (!RPL_WITH_STORING && (dio->mop == RPL_MOP_STORING_NO_MULTICAST || dio->mop == RPL_MOP_STORING_MULTICAST))) { - PRINTF("RPL: DIO advertising a non-supported MOP %u\n", dio->mop); + LOG_WARN("DIO advertising a non-supported MOP %u\n", dio->mop); return; } @@ -1108,30 +1107,30 @@ rpl_join_instance(uip_ipaddr_t *from, rpl_dio_t *dio) objective code point of the DIO. */ of = rpl_find_of(dio->ocp); if(of == NULL) { - PRINTF("RPL: DIO for DAG instance %u does not specify a supported OF: %u\n", + LOG_WARN("DIO for DAG instance %u does not specify a supported OF: %u\n", dio->instance_id, dio->ocp); return; } dag = rpl_alloc_dag(dio->instance_id, &dio->dag_id); if(dag == NULL) { - PRINTF("RPL: Failed to allocate a DAG object!\n"); + LOG_ERR("Failed to allocate a DAG object!\n"); return; } instance = dag->instance; p = rpl_add_parent(dag, dio, from); - PRINTF("RPL: Adding "); - PRINT6ADDR(from); - PRINTF(" as a parent: "); + LOG_DBG("Adding "); + LOG_DBG_6ADDR(from); + LOG_DBG_(" as a parent: "); if(p == NULL) { - PRINTF("failed\n"); + LOG_DBG_("failed\n"); instance->used = 0; return; } p->dtsn = dio->dtsn; - PRINTF("succeeded\n"); + LOG_DBG_("succeeded\n"); /* Autoconfigure an address if this node does not already have an address with this prefix. */ @@ -1177,12 +1176,12 @@ rpl_join_instance(uip_ipaddr_t *from, rpl_dio_t *dio) default_instance = instance; } - PRINTF("RPL: Joined DAG with instance ID %u, rank %hu, DAG ID ", + LOG_INFO("Joined DAG with instance ID %u, rank %hu, DAG ID ", dio->instance_id, dag->rank); - PRINT6ADDR(&dag->dag_id); - PRINTF("\n"); + LOG_INFO_6ADDR(&dag->dag_id); + LOG_INFO_("\n"); - ANNOTATE("#A join=%u\n", dag->dag_id.u8[sizeof(dag->dag_id) - 1]); + LOG_ANNOTATE("#A join=%u\n", dag->dag_id.u8[sizeof(dag->dag_id) - 1]); rpl_reset_dio_timer(instance); rpl_set_default_route(instance, from); @@ -1190,7 +1189,7 @@ rpl_join_instance(uip_ipaddr_t *from, rpl_dio_t *dio) if(instance->mop != RPL_MOP_NO_DOWNWARD_ROUTES) { rpl_schedule_dao(instance); } else { - PRINTF("RPL: The DIO does not meet the prerequisites for sending a DAO\n"); + LOG_WARN("The DIO does not meet the prerequisites for sending a DAO\n"); } instance->of->reset(dag); @@ -1208,7 +1207,7 @@ rpl_add_dag(uip_ipaddr_t *from, rpl_dio_t *dio) dag = rpl_alloc_dag(dio->instance_id, &dio->dag_id); if(dag == NULL) { - PRINTF("RPL: Failed to allocate a DAG object!\n"); + LOG_ERR("Failed to allocate a DAG object!\n"); return NULL; } @@ -1216,16 +1215,16 @@ rpl_add_dag(uip_ipaddr_t *from, rpl_dio_t *dio) previous_dag = find_parent_dag(instance, from); if(previous_dag == NULL) { - PRINTF("RPL: Adding "); - PRINT6ADDR(from); - PRINTF(" as a parent: "); + LOG_DBG("Adding "); + LOG_DBG_6ADDR(from); + LOG_DBG_(" as a parent: "); p = rpl_add_parent(dag, dio, from); if(p == NULL) { - PRINTF("failed\n"); + LOG_DBG_("failed\n"); dag->used = 0; return NULL; } - PRINTF("succeeded\n"); + LOG_DBG_("succeeded\n"); } else { p = rpl_find_parent(previous_dag, from); if(p != NULL) { @@ -1246,7 +1245,7 @@ rpl_add_dag(uip_ipaddr_t *from, rpl_dio_t *dio) instance->dio_redundancy != dio->dag_redund || instance->default_lifetime != dio->default_lifetime || instance->lifetime_unit != dio->lifetime_unit) { - PRINTF("RPL: DIO for DAG instance %u incompatible with previous DIO\n", + LOG_WARN("DIO for DAG instance %u incompatible with previous DIO\n", dio->instance_id); rpl_remove_parent(p); dag->used = 0; @@ -1267,12 +1266,12 @@ rpl_add_dag(uip_ipaddr_t *from, rpl_dio_t *dio) dag->rank = rpl_rank_via_parent(p); dag->min_rank = dag->rank; /* So far this is the lowest rank we know of. */ - PRINTF("RPL: Joined DAG with instance ID %u, rank %hu, DAG ID ", + LOG_INFO("Joined DAG with instance ID %u, rank %hu, DAG ID ", dio->instance_id, dag->rank); - PRINT6ADDR(&dag->dag_id); - PRINTF("\n"); + LOG_INFO_6ADDR(&dag->dag_id); + LOG_INFO_("\n"); - ANNOTATE("#A join=%u\n", dag->dag_id.u8[sizeof(dag->dag_id) - 1]); + LOG_ANNOTATE("#A join=%u\n", dag->dag_id.u8[sizeof(dag->dag_id) - 1]); rpl_process_parent_event(instance, p); p->dtsn = dio->dtsn; @@ -1303,16 +1302,16 @@ global_repair(uip_ipaddr_t *from, rpl_dag_t *dag, rpl_dio_t *dio) p = rpl_add_parent(dag, dio, from); if(p == NULL) { - PRINTF("RPL: Failed to add a parent during the global repair\n"); + LOG_ERR("Failed to add a parent during the global repair\n"); dag->rank = RPL_INFINITE_RANK; } else { dag->rank = rpl_rank_via_parent(p); dag->min_rank = dag->rank; - PRINTF("RPL: rpl_process_parent_event global repair\n"); + LOG_DBG("rpl_process_parent_event global repair\n"); rpl_process_parent_event(dag->instance, p); } - PRINTF("RPL: Participating in a global repair (version=%u, rank=%hu)\n", + LOG_DBG("Participating in a global repair (version=%u, rank=%hu)\n", dag->version, dag->rank); RPL_STAT(rpl_stats.global_repairs++); @@ -1325,10 +1324,10 @@ rpl_local_repair(rpl_instance_t *instance) int i; if(instance == NULL) { - PRINTF("RPL: local repair requested for instance NULL\n"); + LOG_WARN("local repair requested for instance NULL\n"); return; } - PRINTF("RPL: Starting a local instance repair\n"); + LOG_INFO("Starting a local instance repair\n"); for(i = 0; i < RPL_MAX_DAG_PER_INSTANCE; i++) { if(instance->dag_table[i].used) { instance->dag_table[i].rank = RPL_INFINITE_RANK; @@ -1367,9 +1366,9 @@ rpl_recalculate_ranks(void) while(p != NULL) { if(p->dag != NULL && p->dag->instance && (p->flags & RPL_PARENT_FLAG_UPDATED)) { p->flags &= ~RPL_PARENT_FLAG_UPDATED; - PRINTF("RPL: rpl_process_parent_event recalculate_ranks\n"); + LOG_DBG("rpl_process_parent_event recalculate_ranks\n"); if(!rpl_process_parent_event(p->dag->instance, p)) { - PRINTF("RPL: A parent was dropped\n"); + LOG_DBG("A parent was dropped\n"); } } p = nbr_table_next(rpl_parents, p); @@ -1382,26 +1381,26 @@ rpl_process_parent_event(rpl_instance_t *instance, rpl_parent_t *p) int return_value; rpl_parent_t *last_parent = instance->current_dag->preferred_parent; -#if DEBUG - rpl_rank_t old_rank; - old_rank = instance->current_dag->rank; -#endif /* DEBUG */ +#if LOG_DBG_ENABLED + rpl_rank_t old_rank; + old_rank = instance->current_dag->rank; +#endif /* LOG_DBG_ENABLED */ return_value = 1; if(RPL_IS_STORING(instance) && uip_ds6_route_is_nexthop(rpl_parent_get_ipaddr(p)) && !rpl_parent_is_reachable(p) && instance->mop > RPL_MOP_NON_STORING) { - PRINTF("RPL: Unacceptable link %u, removing routes via: ", rpl_get_parent_link_metric(p)); - PRINT6ADDR(rpl_parent_get_ipaddr(p)); - PRINTF("\n"); + LOG_WARN("Unacceptable link %u, removing routes via: ", rpl_get_parent_link_metric(p)); + LOG_WARN_6ADDR(rpl_parent_get_ipaddr(p)); + LOG_WARN_("\n"); rpl_remove_routes_by_nexthop(rpl_parent_get_ipaddr(p), p->dag); } if(!acceptable_rank(p->dag, p->rank)) { /* The candidate parent is no longer valid: the rank increase resulting from the choice of it as a parent would be too high. */ - PRINTF("RPL: Unacceptable rank %u (Current min %u, MaxRankInc %u)\n", (unsigned)p->rank, + LOG_WARN("Unacceptable rank %u (Current min %u, MaxRankInc %u)\n", (unsigned)p->rank, p->dag->min_rank, p->dag->instance->max_rankinc); rpl_nullify_parent(p); if(p != instance->current_dag->preferred_parent) { @@ -1414,26 +1413,26 @@ rpl_process_parent_event(rpl_instance_t *instance, rpl_parent_t *p) if(rpl_select_dag(instance, p) == NULL) { if(last_parent != NULL) { /* No suitable parent anymore; trigger a local repair. */ - PRINTF("RPL: No parents found in any DAG\n"); + LOG_ERR("No parents found in any DAG\n"); rpl_local_repair(instance); return 0; } } -#if DEBUG +#if LOG_DBG_ENABLED if(DAG_RANK(old_rank, instance) != DAG_RANK(instance->current_dag->rank, instance)) { - PRINTF("RPL: Moving in the instance from rank %hu to %hu\n", + LOG_INFO("Moving in the instance from rank %hu to %hu\n", DAG_RANK(old_rank, instance), DAG_RANK(instance->current_dag->rank, instance)); if(instance->current_dag->rank != RPL_INFINITE_RANK) { - PRINTF("RPL: The preferred parent is "); - PRINT6ADDR(rpl_parent_get_ipaddr(instance->current_dag->preferred_parent)); - PRINTF(" (rank %u)\n", + LOG_DBG("The preferred parent is "); + LOG_DBG_6ADDR(rpl_parent_get_ipaddr(instance->current_dag->preferred_parent)); + LOG_DBG_(" (rank %u)\n", (unsigned)DAG_RANK(instance->current_dag->preferred_parent->rank, instance)); } else { - PRINTF("RPL: We don't have any parent"); + LOG_WARN("We don't have any parent"); } } -#endif /* DEBUG */ +#endif /* LOG_DBG_ENABLED */ return return_value; } @@ -1443,9 +1442,9 @@ add_nbr_from_dio(uip_ipaddr_t *from, rpl_dio_t *dio) { /* add this to the neighbor cache if not already there */ if(rpl_icmp6_update_nbr_table(from, NBR_TABLE_REASON_RPL_DIO, dio) == NULL) { - PRINTF("RPL: Out of memory, dropping DIO from "); - PRINT6ADDR(from); - PRINTF("\n"); + LOG_ERR("Out of memory, dropping DIO from "); + LOG_ERR_6ADDR(from); + LOG_ERR_("\n"); return 0; } return 1; @@ -1465,7 +1464,7 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) #else if(dio->mop != RPL_MOP_DEFAULT) { #endif - PRINTF("RPL: Ignoring a DIO with an unsupported MOP: %d\n", dio->mop); + LOG_ERR("Ignoring a DIO with an unsupported MOP: %d\n", dio->mop); return; } @@ -1475,15 +1474,15 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) if(dag != NULL && instance != NULL) { if(lollipop_greater_than(dio->version, dag->version)) { if(dag->rank == ROOT_RANK(instance)) { - PRINTF("RPL: Root received inconsistent DIO version number (current: %u, received: %u)\n", dag->version, dio->version); + LOG_WARN("Root received inconsistent DIO version number (current: %u, received: %u)\n", dag->version, dio->version); dag->version = dio->version; RPL_LOLLIPOP_INCREMENT(dag->version); rpl_reset_dio_timer(instance); } else { - PRINTF("RPL: Global repair\n"); + LOG_DBG("Global repair\n"); if(dio->prefix_info.length != 0) { if(dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) { - PRINTF("RPL: Prefix announced in DIO\n"); + LOG_DBG("Prefix announced in DIO\n"); rpl_set_prefix(dag, &dio->prefix_info.prefix, dio->prefix_info.length); } } @@ -1494,7 +1493,7 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) if(lollipop_greater_than(dag->version, dio->version)) { /* The DIO sender is on an older version of the DAG. */ - PRINTF("RPL: old version received => inconsistency detected\n"); + LOG_WARN("old version received => inconsistency detected\n"); if(dag->joined) { rpl_reset_dio_timer(instance); return; @@ -1503,41 +1502,41 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) } if(instance == NULL) { - PRINTF("RPL: New instance detected (ID=%u): Joining...\n", dio->instance_id); + LOG_INFO("New instance detected (ID=%u): Joining...\n", dio->instance_id); if(add_nbr_from_dio(from, dio)) { rpl_join_instance(from, dio); } else { - PRINTF("RPL: Not joining since could not add parent\n"); + LOG_WARN("Not joining since could not add parent\n"); } return; } if(instance->current_dag->rank == ROOT_RANK(instance) && instance->current_dag != dag) { - PRINTF("RPL: Root ignored DIO for different DAG\n"); + LOG_WARN("Root ignored DIO for different DAG\n"); return; } if(dag == NULL) { #if RPL_MAX_DAG_PER_INSTANCE > 1 - PRINTF("RPL: Adding new DAG to known instance.\n"); + LOG_INFO("Adding new DAG to known instance.\n"); if(!add_nbr_from_dio(from, dio)) { - PRINTF("RPL: Could not add new DAG, could not add parent\n"); + LOG_WARN("Could not add new DAG, could not add parent\n"); return; } dag = rpl_add_dag(from, dio); if(dag == NULL) { - PRINTF("RPL: Failed to add DAG.\n"); + LOG_WARN("Failed to add DAG.\n"); return; } #else /* RPL_MAX_DAG_PER_INSTANCE > 1 */ - PRINTF("RPL: Only one instance supported.\n"); + LOG_WARN("Only one instance supported.\n"); return; #endif /* RPL_MAX_DAG_PER_INSTANCE > 1 */ } if(dio->rank < ROOT_RANK(instance)) { - PRINTF("RPL: Ignoring DIO with too low rank: %u\n", + LOG_INFO("Ignoring DIO with too low rank: %u\n", (unsigned)dio->rank); return; } @@ -1545,13 +1544,13 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) /* Prefix Information Option treated to add new prefix */ if(dio->prefix_info.length != 0) { if(dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) { - PRINTF("RPL: Prefix announced in DIO\n"); + LOG_DBG("Prefix announced in DIO\n"); rpl_set_prefix(dag, &dio->prefix_info.prefix, dio->prefix_info.length); } } if(!add_nbr_from_dio(from, dio)) { - PRINTF("RPL: Could not add parent based on DIO\n"); + LOG_WARN("Could not add parent based on DIO\n"); return; } @@ -1564,9 +1563,9 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) /* The DIO comes from a valid DAG, we can refresh its lifetime */ dag->lifetime = (1UL << (instance->dio_intmin + instance->dio_intdoubl)) * RPL_DAG_LIFETIME / 1000; - PRINTF("Set dag "); - PRINT6ADDR(&dag->dag_id); - PRINTF(" lifetime to %ld\n", dag->lifetime); + LOG_INFO("Set dag "); + LOG_INFO_6ADDR(&dag->dag_id); + LOG_INFO_(" lifetime to %ld\n", (long int) dag->lifetime); /* * At this point, we know that this DIO pertains to a DAG that @@ -1582,14 +1581,14 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) /* Add the DIO sender as a candidate parent. */ p = rpl_add_parent(dag, dio, from); if(p == NULL) { - PRINTF("RPL: Failed to add a new parent ("); - PRINT6ADDR(from); - PRINTF(")\n"); + LOG_WARN("Failed to add a new parent ("); + LOG_WARN_6ADDR(from); + LOG_WARN_(")\n"); return; } - PRINTF("RPL: New candidate parent with rank %u: ", (unsigned)p->rank); - PRINT6ADDR(from); - PRINTF("\n"); + LOG_INFO("New candidate parent with rank %u: ", (unsigned)p->rank); + LOG_INFO_6ADDR(from); + LOG_INFO_("\n"); } else { p = rpl_find_parent(previous_dag, from); if(p != NULL) { @@ -1598,7 +1597,7 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) } } else { if(p->rank == dio->rank) { - PRINTF("RPL: Received consistent DIO\n"); + LOG_WARN("Received consistent DIO\n"); if(dag->joined) { instance->dio_counter++; } @@ -1614,11 +1613,11 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) /* Parent info has been updated, trigger rank recalculation */ p->flags |= RPL_PARENT_FLAG_UPDATED; - PRINTF("RPL: preferred DAG "); - PRINT6ADDR(&instance->current_dag->dag_id); - PRINTF(", rank %u, min_rank %u, ", + LOG_INFO("preferred DAG "); + LOG_INFO_6ADDR(&instance->current_dag->dag_id); + LOG_INFO_(", rank %u, min_rank %u, ", instance->current_dag->rank, instance->current_dag->min_rank); - PRINTF("parent rank %u, link metric %u\n", + LOG_INFO_("parent rank %u, link metric %u\n", p->rank, rpl_get_parent_link_metric(p)); /* We have allocated a candidate parent; process the DIO further. */ @@ -1627,7 +1626,7 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) memcpy(&p->mc, &dio->mc, sizeof(p->mc)); #endif /* RPL_WITH_MC */ if(rpl_process_parent_event(instance, p) == 0) { - PRINTF("RPL: The candidate parent is rejected\n"); + LOG_WARN("The candidate parent is rejected\n"); return; } diff --git a/os/net/routing/rpl-classic/rpl-ext-header.c b/os/net/routing/rpl-classic/rpl-ext-header.c index e6498b993..8488d5ac6 100644 --- a/os/net/routing/rpl-classic/rpl-ext-header.c +++ b/os/net/routing/rpl-classic/rpl-ext-header.c @@ -52,8 +52,10 @@ #include "net/routing/rpl-classic/rpl-private.h" #include "net/packetbuf.h" -#define DEBUG DEBUG_NONE -#include "net/ipv6/uip-debug.h" +#include "sys/log.h" + +#define LOG_MODULE "RPL" +#define LOG_LEVEL LOG_LEVEL_RPL #include #include @@ -83,7 +85,7 @@ rpl_ext_header_hbh_update(int uip_ext_opt_offset) || UIP_EXT_HDR_OPT_RPL_BUF->opt_type != UIP_EXT_HDR_OPT_RPL || UIP_EXT_HDR_OPT_RPL_BUF->opt_len != RPL_HDR_OPT_LEN) { - PRINTF("RPL: Hop-by-hop extension header has wrong size or type (%u %u %u)\n", + LOG_ERR("Hop-by-hop extension header has wrong size or type (%u %u %u)\n", UIP_HBHO_BUF->len, UIP_EXT_HDR_OPT_RPL_BUF->opt_type, UIP_EXT_HDR_OPT_RPL_BUF->opt_len); @@ -92,13 +94,13 @@ rpl_ext_header_hbh_update(int uip_ext_opt_offset) instance = rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance); if(instance == NULL) { - PRINTF("RPL: Unknown instance: %u\n", + LOG_ERR("Unknown instance: %u\n", UIP_EXT_HDR_OPT_RPL_BUF->instance); return 0; } if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_FWD_ERR) { - PRINTF("RPL: Forward error!\n"); + LOG_ERR("Forward error!\n"); /* We should try to repair it by removing the neighbor that caused the packet to be forwareded in the first place. We drop any routes that go through the neighbor that sent the packet to @@ -117,7 +119,7 @@ rpl_ext_header_hbh_update(int uip_ext_opt_offset) } if(!instance->current_dag->joined) { - PRINTF("RPL: No DAG in the instance\n"); + LOG_ERR("No DAG in the instance\n"); return 0; } down = 0; @@ -142,14 +144,14 @@ rpl_ext_header_hbh_update(int uip_ext_opt_offset) sender_closer = sender_rank < instance->current_dag->rank; - PRINTF("RPL: Packet going %s, sender closer %d (%d < %d)\n", down == 1 ? "down" : "up", + LOG_DBG("Packet going %s, sender closer %d (%d < %d)\n", down == 1 ? "down" : "up", sender_closer, sender_rank, instance->current_dag->rank ); if((down && !sender_closer) || (!down && sender_closer)) { - PRINTF("RPL: Loop detected - senderrank: %d my-rank: %d sender_closer: %d\n", + LOG_WARN("Loop detected - senderrank: %d my-rank: %d sender_closer: %d\n", sender_rank, instance->current_dag->rank, sender_closer); /* Attempt to repair the loop by sending a unicast DIO back to the sender @@ -160,18 +162,18 @@ rpl_ext_header_hbh_update(int uip_ext_opt_offset) } if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_RANK_ERR) { RPL_STAT(rpl_stats.loop_errors++); - PRINTF("RPL: Rank error signalled in RPL option!\n"); + LOG_ERR(" Rank error signalled in RPL option!\n"); /* Packet must be dropped and dio trickle timer reset, see RFC6550 - 11.2.2.2 */ rpl_reset_dio_timer(instance); return 0; } - PRINTF("RPL: Single error tolerated\n"); + LOG_WARN("Single error tolerated\n"); RPL_STAT(rpl_stats.loop_warnings++); UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_RANK_ERR; return 1; } - PRINTF("RPL: Rank OK\n"); + LOG_DBG("Rank OK\n"); return 1; } /*---------------------------------------------------------------------------*/ @@ -281,7 +283,7 @@ rpl_ext_header_srh_update(void) path_len = ((ext_len - padding - RPL_RH_LEN - RPL_SRH_LEN - (16 - cmpre)) / (16 - cmpri)) + 1; (void)path_len; - PRINTF("RPL: read SRH, path len %u, segments left %u, Cmpri %u, Cmpre %u, ext len %u (padding %u)\n", + LOG_DBG("read SRH, path len %u, segments left %u, Cmpri %u, Cmpre %u, ext len %u (padding %u)\n", path_len, segments_left, cmpri, cmpre, ext_len, padding); if(segments_left == 0) { @@ -303,9 +305,9 @@ rpl_ext_header_srh_update(void) /* Update segments left field */ UIP_RH_BUF->seg_left--; - PRINTF("RPL: SRH next hop "); - PRINT6ADDR(&UIP_IP_BUF->destipaddr); - PRINTF("\n"); + LOG_INFO("SRH next hop "); + LOG_INFO_6ADDR(&UIP_IP_BUF->destipaddr); + LOG_INFO_("\n"); } uip_ext_len = last_uip_ext_len; return 1; @@ -346,9 +348,9 @@ insert_srh_header(void) rpl_dag_t *dag; uip_ipaddr_t node_addr; - PRINTF("RPL: SRH creating source routing header with destination "); - PRINT6ADDR(&UIP_IP_BUF->destipaddr); - PRINTF(" \n"); + LOG_INFO("SRH creating source routing header with destination "); + LOG_INFO_6ADDR(&UIP_IP_BUF->destipaddr); + LOG_INFO_("\n"); /* Construct source route. We do not do this recursively to keep the runtime stack usage constant. */ @@ -356,7 +358,7 @@ insert_srh_header(void) dag = rpl_get_dag(&UIP_IP_BUF->destipaddr); if(dag == NULL) { - PRINTF("RPL: SRH DAG not found\n"); + LOG_ERR("SRH DAG not found\n"); return 0; } @@ -368,12 +370,12 @@ insert_srh_header(void) root_node = uip_sr_get_node(dag, &dag->dag_id); if(root_node == NULL) { - PRINTF("RPL: SRH root node not found\n"); + LOG_ERR("SRH root node not found\n"); return 0; } if(!uip_sr_is_addr_reachable(dag, &UIP_IP_BUF->destipaddr)) { - PRINTF("RPL: SRH no path found to destination\n"); + LOG_ERR("SRH no path found to destination\n"); return 0; } @@ -385,7 +387,7 @@ insert_srh_header(void) cmpre = 15; if(node == root_node) { - PRINTF("RPL: SRH no need to insert SRH\n"); + LOG_DBG("SRH no need to insert SRH\n"); return 1; } @@ -397,9 +399,9 @@ insert_srh_header(void) cmpri = MIN(cmpri, count_matching_bytes(&node_addr, &UIP_IP_BUF->destipaddr, 16)); cmpre = cmpri; - PRINTF("RPL: SRH Hop "); - PRINT6ADDR(&node_addr); - PRINTF("\n"); + LOG_DBG("SRH Hop "); + LOG_DBG_6ADDR(&node_addr); + LOG_DBG_("\n"); node = node->parent; path_len++; } @@ -412,12 +414,12 @@ insert_srh_header(void) padding = ext_len % 8 == 0 ? 0 : (8 - (ext_len % 8)); ext_len += padding; - PRINTF("RPL: SRH Path len: %u, ComprI %u, ComprE %u, ext len %u (padding %u)\n", + LOG_DBG("SRH Path len: %u, ComprI %u, ComprE %u, ext len %u (padding %u)\n", path_len, cmpri, cmpre, ext_len, padding); /* Check if there is enough space to store the extension header */ if(uip_len + ext_len > UIP_BUFSIZE - UIP_LLH_LEN) { - PRINTF("RPL: Packet too long: impossible to add source routing header (%u bytes)\n", ext_len); + LOG_ERR("Packet too long: impossible to add source routing header (%u bytes)\n", ext_len); return 0; } @@ -486,7 +488,7 @@ update_hbh_header(void) if(UIP_HBHO_BUF->len != ((RPL_HOP_BY_HOP_LEN - 8) / 8) || UIP_EXT_HDR_OPT_RPL_BUF->opt_len != RPL_HDR_OPT_LEN) { - PRINTF("RPL: Hop-by-hop extension header has wrong size (%u %u)\n", + LOG_ERR("Hop-by-hop extension header has wrong size (%u %u)\n", UIP_EXT_HDR_OPT_RPL_BUF->opt_len, uip_ext_len); return 0; /* Drop */ @@ -494,12 +496,12 @@ update_hbh_header(void) instance = rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance); if(instance == NULL || !instance->used || !instance->current_dag->joined) { - PRINTF("RPL: Unable to add/update hop-by-hop extension header: incorrect instance\n"); + LOG_ERR("Unable to add/update hop-by-hop extension header: incorrect instance\n"); uip_ext_len = last_uip_ext_len; return 0; /* Drop */ } - PRINTF("RPL: Updating RPL option\n"); + LOG_INFO("Updating RPL option\n"); /* Update sender rank and instance, will update flags next */ UIP_EXT_HDR_OPT_RPL_BUF->senderrank = UIP_HTONS(instance->current_dag->rank); UIP_EXT_HDR_OPT_RPL_BUF->instance = instance->instance_id; @@ -512,10 +514,10 @@ update_hbh_header(void) if((UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_DOWN)) { if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) { UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_FWD_ERR; - PRINTF("RPL forwarding error\n"); + LOG_WARN("RPL forwarding error\n"); /* We should send back the packet to the originating parent, but it is not feasible yet, so we send a No-Path DAO instead */ - PRINTF("RPL generate No-Path DAO\n"); + LOG_WARN("RPL generate No-Path DAO\n"); parent = rpl_get_parent((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER)); if(parent != NULL) { dao_output_target(parent, &UIP_IP_BUF->destipaddr, RPL_ZERO_LIFETIME); @@ -531,11 +533,11 @@ update_hbh_header(void) /* No route was found, so this packet will go towards the RPL root. If so, we should not set the down flag. */ UIP_EXT_HDR_OPT_RPL_BUF->flags &= ~RPL_HDR_OPT_DOWN; - PRINTF("RPL option going up\n"); + LOG_DBG("RPL option going up\n"); } else { /* A DAO route was found so we set the down flag. */ UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_DOWN; - PRINTF("RPL option going down\n"); + LOG_DBG("RPL option going down\n"); } } } @@ -557,9 +559,9 @@ insert_hbh_header(const rpl_instance_t *instance) uip_ext_opt_offset = 2; /* Insert hop-by-hop header */ - PRINTF("RPL: Creating hop-by-hop option\n"); + LOG_DBG("Creating hop-by-hop option\n"); if(uip_len + RPL_HOP_BY_HOP_LEN > UIP_BUFSIZE - UIP_LLH_LEN) { - PRINTF("RPL: Packet too long: impossible to add hop-by-hop option\n"); + LOG_ERR("Packet too long: impossible to add hop-by-hop option\n"); uip_ext_len = last_uip_ext_len; return 0; } @@ -619,7 +621,7 @@ rpl_ext_header_remove(void) if(UIP_IP_BUF->len[1] > temp_len) { UIP_IP_BUF->len[0]--; } - PRINTF("RPL: Removing RPL extension header (type %u, len %u)\n", *uip_next_hdr, rpl_ext_hdr_len); + LOG_DBG("Removing RPL extension header (type %u, len %u)\n", *uip_next_hdr, rpl_ext_hdr_len); memmove(UIP_EXT_BUF, ((uint8_t *)UIP_EXT_BUF) + rpl_ext_hdr_len, uip_len - UIP_IPH_LEN); } else { uip_next_hdr = &UIP_EXT_BUF->next; diff --git a/os/net/routing/rpl-classic/rpl-icmp6.c b/os/net/routing/rpl-classic/rpl-icmp6.c index 914575dbf..a246e576e 100644 --- a/os/net/routing/rpl-classic/rpl-icmp6.c +++ b/os/net/routing/rpl-classic/rpl-icmp6.c @@ -56,12 +56,13 @@ #include "net/ipv6/multicast/uip-mcast6.h" #include "random.h" +#include "sys/log.h" + #include #include -#define DEBUG DEBUG_NONE - -#include "net/ipv6/uip-debug.h" +#define LOG_MODULE "RPL" +#define LOG_LEVEL LOG_LEVEL_RPL /*---------------------------------------------------------------------------*/ #define RPL_DIO_GROUNDED 0x80 @@ -201,11 +202,11 @@ rpl_icmp6_update_nbr_table(uip_ipaddr_t *from, nbr_table_reason_t reason, void * if((nbr = uip_ds6_nbr_add(from, (uip_lladdr_t *) packetbuf_addr(PACKETBUF_ADDR_SENDER), 0, NBR_REACHABLE, reason, data)) != NULL) { - PRINTF("RPL: Neighbor added to neighbor cache "); - PRINT6ADDR(from); - PRINTF(", "); - PRINTLLADDR((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER)); - PRINTF("\n"); + LOG_INFO("Neighbor added to neighbor cache "); + LOG_INFO_6ADDR(from); + LOG_INFO_(", "); + LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER)); + LOG_INFO_("\n"); } } @@ -219,31 +220,31 @@ dis_input(void) rpl_instance_t *end; /* DAG Information Solicitation */ - PRINTF("RPL: Received a DIS from "); - PRINT6ADDR(&UIP_IP_BUF->srcipaddr); - PRINTF("\n"); + LOG_INFO("Received a DIS from "); + LOG_INFO_6ADDR(&UIP_IP_BUF->srcipaddr); + LOG_INFO_("\n"); for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES; instance < end; ++instance) { if(instance->used == 1) { if(uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) { #if RPL_LEAF_ONLY - PRINTF("RPL: LEAF ONLY Multicast DIS will NOT reset DIO timer\n"); + LOG_INFO("LEAF ONLY Multicast DIS will NOT reset DIO timer\n"); #else /* !RPL_LEAF_ONLY */ - PRINTF("RPL: Multicast DIS => reset DIO timer\n"); + LOG_DBG("Multicast DIS => reset DIO timer\n"); rpl_reset_dio_timer(instance); #endif /* !RPL_LEAF_ONLY */ } else { /* Check if this neighbor should be added according to the policy. */ if(rpl_icmp6_update_nbr_table(&UIP_IP_BUF->srcipaddr, NBR_TABLE_REASON_RPL_DIS, NULL) == NULL) { - PRINTF("RPL: Out of Memory, not sending unicast DIO, DIS from "); - PRINT6ADDR(&UIP_IP_BUF->srcipaddr); - PRINTF(", "); - PRINTLLADDR((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER)); - PRINTF("\n"); + LOG_ERR("Out of Memory, not sending unicast DIO, DIS from "); + LOG_ERR_6ADDR(&UIP_IP_BUF->srcipaddr); + LOG_ERR_(", "); + LOG_ERR_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER)); + LOG_ERR_("\n"); } else { - PRINTF("RPL: Unicast DIS, reply to sender\n"); + LOG_DBG("Unicast DIS, reply to sender\n"); dio_output(instance, &UIP_IP_BUF->srcipaddr); } /* } */ @@ -276,9 +277,9 @@ dis_output(uip_ipaddr_t *addr) addr = &tmpaddr; } - PRINTF("RPL: Sending a DIS to "); - PRINT6ADDR(addr); - PRINTF("\n"); + LOG_INFO("Sending a DIS to "); + LOG_INFO_6ADDR(addr); + LOG_INFO_("\n"); uip_icmp6_send(addr, ICMP6_RPL, RPL_CODE_DIS, 2); } @@ -309,9 +310,9 @@ dio_input(void) uip_ipaddr_copy(&from, &UIP_IP_BUF->srcipaddr); /* DAG Information Object */ - PRINTF("RPL: Received a DIO from "); - PRINT6ADDR(&from); - PRINTF("\n"); + LOG_INFO("Received a DIO from "); + LOG_INFO_6ADDR(&from); + LOG_INFO_("\n"); buffer_length = uip_len - uip_l3_icmp_hdr_len; @@ -324,7 +325,7 @@ dio_input(void) dio.rank = get16(buffer, i); i += 2; - PRINTF("RPL: Incoming DIO (id, ver, rank) = (%u,%u,%u)\n", + LOG_DBG("Incoming DIO (id, ver, rank) = (%u,%u,%u)\n", (unsigned)dio.instance_id, (unsigned)dio.version, (unsigned)dio.rank); @@ -340,9 +341,9 @@ dio_input(void) memcpy(&dio.dag_id, buffer + i, sizeof(dio.dag_id)); i += sizeof(dio.dag_id); - PRINTF("RPL: Incoming DIO (dag_id, pref) = ("); - PRINT6ADDR(&dio.dag_id); - PRINTF(", %u)\n", dio.preference); + LOG_DBG("Incoming DIO (dag_id, pref) = ("); + LOG_DBG_6ADDR(&dio.dag_id); + LOG_DBG_(", %u)\n", dio.preference); /* Check if there are any DIO suboptions. */ for(; i < buffer_length; i += len) { @@ -355,17 +356,17 @@ dio_input(void) } if(len + i > buffer_length) { - PRINTF("RPL: Invalid DIO packet\n"); + LOG_WARN("Invalid DIO packet\n"); RPL_STAT(rpl_stats.malformed_msgs++); goto discard; } - PRINTF("RPL: DIO option %u, length: %u\n", subopt_type, len - 2); + LOG_DBG("Incoming DIO (option, length) = (%u, %u)\n", subopt_type, len - 2); switch(subopt_type) { case RPL_OPTION_DAG_METRIC_CONTAINER: if(len < 6) { - PRINTF("RPL: Invalid DAG MC, len = %d\n", len); + LOG_WARN("Invalid DAG MC, len = %d\n", len); RPL_STAT(rpl_stats.malformed_msgs++); goto discard; } @@ -381,7 +382,7 @@ dio_input(void) } else if(dio.mc.type == RPL_DAG_MC_ETX) { dio.mc.obj.etx = get16(buffer, i + 6); - PRINTF("RPL: DAG MC: type %u, flags %u, aggr %u, prec %u, length %u, ETX %u\n", + LOG_DBG("DAG MC: type %u, flags %u, aggr %u, prec %u, length %u, ETX %u\n", (unsigned)dio.mc.type, (unsigned)dio.mc.flags, (unsigned)dio.mc.aggr, @@ -392,13 +393,13 @@ dio_input(void) dio.mc.obj.energy.flags = buffer[i + 6]; dio.mc.obj.energy.energy_est = buffer[i + 7]; } else { - PRINTF("RPL: Unhandled DAG MC type: %u\n", (unsigned)dio.mc.type); + LOG_WARN("Unhandled DAG MC type: %u\n", (unsigned)dio.mc.type); goto discard; } break; case RPL_OPTION_ROUTE_INFO: if(len < 9) { - PRINTF("RPL: Invalid destination prefix option, len = %d\n", len); + LOG_WARN("Invalid destination prefix option, len = %d\n", len); RPL_STAT(rpl_stats.malformed_msgs++); goto discard; } @@ -410,11 +411,11 @@ dio_input(void) if(((dio.destination_prefix.length + 7) / 8) + 8 <= len && dio.destination_prefix.length <= 128) { - PRINTF("RPL: Copying destination prefix\n"); + LOG_INFO("Copying destination prefix\n"); memcpy(&dio.destination_prefix.prefix, &buffer[i + 8], (dio.destination_prefix.length + 7) / 8); } else { - PRINTF("RPL: Invalid route info option, len = %d\n", len); + LOG_WARN("Invalid route info option, len = %d\n", len); RPL_STAT(rpl_stats.malformed_msgs++); goto discard; } @@ -422,7 +423,7 @@ dio_input(void) break; case RPL_OPTION_DAG_CONF: if(len != 16) { - PRINTF("RPL: Invalid DAG configuration option, len = %d\n", len); + LOG_WARN("Invalid DAG configuration option, len = %d\n", len); RPL_STAT(rpl_stats.malformed_msgs++); goto discard; } @@ -437,14 +438,14 @@ dio_input(void) /* buffer + 12 is reserved */ dio.default_lifetime = buffer[i + 13]; dio.lifetime_unit = get16(buffer, i + 14); - PRINTF("RPL: DAG conf:dbl=%d, min=%d red=%d maxinc=%d mininc=%d ocp=%d d_l=%u l_u=%u\n", + LOG_INFO("DAG conf:dbl=%d, min=%d red=%d maxinc=%d mininc=%d ocp=%d d_l=%u l_u=%u\n", dio.dag_intdoubl, dio.dag_intmin, dio.dag_redund, dio.dag_max_rankinc, dio.dag_min_hoprankinc, dio.ocp, dio.default_lifetime, dio.lifetime_unit); break; case RPL_OPTION_PREFIX_INFO: if(len != 32) { - PRINTF("RPL: Invalid DAG prefix info, len != 32\n"); + LOG_WARN("Invalid DAG prefix info, len != 32\n"); RPL_STAT(rpl_stats.malformed_msgs++); goto discard; } @@ -454,11 +455,11 @@ dio_input(void) /* preferred lifetime stored in lifetime */ dio.prefix_info.lifetime = get32(buffer, i + 8); /* 32-bit reserved at i + 12 */ - PRINTF("RPL: Copying prefix information\n"); + LOG_INFO("Copying prefix information\n"); memcpy(&dio.prefix_info.prefix, &buffer[i + 16], 16); break; default: - PRINTF("RPL: Unsupported suboption type in DIO: %u\n", + LOG_WARN("Unsupported suboption type in DIO: %u\n", (unsigned)subopt_type); } } @@ -488,7 +489,7 @@ dio_output(rpl_instance_t *instance, uip_ipaddr_t *uc_addr) /* In leaf mode, we only send DIO messages as unicasts in response to unicast DIS messages. */ if(uc_addr == NULL) { - PRINTF("RPL: LEAF ONLY have multicast addr: skip dio_output\n"); + LOG_DBG("LEAF ONLY have multicast addr: skip dio_output\n"); return; } #endif /* RPL_LEAF_ONLY */ @@ -502,7 +503,7 @@ dio_output(rpl_instance_t *instance, uip_ipaddr_t *uc_addr) is_root = (dag->rank == ROOT_RANK(instance)); #if RPL_LEAF_ONLY - PRINTF("RPL: LEAF ONLY DIO rank set to RPL_INFINITE_RANK\n"); + LOG_DBG("LEAF ONLY DIO rank set to RPL_INFINITE_RANK\n"); set16(buffer, pos, RPL_INFINITE_RANK); #else /* RPL_LEAF_ONLY */ set16(buffer, pos, dag->rank); @@ -553,7 +554,7 @@ dio_output(rpl_instance_t *instance, uip_ipaddr_t *uc_addr) buffer[pos++] = instance->mc.obj.energy.flags; buffer[pos++] = instance->mc.obj.energy.energy_est; } else { - PRINTF("RPL: Unable to send DIO because of unhandled DAG MC type %u\n", + LOG_ERR("Unable to send DIO because of unhandled DAG MC type %u\n", (unsigned)instance->mc.type); return; } @@ -593,37 +594,38 @@ dio_output(rpl_instance_t *instance, uip_ipaddr_t *uc_addr) pos += 4; memcpy(&buffer[pos], &dag->prefix_info.prefix, 16); pos += 16; - PRINTF("RPL: Sending prefix info in DIO for "); - PRINT6ADDR(&dag->prefix_info.prefix); - PRINTF("\n"); + LOG_DBG("Sending prefix info in DIO for "); + LOG_DBG_6ADDR(&dag->prefix_info.prefix); + LOG_DBG_("\n"); } else { - PRINTF("RPL: No prefix to announce (len %d)\n", + LOG_DBG("No prefix to announce (len %d)\n", dag->prefix_info.length); } #if RPL_LEAF_ONLY -#if (DEBUG) & DEBUG_PRINT - if(uc_addr == NULL) { - PRINTF("RPL: LEAF ONLY sending unicast-DIO from multicast-DIO\n"); + if(LOG_DBG_ENABLED) { + if(uc_addr == NULL) { + LOG_DBG("LEAF ONLY sending unicast-DIO from multicast-DIO\n"); + } } -#endif /* DEBUG_PRINT */ - PRINTF("RPL: Sending unicast-DIO with rank %u to ", + + LOG_INFO("Sending unicast-DIO with rank %u to ", (unsigned)dag->rank); - PRINT6ADDR(uc_addr); - PRINTF("\n"); + LOG_INFO_6ADDR(uc_addr); + LOG_INFO_("\n"); uip_icmp6_send(uc_addr, ICMP6_RPL, RPL_CODE_DIO, pos); #else /* RPL_LEAF_ONLY */ /* Unicast requests get unicast replies! */ if(uc_addr == NULL) { - PRINTF("RPL: Sending a multicast-DIO with rank %u\n", + LOG_INFO("Sending a multicast-DIO with rank %u\n", (unsigned)instance->current_dag->rank); uip_create_linklocal_rplnodes_mcast(&addr); uip_icmp6_send(&addr, ICMP6_RPL, RPL_CODE_DIO, pos); } else { - PRINTF("RPL: Sending unicast-DIO with rank %u to ", + LOG_INFO("Sending unicast-DIO with rank %u to ", (unsigned)instance->current_dag->rank); - PRINT6ADDR(uc_addr); - PRINTF("\n"); + LOG_INFO_6ADDR(uc_addr); + LOG_INFO_("\n"); uip_icmp6_send(uc_addr, ICMP6_RPL, RPL_CODE_DIO, pos); } #endif /* RPL_LEAF_ONLY */ @@ -685,7 +687,7 @@ dao_input_storing(void) /* Is the DAG ID present? */ if(flags & RPL_DAO_D_FLAG) { if(memcmp(&dag->dag_id, &buffer[pos], sizeof(dag->dag_id))) { - PRINTF("RPL: Ignoring a DAO for a DAG different from ours\n"); + LOG_INFO("Ignoring a DAO for a DAG different from ours\n"); return; } pos += 16; @@ -695,10 +697,10 @@ dao_input_storing(void) RPL_ROUTE_FROM_MULTICAST_DAO : RPL_ROUTE_FROM_UNICAST_DAO; /* Destination Advertisement Object */ - PRINTF("RPL: Received a (%s) DAO with sequence number %u from ", + LOG_DBG("Received a (%s) DAO with sequence number %u from ", learned_from == RPL_ROUTE_FROM_UNICAST_DAO? "unicast": "multicast", sequence); - PRINT6ADDR(&dao_sender_addr); - PRINTF("\n"); + LOG_DBG_6ADDR(&dao_sender_addr); + LOG_DBG_("\n"); if(learned_from == RPL_ROUTE_FROM_UNICAST_DAO) { /* Check whether this is a DAO forwarding loop. */ @@ -707,7 +709,7 @@ dao_input_storing(void) /* if we already route to this node it is likely */ if(parent != NULL && DAG_RANK(parent->rank, instance) < DAG_RANK(dag->rank, instance)) { - PRINTF("RPL: Loop detected when receiving a unicast DAO from a node with a lower rank! (%u < %u)\n", + LOG_WARN("Loop detected when receiving a unicast DAO from a node with a lower rank! (%u < %u)\n", DAG_RANK(parent->rank, instance), DAG_RANK(dag->rank, instance)); parent->rank = RPL_INFINITE_RANK; parent->flags |= RPL_PARENT_FLAG_UPDATED; @@ -716,7 +718,7 @@ dao_input_storing(void) /* If we get the DAO from our parent, we also have a loop. */ if(parent != NULL && parent == dag->preferred_parent) { - PRINTF("RPL: Loop detected when receiving a unicast DAO from our parent\n"); + LOG_WARN("Loop detected when receiving a unicast DAO from our parent\n"); parent->rank = RPL_INFINITE_RANK; parent->flags |= RPL_PARENT_FLAG_UPDATED; return; @@ -750,10 +752,10 @@ dao_input_storing(void) } } - PRINTF("RPL: DAO lifetime: %u, prefix length: %u prefix: ", + LOG_INFO("DAO lifetime: %u, prefix length: %u prefix: ", (unsigned)lifetime, (unsigned)prefixlen); - PRINT6ADDR(&prefix); - PRINTF("\n"); + LOG_INFO_6ADDR(&prefix); + LOG_INFO_("\n"); #if RPL_WITH_MULTICAST if(uip_is_addr_mcast_global(&prefix)) { @@ -774,16 +776,16 @@ dao_input_storing(void) rep = uip_ds6_route_lookup(&prefix); if(lifetime == RPL_ZERO_LIFETIME) { - PRINTF("RPL: No-Path DAO received\n"); + LOG_INFO("No-Path DAO received\n"); /* No-Path DAO received; invoke the route purging routine. */ if(rep != NULL && !RPL_ROUTE_IS_NOPATH_RECEIVED(rep) && rep->length == prefixlen && uip_ds6_route_nexthop(rep) != NULL && uip_ipaddr_cmp(uip_ds6_route_nexthop(rep), &dao_sender_addr)) { - PRINTF("RPL: Setting expiration timer for prefix "); - PRINT6ADDR(&prefix); - PRINTF("\n"); + LOG_DBG("Setting expiration timer for prefix "); + LOG_DBG_6ADDR(&prefix); + LOG_DBG_("\n"); RPL_ROUTE_SET_NOPATH_RECEIVED(rep); rep->state.lifetime = RPL_NOPATH_REMOVAL_DELAY; @@ -794,10 +796,10 @@ dao_input_storing(void) uint8_t out_seq; out_seq = prepare_for_dao_fwd(sequence, rep); - PRINTF("RPL: Forwarding No-path DAO to parent - out_seq:%d", + LOG_DBG("Forwarding No-path DAO to parent - out_seq:%d", out_seq); - PRINT6ADDR(rpl_parent_get_ipaddr(dag->preferred_parent)); - PRINTF("\n"); + LOG_DBG_6ADDR(rpl_parent_get_ipaddr(dag->preferred_parent)); + LOG_DBG_("\n"); buffer = UIP_ICMP_PAYLOAD; buffer[3] = out_seq; /* add an outgoing seq no before fwd */ @@ -815,15 +817,15 @@ dao_input_storing(void) return; } - PRINTF("RPL: Adding DAO route\n"); + LOG_INFO("Adding DAO route\n"); /* Update and add neighbor - if no room - fail. */ if((nbr = rpl_icmp6_update_nbr_table(&dao_sender_addr, NBR_TABLE_REASON_RPL_DAO, instance)) == NULL) { - PRINTF("RPL: Out of Memory, dropping DAO from "); - PRINT6ADDR(&dao_sender_addr); - PRINTF(", "); - PRINTLLADDR((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER)); - PRINTF("\n"); + LOG_ERR("Out of Memory, dropping DAO from "); + LOG_ERR_6ADDR(&dao_sender_addr); + LOG_ERR_(", "); + LOG_ERR_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER)); + LOG_ERR_("\n"); if(flags & RPL_DAO_K_FLAG) { /* signal the failure to add the node */ dao_ack_output(instance, &dao_sender_addr, sequence, @@ -836,7 +838,7 @@ dao_input_storing(void) rep = rpl_add_route(dag, &prefix, prefixlen, &dao_sender_addr); if(rep == NULL) { RPL_STAT(rpl_stats.mem_overflows++); - PRINTF("RPL: Could not add a route after receiving a DAO\n"); + LOG_ERR("Could not add a route after receiving a DAO\n"); if(flags & RPL_DAO_K_FLAG) { /* signal the failure to add the node */ dao_ack_output(instance, &dao_sender_addr, sequence, @@ -887,9 +889,9 @@ fwd_dao: } } - PRINTF("RPL: Forwarding DAO to parent "); - PRINT6ADDR(rpl_parent_get_ipaddr(dag->preferred_parent)); - PRINTF(" in seq: %d out seq: %d\n", sequence, out_seq); + LOG_DBG("Forwarding DAO to parent "); + LOG_DBG_6ADDR(rpl_parent_get_ipaddr(dag->preferred_parent)); + LOG_DBG_(" in seq: %d out seq: %d\n", sequence, out_seq); buffer = UIP_ICMP_PAYLOAD; buffer[3] = out_seq; /* add an outgoing seq no before fwd */ @@ -897,7 +899,7 @@ fwd_dao: ICMP6_RPL, RPL_CODE_DAO, buffer_length); } if(should_ack) { - PRINTF("RPL: Sending DAO ACK\n"); + LOG_DBG("Sending DAO ACK\n"); uip_clear_buf(); dao_ack_output(instance, &dao_sender_addr, sequence, RPL_DAO_ACK_UNCONDITIONAL_ACCEPT); @@ -927,6 +929,11 @@ dao_input_nonstoring(void) int len; int i; + /* Destination Advertisement Object */ + LOG_INFO("Received a DAO from "); + LOG_INFO_6ADDR(&UIP_IP_BUF->srcipaddr); + LOG_INFO_("\n"); + prefixlen = 0; uip_ipaddr_copy(&dao_sender_addr, &UIP_IP_BUF->srcipaddr); @@ -949,7 +956,7 @@ dao_input_nonstoring(void) /* Is the DAG ID present? */ if(flags & RPL_DAO_D_FLAG) { if(memcmp(&dag->dag_id, &buffer[pos], sizeof(dag->dag_id))) { - PRINTF("RPL: Ignoring a DAO for a DAG different from ours\n"); + LOG_INFO("Ignoring a DAO for a DAG different from ours\n"); return; } pos += 16; @@ -984,25 +991,29 @@ dao_input_nonstoring(void) } } - PRINTF("RPL: DAO lifetime: %u, prefix length: %u prefix: ", + LOG_INFO("DAO lifetime: %u, prefix length: %u prefix: ", (unsigned)lifetime, (unsigned)prefixlen); - PRINT6ADDR(&prefix); - PRINTF(", parent: "); - PRINT6ADDR(&dao_parent_addr); - PRINTF(" \n"); + LOG_INFO_6ADDR(&prefix); + LOG_INFO_(", parent: "); + LOG_INFO_6ADDR(&dao_parent_addr); + LOG_INFO_("\n"); if(lifetime == RPL_ZERO_LIFETIME) { - PRINTF("RPL: No-Path DAO received\n"); + LOG_DBG("No-Path DAO received\n"); uip_sr_expire_parent(dag, &prefix, &dao_parent_addr); } else { if(uip_sr_update_node(dag, &prefix, &dao_parent_addr, RPL_LIFETIME(instance, lifetime)) == NULL) { - PRINTF("RPL: failed to add link\n"); + LOG_WARN("DAO failed to add link prefix: "); + LOG_WARN_6ADDR(&prefix); + LOG_WARN_(", parent: "); + LOG_WARN_6ADDR(&dao_parent_addr); + LOG_WARN_("\n"); return; } } if(flags & RPL_DAO_K_FLAG) { - PRINTF("RPL: Sending DAO ACK\n"); + LOG_DBG("Sending DAO ACK\n"); uip_clear_buf(); dao_ack_output(instance, &dao_sender_addr, sequence, RPL_DAO_ACK_UNCONDITIONAL_ACCEPT); @@ -1017,14 +1028,14 @@ dao_input(void) uint8_t instance_id; /* Destination Advertisement Object */ - PRINTF("RPL: Received a DAO from "); - PRINT6ADDR(&UIP_IP_BUF->srcipaddr); - PRINTF("\n"); + LOG_INFO("Received a DAO from "); + LOG_INFO_6ADDR(&UIP_IP_BUF->srcipaddr); + LOG_INFO_("\n"); instance_id = UIP_ICMP_PAYLOAD[0]; instance = rpl_get_instance(instance_id); if(instance == NULL) { - PRINTF("RPL: Ignoring a DAO for an unknown RPL instance(%u)\n", + LOG_INFO("Ignoring a DAO for an unknown RPL instance(%u)\n", instance_id); goto discard; } @@ -1076,7 +1087,7 @@ handle_dao_retransmission(void *ptr) return; } - PRINTF("RPL: will retransmit DAO - seq:%d trans:%d\n", instance->my_dao_seqno, + LOG_INFO("will retransmit DAO - seq:%d trans:%d\n", instance->my_dao_seqno, instance->my_dao_transmissions); if(get_global_addr(&prefix) == 0) { @@ -1101,7 +1112,7 @@ dao_output(rpl_parent_t *parent, uint8_t lifetime) uip_ipaddr_t prefix; if(get_global_addr(&prefix) == 0) { - PRINTF("RPL: No global address set for this node - suppressing DAO\n"); + LOG_ERR("No global address set for this node - suppressing DAO\n"); return; } @@ -1159,30 +1170,30 @@ dao_output_target_seq(rpl_parent_t *parent, uip_ipaddr_t *prefix, } if(parent == NULL) { - PRINTF("RPL dao_output_target error parent NULL\n"); + LOG_ERR("dao_output_target error parent NULL\n"); return; } parent_ipaddr = rpl_parent_get_ipaddr(parent); if(parent_ipaddr == NULL) { - PRINTF("RPL dao_output_target error parent IP address NULL\n"); + LOG_ERR("dao_output_target error parent IP address NULL\n"); return; } dag = parent->dag; if(dag == NULL) { - PRINTF("RPL dao_output_target error dag NULL\n"); + LOG_ERR("dao_output_target error dag NULL\n"); return; } instance = dag->instance; if(instance == NULL) { - PRINTF("RPL dao_output_target error instance NULL\n"); + LOG_ERR("dao_output_target error instance NULL\n"); return; } if(prefix == NULL) { - PRINTF("RPL dao_output_target error prefix NULL\n"); + LOG_ERR("dao_output_target error prefix NULL\n"); return; } #ifdef RPL_DEBUG_DAO_OUTPUT @@ -1240,15 +1251,15 @@ dao_output_target_seq(rpl_parent_t *parent, uip_ipaddr_t *prefix, dest_ipaddr = &parent->dag->dag_id; } - PRINTF("RPL: Sending a %sDAO with sequence number %u, lifetime %u, prefix ", + LOG_INFO("Sending a %sDAO with sequence number %u, lifetime %u, prefix ", lifetime == RPL_ZERO_LIFETIME ? "No-Path " : "", seq_no, lifetime); - PRINT6ADDR(prefix); - PRINTF(" to "); - PRINT6ADDR(dest_ipaddr); - PRINTF(" , parent "); - PRINT6ADDR(parent_ipaddr); - PRINTF("\n"); + LOG_INFO_6ADDR(prefix); + LOG_INFO_(" to "); + LOG_INFO_6ADDR(dest_ipaddr); + LOG_INFO_(" , parent "); + LOG_INFO_6ADDR(parent_ipaddr); + LOG_INFO_("\n"); if(dest_ipaddr != NULL) { uip_icmp6_send(dest_ipaddr, ICMP6_RPL, RPL_CODE_DAO, pos); @@ -1291,16 +1302,16 @@ dao_ack_input(void) } if(instance->current_dag->rank == ROOT_RANK(instance)) { - PRINTF("RPL: DODAG root received a DAO ACK, ignoring it\n"); + LOG_DBG("DODAG root received a DAO ACK, ignoring it\n"); uip_clear_buf(); return; } - PRINTF("RPL: Received a DAO %s with sequence number %d (%d) and status %d from ", + LOG_INFO("Received a DAO %s with sequence number %d (%d) and status %d from ", status < 128 ? "ACK" : "NACK", sequence, instance->my_dao_seqno, status); - PRINT6ADDR(&UIP_IP_BUF->srcipaddr); - PRINTF("\n"); + LOG_INFO_6ADDR(&UIP_IP_BUF->srcipaddr); + LOG_INFO_("\n"); if(sequence == instance->my_dao_seqno) { instance->has_downward_route = status < 128; @@ -1334,11 +1345,11 @@ dao_ack_input(void) nexthop = uip_ds6_route_nexthop(re); if(nexthop == NULL) { - PRINTF("RPL: No next hop to fwd DAO ACK to\n"); + LOG_WARN("No next hop to fwd DAO ACK to\n"); } else { - PRINTF("RPL: Fwd DAO ACK to:"); - PRINT6ADDR(nexthop); - PRINTF("\n"); + LOG_INFO("Fwd DAO ACK to:"); + LOG_INFO_6ADDR(nexthop); + LOG_INFO_("\n"); buffer[2] = re->state.dao_seqno_in; uip_icmp6_send(nexthop, ICMP6_RPL, RPL_CODE_DAO_ACK, 4); } @@ -1348,7 +1359,7 @@ dao_ack_input(void) uip_ds6_route_rm(re); } } else { - PRINTF("RPL: No route entry found to forward DAO ACK (seqno %u)\n", sequence); + LOG_WARN("No route entry found to forward DAO ACK (seqno %u)\n", sequence); } } #endif /* RPL_WITH_DAO_ACK */ @@ -1362,9 +1373,9 @@ dao_ack_output(rpl_instance_t *instance, uip_ipaddr_t *dest, uint8_t sequence, #if RPL_WITH_DAO_ACK unsigned char *buffer; - PRINTF("RPL: Sending a DAO %s with sequence number %d to ", status < 128 ? "ACK" : "NACK", sequence); - PRINT6ADDR(dest); - PRINTF(" with status %d\n", status); + LOG_INFO("Sending a DAO %s with sequence number %d to ", status < 128 ? "ACK" : "NACK", sequence); + LOG_INFO_6ADDR(dest); + LOG_INFO_(" with status %d\n", status); buffer = UIP_ICMP_PAYLOAD; diff --git a/os/net/routing/rpl-classic/rpl-mrhof.c b/os/net/routing/rpl-classic/rpl-mrhof.c index f3c75985b..988991b19 100644 --- a/os/net/routing/rpl-classic/rpl-mrhof.c +++ b/os/net/routing/rpl-classic/rpl-mrhof.c @@ -51,8 +51,10 @@ #include "net/nbr-table.h" #include "net/link-stats.h" -#define DEBUG DEBUG_NONE -#include "net/ipv6/uip-debug.h" +#include "sys/log.h" + +#define LOG_MODULE "RPL" +#define LOG_LEVEL LOG_LEVEL_RPL /* RFC6551 and RFC6719 do not mandate the use of a specific formula to * compute the ETX value. This MRHOF implementation relies on the value @@ -97,7 +99,7 @@ to the threshold of 96 in the non-squared case) */ static void reset(rpl_dag_t *dag) { - PRINTF("RPL: Reset MRHOF\n"); + LOG_INFO("Reset MRHOF\n"); } /*---------------------------------------------------------------------------*/ #if RPL_WITH_DAO_ACK @@ -108,7 +110,7 @@ dao_ack_callback(rpl_parent_t *p, int status) return; } /* here we need to handle failed DAO's and other stuff */ - PRINTF("RPL: MRHOF - DAO ACK received with status: %d\n", status); + LOG_DBG("MRHOF - DAO ACK received with status: %d\n", status); if(status >= RPL_DAO_ACK_UNABLE_TO_ACCEPT) { /* punish the ETX as if this was 10 packets lost */ link_stats_packet_sent(rpl_get_parent_lladdr(p), MAC_TX_OK, 10); @@ -262,7 +264,7 @@ update_metric_container(rpl_instance_t *instance) dag = instance->current_dag; if(dag == NULL || !dag->joined) { - PRINTF("RPL: Cannot update the metric container when not joined\n"); + LOG_WARN("Cannot update the metric container when not joined\n"); return; } @@ -297,7 +299,7 @@ update_metric_container(rpl_instance_t *instance) instance->mc.obj.energy.energy_est = path_cost >> 8; break; default: - PRINTF("RPL: MRHOF, non-supported MC %u\n", instance->mc.type); + LOG_WARN("MRHOF, non-supported MC %u\n", instance->mc.type); break; } } diff --git a/os/net/routing/rpl-classic/rpl-nbr-policy.c b/os/net/routing/rpl-classic/rpl-nbr-policy.c index 077977a10..344840d0e 100644 --- a/os/net/routing/rpl-classic/rpl-nbr-policy.c +++ b/os/net/routing/rpl-classic/rpl-nbr-policy.c @@ -49,8 +49,10 @@ #include "net/ipv6/uip-ds6-nbr.h" #include "net/ipv6/uip-ds6-route.h" -#define DEBUG DEBUG_NONE -#include "net/ipv6/uip-debug.h" +#include "sys/log.h" + +#define LOG_MODULE "RPL" +#define LOG_LEVEL LOG_LEVEL_RPL /* * Policy for neighbor adds @@ -71,7 +73,7 @@ static int num_free; static linkaddr_t *worst_rank_nbr; /* the parent that has the worst rank */ static rpl_rank_t worst_rank; /*---------------------------------------------------------------------------*/ -#if DEBUG == DEBUG_FULL +#if LOG_DBG_ENABLED /* * This create a periodic call of the update_nbr function that will print * useful debugging information when in DEBUG_FULL mode @@ -85,7 +87,7 @@ handle_periodic_timer(void *ptr) update_nbr(); ctimer_restart(&periodic_timer); } -#endif /* DEBUG == DEBUG_FULL */ +#endif /* LOG_DBG_ENABLED */ /*---------------------------------------------------------------------------*/ static void update_nbr(void) @@ -96,13 +98,13 @@ update_nbr(void) int is_used; rpl_rank_t rank; -#if DEBUG == DEBUG_FULL - if(!timer_init) { - timer_init = 1; - ctimer_set(&periodic_timer, 60 * CLOCK_SECOND, - &handle_periodic_timer, NULL); - } -#endif /* DEBUG == DEBUG_FULL */ +#if LOG_DBG_ENABLED + if(!timer_init) { + timer_init = 1; + ctimer_set(&periodic_timer, 60 * CLOCK_SECOND, + &handle_periodic_timer, NULL); + } +#endif /* LOG_DBG_ENABLED */ worst_rank = 0; worst_rank_nbr = NULL; @@ -152,9 +154,9 @@ update_nbr(void) worst_rank_nbr = lladdr; worst_rank = RPL_INFINITE_RANK; } else if(is_used > 1) { - PRINTF("NBR-POLICY: *** Neighbor is both child and candidate parent: "); - PRINTLLADDR((uip_lladdr_t *)lladdr); - PRINTF("\n"); + LOG_DBG("nbr-policy: *** neighbor is both child and candidate parent: "); + LOG_DBG_LLADDR(lladdr); + LOG_DBG_("\n"); } nbr = nbr_table_next(ds6_neighbors, nbr); @@ -163,7 +165,7 @@ update_nbr(void) /* how many more IP neighbors can be have? */ num_free = NBR_TABLE_MAX_NEIGHBORS - num_used; - PRINTF("NBR-POLICY: Free: %d, Children: %d, Parents: %d Routes: %d\n", + LOG_DBG("nbr-policy: free: %d, children: %d, parents: %d routes: %d\n", num_free, num_children, num_parents, uip_ds6_route_num_routes()); } /*---------------------------------------------------------------------------*/ @@ -177,7 +179,7 @@ find_removable_dis(uip_ipaddr_t *from) if(num_free > 0) { /* there are free entries (e.g. unsused by RPL and ND6) but since it is used by other modules we can not pick these entries for removal. */ - PRINTF("Num-free > 0 = %d - Other for RPL/ND6 unused NBR entry exists .", + LOG_DBG("nbr-policy: num-free > 0 = %d - Other for RPL/ND6 unused NBR entry exists.\n", num_free); } if(num_children < MAX_CHILDREN) { @@ -195,20 +197,20 @@ find_removable_dio(uip_ipaddr_t *from, rpl_dio_t *dio) instance = rpl_get_instance(dio->instance_id); if(instance == NULL || instance->current_dag == NULL) { - PRINTF("Did not find instance id: %d\n", dio->instance_id); + LOG_WARN("nbr-policy: did not find instance id: %d\n", dio->instance_id); return NULL; } /* Add the new neighbor only if it is better than the worst parent. */ if(dio->rank + instance->min_hoprankinc < worst_rank - instance->min_hoprankinc / 2) { /* Found *great* neighbor - add! */ - PRINTF("Found better neighbor %d < %d - add to cache...\n", + LOG_DBG("nbr-policy: DIO rank %u, worst_rank %u -- add to cache\n", dio->rank, worst_rank); return worst_rank_nbr; } - PRINTF("Found worse neighbor with new %d and old %d - NOT add to cache.\n", + LOG_DBG("nbr-policy: DIO rank %u, worst_rank %u -- do not add to cache\n", dio->rank, worst_rank); return NULL; } @@ -229,7 +231,7 @@ find_removable_dao(uip_ipaddr_t *from, rpl_instance_t *instance) /* Check if this DAO sender is not yet neighbor and there is already too many children. */ if(num_children >= max) { - PRINTF("Can not add another child - already at max.\n"); + LOG_ERR("nbr-policy: can not add another child - already at max.\n"); return NULL; } /* remove the worst ranked nbr */ diff --git a/os/net/routing/rpl-classic/rpl-of0.c b/os/net/routing/rpl-classic/rpl-of0.c index 1a679d23b..602b8934d 100644 --- a/os/net/routing/rpl-classic/rpl-of0.c +++ b/os/net/routing/rpl-classic/rpl-of0.c @@ -47,8 +47,10 @@ #include "net/nbr-table.h" #include "net/link-stats.h" -#define DEBUG DEBUG_NONE -#include "net/ipv6/uip-debug.h" +#include "sys/log.h" + +#define LOG_MODULE "RPL" +#define LOG_LEVEL LOG_LEVEL_RPL /* Constants from RFC6552. We use the default values. */ #define RANK_STRETCH 0 /* Must be in the range [0;5] */ @@ -87,7 +89,7 @@ static void reset(rpl_dag_t *dag) { - PRINTF("RPL: Reset OF0\n"); + LOG_INFO("Reset OF0\n"); } /*---------------------------------------------------------------------------*/ #if RPL_WITH_DAO_ACK @@ -98,7 +100,7 @@ dao_ack_callback(rpl_parent_t *p, int status) return; } /* here we need to handle failed DAO's and other stuff */ - PRINTF("RPL: OF0 - DAO ACK received with status: %d\n", status); + LOG_DBG("OF0 - DAO ACK received with status: %d\n", status); if(status >= RPL_DAO_ACK_UNABLE_TO_ACCEPT) { /* punish the ETX as if this was 10 packets lost */ link_stats_packet_sent(rpl_get_parent_lladdr(p), MAC_TX_OK, 10); diff --git a/os/net/routing/rpl-classic/rpl-timers.c b/os/net/routing/rpl-classic/rpl-timers.c index 97233f574..0bcfc57dd 100644 --- a/os/net/routing/rpl-classic/rpl-timers.c +++ b/os/net/routing/rpl-classic/rpl-timers.c @@ -48,9 +48,10 @@ #include "net/ipv6/uip-sr.h" #include "lib/random.h" #include "sys/ctimer.h" +#include "sys/log.h" -#define DEBUG DEBUG_NONE -#include "net/ipv6/uip-debug.h" +#define LOG_MODULE "RPL" +#define LOG_LEVEL LOG_LEVEL_RPL /* A configurable function called after update of the RPL DIO interval */ #ifdef RPL_CALLBACK_NEW_DIO_INTERVAL @@ -133,7 +134,7 @@ new_dio_interval(rpl_instance_t *instance) /* keep some stats */ instance->dio_totint++; instance->dio_totrecv += instance->dio_counter; - ANNOTATE("#A rank=%u.%u(%u),stats=%d %d %d %d,color=%s\n", + LOG_ANNOTATE("#A rank=%u.%u(%u),stats=%d %d %d %d,color=%s\n", DAG_RANK(instance->current_dag->rank, instance), (10 * (instance->current_dag->rank % instance->min_hoprankinc)) / instance->min_hoprankinc, instance->current_dag->version, @@ -146,7 +147,7 @@ new_dio_interval(rpl_instance_t *instance) instance->dio_counter = 0; /* schedule the timer */ - PRINTF("RPL: Scheduling DIO timer %lu ticks in future (Interval)\n", ticks); + LOG_INFO("Scheduling DIO timer %lu ticks in future (Interval)\n", ticks); ctimer_set(&instance->dio_timer, ticks, &handle_dio_timer, instance); #ifdef RPL_CALLBACK_NEW_DIO_INTERVAL @@ -161,12 +162,12 @@ handle_dio_timer(void *ptr) instance = (rpl_instance_t *)ptr; - PRINTF("RPL: DIO Timer triggered\n"); + LOG_DBG("DIO Timer triggered\n"); if(!dio_send_ok) { if(uip_ds6_get_link_local(ADDR_PREFERRED) != NULL) { dio_send_ok = 1; } else { - PRINTF("RPL: Postponing DIO transmission since link local address is not ok\n"); + LOG_WARN("Postponing DIO transmission since link local address is not ok\n"); ctimer_set(&instance->dio_timer, CLOCK_SECOND, &handle_dio_timer, instance); return; } @@ -180,25 +181,25 @@ handle_dio_timer(void *ptr) #endif /* RPL_CONF_STATS */ dio_output(instance, NULL); } else { - PRINTF("RPL: Suppressing DIO transmission (%d >= %d)\n", + LOG_DBG("Suppressing DIO transmission (%d >= %d)\n", instance->dio_counter, instance->dio_redundancy); } instance->dio_send = 0; - PRINTF("RPL: Scheduling DIO timer %lu ticks in future (sent)\n", + LOG_DBG("Scheduling DIO timer %lu ticks in future (sent)\n", instance->dio_next_delay); ctimer_set(&instance->dio_timer, instance->dio_next_delay, handle_dio_timer, instance); } else { /* check if we need to double interval */ if(instance->dio_intcurrent < instance->dio_intmin + instance->dio_intdoubl) { instance->dio_intcurrent++; - PRINTF("RPL: DIO Timer interval doubled %d\n", instance->dio_intcurrent); + LOG_DBG("DIO Timer interval doubled %d\n", instance->dio_intcurrent); } new_dio_interval(instance); } -#if DEBUG - rpl_print_neighbor_list(); -#endif + if(LOG_DBG_ENABLED) { + rpl_print_neighbor_list(); + } } /*---------------------------------------------------------------------------*/ void @@ -245,7 +246,7 @@ set_dao_lifetime_timer(rpl_instance_t *instance) CLOCK_SECOND / 2; /* make the time for the re registration be betwen 1/2 - 3/4 of lifetime */ expiration_time = expiration_time + (random_rand() % (expiration_time / 2)); - PRINTF("RPL: Scheduling DAO lifetime timer %u ticks in the future\n", + LOG_DBG("Scheduling DAO lifetime timer %u ticks in the future\n", (unsigned)expiration_time); ctimer_set(&instance->dao_lifetime_timer, expiration_time, handle_dao_timer, instance); @@ -264,14 +265,14 @@ handle_dao_timer(void *ptr) instance = (rpl_instance_t *)ptr; if(!dio_send_ok && uip_ds6_get_link_local(ADDR_PREFERRED) == NULL) { - PRINTF("RPL: Postpone DAO transmission\n"); + LOG_INFO("Postpone DAO transmission\n"); ctimer_set(&instance->dao_timer, CLOCK_SECOND, handle_dao_timer, instance); return; } /* Send the DAO to the DAO parent set -- the preferred parent in our case. */ if(instance->current_dag->preferred_parent != NULL) { - PRINTF("RPL: handle_dao_timer - sending DAO\n"); + LOG_INFO("handle_dao_timer - sending DAO\n"); /* Set the route lifetime to the default value. */ dao_output(instance->current_dag->preferred_parent, instance->default_lifetime); @@ -300,7 +301,7 @@ handle_dao_timer(void *ptr) } #endif } else { - PRINTF("RPL: No suitable DAO parent\n"); + LOG_INFO("No suitable DAO parent\n"); } ctimer_stop(&instance->dao_timer); @@ -322,7 +323,7 @@ schedule_dao(rpl_instance_t *instance, clock_time_t latency) expiration_time = etimer_expiration_time(&instance->dao_timer.etimer); if(!etimer_expired(&instance->dao_timer.etimer)) { - PRINTF("RPL: DAO timer already scheduled\n"); + LOG_DBG("DAO timer already scheduled\n"); } else { if(latency != 0) { expiration_time = latency / 2 + @@ -330,7 +331,7 @@ schedule_dao(rpl_instance_t *instance, clock_time_t latency) } else { expiration_time = 0; } - PRINTF("RPL: Scheduling DAO timer %u ticks in the future\n", + LOG_DBG("Scheduling DAO timer %u ticks in the future\n", (unsigned)expiration_time); ctimer_set(&instance->dao_timer, expiration_time, handle_dao_timer, instance); @@ -479,7 +480,7 @@ handle_probing_timer(void *ptr) if(target_ipaddr != NULL) { const struct link_stats *stats = rpl_get_parent_link_stats(probing_target); (void)stats; - PRINTF("RPL: probing %u %s last tx %u min ago\n", + LOG_INFO("probing %u %s last tx %u min ago\n", rpl_get_parent_lladdr(probing_target)->u8[7], instance->urgent_probing_target != NULL ? "(urgent)" : "", probing_target != NULL ? @@ -492,9 +493,9 @@ handle_probing_timer(void *ptr) /* Schedule next probing */ rpl_schedule_probing(instance); -#if DEBUG - rpl_print_neighbor_list(); -#endif + if(LOG_DBG_ENABLED) { + rpl_print_neighbor_list(); + } } /*---------------------------------------------------------------------------*/ void diff --git a/os/net/routing/rpl-classic/rpl.c b/os/net/routing/rpl-classic/rpl.c index ecbcdc158..d4929d993 100644 --- a/os/net/routing/rpl-classic/rpl.c +++ b/os/net/routing/rpl-classic/rpl.c @@ -52,12 +52,14 @@ #include "net/routing/rpl-classic/rpl-dag-root.h" #include "net/ipv6/multicast/uip-mcast6.h" -#define DEBUG DEBUG_NONE -#include "net/ipv6/uip-debug.h" +#include "sys/log.h" #include #include +#define LOG_MODULE "RPL" +#define LOG_LEVEL LOG_LEVEL_RPL + #if RPL_CONF_STATS rpl_stats_t rpl_stats; #endif @@ -83,7 +85,7 @@ rpl_set_mode(enum rpl_mode m) inform our parent that we now are reachable. Before we do this, we must set the mode variable, since DAOs will not be sent if we are in feather mode. */ - PRINTF("RPL: switching to mesh mode\n"); + LOG_DBG("rpl_set_mode: switching to mesh mode\n"); mode = m; if(default_instance != NULL) { @@ -91,15 +93,15 @@ rpl_set_mode(enum rpl_mode m) } } else if(m == RPL_MODE_FEATHER) { - PRINTF("RPL: switching to feather mode\n"); + LOG_INFO("rpl_set_mode: switching to feather mode\n"); if(default_instance != NULL) { - PRINTF("rpl_set_mode: RPL sending DAO with zero lifetime\n"); + LOG_INFO("rpl_set_mode: RPL sending DAO with zero lifetime\n"); if(default_instance->current_dag != NULL) { dao_output(default_instance->current_dag->preferred_parent, RPL_ZERO_LIFETIME); } rpl_cancel_dao(default_instance); } else { - PRINTF("rpl_set_mode: no default instance\n"); + LOG_INFO("rpl_set_mode: no default instance\n"); } mode = m; @@ -145,17 +147,17 @@ rpl_purge_routes(void) uip_ipaddr_copy(&prefix, &r->ipaddr); uip_ds6_route_rm(r); r = uip_ds6_route_head(); - PRINTF("No more routes to "); - PRINT6ADDR(&prefix); + LOG_INFO("No more routes to "); + LOG_INFO_6ADDR(&prefix); dag = default_instance->current_dag; /* Propagate this information with a No-Path DAO to preferred parent if we are not a RPL Root */ if(dag->rank != ROOT_RANK(default_instance)) { - PRINTF(" -> generate No-Path DAO\n"); + LOG_INFO_(" -> generate No-Path DAO\n"); dao_output_target(dag->preferred_parent, &prefix, RPL_ZERO_LIFETIME); /* Don't schedule more than 1 No-Path DAO, let next iteration handle that */ return; } - PRINTF("\n"); + LOG_INFO_("\n"); } else { r = uip_ds6_route_next(r); } @@ -223,7 +225,7 @@ rpl_remove_routes_by_nexthop(uip_ipaddr_t *nexthop, rpl_dag_t *dag) } r = uip_ds6_route_next(r); } - ANNOTATE("#L %u 0\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]); + LOG_ANNOTATE("#L %u 0\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]); } /*---------------------------------------------------------------------------*/ uip_ds6_route_t * @@ -233,7 +235,7 @@ rpl_add_route(rpl_dag_t *dag, uip_ipaddr_t *prefix, int prefix_len, uip_ds6_route_t *rep; if((rep = uip_ds6_route_add(prefix, prefix_len, next_hop)) == NULL) { - PRINTF("RPL: No space for more route entries\n"); + LOG_ERR("No space for more route entries\n"); return NULL; } @@ -242,11 +244,11 @@ rpl_add_route(rpl_dag_t *dag, uip_ipaddr_t *prefix, int prefix_len, /* always clear state flags for the no-path received when adding/refreshing */ RPL_ROUTE_CLEAR_NOPATH_RECEIVED(rep); - PRINTF("RPL: Added a route to "); - PRINT6ADDR(prefix); - PRINTF("/%d via ", prefix_len); - PRINT6ADDR(next_hop); - PRINTF("\n"); + LOG_INFO("Added a route to "); + LOG_INFO_6ADDR(prefix); + LOG_INFO_("/%d via ", prefix_len); + LOG_INFO_6ADDR(next_hop); + LOG_INFO_("\n"); return rep; } @@ -272,7 +274,7 @@ rpl_link_callback(const linkaddr_t *addr, int status, int numtx) instance->urgent_probing_target = NULL; } /* Trigger DAG rank recalculation. */ - PRINTF("RPL: rpl_link_callback triggering update\n"); + LOG_DBG("rpl_link_callback triggering update\n"); parent->flags |= RPL_PARENT_FLAG_UPDATED; } } @@ -286,12 +288,12 @@ rpl_ipv6_neighbor_callback(uip_ds6_nbr_t *nbr) rpl_instance_t *instance; rpl_instance_t *end; - PRINTF("RPL: Neighbor state changed for "); - PRINT6ADDR(&nbr->ipaddr); + LOG_DBG("Neighbor state changed for "); + LOG_DBG_6ADDR(&nbr->ipaddr); #if UIP_ND6_SEND_NS || UIP_ND6_SEND_RA - PRINTF(", nscount=%u, state=%u\n", nbr->nscount, nbr->state); + LOG_DBG_(", nscount=%u, state=%u\n", nbr->nscount, nbr->state); #else /* UIP_ND6_SEND_NS || UIP_ND6_SEND_RA */ - PRINTF(", state=%u\n", nbr->state); + LOG_DBG_(", state=%u\n", nbr->state); #endif /* UIP_ND6_SEND_NS || UIP_ND6_SEND_RA */ for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES; instance < end; ++instance) { if(instance->used == 1 ) { @@ -299,7 +301,7 @@ rpl_ipv6_neighbor_callback(uip_ds6_nbr_t *nbr) if(p != NULL) { p->rank = RPL_INFINITE_RANK; /* Trigger DAG rank recalculation. */ - PRINTF("RPL: rpl_ipv6_neighbor_callback infinite rank\n"); + LOG_DBG("rpl_ipv6_neighbor_callback infinite rank\n"); p->flags |= RPL_PARENT_FLAG_UPDATED; } } @@ -320,9 +322,9 @@ rpl_purge_dags(void) if(instance->dag_table[i].used) { if(instance->dag_table[i].lifetime == 0) { if(!instance->dag_table[i].joined) { - PRINTF("Removing dag "); - PRINT6ADDR(&instance->dag_table[i].dag_id); - PRINTF("\n"); + LOG_INFO("Removing dag "); + LOG_INFO_6ADDR(&instance->dag_table[i].dag_id); + LOG_INFO_("\n"); rpl_free_dag(&instance->dag_table[i]); } } else { @@ -338,7 +340,7 @@ static void init(void) { uip_ipaddr_t rplmaddr; - PRINTF("RPL started\n"); + LOG_INFO("rpl-classic started\n"); default_instance = NULL; rpl_dag_init(); @@ -403,7 +405,7 @@ drop_route(uip_ds6_route_t *route) static void leave_network(void) { - PRINTF("RPL: leave_network not supported in RPL Classic\n"); + LOG_ERR("leave_network not supported in RPL Classic\n"); } /*---------------------------------------------------------------------------*/ static int From 54e5944d89853634b12540431a762eb6cf3de7d5 Mon Sep 17 00:00:00 2001 From: Olav Frengstad Date: Fri, 31 Aug 2018 14:56:11 +0200 Subject: [PATCH 328/485] RPL-CLASSIC: Add guard for urgent probing Compiling with RPL_CONF_WITH_PROBING := 0 was not possible due to `urgent_probing_target` not present. --- os/net/routing/rpl-classic/rpl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/os/net/routing/rpl-classic/rpl.c b/os/net/routing/rpl-classic/rpl.c index ecbcdc158..751bc6ef1 100644 --- a/os/net/routing/rpl-classic/rpl.c +++ b/os/net/routing/rpl-classic/rpl.c @@ -268,9 +268,11 @@ rpl_link_callback(const linkaddr_t *addr, int status, int numtx) if(parent != NULL) { /* If this is the neighbor we were probing urgently, mark urgent probing as done */ +#if RPL_WITH_PROBING if(instance->urgent_probing_target == parent) { instance->urgent_probing_target = NULL; } +#endif /* RPL_WITH_PROBING */ /* Trigger DAG rank recalculation. */ PRINTF("RPL: rpl_link_callback triggering update\n"); parent->flags |= RPL_PARENT_FLAG_UPDATED; From 232fbd4c98a5afae10218bfc05d7edbbfab9b56d Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Fri, 31 Aug 2018 12:15:22 +0200 Subject: [PATCH 329/485] Fixed travis errors --- arch/cpu/arm/cortex-m/cm4/Makefile.cm4 | 10 ++--- arch/cpu/nrf52832/Makefile.nrf52832 | 8 ++-- .../Makefile.cc13xx-cc26xx | 5 ++- .../cc13x2-cc26x2/Makefile.cc13x2-cc26x2 | 2 +- arch/cpu/simplelink-cc13xx-cc26xx/ccfg-conf.c | 2 +- .../dev/startup_cc13xx_cc26xx_gcc.c | 1 + .../dev/startup_cc13xx_cc26xx_iar.c | 1 + .../rf-settings/cc13x2/ble-settings.c | 44 ++++++++++--------- .../rf-settings/cc13x2/ble-settings.h | 6 +-- .../simplelink-cc13xx-cc26xx/rf/ble-addr.h | 4 ++ .../simplelink-cc13xx-cc26xx/rf/ble-beacond.h | 8 +--- .../launchpad/cc1310/CC1310_LAUNCHXL.h | 4 +- .../launchpad/cc1312r1/CC1312R1_LAUNCHXL.h | 4 +- .../launchpad/cc1350-4/CC1350_LAUNCHXL_433.h | 4 +- .../launchpad/cc1350/CC1350_LAUNCHXL.h | 4 +- .../launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h | 4 +- .../launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.h | 4 +- .../launchpad/cc1352p1/CC1352P1_LAUNCHXL.h | 4 +- .../launchpad/cc1352r1/CC1352R1_LAUNCHXL.h | 4 +- .../launchpad/cc2650/CC2650_LAUNCHXL.h | 4 +- .../launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h | 4 +- .../cc13xx-cc26xx/sensortag/bmp-280-sensor.c | 3 +- .../sensortag/cc1350/CC1350STK.h | 4 +- .../sensortag/cc2650/CC2650STK.h | 4 +- .../cc13xx-cc26xx/sensortag/tmp-007-sensor.c | 22 +++++----- .../cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h | 4 +- .../cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h | 4 +- tools/doxygen/Doxyfile | 8 ++-- 28 files changed, 92 insertions(+), 88 deletions(-) diff --git a/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 b/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 index 0635a3148..110e0697b 100644 --- a/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 +++ b/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 @@ -2,7 +2,7 @@ CONTIKI_ARM_DIRS += cortex-m/cm4 CFLAGS += -mcpu=cortex-m4 -LDFLAGS += -mcpu=cortex-m4 -nostartfiles +LDFLAGS += -mcpu=cortex-m4 LDFLAGS += -T $(LDSCRIPT) LDFLAGS += -Wl,--gc-sections,--sort-section=alignment LDFLAGS += -Wl,-Map=$(CONTIKI_NG_PROJECT_MAP),--cref,--no-warn-mismatch @@ -19,12 +19,10 @@ CUSTOM_RULE_LINK = 1 ### Resolve any potential circular dependencies between the linked libraries ### See: https://stackoverflow.com/questions/5651869/gcc-what-are-the-start-group-and-end-group-command-line-options/5651895 -TARGET_LIBFLAGS := -Wl,--start-group $(TARGET_LIBFILES) -lm -Wl,--end-group +TARGET_LIBFLAGS := -Wl,--start-group $(TARGET_LIBFILES) -Wl,--end-group -.SECONDEXPANSION: - -%.elf: $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(LDSCRIPT) +%.elf: $(CPU_STARTFILES) %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(CONTIKI_NG_TARGET_LIB) $(TARGET_LIBS) $(TRACE_LD) - $(Q)$(LD) $(LDFLAGS) ${filter-out $(LDSCRIPT) %.a,$^} ${filter %.a,$^} $(TARGET_LIBFLAGS) -o $@ + $(Q)$(LD) $(LDFLAGS) ${filter %.o %.a,$^} $(TARGET_LIBFLAGS) -o $@ include $(CONTIKI)/arch/cpu/arm/cortex-m/Makefile.cortex-m diff --git a/arch/cpu/nrf52832/Makefile.nrf52832 b/arch/cpu/nrf52832/Makefile.nrf52832 index 3765484d8..c97c728e5 100644 --- a/arch/cpu/nrf52832/Makefile.nrf52832 +++ b/arch/cpu/nrf52832/Makefile.nrf52832 @@ -25,9 +25,9 @@ ifneq ($(NRF52_WITHOUT_SOFTDEVICE),1) NRF52_SOFTDEVICE := $(shell find $(NRF52_SDK_ROOT) -name *iot*_softdevice.hex | head -n 1) endif $(info SoftDevice: $(NRF52_SOFTDEVICE)) - LINKER_SCRIPT := $(CONTIKI_CPU)/ld/nrf52-$(NRF52_DK_REVISION)-sd.ld + LDSCRIPT := $(CONTIKI_CPU)/ld/nrf52-$(NRF52_DK_REVISION)-sd.ld else - LINKER_SCRIPT := $(CONTIKI_CPU)/ld/nrf52.ld + LDSCRIPT := $(CONTIKI_CPU)/ld/nrf52.ld endif OUTPUT_FILENAME := $(CONTIKI_PROJECT) @@ -140,7 +140,7 @@ CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16 # keep every function in separate section. This will allow linker to dump unused functions LDFLAGS += -Xlinker -Map=$(CONTIKI_NG_PROJECT_MAP) -LDFLAGS += -mabi=aapcs -L $(TEMPLATE_PATH) -T$(LINKER_SCRIPT) +LDFLAGS += -mabi=aapcs -L $(TEMPLATE_PATH) LDFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16 # let linker to dump unused sections LDFLAGS += -Wl,--gc-sections @@ -174,7 +174,7 @@ OBJECTS = $(C_OBJECTS) $(ASM_OBJECTS) CLEAN += nrf52832.a -TARGET_LIBS= nrf52832.a $(NRF52_SDK_ROOT)/components/iot/ble_6lowpan/lib/ble_6lowpan.a +TARGET_LIBS = nrf52832.a $(NRF52_SDK_ROOT)/components/iot/ble_6lowpan/lib/ble_6lowpan.a nrf52832.a: $(OBJECTS) $(TRACE_AR) diff --git a/arch/cpu/simplelink-cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/cpu/simplelink-cc13xx-cc26xx/Makefile.cc13xx-cc26xx index 19b3689e8..3eb11182d 100644 --- a/arch/cpu/simplelink-cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/cpu/simplelink-cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -118,14 +118,15 @@ CFLAGS += -fno-common # Linker flags LDFLAGS += --entry resetISR -LDFLAGS += -static LDFLAGS += --specs=nano.specs +LDFLAGS += -nostartfiles +LDFLAGS += -static # Linker script LDSCRIPT := $(CONTIKI_CPU)/$(SUBFAMILY)/$(SUBFAMILY).lds # Globally linked libraries -TARGET_LIBFILES += -lc -lgcc -lnosys +TARGET_LIBFILES += -lc -lgcc -lnosys -lm ################################################################################ ### Specialized build targets diff --git a/arch/cpu/simplelink-cc13xx-cc26xx/cc13x2-cc26x2/Makefile.cc13x2-cc26x2 b/arch/cpu/simplelink-cc13xx-cc26xx/cc13x2-cc26x2/Makefile.cc13x2-cc26x2 index ede55d4bc..52333f47d 100644 --- a/arch/cpu/simplelink-cc13xx-cc26xx/cc13x2-cc26x2/Makefile.cc13x2-cc26x2 +++ b/arch/cpu/simplelink-cc13xx-cc26xx/cc13x2-cc26x2/Makefile.cc13x2-cc26x2 @@ -7,5 +7,5 @@ TARGET_LIBFILES += $(SDK_DRIVERS)/rf/lib/rf_multiMode_$(SDK_LIB_NAME).am4fg TARGET_LIBFILES += $(SDK_DRIVERS)/lib/drivers_$(SDK_LIB_NAME).am4fg TARGET_LIBFILES += $(SDK_DEVICES)/driverlib/bin/gcc/driverlib.lib -# CC13x0/CC26x0 is a Cortex-M4 architecture +# CC13x2/CC26x2 is a Cortex-M4 architecture include $(CONTIKI)/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 diff --git a/arch/cpu/simplelink-cc13xx-cc26xx/ccfg-conf.c b/arch/cpu/simplelink-cc13xx-cc26xx/ccfg-conf.c index be6c1ed9b..ef83fc29b 100644 --- a/arch/cpu/simplelink-cc13xx-cc26xx/ccfg-conf.c +++ b/arch/cpu/simplelink-cc13xx-cc26xx/ccfg-conf.c @@ -31,7 +31,7 @@ * \addtogroup cc13xx-cc26xx-cpu * @{ * - * \defgroupt cc13xx-cc26xx-ccfg Customer Configuration (CCFG) + * \defgroup cc13xx-cc26xx-ccfg Customer Configuration (CCFG) * * @{ * diff --git a/arch/cpu/simplelink-cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c b/arch/cpu/simplelink-cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c index 7c542084b..7b34cd29b 100644 --- a/arch/cpu/simplelink-cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c +++ b/arch/cpu/simplelink-cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c @@ -308,3 +308,4 @@ _fini(void) /* Function body left empty intentionally */ } /*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/cpu/simplelink-cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_iar.c b/arch/cpu/simplelink-cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_iar.c index 84b17ac76..3ea8500c2 100644 --- a/arch/cpu/simplelink-cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_iar.c +++ b/arch/cpu/simplelink-cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_iar.c @@ -315,3 +315,4 @@ intDefaultHandler(void) for(;;) { /* hang */ } } /*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.c b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.c index e6771de64..b9e32a04d 100644 --- a/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.c +++ b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.c @@ -122,7 +122,7 @@ uint32_t rf_ble_overrides_coded[] CC_ALIGN(4) = }; /*---------------------------------------------------------------------------*/ /* CMD_BLE5_RADIO_SETUP: Bluetooth 5 Radio Setup Command for all PHYs */ -rfc_CMD_BLE5_RADIO_SETUP_t rf_cmd_ble5_radio_setup = +rfc_CMD_BLE5_RADIO_SETUP_t rf_ble_cmd_radio_setup = { .commandNo = CMD_BLE5_RADIO_SETUP, .status = IDLE, @@ -148,8 +148,8 @@ rfc_CMD_BLE5_RADIO_SETUP_t rf_cmd_ble5_radio_setup = .pRegOverrideCoded = rf_ble_overrides_coded, }; /*---------------------------------------------------------------------------*/ -/* Structure for CMD_BLE5_ADV_AUX.pParams */ -rfc_ble5AdvAuxPar_t rf_ble5_adv_aux_par = +/* Structure for CMD_BLE5_ADV_NC.pParams */ +rfc_bleAdvPar_t rf_ble_adv_par = { .pRxQ = 0, .rxConfig.bAutoFlushIgnored = 0x0, @@ -162,32 +162,36 @@ rfc_ble5AdvAuxPar_t rf_ble5_adv_aux_par = .rxConfig.bAppendTimestamp = 0x0, .advConfig.advFilterPolicy = 0x0, .advConfig.deviceAddrType = 0x0, - .advConfig.targetAddrType = 0x0, + .advConfig.peerAddrType = 0x0, .advConfig.bStrictLenFilter = 0x0, - .advConfig.bDirected = 0x0, - .advConfig.privIgnMode = 0x0, .advConfig.rpaMode = 0x0, - .__dummy0 = 0x00, - .auxPtrTargetType = 0x00, - .auxPtrTargetTime = 0x00000000, - .pAdvPkt = 0, - .pRspPkt = 0, + .advLen = 0x18, + .scanRspLen = 0x00, + .pAdvData = 0, + .pScanRspData = 0, .pDeviceAddress = 0, .pWhiteList = 0, + .__dummy0 = 0x0000, + .__dummy1 = 0x00, + .endTrigger.triggerType = TRIG_NEVER, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, }; /*---------------------------------------------------------------------------*/ -/* CMD_BLE5_ADV_AUX: Bluetooth 5 Secondary Channel Advertiser Command */ -rfc_CMD_BLE5_ADV_AUX_t rf_cmd_ble5_adv_aux = +/* CMD_BLE5_ADV_NC: Bluetooth 5 Non-Connectable Advertiser Command */ +rfc_CMD_BLE5_ADV_NC_t rf_ble_cmd_ble_adv_nc = { - .commandNo = CMD_BLE5_ADV_AUX, - .status = IDLE, - .pNextOp = 0, + .commandNo = 0x182D, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, + .startTrigger.triggerType = 0x0, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, + .condition.rule = 0x1, .condition.nSkip = 0x0, .channel = 0x8C, .whitening.init = 0x51, @@ -196,8 +200,8 @@ rfc_CMD_BLE5_ADV_AUX_t rf_cmd_ble5_adv_aux = .phyMode.coding = 0x0, .rangeDelay = 0x00, .txPower = 0x0000, - .pParams = &rf_ble5_adv_aux_par, - .pOutput = 0, + .pParams = &rf_ble_adv_par, + .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx .tx20Power = 0x00000000, }; /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.h b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.h index 7793b89e6..2e6defa71 100644 --- a/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.h +++ b/arch/cpu/simplelink-cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.h @@ -42,9 +42,9 @@ extern RF_Mode rf_ble_mode; /*---------------------------------------------------------------------------*/ /* RF Core API commands */ -extern rfc_CMD_BLE5_RADIO_SETUP_t rf_cmd_ble5_radio_setup; -extern rfc_ble5AdvAuxPar_t rf_ble5_adv_aux_par; -extern rfc_CMD_BLE5_ADV_AUX_t rf_cmd_ble5_adv_aux; +extern rfc_CMD_BLE5_RADIO_SETUP_t rf_ble_cmd_radio_setup; +extern rfc_bleAdvPar_t rf_ble_adv_par; +extern rfc_CMD_BLE5_ADV_NC_t rf_ble_cmd_ble_adv_nc; /*---------------------------------------------------------------------------*/ /* RF Core API Overrides */ extern uint32_t rf_ble_overrides_common[]; diff --git a/arch/cpu/simplelink-cc13xx-cc26xx/rf/ble-addr.h b/arch/cpu/simplelink-cc13xx-cc26xx/rf/ble-addr.h index 7fb45b1f2..fd63c17d0 100644 --- a/arch/cpu/simplelink-cc13xx-cc26xx/rf/ble-addr.h +++ b/arch/cpu/simplelink-cc13xx-cc26xx/rf/ble-addr.h @@ -93,3 +93,7 @@ int ble_addr_to_eui64_cpy(uint8_t *dst); /*---------------------------------------------------------------------------*/ #endif /* BLE_ADDR_H_ */ /*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ \ No newline at end of file diff --git a/arch/cpu/simplelink-cc13xx-cc26xx/rf/ble-beacond.h b/arch/cpu/simplelink-cc13xx-cc26xx/rf/ble-beacond.h index c273ad1c1..7741a2d71 100644 --- a/arch/cpu/simplelink-cc13xx-cc26xx/rf/ble-beacond.h +++ b/arch/cpu/simplelink-cc13xx-cc26xx/rf/ble-beacond.h @@ -55,13 +55,7 @@ typedef enum { } rf_ble_beacond_result_t; /*---------------------------------------------------------------------------*/ /** - * \brief Set the device name to use with the BLE advertisement/beacon daemon - * \param interval The interval (ticks) between two consecutive beacon bursts - * \param name The device name to advertise - * - * If name is NULL it will be ignored. If interval==0 it will be ignored. Thus, - * this function can be used to configure a single parameter at a time if so - * desired. + * \brief Initialize the BLE advertisement/beacon daemon */ rf_ble_beacond_result_t rf_ble_beacond_init(void); diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h index b1066711b..f2c1638d7 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h @@ -167,7 +167,7 @@ typedef enum CC1310_LAUNCHXL_ADCBufName { } CC1310_LAUNCHXL_ADCBufName; /*! - * @def CC1310_LAUNCHXL_ADCBuf0SourceName + * @def CC1310_LAUNCHXL_ADCBuf0ChannelName * @brief Enum of ADCBuf channels */ typedef enum CC1310_LAUNCHXL_ADCBuf0ChannelName { @@ -290,7 +290,7 @@ typedef enum CC1310_LAUNCHXL_NVSName { } CC1310_LAUNCHXL_NVSName; /*! - * @def CC1310_LAUNCHXL_PWM + * @def CC1310_LAUNCHXL_PWMName * @brief Enum of PWM outputs */ typedef enum CC1310_LAUNCHXL_PWMName { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h index a6e5e3bbf..0295dc0b4 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h @@ -176,7 +176,7 @@ typedef enum CC1312R1_LAUNCHXL_ADCBufName { } CC1312R1_LAUNCHXL_ADCBufName; /*! - * @def CC1312R1_LAUNCHXL_ADCBuf0SourceName + * @def CC1312R1_LAUNCHXL_ADCBuf0ChannelName * @brief Enum of ADCBuf channels */ typedef enum CC1312R1_LAUNCHXL_ADCBuf0ChannelName { @@ -349,7 +349,7 @@ typedef enum CC1312R1_LAUNCHXL_NVSName { } CC1312R1_LAUNCHXL_NVSName; /*! - * @def CC1312R1_LAUNCHXL_PWM + * @def CC1312R1_LAUNCHXL_PWMName * @brief Enum of PWM outputs */ typedef enum CC1312R1_LAUNCHXL_PWMName { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h index 479b81a71..5377700d5 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h @@ -170,7 +170,7 @@ typedef enum CC1350_LAUNCHXL_433_ADCBufName { } CC1350_LAUNCHXL_433_ADCBufName; /*! - * @def CC1350_LAUNCHXL_433_ADCBuf0SourceName + * @def CC1350_LAUNCHXL_433_ADCBuf0ChannelName * @brief Enum of ADCBuf channels */ typedef enum CC1350_LAUNCHXL_433_ADCBuf0ChannelName { @@ -291,7 +291,7 @@ typedef enum CC1350_LAUNCHXL_433_NVSName { } CC1350_LAUNCHXL_433_NVSName; /*! - * @def CC1350_LAUNCHXL_433_PWM + * @def CC1350_LAUNCHXL_433_PWMName * @brief Enum of PWM outputs */ typedef enum CC1350_LAUNCHXL_433_PWMName { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h index f711874c2..9167a15c3 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h @@ -170,7 +170,7 @@ typedef enum CC1350_LAUNCHXL_ADCBufName { } CC1350_LAUNCHXL_ADCBufName; /*! - * @def CC1350_LAUNCHXL_ADCBuf0SourceName + * @def CC1350_LAUNCHXL_ADCBuf0ChannelName * @brief Enum of ADCBuf channels */ typedef enum CC1350_LAUNCHXL_ADCBuf0ChannelName { @@ -293,7 +293,7 @@ typedef enum CC1350_LAUNCHXL_NVSName { } CC1350_LAUNCHXL_NVSName; /*! - * @def CC1350_LAUNCHXL_PWM + * @def CC1350_LAUNCHXL_PWMName * @brief Enum of PWM outputs */ typedef enum CC1350_LAUNCHXL_PWMName { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h index 29e089cfb..a3defe845 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h @@ -191,7 +191,7 @@ typedef enum CC1352P_2_LAUNCHXL_ADCBufName { } CC1352P_2_LAUNCHXL_ADCBufName; /*! - * @def CC1352P_2_LAUNCHXL_ADCBuf0SourceName + * @def CC1352P_2_LAUNCHXL_ADCBuf0ChannelName * @brief Enum of ADCBuf channels */ typedef enum CC1352P_2_LAUNCHXL_ADCBuf0ChannelName { @@ -358,7 +358,7 @@ typedef enum CC1352P_2_LAUNCHXL_NVSName { } CC1352P_2_LAUNCHXL_NVSName; /*! - * @def CC1352P_2_LAUNCHXL_PWM + * @def CC1352P_2_LAUNCHXL_PWMName * @brief Enum of PWM outputs */ typedef enum CC1352P_2_LAUNCHXL_PWMName { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.h index bce1bb54a..d33d50847 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.h @@ -191,7 +191,7 @@ typedef enum CC1352P_4_LAUNCHXL_ADCBufName { } CC1352P_4_LAUNCHXL_ADCBufName; /*! - * @def CC1352P_4_LAUNCHXL_ADCBuf0SourceName + * @def CC1352P_4_LAUNCHXL_ADCBuf0ChannelName * @brief Enum of ADCBuf channels */ typedef enum CC1352P_4_LAUNCHXL_ADCBuf0ChannelName { @@ -358,7 +358,7 @@ typedef enum CC1352P_4_LAUNCHXL_NVSName { } CC1352P_4_LAUNCHXL_NVSName; /*! - * @def CC1352P_4_LAUNCHXL_PWM + * @def CC1352P_4_LAUNCHXL_PWMName * @brief Enum of PWM outputs */ typedef enum CC1352P_4_LAUNCHXL_PWMName { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h index f5fa59fe7..067a3ea87 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h @@ -191,7 +191,7 @@ typedef enum CC1352P1_LAUNCHXL_ADCBufName { } CC1352P1_LAUNCHXL_ADCBufName; /*! - * @def CC1352P1_LAUNCHXL_ADCBuf0SourceName + * @def CC1352P1_LAUNCHXL_ADCBuf0ChannelName * @brief Enum of ADCBuf channels */ typedef enum CC1352P1_LAUNCHXL_ADCBuf0ChannelName { @@ -362,7 +362,7 @@ typedef enum CC1352P1_LAUNCHXL_NVSName { } CC1352P1_LAUNCHXL_NVSName; /*! - * @def CC1352P1_LAUNCHXL_PWM + * @def CC1352P1_LAUNCHXL_PWMName * @brief Enum of PWM outputs */ typedef enum CC1352P1_LAUNCHXL_PWMName { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h index f0d94306b..b6362cf9f 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h @@ -182,7 +182,7 @@ typedef enum CC1352R1_LAUNCHXL_ADCBufName { } CC1352R1_LAUNCHXL_ADCBufName; /*! - * @def CC1352R1_LAUNCHXL_ADCBuf0SourceName + * @def CC1352R1_LAUNCHXL_ADCBuf0ChannelName * @brief Enum of ADCBuf channels */ typedef enum CC1352R1_LAUNCHXL_ADCBuf0ChannelName { @@ -353,7 +353,7 @@ typedef enum CC1352R1_LAUNCHXL_NVSName { } CC1352R1_LAUNCHXL_NVSName; /*! - * @def CC1352R1_LAUNCHXL_PWM + * @def CC1352R1_LAUNCHXL_PWMName * @brief Enum of PWM outputs */ typedef enum CC1352R1_LAUNCHXL_PWMName { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h index 90bf27d38..8c440aa9d 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h @@ -167,7 +167,7 @@ typedef enum CC2650_LAUNCHXL_ADCBufName { } CC2650_LAUNCHXL_ADCBufName; /*! - * @def CC2650_LAUNCHXL_ADCBuf0SourceName + * @def CC2650_LAUNCHXL_ADCBuf0ChannelName * @brief Enum of ADCBuf channels */ typedef enum CC2650_LAUNCHXL_ADCBuf0ChannelName { @@ -290,7 +290,7 @@ typedef enum CC2650_LAUNCHXL_NVSName { } CC2650_LAUNCHXL_NVSName; /*! - * @def CC2650_LAUNCHXL_PWM + * @def CC2650_LAUNCHXL_PWMName * @brief Enum of PWM outputs */ typedef enum CC2650_LAUNCHXL_PWMName { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h index 040d9fb50..840d937e7 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h @@ -182,7 +182,7 @@ typedef enum CC26X2R1_LAUNCHXL_ADCBufName { } CC26X2R1_LAUNCHXL_ADCBufName; /*! - * @def CC26X2R1_LAUNCHXL_ADCBuf0SourceName + * @def CC26X2R1_LAUNCHXL_ADCBuf0ChannelName * @brief Enum of ADCBuf channels */ typedef enum CC26X2R1_LAUNCHXL_ADCBuf0ChannelName { @@ -355,7 +355,7 @@ typedef enum CC26X2R1_LAUNCHXL_NVSName { } CC26X2R1_LAUNCHXL_NVSName; /*! - * @def CC26X2R1_LAUNCHXL_PWM + * @def CC26X2R1_LAUNCHXL_PWMName * @brief Enum of PWM outputs */ typedef enum CC26X2R1_LAUNCHXL_PWMName { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c index 7c6b0f2f1..bf47c1571 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c @@ -234,7 +234,8 @@ enable_sensor(bool enable) /** * \brief Read temperature and pressure data. * \param data Pointer to a buffer where temperature and pressure will be - * written (6 bytes). + * written. + * \param count Number of byes to read. * \return Boolean Value descibing whether initialization were * successful or not. * \retval true Successful initialization diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.h index dae1c7739..2347876b1 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.h @@ -256,7 +256,7 @@ typedef enum CC1350STK_NVSName { } CC1350STK_NVSName; /*! - * @def CC1350STK_PdmName + * @def CC1350STK_PDMName * @brief Enum of PDM names */ typedef enum CC1350STK_PDMName { @@ -266,7 +266,7 @@ typedef enum CC1350STK_PDMName { } CC1350STK_PDMName; /*! - * @def CC1350STK_PWM + * @def CC1350STK_PWMName * @brief Enum of PWM outputs */ typedef enum CC1350STK_PWMName { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h index 8dc1a9326..17533f6cd 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h @@ -257,7 +257,7 @@ typedef enum CC2650STK_NVSName { } CC2650STK_NVSName; /*! - * @def CC2650STK_PdmName + * @def CC2650STK_PDMName * @brief Enum of PDM names */ typedef enum CC2650STK_PDMName { @@ -267,7 +267,7 @@ typedef enum CC2650STK_PDMName { } CC2650STK_PDMName; /*! - * @def CC2650STK_PWM + * @def CC2650STK_PWMName * @brief Enum of PWM outputs */ typedef enum CC2650STK_PWMName { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c index 68bd4669a..7e08006ea 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c @@ -241,12 +241,12 @@ enable_sensor(bool enable) } /*---------------------------------------------------------------------------*/ /** - * \brief Read the sensor value registers. - * \param raw_temp Output variable holding the Temperature in - * 16-bit format. - * \param raw_obj_temp Output variable holding the Object temperature in - * 16-bit format. - * \return true if valid data could be retrieved; else, false. + * \brief Read the sensor value registers. + * \param local_tmp Output variable holding the Temperature in + * 16-bit format. + * \param obj_tmp Output variable holding the Object temperature in + * 16-bit format. + * \return true if valid data could be retrieved; else, false. */ static bool read_data(uint16_t *local_tmp, uint16_t *obj_tmp) @@ -292,11 +292,11 @@ read_data(uint16_t *local_tmp, uint16_t *obj_tmp) } /*---------------------------------------------------------------------------*/ /** - * \brief Convert raw data to values in degrees Celsius. - * \param raw_temp Output variable holding the raw ambient temperature - * from sensor. - * \param raw_obj_temp Output variable holding the raw object temperature - * from sensor. + * \brief Convert raw data to values in degrees Celsius. + * \param local_tmp Output variable holding the raw ambient temperature + * from sensor. + * \param obj_tmp Output variable holding the raw object temperature + * from sensor. */ static void convert(uint16_t *local_tmp, uint16_t *obj_tmp) diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h index b531041cb..4c705abe5 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h @@ -178,7 +178,7 @@ typedef enum CC1350DK_7XD_ADCBufName { } CC1350DK_7XD_ADCBufName; /*! - * @def CC1350DK_7XD_ADCBuf0SourceName + * @def CC1350DK_7XD_ADCBuf0ChannelName * @brief Enum of ADCBuf channels */ typedef enum CC1350DK_7XD_ADCBuf0ChannelName { @@ -290,7 +290,7 @@ typedef enum CC1350DK_7XD_NVSName { } CC1350DK_7XD_NVSName; /*! - * @def CC1350DK_7XD_PWM + * @def CC1350DK_7XD_PWMName * @brief Enum of PWM outputs */ typedef enum CC1350DK_7XD_PWMName { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h index a48531407..21bae0eed 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h @@ -178,7 +178,7 @@ typedef enum CC2650DK_7ID_ADCBufName { } CC2650DK_7ID_ADCBufName; /*! - * @def CC2650DK_7ID_ADCBuf0SourceName + * @def CC2650DK_7ID_ADCBuf0ChannelName * @brief Enum of ADCBuf channels */ typedef enum CC2650DK_7ID_ADCBuf0ChannelName { @@ -290,7 +290,7 @@ typedef enum CC2650DK_7ID_NVSName { } CC2650DK_7ID_NVSName; /*! - * @def CC2650DK_7ID_PWM + * @def CC2650DK_7ID_PWMName * @brief Enum of PWM outputs */ typedef enum CC2650DK_7ID_PWMName { diff --git a/tools/doxygen/Doxyfile b/tools/doxygen/Doxyfile index db2efa697..dab2c18e3 100644 --- a/tools/doxygen/Doxyfile +++ b/tools/doxygen/Doxyfile @@ -809,10 +809,10 @@ EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = */cpu/cc26xx-cc13xx/lib/* \ */cpu/cc26xx-cc13xx/rf-core/api/* \ - */cpu/cc13xx-cc26xx/lib/* \ - */cpu/cc13xx-cc26xx/rf-settings/* \ - */cpu/cc13xx-cc26xx/cc13x0-cc26x0/driverlib/* \ - */cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf_patches/* \ + */cpu/simplelink-cc13xx-cc26xx/lib/* \ + */cpu/simplelink-cc13xx-cc26xx/rf-settings/* \ + */cpu/simplelink-cc13xx-cc26xx/cc13x0-cc26x0/driverlib/* \ + */cpu/simplelink-cc13xx-cc26xx/cc13x0-cc26x0/rf_patches/* \ */platform/stm32nucleo-spirit1/stm32cube-lib/* \ */os/net/security/tinydtls/* From 61f6b704dbcca529b20043213ee0de0716ab6a25 Mon Sep 17 00:00:00 2001 From: Atis Elsts Date: Fri, 31 Aug 2018 17:22:04 +0100 Subject: [PATCH 330/485] TSCH: improve the readability of add_link and remove_link messages --- os/net/mac/tsch/tsch-schedule.c | 51 ++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/os/net/mac/tsch/tsch-schedule.c b/os/net/mac/tsch/tsch-schedule.c index 4f94b8e30..3785cacb2 100644 --- a/os/net/mac/tsch/tsch-schedule.c +++ b/os/net/mac/tsch/tsch-schedule.c @@ -171,6 +171,45 @@ tsch_schedule_get_link_by_handle(uint16_t handle) return NULL; } /*---------------------------------------------------------------------------*/ +static const char * +print_link_options(uint16_t link_options) +{ + static char buffer[20]; + unsigned length; + + buffer[0] = '\0'; + if(link_options & LINK_OPTION_TX) { + strcat(buffer, "Tx|"); + } + if(link_options & LINK_OPTION_RX) { + strcat(buffer, "Rx|"); + } + if(link_options & LINK_OPTION_SHARED) { + strcat(buffer, "Sh|"); + } + length = strlen(buffer); + if(length > 0) { + buffer[length - 1] = '\0'; + } + + return buffer; +} +/*---------------------------------------------------------------------------*/ +static const char * +print_link_type(uint16_t link_type) +{ + switch(link_type) { + case LINK_TYPE_NORMAL: + return "NORMAL"; + case LINK_TYPE_ADVERTISING: + return "ADV"; + case LINK_TYPE_ADVERTISING_ONLY: + return "ADV_ONLY"; + default: + return "?"; + } +} +/*---------------------------------------------------------------------------*/ /* Adds a link to a slotframe, return a pointer to it (NULL if failure) */ struct tsch_link * tsch_schedule_add_link(struct tsch_slotframe *slotframe, @@ -218,8 +257,10 @@ tsch_schedule_add_link(struct tsch_slotframe *slotframe, } linkaddr_copy(&l->addr, address); - LOG_INFO("add_link %u %u %u %u %u ", - slotframe->handle, link_options, link_type, timeslot, channel_offset); + LOG_INFO("add_link sf=%u opt=%s type=%s ts=%u ch=%u addr=", + slotframe->handle, + print_link_options(link_options), + print_link_type(link_type), timeslot, channel_offset); LOG_INFO_LLADDR(address); LOG_INFO_("\n"); /* Release the lock before we update the neighbor (will take the lock) */ @@ -260,8 +301,10 @@ tsch_schedule_remove_link(struct tsch_slotframe *slotframe, struct tsch_link *l) if(l == current_link) { current_link = NULL; } - LOG_INFO("remove_link %u %u %u %u ", - slotframe->handle, l->link_options, l->timeslot, l->channel_offset); + LOG_INFO("remove_link sf=%u opt=%s type=%s ts=%u ch=%u addr=", + slotframe->handle, + print_link_options(l->link_options), + print_link_type(l->link_type), l->timeslot, l->channel_offset); LOG_INFO_LLADDR(&l->addr); LOG_INFO_("\n"); From eb253c0f3b284058540c540a4aea1373251e5641 Mon Sep 17 00:00:00 2001 From: Atis Elsts Date: Mon, 3 Sep 2018 11:49:08 +0100 Subject: [PATCH 331/485] Generate a descriptive error message in case cc26xxware/cc13xxware does not exist --- arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx b/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx index 4845b36ba..a5ffec9a6 100644 --- a/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx +++ b/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx @@ -1,6 +1,12 @@ CPU_ABS_PATH = arch/cpu/cc26xx-cc13xx TI_XXWARE = $(CONTIKI_CPU)/$(TI_XXWARE_PATH) +ifeq (,$(wildcard $(TI_XXWARE))) + $(warning $(TI_XXWARE) does not exist.) + $(warning Did you run 'git submodule update --init' ?) + $(error "") +endif + ### cc26xxware sources under driverlib will be added to the MODULES list TI_XXWARE_SRC = $(CPU_ABS_PATH)/$(TI_XXWARE_PATH)/driverlib From c8792c926116541a2b76fca5fca1798c13282505 Mon Sep 17 00:00:00 2001 From: Atis Elsts Date: Mon, 3 Sep 2018 12:01:34 +0100 Subject: [PATCH 332/485] Set -Werror only if WERROR is set --- arch/cpu/arm/Makefile.arm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/cpu/arm/Makefile.arm b/arch/cpu/arm/Makefile.arm index 0b2662423..285031e82 100644 --- a/arch/cpu/arm/Makefile.arm +++ b/arch/cpu/arm/Makefile.arm @@ -9,10 +9,13 @@ SIZE = arm-none-eabi-size SREC_CAT = srec_cat CFLAGS += -mthumb -mabi=aapcs -mlittle-endian -CFLAGS += -Werror -Wall +CFLAGS += -Wall CFLAGS += -std=c99 CFLAGS += -ffunction-sections -fdata-sections -fno-strict-aliasing CFLAGS += -fshort-enums -fomit-frame-pointer -fno-builtin +ifeq ($(WERROR),1) + CFLAGS += -Werror +endif LDFLAGS += -mthumb -mlittle-endian From d953adf0cb0b908f153437e3055c0773ef1d77f2 Mon Sep 17 00:00:00 2001 From: Olav Frengstad Date: Tue, 4 Sep 2018 18:31:48 +0200 Subject: [PATCH 333/485] Make cc26xx radio driver configurable in prop mode operation It's already possible to override the default radio driver when operating in IEEE mode. This patch opens up for users defining their own radio driver when using prop mode. This is useful when overriding certain radio driver functions. --- arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h b/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h index df1ca0440..6ff047ebe 100644 --- a/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h +++ b/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h @@ -71,7 +71,9 @@ #endif /* CPU_FAMILY_CC13XX */ #if CC13XX_CONF_PROP_MODE +#ifndef NETSTACK_CONF_RADIO #define NETSTACK_CONF_RADIO prop_mode_driver +#endif /* NETSTACK_CONF_RADIO */ /* Channels count from 0 upwards in IEEE 802.15.4g */ #ifndef IEEE802154_CONF_DEFAULT_CHANNEL From 57f1042bf3c6fbe52d98ba454f0be8c0a898659a Mon Sep 17 00:00:00 2001 From: Afonso Oliveira Date: Fri, 7 Sep 2018 16:39:53 +0100 Subject: [PATCH 334/485] add qualifier const to uip-ds6-route methods --- os/net/ipv6/tcpip.c | 10 +++++----- os/net/ipv6/uip-ds6-route.c | 22 +++++++++++----------- os/net/ipv6/uip-ds6-route.h | 20 ++++++++++---------- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/os/net/ipv6/tcpip.c b/os/net/ipv6/tcpip.c index 5db4b9a21..8d546c1d7 100644 --- a/os/net/ipv6/tcpip.c +++ b/os/net/ipv6/tcpip.c @@ -480,7 +480,7 @@ output_fallback(void) } /*---------------------------------------------------------------------------*/ static void -annotate_transmission(uip_ipaddr_t *nexthop) +annotate_transmission(const uip_ipaddr_t *nexthop) { #if TCPIP_CONF_ANNOTATE_TRANSMISSIONS static uint8_t annotate_last; @@ -495,10 +495,10 @@ annotate_transmission(uip_ipaddr_t *nexthop) #endif /* TCPIP_CONF_ANNOTATE_TRANSMISSIONS */ } /*---------------------------------------------------------------------------*/ -static uip_ipaddr_t* +static const uip_ipaddr_t* get_nexthop(uip_ipaddr_t *addr) { - uip_ipaddr_t *nexthop; + const uip_ipaddr_t *nexthop; uip_ds6_route_t *route; LOG_INFO("output: processing %u bytes packet from ", uip_len); @@ -597,7 +597,7 @@ send_queued(uip_ds6_nbr_t *nbr) } /*---------------------------------------------------------------------------*/ static int -send_nd6_ns(uip_ipaddr_t *nexthop) +send_nd6_ns(const uip_ipaddr_t *nexthop) { int err = 1; @@ -638,7 +638,7 @@ tcpip_ipv6_output(void) uip_ipaddr_t ipaddr; uip_ds6_nbr_t *nbr = NULL; const uip_lladdr_t *linkaddr; - uip_ipaddr_t *nexthop; + const uip_ipaddr_t *nexthop; if(uip_len == 0) { return; diff --git a/os/net/ipv6/uip-ds6-route.c b/os/net/ipv6/uip-ds6-route.c index a8fdd88fb..08cfce80c 100644 --- a/os/net/ipv6/uip-ds6-route.c +++ b/os/net/ipv6/uip-ds6-route.c @@ -133,8 +133,8 @@ assert_nbr_routes_list_sane(void) /*---------------------------------------------------------------------------*/ #if UIP_DS6_NOTIFICATIONS static void -call_route_callback(int event, uip_ipaddr_t *route, - uip_ipaddr_t *nexthop) +call_route_callback(int event, const uip_ipaddr_t *route, + const uip_ipaddr_t *nexthop) { int num; struct uip_ds6_notification *n; @@ -199,7 +199,7 @@ uip_ds6_route_nexthop_lladdr(uip_ds6_route_t *route) } #endif /* (UIP_MAX_ROUTES != 0) */ /*---------------------------------------------------------------------------*/ -uip_ipaddr_t * +const uip_ipaddr_t * uip_ds6_route_nexthop(uip_ds6_route_t *route) { #if (UIP_MAX_ROUTES != 0) @@ -263,7 +263,7 @@ uip_ds6_route_num_routes(void) } /*---------------------------------------------------------------------------*/ uip_ds6_route_t * -uip_ds6_route_lookup(uip_ipaddr_t *addr) +uip_ds6_route_lookup(const uip_ipaddr_t *addr) { #if (UIP_MAX_ROUTES != 0) uip_ds6_route_t *r; @@ -321,8 +321,8 @@ uip_ds6_route_lookup(uip_ipaddr_t *addr) } /*---------------------------------------------------------------------------*/ uip_ds6_route_t * -uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length, - uip_ipaddr_t *nexthop) +uip_ds6_route_add(const uip_ipaddr_t *ipaddr, uint8_t length, + const uip_ipaddr_t *nexthop) { #if (UIP_MAX_ROUTES != 0) uip_ds6_route_t *r; @@ -350,7 +350,7 @@ uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length, one first. */ r = uip_ds6_route_lookup(ipaddr); if(r != NULL) { - uip_ipaddr_t *current_nexthop; + const uip_ipaddr_t *current_nexthop; current_nexthop = uip_ds6_route_nexthop(r); if(current_nexthop != NULL && uip_ipaddr_cmp(nexthop, current_nexthop)) { /* no need to update route - already correct! */ @@ -580,7 +580,7 @@ rm_routelist_callback(nbr_table_item_t *ptr) #endif /* (UIP_MAX_ROUTES != 0) */ /*---------------------------------------------------------------------------*/ void -uip_ds6_route_rm_by_nexthop(uip_ipaddr_t *nexthop) +uip_ds6_route_rm_by_nexthop(const uip_ipaddr_t *nexthop) { #if (UIP_MAX_ROUTES != 0) /* Get routing entry list of this neighbor */ @@ -601,7 +601,7 @@ uip_ds6_defrt_head(void) } /*---------------------------------------------------------------------------*/ uip_ds6_defrt_t * -uip_ds6_defrt_add(uip_ipaddr_t *ipaddr, unsigned long interval) +uip_ds6_defrt_add(const uip_ipaddr_t *ipaddr, unsigned long interval) { uip_ds6_defrt_t *d; @@ -684,7 +684,7 @@ uip_ds6_defrt_rm(uip_ds6_defrt_t *defrt) } /*---------------------------------------------------------------------------*/ uip_ds6_defrt_t * -uip_ds6_defrt_lookup(uip_ipaddr_t *ipaddr) +uip_ds6_defrt_lookup(const uip_ipaddr_t *ipaddr) { uip_ds6_defrt_t *d; if(ipaddr == NULL) { @@ -700,7 +700,7 @@ uip_ds6_defrt_lookup(uip_ipaddr_t *ipaddr) return NULL; } /*---------------------------------------------------------------------------*/ -uip_ipaddr_t * +const uip_ipaddr_t * uip_ds6_defrt_choose(void) { uip_ds6_defrt_t *d; diff --git a/os/net/ipv6/uip-ds6-route.h b/os/net/ipv6/uip-ds6-route.h index 9f435824c..69ab18f5b 100644 --- a/os/net/ipv6/uip-ds6-route.h +++ b/os/net/ipv6/uip-ds6-route.h @@ -89,8 +89,8 @@ void uip_ds6_route_init(void); #define UIP_DS6_NOTIFICATION_ROUTE_RM 3 typedef void (* uip_ds6_notification_callback)(int event, - uip_ipaddr_t *route, - uip_ipaddr_t *nexthop, + const uip_ipaddr_t *route, + const uip_ipaddr_t *nexthop, int num_routes); struct uip_ds6_notification { struct uip_ds6_notification *next; @@ -201,11 +201,11 @@ typedef struct uip_ds6_defrt { /** \name Default router list basic routines */ /** @{ */ uip_ds6_defrt_t *uip_ds6_defrt_head(void); -uip_ds6_defrt_t *uip_ds6_defrt_add(uip_ipaddr_t *ipaddr, +uip_ds6_defrt_t *uip_ds6_defrt_add(const uip_ipaddr_t *ipaddr, unsigned long interval); void uip_ds6_defrt_rm(uip_ds6_defrt_t *defrt); -uip_ds6_defrt_t *uip_ds6_defrt_lookup(uip_ipaddr_t *ipaddr); -uip_ipaddr_t *uip_ds6_defrt_choose(void); +uip_ds6_defrt_t *uip_ds6_defrt_lookup(const uip_ipaddr_t *ipaddr); +const uip_ipaddr_t *uip_ds6_defrt_choose(void); void uip_ds6_defrt_periodic(void); /** @} */ @@ -213,13 +213,13 @@ void uip_ds6_defrt_periodic(void); /** \name Routing Table basic routines */ /** @{ */ -uip_ds6_route_t *uip_ds6_route_lookup(uip_ipaddr_t *destipaddr); -uip_ds6_route_t *uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length, - uip_ipaddr_t *next_hop); +uip_ds6_route_t *uip_ds6_route_lookup(const uip_ipaddr_t *destipaddr); +uip_ds6_route_t *uip_ds6_route_add(const uip_ipaddr_t *ipaddr, uint8_t length, + const uip_ipaddr_t *next_hop); void uip_ds6_route_rm(uip_ds6_route_t *route); -void uip_ds6_route_rm_by_nexthop(uip_ipaddr_t *nexthop); +void uip_ds6_route_rm_by_nexthop(const uip_ipaddr_t *nexthop); -uip_ipaddr_t *uip_ds6_route_nexthop(uip_ds6_route_t *); +const uip_ipaddr_t *uip_ds6_route_nexthop(uip_ds6_route_t *); int uip_ds6_route_num_routes(void); uip_ds6_route_t *uip_ds6_route_head(void); uip_ds6_route_t *uip_ds6_route_next(uip_ds6_route_t *); From f6fff896fcf77c83cde6af76a2e442af22c0591f Mon Sep 17 00:00:00 2001 From: Afonso Oliveira Date: Sat, 8 Sep 2018 01:14:22 +0100 Subject: [PATCH 335/485] add const qualifier to tests that require it --- tests/15-rpl-classic/code/receiver-node.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/15-rpl-classic/code/receiver-node.c b/tests/15-rpl-classic/code/receiver-node.c index 20bf165f8..798aea84d 100644 --- a/tests/15-rpl-classic/code/receiver-node.c +++ b/tests/15-rpl-classic/code/receiver-node.c @@ -94,7 +94,7 @@ set_global_address(void) #if RPL_WITH_STORING uint8_t should_blink = 1; static void -route_callback(int event, uip_ipaddr_t *route, uip_ipaddr_t *ipaddr, int num_routes) +route_callback(int event, const uip_ipaddr_t *route, const uip_ipaddr_t *ipaddr, int num_routes) { if(event == UIP_DS6_NOTIFICATION_DEFRT_ADD) { should_blink = 0; From bce71648278ece87e70183b3b018549cc7a5a2bb Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 9 Sep 2018 20:10:53 +0100 Subject: [PATCH 336/485] Fix RPL classic compilation for TARGET sky --- os/net/routing/rpl-classic/rpl-dag-root.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/os/net/routing/rpl-classic/rpl-dag-root.c b/os/net/routing/rpl-classic/rpl-dag-root.c index 17ac24d33..3a0162627 100644 --- a/os/net/routing/rpl-classic/rpl-dag-root.c +++ b/os/net/routing/rpl-classic/rpl-dag-root.c @@ -48,6 +48,7 @@ static void set_global_address(uip_ipaddr_t *prefix, uip_ipaddr_t *iid) { static uip_ipaddr_t root_ipaddr; + int i; /* Assign a unique local address (RFC4193, http://tools.ietf.org/html/rfc4193). */ @@ -68,7 +69,7 @@ set_global_address(uip_ipaddr_t *prefix, uip_ipaddr_t *iid) uint8_t state; LOG_DBG("IPv6 addresses: "); - for(int i = 0; i < UIP_DS6_ADDR_NB; i++) { + for(i = 0; i < UIP_DS6_ADDR_NB; i++) { state = uip_ds6_if.addr_list[i].state; if(uip_ds6_if.addr_list[i].isused && (state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) { From bf9fa6d34f21cb14c74effa799a4b1cf684aa448 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 9 Sep 2018 20:24:36 +0100 Subject: [PATCH 337/485] Fix multicast engine stats extension usage --- os/net/ipv6/multicast/esmrf.c | 4 +++- os/net/ipv6/multicast/esmrf.h | 9 +-------- os/net/ipv6/multicast/smrf.h | 12 ------------ 3 files changed, 4 insertions(+), 21 deletions(-) diff --git a/os/net/ipv6/multicast/esmrf.c b/os/net/ipv6/multicast/esmrf.c index 00619c354..5b6f1b863 100644 --- a/os/net/ipv6/multicast/esmrf.c +++ b/os/net/ipv6/multicast/esmrf.c @@ -376,7 +376,9 @@ in() static void init() { - UIP_MCAST6_STATS_INIT(NULL); + ESMRF_STATS_INIT(); + UIP_MCAST6_STATS_INIT(&stats); + uip_mcast6_route_init(); /* Register the ICMPv6 input handler */ uip_icmp6_register_input_handler(&esmrf_icmp_handler); diff --git a/os/net/ipv6/multicast/esmrf.h b/os/net/ipv6/multicast/esmrf.h index a44a87396..15857a1d4 100644 --- a/os/net/ipv6/multicast/esmrf.h +++ b/os/net/ipv6/multicast/esmrf.h @@ -68,16 +68,9 @@ /* Stats datatype */ /*---------------------------------------------------------------------------*/ struct esmrf_stats { - uint16_t mcast_in_unique; - uint16_t mcast_in_all; /* At layer 3 */ - uint16_t mcast_in_ours; /* Unique and we are a group member */ - uint16_t mcast_fwd; /* Forwarded by us but we are not the seed */ - uint16_t mcast_out; /* We are the seed */ - uint16_t mcast_bad; - uint16_t mcast_dropped; uint16_t icmp_out; uint16_t icmp_in; uint16_t icmp_bad; }; - +/*---------------------------------------------------------------------------*/ #endif /* ESMRF_H_ */ diff --git a/os/net/ipv6/multicast/smrf.h b/os/net/ipv6/multicast/smrf.h index bbe7e5e26..d69aa73a5 100644 --- a/os/net/ipv6/multicast/smrf.h +++ b/os/net/ipv6/multicast/smrf.h @@ -70,18 +70,6 @@ #define SMRF_MAX_SPREAD 4 #endif /*---------------------------------------------------------------------------*/ -/* Stats datatype */ -/*---------------------------------------------------------------------------*/ -struct smrf_stats { - uint16_t mcast_in_unique; - uint16_t mcast_in_all; /* At layer 3 */ - uint16_t mcast_in_ours; /* Unique and we are a group member */ - uint16_t mcast_fwd; /* Forwarded by us but we are not the seed */ - uint16_t mcast_out; /* We are the seed */ - uint16_t mcast_bad; - uint16_t mcast_dropped; -}; -/*---------------------------------------------------------------------------*/ #endif /* SMRF_H_ */ /*---------------------------------------------------------------------------*/ /** @} */ From b774736f35ba12b2ff1e39f0fe3c8b6451e85dbe Mon Sep 17 00:00:00 2001 From: Atis Elsts Date: Sun, 9 Sep 2018 21:43:40 +0100 Subject: [PATCH 338/485] Add link stat packet counters --- os/net/link-stats.c | 59 ++++++++++++++++++++++++++++++++++++++++----- os/net/link-stats.h | 26 ++++++++++++++++++++ 2 files changed, 79 insertions(+), 6 deletions(-) diff --git a/os/net/link-stats.c b/os/net/link-stats.c index 8ec372f4e..c11365b9a 100644 --- a/os/net/link-stats.c +++ b/os/net/link-stats.c @@ -37,12 +37,10 @@ #include "net/link-stats.h" #include -#define DEBUG 0 -#if DEBUG -#define PRINTF(...) printf(__VA_ARGS__) -#else -#define PRINTF(...) -#endif +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Link Stats" +#define LOG_LEVEL LOG_LEVEL_MAC /* Maximum value for the Tx count counter */ #define TX_COUNT_MAX 32 @@ -82,6 +80,13 @@ link_stats_from_lladdr(const linkaddr_t *lladdr) return nbr_table_get_from_lladdr(link_stats, lladdr); } /*---------------------------------------------------------------------------*/ +/* Returns the neighbor's address given a link stats item */ +const linkaddr_t * +link_stats_get_lladdr(const struct link_stats *stat) +{ + return nbr_table_get_lladdr(link_stats, stat); +} +/*---------------------------------------------------------------------------*/ /* Are the statistics fresh? */ int link_stats_is_fresh(const struct link_stats *stats) @@ -156,6 +161,14 @@ link_stats_packet_sent(const linkaddr_t *lladdr, int status, int numtx) stats->last_tx_time = clock_time(); stats->freshness = MIN(stats->freshness + numtx, FRESHNESS_MAX); +#if LINK_STATS_PACKET_COUNTERS + /* Update paket counters */ + stats->cnt_current.num_packets_tx += numtx; + if(status == MAC_TX_OK) { + stats->cnt_current.num_packets_acked++; + } +#endif + /* Add penalty in case of no-ACK */ if(status == MAC_TX_NOACK) { numtx += ETX_NOACK_PENALTY; @@ -219,8 +232,38 @@ link_stats_input_callback(const linkaddr_t *lladdr) /* Update RSSI EWMA */ stats->rssi = ((int32_t)stats->rssi * (EWMA_SCALE - EWMA_ALPHA) + (int32_t)packet_rssi * EWMA_ALPHA) / EWMA_SCALE; + +#if LINK_STATS_PACKET_COUNTERS + stats->cnt_current.num_packets_rx++; +#endif } /*---------------------------------------------------------------------------*/ +#if LINK_STATS_PACKET_COUNTERS +/*---------------------------------------------------------------------------*/ +static void +print_and_update_counters(void) +{ + struct link_stats *stats; + + for(stats = nbr_table_head(link_stats); stats != NULL; + stats = nbr_table_next(link_stats, stats)) { + + struct link_packet_counter *c = &stats->cnt_current; + + LOG_INFO("num packets: tx=%u ack=%u rx=%u to=", + c->num_packets_tx, c->num_packets_acked, c->num_packets_rx); + LOG_INFO_LLADDR(link_stats_get_lladdr(stats)); + LOG_INFO_("\n"); + + stats->cnt_total.num_packets_tx += stats->cnt_current.num_packets_tx; + stats->cnt_total.num_packets_acked += stats->cnt_current.num_packets_acked; + stats->cnt_total.num_packets_rx += stats->cnt_current.num_packets_rx; + memset(&stats->cnt_current, 0, sizeof(stats->cnt_current)); + } +} +/*---------------------------------------------------------------------------*/ +#endif /* LINK_STATS_PACKET_COUNTERS */ +/*---------------------------------------------------------------------------*/ /* Periodic timer called at a period of FRESHNESS_HALF_LIFE */ static void periodic(void *ptr) @@ -231,6 +274,10 @@ periodic(void *ptr) for(stats = nbr_table_head(link_stats); stats != NULL; stats = nbr_table_next(link_stats, stats)) { stats->freshness >>= 1; } + +#if LINK_STATS_PACKET_COUNTERS + print_and_update_counters(); +#endif } /*---------------------------------------------------------------------------*/ /* Resets link-stats module */ diff --git a/os/net/link-stats.h b/os/net/link-stats.h index cca15fd32..51f1d285b 100644 --- a/os/net/link-stats.h +++ b/os/net/link-stats.h @@ -56,6 +56,25 @@ #define LINK_STATS_ETX_FROM_PACKET_COUNT 0 #endif /* LINK_STATS_ETX_FROM_PACKET_COUNT */ +/* Store and periodically print packet counters? */ +#ifdef LINK_STATS_CONF_PACKET_COUNTERS +#define LINK_STATS_PACKET_COUNTERS LINK_STATS_CONF_PACKET_COUNTERS +#else /* LINK_STATS_CONF_PACKET_COUNTERS */ +#define LINK_STATS_PACKET_COUNTERS 0 +#endif /* LINK_STATS_PACKET_COUNTERS */ + +typedef uint16_t link_packet_stat_t; + +struct link_packet_counter { + /* total attempts to transmit unicast packets */ + link_packet_stat_t num_packets_tx; + /* total ACKs for unicast packets */ + link_packet_stat_t num_packets_acked; + /* total number of unicast and broadcast packets received */ + link_packet_stat_t num_packets_rx; +}; + + /* All statistics of a given link */ struct link_stats { clock_time_t last_tx_time; /* Last Tx timestamp */ @@ -66,10 +85,17 @@ struct link_stats { uint8_t tx_count; /* Tx count, used for ETX calculation */ uint8_t ack_count; /* ACK count, used for ETX calculation */ #endif /* LINK_STATS_ETX_FROM_PACKET_COUNT */ + +#if LINK_STATS_PACKET_COUNTERS + struct link_packet_counter cnt_current; /* packets in the current period */ + struct link_packet_counter cnt_total; /* packets in total */ +#endif }; /* Returns the neighbor's link statistics */ const struct link_stats *link_stats_from_lladdr(const linkaddr_t *lladdr); +/* Returns the address of the neighbor */ +const linkaddr_t *link_stats_get_lladdr(const struct link_stats *); /* Are the statistics fresh? */ int link_stats_is_fresh(const struct link_stats *stats); /* Resets link-stats module */ From dc294cbabb58a91fcc3a44e9d3543970e3e240a8 Mon Sep 17 00:00:00 2001 From: Atis Elsts Date: Sun, 9 Sep 2018 21:49:10 +0100 Subject: [PATCH 339/485] build-all.sh: there is also launchpad/cc1310 board --- tests/compile-all/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-all/build.sh b/tests/compile-all/build.sh index 795343eeb..d790d7f50 100755 --- a/tests/compile-all/build.sh +++ b/tests/compile-all/build.sh @@ -100,7 +100,7 @@ do if [[ "$platform" == "srf06-cc26xx" ]] then # srf06-cc26xx has multiple boards - BOARDS="srf06/cc26xx srf06/cc13xx launchpad/cc2650 launchpad/cc1350 sensortag/cc2650 sensortag/cc1350" + BOARDS="srf06/cc26xx srf06/cc13xx launchpad/cc2650 launchpad/cc1310 launchpad/cc1350 sensortag/cc2650 sensortag/cc1350" elif [[ "$platform" == "zoul" ]] then # Zoul has multiple boards From 1e7e721395c04e4f9f0d13fbc191331d4d2ffa0b Mon Sep 17 00:00:00 2001 From: Afonso Oliveira Date: Mon, 10 Sep 2018 10:49:06 +0100 Subject: [PATCH 340/485] correct identation --- os/net/ipv6/uip-ds6-route.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/os/net/ipv6/uip-ds6-route.c b/os/net/ipv6/uip-ds6-route.c index 08cfce80c..ed263edc4 100644 --- a/os/net/ipv6/uip-ds6-route.c +++ b/os/net/ipv6/uip-ds6-route.c @@ -134,7 +134,7 @@ assert_nbr_routes_list_sane(void) #if UIP_DS6_NOTIFICATIONS static void call_route_callback(int event, const uip_ipaddr_t *route, - const uip_ipaddr_t *nexthop) + const uip_ipaddr_t *nexthop) { int num; struct uip_ds6_notification *n; @@ -322,7 +322,7 @@ uip_ds6_route_lookup(const uip_ipaddr_t *addr) /*---------------------------------------------------------------------------*/ uip_ds6_route_t * uip_ds6_route_add(const uip_ipaddr_t *ipaddr, uint8_t length, - const uip_ipaddr_t *nexthop) + const uip_ipaddr_t *nexthop) { #if (UIP_MAX_ROUTES != 0) uip_ds6_route_t *r; From 86232c86f9fc06f1257b8f3c6b19124c9066d864 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Tue, 11 Sep 2018 13:17:21 +0200 Subject: [PATCH 341/485] Expanded travis builds with SimpleLink platform In addition, some small grammar fixes and slight bugfix in Makefile.simplelink --- .gitignore | 1 + .../cc13x0-cc26x0/cc13x0-cc26x0.lds | 2 +- .../cc13x2-cc26x2/cc13x2-cc26x2.lds | 2 +- .../cc13xx-cc26xx-conf.h | 2 +- arch/platform/simplelink/Makefile.simplelink | 2 +- .../cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 20 +++++---- examples/dev/gpio-hal/simplelink/pins.c | 43 +++++++++++++++++++ tests/02-compile-arm-ports-01/Makefile | 34 +++++++++++++++ tests/compile-all/build.sh | 4 ++ 9 files changed, 97 insertions(+), 13 deletions(-) create mode 100644 examples/dev/gpio-hal/simplelink/pins.c diff --git a/.gitignore b/.gitignore index 91721ed08..0ff1ebfa2 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,7 @@ COOJA.testlog *.native *.nrf52dk *.openmote-cc2538 +*.simplelink *.sky *.firmware *.srf06-cc26xx diff --git a/arch/cpu/simplelink-cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds b/arch/cpu/simplelink-cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds index 83e834f13..26930dea8 100644 --- a/arch/cpu/simplelink-cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds +++ b/arch/cpu/simplelink-cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds @@ -30,7 +30,7 @@ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -MIN_STACKSIZE = 0x800; /* 2048 bytes */ +MIN_STACKSIZE = 0x600; /* 1536 bytes */ HEAPSIZE = 0x100; /* 256 bytes */ MEMORY diff --git a/arch/cpu/simplelink-cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds b/arch/cpu/simplelink-cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds index 2c663d6b2..9c2211cb8 100644 --- a/arch/cpu/simplelink-cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds +++ b/arch/cpu/simplelink-cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds @@ -30,7 +30,7 @@ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -MIN_STACKSIZE = 0x800; /* 2048 bytes */ +MIN_STACKSIZE = 0x600; /* 1536 bytes */ HEAPSIZE = 0x100; /* 256 bytes */ MEMORY diff --git a/arch/cpu/simplelink-cc13xx-cc26xx/cc13xx-cc26xx-conf.h b/arch/cpu/simplelink-cc13xx-cc26xx/cc13xx-cc26xx-conf.h index 2dbb0b8b9..87fa922b9 100644 --- a/arch/cpu/simplelink-cc13xx-cc26xx/cc13xx-cc26xx-conf.h +++ b/arch/cpu/simplelink-cc13xx-cc26xx/cc13xx-cc26xx-conf.h @@ -91,7 +91,7 @@ */ /* - * Set the inactivity timeout peroid for the RF driver. This determines how + * Set the inactivity timeout period for the RF driver. This determines how * long the RF driver will wait when inactive until turning off the RF Core. * Specified in microseconds. */ diff --git a/arch/platform/simplelink/Makefile.simplelink b/arch/platform/simplelink/Makefile.simplelink index 929bbc8b7..d14643c3f 100644 --- a/arch/platform/simplelink/Makefile.simplelink +++ b/arch/platform/simplelink/Makefile.simplelink @@ -24,7 +24,7 @@ verify_family = $(shell [ -d $(CONTIKI)/arch/platform/simplelink/$(1)/$(BOARD) ] # Test each supported SimpleLink family and see if it contains the specified Board. # Throw an error if it isn't found. FAMILY := $(foreach FAMILY, $(SIMPLELINK_FAMILIES), $(call verify_family,$(FAMILY))) -ifeq ($(FAMILY),) +ifeq ($(strip $(FAMILY)),) $(error Board '$(BOARD)' does not corresponding to any SimpleLink family. Make sure your BOARD variable is correct.) endif # If multiple families are found, only the first one is chosen. If this ever diff --git a/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index 5c34a233f..9f2dbe45b 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -25,20 +25,22 @@ TARGET_FAMILY_DIRS += $(BOARD) CONTIKI_TARGET_DIRS += $(FAMILY) CONTIKI_TARGET_DIRS += $(addprefix $(FAMILY)/, $(TARGET_FAMILY_DIRS)) -DEFINES += DeviceFamily_$(DEVICE_FAMILY) -DEFINES += DEVICE_LINE_$(DEVICE_LINE) -DEFINES += DEVICE_$(DEVICE) -DEFINES += $(BOARD_TYPE) -DEFINES += SUPPORTS_PROP_MODE=$(SUPPORTS_PROP_MODE) -DEFINES += SUPPORTS_IEEE_MODE=$(SUPPORTS_IEEE_MODE) -DEFINES += SUPPORTS_BLE_BEACON=$(SUPPORTS_BLE_BEACON) -DEFINES += SUPPORTS_HIGH_PA=$(SUPPORTS_HIGH_PA) +BOARD_DEFINES += DeviceFamily_$(DEVICE_FAMILY) +BOARD_DEFINES += DEVICE_LINE_$(DEVICE_LINE) +BOARD_DEFINES += DEVICE_$(DEVICE) +BOARD_DEFINES += $(BOARD_TYPE) +BOARD_DEFINES += SUPPORTS_PROP_MODE=$(SUPPORTS_PROP_MODE) +BOARD_DEFINES += SUPPORTS_IEEE_MODE=$(SUPPORTS_IEEE_MODE) +BOARD_DEFINES += SUPPORTS_BLE_BEACON=$(SUPPORTS_BLE_BEACON) +BOARD_DEFINES += SUPPORTS_HIGH_PA=$(SUPPORTS_HIGH_PA) # If the user-specified a Node ID, pass a define ifdef NODEID - DEFINES += IEEE_ADDR_NODE_ID=$(NODEID) + BOARD_DEFINES += IEEE_ADDR_NODE_ID=$(NODEID) endif +CFLAGS += $(addprefix -D, $(BOARD_DEFINES)) + CONTIKI_TARGET_SOURCEFILES += platform.c CONTIKI_TARGET_SOURCEFILES += batmon-sensor.c CONTIKI_TARGET_SOURCEFILES += $(BOARD_SOURCEFILES) diff --git a/examples/dev/gpio-hal/simplelink/pins.c b/examples/dev/gpio-hal/simplelink/pins.c new file mode 100644 index 000000000..16a7afa1f --- /dev/null +++ b/examples/dev/gpio-hal/simplelink/pins.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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 +/*---------------------------------------------------------------------------*/ +gpio_hal_pin_t out_pin1 = Board_PIN_LED0; +gpio_hal_pin_t out_pin2 = Board_PIN_LED1; +gpio_hal_pin_t out_pin3 = Board_PIN_LED2; +/*---------------------------------------------------------------------------*/ +gpio_hal_pin_t btn_pin = Board_PIN_BTN1; +/*---------------------------------------------------------------------------*/ diff --git a/tests/02-compile-arm-ports-01/Makefile b/tests/02-compile-arm-ports-01/Makefile index 4bb1e9269..f4063a54b 100644 --- a/tests/02-compile-arm-ports-01/Makefile +++ b/tests/02-compile-arm-ports-01/Makefile @@ -35,6 +35,40 @@ dev/leds/srf06-cc26xx:BOARD=launchpad/cc2650 \ mqtt-client/srf06-cc26xx:BOARD=srf06/cc26xx \ mqtt-client/srf06-cc26xx:BOARD=launchpad/cc2650 \ mqtt-client/srf06-cc26xx:BOARD=sensortag/cc2650 \ +hello-world/simplelink:BOARD=launchpad/cc26x2r1 \ +hello-world/simplelink:BOARD=sensortag/cc2650 \ +nullnet/simplelink:BOARD=sensortag/cc2650 \ +rpl-border-router/simplelink:BOARD=launchpad/cc26x2r1 \ +sensniff/simplelink:BOARD=launchpad/cc26x2r1 \ +dev/gpio-hal/simplelink:BOARD=launchpad/cc1310 \ +dev/gpio-hal/simplelink:BOARD=launchpad/cc1312r1 \ +dev/gpio-hal/simplelink:BOARD=launchpad/cc1350 \ +dev/gpio-hal/simplelink:BOARD=launchpad/cc1350-4 \ +dev/gpio-hal/simplelink:BOARD=launchpad/cc1352p1 \ +dev/gpio-hal/simplelink:BOARD=launchpad/cc1352p-2 \ +dev/gpio-hal/simplelink:BOARD=launchpad/cc1352p-4 \ +dev/gpio-hal/simplelink:BOARD=launchpad/cc1352r1 \ +dev/gpio-hal/simplelink:BOARD=launchpad/cc26x2r1 \ +dev/gpio-hal/simplelink:BOARD=sensortag/cc1350 \ +dev/gpio-hal/simplelink:BOARD=sensortag/cc2650 \ +dev/gpio-hal/simplelink:BOARD=srf06/cc13x0 \ +dev/gpio-hal/simplelink:BOARD=srf06/cc26x0 \ +dev/leds/simplelink:BOARD=launchpad/cc1310 \ +dev/leds/simplelink:BOARD=launchpad/cc1312r1 \ +dev/leds/simplelink:BOARD=launchpad/cc1350 \ +dev/leds/simplelink:BOARD=launchpad/cc1350-4 \ +dev/leds/simplelink:BOARD=launchpad/cc1352p1 \ +dev/leds/simplelink:BOARD=launchpad/cc1352p-2 \ +dev/leds/simplelink:BOARD=launchpad/cc1352p-4 \ +dev/leds/simplelink:BOARD=launchpad/cc1352r1 \ +dev/leds/simplelink:BOARD=launchpad/cc26x2r1 \ +dev/leds/simplelink:BOARD=sensortag/cc1350 \ +dev/leds/simplelink:BOARD=sensortag/cc2650 \ +dev/leds/simplelink:BOARD=srf06/cc13x0 \ +dev/leds/simplelink:BOARD=srf06/cc26x0 \ +mqtt-client/simplelink:BOARD=launchpad/cc26x2r1 \ +mqtt-client/simplelink:BOARD=sensortag/cc2650:DEFINES=BOARD_CONF_SENSORS_DISABLE=1,TI_SPI_CONF_ENABLE=0 \ +mqtt-client/simplelink:BOARD=srf06/cc26x0:DEFINES=BOARD_CONF_SENSORS_DISABLE=1,TI_SPI_CONF_ENABLE=0 \ mqtt-client/cc2538dk \ storage/cfs-coffee/cc2538dk \ sensniff/cc2538dk \ diff --git a/tests/compile-all/build.sh b/tests/compile-all/build.sh index 795343eeb..bab912f06 100755 --- a/tests/compile-all/build.sh +++ b/tests/compile-all/build.sh @@ -101,6 +101,10 @@ do then # srf06-cc26xx has multiple boards BOARDS="srf06/cc26xx srf06/cc13xx launchpad/cc2650 launchpad/cc1350 sensortag/cc2650 sensortag/cc1350" + elif [[ "$platform" == "simplelink" ]] + then + # SimpleLink has multiple boards + BOARDS="launchpad/cc1310 launchpad/cc1312r1 launchpad/cc1350 launchpad/cc1350-4 launchpad/cc1352p-2 launchpad/cc1352p-4 launchpad/cc1352p1 launchpad/cc1352r1 launchpad/cc2650 launchpad/cc26x2r1 sensortag/cc1350 sensortag/cc2650 srf06/cc13x0 srf06/cc26x0" elif [[ "$platform" == "zoul" ]] then # Zoul has multiple boards From 3ece31be3008783a7e5cad3291f4fcfe94fa95ea Mon Sep 17 00:00:00 2001 From: Jinyan BAI Date: Tue, 11 Sep 2018 12:43:27 +0100 Subject: [PATCH 342/485] add support for TI's CC2640R2 --- .gitmodules | 3 + arch/cpu/cc26xx-cc13xx/Makefile.cc26x0r2f | 3 + arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx | 9 +- arch/cpu/cc26xx-cc13xx/cc26xx.ld | 1 + arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c | 10 +- arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h | 12 +- arch/cpu/cc26xx-cc13xx/dev/spi-arch.c | 22 +- arch/cpu/cc26xx-cc13xx/lib/cc2640r2-sdk | 1 + arch/cpu/cc26xx-cc13xx/lpm.c | 5 +- arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c | 3 + arch/cpu/cc26xx-cc13xx/ti-lib-rom.h | 40 ++-- arch/cpu/cc26xx-cc13xx/ti-lib.h | 8 + .../srf06-cc26xx/Makefile.srf06-cc26xx | 2 +- .../launchpad/cc2640r2/Makefile.cc2640r2 | 8 + .../srf06-cc26xx/launchpad/cc2640r2/board.h | 219 ++++++++++++++++++ arch/platform/srf06-cc26xx/platform.c | 2 + tests/02-compile-arm-ports-01/Makefile | 2 + 17 files changed, 314 insertions(+), 36 deletions(-) create mode 100644 arch/cpu/cc26xx-cc13xx/Makefile.cc26x0r2f create mode 160000 arch/cpu/cc26xx-cc13xx/lib/cc2640r2-sdk create mode 100644 arch/platform/srf06-cc26xx/launchpad/cc2640r2/Makefile.cc2640r2 create mode 100644 arch/platform/srf06-cc26xx/launchpad/cc2640r2/board.h diff --git a/.gitmodules b/.gitmodules index 80dd37e17..cf37acb3b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,3 +22,6 @@ [submodule "tools/motelist"] path = tools/motelist url = https://github.com/contiki-ng/motelist +[submodule "arch/cpu/cc26xx-cc13xx/lib/cc2640r2-sdk"] + path = arch/cpu/cc26xx-cc13xx/lib/cc2640r2-sdk + url = https://github.com/contiki-ng/cc2640r2-sdk.git diff --git a/arch/cpu/cc26xx-cc13xx/Makefile.cc26x0r2f b/arch/cpu/cc26xx-cc13xx/Makefile.cc26x0r2f new file mode 100644 index 000000000..decece481 --- /dev/null +++ b/arch/cpu/cc26xx-cc13xx/Makefile.cc26x0r2f @@ -0,0 +1,3 @@ +TI_XXWARE_PATH = lib/cc2640r2-sdk + +include $(CONTIKI_CPU)/Makefile.cc26xx-cc13xx diff --git a/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx b/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx index a5ffec9a6..3d4af557c 100644 --- a/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx +++ b/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx @@ -1,13 +1,8 @@ CPU_ABS_PATH = arch/cpu/cc26xx-cc13xx TI_XXWARE = $(CONTIKI_CPU)/$(TI_XXWARE_PATH) -ifeq (,$(wildcard $(TI_XXWARE))) - $(warning $(TI_XXWARE) does not exist.) - $(warning Did you run 'git submodule update --init' ?) - $(error "") -endif - -### cc26xxware sources under driverlib will be added to the MODULES list +### cc26xxware / cc26x0r2fware sources under driverlib will be added to the +### MODULES list TI_XXWARE_SRC = $(CPU_ABS_PATH)/$(TI_XXWARE_PATH)/driverlib ### The directory with startup sources will be added to the CONTIKI_CPU_DIRS diff --git a/arch/cpu/cc26xx-cc13xx/cc26xx.ld b/arch/cpu/cc26xx-cc13xx/cc26xx.ld index 46ecf1322..649da32cf 100644 --- a/arch/cpu/cc26xx-cc13xx/cc26xx.ld +++ b/arch/cpu/cc26xx-cc13xx/cc26xx.ld @@ -76,6 +76,7 @@ SECTIONS *(.data*) _edata = .; } > SRAM AT > FLASH + _ldata = LOADADDR(.data); .ARM.exidx : { diff --git a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c index a7b025800..293fc1cce 100644 --- a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c +++ b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c @@ -53,7 +53,11 @@ gpio_hal_arch_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg) gpio_hal_pin_cfg_t tmp; /* Clear settings that we are about to change, keep everything else */ +#ifdef ThisLibraryIsFor_CC26x0R2_HaltIfViolated + config = ti_lib_ioc_port_configure_get(pin); +#else config = ti_lib_rom_ioc_port_configure_get(pin); +#endif config &= ~CONFIG_MASK; tmp = cfg & GPIO_HAL_PIN_CFG_EDGE_BOTH; @@ -94,7 +98,11 @@ gpio_hal_arch_pin_cfg_get(gpio_hal_pin_t pin) uint32_t config; cfg = 0; - config = ti_lib_rom_ioc_port_configure_get(pin); +#ifdef ThisLibraryIsFor_CC26x0R2_HaltIfViolated + config = ti_lib_ioc_port_configure_get(pin); +#else + config = ti_lib_rom_ioc_port_configure_get(pin); +#endif /* Pull */ tmp = config & IOC_IOPULL_M; diff --git a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h index 7d87670c5..ff13dacf7 100644 --- a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h +++ b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h @@ -56,9 +56,13 @@ #define gpio_hal_arch_interrupt_enable(p) interrupt_enable(p) #define gpio_hal_arch_interrupt_disable(p) ti_lib_rom_ioc_int_disable(p) -#define gpio_hal_arch_pin_set_input(p) ti_lib_rom_ioc_pin_type_gpio_input(p) -#define gpio_hal_arch_pin_set_output(p) ti_lib_rom_ioc_pin_type_gpio_output(p) - +#ifdef ThisLibraryIsFor_CC26x0R2_HaltIfViolated + #define gpio_hal_arch_pin_set_input(p) ti_lib_ioc_pin_type_gpio_input(p) + #define gpio_hal_arch_pin_set_output(p) ti_lib_ioc_pin_type_gpio_output(p) +#else + #define gpio_hal_arch_pin_set_input(p) ti_lib_rom_ioc_pin_type_gpio_input(p) + #define gpio_hal_arch_pin_set_output(p) ti_lib_rom_ioc_pin_type_gpio_output(p) +#endif #define gpio_hal_arch_set_pin(p) ti_lib_gpio_set_dio(p) #define gpio_hal_arch_clear_pin(p) ti_lib_gpio_clear_dio(p) #define gpio_hal_arch_toggle_pin(p) ti_lib_gpio_toggle_dio(p) @@ -73,7 +77,9 @@ static inline void interrupt_enable(gpio_hal_pin_t pin) { ti_lib_gpio_clear_event_dio(pin); +#ifndef ThisLibraryIsFor_CC26x0R2_HaltIfViolated ti_lib_rom_ioc_int_enable(pin); +#endif } /*---------------------------------------------------------------------------*/ #endif /* GPIO_HAL_ARCH_H_ */ diff --git a/arch/cpu/cc26xx-cc13xx/dev/spi-arch.c b/arch/cpu/cc26xx-cc13xx/dev/spi-arch.c index d274a1d52..897cfe878 100644 --- a/arch/cpu/cc26xx-cc13xx/dev/spi-arch.c +++ b/arch/cpu/cc26xx-cc13xx/dev/spi-arch.c @@ -130,10 +130,18 @@ spi_arch_lock_and_open(spi_device_t *dev) /* SPI configuration */ ti_lib_ssi_int_disable(spi_controller[dev->spi_controller].ssi_base, SSI_RXOR | SSI_RXFF | SSI_RXTO | SSI_TXFF); ti_lib_ssi_int_clear(spi_controller[dev->spi_controller].ssi_base, SSI_RXOR | SSI_RXTO); - ti_lib_rom_ssi_config_set_exp_clk(spi_controller[dev->spi_controller].ssi_base, ti_lib_sys_ctrl_clock_get(), + +#ifdef ThisLibraryIsFor_CC26x0R2_HaltIfViolated + ti_lib_ssi_config_set_exp_clk(spi_controller[dev->spi_controller].ssi_base, ti_lib_sys_ctrl_clock_get(), get_mode(dev), SSI_MODE_MASTER, dev->spi_bit_rate, 8); - ti_lib_rom_ioc_pin_type_ssi_master(spi_controller[dev->spi_controller].ssi_base, dev->pin_spi_miso, + ti_lib_ioc_pin_type_ssi_master(spi_controller[dev->spi_controller].ssi_base, dev->pin_spi_miso, dev->pin_spi_mosi, IOID_UNUSED, dev->pin_spi_sck); +#else + ti_lib_rom_ssi_config_set_exp_clk(spi_controller[dev->spi_controller].ssi_base, ti_lib_sys_ctrl_clock_get(), + get_mode(dev), SSI_MODE_MASTER, dev->spi_bit_rate, 8); + ti_lib_rom_ioc_pin_type_ssi_master(spi_controller[dev->spi_controller].ssi_base, dev->pin_spi_miso, + dev->pin_spi_mosi, IOID_UNUSED, dev->pin_spi_sck); +#endif ti_lib_ssi_enable(spi_controller[dev->spi_controller].ssi_base); @@ -205,14 +213,20 @@ spi_arch_transfer(spi_device_t *dev, for(i = 0; i < totlen; i++) { c = i < wlen ? write_buf[i] : 0; ti_lib_ssi_data_put(spi_controller[dev->spi_controller].ssi_base, (uint8_t)c); +#ifdef ThisLibraryIsFor_CC26x0R2_HaltIfViolated + ti_lib_ssi_data_get(spi_controller[dev->spi_controller].ssi_base, &c); +#else ti_lib_rom_ssi_data_get(spi_controller[dev->spi_controller].ssi_base, &c); +#endif if(i < rlen) { inbuf[i] = (uint8_t)c; } } - +#ifdef ThisLibraryIsFor_CC26x0R2_HaltIfViolated + while(ti_lib_ssi_data_get_non_blocking(spi_controller[dev->spi_controller].ssi_base, &c)) ; +#else while(ti_lib_rom_ssi_data_get_non_blocking(spi_controller[dev->spi_controller].ssi_base, &c)) ; - +#endif return SPI_DEV_STATUS_OK; } /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc26xx-cc13xx/lib/cc2640r2-sdk b/arch/cpu/cc26xx-cc13xx/lib/cc2640r2-sdk new file mode 160000 index 000000000..0c01cfd36 --- /dev/null +++ b/arch/cpu/cc26xx-cc13xx/lib/cc2640r2-sdk @@ -0,0 +1 @@ +Subproject commit 0c01cfd363fd421d43baaa52af551a4ce8bf9e2b diff --git a/arch/cpu/cc26xx-cc13xx/lpm.c b/arch/cpu/cc26xx-cc13xx/lpm.c index a5e746f24..d5da32686 100644 --- a/arch/cpu/cc26xx-cc13xx/lpm.c +++ b/arch/cpu/cc26xx-cc13xx/lpm.c @@ -162,8 +162,10 @@ lpm_shutdown(uint32_t wakeup_pin, uint32_t io_pull, uint32_t wake_on) ti_lib_aon_wuc_mcu_power_off_config(MCU_VIRT_PWOFF_DISABLE); /* Latch the IOs in the padring and enable I/O pad sleep mode */ +#if !defined(ThisLibraryIsFor_CC26x0R2_HaltIfViolated) ti_lib_pwr_ctrl_io_freeze_enable(); +#endif /* Turn off VIMS cache, CRAM and TRAM - possibly not required */ ti_lib_prcm_cache_retention_disable(); ti_lib_vims_mode_set(VIMS_BASE, VIMS_MODE_OFF); @@ -191,7 +193,8 @@ wake_up(void) ti_lib_sys_ctrl_aon_sync(); /* Adjust recharge settings */ - ti_lib_sys_ctrl_adjust_recharge_after_power_down(); + // May need to change to XOSC_IN_LOW_POWER_MODE + ti_lib_sys_ctrl_adjust_recharge_after_power_down(XOSC_IN_HIGH_POWER_MODE); /* * Release the request to the uLDO diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c b/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c index 23b78eab4..ccc014b54 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c +++ b/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c @@ -399,6 +399,9 @@ rf_core_set_modesel() } else if(chip_type == CHIP_TYPE_CC1350) { HWREG(PRCM_BASE + PRCM_O_RFCMODESEL) = PRCM_RFCMODESEL_CURR_MODE5; rv = RF_CORE_CMD_OK; + } else if (chip_type == CHIP_TYPE_CC2640R2) { + HWREG(PRCM_BASE + PRCM_O_RFCMODESEL) = PRCM_RFCMODESEL_CURR_MODE1; + rv = RF_CORE_CMD_OK; } return rv; diff --git a/arch/cpu/cc26xx-cc13xx/ti-lib-rom.h b/arch/cpu/cc26xx-cc13xx/ti-lib-rom.h index 7334978b9..062b5103a 100644 --- a/arch/cpu/cc26xx-cc13xx/ti-lib-rom.h +++ b/arch/cpu/cc26xx-cc13xx/ti-lib-rom.h @@ -90,25 +90,27 @@ /* IOC API */ #define ti_lib_rom_ioc_port_configure_set ROM_IOCPortConfigureSet -#define ti_lib_rom_ioc_port_configure_get ROM_IOCPortConfigureGet -#define ti_lib_rom_ioc_io_shutdown_set ROM_IOCIOShutdownSet -#define ti_lib_rom_ioc_io_mode_set ROM_IOCIOModeSet -#define ti_lib_rom_ioc_io_int_set ROM_IOCIOIntSet -#define ti_lib_rom_ioc_io_port_pull_set ROM_IOCIOPortPullSet -#define ti_lib_rom_ioc_io_hyst_set ROM_IOCIOHystSet -#define ti_lib_rom_ioc_io_input_set ROM_IOCIOInputSet -#define ti_lib_rom_ioc_io_slew_ctrl_set ROM_IOCIOSlewCtrlSet -#define ti_lib_rom_ioc_io_drv_strength_set ROM_IOCIODrvStrengthSet -#define ti_lib_rom_ioc_io_port_id_set ROM_IOCIOPortIdSet -#define ti_lib_rom_ioc_int_enable ROM_IOCIntEnable -#define ti_lib_rom_ioc_int_disable ROM_IOCIntDisable -#define ti_lib_rom_ioc_pin_type_gpio_input ROM_IOCPinTypeGpioInput -#define ti_lib_rom_ioc_pin_type_gpio_output ROM_IOCPinTypeGpioOutput -#define ti_lib_rom_ioc_pin_type_uart ROM_IOCPinTypeUart -#define ti_lib_rom_ioc_pin_type_ssi_master ROM_IOCPinTypeSsiMaster -#define ti_lib_rom_ioc_pin_type_ssi_slave ROM_IOCPinTypeSsiSlave -#define ti_lib_rom_ioc_pin_type_i2c ROM_IOCPinTypeI2c -#define ti_lib_rom_ioc_pin_type_aux ROM_IOCPinTypeAux +#if !defined(ThisLibraryIsFor_CC26x0R2_HaltIfViolated) + #define ti_lib_rom_ioc_port_configure_get ROM_IOCPortConfigureGet + #define ti_lib_rom_ioc_io_shutdown_set ROM_IOCIOShutdownSet + #define ti_lib_rom_ioc_io_mode_set ROM_IOCIOModeSet + #define ti_lib_rom_ioc_io_int_set ROM_IOCIOIntSet + #define ti_lib_rom_ioc_io_port_pull_set ROM_IOCIOPortPullSet + #define ti_lib_rom_ioc_io_hyst_set ROM_IOCIOHystSet + #define ti_lib_rom_ioc_io_input_set ROM_IOCIOInputSet + #define ti_lib_rom_ioc_io_slew_ctrl_set ROM_IOCIOSlewCtrlSet + #define ti_lib_rom_ioc_io_drv_strength_set ROM_IOCIODrvStrengthSet + #define ti_lib_rom_ioc_io_port_id_set ROM_IOCIOPortIdSet + #define ti_lib_rom_ioc_int_enable ROM_IOCIntEnable + #define ti_lib_rom_ioc_int_disable ROM_IOCIntDisable + #define ti_lib_rom_ioc_pin_type_gpio_input ROM_IOCPinTypeGpioInput + #define ti_lib_rom_ioc_pin_type_gpio_output ROM_IOCPinTypeGpioOutput + #define ti_lib_rom_ioc_pin_type_uart ROM_IOCPinTypeUart + #define ti_lib_rom_ioc_pin_type_ssi_master ROM_IOCPinTypeSsiMaster + #define ti_lib_rom_ioc_pin_type_ssi_slave ROM_IOCPinTypeSsiSlave + #define ti_lib_rom_ioc_pin_type_i2c ROM_IOCPinTypeI2c + #define ti_lib_rom_ioc_pin_type_aux ROM_IOCPinTypeAux +#endif /* PRCM API */ #define ti_lib_rom_prcm_inf_clock_configure_set ROM_PRCMInfClockConfigureSet diff --git a/arch/cpu/cc26xx-cc13xx/ti-lib.h b/arch/cpu/cc26xx-cc13xx/ti-lib.h index 3ab5ceb28..6a8fae405 100644 --- a/arch/cpu/cc26xx-cc13xx/ti-lib.h +++ b/arch/cpu/cc26xx-cc13xx/ti-lib.h @@ -200,8 +200,14 @@ #define ti_lib_chipinfo_get_device_id_hw_rev_code(...) ChipInfo_GetDeviceIdHwRevCode(__VA_ARGS__) #define ti_lib_chipinfo_get_chip_type(...) ChipInfo_GetChipType(__VA_ARGS__) #define ti_lib_chipinfo_get_chip_family(...) ChipInfo_GetChipFamily(__VA_ARGS__) +#ifdef ThisLibraryIsFor_CC26x0R2_HaltIfViolated +#define ti_lib_chipinfo_chip_family_is_cc26xx(...) ChipInfo_ChipFamilyIs_CC26x0(__VA_ARGS__) +#define ti_lib_chipinfo_chip_family_is_cc13xx(...) ChipInfo_ChipFamilyIs_CC13x0(__VA_ARGS__) +#define ti_lib_chipinfo_chip_family_is_cc26x0r2(...) ChipInfo_ChipFamilyIs_CC26x0R2(__VA_ARGS__) +#else #define ti_lib_chipinfo_chip_family_is_cc26xx(...) ChipInfo_ChipFamilyIsCC26xx(__VA_ARGS__) #define ti_lib_chipinfo_chip_family_is_cc13xx(...) ChipInfo_ChipFamilyIsCC13xx(__VA_ARGS__) +#endif #define ti_lib_chipinfo_get_hw_revision(...) ChipInfo_GetHwRevision(__VA_ARGS__) #define ti_lib_chipinfo_hw_revision_is_1_0(...) ChipInfo_HwRevisionIs_1_0(__VA_ARGS__) #define ti_lib_chipinfo_hw_revision_is_gteq_2_0(...) ChipInfo_HwRevisionIs_GTEQ_2_0(__VA_ARGS__) @@ -388,8 +394,10 @@ #define ti_lib_pwr_ctrl_source_get(...) PowerCtrlSourceGet(__VA_ARGS__) #define ti_lib_pwr_ctrl_reset_source_get(...) PowerCtrlResetSourceGet(__VA_ARGS__) #define ti_lib_pwr_ctrl_reset_source_clear(...) PowerCtrlResetSourceClear(__VA_ARGS__) +#if !defined(ThisLibraryIsFor_CC26x0R2_HaltIfViolated) #define ti_lib_pwr_ctrl_io_freeze_enable(...) PowerCtrlIOFreezeEnable(__VA_ARGS__) #define ti_lib_pwr_ctrl_io_freeze_disable(...) PowerCtrlIOFreezeDisable(__VA_ARGS__) +#endif /*---------------------------------------------------------------------------*/ /* rfc.h */ #include "driverlib/rfc.h" diff --git a/arch/platform/srf06-cc26xx/Makefile.srf06-cc26xx b/arch/platform/srf06-cc26xx/Makefile.srf06-cc26xx index db4209adc..03eefcf8b 100644 --- a/arch/platform/srf06-cc26xx/Makefile.srf06-cc26xx +++ b/arch/platform/srf06-cc26xx/Makefile.srf06-cc26xx @@ -6,7 +6,7 @@ endif ### Board and BSP selection BOARD ?= srf06/cc26xx -BOARDS = srf06/cc26xx srf06/cc13xx launchpad/cc2650 launchpad/cc1310 launchpad/cc1350 sensortag/cc2650 sensortag/cc1350 +BOARDS = srf06/cc26xx srf06/cc13xx launchpad/cc2640r2 launchpad/cc2650 launchpad/cc1310 launchpad/cc1350 sensortag/cc2650 sensortag/cc1350 CONTIKI_TARGET_DIRS += . diff --git a/arch/platform/srf06-cc26xx/launchpad/cc2640r2/Makefile.cc2640r2 b/arch/platform/srf06-cc26xx/launchpad/cc2640r2/Makefile.cc2640r2 new file mode 100644 index 000000000..5abb37a97 --- /dev/null +++ b/arch/platform/srf06-cc26xx/launchpad/cc2640r2/Makefile.cc2640r2 @@ -0,0 +1,8 @@ +### Will allow the inclusion of the correct CPU makefile +CPU_FAMILY = cc26x0r2f + +### Add to the source dirs +CONTIKI_TARGET_DIRS += launchpad/cc2640r2 + +### Include the common launchpad makefile +include $(PLATFORM_ROOT_DIR)/launchpad/Makefile.launchpad diff --git a/arch/platform/srf06-cc26xx/launchpad/cc2640r2/board.h b/arch/platform/srf06-cc26xx/launchpad/cc2640r2/board.h new file mode 100644 index 000000000..4d352041a --- /dev/null +++ b/arch/platform/srf06-cc26xx/launchpad/cc2640r2/board.h @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** \addtogroup launchpad-peripherals + * @{ + * + * \defgroup launchpad-cc26xx-specific CC2650 LaunchPad Peripherals + * + * Defines related to the CC2650 LaunchPad + * + * This file provides connectivity information on LEDs, Buttons, UART and + * other peripherals + * + * This file is not meant to be modified by the user. + * @{ + * + * \file + * Header file with definitions related to the I/O connections on the TI + * CC2650 LaunchPad + * + * \note Do not include this file directly. It gets included by contiki-conf + * after all relevant directives have been set. + */ +/*---------------------------------------------------------------------------*/ +#ifndef BOARD_H_ +#define BOARD_H_ +/*---------------------------------------------------------------------------*/ +#include "ioc.h" +/*---------------------------------------------------------------------------*/ +/** + * \name LED HAL configuration + * + * Those values are not meant to be modified by the user + * @{ + */ +#define LEDS_CONF_COUNT 2 +#define LEDS_CONF_RED 1 +#define LEDS_CONF_GREEN 2 +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \name LED IOID mappings + * + * Those values are not meant to be modified by the user + * @{ + */ +#define BOARD_IOID_LED_1 IOID_6 +#define BOARD_IOID_LED_2 IOID_7 +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \name UART IOID mapping + * + * Those values are not meant to be modified by the user + * @{ + */ +#define BOARD_IOID_UART_RX IOID_2 +#define BOARD_IOID_UART_TX IOID_3 +#define BOARD_IOID_UART_RTS IOID_18 +#define BOARD_IOID_UART_CTS IOID_19 +#define BOARD_UART_RX (1 << BOARD_IOID_UART_RX) +#define BOARD_UART_TX (1 << BOARD_IOID_UART_TX) +#define BOARD_UART_RTS (1 << BOARD_IOID_UART_RTS) +#define BOARD_UART_CTS (1 << BOARD_IOID_UART_CTS) +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \name Button IOID mapping + * + * Those values are not meant to be modified by the user + * @{ + */ +#define BOARD_IOID_KEY_LEFT IOID_13 +#define BOARD_IOID_KEY_RIGHT IOID_14 +#define BOARD_KEY_LEFT (1 << BOARD_IOID_KEY_LEFT) +#define BOARD_KEY_RIGHT (1 << BOARD_IOID_KEY_RIGHT) +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \name External flash IOID mapping + * + * Those values are not meant to be modified by the user + * @{ + */ +#define EXT_FLASH_SPI_CONTROLLER SPI_CONTROLLER_SPI0 + +#define BOARD_IOID_FLASH_SCK IOID_10 +#define BOARD_IOID_FLASH_MOSI IOID_9 +#define BOARD_IOID_FLASH_MISO IOID_8 +#define BOARD_IOID_FLASH_CS IOID_20 + +#define EXT_FLASH_SPI_PIN_SCK 10 +#define EXT_FLASH_SPI_PIN_MOSI 9 +#define EXT_FLASH_SPI_PIN_MISO 8 +#define EXT_FLASH_SPI_PIN_CS 20 + +#define EXT_FLASH_DEVICE_ID 0x14 +#define EXT_FLASH_MID 0xC2 + +#define EXT_FLASH_PROGRAM_PAGE_SIZE 256 +#define EXT_FLASH_ERASE_SECTOR_SIZE 4096 +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \brief I2C IOID mappings + * + * Those values are not meant to be modified by the user + * @{ + */ +#define BOARD_IOID_SCL IOID_4 +#define BOARD_IOID_SDA IOID_5 +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \brief ROM bootloader configuration + * + * Change SET_CCFG_BL_CONFIG_BL_PIN_NUMBER to BOARD_IOID_KEY_xyz to select + * which button triggers the bootloader on reset. + * + * The remaining values are not meant to be modified by the user + * @{ + */ +#if ROM_BOOTLOADER_ENABLE +#define SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE 0xC5 +#define SET_CCFG_BL_CONFIG_BL_LEVEL 0x00 +#define SET_CCFG_BL_CONFIG_BL_PIN_NUMBER BOARD_IOID_KEY_LEFT +#define SET_CCFG_BL_CONFIG_BL_ENABLE 0xC5 +#else +#define SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE 0x00 +#define SET_CCFG_BL_CONFIG_BL_LEVEL 0x01 +#define SET_CCFG_BL_CONFIG_BL_PIN_NUMBER 0xFF +#define SET_CCFG_BL_CONFIG_BL_ENABLE 0xFF +#endif +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \brief Remaining pins + * + * Those values are not meant to be modified by the user + * @{ + */ +#define BOARD_IOID_DIO0 IOID_0 +#define BOARD_IOID_DIO1 IOID_1 +#define BOARD_IOID_CS IOID_11 +#define BOARD_IOID_TDO IOID_16 +#define BOARD_IOID_TDI IOID_17 +#define BOARD_IOID_DIO12 IOID_12 +#define BOARD_IOID_DIO15 IOID_15 +#define BOARD_IOID_DIO21 IOID_21 +#define BOARD_IOID_DIO22 IOID_22 +#define BOARD_IOID_DIO23 IOID_23 +#define BOARD_IOID_DIO24 IOID_24 +#define BOARD_IOID_DIO25 IOID_25 +#define BOARD_IOID_DIO26 IOID_26 +#define BOARD_IOID_DIO27 IOID_27 +#define BOARD_IOID_DIO28 IOID_28 +#define BOARD_IOID_DIO29 IOID_29 +#define BOARD_IOID_DIO30 IOID_30 + +#define BOARD_UNUSED_PINS { \ + BOARD_IOID_DIO0, BOARD_IOID_DIO1, BOARD_IOID_CS, BOARD_IOID_TDO, \ + BOARD_IOID_TDI, BOARD_IOID_DIO12, BOARD_IOID_DIO15, BOARD_IOID_DIO21, \ + BOARD_IOID_DIO22, BOARD_IOID_DIO23, BOARD_IOID_DIO24, BOARD_IOID_DIO25, \ + BOARD_IOID_DIO26, BOARD_IOID_DIO27, BOARD_IOID_DIO28, BOARD_IOID_DIO29, \ + BOARD_IOID_DIO30, IOID_UNUSED \ + } +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \brief Board indices for the button HAL + * + * Those values are not meant to be modified by the user + * @{ + */ +#define BOARD_BUTTON_HAL_INDEX_KEY_LEFT 0x00 +#define BOARD_BUTTON_HAL_INDEX_KEY_RIGHT 0x01 +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \name Device string used on startup + * @{ + */ +#define BOARD_STRING "LAUNCHXL-CC2640R2" + +/** @} */ +/*---------------------------------------------------------------------------*/ +#endif /* BOARD_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/platform/srf06-cc26xx/platform.c b/arch/platform/srf06-cc26xx/platform.c index d71e597f1..427504ed8 100644 --- a/arch/platform/srf06-cc26xx/platform.c +++ b/arch/platform/srf06-cc26xx/platform.c @@ -158,8 +158,10 @@ platform_init_stage_one() * latches in the first place. Before doing these things though, we should * allow software to first regain control of pins */ +#if !defined(ThisLibraryIsFor_CC26x0R2_HaltIfViolated) ti_lib_pwr_ctrl_io_freeze_disable(); +#endif ti_lib_rom_int_enable(INT_AON_GPIO_EDGE); ti_lib_int_master_enable(); diff --git a/tests/02-compile-arm-ports-01/Makefile b/tests/02-compile-arm-ports-01/Makefile index 4bb1e9269..a6288ae7c 100644 --- a/tests/02-compile-arm-ports-01/Makefile +++ b/tests/02-compile-arm-ports-01/Makefile @@ -24,6 +24,7 @@ dev/gpio-hal/srf06-cc26xx:BOARD=sensortag/cc2650 \ dev/gpio-hal/srf06-cc26xx:BOARD=launchpad/cc1310 \ dev/gpio-hal/srf06-cc26xx:BOARD=launchpad/cc1350 \ dev/gpio-hal/srf06-cc26xx:BOARD=launchpad/cc2650 \ +dev/gpio-hal/srf06-cc26xx:BOARD=launchpad/cc2640r2 \ dev/leds/srf06-cc26xx:BOARD=srf06/cc13xx \ dev/leds/srf06-cc26xx:BOARD=srf06/cc26xx \ dev/leds/srf06-cc26xx:BOARD=sensortag/cc1350 \ @@ -31,6 +32,7 @@ dev/leds/srf06-cc26xx:BOARD=sensortag/cc2650 \ dev/leds/srf06-cc26xx:BOARD=launchpad/cc1310 \ dev/leds/srf06-cc26xx:BOARD=launchpad/cc1350 \ dev/leds/srf06-cc26xx:BOARD=launchpad/cc2650 \ +dev/leds/srf06-cc26xx:BOARD=launchpad/cc2640r2 \ 6tisch/etsi-plugtest-2017/srf06-cc26xx:BOARD=launchpad/cc2650 \ mqtt-client/srf06-cc26xx:BOARD=srf06/cc26xx \ mqtt-client/srf06-cc26xx:BOARD=launchpad/cc2650 \ From 9406f5b5d9f34ba3d0ed37ac9c070d49fd0d367c Mon Sep 17 00:00:00 2001 From: Jinyan BAI Date: Tue, 11 Sep 2018 12:45:29 +0100 Subject: [PATCH 343/485] BLE5 support for CC2640R2 --- .../rf-core/ble-hal/ble-hal-cc26xx.c | 35 ++- .../rf-core/ble-hal/rf-ble-cmd.c | 284 +++++++++++++++++- .../rf-core/ble-hal/rf-ble-cmd.h | 77 +++++ 3 files changed, 389 insertions(+), 7 deletions(-) diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.c b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.c index d4c761dcd..a9b949d93 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.c +++ b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2017, Graz University of Technology + * 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 @@ -34,6 +35,7 @@ * * \author * Michael Spoerk + * Jinyan BAI */ /*---------------------------------------------------------------------------*/ @@ -63,6 +65,9 @@ #include #include "rf-core/ble-hal/rf-ble-cmd.h" +#if RADIO_CONF_BLE5 +#include "rf_patches/rf_patch_cpe_bt5.h" +#endif /*---------------------------------------------------------------------------*/ #include "sys/log.h" #define LOG_MODULE "BLE-RADIO" @@ -117,9 +122,15 @@ ticks_to_unit(rtimer_clock_t value, uint32_t unit) return (uint32_t)temp; } /*---------------------------------------------------------------------------*/ +#if RADIO_CONF_BLE5 +#define CMD_BUFFER_SIZE 28 +#define PARAM_BUFFER_SIZE 48 +#define OUTPUT_BUFFER_SIZE 24 +#else #define CMD_BUFFER_SIZE 24 #define PARAM_BUFFER_SIZE 36 #define OUTPUT_BUFFER_SIZE 24 +#endif /*---------------------------------------------------------------------------*/ /* ADVERTISING data structures */ #define ADV_RX_BUFFERS_OVERHEAD 8 @@ -358,11 +369,23 @@ on(void) oscillators_request_hf_xosc(); if(!rf_core_is_accessible()) { /* boot the rf core */ - if(rf_core_boot() != RF_CORE_CMD_OK) { - LOG_ERR("ble_controller_reset() could not boot rf-core\n"); - return BLE_RESULT_ERROR; - } + /* boot and apply Bluetooth 5 Patch */ + if(rf_core_power_up() != RF_CORE_CMD_OK) { + LOG_ERR("rf_core_boot: rf_core_power_up() failed\n"); + rf_core_power_down(); + return RF_CORE_CMD_ERROR; + } + +#if RADIO_CONF_BLE5 + /* Apply Bluetooth 5 patch, if applicable */ + rf_patch_cpe_bt5(); +#endif + if(rf_core_start_rat() != RF_CORE_CMD_OK) { + LOG_ERR("rf_core_boot: rf_core_start_rat() failed\n"); + rf_core_power_down(); + return RF_CORE_CMD_ERROR; + } rf_core_setup_interrupts(0); oscillators_switch_to_hf_xosc(); @@ -845,7 +868,11 @@ connection_rx(ble_conn_param_t *param) while(RX_ENTRY_STATUS(param->rx_queue_current) == DATA_ENTRY_FINISHED) { rx_data = RX_ENTRY_DATA_PTR(param->rx_queue_current); +#if RADIO_CONF_BLE5 + len = RX_ENTRY_DATA_LENGTH(param->rx_queue_current) - 7 - 2; /* last 9 bytes are status, timestamp, ... */ +#else len = RX_ENTRY_DATA_LENGTH(param->rx_queue_current) - 6 - 2; /* last 8 bytes are status, timestamp, ... */ +#endif channel = (rx_data[len + 3] & 0x3F); frame_type = rx_data[0] & 0x03; more_data = (rx_data[0] & 0x10) >> 4; diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.c b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.c index cde42f99b..3d427c9ef 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.c +++ b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2017, Graz University of Technology + * 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 @@ -36,6 +37,7 @@ * * \author * Michael Spoerk + * Jinyan BAI */ /*---------------------------------------------------------------------------*/ #include "contiki.h" @@ -57,6 +59,62 @@ static uint16_t tx_power = 0x3161; /* 0 dBm */ /*static uint16_t tx_power = 0x0CCB; / * -15 dBm * / */ /*---------------------------------------------------------------------------*/ /* BLE overrides */ +#if RADIO_CONF_BLE5 +uint32_t ble_overrides_common[] = +{ + /* Rx: Set LNA IB trim value based on the selected defaultPhy.mainMode setting. (NOTE: The value 0x8 is a placeholder. The value to use should be set during run-time by radio driver function.) */ + ADI_HALFREG_OVERRIDE(0,4,0xF,0x8), + /* Rx: Set LNA IB offset used for automatic software compensation to 0 */ + (uint32_t)0x00008883, + /* Synth: Use 24 MHz crystal, enable extra PLL filtering */ + (uint32_t)0x02010403, + /* Synth: Set fine top and bottom code to 127 and 0 */ + HW_REG_OVERRIDE(0x4020, 0x7F00), + /* Synth: Configure faster calibration */ + HW32_ARRAY_OVERRIDE(0x4004, 1), + /* Synth: Configure faster calibration */ + (uint32_t)0x1C0C0618, + /* Synth: Configure faster calibration */ + (uint32_t)0xC00401A1, + /* Synth: Configure faster calibration */ + (uint32_t)0x21010101, + /* Synth: Configure faster calibration */ + (uint32_t)0xC0040141, + /* Synth: Configure faster calibration */ + (uint32_t)0x00214AD3, + /* Synth: Decrease synth programming time-out by 90 us (0x0298 RAT ticks = 166 us) */ + (uint32_t)0x02980243, + /* Bluetooth 5: Set correct total clock accuracy for received AuxPtr assuming local sleep clock of 50 ppm */ + (uint32_t)0x0E490823, + /* override_frontend_id.xml */ + (uint32_t)0xFFFFFFFF, +}; + +uint32_t ble_overrides_1Mbps[] = +{ + /* Rx: Set LNA IB trim to normal trim value. (NOTE: The value 0x8 is a placeholder. The value to use should be set during run-time by radio driver function.) */ + ADI_HALFREG_OVERRIDE(0,4,0xF,0x8), + /* Rx: Configure AGC to use gain table for improved performance */ + HW_REG_OVERRIDE(0x6084, 0x05F8), + (uint32_t)0xFFFFFFFF, +}; + +uint32_t ble_overrides_2Mbps[] = +{ + /* Rx: Set LNA IB trim to normal trim value. (NOTE: The value 0x8 is a placeholder. The value to use should be set during run-time by radio driver function.) */ + ADI_HALFREG_OVERRIDE(0,4,0xF,0x8), + (uint32_t)0xFFFFFFFF, +}; + +uint32_t ble_overrides_coded[] = +{ + /* Rx: Set LNA IB trim to 0xF (maximum) */ + ADI_HALFREG_OVERRIDE(0,4,0xF,0xF), + /* Rx: Override AGC target gain to improve performance */ + HW_REG_OVERRIDE(0x6088, 0x0018), + (uint32_t)0xFFFFFFFF, +}; +#else static uint32_t ble_overrides[] = { 0x00364038, /* Synth: Set RTRIM (POTAILRESTRIM) to 6 */ 0x000784A3, /* Synth: Set FREF = 3.43 MHz (24 MHz / 7) */ @@ -67,6 +125,7 @@ static uint32_t ble_overrides[] = { 0x008F88B3, /* GPIO mode: https://e2e.ti.com/support/wireless_connectivity/proprietary_sub_1_ghz_simpliciti/f/156/t/488244?*/ 0xFFFFFFFF, /* End of override list */ }; +#endif /*---------------------------------------------------------------------------*/ unsigned short rf_ble_cmd_send(uint8_t *command) @@ -97,14 +156,29 @@ rf_ble_cmd_wait(uint8_t *command) unsigned short rf_ble_cmd_setup_ble_mode(void) { +#if RADIO_CONF_BLE5 + rfc_CMD_BLE5_RADIO_SETUP_t cmd; + + /* Create radio setup command */ + rf_core_init_radio_op((rfc_radioOp_t *)&cmd, sizeof(cmd), CMD_BLE5_RADIO_SETUP); + + cmd.startTrigger.bEnaCmd = 0; + cmd.defaultPhy.mainMode = 1; + cmd.defaultPhy.coding = 1; + cmd.pRegOverrideCommon = ble_overrides_common; + cmd.pRegOverride1Mbps = ble_overrides_1Mbps; + cmd.pRegOverride2Mbps = ble_overrides_2Mbps; + cmd.pRegOverrideCoded = ble_overrides_coded; +#else rfc_CMD_RADIO_SETUP_t cmd; /* Create radio setup command */ rf_core_init_radio_op((rfc_radioOp_t *)&cmd, sizeof(cmd), CMD_RADIO_SETUP); - cmd.txPower = tx_power; - cmd.pRegOverride = ble_overrides; cmd.mode = 0; + cmd.pRegOverride = ble_overrides; +#endif + cmd.txPower = tx_power; /* Send Radio setup to RF Core */ if(rf_ble_cmd_send((uint8_t *)&cmd) != RF_BLE_CMD_OK) { @@ -116,14 +190,26 @@ rf_ble_cmd_setup_ble_mode(void) } /*---------------------------------------------------------------------------*/ /* ADVERTISING functions */ +/*---------------------------------------------------------------------------*/ void rf_ble_cmd_create_adv_cmd(uint8_t *command, uint8_t channel, uint8_t *param, uint8_t *output) { +#if RADIO_CONF_BLE5 + rfc_CMD_BLE5_ADV_t *c = (rfc_CMD_BLE5_ADV_t *)command; + + memset(c, 0x00, sizeof(rfc_CMD_BLE5_ADV_t)); + + c->commandNo = CMD_BLE5_ADV; + c->rangeDelay = 0; + + c->txPower = tx_power; +#else rfc_CMD_BLE_ADV_t *c = (rfc_CMD_BLE_ADV_t *)command; memset(c, 0x00, sizeof(rfc_CMD_BLE_ADV_t)); c->commandNo = CMD_BLE_ADV; +#endif c->condition.rule = COND_NEVER; c->whitening.bOverride = 0; c->channel = channel; @@ -162,12 +248,113 @@ rf_ble_cmd_create_adv_params(uint8_t *param, dataQueue_t *rx_queue, p->endTrigger.triggerType = TRIG_NEVER; } /*---------------------------------------------------------------------------*/ +/* INITIATOR functions */ +/*---------------------------------------------------------------------------*/ +void +rf_ble_cmd_create_initiator_cmd(uint8_t *cmd, uint8_t channel, uint8_t *params, + uint8_t *output, uint32_t start_time) +{ +#if RADIO_CONF_BLE5 + rfc_CMD_BLE5_INITIATOR_t *c = (rfc_CMD_BLE5_INITIATOR_t *)cmd; + + memset(c, 0x00, sizeof(rfc_CMD_BLE5_INITIATOR_t)); + + c->commandNo = CMD_BLE5_INITIATOR; + c->condition.rule = COND_NEVER; + c->whitening.bOverride = 0; + c->channel = channel; + c->pParams = (rfc_ble5InitiatorPar_t *)params; + c->startTrigger.triggerType = TRIG_ABSTIME; + c->startTime = start_time; + c->pOutput = (rfc_ble5ScanInitOutput_t *)output; + + c->txPower = tx_power; + c->rangeDelay = 0; +#else + rfc_CMD_BLE_INITIATOR_t *c = (rfc_CMD_BLE_INITIATOR_t *)cmd; + + memset(c, 0x00, sizeof(rfc_CMD_BLE_INITIATOR_t)); + + c->commandNo = CMD_BLE_INITIATOR; + c->condition.rule = COND_NEVER; + c->whitening.bOverride = 0; + c->channel = channel; + c->pParams = (rfc_bleInitiatorPar_t *)params; + c->startTrigger.triggerType = TRIG_ABSTIME; + c->startTime = start_time; + c->pOutput = (rfc_bleInitiatorOutput_t *)output; +#endif +} +/*---------------------------------------------------------------------------*/ +void +rf_ble_cmd_create_initiator_params(uint8_t *param, dataQueue_t *rx_queue, + uint32_t initiator_time, + ble_addr_type_t own_addr_type, uint8_t *own_addr, + ble_addr_type_t peer_addr_type, uint8_t *peer_addr, + uint32_t connect_time, uint8_t *conn_req_data) +{ +#if RADIO_CONF_BLE5 + rfc_ble5InitiatorPar_t *p = (rfc_ble5InitiatorPar_t *)param; + p->backoffPar.bLastSucceeded = 0; + p->backoffPar.bLastFailed = 0; + p->maxWaitTimeForAuxCh = 0; + p->rxStartTime = 0; + p->rxListenTime = 0; +#else + rfc_bleInitiatorPar_t *p = (rfc_bleInitiatorPar_t *)param; +#endif + p->pRxQ = rx_queue; + p->rxConfig.bAutoFlushIgnored = 1; + p->rxConfig.bAutoFlushCrcErr = 0; + p->rxConfig.bAutoFlushEmpty = 1; + p->rxConfig.bIncludeLenByte = 1; + p->rxConfig.bIncludeCrc = 0; + p->rxConfig.bAppendRssi = 1; + p->rxConfig.bAppendStatus = 1; + p->rxConfig.bAppendTimestamp = 1; + + /* p->initConfig.bUseWhiteList = 0; */ + p->initConfig.bUseWhiteList = 1; + p->initConfig.bDynamicWinOffset = 0; + p->initConfig.deviceAddrType = own_addr_type; + p->initConfig.peerAddrType = peer_addr_type; + p->initConfig.bStrictLenFilter = 1; + + p->connectReqLen = 22; + p->pConnectReqData = conn_req_data; + p->pDeviceAddress = (uint16_t *)own_addr; + p->pWhiteList = (rfc_bleWhiteListEntry_t *)peer_addr; + p->connectTime = connect_time; + p->timeoutTrigger.triggerType = TRIG_REL_START; + p->timeoutTime = initiator_time; + p->endTrigger.triggerType = TRIG_NEVER; +} +/*---------------------------------------------------------------------------*/ /* CONNECTION slave functions */ /*---------------------------------------------------------------------------*/ void rf_ble_cmd_create_slave_cmd(uint8_t *cmd, uint8_t channel, uint8_t *params, uint8_t *output, uint32_t start_time) { +#if RADIO_CONF_BLE5 + rfc_CMD_BLE5_SLAVE_t *c = (rfc_CMD_BLE5_SLAVE_t *)cmd; + + memset(c, 0x00, sizeof(rfc_CMD_BLE5_SLAVE_t)); + + c->commandNo = CMD_BLE5_SLAVE; + c->condition.rule = COND_NEVER; + c->whitening.bOverride = 0; + c->channel = channel; + c->pParams = (rfc_ble5SlavePar_t *)params; + c->startTrigger.triggerType = TRIG_ABSTIME; + c->startTime = start_time; + c->pOutput = (rfc_bleMasterSlaveOutput_t *)output; + + c->phyMode.mainMode = 1; + c->phyMode.coding = 1; + c->txPower = tx_power; + c->rangeDelay = 0; +#else rfc_CMD_BLE_SLAVE_t *c = (rfc_CMD_BLE_SLAVE_t *)cmd; memset(c, 0x00, sizeof(rfc_CMD_BLE_SLAVE_t)); @@ -181,6 +368,7 @@ rf_ble_cmd_create_slave_cmd(uint8_t *cmd, uint8_t channel, uint8_t *params, c->startTrigger.pastTrig = 0; c->startTime = start_time; c->pOutput = (rfc_bleMasterSlaveOutput_t *)output; +#endif } /*---------------------------------------------------------------------------*/ void @@ -190,8 +378,13 @@ rf_ble_cmd_create_slave_params(uint8_t *params, dataQueue_t *rx_queue, uint8_t crc_init_2, uint32_t win_size, uint32_t window_widening, uint8_t first_packet) { +#if RADIO_CONF_BLE5 + rfc_ble5SlavePar_t *p = (rfc_ble5SlavePar_t *)params; + p->maxRxPktLen = 255; + p->maxLenLowRate = 0; +#else rfc_bleSlavePar_t *p = (rfc_bleSlavePar_t *)params; - +#endif p->pRxQ = rx_queue; p->pTxQ = tx_queue; p->rxConfig.bAutoFlushIgnored = 1; @@ -230,6 +423,91 @@ rf_ble_cmd_create_slave_params(uint8_t *params, dataQueue_t *rx_queue, p->endTrigger.triggerType = TRIG_NEVER; } /*---------------------------------------------------------------------------*/ +/* CONNECTION master functions */ +/*---------------------------------------------------------------------------*/ +void +rf_ble_cmd_create_master_cmd(uint8_t *cmd, uint8_t channel, uint8_t *params, + uint8_t *output, uint32_t start_time) +{ +#if RADIO_CONF_BLE5 + rfc_CMD_BLE5_MASTER_t *c = (rfc_CMD_BLE5_MASTER_t *)cmd; + + memset(c, 0x00, sizeof(rfc_CMD_BLE5_MASTER_t)); + + c->commandNo = CMD_BLE5_MASTER; + c->condition.rule = COND_NEVER; + c->whitening.bOverride = 0; + c->channel = channel; + c->pParams = (rfc_ble5MasterPar_t *)params; + c->startTrigger.triggerType = TRIG_ABSTIME; + c->startTime = start_time; + c->pOutput = (rfc_bleMasterSlaveOutput_t *)output; + + c->phyMode.mainMode = 1; + c->phyMode.coding = 1; + c->txPower = tx_power; + c->rangeDelay = 0; +#else + rfc_CMD_BLE_MASTER_t *c = (rfc_CMD_BLE_MASTER_t *)cmd; + + memset(c, 0x00, sizeof(rfc_CMD_BLE_MASTER_t)); + + c->commandNo = CMD_BLE_MASTER; + c->condition.rule = COND_NEVER; + c->whitening.bOverride = 0; + c->channel = channel; + c->pParams = (rfc_bleMasterPar_t *)params; + c->startTrigger.triggerType = TRIG_ABSTIME; + c->startTime = start_time; + c->pOutput = (rfc_bleMasterSlaveOutput_t *)output; +#endif +} +/*---------------------------------------------------------------------------*/ +void +rf_ble_cmd_create_master_params(uint8_t *params, dataQueue_t *rx_queue, + dataQueue_t *tx_queue, uint32_t access_address, + uint8_t crc_init_0, uint8_t crc_init_1, + uint8_t crc_init_2, uint8_t first_packet) +{ +#if RADIO_CONF_BLE5 + rfc_ble5MasterPar_t *p = (rfc_ble5MasterPar_t *)params; + p->maxRxPktLen = 255; + p->maxLenLowRate = 0; +#else + rfc_bleMasterPar_t *p = (rfc_bleMasterPar_t *)params; +#endif + p->pRxQ = rx_queue; + p->pTxQ = tx_queue; + p->rxConfig.bAutoFlushIgnored = 1; + p->rxConfig.bAutoFlushCrcErr = 1; + p->rxConfig.bAutoFlushEmpty = 1; + p->rxConfig.bIncludeLenByte = 1; + p->rxConfig.bIncludeCrc = 0; + p->rxConfig.bAppendRssi = 1; + p->rxConfig.bAppendStatus = 1; + p->rxConfig.bAppendTimestamp = 1; + + if(first_packet) { + /* set parameters for first packet according to TI Technical Reference Manual */ + p->seqStat.lastRxSn = 1; + p->seqStat.lastTxSn = 1; + p->seqStat.nextTxSn = 0; + p->seqStat.bFirstPkt = 1; + p->seqStat.bAutoEmpty = 0; + p->seqStat.bLlCtrlTx = 0; + p->seqStat.bLlCtrlAckRx = 0; + p->seqStat.bLlCtrlAckPending = 0; + } + + p->maxPkt = 12; + p->accessAddress = access_address; + p->crcInit0 = crc_init_0; + p->crcInit1 = crc_init_1; + p->crcInit2 = crc_init_2; + p->endTrigger.triggerType = TRIG_REL_START; + p->endTime = (uint32_t)15 * 4000; /* a connection event must end after 10 ms */ +} +/*---------------------------------------------------------------------------*/ /* DATA queue functions */ /*---------------------------------------------------------------------------*/ unsigned short diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h index d8a86f798..c4b676513 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h +++ b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h @@ -106,6 +106,45 @@ void rf_ble_cmd_create_adv_params(uint8_t *param, dataQueue_t *rx_queue, uint8_t scan_resp_data_len, uint8_t *scan_resp_data, ble_addr_type_t own_addr_type, uint8_t *own_addr); +/*---------------------------------------------------------------------------*/ +/** + * \brief Creates a BLE radio command structure that sets up + * BLE initiation event when sent to the radio core + * \param cmd A pointer to command that is created + * \param channel The BLE data channel used for the connection event + * \param param A pointer to the radio command parameters + * \param output A pointer to the radio command output + * \param start_time + * The time in rf_core_ticks when the connection event will start + */ +void rf_ble_cmd_create_initiator_cmd(uint8_t *cmd, uint8_t channel, uint8_t *params, + uint8_t *output, uint32_t start_time); + +/*---------------------------------------------------------------------------*/ +/** + * \brief Creates BLE radio command parameters that are used to set up + * BLE initiation event on the radio core + * \param param A pointer to parameter structure that is created + * \param rx_queue A pointer to the RX queue that is used + * \param initiator_window + * T + * \param own_addr_type + * Either BLE_ADDR_TYPE_PUBLIC or BLE_ADDR_TYPE_RANDOM + * \param own_addr A pointer to the device address that is used as own address + * \param peer_addr_type + * Either BLE_ADDR_TYPE_PUBLIC or BLE_ADDR_TYPE_RANDOM + * \param peer_addr A pointer to the device address that is used as peer address + * \param connect_time + The first possible start time of the first connection event + * \param conn_req_data A pointer to the connect request data + */ +void rf_ble_cmd_create_initiator_params(uint8_t *param, dataQueue_t *rx_queue, + uint32_t initiator_window, + ble_addr_type_t own_addr_type, uint8_t *own_addr, + ble_addr_type_t peer_addr_type, uint8_t *peer_addr, + uint32_t connect_time, + uint8_t *conn_req_data); + /*---------------------------------------------------------------------------*/ /** * \brief Creates a BLE radio command structure that sets up a single @@ -148,6 +187,44 @@ void rf_ble_cmd_create_slave_params(uint8_t *param, dataQueue_t *rx_queue, uint8_t crc_init_2, uint32_t win_size, uint32_t window_widening, uint8_t first_packet); +/*---------------------------------------------------------------------------*/ +/** + * \brief Creates a BLE radio command structure that sets up + * BLE connection event when sent to the radio core + * \param cmd A pointer to command that is created + * \param channel The BLE data channel used for the connection event + * \param param A pointer to the radio command parameters + * \param output A pointer to the radio command output + * \param start_time + * The time in rf_core_ticks when the connection event will start + */ +void rf_ble_cmd_create_master_cmd(uint8_t *cmd, uint8_t channel, uint8_t *params, + uint8_t *output, uint32_t start_time); + +/*---------------------------------------------------------------------------*/ +/** + * \brief Creates BLE radio command parameters that are used to set up + * BLE connection event on the radio core + * \param param A pointer to parameter structure that is created + * \param rx_queue A pointer to the RX queue that is used + * \param tx_queue A pointer to the TX queue that is used + * \param access_address + * The access address of the used BLE connection + * \param crc_init_0 + * Part of the initialization of the CRC checksum + * \param crc_init_1 + * Part of the initialization of the CRC checksum + * \param crc_init_2 + * Part of the initialization of the CRC checksum + * \param first_packet + * 1 for the first packet of the BLE connection so that the + * connection is properly initialized + */ +void rf_ble_cmd_create_master_params(uint8_t *params, dataQueue_t *rx_queue, + dataQueue_t *tx_queue, uint32_t access_address, + uint8_t crc_init_0, uint8_t crc_init_1, + uint8_t crc_init_2, uint8_t first_packet); + /*---------------------------------------------------------------------------*/ /** * \brief Adds a data buffer to a BLE transmission queue From 46eca2ee250f00f30eeaf48cf8419d37f506f2e4 Mon Sep 17 00:00:00 2001 From: Jinyan BAI Date: Tue, 11 Sep 2018 15:23:34 +0100 Subject: [PATCH 344/485] Fix some code style problems --- arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx | 6 +++ arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c | 4 +- arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h | 8 ++-- arch/cpu/cc26xx-cc13xx/lpm.c | 4 ++ arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c | 4 +- arch/cpu/cc26xx-cc13xx/ti-lib-rom.h | 38 +++++++++---------- arch/cpu/cc26xx-cc13xx/ti-lib.h | 2 +- .../srf06-cc26xx/launchpad/cc2640r2/board.h | 6 +-- 8 files changed, 41 insertions(+), 31 deletions(-) diff --git a/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx b/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx index 3d4af557c..f54a8d72d 100644 --- a/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx +++ b/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx @@ -1,6 +1,12 @@ CPU_ABS_PATH = arch/cpu/cc26xx-cc13xx TI_XXWARE = $(CONTIKI_CPU)/$(TI_XXWARE_PATH) +ifeq (,$(wildcard $(TI_XXWARE))) + $(warning $(TI_XXWARE) does not exist.) + $(warning Did you run 'git submodule update --init' ?) + $(error "") +endif + ### cc26xxware / cc26x0r2fware sources under driverlib will be added to the ### MODULES list TI_XXWARE_SRC = $(CPU_ABS_PATH)/$(TI_XXWARE_PATH)/driverlib diff --git a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c index 293fc1cce..6516c22cd 100644 --- a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c +++ b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c @@ -99,9 +99,9 @@ gpio_hal_arch_pin_cfg_get(gpio_hal_pin_t pin) cfg = 0; #ifdef ThisLibraryIsFor_CC26x0R2_HaltIfViolated - config = ti_lib_ioc_port_configure_get(pin); + config = ti_lib_ioc_port_configure_get(pin); #else - config = ti_lib_rom_ioc_port_configure_get(pin); + config = ti_lib_rom_ioc_port_configure_get(pin); #endif /* Pull */ diff --git a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h index ff13dacf7..ce757eb50 100644 --- a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h +++ b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h @@ -57,11 +57,11 @@ #define gpio_hal_arch_interrupt_disable(p) ti_lib_rom_ioc_int_disable(p) #ifdef ThisLibraryIsFor_CC26x0R2_HaltIfViolated - #define gpio_hal_arch_pin_set_input(p) ti_lib_ioc_pin_type_gpio_input(p) - #define gpio_hal_arch_pin_set_output(p) ti_lib_ioc_pin_type_gpio_output(p) +#define gpio_hal_arch_pin_set_input(p) ti_lib_ioc_pin_type_gpio_input(p) +#define gpio_hal_arch_pin_set_output(p) ti_lib_ioc_pin_type_gpio_output(p) #else - #define gpio_hal_arch_pin_set_input(p) ti_lib_rom_ioc_pin_type_gpio_input(p) - #define gpio_hal_arch_pin_set_output(p) ti_lib_rom_ioc_pin_type_gpio_output(p) +#define gpio_hal_arch_pin_set_input(p) ti_lib_rom_ioc_pin_type_gpio_input(p) +#define gpio_hal_arch_pin_set_output(p) ti_lib_rom_ioc_pin_type_gpio_output(p) #endif #define gpio_hal_arch_set_pin(p) ti_lib_gpio_set_dio(p) #define gpio_hal_arch_clear_pin(p) ti_lib_gpio_clear_dio(p) diff --git a/arch/cpu/cc26xx-cc13xx/lpm.c b/arch/cpu/cc26xx-cc13xx/lpm.c index d5da32686..4c8e0256b 100644 --- a/arch/cpu/cc26xx-cc13xx/lpm.c +++ b/arch/cpu/cc26xx-cc13xx/lpm.c @@ -193,8 +193,12 @@ wake_up(void) ti_lib_sys_ctrl_aon_sync(); /* Adjust recharge settings */ +#ifdef ThisLibraryIsFor_CC26x0R2_HaltIfViolated // May need to change to XOSC_IN_LOW_POWER_MODE ti_lib_sys_ctrl_adjust_recharge_after_power_down(XOSC_IN_HIGH_POWER_MODE); +#else + ti_lib_sys_ctrl_adjust_recharge_after_power_down(); +#endif /* * Release the request to the uLDO diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c b/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c index ccc014b54..4c3db599f 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c +++ b/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c @@ -400,8 +400,8 @@ rf_core_set_modesel() HWREG(PRCM_BASE + PRCM_O_RFCMODESEL) = PRCM_RFCMODESEL_CURR_MODE5; rv = RF_CORE_CMD_OK; } else if (chip_type == CHIP_TYPE_CC2640R2) { - HWREG(PRCM_BASE + PRCM_O_RFCMODESEL) = PRCM_RFCMODESEL_CURR_MODE1; - rv = RF_CORE_CMD_OK; + HWREG(PRCM_BASE + PRCM_O_RFCMODESEL) = PRCM_RFCMODESEL_CURR_MODE1; + rv = RF_CORE_CMD_OK; } return rv; diff --git a/arch/cpu/cc26xx-cc13xx/ti-lib-rom.h b/arch/cpu/cc26xx-cc13xx/ti-lib-rom.h index 062b5103a..e9fe50111 100644 --- a/arch/cpu/cc26xx-cc13xx/ti-lib-rom.h +++ b/arch/cpu/cc26xx-cc13xx/ti-lib-rom.h @@ -91,25 +91,25 @@ /* IOC API */ #define ti_lib_rom_ioc_port_configure_set ROM_IOCPortConfigureSet #if !defined(ThisLibraryIsFor_CC26x0R2_HaltIfViolated) - #define ti_lib_rom_ioc_port_configure_get ROM_IOCPortConfigureGet - #define ti_lib_rom_ioc_io_shutdown_set ROM_IOCIOShutdownSet - #define ti_lib_rom_ioc_io_mode_set ROM_IOCIOModeSet - #define ti_lib_rom_ioc_io_int_set ROM_IOCIOIntSet - #define ti_lib_rom_ioc_io_port_pull_set ROM_IOCIOPortPullSet - #define ti_lib_rom_ioc_io_hyst_set ROM_IOCIOHystSet - #define ti_lib_rom_ioc_io_input_set ROM_IOCIOInputSet - #define ti_lib_rom_ioc_io_slew_ctrl_set ROM_IOCIOSlewCtrlSet - #define ti_lib_rom_ioc_io_drv_strength_set ROM_IOCIODrvStrengthSet - #define ti_lib_rom_ioc_io_port_id_set ROM_IOCIOPortIdSet - #define ti_lib_rom_ioc_int_enable ROM_IOCIntEnable - #define ti_lib_rom_ioc_int_disable ROM_IOCIntDisable - #define ti_lib_rom_ioc_pin_type_gpio_input ROM_IOCPinTypeGpioInput - #define ti_lib_rom_ioc_pin_type_gpio_output ROM_IOCPinTypeGpioOutput - #define ti_lib_rom_ioc_pin_type_uart ROM_IOCPinTypeUart - #define ti_lib_rom_ioc_pin_type_ssi_master ROM_IOCPinTypeSsiMaster - #define ti_lib_rom_ioc_pin_type_ssi_slave ROM_IOCPinTypeSsiSlave - #define ti_lib_rom_ioc_pin_type_i2c ROM_IOCPinTypeI2c - #define ti_lib_rom_ioc_pin_type_aux ROM_IOCPinTypeAux +#define ti_lib_rom_ioc_port_configure_get ROM_IOCPortConfigureGet +#define ti_lib_rom_ioc_io_shutdown_set ROM_IOCIOShutdownSet +#define ti_lib_rom_ioc_io_mode_set ROM_IOCIOModeSet +#define ti_lib_rom_ioc_io_int_set ROM_IOCIOIntSet +#define ti_lib_rom_ioc_io_port_pull_set ROM_IOCIOPortPullSet +#define ti_lib_rom_ioc_io_hyst_set ROM_IOCIOHystSet +#define ti_lib_rom_ioc_io_input_set ROM_IOCIOInputSet +#define ti_lib_rom_ioc_io_slew_ctrl_set ROM_IOCIOSlewCtrlSet +#define ti_lib_rom_ioc_io_drv_strength_set ROM_IOCIODrvStrengthSet +#define ti_lib_rom_ioc_io_port_id_set ROM_IOCIOPortIdSet +#define ti_lib_rom_ioc_int_enable ROM_IOCIntEnable +#define ti_lib_rom_ioc_int_disable ROM_IOCIntDisable +#define ti_lib_rom_ioc_pin_type_gpio_input ROM_IOCPinTypeGpioInput +#define ti_lib_rom_ioc_pin_type_gpio_output ROM_IOCPinTypeGpioOutput +#define ti_lib_rom_ioc_pin_type_uart ROM_IOCPinTypeUart +#define ti_lib_rom_ioc_pin_type_ssi_master ROM_IOCPinTypeSsiMaster +#define ti_lib_rom_ioc_pin_type_ssi_slave ROM_IOCPinTypeSsiSlave +#define ti_lib_rom_ioc_pin_type_i2c ROM_IOCPinTypeI2c +#define ti_lib_rom_ioc_pin_type_aux ROM_IOCPinTypeAux #endif /* PRCM API */ diff --git a/arch/cpu/cc26xx-cc13xx/ti-lib.h b/arch/cpu/cc26xx-cc13xx/ti-lib.h index 6a8fae405..6e6d78afb 100644 --- a/arch/cpu/cc26xx-cc13xx/ti-lib.h +++ b/arch/cpu/cc26xx-cc13xx/ti-lib.h @@ -200,7 +200,7 @@ #define ti_lib_chipinfo_get_device_id_hw_rev_code(...) ChipInfo_GetDeviceIdHwRevCode(__VA_ARGS__) #define ti_lib_chipinfo_get_chip_type(...) ChipInfo_GetChipType(__VA_ARGS__) #define ti_lib_chipinfo_get_chip_family(...) ChipInfo_GetChipFamily(__VA_ARGS__) -#ifdef ThisLibraryIsFor_CC26x0R2_HaltIfViolated +#ifdef ThisLibraryIsFor_CC26x0R2_HaltIfViolated #define ti_lib_chipinfo_chip_family_is_cc26xx(...) ChipInfo_ChipFamilyIs_CC26x0(__VA_ARGS__) #define ti_lib_chipinfo_chip_family_is_cc13xx(...) ChipInfo_ChipFamilyIs_CC13x0(__VA_ARGS__) #define ti_lib_chipinfo_chip_family_is_cc26x0r2(...) ChipInfo_ChipFamilyIs_CC26x0R2(__VA_ARGS__) diff --git a/arch/platform/srf06-cc26xx/launchpad/cc2640r2/board.h b/arch/platform/srf06-cc26xx/launchpad/cc2640r2/board.h index 4d352041a..66ba6d78c 100644 --- a/arch/platform/srf06-cc26xx/launchpad/cc2640r2/board.h +++ b/arch/platform/srf06-cc26xx/launchpad/cc2640r2/board.h @@ -31,9 +31,9 @@ /** \addtogroup launchpad-peripherals * @{ * - * \defgroup launchpad-cc26xx-specific CC2650 LaunchPad Peripherals + * \defgroup launchpad-cc2640r2-specific CC2640R2 LaunchPad Peripherals * - * Defines related to the CC2650 LaunchPad + * Defines related to the CC2640R2 LaunchPad * * This file provides connectivity information on LEDs, Buttons, UART and * other peripherals @@ -43,7 +43,7 @@ * * \file * Header file with definitions related to the I/O connections on the TI - * CC2650 LaunchPad + * CC2640R2 LaunchPad * * \note Do not include this file directly. It gets included by contiki-conf * after all relevant directives have been set. From 84384d5efc4eb88b8e75c7a78a4f6dd5ca68fef4 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Tue, 11 Sep 2018 16:45:21 +0200 Subject: [PATCH 345/485] Added missing LED define in sensortag/cc1350 Board --- arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h index a6aeb1116..ecdb6d2af 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h @@ -97,6 +97,8 @@ extern "C" { #define Board_PIN_BUTTON0 CC1350STK_KEY_LEFT #define Board_PIN_BUTTON1 CC1350STK_KEY_RIGHT +#define Board_PIN_BTN1 CC1350STK_KEY_LEFT +#define Board_PIN_BTN2 CC1350STK_KEY_RIGHT #define Board_PIN_LED0 CC1350STK_PIN_LED1 #define Board_PIN_LED1 CC1350STK_PIN_LED1 #define Board_PIN_LED2 CC1350STK_PIN_LED1 From e212fd31fe9c99d4bc98d6b4d63e724e55d877ec Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Tue, 11 Sep 2018 17:39:17 +0200 Subject: [PATCH 346/485] Added missing defines for PLATFORM_HAS_* --- .../simplelink/cc13xx-cc26xx/launchpad/board-conf.h | 5 +++++ .../simplelink/cc13xx-cc26xx/sensortag/board-conf.h | 13 +++++++++++++ .../simplelink/cc13xx-cc26xx/srf06/board-conf.h | 5 +++++ 3 files changed, 23 insertions(+) diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-conf.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-conf.h index 4e8ba08d8..71d59501d 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-conf.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-conf.h @@ -58,6 +58,8 @@ * Those values are not meant to be modified by the user * @{ */ +#define PLATFORM_HAS_LEDS 1 + #define LEDS_CONF_COUNT 2 #define LEDS_CONF_RED 0 @@ -72,6 +74,9 @@ * Those values are not meant to be modified by the user * @{ */ +#define PLATFORM_HAS_BUTTON 1 +#define PLATFORM_SUPPORTS_BUTTON_HAL 1 + #define BUTTON_HAL_ID_KEY_LEFT 0 #define BUTTON_HAL_ID_KEY_RIGHT 1 /** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h index 8297edd7e..bb8689c98 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h @@ -54,12 +54,25 @@ /*---------------------------------------------------------------------------*/ #include "leds-arch.h" /*---------------------------------------------------------------------------*/ +/** + * \name LED configurations for the dev/leds.h API. The actual LED + * configuration of available LEDs are done in leds-arch.h. + * + * Those values are not meant to be modified by the user + * @{ + */ +#define PLATFORM_HAS_LEDS 1 +/** @} */ +/*---------------------------------------------------------------------------*/ /** * \name Button configurations for the dev/button-hal.h API. * * Those values are not meant to be modified by the user * @{ */ +#define PLATFORM_HAS_BUTTON 1 +#define PLATFORM_SUPPORTS_BUTTON_HAL 1 + #define BUTTON_HAL_ID_KEY_LEFT 0 #define BUTTON_HAL_ID_KEY_RIGHT 1 #define BUTTON_HAL_ID_REED_RELAY 2 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/board-conf.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/board-conf.h index a8a97ddf5..037e7eb3f 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/board-conf.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/board-conf.h @@ -48,6 +48,8 @@ * Those values are not meant to be modified by the user * @{ */ +#define PLATFORM_HAS_LEDS 1 + #define LEDS_CONF_COUNT 4 #define LEDS_CONF_RED 0 @@ -64,6 +66,9 @@ * Those values are not meant to be modified by the user * @{ */ +#define PLATFORM_HAS_BUTTON 1 +#define PLATFORM_SUPPORTS_BUTTON_HAL 1 + #define BUTTON_HAL_ID_KEY_LEFT 0 #define BUTTON_HAL_ID_KEY_RIGHT 1 #define BUTTON_HAL_ID_KEY_UP 2 From dee158431273adbdcb7a74c25073332768859cba Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Tue, 11 Sep 2018 17:50:11 +0200 Subject: [PATCH 347/485] Added missing button defines for sensortag/cc2650 Board --- arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h index a09723a73..e334645bb 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h @@ -97,6 +97,8 @@ extern "C" { #define Board_PIN_BUTTON0 CC2650STK_KEY_LEFT #define Board_PIN_BUTTON1 CC2650STK_KEY_RIGHT +#define Board_PIN_BTN1 CC2650STK_KEY_LEFT +#define Board_PIN_BTN2 CC2650STK_KEY_RIGHT #define Board_PIN_LED0 CC2650STK_PIN_LED0 #define Board_PIN_LED1 CC2650STK_PIN_LED1 #define Board_PIN_LED2 CC2650STK_PIN_LED1 From b82851568f2484e11be3a7be959f5041bce6c77d Mon Sep 17 00:00:00 2001 From: Jinyan BAI Date: Tue, 11 Sep 2018 19:17:26 +0100 Subject: [PATCH 348/485] get rid of undeclared identifier --- arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c b/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c index 4c3db599f..185842b42 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c +++ b/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c @@ -399,9 +399,11 @@ rf_core_set_modesel() } else if(chip_type == CHIP_TYPE_CC1350) { HWREG(PRCM_BASE + PRCM_O_RFCMODESEL) = PRCM_RFCMODESEL_CURR_MODE5; rv = RF_CORE_CMD_OK; +#ifdef ThisLibraryIsFor_CC26x0R2_HaltIfViolated } else if (chip_type == CHIP_TYPE_CC2640R2) { HWREG(PRCM_BASE + PRCM_O_RFCMODESEL) = PRCM_RFCMODESEL_CURR_MODE1; rv = RF_CORE_CMD_OK; +#endif } return rv; From 7acf0bff18188b350eaa3cdf74f83a45a88f677b Mon Sep 17 00:00:00 2001 From: Jinyan BAI Date: Tue, 11 Sep 2018 23:42:36 +0100 Subject: [PATCH 349/485] use non-ROM variant functions since the ROM ones are no longer supported in cc2640r2sdk --- arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h index ce757eb50..8983051ce 100644 --- a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h +++ b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h @@ -54,12 +54,13 @@ #include /*---------------------------------------------------------------------------*/ #define gpio_hal_arch_interrupt_enable(p) interrupt_enable(p) -#define gpio_hal_arch_interrupt_disable(p) ti_lib_rom_ioc_int_disable(p) #ifdef ThisLibraryIsFor_CC26x0R2_HaltIfViolated +#define gpio_hal_arch_interrupt_disable(p) ti_lib_ioc_int_disable(p) #define gpio_hal_arch_pin_set_input(p) ti_lib_ioc_pin_type_gpio_input(p) #define gpio_hal_arch_pin_set_output(p) ti_lib_ioc_pin_type_gpio_output(p) #else +#define gpio_hal_arch_interrupt_disable(p) ti_lib_rom_ioc_int_disable(p) #define gpio_hal_arch_pin_set_input(p) ti_lib_rom_ioc_pin_type_gpio_input(p) #define gpio_hal_arch_pin_set_output(p) ti_lib_rom_ioc_pin_type_gpio_output(p) #endif @@ -79,6 +80,8 @@ interrupt_enable(gpio_hal_pin_t pin) ti_lib_gpio_clear_event_dio(pin); #ifndef ThisLibraryIsFor_CC26x0R2_HaltIfViolated ti_lib_rom_ioc_int_enable(pin); +#else + ti_lib_ioc_int_enable(pin) #endif } /*---------------------------------------------------------------------------*/ From a4598b266070689960b39a3d1a2f3a3d76320f1a Mon Sep 17 00:00:00 2001 From: Jinyan BAI Date: Wed, 12 Sep 2018 00:31:39 +0100 Subject: [PATCH 350/485] add missing ';' --- arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h index 8983051ce..f08d595e9 100644 --- a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h +++ b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h @@ -81,7 +81,7 @@ interrupt_enable(gpio_hal_pin_t pin) #ifndef ThisLibraryIsFor_CC26x0R2_HaltIfViolated ti_lib_rom_ioc_int_enable(pin); #else - ti_lib_ioc_int_enable(pin) + ti_lib_ioc_int_enable(pin); #endif } /*---------------------------------------------------------------------------*/ From 113302d1bcbd38c81d62ad7bce69b49b399ab5b7 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Wed, 12 Sep 2018 09:50:19 +0200 Subject: [PATCH 351/485] Fixed wrong filename include Will only trigger an error on case-sensitive systems --- arch/cpu/simplelink-cc13xx-cc26xx/dev/trng-arch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/cpu/simplelink-cc13xx-cc26xx/dev/trng-arch.c b/arch/cpu/simplelink-cc13xx-cc26xx/dev/trng-arch.c index 5371bdcb4..d04410bff 100644 --- a/arch/cpu/simplelink-cc13xx-cc26xx/dev/trng-arch.c +++ b/arch/cpu/simplelink-cc13xx-cc26xx/dev/trng-arch.c @@ -51,7 +51,7 @@ */ #include #if (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0) -#include +#include #endif /*---------------------------------------------------------------------------*/ #include From 22718bae346291a0d06f15310b2fd1801ad493ba Mon Sep 17 00:00:00 2001 From: Jinyan BAI Date: Wed, 12 Sep 2018 22:44:33 +0100 Subject: [PATCH 352/485] Edit comments to pass doxygen test --- arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h index c4b676513..798d1b879 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h +++ b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h @@ -112,7 +112,7 @@ void rf_ble_cmd_create_adv_params(uint8_t *param, dataQueue_t *rx_queue, * BLE initiation event when sent to the radio core * \param cmd A pointer to command that is created * \param channel The BLE data channel used for the connection event - * \param param A pointer to the radio command parameters + * \param params A pointer to the radio command parameters * \param output A pointer to the radio command output * \param start_time * The time in rf_core_ticks when the connection event will start @@ -193,7 +193,7 @@ void rf_ble_cmd_create_slave_params(uint8_t *param, dataQueue_t *rx_queue, * BLE connection event when sent to the radio core * \param cmd A pointer to command that is created * \param channel The BLE data channel used for the connection event - * \param param A pointer to the radio command parameters + * \param params A pointer to the radio command parameters * \param output A pointer to the radio command output * \param start_time * The time in rf_core_ticks when the connection event will start @@ -205,7 +205,7 @@ void rf_ble_cmd_create_master_cmd(uint8_t *cmd, uint8_t channel, uint8_t *params /** * \brief Creates BLE radio command parameters that are used to set up * BLE connection event on the radio core - * \param param A pointer to parameter structure that is created + * \param params A pointer to parameter structure that is created * \param rx_queue A pointer to the RX queue that is used * \param tx_queue A pointer to the TX queue that is used * \param access_address From 163f455fc78ed89faac3b1e93773c527f4a4731c Mon Sep 17 00:00:00 2001 From: Rehan MALAK Date: Mon, 13 Aug 2018 17:46:08 +0200 Subject: [PATCH 353/485] add '\0' terminal character --- examples/rpl-border-router/webserver/httpd-simple.c | 6 ++++-- tools/serial-io/tunslip6.c | 11 +++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/examples/rpl-border-router/webserver/httpd-simple.c b/examples/rpl-border-router/webserver/httpd-simple.c index d8ce76816..7ce984e6a 100644 --- a/examples/rpl-border-router/webserver/httpd-simple.c +++ b/examples/rpl-border-router/webserver/httpd-simple.c @@ -128,7 +128,8 @@ PT_THREAD(handle_output(struct httpd_state *s)) s->script = NULL; s->script = httpd_simple_get_script(&s->filename[1]); if(s->script == NULL) { - strncpy(s->filename, "/notfound.html", sizeof(s->filename)); + strncpy(s->filename, "/notfound.html", sizeof(s->filename) - 1); + s->filename[sizeof(s->filename) - 1] = '\0'; PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_404)); PT_WAIT_THREAD(&s->outputpt, @@ -170,7 +171,8 @@ PT_THREAD(handle_input(struct httpd_state *s)) urlconv_tofilename(s->filename, s->inputbuf, sizeof(s->filename)); #else /* URLCONV */ if(s->inputbuf[1] == ISO_space) { - strncpy(s->filename, http_index_html, sizeof(s->filename)); + strncpy(s->filename, http_index_html, sizeof(s->filename) - 1); + s->filename[sizeof(s->filename) - 1] = '\0'; } else { s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0; strncpy(s->filename, s->inputbuf, sizeof(s->filename)); diff --git a/tools/serial-io/tunslip6.c b/tools/serial-io/tunslip6.c index aa8b5b9fd..548bc1cd6 100644 --- a/tools/serial-io/tunslip6.c +++ b/tools/serial-io/tunslip6.c @@ -579,8 +579,10 @@ tun_alloc(char *dev, int tap) * IFF_NO_PI - Do not provide packet information */ ifr.ifr_flags = (tap ? IFF_TAP : IFF_TUN) | IFF_NO_PI; - if(*dev != 0) - strncpy(ifr.ifr_name, dev, IFNAMSIZ); + if(*dev != 0) { + strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name) - 1); + ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0'; + } if((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) { close(fd); @@ -806,10 +808,11 @@ main(int argc, char **argv) case 't': if(strncmp("/dev/", optarg, 5) == 0) { - strncpy(tundev, optarg + 5, sizeof(tundev)); + strncpy(tundev, optarg + 5, sizeof(tundev) - 1); } else { - strncpy(tundev, optarg, sizeof(tundev)); + strncpy(tundev, optarg, sizeof(tundev) - 1); } + tundev[sizeof(tundev) - 1] = '\0'; break; case 'a': From 9a5373f267d1630f4e2661bec7bfde1c07c8f2ff Mon Sep 17 00:00:00 2001 From: Rehan MALAK Date: Thu, 16 Aug 2018 14:00:54 +0200 Subject: [PATCH 354/485] fix indentation --- tools/serial-io/tunslip6.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/serial-io/tunslip6.c b/tools/serial-io/tunslip6.c index 548bc1cd6..48b0ecd0f 100644 --- a/tools/serial-io/tunslip6.c +++ b/tools/serial-io/tunslip6.c @@ -795,9 +795,9 @@ main(int argc, char **argv) case 's': if(strncmp("/dev/", optarg, 5) == 0) { - siodev = optarg + 5; + siodev = optarg + 5; } else { - siodev = optarg; + siodev = optarg; } break; From ee9d12384266d68f2c8a9d2092867187f0bdf730 Mon Sep 17 00:00:00 2001 From: Rehan MALAK Date: Thu, 13 Sep 2018 11:12:36 +0200 Subject: [PATCH 355/485] update uncrustify configuration --- tools/code-style/uncrustify.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/code-style/uncrustify.cfg b/tools/code-style/uncrustify.cfg index 37b49a48b..7b2b353ec 100644 --- a/tools/code-style/uncrustify.cfg +++ b/tools/code-style/uncrustify.cfg @@ -35,7 +35,7 @@ sp_balance_nested_parens=false align_keep_tabs=false align_with_tabs=false align_on_tabstop=false -align_number_left=false +align_number_right=false align_func_params=false align_same_func_call_params=false align_var_def_colon=false From 8f271797827bd1c564bca8575e36f19a3f5da8e5 Mon Sep 17 00:00:00 2001 From: Atis Elsts Date: Sat, 15 Sep 2018 14:23:39 +0100 Subject: [PATCH 356/485] remove BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN and button_sensor definitions for cc26xx: dead code since changing to the button HAL --- arch/platform/srf06-cc26xx/contiki-conf.h | 10 ---------- .../platform-specific/cc26xx/ble-ipv6/project-conf.h | 3 --- 2 files changed, 13 deletions(-) diff --git a/arch/platform/srf06-cc26xx/contiki-conf.h b/arch/platform/srf06-cc26xx/contiki-conf.h index 4a1470b40..23c086db3 100644 --- a/arch/platform/srf06-cc26xx/contiki-conf.h +++ b/arch/platform/srf06-cc26xx/contiki-conf.h @@ -50,23 +50,13 @@ /** * \name Button configurations * - * Configure a button as power on/off: We use the right button for both boards. * @{ */ -#ifndef BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN -#define BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN 1 -#endif /* Notify various examples that we have Buttons */ #define PLATFORM_HAS_BUTTON 1 #define PLATFORM_SUPPORTS_BUTTON_HAL 1 -/* - * Override button symbols from dev/button-sensor.h, for the examples that - * include it - */ -#define button_sensor button_left_sensor -#define button_sensor2 button_right_sensor /** @} */ /*---------------------------------------------------------------------------*/ /* Platform-specific define to signify sensor reading failure */ diff --git a/examples/platform-specific/cc26xx/ble-ipv6/project-conf.h b/examples/platform-specific/cc26xx/ble-ipv6/project-conf.h index 815cfb90a..b311a2fa5 100644 --- a/examples/platform-specific/cc26xx/ble-ipv6/project-conf.h +++ b/examples/platform-specific/cc26xx/ble-ipv6/project-conf.h @@ -36,9 +36,6 @@ #ifndef PROJECT_CONF_H_ #define PROJECT_CONF_H_ -/*---------------------------------------------------------------------------*/ -/* Disable button shutdown functionality */ -#define BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN 0 /*---------------------------------------------------------------------------*/ /* Change to match your configuration */ #define BOARD_CONF_DEBUGGER_DEVPACK 1 From 8d12ca730f7d3fc1bcd3208b2f3d389f2cf0ead3 Mon Sep 17 00:00:00 2001 From: Atis Elsts Date: Sat, 15 Sep 2018 14:30:17 +0100 Subject: [PATCH 357/485] remove duplicate definitions of CC26xx/CC13xx flash pins --- arch/platform/srf06-cc26xx/launchpad/cc1310/board.h | 13 ++++--------- arch/platform/srf06-cc26xx/launchpad/cc1350/board.h | 13 ++++--------- .../srf06-cc26xx/launchpad/cc2640r2/board.h | 13 ++++--------- arch/platform/srf06-cc26xx/launchpad/cc2650/board.h | 13 ++++--------- arch/platform/srf06-cc26xx/sensortag/cc1350/board.h | 13 ++++--------- arch/platform/srf06-cc26xx/sensortag/cc2650/board.h | 13 ++++--------- 6 files changed, 24 insertions(+), 54 deletions(-) diff --git a/arch/platform/srf06-cc26xx/launchpad/cc1310/board.h b/arch/platform/srf06-cc26xx/launchpad/cc1310/board.h index 41e929571..f3c1dcd0f 100644 --- a/arch/platform/srf06-cc26xx/launchpad/cc1310/board.h +++ b/arch/platform/srf06-cc26xx/launchpad/cc1310/board.h @@ -111,15 +111,10 @@ */ #define EXT_FLASH_SPI_CONTROLLER SPI_CONTROLLER_SPI0 -#define BOARD_IOID_FLASH_SCK IOID_10 -#define BOARD_IOID_FLASH_MOSI IOID_9 -#define BOARD_IOID_FLASH_MISO IOID_8 -#define BOARD_IOID_FLASH_CS IOID_20 - -#define EXT_FLASH_SPI_PIN_SCK 10 -#define EXT_FLASH_SPI_PIN_MOSI 9 -#define EXT_FLASH_SPI_PIN_MISO 8 -#define EXT_FLASH_SPI_PIN_CS 20 +#define EXT_FLASH_SPI_PIN_SCK IOID_10 +#define EXT_FLASH_SPI_PIN_MOSI IOID_9 +#define EXT_FLASH_SPI_PIN_MISO IOID_8 +#define EXT_FLASH_SPI_PIN_CS IOID_20 #define EXT_FLASH_DEVICE_ID 0x14 #define EXT_FLASH_MID 0xC2 diff --git a/arch/platform/srf06-cc26xx/launchpad/cc1350/board.h b/arch/platform/srf06-cc26xx/launchpad/cc1350/board.h index 643d69e0b..b989311b4 100644 --- a/arch/platform/srf06-cc26xx/launchpad/cc1350/board.h +++ b/arch/platform/srf06-cc26xx/launchpad/cc1350/board.h @@ -111,15 +111,10 @@ */ #define EXT_FLASH_SPI_CONTROLLER SPI_CONTROLLER_SPI0 -#define BOARD_IOID_FLASH_SCK IOID_10 -#define BOARD_IOID_FLASH_MOSI IOID_9 -#define BOARD_IOID_FLASH_MISO IOID_8 -#define BOARD_IOID_FLASH_CS IOID_20 - -#define EXT_FLASH_SPI_PIN_SCK 10 -#define EXT_FLASH_SPI_PIN_MOSI 9 -#define EXT_FLASH_SPI_PIN_MISO 8 -#define EXT_FLASH_SPI_PIN_CS 20 +#define EXT_FLASH_SPI_PIN_SCK IOID_10 +#define EXT_FLASH_SPI_PIN_MOSI IOID_9 +#define EXT_FLASH_SPI_PIN_MISO IOID_8 +#define EXT_FLASH_SPI_PIN_CS IOID_20 #define EXT_FLASH_DEVICE_ID 0x14 #define EXT_FLASH_MID 0xC2 diff --git a/arch/platform/srf06-cc26xx/launchpad/cc2640r2/board.h b/arch/platform/srf06-cc26xx/launchpad/cc2640r2/board.h index 66ba6d78c..df5866eee 100644 --- a/arch/platform/srf06-cc26xx/launchpad/cc2640r2/board.h +++ b/arch/platform/srf06-cc26xx/launchpad/cc2640r2/board.h @@ -111,15 +111,10 @@ */ #define EXT_FLASH_SPI_CONTROLLER SPI_CONTROLLER_SPI0 -#define BOARD_IOID_FLASH_SCK IOID_10 -#define BOARD_IOID_FLASH_MOSI IOID_9 -#define BOARD_IOID_FLASH_MISO IOID_8 -#define BOARD_IOID_FLASH_CS IOID_20 - -#define EXT_FLASH_SPI_PIN_SCK 10 -#define EXT_FLASH_SPI_PIN_MOSI 9 -#define EXT_FLASH_SPI_PIN_MISO 8 -#define EXT_FLASH_SPI_PIN_CS 20 +#define EXT_FLASH_SPI_PIN_SCK IOID_10 +#define EXT_FLASH_SPI_PIN_MOSI IOID_9 +#define EXT_FLASH_SPI_PIN_MISO IOID_8 +#define EXT_FLASH_SPI_PIN_CS IOID_20 #define EXT_FLASH_DEVICE_ID 0x14 #define EXT_FLASH_MID 0xC2 diff --git a/arch/platform/srf06-cc26xx/launchpad/cc2650/board.h b/arch/platform/srf06-cc26xx/launchpad/cc2650/board.h index 822e776b8..047d4f920 100644 --- a/arch/platform/srf06-cc26xx/launchpad/cc2650/board.h +++ b/arch/platform/srf06-cc26xx/launchpad/cc2650/board.h @@ -111,15 +111,10 @@ */ #define EXT_FLASH_SPI_CONTROLLER SPI_CONTROLLER_SPI0 -#define BOARD_IOID_FLASH_SCK IOID_10 -#define BOARD_IOID_FLASH_MOSI IOID_9 -#define BOARD_IOID_FLASH_MISO IOID_8 -#define BOARD_IOID_FLASH_CS IOID_20 - -#define EXT_FLASH_SPI_PIN_SCK 10 -#define EXT_FLASH_SPI_PIN_MOSI 9 -#define EXT_FLASH_SPI_PIN_MISO 8 -#define EXT_FLASH_SPI_PIN_CS 20 +#define EXT_FLASH_SPI_PIN_SCK IOID_10 +#define EXT_FLASH_SPI_PIN_MOSI IOID_9 +#define EXT_FLASH_SPI_PIN_MISO IOID_8 +#define EXT_FLASH_SPI_PIN_CS IOID_20 #define EXT_FLASH_DEVICE_ID 0x14 #define EXT_FLASH_MID 0xC2 diff --git a/arch/platform/srf06-cc26xx/sensortag/cc1350/board.h b/arch/platform/srf06-cc26xx/sensortag/cc1350/board.h index 6fdab1295..c9999c219 100644 --- a/arch/platform/srf06-cc26xx/sensortag/cc1350/board.h +++ b/arch/platform/srf06-cc26xx/sensortag/cc1350/board.h @@ -137,15 +137,10 @@ */ #define EXT_FLASH_SPI_CONTROLLER SPI_CONTROLLER_SPI0 -#define BOARD_IOID_FLASH_SCK IOID_17 -#define BOARD_IOID_FLASH_MOSI IOID_19 -#define BOARD_IOID_FLASH_MISO IOID_18 -#define BOARD_IOID_FLASH_CS IOID_14 - -#define EXT_FLASH_SPI_PIN_SCK 17 -#define EXT_FLASH_SPI_PIN_MOSI 19 -#define EXT_FLASH_SPI_PIN_MISO 18 -#define EXT_FLASH_SPI_PIN_CS 14 +#define EXT_FLASH_SPI_PIN_SCK IOID_17 +#define EXT_FLASH_SPI_PIN_MOSI IOID_19 +#define EXT_FLASH_SPI_PIN_MISO IOID_18 +#define EXT_FLASH_SPI_PIN_CS IOID_14 #define EXT_FLASH_DEVICE_ID 0x14 #define EXT_FLASH_MID 0xC2 diff --git a/arch/platform/srf06-cc26xx/sensortag/cc2650/board.h b/arch/platform/srf06-cc26xx/sensortag/cc2650/board.h index dda3e46e5..4784815a4 100644 --- a/arch/platform/srf06-cc26xx/sensortag/cc2650/board.h +++ b/arch/platform/srf06-cc26xx/sensortag/cc2650/board.h @@ -139,15 +139,10 @@ */ #define EXT_FLASH_SPI_CONTROLLER SPI_CONTROLLER_SPI0 -#define BOARD_IOID_FLASH_SCK IOID_17 -#define BOARD_IOID_FLASH_MOSI IOID_19 -#define BOARD_IOID_FLASH_MISO IOID_18 -#define BOARD_IOID_FLASH_CS IOID_14 - -#define EXT_FLASH_SPI_PIN_SCK 17 -#define EXT_FLASH_SPI_PIN_MOSI 19 -#define EXT_FLASH_SPI_PIN_MISO 18 -#define EXT_FLASH_SPI_PIN_CS 14 +#define EXT_FLASH_SPI_PIN_SCK IOID_17 +#define EXT_FLASH_SPI_PIN_MOSI IOID_19 +#define EXT_FLASH_SPI_PIN_MISO IOID_18 +#define EXT_FLASH_SPI_PIN_CS IOID_14 #if SENSORTAG_CC2650_REV_1_2_0 #define EXT_FLASH_DEVICE_ID 0x12 From f63012137d8d7ecaf71fd924088a809e8f8940dd Mon Sep 17 00:00:00 2001 From: Atis Elsts Date: Sat, 15 Sep 2018 14:37:17 +0100 Subject: [PATCH 358/485] CC26xx/CC13xx GPIO interrupt hal: clear the interrupt flags before calling the callbacks, not after --- arch/cpu/cc26xx-cc13xx/dev/gpio-interrupt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/cpu/cc26xx-cc13xx/dev/gpio-interrupt.c b/arch/cpu/cc26xx-cc13xx/dev/gpio-interrupt.c index c90e9239d..375e23a4a 100644 --- a/arch/cpu/cc26xx-cc13xx/dev/gpio-interrupt.c +++ b/arch/cpu/cc26xx-cc13xx/dev/gpio-interrupt.c @@ -52,10 +52,10 @@ gpio_interrupt_isr(void) /* Read interrupt flags */ pin_mask = (HWREG(GPIO_BASE + GPIO_O_EVFLAGS31_0) & GPIO_DIO_ALL_MASK); - gpio_hal_event_handler(pin_mask); - /* Clear the interrupt flags */ HWREG(GPIO_BASE + GPIO_O_EVFLAGS31_0) = pin_mask; + + gpio_hal_event_handler(pin_mask); } /*---------------------------------------------------------------------------*/ /** @} */ From 06bbb65bdb6eddca3bbed20c28836b1137658ad3 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Thu, 16 Aug 2018 22:01:48 +0100 Subject: [PATCH 359/485] Simplify configuration of the CC13xx/CC26xx ROM bootloader Currently board.h does all the work, but it does not really need to. This commit moves most of the ccfg defines to ccxxware-conf.h and now board.h only needs to specify the bootloader enable pin and corresponding level. --- arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h | 10 +++++++-- arch/cpu/cc26xx-cc13xx/ccxxware-conf.h | 20 ++++++++++++++++++ .../srf06-cc26xx/launchpad/cc1310/board.h | 21 ++++++------------- .../srf06-cc26xx/launchpad/cc1350/board.h | 21 ++++++------------- .../srf06-cc26xx/launchpad/cc2640r2/board.h | 21 ++++++------------- .../srf06-cc26xx/launchpad/cc2650/board.h | 21 ++++++------------- .../srf06-cc26xx/sensortag/cc1350/board.h | 10 +++++++++ .../srf06-cc26xx/sensortag/cc2650/board.h | 10 +++++++++ .../srf06-cc26xx/srf06/cc13xx/board.h | 21 ++++++------------- .../srf06-cc26xx/srf06/cc26xx/board.h | 21 ++++++------------- .../cc26xx/cc26xx-web-demo/project-conf.h | 2 +- .../platform-specific/cc26xx/project-conf.h | 2 +- .../cc26xx/very-sleepy-demo/project-conf.h | 3 +-- examples/sensniff/srf06-cc26xx/target-conf.h | 6 +++--- 14 files changed, 90 insertions(+), 99 deletions(-) diff --git a/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h b/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h index 6ff047ebe..e7d9dacd7 100644 --- a/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h +++ b/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h @@ -199,8 +199,14 @@ * the chip to enter bootloader mode. * @{ */ -#ifndef ROM_BOOTLOADER_ENABLE -#define ROM_BOOTLOADER_ENABLE 1 + +/* Backward compatibility */ +#ifdef ROM_BOOTLOADER_ENABLE +#define CCXXWARE_CONF_ROM_BOOTLOADER_ENABLE ROM_BOOTLOADER_ENABLE +#endif + +#ifndef CCXXWARE_CONF_ROM_BOOTLOADER_ENABLE +#define CCXXWARE_CONF_ROM_BOOTLOADER_ENABLE 1 #endif /** @} */ /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc26xx-cc13xx/ccxxware-conf.h b/arch/cpu/cc26xx-cc13xx/ccxxware-conf.h index 97be16b5d..bc26f1171 100644 --- a/arch/cpu/cc26xx-cc13xx/ccxxware-conf.h +++ b/arch/cpu/cc26xx-cc13xx/ccxxware-conf.h @@ -68,6 +68,26 @@ #define SET_CCFG_CCFG_TAP_DAP_1_WUC_TAP_ENABLE 0x00 #endif /** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \brief ROM bootloader configuration + * + * Those values are not meant to be modified by the user + * @{ + */ +#if CCXXWARE_CONF_ROM_BOOTLOADER_ENABLE +#define SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE 0xC5 +#define SET_CCFG_BL_CONFIG_BL_LEVEL CCXXWARE_CONF_BL_LEVEL +#define SET_CCFG_BL_CONFIG_BL_PIN_NUMBER CCXXWARE_CONF_BL_PIN_NUMBER +#define SET_CCFG_BL_CONFIG_BL_ENABLE 0xC5 +#else +#define SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE 0x00 +#define SET_CCFG_BL_CONFIG_BL_LEVEL 0x01 +#define SET_CCFG_BL_CONFIG_BL_PIN_NUMBER IOID_UNUSED +#define SET_CCFG_BL_CONFIG_BL_ENABLE 0xFF +#endif +/** @} */ +/*---------------------------------------------------------------------------*/ #endif /* CCXXWARE_CONF_H_ */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/srf06-cc26xx/launchpad/cc1310/board.h b/arch/platform/srf06-cc26xx/launchpad/cc1310/board.h index 41e929571..71253b063 100644 --- a/arch/platform/srf06-cc26xx/launchpad/cc1310/board.h +++ b/arch/platform/srf06-cc26xx/launchpad/cc1310/board.h @@ -141,23 +141,14 @@ /** * \brief ROM bootloader configuration * - * Change SET_CCFG_BL_CONFIG_BL_PIN_NUMBER to BOARD_IOID_KEY_xyz to select - * which button triggers the bootloader on reset. - * - * The remaining values are not meant to be modified by the user + * Change CCXXWARE_CONF_BL_PIN_NUMBER to BOARD_IOID_KEY_xyz to select which + * button triggers the bootloader on reset. Use CCXXWARE_CONF_BL_LEVEL to + * control the pin level that enables the bootloader (0: low, 1: high). It is + * also possible to use any other externally-controlled DIO. * @{ */ -#if ROM_BOOTLOADER_ENABLE -#define SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE 0xC5 -#define SET_CCFG_BL_CONFIG_BL_LEVEL 0x00 -#define SET_CCFG_BL_CONFIG_BL_PIN_NUMBER BOARD_IOID_KEY_LEFT -#define SET_CCFG_BL_CONFIG_BL_ENABLE 0xC5 -#else -#define SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE 0x00 -#define SET_CCFG_BL_CONFIG_BL_LEVEL 0x01 -#define SET_CCFG_BL_CONFIG_BL_PIN_NUMBER 0xFF -#define SET_CCFG_BL_CONFIG_BL_ENABLE 0xFF -#endif +#define CCXXWARE_CONF_BL_PIN_NUMBER BOARD_IOID_KEY_LEFT +#define CCXXWARE_CONF_BL_LEVEL 0 /** @} */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/srf06-cc26xx/launchpad/cc1350/board.h b/arch/platform/srf06-cc26xx/launchpad/cc1350/board.h index 643d69e0b..bef7ef78e 100644 --- a/arch/platform/srf06-cc26xx/launchpad/cc1350/board.h +++ b/arch/platform/srf06-cc26xx/launchpad/cc1350/board.h @@ -158,23 +158,14 @@ /** * \brief ROM bootloader configuration * - * Change SET_CCFG_BL_CONFIG_BL_PIN_NUMBER to BOARD_IOID_KEY_xyz to select - * which button triggers the bootloader on reset. - * - * The remaining values are not meant to be modified by the user + * Change CCXXWARE_CONF_BL_PIN_NUMBER to BOARD_IOID_KEY_xyz to select which + * button triggers the bootloader on reset. Use CCXXWARE_CONF_BL_LEVEL to + * control the pin level that enables the bootloader (0: low, 1: high). It is + * also possible to use any other externally-controlled DIO. * @{ */ -#if ROM_BOOTLOADER_ENABLE -#define SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE 0xC5 -#define SET_CCFG_BL_CONFIG_BL_LEVEL 0x00 -#define SET_CCFG_BL_CONFIG_BL_PIN_NUMBER BOARD_IOID_KEY_LEFT -#define SET_CCFG_BL_CONFIG_BL_ENABLE 0xC5 -#else -#define SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE 0x00 -#define SET_CCFG_BL_CONFIG_BL_LEVEL 0x01 -#define SET_CCFG_BL_CONFIG_BL_PIN_NUMBER 0xFF -#define SET_CCFG_BL_CONFIG_BL_ENABLE 0xFF -#endif +#define CCXXWARE_CONF_BL_PIN_NUMBER BOARD_IOID_KEY_LEFT +#define CCXXWARE_CONF_BL_LEVEL 0 /** @} */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/srf06-cc26xx/launchpad/cc2640r2/board.h b/arch/platform/srf06-cc26xx/launchpad/cc2640r2/board.h index 66ba6d78c..6d0edbe7c 100644 --- a/arch/platform/srf06-cc26xx/launchpad/cc2640r2/board.h +++ b/arch/platform/srf06-cc26xx/launchpad/cc2640r2/board.h @@ -141,23 +141,14 @@ /** * \brief ROM bootloader configuration * - * Change SET_CCFG_BL_CONFIG_BL_PIN_NUMBER to BOARD_IOID_KEY_xyz to select - * which button triggers the bootloader on reset. - * - * The remaining values are not meant to be modified by the user + * Change CCXXWARE_CONF_BL_PIN_NUMBER to BOARD_IOID_KEY_xyz to select which + * button triggers the bootloader on reset. Use CCXXWARE_CONF_BL_LEVEL to + * control the pin level that enables the bootloader (0: low, 1: high). It is + * also possible to use any other externally-controlled DIO. * @{ */ -#if ROM_BOOTLOADER_ENABLE -#define SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE 0xC5 -#define SET_CCFG_BL_CONFIG_BL_LEVEL 0x00 -#define SET_CCFG_BL_CONFIG_BL_PIN_NUMBER BOARD_IOID_KEY_LEFT -#define SET_CCFG_BL_CONFIG_BL_ENABLE 0xC5 -#else -#define SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE 0x00 -#define SET_CCFG_BL_CONFIG_BL_LEVEL 0x01 -#define SET_CCFG_BL_CONFIG_BL_PIN_NUMBER 0xFF -#define SET_CCFG_BL_CONFIG_BL_ENABLE 0xFF -#endif +#define CCXXWARE_CONF_BL_PIN_NUMBER BOARD_IOID_KEY_LEFT +#define CCXXWARE_CONF_BL_LEVEL 0 /** @} */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/srf06-cc26xx/launchpad/cc2650/board.h b/arch/platform/srf06-cc26xx/launchpad/cc2650/board.h index 822e776b8..cee29a06e 100644 --- a/arch/platform/srf06-cc26xx/launchpad/cc2650/board.h +++ b/arch/platform/srf06-cc26xx/launchpad/cc2650/board.h @@ -141,23 +141,14 @@ /** * \brief ROM bootloader configuration * - * Change SET_CCFG_BL_CONFIG_BL_PIN_NUMBER to BOARD_IOID_KEY_xyz to select - * which button triggers the bootloader on reset. - * - * The remaining values are not meant to be modified by the user + * Change CCXXWARE_CONF_BL_PIN_NUMBER to BOARD_IOID_KEY_xyz to select which + * button triggers the bootloader on reset. Use CCXXWARE_CONF_BL_LEVEL to + * control the pin level that enables the bootloader (0: low, 1: high). It is + * also possible to use any other externally-controlled DIO. * @{ */ -#if ROM_BOOTLOADER_ENABLE -#define SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE 0xC5 -#define SET_CCFG_BL_CONFIG_BL_LEVEL 0x00 -#define SET_CCFG_BL_CONFIG_BL_PIN_NUMBER BOARD_IOID_KEY_LEFT -#define SET_CCFG_BL_CONFIG_BL_ENABLE 0xC5 -#else -#define SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE 0x00 -#define SET_CCFG_BL_CONFIG_BL_LEVEL 0x01 -#define SET_CCFG_BL_CONFIG_BL_PIN_NUMBER 0xFF -#define SET_CCFG_BL_CONFIG_BL_ENABLE 0xFF -#endif +#define CCXXWARE_CONF_BL_PIN_NUMBER BOARD_IOID_KEY_LEFT +#define CCXXWARE_CONF_BL_LEVEL 0 /** @} */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/srf06-cc26xx/sensortag/cc1350/board.h b/arch/platform/srf06-cc26xx/sensortag/cc1350/board.h index 6fdab1295..fca3246ce 100644 --- a/arch/platform/srf06-cc26xx/sensortag/cc1350/board.h +++ b/arch/platform/srf06-cc26xx/sensortag/cc1350/board.h @@ -253,6 +253,16 @@ #define BOARD_BUTTON_HAL_INDEX_REED_RELAY 0xFF /** @} */ /*---------------------------------------------------------------------------*/ +/** + * \brief ROM bootloader configuration + * + * Sensortags do not support the bootloader + * @{ + */ +#define CCXXWARE_CONF_BL_PIN_NUMBER IOID_UNUSED +#define CCXXWARE_CONF_BL_LEVEL 0 +/** @} */ +/*---------------------------------------------------------------------------*/ /** * \name Device string used on startup * @{ diff --git a/arch/platform/srf06-cc26xx/sensortag/cc2650/board.h b/arch/platform/srf06-cc26xx/sensortag/cc2650/board.h index dda3e46e5..706665757 100644 --- a/arch/platform/srf06-cc26xx/sensortag/cc2650/board.h +++ b/arch/platform/srf06-cc26xx/sensortag/cc2650/board.h @@ -234,6 +234,16 @@ #define BOARD_BUTTON_HAL_INDEX_REED_RELAY 0xFF /** @} */ /*---------------------------------------------------------------------------*/ +/** + * \brief ROM bootloader configuration + * + * Sensortags do not support the bootloader + * @{ + */ +#define CCXXWARE_CONF_BL_PIN_NUMBER IOID_UNUSED +#define CCXXWARE_CONF_BL_LEVEL 0 +/** @} */ +/*---------------------------------------------------------------------------*/ /** * \name Device string used on startup * @{ diff --git a/arch/platform/srf06-cc26xx/srf06/cc13xx/board.h b/arch/platform/srf06-cc26xx/srf06/cc13xx/board.h index 9fece9180..4c0fcf686 100644 --- a/arch/platform/srf06-cc26xx/srf06/cc13xx/board.h +++ b/arch/platform/srf06-cc26xx/srf06/cc13xx/board.h @@ -213,23 +213,14 @@ /** * \brief ROM bootloader configuration * - * Change SET_CCFG_BL_CONFIG_BL_PIN_NUMBER to BOARD_IOID_KEY_xyz to select - * which button triggers the bootloader on reset. - * - * The remaining values are not meant to be modified by the user + * Change CCXXWARE_CONF_BL_PIN_NUMBER to BOARD_IOID_KEY_xyz to select which + * button triggers the bootloader on reset. Use CCXXWARE_CONF_BL_LEVEL to + * control the pin level that enables the bootloader (0: low, 1: high). It is + * also possible to use any other externally-controlled DIO. * @{ */ -#if ROM_BOOTLOADER_ENABLE -#define SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE 0xC5 -#define SET_CCFG_BL_CONFIG_BL_LEVEL 0x00 -#define SET_CCFG_BL_CONFIG_BL_PIN_NUMBER BOARD_IOID_KEY_SELECT -#define SET_CCFG_BL_CONFIG_BL_ENABLE 0xC5 -#else -#define SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE 0x00 -#define SET_CCFG_BL_CONFIG_BL_LEVEL 0x01 -#define SET_CCFG_BL_CONFIG_BL_PIN_NUMBER 0xFF -#define SET_CCFG_BL_CONFIG_BL_ENABLE 0xFF -#endif +#define CCXXWARE_CONF_BL_PIN_NUMBER BOARD_IOID_KEY_SELECT +#define CCXXWARE_CONF_BL_LEVEL 0 /** @} */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/srf06-cc26xx/srf06/cc26xx/board.h b/arch/platform/srf06-cc26xx/srf06/cc26xx/board.h index b9171388a..f31a94fb3 100644 --- a/arch/platform/srf06-cc26xx/srf06/cc26xx/board.h +++ b/arch/platform/srf06-cc26xx/srf06/cc26xx/board.h @@ -213,23 +213,14 @@ /** * \brief ROM bootloader configuration * - * Change SET_CCFG_BL_CONFIG_BL_PIN_NUMBER to BOARD_IOID_KEY_xyz to select - * which button triggers the bootloader on reset. - * - * The remaining values are not meant to be modified by the user + * Change CCXXWARE_CONF_BL_PIN_NUMBER to BOARD_IOID_KEY_xyz to select which + * button triggers the bootloader on reset. Use CCXXWARE_CONF_BL_LEVEL to + * control the pin level that enables the bootloader (0: low, 1: high). It is + * also possible to use any other externally-controlled DIO. * @{ */ -#if ROM_BOOTLOADER_ENABLE -#define SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE 0xC5 -#define SET_CCFG_BL_CONFIG_BL_LEVEL 0x00 -#define SET_CCFG_BL_CONFIG_BL_PIN_NUMBER BOARD_IOID_KEY_SELECT -#define SET_CCFG_BL_CONFIG_BL_ENABLE 0xC5 -#else -#define SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE 0x00 -#define SET_CCFG_BL_CONFIG_BL_LEVEL 0x01 -#define SET_CCFG_BL_CONFIG_BL_PIN_NUMBER 0xFF -#define SET_CCFG_BL_CONFIG_BL_ENABLE 0xFF -#endif +#define CCXXWARE_CONF_BL_PIN_NUMBER BOARD_IOID_KEY_SELECT +#define CCXXWARE_CONF_BL_LEVEL 0 /** @} */ /*---------------------------------------------------------------------------*/ /** 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 36114eeb7..ee40e1749 100644 --- a/examples/platform-specific/cc26xx/cc26xx-web-demo/project-conf.h +++ b/examples/platform-specific/cc26xx/cc26xx-web-demo/project-conf.h @@ -64,7 +64,7 @@ #define SENSORTAG_CC2650_REV_1_2_0 0 /*---------------------------------------------------------------------------*/ /* Enable the ROM bootloader */ -#define ROM_BOOTLOADER_ENABLE 1 +#define CCXXWARE_CONF_ROM_BOOTLOADER_ENABLE 1 /*---------------------------------------------------------------------------*/ /* * Shrink the size of the uIP buffer, routing table and ND cache. diff --git a/examples/platform-specific/cc26xx/project-conf.h b/examples/platform-specific/cc26xx/project-conf.h index 17bd2ce29..3cbc0da86 100644 --- a/examples/platform-specific/cc26xx/project-conf.h +++ b/examples/platform-specific/cc26xx/project-conf.h @@ -32,7 +32,7 @@ #define PROJECT_CONF_H_ /*---------------------------------------------------------------------------*/ /* Enable the ROM bootloader */ -#define ROM_BOOTLOADER_ENABLE 1 +#define CCXXWARE_CONF_ROM_BOOTLOADER_ENABLE 1 /*---------------------------------------------------------------------------*/ /* Change to match your configuration */ #define IEEE802154_CONF_PANID 0xABCD 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 f22fb2685..0f8467a68 100644 --- a/examples/platform-specific/cc26xx/very-sleepy-demo/project-conf.h +++ b/examples/platform-specific/cc26xx/very-sleepy-demo/project-conf.h @@ -35,9 +35,8 @@ #define IEEE802154_CONF_PANID 0xABCD #define IEEE802154_CONF_DEFAULT_CHANNEL 25 /*---------------------------------------------------------------------------*/ - /* Enable the ROM bootloader */ -#define ROM_BOOTLOADER_ENABLE 1 +#define CCXXWARE_CONF_ROM_BOOTLOADER_ENABLE 1 /*---------------------------------------------------------------------------*/ /* For very sleepy operation */ #define RF_BLE_CONF_ENABLED 0 diff --git a/examples/sensniff/srf06-cc26xx/target-conf.h b/examples/sensniff/srf06-cc26xx/target-conf.h index 4d9deffda..b86df35c5 100644 --- a/examples/sensniff/srf06-cc26xx/target-conf.h +++ b/examples/sensniff/srf06-cc26xx/target-conf.h @@ -32,9 +32,9 @@ #ifndef TARGET_CONF_H_ #define TARGET_CONF_H_ /*---------------------------------------------------------------------------*/ -#define CC26XX_UART_CONF_BAUD_RATE 460800 -#define RF_BLE_CONF_ENABLED 0 -#define ROM_BOOTLOADER_ENABLE 1 +#define CC26XX_UART_CONF_BAUD_RATE 460800 +#define RF_BLE_CONF_ENABLED 0 +#define CCXXWARE_CONF_ROM_BOOTLOADER_ENABLE 1 /*---------------------------------------------------------------------------*/ #define SENSNIFF_IO_DRIVER_H "pool/cc13xx-cc26xx-io.h" /*---------------------------------------------------------------------------*/ From cb55197f90c7d44853a0cd5e811a9301e1acfe12 Mon Sep 17 00:00:00 2001 From: Atis Elsts Date: Sat, 15 Sep 2018 14:16:27 +0100 Subject: [PATCH 360/485] CC26xx/CC13xx: update the TSCH_CONF_ASSOCIATION_POLL_FREQUENCY parameter to make it associate faster --- arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-def.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-def.h b/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-def.h index 15db03448..525357253 100644 --- a/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-def.h +++ b/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-def.h @@ -85,6 +85,11 @@ #define TSCH_CONF_CHANNEL_SCAN_DURATION (CLOCK_SECOND / 10) #endif +/* Increase this from the default 100 to improve TSCH association speed on this platform */ +#ifndef TSCH_CONF_ASSOCIATION_POLL_FREQUENCY +#define TSCH_CONF_ASSOCIATION_POLL_FREQUENCY 1000 +#endif + /* Slightly reduce the TSCH guard time (from 2200 usec to 1800 usec) to make sure * the CC26xx radio has sufficient time to start up. */ #ifndef TSCH_CONF_RX_WAIT From 53e4892c1dd41c0a6b4c96ecaf9b691c18dbbc96 Mon Sep 17 00:00:00 2001 From: Rehan MALAK Date: Thu, 20 Sep 2018 11:38:29 +0200 Subject: [PATCH 361/485] exclude some platforms from benchmarks --- examples/benchmarks/rpl-req-resp/Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/benchmarks/rpl-req-resp/Makefile b/examples/benchmarks/rpl-req-resp/Makefile index 4be6d431b..11413ecd3 100644 --- a/examples/benchmarks/rpl-req-resp/Makefile +++ b/examples/benchmarks/rpl-req-resp/Makefile @@ -1,6 +1,9 @@ CONTIKI_PROJECT = node all: $(CONTIKI_PROJECT) +PLATFORMS_EXCLUDE = sky nrf52dk native simplelink +BOARDS_EXCLUDE = srf06/cc13xx launchpad/cc1310 launchpad/cc1350 sensortag/cc2650 sensortag/cc1350 + MODULES_REL += ../testbeds MODULES += os/services/deployment MODULES += os/services/simple-energest From 665dfa175e217b34de1baa9b63c6c62049bad924 Mon Sep 17 00:00:00 2001 From: Rehan MALAK Date: Thu, 20 Sep 2018 15:44:47 +0200 Subject: [PATCH 362/485] remove bug in simplelink boards name make -C tests/compile-all was emitting lots of ../../arch/platform/simplelink/Makefile.simplelink:28: *** Board 'launchpad/cc2650sensortag/cc1350' does not corresponding to any SimpleLink family. Make sure your BOARD variable is correct.. Stop. --- tests/compile-all/build.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/compile-all/build.sh b/tests/compile-all/build.sh index 13ccd9a15..fcbbd7bd7 100755 --- a/tests/compile-all/build.sh +++ b/tests/compile-all/build.sh @@ -104,9 +104,9 @@ do elif [[ "$platform" == "simplelink" ]] then # SimpleLink has multiple boards - BOARDS="launchpad/cc1310 launchpad/cc1350 launchpad/cc1350-4 launchpad/cc2650" - BOARDS+="sensortag/cc1350 sensortag/cc2650 srf06/cc13x0 srf06/cc26x0" - BOARDS+="launchpad/cc1312r1 launchpad/cc1352r1 launchpad/cc1352p1 launchpad/cc1352p-2 launchpad/cc1352p-4 launchpad/cc26x2r1" + BOARDS="launchpad/cc1310 launchpad/cc1350 launchpad/cc1350-4 launchpad/cc2650 \ + sensortag/cc1350 sensortag/cc2650 srf06/cc13x0 srf06/cc26x0 \ + launchpad/cc1312r1 launchpad/cc1352r1 launchpad/cc1352p1 launchpad/cc1352p-2 launchpad/cc1352p-4 launchpad/cc26x2r1" elif [[ "$platform" == "zoul" ]] then # Zoul has multiple boards From cc7c2312eca04f570ba87fdf44e3d93328bc6018 Mon Sep 17 00:00:00 2001 From: Rehan MALAK Date: Fri, 21 Sep 2018 09:40:26 +0200 Subject: [PATCH 363/485] missing header inttypes.h --- examples/multicast/root.c | 1 + os/net/ipv6/uip-nd6.c | 1 + os/services/lwm2m/lwm2m-tlv.c | 1 + 3 files changed, 3 insertions(+) diff --git a/examples/multicast/root.c b/examples/multicast/root.c index f997e9613..59d5d2aa8 100644 --- a/examples/multicast/root.c +++ b/examples/multicast/root.c @@ -45,6 +45,7 @@ #include "net/ipv6/multicast/uip-mcast6.h" #include +#include #define DEBUG DEBUG_PRINT #include "net/ipv6/uip-debug.h" diff --git a/os/net/ipv6/uip-nd6.c b/os/net/ipv6/uip-nd6.c index 2765c593d..63ae46b47 100644 --- a/os/net/ipv6/uip-nd6.c +++ b/os/net/ipv6/uip-nd6.c @@ -69,6 +69,7 @@ */ #include +#include #include "net/ipv6/uip-icmp6.h" #include "net/ipv6/uip-nd6.h" #include "net/ipv6/uip-ds6.h" diff --git a/os/services/lwm2m/lwm2m-tlv.c b/os/services/lwm2m/lwm2m-tlv.c index 2bda7f8bb..cdadee9f6 100644 --- a/os/services/lwm2m/lwm2m-tlv.c +++ b/os/services/lwm2m/lwm2m-tlv.c @@ -44,6 +44,7 @@ #include #include +#include #include "lwm2m-tlv.h" /* Log configuration */ From 75d372cde422211047223fb9af83170f810fb563 Mon Sep 17 00:00:00 2001 From: Rehan MALAK Date: Fri, 21 Sep 2018 11:33:14 +0200 Subject: [PATCH 364/485] minor refactoring of hdc-1000-sensor following commit f4a8cba37 --- arch/platform/srf06-cc26xx/sensortag/hdc-1000-sensor.c | 6 +++--- arch/platform/srf06-cc26xx/sensortag/hdc-1000-sensor.h | 4 ++-- examples/lwm2m-ipso-objects/example-ipso-objects.c | 2 +- examples/platform-specific/cc26xx/cc26xx-demo.c | 2 +- .../cc26xx/cc26xx-web-demo/cc26xx-web-demo.c | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/platform/srf06-cc26xx/sensortag/hdc-1000-sensor.c b/arch/platform/srf06-cc26xx/sensortag/hdc-1000-sensor.c index acc5f19be..15ee8d434 100644 --- a/arch/platform/srf06-cc26xx/sensortag/hdc-1000-sensor.c +++ b/arch/platform/srf06-cc26xx/sensortag/hdc-1000-sensor.c @@ -205,7 +205,7 @@ notify_ready(void *not_used) /*---------------------------------------------------------------------------*/ /** * \brief Returns a reading from the sensor - * \param type HDC_1000_SENSOR_TYPE_TEMP or HDC_1000_SENSOR_TYPE_HUMIDITY + * \param type HDC_1000_SENSOR_TYPE_TEMP or HDC_1000_SENSOR_TYPE_HUMID * \return Temperature (centi degrees C) or Humidity (centi %RH) */ static int @@ -221,7 +221,7 @@ value(int type) } if((type != HDC_1000_SENSOR_TYPE_TEMP) && - type != HDC_1000_SENSOR_TYPE_HUMIDITY) { + type != HDC_1000_SENSOR_TYPE_HUMID) { PRINTF("Invalid type\n"); return CC26XX_SENSOR_READING_ERROR; } else { @@ -231,7 +231,7 @@ value(int type) if(type == HDC_1000_SENSOR_TYPE_TEMP) { rv = (int)(temp * 100); - } else if(type == HDC_1000_SENSOR_TYPE_HUMIDITY) { + } else if(type == HDC_1000_SENSOR_TYPE_HUMID) { rv = (int)(hum * 100); } } diff --git a/arch/platform/srf06-cc26xx/sensortag/hdc-1000-sensor.h b/arch/platform/srf06-cc26xx/sensortag/hdc-1000-sensor.h index d3089d742..5c3a8aaff 100644 --- a/arch/platform/srf06-cc26xx/sensortag/hdc-1000-sensor.h +++ b/arch/platform/srf06-cc26xx/sensortag/hdc-1000-sensor.h @@ -45,7 +45,7 @@ * and latch them. It will then generate a sensors_changed event. * * The user can then retrieve readings by calling .value() and by passing - * either HDC_1000_SENSOR_TYPE_TEMP or HDC_1000_SENSOR_TYPE_HUMIDITY as the + * either HDC_1000_SENSOR_TYPE_TEMP or HDC_1000_SENSOR_TYPE_HUMID as the * argument. Multiple calls to value() will not trigger new readings, they will * simply return the most recent latched values. * @@ -65,7 +65,7 @@ #include "lib/sensors.h" /*---------------------------------------------------------------------------*/ #define HDC_1000_SENSOR_TYPE_TEMP 1 -#define HDC_1000_SENSOR_TYPE_HUMIDITY 2 +#define HDC_1000_SENSOR_TYPE_HUMID 2 /*---------------------------------------------------------------------------*/ /** * \name HDC1000 driver states diff --git a/examples/lwm2m-ipso-objects/example-ipso-objects.c b/examples/lwm2m-ipso-objects/example-ipso-objects.c index 013c62205..51bd84040 100644 --- a/examples/lwm2m-ipso-objects/example-ipso-objects.c +++ b/examples/lwm2m-ipso-objects/example-ipso-objects.c @@ -77,7 +77,7 @@ read_temp_value(const ipso_sensor_t *s, int32_t *value) static lwm2m_status_t read_hum_value(const ipso_sensor_t *s, int32_t *value) { - *value = 10 * hdc_1000_sensor.value(HDC_1000_SENSOR_TYPE_HUMIDITY); + *value = 10 * hdc_1000_sensor.value(HDC_1000_SENSOR_TYPE_HUMID); return LWM2M_STATUS_OK; } /* Lux reading */ diff --git a/examples/platform-specific/cc26xx/cc26xx-demo.c b/examples/platform-specific/cc26xx/cc26xx-demo.c index 8c90905af..81e99f3fa 100644 --- a/examples/platform-specific/cc26xx/cc26xx-demo.c +++ b/examples/platform-specific/cc26xx/cc26xx-demo.c @@ -203,7 +203,7 @@ get_hdc_reading() printf("HDC: Temp Read Error\n"); } - value = hdc_1000_sensor.value(HDC_1000_SENSOR_TYPE_HUMIDITY); + value = hdc_1000_sensor.value(HDC_1000_SENSOR_TYPE_HUMID); if(value != CC26XX_SENSOR_READING_ERROR) { printf("HDC: Humidity=%d.%02d %%RH\n", value / 100, value % 100); } else { diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/cc26xx-web-demo.c b/examples/platform-specific/cc26xx/cc26xx-web-demo/cc26xx-web-demo.c index f69a19478..3944a58b2 100644 --- a/examples/platform-specific/cc26xx/cc26xx-web-demo/cc26xx-web-demo.c +++ b/examples/platform-specific/cc26xx/cc26xx-web-demo/cc26xx-web-demo.c @@ -636,7 +636,7 @@ get_hdc_reading() } if(hdc_hum_reading.publish) { - value = hdc_1000_sensor.value(HDC_1000_SENSOR_TYPE_HUMIDITY); + value = hdc_1000_sensor.value(HDC_1000_SENSOR_TYPE_HUMID); if(value != CC26XX_SENSOR_READING_ERROR) { hdc_hum_reading.raw = value; From ba73abfeac542541c21f9c861aa35b931cc43e13 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 23 Sep 2018 12:58:31 +0100 Subject: [PATCH 365/485] Provide default board for platform simplelink If BOARD is unspecified, simplelink platform's build system will generate an error instead of choosing a default. This is a) inconsistent with what we do for other platforms and b) problematic because making targets clean, distclean etc will fail. --- arch/platform/simplelink/Makefile.simplelink | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/platform/simplelink/Makefile.simplelink b/arch/platform/simplelink/Makefile.simplelink index d14643c3f..acb613d6e 100644 --- a/arch/platform/simplelink/Makefile.simplelink +++ b/arch/platform/simplelink/Makefile.simplelink @@ -8,9 +8,7 @@ ifndef CONTIKI $(error 'CONTIKI' not defined! You must specify where CONTIKI resides!) endif -ifndef BOARD - $(error 'BOARD' not defined! You must specify which board you are using!) -endif +BOARD ?= srf06/cc26x0 ################################################################################ ### Resolve the SimpleLink Family From 8db3c8d3be78b709922055336184e4d10ba45f51 Mon Sep 17 00:00:00 2001 From: Atis Elsts Date: Mon, 24 Sep 2018 17:51:47 +0100 Subject: [PATCH 366/485] add const to spi_device_t * parameter in SPI functions, and store ext-flash default config in ROM instead of RAM --- arch/cpu/cc2538/dev/spi-arch.c | 26 ++++++------ arch/cpu/cc26xx-cc13xx/dev/spi-arch.c | 18 ++++---- .../simplelink-cc13xx-cc26xx/dev/spi-arch.c | 18 ++++---- arch/dev/ext-flash/ext-flash.c | 42 +++++++++---------- arch/dev/ext-flash/ext-flash.h | 12 +++--- os/dev/spi.c | 26 ++++++------ os/dev/spi.h | 40 +++++++++--------- 7 files changed, 91 insertions(+), 91 deletions(-) diff --git a/arch/cpu/cc2538/dev/spi-arch.c b/arch/cpu/cc2538/dev/spi-arch.c index c876e4ed7..d8c6437d5 100644 --- a/arch/cpu/cc2538/dev/spi-arch.c +++ b/arch/cpu/cc2538/dev/spi-arch.c @@ -107,7 +107,7 @@ static const spi_regs_t spi_regs[SSI_INSTANCE_COUNT] = { typedef struct spi_locks_s { mutex_t lock; - spi_device_t *owner; + const spi_device_t *owner; } spi_locks_t; /* One lock per SPI controller */ @@ -115,40 +115,40 @@ spi_locks_t board_spi_locks_spi[SPI_CONTROLLER_COUNT] = { { MUTEX_STATUS_UNLOCKE /*---------------------------------------------------------------------------*/ static void -spix_wait_tx_ready(spi_device_t *dev) +spix_wait_tx_ready(const spi_device_t *dev) { /* Infinite loop until SR_TNF - Transmit FIFO Not Full */ while(!(REG(spi_regs[dev->spi_controller].base + SSI_SR) & SSI_SR_TNF)); } /*---------------------------------------------------------------------------*/ static int -spix_read_buf(spi_device_t *dev) +spix_read_buf(const spi_device_t *dev) { return REG(spi_regs[dev->spi_controller].base + SSI_DR); } /*---------------------------------------------------------------------------*/ static void -spix_write_buf(spi_device_t *dev, int data) +spix_write_buf(const spi_device_t *dev, int data) { REG(spi_regs[dev->spi_controller].base + SSI_DR) = data; } /*---------------------------------------------------------------------------*/ static void -spix_wait_eotx(spi_device_t *dev) +spix_wait_eotx(const spi_device_t *dev) { /* wait until not busy */ while(REG(spi_regs[dev->spi_controller].base + SSI_SR) & SSI_SR_BSY); } /*---------------------------------------------------------------------------*/ static void -spix_wait_eorx(spi_device_t *dev) +spix_wait_eorx(const spi_device_t *dev) { /* wait as long as receive is empty */ while(!(REG(spi_regs[dev->spi_controller].base + SSI_SR) & SSI_SR_RNE)); } /*---------------------------------------------------------------------------*/ bool -spi_arch_has_lock(spi_device_t *dev) +spi_arch_has_lock(const spi_device_t *dev) { if(board_spi_locks_spi[dev->spi_controller].owner == dev) { return true; @@ -158,7 +158,7 @@ spi_arch_has_lock(spi_device_t *dev) } /*---------------------------------------------------------------------------*/ bool -spi_arch_is_bus_locked(spi_device_t *dev) +spi_arch_is_bus_locked(const spi_device_t *dev) { if(board_spi_locks_spi[dev->spi_controller].lock == MUTEX_STATUS_LOCKED) { return true; @@ -168,7 +168,7 @@ spi_arch_is_bus_locked(spi_device_t *dev) } /*---------------------------------------------------------------------------*/ spi_status_t -spi_arch_lock_and_open(spi_device_t *dev) +spi_arch_lock_and_open(const spi_device_t *dev) { const spi_regs_t *regs; uint32_t scr; @@ -265,7 +265,7 @@ spi_arch_lock_and_open(spi_device_t *dev) } /*---------------------------------------------------------------------------*/ spi_status_t -spi_arch_close_and_unlock(spi_device_t *dev) +spi_arch_close_and_unlock(const spi_device_t *dev) { if(!spi_arch_has_lock(dev)) { return SPI_DEV_STATUS_BUS_NOT_OWNED; @@ -282,7 +282,7 @@ spi_arch_close_and_unlock(spi_device_t *dev) } /*---------------------------------------------------------------------------*/ spi_status_t -spi_arch_select(spi_device_t *dev) +spi_arch_select(const spi_device_t *dev) { if(!spi_arch_has_lock(dev)) { @@ -295,7 +295,7 @@ spi_arch_select(spi_device_t *dev) } /*---------------------------------------------------------------------------*/ spi_status_t -spi_arch_deselect(spi_device_t *dev) +spi_arch_deselect(const spi_device_t *dev) { SPIX_CS_SET(PIN_TO_PORT(dev->pin_spi_cs), PIN_TO_NUM(dev->pin_spi_cs)); @@ -304,7 +304,7 @@ spi_arch_deselect(spi_device_t *dev) /*---------------------------------------------------------------------------*/ /* Assumes that checking dev and bus is not NULL before calling this */ spi_status_t -spi_arch_transfer(spi_device_t *dev, +spi_arch_transfer(const spi_device_t *dev, const uint8_t *write_buf, int wlen, uint8_t *inbuf, int rlen, int ignore_len) { diff --git a/arch/cpu/cc26xx-cc13xx/dev/spi-arch.c b/arch/cpu/cc26xx-cc13xx/dev/spi-arch.c index 897cfe878..d42c06af9 100644 --- a/arch/cpu/cc26xx-cc13xx/dev/spi-arch.c +++ b/arch/cpu/cc26xx-cc13xx/dev/spi-arch.c @@ -37,7 +37,7 @@ typedef struct spi_locks_s { mutex_t lock; - spi_device_t *owner; + const spi_device_t *owner; } spi_locks_t; /* One lock per SPI controller */ @@ -68,7 +68,7 @@ static const board_spi_controller_t spi_controller[SPI_CONTROLLER_COUNT] = { }; /*---------------------------------------------------------------------------*/ bool -spi_arch_has_lock(spi_device_t *dev) +spi_arch_has_lock(const spi_device_t *dev) { if(board_spi_locks_spi[dev->spi_controller].owner == dev) { return true; @@ -78,7 +78,7 @@ spi_arch_has_lock(spi_device_t *dev) } /*---------------------------------------------------------------------------*/ bool -spi_arch_is_bus_locked(spi_device_t *dev) +spi_arch_is_bus_locked(const spi_device_t *dev) { if(board_spi_locks_spi[dev->spi_controller].lock == MUTEX_STATUS_LOCKED) { return true; @@ -88,7 +88,7 @@ spi_arch_is_bus_locked(spi_device_t *dev) } /*---------------------------------------------------------------------------*/ static uint32_t -get_mode(spi_device_t *dev) +get_mode(const spi_device_t *dev) { /* Select the correct SPI mode */ if(dev->spi_pha == 0 && dev->spi_pol == 0) { @@ -103,7 +103,7 @@ get_mode(spi_device_t *dev) } /*---------------------------------------------------------------------------*/ spi_status_t -spi_arch_lock_and_open(spi_device_t *dev) +spi_arch_lock_and_open(const spi_device_t *dev) { uint32_t c; @@ -152,7 +152,7 @@ spi_arch_lock_and_open(spi_device_t *dev) } /*---------------------------------------------------------------------------*/ spi_status_t -spi_arch_close_and_unlock(spi_device_t *dev) +spi_arch_close_and_unlock(const spi_device_t *dev) { if(!spi_arch_has_lock(dev)) { return SPI_DEV_STATUS_BUS_NOT_OWNED; @@ -181,7 +181,7 @@ spi_arch_close_and_unlock(spi_device_t *dev) } /*---------------------------------------------------------------------------*/ spi_status_t -spi_arch_transfer(spi_device_t *dev, +spi_arch_transfer(const spi_device_t *dev, const uint8_t *write_buf, int wlen, uint8_t *inbuf, int rlen, int ignore_len) { @@ -231,7 +231,7 @@ spi_arch_transfer(spi_device_t *dev, } /*---------------------------------------------------------------------------*/ spi_status_t -spi_arch_select(spi_device_t *dev) +spi_arch_select(const spi_device_t *dev) { if(!spi_arch_has_lock(dev)) { @@ -243,7 +243,7 @@ spi_arch_select(spi_device_t *dev) return SPI_DEV_STATUS_OK; } spi_status_t -spi_arch_deselect(spi_device_t *dev) +spi_arch_deselect(const spi_device_t *dev) { ti_lib_gpio_set_dio(dev->pin_spi_cs); diff --git a/arch/cpu/simplelink-cc13xx-cc26xx/dev/spi-arch.c b/arch/cpu/simplelink-cc13xx-cc26xx/dev/spi-arch.c index 6950b7baf..a019a33fb 100644 --- a/arch/cpu/simplelink-cc13xx-cc26xx/dev/spi-arch.c +++ b/arch/cpu/simplelink-cc13xx-cc26xx/dev/spi-arch.c @@ -54,7 +54,7 @@ /*---------------------------------------------------------------------------*/ typedef struct { SPI_Handle handle; - spi_device_t *owner; + const spi_device_t *owner; } spi_arch_t; /*---------------------------------------------------------------------------*/ #if (SPI_CONTROLLER_COUNT > 0) @@ -96,7 +96,7 @@ convert_frame_format(uint8_t pol, uint8_t pha) } /*---------------------------------------------------------------------------*/ bool -spi_arch_has_lock(spi_device_t *dev) +spi_arch_has_lock(const spi_device_t *dev) { /* * The SPI device is the owner if the SPI controller returns a valid @@ -107,7 +107,7 @@ spi_arch_has_lock(spi_device_t *dev) } /*---------------------------------------------------------------------------*/ bool -spi_arch_is_bus_locked(spi_device_t *dev) +spi_arch_is_bus_locked(const spi_device_t *dev) { /* * The SPI controller is locked by any device if the SPI controller returns @@ -118,7 +118,7 @@ spi_arch_is_bus_locked(spi_device_t *dev) } /*---------------------------------------------------------------------------*/ spi_status_t -spi_arch_lock_and_open(spi_device_t *dev) +spi_arch_lock_and_open(const spi_device_t *dev) { uint_least8_t spi_index; spi_arch_t *spi_arch; @@ -167,7 +167,7 @@ spi_arch_lock_and_open(spi_device_t *dev) } /*---------------------------------------------------------------------------*/ spi_status_t -spi_arch_close_and_unlock(spi_device_t *dev) +spi_arch_close_and_unlock(const spi_device_t *dev) { spi_arch_t *spi_arch; @@ -196,7 +196,7 @@ spi_arch_close_and_unlock(spi_device_t *dev) } /*---------------------------------------------------------------------------*/ spi_status_t -spi_arch_transfer(spi_device_t *dev, +spi_arch_transfer(const spi_device_t *dev, const uint8_t *write_buf, int wlen, uint8_t *inbuf, int rlen, int ignore_len) { @@ -236,7 +236,7 @@ spi_arch_transfer(spi_device_t *dev, } /*---------------------------------------------------------------------------*/ spi_status_t -spi_arch_select(spi_device_t *dev) +spi_arch_select(const spi_device_t *dev) { if(!spi_arch_has_lock(dev)) { return SPI_DEV_STATUS_BUS_NOT_OWNED; @@ -248,7 +248,7 @@ spi_arch_select(spi_device_t *dev) } /*---------------------------------------------------------------------------*/ spi_status_t -spi_arch_deselect(spi_device_t *dev) +spi_arch_deselect(const spi_device_t *dev) { if(!spi_arch_has_lock(dev)) { return SPI_DEV_STATUS_BUS_NOT_OWNED; @@ -262,4 +262,4 @@ spi_arch_deselect(spi_device_t *dev) /** * @} * @} - */ \ No newline at end of file + */ diff --git a/arch/dev/ext-flash/ext-flash.c b/arch/dev/ext-flash/ext-flash.c index c9378d2aa..c4b108271 100644 --- a/arch/dev/ext-flash/ext-flash.c +++ b/arch/dev/ext-flash/ext-flash.c @@ -99,7 +99,7 @@ #define VERIFY_PART_POWERED_DOWN 0 #define VERIFY_PART_OK 1 /*---------------------------------------------------------------------------*/ -static spi_device_t flash_spi_configuration_default = { +static const spi_device_t flash_spi_configuration_default = { .spi_controller = EXT_FLASH_SPI_CONTROLLER, .pin_spi_sck = EXT_FLASH_SPI_PIN_SCK, .pin_spi_miso = EXT_FLASH_SPI_PIN_MISO, @@ -113,8 +113,8 @@ 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 const spi_device_t * +get_spi_conf(const spi_device_t *conf) { if(conf == NULL) { return &flash_spi_configuration_default; @@ -126,7 +126,7 @@ get_spi_conf(spi_device_t *conf) * Clear external flash CSN line */ static bool -select_on_bus(spi_device_t *flash_spi_configuration) +select_on_bus(const spi_device_t *flash_spi_configuration) { if(spi_select(flash_spi_configuration) == SPI_DEV_STATUS_OK) { return true; @@ -138,7 +138,7 @@ select_on_bus(spi_device_t *flash_spi_configuration) * Set external flash CSN line */ static void -deselect(spi_device_t *flash_spi_configuration) +deselect(const spi_device_t *flash_spi_configuration) { spi_deselect(flash_spi_configuration); } @@ -148,7 +148,7 @@ deselect(spi_device_t *flash_spi_configuration) * \return True when successful. */ static bool -wait_ready(spi_device_t *flash_spi_configuration) +wait_ready(const spi_device_t *flash_spi_configuration) { bool ret; const uint8_t wbuf[1] = { BLS_CODE_READ_STATUS }; @@ -196,7 +196,7 @@ wait_ready(spi_device_t *flash_spi_configuration) * was powered down */ static uint8_t -verify_part(spi_device_t *flash_spi_configuration) +verify_part(const spi_device_t *flash_spi_configuration) { const uint8_t wbuf[] = { BLS_CODE_MDID, 0xFF, 0xFF, 0x00 }; uint8_t rbuf[2] = { 0, 0 }; @@ -230,7 +230,7 @@ verify_part(spi_device_t *flash_spi_configuration) * the status register is accessible. */ static bool -power_down(spi_device_t *flash_spi_configuration) +power_down(const spi_device_t *flash_spi_configuration) { uint8_t cmd; uint8_t i; @@ -271,7 +271,7 @@ power_down(spi_device_t *flash_spi_configuration) * \return True if the command was written successfully */ static bool -power_standby(spi_device_t *flash_spi_configuration) +power_standby(const spi_device_t *flash_spi_configuration) { uint8_t cmd; bool success; @@ -297,7 +297,7 @@ power_standby(spi_device_t *flash_spi_configuration) * \return True when successful. */ static bool -write_enable(spi_device_t *flash_spi_configuration) +write_enable(const spi_device_t *flash_spi_configuration) { bool ret; const uint8_t wbuf[] = { BLS_CODE_WRITE_ENABLE }; @@ -316,9 +316,9 @@ write_enable(spi_device_t *flash_spi_configuration) } /*---------------------------------------------------------------------------*/ bool -ext_flash_open(spi_device_t *conf) +ext_flash_open(const spi_device_t *conf) { - spi_device_t *flash_spi_configuration; + const spi_device_t *flash_spi_configuration; flash_spi_configuration = get_spi_conf(conf); @@ -346,10 +346,10 @@ ext_flash_open(spi_device_t *conf) } /*---------------------------------------------------------------------------*/ bool -ext_flash_close(spi_device_t *conf) +ext_flash_close(const spi_device_t *conf) { bool ret; - spi_device_t *flash_spi_configuration; + const spi_device_t *flash_spi_configuration; flash_spi_configuration = get_spi_conf(conf); @@ -365,12 +365,12 @@ ext_flash_close(spi_device_t *conf) } /*---------------------------------------------------------------------------*/ bool -ext_flash_read(spi_device_t *conf, uint32_t offset, uint32_t length, uint8_t *buf) +ext_flash_read(const spi_device_t *conf, uint32_t offset, uint32_t length, uint8_t *buf) { uint8_t wbuf[4]; bool ret; - spi_device_t *flash_spi_configuration; + const spi_device_t *flash_spi_configuration; flash_spi_configuration = get_spi_conf(conf); @@ -406,12 +406,12 @@ ext_flash_read(spi_device_t *conf, uint32_t offset, uint32_t length, uint8_t *bu } /*---------------------------------------------------------------------------*/ bool -ext_flash_write(spi_device_t *conf, uint32_t offset, uint32_t length, const uint8_t *buf) +ext_flash_write(const spi_device_t *conf, uint32_t offset, uint32_t length, const uint8_t *buf) { uint8_t wbuf[4]; uint32_t ilen; /* interim length per instruction */ - spi_device_t *flash_spi_configuration; + const spi_device_t *flash_spi_configuration; flash_spi_configuration = get_spi_conf(conf); @@ -466,7 +466,7 @@ ext_flash_write(spi_device_t *conf, uint32_t offset, uint32_t length, const uint } /*---------------------------------------------------------------------------*/ bool -ext_flash_erase(spi_device_t *conf, uint32_t offset, uint32_t length) +ext_flash_erase(const spi_device_t *conf, uint32_t offset, uint32_t length) { /* * Note that Block erase might be more efficient when the floor map @@ -477,7 +477,7 @@ ext_flash_erase(spi_device_t *conf, uint32_t offset, uint32_t length) uint32_t i, numsectors; uint32_t endoffset = offset + length - 1; - spi_device_t *flash_spi_configuration; + const spi_device_t *flash_spi_configuration; flash_spi_configuration = get_spi_conf(conf); @@ -518,7 +518,7 @@ ext_flash_erase(spi_device_t *conf, uint32_t offset, uint32_t length) } /*---------------------------------------------------------------------------*/ bool -ext_flash_init(spi_device_t *conf) +ext_flash_init(const spi_device_t *conf) { if(ext_flash_open(conf) == false) { return false; diff --git a/arch/dev/ext-flash/ext-flash.h b/arch/dev/ext-flash/ext-flash.h index 73b7320f8..2d081f5be 100644 --- a/arch/dev/ext-flash/ext-flash.h +++ b/arch/dev/ext-flash/ext-flash.h @@ -61,7 +61,7 @@ * \param conf SPI bus configuration struct. NULL for default. * \return True when successful. */ -bool ext_flash_open(spi_device_t *conf); +bool ext_flash_open(const spi_device_t *conf); /** * \brief Close the storage driver @@ -70,7 +70,7 @@ bool ext_flash_open(spi_device_t *conf); * * This call will put the device in its lower power mode (power down). */ -bool ext_flash_close(spi_device_t *conf); +bool ext_flash_close(const spi_device_t *conf); /** * \brief Read storage content @@ -82,7 +82,7 @@ bool ext_flash_close(spi_device_t *conf); * * buf must be allocated by the caller */ -bool ext_flash_read(spi_device_t *conf, uint32_t offset, uint32_t length, uint8_t *buf); +bool ext_flash_read(const spi_device_t *conf, uint32_t offset, uint32_t length, uint8_t *buf); /** * \brief Erase storage sectors corresponding to the range. @@ -94,7 +94,7 @@ bool ext_flash_read(spi_device_t *conf, uint32_t offset, uint32_t length, uint8_ * The erase operation will be sector-wise, therefore a call to this function * will generally start the erase procedure at an address lower than offset */ -bool ext_flash_erase(spi_device_t *conf, uint32_t offset, uint32_t length); +bool ext_flash_erase(const spi_device_t *conf, uint32_t offset, uint32_t length); /** * \brief Write to storage sectors. @@ -105,7 +105,7 @@ bool ext_flash_erase(spi_device_t *conf, uint32_t offset, uint32_t length); * * \return True when successful. */ -bool ext_flash_write(spi_device_t *conf, uint32_t offset, uint32_t length, const uint8_t *buf); +bool ext_flash_write(const spi_device_t *conf, uint32_t offset, uint32_t length, const uint8_t *buf); /** * \brief Initialise the external flash @@ -117,7 +117,7 @@ bool ext_flash_write(spi_device_t *conf, uint32_t offset, uint32_t length, const * In order to perform any operation, the caller must first wake the device * up by calling ext_flash_open() */ -bool ext_flash_init(spi_device_t *conf); +bool ext_flash_init(const spi_device_t *conf); /*---------------------------------------------------------------------------*/ #endif /* EXT_FLASH_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/os/dev/spi.c b/os/dev/spi.c index c41cf206f..145a4f72e 100644 --- a/os/dev/spi.c +++ b/os/dev/spi.c @@ -43,7 +43,7 @@ #include /*---------------------------------------------------------------------------*/ spi_status_t -spi_acquire(spi_device_t *dev) +spi_acquire(const spi_device_t *dev) { if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) { return SPI_DEV_STATUS_EINVAL; @@ -54,7 +54,7 @@ spi_acquire(spi_device_t *dev) } /*---------------------------------------------------------------------------*/ spi_status_t -spi_release(spi_device_t *dev) +spi_release(const spi_device_t *dev) { if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) { return SPI_DEV_STATUS_EINVAL; @@ -65,19 +65,19 @@ spi_release(spi_device_t *dev) } /*---------------------------------------------------------------------------*/ spi_status_t -spi_select(spi_device_t *dev) +spi_select(const spi_device_t *dev) { return spi_arch_select(dev); } /*---------------------------------------------------------------------------*/ spi_status_t -spi_deselect(spi_device_t *dev) +spi_deselect(const spi_device_t *dev) { return spi_arch_deselect(dev); } /*---------------------------------------------------------------------------*/ bool -spi_has_bus(spi_device_t *dev) +spi_has_bus(const spi_device_t *dev) { if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) { return false; @@ -87,7 +87,7 @@ spi_has_bus(spi_device_t *dev) } /*---------------------------------------------------------------------------*/ spi_status_t -spi_write_byte(spi_device_t *dev, uint8_t data) +spi_write_byte(const spi_device_t *dev, uint8_t data) { if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) { return SPI_DEV_STATUS_EINVAL; @@ -101,7 +101,7 @@ spi_write_byte(spi_device_t *dev, uint8_t data) } /*---------------------------------------------------------------------------*/ spi_status_t -spi_write(spi_device_t *dev, const uint8_t *data, int size) +spi_write(const spi_device_t *dev, const uint8_t *data, int size) { if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) { return SPI_DEV_STATUS_EINVAL; @@ -115,7 +115,7 @@ spi_write(spi_device_t *dev, const uint8_t *data, int size) } /*---------------------------------------------------------------------------*/ spi_status_t -spi_read_byte(spi_device_t *dev, uint8_t *buf) +spi_read_byte(const spi_device_t *dev, uint8_t *buf) { if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) { return SPI_DEV_STATUS_EINVAL; @@ -129,7 +129,7 @@ spi_read_byte(spi_device_t *dev, uint8_t *buf) } /*---------------------------------------------------------------------------*/ spi_status_t -spi_read(spi_device_t *dev, uint8_t *buf, int size) +spi_read(const spi_device_t *dev, uint8_t *buf, int size) { if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) { return SPI_DEV_STATUS_EINVAL; @@ -143,7 +143,7 @@ spi_read(spi_device_t *dev, uint8_t *buf, int size) } /*---------------------------------------------------------------------------*/ spi_status_t -spi_read_skip(spi_device_t *dev, int size) +spi_read_skip(const spi_device_t *dev, int size) { if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) { return SPI_DEV_STATUS_EINVAL; @@ -157,7 +157,7 @@ spi_read_skip(spi_device_t *dev, int size) } /*---------------------------------------------------------------------------*/ spi_status_t -spi_transfer(spi_device_t *dev, +spi_transfer(const spi_device_t *dev, const uint8_t *wdata, int wsize, uint8_t *rbuf, int rsize, int ignore) { @@ -181,7 +181,7 @@ spi_transfer(spi_device_t *dev, } /*---------------------------------------------------------------------------*/ spi_status_t -spi_read_register(spi_device_t *dev, uint8_t reg, uint8_t *data, int size) +spi_read_register(const spi_device_t *dev, uint8_t reg, uint8_t *data, int size) { spi_status_t status; if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) { @@ -204,7 +204,7 @@ spi_read_register(spi_device_t *dev, uint8_t reg, uint8_t *data, int size) } /*---------------------------------------------------------------------------*/ spi_status_t -spi_strobe(spi_device_t *dev, uint8_t strobe, uint8_t *result) +spi_strobe(const spi_device_t *dev, uint8_t strobe, uint8_t *result) { if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) { return SPI_DEV_STATUS_EINVAL; diff --git a/os/dev/spi.h b/os/dev/spi.h index 70faa6b5b..b7114717f 100644 --- a/os/dev/spi.h +++ b/os/dev/spi.h @@ -115,7 +115,7 @@ typedef struct spi_device { * to be locked and the opening configuration. * \return SPI return code */ -spi_status_t spi_acquire(spi_device_t *dev); +spi_status_t spi_acquire(const spi_device_t *dev); /** * \brief Closes and then unlocks an SPI controller @@ -127,7 +127,7 @@ spi_status_t spi_acquire(spi_device_t *dev); * This should work only if the device has already locked the SPI * controller. */ -spi_status_t spi_release(spi_device_t *dev); +spi_status_t spi_release(const spi_device_t *dev); /** * \brief Selects the SPI peripheral @@ -137,7 +137,7 @@ spi_status_t spi_release(spi_device_t *dev); * Clears the CS pin. This should work only if the device has * already locked the SPI controller. */ -spi_status_t spi_select(spi_device_t *dev); +spi_status_t spi_select(const spi_device_t *dev); /** * \brief Deselects the SPI peripheral @@ -146,14 +146,14 @@ spi_status_t spi_select(spi_device_t *dev); * * Sets the CS pin. Lock is not required. */ -spi_status_t spi_deselect(spi_device_t *dev); +spi_status_t spi_deselect(const spi_device_t *dev); /** * \brief Checks if a device has locked an SPI controller * \param dev An SPI device configuration which defines the controller. * \return true if the device has the lock, false otherwise. */ -bool spi_has_bus(spi_device_t *dev); +bool spi_has_bus(const spi_device_t *dev); /** * \brief Writes a single byte to an SPI device @@ -163,7 +163,7 @@ bool spi_has_bus(spi_device_t *dev); * * It should work only if the device has already locked the SPI controller. */ -spi_status_t spi_write_byte(spi_device_t *dev, uint8_t data); +spi_status_t spi_write_byte(const spi_device_t *dev, uint8_t data); /** * \brief Reads a single byte from an SPI device @@ -173,7 +173,7 @@ spi_status_t spi_write_byte(spi_device_t *dev, uint8_t data); * * It should work only if the device has already locked the SPI controller. */ -spi_status_t spi_read_byte(spi_device_t *dev, uint8_t *data); +spi_status_t spi_read_byte(const spi_device_t *dev, uint8_t *data); /** * \brief Writes a buffer to an SPI device @@ -184,7 +184,7 @@ spi_status_t spi_read_byte(spi_device_t *dev, uint8_t *data); * * It should work only if the device has already locked the SPI controller. */ -spi_status_t spi_write(spi_device_t *dev, +spi_status_t spi_write(const spi_device_t *dev, const uint8_t *data, int size); /** @@ -196,7 +196,7 @@ spi_status_t spi_write(spi_device_t *dev, * * It should work only if the device has already locked the SPI controller. */ -spi_status_t spi_read(spi_device_t *dev, uint8_t *data, int size); +spi_status_t spi_read(const spi_device_t *dev, uint8_t *data, int size); /** * \brief Reads and ignores data from an SPI device @@ -207,7 +207,7 @@ spi_status_t spi_read(spi_device_t *dev, uint8_t *data, int size); * Reads size bytes from the SPI and throws them away. * It should work only if the device has already locked the SPI controller. */ -spi_status_t spi_read_skip(spi_device_t *dev, int size); +spi_status_t spi_read_skip(const spi_device_t *dev, int size); /** * \brief Performs a generic SPI transfer @@ -226,7 +226,7 @@ spi_status_t spi_read_skip(spi_device_t *dev, int size); * be copied to buf. The remaining ignore_len bytes won't be copied to the * buffer. The maximum of wlen and rlen+ignore_len of bytes will be transfered. */ -spi_status_t spi_transfer(spi_device_t *dev, +spi_status_t spi_transfer(const spi_device_t *dev, const uint8_t *data, int wsize, uint8_t *buf, int rsize, int ignore); @@ -239,7 +239,7 @@ spi_status_t spi_transfer(spi_device_t *dev, * * It should work only if the device has already locked the SPI controller. */ -spi_status_t spi_strobe(spi_device_t *dev, uint8_t strobe, +spi_status_t spi_strobe(const spi_device_t *dev, uint8_t strobe, uint8_t *status); /** @@ -252,7 +252,7 @@ spi_status_t spi_strobe(spi_device_t *dev, uint8_t strobe, * * It should work only if the device has already locked the SPI controller. */ -spi_status_t spi_read_register(spi_device_t *dev, uint8_t reg, +spi_status_t spi_read_register(const spi_device_t *dev, uint8_t reg, uint8_t *data, int size); /*---------------------------------------------------------------------------*/ @@ -266,7 +266,7 @@ spi_status_t spi_read_register(spi_device_t *dev, uint8_t reg, * \return 1 if the device has the lock, 0 otherwise. * */ -bool spi_arch_has_lock(spi_device_t *dev); +bool spi_arch_has_lock(const spi_device_t *dev); /** * \brief Checks if an SPI controller is locked by any device @@ -275,7 +275,7 @@ bool spi_arch_has_lock(spi_device_t *dev); * \return 1 if the controller is locked, 0 otherwise. * */ -bool spi_arch_is_bus_locked(spi_device_t *dev); +bool spi_arch_is_bus_locked(const spi_device_t *dev); /** * \brief Locks and opens an SPI controller to the configuration specified. @@ -286,7 +286,7 @@ bool spi_arch_is_bus_locked(spi_device_t *dev); * controller. * */ -spi_status_t spi_arch_lock_and_open(spi_device_t *dev); +spi_status_t spi_arch_lock_and_open(const spi_device_t *dev); /** * \brief Closes and unlocks an SPI controller @@ -299,7 +299,7 @@ spi_status_t spi_arch_lock_and_open(spi_device_t *dev); * controller. * */ -spi_status_t spi_arch_close_and_unlock(spi_device_t *dev); +spi_status_t spi_arch_close_and_unlock(const spi_device_t *dev); /** * \brief Performs an SPI transfer @@ -318,7 +318,7 @@ spi_status_t spi_arch_close_and_unlock(spi_device_t *dev); * be copied to buf. The remaining ignore_len bytes won't be copied to the * buffer. The maximum of wlen and rlen+ignore_len of bytes will be transfered. */ -spi_status_t spi_arch_transfer(spi_device_t *dev, +spi_status_t spi_arch_transfer(const spi_device_t *dev, const uint8_t *data, int wlen, uint8_t *buf, int rlen, int ignore_len); @@ -331,7 +331,7 @@ spi_status_t spi_arch_transfer(spi_device_t *dev, * Clears the CS pin. It should work only if the device has already * locked the SPI controller. */ -spi_status_t spi_arch_select(spi_device_t *dev); +spi_status_t spi_arch_select(const spi_device_t *dev); /** * \brief Deselects an SPI device @@ -340,7 +340,7 @@ spi_status_t spi_arch_select(spi_device_t *dev); * * Set the CS pin. Locking the SPI controller is not needed. */ -spi_status_t spi_arch_deselect(spi_device_t *dev); +spi_status_t spi_arch_deselect(const spi_device_t *dev); #endif /* SPI_H_ */ /*---------------------------------------------------------------------------*/ From e71ef49c047a9be55b4ec15e52f2bed45a12603f Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Wed, 26 Sep 2018 21:42:06 +0100 Subject: [PATCH 367/485] Create platform-independent SPI select and deselect --- arch/cpu/cc2538/dev/spi-arch.c | 21 ---------------- arch/cpu/cc26xx-cc13xx/dev/spi-arch.c | 19 --------------- .../simplelink-cc13xx-cc26xx/dev/spi-arch.c | 24 ------------------- os/dev/spi.c | 12 ++++++++-- 4 files changed, 10 insertions(+), 66 deletions(-) diff --git a/arch/cpu/cc2538/dev/spi-arch.c b/arch/cpu/cc2538/dev/spi-arch.c index d8c6437d5..aae0ed797 100644 --- a/arch/cpu/cc2538/dev/spi-arch.c +++ b/arch/cpu/cc2538/dev/spi-arch.c @@ -281,27 +281,6 @@ spi_arch_close_and_unlock(const spi_device_t *dev) return SPI_DEV_STATUS_OK; } /*---------------------------------------------------------------------------*/ -spi_status_t -spi_arch_select(const spi_device_t *dev) -{ - - if(!spi_arch_has_lock(dev)) { - return SPI_DEV_STATUS_BUS_NOT_OWNED; - } - - SPIX_CS_CLR(PIN_TO_PORT(dev->pin_spi_cs), PIN_TO_NUM(dev->pin_spi_cs)); - - return SPI_DEV_STATUS_OK; -} -/*---------------------------------------------------------------------------*/ -spi_status_t -spi_arch_deselect(const spi_device_t *dev) -{ - SPIX_CS_SET(PIN_TO_PORT(dev->pin_spi_cs), PIN_TO_NUM(dev->pin_spi_cs)); - - return SPI_DEV_STATUS_OK; -} -/*---------------------------------------------------------------------------*/ /* Assumes that checking dev and bus is not NULL before calling this */ spi_status_t spi_arch_transfer(const spi_device_t *dev, diff --git a/arch/cpu/cc26xx-cc13xx/dev/spi-arch.c b/arch/cpu/cc26xx-cc13xx/dev/spi-arch.c index d42c06af9..426e09a1b 100644 --- a/arch/cpu/cc26xx-cc13xx/dev/spi-arch.c +++ b/arch/cpu/cc26xx-cc13xx/dev/spi-arch.c @@ -230,22 +230,3 @@ spi_arch_transfer(const spi_device_t *dev, return SPI_DEV_STATUS_OK; } /*---------------------------------------------------------------------------*/ -spi_status_t -spi_arch_select(const spi_device_t *dev) -{ - - if(!spi_arch_has_lock(dev)) { - return SPI_DEV_STATUS_BUS_NOT_OWNED; - } - - ti_lib_gpio_clear_dio(dev->pin_spi_cs); - - return SPI_DEV_STATUS_OK; -} -spi_status_t -spi_arch_deselect(const spi_device_t *dev) -{ - ti_lib_gpio_set_dio(dev->pin_spi_cs); - - return SPI_DEV_STATUS_OK; -} diff --git a/arch/cpu/simplelink-cc13xx-cc26xx/dev/spi-arch.c b/arch/cpu/simplelink-cc13xx-cc26xx/dev/spi-arch.c index a019a33fb..f4c6114e8 100644 --- a/arch/cpu/simplelink-cc13xx-cc26xx/dev/spi-arch.c +++ b/arch/cpu/simplelink-cc13xx-cc26xx/dev/spi-arch.c @@ -235,30 +235,6 @@ spi_arch_transfer(const spi_device_t *dev, return SPI_DEV_STATUS_OK; } /*---------------------------------------------------------------------------*/ -spi_status_t -spi_arch_select(const spi_device_t *dev) -{ - if(!spi_arch_has_lock(dev)) { - return SPI_DEV_STATUS_BUS_NOT_OWNED; - } - - PINCC26XX_setOutputValue(dev->pin_spi_cs, 0); - - return SPI_DEV_STATUS_OK; -} -/*---------------------------------------------------------------------------*/ -spi_status_t -spi_arch_deselect(const spi_device_t *dev) -{ - if(!spi_arch_has_lock(dev)) { - return SPI_DEV_STATUS_BUS_NOT_OWNED; - } - - PINCC26XX_setOutputValue(dev->pin_spi_cs, 1); - - return SPI_DEV_STATUS_OK; -} -/*---------------------------------------------------------------------------*/ /** * @} * @} diff --git a/os/dev/spi.c b/os/dev/spi.c index 145a4f72e..091cf8e51 100644 --- a/os/dev/spi.c +++ b/os/dev/spi.c @@ -67,13 +67,21 @@ spi_release(const spi_device_t *dev) spi_status_t spi_select(const spi_device_t *dev) { - return spi_arch_select(dev); + if(!spi_arch_has_lock(dev)) { + return SPI_DEV_STATUS_BUS_NOT_OWNED; + } + + gpio_hal_arch_clear_pin(dev->pin_spi_cs); + + return SPI_DEV_STATUS_OK; } /*---------------------------------------------------------------------------*/ spi_status_t spi_deselect(const spi_device_t *dev) { - return spi_arch_deselect(dev); + gpio_hal_arch_set_pin(dev->pin_spi_cs); + + return SPI_DEV_STATUS_OK; } /*---------------------------------------------------------------------------*/ bool From ad577cf77f424809308879fc23db61620c2040c2 Mon Sep 17 00:00:00 2001 From: Atis Elsts Date: Fri, 31 Aug 2018 15:11:25 +0100 Subject: [PATCH 368/485] Add TSCH stats --- arch/platform/cooja/dev/cooja-radio.c | 4 + examples/6tisch/tsch-stats/Makefile | 28 ++ examples/6tisch/tsch-stats/README.md | 1 + examples/6tisch/tsch-stats/node.c | 93 +++++++ examples/6tisch/tsch-stats/project-conf.h | 92 ++++++ .../6tisch/tsch-stats/tsch-stats-cooja.csc | 263 ++++++++++++++++++ os/net/mac/tsch/tsch-queue.c | 2 + os/net/mac/tsch/tsch-slot-operation.c | 16 ++ os/net/mac/tsch/tsch-stats.c | 236 ++++++++++++++++ os/net/mac/tsch/tsch-stats.h | 223 +++++++++++++++ os/net/mac/tsch/tsch.c | 5 + os/net/mac/tsch/tsch.h | 1 + 12 files changed, 964 insertions(+) create mode 100644 examples/6tisch/tsch-stats/Makefile create mode 100644 examples/6tisch/tsch-stats/README.md create mode 100644 examples/6tisch/tsch-stats/node.c create mode 100644 examples/6tisch/tsch-stats/project-conf.h create mode 100644 examples/6tisch/tsch-stats/tsch-stats-cooja.csc create mode 100644 os/net/mac/tsch/tsch-stats.c create mode 100644 os/net/mac/tsch/tsch-stats.h diff --git a/arch/platform/cooja/dev/cooja-radio.c b/arch/platform/cooja/dev/cooja-radio.c index 4f7e6a357..f0dee567b 100644 --- a/arch/platform/cooja/dev/cooja-radio.c +++ b/arch/platform/cooja/dev/cooja-radio.c @@ -330,6 +330,10 @@ get_value(radio_param_t param, radio_value_t *value) case RADIO_PARAM_LAST_LINK_QUALITY: *value = simLQI; return RADIO_RESULT_OK; + case RADIO_PARAM_RSSI: + /* return a fixed value depending on the channel */ + *value = -90 + simRadioChannel - 11; + return RADIO_RESULT_OK; default: return RADIO_RESULT_NOT_SUPPORTED; } diff --git a/examples/6tisch/tsch-stats/Makefile b/examples/6tisch/tsch-stats/Makefile new file mode 100644 index 000000000..20592ebad --- /dev/null +++ b/examples/6tisch/tsch-stats/Makefile @@ -0,0 +1,28 @@ +CONTIKI_PROJECT = node +all: $(CONTIKI_PROJECT) + +CONTIKI=../../.. + +# force Orchestra from command line +MAKE_WITH_ORCHESTRA ?= 0 +# force Security from command line +MAKE_WITH_SECURITY ?= 0 +# print #routes periodically, used for regression tests +MAKE_WITH_PERIODIC_ROUTES_PRINT ?= 0 + +MAKE_MAC = MAKE_MAC_TSCH +MODULES += os/services/shell + +ifeq ($(MAKE_WITH_ORCHESTRA),1) +MODULES += os/services/orchestra +endif + +ifeq ($(MAKE_WITH_SECURITY),1) +CFLAGS += -DWITH_SECURITY=1 +endif + +ifeq ($(MAKE_WITH_PERIODIC_ROUTES_PRINT),1) +CFLAGS += -DWITH_PERIODIC_ROUTES_PRINT=1 +endif + +include $(CONTIKI)/Makefile.include diff --git a/examples/6tisch/tsch-stats/README.md b/examples/6tisch/tsch-stats/README.md new file mode 100644 index 000000000..1ee915f9d --- /dev/null +++ b/examples/6tisch/tsch-stats/README.md @@ -0,0 +1 @@ +Demonstration of TSCH stats. \ No newline at end of file diff --git a/examples/6tisch/tsch-stats/node.c b/examples/6tisch/tsch-stats/node.c new file mode 100644 index 000000000..b27821c65 --- /dev/null +++ b/examples/6tisch/tsch-stats/node.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2015, SICS Swedish ICT. + * Copyright (c) 2017, 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 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. + * + */ +/** + * \file + * A RPL+TSCH node. + * + * \author Simon Duquennoy + * Atis Elsts + */ + +#include "contiki.h" +#include "node-id.h" +#include "rpl.h" +#include "rpl-dag-root.h" +#include "sys/log.h" +#include "net/ipv6/uip-ds6-route.h" +#include "net/mac/tsch/tsch.h" +#include "net/mac/tsch/tsch-log.h" +#if UIP_CONF_IPV6_RPL_LITE == 0 +#include "rpl-private.h" +#endif /* UIP_CONF_IPV6_RPL_LITE == 0 */ + +#define DEBUG DEBUG_PRINT +#include "net/ipv6/uip-debug.h" + +/*---------------------------------------------------------------------------*/ +PROCESS(node_process, "RPL Node"); +AUTOSTART_PROCESSES(&node_process); + +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(node_process, ev, data) +{ + int is_coordinator; + + PROCESS_BEGIN(); + + is_coordinator = (node_id == 1); + + if(is_coordinator) { + rpl_dag_root_init_dag_immediately(); + } + NETSTACK_MAC.on(); + +#if WITH_PERIODIC_ROUTES_PRINT + { + static struct etimer et; + /* Print out routing tables every minute */ + etimer_set(&et, CLOCK_SECOND * 60); + while(1) { + /* Used for non-regression testing */ + #if RPL_WITH_STORING + PRINTF("Routing entries: %u\n", uip_ds6_route_num_routes()); + #endif + #if RPL_WITH_NON_STORING + PRINTF("Routing links: %u\n", rpl_ns_num_nodes()); + #endif + PROCESS_YIELD_UNTIL(etimer_expired(&et)); + etimer_reset(&et); + } + } +#endif /* WITH_PERIODIC_ROUTES_PRINT */ + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/examples/6tisch/tsch-stats/project-conf.h b/examples/6tisch/tsch-stats/project-conf.h new file mode 100644 index 000000000..5a2248dae --- /dev/null +++ b/examples/6tisch/tsch-stats/project-conf.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2015, SICS Swedish ICT. + * Copyright (c) 2017, 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 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. + * + */ + +/** + * \author Simon Duquennoy + * Atis Elsts + */ + +#ifndef __PROJECT_CONF_H__ +#define __PROJECT_CONF_H__ + +/* Set to enable TSCH security */ +#ifndef WITH_SECURITY +#define WITH_SECURITY 0 +#endif /* WITH_SECURITY */ + +/* USB serial takes space, free more space elsewhere */ +#define SICSLOWPAN_CONF_FRAG 0 +#define UIP_CONF_BUFFER_SIZE 160 + +/*******************************************************/ +/******************* Configure TSCH ********************/ +/*******************************************************/ + +/* IEEE802.15.4 PANID */ +#define IEEE802154_CONF_PANID 0x81a5 + +/* Do not start TSCH at init, wait for NETSTACK_MAC.on() */ +#define TSCH_CONF_AUTOSTART 0 + +/* 6TiSCH minimal schedule length. + * Larger values result in less frequent active slots: reduces capacity and saves energy. */ +#define TSCH_SCHEDULE_CONF_DEFAULT_LENGTH 3 + +#if WITH_SECURITY + +/* Enable security */ +#define LLSEC802154_CONF_ENABLED 1 + +#endif /* WITH_SECURITY */ + +/* Enable TSCH statistics */ +#define TSCH_STATS_CONF_ON 1 + +/* Enable periodic RSSI sampling for TSCH statistics */ +#define TSCH_STATS_CONF_SAMPLE_NOISE_RSSI 1 + +/* Reduce the TSCH stat "decay to normal" period */ +#define TSCH_STATS_CONF_DECAY_INTERVAL (60 * CLOCK_SECOND) + +/*******************************************************/ +/************* Other system configuration **************/ +/*******************************************************/ + +/* Logging */ +#define LOG_CONF_LEVEL_RPL LOG_LEVEL_INFO +#define LOG_CONF_LEVEL_TCPIP LOG_LEVEL_WARN +#define LOG_CONF_LEVEL_IPV6 LOG_LEVEL_WARN +#define LOG_CONF_LEVEL_6LOWPAN LOG_LEVEL_WARN +#define LOG_CONF_LEVEL_MAC LOG_LEVEL_DBG +#define LOG_CONF_LEVEL_FRAMER LOG_LEVEL_INFO +#define TSCH_LOG_CONF_PER_SLOT 1 + +#endif /* __PROJECT_CONF_H__ */ diff --git a/examples/6tisch/tsch-stats/tsch-stats-cooja.csc b/examples/6tisch/tsch-stats/tsch-stats-cooja.csc new file mode 100644 index 000000000..76f87e9be --- /dev/null +++ b/examples/6tisch/tsch-stats/tsch-stats-cooja.csc @@ -0,0 +1,263 @@ + + + [APPS_DIR]/mrm + [APPS_DIR]/mspsim + [APPS_DIR]/avrora + [APPS_DIR]/serial_socket + [APPS_DIR]/collect-view + [APPS_DIR]/powertracker + + TSCH stats + 123456 + 1000000 + + org.contikios.cooja.radiomediums.UDGM + 50.0 + 100.0 + 1.0 + 0.5 + + + 40000 + + + org.contikios.cooja.contikimote.ContikiMoteType + mtype660 + RPL/TSCH Node + [CONFIG_DIR]/node.c + make TARGET=cooja clean + make TARGET=cooja 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.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + false + + + + org.contikios.cooja.interfaces.Position + -1.285769821276336 + 38.58045647334346 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 1 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype660 + + + + org.contikios.cooja.interfaces.Position + -19.324109516886306 + 76.23135780254927 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 2 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype660 + + + + org.contikios.cooja.interfaces.Position + 5.815501305791592 + 76.77463755494317 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 3 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype660 + + + + org.contikios.cooja.interfaces.Position + 31.920697784030082 + 50.5212265977149 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 4 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype660 + + + + org.contikios.cooja.interfaces.Position + 47.21747673247198 + 30.217765340599726 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 5 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype660 + + + + org.contikios.cooja.interfaces.Position + 10.622284947035123 + 109.81862399725188 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 6 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype660 + + + + org.contikios.cooja.interfaces.Position + 52.41150716335335 + 109.93228340481916 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 7 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype660 + + + + org.contikios.cooja.interfaces.Position + 70.18727461718498 + 70.06861701541145 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 8 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype660 + + + + org.contikios.cooja.interfaces.Position + 80.29870484201041 + 99.37351603835938 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 9 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype660 + + + + org.contikios.cooja.plugins.SimControl + 242 + 4 + 160 + 11 + 241 + + + org.contikios.cooja.plugins.Visualizer + + true + org.contikios.cooja.plugins.skins.IDVisualizerSkin + org.contikios.cooja.plugins.skins.GridVisualizerSkin + org.contikios.cooja.plugins.skins.TrafficVisualizerSkin + org.contikios.cooja.plugins.skins.UDGMVisualizerSkin + 1.7405603810040515 0.0 0.0 1.7405603810040515 47.95980153208088 -42.576134155447555 + + 236 + 3 + 230 + 1 + 1 + + + org.contikios.cooja.plugins.LogListener + + + + + + 1031 + 0 + 394 + 273 + 6 + + + org.contikios.cooja.plugins.TimeLine + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + + + + 16529.88882215865 + + 1304 + 2 + 311 + 0 + 412 + + + diff --git a/os/net/mac/tsch/tsch-queue.c b/os/net/mac/tsch/tsch-queue.c index 4ef5130fb..f586ac90e 100644 --- a/os/net/mac/tsch/tsch-queue.c +++ b/os/net/mac/tsch/tsch-queue.c @@ -173,6 +173,8 @@ tsch_queue_update_time_source(const linkaddr_t *new_addr) old_time_src->is_time_source = 0; } + tsch_stats_reset_neighbor_stats(); + #ifdef TSCH_CALLBACK_NEW_TIME_SOURCE TSCH_CALLBACK_NEW_TIME_SOURCE(old_time_src, new_time_src); #endif diff --git a/os/net/mac/tsch/tsch-slot-operation.c b/os/net/mac/tsch/tsch-slot-operation.c index 917d13816..843b79f42 100644 --- a/os/net/mac/tsch/tsch-slot-operation.c +++ b/os/net/mac/tsch/tsch-slot-operation.c @@ -625,6 +625,7 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t)) "!truncated dr %d %d", (int)eack_time_correction, (int)drift_correction); ); } + tsch_stats_on_time_synchronization(eack_time_correction); is_drift_correction_used = 1; tsch_timesync_update(current_neighbor, since_last_timesync, drift_correction); /* Keep track of sync time */ @@ -666,6 +667,11 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t)) ringbufindex_put(&dequeued_ringbuf); } + /* If this is an unicast packet to timesource, update stats */ + if(current_neighbor != NULL && current_neighbor->is_time_source) { + tsch_stats_tx_packet(current_neighbor, mac_tx_status, tsch_current_channel); + } + /* Log every tx attempt */ TSCH_LOG_ADD(tsch_log_tx, log->tx.mac_tx_status = mac_tx_status; @@ -764,6 +770,7 @@ PT_THREAD(tsch_rx_slot(struct pt *pt, struct rtimer *t)) static int header_len; static frame802154_t frame; radio_value_t radio_last_rssi; + radio_value_t radio_last_lqi; /* Read packet */ current_input->len = NETSTACK_RADIO.read((void *)current_input->payload, TSCH_PACKET_MAX_LEN); @@ -821,6 +828,7 @@ PT_THREAD(tsch_rx_slot(struct pt *pt, struct rtimer *t)) int do_nack = 0; rx_count++; estimated_drift = RTIMER_CLOCK_DIFF(expected_rx_time, rx_start_time); + tsch_stats_on_time_synchronization(estimated_drift); #if TSCH_TIMESYNC_REMOVE_JITTER /* remove jitter due to measurement errors */ @@ -889,6 +897,12 @@ PT_THREAD(tsch_rx_slot(struct pt *pt, struct rtimer *t)) /* Add current input to ringbuf */ ringbufindex_put(&input_ringbuf); + /* If the neighbor is known, update its stats */ + if(n != NULL) { + NETSTACK_RADIO.get_value(RADIO_PARAM_LAST_LINK_QUALITY, &radio_last_lqi); + tsch_stats_rx_packet(n, current_input->rssi, radio_last_lqi, tsch_current_channel); + } + /* Log every reception */ TSCH_LOG_ADD(tsch_log_rx, linkaddr_copy(&log->rx.src, (linkaddr_t *)&frame.src_addr); @@ -951,6 +965,8 @@ PT_THREAD(tsch_slot_operation(struct rtimer *t, void *ptr)) int is_active_slot; TSCH_DEBUG_SLOT_START(); tsch_in_slot_operation = 1; + /* Measure on-air noise level while TSCH is idle */ + tsch_stats_sample_rssi(); /* Reset drift correction */ drift_correction = 0; is_drift_correction_used = 0; diff --git a/os/net/mac/tsch/tsch-stats.c b/os/net/mac/tsch/tsch-stats.c new file mode 100644 index 000000000..474728e6d --- /dev/null +++ b/os/net/mac/tsch/tsch-stats.c @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2016-2017, University of Bristol - http://www.bristol.ac.uk + * + * 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 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. + * + */ + +/** + * \file + * Source file for TSCH statistics + * \author + * Atis Elsts + */ + +#include "contiki.h" +#include "net/mac/tsch/tsch.h" +#include "net/netstack.h" +#include "dev/radio.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "TSCH Stats" +#define LOG_LEVEL LOG_LEVEL_MAC + +/*---------------------------------------------------------------------------*/ +#if TSCH_STATS_ON +/*---------------------------------------------------------------------------*/ + +struct tsch_global_stats tsch_stats; +struct tsch_neighbor_stats tsch_neighbor_stats; + +/* Called every TSCH_STATS_DECAY_INTERVAL ticks */ +static struct ctimer periodic_timer; + +static void periodic(void *); + +/*---------------------------------------------------------------------------*/ +void +tsch_stats_init(void) +{ +#if TSCH_STATS_SAMPLE_NOISE_RSSI + int i; + + for(i = 0; i < TSCH_STATS_NUM_CHANNELS; ++i) { + tsch_stats.noise_rssi[i] = TSCH_STATS_DEFAULT_RSSI; + tsch_stats.channel_free_ewma[i] = TSCH_STATS_DEFAULT_CHANNEL_FREE; + } +#endif + + tsch_stats_reset_neighbor_stats(); + + /* Start the periodic processing soonish */ + ctimer_set(&periodic_timer, TSCH_STATS_DECAY_INTERVAL / 10, periodic, NULL); +} +/*---------------------------------------------------------------------------*/ +void +tsch_stats_reset_neighbor_stats(void) +{ + int i; + struct tsch_channel_stats *ch_stats; + + ch_stats = tsch_neighbor_stats.channel_stats; + for(i = 0; i < TSCH_STATS_NUM_CHANNELS; ++i) { + ch_stats[i].rssi = TSCH_STATS_DEFAULT_RSSI; + ch_stats[i].lqi = TSCH_STATS_DEFAULT_LQI; + ch_stats[i].p_tx_success = TSCH_STATS_DEFAULT_P_TX; + } +} +/*---------------------------------------------------------------------------*/ +struct tsch_neighbor_stats * +tsch_stats_get_from_neighbor(struct tsch_neighbor *n) +{ + /* Due to RAM limitations, this module only collects neighbor stats about the time source */ + if(n != NULL && n->is_time_source) { + return &tsch_neighbor_stats; + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +void +tsch_stats_tx_packet(struct tsch_neighbor *n, uint8_t mac_status, uint8_t channel) +{ + struct tsch_neighbor_stats *stats; + + stats = tsch_stats_get_from_neighbor(n); + if(stats != NULL) { + uint8_t index = tsch_stats_channel_to_index(channel); + uint16_t new_tx_value = (mac_status == MAC_TX_OK ? 1 : 0); + new_tx_value *= TSCH_STATS_BINARY_SCALING_FACTOR; + TSCH_STATS_EWMA_UPDATE(stats->channel_stats[index].p_tx_success, new_tx_value); + } +} +/*---------------------------------------------------------------------------*/ +void +tsch_stats_rx_packet(struct tsch_neighbor *n, int8_t rssi, uint8_t lqi, uint8_t channel) +{ + struct tsch_neighbor_stats *stats; + + stats = tsch_stats_get_from_neighbor(n); + if(stats != NULL) { + uint8_t index = tsch_stats_channel_to_index(channel); + + TSCH_STATS_EWMA_UPDATE(stats->channel_stats[index].rssi, + TSCH_STATS_TRANSFORM(rssi, TSCH_STATS_RSSI_SCALING_FACTOR)); + TSCH_STATS_EWMA_UPDATE(stats->channel_stats[index].lqi, + TSCH_STATS_TRANSFORM(lqi, TSCH_STATS_LQI_SCALING_FACTOR)); + } +} +/*---------------------------------------------------------------------------*/ +void +tsch_stats_on_time_synchronization(int32_t sync_error) +{ + /* Update the maximal error so far if the absolute value of the new one is larger */ + tsch_stats.max_sync_error = MAX(tsch_stats.max_sync_error, ABS(sync_error)); +} +/*---------------------------------------------------------------------------*/ +void +tsch_stats_sample_rssi(void) +{ +#if TSCH_STATS_SAMPLE_NOISE_RSSI + uint8_t index; + radio_value_t value; + radio_result_t rv; + + static uint8_t measurement_channel = TSCH_STATS_FIRST_CHANNEL; + + index = tsch_stats_channel_to_index(measurement_channel); + + /* Select the measurement channel */ + NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, measurement_channel); + + /* Need to explicitly turn on for Coojamotes */ + NETSTACK_RADIO.on(); + + /* Measure the background noise RSSI and act on it */ + rv = NETSTACK_RADIO.get_value(RADIO_PARAM_RSSI, &value); + if(rv == RADIO_RESULT_OK) { + tsch_stat_t prev_busyness_metric; + uint16_t is_free; + + is_free = (((int)value <= TSCH_STATS_BUSY_CHANNEL_RSSI) ? 1 : 0) * TSCH_STATS_BINARY_SCALING_FACTOR; + + /* LOG_DBG("noise RSSI on %u: %d\n", measurement_channel, (int)value); */ + + TSCH_STATS_EWMA_UPDATE(tsch_stats.noise_rssi[index], + TSCH_STATS_TRANSFORM((int)value, TSCH_STATS_RSSI_SCALING_FACTOR)); + + prev_busyness_metric = tsch_stats.channel_free_ewma[index]; + (void)prev_busyness_metric; + TSCH_STATS_EWMA_UPDATE(tsch_stats.channel_free_ewma[index], is_free); + + /* potentially select a new TSCH hopping sequence */ +#ifdef TSCH_CALLBACK_CHANNEL_STATS_UPDATED + TSCH_CALLBACK_CHANNEL_STATS_UPDATED(measurement_channel, prev_busyness_metric); +#endif + } else { + LOG_ERR("! sampling RSSI failed: %d\n", (int)rv); + } + + /* Increment the channel index for the next time */ + measurement_channel++; + if(measurement_channel >= TSCH_STATS_FIRST_CHANNEL + TSCH_STATS_NUM_CHANNELS) { + measurement_channel = TSCH_STATS_FIRST_CHANNEL; + } +#endif /* TSCH_STATS_SAMPLE_NOISE_RSSI */ +} +/*---------------------------------------------------------------------------*/ +/* Periodic timer called every TSCH_STATS_DECAY_INTERVAL ticks */ +static void +periodic(void *ptr) +{ + int i; + struct tsch_neighbor *timesource; + struct tsch_channel_stats *stats = tsch_neighbor_stats.channel_stats; + +#if TSCH_STATS_SAMPLE_NOISE_RSSI + LOG_DBG("Noise RSSI:\n"); + for(i = 0; i < TSCH_STATS_NUM_CHANNELS; ++i) { + LOG_DBG(" channel %u: %d rssi, %u/%u free\n", + TSCH_STATS_FIRST_CHANNEL + i, + tsch_stats.noise_rssi[i] / TSCH_STATS_RSSI_SCALING_FACTOR, + tsch_stats.channel_free_ewma[i], + TSCH_STATS_BINARY_SCALING_FACTOR); + } +#endif + + timesource = tsch_queue_get_time_source(); + if(timesource != NULL) { + LOG_DBG("Time source neighbor:\n"); + + for(i = 0; i < TSCH_STATS_NUM_CHANNELS; ++i) { + LOG_DBG(" channel %u: %d rssi, %u lqi, %u/%u P(tx)\n", + TSCH_STATS_FIRST_CHANNEL + i, + stats[i].rssi / TSCH_STATS_RSSI_SCALING_FACTOR, + stats[i].lqi / TSCH_STATS_LQI_SCALING_FACTOR, + stats[i].p_tx_success, + TSCH_STATS_BINARY_SCALING_FACTOR); + } + } + + /* Do not decay the periodic global stats, as they are updated independely of packet rate */ + for(i = 0; i < TSCH_STATS_NUM_CHANNELS; ++i) { + /* decay Rx stats */ + TSCH_STATS_EWMA_UPDATE(stats[i].rssi, TSCH_STATS_DEFAULT_RSSI); + TSCH_STATS_EWMA_UPDATE(stats[i].lqi, TSCH_STATS_DEFAULT_LQI); + /* decay Tx stats */ + TSCH_STATS_EWMA_UPDATE(stats[i].p_tx_success, TSCH_STATS_DEFAULT_P_TX); + } + + ctimer_set(&periodic_timer, TSCH_STATS_DECAY_INTERVAL, periodic, NULL); +} +/*---------------------------------------------------------------------------*/ +#endif /* TSCH_STATS_ON */ +/*---------------------------------------------------------------------------*/ diff --git a/os/net/mac/tsch/tsch-stats.h b/os/net/mac/tsch/tsch-stats.h new file mode 100644 index 000000000..794cf1df1 --- /dev/null +++ b/os/net/mac/tsch/tsch-stats.h @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2016-2017, University of Bristol - http://www.bristol.ac.uk + * + * 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 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. + * + */ + +/** + * \file + * Header file for TSCH statistics + * \author + * Atis Elsts + */ + +/** + * \addtogroup tsch + * @{ +*/ + +#ifndef __TSCH_STATS_H__ +#define __TSCH_STATS_H__ + +/********** Includes **********/ + +#include "contiki.h" +#include "net/linkaddr.h" +#include "net/mac/tsch/tsch-conf.h" +#include "net/mac/tsch/tsch-queue.h" + +/************ Constants ***********/ + +/* Enable the collection of TSCH statistics? */ +#ifdef TSCH_STATS_CONF_ON +#define TSCH_STATS_ON TSCH_STATS_CONF_ON +#else +#define TSCH_STATS_ON 0 +#endif + +/* Enable the collection background noise RSSI? */ +#ifdef TSCH_STATS_CONF_SAMPLE_NOISE_RSSI +#define TSCH_STATS_SAMPLE_NOISE_RSSI TSCH_STATS_CONF_SAMPLE_NOISE_RSSI +#else +#define TSCH_STATS_SAMPLE_NOISE_RSSI 0 +#endif + +/* + * How to update a TSCH statistic. + * Uses a hardcoded EWMA alpha value equal to 0.125 by default. + */ +#ifdef TSCH_STATS_CONF_EWMA_UPDATE +#define TSCH_STATS_EWMA_UPDATE TSCH_STATS_CONF_EWMA_UPDATE +#else +#define TSCH_STATS_EWMA_UPDATE(x, v) (x) = (((x) * 7 / 8) + (v) / 8) +#endif + +/* + * A channel is considered busy if at the sampling instant + * it has RSSI higher or equal to this limit. + */ +#ifdef TSCH_STATS_CONF_BUSY_CHANNEL_RSSI +#define TSCH_STATS_BUSY_CHANNEL_RSSI TSCH_STATS_CONF_BUSY_CHANNEL_RSSI +#else +#define TSCH_STATS_BUSY_CHANNEL_RSSI -85 +#endif + +/* The period after which stat values are decayed towards the default values */ +#ifdef TSCH_STATS_CONF_DECAY_INTERVAL +#define TSCH_STATS_DECAY_INTERVAL TSCH_STATS_CONF_DECAY_INTERVAL +#else +#define TSCH_STATS_DECAY_INTERVAL (20ul * 60 * CLOCK_SECOND) +#endif + +/* + * The total number of MAC-layer channels. + * Sixteen for the IEEE802.15.4 2.4 GHz band. + */ +#ifdef TSCH_STATS_CONF_NUM_CHANNELS +#define TSCH_STATS_NUM_CHANNELS TSCH_STATS_CONF_NUM_CHANNELS +#else +#define TSCH_STATS_NUM_CHANNELS 16 +#endif + +/* The number of the first MAC-layer channel. */ +#ifdef TSCH_STATS_CONF_FIRST_CHANNEL +#define TSCH_STATS_FIRST_CHANNEL TSCH_STATS_CONF_FIRST_CHANNEL +#else +#define TSCH_STATS_FIRST_CHANNEL 11 +#endif + +/* Internal: the scaling of the various stats */ +#define TSCH_STATS_RSSI_SCALING_FACTOR -16 +#define TSCH_STATS_LQI_SCALING_FACTOR 16 +#define TSCH_STATS_BINARY_SCALING_FACTOR 4096 + +/* + * Transform a statistic from external form to the internal representation. + * To transform back, simply divide by the factor. + */ +#define TSCH_STATS_TRANSFORM(x, factor) ((int16_t)(x) * factor) + +/* The default value for RSSI statistics: -90 dBm */ +#define TSCH_STATS_DEFAULT_RSSI TSCH_STATS_TRANSFORM(-90, TSCH_STATS_RSSI_SCALING_FACTOR) +/* The default value for LQI statistics: 100 */ +#define TSCH_STATS_DEFAULT_LQI TSCH_STATS_TRANSFORM(100, TSCH_STATS_LQI_SCALING_FACTOR) +/* The default value for P_tx (packet transmission probability) statistics: 50% */ +#define TSCH_STATS_DEFAULT_P_TX (TSCH_STATS_BINARY_SCALING_FACTOR / 2) +/* The default value for channel free status: 100% */ +#define TSCH_STATS_DEFAULT_CHANNEL_FREE TSCH_STATS_BINARY_SCALING_FACTOR + +/* #define these callbacks to do the adaptive channel selection based on RSSI */ +/* TSCH_CALLBACK_CHANNEL_STATS_UPDATED(channel, previous_metric); */ +/* TSCH_CALLBACK_SELECT_CHANNELS(); */ + + +/************ Types ***********/ + +typedef uint16_t tsch_stat_t; + +struct tsch_global_stats { + /* the maximum synchronization error */ + uint32_t max_sync_error; + /* number of disassociations */ + uint16_t num_disassociations; +#if TSCH_STATS_SAMPLE_NOISE_RSSI + /* per-channel noise estimates */ + tsch_stat_t noise_rssi[TSCH_STATS_NUM_CHANNELS]; + /* derived from `noise_rssi` and BUSY_CHANNEL_RSSI */ + tsch_stat_t channel_free_ewma[TSCH_STATS_NUM_CHANNELS]; +#endif /* TSCH_STATS_SAMPLE_NOISE_RSSI */ +}; + +struct tsch_channel_stats { + /* EWMA, from receptions */ + tsch_stat_t rssi; + /* EWMA, from receptions */ + tsch_stat_t lqi; + /* EWMA of probability, for unicast transmissions only */ + tsch_stat_t p_tx_success; +}; + +struct tsch_neighbor_stats { + struct tsch_channel_stats channel_stats[TSCH_STATS_NUM_CHANNELS]; +}; + +struct tsch_neighbor; /* Forward declaration */ + + +/************ External variables ***********/ + +#if TSCH_STATS_ON + +/* Statistics for the local node */ +extern struct tsch_global_stats tsch_stats; + +/* For the timesource neighbor */ +extern struct tsch_neighbor_stats tsch_neighbor_stats; + + +/************ Functions ***********/ + +void tsch_stats_init(void); + +void tsch_stats_tx_packet(struct tsch_neighbor *, uint8_t mac_status, uint8_t channel); + +void tsch_stats_rx_packet(struct tsch_neighbor *, int8_t rssi, uint8_t lqi, uint8_t channel); + +void tsch_stats_on_time_synchronization(int32_t sync_error); + +void tsch_stats_sample_rssi(void); + +struct tsch_neighbor_stats *tsch_stats_get_from_neighbor(struct tsch_neighbor *); + +void tsch_stats_reset_neighbor_stats(void); + +#else /* TSCH_STATS_ON */ + +#define tsch_stats_init() +#define tsch_stats_tx_packet(n, mac_status, channel) +#define tsch_stats_rx_packet(n, rssi, lqi, channel) +#define tsch_stats_on_time_synchronization(sync_error) +#define tsch_stats_sample_rssi() +#define tsch_stats_get_from_neighbor(neighbor) NULL +#define tsch_stats_reset_neighbor_stats() + +#endif /* TSCH_STATS_ON */ + +static inline uint8_t +tsch_stats_channel_to_index(uint8_t channel) +{ + return channel - TSCH_STATS_FIRST_CHANNEL; +} + +static inline uint8_t +tsch_stats_index_to_channel(uint8_t channel_index) +{ + return channel_index + TSCH_STATS_FIRST_CHANNEL; +} + + +#endif /* __TSCH_STATS_H__ */ +/** @} */ diff --git a/os/net/mac/tsch/tsch.c b/os/net/mac/tsch/tsch.c index 45df20e6f..e67e11c7c 100644 --- a/os/net/mac/tsch/tsch.c +++ b/os/net/mac/tsch/tsch.c @@ -864,6 +864,9 @@ PROCESS_THREAD(tsch_pending_events_process, ev, data) tsch_rx_process_pending(); tsch_tx_process_pending(); tsch_log_process_pending(); +#ifdef TSCH_CALLBACK_SELECT_CHANNELS + TSCH_CALLBACK_SELECT_CHANNELS(); +#endif } PROCESS_END(); } @@ -944,6 +947,8 @@ tsch_init(void) #if TSCH_WITH_SIXTOP sixtop_init(); #endif + + tsch_stats_init(); } /*---------------------------------------------------------------------------*/ /* Function send for TSCH-MAC, puts the packet in packetbuf in the MAC queue */ diff --git a/os/net/mac/tsch/tsch.h b/os/net/mac/tsch/tsch.h index 88ebb4db6..273f979e4 100644 --- a/os/net/mac/tsch/tsch.h +++ b/os/net/mac/tsch/tsch.h @@ -60,6 +60,7 @@ frequency hopping for enhanced reliability. #include "net/mac/tsch/tsch-packet.h" #include "net/mac/tsch/tsch-security.h" #include "net/mac/tsch/tsch-schedule.h" +#include "net/mac/tsch/tsch-stats.h" #if UIP_CONF_IPV6_RPL #include "net/mac/tsch/tsch-rpl.h" #endif /* UIP_CONF_IPV6_RPL */ From bc9967dbb05371d853ecc2ce657ae47d44a733b8 Mon Sep 17 00:00:00 2001 From: Atis Elsts Date: Tue, 28 Nov 2017 14:58:42 +0000 Subject: [PATCH 369/485] add TSCH channel selection service --- os/contiki-main.c | 6 + os/net/mac/tsch/tsch.c | 16 ++ os/services/tsch-cs/Makefile | 1 + os/services/tsch-cs/tsch-cs.c | 328 ++++++++++++++++++++++++++++++++++ os/services/tsch-cs/tsch-cs.h | 76 ++++++++ 5 files changed, 427 insertions(+) create mode 100644 os/services/tsch-cs/Makefile create mode 100644 os/services/tsch-cs/tsch-cs.c create mode 100644 os/services/tsch-cs/tsch-cs.h diff --git a/os/contiki-main.c b/os/contiki-main.c index c756cf206..db8893717 100644 --- a/os/contiki-main.c +++ b/os/contiki-main.c @@ -53,6 +53,7 @@ #include "services/orchestra/orchestra.h" #include "services/shell/serial-shell.h" #include "services/simple-energest/simple-energest.h" +#include "services/tsch-cs/tsch-cs.h" #include #include @@ -146,6 +147,11 @@ main(void) simple_energest_init(); #endif /* BUILD_WITH_SIMPLE_ENERGEST */ +#if BUILD_WITH_TSCH_CS + /* Initialize the channel selection module */ + tsch_cs_adaptations_init(); +#endif /* BUILD_WITH_TSCH_CS */ + autostart_start(autostart_processes); watchdog_start(); diff --git a/os/net/mac/tsch/tsch.c b/os/net/mac/tsch/tsch.c index e67e11c7c..c040826ca 100644 --- a/os/net/mac/tsch/tsch.c +++ b/os/net/mac/tsch/tsch.c @@ -412,6 +412,22 @@ eb_input(struct input_packet *current_input) } #endif /* TSCH_AUTOSELECT_TIME_SOURCE */ } + + /* TSCH hopping sequence */ + if(eb_ies.ie_channel_hopping_sequence_id != 0) { + if(eb_ies.ie_hopping_sequence_len != tsch_hopping_sequence_length.val + || memcmp((uint8_t *)tsch_hopping_sequence, eb_ies.ie_hopping_sequence_list, tsch_hopping_sequence_length.val)) { + if(eb_ies.ie_hopping_sequence_len <= sizeof(tsch_hopping_sequence)) { + memcpy((uint8_t *)tsch_hopping_sequence, eb_ies.ie_hopping_sequence_list, + eb_ies.ie_hopping_sequence_len); + TSCH_ASN_DIVISOR_INIT(tsch_hopping_sequence_length, eb_ies.ie_hopping_sequence_len); + + LOG_WARN("Updating TSCH hopping sequence from EB\n"); + } else { + LOG_WARN("TSCH:! parse_eb: hopping sequence too long (%u)\n", eb_ies.ie_hopping_sequence_len); + } + } + } } } } diff --git a/os/services/tsch-cs/Makefile b/os/services/tsch-cs/Makefile new file mode 100644 index 000000000..23e2acb3d --- /dev/null +++ b/os/services/tsch-cs/Makefile @@ -0,0 +1 @@ +CFLAGS += -DBUILD_WITH_TSCH_CS=1 diff --git a/os/services/tsch-cs/tsch-cs.c b/os/services/tsch-cs/tsch-cs.c new file mode 100644 index 000000000..801f74b77 --- /dev/null +++ b/os/services/tsch-cs/tsch-cs.c @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2016-2018, University of Bristol - http://www.bristol.ac.uk + * + * 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 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. + * + */ + +/** + * \file + * Source file for TSCH adaptive channel selection + * \author + * Atis Elsts + */ + +#include "tsch.h" +#include "tsch-stats.h" +#include "tsch-cs.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "TSCH CS" +#define LOG_LEVEL LOG_LEVEL_MAC + +/*---------------------------------------------------------------------------*/ + +/* Allow to change only 1 channel at once */ +#define TSCH_CS_MAX_CHANNELS_CHANGED 1 + +/* Do not up change channels more frequently than this */ +#define TSCH_CS_MIN_UPDATE_INTERVAL_SEC 60 + +/* Do not change channels if the difference in qualities is below this */ +#define TSCH_CS_HYSTERESIS (TSCH_STATS_BINARY_SCALING_FACTOR / 10) + +/* After removing a channel from the sequence, do not add it back at least this time */ +#define TSCH_CS_BLACKLIST_DURATION_SEC (5 * 60) + +/* A potential for change detected? */ +static bool recaculation_requested; + +/* Time (in seconds) when channels were marked as busy; 0 if they are not busy */ +static uint32_t tsch_cs_busy_since[TSCH_STATS_NUM_CHANNELS]; + +/* + * The following variables are kept in order to avoid completely migrating away + * from the initial hopping sequence (as then new nodes would not be able to join). + * The invariant is: tsch_cs_initial_bitmap & tsch_cs_current_bitmap != 0 + */ +/* The bitmap with the initial channels */ +static tsch_cs_bitmap_t tsch_cs_initial_bitmap; +/* The bitmap with the current channels */ +static tsch_cs_bitmap_t tsch_cs_current_bitmap; + +/* structure for sorting */ +struct tsch_cs_quality { + /* channel number */ + uint8_t channel; + /* the higher, the better */ + tsch_stat_t metric; +}; +/*---------------------------------------------------------------------------*/ +static inline bool +tsch_cs_bitmap_contains(tsch_cs_bitmap_t bitmap, uint8_t channel) +{ + return (1 << (channel - TSCH_STATS_FIRST_CHANNEL)) & bitmap; +} +/*---------------------------------------------------------------------------*/ +static inline tsch_cs_bitmap_t +tsch_cs_bitmap_set(tsch_cs_bitmap_t bitmap, uint8_t channel) +{ + return (1 << (channel - TSCH_STATS_FIRST_CHANNEL)) | bitmap; +} +/*---------------------------------------------------------------------------*/ +static tsch_cs_bitmap_t +tsch_cs_bitmap_calc(void) +{ + tsch_cs_bitmap_t result = 0; + int i; + for(i = 0; i < tsch_hopping_sequence_length.val; ++i) { + result = tsch_cs_bitmap_set(result, tsch_hopping_sequence[i]); + } + return result; +} +/*---------------------------------------------------------------------------*/ +void +tsch_cs_adaptations_init(void) +{ + tsch_cs_initial_bitmap = tsch_cs_bitmap_calc(); + tsch_cs_current_bitmap = tsch_cs_initial_bitmap; +} +/*---------------------------------------------------------------------------*/ +/* Sort the elements to that the channels with the best metrics are in the front */ +static void +tsch_cs_bubble_sort(struct tsch_cs_quality *qualities) +{ + int i, j; + struct tsch_cs_quality tmp; + + for(i = 0; i < TSCH_STATS_NUM_CHANNELS; ++i) { + for(j = 0; j + 1 < TSCH_STATS_NUM_CHANNELS; ++j) { + if(qualities[j].metric < qualities[j+1].metric){ + tmp = qualities[j]; + qualities[j] = qualities[j+1]; + qualities[j+1] = tmp; + } + } + } +} +/*---------------------------------------------------------------------------*/ +/* Select a single, currently unused, good enough channel. Returns 0xff on failure. */ +static uint8_t +tsch_cs_select_replacement(uint8_t old_channel, tsch_stat_t old_ewma, + struct tsch_cs_quality *qualities, uint8_t is_in_sequence[]) +{ + int i; + uint32_t now = clock_seconds(); + tsch_cs_bitmap_t bitmap = tsch_cs_bitmap_set(0, old_channel); + + /* Don't want to replace a channel if the improvement is miniscule (< 10%) */ + old_ewma += TSCH_CS_HYSTERESIS; + + /* iterate up to -1 because we know that at least one of the channels is bad */ + for(i = 0; i < TSCH_STATS_NUM_CHANNELS - 1; ++i) { + /* select a replacement candidate */ + uint8_t candidate = qualities[i].channel; + + if(qualities[i].metric < TSCH_CS_FREE_THRESHOLD) { + /* This channel is not good enough. + * since we know that the other channels in the sorted list are even worse, + * it makes sense to return immediately rather than to continue t + */ + LOG_DBG("ch %u: busy\n", candidate); + return 0xff; + } + + if(qualities[i].metric < old_ewma) { + /* not good enough to replace */ + LOG_DBG("ch %u: hysteresis check failed\n", candidate); + return 0xff; + } + + /* already in the current TSCH hopping sequence? */ + if(is_in_sequence[candidate - TSCH_STATS_FIRST_CHANNEL] != 0xff) { + LOG_DBG("ch %u: in seq\n", candidate); + continue; + } + + /* ignore this candidate if too recently blacklisted */ + if(tsch_cs_busy_since[candidate - TSCH_STATS_FIRST_CHANNEL] != 0 + && tsch_cs_busy_since[candidate - TSCH_STATS_FIRST_CHANNEL] + TSCH_CS_BLACKLIST_DURATION_SEC > now) { + LOG_DBG("ch %u: recent bl\n", candidate); + continue; + } + + /* check if removing the old channel would break our hopping sequence invariant */ + if(bitmap == (tsch_cs_initial_bitmap & tsch_cs_current_bitmap)) { + /* the channel is the only one that belongs to both */ + if(!tsch_cs_bitmap_contains(tsch_cs_initial_bitmap, candidate)) { + /* the candidate is not in the initial sequence; not acceptable */ + continue; + } + } + + return candidate; + } + + return 0xff; +} +/*---------------------------------------------------------------------------*/ +bool +tsch_cs_process(void) +{ + int i; + bool try_replace; + bool has_replaced; + struct tsch_cs_quality qualities[TSCH_STATS_NUM_CHANNELS]; + uint8_t is_channel_busy[TSCH_STATS_NUM_CHANNELS]; + uint8_t is_in_sequence[TSCH_STATS_NUM_CHANNELS]; + static uint32_t last_time_changed; + + if(!recaculation_requested) { + /* nothing to do */ + return false; + } + + if(last_time_changed != 0 && last_time_changed + TSCH_CS_MIN_UPDATE_INTERVAL_SEC > clock_seconds()) { + /* too soon */ + return false; + } + + /* reset the flag */ + recaculation_requested = false; + + for(i = 0; i < TSCH_STATS_NUM_CHANNELS; ++i) { + qualities[i].channel = i + TSCH_STATS_FIRST_CHANNEL; + qualities[i].metric = tsch_stats.channel_free_ewma[i]; + } + + /* bubble sort the channels */ + tsch_cs_bubble_sort(qualities); + + /* start with the threshold values */ + for(i = 0; i < TSCH_STATS_NUM_CHANNELS; ++i) { + is_channel_busy[i] = (tsch_stats.channel_free_ewma[i] < TSCH_CS_FREE_THRESHOLD); + } + memset(is_in_sequence, 0xff, sizeof(is_in_sequence)); + for(i = 0; i < tsch_hopping_sequence_length.val; ++i) { + uint8_t channel = tsch_hopping_sequence[i]; + is_in_sequence[channel - TSCH_STATS_FIRST_CHANNEL] = i; + } + + /* mark the first N channels as "good" - there is nothing better to select */ + for(i = 0; i < tsch_hopping_sequence_length.val; ++i) { + is_channel_busy[qualities[i].channel - TSCH_STATS_FIRST_CHANNEL] = 0; + } + + for(i = 0; i < TSCH_STATS_NUM_CHANNELS; ++i) { + uint8_t ci = qualities[i].channel - TSCH_STATS_FIRST_CHANNEL; + (void)ci; + LOG_DBG("ch %u q %u busy %u in seq %u\n", + qualities[i].channel, + qualities[i].metric, + is_channel_busy[ci], + is_in_sequence[ci] == 0xff ? 0 : 1); + } + + try_replace = false; + for(i = 0; i < tsch_hopping_sequence_length.val; ++i) { + uint8_t channel = tsch_hopping_sequence[i]; + if(is_channel_busy[channel - TSCH_STATS_FIRST_CHANNEL]) { + try_replace = true; + } + } + if(!try_replace) { + LOG_DBG("cs: not replacing\n"); + return false; + } + + has_replaced = false; + for(i = TSCH_STATS_NUM_CHANNELS - 1; i >= tsch_hopping_sequence_length.val; --i) { + if(is_in_sequence[qualities[i].channel - TSCH_STATS_FIRST_CHANNEL] != 0xff) { + /* found the worst channel; it must be busy */ + uint8_t channel = qualities[i].channel; + tsch_stat_t ewma_metric = qualities[i].metric; + uint8_t replacement = tsch_cs_select_replacement(channel, ewma_metric, + qualities, is_in_sequence); + uint8_t position = is_in_sequence[channel - TSCH_STATS_FIRST_CHANNEL]; + + if(replacement != 0xff) { + printf("\ncs: replacing channel %u %u (%u) with %u\n", + channel, tsch_hopping_sequence[position], position, replacement); + /* mark the old channel as busy */ + tsch_cs_busy_since[channel - TSCH_STATS_FIRST_CHANNEL] = clock_seconds(); + /* do the actual replacement in the global TSCH HS variable */ + tsch_hopping_sequence[position] = replacement; + has_replaced = true; + /* recalculate the hopping sequence bitmap */ + tsch_cs_current_bitmap = tsch_cs_bitmap_calc(); + } + break; /* replace just one at once */ + } + } + + if(has_replaced) { + last_time_changed = clock_seconds(); + return true; + } + + LOG_DBG("cs: no changes\n"); + return false; +} +/*---------------------------------------------------------------------------*/ +void +tsch_cs_channel_stats_updated(uint8_t updated_channel, uint16_t old_busyness_metric) +{ + uint8_t index; + bool old_is_busy; + bool new_is_busy; + + /* Enable this only on the coordinator node */ + if(!tsch_is_coordinator) { + return; + } + + /* Do not try to adapt before enough information has been learned */ + if(clock_seconds() < TSCH_CS_LEARNING_PERIOD_SEC) { + return; + } + + index = tsch_stats_channel_to_index(updated_channel); + + old_is_busy = (old_busyness_metric < TSCH_CS_FREE_THRESHOLD); + new_is_busy = (tsch_stats.channel_free_ewma[index] < TSCH_CS_FREE_THRESHOLD); + + if(old_is_busy != new_is_busy) { + /* the status of the channel has changed*/ + recaculation_requested = true; + + } else if(new_is_busy) { + /* run the reselection algorithm iff the channel is both (1) bad and (2) in use */ + if(tsch_cs_bitmap_contains(tsch_cs_current_bitmap, updated_channel)) { + /* the channel is in use and is busy */ + recaculation_requested = true; + } + } +} diff --git a/os/services/tsch-cs/tsch-cs.h b/os/services/tsch-cs/tsch-cs.h new file mode 100644 index 000000000..900e77339 --- /dev/null +++ b/os/services/tsch-cs/tsch-cs.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2016-2018, University of Bristol - http://www.bristol.ac.uk + * + * 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 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. + * + */ + +/** + * \file + * Header file for TSCH adaptive channel selection + * \author + * Atis Elsts + */ + +#ifndef __TSCH_CS_H__ +#define __TSCH_CS_H__ + +#include "contiki.h" +#include + +/* If `channel_free_ewma` value is less than this, the channel is considered busy */ +#ifdef TSCH_CS_CONF_FREE_THRESHOLD +#define TSCH_CS_FREE_THRESHOLD TSCH_CS_CONF_FREE_THRESHOLD +#else +/* < 85% free */ +#define TSCH_CS_FREE_THRESHOLD ((tsch_stat_t)(85ul * TSCH_STATS_BINARY_SCALING_FACTOR / 100)) +#endif + +#define TSCH_CS_LEARNING_PERIOD_SEC 30 + +/** + * \brief Initializes the TSCH hopping sequence selection module. + */ +void tsch_cs_adaptations_init(void); + +/** + * \brief Signal the need to potentially update the TSCH hopping sequence. + * \param updated_channel The channel with the updated RSSI measurement + * \param old_busyness_metric The EWMA value of the "channel busy" status before the last RSSI measurement + */ +void tsch_cs_channel_stats_updated(uint8_t updated_channel, uint16_t old_busyness_metric); + +/** + * \brief Potentially update the TSCH hopping sequence + * \return true if the hopping sequence was updated, false otherwise + */ +bool tsch_cs_process(void); + + +/* A bit corresponds to a channel; `uint16_t` value is OK for up to 16 channels. */ +typedef uint16_t tsch_cs_bitmap_t; + + +#endif /* __TSCH_CS_H__ */ From df733e409a6bf419fedf8a87cb9d52c31dae691a Mon Sep 17 00:00:00 2001 From: Atis Elsts Date: Tue, 28 Nov 2017 14:59:41 +0000 Subject: [PATCH 370/485] add TSCH channel selection example --- .../6tisch/channel-selection-demo/Makefile | 34 ++++++ .../6tisch/channel-selection-demo/README.md | 8 ++ examples/6tisch/channel-selection-demo/node.c | 94 +++++++++++++++ .../channel-selection-demo/project-conf.h | 109 ++++++++++++++++++ 4 files changed, 245 insertions(+) create mode 100644 examples/6tisch/channel-selection-demo/Makefile create mode 100644 examples/6tisch/channel-selection-demo/README.md create mode 100644 examples/6tisch/channel-selection-demo/node.c create mode 100644 examples/6tisch/channel-selection-demo/project-conf.h diff --git a/examples/6tisch/channel-selection-demo/Makefile b/examples/6tisch/channel-selection-demo/Makefile new file mode 100644 index 000000000..a44c76f10 --- /dev/null +++ b/examples/6tisch/channel-selection-demo/Makefile @@ -0,0 +1,34 @@ +CONTIKI_PROJECT = node +all: $(CONTIKI_PROJECT) + +CONTIKI=../../.. + +PLATFORMS_EXCLUDE = sky nrf52dk native +BOARDS_EXCLUDE = srf06/cc13xx launchpad/cc1310 launchpad/cc1350 sensortag/cc2650 sensortag/cc1350 + +# The channel selection library +MODULES += os/services/tsch-cs + +# force Orchestra from command line +MAKE_WITH_ORCHESTRA ?= 0 +# force Security from command line +MAKE_WITH_SECURITY ?= 0 +# print #routes periodically, used for regression tests +MAKE_WITH_PERIODIC_ROUTES_PRINT ?= 0 + +MAKE_MAC = MAKE_MAC_TSCH +MODULES += os/services/shell + +ifeq ($(MAKE_WITH_ORCHESTRA),1) +MODULES += os/services/orchestra +endif + +ifeq ($(MAKE_WITH_SECURITY),1) +CFLAGS += -DWITH_SECURITY=1 +endif + +ifeq ($(MAKE_WITH_PERIODIC_ROUTES_PRINT),1) +CFLAGS += -DWITH_PERIODIC_ROUTES_PRINT=1 +endif + +include $(CONTIKI)/Makefile.include diff --git a/examples/6tisch/channel-selection-demo/README.md b/examples/6tisch/channel-selection-demo/README.md new file mode 100644 index 000000000..b6415ab9b --- /dev/null +++ b/examples/6tisch/channel-selection-demo/README.md @@ -0,0 +1,8 @@ +Demonstration of TSCH adaptive channel selection based on background noise RSSI metric. +TSCH stats must be enabled for the adaptive selection functionality to compile and work. + +This code relies on the `os/services/channel-selection` library that implements +the "RSSI upstream" adaptative channel selection strategy, described in the following paper: + +A. Elsts, X. Fafoutis, G. Oikonomou and R. Piechocki. Adaptive Channel Selection in IEEE 802.15.4 TSCH Networks, 1st Global Internet of Things Summit, 2017. +http://ieeexplore.ieee.org/document/8016246/ \ No newline at end of file diff --git a/examples/6tisch/channel-selection-demo/node.c b/examples/6tisch/channel-selection-demo/node.c new file mode 100644 index 000000000..86dca79d8 --- /dev/null +++ b/examples/6tisch/channel-selection-demo/node.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2015, SICS Swedish ICT. + * 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 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. + * + */ +/** + * \file + * A RPL+TSCH node. + * + * \author Simon Duquennoy + * Atis Elsts + */ + +#include "contiki.h" +#include "sys/node-id.h" +#include "sys/log.h" +#include "net/ipv6/uip-ds6-route.h" +#include "net/ipv6/uip-sr.h" +#include "net/mac/tsch/tsch.h" +#include "net/routing/routing.h" +#include "tsch-cs.h" + +#define DEBUG DEBUG_PRINT +#include "net/ipv6/uip-debug.h" + +/*---------------------------------------------------------------------------*/ +PROCESS(node_process, "RPL Node"); +AUTOSTART_PROCESSES(&node_process); + +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(node_process, ev, data) +{ + int is_coordinator; + + PROCESS_BEGIN(); + + is_coordinator = 0; + +#if CONTIKI_TARGET_COOJA + is_coordinator = (node_id == 1); +#endif + + if(is_coordinator) { + NETSTACK_ROUTING.root_start(); + } + NETSTACK_MAC.on(); + +#if WITH_PERIODIC_ROUTES_PRINT + { + static struct etimer et; + /* Print out routing tables every minute */ + etimer_set(&et, CLOCK_SECOND * 60); + while(1) { + /* Used for non-regression testing */ + #if (UIP_MAX_ROUTES != 0) + PRINTF("Routing entries: %u\n", uip_ds6_route_num_routes()); + #endif + #if (UIP_SR_LINK_NUM != 0) + PRINTF("Routing links: %u\n", uip_sr_num_nodes()); + #endif + PROCESS_YIELD_UNTIL(etimer_expired(&et)); + etimer_reset(&et); + } + } +#endif /* WITH_PERIODIC_ROUTES_PRINT */ + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/examples/6tisch/channel-selection-demo/project-conf.h b/examples/6tisch/channel-selection-demo/project-conf.h new file mode 100644 index 000000000..dcf326036 --- /dev/null +++ b/examples/6tisch/channel-selection-demo/project-conf.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2015, SICS Swedish ICT. + * Copyright (c) 2017, 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 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. + * + */ + +/** + * \author Simon Duquennoy + * Atis Elsts + */ + +#ifndef __PROJECT_CONF_H__ +#define __PROJECT_CONF_H__ + +#include +#include + +/* Set to enable TSCH security */ +#ifndef WITH_SECURITY +#define WITH_SECURITY 0 +#endif /* WITH_SECURITY */ + +/* USB serial takes space, free more space elsewhere */ +#define SICSLOWPAN_CONF_FRAG 0 +#define UIP_CONF_BUFFER_SIZE 160 + +/*******************************************************/ +/******************* Configure TSCH ********************/ +/*******************************************************/ + +/* IEEE802.15.4 PANID */ +#define IEEE802154_CONF_PANID 0x81a5 + +/* Do not start TSCH at init, wait for NETSTACK_MAC.on() */ +#define TSCH_CONF_AUTOSTART 0 + +/* 6TiSCH minimal schedule length. + * Larger values result in less frequent active slots: reduces capacity and saves energy. */ +#define TSCH_SCHEDULE_CONF_DEFAULT_LENGTH 3 + +#if WITH_SECURITY + +/* Enable security */ +#define LLSEC802154_CONF_ENABLED 1 + +#endif /* WITH_SECURITY */ + +/* Enable TSCH statistics: must be on for channel selection to work */ +#define TSCH_STATS_CONF_ON 1 + +/* Enable periodic RSSI sampling for TSCH statistics */ +#define TSCH_STATS_CONF_SAMPLE_NOISE_RSSI 1 + +/* Reduce the TSCH stat "decay to normal" period to get printouts more often */ +#define TSCH_STATS_CONF_DECAY_INTERVAL (60 * CLOCK_SECOND) + +/* For adaptive channel selection */ +extern void tsch_cs_channel_stats_updated(uint8_t updated_channel, uint16_t old_busyness_metric); +extern bool tsch_cs_process(void); +/* These will be called from the core TSCH code */ +#define TSCH_CALLBACK_CHANNEL_STATS_UPDATED tsch_cs_channel_stats_updated +#define TSCH_CALLBACK_SELECT_CHANNELS tsch_cs_process + +/* The coordinator will update the network nodes with new hopping sequences */ +#define TSCH_PACKET_CONF_EB_WITH_HOPPING_SEQUENCE 1 + +/* Reduce the EB period in order to update the network nodes with more agility */ +#define TSCH_CONF_EB_PERIOD (4 * CLOCK_SECOND) +#define TSCH_CONF_MAX_EB_PERIOD (4 * CLOCK_SECOND) + +/*******************************************************/ +/************* Other system configuration **************/ +/*******************************************************/ + +/* Logging */ +#define LOG_CONF_LEVEL_RPL LOG_LEVEL_INFO +#define LOG_CONF_LEVEL_TCPIP LOG_LEVEL_WARN +#define LOG_CONF_LEVEL_IPV6 LOG_LEVEL_WARN +#define LOG_CONF_LEVEL_6LOWPAN LOG_LEVEL_WARN +#define LOG_CONF_LEVEL_MAC LOG_LEVEL_DBG +#define LOG_CONF_LEVEL_FRAMER LOG_LEVEL_INFO +#define TSCH_LOG_CONF_PER_SLOT 1 + +#endif /* __PROJECT_CONF_H__ */ From 3ccf4c78bb547e757d914086c009ac9a786726e8 Mon Sep 17 00:00:00 2001 From: Atis Elsts Date: Mon, 27 Nov 2017 17:34:43 +0000 Subject: [PATCH 371/485] Add TSCH stats example --- examples/6tisch/tsch-stats/Makefile | 3 + examples/6tisch/tsch-stats/node.c | 24 +- examples/6tisch/tsch-stats/project-conf.h | 2 +- .../6tisch/tsch-stats/tsch-stats-cooja.csc | 263 ------------------ 4 files changed, 16 insertions(+), 276 deletions(-) delete mode 100644 examples/6tisch/tsch-stats/tsch-stats-cooja.csc diff --git a/examples/6tisch/tsch-stats/Makefile b/examples/6tisch/tsch-stats/Makefile index 20592ebad..0c8863301 100644 --- a/examples/6tisch/tsch-stats/Makefile +++ b/examples/6tisch/tsch-stats/Makefile @@ -3,6 +3,9 @@ all: $(CONTIKI_PROJECT) CONTIKI=../../.. +PLATFORMS_EXCLUDE = sky nrf52dk native +BOARDS_EXCLUDE = srf06/cc13xx launchpad/cc1310 launchpad/cc1350 sensortag/cc2650 sensortag/cc1350 + # force Orchestra from command line MAKE_WITH_ORCHESTRA ?= 0 # force Security from command line diff --git a/examples/6tisch/tsch-stats/node.c b/examples/6tisch/tsch-stats/node.c index b27821c65..92b19306a 100644 --- a/examples/6tisch/tsch-stats/node.c +++ b/examples/6tisch/tsch-stats/node.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2015, SICS Swedish ICT. - * Copyright (c) 2017, University of Bristol - http://www.bristol.ac.uk + * 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 @@ -37,16 +37,12 @@ */ #include "contiki.h" -#include "node-id.h" -#include "rpl.h" -#include "rpl-dag-root.h" +#include "sys/node-id.h" #include "sys/log.h" #include "net/ipv6/uip-ds6-route.h" +#include "net/ipv6/uip-sr.h" #include "net/mac/tsch/tsch.h" -#include "net/mac/tsch/tsch-log.h" -#if UIP_CONF_IPV6_RPL_LITE == 0 -#include "rpl-private.h" -#endif /* UIP_CONF_IPV6_RPL_LITE == 0 */ +#include "net/routing/routing.h" #define DEBUG DEBUG_PRINT #include "net/ipv6/uip-debug.h" @@ -62,10 +58,14 @@ PROCESS_THREAD(node_process, ev, data) PROCESS_BEGIN(); + is_coordinator = 0; + +#if CONTIKI_TARGET_COOJA is_coordinator = (node_id == 1); +#endif if(is_coordinator) { - rpl_dag_root_init_dag_immediately(); + NETSTACK_ROUTING.root_start(); } NETSTACK_MAC.on(); @@ -76,11 +76,11 @@ PROCESS_THREAD(node_process, ev, data) etimer_set(&et, CLOCK_SECOND * 60); while(1) { /* Used for non-regression testing */ - #if RPL_WITH_STORING + #if (UIP_MAX_ROUTES != 0) PRINTF("Routing entries: %u\n", uip_ds6_route_num_routes()); #endif - #if RPL_WITH_NON_STORING - PRINTF("Routing links: %u\n", rpl_ns_num_nodes()); + #if (UIP_SR_LINK_NUM != 0) + PRINTF("Routing links: %u\n", uip_sr_num_nodes()); #endif PROCESS_YIELD_UNTIL(etimer_expired(&et)); etimer_reset(&et); diff --git a/examples/6tisch/tsch-stats/project-conf.h b/examples/6tisch/tsch-stats/project-conf.h index 5a2248dae..f3e80dc99 100644 --- a/examples/6tisch/tsch-stats/project-conf.h +++ b/examples/6tisch/tsch-stats/project-conf.h @@ -73,7 +73,7 @@ /* Enable periodic RSSI sampling for TSCH statistics */ #define TSCH_STATS_CONF_SAMPLE_NOISE_RSSI 1 -/* Reduce the TSCH stat "decay to normal" period */ +/* Reduce the TSCH stat "decay to normal" period to get printouts more often */ #define TSCH_STATS_CONF_DECAY_INTERVAL (60 * CLOCK_SECOND) /*******************************************************/ diff --git a/examples/6tisch/tsch-stats/tsch-stats-cooja.csc b/examples/6tisch/tsch-stats/tsch-stats-cooja.csc deleted file mode 100644 index 76f87e9be..000000000 --- a/examples/6tisch/tsch-stats/tsch-stats-cooja.csc +++ /dev/null @@ -1,263 +0,0 @@ - - - [APPS_DIR]/mrm - [APPS_DIR]/mspsim - [APPS_DIR]/avrora - [APPS_DIR]/serial_socket - [APPS_DIR]/collect-view - [APPS_DIR]/powertracker - - TSCH stats - 123456 - 1000000 - - org.contikios.cooja.radiomediums.UDGM - 50.0 - 100.0 - 1.0 - 0.5 - - - 40000 - - - org.contikios.cooja.contikimote.ContikiMoteType - mtype660 - RPL/TSCH Node - [CONFIG_DIR]/node.c - make TARGET=cooja clean - make TARGET=cooja 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.interfaces.Mote2MoteRelations - org.contikios.cooja.interfaces.MoteAttributes - false - - - - org.contikios.cooja.interfaces.Position - -1.285769821276336 - 38.58045647334346 - 0.0 - - - org.contikios.cooja.contikimote.interfaces.ContikiMoteID - 1 - - - org.contikios.cooja.contikimote.interfaces.ContikiRadio - 250.0 - - mtype660 - - - - org.contikios.cooja.interfaces.Position - -19.324109516886306 - 76.23135780254927 - 0.0 - - - org.contikios.cooja.contikimote.interfaces.ContikiMoteID - 2 - - - org.contikios.cooja.contikimote.interfaces.ContikiRadio - 250.0 - - mtype660 - - - - org.contikios.cooja.interfaces.Position - 5.815501305791592 - 76.77463755494317 - 0.0 - - - org.contikios.cooja.contikimote.interfaces.ContikiMoteID - 3 - - - org.contikios.cooja.contikimote.interfaces.ContikiRadio - 250.0 - - mtype660 - - - - org.contikios.cooja.interfaces.Position - 31.920697784030082 - 50.5212265977149 - 0.0 - - - org.contikios.cooja.contikimote.interfaces.ContikiMoteID - 4 - - - org.contikios.cooja.contikimote.interfaces.ContikiRadio - 250.0 - - mtype660 - - - - org.contikios.cooja.interfaces.Position - 47.21747673247198 - 30.217765340599726 - 0.0 - - - org.contikios.cooja.contikimote.interfaces.ContikiMoteID - 5 - - - org.contikios.cooja.contikimote.interfaces.ContikiRadio - 250.0 - - mtype660 - - - - org.contikios.cooja.interfaces.Position - 10.622284947035123 - 109.81862399725188 - 0.0 - - - org.contikios.cooja.contikimote.interfaces.ContikiMoteID - 6 - - - org.contikios.cooja.contikimote.interfaces.ContikiRadio - 250.0 - - mtype660 - - - - org.contikios.cooja.interfaces.Position - 52.41150716335335 - 109.93228340481916 - 0.0 - - - org.contikios.cooja.contikimote.interfaces.ContikiMoteID - 7 - - - org.contikios.cooja.contikimote.interfaces.ContikiRadio - 250.0 - - mtype660 - - - - org.contikios.cooja.interfaces.Position - 70.18727461718498 - 70.06861701541145 - 0.0 - - - org.contikios.cooja.contikimote.interfaces.ContikiMoteID - 8 - - - org.contikios.cooja.contikimote.interfaces.ContikiRadio - 250.0 - - mtype660 - - - - org.contikios.cooja.interfaces.Position - 80.29870484201041 - 99.37351603835938 - 0.0 - - - org.contikios.cooja.contikimote.interfaces.ContikiMoteID - 9 - - - org.contikios.cooja.contikimote.interfaces.ContikiRadio - 250.0 - - mtype660 - - - - org.contikios.cooja.plugins.SimControl - 242 - 4 - 160 - 11 - 241 - - - org.contikios.cooja.plugins.Visualizer - - true - org.contikios.cooja.plugins.skins.IDVisualizerSkin - org.contikios.cooja.plugins.skins.GridVisualizerSkin - org.contikios.cooja.plugins.skins.TrafficVisualizerSkin - org.contikios.cooja.plugins.skins.UDGMVisualizerSkin - 1.7405603810040515 0.0 0.0 1.7405603810040515 47.95980153208088 -42.576134155447555 - - 236 - 3 - 230 - 1 - 1 - - - org.contikios.cooja.plugins.LogListener - - - - - - 1031 - 0 - 394 - 273 - 6 - - - org.contikios.cooja.plugins.TimeLine - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 16529.88882215865 - - 1304 - 2 - 311 - 0 - 412 - - - From 9fb7e8bfed6bab8d7543c95ef4192fd83c6c9b83 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 28 Sep 2018 16:12:28 +0200 Subject: [PATCH 372/485] TSCH: cleanup flags for CCA configuration --- os/net/mac/tsch/tsch-conf.h | 10 ++++++++++ os/net/mac/tsch/tsch-slot-operation.c | 8 ++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/os/net/mac/tsch/tsch-conf.h b/os/net/mac/tsch/tsch-conf.h index 8613eb0e3..a6e1bc768 100644 --- a/os/net/mac/tsch/tsch-conf.h +++ b/os/net/mac/tsch/tsch-conf.h @@ -365,18 +365,21 @@ /******** Configuration: CSMA *******/ /* TSCH CSMA-CA parameters, see IEEE 802.15.4e-2012 */ + /* Min backoff exponent */ #ifdef TSCH_CONF_MAC_MIN_BE #define TSCH_MAC_MIN_BE TSCH_CONF_MAC_MIN_BE #else #define TSCH_MAC_MIN_BE 1 #endif + /* Max backoff exponent */ #ifdef TSCH_CONF_MAC_MAX_BE #define TSCH_MAC_MAX_BE TSCH_CONF_MAC_MAX_BE #else #define TSCH_MAC_MAX_BE 5 #endif + /* Max number of re-transmissions */ #ifdef TSCH_CONF_MAC_MAX_FRAME_RETRIES #define TSCH_MAC_MAX_FRAME_RETRIES TSCH_CONF_MAC_MAX_FRAME_RETRIES @@ -391,6 +394,13 @@ #define TSCH_PACKET_EACK_WITH_SRC_ADDR 0 #endif +/* Perform CCA before sending? */ +#ifdef TSCH_CONF_CCA_ENABLED +#define TSCH_CCA_ENABLED TSCH_CONF_CCA_ENABLED +#else +#define TSCH_CCA_ENABLED 0 +#endif + /* Include destination address in ACK? */ #ifdef TSCH_PACKET_CONF_EACK_WITH_DEST_ADDR #define TSCH_PACKET_EACK_WITH_DEST_ADDR TSCH_PACKET_CONF_EACK_WITH_DEST_ADDR diff --git a/os/net/mac/tsch/tsch-slot-operation.c b/os/net/mac/tsch/tsch-slot-operation.c index 843b79f42..74ab6b46e 100644 --- a/os/net/mac/tsch/tsch-slot-operation.c +++ b/os/net/mac/tsch/tsch-slot-operation.c @@ -464,9 +464,9 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t)) /* Did we set the frame pending bit to request an extra burst link? */ static int burst_link_requested; -#if CCA_ENABLED +#if TSCH_CCA_ENABLED static uint8_t cca_status; -#endif +#endif /* TSCH_CCA_ENABLED */ /* get payload */ packet = queuebuf_dataptr(current_packet->qb); @@ -507,7 +507,7 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t)) if(packet_ready && NETSTACK_RADIO.prepare(packet, packet_len) == 0) { /* 0 means success */ static rtimer_clock_t tx_duration; -#if CCA_ENABLED +#if TSCH_CCA_ENABLED cca_status = 1; /* delay before CCA */ TSCH_SCHEDULE_AND_YIELD(pt, t, current_slot_start, TS_CCA_OFFSET, "cca"); @@ -522,7 +522,7 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t)) if(cca_status == 0) { mac_tx_status = MAC_TX_COLLISION; } else -#endif /* CCA_ENABLED */ +#endif /* TSCH_CCA_ENABLED */ { /* delay before TX */ TSCH_SCHEDULE_AND_YIELD(pt, t, current_slot_start, tsch_timing[tsch_ts_tx_offset] - RADIO_DELAY_BEFORE_TX, "TxBeforeTx"); From 1f4f0c406c85595c748227336acd34a4f5df1428 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 28 Sep 2018 16:14:33 +0200 Subject: [PATCH 373/485] TSCH: fix timing variables in CCA code --- os/net/mac/tsch/tsch-slot-operation.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/os/net/mac/tsch/tsch-slot-operation.c b/os/net/mac/tsch/tsch-slot-operation.c index 74ab6b46e..2f36b9cfa 100644 --- a/os/net/mac/tsch/tsch-slot-operation.c +++ b/os/net/mac/tsch/tsch-slot-operation.c @@ -510,12 +510,12 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t)) #if TSCH_CCA_ENABLED cca_status = 1; /* delay before CCA */ - TSCH_SCHEDULE_AND_YIELD(pt, t, current_slot_start, TS_CCA_OFFSET, "cca"); + TSCH_SCHEDULE_AND_YIELD(pt, t, current_slot_start, tsch_timing[tsch_ts_cca_offset], "cca"); TSCH_DEBUG_TX_EVENT(); tsch_radio_on(TSCH_RADIO_CMD_ON_WITHIN_TIMESLOT); /* CCA */ BUSYWAIT_UNTIL_ABS(!(cca_status |= NETSTACK_RADIO.channel_clear()), - current_slot_start, TS_CCA_OFFSET + TS_CCA); + current_slot_start, tsch_timing[tsch_ts_cca_offset] + tsch_timing[tsch_ts_cca]); TSCH_DEBUG_TX_EVENT(); /* there is not enough time to turn radio off */ /* NETSTACK_RADIO.off(); */ From 3e83903ee5f94adced4a1629f50dc4e90b95d0f9 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 28 Sep 2018 16:16:25 +0200 Subject: [PATCH 374/485] TSCH: fix CCA checking logic --- os/net/mac/tsch/tsch-slot-operation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/net/mac/tsch/tsch-slot-operation.c b/os/net/mac/tsch/tsch-slot-operation.c index 2f36b9cfa..a3b150c51 100644 --- a/os/net/mac/tsch/tsch-slot-operation.c +++ b/os/net/mac/tsch/tsch-slot-operation.c @@ -514,7 +514,7 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t)) TSCH_DEBUG_TX_EVENT(); tsch_radio_on(TSCH_RADIO_CMD_ON_WITHIN_TIMESLOT); /* CCA */ - BUSYWAIT_UNTIL_ABS(!(cca_status |= NETSTACK_RADIO.channel_clear()), + BUSYWAIT_UNTIL_ABS(!(cca_status &= NETSTACK_RADIO.channel_clear()), current_slot_start, tsch_timing[tsch_ts_cca_offset] + tsch_timing[tsch_ts_cca]); TSCH_DEBUG_TX_EVENT(); /* there is not enough time to turn radio off */ From a01413369df50d65631abfff991f7de18a6c4a27 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 28 Sep 2018 16:08:26 +0200 Subject: [PATCH 375/485] RPL-Lite: fix DAG lifetime, was 60h, now 8h --- os/net/routing/rpl-lite/rpl-conf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/net/routing/rpl-lite/rpl-conf.h b/os/net/routing/rpl-lite/rpl-conf.h index 9b8a12adb..5d674fa96 100644 --- a/os/net/routing/rpl-lite/rpl-conf.h +++ b/os/net/routing/rpl-lite/rpl-conf.h @@ -272,7 +272,7 @@ #ifdef RPL_CONF_DAG_LIFETIME #define RPL_DAG_LIFETIME RPL_CONF_DAG_LIFETIME #else -#define RPL_DAG_LIFETIME (60 * 60) /* one hour */ +#define RPL_DAG_LIFETIME (8 * 60) /* 8 hours */ #endif /* RPL_CONF_DAG_LIFETIME */ /* From 3e9d79ca8cf5b4aa372aa1f778814277f883830a Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 30 Sep 2018 13:03:50 +0100 Subject: [PATCH 376/485] Fix pin to mask conversion macro for 64-bit masks --- os/dev/gpio-hal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/dev/gpio-hal.h b/os/dev/gpio-hal.h index 9fe541772..5ad9f472b 100644 --- a/os/dev/gpio-hal.h +++ b/os/dev/gpio-hal.h @@ -189,7 +189,7 @@ void gpio_hal_event_handler(gpio_hal_pin_mask_t pins); * \param pin The pin * \return The corresponding mask */ -#define gpio_hal_pin_to_mask(pin) (1 << (pin)) +#define gpio_hal_pin_to_mask(pin) ((gpio_hal_pin_mask_t)1 << (pin)) /** @} */ /*---------------------------------------------------------------------------*/ /** From b4db7aa4e762efa65de62e300140698d1be97408 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 30 Sep 2018 13:21:36 +0100 Subject: [PATCH 377/485] GPIO HAL example fix 64-bit support --- examples/dev/gpio-hal/gpio-hal-example.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/dev/gpio-hal/gpio-hal-example.c b/examples/dev/gpio-hal/gpio-hal-example.c index 380c06388..75137e26a 100644 --- a/examples/dev/gpio-hal/gpio-hal-example.c +++ b/examples/dev/gpio-hal/gpio-hal-example.c @@ -46,9 +46,9 @@ 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 +#define PIN_MASK_FMT "0x%016" PRIx64 #else -#define PIN_MASK_FMT PRIx32 +#define PIN_MASK_FMT "0x%08" PRIx32 #endif /*---------------------------------------------------------------------------*/ PROCESS(gpio_hal_example, "GPIO HAL Example"); @@ -127,7 +127,7 @@ PROCESS_THREAD(gpio_hal_example, ev, data) } /* Test read */ - printf("%u: Pins are 1-%u, 2=%u, 3=%u, mask=0x%08" PIN_MASK_FMT "\n", + printf("%u: Pins are 1-%u, 2=%u, 3=%u, mask=" PIN_MASK_FMT "\n", counter & 7, gpio_hal_arch_read_pin(out_pin1), gpio_hal_arch_read_pin(out_pin2), From 3045a47a29e280b3043f914f61713d29cf2d2a0b Mon Sep 17 00:00:00 2001 From: kkrentz Date: Thu, 2 Aug 2018 01:01:41 -0700 Subject: [PATCH 378/485] cc2538-rf: As per the user's guide, RFCORE_XREG_FSCAL1 needs updating, too --- arch/cpu/cc2538/dev/cc2538-rf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/cpu/cc2538/dev/cc2538-rf.c b/arch/cpu/cc2538/dev/cc2538-rf.c index f33e87131..e287efe57 100644 --- a/arch/cpu/cc2538/dev/cc2538-rf.c +++ b/arch/cpu/cc2538/dev/cc2538-rf.c @@ -490,6 +490,7 @@ init(void) REG(RFCORE_XREG_TXFILTCFG) = 0x09; /** TX anti-aliasing filter bandwidth */ REG(RFCORE_XREG_AGCCTRL1) = 0x15; /** AGC target value */ REG(ANA_REGS_IVCTRL) = 0x0B; /** Bias currents */ + REG(RFCORE_XREG_FSCAL1) = 0x01; /** Tune frequency calibration */ /* * Defaults: From c919975d41712cf8cf3b400360d5164b9dd746e0 Mon Sep 17 00:00:00 2001 From: kkrentz Date: Thu, 2 Aug 2018 01:08:45 -0700 Subject: [PATCH 379/485] cc2538-rf: I see no point in flushing twice --- arch/cpu/cc2538/dev/cc2538-rf.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/cpu/cc2538/dev/cc2538-rf.h b/arch/cpu/cc2538/dev/cc2538-rf.h index b89738436..e22f9c080 100644 --- a/arch/cpu/cc2538/dev/cc2538-rf.h +++ b/arch/cpu/cc2538/dev/cc2538-rf.h @@ -113,7 +113,6 @@ */ #define CC2538_RF_CSP_ISFLUSHRX() do { \ REG(RFCORE_SFR_RFST) = CC2538_RF_CSP_OP_ISFLUSHRX; \ - REG(RFCORE_SFR_RFST) = CC2538_RF_CSP_OP_ISFLUSHRX; \ } while(0) /** @@ -121,7 +120,6 @@ */ #define CC2538_RF_CSP_ISFLUSHTX() do { \ REG(RFCORE_SFR_RFST) = CC2538_RF_CSP_OP_ISFLUSHTX; \ - REG(RFCORE_SFR_RFST) = CC2538_RF_CSP_OP_ISFLUSHTX; \ } while(0) /*---------------------------------------------------------------------------*/ /** The NETSTACK data structure for the cc2538 RF driver */ From a1fddeb0f7ae7a7a805ca0d2dea9d531cba4ef22 Mon Sep 17 00:00:00 2001 From: kkrentz Date: Thu, 2 Aug 2018 01:23:12 -0700 Subject: [PATCH 380/485] cc2538-rf: After init, we are not in receive mode --- arch/cpu/cc2538/dev/cc2538-rf.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/cpu/cc2538/dev/cc2538-rf.c b/arch/cpu/cc2538/dev/cc2538-rf.c index e287efe57..c87e80ed5 100644 --- a/arch/cpu/cc2538/dev/cc2538-rf.c +++ b/arch/cpu/cc2538/dev/cc2538-rf.c @@ -546,8 +546,6 @@ init(void) rf_flags |= RF_ON; - ENERGEST_ON(ENERGEST_TYPE_LISTEN); - return 1; } /*---------------------------------------------------------------------------*/ From 34997f60f6fb6a205666314ff182bf82f9ebd16e Mon Sep 17 00:00:00 2001 From: kkrentz Date: Thu, 2 Aug 2018 01:27:30 -0700 Subject: [PATCH 381/485] cc2538-rf: Removed unused function "cc2538_rf_set_promiscous_mode" --- arch/cpu/cc2538/dev/cc2538-rf.c | 7 +------ arch/cpu/cc2538/dev/cc2538-rf.h | 10 ---------- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/arch/cpu/cc2538/dev/cc2538-rf.c b/arch/cpu/cc2538/dev/cc2538-rf.c index c87e80ed5..ced919a09 100644 --- a/arch/cpu/cc2538/dev/cc2538-rf.c +++ b/arch/cpu/cc2538/dev/cc2538-rf.c @@ -1096,10 +1096,5 @@ cc2538_rf_err_isr(void) process_poll(&cc2538_rf_process); } /*---------------------------------------------------------------------------*/ -void -cc2538_rf_set_promiscous_mode(char p) -{ - set_frame_filtering(p); -} -/*---------------------------------------------------------------------------*/ + /** @} */ diff --git a/arch/cpu/cc2538/dev/cc2538-rf.h b/arch/cpu/cc2538/dev/cc2538-rf.h index e22f9c080..ffd8a6c08 100644 --- a/arch/cpu/cc2538/dev/cc2538-rf.h +++ b/arch/cpu/cc2538/dev/cc2538-rf.h @@ -136,16 +136,6 @@ extern const struct radio_driver cc2538_rf_driver; */ void cc2538_rf_set_addr(uint16_t pan); -/** - * \brief Turn promiscous mode on or off - * \param p If promiscous mode should be on (1) or off (0) - * - * This function turns promiscous mode on or off. In promiscous mode, - * every received frame is returned from the RF core. In - * non-promiscous mode, only broadcast frames or frames with our - * address as the receive address are returned from the RF core. - */ -void cc2538_rf_set_promiscous_mode(char p); /*---------------------------------------------------------------------------*/ #endif /* CC2538_RF_H__ */ From 9c1fefa7a74922eff6c3b0371c3f983b56ff9f89 Mon Sep 17 00:00:00 2001 From: kkrentz Date: Thu, 2 Aug 2018 02:16:13 -0700 Subject: [PATCH 382/485] cc2538-rf: More compact implementation of getting RSSIs --- arch/cpu/cc2538/dev/cc2538-rf.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/cpu/cc2538/dev/cc2538-rf.c b/arch/cpu/cc2538/dev/cc2538-rf.c index ced919a09..a1aee0582 100644 --- a/arch/cpu/cc2538/dev/cc2538-rf.c +++ b/arch/cpu/cc2538/dev/cc2538-rf.c @@ -86,6 +86,7 @@ #define LQI_BIT_MASK 0x7F /* RSSI Offset */ #define RSSI_OFFSET 73 +#define RSSI_INVALID -128 /* 192 usec off -> on interval (RX Callib -> SFD Wait). We wait a bit more */ #define ONOFF_TIME RTIMER_ARCH_SECOND / 3125 @@ -244,10 +245,11 @@ get_rssi(void) on(); } - /* Wait on RSSI_VALID */ - while((REG(RFCORE_XREG_RSSISTAT) & RFCORE_XREG_RSSISTAT_RSSI_VALID) == 0); - - rssi = (int8_t)(REG(RFCORE_XREG_RSSI) & RFCORE_XREG_RSSI_RSSI_VAL) - RSSI_OFFSET; + /* Wait for a valid RSSI reading */ + do { + rssi = REG(RFCORE_XREG_RSSI); + } while(rssi == RSSI_INVALID); + rssi -= RSSI_OFFSET; /* If we were off, turn back off */ if(was_off) { From f8091cb87c99b08c9b37ba0ad550db66946b677e Mon Sep 17 00:00:00 2001 From: kkrentz Date: Thu, 2 Aug 2018 05:32:43 -0700 Subject: [PATCH 383/485] cc2538-rf: Use logging API --- arch/cpu/cc2538/dev/cc2538-rf.c | 59 ++++++++++++++++----------------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/arch/cpu/cc2538/dev/cc2538-rf.c b/arch/cpu/cc2538/dev/cc2538-rf.c index a1aee0582..27b6c3061 100644 --- a/arch/cpu/cc2538/dev/cc2538-rf.c +++ b/arch/cpu/cc2538/dev/cc2538-rf.c @@ -68,13 +68,10 @@ */ #define UDMA_RX_SIZE_THRESHOLD 3 /*---------------------------------------------------------------------------*/ -#include -#define DEBUG 0 -#if DEBUG -#define PRINTF(...) printf(__VA_ARGS__) -#else -#define PRINTF(...) -#endif +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "cc2538-rf" +#define LOG_LEVEL LOG_LEVEL_NONE /*---------------------------------------------------------------------------*/ /* Local RF Flags */ #define RX_ACTIVE 0x80 @@ -174,7 +171,7 @@ set_channel(uint8_t channel) { uint8_t was_on = 0; - PRINTF("RF: Set Channel\n"); + LOG_INFO("Set Channel\n"); if((channel < CC2538_RF_CHANNEL_MIN) || (channel > CC2538_RF_CHANNEL_MAX)) { return CC2538_RF_CHANNEL_SET_ERROR; @@ -405,7 +402,7 @@ channel_clear(void) int cca; uint8_t was_off = 0; - PRINTF("RF: CCA\n"); + LOG_INFO("CCA\n"); /* If we are off, turn on first */ if((REG(RFCORE_XREG_FSMSTAT0) & RFCORE_XREG_FSMSTAT0_FSM_FFCTRL_STATE) == 0) { @@ -433,7 +430,7 @@ channel_clear(void) static int on(void) { - PRINTF("RF: On\n"); + LOG_INFO("On\n"); if(!(rf_flags & RX_ACTIVE)) { CC2538_RF_CSP_ISFLUSHRX(); @@ -449,7 +446,7 @@ on(void) static int off(void) { - PRINTF("RF: Off\n"); + LOG_INFO("Off\n"); /* Wait for ongoing TX to complete (e.g. this could be an outgoing ACK) */ while(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE); @@ -472,7 +469,7 @@ off(void) static int init(void) { - PRINTF("RF: Init\n"); + LOG_INFO("Init\n"); if(rf_flags & RF_ON) { return 0; @@ -556,7 +553,7 @@ prepare(const void *payload, unsigned short payload_len) { uint8_t i; - PRINTF("RF: Prepare 0x%02x bytes\n", payload_len + CHECKSUM_LEN); + LOG_INFO("Prepare 0x%02x bytes\n", payload_len + CHECKSUM_LEN); /* * When we transmit in very quick bursts, make sure previous transmission @@ -570,12 +567,12 @@ prepare(const void *payload, unsigned short payload_len) CC2538_RF_CSP_ISFLUSHTX(); - PRINTF("RF: data = "); + LOG_INFO("data = "); /* Send the phy length byte first */ REG(RFCORE_SFR_RFDATA) = payload_len + CHECKSUM_LEN; if(CC2538_RF_CONF_TX_USE_DMA) { - PRINTF(""); + LOG_INFO_(""); /* Set the transfer source's end address */ udma_set_channel_src(CC2538_RF_CONF_TX_DMA_CHAN, @@ -599,10 +596,10 @@ prepare(const void *payload, unsigned short payload_len) } else { for(i = 0; i < payload_len; i++) { REG(RFCORE_SFR_RFDATA) = ((unsigned char *)(payload))[i]; - PRINTF("%02x", ((unsigned char *)(payload))[i]); + LOG_INFO_("%02x", ((unsigned char *)(payload))[i]); } } - PRINTF("\n"); + LOG_INFO_("\n"); return 0; } @@ -615,7 +612,7 @@ transmit(unsigned short transmit_len) rtimer_clock_t t0; uint8_t was_off = 0; - PRINTF("RF: Transmit\n"); + LOG_INFO("Transmit\n"); if(!(rf_flags & RX_ACTIVE)) { t0 = RTIMER_NOW(); @@ -650,7 +647,7 @@ transmit(unsigned short transmit_len) } if(!(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE)) { - PRINTF("RF: TX never active.\n"); + LOG_ERR("TX never active.\n"); CC2538_RF_CSP_ISFLUSHTX(); ret = RADIO_TX_ERR; } else { @@ -680,7 +677,7 @@ read(void *buf, unsigned short bufsize) uint8_t i; uint8_t len; - PRINTF("RF: Read\n"); + LOG_INFO("Read\n"); if((REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFOP) == 0) { return 0; @@ -692,33 +689,33 @@ read(void *buf, unsigned short bufsize) /* Check for validity */ if(len > CC2538_RF_MAX_PACKET_LEN) { /* Oops, we must be out of sync. */ - PRINTF("RF: bad sync\n"); + LOG_ERR("RF: bad sync\n"); CC2538_RF_CSP_ISFLUSHRX(); return 0; } if(len <= CC2538_RF_MIN_PACKET_LEN) { - PRINTF("RF: too short\n"); + LOG_ERR("RF: too short\n"); CC2538_RF_CSP_ISFLUSHRX(); return 0; } if(len - CHECKSUM_LEN > bufsize) { - PRINTF("RF: too long\n"); + LOG_ERR("RF: too long\n"); CC2538_RF_CSP_ISFLUSHRX(); return 0; } /* If we reach here, chances are the FIFO is holding a valid frame */ - PRINTF("RF: read (0x%02x bytes) = ", len); + LOG_INFO("read (0x%02x bytes) = ", len); len -= CHECKSUM_LEN; /* Don't bother with uDMA for short frames (e.g. ACKs) */ if(CC2538_RF_CONF_RX_USE_DMA && len > UDMA_RX_SIZE_THRESHOLD) { - PRINTF(""); + LOG_INFO_(""); /* Set the transfer destination's end address */ udma_set_channel_dst(CC2538_RF_CONF_RX_DMA_CHAN, @@ -739,7 +736,7 @@ read(void *buf, unsigned short bufsize) } else { for(i = 0; i < len; ++i) { ((unsigned char *)(buf))[i] = REG(RFCORE_SFR_RFDATA); - PRINTF("%02x", ((unsigned char *)(buf))[i]); + LOG_INFO_("%02x", ((unsigned char *)(buf))[i]); } } @@ -747,14 +744,14 @@ read(void *buf, unsigned short bufsize) rssi = ((int8_t)REG(RFCORE_SFR_RFDATA)) - RSSI_OFFSET; crc_corr = REG(RFCORE_SFR_RFDATA); - PRINTF("%02x%02x\n", (uint8_t)rssi, crc_corr); + LOG_INFO_("%02x%02x\n", (uint8_t)rssi, crc_corr); /* MS bit CRC OK/Not OK, 7 LS Bits, Correlation value */ if(crc_corr & CRC_BIT_MASK) { packetbuf_set_attr(PACKETBUF_ATTR_RSSI, rssi); packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, crc_corr & LQI_BIT_MASK); } else { - PRINTF("RF: Bad CRC\n"); + LOG_ERR("Bad CRC\n"); CC2538_RF_CSP_ISFLUSHRX(); return 0; } @@ -776,7 +773,7 @@ read(void *buf, unsigned short bufsize) static int receiving_packet(void) { - PRINTF("RF: Receiving\n"); + LOG_INFO("Receiving\n"); /* * SFD high while transmitting and receiving. @@ -792,7 +789,7 @@ receiving_packet(void) static int pending_packet(void) { - PRINTF("RF: Pending\n"); + LOG_INFO("Pending\n"); return REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFOP; } @@ -1086,7 +1083,7 @@ cc2538_rf_rx_tx_isr(void) void cc2538_rf_err_isr(void) { - PRINTF("RF Error: 0x%08lx\n", REG(RFCORE_SFR_RFERRF)); + LOG_ERR("Error 0x%08lx occurred\n", REG(RFCORE_SFR_RFERRF)); /* If the error is not an RX FIFO overflow, set a flag */ if(REG(RFCORE_SFR_RFERRF) != RFCORE_SFR_RFERRF_RXOVERF) { From 34f697adf7038bc0d06eb7db4627d760134dddcc Mon Sep 17 00:00:00 2001 From: kkrentz Date: Thu, 2 Aug 2018 05:44:18 -0700 Subject: [PATCH 384/485] cc2538-rf: Support for disabling the SHR search --- arch/cpu/cc2538/dev/cc2538-rf.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/cpu/cc2538/dev/cc2538-rf.c b/arch/cpu/cc2538/dev/cc2538-rf.c index 27b6c3061..39aa1f5ed 100644 --- a/arch/cpu/cc2538/dev/cc2538-rf.c +++ b/arch/cpu/cc2538/dev/cc2538-rf.c @@ -321,6 +321,16 @@ set_frame_filtering(uint8_t enable) } /*---------------------------------------------------------------------------*/ static void +set_shr_search(int enable) +{ + if(enable) { + REG(RFCORE_XREG_FRMCTRL0) &= ~RFCORE_XREG_FRMCTRL0_RX_MODE; + } else { + REG(RFCORE_XREG_FRMCTRL0) |= RFCORE_XREG_FRMCTRL0_RX_MODE; + } +} +/*---------------------------------------------------------------------------*/ +static void mac_timer_init(void) { CLOCK_STABLE(); @@ -513,6 +523,9 @@ init(void) set_channel(rf_channel); + /* Enable SHR search */ + set_shr_search(1); + /* Acknowledge all RF Error interrupts */ REG(RFCORE_XREG_RFERRM) = RFCORE_XREG_RFERRM_RFERRM; NVIC_EnableIRQ(RF_ERR_IRQn); @@ -922,6 +935,9 @@ set_value(radio_param_t param, radio_value_t value) case RADIO_PARAM_CCA_THRESHOLD: set_cca_threshold(value); return RADIO_RESULT_OK; + case RADIO_PARAM_SHR_SEARCH: + set_shr_search(value); + return RADIO_RESULT_OK; default: return RADIO_RESULT_NOT_SUPPORTED; } From 9f78836219c3bebad6329c31efb1d0b944dcee5f Mon Sep 17 00:00:00 2001 From: kkrentz Date: Thu, 2 Aug 2018 05:46:34 -0700 Subject: [PATCH 385/485] cc2538-rf: Simplified get_channel --- arch/cpu/cc2538/dev/cc2538-rf.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/arch/cpu/cc2538/dev/cc2538-rf.c b/arch/cpu/cc2538/dev/cc2538-rf.c index 39aa1f5ed..804870a47 100644 --- a/arch/cpu/cc2538/dev/cc2538-rf.c +++ b/arch/cpu/cc2538/dev/cc2538-rf.c @@ -154,10 +154,7 @@ PROCESS(cc2538_rf_process, "cc2538 RF driver"); static uint8_t get_channel() { - uint8_t chan = REG(RFCORE_XREG_FREQCTRL) & RFCORE_XREG_FREQCTRL_FREQ; - - return (chan - CC2538_RF_CHANNEL_MIN) / CC2538_RF_CHANNEL_SPACING - + CC2538_RF_CHANNEL_MIN; + return rf_channel; } /*---------------------------------------------------------------------------*/ /** From 501ce04f0510a98aecb52009623bc002e93ed0aa Mon Sep 17 00:00:00 2001 From: kkrentz Date: Fri, 3 Aug 2018 03:12:00 -0700 Subject: [PATCH 386/485] cc2538-rf: Simplified set_channel --- arch/cpu/cc2538/dev/cc2538-rf.c | 14 ++------------ arch/cpu/cc2538/dev/cc2538-rf.h | 1 - 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/arch/cpu/cc2538/dev/cc2538-rf.c b/arch/cpu/cc2538/dev/cc2538-rf.c index 804870a47..eea715653 100644 --- a/arch/cpu/cc2538/dev/cc2538-rf.c +++ b/arch/cpu/cc2538/dev/cc2538-rf.c @@ -160,20 +160,14 @@ get_channel() /** * \brief Set the current operating channel * \param channel The desired channel as a value in [11,26] - * \return Returns a value in [11,26] representing the current channel - * or a negative value if \e channel was out of bounds */ -static int8_t +static void set_channel(uint8_t channel) { uint8_t was_on = 0; LOG_INFO("Set Channel\n"); - if((channel < CC2538_RF_CHANNEL_MIN) || (channel > CC2538_RF_CHANNEL_MAX)) { - return CC2538_RF_CHANNEL_SET_ERROR; - } - /* Changes to FREQCTRL take effect after the next recalibration */ /* If we are off, save state, otherwise switch off and save state */ @@ -190,8 +184,6 @@ set_channel(uint8_t channel) } rf_channel = channel; - - return (int8_t)channel; } /*---------------------------------------------------------------------------*/ static radio_value_t @@ -894,9 +886,7 @@ set_value(radio_param_t param, radio_value_t value) value > CC2538_RF_CHANNEL_MAX) { return RADIO_RESULT_INVALID_VALUE; } - if(set_channel(value) == CC2538_RF_CHANNEL_SET_ERROR) { - return RADIO_RESULT_ERROR; - } + set_channel(value); return RADIO_RESULT_OK; case RADIO_PARAM_PAN_ID: set_pan_id(value & 0xffff); diff --git a/arch/cpu/cc2538/dev/cc2538-rf.h b/arch/cpu/cc2538/dev/cc2538-rf.h index ffd8a6c08..958221783 100644 --- a/arch/cpu/cc2538/dev/cc2538-rf.h +++ b/arch/cpu/cc2538/dev/cc2538-rf.h @@ -56,7 +56,6 @@ #define CC2538_RF_CHANNEL_MIN 11 #define CC2538_RF_CHANNEL_MAX 26 #define CC2538_RF_CHANNEL_SPACING 5 -#define CC2538_RF_CHANNEL_SET_ERROR -1 #define CC2538_RF_MAX_PACKET_LEN 127 #define CC2538_RF_MIN_PACKET_LEN 4 #define CC2538_RF_CCA_CLEAR 1 From 11a2fb14b124df97091260b9e495aaa3f4e63263 Mon Sep 17 00:00:00 2001 From: kkrentz Date: Tue, 2 Oct 2018 07:56:23 -0700 Subject: [PATCH 387/485] radio.h: Added RADIO_PARAM_SHR_SEARCH --- os/dev/radio.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/os/dev/radio.h b/os/dev/radio.h index 982acc51d..9bbef9619 100644 --- a/os/dev/radio.h +++ b/os/dev/radio.h @@ -170,6 +170,9 @@ enum { * it needs to be used with radio.get_object()/set_object(). */ RADIO_PARAM_LAST_PACKET_TIMESTAMP, + /* For enabling and disabling the SHR search */ + RADIO_PARAM_SHR_SEARCH, + /* Constants (read only) */ /* The lowest radio channel. */ From 6b1292d9d9f63b49e22c224dcb652c3539f1aa18 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 3 Oct 2018 12:24:40 +0200 Subject: [PATCH 388/485] cc1200: add required structures and defines for TSCH support --- .../cc1200-802154g-863-870-fsk-50kbps.c | 56 ++++++++++++++++++- arch/dev/cc1200/cc1200-868-fsk-1-2kbps.c | 5 ++ arch/dev/cc1200/cc1200-rf-cfg.h | 11 ++++ 3 files changed, 71 insertions(+), 1 deletion(-) diff --git a/arch/dev/cc1200/cc1200-802154g-863-870-fsk-50kbps.c b/arch/dev/cc1200/cc1200-802154g-863-870-fsk-50kbps.c index 0fe452999..b1d4b2064 100644 --- a/arch/dev/cc1200/cc1200-802154g-863-870-fsk-50kbps.c +++ b/arch/dev/cc1200/cc1200-802154g-863-870-fsk-50kbps.c @@ -34,6 +34,7 @@ #include "cc1200-rf-cfg.h" #include "cc1200-const.h" +#include "net/mac/tsch/tsch.h" /* * This is a setup for the following configuration: @@ -62,7 +63,53 @@ /*---------------------------------------------------------------------------*/ static const char rf_cfg_descriptor[] = "802.15.4g 863-870MHz MR-FSK mode #1"; /*---------------------------------------------------------------------------*/ -/* + +/* 1 byte time: 160 usec */ +#define CC1200_TSCH_PREAMBLE_LENGTH 800 /* 5 bytes */ +#define CC1200_TSCH_CONF_RX_WAIT 2200 +#define CC1200_TSCH_CONF_RX_ACK_WAIT 400 + +#define CC1200_TSCH_DEFAULT_TS_CCA_OFFSET 1800 +#define CC1200_TSCH_DEFAULT_TS_CCA 128 + +#define CC1200_TSCH_DEFAULT_TS_TX_OFFSET 3800 +#define CC1200_TSCH_DEFAULT_TS_RX_OFFSET (CC1200_TSCH_DEFAULT_TS_TX_OFFSET - CC1200_TSCH_PREAMBLE_LENGTH - (CC1200_TSCH_CONF_RX_WAIT / 2)) +#define CC1200_TSCH_DEFAULT_TS_RX_ACK_DELAY (CC1200_TSCH_DEFAULT_TS_TX_ACK_DELAY - CC1200_TSCH_PREAMBLE_LENGTH - (CC1200_TSCH_CONF_RX_ACK_WAIT / 2)) +#define CC1200_TSCH_DEFAULT_TS_TX_ACK_DELAY 3000 + +#define CC1200_TSCH_DEFAULT_TS_RX_WAIT (CC1200_TSCH_PREAMBLE_LENGTH + CC1200_TSCH_CONF_RX_WAIT) +#define CC1200_TSCH_DEFAULT_TS_ACK_WAIT (CC1200_TSCH_PREAMBLE_LENGTH + CC1200_TSCH_CONF_RX_ACK_WAIT) +#define CC1200_TSCH_DEFAULT_TS_RX_TX 192 +#define CC1200_TSCH_DEFAULT_TS_MAX_ACK 3360 /* 17+1+3 bytes at 50 kbps */ +#define CC1200_TSCH_DEFAULT_TS_MAX_TX 20800 /* 126+1+3 bytes at 50 kbps */ + +#define CC1200_TSCH_DEFAULT_SLACK_TIME 500 +/* Timeslot length: 31460 usec */ +#define CC1200_TSCH_DEFAULT_TS_TIMESLOT_LENGTH \ + ( CC1200_TSCH_DEFAULT_TS_TX_OFFSET \ + + CC1200_TSCH_DEFAULT_TS_MAX_TX \ + + CC1200_TSCH_DEFAULT_TS_TX_ACK_DELAY \ + + CC1200_TSCH_DEFAULT_TS_MAX_ACK \ + + CC1200_TSCH_DEFAULT_SLACK_TIME \ + ) + +/* TSCH timeslot timing (mircoseconds) */ +static uint16_t cc1200_50kbps_tsch_timing[tsch_ts_elements_count] = { + CC1200_TSCH_DEFAULT_TS_CCA_OFFSET, + CC1200_TSCH_DEFAULT_TS_CCA, + CC1200_TSCH_DEFAULT_TS_TX_OFFSET, + CC1200_TSCH_DEFAULT_TS_RX_OFFSET, + CC1200_TSCH_DEFAULT_TS_RX_ACK_DELAY, + CC1200_TSCH_DEFAULT_TS_TX_ACK_DELAY, + CC1200_TSCH_DEFAULT_TS_RX_WAIT, + CC1200_TSCH_DEFAULT_TS_ACK_WAIT, + CC1200_TSCH_DEFAULT_TS_RX_TX, + CC1200_TSCH_DEFAULT_TS_MAX_ACK, + CC1200_TSCH_DEFAULT_TS_MAX_TX, + CC1200_TSCH_DEFAULT_TS_TIMESLOT_LENGTH, +}; + +/* * Register settings exported from SmartRF Studio using the standard template * "trxEB RF Settings Performance Line". */ @@ -159,6 +206,11 @@ const cc1200_rf_cfg_t cc1200_802154g_863_870_fsk_50kbps = { .size_of_register_settings = sizeof(preferredSettings), .tx_pkt_lifetime = (RTIMER_SECOND / 20), .tx_rx_turnaround = (RTIMER_SECOND / 100), + /* Includes 3 Bytes preamble + 2 Bytes SFD, at 160usec per byte = 800 usec */ + /* Includes time to completion of "Wait for TX to start" if cc1200.c: 397 usec */ + .delay_before_tx = ((unsigned)US_TO_RTIMERTICKS(800 + 397 + 423)), + .delay_before_rx = (unsigned)US_TO_RTIMERTICKS(400), + .delay_before_detect = 0, .chan_center_freq0 = RF_CFG_CHAN_CENTER_F0, .chan_spacing = RF_CFG_CHAN_SPACING, .min_channel = RF_CFG_MIN_CHANNEL, @@ -166,5 +218,7 @@ const cc1200_rf_cfg_t cc1200_802154g_863_870_fsk_50kbps = { .max_txpower = RF_CFG_MAX_TXPOWER, .cca_threshold = RF_CFG_CCA_THRESHOLD, .rssi_offset = RF_CFG_RSSI_OFFSET, + .bitrate = 50000, + .tsch_timing = cc1200_50kbps_tsch_timing, }; /*---------------------------------------------------------------------------*/ diff --git a/arch/dev/cc1200/cc1200-868-fsk-1-2kbps.c b/arch/dev/cc1200/cc1200-868-fsk-1-2kbps.c index 7c8d52cb4..7cb8f3021 100644 --- a/arch/dev/cc1200/cc1200-868-fsk-1-2kbps.c +++ b/arch/dev/cc1200/cc1200-868-fsk-1-2kbps.c @@ -126,6 +126,9 @@ const cc1200_rf_cfg_t cc1200_868_fsk_1_2kbps = { .size_of_register_settings = sizeof(preferredSettings), .tx_pkt_lifetime = (2 * RTIMER_SECOND), .tx_rx_turnaround = (RTIMER_SECOND / 2), + .delay_before_tx = 0, + .delay_before_rx = 0, + .delay_before_detect = 0, .chan_center_freq0 = RF_CFG_CHAN_CENTER_F0, .chan_spacing = RF_CFG_CHAN_SPACING, .min_channel = RF_CFG_MIN_CHANNEL, @@ -133,5 +136,7 @@ const cc1200_rf_cfg_t cc1200_868_fsk_1_2kbps = { .max_txpower = RF_CFG_MAX_TXPOWER, .cca_threshold = RF_CFG_CCA_THRESHOLD, .rssi_offset = RF_CFG_RSSI_OFFSET, + .bitrate = 1200, + .tsch_timing = NULL, }; /*---------------------------------------------------------------------------*/ diff --git a/arch/dev/cc1200/cc1200-rf-cfg.h b/arch/dev/cc1200/cc1200-rf-cfg.h index 4b206959b..d047f772e 100644 --- a/arch/dev/cc1200/cc1200-rf-cfg.h +++ b/arch/dev/cc1200/cc1200-rf-cfg.h @@ -69,6 +69,13 @@ typedef struct cc1200_rf_cfg { rtimer_clock_t tx_pkt_lifetime; /* The maximum time it takes to switch from Tx to Rx */ rtimer_clock_t tx_rx_turnaround; + /* The delay between a call to transmit() and end of SFD */ + rtimer_clock_t delay_before_tx; + /* Delay between GO signal and start listening + * Measured 104us: between GO signal and start listening */ + rtimer_clock_t delay_before_rx; + /* Delay between the SFD finishes arriving and it is detected in software */ + rtimer_clock_t delay_before_detect; /* Base frequency in kHz */ uint32_t chan_center_freq0; /* Channel spacing in Hz */ @@ -87,6 +94,10 @@ typedef struct cc1200_rf_cfg { /* The RSSI offset in dBm. * -99 when MDMCFG1.DVGA_GAIN=00, -81 when MDMCFG1.DVGA_GAIN=01 */ int8_t rssi_offset; + /* The bitrate in bps */ + uint32_t bitrate; + /* TSCH timeslot timing */ + uint16_t *tsch_timing; } cc1200_rf_cfg_t; /*---------------------------------------------------------------------------*/ #endif /* CC1200_RF_CFG_H */ From c4c1e589f7ab68e9d19955a75cbc8ed8e7adbac2 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 3 Oct 2018 12:25:09 +0200 Subject: [PATCH 389/485] cc1200: add 1000 kbps configuration, including TSCH configuration --- arch/dev/cc1200/cc1200-868-4gfsk-1000kbps.c | 176 ++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 arch/dev/cc1200/cc1200-868-4gfsk-1000kbps.c diff --git a/arch/dev/cc1200/cc1200-868-4gfsk-1000kbps.c b/arch/dev/cc1200/cc1200-868-4gfsk-1000kbps.c new file mode 100644 index 000000000..506fad801 --- /dev/null +++ b/arch/dev/cc1200/cc1200-868-4gfsk-1000kbps.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2015, Weptech elektronik GmbH Germany + * http://www.weptech.de + * + * 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. + * + * This file is part of the Contiki operating system. + */ + +#include "cc1200-rf-cfg.h" +#include "cc1200-const.h" +#include "net/mac/tsch/tsch.h" + +/* +* Register settings exported from SmartRF Studio using the standard 1000kpbs 868MHz template + */ + + /* Base frequency in kHz */ + #define RF_CFG_CHAN_CENTER_F0 863125 + /* Channel spacing in Hz */ + #define RF_CFG_CHAN_SPACING 1666667 +/* The minimum channel */ +#define RF_CFG_MIN_CHANNEL 0 +/* The maximum channel */ +#define RF_CFG_MAX_CHANNEL 3 +/* The maximum output power in dBm */ +#define RF_CFG_MAX_TXPOWER CC1200_CONST_TX_POWER_MAX +/* The carrier sense level used for CCA in dBm */ +#define RF_CFG_CCA_THRESHOLD (-91) +/* The RSSI offset in dBm */ +#define RF_CFG_RSSI_OFFSET (-81) +/*---------------------------------------------------------------------------*/ +static const char rf_cfg_descriptor[] = "868MHz 2-GFSK 1000 kbps"; +/*---------------------------------------------------------------------------*/ + +/* 1 byte time: 8 usec */ +#define CC1200_TSCH_PREAMBLE_LENGTH 800 /* 5 bytes */ +#define CC1200_TSCH_CONF_RX_WAIT 2200 +#define CC1200_TSCH_CONF_RX_ACK_WAIT 400 + +#define CC1200_TSCH_DEFAULT_TS_CCA_OFFSET 1800 +#define CC1200_TSCH_DEFAULT_TS_CCA 128 +#define CC1200_TSCH_DEFAULT_TS_TX_OFFSET 2200 +#define CC1200_TSCH_DEFAULT_TS_RX_OFFSET (CC1200_TSCH_DEFAULT_TS_TX_OFFSET - CC1200_TSCH_PREAMBLE_LENGTH - (CC1200_TSCH_CONF_RX_WAIT / 2)) +#define CC1200_TSCH_DEFAULT_TS_RX_ACK_DELAY (CC1200_TSCH_DEFAULT_TS_TX_ACK_DELAY - CC1200_TSCH_PREAMBLE_LENGTH - (CC1200_TSCH_CONF_RX_ACK_WAIT / 2)) +#define CC1200_TSCH_DEFAULT_TS_TX_ACK_DELAY 1900 +#define CC1200_TSCH_DEFAULT_TS_RX_WAIT (CC1200_TSCH_PREAMBLE_LENGTH + CC1200_TSCH_CONF_RX_WAIT) +#define CC1200_TSCH_DEFAULT_TS_ACK_WAIT (CC1200_TSCH_PREAMBLE_LENGTH + CC1200_TSCH_CONF_RX_ACK_WAIT) +#define CC1200_TSCH_DEFAULT_TS_RX_TX 192 +#define CC1200_TSCH_DEFAULT_TS_MAX_ACK 168 /* 17+1+3 bytes at 1000 kbps */ +#define CC1200_TSCH_DEFAULT_TS_MAX_TX 1040 /* 126+1+3 bytes at 1000 kbps */ + +#define CC1200_TSCH_DEFAULT_SLACK_TIME 500 +/* Timeslot length: 5808 usec */ +#define CC1200_TSCH_DEFAULT_TS_TIMESLOT_LENGTH \ + ( CC1200_TSCH_DEFAULT_TS_TX_OFFSET \ + + CC1200_TSCH_DEFAULT_TS_MAX_TX \ + + CC1200_TSCH_DEFAULT_TS_TX_ACK_DELAY \ + + CC1200_TSCH_DEFAULT_TS_MAX_ACK \ + + CC1200_TSCH_DEFAULT_SLACK_TIME \ + ) + +/* TSCH timeslot timing (in rtimer ticks) */ +static uint16_t cc1200_1000kbps_tsch_timing[tsch_ts_elements_count] = { + CC1200_TSCH_DEFAULT_TS_CCA_OFFSET, + CC1200_TSCH_DEFAULT_TS_CCA, + CC1200_TSCH_DEFAULT_TS_TX_OFFSET, + CC1200_TSCH_DEFAULT_TS_RX_OFFSET, + CC1200_TSCH_DEFAULT_TS_RX_ACK_DELAY, + CC1200_TSCH_DEFAULT_TS_TX_ACK_DELAY, + CC1200_TSCH_DEFAULT_TS_RX_WAIT, + CC1200_TSCH_DEFAULT_TS_ACK_WAIT, + CC1200_TSCH_DEFAULT_TS_RX_TX, + CC1200_TSCH_DEFAULT_TS_MAX_ACK, + CC1200_TSCH_DEFAULT_TS_MAX_TX, + CC1200_TSCH_DEFAULT_TS_TIMESLOT_LENGTH, +}; + +static const registerSetting_t preferredSettings[]= +{ + {CC1200_IOCFG2, 0x06}, + {CC1200_SYNC_CFG1, 0xA8}, + {CC1200_DEVIATION_M, 0x47}, + {CC1200_MODCFG_DEV_E, 0x2F}, + {CC1200_DCFILT_CFG, 0x1E}, + {CC1200_PREAMBLE_CFG0, 0x8A}, + {CC1200_IQIC, 0x00}, + {CC1200_CHAN_BW, 0x01}, + {CC1200_MDMCFG1, 0x42}, + {CC1200_MDMCFG0, 0x05}, + {CC1200_SYMBOL_RATE2, 0xC9}, + {CC1200_SYMBOL_RATE1, 0x99}, + {CC1200_SYMBOL_RATE0, 0x99}, + {CC1200_AGC_REF, 0x2F}, + {CC1200_AGC_CS_THR, 0xF8}, + {CC1200_AGC_CFG2, 0x60}, + {CC1200_AGC_CFG1, 0x12}, + {CC1200_AGC_CFG0, 0x84}, + {CC1200_FIFO_CFG, 0x00}, + {CC1200_FS_CFG, 0x12}, + {CC1200_PKT_CFG2, 0x00}, + {CC1200_PKT_CFG0, 0x20}, + {CC1200_PKT_LEN, 0xFF}, + {CC1200_FREQOFF_CFG, 0x23}, + {CC1200_MDMCFG2, 0x00}, + {CC1200_FREQ2, 0x56}, + {CC1200_FREQ1, 0xCC}, + {CC1200_FREQ0, 0xCC}, + {CC1200_IF_ADC1, 0xEE}, + {CC1200_IF_ADC0, 0x10}, + {CC1200_FS_DIG1, 0x04}, + {CC1200_FS_DIG0, 0xA3}, + {CC1200_FS_CAL1, 0x40}, + {CC1200_FS_CAL0, 0x0E}, + {CC1200_FS_DIVTWO, 0x03}, + {CC1200_FS_DSM0, 0x33}, + {CC1200_FS_DVC1, 0xF7}, + {CC1200_FS_DVC0, 0x0F}, + {CC1200_FS_PFD, 0x00}, + {CC1200_FS_PRE, 0x6E}, + {CC1200_FS_REG_DIV_CML, 0x1C}, + {CC1200_FS_SPARE, 0xAC}, + {CC1200_FS_VCO0, 0xB5}, + {CC1200_IFAMP, 0x0D}, + {CC1200_XOSC5, 0x0E}, + {CC1200_XOSC1, 0x03}, +}; +/*---------------------------------------------------------------------------*/ +/* Global linkage: symbol name must be different in each exported file! */ +const cc1200_rf_cfg_t cc1200_868_4gfsk_1000kbps = { + .cfg_descriptor = rf_cfg_descriptor, + .register_settings = preferredSettings, + .size_of_register_settings = sizeof(preferredSettings), + .tx_pkt_lifetime = (RTIMER_SECOND), + .tx_rx_turnaround = (RTIMER_SECOND / 100), + /* Includes 3 Bytes preamble + 2 Bytes SFD, at 8usec per byte = 40 usec */ + /* Includes time to completion of "Wait for TX to start" if cc1200.c: 397 usec */ + .delay_before_tx = ((unsigned)US_TO_RTIMERTICKS(40 + 397 + 207)), + .delay_before_rx = (unsigned)US_TO_RTIMERTICKS(400), + .delay_before_detect = 0, + .chan_center_freq0 = RF_CFG_CHAN_CENTER_F0, + .chan_spacing = RF_CFG_CHAN_SPACING, + .min_channel = RF_CFG_MIN_CHANNEL, + .max_channel = RF_CFG_MAX_CHANNEL, + .max_txpower = RF_CFG_MAX_TXPOWER, + .cca_threshold = RF_CFG_CCA_THRESHOLD, + .rssi_offset = RF_CFG_RSSI_OFFSET, + .bitrate = 1000000, + .tsch_timing = cc1200_1000kbps_tsch_timing, +}; +/*---------------------------------------------------------------------------*/ From cad068d5e8aade998e5148491d773d78639ed164 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 3 Oct 2018 12:27:01 +0200 Subject: [PATCH 390/485] sixtop example: remove obsolete z1 configuration --- examples/6tisch/sixtop/project-conf.h | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/examples/6tisch/sixtop/project-conf.h b/examples/6tisch/sixtop/project-conf.h index 5235353c2..e3d82d972 100755 --- a/examples/6tisch/sixtop/project-conf.h +++ b/examples/6tisch/sixtop/project-conf.h @@ -78,25 +78,6 @@ /************* Other system configuration **************/ /*******************************************************/ -#if CONTIKI_TARGET_Z1 -/* Save some space to fit the limited RAM of the z1 */ -#define UIP_CONF_TCP 0 -#define QUEUEBUF_CONF_NUM 2 -#define NETSTACK_MAX_ROUTE_ENTRIES 2 -#define NBR_TABLE_CONF_MAX_NEIGHBORS 2 -#define UIP_CONF_ND6_SEND_NA 0 -#define SICSLOWPAN_CONF_FRAG 0 - -#if WITH_SECURITY -/* Note: on sky or z1 in cooja, crypto operations are done in S/W and - * cannot be accommodated in normal slots. Use 65ms slots instead, and - * a very short 6TiSCH minimal schedule length */ -#define TSCH_CONF_DEFAULT_TIMESLOT_LENGTH 65000 -#define TSCH_SCHEDULE_CONF_DEFAULT_LENGTH 2 -#endif /* WITH_SECURITY */ - -#endif /* CONTIKI_TARGET_Z1 */ - #if CONTIKI_TARGET_CC2538DK || CONTIKI_TARGET_ZOUL || \ CONTIKI_TARGET_OPENMOTE_CC2538 #define TSCH_CONF_HW_FRAME_FILTERING 0 From 4583fff0944a7c008abffa2e7109a6ccd7469d83 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 3 Oct 2018 12:42:06 +0200 Subject: [PATCH 391/485] Radio API: added values/objects for TSCH constants --- arch/cpu/cc2538/dev/cc2538-rf.c | 22 +++++++++++++++++++++ arch/dev/cc1200/cc1200.c | 35 +++++++++++++++++++++++++++++++++ os/dev/radio.h | 9 ++++++++- 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/arch/cpu/cc2538/dev/cc2538-rf.c b/arch/cpu/cc2538/dev/cc2538-rf.c index eea715653..990f0f787 100644 --- a/arch/cpu/cc2538/dev/cc2538-rf.c +++ b/arch/cpu/cc2538/dev/cc2538-rf.c @@ -862,6 +862,20 @@ get_value(radio_param_t param, radio_value_t *value) case RADIO_CONST_TXPOWER_MAX: *value = OUTPUT_POWER_MAX; return RADIO_RESULT_OK; + case RADIO_CONST_PHY_OVERHEAD: + *value = (radio_value_t)3; /* 1 len byte, 2 bytes CRC */ + case RADIO_CONST_BYTE_AIR_TIME: + *value = (radio_value_t)32; /* 250kbps data rate. One byte = 32us.*/ + return RADIO_RESULT_OK; + case RADIO_CONST_DELAY_BEFORE_TX: + *value = (radio_value_t)CC2538_DELAY_BEFORE_TX; + return RADIO_RESULT_OK; + case RADIO_CONST_DELAY_BEFORE_RX: + *value = (radio_value_t)CC2538_DELAY_BEFORE_RX; + return RADIO_RESULT_OK; + case RADIO_CONST_DELAY_BEFORE_DETECT: + *value = (radio_value_t)CC2538_DELAY_BEFORE_DETECT; + return RADIO_RESULT_OK; default: return RADIO_RESULT_NOT_SUPPORTED; } @@ -957,6 +971,14 @@ get_object(radio_param_t param, void *dest, size_t size) return RADIO_RESULT_OK; } + if(param == RADIO_CONST_TSCH_TIMING) { + if(size != sizeof(uint16_t *) || !dest) { + return RADIO_RESULT_INVALID_VALUE; + } + *(uint16_t **)dest = tsch_timeslot_timing_us_10000; + return RADIO_RESULT_OK; + } + return RADIO_RESULT_NOT_SUPPORTED; } /*---------------------------------------------------------------------------*/ diff --git a/arch/dev/cc1200/cc1200.c b/arch/dev/cc1200/cc1200.c index 3d9b1befc..d61618b6a 100644 --- a/arch/dev/cc1200/cc1200.c +++ b/arch/dev/cc1200/cc1200.c @@ -1180,6 +1180,34 @@ get_value(radio_param_t param, radio_value_t *value) *value = (radio_value_t)CC1200_RF_CFG.max_txpower; return RADIO_RESULT_OK; + case RADIO_CONST_PHY_OVERHEAD: +#if CC1200_802154G +#if CC1200_802154G_CRC16 + *value = (radio_value_t)4; /* 2 bytes PHR, 2 bytes CRC */ +#else + *value = (radio_value_t)6; /* 2 bytes PHR, 4 bytes CRC */ +#endif +#else + *value = (radio_value_t)3; /* 1 len byte, 2 bytes CRC */ +#endif + return RADIO_RESULT_OK; + + case RADIO_CONST_BYTE_AIR_TIME: + *value = (radio_value_t)8*1000*1000 / CC1200_RF_CFG.bitrate; + return RADIO_RESULT_OK; + + case RADIO_CONST_DELAY_BEFORE_TX: + *value = (radio_value_t)CC1200_RF_CFG.delay_before_tx; + return RADIO_RESULT_OK; + + case RADIO_CONST_DELAY_BEFORE_RX: + *value = (radio_value_t)CC1200_RF_CFG.delay_before_rx; + return RADIO_RESULT_OK; + + case RADIO_CONST_DELAY_BEFORE_DETECT: + *value = (radio_value_t)CC1200_RF_CFG.delay_before_detect; + return RADIO_RESULT_OK; + default: return RADIO_RESULT_NOT_SUPPORTED; @@ -1282,6 +1310,13 @@ set_value(radio_param_t param, radio_value_t value) static radio_result_t get_object(radio_param_t param, void *dest, size_t size) { + if(param == RADIO_CONST_TSCH_TIMING) { + if(size != sizeof(uint16_t *) || !dest) { + return RADIO_RESULT_INVALID_VALUE; + } + *(uint16_t **)dest = CC1200_RF_CFG.tsch_timing; + return RADIO_RESULT_OK; + } return RADIO_RESULT_NOT_SUPPORTED; diff --git a/os/dev/radio.h b/os/dev/radio.h index 9bbef9619..e6ca64f3d 100644 --- a/os/dev/radio.h +++ b/os/dev/radio.h @@ -183,7 +183,14 @@ enum { /* The minimum transmission power in dBm. */ RADIO_CONST_TXPOWER_MIN, /* The maximum transmission power in dBm. */ - RADIO_CONST_TXPOWER_MAX + RADIO_CONST_TXPOWER_MAX, + + RADIO_CONST_TSCH_TIMING, + RADIO_CONST_PHY_OVERHEAD, + RADIO_CONST_BYTE_AIR_TIME, + RADIO_CONST_DELAY_BEFORE_TX, + RADIO_CONST_DELAY_BEFORE_RX, + RADIO_CONST_DELAY_BEFORE_DETECT, }; /* Radio power modes */ From 423412d99cfec2797166a2034db50cfd430373da Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 3 Oct 2018 12:47:10 +0200 Subject: [PATCH 392/485] TSCH: set max hopping sequence length to default hopping sequence --- os/net/mac/tsch/tsch-conf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/net/mac/tsch/tsch-conf.h b/os/net/mac/tsch/tsch-conf.h index 8613eb0e3..ebec4d4c0 100644 --- a/os/net/mac/tsch/tsch-conf.h +++ b/os/net/mac/tsch/tsch-conf.h @@ -151,7 +151,7 @@ #ifdef TSCH_CONF_HOPPING_SEQUENCE_MAX_LEN #define TSCH_HOPPING_SEQUENCE_MAX_LEN TSCH_CONF_HOPPING_SEQUENCE_MAX_LEN #else -#define TSCH_HOPPING_SEQUENCE_MAX_LEN 16 +#define TSCH_HOPPING_SEQUENCE_MAX_LEN sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE) #endif /******** Configuration: association *******/ From 3ba1b43bd965d7efc13353a18db0a9721aebaac4 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 3 Oct 2018 12:59:52 +0200 Subject: [PATCH 393/485] TSCH: define SYNC_IE_BOUND from timing in use rather than default --- os/net/mac/tsch/tsch-slot-operation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/net/mac/tsch/tsch-slot-operation.c b/os/net/mac/tsch/tsch-slot-operation.c index 843b79f42..a6f6e1da9 100644 --- a/os/net/mac/tsch/tsch-slot-operation.c +++ b/os/net/mac/tsch/tsch-slot-operation.c @@ -94,7 +94,7 @@ /* Truncate received drift correction information to maximum half * of the guard time (one fourth of TSCH_DEFAULT_TS_RX_WAIT) */ -#define SYNC_IE_BOUND ((int32_t)US_TO_RTIMERTICKS(TSCH_DEFAULT_TS_RX_WAIT / 4)) +#define SYNC_IE_BOUND ((int32_t)US_TO_RTIMERTICKS(tsch_timing_us[tsch_ts_rx_wait] / 4)) /* By default: check that rtimer runs at >=32kHz and use a guard time of 10us */ #if RTIMER_SECOND < (32 * 1024) From ace15d64992a2f6d2434d4877666a91a327ed5e1 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 3 Oct 2018 13:01:21 +0200 Subject: [PATCH 394/485] TSCH: when receiving, bound packet duration with MaxTx from timing template --- os/net/mac/tsch/tsch-slot-operation.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/os/net/mac/tsch/tsch-slot-operation.c b/os/net/mac/tsch/tsch-slot-operation.c index a6f6e1da9..5c7dc904d 100644 --- a/os/net/mac/tsch/tsch-slot-operation.c +++ b/os/net/mac/tsch/tsch-slot-operation.c @@ -789,6 +789,8 @@ PT_THREAD(tsch_rx_slot(struct pt *pt, struct rtimer *t)) #endif packet_duration = TSCH_PACKET_DURATION(current_input->len); + /* limit packet_duration to its max value */ + packet_duration = MIN(packet_duration, tsch_timing[tsch_ts_max_tx]); if(!frame_valid) { TSCH_LOG_ADD(tsch_log_message, From 17c21582297d63b6d1d6c188bd4ce027113783ab Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 3 Oct 2018 13:16:19 +0200 Subject: [PATCH 395/485] TSCH: when scanning, set channel periodically regardless of previous channel --- os/net/mac/tsch/tsch.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/os/net/mac/tsch/tsch.c b/os/net/mac/tsch/tsch.c index c040826ca..c4e097e07 100644 --- a/os/net/mac/tsch/tsch.c +++ b/os/net/mac/tsch/tsch.c @@ -730,11 +730,11 @@ PT_THREAD(tsch_scan(struct pt *pt)) /* Pick a channel at random in TSCH_JOIN_HOPPING_SEQUENCE */ uint8_t scan_channel = TSCH_JOIN_HOPPING_SEQUENCE[ random_rand() % sizeof(TSCH_JOIN_HOPPING_SEQUENCE)]; - if(current_channel != scan_channel) { - NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, scan_channel); - current_channel = scan_channel; - LOG_INFO("scanning on channel %u\n", scan_channel); - } + + NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, scan_channel); + current_channel = scan_channel; + LOG_INFO("scanning on channel %u\n", scan_channel); + current_channel_since = now_time; } From e6dec9ee4a4e1685ddc755fd81639858747e6f39 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 3 Oct 2018 13:16:59 +0200 Subject: [PATCH 396/485] TSCH: before associating on an EB, check that the Rx timestamp is sensible --- os/net/mac/tsch/tsch.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/os/net/mac/tsch/tsch.c b/os/net/mac/tsch/tsch.c index c4e097e07..ffdf46e3a 100644 --- a/os/net/mac/tsch/tsch.c +++ b/os/net/mac/tsch/tsch.c @@ -749,16 +749,26 @@ PT_THREAD(tsch_scan(struct pt *pt)) } if(is_packet_pending) { + rtimer_clock_t t1; /* Read packet */ input_eb.len = NETSTACK_RADIO.read(input_eb.payload, TSCH_PACKET_MAX_LEN); /* Save packet timestamp */ NETSTACK_RADIO.get_object(RADIO_PARAM_LAST_PACKET_TIMESTAMP, &t0, sizeof(rtimer_clock_t)); + t1 = RTIMER_NOW(); /* Parse EB and attempt to associate */ LOG_INFO("scan: received packet (%u bytes) on channel %u\n", input_eb.len, current_channel); - tsch_associate(&input_eb, t0); + /* Sanity-check the timestamp */ + if(ABS(RTIMER_CLOCK_DIFF(t0, t1)) < tsch_timing[tsch_ts_timeslot_length]) { + tsch_associate(&input_eb, t0); + } else { + LOG_WARN("scan: dropping packet, timestamp too far from current time %u %u\n", + (unsigned)t0, + (unsigned)t1 + ); + } } if(tsch_is_associated) { From a09fb40bf77e926e5414aa7de500a8065b7e422e Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 3 Oct 2018 13:28:50 +0200 Subject: [PATCH 397/485] CC1200: add SFD timestamping and RSSI features --- arch/dev/cc1200/cc1200.c | 73 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/arch/dev/cc1200/cc1200.c b/arch/dev/cc1200/cc1200.c index d61618b6a..c7a8faee2 100644 --- a/arch/dev/cc1200/cc1200.c +++ b/arch/dev/cc1200/cc1200.c @@ -47,6 +47,9 @@ #include #include +static int16_t rssi; +static rtimer_clock_t sfd_timestamp = 0; + /*---------------------------------------------------------------------------*/ /* Various implementation specific defines */ /*---------------------------------------------------------------------------*/ @@ -249,6 +252,8 @@ extern const cc1200_rf_cfg_t CC1200_RF_CFG; #define RF_UPDATE_CHANNEL 0x10 /* SPI was locked when calling RX interrupt, let the pollhandler do the job */ #define RF_POLL_RX_INTERRUPT 0x20 +/* Ongoing reception */ +#define RF_RX_ONGOING 0x40 /* Force calibration in case we don't use CC1200 AUTOCAL + timeout */ #if !CC1200_AUTOCAL #if CC1200_CAL_TIMEOUT_SECONDS @@ -861,7 +866,7 @@ read(void *buf, unsigned short buf_len) if(rx_pkt_len > 0) { - int8_t rssi = rx_pkt[rx_pkt_len - 2]; + rssi = (int8_t)rx_pkt[rx_pkt_len - 2] + (int)CC1200_RF_CFG.rssi_offset; /* CRC is already checked */ uint8_t crc_lqi = rx_pkt[rx_pkt_len - 1]; @@ -1106,6 +1111,40 @@ off(void) } /*---------------------------------------------------------------------------*/ +/** + * \brief Reads the current signal strength (RSSI) + * \return The current RSSI in dBm + * + * This function reads the current RSSI on the currently configured + * channel. + */ +static int16_t +get_rssi(void) +{ + int16_t rssi0, rssi1; + uint8_t was_off = 0; + + /* If we are off, turn on first */ + if(!(rf_flags & RF_ON)) { + was_off = 1; + on(); + } + + /* Wait for CARRIER_SENSE_VALID signal */ + BUSYWAIT_UNTIL(((rssi0 = single_read(CC1200_RSSI0)) + & CC1200_CARRIER_SENSE_VALID), + RTIMER_SECOND / 100); + RF_ASSERT(rssi0 & CC1200_CARRIER_SENSE_VALID); + rssi1 = (int8_t)single_read(CC1200_RSSI1) + (int)CC1200_RF_CFG.rssi_offset; + + /* If we were off, turn back off */ + if(was_off) { + off(); + } + + return rssi1; +} +/*---------------------------------------------------------------------------*/ /* Get a radio parameter value. */ static radio_result_t get_value(radio_param_t param, radio_value_t *value) @@ -1156,6 +1195,13 @@ get_value(radio_param_t param, radio_value_t *value) return RADIO_RESULT_OK; case RADIO_PARAM_RSSI: + *value = get_rssi(); + return RADIO_RESULT_OK; + + case RADIO_PARAM_LAST_RSSI: + *value = (radio_value_t)rssi; + return RADIO_RESULT_OK; + case RADIO_PARAM_64BIT_ADDR: return RADIO_RESULT_NOT_SUPPORTED; @@ -1310,6 +1356,14 @@ set_value(radio_param_t param, radio_value_t value) static radio_result_t get_object(radio_param_t param, void *dest, size_t size) { + if(param == RADIO_PARAM_LAST_PACKET_TIMESTAMP) { + if(size != sizeof(rtimer_clock_t) || !dest) { + return RADIO_RESULT_INVALID_VALUE; + } + *(rtimer_clock_t *)dest = sfd_timestamp; + return RADIO_RESULT_OK; + } + if(param == RADIO_CONST_TSCH_TIMING) { if(size != sizeof(uint16_t *) || !dest) { return RADIO_RESULT_INVALID_VALUE; @@ -2239,6 +2293,23 @@ cc1200_rx_interrupt(void) */ static uint8_t buf[CC1200_MAX_PAYLOAD_LEN + APPENDIX_LEN]; + /* + * If CC1200_USE_GPIO2 is enabled, we come here either once RX FIFO + * threshold is reached (GPIO2 rising edge) + * or at the end of the packet (GPIO0 falling edge). + */ +#if CC1200_USE_GPIO2 + int gpio2 = cc1200_arch_gpio2_read_pin(); + int gpio0 = cc1200_arch_gpio0_read_pin(); + if((rf_flags & RF_RX_ONGOING) == 0 && gpio2 > 0) { + rf_flags |= RF_RX_ONGOING; + sfd_timestamp = RTIMER_NOW(); + } + if(gpio0 == 0) { + rf_flags &= ~RF_RX_ONGOING; + } +#endif + if(SPI_IS_LOCKED()) { /* From e18660367bea831c52da9e6dd1643fc63d9c7629 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 3 Oct 2018 13:29:47 +0200 Subject: [PATCH 398/485] CC1200: disable debug by default --- arch/dev/cc1200/cc1200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/dev/cc1200/cc1200.c b/arch/dev/cc1200/cc1200.c index c7a8faee2..2873c0629 100644 --- a/arch/dev/cc1200/cc1200.c +++ b/arch/dev/cc1200/cc1200.c @@ -60,7 +60,7 @@ static rtimer_clock_t sfd_timestamp = 0; * - 2: Print errors + warnings (recoverable errors) * - 3: Print errors + warnings + information (what's going on...) */ -#define DEBUG_LEVEL 2 +#define DEBUG_LEVEL 0 /* * RF test mode. Blocks inside "configure()". * - Set this parameter to 1 in order to produce an modulated carrier (PN9) From ddeeb63ddd53c4b12b8d5090c9882eba43e03bf7 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 3 Oct 2018 13:31:33 +0200 Subject: [PATCH 399/485] CC1200 set_channel: compute channel within bounds from any input channel --- arch/dev/cc1200/cc1200.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/dev/cc1200/cc1200.c b/arch/dev/cc1200/cc1200.c index 2873c0629..d2b7db770 100644 --- a/arch/dev/cc1200/cc1200.c +++ b/arch/dev/cc1200/cc1200.c @@ -2115,6 +2115,9 @@ set_channel(uint8_t channel) uint8_t was_off = 0; uint32_t freq; + channel %= (CC1200_RF_CFG.max_channel - CC1200_RF_CFG.min_channel + 1); + channel += CC1200_RF_CFG.min_channel; + #if 0 /* * We explicitly allow a channel update even if the channel does not change. From 64ce406ae4e0b4c96b4a3ab7bf0e3f15abbb6f7b Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 3 Oct 2018 13:33:29 +0200 Subject: [PATCH 400/485] Zoul: TSCH configuration assuming not only cc2538 --- arch/cpu/cc2538/cc2538-def.h | 21 +++------------- arch/platform/zoul/contiki-conf.h | 41 ++++++++++++++++++++++++++++++ arch/platform/zoul/platform.c | 42 +++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 18 deletions(-) diff --git a/arch/cpu/cc2538/cc2538-def.h b/arch/cpu/cc2538/cc2538-def.h index e4c7451a6..75195258e 100644 --- a/arch/cpu/cc2538/cc2538-def.h +++ b/arch/cpu/cc2538/cc2538-def.h @@ -37,26 +37,11 @@ #define RTIMER_ARCH_SECOND 32768 /*---------------------------------------------------------------------------*/ /* 352us from calling transmit() until the SFD byte has been sent */ -#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(352)) +#define CC2538_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(352)) /* 192us as in datasheet but ACKs are not always received, so adjusted to 250us */ -#define RADIO_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(250)) -#define RADIO_DELAY_BEFORE_DETECT 0 -#ifndef TSCH_CONF_BASE_DRIFT_PPM -/* The drift compared to "true" 10ms slots. - * Enable adaptive sync to enable compensation for this. - * Slot length 10000 usec - * 328 ticks - * Tick duration 30.517578125 usec - * Real slot duration 10009.765625 usec - * Target - real duration = -9.765625 usec - * TSCH_CONF_BASE_DRIFT_PPM -977 - */ -#define TSCH_CONF_BASE_DRIFT_PPM -977 -#endif +#define CC2538_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(250)) +#define CC2538_DELAY_BEFORE_DETECT 0 -#if MAC_CONF_WITH_TSCH -#define TSCH_CONF_HW_FRAME_FILTERING 0 -#endif /* MAC_CONF_WITH_TSCH */ /*---------------------------------------------------------------------------*/ #define SPI_CONF_CONTROLLER_COUNT 2 /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/zoul/contiki-conf.h b/arch/platform/zoul/contiki-conf.h index 098c37404..b8f545bf0 100644 --- a/arch/platform/zoul/contiki-conf.h +++ b/arch/platform/zoul/contiki-conf.h @@ -55,6 +55,47 @@ #endif /* PROJECT_CONF_PATH */ /*---------------------------------------------------------------------------*/ #include "cc2538-def.h" + +unsigned radio_phy_overhead(void); +unsigned radio_byte_air_time(void); +unsigned radio_delay_before_tx(void); +unsigned radio_delay_before_rx(void); +unsigned radio_delay_before_detect(void); +uint16_t *radio_tsch_timeslot_timing(void); + +/** @} */ +/*---------------------------------------------------------------------------*/ +/* 352us from calling transmit() until the SFD byte has been sent */ +#define CC2538_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(352)) +/* 192us as in datasheet but ACKs are not always received, so adjusted to 250us */ +#define CC2538_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(250)) +#define CC2538_DELAY_BEFORE_DETECT 0 + +#define RADIO_PHY_OVERHEAD radio_phy_overhead() +#define RADIO_BYTE_AIR_TIME radio_byte_air_time() +#define RADIO_DELAY_BEFORE_TX radio_delay_before_tx() +#define RADIO_DELAY_BEFORE_RX radio_delay_before_rx() +#define RADIO_DELAY_BEFORE_DETECT radio_delay_before_detect() + +#define TSCH_CONF_DEFAULT_TIMESLOT_TIMING radio_tsch_timeslot_timing() + +#ifndef TSCH_CONF_BASE_DRIFT_PPM +/* The drift compared to "true" 10ms slots. + * Enable adaptive sync to enable compensation for this. + * Slot length 10000 usec + * 328 ticks + * Tick duration 30.517578125 usec + * Real slot duration 10009.765625 usec + * Target - real duration = -9.765625 usec + * TSCH_CONF_BASE_DRIFT_PPM -977 + */ +#define TSCH_CONF_BASE_DRIFT_PPM -977 +#endif + +#if MAC_CONF_WITH_TSCH +#define TSCH_CONF_HW_FRAME_FILTERING 0 +#endif /* MAC_CONF_WITH_TSCH */ + /*---------------------------------------------------------------------------*/ /** * \name Serial Boot Loader Backdoor configuration diff --git a/arch/platform/zoul/platform.c b/arch/platform/zoul/platform.c index 703f0e521..bed948829 100644 --- a/arch/platform/zoul/platform.c +++ b/arch/platform/zoul/platform.c @@ -257,6 +257,48 @@ platform_idle() lpm_enter(); } /*---------------------------------------------------------------------------*/ +unsigned +radio_phy_overhead(void) { + radio_value_t ret; + NETSTACK_RADIO.get_value(RADIO_CONST_PHY_OVERHEAD, &ret); + return (unsigned)ret; +} +/*---------------------------------------------------------------------------*/ +unsigned +radio_byte_air_time(void) { + radio_value_t ret; + NETSTACK_RADIO.get_value(RADIO_CONST_BYTE_AIR_TIME, &ret); + return (unsigned)ret; +} +/*---------------------------------------------------------------------------*/ +unsigned +radio_delay_before_tx(void) { + radio_value_t ret; + NETSTACK_RADIO.get_value(RADIO_CONST_DELAY_BEFORE_TX, &ret); + return (unsigned)ret; +} +/*---------------------------------------------------------------------------*/ +unsigned +radio_delay_before_rx(void) { + radio_value_t ret; + NETSTACK_RADIO.get_value(RADIO_CONST_DELAY_BEFORE_RX, &ret); + return (unsigned)ret; +} +/*---------------------------------------------------------------------------*/ +unsigned +radio_delay_before_detect(void) { + radio_value_t ret; + NETSTACK_RADIO.get_value(RADIO_CONST_DELAY_BEFORE_DETECT, &ret); + return (unsigned)ret; +} +/*---------------------------------------------------------------------------*/ +uint16_t * +radio_tsch_timeslot_timing(void) { + uint16_t *ret; + NETSTACK_RADIO.get_object(RADIO_CONST_TSCH_TIMING, &ret, sizeof(ret)); + return ret; +} +/*---------------------------------------------------------------------------*/ /** * @} * @} From 572c6725d393c95cef00b0ef25dbde20b70a912a Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 3 Oct 2018 13:35:09 +0200 Subject: [PATCH 401/485] TSCH: configurable byte air time and PHY overhead --- arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-def.h | 4 ++++ arch/cpu/simplelink-cc13xx-cc26xx/cc13xx-cc26xx-def.h | 4 ++++ arch/platform/cooja/contiki-conf.h | 4 ++++ arch/platform/jn516x/jn516x-def.h | 4 ++++ arch/platform/sky/sky-def.h | 5 +++++ os/net/mac/tsch/tsch-const.h | 2 +- 6 files changed, 22 insertions(+), 1 deletion(-) diff --git a/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-def.h b/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-def.h index 525357253..47dbc4eb5 100644 --- a/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-def.h +++ b/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-def.h @@ -36,6 +36,10 @@ /*---------------------------------------------------------------------------*/ /* TSCH related defines */ +/* 1 len byte, 2 bytes CRC */ +#define RADIO_PHY_OVERHEAD 3 +/* 250kbps data rate. One byte = 32us */ +#define RADIO_BYTE_AIR_TIME 32 /* Delay between GO signal and SFD */ #define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(81)) /* Delay between GO signal and start listening. diff --git a/arch/cpu/simplelink-cc13xx-cc26xx/cc13xx-cc26xx-def.h b/arch/cpu/simplelink-cc13xx-cc26xx/cc13xx-cc26xx-def.h index 44ac92cf7..5bcde9d93 100644 --- a/arch/cpu/simplelink-cc13xx-cc26xx/cc13xx-cc26xx-def.h +++ b/arch/cpu/simplelink-cc13xx-cc26xx/cc13xx-cc26xx-def.h @@ -57,6 +57,10 @@ /*---------------------------------------------------------------------------*/ /* TSCH related defines */ +/* 1 len byte, 2 bytes CRC */ +#define RADIO_PHY_OVERHEAD 3 +/* 250kbps data rate. One byte = 32us */ +#define RADIO_BYTE_AIR_TIME 32 /* Delay between GO signal and SFD */ #define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(81)) /* Delay between GO signal and start listening. diff --git a/arch/platform/cooja/contiki-conf.h b/arch/platform/cooja/contiki-conf.h index 4942b0ab6..44c984dbf 100644 --- a/arch/platform/cooja/contiki-conf.h +++ b/arch/platform/cooja/contiki-conf.h @@ -122,6 +122,10 @@ typedef unsigned long clock_time_t; /* Use 64-bit rtimer (default in Contiki-NG is 32) */ #define RTIMER_CONF_CLOCK_SIZE 8 +/* 1 len byte, 2 bytes CRC */ +#define RADIO_PHY_OVERHEAD 3 +/* 250kbps data rate. One byte = 32us */ +#define RADIO_BYTE_AIR_TIME 32 #define RADIO_DELAY_BEFORE_TX 0 #define RADIO_DELAY_BEFORE_RX 0 #define RADIO_DELAY_BEFORE_DETECT 0 diff --git a/arch/platform/jn516x/jn516x-def.h b/arch/platform/jn516x/jn516x-def.h index a4ee45c75..a7d8906f9 100644 --- a/arch/platform/jn516x/jn516x-def.h +++ b/arch/platform/jn516x/jn516x-def.h @@ -38,6 +38,10 @@ #undef putchar +/* 1 len byte, 2 bytes CRC */ +#define RADIO_PHY_OVERHEAD 3 +/* 250kbps data rate. One byte = 32us */ +#define RADIO_BYTE_AIR_TIME 32 /* Delay between GO signal and SFD * Measured 153us between GO and preamble. Add 5 bytes (preamble + SFD) air time: 153+5*32 = 313 */ #define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(313)) diff --git a/arch/platform/sky/sky-def.h b/arch/platform/sky/sky-def.h index edab43ee7..1077563a3 100644 --- a/arch/platform/sky/sky-def.h +++ b/arch/platform/sky/sky-def.h @@ -43,6 +43,11 @@ * Definitions below are dictated by the hardware and not really * changeable! */ + + /* 1 len byte, 2 bytes CRC */ + #define RADIO_PHY_OVERHEAD 3 + /* 250kbps data rate. One byte = 32us */ + #define RADIO_BYTE_AIR_TIME 32 /* Delay between GO signal and SFD: radio fixed delay + 4Bytes preample + 1B SFD -- 1Byte time is 32us * ~327us + 129preample = 456 us */ #define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(456)) diff --git a/os/net/mac/tsch/tsch-const.h b/os/net/mac/tsch/tsch-const.h index 81ca7ffa8..a5bafbc64 100644 --- a/os/net/mac/tsch/tsch-const.h +++ b/os/net/mac/tsch/tsch-const.h @@ -80,7 +80,7 @@ /* Calculate packet tx/rx duration in rtimer ticks based on sent * packet len in bytes with 802.15.4 250kbps data rate. * One byte = 32us. Add two bytes for CRC and one for len field */ -#define TSCH_PACKET_DURATION(len) US_TO_RTIMERTICKS(32 * ((len) + 3)) +#define TSCH_PACKET_DURATION(len) US_TO_RTIMERTICKS(RADIO_BYTE_AIR_TIME * ((len) + RADIO_PHY_OVERHEAD)) /* Convert rtimer ticks to clock and vice versa */ #define TSCH_CLOCK_TO_TICKS(c) (((c) * RTIMER_SECOND) / CLOCK_SECOND) From 665f21592f5962261c798f668bc318cb2a1b5b64 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 3 Oct 2018 13:35:34 +0200 Subject: [PATCH 402/485] TSCH: compute TSCH_SLOTS_PER_SECOND based on current timeslot timings rather than default --- os/net/mac/tsch/tsch-const.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/net/mac/tsch/tsch-const.h b/os/net/mac/tsch/tsch-const.h index a5bafbc64..78634dd42 100644 --- a/os/net/mac/tsch/tsch-const.h +++ b/os/net/mac/tsch/tsch-const.h @@ -75,7 +75,7 @@ #define TSCH_TIMESYNC_MEASUREMENT_ERROR US_TO_RTIMERTICKS(32) /* The approximate number of slots per second */ -#define TSCH_SLOTS_PER_SECOND (1000000 / TSCH_DEFAULT_TS_TIMESLOT_LENGTH) +#define TSCH_SLOTS_PER_SECOND (1000000 / tsch_timing_us[tsch_ts_timeslot_length]) /* Calculate packet tx/rx duration in rtimer ticks based on sent * packet len in bytes with 802.15.4 250kbps data rate. From ddde2aebdc654ab3da0b945549594474e0848659 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 3 Oct 2018 13:36:00 +0200 Subject: [PATCH 403/485] jn516x example: compute sample_count on current timeslot timings rather than defaults --- .../jn516x/tsch/simple-sensor-network/node/node.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/platform-specific/jn516x/tsch/simple-sensor-network/node/node.c b/examples/platform-specific/jn516x/tsch/simple-sensor-network/node/node.c index df72b69b3..251b0d135 100644 --- a/examples/platform-specific/jn516x/tsch/simple-sensor-network/node/node.c +++ b/examples/platform-specific/jn516x/tsch/simple-sensor-network/node/node.c @@ -194,7 +194,7 @@ PROCESS_THREAD(node_process, ev, data) if (host_found) { /* Make sample count dependent on asn. After a disconnect, waveforms remain synchronous. Use node_mac to create phase offset between waveforms in different nodes */ - sample_count = ((tsch_current_asn.ls4b/((1000/(TSCH_CONF_DEFAULT_TIMESLOT_LENGTH/1000)))/INTERVAL)+node_mac[7]) % (SIZE_OF_WAVEFORM-1); + sample_count = ((tsch_current_asn.ls4b/((1000/(tsch_timing_us[tsch_ts_timeslot_length]/1000)))/INTERVAL)+node_mac[7]) % (SIZE_OF_WAVEFORM-1); printf("%d sec. waveform=%s. cnt=%d. value=%d\n", total_time, waveform_table[selected_waveform].str, sample_count, waveform_table[selected_waveform].table[sample_count]); my_sprintf(udp_buf, waveform_table[selected_waveform].table[sample_count]); uip_udp_packet_send(udp_conn_tx, udp_buf, strlen(udp_buf)); From 5497dc1e203be2aaee6ff91db9fde2d0dd61b2cf Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 3 Oct 2018 13:36:46 +0200 Subject: [PATCH 404/485] TSCH: timeslot timings as a structure, for flexible configuration --- arch/cpu/cc2538/dev/cc2538-rf.c | 1 + arch/platform/sky/contiki-conf.h | 7 ++-- arch/platform/sky/platform.c | 17 ++++++++ os/net/mac/tsch/tsch-conf.h | 12 +++--- os/net/mac/tsch/tsch-const.h | 71 -------------------------------- os/net/mac/tsch/tsch.c | 54 ++++++++++++++++-------- os/net/mac/tsch/tsch.h | 4 ++ tools/viewconf/viewconf.c | 6 +-- 8 files changed, 72 insertions(+), 100 deletions(-) diff --git a/arch/cpu/cc2538/dev/cc2538-rf.c b/arch/cpu/cc2538/dev/cc2538-rf.c index 990f0f787..d3d2d2dff 100644 --- a/arch/cpu/cc2538/dev/cc2538-rf.c +++ b/arch/cpu/cc2538/dev/cc2538-rf.c @@ -42,6 +42,7 @@ #include "net/packetbuf.h" #include "net/linkaddr.h" #include "net/netstack.h" +#include "net/mac/tsch/tsch.h" #include "sys/energest.h" #include "dev/cc2538-rf.h" #include "dev/rfcore.h" diff --git a/arch/platform/sky/contiki-conf.h b/arch/platform/sky/contiki-conf.h index 8df4549ef..cf0a1e9ac 100644 --- a/arch/platform/sky/contiki-conf.h +++ b/arch/platform/sky/contiki-conf.h @@ -17,11 +17,12 @@ #define NETSTACK_CONF_RADIO cc2420_driver #endif /* NETSTACK_CONF_RADIO */ +extern uint16_t tsch_timeslot_timing_us_15000[]; /* The TSCH default slot length of 10ms is a bit too short for this platform, * use 15ms instead. */ -#ifndef TSCH_CONF_DEFAULT_TIMESLOT_LENGTH -#define TSCH_CONF_DEFAULT_TIMESLOT_LENGTH 15000 -#endif /* TSCH_CONF_DEFAULT_TIMESLOT_LENGTH */ +#ifndef TSCH_CONF_DEFAULT_TIMESLOT_TIMING +#define TSCH_CONF_DEFAULT_TIMESLOT_TIMING tsch_timeslot_timing_us_15000 +#endif /* TSCH_CONF_DEFAULT_TIMESLOT_TIMING */ /* Save RAM through a smaller uIP buffer */ #ifndef UIP_CONF_BUFFER_SIZE diff --git a/arch/platform/sky/platform.c b/arch/platform/sky/platform.c index 89d18d3e8..90a856520 100644 --- a/arch/platform/sky/platform.c +++ b/arch/platform/sky/platform.c @@ -43,6 +43,7 @@ #include "lib/random.h" #include "net/netstack.h" #include "net/mac/framer/frame802154.h" +#include "net/mac/tsch/tsch.h" #if NETSTACK_CONF_WITH_IPV6 #include "net/ipv6/uip-ds6.h" @@ -63,6 +64,22 @@ extern int msp430_dco_required; #include "experiment-setup.h" #endif +/* TSCH timeslot timing for platforms requiring 15ms slots */ +uint16_t tsch_timeslot_timing_us_15000[tsch_ts_elements_count] = { + 1800, /* CCAOffset */ + 128, /* CCA */ + 4000, /* TxOffset */ + (4000 - (TSCH_CONF_RX_WAIT / 2)), /* RxOffset */ + 3600, /* RxAckDelay */ + 4000, /* TxAckDelay */ + TSCH_CONF_RX_WAIT, /* RxWait */ + 800, /* AckWait */ + 2072, /* RxTx */ + 2400, /* MaxAck */ + 4256, /* MaxTx */ + 15000, /* TimeslotLength */ +}; + void init_platform(void); /*---------------------------------------------------------------------------*/ /* Log configuration */ diff --git a/os/net/mac/tsch/tsch-conf.h b/os/net/mac/tsch/tsch-conf.h index ebec4d4c0..c1611e200 100644 --- a/os/net/mac/tsch/tsch-conf.h +++ b/os/net/mac/tsch/tsch-conf.h @@ -415,12 +415,12 @@ by default, useful in case of duplicate seqno */ #define TSCH_RADIO_ON_DURING_TIMESLOT 0 #endif - - -/* Timeslot timing */ -#ifndef TSCH_CONF_DEFAULT_TIMESLOT_LENGTH -#define TSCH_CONF_DEFAULT_TIMESLOT_LENGTH 10000 -#endif /* TSCH_CONF_DEFAULT_TIMESLOT_LENGTH */ +/* TSCH timeslot timing template */ +#ifdef TSCH_CONF_DEFAULT_TIMESLOT_TIMING +#define TSCH_DEFAULT_TIMESLOT_TIMING TSCH_CONF_DEFAULT_TIMESLOT_TIMING +#else +#define TSCH_DEFAULT_TIMESLOT_TIMING tsch_timeslot_timing_us_10000 +#endif /* Configurable Rx guard time is micro-seconds */ #ifndef TSCH_CONF_RX_WAIT diff --git a/os/net/mac/tsch/tsch-const.h b/os/net/mac/tsch/tsch-const.h index 78634dd42..edc989378 100644 --- a/os/net/mac/tsch/tsch-const.h +++ b/os/net/mac/tsch/tsch-const.h @@ -86,76 +86,5 @@ #define TSCH_CLOCK_TO_TICKS(c) (((c) * RTIMER_SECOND) / CLOCK_SECOND) #define TSCH_CLOCK_TO_SLOTS(c, timeslot_length) (TSCH_CLOCK_TO_TICKS(c) / timeslot_length) -/* The default timeslot timing in the standard is a guard time of - * 2200 us, a Tx offset of 2120 us and a Rx offset of 1120 us. - * As a result, the listening device has a guard time not centered - * on the expected Tx time. This is to be fixed in the next iteration - * of the standard. This can be enabled with: - * #define TSCH_DEFAULT_TS_TX_OFFSET 2120 - * #define TSCH_DEFAULT_TS_RX_OFFSET 1120 - * #define TSCH_DEFAULT_TS_RX_WAIT 2200 - * - * Instead, we align the Rx guard time on expected Tx time. The Rx - * guard time is user-configurable with TSCH_CONF_RX_WAIT. - - * (TS_TX_OFFSET - (TS_RX_WAIT / 2)) instead */ - -#if TSCH_CONF_DEFAULT_TIMESLOT_LENGTH == 10000 -/* Default timeslot timing as per IEEE 802.15.4e */ - -#define TSCH_DEFAULT_TS_CCA_OFFSET 1800 -#define TSCH_DEFAULT_TS_CCA 128 -#define TSCH_DEFAULT_TS_TX_OFFSET 2120 -#define TSCH_DEFAULT_TS_RX_OFFSET (TSCH_DEFAULT_TS_TX_OFFSET - (TSCH_CONF_RX_WAIT / 2)) -#define TSCH_DEFAULT_TS_RX_ACK_DELAY 800 -#define TSCH_DEFAULT_TS_TX_ACK_DELAY 1000 -#define TSCH_DEFAULT_TS_RX_WAIT TSCH_CONF_RX_WAIT -#define TSCH_DEFAULT_TS_ACK_WAIT 400 -#define TSCH_DEFAULT_TS_RX_TX 192 -#define TSCH_DEFAULT_TS_MAX_ACK 2400 -#define TSCH_DEFAULT_TS_MAX_TX 4256 -#define TSCH_DEFAULT_TS_TIMESLOT_LENGTH 10000 - -#elif TSCH_CONF_DEFAULT_TIMESLOT_LENGTH == 15000 -/* Default timeslot timing for platforms requiring 15ms slots */ - -#define TSCH_DEFAULT_TS_CCA_OFFSET 1800 -#define TSCH_DEFAULT_TS_CCA 128 -#define TSCH_DEFAULT_TS_TX_OFFSET 4000 -#define TSCH_DEFAULT_TS_RX_OFFSET (TSCH_DEFAULT_TS_TX_OFFSET - (TSCH_CONF_RX_WAIT / 2)) -#define TSCH_DEFAULT_TS_RX_ACK_DELAY 3600 -#define TSCH_DEFAULT_TS_TX_ACK_DELAY 4000 -#define TSCH_DEFAULT_TS_RX_WAIT TSCH_CONF_RX_WAIT -#define TSCH_DEFAULT_TS_ACK_WAIT 800 -#define TSCH_DEFAULT_TS_RX_TX 2072 -#define TSCH_DEFAULT_TS_MAX_ACK 2400 -#define TSCH_DEFAULT_TS_MAX_TX 4256 -#define TSCH_DEFAULT_TS_TIMESLOT_LENGTH 15000 - -#elif TSCH_CONF_DEFAULT_TIMESLOT_LENGTH == 65000U -/* 65ms timeslot, i.e. nearly the max length allowed by standard (16-bit unsigned in micro-seconds). - * Useful for running link-layer security on sky in Cooja, where only S/W security is supported. - * Note: this slot timing would require a total of 120ms. If a slot overlaps with the next active slot, - * the latter will be skipped. - * This configuration is mostly a work-around to test link-layer security in Cooja, it is recommended - * to use it with a 6TiSCH minimal schedule of length >= 2. */ - -#define TSCH_DEFAULT_TS_CCA_OFFSET 1800 -#define TSCH_DEFAULT_TS_CCA 128 -#define TSCH_DEFAULT_TS_TX_OFFSET 52000 -#define TSCH_DEFAULT_TS_RX_OFFSET (TSCH_DEFAULT_TS_TX_OFFSET - (TSCH_CONF_RX_WAIT / 2)) -#define TSCH_DEFAULT_TS_RX_ACK_DELAY 58600 -#define TSCH_DEFAULT_TS_TX_ACK_DELAY 59000 -#define TSCH_DEFAULT_TS_RX_WAIT TSCH_CONF_RX_WAIT -#define TSCH_DEFAULT_TS_ACK_WAIT 800 -#define TSCH_DEFAULT_TS_RX_TX 2072 -#define TSCH_DEFAULT_TS_MAX_ACK 2400 -#define TSCH_DEFAULT_TS_MAX_TX 4256 -#define TSCH_DEFAULT_TS_TIMESLOT_LENGTH 65000 - -#else -#error "TSCH: Unsupported default timeslot length" -#endif - #endif /* __TSCH_CONST_H__ */ /** @} */ diff --git a/os/net/mac/tsch/tsch.c b/os/net/mac/tsch/tsch.c index ffdf46e3a..f5a671541 100644 --- a/os/net/mac/tsch/tsch.c +++ b/os/net/mac/tsch/tsch.c @@ -101,21 +101,38 @@ NBR_TABLE(struct eb_stat, eb_stats); uint8_t tsch_hopping_sequence[TSCH_HOPPING_SEQUENCE_MAX_LEN]; struct tsch_asn_divisor_t tsch_hopping_sequence_length; -/* Default TSCH timeslot timing (in micro-second) */ -static const uint16_t tsch_default_timing_us[tsch_ts_elements_count] = { - TSCH_DEFAULT_TS_CCA_OFFSET, - TSCH_DEFAULT_TS_CCA, - TSCH_DEFAULT_TS_TX_OFFSET, - TSCH_DEFAULT_TS_RX_OFFSET, - TSCH_DEFAULT_TS_RX_ACK_DELAY, - TSCH_DEFAULT_TS_TX_ACK_DELAY, - TSCH_DEFAULT_TS_RX_WAIT, - TSCH_DEFAULT_TS_ACK_WAIT, - TSCH_DEFAULT_TS_RX_TX, - TSCH_DEFAULT_TS_MAX_ACK, - TSCH_DEFAULT_TS_MAX_TX, - TSCH_DEFAULT_TS_TIMESLOT_LENGTH, +/* The default timeslot timing in the standard is a guard time of + * 2200 us, a Tx offset of 2120 us and a Rx offset of 1120 us. + * As a result, the listening device has a guard time not centered + * on the expected Tx time. This is to be fixed in the next iteration + * of the standard. This can be enabled with: + * TxOffset: 2120 + * RxOffset: 1120 + * RxWait: 2200 + * + * Instead, we align the Rx guard time on expected Tx time. The Rx + * guard time is user-configurable with TSCH_CONF_RX_WAIT. + * (TxOffset - (RxWait / 2)) instead */ + +uint16_t tsch_timeslot_timing_us_10000[tsch_ts_elements_count] = { + 1800, /* CCAOffset */ + 128, /* CCA */ + 2120, /* TxOffset */ + (2120 - (TSCH_CONF_RX_WAIT / 2)), /* RxOffset */ + 800, /* RxAckDelay */ + 1000, /* TxAckDelay */ + TSCH_CONF_RX_WAIT, /* RxWait */ + 400, /* AckWait */ + 192, /* RxTx */ + 2400, /* MaxAck */ + 4256, /* MaxTx */ + 10000, /* TimeslotLength */ }; + +/* Default TSCH timeslot timing (in micro-second) */ +static const uint16_t *tsch_default_timing_us; +/* TSCH timeslot timing (in micro-second) */ +uint16_t tsch_timing_us[tsch_ts_elements_count]; /* TSCH timeslot timing (in rtimer ticks) */ rtimer_clock_t tsch_timing[tsch_ts_elements_count]; @@ -231,8 +248,10 @@ tsch_reset(void) TSCH_ASN_INIT(tsch_current_asn, 0, 0); current_link = NULL; /* Reset timeslot timing to defaults */ + tsch_default_timing_us = TSCH_DEFAULT_TIMESLOT_TIMING; for(i = 0; i < tsch_ts_elements_count; i++) { - tsch_timing[i] = US_TO_RTIMERTICKS(tsch_default_timing_us[i]); + tsch_timing_us[i] = tsch_default_timing_us[i]; + tsch_timing[i] = US_TO_RTIMERTICKS(tsch_timing_us[i]); } #ifdef TSCH_CALLBACK_LEAVING_NETWORK TSCH_CALLBACK_LEAVING_NETWORK(); @@ -581,10 +600,11 @@ tsch_associate(const struct input_packet *input_eb, rtimer_clock_t timestamp) /* TSCH timeslot timing */ for(i = 0; i < tsch_ts_elements_count; i++) { if(ies.ie_tsch_timeslot_id == 0) { - tsch_timing[i] = US_TO_RTIMERTICKS(tsch_default_timing_us[i]); + tsch_timing_us[i] = tsch_default_timing_us[i]; } else { - tsch_timing[i] = US_TO_RTIMERTICKS(ies.ie_tsch_timeslot[i]); + tsch_timing_us[i] = ies.ie_tsch_timeslot[i]; } + tsch_timing[i] = US_TO_RTIMERTICKS(tsch_timing_us[i]); } /* TSCH hopping sequence */ diff --git a/os/net/mac/tsch/tsch.h b/os/net/mac/tsch/tsch.h index 273f979e4..6d0b68253 100644 --- a/os/net/mac/tsch/tsch.h +++ b/os/net/mac/tsch/tsch.h @@ -170,6 +170,8 @@ extern uint8_t tsch_current_channel; /* TSCH channel hopping sequence */ extern uint8_t tsch_hopping_sequence[TSCH_HOPPING_SEQUENCE_MAX_LEN]; extern struct tsch_asn_divisor_t tsch_hopping_sequence_length; +/* TSCH timeslot timing (in micro-second) */ +uint16_t tsch_timing_us[tsch_ts_elements_count]; /* TSCH timeslot timing (in rtimer ticks) */ extern rtimer_clock_t tsch_timing[tsch_ts_elements_count]; /* Statistics on the current session */ @@ -179,6 +181,8 @@ extern unsigned long sync_count; extern int32_t min_drift_seen; extern int32_t max_drift_seen; +extern uint16_t tsch_timeslot_timing_us_10000[tsch_ts_elements_count]; + /* TSCH processes */ PROCESS_NAME(tsch_process); PROCESS_NAME(tsch_send_eb_process); diff --git a/tools/viewconf/viewconf.c b/tools/viewconf/viewconf.c index 678663ee1..b5fe8dc7f 100644 --- a/tools/viewconf/viewconf.c +++ b/tools/viewconf/viewconf.c @@ -54,10 +54,10 @@ ##### "TSCH_CONF_MAX_EB_PERIOD": _______________ -> TSCH_MAX_EB_PERIOD #endif -#if TSCH_CONF_DEFAULT_TIMESLOT_LENGTH -##### "TSCH_CONF_DEFAULT_TIMESLOT_LENGTH": _____ == TSCH_CONF_DEFAULT_TIMESLOT_LENGTH +#ifdef TSCH_CONF_DEFAULT_TIMESLOT_TIMING +##### "TSCH_CONF_DEFAULT_TIMESLOT_TIMING": _____ == TSCH_CONF_DEFAULT_TIMESLOT_TIMING #else -##### "TSCH_CONF_DEFAULT_TIMESLOT_LENGTH": _____ -> TSCH_DEFAULT_TIMESLOT_LENGTH +##### "TSCH_CONF_DEFAULT_TIMESLOT_TIMING": _____ -> TSCH_DEFAULT_TIMESLOT_TIMING #endif #ifdef TSCH_SCHEDULE_CONF_DEFAULT_LENGTH From f79a19eaab3ccc93fc015bf9e80d33095b8cc2d1 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 3 Oct 2018 13:44:48 +0200 Subject: [PATCH 405/485] cc2538-rf and cc1200: only include implementation of RADIO_CONST_TSCH_TIMING when TSCH is enabled --- arch/cpu/cc2538/dev/cc2538-rf.c | 2 ++ arch/dev/cc1200/cc1200.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/cpu/cc2538/dev/cc2538-rf.c b/arch/cpu/cc2538/dev/cc2538-rf.c index d3d2d2dff..fdda8ccf9 100644 --- a/arch/cpu/cc2538/dev/cc2538-rf.c +++ b/arch/cpu/cc2538/dev/cc2538-rf.c @@ -972,6 +972,7 @@ get_object(radio_param_t param, void *dest, size_t size) return RADIO_RESULT_OK; } +#if MAC_CONF_WITH_TSCH if(param == RADIO_CONST_TSCH_TIMING) { if(size != sizeof(uint16_t *) || !dest) { return RADIO_RESULT_INVALID_VALUE; @@ -979,6 +980,7 @@ get_object(radio_param_t param, void *dest, size_t size) *(uint16_t **)dest = tsch_timeslot_timing_us_10000; return RADIO_RESULT_OK; } +#endif /* MAC_CONF_WITH_TSCH */ return RADIO_RESULT_NOT_SUPPORTED; } diff --git a/arch/dev/cc1200/cc1200.c b/arch/dev/cc1200/cc1200.c index d2b7db770..83510f249 100644 --- a/arch/dev/cc1200/cc1200.c +++ b/arch/dev/cc1200/cc1200.c @@ -1364,6 +1364,7 @@ get_object(radio_param_t param, void *dest, size_t size) return RADIO_RESULT_OK; } +#if MAC_CONF_WITH_TSCH if(param == RADIO_CONST_TSCH_TIMING) { if(size != sizeof(uint16_t *) || !dest) { return RADIO_RESULT_INVALID_VALUE; @@ -1371,6 +1372,7 @@ get_object(radio_param_t param, void *dest, size_t size) *(uint16_t **)dest = CC1200_RF_CFG.tsch_timing; return RADIO_RESULT_OK; } +#endif /* MAC_CONF_WITH_TSCH */ return RADIO_RESULT_NOT_SUPPORTED; From ce0f95ec50badfd15b188a783b4e7787b0fae5eb Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 3 Oct 2018 13:53:10 +0200 Subject: [PATCH 406/485] cc1200 flags for TSCH --- arch/dev/cc1200/cc1200.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/dev/cc1200/cc1200.c b/arch/dev/cc1200/cc1200.c index 83510f249..a49cb8667 100644 --- a/arch/dev/cc1200/cc1200.c +++ b/arch/dev/cc1200/cc1200.c @@ -96,7 +96,11 @@ static rtimer_clock_t sfd_timestamp = 0; * * TODO: Option to be removed upon approval of the driver */ +#if MAC_CONF_WITH_TSCH +#define USE_SFSTXON 0 +#else /* MAC_CONF_WITH_TSCH */ #define USE_SFSTXON 1 +#endif /* MAC_CONF_WITH_TSCH */ /*---------------------------------------------------------------------------*/ /* Phy header length */ #if CC1200_802154G @@ -136,7 +140,15 @@ static rtimer_clock_t sfd_timestamp = 0; /* Use GPIO2 as RX / TX FIFO threshold indicator pin */ #define GPIO2_IOCFG CC1200_IOCFG_RXFIFO_THR /* This is the FIFO threshold we use */ +#if MAC_CONF_WITH_TSCH +#if CC1200_802154G +#define FIFO_THRESHOLD 1 +#else +#define FIFO_THRESHOLD 0 +#endif +#else /* MAC_CONF_WITH_TSCH */ #define FIFO_THRESHOLD 32 +#endif /* MAC_CONF_WITH_TSCH */ /* Turn on RX after packet reception */ #define RXOFF_MODE_RX 1 /* Let the CC1200 append RSSI + LQI */ From c589875aeee7d1c2d98eb4c0fd41ac750c17226d Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 3 Oct 2018 14:07:47 +0200 Subject: [PATCH 407/485] cc1200: implement poll mode --- arch/dev/cc1200/cc1200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/dev/cc1200/cc1200.c b/arch/dev/cc1200/cc1200.c index a49cb8667..58169be17 100644 --- a/arch/dev/cc1200/cc1200.c +++ b/arch/dev/cc1200/cc1200.c @@ -641,7 +641,7 @@ pollhandler(void) set_channel(new_rf_channel); } - if(rx_pkt_len > 0) { + if((rx_mode_value & RADIO_RX_MODE_POLL_MODE) == 0 && rx_pkt_len > 0) { int len; From f4c1ae0fdd269a338c7756cdd4d96a1bb8a9cd7e Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 3 Oct 2018 14:15:05 +0200 Subject: [PATCH 408/485] cc1200: reset rf_flags in on() --- arch/dev/cc1200/cc1200.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/dev/cc1200/cc1200.c b/arch/dev/cc1200/cc1200.c index 58169be17..b1a1c3b44 100644 --- a/arch/dev/cc1200/cc1200.c +++ b/arch/dev/cc1200/cc1200.c @@ -1055,6 +1055,7 @@ on(void) RF_ASSERT((cc1200_arch_gpio0_read_pin() == 0)); cc1200_arch_spi_deselect(); + rf_flags = RF_INITIALIZED; rf_flags |= RF_ON; /* Radio is IDLE now, re-configure GPIO0 (modified inside off()) */ From 90264a3ba383e6e05f242635dc3fa7a5ead95a3f Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 3 Oct 2018 14:15:25 +0200 Subject: [PATCH 409/485] cc1200: read out any pending packet before turning off --- arch/dev/cc1200/cc1200.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/dev/cc1200/cc1200.c b/arch/dev/cc1200/cc1200.c index b1a1c3b44..42b9fe092 100644 --- a/arch/dev/cc1200/cc1200.c +++ b/arch/dev/cc1200/cc1200.c @@ -1098,6 +1098,16 @@ off(void) idle(); + if(single_read(CC1200_NUM_RXBYTES) > 0) { + RELEASE_SPI(); + /* In case there is something in the Rx FIFO, read it */ + cc1200_rx_interrupt(); + if(SPI_IS_LOCKED()) { + return 0; + } + LOCK_SPI(); + } + /* * As we use GPIO as CHIP_RDYn signal on wake-up / on(), * we re-configure it for CHIP_RDYn. From 0ef1ee6df5423cb5684b56266da5c865e606b0d4 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 3 Oct 2018 14:16:54 +0200 Subject: [PATCH 410/485] cc1200: make pending_packet work even when interrupt handler was not called --- arch/dev/cc1200/cc1200.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/dev/cc1200/cc1200.c b/arch/dev/cc1200/cc1200.c index 42b9fe092..f7387f659 100644 --- a/arch/dev/cc1200/cc1200.c +++ b/arch/dev/cc1200/cc1200.c @@ -1026,9 +1026,16 @@ receiving_packet(void) static int pending_packet(void) { + int ret; + ret = ((rx_pkt_len != 0) ? 1 : 0); + if(ret == 0 && !SPI_IS_LOCKED()) { + LOCK_SPI(); + ret = (single_read(CC1200_NUM_RXBYTES) > 0); + RELEASE_SPI(); + } - INFO("RF: Pending (%d)\n", ((rx_pkt_len != 0) ? 1 : 0)); - return (rx_pkt_len != 0) ? 1 : 0; + INFO("RF: Pending (%d)\n", ret); + return ret; } /*---------------------------------------------------------------------------*/ From b5e12154c489a28283e50a025bfe2e2b680c4dc7 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 3 Oct 2018 15:15:18 +0200 Subject: [PATCH 411/485] cc1200: added option to separate filling the Tx FIFO from actual transmission --- arch/dev/cc1200/cc1200.c | 144 +++++++++++++++++++++++---------------- 1 file changed, 87 insertions(+), 57 deletions(-) diff --git a/arch/dev/cc1200/cc1200.c b/arch/dev/cc1200/cc1200.c index f7387f659..a44454564 100644 --- a/arch/dev/cc1200/cc1200.c +++ b/arch/dev/cc1200/cc1200.c @@ -82,6 +82,14 @@ static rtimer_clock_t sfd_timestamp = 0; #define CC1200_RF_CFG cc1200_802154g_863_870_fsk_50kbps #endif #endif +/* + * When set, a software buffer is used to store outgoing packets before copying + * to Tx FIFO. This enabled sending packets larger than the FIFO. When unset, + * no buffer is used; instead, the payload is copied directly to the Tx FIFO. + * This is requried by TSCH, for shorter and more predictable delay in the Tx + * chain. This, however, restircts the payload length to the Tx FIFO size. + */ +#define CC1200_WITH_TX_BUF (!MAC_CONF_WITH_TSCH) /* * Set this parameter to 1 in order to use the MARC_STATE register when * polling the chips's status. Else use the status byte returned when sending @@ -398,10 +406,14 @@ extern const cc1200_rf_cfg_t CC1200_RF_CFG; /*---------------------------------------------------------------------------*/ /* Flag indicating whether non-interrupt routines are using SPI */ static volatile uint8_t spi_locked = 0; +#if CC1200_WITH_TX_BUF /* Packet buffer for transmission, filled within prepare() */ static uint8_t tx_pkt[CC1200_MAX_PAYLOAD_LEN]; +#endif /* CC1200_WITH_TX_BUF */ /* The number of bytes waiting in tx_pkt */ static uint16_t tx_pkt_len; +/* Number of bytes from tx_pkt left to write to FIFO */ +uint16_t bytes_left_to_write; /* Packet buffer for reception */ static uint8_t rx_pkt[CC1200_MAX_PAYLOAD_LEN + APPENDIX_LEN]; /* The number of bytes placed in rx_pkt */ @@ -439,6 +451,9 @@ static struct etimer et; /* Init the radio. */ static int init(void); +/* Prepare and copy PHY header to Tx FIFO */ +static int +copy_header_to_tx_fifo(unsigned short payload_len); /* Prepare the radio with a packet to be sent. */ static int prepare(const void *payload, unsigned short payload_len); @@ -547,7 +562,7 @@ idle_calibrate_rx(void); /* Restart RX from within RX interrupt. */ static void rx_rx(void); -/* Fill TX FIFO, start TX and wait for TX to complete (blocking!). */ +/* Fill TX FIFO (if not already done), start TX and wait for TX to complete (blocking!). */ static int idle_tx_rx(const uint8_t *payload, uint16_t payload_len); /* Update TX power */ @@ -739,10 +754,67 @@ prepare(const void *payload, unsigned short payload_len) } tx_pkt_len = payload_len; + +#if CC1200_WITH_TX_BUF + /* Copy payload to buffer, will be sent later */ memcpy(tx_pkt, payload, tx_pkt_len); +#else /* CC1200_WITH_TX_BUF */ +#if (CC1200_MAX_PAYLOAD_LEN > (CC1200_FIFO_SIZE - PHR_LEN)) +#error CC1200 max payload too large +#else + /* Copy header and payload directly to Radio Tx FIFO (127 bytes max) */ + copy_header_to_tx_fifo(payload_len); + burst_write(CC1200_TXFIFO, payload, payload_len); +#endif +#endif /* CC1200_WITH_TX_BUF */ return RADIO_TX_OK; +} +/*---------------------------------------------------------------------------*/ +/* Prepare the radio with a packet to be sent. */ +static int +copy_header_to_tx_fifo(unsigned short payload_len) +{ +#if CC1200_802154G + /* Prepare PHR for 802.15.4g frames */ + struct { + uint8_t phra; + uint8_t phrb; + } phr; +#if CC1200_802154G_CRC16 + payload_len += 2; +#else + payload_len += 4; +#endif + /* Frame length */ + phr.phrb = (uint8_t)(payload_len & 0x00FF); + phr.phra = (uint8_t)((payload_len >> 8) & 0x0007); +#if CC1200_802154G_WHITENING + /* Enable Whitening */ + phr.phra |= (1 << 3); +#endif /* #if CC1200_802154G_WHITENING */ +#if CC1200_802154G_CRC16 + /* FCS type 1, 2 Byte CRC */ + phr.phra |= (1 << 4); +#endif /* #if CC1200_802154G_CRC16 */ +#endif /* #if CC1200_802154G */ + idle(); + + rf_flags &= ~RF_RX_PROCESSING_PKT; + strobe(CC1200_SFRX); + /* Flush TX FIFO */ + strobe(CC1200_SFTX); + +#if CC1200_802154G + /* Write PHR */ + burst_write(CC1200_TXFIFO, (uint8_t *)&phr, PHR_LEN); +#else + /* Write length byte */ + burst_write(CC1200_TXFIFO, (uint8_t *)&payload_len, PHR_LEN); +#endif /* #if CC1200_802154G */ + + return 0; } /*---------------------------------------------------------------------------*/ /* Send the packet that has previously been prepared. */ @@ -752,6 +824,7 @@ transmit(unsigned short transmit_len) uint8_t was_off = 0; int ret = RADIO_TX_OK; + int txret; INFO("RF: Transmit (%d)\n", transmit_len); @@ -807,7 +880,12 @@ transmit(unsigned short transmit_len) #endif /* Send data using TX FIFO */ - if(idle_tx_rx((const uint8_t *)tx_pkt, tx_pkt_len) == RADIO_TX_OK) { +#if CC1200_WITH_TX_BUF + txret = idle_tx_rx(tx_pkt, tx_pkt_len); +#else /* CC1200_WITH_TX_BUF */ + txret = idle_tx_rx(NULL, tx_pkt_len); +#endif /* CC1200_WITH_TX_BUF */ + if(txret == RADIO_TX_OK) { /* * TXOFF_MODE is set to RX, @@ -1885,75 +1963,25 @@ rx_rx(void) } /*---------------------------------------------------------------------------*/ -/* Fill TX FIFO, start TX and wait for TX to complete (blocking!). */ +/* Fill TX FIFO (if not already done), start TX and wait for TX to complete (blocking!). */ static int idle_tx_rx(const uint8_t *payload, uint16_t payload_len) { - #if (CC1200_MAX_PAYLOAD_LEN > (CC1200_FIFO_SIZE - PHR_LEN)) - uint16_t bytes_left_to_write; uint8_t to_write; const uint8_t *p; #endif -#if CC1200_802154G - /* Prepare PHR for 802.15.4g frames */ - struct { - uint8_t phra; - uint8_t phrb; - } phr; -#if CC1200_802154G_CRC16 - payload_len += 2; -#else - payload_len += 4; -#endif - /* Frame length */ - phr.phrb = (uint8_t)(payload_len & 0x00FF); - phr.phra = (uint8_t)((payload_len >> 8) & 0x0007); -#if CC1200_802154G_WHITENING - /* Enable Whitening */ - phr.phra |= (1 << 3); -#endif /* #if CC1200_802154G_WHITENING */ -#if CC1200_802154G_CRC16 - /* FCS type 1, 2 Byte CRC */ - phr.phra |= (1 << 4); -#endif /* #if CC1200_802154G_CRC16 */ -#endif /* #if CC1200_802154G */ - /* Prepare for RX */ rf_flags &= ~RF_RX_PROCESSING_PKT; strobe(CC1200_SFRX); - /* Flush TX FIFO */ - strobe(CC1200_SFTX); - -#if USE_SFSTXON - /* - * Enable synthesizer. Saves us a few µs especially if it takes - * long enough to fill the FIFO. This strobe must not be - * send before SFTX! - */ - strobe(CC1200_SFSTXON); -#endif - /* Configure GPIO0 to detect TX state */ single_write(CC1200_IOCFG0, CC1200_IOCFG_MARC_2PIN_STATUS_0); -#if (CC1200_MAX_PAYLOAD_LEN > (CC1200_FIFO_SIZE - PHR_LEN)) - /* - * We already checked that GPIO2 is used if - * CC1200_MAX_PAYLOAD_LEN > 127 / 126 in the header of this file - */ - single_write(CC1200_IOCFG2, CC1200_IOCFG_TXFIFO_THR); -#endif - -#if CC1200_802154G - /* Write PHR */ - burst_write(CC1200_TXFIFO, (uint8_t *)&phr, PHR_LEN); -#else - /* Write length byte */ - burst_write(CC1200_TXFIFO, (uint8_t *)&payload_len, PHR_LEN); -#endif /* #if CC1200_802154G */ +#if CC1200_WITH_TX_BUF + /* Prepare and write header */ + copy_header_to_tx_fifo(payload_len); /* * Fill FIFO with data. If SPI is slow it might make sense @@ -1970,6 +1998,7 @@ idle_tx_rx(const uint8_t *payload, uint16_t payload_len) #else burst_write(CC1200_TXFIFO, payload, payload_len); #endif +#endif /* CC1200_WITH_TX_BUF */ #if USE_SFSTXON /* Wait for synthesizer to be ready */ @@ -2009,7 +2038,7 @@ idle_tx_rx(const uint8_t *payload, uint16_t payload_len) } -#if (CC1200_MAX_PAYLOAD_LEN > (CC1200_FIFO_SIZE - PHR_LEN)) +#if (CC1200_MAX_PAYLOAD_LEN > (CC1200_FIFO_SIZE - PHR_LEN)) && CC1200_WITH_TX_BUF if(bytes_left_to_write != 0) { rtimer_clock_t t0; uint8_t s; @@ -2280,6 +2309,7 @@ addr_check_auto_ack(uint8_t *frame, uint16_t frame_len) idle(); #endif + prepare((const uint8_t *)ack, ACK_LEN); idle_tx_rx((const uint8_t *)ack, ACK_LEN); /* rx_rx() will follow */ From cc0c70c1b394344f7287eef622f4ed931779e2c7 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Thu, 4 Oct 2018 10:33:52 +0200 Subject: [PATCH 412/485] TSCH: move 10ms and 15ms timeslot timings to separate files --- arch/dev/cc2420/cc2420-tsch-15ms.c | 61 ++++++++++++++++++++ arch/platform/sky/contiki-conf.h | 2 + arch/platform/sky/platform.c | 16 ------ os/net/mac/tsch/tsch-timeslot-timing.c | 79 ++++++++++++++++++++++++++ os/net/mac/tsch/tsch.c | 28 --------- os/net/mac/tsch/tsch.h | 2 +- 6 files changed, 143 insertions(+), 45 deletions(-) create mode 100644 arch/dev/cc2420/cc2420-tsch-15ms.c create mode 100644 os/net/mac/tsch/tsch-timeslot-timing.c diff --git a/arch/dev/cc2420/cc2420-tsch-15ms.c b/arch/dev/cc2420/cc2420-tsch-15ms.c new file mode 100644 index 000000000..6f79bff91 --- /dev/null +++ b/arch/dev/cc2420/cc2420-tsch-15ms.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2018, RISE SICS. + * 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 + * IEEE 802.15.4 TSCH timeslot timings for 15ms slots + * \author + * Simon Duquennoy + * + */ + +#include "contiki.h" +#include "net/mac/tsch/tsch.h" + +/** + * \brief 15ms TSCH timeslot timings, required for cc2420 platforms as + * they are unable to keep up with the defulat 10ms timeslots. + */ +uint16_t tsch_timeslot_timing_us_15000[tsch_ts_elements_count] = { + 1800, /* CCAOffset */ + 128, /* CCA */ + 4000, /* TxOffset */ + (4000 - (TSCH_CONF_RX_WAIT / 2)), /* RxOffset */ + 3600, /* RxAckDelay */ + 4000, /* TxAckDelay */ + TSCH_CONF_RX_WAIT, /* RxWait */ + 800, /* AckWait */ + 2072, /* RxTx */ + 2400, /* MaxAck */ + 4256, /* MaxTx */ + 15000, /* TimeslotLength */ +}; diff --git a/arch/platform/sky/contiki-conf.h b/arch/platform/sky/contiki-conf.h index cf0a1e9ac..634b77ca9 100644 --- a/arch/platform/sky/contiki-conf.h +++ b/arch/platform/sky/contiki-conf.h @@ -17,7 +17,9 @@ #define NETSTACK_CONF_RADIO cc2420_driver #endif /* NETSTACK_CONF_RADIO */ +/* TSCH 15ms timeslot timing template, required for cc2420 */ extern uint16_t tsch_timeslot_timing_us_15000[]; + /* The TSCH default slot length of 10ms is a bit too short for this platform, * use 15ms instead. */ #ifndef TSCH_CONF_DEFAULT_TIMESLOT_TIMING diff --git a/arch/platform/sky/platform.c b/arch/platform/sky/platform.c index 90a856520..8044a7196 100644 --- a/arch/platform/sky/platform.c +++ b/arch/platform/sky/platform.c @@ -64,22 +64,6 @@ extern int msp430_dco_required; #include "experiment-setup.h" #endif -/* TSCH timeslot timing for platforms requiring 15ms slots */ -uint16_t tsch_timeslot_timing_us_15000[tsch_ts_elements_count] = { - 1800, /* CCAOffset */ - 128, /* CCA */ - 4000, /* TxOffset */ - (4000 - (TSCH_CONF_RX_WAIT / 2)), /* RxOffset */ - 3600, /* RxAckDelay */ - 4000, /* TxAckDelay */ - TSCH_CONF_RX_WAIT, /* RxWait */ - 800, /* AckWait */ - 2072, /* RxTx */ - 2400, /* MaxAck */ - 4256, /* MaxTx */ - 15000, /* TimeslotLength */ -}; - void init_platform(void); /*---------------------------------------------------------------------------*/ /* Log configuration */ diff --git a/os/net/mac/tsch/tsch-timeslot-timing.c b/os/net/mac/tsch/tsch-timeslot-timing.c new file mode 100644 index 000000000..13b05851b --- /dev/null +++ b/os/net/mac/tsch/tsch-timeslot-timing.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2018, RISE SICS. + * 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 + * IEEE 802.15.4 TSCH timeslot timings + * \author + * Simon Duquennoy + * + */ + +/** + * \addtogroup tsch + * @{ +*/ + +#include "contiki.h" +#include "net/mac/tsch/tsch.h" + +/** + * \brief The default timeslot timing in the standard is a guard time of + * 2200 us, a Tx offset of 2120 us and a Rx offset of 1120 us. + * As a result, the listening device has a guard time not centered + * on the expected Tx time. This is to be fixed in the next iteration + * of the standard. This can be enabled with: + * TxOffset: 2120 + * RxOffset: 1120 + * RxWait: 2200 + * + * Instead, we align the Rx guard time on expected Tx time. The Rx + * guard time is user-configurable with TSCH_CONF_RX_WAIT. + * (TxOffset - (RxWait / 2)) instead + */ + +uint16_t tsch_timeslot_timing_us_10000[tsch_ts_elements_count] = { + 1800, /* CCAOffset */ + 128, /* CCA */ + 2120, /* TxOffset */ + (2120 - (TSCH_CONF_RX_WAIT / 2)), /* RxOffset */ + 800, /* RxAckDelay */ + 1000, /* TxAckDelay */ + TSCH_CONF_RX_WAIT, /* RxWait */ + 400, /* AckWait */ + 192, /* RxTx */ + 2400, /* MaxAck */ + 4256, /* MaxTx */ + 10000, /* TimeslotLength */ +}; + +/** @} */ diff --git a/os/net/mac/tsch/tsch.c b/os/net/mac/tsch/tsch.c index f5a671541..982715bd5 100644 --- a/os/net/mac/tsch/tsch.c +++ b/os/net/mac/tsch/tsch.c @@ -101,34 +101,6 @@ NBR_TABLE(struct eb_stat, eb_stats); uint8_t tsch_hopping_sequence[TSCH_HOPPING_SEQUENCE_MAX_LEN]; struct tsch_asn_divisor_t tsch_hopping_sequence_length; -/* The default timeslot timing in the standard is a guard time of - * 2200 us, a Tx offset of 2120 us and a Rx offset of 1120 us. - * As a result, the listening device has a guard time not centered - * on the expected Tx time. This is to be fixed in the next iteration - * of the standard. This can be enabled with: - * TxOffset: 2120 - * RxOffset: 1120 - * RxWait: 2200 - * - * Instead, we align the Rx guard time on expected Tx time. The Rx - * guard time is user-configurable with TSCH_CONF_RX_WAIT. - * (TxOffset - (RxWait / 2)) instead */ - -uint16_t tsch_timeslot_timing_us_10000[tsch_ts_elements_count] = { - 1800, /* CCAOffset */ - 128, /* CCA */ - 2120, /* TxOffset */ - (2120 - (TSCH_CONF_RX_WAIT / 2)), /* RxOffset */ - 800, /* RxAckDelay */ - 1000, /* TxAckDelay */ - TSCH_CONF_RX_WAIT, /* RxWait */ - 400, /* AckWait */ - 192, /* RxTx */ - 2400, /* MaxAck */ - 4256, /* MaxTx */ - 10000, /* TimeslotLength */ -}; - /* Default TSCH timeslot timing (in micro-second) */ static const uint16_t *tsch_default_timing_us; /* TSCH timeslot timing (in micro-second) */ diff --git a/os/net/mac/tsch/tsch.h b/os/net/mac/tsch/tsch.h index 6d0b68253..3cda54d96 100644 --- a/os/net/mac/tsch/tsch.h +++ b/os/net/mac/tsch/tsch.h @@ -180,7 +180,7 @@ extern unsigned long rx_count; extern unsigned long sync_count; extern int32_t min_drift_seen; extern int32_t max_drift_seen; - +/* The TSCH standard 10ms timeslot timing */ extern uint16_t tsch_timeslot_timing_us_10000[tsch_ts_elements_count]; /* TSCH processes */ From 22cbced03734cfb51142c62031a1c31e9937c8f9 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Thu, 4 Oct 2018 10:38:18 +0200 Subject: [PATCH 413/485] TSCH: timeslot timing templates as const --- arch/cpu/cc2538/dev/cc2538-rf.c | 2 +- arch/dev/cc1200/cc1200-802154g-863-870-fsk-50kbps.c | 2 +- arch/dev/cc1200/cc1200-868-4gfsk-1000kbps.c | 2 +- arch/dev/cc1200/cc1200-rf-cfg.h | 2 +- arch/dev/cc1200/cc1200.c | 2 +- arch/dev/cc2420/cc2420-tsch-15ms.c | 2 +- arch/platform/sky/contiki-conf.h | 2 +- os/net/mac/tsch/tsch-timeslot-timing.c | 2 +- os/net/mac/tsch/tsch.h | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/cpu/cc2538/dev/cc2538-rf.c b/arch/cpu/cc2538/dev/cc2538-rf.c index fdda8ccf9..5a8bb8d6f 100644 --- a/arch/cpu/cc2538/dev/cc2538-rf.c +++ b/arch/cpu/cc2538/dev/cc2538-rf.c @@ -977,7 +977,7 @@ get_object(radio_param_t param, void *dest, size_t size) if(size != sizeof(uint16_t *) || !dest) { return RADIO_RESULT_INVALID_VALUE; } - *(uint16_t **)dest = tsch_timeslot_timing_us_10000; + *(const uint16_t **)dest = tsch_timeslot_timing_us_10000; return RADIO_RESULT_OK; } #endif /* MAC_CONF_WITH_TSCH */ diff --git a/arch/dev/cc1200/cc1200-802154g-863-870-fsk-50kbps.c b/arch/dev/cc1200/cc1200-802154g-863-870-fsk-50kbps.c index b1d4b2064..ad19b5769 100644 --- a/arch/dev/cc1200/cc1200-802154g-863-870-fsk-50kbps.c +++ b/arch/dev/cc1200/cc1200-802154g-863-870-fsk-50kbps.c @@ -94,7 +94,7 @@ static const char rf_cfg_descriptor[] = "802.15.4g 863-870MHz MR-FSK mode #1"; ) /* TSCH timeslot timing (mircoseconds) */ -static uint16_t cc1200_50kbps_tsch_timing[tsch_ts_elements_count] = { +static const uint16_t cc1200_50kbps_tsch_timing[tsch_ts_elements_count] = { CC1200_TSCH_DEFAULT_TS_CCA_OFFSET, CC1200_TSCH_DEFAULT_TS_CCA, CC1200_TSCH_DEFAULT_TS_TX_OFFSET, diff --git a/arch/dev/cc1200/cc1200-868-4gfsk-1000kbps.c b/arch/dev/cc1200/cc1200-868-4gfsk-1000kbps.c index 506fad801..29beef6c0 100644 --- a/arch/dev/cc1200/cc1200-868-4gfsk-1000kbps.c +++ b/arch/dev/cc1200/cc1200-868-4gfsk-1000kbps.c @@ -86,7 +86,7 @@ static const char rf_cfg_descriptor[] = "868MHz 2-GFSK 1000 kbps"; ) /* TSCH timeslot timing (in rtimer ticks) */ -static uint16_t cc1200_1000kbps_tsch_timing[tsch_ts_elements_count] = { +static const uint16_t cc1200_1000kbps_tsch_timing[tsch_ts_elements_count] = { CC1200_TSCH_DEFAULT_TS_CCA_OFFSET, CC1200_TSCH_DEFAULT_TS_CCA, CC1200_TSCH_DEFAULT_TS_TX_OFFSET, diff --git a/arch/dev/cc1200/cc1200-rf-cfg.h b/arch/dev/cc1200/cc1200-rf-cfg.h index d047f772e..3042ffdd5 100644 --- a/arch/dev/cc1200/cc1200-rf-cfg.h +++ b/arch/dev/cc1200/cc1200-rf-cfg.h @@ -97,7 +97,7 @@ typedef struct cc1200_rf_cfg { /* The bitrate in bps */ uint32_t bitrate; /* TSCH timeslot timing */ - uint16_t *tsch_timing; + const uint16_t *tsch_timing; } cc1200_rf_cfg_t; /*---------------------------------------------------------------------------*/ #endif /* CC1200_RF_CFG_H */ diff --git a/arch/dev/cc1200/cc1200.c b/arch/dev/cc1200/cc1200.c index a44454564..5f76e4817 100644 --- a/arch/dev/cc1200/cc1200.c +++ b/arch/dev/cc1200/cc1200.c @@ -1477,7 +1477,7 @@ get_object(radio_param_t param, void *dest, size_t size) if(size != sizeof(uint16_t *) || !dest) { return RADIO_RESULT_INVALID_VALUE; } - *(uint16_t **)dest = CC1200_RF_CFG.tsch_timing; + *(const uint16_t **)dest = CC1200_RF_CFG.tsch_timing; return RADIO_RESULT_OK; } #endif /* MAC_CONF_WITH_TSCH */ diff --git a/arch/dev/cc2420/cc2420-tsch-15ms.c b/arch/dev/cc2420/cc2420-tsch-15ms.c index 6f79bff91..b3b825584 100644 --- a/arch/dev/cc2420/cc2420-tsch-15ms.c +++ b/arch/dev/cc2420/cc2420-tsch-15ms.c @@ -45,7 +45,7 @@ * \brief 15ms TSCH timeslot timings, required for cc2420 platforms as * they are unable to keep up with the defulat 10ms timeslots. */ -uint16_t tsch_timeslot_timing_us_15000[tsch_ts_elements_count] = { +const uint16_t tsch_timeslot_timing_us_15000[tsch_ts_elements_count] = { 1800, /* CCAOffset */ 128, /* CCA */ 4000, /* TxOffset */ diff --git a/arch/platform/sky/contiki-conf.h b/arch/platform/sky/contiki-conf.h index 634b77ca9..82e391164 100644 --- a/arch/platform/sky/contiki-conf.h +++ b/arch/platform/sky/contiki-conf.h @@ -18,7 +18,7 @@ #endif /* NETSTACK_CONF_RADIO */ /* TSCH 15ms timeslot timing template, required for cc2420 */ -extern uint16_t tsch_timeslot_timing_us_15000[]; +extern const uint16_t tsch_timeslot_timing_us_15000[]; /* The TSCH default slot length of 10ms is a bit too short for this platform, * use 15ms instead. */ diff --git a/os/net/mac/tsch/tsch-timeslot-timing.c b/os/net/mac/tsch/tsch-timeslot-timing.c index 13b05851b..a75676101 100644 --- a/os/net/mac/tsch/tsch-timeslot-timing.c +++ b/os/net/mac/tsch/tsch-timeslot-timing.c @@ -61,7 +61,7 @@ * (TxOffset - (RxWait / 2)) instead */ -uint16_t tsch_timeslot_timing_us_10000[tsch_ts_elements_count] = { +const uint16_t tsch_timeslot_timing_us_10000[tsch_ts_elements_count] = { 1800, /* CCAOffset */ 128, /* CCA */ 2120, /* TxOffset */ diff --git a/os/net/mac/tsch/tsch.h b/os/net/mac/tsch/tsch.h index 3cda54d96..5eed691cd 100644 --- a/os/net/mac/tsch/tsch.h +++ b/os/net/mac/tsch/tsch.h @@ -181,7 +181,7 @@ extern unsigned long sync_count; extern int32_t min_drift_seen; extern int32_t max_drift_seen; /* The TSCH standard 10ms timeslot timing */ -extern uint16_t tsch_timeslot_timing_us_10000[tsch_ts_elements_count]; +extern const uint16_t tsch_timeslot_timing_us_10000[tsch_ts_elements_count]; /* TSCH processes */ PROCESS_NAME(tsch_process); From 3ace2b93f625c17661f16ce5bf99220681ca561a Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Thu, 4 Oct 2018 10:42:13 +0200 Subject: [PATCH 414/485] tsch_init: added missing return in case of failed initialization --- os/net/mac/tsch/tsch.c | 1 + 1 file changed, 1 insertion(+) diff --git a/os/net/mac/tsch/tsch.c b/os/net/mac/tsch/tsch.c index 982715bd5..7dbb0a7ce 100644 --- a/os/net/mac/tsch/tsch.c +++ b/os/net/mac/tsch/tsch.c @@ -939,6 +939,7 @@ tsch_init(void) /* Check max hopping sequence length vs default sequence length */ if(TSCH_HOPPING_SEQUENCE_MAX_LEN < sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE)) { LOG_ERR("! TSCH_HOPPING_SEQUENCE_MAX_LEN < sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE). Abort init.\n"); + return; } /* Init the queuebuf and TSCH sub-modules */ From 7c5977d9f717f402dfb44bb8dfb6d9e2c35e35d7 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Thu, 4 Oct 2018 10:43:41 +0200 Subject: [PATCH 415/485] tsch_init: check that a timeslot timing template is provided --- os/net/mac/tsch/tsch.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/os/net/mac/tsch/tsch.c b/os/net/mac/tsch/tsch.c index 7dbb0a7ce..e78b888d0 100644 --- a/os/net/mac/tsch/tsch.c +++ b/os/net/mac/tsch/tsch.c @@ -899,6 +899,12 @@ tsch_init(void) radio_value_t radio_tx_mode; rtimer_clock_t t; + /* Check that the platform provides a TSCH timeslot timing template */ + if(TSCH_DEFAULT_TIMESLOT_TIMING == NULL) { + LOG_ERR("! platform does not provide a timeslot timing template.\n"); + return; + } + /* Radio Rx mode */ if(NETSTACK_RADIO.get_value(RADIO_PARAM_RX_MODE, &radio_rx_mode) != RADIO_RESULT_OK) { LOG_ERR("! radio does not support getting RADIO_PARAM_RX_MODE. Abort init.\n"); From 085601f79567f8838e4cceac4035aaa46d7fce37 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Thu, 4 Oct 2018 15:39:00 +0100 Subject: [PATCH 416/485] Default to using os/lib/dbg-io for all arm-powered platforms With the exception of one specific build configuration for platform nrf52dk, all our arm-based platforms use the debugging I/O library from os/lib/dbg-io. This commit changes the build system to include this module by default for all arm devices. Platform / CPU Makefiles will no longer need to request this MODULE explicitly. Configuration provided to allow exclusion where required, as is the case for nrf52dk when NRF52_USE_RTT is set to 1. --- arch/cpu/arm/Makefile.arm | 11 +++++++++-- arch/cpu/cc2538/Makefile.cc2538 | 2 -- arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx | 2 -- .../simplelink-cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 3 --- arch/platform/jn516x/Makefile.jn516x | 2 -- arch/platform/nrf52dk/Makefile.nrf52dk | 4 ++-- 6 files changed, 11 insertions(+), 13 deletions(-) diff --git a/arch/cpu/arm/Makefile.arm b/arch/cpu/arm/Makefile.arm index 285031e82..f2f86ff7a 100644 --- a/arch/cpu/arm/Makefile.arm +++ b/arch/cpu/arm/Makefile.arm @@ -29,10 +29,17 @@ else CFLAGS += -O2 endif -### Use CMSIS and the existing dbg-io from arch/cpu/arm/common -CONTIKI_ARM_DIRS += . common/dbg-io +### Use CMSIS from arch/cpu/arm/common +CONTIKI_ARM_DIRS += . CONTIKI_CPU_DIRS += $(addprefix ../arm/, $(CONTIKI_ARM_DIRS)) +### Default to use os/lib/dbg-io unless configured to do otherwise +PLATFORM_DBG_IO ?= 0 + +ifeq ($(PLATFORM_DBG_IO),0) + MODULES += os/lib/dbg-io +endif + ### CPU-dependent cleanup files CLEAN += *.elf *.bin *.lst *.hex *.i16hex diff --git a/arch/cpu/cc2538/Makefile.cc2538 b/arch/cpu/cc2538/Makefile.cc2538 index 891215093..51a5c40c7 100644 --- a/arch/cpu/cc2538/Makefile.cc2538 +++ b/arch/cpu/cc2538/Makefile.cc2538 @@ -28,8 +28,6 @@ CONTIKI_CPU_SOURCEFILES += slip-arch.c slip.c CONTIKI_CPU_SOURCEFILES += i2c.c cc2538-temp-sensor.c vdd3-sensor.c CONTIKI_CPU_SOURCEFILES += cfs-coffee.c cfs-coffee-arch.c pwm.c -MODULES += os/lib/dbg-io - USB_SOURCEFILES += usb-core.c cdc-acm.c usb-arch.c usb-serial.c cdc-acm-descriptors.c CPU_START_SOURCEFILES = startup-gcc.c diff --git a/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx b/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx index f54a8d72d..00f9ae232 100644 --- a/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx +++ b/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx @@ -45,8 +45,6 @@ CONTIKI_CPU_SOURCEFILES += ble-cc2650.c ble-hal-cc26xx.c ble-addr.c rf-ble-cmd.c CONTIKI_CPU_SOURCEFILES += random.c soc-trng.c int-master.c CONTIKI_CPU_SOURCEFILES += spi-arch.c -MODULES += os/lib/dbg-io - CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES) CPU_START_SOURCEFILES += fault-handlers.c $(TI_XXWARE_STARTUP_SRCS) diff --git a/arch/cpu/simplelink-cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/cpu/simplelink-cc13xx-cc26xx/Makefile.cc13xx-cc26xx index 3eb11182d..dfd14637e 100644 --- a/arch/cpu/simplelink-cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/cpu/simplelink-cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -91,9 +91,6 @@ SDK_DEVICES := $(CORE_SDK)/source/ti/devices/$(SDK_DEVICES_NAME) EXTERNALDIRS += $(SDK_SOURCE) $(SDK_NORTOS) -# CPU-dependent debug source files -MODULES += os/lib/dbg-io - # CPU-dependent directories CONTIKI_CPU_DIRS += . dev $(SUBFAMILY) CONTIKI_CPU_DIRS += rf rf-settings rf-settings/$(DEVICE_FAMILY_LC) diff --git a/arch/platform/jn516x/Makefile.jn516x b/arch/platform/jn516x/Makefile.jn516x index 6cff59c65..9ad9488d5 100644 --- a/arch/platform/jn516x/Makefile.jn516x +++ b/arch/platform/jn516x/Makefile.jn516x @@ -103,8 +103,6 @@ endif CONTIKI_TARGET_DIRS = . dev CONTIKI_TARGET_MAIN = platform.c -MODULES += os/lib/dbg-io - ifeq ($(JN516x_WITH_DR1175),1) JN516x_WITH_DR1174 = 1 CFLAGS += -DSENSOR_BOARD_DR1175 diff --git a/arch/platform/nrf52dk/Makefile.nrf52dk b/arch/platform/nrf52dk/Makefile.nrf52dk index 7e931880a..302c9c91d 100644 --- a/arch/platform/nrf52dk/Makefile.nrf52dk +++ b/arch/platform/nrf52dk/Makefile.nrf52dk @@ -9,12 +9,12 @@ CONTIKI_TARGET_DIRS += . dev config CONTIKI_SOURCEFILES += platform.c leds-arch.c nrf52dk-sensors.c button-sensor.c temperature-sensor.c ifeq ($(NRF52_USE_RTT),1) -### Use the existing debug I/O in arch/cpu/arm/common +### Suppress the existing debug I/O in os/lib +PLATFORM_DBG_IO = 1 CONTIKI_TARGET_DIRS += rtt CONTIKI_SOURCEFILES += rtt-printf.c segger-rtt.c segger-rtt-printf.c else CONTIKI_SOURCEFILES += dbg.c -MODULES += os/lib/dbg-io endif ### Unless the example dictates otherwise, build with code size optimisations switched off From 123b38fc2bbf4cc19c601d46a9e70e97f6464726 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 5 Oct 2018 11:13:44 +0100 Subject: [PATCH 417/485] Rename make variable to better match current practice --- arch/cpu/arm/Makefile.arm | 4 ++-- arch/platform/nrf52dk/Makefile.nrf52dk | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/cpu/arm/Makefile.arm b/arch/cpu/arm/Makefile.arm index f2f86ff7a..83f9b8a36 100644 --- a/arch/cpu/arm/Makefile.arm +++ b/arch/cpu/arm/Makefile.arm @@ -34,9 +34,9 @@ CONTIKI_ARM_DIRS += . CONTIKI_CPU_DIRS += $(addprefix ../arm/, $(CONTIKI_ARM_DIRS)) ### Default to use os/lib/dbg-io unless configured to do otherwise -PLATFORM_DBG_IO ?= 0 +MAKE_WITH_LIB_DBG_IO ?= 1 -ifeq ($(PLATFORM_DBG_IO),0) +ifeq ($(MAKE_WITH_LIB_DBG_IO),1) MODULES += os/lib/dbg-io endif diff --git a/arch/platform/nrf52dk/Makefile.nrf52dk b/arch/platform/nrf52dk/Makefile.nrf52dk index 302c9c91d..e1d56c090 100644 --- a/arch/platform/nrf52dk/Makefile.nrf52dk +++ b/arch/platform/nrf52dk/Makefile.nrf52dk @@ -10,7 +10,7 @@ CONTIKI_SOURCEFILES += platform.c leds-arch.c nrf52dk-sensors.c button-sensor.c ifeq ($(NRF52_USE_RTT),1) ### Suppress the existing debug I/O in os/lib -PLATFORM_DBG_IO = 1 +MAKE_WITH_LIB_DBG_IO = 0 CONTIKI_TARGET_DIRS += rtt CONTIKI_SOURCEFILES += rtt-printf.c segger-rtt.c segger-rtt-printf.c else From d150de227f14971c3ae62a689feb2a5dbfd8e8be Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 10 Oct 2018 12:02:53 +0200 Subject: [PATCH 418/485] cc2420: remove unused variables --- arch/dev/cc2420/cc2420.c | 3 --- arch/dev/cc2420/cc2420.h | 3 --- 2 files changed, 6 deletions(-) diff --git a/arch/dev/cc2420/cc2420.c b/arch/dev/cc2420/cc2420.c index 5cfa00e4a..a1572b0ef 100644 --- a/arch/dev/cc2420/cc2420.c +++ b/arch/dev/cc2420/cc2420.c @@ -96,9 +96,6 @@ static const struct output_config output_power[] = { void cc2420_arch_init(void); -/* XXX hack: these will be made as Chameleon packet attributes */ -rtimer_clock_t cc2420_time_of_arrival, cc2420_time_of_departure; - int cc2420_authority_level_of_sender; volatile uint8_t cc2420_sfd_counter; diff --git a/arch/dev/cc2420/cc2420.h b/arch/dev/cc2420/cc2420.h index 07b578aa4..33135e21c 100644 --- a/arch/dev/cc2420/cc2420.h +++ b/arch/dev/cc2420/cc2420.h @@ -102,9 +102,6 @@ int cc2420_get_txpower(void); */ int cc2420_interrupt(void); -/* XXX hack: these will be made as Chameleon packet attributes */ -extern rtimer_clock_t cc2420_time_of_arrival, - cc2420_time_of_departure; extern int cc2420_authority_level_of_sender; int cc2420_on(void); From fac787231d9658572f225c136cab6af8ecd0b039 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 10 Oct 2018 16:52:33 +0200 Subject: [PATCH 419/485] Added TSCH_CONF_ARCH_HDR_PATH for platform-specific TSCH includes --- arch/dev/cc2420/cc2420-tsch-15ms.h | 35 ++++++++++++++++++++++++++++++ arch/platform/sky/contiki-conf.h | 4 ++-- os/net/mac/tsch/tsch.h | 5 +++++ 3 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 arch/dev/cc2420/cc2420-tsch-15ms.h diff --git a/arch/dev/cc2420/cc2420-tsch-15ms.h b/arch/dev/cc2420/cc2420-tsch-15ms.h new file mode 100644 index 000000000..7c0b47073 --- /dev/null +++ b/arch/dev/cc2420/cc2420-tsch-15ms.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018, RISE SICS. + * 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. + * + */ + +#include "contiki.h" + +extern const uint16_t tsch_timeslot_timing_us_15000[]; diff --git a/arch/platform/sky/contiki-conf.h b/arch/platform/sky/contiki-conf.h index 82e391164..d690af86a 100644 --- a/arch/platform/sky/contiki-conf.h +++ b/arch/platform/sky/contiki-conf.h @@ -17,8 +17,8 @@ #define NETSTACK_CONF_RADIO cc2420_driver #endif /* NETSTACK_CONF_RADIO */ -/* TSCH 15ms timeslot timing template, required for cc2420 */ -extern const uint16_t tsch_timeslot_timing_us_15000[]; +/* Symbol for the TSCH 15ms timeslot timing template */ +#define TSCH_CONF_ARCH_HDR_PATH "dev/cc2420/cc2420-tsch-15ms.h" /* The TSCH default slot length of 10ms is a bit too short for this platform, * use 15ms instead. */ diff --git a/os/net/mac/tsch/tsch.h b/os/net/mac/tsch/tsch.h index 5eed691cd..65a46521f 100644 --- a/os/net/mac/tsch/tsch.h +++ b/os/net/mac/tsch/tsch.h @@ -70,6 +70,11 @@ frequency hopping for enhanced reliability. #include "sys/cooja_mt.h" #endif /* CONTIKI_TARGET_COOJA */ +/* Include Arch-Specific conf */ +#ifdef TSCH_CONF_ARCH_HDR_PATH +#include TSCH_CONF_ARCH_HDR_PATH +#endif /* TSCH_CONF_ARCH_HDR_PATH */ + /*********** Macros *********/ /* Wait for a condition with timeout t0+offset. */ From b7c9cae60ccca37f258df39db3c56c72531df0a9 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 10 Oct 2018 17:01:11 +0200 Subject: [PATCH 420/485] Platform Zoul: move generic cc2538 defines from contiki-conf.h to cc2538-def.h --- arch/cpu/cc2538/cc2538-def.h | 15 +++++++++++++++ arch/platform/zoul/contiki-conf.h | 22 ---------------------- examples/6tisch/sixtop/project-conf.h | 10 ---------- 3 files changed, 15 insertions(+), 32 deletions(-) diff --git a/arch/cpu/cc2538/cc2538-def.h b/arch/cpu/cc2538/cc2538-def.h index 75195258e..163456a14 100644 --- a/arch/cpu/cc2538/cc2538-def.h +++ b/arch/cpu/cc2538/cc2538-def.h @@ -41,6 +41,21 @@ /* 192us as in datasheet but ACKs are not always received, so adjusted to 250us */ #define CC2538_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(250)) #define CC2538_DELAY_BEFORE_DETECT 0 +/* Frame filtering done in software */ +#define TSCH_CONF_HW_FRAME_FILTERING 0 + +#ifndef TSCH_CONF_BASE_DRIFT_PPM +/* The drift compared to "true" 10ms slots. + * Enable adaptive sync to enable compensation for this. + * Slot length 10000 usec + * 328 ticks + * Tick duration 30.517578125 usec + * Real slot duration 10009.765625 usec + * Target - real duration = -9.765625 usec + * TSCH_CONF_BASE_DRIFT_PPM -977 + */ +#define TSCH_CONF_BASE_DRIFT_PPM -977 +#endif /*---------------------------------------------------------------------------*/ #define SPI_CONF_CONTROLLER_COUNT 2 diff --git a/arch/platform/zoul/contiki-conf.h b/arch/platform/zoul/contiki-conf.h index b8f545bf0..a4c455d86 100644 --- a/arch/platform/zoul/contiki-conf.h +++ b/arch/platform/zoul/contiki-conf.h @@ -65,11 +65,6 @@ uint16_t *radio_tsch_timeslot_timing(void); /** @} */ /*---------------------------------------------------------------------------*/ -/* 352us from calling transmit() until the SFD byte has been sent */ -#define CC2538_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(352)) -/* 192us as in datasheet but ACKs are not always received, so adjusted to 250us */ -#define CC2538_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(250)) -#define CC2538_DELAY_BEFORE_DETECT 0 #define RADIO_PHY_OVERHEAD radio_phy_overhead() #define RADIO_BYTE_AIR_TIME radio_byte_air_time() @@ -79,23 +74,6 @@ uint16_t *radio_tsch_timeslot_timing(void); #define TSCH_CONF_DEFAULT_TIMESLOT_TIMING radio_tsch_timeslot_timing() -#ifndef TSCH_CONF_BASE_DRIFT_PPM -/* The drift compared to "true" 10ms slots. - * Enable adaptive sync to enable compensation for this. - * Slot length 10000 usec - * 328 ticks - * Tick duration 30.517578125 usec - * Real slot duration 10009.765625 usec - * Target - real duration = -9.765625 usec - * TSCH_CONF_BASE_DRIFT_PPM -977 - */ -#define TSCH_CONF_BASE_DRIFT_PPM -977 -#endif - -#if MAC_CONF_WITH_TSCH -#define TSCH_CONF_HW_FRAME_FILTERING 0 -#endif /* MAC_CONF_WITH_TSCH */ - /*---------------------------------------------------------------------------*/ /** * \name Serial Boot Loader Backdoor configuration diff --git a/examples/6tisch/sixtop/project-conf.h b/examples/6tisch/sixtop/project-conf.h index e3d82d972..bb107175f 100755 --- a/examples/6tisch/sixtop/project-conf.h +++ b/examples/6tisch/sixtop/project-conf.h @@ -74,14 +74,4 @@ #endif /* WITH_SECURITY */ -/*******************************************************/ -/************* Other system configuration **************/ -/*******************************************************/ - -#if CONTIKI_TARGET_CC2538DK || CONTIKI_TARGET_ZOUL || \ - CONTIKI_TARGET_OPENMOTE_CC2538 -#define TSCH_CONF_HW_FRAME_FILTERING 0 -#endif /* CONTIKI_TARGET_CC2538DK || CONTIKI_TARGET_ZOUL \ - || CONTIKI_TARGET_OPENMOTE_CC2538 */ - #endif /* PROJECT_CONF_H_ */ From 1627aa18a4476d41ed80301192db835362de081f Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Thu, 11 Oct 2018 20:18:51 +0200 Subject: [PATCH 421/485] Add missing return statement --- arch/cpu/cc2538/dev/cc2538-rf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/cpu/cc2538/dev/cc2538-rf.c b/arch/cpu/cc2538/dev/cc2538-rf.c index 5a8bb8d6f..bddfcc942 100644 --- a/arch/cpu/cc2538/dev/cc2538-rf.c +++ b/arch/cpu/cc2538/dev/cc2538-rf.c @@ -865,6 +865,7 @@ get_value(radio_param_t param, radio_value_t *value) return RADIO_RESULT_OK; case RADIO_CONST_PHY_OVERHEAD: *value = (radio_value_t)3; /* 1 len byte, 2 bytes CRC */ + return RADIO_RESULT_OK; case RADIO_CONST_BYTE_AIR_TIME: *value = (radio_value_t)32; /* 250kbps data rate. One byte = 32us.*/ return RADIO_RESULT_OK; From b80d11325368c3bbee1961bdef34d1ce9d3a3a56 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Thu, 11 Oct 2018 20:23:21 +0200 Subject: [PATCH 422/485] Add a common set of portable RTIMER_BUSY_WAIT functions --- arch/dev/cc1200/cc1200.c | 80 ++++++++--------------- arch/platform/cooja/dev/watchdog.c | 7 +- arch/platform/jn516x/dev/micromac-radio.c | 13 +--- arch/platform/jn516x/dev/uart-driver.c | 10 +-- arch/platform/zoul/dev/cc1200-zoul-arch.c | 15 +---- arch/platform/zoul/dev/dht22.c | 13 +--- os/net/mac/csma/csma-output.c | 15 +---- os/net/mac/tsch/tsch-slot-operation.c | 23 +++---- os/net/mac/tsch/tsch.c | 2 +- os/net/mac/tsch/tsch.h | 18 ----- os/sys/rtimer.h | 19 ++++++ 11 files changed, 70 insertions(+), 145 deletions(-) diff --git a/arch/dev/cc1200/cc1200.c b/arch/dev/cc1200/cc1200.c index 5f76e4817..dd90fdda7 100644 --- a/arch/dev/cc1200/cc1200.c +++ b/arch/dev/cc1200/cc1200.c @@ -310,15 +310,7 @@ extern const cc1200_rf_cfg_t CC1200_RF_CFG; #define LOCK_SPI() do { spi_locked++; } while(0) #define SPI_IS_LOCKED() (spi_locked != 0) #define RELEASE_SPI() do { spi_locked--; } while(0) -/*---------------------------------------------------------------------------*/ -#define BUSYWAIT_UNTIL(cond, max_time) \ - do { \ - rtimer_clock_t t0; \ - t0 = RTIMER_NOW(); \ - while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time))) { \ - watchdog_periodic(); \ - } \ - } while(0) + /*---------------------------------------------------------------------------*/ #if CC1200_USE_GPIO2 /* Configure GPIO interrupts. GPIO0: falling, GPIO2: rising edge */ @@ -378,29 +370,9 @@ extern const cc1200_rf_cfg_t CC1200_RF_CFG; #define INFO(...) #endif -#if DEBUG_LEVEL > 0 -/* - * As BUSYWAIT_UNTIL was mainly used to test for a state transition, - * we define a separate macro for this adding the possibility to - * throw an error message when the timeout exceeds - */ -#define BUSYWAIT_UNTIL_STATE(s, t) \ - do { \ - rtimer_clock_t t0; \ - t0 = RTIMER_NOW(); \ - while((state() != s) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (t))) {} \ - if(!(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (t)))) { \ - printf("RF: Timeout exceeded in line %d!\n", __LINE__); \ - } \ - } while(0) -#else -#define BUSYWAIT_UNTIL_STATE(s, t) \ - do { \ - rtimer_clock_t t0; \ - t0 = RTIMER_NOW(); \ - while((state() != s) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (t))) {} \ - } while(0) -#endif +/* Busy-wait (time-bounded) until the radio reaches a given state */ +#define RTIMER_BUSYWAIT_UNTIL_STATE(s, t) RTIMER_BUSYWAIT_UNTIL(state() == (s), t) + /*---------------------------------------------------------------------------*/ /* Variables */ /*---------------------------------------------------------------------------*/ @@ -604,7 +576,7 @@ PROCESS_THREAD(cc1200_process, ev, data) /* * We are on and not in TX. As every function of this driver * assures that we are in RX mode - * (using BUSYWAIT_UNTIL_STATE(STATE_RX, ...) construct) in + * (using RTIMER_BUSYWAIT_UNTIL_STATE(STATE_RX, ...) construct) in * either rx_rx(), idle_calibrate_rx() or transmit(), * something probably went wrong in the rx interrupt handler * if we are not in RX at this point. @@ -893,7 +865,7 @@ transmit(unsigned short transmit_len) * again as they were turned off in idle() */ - BUSYWAIT_UNTIL_STATE(STATE_RX, + RTIMER_BUSYWAIT_UNTIL_STATE(STATE_RX, CC1200_RF_CFG.tx_rx_turnaround); ENABLE_GPIO_INTERRUPTS(); @@ -1033,7 +1005,7 @@ channel_clear(void) } /* Wait for CARRIER_SENSE_VALID signal */ - BUSYWAIT_UNTIL(((rssi0 = single_read(CC1200_RSSI0)) + RTIMER_BUSYWAIT_UNTIL(((rssi0 = single_read(CC1200_RSSI0)) & CC1200_CARRIER_SENSE_VALID), RTIMER_SECOND / 100); RF_ASSERT(rssi0 & CC1200_CARRIER_SENSE_VALID); @@ -1135,7 +1107,7 @@ on(void) /* Wake-up procedure. Wait for GPIO0 to de-assert (CHIP_RDYn) */ cc1200_arch_spi_select(); - BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 0), + RTIMER_BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 0), RTIMER_SECOND / 100); RF_ASSERT((cc1200_arch_gpio0_read_pin() == 0)); cc1200_arch_spi_deselect(); @@ -1239,7 +1211,7 @@ get_rssi(void) } /* Wait for CARRIER_SENSE_VALID signal */ - BUSYWAIT_UNTIL(((rssi0 = single_read(CC1200_RSSI0)) + RTIMER_BUSYWAIT_UNTIL(((rssi0 = single_read(CC1200_RSSI0)) & CC1200_CARRIER_SENSE_VALID), RTIMER_SECOND / 100); RF_ASSERT(rssi0 & CC1200_CARRIER_SENSE_VALID); @@ -1706,20 +1678,20 @@ configure(void) while(1) { #if (CC1200_RF_TESTMODE == 1) watchdog_periodic(); - BUSYWAIT_UNTIL(0, RTIMER_SECOND / 10); + RTIMER_BUSYWAIT(RTIMER_SECOND / 10); leds_off(LEDS_YELLOW); leds_on(LEDS_RED); watchdog_periodic(); - BUSYWAIT_UNTIL(0, RTIMER_SECOND / 10); + RTIMER_BUSYWAIT(RTIMER_SECOND / 10); leds_off(LEDS_RED); leds_on(LEDS_YELLOW); #else watchdog_periodic(); - BUSYWAIT_UNTIL(0, RTIMER_SECOND / 10); + RTIMER_BUSYWAIT(RTIMER_SECOND / 10); leds_off(LEDS_GREEN); leds_on(LEDS_RED); watchdog_periodic(); - BUSYWAIT_UNTIL(0, RTIMER_SECOND / 10); + RTIMER_BUSYWAIT(RTIMER_SECOND / 10); leds_off(LEDS_RED); leds_on(LEDS_GREEN); #endif @@ -1741,11 +1713,11 @@ configure(void) while(1) { watchdog_periodic(); - BUSYWAIT_UNTIL(0, RTIMER_SECOND / 10); + RTIMER_BUSYWAIT(RTIMER_SECOND / 10); leds_off(LEDS_GREEN); leds_on(LEDS_YELLOW); watchdog_periodic(); - BUSYWAIT_UNTIL(0, RTIMER_SECOND / 10); + RTIMER_BUSYWAIT(RTIMER_SECOND / 10); leds_off(LEDS_YELLOW); leds_on(LEDS_GREEN); clock_delay_usec(1000); @@ -1866,8 +1838,8 @@ calibrate(void) INFO("RF: Calibrate\n"); strobe(CC1200_SCAL); - BUSYWAIT_UNTIL_STATE(STATE_CALIBRATE, RTIMER_SECOND / 100); - BUSYWAIT_UNTIL_STATE(STATE_IDLE, RTIMER_SECOND / 100); + RTIMER_BUSYWAIT_UNTIL_STATE(STATE_CALIBRATE, RTIMER_SECOND / 100); + RTIMER_BUSYWAIT_UNTIL_STATE(STATE_IDLE, RTIMER_SECOND / 100); #if CC1200_CAL_TIMEOUT_SECONDS cal_timer = clock_seconds(); @@ -1904,7 +1876,7 @@ idle(void) } strobe(CC1200_SIDLE); - BUSYWAIT_UNTIL_STATE(STATE_IDLE, RTIMER_SECOND / 100); + RTIMER_BUSYWAIT_UNTIL_STATE(STATE_IDLE, RTIMER_SECOND / 100); } /* idle(), 21.05.2015 */ /*---------------------------------------------------------------------------*/ @@ -1922,7 +1894,7 @@ idle_calibrate_rx(void) rf_flags &= ~RF_RX_PROCESSING_PKT; strobe(CC1200_SFRX); strobe(CC1200_SRX); - BUSYWAIT_UNTIL_STATE(STATE_RX, RTIMER_SECOND / 100); + RTIMER_BUSYWAIT_UNTIL_STATE(STATE_RX, RTIMER_SECOND / 100); ENABLE_GPIO_INTERRUPTS(); @@ -1947,7 +1919,7 @@ rx_rx(void) strobe(CC1200_SFTX); } else { strobe(CC1200_SIDLE); - BUSYWAIT_UNTIL_STATE(STATE_IDLE, + RTIMER_BUSYWAIT_UNTIL_STATE(STATE_IDLE, RTIMER_SECOND / 100); } @@ -1959,7 +1931,7 @@ rx_rx(void) strobe(CC1200_SFRX); strobe(CC1200_SRX); - BUSYWAIT_UNTIL_STATE(STATE_RX, RTIMER_SECOND / 100); + RTIMER_BUSYWAIT_UNTIL_STATE(STATE_RX, RTIMER_SECOND / 100); } /*---------------------------------------------------------------------------*/ @@ -2002,14 +1974,14 @@ idle_tx_rx(const uint8_t *payload, uint16_t payload_len) #if USE_SFSTXON /* Wait for synthesizer to be ready */ - BUSYWAIT_UNTIL_STATE(STATE_FSTXON, RTIMER_SECOND / 100); + RTIMER_BUSYWAIT_UNTIL_STATE(STATE_FSTXON, RTIMER_SECOND / 100); #endif /* Start TX */ strobe(CC1200_STX); /* Wait for TX to start. */ - BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 1), RTIMER_SECOND / 100); + RTIMER_BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 1), RTIMER_SECOND / 100); /* Turned off at the latest in idle() */ TX_LEDS_ON(); @@ -2072,7 +2044,7 @@ idle_tx_rx(const uint8_t *payload, uint16_t payload_len) */ INFO("RF: TX failure!\n"); - BUSYWAIT_UNTIL((state() != STATE_TX), RTIMER_SECOND / 100); + RTIMER_BUSYWAIT_UNTIL((state() != STATE_TX), RTIMER_SECOND / 100); /* Re-configure GPIO2 */ single_write(CC1200_IOCFG2, GPIO2_IOCFG); idle(); @@ -2086,12 +2058,12 @@ idle_tx_rx(const uint8_t *payload, uint16_t payload_len) } else { /* Wait for TX to complete */ - BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 0), + RTIMER_BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 0), CC1200_RF_CFG.tx_pkt_lifetime); } #else /* Wait for TX to complete */ - BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 0), + RTIMER_BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 0), CC1200_RF_CFG.tx_pkt_lifetime); #endif diff --git a/arch/platform/cooja/dev/watchdog.c b/arch/platform/cooja/dev/watchdog.c index a30fc0fc8..347d9a996 100644 --- a/arch/platform/cooja/dev/watchdog.c +++ b/arch/platform/cooja/dev/watchdog.c @@ -30,8 +30,10 @@ * */ - /* Dummy watchdog routines for the Raven 1284p */ + /* Dummy watchdog routines for Cooja motes */ #include "dev/watchdog.h" +#include "lib/simEnvChange.h" +#include "sys/cooja_mt.h" /*---------------------------------------------------------------------------*/ void @@ -47,6 +49,9 @@ watchdog_start(void) void watchdog_periodic(void) { + /* Yield and give control back to the simulator scheduler */ + simProcessRunValue = 1; + cooja_mt_yield(); } /*---------------------------------------------------------------------------*/ void diff --git a/arch/platform/jn516x/dev/micromac-radio.c b/arch/platform/jn516x/dev/micromac-radio.c index 6e2ddb908..bad81f4f0 100644 --- a/arch/platform/jn516x/dev/micromac-radio.c +++ b/arch/platform/jn516x/dev/micromac-radio.c @@ -130,13 +130,6 @@ #define MICROMAC_CONF_ALWAYS_ON 1 #endif /* MICROMAC_CONF_ALWAYS_ON */ -#define BUSYWAIT_UNTIL(cond, max_time) \ - do { \ - rtimer_clock_t t0; \ - t0 = RTIMER_NOW(); \ - while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time))) ; \ - } while(0) - /* Local variables */ static volatile signed char radio_last_rssi; static volatile uint8_t radio_last_correlation; /* LQI */ @@ -377,14 +370,14 @@ transmit(unsigned short payload_len) (send_on_cca ? E_MMAC_TX_USE_CCA : E_MMAC_TX_NO_CCA)); #endif if(poll_mode) { - BUSYWAIT_UNTIL(u32MMAC_PollInterruptSource(E_MMAC_INT_TX_COMPLETE), MAX_PACKET_DURATION); + RTIMER_BUSYWAIT_UNTIL(u32MMAC_PollInterruptSource(E_MMAC_INT_TX_COMPLETE), MAX_PACKET_DURATION); } else { if(in_ack_transmission) { /* as nested interupts are not possible, the tx flag will never be cleared */ - BUSYWAIT_UNTIL(FALSE, MAX_ACK_DURATION); + RTIMER_BUSYWAIT_UNTIL(FALSE, MAX_ACK_DURATION); } else { /* wait until the tx flag is cleared */ - BUSYWAIT_UNTIL(!tx_in_progress, MAX_PACKET_DURATION); + RTIMER_BUSYWAIT_UNTIL(!tx_in_progress, MAX_PACKET_DURATION); } } diff --git a/arch/platform/jn516x/dev/uart-driver.c b/arch/platform/jn516x/dev/uart-driver.c index 31a4b286c..aeeffeeb4 100644 --- a/arch/platform/jn516x/dev/uart-driver.c +++ b/arch/platform/jn516x/dev/uart-driver.c @@ -66,14 +66,6 @@ extern volatile unsigned char xonxoff_state; #endif /* UART_XONXOFF_FLOW_CTRL */ -/*** Macro Definitions ***/ -#define BUSYWAIT_UNTIL(cond, max_time) \ - do { \ - rtimer_clock_t t0; \ - t0 = RTIMER_NOW(); \ - while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time))) ; \ - } while(0) - #define DEBUG_UART_BUFFERED FALSE #define CHAR_DEADLINE (uart_char_delay * 100) @@ -276,7 +268,7 @@ uart_driver_write_with_deadline(uint8_t uart_dev, uint8_t ch) volatile int16_t write = 0; watchdog_periodic(); /* wait until there is space in tx fifo */ - BUSYWAIT_UNTIL(write = (uart_driver_get_tx_fifo_available_space(uart_dev) > 0), + RTIMER_BUSYWAIT_UNTIL(write = (uart_driver_get_tx_fifo_available_space(uart_dev) > 0), CHAR_DEADLINE); /* write only if there is space so we do not get stuck */ if(write) { diff --git a/arch/platform/zoul/dev/cc1200-zoul-arch.c b/arch/platform/zoul/dev/cc1200-zoul-arch.c index 8c9d8cdd7..b0fd8dd96 100644 --- a/arch/platform/zoul/dev/cc1200-zoul-arch.c +++ b/arch/platform/zoul/dev/cc1200-zoul-arch.c @@ -76,18 +76,8 @@ /*---------------------------------------------------------------------------*/ #if DEBUG_CC1200_ARCH > 0 #define PRINTF(...) printf(__VA_ARGS__) -#define BUSYWAIT_UNTIL(cond, max_time) \ - do { \ - rtimer_clock_t t0; \ - t0 = RTIMER_NOW(); \ - while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time))) {} \ - if(!(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time)))) { \ - printf("ARCH: Timeout exceeded in line %d!\n", __LINE__); \ - } \ - } while(0) #else #define PRINTF(...) -#define BUSYWAIT_UNTIL(cond, max_time) while(!cond) #endif /*---------------------------------------------------------------------------*/ extern int cc1200_rx_interrupt(void); @@ -105,7 +95,7 @@ cc1200_arch_spi_select(void) /* Set CSn to low (0) */ GPIO_CLR_PIN(CC1200_SPI_CSN_PORT_BASE, CC1200_SPI_CSN_PIN_MASK); /* The MISO pin should go low before chip is fully enabled. */ - BUSYWAIT_UNTIL( + RTIMER_BUSYWAIT_UNTIL( GPIO_READ_PIN(CC1200_SPI_MISO_PORT_BASE, CC1200_SPI_MISO_PIN_MASK) == 0, RTIMER_SECOND / 100); } @@ -288,7 +278,7 @@ cc1200_arch_init(void) cc1200_arch_spi_deselect(); /* Ensure MISO is high */ - BUSYWAIT_UNTIL( + RTIMER_BUSYWAIT_UNTIL( GPIO_READ_PIN(CC1200_SPI_MISO_PORT_BASE, CC1200_SPI_MISO_PIN_MASK), RTIMER_SECOND / 10); } @@ -297,4 +287,3 @@ cc1200_arch_init(void) * @} * @} */ - diff --git a/arch/platform/zoul/dev/dht22.c b/arch/platform/zoul/dev/dht22.c index e5d14d53b..23174b2e6 100644 --- a/arch/platform/zoul/dev/dht22.c +++ b/arch/platform/zoul/dev/dht22.c @@ -51,15 +51,6 @@ #define PRINTF(...) #endif /*---------------------------------------------------------------------------*/ -#define BUSYWAIT_UNTIL(max_time) \ - do { \ - rtimer_clock_t t0; \ - t0 = RTIMER_NOW(); \ - while(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time))) { \ - watchdog_periodic(); \ - } \ - } while(0) -/*---------------------------------------------------------------------------*/ #define DHT22_PORT_BASE GPIO_PORT_TO_BASE(DHT22_PORT) #define DHT22_PIN_MASK GPIO_PIN_MASK(DHT22_PIN) /*---------------------------------------------------------------------------*/ @@ -80,12 +71,12 @@ dht22_read(void) /* Exit low power mode and initialize variables */ GPIO_SET_OUTPUT(DHT22_PORT_BASE, DHT22_PIN_MASK); GPIO_SET_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK); - BUSYWAIT_UNTIL(DHT22_AWAKE_TIME); + RTIMER_BUSYWAIT(DHT22_AWAKE_TIME); memset(dht22_data, 0, DHT22_BUFFER); /* Initialization sequence */ GPIO_CLR_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK); - BUSYWAIT_UNTIL(DHT22_START_TIME); + RTIMER_BUSYWAIT(DHT22_START_TIME); GPIO_SET_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK); clock_delay_usec(DHT22_READY_TIME); diff --git a/os/net/mac/csma/csma-output.c b/os/net/mac/csma/csma-output.c index 9c88d569d..20d96b1d1 100644 --- a/os/net/mac/csma/csma-output.c +++ b/os/net/mac/csma/csma-output.c @@ -50,11 +50,6 @@ #include "lib/list.h" #include "lib/memb.h" -#if CONTIKI_TARGET_COOJA -#include "lib/simEnvChange.h" -#include "sys/cooja_mt.h" -#endif /* CONTIKI_TARGET_COOJA */ - /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "CSMA" @@ -207,10 +202,7 @@ 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 - simProcessRunValue = 1; - cooja_mt_yield(); -#endif /* CONTIKI_TARGET_COOJA */ + watchdog_periodic(); } ret = MAC_TX_NOACK; @@ -225,10 +217,7 @@ send_one_packet(void *ptr) watchdog_periodic(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + CSMA_AFTER_ACK_DETECTED_WAIT_TIME)) { -#if CONTIKI_TARGET_COOJA - simProcessRunValue = 1; - cooja_mt_yield(); -#endif /* CONTIKI_TARGET_COOJA */ + watchdog_periodic(); } } diff --git a/os/net/mac/tsch/tsch-slot-operation.c b/os/net/mac/tsch/tsch-slot-operation.c index b1a3f6ba8..841dee07f 100644 --- a/os/net/mac/tsch/tsch-slot-operation.c +++ b/os/net/mac/tsch/tsch-slot-operation.c @@ -52,10 +52,6 @@ #include "net/queuebuf.h" #include "net/mac/framer/framer-802154.h" #include "net/mac/tsch/tsch.h" -#if CONTIKI_TARGET_COOJA -#include "lib/simEnvChange.h" -#include "sys/cooja_mt.h" -#endif /* CONTIKI_TARGET_COOJA */ #include "sys/log.h" /* TSCH debug macros, i.e. to set LEDs or GPIOs on various TSCH @@ -206,10 +202,7 @@ tsch_get_lock(void) busy_wait = 1; busy_wait_time = RTIMER_NOW(); while(tsch_in_slot_operation) { -#if CONTIKI_TARGET_COOJA - simProcessRunValue = 1; - cooja_mt_yield(); -#endif /* CONTIKI_TARGET_COOJA */ + watchdog_periodic(); } busy_wait_time = RTIMER_NOW() - busy_wait_time; } @@ -303,7 +296,7 @@ tsch_schedule_slot_operation(struct rtimer *tm, rtimer_clock_t ref_time, rtimer_ } /* block until the time to schedule comes */ - BUSYWAIT_UNTIL_ABS(0, ref_time, offset); + RTIMER_BUSYWAIT_UNTIL_ABS(0, ref_time, offset); return 0; } /*---------------------------------------------------------------------------*/ @@ -314,7 +307,7 @@ tsch_schedule_slot_operation(struct rtimer *tm, rtimer_clock_t ref_time, rtimer_ do { \ if(tsch_schedule_slot_operation(tm, ref_time, offset - RTIMER_GUARD, str)) { \ PT_YIELD(pt); \ - BUSYWAIT_UNTIL_ABS(0, ref_time, offset); \ + RTIMER_BUSYWAIT_UNTIL_ABS(0, ref_time, offset); \ } \ } while(0); /*---------------------------------------------------------------------------*/ @@ -514,7 +507,7 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t)) TSCH_DEBUG_TX_EVENT(); tsch_radio_on(TSCH_RADIO_CMD_ON_WITHIN_TIMESLOT); /* CCA */ - BUSYWAIT_UNTIL_ABS(!(cca_status &= NETSTACK_RADIO.channel_clear()), + RTIMER_BUSYWAIT_UNTIL_ABS(!(cca_status &= NETSTACK_RADIO.channel_clear()), current_slot_start, tsch_timing[tsch_ts_cca_offset] + tsch_timing[tsch_ts_cca]); TSCH_DEBUG_TX_EVENT(); /* there is not enough time to turn radio off */ @@ -561,14 +554,14 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t)) TSCH_DEBUG_TX_EVENT(); tsch_radio_on(TSCH_RADIO_CMD_ON_WITHIN_TIMESLOT); /* Wait for ACK to come */ - BUSYWAIT_UNTIL_ABS(NETSTACK_RADIO.receiving_packet(), + RTIMER_BUSYWAIT_UNTIL_ABS(NETSTACK_RADIO.receiving_packet(), tx_start_time, tx_duration + tsch_timing[tsch_ts_rx_ack_delay] + tsch_timing[tsch_ts_ack_wait] + RADIO_DELAY_BEFORE_DETECT); TSCH_DEBUG_TX_EVENT(); ack_start_time = RTIMER_NOW() - RADIO_DELAY_BEFORE_DETECT; /* Wait for ACK to finish */ - BUSYWAIT_UNTIL_ABS(!NETSTACK_RADIO.receiving_packet(), + RTIMER_BUSYWAIT_UNTIL_ABS(!NETSTACK_RADIO.receiving_packet(), ack_start_time, tsch_timing[tsch_ts_max_ack]); TSCH_DEBUG_TX_EVENT(); tsch_radio_off(TSCH_RADIO_CMD_OFF_WITHIN_TIMESLOT); @@ -748,7 +741,7 @@ PT_THREAD(tsch_rx_slot(struct pt *pt, struct rtimer *t)) packet_seen = NETSTACK_RADIO.receiving_packet() || NETSTACK_RADIO.pending_packet(); if(!packet_seen) { /* Check if receiving within guard time */ - BUSYWAIT_UNTIL_ABS((packet_seen = NETSTACK_RADIO.receiving_packet()), + RTIMER_BUSYWAIT_UNTIL_ABS((packet_seen = NETSTACK_RADIO.receiving_packet()), current_slot_start, tsch_timing[tsch_ts_rx_offset] + tsch_timing[tsch_ts_rx_wait] + RADIO_DELAY_BEFORE_DETECT); } if(!packet_seen) { @@ -760,7 +753,7 @@ PT_THREAD(tsch_rx_slot(struct pt *pt, struct rtimer *t)) rx_start_time = RTIMER_NOW() - RADIO_DELAY_BEFORE_DETECT; /* Wait until packet is received, turn radio off */ - BUSYWAIT_UNTIL_ABS(!NETSTACK_RADIO.receiving_packet(), + RTIMER_BUSYWAIT_UNTIL_ABS(!NETSTACK_RADIO.receiving_packet(), current_slot_start, tsch_timing[tsch_ts_rx_offset] + tsch_timing[tsch_ts_rx_wait] + tsch_timing[tsch_ts_max_tx]); TSCH_DEBUG_RX_EVENT(); tsch_radio_off(TSCH_RADIO_CMD_OFF_WITHIN_TIMESLOT); diff --git a/os/net/mac/tsch/tsch.c b/os/net/mac/tsch/tsch.c index e78b888d0..25b565809 100644 --- a/os/net/mac/tsch/tsch.c +++ b/os/net/mac/tsch/tsch.c @@ -737,7 +737,7 @@ PT_THREAD(tsch_scan(struct pt *pt)) if(!is_packet_pending && NETSTACK_RADIO.receiving_packet()) { /* If we are currently receiving a packet, wait until end of reception */ t0 = RTIMER_NOW(); - BUSYWAIT_UNTIL_ABS((is_packet_pending = NETSTACK_RADIO.pending_packet()), t0, RTIMER_SECOND / 100); + RTIMER_BUSYWAIT_UNTIL_ABS((is_packet_pending = NETSTACK_RADIO.pending_packet()), t0, RTIMER_SECOND / 100); } if(is_packet_pending) { diff --git a/os/net/mac/tsch/tsch.h b/os/net/mac/tsch/tsch.h index 65a46521f..8590dcb38 100644 --- a/os/net/mac/tsch/tsch.h +++ b/os/net/mac/tsch/tsch.h @@ -65,30 +65,12 @@ frequency hopping for enhanced reliability. #include "net/mac/tsch/tsch-rpl.h" #endif /* UIP_CONF_IPV6_RPL */ -#if CONTIKI_TARGET_COOJA -#include "lib/simEnvChange.h" -#include "sys/cooja_mt.h" -#endif /* CONTIKI_TARGET_COOJA */ /* Include Arch-Specific conf */ #ifdef TSCH_CONF_ARCH_HDR_PATH #include TSCH_CONF_ARCH_HDR_PATH #endif /* TSCH_CONF_ARCH_HDR_PATH */ -/*********** Macros *********/ - -/* Wait for a condition with timeout t0+offset. */ -#if CONTIKI_TARGET_COOJA -#define BUSYWAIT_UNTIL_ABS(cond, t0, offset) \ - while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), (t0) + (offset))) { \ - simProcessRunValue = 1; \ - cooja_mt_yield(); \ - }; -#else -#define BUSYWAIT_UNTIL_ABS(cond, t0, offset) \ - while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), (t0) + (offset))) ; -#endif /* CONTIKI_TARGET_COOJA */ - /*********** Callbacks *********/ /* Link callbacks to RPL in case RPL is enabled */ diff --git a/os/sys/rtimer.h b/os/sys/rtimer.h index 44ad92a2f..8af9a40f3 100644 --- a/os/sys/rtimer.h +++ b/os/sys/rtimer.h @@ -54,6 +54,7 @@ #define RTIMER_H_ #include "contiki.h" +#include "dev/watchdog.h" /** \brief The rtimer size (in bytes) */ #ifdef RTIMER_CONF_CLOCK_SIZE @@ -186,6 +187,24 @@ void rtimer_arch_schedule(rtimer_clock_t t); #define RTIMER_GUARD_TIME (RTIMER_ARCH_SECOND >> 14) #endif /* RTIMER_CONF_GUARD_TIME */ +/** \brief Busy-wait until a condition. Start time is t0, max wait time is max_time */ +#define RTIMER_BUSYWAIT_UNTIL_ABS(cond, t0, max_time) \ + do { \ + while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), (t0) + (max_time))) { \ + watchdog_periodic(); \ + } \ + } while(0) + +/** \brief Busy-wait until a condition for at most max_time */ +#define RTIMER_BUSYWAIT_UNTIL(cond, max_time) \ + do { \ + rtimer_clock_t t0 = RTIMER_NOW(); \ + RTIMER_BUSYWAIT_UNTIL_ABS(cond, t0, max_time); \ + } while(0) + +/** \brief Busy-wait for a fixed duration */ +#define RTIMER_BUSYWAIT(duration) RTIMER_BUSYWAIT_UNTIL(0, duration) + #endif /* RTIMER_H_ */ /** @} */ From 4097883229ea22c0337dca62f90a978c264e76ad Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Thu, 31 May 2018 01:41:24 -0700 Subject: [PATCH 423/485] CSMA: simplify routine that waits for ACK --- os/net/mac/csma/csma-output.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/os/net/mac/csma/csma-output.c b/os/net/mac/csma/csma-output.c index 20d96b1d1..1773e0cb0 100644 --- a/os/net/mac/csma/csma-output.c +++ b/os/net/mac/csma/csma-output.c @@ -196,14 +196,10 @@ send_one_packet(void *ptr) if(is_broadcast) { ret = MAC_TX_OK; } else { - rtimer_clock_t wt; - /* Check for ack */ - wt = RTIMER_NOW(); - watchdog_periodic(); - while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + CSMA_ACK_WAIT_TIME)) { - watchdog_periodic(); - } + + /* Wait for max CSMA_ACK_WAIT_TIME */ + RTIMER_BUSYWAIT_UNTIL(NETSTACK_RADIO.pending_packet(), CSMA_ACK_WAIT_TIME); ret = MAC_TX_NOACK; if(NETSTACK_RADIO.receiving_packet() || @@ -212,14 +208,8 @@ send_one_packet(void *ptr) int len; uint8_t ackbuf[CSMA_ACK_LEN]; - if(CSMA_AFTER_ACK_DETECTED_WAIT_TIME > 0) { - wt = RTIMER_NOW(); - watchdog_periodic(); - while(RTIMER_CLOCK_LT(RTIMER_NOW(), - wt + CSMA_AFTER_ACK_DETECTED_WAIT_TIME)) { - watchdog_periodic(); - } - } + /* Wait an additional CSMA_AFTER_ACK_DETECTED_WAIT_TIME to complete reception */ + RTIMER_BUSYWAIT_UNTIL(NETSTACK_RADIO.pending_packet(), CSMA_AFTER_ACK_DETECTED_WAIT_TIME); if(NETSTACK_RADIO.pending_packet()) { len = NETSTACK_RADIO.read(ackbuf, CSMA_ACK_LEN); From d85cecea34d30e560772bfe0f520ee7a9a0a608d Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sun, 23 Sep 2018 15:52:13 +0200 Subject: [PATCH 424/485] rtimer.h: add return value to RTIMER_BUSYWAIT* macros --- os/sys/rtimer.h | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/os/sys/rtimer.h b/os/sys/rtimer.h index 8af9a40f3..260f08950 100644 --- a/os/sys/rtimer.h +++ b/os/sys/rtimer.h @@ -55,6 +55,7 @@ #include "contiki.h" #include "dev/watchdog.h" +#include /** \brief The rtimer size (in bytes) */ #ifdef RTIMER_CONF_CLOCK_SIZE @@ -189,18 +190,20 @@ void rtimer_arch_schedule(rtimer_clock_t t); /** \brief Busy-wait until a condition. Start time is t0, max wait time is max_time */ #define RTIMER_BUSYWAIT_UNTIL_ABS(cond, t0, max_time) \ - do { \ - while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), (t0) + (max_time))) { \ - watchdog_periodic(); \ - } \ - } while(0) + ({ \ + bool c; \ + while(!(c = cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), (t0) + (max_time))) { \ + watchdog_periodic(); \ + } \ + c; \ + }) /** \brief Busy-wait until a condition for at most max_time */ -#define RTIMER_BUSYWAIT_UNTIL(cond, max_time) \ - do { \ - rtimer_clock_t t0 = RTIMER_NOW(); \ - RTIMER_BUSYWAIT_UNTIL_ABS(cond, t0, max_time); \ - } while(0) +#define RTIMER_BUSYWAIT_UNTIL(cond, max_time) \ + ({ \ + rtimer_clock_t t0 = RTIMER_NOW(); \ + RTIMER_BUSYWAIT_UNTIL_ABS(cond, t0, max_time); \ + }) /** \brief Busy-wait for a fixed duration */ #define RTIMER_BUSYWAIT(duration) RTIMER_BUSYWAIT_UNTIL(0, duration) From c3ed24d531d70a0b18b95d702dc67ceb342548bd Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 12 Oct 2018 14:14:07 +0200 Subject: [PATCH 425/485] Removing native compilation from ARM compile test suite --- tests/01-compile-base/Makefile | 2 +- tests/02-compile-arm-ports-01/Makefile | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/01-compile-base/Makefile b/tests/01-compile-base/Makefile index d9ef0ba58..e51ff523b 100644 --- a/tests/01-compile-base/Makefile +++ b/tests/01-compile-base/Makefile @@ -16,7 +16,7 @@ libs/stack-check/sky \ lwm2m-ipso-objects/native \ lwm2m-ipso-objects/native:MAKE_WITH_DTLS=1 \ lwm2m-ipso-objects/native:DEFINES=LWM2M_Q_MODE_CONF_ENABLED=1 \ -lwm2m-ipso-objects/native:DEFINES=LWM2M_Q_MODE_CONF_ENABLED=1,LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION=1\ +lwm2m-ipso-objects/native:DEFINES=LWM2M_Q_MODE_CONF_ENABLED=1,LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION=1 \ rpl-udp/sky \ rpl-border-router/native \ rpl-border-router/native:MAKE_ROUTING=MAKE_ROUTING_RPL_CLASSIC \ diff --git a/tests/02-compile-arm-ports-01/Makefile b/tests/02-compile-arm-ports-01/Makefile index b3a3abdda..2ec2ce443 100644 --- a/tests/02-compile-arm-ports-01/Makefile +++ b/tests/02-compile-arm-ports-01/Makefile @@ -80,7 +80,6 @@ coap/coap-example-server/cc2538dk \ slip-radio/cc2538dk \ lwm2m-ipso-objects/cc2538dk \ lwm2m-ipso-objects/cc2538dk:DEFINES=LWM2M_Q_MODE_CONF_ENABLED=1 \ -lwm2m-ipso-objects/native:DEFINES=LWM2M_Q_MODE_CONF_ENABLED=1,LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION=1\ multicast/cc2538dk \ dev/gpio-hal/cc2538dk \ dev/leds/cc2538dk \ From 8e990819a81fec50b03aa0ad8db0b54b3e0cbea1 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Tue, 2 Oct 2018 23:07:24 +0100 Subject: [PATCH 426/485] Remove all instances of ti_lib_rom_ macros --- arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c | 10 +----- arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h | 11 +------ arch/cpu/cc26xx-cc13xx/dev/soc-rtc.c | 2 +- arch/cpu/cc26xx-cc13xx/dev/soc-trng.c | 18 +++++------ arch/cpu/cc26xx-cc13xx/dev/spi-arch.c | 31 ++++++------------- .../srf06-cc26xx/launchpad/cc1350/rf-switch.c | 4 +-- arch/platform/srf06-cc26xx/platform.c | 2 +- .../srf06-cc26xx/sensortag/mpu-9250-sensor.c | 4 +-- arch/platform/srf06-cc26xx/srf06/als-sensor.c | 6 ++-- 9 files changed, 30 insertions(+), 58 deletions(-) diff --git a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c index 6516c22cd..285652690 100644 --- a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c +++ b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c @@ -53,11 +53,7 @@ gpio_hal_arch_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg) gpio_hal_pin_cfg_t tmp; /* Clear settings that we are about to change, keep everything else */ -#ifdef ThisLibraryIsFor_CC26x0R2_HaltIfViolated config = ti_lib_ioc_port_configure_get(pin); -#else - config = ti_lib_rom_ioc_port_configure_get(pin); -#endif config &= ~CONFIG_MASK; tmp = cfg & GPIO_HAL_PIN_CFG_EDGE_BOTH; @@ -87,7 +83,7 @@ gpio_hal_arch_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg) config |= IOC_INT_ENABLE; } - ti_lib_rom_ioc_port_configure_set(pin, IOC_PORT_GPIO, config); + ti_lib_ioc_port_configure_set(pin, IOC_PORT_GPIO, config); } /*---------------------------------------------------------------------------*/ gpio_hal_pin_cfg_t @@ -98,11 +94,7 @@ gpio_hal_arch_pin_cfg_get(gpio_hal_pin_t pin) uint32_t config; cfg = 0; -#ifdef ThisLibraryIsFor_CC26x0R2_HaltIfViolated config = ti_lib_ioc_port_configure_get(pin); -#else - config = ti_lib_rom_ioc_port_configure_get(pin); -#endif /* Pull */ tmp = config & IOC_IOPULL_M; diff --git a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h index 42a912674..ae1b04e26 100644 --- a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h +++ b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h @@ -57,15 +57,10 @@ #define gpio_hal_arch_interrupt_enable(p) interrupt_enable(p) -#ifdef ThisLibraryIsFor_CC26x0R2_HaltIfViolated #define gpio_hal_arch_interrupt_disable(p) ti_lib_ioc_int_disable(p) #define gpio_hal_arch_pin_set_input(p) ti_lib_ioc_pin_type_gpio_input(p) #define gpio_hal_arch_pin_set_output(p) ti_lib_ioc_pin_type_gpio_output(p) -#else -#define gpio_hal_arch_interrupt_disable(p) ti_lib_rom_ioc_int_disable(p) -#define gpio_hal_arch_pin_set_input(p) ti_lib_rom_ioc_pin_type_gpio_input(p) -#define gpio_hal_arch_pin_set_output(p) ti_lib_rom_ioc_pin_type_gpio_output(p) -#endif + #define gpio_hal_arch_set_pin(p) ti_lib_gpio_set_dio(p) #define gpio_hal_arch_clear_pin(p) ti_lib_gpio_clear_dio(p) #define gpio_hal_arch_toggle_pin(p) ti_lib_gpio_toggle_dio(p) @@ -80,11 +75,7 @@ static inline void interrupt_enable(gpio_hal_pin_t pin) { ti_lib_gpio_clear_event_dio(pin); -#ifndef ThisLibraryIsFor_CC26x0R2_HaltIfViolated - ti_lib_rom_ioc_int_enable(pin); -#else ti_lib_ioc_int_enable(pin); -#endif } /*---------------------------------------------------------------------------*/ #endif /* GPIO_HAL_ARCH_H_ */ diff --git a/arch/cpu/cc26xx-cc13xx/dev/soc-rtc.c b/arch/cpu/cc26xx-cc13xx/dev/soc-rtc.c index 8de930a9c..2309026b6 100644 --- a/arch/cpu/cc26xx-cc13xx/dev/soc-rtc.c +++ b/arch/cpu/cc26xx-cc13xx/dev/soc-rtc.c @@ -99,7 +99,7 @@ soc_rtc_init(void) ti_lib_aon_rtc_channel_enable(AON_RTC_CH1); ti_lib_aon_rtc_enable(); - ti_lib_rom_int_enable(INT_AON_RTC_COMB); + ti_lib_int_enable(INT_AON_RTC_COMB); /* Re-enable interrupts */ if(!interrupts_disabled) { diff --git a/arch/cpu/cc26xx-cc13xx/dev/soc-trng.c b/arch/cpu/cc26xx-cc13xx/dev/soc-trng.c index 2fea8418d..30a558640 100644 --- a/arch/cpu/cc26xx-cc13xx/dev/soc-trng.c +++ b/arch/cpu/cc26xx-cc13xx/dev/soc-trng.c @@ -71,7 +71,7 @@ static void disable_number_ready_interrupt(void) { ti_lib_trng_int_disable(TRNG_NUMBER_READY); - ti_lib_rom_int_disable(INT_TRNG_IRQ); + ti_lib_int_disable(INT_TRNG_IRQ); } /*---------------------------------------------------------------------------*/ static void @@ -79,14 +79,14 @@ enable_number_ready_interrupt(void) { ti_lib_trng_int_clear(TRNG_NUMBER_READY); ti_lib_trng_int_enable(TRNG_NUMBER_READY); - ti_lib_rom_int_enable(INT_TRNG_IRQ); + ti_lib_int_enable(INT_TRNG_IRQ); } /*---------------------------------------------------------------------------*/ static bool accessible(void) { /* First, check the PD */ - if(ti_lib_rom_prcm_power_domain_status(PRCM_DOMAIN_PERIPH) + if(ti_lib_prcm_power_domain_status(PRCM_DOMAIN_PERIPH) != PRCM_DOMAIN_POWER_ON) { return false; } @@ -104,12 +104,12 @@ static void power_up(void) { /* First, make sure the PERIPH PD is on */ - ti_lib_rom_prcm_power_domain_on(PRCM_DOMAIN_PERIPH); - while((ti_lib_rom_prcm_power_domain_status(PRCM_DOMAIN_PERIPH) + ti_lib_prcm_power_domain_on(PRCM_DOMAIN_PERIPH); + while((ti_lib_prcm_power_domain_status(PRCM_DOMAIN_PERIPH) != PRCM_DOMAIN_POWER_ON)); /* Enable clock in active mode */ - ti_lib_rom_prcm_peripheral_run_enable(PRCM_PERIPH_TRNG); + ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_TRNG); ti_lib_prcm_load_set(); while(!ti_lib_prcm_load_get()); } @@ -136,7 +136,7 @@ static uint64_t read_number(void) { uint64_t ran = (uint64_t)HWREG(TRNG_BASE + TRNG_O_OUT1) << 32; - ran += ti_lib_rom_trng_number_get(TRNG_LOW_WORD); + ran += ti_lib_trng_number_get(TRNG_LOW_WORD); return ran; } @@ -237,7 +237,7 @@ soc_trng_rand_asynchronous(uint32_t samples, soc_trng_callback_t cb) ti_lib_trng_int_clear(TRNG_NUMBER_READY); /* Enable clock in sleep mode and register with LPM */ - ti_lib_rom_prcm_peripheral_sleep_enable(PRCM_PERIPH_TRNG); + ti_lib_prcm_peripheral_sleep_enable(PRCM_PERIPH_TRNG); ti_lib_prcm_load_set(); while(!ti_lib_prcm_load_get()); @@ -271,7 +271,7 @@ PROCESS_THREAD(soc_trng_process, ev, data) } /* Disable clock in sleep mode */ - ti_lib_rom_prcm_peripheral_sleep_disable(PRCM_PERIPH_TRNG); + ti_lib_prcm_peripheral_sleep_disable(PRCM_PERIPH_TRNG); ti_lib_prcm_load_set(); while(!ti_lib_prcm_load_get()); diff --git a/arch/cpu/cc26xx-cc13xx/dev/spi-arch.c b/arch/cpu/cc26xx-cc13xx/dev/spi-arch.c index d42c06af9..1f4a1ca32 100644 --- a/arch/cpu/cc26xx-cc13xx/dev/spi-arch.c +++ b/arch/cpu/cc26xx-cc13xx/dev/spi-arch.c @@ -123,7 +123,7 @@ spi_arch_lock_and_open(const spi_device_t *dev) != PRCM_DOMAIN_POWER_ON)) ; /* Enable clock in active mode */ - ti_lib_rom_prcm_peripheral_run_enable(spi_controller[dev->spi_controller].prcm_periph); + ti_lib_prcm_peripheral_run_enable(spi_controller[dev->spi_controller].prcm_periph); ti_lib_prcm_load_set(); while(!ti_lib_prcm_load_get()) ; @@ -131,17 +131,14 @@ spi_arch_lock_and_open(const spi_device_t *dev) ti_lib_ssi_int_disable(spi_controller[dev->spi_controller].ssi_base, SSI_RXOR | SSI_RXFF | SSI_RXTO | SSI_TXFF); ti_lib_ssi_int_clear(spi_controller[dev->spi_controller].ssi_base, SSI_RXOR | SSI_RXTO); -#ifdef ThisLibraryIsFor_CC26x0R2_HaltIfViolated - ti_lib_ssi_config_set_exp_clk(spi_controller[dev->spi_controller].ssi_base, ti_lib_sys_ctrl_clock_get(), - get_mode(dev), SSI_MODE_MASTER, dev->spi_bit_rate, 8); - ti_lib_ioc_pin_type_ssi_master(spi_controller[dev->spi_controller].ssi_base, dev->pin_spi_miso, - dev->pin_spi_mosi, IOID_UNUSED, dev->pin_spi_sck); -#else - ti_lib_rom_ssi_config_set_exp_clk(spi_controller[dev->spi_controller].ssi_base, ti_lib_sys_ctrl_clock_get(), - get_mode(dev), SSI_MODE_MASTER, dev->spi_bit_rate, 8); - ti_lib_rom_ioc_pin_type_ssi_master(spi_controller[dev->spi_controller].ssi_base, dev->pin_spi_miso, - dev->pin_spi_mosi, IOID_UNUSED, dev->pin_spi_sck); -#endif + ti_lib_ssi_config_set_exp_clk(spi_controller[dev->spi_controller].ssi_base, + ti_lib_sys_ctrl_clock_get(), + get_mode(dev), SSI_MODE_MASTER, + dev->spi_bit_rate, 8); + ti_lib_ioc_pin_type_ssi_master(spi_controller[dev->spi_controller].ssi_base, + dev->pin_spi_miso, + dev->pin_spi_mosi, IOID_UNUSED, + dev->pin_spi_sck); ti_lib_ssi_enable(spi_controller[dev->spi_controller].ssi_base); @@ -159,7 +156,7 @@ spi_arch_close_and_unlock(const spi_device_t *dev) } /* Power down SSI */ - ti_lib_rom_prcm_peripheral_run_disable(spi_controller[dev->spi_controller].prcm_periph); + ti_lib_prcm_peripheral_run_disable(spi_controller[dev->spi_controller].prcm_periph); ti_lib_prcm_load_set(); while(!ti_lib_prcm_load_get()) ; @@ -213,20 +210,12 @@ spi_arch_transfer(const spi_device_t *dev, for(i = 0; i < totlen; i++) { c = i < wlen ? write_buf[i] : 0; ti_lib_ssi_data_put(spi_controller[dev->spi_controller].ssi_base, (uint8_t)c); -#ifdef ThisLibraryIsFor_CC26x0R2_HaltIfViolated ti_lib_ssi_data_get(spi_controller[dev->spi_controller].ssi_base, &c); -#else - ti_lib_rom_ssi_data_get(spi_controller[dev->spi_controller].ssi_base, &c); -#endif if(i < rlen) { inbuf[i] = (uint8_t)c; } } -#ifdef ThisLibraryIsFor_CC26x0R2_HaltIfViolated while(ti_lib_ssi_data_get_non_blocking(spi_controller[dev->spi_controller].ssi_base, &c)) ; -#else - while(ti_lib_rom_ssi_data_get_non_blocking(spi_controller[dev->spi_controller].ssi_base, &c)) ; -#endif return SPI_DEV_STATUS_OK; } /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/srf06-cc26xx/launchpad/cc1350/rf-switch.c b/arch/platform/srf06-cc26xx/launchpad/cc1350/rf-switch.c index 42e648a73..639b246cc 100644 --- a/arch/platform/srf06-cc26xx/launchpad/cc1350/rf-switch.c +++ b/arch/platform/srf06-cc26xx/launchpad/cc1350/rf-switch.c @@ -63,9 +63,9 @@ LPM_MODULE(rf_switch_module, NULL, shutdown_handler, NULL, LPM_DOMAIN_NONE); void rf_switch_init() { - ti_lib_rom_ioc_pin_type_gpio_output(POWER_PIN); + ti_lib_ioc_pin_type_gpio_output(POWER_PIN); ti_lib_gpio_clear_dio(POWER_PIN); - ti_lib_rom_ioc_pin_type_gpio_output(SELECT_PIN); + ti_lib_ioc_pin_type_gpio_output(SELECT_PIN); ti_lib_gpio_clear_dio(SELECT_PIN); lpm_register_module(&rf_switch_module); diff --git a/arch/platform/srf06-cc26xx/platform.c b/arch/platform/srf06-cc26xx/platform.c index 427504ed8..cf72dfae2 100644 --- a/arch/platform/srf06-cc26xx/platform.c +++ b/arch/platform/srf06-cc26xx/platform.c @@ -162,7 +162,7 @@ platform_init_stage_one() ti_lib_pwr_ctrl_io_freeze_disable(); #endif - ti_lib_rom_int_enable(INT_AON_GPIO_EDGE); + ti_lib_int_enable(INT_AON_GPIO_EDGE); ti_lib_int_master_enable(); soc_rtc_init(); diff --git a/arch/platform/srf06-cc26xx/sensortag/mpu-9250-sensor.c b/arch/platform/srf06-cc26xx/sensortag/mpu-9250-sensor.c index a2b3651e5..9e9685cd3 100644 --- a/arch/platform/srf06-cc26xx/sensortag/mpu-9250-sensor.c +++ b/arch/platform/srf06-cc26xx/sensortag/mpu-9250-sensor.c @@ -601,11 +601,11 @@ configure(int type, int enable) { switch(type) { case SENSORS_HW_INIT: - ti_lib_rom_ioc_pin_type_gpio_input(BOARD_IOID_MPU_INT); + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_MPU_INT); ti_lib_ioc_io_port_pull_set(BOARD_IOID_MPU_INT, IOC_IOPULL_DOWN); ti_lib_ioc_io_hyst_set(BOARD_IOID_MPU_INT, IOC_HYST_ENABLE); - ti_lib_rom_ioc_pin_type_gpio_output(BOARD_IOID_MPU_POWER); + ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_MPU_POWER); ti_lib_ioc_io_drv_strength_set(BOARD_IOID_MPU_POWER, IOC_CURRENT_4MA, IOC_STRENGTH_MAX); ti_lib_gpio_clear_dio(BOARD_IOID_MPU_POWER); diff --git a/arch/platform/srf06-cc26xx/srf06/als-sensor.c b/arch/platform/srf06-cc26xx/srf06/als-sensor.c index 3b6fdecb9..74edc06bb 100644 --- a/arch/platform/srf06-cc26xx/srf06/als-sensor.c +++ b/arch/platform/srf06-cc26xx/srf06/als-sensor.c @@ -59,10 +59,10 @@ config(int type, int enable) ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_ALS_PWR); break; case SENSORS_ACTIVE: - ti_lib_rom_ioc_pin_type_gpio_output(BOARD_IOID_ALS_PWR); - ti_lib_rom_ioc_port_configure_set(BOARD_IOID_ALS_OUT, IOC_PORT_GPIO, + ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_ALS_PWR); + ti_lib_ioc_port_configure_set(BOARD_IOID_ALS_OUT, IOC_PORT_GPIO, IOC_STD_OUTPUT); - ti_lib_rom_ioc_pin_type_gpio_input(BOARD_IOID_ALS_OUT); + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_ALS_OUT); if(enable) { ti_lib_gpio_set_dio(BOARD_IOID_ALS_PWR); From 23ab33cc390e0400d53b2fbfd63eda1b883a9f45 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Tue, 2 Oct 2018 23:08:26 +0100 Subject: [PATCH 427/485] Remove ti-lib-rom.h --- arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c | 1 - arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h | 1 - arch/cpu/cc26xx-cc13xx/ti-lib-rom.h | 195 --------------------- arch/cpu/cc26xx-cc13xx/ti-lib.h | 3 - 4 files changed, 200 deletions(-) delete mode 100644 arch/cpu/cc26xx-cc13xx/ti-lib-rom.h diff --git a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c index 285652690..4fd4f7688 100644 --- a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c +++ b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c @@ -39,7 +39,6 @@ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "ti-lib.h" -#include "ti-lib-rom.h" #include "dev/gpio-hal.h" #include diff --git a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h index ae1b04e26..3997c1062 100644 --- a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h +++ b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h @@ -49,7 +49,6 @@ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "ti-lib.h" -#include "ti-lib-rom.h" #include /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc26xx-cc13xx/ti-lib-rom.h b/arch/cpu/cc26xx-cc13xx/ti-lib-rom.h deleted file mode 100644 index e9fe50111..000000000 --- a/arch/cpu/cc26xx-cc13xx/ti-lib-rom.h +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (c) 2016, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/*---------------------------------------------------------------------------*/ -/** - * \addtogroup cc26xx-ti-lib - * @{ - * - * \file - * Header file with CC13xxware/CC26xxware ROM API. - */ -/*---------------------------------------------------------------------------*/ -#ifndef TI_LIB_ROM_H_ -#define TI_LIB_ROM_H_ -/*---------------------------------------------------------------------------*/ -/* rom.h */ -#include "driverlib/rom.h" - -/* AON API */ -#define ti_lib_rom_aon_event_mcu_wake_up_set ROM_AONEventMcuWakeUpSet -#define ti_lib_rom_aon_event_mcu_wake_up_get ROM_AONEventMcuWakeUpGet -#define ti_lib_rom_aon_event_aux_wake_up_set ROM_AONEventAuxWakeUpSet -#define ti_lib_rom_aon_event_aux_wake_up_get ROM_AONEventAuxWakeUpGet -#define ti_lib_rom_aon_event_mcu_set ROM_AONEventMcuSet -#define ti_lib_rom_aon_event_mcu_get ROM_AONEventMcuGet - -/* AON_WUC API */ -#define ti_lib_rom_aon_wuc_aux_reset ROM_AONWUCAuxReset -#define ti_lib_rom_aon_wuc_recharge_ctrl_config_set ROM_AONWUCRechargeCtrlConfigSet -#define ti_lib_rom_aon_wuc_osc_config ROM_AONWUCOscConfig - -/* AUX_TDC API */ -#define ti_lib_rom_aux_tdc_config_set ROM_AUXTDCConfigSet -#define ti_lib_rom_aux_tdc_measurement_done ROM_AUXTDCMeasurementDone - -/* AUX_WUC API */ -#define ti_lib_rom_aux_wuc_clock_enable ROM_AUXWUCClockEnable -#define ti_lib_rom_aux_wuc_clock_disable ROM_AUXWUCClockDisable -#define ti_lib_rom_aux_wuc_clock_status ROM_AUXWUCClockStatus -#define ti_lib_rom_aux_wuc_power_ctrl ROM_AUXWUCPowerCtrl - -/* FLASH API */ -#define ti_lib_rom_flash_power_mode_get ROM_FlashPowerModeGet -#define ti_lib_rom_flash_protection_set ROM_FlashProtectionSet -#define ti_lib_rom_flash_protection_get ROM_FlashProtectionGet -#define ti_lib_rom_flash_protection_save ROM_FlashProtectionSave -#define ti_lib_rom_flash_efuse_read_row ROM_FlashEfuseReadRow -#define ti_lib_rom_flash_disable_sectors_for_write ROM_FlashDisableSectorsForWrite - -/* I2C API */ -#define ti_lib_rom_i2c_master_init_exp_clk ROM_I2CMasterInitExpClk -#define ti_lib_rom_i2c_master_err ROM_I2CMasterErr - -/* INTERRUPT API */ -#define ti_lib_rom_int_priority_grouping_set ROM_IntPriorityGroupingSet -#define ti_lib_rom_int_priority_grouping_get ROM_IntPriorityGroupingGet -#define ti_lib_rom_int_priority_set ROM_IntPrioritySet -#define ti_lib_rom_int_priority_get ROM_IntPriorityGet -#define ti_lib_rom_int_enable ROM_IntEnable -#define ti_lib_rom_int_disable ROM_IntDisable -#define ti_lib_rom_int_pend_set ROM_IntPendSet -#define ti_lib_rom_int_pend_get ROM_IntPendGet -#define ti_lib_rom_int_pend_clear ROM_IntPendClear - -/* IOC API */ -#define ti_lib_rom_ioc_port_configure_set ROM_IOCPortConfigureSet -#if !defined(ThisLibraryIsFor_CC26x0R2_HaltIfViolated) -#define ti_lib_rom_ioc_port_configure_get ROM_IOCPortConfigureGet -#define ti_lib_rom_ioc_io_shutdown_set ROM_IOCIOShutdownSet -#define ti_lib_rom_ioc_io_mode_set ROM_IOCIOModeSet -#define ti_lib_rom_ioc_io_int_set ROM_IOCIOIntSet -#define ti_lib_rom_ioc_io_port_pull_set ROM_IOCIOPortPullSet -#define ti_lib_rom_ioc_io_hyst_set ROM_IOCIOHystSet -#define ti_lib_rom_ioc_io_input_set ROM_IOCIOInputSet -#define ti_lib_rom_ioc_io_slew_ctrl_set ROM_IOCIOSlewCtrlSet -#define ti_lib_rom_ioc_io_drv_strength_set ROM_IOCIODrvStrengthSet -#define ti_lib_rom_ioc_io_port_id_set ROM_IOCIOPortIdSet -#define ti_lib_rom_ioc_int_enable ROM_IOCIntEnable -#define ti_lib_rom_ioc_int_disable ROM_IOCIntDisable -#define ti_lib_rom_ioc_pin_type_gpio_input ROM_IOCPinTypeGpioInput -#define ti_lib_rom_ioc_pin_type_gpio_output ROM_IOCPinTypeGpioOutput -#define ti_lib_rom_ioc_pin_type_uart ROM_IOCPinTypeUart -#define ti_lib_rom_ioc_pin_type_ssi_master ROM_IOCPinTypeSsiMaster -#define ti_lib_rom_ioc_pin_type_ssi_slave ROM_IOCPinTypeSsiSlave -#define ti_lib_rom_ioc_pin_type_i2c ROM_IOCPinTypeI2c -#define ti_lib_rom_ioc_pin_type_aux ROM_IOCPinTypeAux -#endif - -/* PRCM API */ -#define ti_lib_rom_prcm_inf_clock_configure_set ROM_PRCMInfClockConfigureSet -#define ti_lib_rom_prcm_inf_clock_configure_get ROM_PRCMInfClockConfigureGet -#define ti_lib_rom_prcm_audio_clock_config_set ROM_PRCMAudioClockConfigSet -#define ti_lib_rom_prcm_power_domain_on ROM_PRCMPowerDomainOn -#define ti_lib_rom_prcm_power_domain_off ROM_PRCMPowerDomainOff -#define ti_lib_rom_prcm_peripheral_run_enable ROM_PRCMPeripheralRunEnable -#define ti_lib_rom_prcm_peripheral_run_disable ROM_PRCMPeripheralRunDisable -#define ti_lib_rom_prcm_peripheral_sleep_enable ROM_PRCMPeripheralSleepEnable -#define ti_lib_rom_prcm_peripheral_sleep_disable ROM_PRCMPeripheralSleepDisable -#define ti_lib_rom_prcm_peripheral_deep_sleep_enable ROM_PRCMPeripheralDeepSleepEnable -#define ti_lib_rom_prcm_peripheral_deep_sleep_disable ROM_PRCMPeripheralDeepSleepDisable -#define ti_lib_rom_prcm_power_domain_status ROM_PRCMPowerDomainStatus -#define ti_lib_rom_prcm_deep_sleep ROM_PRCMDeepSleep - -/* SMPH API */ -#define ti_lib_rom_smph_acquire ROM_SMPHAcquire - -/* SSI API */ -#define ti_lib_rom_ssi_config_set_exp_clk ROM_SSIConfigSetExpClk -#define ti_lib_rom_ssi_data_put ROM_SSIDataPut -#define ti_lib_rom_ssi_data_put_non_blocking ROM_SSIDataPutNonBlocking -#define ti_lib_rom_ssi_data_get ROM_SSIDataGet -#define ti_lib_rom_ssi_data_get_non_blocking ROM_SSIDataGetNonBlocking - -/* TIMER API */ -#define ti_lib_rom_timer_configure ROM_TimerConfigure -#define ti_lib_rom_timer_level_control ROM_TimerLevelControl -#define ti_lib_rom_timer_stall_control ROM_TimerStallControl -#define ti_lib_rom_timer_wait_on_trigger_control ROM_TimerWaitOnTriggerControl - -/* TRNG API */ -#define ti_lib_rom_trng_number_get ROM_TRNGNumberGet - -/* UART API */ -#define ti_lib_rom_uart_fifo_level_get ROM_UARTFIFOLevelGet -#define ti_lib_rom_uart_config_set_exp_clk ROM_UARTConfigSetExpClk -#define ti_lib_rom_uart_config_get_exp_clk ROM_UARTConfigGetExpClk -#define ti_lib_rom_uart_disable ROM_UARTDisable -#define ti_lib_rom_uart_char_get_non_blocking ROM_UARTCharGetNonBlocking -#define ti_lib_rom_uart_char_get ROM_UARTCharGet -#define ti_lib_rom_uart_char_put_non_blocking ROM_UARTCharPutNonBlocking -#define ti_lib_rom_uart_char_put ROM_UARTCharPut - -/* UDMA API */ -#define ti_lib_rom_udma_channel_attribute_enable ROM_uDMAChannelAttributeEnable -#define ti_lib_rom_udma_channel_attribute_disable ROM_uDMAChannelAttributeDisable -#define ti_lib_rom_udma_channel_attribute_get ROM_uDMAChannelAttributeGet -#define ti_lib_rom_udma_channel_control_set ROM_uDMAChannelControlSet -#define ti_lib_rom_udma_channel_transfer_set ROM_uDMAChannelTransferSet -#define ti_lib_rom_udma_channel_scatter_gather_set ROM_uDMAChannelScatterGatherSet -#define ti_lib_rom_udma_channel_size_get ROM_uDMAChannelSizeGet -#define ti_lib_rom_udma_channel_mode_get ROM_uDMAChannelModeGet - -/* VIMS API */ -#define ti_lib_rom_vims_configure ROM_VIMSConfigure -#define ti_lib_rom_vims_mode_set ROM_VIMSModeSet - -/* HAPI */ -#define ti_lib_hapi_crc32(a, b, c) HapiCrc32(a, b, c) -#define ti_lib_hapi_get_flash_size() HapiGetFlashSize() -#define ti_lib_hapi_get_chip_id() HapiGetChipId() -#define ti_lib_hapi_sector_erase(a) HapiSectorErase(a) -#define ti_lib_hapi_program_flash(a, b, c) HapiProgramFlash(a, b, c) -#define ti_lib_hapi_reset_device() HapiResetDevice() -#define ti_lib_hapi_fletcher32(a, b, c) HapiFletcher32(a, b, c) -#define ti_lib_hapi_min_value(a, b) HapiMinValue(a,b) -#define ti_lib_hapi_max_value(a, b) HapiMaxValue(a,b) -#define ti_lib_hapi_mean_value(a, b) HapiMeanValue(a,b) -#define ti_lib_hapi_stand_deviation_value(a, b) HapiStandDeviationValue(a,b) -#define ti_lib_hapi_hf_source_safe_switch() HapiHFSourceSafeSwitch() -#define ti_lib_hapi_select_comp_a_input(a) HapiSelectCompAInput(a) -#define ti_lib_hapi_select_comp_a_ref(a) HapiSelectCompARef(a) -#define ti_lib_hapi_select_adc_comp_b_input(a) HapiSelectADCCompBInput(a) -#define ti_lib_hapi_select_comp_b_ref(a) HapiSelectCompBRef(a) -/*---------------------------------------------------------------------------*/ -#endif /* TI_LIB_ROM_H_ */ -/*---------------------------------------------------------------------------*/ -/** - * @} - */ diff --git a/arch/cpu/cc26xx-cc13xx/ti-lib.h b/arch/cpu/cc26xx-cc13xx/ti-lib.h index 6e6d78afb..6afcfeb84 100644 --- a/arch/cpu/cc26xx-cc13xx/ti-lib.h +++ b/arch/cpu/cc26xx-cc13xx/ti-lib.h @@ -52,9 +52,6 @@ #ifndef TI_LIB_H_ #define TI_LIB_H_ /*---------------------------------------------------------------------------*/ -/* Include ROM API */ -#include "ti-lib-rom.h" -/*---------------------------------------------------------------------------*/ /* aon_batmon.h */ #include "driverlib/aon_batmon.h" From 3ba8afea79ab49ceeb2f3f25ac67848f78d5790f Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Tue, 2 Oct 2018 23:10:06 +0100 Subject: [PATCH 428/485] Harmonize usage across XXwares and CC2640R2-SDK --- arch/cpu/cc26xx-cc13xx/lpm.c | 11 +++-------- arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c | 4 ++-- arch/cpu/cc26xx-cc13xx/ti-lib.h | 21 +++++++++++++-------- arch/platform/srf06-cc26xx/platform.c | 6 +++--- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/arch/cpu/cc26xx-cc13xx/lpm.c b/arch/cpu/cc26xx-cc13xx/lpm.c index 4c8e0256b..2337fb24f 100644 --- a/arch/cpu/cc26xx-cc13xx/lpm.c +++ b/arch/cpu/cc26xx-cc13xx/lpm.c @@ -162,10 +162,10 @@ lpm_shutdown(uint32_t wakeup_pin, uint32_t io_pull, uint32_t wake_on) ti_lib_aon_wuc_mcu_power_off_config(MCU_VIRT_PWOFF_DISABLE); /* Latch the IOs in the padring and enable I/O pad sleep mode */ -#if !defined(ThisLibraryIsFor_CC26x0R2_HaltIfViolated) - ti_lib_pwr_ctrl_io_freeze_enable(); + ti_lib_aon_ioc_freeze_enable(); + HWREG(AON_SYSCTL_BASE + AON_SYSCTL_O_SLEEPCTL) = 0; + ti_lib_sys_ctrl_aon_sync(); -#endif /* Turn off VIMS cache, CRAM and TRAM - possibly not required */ ti_lib_prcm_cache_retention_disable(); ti_lib_vims_mode_set(VIMS_BASE, VIMS_MODE_OFF); @@ -193,12 +193,7 @@ wake_up(void) ti_lib_sys_ctrl_aon_sync(); /* Adjust recharge settings */ -#ifdef ThisLibraryIsFor_CC26x0R2_HaltIfViolated - // May need to change to XOSC_IN_LOW_POWER_MODE - ti_lib_sys_ctrl_adjust_recharge_after_power_down(XOSC_IN_HIGH_POWER_MODE); -#else ti_lib_sys_ctrl_adjust_recharge_after_power_down(); -#endif /* * Release the request to the uLDO diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c b/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c index 185842b42..faa8f808b 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c +++ b/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c @@ -399,8 +399,8 @@ rf_core_set_modesel() } else if(chip_type == CHIP_TYPE_CC1350) { HWREG(PRCM_BASE + PRCM_O_RFCMODESEL) = PRCM_RFCMODESEL_CURR_MODE5; rv = RF_CORE_CMD_OK; -#ifdef ThisLibraryIsFor_CC26x0R2_HaltIfViolated - } else if (chip_type == CHIP_TYPE_CC2640R2) { +#if CPU_FAMILY_CC26X0R2 + } else if(chip_type == CHIP_TYPE_CC2640R2) { HWREG(PRCM_BASE + PRCM_O_RFCMODESEL) = PRCM_RFCMODESEL_CURR_MODE1; rv = RF_CORE_CMD_OK; #endif diff --git a/arch/cpu/cc26xx-cc13xx/ti-lib.h b/arch/cpu/cc26xx-cc13xx/ti-lib.h index 6afcfeb84..6bba7c849 100644 --- a/arch/cpu/cc26xx-cc13xx/ti-lib.h +++ b/arch/cpu/cc26xx-cc13xx/ti-lib.h @@ -197,14 +197,16 @@ #define ti_lib_chipinfo_get_device_id_hw_rev_code(...) ChipInfo_GetDeviceIdHwRevCode(__VA_ARGS__) #define ti_lib_chipinfo_get_chip_type(...) ChipInfo_GetChipType(__VA_ARGS__) #define ti_lib_chipinfo_get_chip_family(...) ChipInfo_GetChipFamily(__VA_ARGS__) -#ifdef ThisLibraryIsFor_CC26x0R2_HaltIfViolated + +#if CPU_FAMILY_CC26X0R2 #define ti_lib_chipinfo_chip_family_is_cc26xx(...) ChipInfo_ChipFamilyIs_CC26x0(__VA_ARGS__) #define ti_lib_chipinfo_chip_family_is_cc13xx(...) ChipInfo_ChipFamilyIs_CC13x0(__VA_ARGS__) -#define ti_lib_chipinfo_chip_family_is_cc26x0r2(...) ChipInfo_ChipFamilyIs_CC26x0R2(__VA_ARGS__) +#define ti_lib_chipinfo_chip_family_is_cc26x0r2(...) ChipInfo_ChipFamilyIs_CC26x0R2(__VA_ARGS__) #else #define ti_lib_chipinfo_chip_family_is_cc26xx(...) ChipInfo_ChipFamilyIsCC26xx(__VA_ARGS__) #define ti_lib_chipinfo_chip_family_is_cc13xx(...) ChipInfo_ChipFamilyIsCC13xx(__VA_ARGS__) -#endif +#endif /* CPU_FAMILY_CC26X0R2 */ + #define ti_lib_chipinfo_get_hw_revision(...) ChipInfo_GetHwRevision(__VA_ARGS__) #define ti_lib_chipinfo_hw_revision_is_1_0(...) ChipInfo_HwRevisionIs_1_0(__VA_ARGS__) #define ti_lib_chipinfo_hw_revision_is_gteq_2_0(...) ChipInfo_HwRevisionIs_GTEQ_2_0(__VA_ARGS__) @@ -391,10 +393,6 @@ #define ti_lib_pwr_ctrl_source_get(...) PowerCtrlSourceGet(__VA_ARGS__) #define ti_lib_pwr_ctrl_reset_source_get(...) PowerCtrlResetSourceGet(__VA_ARGS__) #define ti_lib_pwr_ctrl_reset_source_clear(...) PowerCtrlResetSourceClear(__VA_ARGS__) -#if !defined(ThisLibraryIsFor_CC26x0R2_HaltIfViolated) -#define ti_lib_pwr_ctrl_io_freeze_enable(...) PowerCtrlIOFreezeEnable(__VA_ARGS__) -#define ti_lib_pwr_ctrl_io_freeze_disable(...) PowerCtrlIOFreezeDisable(__VA_ARGS__) -#endif /*---------------------------------------------------------------------------*/ /* rfc.h */ #include "driverlib/rfc.h" @@ -413,7 +411,14 @@ #define ti_lib_sys_ctrl_aon_sync(...) SysCtrlAonSync(__VA_ARGS__) #define ti_lib_sys_ctrl_aon_update(...) SysCtrlAonUpdate(__VA_ARGS__) #define ti_lib_sys_ctrl_set_recharge_before_power_down(...) SysCtrlSetRechargeBeforePowerDown(__VA_ARGS__) -#define ti_lib_sys_ctrl_adjust_recharge_after_power_down(...) SysCtrlAdjustRechargeAfterPowerDown(__VA_ARGS__) + +#if CPU_FAMILY_CC26X0R2 +/* May need to change to XOSC_IN_LOW_POWER_MODE */ +#define ti_lib_sys_ctrl_adjust_recharge_after_power_down() SysCtrlAdjustRechargeAfterPowerDown(XOSC_IN_HIGH_POWER_MODE) +#else +#define ti_lib_sys_ctrl_adjust_recharge_after_power_down() SysCtrlAdjustRechargeAfterPowerDown() +#endif /* CPU_FAMILY_CC26X0R2 */ + #define ti_lib_sys_ctrl_dcdc_voltage_conditional_control(...) SysCtrl_DCDC_VoltageConditionalControl(__VA_ARGS__) #define ti_lib_sys_ctrl_reset_source_get(...) SysCtrlResetSourceGet(__VA_ARGS__) #define ti_lib_sys_ctrl_system_reset(...) SysCtrlSystemReset(__VA_ARGS__) diff --git a/arch/platform/srf06-cc26xx/platform.c b/arch/platform/srf06-cc26xx/platform.c index cf72dfae2..d160c13e1 100644 --- a/arch/platform/srf06-cc26xx/platform.c +++ b/arch/platform/srf06-cc26xx/platform.c @@ -158,10 +158,10 @@ platform_init_stage_one() * latches in the first place. Before doing these things though, we should * allow software to first regain control of pins */ -#if !defined(ThisLibraryIsFor_CC26x0R2_HaltIfViolated) - ti_lib_pwr_ctrl_io_freeze_disable(); + ti_lib_aon_ioc_freeze_disable(); + HWREG(AON_SYSCTL_BASE + AON_SYSCTL_O_SLEEPCTL) = 1; + ti_lib_sys_ctrl_aon_sync(); -#endif ti_lib_int_enable(INT_AON_GPIO_EDGE); ti_lib_int_master_enable(); From 4a0c9d88944e6525a8556c5beadda01149fd03c5 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Tue, 2 Oct 2018 23:14:26 +0100 Subject: [PATCH 429/485] Change define to reflect current chip family name --- arch/cpu/cc26xx-cc13xx/Makefile.cc13xx | 2 +- arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h | 4 ++-- .../cc26xx/cc26xx-web-demo/cc26xx-web-demo.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/cpu/cc26xx-cc13xx/Makefile.cc13xx b/arch/cpu/cc26xx-cc13xx/Makefile.cc13xx index 093aa1f02..ac050efe8 100644 --- a/arch/cpu/cc26xx-cc13xx/Makefile.cc13xx +++ b/arch/cpu/cc26xx-cc13xx/Makefile.cc13xx @@ -2,6 +2,6 @@ TI_XXWARE_PATH = lib/cc13xxware CONTIKI_CPU_SOURCEFILES += smartrf-settings.c prop-mode.c prop-mode-tx-power.c -CFLAGS += -DCPU_FAMILY_CC13XX=1 +CFLAGS += -DCPU_FAMILY_CC13X0=1 -DCPU_FAMILY_CC13XX=1 include $(CONTIKI_CPU)/Makefile.cc26xx-cc13xx diff --git a/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h b/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h index e7d9dacd7..7400c5ad9 100644 --- a/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h +++ b/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h @@ -64,11 +64,11 @@ * project has specified otherwise. Depending on the final mode, determine a * default channel (again, if unspecified) and configure RDC params */ -#if CPU_FAMILY_CC13XX +#if CPU_FAMILY_CC13X0 #ifndef CC13XX_CONF_PROP_MODE #define CC13XX_CONF_PROP_MODE 1 #endif /* CC13XX_CONF_PROP_MODE */ -#endif /* CPU_FAMILY_CC13XX */ +#endif /* CPU_FAMILY_CC13X0 */ #if CC13XX_CONF_PROP_MODE #ifndef NETSTACK_CONF_RADIO diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/cc26xx-web-demo.h b/examples/platform-specific/cc26xx/cc26xx-web-demo/cc26xx-web-demo.h index 0761725c7..f59e41bc7 100644 --- a/examples/platform-specific/cc26xx/cc26xx-web-demo/cc26xx-web-demo.h +++ b/examples/platform-specific/cc26xx/cc26xx-web-demo/cc26xx-web-demo.h @@ -119,7 +119,7 @@ /*---------------------------------------------------------------------------*/ /* Default configuration values */ #define CC26XX_WEB_DEMO_DEFAULT_ORG_ID "quickstart" -#if CPU_FAMILY_CC13XX +#if CPU_FAMILY_CC13X0 #define CC26XX_WEB_DEMO_DEFAULT_TYPE_ID "cc13xx" #else #define CC26XX_WEB_DEMO_DEFAULT_TYPE_ID "cc26xx" From bf0e80aae33119c80641a243be52e8a1cc43b934 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Tue, 2 Oct 2018 23:14:53 +0100 Subject: [PATCH 430/485] Always provide -DCPU_FAMILY_xxx --- arch/cpu/cc26xx-cc13xx/Makefile.cc26x0r2f | 2 ++ arch/cpu/cc26xx-cc13xx/Makefile.cc26xx | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/cpu/cc26xx-cc13xx/Makefile.cc26x0r2f b/arch/cpu/cc26xx-cc13xx/Makefile.cc26x0r2f index decece481..56d041516 100644 --- a/arch/cpu/cc26xx-cc13xx/Makefile.cc26x0r2f +++ b/arch/cpu/cc26xx-cc13xx/Makefile.cc26x0r2f @@ -1,3 +1,5 @@ TI_XXWARE_PATH = lib/cc2640r2-sdk +CFLAGS += -DCPU_FAMILY_CC26X0R2=1 -DCPU_FAMILY_CC26XXR2=1 + include $(CONTIKI_CPU)/Makefile.cc26xx-cc13xx diff --git a/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx b/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx index 4bc2cdcad..34a147f7b 100644 --- a/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx +++ b/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx @@ -1,3 +1,5 @@ TI_XXWARE_PATH = lib/cc26xxware +CFLAGS += -DCPU_FAMILY_CC26X0=1 -DCPU_FAMILY_CC26XX=1 + include $(CONTIKI_CPU)/Makefile.cc26xx-cc13xx From 8ea3e9fb774861210334c9928b9bf6646b88a839 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Tue, 2 Oct 2018 23:35:22 +0100 Subject: [PATCH 431/485] Improve code style --- arch/platform/srf06-cc26xx/srf06/als-sensor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/platform/srf06-cc26xx/srf06/als-sensor.c b/arch/platform/srf06-cc26xx/srf06/als-sensor.c index 74edc06bb..42e714065 100644 --- a/arch/platform/srf06-cc26xx/srf06/als-sensor.c +++ b/arch/platform/srf06-cc26xx/srf06/als-sensor.c @@ -61,7 +61,7 @@ config(int type, int enable) case SENSORS_ACTIVE: ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_ALS_PWR); ti_lib_ioc_port_configure_set(BOARD_IOID_ALS_OUT, IOC_PORT_GPIO, - IOC_STD_OUTPUT); + IOC_STD_OUTPUT); ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_ALS_OUT); if(enable) { From 163d1241b3bdb5875c9235c0a539b7121fb60177 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 25 May 2018 07:03:22 -0700 Subject: [PATCH 432/485] timer_reset: do not do anything if the timer has not expired --- os/sys/timer.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/os/sys/timer.c b/os/sys/timer.c index 1eeae64de..b99aa4127 100644 --- a/os/sys/timer.c +++ b/os/sys/timer.c @@ -74,9 +74,8 @@ timer_set(struct timer *t, clock_time_t interval) * given to the timer_set() function. The start point of the interval * is the exact time that the timer last expired. Therefore, this * function will cause the timer to be stable over time, unlike the - * timer_restart() function. - * - * \note Must not be executed before timer expired + * timer_restart() function. If this is executed before the + * timer expired, this function has no effect. * * \param t A pointer to the timer. * \sa timer_restart() @@ -84,7 +83,9 @@ timer_set(struct timer *t, clock_time_t interval) void timer_reset(struct timer *t) { - t->start += t->interval; + if(timer_expired(t)) { + t->start += t->interval; + } } /*---------------------------------------------------------------------------*/ /** From 8472cf8bbe4d57d18bce7522070aa1cf9be7fabd Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 13 Oct 2018 10:17:30 +0200 Subject: [PATCH 433/485] stimer_reset: do not do anything if the timer has not expired --- os/sys/stimer.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/os/sys/stimer.c b/os/sys/stimer.c index 1301dc41e..007587e83 100644 --- a/os/sys/stimer.c +++ b/os/sys/stimer.c @@ -77,7 +77,8 @@ stimer_set(struct stimer *t, unsigned long interval) * given to the stimer_set() function. The start point of the interval * is the exact time that the timer last expired. Therefore, this * function will cause the timer to be stable over time, unlike the - * stimer_restart() function. + * stimer_restart() function. If this is executed before the + * timer expired, this function has no effect. * * \param t A pointer to the timer. * @@ -86,7 +87,9 @@ stimer_set(struct stimer *t, unsigned long interval) void stimer_reset(struct stimer *t) { - t->start += t->interval; + if(stimer_expired(t)) { + t->start += t->interval; + } } /*---------------------------------------------------------------------------*/ /** From 2a66edfd6b3a991744b5558b1c3e3d19e3f56023 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 13 Oct 2018 10:19:18 +0200 Subject: [PATCH 434/485] Doxygen clarification to etimer_reset and ctimer_reset --- os/sys/ctimer.h | 3 ++- os/sys/etimer.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/os/sys/ctimer.h b/os/sys/ctimer.h index 2d391a5e5..e7e463ac4 100644 --- a/os/sys/ctimer.h +++ b/os/sys/ctimer.h @@ -76,7 +76,8 @@ struct ctimer { * is the exact time that the callback timer last * expired. Therefore, this function will cause the timer * to be stable over time, unlike the ctimer_restart() - * function. + * function. If this is executed before the timer expired, + * this function has no effect. * * \sa ctimer_restart() */ diff --git a/os/sys/etimer.h b/os/sys/etimer.h index 02ad5df11..2922b9aa2 100644 --- a/os/sys/etimer.h +++ b/os/sys/etimer.h @@ -107,7 +107,8 @@ void etimer_set(struct etimer *et, clock_time_t interval); * is the exact time that the event timer last * expired. Therefore, this function will cause the timer * to be stable over time, unlike the etimer_restart() - * function. + * function. If this is executed before the timer expired, + * this function has no effect. * * \sa etimer_restart() */ From 87efd3fb45a34d1dbd8428c5ef90da80f641d945 Mon Sep 17 00:00:00 2001 From: Atis Elsts Date: Sun, 9 Sep 2018 20:34:17 +0100 Subject: [PATCH 435/485] TI lib: add ti_lib_rfc_hw_int_enable/disable/clear functions --- arch/cpu/cc26xx-cc13xx/ti-lib.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/cpu/cc26xx-cc13xx/ti-lib.h b/arch/cpu/cc26xx-cc13xx/ti-lib.h index 6bba7c849..d6c7363ee 100644 --- a/arch/cpu/cc26xx-cc13xx/ti-lib.h +++ b/arch/cpu/cc26xx-cc13xx/ti-lib.h @@ -399,6 +399,9 @@ #define ti_lib_rfc_rtrim(...) RFCRTrim(__VA_ARGS__) #define ti_lib_rfc_adi3vco_ldo_voltage_mode(...) RFCAdi3VcoLdoVoltageMode(__VA_ARGS__) +#define ti_lib_rfc_hw_int_enable(...) RFCHwIntEnable(__VA_ARGS__) +#define ti_lib_rfc_hw_int_disable(...) RFCHwIntDisable(__VA_ARGS__) +#define ti_lib_rfc_hw_int_clear(...) RFCHwIntClear(__VA_ARGS__) /*---------------------------------------------------------------------------*/ /* sys_ctrl.h */ #include "driverlib/sys_ctrl.h" From cb65f31d48fe5c13b85ced660f3029c382cb23a1 Mon Sep 17 00:00:00 2001 From: Atis Elsts Date: Sat, 15 Sep 2018 12:16:05 +0100 Subject: [PATCH 436/485] Remove BOARDS_EXCLUDE for TSCH examples: now they can be built for CC13xx boards --- examples/6tisch/6p-packet/Makefile | 1 - examples/6tisch/etsi-plugtest-2017/Makefile | 2 +- examples/6tisch/simple-node/Makefile | 1 - examples/6tisch/sixtop/Makefile | 1 - 4 files changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/6tisch/6p-packet/Makefile b/examples/6tisch/6p-packet/Makefile index ac92805ae..3ba74d3b9 100644 --- a/examples/6tisch/6p-packet/Makefile +++ b/examples/6tisch/6p-packet/Makefile @@ -2,7 +2,6 @@ CONTIKI_PROJECT = sixp-node PROJECT_SOURCEFILES += test-sf.c PLATFORMS_EXCLUDE = sky nrf52dk native simplelink -BOARDS_EXCLUDE = srf06/cc13xx launchpad/cc1310 launchpad/cc1350 sensortag/cc2650 sensortag/cc1350 CONTIKI = ../../../ diff --git a/examples/6tisch/etsi-plugtest-2017/Makefile b/examples/6tisch/etsi-plugtest-2017/Makefile index b5aeb66f5..6dc463078 100644 --- a/examples/6tisch/etsi-plugtest-2017/Makefile +++ b/examples/6tisch/etsi-plugtest-2017/Makefile @@ -2,7 +2,7 @@ CONTIKI_PROJECT = node all: $(CONTIKI_PROJECT) PLATFORMS_EXCLUDE = sky nrf52dk native simplelink -BOARDS_EXCLUDE = srf06/cc13xx launchpad/cc1310 launchpad/cc1350 sensortag/cc2650 sensortag/cc1350 +BOARDS_EXCLUDE = sensortag/cc2650 sensortag/cc1350 MAKE_WITH_SECURITY ?= 0 # force Security from command line ifeq ($(MAKE_WITH_SECURITY),1) diff --git a/examples/6tisch/simple-node/Makefile b/examples/6tisch/simple-node/Makefile index c2e976b4e..06a83ebdd 100644 --- a/examples/6tisch/simple-node/Makefile +++ b/examples/6tisch/simple-node/Makefile @@ -2,7 +2,6 @@ CONTIKI_PROJECT = node all: $(CONTIKI_PROJECT) PLATFORMS_EXCLUDE = sky nrf52dk native simplelink -BOARDS_EXCLUDE = srf06/cc13xx launchpad/cc1310 launchpad/cc1350 sensortag/cc2650 sensortag/cc1350 CONTIKI=../../.. diff --git a/examples/6tisch/sixtop/Makefile b/examples/6tisch/sixtop/Makefile index 2469cd445..5c35696e4 100644 --- a/examples/6tisch/sixtop/Makefile +++ b/examples/6tisch/sixtop/Makefile @@ -2,7 +2,6 @@ CONTIKI_PROJECT = node-sixtop all: $(CONTIKI_PROJECT) PLATFORMS_EXCLUDE = sky nrf52dk native simplelink -BOARDS_EXCLUDE = srf06/cc13xx launchpad/cc1310 launchpad/cc1350 sensortag/cc2650 sensortag/cc1350 PROJECT_SOURCEFILES += sf-simple.c CONTIKI=../../.. From 5d041474066155a896de520a273daedc86d1c21b Mon Sep 17 00:00:00 2001 From: Atis Elsts Date: Sun, 9 Sep 2018 20:32:33 +0100 Subject: [PATCH 437/485] CC26xx/CC13xx: Add support for TSCH API for the prop-mode.c radio driver, and unify the radio timer handling between the IEEE and prop modes --- arch/cpu/cc26xx-cc13xx/Makefile.cc13xx | 2 +- arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-def.h | 42 +- .../rf-core/ble-hal/ble-hal-cc26xx.c | 2 +- .../rf-core/cc13xx-50kbps-tsch.c | 73 ++++ .../rf-core/cc13xx-50kbps-tsch.h | 41 ++ arch/cpu/cc26xx-cc13xx/rf-core/ieee-mode.c | 334 ++++----------- arch/cpu/cc26xx-cc13xx/rf-core/prop-mode.c | 386 +++++++++++++----- arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c | 164 +++++++- arch/cpu/cc26xx-cc13xx/rf-core/rf-core.h | 91 ++++- os/net/mac/tsch/tsch-const.h | 4 +- 10 files changed, 757 insertions(+), 382 deletions(-) create mode 100644 arch/cpu/cc26xx-cc13xx/rf-core/cc13xx-50kbps-tsch.c create mode 100644 arch/cpu/cc26xx-cc13xx/rf-core/cc13xx-50kbps-tsch.h diff --git a/arch/cpu/cc26xx-cc13xx/Makefile.cc13xx b/arch/cpu/cc26xx-cc13xx/Makefile.cc13xx index ac050efe8..5ea92e30c 100644 --- a/arch/cpu/cc26xx-cc13xx/Makefile.cc13xx +++ b/arch/cpu/cc26xx-cc13xx/Makefile.cc13xx @@ -1,6 +1,6 @@ TI_XXWARE_PATH = lib/cc13xxware -CONTIKI_CPU_SOURCEFILES += smartrf-settings.c prop-mode.c prop-mode-tx-power.c +CONTIKI_CPU_SOURCEFILES += smartrf-settings.c prop-mode.c prop-mode-tx-power.c cc13xx-50kbps-tsch.c CFLAGS += -DCPU_FAMILY_CC13X0=1 -DCPU_FAMILY_CC13XX=1 diff --git a/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-def.h b/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-def.h index 47dbc4eb5..97b188e15 100644 --- a/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-def.h +++ b/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-def.h @@ -36,12 +36,43 @@ /*---------------------------------------------------------------------------*/ /* TSCH related defines */ +/* 2 bytes header, 4 bytes CRC */ +#define CC13XX_RADIO_PHY_OVERHEAD 6 +/* 3 bytes preamble, 3 bytes sync */ +#define CC13XX_RADIO_PHY_HEADER_LEN 6 +/* The default data rate is 50 kbps */ +#define CC13XX_RADIO_BIT_RATE 50000 + /* 1 len byte, 2 bytes CRC */ -#define RADIO_PHY_OVERHEAD 3 -/* 250kbps data rate. One byte = 32us */ -#define RADIO_BYTE_AIR_TIME 32 +#define CC26XX_RADIO_PHY_OVERHEAD 3 +/* 4 bytes preamble, 1 byte sync */ +#define CC26XX_RADIO_PHY_HEADER_LEN 5 +/* The fixed data rate is 250 kbps */ +#define CC26XX_RADIO_BIT_RATE 250000 + +#if CPU_FAMILY_CC13XX +#define RADIO_PHY_HEADER_LEN CC13XX_RADIO_PHY_HEADER_LEN +#define RADIO_PHY_OVERHEAD CC13XX_RADIO_PHY_OVERHEAD +#define RADIO_BIT_RATE CC13XX_RADIO_BIT_RATE + +/* The TSCH default slot length of 10ms is too short, use custom one instead */ +#ifndef TSCH_CONF_DEFAULT_TIMESLOT_TIMING +#define TSCH_CONF_DEFAULT_TIMESLOT_TIMING tsch_timing_cc13xx_50kbps +#endif /* TSCH_CONF_DEFAULT_TIMESLOT_TIMING */ + +/* Symbol for the custom TSCH timeslot timing template */ +#define TSCH_CONF_ARCH_HDR_PATH "rf-core/cc13xx-50kbps-tsch.h" + +#else +#define RADIO_PHY_HEADER_LEN CC26XX_RADIO_PHY_HEADER_LEN +#define RADIO_PHY_OVERHEAD CC26XX_RADIO_PHY_OVERHEAD +#define RADIO_BIT_RATE CC26XX_RADIO_BIT_RATE +#endif + +#define RADIO_BYTE_AIR_TIME (1000000 / (RADIO_BIT_RATE / 8)) + /* Delay between GO signal and SFD */ -#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(81)) +#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(RADIO_PHY_HEADER_LEN * RADIO_BYTE_AIR_TIME)) /* Delay between GO signal and start listening. * This value is so small because the radio is constantly on within each timeslot. */ #define RADIO_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(15)) @@ -56,9 +87,6 @@ #define RADIO_TO_RTIMER(X) ((uint32_t)(((uint64_t)(X) * (RTIMER_SECOND / 256)) / (RADIO_TIMER_SECOND / 256))) #define USEC_TO_RADIO(X) ((X) * 4) -/* The PHY header (preamble + SFD, 4+1 bytes) duration is equivalent to 10 symbols */ -#define RADIO_IEEE_802154_PHY_HEADER_DURATION_USEC 160 - /* Do not turn off TSCH within a timeslot: not enough time */ #define TSCH_CONF_RADIO_ON_DURING_TIMESLOT 1 diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.c b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.c index a9b949d93..3245b9c4f 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.c +++ b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.c @@ -386,7 +386,7 @@ on(void) rf_core_power_down(); return RF_CORE_CMD_ERROR; } - rf_core_setup_interrupts(0); + rf_core_setup_interrupts(); oscillators_switch_to_hf_xosc(); if(rf_ble_cmd_setup_ble_mode() != RF_BLE_CMD_OK) { diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/cc13xx-50kbps-tsch.c b/arch/cpu/cc26xx-cc13xx/rf-core/cc13xx-50kbps-tsch.c new file mode 100644 index 000000000..af76d63e3 --- /dev/null +++ b/arch/cpu/cc26xx-cc13xx/rf-core/cc13xx-50kbps-tsch.c @@ -0,0 +1,73 @@ +/* + * 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 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 + * IEEE 802.15.4 TSCH timeslot timings for CC13xx chips at 50kbps datarate + * \author + * Atis Elsts + * + */ + +#include "contiki.h" +#include "net/mac/tsch/tsch.h" + +#define CC13XX_TSCH_DEFAULT_TS_CCA_OFFSET 1800 +#define CC13XX_TSCH_DEFAULT_TS_CCA 128 +#define CC13XX_TSCH_DEFAULT_TS_TX_OFFSET 2500 +#define CC13XX_TSCH_DEFAULT_TS_RX_OFFSET (CC13XX_TSCH_DEFAULT_TS_TX_OFFSET - (TSCH_CONF_RX_WAIT / 2)) +#define CC13XX_TSCH_DEFAULT_TS_RX_ACK_DELAY 2000 +#define CC13XX_TSCH_DEFAULT_TS_TX_ACK_DELAY 3000 +#define CC13XX_TSCH_DEFAULT_TS_RX_WAIT TSCH_CONF_RX_WAIT +#define CC13XX_TSCH_DEFAULT_TS_ACK_WAIT 3000 +#define CC13XX_TSCH_DEFAULT_TS_RX_TX 192 +#define CC13XX_TSCH_DEFAULT_TS_MAX_ACK 10000 +#define CC13XX_TSCH_DEFAULT_TS_MAX_TX 21600 + +/* Timeslot length: 40000 usec */ +#define CC13XX_TSCH_DEFAULT_TS_TIMESLOT_LENGTH 40000 + +/* TSCH timeslot timing (microseconds) */ +const uint16_t tsch_timing_cc13xx_50kbps[tsch_ts_elements_count] = { + CC13XX_TSCH_DEFAULT_TS_CCA_OFFSET, + CC13XX_TSCH_DEFAULT_TS_CCA, + CC13XX_TSCH_DEFAULT_TS_TX_OFFSET, + CC13XX_TSCH_DEFAULT_TS_RX_OFFSET, + CC13XX_TSCH_DEFAULT_TS_RX_ACK_DELAY, + CC13XX_TSCH_DEFAULT_TS_TX_ACK_DELAY, + CC13XX_TSCH_DEFAULT_TS_RX_WAIT, + CC13XX_TSCH_DEFAULT_TS_ACK_WAIT, + CC13XX_TSCH_DEFAULT_TS_RX_TX, + CC13XX_TSCH_DEFAULT_TS_MAX_ACK, + CC13XX_TSCH_DEFAULT_TS_MAX_TX, + CC13XX_TSCH_DEFAULT_TS_TIMESLOT_LENGTH, +}; diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/cc13xx-50kbps-tsch.h b/arch/cpu/cc26xx-cc13xx/rf-core/cc13xx-50kbps-tsch.h new file mode 100644 index 000000000..5d4fdb376 --- /dev/null +++ b/arch/cpu/cc26xx-cc13xx/rf-core/cc13xx-50kbps-tsch.h @@ -0,0 +1,41 @@ +/* + * 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 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. + * + */ + +#ifndef CC13XX_50KBPS_TSCH_H_ +#define CC13XX_50KBPS_TSCH_H_ + +#include "contiki.h" + +/* TSCH timeslot timing (microseconds) */ +extern const uint16_t tsch_timing_cc13xx_50kbps[]; + +#endif /* CC13XX_50KBPS_TSCH_H_ */ diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/ieee-mode.c b/arch/cpu/cc26xx-cc13xx/rf-core/ieee-mode.c index 3516147b5..9f4021d21 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/ieee-mode.c +++ b/arch/cpu/cc26xx-cc13xx/rf-core/ieee-mode.c @@ -120,6 +120,8 @@ static uint8_t rf_stats[16] = { 0 }; /* The size of the RF commands buffer */ #define RF_CMD_BUFFER_SIZE 128 /*---------------------------------------------------------------------------*/ +#define RAT_TIMESTAMP_OFFSET_2_4_GHZ 0 +/*---------------------------------------------------------------------------*/ /** * \brief Returns the current status of a running Radio Op command * \param a A pointer with the buffer used to initiate the command @@ -130,55 +132,9 @@ static uint8_t rf_stats[16] = { 0 }; */ #define RF_RADIO_OP_GET_STATUS(a) (((rfc_radioOp_t *)a)->status) /*---------------------------------------------------------------------------*/ -/* Special value returned by CMD_IEEE_CCA_REQ when an RSSI is not available */ -#define RF_CMD_CCA_REQ_RSSI_UNKNOWN -128 - -/* Used for the return value of channel_clear */ -#define RF_CCA_CLEAR 1 -#define RF_CCA_BUSY 0 - -/* Used as an error return value for get_cca_info */ -#define RF_GET_CCA_INFO_ERROR 0xFF - -/* - * Values of the individual bits of the ccaInfo field in CMD_IEEE_CCA_REQ's - * status struct - */ -#define RF_CMD_CCA_REQ_CCA_STATE_IDLE 0 /* 00 */ -#define RF_CMD_CCA_REQ_CCA_STATE_BUSY 1 /* 01 */ -#define RF_CMD_CCA_REQ_CCA_STATE_INVALID 2 /* 10 */ - -#define RF_CMD_CCA_REQ_CCA_CORR_IDLE (0 << 4) -#define RF_CMD_CCA_REQ_CCA_CORR_BUSY (1 << 4) -#define RF_CMD_CCA_REQ_CCA_CORR_INVALID (3 << 4) -#define RF_CMD_CCA_REQ_CCA_CORR_MASK (3 << 4) - -#define RF_CMD_CCA_REQ_CCA_SYNC_BUSY (1 << 6) -/*---------------------------------------------------------------------------*/ #define IEEE_MODE_CHANNEL_MIN 11 #define IEEE_MODE_CHANNEL_MAX 26 /*---------------------------------------------------------------------------*/ -/* How long to wait for an ongoing ACK TX to finish before starting frame TX */ -#define TX_WAIT_TIMEOUT (RTIMER_SECOND >> 11) - -/* How long to wait for the RF to enter RX in rf_cmd_ieee_rx */ -#define ENTER_RX_WAIT_TIMEOUT (RTIMER_SECOND >> 10) - -/* How long to wait for the RF to react on CMD_ABORT: around 1 msec */ -#define RF_TURN_OFF_WAIT_TIMEOUT (RTIMER_SECOND >> 10) - -/* How long to wait for the RF to finish TX of a packet or an ACK */ -#define TX_FINISH_WAIT_TIMEOUT (RTIMER_SECOND >> 7) - -#define LIMITED_BUSYWAIT(cond, timeout) do { \ - rtimer_clock_t end_time = RTIMER_NOW() + timeout; \ - while(cond) { \ - if(!RTIMER_CLOCK_LT(RTIMER_NOW(), end_time)) { \ - break; \ - } \ - } \ - } while(0) -/*---------------------------------------------------------------------------*/ /* TX Power dBm lookup table - values from SmartRF Studio */ typedef struct output_config { radio_value_t dbm; @@ -211,33 +167,6 @@ static const output_config_t output_power[] = { /* Default TX Power - position in output_power[] */ static const output_config_t *tx_power_current = &output_power[0]; /*---------------------------------------------------------------------------*/ -static volatile int8_t last_rssi = 0; -static volatile uint8_t last_corr_lqi = 0; - -extern int32_t rat_offset; - -/*---------------------------------------------------------------------------*/ -/* SFD timestamp in RTIMER ticks */ -static volatile uint32_t last_packet_timestamp = 0; -/* SFD timestamp in RAT ticks (but 64 bits) */ -static uint64_t last_rat_timestamp64 = 0; - -/* For RAT overflow handling */ -static struct ctimer rat_overflow_timer; -static volatile uint32_t rat_overflow_counter = 0; -static rtimer_clock_t last_rat_overflow = 0; - -/* RAT has 32-bit register, overflows once 18 minutes */ -#define RAT_RANGE 4294967296ull -/* approximate value */ -#define RAT_OVERFLOW_PERIOD_SECONDS (60 * 18) - -/* XXX: don't know what exactly is this, looks like the time to Tx 3 octets */ -#define TIMESTAMP_OFFSET -(USEC_TO_RADIO(32 * 3) - 1) /* -95.75 usec */ -/*---------------------------------------------------------------------------*/ -/* Are we currently in poll mode? */ -static uint8_t poll_mode = 0; - static rfc_CMD_IEEE_MOD_FILT_t filter_cmd; /*---------------------------------------------------------------------------*/ /* @@ -256,27 +185,28 @@ static uint8_t cmd_ieee_rx_buf[RF_CMD_BUFFER_SIZE] CC_ALIGN(4); #define DATA_ENTRY_LENSZ_BYTE 1 #define DATA_ENTRY_LENSZ_WORD 2 /* 2 bytes */ -#define RX_BUF_SIZE 144 -/* Four receive buffers entries with room for 1 IEEE802.15.4 frame in each */ -static uint8_t rx_buf_0[RX_BUF_SIZE] CC_ALIGN(4); -static uint8_t rx_buf_1[RX_BUF_SIZE] CC_ALIGN(4); -static uint8_t rx_buf_2[RX_BUF_SIZE] CC_ALIGN(4); -static uint8_t rx_buf_3[RX_BUF_SIZE] CC_ALIGN(4); - -#define RX_BUF_INCLUDE_CRC 1 -#define RX_BUF_INCLUDE_RSSI 1 -#define RX_BUF_INCLUDE_CORR 1 -#define RX_BUF_INCLUDE_TIMESTAMP 1 - /* The size of the metadata (excluding the packet length field) */ #define RX_BUF_METADATA_SIZE \ - (2 * RX_BUF_INCLUDE_CRC + RX_BUF_INCLUDE_RSSI + RX_BUF_INCLUDE_CORR + 4 * RX_BUF_INCLUDE_TIMESTAMP) + (2 * RF_CORE_RX_BUF_INCLUDE_CRC \ + + RF_CORE_RX_BUF_INCLUDE_RSSI \ + + RF_CORE_RX_BUF_INCLUDE_CORR \ + + 4 * RF_CORE_RX_BUF_INCLUDE_TIMESTAMP) /* The offset of the packet length in a rx buffer */ #define RX_BUF_LENGTH_OFFSET sizeof(rfc_dataEntry_t) /* The offset of the packet data in a rx buffer */ #define RX_BUF_DATA_OFFSET (RX_BUF_LENGTH_OFFSET + 1) +#define RX_BUF_SIZE (RX_BUF_DATA_OFFSET \ + + NETSTACK_RADIO_MAX_PAYLOAD_LEN \ + + RX_BUF_METADATA_SIZE) + +/* Four receive buffers entries with room for 1 IEEE802.15.4 frame in each */ +static uint8_t rx_buf_0[RX_BUF_SIZE] CC_ALIGN(4); +static uint8_t rx_buf_1[RX_BUF_SIZE] CC_ALIGN(4); +static uint8_t rx_buf_2[RX_BUF_SIZE] CC_ALIGN(4); +static uint8_t rx_buf_3[RX_BUF_SIZE] CC_ALIGN(4); + /* The RX Data Queue */ static dataQueue_t rx_data_queue = { 0 }; @@ -358,8 +288,8 @@ transmitting(void) return 0; } - if((cmd.currentRssi == RF_CMD_CCA_REQ_RSSI_UNKNOWN) && - (cmd.ccaInfo.ccaEnergy == RF_CMD_CCA_REQ_CCA_STATE_BUSY)) { + if((cmd.currentRssi == RF_CORE_CMD_CCA_REQ_RSSI_UNKNOWN) && + (cmd.ccaInfo.ccaEnergy == RF_CORE_CMD_CCA_REQ_CCA_STATE_BUSY)) { return 1; } @@ -368,12 +298,12 @@ transmitting(void) /*---------------------------------------------------------------------------*/ /** * \brief Returns CCA information - * \return RF_GET_CCA_INFO_ERROR if the RF was not on + * \return RF_CORE_GET_CCA_INFO_ERROR if the RF was not on * \return On success, the return value is formatted as per the ccaInfo field * of CMD_IEEE_CCA_REQ * * It is the caller's responsibility to make sure the RF is on. This function - * will return RF_GET_CCA_INFO_ERROR if the RF is off + * will return RF_CORE_GET_CCA_INFO_ERROR if the RF is off * * This function will in fact wait for a valid CCA state */ @@ -385,20 +315,20 @@ get_cca_info(void) if(!rf_is_on()) { PRINTF("get_cca_info: Not on\n"); - return RF_GET_CCA_INFO_ERROR; + return RF_CORE_GET_CCA_INFO_ERROR; } memset(&cmd, 0x00, sizeof(cmd)); - cmd.ccaInfo.ccaState = RF_CMD_CCA_REQ_CCA_STATE_INVALID; + cmd.ccaInfo.ccaState = RF_CORE_CMD_CCA_REQ_CCA_STATE_INVALID; - while(cmd.ccaInfo.ccaState == RF_CMD_CCA_REQ_CCA_STATE_INVALID) { + while(cmd.ccaInfo.ccaState == RF_CORE_CMD_CCA_REQ_CCA_STATE_INVALID) { memset(&cmd, 0x00, sizeof(cmd)); cmd.commandNo = CMD_IEEE_CCA_REQ; if(rf_core_send_cmd((uint32_t)&cmd, &cmd_status) == RF_CORE_CMD_ERROR) { PRINTF("get_cca_info: CMDSTA=0x%08lx\n", cmd_status); - return RF_GET_CCA_INFO_ERROR; + return RF_CORE_GET_CCA_INFO_ERROR; } } @@ -425,14 +355,14 @@ get_rssi(void) was_off = 1; if(on() != RF_CORE_CMD_OK) { PRINTF("get_rssi: on() failed\n"); - return RF_CMD_CCA_REQ_RSSI_UNKNOWN; + return RF_CORE_CMD_CCA_REQ_RSSI_UNKNOWN; } } memset(&cmd, 0x00, sizeof(cmd)); - cmd.ccaInfo.ccaEnergy = RF_CMD_CCA_REQ_CCA_STATE_INVALID; + cmd.ccaInfo.ccaEnergy = RF_CORE_CMD_CCA_REQ_CCA_STATE_INVALID; - while(cmd.ccaInfo.ccaEnergy == RF_CMD_CCA_REQ_CCA_STATE_INVALID) { + while(cmd.ccaInfo.ccaEnergy == RF_CORE_CMD_CCA_REQ_CCA_STATE_INVALID) { memset(&cmd, 0x00, sizeof(cmd)); cmd.commandNo = CMD_IEEE_CCA_REQ; @@ -440,7 +370,7 @@ get_rssi(void) PRINTF("get_rssi: CMDSTA=0x%08lx\n", cmd_status); /* Make sure to return RSSI unknown */ - cmd.currentRssi = RF_CMD_CCA_REQ_RSSI_UNKNOWN; + cmd.currentRssi = RF_CORE_CMD_CCA_REQ_RSSI_UNKNOWN; break; } } @@ -558,8 +488,8 @@ rf_cmd_ieee_rx() return RF_CORE_CMD_ERROR; } - LIMITED_BUSYWAIT(RF_RADIO_OP_GET_STATUS(cmd_ieee_rx_buf) != RF_CORE_RADIO_OP_STATUS_ACTIVE, - ENTER_RX_WAIT_TIMEOUT); + RTIMER_BUSYWAIT_UNTIL(RF_RADIO_OP_GET_STATUS(cmd_ieee_rx_buf) == RF_CORE_RADIO_OP_STATUS_ACTIVE, + RF_CORE_ENTER_RX_TIMEOUT); /* Wait to enter RX */ if(RF_RADIO_OP_GET_STATUS(cmd_ieee_rx_buf) != RF_CORE_RADIO_OP_STATUS_ACTIVE) { @@ -615,11 +545,11 @@ init_rf_params(void) cmd->rxConfig.bAutoFlushCrc = 1; cmd->rxConfig.bAutoFlushIgn = 0; cmd->rxConfig.bIncludePhyHdr = 0; - cmd->rxConfig.bIncludeCrc = RX_BUF_INCLUDE_CRC; - cmd->rxConfig.bAppendRssi = RX_BUF_INCLUDE_RSSI; - cmd->rxConfig.bAppendCorrCrc = RX_BUF_INCLUDE_CORR; + cmd->rxConfig.bIncludeCrc = RF_CORE_RX_BUF_INCLUDE_CRC; + cmd->rxConfig.bAppendRssi = RF_CORE_RX_BUF_INCLUDE_RSSI; + cmd->rxConfig.bAppendCorrCrc = RF_CORE_RX_BUF_INCLUDE_CORR; cmd->rxConfig.bAppendSrcInd = 0; - cmd->rxConfig.bAppendTimestamp = RX_BUF_INCLUDE_TIMESTAMP; + cmd->rxConfig.bAppendTimestamp = RF_CORE_RX_BUF_INCLUDE_TIMESTAMP; cmd->pRxQ = &rx_data_queue; cmd->pOutput = (rfc_ieeeRxOutput_t *)rf_stats; @@ -714,7 +644,7 @@ rx_off(void) } /* Wait for ongoing ACK TX to finish */ - LIMITED_BUSYWAIT(transmitting(), TX_FINISH_WAIT_TIMEOUT); + RTIMER_BUSYWAIT_UNTIL(!transmitting(), RF_CORE_TX_FINISH_TIMEOUT); /* Send a CMD_ABORT command to RF Core */ if(rf_core_send_cmd(CMDR_DIR_CMD(CMD_ABORT), &cmd_status) != RF_CORE_CMD_OK) { @@ -722,7 +652,7 @@ rx_off(void) /* Continue nonetheless */ } - LIMITED_BUSYWAIT(rf_is_on(), RF_TURN_OFF_WAIT_TIMEOUT); + RTIMER_BUSYWAIT_UNTIL(!rf_is_on(), RF_CORE_TURN_OFF_TIMEOUT); if(RF_RADIO_OP_GET_STATUS(cmd_ieee_rx_buf) == IEEE_DONE_STOPPED || RF_RADIO_OP_GET_STATUS(cmd_ieee_rx_buf) == IEEE_DONE_ABORT) { @@ -773,8 +703,8 @@ soft_off(void) return; } - LIMITED_BUSYWAIT((cmd->status & RF_CORE_RADIO_OP_MASKED_STATUS) == - RF_CORE_RADIO_OP_MASKED_STATUS_RUNNING, RF_TURN_OFF_WAIT_TIMEOUT); + RTIMER_BUSYWAIT_UNTIL((cmd->status & RF_CORE_RADIO_OP_MASKED_STATUS) != + RF_CORE_RADIO_OP_MASKED_STATUS_RUNNING, RF_CORE_TURN_OFF_TIMEOUT); } /*---------------------------------------------------------------------------*/ static uint8_t @@ -791,71 +721,10 @@ soft_on(void) static const rf_core_primary_mode_t mode_ieee = { soft_off, soft_on, + rf_is_on, + RAT_TIMESTAMP_OFFSET_2_4_GHZ }; /*---------------------------------------------------------------------------*/ -static uint8_t -check_rat_overflow(bool first_time) -{ - static uint32_t last_value; - uint32_t current_value; - uint8_t interrupts_disabled; - - /* Bail out if the RF is not on */ - if(!rf_is_on()) { - return 0; - } - - interrupts_disabled = ti_lib_int_master_disable(); - if(first_time) { - last_value = HWREG(RFC_RAT_BASE + RATCNT); - } else { - current_value = HWREG(RFC_RAT_BASE + RATCNT); - if(current_value + RAT_RANGE / 4 < last_value) { - /* Overflow detected */ - last_rat_overflow = RTIMER_NOW(); - rat_overflow_counter++; - } - last_value = current_value; - } - if(!interrupts_disabled) { - ti_lib_int_master_enable(); - } - return 1; -} -/*---------------------------------------------------------------------------*/ -static void -handle_rat_overflow(void *unused) -{ - uint8_t success; - uint8_t was_off = 0; - - if(!rf_is_on()) { - was_off = 1; - if(on() != RF_CORE_CMD_OK) { - PRINTF("overflow: on() failed\n"); - ctimer_set(&rat_overflow_timer, CLOCK_SECOND, - handle_rat_overflow, NULL); - return; - } - } - - success = check_rat_overflow(false); - - if(was_off) { - off(); - } - - if(success) { - /* Retry after half of the interval */ - ctimer_set(&rat_overflow_timer, RAT_OVERFLOW_PERIOD_SECONDS * CLOCK_SECOND / 2, - handle_rat_overflow, NULL); - } else { - /* Retry sooner */ - ctimer_set(&rat_overflow_timer, CLOCK_SECOND, - handle_rat_overflow, NULL); - } -} -/*---------------------------------------------------------------------------*/ static int init(void) { @@ -889,9 +758,7 @@ init(void) rf_core_primary_mode_register(&mode_ieee); - check_rat_overflow(true); - ctimer_set(&rat_overflow_timer, RAT_OVERFLOW_PERIOD_SECONDS * CLOCK_SECOND / 2, - handle_rat_overflow, NULL); + rf_core_rat_init(); process_start(&rf_core_process, NULL); return 1; @@ -935,7 +802,7 @@ transmit(unsigned short transmit_len) do { tx_active = transmitting(); } while(tx_active == 1 && - (RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + TX_WAIT_TIMEOUT))); + (RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + RF_CORE_TX_TIMEOUT))); if(tx_active) { PRINTF("transmit: Already TXing and wait timed out\n"); @@ -957,7 +824,7 @@ transmit(unsigned short transmit_len) cmd.startTrigger.triggerType = TRIG_NOW; /* Enable the LAST_FG_COMMAND_DONE interrupt, which will wake us up */ - rf_core_cmd_done_en(true, poll_mode); + rf_core_cmd_done_en(true); ret = rf_core_send_cmd((uint32_t)&cmd, &cmd_status); @@ -973,7 +840,7 @@ transmit(unsigned short transmit_len) * 1) make the `lpm_sleep()` call here unconditional; * 2) change the radio ISR priority to allow radio ISR to interrupt rtimer ISR. */ - if(!poll_mode) { + if(!rf_core_poll_mode) { lpm_sleep(); } } @@ -1007,7 +874,7 @@ transmit(unsigned short transmit_len) * Disable LAST_FG_COMMAND_DONE interrupt. We don't really care about it * except when we are transmitting */ - rf_core_cmd_done_dis(poll_mode); + rf_core_cmd_done_dis(); if(was_off) { off(); @@ -1036,46 +903,6 @@ release_data_entry(void) rx_read_entry = entry->pNextEntry; } /*---------------------------------------------------------------------------*/ -static uint32_t -calc_last_packet_timestamp(uint32_t rat_timestamp) -{ - uint64_t rat_timestamp64; - uint32_t adjusted_overflow_counter; - uint8_t was_off = 0; - - if(!rf_is_on()) { - was_off = 1; - on(); - } - - if(rf_is_on()) { - check_rat_overflow(false); - if(was_off) { - off(); - } - } - - adjusted_overflow_counter = rat_overflow_counter; - - /* if the timestamp is large and the last oveflow was recently, - assume that the timestamp refers to the time before the overflow */ - if(rat_timestamp > (uint32_t)(RAT_RANGE * 3 / 4)) { - if(RTIMER_CLOCK_LT(RTIMER_NOW(), - last_rat_overflow + RAT_OVERFLOW_PERIOD_SECONDS * RTIMER_SECOND / 4)) { - adjusted_overflow_counter--; - } - } - - /* add the overflowed time to the timestamp */ - rat_timestamp64 = rat_timestamp + RAT_RANGE * adjusted_overflow_counter; - /* correct timestamp so that it refers to the end of the SFD */ - rat_timestamp64 += TIMESTAMP_OFFSET; - - last_rat_timestamp64 = rat_timestamp64 - rat_offset; - - return RADIO_TO_RTIMER(rat_timestamp64 - rat_offset); -} -/*---------------------------------------------------------------------------*/ static int read_frame(void *buf, unsigned short buf_len) { @@ -1111,20 +938,20 @@ read_frame(void *buf, unsigned short buf_len) memcpy(buf, (uint8_t *)rx_read_entry + RX_BUF_DATA_OFFSET, len); - last_rssi = (int8_t)rx_read_entry[RX_BUF_DATA_OFFSET + len + 2]; - last_corr_lqi = (uint8_t)rx_read_entry[RX_BUF_DATA_OFFSET + len + 3] & STATUS_CORRELATION; + rf_core_last_rssi = (int8_t)rx_read_entry[RX_BUF_DATA_OFFSET + len]; + rf_core_last_corr_lqi = (uint8_t)rx_read_entry[RX_BUF_DATA_OFFSET + len + 1] & STATUS_CORRELATION; /* get the timestamp */ - memcpy(&rat_timestamp, (uint8_t *)rx_read_entry + RX_BUF_DATA_OFFSET + len + 4, 4); + memcpy(&rat_timestamp, (uint8_t *)rx_read_entry + RX_BUF_DATA_OFFSET + len + 2, 4); - last_packet_timestamp = calc_last_packet_timestamp(rat_timestamp); + rf_core_last_packet_timestamp = rf_core_convert_rat_to_rtimer(rat_timestamp); - if(!poll_mode) { + if(!rf_core_poll_mode) { /* Not in poll mode: packetbuf should not be accessed in interrupt context. * In poll mode, the last packet RSSI and link quality can be obtained through * RADIO_PARAM_LAST_RSSI and RADIO_PARAM_LAST_LINK_QUALITY */ - packetbuf_set_attr(PACKETBUF_ATTR_RSSI, last_rssi); - packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, last_corr_lqi); + packetbuf_set_attr(PACKETBUF_ATTR_RSSI, rf_core_last_rssi); + packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, rf_core_last_corr_lqi); } release_data_entry(); @@ -1137,7 +964,7 @@ channel_clear(void) { uint8_t was_off = 0; uint8_t cca_info; - int ret = RF_CCA_CLEAR; + int ret = RF_CORE_CCA_CLEAR; /* * If we are in the middle of a BLE operation, we got called by ContikiMAC @@ -1145,7 +972,7 @@ channel_clear(void) */ if(rf_ble_is_active() == RF_BLE_ACTIVE) { PRINTF("channel_clear: Interrupt context but BLE in progress\n"); - return RF_CCA_CLEAR; + return RF_CORE_CCA_CLEAR; } if(rf_is_on()) { @@ -1157,7 +984,7 @@ channel_clear(void) * * We could probably even simply return that the channel is clear */ - LIMITED_BUSYWAIT(transmitting(), TX_FINISH_WAIT_TIMEOUT); + RTIMER_BUSYWAIT_UNTIL(!transmitting(), RF_CORE_TX_FINISH_TIMEOUT); } else { was_off = 1; if(on() != RF_CORE_CMD_OK) { @@ -1165,21 +992,21 @@ channel_clear(void) if(was_off) { off(); } - return RF_CCA_CLEAR; + return RF_CORE_CCA_CLEAR; } } cca_info = get_cca_info(); - if(cca_info == RF_GET_CCA_INFO_ERROR) { + if(cca_info == RF_CORE_GET_CCA_INFO_ERROR) { PRINTF("channel_clear: CCA error\n"); - ret = RF_CCA_CLEAR; + ret = RF_CORE_CCA_CLEAR; } else { /* * cca_info bits 1:0 - ccaStatus * Return 1 (clear) if idle or invalid. */ - ret = (cca_info & 0x03) != RF_CMD_CCA_REQ_CCA_STATE_BUSY; + ret = (cca_info & 0x03) != RF_CORE_CMD_CCA_REQ_CCA_STATE_BUSY; } if(was_off) { @@ -1218,12 +1045,12 @@ receiving_packet(void) cca_info = get_cca_info(); /* If we can't read CCA info, return "not receiving" */ - if(cca_info == RF_GET_CCA_INFO_ERROR) { + if(cca_info == RF_CORE_GET_CCA_INFO_ERROR) { return 0; } /* If sync has been seen, return 1 (receiving) */ - if(cca_info & RF_CMD_CCA_REQ_CCA_SYNC_BUSY) { + if(cca_info & RF_CORE_CMD_CCA_REQ_CCA_SYNC_BUSY) { return 1; } @@ -1241,7 +1068,7 @@ pending_packet(void) if(entry->status == DATA_ENTRY_STATUS_FINISHED || entry->status == DATA_ENTRY_STATUS_BUSY) { rv = 1; - if(!poll_mode) { + if(!rf_core_poll_mode) { process_poll(&rf_core_process); } } @@ -1292,7 +1119,7 @@ on(void) return RF_CORE_CMD_ERROR; } - rf_core_setup_interrupts(poll_mode); + rf_core_setup_interrupts(); if(rf_radio_setup() != RF_CORE_CMD_OK) { PRINTF("on: radio_setup() failed\n"); @@ -1314,7 +1141,7 @@ off(void) return RF_CORE_CMD_OK; } - LIMITED_BUSYWAIT(transmitting(), TX_FINISH_WAIT_TIMEOUT); + RTIMER_BUSYWAIT_UNTIL(!transmitting(), RF_CORE_TX_FINISH_TIMEOUT); /* stopping the rx explicitly results in lower sleep-mode power usage */ rx_off(); @@ -1394,7 +1221,7 @@ get_value(radio_param_t param, radio_value_t *value) if(cmd->frameFiltOpt.autoAckEn) { *value |= RADIO_RX_MODE_AUTOACK; } - if(poll_mode) { + if(rf_core_poll_mode) { *value |= RADIO_RX_MODE_POLL_MODE; } @@ -1411,7 +1238,7 @@ get_value(radio_param_t param, radio_value_t *value) case RADIO_PARAM_RSSI: *value = get_rssi(); - if(*value == RF_CMD_CCA_REQ_RSSI_UNKNOWN) { + if(*value == RF_CORE_CMD_CCA_REQ_RSSI_UNKNOWN) { return RADIO_RESULT_ERROR; } else { return RADIO_RESULT_OK; @@ -1429,10 +1256,25 @@ get_value(radio_param_t param, radio_value_t *value) *value = OUTPUT_POWER_MAX; return RADIO_RESULT_OK; case RADIO_PARAM_LAST_RSSI: - *value = last_rssi; + *value = rf_core_last_rssi; return RADIO_RESULT_OK; case RADIO_PARAM_LAST_LINK_QUALITY: - *value = last_corr_lqi; + *value = rf_core_last_corr_lqi; + return RADIO_RESULT_OK; + case RADIO_CONST_PHY_OVERHEAD: + *value = (radio_value_t)RADIO_PHY_OVERHEAD; + return RADIO_RESULT_OK; + case RADIO_CONST_BYTE_AIR_TIME: + *value = (radio_value_t)RADIO_BYTE_AIR_TIME; + return RADIO_RESULT_OK; + case RADIO_CONST_DELAY_BEFORE_TX: + *value = (radio_value_t)RADIO_DELAY_BEFORE_TX; + return RADIO_RESULT_OK; + case RADIO_CONST_DELAY_BEFORE_RX: + *value = (radio_value_t)RADIO_DELAY_BEFORE_RX; + return RADIO_RESULT_OK; + case RADIO_CONST_DELAY_BEFORE_DETECT: + *value = (radio_value_t)RADIO_DELAY_BEFORE_DETECT; return RADIO_RESULT_OK; default: return RADIO_RESULT_NOT_SUPPORTED; @@ -1498,9 +1340,9 @@ set_value(radio_param_t param, radio_value_t value) cmd->frameFiltOpt.bPanCoord = 0; cmd->frameFiltOpt.bStrictLenFilter = 0; - old_poll_mode = poll_mode; - poll_mode = (value & RADIO_RX_MODE_POLL_MODE) != 0; - if(poll_mode == old_poll_mode) { + old_poll_mode = rf_core_poll_mode; + rf_core_poll_mode = (value & RADIO_RX_MODE_POLL_MODE) != 0; + if(rf_core_poll_mode == old_poll_mode) { uint32_t cmd_status; /* do not turn the radio on and off, just send an update command */ @@ -1552,7 +1394,7 @@ set_value(radio_param_t param, radio_value_t value) /* Restart the radio timer (RAT). This causes resynchronization between RAT and RTC: useful for TSCH. */ if(rf_core_restart_rat() == RF_CORE_CMD_OK) { - check_rat_overflow(false); + rf_core_check_rat_overflow(); } if(rx_on() != RF_CORE_CMD_OK) { @@ -1590,7 +1432,7 @@ get_object(radio_param_t param, void *dest, size_t size) if(size != sizeof(rtimer_clock_t) || !dest) { return RADIO_RESULT_INVALID_VALUE; } - *(rtimer_clock_t *)dest = last_packet_timestamp; + *(rtimer_clock_t *)dest = rf_core_last_packet_timestamp; return RADIO_RESULT_OK; } diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/prop-mode.c b/arch/cpu/cc26xx-cc13xx/rf-core/prop-mode.c index 66b4a4370..0ce6de5dd 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/prop-mode.c +++ b/arch/cpu/cc26xx-cc13xx/rf-core/prop-mode.c @@ -115,24 +115,6 @@ */ #define RF_RADIO_OP_GET_STATUS(a) GET_FIELD_V(a, radioOp, status) /*---------------------------------------------------------------------------*/ -/* Special value returned by CMD_IEEE_CCA_REQ when an RSSI is not available */ -#define RF_CMD_CCA_REQ_RSSI_UNKNOWN -128 - -/* Used for the return value of channel_clear */ -#define RF_CCA_CLEAR 1 -#define RF_CCA_BUSY 0 - -/* Used as an error return value for get_cca_info */ -#define RF_GET_CCA_INFO_ERROR 0xFF - -/* - * Values of the individual bits of the ccaInfo field in CMD_IEEE_CCA_REQ's - * status struct - */ -#define RF_CMD_CCA_REQ_CCA_STATE_IDLE 0 /* 00 */ -#define RF_CMD_CCA_REQ_CCA_STATE_BUSY 1 /* 01 */ -#define RF_CMD_CCA_REQ_CCA_STATE_INVALID 2 /* 10 */ - #ifdef PROP_MODE_CONF_RSSI_THRESHOLD #define PROP_MODE_RSSI_THRESHOLD PROP_MODE_CONF_RSSI_THRESHOLD #else @@ -141,6 +123,8 @@ static int8_t rssi_threshold = PROP_MODE_RSSI_THRESHOLD; /*---------------------------------------------------------------------------*/ +static volatile uint8_t is_receiving_packet; +/*---------------------------------------------------------------------------*/ static int on(void); static int off(void); @@ -170,12 +154,6 @@ static rfc_propRxOutput_t rx_stats; #define DOT_4G_PHR_DW_BIT 0 #endif /*---------------------------------------------------------------------------*/ -/* How long to wait for an ongoing ACK TX to finish before starting frame TX */ -#define TX_WAIT_TIMEOUT (RTIMER_SECOND >> 11) - -/* How long to wait for the RF to enter RX in rf_cmd_ieee_rx */ -#define ENTER_RX_WAIT_TIMEOUT (RTIMER_SECOND >> 10) -/*---------------------------------------------------------------------------*/ /* TX power table for the 431-527MHz band */ #ifdef PROP_MODE_CONF_TX_POWER_431_527 #define PROP_MODE_TX_POWER_431_527 PROP_MODE_CONF_TX_POWER_431_527 @@ -222,12 +200,29 @@ static const prop_mode_tx_power_config_t *tx_power_current = &TX_POWER_DRIVER[1] #define DATA_ENTRY_LENSZ_BYTE 1 #define DATA_ENTRY_LENSZ_WORD 2 /* 2 bytes */ +/* The size of the metadata (excluding the packet length field) */ +#define RX_BUF_METADATA_SIZE \ + (CRC_LEN * RF_CORE_RX_BUF_INCLUDE_CRC \ + + RF_CORE_RX_BUF_INCLUDE_RSSI \ + + RF_CORE_RX_BUF_INCLUDE_CORR \ + + 4 * RF_CORE_RX_BUF_INCLUDE_TIMESTAMP) + +/* The offset of the packet length in a rx buffer */ +#define RX_BUF_LENGTH_OFFSET sizeof(rfc_dataEntry_t) +/* The offset of the packet data in a rx buffer */ +#define RX_BUF_DATA_OFFSET (RX_BUF_LENGTH_OFFSET + DOT_4G_PHR_LEN) + +#define ALIGN_TO_4(size) (((size) + 3) & ~3) + +#define RX_BUF_SIZE ALIGN_TO_4(RX_BUF_DATA_OFFSET \ + + NETSTACK_RADIO_MAX_PAYLOAD_LEN \ + + RX_BUF_METADATA_SIZE) + /* * RX buffers. * PROP_MODE_RX_BUF_CNT buffers of RX_BUF_SIZE bytes each. The start of each * buffer must be 4-byte aligned, therefore RX_BUF_SIZE must divide by 4 */ -#define RX_BUF_SIZE 140 static uint8_t rx_buf[PROP_MODE_RX_BUF_CNT][RX_BUF_SIZE] CC_ALIGN(4); /* The RX Data Queue */ @@ -236,6 +231,12 @@ static dataQueue_t rx_data_queue = { 0 }; /* Receive entry pointer to keep track of read items */ volatile static uint8_t *rx_read_entry; /*---------------------------------------------------------------------------*/ +/* + * Increasing this number causes unicast Tx immediately after broadcast Rx to have + * negative synchronization errors ("dr" in TSCH logs); decreasing it: the opposite. + */ +#define RAT_TIMESTAMP_OFFSET_SUB_GHZ USEC_TO_RADIO(160 * 6 - 240) +/*---------------------------------------------------------------------------*/ /* The outgoing frame buffer */ #define TX_BUF_PAYLOAD_LEN 180 #define TX_BUF_HDR_LEN 2 @@ -272,13 +273,13 @@ get_rssi(void) was_off = 1; if(on() != RF_CORE_CMD_OK) { PRINTF("get_rssi: on() failed\n"); - return RF_CMD_CCA_REQ_RSSI_UNKNOWN; + return RF_CORE_CMD_CCA_REQ_RSSI_UNKNOWN; } } - rssi = RF_CMD_CCA_REQ_RSSI_UNKNOWN; + rssi = RF_CORE_CMD_CCA_REQ_RSSI_UNKNOWN; - while((rssi == RF_CMD_CCA_REQ_RSSI_UNKNOWN || rssi == 0) && ++attempts < 10) { + while((rssi == RF_CORE_CMD_CCA_REQ_RSSI_UNKNOWN || rssi == 0) && ++attempts < 10) { memset(&cmd, 0x00, sizeof(cmd)); cmd.commandNo = CMD_GET_RSSI; @@ -420,13 +421,17 @@ static uint8_t rf_cmd_prop_rx() { uint32_t cmd_status; - rtimer_clock_t t0; volatile rfc_CMD_PROP_RX_ADV_t *cmd_rx_adv; int ret; cmd_rx_adv = (rfc_CMD_PROP_RX_ADV_t *)&smartrf_settings_cmd_prop_rx_adv; cmd_rx_adv->status = RF_CORE_RADIO_OP_STATUS_IDLE; + cmd_rx_adv->rxConf.bIncludeCrc = RF_CORE_RX_BUF_INCLUDE_CRC; + cmd_rx_adv->rxConf.bAppendRssi = RF_CORE_RX_BUF_INCLUDE_RSSI; + cmd_rx_adv->rxConf.bAppendTimestamp = RF_CORE_RX_BUF_INCLUDE_TIMESTAMP; + cmd_rx_adv->rxConf.bAppendStatus = RF_CORE_RX_BUF_INCLUDE_CORR; + /* * Set the max Packet length. This is for the payload only, therefore * 2047 - length offset @@ -441,10 +446,8 @@ rf_cmd_prop_rx() return RF_CORE_CMD_ERROR; } - t0 = RTIMER_NOW(); - - while(cmd_rx_adv->status != RF_CORE_RADIO_OP_STATUS_ACTIVE && - (RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + ENTER_RX_WAIT_TIMEOUT))); + RTIMER_BUSYWAIT_UNTIL(cmd_rx_adv->status == RF_CORE_RADIO_OP_STATUS_ACTIVE, + RF_CORE_ENTER_RX_TIMEOUT); /* Wait to enter RX */ if(cmd_rx_adv->status != RF_CORE_RADIO_OP_STATUS_ACTIVE) { @@ -506,13 +509,16 @@ rx_off_prop(void) return RF_CORE_CMD_OK; } + /* Wait for ongoing ACK TX to finish */ + RTIMER_BUSYWAIT_UNTIL(!transmitting(), RF_CORE_TX_FINISH_TIMEOUT); + /* Send a CMD_ABORT command to RF Core */ if(rf_core_send_cmd(CMDR_DIR_CMD(CMD_ABORT), &cmd_status) != RF_CORE_CMD_OK) { PRINTF("rx_off_prop: CMD_ABORT status=0x%08lx\n", cmd_status); /* Continue nonetheless */ } - while(rf_is_on()); + RTIMER_BUSYWAIT_UNTIL(!rf_is_on(), RF_CORE_TURN_OFF_TIMEOUT); if(smartrf_settings_cmd_prop_rx_adv.status == PROP_DONE_STOPPED || smartrf_settings_cmd_prop_rx_adv.status == PROP_DONE_ABORT) { @@ -583,8 +589,8 @@ soft_off_prop(void) return; } - while((cmd->status & RF_CORE_RADIO_OP_MASKED_STATUS) == - RF_CORE_RADIO_OP_MASKED_STATUS_RUNNING); + RTIMER_BUSYWAIT_UNTIL((cmd->status & RF_CORE_RADIO_OP_MASKED_STATUS) != + RF_CORE_RADIO_OP_MASKED_STATUS_RUNNING, RF_CORE_TURN_OFF_TIMEOUT); } /*---------------------------------------------------------------------------*/ static uint8_t @@ -606,6 +612,8 @@ soft_on_prop(void) static const rf_core_primary_mode_t mode_prop = { soft_off_prop, soft_on_prop, + rf_is_on, + RAT_TIMESTAMP_OFFSET_SUB_GHZ }; /*---------------------------------------------------------------------------*/ static int @@ -637,10 +645,15 @@ init(void) return RF_CORE_CMD_ERROR; } + /* Enable the "sync word seen" interrupt */ + ti_lib_rfc_hw_int_enable(RFC_DBELL_RFHWIEN_MDMSOFT); + ENERGEST_ON(ENERGEST_TYPE_LISTEN); rf_core_primary_mode_register(&mode_prop); + rf_core_rat_init(); + process_start(&rf_core_process, NULL); return 1; @@ -701,7 +714,7 @@ transmit(unsigned short transmit_len) rx_off_prop(); /* Enable the LAST_COMMAND_DONE interrupt to wake us up */ - rf_core_cmd_done_en(false, false); + rf_core_cmd_done_en(false); ret = rf_core_send_cmd((uint32_t)cmd_tx_adv, &cmd_status); @@ -714,7 +727,14 @@ transmit(unsigned short transmit_len) /* Idle away while the command is running */ while((cmd_tx_adv->status & RF_CORE_RADIO_OP_MASKED_STATUS) == RF_CORE_RADIO_OP_MASKED_STATUS_RUNNING) { - lpm_sleep(); + /* Note: for now sleeping while Tx'ing in polling mode is disabled. + * To enable it: + * 1) make the `lpm_sleep()` call here unconditional; + * 2) change the radio ISR priority to allow radio ISR to interrupt rtimer ISR. + */ + if(!rf_core_poll_mode) { + lpm_sleep(); + } } if(cmd_tx_adv->status == RF_CORE_RADIO_OP_STATUS_PROP_DONE_OK) { @@ -743,7 +763,7 @@ transmit(unsigned short transmit_len) * Disable LAST_FG_COMMAND_DONE interrupt. We don't really care about it * except when we are transmitting */ - rf_core_cmd_done_dis(false); + rf_core_cmd_done_dis(); /* Workaround. Set status to IDLE */ cmd_tx_adv->status = RF_CORE_RADIO_OP_STATUS_IDLE; @@ -764,47 +784,98 @@ send(const void *payload, unsigned short payload_len) return transmit(payload_len); } /*---------------------------------------------------------------------------*/ -static int -read_frame(void *buf, unsigned short buf_len) +static void +release_data_entry(void) { - int_master_status_t status; rfc_dataEntryGeneral_t *entry = (rfc_dataEntryGeneral_t *)rx_read_entry; uint8_t *data_ptr = &entry->data; - int len = 0; + int_master_status_t interrupt_status; - if(entry->status == DATA_ENTRY_STATUS_FINISHED) { + /* Clear the length field (2 bytes) */ + data_ptr[0] = 0; + data_ptr[1] = 0; - /* - * First 2 bytes in the data entry are the length. - * Our data entry consists of: Payload + RSSI (1 byte) + Status (1 byte) - * This length includes all of those. - */ - len = (*(uint16_t *)data_ptr); - data_ptr += 2; - len -= 2; + /* Set status to 0 "Pending" in element */ + entry->status = DATA_ENTRY_STATUS_PENDING; + rx_read_entry = entry->pNextEntry; - if(len > 0) { - if(len <= buf_len) { - memcpy(buf, data_ptr, len); - } - - packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (int8_t)data_ptr[len]); - packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, 0x7F); - } - - /* Move read entry pointer to next entry */ - rx_read_entry = entry->pNextEntry; - entry->status = DATA_ENTRY_STATUS_PENDING; - } - - status = critical_enter(); - if(rx_is_full) { - rx_is_full = false; + interrupt_status = critical_enter(); + if(rf_core_rx_is_full) { + rf_core_rx_is_full = false; PRINTF("RXQ was full, re-enabling radio!\n"); rx_on_prop(); } - critical_exit(status); - + critical_exit(interrupt_status); + +} +/*---------------------------------------------------------------------------*/ +static int +read_frame(void *buf, unsigned short buf_len) +{ + rfc_dataEntryGeneral_t *entry = (rfc_dataEntryGeneral_t *)rx_read_entry; + uint8_t *data_ptr = &entry->data; + int len = 0; + uint32_t rat_timestamp; + + /* wait for entry to become finished */ + rtimer_clock_t t0 = RTIMER_NOW(); + while(entry->status == DATA_ENTRY_STATUS_BUSY + && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (RTIMER_SECOND / 50))); + + /* Make sure the flag is reset */ + is_receiving_packet = 0; + + if(entry->status != DATA_ENTRY_STATUS_FINISHED) { + /* No available data */ + return 0; + } + + /* + * First 2 bytes in the data entry are the length. + * Our data entry consists of: + * Payload + RSSI (1 byte) + Timestamp (4 bytes) + Status (1 byte) + * This length includes all of those. + */ + len = (*(uint16_t *)data_ptr); + + if(len <= RX_BUF_METADATA_SIZE) { + PRINTF("RF: too short!"); + + release_data_entry(); + return 0; + } + + data_ptr += 2; + len -= RX_BUF_METADATA_SIZE; + + if(len > buf_len) { + PRINTF("RF: too long\n"); + + release_data_entry(); + return 0; + } + + memcpy(buf, data_ptr, len); + + /* get the RSSI and status */ + rf_core_last_rssi = (int8_t)data_ptr[len]; + rf_core_last_corr_lqi = data_ptr[len + 5]; + + /* get the timestamp */ + memcpy(&rat_timestamp, data_ptr + len + 1, 4); + + rf_core_last_packet_timestamp = rf_core_convert_rat_to_rtimer(rat_timestamp); + + if(!rf_core_poll_mode) { + /* Not in poll mode: packetbuf should not be accessed in interrupt context. + * In poll mode, the last packet RSSI and link quality can be obtained through + * RADIO_PARAM_LAST_RSSI and RADIO_PARAM_LAST_LINK_QUALITY */ + packetbuf_set_attr(PACKETBUF_ATTR_RSSI, rf_core_last_rssi); + packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, rf_core_last_corr_lqi); + } + + release_data_entry(); + return len; } /*---------------------------------------------------------------------------*/ @@ -813,14 +884,14 @@ channel_clear(void) { uint8_t was_off = 0; uint32_t cmd_status; - int8_t rssi = RF_CMD_CCA_REQ_RSSI_UNKNOWN; + int8_t rssi = RF_CORE_CMD_CCA_REQ_RSSI_UNKNOWN; /* * If we are in the middle of a BLE operation, we got called by ContikiMAC * from within an interrupt context. Indicate a clear channel */ if(rf_ble_is_active() == RF_BLE_ACTIVE) { - return RF_CCA_CLEAR; + return RF_CORE_CCA_CLEAR; } if(!rf_core_is_accessible()) { @@ -830,16 +901,16 @@ channel_clear(void) if(was_off) { off(); } - return RF_CCA_CLEAR; + return RF_CORE_CCA_CLEAR; } } else { if(transmitting()) { PRINTF("channel_clear: called while in TX\n"); - return RF_CCA_CLEAR; + return RF_CORE_CCA_CLEAR; } } - while(rssi == RF_CMD_CCA_REQ_RSSI_UNKNOWN || rssi == 0) { + while(rssi == RF_CORE_CMD_CCA_REQ_RSSI_UNKNOWN || rssi == 0) { if(rf_core_send_cmd(CMDR_DIR_CMD(CMD_GET_RSSI), &cmd_status) != RF_CORE_CMD_OK) { break; @@ -853,10 +924,10 @@ channel_clear(void) } if(rssi >= rssi_threshold) { - return RF_CCA_BUSY; + return RF_CORE_CCA_BUSY; } - return RF_CCA_CLEAR; + return RF_CORE_CCA_CLEAR; } /*---------------------------------------------------------------------------*/ static int @@ -866,11 +937,23 @@ receiving_packet(void) return 0; } - if(channel_clear() == RF_CCA_CLEAR) { - return 0; + if(!is_receiving_packet) { + /* Look for the modem synchronization word detection interrupt flag. + * This flag is raised when the synchronization word is received. + */ + if(HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFHWIFG) & RFC_DBELL_RFHWIFG_MDMSOFT) { + is_receiving_packet = 1; + } + } else { + /* After the start of the packet: reset the Rx flag once the channel gets clear */ + is_receiving_packet = (channel_clear() == RF_CORE_CCA_BUSY); + if(!is_receiving_packet) { + /* Clear the modem sync flag */ + ti_lib_rfc_hw_int_clear(RFC_DBELL_RFHWIFG_MDMSOFT); + } } - return 1; + return is_receiving_packet; } /*---------------------------------------------------------------------------*/ static int @@ -881,9 +964,12 @@ pending_packet(void) /* Go through all RX buffers and check their status */ do { - if(entry->status == DATA_ENTRY_STATUS_FINISHED) { - rv += 1; - process_poll(&rf_core_process); + if(entry->status == DATA_ENTRY_STATUS_FINISHED + || entry->status == DATA_ENTRY_STATUS_BUSY) { + rv = 1; + if(!rf_core_poll_mode) { + process_poll(&rf_core_process); + } } entry = (rfc_dataEntry_t *)entry->pNextEntry; @@ -904,18 +990,18 @@ on(void) return RF_CORE_CMD_OK; } - /* - * Request the HF XOSC as the source for the HF clock. Needed before we can - * use the FS. This will only request, it will _not_ perform the switch. - */ - oscillators_request_hf_xosc(); - if(rf_is_on()) { PRINTF("on: We were on. PD=%u, RX=0x%04x \n", rf_core_is_accessible(), smartrf_settings_cmd_prop_rx_adv.status); return RF_CORE_CMD_OK; } + /* + * Request the HF XOSC as the source for the HF clock. Needed before we can + * use the FS. This will only request, it will _not_ perform the switch. + */ + oscillators_request_hf_xosc(); + if(!rf_core_is_accessible()) { if(rf_core_power_up() != RF_CORE_CMD_OK) { PRINTF("on: rf_core_power_up() failed\n"); @@ -958,7 +1044,7 @@ on(void) } } - rf_core_setup_interrupts(false); + rf_core_setup_interrupts(); init_rx_buffers(); @@ -985,6 +1071,9 @@ on(void) static int off(void) { + int i; + rfc_dataEntry_t *entry; + /* * If we are in the middle of a BLE operation, we got called by ContikiMAC * from within an interrupt context. Abort, but pretend everything is OK. @@ -998,15 +1087,39 @@ off(void) ENERGEST_OFF(ENERGEST_TYPE_LISTEN); +#if !CC2650_FAST_RADIO_STARTUP /* Switch HF clock source to the RCOSC to preserve power */ oscillators_switch_to_hf_rc(); +#endif /* We pulled the plug, so we need to restore the status manually */ smartrf_settings_cmd_prop_rx_adv.status = RF_CORE_RADIO_OP_STATUS_IDLE; + /* + * Just in case there was an ongoing RX (which started after we begun the + * shutdown sequence), we don't want to leave the buffer in state == ongoing + */ + for(i = 0; i < PROP_MODE_RX_BUF_CNT; i++) { + entry = (rfc_dataEntry_t *)rx_buf[i]; + if(entry->status == DATA_ENTRY_STATUS_BUSY) { + entry->status = DATA_ENTRY_STATUS_PENDING; + } + } + return RF_CORE_CMD_OK; } /*---------------------------------------------------------------------------*/ +/* Enable or disable CCA before sending */ +static radio_result_t +set_send_on_cca(uint8_t enable) +{ + if(enable) { + /* this driver does not have support for CCA on Tx */ + return RADIO_RESULT_NOT_SUPPORTED; + } + return RADIO_RESULT_OK; +} +/*---------------------------------------------------------------------------*/ static radio_result_t get_value(radio_param_t param, radio_value_t *value) { @@ -1022,6 +1135,15 @@ get_value(radio_param_t param, radio_value_t *value) case RADIO_PARAM_CHANNEL: *value = (radio_value_t)get_channel(); return RADIO_RESULT_OK; + case RADIO_PARAM_RX_MODE: + *value = 0; + if(rf_core_poll_mode) { + *value |= RADIO_RX_MODE_POLL_MODE; + } + return RADIO_RESULT_OK; + case RADIO_PARAM_TX_MODE: + *value = 0; + return RADIO_RESULT_OK; case RADIO_PARAM_TXPOWER: *value = get_tx_power(); return RADIO_RESULT_OK; @@ -1031,7 +1153,7 @@ get_value(radio_param_t param, radio_value_t *value) case RADIO_PARAM_RSSI: *value = get_rssi(); - if(*value == RF_CMD_CCA_REQ_RSSI_UNKNOWN) { + if(*value == RF_CORE_CMD_CCA_REQ_RSSI_UNKNOWN) { return RADIO_RESULT_ERROR; } else { return RADIO_RESULT_OK; @@ -1048,6 +1170,28 @@ get_value(radio_param_t param, radio_value_t *value) case RADIO_CONST_TXPOWER_MAX: *value = OUTPUT_POWER_MAX; return RADIO_RESULT_OK; + case RADIO_PARAM_LAST_RSSI: + *value = rf_core_last_rssi; + return RADIO_RESULT_OK; + case RADIO_PARAM_LAST_LINK_QUALITY: + *value = rf_core_last_corr_lqi; + return RADIO_RESULT_OK; + case RADIO_CONST_PHY_OVERHEAD: + /* 2 header bytes, 2 or 4 bytes CRC */ + *value = (radio_value_t)(DOT_4G_PHR_LEN + CRC_LEN); + return RADIO_RESULT_OK; + case RADIO_CONST_BYTE_AIR_TIME: + *value = (radio_value_t)RADIO_BYTE_AIR_TIME; + return RADIO_RESULT_OK; + case RADIO_CONST_DELAY_BEFORE_TX: + *value = (radio_value_t)RADIO_DELAY_BEFORE_TX; + return RADIO_RESULT_OK; + case RADIO_CONST_DELAY_BEFORE_RX: + *value = (radio_value_t)RADIO_DELAY_BEFORE_RX; + return RADIO_RESULT_OK; + case RADIO_CONST_DELAY_BEFORE_DETECT: + *value = (radio_value_t)RADIO_DELAY_BEFORE_DETECT; + return RADIO_RESULT_OK; default: return RADIO_RESULT_NOT_SUPPORTED; } @@ -1056,8 +1200,8 @@ get_value(radio_param_t param, radio_value_t *value) static radio_result_t set_value(radio_param_t param, radio_value_t value) { - uint8_t was_off = 0; radio_result_t rv = RADIO_RESULT_OK; + uint8_t old_poll_mode; switch(param) { case RADIO_PARAM_POWER_MODE: @@ -1087,6 +1231,25 @@ set_value(radio_param_t param, radio_value_t value) set_channel((uint8_t)value); break; + + case RADIO_PARAM_RX_MODE: + if(value & ~(RADIO_RX_MODE_POLL_MODE)) { + return RADIO_RESULT_INVALID_VALUE; + } + + old_poll_mode = rf_core_poll_mode; + rf_core_poll_mode = (value & RADIO_RX_MODE_POLL_MODE) != 0; + if(rf_core_poll_mode == old_poll_mode) { + return RADIO_RESULT_OK; + } + break; + + case RADIO_PARAM_TX_MODE: + if(value & ~(RADIO_TX_MODE_SEND_ON_CCA)) { + return RADIO_RESULT_INVALID_VALUE; + } + return set_send_on_cca((value & RADIO_TX_MODE_SEND_ON_CCA) != 0); + case RADIO_PARAM_TXPOWER: if(value < TX_POWER_DRIVER[get_tx_power_array_last_element()].dbm || value > OUTPUT_POWER_MAX) { @@ -1103,8 +1266,7 @@ set_value(radio_param_t param, radio_value_t value) } return RADIO_RESULT_OK; - case RADIO_PARAM_RX_MODE: - return RADIO_RESULT_OK; + case RADIO_PARAM_CCA_THRESHOLD: rssi_threshold = (int8_t)value; break; @@ -1112,28 +1274,29 @@ set_value(radio_param_t param, radio_value_t value) return RADIO_RESULT_NOT_SUPPORTED; } - /* If we reach here we had no errors. Apply new settings */ + /* If off, the new configuration will be applied the next time radio is started */ if(!rf_is_on()) { - was_off = 1; - if(on() != RF_CORE_CMD_OK) { - PRINTF("set_value: on() failed (2)\n"); - return RADIO_RESULT_ERROR; - } + return RADIO_RESULT_OK; } + /* If we reach here we had no errors. Apply new settings */ if(rx_off_prop() != RF_CORE_CMD_OK) { PRINTF("set_value: rx_off_prop() failed\n"); rv = RADIO_RESULT_ERROR; } - if(soft_on_prop() != RF_CORE_CMD_OK) { - PRINTF("set_value: rx_on_prop() failed\n"); - rv = RADIO_RESULT_ERROR; + /* Restart the radio timer (RAT). + This causes resynchronization between RAT and RTC: useful for TSCH. */ + if(rf_core_restart_rat() != RF_CORE_CMD_OK) { + PRINTF("set_value: rf_core_restart_rat() failed\n"); + /* do not set the error */ + } else { + rf_core_check_rat_overflow(); } - /* If we were off, turn back off */ - if(was_off) { - off(); + if(soft_on_prop() != RF_CORE_CMD_OK) { + PRINTF("set_value: soft_on_prop() failed\n"); + rv = RADIO_RESULT_ERROR; } return rv; @@ -1142,6 +1305,15 @@ set_value(radio_param_t param, radio_value_t value) static radio_result_t get_object(radio_param_t param, void *dest, size_t size) { + if(param == RADIO_PARAM_LAST_PACKET_TIMESTAMP) { + if(size != sizeof(rtimer_clock_t) || !dest) { + return RADIO_RESULT_INVALID_VALUE; + } + *(rtimer_clock_t *)dest = rf_core_last_packet_timestamp; + + return RADIO_RESULT_OK; + } + return RADIO_RESULT_NOT_SUPPORTED; } /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c b/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c index faa8f808b..db3c6adb3 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c +++ b/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c @@ -99,12 +99,37 @@ static rfc_radioOp_t *last_radio_op = NULL; /* A struct holding pointers to the primary mode's abort() and restore() */ static const rf_core_primary_mode_t *primary_mode = NULL; /*---------------------------------------------------------------------------*/ +/* RAT has 32-bit register, overflows once 18 minutes */ +#define RAT_RANGE 4294967296ull +/* approximate value */ +#define RAT_OVERFLOW_PERIOD_SECONDS (60 * 18) + +/* how often to check for the overflow, as a minimum */ +#define RAT_OVERFLOW_TIMER_INTERVAL (CLOCK_SECOND * RAT_OVERFLOW_PERIOD_SECONDS / 3) + /* Radio timer (RAT) offset as compared to the rtimer counter (RTC) */ -int32_t rat_offset = 0; -static bool rat_offset_known = false; +static int32_t rat_offset; +static bool rat_offset_known; + +/* Value during the last read of the RAT register */ +static uint32_t rat_last_value; + +/* For RAT overflow handling */ +static struct ctimer rat_overflow_timer; +static volatile uint32_t rat_overflow_counter; +static rtimer_clock_t rat_last_overflow; + +static void rat_overflow_check_timer_cb(void *); +/*---------------------------------------------------------------------------*/ +volatile int8_t rf_core_last_rssi = RF_CORE_CMD_CCA_REQ_RSSI_UNKNOWN; +volatile uint8_t rf_core_last_corr_lqi = 0; +volatile uint32_t rf_core_last_packet_timestamp = 0; +/*---------------------------------------------------------------------------*/ +/* Are we currently in poll mode? */ +uint8_t rf_core_poll_mode = 0; /*---------------------------------------------------------------------------*/ /* Buffer full flag */ -volatile bool rx_is_full = false; +volatile bool rf_core_rx_is_full = false; /*---------------------------------------------------------------------------*/ PROCESS(rf_core_process, "CC13xx / CC26xx RF driver"); /*---------------------------------------------------------------------------*/ @@ -451,10 +476,10 @@ rf_core_restart_rat(void) } /*---------------------------------------------------------------------------*/ void -rf_core_setup_interrupts(bool poll_mode) +rf_core_setup_interrupts(void) { bool interrupts_disabled; - const uint32_t enabled_irqs = poll_mode ? ENABLED_IRQS_POLL_MODE : ENABLED_IRQS; + const uint32_t enabled_irqs = rf_core_poll_mode ? ENABLED_IRQS_POLL_MODE : ENABLED_IRQS; /* We are already turned on by the caller, so this should not happen */ if(!rf_core_is_accessible()) { @@ -485,19 +510,19 @@ rf_core_setup_interrupts(bool poll_mode) } /*---------------------------------------------------------------------------*/ void -rf_core_cmd_done_en(bool fg, bool poll_mode) +rf_core_cmd_done_en(bool fg) { uint32_t irq = fg ? IRQ_LAST_FG_COMMAND_DONE : IRQ_LAST_COMMAND_DONE; - const uint32_t enabled_irqs = poll_mode ? ENABLED_IRQS_POLL_MODE : ENABLED_IRQS; + const uint32_t enabled_irqs = rf_core_poll_mode ? ENABLED_IRQS_POLL_MODE : ENABLED_IRQS; HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIFG) = enabled_irqs; HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIEN) = enabled_irqs | irq; } /*---------------------------------------------------------------------------*/ void -rf_core_cmd_done_dis(bool poll_mode) +rf_core_cmd_done_dis(void) { - const uint32_t enabled_irqs = poll_mode ? ENABLED_IRQS_POLL_MODE : ENABLED_IRQS; + const uint32_t enabled_irqs = rf_core_poll_mode ? ENABLED_IRQS_POLL_MODE : ENABLED_IRQS; HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIEN) = enabled_irqs; } /*---------------------------------------------------------------------------*/ @@ -544,6 +569,123 @@ rf_core_primary_mode_restore() return RF_CORE_CMD_ERROR; } /*---------------------------------------------------------------------------*/ +uint8_t +rf_core_rat_init(void) +{ + rat_last_value = HWREG(RFC_RAT_BASE + RATCNT); + + ctimer_set(&rat_overflow_timer, RAT_OVERFLOW_TIMER_INTERVAL, + rat_overflow_check_timer_cb, NULL); + + return 1; +} +/*---------------------------------------------------------------------------*/ +uint8_t +rf_core_check_rat_overflow(void) +{ + uint32_t rat_current_value; + uint8_t interrupts_disabled; + + /* Bail out if the RF is not on */ + if(primary_mode == NULL || !primary_mode->is_on()) { + return 0; + } + + interrupts_disabled = ti_lib_int_master_disable(); + + rat_current_value = HWREG(RFC_RAT_BASE + RATCNT); + if(rat_current_value + RAT_RANGE / 4 < rat_last_value) { + /* Overflow detected */ + rat_last_overflow = RTIMER_NOW(); + rat_overflow_counter++; + } + rat_last_value = rat_current_value; + + if(!interrupts_disabled) { + ti_lib_int_master_enable(); + } + + return 1; +} +/*---------------------------------------------------------------------------*/ +static void +rat_overflow_check_timer_cb(void *unused) +{ + uint8_t success = 0; + uint8_t was_off = 0; + + if(primary_mode != NULL) { + + if(!primary_mode->is_on()) { + was_off = 1; + if(NETSTACK_RADIO.on() != RF_CORE_CMD_OK) { + PRINTF("overflow: on() failed\n"); + ctimer_set(&rat_overflow_timer, CLOCK_SECOND, + rat_overflow_check_timer_cb, NULL); + return; + } + } + + success = rf_core_check_rat_overflow(); + + if(was_off) { + NETSTACK_RADIO.off(); + } + } + + if(success) { + /* Retry after half of the interval */ + ctimer_set(&rat_overflow_timer, RAT_OVERFLOW_TIMER_INTERVAL, + rat_overflow_check_timer_cb, NULL); + } else { + /* Retry sooner */ + ctimer_set(&rat_overflow_timer, CLOCK_SECOND, + rat_overflow_check_timer_cb, NULL); + } +} +/*---------------------------------------------------------------------------*/ +uint32_t +rf_core_convert_rat_to_rtimer(uint32_t rat_timestamp) +{ + uint64_t rat_timestamp64; + uint32_t adjusted_overflow_counter; + uint8_t was_off = 0; + + if(primary_mode == NULL) { + PRINTF("rf_core_convert_rat_to_rtimer: not initialized\n"); + return 0; + } + + if(!primary_mode->is_on()) { + was_off = 1; + NETSTACK_RADIO.on(); + } + + rf_core_check_rat_overflow(); + + if(was_off) { + NETSTACK_RADIO.off(); + } + + adjusted_overflow_counter = rat_overflow_counter; + + /* if the timestamp is large and the last oveflow was recently, + assume that the timestamp refers to the time before the overflow */ + if(rat_timestamp > (uint32_t)(RAT_RANGE * 3 / 4)) { + if(RTIMER_CLOCK_LT(RTIMER_NOW(), + rat_last_overflow + RAT_OVERFLOW_PERIOD_SECONDS * RTIMER_SECOND / 4)) { + adjusted_overflow_counter--; + } + } + + /* add the overflowed time to the timestamp */ + rat_timestamp64 = rat_timestamp + RAT_RANGE * adjusted_overflow_counter; + /* correct timestamp so that it refers to the end of the SFD */ + rat_timestamp64 += primary_mode->sfd_timestamp_offset; + + return RADIO_TO_RTIMER(rat_timestamp64 - rat_offset); +} +/*---------------------------------------------------------------------------*/ PROCESS_THREAD(rf_core_process, ev, data) { int len; @@ -582,11 +724,11 @@ cc26xx_rf_cpe1_isr(void) return; } } - + if(HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIFG) & IRQ_RX_BUF_FULL) { PRINTF("\nRF: BUF_FULL\n\n"); /* set a flag that the buffer is full*/ - rx_is_full = true; + rf_core_rx_is_full = true; /* make sure read_frame() will be called to make space in RX buffer */ process_poll(&rf_core_process); /* Clear the IRQ_RX_BUF_FULL interrupt flag by writing zero to bit */ diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.h b/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.h index c97ab0f8a..6cb65672d 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.h +++ b/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.h @@ -133,6 +133,17 @@ typedef struct rf_core_primary_mode_s { * \return RF_CORE_CMD_OK or RF_CORE_CMD_ERROR */ uint8_t (*restore)(void); + + /** + * \brief A pointer to a function that checks if the radio is on + * \return 1 or 0 + */ + uint8_t (*is_on)(void); + + /** + * \brief Offset of the end of SFD when compared to the radio HW-generated timestamp + */ + int16_t sfd_timestamp_offset; } rf_core_primary_mode_t; /*---------------------------------------------------------------------------*/ /* RF Command status constants - Correspond to values in the CMDSTA register */ @@ -263,12 +274,65 @@ typedef struct rf_core_primary_mode_s { /* Radio timer register */ #define RATCNT 0x00000004 /*---------------------------------------------------------------------------*/ -/* Buffer full flag */ -extern volatile bool rx_is_full; +/* Special value returned by CMD_IEEE_CCA_REQ when an RSSI is not available */ +#define RF_CORE_CMD_CCA_REQ_RSSI_UNKNOWN -128 + +/* Used for the return value of channel_clear */ +#define RF_CORE_CCA_CLEAR 1 +#define RF_CORE_CCA_BUSY 0 + +/* Used as an error return value for get_cca_info */ +#define RF_CORE_GET_CCA_INFO_ERROR 0xFF + +/* + * Values of the individual bits of the ccaInfo field in CMD_IEEE_CCA_REQ's + * status struct + */ +#define RF_CORE_CMD_CCA_REQ_CCA_STATE_IDLE 0 /* 00 */ +#define RF_CORE_CMD_CCA_REQ_CCA_STATE_BUSY 1 /* 01 */ +#define RF_CORE_CMD_CCA_REQ_CCA_STATE_INVALID 2 /* 10 */ + +#define RF_CORE_CMD_CCA_REQ_CCA_CORR_IDLE (0 << 4) +#define RF_CORE_CMD_CCA_REQ_CCA_CORR_BUSY (1 << 4) +#define RF_CORE_CMD_CCA_REQ_CCA_CORR_INVALID (3 << 4) +#define RF_CORE_CMD_CCA_REQ_CCA_CORR_MASK (3 << 4) + +#define RF_CORE_CMD_CCA_REQ_CCA_SYNC_BUSY (1 << 6) +/*---------------------------------------------------------------------------*/ +#define RF_CORE_RX_BUF_INCLUDE_CRC 0 +#define RF_CORE_RX_BUF_INCLUDE_RSSI 1 +#define RF_CORE_RX_BUF_INCLUDE_CORR 1 +#define RF_CORE_RX_BUF_INCLUDE_TIMESTAMP 1 +/*---------------------------------------------------------------------------*/ +/* How long to wait for an ongoing ACK TX to finish before starting frame TX */ +#define RF_CORE_TX_TIMEOUT (RTIMER_SECOND >> 11) + +/* How long to wait for the RF to enter RX in rf_cmd_ieee_rx */ +#define RF_CORE_ENTER_RX_TIMEOUT (RTIMER_SECOND >> 10) + +/* How long to wait for the RF to react on CMD_ABORT: around 1 msec */ +#define RF_CORE_TURN_OFF_TIMEOUT (RTIMER_SECOND >> 10) + +/* How long to wait for the RF to finish TX of a packet or an ACK */ +#define RF_CORE_TX_FINISH_TIMEOUT (RTIMER_SECOND >> 7) + /*---------------------------------------------------------------------------*/ /* Make the main driver process visible to mode drivers */ PROCESS_NAME(rf_core_process); /*---------------------------------------------------------------------------*/ +/* Buffer full flag */ +extern volatile bool rf_core_rx_is_full; +/*---------------------------------------------------------------------------*/ +/* RSSI of the last read frame */ +extern volatile int8_t rf_core_last_rssi; +/* Correlation/LQI of the last read frame */ +extern volatile uint8_t rf_core_last_corr_lqi; +/* SFD timestamp of the last read frame, in rtimer ticks */ +extern volatile uint32_t rf_core_last_packet_timestamp; +/*---------------------------------------------------------------------------*/ +/* Are we currently in poll mode? */ +extern uint8_t rf_core_poll_mode; +/*---------------------------------------------------------------------------*/ /** * \brief Check whether the RF core is accessible * \retval RF_CORE_ACCESSIBLE The core is powered and ready for access @@ -383,20 +447,19 @@ uint8_t rf_core_boot(void); /** * \brief Setup RF core interrupts */ -void rf_core_setup_interrupts(bool poll_mode); +void rf_core_setup_interrupts(void); /** * \brief Enable interrupt on command done. * \param fg set true to enable irq on foreground command done and false for * background commands or if not in ieee mode. - * \param poll_mode true if the driver is in poll mode * * This is used within TX routines in order to be able to sleep the CM3 and * wake up after TX has finished * * \sa rf_core_cmd_done_dis() */ -void rf_core_cmd_done_en(bool fg, bool poll_mode); +void rf_core_cmd_done_en(bool fg); /** * \brief Disable the LAST_CMD_DONE and LAST_FG_CMD_DONE interrupts. @@ -405,7 +468,7 @@ void rf_core_cmd_done_en(bool fg, bool poll_mode); * * \sa rf_core_cmd_done_en() */ -void rf_core_cmd_done_dis(bool poll_mode); +void rf_core_cmd_done_dis(void); /** * \brief Returns a pointer to the most recent proto-dependent Radio Op @@ -467,6 +530,22 @@ void rf_core_primary_mode_abort(void); * \brief Abort the currently running primary radio op */ uint8_t rf_core_primary_mode_restore(void); + +/** + * \brief Initialize the RAT to RTC conversion machinery + */ +uint8_t rf_core_rat_init(void); + +/** + * \brief Check if RAT overflow has occured and increment the overflow counter if so + */ +uint8_t rf_core_check_rat_overflow(void); + +/** + * \brief Convert from RAT timestamp to rtimer ticks + */ +uint32_t rf_core_convert_rat_to_rtimer(uint32_t rat_timestamp); + /*---------------------------------------------------------------------------*/ #endif /* RF_CORE_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/os/net/mac/tsch/tsch-const.h b/os/net/mac/tsch/tsch-const.h index edc989378..d158c802c 100644 --- a/os/net/mac/tsch/tsch-const.h +++ b/os/net/mac/tsch/tsch-const.h @@ -77,9 +77,7 @@ /* The approximate number of slots per second */ #define TSCH_SLOTS_PER_SECOND (1000000 / tsch_timing_us[tsch_ts_timeslot_length]) -/* Calculate packet tx/rx duration in rtimer ticks based on sent - * packet len in bytes with 802.15.4 250kbps data rate. - * One byte = 32us. Add two bytes for CRC and one for len field */ +/* Calculate packet tx/rx duration in rtimer ticks based on packet length in bytes. */ #define TSCH_PACKET_DURATION(len) US_TO_RTIMERTICKS(RADIO_BYTE_AIR_TIME * ((len) + RADIO_PHY_OVERHEAD)) /* Convert rtimer ticks to clock and vice versa */ From ad03d3a05e29de87b2ef1fdf1b4941e63924b22a Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 13 Oct 2018 16:02:06 +0100 Subject: [PATCH 438/485] Remove obsolete function prototypes --- os/dev/spi.h | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/os/dev/spi.h b/os/dev/spi.h index b7114717f..9dda05b8e 100644 --- a/os/dev/spi.h +++ b/os/dev/spi.h @@ -323,25 +323,6 @@ spi_status_t spi_arch_transfer(const spi_device_t *dev, uint8_t *buf, int rlen, int ignore_len); -/** - * \brief Selects an SPI device - * \param dev An SPI device configuration that specifies the CS pin. - * \return SPI return code - * - * Clears the CS pin. It should work only if the device has already - * locked the SPI controller. - */ -spi_status_t spi_arch_select(const spi_device_t *dev); - -/** - * \brief Deselects an SPI device - * \param dev An SPI device configuration that specifies the CS pin. - * \return SPI return code - * - * Set the CS pin. Locking the SPI controller is not needed. - */ -spi_status_t spi_arch_deselect(const spi_device_t *dev); - #endif /* SPI_H_ */ /*---------------------------------------------------------------------------*/ /** From 4b7266247e17726e89b1a71768039bb7bf1137a1 Mon Sep 17 00:00:00 2001 From: Atis Elsts Date: Wed, 26 Sep 2018 13:41:38 +0100 Subject: [PATCH 439/485] Add optimization flags for native builds --- arch/cpu/native/Makefile.native | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/cpu/native/Makefile.native b/arch/cpu/native/Makefile.native index d7832d358..30883622d 100644 --- a/arch/cpu/native/Makefile.native +++ b/arch/cpu/native/Makefile.native @@ -20,6 +20,30 @@ endif CFLAGSNO = -Wall -g -I/usr/local/include $(CFLAGSWERROR) CFLAGS += $(CFLAGSNO) +### Are we building with code size optimisations? +SMALL ?= 0 + +# The optimizations on native platform cannot be enabled in GCC (not Clang) versions less than 7.2 +GCC_IS_CLANG := $(shell gcc --version 2> /dev/null | grep clang) +ifneq ($(GCC_IS_CLANG),) + NATIVE_CAN_OPTIIMIZE = 1 +else + GCC_VERSION := $(shell gcc -dumpfullversion -dumpversion | cut -b1-3) + ifeq ($(shell expr $(GCC_VERSION) \>= 7.2), 1) + NATIVE_CAN_OPTIIMIZE = 1 + else + NATIVE_CAN_OPTIIMIZE = 0 + endif +endif + +ifeq ($(NATIVE_CAN_OPTIIMIZE),1) + ifeq ($(SMALL),1) + CFLAGS += -Os + else + CFLAGS += -O2 + endif +endif + ifeq ($(HOST_OS),Darwin) AROPTS = -rc LDFLAGS_WERROR := -Wl,-fatal_warnings From 386e528cc5aad9599ae3b2e5a111d9f4e171da42 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 23 Sep 2018 17:57:47 +0100 Subject: [PATCH 440/485] Harmonise link rule for all cortex CPUs --- arch/cpu/arm/cortex-m/Makefile.cortex-m | 11 +++++++++++ arch/cpu/arm/cortex-m/cm3/Makefile.cm3 | 12 ------------ arch/cpu/arm/cortex-m/cm4/Makefile.cm4 | 10 ---------- arch/cpu/cc26xx-cc13xx/cc26xx.ld | 2 ++ arch/cpu/nrf52832/ld/nrf52-pca10036-sd.ld | 2 ++ arch/cpu/nrf52832/ld/nrf52-pca10040-sd.ld | 2 ++ arch/cpu/nrf52832/ld/nrf52.ld | 2 ++ 7 files changed, 19 insertions(+), 22 deletions(-) diff --git a/arch/cpu/arm/cortex-m/Makefile.cortex-m b/arch/cpu/arm/cortex-m/Makefile.cortex-m index 444df05cd..aebcf2bdd 100644 --- a/arch/cpu/arm/cortex-m/Makefile.cortex-m +++ b/arch/cpu/arm/cortex-m/Makefile.cortex-m @@ -1,3 +1,14 @@ CONTIKI_ARM_DIRS += cortex-m cortex-m/CMSIS +### Build syscalls for newlib +MODULES += os/lib/newlib + +CUSTOM_RULE_LINK = 1 + +.SECONDEXPANSION: + +%.elf: $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(LDSCRIPT) $(TARGET_LIBS) + $(TRACE_LD) + $(Q)$(LD) $(LDFLAGS) ${filter-out $(LDSCRIPT) %.a,$^} ${filter %.a,$^} $(TARGET_LIBFLAGS) -o $@ + include $(CONTIKI)/arch/cpu/arm/Makefile.arm diff --git a/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 b/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 index 6bd76135c..3cf216bfb 100644 --- a/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 +++ b/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 @@ -9,22 +9,10 @@ LDFLAGS += -Wl,-Map=$(CONTIKI_NG_PROJECT_MAP),--cref,--no-warn-mismatch OBJCOPY_FLAGS += --gap-fill 0xff -### Build syscalls for newlib -MODULES += os/lib/newlib - CPU_STARTFILES = ${addprefix $(OBJECTDIR)/,${call oname, $(CPU_START_SOURCEFILES)}} -### Compilation rules -CUSTOM_RULE_LINK = 1 - ### Resolve any potential circular dependencies between the linked libraries ### See: https://stackoverflow.com/questions/5651869/gcc-what-are-the-start-group-and-end-group-command-line-options/5651895 TARGET_LIBFLAGS := -Wl,--start-group $(TARGET_LIBFILES) -lm -Wl,--end-group -.SECONDEXPANSION: - -%.elf: $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(LDSCRIPT) - $(TRACE_LD) - $(Q)$(LD) $(LDFLAGS) ${filter-out $(LDSCRIPT) %.a,$^} ${filter %.a,$^} $(TARGET_LIBFLAGS) -o $@ - include $(CONTIKI)/arch/cpu/arm/cortex-m/Makefile.cortex-m diff --git a/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 b/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 index 110e0697b..b0b592e43 100644 --- a/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 +++ b/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 @@ -9,20 +9,10 @@ LDFLAGS += -Wl,-Map=$(CONTIKI_NG_PROJECT_MAP),--cref,--no-warn-mismatch OBJCOPY_FLAGS += --gap-fill 0xff -### Build syscalls for newlib -MODULES += os/lib/newlib - CPU_STARTFILES = ${addprefix $(OBJECTDIR)/,${call oname, $(CPU_START_SOURCEFILES)}} -### Compilation rules -CUSTOM_RULE_LINK = 1 - ### Resolve any potential circular dependencies between the linked libraries ### See: https://stackoverflow.com/questions/5651869/gcc-what-are-the-start-group-and-end-group-command-line-options/5651895 TARGET_LIBFLAGS := -Wl,--start-group $(TARGET_LIBFILES) -Wl,--end-group -%.elf: $(CPU_STARTFILES) %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(CONTIKI_NG_TARGET_LIB) $(TARGET_LIBS) - $(TRACE_LD) - $(Q)$(LD) $(LDFLAGS) ${filter %.o %.a,$^} $(TARGET_LIBFLAGS) -o $@ - include $(CONTIKI)/arch/cpu/arm/cortex-m/Makefile.cortex-m diff --git a/arch/cpu/cc26xx-cc13xx/cc26xx.ld b/arch/cpu/cc26xx-cc13xx/cc26xx.ld index 649da32cf..4ea422558 100644 --- a/arch/cpu/cc26xx-cc13xx/cc26xx.ld +++ b/arch/cpu/cc26xx-cc13xx/cc26xx.ld @@ -96,6 +96,8 @@ SECTIONS /* These symbols are used by the stack check library. */ _stack = .; _stack_origin = ORIGIN(SRAM) + LENGTH(SRAM); + _heap = _stack; + _eheap = _stack_origin; .ccfg : { diff --git a/arch/cpu/nrf52832/ld/nrf52-pca10036-sd.ld b/arch/cpu/nrf52832/ld/nrf52-pca10036-sd.ld index f3bc5bc43..2afa9e6e2 100644 --- a/arch/cpu/nrf52832/ld/nrf52-pca10036-sd.ld +++ b/arch/cpu/nrf52832/ld/nrf52-pca10036-sd.ld @@ -14,3 +14,5 @@ INCLUDE "nrf5x_common.ld" /* These symbols are used by the stack check library. */ _stack = end; _stack_origin = ORIGIN(RAM) + LENGTH(RAM); +_heap = _stack; +_eheap = _stack_origin; diff --git a/arch/cpu/nrf52832/ld/nrf52-pca10040-sd.ld b/arch/cpu/nrf52832/ld/nrf52-pca10040-sd.ld index 0bc7349e3..b2c747f0a 100644 --- a/arch/cpu/nrf52832/ld/nrf52-pca10040-sd.ld +++ b/arch/cpu/nrf52832/ld/nrf52-pca10040-sd.ld @@ -14,3 +14,5 @@ INCLUDE "nrf5x_common.ld" /* These symbols are used by the stack check library. */ _stack = end; _stack_origin = ORIGIN(RAM) + LENGTH(RAM); +_heap = _stack; +_eheap = _stack_origin; diff --git a/arch/cpu/nrf52832/ld/nrf52.ld b/arch/cpu/nrf52832/ld/nrf52.ld index 87fc9152d..3fead1250 100644 --- a/arch/cpu/nrf52832/ld/nrf52.ld +++ b/arch/cpu/nrf52832/ld/nrf52.ld @@ -14,3 +14,5 @@ INCLUDE "nrf5x_common.ld" /* These symbols are used by the stack check library. */ _stack = end; _stack_origin = ORIGIN(RAM) + LENGTH(RAM); +_heap = _stack; +_eheap = _stack_origin; From db18b43f0fbe401943c0b4131a15e4b7659861de Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 13 Oct 2018 22:07:25 +0100 Subject: [PATCH 441/485] Make sure CONTIKI_BOARD_xyz is defined --- Makefile.include | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Makefile.include b/Makefile.include index 319ae29d7..3578730eb 100644 --- a/Makefile.include +++ b/Makefile.include @@ -46,11 +46,6 @@ UPPERCASE = _ABCDEFGHIJKLMNOPQRSTUVWXYZ_ TARGET_UPPERCASE := ${strip ${shell echo $(TARGET) | sed y!$(LOWERCASE)!$(UPPERCASE)!}} CFLAGS += -DCONTIKI=1 -DCONTIKI_TARGET_$(TARGET_UPPERCASE)=1 CFLAGS += -DCONTIKI_TARGET_STRING=\"$(TARGET)\" -ifneq ($(BOARD),) -TARGET_BOARD_UPPERCASE := ${strip ${shell echo $(BOARD) | sed y!$(LOWERCASE)!$(UPPERCASE)!}} -CFLAGS += -DCONTIKI_BOARD_$(TARGET_BOARD_UPPERCASE)=1 -CFLAGS += -DCONTIKI_BOARD_STRING=\"$(BOARD)\" -endif CFLAGS += -Wno-unused-const-variable @@ -129,6 +124,12 @@ endif # $(BOARD) not empty PLATFORM_ACTION ?= build +ifneq ($(BOARD),) + TARGET_BOARD_UPPERCASE := ${strip ${shell echo $(BOARD) | sed y!$(LOWERCASE)!$(UPPERCASE)!}} + CFLAGS += -DCONTIKI_BOARD_$(TARGET_BOARD_UPPERCASE)=1 + CFLAGS += -DCONTIKI_BOARD_STRING=\"$(BOARD)\" +endif + # Configure MAC layer # The different options From 6a7deb9fc174e8a6b2b8bd53e91795404195ecf2 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 14 Oct 2018 21:05:52 +0100 Subject: [PATCH 442/485] Detect boards automatically in the build-all script --- tests/compile-all/build.sh | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/tests/compile-all/build.sh b/tests/compile-all/build.sh index fcbbd7bd7..81441816e 100755 --- a/tests/compile-all/build.sh +++ b/tests/compile-all/build.sh @@ -40,17 +40,21 @@ # To invoke the building for a specific platform, run: # $ PLATFORMS=zoul ./build.sh # +CONTIKI_NG_TOP_DIR="../.." +EXAMPLES_DIR=$CONTIKI_NG_TOP_DIR/examples if [[ "$PLATFORMS" == "" ]] then - PLATFORMS=`ls ../../arch/platform` + PLATFORMS=`ls $CONTIKI_NG_TOP_DIR/arch/platform` fi if [[ "$MAKEFILES" == "" ]] then - MAKEFILES=`find ../../examples/ -name Makefile` + MAKEFILES=`find $EXAMPLES_DIR -name Makefile` fi +HELLO_WORLD=$EXAMPLES_DIR/hello-world + # Set the make goal the first argument of the script or to "all" if called w/o arguments if [[ $# -gt 0 ]] then @@ -97,22 +101,14 @@ do continue fi - if [[ "$platform" == "srf06-cc26xx" ]] + # Detect all boards for the current platform by calling + # make TARGET=$platform boards + # in the hello-world dir. + BOARDS=`make -s -C $HELLO_WORLD TARGET=$platform boards \ + | grep -v "no boards" | rev | cut -f3- -d" " | rev` + + if [[ -z $BOARDS ]] then - # srf06-cc26xx has multiple boards - BOARDS="srf06/cc26xx srf06/cc13xx launchpad/cc2650 launchpad/cc1310 launchpad/cc1350 sensortag/cc2650 sensortag/cc1350" - elif [[ "$platform" == "simplelink" ]] - then - # SimpleLink has multiple boards - BOARDS="launchpad/cc1310 launchpad/cc1350 launchpad/cc1350-4 launchpad/cc2650 \ - sensortag/cc1350 sensortag/cc2650 srf06/cc13x0 srf06/cc26x0 \ - launchpad/cc1312r1 launchpad/cc1352r1 launchpad/cc1352p1 launchpad/cc1352p-2 launchpad/cc1352p-4 launchpad/cc26x2r1" - elif [[ "$platform" == "zoul" ]] - then - # Zoul has multiple boards - BOARDS="remote-reva remote-revb firefly-reva firefly orion" - else - # Other platforms have just a single board BOARDS="default" fi From 3b5369cf2a1851a062510e21261e0904704aebba Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Mon, 15 Oct 2018 14:11:59 +0200 Subject: [PATCH 443/485] MQTT parse_publish_vhdr: added missing initialization of topic_pos --- os/net/app-layer/mqtt/mqtt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/os/net/app-layer/mqtt/mqtt.c b/os/net/app-layer/mqtt/mqtt.c index 46a542c3f..e73ddb425 100644 --- a/os/net/app-layer/mqtt/mqtt.c +++ b/os/net/app-layer/mqtt/mqtt.c @@ -872,6 +872,7 @@ parse_publish_vhdr(struct mqtt_connection *conn, /* Read out topic length */ if(conn->in_packet.topic_len_received == 0) { + conn->in_packet.topic_pos = 0; conn->in_packet.topic_len = (input_data_ptr[(*pos)++] << 8); conn->in_packet.byte_counter++; if(*pos >= input_data_len) { From bcebd3afcfbd472dfc76b5f2d4f599bbc42c97ba Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Mon, 15 Oct 2018 14:12:08 +0200 Subject: [PATCH 444/485] MQTT parse_publish_vhdr: added missing check of topic length --- os/net/app-layer/mqtt/mqtt.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/os/net/app-layer/mqtt/mqtt.c b/os/net/app-layer/mqtt/mqtt.c index e73ddb425..9571244d8 100644 --- a/os/net/app-layer/mqtt/mqtt.c +++ b/os/net/app-layer/mqtt/mqtt.c @@ -881,7 +881,11 @@ parse_publish_vhdr(struct mqtt_connection *conn, conn->in_packet.topic_len |= input_data_ptr[(*pos)++]; conn->in_packet.byte_counter++; conn->in_packet.topic_len_received = 1; - + /* Abort if topic is longer than our topic buffer */ + if(conn->in_packet.topic_len > MQTT_MAX_TOPIC_LENGTH) { + DBG("MQTT - topic too long %u/%u\n", conn->in_packet.topic_len, MQTT_MAX_TOPIC_LENGTH); + return; + } DBG("MQTT - Read PUBLISH topic len %i\n", conn->in_packet.topic_len); /* WARNING: Check here if TOPIC fits in payload area, otherwise error */ } From 963c2d57aa63fa5421cf30698485bd4ba20e06aa Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Mon, 15 Oct 2018 15:54:11 +0200 Subject: [PATCH 445/485] Json library: fix a number of potential buffer overflows --- os/lib/json/jsonparse.c | 98 ++++++++++++++++++++++------------------- os/lib/json/jsontree.c | 10 ++++- 2 files changed, 61 insertions(+), 47 deletions(-) diff --git a/os/lib/json/jsonparse.c b/os/lib/json/jsonparse.c index 6277b56c4..941420521 100644 --- a/os/lib/json/jsonparse.c +++ b/os/lib/json/jsonparse.c @@ -32,34 +32,42 @@ #include "jsonparse.h" #include #include +#include /*--------------------------------------------------------------------*/ -static int +static bool push(struct jsonparse_state *state, char c) { - state->stack[state->depth] = c; - state->depth++; - state->vtype = 0; - return state->depth < JSONPARSE_MAX_DEPTH; + if(state->depth < JSONPARSE_MAX_DEPTH) { + state->stack[state->depth] = c; + state->depth++; + state->vtype = 0; + return true; + } else { + return false; + } } /*--------------------------------------------------------------------*/ -static void +static bool modify(struct jsonparse_state *state, char c) { if(state->depth > 0) { state->stack[state->depth - 1] = c; + return true; + } else { + return false; } } /*--------------------------------------------------------------------*/ -static char +static bool pop(struct jsonparse_state *state) { if(state->depth == 0) { - return JSON_TYPE_ERROR; + return false; } state->depth--; state->vtype = state->stack[state->depth]; - return state->stack[state->depth]; + return true; } /*--------------------------------------------------------------------*/ /* will pass by the value and store the start and length of the value for @@ -134,15 +142,11 @@ skip_ws(struct jsonparse_state *state) } } /*--------------------------------------------------------------------*/ -static int +static bool is_atomic(struct jsonparse_state *state) { char v = state->vtype; - if(v == 'N' || v == '"' || v == '0' || v == 'n' || v == 't' || v == 'f') { - return 1; - } else { - return 0; - } + return v == 'N' || v == '"' || v == '0' || v == 'n' || v == 't' || v == 'f'; } /*--------------------------------------------------------------------*/ void @@ -163,6 +167,7 @@ jsonparse_next(struct jsonparse_state *state) char c; char s; char v; + bool ret; skip_ws(state); c = state->json[state->pos]; @@ -173,48 +178,51 @@ jsonparse_next(struct jsonparse_state *state) switch(c) { case '{': if((s == 0 && v == 0) || s == '[' || s == ':') { - push(state, c); - } else { - state->error = JSON_ERROR_UNEXPECTED_OBJECT; - return JSON_TYPE_ERROR; + if(push(state, c)) { + return c; + } } - return c; + state->error = JSON_ERROR_UNEXPECTED_OBJECT; + return JSON_TYPE_ERROR; case '}': if((s == ':' && v != ',' && v != 0 ) || (s == '{' && v == 0)) { - pop(state); - } else { - state->error = JSON_ERROR_UNEXPECTED_END_OF_OBJECT; - return JSON_TYPE_ERROR; + if(pop(state)) { + return c; + } } - return c; + state->error = JSON_ERROR_UNEXPECTED_END_OF_OBJECT; + return JSON_TYPE_ERROR; case ']': if(s == '[' && v != ',') { - pop(state); - } else { - state->error = JSON_ERROR_UNEXPECTED_END_OF_ARRAY; - return JSON_TYPE_ERROR; + if(pop(state)) { + return c; + } } - return c; + state->error = JSON_ERROR_UNEXPECTED_END_OF_ARRAY; + return JSON_TYPE_ERROR; case ':': if(s == '{' && v == 'N') { - modify(state, ':'); + ret = modify(state, ':'); state->vtype = 0; - } else { - state->error = JSON_ERROR_SYNTAX; - return JSON_TYPE_ERROR; + if(ret) { + return jsonparse_next(state); + } } - return jsonparse_next(state); + state->error = JSON_ERROR_SYNTAX; + return JSON_TYPE_ERROR; case ',': if(s == ':' && v != 0) { - modify(state, '{'); + ret = modify(state, '{'); state->vtype = c; + if(ret) { + return c; + } } else if(s == '[') { state->vtype = c; - } else { - state->error = JSON_ERROR_SYNTAX; - return JSON_TYPE_ERROR; + return c; } - return c; + state->error = JSON_ERROR_SYNTAX; + return JSON_TYPE_ERROR; case '"': if((s == 0 && v == 0) || s == '{' || s == '[' || s == ':') { return atomic(state, c = (s == '{' ? JSON_TYPE_PAIR_NAME : c)); @@ -225,12 +233,12 @@ jsonparse_next(struct jsonparse_state *state) return c; case '[': if((s == 0 && v == 0) || s == '[' || s == ':') { - push(state, c); - } else { - state->error = JSON_ERROR_UNEXPECTED_ARRAY; - return JSON_TYPE_ERROR; + if(push(state, c)) { + return c; + } } - return c; + state->error = JSON_ERROR_UNEXPECTED_ARRAY; + return JSON_TYPE_ERROR; case 0: if(v == 0 || state->depth > 0) { state->error = JSON_ERROR_SYNTAX; diff --git a/os/lib/json/jsontree.c b/os/lib/json/jsontree.c index 13d7d8604..259525376 100644 --- a/os/lib/json/jsontree.c +++ b/os/lib/json/jsontree.c @@ -198,7 +198,10 @@ jsontree_print_next(struct jsontree_context *js_ctx) } else { ov = o->values[index]; } - /* TODO check max depth */ + if(js_ctx->depth >= JSONTREE_MAX_DEPTH - 1) { + /* Too deep: return 0 */ + return 0; + } js_ctx->depth++; /* step down to value... */ js_ctx->index[js_ctx->depth] = 0; /* and init index */ js_ctx->values[js_ctx->depth] = ov; @@ -299,7 +302,10 @@ find_next(struct jsontree_context *js_ctx) } else { ov = o->values[index]; } - /* TODO check max depth */ + if(js_ctx->depth >= JSONTREE_MAX_DEPTH - 1) { + /* Too deep: return NULL */ + return NULL; + } js_ctx->depth++; /* step down to value... */ js_ctx->index[js_ctx->depth] = 0; /* and init index */ js_ctx->values[js_ctx->depth] = ov; From f9134b11985729a84c2722a2321de3c9479b13b6 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 16 Oct 2018 09:23:54 +0200 Subject: [PATCH 446/485] Add mising TSCH constants for platforms openmote-cc2528 and cc2538dk --- arch/cpu/cc2538/cc2538-def.h | 8 +++++--- arch/platform/cc2538dk/dev/board.h | 12 ++++++++++++ arch/platform/openmote-cc2538/board.h | 12 ++++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/arch/cpu/cc2538/cc2538-def.h b/arch/cpu/cc2538/cc2538-def.h index 163456a14..defa4ecb0 100644 --- a/arch/cpu/cc2538/cc2538-def.h +++ b/arch/cpu/cc2538/cc2538-def.h @@ -36,11 +36,13 @@ /*---------------------------------------------------------------------------*/ #define RTIMER_ARCH_SECOND 32768 /*---------------------------------------------------------------------------*/ +#define CC2538_PHY_OVERHEAD 3 +#define CC2538_BYTE_AIR_TIME 32 /* 352us from calling transmit() until the SFD byte has been sent */ -#define CC2538_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(352)) +#define CC2538_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(352)) /* 192us as in datasheet but ACKs are not always received, so adjusted to 250us */ -#define CC2538_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(250)) -#define CC2538_DELAY_BEFORE_DETECT 0 +#define CC2538_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(250)) +#define CC2538_DELAY_BEFORE_DETECT 0 /* Frame filtering done in software */ #define TSCH_CONF_HW_FRAME_FILTERING 0 diff --git a/arch/platform/cc2538dk/dev/board.h b/arch/platform/cc2538dk/dev/board.h index 80f036fd7..2540b7ce7 100644 --- a/arch/platform/cc2538dk/dev/board.h +++ b/arch/platform/cc2538dk/dev/board.h @@ -220,6 +220,18 @@ #endif /* #if SPI1_IN_USE */ /** @} */ /*---------------------------------------------------------------------------*/ +/** + * \name CC2538 TSCH configuration + * + * @{ + */ +#define RADIO_PHY_OVERHEAD CC2538_PHY_OVERHEAD +#define RADIO_BYTE_AIR_TIME CC2538_BYTE_AIR_TIME +#define RADIO_DELAY_BEFORE_TX CC2538_DELAY_BEFORE_TX +#define RADIO_DELAY_BEFORE_RX CC2538_DELAY_BEFORE_RX +#define RADIO_DELAY_BEFORE_DETECT CC2538_DELAY_BEFORE_DETECT +/** @} */ +/*---------------------------------------------------------------------------*/ /** * \name Device string used on startup * @{ diff --git a/arch/platform/openmote-cc2538/board.h b/arch/platform/openmote-cc2538/board.h index abb89b8e2..6e2a15e46 100644 --- a/arch/platform/openmote-cc2538/board.h +++ b/arch/platform/openmote-cc2538/board.h @@ -174,6 +174,18 @@ #define I2C_SDA_PIN 4 /** @} */ /*---------------------------------------------------------------------------*/ +/** + * \name CC2538 TSCH configuration + * + * @{ + */ +#define RADIO_PHY_OVERHEAD CC2538_PHY_OVERHEAD +#define RADIO_BYTE_AIR_TIME CC2538_BYTE_AIR_TIME +#define RADIO_DELAY_BEFORE_TX CC2538_DELAY_BEFORE_TX +#define RADIO_DELAY_BEFORE_RX CC2538_DELAY_BEFORE_RX +#define RADIO_DELAY_BEFORE_DETECT CC2538_DELAY_BEFORE_DETECT +/** @} */ +/*---------------------------------------------------------------------------*/ /** * \name Device string used on startup * @{ From 5717fedc13fc0b7fa8d2afdaac736d4a80628c72 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 16 Oct 2018 09:33:50 +0200 Subject: [PATCH 447/485] Add CI compile tests for 6tisch on platforms openmote-cc2538, cc2538dk, and sky --- tests/01-compile-base/Makefile | 2 ++ tests/02-compile-arm-ports-01/Makefile | 2 ++ tests/03-compile-arm-ports-02/Makefile | 2 ++ 3 files changed, 6 insertions(+) diff --git a/tests/01-compile-base/Makefile b/tests/01-compile-base/Makefile index e51ff523b..09f89418d 100644 --- a/tests/01-compile-base/Makefile +++ b/tests/01-compile-base/Makefile @@ -24,6 +24,8 @@ rpl-border-router/sky \ slip-radio/sky \ libs/ipv6-hooks/sky \ nullnet/native \ +nullnet/sky \ +nullnet/sky:MAKE_MAC=MAKE_MAC_TSCH \ mqtt-client/native \ coap/coap-example-client/native \ coap/coap-example-server/native \ diff --git a/tests/02-compile-arm-ports-01/Makefile b/tests/02-compile-arm-ports-01/Makefile index 2ec2ce443..aaebab164 100644 --- a/tests/02-compile-arm-ports-01/Makefile +++ b/tests/02-compile-arm-ports-01/Makefile @@ -89,6 +89,8 @@ platform-specific/cc2538-common/pka/cc2538dk \ hello-world/cc2538dk \ rpl-border-router/cc2538dk \ rpl-border-router/cc2538dk:MAKE_ROUTING=MAKE_ROUTING_RPL_CLASSIC \ +6tisch/simple-node/cc2538dk \ +6tisch/simple-node/cc2538dk:MAKE_WITH_SECURITY=1,MAKE_WITH_ORCHESTRA=1 \ hello-world/nrf52dk \ platform-specific/nrf52dk/coap-demo/coap-server/nrf52dk \ platform-specific/nrf52dk/coap-demo/coap-client/nrf52dk:SERVER_IPV6_EP=ffff \ diff --git a/tests/03-compile-arm-ports-02/Makefile b/tests/03-compile-arm-ports-02/Makefile index 190d36e4d..950888f06 100644 --- a/tests/03-compile-arm-ports-02/Makefile +++ b/tests/03-compile-arm-ports-02/Makefile @@ -68,6 +68,8 @@ libs/ipv6-hooks/openmote-cc2538 \ libs/shell/openmote-cc2538 \ libs/simple-energest/openmote-cc2538 \ libs/deployment/openmote-cc2538 \ +6tisch/simple-node/openmote-cc2538 \ +6tisch/simple-node/openmote-cc2538:MAKE_WITH_SECURITY=1,MAKE_WITH_ORCHESTRA=1 \ TOOLS= From 7ab140c55e9c58c487612f2b2f12bd2bd7690208 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 16 Oct 2018 15:17:54 +0200 Subject: [PATCH 448/485] Added missing 'extern' qualifier to tsch_timing_us --- os/net/mac/tsch/tsch.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/net/mac/tsch/tsch.h b/os/net/mac/tsch/tsch.h index 8590dcb38..db23b4851 100644 --- a/os/net/mac/tsch/tsch.h +++ b/os/net/mac/tsch/tsch.h @@ -158,7 +158,7 @@ extern uint8_t tsch_current_channel; extern uint8_t tsch_hopping_sequence[TSCH_HOPPING_SEQUENCE_MAX_LEN]; extern struct tsch_asn_divisor_t tsch_hopping_sequence_length; /* TSCH timeslot timing (in micro-second) */ -uint16_t tsch_timing_us[tsch_ts_elements_count]; +extern uint16_t tsch_timing_us[tsch_ts_elements_count]; /* TSCH timeslot timing (in rtimer ticks) */ extern rtimer_clock_t tsch_timing[tsch_ts_elements_count]; /* Statistics on the current session */ From d45ee85867c416c3dff3d6462214d4a885d444aa Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 16 Oct 2018 15:19:59 +0200 Subject: [PATCH 449/485] Add CI compile test for TSCH with logging --- tests/03-compile-arm-ports-02/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/03-compile-arm-ports-02/Makefile b/tests/03-compile-arm-ports-02/Makefile index 950888f06..655967e1b 100644 --- a/tests/03-compile-arm-ports-02/Makefile +++ b/tests/03-compile-arm-ports-02/Makefile @@ -28,6 +28,7 @@ storage/antelope-shell/zoul \ 6tisch/simple-node/zoul:MAKE_WITH_ORCHESTRA=1 \ 6tisch/simple-node/zoul:MAKE_WITH_SECURITY=1 \ libs/logging/zoul \ +libs/logging/zoul:MAKE_MAC=MAKE_MAC_TSCH \ 6tisch/etsi-plugtest-2017/zoul:BOARD=remote \ 6tisch/6p-packet/zoul \ 6tisch/sixtop/zoul \ From 1cdd4ffb124f936c499a751ffc750790244148fd Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 14 Oct 2018 17:00:40 +0100 Subject: [PATCH 450/485] Move the help and usage targets to a separate Makefile --- Makefile.help | 29 +++++++++++++++++++++++++++++ Makefile.include | 29 +---------------------------- 2 files changed, 30 insertions(+), 28 deletions(-) create mode 100644 Makefile.help diff --git a/Makefile.help b/Makefile.help new file mode 100644 index 000000000..d8de20c00 --- /dev/null +++ b/Makefile.help @@ -0,0 +1,29 @@ +usage: + @echo "Usage:" + @echo " make [TARGET=(TARGET)] [BOARD=(BOARD)] [DEFINES=(DEFINES)] [PORT=(PORT)] [target]" + @echo "" + @echo "Typical usage:" + @echo " make [TARGET=(TARGET)] [BOARD=(BOARD)] [all]" + @echo "" + @echo " Will build Contiki-NG firmware(s) from the current example dir" + @echo " for platform TARGET, board BOARD." + @echo "" + @echo "Miscellaneous targets:" + @echo " targets Prints list of supported platforms" + @echo " boards Prints a list of supported boards for TARGET" + @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" + @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)" + @echo " login View the serial output of the device connected to PORT" + @echo " serialview Same as login, but prepend serial output with a unix timestamp" + @echo " serialdump same as serialview, but also save the output to a file" + @echo " motelist-all Prints a list of connected devices" + +help: usage diff --git a/Makefile.include b/Makefile.include index 3578730eb..a194274bd 100644 --- a/Makefile.include +++ b/Makefile.include @@ -395,34 +395,7 @@ endif %.flashprof: %.$(TARGET) $(NM) -S -td --size-sort $< | grep -i " [t] " | cut -d' ' -f2,4 -usage: - @echo "Usage:" - @echo " make [TARGET=(TARGET)] [BOARD=(BOARD)] [DEFINES=(DEFINES)] [PORT=(PORT)] [target]" - @echo "" - @echo "Typical usage:" - @echo " make [TARGET=(TARGET)] [BOARD=(BOARD)] [all]" - @echo "" - @echo " Will build Contiki-NG firmware(s) from the current example dir" - @echo " for platform TARGET, board BOARD." - @echo "" - @echo "Miscellaneous targets:" - @echo " targets Prints list of supported platforms" - @echo " boards Prints a list of supported boards for TARGET" - @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" - @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)" - @echo " login View the serial output of the device connected to PORT" - @echo " serialview Same as login, but prepend serial output with a unix timestamp" - @echo " serialdump same as serialview, but also save the output to a file" - -help: usage +include $(CONTIKI)/Makefile.help targets: @ls $(CONTIKI)/arch/platform $(TARGETDIRS) From 882bfd083d1307811fbaaa92eb987aa517eef44a Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 14 Oct 2018 17:02:20 +0100 Subject: [PATCH 451/485] Delete the zolertia-specific motelist --- tools/zolertia/license-bsl.txt | 62 ------ tools/zolertia/motelist-zolertia | 295 ------------------------- tools/zolertia/motelist-zolertia-macos | 75 ------- 3 files changed, 432 deletions(-) delete mode 100644 tools/zolertia/license-bsl.txt delete mode 100755 tools/zolertia/motelist-zolertia delete mode 100755 tools/zolertia/motelist-zolertia-macos diff --git a/tools/zolertia/license-bsl.txt b/tools/zolertia/license-bsl.txt deleted file mode 100644 index e6775e9d7..000000000 --- a/tools/zolertia/license-bsl.txt +++ /dev/null @@ -1,62 +0,0 @@ -Copyright (c) 2001-2003 Chris Liechti - -All Rights Reserved. - -This is the Python license. In short, you can use this product in -commercial and non-commercial applications, modify it, redistribute it. -A notification to the author when you use and/or modify it is welcome. - -TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING THIS SOFTWARE -============================================ - -LICENSE AGREEMENT ------------------ - -1. This LICENSE AGREEMENT is between the copyright holder of this -product, and the Individual or Organization ("Licensee") accessing -and otherwise using this product in source or binary form and its -associated documentation. - -2. Subject to the terms and conditions of this License Agreement, -the copyright holder hereby grants Licensee a nonexclusive, -royalty-free, world-wide license to reproduce, analyze, test, -perform and/or display publicly, prepare derivative works, distribute, -and otherwise use this product alone or in any derivative version, -provided, however, that copyright holders License Agreement and -copyright holders notice of copyright are retained in this product -alone or in any derivative version prepared by Licensee. - -3. In the event Licensee prepares a derivative work that is based on -or incorporates this product or any part thereof, and wants to make -the derivative work available to others as provided herein, then -Licensee hereby agrees to include in any such work a brief summary of -the changes made to this product. - -4. The copyright holder is making this product available to Licensee -on an "AS IS" basis. THE COPYRIGHT HOLDER MAKES NO REPRESENTATIONS -OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT -LIMITATION, THE COPYRIGHT HOLDER MAKES NO AND DISCLAIMS ANY -REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR -ANY PARTICULAR PURPOSE OR THAT THE USE OF THIS PRODUCT WILL -NOT INFRINGE ANY THIRD PARTY RIGHTS. - -5. THE COPYRIGHT HOLDER SHALL NOT BE LIABLE TO LICENSEE OR ANY -OTHER USERS OF THIS PRODUCT FOR ANY INCIDENTAL, SPECIAL, OR -CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, -DISTRIBUTING, OR OTHERWISE USING THIS PRODUCT, OR ANY -DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY -THEREOF. - -6. This License Agreement will automatically terminate upon a -material breach of its terms and conditions. - -7. Nothing in this License Agreement shall be deemed to create any -relationship of agency, partnership, or joint venture between the -copyright holder and Licensee. This License Agreement does not grant -permission to use trademarks or trade names from the copyright holder -in a trademark sense to endorse or promote products or services of -Licensee, or any third party. - -8. By copying, installing or otherwise using this product, Licensee -agrees to be bound by the terms and conditions of this License -Agreement. diff --git a/tools/zolertia/motelist-zolertia b/tools/zolertia/motelist-zolertia deleted file mode 100755 index e5f7da99e..000000000 --- a/tools/zolertia/motelist-zolertia +++ /dev/null @@ -1,295 +0,0 @@ -#!/usr/bin/perl -w -use strict; -# $Id: motelist-z1,v 1.1 2010/08/24 15:48:20 joxe Exp $ -# @author Cory Sharp -# @author Joe Polastre - -my $help = <<'EOF'; -usage: motelist [options] - - $Revision: 1.1 $ - -options: - -h display this help - -c compact format, not pretty but easier for parsing - -f specify the usb-serial file (for smote.cs) - -k kernel version: 2.4, 2.6, auto (default) - -m method to scan usb: procfs, sysfs, auto (default) - -dev_prefix force the device prefix for the serial device - -usb display extra usb information - -b specify which Zolertia board to list (z1, remote, etc) -EOF - -my %Opt = ( - compact => 0, - usb => 0, - board => "", - method => "auto", - kernel => "auto", - dev_prefix => [ "/dev/usb/tts/", "/dev/ttyUSB", "/dev/tts/USB" ], - usbserial => "sudo cat /proc/tty/driver/usbserial |", -); - -while (@ARGV) { - last unless $ARGV[0] =~ /^-/; - my $opt = shift @ARGV; - if( $opt eq "-h" ) { print "$help\n"; exit 0; } - elsif( $opt eq "-c" ) { $Opt{compact} = 1; } - elsif( $opt eq "-f" ) { $Opt{usbserial} = shift @ARGV; } - elsif( $opt eq "-k" ) { $Opt{kernel} = shift @ARGV; } - elsif( $opt eq "-m" ) { $Opt{method} = shift @ARGV; } - elsif( $opt eq "-dev_prefix" ) { $Opt{dev_prefix} = shift @ARGV; } - elsif( $opt eq "-usb" ) { $Opt{usb} = 1; } - elsif( $opt eq "-b" ) { $Opt{board} = shift @ARGV; } - else { print STDERR "$help\nerror, unknown command line option $opt\n"; exit 1; } -} - -if( $Opt{kernel} eq "auto" ) { - $Opt{kernel} = "unknown"; - $Opt{kernel} = $1 if snarf("/proc/version") =~ /\bLinux version (\d+\.\d+)/; -} - -if( $Opt{method} eq "auto" ) { - $Opt{method} = ($Opt{kernel} eq "2.4") ? "procfs" : "sysfs"; -} - -if( $Opt{board} eq "z1" ) { - $Opt{board} = "Zolertia Z1"; -} elsif( $Opt{board} eq "remote" ) { - $Opt{board} = "Zolertia RE-Mote platform"; -} elsif( $Opt{board} eq "firefly" ) { - $Opt{board} = "Zolertia Firefly platform"; -} elsif( $Opt{board} eq "orion" ) { - $Opt{board} = "Zolertia Orion Ethernet router"; -} - -my @devs = $Opt{method} eq "procfs" ? scan_procfs() : scan_sysfs(); -print_motelist( sort { cmp_usbdev($a,$b) } @devs ); - - -# -# SysFS -# -sub scan_sysfs { - - my $tmp = '($_->{UsbVendor}||"") eq "10c4" && ($_->{UsbProduct}||"") eq "ea60"'; - - if($Opt{board}) { - $tmp = '($_->{ProductString}||"") eq $Opt{board} && ' . $tmp - } - - # Scan /sys/bus/usb/drivers/usb for CP210x devices - my @cpdevs = - grep { eval "$tmp" } - map { { - SysPath => $_, - UsbVendor => snarf("$_/idVendor",1), - UsbProduct => snarf("$_/idProduct",1), - ProductString => snarf("$_/product",1), - } } - glob("/sys/bus/usb/drivers/usb/*"); - - # Gather information about each CP210x device - for my $f (@cpdevs) { - my $syspath = $f->{SysPath}; - $f->{InfoSerial} = snarf("$syspath/serial",1); - $f->{InfoManufacturer} = snarf("$syspath/manufacturer",1); - $f->{InfoProduct} = snarf("$syspath/product",1); - $f->{UsbDevNum} = snarf("$syspath/devnum",1); - - my $devstr = readlink($syspath); - if( $devstr =~ m{([^/]+)/usb(\d+)/.*-([^/]+)$} ) { - $f->{UsbPath} = "usb-$1-$3"; - $f->{UsbBusNum} = $2; - } - ($f->{SysDev} = $syspath) =~ s{^.*/}{}; - - my $port = "$syspath/$f->{SysDev}:1.0"; - ($f->{DriverName} = readlink("$port/driver")) =~ s{^.*/}{} if -l "$port/driver"; - ($f->{SerialDevName} = (glob("$port/tty*"),undef)[0]) =~ s{^.*/}{}; - $f->{SerialDevNum} = $1 if $f->{SerialDevName} =~ /(\d+)/; - $f->{SerialDevName} = getSerialDevName( $f->{SerialDevNum} ) || " (none)"; - } - return @cpdevs; -} - - -# -# Scan Procfs -# -sub scan_procfs { - - my $text_devs = snarf("< /proc/bus/usb/devices"); - my $text_serial = snarf($Opt{usbserial}); - - my @usbdevs = map { {parse_usb_devices_text($_)} } - grep { !/^\s*$/ } split /\n+(?=T:)/, $text_devs; - my %usbtree = build_usb_tree( @usbdevs ); - my %usbserialtree = build_usbserial_tree( $text_serial ); - for my $tts ( values %usbserialtree ) { - $usbtree{usbkey($tts->{path})}{usbserial} = $tts if defined $tts->{path}; - } - - my @cpdevs = map { { - UsbVendor => $_->{Vendor}, - UsbProduct => $_->{ProdID}, - InfoManufacturer => $_->{Manufacturer}, - InfoProduct => $_->{Product}, - InfoSerial => $_->{SerialNumber}, - UsbBusNum => $_->{nbus}, - UsbDevNum => $_->{ndev}, - UsbPath => (($Opt{kernel} eq "2.4") ? $_->{usbserial}{path} : $_->{usbpath}), - DriverName => $_->{driver}, - SerialDevNum => $_->{usbserial}{tts}, - SerialDevName => getSerialDevName($_->{usbserial}{tts}) || " (none)", - } } - grep { ($_->{Vendor}||"") eq "0403" && ($_->{ProdID}||"") eq "6001" } - values %usbtree; - - return @cpdevs; -} - -sub build_usb_tree { - my @devs = @_; - my %tree = (); - for my $dev (sort { $a->{Lev} <=> $b->{Lev} } @devs) { - my ($bus,$lev,$prnt) = ( $dev->{Bus}+0, $dev->{Lev}+0, $dev->{Prnt}+0 ); - my $devnum = $dev->{"Dev#"}+0; - $dev->{nbus} = $bus; - $dev->{ndev} = $devnum; - $tree{"bus$bus"} = {} unless exists $tree{"bus$bus"}; - $tree{"bus$bus"}{"dev$devnum"} = $dev; - if( $lev == 0 ) { - $dev->{usbpath} = "usb-$dev->{SerialNumber}"; - } else { - my $sep = ($lev==1) ? "-" : "."; - $dev->{parent} = $tree{"bus$bus"}{"dev$prnt"}; - $dev->{usbpath} = $dev->{parent}{usbpath} . $sep . ($dev->{Port}+1); - } - $tree{usbkey($dev->{usbpath})} = $dev; - } - return %tree; -} - -sub parse_usb_devices_text { - my $text = shift; - $text =~ s/^\S+\s*//gm; - return ($text =~ m/([^\s=]+)=\s*(.*?\S)\s*(?=[^\s=]+=|$)/mg); -} - -sub build_usbserial_tree { - my $text = shift; - my %tree = (); - while( $text =~ /^([^:]+):(.*)/mg ) { - my ($tts,$params) = ($1,$2); - $tree{$tts} = { tts => $tts }; - while ($params =~ m/\s+([^:]+):(?:"([^"]*)"|(\S+))/g) { - $tree{$tts}{$1} = $2||$3; - } - } - return %tree; -} - -sub usbkey { - if( $Opt{kernel} eq "2.4" ) { - (my $key = $_[0]) =~ s/^.*-//; - return $key; - } - return $_[0]; -} - - -# -# getSerialDevName -# -# For each device, force to use dev_prefix if it's not an array. Otherwise, -# assume it's a list of candidate prefixes. Check them and commit to the -# first one that actually exists. -# -sub getSerialDevName { - my $devnum = shift; - my $devname = undef; - if( defined $devnum ) { - if( ref($Opt{dev_prefix}) eq "ARRAY" ) { - $devname = $devnum; - for my $prefix (@{$Opt{dev_prefix}}) { - my $file = $prefix . $devnum; - if( -e $file ) { $devname = $file; last; } - } - } else { - $devname = $Opt{dev_prefix} . $devnum; - } - } - return $devname; -} - - -# -# Print motelist -# -sub print_motelist { - my @devs = @_; - - # If none were found, quit - if( @devs == 0 ) { - print "No devices found.\n"; - return; - } - - # Print a header - if( !$Opt{compact} ) { - if( $Opt{usb} ) { - print << "EOF" unless $Opt{compact}; ---- --- ------------------------ -------------- ---------------- ------------------------------------- -Bus Dev USB Path Reference Device Description ---- --- ------------------------ -------------- ---------------- ------------------------------------- -EOF - } else { - print << "EOF" unless $Opt{compact}; --------------- ---------------- --------------------------------------------- -Reference Device Description --------------- ---------------- --------------------------------------------- -EOF - } - } - - # Print the usb information - for my $dev (sort { cmp_usbdev($a,$b) } @devs) { - my $desc = join( " ", $dev->{InfoManufacturer}||"", $dev->{InfoProduct}||"" ) || " (none)"; - my @output = ( $dev->{InfoSerial}||" (none)", $dev->{SerialDevName}, $desc ); - @output = ( $dev->{UsbBusNum}, $dev->{UsbDevNum}, $dev->{UsbPath}, @output ) if $Opt{usb}; - if( $Opt{compact} ) { - print join(",",@output) . "\n"; - } else { - printf( ($Opt{usb}?"%3d %3d %-24s ":"")."%-14s %-16s %s\n", @output ); - } - } -} - - -# -# Cmp Usbdev's -# -sub cmp_usbdev { - my ($a,$b) = @_; - if( defined $a->{SerialDevNum} ) { - if( defined $b->{SerialDevNum} ) { - return $a->{SerialDevNum} <=> $b->{SerialDevNum}; - } - return -1; - } - return 1 if defined $b->{SerialDevNum}; - return ($a->{InfoSerial}||"") cmp ($b->{InfoSerial}||""); -} - -# -# Read a file in -# -sub snarf { - open my $fh, $_[0] or return undef; - my $text = do{local $/;<$fh>}; - close $fh; - $text =~ s/\s+$// if $_[1]; - return $text; -} - diff --git a/tools/zolertia/motelist-zolertia-macos b/tools/zolertia/motelist-zolertia-macos deleted file mode 100755 index 526b4887e..000000000 --- a/tools/zolertia/motelist-zolertia-macos +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/perl -w -use strict; - -my $help = <<'EOF'; -usage: motelist [options] - -options: - -h display this help - -c compact format, not pretty but easier for parsing -EOF - -my %Opt = ( - compact => 0, - dev_prefix => [ "/dev/tty.SLAB" ], -); - -while (@ARGV) { - last unless $ARGV[0] =~ /^-/; - my $opt = shift @ARGV; - if( $opt eq "-h" ) { print "$help\n"; exit 0; } - elsif( $opt eq "-c" ) { $Opt{compact} = 1; } - else { print STDERR "$help\nerror, unknown command line option $opt\n"; exit 1; } -} - -print_motelist( scan_dev() ); - -# -# Scan /dev for tty.SLAB* -# -sub scan_dev { - my @devs; - foreach (`ls /dev/tty.SLAB* 2>&1`) { - my($dev, $serial) = /(\/dev\/tty.SLAB(\S+))/; - if ($serial ne "*:") { - my $d; - $d->{"InfoSerial"} = $serial; - $d->{"SerialDevName"} = $dev; - push(@devs, $d); - } - } - return @devs; -} - - -# -# Print motelist -# -sub print_motelist { - my @devs = @_; - - # If none were found, quit - if( @devs == 0 ) { - #print "No devices found.\n"; - return; - } - - # Print a header - if( !$Opt{compact} ) { - print << "EOF" unless $Opt{compact}; -Reference Device Description ----------- --------------------------- --------------------------------------- -EOF - } - - # Print the usb information - for my $dev (@devs) { - my $desc = "(none)"; - my @output = ( $dev->{"InfoSerial"}, $dev->{"SerialDevName"}, $desc ); - if( $Opt{compact} ) { - print join(",",@output) . "\n"; - } else { - printf( "%-10s %-27s %s\n", @output ); - } - } -} From 5ec90633140e65cc28457995a5947ba7a3e6009f Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 14 Oct 2018 17:02:59 +0100 Subject: [PATCH 452/485] Add board search strings for Zolertia devices --- arch/platform/zoul/firefly-reva/Makefile.firefly-reva | 2 +- arch/platform/zoul/firefly/Makefile.firefly | 2 +- arch/platform/zoul/orion/Makefile.orion | 2 +- arch/platform/zoul/remote-reva/Makefile.remote-reva | 2 +- arch/platform/zoul/remote-revb/Makefile.remote-revb | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/platform/zoul/firefly-reva/Makefile.firefly-reva b/arch/platform/zoul/firefly-reva/Makefile.firefly-reva index afecf9fa5..bfbcb03fb 100644 --- a/arch/platform/zoul/firefly-reva/Makefile.firefly-reva +++ b/arch/platform/zoul/firefly-reva/Makefile.firefly-reva @@ -1,2 +1,2 @@ -MOTELIST_ZOLERTIA = firefly +MOTELIST_ZOLERTIA := Firefly BOARD_SOURCEFILES += board.c diff --git a/arch/platform/zoul/firefly/Makefile.firefly b/arch/platform/zoul/firefly/Makefile.firefly index afecf9fa5..bfbcb03fb 100644 --- a/arch/platform/zoul/firefly/Makefile.firefly +++ b/arch/platform/zoul/firefly/Makefile.firefly @@ -1,2 +1,2 @@ -MOTELIST_ZOLERTIA = firefly +MOTELIST_ZOLERTIA := Firefly BOARD_SOURCEFILES += board.c diff --git a/arch/platform/zoul/orion/Makefile.orion b/arch/platform/zoul/orion/Makefile.orion index ebc1bdad4..b7313afc0 100644 --- a/arch/platform/zoul/orion/Makefile.orion +++ b/arch/platform/zoul/orion/Makefile.orion @@ -1,4 +1,4 @@ -MOTELIST_ZOLERTIA = orion +MOTELIST_ZOLERTIA := Orion MODULES += arch/dev/enc28j60 CC2538_ENC28J60_ARCH ?= gpio ifeq ($(WITH_IP64),1) diff --git a/arch/platform/zoul/remote-reva/Makefile.remote-reva b/arch/platform/zoul/remote-reva/Makefile.remote-reva index fcccdf0f4..ec4095265 100644 --- a/arch/platform/zoul/remote-reva/Makefile.remote-reva +++ b/arch/platform/zoul/remote-reva/Makefile.remote-reva @@ -1,4 +1,4 @@ -MOTELIST_ZOLERTIA = remote +MOTELIST_ZOLERTIA := RE-Mote BOARD_SOURCEFILES += board.c antenna-sw.c mmc-arch.c rtcc.c power-mgmt.c MODULES += os/lib/fs/fat os/lib/fs/fat/option arch/platform/zoul/fs/fat arch/dev/disk/mmc diff --git a/arch/platform/zoul/remote-revb/Makefile.remote-revb b/arch/platform/zoul/remote-revb/Makefile.remote-revb index fcccdf0f4..ec4095265 100644 --- a/arch/platform/zoul/remote-revb/Makefile.remote-revb +++ b/arch/platform/zoul/remote-revb/Makefile.remote-revb @@ -1,4 +1,4 @@ -MOTELIST_ZOLERTIA = remote +MOTELIST_ZOLERTIA := RE-Mote BOARD_SOURCEFILES += board.c antenna-sw.c mmc-arch.c rtcc.c power-mgmt.c MODULES += os/lib/fs/fat os/lib/fs/fat/option arch/platform/zoul/fs/fat arch/dev/disk/mmc From 470ac26c4e9e7b3fa5aeed0841dba37092f300e8 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 14 Oct 2018 17:03:55 +0100 Subject: [PATCH 453/485] Add the motelist-all target - common for all embedded platforms --- Makefile.embedded | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Makefile.embedded b/Makefile.embedded index 4654626c4..e6841926b 100644 --- a/Makefile.embedded +++ b/Makefile.embedded @@ -3,6 +3,9 @@ # Future extensions to the build system that are of a similar nature (for # embedded devices only), can be achieved by extending this Makefile here. +### +### Targets using the tools/serial-io +### RLWRAPGOALS = login serialdump serialview .PHONY: $(RLWRAPGOALS) @@ -31,3 +34,14 @@ serialview: $(SERIAL_DUMP_BIN) login: $(SERIAL_DUMP_BIN) $(SERIALDUMP) -b$(BAUDRATE) $(PORT) + +### +### Targets using tools/motelist +### +CONTIKI_NG_MOTELIST_DIR = $(TOOLS_DIR)/motelist +CONTIKI_NG_MOTELIST = python $(CONTIKI_NG_MOTELIST_DIR)/motelist.py + +.PHONY: motelist-all + +motelist-all: + $(CONTIKI_NG_MOTELIST) From 95cebf10bcad42e1c1b2ff111266966e7f5bfe1b Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 14 Oct 2018 17:10:50 +0100 Subject: [PATCH 454/485] Change platform zoul to use the new motelist --- arch/platform/zoul/Makefile.zoul | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/arch/platform/zoul/Makefile.zoul b/arch/platform/zoul/Makefile.zoul index 38b86fd13..938abe035 100644 --- a/arch/platform/zoul/Makefile.zoul +++ b/arch/platform/zoul/Makefile.zoul @@ -46,23 +46,8 @@ MODULES += arch/dev/cc1200 arch/dev/rgb-led os/storage/cfs BSL = $(CONTIKI)/tools/cc2538-bsl/cc2538-bsl.py -### Use the specific Zoul subplatform to query for connected devices -ifdef MOTELIST_ZOLERTIA - MOTELIST_FLAGS += -b $(MOTELIST_ZOLERTIA) -endif - -### Detect if a mote is connected over serial port -ifeq ($(HOST_OS),Darwin) - USBDEVPREFIX= - MOTELIST := $(CONTIKI)/tools/zolertia/motelist-zolertia-macos - MOTES := $(shell $(MOTELIST) -c 2>&- | cut -f 2 -d ,) -else -### If we are not running under Mac, we assume Linux - USBDEVPREFIX= - 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+)-);') -endif +MOTES := $(shell python $(TOOLS_DIR)/motelist/motelist.py --omit-header \ + | grep $(MOTELIST_ZOLERTIA) | cut -f1 -d " ") ### If PORT is defined, override to keep backward compatibility ifdef PORT @@ -81,7 +66,8 @@ endif ### Variable that expands into a pattern rule to upload to a given MOTE. ### Requires $(MOTE) to be defined -### $$$$ Double escapes $s that need to be passed to the shell - once for when make parses UPLOAD_RULE, and once for when the expanded rule is parsed by make. +### $$$$ Double escapes $s that need to be passed to the shell - once for when +### make parses UPLOAD_RULE, and once for when the expanded rule is parsed by make. define UPLOAD_RULE %.$(MOTE): %.bin %.elf @echo "Flashing $(MOTE)" @@ -94,10 +80,8 @@ endef ### Create an upload rule for every MOTE connected $(foreach MOTE,$(MOTES),$(eval $(UPLOAD_RULE))) -motelist: - $(MOTELIST) -zoul-motelist: - $(MOTELIST) $(MOTELIST_FLAGS) +.PHONY: zoul-motes + zoul-motes: @echo $(MOTES) From fc8ccac5604c6c1e8b4c4079ced2dd9b15d8b7f8 Mon Sep 17 00:00:00 2001 From: Toshio Ito Date: Thu, 18 Oct 2018 16:05:45 +0900 Subject: [PATCH 455/485] tsch: report MAC_TX_ERR if prepare() fails Before this fix, uninitialized mac_tx_status was reported in this case. --- os/net/mac/tsch/tsch-slot-operation.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/os/net/mac/tsch/tsch-slot-operation.c b/os/net/mac/tsch/tsch-slot-operation.c index 841dee07f..5fbf86013 100644 --- a/os/net/mac/tsch/tsch-slot-operation.c +++ b/os/net/mac/tsch/tsch-slot-operation.c @@ -643,6 +643,8 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t)) mac_tx_status = MAC_TX_ERR; } } + }else { + mac_tx_status = MAC_TX_ERR; } } From 1cfe9df73e50a013a0baf9577412be6dc0975392 Mon Sep 17 00:00:00 2001 From: Atis Elsts Date: Fri, 31 Aug 2018 16:45:50 +0100 Subject: [PATCH 456/485] CC26xx RF: in polling mode, disable the CPE0 radio interrupt completely --- arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c b/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c index db3c6adb3..7e638509d 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c +++ b/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c @@ -512,9 +512,13 @@ rf_core_setup_interrupts(void) void rf_core_cmd_done_en(bool fg) { - uint32_t irq = fg ? IRQ_LAST_FG_COMMAND_DONE : IRQ_LAST_COMMAND_DONE; + uint32_t irq = 0; const uint32_t enabled_irqs = rf_core_poll_mode ? ENABLED_IRQS_POLL_MODE : ENABLED_IRQS; + if(!rf_core_poll_mode) { + irq = fg ? IRQ_LAST_FG_COMMAND_DONE : IRQ_LAST_COMMAND_DONE; + } + HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIFG) = enabled_irqs; HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIEN) = enabled_irqs | irq; } From 093caff1d3d69385ff44ef51cd6b185869ef0e8b Mon Sep 17 00:00:00 2001 From: Atis Elsts Date: Thu, 18 Oct 2018 18:16:54 +0100 Subject: [PATCH 457/485] CC13x0/CC26x0 building: also fail with descriptive error message when cc13xxware/cc26xxware exists, but is empty --- arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx b/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx index 00f9ae232..592ddfbd8 100644 --- a/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx +++ b/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx @@ -1,8 +1,8 @@ CPU_ABS_PATH = arch/cpu/cc26xx-cc13xx TI_XXWARE = $(CONTIKI_CPU)/$(TI_XXWARE_PATH) -ifeq (,$(wildcard $(TI_XXWARE))) - $(warning $(TI_XXWARE) does not exist.) +ifeq (,$(wildcard $(TI_XXWARE)/*)) + $(warning $(TI_XXWARE) does not exist or is empty.) $(warning Did you run 'git submodule update --init' ?) $(error "") endif From 9bb648f92223ed00f70fa297561b2b3befdea612 Mon Sep 17 00:00:00 2001 From: Alex Raimondi Date: Thu, 18 Oct 2018 17:15:27 +0200 Subject: [PATCH 458/485] Fixed all-timers example application --- examples/libs/timers/all-timers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/libs/timers/all-timers.c b/examples/libs/timers/all-timers.c index 2a1f27b28..bb6dfed90 100644 --- a/examples/libs/timers/all-timers.c +++ b/examples/libs/timers/all-timers.c @@ -79,7 +79,7 @@ PROCESS_THREAD(timer_process, ev, data) PROCESS_BEGIN(); ctimer_set(&timer_ctimer, CLOCK_SECOND, ctimer_callback, NULL); - rtimer_set(&timer_rtimer, RTIMER_NOW() + CLOCK_SECOND / 2, 0, + rtimer_set(&timer_rtimer, RTIMER_NOW() + RTIMER_SECOND / 2, 0, rtimer_callback, NULL); while(1) { From 9faa834f572002241f67ad1a53e47ef6459ced3d Mon Sep 17 00:00:00 2001 From: Atis Elsts Date: Wed, 29 Aug 2018 22:28:51 +0100 Subject: [PATCH 459/485] Allow the user to configure COAP_CONF_OBSERVE_REFRESH_INTERVAL and allow it to be zero --- os/net/app-layer/coap/coap-conf.h | 4 +++- os/net/app-layer/coap/coap-observe.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/os/net/app-layer/coap/coap-conf.h b/os/net/app-layer/coap/coap-conf.h index 911017ed8..5b610dca3 100644 --- a/os/net/app-layer/coap/coap-conf.h +++ b/os/net/app-layer/coap/coap-conf.h @@ -99,7 +99,9 @@ #endif /* COAP_MAX_OBSERVERS */ /* Interval in notifies in which NON notifies are changed to CON notifies to check client. */ -#ifndef COAP_OBSERVE_REFRESH_INTERVAL +#ifdef COAP_CONF_OBSERVE_REFRESH_INTERVAL +#define COAP_OBSERVE_REFRESH_INTERVAL COAP_CONF_OBSERVE_REFRESH_INTERVAL +#else #define COAP_OBSERVE_REFRESH_INTERVAL 20 #endif /* COAP_OBSERVE_REFRESH_INTERVAL */ diff --git a/os/net/app-layer/coap/coap-observe.c b/os/net/app-layer/coap/coap-observe.c index d6ef3887e..3574acac4 100644 --- a/os/net/app-layer/coap/coap-observe.c +++ b/os/net/app-layer/coap/coap-observe.c @@ -244,7 +244,9 @@ coap_notify_observers_sub(coap_resource_t *resource, const char *subpath) /*TODO implement special transaction for CON, sharing the same buffer to allow for more observers */ if((transaction = coap_new_transaction(coap_get_mid(), &obs->endpoint))) { - if(obs->obs_counter % COAP_OBSERVE_REFRESH_INTERVAL == 0) { + /* if COAP_OBSERVE_REFRESH_INTERVAL is zero, never send observations as confirmable messages */ + if(COAP_OBSERVE_REFRESH_INTERVAL != 0 + && (obs->obs_counter % COAP_OBSERVE_REFRESH_INTERVAL == 0)) { LOG_DBG(" Force Confirmable for\n"); notification->type = COAP_TYPE_CON; } From cb962855a46dba83537a9f89bb960c5bcdb79b88 Mon Sep 17 00:00:00 2001 From: Toshio Ito Date: Fri, 19 Oct 2018 22:32:52 +0900 Subject: [PATCH 460/485] fix code style for else --- os/net/mac/tsch/tsch-slot-operation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/net/mac/tsch/tsch-slot-operation.c b/os/net/mac/tsch/tsch-slot-operation.c index 5fbf86013..a801bc92e 100644 --- a/os/net/mac/tsch/tsch-slot-operation.c +++ b/os/net/mac/tsch/tsch-slot-operation.c @@ -643,7 +643,7 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t)) mac_tx_status = MAC_TX_ERR; } } - }else { + } else { mac_tx_status = MAC_TX_ERR; } } From 995a076262f924524b7423aa8d32812d968264ec Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 20 Oct 2018 15:24:16 +0100 Subject: [PATCH 461/485] Explicitly set noninteractive frontent --- tools/docker/Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 9d15704ac..6c84ecabf 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -1,5 +1,7 @@ FROM 32bit/ubuntu:16.04 +ENV DEBIAN_FRONTEND noninteractive + # Tools RUN apt-get update && \ apt-get install -y --no-install-recommends \ From 20fa52997ca02626019f091608c9a604515be2dd Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 20 Oct 2018 15:25:02 +0100 Subject: [PATCH 462/485] Quiet wget --- tools/docker/Dockerfile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 6c84ecabf..38c04a90c 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -11,21 +11,21 @@ RUN apt-get update && \ && 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 && \ +RUN wget -nv https://launchpad.net/gcc-arm-embedded/5.0/5-2015-q4-major/+download/gcc-arm-none-eabi-5_2-2015q4-20151219-linux.tar.bz2 && \ tar xjf gcc-arm-none-eabi-5_2-2015q4-20151219-linux.tar.bz2 -C /tmp/ && \ cp -f -r /tmp/gcc-arm-none-eabi-5_2-2015q4/* /usr/local/ && \ rm -rf /tmp/gcc-arm-none-eabi-* gcc-arm-none-eabi-*-linux.tar.bz2 # Install msp430 toolchain -RUN wget http://simonduq.github.io/resources/mspgcc-4.7.2-compiled.tar.bz2 && \ +RUN wget -nv http://simonduq.github.io/resources/mspgcc-4.7.2-compiled.tar.bz2 && \ tar xjf mspgcc*.tar.bz2 -C /tmp/ && \ cp -f -r /tmp/msp430/* /usr/local/ && \ rm -rf /tmp/msp430 mspgcc*.tar.bz2 # Install NXP toolchain (partial, with binaries excluded. Download from nxp.com) -RUN wget http://simonduq.github.io/resources/ba-elf-gcc-4.7.4-part1.tar.bz2 && \ - wget http://simonduq.github.io/resources/ba-elf-gcc-4.7.4-part2.tar.bz2 && \ - wget http://simonduq.github.io/resources/jn516x-sdk-4163-1416.tar.bz2 && \ +RUN wget -nv http://simonduq.github.io/resources/ba-elf-gcc-4.7.4-part1.tar.bz2 && \ + wget -nv http://simonduq.github.io/resources/ba-elf-gcc-4.7.4-part2.tar.bz2 && \ + wget -nv http://simonduq.github.io/resources/jn516x-sdk-4163-1416.tar.bz2 && \ mkdir /tmp/jn516x-sdk /tmp/ba-elf-gcc && \ tar xjf jn516x-sdk-*.tar.bz2 -C /tmp/jn516x-sdk && \ tar xjf ba-elf-gcc-*part1.tar.bz2 -C /tmp/ba-elf-gcc && \ @@ -37,7 +37,7 @@ RUN wget http://simonduq.github.io/resources/ba-elf-gcc-4.7.4-part1.tar.bz2 && \ ENV PATH="/usr/ba-elf-gcc/bin:${PATH}" ## Install nRF52 SDK -RUN wget https://developer.nordicsemi.com/nRF5_IoT_SDK/nRF5_IoT_SDK_v0.9.x/nrf5_iot_sdk_3288530.zip && \ +RUN wget -nv https://developer.nordicsemi.com/nRF5_IoT_SDK/nRF5_IoT_SDK_v0.9.x/nrf5_iot_sdk_3288530.zip && \ mkdir /usr/nrf52-sdk && \ unzip nrf5_iot_sdk_3288530.zip -d /usr/nrf52-sdk && \ rm nrf5_iot_sdk_3288530.zip From d756cb6e48abad103752baf307bbec65b132fb65 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 20 Oct 2018 15:25:14 +0100 Subject: [PATCH 463/485] Quiet git clone --- tools/docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 38c04a90c..27e476e61 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -90,7 +90,7 @@ RUN sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E && sudo apt-get clean # Download, build and install Renode -RUN git clone https://github.com/renode/renode.git \ +RUN git clone --quiet https://github.com/renode/renode.git \ && cd ${HOME}/renode \ && git checkout v1.3 \ && ./build.sh From 3c9eafc83b7f53f43002e44647ecf60ed0a84b05 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 20 Oct 2018 15:25:40 +0100 Subject: [PATCH 464/485] Quiet pip output --- tools/docker/Dockerfile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 27e476e61..e4cb39037 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -46,9 +46,8 @@ ENV NRF52_SDK_ROOT /usr/nrf52-sdk # Install sphinx and sphinx_rtd_theme, required for building and testing the # readthedocs API documentation -RUN pip install --upgrade pip -RUN pip install setuptools -RUN pip install sphinx_rtd_theme sphinx +RUN pip -q install --upgrade pip +RUN pip -q install setuptools && pip -q install sphinx_rtd_theme sphinx # Create user, enable X forwarding, add to group dialout # -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix From 06ad0f26b3c2680e24683f99894e7c971f4a093e Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 20 Oct 2018 15:25:52 +0100 Subject: [PATCH 465/485] Quiet unzip --- tools/docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index e4cb39037..bd6dd4821 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -39,7 +39,7 @@ ENV PATH="/usr/ba-elf-gcc/bin:${PATH}" ## Install nRF52 SDK RUN wget -nv https://developer.nordicsemi.com/nRF5_IoT_SDK/nRF5_IoT_SDK_v0.9.x/nrf5_iot_sdk_3288530.zip && \ mkdir /usr/nrf52-sdk && \ - unzip nrf5_iot_sdk_3288530.zip -d /usr/nrf52-sdk && \ + unzip -q nrf5_iot_sdk_3288530.zip -d /usr/nrf52-sdk && \ rm nrf5_iot_sdk_3288530.zip ENV NRF52_SDK_ROOT /usr/nrf52-sdk From b4684e3d5faec000f46db5e1062f81d565caec01 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 20 Oct 2018 15:26:37 +0100 Subject: [PATCH 466/485] Single docker RUN for all apt- and npm work. Quiet npm and run all of the above without sudo --- tools/docker/Dockerfile | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index bd6dd4821..8b156efb1 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -3,12 +3,20 @@ FROM 32bit/ubuntu:16.04 ENV DEBIAN_FRONTEND noninteractive # Tools -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - build-essential doxygen git wget unzip python-serial python-pip \ - default-jdk ant srecord iputils-tracepath rlwrap \ - mosquitto mosquitto-clients gdb \ - && apt-get clean +RUN 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 && \ + apt-get -qq update && \ + apt-get -qq -y --no-install-recommends install \ + build-essential doxygen git wget unzip python-serial python-pip \ + default-jdk ant srecord iputils-tracepath rlwrap \ + mosquitto mosquitto-clients gdb npm \ + mono-complete gksu libgtk2.0-0 screen uml-utilities gtk-sharp2 \ + libcanberra-gtk-module:i386 \ + && apt-get -qq clean + +# Install coap-cli +RUN npm -q install coap-cli -g \ + && sudo ln -s /usr/bin/nodejs /usr/bin/node # Install ARM toolchain RUN wget -nv https://launchpad.net/gcc-arm-embedded/5.0/5-2015-q4-major/+download/gcc-arm-none-eabi-5_2-2015q4-20151219-linux.tar.bz2 && \ @@ -75,19 +83,6 @@ WORKDIR ${HOME} RUN echo "#!/bin/bash\nant -Dbasedir=${COOJA} -f ${COOJA}/build.xml run" > ${HOME}/cooja && \ chmod +x ${HOME}/cooja -# Install coap-cli -RUN sudo apt-get install -y npm \ - && sudo apt-get clean \ - && 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 --quiet https://github.com/renode/renode.git \ && cd ${HOME}/renode \ From b25e7bedf93a54c2a4b30ba328ee1bd81fe08dff Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 20 Oct 2018 15:52:47 +0100 Subject: [PATCH 467/485] Redirect apt-get stdout to /dev/null --- tools/docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 8b156efb1..634f85ea6 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -11,7 +11,7 @@ RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E03280 default-jdk ant srecord iputils-tracepath rlwrap \ mosquitto mosquitto-clients gdb npm \ mono-complete gksu libgtk2.0-0 screen uml-utilities gtk-sharp2 \ - libcanberra-gtk-module:i386 \ + libcanberra-gtk-module:i386 > /dev/null \ && apt-get -qq clean # Install coap-cli From 08141e6b9b74fff6b7528c3180a6681e7b855f18 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 21 Oct 2018 12:33:58 +0100 Subject: [PATCH 468/485] Sort apt-get install packages, one package per line --- tools/docker/Dockerfile | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 634f85ea6..6eb9dbb17 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -7,11 +7,30 @@ RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E03280 echo "deb http://download.mono-project.com/repo/ubuntu xenial main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list && \ apt-get -qq update && \ apt-get -qq -y --no-install-recommends install \ - build-essential doxygen git wget unzip python-serial python-pip \ - default-jdk ant srecord iputils-tracepath rlwrap \ - mosquitto mosquitto-clients gdb npm \ - mono-complete gksu libgtk2.0-0 screen uml-utilities gtk-sharp2 \ - libcanberra-gtk-module:i386 > /dev/null \ + ant \ + build-essential \ + default-jdk \ + doxygen \ + gdb \ + git \ + gksu \ + gtk-sharp2 \ + iputils-tracepath \ + libcanberra-gtk-module:i386 \ + libgtk2.0-0 \ + mono-complete \ + mosquitto \ + mosquitto-clients \ + npm \ + python-pip \ + python-serial \ + rlwrap \ + screen \ + srecord \ + uml-utilities \ + unzip \ + wget \ + > /dev/null \ && apt-get -qq clean # Install coap-cli From 6d4cddeec104345206bb7ff18731ad5a78cac34d Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 21 Oct 2018 17:13:17 +0100 Subject: [PATCH 469/485] Make the MQTT client example a little more configurable and verbose Suitable for native run testing --- examples/mqtt-client/mqtt-client.c | 5 +++++ examples/mqtt-client/project-conf.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/examples/mqtt-client/mqtt-client.c b/examples/mqtt-client/mqtt-client.c index be3c97cdb..b71a193ea 100644 --- a/examples/mqtt-client/mqtt-client.c +++ b/examples/mqtt-client/mqtt-client.c @@ -47,7 +47,11 @@ #include /*---------------------------------------------------------------------------*/ #define LOG_MODULE "mqtt-client" +#ifdef MQTT_CLIENT_CONF_LOG_LEVEL +#define LOG_LEVEL MQTT_CLIENT_CONF_LOG_LEVEL +#else #define LOG_LEVEL LOG_LEVEL_NONE +#endif /*---------------------------------------------------------------------------*/ /* Controls whether the example will work in IBM Watson IoT platform mode */ #ifdef MQTT_CLIENT_CONF_WITH_IBM_WATSON @@ -305,6 +309,7 @@ pub_handler(const char *topic, uint16_t topic_len, const uint8_t *chunk, } if(strncmp(&topic[10], "leds", 4) == 0) { + LOG_DBG("Received MQTT SUB\n"); if(chunk[0] == '1') { leds_on(LEDS_RED); } else if(chunk[0] == '0') { diff --git a/examples/mqtt-client/project-conf.h b/examples/mqtt-client/project-conf.h index 66ba909ce..6b011f7b0 100644 --- a/examples/mqtt-client/project-conf.h +++ b/examples/mqtt-client/project-conf.h @@ -52,7 +52,9 @@ * devices, set your Org ID here and then make sure you set the correct token * through MQTT_CLIENT_CONF_AUTH_TOKEN. */ +#ifndef MQTT_CLIENT_CONF_ORG_ID #define MQTT_CLIENT_CONF_ORG_ID "quickstart" +#endif /* * The MQTT username. From c2ceaab13b5e38cf9660f12ba955b260bae88a99 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 21 Oct 2018 17:14:17 +0100 Subject: [PATCH 470/485] Add MQTT client execution test --- tests/08-native-runs/02-mqtt-client.sh | 79 ++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100755 tests/08-native-runs/02-mqtt-client.sh diff --git a/tests/08-native-runs/02-mqtt-client.sh b/tests/08-native-runs/02-mqtt-client.sh new file mode 100755 index 000000000..cb1ee937a --- /dev/null +++ b/tests/08-native-runs/02-mqtt-client.sh @@ -0,0 +1,79 @@ +#!/bin/bash +source ../utils.sh + +# Contiki directory +CONTIKI=$1 + +# Example code directory +CODE_DIR=$CONTIKI/examples/mqtt-client/ +CODE=mqtt-client + +CLIENT_LOG=$CODE.log +CLIENT_TESTLOG=$CODE.testlog +CLIENT_ERR=$CODE.err +MOSQ_SUB_LOG=mosquitto_sub.log +MOSQ_SUB_ERR=mosquitto_sub.err + +# Start mosquitto server +echo "Starting mosquitto daemon" +mosquitto &> /dev/null & +MOSQID=$! +sleep 2 + +# Start mosquitto_sub client. Subscribe +echo "Starting mosquitto subscriber" +mosquitto_sub -t iot-2/evt/status/fmt/json > $MOSQ_SUB_LOG 2> $MOSQ_SUB_ERR & +MSUBID=$! +sleep 2 + +# Starting Contiki-NG native node +echo "Starting native node" +make -C $CODE_DIR TARGET=native \ + DEFINES=MQTT_CLIENT_CONF_ORG_ID=\\\"travis-test\\\",MQTT_CLIENT_CONF_LOG_LEVEL=LOG_LEVEL_DBG \ + > make.log 2> make.err +sudo $CODE_DIR/$CODE.native > $CLIENT_LOG 2> $CLIENT_ERR & +CPID=$! + +# The mqtt-client will publish every 30 secs. Wait for 45 +sleep 45 + +# Send a publish to the mqtt client +mosquitto_pub -m "1" -t iot-2/cmd/leds/fmt/json + +echo "Closing native node" +sleep 2 +kill_bg $CPID + +echo "Stopping mosquitto daemon" +kill_bg $MOSQID + +echo "Stopping mosquitto subscriber" +kill_bg $MSUBID + +# Success criteria: +# * mosquitto_sub output not empty +# * mqtt-client.native output contains "MQTT SUB" +SUB_RCV=`grep "MQTT SUB" $CLIENT_LOG` +if [ -s "$MOSQ_SUB_LOG" -a -n "$SUB_RCV" ] +then + cp $CLIENT_LOG $CODE.testlog + printf "%-32s TEST OK\n" "$CODE" | tee $CODE.testlog; +else + echo "==== make.log ====" ; cat make.log; + echo "==== make.err ====" ; cat make.err; + echo "==== $CLIENT_LOG ====" ; cat $CLIENT_LOG; + echo "==== $CLIENT_ERR ====" ; cat $CLIENT_ERR; + echo "==== $MOSQ_SUB_LOG ====" ; cat $MOSQ_SUB_LOG; + echo "==== $MOSQ_SUB_ERR ====" ; cat $MOSQ_SUB_ERR; + + printf "%-32s TEST FAIL\n" "$CODE" | tee $CODE.testlog; +fi + +rm make.log +rm make.err +rm $CLIENT_LOG $CLIENT_ERR +rm $MOSQ_SUB_LOG $MOSQ_SUB_ERR + +# We do not want Make to stop -> Return 0 +# The Makefile will check if a log contains FAIL at the end +exit 0 From 7427a861a3d20845681ee2cc4d0545611936fdce Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 21 Oct 2018 19:36:35 +0100 Subject: [PATCH 471/485] Only build cooja for tests that actually use it --- .travis.yml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index f5a58c609..60d8db747 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,8 +30,10 @@ before_install: docker push $DOCKER_IMG; fi fi - # Build Cooja - - ant -q -f $CNG_HOST_PATH/tools/cooja/build.xml jar + # Build Cooja conditionally + - if [ ${BUILD_COOJA:-false} = true ] ; then + ant -q -f $CNG_HOST_PATH/tools/cooja/build.xml jar ; + fi # Set permissions for Docker mount - sudo chgrp -hR 1000 $CNG_HOST_PATH @@ -55,14 +57,14 @@ env: - TEST_NAME='compile-base' - TEST_NAME='compile-arm-ports-01' - TEST_NAME='compile-arm-ports-02' - - TEST_NAME='rpl-lite' - - TEST_NAME='rpl-classic' - - TEST_NAME='tun-rpl-br' + - TEST_NAME='rpl-lite' BUILD_COOJA=true + - TEST_NAME='rpl-classic' BUILD_COOJA=true + - TEST_NAME='tun-rpl-br' BUILD_COOJA=true - TEST_NAME='coap-lwm2m' - - TEST_NAME='simulation-base' - - TEST_NAME='ieee802154' + - TEST_NAME='simulation-base' BUILD_COOJA=true + - TEST_NAME='ieee802154' BUILD_COOJA=true - TEST_NAME='compile-nxp-ports' - TEST_NAME='documentation' - TEST_NAME='compile-tools' - TEST_NAME='native-runs' - - TEST_NAME='ipv6' + - TEST_NAME='ipv6' BUILD_COOJA=true From 81d6218ebcd6402bc200846a3e26ab7ac0e93ee2 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 21 Oct 2018 20:32:32 +0100 Subject: [PATCH 472/485] Don't try to build cooja from inside test makefiles --- tests/Makefile.script-test | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/Makefile.script-test b/tests/Makefile.script-test index e4dd0da6a..e58acec80 100644 --- a/tests/Makefile.script-test +++ b/tests/Makefile.script-test @@ -5,18 +5,14 @@ CONTIKI=../.. all: clean summary -summary: cooja $(TESTLOGS) +summary: $(TESTLOGS) @cat *.testlog > summary @echo "========== Summary ==========" @cat summary -%.testlog: %.sh cooja +%.testlog: %.sh @echo "========== Running script test $(basename $@).sh ==========" @bash "$(basename $@).sh" "$(CONTIKI)" clean: @rm -f *.*log report summary - -cooja: $(CONTIKI)/tools/cooja/dist/cooja.jar -$(CONTIKI)/tools/cooja/dist/cooja.jar: - (cd $(CONTIKI)/tools/cooja; ant jar) From a2c9f75e468174075102b1e9dff95b507d9e77b4 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 19 Oct 2018 14:17:25 +0100 Subject: [PATCH 473/485] Add out of tree build tests --- .travis.yml | 17 +++++++++++++++-- tests/19-out-of-tree-build/Makefile | 20 ++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 tests/19-out-of-tree-build/Makefile diff --git a/.travis.yml b/.travis.yml index 60d8db747..ca4dbf8d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,12 +34,22 @@ before_install: - if [ ${BUILD_COOJA:-false} = true ] ; then ant -q -f $CNG_HOST_PATH/tools/cooja/build.xml jar ; fi + + # Create a directory for out of tree tests and clone the test repo therein + # The directory will need created unconditionally so we can always chgrp and + # mount it, even if empty. Checkout a pre-defined version. + - mkdir -p $OUT_OF_TREE_TEST_PATH + - if [ ${TEST_NAME} = "out-of-tree-build" ] ; then + git clone --depth 1 https://github.com/contiki-ng/out-of-tree-tests $OUT_OF_TREE_TEST_PATH && + cd $OUT_OF_TREE_TEST_PATH && + git checkout $OUT_OF_TREE_TEST_VER ; + fi # Set permissions for Docker mount - - sudo chgrp -hR 1000 $CNG_HOST_PATH + - sudo chgrp -hR 1000 $CNG_HOST_PATH $OUT_OF_TREE_TEST_PATH # The test script for each build script: - - docker run --privileged -v $CNG_HOST_PATH:/home/user/contiki-ng -ti $DOCKER_IMG bash --login -c "make -C tests/??-$TEST_NAME"; + - docker run --privileged -v $OUT_OF_TREE_TEST_PATH:/home/user/out-of-tree-tests -v $CNG_HOST_PATH:/home/user/contiki-ng -ti $DOCKER_IMG bash --login -c "make -C tests/??-$TEST_NAME"; # Check outcome of the test - $CNG_HOST_PATH/tests/check-test.sh $CNG_HOST_PATH/tests/??-$TEST_NAME; exit $?; @@ -49,6 +59,8 @@ env: global: - DOCKER_IMG='contiker/contiki-ng' - CNG_HOST_PATH=`pwd` + - OUT_OF_TREE_TEST_PATH=$HOME/out-of-tree-tests + - OUT_OF_TREE_TEST_VER=2869ae7 # Encrypted environment variables. # Only available on builds of contiki-ng/contiki-ng branches, not PRs or forks. - secure: 0nrV5yjpT2kE19Hlm7t619Qbmyjx/G7bSUI1c+U3kZbyuxnRlASjVcDN5uPBoimIfGiBRI0nRq690BogAJt4EKwbC1Dy8kC1XD8mRtQ2AIZ6PHaUoG9iS5sBhFBQK0XkB83bwh6omRn/04O0uuX74ooSWT7fDrWxi/y5+0ysXK6gRtOhdrJ3FU5OkNVewX8NeCdx3pOWhMOtXWdFkMIi1XRdDnvMM5/hHlHMkdXXtaZQX9UsK3Q3DSjPRLZjKRiOlcx9MIg2ebh9ITmd2Du2p2q/LKtoutJckvhbKQPWcZi/B+1ZTSff0FHBIg+EYxf6TeFuia7XSTWH7sr2CDCCtcvSR9bB5yW6jdmGfa8Af8I1TCBuqoSUo0Re50BZBZF7COleEh+IojbjXn2CIDMg5rT4Sh3qcMGvFn9OW1cz5h5UNSOk7EIAXXPcI7Aloxh2sBo4/DrvvbfIsKrvxV9Fx4bdyNtR7dZ7xsoOw6L0zttC3K9naf3VAOeBAyjBiRwm0tWxJC/buhTsKlYrthhyUrwLtYAFL4UHcazvz57hY/cEzR2X6F//9Hp7HFoNtn1E36doX3ZfeI22yxHMo9SYW7O69C45wbhJ29lAA9XXbYVyGBKFkY8C1NCZ0Xckt9H8/Ow5Sz8HmW/NNBJCn0Fsx+jezdGc4ED5naugNbLAyNg= @@ -68,3 +80,4 @@ env: - TEST_NAME='compile-tools' - TEST_NAME='native-runs' - TEST_NAME='ipv6' BUILD_COOJA=true + - TEST_NAME='out-of-tree-build' diff --git a/tests/19-out-of-tree-build/Makefile b/tests/19-out-of-tree-build/Makefile new file mode 100644 index 000000000..759027062 --- /dev/null +++ b/tests/19-out-of-tree-build/Makefile @@ -0,0 +1,20 @@ +EXAMPLESDIR=$(HOME)/out-of-tree-tests +TOOLSDIR=$(HOME)/contiki-ng/tools + +EXAMPLES = \ +hello-world/native \ +hello-world/native:MAKE_NET=MAKE_NET_NULLNET \ +hello-world/native:MAKE_ROUTING=MAKE_ROUTING_RPL_CLASSIC \ +hello-world/sky \ +hello-world/nrf52dk \ +hello-world/cc2538dk \ +hello-world/zoul \ +hello-world/openmote-cc2538 \ +hello-world/srf06-cc26xx \ +hello-world/jn516x \ +hello-world/simplelink:BOARD=launchpad/cc26x2r1 \ +hello-world/simplelink:BOARD=sensortag/cc2650 \ + +TOOLS= + +include ../Makefile.compile-test From 1841aadf6a20ef00a155f72b5b9fb24965a441ae Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 13 Oct 2018 19:59:01 +0100 Subject: [PATCH 474/485] Reduce makefile code duplication --- arch/cpu/arm/cortex-m/Makefile.cortex-m | 12 ++++++++++++ arch/cpu/arm/cortex-m/cm3/Makefile.cm3 | 11 +---------- arch/cpu/arm/cortex-m/cm4/Makefile.cm4 | 11 ----------- 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/arch/cpu/arm/cortex-m/Makefile.cortex-m b/arch/cpu/arm/cortex-m/Makefile.cortex-m index aebcf2bdd..36487ef8a 100644 --- a/arch/cpu/arm/cortex-m/Makefile.cortex-m +++ b/arch/cpu/arm/cortex-m/Makefile.cortex-m @@ -3,6 +3,18 @@ CONTIKI_ARM_DIRS += cortex-m cortex-m/CMSIS ### Build syscalls for newlib MODULES += os/lib/newlib +LDFLAGS += -T $(LDSCRIPT) +LDFLAGS += -Wl,--gc-sections,--sort-section=alignment +LDFLAGS += -Wl,-Map=$(CONTIKI_NG_PROJECT_MAP),--cref,--no-warn-mismatch + +OBJCOPY_FLAGS += --gap-fill 0xff + +CPU_STARTFILES = ${addprefix $(OBJECTDIR)/,${call oname, $(CPU_START_SOURCEFILES)}} + +### Resolve any potential circular dependencies between the linked libraries +### See: https://stackoverflow.com/questions/5651869/gcc-what-are-the-start-group-and-end-group-command-line-options/5651895 +TARGET_LIBFLAGS := -Wl,--start-group $(TARGET_LIBFILES) -Wl,--end-group + CUSTOM_RULE_LINK = 1 .SECONDEXPANSION: diff --git a/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 b/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 index 3cf216bfb..b4bf612da 100644 --- a/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 +++ b/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 @@ -3,16 +3,7 @@ CONTIKI_ARM_DIRS += cortex-m/cm3 CFLAGS += -mcpu=cortex-m3 LDFLAGS += -mcpu=cortex-m3 -nostartfiles -LDFLAGS += -T $(LDSCRIPT) -LDFLAGS += -Wl,--gc-sections,--sort-section=alignment -LDFLAGS += -Wl,-Map=$(CONTIKI_NG_PROJECT_MAP),--cref,--no-warn-mismatch -OBJCOPY_FLAGS += --gap-fill 0xff - -CPU_STARTFILES = ${addprefix $(OBJECTDIR)/,${call oname, $(CPU_START_SOURCEFILES)}} - -### Resolve any potential circular dependencies between the linked libraries -### See: https://stackoverflow.com/questions/5651869/gcc-what-are-the-start-group-and-end-group-command-line-options/5651895 -TARGET_LIBFLAGS := -Wl,--start-group $(TARGET_LIBFILES) -lm -Wl,--end-group +TARGET_LIBFILES += -lm include $(CONTIKI)/arch/cpu/arm/cortex-m/Makefile.cortex-m diff --git a/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 b/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 index b0b592e43..7443681ea 100644 --- a/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 +++ b/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 @@ -3,16 +3,5 @@ CONTIKI_ARM_DIRS += cortex-m/cm4 CFLAGS += -mcpu=cortex-m4 LDFLAGS += -mcpu=cortex-m4 -LDFLAGS += -T $(LDSCRIPT) -LDFLAGS += -Wl,--gc-sections,--sort-section=alignment -LDFLAGS += -Wl,-Map=$(CONTIKI_NG_PROJECT_MAP),--cref,--no-warn-mismatch - -OBJCOPY_FLAGS += --gap-fill 0xff - -CPU_STARTFILES = ${addprefix $(OBJECTDIR)/,${call oname, $(CPU_START_SOURCEFILES)}} - -### Resolve any potential circular dependencies between the linked libraries -### See: https://stackoverflow.com/questions/5651869/gcc-what-are-the-start-group-and-end-group-command-line-options/5651895 -TARGET_LIBFLAGS := -Wl,--start-group $(TARGET_LIBFILES) -Wl,--end-group include $(CONTIKI)/arch/cpu/arm/cortex-m/Makefile.cortex-m From ab5d5ba33cac0f4c7c5fd2b928b7c611f66fbf7f Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 13 Oct 2018 22:26:22 +0100 Subject: [PATCH 475/485] Extend build verbosity control Apply verbosity control for mkdir, cp, srec_cat, objcopy, objdump --- Makefile.include | 11 ++++++++++- arch/cpu/arm/Makefile.arm | 23 ++++++++++++++++++----- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/Makefile.include b/Makefile.include index a194274bd..7d7bef70e 100644 --- a/Makefile.include +++ b/Makefile.include @@ -77,7 +77,8 @@ PROJECT_OBJECTFILES = ${addprefix $(OBJECTDIR)/,${call oname, $(PROJECT_SOURCEFI # Provide way to create $(OBJECTDIR) if it has been removed by make clean $(OBJECTDIR): - mkdir $@ + $(TRACE_MKDIR) + $(Q)mkdir $@ uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1))) @@ -241,12 +242,20 @@ ifeq ($(V),1) TRACE_LD = TRACE_AR = TRACE_AS = + TRACE_OBJCOPY = + TRACE_OBJDUMP = + TRACE_MKDIR = + TRACE_CP = Q= else TRACE_CC = @echo " CC " $< TRACE_LD = @echo " LD " $@ TRACE_AR = @echo " AR " $@ TRACE_AS = @echo " AS " $< + TRACE_OBJCOPY = @echo " OBJCOPY " $< "-->" $@ + TRACE_OBJDUMP = @echo " OBJDUMP " $< "-->" $@ + TRACE_MKDIR = @echo " MKDIR " $@ + TRACE_CP = @echo " CP " $< "-->" $@ Q=@ endif diff --git a/arch/cpu/arm/Makefile.arm b/arch/cpu/arm/Makefile.arm index 83f9b8a36..e24385f4b 100644 --- a/arch/cpu/arm/Makefile.arm +++ b/arch/cpu/arm/Makefile.arm @@ -1,3 +1,11 @@ +### Verbosity control. Use make V=1 to get verbose builds. +### Extends what we already have in the top-level Makefile +ifeq ($(V),1) + TRACE_SREC_CAT = +else + TRACE_SREC_CAT = @echo " SREC_CAT " $< "-->" $@ +endif + CC = arm-none-eabi-gcc CPP = arm-none-eabi-cpp LD = arm-none-eabi-gcc @@ -47,18 +55,23 @@ CLEAN += *.elf *.bin *.lst *.hex *.i16hex .PRECIOUS: %.elf %.hex %.bin %.i16hex: %.elf - $(OBJCOPY) -O ihex $< $@ + $(TRACE_OBJCOPY) + $(Q)$(OBJCOPY) -O ihex $< $@ %.hex: %.i16hex - $(SREC_CAT) $< -intel -o $@ -intel + $(TRACE_SREC_CAT) + $(Q)$(SREC_CAT) $< -intel -o $@ -intel %.bin: %.elf - $(OBJCOPY) -O binary $(OBJCOPY_FLAGS) $< $@ + $(TRACE_OBJCOPY) + $(Q)$(OBJCOPY) -O binary $(OBJCOPY_FLAGS) $< $@ %.lst: %.elf - $(OBJDUMP) $(OBJDUMP_FLAGS) $< > $@ + $(TRACE_OBJDUMP) + $(Q)$(OBJDUMP) $(OBJDUMP_FLAGS) $< > $@ ### We don't really need the .hex and .bin for the .$(TARGET) but let's make ### sure they get built %.$(TARGET): %.elf %.hex %.bin - cp $< $@ + $(TRACE_CP) + $(Q)cp $< $@ From f8ea68c3eb39d7de1c28d3ceaa7a2c6896e91b42 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 13 Oct 2018 23:14:51 +0100 Subject: [PATCH 476/485] Change build output dir structure and filenames --- Makefile.include | 27 ++++++++++++++----------- arch/cpu/arm/Makefile.arm | 19 ++++++++++------- arch/cpu/arm/cortex-m/Makefile.cortex-m | 4 +++- arch/cpu/nrf52832/Makefile.nrf52832 | 6 +++--- 4 files changed, 33 insertions(+), 23 deletions(-) diff --git a/Makefile.include b/Makefile.include index 7d7bef70e..7d26da821 100644 --- a/Makefile.include +++ b/Makefile.include @@ -13,8 +13,6 @@ include $(CONTIKI)/Makefile.identify-target ### Include Makefile.tools to pull in targets that allow us to build tools dir include $(CONTIKI)/Makefile.tools -CONTIKI_NG_TARGET_LIB = contiki-ng-$(TARGET).a - ifeq ($(DEFINES),) -include Makefile.$(TARGET).defines ifneq ($(DEFINES),) @@ -39,7 +37,12 @@ ifdef CI endif endif -OBJECTDIR = obj_$(TARGET) +BUILD_DIR = build +BUILD_DIR_TARGET = $(BUILD_DIR)/$(TARGET) +BUILD_DIR_BOARD = $(BUILD_DIR_TARGET)/$(BOARD) +OBJECTDIR = $(BUILD_DIR_BOARD)/obj + +CONTIKI_NG_TARGET_LIB = $(BUILD_DIR_BOARD)/contiki-ng-$(TARGET).a LOWERCASE = -abcdefghijklmnopqrstuvwxyz/ UPPERCASE = _ABCDEFGHIJKLMNOPQRSTUVWXYZ_ @@ -75,11 +78,6 @@ endef CONTIKI_OBJECTFILES = ${addprefix $(OBJECTDIR)/,${call oname, $(CONTIKI_SOURCEFILES)}} PROJECT_OBJECTFILES = ${addprefix $(OBJECTDIR)/,${call oname, $(PROJECT_SOURCEFILES)}} -# Provide way to create $(OBJECTDIR) if it has been removed by make clean -$(OBJECTDIR): - $(TRACE_MKDIR) - $(Q)mkdir $@ - uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1))) ### Include target makefile (TODO Unsafe?) @@ -125,6 +123,11 @@ endif # $(BOARD) not empty PLATFORM_ACTION ?= build +# Provide way to create $(OBJECTDIR) if it has been removed by make clean +$(OBJECTDIR): + $(TRACE_MKDIR) + $(Q)mkdir -p $@ + ifneq ($(BOARD),) TARGET_BOARD_UPPERCASE := ${strip ${shell echo $(BOARD) | sed y!$(LOWERCASE)!$(UPPERCASE)!}} CFLAGS += -DCONTIKI_BOARD_$(TARGET_BOARD_UPPERCASE)=1 @@ -312,14 +315,13 @@ endef ### Harmonize filename of a .map file, if the platform's build system wants ### to create one -CONTIKI_NG_PROJECT_MAP = $(addsuffix -$(TARGET).map, $(basename $@)) +CONTIKI_NG_PROJECT_MAP = $(BUILD_DIR_BOARD)/$(basename $(notdir $@)).map .PHONY: clean distclean usage help targets boards savetarget savedefines viewconf clean: - -$(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 *.d *.e *.o $(CLEAN) + -$(Q)rm -rf $(BUILD_DIR_TARGET) -$(Q)rm -f $(addsuffix .$(TARGET), $(CONTIKI_PROJECT)) @echo Target $(TARGET) cleaned @@ -328,6 +330,7 @@ distclean: echo Running: $(MAKE) TARGET=$$TARG clean; \ $(MAKE) TARGET=$$TARG clean; \ done + rmdir $(BUILD_DIR) -include $(CONTIKI)/arch/platform/$(TARGET)/Makefile.customrules-$(TARGET) diff --git a/arch/cpu/arm/Makefile.arm b/arch/cpu/arm/Makefile.arm index e24385f4b..d378d1132 100644 --- a/arch/cpu/arm/Makefile.arm +++ b/arch/cpu/arm/Makefile.arm @@ -51,27 +51,32 @@ endif ### CPU-dependent cleanup files CLEAN += *.elf *.bin *.lst *.hex *.i16hex -### Don't treat the following files as intermediate -.PRECIOUS: %.elf %.hex %.bin +OUT_HEX = $(BUILD_DIR_BOARD)/%.hex +OUT_I16HEX = $(BUILD_DIR_BOARD)/%.i16hex +OUT_BIN = $(BUILD_DIR_BOARD)/%.bin +OUT_LST = $(BUILD_DIR_BOARD)/%.lst -%.i16hex: %.elf +### Don't treat the following files as intermediate +.PRECIOUS: $(OUT_ELF) $(OUT_HEX) $(OUT_BIN) + +$(OUT_I16HEX): $(OUT_ELF) $(TRACE_OBJCOPY) $(Q)$(OBJCOPY) -O ihex $< $@ -%.hex: %.i16hex +$(OUT_HEX): $(OUT_I16HEX) $(TRACE_SREC_CAT) $(Q)$(SREC_CAT) $< -intel -o $@ -intel -%.bin: %.elf +$(OUT_BIN): $(OUT_ELF) $(TRACE_OBJCOPY) $(Q)$(OBJCOPY) -O binary $(OBJCOPY_FLAGS) $< $@ -%.lst: %.elf +$(OUT_LST): $(OUT_ELF) $(TRACE_OBJDUMP) $(Q)$(OBJDUMP) $(OBJDUMP_FLAGS) $< > $@ ### We don't really need the .hex and .bin for the .$(TARGET) but let's make ### sure they get built -%.$(TARGET): %.elf %.hex %.bin +%.$(TARGET): $(OUT_ELF) $(OUT_HEX) $(OUT_BIN) $(TRACE_CP) $(Q)cp $< $@ diff --git a/arch/cpu/arm/cortex-m/Makefile.cortex-m b/arch/cpu/arm/cortex-m/Makefile.cortex-m index 36487ef8a..0ca1d54ff 100644 --- a/arch/cpu/arm/cortex-m/Makefile.cortex-m +++ b/arch/cpu/arm/cortex-m/Makefile.cortex-m @@ -17,9 +17,11 @@ TARGET_LIBFLAGS := -Wl,--start-group $(TARGET_LIBFILES) -Wl,--end-group CUSTOM_RULE_LINK = 1 +OUT_ELF = $(BUILD_DIR_BOARD)/%.elf + .SECONDEXPANSION: -%.elf: $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(LDSCRIPT) $(TARGET_LIBS) +$(OUT_ELF): $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(LDSCRIPT) $(TARGET_LIBS) $(TRACE_LD) $(Q)$(LD) $(LDFLAGS) ${filter-out $(LDSCRIPT) %.a,$^} ${filter %.a,$^} $(TARGET_LIBFLAGS) -o $@ diff --git a/arch/cpu/nrf52832/Makefile.nrf52832 b/arch/cpu/nrf52832/Makefile.nrf52832 index c97c728e5..098033ce4 100644 --- a/arch/cpu/nrf52832/Makefile.nrf52832 +++ b/arch/cpu/nrf52832/Makefile.nrf52832 @@ -172,11 +172,11 @@ vpath %.s $(ASM_PATHS) OBJECTS = $(C_OBJECTS) $(ASM_OBJECTS) -CLEAN += nrf52832.a +NRFLIB = $(BUILD_DIR_BOARD)/nrf52832.a -TARGET_LIBS = nrf52832.a $(NRF52_SDK_ROOT)/components/iot/ble_6lowpan/lib/ble_6lowpan.a +TARGET_LIBS = $(NRFLIB) $(NRF52_SDK_ROOT)/components/iot/ble_6lowpan/lib/ble_6lowpan.a -nrf52832.a: $(OBJECTS) +$(NRFLIB): $(OBJECTS) $(TRACE_AR) $(Q)$(AR) $(AROPTS) $@ $^ From 1b85bc61242f2e793c8c41a17f4f7c3015616037 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 13 Oct 2018 23:15:06 +0100 Subject: [PATCH 477/485] Ignore the new build output dir --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 0ff1ebfa2..c80b86fd0 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,7 @@ *.ihex *.pyc *~ -obj_* +build/* Makefile.target Makefile.*.defines tools/doxygen/html From 6f2f4b4b2371b6027c71860b7a3773a069c34cf4 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 14 Oct 2018 00:23:43 +0100 Subject: [PATCH 478/485] Fix the .upload target --- arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx | 6 +++--- arch/platform/cc2538dk/Makefile.cc2538dk | 5 +++-- arch/platform/openmote-cc2538/Makefile.openmote-cc2538 | 5 +++-- arch/platform/zoul/Makefile.zoul | 4 ++-- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx b/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx index 592ddfbd8..94f4e5111 100644 --- a/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx +++ b/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx @@ -81,8 +81,10 @@ STACK_SIZE = 0 @$(SIZE) -A $< | egrep "data|bss" | awk '{s+=$$2} END {s=s+$(STACK_SIZE); f=$(RAM_SIZE)-s; printf "[RAM] used %6d, free %6d\n",s,f;}' @$(SIZE) -A $< | egrep "text|isr_vector" | awk '{s+=$$2} END {f=$(FLASH_SIZE)-s; printf "[Flash] used %6d, free %6d\n",s,f;}' +include $(CONTIKI)/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 + ifeq ($(BOARD_SUPPORTS_BSL),1) -%.upload: %.bin +%.upload: $(OUT_BIN) ifeq ($(wildcard $(BSL)), ) @echo "ERROR: Could not find the cc2538-bsl script. Did you run 'git submodule update --init' ?" else @@ -95,5 +97,3 @@ endif ### For the login etc targets BAUDRATE = 115200 - -include $(CONTIKI)/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 diff --git a/arch/platform/cc2538dk/Makefile.cc2538dk b/arch/platform/cc2538dk/Makefile.cc2538dk index d80fd8d5f..148c6e837 100644 --- a/arch/platform/cc2538dk/Makefile.cc2538dk +++ b/arch/platform/cc2538dk/Makefile.cc2538dk @@ -28,11 +28,12 @@ endif BSL = $(CONTIKI)/tools/cc2538-bsl/cc2538-bsl.py -%.upload: %.bin %.elf +%.upload: $(OUT_BIN) $(OUT_ELF) ifeq ($(wildcard $(BSL)), ) @echo "ERROR: Could not find the cc2538-bsl script. Did you run 'git submodule update --init' ?" else - $(eval BSL_ADDRESS_ARG := -a $(shell $(OBJDUMP) -h $*.elf | grep -B1 LOAD | \ + $(eval BSL_ADDRESS_ARG := -a $(shell $(OBJDUMP) -h \ + $(BUILD_DIR_BOARD)/$*.elf | grep -B1 LOAD | \ grep -Ev 'LOAD|\-\-' | awk '{print "0x" $$5}' | \ sort -g | head -1)) $(PYTHON) $(BSL) $(BSL_FLAGS) $(BSL_ADDRESS_ARG) $< diff --git a/arch/platform/openmote-cc2538/Makefile.openmote-cc2538 b/arch/platform/openmote-cc2538/Makefile.openmote-cc2538 index d3863fdbc..8b25b0bfe 100644 --- a/arch/platform/openmote-cc2538/Makefile.openmote-cc2538 +++ b/arch/platform/openmote-cc2538/Makefile.openmote-cc2538 @@ -35,11 +35,12 @@ endif BSL = $(CONTIKI)/tools/cc2538-bsl/cc2538-bsl.py -%.upload: %.bin %.elf +%.upload: $(OUT_BIN) $(OUT_ELF) ifeq ($(wildcard $(BSL)), ) @echo "ERROR: Could not find the cc2538-bsl script. Did you run 'git submodule update --init' ?" else - $(eval BSL_ADDRESS_ARG := -a $(shell $(OBJDUMP) -h $*.elf | grep -B1 LOAD | \ + $(eval BSL_ADDRESS_ARG := -a $(shell $(OBJDUMP) -h \ + $(BUILD_DIR_BOARD)/$*.elf | grep -B1 LOAD | \ grep -Ev 'LOAD|\-\-' | awk '{print "0x" $$5}' | \ sort -g | head -1)) $(PYTHON) $(BSL) $(BSL_FLAGS) $(BSL_ADDRESS_ARG) $< diff --git a/arch/platform/zoul/Makefile.zoul b/arch/platform/zoul/Makefile.zoul index 938abe035..e43f84744 100644 --- a/arch/platform/zoul/Makefile.zoul +++ b/arch/platform/zoul/Makefile.zoul @@ -69,9 +69,9 @@ endif ### $$$$ Double escapes $s that need to be passed to the shell - once for when ### make parses UPLOAD_RULE, and once for when the expanded rule is parsed by make. define UPLOAD_RULE -%.$(MOTE): %.bin %.elf +%.$(MOTE): $(OUT_BIN) $(OUT_ELF) @echo "Flashing $(MOTE)" - @BSL_ADDRESS=`$(OBJDUMP) -h $$*.elf | grep -B1 LOAD | \ + @BSL_ADDRESS=`$(OBJDUMP) -h $(BUILD_DIR_BOARD)/$$*.elf | grep -B1 LOAD | \ grep -Ev 'LOAD|\-\-' | awk '{print "0x" $$$$5}' | \ sort -g | head -1`; \ $(PYTHON) $(BSL) $(BSL_FLAGS) -b $(BSL_SPEED) -a $$$${BSL_ADDRESS} -p $(MOTE) $$< From 8121383950402e614f33dbb667e67cefc9069185 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Wed, 17 Oct 2018 12:36:52 +0100 Subject: [PATCH 479/485] Update the Cooja submodule to the latest version --- tools/cooja | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cooja b/tools/cooja index a5904b983..63538bbb8 160000 --- a/tools/cooja +++ b/tools/cooja @@ -1 +1 @@ -Subproject commit a5904b98366478bb9e7f7fe9f0bb78fc064914c5 +Subproject commit 63538bbb882ba06a7b8cf97c11ce2fe4d22e4f88 From 44d3f78b9c77fe2872e4d10feba39e3e6afbbbb8 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 14 Oct 2018 00:29:47 +0100 Subject: [PATCH 480/485] Adjust the Cooja build system to the new build output dir structure --- arch/platform/cooja/Makefile.cooja | 8 ++++---- arch/platform/cooja/Makefile.customrules-cooja | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/platform/cooja/Makefile.cooja b/arch/platform/cooja/Makefile.cooja index d06aa08d5..6a6a9d49e 100644 --- a/arch/platform/cooja/Makefile.cooja +++ b/arch/platform/cooja/Makefile.cooja @@ -34,10 +34,10 @@ endif endif ## QUICKSTART -#MAIN_SRC = $(OBJECTDIR)/$(LIBNAME).c -MAIN_OBJ = $(OBJECTDIR)/$(LIBNAME).o -ARCHIVE = $(OBJECTDIR)/$(LIBNAME).a -JNILIB = $(OBJECTDIR)/$(LIBNAME).$(TARGET) +#MAIN_SRC = $(BUILD_DIR_BOARD)/$(LIBNAME).c +MAIN_OBJ = $(BUILD_DIR_BOARD)/$(LIBNAME).o +ARCHIVE = $(BUILD_DIR_BOARD)/$(LIBNAME).a +JNILIB = $(BUILD_DIR_BOARD)/$(LIBNAME).$(TARGET) CONTIKI_APP_OBJ = $(CONTIKI_APP).o ### COOJA platform sources diff --git a/arch/platform/cooja/Makefile.customrules-cooja b/arch/platform/cooja/Makefile.customrules-cooja index 42d6e125e..60d6240f1 100644 --- a/arch/platform/cooja/Makefile.customrules-cooja +++ b/arch/platform/cooja/Makefile.customrules-cooja @@ -10,11 +10,11 @@ CUSTOM_RULE_LINK=1 REDEF_PRINTF=1 # Redefine functions to enable printf()s inside Cooja -# NB: Assumes ARCHIVE was not overridden and is in $(OBJECTDIR) +# NB: Assumes ARCHIVE was not overridden and is in $(BUILD_DIR_BOARD) $(ARCHIVE): $(CONTIKI_OBJECTFILES) | $(OBJECTDIR) $(AR_COMMAND_1) $^ $(AR_COMMAND_2) -# NB: Assumes JNILIB was not overridden and is in $(OBJECTDIR) +# NB: Assumes JNILIB was not overridden and is in $(BUILD_DIR_BOARD) $(JNILIB): $(CONTIKI_APP_OBJ) $(MAIN_OBJ) $(PROJECT_OBJECTFILES) $(ARCHIVE) | $(OBJECTDIR) ifdef REDEF_PRINTF From 0622889add62f0a230db1ecd6f1b1ce68d556e5b Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Thu, 18 Oct 2018 20:14:48 +0100 Subject: [PATCH 481/485] Allow users to specify build configurations --- Makefile.include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.include b/Makefile.include index 7d26da821..1ebe8f582 100644 --- a/Makefile.include +++ b/Makefile.include @@ -39,7 +39,7 @@ endif BUILD_DIR = build BUILD_DIR_TARGET = $(BUILD_DIR)/$(TARGET) -BUILD_DIR_BOARD = $(BUILD_DIR_TARGET)/$(BOARD) +BUILD_DIR_BOARD = $(BUILD_DIR_TARGET)/$(BOARD)/$(BUILD_DIR_CONFIG) OBJECTDIR = $(BUILD_DIR_BOARD)/obj CONTIKI_NG_TARGET_LIB = $(BUILD_DIR_BOARD)/contiki-ng-$(TARGET).a From d89cca83acded3ce51045efd0eb8c550ac2a48a7 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Tue, 23 Oct 2018 16:49:54 +0100 Subject: [PATCH 482/485] Don't generate an error if build/ does not exist --- Makefile.include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.include b/Makefile.include index 1ebe8f582..3c9058c9e 100644 --- a/Makefile.include +++ b/Makefile.include @@ -330,7 +330,7 @@ distclean: echo Running: $(MAKE) TARGET=$$TARG clean; \ $(MAKE) TARGET=$$TARG clean; \ done - rmdir $(BUILD_DIR) + -$(Q)rm -rf $(BUILD_DIR) -include $(CONTIKI)/arch/platform/$(TARGET)/Makefile.customrules-$(TARGET) From 14eeeccebca59bb9ce2f892bc927c90ca5e8b4af Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Tue, 23 Oct 2018 17:45:43 +0100 Subject: [PATCH 483/485] Always create example.$(TARGET) under build/ and then copy to . --- Makefile.include | 12 ++++++++---- arch/cpu/arm/Makefile.arm | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Makefile.include b/Makefile.include index 3c9058c9e..672c7f4c1 100644 --- a/Makefile.include +++ b/Makefile.include @@ -395,12 +395,16 @@ ifndef LD endif ifndef CUSTOM_RULE_LINK -%.$(TARGET): %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(CONTIKI_NG_TARGET_LIB) +$(BUILD_DIR_BOARD)/%.$(TARGET): %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(CONTIKI_NG_TARGET_LIB) $(TRACE_LD) $(Q)$(LD) $(LDFLAGS) $(TARGET_STARTFILES) ${filter-out %.a,$^} \ ${filter %.a,$^} $(TARGET_LIBFILES) -o $@ endif +%.$(TARGET): $(BUILD_DIR_BOARD)/%.$(TARGET) + $(TRACE_CP) + $(Q)cp $< $@ + %.ramprof: %.$(TARGET) $(NM) -S -td --size-sort $< | grep -i " [abdrw] " | cut -d' ' -f2,4 @@ -458,9 +462,9 @@ ifeq ($(findstring $(TARGET),native cooja),) include $(CONTIKI)/Makefile.embedded endif -# Don't treat %.$(TARGET) as an intermediate file because it is -# in fact the primary target. -.PRECIOUS: %.$(TARGET) +# Don't treat $(BUILD_DIR_BOARD)/%.$(TARGET) and $(TARGET) as intermediate +# files because for many platforms they are in fact the primary target. +.PRECIOUS: $(BUILD_DIR_BOARD)/%.$(TARGET) %.$(TARGET) # Cancel the predefined implict rule for compiling and linking # a single C source into a binary to force GNU make to consider diff --git a/arch/cpu/arm/Makefile.arm b/arch/cpu/arm/Makefile.arm index d378d1132..e8befdb86 100644 --- a/arch/cpu/arm/Makefile.arm +++ b/arch/cpu/arm/Makefile.arm @@ -77,6 +77,6 @@ $(OUT_LST): $(OUT_ELF) ### We don't really need the .hex and .bin for the .$(TARGET) but let's make ### sure they get built -%.$(TARGET): $(OUT_ELF) $(OUT_HEX) $(OUT_BIN) +$(BUILD_DIR_BOARD)/%.$(TARGET): $(OUT_ELF) $(OUT_HEX) $(OUT_BIN) $(TRACE_CP) $(Q)cp $< $@ From 1dc02498369470c810ed0cef110ccb399c562014 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Tue, 23 Oct 2018 17:45:59 +0100 Subject: [PATCH 484/485] Adjust the jn516x build system to the new build output dir structure --- arch/platform/jn516x/Makefile.jn516x | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/arch/platform/jn516x/Makefile.jn516x b/arch/platform/jn516x/Makefile.jn516x index 9ad9488d5..051c336fb 100644 --- a/arch/platform/jn516x/Makefile.jn516x +++ b/arch/platform/jn516x/Makefile.jn516x @@ -229,30 +229,34 @@ ALLLIBS = $(addprefix -l,$(LDLIBS)) $(addprefix -l,$(LDSTACKLIBS)) $(addprefix - ABS_APPLIBS = $(addsuffix _$(JENNIC_CHIP_FAMILY).a,$(addprefix $(COMPONENTS_BASE_DIR)/Library/lib,$(APPLIBS))) ifneq ($(wildcard $(SDK_BASE_DIR)/Components/Library/*),) -# The SDK is fully installed, proceed to linking and objcopy to ready-to-upload .jn516x.bin file -%.$(TARGET): %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(CONTIKI_NG_TARGET_LIB) $(ABS_APPLIBS) - echo ${filter %.a,$^} +# The SDK is fully installed, proceed to linking +$(BUILD_DIR_BOARD)/%.$(TARGET): %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(CONTIKI_NG_TARGET_LIB) $(ABS_APPLIBS) + @echo ${filter %.a,$^} $(Q)$(CC) -Wl,--gc-sections $(LDFLAGS) -T$(LINKCMD) -o $@ -Wl,--start-group \ $(patsubst /cygdrive/c/%,c:/%,${filter-out %.a,$^}) \ $(patsubst /cygdrive/c/%,c:/%,${filter %.a,$^}) \ $(ALLLIBS) -Wl,--end-group -Wl,-Map,$(CONTIKI_NG_PROJECT_MAP) - $(OBJCOPY) -S -O binary $@ $@.bin else # The SDK does not include libraries, only build objects and libraries, skip linking -%.$(TARGET): %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(CONTIKI_NG_TARGET_LIB) - echo Creating empty $@ +$(BUILD_DIR_BOARD)/%.$(TARGET): %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(CONTIKI_NG_TARGET_LIB) + @echo Creating empty $@ touch $@ endif -%.$(TARGET).bin: %.$(TARGET) +$(BUILD_DIR_BOARD)/%.$(TARGET).bin: $(BUILD_DIR_BOARD)/%.$(TARGET) + $(TRACE_OBJCOPY) $(Q)$(OBJCOPY) -S -O binary $< $@ +%.$(TARGET).bin: $(BUILD_DIR_BOARD)/%.$(TARGET).bin + $(TRACE_CP) + $(Q)$(CP) $< $@ + ### Upload target to one jn516x mote specified by MOTE=portNumber ifeq ($(HOST_OS),Windows) -%.upload: %.$(TARGET).bin +%.upload: $(BUILD_DIR_BOARD)/%.$(TARGET).bin ${FLASH_PROGRAMMER} -a -c $(DEV_PORT) -B 1000000 -s -w -f $< else -%.upload: %.$(TARGET).bin +%.upload: $(BUILD_DIR_BOARD)/%.$(TARGET).bin ${FLASH_PROGRAMMER} -V 10 -v -s $(DEV_PORT) -I 38400 -P 1000000 -f $< endif @@ -276,7 +280,7 @@ motelistinfo: $(Q)$(MOTELIST) ${FLASH_PROGRAMMER} \? ### Upload target to all connected jn516x motes -%.uploadall: %.$(TARGET).bin +%.uploadall: $(BUILD_DIR_BOARD)/%.$(TARGET).bin $(Q)$(MOTELIST) ${FLASH_PROGRAMMER} $< ### Flash the given file to all connected jn516x motes From 5d8fda2af49eb58420d08e1c09f87baee8853c2d Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Mon, 5 Nov 2018 14:35:06 +0100 Subject: [PATCH 485/485] Native border router: clearer error messages --- os/services/rpl-border-router/native/slip-dev.c | 2 +- os/services/rpl-border-router/native/tun-bridge.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/os/services/rpl-border-router/native/slip-dev.c b/os/services/rpl-border-router/native/slip-dev.c index 7ea764836..3ccd1db4b 100644 --- a/os/services/rpl-border-router/native/slip-dev.c +++ b/os/services/rpl-border-router/native/slip-dev.c @@ -562,7 +562,7 @@ slip_init(void) slip_send(slipfd, SLIP_END); inslip = fdopen(slipfd, "r"); if(inslip == NULL) { - err(1, "main: fdopen"); + err(1, "slip_init: fdopen"); } } /*---------------------------------------------------------------------------*/ diff --git a/os/services/rpl-border-router/native/tun-bridge.c b/os/services/rpl-border-router/native/tun-bridge.c index f321577b3..289a32185 100644 --- a/os/services/rpl-border-router/native/tun-bridge.c +++ b/os/services/rpl-border-router/native/tun-bridge.c @@ -210,7 +210,7 @@ tun_init() tunfd = tun_alloc(slip_config_tundev); if(tunfd == -1) { - err(1, "main: open"); + err(1, "tun_init: open"); } select_set_callback(tunfd, &tun_select_callback);

&YTNNEplw)aD0|;sK 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 diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/quickstart-sensortag.png b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/quickstart-sensortag.png deleted file mode 100644 index a7ce7dabeb979afdf8a31a5803265281fb10636f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 158808 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 MIn&AxK&B#q%BQyt^9Mm;?p>DPv~0V;+Nskt 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 diff --git a/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/sensor-readings-config.png b/examples/platform-specific/simplelink/cc13xx-cc26xx/web-demo/img/sensor-readings-config.png deleted file mode 100644 index 79c8e61e3f410f2500dda37b87466863464e2b8c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33000 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

`SA&U6X|M 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%0DZB>VN+&uUWzOZ*47*hI6BTHn=WDlK%yIF@UE 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 literal 0 HcmV?d00001 From 6df96a7b19c5e4ec9cf5ca558634758aa1bdcf5b Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Thu, 26 Jul 2018 11:58:34 +0200 Subject: [PATCH 306/485] Added missing files for cc26xx examples folder --- .../platform-specific/cc26xx/Makefile.target | 1 + .../cc26xx/cc26xx-web-demo/Makefile.target | 1 + .../cc26xx/cc26xx-web-demo/img/6lbr-web.png | Bin 0 -> 81741 bytes .../ibm-watson-iot-platform-tls-optional.png | Bin 0 -> 86462 bytes .../img/quickstart-sensortag.png | Bin 0 -> 158808 bytes .../img/sensor-readings-config.png | Bin 0 -> 33000 bytes .../cc26xx-web-demo/img/well-known-core.png | Bin 0 -> 9102 bytes .../cc26xx/very-sleepy-demo/Makefile.target | 1 + 8 files changed, 3 insertions(+) create mode 100644 examples/platform-specific/cc26xx/Makefile.target create mode 100644 examples/platform-specific/cc26xx/cc26xx-web-demo/Makefile.target create mode 100644 examples/platform-specific/cc26xx/cc26xx-web-demo/img/6lbr-web.png create mode 100644 examples/platform-specific/cc26xx/cc26xx-web-demo/img/ibm-watson-iot-platform-tls-optional.png create mode 100644 examples/platform-specific/cc26xx/cc26xx-web-demo/img/quickstart-sensortag.png create mode 100644 examples/platform-specific/cc26xx/cc26xx-web-demo/img/sensor-readings-config.png create mode 100644 examples/platform-specific/cc26xx/cc26xx-web-demo/img/well-known-core.png create mode 100644 examples/platform-specific/cc26xx/very-sleepy-demo/Makefile.target diff --git a/examples/platform-specific/cc26xx/Makefile.target b/examples/platform-specific/cc26xx/Makefile.target new file mode 100644 index 000000000..15890aa6a --- /dev/null +++ b/examples/platform-specific/cc26xx/Makefile.target @@ -0,0 +1 @@ +TARGET = srf06-cc26xx diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/Makefile.target b/examples/platform-specific/cc26xx/cc26xx-web-demo/Makefile.target new file mode 100644 index 000000000..15890aa6a --- /dev/null +++ b/examples/platform-specific/cc26xx/cc26xx-web-demo/Makefile.target @@ -0,0 +1 @@ +TARGET = srf06-cc26xx diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/img/6lbr-web.png b/examples/platform-specific/cc26xx/cc26xx-web-demo/img/6lbr-web.png new file mode 100644 index 0000000000000000000000000000000000000000..5308c412bc183fe3f62930fec950a1029ebc036b GIT binary patch literal 81741 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 LdQl>7^!EP%AFu2O literal 0 HcmV?d00001 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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

L5>wJ$7t>6!t%#TC9o89^*XGpXZ zSCvm5(2b6&`h8gHdp7&%KxnQqCWn{4mOUP%c#ZSpyyo)eLpRPp8$)d(x~0+hE%|*? zG^<=mi54^XgwynyjUwOZyHbGl^hINNN(E(})7kn^J%I{s4ofao|qgkdNdtr`$FUGaB6D9AUQe!`*2P%XK|@ z&TweRc*Zh!2-PdM6xs!Zsj~K+F;sHn^H-pTpNOF@Z|*VA0b=?H>iu5lW-%*rh?#CL z*U`CJV8VsHd2jQ2Ha+ML`rO`y3v?%lV#LigMV@SVPthssoyt&PIHG)kWKzJ~qYTdM zA|N-kDcuo$z+Cw9L&D`pYGa}^)gKE-+UjKZ37tok=TD(JpT@C* Date: Sat, 12 May 2018 16:17:22 +0100 Subject: [PATCH 133/485] Move serialdump source to the top-level tools dir --- tools/{sky => }/serialdump.c | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tools/{sky => }/serialdump.c (100%) diff --git a/tools/sky/serialdump.c b/tools/serialdump.c similarity index 100% rename from tools/sky/serialdump.c rename to tools/serialdump.c From 5c65a07c56376318945e405874aab24f96ce5e01 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 12 May 2018 16:18:03 +0100 Subject: [PATCH 134/485] Fix serialdump code style --- tools/serialdump.c | 286 +++++++++++++++++++++++---------------------- 1 file changed, 144 insertions(+), 142 deletions(-) diff --git a/tools/serialdump.c b/tools/serialdump.c index 1fc93ef49..b2822d6bf 100644 --- a/tools/serialdump.c +++ b/tools/serialdump.c @@ -1,4 +1,5 @@ #define _GNU_SOURCE +/*---------------------------------------------------------------------------*/ #include #include #include @@ -9,15 +10,16 @@ #include #include #include - +/*---------------------------------------------------------------------------*/ #define BAUDRATE B115200 #define BAUDRATE_S "115200" +/*---------------------------------------------------------------------------*/ #ifdef linux #define MODEMDEVICE "/dev/ttyS0" #else #define MODEMDEVICE "/dev/com1" #endif /* linux */ - +/*---------------------------------------------------------------------------*/ #define SLIP_END 0300 #define SLIP_ESC 0333 #define SLIP_ESC_END 0334 @@ -38,9 +40,11 @@ #define MODE_SLIP_AUTO 6 #define MODE_SLIP 7 #define MODE_SLIP_HIDE 8 +/*---------------------------------------------------------------------------*/ + static unsigned char rxbuf[2048]; - +/*---------------------------------------------------------------------------*/ static int usage(int result) { @@ -54,7 +58,7 @@ usage(int result) printf(" (see man page for strftime() for format description)\n"); return result; } - +/*---------------------------------------------------------------------------*/ static void print_hex_line(char *prefix, unsigned char *outbuf, int index) { @@ -82,13 +86,13 @@ print_hex_line(char *prefix, unsigned char *outbuf, int index) } } } - +/*---------------------------------------------------------------------------*/ static void intHandler(int sig) { exit(0); } - +/*---------------------------------------------------------------------------*/ int main(int argc, char **argv) { @@ -111,57 +115,57 @@ main(int argc, char **argv) while(index < argc) { if(argv[index][0] == '-') { switch(argv[index][1]) { - case 'b': - /* set speed */ - if(strcmp(&argv[index][2], "38400") == 0) { - speed = B38400; - speedname = "38400"; - } else if(strcmp(&argv[index][2], "19200") == 0) { - speed = B19200; - speedname = "19200"; - } else if(strcmp(&argv[index][2], "57600") == 0) { - speed = B57600; - speedname = "57600"; - } else if(strcmp(&argv[index][2], "115200") == 0) { - speed = B115200; - speedname = "115200"; - } else { - fprintf(stderr, "unsupported speed: %s\n", &argv[index][2]); - return usage(1); - } - break; - case 'x': - mode = MODE_HEX; - break; - case 'i': - mode = MODE_INT; - break; - case 's': - switch(argv[index][2]) { - case 'n': - mode = MODE_SLIP_HIDE; - break; - case 'o': - mode = MODE_SLIP; - break; - default: - mode = MODE_SLIP_AUTO; - break; - } - break; - case 'T': - if(strlen(&argv[index][2]) == 0) { - timeformat = "%Y-%m-%d %H:%M:%S"; - } else { - timeformat = &argv[index][2]; - } - mode = MODE_START_DATE; - break; - case 'h': - return usage(0); - default: - fprintf(stderr, "unknown option '%c'\n", argv[index][1]); + case 'b': + /* set speed */ + if(strcmp(&argv[index][2], "38400") == 0) { + speed = B38400; + speedname = "38400"; + } else if(strcmp(&argv[index][2], "19200") == 0) { + speed = B19200; + speedname = "19200"; + } else if(strcmp(&argv[index][2], "57600") == 0) { + speed = B57600; + speedname = "57600"; + } else if(strcmp(&argv[index][2], "115200") == 0) { + speed = B115200; + speedname = "115200"; + } else { + fprintf(stderr, "unsupported speed: %s\n", &argv[index][2]); return usage(1); + } + break; + case 'x': + mode = MODE_HEX; + break; + case 'i': + mode = MODE_INT; + break; + case 's': + switch(argv[index][2]) { + case 'n': + mode = MODE_SLIP_HIDE; + break; + case 'o': + mode = MODE_SLIP; + break; + default: + mode = MODE_SLIP_AUTO; + break; + } + break; + case 'T': + if(strlen(&argv[index][2]) == 0) { + timeformat = "%Y-%m-%d %H:%M:%S"; + } else { + timeformat = &argv[index][2]; + } + mode = MODE_START_DATE; + break; + case 'h': + return usage(0); + default: + fprintf(stderr, "unknown option '%c'\n", argv[index][1]); + return usage(1); } index++; } else { @@ -174,8 +178,6 @@ main(int argc, char **argv) } fprintf(stderr, "connecting to %s (%s)", device, speedname); - - #ifndef O_SYNC #define O_SYNC 0 #endif @@ -184,7 +186,7 @@ main(int argc, char **argv) /* Some systems do not support certain parameters (e.g. raspbian) * Just do some random testing. Not sure whether there is a better way * of doing this. */ - if(fd < 0 && errno == EINVAL){ + if(fd < 0 && errno == EINVAL) { fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY | O_SYNC); } #else @@ -241,7 +243,7 @@ main(int argc, char **argv) index = 0; for(;;) { smask = mask; - nfound = select(FD_SETSIZE, &smask, (fd_set *) 0, (fd_set *) 0, (struct timeval *) 0); + nfound = select(FD_SETSIZE, &smask, (fd_set *)0, (fd_set *)0, (struct timeval *)0); if(nfound < 0) { if(errno == EINTR) { fprintf(stderr, "interrupted system call\n"); @@ -260,7 +262,7 @@ main(int argc, char **argv) exit(-1); } else if(n > 0) { /* because commands might need parameters, lines needs to be - separated which means the terminating LF must be sent */ + separated which means the terminating LF must be sent */ /* while(n > 0 && buf[n - 1] < 32) { */ /* n--; */ /* } */ @@ -298,103 +300,103 @@ main(int argc, char **argv) for(i = 0; i < n; i++) { switch(mode) { - case MODE_START_TEXT: - case MODE_TEXT: - printf("%c", buf[i]); - break; - case MODE_START_DATE: { - time_t t; - t = time(&t); - strftime(outbuf, HCOLS, timeformat, localtime(&t)); - printf("%s|", outbuf); - mode = MODE_DATE; + case MODE_START_TEXT: + case MODE_TEXT: + printf("%c", buf[i]); + break; + case MODE_START_DATE: { + time_t t; + t = time(&t); + strftime(outbuf, HCOLS, timeformat, localtime(&t)); + printf("%s|", outbuf); + mode = MODE_DATE; + } + /* continue into the MODE_DATE */ + case MODE_DATE: + printf("%c", buf[i]); + if(buf[i] == '\n') { + mode = MODE_START_DATE; } - /* continue into the MODE_DATE */ - case MODE_DATE: + break; + case MODE_INT: + printf("%03d ", buf[i]); + if(++index >= ICOLS) { + index = 0; + printf("\n"); + } + break; + case MODE_HEX: + rxbuf[index++] = buf[i]; + if(index >= HCOLS) { + print_hex_line("", rxbuf, index); + index = 0; + printf("\n"); + } + break; + + case MODE_SLIP_AUTO: + case MODE_SLIP_HIDE: + if(!flags && (buf[i] != SLIP_END)) { + /* Not a SLIP packet? */ printf("%c", buf[i]); - if(buf[i] == '\n') { - mode = MODE_START_DATE; - } break; - case MODE_INT: - printf("%03d ", buf[i]); - if(++index >= ICOLS) { + } + /* continue to slip only mode */ + case MODE_SLIP: + switch(buf[i]) { + case SLIP_ESC: + lastc = SLIP_ESC; + break; + + case SLIP_END: + if(index > 0) { + if(flags != 2 && mode != MODE_SLIP_HIDE) { + /* not overflowed: show packet */ + print_hex_line("SLIP: ", rxbuf, index > HCOLS ? HCOLS : index); + printf("\n"); + } + lastc = '\0'; index = 0; - printf("\n"); + flags = 0; + } else { + flags = !flags; } break; - case MODE_HEX: + + default: + if(lastc == SLIP_ESC) { + lastc = '\0'; + + /* Previous read byte was an escape byte, so this byte will be + interpreted differently from others. */ + switch(buf[i]) { + case SLIP_ESC_END: + buf[i] = SLIP_END; + break; + case SLIP_ESC_ESC: + buf[i] = SLIP_ESC; + break; + } + } + rxbuf[index++] = buf[i]; - if(index >= HCOLS) { - print_hex_line("", rxbuf, index); + if(index >= sizeof(rxbuf)) { + fprintf(stderr, "**** slip overflow\n"); index = 0; - printf("\n"); - } - break; - - case MODE_SLIP_AUTO: - case MODE_SLIP_HIDE: - if(!flags && (buf[i] != SLIP_END)) { - /* Not a SLIP packet? */ - printf("%c", buf[i]); - break; - } - /* continue to slip only mode */ - case MODE_SLIP: - switch(buf[i]) { - case SLIP_ESC: - lastc = SLIP_ESC; - break; - - case SLIP_END: - if(index > 0) { - if(flags != 2 && mode != MODE_SLIP_HIDE) { - /* not overflowed: show packet */ - print_hex_line("SLIP: ", rxbuf, index > HCOLS ? HCOLS : index); - printf("\n"); - } - lastc = '\0'; - index = 0; - flags = 0; - } else { - flags = !flags; - } - break; - - default: - if(lastc == SLIP_ESC) { - lastc = '\0'; - - /* Previous read byte was an escape byte, so this byte will be - interpreted differently from others. */ - switch(buf[i]) { - case SLIP_ESC_END: - buf[i] = SLIP_END; - break; - case SLIP_ESC_ESC: - buf[i] = SLIP_ESC; - break; - } - } - - rxbuf[index++] = buf[i]; - if(index >= sizeof(rxbuf)) { - fprintf(stderr, "**** slip overflow\n"); - index = 0; - flags = 2; - } - break; + flags = 2; } break; + } + break; } } /* after processing for some output modes */ if(index > 0) { switch(mode) { - case MODE_HEX: - print_hex_line("", rxbuf, index); - break; + case MODE_HEX: + print_hex_line("", rxbuf, index); + break; } } fflush(stdout); From a81ff510f58b6e8fee21cddabaca0b74090555f5 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 12 May 2018 16:20:49 +0100 Subject: [PATCH 135/485] Provide a macro for the unknown baudrate --- tools/tools-utils.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/tools-utils.h b/tools/tools-utils.h index 4b996cc75..c3e655305 100644 --- a/tools/tools-utils.h +++ b/tools/tools-utils.h @@ -35,6 +35,9 @@ #include +/* The unspecified baudrate */ +#define BUNKNOWN -2 + #if __APPLE__ #ifndef B460800 #define B460800 460800 From aa926ee288c907761664c71a1d530701e7d81ace Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 12 May 2018 16:21:08 +0100 Subject: [PATCH 136/485] Remove dead code block --- tools/serialdump.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tools/serialdump.c b/tools/serialdump.c index b2822d6bf..d9bb986f2 100644 --- a/tools/serialdump.c +++ b/tools/serialdump.c @@ -230,12 +230,6 @@ main(int argc, char **argv) exit(-1); } - /* Make read() return immediately */ - /* if (fcntl(fd, F_SETFL, FNDELAY) < 0) { */ - /* perror("\ncould not set fcntl"); */ - /* exit(-1); */ - /* } */ - FD_ZERO(&mask); FD_SET(fd, &mask); FD_SET(fileno(stdin), &mask); From 64ad54d692ef2d5047de9c4e997efb06fc45b99b Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 12 May 2018 16:24:05 +0100 Subject: [PATCH 137/485] Fix usage string --- tools/serialdump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/serialdump.c b/tools/serialdump.c index d9bb986f2..316cc517e 100644 --- a/tools/serialdump.c +++ b/tools/serialdump.c @@ -48,7 +48,7 @@ static unsigned char rxbuf[2048]; static int usage(int result) { - printf("Usage: serialdump [-x] [-s[on]] [-i] [-bSPEED] [SERIALDEVICE]\n"); + printf("Usage: serialdump [-x] [-s[on]] [-i] [-bSPEED] T[format] [SERIALDEVICE]\n"); printf(" -x for hexadecimal output\n"); printf(" -i for decimal output\n"); printf(" -s for automatic SLIP mode\n"); From b2bd5ed662f90f4391a25f9a115b70fa1d8a75f6 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 12 May 2018 16:25:33 +0100 Subject: [PATCH 138/485] Tidy-up handling of O_SYNC and O_DIRECT --- tools/serialdump.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/tools/serialdump.c b/tools/serialdump.c index 316cc517e..02e3df15e 100644 --- a/tools/serialdump.c +++ b/tools/serialdump.c @@ -41,8 +41,12 @@ #define MODE_SLIP 7 #define MODE_SLIP_HIDE 8 /*---------------------------------------------------------------------------*/ +#ifndef O_SYNC +#define O_SYNC 0 +#endif - +#define OPEN_FLAGS (O_RDWR | O_NOCTTY | O_NDELAY | O_SYNC) +/*---------------------------------------------------------------------------*/ static unsigned char rxbuf[2048]; /*---------------------------------------------------------------------------*/ static int @@ -176,22 +180,13 @@ main(int argc, char **argv) } } } - fprintf(stderr, "connecting to %s (%s)", device, speedname); -#ifndef O_SYNC -#define O_SYNC 0 -#endif -#ifdef O_DIRECT - fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY | O_DIRECT | O_SYNC); - /* Some systems do not support certain parameters (e.g. raspbian) - * Just do some random testing. Not sure whether there is a better way - * of doing this. */ - if(fd < 0 && errno == EINVAL) { - fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY | O_SYNC); } -#else - fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY | O_SYNC); -#endif + + fprintf(stderr, "connecting to %s", device); + + fd = open(device, OPEN_FLAGS); + if(fd < 0) { fprintf(stderr, "\n"); perror("open"); From 93608baed40a898c38ccd0ac3e30ed79d6ebed93 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 12 May 2018 16:28:56 +0100 Subject: [PATCH 139/485] Improve baudrate handling --- tools/serialdump.c | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/tools/serialdump.c b/tools/serialdump.c index 02e3df15e..ed4f6d85d 100644 --- a/tools/serialdump.c +++ b/tools/serialdump.c @@ -1,5 +1,7 @@ #define _GNU_SOURCE /*---------------------------------------------------------------------------*/ +#include "tools-utils.h" + #include #include #include @@ -13,6 +15,8 @@ /*---------------------------------------------------------------------------*/ #define BAUDRATE B115200 #define BAUDRATE_S "115200" + +speed_t b_rate = BAUDRATE; /*---------------------------------------------------------------------------*/ #ifdef linux #define MODEMDEVICE "/dev/ttyS0" @@ -105,8 +109,7 @@ main(int argc, char **argv) struct termios options; fd_set mask, smask; int fd; - speed_t speed = BAUDRATE; - char *speedname = BAUDRATE_S; + int baudrate = BUNKNOWN; char *device = MODEMDEVICE; char *timeformat = NULL; unsigned char buf[BUFSIZE]; @@ -120,23 +123,7 @@ main(int argc, char **argv) if(argv[index][0] == '-') { switch(argv[index][1]) { case 'b': - /* set speed */ - if(strcmp(&argv[index][2], "38400") == 0) { - speed = B38400; - speedname = "38400"; - } else if(strcmp(&argv[index][2], "19200") == 0) { - speed = B19200; - speedname = "19200"; - } else if(strcmp(&argv[index][2], "57600") == 0) { - speed = B57600; - speedname = "57600"; - } else if(strcmp(&argv[index][2], "115200") == 0) { - speed = B115200; - speedname = "115200"; - } else { - fprintf(stderr, "unsupported speed: %s\n", &argv[index][2]); - return usage(1); - } + baudrate = atoi(&argv[index][2]); break; case 'x': mode = MODE_HEX; @@ -181,6 +168,12 @@ main(int argc, char **argv) } } + if(baudrate != BUNKNOWN) { + b_rate = select_baudrate(baudrate); + if(b_rate == 0) { + fprintf(stderr, "unknown baudrate %d\n", baudrate); + exit(-1); + } } fprintf(stderr, "connecting to %s", device); @@ -203,9 +196,10 @@ main(int argc, char **argv) perror("could not get options"); exit(-1); } - /* fprintf(stderr, "serial options set\n"); */ - cfsetispeed(&options, speed); - cfsetospeed(&options, speed); + + cfsetispeed(&options, b_rate); + cfsetospeed(&options, b_rate); + /* Enable the receiver and set local mode */ options.c_cflag |= (CLOCAL | CREAD); /* Mask the character size bits and turn off (odd) parity */ From 4d97186df237030adafa05ed6db0876bbbb93f5e Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 12 May 2018 16:29:24 +0100 Subject: [PATCH 140/485] Support tunslip6 and serialdump with a single makefile --- tools/Makefile | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tools/Makefile b/tools/Makefile index ef1711d7c..a17086730 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -1,8 +1,13 @@ -all: tunslip6 +APPS = tunslip6 serialdump +LIB_SRCS = tools-utils.c +DEPEND = tools-utils.h -CFLAGS += -Wall -Werror +all: $(APPS) -tunslip6: tools-utils.c tunslip6.c +CFLAGS += -Wall -Werror -O2 + +$(APPS) : % : %.c $(LIB_SRCS) $(DEPEND) + $(CC) $(CFLAGS) $< $(LIB_SRCS) -o $@ clean: - rm -f *.o tunslip6 + rm -f $(APPS) From 1d551724568be4ecaae0571379dcb485f0f84a2a Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 12 May 2018 16:29:38 +0100 Subject: [PATCH 141/485] Remove obsolete line in gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index f59be6e16..444d6ee24 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,6 @@ Makefile.target Makefile.*.defines tools/doxygen/html patches-* -tools/tunslip tools/tunslip6 build tools/coffee-manager/build/ From 1c48307690a4b8c723fd15b50cd9f3125ed5702c Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 12 May 2018 16:29:55 +0100 Subject: [PATCH 142/485] gitignore the serialdump binary --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 444d6ee24..a40863398 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ Makefile.*.defines tools/doxygen/html patches-* tools/tunslip6 +tools/serialdump build tools/coffee-manager/build/ tools/coffee-manager/coffee.jar From 8c347f96d73adb32f2cc78592646ff819828d0ca Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 12 May 2018 19:36:30 +0100 Subject: [PATCH 143/485] gitignore files created by make serialdump --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a40863398..8bcfac060 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ tools/doxygen/html patches-* tools/tunslip6 tools/serialdump +serialdump-* build tools/coffee-manager/build/ tools/coffee-manager/coffee.jar From 37f14efad503de8563ef25167cc24ff0c7a0da1c Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 12 May 2018 17:34:29 +0100 Subject: [PATCH 144/485] Harmonize building of tools from within an example dir --- Makefile.include | 3 +++ Makefile.tools | 11 +++++++++++ arch/platform/jn516x/Makefile.jn516x | 3 --- .../rpl-border-router/embedded/Makefile.embedded | 12 +++++------- 4 files changed, 19 insertions(+), 10 deletions(-) create mode 100644 Makefile.tools diff --git a/Makefile.include b/Makefile.include index de0606ad4..105459d4d 100644 --- a/Makefile.include +++ b/Makefile.include @@ -10,6 +10,9 @@ WERROR ?= 1 include $(CONTIKI)/Makefile.identify-target +### Include Makefile.tools to pull in targets that allow us to build tools dir +include $(CONTIKI)/Makefile.tools + CONTIKI_NG_TARGET_LIB = contiki-ng-$(TARGET).a ifeq ($(DEFINES),) diff --git a/Makefile.tools b/Makefile.tools new file mode 100644 index 000000000..6dd978ee1 --- /dev/null +++ b/Makefile.tools @@ -0,0 +1,11 @@ +TOOLS_DIR = $(CONTIKI)/tools +TOOL_DEPS = $(TOOLS_DIR)/tools-utils.c $(TOOLS_DIR)/tools-utils.h + +TUNSLIP6 = $(TOOLS_DIR)/tunslip6 +SERIAL_DUMP_BIN = $(TOOLS_DIR)/serialdump + +$(SERIAL_DUMP_BIN): $(TOOLS_DIR)/serialdump.c $(TOOL_DEPS) + make -C $(TOOLS_DIR) serialdump + +$(TUNSLIP6): $(TOOLS_DIR)/tunslip6.c $(TOOL_DEPS) + make -C $(TOOLS_DIR) tunslip6 diff --git a/arch/platform/jn516x/Makefile.jn516x b/arch/platform/jn516x/Makefile.jn516x index 93ba5f296..2dbe0cdef 100644 --- a/arch/platform/jn516x/Makefile.jn516x +++ b/arch/platform/jn516x/Makefile.jn516x @@ -299,9 +299,6 @@ serialdumpall: UART_BAUDRATE ?= 1000000 -$(CONTIKI)/tools/tunslip6: $(CONTIKI)/tools/tunslip6.c - ($(MAKE) -C $(CONTIKI)/tools tunslip6 CFLAGS= LDFLAGS= LDLIBS= INCFLAGS=) - $(SERIALDUMP): $(CONTIKI)/tools/jn516x/serialdump.c (cd $(CONTIKI)/tools/jn516x; ${MAKE} $(notdir $(SERIALDUMP))) diff --git a/os/services/rpl-border-router/embedded/Makefile.embedded b/os/services/rpl-border-router/embedded/Makefile.embedded index c62f7df54..8324722fc 100644 --- a/os/services/rpl-border-router/embedded/Makefile.embedded +++ b/os/services/rpl-border-router/embedded/Makefile.embedded @@ -1,9 +1,7 @@ -$(CONTIKI)/tools/tunslip6: $(CONTIKI)/tools/tunslip6.c - (cd $(CONTIKI)/tools && $(MAKE) tunslip6) - PREFIX ?= fd00::1/64 -connect-router: $(CONTIKI)/tools/tunslip6 - sudo $(CONTIKI)/tools/tunslip6 $(PREFIX) -connect-router-cooja: $(CONTIKI)/tools/tunslip6 - sudo $(CONTIKI)/tools/tunslip6 -a 127.0.0.1 $(PREFIX) +connect-router: $(TUNSLIP6) + sudo $(TUNSLIP6) $(PREFIX) + +connect-router-cooja: $(TUNSLIP6) + sudo $(TUNSLIP6) -a 127.0.0.1 $(PREFIX) From 11f563dc98b9f622a8247c0a4d2c36723cc3262b Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 12 May 2018 17:35:51 +0100 Subject: [PATCH 145/485] Harmonize login, serialdump and serialvew across all platforms --- Makefile.embedded | 18 ++++++++++++ Makefile.include | 11 ++++++- arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx | 18 ++---------- arch/platform/jn516x/Makefile.jn516x | 29 +++++-------------- arch/platform/sky/Makefile.common | 20 ++----------- arch/platform/zoul/Makefile.zoul | 10 ++----- 6 files changed, 43 insertions(+), 63 deletions(-) create mode 100644 Makefile.embedded diff --git a/Makefile.embedded b/Makefile.embedded new file mode 100644 index 000000000..a0967b628 --- /dev/null +++ b/Makefile.embedded @@ -0,0 +1,18 @@ +.PHONY: login serialdump serialview + +BAUDRATE ?= 115200 +TIMESTAMP = $(CONTIKI)/tools/timestamp +ifeq ($(HOST_OS),Windows) + SERIALDUMP = $(SERIAL_DUMP_BIN) +else + SERIALDUMP = rlwrap $(SERIAL_DUMP_BIN) +endif + +serialdump: $(SERIAL_DUMP_BIN) + $(SERIALDUMP) -b$(BAUDRATE) $(PORT) | $(TIMESTAMP) | tee serialdump-`date +%Y%m%d-%H%M` + +serialview: $(SERIAL_DUMP_BIN) + $(SERIALDUMP) -b$(BAUDRATE) $(PORT) | $(TIMESTAMP) + +login: $(SERIAL_DUMP_BIN) + $(SERIALDUMP) -b$(BAUDRATE) $(PORT) diff --git a/Makefile.include b/Makefile.include index 105459d4d..f24124e83 100644 --- a/Makefile.include +++ b/Makefile.include @@ -396,7 +396,7 @@ endif usage: @echo "Usage:" - @echo " make [TARGET=(TARGET)] [BOARD=(BOARD)] [DEFINES=(DEFINES)] [target]" + @echo " make [TARGET=(TARGET)] [BOARD=(BOARD)] [DEFINES=(DEFINES)] [PORT=(PORT)] [target]" @echo "" @echo "Typical usage:" @echo " make [TARGET=(TARGET)] [BOARD=(BOARD)] [all]" @@ -417,6 +417,9 @@ usage: @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)" + @echo " login View the serial output of the device connected to PORT" + @echo " serialview Same as login, but prepend serial output with a unix timestamp" + @echo " serialdump same as serialview, but also save the output to a file" help: usage @@ -462,6 +465,12 @@ endif @echo "To view more Make variables, edit $(CONTIKI)/Makefile.include, rule 'viewconf'" @echo "To view more C variables, edit $(CONTIKI)/tools/viewconf.c" +### Include Makefile.embedded for relevant platforms, in order to pull in +### rules for login, serialview etc +ifeq ($(findstring $(TARGET),native cooja),) + include $(CONTIKI)/Makefile.embedded +endif + # Don't treat %.$(TARGET) as an intermediate file because it is # in fact the primary target. .PRECIOUS: %.$(TARGET) diff --git a/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx b/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx index ef7c47443..4845b36ba 100644 --- a/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx +++ b/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx @@ -88,21 +88,7 @@ else @echo "This board cannot be programmed through the ROM bootloader and therefore does not support the .upload target." endif -# Check if we are running under Windows -ifeq ($(HOST_OS),Windows) - SERIALDUMP ?= $(CONTIKI)/tools/sky/serialdump-windows -else -ifeq ($(HOST_OS),Darwin) - SERIALDUMP ?= rlwrap $(CONTIKI)/tools/sky/serialdump-macos -else - # Else assume Linux - SERIALDUMP ?= rlwrap $(CONTIKI)/tools/sky/serialdump-linux -endif -endif - -UART_BAUDRATE = 115200 - -login: - $(SERIALDUMP) -b$(UART_BAUDRATE) $(PORT) +### For the login etc targets +BAUDRATE = 115200 include $(CONTIKI)/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 diff --git a/arch/platform/jn516x/Makefile.jn516x b/arch/platform/jn516x/Makefile.jn516x index 2dbe0cdef..6cff59c65 100644 --- a/arch/platform/jn516x/Makefile.jn516x +++ b/arch/platform/jn516x/Makefile.jn516x @@ -175,17 +175,14 @@ MOTELIST = python $(CONTIKI)/tools/jn516x/mote-list.py ifeq ($(HOST_OS),Windows) USBDEVPREFIX=/dev/com USBDEVBASENAME=COM - SERIALDUMP ?= $(CONTIKI)/tools/jn516x/serialdump-windows else ifeq ($(HOST_OS),Darwin) USBDEVPREFIX= USBDEVBASENAME=/dev/tty.usbserial- - SERIALDUMP ?= rlwrap $(CONTIKI)/tools/jn516x/serialdump-macos else # Else we assume Linux USBDEVPREFIX= USBDEVBASENAME=/dev/ttyUSB - SERIALDUMP ?= rlwrap $(CONTIKI)/tools/jn516x/serialdump-linux endif endif @@ -195,7 +192,7 @@ ifndef MOTE $(error MOTE not defined! You must specify which MOTE (serial port) to use) endif endif -PORT = $(USBDEVBASENAME)$(MOTE) +DEV_PORT = $(USBDEVBASENAME)$(MOTE) #### make targets @@ -255,19 +252,19 @@ endif ### Upload target to one jn516x mote specified by MOTE=portNumber ifeq ($(HOST_OS),Windows) %.upload: %.$(TARGET).bin - ${FLASH_PROGRAMMER} -a -c $(PORT) -B 1000000 -s -w -f $< + ${FLASH_PROGRAMMER} -a -c $(DEV_PORT) -B 1000000 -s -w -f $< else %.upload: %.$(TARGET).bin - ${FLASH_PROGRAMMER} -V 10 -v -s $(PORT) -I 38400 -P 1000000 -f $< + ${FLASH_PROGRAMMER} -V 10 -v -s $(DEV_PORT) -I 38400 -P 1000000 -f $< endif ### Flash the given file ifeq ($(HOST_OS),Windows) %.flash: ${FLASH_PROGRAMMER} - ${FLASH_PROGRAMMER} -a -c $(PORT) -B 1000000 -s -w -f $*.$(TARGET).bin + ${FLASH_PROGRAMMER} -a -c $(DEV_PORT) -B 1000000 -s -w -f $*.$(TARGET).bin else %.flash: ${FLASH_PROGRAMMER} - ${FLASH_PROGRAMMER} -V 10 -v -s $(PORT) -I 38400 -P 1000000 -s -f $*.$(TARGET).bin + ${FLASH_PROGRAMMER} -V 10 -v -s $(DEV_PORT) -I 38400 -P 1000000 -s -f $*.$(TARGET).bin endif ### List the ports with connected jn516x motes @@ -297,16 +294,6 @@ serialdumpall: ### UART_BAUDRATE: i.e., 115200. default is 1000000 ### example: make TARGET=jn516x UART_BAUDRATE=115200 login MOTE=1 -UART_BAUDRATE ?= 1000000 - -$(SERIALDUMP): $(CONTIKI)/tools/jn516x/serialdump.c - (cd $(CONTIKI)/tools/jn516x; ${MAKE} $(notdir $(SERIALDUMP))) - -login: $(SERIALDUMP) - $(SERIALDUMP) -b${UART_BAUDRATE} $(USBDEVPREFIX)$(PORT) - -serialview: $(SERIALDUMP) - $(SERIALDUMP) -b${UART_BAUDRATE} $(USBDEVPREFIX)$(PORT) | $(CONTIKI)/tools/timestamp - -serialdump: $(SERIALDUMP) - $(SERIALDUMP) -b${UART_BAUDRATE} $(USBDEVPREFIX)$(PORT) | $(CONTIKI)/tools/timestamp | tee serialdump-$(notdir $(PORT))-`date +%Y%m%d-%H%M` +### For the login etc targets +BAUDRATE = 1000000 +PORT = $(USBDEVPREFIX)$(DEV_PORT) diff --git a/arch/platform/sky/Makefile.common b/arch/platform/sky/Makefile.common index c8de6d6ad..5018da3da 100644 --- a/arch/platform/sky/Makefile.common +++ b/arch/platform/sky/Makefile.common @@ -54,7 +54,6 @@ else ifeq ($(HOST_OS),Darwin) ifndef MOTELIST USBDEVPREFIX= - 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 +74,6 @@ else # Else we assume Linux ifndef MOTELIST USBDEVPREFIX= - 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) @@ -171,21 +169,7 @@ $(CONTIKI)/tools/tunslip: (cd $(CONTIKI)/tools; $(MAKE) tunslip) ifdef MOTE -serialdump: - $(SERIALDUMP) -b115200 $(USBDEVPREFIX)$(word $(MOTE), $(CMOTES)) | $(CONTIKI)/tools/timestamp | tee serialdump-`date +%Y%m%d-%H%M` - -serialview: - $(SERIALDUMP) -b115200 $(USBDEVPREFIX)$(word $(MOTE), $(CMOTES)) | $(CONTIKI)/tools/timestamp - -login: - $(SERIALDUMP) -b115200 $(USBDEVPREFIX)$(word $(MOTE), $(CMOTES)) + PORT = $(USBDEVPREFIX)$(word $(MOTE), $(CMOTES)) else -serialdump: - $(SERIALDUMP) -b115200 $(USBDEVPREFIX)$(firstword $(CMOTES)) | $(CONTIKI)/tools/timestamp | tee serialdump-`date +%Y%m%d-%H%M` - -serialview: - $(SERIALDUMP) -b115200 $(USBDEVPREFIX)$(firstword $(CMOTES)) | $(CONTIKI)/tools/timestamp - -login: - $(SERIALDUMP) -b115200 $(USBDEVPREFIX)$(firstword $(CMOTES)) + PORT = $(USBDEVPREFIX)$(firstword $(CMOTES)) endif diff --git a/arch/platform/zoul/Makefile.zoul b/arch/platform/zoul/Makefile.zoul index e7e4af709..38b86fd13 100644 --- a/arch/platform/zoul/Makefile.zoul +++ b/arch/platform/zoul/Makefile.zoul @@ -56,11 +56,9 @@ ifeq ($(HOST_OS),Darwin) USBDEVPREFIX= MOTELIST := $(CONTIKI)/tools/zolertia/motelist-zolertia-macos MOTES := $(shell $(MOTELIST) -c 2>&- | cut -f 2 -d ,) - SERIALDUMP := rlwrap $(CONTIKI)/tools/sky/serialdump-macos else ### If we are not running under Mac, we assume Linux USBDEVPREFIX= - 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+)-);') @@ -103,8 +101,6 @@ zoul-motelist: zoul-motes: @echo $(MOTES) -serialview: - $(SERIALDUMP) -b115200 $(USBDEVPREFIX)$(firstword $(MOTES)) | $(CONTIKI)/tools/timestamp - -login: - $(SERIALDUMP) -b115200 $(USBDEVPREFIX)$(firstword $(MOTES)) +### For the login etc targets +BAUDRATE = 115200 +PORT = $(USBDEVPREFIX)$(firstword $(MOTES)) From a73f126c1d553cecc3ab6e3803952ef60a6c2332 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 12 May 2018 18:02:15 +0100 Subject: [PATCH 146/485] Adjust travis tests for tools/ --- tests/05-compile-tools/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/05-compile-tools/Makefile b/tests/05-compile-tools/Makefile index 43f84405a..a89a585e4 100644 --- a/tests/05-compile-tools/Makefile +++ b/tests/05-compile-tools/Makefile @@ -25,7 +25,7 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. -TOOLS=tools tools/sky tools/jn516x +TOOLS=tools BASEDIR=../../ TESTLOGS=$(subst /,__,$(patsubst %,%.testlog, $(TOOLS))) From 4e7ab7ff2608caf92ed54fa9df4e3cb63de5cbc5 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Mon, 14 May 2018 16:58:40 +0100 Subject: [PATCH 147/485] Run serialdump without rlwrap if it is missing and warn the user --- Makefile.embedded | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Makefile.embedded b/Makefile.embedded index a0967b628..1c1a7b8ec 100644 --- a/Makefile.embedded +++ b/Makefile.embedded @@ -1,11 +1,20 @@ -.PHONY: login serialdump serialview +RLWRAPGOALS = login serialdump serialview + +.PHONY: $(RLWRAPGOALS) BAUDRATE ?= 115200 TIMESTAMP = $(CONTIKI)/tools/timestamp ifeq ($(HOST_OS),Windows) SERIALDUMP = $(SERIAL_DUMP_BIN) else - SERIALDUMP = rlwrap $(SERIAL_DUMP_BIN) + RLWRAP = $(notdir $(shell which rlwrap)) + ifeq ($(RLWRAP),) + ifneq ($(filter $(RLWRAPGOALS),$(MAKECMDGOALS)),) + $(info Running serialdump without rlwrap support.) + $(info Consider installing rlwarp in order to be able to use command history) + endif + endif + SERIALDUMP = $(RLWRAP) $(SERIAL_DUMP_BIN) endif serialdump: $(SERIAL_DUMP_BIN) From da9b35e8158e7f88c5edac3b31377f0fe15b672a Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Tue, 15 May 2018 17:48:50 +0100 Subject: [PATCH 148/485] Change time format output --- tools/serialdump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/serialdump.c b/tools/serialdump.c index ed4f6d85d..ab82024a3 100644 --- a/tools/serialdump.c +++ b/tools/serialdump.c @@ -291,7 +291,7 @@ main(int argc, char **argv) time_t t; t = time(&t); strftime(outbuf, HCOLS, timeformat, localtime(&t)); - printf("%s|", outbuf); + printf("[%s] ", outbuf); mode = MODE_DATE; } /* continue into the MODE_DATE */ From 0dd46af8e6d21b92f74d63553449c09343bfc73e Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Tue, 15 May 2018 17:49:32 +0100 Subject: [PATCH 149/485] Timestamp lines using serialdump -T instead of tools/timestamp --- Makefile.embedded | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile.embedded b/Makefile.embedded index 1c1a7b8ec..67d12ef34 100644 --- a/Makefile.embedded +++ b/Makefile.embedded @@ -3,7 +3,7 @@ RLWRAPGOALS = login serialdump serialview .PHONY: $(RLWRAPGOALS) BAUDRATE ?= 115200 -TIMESTAMP = $(CONTIKI)/tools/timestamp + ifeq ($(HOST_OS),Windows) SERIALDUMP = $(SERIAL_DUMP_BIN) else @@ -18,10 +18,10 @@ else endif serialdump: $(SERIAL_DUMP_BIN) - $(SERIALDUMP) -b$(BAUDRATE) $(PORT) | $(TIMESTAMP) | tee serialdump-`date +%Y%m%d-%H%M` + $(SERIALDUMP) -b$(BAUDRATE) -T $(PORT) | tee serialdump-`date +%Y%m%d-%H%M` serialview: $(SERIAL_DUMP_BIN) - $(SERIALDUMP) -b$(BAUDRATE) $(PORT) | $(TIMESTAMP) + $(SERIALDUMP) -b$(BAUDRATE) -T $(PORT) login: $(SERIAL_DUMP_BIN) $(SERIALDUMP) -b$(BAUDRATE) $(PORT) From e1a81808df09e7f2e36a2b7ed21dec86b63bbba4 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Tue, 15 May 2018 17:50:56 +0100 Subject: [PATCH 150/485] Remove tools/timestamp, which is no longer in use --- tools/timestamp | 3 --- 1 file changed, 3 deletions(-) delete mode 100755 tools/timestamp diff --git a/tools/timestamp b/tools/timestamp deleted file mode 100755 index 16db8c988..000000000 --- a/tools/timestamp +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -# We run perl through a shell to avoid having to hard-code the path to perl -perl -e '$|=1; while(<>) {print time . " $_";}' From cdfcf9003f8a4b6e7b2b8f12995eba7973e4c455 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Tue, 15 May 2018 22:24:22 +0100 Subject: [PATCH 151/485] Make serialdump timestamp format configurable from the command line --- Makefile.embedded | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile.embedded b/Makefile.embedded index 67d12ef34..8253b39af 100644 --- a/Makefile.embedded +++ b/Makefile.embedded @@ -3,6 +3,7 @@ RLWRAPGOALS = login serialdump serialview .PHONY: $(RLWRAPGOALS) BAUDRATE ?= 115200 +SERIALDUMP_TIME_FMT ?= ifeq ($(HOST_OS),Windows) SERIALDUMP = $(SERIAL_DUMP_BIN) @@ -18,10 +19,10 @@ else endif serialdump: $(SERIAL_DUMP_BIN) - $(SERIALDUMP) -b$(BAUDRATE) -T $(PORT) | tee serialdump-`date +%Y%m%d-%H%M` + $(SERIALDUMP) -b$(BAUDRATE) -T$(SERIALDUMP_TIME_FMT) $(PORT) | tee serialdump-`date +%Y%m%d-%H%M` serialview: $(SERIAL_DUMP_BIN) - $(SERIALDUMP) -b$(BAUDRATE) -T $(PORT) + $(SERIALDUMP) -b$(BAUDRATE) -T$(SERIALDUMP_TIME_FMT) $(PORT) login: $(SERIAL_DUMP_BIN) $(SERIALDUMP) -b$(BAUDRATE) $(PORT) From c29534f0132e7151cf31d50a310975f758758a8f Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 26 May 2018 13:59:12 +0100 Subject: [PATCH 152/485] Document the various top-level Makefiles --- Makefile.embedded | 5 +++++ Makefile.identify-target | 5 +++++ Makefile.tools | 4 ++++ 3 files changed, 14 insertions(+) diff --git a/Makefile.embedded b/Makefile.embedded index 8253b39af..4654626c4 100644 --- a/Makefile.embedded +++ b/Makefile.embedded @@ -1,3 +1,8 @@ +# This Makefile contains make variables and rules that are only applicable +# to builds for embedded devices (i.e. excluding platforms native and cooja). +# Future extensions to the build system that are of a similar nature (for +# embedded devices only), can be achieved by extending this Makefile here. + RLWRAPGOALS = login serialdump serialview .PHONY: $(RLWRAPGOALS) diff --git a/Makefile.identify-target b/Makefile.identify-target index 7843fdf6a..86e06c093 100644 --- a/Makefile.identify-target +++ b/Makefile.identify-target @@ -1,3 +1,8 @@ +# This Makefile can be used to identify the selected TARGET used for a +# specific build. It can be included by example Makefiles that need to take +# decisions based on TARGET. It is also automatically included by the +# top-level Makefile.include. + ifeq ($(TARGET),) -include Makefile.target ifeq ($(TARGET),) diff --git a/Makefile.tools b/Makefile.tools index 6dd978ee1..041f383b6 100644 --- a/Makefile.tools +++ b/Makefile.tools @@ -1,3 +1,7 @@ +# Some make rules in the main build system depend on the presence of utilities +# under the tools/ dir. For those dependencies, we use this makefile here to +# recursively invoke the respective build under tools/. + TOOLS_DIR = $(CONTIKI)/tools TOOL_DEPS = $(TOOLS_DIR)/tools-utils.c $(TOOLS_DIR)/tools-utils.h From 3e3cb08c7f37114975f30ed1db9d3dbdf1f2dbbc Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 26 May 2018 15:26:20 +0100 Subject: [PATCH 153/485] Move serialdump and tunslip6 to their own subdir --- .gitignore | 4 ++-- Makefile.tools | 16 +++++++++------- tools/{ => serial-io}/Makefile | 0 tools/{ => serial-io}/serialdump.c | 0 tools/{ => serial-io}/tools-utils.c | 3 +-- tools/{ => serial-io}/tools-utils.h | 0 tools/{ => serial-io}/tunslip6.c | 0 7 files changed, 12 insertions(+), 11 deletions(-) rename tools/{ => serial-io}/Makefile (100%) rename tools/{ => serial-io}/serialdump.c (100%) rename tools/{ => serial-io}/tools-utils.c (99%) rename tools/{ => serial-io}/tools-utils.h (100%) rename tools/{ => serial-io}/tunslip6.c (100%) diff --git a/.gitignore b/.gitignore index 8bcfac060..6bab22c32 100644 --- a/.gitignore +++ b/.gitignore @@ -17,8 +17,8 @@ Makefile.target Makefile.*.defines tools/doxygen/html patches-* -tools/tunslip6 -tools/serialdump +tools/serial-io/tunslip6 +tools/serial-io/serialdump serialdump-* build tools/coffee-manager/build/ diff --git a/Makefile.tools b/Makefile.tools index 041f383b6..6151ba83a 100644 --- a/Makefile.tools +++ b/Makefile.tools @@ -3,13 +3,15 @@ # recursively invoke the respective build under tools/. TOOLS_DIR = $(CONTIKI)/tools -TOOL_DEPS = $(TOOLS_DIR)/tools-utils.c $(TOOLS_DIR)/tools-utils.h +SERIAL_IO_TOOL_DIR = $(TOOLS_DIR)/serial-io -TUNSLIP6 = $(TOOLS_DIR)/tunslip6 -SERIAL_DUMP_BIN = $(TOOLS_DIR)/serialdump +SERIAL_IO_TOOL_DEPS = $(addprefix $(SERIAL_IO_TOOL_DIR)/, tools-utils.c tools-utils.h) -$(SERIAL_DUMP_BIN): $(TOOLS_DIR)/serialdump.c $(TOOL_DEPS) - make -C $(TOOLS_DIR) serialdump +TUNSLIP6 = $(SERIAL_IO_TOOL_DIR)/tunslip6 +SERIAL_DUMP_BIN = $(SERIAL_IO_TOOL_DIR)/serialdump -$(TUNSLIP6): $(TOOLS_DIR)/tunslip6.c $(TOOL_DEPS) - make -C $(TOOLS_DIR) tunslip6 +$(SERIAL_DUMP_BIN): $(SERIAL_IO_TOOL_DIR)/serialdump.c $(SERIAL_IO_TOOL_DEPS) + make -C $(SERIAL_IO_TOOL_DIR) serialdump + +$(TUNSLIP6): $(SERIAL_IO_TOOL_DIR)/tunslip6.c $(SERIAL_IO_TOOL_DEPS) + make -C $(SERIAL_IO_TOOL_DIR) tunslip6 diff --git a/tools/Makefile b/tools/serial-io/Makefile similarity index 100% rename from tools/Makefile rename to tools/serial-io/Makefile diff --git a/tools/serialdump.c b/tools/serial-io/serialdump.c similarity index 100% rename from tools/serialdump.c rename to tools/serial-io/serialdump.c diff --git a/tools/tools-utils.c b/tools/serial-io/tools-utils.c similarity index 99% rename from tools/tools-utils.c rename to tools/serial-io/tools-utils.c index 50a50c025..8e292e9b3 100644 --- a/tools/tools-utils.c +++ b/tools/serial-io/tools-utils.c @@ -30,7 +30,7 @@ * */ -#include "tools-utils.h" +#include "tools-utils.h" speed_t select_baudrate(int baudrate) { @@ -159,4 +159,3 @@ select_baudrate(int baudrate) { return 0; } } - diff --git a/tools/tools-utils.h b/tools/serial-io/tools-utils.h similarity index 100% rename from tools/tools-utils.h rename to tools/serial-io/tools-utils.h diff --git a/tools/tunslip6.c b/tools/serial-io/tunslip6.c similarity index 100% rename from tools/tunslip6.c rename to tools/serial-io/tunslip6.c From 285578bbf48b562652e762126ffdd4cd2803ec18 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 27 May 2018 13:35:50 +0100 Subject: [PATCH 154/485] Update travis test for tools/serial-io --- tests/05-compile-tools/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/05-compile-tools/Makefile b/tests/05-compile-tools/Makefile index a89a585e4..6377d6674 100644 --- a/tests/05-compile-tools/Makefile +++ b/tests/05-compile-tools/Makefile @@ -25,7 +25,7 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. -TOOLS=tools +TOOLS=tools/serial-io BASEDIR=../../ TESTLOGS=$(subst /,__,$(patsubst %,%.testlog, $(TOOLS))) From 5f7984354774e2e5ef2ea0cc1e97cdffa2427943 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 27 May 2018 14:48:38 +0100 Subject: [PATCH 155/485] Create the (failed) summary log even when sub-make fails --- tests/00-doxygen/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/00-doxygen/Makefile b/tests/00-doxygen/Makefile index 3d99c5d00..067090b73 100644 --- a/tests/00-doxygen/Makefile +++ b/tests/00-doxygen/Makefile @@ -30,7 +30,7 @@ DOCDIR=../../tools/doxygen all: clean summary doxygen: - @make -C $(DOCDIR) 2> doxygen.err > /dev/null + -@$(MAKE) -C $(DOCDIR) 2> doxygen.err > /dev/null summary: doxygen @( \ @@ -55,4 +55,4 @@ summary: doxygen clean: @rm -f summary doxygen.err - @make -C $(DOCDIR) clean + @$(MAKE) -C $(DOCDIR) clean From 8daaa357f57445c93587e65dfeed91a15b8b1ad2 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 27 May 2018 15:34:33 +0100 Subject: [PATCH 156/485] Remove makefsdata --- tools/makefsdata | 375 ----------------------------------------------- 1 file changed, 375 deletions(-) delete mode 100755 tools/makefsdata diff --git a/tools/makefsdata b/tools/makefsdata deleted file mode 100755 index 5ea48a611..000000000 --- a/tools/makefsdata +++ /dev/null @@ -1,375 +0,0 @@ -#!/usr/bin/perl -#Generate a .c source that preinitializes a file system -#David Kopf July 2009 -#Extended from the existing non-coffee tool - -#The simplest format is used with httpd-fs.c. It contains a linked -#list pointing to file names and file contents. - -#An extension uses the same linked list that points to a the file names -#and contents within a coffee file system having fixed file sizes. -#This allows the content to be rewritten by coffee while still being -#readable by httpd-fs.c New files or sector extension of existing files -#is not possible, but a larger initial sector allocation could be given -#to some files to allow a limited size increase. Since this would leave the -#wrong file size in the linked list, httpd-fs would have to terminate on -#a reverse zero scan like coffee does. Rewriting the linked list would -#probably be OK if in eeprom, but not if in program flash. Suggestions -#for a workaround would be welcome! - -#Lastly a full coffee file system can be preinitialized. File reads must -#then be done using coffee. - -#Assumes the coffee file_header structure is -#struct file_header { -# coffee_page_t log_page; -# uint16_t log_records; -# uint16_t log_record_size; -# coffee_page_t max_pages; -# uint8_t deprecated_eof_hint; -# uint8_t flags=3 for the initial value; -# char name[COFFEE_NAME_LENGTH]; -# } __attribute__((packed)); - -goto DEFAULTS; -START:$version="1.1"; - -#Process options -for($n=0;$n<=$#ARGV;$n++) { - $arg=$ARGV[$n]; - if ($arg eq "-v") { - print "makefsdata Version $version\n"; - } elsif ($arg eq "-A") { - $n++;$attribute=$ARGV[$n]; - } elsif ($arg eq "-C") { - $coffee=1; - } elsif ($arg eq "-c") { - $complement=1; - } elsif ($arg eq "-i") { - $n++;$includefile=$ARGV[$n]; -# } elsif ($arg eq "-p") { -# $n++;$coffee_page_length=$ARGV[$n]; - } elsif ($arg eq "-s") { - $n++;$coffee_sector_size=$ARGV[$n]; - } elsif ($arg eq "-t") { - $n++;$coffee_page_t =$ARGV[$n]; - } elsif ($arg eq "-f") { - $n++;$coffee_name_length=$ARGV[$n]; - } elsif ($arg eq "-S") { - $n++;$sectionname=$ARGV[$n]; - } elsif ($arg eq "-l") { - $linkedlist=1; - } elsif ($arg eq "-d") { - $n++;$directory=$ARGV[$n]; - } elsif ($arg eq "-o") { - $n++;$outputfile=$ARGV[$n]; - $coffeefile=$outputfile; - } else { -DEFAULTS: -#Set up defaults -$coffee=0; -#$coffee_page_length=256; -$coffee_sector_size=256; -$coffee_page_t=1; -$coffee_name_length=16; -$complement=0; -$directory=""; -$outputfile="httpd-fsdata.c"; -$coffeefile="httpd-coffeedata.c"; -$includefile="makefsdata.h"; -$linkedlist=0; -$attribute=""; -$sectionname=".coffeefiles"; -if (!$version) {goto START;} - print "\n"; - print "Usage: makefsdata <-d input_directory> <-o output_file>\n\n"; - print " Generates c source file to pre-initialize a contiki file system.\n"; - print " The default output is a simple linked list readable by httpd-fs.c\n"; - print " and written to $outputfile.\n\n"; - print " The -C option makes a coffee file system to default output $coffeefile.\n"; - print " A linked list can be still be generated for use with httpd-fs.c so long\n"; - print " as coffee does not extend, delete, or add any files.\n\n"; - print " The input directory structure is copied. If input_directory is specified\n"; - print " it becomes the root \"/\". If no input_directory is specified the first\n"; - print " subdirectory found in the current directory is used as the root.\n\n"; - print " WARNING : If the output file exists it will be overwritten without confirmation!\n\n"; - print " Options are:\n"; - print " -v Display the version number\n"; - print " -A attribute Append \"attribute\" to the declaration, e.g. PROGMEM to put data in AVR program flash memory\n"; - print " -C Use coffee file system format\n"; - print " -c Complement the data, useful for obscurity or fast page erases for coffee\n"; - print " -i filename Treat any input files with name \"filename\" as include files.\n"; - print " Useful for giving a server a name and ip address associated with the web content.\n"; - print " The default is $includefile.\n\n"; - print " The following apply only to coffee file system\n"; -# print " -p pagesize Page size in bytes (default $coffee_page_length)\n"; - print " -s sectorsize Sector size in bytes (default $coffee_sector_size)\n"; - print " -t page_t Number of bytes in coffee_page_t (1,2,or 4, default $coffee_page_t)\n"; - print " -f namesize File name field size in bytes (default $coffee_name_length)\n"; - print " -S section Section name for data (default $sectionname)\n"; - print " -l Append a linked list for use with httpd-fs\n"; - exit; - } -} - -#--------------------Configure parameters----------------------- -if ($coffee) { - $outputfile=$coffeefile; - $coffee_header_length=2*$coffee_page_t+$coffee_name_length+6; - if ($coffee_page_t==1) { - $coffeemax=0xff; - } elsif ($coffee_page_t==2) { - $coffeemax=0xffff; - } elsif ($coffee_page_t==4) { - $coffeemax=0xffffffff; - } else { - die "Unsupported coffee_page_t $coffee_page_t\n"; - } -} else { -# $coffee_page_length=1; - $coffee_sector_size=1; - $linkedlist=1; - $coffee_name_length=256; - $coffee_max=0xffffffff; - $coffee_header_length=0; -} -$null="0x00";if ($complement) {$null="0xff";} -$tab=" "; #optional tabs or spaces at beginning of line, e.g. "\t\t" - -#--------------------Create output file------------------------- -#awkward but could not figure out how to compare paths later unless the file exists -- dak -if (!open(OUTPUT, "> $outputfile")) {die "Aborted: Could not create output file $outputfile";} -print(OUTPUT "\n"); -close($outputfile); -use Cwd qw(abs_path); -if (!open(OUTPUT, "> $outputfile")) {die "Aborted: Could not create output file $outputfile";} -$outputfile=abs_path($outputfile); - -#--------------------Get a list of input files------------------ -if ($directory eq "") { - opendir(DIR, "."); - @files = grep { !/^\./ && !/(CVS|~)/ } readdir(DIR); - closedir(DIR); - foreach $file (@files) { - if(-d $file && $file !~ /^\./) { - $directory=$file; - break; - } - } -} -if ($directory eq "") {die "Aborted: No subdirectory in current directory";} -if (!chdir("$directory")) {die "Aborted: Directory \"$directory\" does not exist!";} - -if ($coffee) { - print "Processing directory $directory as root of coffee file system\n"; -} else { - print "Processing directory $directory as root of packed httpd-fs file system\n"; -} -opendir(DIR, "."); -@files = grep { !/^\./ && !/(CVS|~)/ && !/(makefsdata.ignore)/ } readdir(DIR); -closedir(DIR); - -foreach $file (@files) { - if(-d $file && $file !~ /^\./) { - print "Adding subdirectory $file\n"; - opendir(DIR, $file); - @newfiles = grep { !/^\./ && !/(CVS|~)/ } readdir(DIR); - closedir(DIR); -# printf "Adding files @newfiles\n"; - @files = (@files, map { $_ = "$file/$_" } @newfiles); - next; - } -} -#--------------------Write the output file------------------- -print "Writing to $outputfile\n"; -($DAY, $MONTH, $YEAR) = (localtime)[3,4,5]; -printf(OUTPUT "/*********Generated by contiki/tools/makefsdata on %04d-%02d-%02d*********/\n", $YEAR+1900, $MONTH+1, $DAY); -if ($coffee) { - print(OUTPUT "/*For coffee filesystem of sector size $coffee_sector_size and header length $coffee_header_length bytes*/\n"); -} -print(OUTPUT "\n"); -#--------------------Process include file------------------- -foreach $file (@files) {if ($file eq $includefile) { - open(FILE, $file) || die "Aborted: Could not open include file $file\n"; - print "Including text from $file\n"; - $file_length= -s FILE; - read(FILE, $data, $file_length); - print OUTPUT ($data); - close(FILE); - next; #include all include file matches -# break; #include only first include file match -}} - -#--------------------Process data files------------------- -$n=0;$coffeesize=0;$coffeesectors=0; -foreach $file (@files) {if(-f $file) { - if (length($file)>=($coffee_name_length-1)) {die "Aborted: File name $file is too long";} - if (abs_path("$file") eq abs_path("$outputfile")) { - print "Skipping output file $outputfile - recursive input NOT allowed\n"; - next; - } - if ($file eq $includefile) {next;} - open(FILE, $file) || die "Aborted: Could not open file $file\n"; - print "Adding /$file\n"; - if (grep /.png/||/.jpg/||/jpeg/||/.pdf/||/.gif/||/.bin/||/.zip/,$file) {binmode FILE;} - - $file_length= -s FILE; - $file =~ s-^-/-; - $fvar = $file; - $fvar =~ s-/-_-g; - $fvar =~ s-\.-_-g; - - if ($coffee) { - $coffee_sectors=int(($coffee_header_length+$file_length+$coffee_sector_size-1)/$coffee_sector_size); -# $coffee_sectors=sprintf("%.0f",($coffee_header_length+$file_length+$coffee_sector_size-1)/$coffee_sector_size)-1; - $coffee_length=$coffee_sectors*$coffee_sector_size; - } else { - $coffee_length=$file_length+length($file)+1; - } - $flen[$n]=$file_length; - $clen[$n]=$coffee_length; - $n++;$coffeesectors+=$coffee_sectors;$coffeesize+=$coffee_length; - if ($coffee) { - if ($coffeesectors>$coffeemax) { - print "Warning: sector number $coffeesectors overflows allocated sector size in coffee header\n"; - } - print(OUTPUT "\n__attribute__ ((section (\"$sectionname\")))\n"); - print(OUTPUT "volatile const char data".$fvar."[$coffee_length] = {\n"); - } else { - print(OUTPUT "\nconst char data".$fvar."[$coffee_length] $attribute = {\n"); - } - print(OUTPUT "$tab/* $file */\n$tab"); -#--------------------Header----------------------------- -#log_page - if ($coffee) { - print (OUTPUT " "); - for($j=0;$j<$coffee_page_t;$j++) {print (OUTPUT "$ null ,");} -#log_records, log_record_size - for($j=0;$j<4;$j++) {print (OUTPUT "$null, ");} -#max_pages - if ($complement) {$coffee_sectors=$coffee_sectors^0xffffffff;} - if ($coffee_page_t==1) { - printf(OUTPUT "0x%2.2x, ",($coffee_sectors )&0xff); - } elsif ($coffee_page_t==2) { - printf(OUTPUT "0x%2.2x, ",($coffee_sectors>> 8)&0xff); - printf(OUTPUT "0x%2.2x, ",($coffee_sectors )&0xff); - } elsif ($coffee_page_t==4) { - printf(OUTPUT "0x%2.2x, ",($coffee_sectors>>24)&0xff); - printf(OUTPUT "0x%2.2x, ",($coffee_sectors>>16)&0xff); - printf(OUTPUT "0x%2.2x, ",($coffee_sectors>> 8)&0xff); - printf(OUTPUT "0x%2.2x, ",($coffee_sectors )&0xff); - } - if ($complement) {$coffee_sectors=$coffee_sectors^0xffffffff;} -#eof hint and flags - if ($complement) { - print(OUTPUT "0xff, 0xfc,\n$tab"); - } else { - print(OUTPUT "0x00, 0x03,\n$tab"); - } - } - -#-------------------File name-------------------------- - for($j = 0; $j < length($file); $j++) { - $temp=unpack("C", substr($file, $j, 1)); - if ($complement) {$temp=$temp^0xff;} - printf(OUTPUT " %#02.2x,", $temp); - } - if ($coffee) { - for(; $j < $coffee_name_length-1; $j++) {printf(OUTPUT " $null,");} - {print(OUTPUT " $null");} - } else { - {printf(OUTPUT " $null");} - } -#------------------File Data--------------------------- - $coffee_length-=$coffee_header_length; - $i = 10; - while(read(FILE, $data, 1)) { - $temp=unpack("C", $data); - if ($complement) {$temp=$temp^0xff;} - if($i == 10) { - printf(OUTPUT ",\n$tab 0x%2.2x", $temp); - $i = 0; - } else { - printf(OUTPUT ", 0x%2.2x", $temp) - } - $i++;$coffee_length--; - } - - if ($coffee) { - print (OUTPUT ","); - while (--$coffee_length) { - if($i==9) { - print(OUTPUT " $null,\n$tab"); - $i = 0; - } else { - print (OUTPUT " $null,"); - $i++; - } - } - print (OUTPUT " $null"); - } - print (OUTPUT "};\n"); - close(FILE); - push(@fvars, $fvar); - push(@pfiles, $file); -}} - -if ($linkedlist) { -#-------------------httpd_fsdata_file links------------------- -#The non-coffee PROGMEM flash file system for the Raven webserver uses a linked flash list as follows: -print(OUTPUT "\n\n/* Structure of linked list (all offsets relative to start of section):\n"); -print(OUTPUT "struct httpd_fsdata_file {\n"); -print(OUTPUT "$tab const struct httpd_fsdata_file *next; //actual flash address of next link\n"); -print(OUTPUT "$tab const char *name; //offset to coffee file name\n"); -print(OUTPUT "$tab const char *data; //offset to coffee file data\n"); -print(OUTPUT "$tab const int len; //length of file data\n"); -print(OUTPUT "#if HTTPD_FS_STATISTICS == 1 //not enabled since list is in PROGMEM\n"); -print(OUTPUT "$tab uint16_t count; //storage for file statistics\n"); -print(OUTPUT "#endif\n"); -print(OUTPUT "}\n*/\n"); - -# For the static httpd-fs.c file system the file name and data addresses in the linked list -# point to the actual memory locations. -# For the coffee file system the addresses start from zero. The starting address must be added -# in the coffee read routine. - -for($i = 0; $i < @fvars; $i++) { - $file = $pfiles[$i]; - $fvar = $fvars[$i]; - if($i == 0) { - $prevfile = "NULL"; - $data_offset=0; - } else { - $data_offset=$data_offset+$clen[$i-1]; - $prevfile = "file" . $fvars[$i - 1]; - } - $filename_offset=$data_offset+6+2*$coffee_page_t; - $coffee_offset=$data_offset+$coffee_header_length; - if ($coffee_offset>0xffff) {print "Warning : Linked list offset field overflow\n";} - print(OUTPUT "const struct httpd_fsdata_file"); - for ($t=length($file);$t<16;$t++) {print(OUTPUT " ")}; - print(OUTPUT " file".$fvar."[] "); - if ($attribute) {print(OUTPUT "$attribute ");} - print(OUTPUT "={{"); - for ($t=length($prevfile);$t<20;$t++) {print(OUTPUT " ")}; - print(OUTPUT "$prevfile, "); - if ($coffee) { - printf(OUTPUT "(const char *)0x%4.4x, ",$filename_offset); - printf(OUTPUT "(const char *)0x%4.4x, ",$coffee_offset); - printf(OUTPUT "%5u}};\n",$flen[$i]); - } else { - print(OUTPUT "data$fvar"); - for ($t=length($file);$t<15;$t++) {print(OUTPUT " ")}; - print(OUTPUT ", data$fvar"); - for ($t=length($file);$t<15;$t++) {print(OUTPUT " ")}; - print(OUTPUT " +".(length($file)+1).", sizeof(data$fvar)"); - for ($t=length($file);$t<16;$t++) {print(OUTPUT " ")}; - print(OUTPUT " -".(length($file)+1)."}};\n"); - } -} -print(OUTPUT "\n#define HTTPD_FS_ROOT file$fvars[$n-1]\n"); -print(OUTPUT "#define HTTPD_FS_NUMFILES $n\n"); -print(OUTPUT "#define HTTPD_FS_SIZE $coffeesize\n"); -} -print "All done, files occupy $coffeesize bytes\n"; - From 5d234e1138b365147560d8cc600e7a8452402ab2 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 12 May 2018 18:14:03 +0100 Subject: [PATCH 157/485] Move viewconf to its own dir --- Makefile.include | 5 +++-- tools/{ => viewconf}/viewconf.c | 0 2 files changed, 3 insertions(+), 2 deletions(-) rename tools/{ => viewconf}/viewconf.c (100%) diff --git a/Makefile.include b/Makefile.include index f24124e83..61e028c72 100644 --- a/Makefile.include +++ b/Makefile.include @@ -446,6 +446,7 @@ savedefines: @echo "saving Makefile.$(TARGET).defines" @echo >Makefile.$(TARGET).defines "DEFINES = $(DEFINES)" +VIEWCONF = $(CONTIKI)/tools/viewconf/viewconf.c viewconf: @echo "----------------- Make variables: --------------" @echo "##### \"TARGET\": ________________________________ $(TARGET)" @@ -457,13 +458,13 @@ ifdef MAKE_COAP_DTLS_KEYSTORE @echo "##### \"MAKE_COAP_DTLS_KEYSTORE\": _______________ $(MAKE_COAP_DTLS_KEYSTORE)" endif @echo "----------------- C variables: -----------------" - $(Q)$(CC) $(CFLAGS) -E $(CONTIKI)/tools/viewconf.c | grep \#\#\#\#\# + $(Q)$(CC) $(CFLAGS) -E $(VIEWCONF) | grep \#\#\#\#\# @echo "------------------------------------------------" @echo "'==' Means the flag is set to a given a value" @echo "'->' Means the flag is unset, but will default to a given value" @echo "'><' Means the flag is unset and has no default value" @echo "To view more Make variables, edit $(CONTIKI)/Makefile.include, rule 'viewconf'" - @echo "To view more C variables, edit $(CONTIKI)/tools/viewconf.c" + @echo "To view more C variables, edit $(VIEWCONF)" ### Include Makefile.embedded for relevant platforms, in order to pull in ### rules for login, serialview etc diff --git a/tools/viewconf.c b/tools/viewconf/viewconf.c similarity index 100% rename from tools/viewconf.c rename to tools/viewconf/viewconf.c From 6177cac919e680b662e3d40096da0cc345901693 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 27 May 2018 19:21:08 +0100 Subject: [PATCH 158/485] Use $(MAKE) instead of make to invoke recursively --- Makefile.include | 4 ++-- Makefile.tools | 4 ++-- tests/Makefile | 2 +- tests/Makefile.compile-test | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Makefile.include b/Makefile.include index f24124e83..51ce92cfa 100644 --- a/Makefile.include +++ b/Makefile.include @@ -315,8 +315,8 @@ clean: distclean: @for TARG in `ls $(CONTIKI)/arch/platform $(TARGETDIRS)`; do \ - echo Running: make TARGET=$$TARG clean; \ - make TARGET=$$TARG clean; \ + echo Running: $(MAKE) TARGET=$$TARG clean; \ + $(MAKE) TARGET=$$TARG clean; \ done -include $(CONTIKI)/arch/platform/$(TARGET)/Makefile.customrules-$(TARGET) diff --git a/Makefile.tools b/Makefile.tools index 6151ba83a..81653cde6 100644 --- a/Makefile.tools +++ b/Makefile.tools @@ -11,7 +11,7 @@ TUNSLIP6 = $(SERIAL_IO_TOOL_DIR)/tunslip6 SERIAL_DUMP_BIN = $(SERIAL_IO_TOOL_DIR)/serialdump $(SERIAL_DUMP_BIN): $(SERIAL_IO_TOOL_DIR)/serialdump.c $(SERIAL_IO_TOOL_DEPS) - make -C $(SERIAL_IO_TOOL_DIR) serialdump + $(MAKE) -C $(SERIAL_IO_TOOL_DIR) serialdump $(TUNSLIP6): $(SERIAL_IO_TOOL_DIR)/tunslip6.c $(SERIAL_IO_TOOL_DEPS) - make -C $(SERIAL_IO_TOOL_DIR) tunslip6 + $(MAKE) -C $(SERIAL_IO_TOOL_DIR) tunslip6 diff --git a/tests/Makefile b/tests/Makefile index a879c805f..ddee606f2 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -36,7 +36,7 @@ summary: $(SUMMARIES) @cat $(SUMMARIES) > $@ %/summary: - @make -C $* summary || true + @$(MAKE) -C $* summary || true clean: rm -f $(SUMMARIES) summary diff --git a/tests/Makefile.compile-test b/tests/Makefile.compile-test index 1a5952033..e30f9da36 100644 --- a/tests/Makefile.compile-test +++ b/tests/Makefile.compile-test @@ -40,7 +40,7 @@ get_target_vars = $(wordlist 2,15,$(subst :, ,$1)) define dooneexample @echo -n Building example $(3): $(1) $(4) for target $(2) @((cd $(EXAMPLESDIR)/$(1); \ - make $(4) TARGET=$(2) clean && make -j $(4) TARGET=$(2) WERROR=1) > \ + $(MAKE) $(4) TARGET=$(2) clean && make -j $(4) TARGET=$(2) WERROR=1) > \ /dev/null 2>make.err && \ (echo " -> OK" && printf "%-75s %-40s %-20s TEST OK\n" "$(1)" "$(4)" "$(2)" > $(3)-$(subst /,-,$(1))$(2).testlog) || \ (echo " -> FAIL" && printf "%-75s %-40s %-20s TEST FAIL\n" "$(1)" "$(4)" "$(2)" > $(3)-$(subst /,-,$(1))$(2).testlog ; cat make.err)) @@ -65,4 +65,4 @@ clean: @rm -f *.testlog summary @$(foreach example, $(EXAMPLES), \ $(foreach target, $(EXAMPLESTARGETS), \ - (cd $(EXAMPLESDIR)/$(example); make TARGET=$(target) clean);)) + (cd $(EXAMPLESDIR)/$(example); $(MAKE) TARGET=$(target) clean);)) From 535e2dbbdccca7fca077c30f58a20edbe6d5842a Mon Sep 17 00:00:00 2001 From: Rehan MALAK Date: Mon, 28 May 2018 13:19:54 +0200 Subject: [PATCH 159/485] exclude sky platform for examples/libs/shell --- examples/libs/shell/Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/libs/shell/Makefile b/examples/libs/shell/Makefile index b44069cf8..7be7dd18e 100644 --- a/examples/libs/shell/Makefile +++ b/examples/libs/shell/Makefile @@ -3,4 +3,7 @@ all: $(CONTIKI_PROJECT) MODULES += os/services/shell CONTIKI = ../../.. + +PLATFORMS_EXCLUDE = sky + include $(CONTIKI)/Makefile.include From 12f15a4f27712cac06c95e153a3bd33aa571018a Mon Sep 17 00:00:00 2001 From: Rehan MALAK Date: Mon, 28 May 2018 20:56:12 +0200 Subject: [PATCH 160/485] minor modifications related to tools/serial-io/tunslip6 --- tests/17-tun-rpl-br/04-border-router-traceroute.sh | 7 +++---- tests/17-tun-rpl-br/test-border-router.sh | 7 +++---- tests/17-tun-rpl-br/test-native-border-router.sh | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/tests/17-tun-rpl-br/04-border-router-traceroute.sh b/tests/17-tun-rpl-br/04-border-router-traceroute.sh index fe1333aab..4effb9bd3 100755 --- a/tests/17-tun-rpl-br/04-border-router-traceroute.sh +++ b/tests/17-tun-rpl-br/04-border-router-traceroute.sh @@ -22,10 +22,9 @@ java -Xshare:on -jar $CONTIKI/tools/cooja/dist/cooja.jar -nogui=$BASENAME.csc -c JPID=$! sleep 20 -# Connect to the simlation +# Connect to the simulation echo "Starting tunslip6" -make -C $CONTIKI/tools tunslip6 -make -C $CONTIKI/examples/rpl-border-router/ connect-router-cooja TARGET=zoul >> $BASENAME.tunslip.log 2>&1 & +make -C $CONTIKI/examples/rpl-border-router/ connect-router-cooja TARGET=zoul >> $BASENAME.tunslip6.log 2>&1 & MPID=$! printf "Waiting for network formation (%d seconds)\n" "$WAIT_TIME" sleep $WAIT_TIME @@ -49,7 +48,7 @@ if [ $STATUS -eq 0 ] && [ $HOPS -eq $TARGETHOPS ] ; then printf "%-32s TEST OK\n" "$BASENAME" | tee $BASENAME.testlog; else echo "==== $BASENAME.coojalog ====" ; cat $BASENAME.coojalog; - echo "==== $BASENAME.tunslip.log ====" ; cat $BASENAME.tunslip.log; + echo "==== $BASENAME.tunslip6.log ====" ; cat $BASENAME.tunslip6.log; echo "==== $BASENAME.scriptlog ====" ; cat $BASENAME.scriptlog; printf "%-32s TEST FAIL\n" "$BASENAME" | tee $BASENAME.testlog; diff --git a/tests/17-tun-rpl-br/test-border-router.sh b/tests/17-tun-rpl-br/test-border-router.sh index c5653d480..a69446254 100755 --- a/tests/17-tun-rpl-br/test-border-router.sh +++ b/tests/17-tun-rpl-br/test-border-router.sh @@ -28,10 +28,9 @@ java -Xshare:on -jar $CONTIKI/tools/cooja/dist/cooja.jar -nogui=$BASENAME.csc -c JPID=$! sleep 20 -# Connect to the simlation +# Connect to the simulation echo "Starting tunslip6" -make -C $CONTIKI/tools tunslip6 -make -C $CONTIKI/examples/rpl-border-router/ connect-router-cooja TARGET=zoul >> $BASENAME.tunslip.log 2>&1 & +make -C $CONTIKI/examples/rpl-border-router/ connect-router-cooja TARGET=zoul >> $BASENAME.tunslip6.log 2>&1 & MPID=$! printf "Waiting for network formation (%d seconds)\n" "$WAIT_TIME" sleep $WAIT_TIME @@ -55,7 +54,7 @@ if [ $STATUS -eq 0 ] && [ $REPLIES -eq $COUNT ] ; then printf "%-32s TEST OK\n" "$BASENAME" | tee $BASENAME.testlog; else echo "==== $BASENAME.coojalog ====" ; cat $BASENAME.coojalog; - echo "==== $BASENAME.tunslip.log ====" ; cat $BASENAME.tunslip.log; + echo "==== $BASENAME.tunslip6.log ====" ; cat $BASENAME.tunslip6.log; echo "==== $BASENAME.scriptlog ====" ; cat $BASENAME.scriptlog; printf "%-32s TEST FAIL\n" "$BASENAME" | tee $BASENAME.testlog; diff --git a/tests/17-tun-rpl-br/test-native-border-router.sh b/tests/17-tun-rpl-br/test-native-border-router.sh index 50ea18179..e2e205f20 100644 --- a/tests/17-tun-rpl-br/test-native-border-router.sh +++ b/tests/17-tun-rpl-br/test-native-border-router.sh @@ -28,7 +28,7 @@ java -Xshare:on -jar $CONTIKI/tools/cooja/dist/cooja.jar -nogui=$BASENAME.csc -c JPID=$! sleep 20 -# Connect to the simlation +# Connect to the simulation echo "Starting native border-router" nohup make -C $CONTIKI/examples/rpl-border-router/ connect-router-cooja TARGET=native >> $BASENAME.nbr.log 2>&1 & MPID=$! From f873fa25bf78907530f35d4524a8271ad0fc7096 Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Thu, 24 May 2018 13:56:01 +0200 Subject: [PATCH 161/485] coap: bug fix when parsing secure CoAP endpoint with a specified port. Thanks to Carlos Gonzalo Peces for reporting the issue. --- os/net/app-layer/coap/coap-uip.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/os/net/app-layer/coap/coap-uip.c b/os/net/app-layer/coap/coap-uip.c index 8db2bbbbf..843049d4f 100644 --- a/os/net/app-layer/coap/coap-uip.c +++ b/os/net/app-layer/coap/coap-uip.c @@ -214,30 +214,27 @@ coap_endpoint_parse(const char *text, size_t size, coap_endpoint_t *ep) /* Only IPv6 supported */ int start = index_of(text, 0, size, '['); int end = index_of(text, start, size, ']'); - int secure = strncmp((const char *)text, "coaps:", 6) == 0; uint32_t port; - if(start > 0 && end > start && - uiplib_ipaddrconv((const char *)&text[start], &ep->ipaddr)) { + + ep->secure = strncmp(text, "coaps:", 6) == 0; + if(start >= 0 && end > start && + uiplib_ipaddrconv(&text[start], &ep->ipaddr)) { if(text[end + 1] == ':' && get_port(text + end + 2, size - end - 2, &port)) { ep->port = UIP_HTONS(port); - } else if(secure) { - /** - * Secure CoAP should use a different port but for now - * the same port is used. - */ - LOG_DBG("Using secure port (coaps)\n"); + } else if(ep->secure) { + /* Use secure CoAP port by default for secure endpoints. */ ep->port = SERVER_LISTEN_SECURE_PORT; - ep->secure = 1; } else { ep->port = SERVER_LISTEN_PORT; - ep->secure = 0; } return 1; - } else { - if(uiplib_ipaddrconv((const char *)&text, &ep->ipaddr)) { + } else if(size < UIPLIB_IPV6_MAX_STR_LEN) { + char buf[UIPLIB_IPV6_MAX_STR_LEN]; + memcpy(buf, text, size); + buf[size] = '\0'; + if(uiplib_ipaddrconv(buf, &ep->ipaddr)) { ep->port = SERVER_LISTEN_PORT; - ep->secure = 0; return 1; } } From 7091a846fef07ef3adffc01a37e4b988c1ed86cd Mon Sep 17 00:00:00 2001 From: Rehan MALAK Date: Tue, 29 May 2018 18:32:13 +0200 Subject: [PATCH 162/485] ignore files produced during coap-lwm2m tests --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6bab22c32..31afb98b3 100644 --- a/.gitignore +++ b/.gitignore @@ -60,7 +60,7 @@ COOJA.testlog summary tests/[0-9][0-9]-*/org/ tests/18-coap-lwm2m/Californium.properties -tests/18-coap-lwm2m/leshan-server-demo-1.0.0-SNAPSHOT-jar-with-dependencies.jar +tests/18-coap-lwm2m/leshan-server-demo*.jar # x86 UEFI files cpu/x86/uefi/Makefile.uefi From 9e2e6d74bd8bba5ef94b8e3035daa6ccf59221c1 Mon Sep 17 00:00:00 2001 From: Rehan MALAK Date: Tue, 29 May 2018 18:49:58 +0200 Subject: [PATCH 163/485] leshan server downloaded is the one used by the test --- tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh | 5 +++-- tests/18-coap-lwm2m/07-lwm2m-standalone-test.sh | 5 +++-- tests/18-coap-lwm2m/08-lwm2m-qmode-ipso-test.sh | 5 +++-- tests/18-coap-lwm2m/09-lwm2m-qmode-standalone-test.sh | 5 +++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh b/tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh index ec7502a21..f596206a9 100755 --- a/tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh +++ b/tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh @@ -17,9 +17,10 @@ CPID=$! sleep 10 echo "Downloading leshan" -wget -nc https://joakimeriksson.github.io/resources/leshan-server-demo-1.0.0-SNAPSHOT-jar-with-dependencies.jar +LESHAN_JAR=leshan-server-demo-1.0.0-SNAPSHOT-jar-with-dependencies.jar +wget -nc https://joakimeriksson.github.io/resources/$LESHAN_JAR echo "Starting leshan server" -java -jar leshan-server-demo-1.0.0-SNAPSHOT-jar-with-dependencies.jar >leshan.log 2>leshan.err & +java -jar $LESHAN_JAR >leshan.log 2>leshan.err & LESHID=$! COUNTER=10 diff --git a/tests/18-coap-lwm2m/07-lwm2m-standalone-test.sh b/tests/18-coap-lwm2m/07-lwm2m-standalone-test.sh index a1257f36e..2e6371896 100755 --- a/tests/18-coap-lwm2m/07-lwm2m-standalone-test.sh +++ b/tests/18-coap-lwm2m/07-lwm2m-standalone-test.sh @@ -12,9 +12,10 @@ make CONTIKI_NG=../../$CONTIKI -C example-lwm2m-standalone/lwm2m clean >/dev/nul 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 +LESHAN_JAR=leshan-server-demo-1.0.0-SNAPSHOT-jar-with-dependencies.jar +wget -nc https://joakimeriksson.github.io/resources/$LESHAN_JAR echo "Starting leshan server" -java -jar leshan-server-demo-1.0.0-SNAPSHOT-jar-with-dependencies.jar -lp 5686 -slp 5687 >leshan.log 2>leshan.err & +java -jar $LESHAN_JAR -lp 5686 -slp 5687 >leshan.log 2>leshan.err & LESHID=$! echo "Starting lwm2m standalone example" diff --git a/tests/18-coap-lwm2m/08-lwm2m-qmode-ipso-test.sh b/tests/18-coap-lwm2m/08-lwm2m-qmode-ipso-test.sh index 2b3d52c3e..b5ce6aa3f 100755 --- a/tests/18-coap-lwm2m/08-lwm2m-qmode-ipso-test.sh +++ b/tests/18-coap-lwm2m/08-lwm2m-qmode-ipso-test.sh @@ -16,9 +16,10 @@ CPID=$! sleep 10 echo "Downloading leshan with Q-Mode support" -wget -nc https://carlosgp143.github.io/resources/leshan-server-demo-qmode-support1.0.0-SNAPSHOT-jar-with-dependencies.jar +LESHAN_JAR=leshan-server-demo-qmode-support1.0.0-SNAPSHOT-jar-with-dependencies.jar +wget -nc https://carlosgp143.github.io/resources/$LESHAN_JAR echo "Starting leshan server with Q-Mode enabled" -java -jar leshan-server-demo-qmode-support1.0.0-SNAPSHOT-jar-with-dependencies.jar >leshan.log 2>leshan.err & +java -jar $LESHAN_JAR >leshan.log 2>leshan.err & LESHID=$! COUNTER=10 diff --git a/tests/18-coap-lwm2m/09-lwm2m-qmode-standalone-test.sh b/tests/18-coap-lwm2m/09-lwm2m-qmode-standalone-test.sh index 57f0e3f71..d84d3cd93 100755 --- a/tests/18-coap-lwm2m/09-lwm2m-qmode-standalone-test.sh +++ b/tests/18-coap-lwm2m/09-lwm2m-qmode-standalone-test.sh @@ -11,9 +11,10 @@ make CONTIKI_NG=../../$CONTIKI -C example-lwm2m-standalone/lwm2m clean >/dev/nul make CONTIKI_NG=../../$CONTIKI -C example-lwm2m-standalone/lwm2m DEFINES=LWM2M_QUEUE_MODE_CONF_ENABLED=1,LWM2M_QUEUE_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION=1,LWM2M_QUEUE_MODE_OBJECT_CONF_ENABLED=1 >make.log 2>make.err echo "Downloading leshan with Q-Mode support" -wget -nc https://carlosgp143.github.io/resources/leshan-server-demo-qmode-support1.0.0-SNAPSHOT-jar-with-dependencies.jar +LESHAN_JAR=leshan-server-demo-qmode-support1.0.0-SNAPSHOT-jar-with-dependencies.jar +wget -nc https://carlosgp143.github.io/resources/$LESHAN_JAR echo "Starting leshan server with Q-Mode enabled" -java -jar leshan-server-demo-1.0.0-SNAPSHOT-jar-with-dependencies.jar -lp 5686 -slp 5687 >leshan.log 2>leshan.err & +java -jar $LESHAN_JAR -lp 5686 -slp 5687 >leshan.log 2>leshan.err & LESHID=$! echo "Starting lwm2m standalone example" From 9327edb91f0550661392fddaa4cd6001b4dba13f Mon Sep 17 00:00:00 2001 From: "carlosgp143@gmail.com" Date: Wed, 30 May 2018 09:03:45 +0200 Subject: [PATCH 164/485] Added list_contains feature --- os/lib/list.c | 22 ++++++++++++++++++++++ os/lib/list.h | 2 ++ 2 files changed, 24 insertions(+) diff --git a/os/lib/list.c b/os/lib/list.c index afa9df585..f584ebb3e 100644 --- a/os/lib/list.c +++ b/os/lib/list.c @@ -324,4 +324,26 @@ list_item_next(void *item) return item == NULL ? NULL : ((struct list *)item)->next; } /*---------------------------------------------------------------------------*/ +/** + * \brief Check if the list contains an item + * \param list The list that is checked + * \param item An item to look for in the list + * \returns 0 if the list does not contains the item, and 1 otherwise + * + * This function searches for an item in the list and returns + * 0 if the list does not contain the item, and 1 if the item + * is present in the list. + */ +int +list_contains(list_t list, void *item) +{ + struct list *l; + for(l = *list; l != NULL; l = l->next) { + if(item == l) { + return 1; + } + } + return 0; +} +/*---------------------------------------------------------------------------*/ /** @} */ diff --git a/os/lib/list.h b/os/lib/list.h index 7d3ff43d3..e4c948665 100644 --- a/os/lib/list.h +++ b/os/lib/list.h @@ -151,6 +151,8 @@ void list_insert(list_t list, void *previtem, void *newitem); void * list_item_next(void *item); +int list_contains(list_t list, void *item); + #endif /* LIST_H_ */ /** @} */ From 5a9f61653ca0808960519238364f5eb50e8f709e Mon Sep 17 00:00:00 2001 From: "carlosgp143@gmail.com" Date: Thu, 31 May 2018 08:54:23 +0200 Subject: [PATCH 165/485] Added tests in singly-linked list --- .../code-data-structures/test-data-structures.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/07-simulation-base/code-data-structures/test-data-structures.c b/tests/07-simulation-base/code-data-structures/test-data-structures.c index dc4d8bb5b..0bdc8e6c4 100644 --- a/tests/07-simulation-base/code-data-structures/test-data-structures.c +++ b/tests/07-simulation-base/code-data-structures/test-data-structures.c @@ -156,6 +156,19 @@ UNIT_TEST(test_list) UNIT_TEST_ASSERT(tail->next == NULL); UNIT_TEST_ASSERT(list_length(lst) == 4); + /* + * Check that list contains elements 0, 1, 2, 3 + * and not others + * 0 --> 1 --> 2 --> 3 --> NULL + */ + UNIT_TEST_ASSERT(list_contains(lst, &elements[0])); + UNIT_TEST_ASSERT(list_contains(lst, &elements[1])); + UNIT_TEST_ASSERT(list_contains(lst, &elements[2])); + UNIT_TEST_ASSERT(list_contains(lst, &elements[3])); + int i; + for(i=4; i 1 --> 2 --> NULL From 2049ce09ed30f4e1bae40e0828c57cfd7c6a1c2d Mon Sep 17 00:00:00 2001 From: "carlosgp143@gmail.com" Date: Thu, 31 May 2018 10:11:56 +0200 Subject: [PATCH 166/485] Changed return from int to bool --- os/lib/list.c | 6 +++--- os/lib/list.h | 4 +++- .../code-data-structures/test-data-structures.c | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/os/lib/list.c b/os/lib/list.c index f584ebb3e..9eaf1945e 100644 --- a/os/lib/list.c +++ b/os/lib/list.c @@ -334,16 +334,16 @@ list_item_next(void *item) * 0 if the list does not contain the item, and 1 if the item * is present in the list. */ -int +bool list_contains(list_t list, void *item) { struct list *l; for(l = *list; l != NULL; l = l->next) { if(item == l) { - return 1; + return true; } } - return 0; + return false; } /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/os/lib/list.h b/os/lib/list.h index e4c948665..af0136435 100644 --- a/os/lib/list.h +++ b/os/lib/list.h @@ -66,6 +66,8 @@ #ifndef LIST_H_ #define LIST_H_ +#include + #define LIST_CONCAT2(s1, s2) s1##s2 #define LIST_CONCAT(s1, s2) LIST_CONCAT2(s1, s2) @@ -151,7 +153,7 @@ void list_insert(list_t list, void *previtem, void *newitem); void * list_item_next(void *item); -int list_contains(list_t list, void *item); +bool list_contains(list_t list, void *item); #endif /* LIST_H_ */ diff --git a/tests/07-simulation-base/code-data-structures/test-data-structures.c b/tests/07-simulation-base/code-data-structures/test-data-structures.c index 0bdc8e6c4..da3833dc3 100644 --- a/tests/07-simulation-base/code-data-structures/test-data-structures.c +++ b/tests/07-simulation-base/code-data-structures/test-data-structures.c @@ -167,7 +167,7 @@ UNIT_TEST(test_list) UNIT_TEST_ASSERT(list_contains(lst, &elements[3])); int i; for(i=4; i Date: Sun, 27 May 2018 07:16:27 -0700 Subject: [PATCH 167/485] Docker: by default, build non-standalone image (contiki-ng as a mount) --- tools/docker/Dockerfile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index be28bf682..e1d85d003 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -88,12 +88,12 @@ RUN git clone https://github.com/renode/renode.git \ && ./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: +# By default, we use a Docker bind mount to share the repo with the host, +# with Docker run option: # -v :/home/user/contiki-ng -RUN git clone --recursive https://github.com/contiki-ng/contiki-ng.git ${CONTIKI_NG} -RUN ant -q -f ${CONTIKI_NG}/tools/cooja/build.xml jar +# Alternatively, uncomment the next two lines to download Contiki-NG and pre-compile Cooja. +#RUN git clone --recursive https://github.com/contiki-ng/contiki-ng.git ${CONTIKI_NG} +#RUN ant -q -f ${CONTIKI_NG}/tools/cooja/build.xml jar # Working directory WORKDIR ${CONTIKI_NG} From 74ce416884846821552d0ddb550f8d00f804e850 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sun, 27 May 2018 14:39:42 -0700 Subject: [PATCH 168/485] Travis: if Dockerfile has changed, rebuild image. When updating branch develop, push new image to Dockerhub --- .travis.yml | 74 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 23 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0467424de..e91ee6aea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,36 +1,64 @@ # Setup environment for Docker language: generic services: docker - notifications: - - email: false + email: false +# Environment setup before test script. Runs for each build before_install: - # Environment setup before test script - - export CNG_HOST_PATH=`pwd` - - export DOCKER_IMG='simonduq/contiki-ng:latest' - - sudo chgrp -hR 1000 $CNG_HOST_PATH - - docker pull $DOCKER_IMG + # Check if anything has changed within the docker directory + - DOCKER_CHANGED=`git diff --name-only $TRAVIS_BRANCH...HEAD -- tools/docker | wc -l` + # If Docker directory has not changed, pull image from Dockerhub. Else, build + # image from Dockerifle. This needs to be done for each job. Any build error + # will count as Travis test failure. In case this updates develop, push new + # image to Dockerhub (secure credentials only readable on bulids to + # contiki-ng/contiki-ng branches, not forks or PRs) + - > + if [ $DOCKER_CHANGED == 0 ]; then + echo "Docker image unchanged, pull from Dockerhub" + docker pull $DOCKER_IMG; + else + echo "Docker image changed, build from Dockerfile" + docker build tools/docker -t $DOCKER_IMG; + if [ $TRAVIS_SECURE_ENV_VARS == true ] && [ $TRAVIS_PULL_REQUEST == false ] && [ $TRAVIS_BRANCH == 'develop' ]; then + echo "This build is for an update of branch develop. Push image to Dockerhub" + echo $DOCKERHUB_PASSWD | docker login --username contiker --password-stdin + docker push $DOCKER_IMG; + fi + fi + # Build Cooja - ant -q -f $CNG_HOST_PATH/tools/cooja/build.xml jar + # Set permissions for Docker mount + - sudo chgrp -hR 1000 $CNG_HOST_PATH -script: # The test script for each build. +# The test script for each build +script: - docker run --privileged -v $CNG_HOST_PATH:/home/user/contiki-ng -ti $DOCKER_IMG bash --login -c "make -C tests/??-$TEST_NAME"; # Check outcome of the test - $CNG_HOST_PATH/tests/check-test.sh $CNG_HOST_PATH/tests/??-$TEST_NAME; exit $?; +# Environment variables env: - # Parallel builds - - TEST_NAME='compile-base' - - TEST_NAME='compile-arm-ports-01' - - TEST_NAME='compile-arm-ports-02' - - TEST_NAME='rpl-lite' - - TEST_NAME='rpl-classic' - - TEST_NAME='tun-rpl-br' - - TEST_NAME='coap-lwm2m' - - TEST_NAME='simulation-base' - - TEST_NAME='ieee802154' - - TEST_NAME='compile-nxp-ports' - - TEST_NAME='doxygen' - - TEST_NAME='compile-tools' - - TEST_NAME='native-runs' - - TEST_NAME='ipv6' + # Global environment variables, i.e., set for all builds + global: + - DOCKER_IMG='contiker/contiki-ng' + - CNG_HOST_PATH=`pwd` + # Encrypted environment variables. + # Only available on builds of contiki-ng/contiki-ng branches, not PRs or forks. + - secure: 0nrV5yjpT2kE19Hlm7t619Qbmyjx/G7bSUI1c+U3kZbyuxnRlASjVcDN5uPBoimIfGiBRI0nRq690BogAJt4EKwbC1Dy8kC1XD8mRtQ2AIZ6PHaUoG9iS5sBhFBQK0XkB83bwh6omRn/04O0uuX74ooSWT7fDrWxi/y5+0ysXK6gRtOhdrJ3FU5OkNVewX8NeCdx3pOWhMOtXWdFkMIi1XRdDnvMM5/hHlHMkdXXtaZQX9UsK3Q3DSjPRLZjKRiOlcx9MIg2ebh9ITmd2Du2p2q/LKtoutJckvhbKQPWcZi/B+1ZTSff0FHBIg+EYxf6TeFuia7XSTWH7sr2CDCCtcvSR9bB5yW6jdmGfa8Af8I1TCBuqoSUo0Re50BZBZF7COleEh+IojbjXn2CIDMg5rT4Sh3qcMGvFn9OW1cz5h5UNSOk7EIAXXPcI7Aloxh2sBo4/DrvvbfIsKrvxV9Fx4bdyNtR7dZ7xsoOw6L0zttC3K9naf3VAOeBAyjBiRwm0tWxJC/buhTsKlYrthhyUrwLtYAFL4UHcazvz57hY/cEzR2X6F//9Hp7HFoNtn1E36doX3ZfeI22yxHMo9SYW7O69C45wbhJ29lAA9XXbYVyGBKFkY8C1NCZ0Xckt9H8/Ow5Sz8HmW/NNBJCn0Fsx+jezdGc4ED5naugNbLAyNg= + # Each line in the 'matrix' triggers a separate Travis build + matrix: + - TEST_NAME='compile-base' + - TEST_NAME='compile-arm-ports-01' + - TEST_NAME='compile-arm-ports-02' + - TEST_NAME='rpl-lite' + - TEST_NAME='rpl-classic' + - TEST_NAME='tun-rpl-br' + - TEST_NAME='coap-lwm2m' + - TEST_NAME='simulation-base' + - TEST_NAME='ieee802154' + - TEST_NAME='compile-nxp-ports' + - TEST_NAME='doxygen' + - TEST_NAME='compile-tools' + - TEST_NAME='native-runs' + - TEST_NAME='ipv6' From 7b38f46abaea49029a5167939ecaee7b6ead7a86 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Mon, 4 Jun 2018 23:08:22 +0200 Subject: [PATCH 169/485] Travis: fix in test of whether the docker configuration has changed --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e91ee6aea..2ba80e188 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ notifications: # Environment setup before test script. Runs for each build before_install: # Check if anything has changed within the docker directory - - DOCKER_CHANGED=`git diff --name-only $TRAVIS_BRANCH...HEAD -- tools/docker | wc -l` + - DOCKER_CHANGED=`git diff --name-only $TRAVIS_COMMIT_RANGE -- tools/docker | wc -l` # If Docker directory has not changed, pull image from Dockerhub. Else, build # image from Dockerifle. This needs to be done for each job. Any build error # will count as Travis test failure. In case this updates develop, push new From e71bc0a8180606b9c532061ac4dbfd0326df0693 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 5 Jun 2018 13:05:20 +0200 Subject: [PATCH 170/485] Update Cooja to latest --- tools/cooja | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cooja b/tools/cooja index 22b1262d9..a5904b983 160000 --- a/tools/cooja +++ b/tools/cooja @@ -1 +1 @@ -Subproject commit 22b1262d9e668d9cf6c8eaf70715f1bcd5728642 +Subproject commit a5904b98366478bb9e7f7fe9f0bb78fc064914c5 From 4c7474da70ec2eacc04f44c964b0450b2512ed84 Mon Sep 17 00:00:00 2001 From: Martin Hermsen Date: Tue, 5 Jun 2018 13:14:00 +0200 Subject: [PATCH 171/485] rx full IRQ handling for cc13xx/cc26xx --- arch/cpu/cc26xx-cc13xx/rf-core/prop-mode.c | 10 ++++++++++ arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c | 15 ++++++++++++++- arch/cpu/cc26xx-cc13xx/rf-core/rf-core.h | 3 +++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/prop-mode.c b/arch/cpu/cc26xx-cc13xx/rf-core/prop-mode.c index f4e7f66e7..66b4a4370 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/prop-mode.c +++ b/arch/cpu/cc26xx-cc13xx/rf-core/prop-mode.c @@ -45,6 +45,7 @@ #include "net/netstack.h" #include "sys/energest.h" #include "sys/clock.h" +#include "sys/critical.h" #include "sys/rtimer.h" #include "sys/cc.h" #include "lpm.h" @@ -766,6 +767,7 @@ send(const void *payload, unsigned short payload_len) static int read_frame(void *buf, unsigned short buf_len) { + int_master_status_t status; rfc_dataEntryGeneral_t *entry = (rfc_dataEntryGeneral_t *)rx_read_entry; uint8_t *data_ptr = &entry->data; int len = 0; @@ -795,6 +797,14 @@ read_frame(void *buf, unsigned short buf_len) entry->status = DATA_ENTRY_STATUS_PENDING; } + status = critical_enter(); + if(rx_is_full) { + rx_is_full = false; + PRINTF("RXQ was full, re-enabling radio!\n"); + rx_on_prop(); + } + critical_exit(status); + return len; } /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c b/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c index 2baa883ad..23b78eab4 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c +++ b/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c @@ -76,7 +76,7 @@ /*---------------------------------------------------------------------------*/ /* RF interrupts */ #define RX_FRAME_IRQ IRQ_RX_ENTRY_DONE -#define ERROR_IRQ IRQ_INTERNAL_ERROR +#define ERROR_IRQ (IRQ_INTERNAL_ERROR | IRQ_RX_BUF_FULL) #define RX_NOK_IRQ IRQ_RX_NOK /* Those IRQs are enabled all the time */ @@ -103,6 +103,9 @@ static const rf_core_primary_mode_t *primary_mode = NULL; int32_t rat_offset = 0; static bool rat_offset_known = false; /*---------------------------------------------------------------------------*/ +/* Buffer full flag */ +volatile bool rx_is_full = false; +/*---------------------------------------------------------------------------*/ PROCESS(rf_core_process, "CC13xx / CC26xx RF driver"); /*---------------------------------------------------------------------------*/ #define RF_CORE_CLOCKS_MASK (RFC_PWR_PWMCLKEN_RFC_M | RFC_PWR_PWMCLKEN_CPE_M \ @@ -574,6 +577,16 @@ cc26xx_rf_cpe1_isr(void) return; } } + + if(HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIFG) & IRQ_RX_BUF_FULL) { + PRINTF("\nRF: BUF_FULL\n\n"); + /* set a flag that the buffer is full*/ + rx_is_full = true; + /* make sure read_frame() will be called to make space in RX buffer */ + process_poll(&rf_core_process); + /* Clear the IRQ_RX_BUF_FULL interrupt flag by writing zero to bit */ + HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIFG) = ~(IRQ_RX_BUF_FULL); + } /* Clear INTERNAL_ERROR interrupt flag */ HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIFG) = 0x7FFFFFFF; diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.h b/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.h index ac48bc52a..c97ab0f8a 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.h +++ b/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.h @@ -263,6 +263,9 @@ typedef struct rf_core_primary_mode_s { /* Radio timer register */ #define RATCNT 0x00000004 /*---------------------------------------------------------------------------*/ +/* Buffer full flag */ +extern volatile bool rx_is_full; +/*---------------------------------------------------------------------------*/ /* Make the main driver process visible to mode drivers */ PROCESS_NAME(rf_core_process); /*---------------------------------------------------------------------------*/ From 4dbba4df9a09d8dafb240ab9a294d923af92c1ee Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 5 Jun 2018 14:07:05 +0200 Subject: [PATCH 172/485] Platform native: overprovision routes, neighbor table and queues --- arch/platform/native/contiki-conf.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/platform/native/contiki-conf.h b/arch/platform/native/contiki-conf.h index 8d2c13820..e8177d7b2 100644 --- a/arch/platform/native/contiki-conf.h +++ b/arch/platform/native/contiki-conf.h @@ -78,6 +78,19 @@ typedef unsigned int uip_stats_t; #define NETSTACK_CONF_LINUXRADIO_DEV "wpan0" +/* configure network size and density */ +#ifndef NETSTACK_MAX_ROUTE_ENTRIES +#define NETSTACK_MAX_ROUTE_ENTRIES 300 +#endif /* NETSTACK_MAX_ROUTE_ENTRIES */ +#ifndef NBR_TABLE_CONF_MAX_NEIGHBORS +#define NBR_TABLE_CONF_MAX_NEIGHBORS 300 +#endif /* NBR_TABLE_CONF_MAX_NEIGHBORS */ + +/* configure queues */ +#ifndef QUEUEBUF_CONF_NUM +#define QUEUEBUF_CONF_NUM 64 +#endif /* QUEUEBUF_CONF_NUM */ + #define UIP_CONF_IPV6_QUEUE_PKT 1 #define UIP_ARCH_IPCHKSUM 1 From 838db51b8f5b8a82fb282daba213ff952c47ecb0 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 5 Jun 2018 13:15:19 +0200 Subject: [PATCH 173/485] CI fragmentation tests: increase ping size to 1200 bytes --- tests/17-tun-rpl-br/08-border-router-cooja-frag.sh | 2 +- tests/17-tun-rpl-br/09-native-border-router-cooja-frag.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/17-tun-rpl-br/08-border-router-cooja-frag.sh b/tests/17-tun-rpl-br/08-border-router-cooja-frag.sh index 53b867644..0e80018b4 100644 --- a/tests/17-tun-rpl-br/08-border-router-cooja-frag.sh +++ b/tests/17-tun-rpl-br/08-border-router-cooja-frag.sh @@ -6,4 +6,4 @@ CONTIKI=$1 # Simulation file BASENAME=01-border-router-cooja -bash test-border-router.sh $CONTIKI $BASENAME fd00::204:4:4:4 60 600 2 +bash test-border-router.sh $CONTIKI $BASENAME fd00::204:4:4:4 60 1200 4 diff --git a/tests/17-tun-rpl-br/09-native-border-router-cooja-frag.sh b/tests/17-tun-rpl-br/09-native-border-router-cooja-frag.sh index b1aa1351b..24baa1556 100755 --- a/tests/17-tun-rpl-br/09-native-border-router-cooja-frag.sh +++ b/tests/17-tun-rpl-br/09-native-border-router-cooja-frag.sh @@ -6,4 +6,4 @@ CONTIKI=$1 # Simulation file BASENAME=07-native-border-router-cooja -bash test-native-border-router.sh $CONTIKI $BASENAME fd00::204:4:4:4 60 600 2 +bash test-native-border-router.sh $CONTIKI $BASENAME fd00::204:4:4:4 60 1200 4 From 94398b0176251f1bcde902472a9d90faa63c414c Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 5 Jun 2018 15:11:32 +0200 Subject: [PATCH 174/485] CI: fail test in case building Docker image failed --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2ba80e188..da6dea283 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,10 @@ before_install: else echo "Docker image changed, build from Dockerfile" docker build tools/docker -t $DOCKER_IMG; + if [ $? != 0 ]; then + echo "Failed to build Docker image" + exit 1 + fi if [ $TRAVIS_SECURE_ENV_VARS == true ] && [ $TRAVIS_PULL_REQUEST == false ] && [ $TRAVIS_BRANCH == 'develop' ]; then echo "This build is for an update of branch develop. Push image to Dockerhub" echo $DOCKERHUB_PASSWD | docker login --username contiker --password-stdin From 57692d21f9a3cd8a693c9f044aa51fab165321c8 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 25 May 2018 21:07:02 +0100 Subject: [PATCH 175/485] Add support for documentation on readthedocs.io --- .gitignore | 1 + tools/readthedocs/Makefile | 19 +++++ tools/readthedocs/api-doc.py | 65 ++++++++++++++ tools/readthedocs/conf.py | 112 ++++++++++++++++++++++++ tools/readthedocs/index.rst | 23 +++++ tools/readthedocs/js/dynsections.js | 127 ++++++++++++++++++++++++++++ 6 files changed, 347 insertions(+) create mode 100644 tools/readthedocs/Makefile create mode 100644 tools/readthedocs/api-doc.py create mode 100644 tools/readthedocs/conf.py create mode 100644 tools/readthedocs/index.rst create mode 100644 tools/readthedocs/js/dynsections.js diff --git a/.gitignore b/.gitignore index 31afb98b3..91721ed08 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ obj_* Makefile.target Makefile.*.defines tools/doxygen/html +tools/readthedocs/_build patches-* tools/serial-io/tunslip6 tools/serial-io/serialdump diff --git a/tools/readthedocs/Makefile b/tools/readthedocs/Makefile new file mode 100644 index 000000000..ecf5b58d4 --- /dev/null +++ b/tools/readthedocs/Makefile @@ -0,0 +1,19 @@ +# Makefile used to generate documentation with sphinx, which is used on +# readthedocs. Use this Makefile to test readthedocs generation locally on +# your computer. +# +# For this to work, you will need to install sphinx and sphinx_rtd_theme. They +# can be installed through pip +.PHONY = clean all readthedocs + +SPHINX = sphinx-build +SPHINX_CONF_DIR = . +SPHINX_OUT_DIR = _build + +all: readthedocs + +clean: + rm -rf $(SPHINX_OUT_DIR) + +readthedocs: + $(SPHINX) -b html $(SPHINX_CONF_DIR) $(SPHINX_OUT_DIR) diff --git a/tools/readthedocs/api-doc.py b/tools/readthedocs/api-doc.py new file mode 100644 index 000000000..c59b0864e --- /dev/null +++ b/tools/readthedocs/api-doc.py @@ -0,0 +1,65 @@ +# Sphinx extension that builds Contiki-NG documentation and copies it over to +# the sphinx build dir +import subprocess +from sphinx.util import logging +logger = logging.getLogger(__name__) + + +api_doc_defaults = { + 'doxygen_src_dir': '../doxygen', + 'doxygen_out_dir': 'html', + 'doxygen_suppress_out': True, + 'doxygen_build': True, +} + + +def api_doc_build(app, exception): + if exception is not None: + logger.warning('%s exiting without building' % (__name__,)) + return + + if app.config.api_doc_doxygen_build: + make_invocation_suffix = ('> /dev/null' + if app.config.api_doc_doxygen_suppress_out + else '') + make_invocation = ' '.join(('make -C', + app.config.api_doc_doxygen_src_dir, + make_invocation_suffix)) + + logger.info('%s building API docs from "%s"' + % (__name__, app.config.api_doc_doxygen_src_dir)) + logger.info('%s executing "%s"' + % (__name__, make_invocation)) + + subprocess.call(make_invocation, shell=True) + + api_doc_build_dir = "/".join((app.config.api_doc_doxygen_src_dir, + app.config.api_doc_doxygen_out_dir)) + api_doc_static_api_dir = "/".join((app.outdir, '_api')) + + logger.info('%s moving "%s" to "%s"' + % (__name__, api_doc_build_dir, api_doc_static_api_dir)) + subprocess.call(' '.join(('mv', api_doc_build_dir, + api_doc_static_api_dir)), + shell=True) + + # Fundamentally a workaround: Readthedocs doxygen build plain refulses + # to build the same html/*.js files as local builds do. So we ship them + # and we copy them over to the output dir by force, till readthedocs + # starts behaving, hopefully in the near future + subprocess.call(' '.join(('cp js/dynsections.js', + api_doc_static_api_dir)), + shell=True) + + +def setup(app): + for k, v in api_doc_defaults.items(): + config_val = 'api_doc_' + k + logger.debug('Add config value %s: %s' %(config_val, v)) + app.add_config_value(config_val, v, '') + + # We will build and copy the docs after the end of the sphinx build, and. + # only if it has been successful. Regsiter for the build-finished event. + app.connect('build-finished', api_doc_build) + + logger.info('%s initialised' % (__name__,)) diff --git a/tools/readthedocs/conf.py b/tools/readthedocs/conf.py new file mode 100644 index 000000000..50e43737e --- /dev/null +++ b/tools/readthedocs/conf.py @@ -0,0 +1,112 @@ +# -*- coding: utf-8 -*- +# +# Configuration file for the Sphinx documentation builder. +# +# This file does only contain a selection of the most common options. For a +# full list see the documentation: +# http://www.sphinx-doc.org/en/master/config + + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys +sys.path.insert(0, os.path.abspath('.')) + + +# -- Project information ----------------------------------------------------- + +project = u'Contiki-NG' +copyright = u'2018, Contiki-NG maintainers and contributors' +author = u'Contiki-NG maintainers and contributors' + +# The short X.Y version +version = u'' +# The full version, including alpha/beta/rc tags +release = u'' + + +# -- General configuration --------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'api-doc' +] + +# api-doc configuration +api_doc_doxygen_src_dir = '../doxygen' +api_doc_doxygen_out_dir = 'html' +api_doc_doxygen_suppress_out = True +api_doc_doxygen_build = True + +# Add any paths that contain templates here, relative to this directory. +#templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path . +exclude_patterns = [u'_build', 'Thumbs.db', '.DS_Store'] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'sphinx_rtd_theme' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +#html_static_path = ['_static'] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# The default sidebars (for documents that don't match any pattern) are +# defined by theme itself. Builtin themes are using these templates by +# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', +# 'searchbox.html']``. +# +# html_sidebars = {} + + +# -- Options for HTMLHelp output --------------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = 'Contiki-NGdoc' diff --git a/tools/readthedocs/index.rst b/tools/readthedocs/index.rst new file mode 100644 index 000000000..794c0866b --- /dev/null +++ b/tools/readthedocs/index.rst @@ -0,0 +1,23 @@ +Contiki-NG API documentation! +============================= + +These pages host Contiki-NG's API documentation. + +The primary target audience +consists developers who want to develop an application with Contiki-NG or who +want to modify Contiki-NG itself. + +For guides and tutorials, visit the `Contiki-NG wiki`_. + +Index +===== +* `API Home`_ +* `List of Modules`_ +* `Data Structure Index`_ +* `Index of Files`_ + +.. _Contiki-NG wiki: https://github.com/contiki-ng/contiki-ng/wiki +.. _API Home: _api/index.html +.. _List of Modules: _api/modules.html +.. _Data Structure Index: _api/annotated.html +.. _Index of Files: _api/files.html diff --git a/tools/readthedocs/js/dynsections.js b/tools/readthedocs/js/dynsections.js new file mode 100644 index 000000000..537e3e498 --- /dev/null +++ b/tools/readthedocs/js/dynsections.js @@ -0,0 +1,127 @@ +/* + @licstart The following is the entire license notice for the + JavaScript code in this file. + + Copyright (C) 1997-2017 by Dimitri van Heesch + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + @licend The above is the entire license notice + for the JavaScript code in this file + */ +function toggleVisibility(linkObj) +{ + var base = $(linkObj).attr('id'); + var summary = $('#'+base+'-summary'); + var content = $('#'+base+'-content'); + var trigger = $('#'+base+'-trigger'); + var src=$(trigger).attr('src'); + if (content.is(':visible')===true) { + content.hide(); + summary.show(); + $(linkObj).addClass('closed').removeClass('opened'); + $(trigger).attr('src',src.substring(0,src.length-8)+'closed.png'); + } else { + content.show(); + summary.hide(); + $(linkObj).removeClass('closed').addClass('opened'); + $(trigger).attr('src',src.substring(0,src.length-10)+'open.png'); + } + return false; +} + +function updateStripes() +{ + $('table.directory tr'). + removeClass('even').filter(':visible:even').addClass('even'); +} + +function toggleLevel(level) +{ + $('table.directory tr').each(function() { + var l = this.id.split('_').length-1; + var i = $('#img'+this.id.substring(3)); + var a = $('#arr'+this.id.substring(3)); + if (l Date: Sun, 27 May 2018 15:07:55 +0100 Subject: [PATCH 176/485] Update the dockerfile to install packages required for readthedocs builds/tests --- tools/docker/Dockerfile | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index e1d85d003..80b719ab1 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -3,7 +3,7 @@ FROM 32bit/ubuntu:16.04 # Tools RUN apt-get update && \ apt-get install -y --no-install-recommends \ - build-essential doxygen git wget unzip python-serial \ + build-essential doxygen git wget unzip python-serial python-pip \ default-jdk ant srecord iputils-tracepath rlwrap \ mosquitto mosquitto-clients \ && apt-get clean @@ -42,6 +42,12 @@ RUN wget https://developer.nordicsemi.com/nRF5_IoT_SDK/nRF5_IoT_SDK_v0.9.x/nrf5_ ENV NRF52_SDK_ROOT /usr/nrf52-sdk +# Install sphinx and sphinx_rtd_theme, required for building and testing the +# readthedocs API documentation +RUN pip install --upgrade pip +RUN pip install setuptools +RUN pip install sphinx_rtd_theme sphinx + # Create user, enable X forwarding, add to group dialout # -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix RUN export uid=1000 gid=1000 && \ From 41c0851f79a896b3f6e5fa0852bab58b668de014 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Tue, 5 Jun 2018 12:11:29 +0100 Subject: [PATCH 177/485] Test readthedocs build on travis --- .travis.yml | 2 +- .../{00-doxygen => 00-documentation}/Makefile | 47 ++++++++++++++----- 2 files changed, 35 insertions(+), 14 deletions(-) rename tests/{00-doxygen => 00-documentation}/Makefile (60%) diff --git a/.travis.yml b/.travis.yml index 2ba80e188..ba65df5ad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -58,7 +58,7 @@ env: - TEST_NAME='simulation-base' - TEST_NAME='ieee802154' - TEST_NAME='compile-nxp-ports' - - TEST_NAME='doxygen' + - TEST_NAME='documentation' - TEST_NAME='compile-tools' - TEST_NAME='native-runs' - TEST_NAME='ipv6' diff --git a/tests/00-doxygen/Makefile b/tests/00-documentation/Makefile similarity index 60% rename from tests/00-doxygen/Makefile rename to tests/00-documentation/Makefile index 067090b73..ea0aa85b4 100644 --- a/tests/00-doxygen/Makefile +++ b/tests/00-documentation/Makefile @@ -24,35 +24,56 @@ # 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. +TOOLS_DIR = ../../tools -DOCDIR=../../tools/doxygen +DOXYGEN = doxygen +DOXYGEN_DIR = $(TOOLS_DIR)/doxygen +DOXYGEN_LOG = $(DOXYGEN).log +DOXYGEN_ERR = $(DOXYGEN).err + +RAEDTHEDOCS = readthedocs +READTHEDOCS_DIR = $(TOOLS_DIR)/readthedocs +READTHEDOCS_LOG = $(RAEDTHEDOCS).log +READTHEDOCS_ERR = $(RAEDTHEDOCS).err + +CLEAN_TARGETS += $(DOXYGEN_LOG) $(DOXYGEN_ERR) +CLEAN_TARGETS += $(READTHEDOCS_LOG) $(READTHEDOCS_ERR) all: clean summary doxygen: - -@$(MAKE) -C $(DOCDIR) 2> doxygen.err > /dev/null + -@$(MAKE) -C $(DOXYGEN_DIR) 2> $(DOXYGEN_ERR) > /dev/null -summary: doxygen +readthedocs: + -@$(MAKE) -C $(READTHEDOCS_DIR) 2> $(READTHEDOCS_ERR) > /dev/null + +summary: doxygen readthedocs @( \ 1> summary; \ - if [ -s doxygen.err ] ; then \ - echo "Doxygen: TEST FAIL" | tee summary; \ + if [ -s $(DOXYGEN_ERR) ] ; then \ + echo "Doxygen: TEST FAIL" | tee -a summary; \ echo "Errors:"; \ - cat doxygen.err; \ + cat $(DOXYGEN_ERR); \ fi ; \ - if [ -s $(DOCDIR)/doxygen.log ] ; then \ - echo "Doxygen: TEST FAIL" | tee summary; \ + if [ -s $(DOXYGEN_DIR)/doxygen.log ] ; then \ + echo "Doxygen: TEST FAIL" | tee -a summary; \ echo "Warnings:"; \ - cat $(DOCDIR)/doxygen.log; \ + cat $(DOXYGEN_DIR)/doxygen.log; \ + fi ; \ + if [ -s $(READTHEDOCS_ERR) ] ; then \ + echo "Readthedocs: TEST FAIL" | tee -a summary; \ + echo "Errors:"; \ + cat $(READTHEDOCS_ERR); \ fi ; \ if [ ! -s summary ] ; then \ - echo "Doxygen: TEST OK (no warning nor error)" | tee summary; \ + echo "Documentation: TEST OK (no warning nor error)" | tee summary; \ fi ; \ ) - @rm doxygen.err + @rm -f $(CLEAN_TARGETS) @echo "========== Summary ==========" @cat summary clean: - @rm -f summary doxygen.err - @$(MAKE) -C $(DOCDIR) clean + @rm -f summary $(CLEAN_TARGETS) + @$(MAKE) -C $(DOXYGEN_DIR) clean + @$(MAKE) -C $(READTHEDOCS_DIR) clean From 9ae283031aad7c1869e9d9b695795b638a6a62e3 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 26 May 2018 05:03:08 -0700 Subject: [PATCH 178/485] Added deployment module --- os/services/deployment/deployment.c | 141 +++++++++++++++++++++++++ os/services/deployment/deployment.h | 126 ++++++++++++++++++++++ os/services/deployment/module-macros.h | 1 + os/sys/node-id.c | 5 + 4 files changed, 273 insertions(+) create mode 100644 os/services/deployment/deployment.c create mode 100644 os/services/deployment/deployment.h create mode 100644 os/services/deployment/module-macros.h diff --git a/os/services/deployment/deployment.c b/os/services/deployment/deployment.c new file mode 100644 index 000000000..c48a0cbae --- /dev/null +++ b/os/services/deployment/deployment.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2018, 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. + * + */ + +/** +* \addtogroup deployment +* @{ +*/ + +/** + * \file + * Code managing id<->mac address<->IPv6 address mapping, and doing this + * for different deployment scenarios: Cooja, Nodes, Indriya or Twist testbeds + * + * \author Simon Duquennoy + */ + +#include "contiki.h" +#include "contiki-net.h" +#include "deployment.h" +#include "sys/node-id.h" +#include +#include + +/** + * \brief List of ID<->MAC mapping used for different deployments + */ +extern const struct id_mac DEPLOYMENT_MAPPING[]; +/** + * \brief The number of nodes in the deployment + */ +static int node_count = 0; + +/*---------------------------------------------------------------------------*/ +void +deployment_init(void) +{ + const struct id_mac *curr = DEPLOYMENT_MAPPING; + /* Initialize node_id */ + node_id = deployment_id_from_lladdr((const linkaddr_t *)&linkaddr_node_addr); + /* Count nodes */ + node_count = 0; + while(curr->id != 0) { + node_count++; + curr++; + } +} +/*---------------------------------------------------------------------------*/ +int +deployment_node_count(void) +{ + return node_count; +} +/*---------------------------------------------------------------------------*/ +uint16_t +deployment_id_from_lladdr(const linkaddr_t *lladdr) +{ + const struct id_mac *curr = DEPLOYMENT_MAPPING; + if(lladdr == NULL) { + return 0; + } + while(curr->id != 0) { + /* Assume network-wide unique 16-bit MAC addresses */ + if(linkaddr_cmp(lladdr, &curr->mac)) { + return curr->id; + } + curr++; + } + return 0; +} +/*---------------------------------------------------------------------------*/ +void +deployment_lladdr_from_id(linkaddr_t *lladdr, uint16_t id) +{ + const struct id_mac *curr = DEPLOYMENT_MAPPING; + if(id == 0 || lladdr == NULL) { + return; + } + while(curr->id != 0) { + if(curr->id == id) { + linkaddr_copy(lladdr, &curr->mac); + return; + } + curr++; + } +} +/*---------------------------------------------------------------------------*/ +uint16_t +deployment_id_from_iid(const uip_ipaddr_t *ipaddr) +{ + const linkaddr_t lladdr; + uip_ds6_set_lladdr_from_iid((uip_lladdr_t *)&lladdr, ipaddr); + return deployment_id_from_lladdr(&lladdr); +} +/*---------------------------------------------------------------------------*/ +void +deployment_iid_from_id(uip_ipaddr_t *ipaddr, uint16_t id) +{ + linkaddr_t lladdr; + deployment_lladdr_from_id(&lladdr, id); + uip_ds6_set_addr_iid(ipaddr, (uip_lladdr_t *)&lladdr); +} +/*---------------------------------------------------------------------------*/ +uint16_t +deployment_id_from_index(uint16_t index) +{ + if(index < deployment_node_count()) { + return DEPLOYMENT_MAPPING[index].id; + } else { + return 0; + } +} +/*---------------------------------------------------------------------------*/ + +/** @} */ diff --git a/os/services/deployment/deployment.h b/os/services/deployment/deployment.h new file mode 100644 index 000000000..b2e3c1928 --- /dev/null +++ b/os/services/deployment/deployment.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2018, 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. + * + */ + +/** +* \addtogroup deployment +* @{ +* +* \file + Per-deployment MAC <-> nodeid mapping +* \author Simon Duquennoy +* +*/ + +#ifndef DEPLOYMENT_H_ +#define DEPLOYMENT_H_ + +#include "contiki-conf.h" +#include "sys/node-id.h" +#include "net/ipv6/uip.h" +#include "net/linkaddr.h" + +/** + * \brief ID<->MAC address mapping structure + */ +struct id_mac { + uint16_t id; + linkaddr_t mac; +}; + +/** + * DEPLOYMENT_MAPPING: + * A table of struct id_mac that provides ID-MAC mapping for a deployment. + * Example with four nodes: + * In configuration file: + * \#define DEPLOYMENT_MAPPING custom_array + * In a .c file: + * const struct id_mac custom_array[] = { + { 1, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb6,0x14}}}, + { 2, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb1,0xe7}}}, + { 3, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb4,0x35}}}, + { 4, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb1,0xcf}}}, + { 0, {{0}}} + }; + */ + +/** + * Initialize the deployment module + */ +void deployment_init(void); + +/** + * Get the number of nodes for the deployment (length of mapping table) + * + * \return The number of nodes in the deployment + */ +int deployment_node_count(void); + +/** + * Get node ID from a link-layer address, from the deployment mapping table + * + * \param lladdr The link-layer address to look up for + * \return Node ID from a corresponding link-layer address + */ +uint16_t deployment_id_from_lladdr(const linkaddr_t *lladdr); + +/** + * Get node link-layer address from a node ID, from the deployment mapping table + * + * \param lladdr A pointer where to write the link-layer address + * \param id The node ID to look up for + */ +void deployment_lladdr_from_id(linkaddr_t *lladdr, uint16_t id); + +/** + * Get node ID from the IID of an IPv6 address + * + * \param ipaddr The IPv6 (global or link-local) address that contains the IID + * \return Node ID from a corresponding IID + */ +uint16_t deployment_id_from_iid(const uip_ipaddr_t *ipaddr); + +/** + * Get IPv6 IID from node IDs + * + * \param ipaddr The IPv6 where to write the IID + * \param id The node ID + */ +void deployment_iid_from_id(uip_ipaddr_t *ipaddr, uint16_t id); + +/** + * Get node ID from index in mapping table + * + * \param index The index in the deployment mapping table + * \return Node ID at the corresponding index + */ +uint16_t deployment_id_from_index(uint16_t index); + +#endif /* DEPLOYMENT_H_ */ +/** @} */ diff --git a/os/services/deployment/module-macros.h b/os/services/deployment/module-macros.h new file mode 100644 index 000000000..ed2d639ef --- /dev/null +++ b/os/services/deployment/module-macros.h @@ -0,0 +1 @@ +#define BUILD_WITH_DEPLOYMENT 1 diff --git a/os/sys/node-id.c b/os/sys/node-id.c index 7914256e9..2fd52f8dc 100644 --- a/os/sys/node-id.c +++ b/os/sys/node-id.c @@ -40,12 +40,17 @@ #include "contiki.h" #include "sys/node-id.h" #include "net/linkaddr.h" +#include "services/deployment/deployment.h" uint16_t node_id = 0; void node_id_init(void) { +#if BUILD_WITH_DEPLOYMENT + deployment_init(); +#else /* BUILD_WITH_DEPLOYMENT */ /* Initialize with a default value derived from linkaddr */ node_id = linkaddr_node_addr.u8[LINKADDR_SIZE - 1] + (linkaddr_node_addr.u8[LINKADDR_SIZE - 2] << 8); +#endif /* BUILD_WITH_DEPLOYMENT */ } From 95208a804a61a0a3cb675fc5d3cf0aba95247734 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 26 May 2018 05:04:03 -0700 Subject: [PATCH 179/485] Deployment: use node-id for compact address logging --- os/net/ipv6/uip-sr.c | 12 ++++++-- os/net/routing/rpl-lite/rpl-neighbor.c | 6 +++- os/sys/log-conf.h | 3 +- os/sys/log.c | 41 +++++++++++++++++++------- os/sys/log.h | 11 +++++++ 5 files changed, 58 insertions(+), 15 deletions(-) diff --git a/os/net/ipv6/uip-sr.c b/os/net/ipv6/uip-sr.c index a82491827..133fd6f28 100644 --- a/os/net/ipv6/uip-sr.c +++ b/os/net/ipv6/uip-sr.c @@ -258,7 +258,11 @@ uip_sr_link_snprint(char *buf, int buflen, uip_sr_node_t *link) NETSTACK_ROUTING.get_sr_node_ipaddr(&child_ipaddr, link); NETSTACK_ROUTING.get_sr_node_ipaddr(&parent_ipaddr, link->parent); - index += uiplib_ipaddr_snprint(buf+index, buflen-index, &child_ipaddr); + if(LOG_WITH_COMPACT_ADDR) { + index += log_6addr_compact_snprint(buf+index, buflen-index, &child_ipaddr); + } else { + index += uiplib_ipaddr_snprint(buf+index, buflen-index, &child_ipaddr); + } if(index >= buflen) { return index; } @@ -273,7 +277,11 @@ uip_sr_link_snprint(char *buf, int buflen, uip_sr_node_t *link) if(index >= buflen) { return index; } - index += uiplib_ipaddr_snprint(buf+index, buflen-index, &parent_ipaddr); + if(LOG_WITH_COMPACT_ADDR) { + index += log_6addr_compact_snprint(buf+index, buflen-index, &parent_ipaddr); + } else { + index += uiplib_ipaddr_snprint(buf+index, buflen-index, &parent_ipaddr); + } if(index >= buflen) { return index; } diff --git a/os/net/routing/rpl-lite/rpl-neighbor.c b/os/net/routing/rpl-lite/rpl-neighbor.c index a066af313..a0f5d95b0 100644 --- a/os/net/routing/rpl-lite/rpl-neighbor.c +++ b/os/net/routing/rpl-lite/rpl-neighbor.c @@ -94,7 +94,11 @@ rpl_neighbor_snprint(char *buf, int buflen, rpl_nbr_t *nbr) const struct link_stats *stats = rpl_neighbor_get_link_stats(nbr); clock_time_t clock_now = clock_time(); - index += uiplib_ipaddr_snprint(buf+index, buflen-index, rpl_neighbor_get_ipaddr(nbr)); + if(LOG_WITH_COMPACT_ADDR) { + index += log_6addr_compact_snprint(buf+index, buflen-index, rpl_neighbor_get_ipaddr(nbr)); + } else { + index += uiplib_ipaddr_snprint(buf+index, buflen-index, rpl_neighbor_get_ipaddr(nbr)); + } if(index >= buflen) { return index; } diff --git a/os/sys/log-conf.h b/os/sys/log-conf.h index 24cf21f71..17d8562cc 100644 --- a/os/sys/log-conf.h +++ b/os/sys/log-conf.h @@ -46,7 +46,8 @@ #ifndef __LOG_CONF_H__ #define __LOG_CONF_H__ -/* Log only the last 16 bytes of link-layer and IPv6 addresses */ +/* Log only the last 16 bytes of link-layer and IPv6 addresses (or, if) + * the deployment module is enabled, the node IDs */ #ifdef LOG_CONF_WITH_COMPACT_ADDR #define LOG_WITH_COMPACT_ADDR LOG_CONF_WITH_COMPACT_ADDR #else /* LOG_CONF_WITH_COMPACT_ADDR */ diff --git a/os/sys/log.c b/os/sys/log.c index 9a02087a2..abb960b98 100644 --- a/os/sys/log.c +++ b/os/sys/log.c @@ -51,6 +51,7 @@ #include "sys/log.h" #include "net/ipv6/ip64-addr.h" #include "net/ipv6/uiplib.h" +#include "deployment/deployment.h" int curr_log_level_rpl = LOG_CONF_LEVEL_RPL; int curr_log_level_tcpip = LOG_CONF_LEVEL_TCPIP; @@ -90,22 +91,36 @@ log_6addr(const uip_ipaddr_t *ipaddr) LOG_OUTPUT("%s", buf); } /*---------------------------------------------------------------------------*/ +int +log_6addr_compact_snprint(char *buf, size_t size, const uip_ipaddr_t *ipaddr) +{ + if(ipaddr == NULL) { + return snprintf(buf, size, "6A-NULL"); + } else { + char *prefix = NULL; + if(uip_is_addr_mcast(ipaddr)) { + prefix = "6M"; + } else if(uip_is_addr_linklocal(ipaddr)) { + prefix = "6L"; + } else { + prefix = "6G"; + } +#if BUILD_WITH_DEPLOYMENT + return snprintf(buf, size, "%s-%03u", prefix, deployment_id_from_iid(ipaddr)); +#else /* BUILD_WITH_DEPLOYMENT */ + return snprintf(buf, size, "%s-%04x", prefix, UIP_HTONS(ipaddr->u16[sizeof(uip_ipaddr_t)/2-1])); +#endif /* BUILD_WITH_DEPLOYMENT */ + } +} +/*---------------------------------------------------------------------------*/ void log_6addr_compact(const uip_ipaddr_t *ipaddr) { - if(ipaddr == NULL) { - LOG_OUTPUT("6A-NULL"); - } else if(uip_is_addr_mcast(ipaddr)) { - LOG_OUTPUT("6M-%04x", UIP_HTONS(ipaddr->u16[sizeof(uip_ipaddr_t)/2-1])); - } else if(uip_is_addr_linklocal(ipaddr)) { - LOG_OUTPUT("6L-%04x", UIP_HTONS(ipaddr->u16[sizeof(uip_ipaddr_t)/2-1])); - } else { - LOG_OUTPUT("6G-%04x", UIP_HTONS(ipaddr->u16[sizeof(uip_ipaddr_t)/2-1])); - } + char buf[8]; + log_6addr_compact_snprint(buf, sizeof(buf), ipaddr); + LOG_OUTPUT("%s", buf); } - #endif /* NETSTACK_CONF_WITH_IPV6 */ - /*---------------------------------------------------------------------------*/ void log_lladdr(const linkaddr_t *lladdr) @@ -130,11 +145,15 @@ log_lladdr_compact(const linkaddr_t *lladdr) if(lladdr == NULL || linkaddr_cmp(lladdr, &linkaddr_null)) { LOG_OUTPUT("LL-NULL"); } else { +#if BUILD_WITH_DEPLOYMENT + LOG_OUTPUT("LL-%04u", deployment_id_from_lladdr(lladdr)); +#else /* BUILD_WITH_DEPLOYMENT */ #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 +#endif /* BUILD_WITH_DEPLOYMENT */ } } /*---------------------------------------------------------------------------*/ diff --git a/os/sys/log.h b/os/sys/log.h index e27a3007e..0f5f840d2 100644 --- a/os/sys/log.h +++ b/os/sys/log.h @@ -194,6 +194,17 @@ void log_6addr(const uip_ipaddr_t *ipaddr); */ void log_6addr_compact(const uip_ipaddr_t *ipaddr); +/** + * Write at most size - 1 characters of the IP address to the output string, + * in a compact representation. The output is always null-terminated, unless + * size is 0. + * + * \param buf A pointer to an output string with at least size bytes. + * \param size The max number of characters to write to the output string. + * \param ipaddr A pointer to a uip_ipaddr_t that will be printed with printf(). + */ +int log_6addr_compact_snprint(char *buf, size_t size, const uip_ipaddr_t *ipaddr); + #endif /* NETSTACK_CONF_WITH_IPV6 */ /** From c0a1c586be7d1aad66f090fc3c6ce64e281be16b Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 26 May 2018 05:03:21 -0700 Subject: [PATCH 180/485] Added deployment example --- examples/libs/deployment/Makefile | 7 + examples/libs/deployment/README.md | 3 + examples/libs/deployment/node.c | 111 ++++++++++ examples/libs/deployment/project-conf.h | 12 ++ examples/libs/deployment/sim.csc | 275 ++++++++++++++++++++++++ 5 files changed, 408 insertions(+) create mode 100644 examples/libs/deployment/Makefile create mode 100644 examples/libs/deployment/README.md create mode 100644 examples/libs/deployment/node.c create mode 100644 examples/libs/deployment/project-conf.h create mode 100644 examples/libs/deployment/sim.csc diff --git a/examples/libs/deployment/Makefile b/examples/libs/deployment/Makefile new file mode 100644 index 000000000..5ad17e22d --- /dev/null +++ b/examples/libs/deployment/Makefile @@ -0,0 +1,7 @@ +CONTIKI_PROJECT = node +all: $(CONTIKI_PROJECT) + +MODULES += os/services/deployment + +CONTIKI = ../../.. +include $(CONTIKI)/Makefile.include diff --git a/examples/libs/deployment/README.md b/examples/libs/deployment/README.md new file mode 100644 index 000000000..8484c3aee --- /dev/null +++ b/examples/libs/deployment/README.md @@ -0,0 +1,3 @@ +A simple example of how to use the deployment module. Intended for Cooja, +with a Cooja motes, as in the provided simulation file `sim.csc`. For use +in a real deployment, set DEPLOYMENT_MAPPING to your own ID-MAC mapping table. diff --git a/examples/libs/deployment/node.c b/examples/libs/deployment/node.c new file mode 100644 index 000000000..188b66e14 --- /dev/null +++ b/examples/libs/deployment/node.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2018, RISE SICS. + * 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 + * Benchmark: the root sends requests to all nodes in a randomized + * order, and receives resopnses back. + * \author + * Simon Duquennoy + */ + +#include "contiki.h" +#include "contiki-net.h" +#include "services/deployment/deployment.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "App" +#define LOG_LEVEL LOG_LEVEL_INFO + +#include "services/deployment/deployment.h" + +/** \brief A mapping table for a 8-node Cooja mote simulation. + * Define your own for any given deployment environment */ +const struct id_mac deployment_cooja8[] = { + { 1, {{0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01}}}, + { 2, {{0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02}}}, + { 3, {{0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03}}}, + { 4, {{0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04}}}, + { 5, {{0x00,0x05,0x00,0x05,0x00,0x05,0x00,0x05}}}, + { 6, {{0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06}}}, + { 7, {{0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x07}}}, + { 8, {{0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08}}}, + { 0, {{0}}} +}; + +/*---------------------------------------------------------------------------*/ +PROCESS(app_process, "App process"); +AUTOSTART_PROCESSES(&app_process); + +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(app_process, ev, data) +{ + static struct etimer timer; + static uip_ipaddr_t ipaddr; + static linkaddr_t lladdr; + static int i; + + PROCESS_BEGIN(); + + if(node_id == ROOT_ID) { + /* We are the root, start a DAG */ + NETSTACK_ROUTING.root_start(); + /* Setup a periodic timer that expires after 10 seconds. */ + etimer_set(&timer, CLOCK_SECOND * 10); + /* Wait until all nodes have joined */ + while(1) { + PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&timer)); + etimer_reset(&timer); + /* Log expected IPv6 addresses of all nodes */ + LOG_INFO("Node list:\n"); + for(i = 0; iMAC) */ +#define DEPLOYMENT_MAPPING deployment_cooja8 +/* Compact address logging (both link-layer and IPv6). + * Shows an abbreviated form that contains the node-id */ +#define LOG_CONF_WITH_COMPACT_ADDR 1 + +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/libs/deployment/sim.csc b/examples/libs/deployment/sim.csc new file mode 100644 index 000000000..9daa11426 --- /dev/null +++ b/examples/libs/deployment/sim.csc @@ -0,0 +1,275 @@ + + + [APPS_DIR]/mrm + [APPS_DIR]/mspsim + [APPS_DIR]/avrora + [APPS_DIR]/serial_socket + [APPS_DIR]/powertracker + + My simulation + 123456 + 1000000 + + org.contikios.cooja.radiomediums.UDGM + 50.0 + 100.0 + 1.0 + 1.0 + + + 40000 + + + org.contikios.cooja.contikimote.ContikiMoteType + mtype90 + Cooja Mote Type #1 + [CONTIKI_DIR]/examples/libs/deployment/node.c + make node.cooja TARGET=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 + 12.478629242391953 + 42.201041276604826 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 1 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype90 + + + + org.contikios.cooja.interfaces.Position + 25.625935608473608 + 82.53975431376661 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 2 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype90 + + + + org.contikios.cooja.interfaces.Position + 51.615094138350024 + 59.70602651475372 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 3 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype90 + + + + org.contikios.cooja.interfaces.Position + 41.04314122620578 + 121.24693889311891 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 4 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype90 + + + + org.contikios.cooja.interfaces.Position + 64.9463558635099 + 104.25039302469283 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 5 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype90 + + + + org.contikios.cooja.interfaces.Position + 93.59263858654369 + 75.40399148300003 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 6 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype90 + + + + org.contikios.cooja.interfaces.Position + 75.6297158696234 + 139.97002035548905 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 7 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype90 + + + + org.contikios.cooja.interfaces.Position + 104.34293924684245 + 116.07658566915099 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 8 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype90 + + + + org.contikios.cooja.plugins.SimControl + 280 + 2 + 160 + 400 + 0 + + + org.contikios.cooja.plugins.Visualizer + + true + org.contikios.cooja.plugins.skins.IDVisualizerSkin + org.contikios.cooja.plugins.skins.GridVisualizerSkin + org.contikios.cooja.plugins.skins.TrafficVisualizerSkin + org.contikios.cooja.plugins.skins.UDGMVisualizerSkin + 2.4250860844175466 0.0 0.0 2.4250860844175466 35.26895372864869 -46.9106236441515 + + 400 + 3 + 400 + 1 + 1 + + + org.contikios.cooja.plugins.LogListener + + App + + + + 827 + 0 + 665 + 681 + -1 + + + org.contikios.cooja.plugins.TimeLine + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + + + + 500.0 + + 1539 + 1 + 263 + 0 + 709 + + From 98338aad2df8e7c302ca2c907d4593e1fff4cad0 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 26 May 2018 05:11:42 -0700 Subject: [PATCH 181/485] Add Flocklab Openmotes as an example deployment mapping --- examples/libs/deployment/node.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/examples/libs/deployment/node.c b/examples/libs/deployment/node.c index 188b66e14..2cbe1f276 100644 --- a/examples/libs/deployment/node.c +++ b/examples/libs/deployment/node.c @@ -63,6 +63,21 @@ const struct id_mac deployment_cooja8[] = { { 0, {{0}}} }; +/** \brief An example mapping for Openmotes in Flocklab. + * To use, set DEPLOYMENT_MAPPING to deployment_flocklab_openmotes */ +const struct id_mac deployment_flocklab_openmotes[] = { + { 3, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0x9b,0x29}}}, + { 6, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0x9b,0x34}}}, + { 8, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0x9b,0x1f}}}, + { 15, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0x9b,0x85}}}, + { 16, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0x9b,0x00}}}, + { 18, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0x9b,0x37}}}, + { 22, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0x9b,0x08}}}, + { 23, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0x9b,0x5f}}}, + { 31, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0x9b,0xb1}}}, + { 0, {{0}}} +}; + /*---------------------------------------------------------------------------*/ PROCESS(app_process, "App process"); AUTOSTART_PROCESSES(&app_process); From f968c11a2fc129b0946876e15704dd64f937d686 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 26 May 2018 05:13:09 -0700 Subject: [PATCH 182/485] Added compile test for example libs/deployment --- tests/03-compile-arm-ports-02/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/03-compile-arm-ports-02/Makefile b/tests/03-compile-arm-ports-02/Makefile index ceb1b79e3..7efb1b14b 100644 --- a/tests/03-compile-arm-ports-02/Makefile +++ b/tests/03-compile-arm-ports-02/Makefile @@ -66,6 +66,7 @@ rpl-border-router/openmote-cc2538 \ libs/ipv6-hooks/openmote-cc2538 \ libs/shell/openmote-cc2538 \ libs/simple-energest/openmote-cc2538 \ +libs/deployment/openmote-cc2538 \ TOOLS= From 833cf2f87d8e91fe4ce9d3d801dcacf69b59fb4d Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 6 Jun 2018 15:38:16 +0200 Subject: [PATCH 183/485] Fix copyright headers --- examples/libs/shell/example.c | 2 +- examples/libs/simple-energest/example.c | 2 +- os/services/deployment/deployment.c | 2 +- os/services/deployment/deployment.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/libs/shell/example.c b/examples/libs/shell/example.c index 9d2320c58..51cc98826 100644 --- a/examples/libs/shell/example.c +++ b/examples/libs/shell/example.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Swedish Institute of Computer Science. + * Copyright (c) 2018, RISE SICS. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/examples/libs/simple-energest/example.c b/examples/libs/simple-energest/example.c index e9d6d585c..35d1f0b8d 100644 --- a/examples/libs/simple-energest/example.c +++ b/examples/libs/simple-energest/example.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Swedish Institute of Computer Science. + * Copyright (c) 2018, RISE SICS. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/os/services/deployment/deployment.c b/os/services/deployment/deployment.c index c48a0cbae..087d9766d 100644 --- a/os/services/deployment/deployment.c +++ b/os/services/deployment/deployment.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Swedish Institute of Computer Science. + * Copyright (c) 2018, RISE SICS. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/os/services/deployment/deployment.h b/os/services/deployment/deployment.h index b2e3c1928..29cd5214b 100644 --- a/os/services/deployment/deployment.h +++ b/os/services/deployment/deployment.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Swedish Institute of Computer Science. + * Copyright (c) 2018, RISE SICS. * All rights reserved. * * Redistribution and use in source and binary forms, with or without From b0f564010191f62e66c120ad2e9cf0aaaf66f961 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Thu, 7 Jun 2018 12:56:12 +0100 Subject: [PATCH 184/485] Update cc2538-bsl to latest version --- tools/cc2538-bsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cc2538-bsl b/tools/cc2538-bsl index 81cd4cbe5..edb3c8c73 160000 --- a/tools/cc2538-bsl +++ b/tools/cc2538-bsl @@ -1 +1 @@ -Subproject commit 81cd4cbe5e05e4fa97782d1859ed15b769f4bf2b +Subproject commit edb3c8c73c4688ebd336b278450db216512a769b From 1a95aad7a72348e72f7301abe698757bba748ebd Mon Sep 17 00:00:00 2001 From: Angelos Oikonomopoulos Date: Thu, 7 Jun 2018 14:26:47 +0000 Subject: [PATCH 185/485] Mark shell_commands as const This enables the compiler to place the array in flash, saving us a bit of RAM. Suggested-by: g-oikonomou --- os/services/shell/shell-commands.c | 4 ++-- os/services/shell/shell-commands.h | 2 +- os/services/shell/shell.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/os/services/shell/shell-commands.c b/os/services/shell/shell-commands.c index f2f036eda..67c81b6e1 100644 --- a/os/services/shell/shell-commands.c +++ b/os/services/shell/shell-commands.c @@ -345,7 +345,7 @@ PT_THREAD(cmd_log(struct pt *pt, shell_output_func output, char *args)) static PT_THREAD(cmd_help(struct pt *pt, shell_output_func output, char *args)) { - struct shell_command_t *cmd_ptr; + const struct shell_command_t *cmd_ptr; PT_BEGIN(pt); @@ -734,7 +734,7 @@ shell_commands_init(void) echo_reply_handler); } /*---------------------------------------------------------------------------*/ -struct shell_command_t shell_commands[] = { +const struct shell_command_t shell_commands[] = { { "help", cmd_help, "'> help': Shows this help" }, { "reboot", cmd_reboot, "'> reboot': Reboot the board by watchdog_reboot()" }, { "ip-addr", cmd_ipaddr, "'> ip-addr': Shows all IPv6 addresses" }, diff --git a/os/services/shell/shell-commands.h b/os/services/shell/shell-commands.h index f89703273..4d89d2e4b 100644 --- a/os/services/shell/shell-commands.h +++ b/os/services/shell/shell-commands.h @@ -54,7 +54,7 @@ struct shell_command_t { }; /* The set of supported commands */ -extern struct shell_command_t shell_commands[]; +extern const struct shell_command_t shell_commands[]; /** * Initializes Shell-commands module diff --git a/os/services/shell/shell.c b/os/services/shell/shell.c index fcf419880..e16a69b30 100644 --- a/os/services/shell/shell.c +++ b/os/services/shell/shell.c @@ -89,7 +89,7 @@ output_prompt(shell_output_func output) PT_THREAD(shell_input(struct pt *pt, shell_output_func output, const char *cmd)) { static char *args; - static struct shell_command_t *cmd_ptr; + static const struct shell_command_t *cmd_ptr; PT_BEGIN(pt); From f325d449641058740b8b4bb12ae333fa8f065822 Mon Sep 17 00:00:00 2001 From: Yasuyuki Tanaka Date: Sat, 9 Jun 2018 23:16:32 +0200 Subject: [PATCH 186/485] Dockerfile: add gdb --- tools/docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 80b719ab1..9d15704ac 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -5,7 +5,7 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends \ build-essential doxygen git wget unzip python-serial python-pip \ default-jdk ant srecord iputils-tracepath rlwrap \ - mosquitto mosquitto-clients \ + mosquitto mosquitto-clients gdb \ && apt-get clean # Install ARM toolchain From f8d004b92fe4c96fd48185aa7a2519832ca04065 Mon Sep 17 00:00:00 2001 From: Olav Frengstad Date: Wed, 6 Jun 2018 16:53:16 +0200 Subject: [PATCH 187/485] Move LLSEC checks from `tsch-security.h` to `tsch-security.c` Different part of the stack is pulled in from `contiki-main.c` this has the unintended side effect of including TSCH headers even when TSCH is not used. When using LLSEC for CSMA this triggers an error and compilation fails. --- os/net/mac/tsch/tsch-security.c | 4 ++++ os/net/mac/tsch/tsch-security.h | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/os/net/mac/tsch/tsch-security.c b/os/net/mac/tsch/tsch-security.c index 1c4266626..12f0de6d5 100644 --- a/os/net/mac/tsch/tsch-security.c +++ b/os/net/mac/tsch/tsch-security.c @@ -53,6 +53,10 @@ #include #include +#if LLSEC802154_ENABLED && !LLSEC802154_USES_EXPLICIT_KEYS +#error LLSEC802154_ENABLED set but LLSEC802154_USES_EXPLICIT_KEYS unset +#endif /* LLSEC802154_ENABLED */ + /* The two keys K1 and K2 from 6TiSCH minimal configuration * K1: well-known, used for EBs * K2: secret, used for data and ACK diff --git a/os/net/mac/tsch/tsch-security.h b/os/net/mac/tsch/tsch-security.h index 56c854414..4320d3a70 100644 --- a/os/net/mac/tsch/tsch-security.h +++ b/os/net/mac/tsch/tsch-security.h @@ -54,10 +54,6 @@ * - set LLSEC802154_CONF_USES_EXPLICIT_KEYS * */ -#if LLSEC802154_ENABLED && !LLSEC802154_USES_EXPLICIT_KEYS -#error LLSEC802154_ENABLED set but LLSEC802154_USES_EXPLICIT_KEYS unset -#endif /* LLSEC802154_ENABLED */ - /* K1, defined in 6TiSCH minimal, is well-known (offers no security) and used for EBs only */ #ifdef TSCH_SECURITY_CONF_K1 #define TSCH_SECURITY_K1 TSCH_SECURITY_CONF_K1 From 45b0241f94befcd85ef8d77dcf8e718b640841da Mon Sep 17 00:00:00 2001 From: Angelos Oikonomopoulos Date: Fri, 8 Jun 2018 10:16:49 +0000 Subject: [PATCH 188/485] Introduce dynamically registered shell command sets Commands are part of a single array, which means that their definition is static. However, different apps in the same source tree may reasonably want to add to the command set (perhaps even shadow existing commands), which would make for awkward code. Instead, allow dynamic registration/deregistration of command sets at runtime. This keeps the data overhead low (two pointers per enabled command set). --- os/services/shell/shell-commands.c | 59 ++++++++++++++++++++++++++---- os/services/shell/shell-commands.h | 10 ++++- os/services/shell/shell.c | 20 ++++------ 3 files changed, 66 insertions(+), 23 deletions(-) diff --git a/os/services/shell/shell-commands.c b/os/services/shell/shell-commands.c index 67c81b6e1..e8bb4b6b2 100644 --- a/os/services/shell/shell-commands.c +++ b/os/services/shell/shell-commands.c @@ -45,6 +45,7 @@ #include "contiki.h" #include "shell.h" #include "shell-commands.h" +#include "lib/list.h" #include "sys/log.h" #include "dev/watchdog.h" #include "net/ipv6/uip.h" @@ -76,7 +77,8 @@ static uint16_t curr_ping_datalen; #if TSCH_WITH_SIXTOP static shell_command_6top_sub_cmd_t sixtop_sub_cmd = NULL; #endif /* TSCH_WITH_SIXTOP */ - +static struct shell_command_set_t builtin_shell_command_set; +LIST(shell_command_sets); /*---------------------------------------------------------------------------*/ static const char * ds6_nbr_state_to_str(uint8_t state) @@ -345,15 +347,16 @@ PT_THREAD(cmd_log(struct pt *pt, shell_output_func output, char *args)) static PT_THREAD(cmd_help(struct pt *pt, shell_output_func output, char *args)) { - const struct shell_command_t *cmd_ptr; - + struct shell_command_set_t *set; + const struct shell_command_t *cmd; PT_BEGIN(pt); SHELL_OUTPUT(output, "Available commands:\n"); - cmd_ptr = shell_commands; - while(cmd_ptr->name != NULL) { - SHELL_OUTPUT(output, "%s\n", cmd_ptr->help); - cmd_ptr++; + /* Note: we explicitly don't expend any code space to deal with shadowing */ + for(set = list_head(shell_command_sets); set != NULL; set = list_item_next(set)) { + for(cmd = set->commands; cmd->name != NULL; ++cmd) { + SHELL_OUTPUT(output, "%s\n", cmd->help); + } } PT_END(pt); @@ -729,12 +732,48 @@ PT_THREAD(cmd_6top(struct pt *pt, shell_output_func output, char *args)) void shell_commands_init(void) { + list_init(shell_command_sets); + list_add(shell_command_sets, &builtin_shell_command_set); /* Set up Ping Reply callback */ uip_icmp6_echo_reply_callback_add(&echo_reply_notification, echo_reply_handler); } /*---------------------------------------------------------------------------*/ -const struct shell_command_t shell_commands[] = { +void +shell_command_set_register(struct shell_command_set_t *set) +{ + list_push(shell_command_sets, set); +} +/*---------------------------------------------------------------------------*/ +int +shell_command_set_deregister(struct shell_command_set_t *set) +{ + if(!list_contains(shell_command_sets, set)) { + return !0; + } + list_remove(shell_command_sets, set); + return 0; +} +/*---------------------------------------------------------------------------*/ +const struct shell_command_t * +shell_command_lookup(const char *name) +{ + struct shell_command_set_t *set; + const struct shell_command_t *cmd; + + for(set = list_head(shell_command_sets); + set != NULL; + set = list_item_next(set)) { + for(cmd = set->commands; cmd->name != NULL; ++cmd) { + if(!strcmp(cmd->name, name)) { + return cmd; + } + } + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +const struct shell_command_t builtin_shell_commands[] = { { "help", cmd_help, "'> help': Shows this help" }, { "reboot", cmd_reboot, "'> reboot': Reboot the board by watchdog_reboot()" }, { "ip-addr", cmd_ipaddr, "'> ip-addr': Shows all IPv6 addresses" }, @@ -765,4 +804,8 @@ const struct shell_command_t shell_commands[] = { { NULL, NULL, NULL }, }; +static struct shell_command_set_t builtin_shell_command_set = { + .next = NULL, + .commands = builtin_shell_commands, +}; /** @} */ diff --git a/os/services/shell/shell-commands.h b/os/services/shell/shell-commands.h index 4d89d2e4b..f510e861d 100644 --- a/os/services/shell/shell-commands.h +++ b/os/services/shell/shell-commands.h @@ -53,8 +53,14 @@ struct shell_command_t { const char *help; }; -/* The set of supported commands */ -extern const struct shell_command_t shell_commands[]; +struct shell_command_set_t { + struct shell_command_set_t *next; + const struct shell_command_t *const commands; +}; + +void shell_command_set_register(struct shell_command_set_t *); +int shell_command_set_deregister(struct shell_command_set_t *); +const struct shell_command_t *shell_command_lookup(const char *); /** * Initializes Shell-commands module diff --git a/os/services/shell/shell.c b/os/services/shell/shell.c index e16a69b30..c219b1903 100644 --- a/os/services/shell/shell.c +++ b/os/services/shell/shell.c @@ -89,7 +89,7 @@ output_prompt(shell_output_func output) PT_THREAD(shell_input(struct pt *pt, shell_output_func output, const char *cmd)) { static char *args; - static const struct shell_command_t *cmd_ptr; + static const struct shell_command_t *cmd_descr = NULL; PT_BEGIN(pt); @@ -105,20 +105,14 @@ PT_THREAD(shell_input(struct pt *pt, shell_output_func output, const char *cmd)) args++; } - /* Lookup for command */ - cmd_ptr = shell_commands; - while(cmd_ptr->name != NULL) { - if(strcmp(cmd, cmd_ptr->name) == 0) { - static struct pt cmd_pt; - PT_SPAWN(pt, &cmd_pt, cmd_ptr->func(&cmd_pt, output, args)); - goto done; - } - cmd_ptr++; + cmd_descr = shell_command_lookup(cmd); + if(cmd_descr != NULL) { + static struct pt cmd_pt; + PT_SPAWN(pt, &cmd_pt, cmd_descr->func(&cmd_pt, output, args)); + } else { + SHELL_OUTPUT(output, "Command not found. Type 'help' for a list of commands\n"); } - SHELL_OUTPUT(output, "Command not found. Type 'help' for a list of commands\n"); - -done: output_prompt(output); PT_END(pt); } From ae9a65663203641f0309da3804a0e650c215198f Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 9 Jun 2018 14:38:19 +0200 Subject: [PATCH 189/485] Added examples/benchmarks directory, with code for testbed nightly runs --- examples/benchmarks/rpl-req-resp/Makefile | 26 ++ examples/benchmarks/rpl-req-resp/node.c | 156 ++++++++++ examples/benchmarks/rpl-req-resp/parse.py | 269 +++++++++++++++++ .../benchmarks/rpl-req-resp/project-conf.h | 48 +++ examples/benchmarks/rpl-req-resp/sim.csc | 275 ++++++++++++++++++ examples/benchmarks/testbeds/cooja8.c | 14 + examples/benchmarks/testbeds/sics-firefly.c | 31 ++ 7 files changed, 819 insertions(+) create mode 100644 examples/benchmarks/rpl-req-resp/Makefile create mode 100644 examples/benchmarks/rpl-req-resp/node.c create mode 100644 examples/benchmarks/rpl-req-resp/parse.py create mode 100644 examples/benchmarks/rpl-req-resp/project-conf.h create mode 100644 examples/benchmarks/rpl-req-resp/sim.csc create mode 100644 examples/benchmarks/testbeds/cooja8.c create mode 100644 examples/benchmarks/testbeds/sics-firefly.c diff --git a/examples/benchmarks/rpl-req-resp/Makefile b/examples/benchmarks/rpl-req-resp/Makefile new file mode 100644 index 000000000..4be6d431b --- /dev/null +++ b/examples/benchmarks/rpl-req-resp/Makefile @@ -0,0 +1,26 @@ +CONTIKI_PROJECT = node +all: $(CONTIKI_PROJECT) + +MODULES_REL += ../testbeds +MODULES += os/services/deployment +MODULES += os/services/simple-energest + +CONFIG?=CONFIG_TSCH_OPTIMS + +ifeq ($(CONFIG),CONFIG_CSMA) +MAKE_MAC = MAKE_MAC_CSMA +else ifeq ($(CONFIG),CONFIG_TSCH) +MAKE_MAC = MAKE_MAC_TSCH +MODULES += os/services/orchestra +else ifeq ($(CONFIG),CONFIG_TSCH_OPTIMS) +MAKE_MAC = MAKE_MAC_TSCH +MODULES += os/services/orchestra +CFLAGS += -DCONFIG_OPTIMS=1 +else ifeq ($(CONFIG),CONFIG_TSCH_OPTIMS2) +MAKE_MAC = MAKE_MAC_TSCH +MODULES += os/services/orchestra +CFLAGS += -DCONFIG_OPTIMS=2 +endif + +CONTIKI = ../../.. +include $(CONTIKI)/Makefile.include diff --git a/examples/benchmarks/rpl-req-resp/node.c b/examples/benchmarks/rpl-req-resp/node.c new file mode 100644 index 000000000..4b92415f9 --- /dev/null +++ b/examples/benchmarks/rpl-req-resp/node.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2018, RISE SICS. + * 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 + * Benchmark: the root sends requests to all nodes in a randomized + * order, and receives resopnses back. + * \author + * Simon Duquennoy + */ + +#include "contiki.h" +#include "contiki-net.h" +#include "services/deployment/deployment.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "App" +#define LOG_LEVEL LOG_LEVEL_INFO + +#define UDP_PORT 8214 +#define SEND_INTERVAL (CLOCK_SECOND) + +static struct simple_udp_connection udp_conn; + +/*---------------------------------------------------------------------------*/ +PROCESS(app_process, "App process"); +AUTOSTART_PROCESSES(&app_process); + +/*---------------------------------------------------------------------------*/ +static void +udp_rx_callback(struct simple_udp_connection *c, + const uip_ipaddr_t *sender_addr, + uint16_t sender_port, + const uip_ipaddr_t *receiver_addr, + uint16_t receiver_port, + const uint8_t *data, + uint16_t datalen) +{ + uint32_t count; + int is_response; + /* Copy and parse payload */ + memcpy(&count, data, sizeof(uint32_t)); + /* Most significant bit: request (0) / response (1) */ + is_response = count & 0x80000000; + count &= 0x7fffffff; + + if(is_response) { + LOG_INFO("Received response %"PRIu32" from ", count); + LOG_INFO_6ADDR(sender_addr); + LOG_INFO_("\n"); + } else { + LOG_INFO("Received request %"PRIu32" from ", count); + LOG_INFO_6ADDR(sender_addr); + LOG_INFO_("\n"); + LOG_INFO("Sending response %"PRIu32" to ", count); + LOG_INFO_6ADDR(sender_addr); + LOG_INFO_("\n"); + /* Set most significant bit to signal a response */ + count |= 0x80000000; + simple_udp_sendto(&udp_conn, &count, sizeof(count), sender_addr); + } +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(app_process, ev, data) +{ + static struct etimer timer; + static uip_ipaddr_t dest_ipaddr; + + PROCESS_BEGIN(); + + /* Initialize UDP connection */ + simple_udp_register(&udp_conn, UDP_PORT, NULL, + UDP_PORT, udp_rx_callback); + + if(node_id == ROOT_ID) { + /* Wait 5 seconds before starting */ + etimer_set(&timer, CLOCK_SECOND * 5); + PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&timer)); + + /* We are the root, start a DAG */ + NETSTACK_ROUTING.root_start(); + /* Set dest_ipaddr with DODAG ID, so we get the prefix */ + NETSTACK_ROUTING.get_root_ipaddr(&dest_ipaddr); + /* Setup a periodic timer that expires after 10 seconds. */ + etimer_set(&timer, CLOCK_SECOND * 10); + /* Wait until all nodes have joined */ + do { + PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&timer)); + etimer_reset(&timer); + + if(deployment_node_count() > NETSTACK_MAX_ROUTE_ENTRIES) { + LOG_WARN("Not enough routing entries for deployment: %u/%u\n", + deployment_node_count(), NETSTACK_MAX_ROUTE_ENTRIES); + } + LOG_INFO("Node count: %u/%u\n", uip_sr_num_nodes(), deployment_node_count()); + + } while(uip_sr_num_nodes() < deployment_node_count()); + + /* Now start requesting nodes at random */ + etimer_set(&timer, SEND_INTERVAL); + while(uip_sr_num_nodes() == deployment_node_count()) { + static uint32_t count = 0; + uint16_t dest_id; + + PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&timer)); + etimer_reset(&timer); + + /* Select a destination at random. Iterate until we do not select ourselve */ + do { + dest_id = deployment_id_from_index(random_rand() % deployment_node_count()); + } while(dest_id == ROOT_ID); + /* Prefix was already set, set IID now */ + deployment_iid_from_id(&dest_ipaddr, dest_id); + + /* Request: most significant bit not unset */ + LOG_INFO("Sending request %"PRIu32" to ", count); + LOG_INFO_6ADDR(&dest_ipaddr); + LOG_INFO_("\n"); + simple_udp_sendto(&udp_conn, &count, sizeof(count), &dest_ipaddr); + count++; + } + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/examples/benchmarks/rpl-req-resp/parse.py b/examples/benchmarks/rpl-req-resp/parse.py new file mode 100644 index 000000000..a15b9c49b --- /dev/null +++ b/examples/benchmarks/rpl-req-resp/parse.py @@ -0,0 +1,269 @@ +#!/usr/bin/env python + +import re +import os +import fileinput +import math +import yaml +import pandas as pd +from pandas import * +from pylab import * +from datetime import * +from collections import OrderedDict +from IPython import embed +import matplotlib as mpl + +pd.set_option('display.max_rows', 48) +pd.set_option('display.width', None) +pd.set_option('display.max_columns', None) + +networkFormationTime = None +parents = {} + +def calculateHops(node): + hops = 0 + while(parents[node] != None): + node = parents[node] + hops += 1 + # safeguard, in case of scrambled logs + if hops > 50: + return hops + return hops + +def calculateChildren(node): + children = 0 + for n in parents.keys(): + if(parents[n] == node): + children += 1 + return children + +def updateTopology(child, parent): + global parents + if not child in parents: + parents[child] = {} + if not parent in parents: + parents[parent] = None + parents[child] = parent + +def parseRPL(log): + res = re.compile('.*? rank (\d*).*?dioint (\d*).*?nbr count (\d*)').match(log) + if res: + rank = int(res.group(1)) + trickle = (2**int(res.group(2)))/(60*1000.) + nbrCount = int(res.group(3)) + return {'event': 'rank', 'rank': rank, 'trickle': trickle } + res = re.compile('parent switch: .*? -> .*?-(\d*)$').match(log) + if res: + parent = int(res.group(1)) + return {'event': 'switch', 'pswitch': parent } + res = re.compile('sending a (.+?) ').match(log) + if res: + message = res.group(1) + return {'event': 'sending', 'message': message } + res = re.compile('links: 6G-(\d+)\s*to 6G-(\d+)').match(log) + if res: + child = int(res.group(1)) + parent = int(res.group(2)) + updateTopology(child, parent) + return None + res = re.compile('links: end of list').match(log) + if res: + # This was the last line, commit full topology + return {'event': 'topology' } + return None + +def parseEnergest(log): + res = re.compile('Radio Tx\s*:\s*(\d*)/\s*(\d+)').match(log) + if res: + tx = float(res.group(1)) + total = float(res.group(2)) + return {'channel-utilization': 100.*tx/total } + res = re.compile('Radio total\s*:\s*(\d*)/\s*(\d+)').match(log) + if res: + radio = float(res.group(1)) + total = float(res.group(2)) + return {'duty-cycle': 100.*radio/total } + return None + +def parseApp(log): + res = re.compile('Sending (.+?) (\d+) to 6G-(\d+)').match(log) + if res: + type = res.group(1) + id = int(res.group(2)) + dest = int(res.group(3)) + return {'event': 'send', 'type': type, 'id': id, 'node': dest } + res = re.compile('Received (.+?) (\d+) from 6G-(\d+)').match(log) + if res: + type = res.group(1) + id = int(res.group(2)) + src = int(res.group(3)) + return {'event': 'recv', 'type': type, 'id': id, 'src': src } + return None + +def parseLine(line): + res = re.compile('\s*([.\d]+)\\tID:(\d+)\\t\[(.*?):(.*?)\](.*)$').match(line) + if res: + time = float(res.group(1)) + nodeid = int(res.group(2)) + level = res.group(3).strip() + module = res.group(4).strip() + log = res.group(5).strip() + return time, nodeid, level, module, log + return None, None, None, None, None + +def doParse(file): + global networkFormationTime + + time = None + lastPrintedTime = 0 + + arrays = { + "packets": [], + "energest": [], + "ranks": [], + "trickle": [], + "switches": [], + "topology": [], + } + +# print("\nProcessing %s" %(file)) + # Filter out non-printable chars from log file + os.system("cat %s | tr -dc '[:print:]\n\t' | sponge %s" %(file, file)) + for line in open(file, 'r').readlines(): + # match time, id, module, log; The common format for all log lines + time, nodeid, level, module, log = parseLine(line) + + if time == None: + # malformed line + continue + + if time - lastPrintedTime >= 60: +# print("%u, "%(time / 60),end='', flush=True) + lastPrintedTime = time + + entry = { + "timestamp": timedelta(seconds=time), + "node": nodeid, + } + + try: + if module == "App": + ret = parseApp(log) + if(ret != None): + entry.update(ret) + if(ret['event'] == 'send' and ret['type'] == 'request'): + # populate series of sent requests + entry['pdr'] = 0. + arrays["packets"].append(entry) + if networkFormationTime == None: + networkFormationTime = time + elif(ret['event'] == 'recv' and ret['type'] == 'response'): + # update sent request series with latency and PDR + txElement = [x for x in arrays["packets"] if x['event']=='send' and x['id']==ret['id']][0] + txElement['latency'] = time - txElement['timestamp'].seconds + txElement['pdr'] = 100. + + if module == "Energest": + ret = parseEnergest(log) + if(ret != None): + entry.update(ret) + arrays["energest"].append(entry) + + if module == "RPL": + ret = parseRPL(log) + if(ret != None): + entry.update(ret) + if(ret['event'] == 'rank'): + arrays["ranks"].append(entry) + arrays["trickle"].append(entry) + elif(ret['event'] == 'switch'): + arrays["switches"].append(entry) + elif(ret['event'] == 'sending'): + if not ret['message'] in arrays: + arrays[ret['message']] = [] + arrays[ret['message']].append(entry) + elif(ret['event'] == 'topology'): + for n in parents.keys(): + nodeEntry = entry.copy() + nodeEntry["node"] = n + nodeEntry["hops"] = calculateHops(n) + nodeEntry["children"] = calculateChildren(n) + arrays["topology"].append(nodeEntry) + except: # typical exception: failed str conversion to int, due to lossy logs + print("Exception: %s" %(str(sys.exc_info()[0]))) + continue + +# print("") + + # Remove last few packets -- might be in-flight when test stopped + arrays["packets"] = arrays["packets"][0:-10] + + dfs = {} + for key in arrays.keys(): + if(len(arrays[key]) > 0): + df = DataFrame(arrays[key]) + dfs[key] = df.set_index("timestamp") + + return dfs + +def outputStats(dfs, key, metric, agg, name, metricLabel = None): + if not key in dfs: + return + + df = dfs[key] + perNode = getattr(df.groupby("node")[metric], agg)() + perTime = getattr(df.groupby([pd.Grouper(freq="2Min")])[metric], agg)() + + print(" %s:" %(metricLabel if metricLabel != None else metric)) + print(" name: %s" %(name)) + print(" per-node:") + print(" x: [%s]" %(", ".join(["%u"%x for x in sort(df.node.unique())]))) + print(" y: [%s]" %(', '.join(["%.4f"%(x) for x in perNode]))) + print(" per-time:") + print(" x: [%s]" %(", ".join(["%u"%x for x in range(0, 2*len(df.groupby([pd.Grouper(freq="2Min")]).mean().index), 2)]))) + print(" y: [%s]" %(', '.join(["%.4f"%(x) for x in perTime]).replace("nan", "null"))) + +def main(): + if len(sys.argv) < 1: + return + else: + file = sys.argv[1].rstrip('/') + + # Parse the original log + dfs = doParse(file) + + if len(dfs) == 0: + return + + print("global-stats:") + print(" pdr: %.4f" %(dfs["packets"]["pdr"].mean())) + print(" loss-rate: %.e" %(1-(dfs["packets"]["pdr"].mean()/100))) + print(" packets-sent: %u" %(dfs["packets"]["pdr"].count())) + print(" packets-received: %u" %(dfs["packets"]["pdr"].sum()/100)) + print(" latency: %.4f" %(dfs["packets"]["latency"].mean())) + print(" duty-cycle: %.2f" %(dfs["energest"]["duty-cycle"].mean())) + print(" channel-utilization: %.2f" %(dfs["energest"]["channel-utilization"].mean())) + print(" network-formation-time: %.2f" %(networkFormationTime)) + print("stats:") + + # Output relevant metrics + outputStats(dfs, "packets", "pdr", "mean", "Round-trip PDR (%)") + outputStats(dfs, "packets", "latency", "mean", "Round-trip latency (s)") + + outputStats(dfs, "energest", "duty-cycle", "mean", "Radio duty cycle (%)") + outputStats(dfs, "energest", "channel-utilization", "mean", "Channel utilization (%)") + + outputStats(dfs, "ranks", "rank", "mean", "RPL rank (ETX-128)") + outputStats(dfs, "switches", "pswitch", "count", "RPL parent switches (#)") + outputStats(dfs, "trickle", "trickle", "mean", "RPL Trickle period (min)") + + outputStats(dfs, "DIS", "message", "count", "RPL DIS sent (#)", "rpl-dis") + outputStats(dfs, "unicast-DIO", "message", "count", "RPL uDIO sent (#)", "rpl-udio") + outputStats(dfs, "multicast-DIO", "message", "count", "RPL mDIO sent (#)", "rpl-mdio") + outputStats(dfs, "DAO", "message", "count", "RPL DAO sent (#)", "rpl-dao") + outputStats(dfs, "DAO-ACK", "message", "count", "RPL DAO-ACK sent (#)", "rpl-daoack") + + outputStats(dfs, "topology", "hops", "mean", "RPL hop count (#)") + outputStats(dfs, "topology", "children", "mean", "RPL children count (#)") + +main() diff --git a/examples/benchmarks/rpl-req-resp/project-conf.h b/examples/benchmarks/rpl-req-resp/project-conf.h new file mode 100644 index 000000000..1140bb9e5 --- /dev/null +++ b/examples/benchmarks/rpl-req-resp/project-conf.h @@ -0,0 +1,48 @@ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ + +/* Testbed configuration */ +#define ROOT_ID 1 +#if CONTIKI_TARGET_COOJA +#define DEPLOYMENT_MAPPING deployment_cooja8 +#else /* CONTIKI_TARGET_COOJA */ +#define DEPLOYMENT_MAPPING deployment_sics_firefly +#endif /* CONTIKI_TARGET_COOJA */ +#define IEEE802154_CONF_PANID 0x8921 + +/* Logging */ +#define LOG_CONF_LEVEL_RPL LOG_LEVEL_INFO +#define LOG_CONF_LEVEL_MAC LOG_LEVEL_WARN +#define LOG_CONF_WITH_COMPACT_ADDR 1 + +/* Provisioning */ +#define NETSTACK_MAX_ROUTE_ENTRIES 25 +#define NBR_TABLE_CONF_MAX_NEIGHBORS 8 + +#if CONFIG_OPTIMS >= 1 + +/* RPL configuration */ +#define RPL_MRHOF_CONF_SQUARED_ETX 1 +#define RPL_CONF_MAX_RANKINC 0 + +/* TSCH configuration */ +#define TSCH_CONF_RX_WAIT 1000 +#define ORCHESTRA_CONF_UNICAST_PERIOD 7 + +#if CONFIG_OPTIMS == 2 + +/* Five nines reliability paper used the config below */ +#define RPL_CONF_DIO_INTERVAL_MIN 14 /* 2^14 ms = 16.384 s */ +#define RPL_CONF_DIO_INTERVAL_DOUBLINGS 6 /* 2^(14+6) ms = 1048.576 s */ +#define RPL_CONF_PROBING_INTERVAL (60 * CLOCK_SECOND) + +/* Five nines reliability paper used the config below */ +#define TSCH_CONF_KEEPALIVE_TIMEOUT (20 * CLOCK_SECOND) +#define TSCH_CONF_MAX_KEEPALIVE_TIMEOUT (60 * CLOCK_SECOND) +//#define TSCH_CONF_EB_PERIOD (16 * CLOCK_SECOND) +//#define TSCH_CONF_MAX_EB_PERIOD (50 * CLOCK_SECOND) + +#endif +#endif + +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/benchmarks/rpl-req-resp/sim.csc b/examples/benchmarks/rpl-req-resp/sim.csc new file mode 100644 index 000000000..d973a1d8d --- /dev/null +++ b/examples/benchmarks/rpl-req-resp/sim.csc @@ -0,0 +1,275 @@ + + + [APPS_DIR]/mrm + [APPS_DIR]/mspsim + [APPS_DIR]/avrora + [APPS_DIR]/serial_socket + [APPS_DIR]/powertracker + + My simulation + 123456 + 1000000 + + org.contikios.cooja.radiomediums.UDGM + 50.0 + 100.0 + 1.0 + 1.0 + + + 40000 + + + org.contikios.cooja.contikimote.ContikiMoteType + mtype90 + Cooja Mote Type #1 + [CONTIKI_DIR]/examples/benchmarks/rpl-req-resp/node.c + make node.cooja TARGET=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 + 12.478629242391953 + 42.201041276604826 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 1 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype90 + + + + org.contikios.cooja.interfaces.Position + 25.625935608473608 + 82.53975431376661 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 2 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype90 + + + + org.contikios.cooja.interfaces.Position + 51.615094138350024 + 59.70602651475372 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 3 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype90 + + + + org.contikios.cooja.interfaces.Position + 41.04314122620578 + 121.24693889311891 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 4 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype90 + + + + org.contikios.cooja.interfaces.Position + 64.9463558635099 + 104.25039302469283 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 5 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype90 + + + + org.contikios.cooja.interfaces.Position + 93.59263858654369 + 75.40399148300003 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 6 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype90 + + + + org.contikios.cooja.interfaces.Position + 75.6297158696234 + 139.97002035548905 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 7 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype90 + + + + org.contikios.cooja.interfaces.Position + 104.34293924684245 + 116.07658566915099 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 8 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype90 + + + + org.contikios.cooja.plugins.SimControl + 280 + 2 + 160 + 400 + 0 + + + org.contikios.cooja.plugins.Visualizer + + true + org.contikios.cooja.plugins.skins.IDVisualizerSkin + org.contikios.cooja.plugins.skins.GridVisualizerSkin + org.contikios.cooja.plugins.skins.TrafficVisualizerSkin + org.contikios.cooja.plugins.skins.UDGMVisualizerSkin + 2.4250860844175466 0.0 0.0 2.4250860844175466 35.26895372864869 -46.9106236441515 + + 400 + 3 + 400 + 1 + 1 + + + org.contikios.cooja.plugins.LogListener + + App + + + + 827 + 0 + 665 + 681 + -1 + + + org.contikios.cooja.plugins.TimeLine + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + + + + 500.0 + + 1539 + 1 + 263 + 0 + 709 + + diff --git a/examples/benchmarks/testbeds/cooja8.c b/examples/benchmarks/testbeds/cooja8.c new file mode 100644 index 000000000..f6ccaec97 --- /dev/null +++ b/examples/benchmarks/testbeds/cooja8.c @@ -0,0 +1,14 @@ +#include "services/deployment/deployment.h" + +/** \brief A mapping table for a 8-node Cooja mote simulation. */ +const struct id_mac deployment_cooja8[] = { + { 1, {{0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01}}}, + { 2, {{0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02}}}, + { 3, {{0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03}}}, + { 4, {{0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04}}}, + { 5, {{0x00,0x05,0x00,0x05,0x00,0x05,0x00,0x05}}}, + { 6, {{0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06}}}, + { 7, {{0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x07}}}, + { 8, {{0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08}}}, + { 0, {{0}}} +}; diff --git a/examples/benchmarks/testbeds/sics-firefly.c b/examples/benchmarks/testbeds/sics-firefly.c new file mode 100644 index 000000000..0478dc65d --- /dev/null +++ b/examples/benchmarks/testbeds/sics-firefly.c @@ -0,0 +1,31 @@ +#include "services/deployment/deployment.h" + +/** \brief The 25-node RISE SICS node testbed. Firefly-reva nodes. */ +const struct id_mac deployment_sics_firefly[] = { + { 1, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb6,0x14}}}, + { 2, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb1,0xe7}}}, + { 3, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb4,0x35}}}, + { 4, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb1,0xcf}}}, + { 5, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb2,0x06}}}, + { 6, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb1,0x5f}}}, + { 8, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb1,0x91}}}, + { 7, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb1,0x29}}}, + { 9, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb1,0xc6}}}, + { 10, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb1,0x63}}}, + { 12, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb2,0x03}}}, + { 11, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb4,0x3b}}}, + { 13, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb6,0x0d}}}, + { 14, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb5,0x66}}}, + { 15, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb5,0x8a}}}, + { 16, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb4,0x49}}}, + { 17, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb1,0x35}}}, + { 18, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb2,0x15}}}, + { 19, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb5,0xfc}}}, + { 20, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb1,0xa8}}}, + { 21, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb1,0x6a}}}, + { 22, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb4,0x5b}}}, + { 23, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb1,0xe6}}}, + { 24, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb6,0x00}}}, + { 25, {{0x00,0x12,0x4b,0x00,0x06,0x0d,0xb1,0xb8}}}, + { 0, {{0}}} +}; From fd310067b981df1989f182e378ae92c55de63335 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 9 Jun 2018 14:40:35 +0200 Subject: [PATCH 190/485] Added CI test for benchmarks/rpl-req-resp --- tests/03-compile-arm-ports-02/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/03-compile-arm-ports-02/Makefile b/tests/03-compile-arm-ports-02/Makefile index 7efb1b14b..190d36e4d 100644 --- a/tests/03-compile-arm-ports-02/Makefile +++ b/tests/03-compile-arm-ports-02/Makefile @@ -39,6 +39,7 @@ libs/data-structures/zoul \ libs/ipv6-uipbuf/zoul \ nullnet/zoul \ slip-radio/zoul \ +benchmarks/rpl-req-resp/zoul \ dev/gpio-hal/zoul:BOARD=remote-reva \ dev/gpio-hal/zoul:BOARD=remote-revb \ dev/gpio-hal/zoul:BOARD=firefly-reva \ From 05455f949c9845701dbac4aeab6666a46d6a0c6c Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 23 Jun 2018 13:35:22 +0100 Subject: [PATCH 191/485] Enable license auto-detection This commit changes the LICENSE.md text such that it can get automatically detected by licensee and github's license detection. This will make the license appear in the project's overview on github. Additional information that was previously in LICENSE.md is moved to the README. --- LICENSE.md | 67 +++++++++++++++++++++++------------------------------- README.md | 5 +++- 2 files changed, 32 insertions(+), 40 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index b2f909d44..f4b1a054c 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,41 +1,30 @@ -Contiki-NG is licensed under the 3-clause BSD license. This license gives -everyone the right to use and distribute the code, either in binary or -source code format, as long as the copyright license is retained in -the source code. +Copyright (c) (Year), (Name of copyright holder) +All rights reserved. -The copyright for different parts of the code is held by different -people and organizations, but the code is licensed under the same type -of license. The license text is: +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: -``` -/* - * Copyright (c) (Year), (Name of copyright holder) - * 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. - */ -``` +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. diff --git a/README.md b/README.md index df7d7ff58..e9a1005ef 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,10 @@ 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). This license gives +everyone the right to use and distribute the code, either in binary or +source code format, as long as the copyright license is retained in +the source code. Contiki-NG started as a fork of the Contiki OS and retains some of its original features. From 14225300fcb17d5fe5feb814954f03c51daeb457 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 24 Jun 2018 16:29:47 +0100 Subject: [PATCH 192/485] Specify default tun/tap name on Mac OS e5c7437 fixed a bug that was preventing multiple instances of tunslip6 from running. This same commit however broke tunslip6 on Mac OS, as documented in contiki-os/contiki#1560 as well as in contiki-ng/contiki-ng#466 Basically the commit in question merely removed some code. This commit puts that code back in, but makes it conditional for Mac OS. Fixes #466 --- tools/serial-io/tunslip6.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tools/serial-io/tunslip6.c b/tools/serial-io/tunslip6.c index e1a72078a..aa8b5b9fd 100644 --- a/tools/serial-io/tunslip6.c +++ b/tools/serial-io/tunslip6.c @@ -885,6 +885,17 @@ exit(1); } } +#ifdef __APPLE__ + if(*tundev == '\0') { + /* Use default. */ + if(tap) { + strcpy(tundev, "tap0"); + } else { + strcpy(tundev, "tun0"); + } + } +#endif + if(host != NULL) { struct addrinfo hints, *servinfo, *p; int rv; From a4757cb723e3131fe5c67384d063df084509fece Mon Sep 17 00:00:00 2001 From: "carlosgp143@gmail.com" Date: Wed, 27 Jun 2018 09:36:00 +0200 Subject: [PATCH 193/485] Changed default values for dynamic adaptation and Q-Mode objects --- examples/lwm2m-ipso-objects/project-conf.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/lwm2m-ipso-objects/project-conf.h b/examples/lwm2m-ipso-objects/project-conf.h index 01f919866..a8603c67b 100644 --- a/examples/lwm2m-ipso-objects/project-conf.h +++ b/examples/lwm2m-ipso-objects/project-conf.h @@ -64,7 +64,7 @@ #define LWM2M_QUEUE_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION 1 #define LWM2M_QUEUE_MODE_CONF_DEFAULT_CLIENT_AWAKE_TIME 2000 #define LWM2M_QUEUE_MODE_CONF_DEFAULT_CLIENT_SLEEP_TIME 10000 - #define LWM2M_QUEUE_MODE_CONF_DEFAULT_DYNAMIC_ADAPTATION_FLAG 1 - #define LWM2M_QUEUE_MODE_OBJECT_CONF_ENABLED 0 */ + #define LWM2M_QUEUE_MODE_CONF_DEFAULT_DYNAMIC_ADAPTATION_FLAG 0 + #define LWM2M_QUEUE_MODE_OBJECT_CONF_ENABLED 1 */ #endif /* PROJECT_CONF_H_ */ From 2db8fa80e211eab66908deced0bc8063d6441882 Mon Sep 17 00:00:00 2001 From: "carlosgp143@gmail.com" Date: Thu, 31 May 2018 16:22:01 +0200 Subject: [PATCH 194/485] Unified coap_request_state and added status for extra information --- os/net/app-layer/coap/coap-blocking-api.c | 58 ++++++---- os/net/app-layer/coap/coap-blocking-api.h | 17 ++- os/net/app-layer/coap/coap-callback-api.c | 66 +++++++----- os/net/app-layer/coap/coap-callback-api.h | 21 ++-- os/net/app-layer/coap/coap-request-state.h | 69 ++++++++++++ os/services/lwm2m/lwm2m-rd-client.c | 118 ++++++++++----------- 6 files changed, 216 insertions(+), 133 deletions(-) create mode 100644 os/net/app-layer/coap/coap-request-state.h diff --git a/os/net/app-layer/coap/coap-blocking-api.c b/os/net/app-layer/coap/coap-blocking-api.c index 1be7cbe7c..9fd691d74 100644 --- a/os/net/app-layer/coap/coap-blocking-api.c +++ b/os/net/app-layer/coap/coap-blocking-api.c @@ -60,37 +60,36 @@ void coap_blocking_request_callback(void *callback_data, coap_message_t *response) { - coap_request_state_t *state = (coap_request_state_t *)callback_data; + coap_blocking_request_state_t *blocking_state = (coap_blocking_request_state_t *)callback_data; - state->response = response; - process_poll(state->process); + blocking_state->state.response = response; + process_poll(blocking_state->process); } /*---------------------------------------------------------------------------*/ PT_THREAD(coap_blocking_request - (coap_request_state_t *state, process_event_t ev, + (coap_blocking_request_state_t *blocking_state, process_event_t ev, coap_endpoint_t *remote_ep, coap_message_t *request, coap_blocking_response_handler_t request_callback)) { - PT_BEGIN(&state->pt); + /* Before PT_BEGIN in order to not be a local variable in the PT_Thread and maintain it */ + coap_request_state_t *state = &blocking_state->state; - static uint32_t res_block; - static uint8_t more; - static uint8_t block_error; + PT_BEGIN(&blocking_state->pt); state->block_num = 0; state->response = NULL; - state->process = PROCESS_CURRENT(); + blocking_state->process = PROCESS_CURRENT(); - more = 0; - res_block = 0; - block_error = 0; + state->more = 0; + state->res_block = 0; + state->block_error = 0; do { request->mid = coap_get_mid(); if((state->transaction = coap_new_transaction(request->mid, remote_ep))) { state->transaction->callback = coap_blocking_request_callback; - state->transaction->callback_data = state; + state->transaction->callback_data = blocking_state; if(state->block_num > 0) { coap_set_header_block2(request, state->block_num, 0, @@ -104,33 +103,46 @@ PT_THREAD(coap_blocking_request coap_send_transaction(state->transaction); LOG_DBG("Requested #%"PRIu32" (MID %u)\n", state->block_num, request->mid); - PT_YIELD_UNTIL(&state->pt, ev == PROCESS_EVENT_POLL); + PT_YIELD_UNTIL(&blocking_state->pt, ev == PROCESS_EVENT_POLL); if(!state->response) { LOG_WARN("Server not responding\n"); - PT_EXIT(&state->pt); + state->status = COAP_REQUEST_STATUS_TIMEOUT; + PT_EXIT(&blocking_state->pt); } - coap_get_header_block2(state->response, &res_block, &more, NULL, NULL); + coap_get_header_block2(state->response, &state->res_block, &state->more, NULL, NULL); - LOG_DBG("Received #%"PRIu32"%s (%u bytes)\n", res_block, more ? "+" : "", + LOG_DBG("Received #%"PRIu32"%s (%u bytes)\n", state->res_block, state->more ? "+" : "", state->response->payload_len); + if(state->more) { + state->status = COAP_REQUEST_STATUS_MORE; + } else { + state->status = COAP_REQUEST_STATUS_RESPONSE; + } - if(res_block == state->block_num) { + if(state->res_block == state->block_num) { request_callback(state->response); ++(state->block_num); } else { LOG_WARN("WRONG BLOCK %"PRIu32"/%"PRIu32"\n", - res_block, state->block_num); - ++block_error; + state->res_block, state->block_num); + ++(state->block_error); } } else { LOG_WARN("Could not allocate transaction buffer"); - PT_EXIT(&state->pt); + PT_EXIT(&blocking_state->pt); } - } while(more && block_error < COAP_MAX_ATTEMPTS); + } while(state->more && (state->block_error) < COAP_MAX_ATTEMPTS); - PT_END(&state->pt); + if((state->block_error) >= COAP_MAX_ATTEMPTS) { + /* failure - now we give up */ + state->status = COAP_REQUEST_STATUS_BLOCK_ERROR; + } else { + /* No more blocks, request finished */ + state->status = COAP_REQUEST_STATUS_FINISHED; + } + PT_END(&blocking_state->pt); } /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/os/net/app-layer/coap/coap-blocking-api.h b/os/net/app-layer/coap/coap-blocking-api.h index d9a916c04..716a261b5 100644 --- a/os/net/app-layer/coap/coap-blocking-api.h +++ b/os/net/app-layer/coap/coap-blocking-api.h @@ -39,31 +39,30 @@ #include "sys/pt.h" #include "coap-transactions.h" +#include "coap-request-state.h" /*---------------------------------------------------------------------------*/ /*- Client Part -------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ -typedef struct coap_request_state { +typedef struct coap_blocking_request_state { + coap_request_state_t state; struct pt pt; struct process *process; - coap_transaction_t *transaction; - coap_message_t *response; - uint32_t block_num; -} coap_request_state_t; +} coap_blocking_request_state_t; typedef void (* coap_blocking_response_handler_t)(coap_message_t *response); PT_THREAD(coap_blocking_request - (coap_request_state_t *state, process_event_t ev, + (coap_blocking_request_state_t *blocking_state, process_event_t ev, coap_endpoint_t *remote, coap_message_t *request, coap_blocking_response_handler_t request_callback)); #define COAP_BLOCKING_REQUEST(server_endpoint, request, chunk_handler) \ { \ - static coap_request_state_t request_state; \ - PT_SPAWN(process_pt, &request_state.pt, \ - coap_blocking_request(&request_state, ev, \ + static coap_blocking_request_state_t blocking_state; \ + PT_SPAWN(process_pt, &blocking_state.pt, \ + coap_blocking_request(&blocking_state, ev, \ server_endpoint, \ request, chunk_handler) \ ); \ diff --git a/os/net/app-layer/coap/coap-callback-api.c b/os/net/app-layer/coap/coap-callback-api.c index 0f0ab2c99..41a2ef846 100644 --- a/os/net/app-layer/coap/coap-callback-api.c +++ b/os/net/app-layer/coap/coap-callback-api.c @@ -54,19 +54,13 @@ #define LOG_MODULE "coap" #define LOG_LEVEL LOG_LEVEL_COAP -/* These should go into the state struct so that we can have multiple - requests */ - -static uint32_t res_block; -static uint8_t more; -static uint8_t block_error; - static void coap_request_callback(void *callback_data, coap_message_t *response); /*---------------------------------------------------------------------------*/ static int -progress_request(coap_request_state_t *state) { +progress_request(coap_callback_request_state_t *callback_state) { + coap_request_state_t *state = &callback_state->state; coap_message_t *request = state->request; request->mid = coap_get_mid(); if((state->transaction = @@ -93,7 +87,9 @@ progress_request(coap_request_state_t *state) { static void coap_request_callback(void *callback_data, coap_message_t *response) { - coap_request_state_t *state = (coap_request_state_t *)callback_data; + coap_callback_request_state_t *callback_state = (coap_callback_request_state_t*)callback_data; + coap_request_state_t *state = &callback_state->state; + uint32_t res_block1; state->response = response; @@ -102,58 +98,70 @@ coap_request_callback(void *callback_data, coap_message_t *response) if(!state->response) { LOG_WARN("Server not responding giving up...\n"); - state->callback(state); + state->status = COAP_REQUEST_STATUS_TIMEOUT; + callback_state->callback(callback_state); return; } /* Got a response */ - coap_get_header_block2(state->response, &res_block, &more, NULL, NULL); + coap_get_header_block2(state->response, &state->res_block, &state->more, NULL, NULL); coap_get_header_block1(state->response, &res_block1, NULL, NULL, NULL); LOG_DBG("Received #%lu%s B1:%lu (%u bytes)\n", - (unsigned long)res_block, (unsigned)more ? "+" : "", + (unsigned long)state->res_block, (unsigned)state->more ? "+" : "", (unsigned long)res_block1, state->response->payload_len); - if(res_block == state->block_num) { + if(state->res_block == state->block_num) { /* Call the callback function as we have more data */ - state->callback(state); + if(state->more) { + state->status = COAP_REQUEST_STATUS_MORE; + } else { + state->status = COAP_REQUEST_STATUS_RESPONSE; + } + callback_state->callback(callback_state); /* this is only for counting BLOCK2 blocks.*/ ++(state->block_num); } else { - LOG_WARN("WRONG BLOCK %"PRIu32"/%"PRIu32"\n", res_block, state->block_num); - ++block_error; + LOG_WARN("WRONG BLOCK %"PRIu32"/%"PRIu32"\n", state->res_block, state->block_num); + ++(state->block_error); } - if(more && block_error < COAP_MAX_ATTEMPTS) { - progress_request(state); + if(state->more) { + if((state->block_error) < COAP_MAX_ATTEMPTS) { + progress_request(callback_state); + } else { + /* failure - now we give up and notify the callback */ + state->status = COAP_REQUEST_STATUS_BLOCK_ERROR; + callback_state->callback(callback_state); + } } else { - /* failure - now we give up and notify the callback */ + /* No more blocks, finish and notify the callback */ + state->status = COAP_REQUEST_STATUS_FINISHED; state->response = NULL; - state->callback(state); + callback_state->callback(callback_state); } } /*---------------------------------------------------------------------------*/ int -coap_send_request(coap_request_state_t *state, coap_endpoint_t *endpoint, +coap_send_request(coap_callback_request_state_t *callback_state, coap_endpoint_t *endpoint, coap_message_t *request, - void (*callback)(coap_request_state_t *state)) + void (*callback)(coap_callback_request_state_t *callback_state)) { - /* can we have these variables shared between multiple requests? */ - /* ripped from blocking request */ - more = 0; - res_block = 0; - block_error = 0; + coap_request_state_t *state = &callback_state->state; + state->more = 0; + state->res_block = 0; + state->block_error = 0; state->block_num = 0; state->response = NULL; state->request = request; state->remote_endpoint = endpoint; - state->callback = callback; + callback_state->callback = callback; - return progress_request(state); + return progress_request(callback_state); } /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/os/net/app-layer/coap/coap-callback-api.h b/os/net/app-layer/coap/coap-callback-api.h index 69ceea4f5..a9019aeb8 100644 --- a/os/net/app-layer/coap/coap-callback-api.h +++ b/os/net/app-layer/coap/coap-callback-api.h @@ -47,35 +47,30 @@ #include "coap-engine.h" #include "coap-transactions.h" +#include "coap-request-state.h" #include "sys/cc.h" /*---------------------------------------------------------------------------*/ /*- Client Part -------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ -typedef struct coap_request_state coap_request_state_t; +typedef struct coap_callback_request_state coap_callback_request_state_t; -struct coap_request_state { - coap_transaction_t *transaction; - coap_message_t *response; - coap_message_t *request; - coap_endpoint_t *remote_endpoint; - uint32_t block_num; - void *user_data; - coap_timer_t coap_timer; - void (*callback)(coap_request_state_t *state); +struct coap_callback_request_state { + coap_request_state_t state; + void (*callback)(coap_callback_request_state_t *state); }; /** * \brief Send a CoAP request to a remote endpoint - * \param state The state to handle the CoAP request + * \param callback_state The callback state to handle the CoAP request * \param endpoint The destination endpoint * \param request The request to be sent * \param callback callback to execute when the response arrives or the timeout expires * \return 1 if there is a transaction available to send, 0 otherwise */ -int coap_send_request(coap_request_state_t *state, coap_endpoint_t *endpoint, +int coap_send_request(coap_callback_request_state_t *callback_state, coap_endpoint_t *endpoint, coap_message_t *request, - void (*callback)(coap_request_state_t *state)); + void (*callback)(coap_callback_request_state_t *callback_state)); #endif /* COAP_CALLBACK_API_H_ */ /** @} */ diff --git a/os/net/app-layer/coap/coap-request-state.h b/os/net/app-layer/coap/coap-request-state.h new file mode 100644 index 000000000..4c5881bb6 --- /dev/null +++ b/os/net/app-layer/coap/coap-request-state.h @@ -0,0 +1,69 @@ +/* + * 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. + */ + +/** + * \addtogroup coap + * @{ + */ + +/** + * \file + * Common request state for all the APIs + * \author + * Carlos Gonzalo Peces + */ +#ifndef COAP_REQUEST_STATE_H_ +#define COAP_REQUEST_STATE_H_ + +typedef enum { + COAP_REQUEST_STATUS_RESPONSE, /* Response received and no more blocks */ + COAP_REQUEST_STATUS_MORE, /* Response received and there are more blocks */ + COAP_REQUEST_STATUS_FINISHED, /* Request finished */ + COAP_REQUEST_STATUS_TIMEOUT, /* Request Timeout after all retransmissions */ + COAP_REQUEST_STATUS_BLOCK_ERROR /* Blocks in wrong order */ +} coap_request_status_t; + + +typedef struct coap_request_state { + coap_transaction_t *transaction; + coap_message_t *response; + coap_message_t *request; + coap_endpoint_t *remote_endpoint; + uint32_t block_num; + uint32_t res_block; + uint8_t more; + uint8_t block_error; + void *user_data; + coap_request_status_t status; +} coap_request_state_t; + + +#endif /* COAP_REQUEST_STATE_H_ */ +/** @} */ diff --git a/os/services/lwm2m/lwm2m-rd-client.c b/os/services/lwm2m/lwm2m-rd-client.c index 63c9443e1..4b4b11528 100644 --- a/os/services/lwm2m/lwm2m-rd-client.c +++ b/os/services/lwm2m/lwm2m-rd-client.c @@ -84,7 +84,7 @@ #define STATE_MACHINE_UPDATE_INTERVAL 500 static struct lwm2m_session_info session_info; -static coap_request_state_t rd_request_state; +static coap_callback_request_state_t rd_request_state; static coap_message_t request[1]; /* This way the message can be treated as pointer as usual. */ @@ -118,7 +118,6 @@ static uint8_t rd_state = 0; static uint8_t rd_flags = FLAG_RD_DATA_UPDATE_ON_DIRTY; static uint64_t wait_until_network_check = 0; static uint64_t last_update; -static uint64_t last_rd_progress = 0; static char query_data[64]; /* allocate some data for queries and updates */ static uint8_t rd_data[128]; /* allocate some data for the RD */ @@ -126,7 +125,7 @@ static uint8_t rd_data[128]; /* allocate some data for the RD */ static uint32_t rd_block1; static uint8_t rd_more; static coap_timer_t rd_timer; -static void (*rd_callback)(coap_request_state_t *state); +static void (*rd_callback)(coap_callback_request_state_t *callback_state); static coap_timer_t block1_timer; @@ -143,7 +142,7 @@ static void queue_mode_awake_timer_callback(coap_timer_t *timer); #endif static void check_periodic_observations(); -static void update_callback(coap_request_state_t *state); +static void update_callback(coap_callback_request_state_t *callback_state); static int set_rd_data(coap_message_t *request) @@ -370,10 +369,11 @@ update_bootstrap_server(void) * TODO */ static void -bootstrap_callback(coap_request_state_t *state) +bootstrap_callback(coap_callback_request_state_t *callback_state) { + coap_request_state_t *state = &callback_state->state; LOG_DBG("Bootstrap callback Response: %d, ", state->response != NULL); - if(state->response) { + if(state->status == COAP_REQUEST_STATUS_RESPONSE) { if(CHANGED_2_04 == state->response->code) { LOG_DBG_("Considered done!\n"); rd_state = BOOTSTRAP_DONE; @@ -383,12 +383,14 @@ bootstrap_callback(coap_request_state_t *state) LOG_DBG_("Failed with code %d. Retrying\n", state->response->code); /* TODO Application callback? */ rd_state = INIT; - } else if(BOOTSTRAP_SENT == rd_state) { /* this can handle double invocations */ - /* Failure! */ - LOG_DBG("Bootstrap failed! Retry?"); + } else if(state->status == COAP_REQUEST_STATUS_TIMEOUT) { + LOG_DBG_("Server not responding! Retry?"); rd_state = DO_BOOTSTRAP; + } else if(state->status == COAP_REQUEST_STATUS_FINISHED) { + LOG_DBG_("Request finished. Ignore\n"); } else { - LOG_DBG("Ignore\n"); + LOG_DBG_("Unexpected error! Retry?"); + rd_state = DO_BOOTSTRAP; } } /*---------------------------------------------------------------------------*/ @@ -427,10 +429,11 @@ block1_rd_callback(coap_timer_t *timer) * Page 65-66 in 07 April 2016 spec. */ static void -registration_callback(coap_request_state_t *state) +registration_callback(coap_callback_request_state_t *callback_state) { - LOG_DBG("Registration callback. Response: %d, ", state->response != NULL); - if(state->response) { + coap_request_state_t *state = &callback_state->state; + LOG_DBG("Registration callback. Status: %d. Response: %d, ", state->status, state->response != NULL); + if(state->status == COAP_REQUEST_STATUS_RESPONSE) { /* check state and possibly set registration to done */ /* If we get a continue - we need to call the rd generator one more time */ if(CONTINUE_2_31 == state->response->code) { @@ -472,10 +475,14 @@ registration_callback(coap_request_state_t *state) } /* TODO Application callback? */ rd_state = INIT; - /* remember last progress time */ - last_rd_progress = coap_timer_uptime(); + } else if(state->status == COAP_REQUEST_STATUS_TIMEOUT) { + LOG_DBG_("Server not responding, trying to reconnect\n"); + rd_state = INIT; + } else if(state->status == COAP_REQUEST_STATUS_FINISHED){ + LOG_DBG_("Request finished. Ignore\n"); } else { - LOG_DBG_("Ignore\n"); + LOG_DBG_("Unexpected error, trying to reconnect\n"); + rd_state = INIT; } } /*---------------------------------------------------------------------------*/ @@ -483,11 +490,12 @@ registration_callback(coap_request_state_t *state) * Page 65-66 in 07 April 2016 spec. */ static void -update_callback(coap_request_state_t *state) +update_callback(coap_callback_request_state_t *callback_state) { - LOG_DBG("Update callback. Response: %d, ", state->response != NULL); + coap_request_state_t *state = &callback_state->state; + LOG_DBG("Update callback. Status: %d. Response: %d, ", state->status, state->response != NULL); - if(state->response) { + if(state->status == COAP_REQUEST_STATUS_RESPONSE) { /* If we get a continue - we need to call the rd generator one more time */ if(CONTINUE_2_31 == state->response->code) { /* We assume that size never change?! */ @@ -522,20 +530,26 @@ update_callback(coap_request_state_t *state) state->response->code); rd_state = DO_REGISTRATION; } - /* remember last progress */ - last_rd_progress = coap_timer_uptime(); + } else if(state->status == COAP_REQUEST_STATUS_TIMEOUT) { + LOG_DBG_("Server not responding, trying to reconnect\n"); + rd_state = INIT; + } else if(state->status == COAP_REQUEST_STATUS_FINISHED){ + LOG_DBG_("Request finished. Ignore\n"); } else { - LOG_DBG("Ignore\n"); + LOG_DBG_("Unexpected error, trying to reconnect\n"); + rd_state = INIT; } } /*---------------------------------------------------------------------------*/ static void -deregister_callback(coap_request_state_t *state) +deregister_callback(coap_callback_request_state_t *callback_state) { - LOG_DBG("Deregister callback. Response Code: %d\n", + coap_request_state_t *state = &callback_state->state; + LOG_DBG("Deregister callback. Status: %d. Response Code: %d\n", + state->status, state->response != NULL ? state->response->code : 0); - if(state->response && (DELETED_2_02 == state->response->code)) { + if(state->status == COAP_REQUEST_STATUS_RESPONSE && (DELETED_2_02 == state->response->code)) { LOG_DBG("Deregistration success\n"); rd_state = DEREGISTERED; perform_session_callback(LWM2M_RD_CLIENT_DEREGISTERED); @@ -548,13 +562,6 @@ deregister_callback(coap_request_state_t *state) } } /*---------------------------------------------------------------------------*/ -static void -recover_from_rd_delay(void) -{ - /* This can be improved in the future... */ - rd_state = INIT; -} -/*---------------------------------------------------------------------------*/ /* CoAP timer callback */ static void periodic_process(coap_timer_t *timer) @@ -611,10 +618,10 @@ periodic_process(coap_timer_t *timer) LOG_INFO_COAP_EP(&session_info.bs_server_ep); LOG_INFO_("] as '%s'\n", query_data); - coap_send_request(&rd_request_state, &session_info.bs_server_ep, - request, bootstrap_callback); - - rd_state = BOOTSTRAP_SENT; + if(coap_send_request(&rd_request_state, &session_info.bs_server_ep, + request, bootstrap_callback)) { + rd_state = BOOTSTRAP_SENT; + } } } break; @@ -710,18 +717,14 @@ periodic_process(coap_timer_t *timer) } LOG_INFO_("' More:%d\n", rd_more); - coap_send_request(&rd_request_state, &session_info.server_ep, - request, registration_callback); - last_rd_progress = coap_timer_uptime(); - rd_state = REGISTRATION_SENT; + if(coap_send_request(&rd_request_state, &session_info.server_ep, + request, registration_callback)){ + rd_state = REGISTRATION_SENT; + } } break; case REGISTRATION_SENT: /* just wait until the callback kicks us to the next state... */ - if(last_rd_progress + MAX_RD_UPDATE_WAIT < coap_timer_uptime()) { - /* Timeout on the update - something is wrong? */ - recover_from_rd_delay(); - } break; case REGISTRATION_DONE: /* All is done! */ @@ -733,10 +736,10 @@ periodic_process(coap_timer_t *timer) ((uint32_t)session_info.lifetime * 500) <= now - last_update) { /* triggered or time to send an update to the server, at half-time! sec vs ms */ prepare_update(request, rd_flags & FLAG_RD_DATA_UPDATE_TRIGGERED); - coap_send_request(&rd_request_state, &session_info.server_ep, request, - update_callback); - last_rd_progress = coap_timer_uptime(); - rd_state = UPDATE_SENT; + if(coap_send_request(&rd_request_state, &session_info.server_ep, request, + update_callback)) { + rd_state = UPDATE_SENT; + } } break; #if LWM2M_QUEUE_MODE_ENABLED @@ -754,27 +757,24 @@ periodic_process(coap_timer_t *timer) LWM2M_QUEUE_MODE_WAKE_UP(); #endif /* LWM2M_QUEUE_MODE_WAKE_UP */ prepare_update(request, rd_flags & FLAG_RD_DATA_UPDATE_TRIGGERED); - coap_send_request(&rd_request_state, &session_info.server_ep, request, - update_callback); - last_rd_progress = coap_timer_uptime(); - rd_state = UPDATE_SENT; + if(coap_send_request(&rd_request_state, &session_info.server_ep, request, + update_callback)) { + rd_state = UPDATE_SENT; + } break; #endif /* LWM2M_QUEUE_MODE_ENABLED */ case UPDATE_SENT: /* just wait until the callback kicks us to the next state... */ - if(last_rd_progress + MAX_RD_UPDATE_WAIT < coap_timer_uptime()) { - /* Timeout on the update - something is wrong? */ - recover_from_rd_delay(); - } break; case DEREGISTER: LOG_INFO("DEREGISTER %s\n", session_info.assigned_ep); coap_init_message(request, COAP_TYPE_CON, COAP_DELETE, 0); coap_set_header_uri_path(request, session_info.assigned_ep); - coap_send_request(&rd_request_state, &session_info.server_ep, request, - deregister_callback); - rd_state = DEREGISTER_SENT; + if(coap_send_request(&rd_request_state, &session_info.server_ep, request, + deregister_callback)) { + rd_state = DEREGISTER_SENT; + } break; case DEREGISTER_SENT: break; From 840bab8f6cc80a5d6aa851369b99132275d80fa5 Mon Sep 17 00:00:00 2001 From: Toshio Ito Date: Fri, 6 Jul 2018 13:46:36 +0900 Subject: [PATCH 195/485] uip_icmp6_send: move log messages at the end of function. It prints UIP_IP_BUF->destipaddr, but this is updated in the middle of this function. Before this fix, the address was NOT the destination of the ICMPv6 packet, but was whatever destination that previous operation wrote to uip_buf. --- os/net/ipv6/uip-icmp6.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/os/net/ipv6/uip-icmp6.c b/os/net/ipv6/uip-icmp6.c index be33a1101..707a13309 100644 --- a/os/net/ipv6/uip-icmp6.c +++ b/os/net/ipv6/uip-icmp6.c @@ -253,10 +253,6 @@ uip_icmp6_error_output(uint8_t type, uint8_t code, uint32_t param) { void uip_icmp6_send(const uip_ipaddr_t *dest, int type, int code, int payload_len) { - LOG_INFO("Sending ICMPv6 packet to "); - LOG_INFO_6ADDR(&UIP_IP_BUF->destipaddr); - LOG_INFO_(", type %u, code %u, len %u\n", type, code, payload_len); - UIP_IP_BUF->vtc = 0x60; UIP_IP_BUF->tcflow = 0; UIP_IP_BUF->flow = 0; @@ -279,6 +275,10 @@ uip_icmp6_send(const uip_ipaddr_t *dest, int type, int code, int payload_len) UIP_STAT(++uip_stat.icmp.sent); UIP_STAT(++uip_stat.ip.sent); + LOG_INFO("Sending ICMPv6 packet to "); + LOG_INFO_6ADDR(&UIP_IP_BUF->destipaddr); + LOG_INFO_(", type %u, code %u, len %u\n", type, code, payload_len); + tcpip_ipv6_output(); } /*---------------------------------------------------------------------------*/ From 4e79ba949f857e197b895fa7c46ec5899ce236c6 Mon Sep 17 00:00:00 2001 From: ohrensessel Date: Mon, 30 Jul 2018 20:53:29 +0200 Subject: [PATCH 196/485] sixtop example: fix incorrect access to uint8_t *cell_list --- examples/6tisch/sixtop/sf-simple.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/6tisch/sixtop/sf-simple.c b/examples/6tisch/sixtop/sf-simple.c index 689c668e7..f7393ab4c 100644 --- a/examples/6tisch/sixtop/sf-simple.c +++ b/examples/6tisch/sixtop/sf-simple.c @@ -108,7 +108,7 @@ print_cell_list(const uint8_t *cell_list, uint16_t cell_list_len) uint16_t i; sf_simple_cell_t cell; - for(i = 0; i < (cell_list_len / sizeof(cell)); i++) { + for(i = 0; i < cell_list_len; i += sizeof(cell)) { read_cell(&cell_list[i], &cell); PRINTF("%u ", cell.timeslot_offset); } @@ -132,7 +132,7 @@ add_links_to_schedule(const linkaddr_t *peer_addr, uint8_t link_option, return; } - for(i = 0; i < (cell_list_len / sizeof(cell)); i++) { + for(i = 0; i < cell_list_len; i += sizeof(cell)) { read_cell(&cell_list[i], &cell); if(cell.timeslot_offset == 0xffff) { continue; @@ -166,7 +166,7 @@ remove_links_to_schedule(const uint8_t *cell_list, uint16_t cell_list_len) return; } - for(i = 0; i < (cell_list_len / sizeof(cell)); i++) { + for(i = 0; i < cell_list_len; i += sizeof(cell)) { read_cell(&cell_list[i], &cell); if(cell.timeslot_offset == 0xffff) { continue; @@ -335,7 +335,7 @@ delete_req_input(const uint8_t *body, uint16_t body_len, if(num_cells > 0 && cell_list_len > 0) { /* ensure before delete */ - for(i = 0, removed_link = 0; i < (cell_list_len / sizeof(cell)); i++) { + for(i = 0, removed_link = 0; i < cell_list_len; i += sizeof(cell)) { read_cell(&cell_list[i], &cell); if(tsch_schedule_get_link_by_timeslot(slotframe, cell.timeslot_offset) != NULL) { From c8432009e9c34a21e030a516581b22b795f97e64 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 3 Aug 2018 19:08:56 +0100 Subject: [PATCH 197/485] Move variable definition to start of function --- examples/mqtt-client/mqtt-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/mqtt-client/mqtt-client.c b/examples/mqtt-client/mqtt-client.c index 4e128ae37..be3c97cdb 100644 --- a/examples/mqtt-client/mqtt-client.c +++ b/examples/mqtt-client/mqtt-client.c @@ -493,6 +493,7 @@ publish(void) int len; int remaining = APP_BUFFER_SIZE; int i; + char def_rt_str[64]; seq_nr_value++; @@ -519,7 +520,6 @@ publish(void) buf_ptr += len; /* Put our Default route's string representation in a buffer */ - char def_rt_str[64]; memset(def_rt_str, 0, sizeof(def_rt_str)); ipaddr_sprintf(def_rt_str, sizeof(def_rt_str), uip_ds6_defrt_choose()); From 6f65063306fab6d5eab284a8cf9f4923e30e0fd5 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 3 Aug 2018 23:05:39 +0100 Subject: [PATCH 198/485] Bootstrap the vagrant image with a single apt install --- tools/vagrant/bootstrap.sh | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/tools/vagrant/bootstrap.sh b/tools/vagrant/bootstrap.sh index c6cbd3d3c..2f70d34fd 100755 --- a/tools/vagrant/bootstrap.sh +++ b/tools/vagrant/bootstrap.sh @@ -1,15 +1,14 @@ #!/usr/bin/env bash -# i386 binary support on x64 system +# Install i386 binary support on x64 system and required tools sudo dpkg --add-architecture i386 sudo apt update sudo apt install -y --no-install-recommends \ - libc6:i386 libstdc++6:i386 libncurses5:i386 libz1:i386 + libc6:i386 libstdc++6:i386 libncurses5:i386 libz1:i386 \ + build-essential doxygen git wget unzip python-serial rlwrap npm \ + default-jdk ant srecord python-pip iputils-tracepath uncrustify \ + python-magic -# Tools -sudo apt-get install -y --no-install-recommends \ - 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 @@ -61,8 +60,6 @@ source ${HOME}/.bashrc echo "#!/bin/bash\nant -Dbasedir=${COOJA} -f ${COOJA}/build.xml run" > ${HOME}/cooja && chmod +x ${HOME}/cooja # Install coap-cli -sudo apt-get install -y npm -sudo apt-get clean sudo npm install coap-cli -g sudo ln -s /usr/bin/nodejs /usr/bin/node From f73fc7d0e02facbd4497aeff334cef72bc686cc5 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 3 Aug 2018 23:23:14 +0100 Subject: [PATCH 199/485] Install linux kernel image extras --- tools/vagrant/bootstrap.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/vagrant/bootstrap.sh b/tools/vagrant/bootstrap.sh index 2f70d34fd..1a7c2a5a6 100755 --- a/tools/vagrant/bootstrap.sh +++ b/tools/vagrant/bootstrap.sh @@ -7,7 +7,7 @@ sudo apt install -y --no-install-recommends \ libc6:i386 libstdc++6:i386 libncurses5:i386 libz1:i386 \ build-essential doxygen git wget unzip python-serial rlwrap npm \ default-jdk ant srecord python-pip iputils-tracepath uncrustify \ - python-magic + python-magic linux-image-extra-virtual sudo apt-get clean sudo python2 -m pip install intelhex From ffcd04d413062e2f17a6e7b1c99ec756860577fe Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 4 Aug 2018 14:43:22 +0100 Subject: [PATCH 200/485] Add motelist as a submodule This commit adds contiki-ng/motelist as a submodule under tools/motelist. The tool aims to automatically detect and output a list of sensor/IoT devices connected to a computer. It has been developed and tested in OSX and Ubuntu. There is currently no support for Cygwin, nor does the tool's author plan to provide such in the future :). The tool is expected to work with Python 2.7 and 3+. It has been tested and successfully detects CC26xx Launchpads and Zolertia RE-Mote and Firefly devices. Motelist's ultimate goal is to replace vendor-specific motelist-foo tools under the respective tools/ subdirectories, with a single tool that can detect as many devices as possible and that provides its output in a homogenous and script-friendly format. This pull does not remove anything until the new motelist has been tested and found useful. Unless stated otherwise within individual files, motelist sources are distributed under the terms of the 3-clause BSD license. Some parts of motelist.py (especially the Linux backend), are based on ideas and original work done by Janis Judvaitis and Atis Elsts. ## Usage ```bash $ python motelist.py -h usage: motelist.py [-c] [-o] [-b] [-h] [-v] Automatically detect and print out a list of motes connected to this computer optional arguments: -c, --csv Print list in CSV format -o, --omit-header Omit header row -b, --brief Only print serial port paths -h, --help Show this message and exit -v, --version Prints software version ``` Standard output: ```bash $ python motelist.py Port Serial VID PID Product Vendor ------------ ------------------ ------ ------ ----------------------------------- ----------------- /dev/ttyACM0 L200015Z 0x0451 0xBEF3 XDS110 (02.02.05.01) with CMSIS-DAP Texas Instruments /dev/ttyACM1 L200015Z 0x0451 0xBEF3 XDS110 (02.02.05.01) with CMSIS-DAP Texas Instruments /dev/ttyUSB0 ZOL-B001-A20000777 0x10C4 0xEA60 Zolertia Firefly platform Silicon Labs ``` You can get the output in CSV format: ```bash $ python motelist.py -c Port;Serial;VID;PID;Product;Vendor /dev/ttyUSB0;ZOL-B001-A20000777;0x10C4;0xEA60;Zolertia Firefly platform;Silicon Labs /dev/ttyACM0;L200015Z;0x0451;0xBEF3;XDS110 (02.02.05.01) with CMSIS-DAP;Texas Instruments /dev/ttyACM1;L200015Z;0x0451;0xBEF3;XDS110 (02.02.05.01) with CMSIS-DAP;Texas Instruments ``` You can ommit the header row with `-o`. You can also ommit all columns except the first one with `-b`. You can also combine the `-cob` options: ```bash $ python motelist.py -ob /dev/ttyUSB0 /dev/ttyACM0 /dev/ttyACM1 ``` --- .gitmodules | 3 +++ tools/motelist | 1 + 2 files changed, 4 insertions(+) create mode 160000 tools/motelist diff --git a/.gitmodules b/.gitmodules index 36eb3cd95..80dd37e17 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,3 +19,6 @@ [submodule "tests/18-coap-lwm2m/example-lwm2m-standalone"] path = tests/18-coap-lwm2m/example-lwm2m-standalone url = https://github.com/contiki-ng/example-lwm2m-standalone.git +[submodule "tools/motelist"] + path = tools/motelist + url = https://github.com/contiki-ng/motelist diff --git a/tools/motelist b/tools/motelist new file mode 160000 index 000000000..2f089ac92 --- /dev/null +++ b/tools/motelist @@ -0,0 +1 @@ +Subproject commit 2f089ac9277521b32371e68391e53d0bd0017288 From 1a65e0ea759a3bdf29142affb6a4933c57914dcc Mon Sep 17 00:00:00 2001 From: Rehan MALAK Date: Mon, 13 Aug 2018 13:22:00 +0200 Subject: [PATCH 201/485] fix some bugs in the RPL border tests * 08-border-router-cooja-frag.sh was using 01-border-router-cooja.csc so if the test failed, the summary was wrongly indicating a failed 01-board-router-cooja test * same for 09-native-border-router-cooja-frag.sh which has now it's own cooja configuration * 05-native-ping was using 01-native-ping * homogenizes the mode : all scripts are 644 now --- tests/17-tun-rpl-br/01-border-router-cooja.sh | 2 +- .../02-border-router-cooja-tsch.sh | 2 +- tests/17-tun-rpl-br/03-border-router-sky.sh | 2 +- .../04-border-router-traceroute.sh | 2 +- tests/17-tun-rpl-br/05-native-ping.sh | 2 +- tests/17-tun-rpl-br/06-native-coap.sh | 2 +- .../07-native-border-router-cooja.sh | 2 +- .../08-border-router-cooja-frag.sh | 2 +- .../09-native-border-router-cooja-frag.csc | 254 ++++++++++++++++++ .../09-native-border-router-cooja-frag.sh | 2 +- .../test-native-border-router.sh | 0 11 files changed, 263 insertions(+), 9 deletions(-) mode change 100644 => 100755 tests/17-tun-rpl-br/08-border-router-cooja-frag.sh create mode 100644 tests/17-tun-rpl-br/09-native-border-router-cooja-frag.csc mode change 100644 => 100755 tests/17-tun-rpl-br/test-native-border-router.sh diff --git a/tests/17-tun-rpl-br/01-border-router-cooja.sh b/tests/17-tun-rpl-br/01-border-router-cooja.sh index 11b2edc8a..a91e5905b 100755 --- a/tests/17-tun-rpl-br/01-border-router-cooja.sh +++ b/tests/17-tun-rpl-br/01-border-router-cooja.sh @@ -4,6 +4,6 @@ CONTIKI=$1 # Simulation file -BASENAME=01-border-router-cooja +BASENAME=$(basename $0 .sh) bash test-border-router.sh $CONTIKI $BASENAME fd00::204:4:4:4 60 diff --git a/tests/17-tun-rpl-br/02-border-router-cooja-tsch.sh b/tests/17-tun-rpl-br/02-border-router-cooja-tsch.sh index c7e61c8a7..760432c10 100755 --- a/tests/17-tun-rpl-br/02-border-router-cooja-tsch.sh +++ b/tests/17-tun-rpl-br/02-border-router-cooja-tsch.sh @@ -4,7 +4,7 @@ CONTIKI=$1 # Simulation file -BASENAME=02-border-router-cooja-tsch +BASENAME=$(basename $0 .sh) # Add a little extra initial time to account for TSCH association time bash test-border-router.sh $CONTIKI $BASENAME fd00::204:4:4:4 120 diff --git a/tests/17-tun-rpl-br/03-border-router-sky.sh b/tests/17-tun-rpl-br/03-border-router-sky.sh index 7ffa4265e..9bdd86111 100755 --- a/tests/17-tun-rpl-br/03-border-router-sky.sh +++ b/tests/17-tun-rpl-br/03-border-router-sky.sh @@ -4,6 +4,6 @@ CONTIKI=$1 # Simulation file -BASENAME=03-border-router-sky +BASENAME=$(basename $0 .sh) bash test-border-router.sh $CONTIKI $BASENAME fd00::0212:7404:0004:0404 60 diff --git a/tests/17-tun-rpl-br/04-border-router-traceroute.sh b/tests/17-tun-rpl-br/04-border-router-traceroute.sh index 4effb9bd3..611140248 100755 --- a/tests/17-tun-rpl-br/04-border-router-traceroute.sh +++ b/tests/17-tun-rpl-br/04-border-router-traceroute.sh @@ -5,7 +5,7 @@ source ../utils.sh CONTIKI=$1 # Simulation file -BASENAME=04-border-router-traceroute +BASENAME=$(basename $0 .sh) # Destination IPv6 IPADDR=fd00::204:4:4:4 diff --git a/tests/17-tun-rpl-br/05-native-ping.sh b/tests/17-tun-rpl-br/05-native-ping.sh index ea416aac4..6bb53ccd8 100755 --- a/tests/17-tun-rpl-br/05-native-ping.sh +++ b/tests/17-tun-rpl-br/05-native-ping.sh @@ -4,7 +4,7 @@ source ../utils.sh # Contiki directory CONTIKI=$1 # Test basename -BASENAME=01-native-ping +BASENAME=$(basename $0 .sh) IPADDR=fd00::302:304:506:708 diff --git a/tests/17-tun-rpl-br/06-native-coap.sh b/tests/17-tun-rpl-br/06-native-coap.sh index 216d104f4..4c1925699 100755 --- a/tests/17-tun-rpl-br/06-native-coap.sh +++ b/tests/17-tun-rpl-br/06-native-coap.sh @@ -4,7 +4,7 @@ source ../utils.sh # Contiki directory CONTIKI=$1 # Test basename -BASENAME=06-native-coap +BASENAME=$(basename $0 .sh) IPADDR=fd00::302:304:506:708 diff --git a/tests/17-tun-rpl-br/07-native-border-router-cooja.sh b/tests/17-tun-rpl-br/07-native-border-router-cooja.sh index 8f91bd726..c239e4e98 100755 --- a/tests/17-tun-rpl-br/07-native-border-router-cooja.sh +++ b/tests/17-tun-rpl-br/07-native-border-router-cooja.sh @@ -4,6 +4,6 @@ CONTIKI=$1 # Simulation file -BASENAME=07-native-border-router-cooja +BASENAME=$(basename $0 .sh) bash test-native-border-router.sh $CONTIKI $BASENAME fd00::204:4:4:4 60 diff --git a/tests/17-tun-rpl-br/08-border-router-cooja-frag.sh b/tests/17-tun-rpl-br/08-border-router-cooja-frag.sh old mode 100644 new mode 100755 index 0e80018b4..0d308acb6 --- a/tests/17-tun-rpl-br/08-border-router-cooja-frag.sh +++ b/tests/17-tun-rpl-br/08-border-router-cooja-frag.sh @@ -4,6 +4,6 @@ CONTIKI=$1 # Simulation file -BASENAME=01-border-router-cooja +BASENAME=$(basename $0 .sh) bash test-border-router.sh $CONTIKI $BASENAME fd00::204:4:4:4 60 1200 4 diff --git a/tests/17-tun-rpl-br/09-native-border-router-cooja-frag.csc b/tests/17-tun-rpl-br/09-native-border-router-cooja-frag.csc new file mode 100644 index 000000000..7140d183c --- /dev/null +++ b/tests/17-tun-rpl-br/09-native-border-router-cooja-frag.csc @@ -0,0 +1,254 @@ + + + [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 + mtype295 + Cooja Mote Type #1 + [CONTIKI_DIR]/examples/slip-radio/slip-radio.c + make TARGET=cooja clean +make -j slip-radio.cooja TARGET=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.contikimote.ContikiMoteType + mtype686 + Cooja Mote Type #2 + [CONTIKI_DIR]/examples/hello-world/hello-world.c + make TARGET=cooja clean +make -j hello-world.cooja TARGET=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 + 54.36775767371176 + 24.409055040864118 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 1 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype295 + + + + org.contikios.cooja.interfaces.Position + 83.54989222799365 + 52.63050856506214 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 2 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype686 + + + + org.contikios.cooja.interfaces.Position + 108.91767775240822 + 78.59778809170032 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 3 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype686 + + + + org.contikios.cooja.interfaces.Position + 139.91021061864723 + 98.34190023350419 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 4 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype686 + + + + org.contikios.cooja.plugins.SimControl + 280 + 1 + 160 + 400 + 0 + + + org.contikios.cooja.plugins.Visualizer + + true + org.contikios.cooja.plugins.skins.UDGMVisualizerSkin + org.contikios.cooja.plugins.skins.IDVisualizerSkin + 1.9798610460263038 0.0 0.0 1.9798610460263038 -61.112037797038525 -1.2848438586294648 + + 400 + 4 + 400 + 1 + 1 + + + org.contikios.cooja.plugins.LogListener + + ID:4 + + + + 1404 + 2 + 240 + 400 + 160 + + + org.contikios.cooja.plugins.TimeLine + + 0 + 1 + 2 + 3 + + + + 500.0 + + 1804 + 6 + 166 + 0 + 753 + + + org.contikios.cooja.plugins.Notes + + Enter notes here + true + + 1124 + 5 + 160 + 680 + 0 + + + org.contikios.cooja.serialsocket.SerialSocketServer + 0 + + 60001 + true + + 362 + 3 + 116 + 13 + 414 + + + org.contikios.cooja.plugins.ScriptRunner + + + true + + 600 + 0 + 700 + 1037 + 40 + + diff --git a/tests/17-tun-rpl-br/09-native-border-router-cooja-frag.sh b/tests/17-tun-rpl-br/09-native-border-router-cooja-frag.sh index 24baa1556..5b893ffc7 100755 --- a/tests/17-tun-rpl-br/09-native-border-router-cooja-frag.sh +++ b/tests/17-tun-rpl-br/09-native-border-router-cooja-frag.sh @@ -4,6 +4,6 @@ CONTIKI=$1 # Simulation file -BASENAME=07-native-border-router-cooja +BASENAME=$(basename $0 .sh) bash test-native-border-router.sh $CONTIKI $BASENAME fd00::204:4:4:4 60 1200 4 diff --git a/tests/17-tun-rpl-br/test-native-border-router.sh b/tests/17-tun-rpl-br/test-native-border-router.sh old mode 100644 new mode 100755 From 3cb82e7d6c521fda0a9e4a2e01724f3cce139f97 Mon Sep 17 00:00:00 2001 From: tdesmet Date: Tue, 14 Aug 2018 21:23:11 +0200 Subject: [PATCH 202/485] Add option to validate dio before init dag --- os/net/routing/rpl-lite/rpl-conf.h | 7 +++++++ os/net/routing/rpl-lite/rpl-dag.c | 13 +++++++++++++ 2 files changed, 20 insertions(+) diff --git a/os/net/routing/rpl-lite/rpl-conf.h b/os/net/routing/rpl-lite/rpl-conf.h index 8d2f4b7b9..9b8a12adb 100644 --- a/os/net/routing/rpl-lite/rpl-conf.h +++ b/os/net/routing/rpl-lite/rpl-conf.h @@ -191,6 +191,13 @@ #define RPL_DEFAULT_LEAF_ONLY 0 #endif +/* + * Function used to validate dio before using it to init dag + */ +#ifdef RPL_CONF_VALIDATE_DIO_FUNC +#define RPL_VALIDATE_DIO_FUNC RPL_CONF_VALIDATE_DIO_FUNC +#endif + /******************************************************************************/ /********************************** Timing ************************************/ /******************************************************************************/ diff --git a/os/net/routing/rpl-lite/rpl-dag.c b/os/net/routing/rpl-lite/rpl-dag.c index 68d9e7aaa..09caa9625 100644 --- a/os/net/routing/rpl-lite/rpl-dag.c +++ b/os/net/routing/rpl-lite/rpl-dag.c @@ -61,6 +61,12 @@ static int init_dag_from_dio(rpl_dio_t *dio); /* Allocate instance table. */ rpl_instance_t curr_instance; +/*---------------------------------------------------------------------------*/ + +#ifdef RPL_VALIDATE_DIO_FUNC +int RPL_VALIDATE_DIO_FUNC(rpl_dio_t *dio); +#endif /* RPL_PROBING_SELECT_FUNC */ + /*---------------------------------------------------------------------------*/ const char * rpl_dag_state_to_str(enum rpl_dag_state state) @@ -542,6 +548,13 @@ init_dag_from_dio(rpl_dio_t *dio) static int process_dio_init_dag(uip_ipaddr_t *from, rpl_dio_t *dio) { +#ifdef RPL_VALIDATE_DIO_FUNC + if(!RPL_VALIDATE_DIO_FUNC(dio)) { + LOG_WARN("DIO validation failed\n"); + return 0; + } +#endif + /* Check MOP */ if(dio->mop != RPL_MOP_NO_DOWNWARD_ROUTES && dio->mop != RPL_MOP_NON_STORING) { LOG_WARN("ignoring DIO with an unsupported MOP: %d\n", dio->mop); From 8930ca7b2df91ae04214597621203362f8866ff1 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Wed, 22 Aug 2018 23:39:41 +0100 Subject: [PATCH 203/485] Update cc2538-bsl to latest This commit updates cc2538-bsl to its latest version. This latest version improves CC2640R2 detection and also adds support for detection of more chip packages. --- tools/cc2538-bsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cc2538-bsl b/tools/cc2538-bsl index edb3c8c73..59fd804b8 160000 --- a/tools/cc2538-bsl +++ b/tools/cc2538-bsl @@ -1 +1 @@ -Subproject commit edb3c8c73c4688ebd336b278450db216512a769b +Subproject commit 59fd804b80aec868d74ce37c6195086b817981ea From 02dd484ff245da74db26ed03c78b0338d5211d4c Mon Sep 17 00:00:00 2001 From: Sam Kumar Date: Sat, 25 Aug 2018 22:15:45 -0700 Subject: [PATCH 204/485] Fix bug in CoAP retransmission policy --- os/net/app-layer/coap/coap-transactions.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/os/net/app-layer/coap/coap-transactions.c b/os/net/app-layer/coap/coap-transactions.c index 7e34d22e4..a62e8d21f 100644 --- a/os/net/app-layer/coap/coap-transactions.c +++ b/os/net/app-layer/coap/coap-transactions.c @@ -98,12 +98,11 @@ coap_send_transaction(coap_transaction_t *t) { LOG_DBG("Sending transaction %u\n", t->mid); - coap_sendto(&t->endpoint, t->message, t->message_len); - if(COAP_TYPE_CON == ((COAP_HEADER_TYPE_MASK & t->message[0]) >> COAP_HEADER_TYPE_POSITION)) { - if(t->retrans_counter < COAP_MAX_RETRANSMIT) { + if(t->retrans_counter <= COAP_MAX_RETRANSMIT) { /* not timed out yet */ + coap_sendto(&t->endpoint, t->message, t->message_len); LOG_DBG("Keeping transaction %u\n", t->mid); if(t->retrans_counter == 0) { @@ -138,6 +137,7 @@ coap_send_transaction(coap_transaction_t *t) } } } else { + coap_sendto(&t->endpoint, t->message, t->message_len); coap_clear_transaction(t); } } From a73822176ad0a8ce321d0f6460a07721cf6a8d83 Mon Sep 17 00:00:00 2001 From: Nicolas Tsiftes Date: Mon, 20 Aug 2018 14:07:14 +0200 Subject: [PATCH 205/485] Check element size when parsing tokens. --- os/storage/antelope/aql-lexer.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/os/storage/antelope/aql-lexer.c b/os/storage/antelope/aql-lexer.c index 4bdefecf2..0510385b5 100644 --- a/os/storage/antelope/aql-lexer.c +++ b/os/storage/antelope/aql-lexer.c @@ -207,6 +207,10 @@ next_string(lexer_t *lexer, const char *s) *lexer->token = STRING_VALUE; lexer->input = end + 1; /* Skip the closing delimiter. */ + if(length > DB_MAX_ELEMENT_SIZE - 1) { + length = DB_MAX_ELEMENT_SIZE - 1; + } + memcpy(lexer->value, s, length); (*lexer->value)[length] = '\0'; @@ -236,6 +240,10 @@ next_token(lexer_t *lexer, const char *s) *lexer->token = IDENTIFIER; + if(length > DB_MAX_ELEMENT_SIZE - 1) { + length = DB_MAX_ELEMENT_SIZE - 1; + } + memcpy(lexer->value, s, length); (*lexer->value)[length] = '\0'; From f9bc65eab2b416152f06590f8b620904bfd1aae2 Mon Sep 17 00:00:00 2001 From: Nicolas Tsiftes Date: Mon, 20 Aug 2018 15:00:10 +0200 Subject: [PATCH 206/485] Enhanced LVM error checking. --- os/storage/antelope/aql-parser.c | 22 +++-- os/storage/antelope/lvm.c | 151 ++++++++++++++++++++----------- os/storage/antelope/lvm.h | 30 +++--- os/storage/antelope/relation.c | 4 +- 4 files changed, 132 insertions(+), 75 deletions(-) diff --git a/os/storage/antelope/aql-parser.c b/os/storage/antelope/aql-parser.c index 503833b0a..f65a8a6ce 100644 --- a/os/storage/antelope/aql-parser.c +++ b/os/storage/antelope/aql-parser.c @@ -269,8 +269,10 @@ PARSER(operand) NEXT; switch(TOKEN) { case IDENTIFIER: - lvm_register_variable(VALUE, LVM_LONG); - lvm_set_variable(&p, VALUE); + if(LVM_ERROR(lvm_register_variable(VALUE, LVM_LONG)) || + LVM_ERROR(lvm_set_variable(&p, VALUE))) { + RETURN(SYNTAX_ERROR); + } AQL_ADD_PROCESSING_ATTRIBUTE(adt, VALUE); break; case STRING_VALUE: @@ -278,7 +280,9 @@ PARSER(operand) case FLOAT_VALUE: break; case INTEGER_VALUE: - lvm_set_long(&p, *(long *)lexer->value); + if(LVM_ERROR(lvm_set_long(&p, *(long *)lexer->value))) { + RETURN(SYNTAX_ERROR); + } break; default: RETURN(SYNTAX_ERROR); @@ -340,7 +344,9 @@ PARSER(expr) default: RETURN(SYNTAX_ERROR); } - lvm_set_op(&p, op); + if(LVM_ERROR(lvm_set_op(&p, op))) { + RETURN(SYNTAX_ERROR); + } lvm_set_end(&p, saved_end); } @@ -389,7 +395,9 @@ PARSER(comparison) RETURN(SYNTAX_ERROR); } - lvm_set_relation(&p, rel); + if(LVM_ERROR(lvm_set_relation(&p, rel))) { + RETURN(SYNTAX_ERROR); + } lvm_set_end(&p, saved_end); if(!PARSE(expr)) { @@ -422,7 +430,9 @@ PARSER(where) connective = TOKEN == AND ? LVM_AND : LVM_OR; saved_end = lvm_shift_for_operator(&p, saved_end); - lvm_set_relation(&p, connective); + if(LVM_ERROR(lvm_set_relation(&p, connective))) { + RETURN(SYNTAX_ERROR); + } lvm_set_end(&p, saved_end); NEXT; diff --git a/os/storage/antelope/lvm.c b/os/storage/antelope/lvm.c index 731da1622..7abed8d27 100644 --- a/os/storage/antelope/lvm.c +++ b/os/storage/antelope/lvm.c @@ -82,10 +82,10 @@ typedef struct derivation derivation_t; /* Registered variables for a LVM expression. Their values may be changed between executions of the expression. */ -static variable_t variables[LVM_MAX_VARIABLE_ID - 1]; +static variable_t variables[LVM_MAX_VARIABLE_ID]; /* Range derivations of variables that are used for index searches. */ -static derivation_t derivations[LVM_MAX_VARIABLE_ID - 1]; +static derivation_t derivations[LVM_MAX_VARIABLE_ID]; #if DEBUG static void @@ -187,7 +187,7 @@ eval_expr(lvm_instance_t *p, operator_t op, operand_t *result) get_operand(p, &operand[i]); break; default: - return SEMANTIC_ERROR; + return LVM_SEMANTIC_ERROR; } value[i] = operand_to_long(&operand[i]); } @@ -204,18 +204,18 @@ eval_expr(lvm_instance_t *p, operator_t op, operand_t *result) break; case LVM_DIV: if(value[1] == 0) { - return MATH_ERROR; + return LVM_MATH_ERROR; } result_value = value[0] / value[1]; break; default: - return EXECUTION_ERROR; + return LVM_EXECUTION_ERROR; } result->type = LVM_LONG; result->value.l = result_value; - return TRUE; + return LVM_TRUE; } static int @@ -236,7 +236,7 @@ eval_logic(lvm_instance_t *p, operator_t *op) for(i = 0; i < arguments; i++) { type = get_type(p); if(type != LVM_CMP_OP) { - return SEMANTIC_ERROR; + return LVM_SEMANTIC_ERROR; } operator = get_operator(p); logic_result[i] = eval_logic(p, operator); @@ -248,9 +248,9 @@ eval_logic(lvm_instance_t *p, operator_t *op) if(*op == LVM_NOT) { return !logic_result[0]; } else if(*op == LVM_AND) { - return logic_result[0] == TRUE && logic_result[1] == TRUE; + return logic_result[0] == LVM_TRUE && logic_result[1] == LVM_TRUE; } else { - return logic_result[0] == TRUE || logic_result[1] == TRUE; + return logic_result[0] == LVM_TRUE || logic_result[1] == LVM_TRUE; } } @@ -268,7 +268,7 @@ eval_logic(lvm_instance_t *p, operator_t *op) get_operand(p, &operand); break; default: - return SEMANTIC_ERROR; + return LVM_SEMANTIC_ERROR; } result[i] = operand_to_long(&operand); } @@ -294,7 +294,7 @@ eval_logic(lvm_instance_t *p, operator_t *op) break; } - return EXECUTION_ERROR; + return LVM_EXECUTION_ERROR; } void @@ -334,7 +334,8 @@ lvm_shift_for_operator(lvm_instance_t *p, lvm_ip_t end) old_end = p->end; - if(p->end + sizeof(operator_t) > p->size || end >= old_end) { + if(p->end + sizeof(operator_t) + sizeof(node_type_t) > p->size || + end >= old_end) { p->error = __LINE__; return 0; } @@ -369,13 +370,6 @@ lvm_set_end(lvm_instance_t *p, lvm_ip_t end) return old_end; } -void -lvm_set_type(lvm_instance_t *p, node_type_t type) -{ - *(node_type_t *)(p->code + p->end) = type; - p->end += sizeof(type); -} - lvm_status_t lvm_execute(lvm_instance_t *p) { @@ -384,14 +378,14 @@ lvm_execute(lvm_instance_t *p) lvm_status_t status; p->ip = 0; - status = EXECUTION_ERROR; + status = LVM_EXECUTION_ERROR; type = get_type(p); switch(type) { case LVM_CMP_OP: operator = get_operator(p); status = eval_logic(p, operator); if(!LVM_ERROR(status)) { - PRINTF("The statement is %s\n", status == TRUE ? "true" : "false"); + PRINTF("The statement is %s\n", status == LVM_TRUE ? "true" : "false"); } else { PRINTF("Execution error: %d\n", (int)status); } @@ -403,31 +397,80 @@ lvm_execute(lvm_instance_t *p) return status; } -void +lvm_status_t +lvm_set_type(lvm_instance_t *p, node_type_t type) +{ + if(p->end + sizeof(node_type_t) >= DB_VM_BYTECODE_SIZE) { + PRINTF("Error: overflow in lvm_set_type\n"); + return LVM_STACK_OVERFLOW; + } + + *(node_type_t *)(p->code + p->end) = type; + p->end += sizeof(type); + return LVM_TRUE; +} + +lvm_status_t lvm_set_op(lvm_instance_t *p, operator_t op) { - lvm_set_type(p, LVM_ARITH_OP); + lvm_status_t status; + + status = lvm_set_type(p, LVM_ARITH_OP); + if(status != LVM_TRUE) { + return status; + } + + if(p->end + sizeof(op) >= DB_VM_BYTECODE_SIZE) { + PRINTF("Error: overflow in lvm_set_op\n"); + return LVM_STACK_OVERFLOW; + } + memcpy(&p->code[p->end], &op, sizeof(op)); p->end += sizeof(op); + return LVM_TRUE; } -void +lvm_status_t lvm_set_relation(lvm_instance_t *p, operator_t op) { - lvm_set_type(p, LVM_CMP_OP); + lvm_status_t status; + + status = lvm_set_type(p, LVM_CMP_OP); + if(status != LVM_TRUE) { + return status; + } + + if(p->end + sizeof(op) >= DB_VM_BYTECODE_SIZE) { + PRINTF("Error: overflow in lvm_set_relation\n"); + return LVM_STACK_OVERFLOW; + } + memcpy(&p->code[p->end], &op, sizeof(op)); p->end += sizeof(op); + return LVM_TRUE; } -void +lvm_status_t lvm_set_operand(lvm_instance_t *p, operand_t *op) { - lvm_set_type(p, LVM_OPERAND); + lvm_status_t status; + + status = lvm_set_type(p, LVM_OPERAND); + if(status != LVM_TRUE) { + return status; + } + + if(p->end + sizeof(*op) >= DB_VM_BYTECODE_SIZE) { + PRINTF("Error: overflow in lvm_set_operand\n"); + return LVM_STACK_OVERFLOW; + } + memcpy(&p->code[p->end], op, sizeof(*op)); p->end += sizeof(*op); + return LVM_TRUE; } -void +lvm_status_t lvm_set_long(lvm_instance_t *p, long l) { operand_t op; @@ -435,7 +478,7 @@ lvm_set_long(lvm_instance_t *p, long l) op.type = LVM_LONG; op.value.l = l; - lvm_set_operand(p, &op); + return lvm_set_operand(p, &op); } lvm_status_t @@ -446,7 +489,7 @@ lvm_register_variable(char *name, operand_type_t type) id = lookup(name); if(id == LVM_MAX_VARIABLE_ID) { - return VARIABLE_LIMIT_REACHED; + return LVM_VARIABLE_LIMIT_REACHED; } var = &variables[id]; @@ -456,7 +499,7 @@ lvm_register_variable(char *name, operand_type_t type) var->type = type; } - return TRUE; + return LVM_TRUE; } lvm_status_t @@ -466,25 +509,28 @@ lvm_set_variable_value(char *name, operand_value_t value) id = lookup(name); if(id == LVM_MAX_VARIABLE_ID) { - return INVALID_IDENTIFIER; + return LVM_INVALID_IDENTIFIER; } + variables[id].value = value; - return TRUE; + return LVM_TRUE; } -void +lvm_status_t lvm_set_variable(lvm_instance_t *p, char *name) { operand_t op; variable_id_t id; id = lookup(name); - if(id < LVM_MAX_VARIABLE_ID) { - PRINTF("var id = %d\n", id); - op.type = LVM_VARIABLE; - op.value.id = id; - lvm_set_operand(p, &op); + if(id == LVM_MAX_VARIABLE_ID) { + return LVM_INVALID_IDENTIFIER; } + + PRINTF("var id = %d\n", id); + op.type = LVM_VARIABLE; + op.value.id = id; + return lvm_set_operand(p, &op); } void @@ -598,7 +644,7 @@ derive_relation(lvm_instance_t *p, derivation_t *local_derivations) derivation_t d2[LVM_MAX_VARIABLE_ID]; if(*operator != LVM_AND && *operator != LVM_OR) { - return DERIVATION_ERROR; + return LVM_DERIVATION_ERROR; } PRINTF("Attempting to infer ranges from a logical connective\n"); @@ -608,7 +654,7 @@ derive_relation(lvm_instance_t *p, derivation_t *local_derivations) if(LVM_ERROR(derive_relation(p, d1)) || LVM_ERROR(derive_relation(p, d2))) { - return DERIVATION_ERROR; + return LVM_DERIVATION_ERROR; } if(*operator == LVM_AND) { @@ -616,7 +662,7 @@ derive_relation(lvm_instance_t *p, derivation_t *local_derivations) } else if(*operator == LVM_OR) { create_union(local_derivations, d1, d2); } - return TRUE; + return LVM_TRUE; } for(i = 0; i < 2; i++) { @@ -626,18 +672,18 @@ derive_relation(lvm_instance_t *p, derivation_t *local_derivations) get_operand(p, &operand[i]); break; default: - return DERIVATION_ERROR; + return LVM_DERIVATION_ERROR; } } if(operand[0].type == LVM_VARIABLE && operand[1].type == LVM_VARIABLE) { - return DERIVATION_ERROR; + return LVM_DERIVATION_ERROR; } /* Determine which of the operands that is the variable. */ if(operand[0].type == LVM_VARIABLE) { if(operand[1].type == LVM_VARIABLE) { - return DERIVATION_ERROR; + return LVM_DERIVATION_ERROR; } variable_id = operand[0].value.id; value = &operand[1].value; @@ -647,7 +693,7 @@ derive_relation(lvm_instance_t *p, derivation_t *local_derivations) } if(variable_id >= LVM_MAX_VARIABLE_ID) { - return DERIVATION_ERROR; + return LVM_DERIVATION_ERROR; } PRINTF("variable id %d, value %ld\n", variable_id, *(long *)value); @@ -675,12 +721,12 @@ derive_relation(lvm_instance_t *p, derivation_t *local_derivations) derivation->max.l = value->l; break; default: - return DERIVATION_ERROR; + return LVM_DERIVATION_ERROR; } derivation->derived = 1; - return TRUE; + return LVM_TRUE; } lvm_status_t @@ -700,12 +746,12 @@ lvm_get_derived_range(lvm_instance_t *p, char *name, if(derivations[i].derived) { *min = derivations[i].min; *max = derivations[i].max; - return TRUE; + return LVM_TRUE; } - return DERIVATION_ERROR; + return LVM_DERIVATION_ERROR; } } - return INVALID_IDENTIFIER; + return LVM_INVALID_IDENTIFIER; } #if DEBUG @@ -755,7 +801,8 @@ print_operand(lvm_instance_t *p, lvm_ip_t index) switch(operand.type) { case LVM_VARIABLE: - if(operand.value.id >= LVM_MAX_VARIABLE_ID || variables[operand.value.id].name == NULL) { + if(operand.value.id >= LVM_MAX_VARIABLE_ID || + variables[operand.value.id].name == NULL) { PRINTF("var(id:%d):?? ", operand.value.id); } else { PRINTF("var(%s):%ld ", variables[operand.value.id].name, diff --git a/os/storage/antelope/lvm.h b/os/storage/antelope/lvm.h index 0969501d9..6b56d6bd1 100644 --- a/os/storage/antelope/lvm.h +++ b/os/storage/antelope/lvm.h @@ -45,16 +45,16 @@ #include "db-options.h" enum lvm_status { - FALSE = 0, - TRUE = 1, - INVALID_IDENTIFIER = 2, - SEMANTIC_ERROR = 3, - MATH_ERROR = 4, - STACK_OVERFLOW = 5, - TYPE_ERROR = 6, - VARIABLE_LIMIT_REACHED = 7, - EXECUTION_ERROR = 8, - DERIVATION_ERROR = 9 + LVM_FALSE = 0, + LVM_TRUE = 1, + LVM_INVALID_IDENTIFIER = 2, + LVM_SEMANTIC_ERROR = 3, + LVM_MATH_ERROR = 4, + LVM_STACK_OVERFLOW = 5, + LVM_TYPE_ERROR = 6, + LVM_VARIABLE_LIMIT_REACHED = 7, + LVM_EXECUTION_ERROR = 8, + LVM_DERIVATION_ERROR = 9 }; typedef enum lvm_status lvm_status_t; @@ -135,10 +135,10 @@ lvm_ip_t lvm_jump_to_operand(lvm_instance_t *p); lvm_ip_t lvm_shift_for_operator(lvm_instance_t *p, lvm_ip_t end); lvm_ip_t lvm_get_end(lvm_instance_t *p); lvm_ip_t lvm_set_end(lvm_instance_t *p, lvm_ip_t end); -void lvm_set_op(lvm_instance_t *p, operator_t op); -void lvm_set_relation(lvm_instance_t *p, operator_t op); -void lvm_set_operand(lvm_instance_t *p, operand_t *op); -void lvm_set_long(lvm_instance_t *p, long l); -void lvm_set_variable(lvm_instance_t *p, char *name); +lvm_status_t lvm_set_op(lvm_instance_t *p, operator_t op); +lvm_status_t lvm_set_relation(lvm_instance_t *p, operator_t op); +lvm_status_t lvm_set_operand(lvm_instance_t *p, operand_t *op); +lvm_status_t lvm_set_long(lvm_instance_t *p, long l); +lvm_status_t lvm_set_variable(lvm_instance_t *p, char *name); #endif /* LVM_H */ diff --git a/os/storage/antelope/relation.c b/os/storage/antelope/relation.c index c8757bf08..0e939a068 100644 --- a/os/storage/antelope/relation.c +++ b/os/storage/antelope/relation.c @@ -813,9 +813,9 @@ relation_process_select(void *handle_ptr) } } - wanted_result = TRUE; + wanted_result = LVM_TRUE; if(AQL_GET_FLAGS(adt) & AQL_FLAG_INVERSE_LOGIC) { - wanted_result = FALSE; + wanted_result = LVM_FALSE; } /* Check whether the given predicate is true for this tuple. */ From 196accb9b79d39029a9ee07d1191eedf9d588127 Mon Sep 17 00:00:00 2001 From: Nicolas Tsiftes Date: Mon, 20 Aug 2018 15:21:36 +0200 Subject: [PATCH 207/485] Check if too many relations are inserted. --- os/storage/antelope/aql-adt.c | 15 +++++++++++++++ os/storage/antelope/aql.h | 7 ++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/os/storage/antelope/aql-adt.c b/os/storage/antelope/aql-adt.c index d78f3f3c5..e07bffd7a 100644 --- a/os/storage/antelope/aql-adt.c +++ b/os/storage/antelope/aql-adt.c @@ -90,6 +90,21 @@ aql_clear(aql_adt_t *adt) memset(adt->aggregators, 0, sizeof(adt->aggregators)); } +db_result_t +aql_add_relation(aql_adt_t *adt, const char *name) +{ + if(adt->relation_count >= AQL_RELATION_LIMIT) { + return DB_LIMIT_ERROR; + } + + strncpy(adt->relations[adt->relation_count], name, + sizeof(adt->relations[0]) - 1); + adt->relations[adt->relation_count][sizeof(adt->relations[0]) - 1] = '\0'; + adt->relation_count++; + + return DB_OK; +} + db_result_t aql_add_attribute(aql_adt_t *adt, char *name, domain_t domain, unsigned element_size, int processed_only) diff --git a/os/storage/antelope/aql.h b/os/storage/antelope/aql.h index ab29f7e5d..4b898c4ac 100644 --- a/os/storage/antelope/aql.h +++ b/os/storage/antelope/aql.h @@ -188,10 +188,10 @@ typedef struct aql_adt aql_adt_t; #define AQL_SET_FLAG(adt, flag) (((adt)->flags) |= (flag)) #define AQL_GET_FLAGS(adt) ((adt)->flags) -#define AQL_ADD_RELATION(adt, rel) \ - strcpy((adt)->relations[(adt)->relation_count++], (rel)) #define AQL_RELATION_COUNT(adt) ((adt)->relation_count) -#define AQL_ADD_ATTRIBUTE(adt, attr, dom, size) \ +#define AQL_ADD_RELATION(adt, name) \ + aql_add_relation(adt, name) +#define AQL_ADD_ATTRIBUTE(adt, attr, dom, size) \ aql_add_attribute(adt, attr, dom, size, 0) #define AQL_ADD_PROCESSING_ATTRIBUTE(adt, attr) \ aql_add_attribute((adt), (attr), DOMAIN_UNSPECIFIED, 0, 1) @@ -211,6 +211,7 @@ void lexer_rewind(lexer_t *); void aql_clear(aql_adt_t *adt); aql_status_t aql_parse(aql_adt_t *adt, char *query_string); +db_result_t aql_add_relation(aql_adt_t *adt, const char *name); db_result_t aql_add_attribute(aql_adt_t *adt, char *name, domain_t domain, unsigned element_size, int processed_only); From 7860ca5da037c1562793154a70a91a47cbe573de Mon Sep 17 00:00:00 2001 From: Nicolas Tsiftes Date: Mon, 20 Aug 2018 15:43:27 +0200 Subject: [PATCH 208/485] Set a larger default bytecode size since the example on the Contiki-NG wiki requires this. --- os/storage/antelope/db-options.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/storage/antelope/db-options.h b/os/storage/antelope/db-options.h index 2be415f4e..ca8587071 100644 --- a/os/storage/antelope/db-options.h +++ b/os/storage/antelope/db-options.h @@ -108,7 +108,7 @@ /* The maximum size of the LVM bytecode compiled from a single database query. */ #ifndef DB_VM_BYTECODE_SIZE -#define DB_VM_BYTECODE_SIZE 128 +#define DB_VM_BYTECODE_SIZE 256 #endif /* DB_VM_BYTECODE_SIZE */ /*----------------------------------------------------------------------------*/ From e19e67b510ccc88273e89fd4b1571625ddde59bb Mon Sep 17 00:00:00 2001 From: Kiril Petrov Date: Tue, 28 Aug 2018 23:38:05 -0700 Subject: [PATCH 209/485] Fix get_temp_value for lwm2m-ipso-object example Signed-off-by: Kiril Petrov --- os/services/ipso-objects/ipso-temperature.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/os/services/ipso-objects/ipso-temperature.c b/os/services/ipso-objects/ipso-temperature.c index c27d8b6ba..db550a5c5 100644 --- a/os/services/ipso-objects/ipso-temperature.c +++ b/os/services/ipso-objects/ipso-temperature.c @@ -74,8 +74,8 @@ static lwm2m_status_t get_temp_value(const ipso_sensor_t *s, int32_t *value) { #ifdef IPSO_TEMPERATURE - if(IPSO_TEMPERATURE.read_value == NULL || - IPSO_TEMPERATURE.read_value(value) != 0) { + if(IPSO_TEMPERATURE.read_value != NULL && + IPSO_TEMPERATURE.read_value(value) == 0) { return LWM2M_STATUS_OK; } #endif /* IPSO_TEMPERATURE */ From b18320415d208292c0951d0320ef3e13777c3dbe Mon Sep 17 00:00:00 2001 From: Andreas Urke Date: Thu, 30 Aug 2018 13:48:36 +0200 Subject: [PATCH 210/485] Fix incorrect parsing of record TTL into expiration time --- os/net/ipv6/resolv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/os/net/ipv6/resolv.c b/os/net/ipv6/resolv.c index f75a084a9..2bcd3983b 100644 --- a/os/net/ipv6/resolv.c +++ b/os/net/ipv6/resolv.c @@ -1017,7 +1017,8 @@ newdata(void) namemapptr->state = STATE_DONE; #if RESOLV_SUPPORTS_RECORD_EXPIRATION - namemapptr->expiration = ans->ttl[1] + (ans->ttl[0] << 8); + namemapptr->expiration = (uint32_t) uip_ntohs(ans->ttl[0]) << 16 | + (uint32_t) uip_ntohs(ans->ttl[1]); namemapptr->expiration += clock_seconds(); #endif /* RESOLV_SUPPORTS_RECORD_EXPIRATION */ From cbba3750b64e67cdd4bf95916b4437d2a21f74ef Mon Sep 17 00:00:00 2001 From: Tom De Smet Date: Fri, 31 Aug 2018 08:50:45 +0200 Subject: [PATCH 211/485] Bump tinydtls to latest commit --- 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..53a0d97da 160000 --- a/os/net/security/tinydtls +++ b/os/net/security/tinydtls @@ -1 +1 @@ -Subproject commit 5da931eeb78d1cd4a1e0068a91de9b78bd3f66de +Subproject commit 53a0d97da748a67093c49cb38744650c71d58c4d From e8251d786b12a52b8d9faccbde1bd0de9fe4d0bb Mon Sep 17 00:00:00 2001 From: Richard Weickelt Date: Fri, 2 Feb 2018 15:29:35 +0100 Subject: [PATCH 212/485] Fix path errors when including arm makefiles from another location than a CPU makefile --- Makefile.include | 2 +- arch/cpu/arm/Makefile.arm | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Makefile.include b/Makefile.include index 319ae29d7..c3ce40f49 100644 --- a/Makefile.include +++ b/Makefile.include @@ -262,7 +262,7 @@ CONTIKI_CPU_DIRS_CONCAT = ${addprefix $(CONTIKI_CPU)/, \ $(CONTIKI_CPU_DIRS)} CONTIKI_ARCH_DIRS = ${addprefix $(CONTIKI)/, arch} -SOURCEDIRS = . $(PROJECTDIRS) $(CONTIKI_TARGET_DIRS_CONCAT) $(CONTIKI_ARCH_DIRS) \ +SOURCEDIRS = $(CONTIKI) $(PROJECTDIRS) $(CONTIKI_TARGET_DIRS_CONCAT) $(CONTIKI_ARCH_DIRS) \ $(CONTIKI_CPU_DIRS_CONCAT) $(CONTIKIDIRS) $(MODULEDIRS) $(EXTERNALDIRS) ${dir $(target_makefile)} vpath %.c $(SOURCEDIRS) diff --git a/arch/cpu/arm/Makefile.arm b/arch/cpu/arm/Makefile.arm index 0b2662423..0c71d63fa 100644 --- a/arch/cpu/arm/Makefile.arm +++ b/arch/cpu/arm/Makefile.arm @@ -1,3 +1,6 @@ +MAKEFILE := $(lastword $(MAKEFILE_LIST)) +BASE_DIR := $(realpath $(dir $(MAKEFILE))) + CC = arm-none-eabi-gcc CPP = arm-none-eabi-cpp LD = arm-none-eabi-gcc @@ -27,8 +30,9 @@ else endif ### Use CMSIS and the existing dbg-io from arch/cpu/arm/common -CONTIKI_ARM_DIRS += . common/dbg-io -CONTIKI_CPU_DIRS += $(addprefix ../arm/, $(CONTIKI_ARM_DIRS)) +CONTIKI_ARM_DIRS += . +CONTIKI_ARM_DIRS += ../common/dbg-io +CONTIKI_CPU_DIRS += $(realpath $(addprefix $(BASE_DIR)/, $(CONTIKI_ARM_DIRS))) ### CPU-dependent cleanup files CLEAN += *.elf *.bin *.lst *.hex *.i16hex From 81b782636a438117bf28e74a5c8f5a55c1ff500a Mon Sep 17 00:00:00 2001 From: Richard Weickelt Date: Fri, 2 Feb 2018 15:31:37 +0100 Subject: [PATCH 213/485] Initial port --- arch/platform/simplelink/Makefile.simplelink | 49 +++++ arch/platform/simplelink/cc13x2-cc26x2-conf.h | 204 ++++++++++++++++++ arch/platform/simplelink/cc13x2-cc26x2-def.h | 104 +++++++++ arch/platform/simplelink/contiki-conf.h | 102 +++++++++ 4 files changed, 459 insertions(+) create mode 100644 arch/platform/simplelink/Makefile.simplelink create mode 100644 arch/platform/simplelink/cc13x2-cc26x2-conf.h create mode 100644 arch/platform/simplelink/cc13x2-cc26x2-def.h create mode 100644 arch/platform/simplelink/contiki-conf.h diff --git a/arch/platform/simplelink/Makefile.simplelink b/arch/platform/simplelink/Makefile.simplelink new file mode 100644 index 000000000..9c2d00ba1 --- /dev/null +++ b/arch/platform/simplelink/Makefile.simplelink @@ -0,0 +1,49 @@ +# SimpleLink MCU platform makefile + +ifndef CONTIKI + $(error CONTIKI not defined! You must specify where CONTIKI resides!) +endif + +ifndef SIMPLELINK_SDK + $(error SIMPLELINK_SDK not defined! You must specify where the SimpleLink SDK resides!) +endif + +### Board and BSP selection +#BOARD ?= srf06/cc26xx +#BOARDS = srf06/cc26xx srf06/cc13xx launchpad/cc26xx launchpad/cc13xx sensortag/cc26xx sensortag/cc13xx + +CONTIKI_TARGET_DIRS += ./ + +### Include the board-specific makefile +PLATFORM_ROOT_DIR = $(CONTIKI)/arch/platform/$(TARGET) +#-include $(PLATFORM_ROOT_DIR)/$(BOARD)/Makefile.$(notdir $(BOARD)) + +#CONTIKI_TARGET_SOURCEFILES += platform.c +#CONTIKI_TARGET_SOURCEFILES += sensors.c leds.c +#CONTIKI_TARGET_SOURCEFILES += $(BOARD_SOURCEFILES) + +#CONTIKI_SOURCEFILES += $(CONTIKI_TARGET_SOURCEFILES) +CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES) $(DEBUG_IO_SOURCEFILES) + + +CLEAN += *.simplelink + +### Unless the example dictates otherwise, build without code size optimisations +SMALL ?= 0 + +### Always re-build ccfg.c so changes to ccfg-conf.h will apply without having +### to make clean first +$(OBJECTDIR)/ccfg.o: ccfg.c FORCE | $(OBJECTDIR) + $(TRACE_CC) + $(Q)$(CC) $(CFLAGS) -include "ccxxware-conf.h" -c $< -o $@ + +### Define the CPU directory and pull in the correct CPU makefile. This will +### be defined by one of the makefiles included above and it can be either +### Makefile.cc26xx or Makefile.cc13xx +CFLAGS += -I$(CONTIKI)/arch/cpu/arm/cortex-m/ +include $(CONTIKI)/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 + +#MODULES += os/net os/net/mac os/net/mac/framer + + + diff --git a/arch/platform/simplelink/cc13x2-cc26x2-conf.h b/arch/platform/simplelink/cc13x2-cc26x2-conf.h new file mode 100644 index 000000000..6ecdafa6b --- /dev/null +++ b/arch/platform/simplelink/cc13x2-cc26x2-conf.h @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2017, 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup cc26xx + * @{ + * + * \file + * Header with configuration defines common to all CC13xx/CC26xx platforms + */ +/*---------------------------------------------------------------------------*/ +#ifndef CC13XX_CC26XX_CONF_H_ +#define CC13XX_CC26XX_CONF_H_ +/*---------------------------------------------------------------------------*/ +/** + * \name Network Stack Configuration + * + * @{ + */ + +/* + * If set, the systems keeps the HF crystal oscillator on even when the radio is off. + * You need to set this to 1 to use TSCH with its default 2.2ms or larger guard time. + */ +#ifndef CC2650_FAST_RADIO_STARTUP +#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 +#endif + +/* + * Auto-configure Prop-mode radio if we are running on CC13xx, unless the + * project has specified otherwise. Depending on the final mode, determine a + * default channel (again, if unspecified) and configure RDC params + */ +#if CPU_FAMILY_CC13XX +#ifndef CC13XX_CONF_PROP_MODE +#define CC13XX_CONF_PROP_MODE 1 +#endif /* CC13XX_CONF_PROP_MODE */ +#endif /* CPU_FAMILY_CC13XX */ + +#if CC13XX_CONF_PROP_MODE +#define NETSTACK_CONF_RADIO prop_mode_driver + +#ifndef RF_CORE_CONF_CHANNEL +#define RF_CORE_CONF_CHANNEL 0 +#endif + +#define CSMA_CONF_ACK_WAIT_TIME (RTIMER_SECOND / 400) +#define CSMA_CONF_AFTER_ACK_DETECTED_WAIT_TIME (RTIMER_SECOND / 1000) +#define CSMA_CONF_SEND_SOFT_ACK 1 + +#else /* CC13XX_CONF_PROP_MODE */ +#define NETSTACK_CONF_RADIO ieee_mode_driver + +#define CSMA_CONF_SEND_SOFT_ACK 0 +#endif /* CC13XX_CONF_PROP_MODE */ + +#define NETSTACK_RADIO_MAX_PAYLOAD_LEN 125 + +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \name IEEE address configuration + * + * Used to generate our link-local & IPv6 address + * @{ + */ +/** + * \brief Location of the IEEE address + * 0 => Read from InfoPage, + * 1 => Use a hardcoded address, configured by IEEE_ADDR_CONF_ADDRESS + */ +#ifndef IEEE_ADDR_CONF_HARDCODED +#define IEEE_ADDR_CONF_HARDCODED 0 +#endif + +/** + * \brief The hardcoded IEEE address to be used when IEEE_ADDR_CONF_HARDCODED + * is defined as 1 + */ +#ifndef IEEE_ADDR_CONF_ADDRESS +#define IEEE_ADDR_CONF_ADDRESS { 0x00, 0x12, 0x4B, 0x00, 0x89, 0xAB, 0xCD, 0xEF } +#endif +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \name RF configuration + * + * @{ + */ +/* RF Config */ + +#ifndef IEEE_MODE_CONF_AUTOACK +#define IEEE_MODE_CONF_AUTOACK 1 /**< RF H/W generates ACKs */ +#endif + +#ifndef IEEE_MODE_CONF_PROMISCOUS +#define IEEE_MODE_CONF_PROMISCOUS 0 /**< 1 to enable promiscous mode */ +#endif + +#ifndef RF_BLE_CONF_ENABLED +#define RF_BLE_CONF_ENABLED 0 /**< 0 to disable BLE support */ +#endif +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \name Character I/O Configuration + * + * @{ + */ +#ifndef CC26XX_UART_CONF_ENABLE +#define CC26XX_UART_CONF_ENABLE 1 /**< Enable/Disable UART I/O */ +#endif + +#ifndef CC26XX_UART_CONF_BAUD_RATE +#define CC26XX_UART_CONF_BAUD_RATE 115200 /**< Default UART0 baud rate */ +#endif + +/* Enable I/O over the Debugger Devpack - Only relevant for the SensorTag */ +#ifndef BOARD_CONF_DEBUGGER_DEVPACK +#define BOARD_CONF_DEBUGGER_DEVPACK 1 +#endif + +#ifndef SLIP_ARCH_CONF_ENABLED +/* + * Determine whether we need SLIP + * This will keep working while UIP_FALLBACK_INTERFACE and CMD_CONF_OUTPUT + * keep using SLIP + */ +#if defined(UIP_FALLBACK_INTERFACE) || defined(CMD_CONF_OUTPUT) +#define SLIP_ARCH_CONF_ENABLED 1 +#endif +#endif +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \name JTAG interface configuration + * + * Enable/Disable the JTAG DAP and TAP interfaces on the chip. + * Setting this to 0 will disable access to the debug interface + * to secure deployed images. + * @{ + */ +#ifndef CCXXWARE_CONF_JTAG_INTERFACE_ENABLE +#define CCXXWARE_CONF_JTAG_INTERFACE_ENABLE 1 +#endif +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \name ROM Bootloader configuration + * + * Enable/Disable the ROM bootloader in your image, if the board supports it. + * Look in board.h to choose the DIO and corresponding level that will cause + * the chip to enter bootloader mode. + * @{ + */ +#ifndef ROM_BOOTLOADER_ENABLE +#define ROM_BOOTLOADER_ENABLE 0 +#endif +/** @} */ +/*---------------------------------------------------------------------------*/ +#endif /* CC13XX_CC26XX_CONF_H_ */ +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13x2-cc26x2-def.h b/arch/platform/simplelink/cc13x2-cc26x2-def.h new file mode 100644 index 000000000..359c6f051 --- /dev/null +++ b/arch/platform/simplelink/cc13x2-cc26x2-def.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2017, 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 CC13XX_CC26XX_DEF_H_ +#define CC13XX_CC26XX_DEF_H_ +/*---------------------------------------------------------------------------*/ +#include +/*---------------------------------------------------------------------------*/ +/* TSCH related defines */ + +/* Delay between GO signal and SFD */ +#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(81)) +/* Delay between GO signal and start listening. + * This value is so small because the radio is constantly on within each timeslot. */ +#define RADIO_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(15)) +/* Delay between the SFD finishes arriving and it is detected in software. */ +#define RADIO_DELAY_BEFORE_DETECT ((unsigned)US_TO_RTIMERTICKS(352)) + +/* Timer conversion; radio is running at 4 MHz */ +#define RADIO_TIMER_SECOND 4000000u +#if (RTIMER_SECOND % 256) || (RADIO_TIMER_SECOND % 256) +#error RADIO_TO_RTIMER macro must be fixed! +#endif +#define RADIO_TO_RTIMER(X) ((uint32_t)(((uint64_t)(X) * (RTIMER_SECOND / 256)) / (RADIO_TIMER_SECOND / 256))) +#define USEC_TO_RADIO(X) ((X) * 4) + +/* The PHY header (preamble + SFD, 4+1 bytes) duration is equivalent to 10 symbols */ +#define RADIO_IEEE_802154_PHY_HEADER_DURATION_USEC 160 + +/* Do not turn off TSCH within a timeslot: not enough time */ +#define TSCH_CONF_RADIO_ON_DURING_TIMESLOT 1 + +/* Disable TSCH frame filtering */ +#define TSCH_CONF_HW_FRAME_FILTERING 0 + +/* Use hardware timestamps */ +#ifndef TSCH_CONF_RESYNC_WITH_SFD_TIMESTAMPS +#define TSCH_CONF_RESYNC_WITH_SFD_TIMESTAMPS 1 +#define TSCH_CONF_TIMESYNC_REMOVE_JITTER 0 +#endif + +#ifndef TSCH_CONF_BASE_DRIFT_PPM +/* The drift compared to "true" 10ms slots. + * Enable adaptive sync to enable compensation for this. + * Slot length 10000 usec + * 328 ticks + * Tick duration 30.517578125 usec + * Real slot duration 10009.765625 usec + * Target - real duration = -9.765625 usec + * TSCH_CONF_BASE_DRIFT_PPM -977 + */ +#define TSCH_CONF_BASE_DRIFT_PPM -977 +#endif + +/* 10 times per second */ +#ifndef TSCH_CONF_CHANNEL_SCAN_DURATION +#define TSCH_CONF_CHANNEL_SCAN_DURATION (CLOCK_SECOND / 10) +#endif + +/* Slightly reduce the TSCH guard time (from 2200 usec to 1800 usec) to make sure + * the CC26xx radio has sufficient time to start up. */ +#ifndef TSCH_CONF_RX_WAIT +#define TSCH_CONF_RX_WAIT 1800 +#endif +/*---------------------------------------------------------------------------*/ +#define RTIMER_ARCH_SECOND 65536 +/*---------------------------------------------------------------------------*/ +/* Path to CMSIS header */ +//#define CMSIS_CONF_HEADER_PATH "cc13x0-cc26x0-cm3.h" + +/* Path to headers with implementation of mutexes and memory barriers */ +#define MUTEX_CONF_ARCH_HEADER_PATH "mutex-cortex.h" +#define MEMORY_BARRIER_CONF_ARCH_HEADER_PATH "memory-barrier-cortex.h" +/*---------------------------------------------------------------------------*/ +#endif /* CC13XX_CC26XX_DEF_H_ */ +/*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/contiki-conf.h b/arch/platform/simplelink/contiki-conf.h new file mode 100644 index 000000000..5ac07368c --- /dev/null +++ b/arch/platform/simplelink/contiki-conf.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/** + * \addtogroup cc26xx-srf-tag + * @{ + * + * \file + * Configuration for the srf06-cc26xx platform + */ +#ifndef CONTIKI_CONF_H +#define CONTIKI_CONF_H + +#include +/*---------------------------------------------------------------------------*/ +/* Include Project Specific conf */ +#ifdef PROJECT_CONF_PATH +#include PROJECT_CONF_PATH +#endif /* PROJECT_CONF_PATH */ +/*---------------------------------------------------------------------------*/ +#include "cc13x2-cc26x2-def.h" +/*---------------------------------------------------------------------------*/ +/** + * \name Button configurations + * + * Configure a button as power on/off: We use the right button for both boards. + * @{ + */ +#ifndef BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN +#define BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN 1 +#endif + +/* Notify various examples that we have Buttons */ +#define PLATFORM_HAS_BUTTON 1 + +/* + * Override button symbols from dev/button-sensor.h, for the examples that + * include it + */ +#define button_sensor button_left_sensor +#define button_sensor2 button_right_sensor +/** @} */ +/*---------------------------------------------------------------------------*/ +/* Platform-specific define to signify sensor reading failure */ +#define CC26XX_SENSOR_READING_ERROR 0x80000000 +/*---------------------------------------------------------------------------*/ +/* Include CPU-related configuration */ +#include "cc13x2-cc26x2-conf.h" +/*---------------------------------------------------------------------------*/ +/* board.h assumes that basic configuration is done */ +//#include "board.h" +/*---------------------------------------------------------------------------*/ + + +#if CCXXWARE_CONF_JTAG_INTERFACE_ENABLE +#define SET_CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE 0xC5 +#define SET_CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE 0xC5 +#define SET_CCFG_CCFG_TAP_DAP_0_PRCM_TAP_ENABLE 0xC5 +#define SET_CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE 0xC5 +#define SET_CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE 0xC5 +#define SET_CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE 0xC5 +#define SET_CCFG_CCFG_TAP_DAP_1_WUC_TAP_ENABLE 0xC5 +#else +#define SET_CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE 0x00 +#define SET_CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE 0x00 +#define SET_CCFG_CCFG_TAP_DAP_0_PRCM_TAP_ENABLE 0x00 +#define SET_CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE 0x00 +#define SET_CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE 0x00 +#define SET_CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE 0x00 +#define SET_CCFG_CCFG_TAP_DAP_1_WUC_TAP_ENABLE 0x00 +#endif + + +#endif /* CONTIKI_CONF_H */ + +/** @} */ From ddd451a19bfc4609baba6a143af9ef19f118f5c4 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Mon, 5 Feb 2018 17:18:08 +0100 Subject: [PATCH 214/485] Compiling example of dummy simplelink platform --- Makefile.identify-target | 2 + Makefile.include | 20 +- arch/cpu/arm/cortex-m/cm4/Makefile.cm4 | 21 +- arch/cpu/simplelink/Makefile.cc26x0_cc13x0 | 112 ++++++++++ arch/cpu/simplelink/Makefile.cc26x2_cc13x2 | 14 ++ arch/cpu/simplelink/Makefile.simplelink | 75 +++++++ .../cc26x0_cc13x0/cc13x0-cc26x0-cm3.h | 128 +++++++++++ .../simplelink/cc26x0_cc13x0/simplelink-def.h | 104 +++++++++ .../cc26x2_cc13x2/cc13x0-cc26x0-cm4.h | 128 +++++++++++ .../simplelink/cc26x2_cc13x2/simplelink-def.h | 104 +++++++++ arch/cpu/simplelink/rtimer-arch.h | 72 ++++++ arch/cpu/simplelink/simplelink-conf.h | 76 +++++++ arch/platform/simplelink/Makefile.simplelink | 29 +-- arch/platform/simplelink/contiki-conf.h | 29 +-- arch/platform/simplelink/platform.c | 211 ++++++++++++++++++ 15 files changed, 1066 insertions(+), 59 deletions(-) create mode 100644 arch/cpu/simplelink/Makefile.cc26x0_cc13x0 create mode 100644 arch/cpu/simplelink/Makefile.cc26x2_cc13x2 create mode 100644 arch/cpu/simplelink/Makefile.simplelink create mode 100644 arch/cpu/simplelink/cc26x0_cc13x0/cc13x0-cc26x0-cm3.h create mode 100644 arch/cpu/simplelink/cc26x0_cc13x0/simplelink-def.h create mode 100644 arch/cpu/simplelink/cc26x2_cc13x2/cc13x0-cc26x0-cm4.h create mode 100644 arch/cpu/simplelink/cc26x2_cc13x2/simplelink-def.h create mode 100644 arch/cpu/simplelink/rtimer-arch.h create mode 100644 arch/cpu/simplelink/simplelink-conf.h create mode 100644 arch/platform/simplelink/platform.c diff --git a/Makefile.identify-target b/Makefile.identify-target index 86e06c093..22b897421 100644 --- a/Makefile.identify-target +++ b/Makefile.identify-target @@ -11,4 +11,6 @@ ifeq ($(TARGET),) else ${info using saved target '$(TARGET)'} endif +else + ${info using set target '$(TARGET)'} endif diff --git a/Makefile.include b/Makefile.include index c3ce40f49..5be3ea932 100644 --- a/Makefile.include +++ b/Makefile.include @@ -39,13 +39,15 @@ ifdef CI endif endif -OBJECTDIR = obj_$(TARGET) +OBJECTDIR := obj_$(TARGET) -LOWERCASE = -abcdefghijklmnopqrstuvwxyz/ -UPPERCASE = _ABCDEFGHIJKLMNOPQRSTUVWXYZ_ +LOWERCASE := -abcdefghijklmnopqrstuvwxyz/ +UPPERCASE := _ABCDEFGHIJKLMNOPQRSTUVWXYZ_ TARGET_UPPERCASE := ${strip ${shell echo $(TARGET) | sed y!$(LOWERCASE)!$(UPPERCASE)!}} -CFLAGS += -DCONTIKI=1 -DCONTIKI_TARGET_$(TARGET_UPPERCASE)=1 +CFLAGS += -DCONTIKI=1 +CFLAGS += -DCONTIKI_TARGET_$(TARGET_UPPERCASE)=1 CFLAGS += -DCONTIKI_TARGET_STRING=\"$(TARGET)\" + ifneq ($(BOARD),) TARGET_BOARD_UPPERCASE := ${strip ${shell echo $(BOARD) | sed y!$(LOWERCASE)!$(UPPERCASE)!}} CFLAGS += -DCONTIKI_BOARD_$(TARGET_BOARD_UPPERCASE)=1 @@ -479,6 +481,7 @@ endif # Cancel the predefined implict rule for compiling and linking # a single C source into a binary to force GNU make to consider # the match-anything rule below instead. +<<<<<<< HEAD %: %.c ifeq ($(PLATFORM_ACTION),skip) @@ -493,3 +496,12 @@ else %: %.$(TARGET) @ endif +======= +#%: %.c +# +## Match-anything pattern rule to allow the project makefiles to +## abstract from the actual binary name. It needs to contain some +## command in order to be a rule, not just a prerequisite. +#%: %.$(TARGET) +# @echo "match anything rule" +>>>>>>> Compiling example of dummy simplelink platform diff --git a/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 b/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 index 1f3cdd00b..02e9e5648 100644 --- a/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 +++ b/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 @@ -1,13 +1,26 @@ CONTIKI_ARM_DIRS += cortex-m/cm4 CFLAGS += -mcpu=cortex-m4 -LDFLAGS += -mcpu=cortex-m4 + +LDFLAGS += -mcpu=cortex-m4 -nostartfiles +LDFLAGS += -T $(LDSCRIPT) +LDFLAGS += -Wl,--gc-sections,--sort-section=alignment +LDFLAGS += -Wl,-Map=$(@:.elf=-$(TARGET).map),--cref,--no-warn-mismatch + +OBJCOPY_FLAGS += --gap-fill 0xff + +### Build syscalls for newlib +MODULES += os/lib/newlib + +CPU_STARTFILES := ${addprefix $(OBJECTDIR)/,${call oname, $(CPU_START_SOURCEFILES)}} ### Compilation rules -CUSTOM_RULE_LINK=1 +CUSTOM_RULE_LINK = 1 -%.elf: $(TARGET_STARTFILES) %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(CONTIKI_NG_TARGET_LIB) $(TARGET_LIBS) +.SECONDEXPANSION: + +%.elf: $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(TARGET_LIBS) $(CONTIKI_NG_TARGET_LIB) $(TRACE_LD) - $(Q)$(CC) $(LDFLAGS) ${filter %.o %.a,$^} -o $@ + $(Q)$(LD) $(LDFLAGS) ${filter %.o %.a,$^} $(TARGET_LIBS) -o $@ include $(CONTIKI)/arch/cpu/arm/cortex-m/Makefile.cortex-m diff --git a/arch/cpu/simplelink/Makefile.cc26x0_cc13x0 b/arch/cpu/simplelink/Makefile.cc26x0_cc13x0 new file mode 100644 index 000000000..707d20722 --- /dev/null +++ b/arch/cpu/simplelink/Makefile.cc26x0_cc13x0 @@ -0,0 +1,112 @@ + +CPU_ABS_PATH = arch/cpu/simplelink + +TI_XXWARE := $(CONTIKI_CPU)/$(TI_XXWARE_PATH) + +### cc26xxware sources under driverlib will be added to the MODULES list +TI_XXWARE_SRC = $(CPU_ABS_PATH)/$(TI_XXWARE_PATH)/driverlib + +### The directory with startup sources will be added to the CONTIKI_CPU_DIRS +### and the sources therein are added to the sources list explicitly. They are +### also listed explicitly in the linker command (through TARGET_STARTFILES), +### to make sure they always get linked in the image +TI_XXWARE_STARTUP_DIR = $(TI_XXWARE_PATH)/startup_files +TI_XXWARE_STARTUP_SRCS = ccfg.c startup_gcc.c + +### MODULES will add some of these to the include path, but we need to add +### them earlier to prevent filename clashes with Contiki core files +CFLAGS += -I$(TI_XXWARE) -I$(CONTIKI)/$(TI_XXWARE_SRC) +CFLAGS += -I$(TI_XXWARE)/inc +MODULES += $(TI_XXWARE_SRC) + +LDSCRIPT = $(CONTIKI_CPU)/cc26xx.ld + +### If the user-specified a Node ID, pass a define +ifdef NODEID + CFLAGS += -DIEEE_ADDR_NODE_ID=$(NODEID) +endif + +### CPU-dependent directories +CPU_DIRS := dev rf-core rf-core/api $(TI_XXWARE_STARTUP_DIR) +CPU_DIRS_EXPAND := $(realpath $(addprefix $(BASE_DIR)/, $(CPU_DIRS))) + +CONTIKI_ARM_DIRS := $(CONTIKI_ARM_DIRS) $(CPU_DIRS) +CONTIKI_CPU_DIRS := $(CONTIKI_CPU_DIRS) $(CPU_DIRS_EXPAND) + +### CPU-dependent source files +CONTIKI_CPU_SOURCEFILES += clock.c rtimer-arch.c soc-rtc.c uart.c +CONTIKI_CPU_SOURCEFILES += contiki-watchdog.c aux-ctrl.c +CONTIKI_CPU_SOURCEFILES += putchar.c ieee-addr.c batmon-sensor.c adc-sensor.c +CONTIKI_CPU_SOURCEFILES += slip-arch.c slip.c cc26xx-uart.c lpm.c +CONTIKI_CPU_SOURCEFILES += gpio-interrupt.c oscillators.c +CONTIKI_CPU_SOURCEFILES += rf-core.c rf-ble.c ieee-mode.c +CONTIKI_CPU_SOURCEFILES += random.c soc-trng.c int-master.c + +DEBUG_IO_SOURCEFILES += dbg-printf.c dbg-snprintf.c dbg-sprintf.c strformat.c + +CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES) $(DEBUG_IO_SOURCEFILES) + +CPU_START_SOURCEFILES += fault-handlers.c $(TI_XXWARE_STARTUP_SRCS) + +PYTHON = python +BSL_FLAGS += -e -w -v + +ifdef PORT + BSL_FLAGS += -p $(PORT) +endif + +BSL = $(CONTIKI)/tools/cc2538-bsl/cc2538-bsl.py + +### Always re-build ieee-addr.o in case the command line passes a new NODEID +FORCE: + +$(OBJECTDIR)/ieee-addr.o: ieee-addr.c FORCE | $(OBJECTDIR) + $(TRACE_CC) + $(Q)$(CC) $(CFLAGS) -c $< -o $@ + +### Always re-build ccfg.c so changes to ccfg-conf.h will apply without having +### to make clean first +$(OBJECTDIR)/ccfg.o: ccfg.c FORCE | $(OBJECTDIR) + $(TRACE_CC) + $(Q)$(CC) $(CFLAGS) -include "ccxxware-conf.h" -c $< -o $@ + +# a target that gives a user-friendly memory profile, taking into account the RAM +# that is statically occupied by the stack as defined in the linker script +# see $(LDSCRIPT) +RAM_SIZE = 0x00003E00 +FLASH_SIZE = 0x0001E000 +STACK_SIZE = 0 +%.size: %.$(TARGET) + @$(SIZE) -A $< | egrep "data|bss" | awk '{s+=$$2} END {s=s+$(STACK_SIZE); f=$(RAM_SIZE)-s; printf "[RAM] used %6d, free %6d\n",s,f;}' + @$(SIZE) -A $< | egrep "text|isr_vector" | awk '{s+=$$2} END {f=$(FLASH_SIZE)-s; printf "[Flash] used %6d, free %6d\n",s,f;}' + +ifeq ($(BOARD_SUPPORTS_BSL),1) +%.upload: %.bin +ifeq ($(wildcard $(BSL)), ) + @echo "ERROR: Could not find the cc2538-bsl script. Did you run 'git submodule update --init' ?" +else + $(PYTHON) $(BSL) $(BSL_FLAGS) $< +endif +else +%.upload: + @echo "This board cannot be programmed through the ROM bootloader and therefore does not support the .upload target." +endif + +# Check if we are running under Windows +ifeq ($(HOST_OS),Windows) + SERIALDUMP ?= $(CONTIKI)/tools/sky/serialdump-windows +else +ifeq ($(HOST_OS),Darwin) + SERIALDUMP ?= $(CONTIKI)/tools/sky/serialdump-macos +else + # Else assume Linux + SERIALDUMP ?= $(CONTIKI)/tools/sky/serialdump-linux +endif +endif + +UART_BAUDRATE = 115200 + +login: + $(SERIALDUMP) -b$(UART_BAUDRATE) $(PORT) + +include $(CONTIKI)/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 diff --git a/arch/cpu/simplelink/Makefile.cc26x2_cc13x2 b/arch/cpu/simplelink/Makefile.cc26x2_cc13x2 new file mode 100644 index 000000000..3fe18edf2 --- /dev/null +++ b/arch/cpu/simplelink/Makefile.cc26x2_cc13x2 @@ -0,0 +1,14 @@ + +SDK_DRIVERLIB_BIN := $(SDK_DRIVERLIB)/bin/gcc + +ifeq "$(SIMPLELINK_DEVICE)" "cc13x2" +CFLAGS += -DDeviceFamily_CC13X2 +else +CFLAGS += -DDeviceFamily_CC26X2 +endif + +CFLAGS += -I$(CPU_ABS_PATH)/cc26x2_cc13x2 + +TARGET_LIBFILES += $(SDK_DRIVERLIB_BIN)/driverlib.lib + +include $(CONTIKI)/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 diff --git a/arch/cpu/simplelink/Makefile.simplelink b/arch/cpu/simplelink/Makefile.simplelink new file mode 100644 index 000000000..4904ba446 --- /dev/null +++ b/arch/cpu/simplelink/Makefile.simplelink @@ -0,0 +1,75 @@ + +CPU_ABS_PATH = $(CONTIKI)/arch/cpu/simplelink + +SDK_SOURCE := $(SIMPLELINK_SDK)/source +# TODO fix switch +SDK_DEVICES := $(SDK_SOURCE)/ti/devices +SDK_DEVICE := $(shell ls $(SDK_DEVICES) | grep $(SIMPLELINK_DEVICE)) +SDK_DEVICE_SOURCE := $(SDK_SOURCE)/ti/devices/$(SDK_DEVICE) +SDK_DRIVERLIB := $(SDK_DEVICE_SOURCE)/driverlib +SDK_BOARDS := $(SDK_SOURCE)/ti/boards +SDK_STARTUP := $(SDK_DEVICE_SOURCE)/startup_files +SDK_STARTUP_SRCS = ccfg.c startup_gcc.c + +EXTERNALDIRS += $(SDK_STARTUP) + +### MODULES will add some of these to the include path, but we need to add +### them earlier to prevent filename clashes with Contiki core files +CFLAGS += -I$(CPU_ABS_PATH) +CFLAGS += -I$(SDK_SOURCE) +CFLAGS += -I$(SDK_DEVICE_SOURCE) +CFLAGS += -I$(SDK_DEVICE_SOURCE)/inc + +LDSCRIPT = $(SDK_BOARDS)/$(SIMPLELINK_BOARD)/$(SIMPLELINK_BOARD)_NoRTOS.lds + +### If the user-specified a Node ID, pass a define +ifdef NODEID + CFLAGS += -DIEEE_ADDR_NODE_ID=$(NODEID) +endif + +### CPU-dependent directories +CONTIKI_ARM_DIRS += . common/dbg-io +CONTIKI_CPU_DIRS += . $(addprefix ../arm/, $(CPU_DIRS)) + +### CPU-dependent source files +# CONTIKI_CPU_SOURCEFILES += clock.c rtimer-arch.c soc-rtc.c uart.c +# CONTIKI_CPU_SOURCEFILES += contiki-watchdog.c aux-ctrl.c +# CONTIKI_CPU_SOURCEFILES += putchar.c ieee-addr.c batmon-sensor.c adc-sensor.c +# CONTIKI_CPU_SOURCEFILES += slip-arch.c slip.c cc26xx-uart.c lpm.c +# CONTIKI_CPU_SOURCEFILES += gpio-interrupt.c oscillators.c +# CONTIKI_CPU_SOURCEFILES += rf-core.c rf-ble.c ieee-mode.c +# CONTIKI_CPU_SOURCEFILES += random.c soc-trng.c int-master.c + +# DEBUG_IO_SOURCEFILES += dbg-printf.c dbg-snprintf.c dbg-sprintf.c strformat.c + +CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES) $(DEBUG_IO_SOURCEFILES) + +CPU_START_SOURCEFILES += $(SDK_STARTUP_SRCS) + +### Always re-build ieee-addr.o in case the command line passes a new NODEID +FORCE: + +$(OBJECTDIR)/ieee-addr.o: ieee-addr.c FORCE | $(OBJECTDIR) + $(TRACE_CC) + $(Q)$(CC) $(CFLAGS) -c $< -o $@ + +### Always re-build ccfg.c so changes to ccfg-conf.h will apply without having +### to make clean first +$(OBJECTDIR)/ccfg.o: ccfg.c FORCE | $(OBJECTDIR) + $(TRACE_CC) + $(Q)$(CC) $(CFLAGS) -include "simplelink-conf.h" -c $< -o $@ + +RAM_SIZE = 0x00003E00 +FLASH_SIZE = 0x0001E000 +STACK_SIZE = 0 +%.size: %.$(TARGET) + @$(SIZE) -A $< | egrep "data|bss" | awk '{s+=$$2} END {s=s+$(STACK_SIZE); f=$(RAM_SIZE)-s; printf "[RAM] used %6d, free %6d\n",s,f;}' + @$(SIZE) -A $< | egrep "text|isr_vector" | awk '{s+=$$2} END {f=$(FLASH_SIZE)-s; printf "[Flash] used %6d, free %6d\n",s,f;}' + +UART_BAUDRATE = 115200 + +login: + $(SERIALDUMP) -b$(UART_BAUDRATE) $(PORT) + +# TODO fix switch +include $(CPU_ABS_PATH)/Makefile.cc26x2_cc13x2 diff --git a/arch/cpu/simplelink/cc26x0_cc13x0/cc13x0-cc26x0-cm3.h b/arch/cpu/simplelink/cc26x0_cc13x0/cc13x0-cc26x0-cm3.h new file mode 100644 index 000000000..bda2e2b07 --- /dev/null +++ b/arch/cpu/simplelink/cc26x0_cc13x0/cc13x0-cc26x0-cm3.h @@ -0,0 +1,128 @@ +/* + * Template: + * Copyright (c) 2012 ARM LIMITED + * All rights reserved. + * + * CC13xx-CC26xx: + * Copyright (c) 2017, 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup cc26xx + * @{ + * + * \defgroup cc26xx-cm3 CC13xx/CC26xx CMSIS + * + * CC13xx/CC26xx Cortex-M3 CMSIS definitions + * @{ + * + * \file + * CMSIS Cortex-M3 core peripheral access layer header file for CC13xx/CC26xx + */ +/*---------------------------------------------------------------------------*/ +#ifndef CC13XX_CC26XX_CM3_H_ +#define CC13XX_CC26XX_CM3_H_ +/*---------------------------------------------------------------------------*/ +/** + * \name Interrupt Number Definition + * @{ + */ +typedef enum cc13xx_cc26xx_cm3_irq_e { + /* Cortex-M3 Processor Exceptions */ + CC13XX_CC26XX_CM3_EXCEPTION_RESET = -15, /**< 1 Reset */ + CC13XX_CC26XX_CM3_EXCEPTION_NMI = -14, /**< 2 NMI */ + CC13XX_CC26XX_CM3_EXCEPTION_HARD_FAULT = -13, /**< 3 Hard fault */ + CC13XX_CC26XX_CM3_EXCEPTION_MPU_FAULT = -12, /**< 4 MPU fault */ + CC13XX_CC26XX_CM3_EXCEPTION_BUS_FAULT = -11, /**< 5 Bus fault */ + CC13XX_CC26XX_CM3_EXCEPTION_USAGE_FAULT = -10, /**< 6 Usage fault */ + CC13XX_CC26XX_CM3_EXCEPTION_SV_CALL = -5, /**< 11 SVCall */ + CC13XX_CC26XX_CM3_EXCEPTION_DEBUG_MON = -4, /**< 12 Debug monitor */ + CC13XX_CC26XX_CM3_EXCEPTION_PEND_SV = -2, /**< 14 PendSV */ + CC13XX_CC26XX_CM3_EXCEPTION_SYS_TICK = -1, /**< 15 SysTick */ + + /* CC13xx/CC26xx interrupts */ + CC13XX_CC26XX_CM3_IRQ_EDGE_DETECT = 0, /**< 16 AON edge detect */ + CC13XX_CC26XX_CM3_EXCEPTION_I2C = 1, /**< 17 I2C */ + CC13XX_CC26XX_CM3_EXCEPTION_RF_CPE1 = 2, /**< 18 RF Command and Packet Engine 1 */ + CC13XX_CC26XX_CM3_EXCEPTION_AON_SPI_SLAVE = 3, /**< 19 AON SpiSplave Rx, Tx and CS */ + CC13XX_CC26XX_CM3_EXCEPTION_AON_RTC = 4, /**< 20 AON RTC */ + CC13XX_CC26XX_CM3_EXCEPTION_UART0 = 5, /**< 21 UART0 Rx and Tx */ + CC13XX_CC26XX_CM3_EXCEPTION_AON_AUX_SWEV0 = 6, /**< 22 Sensor Controller software event 0, through AON domain*/ + CC13XX_CC26XX_CM3_EXCEPTION_SSI0 = 7, /**< 23 SSI0 Rx and Tx */ + CC13XX_CC26XX_CM3_EXCEPTION_SSI1 = 8, /**< 24 SSI1 Rx and Tx */ + CC13XX_CC26XX_CM3_EXCEPTION_RF_CPE0 = 9, /**< 25 RF Command and Packet Engine 0 */ + CC13XX_CC26XX_CM3_EXCEPTION_RF_HW = 10, /**< 26 RF Core Hardware */ + CC13XX_CC26XX_CM3_EXCEPTION_RF_CMD_ACK = 11, /**< 27 RF Core Command Acknowledge */ + CC13XX_CC26XX_CM3_EXCEPTION_I2S = 12, /**< 28 I2S */ + CC13XX_CC26XX_CM3_EXCEPTION_AON_AUX_SWEV1 = 13, /**< 29 Sensor Controller software event 1, through AON domain*/ + CC13XX_CC26XX_CM3_EXCEPTION_WATCHDOG = 14, /**< 30 Watchdog timer */ + CC13XX_CC26XX_CM3_EXCEPTION_GPTIMER_0A = 15, /**< 31 Timer 0 subtimer A */ + CC13XX_CC26XX_CM3_EXCEPTION_GPTIMER_0B = 16, /**< 32 Timer 0 subtimer B */ + CC13XX_CC26XX_CM3_EXCEPTION_GPTIMER_1A = 17, /**< 33 Timer 1 subtimer A */ + CC13XX_CC26XX_CM3_EXCEPTION_GPTIMER_1B = 18, /**< 34 Timer 1 subtimer B */ + CC13XX_CC26XX_CM3_EXCEPTION_GPTIMER_2A = 19, /**< 35 Timer 2 subtimer A */ + CC13XX_CC26XX_CM3_EXCEPTION_GPTIMER_2B = 20, /**< 36 Timer 2 subtimer B */ + CC13XX_CC26XX_CM3_EXCEPTION_GPTIMER_3A = 21, /**< 37 Timer 3 subtimer A */ + CC13XX_CC26XX_CM3_EXCEPTION_GPTIMER_3B = 22, /**< 38 Timer 3 subtimer B */ + CC13XX_CC26XX_CM3_EXCEPTION_CRYPTO = 23, /**< 39 Crypto Core Result available */ + CC13XX_CC26XX_CM3_EXCEPTION_UDMA = 24, /**< 40 uDMA Software */ + CC13XX_CC26XX_CM3_EXCEPTION_UDMA_ERR = 25, /**< 41 uDMA Error */ + CC13XX_CC26XX_CM3_EXCEPTION_FLASH_CTRL = 26, /**< 42 Flash controller */ + CC13XX_CC26XX_CM3_EXCEPTION_SW0 = 27, /**< 43 Software Event 0 */ + CC13XX_CC26XX_CM3_EXCEPTION_AUX_COM_EVENT = 28, /**< 44 AUX combined event, directly to MCU domain*/ + CC13XX_CC26XX_CM3_EXCEPTION_AON_PRG0 = 29, /**< 45 AON programmable 0 */ + CC13XX_CC26XX_CM3_EXCEPTION_PROG = 30, /**< 46 Dynamic Programmable interrupt (default source: PRCM)*/ + CC13XX_CC26XX_CM3_EXCEPTION_AUX_COMPA = 31, /**< 47 AUX Comparator A */ + CC13XX_CC26XX_CM3_EXCEPTION_AUX_ADC = 32, /**< 48 AUX ADC IRQ */ + CC13XX_CC26XX_CM3_EXCEPTION_TRNG = 33, /**< 49 TRNG event */ +} cc13xx_cc26xx_cm3_irq_t; + +typedef cc13xx_cc26xx_cm3_irq_t IRQn_Type; + +#define SysTick_IRQn CC13XX_CC26XX_CM3_EXCEPTION_SYS_TICK +/** @} */ +/*---------------------------------------------------------------------------*/ +/** \name Processor and Core Peripheral Section + * @{ + */ +/* Configuration of the Cortex-M3 Processor and Core Peripherals */ +#define __MPU_PRESENT 1 /**< MPU present or not */ +#define __NVIC_PRIO_BITS 3 /**< Number of Bits used for Priority Levels */ +#define __Vendor_SysTickConfig 0 /**< Set to 1 if different SysTick Config is used */ +/** @} */ +/*---------------------------------------------------------------------------*/ +#include "core_cm3.h" /* Cortex-M3 processor and core peripherals */ +/*---------------------------------------------------------------------------*/ +#endif /* CC13XX_CC26XX_CM3_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/cpu/simplelink/cc26x0_cc13x0/simplelink-def.h b/arch/cpu/simplelink/cc26x0_cc13x0/simplelink-def.h new file mode 100644 index 000000000..40785b20c --- /dev/null +++ b/arch/cpu/simplelink/cc26x0_cc13x0/simplelink-def.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2017, 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 CC13XX_CC26XX_DEF_H_ +#define CC13XX_CC26XX_DEF_H_ +/*---------------------------------------------------------------------------*/ +#include "cm4/cm4-def.h" +/*---------------------------------------------------------------------------*/ +/* TSCH related defines */ + +/* Delay between GO signal and SFD */ +#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(81)) +/* Delay between GO signal and start listening. + * This value is so small because the radio is constantly on within each timeslot. */ +#define RADIO_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(15)) +/* Delay between the SFD finishes arriving and it is detected in software. */ +#define RADIO_DELAY_BEFORE_DETECT ((unsigned)US_TO_RTIMERTICKS(352)) + +/* Timer conversion; radio is running at 4 MHz */ +#define RADIO_TIMER_SECOND 4000000u +#if (RTIMER_SECOND % 256) || (RADIO_TIMER_SECOND % 256) +#error RADIO_TO_RTIMER macro must be fixed! +#endif +#define RADIO_TO_RTIMER(X) ((uint32_t)(((uint64_t)(X) * (RTIMER_SECOND / 256)) / (RADIO_TIMER_SECOND / 256))) +#define USEC_TO_RADIO(X) ((X) * 4) + +/* The PHY header (preamble + SFD, 4+1 bytes) duration is equivalent to 10 symbols */ +#define RADIO_IEEE_802154_PHY_HEADER_DURATION_USEC 160 + +/* Do not turn off TSCH within a timeslot: not enough time */ +#define TSCH_CONF_RADIO_ON_DURING_TIMESLOT 1 + +/* Disable TSCH frame filtering */ +#define TSCH_CONF_HW_FRAME_FILTERING 0 + +/* Use hardware timestamps */ +#ifndef TSCH_CONF_RESYNC_WITH_SFD_TIMESTAMPS +#define TSCH_CONF_RESYNC_WITH_SFD_TIMESTAMPS 1 +#define TSCH_CONF_TIMESYNC_REMOVE_JITTER 0 +#endif + +#ifndef TSCH_CONF_BASE_DRIFT_PPM +/* The drift compared to "true" 10ms slots. + * Enable adaptive sync to enable compensation for this. + * Slot length 10000 usec + * 328 ticks + * Tick duration 30.517578125 usec + * Real slot duration 10009.765625 usec + * Target - real duration = -9.765625 usec + * TSCH_CONF_BASE_DRIFT_PPM -977 + */ +#define TSCH_CONF_BASE_DRIFT_PPM -977 +#endif + +/* 10 times per second */ +#ifndef TSCH_CONF_CHANNEL_SCAN_DURATION +#define TSCH_CONF_CHANNEL_SCAN_DURATION (CLOCK_SECOND / 10) +#endif + +/* Slightly reduce the TSCH guard time (from 2200 usec to 1800 usec) to make sure + * the CC26xx radio has sufficient time to start up. */ +#ifndef TSCH_CONF_RX_WAIT +#define TSCH_CONF_RX_WAIT 1800 +#endif +/*---------------------------------------------------------------------------*/ +#define RTIMER_ARCH_SECOND 65536 +/*---------------------------------------------------------------------------*/ +/* Path to CMSIS header */ +#define CMSIS_CONF_HEADER_PATH "cc13x0-cc26x0-cm3.h" + +/* Path to headers with implementation of mutexes and memory barriers */ +#define MUTEX_CONF_ARCH_HEADER_PATH "mutex-cortex.h" +#define MEMORY_BARRIER_CONF_ARCH_HEADER_PATH "memory-barrier-cortex.h" +/*---------------------------------------------------------------------------*/ +#endif /* CC13XX_CC26XX_DEF_H_ */ +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/simplelink/cc26x2_cc13x2/cc13x0-cc26x0-cm4.h b/arch/cpu/simplelink/cc26x2_cc13x2/cc13x0-cc26x0-cm4.h new file mode 100644 index 000000000..6a9bc65f4 --- /dev/null +++ b/arch/cpu/simplelink/cc26x2_cc13x2/cc13x0-cc26x0-cm4.h @@ -0,0 +1,128 @@ +/* + * Template: + * Copyright (c) 2012 ARM LIMITED + * All rights reserved. + * + * CC13xx-CC26xx: + * Copyright (c) 2017, 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup cc26xx + * @{ + * + * \defgroup cc26xx-cm4 CC13xx/CC26xx CMSIS + * + * CC13xx/CC26xx Cortex-M4 CMSIS definitions + * @{ + * + * \file + * CMSIS Cortex-M4 core peripheral access layer header file for CC13xx/CC26xx + */ +/*---------------------------------------------------------------------------*/ +#ifndef CC13XX_CC26XX_CM4_H_ +#define CC13XX_CC26XX_CM4_H_ +/*---------------------------------------------------------------------------*/ +/** + * \name Interrupt Number Definition + * @{ + */ +typedef enum cc13xx_cc26xx_cm4_irq_e { + /* Cortex-M4 Processor Exceptions */ + CC13XX_CC26XX_CM4_EXCEPTION_RESET = -15, /**< 1 Reset */ + CC13XX_CC26XX_CM4_EXCEPTION_NMI = -14, /**< 2 NMI */ + CC13XX_CC26XX_CM4_EXCEPTION_HARD_FAULT = -13, /**< 3 Hard fault */ + CC13XX_CC26XX_CM4_EXCEPTION_MPU_FAULT = -12, /**< 4 MPU fault */ + CC13XX_CC26XX_CM4_EXCEPTION_BUS_FAULT = -11, /**< 5 Bus fault */ + CC13XX_CC26XX_CM4_EXCEPTION_USAGE_FAULT = -10, /**< 6 Usage fault */ + CC13XX_CC26XX_CM4_EXCEPTION_SV_CALL = -5, /**< 11 SVCall */ + CC13XX_CC26XX_CM4_EXCEPTION_DEBUG_MON = -4, /**< 12 Debug monitor */ + CC13XX_CC26XX_CM4_EXCEPTION_PEND_SV = -2, /**< 14 PendSV */ + CC13XX_CC26XX_CM4_EXCEPTION_SYS_TICK = -1, /**< 15 SysTick */ + + /* CC13xx/CC26xx interrupts */ + CC13XX_CC26XX_CM4_IRQ_EDGE_DETECT = 0, /**< 16 AON edge detect */ + CC13XX_CC26XX_CM4_EXCEPTION_I2C = 1, /**< 17 I2C */ + CC13XX_CC26XX_CM4_EXCEPTION_RF_CPE1 = 2, /**< 18 RF Command and Packet Engine 1 */ + CC13XX_CC26XX_CM4_EXCEPTION_AON_SPI_SLAVE = 3, /**< 19 AON SpiSplave Rx, Tx and CS */ + CC13XX_CC26XX_CM4_EXCEPTION_AON_RTC = 4, /**< 20 AON RTC */ + CC13XX_CC26XX_CM4_EXCEPTION_UART0 = 5, /**< 21 UART0 Rx and Tx */ + CC13XX_CC26XX_CM4_EXCEPTION_AON_AUX_SWEV0 = 6, /**< 22 Sensor Controller software event 0, through AON domain*/ + CC13XX_CC26XX_CM4_EXCEPTION_SSI0 = 7, /**< 23 SSI0 Rx and Tx */ + CC13XX_CC26XX_CM4_EXCEPTION_SSI1 = 8, /**< 24 SSI1 Rx and Tx */ + CC13XX_CC26XX_CM4_EXCEPTION_RF_CPE0 = 9, /**< 25 RF Command and Packet Engine 0 */ + CC13XX_CC26XX_CM4_EXCEPTION_RF_HW = 10, /**< 26 RF Core Hardware */ + CC13XX_CC26XX_CM4_EXCEPTION_RF_CMD_ACK = 11, /**< 27 RF Core Command Acknowledge */ + CC13XX_CC26XX_CM4_EXCEPTION_I2S = 12, /**< 28 I2S */ + CC13XX_CC26XX_CM4_EXCEPTION_AON_AUX_SWEV1 = 13, /**< 29 Sensor Controller software event 1, through AON domain*/ + CC13XX_CC26XX_CM4_EXCEPTION_WATCHDOG = 14, /**< 30 Watchdog timer */ + CC13XX_CC26XX_CM4_EXCEPTION_GPTIMER_0A = 15, /**< 31 Timer 0 subtimer A */ + CC13XX_CC26XX_CM4_EXCEPTION_GPTIMER_0B = 16, /**< 32 Timer 0 subtimer B */ + CC13XX_CC26XX_CM4_EXCEPTION_GPTIMER_1A = 17, /**< 33 Timer 1 subtimer A */ + CC13XX_CC26XX_CM4_EXCEPTION_GPTIMER_1B = 18, /**< 34 Timer 1 subtimer B */ + CC13XX_CC26XX_CM4_EXCEPTION_GPTIMER_2A = 19, /**< 35 Timer 2 subtimer A */ + CC13XX_CC26XX_CM4_EXCEPTION_GPTIMER_2B = 20, /**< 36 Timer 2 subtimer B */ + CC13XX_CC26XX_CM4_EXCEPTION_GPTIMER_3A = 21, /**< 37 Timer 3 subtimer A */ + CC13XX_CC26XX_CM4_EXCEPTION_GPTIMER_3B = 22, /**< 38 Timer 3 subtimer B */ + CC13XX_CC26XX_CM4_EXCEPTION_CRYPTO = 23, /**< 39 Crypto Core Result available */ + CC13XX_CC26XX_CM4_EXCEPTION_UDMA = 24, /**< 40 uDMA Software */ + CC13XX_CC26XX_CM4_EXCEPTION_UDMA_ERR = 25, /**< 41 uDMA Error */ + CC13XX_CC26XX_CM4_EXCEPTION_FLASH_CTRL = 26, /**< 42 Flash controller */ + CC13XX_CC26XX_CM4_EXCEPTION_SW0 = 27, /**< 43 Software Event 0 */ + CC13XX_CC26XX_CM4_EXCEPTION_AUX_COM_EVENT = 28, /**< 44 AUX combined event, directly to MCU domain*/ + CC13XX_CC26XX_CM4_EXCEPTION_AON_PRG0 = 29, /**< 45 AON programmable 0 */ + CC13XX_CC26XX_CM4_EXCEPTION_PROG = 30, /**< 46 Dynamic Programmable interrupt (default source: PRCM)*/ + CC13XX_CC26XX_CM4_EXCEPTION_AUX_COMPA = 31, /**< 47 AUX Comparator A */ + CC13XX_CC26XX_CM4_EXCEPTION_AUX_ADC = 32, /**< 48 AUX ADC IRQ */ + CC13XX_CC26XX_CM4_EXCEPTION_TRNG = 33, /**< 49 TRNG event */ +} cc13xx_cc26xx_cm4_irq_t; + +typedef cc13xx_cc26xx_cm4_irq_t IRQn_Type; + +#define SysTick_IRQn CC13XX_CC26XX_CM4_EXCEPTION_SYS_TICK +/** @} */ +/*---------------------------------------------------------------------------*/ +/** \name Processor and Core Peripheral Section + * @{ + */ +/* Configuration of the Cortex-M4 Processor and Core Peripherals */ +#define __MPU_PRESENT 1 /**< MPU present or not */ +#define __NVIC_PRIO_BITS 3 /**< Number of Bits used for Priority Levels */ +#define __Vendor_SysTickConfig 0 /**< Set to 1 if different SysTick Config is used */ +/** @} */ +/*---------------------------------------------------------------------------*/ +#include "core_cm4.h" /* Cortex-M4 processor and core peripherals */ +/*---------------------------------------------------------------------------*/ +#endif /* CC13XX_CC26XX_CM4_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/cpu/simplelink/cc26x2_cc13x2/simplelink-def.h b/arch/cpu/simplelink/cc26x2_cc13x2/simplelink-def.h new file mode 100644 index 000000000..d0e95a261 --- /dev/null +++ b/arch/cpu/simplelink/cc26x2_cc13x2/simplelink-def.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2017, 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 CC13XX_CC26XX_DEF_H_ +#define CC13XX_CC26XX_DEF_H_ +/*---------------------------------------------------------------------------*/ +#include "cm4/cm4-def.h" +/*---------------------------------------------------------------------------*/ +/* TSCH related defines */ + +/* Delay between GO signal and SFD */ +#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(81)) +/* Delay between GO signal and start listening. + * This value is so small because the radio is constantly on within each timeslot. */ +#define RADIO_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(15)) +/* Delay between the SFD finishes arriving and it is detected in software. */ +#define RADIO_DELAY_BEFORE_DETECT ((unsigned)US_TO_RTIMERTICKS(352)) + +/* Timer conversion; radio is running at 4 MHz */ +#define RADIO_TIMER_SECOND 4000000u +#if (RTIMER_SECOND % 256) || (RADIO_TIMER_SECOND % 256) +#error RADIO_TO_RTIMER macro must be fixed! +#endif +#define RADIO_TO_RTIMER(X) ((uint32_t)(((uint64_t)(X) * (RTIMER_SECOND / 256)) / (RADIO_TIMER_SECOND / 256))) +#define USEC_TO_RADIO(X) ((X) * 4) + +/* The PHY header (preamble + SFD, 4+1 bytes) duration is equivalent to 10 symbols */ +#define RADIO_IEEE_802154_PHY_HEADER_DURATION_USEC 160 + +/* Do not turn off TSCH within a timeslot: not enough time */ +#define TSCH_CONF_RADIO_ON_DURING_TIMESLOT 1 + +/* Disable TSCH frame filtering */ +#define TSCH_CONF_HW_FRAME_FILTERING 0 + +/* Use hardware timestamps */ +#ifndef TSCH_CONF_RESYNC_WITH_SFD_TIMESTAMPS +#define TSCH_CONF_RESYNC_WITH_SFD_TIMESTAMPS 1 +#define TSCH_CONF_TIMESYNC_REMOVE_JITTER 0 +#endif + +#ifndef TSCH_CONF_BASE_DRIFT_PPM +/* The drift compared to "true" 10ms slots. + * Enable adaptive sync to enable compensation for this. + * Slot length 10000 usec + * 328 ticks + * Tick duration 30.517578125 usec + * Real slot duration 10009.765625 usec + * Target - real duration = -9.765625 usec + * TSCH_CONF_BASE_DRIFT_PPM -977 + */ +#define TSCH_CONF_BASE_DRIFT_PPM -977 +#endif + +/* 10 times per second */ +#ifndef TSCH_CONF_CHANNEL_SCAN_DURATION +#define TSCH_CONF_CHANNEL_SCAN_DURATION (CLOCK_SECOND / 10) +#endif + +/* Slightly reduce the TSCH guard time (from 2200 usec to 1800 usec) to make sure + * the CC26xx radio has sufficient time to start up. */ +#ifndef TSCH_CONF_RX_WAIT +#define TSCH_CONF_RX_WAIT 1800 +#endif +/*---------------------------------------------------------------------------*/ +#define RTIMER_ARCH_SECOND 65536 +/*---------------------------------------------------------------------------*/ +/* Path to CMSIS header */ +#define CMSIS_CONF_HEADER_PATH "cc13x0-cc26x0-cm4.h" + +/* Path to headers with implementation of mutexes and memory barriers */ +#define MUTEX_CONF_ARCH_HEADER_PATH "mutex-cortex.h" +#define MEMORY_BARRIER_CONF_ARCH_HEADER_PATH "memory-barrier-cortex.h" +/*---------------------------------------------------------------------------*/ +#endif /* CC13XX_CC26XX_DEF_H_ */ +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/simplelink/rtimer-arch.h b/arch/cpu/simplelink/rtimer-arch.h new file mode 100644 index 000000000..aa1682ec4 --- /dev/null +++ b/arch/cpu/simplelink/rtimer-arch.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup cc26xx-clocks + * @{ + * + * \defgroup cc26xx-rtimer CC13xx/CC26xx rtimer + * + * Implementation of the rtimer module for the CC13xx/CC26xx + * @{ + */ +/** + * \file + * Header file for the CC13xx/CC26xx rtimer driver + */ +/*---------------------------------------------------------------------------*/ +#ifndef RTIMER_ARCH_H_ +#define RTIMER_ARCH_H_ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +/*---------------------------------------------------------------------------*/ +inline rtimer_clock_t rtimer_arch_now(void) { rtimer_clock_t rtc = { 0 }; return rtc; } + +/* HW oscillator frequency is 32 kHz, not 64 kHz and RTIMER_NOW() never returns + * an odd value; so US_TO_RTIMERTICKS always rounds to the nearest even number. + */ +#define US_TO_RTIMERTICKS(US) (2 * ((US) >= 0 ? \ + (((int32_t)(US) * (RTIMER_ARCH_SECOND / 2) + 500000) / 1000000L) : \ + ((int32_t)(US) * (RTIMER_ARCH_SECOND / 2) - 500000) / 1000000L)) + +#define RTIMERTICKS_TO_US(T) ((T) >= 0 ? \ + (((int32_t)(T) * 1000000L + ((RTIMER_ARCH_SECOND) / 2)) / (RTIMER_ARCH_SECOND)) : \ + ((int32_t)(T) * 1000000L - ((RTIMER_ARCH_SECOND) / 2)) / (RTIMER_ARCH_SECOND)) + +/* A 64-bit version because the 32-bit one cannot handle T >= 4295 ticks. + Intended only for positive values of T. */ +#define RTIMERTICKS_TO_US_64(T) ((uint32_t)(((uint64_t)(T) * 1000000 + ((RTIMER_ARCH_SECOND) / 2)) / (RTIMER_ARCH_SECOND))) +/*---------------------------------------------------------------------------*/ +#endif /* RTIMER_ARCH_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/cpu/simplelink/simplelink-conf.h b/arch/cpu/simplelink/simplelink-conf.h new file mode 100644 index 000000000..97be16b5d --- /dev/null +++ b/arch/cpu/simplelink/simplelink-conf.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2017, Alex Stanoev + * 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. + */ +/** + * \addtogroup cc26xx + * @{ + * + * \defgroup cc26xx-ccxxware-conf CCxxware-specific configuration + * + * @{ + * + * \file + * CCxxware-specific configuration for the cc26xx-cc13xx CPU family + */ +#ifndef CCXXWARE_CONF_H_ +#define CCXXWARE_CONF_H_ + +#include "contiki-conf.h" + +/*---------------------------------------------------------------------------*/ +/** + * \brief JTAG interface configuration + * + * Those values are not meant to be modified by the user + * @{ + */ +#if CCXXWARE_CONF_JTAG_INTERFACE_ENABLE +#define SET_CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE 0xC5 +#define SET_CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE 0xC5 +#define SET_CCFG_CCFG_TAP_DAP_0_PRCM_TAP_ENABLE 0xC5 +#define SET_CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE 0xC5 +#define SET_CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE 0xC5 +#define SET_CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE 0xC5 +#define SET_CCFG_CCFG_TAP_DAP_1_WUC_TAP_ENABLE 0xC5 +#else +#define SET_CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE 0x00 +#define SET_CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE 0x00 +#define SET_CCFG_CCFG_TAP_DAP_0_PRCM_TAP_ENABLE 0x00 +#define SET_CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE 0x00 +#define SET_CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE 0x00 +#define SET_CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE 0x00 +#define SET_CCFG_CCFG_TAP_DAP_1_WUC_TAP_ENABLE 0x00 +#endif +/** @} */ +#endif /* CCXXWARE_CONF_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/platform/simplelink/Makefile.simplelink b/arch/platform/simplelink/Makefile.simplelink index 9c2d00ba1..2a28cd231 100644 --- a/arch/platform/simplelink/Makefile.simplelink +++ b/arch/platform/simplelink/Makefile.simplelink @@ -9,39 +9,20 @@ ifndef SIMPLELINK_SDK endif ### Board and BSP selection -#BOARD ?= srf06/cc26xx -#BOARDS = srf06/cc26xx srf06/cc13xx launchpad/cc26xx launchpad/cc13xx sensortag/cc26xx sensortag/cc13xx -CONTIKI_TARGET_DIRS += ./ +CONTIKI_TARGET_DIRS += . -### Include the board-specific makefile -PLATFORM_ROOT_DIR = $(CONTIKI)/arch/platform/$(TARGET) -#-include $(PLATFORM_ROOT_DIR)/$(BOARD)/Makefile.$(notdir $(BOARD)) - -#CONTIKI_TARGET_SOURCEFILES += platform.c -#CONTIKI_TARGET_SOURCEFILES += sensors.c leds.c -#CONTIKI_TARGET_SOURCEFILES += $(BOARD_SOURCEFILES) - -#CONTIKI_SOURCEFILES += $(CONTIKI_TARGET_SOURCEFILES) -CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES) $(DEBUG_IO_SOURCEFILES) +CONTIKI_TARGET_SOURCEFILES += platform.c +CONTIKI_SOURCEFILES += $(CONTIKI_TARGET_SOURCEFILES) CLEAN += *.simplelink ### Unless the example dictates otherwise, build without code size optimisations SMALL ?= 0 -### Always re-build ccfg.c so changes to ccfg-conf.h will apply without having -### to make clean first -$(OBJECTDIR)/ccfg.o: ccfg.c FORCE | $(OBJECTDIR) - $(TRACE_CC) - $(Q)$(CC) $(CFLAGS) -include "ccxxware-conf.h" -c $< -o $@ - -### Define the CPU directory and pull in the correct CPU makefile. This will -### be defined by one of the makefiles included above and it can be either -### Makefile.cc26xx or Makefile.cc13xx -CFLAGS += -I$(CONTIKI)/arch/cpu/arm/cortex-m/ -include $(CONTIKI)/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 +CONTIKI_CPU = $(CONTIKI)/arch/cpu/simplelink +include $(CONTIKI_CPU)/Makefile.simplelink #MODULES += os/net os/net/mac os/net/mac/framer diff --git a/arch/platform/simplelink/contiki-conf.h b/arch/platform/simplelink/contiki-conf.h index 5ac07368c..c616c7610 100644 --- a/arch/platform/simplelink/contiki-conf.h +++ b/arch/platform/simplelink/contiki-conf.h @@ -44,7 +44,7 @@ #include PROJECT_CONF_PATH #endif /* PROJECT_CONF_PATH */ /*---------------------------------------------------------------------------*/ -#include "cc13x2-cc26x2-def.h" +#include "simplelink-def.h" /*---------------------------------------------------------------------------*/ /** * \name Button configurations @@ -71,32 +71,7 @@ #define CC26XX_SENSOR_READING_ERROR 0x80000000 /*---------------------------------------------------------------------------*/ /* Include CPU-related configuration */ -#include "cc13x2-cc26x2-conf.h" -/*---------------------------------------------------------------------------*/ -/* board.h assumes that basic configuration is done */ -//#include "board.h" -/*---------------------------------------------------------------------------*/ - - -#if CCXXWARE_CONF_JTAG_INTERFACE_ENABLE -#define SET_CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE 0xC5 -#define SET_CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE 0xC5 -#define SET_CCFG_CCFG_TAP_DAP_0_PRCM_TAP_ENABLE 0xC5 -#define SET_CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE 0xC5 -#define SET_CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE 0xC5 -#define SET_CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE 0xC5 -#define SET_CCFG_CCFG_TAP_DAP_1_WUC_TAP_ENABLE 0xC5 -#else -#define SET_CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE 0x00 -#define SET_CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE 0x00 -#define SET_CCFG_CCFG_TAP_DAP_0_PRCM_TAP_ENABLE 0x00 -#define SET_CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE 0x00 -#define SET_CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE 0x00 -#define SET_CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE 0x00 -#define SET_CCFG_CCFG_TAP_DAP_1_WUC_TAP_ENABLE 0x00 -#endif - - +#include "simplelink-conf.h" #endif /* CONTIKI_CONF_H */ /** @} */ diff --git a/arch/platform/simplelink/platform.c b/arch/platform/simplelink/platform.c new file mode 100644 index 000000000..0691f669c --- /dev/null +++ b/arch/platform/simplelink/platform.c @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup cc26xx-platforms + * @{ + * + * \defgroup cc26xx-srf-tag SmartRF+CC13xx/CC26xx EM, SensorTags and LaunchPads + * + * This platform supports a number of different boards: + * - A standard TI SmartRF06EB with a CC26xx EM mounted on it + * - A standard TI SmartRF06EB with a CC1310 EM mounted on it + * - The TI CC2650 SensorTag + * - The TI CC1350 SensorTag + * - The TI CC2650 LaunchPad + * - The TI CC1310 LaunchPad + * - The TI CC1350 LaunchPad + * @{ + */ +#include "contiki.h" +#include "contiki-net.h" +//#include "leds.h" +//#include "lpm.h" +//#include "gpio-interrupt.h" +//#include "dev/oscillators.h" +//#include "ieee-addr.h" +//#include "vims.h" +//#include "dev/cc26xx-uart.h" +//#include "dev/soc-rtc.h" +//#include "rf-core/rf-core.h" +//#include "sys_ctrl.h" +//#include "uart.h" +//#include "sys/clock.h" +//#include "sys/rtimer.h" +//#include "sys/node-id.h" +//#include "sys/platform.h" +//#include "lib/random.h" +//#include "lib/sensors.h" +//#include "button-sensor.h" +//#include "dev/serial-line.h" +//#include "net/mac/framer/frame802154.h" +// +//#include "driverlib/driverlib_release.h" + +#include +/*---------------------------------------------------------------------------*/ +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "CC26xx/CC13xx" +#define LOG_LEVEL LOG_LEVEL_MAIN +/*---------------------------------------------------------------------------*/ +unsigned short node_id = 0; +/*---------------------------------------------------------------------------*/ +/** \brief Board specific iniatialisation */ +void board_init(void); +/*---------------------------------------------------------------------------*/ +//static void +//fade(unsigned char l) +//{ +// volatile int i; +// int k, j; +// for(k = 0; k < 800; ++k) { +// j = k > 400 ? 800 - k : k; +// +// leds_on(l); +// for(i = 0; i < j; ++i) { +// __asm("nop"); +// } +// leds_off(l); +// for(i = 0; i < 400 - j; ++i) { +// __asm("nop"); +// } +// } +//} +/*---------------------------------------------------------------------------*/ +//static void +//set_rf_params(void) +//{ +// uint16_t short_addr; +// uint8_t ext_addr[8]; +// +// ieee_addr_cpy_to(ext_addr, 8); +// +// short_addr = ext_addr[7]; +// short_addr |= ext_addr[6] << 8; +// +// 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_object(RADIO_PARAM_64BIT_ADDR, ext_addr, 8); +// +// /* also set the global node id */ +// node_id = short_addr; +//} +/*---------------------------------------------------------------------------*/ +void +platform_init_stage_one() +{ +// /* Enable flash cache and prefetch. */ +// ti_lib_vims_mode_set(VIMS_BASE, VIMS_MODE_ENABLED); +// ti_lib_vims_configure(VIMS_BASE, true, true); +// +// ti_lib_int_master_disable(); +// +// /* Set the LF XOSC as the LF system clock source */ +// oscillators_select_lf_xosc(); +// +// lpm_init(); +// +// board_init(); +// +// gpio_interrupt_init(); +// +// leds_init(); +// fade(LEDS_RED); +// +// /* +// * Disable I/O pad sleep mode and open I/O latches in the AON IOC interface +// * This is only relevant when returning from shutdown (which is what froze +// * latches in the first place. Before doing these things though, we should +// * allow software to first regain control of pins +// */ +// ti_lib_pwr_ctrl_io_freeze_disable(); +// +// ti_lib_int_master_enable(); +// +// soc_rtc_init(); +// fade(LEDS_YELLOW); +} +/*---------------------------------------------------------------------------*/ +void +platform_init_stage_two() +{ +// random_init(0x1234); +// +// /* Character I/O Initialisation */ +//#if CC26XX_UART_CONF_ENABLE +// cc26xx_uart_init(); +//#endif +// +// serial_line_init(); +// +// /* Populate linkaddr_node_addr */ +// ieee_addr_cpy_to(linkaddr_node_addr.u8, LINKADDR_SIZE); +// +// fade(LEDS_GREEN); +} +/*---------------------------------------------------------------------------*/ +void +platform_init_stage_three() +{ +// radio_value_t chan, pan; +// +// set_rf_params(); +// +// NETSTACK_RADIO.get_value(RADIO_PARAM_CHANNEL, &chan); +// NETSTACK_RADIO.get_value(RADIO_PARAM_PAN_ID, &pan); +// +// LOG_DBG("With DriverLib v%u.%u\n", DRIVERLIB_RELEASE_GROUP, +// DRIVERLIB_RELEASE_BUILD); +// LOG_INFO(BOARD_STRING "\n"); +// LOG_DBG("IEEE 802.15.4: %s, Sub-GHz: %s, BLE: %s, Prop: %s\n", +// ti_lib_chipinfo_supports_ieee_802_15_4() == true ? "Yes" : "No", +// ti_lib_chipinfo_chip_family_is_cc13xx() == true ? "Yes" : "No", +// ti_lib_chipinfo_supports_ble() == true ? "Yes" : "No", +// ti_lib_chipinfo_supports_proprietary() == true ? "Yes" : "No"); +// LOG_INFO(" RF: Channel %d, PANID 0x%04X\n", chan, pan); +// LOG_INFO(" Node ID: %d\n", node_id); +// +// process_start(&sensors_process, NULL); +// fade(LEDS_ORANGE); +} +/*---------------------------------------------------------------------------*/ +void +platform_idle() +{ + /* Drop to some low power mode */ +// lpm_drop(); +} +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ From be4131d2772bf2e6fb1aeb1336ad65b549e04eb7 Mon Sep 17 00:00:00 2001 From: Richard Weickelt Date: Tue, 6 Feb 2018 12:30:10 +0100 Subject: [PATCH 215/485] Add necessary SDK libraries and include paths --- arch/cpu/simplelink/Makefile.cc26x2_cc13x2 | 11 +++++++---- arch/cpu/simplelink/Makefile.simplelink | 6 +++++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/arch/cpu/simplelink/Makefile.cc26x2_cc13x2 b/arch/cpu/simplelink/Makefile.cc26x2_cc13x2 index 3fe18edf2..a0a91679f 100644 --- a/arch/cpu/simplelink/Makefile.cc26x2_cc13x2 +++ b/arch/cpu/simplelink/Makefile.cc26x2_cc13x2 @@ -1,14 +1,17 @@ -SDK_DRIVERLIB_BIN := $(SDK_DRIVERLIB)/bin/gcc - -ifeq "$(SIMPLELINK_DEVICE)" "cc13x2" +ifeq "$(SIMPLELINK_DEVICE)" "cc13x2" CFLAGS += -DDeviceFamily_CC13X2 else CFLAGS += -DDeviceFamily_CC26X2 endif CFLAGS += -I$(CPU_ABS_PATH)/cc26x2_cc13x2 +CFLAGS += -I$(SDK_KERNEL) + +TARGET_LIBFILES += $(SDK_DRIVERLIB)/bin/gcc/driverlib.lib +TARGET_LIBFILES += $(SDK_DRIVERS)/lib/drivers_cc13x2.am4fg +TARGET_LIBFILES += $(SDK_DRIVERS)/lib/rf_multiMode_cc13x2.am4fg +TARGET_LIBFILES += $(SDK_KERNEL)/lib/nortos_cc13x2.am4fg -TARGET_LIBFILES += $(SDK_DRIVERLIB_BIN)/driverlib.lib include $(CONTIKI)/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 diff --git a/arch/cpu/simplelink/Makefile.simplelink b/arch/cpu/simplelink/Makefile.simplelink index 4904ba446..e4f959543 100644 --- a/arch/cpu/simplelink/Makefile.simplelink +++ b/arch/cpu/simplelink/Makefile.simplelink @@ -7,6 +7,8 @@ SDK_DEVICES := $(SDK_SOURCE)/ti/devices SDK_DEVICE := $(shell ls $(SDK_DEVICES) | grep $(SIMPLELINK_DEVICE)) SDK_DEVICE_SOURCE := $(SDK_SOURCE)/ti/devices/$(SDK_DEVICE) SDK_DRIVERLIB := $(SDK_DEVICE_SOURCE)/driverlib +SDK_DRIVERS := $(SDK_SOURCE)/ti/drivers +SDK_KERNEL := $(SIMPLELINK_SDK)/kernel/nortos/ SDK_BOARDS := $(SDK_SOURCE)/ti/boards SDK_STARTUP := $(SDK_DEVICE_SOURCE)/startup_files SDK_STARTUP_SRCS = ccfg.c startup_gcc.c @@ -15,10 +17,12 @@ EXTERNALDIRS += $(SDK_STARTUP) ### MODULES will add some of these to the include path, but we need to add ### them earlier to prevent filename clashes with Contiki core files -CFLAGS += -I$(CPU_ABS_PATH) +CFLAGS += -I$(CPU_ABS_PATH) CFLAGS += -I$(SDK_SOURCE) CFLAGS += -I$(SDK_DEVICE_SOURCE) CFLAGS += -I$(SDK_DEVICE_SOURCE)/inc +CFLAGS += -I$(SDK_KERNEL) +CFLAGS += -I$(SDK_KERNEL)/posix LDSCRIPT = $(SDK_BOARDS)/$(SIMPLELINK_BOARD)/$(SIMPLELINK_BOARD)_NoRTOS.lds From b861190cb8d3fc2a4a2b01f6ec1d0480297b4ec4 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Tue, 6 Feb 2018 13:58:17 +0100 Subject: [PATCH 216/485] Initial commit for rtimer-arch --- arch/cpu/simplelink/Makefile.simplelink | 2 +- arch/cpu/simplelink/rtimer-arch.c | 148 ++++++++++++++++++++++++ arch/cpu/simplelink/rtimer-arch.h | 2 +- 3 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 arch/cpu/simplelink/rtimer-arch.c diff --git a/arch/cpu/simplelink/Makefile.simplelink b/arch/cpu/simplelink/Makefile.simplelink index e4f959543..bda65826d 100644 --- a/arch/cpu/simplelink/Makefile.simplelink +++ b/arch/cpu/simplelink/Makefile.simplelink @@ -36,7 +36,7 @@ CONTIKI_ARM_DIRS += . common/dbg-io CONTIKI_CPU_DIRS += . $(addprefix ../arm/, $(CPU_DIRS)) ### CPU-dependent source files -# CONTIKI_CPU_SOURCEFILES += clock.c rtimer-arch.c soc-rtc.c uart.c +CONTIKI_CPU_SOURCEFILES += rtimer-arch.c # CONTIKI_CPU_SOURCEFILES += contiki-watchdog.c aux-ctrl.c # CONTIKI_CPU_SOURCEFILES += putchar.c ieee-addr.c batmon-sensor.c adc-sensor.c # CONTIKI_CPU_SOURCEFILES += slip-arch.c slip.c cc26xx-uart.c lpm.c diff --git a/arch/cpu/simplelink/rtimer-arch.c b/arch/cpu/simplelink/rtimer-arch.c new file mode 100644 index 000000000..f9f1fbf7a --- /dev/null +++ b/arch/cpu/simplelink/rtimer-arch.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup cc26xx-rtimer + * @{ + * + * \file + * Implementation of the arch-specific rtimer functions for the CC13xx/CC26xx + */ +/*---------------------------------------------------------------------------*/ +#include +#include +#include +#include + +#include "contiki.h" + +#include + +#define RTIMER_RTC_CH AON_RTC_CH1 + +static ClockP_Struct gClk; +static ClockP_Handle hClk; + +typedef void (*IsrFxn)(void); +typedef void (*HwiDispatchFxn)(void); + +static HwiDispatchFxn hwiDispatch = NULL; + +static void rtimer_clock_stub(uintptr_t arg) { /* do nothing */ } + +static void +rtimer_isr_hook(void) +{ + if (AONRTCEventGet(RTIMER_RTC_CH)) + { + AONRTCEventClear(RTIMER_RTC_CH); + AONRTCChannelDisable(RTIMER_RTC_CH); + + rtimer_run_next(); + } + if (hwiDispatch && AONRTCEventGet(AON_RTC_CH0)) + { + hwiDispatch(); + } + else + { + IntPendClear(INT_AON_RTC_COMB); + } +} + +/*---------------------------------------------------------------------------*/ +/** + * \brief TODO + */ +void +rtimer_arch_init(void) +{ + // Create dummy clock to trigger init of the RAM vector table + ClockP_Params clkParams; + ClockP_Params_init(&clkParams); + hClk = ClockP_construct(&gClk, rtimer_clock_stub, 0, &clkParams); + + // Try to access the RAM vector table + IsrFxn *pfnRAMVectors = (IsrFxn *)(HWREG(NVIC_VTABLE)); + if (!pfnRAMVectors) + { + while (0) {} + } + + // The HWI Dispatch ISR should be located at int num INT_AON_RTC_COMB. + // Fetch and store it. + hwiDispatch = (HwiDispatchFxn)pfnRAMVectors[INT_AON_RTC_COMB]; + if (!hwiDispatch) + { + while (0) {} + } + + // Override the INT_AON_RTC_COMB int num with own ISR hook + IntRegister(INT_AON_RTC_COMB, rtimer_isr_hook); + + AONEventMcuWakeUpSet(AON_EVENT_MCU_WU1, AON_EVENT_RTC_CH1); + AONRTCCombinedEventConfig(AON_RTC_CH0 | RTIMER_RTC_CH); + return; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Schedules an rtimer task to be triggered at time t + * \param t The time when the task will need executed. + * + * \e t is an absolute time, in other words the task will be executed AT + * time \e t, not IN \e t rtimer ticks. + * + * This function schedules a one-shot event with the AON RTC. + * + * This functions converts \e to a value suitable for the AON RTC. + */ +void +rtimer_arch_schedule(rtimer_clock_t t) +{ + /* Convert the rtimer tick value to a value suitable for the AON RTC */ + AONRTCCompareValueSet(RTIMER_RTC_CH, (uint32_t)t); + AONRTCChannelEnable(RTIMER_RTC_CH); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Returns the current real-time clock time + * \return The current rtimer time in ticks + * + * The value is read from the AON RTC counter and converted to a number of + * rtimer ticks + * + */ +rtimer_clock_t +rtimer_arch_now() +{ + return ((rtimer_clock_t)AONRTCCurrentCompareValueGet()); +} +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/cpu/simplelink/rtimer-arch.h b/arch/cpu/simplelink/rtimer-arch.h index aa1682ec4..2b9394c1d 100644 --- a/arch/cpu/simplelink/rtimer-arch.h +++ b/arch/cpu/simplelink/rtimer-arch.h @@ -47,7 +47,7 @@ /*---------------------------------------------------------------------------*/ #include "contiki.h" /*---------------------------------------------------------------------------*/ -inline rtimer_clock_t rtimer_arch_now(void) { rtimer_clock_t rtc = { 0 }; return rtc; } +extern rtimer_clock_t rtimer_arch_now(void); /* HW oscillator frequency is 32 kHz, not 64 kHz and RTIMER_NOW() never returns * an odd value; so US_TO_RTIMERTICKS always rounds to the nearest even number. From c7aaefb4daa03a48ffff73cc26cfbab16acdff6e Mon Sep 17 00:00:00 2001 From: Richard Weickelt Date: Tue, 6 Feb 2018 14:30:50 +0100 Subject: [PATCH 217/485] Add board file deduction logic and board init stages --- arch/cpu/simplelink/Makefile.simplelink | 12 +++++++++--- arch/platform/simplelink/Makefile.simplelink | 11 +++++++++++ arch/platform/simplelink/platform.c | 16 ++++++++++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/arch/cpu/simplelink/Makefile.simplelink b/arch/cpu/simplelink/Makefile.simplelink index bda65826d..b5b9084d2 100644 --- a/arch/cpu/simplelink/Makefile.simplelink +++ b/arch/cpu/simplelink/Makefile.simplelink @@ -9,12 +9,15 @@ SDK_DEVICE_SOURCE := $(SDK_SOURCE)/ti/devices/$(SDK_DEVICE) SDK_DRIVERLIB := $(SDK_DEVICE_SOURCE)/driverlib SDK_DRIVERS := $(SDK_SOURCE)/ti/drivers SDK_KERNEL := $(SIMPLELINK_SDK)/kernel/nortos/ -SDK_BOARDS := $(SDK_SOURCE)/ti/boards SDK_STARTUP := $(SDK_DEVICE_SOURCE)/startup_files SDK_STARTUP_SRCS = ccfg.c startup_gcc.c - EXTERNALDIRS += $(SDK_STARTUP) +ifneq ($(SIMPLELINK_BOARD),CUSTOM) + SDK_BOARDS := $(SDK_SOURCE)/ti/boards + LDSCRIPT = $(SDK_BOARDS)/$(SIMPLELINK_BOARD)/$(SIMPLELINK_BOARD)_NoRTOS.lds +endif + ### MODULES will add some of these to the include path, but we need to add ### them earlier to prevent filename clashes with Contiki core files CFLAGS += -I$(CPU_ABS_PATH) @@ -24,7 +27,10 @@ CFLAGS += -I$(SDK_DEVICE_SOURCE)/inc CFLAGS += -I$(SDK_KERNEL) CFLAGS += -I$(SDK_KERNEL)/posix -LDSCRIPT = $(SDK_BOARDS)/$(SIMPLELINK_BOARD)/$(SIMPLELINK_BOARD)_NoRTOS.lds +ifneq ($(SIMPLELINK_BOARD),CUSTOM) + CFLAGS += -I$(SDK_BOARDS)/$(SIMPLELINK_BOARD) +endif + ### If the user-specified a Node ID, pass a define ifdef NODEID diff --git a/arch/platform/simplelink/Makefile.simplelink b/arch/platform/simplelink/Makefile.simplelink index 2a28cd231..bed4c64a5 100644 --- a/arch/platform/simplelink/Makefile.simplelink +++ b/arch/platform/simplelink/Makefile.simplelink @@ -8,6 +8,17 @@ ifndef SIMPLELINK_SDK $(error SIMPLELINK_SDK not defined! You must specify where the SimpleLink SDK resides!) endif +AVAILABLE_BOARDS := $(shell ls $(SIMPLELINK_SDK)/source/ti/boards/) +AVAILABLE_BOARDS += CUSTOM # Allows an own board file in the application project + +ifndef SIMPLELINK_BOARD + $(error SIMPLELINK_BOARD not defined! You must specify a board! Available boards: $(AVAILABLE_BOARDS)) +endif + +ifneq ($(findstring $(SIMPLELINK_BOARD),$(AVAILABLE_BOARDS)),$(SIMPLELINK_BOARD)) + $(error '$(SIMPLELINK_BOARD)' is not a valid board. Available boards: $(AVAILABLE_BOARDS)) +endif + ### Board and BSP selection CONTIKI_TARGET_DIRS += . diff --git a/arch/platform/simplelink/platform.c b/arch/platform/simplelink/platform.c index 0691f669c..8f047463a 100644 --- a/arch/platform/simplelink/platform.c +++ b/arch/platform/simplelink/platform.c @@ -46,6 +46,12 @@ */ #include "contiki.h" #include "contiki-net.h" + +#include +#include +#include + + //#include "leds.h" //#include "lpm.h" //#include "gpio-interrupt.h" @@ -123,6 +129,10 @@ void board_init(void); void platform_init_stage_one() { + Board_initGeneral(); + GPIO_init(); + GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_ON); + GPIO_write(Board_GPIO_LED1, Board_GPIO_LED_OFF); // /* Enable flash cache and prefetch. */ // ti_lib_vims_mode_set(VIMS_BASE, VIMS_MODE_ENABLED); // ti_lib_vims_configure(VIMS_BASE, true, true); @@ -158,6 +168,9 @@ platform_init_stage_one() void platform_init_stage_two() { + GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_OFF); + GPIO_write(Board_GPIO_LED1, Board_GPIO_LED_ON); + // random_init(0x1234); // // /* Character I/O Initialisation */ @@ -176,6 +189,9 @@ platform_init_stage_two() void platform_init_stage_three() { + GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_ON); + GPIO_write(Board_GPIO_LED1, Board_GPIO_LED_ON); + // radio_value_t chan, pan; // // set_rf_params(); From 12c9056cec76e84bcd880376ebc14801a60ea1e9 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Tue, 6 Feb 2018 15:18:07 +0100 Subject: [PATCH 218/485] Cleaned up CCFG configuration, and aligned CC13x0_cc26x0 and CC13x2_CC26x2 CPU conf --- arch/cpu/simplelink/Makefile.simplelink | 5 +- .../cc26x0_cc13x0/cc13x0-cc26x0-def.h | 104 +++++++++ ...c13x0-cc26x0-cm4.h => cc13x2-cc26x2-cm4.h} | 0 .../cc26x2_cc13x2}/cc13x2-cc26x2-def.h | 2 +- .../simplelink/cc26x2_cc13x2/simplelink-def.h | 2 +- arch/cpu/simplelink/ccfg-conf.h | 76 +++++++ arch/cpu/simplelink/rtimer-arch.c | 22 +- arch/cpu/simplelink/simplelink-conf.h | 192 ++++++++++++++--- arch/platform/simplelink/cc13x2-cc26x2-conf.h | 204 ------------------ 9 files changed, 359 insertions(+), 248 deletions(-) create mode 100644 arch/cpu/simplelink/cc26x0_cc13x0/cc13x0-cc26x0-def.h rename arch/cpu/simplelink/cc26x2_cc13x2/{cc13x0-cc26x0-cm4.h => cc13x2-cc26x2-cm4.h} (100%) rename arch/{platform/simplelink => cpu/simplelink/cc26x2_cc13x2}/cc13x2-cc26x2-def.h (98%) create mode 100644 arch/cpu/simplelink/ccfg-conf.h delete mode 100644 arch/platform/simplelink/cc13x2-cc26x2-conf.h diff --git a/arch/cpu/simplelink/Makefile.simplelink b/arch/cpu/simplelink/Makefile.simplelink index b5b9084d2..14b8efb59 100644 --- a/arch/cpu/simplelink/Makefile.simplelink +++ b/arch/cpu/simplelink/Makefile.simplelink @@ -8,7 +8,8 @@ SDK_DEVICE := $(shell ls $(SDK_DEVICES) | grep $(SIMPLELINK_DEVICE)) SDK_DEVICE_SOURCE := $(SDK_SOURCE)/ti/devices/$(SDK_DEVICE) SDK_DRIVERLIB := $(SDK_DEVICE_SOURCE)/driverlib SDK_DRIVERS := $(SDK_SOURCE)/ti/drivers -SDK_KERNEL := $(SIMPLELINK_SDK)/kernel/nortos/ +SDK_KERNEL := $(SIMPLELINK_SDK)/kernel/nortos +SDK_BOARDS := $(SDK_SOURCE)/ti/boards SDK_STARTUP := $(SDK_DEVICE_SOURCE)/startup_files SDK_STARTUP_SRCS = ccfg.c startup_gcc.c EXTERNALDIRS += $(SDK_STARTUP) @@ -67,7 +68,7 @@ $(OBJECTDIR)/ieee-addr.o: ieee-addr.c FORCE | $(OBJECTDIR) ### to make clean first $(OBJECTDIR)/ccfg.o: ccfg.c FORCE | $(OBJECTDIR) $(TRACE_CC) - $(Q)$(CC) $(CFLAGS) -include "simplelink-conf.h" -c $< -o $@ + $(Q)$(CC) $(CFLAGS) -include "ccfg-conf.h" -c $< -o $@ RAM_SIZE = 0x00003E00 FLASH_SIZE = 0x0001E000 diff --git a/arch/cpu/simplelink/cc26x0_cc13x0/cc13x0-cc26x0-def.h b/arch/cpu/simplelink/cc26x0_cc13x0/cc13x0-cc26x0-def.h new file mode 100644 index 000000000..5a1d855eb --- /dev/null +++ b/arch/cpu/simplelink/cc26x0_cc13x0/cc13x0-cc26x0-def.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2017, 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 CC13XX_CC26XX_DEF_H_ +#define CC13XX_CC26XX_DEF_H_ +/*---------------------------------------------------------------------------*/ +#include +/*---------------------------------------------------------------------------*/ +/* TSCH related defines */ + +/* Delay between GO signal and SFD */ +#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(81)) +/* Delay between GO signal and start listening. + * This value is so small because the radio is constantly on within each timeslot. */ +#define RADIO_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(15)) +/* Delay between the SFD finishes arriving and it is detected in software. */ +#define RADIO_DELAY_BEFORE_DETECT ((unsigned)US_TO_RTIMERTICKS(352)) + +/* Timer conversion; radio is running at 4 MHz */ +#define RADIO_TIMER_SECOND 4000000u +#if (RTIMER_SECOND % 256) || (RADIO_TIMER_SECOND % 256) +#error RADIO_TO_RTIMER macro must be fixed! +#endif +#define RADIO_TO_RTIMER(X) ((uint32_t)(((uint64_t)(X) * (RTIMER_SECOND / 256)) / (RADIO_TIMER_SECOND / 256))) +#define USEC_TO_RADIO(X) ((X) * 4) + +/* The PHY header (preamble + SFD, 4+1 bytes) duration is equivalent to 10 symbols */ +#define RADIO_IEEE_802154_PHY_HEADER_DURATION_USEC 160 + +/* Do not turn off TSCH within a timeslot: not enough time */ +#define TSCH_CONF_RADIO_ON_DURING_TIMESLOT 1 + +/* Disable TSCH frame filtering */ +#define TSCH_CONF_HW_FRAME_FILTERING 0 + +/* Use hardware timestamps */ +#ifndef TSCH_CONF_RESYNC_WITH_SFD_TIMESTAMPS +#define TSCH_CONF_RESYNC_WITH_SFD_TIMESTAMPS 1 +#define TSCH_CONF_TIMESYNC_REMOVE_JITTER 0 +#endif + +#ifndef TSCH_CONF_BASE_DRIFT_PPM +/* The drift compared to "true" 10ms slots. + * Enable adaptive sync to enable compensation for this. + * Slot length 10000 usec + * 328 ticks + * Tick duration 30.517578125 usec + * Real slot duration 10009.765625 usec + * Target - real duration = -9.765625 usec + * TSCH_CONF_BASE_DRIFT_PPM -977 + */ +#define TSCH_CONF_BASE_DRIFT_PPM -977 +#endif + +/* 10 times per second */ +#ifndef TSCH_CONF_CHANNEL_SCAN_DURATION +#define TSCH_CONF_CHANNEL_SCAN_DURATION (CLOCK_SECOND / 10) +#endif + +/* Slightly reduce the TSCH guard time (from 2200 usec to 1800 usec) to make sure + * the CC26xx radio has sufficient time to start up. */ +#ifndef TSCH_CONF_RX_WAIT +#define TSCH_CONF_RX_WAIT 1800 +#endif +/*---------------------------------------------------------------------------*/ +#define RTIMER_ARCH_SECOND 65536 +/*---------------------------------------------------------------------------*/ +/* Path to CMSIS header */ +#define CMSIS_CONF_HEADER_PATH "cc13x2-cc26x2-cm4.h" + +/* Path to headers with implementation of mutexes and memory barriers */ +#define MUTEX_CONF_ARCH_HEADER_PATH "mutex-cortex.h" +#define MEMORY_BARRIER_CONF_ARCH_HEADER_PATH "memory-barrier-cortex.h" +/*---------------------------------------------------------------------------*/ +#endif /* CC13XX_CC26XX_DEF_H_ */ +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/simplelink/cc26x2_cc13x2/cc13x0-cc26x0-cm4.h b/arch/cpu/simplelink/cc26x2_cc13x2/cc13x2-cc26x2-cm4.h similarity index 100% rename from arch/cpu/simplelink/cc26x2_cc13x2/cc13x0-cc26x0-cm4.h rename to arch/cpu/simplelink/cc26x2_cc13x2/cc13x2-cc26x2-cm4.h diff --git a/arch/platform/simplelink/cc13x2-cc26x2-def.h b/arch/cpu/simplelink/cc26x2_cc13x2/cc13x2-cc26x2-def.h similarity index 98% rename from arch/platform/simplelink/cc13x2-cc26x2-def.h rename to arch/cpu/simplelink/cc26x2_cc13x2/cc13x2-cc26x2-def.h index 359c6f051..5a1d855eb 100644 --- a/arch/platform/simplelink/cc13x2-cc26x2-def.h +++ b/arch/cpu/simplelink/cc26x2_cc13x2/cc13x2-cc26x2-def.h @@ -94,7 +94,7 @@ #define RTIMER_ARCH_SECOND 65536 /*---------------------------------------------------------------------------*/ /* Path to CMSIS header */ -//#define CMSIS_CONF_HEADER_PATH "cc13x0-cc26x0-cm3.h" +#define CMSIS_CONF_HEADER_PATH "cc13x2-cc26x2-cm4.h" /* Path to headers with implementation of mutexes and memory barriers */ #define MUTEX_CONF_ARCH_HEADER_PATH "mutex-cortex.h" diff --git a/arch/cpu/simplelink/cc26x2_cc13x2/simplelink-def.h b/arch/cpu/simplelink/cc26x2_cc13x2/simplelink-def.h index d0e95a261..ada97c4b5 100644 --- a/arch/cpu/simplelink/cc26x2_cc13x2/simplelink-def.h +++ b/arch/cpu/simplelink/cc26x2_cc13x2/simplelink-def.h @@ -94,7 +94,7 @@ #define RTIMER_ARCH_SECOND 65536 /*---------------------------------------------------------------------------*/ /* Path to CMSIS header */ -#define CMSIS_CONF_HEADER_PATH "cc13x0-cc26x0-cm4.h" +#define CMSIS_CONF_HEADER_PATH "cc13x2-cc26x2-cm4.h" /* Path to headers with implementation of mutexes and memory barriers */ #define MUTEX_CONF_ARCH_HEADER_PATH "mutex-cortex.h" diff --git a/arch/cpu/simplelink/ccfg-conf.h b/arch/cpu/simplelink/ccfg-conf.h new file mode 100644 index 000000000..97be16b5d --- /dev/null +++ b/arch/cpu/simplelink/ccfg-conf.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2017, Alex Stanoev + * 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. + */ +/** + * \addtogroup cc26xx + * @{ + * + * \defgroup cc26xx-ccxxware-conf CCxxware-specific configuration + * + * @{ + * + * \file + * CCxxware-specific configuration for the cc26xx-cc13xx CPU family + */ +#ifndef CCXXWARE_CONF_H_ +#define CCXXWARE_CONF_H_ + +#include "contiki-conf.h" + +/*---------------------------------------------------------------------------*/ +/** + * \brief JTAG interface configuration + * + * Those values are not meant to be modified by the user + * @{ + */ +#if CCXXWARE_CONF_JTAG_INTERFACE_ENABLE +#define SET_CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE 0xC5 +#define SET_CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE 0xC5 +#define SET_CCFG_CCFG_TAP_DAP_0_PRCM_TAP_ENABLE 0xC5 +#define SET_CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE 0xC5 +#define SET_CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE 0xC5 +#define SET_CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE 0xC5 +#define SET_CCFG_CCFG_TAP_DAP_1_WUC_TAP_ENABLE 0xC5 +#else +#define SET_CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE 0x00 +#define SET_CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE 0x00 +#define SET_CCFG_CCFG_TAP_DAP_0_PRCM_TAP_ENABLE 0x00 +#define SET_CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE 0x00 +#define SET_CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE 0x00 +#define SET_CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE 0x00 +#define SET_CCFG_CCFG_TAP_DAP_1_WUC_TAP_ENABLE 0x00 +#endif +/** @} */ +#endif /* CCXXWARE_CONF_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/cpu/simplelink/rtimer-arch.c b/arch/cpu/simplelink/rtimer-arch.c index f9f1fbf7a..88d01c902 100644 --- a/arch/cpu/simplelink/rtimer-arch.c +++ b/arch/cpu/simplelink/rtimer-arch.c @@ -37,7 +37,8 @@ */ /*---------------------------------------------------------------------------*/ #include -#include + +#include #include #include @@ -53,10 +54,17 @@ static ClockP_Handle hClk; typedef void (*IsrFxn)(void); typedef void (*HwiDispatchFxn)(void); -static HwiDispatchFxn hwiDispatch = NULL; +static volatile HwiDispatchFxn hwiDispatch = NULL; +/*---------------------------------------------------------------------------*/ +/** + * \brief TODO + */ static void rtimer_clock_stub(uintptr_t arg) { /* do nothing */ } - +/*---------------------------------------------------------------------------*/ +/** + * \brief TODO + */ static void rtimer_isr_hook(void) { @@ -76,7 +84,6 @@ rtimer_isr_hook(void) IntPendClear(INT_AON_RTC_COMB); } } - /*---------------------------------------------------------------------------*/ /** * \brief TODO @@ -90,10 +97,10 @@ rtimer_arch_init(void) hClk = ClockP_construct(&gClk, rtimer_clock_stub, 0, &clkParams); // Try to access the RAM vector table - IsrFxn *pfnRAMVectors = (IsrFxn *)(HWREG(NVIC_VTABLE)); + volatile IsrFxn * const pfnRAMVectors = (IsrFxn *)(HWREG(NVIC_VTABLE)); if (!pfnRAMVectors) { - while (0) {} + while (0) { /* hang */ } } // The HWI Dispatch ISR should be located at int num INT_AON_RTC_COMB. @@ -101,7 +108,7 @@ rtimer_arch_init(void) hwiDispatch = (HwiDispatchFxn)pfnRAMVectors[INT_AON_RTC_COMB]; if (!hwiDispatch) { - while (0) {} + while (0) { /* hang */ } } // Override the INT_AON_RTC_COMB int num with own ISR hook @@ -109,7 +116,6 @@ rtimer_arch_init(void) AONEventMcuWakeUpSet(AON_EVENT_MCU_WU1, AON_EVENT_RTC_CH1); AONRTCCombinedEventConfig(AON_RTC_CH0 | RTIMER_RTC_CH); - return; } /*---------------------------------------------------------------------------*/ /** diff --git a/arch/cpu/simplelink/simplelink-conf.h b/arch/cpu/simplelink/simplelink-conf.h index 97be16b5d..6ecdafa6b 100644 --- a/arch/cpu/simplelink/simplelink-conf.h +++ b/arch/cpu/simplelink/simplelink-conf.h @@ -1,10 +1,11 @@ /* - * Copyright (c) 2017, Alex Stanoev + * Copyright (c) 2017, 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 @@ -27,50 +28,177 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ +/*---------------------------------------------------------------------------*/ /** * \addtogroup cc26xx * @{ * - * \defgroup cc26xx-ccxxware-conf CCxxware-specific configuration - * - * @{ - * * \file - * CCxxware-specific configuration for the cc26xx-cc13xx CPU family + * Header with configuration defines common to all CC13xx/CC26xx platforms */ -#ifndef CCXXWARE_CONF_H_ -#define CCXXWARE_CONF_H_ - -#include "contiki-conf.h" - +/*---------------------------------------------------------------------------*/ +#ifndef CC13XX_CC26XX_CONF_H_ +#define CC13XX_CC26XX_CONF_H_ /*---------------------------------------------------------------------------*/ /** - * \brief JTAG interface configuration + * \name Network Stack Configuration * - * Those values are not meant to be modified by the user * @{ */ -#if CCXXWARE_CONF_JTAG_INTERFACE_ENABLE -#define SET_CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE 0xC5 -#define SET_CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE 0xC5 -#define SET_CCFG_CCFG_TAP_DAP_0_PRCM_TAP_ENABLE 0xC5 -#define SET_CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE 0xC5 -#define SET_CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE 0xC5 -#define SET_CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE 0xC5 -#define SET_CCFG_CCFG_TAP_DAP_1_WUC_TAP_ENABLE 0xC5 -#else -#define SET_CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE 0x00 -#define SET_CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE 0x00 -#define SET_CCFG_CCFG_TAP_DAP_0_PRCM_TAP_ENABLE 0x00 -#define SET_CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE 0x00 -#define SET_CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE 0x00 -#define SET_CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE 0x00 -#define SET_CCFG_CCFG_TAP_DAP_1_WUC_TAP_ENABLE 0x00 + +/* + * If set, the systems keeps the HF crystal oscillator on even when the radio is off. + * You need to set this to 1 to use TSCH with its default 2.2ms or larger guard time. + */ +#ifndef CC2650_FAST_RADIO_STARTUP +#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 +#endif + +/* + * Auto-configure Prop-mode radio if we are running on CC13xx, unless the + * project has specified otherwise. Depending on the final mode, determine a + * default channel (again, if unspecified) and configure RDC params + */ +#if CPU_FAMILY_CC13XX +#ifndef CC13XX_CONF_PROP_MODE +#define CC13XX_CONF_PROP_MODE 1 +#endif /* CC13XX_CONF_PROP_MODE */ +#endif /* CPU_FAMILY_CC13XX */ + +#if CC13XX_CONF_PROP_MODE +#define NETSTACK_CONF_RADIO prop_mode_driver + +#ifndef RF_CORE_CONF_CHANNEL +#define RF_CORE_CONF_CHANNEL 0 +#endif + +#define CSMA_CONF_ACK_WAIT_TIME (RTIMER_SECOND / 400) +#define CSMA_CONF_AFTER_ACK_DETECTED_WAIT_TIME (RTIMER_SECOND / 1000) +#define CSMA_CONF_SEND_SOFT_ACK 1 + +#else /* CC13XX_CONF_PROP_MODE */ +#define NETSTACK_CONF_RADIO ieee_mode_driver + +#define CSMA_CONF_SEND_SOFT_ACK 0 +#endif /* CC13XX_CONF_PROP_MODE */ + +#define NETSTACK_RADIO_MAX_PAYLOAD_LEN 125 + +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \name IEEE address configuration + * + * Used to generate our link-local & IPv6 address + * @{ + */ +/** + * \brief Location of the IEEE address + * 0 => Read from InfoPage, + * 1 => Use a hardcoded address, configured by IEEE_ADDR_CONF_ADDRESS + */ +#ifndef IEEE_ADDR_CONF_HARDCODED +#define IEEE_ADDR_CONF_HARDCODED 0 +#endif + +/** + * \brief The hardcoded IEEE address to be used when IEEE_ADDR_CONF_HARDCODED + * is defined as 1 + */ +#ifndef IEEE_ADDR_CONF_ADDRESS +#define IEEE_ADDR_CONF_ADDRESS { 0x00, 0x12, 0x4B, 0x00, 0x89, 0xAB, 0xCD, 0xEF } #endif /** @} */ -#endif /* CCXXWARE_CONF_H_ */ /*---------------------------------------------------------------------------*/ /** - * @} - * @} + * \name RF configuration + * + * @{ */ +/* RF Config */ + +#ifndef IEEE_MODE_CONF_AUTOACK +#define IEEE_MODE_CONF_AUTOACK 1 /**< RF H/W generates ACKs */ +#endif + +#ifndef IEEE_MODE_CONF_PROMISCOUS +#define IEEE_MODE_CONF_PROMISCOUS 0 /**< 1 to enable promiscous mode */ +#endif + +#ifndef RF_BLE_CONF_ENABLED +#define RF_BLE_CONF_ENABLED 0 /**< 0 to disable BLE support */ +#endif +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \name Character I/O Configuration + * + * @{ + */ +#ifndef CC26XX_UART_CONF_ENABLE +#define CC26XX_UART_CONF_ENABLE 1 /**< Enable/Disable UART I/O */ +#endif + +#ifndef CC26XX_UART_CONF_BAUD_RATE +#define CC26XX_UART_CONF_BAUD_RATE 115200 /**< Default UART0 baud rate */ +#endif + +/* Enable I/O over the Debugger Devpack - Only relevant for the SensorTag */ +#ifndef BOARD_CONF_DEBUGGER_DEVPACK +#define BOARD_CONF_DEBUGGER_DEVPACK 1 +#endif + +#ifndef SLIP_ARCH_CONF_ENABLED +/* + * Determine whether we need SLIP + * This will keep working while UIP_FALLBACK_INTERFACE and CMD_CONF_OUTPUT + * keep using SLIP + */ +#if defined(UIP_FALLBACK_INTERFACE) || defined(CMD_CONF_OUTPUT) +#define SLIP_ARCH_CONF_ENABLED 1 +#endif +#endif +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \name JTAG interface configuration + * + * Enable/Disable the JTAG DAP and TAP interfaces on the chip. + * Setting this to 0 will disable access to the debug interface + * to secure deployed images. + * @{ + */ +#ifndef CCXXWARE_CONF_JTAG_INTERFACE_ENABLE +#define CCXXWARE_CONF_JTAG_INTERFACE_ENABLE 1 +#endif +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \name ROM Bootloader configuration + * + * Enable/Disable the ROM bootloader in your image, if the board supports it. + * Look in board.h to choose the DIO and corresponding level that will cause + * the chip to enter bootloader mode. + * @{ + */ +#ifndef ROM_BOOTLOADER_ENABLE +#define ROM_BOOTLOADER_ENABLE 0 +#endif +/** @} */ +/*---------------------------------------------------------------------------*/ +#endif /* CC13XX_CC26XX_CONF_H_ */ +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13x2-cc26x2-conf.h b/arch/platform/simplelink/cc13x2-cc26x2-conf.h deleted file mode 100644 index 6ecdafa6b..000000000 --- a/arch/platform/simplelink/cc13x2-cc26x2-conf.h +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (c) 2017, 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. - */ -/*---------------------------------------------------------------------------*/ -/** - * \addtogroup cc26xx - * @{ - * - * \file - * Header with configuration defines common to all CC13xx/CC26xx platforms - */ -/*---------------------------------------------------------------------------*/ -#ifndef CC13XX_CC26XX_CONF_H_ -#define CC13XX_CC26XX_CONF_H_ -/*---------------------------------------------------------------------------*/ -/** - * \name Network Stack Configuration - * - * @{ - */ - -/* - * If set, the systems keeps the HF crystal oscillator on even when the radio is off. - * You need to set this to 1 to use TSCH with its default 2.2ms or larger guard time. - */ -#ifndef CC2650_FAST_RADIO_STARTUP -#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 -#endif - -/* - * Auto-configure Prop-mode radio if we are running on CC13xx, unless the - * project has specified otherwise. Depending on the final mode, determine a - * default channel (again, if unspecified) and configure RDC params - */ -#if CPU_FAMILY_CC13XX -#ifndef CC13XX_CONF_PROP_MODE -#define CC13XX_CONF_PROP_MODE 1 -#endif /* CC13XX_CONF_PROP_MODE */ -#endif /* CPU_FAMILY_CC13XX */ - -#if CC13XX_CONF_PROP_MODE -#define NETSTACK_CONF_RADIO prop_mode_driver - -#ifndef RF_CORE_CONF_CHANNEL -#define RF_CORE_CONF_CHANNEL 0 -#endif - -#define CSMA_CONF_ACK_WAIT_TIME (RTIMER_SECOND / 400) -#define CSMA_CONF_AFTER_ACK_DETECTED_WAIT_TIME (RTIMER_SECOND / 1000) -#define CSMA_CONF_SEND_SOFT_ACK 1 - -#else /* CC13XX_CONF_PROP_MODE */ -#define NETSTACK_CONF_RADIO ieee_mode_driver - -#define CSMA_CONF_SEND_SOFT_ACK 0 -#endif /* CC13XX_CONF_PROP_MODE */ - -#define NETSTACK_RADIO_MAX_PAYLOAD_LEN 125 - -/** @} */ -/*---------------------------------------------------------------------------*/ -/** - * \name IEEE address configuration - * - * Used to generate our link-local & IPv6 address - * @{ - */ -/** - * \brief Location of the IEEE address - * 0 => Read from InfoPage, - * 1 => Use a hardcoded address, configured by IEEE_ADDR_CONF_ADDRESS - */ -#ifndef IEEE_ADDR_CONF_HARDCODED -#define IEEE_ADDR_CONF_HARDCODED 0 -#endif - -/** - * \brief The hardcoded IEEE address to be used when IEEE_ADDR_CONF_HARDCODED - * is defined as 1 - */ -#ifndef IEEE_ADDR_CONF_ADDRESS -#define IEEE_ADDR_CONF_ADDRESS { 0x00, 0x12, 0x4B, 0x00, 0x89, 0xAB, 0xCD, 0xEF } -#endif -/** @} */ -/*---------------------------------------------------------------------------*/ -/** - * \name RF configuration - * - * @{ - */ -/* RF Config */ - -#ifndef IEEE_MODE_CONF_AUTOACK -#define IEEE_MODE_CONF_AUTOACK 1 /**< RF H/W generates ACKs */ -#endif - -#ifndef IEEE_MODE_CONF_PROMISCOUS -#define IEEE_MODE_CONF_PROMISCOUS 0 /**< 1 to enable promiscous mode */ -#endif - -#ifndef RF_BLE_CONF_ENABLED -#define RF_BLE_CONF_ENABLED 0 /**< 0 to disable BLE support */ -#endif -/** @} */ -/*---------------------------------------------------------------------------*/ -/** - * \name Character I/O Configuration - * - * @{ - */ -#ifndef CC26XX_UART_CONF_ENABLE -#define CC26XX_UART_CONF_ENABLE 1 /**< Enable/Disable UART I/O */ -#endif - -#ifndef CC26XX_UART_CONF_BAUD_RATE -#define CC26XX_UART_CONF_BAUD_RATE 115200 /**< Default UART0 baud rate */ -#endif - -/* Enable I/O over the Debugger Devpack - Only relevant for the SensorTag */ -#ifndef BOARD_CONF_DEBUGGER_DEVPACK -#define BOARD_CONF_DEBUGGER_DEVPACK 1 -#endif - -#ifndef SLIP_ARCH_CONF_ENABLED -/* - * Determine whether we need SLIP - * This will keep working while UIP_FALLBACK_INTERFACE and CMD_CONF_OUTPUT - * keep using SLIP - */ -#if defined(UIP_FALLBACK_INTERFACE) || defined(CMD_CONF_OUTPUT) -#define SLIP_ARCH_CONF_ENABLED 1 -#endif -#endif -/** @} */ -/*---------------------------------------------------------------------------*/ -/** - * \name JTAG interface configuration - * - * Enable/Disable the JTAG DAP and TAP interfaces on the chip. - * Setting this to 0 will disable access to the debug interface - * to secure deployed images. - * @{ - */ -#ifndef CCXXWARE_CONF_JTAG_INTERFACE_ENABLE -#define CCXXWARE_CONF_JTAG_INTERFACE_ENABLE 1 -#endif -/** @} */ -/*---------------------------------------------------------------------------*/ -/** - * \name ROM Bootloader configuration - * - * Enable/Disable the ROM bootloader in your image, if the board supports it. - * Look in board.h to choose the DIO and corresponding level that will cause - * the chip to enter bootloader mode. - * @{ - */ -#ifndef ROM_BOOTLOADER_ENABLE -#define ROM_BOOTLOADER_ENABLE 0 -#endif -/** @} */ -/*---------------------------------------------------------------------------*/ -#endif /* CC13XX_CC26XX_CONF_H_ */ -/*---------------------------------------------------------------------------*/ -/** @} */ From a40e5bc31474b9ce395cb097f7343da548c5b504 Mon Sep 17 00:00:00 2001 From: Richard Weickelt Date: Tue, 6 Feb 2018 16:22:02 +0100 Subject: [PATCH 219/485] Build the board file and add all libraries from the SDK --- arch/cpu/arm/cortex-m/cm4/Makefile.cm4 | 7 +++++-- arch/cpu/simplelink/Makefile.cc26x2_cc13x2 | 5 +++-- arch/cpu/simplelink/Makefile.simplelink | 19 ++++++++++++++----- arch/platform/simplelink/Makefile.simplelink | 2 +- arch/platform/simplelink/platform.c | 3 +++ 5 files changed, 26 insertions(+), 10 deletions(-) diff --git a/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 b/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 index 02e9e5648..2cfbe4592 100644 --- a/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 +++ b/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 @@ -7,6 +7,9 @@ LDFLAGS += -T $(LDSCRIPT) LDFLAGS += -Wl,--gc-sections,--sort-section=alignment LDFLAGS += -Wl,-Map=$(@:.elf=-$(TARGET).map),--cref,--no-warn-mismatch +TARGET_LIBFLAGS := ${addprefix -l:,$(TARGET_LIBFILES)} +TARGET_LIBFLAGS += -gcc -lm -lnosys -lc + OBJCOPY_FLAGS += --gap-fill 0xff ### Build syscalls for newlib @@ -19,8 +22,8 @@ CUSTOM_RULE_LINK = 1 .SECONDEXPANSION: -%.elf: $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(TARGET_LIBS) $(CONTIKI_NG_TARGET_LIB) +%.elf: $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(TRACE_LD) - $(Q)$(LD) $(LDFLAGS) ${filter %.o %.a,$^} $(TARGET_LIBS) -o $@ + $(Q)$(LD) $(LDFLAGS) ${filter %.o %.a,$^} -Wl,--start-group $(TARGET_LIBFLAGS) -Wl,--end-group -o $@ include $(CONTIKI)/arch/cpu/arm/cortex-m/Makefile.cortex-m diff --git a/arch/cpu/simplelink/Makefile.cc26x2_cc13x2 b/arch/cpu/simplelink/Makefile.cc26x2_cc13x2 index a0a91679f..d4555ff51 100644 --- a/arch/cpu/simplelink/Makefile.cc26x2_cc13x2 +++ b/arch/cpu/simplelink/Makefile.cc26x2_cc13x2 @@ -8,10 +8,11 @@ endif CFLAGS += -I$(CPU_ABS_PATH)/cc26x2_cc13x2 CFLAGS += -I$(SDK_KERNEL) -TARGET_LIBFILES += $(SDK_DRIVERLIB)/bin/gcc/driverlib.lib +TARGET_LIBFILES += $(SDK_DRIVERS)/rf/lib/rf_multiMode_cc13x2.am4fg TARGET_LIBFILES += $(SDK_DRIVERS)/lib/drivers_cc13x2.am4fg -TARGET_LIBFILES += $(SDK_DRIVERS)/lib/rf_multiMode_cc13x2.am4fg TARGET_LIBFILES += $(SDK_KERNEL)/lib/nortos_cc13x2.am4fg +TARGET_LIBFILES += $(SDK_DRIVERLIB)/bin/gcc/driverlib.lib + include $(CONTIKI)/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 diff --git a/arch/cpu/simplelink/Makefile.simplelink b/arch/cpu/simplelink/Makefile.simplelink index 14b8efb59..3e83c74b3 100644 --- a/arch/cpu/simplelink/Makefile.simplelink +++ b/arch/cpu/simplelink/Makefile.simplelink @@ -11,13 +11,9 @@ SDK_DRIVERS := $(SDK_SOURCE)/ti/drivers SDK_KERNEL := $(SIMPLELINK_SDK)/kernel/nortos SDK_BOARDS := $(SDK_SOURCE)/ti/boards SDK_STARTUP := $(SDK_DEVICE_SOURCE)/startup_files -SDK_STARTUP_SRCS = ccfg.c startup_gcc.c +SDK_STARTUP_SRCS = ccfg.c EXTERNALDIRS += $(SDK_STARTUP) -ifneq ($(SIMPLELINK_BOARD),CUSTOM) - SDK_BOARDS := $(SDK_SOURCE)/ti/boards - LDSCRIPT = $(SDK_BOARDS)/$(SIMPLELINK_BOARD)/$(SIMPLELINK_BOARD)_NoRTOS.lds -endif ### MODULES will add some of these to the include path, but we need to add ### them earlier to prevent filename clashes with Contiki core files @@ -28,8 +24,17 @@ CFLAGS += -I$(SDK_DEVICE_SOURCE)/inc CFLAGS += -I$(SDK_KERNEL) CFLAGS += -I$(SDK_KERNEL)/posix +LDFLAGS += --entry resetISR +LDFLAGS += -static +LDFLAGS += --specs=nano.specs + +SDK_BOARDS := + ifneq ($(SIMPLELINK_BOARD),CUSTOM) + SDK_BOARDS := $(SDK_SOURCE)/ti/boards + LDSCRIPT = $(SDK_BOARDS)/$(SIMPLELINK_BOARD)/$(SIMPLELINK_BOARD)_NoRTOS.lds CFLAGS += -I$(SDK_BOARDS)/$(SIMPLELINK_BOARD) + CONTIKI_SOURCEFILES += $(SIMPLELINK_BOARD).c endif @@ -70,6 +75,10 @@ $(OBJECTDIR)/ccfg.o: ccfg.c FORCE | $(OBJECTDIR) $(TRACE_CC) $(Q)$(CC) $(CFLAGS) -include "ccfg-conf.h" -c $< -o $@ +$(OBJECTDIR)/$(SIMPLELINK_BOARD).o: $(SDK_SOURCE)/ti/boards/$(SIMPLELINK_BOARD)/$(SIMPLELINK_BOARD).c + $(TRACE_CC) + $(Q)$(CC) $(CFLAGS) -c $< -o $@ + RAM_SIZE = 0x00003E00 FLASH_SIZE = 0x0001E000 STACK_SIZE = 0 diff --git a/arch/platform/simplelink/Makefile.simplelink b/arch/platform/simplelink/Makefile.simplelink index bed4c64a5..1aa17a307 100644 --- a/arch/platform/simplelink/Makefile.simplelink +++ b/arch/platform/simplelink/Makefile.simplelink @@ -8,7 +8,7 @@ ifndef SIMPLELINK_SDK $(error SIMPLELINK_SDK not defined! You must specify where the SimpleLink SDK resides!) endif -AVAILABLE_BOARDS := $(shell ls $(SIMPLELINK_SDK)/source/ti/boards/) +AVAILABLE_BOARDS := $(shell ls $(SIMPLELINK_SDK)/source/ti/boards) AVAILABLE_BOARDS += CUSTOM # Allows an own board file in the application project ifndef SIMPLELINK_BOARD diff --git a/arch/platform/simplelink/platform.c b/arch/platform/simplelink/platform.c index 8f047463a..0a2fdba5c 100644 --- a/arch/platform/simplelink/platform.c +++ b/arch/platform/simplelink/platform.c @@ -50,6 +50,7 @@ #include #include #include +#include //#include "leds.h" @@ -131,6 +132,8 @@ platform_init_stage_one() { Board_initGeneral(); GPIO_init(); + NoRTOS_start(); + GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_ON); GPIO_write(Board_GPIO_LED1, Board_GPIO_LED_OFF); // /* Enable flash cache and prefetch. */ From 8cee2abae6628a680d24e82e56fa0f887a4dfa33 Mon Sep 17 00:00:00 2001 From: Richard Weickelt Date: Tue, 6 Feb 2018 16:27:31 +0100 Subject: [PATCH 220/485] List only directories --- arch/platform/simplelink/Makefile.simplelink | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/platform/simplelink/Makefile.simplelink b/arch/platform/simplelink/Makefile.simplelink index 1aa17a307..25f6c2471 100644 --- a/arch/platform/simplelink/Makefile.simplelink +++ b/arch/platform/simplelink/Makefile.simplelink @@ -8,7 +8,7 @@ ifndef SIMPLELINK_SDK $(error SIMPLELINK_SDK not defined! You must specify where the SimpleLink SDK resides!) endif -AVAILABLE_BOARDS := $(shell ls $(SIMPLELINK_SDK)/source/ti/boards) +AVAILABLE_BOARDS := $(shell ls -d $(SIMPLELINK_SDK)/source/ti/boards) AVAILABLE_BOARDS += CUSTOM # Allows an own board file in the application project ifndef SIMPLELINK_BOARD From f83579098baef84a8cbcd22fbaa95d1f6590f249 Mon Sep 17 00:00:00 2001 From: Richard Weickelt Date: Tue, 6 Feb 2018 16:41:15 +0100 Subject: [PATCH 221/485] Resolve remarks --- arch/cpu/simplelink/Makefile.simplelink | 6 +++++- arch/platform/simplelink/Makefile.simplelink | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/cpu/simplelink/Makefile.simplelink b/arch/cpu/simplelink/Makefile.simplelink index 3e83c74b3..8b2cba4ee 100644 --- a/arch/cpu/simplelink/Makefile.simplelink +++ b/arch/cpu/simplelink/Makefile.simplelink @@ -35,6 +35,10 @@ ifneq ($(SIMPLELINK_BOARD),CUSTOM) LDSCRIPT = $(SDK_BOARDS)/$(SIMPLELINK_BOARD)/$(SIMPLELINK_BOARD)_NoRTOS.lds CFLAGS += -I$(SDK_BOARDS)/$(SIMPLELINK_BOARD) CONTIKI_SOURCEFILES += $(SIMPLELINK_BOARD).c +else + ifndef $(LDSCRIPT) + $(error You must speficy a custom linker script in LDSCRIPT.) + endif endif @@ -75,7 +79,7 @@ $(OBJECTDIR)/ccfg.o: ccfg.c FORCE | $(OBJECTDIR) $(TRACE_CC) $(Q)$(CC) $(CFLAGS) -include "ccfg-conf.h" -c $< -o $@ -$(OBJECTDIR)/$(SIMPLELINK_BOARD).o: $(SDK_SOURCE)/ti/boards/$(SIMPLELINK_BOARD)/$(SIMPLELINK_BOARD).c +$(OBJECTDIR)/$(SIMPLELINK_BOARD).o: $(SDK_BOARDS)/$(SIMPLELINK_BOARD)/$(SIMPLELINK_BOARD).c $(TRACE_CC) $(Q)$(CC) $(CFLAGS) -c $< -o $@ diff --git a/arch/platform/simplelink/Makefile.simplelink b/arch/platform/simplelink/Makefile.simplelink index 25f6c2471..bed4c64a5 100644 --- a/arch/platform/simplelink/Makefile.simplelink +++ b/arch/platform/simplelink/Makefile.simplelink @@ -8,7 +8,7 @@ ifndef SIMPLELINK_SDK $(error SIMPLELINK_SDK not defined! You must specify where the SimpleLink SDK resides!) endif -AVAILABLE_BOARDS := $(shell ls -d $(SIMPLELINK_SDK)/source/ti/boards) +AVAILABLE_BOARDS := $(shell ls $(SIMPLELINK_SDK)/source/ti/boards/) AVAILABLE_BOARDS += CUSTOM # Allows an own board file in the application project ifndef SIMPLELINK_BOARD From 65ba0bb5a6253e05584413a8ba165d83977c378d Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Tue, 6 Feb 2018 16:46:25 +0100 Subject: [PATCH 222/485] Fixed remaking Makefiles, removed implicit %.o for %.elf, aligned defines, added volatile qualifier for RAM vector pointer --- Makefile.include | 17 ++++++++++++++++- arch/cpu/arm/cortex-m/cm3/Makefile.cm3 | 2 +- arch/cpu/arm/cortex-m/cm4/Makefile.cm4 | 2 +- arch/cpu/simplelink/Makefile.simplelink | 1 + arch/cpu/simplelink/rtimer-arch.c | 2 +- arch/cpu/simplelink/simplelink-conf.h | 6 +++--- 6 files changed, 23 insertions(+), 7 deletions(-) diff --git a/Makefile.include b/Makefile.include index 5be3ea932..5a35b301d 100644 --- a/Makefile.include +++ b/Makefile.include @@ -39,6 +39,12 @@ ifdef CI endif endif +# Prevent Make from remaking any makefiles. This was particularly an +# issue when you had a Makefile with a suffix equal to that of $(TARGET), +# as it managed to match with the %.$(TARGET) rule, which in turn fucked up +# everything. Now this isn't the case. +Makefile.%: ; + OBJECTDIR := obj_$(TARGET) LOWERCASE := -abcdefghijklmnopqrstuvwxyz/ @@ -321,7 +327,10 @@ distclean: $(MAKE) TARGET=$$TARG clean; \ done --include $(CONTIKI)/arch/platform/$(TARGET)/Makefile.customrules-$(TARGET) +custom_rules := $(CONTIKI)/arch/platform/$(TARGET)/Makefile.customrules-$(TARGET) +ifneq ("$(wildcard $(custom_rules))","") +-include $(custom_rules) +endif ifndef CUSTOM_RULE_C_TO_OBJECTDIR_O $(OBJECTDIR)/%.o: %.c | $(OBJECTDIR) @@ -383,6 +392,10 @@ ifndef LD LD = $(CC) endif +### Make sure Makefiles with the $(TARGET) suffix doesn't match +Makefile.$(TARGET): + @ + ifndef CUSTOM_RULE_LINK %.$(TARGET): %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(CONTIKI_NG_TARGET_LIB) $(TRACE_LD) @@ -478,6 +491,8 @@ endif # in fact the primary target. .PRECIOUS: %.$(TARGET) + + # Cancel the predefined implict rule for compiling and linking # a single C source into a binary to force GNU make to consider # the match-anything rule below instead. diff --git a/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 b/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 index f5e8d2a3c..934e233e6 100644 --- a/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 +++ b/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 @@ -19,7 +19,7 @@ CUSTOM_RULE_LINK = 1 .SECONDEXPANSION: -%.elf: $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(LDSCRIPT) +%.elf: $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(LDSCRIPT) $(TRACE_LD) $(Q)$(LD) $(LDFLAGS) ${filter-out $(LDSCRIPT) %.a,$^} ${filter %.a,$^} $(TARGET_LIBFILES) -lm -o $@ diff --git a/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 b/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 index 2cfbe4592..d26650417 100644 --- a/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 +++ b/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 @@ -22,7 +22,7 @@ CUSTOM_RULE_LINK = 1 .SECONDEXPANSION: -%.elf: $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) +%.elf: $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(TARGET_LIBS) $(TRACE_LD) $(Q)$(LD) $(LDFLAGS) ${filter %.o %.a,$^} -Wl,--start-group $(TARGET_LIBFLAGS) -Wl,--end-group -o $@ diff --git a/arch/cpu/simplelink/Makefile.simplelink b/arch/cpu/simplelink/Makefile.simplelink index 8b2cba4ee..f952b3c41 100644 --- a/arch/cpu/simplelink/Makefile.simplelink +++ b/arch/cpu/simplelink/Makefile.simplelink @@ -12,6 +12,7 @@ SDK_KERNEL := $(SIMPLELINK_SDK)/kernel/nortos SDK_BOARDS := $(SDK_SOURCE)/ti/boards SDK_STARTUP := $(SDK_DEVICE_SOURCE)/startup_files SDK_STARTUP_SRCS = ccfg.c + EXTERNALDIRS += $(SDK_STARTUP) diff --git a/arch/cpu/simplelink/rtimer-arch.c b/arch/cpu/simplelink/rtimer-arch.c index 88d01c902..f48cbe312 100644 --- a/arch/cpu/simplelink/rtimer-arch.c +++ b/arch/cpu/simplelink/rtimer-arch.c @@ -97,7 +97,7 @@ rtimer_arch_init(void) hClk = ClockP_construct(&gClk, rtimer_clock_stub, 0, &clkParams); // Try to access the RAM vector table - volatile IsrFxn * const pfnRAMVectors = (IsrFxn *)(HWREG(NVIC_VTABLE)); + volatile IsrFxn * const pfnRAMVectors = (volatile IsrFxn *)(HWREG(NVIC_VTABLE)); if (!pfnRAMVectors) { while (0) { /* hang */ } diff --git a/arch/cpu/simplelink/simplelink-conf.h b/arch/cpu/simplelink/simplelink-conf.h index 6ecdafa6b..1db50738f 100644 --- a/arch/cpu/simplelink/simplelink-conf.h +++ b/arch/cpu/simplelink/simplelink-conf.h @@ -37,8 +37,8 @@ * Header with configuration defines common to all CC13xx/CC26xx platforms */ /*---------------------------------------------------------------------------*/ -#ifndef CC13XX_CC26XX_CONF_H_ -#define CC13XX_CC26XX_CONF_H_ +#ifndef SIMPLELINK_CONF_H_ +#define SIMPLELINK_CONF_H_ /*---------------------------------------------------------------------------*/ /** * \name Network Stack Configuration @@ -199,6 +199,6 @@ #endif /** @} */ /*---------------------------------------------------------------------------*/ -#endif /* CC13XX_CC26XX_CONF_H_ */ +#endif /* SIMPLELINK_CONF_H_ */ /*---------------------------------------------------------------------------*/ /** @} */ From 765e35ba7f08e3e9973f9d96e861336d66b9c0a9 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Tue, 6 Feb 2018 18:05:51 +0100 Subject: [PATCH 223/485] Added working simplelink platform without netstack --- Makefile.include | 16 +- arch/cpu/arm/cortex-m/cm4/Makefile.cm4 | 3 +- arch/cpu/simplelink/Makefile.cc26x2_cc13x2 | 2 - arch/cpu/simplelink/Makefile.simplelink | 10 +- arch/cpu/simplelink/source/clock-arch.c | 218 ++++++++++++++++++ .../cpu/simplelink/{ => source}/rtimer-arch.c | 6 + .../cpu/simplelink/{ => source}/rtimer-arch.h | 0 arch/cpu/simplelink/source/watchdog-arch.c | 166 +++++++++++++ arch/platform/simplelink/platform.c | 46 ++-- 9 files changed, 425 insertions(+), 42 deletions(-) create mode 100644 arch/cpu/simplelink/source/clock-arch.c rename arch/cpu/simplelink/{ => source}/rtimer-arch.c (97%) rename arch/cpu/simplelink/{ => source}/rtimer-arch.h (100%) create mode 100644 arch/cpu/simplelink/source/watchdog-arch.c diff --git a/Makefile.include b/Makefile.include index 5a35b301d..55c5dd281 100644 --- a/Makefile.include +++ b/Makefile.include @@ -270,8 +270,10 @@ CONTIKI_CPU_DIRS_CONCAT = ${addprefix $(CONTIKI_CPU)/, \ $(CONTIKI_CPU_DIRS)} CONTIKI_ARCH_DIRS = ${addprefix $(CONTIKI)/, arch} -SOURCEDIRS = $(CONTIKI) $(PROJECTDIRS) $(CONTIKI_TARGET_DIRS_CONCAT) $(CONTIKI_ARCH_DIRS) \ - $(CONTIKI_CPU_DIRS_CONCAT) $(CONTIKIDIRS) $(MODULEDIRS) $(EXTERNALDIRS) ${dir $(target_makefile)} +SOURCEDIRS = $(CONTIKI) $(PROJECTDIRS) $(CONTIKI_TARGET_DIRS_CONCAT) \ + $(CONTIKI_ARCH_DIRS) $(CONTIKI_CPU_DIRS_CONCAT) \ + $(CONTIKIDIRS) $(MODULEDIRS) $(EXTERNALDIRS) \ + $(dir $(target_makefile)) vpath %.c $(SOURCEDIRS) vpath %.S $(SOURCEDIRS) @@ -496,7 +498,6 @@ endif # Cancel the predefined implict rule for compiling and linking # a single C source into a binary to force GNU make to consider # the match-anything rule below instead. -<<<<<<< HEAD %: %.c ifeq ($(PLATFORM_ACTION),skip) @@ -511,12 +512,3 @@ else %: %.$(TARGET) @ endif -======= -#%: %.c -# -## Match-anything pattern rule to allow the project makefiles to -## abstract from the actual binary name. It needs to contain some -## command in order to be a rule, not just a prerequisite. -#%: %.$(TARGET) -# @echo "match anything rule" ->>>>>>> Compiling example of dummy simplelink platform diff --git a/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 b/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 index d26650417..8215571e0 100644 --- a/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 +++ b/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 @@ -7,8 +7,7 @@ LDFLAGS += -T $(LDSCRIPT) LDFLAGS += -Wl,--gc-sections,--sort-section=alignment LDFLAGS += -Wl,-Map=$(@:.elf=-$(TARGET).map),--cref,--no-warn-mismatch -TARGET_LIBFLAGS := ${addprefix -l:,$(TARGET_LIBFILES)} -TARGET_LIBFLAGS += -gcc -lm -lnosys -lc +TARGET_LIBFLAGS := $(TARGET_LIBFILES) -gcc -lm -lnosys -lc OBJCOPY_FLAGS += --gap-fill 0xff diff --git a/arch/cpu/simplelink/Makefile.cc26x2_cc13x2 b/arch/cpu/simplelink/Makefile.cc26x2_cc13x2 index d4555ff51..5d6079f6f 100644 --- a/arch/cpu/simplelink/Makefile.cc26x2_cc13x2 +++ b/arch/cpu/simplelink/Makefile.cc26x2_cc13x2 @@ -13,6 +13,4 @@ TARGET_LIBFILES += $(SDK_DRIVERS)/lib/drivers_cc13x2.am4fg TARGET_LIBFILES += $(SDK_KERNEL)/lib/nortos_cc13x2.am4fg TARGET_LIBFILES += $(SDK_DRIVERLIB)/bin/gcc/driverlib.lib - - include $(CONTIKI)/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 diff --git a/arch/cpu/simplelink/Makefile.simplelink b/arch/cpu/simplelink/Makefile.simplelink index f952b3c41..9a73e953e 100644 --- a/arch/cpu/simplelink/Makefile.simplelink +++ b/arch/cpu/simplelink/Makefile.simplelink @@ -11,7 +11,7 @@ SDK_DRIVERS := $(SDK_SOURCE)/ti/drivers SDK_KERNEL := $(SIMPLELINK_SDK)/kernel/nortos SDK_BOARDS := $(SDK_SOURCE)/ti/boards SDK_STARTUP := $(SDK_DEVICE_SOURCE)/startup_files -SDK_STARTUP_SRCS = ccfg.c +SDK_STARTUP_SRCS := ccfg.c EXTERNALDIRS += $(SDK_STARTUP) @@ -19,6 +19,7 @@ EXTERNALDIRS += $(SDK_STARTUP) ### MODULES will add some of these to the include path, but we need to add ### them earlier to prevent filename clashes with Contiki core files CFLAGS += -I$(CPU_ABS_PATH) +CFLAGS += -I$(CPU_ABS_PATH)/source CFLAGS += -I$(SDK_SOURCE) CFLAGS += -I$(SDK_DEVICE_SOURCE) CFLAGS += -I$(SDK_DEVICE_SOURCE)/inc @@ -28,6 +29,9 @@ CFLAGS += -I$(SDK_KERNEL)/posix LDFLAGS += --entry resetISR LDFLAGS += -static LDFLAGS += --specs=nano.specs +LDFLAGS += -Wl,--defsym=_stack_origin=_stack +LDFLAGS += -Wl,--defsym=_heap=__heap_start__ +LDFLAGS += -Wl,--defsym=_eheap=__heap_end__ SDK_BOARDS := @@ -51,9 +55,11 @@ endif ### CPU-dependent directories CONTIKI_ARM_DIRS += . common/dbg-io CONTIKI_CPU_DIRS += . $(addprefix ../arm/, $(CPU_DIRS)) +CONTIKI_CPU_DIRS += source ### CPU-dependent source files -CONTIKI_CPU_SOURCEFILES += rtimer-arch.c +CONTIKI_CPU_SOURCEFILES += rtimer-arch.c clock-arch.c +CONTIKI_CPU_SOURCEFILES += watchdog-arch.c # CONTIKI_CPU_SOURCEFILES += contiki-watchdog.c aux-ctrl.c # CONTIKI_CPU_SOURCEFILES += putchar.c ieee-addr.c batmon-sensor.c adc-sensor.c # CONTIKI_CPU_SOURCEFILES += slip-arch.c slip.c cc26xx-uart.c lpm.c diff --git a/arch/cpu/simplelink/source/clock-arch.c b/arch/cpu/simplelink/source/clock-arch.c new file mode 100644 index 000000000..a3b076d6e --- /dev/null +++ b/arch/cpu/simplelink/source/clock-arch.c @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup cc26xx-clocks + * @{ + * + * \defgroup cc26xx-software-clock Software Clock + * + * Implementation of the clock module for the CC26xx and CC13xx. + * + * The software clock uses the facilities provided by the AON RTC driver + * @{ + * + * \file + * Software clock implementation for the TI CC13xx/CC26xx + */ +/*---------------------------------------------------------------------------*/ +#include +#include +#include +#include + +#include "contiki.h" + +/*---------------------------------------------------------------------------*/ +static volatile uint64_t count; +/*---------------------------------------------------------------------------*/ +static void +power_domain_on(void) +{ + PRCMPowerDomainOn(PRCM_DOMAIN_PERIPH); + while(PRCMPowerDomainStatus(PRCM_DOMAIN_PERIPH) != PRCM_DOMAIN_POWER_ON); +} +/*---------------------------------------------------------------------------*/ +void +clock_init(void) +{ + count = 0; + + /* + * Here, we configure GPT0 Timer A, which we subsequently use in + * clock_delay_usec + * + * We need to access registers, so firstly power up the PD and then enable + * the clock to GPT0. + */ + if(PRCMPowerDomainStatus(PRCM_DOMAIN_PERIPH) != PRCM_DOMAIN_POWER_ON) { + power_domain_on(); + } + + PRCMPeripheralRunEnable(PRCM_PERIPH_TIMER0); + PRCMLoadSet(); + while(!PRCMLoadGet()); + + /* Disable both GPT0 timers */ + HWREG(GPT0_BASE + GPT_O_CTL) &= ~(GPT_CTL_TAEN | GPT_CTL_TBEN); + + /* + * We assume that the clock is running at 48MHz, we use GPT0 Timer A, + * one-shot, countdown, prescaled by 48 gives us 1 tick per usec + */ + TimerConfigure(GPT0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_B_ONE_SHOT); + + /* Global config: split pair (2 x 16-bit wide) */ + HWREG(GPT0_BASE + GPT_O_CFG) = TIMER_CFG_SPLIT_PAIR >> 24; + + /* + * Pre-scale value 47 pre-scales by 48 + * + * ToDo: The theoretical value here should be 47 (to provide x48 prescale) + * However, 49 seems to give results much closer to the desired delay + */ + TimerPrescaleSet(GPT0_BASE, TIMER_B, 49); + + /* GPT0 / Timer B: One shot, PWM interrupt enable */ + HWREG(GPT0_BASE + GPT_O_TBMR) = + ((TIMER_CFG_B_ONE_SHOT >> 8) & 0xFF) | GPT_TBMR_TBPWMIE; + + /* enable sync with radio timer */ + HWREGBITW(AON_RTC_BASE + AON_RTC_O_CTL, AON_RTC_CTL_RTC_UPD_EN_BITN) = 1; +} +/*---------------------------------------------------------------------------*/ +static void +update_clock_variable(void) +{ + uint32_t aon_rtc_secs_now; + uint32_t aon_rtc_secs_now2; + uint16_t aon_rtc_ticks_now; + + do { + aon_rtc_secs_now = HWREG(AON_RTC_BASE + AON_RTC_O_SEC); + aon_rtc_ticks_now = HWREG(AON_RTC_BASE + AON_RTC_O_SUBSEC) >> 16; + aon_rtc_secs_now2 = HWREG(AON_RTC_BASE + AON_RTC_O_SEC); + } while(aon_rtc_secs_now != aon_rtc_secs_now2); + + /* Convert AON RTC ticks to clock tick counter */ + count = (aon_rtc_secs_now * CLOCK_SECOND) + (aon_rtc_ticks_now >> 9); +} +/*---------------------------------------------------------------------------*/ +CCIF clock_time_t +clock_time(void) +{ + update_clock_variable(); + + return (clock_time_t)(count & 0xFFFFFFFF); +} +/*---------------------------------------------------------------------------*/ +void +clock_update(void) +{ + update_clock_variable(); + + if(etimer_pending()) { + etimer_request_poll(); + } +} +/*---------------------------------------------------------------------------*/ +CCIF unsigned long +clock_seconds(void) +{ + bool interrupts_disabled; + uint32_t secs_now; + + interrupts_disabled = IntMasterDisable(); + + secs_now = AONRTCSecGet(); + + /* Re-enable interrupts */ + if(!interrupts_disabled) { + IntMasterEnable(); + } + + return (unsigned long)secs_now; +} +/*---------------------------------------------------------------------------*/ +void +clock_wait(clock_time_t i) +{ + clock_time_t start; + + start = clock_time(); + while(clock_time() - start < (clock_time_t)i); +} +/*---------------------------------------------------------------------------*/ +void +clock_delay_usec(uint16_t len) +{ + uint32_t clock_status; + + if(PRCMPowerDomainStatus(PRCM_DOMAIN_PERIPH) != + PRCM_DOMAIN_POWER_ON) { + power_domain_on(); + } + + clock_status = HWREG(PRCM_BASE + PRCM_O_GPTCLKGR) & PRCM_GPIOCLKGR_CLK_EN; + + PRCMPeripheralRunEnable(PRCM_PERIPH_TIMER0); + PRCMLoadSet(); + while(!PRCMLoadGet()); + + TimerLoadSet(GPT0_BASE, TIMER_B, len); + TimerEnable(GPT0_BASE, TIMER_B); + + /* + * Wait for TBEN to clear. CC26xxware does not provide us with a convenient + * function, hence the direct register access here + */ + while(HWREG(GPT0_BASE + GPT_O_CTL) & GPT_CTL_TBEN); + + if(clock_status == 0) { + PRCMPeripheralRunDisable(PRCM_PERIPH_TIMER0); + PRCMLoadSet(); + while(!PRCMLoadGet()); + } +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Obsolete delay function but we implement it here since some code + * still uses it + */ +void +clock_delay(unsigned int i) +{ + clock_delay_usec(i); +} +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/cpu/simplelink/rtimer-arch.c b/arch/cpu/simplelink/source/rtimer-arch.c similarity index 97% rename from arch/cpu/simplelink/rtimer-arch.c rename to arch/cpu/simplelink/source/rtimer-arch.c index f48cbe312..308094e48 100644 --- a/arch/cpu/simplelink/rtimer-arch.c +++ b/arch/cpu/simplelink/source/rtimer-arch.c @@ -46,6 +46,12 @@ #include + +// FIXME NB TEMPORARY HACK START +#include "radio.h" +const struct radio_driver ieee_mode_driver = { 0 }; +// FIXME NB TEMPORARY HACK END + #define RTIMER_RTC_CH AON_RTC_CH1 static ClockP_Struct gClk; diff --git a/arch/cpu/simplelink/rtimer-arch.h b/arch/cpu/simplelink/source/rtimer-arch.h similarity index 100% rename from arch/cpu/simplelink/rtimer-arch.h rename to arch/cpu/simplelink/source/rtimer-arch.h diff --git a/arch/cpu/simplelink/source/watchdog-arch.c b/arch/cpu/simplelink/source/watchdog-arch.c new file mode 100644 index 000000000..ac137e577 --- /dev/null +++ b/arch/cpu/simplelink/source/watchdog-arch.c @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/** + * \addtogroup cc26xx-clocks + * @{ + * + * \defgroup cc26xx-wdt CC13xx/CC26xx watchdog timer driver + * + * Driver for the CC13xx/CC26xx Watchdog Timer + * + * This file is not called watchdog.c because the filename is in use by + * TI CC26xxware/CC13xxware + * @{ + * + * \file + * Implementation of the CC13xx/CC26xx watchdog driver. + */ +#include +#include + +#include "contiki.h" +#include "dev/watchdog.h" + +#include +#include +/*---------------------------------------------------------------------------*/ +#ifdef CONTIKI_WATCHDOG_CONF_TIMER_TOP +#define CONTIKI_WATCHDOG_TIMER_TOP CONTIKI_WATCHDOG_CONF_TIMER_TOP +#else +#define CONTIKI_WATCHDOG_TIMER_TOP 0xFFFFF +#endif + +#ifdef CONTIKI_WATCHDOG_CONF_LOCK_CONFIG +#define CONTIKI_WATCHDOG_LOCK_CONFIG CONTIKI_WATCHDOG_CONF_LOCK_CONFIG +#else +#define CONTIKI_WATCHDOG_LOCK_CONFIG 1 +#endif + +#define LOCK_INTERRUPTS_DISABLED 0x01 +#define LOCK_REGISTERS_UNLOCKED 0x02 +/*---------------------------------------------------------------------------*/ +static uint32_t +unlock_config(void) +{ + uint32_t ret = 0; + bool int_status; + + if(CONTIKI_WATCHDOG_LOCK_CONFIG) { + int_status = IntMasterDisable(); + + if(WatchdogLockState()) { + ret |= LOCK_REGISTERS_UNLOCKED; + WatchdogUnlock(); + } + + ret |= (int_status) ? (0) : (LOCK_INTERRUPTS_DISABLED); + } + + return ret; +} +/*---------------------------------------------------------------------------*/ +static void +lock_config(uint32_t status) +{ + if(CONTIKI_WATCHDOG_LOCK_CONFIG) { + + if(status & LOCK_REGISTERS_UNLOCKED) { + WatchdogLock(); + } + if(status & LOCK_INTERRUPTS_DISABLED) { + IntMasterEnable(); + } + } +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Initialises the CC26xx WDT + * + * Simply sets the reload counter to a default value. The WDT is not started + * yet. To start it, watchdog_start() must be called. + */ +void +watchdog_init(void) +{ + WatchdogReloadSet(CONTIKI_WATCHDOG_TIMER_TOP); + lock_config(LOCK_REGISTERS_UNLOCKED); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Starts the CC26xx WDT + */ +void +watchdog_start(void) +{ + uint32_t lock_status = unlock_config(); + + watchdog_periodic(); + WatchdogResetEnable(); + + lock_config(lock_status); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Refreshes the CC26xx WDT + */ +void +watchdog_periodic(void) +{ + WatchdogReloadSet(CONTIKI_WATCHDOG_TIMER_TOP); + WatchdogIntClear(); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Stops the WDT such that it won't timeout and cause MCU reset + */ +void +watchdog_stop(void) +{ + uint32_t lock_status = unlock_config(); + + WatchdogResetDisable(); + + lock_config(lock_status); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Manually trigger a WDT reboot + */ +void +watchdog_reboot(void) +{ + watchdog_start(); + while(1); +} +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/platform/simplelink/platform.c b/arch/platform/simplelink/platform.c index 0a2fdba5c..36d7a8ac1 100644 --- a/arch/platform/simplelink/platform.c +++ b/arch/platform/simplelink/platform.c @@ -88,24 +88,24 @@ unsigned short node_id = 0; /** \brief Board specific iniatialisation */ void board_init(void); /*---------------------------------------------------------------------------*/ -//static void -//fade(unsigned char l) -//{ -// volatile int i; -// int k, j; -// for(k = 0; k < 800; ++k) { -// j = k > 400 ? 800 - k : k; -// -// leds_on(l); -// for(i = 0; i < j; ++i) { -// __asm("nop"); -// } -// leds_off(l); -// for(i = 0; i < 400 - j; ++i) { -// __asm("nop"); -// } -// } -//} +static void +fade(unsigned char l) +{ + volatile int i; + int k, j; + for(k = 0; k < 800; ++k) { + j = k > 400 ? 800 - k : k; + + GPIO_write(l, Board_GPIO_LED_ON); + for(i = 0; i < j; ++i) { + __asm("nop"); + } + GPIO_write(l, Board_GPIO_LED_OFF); + for(i = 0; i < 400 - j; ++i) { + __asm("nop"); + } + } +} /*---------------------------------------------------------------------------*/ //static void //set_rf_params(void) @@ -134,8 +134,6 @@ platform_init_stage_one() GPIO_init(); NoRTOS_start(); - GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_ON); - GPIO_write(Board_GPIO_LED1, Board_GPIO_LED_OFF); // /* Enable flash cache and prefetch. */ // ti_lib_vims_mode_set(VIMS_BASE, VIMS_MODE_ENABLED); // ti_lib_vims_configure(VIMS_BASE, true, true); @@ -152,7 +150,7 @@ platform_init_stage_one() // gpio_interrupt_init(); // // leds_init(); -// fade(LEDS_RED); + fade(Board_GPIO_LED0); // // /* // * Disable I/O pad sleep mode and open I/O latches in the AON IOC interface @@ -165,7 +163,7 @@ platform_init_stage_one() // ti_lib_int_master_enable(); // // soc_rtc_init(); -// fade(LEDS_YELLOW); + fade(Board_GPIO_LED1); } /*---------------------------------------------------------------------------*/ void @@ -186,7 +184,7 @@ platform_init_stage_two() // /* Populate linkaddr_node_addr */ // ieee_addr_cpy_to(linkaddr_node_addr.u8, LINKADDR_SIZE); // -// fade(LEDS_GREEN); + fade(Board_GPIO_LED0); } /*---------------------------------------------------------------------------*/ void @@ -214,7 +212,7 @@ platform_init_stage_three() // LOG_INFO(" Node ID: %d\n", node_id); // // process_start(&sensors_process, NULL); -// fade(LEDS_ORANGE); + fade(Board_GPIO_LED1); } /*---------------------------------------------------------------------------*/ void From c8023df8a5d37646342b76b2c6fef73b930fd78d Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Wed, 7 Feb 2018 16:58:16 +0100 Subject: [PATCH 224/485] Added UART serial interface printing --- arch/cpu/simplelink/Makefile.simplelink | 7 +- arch/cpu/simplelink/source/dbg.h | 65 +++++++++++++++ arch/cpu/simplelink/source/debug-uart.h | 49 +++++++++++ arch/cpu/simplelink/source/putchar-arch.c | 87 ++++++++++++++++++++ arch/cpu/simplelink/source/rtimer-arch.c | 4 +- arch/cpu/simplelink/source/simplelink-uart.c | 82 ++++++++++++++++++ arch/cpu/simplelink/source/simplelink-uart.h | 82 ++++++++++++++++++ arch/platform/simplelink/platform.c | 35 ++++---- 8 files changed, 385 insertions(+), 26 deletions(-) create mode 100644 arch/cpu/simplelink/source/dbg.h create mode 100644 arch/cpu/simplelink/source/debug-uart.h create mode 100644 arch/cpu/simplelink/source/putchar-arch.c create mode 100644 arch/cpu/simplelink/source/simplelink-uart.c create mode 100644 arch/cpu/simplelink/source/simplelink-uart.h diff --git a/arch/cpu/simplelink/Makefile.simplelink b/arch/cpu/simplelink/Makefile.simplelink index 9a73e953e..23681367c 100644 --- a/arch/cpu/simplelink/Makefile.simplelink +++ b/arch/cpu/simplelink/Makefile.simplelink @@ -29,7 +29,7 @@ CFLAGS += -I$(SDK_KERNEL)/posix LDFLAGS += --entry resetISR LDFLAGS += -static LDFLAGS += --specs=nano.specs -LDFLAGS += -Wl,--defsym=_stack_origin=_stack +LDFLAGS += -Wl,--defsym=_stack_origin=__stack LDFLAGS += -Wl,--defsym=_heap=__heap_start__ LDFLAGS += -Wl,--defsym=_eheap=__heap_end__ @@ -59,7 +59,8 @@ CONTIKI_CPU_DIRS += source ### CPU-dependent source files CONTIKI_CPU_SOURCEFILES += rtimer-arch.c clock-arch.c -CONTIKI_CPU_SOURCEFILES += watchdog-arch.c +CONTIKI_CPU_SOURCEFILES += watchdog-arch.c putchar-arch.c +CONTIKI_CPU_SOURCEFILES += simplelink-uart.c # CONTIKI_CPU_SOURCEFILES += contiki-watchdog.c aux-ctrl.c # CONTIKI_CPU_SOURCEFILES += putchar.c ieee-addr.c batmon-sensor.c adc-sensor.c # CONTIKI_CPU_SOURCEFILES += slip-arch.c slip.c cc26xx-uart.c lpm.c @@ -67,7 +68,7 @@ CONTIKI_CPU_SOURCEFILES += watchdog-arch.c # CONTIKI_CPU_SOURCEFILES += rf-core.c rf-ble.c ieee-mode.c # CONTIKI_CPU_SOURCEFILES += random.c soc-trng.c int-master.c -# DEBUG_IO_SOURCEFILES += dbg-printf.c dbg-snprintf.c dbg-sprintf.c strformat.c +DEBUG_IO_SOURCEFILES += dbg-printf.c dbg-snprintf.c dbg-sprintf.c strformat.c CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES) $(DEBUG_IO_SOURCEFILES) diff --git a/arch/cpu/simplelink/source/dbg.h b/arch/cpu/simplelink/source/dbg.h new file mode 100644 index 000000000..4460b6eb4 --- /dev/null +++ b/arch/cpu/simplelink/source/dbg.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup cc26xx + * @{ + * + * \defgroup cc26xx-char-io CC13xx/CC26xx Character I/O + * + * CC13xx/CC26xx CPU-specific functions for debugging and SLIP I/O + * @{ + * + * \file + * Header file for the CC13xx/CC26xx Debug I/O module + */ +#ifndef DBG_H_ +#define DBG_H_ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +/*---------------------------------------------------------------------------*/ +/** + * \brief Print a stream of bytes + * \param seq A pointer to the stream + * \param len The number of bytes to print + * \return The number of printed bytes + * + * This function is an arch-specific implementation required by the dbg-io + * API in cpu/arm/common/dbg-io. It prints a stream of bytes over the + * peripheral used by the platform. + */ +unsigned int dbg_send_bytes(const unsigned char *seq, unsigned int len); +/*---------------------------------------------------------------------------*/ +#endif /* DBG_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/cpu/simplelink/source/debug-uart.h b/arch/cpu/simplelink/source/debug-uart.h new file mode 100644 index 000000000..c2d9b0ffb --- /dev/null +++ b/arch/cpu/simplelink/source/debug-uart.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup cc26xx-char-io + * @{ + * + * \file + * This file is here because DBG I/O expects it to be. It just includes + * our own dbg.h which has a non-misleading name and which also adheres + * to Contiki's naming convention + */ +/*---------------------------------------------------------------------------*/ +#ifndef DEBUG_UART_H_ +#define DEBUG_UART_H_ +/*---------------------------------------------------------------------------*/ +#include "dbg.h" +/*---------------------------------------------------------------------------*/ +#endif /* DEBUG_UART_H_ */ +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/cpu/simplelink/source/putchar-arch.c b/arch/cpu/simplelink/source/putchar-arch.c new file mode 100644 index 000000000..b440e2b41 --- /dev/null +++ b/arch/cpu/simplelink/source/putchar-arch.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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 "simplelink-uart.h" + + +#undef putchar +#undef puts +/*---------------------------------------------------------------------------*/ +int +putchar(int c) +{ + const unsigned char ch = (unsigned char)c; + return (simplelink_uart_write(&ch, 1) == 1) + ? (int)ch + : EOF; +} +/*---------------------------------------------------------------------------*/ +int +puts(const char *str) +{ + if(!str) + { + return EOF; + } + + const size_t len = strlen(str); + const unsigned char newline = '\n'; + + if ((simplelink_uart_write(str, len) != len) && + (simplelink_uart_write(&newline, 1) != 1)) + { + return EOF; + } + + return len + 1; +} +/*---------------------------------------------------------------------------*/ +unsigned int +dbg_send_bytes(const unsigned char *s, unsigned int len) +{ + if(!s || strlen((const char *)s) < len) + { + return EOF; + } + + const unsigned char newline = '\n'; + + if ((simplelink_uart_write(s, len) != len) && + (simplelink_uart_write(&newline, 1) != 1)) + { + return EOF; + } + + return len + 1; +} +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/simplelink/source/rtimer-arch.c b/arch/cpu/simplelink/source/rtimer-arch.c index 308094e48..5f56b8359 100644 --- a/arch/cpu/simplelink/source/rtimer-arch.c +++ b/arch/cpu/simplelink/source/rtimer-arch.c @@ -106,7 +106,7 @@ rtimer_arch_init(void) volatile IsrFxn * const pfnRAMVectors = (volatile IsrFxn *)(HWREG(NVIC_VTABLE)); if (!pfnRAMVectors) { - while (0) { /* hang */ } + for (;;) { /* hang */ } } // The HWI Dispatch ISR should be located at int num INT_AON_RTC_COMB. @@ -114,7 +114,7 @@ rtimer_arch_init(void) hwiDispatch = (HwiDispatchFxn)pfnRAMVectors[INT_AON_RTC_COMB]; if (!hwiDispatch) { - while (0) { /* hang */ } + for (;;) { /* hang */ } } // Override the INT_AON_RTC_COMB int num with own ISR hook diff --git a/arch/cpu/simplelink/source/simplelink-uart.c b/arch/cpu/simplelink/source/simplelink-uart.c new file mode 100644 index 000000000..c923228bd --- /dev/null +++ b/arch/cpu/simplelink/source/simplelink-uart.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup cc26xx-uart + * @{ + * + * \file + * Implementation of the CC13xx/CC26xx UART driver. + */ +/*---------------------------------------------------------------------------*/ +#include +#include + +#include + +static UART_Handle hUart; +/*---------------------------------------------------------------------------*/ +void +simplelink_uart_init(void) +{ + UART_init(); + + UART_Params params; + UART_Params_init(¶ms); + // TODO configure + + hUart = UART_open(Board_UART0, ¶ms); + if (!hUart) + { + for (;;) { /* hang */ } + } +} +/*---------------------------------------------------------------------------*/ +int_fast32_t +simplelink_uart_write(const void *buffer, size_t size) +{ + if (!hUart) + { + return UART_STATUS_ERROR; + } + return UART_write(hUart, buffer, size); +} +/*---------------------------------------------------------------------------*/ +int_fast32_t +simplelink_uart_read(void *buffer, size_t size) +{ + if (!hUart) + { + return UART_STATUS_ERROR; + } + return UART_read(hUart, buffer, size); +} +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/cpu/simplelink/source/simplelink-uart.h b/arch/cpu/simplelink/source/simplelink-uart.h new file mode 100644 index 000000000..6e1b2cfe9 --- /dev/null +++ b/arch/cpu/simplelink/source/simplelink-uart.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/** + * \addtogroup cc26xx + * @{ + * + * \defgroup cc26xx-uart CC13xx/CC26xx UARTs + * + * Driver for the CC13xx/CC26xx UART controller + * @{ + * + * \file + * Header file for the CC13xx/CC26xx UART driver + */ +#ifndef SIMPLELINK_UART_H_ +#define SIMPLELINK_UART_H_ + +#include + +/*---------------------------------------------------------------------------*/ +/** \name UART functions + * @{ + */ + +/** + * \brief Initializes the UART driver + */ +void simplelink_uart_init(void); + +/** + * \brief Writes data from a memory buffer to the UART interface. + * \param buffer A pointer to the data buffer. + * \param size Size of the data buffer. + * \return Number of bytes that has been written to the UART. If an + * error occurs, a negative value is returned. + */ +int_fast32_t simplelink_uart_write(const void *buffer, size_t size); + +/** + * \brief Reads data from the UART interface to a memory buffer. + * \param buffer A pointer to the data buffer. + * \param size Number of bytes to read + * \return Number of bytes that has been written to the buffer. If an + * error occurs, a negative value is returned. + */ +int_fast32_t simplelink_uart_read(void *buffer, size_t size); + +/** @} */ +/*---------------------------------------------------------------------------*/ +#endif /* SIMPLELINK_UART_H_ */ + +/** + * @} + * @} + */ diff --git a/arch/platform/simplelink/platform.c b/arch/platform/simplelink/platform.c index 36d7a8ac1..07a4f46c7 100644 --- a/arch/platform/simplelink/platform.c +++ b/arch/platform/simplelink/platform.c @@ -29,29 +29,31 @@ */ /*---------------------------------------------------------------------------*/ /** - * \addtogroup cc26xx-platforms + * \addtogroup cc13xx-cc26xx-platforms * @{ * - * \defgroup cc26xx-srf-tag SmartRF+CC13xx/CC26xx EM, SensorTags and LaunchPads + * \defgroup LaunchPads * * This platform supports a number of different boards: - * - A standard TI SmartRF06EB with a CC26xx EM mounted on it - * - A standard TI SmartRF06EB with a CC1310 EM mounted on it - * - The TI CC2650 SensorTag - * - The TI CC1350 SensorTag - * - The TI CC2650 LaunchPad * - The TI CC1310 LaunchPad * - The TI CC1350 LaunchPad + * - The TI CC2640 LaunchPad + * - The TI CC2650 LaunchPad + * - The TI CC1312R1 LaunchPad + * - The TI CC1352R1 LaunchPad + * - The TI CC1352P1 LaunchPad + * - The TI CC26X2R1 LaunchPad * @{ */ -#include "contiki.h" -#include "contiki-net.h" - #include #include #include #include +#include "contiki.h" +#include "contiki-net.h" + +#include "simplelink-uart.h" //#include "leds.h" //#include "lpm.h" @@ -85,7 +87,7 @@ /*---------------------------------------------------------------------------*/ unsigned short node_id = 0; /*---------------------------------------------------------------------------*/ -/** \brief Board specific iniatialisation */ +/** \brief Board specific initialization */ void board_init(void); /*---------------------------------------------------------------------------*/ static void @@ -169,16 +171,10 @@ platform_init_stage_one() void platform_init_stage_two() { - GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_OFF); - GPIO_write(Board_GPIO_LED1, Board_GPIO_LED_ON); + simplelink_uart_init(); // random_init(0x1234); // -// /* Character I/O Initialisation */ -//#if CC26XX_UART_CONF_ENABLE -// cc26xx_uart_init(); -//#endif -// // serial_line_init(); // // /* Populate linkaddr_node_addr */ @@ -190,9 +186,6 @@ platform_init_stage_two() void platform_init_stage_three() { - GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_ON); - GPIO_write(Board_GPIO_LED1, Board_GPIO_LED_ON); - // radio_value_t chan, pan; // // set_rf_params(); From c99c3b4b5fb33c4e41751fa7a1f89c2dc760c10a Mon Sep 17 00:00:00 2001 From: Richard Weickelt Date: Wed, 7 Feb 2018 17:20:54 +0100 Subject: [PATCH 225/485] Rewriting clock module based upon DPL --- arch/cpu/arm/Makefile.arm | 2 +- arch/cpu/simplelink/source/clock-arch.c | 135 ++++----------------- arch/cpu/simplelink/source/watchdog-arch.c | 5 + arch/platform/simplelink/platform.c | 4 +- os/contiki-main.c | 28 ++--- 5 files changed, 49 insertions(+), 125 deletions(-) diff --git a/arch/cpu/arm/Makefile.arm b/arch/cpu/arm/Makefile.arm index 0c71d63fa..dd00aae6d 100644 --- a/arch/cpu/arm/Makefile.arm +++ b/arch/cpu/arm/Makefile.arm @@ -26,7 +26,7 @@ SMALL ?= 1 ifeq ($(SMALL),1) CFLAGS += -Os else - CFLAGS += -O2 + CFLAGS += -O0 endif ### Use CMSIS and the existing dbg-io from arch/cpu/arm/common diff --git a/arch/cpu/simplelink/source/clock-arch.c b/arch/cpu/simplelink/source/clock-arch.c index a3b076d6e..8869dc734 100644 --- a/arch/cpu/simplelink/source/clock-arch.c +++ b/arch/cpu/simplelink/source/clock-arch.c @@ -47,96 +47,47 @@ #include #include #include +#include +#include +#include #include "contiki.h" +#define DPL_CLOCK_TICK_PERIOD_US ClockP_getSystemTickPeriod() +#define CLOCK_TICKS_SECOND ((uint32_t)1000000 / (CLOCK_SECOND) / (DPL_CLOCK_TICK_PERIOD_US)) + /*---------------------------------------------------------------------------*/ static volatile uint64_t count; -/*---------------------------------------------------------------------------*/ -static void -power_domain_on(void) -{ - PRCMPowerDomainOn(PRCM_DOMAIN_PERIPH); - while(PRCMPowerDomainStatus(PRCM_DOMAIN_PERIPH) != PRCM_DOMAIN_POWER_ON); -} +static ClockP_Struct etimerClock; +static void clock_update(void); /*---------------------------------------------------------------------------*/ void clock_init(void) { count = 0; - - /* - * Here, we configure GPT0 Timer A, which we subsequently use in - * clock_delay_usec - * - * We need to access registers, so firstly power up the PD and then enable - * the clock to GPT0. - */ - if(PRCMPowerDomainStatus(PRCM_DOMAIN_PERIPH) != PRCM_DOMAIN_POWER_ON) { - power_domain_on(); - } - - PRCMPeripheralRunEnable(PRCM_PERIPH_TIMER0); - PRCMLoadSet(); - while(!PRCMLoadGet()); - - /* Disable both GPT0 timers */ - HWREG(GPT0_BASE + GPT_O_CTL) &= ~(GPT_CTL_TAEN | GPT_CTL_TBEN); - - /* - * We assume that the clock is running at 48MHz, we use GPT0 Timer A, - * one-shot, countdown, prescaled by 48 gives us 1 tick per usec - */ - TimerConfigure(GPT0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_B_ONE_SHOT); - - /* Global config: split pair (2 x 16-bit wide) */ - HWREG(GPT0_BASE + GPT_O_CFG) = TIMER_CFG_SPLIT_PAIR >> 24; - - /* - * Pre-scale value 47 pre-scales by 48 - * - * ToDo: The theoretical value here should be 47 (to provide x48 prescale) - * However, 49 seems to give results much closer to the desired delay - */ - TimerPrescaleSet(GPT0_BASE, TIMER_B, 49); - - /* GPT0 / Timer B: One shot, PWM interrupt enable */ - HWREG(GPT0_BASE + GPT_O_TBMR) = - ((TIMER_CFG_B_ONE_SHOT >> 8) & 0xFF) | GPT_TBMR_TBPWMIE; - - /* enable sync with radio timer */ - HWREGBITW(AON_RTC_BASE + AON_RTC_O_CTL, AON_RTC_CTL_RTC_UPD_EN_BITN) = 1; -} -/*---------------------------------------------------------------------------*/ -static void -update_clock_variable(void) -{ - uint32_t aon_rtc_secs_now; - uint32_t aon_rtc_secs_now2; - uint16_t aon_rtc_ticks_now; - - do { - aon_rtc_secs_now = HWREG(AON_RTC_BASE + AON_RTC_O_SEC); - aon_rtc_ticks_now = HWREG(AON_RTC_BASE + AON_RTC_O_SUBSEC) >> 16; - aon_rtc_secs_now2 = HWREG(AON_RTC_BASE + AON_RTC_O_SEC); - } while(aon_rtc_secs_now != aon_rtc_secs_now2); - - /* Convert AON RTC ticks to clock tick counter */ - count = (aon_rtc_secs_now * CLOCK_SECOND) + (aon_rtc_ticks_now >> 9); + ClockP_Params params; + ClockP_Params_init(¶ms); + params.period = CLOCK_TICKS_SECOND; + params.startFlag = true; + ClockP_construct(&etimerClock, (ClockP_Fxn)&clock_update, CLOCK_TICKS_SECOND, ¶ms); } /*---------------------------------------------------------------------------*/ CCIF clock_time_t clock_time(void) { - update_clock_variable(); + uintptr_t hwiState = HwiP_disable(); + clock_time_t result = count; + HwiP_restore(hwiState); - return (clock_time_t)(count & 0xFFFFFFFF); + return (clock_time_t)(result & 0xFFFFFFFF); } /*---------------------------------------------------------------------------*/ -void +static void clock_update(void) { - update_clock_variable(); + uintptr_t hwiState = HwiP_disable(); + count++; + HwiP_restore(hwiState); if(etimer_pending()) { etimer_request_poll(); @@ -146,19 +97,11 @@ clock_update(void) CCIF unsigned long clock_seconds(void) { - bool interrupts_disabled; - uint32_t secs_now; + uintptr_t hwiState = HwiP_disable(); + unsigned long result = count / CLOCK_SECOND; + HwiP_restore(hwiState); - interrupts_disabled = IntMasterDisable(); - - secs_now = AONRTCSecGet(); - - /* Re-enable interrupts */ - if(!interrupts_disabled) { - IntMasterEnable(); - } - - return (unsigned long)secs_now; + return result; } /*---------------------------------------------------------------------------*/ void @@ -173,33 +116,7 @@ clock_wait(clock_time_t i) void clock_delay_usec(uint16_t len) { - uint32_t clock_status; - - if(PRCMPowerDomainStatus(PRCM_DOMAIN_PERIPH) != - PRCM_DOMAIN_POWER_ON) { - power_domain_on(); - } - - clock_status = HWREG(PRCM_BASE + PRCM_O_GPTCLKGR) & PRCM_GPIOCLKGR_CLK_EN; - - PRCMPeripheralRunEnable(PRCM_PERIPH_TIMER0); - PRCMLoadSet(); - while(!PRCMLoadGet()); - - TimerLoadSet(GPT0_BASE, TIMER_B, len); - TimerEnable(GPT0_BASE, TIMER_B); - - /* - * Wait for TBEN to clear. CC26xxware does not provide us with a convenient - * function, hence the direct register access here - */ - while(HWREG(GPT0_BASE + GPT_O_CTL) & GPT_CTL_TBEN); - - if(clock_status == 0) { - PRCMPeripheralRunDisable(PRCM_PERIPH_TIMER0); - PRCMLoadSet(); - while(!PRCMLoadGet()); - } + usleep(len); } /*---------------------------------------------------------------------------*/ /** diff --git a/arch/cpu/simplelink/source/watchdog-arch.c b/arch/cpu/simplelink/source/watchdog-arch.c index ac137e577..01a54c68e 100644 --- a/arch/cpu/simplelink/source/watchdog-arch.c +++ b/arch/cpu/simplelink/source/watchdog-arch.c @@ -109,6 +109,7 @@ lock_config(uint32_t status) void watchdog_init(void) { + return; WatchdogReloadSet(CONTIKI_WATCHDOG_TIMER_TOP); lock_config(LOCK_REGISTERS_UNLOCKED); } @@ -119,6 +120,7 @@ watchdog_init(void) void watchdog_start(void) { + return; uint32_t lock_status = unlock_config(); watchdog_periodic(); @@ -133,6 +135,7 @@ watchdog_start(void) void watchdog_periodic(void) { + return; WatchdogReloadSet(CONTIKI_WATCHDOG_TIMER_TOP); WatchdogIntClear(); } @@ -143,6 +146,7 @@ watchdog_periodic(void) void watchdog_stop(void) { + return; uint32_t lock_status = unlock_config(); WatchdogResetDisable(); @@ -156,6 +160,7 @@ watchdog_stop(void) void watchdog_reboot(void) { + return; watchdog_start(); while(1); } diff --git a/arch/platform/simplelink/platform.c b/arch/platform/simplelink/platform.c index 07a4f46c7..e8b0517fd 100644 --- a/arch/platform/simplelink/platform.c +++ b/arch/platform/simplelink/platform.c @@ -134,7 +134,6 @@ platform_init_stage_one() { Board_initGeneral(); GPIO_init(); - NoRTOS_start(); // /* Enable flash cache and prefetch. */ // ti_lib_vims_mode_set(VIMS_BASE, VIMS_MODE_ENABLED); @@ -206,6 +205,9 @@ platform_init_stage_three() // // process_start(&sensors_process, NULL); fade(Board_GPIO_LED1); + + // Finally enable hardware interrupts + NoRTOS_start(); } /*---------------------------------------------------------------------------*/ void diff --git a/os/contiki-main.c b/os/contiki-main.c index c756cf206..b91817c3a 100644 --- a/os/contiki-main.c +++ b/os/contiki-main.c @@ -122,20 +122,20 @@ main(void) platform_init_stage_three(); -#if BUILD_WITH_RPL_BORDER_ROUTER - rpl_border_router_init(); - LOG_DBG("With RPL Border Router\n"); -#endif /* BUILD_WITH_RPL_BORDER_ROUTER */ - -#if BUILD_WITH_ORCHESTRA - orchestra_init(); - LOG_DBG("With Orchestra\n"); -#endif /* BUILD_WITH_ORCHESTRA */ - -#if BUILD_WITH_SHELL - serial_shell_init(); - LOG_DBG("With Shell\n"); -#endif /* BUILD_WITH_SHELL */ +//#if BUILD_WITH_RPL_BORDER_ROUTER +// rpl_border_router_init(); +// LOG_DBG("With RPL Border Router\n"); +//#endif /* BUILD_WITH_RPL_BORDER_ROUTER */ +// +//#if BUILD_WITH_ORCHESTRA +// orchestra_init(); +// LOG_DBG("With Orchestra\n"); +//#endif /* BUILD_WITH_ORCHESTRA */ +// +//#if BUILD_WITH_SHELL +// serial_shell_init(); +// LOG_DBG("With Shell\n"); +//#endif /* BUILD_WITH_SHELL */ #if BUILD_WITH_COAP coap_engine_init(); From b30ef7d56d8e50b719dcb1709262067e720fe7f6 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Thu, 8 Feb 2018 10:35:08 +0100 Subject: [PATCH 226/485] Added async read on UART --- Makefile.include | 6 --- arch/cpu/simplelink/source/simplelink-uart.c | 48 ++++++++++++++++---- arch/cpu/simplelink/source/simplelink-uart.h | 4 +- arch/platform/simplelink/platform.c | 22 +++++---- 4 files changed, 53 insertions(+), 27 deletions(-) diff --git a/Makefile.include b/Makefile.include index 55c5dd281..27b0ca110 100644 --- a/Makefile.include +++ b/Makefile.include @@ -394,10 +394,6 @@ ifndef LD LD = $(CC) endif -### Make sure Makefiles with the $(TARGET) suffix doesn't match -Makefile.$(TARGET): - @ - ifndef CUSTOM_RULE_LINK %.$(TARGET): %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(CONTIKI_NG_TARGET_LIB) $(TRACE_LD) @@ -493,8 +489,6 @@ endif # in fact the primary target. .PRECIOUS: %.$(TARGET) - - # Cancel the predefined implict rule for compiling and linking # a single C source into a binary to force GNU make to consider # the match-anything rule below instead. diff --git a/arch/cpu/simplelink/source/simplelink-uart.c b/arch/cpu/simplelink/source/simplelink-uart.c index c923228bd..28fb80b53 100644 --- a/arch/cpu/simplelink/source/simplelink-uart.c +++ b/arch/cpu/simplelink/source/simplelink-uart.c @@ -41,7 +41,26 @@ #include -static UART_Handle hUart; +#include "simplelink-uart.h" + +static UART_Handle gh_uart; + +static volatile InputCb g_input_cb; +static unsigned char g_charbuf; + +/*---------------------------------------------------------------------------*/ +static void +uart_cb(UART_Handle handle, void *buf, size_t count) +{ + if (!g_input_cb) { return; } + + const InputCb currCb = g_input_cb; + currCb(g_charbuf); + if (currCb == g_input_cb) + { + UART_read(gh_uart, &g_charbuf, 1); + } +} /*---------------------------------------------------------------------------*/ void simplelink_uart_init(void) @@ -50,10 +69,13 @@ simplelink_uart_init(void) UART_Params params; UART_Params_init(¶ms); + params.readMode = UART_MODE_CALLBACK; + params.writeMode = UART_MODE_BLOCKING ; + params.readCallback = uart_cb; // TODO configure - hUart = UART_open(Board_UART0, ¶ms); - if (!hUart) + gh_uart = UART_open(Board_UART0, ¶ms); + if (!gh_uart) { for (;;) { /* hang */ } } @@ -62,21 +84,27 @@ simplelink_uart_init(void) int_fast32_t simplelink_uart_write(const void *buffer, size_t size) { - if (!hUart) + if (!gh_uart) { return UART_STATUS_ERROR; } - return UART_write(hUart, buffer, size); + return UART_write(gh_uart, buffer, size); } /*---------------------------------------------------------------------------*/ -int_fast32_t -simplelink_uart_read(void *buffer, size_t size) +void +simplelink_uart_set_callback(InputCb input_cb) { - if (!hUart) + if (g_input_cb == input_cb) { return; } + + g_input_cb = input_cb; + if (input_cb) { - return UART_STATUS_ERROR; + UART_read(gh_uart, &g_charbuf, 1); + } + else + { + UART_readCancel(gh_uart); } - return UART_read(hUart, buffer, size); } /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/cpu/simplelink/source/simplelink-uart.h b/arch/cpu/simplelink/source/simplelink-uart.h index 6e1b2cfe9..9e93dc317 100644 --- a/arch/cpu/simplelink/source/simplelink-uart.h +++ b/arch/cpu/simplelink/source/simplelink-uart.h @@ -44,6 +44,8 @@ #include +typedef void (*InputCb)(unsigned char); + /*---------------------------------------------------------------------------*/ /** \name UART functions * @{ @@ -70,7 +72,7 @@ int_fast32_t simplelink_uart_write(const void *buffer, size_t size); * \return Number of bytes that has been written to the buffer. If an * error occurs, a negative value is returned. */ -int_fast32_t simplelink_uart_read(void *buffer, size_t size); +void simplelink_uart_set_callback(InputCb input_cb); /** @} */ /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/platform.c b/arch/platform/simplelink/platform.c index e8b0517fd..74302bb17 100644 --- a/arch/platform/simplelink/platform.c +++ b/arch/platform/simplelink/platform.c @@ -48,6 +48,8 @@ #include #include #include +#include +#include #include #include "contiki.h" @@ -192,16 +194,16 @@ platform_init_stage_three() // NETSTACK_RADIO.get_value(RADIO_PARAM_CHANNEL, &chan); // NETSTACK_RADIO.get_value(RADIO_PARAM_PAN_ID, &pan); // -// LOG_DBG("With DriverLib v%u.%u\n", DRIVERLIB_RELEASE_GROUP, -// DRIVERLIB_RELEASE_BUILD); -// LOG_INFO(BOARD_STRING "\n"); -// LOG_DBG("IEEE 802.15.4: %s, Sub-GHz: %s, BLE: %s, Prop: %s\n", -// ti_lib_chipinfo_supports_ieee_802_15_4() == true ? "Yes" : "No", -// ti_lib_chipinfo_chip_family_is_cc13xx() == true ? "Yes" : "No", -// ti_lib_chipinfo_supports_ble() == true ? "Yes" : "No", -// ti_lib_chipinfo_supports_proprietary() == true ? "Yes" : "No"); -// LOG_INFO(" RF: Channel %d, PANID 0x%04X\n", chan, pan); -// LOG_INFO(" Node ID: %d\n", node_id); + LOG_DBG("With DriverLib v%u.%u\n", DRIVERLIB_RELEASE_GROUP, + DRIVERLIB_RELEASE_BUILD); + //LOG_INFO(BOARD_STRING "\n"); + LOG_DBG("IEEE 802.15.4: %s, Sub-GHz: %s, BLE: %s, Prop: %s\n", + ChipInfo_SupportsIEEE_802_15_4() ? "Yes" : "No", + ChipInfo_ChipFamilyIs_CC13x0() ? "Yes" : "No", + ChipInfo_SupportsBLE() ? "Yes" : "No", + ChipInfo_SupportsPROPRIETARY() ? "Yes" : "No"); + //LOG_INFO(" RF: Channel %d, PANID 0x%04X\n", chan, pan); + //LOG_INFO(" Node ID: %d\n", node_id); // // process_start(&sensors_process, NULL); fade(Board_GPIO_LED1); From 8f0b3fb49c572e0ec570838446da16ac37bcc1ae Mon Sep 17 00:00:00 2001 From: Richard Weickelt Date: Thu, 8 Feb 2018 10:55:53 +0100 Subject: [PATCH 227/485] Undo unnecessary makefile edit --- arch/cpu/arm/Makefile.arm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/cpu/arm/Makefile.arm b/arch/cpu/arm/Makefile.arm index dd00aae6d..0c71d63fa 100644 --- a/arch/cpu/arm/Makefile.arm +++ b/arch/cpu/arm/Makefile.arm @@ -26,7 +26,7 @@ SMALL ?= 1 ifeq ($(SMALL),1) CFLAGS += -Os else - CFLAGS += -O0 + CFLAGS += -O2 endif ### Use CMSIS and the existing dbg-io from arch/cpu/arm/common From 2b0091246dd48f7a764b652c4c56fff25c5e3550 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Thu, 8 Feb 2018 12:42:06 +0100 Subject: [PATCH 228/485] UART0 arch driver impl * Async read * Renamed driver to uart0-arch * Renamed arch/cpu source folder to dev/ --- arch/cpu/simplelink/Makefile.simplelink | 11 ++----- .../simplelink/{source => dev}/clock-arch.c | 0 arch/cpu/simplelink/{source => dev}/dbg.h | 0 .../simplelink/{source => dev}/debug-uart.h | 0 .../simplelink/{source => dev}/putchar-arch.c | 16 +++++----- .../simplelink/{source => dev}/rtimer-arch.c | 0 .../simplelink/{source => dev}/rtimer-arch.h | 0 .../simplelink-uart.c => dev/uart0-arch.c} | 31 ++++++++++--------- .../simplelink-uart.h => dev/uart0-arch.h} | 14 ++++----- .../{source => dev}/watchdog-arch.c | 0 arch/platform/simplelink/platform.c | 4 +-- 11 files changed, 36 insertions(+), 40 deletions(-) rename arch/cpu/simplelink/{source => dev}/clock-arch.c (100%) rename arch/cpu/simplelink/{source => dev}/dbg.h (100%) rename arch/cpu/simplelink/{source => dev}/debug-uart.h (100%) rename arch/cpu/simplelink/{source => dev}/putchar-arch.c (88%) rename arch/cpu/simplelink/{source => dev}/rtimer-arch.c (100%) rename arch/cpu/simplelink/{source => dev}/rtimer-arch.h (100%) rename arch/cpu/simplelink/{source/simplelink-uart.c => dev/uart0-arch.c} (83%) rename arch/cpu/simplelink/{source/simplelink-uart.h => dev/uart0-arch.h} (90%) rename arch/cpu/simplelink/{source => dev}/watchdog-arch.c (100%) diff --git a/arch/cpu/simplelink/Makefile.simplelink b/arch/cpu/simplelink/Makefile.simplelink index 23681367c..ecc5d5272 100644 --- a/arch/cpu/simplelink/Makefile.simplelink +++ b/arch/cpu/simplelink/Makefile.simplelink @@ -55,19 +55,14 @@ endif ### CPU-dependent directories CONTIKI_ARM_DIRS += . common/dbg-io CONTIKI_CPU_DIRS += . $(addprefix ../arm/, $(CPU_DIRS)) -CONTIKI_CPU_DIRS += source +CONTIKI_CPU_DIRS += dev ### CPU-dependent source files CONTIKI_CPU_SOURCEFILES += rtimer-arch.c clock-arch.c CONTIKI_CPU_SOURCEFILES += watchdog-arch.c putchar-arch.c -CONTIKI_CPU_SOURCEFILES += simplelink-uart.c -# CONTIKI_CPU_SOURCEFILES += contiki-watchdog.c aux-ctrl.c -# CONTIKI_CPU_SOURCEFILES += putchar.c ieee-addr.c batmon-sensor.c adc-sensor.c -# CONTIKI_CPU_SOURCEFILES += slip-arch.c slip.c cc26xx-uart.c lpm.c -# CONTIKI_CPU_SOURCEFILES += gpio-interrupt.c oscillators.c -# CONTIKI_CPU_SOURCEFILES += rf-core.c rf-ble.c ieee-mode.c -# CONTIKI_CPU_SOURCEFILES += random.c soc-trng.c int-master.c +CONTIKI_CPU_SOURCEFILES += uart0-arch.c +### CPU-dependent debug source files DEBUG_IO_SOURCEFILES += dbg-printf.c dbg-snprintf.c dbg-sprintf.c strformat.c CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES) $(DEBUG_IO_SOURCEFILES) diff --git a/arch/cpu/simplelink/source/clock-arch.c b/arch/cpu/simplelink/dev/clock-arch.c similarity index 100% rename from arch/cpu/simplelink/source/clock-arch.c rename to arch/cpu/simplelink/dev/clock-arch.c diff --git a/arch/cpu/simplelink/source/dbg.h b/arch/cpu/simplelink/dev/dbg.h similarity index 100% rename from arch/cpu/simplelink/source/dbg.h rename to arch/cpu/simplelink/dev/dbg.h diff --git a/arch/cpu/simplelink/source/debug-uart.h b/arch/cpu/simplelink/dev/debug-uart.h similarity index 100% rename from arch/cpu/simplelink/source/debug-uart.h rename to arch/cpu/simplelink/dev/debug-uart.h diff --git a/arch/cpu/simplelink/source/putchar-arch.c b/arch/cpu/simplelink/dev/putchar-arch.c similarity index 88% rename from arch/cpu/simplelink/source/putchar-arch.c rename to arch/cpu/simplelink/dev/putchar-arch.c index b440e2b41..d5dd4ac49 100644 --- a/arch/cpu/simplelink/source/putchar-arch.c +++ b/arch/cpu/simplelink/dev/putchar-arch.c @@ -31,7 +31,7 @@ #include #include -#include "simplelink-uart.h" +#include "uart0-arch.h" #undef putchar @@ -41,7 +41,7 @@ int putchar(int c) { const unsigned char ch = (unsigned char)c; - return (simplelink_uart_write(&ch, 1) == 1) + return (uart0_write(&ch, 1) == 1) ? (int)ch : EOF; } @@ -49,7 +49,7 @@ putchar(int c) int puts(const char *str) { - if(!str) + if(!str) { return EOF; } @@ -57,8 +57,8 @@ puts(const char *str) const size_t len = strlen(str); const unsigned char newline = '\n'; - if ((simplelink_uart_write(str, len) != len) && - (simplelink_uart_write(&newline, 1) != 1)) + if ((uart0_write(str, len) != len) && + (uart0_write(&newline, 1) != 1)) { return EOF; } @@ -69,15 +69,15 @@ puts(const char *str) unsigned int dbg_send_bytes(const unsigned char *s, unsigned int len) { - if(!s || strlen((const char *)s) < len) + if(!s || strlen((const char *)s) < len) { return EOF; } const unsigned char newline = '\n'; - if ((simplelink_uart_write(s, len) != len) && - (simplelink_uart_write(&newline, 1) != 1)) + if ((uart0_write(s, len) != len) && + (uart0_write(&newline, 1) != 1)) { return EOF; } diff --git a/arch/cpu/simplelink/source/rtimer-arch.c b/arch/cpu/simplelink/dev/rtimer-arch.c similarity index 100% rename from arch/cpu/simplelink/source/rtimer-arch.c rename to arch/cpu/simplelink/dev/rtimer-arch.c diff --git a/arch/cpu/simplelink/source/rtimer-arch.h b/arch/cpu/simplelink/dev/rtimer-arch.h similarity index 100% rename from arch/cpu/simplelink/source/rtimer-arch.h rename to arch/cpu/simplelink/dev/rtimer-arch.h diff --git a/arch/cpu/simplelink/source/simplelink-uart.c b/arch/cpu/simplelink/dev/uart0-arch.c similarity index 83% rename from arch/cpu/simplelink/source/simplelink-uart.c rename to arch/cpu/simplelink/dev/uart0-arch.c index 28fb80b53..b80e9c736 100644 --- a/arch/cpu/simplelink/source/simplelink-uart.c +++ b/arch/cpu/simplelink/dev/uart0-arch.c @@ -41,38 +41,39 @@ #include -#include "simplelink-uart.h" +#include "uart0-arch.h" static UART_Handle gh_uart; -static volatile InputCb g_input_cb; -static unsigned char g_charbuf; +static volatile uart0_input_cb g_input_cb; +static unsigned char g_char_buf; /*---------------------------------------------------------------------------*/ static void -uart_cb(UART_Handle handle, void *buf, size_t count) +uart0_cb(UART_Handle handle, void *buf, size_t count) { if (!g_input_cb) { return; } - const InputCb currCb = g_input_cb; - currCb(g_charbuf); + const uart0_input_cb currCb = g_input_cb; + currCb(g_char_buf); if (currCb == g_input_cb) { - UART_read(gh_uart, &g_charbuf, 1); + UART_read(gh_uart, &g_char_buf, 1); } } /*---------------------------------------------------------------------------*/ void -simplelink_uart_init(void) +uart0_init(void) { UART_init(); UART_Params params; UART_Params_init(¶ms); params.readMode = UART_MODE_CALLBACK; - params.writeMode = UART_MODE_BLOCKING ; - params.readCallback = uart_cb; - // TODO configure + params.writeMode = UART_MODE_BLOCKING; + params.readCallback = uart0_cb; + params.readDataMode = UART_DATA_TEXT; + params.readReturnMode = UART_RETURN_NEWLINE; gh_uart = UART_open(Board_UART0, ¶ms); if (!gh_uart) @@ -82,7 +83,7 @@ simplelink_uart_init(void) } /*---------------------------------------------------------------------------*/ int_fast32_t -simplelink_uart_write(const void *buffer, size_t size) +uart0_write(const void *buffer, size_t size) { if (!gh_uart) { @@ -92,18 +93,18 @@ simplelink_uart_write(const void *buffer, size_t size) } /*---------------------------------------------------------------------------*/ void -simplelink_uart_set_callback(InputCb input_cb) +uart0_set_callback(uart0_input_cb input_cb) { if (g_input_cb == input_cb) { return; } g_input_cb = input_cb; if (input_cb) { - UART_read(gh_uart, &g_charbuf, 1); + UART_read(gh_uart, &g_char_buf, 1); } else { - UART_readCancel(gh_uart); + UART_readCancel(gh_uart); } } /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/simplelink/source/simplelink-uart.h b/arch/cpu/simplelink/dev/uart0-arch.h similarity index 90% rename from arch/cpu/simplelink/source/simplelink-uart.h rename to arch/cpu/simplelink/dev/uart0-arch.h index 9e93dc317..7266a4db5 100644 --- a/arch/cpu/simplelink/source/simplelink-uart.h +++ b/arch/cpu/simplelink/dev/uart0-arch.h @@ -39,12 +39,12 @@ * \file * Header file for the CC13xx/CC26xx UART driver */ -#ifndef SIMPLELINK_UART_H_ -#define SIMPLELINK_UART_H_ +#ifndef UART0_ARCH_H_ +#define UART0_ARCH_H_ #include -typedef void (*InputCb)(unsigned char); +typedef int (*uart0_input_cb)(unsigned char); /*---------------------------------------------------------------------------*/ /** \name UART functions @@ -54,7 +54,7 @@ typedef void (*InputCb)(unsigned char); /** * \brief Initializes the UART driver */ -void simplelink_uart_init(void); +void uart0_init(void); /** * \brief Writes data from a memory buffer to the UART interface. @@ -63,7 +63,7 @@ void simplelink_uart_init(void); * \return Number of bytes that has been written to the UART. If an * error occurs, a negative value is returned. */ -int_fast32_t simplelink_uart_write(const void *buffer, size_t size); +int_fast32_t uart0_write(const void *buffer, size_t size); /** * \brief Reads data from the UART interface to a memory buffer. @@ -72,11 +72,11 @@ int_fast32_t simplelink_uart_write(const void *buffer, size_t size); * \return Number of bytes that has been written to the buffer. If an * error occurs, a negative value is returned. */ -void simplelink_uart_set_callback(InputCb input_cb); +void uart0_set_callback(uart0_input_cb input_cb); /** @} */ /*---------------------------------------------------------------------------*/ -#endif /* SIMPLELINK_UART_H_ */ +#endif /* UART0_ARCH_H_ */ /** * @} diff --git a/arch/cpu/simplelink/source/watchdog-arch.c b/arch/cpu/simplelink/dev/watchdog-arch.c similarity index 100% rename from arch/cpu/simplelink/source/watchdog-arch.c rename to arch/cpu/simplelink/dev/watchdog-arch.c diff --git a/arch/platform/simplelink/platform.c b/arch/platform/simplelink/platform.c index 74302bb17..9d09a072d 100644 --- a/arch/platform/simplelink/platform.c +++ b/arch/platform/simplelink/platform.c @@ -55,7 +55,7 @@ #include "contiki.h" #include "contiki-net.h" -#include "simplelink-uart.h" +#include "uart0-arch.h" //#include "leds.h" //#include "lpm.h" @@ -172,7 +172,7 @@ platform_init_stage_one() void platform_init_stage_two() { - simplelink_uart_init(); + uart0_init(); // random_init(0x1234); // From 5a6578b99f16a2109d712cd79729bf47f1f0be9f Mon Sep 17 00:00:00 2001 From: Richard Weickelt Date: Thu, 8 Feb 2018 13:00:09 +0100 Subject: [PATCH 229/485] Undo watchdog changes --- arch/cpu/simplelink/dev/watchdog-arch.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/cpu/simplelink/dev/watchdog-arch.c b/arch/cpu/simplelink/dev/watchdog-arch.c index 01a54c68e..ac137e577 100644 --- a/arch/cpu/simplelink/dev/watchdog-arch.c +++ b/arch/cpu/simplelink/dev/watchdog-arch.c @@ -109,7 +109,6 @@ lock_config(uint32_t status) void watchdog_init(void) { - return; WatchdogReloadSet(CONTIKI_WATCHDOG_TIMER_TOP); lock_config(LOCK_REGISTERS_UNLOCKED); } @@ -120,7 +119,6 @@ watchdog_init(void) void watchdog_start(void) { - return; uint32_t lock_status = unlock_config(); watchdog_periodic(); @@ -135,7 +133,6 @@ watchdog_start(void) void watchdog_periodic(void) { - return; WatchdogReloadSet(CONTIKI_WATCHDOG_TIMER_TOP); WatchdogIntClear(); } @@ -146,7 +143,6 @@ watchdog_periodic(void) void watchdog_stop(void) { - return; uint32_t lock_status = unlock_config(); WatchdogResetDisable(); @@ -160,7 +156,6 @@ watchdog_stop(void) void watchdog_reboot(void) { - return; watchdog_start(); while(1); } From 64f440a15f798686a8a1aa73bcff7630eb82e066 Mon Sep 17 00:00:00 2001 From: Richard Weickelt Date: Thu, 8 Feb 2018 11:45:47 +0100 Subject: [PATCH 230/485] Initial commit, doesn't compile --- arch/cpu/simplelink/Makefile.simplelink | 5 +- arch/cpu/simplelink/dev/rtimer-arch.c | 10 +- .../rf-settings/proprietary-rf-settings.c | 213 +++ .../rf-settings/proprietary-rf-settings.h | 29 + arch/cpu/simplelink/simplelink-conf.h | 1 + arch/cpu/simplelink/source/proprietary-rf.c | 1225 +++++++++++++++++ 6 files changed, 1474 insertions(+), 9 deletions(-) create mode 100644 arch/cpu/simplelink/rf-settings/proprietary-rf-settings.c create mode 100644 arch/cpu/simplelink/rf-settings/proprietary-rf-settings.h create mode 100644 arch/cpu/simplelink/source/proprietary-rf.c diff --git a/arch/cpu/simplelink/Makefile.simplelink b/arch/cpu/simplelink/Makefile.simplelink index ecc5d5272..fa3831541 100644 --- a/arch/cpu/simplelink/Makefile.simplelink +++ b/arch/cpu/simplelink/Makefile.simplelink @@ -1,4 +1,6 @@ +MODULES += os/net os/net/mac os/net/mac/framer + CPU_ABS_PATH = $(CONTIKI)/arch/cpu/simplelink SDK_SOURCE := $(SIMPLELINK_SDK)/source @@ -55,12 +57,13 @@ endif ### CPU-dependent directories CONTIKI_ARM_DIRS += . common/dbg-io CONTIKI_CPU_DIRS += . $(addprefix ../arm/, $(CPU_DIRS)) -CONTIKI_CPU_DIRS += dev +CONTIKI_CPU_DIRS += dev rf-settings ### CPU-dependent source files CONTIKI_CPU_SOURCEFILES += rtimer-arch.c clock-arch.c CONTIKI_CPU_SOURCEFILES += watchdog-arch.c putchar-arch.c CONTIKI_CPU_SOURCEFILES += uart0-arch.c +CONTIKI_CPU_SOURCEFILES += proprietary-rf.c proprietary-rf-settings.c ### CPU-dependent debug source files DEBUG_IO_SOURCEFILES += dbg-printf.c dbg-snprintf.c dbg-sprintf.c strformat.c diff --git a/arch/cpu/simplelink/dev/rtimer-arch.c b/arch/cpu/simplelink/dev/rtimer-arch.c index 5f56b8359..c52eef128 100644 --- a/arch/cpu/simplelink/dev/rtimer-arch.c +++ b/arch/cpu/simplelink/dev/rtimer-arch.c @@ -46,12 +46,6 @@ #include - -// FIXME NB TEMPORARY HACK START -#include "radio.h" -const struct radio_driver ieee_mode_driver = { 0 }; -// FIXME NB TEMPORARY HACK END - #define RTIMER_RTC_CH AON_RTC_CH1 static ClockP_Struct gClk; @@ -83,7 +77,7 @@ rtimer_isr_hook(void) } if (hwiDispatch && AONRTCEventGet(AON_RTC_CH0)) { - hwiDispatch(); + hwiDispatch(); } else { @@ -116,7 +110,7 @@ rtimer_arch_init(void) { for (;;) { /* hang */ } } - + // Override the INT_AON_RTC_COMB int num with own ISR hook IntRegister(INT_AON_RTC_COMB, rtimer_isr_hook); diff --git a/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.c b/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.c new file mode 100644 index 000000000..38ee56181 --- /dev/null +++ b/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.c @@ -0,0 +1,213 @@ +//********************************************************************************* +// Generated by SmartRF Studio version 2.8.0 ( build #41) +// Compatible with SimpleLink SDK version: CC13x2 SDK 1.60.xx.xx +// Device: CC1352 Rev. 1.0 +// +//********************************************************************************* + + +//********************************************************************************* +// Parameter summary +// Address: off +// Address0: 0xAA +// Address1: 0xBB +// Frequency: 868.00000 MHz +// Data Format: Serial mode disable +// Deviation: 25.000 kHz +// pktLen: 30 +// 802.15.4g Mode: off +// Select bit order to transmit PSDU octets:: 1 +// Packet Length Config: Variable +// Max Packet Length: 255 +// Packet Length: 30 +// RX Filter BW: 98.0 kHz +// Symbol Rate: 50.00000 kBaud +// Sync Word Length: 32 Bits +// TX Power: 14 dBm (requires define CCFG_FORCE_VDDR_HH = 1 in ccfg.c, see CC13xx/CC26xx Technical Reference Manual) +// Whitening: No whitening + +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h) +#include +#include DeviceFamily_constructPath(rf_patches/rf_patch_cpe_prop.h) +#include DeviceFamily_constructPath(rf_patches/rf_patch_rfe_genfsk.h) +#include DeviceFamily_constructPath(rf_patches/rf_patch_mce_genfsk.h) +#include "proprietary-rf-settings.h" + + +// TI-RTOS RF Mode Object +RF_Mode RF_prop = +{ + .rfMode = RF_MODE_AUTO, + .cpePatchFxn = &rf_patch_cpe_prop, + .mcePatchFxn = &rf_patch_mce_genfsk, + .rfePatchFxn = &rf_patch_rfe_genfsk, +}; + +// Overrides for CMD_PROP_RADIO_DIV_SETUP +static uint32_t pOverrides[] = +{ + // override_use_patch_prop_genfsk.xml + // PHY: Use MCE RAM patch, RFE RAM patch + MCE_RFE_OVERRIDE(1,0,0,1,0,0), + // override_synth_prop_863_930_div5.xml + // Synth: Use 48 MHz crystal as synth clock, enable extra PLL filtering + (uint32_t)0x02400403, + // Synth: Set minimum RTRIM to 7 + (uint32_t)0x00078793, + // Synth: Configure extra PLL filtering + (uint32_t)0x00108463, + // Synth: Set Fref to 4 MHz + (uint32_t)0x000684A3, + // Synth: Set loop bandwidth after lock to 20 kHz + (uint32_t)0x0A480583, + // Synth: Set loop bandwidth after lock to 20 kHz + (uint32_t)0x7AB80603, + // override_phy_tx_pa_ramp_genfsk.xml + // Tx: Configure PA ramping, set wait time before turning off (0x2F ticks à 16/24 us = 31.3 us). + HW_REG_OVERRIDE(0x6028,0x002F), + // Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[3]=1) + ADI_HALFREG_OVERRIDE(0,16,0x8,0x8), + // Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[4]=1) + ADI_HALFREG_OVERRIDE(0,17,0x1,0x1), + // override_phy_rx_aaf_bw_0xd.xml + // Rx: Set anti-aliasing filter bandwidth to 0xD (in ADI0, set IFAMPCTL3[7:4]=0xD) + ADI_HALFREG_OVERRIDE(0,61,0xF,0xD), + // override_phy_rx_rssi_offset_neg2db.xml + // Rx: Set RSSI offset to adjust reported RSSI by -2 dB + (uint32_t)0x000288A3, + // TX power override + // DC/DC regulator: In Tx with 14 dBm PA setting, use DCDCCTL5[3:0]=0xF (DITHER_EN=1 and IPEAK=7). In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). + (uint32_t)0xFFFC08C3, + (uint32_t)0xFFFFFFFF, +}; + + +// CMD_PROP_RADIO_DIV_SETUP +// Proprietary Mode Radio Setup Command for All Frequency Bands +rfc_CMD_PROP_RADIO_DIV_SETUP_t RF_cmdPropRadioDivSetup = +{ + .commandNo = 0x3807, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .modulation.modType = 0x1, + .modulation.deviation = 0x64, + .modulation.deviationStepSz = 0x0, + .symbolRate.preScale = 0xF, + .symbolRate.rateWord = 0x8000, + .symbolRate.decimMode = 0x0, + .rxBw = 0x52, + .preamConf.nPreamBytes = 0x4, + .preamConf.preamMode = 0x0, + .formatConf.nSwBits = 0x20, + .formatConf.bBitReversal = 0x0, + .formatConf.bMsbFirst = 0x1, + .formatConf.fecMode = 0x0, + .formatConf.whitenMode = 0x0, + .config.frontEndMode = 0x0, + .config.biasMode = 0x1, + .config.analogCfgMode = 0x0, + .config.bNoFsPowerUp = 0x0, + .txPower = 0x9F3F, + .pRegOverride = pOverrides, + .centerFreq = 0x0364, + .intFreq = 0x8000, + .loDivider = 0x05, +}; + +// CMD_FS +// Frequency Synthesizer Programming Command +rfc_CMD_FS_t RF_cmdFs = +{ + .commandNo = 0x0803, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .frequency = 0x0364, + .fractFreq = 0x0000, + .synthConf.bTxMode = 0x0, + .synthConf.refFreq = 0x0, + .__dummy0 = 0x00, + .__dummy1 = 0x00, + .__dummy2 = 0x00, + .__dummy3 = 0x0000, +}; + +// CMD_PROP_TX +// Proprietary Mode Transmit Command +rfc_CMD_PROP_TX_t RF_cmdPropTx = +{ + .commandNo = 0x3801, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .pktConf.bFsOff = 0x0, + .pktConf.bUseCrc = 0x1, + .pktConf.bVarLen = 0x1, + .pktLen = 0x1E, // SET APPLICATION PAYLOAD LENGTH + .syncWord = 0x930B51DE, + .pPkt = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx +}; + +// CMD_PROP_RX +// Proprietary Mode Receive Command +rfc_CMD_PROP_RX_t RF_cmdPropRx = +{ + .commandNo = 0x3802, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .pktConf.bFsOff = 0x0, + .pktConf.bRepeatOk = 0x0, + .pktConf.bRepeatNok = 0x0, + .pktConf.bUseCrc = 0x1, + .pktConf.bVarLen = 0x1, + .pktConf.bChkAddress = 0x0, + .pktConf.endType = 0x0, + .pktConf.filterOp = 0x0, + .rxConf.bAutoFlushIgnored = 0x0, + .rxConf.bAutoFlushCrcErr = 0x0, + .rxConf.bIncludeHdr = 0x1, + .rxConf.bIncludeCrc = 0x0, + .rxConf.bAppendRssi = 0x0, + .rxConf.bAppendTimestamp = 0x0, + .rxConf.bAppendStatus = 0x1, + .syncWord = 0x930B51DE, + .maxPktLen = 0xFF, // MAKE SURE DATA ENTRY IS LARGE ENOUGH + .address0 = 0xAA, + .address1 = 0xBB, + .endTrigger.triggerType = 0x1, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, + .pQueue = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx + .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx +}; diff --git a/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.h b/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.h new file mode 100644 index 000000000..456804fb7 --- /dev/null +++ b/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.h @@ -0,0 +1,29 @@ +#ifndef _PROPRIETARY_RF_SETTINGS_H_ +#define _PROPRIETARY_RF_SETTINGS_H_ + +//********************************************************************************* +// Generated by SmartRF Studio version 2.8.0 ( build #41) +// Compatible with SimpleLink SDK version: CC13x2 SDK 1.60.xx.xx +// Device: CC1352 Rev. 1.0 +// +//********************************************************************************* +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h) +#include + + +// TI-RTOS RF Mode Object +extern RF_Mode RF_prop; + + +// RF Core API commands +extern rfc_CMD_PROP_RADIO_DIV_SETUP_t RF_cmdPropRadioDivSetup; +extern rfc_CMD_FS_t RF_cmdFs; +extern rfc_CMD_PROP_TX_t RF_cmdPropTx; +extern rfc_CMD_PROP_RX_t RF_cmdPropRx; + + +#endif // _PROPRIETARY_RF_SETTINGS_H_ + diff --git a/arch/cpu/simplelink/simplelink-conf.h b/arch/cpu/simplelink/simplelink-conf.h index 1db50738f..17ea011a2 100644 --- a/arch/cpu/simplelink/simplelink-conf.h +++ b/arch/cpu/simplelink/simplelink-conf.h @@ -91,6 +91,7 @@ #else /* CC13XX_CONF_PROP_MODE */ #define NETSTACK_CONF_RADIO ieee_mode_driver +#error BLABLA #define CSMA_CONF_SEND_SOFT_ACK 0 #endif /* CC13XX_CONF_PROP_MODE */ diff --git a/arch/cpu/simplelink/source/proprietary-rf.c b/arch/cpu/simplelink/source/proprietary-rf.c new file mode 100644 index 000000000..d821bf1d9 --- /dev/null +++ b/arch/cpu/simplelink/source/proprietary-rf.c @@ -0,0 +1,1225 @@ +/* + * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup rf-core-prop + * @{ + * + * \file + * Implementation of the CC13xx prop mode NETSTACK_RADIO driver + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "net/packetbuf.h" +#include "net/netstack.h" +#include "sys/energest.h" +#include "sys/clock.h" +#include "sys/rtimer.h" +#include "sys/cc.h" +/*---------------------------------------------------------------------------*/ +/* RF core and RF HAL API */ +#include +#include +/*---------------------------------------------------------------------------*/ +/* RF Core Mailbox API */ +#include +#include +#include +#include +#include +#include +#include +/*---------------------------------------------------------------------------*/ +#include +#include +#include +#include +/*---------------------------------------------------------------------------*/ +#define DEBUG 0 +#if DEBUG +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif +/*---------------------------------------------------------------------------*/ +/* Data entry status field constants */ +#define DATA_ENTRY_STATUS_PENDING 0x00 /* Not in use by the Radio CPU */ +#define DATA_ENTRY_STATUS_ACTIVE 0x01 /* Open for r/w by the radio CPU */ +#define DATA_ENTRY_STATUS_BUSY 0x02 /* Ongoing r/w */ +#define DATA_ENTRY_STATUS_FINISHED 0x03 /* Free to use and to free */ +#define DATA_ENTRY_STATUS_UNFINISHED 0x04 /* Partial RX entry */ +/*---------------------------------------------------------------------------*/ +/* Data whitener. 1: Whitener, 0: No whitener */ +#ifdef PROP_MODE_CONF_DW +#define PROP_MODE_DW PROP_MODE_CONF_DW +#else +#define PROP_MODE_DW 0 +#endif + +#ifdef PROP_MODE_CONF_USE_CRC16 +#define PROP_MODE_USE_CRC16 PROP_MODE_CONF_USE_CRC16 +#else +#define PROP_MODE_USE_CRC16 0 +#endif +/*---------------------------------------------------------------------------*/ +/** + * \brief Returns the current status of a running Radio Op command + * \param a A pointer with the buffer used to initiate the command + * \return The value of the Radio Op buffer's status field + * + * This macro can be used to e.g. return the status of a previously + * initiated background operation, or of an immediate command + */ +#define RF_RADIO_OP_GET_STATUS(a) GET_FIELD_V(a, radioOp, status) +/*---------------------------------------------------------------------------*/ +/* Special value returned by CMD_IEEE_CCA_REQ when an RSSI is not available */ +#define RF_CMD_CCA_REQ_RSSI_UNKNOWN -128 + +/* Used for the return value of channel_clear */ +#define RF_CCA_CLEAR 1 +#define RF_CCA_BUSY 0 + +/* Used as an error return value for get_cca_info */ +#define RF_GET_CCA_INFO_ERROR 0xFF + +/* + * Values of the individual bits of the ccaInfo field in CMD_IEEE_CCA_REQ's + * status struct + */ +#define RF_CMD_CCA_REQ_CCA_STATE_IDLE 0 /* 00 */ +#define RF_CMD_CCA_REQ_CCA_STATE_BUSY 1 /* 01 */ +#define RF_CMD_CCA_REQ_CCA_STATE_INVALID 2 /* 10 */ + +#ifdef PROP_MODE_CONF_RSSI_THRESHOLD +#define PROP_MODE_RSSI_THRESHOLD PROP_MODE_CONF_RSSI_THRESHOLD +#else +#define PROP_MODE_RSSI_THRESHOLD 0xA6 +#endif + +static int8_t rssi_threshold = PROP_MODE_RSSI_THRESHOLD; +/*---------------------------------------------------------------------------*/ +static int on(void); +static int off(void); + +static rfc_propRxOutput_t rx_stats; +/*---------------------------------------------------------------------------*/ +/* Defines and variables related to the .15.4g PHY HDR */ +#define DOT_4G_MAX_FRAME_LEN 2047 +#define DOT_4G_PHR_LEN 2 + +/* PHY HDR bits */ +#define DOT_4G_PHR_CRC16 0x10 +#define DOT_4G_PHR_DW 0x08 + +#if PROP_MODE_USE_CRC16 +/* CRC16 */ +#define DOT_4G_PHR_CRC_BIT DOT_4G_PHR_CRC16 +#define CRC_LEN 2 +#else +/* CRC32 */ +#define DOT_4G_PHR_CRC_BIT 0 +#define CRC_LEN 4 +#endif + +#if PROP_MODE_DW +#define DOT_4G_PHR_DW_BIT DOT_4G_PHR_DW +#else +#define DOT_4G_PHR_DW_BIT 0 +#endif +/*---------------------------------------------------------------------------*/ +/* How long to wait for an ongoing ACK TX to finish before starting frame TX */ +#define TX_WAIT_TIMEOUT (RTIMER_SECOND >> 11) + +/* How long to wait for the RF to enter RX in rf_cmd_ieee_rx */ +#define ENTER_RX_WAIT_TIMEOUT (RTIMER_SECOND >> 10) +/*---------------------------------------------------------------------------*/ +/* TX power table for the 431-527MHz band */ +#ifdef PROP_MODE_CONF_TX_POWER_431_527 +#define PROP_MODE_TX_POWER_431_527 PROP_MODE_CONF_TX_POWER_431_527 +#else +#define PROP_MODE_TX_POWER_431_527 prop_mode_tx_power_431_527 +#endif +/*---------------------------------------------------------------------------*/ +/* TX power table for the 779-930MHz band */ +#ifdef PROP_MODE_CONF_TX_POWER_779_930 +#define PROP_MODE_TX_POWER_779_930 PROP_MODE_CONF_TX_POWER_779_930 +#else +#define PROP_MODE_TX_POWER_779_930 prop_mode_tx_power_779_930 +#endif +/*---------------------------------------------------------------------------*/ +/* Select power table based on the frequency band */ +#if DOT_15_4G_FREQUENCY_BAND_ID==DOT_15_4G_FREQUENCY_BAND_470 +#define TX_POWER_DRIVER PROP_MODE_TX_POWER_431_527 +#else +#define TX_POWER_DRIVER PROP_MODE_TX_POWER_779_930 +#endif +/*---------------------------------------------------------------------------*/ +extern const prop_mode_tx_power_config_t TX_POWER_DRIVER[]; + +/* Max and Min Output Power in dBm */ +#define OUTPUT_POWER_MAX (TX_POWER_DRIVER[0].dbm) +#define OUTPUT_POWER_UNKNOWN 0xFFFF + +/* Default TX Power - position in output_power[] */ +static const prop_mode_tx_power_config_t *tx_power_current = &TX_POWER_DRIVER[1]; +/*---------------------------------------------------------------------------*/ +#ifdef PROP_MODE_CONF_LO_DIVIDER +#define PROP_MODE_LO_DIVIDER PROP_MODE_CONF_LO_DIVIDER +#else +#define PROP_MODE_LO_DIVIDER 0x05 +#endif +/*---------------------------------------------------------------------------*/ +#ifdef PROP_MODE_CONF_RX_BUF_CNT +#define PROP_MODE_RX_BUF_CNT PROP_MODE_CONF_RX_BUF_CNT +#else +#define PROP_MODE_RX_BUF_CNT 4 +#endif +/*---------------------------------------------------------------------------*/ +#define DATA_ENTRY_LENSZ_NONE 0 +#define DATA_ENTRY_LENSZ_BYTE 1 +#define DATA_ENTRY_LENSZ_WORD 2 /* 2 bytes */ + +/* + * RX buffers. + * PROP_MODE_RX_BUF_CNT buffers of RX_BUF_SIZE bytes each. The start of each + * buffer must be 4-byte aligned, therefore RX_BUF_SIZE must divide by 4 + */ +#define RX_BUF_SIZE 140 +static uint8_t rx_buf[PROP_MODE_RX_BUF_CNT][RX_BUF_SIZE] CC_ALIGN(4); + +/* The RX Data Queue */ +static dataQueue_t rx_data_queue = { 0 }; + +/* Receive entry pointer to keep track of read items */ +volatile static uint8_t *rx_read_entry; +/*---------------------------------------------------------------------------*/ +/* The outgoing frame buffer */ +#define TX_BUF_PAYLOAD_LEN 180 +#define TX_BUF_HDR_LEN 2 + +static uint8_t tx_buf[TX_BUF_HDR_LEN + TX_BUF_PAYLOAD_LEN] CC_ALIGN(4); +/*---------------------------------------------------------------------------*/ +/* RF driver */ +RF_Object rfObject; +RF_Handle handle; +/*---------------------------------------------------------------------------*/ +/* CMD_PROP_TX_ADV */ +rfc_CMD_PROP_TX_ADV_t smartrf_settings_cmd_prop_tx_adv = +{ + .commandNo = 0x3803, + .status = 0x0000, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .pktConf.bFsOff = 0x0, + .pktConf.bUseCrc = 0x1, + .pktConf.bCrcIncSw = 0x0, /* .4g mode */ + .pktConf.bCrcIncHdr = 0x0, /* .4g mode */ + .numHdrBits = 0x10 /* 16: .4g mode */, + .pktLen = 0x0000, + .startConf.bExtTxTrig = 0x0, + .startConf.inputMode = 0x0, + .startConf.source = 0x0, + .preTrigger.triggerType = TRIG_REL_START, + .preTrigger.bEnaCmd = 0x0, + .preTrigger.triggerNo = 0x0, + .preTrigger.pastTrig = 0x1, + .preTime = 0x00000000, + .syncWord = 0x0055904e, + .pPkt = 0, +}; +/*---------------------------------------------------------------------------*/ +/* CMD_PROP_RX_ADV */ +rfc_CMD_PROP_RX_ADV_t smartrf_settings_cmd_prop_rx_adv = +{ + .commandNo = 0x3804, + .status = 0x0000, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .pktConf.bFsOff = 0x0, + .pktConf.bRepeatOk = 0x1, + .pktConf.bRepeatNok = 0x1, + .pktConf.bUseCrc = 0x1, + .pktConf.bCrcIncSw = 0x0, /* .4g mode */ + .pktConf.bCrcIncHdr = 0x0, /* .4g mode */ + .pktConf.endType = 0x0, + .pktConf.filterOp = 0x1, + .rxConf.bAutoFlushIgnored = 0x1, + .rxConf.bAutoFlushCrcErr = 0x1, + .rxConf.bIncludeHdr = 0x0, + .rxConf.bIncludeCrc = 0x0, + .rxConf.bAppendRssi = 0x1, + .rxConf.bAppendTimestamp = 0x0, + .rxConf.bAppendStatus = 0x1, + .syncWord0 = 0x0055904e, + .syncWord1 = 0x00000000, + .maxPktLen = 0x0000, /* To be populated by the driver. */ + .hdrConf.numHdrBits = 0x10, /* 16: .4g mode */ + .hdrConf.lenPos = 0x0, /* .4g mode */ + .hdrConf.numLenBits = 0x0B, /* 11 = 0x0B .4g mode */ + .addrConf.addrType = 0x0, + .addrConf.addrSize = 0x0, + .addrConf.addrPos = 0x0, + .addrConf.numAddr = 0x0, + .lenOffset = -4, /* .4g mode */ + .endTrigger.triggerType = TRIG_NEVER, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, + .pAddr = 0, + .pQueue = 0, + .pOutput = 0, +}; +/*---------------------------------------------------------------------------*/ + + +static uint8_t +transmitting(void) +{ + return smartrf_settings_cmd_prop_tx_adv.status == RF_CORE_RADIO_OP_STATUS_ACTIVE; +} +/*---------------------------------------------------------------------------*/ +static radio_value_t +get_rssi(void) +{ + uint32_t cmd_status; + int8_t rssi; + uint8_t attempts = 0; + uint8_t was_off = 0; + rfc_CMD_GET_RSSI_t cmd; + + /* If we are off, turn on first */ + if(!rf_is_on()) { + was_off = 1; + if(on() != RF_CORE_CMD_OK) { + PRINTF("get_rssi: on() failed\n"); + return RF_CMD_CCA_REQ_RSSI_UNKNOWN; + } + } + + rssi = RF_CMD_CCA_REQ_RSSI_UNKNOWN; + + while((rssi == RF_CMD_CCA_REQ_RSSI_UNKNOWN || rssi == 0) && ++attempts < 10) { + memset(&cmd, 0x00, sizeof(cmd)); + cmd.commandNo = CMD_GET_RSSI; + + if(rf_core_send_cmd((uint32_t)&cmd, &cmd_status) == RF_CORE_CMD_ERROR) { + PRINTF("get_rssi: CMDSTA=0x%08lx\n", cmd_status); + break; + } else { + /* Current RSSI in bits 23:16 of cmd_status */ + rssi = (cmd_status >> 16) & 0xFF; + } + } + + /* If we were off, turn back off */ + if(was_off) { + off(); + } + + return rssi; +} +/*---------------------------------------------------------------------------*/ +static uint8_t +get_channel(void) +{ + uint32_t freq_khz; + + freq_khz = smartrf_settings_cmd_fs.frequency * 1000; + + /* + * For some channels, fractFreq * 1000 / 65536 will return 324.99xx. + * Casting the result to uint32_t will truncate decimals resulting in the + * function returning channel - 1 instead of channel. Thus, we do a quick + * positive integer round up. + */ + freq_khz += (((smartrf_settings_cmd_fs.fractFreq * 1000) + 65535) / 65536); + + return (freq_khz - DOT_15_4G_CHAN0_FREQUENCY) / DOT_15_4G_CHANNEL_SPACING; +} +/*---------------------------------------------------------------------------*/ +static void +set_channel(uint8_t channel) +{ + uint32_t new_freq; + uint16_t freq, frac; + + new_freq = DOT_15_4G_CHAN0_FREQUENCY + (channel * DOT_15_4G_CHANNEL_SPACING); + + freq = (uint16_t)(new_freq / 1000); + frac = (new_freq - (freq * 1000)) * 65536 / 1000; + + PRINTF("set_channel: %u = 0x%04x.0x%04x (%lu)\n", channel, freq, frac, + new_freq); + + smartrf_settings_cmd_prop_radio_div_setup.centerFreq = freq; + smartrf_settings_cmd_fs.frequency = freq; + smartrf_settings_cmd_fs.fractFreq = frac; +} +/*---------------------------------------------------------------------------*/ +static uint8_t +get_tx_power_array_last_element(void) +{ + const prop_mode_tx_power_config_t *array = TX_POWER_DRIVER; + uint8_t count = 0; + + while(array->tx_power != OUTPUT_POWER_UNKNOWN) { + count++; + array++; + } + return count - 1; +} +/*---------------------------------------------------------------------------*/ +/* Returns the current TX power in dBm */ +static radio_value_t +get_tx_power(void) +{ + return tx_power_current->dbm; +} +/*---------------------------------------------------------------------------*/ +/* + * The caller must make sure to send a new CMD_PROP_RADIO_DIV_SETUP to the + * radio after calling this function. + */ +static void +set_tx_power(radio_value_t power) +{ + int i; + + for(i = get_tx_power_array_last_element(); i >= 0; --i) { + if(power <= TX_POWER_DRIVER[i].dbm) { + /* + * Merely save the value. It will be used in all subsequent usages of + * CMD_PROP_RADIO_DIV_SETP, including one immediately after this function + * has returned + */ + tx_power_current = &TX_POWER_DRIVER[i]; + + return; + } + } +} +/*---------------------------------------------------------------------------*/ +static int +prop_div_radio_setup(void) +{ + uint32_t cmd_status; + rfc_radioOp_t *cmd = (rfc_radioOp_t *)&smartrf_settings_cmd_prop_radio_div_setup; + + rf_switch_select_path(RF_SWITCH_PATH_SUBGHZ); + + /* Adjust loDivider depending on the selected band */ + smartrf_settings_cmd_prop_radio_div_setup.loDivider = PROP_MODE_LO_DIVIDER; + + /* Update to the correct TX power setting */ + smartrf_settings_cmd_prop_radio_div_setup.txPower = tx_power_current->tx_power; + + /* Adjust RF Front End and Bias based on the board */ + smartrf_settings_cmd_prop_radio_div_setup.config.frontEndMode = + RF_CORE_PROP_FRONT_END_MODE; + smartrf_settings_cmd_prop_radio_div_setup.config.biasMode = + RF_CORE_PROP_BIAS_MODE; + + /* Send Radio setup to RF Core */ + if(rf_core_send_cmd((uint32_t)cmd, &cmd_status) != RF_CORE_CMD_OK) { + PRINTF("prop_div_radio_setup: DIV_SETUP, CMDSTA=0x%08lx, status=0x%04x\n", + cmd_status, cmd->status); + return RF_CORE_CMD_ERROR; + } + + /* Wait until radio setup is done */ + if(rf_core_wait_cmd_done(cmd) != RF_CORE_CMD_OK) { + PRINTF("prop_div_radio_setup: DIV_SETUP wait, CMDSTA=0x%08lx," + "status=0x%04x\n", cmd_status, cmd->status); + return RF_CORE_CMD_ERROR; + } + + return RF_CORE_CMD_OK; +} +/*---------------------------------------------------------------------------*/ +static uint8_t +rf_cmd_prop_rx() +{ + uint32_t cmd_status; + rtimer_clock_t t0; + volatile rfc_CMD_PROP_RX_ADV_t *cmd_rx_adv; + int ret; + + cmd_rx_adv = (rfc_CMD_PROP_RX_ADV_t *)&smartrf_settings_cmd_prop_rx_adv; + cmd_rx_adv->status = RF_CORE_RADIO_OP_STATUS_IDLE; + + /* + * Set the max Packet length. This is for the payload only, therefore + * 2047 - length offset + */ + cmd_rx_adv->maxPktLen = DOT_4G_MAX_FRAME_LEN - cmd_rx_adv->lenOffset; + + ret = rf_core_send_cmd((uint32_t)cmd_rx_adv, &cmd_status); + + if(ret != RF_CORE_CMD_OK) { + PRINTF("rf_cmd_prop_rx: send_cmd ret=%d, CMDSTA=0x%08lx, status=0x%04x\n", + ret, cmd_status, cmd_rx_adv->status); + return RF_CORE_CMD_ERROR; + } + + t0 = RTIMER_NOW(); + + while(cmd_rx_adv->status != RF_CORE_RADIO_OP_STATUS_ACTIVE && + (RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + ENTER_RX_WAIT_TIMEOUT))); + + /* Wait to enter RX */ + if(cmd_rx_adv->status != RF_CORE_RADIO_OP_STATUS_ACTIVE) { + PRINTF("rf_cmd_prop_rx: CMDSTA=0x%08lx, status=0x%04x\n", + cmd_status, cmd_rx_adv->status); + return RF_CORE_CMD_ERROR; + } + + return ret; +} +/*---------------------------------------------------------------------------*/ +static void +init_rx_buffers(void) +{ + rfc_dataEntry_t *entry; + int i; + + for(i = 0; i < PROP_MODE_RX_BUF_CNT; i++) { + entry = (rfc_dataEntry_t *)rx_buf[i]; + entry->status = DATA_ENTRY_STATUS_PENDING; + entry->config.type = DATA_ENTRY_TYPE_GEN; + entry->config.lenSz = DATA_ENTRY_LENSZ_WORD; + entry->length = RX_BUF_SIZE - 8; + entry->pNextEntry = rx_buf[i + 1]; + } + + ((rfc_dataEntry_t *)rx_buf[PROP_MODE_RX_BUF_CNT - 1])->pNextEntry = rx_buf[0]; +} +/*---------------------------------------------------------------------------*/ +static int +rx_on_prop(void) +{ + int ret; + + if(rf_is_on()) { + PRINTF("rx_on_prop: We were on. PD=%u, RX=0x%04x\n", + rf_core_is_accessible(), smartrf_settings_cmd_prop_rx_adv.status); + return RF_CORE_CMD_OK; + } + + /* Put CPE in RX using the currently configured parameters */ + ret = rf_cmd_prop_rx(); + + if(ret) { + ENERGEST_ON(ENERGEST_TYPE_LISTEN); + } + + return ret; +} +/*---------------------------------------------------------------------------*/ +static int +rx_off_prop(void) +{ + uint32_t cmd_status; + int ret; + + /* If we are off, do nothing */ + if(!rf_is_on()) { + return RF_CORE_CMD_OK; + } + + /* Send a CMD_ABORT command to RF Core */ + if(rf_core_send_cmd(CMDR_DIR_CMD(CMD_ABORT), &cmd_status) != RF_CORE_CMD_OK) { + PRINTF("rx_off_prop: CMD_ABORT status=0x%08lx\n", cmd_status); + /* Continue nonetheless */ + } + + while(rf_is_on()); + + if(smartrf_settings_cmd_prop_rx_adv.status == PROP_DONE_STOPPED || + smartrf_settings_cmd_prop_rx_adv.status == PROP_DONE_ABORT) { + /* Stopped gracefully */ + ENERGEST_OFF(ENERGEST_TYPE_LISTEN); + ret = RF_CORE_CMD_OK; + } else { + PRINTF("rx_off_prop: status=0x%04x\n", + smartrf_settings_cmd_prop_rx_adv.status); + ret = RF_CORE_CMD_ERROR; + } + + return ret; +} +/*---------------------------------------------------------------------------*/ +static uint8_t +request(void) +{ + /* + * We rely on the RDC layer to turn us on and off. Thus, if we are on we + * will only allow sleep, standby otherwise + */ + if(rf_is_on()) { + return LPM_MODE_SLEEP; + } + + return LPM_MODE_MAX_SUPPORTED; +} +/*---------------------------------------------------------------------------*/ +LPM_MODULE(prop_lpm_module, request, NULL, NULL, LPM_DOMAIN_NONE); +/*---------------------------------------------------------------------------*/ +static int +prop_fs(void) +{ + uint32_t cmd_status; + rfc_radioOp_t *cmd = (rfc_radioOp_t *)&smartrf_settings_cmd_fs; + + /* Send the command to the RF Core */ + if(rf_core_send_cmd((uint32_t)cmd, &cmd_status) != RF_CORE_CMD_OK) { + PRINTF("prop_fs: CMD_FS, CMDSTA=0x%08lx, status=0x%04x\n", + cmd_status, cmd->status); + return RF_CORE_CMD_ERROR; + } + + /* Wait until the command is done */ + if(rf_core_wait_cmd_done(cmd) != RF_CORE_CMD_OK) { + PRINTF("prop_fs: CMD_FS wait, CMDSTA=0x%08lx, status=0x%04x\n", + cmd_status, cmd->status); + return RF_CORE_CMD_ERROR; + } + + return RF_CORE_CMD_OK; +} +/*---------------------------------------------------------------------------*/ +static void +soft_off_prop(void) +{ + uint32_t cmd_status; + volatile rfc_radioOp_t *cmd = rf_core_get_last_radio_op(); + + if(!rf_core_is_accessible()) { + return; + } + + /* Send a CMD_ABORT command to RF Core */ + if(rf_core_send_cmd(CMDR_DIR_CMD(CMD_ABORT), &cmd_status) != RF_CORE_CMD_OK) { + PRINTF("soft_off_prop: CMD_ABORT status=0x%08lx\n", cmd_status); + return; + } + + while((cmd->status & RF_CORE_RADIO_OP_MASKED_STATUS) == + RF_CORE_RADIO_OP_MASKED_STATUS_RUNNING); +} +/*---------------------------------------------------------------------------*/ +static uint8_t +soft_on_prop(void) +{ + if(prop_div_radio_setup() != RF_CORE_CMD_OK) { + PRINTF("soft_on_prop: prop_div_radio_setup() failed\n"); + return RF_CORE_CMD_ERROR; + } + + if(prop_fs() != RF_CORE_CMD_OK) { + PRINTF("soft_on_prop: prop_fs() failed\n"); + return RF_CORE_CMD_ERROR; + } + + return rx_on_prop(); +} +/*---------------------------------------------------------------------------*/ +static const rf_core_primary_mode_t mode_prop = { + soft_off_prop, + soft_on_prop, +}; +/*---------------------------------------------------------------------------*/ +static int +init(void) +{ + RF_Params params; + RF_Params_init(¶ms); + params.nInactivityTimeout = 0; // disable automatic power-down + + handle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, ¶ms); + assert(handle != NULL); + + /* Initialise RX buffers */ + memset(rx_buf, 0, sizeof(rx_buf)); + + /* Set of RF Core data queue. Circular buffer, no last entry */ + rx_data_queue.pCurrEntry = rx_buf[0]; + rx_data_queue.pLastEntry = NULL; + + /* Initialize current read pointer to first element (used in ISR) */ + rx_read_entry = rx_buf[0]; + + 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); + + if(on() != RF_CORE_CMD_OK) { + PRINTF("init: on() failed\n"); + return RF_CORE_CMD_ERROR; + } + + ENERGEST_ON(ENERGEST_TYPE_LISTEN); + + rf_core_primary_mode_register(&mode_prop); + + process_start(&rf_core_process, NULL); + + return 1; +} +/*---------------------------------------------------------------------------*/ +static int +prepare(const void *payload, unsigned short payload_len) +{ + int len = MIN(payload_len, TX_BUF_PAYLOAD_LEN); + + memcpy(&tx_buf[TX_BUF_HDR_LEN], payload, len); + return 0; +} +/*---------------------------------------------------------------------------*/ +static int +transmit(unsigned short transmit_len) +{ + int ret; + uint8_t was_off = 0; + uint32_t cmd_status; + volatile rfc_CMD_PROP_TX_ADV_t *cmd_tx_adv; + + /* Length in .15.4g PHY HDR. Includes the CRC but not the HDR itself */ + uint16_t total_length; + + if(!rf_is_on()) { + was_off = 1; + if(on() != RF_CORE_CMD_OK) { + PRINTF("transmit: on() failed\n"); + return RADIO_TX_ERR; + } + } + + /* + * Prepare the .15.4g PHY header + * MS=0, Length MSBits=0, DW and CRC configurable + * Total length = transmit_len (payload) + CRC length + * + * The Radio will flip the bits around, so tx_buf[0] must have the length + * LSBs (PHR[15:8] and tx_buf[1] will have PHR[7:0] + */ + total_length = transmit_len + CRC_LEN; + + tx_buf[0] = total_length & 0xFF; + tx_buf[1] = (total_length >> 8) + DOT_4G_PHR_DW_BIT + DOT_4G_PHR_CRC_BIT; + + /* Prepare the CMD_PROP_TX_ADV command */ + cmd_tx_adv = (rfc_CMD_PROP_TX_ADV_t *)&smartrf_settings_cmd_prop_tx_adv; + + /* + * pktLen: Total number of bytes in the TX buffer, including the header if + * one exists, but not including the CRC (which is not present in the buffer) + */ + cmd_tx_adv->pktLen = transmit_len + DOT_4G_PHR_LEN; + cmd_tx_adv->pPkt = tx_buf; + + /* Abort RX */ + rx_off_prop(); + + /* Enable the LAST_COMMAND_DONE interrupt to wake us up */ + rf_core_cmd_done_en(false, false); + + ret = rf_core_send_cmd((uint32_t)cmd_tx_adv, &cmd_status); + + if(ret) { + /* If we enter here, TX actually started */ + ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT); + + watchdog_periodic(); + + /* Idle away while the command is running */ + while((cmd_tx_adv->status & RF_CORE_RADIO_OP_MASKED_STATUS) + == RF_CORE_RADIO_OP_MASKED_STATUS_RUNNING) { + lpm_sleep(); + } + + if(cmd_tx_adv->status == RF_CORE_RADIO_OP_STATUS_PROP_DONE_OK) { + /* Sent OK */ + ret = RADIO_TX_OK; + } else { + /* Operation completed, but frame was not sent */ + PRINTF("transmit: Not Sent OK status=0x%04x\n", + cmd_tx_adv->status); + ret = RADIO_TX_ERR; + } + } else { + /* Failure sending the CMD_PROP_TX command */ + PRINTF("transmit: PROP_TX_ERR ret=%d, CMDSTA=0x%08lx, status=0x%04x\n", + ret, cmd_status, cmd_tx_adv->status); + ret = RADIO_TX_ERR; + } + + /* + * Update ENERGEST state here, before a potential call to off(), which + * will correctly update it if required. + */ + ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN); + + /* + * Disable LAST_FG_COMMAND_DONE interrupt. We don't really care about it + * except when we are transmitting + */ + rf_core_cmd_done_dis(false); + + /* Workaround. Set status to IDLE */ + cmd_tx_adv->status = RF_CORE_RADIO_OP_STATUS_IDLE; + + rx_on_prop(); + + if(was_off) { + off(); + } + + return ret; +} +/*---------------------------------------------------------------------------*/ +static int +send(const void *payload, unsigned short payload_len) +{ + prepare(payload, payload_len); + return transmit(payload_len); +} +/*---------------------------------------------------------------------------*/ +static int +read_frame(void *buf, unsigned short buf_len) +{ + rfc_dataEntryGeneral_t *entry = (rfc_dataEntryGeneral_t *)rx_read_entry; + uint8_t *data_ptr = &entry->data; + int len = 0; + + if(entry->status == DATA_ENTRY_STATUS_FINISHED) { + + /* + * First 2 bytes in the data entry are the length. + * Our data entry consists of: Payload + RSSI (1 byte) + Status (1 byte) + * This length includes all of those. + */ + len = (*(uint16_t *)data_ptr); + data_ptr += 2; + len -= 2; + + if(len > 0) { + if(len <= buf_len) { + memcpy(buf, data_ptr, len); + } + + packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (int8_t)data_ptr[len]); + packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, 0x7F); + } + + /* Move read entry pointer to next entry */ + rx_read_entry = entry->pNextEntry; + entry->status = DATA_ENTRY_STATUS_PENDING; + } + + return len; +} +/*---------------------------------------------------------------------------*/ +static int +channel_clear(void) +{ + uint8_t was_off = 0; + uint32_t cmd_status; + int8_t rssi = RF_CMD_CCA_REQ_RSSI_UNKNOWN; + + /* + * If we are in the middle of a BLE operation, we got called by ContikiMAC + * from within an interrupt context. Indicate a clear channel + */ + if(rf_ble_is_active() == RF_BLE_ACTIVE) { + return RF_CCA_CLEAR; + } + + if(!rf_core_is_accessible()) { + was_off = 1; + if(on() != RF_CORE_CMD_OK) { + PRINTF("channel_clear: on() failed\n"); + if(was_off) { + off(); + } + return RF_CCA_CLEAR; + } + } else { + if(transmitting()) { + PRINTF("channel_clear: called while in TX\n"); + return RF_CCA_CLEAR; + } + } + + while(rssi == RF_CMD_CCA_REQ_RSSI_UNKNOWN || rssi == 0) { + if(rf_core_send_cmd(CMDR_DIR_CMD(CMD_GET_RSSI), &cmd_status) + != RF_CORE_CMD_OK) { + break; + } + /* Current RSSI in bits 23:16 of cmd_status */ + rssi = (cmd_status >> 16) & 0xFF; + } + + if(was_off) { + off(); + } + + if(rssi >= rssi_threshold) { + return RF_CCA_BUSY; + } + + return RF_CCA_CLEAR; +} +/*---------------------------------------------------------------------------*/ +static int +receiving_packet(void) +{ + if(!rf_is_on()) { + return 0; + } + + if(channel_clear() == RF_CCA_CLEAR) { + return 0; + } + + return 1; +} +/*---------------------------------------------------------------------------*/ +static int +pending_packet(void) +{ + int rv = 0; + volatile rfc_dataEntry_t *entry = (rfc_dataEntry_t *)rx_data_queue.pCurrEntry; + + /* Go through all RX buffers and check their status */ + do { + if(entry->status == DATA_ENTRY_STATUS_FINISHED) { + rv += 1; + process_poll(&rf_core_process); + } + + entry = (rfc_dataEntry_t *)entry->pNextEntry; + } while(entry != (rfc_dataEntry_t *)rx_data_queue.pCurrEntry); + + /* If we didn't find an entry at status finished, no frames are pending */ + return rv; +} +/*---------------------------------------------------------------------------*/ +static int +on(void) +{ + /* + * If we are in the middle of a BLE operation, we got called by ContikiMAC + * from within an interrupt context. Abort, but pretend everything is OK. + */ + if(rf_ble_is_active() == RF_BLE_ACTIVE) { + return RF_CORE_CMD_OK; + } + + /* + * Request the HF XOSC as the source for the HF clock. Needed before we can + * use the FS. This will only request, it will _not_ perform the switch. + */ + oscillators_request_hf_xosc(); + + if(rf_is_on()) { + PRINTF("on: We were on. PD=%u, RX=0x%04x \n", rf_core_is_accessible(), + smartrf_settings_cmd_prop_rx_adv.status); + return RF_CORE_CMD_OK; + } + + if(!rf_core_is_accessible()) { + if(rf_core_power_up() != RF_CORE_CMD_OK) { + PRINTF("on: rf_core_power_up() failed\n"); + + rf_core_power_down(); + + return RF_CORE_CMD_ERROR; + } + + /* Keep track of RF Core mode */ + rf_core_set_modesel(); + + /* Apply patches to radio core */ + rf_patch_cpe_genfsk(); + while(!HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFACKIFG)); + HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFACKIFG) = 0; + rf_patch_rfe_genfsk(); + + /* Initialize bus request */ + HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFACKIFG) = 0; + HWREG(RFC_DBELL_BASE + RFC_DBELL_O_CMDR) = + CMDR_DIR_CMD_1BYTE(CMD_BUS_REQUEST, 1); + + /* set VCOLDO reference */ + ti_lib_rfc_adi3vco_ldo_voltage_mode(true); + + /* Let CC13xxware automatically set a correct value for RTRIM for us */ + ti_lib_rfc_rtrim((rfc_radioOp_t *)&smartrf_settings_cmd_prop_radio_div_setup); + + /* Make sure BUS_REQUEST is done */ + while(!HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFACKIFG)); + HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFACKIFG) = 0; + + if(rf_core_start_rat() != RF_CORE_CMD_OK) { + PRINTF("on: rf_core_start_rat() failed\n"); + + rf_core_power_down(); + + return RF_CORE_CMD_ERROR; + } + } + + rf_core_setup_interrupts(false); + + init_rx_buffers(); + + /* + * Trigger a switch to the XOSC, so that we can subsequently use the RF FS + * This will block until the XOSC is actually ready, but give how we + * requested it early on, this won't be too long a wait/ + */ + oscillators_switch_to_hf_xosc(); + + if(prop_div_radio_setup() != RF_CORE_CMD_OK) { + PRINTF("on: prop_div_radio_setup() failed\n"); + return RF_CORE_CMD_ERROR; + } + + if(prop_fs() != RF_CORE_CMD_OK) { + PRINTF("on: prop_fs() failed\n"); + return RF_CORE_CMD_ERROR; + } + + return rx_on_prop(); +} +/*---------------------------------------------------------------------------*/ +static int +off(void) +{ + /* + * If we are in the middle of a BLE operation, we got called by ContikiMAC + * from within an interrupt context. Abort, but pretend everything is OK. + */ + if(rf_ble_is_active() == RF_BLE_ACTIVE) { + return RF_CORE_CMD_OK; + } + + rx_off_prop(); + rf_core_power_down(); + + ENERGEST_OFF(ENERGEST_TYPE_LISTEN); + + /* Switch HF clock source to the RCOSC to preserve power */ + oscillators_switch_to_hf_rc(); + + /* We pulled the plug, so we need to restore the status manually */ + smartrf_settings_cmd_prop_rx_adv.status = RF_CORE_RADIO_OP_STATUS_IDLE; + + return RF_CORE_CMD_OK; +} +/*---------------------------------------------------------------------------*/ +static radio_result_t +get_value(radio_param_t param, radio_value_t *value) +{ + if(!value) { + return RADIO_RESULT_INVALID_VALUE; + } + + switch(param) { + case RADIO_PARAM_POWER_MODE: + /* On / off */ + *value = rf_is_on() ? RADIO_POWER_MODE_ON : RADIO_POWER_MODE_OFF; + return RADIO_RESULT_OK; + case RADIO_PARAM_CHANNEL: + *value = (radio_value_t)get_channel(); + return RADIO_RESULT_OK; + case RADIO_PARAM_TXPOWER: + *value = get_tx_power(); + return RADIO_RESULT_OK; + case RADIO_PARAM_CCA_THRESHOLD: + *value = rssi_threshold; + return RADIO_RESULT_OK; + case RADIO_PARAM_RSSI: + *value = get_rssi(); + + if(*value == RF_CMD_CCA_REQ_RSSI_UNKNOWN) { + return RADIO_RESULT_ERROR; + } else { + return RADIO_RESULT_OK; + } + case RADIO_CONST_CHANNEL_MIN: + *value = 0; + return RADIO_RESULT_OK; + case RADIO_CONST_CHANNEL_MAX: + *value = DOT_15_4G_CHANNEL_MAX; + return RADIO_RESULT_OK; + case RADIO_CONST_TXPOWER_MIN: + *value = TX_POWER_DRIVER[get_tx_power_array_last_element()].dbm; + return RADIO_RESULT_OK; + case RADIO_CONST_TXPOWER_MAX: + *value = OUTPUT_POWER_MAX; + return RADIO_RESULT_OK; + default: + return RADIO_RESULT_NOT_SUPPORTED; + } +} +/*---------------------------------------------------------------------------*/ +static radio_result_t +set_value(radio_param_t param, radio_value_t value) +{ + uint8_t was_off = 0; + radio_result_t rv = RADIO_RESULT_OK; + + switch(param) { + case RADIO_PARAM_POWER_MODE: + if(value == RADIO_POWER_MODE_ON) { + if(on() != RF_CORE_CMD_OK) { + PRINTF("set_value: on() failed (1)\n"); + return RADIO_RESULT_ERROR; + } + return RADIO_RESULT_OK; + } + if(value == RADIO_POWER_MODE_OFF) { + off(); + return RADIO_RESULT_OK; + } + return RADIO_RESULT_INVALID_VALUE; + case RADIO_PARAM_CHANNEL: + if(value < 0 || + value > DOT_15_4G_CHANNEL_MAX) { + return RADIO_RESULT_INVALID_VALUE; + } + + if(get_channel() == (uint8_t)value) { + /* We already have that very same channel configured. + * Nothing to do here. */ + return RADIO_RESULT_OK; + } + + set_channel((uint8_t)value); + break; + case RADIO_PARAM_TXPOWER: + if(value < TX_POWER_DRIVER[get_tx_power_array_last_element()].dbm || + value > OUTPUT_POWER_MAX) { + return RADIO_RESULT_INVALID_VALUE; + } + + soft_off_prop(); + + set_tx_power(value); + + if(soft_on_prop() != RF_CORE_CMD_OK) { + PRINTF("set_value: soft_on_prop() failed\n"); + rv = RADIO_RESULT_ERROR; + } + + return RADIO_RESULT_OK; + case RADIO_PARAM_RX_MODE: + return RADIO_RESULT_OK; + case RADIO_PARAM_CCA_THRESHOLD: + rssi_threshold = (int8_t)value; + break; + default: + return RADIO_RESULT_NOT_SUPPORTED; + } + + /* If we reach here we had no errors. Apply new settings */ + if(!rf_is_on()) { + was_off = 1; + if(on() != RF_CORE_CMD_OK) { + PRINTF("set_value: on() failed (2)\n"); + return RADIO_RESULT_ERROR; + } + } + + if(rx_off_prop() != RF_CORE_CMD_OK) { + PRINTF("set_value: rx_off_prop() failed\n"); + rv = RADIO_RESULT_ERROR; + } + + if(soft_on_prop() != RF_CORE_CMD_OK) { + PRINTF("set_value: rx_on_prop() failed\n"); + rv = RADIO_RESULT_ERROR; + } + + /* If we were off, turn back off */ + if(was_off) { + off(); + } + + return rv; +} +/*---------------------------------------------------------------------------*/ +static radio_result_t +get_object(radio_param_t param, void *dest, size_t size) +{ + return RADIO_RESULT_NOT_SUPPORTED; +} +/*---------------------------------------------------------------------------*/ +static radio_result_t +set_object(radio_param_t param, const void *src, size_t size) +{ + return RADIO_RESULT_NOT_SUPPORTED; +} +/*---------------------------------------------------------------------------*/ +const struct radio_driver prop_mode_driver = { + init, + prepare, + transmit, + send, + read_frame, + channel_clear, + receiving_packet, + pending_packet, + on, + off, + get_value, + set_value, + get_object, + set_object, +}; +/*---------------------------------------------------------------------------*/ +/** + * @} + */ From c98b0498a74b49d45ddebda778b56932320be803 Mon Sep 17 00:00:00 2001 From: Richard Weickelt Date: Thu, 8 Feb 2018 12:56:35 +0100 Subject: [PATCH 231/485] Adding more functionality --- arch/cpu/simplelink/Makefile.simplelink | 2 +- .../rf-settings/proprietary-rf-settings.c | 49 +++++++++++++++ arch/cpu/simplelink/simplelink-conf.h | 1 - arch/cpu/simplelink/source/proprietary-rf.c | 33 +++++----- arch/cpu/simplelink/source/proprietary-rf.h | 60 +++++++++++++++++++ 5 files changed, 124 insertions(+), 21 deletions(-) create mode 100644 arch/cpu/simplelink/source/proprietary-rf.h diff --git a/arch/cpu/simplelink/Makefile.simplelink b/arch/cpu/simplelink/Makefile.simplelink index fa3831541..3e35ebfed 100644 --- a/arch/cpu/simplelink/Makefile.simplelink +++ b/arch/cpu/simplelink/Makefile.simplelink @@ -1,5 +1,5 @@ -MODULES += os/net os/net/mac os/net/mac/framer +MODULES += os/net/mac/framer CPU_ABS_PATH = $(CONTIKI)/arch/cpu/simplelink diff --git a/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.c b/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.c index 38ee56181..317812c39 100644 --- a/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.c +++ b/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.c @@ -36,6 +36,55 @@ #include DeviceFamily_constructPath(rf_patches/rf_patch_mce_genfsk.h) #include "proprietary-rf-settings.h" +#include "contiki.h" +#include "dev/radio.h" +#include + +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup rf-core-prop + * @{ + * + * \file + * Default TX power settings. The board can override + */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Default TX power settings for the 779-930MHz band */ +const prop_mode_tx_power_config_t prop_mode_tx_power_779_930[] = { + { 14, 0xa73f }, + { 13, 0xa63f }, /* 12.5 */ + { 12, 0xb818 }, + { 11, 0x50da }, + { 10, 0x38d3 }, + { 9, 0x2ccd }, + { 8, 0x24cb }, + { 7, 0x20c9 }, + { 6, 0x1cc7 }, + { 5, 0x18c6 }, + { 4, 0x18c5 }, + { 3, 0x14c4 }, + { 2, 0x1042 }, + { 1, 0x10c3 }, + { 0, 0x0041 }, + { -10, 0x08c0 }, + {-128, 0xFFFF }, +}; +/*---------------------------------------------------------------------------*/ +/* Default TX power settings for the 431-527MHz band */ +const prop_mode_tx_power_config_t prop_mode_tx_power_431_527[] = { + { 15, 0x003f }, + { 14, 0xbe3f }, /* 13.7 */ + { 13, 0x6a0f }, + { 10, 0x3dcb }, + { 6, 0x22c4 }, + {-128, 0xFFFF }, +}; +/*---------------------------------------------------------------------------*/ +/** + * @} + */ // TI-RTOS RF Mode Object RF_Mode RF_prop = diff --git a/arch/cpu/simplelink/simplelink-conf.h b/arch/cpu/simplelink/simplelink-conf.h index 17ea011a2..1db50738f 100644 --- a/arch/cpu/simplelink/simplelink-conf.h +++ b/arch/cpu/simplelink/simplelink-conf.h @@ -91,7 +91,6 @@ #else /* CC13XX_CONF_PROP_MODE */ #define NETSTACK_CONF_RADIO ieee_mode_driver -#error BLABLA #define CSMA_CONF_SEND_SOFT_ACK 0 #endif /* CC13XX_CONF_PROP_MODE */ diff --git a/arch/cpu/simplelink/source/proprietary-rf.c b/arch/cpu/simplelink/source/proprietary-rf.c index d821bf1d9..ea0a21cdc 100644 --- a/arch/cpu/simplelink/source/proprietary-rf.c +++ b/arch/cpu/simplelink/source/proprietary-rf.c @@ -43,6 +43,7 @@ #include "sys/clock.h" #include "sys/rtimer.h" #include "sys/cc.h" +#include "proprietary-rf.h" /*---------------------------------------------------------------------------*/ /* RF core and RF HAL API */ #include @@ -1037,26 +1038,20 @@ on(void) static int off(void) { - /* - * If we are in the middle of a BLE operation, we got called by ContikiMAC - * from within an interrupt context. Abort, but pretend everything is OK. - */ - if(rf_ble_is_active() == RF_BLE_ACTIVE) { +// /* +// * If we are in the middle of a BLE operation, we got called by ContikiMAC +// * from within an interrupt context. Abort, but pretend everything is OK. +// */ +// if(rf_ble_is_active() == RF_BLE_ACTIVE) { +// return RF_CORE_CMD_OK; +// } + + RF_yield(handle); + + /* We pulled the plug, so we need to restore the status manually */ + smartrf_settings_cmd_prop_rx_adv.status = IDLE; + return RF_CORE_CMD_OK; - } - - rx_off_prop(); - rf_core_power_down(); - - ENERGEST_OFF(ENERGEST_TYPE_LISTEN); - - /* Switch HF clock source to the RCOSC to preserve power */ - oscillators_switch_to_hf_rc(); - - /* We pulled the plug, so we need to restore the status manually */ - smartrf_settings_cmd_prop_rx_adv.status = RF_CORE_RADIO_OP_STATUS_IDLE; - - return RF_CORE_CMD_OK; } /*---------------------------------------------------------------------------*/ static radio_result_t diff --git a/arch/cpu/simplelink/source/proprietary-rf.h b/arch/cpu/simplelink/source/proprietary-rf.h new file mode 100644 index 000000000..de61e53ec --- /dev/null +++ b/arch/cpu/simplelink/source/proprietary-rf.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2016, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup rf-core + * @{ + * + * \defgroup rf-core-prop CC13xx Prop mode driver + * + * @{ + * + * \file + * Header file for the CC13xx prop mode NETSTACK_RADIO driver + */ +/*---------------------------------------------------------------------------*/ +#ifndef PROP_MODE_H_ +#define PROP_MODE_H_ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" + +#include +/*---------------------------------------------------------------------------*/ +typedef struct prop_mode_tx_power_config { + radio_value_t dbm; + uint16_t tx_power; /* Value for the PROP_DIV_RADIO_SETUP.txPower field */ +} prop_mode_tx_power_config_t; +/*---------------------------------------------------------------------------*/ +#endif /* PROP_MODE_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ From df236cc05c2bdd8a1d294a58e7a47691e2f3446a Mon Sep 17 00:00:00 2001 From: Richard Weickelt Date: Thu, 8 Feb 2018 16:41:27 +0100 Subject: [PATCH 232/485] Add more RF functionality --- .../{source => dev}/proprietary-rf.c | 531 +++++++----------- .../{source => dev}/proprietary-rf.h | 0 arch/cpu/simplelink/dev/rf-core.h | 9 + .../rf-settings/proprietary-rf-settings.c | 64 --- 4 files changed, 209 insertions(+), 395 deletions(-) rename arch/cpu/simplelink/{source => dev}/proprietary-rf.c (71%) rename arch/cpu/simplelink/{source => dev}/proprietary-rf.h (100%) create mode 100644 arch/cpu/simplelink/dev/rf-core.h diff --git a/arch/cpu/simplelink/source/proprietary-rf.c b/arch/cpu/simplelink/dev/proprietary-rf.c similarity index 71% rename from arch/cpu/simplelink/source/proprietary-rf.c rename to arch/cpu/simplelink/dev/proprietary-rf.c index ea0a21cdc..faee0ea9c 100644 --- a/arch/cpu/simplelink/source/proprietary-rf.c +++ b/arch/cpu/simplelink/dev/proprietary-rf.c @@ -44,6 +44,7 @@ #include "sys/rtimer.h" #include "sys/cc.h" #include "proprietary-rf.h" +#include "rf-core.h" /*---------------------------------------------------------------------------*/ /* RF core and RF HAL API */ #include @@ -228,8 +229,8 @@ volatile static uint8_t *rx_read_entry; static uint8_t tx_buf[TX_BUF_HDR_LEN + TX_BUF_PAYLOAD_LEN] CC_ALIGN(4); /*---------------------------------------------------------------------------*/ /* RF driver */ -RF_Object rfObject; -RF_Handle handle; +static RF_Object rfObject; +static RF_Handle rfHandle; /*---------------------------------------------------------------------------*/ /* CMD_PROP_TX_ADV */ rfc_CMD_PROP_TX_ADV_t smartrf_settings_cmd_prop_tx_adv = @@ -322,60 +323,60 @@ transmitting(void) static radio_value_t get_rssi(void) { - uint32_t cmd_status; - int8_t rssi; - uint8_t attempts = 0; - uint8_t was_off = 0; - rfc_CMD_GET_RSSI_t cmd; - - /* If we are off, turn on first */ - if(!rf_is_on()) { - was_off = 1; - if(on() != RF_CORE_CMD_OK) { - PRINTF("get_rssi: on() failed\n"); - return RF_CMD_CCA_REQ_RSSI_UNKNOWN; - } - } - - rssi = RF_CMD_CCA_REQ_RSSI_UNKNOWN; - - while((rssi == RF_CMD_CCA_REQ_RSSI_UNKNOWN || rssi == 0) && ++attempts < 10) { - memset(&cmd, 0x00, sizeof(cmd)); - cmd.commandNo = CMD_GET_RSSI; - - if(rf_core_send_cmd((uint32_t)&cmd, &cmd_status) == RF_CORE_CMD_ERROR) { - PRINTF("get_rssi: CMDSTA=0x%08lx\n", cmd_status); - break; - } else { - /* Current RSSI in bits 23:16 of cmd_status */ - rssi = (cmd_status >> 16) & 0xFF; - } - } - - /* If we were off, turn back off */ - if(was_off) { - off(); - } - - return rssi; +// uint32_t cmd_status; +// int8_t rssi; +// uint8_t attempts = 0; +// uint8_t was_off = 0; +// rfc_CMD_GET_RSSI_t cmd; +// +// /* If we are off, turn on first */ +// if(!rf_is_on()) { +// was_off = 1; +// if(on() != RF_CORE_CMD_OK) { +// PRINTF("get_rssi: on() failed\n"); +// return RF_CMD_CCA_REQ_RSSI_UNKNOWN; +// } +// } +// +// rssi = RF_CMD_CCA_REQ_RSSI_UNKNOWN; +// +// while((rssi == RF_CMD_CCA_REQ_RSSI_UNKNOWN || rssi == 0) && ++attempts < 10) { +// memset(&cmd, 0x00, sizeof(cmd)); +// cmd.commandNo = CMD_GET_RSSI; +// +// if(rf_core_send_cmd((uint32_t)&cmd, &cmd_status) == RF_CORE_CMD_ERROR) { +// PRINTF("get_rssi: CMDSTA=0x%08lx\n", cmd_status); +// break; +// } else { +// /* Current RSSI in bits 23:16 of cmd_status */ +// rssi = (cmd_status >> 16) & 0xFF; +// } +// } +// +// /* If we were off, turn back off */ +// if(was_off) { +// off(); +// } +// +// return rssi; } /*---------------------------------------------------------------------------*/ static uint8_t get_channel(void) { - uint32_t freq_khz; - - freq_khz = smartrf_settings_cmd_fs.frequency * 1000; - - /* - * For some channels, fractFreq * 1000 / 65536 will return 324.99xx. - * Casting the result to uint32_t will truncate decimals resulting in the - * function returning channel - 1 instead of channel. Thus, we do a quick - * positive integer round up. - */ - freq_khz += (((smartrf_settings_cmd_fs.fractFreq * 1000) + 65535) / 65536); - - return (freq_khz - DOT_15_4G_CHAN0_FREQUENCY) / DOT_15_4G_CHANNEL_SPACING; +// uint32_t freq_khz; +// +// freq_khz = smartrf_settings_cmd_fs.frequency * 1000; +// +// /* +// * For some channels, fractFreq * 1000 / 65536 will return 324.99xx. +// * Casting the result to uint32_t will truncate decimals resulting in the +// * function returning channel - 1 instead of channel. Thus, we do a quick +// * positive integer round up. +// */ +// freq_khz += (((smartrf_settings_cmd_fs.fractFreq * 1000) + 65535) / 65536); +// +// return (freq_khz - DOT_15_4G_CHAN0_FREQUENCY) / DOT_15_4G_CHANNEL_SPACING; } /*---------------------------------------------------------------------------*/ static void @@ -392,9 +393,9 @@ set_channel(uint8_t channel) PRINTF("set_channel: %u = 0x%04x.0x%04x (%lu)\n", channel, freq, frac, new_freq); - smartrf_settings_cmd_prop_radio_div_setup.centerFreq = freq; - smartrf_settings_cmd_fs.frequency = freq; - smartrf_settings_cmd_fs.fractFreq = frac; + RF_cmdPropRadioDivSetup.centerFreq = freq; + RF_cmdFs.frequency = freq; + RF_cmdFs.fractFreq = frac; } /*---------------------------------------------------------------------------*/ static uint8_t @@ -443,38 +444,38 @@ set_tx_power(radio_value_t power) static int prop_div_radio_setup(void) { - uint32_t cmd_status; - rfc_radioOp_t *cmd = (rfc_radioOp_t *)&smartrf_settings_cmd_prop_radio_div_setup; - - rf_switch_select_path(RF_SWITCH_PATH_SUBGHZ); - - /* Adjust loDivider depending on the selected band */ - smartrf_settings_cmd_prop_radio_div_setup.loDivider = PROP_MODE_LO_DIVIDER; - - /* Update to the correct TX power setting */ - smartrf_settings_cmd_prop_radio_div_setup.txPower = tx_power_current->tx_power; - - /* Adjust RF Front End and Bias based on the board */ - smartrf_settings_cmd_prop_radio_div_setup.config.frontEndMode = - RF_CORE_PROP_FRONT_END_MODE; - smartrf_settings_cmd_prop_radio_div_setup.config.biasMode = - RF_CORE_PROP_BIAS_MODE; - - /* Send Radio setup to RF Core */ - if(rf_core_send_cmd((uint32_t)cmd, &cmd_status) != RF_CORE_CMD_OK) { - PRINTF("prop_div_radio_setup: DIV_SETUP, CMDSTA=0x%08lx, status=0x%04x\n", - cmd_status, cmd->status); - return RF_CORE_CMD_ERROR; - } - - /* Wait until radio setup is done */ - if(rf_core_wait_cmd_done(cmd) != RF_CORE_CMD_OK) { - PRINTF("prop_div_radio_setup: DIV_SETUP wait, CMDSTA=0x%08lx," - "status=0x%04x\n", cmd_status, cmd->status); - return RF_CORE_CMD_ERROR; - } - - return RF_CORE_CMD_OK; +// uint32_t cmd_status; +// rfc_radioOp_t *cmd = (rfc_radioOp_t *)&smartrf_settings_cmd_prop_radio_div_setup; +// +// rf_switch_select_path(RF_SWITCH_PATH_SUBGHZ); +// +// /* Adjust loDivider depending on the selected band */ +// smartrf_settings_cmd_prop_radio_div_setup.loDivider = PROP_MODE_LO_DIVIDER; +// +// /* Update to the correct TX power setting */ +// smartrf_settings_cmd_prop_radio_div_setup.txPower = tx_power_current->tx_power; +// +// /* Adjust RF Front End and Bias based on the board */ +// smartrf_settings_cmd_prop_radio_div_setup.config.frontEndMode = +// RF_CORE_PROP_FRONT_END_MODE; +// smartrf_settings_cmd_prop_radio_div_setup.config.biasMode = +// RF_CORE_PROP_BIAS_MODE; +// +// /* Send Radio setup to RF Core */ +// if(rf_core_send_cmd((uint32_t)cmd, &cmd_status) != RF_CORE_CMD_OK) { +// PRINTF("prop_div_radio_setup: DIV_SETUP, CMDSTA=0x%08lx, status=0x%04x\n", +// cmd_status, cmd->status); +// return RF_CORE_CMD_ERROR; +// } +// +// /* Wait until radio setup is done */ +// if(rf_core_wait_cmd_done(cmd) != RF_CORE_CMD_OK) { +// PRINTF("prop_div_radio_setup: DIV_SETUP wait, CMDSTA=0x%08lx," +// "status=0x%04x\n", cmd_status, cmd->status); +// return RF_CORE_CMD_ERROR; +// } +// +// return RF_CORE_CMD_OK; } /*---------------------------------------------------------------------------*/ static uint8_t @@ -486,7 +487,7 @@ rf_cmd_prop_rx() int ret; cmd_rx_adv = (rfc_CMD_PROP_RX_ADV_t *)&smartrf_settings_cmd_prop_rx_adv; - cmd_rx_adv->status = RF_CORE_RADIO_OP_STATUS_IDLE; + cmd_rx_adv->status = IDLE; /* * Set the max Packet length. This is for the payload only, therefore @@ -494,17 +495,15 @@ rf_cmd_prop_rx() */ cmd_rx_adv->maxPktLen = DOT_4G_MAX_FRAME_LEN - cmd_rx_adv->lenOffset; - ret = rf_core_send_cmd((uint32_t)cmd_rx_adv, &cmd_status); - - if(ret != RF_CORE_CMD_OK) { - PRINTF("rf_cmd_prop_rx: send_cmd ret=%d, CMDSTA=0x%08lx, status=0x%04x\n", - ret, cmd_status, cmd_rx_adv->status); - return RF_CORE_CMD_ERROR; + // Todo: subscribe events + RF_CmdHandle cmd = RF_postCmd(rfHandle, (RF_Op*)&smartrf_settings_cmd_prop_rx_adv, RF_PriorityNormal, NULL, 0); + if (cmd == RF_ALLOC_ERROR) { + return RF_CORE_CMD_ERROR; } t0 = RTIMER_NOW(); - while(cmd_rx_adv->status != RF_CORE_RADIO_OP_STATUS_ACTIVE && + while(cmd_rx_adv->status != ACTIVE && (RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + ENTER_RX_WAIT_TIMEOUT))); /* Wait to enter RX */ @@ -514,7 +513,7 @@ rf_cmd_prop_rx() return RF_CORE_CMD_ERROR; } - return ret; + return RF_CORE_CMD_OK; } /*---------------------------------------------------------------------------*/ static void @@ -538,22 +537,22 @@ init_rx_buffers(void) static int rx_on_prop(void) { - int ret; - - if(rf_is_on()) { - PRINTF("rx_on_prop: We were on. PD=%u, RX=0x%04x\n", - rf_core_is_accessible(), smartrf_settings_cmd_prop_rx_adv.status); - return RF_CORE_CMD_OK; - } - - /* Put CPE in RX using the currently configured parameters */ +// int ret; +// +// if(rf_is_on()) { +// PRINTF("rx_on_prop: We were on. PD=%u, RX=0x%04x\n", +// rf_core_is_accessible(), smartrf_settings_cmd_prop_rx_adv.status); +// return RF_CORE_CMD_OK; +// } +// +// /* Put CPE in RX using the currently configured parameters */ ret = rf_cmd_prop_rx(); - - if(ret) { - ENERGEST_ON(ENERGEST_TYPE_LISTEN); - } - - return ret; +// +// if(ret) { +// ENERGEST_ON(ENERGEST_TYPE_LISTEN); +// } +// +// return ret; } /*---------------------------------------------------------------------------*/ static int @@ -567,11 +566,10 @@ rx_off_prop(void) return RF_CORE_CMD_OK; } - /* Send a CMD_ABORT command to RF Core */ - if(rf_core_send_cmd(CMDR_DIR_CMD(CMD_ABORT), &cmd_status) != RF_CORE_CMD_OK) { - PRINTF("rx_off_prop: CMD_ABORT status=0x%08lx\n", cmd_status); - /* Continue nonetheless */ - } + + /* Abort any ongoing operation. Don't care about the result. */ + RF_cancelCmd(rfHandle, RF_CMDHANDLE_FLUSH_ALL, 1); + RF_yield(rfHandle); while(rf_is_on()); @@ -592,15 +590,15 @@ rx_off_prop(void) static uint8_t request(void) { - /* - * We rely on the RDC layer to turn us on and off. Thus, if we are on we - * will only allow sleep, standby otherwise - */ - if(rf_is_on()) { - return LPM_MODE_SLEEP; - } - - return LPM_MODE_MAX_SUPPORTED; +// /* +// * We rely on the RDC layer to turn us on and off. Thus, if we are on we +// * will only allow sleep, standby otherwise +// */ +// if(rf_is_on()) { +// return LPM_MODE_SLEEP; +// } +// +// return LPM_MODE_MAX_SUPPORTED; } /*---------------------------------------------------------------------------*/ LPM_MODULE(prop_lpm_module, request, NULL, NULL, LPM_DOMAIN_NONE); @@ -608,59 +606,24 @@ LPM_MODULE(prop_lpm_module, request, NULL, NULL, LPM_DOMAIN_NONE); static int prop_fs(void) { - uint32_t cmd_status; - rfc_radioOp_t *cmd = (rfc_radioOp_t *)&smartrf_settings_cmd_fs; + RF_EventMask terminationCause = RF_runCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0); + if ((terminationCause == RF_EventLastCmdDone) && (RF_cmdFs.status == DONE_OK)) + { + return RF_CORE_CMD_OK; + } - /* Send the command to the RF Core */ - if(rf_core_send_cmd((uint32_t)cmd, &cmd_status) != RF_CORE_CMD_OK) { - PRINTF("prop_fs: CMD_FS, CMDSTA=0x%08lx, status=0x%04x\n", - cmd_status, cmd->status); return RF_CORE_CMD_ERROR; - } - - /* Wait until the command is done */ - if(rf_core_wait_cmd_done(cmd) != RF_CORE_CMD_OK) { - PRINTF("prop_fs: CMD_FS wait, CMDSTA=0x%08lx, status=0x%04x\n", - cmd_status, cmd->status); - return RF_CORE_CMD_ERROR; - } - - return RF_CORE_CMD_OK; } /*---------------------------------------------------------------------------*/ static void soft_off_prop(void) { - uint32_t cmd_status; - volatile rfc_radioOp_t *cmd = rf_core_get_last_radio_op(); - - if(!rf_core_is_accessible()) { - return; - } - - /* Send a CMD_ABORT command to RF Core */ - if(rf_core_send_cmd(CMDR_DIR_CMD(CMD_ABORT), &cmd_status) != RF_CORE_CMD_OK) { - PRINTF("soft_off_prop: CMD_ABORT status=0x%08lx\n", cmd_status); - return; - } - - while((cmd->status & RF_CORE_RADIO_OP_MASKED_STATUS) == - RF_CORE_RADIO_OP_MASKED_STATUS_RUNNING); + RF_yield(rfHandle); } /*---------------------------------------------------------------------------*/ static uint8_t soft_on_prop(void) { - if(prop_div_radio_setup() != RF_CORE_CMD_OK) { - PRINTF("soft_on_prop: prop_div_radio_setup() failed\n"); - return RF_CORE_CMD_ERROR; - } - - if(prop_fs() != RF_CORE_CMD_OK) { - PRINTF("soft_on_prop: prop_fs() failed\n"); - return RF_CORE_CMD_ERROR; - } - return rx_on_prop(); } /*---------------------------------------------------------------------------*/ @@ -676,8 +639,8 @@ init(void) RF_Params_init(¶ms); params.nInactivityTimeout = 0; // disable automatic power-down - handle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, ¶ms); - assert(handle != NULL); + rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, ¶ms); + assert(rfHandle != NULL); /* Initialise RX buffers */ memset(rx_buf, 0, sizeof(rx_buf)); @@ -720,66 +683,60 @@ prepare(const void *payload, unsigned short payload_len) static int transmit(unsigned short transmit_len) { - int ret; - uint8_t was_off = 0; - uint32_t cmd_status; - volatile rfc_CMD_PROP_TX_ADV_t *cmd_tx_adv; + int ret; + uint8_t was_off = 0; + uint32_t cmd_status; + volatile rfc_CMD_PROP_TX_ADV_t *cmd_tx_adv; - /* Length in .15.4g PHY HDR. Includes the CRC but not the HDR itself */ - uint16_t total_length; + /* Length in .15.4g PHY HDR. Includes the CRC but not the HDR itself */ + uint16_t total_length; - if(!rf_is_on()) { - was_off = 1; - if(on() != RF_CORE_CMD_OK) { - PRINTF("transmit: on() failed\n"); - return RADIO_TX_ERR; + /* + * Prepare the .15.4g PHY header + * MS=0, Length MSBits=0, DW and CRC configurable + * Total length = transmit_len (payload) + CRC length + * + * The Radio will flip the bits around, so tx_buf[0] must have the length + * LSBs (PHR[15:8] and tx_buf[1] will have PHR[7:0] + */ + total_length = transmit_len + CRC_LEN; + + tx_buf[0] = total_length & 0xFF; + tx_buf[1] = (total_length >> 8) + DOT_4G_PHR_DW_BIT + DOT_4G_PHR_CRC_BIT; + + /* Prepare the CMD_PROP_TX_ADV command */ + cmd_tx_adv = (rfc_CMD_PROP_TX_ADV_t *)&smartrf_settings_cmd_prop_tx_adv; + + /* + * pktLen: Total number of bytes in the TX buffer, including the header if + * one exists, but not including the CRC (which is not present in the buffer) + */ + cmd_tx_adv->pktLen = transmit_len + DOT_4G_PHR_LEN; + cmd_tx_adv->pPkt = tx_buf; + + was_off = rx_ + /* Abort RX */ + rx_off_prop(); + + // TODO: Register callback + RF_CmdHandle txHandle = RF_postCmd(rfHandle, (RF_Op*)&cmd_tx_adv, RF_PriorityNormal, NULL, 0); + if (txHandle == RF_ALLOC_ERROR) + { + /* Failure sending the CMD_PROP_TX command */ + PRINTF("transmit: PROP_TX_ERR ret=%d, CMDSTA=0x%08lx, status=0x%04x\n", + ret, cmd_status, cmd_tx_adv->status); + return RADIO_TX_ERR; } - } - /* - * Prepare the .15.4g PHY header - * MS=0, Length MSBits=0, DW and CRC configurable - * Total length = transmit_len (payload) + CRC length - * - * The Radio will flip the bits around, so tx_buf[0] must have the length - * LSBs (PHR[15:8] and tx_buf[1] will have PHR[7:0] - */ - total_length = transmit_len + CRC_LEN; - - tx_buf[0] = total_length & 0xFF; - tx_buf[1] = (total_length >> 8) + DOT_4G_PHR_DW_BIT + DOT_4G_PHR_CRC_BIT; - - /* Prepare the CMD_PROP_TX_ADV command */ - cmd_tx_adv = (rfc_CMD_PROP_TX_ADV_t *)&smartrf_settings_cmd_prop_tx_adv; - - /* - * pktLen: Total number of bytes in the TX buffer, including the header if - * one exists, but not including the CRC (which is not present in the buffer) - */ - cmd_tx_adv->pktLen = transmit_len + DOT_4G_PHR_LEN; - cmd_tx_adv->pPkt = tx_buf; - - /* Abort RX */ - rx_off_prop(); - - /* Enable the LAST_COMMAND_DONE interrupt to wake us up */ - rf_core_cmd_done_en(false, false); - - ret = rf_core_send_cmd((uint32_t)cmd_tx_adv, &cmd_status); - - if(ret) { /* If we enter here, TX actually started */ ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT); - watchdog_periodic(); + // watchdog_periodic(); /* Idle away while the command is running */ - while((cmd_tx_adv->status & RF_CORE_RADIO_OP_MASKED_STATUS) - == RF_CORE_RADIO_OP_MASKED_STATUS_RUNNING) { - lpm_sleep(); - } + RF_pendCmd(rfHandle, txHandle, 0); - if(cmd_tx_adv->status == RF_CORE_RADIO_OP_STATUS_PROP_DONE_OK) { + if(cmd_tx_adv->status == PROP_DONE_OK) { /* Sent OK */ ret = RADIO_TX_OK; } else { @@ -788,35 +745,19 @@ transmit(unsigned short transmit_len) cmd_tx_adv->status); ret = RADIO_TX_ERR; } - } else { - /* Failure sending the CMD_PROP_TX command */ - PRINTF("transmit: PROP_TX_ERR ret=%d, CMDSTA=0x%08lx, status=0x%04x\n", - ret, cmd_status, cmd_tx_adv->status); - ret = RADIO_TX_ERR; - } - /* - * Update ENERGEST state here, before a potential call to off(), which - * will correctly update it if required. - */ - ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN); + /* + * Update ENERGEST state here, before a potential call to off(), which + * will correctly update it if required. + */ + ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN); - /* - * Disable LAST_FG_COMMAND_DONE interrupt. We don't really care about it - * except when we are transmitting - */ - rf_core_cmd_done_dis(false); + /* Workaround. Set status to IDLE */ + cmd_tx_adv->status = RF_CORE_RADIO_OP_STATUS_IDLE; - /* Workaround. Set status to IDLE */ - cmd_tx_adv->status = RF_CORE_RADIO_OP_STATUS_IDLE; + rx_on_prop(); - rx_on_prop(); - - if(was_off) { - off(); - } - - return ret; + return ret; } /*---------------------------------------------------------------------------*/ static int @@ -886,19 +827,18 @@ channel_clear(void) return RF_CCA_CLEAR; } } else { - if(transmitting()) { - PRINTF("channel_clear: called while in TX\n"); - return RF_CCA_CLEAR; - } + + } + + rf_core + + if(transmitting()) { + PRINTF("channel_clear: called while in TX\n"); + return RF_CCA_CLEAR; } while(rssi == RF_CMD_CCA_REQ_RSSI_UNKNOWN || rssi == 0) { - if(rf_core_send_cmd(CMDR_DIR_CMD(CMD_GET_RSSI), &cmd_status) - != RF_CORE_CMD_OK) { - break; - } - /* Current RSSI in bits 23:16 of cmd_status */ - rssi = (cmd_status >> 16) & 0xFF; + rssi = RF_getRssi(rfHandle); } if(was_off) { @@ -949,90 +889,19 @@ pending_packet(void) static int on(void) { - /* - * If we are in the middle of a BLE operation, we got called by ContikiMAC - * from within an interrupt context. Abort, but pretend everything is OK. - */ - if(rf_ble_is_active() == RF_BLE_ACTIVE) { - return RF_CORE_CMD_OK; - } - /* - * Request the HF XOSC as the source for the HF clock. Needed before we can - * use the FS. This will only request, it will _not_ perform the switch. - */ - oscillators_request_hf_xosc(); + init_rx_buffers(); - if(rf_is_on()) { - PRINTF("on: We were on. PD=%u, RX=0x%04x \n", rf_core_is_accessible(), - smartrf_settings_cmd_prop_rx_adv.status); - return RF_CORE_CMD_OK; - } - - if(!rf_core_is_accessible()) { - if(rf_core_power_up() != RF_CORE_CMD_OK) { - PRINTF("on: rf_core_power_up() failed\n"); - - rf_core_power_down(); - - return RF_CORE_CMD_ERROR; + rfc_CMD_NOP_t nop = { 0 }; + nop.commandNo = CMD_NOP; + RF_EventMask terminationCause = RF_runCmd(rfHandle, (RF_Op*)&nop, RF_PriorityNormal, NULL, 0); + if ((terminationCause == RF_EventLastCmdDone) && (RF_cmdFs.status == DONE_OK)) + { + return RF_CORE_CMD_OK; } - /* Keep track of RF Core mode */ - rf_core_set_modesel(); - - /* Apply patches to radio core */ - rf_patch_cpe_genfsk(); - while(!HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFACKIFG)); - HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFACKIFG) = 0; - rf_patch_rfe_genfsk(); - - /* Initialize bus request */ - HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFACKIFG) = 0; - HWREG(RFC_DBELL_BASE + RFC_DBELL_O_CMDR) = - CMDR_DIR_CMD_1BYTE(CMD_BUS_REQUEST, 1); - - /* set VCOLDO reference */ - ti_lib_rfc_adi3vco_ldo_voltage_mode(true); - - /* Let CC13xxware automatically set a correct value for RTRIM for us */ - ti_lib_rfc_rtrim((rfc_radioOp_t *)&smartrf_settings_cmd_prop_radio_div_setup); - - /* Make sure BUS_REQUEST is done */ - while(!HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFACKIFG)); - HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFACKIFG) = 0; - - if(rf_core_start_rat() != RF_CORE_CMD_OK) { - PRINTF("on: rf_core_start_rat() failed\n"); - - rf_core_power_down(); - - return RF_CORE_CMD_ERROR; - } - } - - rf_core_setup_interrupts(false); - - init_rx_buffers(); - - /* - * Trigger a switch to the XOSC, so that we can subsequently use the RF FS - * This will block until the XOSC is actually ready, but give how we - * requested it early on, this won't be too long a wait/ - */ - oscillators_switch_to_hf_xosc(); - - if(prop_div_radio_setup() != RF_CORE_CMD_OK) { - PRINTF("on: prop_div_radio_setup() failed\n"); return RF_CORE_CMD_ERROR; - } - if(prop_fs() != RF_CORE_CMD_OK) { - PRINTF("on: prop_fs() failed\n"); - return RF_CORE_CMD_ERROR; - } - - return rx_on_prop(); } /*---------------------------------------------------------------------------*/ static int @@ -1046,7 +915,7 @@ off(void) // return RF_CORE_CMD_OK; // } - RF_yield(handle); + RF_yield(rfHandle); /* We pulled the plug, so we need to restore the status manually */ smartrf_settings_cmd_prop_rx_adv.status = IDLE; diff --git a/arch/cpu/simplelink/source/proprietary-rf.h b/arch/cpu/simplelink/dev/proprietary-rf.h similarity index 100% rename from arch/cpu/simplelink/source/proprietary-rf.h rename to arch/cpu/simplelink/dev/proprietary-rf.h diff --git a/arch/cpu/simplelink/dev/rf-core.h b/arch/cpu/simplelink/dev/rf-core.h new file mode 100644 index 000000000..e28937384 --- /dev/null +++ b/arch/cpu/simplelink/dev/rf-core.h @@ -0,0 +1,9 @@ +#ifndef CONTIKI_NG_ARCH_CPU_SIMPLELINK_DEV_RF_CORE_H_ +#define CONTIKI_NG_ARCH_CPU_SIMPLELINK_DEV_RF_CORE_H_ + +/*---------------------------------------------------------------------------*/ +#define RF_CORE_CMD_ERROR 0 +#define RF_CORE_CMD_OK 1 +/*---------------------------------------------------------------------------*/ + +#endif /* CONTIKI_NG_ARCH_CPU_SIMPLELINK_DEV_RF_CORE_H_ */ diff --git a/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.c b/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.c index 317812c39..4620a9b55 100644 --- a/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.c +++ b/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.c @@ -196,67 +196,3 @@ rfc_CMD_FS_t RF_cmdFs = .__dummy2 = 0x00, .__dummy3 = 0x0000, }; - -// CMD_PROP_TX -// Proprietary Mode Transmit Command -rfc_CMD_PROP_TX_t RF_cmdPropTx = -{ - .commandNo = 0x3801, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .pktConf.bFsOff = 0x0, - .pktConf.bUseCrc = 0x1, - .pktConf.bVarLen = 0x1, - .pktLen = 0x1E, // SET APPLICATION PAYLOAD LENGTH - .syncWord = 0x930B51DE, - .pPkt = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx -}; - -// CMD_PROP_RX -// Proprietary Mode Receive Command -rfc_CMD_PROP_RX_t RF_cmdPropRx = -{ - .commandNo = 0x3802, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .pktConf.bFsOff = 0x0, - .pktConf.bRepeatOk = 0x0, - .pktConf.bRepeatNok = 0x0, - .pktConf.bUseCrc = 0x1, - .pktConf.bVarLen = 0x1, - .pktConf.bChkAddress = 0x0, - .pktConf.endType = 0x0, - .pktConf.filterOp = 0x0, - .rxConf.bAutoFlushIgnored = 0x0, - .rxConf.bAutoFlushCrcErr = 0x0, - .rxConf.bIncludeHdr = 0x1, - .rxConf.bIncludeCrc = 0x0, - .rxConf.bAppendRssi = 0x0, - .rxConf.bAppendTimestamp = 0x0, - .rxConf.bAppendStatus = 0x1, - .syncWord = 0x930B51DE, - .maxPktLen = 0xFF, // MAKE SURE DATA ENTRY IS LARGE ENOUGH - .address0 = 0xAA, - .address1 = 0xBB, - .endTrigger.triggerType = 0x1, - .endTrigger.bEnaCmd = 0x0, - .endTrigger.triggerNo = 0x0, - .endTrigger.pastTrig = 0x0, - .endTime = 0x00000000, - .pQueue = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx - .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx -}; From 430ba24bbd037aa5c8f32c396209fc293b529c3a Mon Sep 17 00:00:00 2001 From: Richard Weickelt Date: Fri, 9 Feb 2018 09:13:12 +0100 Subject: [PATCH 233/485] Add more functionality --- arch/cpu/simplelink/dev/proprietary-rf.c | 430 ++++++++--------------- 1 file changed, 148 insertions(+), 282 deletions(-) diff --git a/arch/cpu/simplelink/dev/proprietary-rf.c b/arch/cpu/simplelink/dev/proprietary-rf.c index faee0ea9c..072e442be 100644 --- a/arch/cpu/simplelink/dev/proprietary-rf.c +++ b/arch/cpu/simplelink/dev/proprietary-rf.c @@ -127,8 +127,8 @@ static int8_t rssi_threshold = PROP_MODE_RSSI_THRESHOLD; /*---------------------------------------------------------------------------*/ -static int on(void); -static int off(void); +static int rf_switch_on(void); +static int rf_switch_off(void); static rfc_propRxOutput_t rx_stats; /*---------------------------------------------------------------------------*/ @@ -312,71 +312,59 @@ rfc_CMD_PROP_RX_ADV_t smartrf_settings_cmd_prop_rx_adv = .pOutput = 0, }; /*---------------------------------------------------------------------------*/ - - static uint8_t -transmitting(void) +rf_transmitting(void) { - return smartrf_settings_cmd_prop_tx_adv.status == RF_CORE_RADIO_OP_STATUS_ACTIVE; + return smartrf_settings_cmd_prop_tx_adv.status == ACTIVE; +} +/*---------------------------------------------------------------------------*/ +static uint8_t +rf_receiving(void) +{ + return smartrf_settings_cmd_prop_rx_adv.status == ACTIVE; } /*---------------------------------------------------------------------------*/ static radio_value_t get_rssi(void) { -// uint32_t cmd_status; -// int8_t rssi; -// uint8_t attempts = 0; -// uint8_t was_off = 0; -// rfc_CMD_GET_RSSI_t cmd; -// -// /* If we are off, turn on first */ -// if(!rf_is_on()) { -// was_off = 1; -// if(on() != RF_CORE_CMD_OK) { -// PRINTF("get_rssi: on() failed\n"); -// return RF_CMD_CCA_REQ_RSSI_UNKNOWN; -// } -// } -// -// rssi = RF_CMD_CCA_REQ_RSSI_UNKNOWN; -// -// while((rssi == RF_CMD_CCA_REQ_RSSI_UNKNOWN || rssi == 0) && ++attempts < 10) { -// memset(&cmd, 0x00, sizeof(cmd)); -// cmd.commandNo = CMD_GET_RSSI; -// -// if(rf_core_send_cmd((uint32_t)&cmd, &cmd_status) == RF_CORE_CMD_ERROR) { -// PRINTF("get_rssi: CMDSTA=0x%08lx\n", cmd_status); -// break; -// } else { -// /* Current RSSI in bits 23:16 of cmd_status */ -// rssi = (cmd_status >> 16) & 0xFF; -// } -// } -// -// /* If we were off, turn back off */ -// if(was_off) { -// off(); -// } -// -// return rssi; + int8_t rssi = RF_GET_RSSI_ERROR_VAL; + uint8_t was_off = 0; + + if (rf_transmitting()) { + PRINTF("channel_clear: called while in TX\n"); + return RF_CCA_CLEAR; + } else if (!rf_receiving()) { + was_off = 1; + rf_start_rx(); + } + + while(rssi == RF_GET_RSSI_ERROR_VAL || rssi == 0) { + rssi = RF_getRssi(rfHandle); + } + + if(was_off) { + rf_switch_off(); + } + + return rssi; } /*---------------------------------------------------------------------------*/ static uint8_t get_channel(void) { -// uint32_t freq_khz; -// -// freq_khz = smartrf_settings_cmd_fs.frequency * 1000; -// -// /* -// * For some channels, fractFreq * 1000 / 65536 will return 324.99xx. -// * Casting the result to uint32_t will truncate decimals resulting in the -// * function returning channel - 1 instead of channel. Thus, we do a quick -// * positive integer round up. -// */ -// freq_khz += (((smartrf_settings_cmd_fs.fractFreq * 1000) + 65535) / 65536); -// -// return (freq_khz - DOT_15_4G_CHAN0_FREQUENCY) / DOT_15_4G_CHANNEL_SPACING; + uint32_t freq_khz; + + freq_khz = RF_cmdFs.frequency * 1000; + + /* + * For some channels, fractFreq * 1000 / 65536 will return 324.99xx. + * Casting the result to uint32_t will truncate decimals resulting in the + * function returning channel - 1 instead of channel. Thus, we do a quick + * positive integer round up. + */ + freq_khz += (((RF_cmdFs.fractFreq * 1000) + 65535) / 65536); + + return (freq_khz - DOT_15_4G_CHAN0_FREQUENCY) / DOT_15_4G_CHANNEL_SPACING; } /*---------------------------------------------------------------------------*/ static void @@ -396,6 +384,12 @@ set_channel(uint8_t channel) RF_cmdPropRadioDivSetup.centerFreq = freq; RF_cmdFs.frequency = freq; RF_cmdFs.fractFreq = frac; + + // Start FS command asynchronously. We don't care when it is finished. + // "Error" checking is implicitly done later in the RX/TX command + // which will return an error if the synth is not working. + RF_postCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0); + } /*---------------------------------------------------------------------------*/ static uint8_t @@ -441,45 +435,8 @@ set_tx_power(radio_value_t power) } } /*---------------------------------------------------------------------------*/ -static int -prop_div_radio_setup(void) -{ -// uint32_t cmd_status; -// rfc_radioOp_t *cmd = (rfc_radioOp_t *)&smartrf_settings_cmd_prop_radio_div_setup; -// -// rf_switch_select_path(RF_SWITCH_PATH_SUBGHZ); -// -// /* Adjust loDivider depending on the selected band */ -// smartrf_settings_cmd_prop_radio_div_setup.loDivider = PROP_MODE_LO_DIVIDER; -// -// /* Update to the correct TX power setting */ -// smartrf_settings_cmd_prop_radio_div_setup.txPower = tx_power_current->tx_power; -// -// /* Adjust RF Front End and Bias based on the board */ -// smartrf_settings_cmd_prop_radio_div_setup.config.frontEndMode = -// RF_CORE_PROP_FRONT_END_MODE; -// smartrf_settings_cmd_prop_radio_div_setup.config.biasMode = -// RF_CORE_PROP_BIAS_MODE; -// -// /* Send Radio setup to RF Core */ -// if(rf_core_send_cmd((uint32_t)cmd, &cmd_status) != RF_CORE_CMD_OK) { -// PRINTF("prop_div_radio_setup: DIV_SETUP, CMDSTA=0x%08lx, status=0x%04x\n", -// cmd_status, cmd->status); -// return RF_CORE_CMD_ERROR; -// } -// -// /* Wait until radio setup is done */ -// if(rf_core_wait_cmd_done(cmd) != RF_CORE_CMD_OK) { -// PRINTF("prop_div_radio_setup: DIV_SETUP wait, CMDSTA=0x%08lx," -// "status=0x%04x\n", cmd_status, cmd->status); -// return RF_CORE_CMD_ERROR; -// } -// -// return RF_CORE_CMD_OK; -} -/*---------------------------------------------------------------------------*/ static uint8_t -rf_cmd_prop_rx() +rf_start_rx() { uint32_t cmd_status; rtimer_clock_t t0; @@ -507,7 +464,7 @@ rf_cmd_prop_rx() (RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + ENTER_RX_WAIT_TIMEOUT))); /* Wait to enter RX */ - if(cmd_rx_adv->status != RF_CORE_RADIO_OP_STATUS_ACTIVE) { + if(cmd_rx_adv->status != ACTIVE) { PRINTF("rf_cmd_prop_rx: CMDSTA=0x%08lx, status=0x%04x\n", cmd_status, cmd_rx_adv->status); return RF_CORE_CMD_ERROR; @@ -535,27 +492,6 @@ init_rx_buffers(void) } /*---------------------------------------------------------------------------*/ static int -rx_on_prop(void) -{ -// int ret; -// -// if(rf_is_on()) { -// PRINTF("rx_on_prop: We were on. PD=%u, RX=0x%04x\n", -// rf_core_is_accessible(), smartrf_settings_cmd_prop_rx_adv.status); -// return RF_CORE_CMD_OK; -// } -// -// /* Put CPE in RX using the currently configured parameters */ - ret = rf_cmd_prop_rx(); -// -// if(ret) { -// ENERGEST_ON(ENERGEST_TYPE_LISTEN); -// } -// -// return ret; -} -/*---------------------------------------------------------------------------*/ -static int rx_off_prop(void) { uint32_t cmd_status; @@ -587,57 +523,13 @@ rx_off_prop(void) return ret; } /*---------------------------------------------------------------------------*/ -static uint8_t -request(void) -{ -// /* -// * We rely on the RDC layer to turn us on and off. Thus, if we are on we -// * will only allow sleep, standby otherwise -// */ -// if(rf_is_on()) { -// return LPM_MODE_SLEEP; -// } -// -// return LPM_MODE_MAX_SUPPORTED; -} -/*---------------------------------------------------------------------------*/ -LPM_MODULE(prop_lpm_module, request, NULL, NULL, LPM_DOMAIN_NONE); -/*---------------------------------------------------------------------------*/ -static int -prop_fs(void) -{ - RF_EventMask terminationCause = RF_runCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0); - if ((terminationCause == RF_EventLastCmdDone) && (RF_cmdFs.status == DONE_OK)) - { - return RF_CORE_CMD_OK; - } - - return RF_CORE_CMD_ERROR; -} -/*---------------------------------------------------------------------------*/ -static void -soft_off_prop(void) -{ - RF_yield(rfHandle); -} -/*---------------------------------------------------------------------------*/ -static uint8_t -soft_on_prop(void) -{ - return rx_on_prop(); -} -/*---------------------------------------------------------------------------*/ -static const rf_core_primary_mode_t mode_prop = { - soft_off_prop, - soft_on_prop, -}; -/*---------------------------------------------------------------------------*/ static int init(void) { RF_Params params; RF_Params_init(¶ms); params.nInactivityTimeout = 0; // disable automatic power-down + // just to not interfere with stack timing rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, ¶ms); assert(rfHandle != NULL); @@ -652,32 +544,25 @@ init(void) /* Initialize current read pointer to first element (used in ISR) */ rx_read_entry = rx_buf[0]; - smartrf_settings_cmd_prop_rx_adv.pQueue = &rx_data_queue; - smartrf_settings_cmd_prop_rx_adv.pOutput = (uint8_t *)&rx_stats; + 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(RF_CORE_CHANNEL); - if(on() != RF_CORE_CMD_OK) { - PRINTF("init: on() failed\n"); - return RF_CORE_CMD_ERROR; - } + ENERGEST_ON(ENERGEST_TYPE_LISTEN); - ENERGEST_ON(ENERGEST_TYPE_LISTEN); + process_start(&rf_core_process, NULL); - rf_core_primary_mode_register(&mode_prop); - - process_start(&rf_core_process, NULL); - - return 1; + return 1; } /*---------------------------------------------------------------------------*/ static int prepare(const void *payload, unsigned short payload_len) { - int len = MIN(payload_len, TX_BUF_PAYLOAD_LEN); + int len = MIN(payload_len, TX_BUF_PAYLOAD_LEN); - memcpy(&tx_buf[TX_BUF_HDR_LEN], payload, len); - return 0; + memcpy(&tx_buf[TX_BUF_HDR_LEN], payload, len); + return 0; } /*---------------------------------------------------------------------------*/ static int @@ -755,7 +640,7 @@ transmit(unsigned short transmit_len) /* Workaround. Set status to IDLE */ cmd_tx_adv->status = RF_CORE_RADIO_OP_STATUS_IDLE; - rx_on_prop(); + rf_start_rx(); return ret; } @@ -763,149 +648,126 @@ transmit(unsigned short transmit_len) static int send(const void *payload, unsigned short payload_len) { - prepare(payload, payload_len); - return transmit(payload_len); + prepare(payload, payload_len); + return transmit(payload_len); } /*---------------------------------------------------------------------------*/ static int read_frame(void *buf, unsigned short buf_len) { - rfc_dataEntryGeneral_t *entry = (rfc_dataEntryGeneral_t *)rx_read_entry; - uint8_t *data_ptr = &entry->data; - int len = 0; + rfc_dataEntryGeneral_t *entry = (rfc_dataEntryGeneral_t *)rx_read_entry; + uint8_t *data_ptr = &entry->data; + int len = 0; - if(entry->status == DATA_ENTRY_STATUS_FINISHED) { + if(entry->status == DATA_ENTRY_STATUS_FINISHED) { - /* - * First 2 bytes in the data entry are the length. - * Our data entry consists of: Payload + RSSI (1 byte) + Status (1 byte) - * This length includes all of those. - */ - len = (*(uint16_t *)data_ptr); - data_ptr += 2; - len -= 2; + /* + * First 2 bytes in the data entry are the length. + * Our data entry consists of: Payload + RSSI (1 byte) + Status (1 byte) + * This length includes all of those. + */ + len = (*(uint16_t *)data_ptr); + data_ptr += 2; + len -= 2; - if(len > 0) { - if(len <= buf_len) { - memcpy(buf, data_ptr, len); - } + if(len > 0) { + if(len <= buf_len) { + memcpy(buf, data_ptr, len); + } - packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (int8_t)data_ptr[len]); - packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, 0x7F); + packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (int8_t)data_ptr[len]); + packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, 0x7F); + } + + /* Move read entry pointer to next entry */ + rx_read_entry = entry->pNextEntry; + entry->status = DATA_ENTRY_STATUS_PENDING; } - /* Move read entry pointer to next entry */ - rx_read_entry = entry->pNextEntry; - entry->status = DATA_ENTRY_STATUS_PENDING; - } - - return len; + return len; } /*---------------------------------------------------------------------------*/ static int channel_clear(void) { - uint8_t was_off = 0; - uint32_t cmd_status; - int8_t rssi = RF_CMD_CCA_REQ_RSSI_UNKNOWN; + uint8_t was_off = 0; + uint32_t cmd_status; + int8_t rssi = RF_CMD_CCA_REQ_RSSI_UNKNOWN; - /* - * If we are in the middle of a BLE operation, we got called by ContikiMAC - * from within an interrupt context. Indicate a clear channel - */ - if(rf_ble_is_active() == RF_BLE_ACTIVE) { - return RF_CCA_CLEAR; - } +// /* +// * If we are in the middle of a BLE operation, we got called by ContikiMAC +// * from within an interrupt context. Indicate a clear channel +// */ +// if(rf_ble_is_active() == RF_BLE_ACTIVE) { +// return RF_CCA_CLEAR; +// } - if(!rf_core_is_accessible()) { - was_off = 1; - if(on() != RF_CORE_CMD_OK) { - PRINTF("channel_clear: on() failed\n"); - if(was_off) { - off(); - } - return RF_CCA_CLEAR; + if (rf_transmitting()) { + PRINTF("channel_clear: called while in TX\n"); + return RF_CCA_CLEAR; + } else if (!rf_receiving()) { + was_off = 1; + rf_start_rx(); } - } else { - } + while(rssi == RF_CMD_CCA_REQ_RSSI_UNKNOWN || rssi == 0) { + rssi = RF_getRssi(rfHandle); + } - rf_core + if(was_off) { + rf_switch_off(); + } + + if(rssi >= rssi_threshold) { + eturn RF_CCA_BUSY; + } - if(transmitting()) { - PRINTF("channel_clear: called while in TX\n"); return RF_CCA_CLEAR; - } - - while(rssi == RF_CMD_CCA_REQ_RSSI_UNKNOWN || rssi == 0) { - rssi = RF_getRssi(rfHandle); - } - - if(was_off) { - off(); - } - - if(rssi >= rssi_threshold) { - return RF_CCA_BUSY; - } - - return RF_CCA_CLEAR; } /*---------------------------------------------------------------------------*/ static int receiving_packet(void) { - if(!rf_is_on()) { - return 0; - } + if(!rf_is_on()) { + return 0; + } - if(channel_clear() == RF_CCA_CLEAR) { - return 0; - } + if(channel_clear() == RF_CCA_CLEAR) { + return 0; + } - return 1; + return 1; } /*---------------------------------------------------------------------------*/ static int pending_packet(void) { - int rv = 0; - volatile rfc_dataEntry_t *entry = (rfc_dataEntry_t *)rx_data_queue.pCurrEntry; + int rv = 0; + volatile rfc_dataEntry_t *entry = (rfc_dataEntry_t *)rx_data_queue.pCurrEntry; - /* Go through all RX buffers and check their status */ - do { - if(entry->status == DATA_ENTRY_STATUS_FINISHED) { - rv += 1; - process_poll(&rf_core_process); - } + /* Go through all RX buffers and check their status */ + do { + if(entry->status == DATA_ENTRY_STATUS_FINISHED) { + rv += 1; + process_poll(&rf_core_process); + } - entry = (rfc_dataEntry_t *)entry->pNextEntry; - } while(entry != (rfc_dataEntry_t *)rx_data_queue.pCurrEntry); + entry = (rfc_dataEntry_t *)entry->pNextEntry; + } while(entry != (rfc_dataEntry_t *)rx_data_queue.pCurrEntry); - /* If we didn't find an entry at status finished, no frames are pending */ - return rv; + /* If we didn't find an entry at status finished, no frames are pending */ + return rv; } /*---------------------------------------------------------------------------*/ static int -on(void) +rf_switch_on(void) { - init_rx_buffers(); - - rfc_CMD_NOP_t nop = { 0 }; - nop.commandNo = CMD_NOP; - RF_EventMask terminationCause = RF_runCmd(rfHandle, (RF_Op*)&nop, RF_PriorityNormal, NULL, 0); - if ((terminationCause == RF_EventLastCmdDone) && (RF_cmdFs.status == DONE_OK)) - { - return RF_CORE_CMD_OK; - } - - return RF_CORE_CMD_ERROR; - + return rf_start_rx(); } /*---------------------------------------------------------------------------*/ static int -off(void) +rf_switch_off(void) { // /* // * If we are in the middle of a BLE operation, we got called by ContikiMAC @@ -915,6 +777,10 @@ off(void) // return RF_CORE_CMD_OK; // } + // Force abort of any ongoing RF operation. + RF_cancelCmd(rfHandle, RF_CMDHANDLE_FLUSH_ALL, 0); + + // Trigger a manual power-down RF_yield(rfHandle); /* We pulled the plug, so we need to restore the status manually */ @@ -978,14 +844,14 @@ set_value(radio_param_t param, radio_value_t value) switch(param) { case RADIO_PARAM_POWER_MODE: if(value == RADIO_POWER_MODE_ON) { - if(on() != RF_CORE_CMD_OK) { + if(rf_switch_on() != RF_CORE_CMD_OK) { PRINTF("set_value: on() failed (1)\n"); return RADIO_RESULT_ERROR; } return RADIO_RESULT_OK; } if(value == RADIO_POWER_MODE_OFF) { - off(); + rf_switch_off(); return RADIO_RESULT_OK; } return RADIO_RESULT_INVALID_VALUE; @@ -1031,7 +897,7 @@ set_value(radio_param_t param, radio_value_t value) /* If we reach here we had no errors. Apply new settings */ if(!rf_is_on()) { was_off = 1; - if(on() != RF_CORE_CMD_OK) { + if(rf_switch_on() != RF_CORE_CMD_OK) { PRINTF("set_value: on() failed (2)\n"); return RADIO_RESULT_ERROR; } @@ -1049,7 +915,7 @@ set_value(radio_param_t param, radio_value_t value) /* If we were off, turn back off */ if(was_off) { - off(); + rf_switch_off(); } return rv; @@ -1058,13 +924,13 @@ set_value(radio_param_t param, radio_value_t value) static radio_result_t get_object(radio_param_t param, void *dest, size_t size) { - return RADIO_RESULT_NOT_SUPPORTED; + return RADIO_RESULT_NOT_SUPPORTED; } /*---------------------------------------------------------------------------*/ static radio_result_t set_object(radio_param_t param, const void *src, size_t size) { - return RADIO_RESULT_NOT_SUPPORTED; + return RADIO_RESULT_NOT_SUPPORTED; } /*---------------------------------------------------------------------------*/ const struct radio_driver prop_mode_driver = { @@ -1076,8 +942,8 @@ const struct radio_driver prop_mode_driver = { channel_clear, receiving_packet, pending_packet, - on, - off, + rf_switch_on, + rf_switch_off, get_value, set_value, get_object, From 0102628245d0408b1552584dfdc2c137b7db6afe Mon Sep 17 00:00:00 2001 From: Richard Weickelt Date: Fri, 9 Feb 2018 12:50:55 +0100 Subject: [PATCH 234/485] Prop RF driver now complete --- arch/cpu/simplelink/Makefile.simplelink | 1 + arch/cpu/simplelink/dev/dot-15-4g.h | 128 +++++ arch/cpu/simplelink/dev/ieee-addr.c | 90 ++++ arch/cpu/simplelink/dev/ieee-addr.h | 105 ++++ arch/cpu/simplelink/dev/proprietary-rf.c | 457 ++++++++---------- .../rf-settings/proprietary-rf-settings.c | 151 ++++-- .../rf-settings/proprietary-rf-settings.h | 10 +- arch/platform/simplelink/platform.c | 91 ++-- 8 files changed, 690 insertions(+), 343 deletions(-) create mode 100644 arch/cpu/simplelink/dev/dot-15-4g.h create mode 100644 arch/cpu/simplelink/dev/ieee-addr.c create mode 100644 arch/cpu/simplelink/dev/ieee-addr.h diff --git a/arch/cpu/simplelink/Makefile.simplelink b/arch/cpu/simplelink/Makefile.simplelink index 3e35ebfed..3df82643c 100644 --- a/arch/cpu/simplelink/Makefile.simplelink +++ b/arch/cpu/simplelink/Makefile.simplelink @@ -64,6 +64,7 @@ CONTIKI_CPU_SOURCEFILES += rtimer-arch.c clock-arch.c CONTIKI_CPU_SOURCEFILES += watchdog-arch.c putchar-arch.c CONTIKI_CPU_SOURCEFILES += uart0-arch.c CONTIKI_CPU_SOURCEFILES += proprietary-rf.c proprietary-rf-settings.c +CONTIKI_CPU_SOURCEFILES += ieee-addr.c ### CPU-dependent debug source files DEBUG_IO_SOURCEFILES += dbg-printf.c dbg-snprintf.c dbg-sprintf.c strformat.c diff --git a/arch/cpu/simplelink/dev/dot-15-4g.h b/arch/cpu/simplelink/dev/dot-15-4g.h new file mode 100644 index 000000000..7282ac9ba --- /dev/null +++ b/arch/cpu/simplelink/dev/dot-15-4g.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup rf-core + * @{ + * + * \defgroup rf-core-15-4g-modes IEEE 802.15.4g Frequency Bands and Modes + * + * @{ + * + * \file + * Header file with descriptors for the various modes of operation defined in + * IEEE 802.15.4g + */ +/*---------------------------------------------------------------------------*/ +#ifndef DOT_15_4G_H_ +#define DOT_15_4G_H_ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" + +#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 */ +/*---------------------------------------------------------------------------*/ +/* Default band selection to band 4 - 863MHz */ +#ifdef DOT_15_4G_CONF_FREQUENCY_BAND_ID +#define DOT_15_4G_FREQUENCY_BAND_ID DOT_15_4G_CONF_FREQUENCY_BAND_ID +#else +#define DOT_15_4G_FREQUENCY_BAND_ID DOT_15_4G_FREQUENCY_BAND_863 +#endif +/*---------------------------------------------------------------------------*/ +/* + * Channel count, spacing and other params relating to the selected band. We + * currently only support some of the bands defined in .15.4g and for those + * bands we only support operating mode #1 (Table 134). + * + * DOT_15_4G_CHAN0_FREQUENCY is specified here in KHz + */ +#if DOT_15_4G_FREQUENCY_BAND_ID==DOT_15_4G_FREQUENCY_BAND_470 +#define DOT_15_4G_CHANNEL_MAX 198 +#define DOT_15_4G_CHANNEL_SPACING 200 +#define DOT_15_4G_CHAN0_FREQUENCY 470200 +#define PROP_MODE_CONF_LO_DIVIDER 0x0A +#define SMARTRF_SETTINGS_CONF_BAND_OVERRIDES HW32_ARRAY_OVERRIDE(0x405C,1), \ + (uint32_t)0x18000280, + +#elif DOT_15_4G_FREQUENCY_BAND_ID==DOT_15_4G_FREQUENCY_BAND_780 +#define DOT_15_4G_CHANNEL_MAX 38 +#define DOT_15_4G_CHANNEL_SPACING 200 +#define DOT_15_4G_CHAN0_FREQUENCY 779200 +#define PROP_MODE_CONF_LO_DIVIDER 0x06 + +#elif DOT_15_4G_FREQUENCY_BAND_ID==DOT_15_4G_FREQUENCY_BAND_863 +#define DOT_15_4G_CHANNEL_MAX 33 +#define DOT_15_4G_CHANNEL_SPACING 200 +#define DOT_15_4G_CHAN0_FREQUENCY 863125 +#define PROP_MODE_CONF_LO_DIVIDER 0x05 + +#elif DOT_15_4G_FREQUENCY_BAND_ID==DOT_15_4G_FREQUENCY_BAND_915 +#define DOT_15_4G_CHANNEL_MAX 128 +#define DOT_15_4G_CHANNEL_SPACING 200 +#define DOT_15_4G_CHAN0_FREQUENCY 902200 +#define PROP_MODE_CONF_LO_DIVIDER 0x05 + +#elif DOT_15_4G_FREQUENCY_BAND_ID==DOT_15_4G_FREQUENCY_BAND_920 +#define DOT_15_4G_CHANNEL_MAX 37 +#define DOT_15_4G_CHANNEL_SPACING 200 +#define DOT_15_4G_CHAN0_FREQUENCY 920600 +#define PROP_MODE_CONF_LO_DIVIDER 0x05 + +#elif DOT_15_4G_FREQUENCY_BAND_ID==DOT_15_4G_FREQUENCY_BAND_950 +#define DOT_15_4G_CHANNEL_MAX 32 +#define DOT_15_4G_CHANNEL_SPACING 200 +#define DOT_15_4G_CHAN0_FREQUENCY 951000 +#define PROP_MODE_CONF_LO_DIVIDER 0x05 + +#else +#error The selected frequency band is not supported +#endif +/*---------------------------------------------------------------------------*/ +#endif /* DOT_15_4G_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/cpu/simplelink/dev/ieee-addr.c b/arch/cpu/simplelink/dev/ieee-addr.c new file mode 100644 index 000000000..144240cc4 --- /dev/null +++ b/arch/cpu/simplelink/dev/ieee-addr.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup cc26xx-ieee-addr + * @{ + * + * \file + * Driver for the CC13xx/CC26xx IEEE addresses + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "net/linkaddr.h" +#include "ieee-addr.h" + +#include +#include +/*---------------------------------------------------------------------------*/ +void +ieee_addr_cpy_to(uint8_t *dst, uint8_t len) +{ + if(IEEE_ADDR_CONF_HARDCODED) { + uint8_t ieee_addr_hc[8] = IEEE_ADDR_CONF_ADDRESS; + + memcpy(dst, &ieee_addr_hc[8 - len], len); + } else { + int i; + + /* Reading from primary location... */ + uint8_t *location = (uint8_t *)IEEE_ADDR_LOCATION_PRIMARY; + + /* + * ...unless we can find a byte != 0xFF in secondary + * + * Intentionally checking all 8 bytes here instead of len, because we + * are checking validity of the entire IEEE address irrespective of the + * actual number of bytes the caller wants to copy over. + */ + for(i = 0; i < 8; i++) { + if(((uint8_t *)IEEE_ADDR_LOCATION_SECONDARY)[i] != 0xFF) { + /* A byte in the secondary location is not 0xFF. Use the secondary */ + location = (uint8_t *)IEEE_ADDR_LOCATION_SECONDARY; + break; + } + } + + /* + * We have chosen what address to read the IEEE address from. Do so, + * inverting byte order + */ + for(i = 0; i < len; i++) { + dst[i] = location[len - 1 - i]; + } + } + +#if IEEE_ADDR_NODE_ID + dst[len - 1] = IEEE_ADDR_NODE_ID & 0xFF; + dst[len - 2] = IEEE_ADDR_NODE_ID >> 8; +#endif +} +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/cpu/simplelink/dev/ieee-addr.h b/arch/cpu/simplelink/dev/ieee-addr.h new file mode 100644 index 000000000..017ed138e --- /dev/null +++ b/arch/cpu/simplelink/dev/ieee-addr.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup cc26xx + * @{ + * + * \defgroup cc26xx-ieee-addr CC13xx/CC26xx IEEE Address Control + * + * Driver for the retrieval of an IEEE address from flash + * + * The user can specify a hardcoded IEEE address through the + * IEEE_ADDR_CONF_HARDCODED configuration macro. + * + * If the user does not hard-code an address, then one will be read from either + * the primary location (InfoPage) or from the secondary location (on flash). + * + * In order to allow the user to easily program nodes with addresses, the + * secondary location is given priority: If it contains a valid address then + * it will be chosen in favour of the one on InfoPage. + * + * In this context, an address is valid if at least one of the 8 bytes does not + * equal 0xFF. If all 8 bytes are 0xFF, then the primary location will be used. + * + * In all cases, the address is assumed to be written little-endian. + * + * Lastly, it is possible to override the 2 LSB's of the address by using the + * NODE_ID make variable. + * @{ + * + * \file + * Header file with register and macro declarations for the cc26xx IEEE address + * driver + */ +/*---------------------------------------------------------------------------*/ +#ifndef IEEE_ADDR_H_ +#define IEEE_ADDR_H_ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" + +#include +/*---------------------------------------------------------------------------*/ +/** + * \name IEEE address locations + * + * The address of the secondary location can be configured by the platform + * or example + * + * @{ + */ +#define IEEE_ADDR_LOCATION_PRIMARY 0x500012F0 /**< Primary IEEE address location */ + +#ifdef IEEE_ADDR_CONF_LOCATION_SECONDARY +#define IEEE_ADDR_LOCATION_SECONDARY IEEE_ADDR_CONF_LOCATION_SECONDARY +#else +#define IEEE_ADDR_LOCATION_SECONDARY 0x0001FFC8 /**< Secondary IEEE address location */ +#endif +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \brief Copy the node's IEEE address to a destination memory area + * \param dst A pointer to the destination area where the IEEE address is to be + * written + * \param len The number of bytes to write to destination area + * + * This function will copy \e len LS bytes and it will invert byte order in + * the process. The factory address on devices is normally little-endian, + * therefore you should expect dst to store the address in a big-endian order. + */ +void ieee_addr_cpy_to(uint8_t *dst, uint8_t len); +/*---------------------------------------------------------------------------*/ +#endif /* IEEE_ADDR_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/cpu/simplelink/dev/proprietary-rf.c b/arch/cpu/simplelink/dev/proprietary-rf.c index 072e442be..5dfb3b1a1 100644 --- a/arch/cpu/simplelink/dev/proprietary-rf.c +++ b/arch/cpu/simplelink/dev/proprietary-rf.c @@ -43,8 +43,10 @@ #include "sys/clock.h" #include "sys/rtimer.h" #include "sys/cc.h" +#include "dev/watchdog.h" #include "proprietary-rf.h" #include "rf-core.h" +#include "dot-15-4g.h" /*---------------------------------------------------------------------------*/ /* RF core and RF HAL API */ #include @@ -63,6 +65,7 @@ #include #include #include +#include /*---------------------------------------------------------------------------*/ #define DEBUG 0 #if DEBUG @@ -231,87 +234,10 @@ static uint8_t tx_buf[TX_BUF_HDR_LEN + TX_BUF_PAYLOAD_LEN] CC_ALIGN(4); /* RF driver */ static RF_Object rfObject; static RF_Handle rfHandle; +static RF_CmdHandle rxCmdHandle = RF_ALLOC_ERROR; /*---------------------------------------------------------------------------*/ -/* CMD_PROP_TX_ADV */ -rfc_CMD_PROP_TX_ADV_t smartrf_settings_cmd_prop_tx_adv = -{ - .commandNo = 0x3803, - .status = 0x0000, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .pktConf.bFsOff = 0x0, - .pktConf.bUseCrc = 0x1, - .pktConf.bCrcIncSw = 0x0, /* .4g mode */ - .pktConf.bCrcIncHdr = 0x0, /* .4g mode */ - .numHdrBits = 0x10 /* 16: .4g mode */, - .pktLen = 0x0000, - .startConf.bExtTxTrig = 0x0, - .startConf.inputMode = 0x0, - .startConf.source = 0x0, - .preTrigger.triggerType = TRIG_REL_START, - .preTrigger.bEnaCmd = 0x0, - .preTrigger.triggerNo = 0x0, - .preTrigger.pastTrig = 0x1, - .preTime = 0x00000000, - .syncWord = 0x0055904e, - .pPkt = 0, -}; -/*---------------------------------------------------------------------------*/ -/* CMD_PROP_RX_ADV */ -rfc_CMD_PROP_RX_ADV_t smartrf_settings_cmd_prop_rx_adv = -{ - .commandNo = 0x3804, - .status = 0x0000, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .pktConf.bFsOff = 0x0, - .pktConf.bRepeatOk = 0x1, - .pktConf.bRepeatNok = 0x1, - .pktConf.bUseCrc = 0x1, - .pktConf.bCrcIncSw = 0x0, /* .4g mode */ - .pktConf.bCrcIncHdr = 0x0, /* .4g mode */ - .pktConf.endType = 0x0, - .pktConf.filterOp = 0x1, - .rxConf.bAutoFlushIgnored = 0x1, - .rxConf.bAutoFlushCrcErr = 0x1, - .rxConf.bIncludeHdr = 0x0, - .rxConf.bIncludeCrc = 0x0, - .rxConf.bAppendRssi = 0x1, - .rxConf.bAppendTimestamp = 0x0, - .rxConf.bAppendStatus = 0x1, - .syncWord0 = 0x0055904e, - .syncWord1 = 0x00000000, - .maxPktLen = 0x0000, /* To be populated by the driver. */ - .hdrConf.numHdrBits = 0x10, /* 16: .4g mode */ - .hdrConf.lenPos = 0x0, /* .4g mode */ - .hdrConf.numLenBits = 0x0B, /* 11 = 0x0B .4g mode */ - .addrConf.addrType = 0x0, - .addrConf.addrSize = 0x0, - .addrConf.addrPos = 0x0, - .addrConf.numAddr = 0x0, - .lenOffset = -4, /* .4g mode */ - .endTrigger.triggerType = TRIG_NEVER, - .endTrigger.bEnaCmd = 0x0, - .endTrigger.triggerNo = 0x0, - .endTrigger.pastTrig = 0x0, - .endTime = 0x00000000, - .pAddr = 0, - .pQueue = 0, - .pOutput = 0, -}; -/*---------------------------------------------------------------------------*/ +PROCESS(rf_core_process, "CC13xx / CC26xx RF driver"); + static uint8_t rf_transmitting(void) { @@ -324,6 +250,95 @@ rf_receiving(void) return smartrf_settings_cmd_prop_rx_adv.status == ACTIVE; } /*---------------------------------------------------------------------------*/ +static uint8_t +rf_is_on(void) +{ + return rf_receiving() | rf_transmitting(); +} +/*---------------------------------------------------------------------------*/ +static void +rf_rx_callback(RF_Handle client, RF_CmdHandle command, RF_EventMask events) +{ + if (events & RF_EventRxEntryDone) { + process_poll(&rf_core_process); + } +} +/*---------------------------------------------------------------------------*/ +static uint8_t +rf_start_rx() +{ + rtimer_clock_t t0; + volatile rfc_CMD_PROP_RX_ADV_t *cmd_rx_adv; + + cmd_rx_adv = (rfc_CMD_PROP_RX_ADV_t *)&smartrf_settings_cmd_prop_rx_adv; + cmd_rx_adv->status = IDLE; + + /* + * Set the max Packet length. This is for the payload only, therefore + * 2047 - length offset + */ + cmd_rx_adv->maxPktLen = DOT_4G_MAX_FRAME_LEN - cmd_rx_adv->lenOffset; + + rxCmdHandle = RF_postCmd(rfHandle, (RF_Op*)&smartrf_settings_cmd_prop_rx_adv, RF_PriorityNormal, &rf_rx_callback, RF_EventRxEntryDone); + if (rxCmdHandle == RF_ALLOC_ERROR) { + return RF_CORE_CMD_ERROR; + } + + t0 = RTIMER_NOW(); + + while(cmd_rx_adv->status != ACTIVE && + (RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + ENTER_RX_WAIT_TIMEOUT))); + + /* Wait to enter RX */ + if(cmd_rx_adv->status != ACTIVE) { + PRINTF("rf_cmd_prop_rx: CMDSTA=0x%08lx, status=0x%04x\n", + md_status, cmd_rx_adv->status); + rf_switch_off(); + return RF_CORE_CMD_ERROR; + } + + return RF_CORE_CMD_OK; +} +/*---------------------------------------------------------------------------*/ +static int +rf_stop_rx(void) +{ + int ret; + + /* If we are off, do nothing */ + if(!rf_receiving()) { + return RF_CORE_CMD_OK; + } + + /* Abort any ongoing operation. Don't care about the result. */ + RF_cancelCmd(rfHandle, RF_CMDHANDLE_FLUSH_ALL, 1); + + /* Todo: maybe do a RF_pendCmd() to synchronise with command execution. */ + + if(smartrf_settings_cmd_prop_rx_adv.status == PROP_DONE_STOPPED || + smartrf_settings_cmd_prop_rx_adv.status == PROP_DONE_ABORT) { + /* Stopped gracefully */ + ENERGEST_OFF(ENERGEST_TYPE_LISTEN); + ret = RF_CORE_CMD_OK; + } else { + PRINTF("rx_off_prop: status=0x%04x\n", + smartrf_settings_cmd_prop_rx_adv.status); + ret = RF_CORE_CMD_ERROR; + } + + return ret; +}/*---------------------------------------------------------------------------*/ +static uint8_t +rf_run_setup() +{ + RF_runCmd(rfHandle, (RF_Op*)&smartrf_settings_cmd_prop_radio_div_setup, RF_PriorityNormal, NULL, 0); + if (((volatile RF_Op*)&smartrf_settings_cmd_prop_radio_div_setup)->status != PROP_DONE_OK) { + return RF_CORE_CMD_ERROR; + } + + return RF_CORE_CMD_OK; +} +/*---------------------------------------------------------------------------*/ static radio_value_t get_rssi(void) { @@ -354,7 +369,7 @@ get_channel(void) { uint32_t freq_khz; - freq_khz = RF_cmdFs.frequency * 1000; + freq_khz = smartrf_settings_cmd_prop_fs.frequency * 1000; /* * For some channels, fractFreq * 1000 / 65536 will return 324.99xx. @@ -362,7 +377,7 @@ get_channel(void) * function returning channel - 1 instead of channel. Thus, we do a quick * positive integer round up. */ - freq_khz += (((RF_cmdFs.fractFreq * 1000) + 65535) / 65536); + freq_khz += (((smartrf_settings_cmd_prop_fs.fractFreq * 1000) + 65535) / 65536); return (freq_khz - DOT_15_4G_CHAN0_FREQUENCY) / DOT_15_4G_CHANNEL_SPACING; } @@ -370,26 +385,28 @@ get_channel(void) static void set_channel(uint8_t channel) { - uint32_t new_freq; - uint16_t freq, frac; + uint32_t new_freq; + uint16_t freq, frac; - new_freq = DOT_15_4G_CHAN0_FREQUENCY + (channel * DOT_15_4G_CHANNEL_SPACING); + new_freq = DOT_15_4G_CHAN0_FREQUENCY + (channel * DOT_15_4G_CHANNEL_SPACING); - freq = (uint16_t)(new_freq / 1000); - frac = (new_freq - (freq * 1000)) * 65536 / 1000; + freq = (uint16_t)(new_freq / 1000); + frac = (new_freq - (freq * 1000)) * 65536 / 1000; - PRINTF("set_channel: %u = 0x%04x.0x%04x (%lu)\n", channel, freq, frac, + PRINTF("set_channel: %u = 0x%04x.0x%04x (%lu)\n", channel, freq, frac, new_freq); - RF_cmdPropRadioDivSetup.centerFreq = freq; - RF_cmdFs.frequency = freq; - RF_cmdFs.fractFreq = frac; + smartrf_settings_cmd_prop_radio_div_setup.centerFreq = freq; + smartrf_settings_cmd_prop_fs.frequency = freq; + smartrf_settings_cmd_prop_fs.fractFreq = frac; - // Start FS command asynchronously. We don't care when it is finished. - // "Error" checking is implicitly done later in the RX/TX command - // which will return an error if the synth is not working. - RF_postCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0); + // Todo: Need to re-run setup command when deviation from previous frequency + // is too large + // rf_run_setup(); + // We don't care whether the FS command is successful because subsequent + // TX and RX commands will tell us indirectly. + RF_postCmd(rfHandle, (RF_Op*)&smartrf_settings_cmd_prop_fs, RF_PriorityNormal, NULL, 0); } /*---------------------------------------------------------------------------*/ static uint8_t @@ -435,44 +452,6 @@ set_tx_power(radio_value_t power) } } /*---------------------------------------------------------------------------*/ -static uint8_t -rf_start_rx() -{ - uint32_t cmd_status; - rtimer_clock_t t0; - volatile rfc_CMD_PROP_RX_ADV_t *cmd_rx_adv; - int ret; - - cmd_rx_adv = (rfc_CMD_PROP_RX_ADV_t *)&smartrf_settings_cmd_prop_rx_adv; - cmd_rx_adv->status = IDLE; - - /* - * Set the max Packet length. This is for the payload only, therefore - * 2047 - length offset - */ - cmd_rx_adv->maxPktLen = DOT_4G_MAX_FRAME_LEN - cmd_rx_adv->lenOffset; - - // Todo: subscribe events - RF_CmdHandle cmd = RF_postCmd(rfHandle, (RF_Op*)&smartrf_settings_cmd_prop_rx_adv, RF_PriorityNormal, NULL, 0); - if (cmd == RF_ALLOC_ERROR) { - return RF_CORE_CMD_ERROR; - } - - t0 = RTIMER_NOW(); - - while(cmd_rx_adv->status != ACTIVE && - (RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + ENTER_RX_WAIT_TIMEOUT))); - - /* Wait to enter RX */ - if(cmd_rx_adv->status != ACTIVE) { - PRINTF("rf_cmd_prop_rx: CMDSTA=0x%08lx, status=0x%04x\n", - cmd_status, cmd_rx_adv->status); - return RF_CORE_CMD_ERROR; - } - - return RF_CORE_CMD_OK; -} -/*---------------------------------------------------------------------------*/ static void init_rx_buffers(void) { @@ -492,71 +471,6 @@ init_rx_buffers(void) } /*---------------------------------------------------------------------------*/ static int -rx_off_prop(void) -{ - uint32_t cmd_status; - int ret; - - /* If we are off, do nothing */ - if(!rf_is_on()) { - return RF_CORE_CMD_OK; - } - - - /* Abort any ongoing operation. Don't care about the result. */ - RF_cancelCmd(rfHandle, RF_CMDHANDLE_FLUSH_ALL, 1); - RF_yield(rfHandle); - - while(rf_is_on()); - - if(smartrf_settings_cmd_prop_rx_adv.status == PROP_DONE_STOPPED || - smartrf_settings_cmd_prop_rx_adv.status == PROP_DONE_ABORT) { - /* Stopped gracefully */ - ENERGEST_OFF(ENERGEST_TYPE_LISTEN); - ret = RF_CORE_CMD_OK; - } else { - PRINTF("rx_off_prop: status=0x%04x\n", - smartrf_settings_cmd_prop_rx_adv.status); - ret = RF_CORE_CMD_ERROR; - } - - return ret; -} -/*---------------------------------------------------------------------------*/ -static int -init(void) -{ - RF_Params params; - RF_Params_init(¶ms); - params.nInactivityTimeout = 0; // disable automatic power-down - // just to not interfere with stack timing - - rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, ¶ms); - assert(rfHandle != NULL); - - /* Initialise RX buffers */ - memset(rx_buf, 0, sizeof(rx_buf)); - - /* Set of RF Core data queue. Circular buffer, no last entry */ - rx_data_queue.pCurrEntry = rx_buf[0]; - rx_data_queue.pLastEntry = NULL; - - /* Initialize current read pointer to first element (used in ISR) */ - rx_read_entry = rx_buf[0]; - - 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); - - ENERGEST_ON(ENERGEST_TYPE_LISTEN); - - process_start(&rf_core_process, NULL); - - return 1; -} -/*---------------------------------------------------------------------------*/ -static int prepare(const void *payload, unsigned short payload_len) { int len = MIN(payload_len, TX_BUF_PAYLOAD_LEN); @@ -570,9 +484,17 @@ transmit(unsigned short transmit_len) { int ret; uint8_t was_off = 0; - uint32_t cmd_status; volatile rfc_CMD_PROP_TX_ADV_t *cmd_tx_adv; + if (rf_transmitting()) { + PRINTF("transmit: not allowed while transmitting\n"); + return RADIO_TX_ERR; + } else if (rf_receiving()) { + rf_stop_rx(); + } else { + was_off = 1; + } + /* Length in .15.4g PHY HDR. Includes the CRC but not the HDR itself */ uint16_t total_length; @@ -599,10 +521,6 @@ transmit(unsigned short transmit_len) cmd_tx_adv->pktLen = transmit_len + DOT_4G_PHR_LEN; cmd_tx_adv->pPkt = tx_buf; - was_off = rx_ - /* Abort RX */ - rx_off_prop(); - // TODO: Register callback RF_CmdHandle txHandle = RF_postCmd(rfHandle, (RF_Op*)&cmd_tx_adv, RF_PriorityNormal, NULL, 0); if (txHandle == RF_ALLOC_ERROR) @@ -613,8 +531,7 @@ transmit(unsigned short transmit_len) return RADIO_TX_ERR; } - /* If we enter here, TX actually started */ - ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT); + ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); // watchdog_periodic(); @@ -631,16 +548,16 @@ transmit(unsigned short transmit_len) ret = RADIO_TX_ERR; } - /* - * Update ENERGEST state here, before a potential call to off(), which - * will correctly update it if required. - */ - ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN); + ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); /* Workaround. Set status to IDLE */ - cmd_tx_adv->status = RF_CORE_RADIO_OP_STATUS_IDLE; + cmd_tx_adv->status = IDLE; - rf_start_rx(); + if (was_off) { + RF_yield(rfHandle); + } else { + rf_start_rx(); + } return ret; } @@ -691,7 +608,6 @@ static int channel_clear(void) { uint8_t was_off = 0; - uint32_t cmd_status; int8_t rssi = RF_CMD_CCA_REQ_RSSI_UNKNOWN; // /* @@ -719,7 +635,7 @@ channel_clear(void) } if(rssi >= rssi_threshold) { - eturn RF_CCA_BUSY; + return RF_CCA_BUSY; } return RF_CCA_CLEAR; @@ -728,7 +644,7 @@ channel_clear(void) static int receiving_packet(void) { - if(!rf_is_on()) { + if(!rf_receiving()) { return 0; } @@ -838,16 +754,10 @@ get_value(radio_param_t param, radio_value_t *value) static radio_result_t set_value(radio_param_t param, radio_value_t value) { - uint8_t was_off = 0; - radio_result_t rv = RADIO_RESULT_OK; - switch(param) { case RADIO_PARAM_POWER_MODE: if(value == RADIO_POWER_MODE_ON) { - if(rf_switch_on() != RF_CORE_CMD_OK) { - PRINTF("set_value: on() failed (1)\n"); - return RADIO_RESULT_ERROR; - } + // Powering on happens implicitly return RADIO_RESULT_OK; } if(value == RADIO_POWER_MODE_OFF) { @@ -874,51 +784,36 @@ set_value(radio_param_t param, radio_value_t value) value > OUTPUT_POWER_MAX) { return RADIO_RESULT_INVALID_VALUE; } - - soft_off_prop(); - set_tx_power(value); - - if(soft_on_prop() != RF_CORE_CMD_OK) { - PRINTF("set_value: soft_on_prop() failed\n"); - rv = RADIO_RESULT_ERROR; - } - return RADIO_RESULT_OK; case RADIO_PARAM_RX_MODE: return RADIO_RESULT_OK; case RADIO_PARAM_CCA_THRESHOLD: rssi_threshold = (int8_t)value; + return RADIO_RESULT_OK; break; default: return RADIO_RESULT_NOT_SUPPORTED; } /* If we reach here we had no errors. Apply new settings */ - if(!rf_is_on()) { - was_off = 1; - if(rf_switch_on() != RF_CORE_CMD_OK) { - PRINTF("set_value: on() failed (2)\n"); + if (rf_receiving()) { + rf_stop_rx(); + if (rf_run_setup() != RF_CORE_CMD_OK) { + return RADIO_RESULT_ERROR; + } + rf_start_rx(); + } else if (rf_transmitting()) { + // Should not happen. TX is always synchronous and blocking. + // Todo: maybe remove completely here. + PRINTF("set_value: cannot apply new value while transmitting. \n"); return RADIO_RESULT_ERROR; - } + } else { + // was powered off. Nothing to do. New values will be + // applied automatically on next power-up. } - if(rx_off_prop() != RF_CORE_CMD_OK) { - PRINTF("set_value: rx_off_prop() failed\n"); - rv = RADIO_RESULT_ERROR; - } - - if(soft_on_prop() != RF_CORE_CMD_OK) { - PRINTF("set_value: rx_on_prop() failed\n"); - rv = RADIO_RESULT_ERROR; - } - - /* If we were off, turn back off */ - if(was_off) { - rf_switch_off(); - } - - return rv; + return RADIO_RESULT_OK; } /*---------------------------------------------------------------------------*/ static radio_result_t @@ -933,8 +828,64 @@ set_object(radio_param_t param, const void *src, size_t size) return RADIO_RESULT_NOT_SUPPORTED; } /*---------------------------------------------------------------------------*/ +static int +rf_init(void) +{ + RF_Params params; + RF_Params_init(¶ms); + params.nInactivityTimeout = 0; // disable automatic power-down + // just to not interfere with stack timing + + rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&smartrf_settings_cmd_prop_radio_div_setup, ¶ms); + assert(rfHandle != NULL); + + /* Initialise RX buffers */ + memset(rx_buf, 0, sizeof(rx_buf)); + + /* Set of RF Core data queue. Circular buffer, no last entry */ + rx_data_queue.pCurrEntry = rx_buf[0]; + rx_data_queue.pLastEntry = NULL; + + /* Initialize current read pointer to first element (used in ISR) */ + rx_read_entry = rx_buf[0]; + + 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); + + ENERGEST_ON(ENERGEST_TYPE_LISTEN); + + process_start(&rf_core_process, NULL); + + return 1; +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(rf_core_process, ev, data) +{ + int len; + + PROCESS_BEGIN(); + + while(1) { + PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL); + do { + watchdog_periodic(); + packetbuf_clear(); + len = NETSTACK_RADIO.read(packetbuf_dataptr(), PACKETBUF_SIZE); + + if(len > 0) { + packetbuf_set_datalen(len); + + NETSTACK_MAC.input(); + } + } while(len > 0); + } + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ const struct radio_driver prop_mode_driver = { - init, + rf_init, prepare, transmit, send, diff --git a/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.c b/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.c index 4620a9b55..f66d75c5c 100644 --- a/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.c +++ b/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.c @@ -136,46 +136,46 @@ static uint32_t pOverrides[] = // CMD_PROP_RADIO_DIV_SETUP // Proprietary Mode Radio Setup Command for All Frequency Bands -rfc_CMD_PROP_RADIO_DIV_SETUP_t RF_cmdPropRadioDivSetup = +rfc_CMD_PROP_RADIO_DIV_SETUP_t smartrf_settings_cmd_prop_radio_div_setup = { - .commandNo = 0x3807, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .modulation.modType = 0x1, - .modulation.deviation = 0x64, - .modulation.deviationStepSz = 0x0, - .symbolRate.preScale = 0xF, - .symbolRate.rateWord = 0x8000, - .symbolRate.decimMode = 0x0, - .rxBw = 0x52, - .preamConf.nPreamBytes = 0x4, - .preamConf.preamMode = 0x0, - .formatConf.nSwBits = 0x20, - .formatConf.bBitReversal = 0x0, - .formatConf.bMsbFirst = 0x1, - .formatConf.fecMode = 0x0, - .formatConf.whitenMode = 0x0, - .config.frontEndMode = 0x0, - .config.biasMode = 0x1, - .config.analogCfgMode = 0x0, - .config.bNoFsPowerUp = 0x0, - .txPower = 0x9F3F, - .pRegOverride = pOverrides, - .centerFreq = 0x0364, - .intFreq = 0x8000, - .loDivider = 0x05, + .commandNo = 0x3807, + .status = 0x0000, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .modulation.modType = 0x1, + .modulation.deviation = 0x64, + .symbolRate.preScale = 0xf, + .symbolRate.rateWord = 0x8000, + .rxBw = 0x24, + .preamConf.nPreamBytes = 0x3, + .preamConf.preamMode = 0x0, + .formatConf.nSwBits = 0x18, + .formatConf.bBitReversal = 0x0, + .formatConf.bMsbFirst = 0x1, + .formatConf.fecMode = 0x0, + + /* 7: .4g mode with dynamic whitening and CRC choice */ + .formatConf.whitenMode = 0x7, + .config.frontEndMode = 0x00, /* Set by the driver */ + .config.biasMode = 0x00, /* Set by the driver */ + .config.analogCfgMode = 0x0, + .config.bNoFsPowerUp = 0x0, + .txPower = 0x00, /* Driver sets correct value */ + .pRegOverride = pOverrides, + .intFreq = 0x8000, + .centerFreq = 868, + .loDivider = 0x05, }; // CMD_FS // Frequency Synthesizer Programming Command -rfc_CMD_FS_t RF_cmdFs = +rfc_CMD_FS_t smartrf_settings_cmd_prop_fs = { .commandNo = 0x0803, .status = 0x0000, @@ -196,3 +196,84 @@ rfc_CMD_FS_t RF_cmdFs = .__dummy2 = 0x00, .__dummy3 = 0x0000, }; + +/* CMD_PROP_TX_ADV */ +rfc_CMD_PROP_TX_ADV_t smartrf_settings_cmd_prop_tx_adv = +{ + .commandNo = 0x3803, + .status = 0x0000, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .pktConf.bFsOff = 0x0, + .pktConf.bUseCrc = 0x1, + .pktConf.bCrcIncSw = 0x0, /* .4g mode */ + .pktConf.bCrcIncHdr = 0x0, /* .4g mode */ + .numHdrBits = 0x10 /* 16: .4g mode */, + .pktLen = 0x0000, + .startConf.bExtTxTrig = 0x0, + .startConf.inputMode = 0x0, + .startConf.source = 0x0, + .preTrigger.triggerType = TRIG_REL_START, + .preTrigger.bEnaCmd = 0x0, + .preTrigger.triggerNo = 0x0, + .preTrigger.pastTrig = 0x1, + .preTime = 0x00000000, + .syncWord = 0x0055904e, + .pPkt = 0, +}; +/*---------------------------------------------------------------------------*/ +/* CMD_PROP_RX_ADV */ +rfc_CMD_PROP_RX_ADV_t smartrf_settings_cmd_prop_rx_adv = +{ + .commandNo = 0x3804, + .status = 0x0000, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .pktConf.bFsOff = 0x0, + .pktConf.bRepeatOk = 0x1, + .pktConf.bRepeatNok = 0x1, + .pktConf.bUseCrc = 0x1, + .pktConf.bCrcIncSw = 0x0, /* .4g mode */ + .pktConf.bCrcIncHdr = 0x0, /* .4g mode */ + .pktConf.endType = 0x0, + .pktConf.filterOp = 0x1, + .rxConf.bAutoFlushIgnored = 0x1, + .rxConf.bAutoFlushCrcErr = 0x1, + .rxConf.bIncludeHdr = 0x0, + .rxConf.bIncludeCrc = 0x0, + .rxConf.bAppendRssi = 0x1, + .rxConf.bAppendTimestamp = 0x0, + .rxConf.bAppendStatus = 0x1, + .syncWord0 = 0x0055904e, + .syncWord1 = 0x00000000, + .maxPktLen = 0x0000, /* To be populated by the driver. */ + .hdrConf.numHdrBits = 0x10, /* 16: .4g mode */ + .hdrConf.lenPos = 0x0, /* .4g mode */ + .hdrConf.numLenBits = 0x0B, /* 11 = 0x0B .4g mode */ + .addrConf.addrType = 0x0, + .addrConf.addrSize = 0x0, + .addrConf.addrPos = 0x0, + .addrConf.numAddr = 0x0, + .lenOffset = -4, /* .4g mode */ + .endTrigger.triggerType = TRIG_NEVER, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, + .pAddr = 0, + .pQueue = 0, + .pOutput = 0, +}; +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.h b/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.h index 456804fb7..f01ae3498 100644 --- a/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.h +++ b/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.h @@ -13,16 +13,14 @@ #include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h) #include - // TI-RTOS RF Mode Object extern RF_Mode RF_prop; - // RF Core API commands -extern rfc_CMD_PROP_RADIO_DIV_SETUP_t RF_cmdPropRadioDivSetup; -extern rfc_CMD_FS_t RF_cmdFs; -extern rfc_CMD_PROP_TX_t RF_cmdPropTx; -extern rfc_CMD_PROP_RX_t RF_cmdPropRx; +extern rfc_CMD_PROP_RADIO_DIV_SETUP_t smartrf_settings_cmd_prop_radio_div_setup; +extern rfc_CMD_FS_t smartrf_settings_cmd_prop_fs; +extern rfc_CMD_PROP_TX_ADV_t smartrf_settings_cmd_prop_tx_adv; +extern rfc_CMD_PROP_RX_ADV_t smartrf_settings_cmd_prop_rx_adv; #endif // _PROPRIETARY_RF_SETTINGS_H_ diff --git a/arch/platform/simplelink/platform.c b/arch/platform/simplelink/platform.c index 9d09a072d..5a0ddb8c7 100644 --- a/arch/platform/simplelink/platform.c +++ b/arch/platform/simplelink/platform.c @@ -57,27 +57,20 @@ #include "uart0-arch.h" -//#include "leds.h" -//#include "lpm.h" +#include "leds.h" //#include "gpio-interrupt.h" -//#include "dev/oscillators.h" -//#include "ieee-addr.h" -//#include "vims.h" -//#include "dev/cc26xx-uart.h" -//#include "dev/soc-rtc.h" -//#include "rf-core/rf-core.h" -//#include "sys_ctrl.h" +#include "ieee-addr.h" //#include "uart.h" -//#include "sys/clock.h" -//#include "sys/rtimer.h" -//#include "sys/node-id.h" -//#include "sys/platform.h" -//#include "lib/random.h" -//#include "lib/sensors.h" -//#include "button-sensor.h" -//#include "dev/serial-line.h" -//#include "net/mac/framer/frame802154.h" -// +#include "sys/clock.h" +#include "sys/rtimer.h" +#include "sys/node-id.h" +#include "sys/platform.h" +#include "lib/random.h" +#include "lib/sensors.h" +#include "button-sensor.h" +#include "dev/serial-line.h" +#include "net/mac/framer/frame802154.h" + //#include "driverlib/driverlib_release.h" #include @@ -111,25 +104,25 @@ fade(unsigned char l) } } /*---------------------------------------------------------------------------*/ -//static void -//set_rf_params(void) -//{ -// uint16_t short_addr; -// uint8_t ext_addr[8]; -// -// ieee_addr_cpy_to(ext_addr, 8); -// -// short_addr = ext_addr[7]; -// short_addr |= ext_addr[6] << 8; -// -// 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_object(RADIO_PARAM_64BIT_ADDR, ext_addr, 8); -// -// /* also set the global node id */ -// node_id = short_addr; -//} +static void +set_rf_params(void) +{ + uint16_t short_addr; + uint8_t ext_addr[8]; + + ieee_addr_cpy_to(ext_addr, 8); + + short_addr = ext_addr[7]; + short_addr |= ext_addr[6] << 8; + + 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_object(RADIO_PARAM_64BIT_ADDR, ext_addr, 8); + + /* also set the global node id */ + node_id = short_addr; +} /*---------------------------------------------------------------------------*/ void platform_init_stage_one() @@ -178,8 +171,8 @@ platform_init_stage_two() // // serial_line_init(); // -// /* Populate linkaddr_node_addr */ -// ieee_addr_cpy_to(linkaddr_node_addr.u8, LINKADDR_SIZE); + /* Populate linkaddr_node_addr */ + ieee_addr_cpy_to(linkaddr_node_addr.u8, LINKADDR_SIZE); // fade(Board_GPIO_LED0); } @@ -187,13 +180,13 @@ platform_init_stage_two() void platform_init_stage_three() { -// radio_value_t chan, pan; -// -// set_rf_params(); -// -// NETSTACK_RADIO.get_value(RADIO_PARAM_CHANNEL, &chan); -// NETSTACK_RADIO.get_value(RADIO_PARAM_PAN_ID, &pan); -// + radio_value_t chan, pan; + + set_rf_params(); + + NETSTACK_RADIO.get_value(RADIO_PARAM_CHANNEL, &chan); + NETSTACK_RADIO.get_value(RADIO_PARAM_PAN_ID, &pan); + LOG_DBG("With DriverLib v%u.%u\n", DRIVERLIB_RELEASE_GROUP, DRIVERLIB_RELEASE_BUILD); //LOG_INFO(BOARD_STRING "\n"); @@ -202,8 +195,8 @@ platform_init_stage_three() ChipInfo_ChipFamilyIs_CC13x0() ? "Yes" : "No", ChipInfo_SupportsBLE() ? "Yes" : "No", ChipInfo_SupportsPROPRIETARY() ? "Yes" : "No"); - //LOG_INFO(" RF: Channel %d, PANID 0x%04X\n", chan, pan); - //LOG_INFO(" Node ID: %d\n", node_id); + LOG_INFO(" RF: Channel %d, PANID 0x%04X\n", chan, pan); + LOG_INFO(" Node ID: %d\n", node_id); // // process_start(&sensors_process, NULL); fade(Board_GPIO_LED1); From 56721d13cf5ac6d6c149f31f9b19e4afb52e25a7 Mon Sep 17 00:00:00 2001 From: Richard Weickelt Date: Fri, 9 Feb 2018 14:39:40 +0100 Subject: [PATCH 235/485] Working prop rf driver --- arch/cpu/simplelink/dev/proprietary-rf.c | 30 +++++++++---------- .../rf-settings/proprietary-rf-settings.c | 4 +-- arch/platform/simplelink/platform.c | 8 ++--- os/contiki-main.c | 28 ++++++++--------- 4 files changed, 35 insertions(+), 35 deletions(-) diff --git a/arch/cpu/simplelink/dev/proprietary-rf.c b/arch/cpu/simplelink/dev/proprietary-rf.c index 5dfb3b1a1..b8a2ec7c1 100644 --- a/arch/cpu/simplelink/dev/proprietary-rf.c +++ b/arch/cpu/simplelink/dev/proprietary-rf.c @@ -522,21 +522,21 @@ transmit(unsigned short transmit_len) cmd_tx_adv->pPkt = tx_buf; // TODO: Register callback - RF_CmdHandle txHandle = RF_postCmd(rfHandle, (RF_Op*)&cmd_tx_adv, RF_PriorityNormal, NULL, 0); - if (txHandle == RF_ALLOC_ERROR) - { - /* Failure sending the CMD_PROP_TX command */ - PRINTF("transmit: PROP_TX_ERR ret=%d, CMDSTA=0x%08lx, status=0x%04x\n", - ret, cmd_status, cmd_tx_adv->status); - return RADIO_TX_ERR; - } - - ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); - - // watchdog_periodic(); - - /* Idle away while the command is running */ - RF_pendCmd(rfHandle, txHandle, 0); + RF_runCmd(rfHandle, (RF_Op*)cmd_tx_adv, RF_PriorityNormal, NULL, 0); +// if (txHandle == RF_ALLOC_ERROR) +// { +// /* Failure sending the CMD_PROP_TX command */ +// PRINTF("transmit: PROP_TX_ERR ret=%d, CMDSTA=0x%08lx, status=0x%04x\n", +// ret, cmd_status, cmd_tx_adv->status); +// return RADIO_TX_ERR; +// } +// +// ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); +// +// // watchdog_periodic(); +// +// /* Idle away while the command is running */ +// RF_pendCmd(rfHandle, txHandle, RF_EventLastCmdDone); if(cmd_tx_adv->status == PROP_DONE_OK) { /* Sent OK */ diff --git a/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.c b/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.c index f66d75c5c..40bca3458 100644 --- a/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.c +++ b/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.c @@ -204,7 +204,7 @@ rfc_CMD_PROP_TX_ADV_t smartrf_settings_cmd_prop_tx_adv = .status = 0x0000, .pNextOp = 0, .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, + .startTrigger.triggerType = TRIG_NOW, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, @@ -219,7 +219,7 @@ rfc_CMD_PROP_TX_ADV_t smartrf_settings_cmd_prop_tx_adv = .startConf.bExtTxTrig = 0x0, .startConf.inputMode = 0x0, .startConf.source = 0x0, - .preTrigger.triggerType = TRIG_REL_START, + .preTrigger.triggerType = TRIG_NOW, .preTrigger.bEnaCmd = 0x0, .preTrigger.triggerNo = 0x0, .preTrigger.pastTrig = 0x1, diff --git a/arch/platform/simplelink/platform.c b/arch/platform/simplelink/platform.c index 5a0ddb8c7..db6affa07 100644 --- a/arch/platform/simplelink/platform.c +++ b/arch/platform/simplelink/platform.c @@ -60,7 +60,7 @@ #include "leds.h" //#include "gpio-interrupt.h" #include "ieee-addr.h" -//#include "uart.h" +#include "uart0-arch.h" #include "sys/clock.h" #include "sys/rtimer.h" #include "sys/node-id.h" @@ -130,6 +130,9 @@ platform_init_stage_one() Board_initGeneral(); GPIO_init(); + // Only enables interrupts + NoRTOS_start(); + // /* Enable flash cache and prefetch. */ // ti_lib_vims_mode_set(VIMS_BASE, VIMS_MODE_ENABLED); // ti_lib_vims_configure(VIMS_BASE, true, true); @@ -200,9 +203,6 @@ platform_init_stage_three() // // process_start(&sensors_process, NULL); fade(Board_GPIO_LED1); - - // Finally enable hardware interrupts - NoRTOS_start(); } /*---------------------------------------------------------------------------*/ void diff --git a/os/contiki-main.c b/os/contiki-main.c index b91817c3a..c756cf206 100644 --- a/os/contiki-main.c +++ b/os/contiki-main.c @@ -122,20 +122,20 @@ main(void) platform_init_stage_three(); -//#if BUILD_WITH_RPL_BORDER_ROUTER -// rpl_border_router_init(); -// LOG_DBG("With RPL Border Router\n"); -//#endif /* BUILD_WITH_RPL_BORDER_ROUTER */ -// -//#if BUILD_WITH_ORCHESTRA -// orchestra_init(); -// LOG_DBG("With Orchestra\n"); -//#endif /* BUILD_WITH_ORCHESTRA */ -// -//#if BUILD_WITH_SHELL -// serial_shell_init(); -// LOG_DBG("With Shell\n"); -//#endif /* BUILD_WITH_SHELL */ +#if BUILD_WITH_RPL_BORDER_ROUTER + rpl_border_router_init(); + LOG_DBG("With RPL Border Router\n"); +#endif /* BUILD_WITH_RPL_BORDER_ROUTER */ + +#if BUILD_WITH_ORCHESTRA + orchestra_init(); + LOG_DBG("With Orchestra\n"); +#endif /* BUILD_WITH_ORCHESTRA */ + +#if BUILD_WITH_SHELL + serial_shell_init(); + LOG_DBG("With Shell\n"); +#endif /* BUILD_WITH_SHELL */ #if BUILD_WITH_COAP coap_engine_init(); From 2d198a7858eebd9cd6e91e1ab102bdbd4c75d06f Mon Sep 17 00:00:00 2001 From: Richard Weickelt Date: Fri, 9 Feb 2018 18:23:38 +0100 Subject: [PATCH 236/485] Enable proper standby and idle. Just one line, thats it. --- arch/platform/simplelink/platform.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/platform/simplelink/platform.c b/arch/platform/simplelink/platform.c index db6affa07..3647a6134 100644 --- a/arch/platform/simplelink/platform.c +++ b/arch/platform/simplelink/platform.c @@ -210,6 +210,8 @@ platform_idle() { /* Drop to some low power mode */ // lpm_drop(); + + Power_idleFunc(); } /*---------------------------------------------------------------------------*/ /** From 7f813e8e0e5bcf1de0393205f91d9702de95ed7a Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Wed, 14 Feb 2018 17:56:35 +0100 Subject: [PATCH 237/485] Compiling and untested IEEE mode radio driver --- arch/cpu/simplelink/Makefile.simplelink | 8 +- .../dev/{proprietary-rf.h => rf-core.c} | 67 +- arch/cpu/simplelink/dev/rf-core.h | 32 +- arch/cpu/simplelink/dev/rf-ieee-mode.c | 1095 +++++++++++++++++ .../dev/{proprietary-rf.c => rf-prop-mode.c} | 327 ++--- arch/cpu/simplelink/dev/watchdog-arch.c | 5 + .../simplelink/rf-settings/rf-ieee-settings.c | 209 ++++ .../simplelink/rf-settings/rf-ieee-settings.h | 26 + ...etary-rf-settings.c => rf-prop-settings.c} | 22 +- ...etary-rf-settings.h => rf-prop-settings.h} | 23 +- arch/platform/simplelink/platform.c | 1 + 11 files changed, 1581 insertions(+), 234 deletions(-) rename arch/cpu/simplelink/dev/{proprietary-rf.h => rf-core.c} (64%) create mode 100644 arch/cpu/simplelink/dev/rf-ieee-mode.c rename arch/cpu/simplelink/dev/{proprietary-rf.c => rf-prop-mode.c} (75%) create mode 100644 arch/cpu/simplelink/rf-settings/rf-ieee-settings.c create mode 100644 arch/cpu/simplelink/rf-settings/rf-ieee-settings.h rename arch/cpu/simplelink/rf-settings/{proprietary-rf-settings.c => rf-prop-settings.c} (94%) rename arch/cpu/simplelink/rf-settings/{proprietary-rf-settings.h => rf-prop-settings.h} (56%) diff --git a/arch/cpu/simplelink/Makefile.simplelink b/arch/cpu/simplelink/Makefile.simplelink index 3df82643c..266565bdb 100644 --- a/arch/cpu/simplelink/Makefile.simplelink +++ b/arch/cpu/simplelink/Makefile.simplelink @@ -31,7 +31,9 @@ CFLAGS += -I$(SDK_KERNEL)/posix LDFLAGS += --entry resetISR LDFLAGS += -static LDFLAGS += --specs=nano.specs -LDFLAGS += -Wl,--defsym=_stack_origin=__stack +# NB! The symbol _stack, pointing to the stack start, is expected, +# but should already be defined in the linker script. +LDFLAGS += -Wl,--defsym=_stack_origin=__stack_end LDFLAGS += -Wl,--defsym=_heap=__heap_start__ LDFLAGS += -Wl,--defsym=_eheap=__heap_end__ @@ -63,7 +65,9 @@ CONTIKI_CPU_DIRS += dev rf-settings CONTIKI_CPU_SOURCEFILES += rtimer-arch.c clock-arch.c CONTIKI_CPU_SOURCEFILES += watchdog-arch.c putchar-arch.c CONTIKI_CPU_SOURCEFILES += uart0-arch.c -CONTIKI_CPU_SOURCEFILES += proprietary-rf.c proprietary-rf-settings.c +CONTIKI_CPU_SOURCEFILES += rf-core.c +CONTIKI_CPU_SOURCEFILES += rf-prop-mode.c rf-prop-settings.c +CONTIKI_CPU_SOURCEFILES += rf-ieee-mode.c rf-ieee-settings.c CONTIKI_CPU_SOURCEFILES += ieee-addr.c ### CPU-dependent debug source files diff --git a/arch/cpu/simplelink/dev/proprietary-rf.h b/arch/cpu/simplelink/dev/rf-core.c similarity index 64% rename from arch/cpu/simplelink/dev/proprietary-rf.h rename to arch/cpu/simplelink/dev/rf-core.c index de61e53ec..232cffb86 100644 --- a/arch/cpu/simplelink/dev/proprietary-rf.h +++ b/arch/cpu/simplelink/dev/rf-core.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,29 +32,58 @@ * \addtogroup rf-core * @{ * - * \defgroup rf-core-prop CC13xx Prop mode driver - * - * @{ - * * \file - * Header file for the CC13xx prop mode NETSTACK_RADIO driver + * Implementation of the CC13xx/CC26xx RF core driver */ /*---------------------------------------------------------------------------*/ -#ifndef PROP_MODE_H_ -#define PROP_MODE_H_ -/*---------------------------------------------------------------------------*/ #include "contiki.h" - +#include "dev/watchdog.h" +#include "sys/process.h" +#include "sys/clock.h" +#include "sys/ctimer.h" +#include "sys/energest.h" +#include "sys/cc.h" +#include "net/netstack.h" +#include "net/packetbuf.h" +/*---------------------------------------------------------------------------*/ +#include +/*---------------------------------------------------------------------------*/ #include +#include +#include +#include +#include /*---------------------------------------------------------------------------*/ -typedef struct prop_mode_tx_power_config { - radio_value_t dbm; - uint16_t tx_power; /* Value for the PROP_DIV_RADIO_SETUP.txPower field */ -} prop_mode_tx_power_config_t; +#define DEBUG 0 +#if DEBUG +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif /*---------------------------------------------------------------------------*/ -#endif /* PROP_MODE_H_ */ +PROCESS(RF_coreProcess, "SimpleLink RF driver"); /*---------------------------------------------------------------------------*/ -/** - * @} - * @} - */ +PROCESS_THREAD(RF_coreProcess, ev, data) +{ + int len; + + PROCESS_BEGIN(); + + while(1) { + PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL); + do { + watchdog_periodic(); + packetbuf_clear(); + len = NETSTACK_RADIO.read(packetbuf_dataptr(), PACKETBUF_SIZE); + + if(len > 0) { + packetbuf_set_datalen(len); + + NETSTACK_MAC.input(); + } + } while(len > 0); + } + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/cpu/simplelink/dev/rf-core.h b/arch/cpu/simplelink/dev/rf-core.h index e28937384..02e882f66 100644 --- a/arch/cpu/simplelink/dev/rf-core.h +++ b/arch/cpu/simplelink/dev/rf-core.h @@ -2,8 +2,36 @@ #define CONTIKI_NG_ARCH_CPU_SIMPLELINK_DEV_RF_CORE_H_ /*---------------------------------------------------------------------------*/ -#define RF_CORE_CMD_ERROR 0 -#define RF_CORE_CMD_OK 1 +/* Contiki API */ +#include +#include +/*---------------------------------------------------------------------------*/ +#include +/*---------------------------------------------------------------------------*/ +/* Standard library */ +#include +/*---------------------------------------------------------------------------*/ +#ifdef RF_CORE_CONF_CHANNEL +# define RF_CORE_CHANNEL RF_CORE_CONF_CHANNEL +#else +# define RF_CORE_CHANNEL 25 +#endif +/*---------------------------------------------------------------------------*/ +typedef enum { + CMD_ERROR = 0, + CMD_OK = 1, +} CmdResult; +/*---------------------------------------------------------------------------*/ +typedef struct { + radio_value_t dbm; + uint16_t power; /* Value for the PROP_DIV_RADIO_SETUP.txPower field */ +} RF_TxPower; + +#define TX_POWER_UNKNOWN 0xFFFF +/*---------------------------------------------------------------------------*/ +#define RSSI_UNKNOWN -128 +/*---------------------------------------------------------------------------*/ +PROCESS_NAME(RF_coreProcess); /*---------------------------------------------------------------------------*/ #endif /* CONTIKI_NG_ARCH_CPU_SIMPLELINK_DEV_RF_CORE_H_ */ diff --git a/arch/cpu/simplelink/dev/rf-ieee-mode.c b/arch/cpu/simplelink/dev/rf-ieee-mode.c new file mode 100644 index 000000000..f3686505c --- /dev/null +++ b/arch/cpu/simplelink/dev/rf-ieee-mode.c @@ -0,0 +1,1095 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup rf-core + * @{ + * + * \defgroup rf-core-ieee CC13xx/CC26xx IEEE mode driver + * + * @{ + * + * \file + * Implementation of the CC13xx/CC26xx IEEE mode NETSTACK_RADIO driver + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "net/packetbuf.h" +#include "net/linkaddr.h" +#include "net/netstack.h" +#include "sys/energest.h" +#include "sys/clock.h" +#include "sys/rtimer.h" +#include "sys/ctimer.h" +#include "sys/cc.h" +/*---------------------------------------------------------------------------*/ +/* RF driver and RF Core API */ +#include +#include +#include +#include +#include +#include +#include +/*---------------------------------------------------------------------------*/ +/* Simplelink Platform RF dev */ +#include "rf-core.h" +#include "dot-15-4g.h" +/*---------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +/*---------------------------------------------------------------------------*/ +#ifdef NDEBUG +# define PRINTF(...) +#else +# define PRINTF(...) printf(__VA_ARGS__) +#endif +/*---------------------------------------------------------------------------*/ +/* Configuration parameters */ + +/* Configuration to enable/disable auto ACKs in IEEE mode */ +#ifdef IEEE_MODE_CONF_AUTOACK +# define IEEE_MODE_AUTOACK IEEE_MODE_CONF_AUTOACK +# undef IEEE_MODE_CONF_AUTOACK +#else +# define IEEE_MODE_AUTOACK 1 +#endif /* IEEE_MODE_CONF_AUTOACK */ + +/* Configuration to enable/disable frame filtering in IEEE mode */ +#ifdef IEEE_MODE_CONF_PROMISCOUS +# define IEEE_MODE_PROMISCOUS IEEE_MODE_CONF_PROMISCOUS +# undef IEEE_MODE_CONF_PROMISCOUS +#else +# define IEEE_MODE_PROMISCOUS 0 +#endif /* IEEE_MODE_CONF_PROMISCOUS */ + +/* Configuration to set the RSSI threshold */ +#ifdef IEEE_MODE_CONF_RSSI_THRESHOLD +# define IEEE_MODE_RSSI_THRESHOLD IEEE_MODE_CONF_RSSI_THRESHOLD +# undef IEEE_MODE_CONF_RSSI_THRESHOLD +#else +# define IEEE_MODE_RSSI_THRESHOLD 0xA6 +#endif /* IEEE_MODE_CONF_RSSI_THRESHOLD */ + +/* Configuration for default IEEE channel */ +#ifdef IEEE_MODE_CONF_CHANNEL +# define IEEE_MODE_CHANNEL IEEE_MODE_CONF_CHANNEL +# undef IEEE_MODE_CONF_CHANNEL +#else +# define IEEE_MODE_CHANNEL RF_CORE_CHANNEL +#endif + +/* Configuration for TX power table */ +#ifdef TX_POWER_CONF_DRIVER +# define TX_POWER_DRIVER TX_POWER_CONF_DRIVER +# undef TX_POWER_CONF_DRIVER +#else +# define TX_POWER_DRIVER RF_ieeeTxPower +#endif + +#ifdef TX_POWER_CONF_COUNT +# define TX_POWER_COUNT TX_POWER_CONF_COUNT +# undef TX_POWER_CONF_COUNT +#else +# define TX_POWER_COUNT RF_ieeeTxPowerLen +#endif +/*---------------------------------------------------------------------------*/ +/* TX power convenience macros */ +static RF_TxPower * const g_pTxPower = TX_POWER_DRIVER; + +#define TX_POWER_MAX (g_pTxPower[0]) +#define TX_POWER_MIN (g_pTxPower[(TX_POWER_COUNT) - 1]) + +#define TX_POWER_IN_RANGE(dbm) (((dbm) >= TX_POWER_MIN) && ((dbm) <= TX_POWER_MAX)) +/*---------------------------------------------------------------------------*/ +/* IEEE channel-to-frequency conversion constants */ +/* Channel frequency base: 2.405 GHz */ +/* Channel frequency spacing: 5 MHz */ +/* Channel range: 11 - 26 */ +#define IEEE_MODE_FREQ_BASE 2405000 +#define IEEE_MODE_FREQ_SPACING 5000 +#define IEEE_MODE_CHAN_MIN 11 +#define IEEE_MODE_CHAN_MAX 26 + +#define IEEE_MODE_CHAN_IN_RANGE(ch) (((ch) >= IEEE_MODE_CHAN_MIN) && ((ch) <= IEEE_MODE_CHAN_MAX)) + +/* Sanity check of default IEEE channel */ +#if !IEEE_MODE_CHAN_IN_RANGE(IEEE_MODE_CHANNEL) +# error "Default IEEE channel IEEE_MODE_CHANNEL is outside allowed channel range" +#endif +/*---------------------------------------------------------------------------*/ +/* Timeout constants */ + +/* How long to wait for an ongoing ACK TX to finish before starting frame TX */ +#define TIMEOUT_TX_WAIT (RTIMER_SECOND >> 11) + +/* How long to wait for the RF to enter RX in RF_cmdIeeeRx */ +#define TIMEOUT_ENTER_RX_WAIT (RTIMER_SECOND >> 10) + +/* How long to wait for the RF to react on CMD_ABORT: around 1 msec */ +#define TIMEOUT_RF_TURN_OFF_WAIT (RTIMER_SECOND >> 10) + +/* How long to wait for the RF to finish TX of a packet or an ACK */ +#define TIMEOUT_TX_FINISH_WAIT (RTIMER_SECOND >> 7) + +/* How long to wait for the rx read entry to become ready */ +#define TIMEOUT_DATA_ENTRY_BUSY (RTIMER_SECOND / 250) +/*---------------------------------------------------------------------------*/ +/* TI-RTOS RF driver object */ +static RF_Object g_rfObj; +static RF_Handle g_rfHandle; + +/* RF Core command pointers */ +static volatile rfc_CMD_RADIO_SETUP_t *g_vpCmdRadioSetup = &RF_cmdRadioSetup; +static volatile rfc_CMD_FS_t *g_vpCmdFs = &RF_cmdFs; +static volatile rfc_CMD_IEEE_TX_t *g_vpCmdTx = &RF_cmdIeeeTx; +static volatile rfc_CMD_IEEE_RX_t *g_vpCmdRx = &RF_cmdIeeeRx; + +/* RF command handles */ +static RF_CmdHandle g_cmdTxHandle; +static RF_CmdHandle g_cmdRxHandle; + +/* Global RF Core commands */ +static rfc_CMD_IEEE_MOD_FILT_t g_cmdModFilt; + +/* RF stats data structure */ +static rfc_ieeeRxOutput_t g_rxStats; +/*---------------------------------------------------------------------------*/ +/* The outgoing frame buffer */ +#define TX_BUF_PAYLOAD_LEN 180 +#define TX_BUF_HDR_LEN 2 + +static uint8_t g_txBuf[TX_BUF_HDR_LEN + TX_BUF_PAYLOAD_LEN] CC_ALIGN(4); +/*---------------------------------------------------------------------------*/ +/* RX Data Queue */ +static dataQueue_t g_rxDataQueue; +/* Receive entry pointer to keep track of read items */ +volatile static uint8_t *g_pRxReadEntry; + +/* Constants for receive buffers */ +#define DATA_ENTRY_LENSZ_NONE 0 +#define DATA_ENTRY_LENSZ_BYTE 1 +#define DATA_ENTRY_LENSZ_WORD 2 /* 2 bytes */ + +#define RX_BUF_ENTRIES 4 +#define RX_BUF_SIZE 144 + +/* Receive buffer entries with room for 1 IEEE 802.15.4 frame in each */ +typedef union { + rfc_dataEntry_t dataEntry; + uint8_t buf[RX_BUF_SIZE] CC_ALIGN(4); +} RxBuf; +static RxBuf g_rxBufs[RX_BUF_ENTRIES]; +/*---------------------------------------------------------------------------*/ +/* RAT overflow upkeep */ +static struct ctimer g_ratOverflowTimer; +static rtimer_clock_t g_lastRatOverflow; +static volatile uint32_t g_ratOverflowCount; + +#define RAT_RANGE (~(uint32_t)0) +#define RAT_OVERFLOW_PERIOD_SECONDS (RAT_RANGE / (uint32_t)RADIO_TIMER_SECOND) +/* XXX: don't know what exactly is this, looks like the time to TX 3 octets */ +#define RAT_TIMESTAMP_OFFSET -(USEC_TO_RADIO(32 * 3) - 1) /* -95.75 usec */ +/*---------------------------------------------------------------------------*/ +#define STATUS_CORRELATION 0x3f // bits 0-5 +#define STATUS_REJECT_FRAME 0x40 // bit 6 +#define STATUS_CRC_FAIL 0x80 // bit 7 +/*---------------------------------------------------------------------------*/ +#define CHANNEL_CLEAR_ERROR -1 +/*---------------------------------------------------------------------------*/ +/* Global state */ + +/* Current RX channel */ +static volatile uint8_t g_currChannel; + +/* Current TX power */ +static volatile RF_TxPower *g_pCurrTxPower; + +/* Are we currently in poll mode? */ +static volatile bool g_bPollMode = false; + +/* Enable/disable CCA before sending */ +static volatile bool g_bSendOnCca = false; + +/* Last RX operation stats */ +static volatile int8_t g_lastRssi; +static volatile uint8_t g_lastCorrLqi; +static volatile uint32_t g_lastTimestamp; +/*---------------------------------------------------------------------------*/ +typedef enum { + POWER_STATE_ON, + POWER_STATE_OFF, + POWER_STATE_RESTART, +} PowerState; +/*---------------------------------------------------------------------------*/ +/* Forward declarations of static functions */ +static int on(void); +static int off(void); +static int set_rx(const PowerState); +static int channel_clear(void); +static void check_rat_overflow(void); +static bool rf_is_on(void); +static uint32_t rat_to_timestamp(const uint32_t); +/*---------------------------------------------------------------------------*/ +static void +synth_error_cb(RF_Handle h, RF_CmdHandle ch, RF_EventMask e) +{ + if ((ch == RF_ERROR_CMDFS_SYNTH_PROG) && + (g_vpCmdFs->status == ERROR_SYNTH_PROG)) { + // See SWRA521: Synth failed to calibrate, CMD_FS must be repeated + RF_postCmd(g_rfHandle, (RF_Op*)g_vpCmdFs, RF_PriorityNormal, synth_error_cb, 0); + } +} +/*---------------------------------------------------------------------------*/ +static void +rat_overflow_cb(void *arg) +{ + check_rat_overflow(); + // Check next time after half of the RAT interval + ctimer_set(&g_ratOverflowTimer, RAT_OVERFLOW_PERIOD_SECONDS * CLOCK_SECOND / 2, + rat_overflow_cb, NULL); +} +/*---------------------------------------------------------------------------*/ +static void +init_data_queue(void) +{ + // Initialize RF core data queue, circular buffer + g_rxDataQueue.pCurrEntry = g_rxBufs[0].buf; + g_rxDataQueue.pLastEntry = NULL; + // Set current read pointer to first element + g_pRxReadEntry = g_rxDataQueue.pCurrEntry; +} +/*---------------------------------------------------------------------------*/ +static void +init_rf_params(void) +{ + g_vpCmdRx->pRxQ = &g_rxDataQueue; + g_vpCmdRx->pOutput = &g_rxStats; + +#if IEEE_MODE_PROMISCOUS + g_vpCmdRx->frameFiltOpt.frameFiltEn = 0; +#else + g_vpCmdRx->frameFiltOpt.frameFiltEn = 1; +#endif + +#if IEEE_MODE_AUTOACK + g_vpCmdRx->frameFiltOpt.autoAckEn = 1; +#else + g_vpCmdRx->frameFiltOpt.autoAckEn = 0; +#endif + + g_vpCmdRx->ccaRssiThr = IEEE_MODE_RSSI_THRESHOLD; + + // Initialize address filter command + g_cmdModFilt.commandNo = CMD_IEEE_MOD_FILT; + memcpy(&g_cmdModFilt.newFrameFiltOpt, &RF_cmdIeeeRx.frameFiltOpt, sizeof(RF_cmdIeeeRx.frameFiltOpt)); + memcpy(&g_cmdModFilt.newFrameTypes, &RF_cmdIeeeRx.frameTypes, sizeof(RF_cmdIeeeRx.frameTypes)); +} +/*---------------------------------------------------------------------------*/ +static void +init_rx_buffers(void) +{ +#define getEntry(n) (&(g_rxBufs[(n)].dataEntry)) + + rfc_dataEntry_t *entry = NULL; + const uint16_t length = sizeof(g_rxBufs[0].buf) - 8; + + size_t i; + for (i = 0; i < (size_t)(RX_BUF_ENTRIES - 1); ++i) { + entry = getEntry(i); + entry->pNextEntry = (uint8_t*)getEntry(i + 1); + entry->config.lenSz = DATA_ENTRY_LENSZ_BYTE; + entry->length = length; + } + + entry = getEntry(RX_BUF_ENTRIES - 1); + entry->pNextEntry = (uint8_t*)getEntry(0); + entry->config.lenSz = DATA_ENTRY_LENSZ_BYTE; + entry->length = length; + +#undef getEntry +} +/*---------------------------------------------------------------------------*/ +static void +set_channel(uint8_t channel) +{ + if (!IEEE_MODE_CHAN_IN_RANGE(channel)) { + PRINTF("set_channel: illegal channel %d, defaults to %d\n", + channel, IEEE_MODE_CHANNEL); + channel = IEEE_MODE_CHANNEL; + } + if (channel == g_currChannel) { + // We are already calibrated to this channel + return; + } + g_currChannel = channel; + // freq = freq_base + freq_spacing * (channel - channel_min) + const uint32_t newFreq = (uint32_t)IEEE_MODE_FREQ_BASE + + (uint32_t)IEEE_MODE_FREQ_SPACING * ((uint32_t)channel - (uint32_t)IEEE_MODE_CHAN_MIN); + const uint16_t freq = (uint16_t)(newFreq / 1000); + const uint16_t frac = (uint16_t)((newFreq - (freq * 1000)) * 65536 / 1000); + + PRINTF("set_channel: %d = 0x%04X.0x%04X (%lu)\n", + channel, freq, frac, newFreq); + + g_vpCmdFs->frequency = freq; + g_vpCmdFs->fractFreq = frac; + + // Start FS command asynchronously. We don't care when it is finished + RF_postCmd(g_rfHandle, (RF_Op*)g_vpCmdFs, RF_PriorityNormal, synth_error_cb, 0); + if (g_vpCmdRx->status == ACTIVE) { + set_rx(POWER_STATE_RESTART); + } +} +/*---------------------------------------------------------------------------*/ +static int +set_tx_power(const radio_value_t dbm) +{ + g_pCurrTxPower = NULL; + if (dbm > TX_POWER_MAX.dbm) { + g_pCurrTxPower = &TX_POWER_MAX; + } else { + size_t i; + for (i = 0; g_pTxPower[i + 1].power != TX_POWER_UNKNOWN; ++i) { + if (dbm > g_pTxPower[i + 1].dbm) { + break; + } + } + g_pCurrTxPower = &g_pTxPower[i + 1]; + } + + if (!g_pCurrTxPower) { + return CMD_ERROR; + } + + rfc_CMD_SET_TX_POWER_t cmdSetTxPower = { + .commandNo = CMD_SET_TX_POWER, + .txPower = g_pCurrTxPower->power, + }; + + const RF_Stat stat = RF_runImmediateCmd(g_rfHandle, (uint32_t*)&cmdSetTxPower); + if (stat != RF_StatCmdDoneSuccess) { + PRINTF("set_tx_power: stat=0x%02X\n", stat); + return CMD_ERROR; + } + return CMD_OK; +} +/*---------------------------------------------------------------------------*/ +static radio_value_t +get_tx_power(void) +{ + return (g_pCurrTxPower) + ? g_pCurrTxPower->power + : (radio_value_t)TX_POWER_UNKNOWN; +} +/*---------------------------------------------------------------------------*/ +static void +set_send_on_cca(bool enable) +{ + g_bSendOnCca = enable; +} +/*---------------------------------------------------------------------------*/ +static void +check_rat_overflow(void) +{ + const bool was_off = rf_is_on(); + if (was_off) { + RF_runDirectCmd(g_rfHandle, CMD_NOP); + } + const uint32_t currentValue = RF_getCurrentTime(); + + static uint32_t lastValue; + static bool bFirstTime = true; + if (bFirstTime) { + // First time checking overflow will only store the current value + bFirstTime = false; + } else { + // Overflow happens in the last quarter of the RAT range + if (currentValue + RAT_RANGE / 4 < lastValue) { + // Overflow detected + g_lastRatOverflow = RTIMER_NOW(); + g_ratOverflowCount += 1; + } + } + + lastValue = currentValue; + + if (was_off) { + off(); + } +} +/*---------------------------------------------------------------------------*/ +static uint32_t +rat_to_timestamp(const uint32_t ratTimestamp) +{ + check_rat_overflow(); + + uint64_t adjustedOverflowCount = g_ratOverflowCount; + + // If the timestamp is in the 4th quarter and the last oveflow was recently, + // assume that the timestamp refers to the time before the overflow + if(ratTimestamp > (uint32_t)(RAT_RANGE * 3 / 4)) { + if(RTIMER_CLOCK_LT(RTIMER_NOW(), + g_lastRatOverflow + RAT_OVERFLOW_PERIOD_SECONDS * RTIMER_SECOND / 4)) { + adjustedOverflowCount -= 1; + } + } + + // Add the overflowed time to the timestamp + const uint64_t ratTimestamp64 = (uint64_t)ratTimestamp + (uint64_t)RAT_RANGE * adjustedOverflowCount; + + // Correct timestamp so that it refers to the end of the SFD and convert to RTIMER + return RADIO_TO_RTIMER(ratTimestamp64 + RAT_TIMESTAMP_OFFSET); +} +/*---------------------------------------------------------------------------*/ +static int +init(void) +{ + RF_Params params; + RF_Params_init(¶ms); + // Disable automatic power-down just to not interfere with stack timing + params.nInactivityTimeout = 0; + + init_rf_params(); + init_data_queue(); + + g_rfHandle = RF_open(&g_rfObj, &RF_ieeeMode, (RF_RadioSetup*)g_vpCmdRadioSetup, ¶ms); + assert(g_rfHandle != NULL); + + set_channel(IEEE_MODE_CHANNEL); + + ENERGEST_ON(ENERGEST_TYPE_LISTEN); + + // Start RAT overflow upkeep + check_rat_overflow(); + ctimer_set(&g_ratOverflowTimer, RAT_OVERFLOW_PERIOD_SECONDS * CLOCK_SECOND / 2, + rat_overflow_cb, NULL); + + process_start(&RF_coreProcess, NULL); + + return CMD_OK; +} +/*---------------------------------------------------------------------------*/ +static int +prepare(const void *payload, unsigned short payload_len) +{ + const size_t len = MIN((size_t)payload_len, + (size_t)TX_BUF_PAYLOAD_LEN); + memcpy(&g_txBuf[TX_BUF_HDR_LEN], payload, len); + return 0; +} +/*---------------------------------------------------------------------------*/ +static bool +rf_is_on(void) +{ + RF_InfoVal infoVal; + memset(&infoVal, 0x0, sizeof(RF_InfoVal)); + const RF_Stat stat = RF_getInfo(g_rfHandle, RF_GET_RADIO_STATE, &infoVal); + return (stat == RF_StatSuccess) + ? infoVal.bRadioState // 0: Radio OFF, 1: Radio ON + : false; +} +/*---------------------------------------------------------------------------*/ +static int +set_rx(const PowerState state) +{ + if (state == POWER_STATE_OFF || state == POWER_STATE_RESTART) { + const uint8_t stopGracefully = 1; + const RF_Stat stat = RF_cancelCmd(g_rfHandle, g_cmdRxHandle, + stopGracefully); + if (stat != RF_StatSuccess) + { + PRINTF("set_rx(off): unable to cancel RX\n"); + return CMD_ERROR; + } + + } + if (state == POWER_STATE_ON || state == POWER_STATE_RESTART) { + if (g_vpCmdRx->status == ACTIVE) { + PRINTF("set_rx(on): already in RX\n"); + return CMD_OK; + } + + RF_ScheduleCmdParams schedParams = { + .endTime = 0, + .priority = RF_PriorityNormal, + .bIeeeBgCmd = true, + }; + + g_vpCmdRx->status = IDLE; + g_cmdRxHandle = RF_scheduleCmd(g_rfHandle, (RF_Op*)g_vpCmdRx, &schedParams, NULL, 0); + if ((g_cmdTxHandle == RF_ALLOC_ERROR) || (g_cmdTxHandle == RF_SCHEDULE_CMD_ERROR)) { + PRINTF("transmit: unable to allocate RX command\n"); + return CMD_ERROR; + } + } + + return CMD_OK; +} +/*---------------------------------------------------------------------------*/ +static int +transmit_aux(unsigned short transmit_len) +{ + // Configure TX command + g_vpCmdTx->payloadLen = (uint8_t)transmit_len; + g_vpCmdTx->pPayload = &g_txBuf[TX_BUF_HDR_LEN]; + g_vpCmdTx->startTime = 0; + g_vpCmdTx->startTrigger.triggerType = TRIG_NOW; + + RF_ScheduleCmdParams schedParams = { + .endTime = 0, + .priority = RF_PriorityNormal, + .bIeeeBgCmd = false, + }; + + // As IEEE_TX is a FG command, the TX operation will be executed + // either way if RX is running or not + g_vpCmdTx->status = IDLE; + g_cmdTxHandle = RF_scheduleCmd(g_rfHandle, (RF_Op*)g_vpCmdTx, &schedParams, NULL, 0); + if ((g_cmdTxHandle == RF_ALLOC_ERROR) || (g_cmdTxHandle == RF_SCHEDULE_CMD_ERROR)) { + // Failure sending the CMD_IEEE_TX command + PRINTF("transmit: failed to allocate TX command cmdHandle=%d, status=%04x\n", + g_cmdTxHandle, g_vpCmdTx->status); + return RADIO_TX_ERR; + } + + ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT); + + // Wait until TX operation finishes + RF_EventMask events = RF_pendCmd(g_rfHandle, g_cmdTxHandle, 0); + if ((events & (RF_EventFGCmdDone | RF_EventLastFGCmdDone)) == 0) { + PRINTF("transmit: TX command error events=0x%08llx, status=0x%04x\n", + events, g_vpCmdTx->status); + return RADIO_TX_ERR; + } + + return RADIO_TX_OK; +} +/*---------------------------------------------------------------------------*/ +static int +transmit(unsigned short transmit_len) +{ + const bool was_rx = (g_vpCmdRx->status == ACTIVE); + + if (g_bSendOnCca && channel_clear() != 1) { + PRINTF("transmit: channel wasn't clear\n"); + return RADIO_TX_COLLISION; + } + + const int rv = transmit_aux(transmit_len); + ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN); + + if (!was_rx) { + off(); + } + return rv; +} +/*---------------------------------------------------------------------------*/ +static int +send(const void *payload, unsigned short payload_len) +{ + prepare(payload, payload_len); + return transmit(payload_len); +} +/*---------------------------------------------------------------------------*/ +static void +release_data_entry(void) +{ + rfc_dataEntryGeneral_t *pEntry = (rfc_dataEntryGeneral_t *)g_pRxReadEntry; + + // Clear the length byte and set status to 0: "Pending" + pEntry->length = 0; + pEntry->status = DATA_ENTRY_PENDING; + // Set next entry + g_pRxReadEntry = pEntry->pNextEntry; +} +/*---------------------------------------------------------------------------*/ +static int +read_frame(void *buf, unsigned short buf_len) +{ + volatile rfc_dataEntryGeneral_t *pEntry = (rfc_dataEntryGeneral_t *)g_pRxReadEntry; + + const rtimer_clock_t t0 = RTIMER_NOW(); + // Only wait if the Radio timer is accessing the entry + while ((pEntry->status == DATA_ENTRY_BUSY) && + RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + TIMEOUT_DATA_ENTRY_BUSY)); + + if (pEntry->status != DATA_ENTRY_FINISHED) { + // No available data + return 0; + } + + // FIXME: something is wrong here about length constraints + if (pEntry->length < 4) { + PRINTF("read_frame: frame too short \n"); + release_data_entry(); + return 0; + } + + const int frame_len = pEntry->length - 8; + + if (frame_len > buf_len) { + PRINTF("read_frame: frame larger than buffer\n"); + release_data_entry(); + return 0; + } + + const uint8_t *pData = (uint8_t *)&pEntry->data; + + memcpy(buf, pData, frame_len); + + g_lastRssi = (int8_t)(pData[frame_len + 2]); + g_lastCorrLqi = (uint8_t)(pData[frame_len + 3]) & STATUS_CORRELATION; + + uint32_t ratTimestamp; + memcpy(&ratTimestamp, pData + frame_len + 4, sizeof(ratTimestamp)); + g_lastTimestamp = rat_to_timestamp(ratTimestamp); + + if (!g_bPollMode) { + // Not in poll mode: packetbuf should not be accessed in interrupt context. + // In poll mode, the last packet RSSI and link quality can be obtained through + // RADIO_PARAM_LAST_RSSI and RADIO_PARAM_LAST_LINK_QUALITY + packetbuf_set_attr(PACKETBUF_ATTR_RSSI, g_lastRssi); + packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, g_lastCorrLqi); + } + + release_data_entry(); + + return frame_len; +} +/*---------------------------------------------------------------------------*/ +static int +channel_clear_aux(void) +{ + rfc_CMD_IEEE_CCA_REQ_t RF_cmdIeeeCaaReq; + memset(&RF_cmdIeeeCaaReq, 0x0, sizeof(rfc_CMD_IEEE_CCA_REQ_t)); + RF_cmdIeeeCaaReq.commandNo = CMD_IEEE_CCA_REQ; + + const RF_Stat stat = RF_runImmediateCmd(g_rfHandle, (uint32_t*)&RF_cmdIeeeCaaReq); + if (stat != RF_StatCmdDoneSuccess) { + PRINTF("channel_clear: CCA request failed stat=0x%02X\n", stat); + return CMD_ERROR; + } + + // Channel is clear if CCA state is idle (0) or invalid (2), i.e. not busy (1) + return (RF_cmdIeeeCaaReq.ccaInfo.ccaState != 1); +} +/*---------------------------------------------------------------------------*/ +static int +channel_clear(void) +{ + const bool was_rx = (g_vpCmdRx->status == ACTIVE); + if (!was_rx && set_rx(POWER_STATE_ON) != CMD_OK) { + PRINTF("channel_clear: unable to start RX\n"); + return CHANNEL_CLEAR_ERROR; + } + + const int rv = channel_clear_aux(); + + if (!was_rx) { + set_rx(POWER_STATE_OFF); + } + return rv; +} +/*---------------------------------------------------------------------------*/ +static int +receiving_packet(void) +{ + // If we are not in RX, we are not receiving + if (g_vpCmdRx->status != ACTIVE) { + PRINTF("receiving_packet: not in RX\n"); + return 0; + } + + rfc_CMD_IEEE_CCA_REQ_t RF_cmdIeeeCaaReq; + memset(&RF_cmdIeeeCaaReq, 0x0, sizeof(rfc_CMD_IEEE_CCA_REQ_t)); + RF_cmdIeeeCaaReq.commandNo = CMD_IEEE_CCA_REQ; + + const RF_Stat stat = RF_runImmediateCmd(g_rfHandle, (uint32_t*)&RF_cmdIeeeCaaReq); + if (stat != RF_StatCmdDoneSuccess) { + PRINTF("receiving_packet: CCA request failed stat=0x%02X\n", stat); + return 0; + } + + // If the radio is transmitting an ACK or is suspended for running a TX operation, + // ccaEnergy, ccaCorr and ccaSync are all busy (1) + if ((RF_cmdIeeeCaaReq.ccaInfo.ccaEnergy == 1) && + (RF_cmdIeeeCaaReq.ccaInfo.ccaCorr == 1) && + (RF_cmdIeeeCaaReq.ccaInfo.ccaSync == 1)) { + PRINTF("receiving_packet: we were TXing\n"); + return 0; + } + + // We are on and not in TX, then we are in RX if a CCA sync has been seen, + // i.e. ccaSync is busy (1) + return (RF_cmdIeeeCaaReq.ccaInfo.ccaSync == 1); +} +/*---------------------------------------------------------------------------*/ +static int +pending_packet(void) +{ + const rfc_dataEntry_t *const pStartEntry = (rfc_dataEntry_t *)g_rxDataQueue.pCurrEntry; + volatile const rfc_dataEntry_t *pCurrEntry = pStartEntry; + + // Check all RX buffers and check their statuses, stopping when looping the circular buffer + int bIsPending = 0; + do { + const uint8_t status = pCurrEntry->status; + if ((status == DATA_ENTRY_FINISHED) || + (status == DATA_ENTRY_BUSY)) { + bIsPending = 1; + if (!g_bPollMode) { + process_poll(&RF_coreProcess); + } + } + + pCurrEntry = (rfc_dataEntry_t *)pCurrEntry->pNextEntry; + } while (pCurrEntry != pStartEntry); + + // If we didn't find an entry at status finished or busy, no frames are pending + return bIsPending; +} +/*---------------------------------------------------------------------------*/ +static int +on(void) +{ + init_rx_buffers(); + + const int rv = set_rx(POWER_STATE_ON); + + ENERGEST_ON(ENERGEST_TYPE_LISTEN); + + return rv; +} +/*---------------------------------------------------------------------------*/ +static int +off(void) +{ + set_rx(POWER_STATE_OFF); + RF_yield(g_rfHandle); + + ENERGEST_OFF(ENERGEST_TYPE_LISTEN); + + // Reset RX buffers if there was an ongoing RX + size_t i; + for (i = 0; i < RX_BUF_ENTRIES; ++i) { + rfc_dataEntry_t *entry = &(g_rxBufs[i].dataEntry); + if (entry->status == DATA_ENTRY_BUSY) { + entry->status = DATA_ENTRY_PENDING; + } + } + + return CMD_OK; +} +/*---------------------------------------------------------------------------*/ +static radio_result_t +get_value(radio_param_t param, radio_value_t *value) +{ + if (!value) { + return RADIO_RESULT_INVALID_VALUE; + } + + switch (param) { + case RADIO_PARAM_POWER_MODE: + *value = rf_is_on() ? RADIO_POWER_MODE_ON : RADIO_POWER_MODE_OFF; + return RADIO_RESULT_OK; + + case RADIO_PARAM_CHANNEL: + *value = (radio_value_t)g_currChannel; + return RADIO_RESULT_OK; + + case RADIO_PARAM_PAN_ID: + *value = (radio_value_t)g_vpCmdRx->localPanID; + return RADIO_RESULT_OK; + + case RADIO_PARAM_16BIT_ADDR: + *value = (radio_value_t)g_vpCmdRx->localShortAddr; + return RADIO_RESULT_OK; + + case RADIO_PARAM_RX_MODE: + *value = 0; + if (g_vpCmdRx->frameFiltOpt.frameFiltEn) { + *value |= (radio_value_t)RADIO_RX_MODE_ADDRESS_FILTER; + } + if (g_vpCmdRx->frameFiltOpt.autoAckEn) { + *value |= (radio_value_t)RADIO_RX_MODE_AUTOACK; + } + if (g_bPollMode) { + *value |= (radio_value_t)RADIO_RX_MODE_POLL_MODE; + } + return RADIO_RESULT_OK; + + case RADIO_PARAM_TX_MODE: + *value = 0; + return RADIO_RESULT_OK; + + case RADIO_PARAM_TXPOWER: + *value = get_tx_power(); + return (*value == TX_POWER_UNKNOWN) + ? RADIO_RESULT_ERROR + : RADIO_RESULT_OK; + + case RADIO_PARAM_CCA_THRESHOLD: + *value = g_vpCmdRx->ccaRssiThr; + return RADIO_RESULT_OK; + + case RADIO_PARAM_RSSI: + *value = RF_getRssi(g_rfHandle); + return (*value == RF_GET_RSSI_ERROR_VAL) + ? RADIO_RESULT_ERROR + : RADIO_RESULT_OK; + + case RADIO_CONST_CHANNEL_MIN: + *value = (radio_value_t)IEEE_MODE_CHAN_MIN; + return RADIO_RESULT_OK; + + case RADIO_CONST_CHANNEL_MAX: + *value = (radio_value_t)IEEE_MODE_CHAN_MAX; + return RADIO_RESULT_OK; + + case RADIO_CONST_TXPOWER_MIN: + *value = (radio_value_t)(TX_POWER_MIN.dbm); + return RADIO_RESULT_OK; + + case RADIO_CONST_TXPOWER_MAX: + *value = (radio_value_t)(TX_POWER_MAX.dbm); + return RADIO_RESULT_OK; + + case RADIO_PARAM_LAST_RSSI: + *value = (radio_value_t)g_lastRssi; + return RADIO_RESULT_OK; + + case RADIO_PARAM_LAST_LINK_QUALITY: + *value = (radio_value_t)g_lastCorrLqi; + return RADIO_RESULT_OK; + + default: + return RADIO_RESULT_NOT_SUPPORTED; + } +} +/*---------------------------------------------------------------------------*/ +static radio_result_t +set_value(radio_param_t param, radio_value_t value) +{ + switch(param) { + case RADIO_PARAM_POWER_MODE: + switch (value) { + case RADIO_POWER_MODE_ON: + if (on() != CMD_OK) { + PRINTF("set_value: on() failed (1)\n"); + return RADIO_RESULT_ERROR; + } + return RADIO_RESULT_OK; + + case RADIO_POWER_MODE_OFF: + off(); + return RADIO_RESULT_OK; + + default: + return RADIO_RESULT_INVALID_VALUE; + } + + case RADIO_PARAM_CHANNEL: + if (!IEEE_MODE_CHAN_IN_RANGE(value)) { + return RADIO_RESULT_INVALID_VALUE; + } + set_channel((uint8_t)value); + return RADIO_RESULT_OK; + + case RADIO_PARAM_PAN_ID: + g_vpCmdRx->localPanID = (uint16_t)value; + if (rf_is_on() && set_rx(POWER_STATE_RESTART) != CMD_OK) { + PRINTF("failed to restart RX"); + return RADIO_RESULT_ERROR; + } + return RADIO_RESULT_OK; + + case RADIO_PARAM_16BIT_ADDR: + g_vpCmdRx->localShortAddr = (uint16_t)value; + if (rf_is_on() && set_rx(POWER_STATE_RESTART) != CMD_OK) { + PRINTF("failed to restart RX"); + return RADIO_RESULT_ERROR; + } + return RADIO_RESULT_OK; + + case RADIO_PARAM_RX_MODE: { + if (value & ~(RADIO_RX_MODE_ADDRESS_FILTER | + RADIO_RX_MODE_AUTOACK | RADIO_RX_MODE_POLL_MODE)) { + return RADIO_RESULT_INVALID_VALUE; + } + + g_vpCmdRx->frameFiltOpt.frameFiltEn = (value & RADIO_RX_MODE_ADDRESS_FILTER) != 0; + g_vpCmdRx->frameFiltOpt.frameFiltStop = 1; + g_vpCmdRx->frameFiltOpt.autoAckEn = (value & RADIO_RX_MODE_AUTOACK) != 0; + g_vpCmdRx->frameFiltOpt.slottedAckEn = 0; + g_vpCmdRx->frameFiltOpt.autoPendEn = 0; + g_vpCmdRx->frameFiltOpt.defaultPend = 0; + g_vpCmdRx->frameFiltOpt.bPendDataReqOnly = 0; + g_vpCmdRx->frameFiltOpt.bPanCoord = 0; + g_vpCmdRx->frameFiltOpt.bStrictLenFilter = 0; + + const bool bOldPollMode = g_bPollMode; + g_bPollMode = (value & RADIO_RX_MODE_POLL_MODE) != 0; + if (g_bPollMode == bOldPollMode) { + // Do not turn the radio off and on, just send an update command + memcpy(&g_cmdModFilt.newFrameFiltOpt, &RF_cmdIeeeRx.frameFiltOpt, sizeof(RF_cmdIeeeRx.frameFiltOpt)); + const RF_Stat stat = RF_runImmediateCmd(g_rfHandle, (uint32_t*)&g_cmdModFilt); + if (stat != RF_StatCmdDoneSuccess) { + PRINTF("setting address filter failed: stat=0x%02X\n", stat); + return RADIO_RESULT_ERROR; + } + return RADIO_RESULT_OK; + } + if (rf_is_on() && set_rx(POWER_STATE_RESTART) != CMD_OK) { + PRINTF("failed to restart RX"); + return RADIO_RESULT_ERROR; + } + return RADIO_RESULT_OK; + } + + case RADIO_PARAM_TX_MODE: + if(value & ~(RADIO_TX_MODE_SEND_ON_CCA)) { + return RADIO_RESULT_INVALID_VALUE; + } + set_send_on_cca((value & RADIO_TX_MODE_SEND_ON_CCA) != 0); + return RADIO_RESULT_OK; + + case RADIO_PARAM_TXPOWER: + if(value < TX_POWER_MIN.dbm || value > TX_POWER_MAX.dbm) { + return RADIO_RESULT_INVALID_VALUE; + } + return (set_tx_power(value) != CMD_OK) + ? RADIO_RESULT_ERROR + : RADIO_RESULT_OK; + + case RADIO_PARAM_CCA_THRESHOLD: + g_vpCmdRx->ccaRssiThr = (int8_t)value; + if (rf_is_on() && set_rx(POWER_STATE_RESTART) != CMD_OK) { + PRINTF("failed to restart RX"); + return RADIO_RESULT_ERROR; + } + return RADIO_RESULT_OK; + + default: + return RADIO_RESULT_NOT_SUPPORTED; + } +} +/*---------------------------------------------------------------------------*/ +static radio_result_t +get_object(radio_param_t param, void *dest, size_t size) +{ + if (!dest) { + return RADIO_RESULT_INVALID_VALUE; + } + + switch (param) { + case RADIO_PARAM_64BIT_ADDR: { + const size_t srcSize = sizeof(g_vpCmdRx->localExtAddr); + if(size != srcSize) { + return RADIO_RESULT_INVALID_VALUE; + } + + const uint8_t *pSrc = (const uint8_t *)&g_vpCmdRx->localExtAddr; + uint8_t *pDest = dest; + for(size_t i = 0; i < srcSize; ++i) { + pDest[i] = pSrc[srcSize - 1 - i]; + } + + return RADIO_RESULT_OK; + } + case RADIO_PARAM_LAST_PACKET_TIMESTAMP: + if(size != sizeof(rtimer_clock_t)) { + return RADIO_RESULT_INVALID_VALUE; + } + + *(rtimer_clock_t *)dest = g_lastTimestamp; + + return RADIO_RESULT_OK; + + default: + return RADIO_RESULT_NOT_SUPPORTED; + } +} +/*---------------------------------------------------------------------------*/ +static radio_result_t +set_object(radio_param_t param, const void *src, size_t size) +{ + if (!src) { + return RADIO_RESULT_INVALID_VALUE; + } + + switch (param) { + case RADIO_PARAM_64BIT_ADDR: { + const size_t destSize = sizeof(g_vpCmdRx->localExtAddr); + if (size != destSize) { + return RADIO_RESULT_INVALID_VALUE; + } + + const uint8_t *pSrc = (const uint8_t *)src; + uint8_t *pDest = (uint8_t *)&g_vpCmdRx->localExtAddr; + for (size_t i = 0; i < destSize; ++i) { + pDest[i] = pSrc[destSize - 1 - i]; + } + + const bool is_rx = (g_vpCmdRx->status == ACTIVE); + if (is_rx && set_rx(POWER_STATE_RESTART) != CMD_OK) { + return RADIO_RESULT_ERROR; + } + return RADIO_RESULT_OK; + } + default: + return RADIO_RESULT_NOT_SUPPORTED; + } +} +/*---------------------------------------------------------------------------*/ +const struct radio_driver ieee_mode_driver = { + init, + prepare, + transmit, + send, + read_frame, + channel_clear, + receiving_packet, + pending_packet, + on, + off, + get_value, + set_value, + get_object, + set_object, +}; +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/cpu/simplelink/dev/proprietary-rf.c b/arch/cpu/simplelink/dev/rf-prop-mode.c similarity index 75% rename from arch/cpu/simplelink/dev/proprietary-rf.c rename to arch/cpu/simplelink/dev/rf-prop-mode.c index b8a2ec7c1..375b79554 100644 --- a/arch/cpu/simplelink/dev/proprietary-rf.c +++ b/arch/cpu/simplelink/dev/rf-prop-mode.c @@ -44,22 +44,19 @@ #include "sys/rtimer.h" #include "sys/cc.h" #include "dev/watchdog.h" -#include "proprietary-rf.h" -#include "rf-core.h" -#include "dot-15-4g.h" -/*---------------------------------------------------------------------------*/ -/* RF core and RF HAL API */ -#include -#include /*---------------------------------------------------------------------------*/ /* RF Core Mailbox API */ #include #include #include -#include #include -#include +#include #include +#include +/*---------------------------------------------------------------------------*/ +/* Platform RF dev */ +#include "rf-core.h" +#include "dot-15-4g.h" /*---------------------------------------------------------------------------*/ #include #include @@ -67,31 +64,23 @@ #include #include /*---------------------------------------------------------------------------*/ -#define DEBUG 0 -#if DEBUG -#define PRINTF(...) printf(__VA_ARGS__) +#ifdef NDEBUG +# define PRINTF(...) #else -#define PRINTF(...) +# define PRINTF(...) printf(__VA_ARGS__) #endif /*---------------------------------------------------------------------------*/ -/* Data entry status field constants */ -#define DATA_ENTRY_STATUS_PENDING 0x00 /* Not in use by the Radio CPU */ -#define DATA_ENTRY_STATUS_ACTIVE 0x01 /* Open for r/w by the radio CPU */ -#define DATA_ENTRY_STATUS_BUSY 0x02 /* Ongoing r/w */ -#define DATA_ENTRY_STATUS_FINISHED 0x03 /* Free to use and to free */ -#define DATA_ENTRY_STATUS_UNFINISHED 0x04 /* Partial RX entry */ -/*---------------------------------------------------------------------------*/ /* Data whitener. 1: Whitener, 0: No whitener */ #ifdef PROP_MODE_CONF_DW -#define PROP_MODE_DW PROP_MODE_CONF_DW +# define PROP_MODE_DW PROP_MODE_CONF_DW #else -#define PROP_MODE_DW 0 +# define PROP_MODE_DW 0 #endif #ifdef PROP_MODE_CONF_USE_CRC16 -#define PROP_MODE_USE_CRC16 PROP_MODE_CONF_USE_CRC16 +# define PROP_MODE_USE_CRC16 PROP_MODE_CONF_USE_CRC16 #else -#define PROP_MODE_USE_CRC16 0 +# define PROP_MODE_USE_CRC16 0 #endif /*---------------------------------------------------------------------------*/ /** @@ -169,14 +158,14 @@ static rfc_propRxOutput_t rx_stats; #ifdef PROP_MODE_CONF_TX_POWER_431_527 #define PROP_MODE_TX_POWER_431_527 PROP_MODE_CONF_TX_POWER_431_527 #else -#define PROP_MODE_TX_POWER_431_527 prop_mode_tx_power_431_527 +#define PROP_MODE_TX_POWER_431_527 RF_propTxPower431_527 #endif /*---------------------------------------------------------------------------*/ /* TX power table for the 779-930MHz band */ #ifdef PROP_MODE_CONF_TX_POWER_779_930 #define PROP_MODE_TX_POWER_779_930 PROP_MODE_CONF_TX_POWER_779_930 #else -#define PROP_MODE_TX_POWER_779_930 prop_mode_tx_power_779_930 +#define PROP_MODE_TX_POWER_779_930 RF_propTxPower779_930 #endif /*---------------------------------------------------------------------------*/ /* Select power table based on the frequency band */ @@ -185,21 +174,12 @@ static rfc_propRxOutput_t rx_stats; #else #define TX_POWER_DRIVER PROP_MODE_TX_POWER_779_930 #endif -/*---------------------------------------------------------------------------*/ -extern const prop_mode_tx_power_config_t TX_POWER_DRIVER[]; /* Max and Min Output Power in dBm */ #define OUTPUT_POWER_MAX (TX_POWER_DRIVER[0].dbm) -#define OUTPUT_POWER_UNKNOWN 0xFFFF /* Default TX Power - position in output_power[] */ -static const prop_mode_tx_power_config_t *tx_power_current = &TX_POWER_DRIVER[1]; -/*---------------------------------------------------------------------------*/ -#ifdef PROP_MODE_CONF_LO_DIVIDER -#define PROP_MODE_LO_DIVIDER PROP_MODE_CONF_LO_DIVIDER -#else -#define PROP_MODE_LO_DIVIDER 0x05 -#endif +static const RF_TxPower *tx_power_current = &TX_POWER_DRIVER[0]; /*---------------------------------------------------------------------------*/ #ifdef PROP_MODE_CONF_RX_BUF_CNT #define PROP_MODE_RX_BUF_CNT PROP_MODE_CONF_RX_BUF_CNT @@ -231,128 +211,110 @@ volatile static uint8_t *rx_read_entry; static uint8_t tx_buf[TX_BUF_HDR_LEN + TX_BUF_PAYLOAD_LEN] CC_ALIGN(4); /*---------------------------------------------------------------------------*/ +volatile static rfc_CMD_PROP_RADIO_DIV_SETUP_t *gvp_cmd_radio_div_setup = &rf_cmd_prop_radio_div_setup; +volatile static rfc_CMD_FS_t *gvp_cmd_fs = &rf_cmd_prop_fs; +volatile static rfc_CMD_PROP_TX_ADV_t *gvp_cmd_tx_adv = &rf_cmd_prop_tx_adv; +volatile static rfc_CMD_PROP_RX_ADV_t *gvp_cmd_rx_adv = &rf_cmd_prop_rx_adv; +/*---------------------------------------------------------------------------*/ /* RF driver */ static RF_Object rfObject; static RF_Handle rfHandle; -static RF_CmdHandle rxCmdHandle = RF_ALLOC_ERROR; /*---------------------------------------------------------------------------*/ -PROCESS(rf_core_process, "CC13xx / CC26xx RF driver"); - -static uint8_t -rf_transmitting(void) -{ - return smartrf_settings_cmd_prop_tx_adv.status == ACTIVE; -} -/*---------------------------------------------------------------------------*/ -static uint8_t -rf_receiving(void) -{ - return smartrf_settings_cmd_prop_rx_adv.status == ACTIVE; -} -/*---------------------------------------------------------------------------*/ -static uint8_t -rf_is_on(void) -{ - return rf_receiving() | rf_transmitting(); -} +static inline bool rf_is_transmitting(void) { return gvp_cmd_tx_adv->status == ACTIVE; } +static inline bool rf_is_receiving(void) { return gvp_cmd_rx_adv->status == ACTIVE; } +static inline bool rf_is_on(void) { return rf_is_transmitting() || rf_is_receiving(); } /*---------------------------------------------------------------------------*/ static void rf_rx_callback(RF_Handle client, RF_CmdHandle command, RF_EventMask events) { if (events & RF_EventRxEntryDone) { - process_poll(&rf_core_process); + process_poll(&RF_coreProcess); } } /*---------------------------------------------------------------------------*/ -static uint8_t +static CmdResult rf_start_rx() { - rtimer_clock_t t0; - volatile rfc_CMD_PROP_RX_ADV_t *cmd_rx_adv; - - cmd_rx_adv = (rfc_CMD_PROP_RX_ADV_t *)&smartrf_settings_cmd_prop_rx_adv; - cmd_rx_adv->status = IDLE; + gvp_cmd_rx_adv->status = IDLE; /* * Set the max Packet length. This is for the payload only, therefore * 2047 - length offset */ - cmd_rx_adv->maxPktLen = DOT_4G_MAX_FRAME_LEN - cmd_rx_adv->lenOffset; + gvp_cmd_rx_adv->maxPktLen = DOT_4G_MAX_FRAME_LEN - gvp_cmd_rx_adv->lenOffset; - rxCmdHandle = RF_postCmd(rfHandle, (RF_Op*)&smartrf_settings_cmd_prop_rx_adv, RF_PriorityNormal, &rf_rx_callback, RF_EventRxEntryDone); + RF_CmdHandle rxCmdHandle = RF_postCmd(rfHandle, (RF_Op*)gvp_cmd_rx_adv, RF_PriorityNormal, + &rf_rx_callback, RF_EventRxEntryDone); if (rxCmdHandle == RF_ALLOC_ERROR) { - return RF_CORE_CMD_ERROR; + return CMD_ERROR; } - t0 = RTIMER_NOW(); - - while(cmd_rx_adv->status != ACTIVE && - (RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + ENTER_RX_WAIT_TIMEOUT))); - /* Wait to enter RX */ - if(cmd_rx_adv->status != ACTIVE) { - PRINTF("rf_cmd_prop_rx: CMDSTA=0x%08lx, status=0x%04x\n", - md_status, cmd_rx_adv->status); + const rtimer_clock_t t0 = RTIMER_NOW(); + while (!rf_is_receiving() && + (RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + ENTER_RX_WAIT_TIMEOUT))); + + if (!rf_is_receiving()) { + PRINTF("RF_cmdPropRxAdv: handle=0x%08lx, status=0x%04x\n", + (unsigned long)rxCmdHandle, gvp_cmd_rx_adv->status); rf_switch_off(); - return RF_CORE_CMD_ERROR; + return CMD_ERROR; } - return RF_CORE_CMD_OK; + return CMD_OK; } /*---------------------------------------------------------------------------*/ -static int +static CmdResult rf_stop_rx(void) { - int ret; - /* If we are off, do nothing */ - if(!rf_receiving()) { - return RF_CORE_CMD_OK; + if (!rf_is_receiving()) { + return CMD_OK; } /* Abort any ongoing operation. Don't care about the result. */ RF_cancelCmd(rfHandle, RF_CMDHANDLE_FLUSH_ALL, 1); - /* Todo: maybe do a RF_pendCmd() to synchronise with command execution. */ + /* Todo: maybe do a RF_pendCmd() to synchronize with command execution. */ - if(smartrf_settings_cmd_prop_rx_adv.status == PROP_DONE_STOPPED || - smartrf_settings_cmd_prop_rx_adv.status == PROP_DONE_ABORT) { - /* Stopped gracefully */ - ENERGEST_OFF(ENERGEST_TYPE_LISTEN); - ret = RF_CORE_CMD_OK; - } else { - PRINTF("rx_off_prop: status=0x%04x\n", - smartrf_settings_cmd_prop_rx_adv.status); - ret = RF_CORE_CMD_ERROR; + if(gvp_cmd_rx_adv->status != PROP_DONE_STOPPED && + gvp_cmd_rx_adv->status != PROP_DONE_ABORT) { + PRINTF("RF_cmdPropRxAdv cancel: status=0x%04x\n", + gvp_cmd_rx_adv->status); + return CMD_ERROR; } - return ret; -}/*---------------------------------------------------------------------------*/ -static uint8_t + /* Stopped gracefully */ + ENERGEST_OFF(ENERGEST_TYPE_LISTEN); + return CMD_OK; +} +/*---------------------------------------------------------------------------*/ +static CmdResult rf_run_setup() { - RF_runCmd(rfHandle, (RF_Op*)&smartrf_settings_cmd_prop_radio_div_setup, RF_PriorityNormal, NULL, 0); - if (((volatile RF_Op*)&smartrf_settings_cmd_prop_radio_div_setup)->status != PROP_DONE_OK) { - return RF_CORE_CMD_ERROR; + RF_runCmd(rfHandle, (RF_Op*)gvp_cmd_radio_div_setup, RF_PriorityNormal, NULL, 0); + if (gvp_cmd_radio_div_setup->status != PROP_DONE_OK) { + return CMD_ERROR; } - return RF_CORE_CMD_OK; + return CMD_OK; } /*---------------------------------------------------------------------------*/ static radio_value_t get_rssi(void) { - int8_t rssi = RF_GET_RSSI_ERROR_VAL; - uint8_t was_off = 0; - - if (rf_transmitting()) { - PRINTF("channel_clear: called while in TX\n"); - return RF_CCA_CLEAR; - } else if (!rf_receiving()) { - was_off = 1; - rf_start_rx(); + if (rf_is_transmitting()) { + PRINTF("get_rssi: called while in TX\n"); + return RF_GET_RSSI_ERROR_VAL; } + const bool was_off = !rf_is_receiving(); + if (was_off && rf_start_rx() == CMD_ERROR) { + PRINTF("get_rssi: unable to start RX\n"); + return RF_GET_RSSI_ERROR_VAL; + } + + int8_t rssi = RF_GET_RSSI_ERROR_VAL; while(rssi == RF_GET_RSSI_ERROR_VAL || rssi == 0) { rssi = RF_getRssi(rfHandle); } @@ -369,7 +331,7 @@ get_channel(void) { uint32_t freq_khz; - freq_khz = smartrf_settings_cmd_prop_fs.frequency * 1000; + freq_khz = gvp_cmd_fs->frequency * 1000; /* * For some channels, fractFreq * 1000 / 65536 will return 324.99xx. @@ -377,7 +339,7 @@ get_channel(void) * function returning channel - 1 instead of channel. Thus, we do a quick * positive integer round up. */ - freq_khz += (((smartrf_settings_cmd_prop_fs.fractFreq * 1000) + 65535) / 65536); + freq_khz += (((gvp_cmd_fs->fractFreq * 1000) + 65535) / 65536); return (freq_khz - DOT_15_4G_CHAN0_FREQUENCY) / DOT_15_4G_CHANNEL_SPACING; } @@ -385,20 +347,17 @@ get_channel(void) static void set_channel(uint8_t channel) { - uint32_t new_freq; - uint16_t freq, frac; + uint32_t new_freq = DOT_15_4G_CHAN0_FREQUENCY + (channel * DOT_15_4G_CHANNEL_SPACING); - new_freq = DOT_15_4G_CHAN0_FREQUENCY + (channel * DOT_15_4G_CHANNEL_SPACING); + uint16_t freq = (uint16_t)(new_freq / 1000); + uint16_t frac = (new_freq - (freq * 1000)) * 65536 / 1000; - freq = (uint16_t)(new_freq / 1000); - frac = (new_freq - (freq * 1000)) * 65536 / 1000; + PRINTF("set_channel: %u = 0x%04x.0x%04x (%lu)\n", + channel, freq, frac, new_freq); - PRINTF("set_channel: %u = 0x%04x.0x%04x (%lu)\n", channel, freq, frac, - new_freq); - - smartrf_settings_cmd_prop_radio_div_setup.centerFreq = freq; - smartrf_settings_cmd_prop_fs.frequency = freq; - smartrf_settings_cmd_prop_fs.fractFreq = frac; + gvp_cmd_radio_div_setup->centerFreq = freq; + gvp_cmd_fs->frequency = freq; + gvp_cmd_fs->fractFreq = frac; // Todo: Need to re-run setup command when deviation from previous frequency // is too large @@ -406,16 +365,16 @@ set_channel(uint8_t channel) // We don't care whether the FS command is successful because subsequent // TX and RX commands will tell us indirectly. - RF_postCmd(rfHandle, (RF_Op*)&smartrf_settings_cmd_prop_fs, RF_PriorityNormal, NULL, 0); + RF_postCmd(rfHandle, (RF_Op*)gvp_cmd_fs, RF_PriorityNormal, NULL, 0); } /*---------------------------------------------------------------------------*/ -static uint8_t +static size_t get_tx_power_array_last_element(void) { - const prop_mode_tx_power_config_t *array = TX_POWER_DRIVER; + const RF_TxPower *array = TX_POWER_DRIVER; uint8_t count = 0; - while(array->tx_power != OUTPUT_POWER_UNKNOWN) { + while(array->power != TX_POWER_UNKNOWN) { count++; array++; } @@ -434,21 +393,34 @@ get_tx_power(void) * radio after calling this function. */ static void -set_tx_power(radio_value_t power) +set_tx_power(const radio_value_t power) { - int i; + if (power > OUTPUT_POWER_MAX) + { + tx_power_current = &TX_POWER_DRIVER[0]; + } + else + { + size_t i; + for (i = 0; TX_POWER_DRIVER[i + 1].power != TX_POWER_UNKNOWN; ++i) + { + if (power > TX_POWER_DRIVER[i + 1].dbm) + { + break; + } + } - for(i = get_tx_power_array_last_element(); i >= 0; --i) { - if(power <= TX_POWER_DRIVER[i].dbm) { - /* - * Merely save the value. It will be used in all subsequent usages of - * CMD_PROP_RADIO_DIV_SETP, including one immediately after this function - * has returned - */ tx_power_current = &TX_POWER_DRIVER[i]; + } - return; - } + rfc_CMD_SET_TX_POWER_t cmd_set_tx_power; + memset(&cmd_set_tx_power, 0x00, sizeof(rfc_CMD_SET_TX_POWER_t)); + cmd_set_tx_power.commandNo = CMD_SET_TX_POWER; + cmd_set_tx_power.txPower = tx_power_current->power; + + RF_Stat stat = RF_runImmediateCmd(rfHandle, (uint32_t*)&cmd_set_tx_power); + if (stat != RF_StatCmdDoneSuccess) { + PRINTF("set_tx_power: stat=0x%02X\n", stat); } } /*---------------------------------------------------------------------------*/ @@ -460,7 +432,7 @@ init_rx_buffers(void) for(i = 0; i < PROP_MODE_RX_BUF_CNT; i++) { entry = (rfc_dataEntry_t *)rx_buf[i]; - entry->status = DATA_ENTRY_STATUS_PENDING; + entry->status = DATA_ENTRY_PENDING; entry->config.type = DATA_ENTRY_TYPE_GEN; entry->config.lenSz = DATA_ENTRY_LENSZ_WORD; entry->length = RX_BUF_SIZE - 8; @@ -484,12 +456,11 @@ transmit(unsigned short transmit_len) { int ret; uint8_t was_off = 0; - volatile rfc_CMD_PROP_TX_ADV_t *cmd_tx_adv; - if (rf_transmitting()) { + if (rf_is_transmitting()) { PRINTF("transmit: not allowed while transmitting\n"); return RADIO_TX_ERR; - } else if (rf_receiving()) { + } else if (rf_is_receiving()) { rf_stop_rx(); } else { was_off = 1; @@ -511,18 +482,15 @@ transmit(unsigned short transmit_len) tx_buf[0] = total_length & 0xFF; tx_buf[1] = (total_length >> 8) + DOT_4G_PHR_DW_BIT + DOT_4G_PHR_CRC_BIT; - /* Prepare the CMD_PROP_TX_ADV command */ - cmd_tx_adv = (rfc_CMD_PROP_TX_ADV_t *)&smartrf_settings_cmd_prop_tx_adv; - /* * pktLen: Total number of bytes in the TX buffer, including the header if * one exists, but not including the CRC (which is not present in the buffer) */ - cmd_tx_adv->pktLen = transmit_len + DOT_4G_PHR_LEN; - cmd_tx_adv->pPkt = tx_buf; + gvp_cmd_tx_adv->pktLen = transmit_len + DOT_4G_PHR_LEN; + gvp_cmd_tx_adv->pPkt = tx_buf; // TODO: Register callback - RF_runCmd(rfHandle, (RF_Op*)cmd_tx_adv, RF_PriorityNormal, NULL, 0); + RF_runCmd(rfHandle, (RF_Op*)gvp_cmd_tx_adv, RF_PriorityNormal, NULL, 0); // if (txHandle == RF_ALLOC_ERROR) // { // /* Failure sending the CMD_PROP_TX command */ @@ -538,20 +506,20 @@ transmit(unsigned short transmit_len) // /* Idle away while the command is running */ // RF_pendCmd(rfHandle, txHandle, RF_EventLastCmdDone); - if(cmd_tx_adv->status == PROP_DONE_OK) { + if(gvp_cmd_tx_adv->status == PROP_DONE_OK) { /* Sent OK */ ret = RADIO_TX_OK; } else { /* Operation completed, but frame was not sent */ PRINTF("transmit: Not Sent OK status=0x%04x\n", - cmd_tx_adv->status); + gvp_cmd_tx_adv->status); ret = RADIO_TX_ERR; } ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); /* Workaround. Set status to IDLE */ - cmd_tx_adv->status = IDLE; + gvp_cmd_tx_adv->status = IDLE; if (was_off) { RF_yield(rfHandle); @@ -576,7 +544,7 @@ read_frame(void *buf, unsigned short buf_len) uint8_t *data_ptr = &entry->data; int len = 0; - if(entry->status == DATA_ENTRY_STATUS_FINISHED) { + if(entry->status == DATA_ENTRY_FINISHED) { /* * First 2 bytes in the data entry are the length. @@ -598,7 +566,7 @@ read_frame(void *buf, unsigned short buf_len) /* Move read entry pointer to next entry */ rx_read_entry = entry->pNextEntry; - entry->status = DATA_ENTRY_STATUS_PENDING; + entry->status = DATA_ENTRY_PENDING; } return len; @@ -618,10 +586,10 @@ channel_clear(void) // return RF_CCA_CLEAR; // } - if (rf_transmitting()) { + if (rf_is_transmitting()) { PRINTF("channel_clear: called while in TX\n"); return RF_CCA_CLEAR; - } else if (!rf_receiving()) { + } else if (!rf_is_receiving()) { was_off = 1; rf_start_rx(); } @@ -644,7 +612,7 @@ channel_clear(void) static int receiving_packet(void) { - if(!rf_receiving()) { + if(!rf_is_receiving()) { return 0; } @@ -663,9 +631,9 @@ pending_packet(void) /* Go through all RX buffers and check their status */ do { - if(entry->status == DATA_ENTRY_STATUS_FINISHED) { + if(entry->status == DATA_ENTRY_FINISHED) { rv += 1; - process_poll(&rf_core_process); + process_poll(&RF_coreProcess); } entry = (rfc_dataEntry_t *)entry->pNextEntry; @@ -690,7 +658,7 @@ rf_switch_off(void) // * from within an interrupt context. Abort, but pretend everything is OK. // */ // if(rf_ble_is_active() == RF_BLE_ACTIVE) { -// return RF_CORE_CMD_OK; +// return CMD_OK; // } // Force abort of any ongoing RF operation. @@ -700,9 +668,9 @@ rf_switch_off(void) RF_yield(rfHandle); /* We pulled the plug, so we need to restore the status manually */ - smartrf_settings_cmd_prop_rx_adv.status = IDLE; + gvp_cmd_rx_adv->status = IDLE; - return RF_CORE_CMD_OK; + return CMD_OK; } /*---------------------------------------------------------------------------*/ static radio_result_t @@ -797,13 +765,13 @@ set_value(radio_param_t param, radio_value_t value) } /* If we reach here we had no errors. Apply new settings */ - if (rf_receiving()) { + if (rf_is_receiving()) { rf_stop_rx(); - if (rf_run_setup() != RF_CORE_CMD_OK) { + if (rf_run_setup() != CMD_OK) { return RADIO_RESULT_ERROR; } rf_start_rx(); - } else if (rf_transmitting()) { + } else if (rf_is_transmitting()) { // Should not happen. TX is always synchronous and blocking. // Todo: maybe remove completely here. PRINTF("set_value: cannot apply new value while transmitting. \n"); @@ -833,10 +801,10 @@ rf_init(void) { RF_Params params; RF_Params_init(¶ms); - params.nInactivityTimeout = 0; // disable automatic power-down - // just to not interfere with stack timing + // Disable automatic power-down just to not interfere with stack timing + params.nInactivityTimeout = 0; - rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&smartrf_settings_cmd_prop_radio_div_setup, ¶ms); + rfHandle = RF_open(&rfObject, &RF_propMode, (RF_RadioSetup*)gvp_cmd_radio_div_setup, ¶ms); assert(rfHandle != NULL); /* Initialise RX buffers */ @@ -849,39 +817,16 @@ rf_init(void) /* Initialize current read pointer to first element (used in ISR) */ rx_read_entry = rx_buf[0]; - smartrf_settings_cmd_prop_rx_adv.pQueue = &rx_data_queue; - smartrf_settings_cmd_prop_rx_adv.pOutput = (uint8_t *)&rx_stats; + gvp_cmd_rx_adv->pQueue = &rx_data_queue; + gvp_cmd_rx_adv->pOutput = (uint8_t *)&rx_stats; set_channel(RF_CORE_CHANNEL); ENERGEST_ON(ENERGEST_TYPE_LISTEN); - process_start(&rf_core_process, NULL); + process_start(&RF_coreProcess, NULL); - return 1; -} -/*---------------------------------------------------------------------------*/ -PROCESS_THREAD(rf_core_process, ev, data) -{ - int len; - - PROCESS_BEGIN(); - - while(1) { - PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL); - do { - watchdog_periodic(); - packetbuf_clear(); - len = NETSTACK_RADIO.read(packetbuf_dataptr(), PACKETBUF_SIZE); - - if(len > 0) { - packetbuf_set_datalen(len); - - NETSTACK_MAC.input(); - } - } while(len > 0); - } - PROCESS_END(); + return CMD_OK; } /*---------------------------------------------------------------------------*/ const struct radio_driver prop_mode_driver = { diff --git a/arch/cpu/simplelink/dev/watchdog-arch.c b/arch/cpu/simplelink/dev/watchdog-arch.c index ac137e577..505570ccd 100644 --- a/arch/cpu/simplelink/dev/watchdog-arch.c +++ b/arch/cpu/simplelink/dev/watchdog-arch.c @@ -109,6 +109,7 @@ lock_config(uint32_t status) void watchdog_init(void) { + return; WatchdogReloadSet(CONTIKI_WATCHDOG_TIMER_TOP); lock_config(LOCK_REGISTERS_UNLOCKED); } @@ -119,6 +120,7 @@ watchdog_init(void) void watchdog_start(void) { + return; uint32_t lock_status = unlock_config(); watchdog_periodic(); @@ -133,6 +135,7 @@ watchdog_start(void) void watchdog_periodic(void) { + return; WatchdogReloadSet(CONTIKI_WATCHDOG_TIMER_TOP); WatchdogIntClear(); } @@ -143,6 +146,7 @@ watchdog_periodic(void) void watchdog_stop(void) { + return; uint32_t lock_status = unlock_config(); WatchdogResetDisable(); @@ -156,6 +160,7 @@ watchdog_stop(void) void watchdog_reboot(void) { + return; watchdog_start(); while(1); } diff --git a/arch/cpu/simplelink/rf-settings/rf-ieee-settings.c b/arch/cpu/simplelink/rf-settings/rf-ieee-settings.c new file mode 100644 index 000000000..85dda307d --- /dev/null +++ b/arch/cpu/simplelink/rf-settings/rf-ieee-settings.c @@ -0,0 +1,209 @@ +//********************************************************************************* +// Generated by SmartRF Studio version 2.8.0 ( build #41) +// Compatible with SimpleLink SDK version: CC13x2 SDK 1.60.xx.xx +// Device: CC1352 Rev. 1.0 +// +//********************************************************************************* + + +//********************************************************************************* +// Parameter summary +// IEEE Channel: 11 +// Frequency: 2405 MHz +// SFD: 0 +// Preamble (32 bit): 01010101... +// TX Power: 5 dBm + +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_ieee_cmd.h) +#include +#include DeviceFamily_constructPath(rf_patches/rf_patch_cpe_ieee_802_15_4.h) +#include DeviceFamily_constructPath(rf_patches/rf_patch_mce_ieee_802_15_4.h) + +#include +#include + +#include "rf-core.h" + +/*---------------------------------------------------------------------------*/ +/* Default TX power settings for the 2.4 GHz band */ +RF_TxPower RF_ieeeTxPower[] = { + { 5, 0x9330 }, + { 4, 0x9324 }, + { 3, 0x5a1c }, + { 2, 0x4e18 }, + { 1, 0x4214 }, + { 0, 0x3161 }, + { -3, 0x2558 }, + { -6, 0x1d52 }, + { -9, 0x194e }, + { -12, 0x144b }, + { -15, 0x0ccb }, + { -18, 0x0cc9 }, + { -21, 0x0cc7 }, + {-128, 0xFFFF }, +}; +const size_t RF_ieeeTxPowerLen = sizeof(RF_ieeeTxPower) / sizeof(RF_ieeeTxPower[0]); + + +// TI-RTOS RF Mode Object +RF_Mode RF_ieeeMode = +{ + .rfMode = RF_MODE_AUTO, + .cpePatchFxn = &rf_patch_cpe_ieee_802_15_4, + .mcePatchFxn = &rf_patch_mce_ieee_802_15_4, + .rfePatchFxn = 0, +}; + + +// Overrides for CMD_RADIO_SETUP +static uint32_t pOverrides[] = +{ + // override_use_patch_ieee_802_15_4.xml + // PHY: Use MCE RAM patch, RFE ROM bank 1 + MCE_RFE_OVERRIDE(1,0,0,0,1,0), + // override_synth_ieee_802_15_4.xml + // Synth: Use 48 MHz crystal + (uint32_t)0x00408403, + // override_dcdc_rx_tx_common.xml + // DC/DC regulator: In Tx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). + (uint32_t)0xFCFC08C3, + (uint32_t)0xFFFFFFFF, +}; + + +// CMD_RADIO_SETUP +// Radio Setup Command for Pre-Defined Schemes +rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup = +{ + .commandNo = 0x0802, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .mode = 0x01, + .loDivider = 0x00, + .config.frontEndMode = 0x0, + .config.biasMode = 0x0, + .config.analogCfgMode = 0x0, + .config.bNoFsPowerUp = 0x0, + .txPower = 0x001F, + .pRegOverride = pOverrides, +}; + + +// CMD_FS +// Frequency Synthesizer Programming Command +rfc_CMD_FS_t RF_cmdFs = +{ + .commandNo = 0x0803, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .frequency = 0x0965, + .fractFreq = 0x0000, + .synthConf.bTxMode = 0x0, + .synthConf.refFreq = 0x0, + .__dummy0 = 0x00, + .__dummy1 = 0x00, + .__dummy2 = 0x00, + .__dummy3 = 0x0000, +}; + + +// CMD_IEEE_RX +// IEEE 802.15.4 Receive Command +rfc_CMD_IEEE_RX_t RF_cmdIeeeRx = +{ + .commandNo = CMD_IEEE_RX, + .status = IDLE, + .pNextOp = NULL, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .condition.rule = COND_NEVER, + .channel = 0, + .rxConfig.bAutoFlushCrc = 0x1, + .rxConfig.bAutoFlushIgn = 0x0, + .rxConfig.bIncludePhyHdr = 0x0, + .rxConfig.bIncludeCrc = 0x1, + .rxConfig.bAppendRssi = 0x1, + .rxConfig.bAppendCorrCrc = 0x1, + .rxConfig.bAppendSrcInd = 0x0, + .rxConfig.bAppendTimestamp = 0x1, + .pRxQ = NULL, + .pOutput = NULL, + .frameFiltOpt.frameFiltEn = 0x0, + .frameFiltOpt.frameFiltStop = 0x1, + .frameFiltOpt.autoAckEn = 0x0, + .frameFiltOpt.slottedAckEn = 0x0, + .frameFiltOpt.autoPendEn = 0x0, + .frameFiltOpt.defaultPend = 0x0, + .frameFiltOpt.bPendDataReqOnly = 0x0, + .frameFiltOpt.bPanCoord = 0x0, + .frameFiltOpt.maxFrameVersion = 0x2, + .frameFiltOpt.bStrictLenFilter = 0x0, + .frameTypes.bAcceptFt0Beacon = 0x1, + .frameTypes.bAcceptFt1Data = 0x1, + .frameTypes.bAcceptFt2Ack = 0x1, + .frameTypes.bAcceptFt3MacCmd = 0x1, + .frameTypes.bAcceptFt4Reserved = 0x1, + .frameTypes.bAcceptFt5Reserved = 0x1, + .frameTypes.bAcceptFt6Reserved = 0x1, + .frameTypes.bAcceptFt7Reserved = 0x1, + .ccaOpt.ccaEnEnergy = 0x1, + .ccaOpt.ccaEnCorr = 0x1, + .ccaOpt.ccaEnSync = 0x1, + .ccaOpt.ccaCorrOp = 0x1, + .ccaOpt.ccaSyncOp = 0x0, + .ccaOpt.ccaCorrThr = 0x3, + .ccaRssiThr = 0x64, + .numExtEntries = 0x00, + .numShortEntries = 0x00, + .pExtEntryList = NULL, + .pShortEntryList = NULL, + .localExtAddr = 0x0000000012345678, + .localShortAddr = 0xABBA, + .localPanID = 0x0000, + .endTrigger.triggerType = TRIG_NEVER, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, +}; + + +// CMD_IEEE_TX +// IEEE 802.15.4 Transmit Command +rfc_CMD_IEEE_TX_t RF_cmdIeeeTx = +{ + .commandNo = 0x2C01, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .txOpt.bIncludePhyHdr = 0x0, + .txOpt.bIncludeCrc = 0x0, + .txOpt.payloadLenMsb = 0x0, + .payloadLen = 0x1E, + .pPayload = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .timeStamp = 0x00000000, +}; + diff --git a/arch/cpu/simplelink/rf-settings/rf-ieee-settings.h b/arch/cpu/simplelink/rf-settings/rf-ieee-settings.h new file mode 100644 index 000000000..898c830cf --- /dev/null +++ b/arch/cpu/simplelink/rf-settings/rf-ieee-settings.h @@ -0,0 +1,26 @@ +#ifndef IEEE_SETTINGS_H_ +#define IEEE_SETTINGS_H_ + + +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h) +#include + +#include + +// RF TX power table +extern RF_TxPower RF_ieeeTxPower[]; +extern const size_t RF_ieeeTxPowerLen; + +// TI-RTOS RF Mode Object +extern RF_Mode RF_ieeeMode; + +// RF Core API commands +extern rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup; +extern rfc_CMD_FS_t RF_cmdFs; +extern rfc_CMD_IEEE_RX_t RF_cmdIeeeRx; +extern rfc_CMD_IEEE_TX_t RF_cmdIeeeTx; + +#endif /* IEEE_SETTINGS_H_ */ diff --git a/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.c b/arch/cpu/simplelink/rf-settings/rf-prop-settings.c similarity index 94% rename from arch/cpu/simplelink/rf-settings/proprietary-rf-settings.c rename to arch/cpu/simplelink/rf-settings/rf-prop-settings.c index 40bca3458..2307acffb 100644 --- a/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.c +++ b/arch/cpu/simplelink/rf-settings/rf-prop-settings.c @@ -34,11 +34,11 @@ #include DeviceFamily_constructPath(rf_patches/rf_patch_cpe_prop.h) #include DeviceFamily_constructPath(rf_patches/rf_patch_rfe_genfsk.h) #include DeviceFamily_constructPath(rf_patches/rf_patch_mce_genfsk.h) -#include "proprietary-rf-settings.h" -#include "contiki.h" -#include "dev/radio.h" -#include +#include +#include + +#include "rf-core.h" /*---------------------------------------------------------------------------*/ /** @@ -52,7 +52,7 @@ /*---------------------------------------------------------------------------*/ /* Default TX power settings for the 779-930MHz band */ -const prop_mode_tx_power_config_t prop_mode_tx_power_779_930[] = { +RF_TxPower RF_propTxPower779_930[] = { { 14, 0xa73f }, { 13, 0xa63f }, /* 12.5 */ { 12, 0xb818 }, @@ -73,7 +73,7 @@ const prop_mode_tx_power_config_t prop_mode_tx_power_779_930[] = { }; /*---------------------------------------------------------------------------*/ /* Default TX power settings for the 431-527MHz band */ -const prop_mode_tx_power_config_t prop_mode_tx_power_431_527[] = { +RF_TxPower RF_propTxPower431_527[] = { { 15, 0x003f }, { 14, 0xbe3f }, /* 13.7 */ { 13, 0x6a0f }, @@ -87,7 +87,7 @@ const prop_mode_tx_power_config_t prop_mode_tx_power_431_527[] = { */ // TI-RTOS RF Mode Object -RF_Mode RF_prop = +RF_Mode RF_propMode = { .rfMode = RF_MODE_AUTO, .cpePatchFxn = &rf_patch_cpe_prop, @@ -136,7 +136,7 @@ static uint32_t pOverrides[] = // CMD_PROP_RADIO_DIV_SETUP // Proprietary Mode Radio Setup Command for All Frequency Bands -rfc_CMD_PROP_RADIO_DIV_SETUP_t smartrf_settings_cmd_prop_radio_div_setup = +rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup = { .commandNo = 0x3807, .status = 0x0000, @@ -175,7 +175,7 @@ rfc_CMD_PROP_RADIO_DIV_SETUP_t smartrf_settings_cmd_prop_radio_div_setup = // CMD_FS // Frequency Synthesizer Programming Command -rfc_CMD_FS_t smartrf_settings_cmd_prop_fs = +rfc_CMD_FS_t rf_cmd_prop_fs = { .commandNo = 0x0803, .status = 0x0000, @@ -198,7 +198,7 @@ rfc_CMD_FS_t smartrf_settings_cmd_prop_fs = }; /* CMD_PROP_TX_ADV */ -rfc_CMD_PROP_TX_ADV_t smartrf_settings_cmd_prop_tx_adv = +rfc_CMD_PROP_TX_ADV_t rf_cmd_prop_tx_adv = { .commandNo = 0x3803, .status = 0x0000, @@ -229,7 +229,7 @@ rfc_CMD_PROP_TX_ADV_t smartrf_settings_cmd_prop_tx_adv = }; /*---------------------------------------------------------------------------*/ /* CMD_PROP_RX_ADV */ -rfc_CMD_PROP_RX_ADV_t smartrf_settings_cmd_prop_rx_adv = +rfc_CMD_PROP_RX_ADV_t rf_cmd_prop_rx_adv = { .commandNo = 0x3804, .status = 0x0000, diff --git a/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.h b/arch/cpu/simplelink/rf-settings/rf-prop-settings.h similarity index 56% rename from arch/cpu/simplelink/rf-settings/proprietary-rf-settings.h rename to arch/cpu/simplelink/rf-settings/rf-prop-settings.h index f01ae3498..d0ac01ff3 100644 --- a/arch/cpu/simplelink/rf-settings/proprietary-rf-settings.h +++ b/arch/cpu/simplelink/rf-settings/rf-prop-settings.h @@ -1,5 +1,5 @@ -#ifndef _PROPRIETARY_RF_SETTINGS_H_ -#define _PROPRIETARY_RF_SETTINGS_H_ +#ifndef RF_PROP_SETTINGS_H_ +#define RF_PROP_SETTINGS_H_ //********************************************************************************* // Generated by SmartRF Studio version 2.8.0 ( build #41) @@ -13,15 +13,20 @@ #include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h) #include +#include + +// RF TX power table +extern RF_TxPower RF_propTxPower779_930[]; +extern RF_TxPower RF_propTxPower431_527[]; + // TI-RTOS RF Mode Object -extern RF_Mode RF_prop; +extern RF_Mode RF_propMode; // RF Core API commands -extern rfc_CMD_PROP_RADIO_DIV_SETUP_t smartrf_settings_cmd_prop_radio_div_setup; -extern rfc_CMD_FS_t smartrf_settings_cmd_prop_fs; -extern rfc_CMD_PROP_TX_ADV_t smartrf_settings_cmd_prop_tx_adv; -extern rfc_CMD_PROP_RX_ADV_t smartrf_settings_cmd_prop_rx_adv; +extern rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup; +extern rfc_CMD_FS_t rf_cmd_prop_fs; +extern rfc_CMD_PROP_TX_ADV_t rf_cmd_prop_tx_adv; +extern rfc_CMD_PROP_RX_ADV_t rf_cmd_prop_rx_adv; -#endif // _PROPRIETARY_RF_SETTINGS_H_ - +#endif /* RF_PROP_SETTINGS_H_ */ diff --git a/arch/platform/simplelink/platform.c b/arch/platform/simplelink/platform.c index 3647a6134..53cfcefb9 100644 --- a/arch/platform/simplelink/platform.c +++ b/arch/platform/simplelink/platform.c @@ -60,6 +60,7 @@ #include "leds.h" //#include "gpio-interrupt.h" #include "ieee-addr.h" +#include "dev/rf-core.h" #include "uart0-arch.h" #include "sys/clock.h" #include "sys/rtimer.h" From 5c058b9c528d70d0bb6f3037ad3788a40a482928 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Thu, 15 Feb 2018 12:48:02 +0100 Subject: [PATCH 238/485] Refactored after PR review --- arch/cpu/simplelink/Makefile.simplelink | 2 +- .../simplelink/dev/{rf-core.c => rf-common.c} | 36 ++++----- arch/cpu/simplelink/dev/rf-common.h | 80 +++++++++++++++++++ arch/cpu/simplelink/dev/rf-core.h | 37 --------- arch/cpu/simplelink/dev/rf-ieee-mode.c | 51 +++++++----- arch/cpu/simplelink/dev/rf-prop-mode.c | 42 ++++++---- arch/cpu/simplelink/dev/watchdog-arch.c | 5 -- .../simplelink/rf-settings/rf-ieee-settings.c | 5 +- .../simplelink/rf-settings/rf-ieee-settings.h | 2 +- .../simplelink/rf-settings/rf-prop-settings.c | 5 +- .../simplelink/rf-settings/rf-prop-settings.h | 2 +- arch/platform/simplelink/platform.c | 65 +++++++-------- 12 files changed, 187 insertions(+), 145 deletions(-) rename arch/cpu/simplelink/dev/{rf-core.c => rf-common.c} (81%) create mode 100644 arch/cpu/simplelink/dev/rf-common.h delete mode 100644 arch/cpu/simplelink/dev/rf-core.h diff --git a/arch/cpu/simplelink/Makefile.simplelink b/arch/cpu/simplelink/Makefile.simplelink index 266565bdb..0f8765d44 100644 --- a/arch/cpu/simplelink/Makefile.simplelink +++ b/arch/cpu/simplelink/Makefile.simplelink @@ -65,7 +65,7 @@ CONTIKI_CPU_DIRS += dev rf-settings CONTIKI_CPU_SOURCEFILES += rtimer-arch.c clock-arch.c CONTIKI_CPU_SOURCEFILES += watchdog-arch.c putchar-arch.c CONTIKI_CPU_SOURCEFILES += uart0-arch.c -CONTIKI_CPU_SOURCEFILES += rf-core.c +CONTIKI_CPU_SOURCEFILES += rf-common.c CONTIKI_CPU_SOURCEFILES += rf-prop-mode.c rf-prop-settings.c CONTIKI_CPU_SOURCEFILES += rf-ieee-mode.c rf-ieee-settings.c CONTIKI_CPU_SOURCEFILES += ieee-addr.c diff --git a/arch/cpu/simplelink/dev/rf-core.c b/arch/cpu/simplelink/dev/rf-common.c similarity index 81% rename from arch/cpu/simplelink/dev/rf-core.c rename to arch/cpu/simplelink/dev/rf-common.c index 232cffb86..e4538e53b 100644 --- a/arch/cpu/simplelink/dev/rf-core.c +++ b/arch/cpu/simplelink/dev/rf-common.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,24 +29,20 @@ */ /*---------------------------------------------------------------------------*/ /** - * \addtogroup rf-core + * \addtogroup simplelink * @{ * * \file - * Implementation of the CC13xx/CC26xx RF core driver + * Implementation of common CC13xx/CC26xx RF functionality */ /*---------------------------------------------------------------------------*/ -#include "contiki.h" -#include "dev/watchdog.h" -#include "sys/process.h" -#include "sys/clock.h" -#include "sys/ctimer.h" -#include "sys/energest.h" -#include "sys/cc.h" -#include "net/netstack.h" -#include "net/packetbuf.h" -/*---------------------------------------------------------------------------*/ -#include +#include +#include +#include +#include +#include +#include +#include /*---------------------------------------------------------------------------*/ #include #include @@ -54,14 +50,12 @@ #include #include /*---------------------------------------------------------------------------*/ -#define DEBUG 0 -#if DEBUG -#define PRINTF(...) printf(__VA_ARGS__) -#else -#define PRINTF(...) -#endif +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "RF common" +#define LOG_LEVEL LOG_LEVEL_DBG /*---------------------------------------------------------------------------*/ -PROCESS(RF_coreProcess, "SimpleLink RF driver"); +PROCESS(RF_coreProcess, "SimpleLink RF process"); /*---------------------------------------------------------------------------*/ PROCESS_THREAD(RF_coreProcess, ev, data) { diff --git a/arch/cpu/simplelink/dev/rf-common.h b/arch/cpu/simplelink/dev/rf-common.h new file mode 100644 index 000000000..cd646064f --- /dev/null +++ b/arch/cpu/simplelink/dev/rf-common.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup simplelink + * @{ + * + * \defgroup rf-common Common functionality fpr the CC13xx/CC26xx RF + * + * @{ + * + * \file + * Header file of common CC13xx/CC26xx RF functionality + */ +/*---------------------------------------------------------------------------*/ +#ifndef RF_COMMON_H_ +#define RF_COMMON_H_ +/*---------------------------------------------------------------------------*/ +/* Contiki API */ +#include +#include +/*---------------------------------------------------------------------------*/ +/* Standard library */ +#include +/*---------------------------------------------------------------------------*/ +#ifdef RF_CORE_CONF_CHANNEL +# define RF_CORE_CHANNEL RF_CORE_CONF_CHANNEL +#else +# define RF_CORE_CHANNEL 25 +#endif +/*---------------------------------------------------------------------------*/ +typedef enum { + CMD_RESULT_ERROR = 0, + CMD_RESULT_OK = 1, +} CmdResult; +/*---------------------------------------------------------------------------*/ +typedef struct { + radio_value_t dbm; + uint16_t power; ///< Value for the .txPower field +} RF_TxPower; + +#define TX_POWER_UNKNOWN 0xFFFF +/*---------------------------------------------------------------------------*/ +#define RSSI_UNKNOWN -128 +/*---------------------------------------------------------------------------*/ +PROCESS_NAME(RF_coreProcess); +/*---------------------------------------------------------------------------*/ +#endif /* RF_COMMON_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/cpu/simplelink/dev/rf-core.h b/arch/cpu/simplelink/dev/rf-core.h deleted file mode 100644 index 02e882f66..000000000 --- a/arch/cpu/simplelink/dev/rf-core.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef CONTIKI_NG_ARCH_CPU_SIMPLELINK_DEV_RF_CORE_H_ -#define CONTIKI_NG_ARCH_CPU_SIMPLELINK_DEV_RF_CORE_H_ - -/*---------------------------------------------------------------------------*/ -/* Contiki API */ -#include -#include -/*---------------------------------------------------------------------------*/ -#include -/*---------------------------------------------------------------------------*/ -/* Standard library */ -#include -/*---------------------------------------------------------------------------*/ -#ifdef RF_CORE_CONF_CHANNEL -# define RF_CORE_CHANNEL RF_CORE_CONF_CHANNEL -#else -# define RF_CORE_CHANNEL 25 -#endif -/*---------------------------------------------------------------------------*/ -typedef enum { - CMD_ERROR = 0, - CMD_OK = 1, -} CmdResult; -/*---------------------------------------------------------------------------*/ -typedef struct { - radio_value_t dbm; - uint16_t power; /* Value for the PROP_DIV_RADIO_SETUP.txPower field */ -} RF_TxPower; - -#define TX_POWER_UNKNOWN 0xFFFF -/*---------------------------------------------------------------------------*/ -#define RSSI_UNKNOWN -128 -/*---------------------------------------------------------------------------*/ -PROCESS_NAME(RF_coreProcess); -/*---------------------------------------------------------------------------*/ - -#endif /* CONTIKI_NG_ARCH_CPU_SIMPLELINK_DEV_RF_CORE_H_ */ diff --git a/arch/cpu/simplelink/dev/rf-ieee-mode.c b/arch/cpu/simplelink/dev/rf-ieee-mode.c index f3686505c..d80af6d1e 100644 --- a/arch/cpu/simplelink/dev/rf-ieee-mode.c +++ b/arch/cpu/simplelink/dev/rf-ieee-mode.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -57,10 +57,19 @@ #include #include #include -#include +/*---------------------------------------------------------------------------*/ +/* RF settings */ +#ifdef IEEE_MODE_CONF_RF_SETTINGS +# define IEEE_MODE_RF_SETTINGS IEEE_MODE_CONF_RF_SETTINGS +# undef IEEE_MODE_CONF_RF_SETTINGS +#else +# define IEEE_MODE_RF_SETTINGS "rf-settings/rf-ieee-settings.h" +#endif + +#include IEEE_MODE_RF_SETTINGS /*---------------------------------------------------------------------------*/ /* Simplelink Platform RF dev */ -#include "rf-core.h" +#include "rf-common.h" #include "dot-15-4g.h" /*---------------------------------------------------------------------------*/ #include @@ -389,7 +398,7 @@ set_tx_power(const radio_value_t dbm) } if (!g_pCurrTxPower) { - return CMD_ERROR; + return CMD_RESULT_ERROR; } rfc_CMD_SET_TX_POWER_t cmdSetTxPower = { @@ -400,9 +409,9 @@ set_tx_power(const radio_value_t dbm) const RF_Stat stat = RF_runImmediateCmd(g_rfHandle, (uint32_t*)&cmdSetTxPower); if (stat != RF_StatCmdDoneSuccess) { PRINTF("set_tx_power: stat=0x%02X\n", stat); - return CMD_ERROR; + return CMD_RESULT_ERROR; } - return CMD_OK; + return CMD_RESULT_OK; } /*---------------------------------------------------------------------------*/ static radio_value_t @@ -497,7 +506,7 @@ init(void) process_start(&RF_coreProcess, NULL); - return CMD_OK; + return CMD_RESULT_OK; } /*---------------------------------------------------------------------------*/ static int @@ -530,14 +539,14 @@ set_rx(const PowerState state) if (stat != RF_StatSuccess) { PRINTF("set_rx(off): unable to cancel RX\n"); - return CMD_ERROR; + return CMD_RESULT_ERROR; } } if (state == POWER_STATE_ON || state == POWER_STATE_RESTART) { if (g_vpCmdRx->status == ACTIVE) { PRINTF("set_rx(on): already in RX\n"); - return CMD_OK; + return CMD_RESULT_OK; } RF_ScheduleCmdParams schedParams = { @@ -550,11 +559,11 @@ set_rx(const PowerState state) g_cmdRxHandle = RF_scheduleCmd(g_rfHandle, (RF_Op*)g_vpCmdRx, &schedParams, NULL, 0); if ((g_cmdTxHandle == RF_ALLOC_ERROR) || (g_cmdTxHandle == RF_SCHEDULE_CMD_ERROR)) { PRINTF("transmit: unable to allocate RX command\n"); - return CMD_ERROR; + return CMD_RESULT_ERROR; } } - return CMD_OK; + return CMD_RESULT_OK; } /*---------------------------------------------------------------------------*/ static int @@ -698,7 +707,7 @@ channel_clear_aux(void) const RF_Stat stat = RF_runImmediateCmd(g_rfHandle, (uint32_t*)&RF_cmdIeeeCaaReq); if (stat != RF_StatCmdDoneSuccess) { PRINTF("channel_clear: CCA request failed stat=0x%02X\n", stat); - return CMD_ERROR; + return CMD_RESULT_ERROR; } // Channel is clear if CCA state is idle (0) or invalid (2), i.e. not busy (1) @@ -709,7 +718,7 @@ static int channel_clear(void) { const bool was_rx = (g_vpCmdRx->status == ACTIVE); - if (!was_rx && set_rx(POWER_STATE_ON) != CMD_OK) { + if (!was_rx && set_rx(POWER_STATE_ON) != CMD_RESULT_OK) { PRINTF("channel_clear: unable to start RX\n"); return CHANNEL_CLEAR_ERROR; } @@ -809,7 +818,7 @@ off(void) } } - return CMD_OK; + return CMD_RESULT_OK; } /*---------------------------------------------------------------------------*/ static radio_result_t @@ -905,7 +914,7 @@ set_value(radio_param_t param, radio_value_t value) case RADIO_PARAM_POWER_MODE: switch (value) { case RADIO_POWER_MODE_ON: - if (on() != CMD_OK) { + if (on() != CMD_RESULT_OK) { PRINTF("set_value: on() failed (1)\n"); return RADIO_RESULT_ERROR; } @@ -928,7 +937,7 @@ set_value(radio_param_t param, radio_value_t value) case RADIO_PARAM_PAN_ID: g_vpCmdRx->localPanID = (uint16_t)value; - if (rf_is_on() && set_rx(POWER_STATE_RESTART) != CMD_OK) { + if (rf_is_on() && set_rx(POWER_STATE_RESTART) != CMD_RESULT_OK) { PRINTF("failed to restart RX"); return RADIO_RESULT_ERROR; } @@ -936,7 +945,7 @@ set_value(radio_param_t param, radio_value_t value) case RADIO_PARAM_16BIT_ADDR: g_vpCmdRx->localShortAddr = (uint16_t)value; - if (rf_is_on() && set_rx(POWER_STATE_RESTART) != CMD_OK) { + if (rf_is_on() && set_rx(POWER_STATE_RESTART) != CMD_RESULT_OK) { PRINTF("failed to restart RX"); return RADIO_RESULT_ERROR; } @@ -970,7 +979,7 @@ set_value(radio_param_t param, radio_value_t value) } return RADIO_RESULT_OK; } - if (rf_is_on() && set_rx(POWER_STATE_RESTART) != CMD_OK) { + if (rf_is_on() && set_rx(POWER_STATE_RESTART) != CMD_RESULT_OK) { PRINTF("failed to restart RX"); return RADIO_RESULT_ERROR; } @@ -988,13 +997,13 @@ set_value(radio_param_t param, radio_value_t value) if(value < TX_POWER_MIN.dbm || value > TX_POWER_MAX.dbm) { return RADIO_RESULT_INVALID_VALUE; } - return (set_tx_power(value) != CMD_OK) + return (set_tx_power(value) != CMD_RESULT_OK) ? RADIO_RESULT_ERROR : RADIO_RESULT_OK; case RADIO_PARAM_CCA_THRESHOLD: g_vpCmdRx->ccaRssiThr = (int8_t)value; - if (rf_is_on() && set_rx(POWER_STATE_RESTART) != CMD_OK) { + if (rf_is_on() && set_rx(POWER_STATE_RESTART) != CMD_RESULT_OK) { PRINTF("failed to restart RX"); return RADIO_RESULT_ERROR; } @@ -1062,7 +1071,7 @@ set_object(radio_param_t param, const void *src, size_t size) } const bool is_rx = (g_vpCmdRx->status == ACTIVE); - if (is_rx && set_rx(POWER_STATE_RESTART) != CMD_OK) { + if (is_rx && set_rx(POWER_STATE_RESTART) != CMD_RESULT_OK) { return RADIO_RESULT_ERROR; } return RADIO_RESULT_OK; diff --git a/arch/cpu/simplelink/dev/rf-prop-mode.c b/arch/cpu/simplelink/dev/rf-prop-mode.c index 375b79554..f1cc3c2e9 100644 --- a/arch/cpu/simplelink/dev/rf-prop-mode.c +++ b/arch/cpu/simplelink/dev/rf-prop-mode.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -52,10 +52,20 @@ #include #include #include -#include +/*---------------------------------------------------------------------------*/ +/* RF settings */ +/* RF settings */ +#ifdef PROP_MODE_CONF_RF_SETTINGS +# define PROP_MODE_RF_SETTINGS PROP_MODE_CONF_RF_SETTINGS +# undef PROP_MODE_CONF_RF_SETTINGS +#else +# define PROP_MODE_RF_SETTINGS "rf-settings/rf-prop-settings.h" +#endif + +#include PROP_MODE_RF_SETTINGS /*---------------------------------------------------------------------------*/ /* Platform RF dev */ -#include "rf-core.h" +#include "rf-common.h" #include "dot-15-4g.h" /*---------------------------------------------------------------------------*/ #include @@ -246,7 +256,7 @@ rf_start_rx() RF_CmdHandle rxCmdHandle = RF_postCmd(rfHandle, (RF_Op*)gvp_cmd_rx_adv, RF_PriorityNormal, &rf_rx_callback, RF_EventRxEntryDone); if (rxCmdHandle == RF_ALLOC_ERROR) { - return CMD_ERROR; + return CMD_RESULT_ERROR; } /* Wait to enter RX */ @@ -258,10 +268,10 @@ rf_start_rx() PRINTF("RF_cmdPropRxAdv: handle=0x%08lx, status=0x%04x\n", (unsigned long)rxCmdHandle, gvp_cmd_rx_adv->status); rf_switch_off(); - return CMD_ERROR; + return CMD_RESULT_ERROR; } - return CMD_OK; + return CMD_RESULT_OK; } /*---------------------------------------------------------------------------*/ static CmdResult @@ -269,7 +279,7 @@ rf_stop_rx(void) { /* If we are off, do nothing */ if (!rf_is_receiving()) { - return CMD_OK; + return CMD_RESULT_OK; } /* Abort any ongoing operation. Don't care about the result. */ @@ -281,12 +291,12 @@ rf_stop_rx(void) gvp_cmd_rx_adv->status != PROP_DONE_ABORT) { PRINTF("RF_cmdPropRxAdv cancel: status=0x%04x\n", gvp_cmd_rx_adv->status); - return CMD_ERROR; + return CMD_RESULT_ERROR; } /* Stopped gracefully */ ENERGEST_OFF(ENERGEST_TYPE_LISTEN); - return CMD_OK; + return CMD_RESULT_OK; } /*---------------------------------------------------------------------------*/ static CmdResult @@ -294,10 +304,10 @@ rf_run_setup() { RF_runCmd(rfHandle, (RF_Op*)gvp_cmd_radio_div_setup, RF_PriorityNormal, NULL, 0); if (gvp_cmd_radio_div_setup->status != PROP_DONE_OK) { - return CMD_ERROR; + return CMD_RESULT_ERROR; } - return CMD_OK; + return CMD_RESULT_OK; } /*---------------------------------------------------------------------------*/ static radio_value_t @@ -309,7 +319,7 @@ get_rssi(void) } const bool was_off = !rf_is_receiving(); - if (was_off && rf_start_rx() == CMD_ERROR) { + if (was_off && rf_start_rx() == CMD_RESULT_ERROR) { PRINTF("get_rssi: unable to start RX\n"); return RF_GET_RSSI_ERROR_VAL; } @@ -658,7 +668,7 @@ rf_switch_off(void) // * from within an interrupt context. Abort, but pretend everything is OK. // */ // if(rf_ble_is_active() == RF_BLE_ACTIVE) { -// return CMD_OK; +// return CMD_RESULT_OK; // } // Force abort of any ongoing RF operation. @@ -670,7 +680,7 @@ rf_switch_off(void) /* We pulled the plug, so we need to restore the status manually */ gvp_cmd_rx_adv->status = IDLE; - return CMD_OK; + return CMD_RESULT_OK; } /*---------------------------------------------------------------------------*/ static radio_result_t @@ -767,7 +777,7 @@ set_value(radio_param_t param, radio_value_t value) /* If we reach here we had no errors. Apply new settings */ if (rf_is_receiving()) { rf_stop_rx(); - if (rf_run_setup() != CMD_OK) { + if (rf_run_setup() != CMD_RESULT_OK) { return RADIO_RESULT_ERROR; } rf_start_rx(); @@ -826,7 +836,7 @@ rf_init(void) process_start(&RF_coreProcess, NULL); - return CMD_OK; + return CMD_RESULT_OK; } /*---------------------------------------------------------------------------*/ const struct radio_driver prop_mode_driver = { diff --git a/arch/cpu/simplelink/dev/watchdog-arch.c b/arch/cpu/simplelink/dev/watchdog-arch.c index 505570ccd..ac137e577 100644 --- a/arch/cpu/simplelink/dev/watchdog-arch.c +++ b/arch/cpu/simplelink/dev/watchdog-arch.c @@ -109,7 +109,6 @@ lock_config(uint32_t status) void watchdog_init(void) { - return; WatchdogReloadSet(CONTIKI_WATCHDOG_TIMER_TOP); lock_config(LOCK_REGISTERS_UNLOCKED); } @@ -120,7 +119,6 @@ watchdog_init(void) void watchdog_start(void) { - return; uint32_t lock_status = unlock_config(); watchdog_periodic(); @@ -135,7 +133,6 @@ watchdog_start(void) void watchdog_periodic(void) { - return; WatchdogReloadSet(CONTIKI_WATCHDOG_TIMER_TOP); WatchdogIntClear(); } @@ -146,7 +143,6 @@ watchdog_periodic(void) void watchdog_stop(void) { - return; uint32_t lock_status = unlock_config(); WatchdogResetDisable(); @@ -160,7 +156,6 @@ watchdog_stop(void) void watchdog_reboot(void) { - return; watchdog_start(); while(1); } diff --git a/arch/cpu/simplelink/rf-settings/rf-ieee-settings.c b/arch/cpu/simplelink/rf-settings/rf-ieee-settings.c index 85dda307d..1f7fea3d9 100644 --- a/arch/cpu/simplelink/rf-settings/rf-ieee-settings.c +++ b/arch/cpu/simplelink/rf-settings/rf-ieee-settings.c @@ -22,10 +22,7 @@ #include DeviceFamily_constructPath(rf_patches/rf_patch_cpe_ieee_802_15_4.h) #include DeviceFamily_constructPath(rf_patches/rf_patch_mce_ieee_802_15_4.h) -#include -#include - -#include "rf-core.h" +#include "rf-common.h" /*---------------------------------------------------------------------------*/ /* Default TX power settings for the 2.4 GHz band */ diff --git a/arch/cpu/simplelink/rf-settings/rf-ieee-settings.h b/arch/cpu/simplelink/rf-settings/rf-ieee-settings.h index 898c830cf..d3c973b48 100644 --- a/arch/cpu/simplelink/rf-settings/rf-ieee-settings.h +++ b/arch/cpu/simplelink/rf-settings/rf-ieee-settings.h @@ -8,7 +8,7 @@ #include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h) #include -#include +#include // RF TX power table extern RF_TxPower RF_ieeeTxPower[]; diff --git a/arch/cpu/simplelink/rf-settings/rf-prop-settings.c b/arch/cpu/simplelink/rf-settings/rf-prop-settings.c index 2307acffb..4deeca8d3 100644 --- a/arch/cpu/simplelink/rf-settings/rf-prop-settings.c +++ b/arch/cpu/simplelink/rf-settings/rf-prop-settings.c @@ -35,10 +35,7 @@ #include DeviceFamily_constructPath(rf_patches/rf_patch_rfe_genfsk.h) #include DeviceFamily_constructPath(rf_patches/rf_patch_mce_genfsk.h) -#include -#include - -#include "rf-core.h" +#include "rf-common.h" /*---------------------------------------------------------------------------*/ /** diff --git a/arch/cpu/simplelink/rf-settings/rf-prop-settings.h b/arch/cpu/simplelink/rf-settings/rf-prop-settings.h index d0ac01ff3..d897449ce 100644 --- a/arch/cpu/simplelink/rf-settings/rf-prop-settings.h +++ b/arch/cpu/simplelink/rf-settings/rf-prop-settings.h @@ -13,7 +13,7 @@ #include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h) #include -#include +#include // RF TX power table extern RF_TxPower RF_propTxPower779_930[]; diff --git a/arch/platform/simplelink/platform.c b/arch/platform/simplelink/platform.c index 53cfcefb9..e46077d42 100644 --- a/arch/platform/simplelink/platform.c +++ b/arch/platform/simplelink/platform.c @@ -45,35 +45,36 @@ * - The TI CC26X2R1 LaunchPad * @{ */ +/*---------------------------------------------------------------------------*/ +/* Simplelink SDK includes */ #include #include #include #include #include #include - +/*---------------------------------------------------------------------------*/ +/* Contiki API */ #include "contiki.h" #include "contiki-net.h" - -#include "uart0-arch.h" - -#include "leds.h" -//#include "gpio-interrupt.h" -#include "ieee-addr.h" -#include "dev/rf-core.h" -#include "uart0-arch.h" #include "sys/clock.h" #include "sys/rtimer.h" #include "sys/node-id.h" #include "sys/platform.h" +#include "dev/serial-line.h" +#include "net/mac/framer/frame802154.h" +/*---------------------------------------------------------------------------*/ +/* Arch driver implementations */ +#include "uart0-arch.h" +/*---------------------------------------------------------------------------*/ +#include "leds.h" +//#include "gpio-interrupt.h" +#include "ieee-addr.h" +#include "dev/rf-common.h" #include "lib/random.h" #include "lib/sensors.h" #include "button-sensor.h" -#include "dev/serial-line.h" -#include "net/mac/framer/frame802154.h" - -//#include "driverlib/driverlib_release.h" - +/*---------------------------------------------------------------------------*/ #include /*---------------------------------------------------------------------------*/ /* Log configuration */ @@ -81,7 +82,7 @@ #define LOG_MODULE "CC26xx/CC13xx" #define LOG_LEVEL LOG_LEVEL_MAIN /*---------------------------------------------------------------------------*/ -unsigned short node_id = 0; +unsigned short g_nodeId = 0; /*---------------------------------------------------------------------------*/ /** \brief Board specific initialization */ void board_init(void); @@ -90,9 +91,8 @@ static void fade(unsigned char l) { volatile int i; - int k, j; - for(k = 0; k < 800; ++k) { - j = k > 400 ? 800 - k : k; + for(int k = 0; k < 800; ++k) { + int j = k > 400 ? 800 - k : k; GPIO_write(l, Board_GPIO_LED_ON); for(i = 0; i < j; ++i) { @@ -111,7 +111,7 @@ set_rf_params(void) uint16_t short_addr; uint8_t ext_addr[8]; - ieee_addr_cpy_to(ext_addr, 8); + ieee_addr_cpy_to(ext_addr, sizeof(ext_addr)); short_addr = ext_addr[7]; short_addr |= ext_addr[6] << 8; @@ -119,20 +119,20 @@ 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_object(RADIO_PARAM_64BIT_ADDR, ext_addr, 8); + NETSTACK_RADIO.set_object(RADIO_PARAM_64BIT_ADDR, ext_addr, sizeof(ext_addr)); /* also set the global node id */ - node_id = short_addr; + g_nodeId = short_addr; } /*---------------------------------------------------------------------------*/ void platform_init_stage_one() { - Board_initGeneral(); - GPIO_init(); + Board_initGeneral(); + GPIO_init(); // Only enables interrupts - NoRTOS_start(); + NoRTOS_start(); // /* Enable flash cache and prefetch. */ // ti_lib_vims_mode_set(VIMS_BASE, VIMS_MODE_ENABLED); @@ -169,15 +169,14 @@ platform_init_stage_one() void platform_init_stage_two() { - uart0_init(); + uart0_init(); + serial_line_init(); // random_init(0x1234); -// -// serial_line_init(); -// + /* Populate linkaddr_node_addr */ ieee_addr_cpy_to(linkaddr_node_addr.u8, LINKADDR_SIZE); -// + fade(Board_GPIO_LED0); } /*---------------------------------------------------------------------------*/ @@ -200,7 +199,7 @@ platform_init_stage_three() ChipInfo_SupportsBLE() ? "Yes" : "No", ChipInfo_SupportsPROPRIETARY() ? "Yes" : "No"); LOG_INFO(" RF: Channel %d, PANID 0x%04X\n", chan, pan); - LOG_INFO(" Node ID: %d\n", node_id); + LOG_INFO(" Node ID: %d\n", g_nodeId); // // process_start(&sensors_process, NULL); fade(Board_GPIO_LED1); @@ -209,10 +208,8 @@ platform_init_stage_three() void platform_idle() { - /* Drop to some low power mode */ -// lpm_drop(); - - Power_idleFunc(); + // Drop to some low power mode + Power_idleFunc(); } /*---------------------------------------------------------------------------*/ /** From 723e59264c65d1bb6ff662c70c5051fc3f170679 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Thu, 15 Feb 2018 12:51:15 +0100 Subject: [PATCH 239/485] Added TX power table sizes for RF-prop settings --- arch/cpu/simplelink/rf-settings/rf-prop-settings.c | 2 ++ arch/cpu/simplelink/rf-settings/rf-prop-settings.h | 3 +++ 2 files changed, 5 insertions(+) diff --git a/arch/cpu/simplelink/rf-settings/rf-prop-settings.c b/arch/cpu/simplelink/rf-settings/rf-prop-settings.c index 4deeca8d3..2c654cf24 100644 --- a/arch/cpu/simplelink/rf-settings/rf-prop-settings.c +++ b/arch/cpu/simplelink/rf-settings/rf-prop-settings.c @@ -68,6 +68,7 @@ RF_TxPower RF_propTxPower779_930[] = { { -10, 0x08c0 }, {-128, 0xFFFF }, }; +const size_t RF_propTxPower779_930Size = sizeof(RF_propTxPower779_930) / sizeof(RF_propTxPower779_930[0]); /*---------------------------------------------------------------------------*/ /* Default TX power settings for the 431-527MHz band */ RF_TxPower RF_propTxPower431_527[] = { @@ -78,6 +79,7 @@ RF_TxPower RF_propTxPower431_527[] = { { 6, 0x22c4 }, {-128, 0xFFFF }, }; +const size_t RF_propTxPower431_527Size = sizeof(RF_propTxPower431_527) / sizeof(RF_propTxPower431_527[0]); /*---------------------------------------------------------------------------*/ /** * @} diff --git a/arch/cpu/simplelink/rf-settings/rf-prop-settings.h b/arch/cpu/simplelink/rf-settings/rf-prop-settings.h index d897449ce..947c5254e 100644 --- a/arch/cpu/simplelink/rf-settings/rf-prop-settings.h +++ b/arch/cpu/simplelink/rf-settings/rf-prop-settings.h @@ -17,7 +17,10 @@ // RF TX power table extern RF_TxPower RF_propTxPower779_930[]; +extern const size_t RF_propTxPower779_930Size; + extern RF_TxPower RF_propTxPower431_527[]; +extern const size_t RF_propTxPower431_527Size; // TI-RTOS RF Mode Object extern RF_Mode RF_propMode; From 6007b1be078abc8d72d08fc0827169b8883eb1be Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Thu, 15 Feb 2018 15:39:18 +0100 Subject: [PATCH 240/485] Implemented the Contiki leds driver NB! This is by no means a future-proof implementation. However, it should be a good starting point. Configuration of the LEDS_ARCH_* defines in the leds-arch.c file is what determines what LEDs are available of a given device/target. This information should be sufficient from the Board file/device name, and can from there hardcod what board+device combination a given LED should support. --- arch/platform/simplelink/Makefile.simplelink | 55 +++++++- arch/platform/simplelink/common/leds-arch.c | 134 +++++++++++++++++++ arch/platform/simplelink/platform.c | 34 ++--- 3 files changed, 200 insertions(+), 23 deletions(-) create mode 100644 arch/platform/simplelink/common/leds-arch.c diff --git a/arch/platform/simplelink/Makefile.simplelink b/arch/platform/simplelink/Makefile.simplelink index bed4c64a5..024ca6087 100644 --- a/arch/platform/simplelink/Makefile.simplelink +++ b/arch/platform/simplelink/Makefile.simplelink @@ -8,22 +8,65 @@ ifndef SIMPLELINK_SDK $(error SIMPLELINK_SDK not defined! You must specify where the SimpleLink SDK resides!) endif -AVAILABLE_BOARDS := $(shell ls $(SIMPLELINK_SDK)/source/ti/boards/) -AVAILABLE_BOARDS += CUSTOM # Allows an own board file in the application project +# Hacky way to emulate line breaks in warnings/errors +# https://stackoverflow.com/questions/17055773/how-to-synthesize-line-breaks-in-gnu-make-warnings-or-errors +define n + + +endef + +# List of all Simplelink SDKs the Contiki Simplelink platform supports +# with the format "simplelink__sdk". Don't add the version. +# Simply adding a new entry with the name of a new SDK should be enough when +# the necessary implementaitons have been made. +SUPPORTED_SDKS = \ + simplelink_cc13x0_sdk \ + simplelink_cc13x2_sdk \ + simplelink_cc26x0_sdk \ + simplelink_cc26x2_sdk \ + simplelink_cc2640r2_sdk \ + +# The Simplelink SDK name extracted from the file path. +# e.g. C:/ti/simplelink_cc13x0_sdk_1_60_00_21 => simplelink_cc13x0_sdk_1_60_00_21 +SDK_NAME := $(notdir $(SIMPLELINK_SDK)) +# The stripped name from the Simplelink SDK, i.e. without version number. +# e.g. simplelink_cc13x0_sdk_1_60_00_21 => simplelink_cc13x0_sdk +# Note that the first grep verifies the SDK name is on a valid format, +# and the second grep extracts the stripped name +SDK_NAME_STRIPPED := $(shell echo "$(SDK_NAME)" \ + | grep -Po "simplelink_.*?_sdk_[0-9_]+" \ + | grep -Po "simplelink_.*?_sdk") + +# Verify a valid Simplelink SDK has been supplied. +# Format is "simplelink__sdk_" +ifeq (,$(SDK_NAME_STRIPPED)) + $(error Supplied Simplelink SDK '$(SDK_NAME)' is not valid.$nFormat is "simplelink__sdk_") +endif + +# Verify a supported Simplelink SDK has been supplied, else print all supported SDKs +ifeq (,$(findstring $(SDK_NAME_STRIPPED), $(SUPPORTED_SDKS))) + $(error Simplelink SDK '$(SDK_NAME)' is not supported.$nSupported SDKs:$n $(foreach sdk, $(SUPPORTED_SDKS), $(sdk)_$n)) +endif + +# Find all available boards from the '/source/ti/boards directory' +AVAILABLE_BOARDS := $(shell ls -d $(SIMPLELINK_SDK)/source/ti/boards/*) +# Also allow a custom board file in the application project +AVAILABLE_BOARDS += CUSTOM ifndef SIMPLELINK_BOARD - $(error SIMPLELINK_BOARD not defined! You must specify a board! Available boards: $(AVAILABLE_BOARDS)) + $(error SIMPLELINK_BOARD not defined. You must specify a board!$nAvailable boards:$n $(foreach board, $(AVAILABLE_BOARDS), $(board)$n)) endif ifneq ($(findstring $(SIMPLELINK_BOARD),$(AVAILABLE_BOARDS)),$(SIMPLELINK_BOARD)) - $(error '$(SIMPLELINK_BOARD)' is not a valid board. Available boards: $(AVAILABLE_BOARDS)) + $(error Board '$(SIMPLELINK_BOARD)' is not valid for the given Simplelink SDK '$(SDK_NAME)'.$nAvailable boards:$n $(foreach board, $(AVAILABLE_BOARDS), $(board)$n)) endif ### Board and BSP selection -CONTIKI_TARGET_DIRS += . +CONTIKI_TARGET_DIRS += . common CONTIKI_TARGET_SOURCEFILES += platform.c +CONTIKI_TARGET_SOURCEFILES += leds-arch.c CONTIKI_SOURCEFILES += $(CONTIKI_TARGET_SOURCEFILES) @@ -35,7 +78,7 @@ SMALL ?= 0 CONTIKI_CPU = $(CONTIKI)/arch/cpu/simplelink include $(CONTIKI_CPU)/Makefile.simplelink -#MODULES += os/net os/net/mac os/net/mac/framer +MODULES += os/net os/net/mac os/net/mac/framer diff --git a/arch/platform/simplelink/common/leds-arch.c b/arch/platform/simplelink/common/leds-arch.c new file mode 100644 index 000000000..7595d47d3 --- /dev/null +++ b/arch/platform/simplelink/common/leds-arch.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup simplelink-platform + * @{ + * + * \file + * Driver for LaunchPad LEDs + */ +/*---------------------------------------------------------------------------*/ +/* Contiki API */ +#include +#include +/*---------------------------------------------------------------------------*/ +/* Simplelink SDK API */ +#include +#include +/*---------------------------------------------------------------------------*/ +/* Standard library */ +#include +#include +/*---------------------------------------------------------------------------*/ +/* Available LED configuration */ + +/* Green LED */ +#ifdef Board_GPIO_GLED +# define LEDS_ARCH_GREEN Board_GPIO_GLED +#endif + +/* Yellow LED */ +#ifdef Board_GPIO_YLED +# define LEDS_ARCH_YELLOW Board_GPIO_YLED +#endif + +/* Red LED */ +#ifdef Board_GPIO_RLED +# define LEDS_ARCH_RED Board_GPIO_RLED +#endif + +/* Blue LED */ +#ifdef Board_GPIO_BLED +# define LEDS_ARCH_BLUE Board_GPIO_BLED +#endif +/*---------------------------------------------------------------------------*/ +static unsigned char c; +/*---------------------------------------------------------------------------*/ +void +leds_arch_init(void) +{ + static bool bHasInit = false; + if(bHasInit) { + return; + } + bHasInit = true; + + // GPIO_init will most likely be called in platform.c, + // but call it here to be sure GPIO is initialized. + // Calling GPIO_init multiple times is safe. + GPIO_init(); +} +/*---------------------------------------------------------------------------*/ +unsigned char +leds_arch_get(void) +{ + return c; +} +/*---------------------------------------------------------------------------*/ +static inline void +write_led(const bool on, const uint_fast32_t gpioLed) +{ + const GPIO_PinConfig pinCfg = (on) + ? Board_GPIO_LED_ON : Board_GPIO_LED_OFF; + GPIO_write(gpioLed, pinCfg); +} +/*---------------------------------------------------------------------------*/ +void +leds_arch_set(unsigned char leds) +{ + c = leds; + +#define LED_ON(led_define) ((leds & (led_define)) == (led_define)) + + // Green LED +#ifdef LEDS_ARCH_GREEN + write_led(LED_ON(LEDS_GREEN), LEDS_ARCH_GREEN); +#endif + + // Yellow LED +#ifdef LEDS_ARCH_YELLOW + write_led(LED_ON(LEDS_YELLOW), LEDS_ARCH_YELLOW); +#endif + + // Red LED +#ifdef LEDS_ARCH_RED + write_led(LED_ON(LEDS_RED), LEDS_ARCH_RED); +#endif + + // Blue LED +#ifdef LEDS_ARCH_BLUE + write_led(LED_ON(LEDS_BLUE), LEDS_ARCH_BLUE); +#endif + +#undef LED_ON +} +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/platform.c b/arch/platform/simplelink/platform.c index e46077d42..6547de1bd 100644 --- a/arch/platform/simplelink/platform.c +++ b/arch/platform/simplelink/platform.c @@ -52,6 +52,8 @@ #include #include #include +#include +#include #include /*---------------------------------------------------------------------------*/ /* Contiki API */ @@ -62,12 +64,12 @@ #include "sys/node-id.h" #include "sys/platform.h" #include "dev/serial-line.h" +#include "dev/leds.h" #include "net/mac/framer/frame802154.h" /*---------------------------------------------------------------------------*/ /* Arch driver implementations */ #include "uart0-arch.h" /*---------------------------------------------------------------------------*/ -#include "leds.h" //#include "gpio-interrupt.h" #include "ieee-addr.h" #include "dev/rf-common.h" @@ -94,11 +96,11 @@ fade(unsigned char l) for(int k = 0; k < 800; ++k) { int j = k > 400 ? 800 - k : k; - GPIO_write(l, Board_GPIO_LED_ON); + leds_on(l); for(i = 0; i < j; ++i) { __asm("nop"); } - GPIO_write(l, Board_GPIO_LED_OFF); + leds_off(l); for(i = 0; i < 400 - j; ++i) { __asm("nop"); } @@ -128,16 +130,19 @@ set_rf_params(void) void platform_init_stage_one() { + // Enable flash cache + VIMSModeSet(VIMS_BASE, VIMS_MODE_ENABLED); + // Configure round robin arbitration and prefetching + VIMSConfigure(VIMS_BASE, true, true); + Board_initGeneral(); GPIO_init(); - // Only enables interrupts + // NoRTOS_start only enables HWI NoRTOS_start(); -// /* Enable flash cache and prefetch. */ -// ti_lib_vims_mode_set(VIMS_BASE, VIMS_MODE_ENABLED); -// ti_lib_vims_configure(VIMS_BASE, true, true); -// + leds_init(); + // ti_lib_int_master_disable(); // // /* Set the LF XOSC as the LF system clock source */ @@ -145,12 +150,7 @@ platform_init_stage_one() // // lpm_init(); // -// board_init(); -// -// gpio_interrupt_init(); -// -// leds_init(); - fade(Board_GPIO_LED0); + fade(LEDS_RED); // // /* // * Disable I/O pad sleep mode and open I/O latches in the AON IOC interface @@ -163,7 +163,7 @@ platform_init_stage_one() // ti_lib_int_master_enable(); // // soc_rtc_init(); - fade(Board_GPIO_LED1); + fade(LEDS_GREEN); } /*---------------------------------------------------------------------------*/ void @@ -177,7 +177,7 @@ platform_init_stage_two() /* Populate linkaddr_node_addr */ ieee_addr_cpy_to(linkaddr_node_addr.u8, LINKADDR_SIZE); - fade(Board_GPIO_LED0); + fade(LEDS_RED); } /*---------------------------------------------------------------------------*/ void @@ -202,7 +202,7 @@ platform_init_stage_three() LOG_INFO(" Node ID: %d\n", g_nodeId); // // process_start(&sensors_process, NULL); - fade(Board_GPIO_LED1); + fade(LEDS_GREEN); } /*---------------------------------------------------------------------------*/ void From 7e96029211197f39e47671f308e75e51d1280d62 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Fri, 16 Feb 2018 16:55:39 +0100 Subject: [PATCH 241/485] Initial try of structuring platform dependent code --- arch/cpu/simplelink/Makefile.cc26x2_cc13x2 | 6 - arch/cpu/simplelink/dev/rf-ieee-mode.c | 20 +- .../simplelink/rf-settings/rf-ieee-settings.c | 2 + .../simplelink/Makefile.device-family | 33 ++ arch/platform/simplelink/Makefile.simplelink | 28 +- .../cc13x0_cc26x0/Makefile.cc13x0_cc26x0 | 27 ++ .../cc13x0_cc26x0/dev/sensortag-sensors.c | 55 ++++ .../cc13x0_cc26x0/dev/srf06-sensors.c | 55 ++++ .../launchpad/launchpad-sensors.c | 55 ++++ .../cc13x2_cc26x2/Makefile.cc13x2_cc26x2 | 28 ++ .../launchpad/button-sensor-arch.c | 198 ++++++++++++ .../launchpad/button-sensor-arch.h | 58 ++++ .../launchpad/launchpad-sensors.c | 50 +++ .../cc13x2_cc26x2/srf06/als-sensor-arch.c | 99 ++++++ .../cc13x2_cc26x2/srf06/als-sensor-arch.h | 48 +++ .../cc13x2_cc26x2/srf06/button-sensor-arch.c | 294 ++++++++++++++++++ .../cc13x2_cc26x2/srf06/button-sensor-arch.h | 61 ++++ .../cc13x2_cc26x2/srf06/srf06-sensors.c | 55 ++++ arch/platform/simplelink/dev/als-sensor.h | 50 +++ arch/platform/simplelink/dev/button-sensor.h | 66 ++++ .../simplelink/{common => dev}/leds-arch.c | 0 arch/platform/simplelink/platform.c | 10 +- 22 files changed, 1266 insertions(+), 32 deletions(-) create mode 100644 arch/platform/simplelink/Makefile.device-family create mode 100644 arch/platform/simplelink/cc13x0_cc26x0/Makefile.cc13x0_cc26x0 create mode 100644 arch/platform/simplelink/cc13x0_cc26x0/dev/sensortag-sensors.c create mode 100644 arch/platform/simplelink/cc13x0_cc26x0/dev/srf06-sensors.c create mode 100644 arch/platform/simplelink/cc13x0_cc26x0/launchpad/launchpad-sensors.c create mode 100644 arch/platform/simplelink/cc13x2_cc26x2/Makefile.cc13x2_cc26x2 create mode 100644 arch/platform/simplelink/cc13x2_cc26x2/launchpad/button-sensor-arch.c create mode 100644 arch/platform/simplelink/cc13x2_cc26x2/launchpad/button-sensor-arch.h create mode 100644 arch/platform/simplelink/cc13x2_cc26x2/launchpad/launchpad-sensors.c create mode 100644 arch/platform/simplelink/cc13x2_cc26x2/srf06/als-sensor-arch.c create mode 100644 arch/platform/simplelink/cc13x2_cc26x2/srf06/als-sensor-arch.h create mode 100644 arch/platform/simplelink/cc13x2_cc26x2/srf06/button-sensor-arch.c create mode 100644 arch/platform/simplelink/cc13x2_cc26x2/srf06/button-sensor-arch.h create mode 100644 arch/platform/simplelink/cc13x2_cc26x2/srf06/srf06-sensors.c create mode 100644 arch/platform/simplelink/dev/als-sensor.h create mode 100644 arch/platform/simplelink/dev/button-sensor.h rename arch/platform/simplelink/{common => dev}/leds-arch.c (100%) diff --git a/arch/cpu/simplelink/Makefile.cc26x2_cc13x2 b/arch/cpu/simplelink/Makefile.cc26x2_cc13x2 index 5d6079f6f..b828e4789 100644 --- a/arch/cpu/simplelink/Makefile.cc26x2_cc13x2 +++ b/arch/cpu/simplelink/Makefile.cc26x2_cc13x2 @@ -1,10 +1,4 @@ -ifeq "$(SIMPLELINK_DEVICE)" "cc13x2" -CFLAGS += -DDeviceFamily_CC13X2 -else -CFLAGS += -DDeviceFamily_CC26X2 -endif - CFLAGS += -I$(CPU_ABS_PATH)/cc26x2_cc13x2 CFLAGS += -I$(SDK_KERNEL) diff --git a/arch/cpu/simplelink/dev/rf-ieee-mode.c b/arch/cpu/simplelink/dev/rf-ieee-mode.c index d80af6d1e..c6b12d71f 100644 --- a/arch/cpu/simplelink/dev/rf-ieee-mode.c +++ b/arch/cpu/simplelink/dev/rf-ieee-mode.c @@ -533,15 +533,17 @@ static int set_rx(const PowerState state) { if (state == POWER_STATE_OFF || state == POWER_STATE_RESTART) { - const uint8_t stopGracefully = 1; - const RF_Stat stat = RF_cancelCmd(g_rfHandle, g_cmdRxHandle, - stopGracefully); - if (stat != RF_StatSuccess) - { - PRINTF("set_rx(off): unable to cancel RX\n"); - return CMD_RESULT_ERROR; + const uint16_t status = g_vpCmdRx->status; + if (status != IDLE && status != IEEE_DONE_OK && status != IEEE_DONE_STOPPED) { + const uint8_t stopGracefully = 1; + const RF_Stat stat = RF_cancelCmd(g_rfHandle, g_cmdRxHandle, + stopGracefully); + if (stat != RF_StatSuccess) + { + PRINTF("set_rx(off): unable to cancel RX state=0x%02X\n", stat); + return CMD_RESULT_ERROR; + } } - } if (state == POWER_STATE_ON || state == POWER_STATE_RESTART) { if (g_vpCmdRx->status == ACTIVE) { @@ -557,7 +559,7 @@ set_rx(const PowerState state) g_vpCmdRx->status = IDLE; g_cmdRxHandle = RF_scheduleCmd(g_rfHandle, (RF_Op*)g_vpCmdRx, &schedParams, NULL, 0); - if ((g_cmdTxHandle == RF_ALLOC_ERROR) || (g_cmdTxHandle == RF_SCHEDULE_CMD_ERROR)) { + if ((g_cmdRxHandle == RF_ALLOC_ERROR) || (g_cmdRxHandle == RF_SCHEDULE_CMD_ERROR)) { PRINTF("transmit: unable to allocate RX command\n"); return CMD_RESULT_ERROR; } diff --git a/arch/cpu/simplelink/rf-settings/rf-ieee-settings.c b/arch/cpu/simplelink/rf-settings/rf-ieee-settings.c index 1f7fea3d9..9b6c27cc6 100644 --- a/arch/cpu/simplelink/rf-settings/rf-ieee-settings.c +++ b/arch/cpu/simplelink/rf-settings/rf-ieee-settings.c @@ -151,6 +151,8 @@ rfc_CMD_IEEE_RX_t RF_cmdIeeeRx = .frameFiltOpt.bPendDataReqOnly = 0x0, .frameFiltOpt.bPanCoord = 0x0, .frameFiltOpt.maxFrameVersion = 0x2, + .frameFiltOpt.fcfReservedMask = 0x0, + .frameFiltOpt.modifyFtFilter = 0x0, .frameFiltOpt.bStrictLenFilter = 0x0, .frameTypes.bAcceptFt0Beacon = 0x1, .frameTypes.bAcceptFt1Data = 0x1, diff --git a/arch/platform/simplelink/Makefile.device-family b/arch/platform/simplelink/Makefile.device-family new file mode 100644 index 000000000..66d7be369 --- /dev/null +++ b/arch/platform/simplelink/Makefile.device-family @@ -0,0 +1,33 @@ +# Simplelink Device family switch + +# Device name in upper case +DEVICE_UC := $(shell echo $(SIMPLELINK_DEVICE) | tr a-z A-Z) + +# CC13x0/CC26x0 Family +ifeq ($(DEVICE_UC),CC13X0) + FAMILY := cc13x0_cc26x0 + CFLAGS += -DDeviceFamily_CC13X0 +else ifeq ($(DEVICE_UC),CC26X0) + FAMILY := cc13x0_cc26x0 + CFLAGS += -DDeviceFamily_CC26X0 +else ifeq ($(DEVICE_UC),CC26X0R2) + FAMILY := cc13x0_cc26x0 + CFLAGS += -DDeviceFamily_CC26X0R2 + +# CC13x2/CC26x2 Family +else ifeq ($(DEVICE_UC),CC13X2) + FAMILY := cc13x2_cc26x2 + CFLAGS += -DDeviceFamily_CC13X2 +else ifeq ($(DEVICE_UC),CC26X2) + FAMILY := cc13x2_cc26x2 + CFLAGS += -DDeviceFamily_CC26X2 + +# Not supported +else + $(error Simplelink Device '$(SIMPLELINK_DEVICE)' is not currently supported) +endif + +CONTIKI_TARGET_DIRS += $(FAMILY)/dev + +# Include the Family-specific makefile +include $(PLATFORM_ABS_PATH)/$(FAMILY)/Makefile.$(FAMILY) diff --git a/arch/platform/simplelink/Makefile.simplelink b/arch/platform/simplelink/Makefile.simplelink index 024ca6087..628ecc85d 100644 --- a/arch/platform/simplelink/Makefile.simplelink +++ b/arch/platform/simplelink/Makefile.simplelink @@ -4,10 +4,21 @@ ifndef CONTIKI $(error CONTIKI not defined! You must specify where CONTIKI resides!) endif +PLATFORM_ABS_PATH = $(CONTIKI)/arch/platform/simplelink + ifndef SIMPLELINK_SDK $(error SIMPLELINK_SDK not defined! You must specify where the SimpleLink SDK resides!) endif +# Find all available boards from the '/source/ti/boards directory' +AVAILABLE_BOARDS := $(shell ls -d $(SIMPLELINK_SDK)/source/ti/boards/*) +# Also allow a custom board file in the application project +AVAILABLE_BOARDS += CUSTOM + +ifndef SIMPLELINK_BOARD + $(error SIMPLELINK_BOARD not defined. You must specify a board!$nAvailable boards:$n $(foreach board, $(AVAILABLE_BOARDS), $(board)$n)) +endif + # Hacky way to emulate line breaks in warnings/errors # https://stackoverflow.com/questions/17055773/how-to-synthesize-line-breaks-in-gnu-make-warnings-or-errors define n @@ -18,7 +29,7 @@ endef # List of all Simplelink SDKs the Contiki Simplelink platform supports # with the format "simplelink__sdk". Don't add the version. # Simply adding a new entry with the name of a new SDK should be enough when -# the necessary implementaitons have been made. +# the necessary implementations have been made. SUPPORTED_SDKS = \ simplelink_cc13x0_sdk \ simplelink_cc13x2_sdk \ @@ -48,25 +59,18 @@ ifeq (,$(findstring $(SDK_NAME_STRIPPED), $(SUPPORTED_SDKS))) $(error Simplelink SDK '$(SDK_NAME)' is not supported.$nSupported SDKs:$n $(foreach sdk, $(SUPPORTED_SDKS), $(sdk)_$n)) endif -# Find all available boards from the '/source/ti/boards directory' -AVAILABLE_BOARDS := $(shell ls -d $(SIMPLELINK_SDK)/source/ti/boards/*) -# Also allow a custom board file in the application project -AVAILABLE_BOARDS += CUSTOM - -ifndef SIMPLELINK_BOARD - $(error SIMPLELINK_BOARD not defined. You must specify a board!$nAvailable boards:$n $(foreach board, $(AVAILABLE_BOARDS), $(board)$n)) -endif - ifneq ($(findstring $(SIMPLELINK_BOARD),$(AVAILABLE_BOARDS)),$(SIMPLELINK_BOARD)) $(error Board '$(SIMPLELINK_BOARD)' is not valid for the given Simplelink SDK '$(SDK_NAME)'.$nAvailable boards:$n $(foreach board, $(AVAILABLE_BOARDS), $(board)$n)) endif ### Board and BSP selection -CONTIKI_TARGET_DIRS += . common +CONTIKI_TARGET_DIRS += . dev CONTIKI_TARGET_SOURCEFILES += platform.c -CONTIKI_TARGET_SOURCEFILES += leds-arch.c + +# Determine which device family and include the corresponding source files +include $(PLATFORM_ABS_PATH)/Makefile.device-family CONTIKI_SOURCEFILES += $(CONTIKI_TARGET_SOURCEFILES) diff --git a/arch/platform/simplelink/cc13x0_cc26x0/Makefile.cc13x0_cc26x0 b/arch/platform/simplelink/cc13x0_cc26x0/Makefile.cc13x0_cc26x0 new file mode 100644 index 000000000..59c3052b8 --- /dev/null +++ b/arch/platform/simplelink/cc13x0_cc26x0/Makefile.cc13x0_cc26x0 @@ -0,0 +1,27 @@ +# SimpleLink MCU platform makefile + +### Board and BSP selection + +CONTIKI_TARGET_SOURCEFILES += leds-arch.c + +# Launchpad boards +ifneq (,$(findstring LAUNCHXL, $(SIMPLELINK_BOARD))) + CONTIKI_TARGET_SOURCEFILES += launchpad-sensors.c + +# Sensortag boards +else ifneq (,$(findstring STK, $(SIMPLELINK_BOARD))) + CONTIKI_TARGET_SOURCEFILES += sensortag-sensors.c + +# Custom boards +else ifneq (,$(findstring CUSTOM, $(SIMPLELINK_BOARD))) +# TODO + CONTIKI_TARGET_SOURCEFILES += custom-sensors.c + +# Everything else is assumed to be EVMs for the SmartRF06 EB (srf06) +else + CONTIKI_TARGET_SOURCEFILES += srf06-sensors.c + +endif + +CONTIKI_TARGET_SOURCEFILES += button-sensor-arch.c + diff --git a/arch/platform/simplelink/cc13x0_cc26x0/dev/sensortag-sensors.c b/arch/platform/simplelink/cc13x0_cc26x0/dev/sensortag-sensors.c new file mode 100644 index 000000000..c333e62f5 --- /dev/null +++ b/arch/platform/simplelink/cc13x0_cc26x0/dev/sensortag-sensors.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup simplelink-peripherals + * @{ + * + * \file + * Generic module controlling Simplelink sensors + */ +/*---------------------------------------------------------------------------*/ +#include +#include +/*---------------------------------------------------------------------------*/ +#include "common/button-sensor.h" +/*---------------------------------------------------------------------------*/ +/* Exports a global symbol to be used by the sensor API */ +SENSORS( +#ifdef BUTTON_SENSOR_ARCH_BTN1 + &button_sensor, +#endif +#ifdef BUTTON_SENSOR_ARCH_BTN2 + &button_sensor2, +#endif + NULL +); +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13x0_cc26x0/dev/srf06-sensors.c b/arch/platform/simplelink/cc13x0_cc26x0/dev/srf06-sensors.c new file mode 100644 index 000000000..c333e62f5 --- /dev/null +++ b/arch/platform/simplelink/cc13x0_cc26x0/dev/srf06-sensors.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup simplelink-peripherals + * @{ + * + * \file + * Generic module controlling Simplelink sensors + */ +/*---------------------------------------------------------------------------*/ +#include +#include +/*---------------------------------------------------------------------------*/ +#include "common/button-sensor.h" +/*---------------------------------------------------------------------------*/ +/* Exports a global symbol to be used by the sensor API */ +SENSORS( +#ifdef BUTTON_SENSOR_ARCH_BTN1 + &button_sensor, +#endif +#ifdef BUTTON_SENSOR_ARCH_BTN2 + &button_sensor2, +#endif + NULL +); +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13x0_cc26x0/launchpad/launchpad-sensors.c b/arch/platform/simplelink/cc13x0_cc26x0/launchpad/launchpad-sensors.c new file mode 100644 index 000000000..c333e62f5 --- /dev/null +++ b/arch/platform/simplelink/cc13x0_cc26x0/launchpad/launchpad-sensors.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup simplelink-peripherals + * @{ + * + * \file + * Generic module controlling Simplelink sensors + */ +/*---------------------------------------------------------------------------*/ +#include +#include +/*---------------------------------------------------------------------------*/ +#include "common/button-sensor.h" +/*---------------------------------------------------------------------------*/ +/* Exports a global symbol to be used by the sensor API */ +SENSORS( +#ifdef BUTTON_SENSOR_ARCH_BTN1 + &button_sensor, +#endif +#ifdef BUTTON_SENSOR_ARCH_BTN2 + &button_sensor2, +#endif + NULL +); +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13x2_cc26x2/Makefile.cc13x2_cc26x2 b/arch/platform/simplelink/cc13x2_cc26x2/Makefile.cc13x2_cc26x2 new file mode 100644 index 000000000..156d2b010 --- /dev/null +++ b/arch/platform/simplelink/cc13x2_cc26x2/Makefile.cc13x2_cc26x2 @@ -0,0 +1,28 @@ +# SimpleLink MCU platform makefile + +### Board and BSP selection + +CONTIKI_TARGET_SOURCEFILES += leds-arch.c + +# Launchpad boards +ifneq (,$(findstring LAUNCHXL, $(SIMPLELINK_BOARD))) +CONTIKI_TARGET_DIRS += $(FAMILY)/launchpad +CONTIKI_TARGET_SOURCEFILES += button-sensor-arch.c +CONTIKI_TARGET_SOURCEFILES += launchpad-sensors.c + +# Custom boards +else ifneq (,$(findstring CUSTOM, $(SIMPLELINK_BOARD))) +# TODO Need to figure out how custom boards are to be provided +CONTIKI_TARGET_DIRS += $(FAMILY)/custom +CONTIKI_TARGET_SOURCEFILES += custom-sensors.c + +# Everything else is assumed to be EVMs for the SmartRF06 EB (srf06) +else +CONTIKI_TARGET_DIRS += $(FAMILY)/srf06 +CONTIKI_TARGET_SOURCEFILES += button-sensor-arch.c +CONTIKI_TARGET_SOURCEFILES += srf06-sensors.c + +endif + +CONTIKI_TARGET_SOURCEFILES += button-sensor-arch.c + diff --git a/arch/platform/simplelink/cc13x2_cc26x2/launchpad/button-sensor-arch.c b/arch/platform/simplelink/cc13x2_cc26x2/launchpad/button-sensor-arch.c new file mode 100644 index 000000000..03292c580 --- /dev/null +++ b/arch/platform/simplelink/cc13x2_cc26x2/launchpad/button-sensor-arch.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup launchpad-button-sensor + * @{ + * + * \file + * Driver for LaunchPad buttons + */ +/*---------------------------------------------------------------------------*/ +#include +#include +#include +/*---------------------------------------------------------------------------*/ +#include +#include +#include +/*---------------------------------------------------------------------------*/ +#include +/*---------------------------------------------------------------------------*/ +#include "button-sensor.h" +#include "button-sensor-arch.h" +/*---------------------------------------------------------------------------*/ +/* LaunchPad has 2 buttons: BTN1 and BTN2 */ +/* Map the GPIO defines from the Board file */ +#define BTN1_GPIO Board_GPIO_BTN1 +#define BTN2_GPIO Board_GPIO_BTN2 +/*---------------------------------------------------------------------------*/ +#ifdef BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN +# define BUTTON_SENSOR_ENABLE_SHUTDOWN BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN +#else +# define BUTTON_SENSOR_ENABLE_SHUTDOWN 1 +#endif +/*---------------------------------------------------------------------------*/ +#define DEBOUNCE_DURATION (CLOCK_SECOND >> 5) +/*---------------------------------------------------------------------------*/ +typedef struct { + struct timer debounce; + clock_time_t start; + clock_time_t duration; +} BtnTimer; +/*---------------------------------------------------------------------------*/ +static BtnTimer g_btn1Timer; +static BtnTimer g_btn2Timer; +/*---------------------------------------------------------------------------*/ +static void +button_press_cb(uint8_t index, BtnTimer *btnTimer, const struct sensors_sensor *btnSensor) +{ + if (!timer_expired(&btnTimer->debounce)) { + return; + } + + timer_set(&btnTimer->debounce, DEBOUNCE_DURATION); + + // Start press duration counter on press (falling), notify on release (rising) + if(GPIO_read(index) == 0) { + btnTimer->start = clock_time(); + btnTimer->duration = 0; + } else { + btnTimer->duration = clock_time() - btnTimer->start; + sensors_changed(btnSensor); + } +} +/*---------------------------------------------------------------------------*/ +static int +button_value(int type, uint8_t index, BtnTimer *btnTimer) +{ + if (type == BUTTON_SENSOR_VALUE_STATE) { + return (GPIO_read(index) == 0) + ? BUTTON_SENSOR_VALUE_PRESSED + : BUTTON_SENSOR_VALUE_RELEASED; + } else if (type == BUTTON_SENSOR_VALUE_DURATION) { + return (int)btnTimer->duration; + } + return 0; +} +/*---------------------------------------------------------------------------*/ +static int +button_config(int type, int value, uint8_t index, GPIO_CallbackFxn callback) +{ + switch (type) { + case SENSORS_HW_INIT: + GPIO_clearInt(index); + GPIO_setCallback(index, callback); + break; + + case SENSORS_ACTIVE: + if (value) { + GPIO_clearInt(index); + GPIO_enableInt(index); + } else { + GPIO_disableInt(index); + } + break; + } + + return 1; +} +/*---------------------------------------------------------------------------*/ +static int +button_status(int type, uint8_t index) +{ + switch(type) { + case SENSORS_ACTIVE: /* fallthrough */ + case SENSORS_READY: { + GPIO_PinConfig pinCfg = 0; + GPIO_getConfig(index, &pinCfg); + return (pinCfg & GPIO_CFG_IN_INT_NONE) == 0; + } + } + return 0; +} +/*---------------------------------------------------------------------------*/ +static void +btn1_press_cb(unsigned char unusued) +{ + button_press_cb(BTN1_GPIO, &g_btn1Timer, &btn1_sensor); +} +/*---------------------------------------------------------------------------*/ +static int +btn1_value(int type) +{ + return button_value(type, BTN1_GPIO, &g_btn1Timer); +} +/*---------------------------------------------------------------------------*/ +static int +btn1_config(int type, int value) +{ + return button_config(type, value, BTN1_GPIO, btn1_press_cb); +} +/*---------------------------------------------------------------------------*/ +static int +btn1_status(int type) +{ + return button_status(type, BTN1_GPIO); +} +/*---------------------------------------------------------------------------*/ +static void +btn2_press_cb(unsigned char unusued) +{ + if (BUTTON_SENSOR_ENABLE_SHUTDOWN) { + Power_shutdown(Power_ENTERING_SHUTDOWN, 0); + return; + } + + button_press_cb(BTN2_GPIO, &g_btn2Timer, &btn2_sensor); +} +/*---------------------------------------------------------------------------*/ +static int +btn2_value(int type) +{ + return button_value(type, BTN2_GPIO, &g_btn2Timer); +} +/*---------------------------------------------------------------------------*/ +static int +btn2_config(int type, int value) +{ + return button_config(type, value, BTN2_GPIO, btn2_press_cb); +} +/*---------------------------------------------------------------------------*/ +static int +btn2_status(int type) +{ + return button_status(type, BTN1_GPIO); +} +/*---------------------------------------------------------------------------*/ +SENSORS_SENSOR(btn1_sensor, BUTTON_SENSOR, btn1_value, btn1_config, btn1_status); +SENSORS_SENSOR(btn2_sensor, BUTTON_SENSOR, btn2_value, btn2_config, btn2_status); +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13x2_cc26x2/launchpad/button-sensor-arch.h b/arch/platform/simplelink/cc13x2_cc26x2/launchpad/button-sensor-arch.h new file mode 100644 index 000000000..ecd04e8b6 --- /dev/null +++ b/arch/platform/simplelink/cc13x2_cc26x2/launchpad/button-sensor-arch.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2018 Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup simplelink-platform + * @{ + * + * \defgroup simplelink-button-sensor Simplelink Button Driver + * + * One of the buttons can be configured as general purpose or as an on/off key + * @{ + * + * \file + * Header file for the Simplelink Button Driver + */ +/*---------------------------------------------------------------------------*/ +#ifndef BUTTON_SENSOR_ARCH_H_ +#define BUTTON_SENSOR_ARCH_H_ +/*---------------------------------------------------------------------------*/ +/* Contiki API */ +#include +/*---------------------------------------------------------------------------*/ +extern const struct sensors_sensor btn1_sensor; +extern const struct sensors_sensor btn2_sensor; +/*---------------------------------------------------------------------------*/ +#endif /* BUTTON_SENSOR_ARCH_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/platform/simplelink/cc13x2_cc26x2/launchpad/launchpad-sensors.c b/arch/platform/simplelink/cc13x2_cc26x2/launchpad/launchpad-sensors.c new file mode 100644 index 000000000..de65965f8 --- /dev/null +++ b/arch/platform/simplelink/cc13x2_cc26x2/launchpad/launchpad-sensors.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup simplelink-peripherals + * @{ + * + * \file + * Generic module controlling Simplelink sensors + */ +/*---------------------------------------------------------------------------*/ +#include +#include +/*---------------------------------------------------------------------------*/ +#include "button-sensor-arch.h" +/*---------------------------------------------------------------------------*/ +/* Exports a global symbol to be used by the sensor API */ +SENSORS( + &btn1_sensor, + &btn2_sensor +); +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13x2_cc26x2/srf06/als-sensor-arch.c b/arch/platform/simplelink/cc13x2_cc26x2/srf06/als-sensor-arch.c new file mode 100644 index 000000000..1c40c3f12 --- /dev/null +++ b/arch/platform/simplelink/cc13x2_cc26x2/srf06/als-sensor-arch.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2016, University of Bristol - http://www.bris.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 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup srf06-common-peripherals + * @{ + * + * \file + * Driver for the SmartRF06EB ALS when a CC13xx/CC26xxEM is mounted on it + */ +/*---------------------------------------------------------------------------*/ +#include +#include +#include +/*---------------------------------------------------------------------------*/ +#include +#include +#include +#include +/*---------------------------------------------------------------------------*/ +#include "als-sensor.h" +#include "als-sensor-arch.h" +/*---------------------------------------------------------------------------*/ +#include +/*---------------------------------------------------------------------------*/ +/* SmartRF06 EB has one Analog Light Sensor (ALS) */ +#define ALS_OUT_DIO Board_ALS_OUT +#define ALS_PWR_DIO Board_ALS_PWR +/*---------------------------------------------------------------------------*/ +static int +config(int type, int value) +{ + switch (type) { + case SENSORS_ACTIVE: + IOCPinTypeGpioOutput(ALS_PWR_DIO); + IOCPortConfigureSet(ALS_OUT_DIO, IOC_PORT_GPIO, IOC_STD_OUTPUT); + IOCPinTypeGpioInput(ALS_OUT_DIO); + + if (value) { + GPIO_setDio(ALS_PWR_DIO); + AUXADCSelectInput(ALS_OUT_DIO); + clock_delay_usec(2000); + } else { + GPIO_clearDio(ALS_PWR_DIO); + } + break; + } + return 1; +} +/*---------------------------------------------------------------------------*/ +static int +value(int type) +{ + AUXADCEnableSync(AUXADC_REF_VDDS_REL, AUXADC_SAMPLE_TIME_2P7_US, AUXADC_TRIGGER_MANUAL); + AUXADCGenManualTrigger(); + + int val = AUXADCReadFifo(); + + AUXADCDisable(); + + return val; +} +/*---------------------------------------------------------------------------*/ +static int +status(int type) +{ + return 1; +} +/*---------------------------------------------------------------------------*/ +SENSORS_SENSOR(als_sensor, ALS_SENSOR, value, config, status); +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13x2_cc26x2/srf06/als-sensor-arch.h b/arch/platform/simplelink/cc13x2_cc26x2/srf06/als-sensor-arch.h new file mode 100644 index 000000000..8cb482c7b --- /dev/null +++ b/arch/platform/simplelink/cc13x2_cc26x2/srf06/als-sensor-arch.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016, University of Bristol - http://www.bris.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 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup srf06-common-peripherals + * @{ + * + * \file + * Header file for the SmartRF06EB + CC13xx/CC26xxEM ALS Driver + */ +/*---------------------------------------------------------------------------*/ +#ifndef ALS_SENSOR_H_ +#define ALS_SENSOR_H_ +/*---------------------------------------------------------------------------*/ +#include "lib/sensors.h" +/*---------------------------------------------------------------------------*/ +extern const struct sensors_sensor als_sensor; +/*---------------------------------------------------------------------------*/ +#endif /* ALS_SENSOR_H_ */ +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13x2_cc26x2/srf06/button-sensor-arch.c b/arch/platform/simplelink/cc13x2_cc26x2/srf06/button-sensor-arch.c new file mode 100644 index 000000000..f6020d6ad --- /dev/null +++ b/arch/platform/simplelink/cc13x2_cc26x2/srf06/button-sensor-arch.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup launchpad-button-sensor + * @{ + * + * \file + * Driver for LaunchPad buttons + */ +/*---------------------------------------------------------------------------*/ +#include +#include +#include +/*---------------------------------------------------------------------------*/ +#include +#include +#include +/*---------------------------------------------------------------------------*/ +#include +/*---------------------------------------------------------------------------*/ +#include "button-sensor.h" +#include "button-sensor-arch.h" +/*---------------------------------------------------------------------------*/ +/* SmartRF06 EB has 5 buttons: Select, Up, Down, Left, and Right */ +/* Map the GPIO defines from the Board file */ +#define BUTTON_SELECT_GPIO Board_KEY_SELECT +#define BUTTON_UP_GPIO Board_KEY_UP +#define BUTTON_DOWN_GPIO Board_KEY_DOWN +#define BUTTON_LEFT_GPIO Board_KEY_LEFT +#define BUTTON_RIGHT_GPIO Board_KEY_RIGHT +/*---------------------------------------------------------------------------*/ +#ifdef BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN +# define BUTTON_SENSOR_ENABLE_SHUTDOWN BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN +#else +# define BUTTON_SENSOR_ENABLE_SHUTDOWN 1 +#endif +/*---------------------------------------------------------------------------*/ +#define DEBOUNCE_DURATION (CLOCK_SECOND >> 5) +/*---------------------------------------------------------------------------*/ +typedef struct { + struct timer debounce; + clock_time_t start; + clock_time_t duration; +} BtnTimer; +/*---------------------------------------------------------------------------*/ +static BtnTimer g_buttonSelectTimer; +static BtnTimer g_buttonUpTimer; +static BtnTimer g_buttonDownTimer; +static BtnTimer g_buttonLeftTimer; +static BtnTimer g_buttonRightTimer; +/*---------------------------------------------------------------------------*/ +static void +button_press_cb(uint8_t index, BtnTimer *btnTimer, const struct sensors_sensor *btnSensor) +{ + if (!timer_expired(&btnTimer->debounce)) { + return; + } + + timer_set(&btnTimer->debounce, DEBOUNCE_DURATION); + + // Start press duration counter on press (falling), notify on release (rising) + if(GPIO_read(index) == 0) { + btnTimer->start = clock_time(); + btnTimer->duration = 0; + } else { + btnTimer->duration = clock_time() - btnTimer->start; + sensors_changed(btnSensor); + } +} +/*---------------------------------------------------------------------------*/ +static int +button_value(int type, uint8_t index, BtnTimer *btnTimer) +{ + if (type == BUTTON_SENSOR_VALUE_STATE) { + return (GPIO_read(index) == 0) + ? BUTTON_SENSOR_VALUE_PRESSED + : BUTTON_SENSOR_VALUE_RELEASED; + } else if (type == BUTTON_SENSOR_VALUE_DURATION) { + return (int)btnTimer->duration; + } + return 0; +} +/*---------------------------------------------------------------------------*/ +static int +button_config(int type, int value, uint8_t index, GPIO_CallbackFxn callback) +{ + switch (type) { + case SENSORS_HW_INIT: + GPIO_clearInt(index); + GPIO_setCallback(index, callback); + break; + + case SENSORS_ACTIVE: + if (value) { + GPIO_clearInt(index); + GPIO_enableInt(index); + } else { + GPIO_disableInt(index); + } + break; + } + + return 1; +} +/*---------------------------------------------------------------------------*/ +static int +button_status(int type, uint8_t index) +{ + switch(type) { + case SENSORS_ACTIVE: /* fallthrough */ + case SENSORS_READY: { + GPIO_PinConfig pinCfg = 0; + GPIO_getConfig(index, &pinCfg); + return (pinCfg & GPIO_CFG_IN_INT_NONE) == 0; + } + } + return 0; +} +/*---------------------------------------------------------------------------*/ +/* Select Button */ +/*---------------------------------------------------------------------------*/ +static void +button_select_press_cb(unsigned char unusued) +{ + button_press_cb(BUTTON_SELECT_GPIO, &g_buttonSelectTimer, &button_select_sensor); +} +/*---------------------------------------------------------------------------*/ +static int +button_select_value(int type) +{ + return button_value(type, BUTTON_SELECT_GPIO, &g_buttonSelectTimer); +} +/*---------------------------------------------------------------------------*/ +static int +button_select_config(int type, int value) +{ + return button_config(type, value, BUTTON_SELECT_GPIO, button_select_press_cb); +} +/*---------------------------------------------------------------------------*/ +static int +button_select_status(int type) +{ + return button_status(type, BUTTON_SELECT_GPIO); +} +/*---------------------------------------------------------------------------*/ +/* Up Button */ +/*---------------------------------------------------------------------------*/ +static void +button_up_press_cb(unsigned char unusued) +{ + button_press_cb(BUTTON_UP_GPIO, &g_buttonUpTimer, &button_up_sensor); +} +/*---------------------------------------------------------------------------*/ +static int +button_up_value(int type) +{ + return button_value(type, BUTTON_UP_GPIO, &g_buttonUpTimer); +} +/*---------------------------------------------------------------------------*/ +static int +button_up_config(int type, int value) +{ + return button_config(type, value, BUTTON_UP_GPIO, button_up_press_cb); +} +/*---------------------------------------------------------------------------*/ +static int +button_up_status(int type) +{ + return button_status(type, BUTTON_UP_GPIO); +} +/*---------------------------------------------------------------------------*/ +/* Down Button */ +/*---------------------------------------------------------------------------*/ +static void +button_down_press_cb(unsigned char unusued) +{ + button_press_cb(BUTTON_DOWN_GPIO, &g_buttonDownTimer, &button_down_sensor); +} +/*---------------------------------------------------------------------------*/ +static int +button_down_value(int type) +{ + return button_value(type, BUTTON_DOWN_GPIO, &g_buttonDownTimer); +} +/*---------------------------------------------------------------------------*/ +static int +button_down_config(int type, int value) +{ + return button_config(type, value, BUTTON_DOWN_GPIO, button_down_press_cb); +} +/*---------------------------------------------------------------------------*/ +static int +button_down_status(int type) +{ + return button_status(type, BUTTON_DOWN_GPIO); +} +/*---------------------------------------------------------------------------*/ +/* Left Button */ +/*---------------------------------------------------------------------------*/ +static void +button_left_press_cb(unsigned char unusued) +{ + button_press_cb(BUTTON_LEFT_GPIO, &g_buttonLeftTimer, &button_left_sensor); +} +/*---------------------------------------------------------------------------*/ +static int +button_left_value(int type) +{ + return button_value(type, BUTTON_LEFT_GPIO, &g_buttonLeftTimer); +} +/*---------------------------------------------------------------------------*/ +static int +button_left_config(int type, int value) +{ + return button_config(type, value, BUTTON_LEFT_GPIO, button_left_press_cb); +} +/*---------------------------------------------------------------------------*/ +static int +button_left_status(int type) +{ + return button_status(type, BUTTON_LEFT_GPIO); +} +/*---------------------------------------------------------------------------*/ +/* Right Button */ +/*---------------------------------------------------------------------------*/ +static void +button_right_press_cb(unsigned char unusued) +{ + if (BUTTON_SENSOR_ENABLE_SHUTDOWN) { + Power_shutdown(Power_ENTERING_SHUTDOWN, 0); + return; + } + + button_press_cb(BUTTON_RIGHT_GPIO, &g_buttonRightTimer, &button_right_sensor); +} +/*---------------------------------------------------------------------------*/ +static int +button_right_value(int type) +{ + return button_value(type, BUTTON_RIGHT_GPIO, &g_buttoRightimer); +} +/*---------------------------------------------------------------------------*/ +static int +button_right_config(int type, int value) +{ + return button_config(type, value, BUTTON_RIGHT_GPIO, button_right_press_cb); +} +/*---------------------------------------------------------------------------*/ +static int +button_right_status(int type) +{ + return button_status(type, BUTTON_RIGHT_GPIO); +} +/*---------------------------------------------------------------------------*/ +SENSORS_SENSOR(button_select_sensor, BUTTON_SENSOR, + button_select_value, button_select_config, button_select_status); +SENSORS_SENSOR(button_up_sensor, BUTTON_SENSOR, + button_up_value, button_up_config, button_up_status); +SENSORS_SENSOR(button_down_sensor, BUTTON_SENSOR, + button_down_value, button_down_config, button_down_status); +SENSORS_SENSOR(button_left_sensor, BUTTON_SENSOR, + button_left_value, button_left_config, button_left_status); +SENSORS_SENSOR(button_right_sensor, BUTTON_SENSOR, + button_right_value, button_right_config, button_right_status); +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13x2_cc26x2/srf06/button-sensor-arch.h b/arch/platform/simplelink/cc13x2_cc26x2/srf06/button-sensor-arch.h new file mode 100644 index 000000000..761600281 --- /dev/null +++ b/arch/platform/simplelink/cc13x2_cc26x2/srf06/button-sensor-arch.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2018 Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup simplelink-platform + * @{ + * + * \defgroup simplelink-button-sensor Simplelink Button Driver + * + * One of the buttons can be configured as general purpose or as an on/off key + * @{ + * + * \file + * Header file for the Simplelink Button Driver + */ +/*---------------------------------------------------------------------------*/ +#ifndef BUTTON_SENSOR_ARCH_H_ +#define BUTTON_SENSOR_ARCH_H_ +/*---------------------------------------------------------------------------*/ +/* Contiki API */ +#include +/*---------------------------------------------------------------------------*/ +extern const struct sensors_sensor button_select_sensor; +extern const struct sensors_sensor button_up_sensor; +extern const struct sensors_sensor button_down_sensor; +extern const struct sensors_sensor button_left_sensor; +extern const struct sensors_sensor button_right_sensor; +/*---------------------------------------------------------------------------*/ +#endif /* BUTTON_SENSOR_ARCH_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/platform/simplelink/cc13x2_cc26x2/srf06/srf06-sensors.c b/arch/platform/simplelink/cc13x2_cc26x2/srf06/srf06-sensors.c new file mode 100644 index 000000000..ea0283fe0 --- /dev/null +++ b/arch/platform/simplelink/cc13x2_cc26x2/srf06/srf06-sensors.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup srf06-peripherals + * @{ + * + * \file + * Generic module controlling sensors on the SmartRF06EB + */ +/*---------------------------------------------------------------------------*/ +#include +#include +/*---------------------------------------------------------------------------*/ +#include "button-sensor-arch.h" +#include "als-sensor-arch.h" +/*---------------------------------------------------------------------------*/ +/* Exports a global symbol to be used by the sensor API */ +SENSORS( + &button_select_sensor, + &button_up_sensor, + &button_down_sensor, + &button_left_sensor, + &button_right_sensor, + &als_sensor +); +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/dev/als-sensor.h b/arch/platform/simplelink/dev/als-sensor.h new file mode 100644 index 000000000..dcd7fa1da --- /dev/null +++ b/arch/platform/simplelink/dev/als-sensor.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018, University of Bristol - http://www.bris.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 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup srf06-common-peripherals + * @{ + * + * \file + * Header file for the SmartRF06EB + CC13xx/CC26xxEM ALS Driver + */ +/*---------------------------------------------------------------------------*/ +#ifndef ALS_SENSOR_H_ +#define ALS_SENSOR_H_ +/*---------------------------------------------------------------------------*/ +#include +/*---------------------------------------------------------------------------*/ +#include "als-sensor-arch.h" +/*---------------------------------------------------------------------------*/ +#define ALS_SENSOR "ALS" +/*---------------------------------------------------------------------------*/ +#endif /* ALS_SENSOR_H_ */ +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/dev/button-sensor.h b/arch/platform/simplelink/dev/button-sensor.h new file mode 100644 index 000000000..8756d9b6c --- /dev/null +++ b/arch/platform/simplelink/dev/button-sensor.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2018 Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup simplelink-platform + * @{ + * + * \defgroup simplelink-button-sensor Simplelink Button Driver + * + * One of the buttons can be configured as general purpose or as an on/off key + * @{ + * + * \file + * Header file for the Simplelink Button Driver + */ +/*---------------------------------------------------------------------------*/ +#ifndef BUTTON_SENSOR_H_ +#define BUTTON_SENSOR_H_ +/*---------------------------------------------------------------------------*/ +/* Contiki API */ +#include +/*---------------------------------------------------------------------------*/ +/* Board specific button sensors */ +#include "button-sensor-arch.h" +/*---------------------------------------------------------------------------*/ +#define BUTTON_SENSOR "Button" +/*---------------------------------------------------------------------------*/ +#define BUTTON_SENSOR_VALUE_STATE 0 +#define BUTTON_SENSOR_VALUE_DURATION 1 + +#define BUTTON_SENSOR_VALUE_RELEASED 0 +#define BUTTON_SENSOR_VALUE_PRESSED 1 +/*---------------------------------------------------------------------------*/ +#endif /* BUTTON_SENSOR_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/platform/simplelink/common/leds-arch.c b/arch/platform/simplelink/dev/leds-arch.c similarity index 100% rename from arch/platform/simplelink/common/leds-arch.c rename to arch/platform/simplelink/dev/leds-arch.c diff --git a/arch/platform/simplelink/platform.c b/arch/platform/simplelink/platform.c index 6547de1bd..50ef66762 100644 --- a/arch/platform/simplelink/platform.c +++ b/arch/platform/simplelink/platform.c @@ -128,7 +128,7 @@ set_rf_params(void) } /*---------------------------------------------------------------------------*/ void -platform_init_stage_one() +platform_init_stage_one(void) { // Enable flash cache VIMSModeSet(VIMS_BASE, VIMS_MODE_ENABLED); @@ -141,6 +141,7 @@ platform_init_stage_one() // NoRTOS_start only enables HWI NoRTOS_start(); + // Contiki drivers init leds_init(); // ti_lib_int_master_disable(); @@ -162,12 +163,11 @@ platform_init_stage_one() // // ti_lib_int_master_enable(); // -// soc_rtc_init(); fade(LEDS_GREEN); } /*---------------------------------------------------------------------------*/ void -platform_init_stage_two() +platform_init_stage_two(void) { uart0_init(); serial_line_init(); @@ -181,7 +181,7 @@ platform_init_stage_two() } /*---------------------------------------------------------------------------*/ void -platform_init_stage_three() +platform_init_stage_three(void) { radio_value_t chan, pan; @@ -206,7 +206,7 @@ platform_init_stage_three() } /*---------------------------------------------------------------------------*/ void -platform_idle() +platform_idle(void) { // Drop to some low power mode Power_idleFunc(); From 9f32a96590c8e6d1ca8a02f69609b8a37a8475b8 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Fri, 16 Feb 2018 18:49:08 +0100 Subject: [PATCH 242/485] Removed unwanted check of RF cancel command --- arch/cpu/simplelink/dev/rf-ieee-mode.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/arch/cpu/simplelink/dev/rf-ieee-mode.c b/arch/cpu/simplelink/dev/rf-ieee-mode.c index c6b12d71f..393eaa3f4 100644 --- a/arch/cpu/simplelink/dev/rf-ieee-mode.c +++ b/arch/cpu/simplelink/dev/rf-ieee-mode.c @@ -533,18 +533,11 @@ static int set_rx(const PowerState state) { if (state == POWER_STATE_OFF || state == POWER_STATE_RESTART) { - const uint16_t status = g_vpCmdRx->status; - if (status != IDLE && status != IEEE_DONE_OK && status != IEEE_DONE_STOPPED) { - const uint8_t stopGracefully = 1; - const RF_Stat stat = RF_cancelCmd(g_rfHandle, g_cmdRxHandle, - stopGracefully); - if (stat != RF_StatSuccess) - { - PRINTF("set_rx(off): unable to cancel RX state=0x%02X\n", stat); - return CMD_RESULT_ERROR; - } - } + // Stop RX gracefully, don't care about the result + const uint8_t stopGracefully = 1; + RF_cancelCmd(g_rfHandle, g_cmdRxHandle, stopGracefully); } + if (state == POWER_STATE_ON || state == POWER_STATE_RESTART) { if (g_vpCmdRx->status == ACTIVE) { PRINTF("set_rx(on): already in RX\n"); From 6ce955a71f31f0a190574de268f86395610310a4 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Fri, 16 Feb 2018 18:50:09 +0100 Subject: [PATCH 243/485] Added slip driver --- arch/cpu/simplelink/Makefile.simplelink | 2 +- arch/cpu/simplelink/dev/slip-arch.c | 68 +++++++++++++++++++++++++ arch/cpu/simplelink/dev/uart0-arch.h | 6 +-- 3 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 arch/cpu/simplelink/dev/slip-arch.c diff --git a/arch/cpu/simplelink/Makefile.simplelink b/arch/cpu/simplelink/Makefile.simplelink index 0f8765d44..8f6a1e51c 100644 --- a/arch/cpu/simplelink/Makefile.simplelink +++ b/arch/cpu/simplelink/Makefile.simplelink @@ -64,7 +64,7 @@ CONTIKI_CPU_DIRS += dev rf-settings ### CPU-dependent source files CONTIKI_CPU_SOURCEFILES += rtimer-arch.c clock-arch.c CONTIKI_CPU_SOURCEFILES += watchdog-arch.c putchar-arch.c -CONTIKI_CPU_SOURCEFILES += uart0-arch.c +CONTIKI_CPU_SOURCEFILES += uart0-arch.c slip-arch.c CONTIKI_CPU_SOURCEFILES += rf-common.c CONTIKI_CPU_SOURCEFILES += rf-prop-mode.c rf-prop-settings.c CONTIKI_CPU_SOURCEFILES += rf-ieee-mode.c rf-ieee-settings.c diff --git a/arch/cpu/simplelink/dev/slip-arch.c b/arch/cpu/simplelink/dev/slip-arch.c new file mode 100644 index 000000000..c8d3cea2a --- /dev/null +++ b/arch/cpu/simplelink/dev/slip-arch.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup cc26xx-char-io + * @{ + * + * \file + * Arch-specific SLIP functions for the CC13xx/CC26xx + */ +/*---------------------------------------------------------------------------*/ +#include +#include +/*---------------------------------------------------------------------------*/ +#include "dev/uart0-arch.h" +/*---------------------------------------------------------------------------*/ +/** + * \brief Write a byte over SLIP + * \param c the byte + */ +void +slip_arch_writeb(unsigned char c) +{ + uart0_write(&c, 1); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Initialise the arch-specific SLIP driver + */ +void +slip_arch_init() +{ + // Enable an input handler. In doing so, the driver will make sure that UART + // RX stays operational during deep sleep + uart0_init(); + uart0_set_callback(slip_input_byte); +} +/*---------------------------------------------------------------------------*/ + +/** @} */ diff --git a/arch/cpu/simplelink/dev/uart0-arch.h b/arch/cpu/simplelink/dev/uart0-arch.h index 7266a4db5..0a54d2a73 100644 --- a/arch/cpu/simplelink/dev/uart0-arch.h +++ b/arch/cpu/simplelink/dev/uart0-arch.h @@ -41,11 +41,11 @@ */ #ifndef UART0_ARCH_H_ #define UART0_ARCH_H_ - +/*---------------------------------------------------------------------------*/ +#include #include - +/*---------------------------------------------------------------------------*/ typedef int (*uart0_input_cb)(unsigned char); - /*---------------------------------------------------------------------------*/ /** \name UART functions * @{ From a76462b90887c2277473621ebeecf4d89d55fd3e Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Tue, 8 May 2018 21:39:20 +0200 Subject: [PATCH 244/485] Initial commit of Simplelink rework --- arch/cpu/arm/Makefile.arm | 2 +- arch/cpu/arm/cortex-m/cm4/Makefile.cm4 | 2 +- .../Makefile.cc13x0-cc26x0} | 2 + arch/cpu/cc13xx-cc26xx/Makefile.cc13x2-cc26x2 | 74 ++++++ .../Makefile.simplelink | 8 +- .../cc13x0-cc26x0}/cc13x0-cc26x0-cm3.h | 0 .../cc13x0-cc26x0}/cc13x0-cc26x0-def.h | 0 .../cc13x0-cc26x0}/simplelink-def.h | 0 .../cc13x2-cc26x2}/cc13x2-cc26x2-cm4.h | 0 .../cc13x2-cc26x2}/cc13x2-cc26x2-def.h | 0 .../cc13x2-cc26x2}/simplelink-def.h | 0 .../{simplelink => cc13xx-cc26xx}/ccfg-conf.h | 6 +- .../dev/clock-arch.c | 0 .../{simplelink => cc13xx-cc26xx}/dev/dbg.h | 0 .../dev/debug-uart.h | 0 .../dev/dot-15-4g.h | 0 .../dev/ieee-addr.c | 0 .../dev/ieee-addr.h | 2 +- .../dev/putchar-arch.c | 0 .../cc13xx-cc26xx/dev/random-arch.c} | 42 ++-- .../dev/rf-common.c | 4 +- .../dev/rf-common.h | 0 .../dev/rf-ieee-mode.c | 155 +++++++----- .../dev/rf-prop-mode.c | 0 .../dev/rtimer-arch.c | 34 ++- .../dev/rtimer-arch.h | 0 .../dev/slip-arch.c | 0 .../dev/uart0-arch.c | 53 +++-- .../dev/uart0-arch.h | 14 +- .../dev/watchdog-arch.c | 0 .../rf-settings/rf-ieee-settings.c | 0 .../rf-settings/rf-ieee-settings.h | 0 .../rf-settings/rf-prop-settings.c | 0 .../rf-settings/rf-prop-settings.h | 0 .../simplelink-conf.h | 8 +- arch/cpu/simplelink/Makefile.cc26x2_cc13x2 | 10 - .../simplelink/Makefile.device-family | 94 ++++++-- arch/platform/simplelink/Makefile.simplelink | 81 +------ .../cc13x0-cc26x0/Makefile.cc13x0-cc26x0 | 106 +++++++++ .../common}/als-sensor.h | 0 .../common}/button-sensor.h | 0 .../{ => cc13x0-cc26x0}/contiki-conf.h | 0 .../launchpad/Makefile.launchpad | 12 + .../launchpad/button-sensor-arch.c | 0 .../launchpad/button-sensor-arch.h | 0 .../launchpad/cc1310/Makefile.cc1310 | 22 ++ .../launchpad/cc1350-4/Makefile.cc1350-4 | 22 ++ .../launchpad/cc1350/Makefile.cc1350 | 22 ++ .../launchpad/cc2650/Makefile.cc2650 | 22 ++ .../launchpad/launchpad-sensors.c | 0 .../launchpad}/leds-arch.c | 0 .../simplelink/{ => cc13x0-cc26x0}/platform.c | 22 +- .../sensortag/Makefile.sensortag | 12 + .../sensortag/cc1350/Makefile.cc1350 | 22 ++ .../sensortag/cc2650/Makefile.cc2650 | 22 ++ .../sensortag}/sensortag-sensors.c | 0 .../cc13x0-cc26x0/srf06/Makefile.srf06 | 12 + .../srf06/cc1310/Makefile.cc1310 | 22 ++ .../srf06/cc1350/Makefile.cc1350 | 22 ++ .../srf06/cc2650/Makefile.cc2650 | 22 ++ .../srf06}/srf06-sensors.c | 0 .../cc13x0_cc26x0/Makefile.cc13x0_cc26x0 | 27 --- .../cc13x2-cc26x2/Makefile.cc13x2-cc26x2 | 103 ++++++++ .../common/button-sensor.h} | 36 ++- .../simplelink/cc13x2-cc26x2/contiki-conf.h | 78 ++++++ .../launchpad/Makefile.launchpad | 12 + .../launchpad}/button-sensor-arch.c | 172 +++----------- .../launchpad}/button-sensor-arch.h | 7 +- .../launchpad/cc1312r1/Makefile.cc1312r1 | 22 ++ .../launchpad/cc1352p1/Makefile.cc1352p1 | 22 ++ .../launchpad/cc1352r1/Makefile.cc1352r1 | 22 ++ .../launchpad/cc26x2r1/Makefile.cc26x2r1 | 22 ++ .../launchpad/launchpad-sensors.c | 11 +- .../launchpad/leds-arch.c} | 127 ++++++---- .../simplelink/cc13x2-cc26x2/platform.c | 224 ++++++++++++++++++ .../cc13x2_cc26x2/Makefile.cc13x2_cc26x2 | 28 --- 76 files changed, 1372 insertions(+), 494 deletions(-) rename arch/cpu/{simplelink/Makefile.cc26x0_cc13x0 => cc13xx-cc26xx/Makefile.cc13x0-cc26x0} (97%) create mode 100644 arch/cpu/cc13xx-cc26xx/Makefile.cc13x2-cc26x2 rename arch/cpu/{simplelink => cc13xx-cc26xx}/Makefile.simplelink (96%) rename arch/cpu/{simplelink/cc26x0_cc13x0 => cc13xx-cc26xx/cc13x0-cc26x0}/cc13x0-cc26x0-cm3.h (100%) rename arch/cpu/{simplelink/cc26x0_cc13x0 => cc13xx-cc26xx/cc13x0-cc26x0}/cc13x0-cc26x0-def.h (100%) rename arch/cpu/{simplelink/cc26x0_cc13x0 => cc13xx-cc26xx/cc13x0-cc26x0}/simplelink-def.h (100%) rename arch/cpu/{simplelink/cc26x2_cc13x2 => cc13xx-cc26xx/cc13x2-cc26x2}/cc13x2-cc26x2-cm4.h (100%) rename arch/cpu/{simplelink/cc26x2_cc13x2 => cc13xx-cc26xx/cc13x2-cc26x2}/cc13x2-cc26x2-def.h (100%) rename arch/cpu/{simplelink/cc26x2_cc13x2 => cc13xx-cc26xx/cc13x2-cc26x2}/simplelink-def.h (100%) rename arch/cpu/{simplelink => cc13xx-cc26xx}/ccfg-conf.h (97%) rename arch/cpu/{simplelink => cc13xx-cc26xx}/dev/clock-arch.c (100%) rename arch/cpu/{simplelink => cc13xx-cc26xx}/dev/dbg.h (100%) rename arch/cpu/{simplelink => cc13xx-cc26xx}/dev/debug-uart.h (100%) rename arch/cpu/{simplelink => cc13xx-cc26xx}/dev/dot-15-4g.h (100%) rename arch/cpu/{simplelink => cc13xx-cc26xx}/dev/ieee-addr.c (100%) rename arch/cpu/{simplelink => cc13xx-cc26xx}/dev/ieee-addr.h (98%) rename arch/cpu/{simplelink => cc13xx-cc26xx}/dev/putchar-arch.c (100%) rename arch/{platform/simplelink/cc13x2_cc26x2/srf06/srf06-sensors.c => cpu/cc13xx-cc26xx/dev/random-arch.c} (78%) rename arch/cpu/{simplelink => cc13xx-cc26xx}/dev/rf-common.c (98%) rename arch/cpu/{simplelink => cc13xx-cc26xx}/dev/rf-common.h (100%) rename arch/cpu/{simplelink => cc13xx-cc26xx}/dev/rf-ieee-mode.c (91%) rename arch/cpu/{simplelink => cc13xx-cc26xx}/dev/rf-prop-mode.c (100%) rename arch/cpu/{simplelink => cc13xx-cc26xx}/dev/rtimer-arch.c (84%) rename arch/cpu/{simplelink => cc13xx-cc26xx}/dev/rtimer-arch.h (100%) rename arch/cpu/{simplelink => cc13xx-cc26xx}/dev/slip-arch.c (100%) rename arch/cpu/{simplelink => cc13xx-cc26xx}/dev/uart0-arch.c (72%) rename arch/cpu/{simplelink => cc13xx-cc26xx}/dev/uart0-arch.h (87%) rename arch/cpu/{simplelink => cc13xx-cc26xx}/dev/watchdog-arch.c (100%) rename arch/cpu/{simplelink => cc13xx-cc26xx}/rf-settings/rf-ieee-settings.c (100%) rename arch/cpu/{simplelink => cc13xx-cc26xx}/rf-settings/rf-ieee-settings.h (100%) rename arch/cpu/{simplelink => cc13xx-cc26xx}/rf-settings/rf-prop-settings.c (100%) rename arch/cpu/{simplelink => cc13xx-cc26xx}/rf-settings/rf-prop-settings.h (100%) rename arch/cpu/{simplelink => cc13xx-cc26xx}/simplelink-conf.h (96%) delete mode 100644 arch/cpu/simplelink/Makefile.cc26x2_cc13x2 create mode 100644 arch/platform/simplelink/cc13x0-cc26x0/Makefile.cc13x0-cc26x0 rename arch/platform/simplelink/{dev => cc13x0-cc26x0/common}/als-sensor.h (100%) rename arch/platform/simplelink/{dev => cc13x0-cc26x0/common}/button-sensor.h (100%) rename arch/platform/simplelink/{ => cc13x0-cc26x0}/contiki-conf.h (100%) create mode 100644 arch/platform/simplelink/cc13x0-cc26x0/launchpad/Makefile.launchpad rename arch/platform/simplelink/{cc13x2_cc26x2 => cc13x0-cc26x0}/launchpad/button-sensor-arch.c (100%) rename arch/platform/simplelink/{cc13x2_cc26x2 => cc13x0-cc26x0}/launchpad/button-sensor-arch.h (100%) create mode 100644 arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc1310/Makefile.cc1310 create mode 100644 arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc1350-4/Makefile.cc1350-4 create mode 100644 arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc1350/Makefile.cc1350 create mode 100644 arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc2650/Makefile.cc2650 rename arch/platform/simplelink/{cc13x0_cc26x0 => cc13x0-cc26x0}/launchpad/launchpad-sensors.c (100%) rename arch/platform/simplelink/{dev => cc13x0-cc26x0/launchpad}/leds-arch.c (100%) rename arch/platform/simplelink/{ => cc13x0-cc26x0}/platform.c (95%) create mode 100644 arch/platform/simplelink/cc13x0-cc26x0/sensortag/Makefile.sensortag create mode 100644 arch/platform/simplelink/cc13x0-cc26x0/sensortag/cc1350/Makefile.cc1350 create mode 100644 arch/platform/simplelink/cc13x0-cc26x0/sensortag/cc2650/Makefile.cc2650 rename arch/platform/simplelink/{cc13x0_cc26x0/dev => cc13x0-cc26x0/sensortag}/sensortag-sensors.c (100%) create mode 100644 arch/platform/simplelink/cc13x0-cc26x0/srf06/Makefile.srf06 create mode 100644 arch/platform/simplelink/cc13x0-cc26x0/srf06/cc1310/Makefile.cc1310 create mode 100644 arch/platform/simplelink/cc13x0-cc26x0/srf06/cc1350/Makefile.cc1350 create mode 100644 arch/platform/simplelink/cc13x0-cc26x0/srf06/cc2650/Makefile.cc2650 rename arch/platform/simplelink/{cc13x0_cc26x0/dev => cc13x0-cc26x0/srf06}/srf06-sensors.c (100%) delete mode 100644 arch/platform/simplelink/cc13x0_cc26x0/Makefile.cc13x0_cc26x0 create mode 100644 arch/platform/simplelink/cc13x2-cc26x2/Makefile.cc13x2-cc26x2 rename arch/platform/simplelink/{cc13x2_cc26x2/srf06/als-sensor-arch.h => cc13x2-cc26x2/common/button-sensor.h} (70%) create mode 100644 arch/platform/simplelink/cc13x2-cc26x2/contiki-conf.h create mode 100644 arch/platform/simplelink/cc13x2-cc26x2/launchpad/Makefile.launchpad rename arch/platform/simplelink/{cc13x2_cc26x2/srf06 => cc13x2-cc26x2/launchpad}/button-sensor-arch.c (55%) rename arch/platform/simplelink/{cc13x2_cc26x2/srf06 => cc13x2-cc26x2/launchpad}/button-sensor-arch.h (90%) create mode 100644 arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc1312r1/Makefile.cc1312r1 create mode 100644 arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc1352p1/Makefile.cc1352p1 create mode 100644 arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc1352r1/Makefile.cc1352r1 create mode 100644 arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc26x2r1/Makefile.cc26x2r1 rename arch/platform/simplelink/{cc13x2_cc26x2 => cc13x2-cc26x2}/launchpad/launchpad-sensors.c (93%) rename arch/platform/simplelink/{cc13x2_cc26x2/srf06/als-sensor-arch.c => cc13x2-cc26x2/launchpad/leds-arch.c} (59%) create mode 100644 arch/platform/simplelink/cc13x2-cc26x2/platform.c delete mode 100644 arch/platform/simplelink/cc13x2_cc26x2/Makefile.cc13x2_cc26x2 diff --git a/arch/cpu/arm/Makefile.arm b/arch/cpu/arm/Makefile.arm index 0c71d63fa..dd00aae6d 100644 --- a/arch/cpu/arm/Makefile.arm +++ b/arch/cpu/arm/Makefile.arm @@ -26,7 +26,7 @@ SMALL ?= 1 ifeq ($(SMALL),1) CFLAGS += -Os else - CFLAGS += -O2 + CFLAGS += -O0 endif ### Use CMSIS and the existing dbg-io from arch/cpu/arm/common diff --git a/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 b/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 index 8215571e0..5c4d4526b 100644 --- a/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 +++ b/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 @@ -7,7 +7,7 @@ LDFLAGS += -T $(LDSCRIPT) LDFLAGS += -Wl,--gc-sections,--sort-section=alignment LDFLAGS += -Wl,-Map=$(@:.elf=-$(TARGET).map),--cref,--no-warn-mismatch -TARGET_LIBFLAGS := $(TARGET_LIBFILES) -gcc -lm -lnosys -lc +TARGET_LIBFLAGS := $(TARGET_LIBFILES) -lc -lgcc -lm -lnosys OBJCOPY_FLAGS += --gap-fill 0xff diff --git a/arch/cpu/simplelink/Makefile.cc26x0_cc13x0 b/arch/cpu/cc13xx-cc26xx/Makefile.cc13x0-cc26x0 similarity index 97% rename from arch/cpu/simplelink/Makefile.cc26x0_cc13x0 rename to arch/cpu/cc13xx-cc26xx/Makefile.cc13x0-cc26x0 index 707d20722..15dd27e99 100644 --- a/arch/cpu/simplelink/Makefile.cc26x0_cc13x0 +++ b/arch/cpu/cc13xx-cc26xx/Makefile.cc13x0-cc26x0 @@ -1,3 +1,5 @@ +################################################################################ +# CC13x0/CC26x0 CPU makefile CPU_ABS_PATH = arch/cpu/simplelink diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.cc13x2-cc26x2 b/arch/cpu/cc13xx-cc26xx/Makefile.cc13x2-cc26x2 new file mode 100644 index 000000000..7b772f07d --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/Makefile.cc13x2-cc26x2 @@ -0,0 +1,74 @@ +################################################################################ +# CC13x2/CC26x2 CPU makefile + +# ccfg.c comes from the board-specific folder, and startup_cc13xx_cc26xx_gcc.c +# comes from NoRTOS startup folder +CPU_START_SOURCEFILES += ccfg.c startup_cc13xx_cc26xx_gcc.c + +EXTERNALDIRS += $(SDK_SOURCE) +EXTERNALDIRS += $(SDK_KERNEL) +EXTERNALDIRS += $(SDK_KERNEL)/startup +EXTERNALDIRS += $(SDK_BOARD_PATH) +EXTERNALDIRS += $(SDK_DEVICE) + +### If the user-specified a Node ID, pass a define +ifdef NODEID +DEFINES += IEEE_ADDR_NODE_ID=$(NODEID) +endif + +### CPU-dependent source files +CONTIKI_CPU_SOURCEFILES += rtimer-arch.c clock-arch.c +CONTIKI_CPU_SOURCEFILES += watchdog-arch.c putchar-arch.c +CONTIKI_CPU_SOURCEFILES += uart0-arch.c slip-arch.c +CONTIKI_CPU_SOURCEFILES += rf-common.c +CONTIKI_CPU_SOURCEFILES += rf-prop-mode.c rf-prop-settings.c +CONTIKI_CPU_SOURCEFILES += rf-ieee-mode.c rf-ieee-settings.c +CONTIKI_CPU_SOURCEFILES += ieee-addr.c + +### CPU-dependent directories +CONTIKI_CPU_DIRS += $(addprefix ../arm/, $(CPU_DIRS)) +CONTIKI_CPU_DIRS += . dev rf-settings cc13x2-cc26x2 + +### CPU-dependent debug source files +DEBUG_IO_SOURCEFILES += dbg-printf.c dbg-snprintf.c dbg-sprintf.c strformat.c + +CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES) $(DEBUG_IO_SOURCEFILES) + +ifeq ($(SMALL),0) +TARGET_LIBFILES += $(SDK_KERNEL)/lib/nortos_$(DEVICE_FAMILY_NAME).am4f +TARGET_LIBFILES += $(SDK_DRIVERS)/rf/lib/rf_multiMode_$(DEVICE_FAMILY_NAME).am4f +TARGET_LIBFILES += $(SDK_DRIVERS)/lib/drivers_$(DEVICE_FAMILY_NAME).am4f +TARGET_LIBFILES += $(SDK_DEVICE)/driverlib/bin/gcc/driverlib.lib +else +TARGET_LIBFILES += $(SDK_KERNEL)/lib/nortos_$(DEVICE_FAMILY_NAME).am4fg +TARGET_LIBFILES += $(SDK_DRIVERS)/rf/lib/rf_multiMode_$(DEVICE_FAMILY_NAME).am4fg +TARGET_LIBFILES += $(SDK_DRIVERS)/lib/drivers_$(DEVICE_FAMILY_NAME).am4fg +TARGET_LIBFILES += $(SDK_DEVICE)/driverlib/bin/gcc/driverlib.lib +endif + +LDFLAGS += --entry resetISR +LDFLAGS += -static +LDFLAGS += --specs=nano.specs +# NB! The symbol _stack, which points to the stack start, is expected to be defined, +# but should already be defined in the linker script. +LDFLAGS += -Wl,--defsym=_stack_origin=__stack_end +LDFLAGS += -Wl,--defsym=_heap=__heap_start__ +LDFLAGS += -Wl,--defsym=_eheap=__heap_end__ +LDFLAGS += -Wl,--defsym=STACKSIZE=2048 + +LDSCRIPT := $(SDK_BOARD_PATH)/$(SDK_BOARD_NAME)_NoRTOS.lds + +### Always re-build ieee-addr.o in case the command line passes a new NODEID +FORCE: + +$(OBJECTDIR)/ieee-addr.o: ieee-addr.c FORCE | $(OBJECTDIR) + $(TRACE_CC) + $(Q)$(CC) $(CFLAGS) -c $< -o $@ + +### Always re-build ccfg.c so changes to ccfg-conf.h will apply without having +### to make clean first +$(OBJECTDIR)/ccfg.o: ccfg.c FORCE | $(OBJECTDIR) + $(TRACE_CC) + $(Q)$(CC) $(CFLAGS) -include "ccfg-conf.h" -c $< -o $@ + +include $(CONTIKI)/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 diff --git a/arch/cpu/simplelink/Makefile.simplelink b/arch/cpu/cc13xx-cc26xx/Makefile.simplelink similarity index 96% rename from arch/cpu/simplelink/Makefile.simplelink rename to arch/cpu/cc13xx-cc26xx/Makefile.simplelink index 8f6a1e51c..4036246ee 100644 --- a/arch/cpu/simplelink/Makefile.simplelink +++ b/arch/cpu/cc13xx-cc26xx/Makefile.simplelink @@ -1,7 +1,7 @@ MODULES += os/net/mac/framer -CPU_ABS_PATH = $(CONTIKI)/arch/cpu/simplelink +CPU_ABS_PATH = $(CONTIKI)/arch/cpu/cc13xx-cc26xx SDK_SOURCE := $(SIMPLELINK_SDK)/source # TODO fix switch @@ -23,10 +23,10 @@ EXTERNALDIRS += $(SDK_STARTUP) CFLAGS += -I$(CPU_ABS_PATH) CFLAGS += -I$(CPU_ABS_PATH)/source CFLAGS += -I$(SDK_SOURCE) -CFLAGS += -I$(SDK_DEVICE_SOURCE) +CFLAGS += -I$(SDK_DEVICE_SOposixURCE) CFLAGS += -I$(SDK_DEVICE_SOURCE)/inc CFLAGS += -I$(SDK_KERNEL) -CFLAGS += -I$(SDK_KERNEL)/posix +CFLAGS += -I$(SDK_KERNEL)/ LDFLAGS += --entry resetISR LDFLAGS += -static @@ -37,8 +37,6 @@ LDFLAGS += -Wl,--defsym=_stack_origin=__stack_end LDFLAGS += -Wl,--defsym=_heap=__heap_start__ LDFLAGS += -Wl,--defsym=_eheap=__heap_end__ -SDK_BOARDS := - ifneq ($(SIMPLELINK_BOARD),CUSTOM) SDK_BOARDS := $(SDK_SOURCE)/ti/boards LDSCRIPT = $(SDK_BOARDS)/$(SIMPLELINK_BOARD)/$(SIMPLELINK_BOARD)_NoRTOS.lds diff --git a/arch/cpu/simplelink/cc26x0_cc13x0/cc13x0-cc26x0-cm3.h b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0-cm3.h similarity index 100% rename from arch/cpu/simplelink/cc26x0_cc13x0/cc13x0-cc26x0-cm3.h rename to arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0-cm3.h diff --git a/arch/cpu/simplelink/cc26x0_cc13x0/cc13x0-cc26x0-def.h b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0-def.h similarity index 100% rename from arch/cpu/simplelink/cc26x0_cc13x0/cc13x0-cc26x0-def.h rename to arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0-def.h diff --git a/arch/cpu/simplelink/cc26x0_cc13x0/simplelink-def.h b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/simplelink-def.h similarity index 100% rename from arch/cpu/simplelink/cc26x0_cc13x0/simplelink-def.h rename to arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/simplelink-def.h diff --git a/arch/cpu/simplelink/cc26x2_cc13x2/cc13x2-cc26x2-cm4.h b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2-cm4.h similarity index 100% rename from arch/cpu/simplelink/cc26x2_cc13x2/cc13x2-cc26x2-cm4.h rename to arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2-cm4.h diff --git a/arch/cpu/simplelink/cc26x2_cc13x2/cc13x2-cc26x2-def.h b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2-def.h similarity index 100% rename from arch/cpu/simplelink/cc26x2_cc13x2/cc13x2-cc26x2-def.h rename to arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2-def.h diff --git a/arch/cpu/simplelink/cc26x2_cc13x2/simplelink-def.h b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/simplelink-def.h similarity index 100% rename from arch/cpu/simplelink/cc26x2_cc13x2/simplelink-def.h rename to arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/simplelink-def.h diff --git a/arch/cpu/simplelink/ccfg-conf.h b/arch/cpu/cc13xx-cc26xx/ccfg-conf.h similarity index 97% rename from arch/cpu/simplelink/ccfg-conf.h rename to arch/cpu/cc13xx-cc26xx/ccfg-conf.h index 97be16b5d..0f5c4894e 100644 --- a/arch/cpu/simplelink/ccfg-conf.h +++ b/arch/cpu/cc13xx-cc26xx/ccfg-conf.h @@ -38,8 +38,8 @@ * \file * CCxxware-specific configuration for the cc26xx-cc13xx CPU family */ -#ifndef CCXXWARE_CONF_H_ -#define CCXXWARE_CONF_H_ +#ifndef CCFG_CONF_H_ +#define CCFG_CONF_H_ #include "contiki-conf.h" @@ -68,7 +68,7 @@ #define SET_CCFG_CCFG_TAP_DAP_1_WUC_TAP_ENABLE 0x00 #endif /** @} */ -#endif /* CCXXWARE_CONF_H_ */ +#endif /* CCFG_CONF_H_ */ /*---------------------------------------------------------------------------*/ /** * @} diff --git a/arch/cpu/simplelink/dev/clock-arch.c b/arch/cpu/cc13xx-cc26xx/dev/clock-arch.c similarity index 100% rename from arch/cpu/simplelink/dev/clock-arch.c rename to arch/cpu/cc13xx-cc26xx/dev/clock-arch.c diff --git a/arch/cpu/simplelink/dev/dbg.h b/arch/cpu/cc13xx-cc26xx/dev/dbg.h similarity index 100% rename from arch/cpu/simplelink/dev/dbg.h rename to arch/cpu/cc13xx-cc26xx/dev/dbg.h diff --git a/arch/cpu/simplelink/dev/debug-uart.h b/arch/cpu/cc13xx-cc26xx/dev/debug-uart.h similarity index 100% rename from arch/cpu/simplelink/dev/debug-uart.h rename to arch/cpu/cc13xx-cc26xx/dev/debug-uart.h diff --git a/arch/cpu/simplelink/dev/dot-15-4g.h b/arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h similarity index 100% rename from arch/cpu/simplelink/dev/dot-15-4g.h rename to arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h diff --git a/arch/cpu/simplelink/dev/ieee-addr.c b/arch/cpu/cc13xx-cc26xx/dev/ieee-addr.c similarity index 100% rename from arch/cpu/simplelink/dev/ieee-addr.c rename to arch/cpu/cc13xx-cc26xx/dev/ieee-addr.c diff --git a/arch/cpu/simplelink/dev/ieee-addr.h b/arch/cpu/cc13xx-cc26xx/dev/ieee-addr.h similarity index 98% rename from arch/cpu/simplelink/dev/ieee-addr.h rename to arch/cpu/cc13xx-cc26xx/dev/ieee-addr.h index 017ed138e..87d07d7e6 100644 --- a/arch/cpu/simplelink/dev/ieee-addr.h +++ b/arch/cpu/cc13xx-cc26xx/dev/ieee-addr.h @@ -81,7 +81,7 @@ #ifdef IEEE_ADDR_CONF_LOCATION_SECONDARY #define IEEE_ADDR_LOCATION_SECONDARY IEEE_ADDR_CONF_LOCATION_SECONDARY #else -#define IEEE_ADDR_LOCATION_SECONDARY 0x0001FFC8 /**< Secondary IEEE address location */ +#define IEEE_ADDR_LOCATION_SECONDARY 0x00057FC8 /**< Secondary IEEE address location */ #endif /** @} */ /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/simplelink/dev/putchar-arch.c b/arch/cpu/cc13xx-cc26xx/dev/putchar-arch.c similarity index 100% rename from arch/cpu/simplelink/dev/putchar-arch.c rename to arch/cpu/cc13xx-cc26xx/dev/putchar-arch.c diff --git a/arch/platform/simplelink/cc13x2_cc26x2/srf06/srf06-sensors.c b/arch/cpu/cc13xx-cc26xx/dev/random-arch.c similarity index 78% rename from arch/platform/simplelink/cc13x2_cc26x2/srf06/srf06-sensors.c rename to arch/cpu/cc13xx-cc26xx/dev/random-arch.c index ea0283fe0..87962e501 100644 --- a/arch/platform/simplelink/cc13x2_cc26x2/srf06/srf06-sensors.c +++ b/arch/cpu/cc13xx-cc26xx/dev/random-arch.c @@ -10,6 +10,7 @@ * 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. @@ -29,27 +30,38 @@ */ /*---------------------------------------------------------------------------*/ /** - * \addtogroup srf06-peripherals + * \addtogroup cc26xx-trng * @{ * * \file - * Generic module controlling sensors on the SmartRF06EB + * + * This file overrides os/lib/random.c and calls SoC-specific RNG functions */ /*---------------------------------------------------------------------------*/ #include -#include /*---------------------------------------------------------------------------*/ -#include "button-sensor-arch.h" -#include "als-sensor-arch.h" +#include /*---------------------------------------------------------------------------*/ -/* Exports a global symbol to be used by the sensor API */ -SENSORS( - &button_select_sensor, - &button_up_sensor, - &button_down_sensor, - &button_left_sensor, - &button_right_sensor, - &als_sensor -); +/** + * \brief Generates a new random number using the hardware TRNG. + * \return The random number. + */ +unsigned short +random_rand(void) +{ + return (unsigned short)soc_trng_rand_synchronous() & 0xFFFF; +} /*---------------------------------------------------------------------------*/ -/** @} */ +/** + * \brief Function required by the API + * \param seed Ignored. + */ +void +random_init(unsigned short seed) +{ + soc_trng_init(); +} +/*---------------------------------------------------------------------------*/ +/** + * @} + */ diff --git a/arch/cpu/simplelink/dev/rf-common.c b/arch/cpu/cc13xx-cc26xx/dev/rf-common.c similarity index 98% rename from arch/cpu/simplelink/dev/rf-common.c rename to arch/cpu/cc13xx-cc26xx/dev/rf-common.c index e4538e53b..76d6f31f2 100644 --- a/arch/cpu/simplelink/dev/rf-common.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-common.c @@ -52,7 +52,7 @@ /*---------------------------------------------------------------------------*/ /* Log configuration */ #include "sys/log.h" -#define LOG_MODULE "RF common" +#define LOG_MODULE "RF" #define LOG_LEVEL LOG_LEVEL_DBG /*---------------------------------------------------------------------------*/ PROCESS(RF_coreProcess, "SimpleLink RF process"); @@ -66,7 +66,7 @@ PROCESS_THREAD(RF_coreProcess, ev, data) while(1) { PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL); do { - watchdog_periodic(); + //watchdog_periodic(); packetbuf_clear(); len = NETSTACK_RADIO.read(packetbuf_dataptr(), PACKETBUF_SIZE); diff --git a/arch/cpu/simplelink/dev/rf-common.h b/arch/cpu/cc13xx-cc26xx/dev/rf-common.h similarity index 100% rename from arch/cpu/simplelink/dev/rf-common.h rename to arch/cpu/cc13xx-cc26xx/dev/rf-common.h diff --git a/arch/cpu/simplelink/dev/rf-ieee-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c similarity index 91% rename from arch/cpu/simplelink/dev/rf-ieee-mode.c rename to arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c index 393eaa3f4..942c9d343 100644 --- a/arch/cpu/simplelink/dev/rf-ieee-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c @@ -58,26 +58,31 @@ #include #include /*---------------------------------------------------------------------------*/ +/* SimpleLink Platform RF dev */ +#include "rf-common.h" +#include "dot-15-4g.h" +/*---------------------------------------------------------------------------*/ /* RF settings */ #ifdef IEEE_MODE_CONF_RF_SETTINGS # define IEEE_MODE_RF_SETTINGS IEEE_MODE_CONF_RF_SETTINGS -# undef IEEE_MODE_CONF_RF_SETTINGS #else # define IEEE_MODE_RF_SETTINGS "rf-settings/rf-ieee-settings.h" #endif #include IEEE_MODE_RF_SETTINGS /*---------------------------------------------------------------------------*/ -/* Simplelink Platform RF dev */ -#include "rf-common.h" -#include "dot-15-4g.h" -/*---------------------------------------------------------------------------*/ #include +#include #include #include #include #include /*---------------------------------------------------------------------------*/ +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "RF" +#define LOG_LEVEL LOG_LEVEL_NONE +/*---------------------------------------------------------------------------*/ #ifdef NDEBUG # define PRINTF(...) #else @@ -89,7 +94,6 @@ /* Configuration to enable/disable auto ACKs in IEEE mode */ #ifdef IEEE_MODE_CONF_AUTOACK # define IEEE_MODE_AUTOACK IEEE_MODE_CONF_AUTOACK -# undef IEEE_MODE_CONF_AUTOACK #else # define IEEE_MODE_AUTOACK 1 #endif /* IEEE_MODE_CONF_AUTOACK */ @@ -97,7 +101,6 @@ /* Configuration to enable/disable frame filtering in IEEE mode */ #ifdef IEEE_MODE_CONF_PROMISCOUS # define IEEE_MODE_PROMISCOUS IEEE_MODE_CONF_PROMISCOUS -# undef IEEE_MODE_CONF_PROMISCOUS #else # define IEEE_MODE_PROMISCOUS 0 #endif /* IEEE_MODE_CONF_PROMISCOUS */ @@ -105,7 +108,6 @@ /* Configuration to set the RSSI threshold */ #ifdef IEEE_MODE_CONF_RSSI_THRESHOLD # define IEEE_MODE_RSSI_THRESHOLD IEEE_MODE_CONF_RSSI_THRESHOLD -# undef IEEE_MODE_CONF_RSSI_THRESHOLD #else # define IEEE_MODE_RSSI_THRESHOLD 0xA6 #endif /* IEEE_MODE_CONF_RSSI_THRESHOLD */ @@ -113,7 +115,6 @@ /* Configuration for default IEEE channel */ #ifdef IEEE_MODE_CONF_CHANNEL # define IEEE_MODE_CHANNEL IEEE_MODE_CONF_CHANNEL -# undef IEEE_MODE_CONF_CHANNEL #else # define IEEE_MODE_CHANNEL RF_CORE_CHANNEL #endif @@ -121,14 +122,12 @@ /* Configuration for TX power table */ #ifdef TX_POWER_CONF_DRIVER # define TX_POWER_DRIVER TX_POWER_CONF_DRIVER -# undef TX_POWER_CONF_DRIVER #else # define TX_POWER_DRIVER RF_ieeeTxPower #endif #ifdef TX_POWER_CONF_COUNT # define TX_POWER_COUNT TX_POWER_CONF_COUNT -# undef TX_POWER_CONF_COUNT #else # define TX_POWER_COUNT RF_ieeeTxPowerLen #endif @@ -222,7 +221,7 @@ static RxBuf g_rxBufs[RX_BUF_ENTRIES]; /*---------------------------------------------------------------------------*/ /* RAT overflow upkeep */ static struct ctimer g_ratOverflowTimer; -static rtimer_clock_t g_lastRatOverflow; +static rtimer_clock_t g_ratLastOverflow; static volatile uint32_t g_ratOverflowCount; #define RAT_RANGE (~(uint32_t)0) @@ -256,27 +255,70 @@ static volatile uint8_t g_lastCorrLqi; static volatile uint32_t g_lastTimestamp; /*---------------------------------------------------------------------------*/ typedef enum { - POWER_STATE_ON, - POWER_STATE_OFF, - POWER_STATE_RESTART, + POWER_STATE_ON = (1 << 0), + POWER_STATE_OFF = (1 << 1), + POWER_STATE_RESTART = (1 << 2), } PowerState; /*---------------------------------------------------------------------------*/ /* Forward declarations of static functions */ -static int on(void); -static int off(void); static int set_rx(const PowerState); -static int channel_clear(void); static void check_rat_overflow(void); static bool rf_is_on(void); static uint32_t rat_to_timestamp(const uint32_t); /*---------------------------------------------------------------------------*/ +/* Forward declarations of Radio driver functions */ +static int init(void); +static int prepare(const void*, unsigned short); +static int transmit(unsigned short); +static int send(const void*, unsigned short); +static int read(void*, unsigned short); +static int channel_clear(void); +static int receiving_packet(void); +static int pending_packet(void); +static int on(void); +static int off(void); +static radio_result_t get_value(radio_param_t, radio_value_t*); +static radio_result_t set_value(radio_param_t, radio_value_t); +static radio_result_t get_object(radio_param_t, void*, size_t); +static radio_result_t set_object(radio_param_t, const void*, size_t); +/*---------------------------------------------------------------------------*/ +/* Radio driver object */ +const struct radio_driver ieee_mode_driver = { + init, + prepare, + transmit, + send, + read, + channel_clear, + receiving_packet, + pending_packet, + on, + off, + get_value, + set_value, + get_object, + set_object, +}; +/*---------------------------------------------------------------------------*/ static void -synth_error_cb(RF_Handle h, RF_CmdHandle ch, RF_EventMask e) +rx_cb(RF_Handle h, RF_CmdHandle ch, RF_EventMask e) { + if (e & RF_EventRxOk) { + process_poll(&RF_coreProcess); + } + if (e & RF_EventRxBufFull) { + + } +} +/*---------------------------------------------------------------------------*/ +static void +rf_error_cb(RF_Handle h, RF_CmdHandle ch, RF_EventMask e) +{ + // See SWRZ062B: Synth failed to calibrate, CMD_FS must be repeated if ((ch == RF_ERROR_CMDFS_SYNTH_PROG) && (g_vpCmdFs->status == ERROR_SYNTH_PROG)) { - // See SWRA521: Synth failed to calibrate, CMD_FS must be repeated - RF_postCmd(g_rfHandle, (RF_Op*)g_vpCmdFs, RF_PriorityNormal, synth_error_cb, 0); + // Call CMD_FS async, a synth error will trigger rf_error_cb once more + RF_postCmd(g_rfHandle, (RF_Op*)g_vpCmdFs, RF_PriorityNormal, NULL, 0); } } /*---------------------------------------------------------------------------*/ @@ -375,7 +417,7 @@ set_channel(uint8_t channel) g_vpCmdFs->fractFreq = frac; // Start FS command asynchronously. We don't care when it is finished - RF_postCmd(g_rfHandle, (RF_Op*)g_vpCmdFs, RF_PriorityNormal, synth_error_cb, 0); + RF_postCmd(g_rfHandle, (RF_Op*)g_vpCmdFs, RF_PriorityNormal, NULL, 0); if (g_vpCmdRx->status == ACTIVE) { set_rx(POWER_STATE_RESTART); } @@ -431,7 +473,7 @@ set_send_on_cca(bool enable) static void check_rat_overflow(void) { - const bool was_off = rf_is_on(); + const bool was_off = !rf_is_on(); if (was_off) { RF_runDirectCmd(g_rfHandle, CMD_NOP); } @@ -446,7 +488,7 @@ check_rat_overflow(void) // Overflow happens in the last quarter of the RAT range if (currentValue + RAT_RANGE / 4 < lastValue) { // Overflow detected - g_lastRatOverflow = RTIMER_NOW(); + g_ratLastOverflow = RTIMER_NOW(); g_ratOverflowCount += 1; } } @@ -465,11 +507,11 @@ rat_to_timestamp(const uint32_t ratTimestamp) uint64_t adjustedOverflowCount = g_ratOverflowCount; - // If the timestamp is in the 4th quarter and the last oveflow was recently, + // If the timestamp is in the 4th quarter and the last overflow was recently, // assume that the timestamp refers to the time before the overflow if(ratTimestamp > (uint32_t)(RAT_RANGE * 3 / 4)) { if(RTIMER_CLOCK_LT(RTIMER_NOW(), - g_lastRatOverflow + RAT_OVERFLOW_PERIOD_SECONDS * RTIMER_SECOND / 4)) { + g_ratLastOverflow + RAT_OVERFLOW_PERIOD_SECONDS * RTIMER_SECOND / 4)) { adjustedOverflowCount -= 1; } } @@ -488,6 +530,7 @@ init(void) RF_Params_init(¶ms); // Disable automatic power-down just to not interfere with stack timing params.nInactivityTimeout = 0; + params.pErrCb = rf_error_cb; init_rf_params(); init_data_queue(); @@ -532,13 +575,13 @@ rf_is_on(void) static int set_rx(const PowerState state) { - if (state == POWER_STATE_OFF || state == POWER_STATE_RESTART) { + if (state & (POWER_STATE_OFF | POWER_STATE_RESTART)) { // Stop RX gracefully, don't care about the result const uint8_t stopGracefully = 1; RF_cancelCmd(g_rfHandle, g_cmdRxHandle, stopGracefully); } - if (state == POWER_STATE_ON || state == POWER_STATE_RESTART) { + if (state & (POWER_STATE_ON | POWER_STATE_RESTART)) { if (g_vpCmdRx->status == ACTIVE) { PRINTF("set_rx(on): already in RX\n"); return CMD_RESULT_OK; @@ -547,11 +590,12 @@ set_rx(const PowerState state) RF_ScheduleCmdParams schedParams = { .endTime = 0, .priority = RF_PriorityNormal, - .bIeeeBgCmd = true, + //.bIeeeBgCmd = true, }; g_vpCmdRx->status = IDLE; - g_cmdRxHandle = RF_scheduleCmd(g_rfHandle, (RF_Op*)g_vpCmdRx, &schedParams, NULL, 0); + g_cmdRxHandle = RF_scheduleCmd(g_rfHandle, (RF_Op*)g_vpCmdRx, &schedParams, rx_cb, + RF_EventRxOk | RF_EventRxBufFull | RF_EventRxEntryDone); if ((g_cmdRxHandle == RF_ALLOC_ERROR) || (g_cmdRxHandle == RF_SCHEDULE_CMD_ERROR)) { PRINTF("transmit: unable to allocate RX command\n"); return CMD_RESULT_ERROR; @@ -573,7 +617,7 @@ transmit_aux(unsigned short transmit_len) RF_ScheduleCmdParams schedParams = { .endTime = 0, .priority = RF_PriorityNormal, - .bIeeeBgCmd = false, + //.bIeeeBgCmd = false, }; // As IEEE_TX is a FG command, the TX operation will be executed @@ -632,14 +676,14 @@ release_data_entry(void) rfc_dataEntryGeneral_t *pEntry = (rfc_dataEntryGeneral_t *)g_pRxReadEntry; // Clear the length byte and set status to 0: "Pending" - pEntry->length = 0; + g_pRxReadEntry[8] = 0; pEntry->status = DATA_ENTRY_PENDING; // Set next entry g_pRxReadEntry = pEntry->pNextEntry; } /*---------------------------------------------------------------------------*/ static int -read_frame(void *buf, unsigned short buf_len) +read(void *buf, unsigned short buf_len) { volatile rfc_dataEntryGeneral_t *pEntry = (rfc_dataEntryGeneral_t *)g_pRxReadEntry; @@ -654,29 +698,30 @@ read_frame(void *buf, unsigned short buf_len) } // FIXME: something is wrong here about length constraints - if (pEntry->length < 4) { - PRINTF("read_frame: frame too short \n"); + const uint8_t frame_len = g_pRxReadEntry[8]; + if (frame_len < 8) { + PRINTF("read_frame: frame too short len=%d\n", frame_len); release_data_entry(); return 0; } - const int frame_len = pEntry->length - 8; + const uint8_t payload_len = frame_len - 8; - if (frame_len > buf_len) { + if (payload_len > buf_len) { PRINTF("read_frame: frame larger than buffer\n"); release_data_entry(); return 0; } - const uint8_t *pData = (uint8_t *)&pEntry->data; + const uint8_t *pData = (uint8_t *)&g_pRxReadEntry[9]; - memcpy(buf, pData, frame_len); + memcpy(buf, pData, payload_len); - g_lastRssi = (int8_t)(pData[frame_len + 2]); - g_lastCorrLqi = (uint8_t)(pData[frame_len + 3]) & STATUS_CORRELATION; + g_lastRssi = (int8_t)(pData[payload_len + 2]); + g_lastCorrLqi = (uint8_t)(pData[payload_len + 3]) & STATUS_CORRELATION; uint32_t ratTimestamp; - memcpy(&ratTimestamp, pData + frame_len + 4, sizeof(ratTimestamp)); + memcpy(&ratTimestamp, pData + payload_len + 4, sizeof(ratTimestamp)); g_lastTimestamp = rat_to_timestamp(ratTimestamp); if (!g_bPollMode) { @@ -689,7 +734,7 @@ read_frame(void *buf, unsigned short buf_len) release_data_entry(); - return frame_len; + return payload_len; } /*---------------------------------------------------------------------------*/ static int @@ -799,7 +844,8 @@ on(void) static int off(void) { - set_rx(POWER_STATE_OFF); + const uint8_t stopGracefully = 1; + RF_flushCmd(g_rfHandle, RF_CMDHANDLE_FLUSH_ALL, stopGracefully); RF_yield(g_rfHandle); ENERGEST_OFF(ENERGEST_TYPE_LISTEN); @@ -825,7 +871,9 @@ get_value(radio_param_t param, radio_value_t *value) switch (param) { case RADIO_PARAM_POWER_MODE: - *value = rf_is_on() ? RADIO_POWER_MODE_ON : RADIO_POWER_MODE_OFF; + *value = rf_is_on() + ? RADIO_POWER_MODE_ON + : RADIO_POWER_MODE_OFF; return RADIO_RESULT_OK; case RADIO_PARAM_CHANNEL: @@ -1076,23 +1124,6 @@ set_object(radio_param_t param, const void *src, size_t size) } } /*---------------------------------------------------------------------------*/ -const struct radio_driver ieee_mode_driver = { - init, - prepare, - transmit, - send, - read_frame, - channel_clear, - receiving_packet, - pending_packet, - on, - off, - get_value, - set_value, - get_object, - set_object, -}; -/*---------------------------------------------------------------------------*/ /** * @} * @} diff --git a/arch/cpu/simplelink/dev/rf-prop-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c similarity index 100% rename from arch/cpu/simplelink/dev/rf-prop-mode.c rename to arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c diff --git a/arch/cpu/simplelink/dev/rtimer-arch.c b/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c similarity index 84% rename from arch/cpu/simplelink/dev/rtimer-arch.c rename to arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c index c52eef128..05e8b51f3 100644 --- a/arch/cpu/simplelink/dev/rtimer-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c @@ -36,26 +36,27 @@ * Implementation of the arch-specific rtimer functions for the CC13xx/CC26xx */ /*---------------------------------------------------------------------------*/ +#include +#include DeviceFamily_constructPath(driverlib/aon_event.h) +#include DeviceFamily_constructPath(driverlib/aon_rtc.h) +#include DeviceFamily_constructPath(driverlib/interrupt.h) + #include - -#include -#include -#include - +/*---------------------------------------------------------------------------*/ #include "contiki.h" - +/*---------------------------------------------------------------------------*/ #include - -#define RTIMER_RTC_CH AON_RTC_CH1 - +/*---------------------------------------------------------------------------*/ +#define HWIP_RTC_CH AON_RTC_CH0 +#define RTIMER_RTC_CH AON_RTC_CH1 +/*---------------------------------------------------------------------------*/ static ClockP_Struct gClk; static ClockP_Handle hClk; - +/*---------------------------------------------------------------------------*/ typedef void (*IsrFxn)(void); typedef void (*HwiDispatchFxn)(void); static volatile HwiDispatchFxn hwiDispatch = NULL; - /*---------------------------------------------------------------------------*/ /** * \brief TODO @@ -75,7 +76,7 @@ rtimer_isr_hook(void) rtimer_run_next(); } - if (hwiDispatch && AONRTCEventGet(AON_RTC_CH0)) + if (hwiDispatch && AONRTCEventGet(HWIP_RTC_CH)) { hwiDispatch(); } @@ -91,6 +92,8 @@ rtimer_isr_hook(void) void rtimer_arch_init(void) { + const bool intkey = IntMasterDisable(); + // Create dummy clock to trigger init of the RAM vector table ClockP_Params clkParams; ClockP_Params_init(&clkParams); @@ -115,7 +118,12 @@ rtimer_arch_init(void) IntRegister(INT_AON_RTC_COMB, rtimer_isr_hook); AONEventMcuWakeUpSet(AON_EVENT_MCU_WU1, AON_EVENT_RTC_CH1); - AONRTCCombinedEventConfig(AON_RTC_CH0 | RTIMER_RTC_CH); + AONRTCCombinedEventConfig(HWIP_RTC_CH | RTIMER_RTC_CH); + + if (!intkey) + { + IntMasterEnable(); + } } /*---------------------------------------------------------------------------*/ /** diff --git a/arch/cpu/simplelink/dev/rtimer-arch.h b/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.h similarity index 100% rename from arch/cpu/simplelink/dev/rtimer-arch.h rename to arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.h diff --git a/arch/cpu/simplelink/dev/slip-arch.c b/arch/cpu/cc13xx-cc26xx/dev/slip-arch.c similarity index 100% rename from arch/cpu/simplelink/dev/slip-arch.c rename to arch/cpu/cc13xx-cc26xx/dev/slip-arch.c diff --git a/arch/cpu/simplelink/dev/uart0-arch.c b/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c similarity index 72% rename from arch/cpu/simplelink/dev/uart0-arch.c rename to arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c index b80e9c736..3c662d0d2 100644 --- a/arch/cpu/simplelink/dev/uart0-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c @@ -38,26 +38,36 @@ /*---------------------------------------------------------------------------*/ #include #include - +/*---------------------------------------------------------------------------*/ +#include +/*---------------------------------------------------------------------------*/ #include - +#include +#include +/*---------------------------------------------------------------------------*/ #include "uart0-arch.h" - +/*---------------------------------------------------------------------------*/ static UART_Handle gh_uart; static volatile uart0_input_cb g_input_cb; static unsigned char g_char_buf; +static bool g_bIsInit = false; /*---------------------------------------------------------------------------*/ static void uart0_cb(UART_Handle handle, void *buf, size_t count) { if (!g_input_cb) { return; } + // Save the current callback function, as this might be overwritten after + // the callback is called. const uart0_input_cb currCb = g_input_cb; + // Call the callback. Note this might reset g_input_cb currCb(g_char_buf); - if (currCb == g_input_cb) - { + // If the callback pointer didn't change after the call, do another read. + // Else, the uart0_set_callback was called with a different callback pointer + // and triggered an another read. + if (currCb == g_input_cb) { UART_read(gh_uart, &g_char_buf, 1); } } @@ -65,10 +75,16 @@ uart0_cb(UART_Handle handle, void *buf, size_t count) void uart0_init(void) { + if (g_bIsInit) { return; } + g_bIsInit = true; + UART_init(); UART_Params params; UART_Params_init(¶ms); +#ifdef SIMPLELINK_UART_CONF_BAUD_RATE + params.baudRate = SIMPLELINK_UART_CONF_BAUD_RATE; +#endif params.readMode = UART_MODE_CALLBACK; params.writeMode = UART_MODE_BLOCKING; params.readCallback = uart0_cb; @@ -76,35 +92,36 @@ uart0_init(void) params.readReturnMode = UART_RETURN_NEWLINE; gh_uart = UART_open(Board_UART0, ¶ms); - if (!gh_uart) - { - for (;;) { /* hang */ } - } + assert(gh_uart != NULL); } /*---------------------------------------------------------------------------*/ int_fast32_t uart0_write(const void *buffer, size_t size) { - if (!gh_uart) - { + if (!g_bIsInit) { return UART_STATUS_ERROR; } return UART_write(gh_uart, buffer, size); } /*---------------------------------------------------------------------------*/ -void +int_fast32_t uart0_set_callback(uart0_input_cb input_cb) { - if (g_input_cb == input_cb) { return; } + if (!g_bIsInit) { + return UART_STATUS_ERROR; + } + + if (g_input_cb == input_cb) { + return UART_STATUS_SUCCESS; + } g_input_cb = input_cb; - if (input_cb) - { - UART_read(gh_uart, &g_char_buf, 1); + if (input_cb) { + return UART_read(gh_uart, &g_char_buf, 1); } - else - { + else { UART_readCancel(gh_uart); + return UART_STATUS_SUCCESS; } } /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/simplelink/dev/uart0-arch.h b/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.h similarity index 87% rename from arch/cpu/simplelink/dev/uart0-arch.h rename to arch/cpu/cc13xx-cc26xx/dev/uart0-arch.h index 0a54d2a73..2fd5eae42 100644 --- a/arch/cpu/simplelink/dev/uart0-arch.h +++ b/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.h @@ -66,18 +66,18 @@ void uart0_init(void); int_fast32_t uart0_write(const void *buffer, size_t size); /** - * \brief Reads data from the UART interface to a memory buffer. - * \param buffer A pointer to the data buffer. - * \param size Number of bytes to read - * \return Number of bytes that has been written to the buffer. If an - * error occurs, a negative value is returned. + * \brief Sets the callback function for when bytes are received + * on UART0. + * \param input_cb Pointer to the callback function. A valid pointer subscribes + * for UART0 callbacks when bytes are received, while a NULL pointer + * unsubscribes. + * \return 0 for success, negative value for errors. */ -void uart0_set_callback(uart0_input_cb input_cb); +int_fast32_t uart0_set_callback(uart0_input_cb input_cb); /** @} */ /*---------------------------------------------------------------------------*/ #endif /* UART0_ARCH_H_ */ - /** * @} * @} diff --git a/arch/cpu/simplelink/dev/watchdog-arch.c b/arch/cpu/cc13xx-cc26xx/dev/watchdog-arch.c similarity index 100% rename from arch/cpu/simplelink/dev/watchdog-arch.c rename to arch/cpu/cc13xx-cc26xx/dev/watchdog-arch.c diff --git a/arch/cpu/simplelink/rf-settings/rf-ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/rf-ieee-settings.c similarity index 100% rename from arch/cpu/simplelink/rf-settings/rf-ieee-settings.c rename to arch/cpu/cc13xx-cc26xx/rf-settings/rf-ieee-settings.c diff --git a/arch/cpu/simplelink/rf-settings/rf-ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/rf-ieee-settings.h similarity index 100% rename from arch/cpu/simplelink/rf-settings/rf-ieee-settings.h rename to arch/cpu/cc13xx-cc26xx/rf-settings/rf-ieee-settings.h diff --git a/arch/cpu/simplelink/rf-settings/rf-prop-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/rf-prop-settings.c similarity index 100% rename from arch/cpu/simplelink/rf-settings/rf-prop-settings.c rename to arch/cpu/cc13xx-cc26xx/rf-settings/rf-prop-settings.c diff --git a/arch/cpu/simplelink/rf-settings/rf-prop-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/rf-prop-settings.h similarity index 100% rename from arch/cpu/simplelink/rf-settings/rf-prop-settings.h rename to arch/cpu/cc13xx-cc26xx/rf-settings/rf-prop-settings.h diff --git a/arch/cpu/simplelink/simplelink-conf.h b/arch/cpu/cc13xx-cc26xx/simplelink-conf.h similarity index 96% rename from arch/cpu/simplelink/simplelink-conf.h rename to arch/cpu/cc13xx-cc26xx/simplelink-conf.h index 1db50738f..48844ae96 100644 --- a/arch/cpu/simplelink/simplelink-conf.h +++ b/arch/cpu/cc13xx-cc26xx/simplelink-conf.h @@ -148,12 +148,12 @@ * * @{ */ -#ifndef CC26XX_UART_CONF_ENABLE -#define CC26XX_UART_CONF_ENABLE 1 /**< Enable/Disable UART I/O */ +#ifndef SIMPLELINK_UART_CONF_ENABLE +#define SIMPLELINK_UART_CONF_ENABLE 1 /**< Enable/Disable UART I/O */ #endif -#ifndef CC26XX_UART_CONF_BAUD_RATE -#define CC26XX_UART_CONF_BAUD_RATE 115200 /**< Default UART0 baud rate */ +#ifndef SIMPLELINK_UART_CONF_BAUD_RATE +#define SIMPLELINK_UART_CONF_BAUD_RATE 115200 /**< Default UART0 baud rate */ #endif /* Enable I/O over the Debugger Devpack - Only relevant for the SensorTag */ diff --git a/arch/cpu/simplelink/Makefile.cc26x2_cc13x2 b/arch/cpu/simplelink/Makefile.cc26x2_cc13x2 deleted file mode 100644 index b828e4789..000000000 --- a/arch/cpu/simplelink/Makefile.cc26x2_cc13x2 +++ /dev/null @@ -1,10 +0,0 @@ - -CFLAGS += -I$(CPU_ABS_PATH)/cc26x2_cc13x2 -CFLAGS += -I$(SDK_KERNEL) - -TARGET_LIBFILES += $(SDK_DRIVERS)/rf/lib/rf_multiMode_cc13x2.am4fg -TARGET_LIBFILES += $(SDK_DRIVERS)/lib/drivers_cc13x2.am4fg -TARGET_LIBFILES += $(SDK_KERNEL)/lib/nortos_cc13x2.am4fg -TARGET_LIBFILES += $(SDK_DRIVERLIB)/bin/gcc/driverlib.lib - -include $(CONTIKI)/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 diff --git a/arch/platform/simplelink/Makefile.device-family b/arch/platform/simplelink/Makefile.device-family index 66d7be369..45f37f3fb 100644 --- a/arch/platform/simplelink/Makefile.device-family +++ b/arch/platform/simplelink/Makefile.device-family @@ -1,33 +1,79 @@ +################################################################################ # Simplelink Device family switch -# Device name in upper case -DEVICE_UC := $(shell echo $(SIMPLELINK_DEVICE) | tr a-z A-Z) +# A couple of comments: +# - CC26X0R2 is not supported even though it has its own Device SDK, because +# it is a BLE-only chip. +# - CC26X0 overrides the Device Makefile because it doesn't have its own +# Device SDK. Instead, it uses the TI-RTOS SDK, and therefore cannot +# use the same build structure as all other SimpleLink SDK Devices. -# CC13x0/CC26x0 Family -ifeq ($(DEVICE_UC),CC13X0) - FAMILY := cc13x0_cc26x0 - CFLAGS += -DDeviceFamily_CC13X0 -else ifeq ($(DEVICE_UC),CC26X0) - FAMILY := cc13x0_cc26x0 - CFLAGS += -DDeviceFamily_CC26X0 -else ifeq ($(DEVICE_UC),CC26X0R2) - FAMILY := cc13x0_cc26x0 - CFLAGS += -DDeviceFamily_CC26X0R2 +# Device name in lower case (LC) +SIMPLELINK_DEVICE_LC := $(shell echo $(SIMPLELINK_DEVICE) | tr A-Z a-z) +# Device name in upper case (UC) +SIMPLELINK_DEVICE_UC := $(shell echo $(SIMPLELINK_DEVICE) | tr a-z A-Z) -# CC13x2/CC26x2 Family -else ifeq ($(DEVICE_UC),CC13X2) - FAMILY := cc13x2_cc26x2 - CFLAGS += -DDeviceFamily_CC13X2 -else ifeq ($(DEVICE_UC),CC26X2) - FAMILY := cc13x2_cc26x2 - CFLAGS += -DDeviceFamily_CC26X2 +################################################################################ +# All supported SimpleLink Devices +SIMPLELINK_DEVICES = cc13x0 cc13x2 cc26x0 cc26x2 -# Not supported +################################################################################ +# CC13X0/CC26X0 Family + +# CC13X0 +ifeq ($(SIMPLELINK_DEVICE_LC),cc13x0) +PLATFORM_FAMILY_DIR := cc13x0-cc26x0 +DEVICE_FAMILY := DeviceFamily_CC13X0 +CFLAGS += -D$(DEVICE_FAMILY) + +# CC26X0 +else ifeq ($(SIMPLELINK_DEVICE_LC),cc26x0) +PLATFORM_FAMILY_DIR := cc13x0-cc26x0 +DEVICE_MAKEFILE := cc26x0 +DEVICE_FAMILY := DeviceFamily_CC26X0 +CFLAGS += -D$(DEVICE_FAMILY) + +################################################################################ +# CC13X2/CC26X2 Family + +# CC13X2 +else ifeq ($(SIMPLELINK_DEVICE_LC),cc13x2) +PLATFORM_FAMILY_DIR := cc13x2-cc26x2 +DEVICE_FAMILY := DeviceFamily_CC13X2 +CFLAGS += -D$(DEVICE_FAMILY) + +# CC26X2 +else ifeq ($(SIMPLELINK_DEVICE_LC),cc26x2) +PLATFORM_FAMILY_DIR := cc13x2-cc26x2 +DEVICE_FAMILY := DeviceFamily_CC26X2 +CFLAGS += -D$(DEVICE_FAMILY) + +################################################################################ +# Specified Device not supported else - $(error Simplelink Device '$(SIMPLELINK_DEVICE)' is not currently supported) + $(error Simplelink Device '$(SIMPLELINK_DEVICE)' is not supported) endif -CONTIKI_TARGET_DIRS += $(FAMILY)/dev +################################################################################ +# By default, the Device Makefile is common for all Devices in the Device Family +# unless overriden +ifndef DEVICE_MAKEFILE +DEVICE_MAKEFILE := $(PLATFORM_FAMILY_DIR) +endif -# Include the Family-specific makefile -include $(PLATFORM_ABS_PATH)/$(FAMILY)/Makefile.$(FAMILY) +PLATFORM_ROOT_DIR := $(SIMPLELINK_PATH)/$(PLATFORM_FAMILY_DIR) + +# Include the Family-specific Makefile +include $(PLATFORM_ROOT_DIR)/Makefile.$(DEVICE_MAKEFILE) + +# The dirs in CONTIKI_TARGET_DIRS will be appended the target makefile directory +# in Makefile.include as part of the CONTIKI_TARGET_DIRS_CONCAT variable, +# however, this does not take into account that the Simplelink platform has one +# more indirection of directories based on device families. This fixes the added +# indirection. +CONTIKI_TARGET_DIRS := $(addprefix $(PLATFORM_FAMILY_DIR)/, $(CONTIKI_TARGET_DIRS)) + +################################################################################ +# Rule for printing supported devices +simplelink_devices: + @echo "$(SIMPLELINK_DEVICES) (current: $(SIMPLELINK_DEVICE_LC))" diff --git a/arch/platform/simplelink/Makefile.simplelink b/arch/platform/simplelink/Makefile.simplelink index 628ecc85d..f666482f8 100644 --- a/arch/platform/simplelink/Makefile.simplelink +++ b/arch/platform/simplelink/Makefile.simplelink @@ -1,88 +1,33 @@ +################################################################################ # SimpleLink MCU platform makefile +################################################################################ +# Sanity check of expected symbols + ifndef CONTIKI $(error CONTIKI not defined! You must specify where CONTIKI resides!) endif -PLATFORM_ABS_PATH = $(CONTIKI)/arch/platform/simplelink - ifndef SIMPLELINK_SDK $(error SIMPLELINK_SDK not defined! You must specify where the SimpleLink SDK resides!) endif -# Find all available boards from the '/source/ti/boards directory' -AVAILABLE_BOARDS := $(shell ls -d $(SIMPLELINK_SDK)/source/ti/boards/*) -# Also allow a custom board file in the application project -AVAILABLE_BOARDS += CUSTOM +ifndef SIMPLELINK_DEVICE + $(error SIMPLELINK_DEVICE not defined! You must specify which device you are using!) +endif ifndef SIMPLELINK_BOARD - $(error SIMPLELINK_BOARD not defined. You must specify a board!$nAvailable boards:$n $(foreach board, $(AVAILABLE_BOARDS), $(board)$n)) + $(error SIMPLELINK_BOARD not defined! You must specify which board you are using!) endif -# Hacky way to emulate line breaks in warnings/errors -# https://stackoverflow.com/questions/17055773/how-to-synthesize-line-breaks-in-gnu-make-warnings-or-errors -define n +################################################################################ +# Defines +SIMPLELINK_PATH := $(CONTIKI)/arch/platform/simplelink -endef - -# List of all Simplelink SDKs the Contiki Simplelink platform supports -# with the format "simplelink__sdk". Don't add the version. -# Simply adding a new entry with the name of a new SDK should be enough when -# the necessary implementations have been made. -SUPPORTED_SDKS = \ - simplelink_cc13x0_sdk \ - simplelink_cc13x2_sdk \ - simplelink_cc26x0_sdk \ - simplelink_cc26x2_sdk \ - simplelink_cc2640r2_sdk \ - -# The Simplelink SDK name extracted from the file path. -# e.g. C:/ti/simplelink_cc13x0_sdk_1_60_00_21 => simplelink_cc13x0_sdk_1_60_00_21 -SDK_NAME := $(notdir $(SIMPLELINK_SDK)) -# The stripped name from the Simplelink SDK, i.e. without version number. -# e.g. simplelink_cc13x0_sdk_1_60_00_21 => simplelink_cc13x0_sdk -# Note that the first grep verifies the SDK name is on a valid format, -# and the second grep extracts the stripped name -SDK_NAME_STRIPPED := $(shell echo "$(SDK_NAME)" \ - | grep -Po "simplelink_.*?_sdk_[0-9_]+" \ - | grep -Po "simplelink_.*?_sdk") - -# Verify a valid Simplelink SDK has been supplied. -# Format is "simplelink__sdk_" -ifeq (,$(SDK_NAME_STRIPPED)) - $(error Supplied Simplelink SDK '$(SDK_NAME)' is not valid.$nFormat is "simplelink__sdk_") -endif - -# Verify a supported Simplelink SDK has been supplied, else print all supported SDKs -ifeq (,$(findstring $(SDK_NAME_STRIPPED), $(SUPPORTED_SDKS))) - $(error Simplelink SDK '$(SDK_NAME)' is not supported.$nSupported SDKs:$n $(foreach sdk, $(SUPPORTED_SDKS), $(sdk)_$n)) -endif - -ifneq ($(findstring $(SIMPLELINK_BOARD),$(AVAILABLE_BOARDS)),$(SIMPLELINK_BOARD)) - $(error Board '$(SIMPLELINK_BOARD)' is not valid for the given Simplelink SDK '$(SDK_NAME)'.$nAvailable boards:$n $(foreach board, $(AVAILABLE_BOARDS), $(board)$n)) -endif - -### Board and BSP selection - -CONTIKI_TARGET_DIRS += . dev - -CONTIKI_TARGET_SOURCEFILES += platform.c - -# Determine which device family and include the corresponding source files -include $(PLATFORM_ABS_PATH)/Makefile.device-family - -CONTIKI_SOURCEFILES += $(CONTIKI_TARGET_SOURCEFILES) +include $(SIMPLELINK_PATH)/Makefile.device-family CLEAN += *.simplelink -### Unless the example dictates otherwise, build without code size optimisations +# Build without code size optimisations, unless the project dictates otherwise SMALL ?= 0 - -CONTIKI_CPU = $(CONTIKI)/arch/cpu/simplelink -include $(CONTIKI_CPU)/Makefile.simplelink - -MODULES += os/net os/net/mac os/net/mac/framer - - - diff --git a/arch/platform/simplelink/cc13x0-cc26x0/Makefile.cc13x0-cc26x0 b/arch/platform/simplelink/cc13x0-cc26x0/Makefile.cc13x0-cc26x0 new file mode 100644 index 000000000..f7e3b656e --- /dev/null +++ b/arch/platform/simplelink/cc13x0-cc26x0/Makefile.cc13x0-cc26x0 @@ -0,0 +1,106 @@ +################################################################################ +# SimpleLink MCU platform makefile + +# Make sure path to Simplelink SDK is specified as absolute path +SIMPLELINK_SDK := $(abspath $(SIMPLELINK_SDK)) + +################################################################################ +# Device Family + +# The DeviceFamily.h file will always be available and can therefore be +# hard-coded. +DEVICE_FAMILY_H := $(SIMPLELINK_SDK)/source/ti/devices/DeviceFamily.h + +# The define of the Device Family ID is on the format of either +# #define DeviceFamily_ID_ +# or +# #define DeviceFamily_ID_ +# We are interested in the right-hand side of the define, i.e. the third word on the line, +# as it either defines a number or an another Device Family ID. +DEVICE_DEFINE := $(shell cat $(DEVICE_FAMILY_H) \ + | grep "\#define DeviceFamily_ID_$(SIMPLELINK_DEVICE_UC)\\b" \ + | awk '{print $$3}') + +# If the define is a number, then the device family name is the resulting device name; +# Else, it points to a sub-name of the device family, e.g. DeviceFamily_ID_CC13X2_V1. +# This line checks if the extracted define is a number or not, based on this SO post: +# https://stackoverflow.com/a/19116862/5099169 +IS_NUMBER := $(shell if [ "$(DEVICE_DEFINE)" -eq "$(DEVICE_DEFINE)" ] 2>/dev/null; then echo 1 ; else echo 0 ; fi) + +ifeq ($(IS_NUMBER),1) +# The define points to a number, meaning the device family name is the same as the +# specified device name in lower case, e.g. +# cc13x2 +DEVICE_FAMILY_NAME := $(SIMPLELINK_DEVICE_LC) +else +# The define points to a sub-name of the device family. The resulting device family name +# is therefore the name after specified after ID in lower case, e.g. +# DeviceFamily_ID_CC13X2_V1 +# will result in +# cc13x2_v1 +DEVICE_FAMILY_NAME := $(shell echo "$(DEVICE_DEFINE)" \ + | sed -E "s/DeviceFamily_ID_(.+)/\1/" \ + | tr A-Z a-z ) +endif + +# The DeviceFamily_constructPath() macro in DeviceFamily.h will always construct the +# correct path for device specific files. In this case, constructing the device specific +# root path. Note that the returned path is encased in angular brackets, <...>, +# and is therefore extracted with sed. +SDK_DEVICE_DIR := $(shell echo "DeviceFamily_constructPath(dummy)" \ + | gcc -x c -E -D$(DEVICE_FAMILY) -include $(DEVICE_FAMILY_H) - \ + | tail -1 \ + | sed -E "s:<(.+)/dummy>:\1:") + +################################################################################ +# Simplelink SDK paths + +SDK_KERNEL := $(SIMPLELINK_SDK)/kernel/nortos +SDK_SOURCE := $(SIMPLELINK_SDK)/source +SDK_BOARDS := $(SDK_SOURCE)/ti/boards +SDK_DRIVERS := $(SDK_SOURCE)/ti/drivers +SDK_DEVICE := $(SDK_SOURCE)/$(SDK_DEVICE_DIR) + +################################################################################ +# Board and BSP selection +BOARD_TYPES = launchpad sensortag srf06 + +SIMPLELINK_BOARDS := $(foreach BOARD_TYPE,$(BOARD_TYPES),\ + $(shell ls -d $(PLATFORM_ROOT_DIR)/$(BOARD_TYPE)/*/ \ + | sed 's/.$$//' \ + | rev \ + | cut -d / -f -2 \ + | rev)) + +ifeq ($(filter $(SIMPLELINK_BOARD),$(SIMPLELINK_BOARDS)),) + $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported for Device '$(SIMPLELINK_DEVICE)') +endif + +################################################################################ +# Directory and source configurations + +# Add to the source dirs +CONTIKI_TARGET_DIRS += . +CONTIKI_TARGET_DIRS += common +CONTIKI_TARGET_DIRS += $(shell echo $(dir $(SIMPLELINK_BOARD)) | sed 's:/$$::') + +# Include the board-specific Makefile +include $(PLATFORM_ROOT_DIR)/$(SIMPLELINK_BOARD)/Makefile.$(notdir $(SIMPLELINK_BOARD)) + +CONTIKI_TARGET_SOURCEFILES += platform.c +CONTIKI_TARGET_SOURCEFILES += $(BOARD_SOURCEFILES) + +CONTIKI_SOURCEFILES += $(CONTIKI_TARGET_SOURCEFILES) + +# Define the CPU directory and pull in the correct CPU makefile. This will +# be defined by one of the makefiles included above and it can be either +# Makefile.cc26xx or Makefile.cc13xx +CONTIKI_CPU := $(CONTIKI)/arch/cpu/cc13xx-cc26xx +include $(CONTIKI_CPU)/Makefile.cc13x0-cc26x0 + +MODULES += os/net os/net/mac os/net/mac/framer + +################################################################################ +# Display all supported Boards for the given +simplelink_boards: + @echo "$(SIMPLELINK_BOARDS) (current: $(SIMPLELINK_BOARD))" diff --git a/arch/platform/simplelink/dev/als-sensor.h b/arch/platform/simplelink/cc13x0-cc26x0/common/als-sensor.h similarity index 100% rename from arch/platform/simplelink/dev/als-sensor.h rename to arch/platform/simplelink/cc13x0-cc26x0/common/als-sensor.h diff --git a/arch/platform/simplelink/dev/button-sensor.h b/arch/platform/simplelink/cc13x0-cc26x0/common/button-sensor.h similarity index 100% rename from arch/platform/simplelink/dev/button-sensor.h rename to arch/platform/simplelink/cc13x0-cc26x0/common/button-sensor.h diff --git a/arch/platform/simplelink/contiki-conf.h b/arch/platform/simplelink/cc13x0-cc26x0/contiki-conf.h similarity index 100% rename from arch/platform/simplelink/contiki-conf.h rename to arch/platform/simplelink/cc13x0-cc26x0/contiki-conf.h diff --git a/arch/platform/simplelink/cc13x0-cc26x0/launchpad/Makefile.launchpad b/arch/platform/simplelink/cc13x0-cc26x0/launchpad/Makefile.launchpad new file mode 100644 index 000000000..ac61c6d8e --- /dev/null +++ b/arch/platform/simplelink/cc13x0-cc26x0/launchpad/Makefile.launchpad @@ -0,0 +1,12 @@ +################################################################################ +# SimpleLink LaunchPad makefile + +DEFINES += BOARD_LAUNCHPAD=1 + +# leds-arch.c/h etc. +BOARD_SOURCEFILES += launchpad-sensors.c button-sensor-arch.c leds-arch.c + +CONTIKI_TARGET_DIRS += launchpad + +### Signal that we can be programmed with cc2538-bsl +BOARD_SUPPORTS_BSL=1 diff --git a/arch/platform/simplelink/cc13x2_cc26x2/launchpad/button-sensor-arch.c b/arch/platform/simplelink/cc13x0-cc26x0/launchpad/button-sensor-arch.c similarity index 100% rename from arch/platform/simplelink/cc13x2_cc26x2/launchpad/button-sensor-arch.c rename to arch/platform/simplelink/cc13x0-cc26x0/launchpad/button-sensor-arch.c diff --git a/arch/platform/simplelink/cc13x2_cc26x2/launchpad/button-sensor-arch.h b/arch/platform/simplelink/cc13x0-cc26x0/launchpad/button-sensor-arch.h similarity index 100% rename from arch/platform/simplelink/cc13x2_cc26x2/launchpad/button-sensor-arch.h rename to arch/platform/simplelink/cc13x0-cc26x0/launchpad/button-sensor-arch.h diff --git a/arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc1310/Makefile.cc1310 b/arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc1310/Makefile.cc1310 new file mode 100644 index 000000000..bf58ea110 --- /dev/null +++ b/arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc1310/Makefile.cc1310 @@ -0,0 +1,22 @@ +################################################################################ +# SimpleLink Device makefile + +SDK_BOARD_NAME := CC1310_LAUNCHXL + +SDK_BOARD_PATH := $(SDK_BOARDS)/$(SDK_BOARD_NAME) + +SDK_BOARD_PATH_EXISTS := $(shell test ! -d $(SDK_BOARD_PATH); echo $$?) +ifeq ($(SDK_BOARD_PATH_EXISTS),0) + $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported by the specified Simplelink SDK) +endif + +DEFINES += SUPPORTS_PROP_MODE=1 +DEFINES += SUPPORTS_IEEE_MODE=0 + +# Add to the source dirs +BOARD_SOURCEFILES += $(SDK_BOARD_NAME).c + +EXTERNALDIRS += $(SDK_BOARD_PATH) + +# Include the common launchpad makefile +include $(PLATFORM_ROOT_DIR)/launchpad/Makefile.launchpad diff --git a/arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc1350-4/Makefile.cc1350-4 b/arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc1350-4/Makefile.cc1350-4 new file mode 100644 index 000000000..71de07821 --- /dev/null +++ b/arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc1350-4/Makefile.cc1350-4 @@ -0,0 +1,22 @@ +################################################################################ +# SimpleLink Device makefile + +SDK_BOARD_NAME := CC1350_LAUNCHXL_433 + +SDK_BOARD_PATH := $(SDK_BOARDS)/$(SDK_BOARD_NAME) + +SDK_BOARD_PATH_EXISTS := $(shell test ! -d $(SDK_BOARD_PATH); echo $$?) +ifeq ($(SDK_BOARD_PATH_EXISTS),0) + $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported by the specified Simplelink SDK) +endif + +DEFINES += SUPPORTS_PROP_MODE=1 +DEFINES += SUPPORTS_IEEE_MODE=1 + +# Add to the source dirs +BOARD_SOURCEFILES += $(SDK_BOARD_NAME).c + +EXTERNALDIRS += $(SDK_BOARD_PATH) + +# Include the common launchpad makefile +include $(PLATFORM_ROOT_DIR)/launchpad/Makefile.launchpad diff --git a/arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc1350/Makefile.cc1350 b/arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc1350/Makefile.cc1350 new file mode 100644 index 000000000..4789dec86 --- /dev/null +++ b/arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc1350/Makefile.cc1350 @@ -0,0 +1,22 @@ +################################################################################ +# SimpleLink Device makefile + +SDK_BOARD_NAME := CC1350_LAUNCHXL + +SDK_BOARD_PATH := $(SDK_BOARDS)/$(SDK_BOARD_NAME) + +SDK_BOARD_PATH_EXISTS := $(shell test ! -d $(SDK_BOARD_PATH); echo $$?) +ifeq ($(SDK_BOARD_PATH_EXISTS),0) + $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported by the specified Simplelink SDK) +endif + +DEFINES += SUPPORTS_PROP_MODE=1 +DEFINES += SUPPORTS_IEEE_MODE=1 + +# Add to the source dirs +BOARD_SOURCEFILES += $(SDK_BOARD_NAME).c + +EXTERNALDIRS += $(SDK_BOARD_PATH) + +# Include the common launchpad makefile +include $(PLATFORM_ROOT_DIR)/launchpad/Makefile.launchpad diff --git a/arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc2650/Makefile.cc2650 b/arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc2650/Makefile.cc2650 new file mode 100644 index 000000000..9fbad9968 --- /dev/null +++ b/arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc2650/Makefile.cc2650 @@ -0,0 +1,22 @@ +################################################################################ +# SimpleLink Device makefile + +SDK_BOARD_NAME := CC2650_LAUNCHXL + +SDK_BOARD_PATH := $(SDK_BOARDS)/$(SDK_BOARD_NAME) + +SDK_BOARD_PATH_EXISTS := $(shell test ! -d $(SDK_BOARD_PATH); echo $$?) +ifeq ($(SDK_BOARD_PATH_EXISTS),0) + $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported by the specified Simplelink SDK) +endif + +DEFINES += SUPPORTS_PROP_MODE=0 +DEFINES += SUPPORTS_IEEE_MODE=1 + +# Add to the source dirs +BOARD_SOURCEFILES += $(SDK_BOARD_NAME).c + +EXTERNALDIRS += $(SDK_BOARD_PATH) + +# Include the common launchpad makefile +include $(PLATFORM_ROOT_DIR)/launchpad/Makefile.launchpad diff --git a/arch/platform/simplelink/cc13x0_cc26x0/launchpad/launchpad-sensors.c b/arch/platform/simplelink/cc13x0-cc26x0/launchpad/launchpad-sensors.c similarity index 100% rename from arch/platform/simplelink/cc13x0_cc26x0/launchpad/launchpad-sensors.c rename to arch/platform/simplelink/cc13x0-cc26x0/launchpad/launchpad-sensors.c diff --git a/arch/platform/simplelink/dev/leds-arch.c b/arch/platform/simplelink/cc13x0-cc26x0/launchpad/leds-arch.c similarity index 100% rename from arch/platform/simplelink/dev/leds-arch.c rename to arch/platform/simplelink/cc13x0-cc26x0/launchpad/leds-arch.c diff --git a/arch/platform/simplelink/platform.c b/arch/platform/simplelink/cc13x0-cc26x0/platform.c similarity index 95% rename from arch/platform/simplelink/platform.c rename to arch/platform/simplelink/cc13x0-cc26x0/platform.c index 50ef66762..c5718a103 100644 --- a/arch/platform/simplelink/platform.c +++ b/arch/platform/simplelink/cc13x0-cc26x0/platform.c @@ -66,6 +66,7 @@ #include "dev/serial-line.h" #include "dev/leds.h" #include "net/mac/framer/frame802154.h" +#include "lib/sensors.h" /*---------------------------------------------------------------------------*/ /* Arch driver implementations */ #include "uart0-arch.h" @@ -74,7 +75,6 @@ #include "ieee-addr.h" #include "dev/rf-common.h" #include "lib/random.h" -#include "lib/sensors.h" #include "button-sensor.h" /*---------------------------------------------------------------------------*/ #include @@ -82,7 +82,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "CC26xx/CC13xx" -#define LOG_LEVEL LOG_LEVEL_MAIN +#define LOG_LEVEL LOG_LEVEL_DBG /*---------------------------------------------------------------------------*/ unsigned short g_nodeId = 0; /*---------------------------------------------------------------------------*/ @@ -169,10 +169,17 @@ platform_init_stage_one(void) void platform_init_stage_two(void) { +#if SIMPLELINK_UART_CONF_ENABLE uart0_init(); +#endif + serial_line_init(); -// random_init(0x1234); +#if BUILD_WITH_SHELL + uart0_set_callback(serial_line_input_byte); +#endif + + // random_init(0x1234); /* Populate linkaddr_node_addr */ ieee_addr_cpy_to(linkaddr_node_addr.u8, LINKADDR_SIZE); @@ -192,16 +199,15 @@ platform_init_stage_three(void) LOG_DBG("With DriverLib v%u.%u\n", DRIVERLIB_RELEASE_GROUP, DRIVERLIB_RELEASE_BUILD); - //LOG_INFO(BOARD_STRING "\n"); LOG_DBG("IEEE 802.15.4: %s, Sub-GHz: %s, BLE: %s, Prop: %s\n", ChipInfo_SupportsIEEE_802_15_4() ? "Yes" : "No", ChipInfo_ChipFamilyIs_CC13x0() ? "Yes" : "No", ChipInfo_SupportsBLE() ? "Yes" : "No", ChipInfo_SupportsPROPRIETARY() ? "Yes" : "No"); - LOG_INFO(" RF: Channel %d, PANID 0x%04X\n", chan, pan); - LOG_INFO(" Node ID: %d\n", g_nodeId); -// -// process_start(&sensors_process, NULL); + LOG_INFO("RF: Channel %d, PANID 0x%04X\n", chan, pan); + LOG_INFO("Node ID: %d\n", g_nodeId); + + process_start(&sensors_process, NULL); fade(LEDS_GREEN); } /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13x0-cc26x0/sensortag/Makefile.sensortag b/arch/platform/simplelink/cc13x0-cc26x0/sensortag/Makefile.sensortag new file mode 100644 index 000000000..1e25489ab --- /dev/null +++ b/arch/platform/simplelink/cc13x0-cc26x0/sensortag/Makefile.sensortag @@ -0,0 +1,12 @@ +################################################################################ +# SimpleLink LaunchPad makefile + +DEFINES += BOARD_SENSORTAG=1 + +# leds-arch.c/h etc. +BOARD_SOURCEFILES += sensortag-sensors.c button-sensor-arch.c leds-arch.c + +CONTIKI_TARGET_DIRS += sensortag + +### Signal that we can be programmed with cc2538-bsl +BOARD_SUPPORTS_BSL=1 diff --git a/arch/platform/simplelink/cc13x0-cc26x0/sensortag/cc1350/Makefile.cc1350 b/arch/platform/simplelink/cc13x0-cc26x0/sensortag/cc1350/Makefile.cc1350 new file mode 100644 index 000000000..1795df10a --- /dev/null +++ b/arch/platform/simplelink/cc13x0-cc26x0/sensortag/cc1350/Makefile.cc1350 @@ -0,0 +1,22 @@ +################################################################################ +# SimpleLink Device makefile + +SDK_BOARD_NAME := CC1350STK + +SDK_BOARD_PATH := $(SDK_BOARDS)/$(SDK_BOARD_NAME) + +SDK_BOARD_PATH_EXISTS := $(shell test ! -d $(SDK_BOARD_PATH); echo $$?) +ifeq ($(SDK_BOARD_PATH_EXISTS),0) + $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported by the specified Simplelink SDK) +endif + +DEFINES += SUPPORTS_PROP_MODE=1 +DEFINES += SUPPORTS_IEEE_MODE=1 + +# Add to the source dirs +BOARD_SOURCEFILES += $(SDK_BOARD_NAME).c + +EXTERNALDIRS += $(SDK_BOARD_PATH) + +# Include the common launchpad makefile +include $(PLATFORM_ROOT_DIR)/sensortag/Makefile.sensortag diff --git a/arch/platform/simplelink/cc13x0-cc26x0/sensortag/cc2650/Makefile.cc2650 b/arch/platform/simplelink/cc13x0-cc26x0/sensortag/cc2650/Makefile.cc2650 new file mode 100644 index 000000000..47fb09f8b --- /dev/null +++ b/arch/platform/simplelink/cc13x0-cc26x0/sensortag/cc2650/Makefile.cc2650 @@ -0,0 +1,22 @@ +################################################################################ +# SimpleLink Device makefile + +SDK_BOARD_NAME := CC2650STK + +SDK_BOARD_PATH := $(SDK_BOARDS)/$(SDK_BOARD_NAME) + +SDK_BOARD_PATH_EXISTS := $(shell test ! -d $(SDK_BOARD_PATH); echo $$?) +ifeq ($(SDK_BOARD_PATH_EXISTS),0) + $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported by the specified Simplelink SDK) +endif + +DEFINES += SUPPORTS_PROP_MODE=0 +DEFINES += SUPPORTS_IEEE_MODE=1 + +# Add to the source dirs +BOARD_SOURCEFILES += $(SDK_BOARD_NAME).c + +EXTERNALDIRS += $(SDK_BOARD_PATH) + +# Include the common launchpad makefile +include $(PLATFORM_ROOT_DIR)/sensortag/Makefile.sensortag diff --git a/arch/platform/simplelink/cc13x0_cc26x0/dev/sensortag-sensors.c b/arch/platform/simplelink/cc13x0-cc26x0/sensortag/sensortag-sensors.c similarity index 100% rename from arch/platform/simplelink/cc13x0_cc26x0/dev/sensortag-sensors.c rename to arch/platform/simplelink/cc13x0-cc26x0/sensortag/sensortag-sensors.c diff --git a/arch/platform/simplelink/cc13x0-cc26x0/srf06/Makefile.srf06 b/arch/platform/simplelink/cc13x0-cc26x0/srf06/Makefile.srf06 new file mode 100644 index 000000000..862993a72 --- /dev/null +++ b/arch/platform/simplelink/cc13x0-cc26x0/srf06/Makefile.srf06 @@ -0,0 +1,12 @@ +################################################################################ +# SimpleLink LaunchPad makefile + +DEFINES += BOARD_SMARTRF06EB=1 + +# leds-arch.c/h etc. +BOARD_SOURCEFILES += srf06-sensors.c button-sensor-arch.c leds-arch.c + +CONTIKI_TARGET_DIRS += srf06 + +### Signal that we can be programmed with cc2538-bsl +BOARD_SUPPORTS_BSL=1 diff --git a/arch/platform/simplelink/cc13x0-cc26x0/srf06/cc1310/Makefile.cc1310 b/arch/platform/simplelink/cc13x0-cc26x0/srf06/cc1310/Makefile.cc1310 new file mode 100644 index 000000000..aff16d421 --- /dev/null +++ b/arch/platform/simplelink/cc13x0-cc26x0/srf06/cc1310/Makefile.cc1310 @@ -0,0 +1,22 @@ +################################################################################ +# SimpleLink Device makefile + +SDK_BOARD_NAME := CC1310DK_7XD + +SDK_BOARD_PATH := $(SDK_BOARDS)/$(SDK_BOARD_NAME) + +SDK_BOARD_PATH_EXISTS := $(shell test ! -d $(SDK_BOARD_PATH); echo $$?) +ifeq ($(SDK_BOARD_PATH_EXISTS),0) + $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported by the specified Simplelink SDK) +endif + +DEFINES += SUPPORTS_PROP_MODE=1 +DEFINES += SUPPORTS_IEEE_MODE=0 + +# Add to the source dirs +BOARD_SOURCEFILES += $(SDK_BOARD_NAME).c + +EXTERNALDIRS += $(SDK_BOARD_PATH) + +# Include the common srf06 makefile +include $(PLATFORM_ROOT_DIR)/srf06/Makefile.srf06 diff --git a/arch/platform/simplelink/cc13x0-cc26x0/srf06/cc1350/Makefile.cc1350 b/arch/platform/simplelink/cc13x0-cc26x0/srf06/cc1350/Makefile.cc1350 new file mode 100644 index 000000000..2376346bb --- /dev/null +++ b/arch/platform/simplelink/cc13x0-cc26x0/srf06/cc1350/Makefile.cc1350 @@ -0,0 +1,22 @@ +################################################################################ +# SimpleLink Device makefile + +SDK_BOARD_NAME := CC1350DK_7XD + +SDK_BOARD_PATH := $(SDK_BOARDS)/$(SDK_BOARD_NAME) + +SDK_BOARD_PATH_EXISTS := $(shell test ! -d $(SDK_BOARD_PATH); echo $$?) +ifeq ($(SDK_BOARD_PATH_EXISTS),0) + $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported by the specified Simplelink SDK) +endif + +DEFINES += SUPPORTS_PROP_MODE=1 +DEFINES += SUPPORTS_IEEE_MODE=1 + +# Add to the source dirs +BOARD_SOURCEFILES += $(SDK_BOARD_NAME).c + +EXTERNALDIRS += $(SDK_BOARD_PATH) + +# Include the common srf06 makefile +include $(PLATFORM_ROOT_DIR)/srf06/Makefile.srf06 diff --git a/arch/platform/simplelink/cc13x0-cc26x0/srf06/cc2650/Makefile.cc2650 b/arch/platform/simplelink/cc13x0-cc26x0/srf06/cc2650/Makefile.cc2650 new file mode 100644 index 000000000..d8dd24c2c --- /dev/null +++ b/arch/platform/simplelink/cc13x0-cc26x0/srf06/cc2650/Makefile.cc2650 @@ -0,0 +1,22 @@ +################################################################################ +# SimpleLink Device makefile + +SDK_BOARD_NAME := CC2650DK_7ID + +SDK_BOARD_PATH := $(SDK_BOARDS)/$(SDK_BOARD_NAME) + +SDK_BOARD_PATH_EXISTS := $(shell test ! -d $(SDK_BOARD_PATH); echo $$?) +ifeq ($(SDK_BOARD_PATH_EXISTS),0) + $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported by the specified Simplelink SDK) +endif + +DEFINES += SUPPORTS_PROP_MODE=0 +DEFINES += SUPPORTS_IEEE_MODE=1 + +# Add to the source dirs +BOARD_SOURCEFILES += $(SDK_BOARD_NAME).c + +EXTERNALDIRS += $(SDK_BOARD_PATH) + +# Include the common launchpad makefile +include $(PLATFORM_ROOT_DIR)/srf06/Makefile.srf06 diff --git a/arch/platform/simplelink/cc13x0_cc26x0/dev/srf06-sensors.c b/arch/platform/simplelink/cc13x0-cc26x0/srf06/srf06-sensors.c similarity index 100% rename from arch/platform/simplelink/cc13x0_cc26x0/dev/srf06-sensors.c rename to arch/platform/simplelink/cc13x0-cc26x0/srf06/srf06-sensors.c diff --git a/arch/platform/simplelink/cc13x0_cc26x0/Makefile.cc13x0_cc26x0 b/arch/platform/simplelink/cc13x0_cc26x0/Makefile.cc13x0_cc26x0 deleted file mode 100644 index 59c3052b8..000000000 --- a/arch/platform/simplelink/cc13x0_cc26x0/Makefile.cc13x0_cc26x0 +++ /dev/null @@ -1,27 +0,0 @@ -# SimpleLink MCU platform makefile - -### Board and BSP selection - -CONTIKI_TARGET_SOURCEFILES += leds-arch.c - -# Launchpad boards -ifneq (,$(findstring LAUNCHXL, $(SIMPLELINK_BOARD))) - CONTIKI_TARGET_SOURCEFILES += launchpad-sensors.c - -# Sensortag boards -else ifneq (,$(findstring STK, $(SIMPLELINK_BOARD))) - CONTIKI_TARGET_SOURCEFILES += sensortag-sensors.c - -# Custom boards -else ifneq (,$(findstring CUSTOM, $(SIMPLELINK_BOARD))) -# TODO - CONTIKI_TARGET_SOURCEFILES += custom-sensors.c - -# Everything else is assumed to be EVMs for the SmartRF06 EB (srf06) -else - CONTIKI_TARGET_SOURCEFILES += srf06-sensors.c - -endif - -CONTIKI_TARGET_SOURCEFILES += button-sensor-arch.c - diff --git a/arch/platform/simplelink/cc13x2-cc26x2/Makefile.cc13x2-cc26x2 b/arch/platform/simplelink/cc13x2-cc26x2/Makefile.cc13x2-cc26x2 new file mode 100644 index 000000000..6f7c6f1be --- /dev/null +++ b/arch/platform/simplelink/cc13x2-cc26x2/Makefile.cc13x2-cc26x2 @@ -0,0 +1,103 @@ +################################################################################ +# SimpleLink MCU platform makefile + +# Make sure path to Simplelink SDK is specified as absolute path +SIMPLELINK_SDK := $(abspath $(SIMPLELINK_SDK)) + +################################################################################ +# Device Family +DEVICE_FAMILY_H := $(SIMPLELINK_SDK)/source/ti/devices/DeviceFamily.h + +# The define of the Device Family ID is on the format of either +# #define DeviceFamily_ID_ +# or +# #define DeviceFamily_ID_ +# We are interested in the right-hand side of the define, i.e. the third word on the line, +# as it either defines a number or an another Device Family ID. +DEVICE_DEFINE := $(shell cat $(DEVICE_FAMILY_H) \ + | grep "\#define DeviceFamily_ID_$(SIMPLELINK_DEVICE_UC)\\b" \ + | awk '{print $$3}') + +# If the define is a number, then the device family name is the resulting device name; +# Else, it points to a sub-name of the device family, e.g. DeviceFamily_ID_CC13X2_V1. +# This line checks if the extracted define is a number or not, based on this SO post: +# https://stackoverflow.com/a/19116862/5099169 +IS_NUMBER := $(shell if [ "$(DEVICE_DEFINE)" -eq "$(DEVICE_DEFINE)" ] 2>/dev/null; then echo 1 ; else echo 0 ; fi) + +ifeq ($(IS_NUMBER),1) +# The define points to a number, meaning the device family name is the same as the +# specified device name in lower case, e.g. +# cc13x2 +DEVICE_FAMILY_NAME := $(SIMPLELINK_DEVICE_LC) +else +# The define points to a sub-name of the device family. The resulting device family name +# is therefore the name after specified after ID in lower case, e.g. +# DeviceFamily_ID_CC13X2_V1 +# will result in +# cc13x2_v1 +DEVICE_FAMILY_NAME := $(shell echo "$(DEVICE_DEFINE)" \ + | sed -E "s/DeviceFamily_ID_(.+)/\1/" \ + | tr A-Z a-z ) +endif + +# The DeviceFamily_constructPath() macro in DeviceFamily.h will always construct the +# correct path for device specific files. In this case, constructing the device specific +# root path. Note that the returned path is encased in angular brackets, <...>, +# and is therefore extracted with sed. +SDK_DEVICE_DIR := $(shell echo "DeviceFamily_constructPath(dummy)" \ + | gcc -x c -E -D$(DEVICE_FAMILY) -include $(DEVICE_FAMILY_H) - \ + | tail -1 \ + | sed -E "s:<(.+)/dummy>:\1:") + +################################################################################ +# Simplelink SDK paths + +SDK_KERNEL := $(SIMPLELINK_SDK)/kernel/nortos +SDK_SOURCE := $(SIMPLELINK_SDK)/source +SDK_BOARDS := $(SDK_SOURCE)/ti/boards +SDK_DRIVERS := $(SDK_SOURCE)/ti/drivers +SDK_DEVICE := $(SDK_SOURCE)/$(SDK_DEVICE_DIR) + +################################################################################ +# Board and BSP selection +BOARD_TYPES = launchpad + +SIMPLELINK_BOARDS := $(foreach BOARD_TYPE, $(BOARD_TYPES), \ + $(shell ls -d $(PLATFORM_ROOT_DIR)/$(BOARD_TYPES)/*/ \ + | sed 's/.$$//' \ + | rev \ + | cut -d / -f -2 \ + | rev)) + +ifeq ($(filter $(SIMPLELINK_BOARD),$(SIMPLELINK_BOARDS)),) + $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported for Device '$(SIMPLELINK_DEVICE)') +endif + +################################################################################ +# Directory and source configurations + +# Add to the source dirs +CONTIKI_TARGET_DIRS += . +CONTIKI_TARGET_DIRS += common +CONTIKI_TARGET_DIRS += $(shell echo $(dir $(SIMPLELINK_BOARD)) | sed 's:/$$::') + +# Include the board-specific Makefile +include $(PLATFORM_ROOT_DIR)/$(SIMPLELINK_BOARD)/Makefile.$(notdir $(SIMPLELINK_BOARD)) + +CONTIKI_TARGET_SOURCEFILES += platform.c +CONTIKI_TARGET_SOURCEFILES += $(BOARD_SOURCEFILES) + +CONTIKI_SOURCEFILES += $(CONTIKI_TARGET_SOURCEFILES) + +# Define the CPU directory and pull in the correct CPU makefile. This will +# be defined by one of the makefiles included above and it can be either +# Makefile.cc26xx or Makefile.cc13xx +CONTIKI_CPU=$(CONTIKI)/arch/cpu/cc13xx-cc26xx +include $(CONTIKI_CPU)/Makefile.cc13x2-cc26x2 + +MODULES += os/net os/net/mac os/net/mac/framer + +################################################################################ +# Display all supported Boards for the given +simplelink_boards: + @echo "$(SIMPLELINK_BOARDS) (current: $(SIMPLELINK_BOARD))" diff --git a/arch/platform/simplelink/cc13x2_cc26x2/srf06/als-sensor-arch.h b/arch/platform/simplelink/cc13x2-cc26x2/common/button-sensor.h similarity index 70% rename from arch/platform/simplelink/cc13x2_cc26x2/srf06/als-sensor-arch.h rename to arch/platform/simplelink/cc13x2-cc26x2/common/button-sensor.h index 8cb482c7b..8756d9b6c 100644 --- a/arch/platform/simplelink/cc13x2_cc26x2/srf06/als-sensor-arch.h +++ b/arch/platform/simplelink/cc13x2-cc26x2/common/button-sensor.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, University of Bristol - http://www.bris.ac.uk/ + * Copyright (c) 2018 Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,20 +29,38 @@ */ /*---------------------------------------------------------------------------*/ /** - * \addtogroup srf06-common-peripherals + * \addtogroup simplelink-platform + * @{ + * + * \defgroup simplelink-button-sensor Simplelink Button Driver + * + * One of the buttons can be configured as general purpose or as an on/off key * @{ * * \file - * Header file for the SmartRF06EB + CC13xx/CC26xxEM ALS Driver + * Header file for the Simplelink Button Driver */ /*---------------------------------------------------------------------------*/ -#ifndef ALS_SENSOR_H_ -#define ALS_SENSOR_H_ +#ifndef BUTTON_SENSOR_H_ +#define BUTTON_SENSOR_H_ /*---------------------------------------------------------------------------*/ -#include "lib/sensors.h" +/* Contiki API */ +#include /*---------------------------------------------------------------------------*/ -extern const struct sensors_sensor als_sensor; +/* Board specific button sensors */ +#include "button-sensor-arch.h" /*---------------------------------------------------------------------------*/ -#endif /* ALS_SENSOR_H_ */ +#define BUTTON_SENSOR "Button" /*---------------------------------------------------------------------------*/ -/** @} */ +#define BUTTON_SENSOR_VALUE_STATE 0 +#define BUTTON_SENSOR_VALUE_DURATION 1 + +#define BUTTON_SENSOR_VALUE_RELEASED 0 +#define BUTTON_SENSOR_VALUE_PRESSED 1 +/*---------------------------------------------------------------------------*/ +#endif /* BUTTON_SENSOR_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/platform/simplelink/cc13x2-cc26x2/contiki-conf.h b/arch/platform/simplelink/cc13x2-cc26x2/contiki-conf.h new file mode 100644 index 000000000..a841b89ae --- /dev/null +++ b/arch/platform/simplelink/cc13x2-cc26x2/contiki-conf.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/** + * \addtogroup cc26xx-srf-tag + * @{ + * + * \file + * Configuration for the srf06-cc26xx platform + */ +#ifndef CONTIKI_CONF_H +#define CONTIKI_CONF_H + +#include +/*---------------------------------------------------------------------------*/ +/* Include Project Specific conf */ +#ifdef PROJECT_CONF_PATH +#include PROJECT_CONF_PATH +#endif /* PROJECT_CONF_PATH */ +/*---------------------------------------------------------------------------*/ +#include "simplelink-def.h" +/*---------------------------------------------------------------------------*/ +/** + * \name Button configurations + * + * Configure a button as power on/off: We use the right button for both boards. + * @{ + */ +#ifndef BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN +#define BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN 1 +#endif + +/* Notify various examples that we have Buttons */ +#define PLATFORM_HAS_BUTTON 1 + +/* + * Override button symbols from dev/button-sensor.h, for the examples that + * include it + */ +#define button_sensor button_left_sensor +#define button_sensor2 button_right_sensor +/** @} */ +/*---------------------------------------------------------------------------*/ +/* Platform-specific define to signify sensor reading failure */ +#define CC26XX_SENSOR_READING_ERROR 0x80000000 +/*---------------------------------------------------------------------------*/ +/* Include CPU-related configuration */ +#include "simplelink-conf.h" +/*---------------------------------------------------------------------------*/ +#endif /* CONTIKI_CONF_H */ + +/** @} */ diff --git a/arch/platform/simplelink/cc13x2-cc26x2/launchpad/Makefile.launchpad b/arch/platform/simplelink/cc13x2-cc26x2/launchpad/Makefile.launchpad new file mode 100644 index 000000000..60306469a --- /dev/null +++ b/arch/platform/simplelink/cc13x2-cc26x2/launchpad/Makefile.launchpad @@ -0,0 +1,12 @@ +################################################################################ +# SimpleLink LaunchPad makefile + +DEFINES += BOARD_LAUNCHPAD=1 + +# leds-arch.c/h etc. +BOARD_SOURCEFILES += launchpad-sensors.c button-sensor-arch.c leds-arch.c + +CONTIKI_TARGET_DIRS += launchpad + +### Signal that we can be programmed with cc2538-bsl +BOARD_SUPPORTS_BSL=0 diff --git a/arch/platform/simplelink/cc13x2_cc26x2/srf06/button-sensor-arch.c b/arch/platform/simplelink/cc13x2-cc26x2/launchpad/button-sensor-arch.c similarity index 55% rename from arch/platform/simplelink/cc13x2_cc26x2/srf06/button-sensor-arch.c rename to arch/platform/simplelink/cc13x2-cc26x2/launchpad/button-sensor-arch.c index f6020d6ad..03292c580 100644 --- a/arch/platform/simplelink/cc13x2_cc26x2/srf06/button-sensor-arch.c +++ b/arch/platform/simplelink/cc13x2-cc26x2/launchpad/button-sensor-arch.c @@ -49,13 +49,10 @@ #include "button-sensor.h" #include "button-sensor-arch.h" /*---------------------------------------------------------------------------*/ -/* SmartRF06 EB has 5 buttons: Select, Up, Down, Left, and Right */ +/* LaunchPad has 2 buttons: BTN1 and BTN2 */ /* Map the GPIO defines from the Board file */ -#define BUTTON_SELECT_GPIO Board_KEY_SELECT -#define BUTTON_UP_GPIO Board_KEY_UP -#define BUTTON_DOWN_GPIO Board_KEY_DOWN -#define BUTTON_LEFT_GPIO Board_KEY_LEFT -#define BUTTON_RIGHT_GPIO Board_KEY_RIGHT +#define BTN1_GPIO Board_GPIO_BTN1 +#define BTN2_GPIO Board_GPIO_BTN2 /*---------------------------------------------------------------------------*/ #ifdef BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN # define BUTTON_SENSOR_ENABLE_SHUTDOWN BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN @@ -71,11 +68,8 @@ typedef struct { clock_time_t duration; } BtnTimer; /*---------------------------------------------------------------------------*/ -static BtnTimer g_buttonSelectTimer; -static BtnTimer g_buttonUpTimer; -static BtnTimer g_buttonDownTimer; -static BtnTimer g_buttonLeftTimer; -static BtnTimer g_buttonRightTimer; +static BtnTimer g_btn1Timer; +static BtnTimer g_btn2Timer; /*---------------------------------------------------------------------------*/ static void button_press_cb(uint8_t index, BtnTimer *btnTimer, const struct sensors_sensor *btnSensor) @@ -145,150 +139,60 @@ button_status(int type, uint8_t index) return 0; } /*---------------------------------------------------------------------------*/ -/* Select Button */ +static void +btn1_press_cb(unsigned char unusued) +{ + button_press_cb(BTN1_GPIO, &g_btn1Timer, &btn1_sensor); +} +/*---------------------------------------------------------------------------*/ +static int +btn1_value(int type) +{ + return button_value(type, BTN1_GPIO, &g_btn1Timer); +} +/*---------------------------------------------------------------------------*/ +static int +btn1_config(int type, int value) +{ + return button_config(type, value, BTN1_GPIO, btn1_press_cb); +} +/*---------------------------------------------------------------------------*/ +static int +btn1_status(int type) +{ + return button_status(type, BTN1_GPIO); +} /*---------------------------------------------------------------------------*/ static void -button_select_press_cb(unsigned char unusued) -{ - button_press_cb(BUTTON_SELECT_GPIO, &g_buttonSelectTimer, &button_select_sensor); -} -/*---------------------------------------------------------------------------*/ -static int -button_select_value(int type) -{ - return button_value(type, BUTTON_SELECT_GPIO, &g_buttonSelectTimer); -} -/*---------------------------------------------------------------------------*/ -static int -button_select_config(int type, int value) -{ - return button_config(type, value, BUTTON_SELECT_GPIO, button_select_press_cb); -} -/*---------------------------------------------------------------------------*/ -static int -button_select_status(int type) -{ - return button_status(type, BUTTON_SELECT_GPIO); -} -/*---------------------------------------------------------------------------*/ -/* Up Button */ -/*---------------------------------------------------------------------------*/ -static void -button_up_press_cb(unsigned char unusued) -{ - button_press_cb(BUTTON_UP_GPIO, &g_buttonUpTimer, &button_up_sensor); -} -/*---------------------------------------------------------------------------*/ -static int -button_up_value(int type) -{ - return button_value(type, BUTTON_UP_GPIO, &g_buttonUpTimer); -} -/*---------------------------------------------------------------------------*/ -static int -button_up_config(int type, int value) -{ - return button_config(type, value, BUTTON_UP_GPIO, button_up_press_cb); -} -/*---------------------------------------------------------------------------*/ -static int -button_up_status(int type) -{ - return button_status(type, BUTTON_UP_GPIO); -} -/*---------------------------------------------------------------------------*/ -/* Down Button */ -/*---------------------------------------------------------------------------*/ -static void -button_down_press_cb(unsigned char unusued) -{ - button_press_cb(BUTTON_DOWN_GPIO, &g_buttonDownTimer, &button_down_sensor); -} -/*---------------------------------------------------------------------------*/ -static int -button_down_value(int type) -{ - return button_value(type, BUTTON_DOWN_GPIO, &g_buttonDownTimer); -} -/*---------------------------------------------------------------------------*/ -static int -button_down_config(int type, int value) -{ - return button_config(type, value, BUTTON_DOWN_GPIO, button_down_press_cb); -} -/*---------------------------------------------------------------------------*/ -static int -button_down_status(int type) -{ - return button_status(type, BUTTON_DOWN_GPIO); -} -/*---------------------------------------------------------------------------*/ -/* Left Button */ -/*---------------------------------------------------------------------------*/ -static void -button_left_press_cb(unsigned char unusued) -{ - button_press_cb(BUTTON_LEFT_GPIO, &g_buttonLeftTimer, &button_left_sensor); -} -/*---------------------------------------------------------------------------*/ -static int -button_left_value(int type) -{ - return button_value(type, BUTTON_LEFT_GPIO, &g_buttonLeftTimer); -} -/*---------------------------------------------------------------------------*/ -static int -button_left_config(int type, int value) -{ - return button_config(type, value, BUTTON_LEFT_GPIO, button_left_press_cb); -} -/*---------------------------------------------------------------------------*/ -static int -button_left_status(int type) -{ - return button_status(type, BUTTON_LEFT_GPIO); -} -/*---------------------------------------------------------------------------*/ -/* Right Button */ -/*---------------------------------------------------------------------------*/ -static void -button_right_press_cb(unsigned char unusued) +btn2_press_cb(unsigned char unusued) { if (BUTTON_SENSOR_ENABLE_SHUTDOWN) { Power_shutdown(Power_ENTERING_SHUTDOWN, 0); return; } - button_press_cb(BUTTON_RIGHT_GPIO, &g_buttonRightTimer, &button_right_sensor); + button_press_cb(BTN2_GPIO, &g_btn2Timer, &btn2_sensor); } /*---------------------------------------------------------------------------*/ static int -button_right_value(int type) +btn2_value(int type) { - return button_value(type, BUTTON_RIGHT_GPIO, &g_buttoRightimer); + return button_value(type, BTN2_GPIO, &g_btn2Timer); } /*---------------------------------------------------------------------------*/ static int -button_right_config(int type, int value) +btn2_config(int type, int value) { - return button_config(type, value, BUTTON_RIGHT_GPIO, button_right_press_cb); + return button_config(type, value, BTN2_GPIO, btn2_press_cb); } /*---------------------------------------------------------------------------*/ static int -button_right_status(int type) +btn2_status(int type) { - return button_status(type, BUTTON_RIGHT_GPIO); + return button_status(type, BTN1_GPIO); } /*---------------------------------------------------------------------------*/ -SENSORS_SENSOR(button_select_sensor, BUTTON_SENSOR, - button_select_value, button_select_config, button_select_status); -SENSORS_SENSOR(button_up_sensor, BUTTON_SENSOR, - button_up_value, button_up_config, button_up_status); -SENSORS_SENSOR(button_down_sensor, BUTTON_SENSOR, - button_down_value, button_down_config, button_down_status); -SENSORS_SENSOR(button_left_sensor, BUTTON_SENSOR, - button_left_value, button_left_config, button_left_status); -SENSORS_SENSOR(button_right_sensor, BUTTON_SENSOR, - button_right_value, button_right_config, button_right_status); +SENSORS_SENSOR(btn1_sensor, BUTTON_SENSOR, btn1_value, btn1_config, btn1_status); +SENSORS_SENSOR(btn2_sensor, BUTTON_SENSOR, btn2_value, btn2_config, btn2_status); /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/platform/simplelink/cc13x2_cc26x2/srf06/button-sensor-arch.h b/arch/platform/simplelink/cc13x2-cc26x2/launchpad/button-sensor-arch.h similarity index 90% rename from arch/platform/simplelink/cc13x2_cc26x2/srf06/button-sensor-arch.h rename to arch/platform/simplelink/cc13x2-cc26x2/launchpad/button-sensor-arch.h index 761600281..ecd04e8b6 100644 --- a/arch/platform/simplelink/cc13x2_cc26x2/srf06/button-sensor-arch.h +++ b/arch/platform/simplelink/cc13x2-cc26x2/launchpad/button-sensor-arch.h @@ -47,11 +47,8 @@ /* Contiki API */ #include /*---------------------------------------------------------------------------*/ -extern const struct sensors_sensor button_select_sensor; -extern const struct sensors_sensor button_up_sensor; -extern const struct sensors_sensor button_down_sensor; -extern const struct sensors_sensor button_left_sensor; -extern const struct sensors_sensor button_right_sensor; +extern const struct sensors_sensor btn1_sensor; +extern const struct sensors_sensor btn2_sensor; /*---------------------------------------------------------------------------*/ #endif /* BUTTON_SENSOR_ARCH_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc1312r1/Makefile.cc1312r1 b/arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc1312r1/Makefile.cc1312r1 new file mode 100644 index 000000000..880c7a995 --- /dev/null +++ b/arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc1312r1/Makefile.cc1312r1 @@ -0,0 +1,22 @@ +################################################################################ +# SimpleLink Device makefile + +SDK_BOARD_NAME := CC1312R1_LAUNCHXL + +SDK_BOARD_PATH := $(SDK_BOARDS)/$(SDK_BOARD_NAME) + +SDK_BOARD_PATH_EXISTS := $(shell test ! -d $(SDK_BOARD_PATH); echo $$?) +ifeq ($(SDK_BOARD_PATH_EXISTS),0) + $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported by the specified Simplelink SDK) +endif + +DEFINES += SUPPORTS_PROP_MODE=1 +DEFINES += SUPPORTS_IEEE_MODE=0 + +# Add to the source dirs +BOARD_SOURCEFILES += $(SDK_BOARD_NAME).c + +EXTERNALDIRS += $(SDK_BOARD_PATH) + +# Include the common launchpad makefile +include $(PLATFORM_ROOT_DIR)/launchpad/Makefile.launchpad diff --git a/arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc1352p1/Makefile.cc1352p1 b/arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc1352p1/Makefile.cc1352p1 new file mode 100644 index 000000000..ba161e6ab --- /dev/null +++ b/arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc1352p1/Makefile.cc1352p1 @@ -0,0 +1,22 @@ +################################################################################ +# SimpleLink Device makefile + +SDK_BOARD_NAME := CC1352P1_LAUNCHXL + +SDK_BOARD_PATH := $(SDK_BOARDS)/$(SDK_BOARD_NAME) + +SDK_BOARD_PATH_EXISTS := $(shell test ! -d $(SDK_BOARD_PATH); echo $$?) +ifeq ($(SDK_BOARD_PATH_EXISTS),0) + $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported by the specified Simplelink SDK) +endif + +DEFINES += SUPPORTS_PROP_MODE=1 +DEFINES += SUPPORTS_IEEE_MODE=1 + +# Add to the source dirs +BOARD_SOURCEFILES += $(SDK_BOARD_NAME).c + +EXTERNALDIRS += $(SDK_BOARD_PATH) + +# Include the common launchpad makefile +include $(PLATFORM_ROOT_DIR)/launchpad/Makefile.launchpad diff --git a/arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc1352r1/Makefile.cc1352r1 b/arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc1352r1/Makefile.cc1352r1 new file mode 100644 index 000000000..7149d55b4 --- /dev/null +++ b/arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc1352r1/Makefile.cc1352r1 @@ -0,0 +1,22 @@ +################################################################################ +# SimpleLink Device makefile + +SDK_BOARD_NAME := CC1352R1_LAUNCHXL + +# Check that the provided Simplelink SDK supports this device. Simply checking +# whether a folder with the name of $(SDK_BOARD_NAME) exists in the board folder +# is sufficient, # i.e. folder exists in /source/ti/boards. +SDK_BOARD_PATH := $(SDK_BOARDS)/$(SDK_BOARD_NAME) +SDK_BOARD_PATH_EXISTS := $(shell test ! -d $(SDK_BOARD_PATH); echo $$?) +ifeq ($(SDK_BOARD_PATH_EXISTS),0) + $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported by the specified Simplelink SDK) +endif + +DEFINES += SUPPORTS_PROP_MODE=1 +DEFINES += SUPPORTS_IEEE_MODE=1 + +# Add to the source dirs +BOARD_SOURCEFILES += $(SDK_BOARD_NAME).c + +# Include the common launchpad makefile +include $(PLATFORM_ROOT_DIR)/launchpad/Makefile.launchpad diff --git a/arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc26x2r1/Makefile.cc26x2r1 b/arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc26x2r1/Makefile.cc26x2r1 new file mode 100644 index 000000000..f42409d8e --- /dev/null +++ b/arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc26x2r1/Makefile.cc26x2r1 @@ -0,0 +1,22 @@ +################################################################################ +# SimpleLink Device makefile + +SDK_BOARD_NAME := CC26X2R1_LAUNCHXL + +SDK_BOARD_PATH := $(SDK_BOARDS)/$(SDK_BOARD_NAME) + +SDK_BOARD_PATH_EXISTS := $(shell test ! -d $(SDK_BOARD_PATH); echo $$?) +ifeq ($(SDK_BOARD_PATH_EXISTS),0) + $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported by the specified Simplelink SDK) +endif + +DEFINES += SUPPORTS_PROP_MODE=0 +DEFINES += SUPPORTS_IEEE_MODE=1 + +# Add to the source dirs +BOARD_SOURCEFILES += $(SDK_BOARD_NAME).c + +EXTERNALDIRS += $(SDK_BOARD_PATH) + +# Include the common launchpad makefile +include $(PLATFORM_ROOT_DIR)/launchpad/Makefile.launchpad diff --git a/arch/platform/simplelink/cc13x2_cc26x2/launchpad/launchpad-sensors.c b/arch/platform/simplelink/cc13x2-cc26x2/launchpad/launchpad-sensors.c similarity index 93% rename from arch/platform/simplelink/cc13x2_cc26x2/launchpad/launchpad-sensors.c rename to arch/platform/simplelink/cc13x2-cc26x2/launchpad/launchpad-sensors.c index de65965f8..c9c7b6d2e 100644 --- a/arch/platform/simplelink/cc13x2_cc26x2/launchpad/launchpad-sensors.c +++ b/arch/platform/simplelink/cc13x2-cc26x2/launchpad/launchpad-sensors.c @@ -39,12 +39,17 @@ #include #include /*---------------------------------------------------------------------------*/ -#include "button-sensor-arch.h" +#include "button-sensor.h" /*---------------------------------------------------------------------------*/ /* Exports a global symbol to be used by the sensor API */ SENSORS( - &btn1_sensor, - &btn2_sensor +#ifdef BUTTON_SENSOR_ARCH_BTN1 + &button_sensor, +#endif +#ifdef BUTTON_SENSOR_ARCH_BTN2 + &button_sensor2, +#endif + NULL ); /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/platform/simplelink/cc13x2_cc26x2/srf06/als-sensor-arch.c b/arch/platform/simplelink/cc13x2-cc26x2/launchpad/leds-arch.c similarity index 59% rename from arch/platform/simplelink/cc13x2_cc26x2/srf06/als-sensor-arch.c rename to arch/platform/simplelink/cc13x2-cc26x2/launchpad/leds-arch.c index 1c40c3f12..7595d47d3 100644 --- a/arch/platform/simplelink/cc13x2_cc26x2/srf06/als-sensor-arch.c +++ b/arch/platform/simplelink/cc13x2-cc26x2/launchpad/leds-arch.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, University of Bristol - http://www.bris.ac.uk/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,71 +29,106 @@ */ /*---------------------------------------------------------------------------*/ /** - * \addtogroup srf06-common-peripherals + * \addtogroup simplelink-platform * @{ * * \file - * Driver for the SmartRF06EB ALS when a CC13xx/CC26xxEM is mounted on it + * Driver for LaunchPad LEDs */ /*---------------------------------------------------------------------------*/ +/* Contiki API */ #include -#include -#include +#include /*---------------------------------------------------------------------------*/ +/* Simplelink SDK API */ #include -#include -#include -#include -/*---------------------------------------------------------------------------*/ -#include "als-sensor.h" -#include "als-sensor-arch.h" +#include /*---------------------------------------------------------------------------*/ +/* Standard library */ +#include #include /*---------------------------------------------------------------------------*/ -/* SmartRF06 EB has one Analog Light Sensor (ALS) */ -#define ALS_OUT_DIO Board_ALS_OUT -#define ALS_PWR_DIO Board_ALS_PWR -/*---------------------------------------------------------------------------*/ -static int -config(int type, int value) -{ - switch (type) { - case SENSORS_ACTIVE: - IOCPinTypeGpioOutput(ALS_PWR_DIO); - IOCPortConfigureSet(ALS_OUT_DIO, IOC_PORT_GPIO, IOC_STD_OUTPUT); - IOCPinTypeGpioInput(ALS_OUT_DIO); +/* Available LED configuration */ - if (value) { - GPIO_setDio(ALS_PWR_DIO); - AUXADCSelectInput(ALS_OUT_DIO); - clock_delay_usec(2000); - } else { - GPIO_clearDio(ALS_PWR_DIO); - } - break; +/* Green LED */ +#ifdef Board_GPIO_GLED +# define LEDS_ARCH_GREEN Board_GPIO_GLED +#endif + +/* Yellow LED */ +#ifdef Board_GPIO_YLED +# define LEDS_ARCH_YELLOW Board_GPIO_YLED +#endif + +/* Red LED */ +#ifdef Board_GPIO_RLED +# define LEDS_ARCH_RED Board_GPIO_RLED +#endif + +/* Blue LED */ +#ifdef Board_GPIO_BLED +# define LEDS_ARCH_BLUE Board_GPIO_BLED +#endif +/*---------------------------------------------------------------------------*/ +static unsigned char c; +/*---------------------------------------------------------------------------*/ +void +leds_arch_init(void) +{ + static bool bHasInit = false; + if(bHasInit) { + return; } - return 1; + bHasInit = true; + + // GPIO_init will most likely be called in platform.c, + // but call it here to be sure GPIO is initialized. + // Calling GPIO_init multiple times is safe. + GPIO_init(); } /*---------------------------------------------------------------------------*/ -static int -value(int type) +unsigned char +leds_arch_get(void) { - AUXADCEnableSync(AUXADC_REF_VDDS_REL, AUXADC_SAMPLE_TIME_2P7_US, AUXADC_TRIGGER_MANUAL); - AUXADCGenManualTrigger(); - - int val = AUXADCReadFifo(); - - AUXADCDisable(); - - return val; + return c; } /*---------------------------------------------------------------------------*/ -static int -status(int type) +static inline void +write_led(const bool on, const uint_fast32_t gpioLed) { - return 1; + const GPIO_PinConfig pinCfg = (on) + ? Board_GPIO_LED_ON : Board_GPIO_LED_OFF; + GPIO_write(gpioLed, pinCfg); } /*---------------------------------------------------------------------------*/ -SENSORS_SENSOR(als_sensor, ALS_SENSOR, value, config, status); +void +leds_arch_set(unsigned char leds) +{ + c = leds; + +#define LED_ON(led_define) ((leds & (led_define)) == (led_define)) + + // Green LED +#ifdef LEDS_ARCH_GREEN + write_led(LED_ON(LEDS_GREEN), LEDS_ARCH_GREEN); +#endif + + // Yellow LED +#ifdef LEDS_ARCH_YELLOW + write_led(LED_ON(LEDS_YELLOW), LEDS_ARCH_YELLOW); +#endif + + // Red LED +#ifdef LEDS_ARCH_RED + write_led(LED_ON(LEDS_RED), LEDS_ARCH_RED); +#endif + + // Blue LED +#ifdef LEDS_ARCH_BLUE + write_led(LED_ON(LEDS_BLUE), LEDS_ARCH_BLUE); +#endif + +#undef LED_ON +} /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/platform/simplelink/cc13x2-cc26x2/platform.c b/arch/platform/simplelink/cc13x2-cc26x2/platform.c new file mode 100644 index 000000000..c5718a103 --- /dev/null +++ b/arch/platform/simplelink/cc13x2-cc26x2/platform.c @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup cc13xx-cc26xx-platforms + * @{ + * + * \defgroup LaunchPads + * + * This platform supports a number of different boards: + * - The TI CC1310 LaunchPad + * - The TI CC1350 LaunchPad + * - The TI CC2640 LaunchPad + * - The TI CC2650 LaunchPad + * - The TI CC1312R1 LaunchPad + * - The TI CC1352R1 LaunchPad + * - The TI CC1352P1 LaunchPad + * - The TI CC26X2R1 LaunchPad + * @{ + */ +/*---------------------------------------------------------------------------*/ +/* Simplelink SDK includes */ +#include +#include +#include +#include +#include +#include +#include +#include +/*---------------------------------------------------------------------------*/ +/* Contiki API */ +#include "contiki.h" +#include "contiki-net.h" +#include "sys/clock.h" +#include "sys/rtimer.h" +#include "sys/node-id.h" +#include "sys/platform.h" +#include "dev/serial-line.h" +#include "dev/leds.h" +#include "net/mac/framer/frame802154.h" +#include "lib/sensors.h" +/*---------------------------------------------------------------------------*/ +/* Arch driver implementations */ +#include "uart0-arch.h" +/*---------------------------------------------------------------------------*/ +//#include "gpio-interrupt.h" +#include "ieee-addr.h" +#include "dev/rf-common.h" +#include "lib/random.h" +#include "button-sensor.h" +/*---------------------------------------------------------------------------*/ +#include +/*---------------------------------------------------------------------------*/ +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "CC26xx/CC13xx" +#define LOG_LEVEL LOG_LEVEL_DBG +/*---------------------------------------------------------------------------*/ +unsigned short g_nodeId = 0; +/*---------------------------------------------------------------------------*/ +/** \brief Board specific initialization */ +void board_init(void); +/*---------------------------------------------------------------------------*/ +static void +fade(unsigned char l) +{ + volatile int i; + for(int k = 0; k < 800; ++k) { + int j = k > 400 ? 800 - k : k; + + leds_on(l); + for(i = 0; i < j; ++i) { + __asm("nop"); + } + leds_off(l); + for(i = 0; i < 400 - j; ++i) { + __asm("nop"); + } + } +} +/*---------------------------------------------------------------------------*/ +static void +set_rf_params(void) +{ + uint16_t short_addr; + uint8_t ext_addr[8]; + + ieee_addr_cpy_to(ext_addr, sizeof(ext_addr)); + + short_addr = ext_addr[7]; + short_addr |= ext_addr[6] << 8; + + 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_object(RADIO_PARAM_64BIT_ADDR, ext_addr, sizeof(ext_addr)); + + /* also set the global node id */ + g_nodeId = short_addr; +} +/*---------------------------------------------------------------------------*/ +void +platform_init_stage_one(void) +{ + // Enable flash cache + VIMSModeSet(VIMS_BASE, VIMS_MODE_ENABLED); + // Configure round robin arbitration and prefetching + VIMSConfigure(VIMS_BASE, true, true); + + Board_initGeneral(); + GPIO_init(); + + // NoRTOS_start only enables HWI + NoRTOS_start(); + + // Contiki drivers init + leds_init(); + +// ti_lib_int_master_disable(); +// +// /* Set the LF XOSC as the LF system clock source */ +// oscillators_select_lf_xosc(); +// +// lpm_init(); +// + fade(LEDS_RED); +// +// /* +// * Disable I/O pad sleep mode and open I/O latches in the AON IOC interface +// * This is only relevant when returning from shutdown (which is what froze +// * latches in the first place. Before doing these things though, we should +// * allow software to first regain control of pins +// */ +// ti_lib_pwr_ctrl_io_freeze_disable(); +// +// ti_lib_int_master_enable(); +// + fade(LEDS_GREEN); +} +/*---------------------------------------------------------------------------*/ +void +platform_init_stage_two(void) +{ +#if SIMPLELINK_UART_CONF_ENABLE + uart0_init(); +#endif + + serial_line_init(); + +#if BUILD_WITH_SHELL + uart0_set_callback(serial_line_input_byte); +#endif + + // random_init(0x1234); + + /* Populate linkaddr_node_addr */ + ieee_addr_cpy_to(linkaddr_node_addr.u8, LINKADDR_SIZE); + + fade(LEDS_RED); +} +/*---------------------------------------------------------------------------*/ +void +platform_init_stage_three(void) +{ + radio_value_t chan, pan; + + set_rf_params(); + + NETSTACK_RADIO.get_value(RADIO_PARAM_CHANNEL, &chan); + NETSTACK_RADIO.get_value(RADIO_PARAM_PAN_ID, &pan); + + LOG_DBG("With DriverLib v%u.%u\n", DRIVERLIB_RELEASE_GROUP, + DRIVERLIB_RELEASE_BUILD); + LOG_DBG("IEEE 802.15.4: %s, Sub-GHz: %s, BLE: %s, Prop: %s\n", + ChipInfo_SupportsIEEE_802_15_4() ? "Yes" : "No", + ChipInfo_ChipFamilyIs_CC13x0() ? "Yes" : "No", + ChipInfo_SupportsBLE() ? "Yes" : "No", + ChipInfo_SupportsPROPRIETARY() ? "Yes" : "No"); + LOG_INFO("RF: Channel %d, PANID 0x%04X\n", chan, pan); + LOG_INFO("Node ID: %d\n", g_nodeId); + + process_start(&sensors_process, NULL); + fade(LEDS_GREEN); +} +/*---------------------------------------------------------------------------*/ +void +platform_idle(void) +{ + // Drop to some low power mode + Power_idleFunc(); +} +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/platform/simplelink/cc13x2_cc26x2/Makefile.cc13x2_cc26x2 b/arch/platform/simplelink/cc13x2_cc26x2/Makefile.cc13x2_cc26x2 deleted file mode 100644 index 156d2b010..000000000 --- a/arch/platform/simplelink/cc13x2_cc26x2/Makefile.cc13x2_cc26x2 +++ /dev/null @@ -1,28 +0,0 @@ -# SimpleLink MCU platform makefile - -### Board and BSP selection - -CONTIKI_TARGET_SOURCEFILES += leds-arch.c - -# Launchpad boards -ifneq (,$(findstring LAUNCHXL, $(SIMPLELINK_BOARD))) -CONTIKI_TARGET_DIRS += $(FAMILY)/launchpad -CONTIKI_TARGET_SOURCEFILES += button-sensor-arch.c -CONTIKI_TARGET_SOURCEFILES += launchpad-sensors.c - -# Custom boards -else ifneq (,$(findstring CUSTOM, $(SIMPLELINK_BOARD))) -# TODO Need to figure out how custom boards are to be provided -CONTIKI_TARGET_DIRS += $(FAMILY)/custom -CONTIKI_TARGET_SOURCEFILES += custom-sensors.c - -# Everything else is assumed to be EVMs for the SmartRF06 EB (srf06) -else -CONTIKI_TARGET_DIRS += $(FAMILY)/srf06 -CONTIKI_TARGET_SOURCEFILES += button-sensor-arch.c -CONTIKI_TARGET_SOURCEFILES += srf06-sensors.c - -endif - -CONTIKI_TARGET_SOURCEFILES += button-sensor-arch.c - From 02b812a631edf4906dbaa0ddbb30e77fa9d48542 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Mon, 28 May 2018 13:17:01 +0200 Subject: [PATCH 245/485] [Feature]: Simplelink Platform for Simplelink SDK Working Simplelink platform with the following Simplelink SDK's: * CC13x0 SDK * CC13x2 SDK * CC26x2 SDK Is also compatible with Code Composer Studio (XDCTools) --- arch/cpu/arm/cortex-m/cm4/Makefile.cm4 | 4 +- arch/cpu/cc13xx-cc26xx/Makefile.cc13x0-cc26x0 | 114 +- arch/cpu/cc13xx-cc26xx/Makefile.cc13x2-cc26x2 | 66 +- arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 113 ++ arch/cpu/cc13xx-cc26xx/Makefile.cc26x0 | 73 ++ .../cc13x0-cc26x0/cc13x0-cc26x0.lds | 203 +++ .../cc13x0-cc26x0/driverlib/rf_ieee_cmd.h | 629 +++++++++ .../cc13x0-cc26x0/driverlib/rf_ieee_mailbox.h | 74 ++ .../rf-settings/rf-ieee-settings.c | 227 ++++ .../rf-settings/rf-ieee-settings.h | 26 + .../rf-settings/rf-prop-settings.c | 276 ++++ .../rf-settings/rf-prop-settings.h | 0 .../rf_patches/rf_patch_cpe_ieee.h | 269 ++++ .../cc13x2-cc26x2/cc13x2-cc26x2.lds | 204 +++ .../rf-settings/rf-ieee-settings.c | 0 .../rf-settings/rf-ieee-settings.h | 0 .../rf-settings/rf-prop-settings.c | 0 .../rf-settings/rf-prop-settings.h | 35 + arch/cpu/cc13xx-cc26xx/dev/batmon-sensor.c | 139 ++ .../cc13xx-cc26xx/dev/batmon-sensor.h} | 23 +- arch/cpu/cc13xx-cc26xx/dev/clock-arch.c | 55 +- arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c | 43 +- .../dev/startup_cc13xx_cc26xx_gcc.c | 308 +++++ arch/cpu/cc13xx-cc26xx/dev/ti-lib-rom.h | 194 +++ arch/cpu/cc13xx-cc26xx/dev/ti-lib.h | 578 +++++++++ .../simplelink/Makefile.device-family | 20 +- arch/platform/simplelink/Makefile.simplelink | 45 +- .../cc13x0-cc26x0/Makefile.cc13x0-cc26x0 | 106 -- .../launchpad/Makefile.launchpad | 12 - .../launchpad/button-sensor-arch.c | 198 --- .../launchpad/cc1310/Makefile.cc1310 | 22 - .../launchpad/cc1350-4/Makefile.cc1350-4 | 22 - .../launchpad/cc1350/Makefile.cc1350 | 22 - .../launchpad/cc2650/Makefile.cc2650 | 22 - .../sensortag/Makefile.sensortag | 12 - .../sensortag/cc1350/Makefile.cc1350 | 22 - .../sensortag/cc2650/Makefile.cc2650 | 22 - .../cc13x0-cc26x0/srf06/Makefile.srf06 | 12 - .../srf06/cc1310/Makefile.cc1310 | 22 - .../srf06/cc1350/Makefile.cc1350 | 22 - .../srf06/cc2650/Makefile.cc2650 | 22 - .../cc13x2-cc26x2/Makefile.cc13x2-cc26x2 | 103 -- .../launchpad/Makefile.launchpad | 12 - .../launchpad/cc1312r1/Makefile.cc1312r1 | 22 - .../launchpad/cc1352p1/Makefile.cc1352p1 | 22 - .../launchpad/cc1352r1/Makefile.cc1352r1 | 22 - .../launchpad/cc26x2r1/Makefile.cc26x2r1 | 22 - .../simplelink/cc13x2-cc26x2/platform.c | 224 ---- .../cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 65 + .../common/button-sensor.h | 0 .../contiki-conf.h | 4 +- .../launchpad/Makefile.launchpad | 10 + .../launchpad/board-peripherals.h} | 37 +- .../launchpad/button-sensor-arch.c | 2 +- .../launchpad/button-sensor-arch.h | 0 .../cc13xx-cc26xx/launchpad/cc1310/Board.h | 136 ++ .../launchpad/cc1310/CC1310_LAUNCHXL.c | 911 +++++++++++++ .../launchpad/cc1310/CC1310_LAUNCHXL.h | 359 ++++++ .../launchpad/cc1310/Makefile.cc1310 | 16 + .../cc13xx-cc26xx/launchpad/cc1312r1/Board.h | 142 +++ .../launchpad/cc1312r1/CC1312R1_LAUNCHXL.c | 1033 +++++++++++++++ .../launchpad/cc1312r1/CC1312R1_LAUNCHXL.h | 418 ++++++ .../launchpad/cc1312r1/Makefile.cc1312r1 | 16 + .../cc13xx-cc26xx/launchpad/cc1350-4/Board.h | 146 +++ .../launchpad/cc1350-4/CC1350_LAUNCHXL_433.c | 945 ++++++++++++++ .../launchpad/cc1350-4/CC1350_LAUNCHXL_433.h | 361 ++++++ .../launchpad/cc1350-4/Makefile.cc1350-4 | 16 + .../cc13xx-cc26xx/launchpad/cc1350/Board.h | 145 +++ .../launchpad/cc1350/CC1350_LAUNCHXL.c | 946 ++++++++++++++ .../launchpad/cc1350/CC1350_LAUNCHXL.h | 361 ++++++ .../launchpad/cc1350/Makefile.cc1350 | 16 + .../cc13xx-cc26xx/launchpad/cc1352p1/Board.h | 151 +++ .../launchpad/cc1352p1/CC1352P1_LAUNCHXL.c | 1127 +++++++++++++++++ .../launchpad/cc1352p1/CC1352P1_LAUNCHXL.h | 431 +++++++ .../launchpad/cc1352p1/Makefile.cc1352p1 | 16 + .../cc13xx-cc26xx/launchpad/cc1352r1/Board.h | 150 +++ .../launchpad/cc1352r1/CC1352R1_LAUNCHXL.c | 1072 ++++++++++++++++ .../launchpad/cc1352r1/CC1352R1_LAUNCHXL.h | 423 +++++++ .../launchpad/cc1352r1/Makefile.cc1352r1 | 16 + .../cc13xx-cc26xx/launchpad/cc2650/Board.h | 84 ++ .../launchpad/cc2650/CC2650_LAUNCHXL.c | 752 +++++++++++ .../launchpad/cc2650/CC2650_LAUNCHXL.h | 320 +++++ .../launchpad/cc2650/Makefile.cc2650 | 16 + .../cc13xx-cc26xx/launchpad/cc26x2r1/Board.h | 154 +++ .../launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c | 1056 +++++++++++++++ .../launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h | 424 +++++++ .../launchpad/cc26x2r1/Makefile.cc26x2r1 | 16 + .../cc13xx-cc26xx/launchpad/ext-flash.c | 448 +++++++ .../cc13xx-cc26xx/launchpad/ext-flash.h | 116 ++ .../launchpad/launchpad-sensors.c | 0 .../cc13xx-cc26xx/launchpad/launchpad.c | 61 + .../launchpad/leds-arch.c | 0 .../platform.c | 0 .../sensortag/Makefile.sensortag | 10 + .../cc13xx-cc26xx/sensortag/bmp-280-sensor.c | 392 ++++++ .../cc13xx-cc26xx/sensortag/bmp-280-sensor.h | 68 + .../cc13xx-cc26xx/sensortag/board-i2c.c | 343 +++++ .../cc13xx-cc26xx/sensortag/board-i2c.h | 131 ++ .../sensortag/board-peripherals.h} | 66 +- .../cc13xx-cc26xx/sensortag/button-sensor.c | 281 ++++ .../sensortag}/button-sensor.h | 17 +- .../cc13xx-cc26xx/sensortag/buzzer.c | 143 +++ .../cc13xx-cc26xx/sensortag/buzzer.h | 74 ++ .../cc13xx-cc26xx/sensortag/cc1350/Board.h | 129 ++ .../sensortag/cc1350/CC1350STK.c | 756 +++++++++++ .../sensortag/cc1350/CC1350STK.h | 323 +++++ .../sensortag/cc1350/Makefile.cc1350 | 16 + .../cc13xx-cc26xx/sensortag/cc2650/Board.h | 90 ++ .../sensortag/cc2650/CC2650STK.c | 647 ++++++++++ .../sensortag/cc2650/CC2650STK.h | 326 +++++ .../sensortag/cc2650/Makefile.cc2650 | 16 + .../cc13xx-cc26xx/sensortag/hdc-1000-sensor.c | 304 +++++ .../cc13xx-cc26xx/sensortag/hdc-1000-sensor.h | 87 ++ .../cc13xx-cc26xx/sensortag/mpu-9250-sensor.c | 663 ++++++++++ .../cc13xx-cc26xx/sensortag/mpu-9250-sensor.h | 110 ++ .../cc13xx-cc26xx/sensortag/opt-3001-sensor.c | 327 +++++ .../cc13xx-cc26xx/sensortag/opt-3001-sensor.h | 69 + .../cc13xx-cc26xx/sensortag/reed-relay.c | 140 ++ .../cc13xx-cc26xx/sensortag/reed-relay.h | 59 + .../sensortag/sensortag-sensors.c | 0 .../cc13xx-cc26xx/sensortag/sensortag.c | 162 +++ .../cc13xx-cc26xx/sensortag/tmp-007-sensor.c | 319 +++++ .../cc13xx-cc26xx/sensortag/tmp-007-sensor.h | 76 ++ .../cc13xx-cc26xx/srf06/Makefile.srf06 | 10 + .../cc13xx-cc26xx/srf06/als-sensor.c | 105 ++ .../srf06}/als-sensor.h | 8 +- .../cc13xx-cc26xx/srf06/board-peripherals.h | 55 + .../cc13xx-cc26xx/srf06/button-sensor.c | 491 +++++++ .../cc13xx-cc26xx/srf06/button-sensor.h | 60 + .../cc13xx-cc26xx/srf06/cc13x0/Board.h | 88 ++ .../cc13xx-cc26xx/srf06/cc13x0/CC1310DK_7XD.c | 670 ++++++++++ .../cc13xx-cc26xx/srf06/cc13x0/CC1310DK_7XD.h | 289 +++++ .../srf06/cc13x0/Makefile.cc13x0 | 16 + .../cc13xx-cc26xx/srf06/cc26x0/Board.h | 87 ++ .../cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c | 668 ++++++++++ .../cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h | 290 +++++ .../srf06/cc26x0/Makefile.cc26x0 | 16 + .../cc13xx-cc26xx/srf06/leds-arch.c | 90 ++ .../srf06/srf06-sensors.c | 0 .../srf06/srf06.c} | 156 +-- 140 files changed, 25454 insertions(+), 1390 deletions(-) create mode 100644 arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx create mode 100644 arch/cpu/cc13xx-cc26xx/Makefile.cc26x0 create mode 100644 arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds create mode 100644 arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/driverlib/rf_ieee_cmd.h create mode 100644 arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/driverlib/rf_ieee_mailbox.h create mode 100644 arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-ieee-settings.c create mode 100644 arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-ieee-settings.h create mode 100644 arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-prop-settings.c rename arch/cpu/cc13xx-cc26xx/{ => cc13x0-cc26x0}/rf-settings/rf-prop-settings.h (100%) create mode 100644 arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf_patches/rf_patch_cpe_ieee.h create mode 100644 arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds rename arch/cpu/cc13xx-cc26xx/{ => cc13x2-cc26x2}/rf-settings/rf-ieee-settings.c (100%) rename arch/cpu/cc13xx-cc26xx/{ => cc13x2-cc26x2}/rf-settings/rf-ieee-settings.h (100%) rename arch/cpu/cc13xx-cc26xx/{ => cc13x2-cc26x2}/rf-settings/rf-prop-settings.c (100%) create mode 100644 arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/rf-settings/rf-prop-settings.h create mode 100644 arch/cpu/cc13xx-cc26xx/dev/batmon-sensor.c rename arch/{platform/simplelink/cc13x2-cc26x2/launchpad/button-sensor-arch.h => cpu/cc13xx-cc26xx/dev/batmon-sensor.h} (79%) create mode 100644 arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c create mode 100644 arch/cpu/cc13xx-cc26xx/dev/ti-lib-rom.h create mode 100644 arch/cpu/cc13xx-cc26xx/dev/ti-lib.h delete mode 100644 arch/platform/simplelink/cc13x0-cc26x0/Makefile.cc13x0-cc26x0 delete mode 100644 arch/platform/simplelink/cc13x0-cc26x0/launchpad/Makefile.launchpad delete mode 100644 arch/platform/simplelink/cc13x0-cc26x0/launchpad/button-sensor-arch.c delete mode 100644 arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc1310/Makefile.cc1310 delete mode 100644 arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc1350-4/Makefile.cc1350-4 delete mode 100644 arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc1350/Makefile.cc1350 delete mode 100644 arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc2650/Makefile.cc2650 delete mode 100644 arch/platform/simplelink/cc13x0-cc26x0/sensortag/Makefile.sensortag delete mode 100644 arch/platform/simplelink/cc13x0-cc26x0/sensortag/cc1350/Makefile.cc1350 delete mode 100644 arch/platform/simplelink/cc13x0-cc26x0/sensortag/cc2650/Makefile.cc2650 delete mode 100644 arch/platform/simplelink/cc13x0-cc26x0/srf06/Makefile.srf06 delete mode 100644 arch/platform/simplelink/cc13x0-cc26x0/srf06/cc1310/Makefile.cc1310 delete mode 100644 arch/platform/simplelink/cc13x0-cc26x0/srf06/cc1350/Makefile.cc1350 delete mode 100644 arch/platform/simplelink/cc13x0-cc26x0/srf06/cc2650/Makefile.cc2650 delete mode 100644 arch/platform/simplelink/cc13x2-cc26x2/Makefile.cc13x2-cc26x2 delete mode 100644 arch/platform/simplelink/cc13x2-cc26x2/launchpad/Makefile.launchpad delete mode 100644 arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc1312r1/Makefile.cc1312r1 delete mode 100644 arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc1352p1/Makefile.cc1352p1 delete mode 100644 arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc1352r1/Makefile.cc1352r1 delete mode 100644 arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc26x2r1/Makefile.cc26x2r1 delete mode 100644 arch/platform/simplelink/cc13x2-cc26x2/platform.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx rename arch/platform/simplelink/{cc13x0-cc26x0 => cc13xx-cc26xx}/common/button-sensor.h (100%) rename arch/platform/simplelink/{cc13x2-cc26x2 => cc13xx-cc26xx}/contiki-conf.h (97%) create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/Makefile.launchpad rename arch/platform/simplelink/{cc13x0-cc26x0/launchpad/launchpad-sensors.c => cc13xx-cc26xx/launchpad/board-peripherals.h} (81%) rename arch/platform/simplelink/{cc13x2-cc26x2 => cc13xx-cc26xx}/launchpad/button-sensor-arch.c (99%) rename arch/platform/simplelink/{cc13x0-cc26x0 => cc13xx-cc26xx}/launchpad/button-sensor-arch.h (100%) create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Board.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Makefile.cc1310 create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Board.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Board.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Makefile.cc1350-4 create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Board.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Makefile.cc1350 create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Board.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Board.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Makefile.cc2650 create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Board.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Makefile.cc26x2r1 create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/ext-flash.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/ext-flash.h rename arch/platform/simplelink/{cc13x2-cc26x2 => cc13xx-cc26xx}/launchpad/launchpad-sensors.c (100%) create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/launchpad.c rename arch/platform/simplelink/{cc13x0-cc26x0 => cc13xx-cc26xx}/launchpad/leds-arch.c (100%) rename arch/platform/simplelink/{cc13x0-cc26x0 => cc13xx-cc26xx}/platform.c (100%) create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/Makefile.sensortag create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-i2c.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-i2c.h rename arch/platform/simplelink/{cc13x0-cc26x0/contiki-conf.h => cc13xx-cc26xx/sensortag/board-peripherals.h} (67%) create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor.c rename arch/platform/simplelink/{cc13x2-cc26x2/common => cc13xx-cc26xx/sensortag}/button-sensor.h (87%) create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Makefile.cc1350 create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/reed-relay.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/reed-relay.h rename arch/platform/simplelink/{cc13x0-cc26x0 => cc13xx-cc26xx}/sensortag/sensortag-sensors.c (100%) create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/srf06/Makefile.srf06 create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/srf06/als-sensor.c rename arch/platform/simplelink/{cc13x0-cc26x0/common => cc13xx-cc26xx/srf06}/als-sensor.h (94%) create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/srf06/board-peripherals.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Board.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1310DK_7XD.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1310DK_7XD.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Board.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Makefile.cc26x0 create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/srf06/leds-arch.c rename arch/platform/simplelink/{cc13x0-cc26x0 => cc13xx-cc26xx}/srf06/srf06-sensors.c (100%) rename arch/platform/simplelink/{cc13x2-cc26x2/launchpad/leds-arch.c => cc13xx-cc26xx/srf06/srf06.c} (53%) diff --git a/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 b/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 index 5c4d4526b..886b33ad4 100644 --- a/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 +++ b/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 @@ -7,7 +7,7 @@ LDFLAGS += -T $(LDSCRIPT) LDFLAGS += -Wl,--gc-sections,--sort-section=alignment LDFLAGS += -Wl,-Map=$(@:.elf=-$(TARGET).map),--cref,--no-warn-mismatch -TARGET_LIBFLAGS := $(TARGET_LIBFILES) -lc -lgcc -lm -lnosys +TARGET_LIBFLAGS := -Wl,--start-group $(TARGET_LIBFILES) -lc -lgcc -lm -lnosys -Wl,--end-group OBJCOPY_FLAGS += --gap-fill 0xff @@ -23,6 +23,6 @@ CUSTOM_RULE_LINK = 1 %.elf: $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(TARGET_LIBS) $(TRACE_LD) - $(Q)$(LD) $(LDFLAGS) ${filter %.o %.a,$^} -Wl,--start-group $(TARGET_LIBFLAGS) -Wl,--end-group -o $@ + $(Q)$(LD) $(LDFLAGS) ${filter %.o %.a,$^} $(TARGET_LIBFLAGS) -o $@ include $(CONTIKI)/arch/cpu/arm/cortex-m/Makefile.cortex-m diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.cc13x0-cc26x0 b/arch/cpu/cc13xx-cc26xx/Makefile.cc13x0-cc26x0 index 15dd27e99..023ef556b 100644 --- a/arch/cpu/cc13xx-cc26xx/Makefile.cc13x0-cc26x0 +++ b/arch/cpu/cc13xx-cc26xx/Makefile.cc13x0-cc26x0 @@ -1,114 +1,10 @@ ################################################################################ # CC13x0/CC26x0 CPU makefile -CPU_ABS_PATH = arch/cpu/simplelink - -TI_XXWARE := $(CONTIKI_CPU)/$(TI_XXWARE_PATH) - -### cc26xxware sources under driverlib will be added to the MODULES list -TI_XXWARE_SRC = $(CPU_ABS_PATH)/$(TI_XXWARE_PATH)/driverlib - -### The directory with startup sources will be added to the CONTIKI_CPU_DIRS -### and the sources therein are added to the sources list explicitly. They are -### also listed explicitly in the linker command (through TARGET_STARTFILES), -### to make sure they always get linked in the image -TI_XXWARE_STARTUP_DIR = $(TI_XXWARE_PATH)/startup_files -TI_XXWARE_STARTUP_SRCS = ccfg.c startup_gcc.c - -### MODULES will add some of these to the include path, but we need to add -### them earlier to prevent filename clashes with Contiki core files -CFLAGS += -I$(TI_XXWARE) -I$(CONTIKI)/$(TI_XXWARE_SRC) -CFLAGS += -I$(TI_XXWARE)/inc -MODULES += $(TI_XXWARE_SRC) - -LDSCRIPT = $(CONTIKI_CPU)/cc26xx.ld - -### If the user-specified a Node ID, pass a define -ifdef NODEID - CFLAGS += -DIEEE_ADDR_NODE_ID=$(NODEID) -endif - -### CPU-dependent directories -CPU_DIRS := dev rf-core rf-core/api $(TI_XXWARE_STARTUP_DIR) -CPU_DIRS_EXPAND := $(realpath $(addprefix $(BASE_DIR)/, $(CPU_DIRS))) - -CONTIKI_ARM_DIRS := $(CONTIKI_ARM_DIRS) $(CPU_DIRS) -CONTIKI_CPU_DIRS := $(CONTIKI_CPU_DIRS) $(CPU_DIRS_EXPAND) - -### CPU-dependent source files -CONTIKI_CPU_SOURCEFILES += clock.c rtimer-arch.c soc-rtc.c uart.c -CONTIKI_CPU_SOURCEFILES += contiki-watchdog.c aux-ctrl.c -CONTIKI_CPU_SOURCEFILES += putchar.c ieee-addr.c batmon-sensor.c adc-sensor.c -CONTIKI_CPU_SOURCEFILES += slip-arch.c slip.c cc26xx-uart.c lpm.c -CONTIKI_CPU_SOURCEFILES += gpio-interrupt.c oscillators.c -CONTIKI_CPU_SOURCEFILES += rf-core.c rf-ble.c ieee-mode.c -CONTIKI_CPU_SOURCEFILES += random.c soc-trng.c int-master.c - -DEBUG_IO_SOURCEFILES += dbg-printf.c dbg-snprintf.c dbg-sprintf.c strformat.c - -CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES) $(DEBUG_IO_SOURCEFILES) - -CPU_START_SOURCEFILES += fault-handlers.c $(TI_XXWARE_STARTUP_SRCS) - -PYTHON = python -BSL_FLAGS += -e -w -v - -ifdef PORT - BSL_FLAGS += -p $(PORT) -endif - -BSL = $(CONTIKI)/tools/cc2538-bsl/cc2538-bsl.py - -### Always re-build ieee-addr.o in case the command line passes a new NODEID -FORCE: - -$(OBJECTDIR)/ieee-addr.o: ieee-addr.c FORCE | $(OBJECTDIR) - $(TRACE_CC) - $(Q)$(CC) $(CFLAGS) -c $< -o $@ - -### Always re-build ccfg.c so changes to ccfg-conf.h will apply without having -### to make clean first -$(OBJECTDIR)/ccfg.o: ccfg.c FORCE | $(OBJECTDIR) - $(TRACE_CC) - $(Q)$(CC) $(CFLAGS) -include "ccxxware-conf.h" -c $< -o $@ - -# a target that gives a user-friendly memory profile, taking into account the RAM -# that is statically occupied by the stack as defined in the linker script -# see $(LDSCRIPT) -RAM_SIZE = 0x00003E00 -FLASH_SIZE = 0x0001E000 -STACK_SIZE = 0 -%.size: %.$(TARGET) - @$(SIZE) -A $< | egrep "data|bss" | awk '{s+=$$2} END {s=s+$(STACK_SIZE); f=$(RAM_SIZE)-s; printf "[RAM] used %6d, free %6d\n",s,f;}' - @$(SIZE) -A $< | egrep "text|isr_vector" | awk '{s+=$$2} END {f=$(FLASH_SIZE)-s; printf "[Flash] used %6d, free %6d\n",s,f;}' - -ifeq ($(BOARD_SUPPORTS_BSL),1) -%.upload: %.bin -ifeq ($(wildcard $(BSL)), ) - @echo "ERROR: Could not find the cc2538-bsl script. Did you run 'git submodule update --init' ?" -else - $(PYTHON) $(BSL) $(BSL_FLAGS) $< -endif -else -%.upload: - @echo "This board cannot be programmed through the ROM bootloader and therefore does not support the .upload target." -endif - -# Check if we are running under Windows -ifeq ($(HOST_OS),Windows) - SERIALDUMP ?= $(CONTIKI)/tools/sky/serialdump-windows -else -ifeq ($(HOST_OS),Darwin) - SERIALDUMP ?= $(CONTIKI)/tools/sky/serialdump-macos -else - # Else assume Linux - SERIALDUMP ?= $(CONTIKI)/tools/sky/serialdump-linux -endif -endif - -UART_BAUDRATE = 115200 - -login: - $(SERIALDUMP) -b$(UART_BAUDRATE) $(PORT) +### Simplelink SDK pre-compiled libraries +TARGET_LIBFILES += $(SDK_KERNEL)/lib/nortos_$(DEVICE_FAMILY_NAME).am3g +TARGET_LIBFILES += $(SDK_DRIVERS)/rf/lib/rf_multiMode_$(DEVICE_FAMILY_NAME).am3g +TARGET_LIBFILES += $(SDK_DRIVERS)/lib/drivers_$(DEVICE_FAMILY_NAME).am3g +TARGET_LIBFILES += $(SDK_DEVICE)/driverlib/bin/gcc/driverlib.lib include $(CONTIKI)/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.cc13x2-cc26x2 b/arch/cpu/cc13xx-cc26xx/Makefile.cc13x2-cc26x2 index 7b772f07d..64b083840 100644 --- a/arch/cpu/cc13xx-cc26xx/Makefile.cc13x2-cc26x2 +++ b/arch/cpu/cc13xx-cc26xx/Makefile.cc13x2-cc26x2 @@ -1,74 +1,10 @@ ################################################################################ # CC13x2/CC26x2 CPU makefile -# ccfg.c comes from the board-specific folder, and startup_cc13xx_cc26xx_gcc.c -# comes from NoRTOS startup folder -CPU_START_SOURCEFILES += ccfg.c startup_cc13xx_cc26xx_gcc.c - -EXTERNALDIRS += $(SDK_SOURCE) -EXTERNALDIRS += $(SDK_KERNEL) -EXTERNALDIRS += $(SDK_KERNEL)/startup -EXTERNALDIRS += $(SDK_BOARD_PATH) -EXTERNALDIRS += $(SDK_DEVICE) - -### If the user-specified a Node ID, pass a define -ifdef NODEID -DEFINES += IEEE_ADDR_NODE_ID=$(NODEID) -endif - -### CPU-dependent source files -CONTIKI_CPU_SOURCEFILES += rtimer-arch.c clock-arch.c -CONTIKI_CPU_SOURCEFILES += watchdog-arch.c putchar-arch.c -CONTIKI_CPU_SOURCEFILES += uart0-arch.c slip-arch.c -CONTIKI_CPU_SOURCEFILES += rf-common.c -CONTIKI_CPU_SOURCEFILES += rf-prop-mode.c rf-prop-settings.c -CONTIKI_CPU_SOURCEFILES += rf-ieee-mode.c rf-ieee-settings.c -CONTIKI_CPU_SOURCEFILES += ieee-addr.c - -### CPU-dependent directories -CONTIKI_CPU_DIRS += $(addprefix ../arm/, $(CPU_DIRS)) -CONTIKI_CPU_DIRS += . dev rf-settings cc13x2-cc26x2 - -### CPU-dependent debug source files -DEBUG_IO_SOURCEFILES += dbg-printf.c dbg-snprintf.c dbg-sprintf.c strformat.c - -CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES) $(DEBUG_IO_SOURCEFILES) - -ifeq ($(SMALL),0) -TARGET_LIBFILES += $(SDK_KERNEL)/lib/nortos_$(DEVICE_FAMILY_NAME).am4f -TARGET_LIBFILES += $(SDK_DRIVERS)/rf/lib/rf_multiMode_$(DEVICE_FAMILY_NAME).am4f -TARGET_LIBFILES += $(SDK_DRIVERS)/lib/drivers_$(DEVICE_FAMILY_NAME).am4f -TARGET_LIBFILES += $(SDK_DEVICE)/driverlib/bin/gcc/driverlib.lib -else +### Simplelink SDK pre-compiled libraries TARGET_LIBFILES += $(SDK_KERNEL)/lib/nortos_$(DEVICE_FAMILY_NAME).am4fg TARGET_LIBFILES += $(SDK_DRIVERS)/rf/lib/rf_multiMode_$(DEVICE_FAMILY_NAME).am4fg TARGET_LIBFILES += $(SDK_DRIVERS)/lib/drivers_$(DEVICE_FAMILY_NAME).am4fg TARGET_LIBFILES += $(SDK_DEVICE)/driverlib/bin/gcc/driverlib.lib -endif - -LDFLAGS += --entry resetISR -LDFLAGS += -static -LDFLAGS += --specs=nano.specs -# NB! The symbol _stack, which points to the stack start, is expected to be defined, -# but should already be defined in the linker script. -LDFLAGS += -Wl,--defsym=_stack_origin=__stack_end -LDFLAGS += -Wl,--defsym=_heap=__heap_start__ -LDFLAGS += -Wl,--defsym=_eheap=__heap_end__ -LDFLAGS += -Wl,--defsym=STACKSIZE=2048 - -LDSCRIPT := $(SDK_BOARD_PATH)/$(SDK_BOARD_NAME)_NoRTOS.lds - -### Always re-build ieee-addr.o in case the command line passes a new NODEID -FORCE: - -$(OBJECTDIR)/ieee-addr.o: ieee-addr.c FORCE | $(OBJECTDIR) - $(TRACE_CC) - $(Q)$(CC) $(CFLAGS) -c $< -o $@ - -### Always re-build ccfg.c so changes to ccfg-conf.h will apply without having -### to make clean first -$(OBJECTDIR)/ccfg.o: ccfg.c FORCE | $(OBJECTDIR) - $(TRACE_CC) - $(Q)$(CC) $(CFLAGS) -include "ccfg-conf.h" -c $< -o $@ include $(CONTIKI)/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx new file mode 100644 index 000000000..b0b5e1822 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -0,0 +1,113 @@ +################################################################################ +# CC13x2/CC26x2 CPU makefile + +# ccfg.c comes from the device-specific startp_files folder, +# and startup_cc13xx_cc26xx_gcc.c comes from NoRTOS startup folder +CPU_START_SOURCEFILES += ccfg.c startup_cc13xx_cc26xx_gcc.c + +################################################################################ +# Device Family +DEVICE_FAMILY_H := $(SIMPLELINK_SDK)/source/ti/devices/DeviceFamily.h + +# The define of the Device Family ID is on the format of either +# #define DeviceFamily_ID_ +# or +# #define DeviceFamily_ID_ +# We are interested in the right-hand side of the define, i.e. the third word on the line, +# as it either defines a number or an another Device Family ID. +DEVICE_DEFINE := $(shell cat $(DEVICE_FAMILY_H) \ + | grep "\#define DeviceFamily_ID_$(DEVICE_FAMILY)\\b" \ + | awk '{print $$3}') + +# If the define is a number, then the device family name is the resulting device name; +# Else, it points to a sub-name of the device family, e.g. DeviceFamily_ID_CC13X2_V1. +# This line checks if the extracted define is a number or not, based on this SO post: +# https://stackoverflow.com/a/19116862/5099169 +IS_NUMBER := $(shell if [ "$(DEVICE_DEFINE)" -eq "$(DEVICE_DEFINE)" ] 2>/dev/null; then echo 1 ; else echo 0 ; fi) + +ifeq ($(IS_NUMBER),1) + # The define points to a number, meaning the device family name is the same as the + # specified device name in lower case, e.g. + # cc13x2 + DEVICE_FAMILY_NAME := $(shell echo "$(DEVICE_FAMILY)" \ + | tr A-Z a-z) +else + # The define points to a sub-name of the device family. The resulting device family name + # is therefore the name after specified after ID in lower case, e.g. + # DeviceFamily_ID_CC13X2_V1 + # will result in + # cc13x2_v1 + DEVICE_FAMILY_NAME := $(shell echo "$(DEVICE_DEFINE)" \ + | sed -E "s/DeviceFamily_ID_(.+)/\1/" \ + | tr A-Z a-z) +endif + +# The DeviceFamily_constructPath() macro in DeviceFamily.h will always construct the +# correct path for device specific files. In this case, constructing the device specific +# root path. Note that the returned path is encased in angular brackets, <...>, +# and is therefore extracted with sed. +SDK_DEVICE_DIR := $(shell echo "DeviceFamily_constructPath(dummy)" \ + | arm-none-eabi-gcc -x c -E -DDeviceFamily_$(DEVICE_FAMILY) -include $(DEVICE_FAMILY_H) - \ + | tail -1 \ + | sed -E 's:<(.+)/dummy>:\1:') + +################################################################################ +# Simplelink SDK paths + +SDK_KERNEL := $(SIMPLELINK_SDK)/kernel/nortos +SDK_SOURCE := $(SIMPLELINK_SDK)/source +SDK_BOARDS := $(SDK_SOURCE)/ti/boards +SDK_DRIVERS := $(SDK_SOURCE)/ti/drivers +SDK_DEVICE := $(SDK_SOURCE)/$(SDK_DEVICE_DIR) + +EXTERNALDIRS += $(SDK_SOURCE) +EXTERNALDIRS += $(SDK_KERNEL) +EXTERNALDIRS += $(SDK_KERNEL)/startup +EXTERNALDIRS += $(SDK_DEVICE) +EXTERNALDIRS += $(SDK_DEVICE)/startup_files + +### CPU-dependent source files +CONTIKI_CPU_SOURCEFILES += rtimer-arch.c clock-arch.c +CONTIKI_CPU_SOURCEFILES += watchdog-arch.c putchar-arch.c +CONTIKI_CPU_SOURCEFILES += uart0-arch.c slip-arch.c +CONTIKI_CPU_SOURCEFILES += batmon-sensor.c +CONTIKI_CPU_SOURCEFILES += rf-common.c +CONTIKI_CPU_SOURCEFILES += rf-prop-mode.c rf-prop-settings.c +CONTIKI_CPU_SOURCEFILES += rf-ieee-mode.c rf-ieee-settings.c +CONTIKI_CPU_SOURCEFILES += ieee-addr.c + +### CPU-dependent directories +CONTIKI_CPU_DIRS += . dev $(SUBFAMILY) $(SUBFAMILY)/rf-settings + +### CPU-dependent debug source files +### CONTIKI_ARM_DIRS populated by Makefile.arm +DEBUG_IO_SOURCEFILES += dbg-printf.c dbg-snprintf.c dbg-sprintf.c strformat.c + +CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES) $(DEBUG_IO_SOURCEFILES) + +### Linker flag +LDFLAGS += --entry resetISR +LDFLAGS += -static +LDFLAGS += --specs=nano.specs +# NB! The symbol _stack, which points to the stack start, is expected to be defined, +# but should already be defined in the linker script. +LDFLAGS += -Wl,--defsym=_stack_origin=__stack_end +LDFLAGS += -Wl,--defsym=_heap=__heap_start__ +LDFLAGS += -Wl,--defsym=_eheap=__heap_end__ + +LDSCRIPT := $(CONTIKI_CPU)/$(SUBFAMILY)/$(SUBFAMILY).lds + +### Always re-build ieee-addr.o in case the command line passes a new NODEID +FORCE: + +$(OBJECTDIR)/ieee-addr.o: ieee-addr.c FORCE | $(OBJECTDIR) + $(TRACE_CC) + $(Q)$(CC) $(CFLAGS) -c $< -o $@ + +### Always re-build ccfg.c so changes to ccfg-conf.h will apply without having +### to make clean first +$(OBJECTDIR)/ccfg.o: ccfg.c FORCE | $(OBJECTDIR) + $(TRACE_CC) + $(Q)$(CC) $(CFLAGS) -include "ccfg-conf.h" -c $< -o $@ + +include $(CONTIKI_CPU)/Makefile.$(SUBFAMILY) diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.cc26x0 b/arch/cpu/cc13xx-cc26xx/Makefile.cc26x0 new file mode 100644 index 000000000..61cd5c304 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/Makefile.cc26x0 @@ -0,0 +1,73 @@ +################################################################################ +# CC13xx/CC26xx CPU makefile + +include $(CONTIKI_CPU)/Makefile.$(SUBFAMILY) + +EXTERNALDIRS += $(SDK_SOURCE) +EXTERNALDIRS += $(SDK_KERNEL) +EXTERNALDIRS += $(SDK_KERNEL)/startup +EXTERNALDIRS += $(SDK_BOARD_PATH) +EXTERNALDIRS += $(SDK_DEVICE) + +# ccfg.c comes from the board-specific folder, and startup_cc13xx_cc26xx_gcc.c +# comes from NoRTOS startup folder +#CPU_START_SOURCEFILES += ccfg.c startup_cc13xx_cc26xx_gcc.c + + +### If the user-specified a Node ID, pass a define +ifdef NODEID +DEFINES += IEEE_ADDR_NODE_ID=$(NODEID) +endif + +### CPU-dependent source files +CONTIKI_CPU_SOURCEFILES += rtimer-arch.c clock-arch.c +CONTIKI_CPU_SOURCEFILES += watchdog-arch.c putchar-arch.c +CONTIKI_CPU_SOURCEFILES += uart0-arch.c slip-arch.c +CONTIKI_CPU_SOURCEFILES += batmon-sensor.c +CONTIKI_CPU_SOURCEFILES += rf-common.c +CONTIKI_CPU_SOURCEFILES += rf-prop-mode.c rf-prop-settings.c +CONTIKI_CPU_SOURCEFILES += rf-ieee-mode.c rf-ieee-settings.c +CONTIKI_CPU_SOURCEFILES += ieee-addr.c + +### CPU-dependent directories +CONTIKI_CPU_DIRS += $(addprefix ../arm/, $(CPU_DIRS)) +CONTIKI_CPU_DIRS += . dev rf-settings cc13x2-cc26x2 + +### CPU-dependent debug source files +DEBUG_IO_SOURCEFILES += dbg-printf.c dbg-snprintf.c dbg-sprintf.c strformat.c + +CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES) $(DEBUG_IO_SOURCEFILES) + +### Simplelink SDK pre-compiled libraries +TARGET_LIBFILES += $(SDK_KERNEL)/lib/nortos_$(DEVICE_FAMILY_NAME).am4fg +TARGET_LIBFILES += $(SDK_DRIVERS)/rf/lib/rf_multiMode_$(DEVICE_FAMILY_NAME).am4fg +TARGET_LIBFILES += $(SDK_DRIVERS)/lib/drivers_$(DEVICE_FAMILY_NAME).am4fg +TARGET_LIBFILES += $(SDK_DEVICE)/driverlib/bin/gcc/driverlib.lib + +### Linker flag +LDFLAGS += --entry resetISR +LDFLAGS += -static +LDFLAGS += --specs=nano.specs +# NB! The symbol _stack, which points to the stack start, is expected to be defined, +# but should already be defined in the linker script. +LDFLAGS += -Wl,--defsym=_stack_origin=__stack_end +LDFLAGS += -Wl,--defsym=_heap=__heap_start__ +LDFLAGS += -Wl,--defsym=_eheap=__heap_end__ + +LDSCRIPT := $(CONTIKI_CPU)/$(SUBFAMILY)/$(SUBFAMILY).lds + +### Always re-build ieee-addr.o in case the command line passes a new NODEID +FORCE: + +$(OBJECTDIR)/ieee-addr.o: ieee-addr.c FORCE | $(OBJECTDIR) + $(TRACE_CC) + $(Q)$(CC) $(CFLAGS) -c $< -o $@ + +### Always re-build ccfg.c so changes to ccfg-conf.h will apply without having +### to make clean first +$(OBJECTDIR)/ccfg.o: ccfg.c FORCE | $(OBJECTDIR) + $(TRACE_CC) + $(Q)$(CC) $(CFLAGS) -include "ccfg-conf.h" -c $< -o $@ + + +include $(CONTIKI)/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds new file mode 100644 index 000000000..594779b1b --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2017-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ +/* + * ======== CC1310_LAUNCHXL_NoRTOS.lds ======== + * Default Linker script for the Texas Instruments CC1310 + */ + +STACKSIZE = 1024; +HEAPSIZE = 256; + +MEMORY +{ + FLASH (RX) : ORIGIN = 0x00000000, LENGTH = 0x0001ffa8 + /* + * Customer Configuration Area and Bootloader Backdoor configuration in + * flash, 40 bytes + */ + FLASH_CCFG (RX) : ORIGIN = 0x0001ffa8, LENGTH = 0x00000058 + SRAM (RWX) : ORIGIN = 0x20000000, LENGTH = 0x00005000 +} + +REGION_ALIAS("REGION_TEXT", FLASH); +REGION_ALIAS("REGION_BSS", SRAM); +REGION_ALIAS("REGION_DATA", SRAM); +REGION_ALIAS("REGION_STACK", SRAM); +REGION_ALIAS("REGION_HEAP", SRAM); +REGION_ALIAS("REGION_ARM_EXIDX", FLASH); +REGION_ALIAS("REGION_ARM_EXTAB", FLASH); + +SECTIONS { + + PROVIDE (_resetVecs_base_address = + DEFINED(_resetVecs_base_address) ? _resetVecs_base_address : 0x0); + + .resetVecs (_resetVecs_base_address) : AT (_resetVecs_base_address) { + KEEP (*(.resetVecs)) + } > REGION_TEXT + + .ramVecs (NOLOAD) : ALIGN(1024){ + KEEP (*(.ramVecs)) + } > REGION_DATA + + /* + * UDMACC26XX_CONFIG_BASE below must match UDMACC26XX_CONFIG_BASE defined + * by ti/drivers/dma/UDMACC26XX.h + * The user is allowed to change UDMACC26XX_CONFIG_BASE to move it away from + * the default address 0x2000_0400, but remember it must be 1024 bytes aligned. + */ + UDMACC26XX_CONFIG_BASE = 0x20000400; + + /* + * Define absolute addresses for the DMA channels. + * DMA channels must always be allocated at a fixed offset from the DMA base address. + * --------- DO NOT MODIFY ----------- + */ + DMA_SPI0_RX_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x30); + DMA_SPI0_TX_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x40); + DMA_ADC_PRI_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x70); + DMA_GPT0A_PRI_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x90); + DMA_SPI1_RX_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x100); + DMA_SPI1_TX_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x110); + DMA_ADC_ALT_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x270); + DMA_GPT0A_ALT_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x290); + + /* + * Allocate SPI0, SPI1, ADC, and GPTimer0 DMA descriptors at absolute addresses. + * --------- DO NOT MODIFY ----------- + */ + UDMACC26XX_dmaSpi0RxControlTableEntry_is_placed = 0; + .dmaSpi0RxControlTableEntry DMA_SPI0_RX_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_SPI0_RX_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaSpi0RxControlTableEntry)} > REGION_DATA + + UDMACC26XX_dmaSpi0TxControlTableEntry_is_placed = 0; + .dmaSpi0TxControlTableEntry DMA_SPI0_TX_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_SPI0_TX_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaSpi0TxControlTableEntry)} > REGION_DATA + + UDMACC26XX_dmaADCPriControlTableEntry_is_placed = 0; + .dmaADCPriControlTableEntry DMA_ADC_PRI_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_ADC_PRI_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaADCPriControlTableEntry)} > REGION_DATA + + UDMACC26XX_dmaGPT0APriControlTableEntry_is_placed = 0; + .dmaGPT0APriControlTableEntry DMA_GPT0A_PRI_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_GPT0A_PRI_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaGPT0APriControlTableEntry)} > REGION_DATA + + UDMACC26XX_dmaSpi1RxControlTableEntry_is_placed = 0; + .dmaSpi1RxControlTableEntry DMA_SPI1_RX_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_SPI1_RX_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaSpi1RxControlTableEntry)} > REGION_DATA + + UDMACC26XX_dmaSpi1TxControlTableEntry_is_placed = 0; + .dmaSpi1TxControlTableEntry DMA_SPI1_TX_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_SPI1_TX_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaSpi1TxControlTableEntry)} > REGION_DATA + + UDMACC26XX_dmaADCAltControlTableEntry_is_placed = 0; + .dmaADCAltControlTableEntry DMA_ADC_ALT_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_ADC_ALT_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaADCAltControlTableEntry)} > REGION_DATA + + UDMACC26XX_dmaGPT0AAltControlTableEntry_is_placed = 0; + .dmaGPT0AAltControlTableEntry DMA_GPT0A_ALT_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_GPT0A_ALT_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaGPT0AAltControlTableEntry)} > REGION_DATA + + .text : { + CREATE_OBJECT_SYMBOLS + *(.text) + *(.text.*) + . = ALIGN(0x4); + KEEP (*(.ctors)) + . = ALIGN(0x4); + KEEP (*(.dtors)) + . = ALIGN(0x4); + __init_array_start = .; + KEEP (*(.init_array*)) + __init_array_end = .; + *(.init) + *(.fini*) + } > REGION_TEXT AT> REGION_TEXT + + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + + .rodata : { + *(.rodata) + *(.rodata.*) + } > REGION_TEXT AT> REGION_TEXT + + .data : ALIGN(4) { + __data_load__ = LOADADDR (.data); + __data_start__ = .; + *(.data) + *(.data.*) + . = ALIGN (4); + __data_end__ = .; + } > REGION_DATA AT> REGION_TEXT + + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + __exidx_end = .; + } > REGION_ARM_EXIDX AT> REGION_ARM_EXIDX + + .ARM.extab : { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > REGION_ARM_EXTAB AT> REGION_ARM_EXTAB + + .nvs (NOLOAD) : ALIGN(0x1000) { + *(.nvs) + } > REGION_TEXT + + .ccfg : { + KEEP (*(.ccfg)) + } > FLASH_CCFG AT> FLASH_CCFG + + .bss : { + __bss_start__ = .; + *(.shbss) + *(.bss) + *(.bss.*) + *(COMMON) + . = ALIGN (4); + __bss_end__ = .; + } > REGION_BSS AT> REGION_BSS + + .heap : { + __heap_start__ = .; + end = __heap_start__; + _end = end; + __end = end; + . = . + HEAPSIZE; + KEEP(*(.heap)) + __heap_end__ = .; + __HeapLimit = __heap_end__; + } > REGION_HEAP AT> REGION_HEAP + + .stack (NOLOAD) : ALIGN(0x8) { + _stack = .; + __stack = .; + KEEP(*(.stack)) + . += STACKSIZE; + _stack_end = .; + __stack_end = .; + } > REGION_STACK AT> REGION_STACK +} diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/driverlib/rf_ieee_cmd.h b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/driverlib/rf_ieee_cmd.h new file mode 100644 index 000000000..c054da400 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/driverlib/rf_ieee_cmd.h @@ -0,0 +1,629 @@ +/****************************************************************************** +* Filename: rf_ieee_cmd.h +* Revised: 2018-01-15 06:15:14 +0100 (Mon, 15 Jan 2018) +* Revision: 18170 +* +* Description: CC13x2/CC26x2 API for IEEE 802.15.4 commands +* +* Copyright (c) 2015 - 2017, Texas Instruments Incorporated +* 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 ORGANIZATION 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 __IEEE_CMD_H +#define __IEEE_CMD_H + +#ifndef __RFC_STRUCT +#define __RFC_STRUCT +#endif + +#ifndef __RFC_STRUCT_ATTR +#if defined(__GNUC__) +#define __RFC_STRUCT_ATTR __attribute__ ((aligned (4))) +#elif defined(__TI_ARM__) +#define __RFC_STRUCT_ATTR __attribute__ ((__packed__,aligned (4))) +#else +#define __RFC_STRUCT_ATTR +#endif +#endif + +//! \addtogroup rfc +//! @{ + +//! \addtogroup ieee_cmd +//! @{ + +#include +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) + +typedef struct __RFC_STRUCT rfc_CMD_IEEE_RX_s rfc_CMD_IEEE_RX_t; +typedef struct __RFC_STRUCT rfc_CMD_IEEE_ED_SCAN_s rfc_CMD_IEEE_ED_SCAN_t; +typedef struct __RFC_STRUCT rfc_CMD_IEEE_TX_s rfc_CMD_IEEE_TX_t; +typedef struct __RFC_STRUCT rfc_CMD_IEEE_CSMA_s rfc_CMD_IEEE_CSMA_t; +typedef struct __RFC_STRUCT rfc_CMD_IEEE_RX_ACK_s rfc_CMD_IEEE_RX_ACK_t; +typedef struct __RFC_STRUCT rfc_CMD_IEEE_ABORT_BG_s rfc_CMD_IEEE_ABORT_BG_t; +typedef struct __RFC_STRUCT rfc_CMD_IEEE_MOD_CCA_s rfc_CMD_IEEE_MOD_CCA_t; +typedef struct __RFC_STRUCT rfc_CMD_IEEE_MOD_FILT_s rfc_CMD_IEEE_MOD_FILT_t; +typedef struct __RFC_STRUCT rfc_CMD_IEEE_MOD_SRC_MATCH_s rfc_CMD_IEEE_MOD_SRC_MATCH_t; +typedef struct __RFC_STRUCT rfc_CMD_IEEE_ABORT_FG_s rfc_CMD_IEEE_ABORT_FG_t; +typedef struct __RFC_STRUCT rfc_CMD_IEEE_STOP_FG_s rfc_CMD_IEEE_STOP_FG_t; +typedef struct __RFC_STRUCT rfc_CMD_IEEE_CCA_REQ_s rfc_CMD_IEEE_CCA_REQ_t; +typedef struct __RFC_STRUCT rfc_ieeeRxOutput_s rfc_ieeeRxOutput_t; +typedef struct __RFC_STRUCT rfc_shortAddrEntry_s rfc_shortAddrEntry_t; +typedef struct __RFC_STRUCT rfc_ieeeRxCorrCrc_s rfc_ieeeRxCorrCrc_t; + +//! \addtogroup CMD_IEEE_RX +//! @{ +#define CMD_IEEE_RX 0x2801 +//! IEEE 802.15.4 Receive Command +struct __RFC_STRUCT rfc_CMD_IEEE_RX_s { + uint16_t commandNo; //!< The command ID number 0x2801 + uint16_t status; //!< \brief An integer telling the status of the command. This value is + //!< updated by the radio CPU during operation and may be read by the + //!< system CPU at any time. + rfc_radioOp_t *pNextOp; //!< Pointer to the next operation to run after this operation is done + ratmr_t startTime; //!< Absolute or relative start time (depending on the value of startTrigger) + struct { + uint8_t triggerType:4; //!< The type of trigger + uint8_t bEnaCmd:1; //!< \brief 0: No alternative trigger command
+ //!< 1: CMD_TRIGGER can be used as an alternative trigger + uint8_t triggerNo:2; //!< The trigger number of the CMD_TRIGGER command that triggers this action + uint8_t pastTrig:1; //!< \brief 0: A trigger in the past is never triggered, or for start of commands, give an error
+ //!< 1: A trigger in the past is triggered as soon as possible + } startTrigger; //!< Identification of the trigger that starts the operation + struct { + uint8_t rule:4; //!< Condition for running next command: Rule for how to proceed + uint8_t nSkip:4; //!< Number of skips + 1 if the rule involves skipping. 0: same, 1: next, 2: skip next, ... + } condition; + uint8_t channel; //!< \brief Channel to tune to in the start of the operation
+ //!< 0: Use existing channel
+ //!< 11--26: Use as IEEE 802.15.4 channel, i.e. frequency is (2405 + 5 × (channel - 11)) MHz
+ //!< 60--207: Frequency is (2300 + channel) MHz
+ //!< Others: Reserved + struct { + uint8_t bAutoFlushCrc:1; //!< If 1, automatically remove packets with CRC error from Rx queue + uint8_t bAutoFlushIgn:1; //!< If 1, automatically remove packets that can be ignored according to frame filtering from Rx queue + uint8_t bIncludePhyHdr:1; //!< If 1, include the received PHY header field in the stored packet; otherwise discard it + uint8_t bIncludeCrc:1; //!< If 1, include the received CRC field in the stored packet; otherwise discard it + uint8_t bAppendRssi:1; //!< If 1, append an RSSI byte to the packet in the Rx queue + uint8_t bAppendCorrCrc:1; //!< If 1, append a correlation value and CRC result byte to the packet in the Rx queue + uint8_t bAppendSrcInd:1; //!< If 1, append an index from the source matching algorithm + uint8_t bAppendTimestamp:1; //!< If 1, append a timestamp to the packet in the Rx queue + } rxConfig; + dataQueue_t* pRxQ; //!< Pointer to receive queue + rfc_ieeeRxOutput_t *pOutput; //!< Pointer to output structure (NULL: Do not store results) + struct { + uint16_t frameFiltEn:1; //!< \brief 0: Disable frame filtering
+ //!< 1: Enable frame filtering + uint16_t frameFiltStop:1; //!< \brief 0: Receive all packets to the end
+ //!< 1: Stop receiving frame once frame filtering has caused the frame to be rejected. + uint16_t autoAckEn:1; //!< \brief 0: Disable auto ACK
+ //!< 1: Enable auto ACK. + uint16_t slottedAckEn:1; //!< \brief 0: Non-slotted ACK
+ //!< 1: Slotted ACK. + uint16_t autoPendEn:1; //!< \brief 0: Auto-pend disabled
+ //!< 1: Auto-pend enabled + uint16_t defaultPend:1; //!< The value of the pending data bit in auto ACK packets that are not subject to auto-pend + uint16_t bPendDataReqOnly:1; //!< \brief 0: Use auto-pend for any packet
+ //!< 1: Use auto-pend for data request packets only + uint16_t bPanCoord:1; //!< \brief 0: Device is not PAN coordinator
+ //!< 1: Device is PAN coordinator + uint16_t maxFrameVersion:2; //!< Reject frames where the frame version field in the FCF is greater than this value + uint16_t fcfReservedMask:3; //!< Value to be AND-ed with the reserved part of the FCF; frame rejected if result is non-zero + uint16_t modifyFtFilter:2; //!< \brief Treatment of MSB of frame type field before frame-type filtering:
+ //!< 0: No modification
+ //!< 1: Invert MSB
+ //!< 2: Set MSB to 0
+ //!< 3: Set MSB to 1 + uint16_t bStrictLenFilter:1; //!< \brief 0: Accept acknowledgement frames of any length >= 5
+ //!< 1: Accept only acknowledgement frames of length 5 + } frameFiltOpt; //!< Frame filtering options + struct { + uint8_t bAcceptFt0Beacon:1; //!< \brief Treatment of frames with frame type 000 (beacon):
+ //!< 0: Reject
+ //!< 1: Accept + uint8_t bAcceptFt1Data:1; //!< \brief Treatment of frames with frame type 001 (data):
+ //!< 0: Reject
+ //!< 1: Accept + uint8_t bAcceptFt2Ack:1; //!< \brief Treatment of frames with frame type 010 (ACK):
+ //!< 0: Reject, unless running ACK receive command
+ //!< 1: Always accept + uint8_t bAcceptFt3MacCmd:1; //!< \brief Treatment of frames with frame type 011 (MAC command):
+ //!< 0: Reject
+ //!< 1: Accept + uint8_t bAcceptFt4Reserved:1; //!< \brief Treatment of frames with frame type 100 (reserved):
+ //!< 0: Reject
+ //!< 1: Accept + uint8_t bAcceptFt5Reserved:1; //!< \brief Treatment of frames with frame type 101 (reserved):
+ //!< 0: Reject
+ //!< 1: Accept + uint8_t bAcceptFt6Reserved:1; //!< \brief Treatment of frames with frame type 110 (reserved):
+ //!< 0: Reject
+ //!< 1: Accept + uint8_t bAcceptFt7Reserved:1; //!< \brief Treatment of frames with frame type 111 (reserved):
+ //!< 0: Reject
+ //!< 1: Accept + } frameTypes; //!< Frame types to receive in frame filtering + struct { + uint8_t ccaEnEnergy:1; //!< Enable energy scan as CCA source + uint8_t ccaEnCorr:1; //!< Enable correlator based carrier sense as CCA source + uint8_t ccaEnSync:1; //!< Enable sync found based carrier sense as CCA source + uint8_t ccaCorrOp:1; //!< \brief Operator to use between energy based and correlator based CCA
+ //!< 0: Report busy channel if either ccaEnergy or ccaCorr are busy
+ //!< 1: Report busy channel if both ccaEnergy and ccaCorr are busy + uint8_t ccaSyncOp:1; //!< \brief Operator to use between sync found based CCA and the others
+ //!< 0: Always report busy channel if ccaSync is busy
+ //!< 1: Always report idle channel if ccaSync is idle + uint8_t ccaCorrThr:2; //!< Threshold for number of correlation peaks in correlator based carrier sense + } ccaOpt; //!< CCA options + int8_t ccaRssiThr; //!< RSSI threshold for CCA + uint8_t __dummy0; + uint8_t numExtEntries; //!< Number of extended address entries + uint8_t numShortEntries; //!< Number of short address entries + uint32_t* pExtEntryList; //!< Pointer to list of extended address entries + uint32_t* pShortEntryList; //!< Pointer to list of short address entries + uint64_t localExtAddr; //!< The extended address of the local device + uint16_t localShortAddr; //!< The short address of the local device + uint16_t localPanID; //!< The PAN ID of the local device + uint16_t __dummy1; + uint8_t __dummy2; + struct { + uint8_t triggerType:4; //!< The type of trigger + uint8_t bEnaCmd:1; //!< \brief 0: No alternative trigger command
+ //!< 1: CMD_TRIGGER can be used as an alternative trigger + uint8_t triggerNo:2; //!< The trigger number of the CMD_TRIGGER command that triggers this action + uint8_t pastTrig:1; //!< \brief 0: A trigger in the past is never triggered, or for start of commands, give an error
+ //!< 1: A trigger in the past is triggered as soon as possible + } endTrigger; //!< Trigger that causes the device to end the Rx operation + ratmr_t endTime; //!< \brief Time used together with endTrigger that causes the device to end the Rx + //!< operation +} __RFC_STRUCT_ATTR; + +//! @} + +//! \addtogroup CMD_IEEE_ED_SCAN +//! @{ +#define CMD_IEEE_ED_SCAN 0x2802 +//! IEEE 802.15.4 Energy Detect Scan Command +struct __RFC_STRUCT rfc_CMD_IEEE_ED_SCAN_s { + uint16_t commandNo; //!< The command ID number 0x2802 + uint16_t status; //!< \brief An integer telling the status of the command. This value is + //!< updated by the radio CPU during operation and may be read by the + //!< system CPU at any time. + rfc_radioOp_t *pNextOp; //!< Pointer to the next operation to run after this operation is done + ratmr_t startTime; //!< Absolute or relative start time (depending on the value of startTrigger) + struct { + uint8_t triggerType:4; //!< The type of trigger + uint8_t bEnaCmd:1; //!< \brief 0: No alternative trigger command
+ //!< 1: CMD_TRIGGER can be used as an alternative trigger + uint8_t triggerNo:2; //!< The trigger number of the CMD_TRIGGER command that triggers this action + uint8_t pastTrig:1; //!< \brief 0: A trigger in the past is never triggered, or for start of commands, give an error
+ //!< 1: A trigger in the past is triggered as soon as possible + } startTrigger; //!< Identification of the trigger that starts the operation + struct { + uint8_t rule:4; //!< Condition for running next command: Rule for how to proceed + uint8_t nSkip:4; //!< Number of skips + 1 if the rule involves skipping. 0: same, 1: next, 2: skip next, ... + } condition; + uint8_t channel; //!< \brief Channel to tune to in the start of the operation
+ //!< 0: Use existing channel
+ //!< 11--26: Use as IEEE 802.15.4 channel, i.e. frequency is (2405 + 5 × (channel - 11)) MHz
+ //!< 60--207: Frequency is (2300 + channel) MHz
+ //!< Others: Reserved + struct { + uint8_t ccaEnEnergy:1; //!< Enable energy scan as CCA source + uint8_t ccaEnCorr:1; //!< Enable correlator based carrier sense as CCA source + uint8_t ccaEnSync:1; //!< Enable sync found based carrier sense as CCA source + uint8_t ccaCorrOp:1; //!< \brief Operator to use between energy based and correlator based CCA
+ //!< 0: Report busy channel if either ccaEnergy or ccaCorr are busy
+ //!< 1: Report busy channel if both ccaEnergy and ccaCorr are busy + uint8_t ccaSyncOp:1; //!< \brief Operator to use between sync found based CCA and the others
+ //!< 0: Always report busy channel if ccaSync is busy
+ //!< 1: Always report idle channel if ccaSync is idle + uint8_t ccaCorrThr:2; //!< Threshold for number of correlation peaks in correlator based carrier sense + } ccaOpt; //!< CCA options + int8_t ccaRssiThr; //!< RSSI threshold for CCA + uint8_t __dummy0; + int8_t maxRssi; //!< The maximum RSSI recorded during the ED scan + struct { + uint8_t triggerType:4; //!< The type of trigger + uint8_t bEnaCmd:1; //!< \brief 0: No alternative trigger command
+ //!< 1: CMD_TRIGGER can be used as an alternative trigger + uint8_t triggerNo:2; //!< The trigger number of the CMD_TRIGGER command that triggers this action + uint8_t pastTrig:1; //!< \brief 0: A trigger in the past is never triggered, or for start of commands, give an error
+ //!< 1: A trigger in the past is triggered as soon as possible + } endTrigger; //!< Trigger that causes the device to end the Rx operation + ratmr_t endTime; //!< \brief Time used together with endTrigger that causes the device to end the Rx + //!< operation +} __RFC_STRUCT_ATTR; + +//! @} + +//! \addtogroup CMD_IEEE_TX +//! @{ +#define CMD_IEEE_TX 0x2C01 +//! IEEE 802.15.4 Transmit Command +struct __RFC_STRUCT rfc_CMD_IEEE_TX_s { + uint16_t commandNo; //!< The command ID number 0x2C01 + uint16_t status; //!< \brief An integer telling the status of the command. This value is + //!< updated by the radio CPU during operation and may be read by the + //!< system CPU at any time. + rfc_radioOp_t *pNextOp; //!< Pointer to the next operation to run after this operation is done + ratmr_t startTime; //!< Absolute or relative start time (depending on the value of startTrigger) + struct { + uint8_t triggerType:4; //!< The type of trigger + uint8_t bEnaCmd:1; //!< \brief 0: No alternative trigger command
+ //!< 1: CMD_TRIGGER can be used as an alternative trigger + uint8_t triggerNo:2; //!< The trigger number of the CMD_TRIGGER command that triggers this action + uint8_t pastTrig:1; //!< \brief 0: A trigger in the past is never triggered, or for start of commands, give an error
+ //!< 1: A trigger in the past is triggered as soon as possible + } startTrigger; //!< Identification of the trigger that starts the operation + struct { + uint8_t rule:4; //!< Condition for running next command: Rule for how to proceed + uint8_t nSkip:4; //!< Number of skips + 1 if the rule involves skipping. 0: same, 1: next, 2: skip next, ... + } condition; + struct { + uint8_t bIncludePhyHdr:1; //!< \brief 0: Find PHY header automatically
+ //!< 1: Insert PHY header from the buffer + uint8_t bIncludeCrc:1; //!< \brief 0: Append automatically calculated CRC
+ //!< 1: Insert FCS (CRC) from the buffer + uint8_t :1; + uint8_t payloadLenMsb:5; //!< \brief Most significant bits of payload length. Should only be non-zero to create long + //!< non-standard packets for test purposes + } txOpt; + uint8_t payloadLen; //!< Number of bytes in the payload + uint8_t* pPayload; //!< Pointer to payload buffer of size payloadLen + ratmr_t timeStamp; //!< Time stamp of transmitted frame +} __RFC_STRUCT_ATTR; + +//! @} + +//! \addtogroup CMD_IEEE_CSMA +//! @{ +#define CMD_IEEE_CSMA 0x2C02 +//! IEEE 802.15.4 CSMA-CA Command +struct __RFC_STRUCT rfc_CMD_IEEE_CSMA_s { + uint16_t commandNo; //!< The command ID number 0x2C02 + uint16_t status; //!< \brief An integer telling the status of the command. This value is + //!< updated by the radio CPU during operation and may be read by the + //!< system CPU at any time. + rfc_radioOp_t *pNextOp; //!< Pointer to the next operation to run after this operation is done + ratmr_t startTime; //!< Absolute or relative start time (depending on the value of startTrigger) + struct { + uint8_t triggerType:4; //!< The type of trigger + uint8_t bEnaCmd:1; //!< \brief 0: No alternative trigger command
+ //!< 1: CMD_TRIGGER can be used as an alternative trigger + uint8_t triggerNo:2; //!< The trigger number of the CMD_TRIGGER command that triggers this action + uint8_t pastTrig:1; //!< \brief 0: A trigger in the past is never triggered, or for start of commands, give an error
+ //!< 1: A trigger in the past is triggered as soon as possible + } startTrigger; //!< Identification of the trigger that starts the operation + struct { + uint8_t rule:4; //!< Condition for running next command: Rule for how to proceed + uint8_t nSkip:4; //!< Number of skips + 1 if the rule involves skipping. 0: same, 1: next, 2: skip next, ... + } condition; + uint16_t randomState; //!< The state of the pseudo-random generator + uint8_t macMaxBE; //!< The IEEE 802.15.4 MAC parameter macMaxBE + uint8_t macMaxCSMABackoffs; //!< The IEEE 802.15.4 MAC parameter macMaxCSMABackoffs + struct { + uint8_t initCW:5; //!< The initialization value for the CW parameter + uint8_t bSlotted:1; //!< \brief 0: non-slotted CSMA
+ //!< 1: slotted CSMA + uint8_t rxOffMode:2; //!< \brief 0: RX stays on during CSMA backoffs
+ //!< 1: The CSMA-CA algorithm will suspend the receiver if no frame is being received
+ //!< 2: The CSMA-CA algorithm will suspend the receiver if no frame is being received, + //!< or after finishing it (including auto ACK) otherwise
+ //!< 3: The CSMA-CA algorithm will suspend the receiver immediately during back-offs + } csmaConfig; + uint8_t NB; //!< The NB parameter from the IEEE 802.15.4 CSMA-CA algorithm + uint8_t BE; //!< The BE parameter from the IEEE 802.15.4 CSMA-CA algorithm + uint8_t remainingPeriods; //!< The number of remaining periods from a paused backoff countdown + int8_t lastRssi; //!< RSSI measured at the last CCA operation + struct { + uint8_t triggerType:4; //!< The type of trigger + uint8_t bEnaCmd:1; //!< \brief 0: No alternative trigger command
+ //!< 1: CMD_TRIGGER can be used as an alternative trigger + uint8_t triggerNo:2; //!< The trigger number of the CMD_TRIGGER command that triggers this action + uint8_t pastTrig:1; //!< \brief 0: A trigger in the past is never triggered, or for start of commands, give an error
+ //!< 1: A trigger in the past is triggered as soon as possible + } endTrigger; //!< Trigger that causes the device to end the CSMA-CA operation + ratmr_t lastTimeStamp; //!< Time of the last CCA operation + ratmr_t endTime; //!< \brief Time used together with endTrigger that causes the device to end the + //!< CSMA-CA operation +} __RFC_STRUCT_ATTR; + +//! @} + +//! \addtogroup CMD_IEEE_RX_ACK +//! @{ +#define CMD_IEEE_RX_ACK 0x2C03 +//! IEEE 802.15.4 Receive Acknowledgement Command +struct __RFC_STRUCT rfc_CMD_IEEE_RX_ACK_s { + uint16_t commandNo; //!< The command ID number 0x2C03 + uint16_t status; //!< \brief An integer telling the status of the command. This value is + //!< updated by the radio CPU during operation and may be read by the + //!< system CPU at any time. + rfc_radioOp_t *pNextOp; //!< Pointer to the next operation to run after this operation is done + ratmr_t startTime; //!< Absolute or relative start time (depending on the value of startTrigger) + struct { + uint8_t triggerType:4; //!< The type of trigger + uint8_t bEnaCmd:1; //!< \brief 0: No alternative trigger command
+ //!< 1: CMD_TRIGGER can be used as an alternative trigger + uint8_t triggerNo:2; //!< The trigger number of the CMD_TRIGGER command that triggers this action + uint8_t pastTrig:1; //!< \brief 0: A trigger in the past is never triggered, or for start of commands, give an error
+ //!< 1: A trigger in the past is triggered as soon as possible + } startTrigger; //!< Identification of the trigger that starts the operation + struct { + uint8_t rule:4; //!< Condition for running next command: Rule for how to proceed + uint8_t nSkip:4; //!< Number of skips + 1 if the rule involves skipping. 0: same, 1: next, 2: skip next, ... + } condition; + uint8_t seqNo; //!< Sequence number to expect + struct { + uint8_t triggerType:4; //!< The type of trigger + uint8_t bEnaCmd:1; //!< \brief 0: No alternative trigger command
+ //!< 1: CMD_TRIGGER can be used as an alternative trigger + uint8_t triggerNo:2; //!< The trigger number of the CMD_TRIGGER command that triggers this action + uint8_t pastTrig:1; //!< \brief 0: A trigger in the past is never triggered, or for start of commands, give an error
+ //!< 1: A trigger in the past is triggered as soon as possible + } endTrigger; //!< Trigger that causes the device to give up acknowledgement reception + ratmr_t endTime; //!< \brief Time used together with endTrigger that causes the device to give up + //!< acknowledgement reception +} __RFC_STRUCT_ATTR; + +//! @} + +//! \addtogroup CMD_IEEE_ABORT_BG +//! @{ +#define CMD_IEEE_ABORT_BG 0x2C04 +//! IEEE 802.15.4 Abort Background Level Command +struct __RFC_STRUCT rfc_CMD_IEEE_ABORT_BG_s { + uint16_t commandNo; //!< The command ID number 0x2C04 + uint16_t status; //!< \brief An integer telling the status of the command. This value is + //!< updated by the radio CPU during operation and may be read by the + //!< system CPU at any time. + rfc_radioOp_t *pNextOp; //!< Pointer to the next operation to run after this operation is done + ratmr_t startTime; //!< Absolute or relative start time (depending on the value of startTrigger) + struct { + uint8_t triggerType:4; //!< The type of trigger + uint8_t bEnaCmd:1; //!< \brief 0: No alternative trigger command
+ //!< 1: CMD_TRIGGER can be used as an alternative trigger + uint8_t triggerNo:2; //!< The trigger number of the CMD_TRIGGER command that triggers this action + uint8_t pastTrig:1; //!< \brief 0: A trigger in the past is never triggered, or for start of commands, give an error
+ //!< 1: A trigger in the past is triggered as soon as possible + } startTrigger; //!< Identification of the trigger that starts the operation + struct { + uint8_t rule:4; //!< Condition for running next command: Rule for how to proceed + uint8_t nSkip:4; //!< Number of skips + 1 if the rule involves skipping. 0: same, 1: next, 2: skip next, ... + } condition; +} __RFC_STRUCT_ATTR; + +//! @} + +//! \addtogroup CMD_IEEE_MOD_CCA +//! @{ +#define CMD_IEEE_MOD_CCA 0x2001 +//! IEEE 802.15.4 Modify CCA Parameter Command +struct __RFC_STRUCT rfc_CMD_IEEE_MOD_CCA_s { + uint16_t commandNo; //!< The command ID number 0x2001 + struct { + uint8_t ccaEnEnergy:1; //!< Enable energy scan as CCA source + uint8_t ccaEnCorr:1; //!< Enable correlator based carrier sense as CCA source + uint8_t ccaEnSync:1; //!< Enable sync found based carrier sense as CCA source + uint8_t ccaCorrOp:1; //!< \brief Operator to use between energy based and correlator based CCA
+ //!< 0: Report busy channel if either ccaEnergy or ccaCorr are busy
+ //!< 1: Report busy channel if both ccaEnergy and ccaCorr are busy + uint8_t ccaSyncOp:1; //!< \brief Operator to use between sync found based CCA and the others
+ //!< 0: Always report busy channel if ccaSync is busy
+ //!< 1: Always report idle channel if ccaSync is idle + uint8_t ccaCorrThr:2; //!< Threshold for number of correlation peaks in correlator based carrier sense + } newCcaOpt; //!< New value of ccaOpt for the running background level operation + int8_t newCcaRssiThr; //!< New value of ccaRssiThr for the running background level operation +} __RFC_STRUCT_ATTR; + +//! @} + +//! \addtogroup CMD_IEEE_MOD_FILT +//! @{ +#define CMD_IEEE_MOD_FILT 0x2002 +//! IEEE 802.15.4 Modify Frame Filtering Parameter Command +struct __RFC_STRUCT rfc_CMD_IEEE_MOD_FILT_s { + uint16_t commandNo; //!< The command ID number 0x2002 + struct { + uint16_t frameFiltEn:1; //!< \brief 0: Disable frame filtering
+ //!< 1: Enable frame filtering + uint16_t frameFiltStop:1; //!< \brief 0: Receive all packets to the end
+ //!< 1: Stop receiving frame once frame filtering has caused the frame to be rejected. + uint16_t autoAckEn:1; //!< \brief 0: Disable auto ACK
+ //!< 1: Enable auto ACK. + uint16_t slottedAckEn:1; //!< \brief 0: Non-slotted ACK
+ //!< 1: Slotted ACK. + uint16_t autoPendEn:1; //!< \brief 0: Auto-pend disabled
+ //!< 1: Auto-pend enabled + uint16_t defaultPend:1; //!< The value of the pending data bit in auto ACK packets that are not subject to auto-pend + uint16_t bPendDataReqOnly:1; //!< \brief 0: Use auto-pend for any packet
+ //!< 1: Use auto-pend for data request packets only + uint16_t bPanCoord:1; //!< \brief 0: Device is not PAN coordinator
+ //!< 1: Device is PAN coordinator + uint16_t maxFrameVersion:2; //!< Reject frames where the frame version field in the FCF is greater than this value + uint16_t fcfReservedMask:3; //!< Value to be AND-ed with the reserved part of the FCF; frame rejected if result is non-zero + uint16_t modifyFtFilter:2; //!< \brief Treatment of MSB of frame type field before frame-type filtering:
+ //!< 0: No modification
+ //!< 1: Invert MSB
+ //!< 2: Set MSB to 0
+ //!< 3: Set MSB to 1 + uint16_t bStrictLenFilter:1; //!< \brief 0: Accept acknowledgement frames of any length >= 5
+ //!< 1: Accept only acknowledgement frames of length 5 + } newFrameFiltOpt; //!< New value of frameFiltOpt for the running background level operation + struct { + uint8_t bAcceptFt0Beacon:1; //!< \brief Treatment of frames with frame type 000 (beacon):
+ //!< 0: Reject
+ //!< 1: Accept + uint8_t bAcceptFt1Data:1; //!< \brief Treatment of frames with frame type 001 (data):
+ //!< 0: Reject
+ //!< 1: Accept + uint8_t bAcceptFt2Ack:1; //!< \brief Treatment of frames with frame type 010 (ACK):
+ //!< 0: Reject, unless running ACK receive command
+ //!< 1: Always accept + uint8_t bAcceptFt3MacCmd:1; //!< \brief Treatment of frames with frame type 011 (MAC command):
+ //!< 0: Reject
+ //!< 1: Accept + uint8_t bAcceptFt4Reserved:1; //!< \brief Treatment of frames with frame type 100 (reserved):
+ //!< 0: Reject
+ //!< 1: Accept + uint8_t bAcceptFt5Reserved:1; //!< \brief Treatment of frames with frame type 101 (reserved):
+ //!< 0: Reject
+ //!< 1: Accept + uint8_t bAcceptFt6Reserved:1; //!< \brief Treatment of frames with frame type 110 (reserved):
+ //!< 0: Reject
+ //!< 1: Accept + uint8_t bAcceptFt7Reserved:1; //!< \brief Treatment of frames with frame type 111 (reserved):
+ //!< 0: Reject
+ //!< 1: Accept + } newFrameTypes; //!< New value of frameTypes for the running background level operation +} __RFC_STRUCT_ATTR; + +//! @} + +//! \addtogroup CMD_IEEE_MOD_SRC_MATCH +//! @{ +#define CMD_IEEE_MOD_SRC_MATCH 0x2003 +//! IEEE 802.15.4 Enable/Disable Source Matching Entry Command +struct __RFC_STRUCT rfc_CMD_IEEE_MOD_SRC_MATCH_s { + uint16_t commandNo; //!< The command ID number 0x2003 + struct { + uint8_t bEnable:1; //!< \brief 0: Disable entry
+ //!< 1: Enable entry + uint8_t srcPend:1; //!< New value of the pending bit for the entry + uint8_t entryType:1; //!< \brief 0: Short address
+ //!< 1: Extended address + } options; + uint8_t entryNo; //!< Index of entry to enable or disable +} __RFC_STRUCT_ATTR; + +//! @} + +//! \addtogroup CMD_IEEE_ABORT_FG +//! @{ +#define CMD_IEEE_ABORT_FG 0x2401 +//! IEEE 802.15.4 Abort Foreground Level Command +struct __RFC_STRUCT rfc_CMD_IEEE_ABORT_FG_s { + uint16_t commandNo; //!< The command ID number 0x2401 +} __RFC_STRUCT_ATTR; + +//! @} + +//! \addtogroup CMD_IEEE_STOP_FG +//! @{ +#define CMD_IEEE_STOP_FG 0x2402 +//! IEEE 802.15.4 Gracefully Stop Foreground Level Command +struct __RFC_STRUCT rfc_CMD_IEEE_STOP_FG_s { + uint16_t commandNo; //!< The command ID number 0x2402 +} __RFC_STRUCT_ATTR; + +//! @} + +//! \addtogroup CMD_IEEE_CCA_REQ +//! @{ +#define CMD_IEEE_CCA_REQ 0x2403 +//! IEEE 802.15.4 CCA and RSSI Information Request Command +struct __RFC_STRUCT rfc_CMD_IEEE_CCA_REQ_s { + uint16_t commandNo; //!< The command ID number 0x2403 + int8_t currentRssi; //!< The RSSI currently observed on the channel + int8_t maxRssi; //!< The maximum RSSI observed on the channel since Rx was started + struct { + uint8_t ccaState:2; //!< \brief Value of the current CCA state
+ //!< 0: Idle
+ //!< 1: Busy
+ //!< 2: Invalid + uint8_t ccaEnergy:2; //!< \brief Value of the current energy detect CCA state
+ //!< 0: Idle
+ //!< 1: Busy
+ //!< 2: Invalid + uint8_t ccaCorr:2; //!< \brief Value of the current correlator based carrier sense CCA state
+ //!< 0: Idle
+ //!< 1: Busy
+ //!< 2: Invalid + uint8_t ccaSync:1; //!< \brief Value of the current sync found based carrier sense CCA state
+ //!< 0: Idle
+ //!< 1: Busy + } ccaInfo; +} __RFC_STRUCT_ATTR; + +//! @} + +//! \addtogroup ieeeRxOutput +//! @{ +//! Output structure for CMD_IEEE_RX + +struct __RFC_STRUCT rfc_ieeeRxOutput_s { + uint8_t nTxAck; //!< Total number of transmitted ACK frames + uint8_t nRxBeacon; //!< Number of received beacon frames + uint8_t nRxData; //!< Number of received data frames + uint8_t nRxAck; //!< Number of received acknowledgement frames + uint8_t nRxMacCmd; //!< Number of received MAC command frames + uint8_t nRxReserved; //!< Number of received frames with reserved frame type + uint8_t nRxNok; //!< Number of received frames with CRC error + uint8_t nRxIgnored; //!< Number of frames received that are to be ignored + uint8_t nRxBufFull; //!< Number of received frames discarded because the Rx buffer was full + int8_t lastRssi; //!< RSSI of last received frame + int8_t maxRssi; //!< Highest RSSI observed in the operation + uint8_t __dummy0; + ratmr_t beaconTimeStamp; //!< Time stamp of last received beacon frame +} __RFC_STRUCT_ATTR; + +//! @} + +//! \addtogroup shortAddrEntry +//! @{ +//! Structure for short address entries + +struct __RFC_STRUCT rfc_shortAddrEntry_s { + uint16_t shortAddr; //!< Short address + uint16_t panId; //!< PAN ID +} __RFC_STRUCT_ATTR; + +//! @} + +//! \addtogroup ieeeRxCorrCrc +//! @{ +//! Receive status byte that may be appended to message in receive buffer + +struct __RFC_STRUCT rfc_ieeeRxCorrCrc_s { + struct { + uint8_t corr:6; //!< The correlation value + uint8_t bIgnore:1; //!< 1 if the packet should be rejected by frame filtering, 0 otherwise + uint8_t bCrcErr:1; //!< 1 if the packet was received with CRC error, 0 otherwise + } status; +} __RFC_STRUCT_ATTR; + +//! @} + +//! @} +//! @} +#endif diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/driverlib/rf_ieee_mailbox.h b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/driverlib/rf_ieee_mailbox.h new file mode 100644 index 000000000..fce171ff7 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/driverlib/rf_ieee_mailbox.h @@ -0,0 +1,74 @@ +/****************************************************************************** +* Filename: rf_ieee_mailbox.h +* Revised: 2018-01-23 19:51:42 +0100 (Tue, 23 Jan 2018) +* Revision: 18189 +* +* Description: Definitions for IEEE 802.15.4 interface +* +* Copyright (c) 2015 - 2017, Texas Instruments Incorporated +* 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 ORGANIZATION 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 _IEEE_MAILBOX_H +#define _IEEE_MAILBOX_H + +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) + +/// \name Radio operation status +///@{ +/// \name Operation not finished +///@{ +#define IEEE_SUSPENDED 0x2001 ///< Operation suspended +///@} +/// \name Operation finished normally +///@{ +#define IEEE_DONE_OK 0x2400 ///< Operation ended normally +#define IEEE_DONE_BUSY 0x2401 ///< CSMA-CA operation ended with failure +#define IEEE_DONE_STOPPED 0x2402 ///< Operation stopped after stop command +#define IEEE_DONE_ACK 0x2403 ///< ACK packet received with pending data bit cleared +#define IEEE_DONE_ACKPEND 0x2404 ///< ACK packet received with pending data bit set +#define IEEE_DONE_TIMEOUT 0x2405 ///< Operation ended due to timeout +#define IEEE_DONE_BGEND 0x2406 ///< FG operation ended because necessary background level + ///< operation ended +#define IEEE_DONE_ABORT 0x2407 ///< Operation aborted by command +///@} +/// \name Operation finished with error +///@{ +#define IEEE_ERROR_PAR 0x2800 ///< Illegal parameter +#define IEEE_ERROR_NO_SETUP 0x2801 ///< Operation using Rx or Tx attempted when not in 15.4 mode +#define IEEE_ERROR_NO_FS 0x2802 ///< Operation using Rx or Tx attempted without frequency synth configured +#define IEEE_ERROR_SYNTH_PROG 0x2803 ///< Synthesizer programming failed to complete on time +#define IEEE_ERROR_RXOVF 0x2804 ///< Receiver overflowed during operation +#define IEEE_ERROR_TXUNF 0x2805 ///< Transmitter underflowed during operation +///@} +///@} + +#endif diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-ieee-settings.c b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-ieee-settings.c new file mode 100644 index 000000000..f84c413d1 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-ieee-settings.c @@ -0,0 +1,227 @@ +//********************************************************************************* +// Generated by SmartRF Studio version 2.8.0 ( build #41) +// Compatible with SimpleLink SDK version: CC13x2 SDK 1.60.xx.xx +// Device: CC1352 Rev. 1.0 +// +//********************************************************************************* + + +//********************************************************************************* +// Parameter summary +// IEEE Channel: 11 +// Frequency: 2405 MHz +// SFD: 0 +// Packet Data: 255 +// Preamble (32 bit): 01010101... +// TX Power: 5 dBm + +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include + +// This is included from the local driverlib/ directory +#include "driverlib/rf_ieee_cmd.h" +// This is included from the local rf_patches/ directory +#include "rf_patches/rf_patch_cpe_ieee.h" + +#include "rf-ieee-settings.h" +/*---------------------------------------------------------------------------*/ +// TX Power table +// The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: +// RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) +// See the Technical Reference Manual for further details about the "txPower" Command field. +// The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. +RF_TxPowerTable_Entry txPowerTable[] = +{ + {-21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 6) }, + {-18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 6) }, + {-15, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 6) }, + {-12, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 1, 0, 10) }, + { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 1, 12) }, + { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(18, 1, 1, 14) }, + { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 1, 1, 18) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(33, 1, 1, 24) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 0, 0, 33) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 0, 0, 39) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 0, 0, 45) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(36, 0, 1, 73) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(48, 0, 1, 73) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; + +const size_t txPowerTableLen = sizeof(txPowerTable) / sizeof(txPowerTable[0]); + +// TI-RTOS RF Mode Object +RF_Mode RF_ieeeMode = +{ + .rfMode = RF_MODE_IEEE_15_4, + .cpePatchFxn = &rf_patch_cpe_ieee, + .mcePatchFxn = 0, + .rfePatchFxn = 0, +}; + + +// Overrides for CMD_RADIO_SETUP +uint32_t pOverrides[] = +{ + // override_synth_ieee_15_4.xml + HW_REG_OVERRIDE(0x4038,0x0035), // Synth: Set recommended RTRIM to 5 + (uint32_t)0x000784A3, // Synth: Set Fref to 3.43 MHz + (uint32_t)0xA47E0583, // Synth: Set loop bandwidth after lock to 80 kHz + (uint32_t)0xEAE00603, // Synth: Set loop bandwidth after lock to 80 kHz + (uint32_t)0x00010623, // Synth: Set loop bandwidth after lock to 80 kHz + HW32_ARRAY_OVERRIDE(0x405C,1), // Synth: Configure PLL bias + (uint32_t)0x1801F800, // Synth: Configure PLL bias + HW32_ARRAY_OVERRIDE(0x402C,1), // Synth: Configure PLL latency + (uint32_t)0x00608402, // Synth: Configure PLL latency + (uint32_t)0x02010403, // Synth: Use 24 MHz XOSC as synth clock, enable extra PLL filtering + HW32_ARRAY_OVERRIDE(0x4034,1), // Synth: Configure extra PLL filtering + (uint32_t)0x177F0408, // Synth: Configure extra PLL filtering + (uint32_t)0x38000463, // Synth: Configure extra PLL filtering + (uint32_t)0x05000243, // Synth: Increase synth programming timeout + // override_phy_ieee_15_4.xml + (uint32_t)0x002082C3, // Rx: Adjust Rx FIFO threshold to avoid overflow + (uint32_t)0x000288A3, // Rx: Set RSSI offset to adjust reported RSSI by -2 dB + // override_frontend_id.xml + (uint32_t)0x000F8883, // Rx: Configure LNA bias current trim offset + HW_REG_OVERRIDE(0x50DC,0x002B), // Rx: Adjust AGC DC filter + (uint32_t)0xFFFFFFFF, +}; + + +// CMD_RADIO_SETUP +// Radio Setup Command for Pre-Defined Schemes +rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup = +{ + .commandNo = 0x0802, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .mode = 0x01, + .loDivider = 0x00, + .config.frontEndMode = 0x0, + .config.biasMode = 0x0, + .config.analogCfgMode = 0x0, + .config.bNoFsPowerUp = 0x0, + .txPower = 0x001F, + .pRegOverride = pOverrides, +}; + + +// CMD_FS +// Frequency Synthesizer Programming Command +rfc_CMD_FS_t RF_cmdFs = +{ + .commandNo = 0x0803, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .frequency = 0x0965, + .fractFreq = 0x0000, + .synthConf.bTxMode = 0x0, + .synthConf.refFreq = 0x0, + .__dummy0 = 0x00, + .__dummy1 = 0x00, + .__dummy2 = 0x00, + .__dummy3 = 0x0000, +}; + + +// CMD_IEEE_RX +// IEEE 802.15.4 Receive Command +rfc_CMD_IEEE_RX_t RF_cmdIeeeRx = +{ + .commandNo = CMD_IEEE_RX, + .status = IDLE, + .pNextOp = NULL, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .condition.rule = COND_NEVER, + .channel = 0, + .rxConfig.bAutoFlushCrc = 0x1, + .rxConfig.bAutoFlushIgn = 0x0, + .rxConfig.bIncludePhyHdr = 0x0, + .rxConfig.bIncludeCrc = 0x1, + .rxConfig.bAppendRssi = 0x1, + .rxConfig.bAppendCorrCrc = 0x1, + .rxConfig.bAppendSrcInd = 0x0, + .rxConfig.bAppendTimestamp = 0x1, + .pRxQ = NULL, + .pOutput = NULL, + .frameFiltOpt.frameFiltEn = 0x0, + .frameFiltOpt.frameFiltStop = 0x1, + .frameFiltOpt.autoAckEn = 0x0, + .frameFiltOpt.slottedAckEn = 0x0, + .frameFiltOpt.autoPendEn = 0x0, + .frameFiltOpt.defaultPend = 0x0, + .frameFiltOpt.bPendDataReqOnly = 0x0, + .frameFiltOpt.bPanCoord = 0x0, + .frameFiltOpt.maxFrameVersion = 0x2, + .frameFiltOpt.fcfReservedMask = 0x0, + .frameFiltOpt.modifyFtFilter = 0x0, + .frameFiltOpt.bStrictLenFilter = 0x0, + .frameTypes.bAcceptFt0Beacon = 0x1, + .frameTypes.bAcceptFt1Data = 0x1, + .frameTypes.bAcceptFt2Ack = 0x1, + .frameTypes.bAcceptFt3MacCmd = 0x1, + .frameTypes.bAcceptFt4Reserved = 0x1, + .frameTypes.bAcceptFt5Reserved = 0x1, + .frameTypes.bAcceptFt6Reserved = 0x1, + .frameTypes.bAcceptFt7Reserved = 0x1, + .ccaOpt.ccaEnEnergy = 0x1, + .ccaOpt.ccaEnCorr = 0x1, + .ccaOpt.ccaEnSync = 0x1, + .ccaOpt.ccaCorrOp = 0x1, + .ccaOpt.ccaSyncOp = 0x0, + .ccaOpt.ccaCorrThr = 0x3, + .ccaRssiThr = 0x64, + .numExtEntries = 0x00, + .numShortEntries = 0x00, + .pExtEntryList = NULL, + .pShortEntryList = NULL, + .localExtAddr = 0x0000000012345678, + .localShortAddr = 0xABBA, + .localPanID = 0x0000, + .endTrigger.triggerType = TRIG_NEVER, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, +}; + + +// CMD_IEEE_TX +// IEEE 802.15.4 Transmit Command +rfc_CMD_IEEE_TX_t RF_cmdIeeeTx = +{ + .commandNo = 0x2C01, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .txOpt.bIncludePhyHdr = 0x0, + .txOpt.bIncludeCrc = 0x0, + .txOpt.payloadLenMsb = 0x0, + .payloadLen = 0x1E, + .pPayload = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .timeStamp = 0x00000000, +}; + diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-ieee-settings.h b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-ieee-settings.h new file mode 100644 index 000000000..c7461e2fc --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-ieee-settings.h @@ -0,0 +1,26 @@ +#ifndef IEEE_SETTINGS_H_ +#define IEEE_SETTINGS_H_ + +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h) +#include + +// RF TX power table +extern RF_TxPowerTable_Entry txPowerTable[]; +extern const size_t txPowerTableLen; + +// TI-RTOS RF Mode Object +extern RF_Mode RF_ieeeMode; + +// RF Core API commands +extern rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup; +extern rfc_CMD_FS_t RF_cmdFs; +extern rfc_CMD_IEEE_RX_t RF_cmdIeeeRx; +extern rfc_CMD_IEEE_TX_t RF_cmdIeeeTx; + +// RF Core API Overrides +extern uint32_t pOverrides[]; + +#endif /* IEEE_SETTINGS_H_ */ diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-prop-settings.c b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-prop-settings.c new file mode 100644 index 000000000..465bd65c6 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-prop-settings.c @@ -0,0 +1,276 @@ +//********************************************************************************* +// Generated by SmartRF Studio version 2.8.0 ( build #41) +// Compatible with SimpleLink SDK version: CC13x2 SDK 1.60.xx.xx +// Device: CC1352 Rev. 1.0 +// +//********************************************************************************* + + +//********************************************************************************* +// Parameter summary +// Address: off +// Address0: 0xAA +// Address1: 0xBB +// Frequency: 868.00000 MHz +// Data Format: Serial mode disable +// Deviation: 25.000 kHz +// pktLen: 30 +// 802.15.4g Mode: off +// Select bit order to transmit PSDU octets:: 1 +// Packet Length Config: Variable +// Max Packet Length: 255 +// Packet Length: 30 +// RX Filter BW: 98.0 kHz +// Symbol Rate: 50.00000 kBaud +// Sync Word Length: 32 Bits +// TX Power: 14 dBm (requires define CCFG_FORCE_VDDR_HH = 1 in ccfg.c, see CC13xx/CC26xx Technical Reference Manual) +// Whitening: No whitening + +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h) +#include +#include DeviceFamily_constructPath(rf_patches/rf_patch_rfe_genfsk.h) + +#include "rf-common.h" + +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup rf-core-prop + * @{ + * + * \file + * Default TX power settings. The board can override + */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Default TX power settings for the 779-930MHz band */ +RF_TxPower RF_propTxPower779_930[] = { + { 14, 0xa73f }, + { 13, 0xa63f }, /* 12.5 */ + { 12, 0xb818 }, + { 11, 0x50da }, + { 10, 0x38d3 }, + { 9, 0x2ccd }, + { 8, 0x24cb }, + { 7, 0x20c9 }, + { 6, 0x1cc7 }, + { 5, 0x18c6 }, + { 4, 0x18c5 }, + { 3, 0x14c4 }, + { 2, 0x1042 }, + { 1, 0x10c3 }, + { 0, 0x0041 }, + { -10, 0x08c0 }, + {-128, 0xFFFF }, +}; +const size_t RF_propTxPower779_930Size = sizeof(RF_propTxPower779_930) / sizeof(RF_propTxPower779_930[0]); +/*---------------------------------------------------------------------------*/ +/* Default TX power settings for the 431-527MHz band */ +RF_TxPower RF_propTxPower431_527[] = { + { 15, 0x003f }, + { 14, 0xbe3f }, /* 13.7 */ + { 13, 0x6a0f }, + { 10, 0x3dcb }, + { 6, 0x22c4 }, + {-128, 0xFFFF }, +}; +const size_t RF_propTxPower431_527Size = sizeof(RF_propTxPower431_527) / sizeof(RF_propTxPower431_527[0]); +/*---------------------------------------------------------------------------*/ +/** + * @} + */ + +// TI-RTOS RF Mode Object +RF_Mode RF_propMode = +{ + .rfMode = RF_MODE_PROPRIETARY_SUB_1, + .cpePatchFxn = NULL, + .mcePatchFxn = NULL, + .rfePatchFxn = &rf_patch_rfe_genfsk, +}; + +// Overrides for CMD_PROP_RADIO_DIV_SETUP +static uint32_t pOverrides[] = +{ + // override_use_patch_prop_genfsk.xml + // PHY: Use MCE RAM patch, RFE RAM patch + MCE_RFE_OVERRIDE(1,0,0,1,0,0), + // override_synth_prop_863_930_div5.xml + // Synth: Use 48 MHz crystal as synth clock, enable extra PLL filtering + (uint32_t)0x02400403, + // Synth: Set minimum RTRIM to 7 + (uint32_t)0x00078793, + // Synth: Configure extra PLL filtering + (uint32_t)0x00108463, + // Synth: Set Fref to 4 MHz + (uint32_t)0x000684A3, + // Synth: Set loop bandwidth after lock to 20 kHz + (uint32_t)0x0A480583, + // Synth: Set loop bandwidth after lock to 20 kHz + (uint32_t)0x7AB80603, + // override_phy_tx_pa_ramp_genfsk.xml + // Tx: Configure PA ramping, set wait time before turning off (0x2F ticks à 16/24 us = 31.3 us). + HW_REG_OVERRIDE(0x6028,0x002F), + // Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[3]=1) + ADI_HALFREG_OVERRIDE(0,16,0x8,0x8), + // Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[4]=1) + ADI_HALFREG_OVERRIDE(0,17,0x1,0x1), + // override_phy_rx_aaf_bw_0xd.xml + // Rx: Set anti-aliasing filter bandwidth to 0xD (in ADI0, set IFAMPCTL3[7:4]=0xD) + ADI_HALFREG_OVERRIDE(0,61,0xF,0xD), + // override_phy_rx_rssi_offset_neg2db.xml + // Rx: Set RSSI offset to adjust reported RSSI by -2 dB + (uint32_t)0x000288A3, + // TX power override + // DC/DC regulator: In Tx with 14 dBm PA setting, use DCDCCTL5[3:0]=0xF (DITHER_EN=1 and IPEAK=7). In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). + (uint32_t)0xFFFC08C3, + (uint32_t)0xFFFFFFFF, +}; + + +// CMD_PROP_RADIO_DIV_SETUP +// Proprietary Mode Radio Setup Command for All Frequency Bands +rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup = +{ + .commandNo = 0x3807, + .status = 0x0000, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .modulation.modType = 0x1, + .modulation.deviation = 0x64, + .symbolRate.preScale = 0xf, + .symbolRate.rateWord = 0x8000, + .rxBw = 0x24, + .preamConf.nPreamBytes = 0x3, + .preamConf.preamMode = 0x0, + .formatConf.nSwBits = 0x18, + .formatConf.bBitReversal = 0x0, + .formatConf.bMsbFirst = 0x1, + .formatConf.fecMode = 0x0, + + /* 7: .4g mode with dynamic whitening and CRC choice */ + .formatConf.whitenMode = 0x7, + .config.frontEndMode = 0x00, /* Set by the driver */ + .config.biasMode = 0x00, /* Set by the driver */ + .config.analogCfgMode = 0x0, + .config.bNoFsPowerUp = 0x0, + .txPower = 0x00, /* Driver sets correct value */ + .pRegOverride = pOverrides, + .intFreq = 0x8000, + .centerFreq = 868, + .loDivider = 0x05, +}; + +// CMD_FS +// Frequency Synthesizer Programming Command +rfc_CMD_FS_t rf_cmd_prop_fs = +{ + .commandNo = 0x0803, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .frequency = 0x0364, + .fractFreq = 0x0000, + .synthConf.bTxMode = 0x0, + .synthConf.refFreq = 0x0, + .__dummy0 = 0x00, + .__dummy1 = 0x00, + .__dummy2 = 0x00, + .__dummy3 = 0x0000, +}; + +/* CMD_PROP_TX_ADV */ +rfc_CMD_PROP_TX_ADV_t rf_cmd_prop_tx_adv = +{ + .commandNo = 0x3803, + .status = 0x0000, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .pktConf.bFsOff = 0x0, + .pktConf.bUseCrc = 0x1, + .pktConf.bCrcIncSw = 0x0, /* .4g mode */ + .pktConf.bCrcIncHdr = 0x0, /* .4g mode */ + .numHdrBits = 0x10 /* 16: .4g mode */, + .pktLen = 0x0000, + .startConf.bExtTxTrig = 0x0, + .startConf.inputMode = 0x0, + .startConf.source = 0x0, + .preTrigger.triggerType = TRIG_NOW, + .preTrigger.bEnaCmd = 0x0, + .preTrigger.triggerNo = 0x0, + .preTrigger.pastTrig = 0x1, + .preTime = 0x00000000, + .syncWord = 0x0055904e, + .pPkt = 0, +}; +/*---------------------------------------------------------------------------*/ +/* CMD_PROP_RX_ADV */ +rfc_CMD_PROP_RX_ADV_t rf_cmd_prop_rx_adv = +{ + .commandNo = 0x3804, + .status = 0x0000, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .pktConf.bFsOff = 0x0, + .pktConf.bRepeatOk = 0x1, + .pktConf.bRepeatNok = 0x1, + .pktConf.bUseCrc = 0x1, + .pktConf.bCrcIncSw = 0x0, /* .4g mode */ + .pktConf.bCrcIncHdr = 0x0, /* .4g mode */ + .pktConf.endType = 0x0, + .pktConf.filterOp = 0x1, + .rxConf.bAutoFlushIgnored = 0x1, + .rxConf.bAutoFlushCrcErr = 0x1, + .rxConf.bIncludeHdr = 0x0, + .rxConf.bIncludeCrc = 0x0, + .rxConf.bAppendRssi = 0x1, + .rxConf.bAppendTimestamp = 0x0, + .rxConf.bAppendStatus = 0x1, + .syncWord0 = 0x0055904e, + .syncWord1 = 0x00000000, + .maxPktLen = 0x0000, /* To be populated by the driver. */ + .hdrConf.numHdrBits = 0x10, /* 16: .4g mode */ + .hdrConf.lenPos = 0x0, /* .4g mode */ + .hdrConf.numLenBits = 0x0B, /* 11 = 0x0B .4g mode */ + .addrConf.addrType = 0x0, + .addrConf.addrSize = 0x0, + .addrConf.addrPos = 0x0, + .addrConf.numAddr = 0x0, + .lenOffset = -4, /* .4g mode */ + .endTrigger.triggerType = TRIG_NEVER, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, + .pAddr = 0, + .pQueue = 0, + .pOutput = 0, +}; +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/rf-prop-settings.h b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-prop-settings.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/rf-prop-settings.h rename to arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-prop-settings.h diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf_patches/rf_patch_cpe_ieee.h b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf_patches/rf_patch_cpe_ieee.h new file mode 100644 index 000000000..f3089f061 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf_patches/rf_patch_cpe_ieee.h @@ -0,0 +1,269 @@ +/****************************************************************************** +* Filename: rf_patch_cpe_ieee.h +* Revised: $Date$ +* Revision: $Revision$ +* +* Description: RF Core patch file for CC26xx IEEE 802.15.4 PHY +* +* Copyright (c) 2015, Texas Instruments Incorporated +* 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 ORGANIZATION 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 _RF_PATCH_CPE_IEEE_H +#define _RF_PATCH_CPE_IEEE_H + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include + +#ifndef CPE_PATCH_TYPE +#define CPE_PATCH_TYPE static const uint32_t +#endif + +#ifndef SYS_PATCH_TYPE +#define SYS_PATCH_TYPE static const uint32_t +#endif + +#ifndef PATCH_FUN_SPEC +#define PATCH_FUN_SPEC static inline +#endif + +#ifndef _APPLY_PATCH_TAB +#define _APPLY_PATCH_TAB +#endif + + +CPE_PATCH_TYPE patchImageIeee[] = { + 0x210004ef, + 0x21000419, + 0x21000519, + 0x21000599, + 0x210004b1, + 0x22024823, + 0x421a7dc3, + 0xd0034472, + 0x1dc04678, + 0xb5f84686, + 0x4c1f4710, + 0x200834ae, + 0x490347a0, + 0x60082008, + 0x3cec6008, + 0xbdf847a0, + 0x40045004, + 0x4c17b5f0, + 0x18612140, + 0x280278c8, + 0x4809d005, + 0x60012100, + 0x47884908, + 0x6e25bdf0, + 0x60354e07, + 0x43280760, + 0x68276620, + 0x480e6024, + 0x60274780, + 0xbdf06035, + 0x4004112c, + 0x000065a5, + 0x40044028, + 0x4c07b510, + 0x29007da1, + 0x2101d105, + 0x024875a1, + 0x393e4904, + 0x68204788, + 0xd0002800, + 0xbd104780, + 0x21000254, + 0x0000398b, + 0x6a034807, + 0x46784907, + 0x46861dc0, + 0x4788b5f8, + 0x009b089b, + 0x6a014802, + 0xd10007c9, + 0xbdf86203, + 0x40045040, + 0x0000f1ab, + 0x6a00480b, + 0xd00407c0, + 0x2201480a, + 0x43117801, + 0x48097001, + 0x72c84700, + 0xd006280d, + 0x00802285, + 0x18800252, + 0x60486840, + 0x48044770, + 0x0000e7fb, + 0x40045040, + 0x21000268, + 0x0000ff39, + 0x210004d9, + 0x4e1ab5f8, + 0x6b314605, + 0x09cc4819, + 0x2d0001e4, + 0x4918d011, + 0x29027809, + 0x7b00d00f, + 0xb6724304, + 0x4f152001, + 0x47b80240, + 0x38204811, + 0x09c18800, + 0xd00407c9, + 0x7ac0e016, + 0x7b40e7f0, + 0x490fe7ee, + 0x61cc6334, + 0x07c00a40, + 0x2001d00c, + 0x6af10380, + 0xd0012d00, + 0xe0004301, + 0x46084381, + 0x490762f1, + 0x63483940, + 0x47b82000, + 0xbdf8b662, + 0x21000280, + 0x21000088, + 0x21000296, + 0x00003cdf, + 0x40044040, + 0x28004907, + 0x2004d000, + 0xb6724a06, + 0x07c97809, + 0x5810d001, + 0x2080e000, + 0xb240b662, + 0x00004770, + 0x2100026b, + 0x40046058, +}; +#define _NWORD_PATCHIMAGE_IEEE 111 + +#define _NWORD_PATCHSYS_IEEE 0 + +#define _IRQ_PATCH_0 0x21000449 +#define _IRQ_PATCH_1 0x21000489 + + +#ifndef _IEEE_SYSRAM_START +#define _IEEE_SYSRAM_START 0x20000000 +#endif + +#ifndef _IEEE_CPERAM_START +#define _IEEE_CPERAM_START 0x21000000 +#endif + +#define _IEEE_SYS_PATCH_FIXED_ADDR 0x20000000 + +#define _IEEE_PARSER_PATCH_TAB_OFFSET 0x0334 +#define _IEEE_PATCH_TAB_OFFSET 0x033C +#define _IEEE_IRQPATCH_OFFSET 0x03AC +#define _IEEE_PATCH_VEC_OFFSET 0x0404 + +PATCH_FUN_SPEC void enterIeeeCpePatch(void) +{ + uint32_t *pPatchVec = (uint32_t *) (_IEEE_CPERAM_START + _IEEE_PATCH_VEC_OFFSET); + +#if (_NWORD_PATCHIMAGE_IEEE > 0) + memcpy(pPatchVec, patchImageIeee, sizeof(patchImageIeee)); +#endif +} + +PATCH_FUN_SPEC void enterIeeeSysPatch(void) +{ +} + +PATCH_FUN_SPEC void configureIeeePatch(void) +{ + uint8_t *pPatchTab = (uint8_t *) (_IEEE_CPERAM_START + _IEEE_PATCH_TAB_OFFSET); + uint32_t *pIrqPatch = (uint32_t *) (_IEEE_CPERAM_START + _IEEE_IRQPATCH_OFFSET); + + + pPatchTab[5] = 0; + pPatchTab[52] = 1; + pPatchTab[103] = 2; + pPatchTab[60] = 3; + pPatchTab[38] = 4; + + pIrqPatch[1] = _IRQ_PATCH_0; + pIrqPatch[9] = _IRQ_PATCH_1; +} + +PATCH_FUN_SPEC void applyIeeePatch(void) +{ + enterIeeeSysPatch(); + enterIeeeCpePatch(); + configureIeeePatch(); +} + +PATCH_FUN_SPEC void refreshIeeePatch(void) +{ + enterIeeeCpePatch(); + configureIeeePatch(); +} + +PATCH_FUN_SPEC void rf_patch_cpe_ieee(void) +{ + applyIeeePatch(); +} + +#undef _IRQ_PATCH_0 +#undef _IRQ_PATCH_1 + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif + +#endif // _RF_PATCH_CPE_IEEE_H + diff --git a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds new file mode 100644 index 000000000..91c5e1bd0 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2017-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ +/* + * ======== CC26X2R1_LAUNCHXL_NoRTOS.lds ======== + * Default Linker script for the Texas Instruments CC1352 + */ + +STACKSIZE = 1024; +HEAPSIZE = 256; /* Size of heap buffer used by HeapMem */ + +MEMORY +{ + FLASH (RX) : ORIGIN = 0x00000000, LENGTH = 0x00057fa8 + /* + * Customer Configuration Area and Bootloader Backdoor configuration in + * flash, 40 bytes + */ + FLASH_CCFG (RX) : ORIGIN = 0x00057fa8, LENGTH = 0x00000058 + SRAM (RWX) : ORIGIN = 0x20000000, LENGTH = 0x00014000 + GPRAM (RWX) : ORIGIN = 0x11000000, LENGTH = 0x00002000 +} + +REGION_ALIAS("REGION_TEXT", FLASH); +REGION_ALIAS("REGION_BSS", SRAM); +REGION_ALIAS("REGION_DATA", SRAM); +REGION_ALIAS("REGION_STACK", SRAM); +REGION_ALIAS("REGION_HEAP", SRAM); +REGION_ALIAS("REGION_ARM_EXIDX", FLASH); +REGION_ALIAS("REGION_ARM_EXTAB", FLASH); + +SECTIONS { + + PROVIDE (_resetVecs_base_address = + DEFINED(_resetVecs_base_address) ? _resetVecs_base_address : 0x0); + + .resetVecs (_resetVecs_base_address) : AT (_resetVecs_base_address) { + KEEP (*(.resetVecs)) + } > REGION_TEXT + + .ramVecs (NOLOAD) : ALIGN(1024){ + KEEP (*(.ramVecs)) + } > REGION_DATA + + /* + * UDMACC26XX_CONFIG_BASE below must match UDMACC26XX_CONFIG_BASE defined + * by ti/drivers/dma/UDMACC26XX.h + * The user is allowed to change UDMACC26XX_CONFIG_BASE to move it away from + * the default address 0x2000_1800, but remember it must be 1024 bytes aligned. + */ + UDMACC26XX_CONFIG_BASE = 0x20001800; + + /* + * Define absolute addresses for the DMA channels. + * DMA channels must always be allocated at a fixed offset from the DMA base address. + * --------- DO NOT MODIFY ----------- + */ + DMA_SPI0_RX_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x30); + DMA_SPI0_TX_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x40); + DMA_ADC_PRI_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x70); + DMA_GPT0A_PRI_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x90); + DMA_SPI1_RX_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x100); + DMA_SPI1_TX_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x110); + DMA_ADC_ALT_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x270); + DMA_GPT0A_ALT_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x290); + + /* + * Allocate SPI0, SPI1, ADC, and GPTimer0 DMA descriptors at absolute addresses. + * --------- DO NOT MODIFY ----------- + */ + UDMACC26XX_dmaSpi0RxControlTableEntry_is_placed = 0; + .dmaSpi0RxControlTableEntry DMA_SPI0_RX_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_SPI0_RX_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaSpi0RxControlTableEntry)} > REGION_DATA + + UDMACC26XX_dmaSpi0TxControlTableEntry_is_placed = 0; + .dmaSpi0TxControlTableEntry DMA_SPI0_TX_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_SPI0_TX_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaSpi0TxControlTableEntry)} > REGION_DATA + + UDMACC26XX_dmaADCPriControlTableEntry_is_placed = 0; + .dmaADCPriControlTableEntry DMA_ADC_PRI_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_ADC_PRI_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaADCPriControlTableEntry)} > REGION_DATA + + UDMACC26XX_dmaGPT0APriControlTableEntry_is_placed = 0; + .dmaGPT0APriControlTableEntry DMA_GPT0A_PRI_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_GPT0A_PRI_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaGPT0APriControlTableEntry)} > REGION_DATA + + UDMACC26XX_dmaSpi1RxControlTableEntry_is_placed = 0; + .dmaSpi1RxControlTableEntry DMA_SPI1_RX_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_SPI1_RX_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaSpi1RxControlTableEntry)} > REGION_DATA + + UDMACC26XX_dmaSpi1TxControlTableEntry_is_placed = 0; + .dmaSpi1TxControlTableEntry DMA_SPI1_TX_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_SPI1_TX_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaSpi1TxControlTableEntry)} > REGION_DATA + + UDMACC26XX_dmaADCAltControlTableEntry_is_placed = 0; + .dmaADCAltControlTableEntry DMA_ADC_ALT_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_ADC_ALT_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaADCAltControlTableEntry)} > REGION_DATA + + UDMACC26XX_dmaGPT0AAltControlTableEntry_is_placed = 0; + .dmaGPT0AAltControlTableEntry DMA_GPT0A_ALT_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_GPT0A_ALT_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaGPT0AAltControlTableEntry)} > REGION_DATA + + .text : { + CREATE_OBJECT_SYMBOLS + *(.text) + *(.text.*) + . = ALIGN(0x4); + KEEP (*(.ctors)) + . = ALIGN(0x4); + KEEP (*(.dtors)) + . = ALIGN(0x4); + __init_array_start = .; + KEEP (*(.init_array*)) + __init_array_end = .; + *(.init) + *(.fini*) + } > REGION_TEXT AT> REGION_TEXT + + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + + .rodata : { + *(.rodata) + *(.rodata.*) + } > REGION_TEXT AT> REGION_TEXT + + .data : ALIGN(4) { + __data_load__ = LOADADDR (.data); + __data_start__ = .; + *(.data) + *(.data.*) + . = ALIGN (4); + __data_end__ = .; + } > REGION_DATA AT> REGION_TEXT + + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + __exidx_end = .; + } > REGION_ARM_EXIDX AT> REGION_ARM_EXIDX + + .ARM.extab : { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > REGION_ARM_EXTAB AT> REGION_ARM_EXTAB + + .nvs (NOLOAD) : ALIGN(0x2000) { + *(.nvs) + } > REGION_TEXT + + .ccfg : { + KEEP (*(.ccfg)) + } > FLASH_CCFG AT> FLASH_CCFG + + .bss : { + __bss_start__ = .; + *(.shbss) + *(.bss) + *(.bss.*) + *(COMMON) + . = ALIGN (4); + __bss_end__ = .; + } > REGION_BSS AT> REGION_BSS + + .heap : { + __heap_start__ = .; + end = __heap_start__; + _end = end; + __end = end; + . = . + HEAPSIZE; + KEEP(*(.heap)) + __heap_end__ = .; + __HeapLimit = __heap_end__; + } > REGION_HEAP AT> REGION_HEAP + + .stack (NOLOAD) : ALIGN(0x8) { + _stack = .; + __stack = .; + KEEP(*(.stack)) + . += STACKSIZE; + _stack_end = .; + __stack_end = .; + } > REGION_STACK AT> REGION_STACK +} diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/rf-ieee-settings.c b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/rf-settings/rf-ieee-settings.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/rf-ieee-settings.c rename to arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/rf-settings/rf-ieee-settings.c diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/rf-ieee-settings.h b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/rf-settings/rf-ieee-settings.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/rf-ieee-settings.h rename to arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/rf-settings/rf-ieee-settings.h diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/rf-prop-settings.c b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/rf-settings/rf-prop-settings.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/rf-settings/rf-prop-settings.c rename to arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/rf-settings/rf-prop-settings.c diff --git a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/rf-settings/rf-prop-settings.h b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/rf-settings/rf-prop-settings.h new file mode 100644 index 000000000..947c5254e --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/rf-settings/rf-prop-settings.h @@ -0,0 +1,35 @@ +#ifndef RF_PROP_SETTINGS_H_ +#define RF_PROP_SETTINGS_H_ + +//********************************************************************************* +// Generated by SmartRF Studio version 2.8.0 ( build #41) +// Compatible with SimpleLink SDK version: CC13x2 SDK 1.60.xx.xx +// Device: CC1352 Rev. 1.0 +// +//********************************************************************************* +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h) +#include + +#include + +// RF TX power table +extern RF_TxPower RF_propTxPower779_930[]; +extern const size_t RF_propTxPower779_930Size; + +extern RF_TxPower RF_propTxPower431_527[]; +extern const size_t RF_propTxPower431_527Size; + +// TI-RTOS RF Mode Object +extern RF_Mode RF_propMode; + +// RF Core API commands +extern rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup; +extern rfc_CMD_FS_t rf_cmd_prop_fs; +extern rfc_CMD_PROP_TX_ADV_t rf_cmd_prop_tx_adv; +extern rfc_CMD_PROP_RX_ADV_t rf_cmd_prop_rx_adv; + + +#endif /* RF_PROP_SETTINGS_H_ */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/batmon-sensor.c b/arch/cpu/cc13xx-cc26xx/dev/batmon-sensor.c new file mode 100644 index 000000000..423a9fbcc --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/dev/batmon-sensor.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup cc26xx-batmon + * @{ + * + * \file + * Driver for the CC13xx/CC26xx AON battery monitor + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "lib/sensors.h" +#include "batmon-sensor.h" + +#include "ti-lib.h" + +#include +#include +/*---------------------------------------------------------------------------*/ +#define DEBUG 0 +#if DEBUG +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif +/*---------------------------------------------------------------------------*/ +#define SENSOR_STATUS_DISABLED 0 +#define SENSOR_STATUS_ENABLED 1 + +static int enabled = SENSOR_STATUS_DISABLED; +/*---------------------------------------------------------------------------*/ +/** + * \brief Returns a reading from the sensor + * \param type BATMON_SENSOR_TYPE_TEMP or BATMON_SENSOR_TYPE_VOLT + * + * \return The value as returned by the respective CC26xxware function + */ +static int +value(int type) +{ + if(enabled == SENSOR_STATUS_DISABLED) { + PRINTF("Sensor Disabled\n"); + return 0; + } + + if(type == BATMON_SENSOR_TYPE_TEMP) { + return (int)ti_lib_aon_batmon_temperature_get_deg_c(); + } else if(type == BATMON_SENSOR_TYPE_VOLT) { + return (int)ti_lib_aon_batmon_battery_voltage_get(); + } else { + PRINTF("Invalid type\n"); + } + + return 0; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Configuration function for the battery monitor sensor. + * + * \param type Activate, enable or disable the sensor. See below + * \param enable If + * + * When type == SENSORS_HW_INIT we turn on the hardware + * When type == SENSORS_ACTIVE and enable==1 we enable the sensor + * When type == SENSORS_ACTIVE and enable==0 we disable the sensor + */ +static int +configure(int type, int enable) +{ + switch(type) { + case SENSORS_HW_INIT: + ti_lib_aon_batmon_enable(); + enabled = SENSOR_STATUS_ENABLED; + break; + case SENSORS_ACTIVE: + if(enable) { + ti_lib_aon_batmon_enable(); + enabled = SENSOR_STATUS_ENABLED; + } else { + ti_lib_aon_batmon_disable(); + enabled = SENSOR_STATUS_DISABLED; + } + break; + default: + break; + } + return enabled; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Returns the status of the sensor + * \param type SENSORS_ACTIVE or SENSORS_READY + * \return 1 if the sensor is enabled + */ +static int +status(int type) +{ + switch(type) { + case SENSORS_ACTIVE: + case SENSORS_READY: + return enabled; + break; + default: + break; + } + return SENSOR_STATUS_DISABLED; +} +/*---------------------------------------------------------------------------*/ +SENSORS_SENSOR(batmon_sensor, "Battery Monitor", value, configure, status); +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13x2-cc26x2/launchpad/button-sensor-arch.h b/arch/cpu/cc13xx-cc26xx/dev/batmon-sensor.h similarity index 79% rename from arch/platform/simplelink/cc13x2-cc26x2/launchpad/button-sensor-arch.h rename to arch/cpu/cc13xx-cc26xx/dev/batmon-sensor.h index ecd04e8b6..014e9a17d 100644 --- a/arch/platform/simplelink/cc13x2-cc26x2/launchpad/button-sensor-arch.h +++ b/arch/cpu/cc13xx-cc26xx/dev/batmon-sensor.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,28 +29,27 @@ */ /*---------------------------------------------------------------------------*/ /** - * \addtogroup simplelink-platform + * \addtogroup cc26xx * @{ * - * \defgroup simplelink-button-sensor Simplelink Button Driver + * \defgroup cc26xx-batmon CC13xx/CC26xx BatMon sensor driver * - * One of the buttons can be configured as general purpose or as an on/off key + * Driver for the on-chip battery voltage and chip temperature sensor. * @{ * * \file - * Header file for the Simplelink Button Driver + * Header file for the CC13xx/CC26xx battery monitor */ /*---------------------------------------------------------------------------*/ -#ifndef BUTTON_SENSOR_ARCH_H_ -#define BUTTON_SENSOR_ARCH_H_ +#ifndef BATMON_SENSOR_H_ +#define BATMON_SENSOR_H_ /*---------------------------------------------------------------------------*/ -/* Contiki API */ -#include +#define BATMON_SENSOR_TYPE_TEMP 1 +#define BATMON_SENSOR_TYPE_VOLT 2 /*---------------------------------------------------------------------------*/ -extern const struct sensors_sensor btn1_sensor; -extern const struct sensors_sensor btn2_sensor; +extern const struct sensors_sensor batmon_sensor; /*---------------------------------------------------------------------------*/ -#endif /* BUTTON_SENSOR_ARCH_H_ */ +#endif /* BATMON_SENSOR_H_ */ /*---------------------------------------------------------------------------*/ /** * @} diff --git a/arch/cpu/cc13xx-cc26xx/dev/clock-arch.c b/arch/cpu/cc13xx-cc26xx/dev/clock-arch.c index 8869dc734..784530de9 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/clock-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/clock-arch.c @@ -43,13 +43,14 @@ * Software clock implementation for the TI CC13xx/CC26xx */ /*---------------------------------------------------------------------------*/ -#include -#include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/aon_rtc.h) +#include DeviceFamily_constructPath(driverlib/cpu.h) +#include DeviceFamily_constructPath(driverlib/interrupt.h) +#include DeviceFamily_constructPath(driverlib/prcm.h) +#include DeviceFamily_constructPath(driverlib/timer.h) #include #include -#include #include "contiki.h" @@ -75,21 +76,26 @@ clock_init(void) CCIF clock_time_t clock_time(void) { - uintptr_t hwiState = HwiP_disable(); - clock_time_t result = count; - HwiP_restore(hwiState); + uint64_t count_read; + { + const uintptr_t key = HwiP_disable(); + count_read = count; + HwiP_restore(key); + } - return (clock_time_t)(result & 0xFFFFFFFF); + return (clock_time_t)(count_read & 0xFFFFFFFF); } /*---------------------------------------------------------------------------*/ static void clock_update(void) { - uintptr_t hwiState = HwiP_disable(); - count++; - HwiP_restore(hwiState); + { + const uintptr_t key = HwiP_disable(); + count += 1; + HwiP_restore(key); + } - if(etimer_pending()) { + if (etimer_pending()) { etimer_request_poll(); } } @@ -97,26 +103,33 @@ clock_update(void) CCIF unsigned long clock_seconds(void) { - uintptr_t hwiState = HwiP_disable(); - unsigned long result = count / CLOCK_SECOND; - HwiP_restore(hwiState); + uint64_t count_read; + { + const uintptr_t key = HwiP_disable(); + count_read = count; + HwiP_restore(key); + } - return result; + return (unsigned long)count_read / CLOCK_SECOND; } /*---------------------------------------------------------------------------*/ void clock_wait(clock_time_t i) { - clock_time_t start; - - start = clock_time(); + const clock_time_t start = clock_time(); while(clock_time() - start < (clock_time_t)i); } /*---------------------------------------------------------------------------*/ void clock_delay_usec(uint16_t len) { - usleep(len); + // See driverlib/cpu.h + const uint32_t cpu_clock_mhz = 48; + // Code in flash, cache disabled: 7 cycles per loop + const uint32_t cycles_per_loop = 7; + // ui32Count = [delay in us] * [CPU clock in MHz] / [cycles per loop] + const uint32_t count = (uint32_t)len * cpu_clock_mhz / cycles_per_loop; + CPUdelay(count); } /*---------------------------------------------------------------------------*/ /** diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c index 942c9d343..4c7fd69f6 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c @@ -123,20 +123,20 @@ #ifdef TX_POWER_CONF_DRIVER # define TX_POWER_DRIVER TX_POWER_CONF_DRIVER #else -# define TX_POWER_DRIVER RF_ieeeTxPower +# define TX_POWER_DRIVER txPowerTable #endif #ifdef TX_POWER_CONF_COUNT # define TX_POWER_COUNT TX_POWER_CONF_COUNT #else -# define TX_POWER_COUNT RF_ieeeTxPowerLen +# define TX_POWER_COUNT txPowerTableLen #endif /*---------------------------------------------------------------------------*/ /* TX power convenience macros */ -static RF_TxPower * const g_pTxPower = TX_POWER_DRIVER; +static RF_TxPowerTable_Entry * const g_pTxPower = TX_POWER_DRIVER; -#define TX_POWER_MAX (g_pTxPower[0]) -#define TX_POWER_MIN (g_pTxPower[(TX_POWER_COUNT) - 1]) +#define TX_POWER_MIN (g_pTxPower[0]) +#define TX_POWER_MAX (g_pTxPower[(TX_POWER_COUNT) - 1]) #define TX_POWER_IN_RANGE(dbm) (((dbm) >= TX_POWER_MIN) && ((dbm) <= TX_POWER_MAX)) /*---------------------------------------------------------------------------*/ @@ -426,31 +426,14 @@ set_channel(uint8_t channel) static int set_tx_power(const radio_value_t dbm) { - g_pCurrTxPower = NULL; - if (dbm > TX_POWER_MAX.dbm) { - g_pCurrTxPower = &TX_POWER_MAX; - } else { - size_t i; - for (i = 0; g_pTxPower[i + 1].power != TX_POWER_UNKNOWN; ++i) { - if (dbm > g_pTxPower[i + 1].dbm) { - break; - } - } - g_pCurrTxPower = &g_pTxPower[i + 1]; - } - - if (!g_pCurrTxPower) { + const RF_TxPowerTable_Value txPowerTableValue = RF_TxPowerTable_findValue(txPowerTable, (int8_t)dbm); + if (txPowerTableValue.rawValue == RF_TxPowerTable_INVALID_VALUE) { return CMD_RESULT_ERROR; } - rfc_CMD_SET_TX_POWER_t cmdSetTxPower = { - .commandNo = CMD_SET_TX_POWER, - .txPower = g_pCurrTxPower->power, - }; - - const RF_Stat stat = RF_runImmediateCmd(g_rfHandle, (uint32_t*)&cmdSetTxPower); - if (stat != RF_StatCmdDoneSuccess) { - PRINTF("set_tx_power: stat=0x%02X\n", stat); + const RF_Stat stat = RF_setTxPower(g_rfHandle, txPowerTableValue); + if (stat != RF_StatSuccess) { + PRINTF("RF_setTxPower: stat=0x%02X\n", stat); return CMD_RESULT_ERROR; } return CMD_RESULT_OK; @@ -930,11 +913,11 @@ get_value(radio_param_t param, radio_value_t *value) return RADIO_RESULT_OK; case RADIO_CONST_TXPOWER_MIN: - *value = (radio_value_t)(TX_POWER_MIN.dbm); + *value = (radio_value_t)(TX_POWER_MIN.power); return RADIO_RESULT_OK; case RADIO_CONST_TXPOWER_MAX: - *value = (radio_value_t)(TX_POWER_MAX.dbm); + *value = (radio_value_t)(TX_POWER_MAX.power); return RADIO_RESULT_OK; case RADIO_PARAM_LAST_RSSI: @@ -1037,7 +1020,7 @@ set_value(radio_param_t param, radio_value_t value) return RADIO_RESULT_OK; case RADIO_PARAM_TXPOWER: - if(value < TX_POWER_MIN.dbm || value > TX_POWER_MAX.dbm) { + if(value < TX_POWER_MIN.power || value > TX_POWER_MAX.power) { return RADIO_RESULT_INVALID_VALUE; } return (set_tx_power(value) != CMD_RESULT_OK) diff --git a/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c b/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c new file mode 100644 index 000000000..6a0042618 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2017, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + + +//***************************************************************************** +// +// Check if compiler is GNU Compiler +// +//***************************************************************************** +#if !(defined(__GNUC__)) +#error "startup_cc13xx_cc26xx_gcc.c: Unsupported compiler!" +#endif + +#include + +#include +#include DeviceFamily_constructPath(inc/hw_types.h) +#include DeviceFamily_constructPath(driverlib/interrupt.h) +#include DeviceFamily_constructPath(driverlib/setup.h) + +//***************************************************************************** +// +// Forward declaration of the default fault handlers. +// +//***************************************************************************** +void resetISR(void); +static void nmiISR(void); +static void faultISR(void); +static void defaultHandler(void); +static void busFaultHandler(void); + +//***************************************************************************** +// +// External declaration for the reset handler that is to be called when the +// processor is started +// +//***************************************************************************** +extern void _c_int00(void); + +//***************************************************************************** +// +// The entry point for the application. +// +//***************************************************************************** +extern int main(void); + +//***************************************************************************** +// +// linker variable that marks the top of stack. +// +//***************************************************************************** +extern unsigned long _stack_end; + +//***************************************************************************** +// +// The vector table. Note that the proper constructs must be placed on this to +// ensure that it ends up at physical address 0x0000.0000. +// +//***************************************************************************** +__attribute__ ((section(".resetVecs"))) __attribute__ ((used)) +static void (* const resetVectors[16])(void) = +{ + (void (*)(void))((uint32_t)&_stack_end), + // The initial stack pointer + resetISR, // The reset handler + nmiISR, // The NMI handler + faultISR, // The hard fault handler + defaultHandler, // The MPU fault handler + busFaultHandler, // The bus fault handler + defaultHandler, // The usage fault handler + 0, // Reserved + 0, // Reserved + 0, // Reserved + 0, // Reserved + defaultHandler, // SVCall handler + defaultHandler, // Debug monitor handler + 0, // Reserved + defaultHandler, // The PendSV handler + defaultHandler // The SysTick handler +}; + +__attribute__ ((section(".ramVecs"))) +static unsigned long ramVectors[50]; + +//***************************************************************************** +// +// The following are arrays of pointers to constructor functions that need to +// be called during startup to initialize global objects. +// +//***************************************************************************** +extern void (*__init_array_start []) (void); +extern void (*__init_array_end []) (void); + +//***************************************************************************** +// +// The following global variable is required for C++ support. +// +//***************************************************************************** +void * __dso_handle = (void *) &__dso_handle; + +//***************************************************************************** +// +// The following are constructs created by the linker, indicating where the +// the "data" and "bss" segments reside in memory. The initializers for the +// for the "data" segment resides immediately following the "text" segment. +// +//***************************************************************************** +extern uint32_t __bss_start__, __bss_end__; +extern uint32_t __data_load__, __data_start__, __data_end__; + +// +//***************************************************************************** +// +// Initialize the .data and .bss sections and copy the first 16 vectors from +// the read-only/reset table to the runtime RAM table. Fill the remaining +// vectors with a stub. This vector table will be updated at runtime. +// +//***************************************************************************** +// +void localProgramStart(void) +{ + uint32_t * bs; + uint32_t * be; + uint32_t * dl; + uint32_t * ds; + uint32_t * de; + uint32_t count; + uint32_t i; + +#if defined (__ARM_ARCH_7EM__) && defined(__VFP_FP__) && !defined(__SOFTFP__) + volatile uint32_t * pui32Cpacr = (uint32_t *) 0xE000ED88; + + /* Enable Coprocessor Access Control (CPAC) */ + *pui32Cpacr |= (0xF << 20); +#endif + + IntMasterDisable(); + + /* Final trim of device */ + SetupTrimDevice(); + + /* initiailize .bss to zero */ + bs = & __bss_start__; + be = & __bss_end__; + while (bs < be) { + *bs = 0; + bs++; + } + + /* relocate the .data section */ + dl = & __data_load__; + ds = & __data_start__; + de = & __data_end__; + if (dl != ds) { + while (ds < de) { + *ds = *dl; + dl++; + ds++; + } + } + + /* Run any constructors */ + count = (uint32_t)(__init_array_end - __init_array_start); + for (i = 0; i < count; i++) { + __init_array_start[i](); + } + + /* Copy from reset vector table into RAM vector table */ + memcpy(ramVectors, resetVectors, 16*4); + + /* fill remaining vectors with default handler */ + for (i=16; i < 50; i++) { + ramVectors[i] = (unsigned long)defaultHandler; + } + + /* Call the application's entry point. */ + main(); + + /* If we ever return signal Error */ + faultISR(); +} + +//***************************************************************************** +// +// This is the code that gets called when the processor first starts execution +// following a reset event. Only the absolutely necessary set is performed, +// after which the application supplied entry() routine is called. Any fancy +// actions (such as making decisions based on the reset cause register, and +// resetting the bits in that register) are left solely in the hands of the +// application. +// +//***************************************************************************** +void __attribute__((naked)) resetISR(void) +{ + __asm__ __volatile__ ( + " movw r0, #:lower16:resetVectors\n" + " movt r0, #:upper16:resetVectors\n" + " ldr r0, [r0]\n" + " mov sp, r0\n" + " bl localProgramStart" + ); +} + +//***************************************************************************** +// +// This is the code that gets called when the processor receives a NMI. This +// simply enters an infinite loop, preserving the system state for examination +// by a debugger. +// +//***************************************************************************** +static void +nmiISR(void) +{ + /* Enter an infinite loop. */ + while(1) + { + } +} + +//***************************************************************************** +// +// This is the code that gets called when the processor receives a fault +// interrupt. This simply enters an infinite loop, preserving the system state +// for examination by a debugger. +// +//***************************************************************************** +static void +faultISR(void) +{ + /* Enter an infinite loop. */ + while(1) + { + } +} + +//***************************************************************************** +// +// This is the code that gets called when the processor receives an unexpected +// interrupt. This simply enters an infinite loop, preserving the system state +// for examination by a debugger. +// +//***************************************************************************** + +static void +busFaultHandler(void) +{ + /* Enter an infinite loop. */ + while(1) + { + } +} + +//***************************************************************************** +// +// This is the code that gets called when the processor receives an unexpected +// interrupt. This simply enters an infinite loop, preserving the system state +// for examination by a debugger. +// +//***************************************************************************** +static void +defaultHandler(void) +{ + /* Enter an infinite loop. */ + while(1) + { + } +} + +//***************************************************************************** +// +// This function is called by __libc_fini_array which gets called when exit() +// is called. In order to support exit(), an empty _fini() stub function is +// required. +// +//***************************************************************************** +void _fini(void) +{ + /* Function body left empty intentionally */ +} diff --git a/arch/cpu/cc13xx-cc26xx/dev/ti-lib-rom.h b/arch/cpu/cc13xx-cc26xx/dev/ti-lib-rom.h new file mode 100644 index 000000000..cd019ce01 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/dev/ti-lib-rom.h @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2016, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup cc26xx-ti-lib + * @{ + * + * \file + * Header file with CC13xxware/CC26xxware ROM API. + */ +/*---------------------------------------------------------------------------*/ +#ifndef TI_LIB_ROM_H_ +#define TI_LIB_ROM_H_ +/*---------------------------------------------------------------------------*/ +/* rom.h */ +#include +#include DeviceFamily_constructPath(driverlib/rom.h) + +/* AON API */ +#define ti_lib_rom_aon_event_mcu_wake_up_set ROM_AONEventMcuWakeUpSet +#define ti_lib_rom_aon_event_mcu_wake_up_get ROM_AONEventMcuWakeUpGet +#define ti_lib_rom_aon_event_aux_wake_up_set ROM_AONEventAuxWakeUpSet +#define ti_lib_rom_aon_event_aux_wake_up_get ROM_AONEventAuxWakeUpGet +#define ti_lib_rom_aon_event_mcu_set ROM_AONEventMcuSet +#define ti_lib_rom_aon_event_mcu_get ROM_AONEventMcuGet + +/* AON_WUC API */ +#define ti_lib_rom_aon_wuc_aux_reset ROM_AONWUCAuxReset +#define ti_lib_rom_aon_wuc_recharge_ctrl_config_set ROM_AONWUCRechargeCtrlConfigSet +#define ti_lib_rom_aon_wuc_osc_config ROM_AONWUCOscConfig + +/* AUX_TDC API */ +#define ti_lib_rom_aux_tdc_config_set ROM_AUXTDCConfigSet +#define ti_lib_rom_aux_tdc_measurement_done ROM_AUXTDCMeasurementDone + +/* AUX_WUC API */ +#define ti_lib_rom_aux_wuc_clock_enable ROM_AUXWUCClockEnable +#define ti_lib_rom_aux_wuc_clock_disable ROM_AUXWUCClockDisable +#define ti_lib_rom_aux_wuc_clock_status ROM_AUXWUCClockStatus +#define ti_lib_rom_aux_wuc_power_ctrl ROM_AUXWUCPowerCtrl + +/* FLASH API */ +#define ti_lib_rom_flash_power_mode_get ROM_FlashPowerModeGet +#define ti_lib_rom_flash_protection_set ROM_FlashProtectionSet +#define ti_lib_rom_flash_protection_get ROM_FlashProtectionGet +#define ti_lib_rom_flash_protection_save ROM_FlashProtectionSave +#define ti_lib_rom_flash_efuse_read_row ROM_FlashEfuseReadRow +#define ti_lib_rom_flash_disable_sectors_for_write ROM_FlashDisableSectorsForWrite + +/* I2C API */ +#define ti_lib_rom_i2c_master_init_exp_clk ROM_I2CMasterInitExpClk +#define ti_lib_rom_i2c_master_err ROM_I2CMasterErr + +/* INTERRUPT API */ +#define ti_lib_rom_int_priority_grouping_set ROM_IntPriorityGroupingSet +#define ti_lib_rom_int_priority_grouping_get ROM_IntPriorityGroupingGet +#define ti_lib_rom_int_priority_set ROM_IntPrioritySet +#define ti_lib_rom_int_priority_get ROM_IntPriorityGet +#define ti_lib_rom_int_enable ROM_IntEnable +#define ti_lib_rom_int_disable ROM_IntDisable +#define ti_lib_rom_int_pend_set ROM_IntPendSet +#define ti_lib_rom_int_pend_get ROM_IntPendGet +#define ti_lib_rom_int_pend_clear ROM_IntPendClear + +/* IOC API */ +#define ti_lib_rom_ioc_port_configure_set ROM_IOCPortConfigureSet +#define ti_lib_rom_ioc_port_configure_get ROM_IOCPortConfigureGet +#define ti_lib_rom_ioc_io_shutdown_set ROM_IOCIOShutdownSet +#define ti_lib_rom_ioc_io_mode_set ROM_IOCIOModeSet +#define ti_lib_rom_ioc_io_int_set ROM_IOCIOIntSet +#define ti_lib_rom_ioc_io_port_pull_set ROM_IOCIOPortPullSet +#define ti_lib_rom_ioc_io_hyst_set ROM_IOCIOHystSet +#define ti_lib_rom_ioc_io_input_set ROM_IOCIOInputSet +#define ti_lib_rom_ioc_io_slew_ctrl_set ROM_IOCIOSlewCtrlSet +#define ti_lib_rom_ioc_io_drv_strength_set ROM_IOCIODrvStrengthSet +#define ti_lib_rom_ioc_io_port_id_set ROM_IOCIOPortIdSet +#define ti_lib_rom_ioc_int_enable ROM_IOCIntEnable +#define ti_lib_rom_ioc_int_disable ROM_IOCIntDisable +#define ti_lib_rom_ioc_pin_type_gpio_input ROM_IOCPinTypeGpioInput +#define ti_lib_rom_ioc_pin_type_gpio_output ROM_IOCPinTypeGpioOutput +#define ti_lib_rom_ioc_pin_type_uart ROM_IOCPinTypeUart +#define ti_lib_rom_ioc_pin_type_ssi_master ROM_IOCPinTypeSsiMaster +#define ti_lib_rom_ioc_pin_type_ssi_slave ROM_IOCPinTypeSsiSlave +#define ti_lib_rom_ioc_pin_type_i2c ROM_IOCPinTypeI2c +#define ti_lib_rom_ioc_pin_type_aux ROM_IOCPinTypeAux + +/* PRCM API */ +#define ti_lib_rom_prcm_inf_clock_configure_set ROM_PRCMInfClockConfigureSet +#define ti_lib_rom_prcm_inf_clock_configure_get ROM_PRCMInfClockConfigureGet +#define ti_lib_rom_prcm_audio_clock_config_set ROM_PRCMAudioClockConfigSet +#define ti_lib_rom_prcm_power_domain_on ROM_PRCMPowerDomainOn +#define ti_lib_rom_prcm_power_domain_off ROM_PRCMPowerDomainOff +#define ti_lib_rom_prcm_peripheral_run_enable ROM_PRCMPeripheralRunEnable +#define ti_lib_rom_prcm_peripheral_run_disable ROM_PRCMPeripheralRunDisable +#define ti_lib_rom_prcm_peripheral_sleep_enable ROM_PRCMPeripheralSleepEnable +#define ti_lib_rom_prcm_peripheral_sleep_disable ROM_PRCMPeripheralSleepDisable +#define ti_lib_rom_prcm_peripheral_deep_sleep_enable ROM_PRCMPeripheralDeepSleepEnable +#define ti_lib_rom_prcm_peripheral_deep_sleep_disable ROM_PRCMPeripheralDeepSleepDisable +#define ti_lib_rom_prcm_power_domain_status ROM_PRCMPowerDomainStatus +#define ti_lib_rom_prcm_deep_sleep ROM_PRCMDeepSleep + +/* SMPH API */ +#define ti_lib_rom_smph_acquire ROM_SMPHAcquire + +/* SSI API */ +#define ti_lib_rom_ssi_config_set_exp_clk ROM_SSIConfigSetExpClk +#define ti_lib_rom_ssi_data_put ROM_SSIDataPut +#define ti_lib_rom_ssi_data_put_non_blocking ROM_SSIDataPutNonBlocking +#define ti_lib_rom_ssi_data_get ROM_SSIDataGet +#define ti_lib_rom_ssi_data_get_non_blocking ROM_SSIDataGetNonBlocking + +/* TIMER API */ +#define ti_lib_rom_timer_configure ROM_TimerConfigure +#define ti_lib_rom_timer_level_control ROM_TimerLevelControl +#define ti_lib_rom_timer_stall_control ROM_TimerStallControl +#define ti_lib_rom_timer_wait_on_trigger_control ROM_TimerWaitOnTriggerControl + +/* TRNG API */ +#define ti_lib_rom_trng_number_get ROM_TRNGNumberGet + +/* UART API */ +#define ti_lib_rom_uart_fifo_level_get ROM_UARTFIFOLevelGet +#define ti_lib_rom_uart_config_set_exp_clk ROM_UARTConfigSetExpClk +#define ti_lib_rom_uart_config_get_exp_clk ROM_UARTConfigGetExpClk +#define ti_lib_rom_uart_disable ROM_UARTDisable +#define ti_lib_rom_uart_char_get_non_blocking ROM_UARTCharGetNonBlocking +#define ti_lib_rom_uart_char_get ROM_UARTCharGet +#define ti_lib_rom_uart_char_put_non_blocking ROM_UARTCharPutNonBlocking +#define ti_lib_rom_uart_char_put ROM_UARTCharPut + +/* UDMA API */ +#define ti_lib_rom_udma_channel_attribute_enable ROM_uDMAChannelAttributeEnable +#define ti_lib_rom_udma_channel_attribute_disable ROM_uDMAChannelAttributeDisable +#define ti_lib_rom_udma_channel_attribute_get ROM_uDMAChannelAttributeGet +#define ti_lib_rom_udma_channel_control_set ROM_uDMAChannelControlSet +#define ti_lib_rom_udma_channel_transfer_set ROM_uDMAChannelTransferSet +#define ti_lib_rom_udma_channel_scatter_gather_set ROM_uDMAChannelScatterGatherSet +#define ti_lib_rom_udma_channel_size_get ROM_uDMAChannelSizeGet +#define ti_lib_rom_udma_channel_mode_get ROM_uDMAChannelModeGet + +/* VIMS API */ +#define ti_lib_rom_vims_configure ROM_VIMSConfigure +#define ti_lib_rom_vims_mode_set ROM_VIMSModeSet + +/* HAPI */ +#define ti_lib_hapi_crc32(a, b, c) HapiCrc32(a, b, c) +#define ti_lib_hapi_get_flash_size() HapiGetFlashSize() +#define ti_lib_hapi_get_chip_id() HapiGetChipId() +#define ti_lib_hapi_sector_erase(a) HapiSectorErase(a) +#define ti_lib_hapi_program_flash(a, b, c) HapiProgramFlash(a, b, c) +#define ti_lib_hapi_reset_device() HapiResetDevice() +#define ti_lib_hapi_fletcher32(a, b, c) HapiFletcher32(a, b, c) +#define ti_lib_hapi_min_value(a, b) HapiMinValue(a,b) +#define ti_lib_hapi_max_value(a, b) HapiMaxValue(a,b) +#define ti_lib_hapi_mean_value(a, b) HapiMeanValue(a,b) +#define ti_lib_hapi_stand_deviation_value(a, b) HapiStandDeviationValue(a,b) +#define ti_lib_hapi_hf_source_safe_switch() HapiHFSourceSafeSwitch() +#define ti_lib_hapi_select_comp_a_input(a) HapiSelectCompAInput(a) +#define ti_lib_hapi_select_comp_a_ref(a) HapiSelectCompARef(a) +#define ti_lib_hapi_select_adc_comp_b_input(a) HapiSelectADCCompBInput(a) +#define ti_lib_hapi_select_comp_b_ref(a) HapiSelectCompBRef(a) +/*---------------------------------------------------------------------------*/ +#endif /* TI_LIB_ROM_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/ti-lib.h b/arch/cpu/cc13xx-cc26xx/dev/ti-lib.h new file mode 100644 index 000000000..022a6543f --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/dev/ti-lib.h @@ -0,0 +1,578 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/** + * \addtogroup cc26xx + * @{ + * + * \defgroup cc26xx-ti-lib TI CC26xxware/CC13xxware Glue + * + * Glue file which renames TI CC26xxware functions. Thus, for example, + * PowerCtrlIOFreezeDisable() becomes power_ctrl_io_freeze_disable() + * + * This is not strictly required and a call to the former will work perfectly + * correctly. However, in using those macros, we make the core of the Contiki + * port match the naming convention. + * + * Since all functions are prefixed with ti_lib, it also becomes clear to the + * reader that this is a call to TI driverlib's sources and not a call to a + * function inside Contiki + * + * @{ + * + * \file + * Header file with macros which rename TI CC26xxware functions. + */ +#ifndef TI_LIB_H_ +#define TI_LIB_H +/*---------------------------------------------------------------------------*/ +/* For DeviceFamily_constructPath() */ +#include +/*---------------------------------------------------------------------------*/ +/* Include ROM API */ +#include "ti-lib-rom.h" +/*---------------------------------------------------------------------------*/ +/* aon_batmon.h */ +#include DeviceFamily_constructPath(driverlib/aon_batmon.h) + +#define ti_lib_aon_batmon_enable(...) AONBatMonEnable(__VA_ARGS__) +#define ti_lib_aon_batmon_disable(...) AONBatMonDisable(__VA_ARGS__) +#define ti_lib_aon_batmon_temperature_get_deg_c(...) AONBatMonTemperatureGetDegC(__VA_ARGS__) +#define ti_lib_aon_batmon_battery_voltage_get(...) AONBatMonBatteryVoltageGet(__VA_ARGS__) +#define ti_lib_aon_batmon_new_battery_measure_ready(...) AONBatMonNewBatteryMeasureReady(__VA_ARGS__) +#define ti_lib_aon_batmon_new_temp_measure_ready(...) AONBatMonNewTempMeasureReady(__VA_ARGS__) +/*---------------------------------------------------------------------------*/ +/* aon_event.h */ +#include DeviceFamily_constructPath(driverlib/aon_event.h) + +#define ti_lib_aon_event_mcu_wake_up_set(...) AONEventMcuWakeUpSet(__VA_ARGS__) +#define ti_lib_aon_event_mcu_wake_up_get(...) AONEventMcuWakeUpGet(__VA_ARGS__) +#define ti_lib_aon_event_aux_wake_up_set(...) AONEventAuxWakeUpSet(__VA_ARGS__) +#define ti_lib_aon_event_aux_wake_up_get(...) AONEventAuxWakeUpGet(__VA_ARGS__) +#define ti_lib_aon_event_mcu_set(...) AONEventMcuSet(__VA_ARGS__) +#define ti_lib_aon_event_mcu_get(...) AONEventMcuGet(__VA_ARGS__) +#define ti_lib_aon_event_rtc_set(...) AONEventRtcSet(__VA_ARGS__) +#define ti_lib_aon_event_rtc_get(...) AONEventRtcGet(__VA_ARGS__) +/*---------------------------------------------------------------------------*/ +/* aon_ioc.h */ +#include DeviceFamily_constructPath(driverlib/aon_ioc.h) + +#define ti_lib_aon_ioc_drive_strength_set(...) AONIOCDriveStrengthSet(__VA_ARGS__) +#define ti_lib_aon_ioc_drive_strength_get(...) AONIOCDriveStrengthGet(__VA_ARGS__) +#define ti_lib_aon_ioc_freeze_enable(...) AONIOCFreezeEnable(__VA_ARGS__) +#define ti_lib_aon_ioc_freeze_disable(...) AONIOCFreezeDisable(__VA_ARGS__) +#define ti_lib_aon_ioc_32_khz_output_disable(...) AONIOC32kHzOutputDisable(__VA_ARGS__) +#define ti_lib_aon_ioc_32_khz_output_enable(...) AONIOC32kHzOutputEnable(__VA_ARGS__) +/*---------------------------------------------------------------------------*/ +/* aon_rtc.h */ +#include DeviceFamily_constructPath(driverlib/aon_rtc.h) + +#define ti_lib_aon_rtc_enable(...) AONRTCEnable(__VA_ARGS__) +#define ti_lib_aon_rtc_disable(...) AONRTCDisable(__VA_ARGS__) +#define ti_lib_aon_rtc_active(...) AONRTCActive(__VA_ARGS__) +#define ti_lib_aon_rtc_channel_active(...) AONRTCChannelActive(__VA_ARGS__) +#define ti_lib_aon_rtc_reset(...) AONRTCReset(__VA_ARGS__) +#define ti_lib_aon_rtc_delay_config(...) AONRTCDelayConfig(__VA_ARGS__) +#define ti_lib_aon_rtc_combined_event_config(...) AONRTCCombinedEventConfig(__VA_ARGS__) +#define ti_lib_aon_rtc_event_clear(...) AONRTCEventClear(__VA_ARGS__) +#define ti_lib_aon_rtc_event_get(...) AONRTCEventGet(__VA_ARGS__) +#define ti_lib_aon_rtc_sec_get(...) AONRTCSecGet(__VA_ARGS__) +#define ti_lib_aon_rtc_fraction_get(...) AONRTCFractionGet(__VA_ARGS__) +#define ti_lib_aon_rtc_sub_sec_incr_get(...) AONRTCSubSecIncrGet(__VA_ARGS__) +#define ti_lib_aon_rtc_mode_ch1_set(...) AONRTCModeCh1Set(__VA_ARGS__) +#define ti_lib_aon_rtc_mode_ch1_get(...) AONRTCModeCh1Get(__VA_ARGS__) +#define ti_lib_aon_rtc_mode_ch2_set(...) AONRTCModeCh2Set(__VA_ARGS__) +#define ti_lib_aon_rtc_mode_ch2_get(...) AONRTCModeCh2Get(__VA_ARGS__) +#define ti_lib_aon_rtc_channel_enable(...) AONRTCChannelEnable(__VA_ARGS__) +#define ti_lib_aon_rtc_channel_disable(...) AONRTCChannelDisable(__VA_ARGS__) +#define ti_lib_aon_rtc_compare_value_set(...) AONRTCCompareValueSet(__VA_ARGS__) +#define ti_lib_aon_rtc_compare_value_get(...) AONRTCCompareValueGet(__VA_ARGS__) +#define ti_lib_aon_rtc_current_compare_value_get(...) AONRTCCurrentCompareValueGet(__VA_ARGS__) +#define ti_lib_aon_rtc_current_64_bit_value_get(...) AONRTCCurrent64BitValueGet(__VA_ARGS__) +#define ti_lib_aon_rtc_inc_value_ch2_set(...) AONRTCIncValueCh2Set(__VA_ARGS__) +#define ti_lib_aon_rtc_inc_value_ch2_get(...) AONRTCIncValueCh2Get(__VA_ARGS__) +#define ti_lib_aon_rtc_capture_value_ch1_get(...) AONRTCCaptureValueCh1Get(__VA_ARGS__) +/*---------------------------------------------------------------------------*/ +#if DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0 +/* aon_wuc.h */ +#include DeviceFamily_constructPath(driverlib/aon_wuc.h) + +#define ti_lib_aon_wuc_mcu_wake_up_config(...) AONWUCMcuWakeUpConfig(__VA_ARGS__) +#define ti_lib_aon_wuc_mcu_power_down_config(...) AONWUCMcuPowerDownConfig(__VA_ARGS__) +#define ti_lib_aon_wuc_mcu_power_off_config(...) AONWUCMcuPowerOffConfig(__VA_ARGS__) +#define ti_lib_aon_wuc_mcu_sram_config(...) AONWUCMcuSRamConfig(__VA_ARGS__) +#define ti_lib_aon_wuc_aux_clock_config_get(...) AONWUCAuxClockConfigGet(__VA_ARGS__) +#define ti_lib_aon_wuc_aux_power_down_config(...) AONWUCAuxPowerDownConfig(__VA_ARGS__) +#define ti_lib_aon_wuc_aux_wake_up_config(...) AONWUCAuxWakeUpConfig(__VA_ARGS__) +#define ti_lib_aon_wuc_aux_sram_config(...) AONWUCAuxSRamConfig(__VA_ARGS__) +#define ti_lib_aon_wuc_aux_wakeup_event(...) AONWUCAuxWakeupEvent(__VA_ARGS__) +#define ti_lib_aon_wuc_aux_image_valid(...) AONWUCAuxImageValid(__VA_ARGS__) +#define ti_lib_aon_wuc_aux_image_invalid(...) AONWUCAuxImageInvalid(__VA_ARGS__) +#define ti_lib_aon_wuc_aux_reset(...) AONWUCAuxReset(__VA_ARGS__) +#define ti_lib_aon_wuc_power_status_get(...) AONWUCPowerStatusGet(__VA_ARGS__) +#define ti_lib_aon_wuc_shut_down_enable(...) AONWUCShutDownEnable(__VA_ARGS__) +#define ti_lib_aon_wuc_domain_power_down_enable(...) AONWUCDomainPowerDownEnable(__VA_ARGS__) +#define ti_lib_aon_wuc_domain_power_down_disable(...) AONWUCDomainPowerDownDisable(__VA_ARGS__) +#define ti_lib_aon_wuc_mcu_reset_status_get(...) AONWUCMcuResetStatusGet(__VA_ARGS__) +#define ti_lib_aon_wuc_mcu_reset_clear(...) AONWUCMcuResetClear(__VA_ARGS__) +#define ti_lib_aon_wuc_recharge_ctrl_config_set(...) AONWUCRechargeCtrlConfigSet(__VA_ARGS__) +#define ti_lib_aon_wuc_recharge_ctrl_config_get(...) AONWUCRechargeCtrlConfigGet(__VA_ARGS__) +#define ti_lib_aon_wuc_osc_config(...) AONWUCOscConfig(__VA_ARGS__) +#define ti_lib_aon_wuc_jtag_power_off(...) AONWUCJtagPowerOff(__VA_ARGS__) + +#endif /* DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0 */ +/*---------------------------------------------------------------------------*/ +/* aux_adc.h */ +#include DeviceFamily_constructPath(driverlib/aux_adc.h) + +#define ti_lib_aux_adc_disable(...) AUXADCDisable(__VA_ARGS__) +#define ti_lib_aux_adc_enable_async(...) AUXADCEnableAsync(__VA_ARGS__) +#define ti_lib_aux_adc_enable_sync(...) AUXADCEnableSync(__VA_ARGS__) +#define ti_lib_aux_adc_disable_input_scaling(...) AUXADCDisableInputScaling(__VA_ARGS__) +#define ti_lib_aux_adc_flush_fifo(...) AUXADCFlushFifo(__VA_ARGS__) +#define ti_lib_aux_adc_gen_manual_trigger(...) AUXADCGenManualTrigger(__VA_ARGS__) +#define ti_lib_aux_adc_get_fifo_status(...) AUXADCGetFifoStatus(__VA_ARGS__) +#define ti_lib_aux_adc_read_fifo(...) AUXADCReadFifo(__VA_ARGS__) +#define ti_lib_aux_adc_pop_fifo(...) AUXADCPopFifo(__VA_ARGS__) +#define ti_lib_aux_adc_select_input(...) AUXADCSelectInput(__VA_ARGS__) +#define ti_lib_aux_adc_get_adjustment_gain(...) AUXADCGetAdjustmentGain(__VA_ARGS__) +#define ti_lib_aux_adc_get_adjustment_offset(...) AUXADCGetAdjustmentOffset(__VA_ARGS__) +#define ti_lib_aux_adc_value_to_microvolts(...) AUXADCValueToMicrovolts(__VA_ARGS__) +#define ti_lib_aux_adc_microvolts_to_value(...) AUXADCMicrovoltsToValue(__VA_ARGS__) +#define ti_lib_aux_adc_adjust_value_for_gain_and_offset(...) AUXADCAdjustValueForGainAndOffset(__VA_ARGS__) +#define ti_lib_aux_adc_unadjust_value_for_gain_and_offset(...) AUXADCUnadjustValueForGainAndOffset(__VA_ARGS__) +/*---------------------------------------------------------------------------*/ +#if DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0 +/* aux_wuc.h */ +#include DeviceFamily_constructPath(driverlib/aux_wuc.h) + +#define ti_lib_aux_wuc_clock_enable(...) AUXWUCClockEnable(__VA_ARGS__) +#define ti_lib_aux_wuc_clock_disable(...) AUXWUCClockDisable(__VA_ARGS__) +#define ti_lib_aux_wuc_clock_status(...) AUXWUCClockStatus(__VA_ARGS__) +#define ti_lib_aux_wuc_clock_freq_req(...) AUXWUCClockFreqReq(__VA_ARGS__) +#define ti_lib_aux_wuc_power_ctrl(...) AUXWUCPowerCtrl(__VA_ARGS__) +#define ti_lib_aux_wuc_freeze_enable(...) AUXWUCFreezeEnable(__VA_ARGS__) +#define ti_lib_aux_wuc_freeze_disable(...) AUXWUCFreezeDisable(__VA_ARGS__) + +#endif /* DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0 */ +/*---------------------------------------------------------------------------*/ +/* cpu.h */ +#include DeviceFamily_constructPath(driverlib/cpu.h) + +#define ti_lib_cpu_cpsid(...) CPUcpsid(__VA_ARGS__) +#define ti_lib_cpu_cpsie(...) CPUcpsie(__VA_ARGS__) +#define ti_lib_cpu_primask(...) CPUprimask(__VA_ARGS__) +#define ti_lib_cpu_wfi(...) CPUwfi(__VA_ARGS__) +#define ti_lib_cpu_wfe(...) CPUwfe(__VA_ARGS__) +#define ti_lib_cpu_sev(...) CPUsev(__VA_ARGS__) +#define ti_lib_cpu_base_pri_get(...) CPUbasepriGet(__VA_ARGS__) +#define ti_lib_cpu_base_pri_set(...) CPUbasepriSet(__VA_ARGS__) +#define ti_lib_cpu_delay(...) CPUdelay(__VA_ARGS__) +/*---------------------------------------------------------------------------*/ +/* chipinfo.h */ +#include DeviceFamily_constructPath(driverlib/chipinfo.h) + +#define ti_lib_chipinfo_get_supported_protocol_bv(...) ChipInfo_GetSupportedProtocol_BV(__VA_ARGS__) +#define ti_lib_chipinfo_supports_ble(...) ChipInfo_SupportsBLE(__VA_ARGS__) +#define ti_lib_chipinfo_supports_ieee_802_15_4(...) ChipInfo_SupportsIEEE_802_15_4(__VA_ARGS__) +#define ti_lib_chipinfo_supports_proprietary(...) ChipInfo_SupportsPROPRIETARY(__VA_ARGS__) +#define ti_lib_chipinfo_get_package_type(...) ChipInfo_GetPackageType(__VA_ARGS__) +#define ti_lib_chipinfo_package_type_is_4x4(...) ChipInfo_PackageTypeIs4x4(__VA_ARGS__) +#define ti_lib_chipinfo_package_type_is_5x5(...) ChipInfo_PackageTypeIs5x5(__VA_ARGS__) +#define ti_lib_chipinfo_package_type_is_7x7(...) ChipInfo_PackageTypeIs7x7(__VA_ARGS__) +#define ti_lib_chipinfo_get_device_id_hw_rev_code(...) ChipInfo_GetDeviceIdHwRevCode(__VA_ARGS__) +#define ti_lib_chipinfo_get_chip_type(...) ChipInfo_GetChipType(__VA_ARGS__) +#define ti_lib_chipinfo_get_chip_family(...) ChipInfo_GetChipFamily(__VA_ARGS__) +#define ti_lib_chipinfo_chip_family_is_cc13x0(...) ChipInfo_ChipFamilyIs_CC13x0(__VA_ARGS__) +#define ti_lib_chipinfo_chip_family_is_cc26x0(...) ChipInfo_ChipFamilyIs_CC26x0(__VA_ARGS__) +#define ti_lib_chipinfo_chip_family_is_cc26x0r2(...) ChipInfo_ChipFamilyIs_CC26x0R2(__VA_ARGS__) +#define ti_lib_chipinfo_chip_family_is_cc26x1(...) ChipInfo_ChipFamilyIs_CC26x1(__VA_ARGS__) +#define ti_lib_chipinfo_chip_family_is_cc13x2_cc26x2(...) ChipInfo_ChipFamilyIs_CC13x2_CC26x2(__VA_ARGS__) +#define ti_lib_chipinfo_get_hw_revision(...) ChipInfo_GetHwRevision(__VA_ARGS__) +#define ti_lib_chipinfo_hw_revision_is_1_0(...) ChipInfo_HwRevisionIs_1_0(__VA_ARGS__) +#define ti_lib_chipinfo_hw_revision_is_gteq_2_0(...) ChipInfo_HwRevisionIs_GTEQ_2_0(__VA_ARGS__) +#define ti_lib_chipinfo_hw_revision_is_2_0(...) ChipInfo_HwRevisionIs_2_0(__VA_ARGS__) +#define ti_lib_chipinfo_hw_revision_is_2_1(...) ChipInfo_HwRevisionIs_2_1(__VA_ARGS__) +#define ti_lib_chipinfo_hw_revision_is_2_2(...) ChipInfo_HwRevisionIs_2_2(__VA_ARGS__) +#define ti_lib_chipinfo_hw_revision_is_gteq_2_2(...) ChipInfo_HwRevisionIs_GTEQ_2_2( __VA_ARGS__ ) +/*---------------------------------------------------------------------------*/ +/* ddi.h */ +#include DeviceFamily_constructPath(driverlib/ddi.h) + +#define ti_lib_aux_adi_ddi_safe_write(...) AuxAdiDdiSafeWrite(__VA_ARGS__) +#define ti_lib_aux_adi_ddi_safe_read(...) AuxAdiDdiSafeRead(__VA_ARGS__) +#define ti_lib_ddi_32_reg_write(...) DDI32RegWrite(__VA_ARGS__) +#define ti_lib_ddi_32_reg_read(...) DDI32RegRead(__VA_ARGS__) +#define ti_lib_ddi_32_bits_set(...) DDI32BitsSet(__VA_ARGS__) +#define ti_lib_ddi_32_bits_clear(...) DDI32BitsClear(__VA_ARGS__) +#define ti_lib_ddi_8_set_val_bit(...) DDI8SetValBit(__VA_ARGS__) +#define ti_lib_ddi_16_set_val_bit(...) DDI16SetValBit(__VA_ARGS__) +#define ti_lib_ddi_16_bit_write(...) DDI16BitWrite(__VA_ARGS__) +#define ti_lib_ddi_16_bit_field_write(...) DDI16BitfieldWrite(__VA_ARGS__) +#define ti_lib_ddi_16_bit_read(...) DDI16BitRead(__VA_ARGS__) +#define ti_lib_ddi_16_bitfield_read(...) DDI16BitfieldRead(__VA_ARGS__) +/*---------------------------------------------------------------------------*/ +/* gpio.h */ +#include DeviceFamily_constructPath(driverlib/gpio.h) + +#define ti_lib_gpio_read_dio(...) GPIO_readDio(__VA_ARGS__) +#define ti_lib_gpio_read_multi_dio(...) GPIO_readMultiDio(__VA_ARGS__) +#define ti_lib_gpio_write_dio(...) GPIO_writeDio(__VA_ARGS__) +#define ti_lib_gpio_write_multi_dio(...) GPIO_writeMultiDio(__VA_ARGS__) +#define ti_lib_gpio_set_dio(...) GPIO_setDio(__VA_ARGS__) +#define ti_lib_gpio_set_multi_dio(...) GPIO_setMultiDio(__VA_ARGS__) +#define ti_lib_gpio_clear_dio(...) GPIO_clearDio(__VA_ARGS__) +#define ti_lib_gpio_clear_multi_dio(...) GPIO_clearMultiDio(__VA_ARGS__) +#define ti_lib_gpio_toggle_dio(...) GPIO_toggleDio(__VA_ARGS__) +#define ti_lib_gpio_toggle_multi_dio(...) GPIO_toggleMultiDio(__VA_ARGS__) +#define ti_lib_gpio_get_output_enable_dio(...) GPIO_getOutputEnableDio(__VA_ARGS__) +#define ti_lib_gpio_get_output_enable_multi_dio(...) GPIO_getOutputEnableMultiDio(__VA_ARGS__) +#define ti_lib_gpio_set_output_enable_dio(...) GPIO_setOutputEnableDio(__VA_ARGS__) +#define ti_lib_gpio_set_output_enable_multi_dio(...) GPIO_setOutputEnableMultiDio(__VA_ARGS__) +#define ti_lib_gpio_get_event_dio(...) GPIO_getEventDio(__VA_ARGS__) +#define ti_lib_gpio_get_event_multi_dio(...) GPIO_getEventMultiDio(__VA_ARGS__) +#define ti_lib_gpio_clear_event_dio(...) GPIO_clearEventDio(__VA_ARGS__) +#define ti_lib_gpio_clear_event_multi_dio(...) GPIO_clearEventMultiDio(__VA_ARGS__) +/*---------------------------------------------------------------------------*/ +/* i2c.h */ +#include DeviceFamily_constructPath(driverlib/i2c.h) + +#define ti_lib_i2c_int_register(...) I2CIntRegister(__VA_ARGS__) +#define ti_lib_i2c_int_unregister(...) I2CIntUnregister(__VA_ARGS__) +#define ti_lib_i2c_master_bus_busy(...) I2CMasterBusBusy(__VA_ARGS__) +#define ti_lib_i2c_master_busy(...) I2CMasterBusy(__VA_ARGS__) +#define ti_lib_i2c_master_control(...) I2CMasterControl(__VA_ARGS__) +#define ti_lib_i2c_master_data_get(...) I2CMasterDataGet(__VA_ARGS__) +#define ti_lib_i2c_master_data_put(...) I2CMasterDataPut(__VA_ARGS__) +#define ti_lib_i2c_master_disable(...) I2CMasterDisable(__VA_ARGS__) +#define ti_lib_i2c_master_enable(...) I2CMasterEnable(__VA_ARGS__) +#define ti_lib_i2c_master_err(...) I2CMasterErr(__VA_ARGS__) +#define ti_lib_i2c_master_init_exp_clk(...) I2CMasterInitExpClk(__VA_ARGS__) +#define ti_lib_i2c_master_int_clear(...) I2CMasterIntClear(__VA_ARGS__) +#define ti_lib_i2c_master_int_disable(...) I2CMasterIntDisable(__VA_ARGS__) +#define ti_lib_i2c_master_int_enable(...) I2CMasterIntEnable(__VA_ARGS__) +#define ti_lib_i2c_master_int_status(...) I2CMasterIntStatus(__VA_ARGS__) +#define ti_lib_i2c_master_slave_addr_set(...) I2CMasterSlaveAddrSet(__VA_ARGS__) +#define ti_lib_i2c_slave_data_get(...) I2CSlaveDataGet(__VA_ARGS__) +#define ti_lib_i2c_slave_data_put(...) I2CSlaveDataPut(__VA_ARGS__) +#define ti_lib_i2c_slave_disable(...) I2CSlaveDisable(__VA_ARGS__) +#define ti_lib_i2c_slave_enable(...) I2CSlaveEnable(__VA_ARGS__) +#define ti_lib_i2c_slave_init(...) I2CSlaveInit(__VA_ARGS__) +#define ti_lib_i2c_slave_address_set(...) I2CSlaveAddressSet(__VA_ARGS__) +#define ti_lib_i2c_slave_int_clear(...) I2CSlaveIntClear(__VA_ARGS__) +#define ti_lib_i2c_slave_int_disable(...) I2CSlaveIntDisable(__VA_ARGS__) +#define ti_lib_i2c_slave_int_enable(...) I2CSlaveIntEnable(__VA_ARGS__) +#define ti_lib_i2c_slave_int_status(...) I2CSlaveIntStatus(__VA_ARGS__) +#define ti_lib_i2c_slave_status(...) I2CSlaveStatus(__VA_ARGS__) +/*---------------------------------------------------------------------------*/ +/* interrupt.h */ +#include DeviceFamily_constructPath(driverlib/interrupt.h) + +#define ti_lib_int_master_enable(...) IntMasterEnable(__VA_ARGS__) +#define ti_lib_int_master_disable(...) IntMasterDisable(__VA_ARGS__) +#define ti_lib_int_register(...) IntRegister(__VA_ARGS__); +#define ti_lib_int_unregsiter(...) IntUnregister(__VA_ARGS__) +#define ti_lib_int_priority_grouping_set(...) IntPriorityGroupingSet(__VA_ARGS__) +#define ti_lib_int_priority_grouping_get(...) IntPriorityGroupingGet(__VA_ARGS__) +#define ti_lib_int_priority_set(...) IntPrioritySet(__VA_ARGS__) +#define ti_lib_int_priority_get(...) IntPriorityGet(__VA_ARGS__) +#define ti_lib_int_enable(...) IntEnable(__VA_ARGS__) +#define ti_lib_int_disable(...) IntDisable(__VA_ARGS__) +#define ti_lib_int_pend_set(...) IntPendSet(__VA_ARGS__) +#define ti_lib_int_pend_get(...) IntPendGet(__VA_ARGS__) +#define ti_lib_int_pend_clear(...) IntPendClear(__VA_ARGS__) +#define ti_lib_int_mask_set(...) IntPriorityMaskSet(__VA_ARGS__) +#define ti_lib_int_mask_get(...) IntPriorityMaskGet(__VA_ARGS__) +/*---------------------------------------------------------------------------*/ +/* ioc.h */ +#include DeviceFamily_constructPath(driverlib/ioc.h) + +#define ti_lib_ioc_port_configure_set(...) IOCPortConfigureSet(__VA_ARGS__) +#define ti_lib_ioc_port_configure_get(...) IOCPortConfigureGet(__VA_ARGS__) +#define ti_lib_ioc_io_shutdown_set(...) IOCIOShutdownSet(__VA_ARGS__) +#define ti_lib_ioc_io_mode_set(...) IOCIOModeSet(__VA_ARGS__) +#define ti_lib_ioc_io_port_pull_set(...) IOCIOPortPullSet(__VA_ARGS__) +#define ti_lib_ioc_io_hyst_set(...) IOCIOHystSet(__VA_ARGS__) +#define ti_lib_ioc_io_input_set(...) IOCIOInputSet(__VA_ARGS__) +#define ti_lib_ioc_io_slew_ctrl_set(...) IOCIOSlewCtrlSet(__VA_ARGS__) +#define ti_lib_ioc_io_drv_strength_set(...) IOCIODrvStrengthSet(__VA_ARGS__) +#define ti_lib_ioc_io_port_id_set(...) IOCIOPortIdSet(__VA_ARGS__) +#define ti_lib_ioc_io_int_set(...) IOCIOIntSet(__VA_ARGS__) +#define ti_lib_ioc_int_register(...) IOCIntRegister(__VA_ARGS__); +#define ti_lib_ioc_int_unregister(...) IOCIntUnregister(__VA_ARGS__) +#define ti_lib_ioc_int_enable(...) IOCIntEnable(__VA_ARGS__) +#define ti_lib_ioc_int_disable(...) IOCIntDisable(__VA_ARGS__) +#define ti_lib_ioc_int_clear(...) IOCIntClear(__VA_ARGS__) +#define ti_lib_ioc_int_status(...) IOCIntStatus(__VA_ARGS__) +#define ti_lib_ioc_pin_type_gpio_input(...) IOCPinTypeGpioInput(__VA_ARGS__) +#define ti_lib_ioc_pin_type_gpio_output(...) IOCPinTypeGpioOutput(__VA_ARGS__) +#define ti_lib_ioc_pin_type_uart(...) IOCPinTypeUart(__VA_ARGS__) +#define ti_lib_ioc_pin_type_ssi_master(...) IOCPinTypeSsiMaster(__VA_ARGS__) +#define ti_lib_ioc_pin_type_ssi_slave(...) IOCPinTypeSsiSlave(__VA_ARGS__) +#define ti_lib_ioc_pin_type_i2c(...) IOCPinTypeI2c(__VA_ARGS__) +#define ti_lib_ioc_pin_type_aux(...) IOCPinTypeAux(__VA_ARGS__) +#define ti_lib_ioc_pin_type_spis(...) IOCPinTypeSpis(__VA_ARGS__) +/*---------------------------------------------------------------------------*/ +/* osc.h */ +#include DeviceFamily_constructPath(driverlib/osc.h) + +#define ti_lib_osc_xhf_power_mode_set(...) OSCXHfPowerModeSet(__VA_ARGS__) +#define ti_lib_osc_clock_loss_event_enable(...) OSCClockLossEventEnable(__VA_ARGS__) +#define ti_lib_osc_clock_loss_event_disable(...) OSCClockLossEventDisable(__VA_ARGS__) +#define ti_lib_osc_clock_source_set(...) OSCClockSourceSet(__VA_ARGS__) +#define ti_lib_osc_clock_source_get(...) OSCClockSourceGet(__VA_ARGS__) +#define ti_lib_osc_hf_source_ready(...) OSCHfSourceReady(__VA_ARGS__) +#define ti_lib_osc_hf_source_switch(...) OSCHfSourceSwitch(__VA_ARGS__) +#define ti_lib_osc_hf_get_startup_time(...) OSCHF_GetStartupTime(__VA_ARGS__) +#define ti_lib_osc_hf_turn_on_xosc(...) OSCHF_TurnOnXosc(__VA_ARGS__) +#define ti_lib_osc_hf_attempt_to_switch_to_xosc(...) OSCHF_AttemptToSwitchToXosc(__VA_ARGS__) +#define ti_lib_osc_hf_debug_get_crystal_amplitude(...) OSCHF_DebugGetCrystalAmplitude(__VA_ARGS__) +#define ti_lib_osc_hf_debug_get_expected_average_crystal_amplitude(...) \ + OSCHF_DebugGetExpectedAverageCrystalAmplitude(__VA_ARGS__) +#define ti_lib_osc_hposc_relative_frequency_offset_get(...) OSC_HPOSCRelativeFrequencyOffsetGet(__VA_ARGS__) +#define ti_lib_osc_hposc_relative_frequency_offset_to_rf_core_format_convert(...) \ + OSC_HPOSCRelativeFrequencyOffsetToRFCoreFormatConvert(__VA_ARGS__) +#define ti_lib_osc_hf_switch_to_rc_osc_turn_off_xosc(...) OSCHF_SwitchToRcOscTurnOffXosc(__VA_ARGS__) +/*---------------------------------------------------------------------------*/ +/* prcm.h */ +#include DeviceFamily_constructPath(driverlib/prcm.h) + +#define ti_lib_prcm_inf_clock_configure_set(...) PRCMInfClockConfigureSet(__VA_ARGS__) +#define ti_lib_prcm_inf_clock_configure_get(...) PRCMInfClockConfigureGet(__VA_ARGS__) +#define ti_lib_prcm_mcu_power_off(...) PRCMMcuPowerOff(__VA_ARGS__) +#define ti_lib_prcm_mcu_power_off_cancel(...) PRCMMcuPowerOffCancel(__VA_ARGS__) +#define ti_lib_prcm_mcu_uldo_configure(...) PRCMMcuUldoConfigure(__VA_ARGS__) +#define ti_lib_prcm_audio_clock_enable(...) PRCMAudioClockEnable(__VA_ARGS__) +#define ti_lib_prcm_audio_clock_disable(...) PRCMAudioClockDisable(__VA_ARGS__) +#define ti_lib_prcm_audio_clock_config_set(...) PRCMAudioClockConfigSet(__VA_ARGS__) +#define ti_lib_prcm_load_set(...) PRCMLoadSet(__VA_ARGS__) +#define ti_lib_prcm_load_get(...) PRCMLoadGet(__VA_ARGS__) +#define ti_lib_prcm_domain_enable(...) PRCMDomainEnable(__VA_ARGS__) +#define ti_lib_prcm_domain_disable(...) PRCMDomainDisable(__VA_ARGS__) +#define ti_lib_prcm_power_domain_on(...) PRCMPowerDomainOn(__VA_ARGS__) +#define ti_lib_prcm_power_domain_off(...) PRCMPowerDomainOff(__VA_ARGS__) +#define ti_lib_prcm_rf_power_down_when_idle(...) PRCMRfPowerDownWhenIdle(__VA_ARGS__) +#define ti_lib_prcm_peripheral_run_enable(...) PRCMPeripheralRunEnable(__VA_ARGS__) +#define ti_lib_prcm_peripheral_run_disable(...) PRCMPeripheralRunDisable(__VA_ARGS__) +#define ti_lib_prcm_peripheral_sleep_enable(...) PRCMPeripheralSleepEnable(__VA_ARGS__) +#define ti_lib_prcm_peripheral_sleep_disable(...) PRCMPeripheralSleepDisable(__VA_ARGS__) +#define ti_lib_prcm_peripheral_deep_sleep_enable(...) PRCMPeripheralDeepSleepEnable(__VA_ARGS__) +#define ti_lib_prcm_peripheral_deep_sleep_disable(...) PRCMPeripheralDeepSleepDisable(__VA_ARGS__) +#define ti_lib_prcm_power_domain_status(...) PRCMPowerDomainStatus(__VA_ARGS__) +#define ti_lib_prcm_rf_ready(...) PRCMRfReady(__VA_ARGS__) +#define ti_lib_prcm_sleep(...) PRCMSleep(__VA_ARGS__) +#define ti_lib_prcm_deep_sleep(...) PRCMDeepSleep(__VA_ARGS__) +#define ti_lib_prcm_cache_retention_enable(...) PRCMCacheRetentionEnable(__VA_ARGS__) +#define ti_lib_prcm_cache_retention_disable(...) PRCMCacheRetentionDisable(__VA_ARGS__) +/*---------------------------------------------------------------------------*/ +/* sys_ctrl.h */ +#include DeviceFamily_constructPath(driverlib/pwr_ctrl.h) + +#define ti_lib_pwr_ctrl_state_set(...) PowerCtrlStateSet(__VA_ARGS__) +#define ti_lib_pwr_ctrl_source_set(...) PowerCtrlSourceSet(__VA_ARGS__) +#define ti_lib_pwr_ctrl_source_get(...) PowerCtrlSourceGet(__VA_ARGS__) +#define ti_lib_pwr_ctrl_reset_source_get(...) PowerCtrlResetSourceGet(__VA_ARGS__) +#define ti_lib_pwr_ctrl_reset_source_clear(...) PowerCtrlResetSourceClear(__VA_ARGS__) +#define ti_lib_pwr_ctrl_io_freeze_enable(...) PowerCtrlIOFreezeEnable(__VA_ARGS__) +#define ti_lib_pwr_ctrl_io_freeze_disable(...) PowerCtrlIOFreezeDisable(__VA_ARGS__) +/*---------------------------------------------------------------------------*/ +/* rfc.h */ +#include DeviceFamily_constructPath(driverlib/rfc.h) + +#define ti_lib_rfc_rtrim(...) RFCRTrim(__VA_ARGS__) +#define ti_lib_rfc_adi3vco_ldo_voltage_mode(...) RFCAdi3VcoLdoVoltageMode(__VA_ARGS__) +/*---------------------------------------------------------------------------*/ +/* sys_ctrl.h */ +#include DeviceFamily_constructPath(driverlib/sys_ctrl.h) + +#define ti_lib_sys_ctrl_power_everything(...) SysCtrlPowerEverything(__VA_ARGS__) +#define ti_lib_sys_ctrl_powerdown(...) SysCtrlPowerdown(__VA_ARGS__) +#define ti_lib_sys_ctrl_standby(...) SysCtrlStandby(__VA_ARGS__) +#define ti_lib_sys_ctrl_shutdown(...) SysCtrlShutdown(__VA_ARGS__) +#define ti_lib_sys_ctrl_clock_get(...) SysCtrlClockGet(__VA_ARGS__) +#define ti_lib_sys_ctrl_aon_sync(...) SysCtrlAonSync(__VA_ARGS__) +#define ti_lib_sys_ctrl_aon_update(...) SysCtrlAonUpdate(__VA_ARGS__) +#define ti_lib_sys_ctrl_set_recharge_before_power_down(...) SysCtrlSetRechargeBeforePowerDown(__VA_ARGS__) +#define ti_lib_sys_ctrl_adjust_recharge_after_power_down(...) SysCtrlAdjustRechargeAfterPowerDown(__VA_ARGS__) +#define ti_lib_sys_ctrl_dcdc_voltage_conditional_control(...) SysCtrl_DCDC_VoltageConditionalControl(__VA_ARGS__) +#define ti_lib_sys_ctrl_reset_source_get(...) SysCtrlResetSourceGet(__VA_ARGS__) +#define ti_lib_sys_ctrl_system_reset(...) SysCtrlSystemReset(__VA_ARGS__) +/*---------------------------------------------------------------------------*/ +/* ssi.h */ +#include DeviceFamily_constructPath(driverlib/ssi.h) + +#define ti_lib_ssi_config_set_exp_clk(...) SSIConfigSetExpClk(__VA_ARGS__) +#define ti_lib_ssi_enable(...) SSIEnable(__VA_ARGS__) +#define ti_lib_ssi_disable(...) SSIDisable(__VA_ARGS__) +#define ti_lib_ssi_data_put(...) SSIDataPut(__VA_ARGS__) +#define ti_lib_ssi_data_put_non_blocking(...) SSIDataPutNonBlocking(__VA_ARGS__) +#define ti_lib_ssi_data_get(...) SSIDataGet(__VA_ARGS__) +#define ti_lib_ssi_data_get_non_blocking(...) SSIDataGetNonBlocking(__VA_ARGS__) +#define ti_lib_ssi_busy(...) SSIBusy(__VA_ARGS__) +#define ti_lib_ssi_status(...) SSIStatus(__VA_ARGS__) +#define ti_lib_ssi_int_register(...) SSIIntRegister(__VA_ARGS__) +#define ti_lib_ssi_int_unregister(...) SSIIntUnregister(__VA_ARGS__) +#define ti_lib_ssi_int_enable(...) SSIIntEnable(__VA_ARGS__) +#define ti_lib_ssi_int_disable(...) SSIIntDisable(__VA_ARGS__) +#define ti_lib_ssi_int_clear(...) SSIIntClear(__VA_ARGS__) +#define ti_lib_ssi_int_status(...) SSIIntStatus(__VA_ARGS__) +#define ti_lib_ssi_dma_enable(...) SSIDMAEnable(__VA_ARGS__) +#define ti_lib_ssi_dma_disable(...) SSIDMADisable(__VA_ARGS__) +/*---------------------------------------------------------------------------*/ +/* systick.h */ +#include DeviceFamily_constructPath(driverlib/systick.h) + +#define ti_lib_systick_enable(...) SysTickEnable(__VA_ARGS__) +#define ti_lib_systick_disable(...) SysTickDisable(__VA_ARGS__) +#define ti_lib_systick_int_register(...) SysTickIntRegister(__VA_ARGS__) +#define ti_lib_systick_int_unregister(...) SysTickIntUnregister(__VA_ARGS__) +#define ti_lib_systick_int_enable(...) SysTickIntEnable(__VA_ARGS__) +#define ti_lib_systick_int_disable(...) SysTickIntDisable(__VA_ARGS__) +#define ti_lib_systick_period_set(...) SysTickPeriodSet(__VA_ARGS__) +#define ti_lib_systick_period_get(...) SysTickPeriodGet(__VA_ARGS__) +#define ti_lib_systick_value_get(...) SysTickValueGet(__VA_ARGS__) +/*---------------------------------------------------------------------------*/ +/* timer.h */ +#include DeviceFamily_constructPath(driverlib/timer.h) + +#define ti_lib_timer_enable(...) TimerEnable(__VA_ARGS__) +#define ti_lib_timer_disable(...) TimerDisable(__VA_ARGS__) +#define ti_lib_timer_configure(...) TimerConfigure(__VA_ARGS__) +#define ti_lib_timer_level_control(...) TimerLevelControl(__VA_ARGS__) +#define ti_lib_timer_event_control(...) TimerEventControl(__VA_ARGS__) +#define ti_lib_timer_stall_control(...) TimerStallControl(__VA_ARGS__) +#define ti_lib_timer_wait_on_trigger_control(...) TimerWaitOnTriggerControl(__VA_ARGS__) +#define ti_lib_timer_rtc_enable(...) TimerRtcEnable(__VA_ARGS__) +#define ti_lib_timer_rtc_disable(...) TimerRtcDisable(__VA_ARGS__) +#define ti_lib_timer_prescale_set(...) TimerPrescaleSet(__VA_ARGS__) +#define ti_lib_timer_prescale_get(...) TimerPrescaleGet(__VA_ARGS__) +#define ti_lib_timer_prescale_match_set(...) TimerPrescaleMatchSet(__VA_ARGS__) +#define ti_lib_timer_prescale_match_get(...) TimerPrescaleMatchGet(__VA_ARGS__) +#define ti_lib_timer_load_set(...) TimerLoadSet(__VA_ARGS__) +#define ti_lib_timer_load_get(...) TimerLoadGet(__VA_ARGS__) +#define ti_lib_timer_value_get(...) TimerValueGet(__VA_ARGS__) +#define ti_lib_timer_match_set(...) TimerMatchSet(__VA_ARGS__) +#define ti_lib_timer_match_get(...) TimerMatchGet(__VA_ARGS__) +#define ti_lib_timer_int_register(...) TimerIntRegister(__VA_ARGS__) +#define ti_lib_timer_int_unregister(...) TimerIntUnregister(__VA_ARGS__) +#define ti_lib_timer_int_enable(...) TimerIntEnable(__VA_ARGS__) +#define ti_lib_timer_int_disable(...) TimerIntDisable(__VA_ARGS__) +#define ti_lib_timer_int_status(...) TimerIntStatus(__VA_ARGS__) +#define ti_lib_timer_int_clear(...) TimerIntClear(__VA_ARGS__) +#define ti_lib_timer_synchronize(...) TimerSynchronize(__VA_ARGS__) +#define ti_lib_timer_ccp_combine_enable(...) TimerCcpCombineEnable(__VA_ARGS__) +#define ti_lib_timer_ccp_combine_disable(...) TimerCcpCombineDisable(__VA_ARGS__) +#define ti_lib_timer_match_update_mode(...) TimerMatchUpdateMode(__VA_ARGS__) +#define ti_lib_timer_interval_load_mode(...) TimerIntervalLoadMode(__VA_ARGS__) +/*---------------------------------------------------------------------------*/ +/* trng.h */ +#include DeviceFamily_constructPath(driverlib/trng.h) + +#define ti_lib_trng_configure(...) TRNGConfigure(__VA_ARGS__) +#define ti_lib_trng_enable(...) TRNGEnable(__VA_ARGS__) +#define ti_lib_trng_disable(...) TRNGDisable(__VA_ARGS__) +#define ti_lib_trng_number_get(...) TRNGNumberGet(__VA_ARGS__) +#define ti_lib_trng_status_get(...) TRNGStatusGet(__VA_ARGS__) +#define ti_lib_trng_reset(...) TRNGReset(__VA_ARGS__) +#define ti_lib_trng_int_enable(...) TRNGIntEnable(__VA_ARGS__) +#define ti_lib_trng_int_disable(...) TRNGIntDisable(__VA_ARGS__) +#define ti_lib_trng_int_status(...) TRNGIntStatus(__VA_ARGS__) +#define ti_lib_trng_int_clear(...) TRNGIntClear(__VA_ARGS__) +#define ti_lib_trng_int_register(...) TRNGIntRegister(__VA_ARGS__) +#define ti_lib_trng_int_unregister(...) TRNGIntUnregister(__VA_ARGS__) +/*---------------------------------------------------------------------------*/ +/* uart.h */ +#include DeviceFamily_constructPath(driverlib/uart.h) + +#define ti_lib_uart_parity_mode_set(...) UARTParityModeSet(__VA_ARGS__) +#define ti_lib_uart_parity_mode_get(...) UARTParityModeGet(__VA_ARGS__) +#define ti_lib_uart_fifo_level_set(...) UARTFIFOLevelSet(__VA_ARGS__) +#define ti_lib_uart_fifo_level_get(...) UARTFIFOLevelGet(__VA_ARGS__) +#define ti_lib_uart_config_set_exp_clk(...) UARTConfigSetExpClk(__VA_ARGS__) +#define ti_lib_uart_config_get_exp_clk(...) UARTConfigGetExpClk(__VA_ARGS__) +#define ti_lib_uart_enable(...) UARTEnable(__VA_ARGS__) +#define ti_lib_uart_disable(...) UARTDisable(__VA_ARGS__) +#define ti_lib_uart_fifo_enable(...) UARTFIFOEnable(__VA_ARGS__) +#define ti_lib_uart_fifo_disable(...) UARTFIFODisable(__VA_ARGS__) +#define ti_lib_uart_chars_avail(...) UARTCharsAvail(__VA_ARGS__) +#define ti_lib_uart_space_avail(...) UARTSpaceAvail(__VA_ARGS__) +#define ti_lib_uart_char_get_non_blocking(...) UARTCharGetNonBlocking(__VA_ARGS__) +#define ti_lib_uart_char_get(...) UARTCharGet(__VA_ARGS__) +#define ti_lib_uart_char_put_non_blocking(...) UARTCharPutNonBlocking(__VA_ARGS__) +#define ti_lib_uart_char_put(...) UARTCharPut(__VA_ARGS__) +#define ti_lib_uart_break_ctl(...) UARTBreakCtl(__VA_ARGS__) +#define ti_lib_uart_busy(...) UARTBusy(__VA_ARGS__) +#define ti_lib_uart_int_register(...) UARTIntRegister(__VA_ARGS__) +#define ti_lib_uart_int_unregister(...) UARTIntUnregister(__VA_ARGS__) +#define ti_lib_uart_int_enable(...) UARTIntEnable(__VA_ARGS__) +#define ti_lib_uart_int_disable(...) UARTIntDisable(__VA_ARGS__) +#define ti_lib_uart_int_status(...) UARTIntStatus(__VA_ARGS__) +#define ti_lib_uart_int_clear(...) UARTIntClear(__VA_ARGS__) +#define ti_lib_uart_dma_enable(...) UARTDMAEnable(__VA_ARGS__) +#define ti_lib_uart_dma_disable(...) UARTDMADisable(__VA_ARGS__) +#define ti_lib_uart_rx_error_get(...) UARTRxErrorGet(__VA_ARGS__) +#define ti_lib_uart_rx_error_clear(...) UARTRxErrorClear(__VA_ARGS__) +#define ti_lib_uart_hw_flow_control_en(...) UARTHwFlowControlEnable(__VA_ARGS__) +#define ti_lib_uart_hw_flow_control_dis(...) UARTHwFlowControlDisable(__VA_ARGS__) +/*---------------------------------------------------------------------------*/ +/* vims.h */ +#include DeviceFamily_constructPath(driverlib/vims.h) + +#define ti_lib_vims_configure(...) VIMSConfigure(__VA_ARGS__) +#define ti_lib_vims_mode_set(...) VIMSModeSet(__VA_ARGS__) +#define ti_lib_vims_mode_get(...) VIMSModeGet(__VA_ARGS__) +/*---------------------------------------------------------------------------*/ +/* watchdog.h */ +#include DeviceFamily_constructPath(driverlib/watchdog.h) + +#define ti_lib_watchdog_running(...) WatchdogRunning(__VA_ARGS__) +#define ti_lib_watchdog_enable(...) WatchdogEnable(__VA_ARGS__) +#define ti_lib_watchdog_reset_enable(...) WatchdogResetEnable(__VA_ARGS__) +#define ti_lib_watchdog_reset_disable(...) WatchdogResetDisable(__VA_ARGS__) +#define ti_lib_watchdog_lock(...) WatchdogLock(__VA_ARGS__) +#define ti_lib_watchdog_unlock(...) WatchdogUnlock(__VA_ARGS__) +#define ti_lib_watchdog_lock_state(...) WatchdogLockState(__VA_ARGS__) +#define ti_lib_watchdog_reload_set(...) WatchdogReloadSet(__VA_ARGS__) +#define ti_lib_watchdog_reload_get(...) WatchdogReloadGet(__VA_ARGS__) +#define ti_lib_watchdog_value_get(...) WatchdogValueGet(__VA_ARGS__) +#define ti_lib_watchdog_int_register(...) WatchdogIntRegister(__VA_ARGS__) +#define ti_lib_watchdog_int_unregister(...) WatchdogIntUnregister(__VA_ARGS__) +#define ti_lib_watchdog_int_enable(...) WatchdogIntEnable(__VA_ARGS__) +#define ti_lib_watchdog_int_status(...) WatchdogIntStatus(__VA_ARGS__) +#define ti_lib_watchdog_int_clear(...) WatchdogIntClear(__VA_ARGS__) +#define ti_lib_watchdog_int_type_set(...) WatchdogIntTypeSet(__VA_ARGS__) +#define ti_lib_watchdog_stall_enable(...) WatchdogStallEnable(__VA_ARGS__) +#define ti_lib_watchdog_stall_disable(...) WatchdogStallDisable(__VA_ARGS__) +/*---------------------------------------------------------------------------*/ +#endif /* TI_LIB_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/platform/simplelink/Makefile.device-family b/arch/platform/simplelink/Makefile.device-family index 45f37f3fb..64af7c432 100644 --- a/arch/platform/simplelink/Makefile.device-family +++ b/arch/platform/simplelink/Makefile.device-family @@ -9,25 +9,25 @@ # use the same build structure as all other SimpleLink SDK Devices. # Device name in lower case (LC) -SIMPLELINK_DEVICE_LC := $(shell echo $(SIMPLELINK_DEVICE) | tr A-Z a-z) +SIMPLELINK_FAMILY_LC := $(shell echo $(SIMPLELINK_FAMILY) | tr A-Z a-z) # Device name in upper case (UC) -SIMPLELINK_DEVICE_UC := $(shell echo $(SIMPLELINK_DEVICE) | tr a-z A-Z) +SIMPLELINK_FAMILY_UC := $(shell echo $(SIMPLELINK_FAMILY) | tr a-z A-Z) ################################################################################ # All supported SimpleLink Devices -SIMPLELINK_DEVICES = cc13x0 cc13x2 cc26x0 cc26x2 +SIMPLELINK_FAMILIES = cc13x0 cc13x2 cc26x0 cc26x2 ################################################################################ # CC13X0/CC26X0 Family # CC13X0 -ifeq ($(SIMPLELINK_DEVICE_LC),cc13x0) +ifeq ($(SIMPLELINK_FAMILY_LC),cc13x0) PLATFORM_FAMILY_DIR := cc13x0-cc26x0 DEVICE_FAMILY := DeviceFamily_CC13X0 CFLAGS += -D$(DEVICE_FAMILY) # CC26X0 -else ifeq ($(SIMPLELINK_DEVICE_LC),cc26x0) +else ifeq ($(SIMPLELINK_FAMILY_LC),cc26x0) PLATFORM_FAMILY_DIR := cc13x0-cc26x0 DEVICE_MAKEFILE := cc26x0 DEVICE_FAMILY := DeviceFamily_CC26X0 @@ -37,13 +37,13 @@ CFLAGS += -D$(DEVICE_FAMILY) # CC13X2/CC26X2 Family # CC13X2 -else ifeq ($(SIMPLELINK_DEVICE_LC),cc13x2) +else ifeq ($(SIMPLELINK_FAMILY_LC),cc13x2) PLATFORM_FAMILY_DIR := cc13x2-cc26x2 DEVICE_FAMILY := DeviceFamily_CC13X2 CFLAGS += -D$(DEVICE_FAMILY) # CC26X2 -else ifeq ($(SIMPLELINK_DEVICE_LC),cc26x2) +else ifeq ($(SIMPLELINK_FAMILY_LC),cc26x2) PLATFORM_FAMILY_DIR := cc13x2-cc26x2 DEVICE_FAMILY := DeviceFamily_CC26X2 CFLAGS += -D$(DEVICE_FAMILY) @@ -51,7 +51,7 @@ CFLAGS += -D$(DEVICE_FAMILY) ################################################################################ # Specified Device not supported else - $(error Simplelink Device '$(SIMPLELINK_DEVICE)' is not supported) + $(error Simplelink Device '$(SIMPLELINK_FAMILY)' is not supported) endif ################################################################################ @@ -75,5 +75,5 @@ CONTIKI_TARGET_DIRS := $(addprefix $(PLATFORM_FAMILY_DIR)/, $(CONTIKI_TARGET_DIR ################################################################################ # Rule for printing supported devices -simplelink_devices: - @echo "$(SIMPLELINK_DEVICES) (current: $(SIMPLELINK_DEVICE_LC))" +simplelink_families: + @echo "$(SIMPLELINK_FAMILIES) (current: $(SIMPLELINK_FAMILY_LC))" diff --git a/arch/platform/simplelink/Makefile.simplelink b/arch/platform/simplelink/Makefile.simplelink index f666482f8..2435e6e3d 100644 --- a/arch/platform/simplelink/Makefile.simplelink +++ b/arch/platform/simplelink/Makefile.simplelink @@ -1,33 +1,50 @@ ################################################################################ -# SimpleLink MCU platform makefile +### SimpleLink MCU platform makefile ################################################################################ -# Sanity check of expected symbols +### Sanity check of expected symbols ifndef CONTIKI - $(error CONTIKI not defined! You must specify where CONTIKI resides!) + $(error 'CONTIKI' not defined! You must specify where CONTIKI resides!) +endif + +ifndef FAMILY + $(error 'FAMILY' not defined! You must specify which Simplelink family you are using!) +endif + +ifndef BOARD + $(error 'BOARD' not defined! You must specify which board you are using!) endif ifndef SIMPLELINK_SDK - $(error SIMPLELINK_SDK not defined! You must specify where the SimpleLink SDK resides!) + $(error 'SIMPLELINK_SDK' not defined! You must specify where the installed SimpleLink SDK resides!) endif -ifndef SIMPLELINK_DEVICE - $(error SIMPLELINK_DEVICE not defined! You must specify which device you are using!) -endif +SIMPLELINK_SDK_EXISTS := $(shell [ -d "$(SIMPLELINK_SDK)" ]; echo $$?) -ifndef SIMPLELINK_BOARD - $(error SIMPLELINK_BOARD not defined! You must specify which board you are using!) +ifneq ($(SIMPLELINK_SDK_EXISTS),0) + $(error Simplelink SDK path 'SIMPLELINK_SDK' does not exist) endif ################################################################################ -# Defines +### Defines -SIMPLELINK_PATH := $(CONTIKI)/arch/platform/simplelink +SIMPLELINK_SDK := $(realpath $(SIMPLELINK_SDK)) -include $(SIMPLELINK_PATH)/Makefile.device-family +SUPPORTED_FAMILIES := cc13xx-cc26xx + +ifeq ($(filter $(FAMILY), $(SUPPORTED_FAMILIES)),) + $(error Simlpelink Family $(FAMILY) is not supported.) +endif + +FAMILY_PATH := $(realpath $(CONTIKI)/arch/platform/simplelink/$(FAMILY)) CLEAN += *.simplelink -# Build without code size optimisations, unless the project dictates otherwise -SMALL ?= 0 +### Include the Simplelink Family specific Makefile +include $(FAMILY_PATH)/Makefile.$(FAMILY) + +################################################################################ +# Display all supported SimpleLink Families +simplelink_families: + @echo "$(SUPPORTED_FAMILIES) (current: $(FAMILY))" diff --git a/arch/platform/simplelink/cc13x0-cc26x0/Makefile.cc13x0-cc26x0 b/arch/platform/simplelink/cc13x0-cc26x0/Makefile.cc13x0-cc26x0 deleted file mode 100644 index f7e3b656e..000000000 --- a/arch/platform/simplelink/cc13x0-cc26x0/Makefile.cc13x0-cc26x0 +++ /dev/null @@ -1,106 +0,0 @@ -################################################################################ -# SimpleLink MCU platform makefile - -# Make sure path to Simplelink SDK is specified as absolute path -SIMPLELINK_SDK := $(abspath $(SIMPLELINK_SDK)) - -################################################################################ -# Device Family - -# The DeviceFamily.h file will always be available and can therefore be -# hard-coded. -DEVICE_FAMILY_H := $(SIMPLELINK_SDK)/source/ti/devices/DeviceFamily.h - -# The define of the Device Family ID is on the format of either -# #define DeviceFamily_ID_ -# or -# #define DeviceFamily_ID_ -# We are interested in the right-hand side of the define, i.e. the third word on the line, -# as it either defines a number or an another Device Family ID. -DEVICE_DEFINE := $(shell cat $(DEVICE_FAMILY_H) \ - | grep "\#define DeviceFamily_ID_$(SIMPLELINK_DEVICE_UC)\\b" \ - | awk '{print $$3}') - -# If the define is a number, then the device family name is the resulting device name; -# Else, it points to a sub-name of the device family, e.g. DeviceFamily_ID_CC13X2_V1. -# This line checks if the extracted define is a number or not, based on this SO post: -# https://stackoverflow.com/a/19116862/5099169 -IS_NUMBER := $(shell if [ "$(DEVICE_DEFINE)" -eq "$(DEVICE_DEFINE)" ] 2>/dev/null; then echo 1 ; else echo 0 ; fi) - -ifeq ($(IS_NUMBER),1) -# The define points to a number, meaning the device family name is the same as the -# specified device name in lower case, e.g. -# cc13x2 -DEVICE_FAMILY_NAME := $(SIMPLELINK_DEVICE_LC) -else -# The define points to a sub-name of the device family. The resulting device family name -# is therefore the name after specified after ID in lower case, e.g. -# DeviceFamily_ID_CC13X2_V1 -# will result in -# cc13x2_v1 -DEVICE_FAMILY_NAME := $(shell echo "$(DEVICE_DEFINE)" \ - | sed -E "s/DeviceFamily_ID_(.+)/\1/" \ - | tr A-Z a-z ) -endif - -# The DeviceFamily_constructPath() macro in DeviceFamily.h will always construct the -# correct path for device specific files. In this case, constructing the device specific -# root path. Note that the returned path is encased in angular brackets, <...>, -# and is therefore extracted with sed. -SDK_DEVICE_DIR := $(shell echo "DeviceFamily_constructPath(dummy)" \ - | gcc -x c -E -D$(DEVICE_FAMILY) -include $(DEVICE_FAMILY_H) - \ - | tail -1 \ - | sed -E "s:<(.+)/dummy>:\1:") - -################################################################################ -# Simplelink SDK paths - -SDK_KERNEL := $(SIMPLELINK_SDK)/kernel/nortos -SDK_SOURCE := $(SIMPLELINK_SDK)/source -SDK_BOARDS := $(SDK_SOURCE)/ti/boards -SDK_DRIVERS := $(SDK_SOURCE)/ti/drivers -SDK_DEVICE := $(SDK_SOURCE)/$(SDK_DEVICE_DIR) - -################################################################################ -# Board and BSP selection -BOARD_TYPES = launchpad sensortag srf06 - -SIMPLELINK_BOARDS := $(foreach BOARD_TYPE,$(BOARD_TYPES),\ - $(shell ls -d $(PLATFORM_ROOT_DIR)/$(BOARD_TYPE)/*/ \ - | sed 's/.$$//' \ - | rev \ - | cut -d / -f -2 \ - | rev)) - -ifeq ($(filter $(SIMPLELINK_BOARD),$(SIMPLELINK_BOARDS)),) - $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported for Device '$(SIMPLELINK_DEVICE)') -endif - -################################################################################ -# Directory and source configurations - -# Add to the source dirs -CONTIKI_TARGET_DIRS += . -CONTIKI_TARGET_DIRS += common -CONTIKI_TARGET_DIRS += $(shell echo $(dir $(SIMPLELINK_BOARD)) | sed 's:/$$::') - -# Include the board-specific Makefile -include $(PLATFORM_ROOT_DIR)/$(SIMPLELINK_BOARD)/Makefile.$(notdir $(SIMPLELINK_BOARD)) - -CONTIKI_TARGET_SOURCEFILES += platform.c -CONTIKI_TARGET_SOURCEFILES += $(BOARD_SOURCEFILES) - -CONTIKI_SOURCEFILES += $(CONTIKI_TARGET_SOURCEFILES) - -# Define the CPU directory and pull in the correct CPU makefile. This will -# be defined by one of the makefiles included above and it can be either -# Makefile.cc26xx or Makefile.cc13xx -CONTIKI_CPU := $(CONTIKI)/arch/cpu/cc13xx-cc26xx -include $(CONTIKI_CPU)/Makefile.cc13x0-cc26x0 - -MODULES += os/net os/net/mac os/net/mac/framer - -################################################################################ -# Display all supported Boards for the given -simplelink_boards: - @echo "$(SIMPLELINK_BOARDS) (current: $(SIMPLELINK_BOARD))" diff --git a/arch/platform/simplelink/cc13x0-cc26x0/launchpad/Makefile.launchpad b/arch/platform/simplelink/cc13x0-cc26x0/launchpad/Makefile.launchpad deleted file mode 100644 index ac61c6d8e..000000000 --- a/arch/platform/simplelink/cc13x0-cc26x0/launchpad/Makefile.launchpad +++ /dev/null @@ -1,12 +0,0 @@ -################################################################################ -# SimpleLink LaunchPad makefile - -DEFINES += BOARD_LAUNCHPAD=1 - -# leds-arch.c/h etc. -BOARD_SOURCEFILES += launchpad-sensors.c button-sensor-arch.c leds-arch.c - -CONTIKI_TARGET_DIRS += launchpad - -### Signal that we can be programmed with cc2538-bsl -BOARD_SUPPORTS_BSL=1 diff --git a/arch/platform/simplelink/cc13x0-cc26x0/launchpad/button-sensor-arch.c b/arch/platform/simplelink/cc13x0-cc26x0/launchpad/button-sensor-arch.c deleted file mode 100644 index 03292c580..000000000 --- a/arch/platform/simplelink/cc13x0-cc26x0/launchpad/button-sensor-arch.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/*---------------------------------------------------------------------------*/ -/** - * \addtogroup launchpad-button-sensor - * @{ - * - * \file - * Driver for LaunchPad buttons - */ -/*---------------------------------------------------------------------------*/ -#include -#include -#include -/*---------------------------------------------------------------------------*/ -#include -#include -#include -/*---------------------------------------------------------------------------*/ -#include -/*---------------------------------------------------------------------------*/ -#include "button-sensor.h" -#include "button-sensor-arch.h" -/*---------------------------------------------------------------------------*/ -/* LaunchPad has 2 buttons: BTN1 and BTN2 */ -/* Map the GPIO defines from the Board file */ -#define BTN1_GPIO Board_GPIO_BTN1 -#define BTN2_GPIO Board_GPIO_BTN2 -/*---------------------------------------------------------------------------*/ -#ifdef BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN -# define BUTTON_SENSOR_ENABLE_SHUTDOWN BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN -#else -# define BUTTON_SENSOR_ENABLE_SHUTDOWN 1 -#endif -/*---------------------------------------------------------------------------*/ -#define DEBOUNCE_DURATION (CLOCK_SECOND >> 5) -/*---------------------------------------------------------------------------*/ -typedef struct { - struct timer debounce; - clock_time_t start; - clock_time_t duration; -} BtnTimer; -/*---------------------------------------------------------------------------*/ -static BtnTimer g_btn1Timer; -static BtnTimer g_btn2Timer; -/*---------------------------------------------------------------------------*/ -static void -button_press_cb(uint8_t index, BtnTimer *btnTimer, const struct sensors_sensor *btnSensor) -{ - if (!timer_expired(&btnTimer->debounce)) { - return; - } - - timer_set(&btnTimer->debounce, DEBOUNCE_DURATION); - - // Start press duration counter on press (falling), notify on release (rising) - if(GPIO_read(index) == 0) { - btnTimer->start = clock_time(); - btnTimer->duration = 0; - } else { - btnTimer->duration = clock_time() - btnTimer->start; - sensors_changed(btnSensor); - } -} -/*---------------------------------------------------------------------------*/ -static int -button_value(int type, uint8_t index, BtnTimer *btnTimer) -{ - if (type == BUTTON_SENSOR_VALUE_STATE) { - return (GPIO_read(index) == 0) - ? BUTTON_SENSOR_VALUE_PRESSED - : BUTTON_SENSOR_VALUE_RELEASED; - } else if (type == BUTTON_SENSOR_VALUE_DURATION) { - return (int)btnTimer->duration; - } - return 0; -} -/*---------------------------------------------------------------------------*/ -static int -button_config(int type, int value, uint8_t index, GPIO_CallbackFxn callback) -{ - switch (type) { - case SENSORS_HW_INIT: - GPIO_clearInt(index); - GPIO_setCallback(index, callback); - break; - - case SENSORS_ACTIVE: - if (value) { - GPIO_clearInt(index); - GPIO_enableInt(index); - } else { - GPIO_disableInt(index); - } - break; - } - - return 1; -} -/*---------------------------------------------------------------------------*/ -static int -button_status(int type, uint8_t index) -{ - switch(type) { - case SENSORS_ACTIVE: /* fallthrough */ - case SENSORS_READY: { - GPIO_PinConfig pinCfg = 0; - GPIO_getConfig(index, &pinCfg); - return (pinCfg & GPIO_CFG_IN_INT_NONE) == 0; - } - } - return 0; -} -/*---------------------------------------------------------------------------*/ -static void -btn1_press_cb(unsigned char unusued) -{ - button_press_cb(BTN1_GPIO, &g_btn1Timer, &btn1_sensor); -} -/*---------------------------------------------------------------------------*/ -static int -btn1_value(int type) -{ - return button_value(type, BTN1_GPIO, &g_btn1Timer); -} -/*---------------------------------------------------------------------------*/ -static int -btn1_config(int type, int value) -{ - return button_config(type, value, BTN1_GPIO, btn1_press_cb); -} -/*---------------------------------------------------------------------------*/ -static int -btn1_status(int type) -{ - return button_status(type, BTN1_GPIO); -} -/*---------------------------------------------------------------------------*/ -static void -btn2_press_cb(unsigned char unusued) -{ - if (BUTTON_SENSOR_ENABLE_SHUTDOWN) { - Power_shutdown(Power_ENTERING_SHUTDOWN, 0); - return; - } - - button_press_cb(BTN2_GPIO, &g_btn2Timer, &btn2_sensor); -} -/*---------------------------------------------------------------------------*/ -static int -btn2_value(int type) -{ - return button_value(type, BTN2_GPIO, &g_btn2Timer); -} -/*---------------------------------------------------------------------------*/ -static int -btn2_config(int type, int value) -{ - return button_config(type, value, BTN2_GPIO, btn2_press_cb); -} -/*---------------------------------------------------------------------------*/ -static int -btn2_status(int type) -{ - return button_status(type, BTN1_GPIO); -} -/*---------------------------------------------------------------------------*/ -SENSORS_SENSOR(btn1_sensor, BUTTON_SENSOR, btn1_value, btn1_config, btn1_status); -SENSORS_SENSOR(btn2_sensor, BUTTON_SENSOR, btn2_value, btn2_config, btn2_status); -/*---------------------------------------------------------------------------*/ -/** @} */ diff --git a/arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc1310/Makefile.cc1310 b/arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc1310/Makefile.cc1310 deleted file mode 100644 index bf58ea110..000000000 --- a/arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc1310/Makefile.cc1310 +++ /dev/null @@ -1,22 +0,0 @@ -################################################################################ -# SimpleLink Device makefile - -SDK_BOARD_NAME := CC1310_LAUNCHXL - -SDK_BOARD_PATH := $(SDK_BOARDS)/$(SDK_BOARD_NAME) - -SDK_BOARD_PATH_EXISTS := $(shell test ! -d $(SDK_BOARD_PATH); echo $$?) -ifeq ($(SDK_BOARD_PATH_EXISTS),0) - $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported by the specified Simplelink SDK) -endif - -DEFINES += SUPPORTS_PROP_MODE=1 -DEFINES += SUPPORTS_IEEE_MODE=0 - -# Add to the source dirs -BOARD_SOURCEFILES += $(SDK_BOARD_NAME).c - -EXTERNALDIRS += $(SDK_BOARD_PATH) - -# Include the common launchpad makefile -include $(PLATFORM_ROOT_DIR)/launchpad/Makefile.launchpad diff --git a/arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc1350-4/Makefile.cc1350-4 b/arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc1350-4/Makefile.cc1350-4 deleted file mode 100644 index 71de07821..000000000 --- a/arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc1350-4/Makefile.cc1350-4 +++ /dev/null @@ -1,22 +0,0 @@ -################################################################################ -# SimpleLink Device makefile - -SDK_BOARD_NAME := CC1350_LAUNCHXL_433 - -SDK_BOARD_PATH := $(SDK_BOARDS)/$(SDK_BOARD_NAME) - -SDK_BOARD_PATH_EXISTS := $(shell test ! -d $(SDK_BOARD_PATH); echo $$?) -ifeq ($(SDK_BOARD_PATH_EXISTS),0) - $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported by the specified Simplelink SDK) -endif - -DEFINES += SUPPORTS_PROP_MODE=1 -DEFINES += SUPPORTS_IEEE_MODE=1 - -# Add to the source dirs -BOARD_SOURCEFILES += $(SDK_BOARD_NAME).c - -EXTERNALDIRS += $(SDK_BOARD_PATH) - -# Include the common launchpad makefile -include $(PLATFORM_ROOT_DIR)/launchpad/Makefile.launchpad diff --git a/arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc1350/Makefile.cc1350 b/arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc1350/Makefile.cc1350 deleted file mode 100644 index 4789dec86..000000000 --- a/arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc1350/Makefile.cc1350 +++ /dev/null @@ -1,22 +0,0 @@ -################################################################################ -# SimpleLink Device makefile - -SDK_BOARD_NAME := CC1350_LAUNCHXL - -SDK_BOARD_PATH := $(SDK_BOARDS)/$(SDK_BOARD_NAME) - -SDK_BOARD_PATH_EXISTS := $(shell test ! -d $(SDK_BOARD_PATH); echo $$?) -ifeq ($(SDK_BOARD_PATH_EXISTS),0) - $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported by the specified Simplelink SDK) -endif - -DEFINES += SUPPORTS_PROP_MODE=1 -DEFINES += SUPPORTS_IEEE_MODE=1 - -# Add to the source dirs -BOARD_SOURCEFILES += $(SDK_BOARD_NAME).c - -EXTERNALDIRS += $(SDK_BOARD_PATH) - -# Include the common launchpad makefile -include $(PLATFORM_ROOT_DIR)/launchpad/Makefile.launchpad diff --git a/arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc2650/Makefile.cc2650 b/arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc2650/Makefile.cc2650 deleted file mode 100644 index 9fbad9968..000000000 --- a/arch/platform/simplelink/cc13x0-cc26x0/launchpad/cc2650/Makefile.cc2650 +++ /dev/null @@ -1,22 +0,0 @@ -################################################################################ -# SimpleLink Device makefile - -SDK_BOARD_NAME := CC2650_LAUNCHXL - -SDK_BOARD_PATH := $(SDK_BOARDS)/$(SDK_BOARD_NAME) - -SDK_BOARD_PATH_EXISTS := $(shell test ! -d $(SDK_BOARD_PATH); echo $$?) -ifeq ($(SDK_BOARD_PATH_EXISTS),0) - $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported by the specified Simplelink SDK) -endif - -DEFINES += SUPPORTS_PROP_MODE=0 -DEFINES += SUPPORTS_IEEE_MODE=1 - -# Add to the source dirs -BOARD_SOURCEFILES += $(SDK_BOARD_NAME).c - -EXTERNALDIRS += $(SDK_BOARD_PATH) - -# Include the common launchpad makefile -include $(PLATFORM_ROOT_DIR)/launchpad/Makefile.launchpad diff --git a/arch/platform/simplelink/cc13x0-cc26x0/sensortag/Makefile.sensortag b/arch/platform/simplelink/cc13x0-cc26x0/sensortag/Makefile.sensortag deleted file mode 100644 index 1e25489ab..000000000 --- a/arch/platform/simplelink/cc13x0-cc26x0/sensortag/Makefile.sensortag +++ /dev/null @@ -1,12 +0,0 @@ -################################################################################ -# SimpleLink LaunchPad makefile - -DEFINES += BOARD_SENSORTAG=1 - -# leds-arch.c/h etc. -BOARD_SOURCEFILES += sensortag-sensors.c button-sensor-arch.c leds-arch.c - -CONTIKI_TARGET_DIRS += sensortag - -### Signal that we can be programmed with cc2538-bsl -BOARD_SUPPORTS_BSL=1 diff --git a/arch/platform/simplelink/cc13x0-cc26x0/sensortag/cc1350/Makefile.cc1350 b/arch/platform/simplelink/cc13x0-cc26x0/sensortag/cc1350/Makefile.cc1350 deleted file mode 100644 index 1795df10a..000000000 --- a/arch/platform/simplelink/cc13x0-cc26x0/sensortag/cc1350/Makefile.cc1350 +++ /dev/null @@ -1,22 +0,0 @@ -################################################################################ -# SimpleLink Device makefile - -SDK_BOARD_NAME := CC1350STK - -SDK_BOARD_PATH := $(SDK_BOARDS)/$(SDK_BOARD_NAME) - -SDK_BOARD_PATH_EXISTS := $(shell test ! -d $(SDK_BOARD_PATH); echo $$?) -ifeq ($(SDK_BOARD_PATH_EXISTS),0) - $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported by the specified Simplelink SDK) -endif - -DEFINES += SUPPORTS_PROP_MODE=1 -DEFINES += SUPPORTS_IEEE_MODE=1 - -# Add to the source dirs -BOARD_SOURCEFILES += $(SDK_BOARD_NAME).c - -EXTERNALDIRS += $(SDK_BOARD_PATH) - -# Include the common launchpad makefile -include $(PLATFORM_ROOT_DIR)/sensortag/Makefile.sensortag diff --git a/arch/platform/simplelink/cc13x0-cc26x0/sensortag/cc2650/Makefile.cc2650 b/arch/platform/simplelink/cc13x0-cc26x0/sensortag/cc2650/Makefile.cc2650 deleted file mode 100644 index 47fb09f8b..000000000 --- a/arch/platform/simplelink/cc13x0-cc26x0/sensortag/cc2650/Makefile.cc2650 +++ /dev/null @@ -1,22 +0,0 @@ -################################################################################ -# SimpleLink Device makefile - -SDK_BOARD_NAME := CC2650STK - -SDK_BOARD_PATH := $(SDK_BOARDS)/$(SDK_BOARD_NAME) - -SDK_BOARD_PATH_EXISTS := $(shell test ! -d $(SDK_BOARD_PATH); echo $$?) -ifeq ($(SDK_BOARD_PATH_EXISTS),0) - $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported by the specified Simplelink SDK) -endif - -DEFINES += SUPPORTS_PROP_MODE=0 -DEFINES += SUPPORTS_IEEE_MODE=1 - -# Add to the source dirs -BOARD_SOURCEFILES += $(SDK_BOARD_NAME).c - -EXTERNALDIRS += $(SDK_BOARD_PATH) - -# Include the common launchpad makefile -include $(PLATFORM_ROOT_DIR)/sensortag/Makefile.sensortag diff --git a/arch/platform/simplelink/cc13x0-cc26x0/srf06/Makefile.srf06 b/arch/platform/simplelink/cc13x0-cc26x0/srf06/Makefile.srf06 deleted file mode 100644 index 862993a72..000000000 --- a/arch/platform/simplelink/cc13x0-cc26x0/srf06/Makefile.srf06 +++ /dev/null @@ -1,12 +0,0 @@ -################################################################################ -# SimpleLink LaunchPad makefile - -DEFINES += BOARD_SMARTRF06EB=1 - -# leds-arch.c/h etc. -BOARD_SOURCEFILES += srf06-sensors.c button-sensor-arch.c leds-arch.c - -CONTIKI_TARGET_DIRS += srf06 - -### Signal that we can be programmed with cc2538-bsl -BOARD_SUPPORTS_BSL=1 diff --git a/arch/platform/simplelink/cc13x0-cc26x0/srf06/cc1310/Makefile.cc1310 b/arch/platform/simplelink/cc13x0-cc26x0/srf06/cc1310/Makefile.cc1310 deleted file mode 100644 index aff16d421..000000000 --- a/arch/platform/simplelink/cc13x0-cc26x0/srf06/cc1310/Makefile.cc1310 +++ /dev/null @@ -1,22 +0,0 @@ -################################################################################ -# SimpleLink Device makefile - -SDK_BOARD_NAME := CC1310DK_7XD - -SDK_BOARD_PATH := $(SDK_BOARDS)/$(SDK_BOARD_NAME) - -SDK_BOARD_PATH_EXISTS := $(shell test ! -d $(SDK_BOARD_PATH); echo $$?) -ifeq ($(SDK_BOARD_PATH_EXISTS),0) - $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported by the specified Simplelink SDK) -endif - -DEFINES += SUPPORTS_PROP_MODE=1 -DEFINES += SUPPORTS_IEEE_MODE=0 - -# Add to the source dirs -BOARD_SOURCEFILES += $(SDK_BOARD_NAME).c - -EXTERNALDIRS += $(SDK_BOARD_PATH) - -# Include the common srf06 makefile -include $(PLATFORM_ROOT_DIR)/srf06/Makefile.srf06 diff --git a/arch/platform/simplelink/cc13x0-cc26x0/srf06/cc1350/Makefile.cc1350 b/arch/platform/simplelink/cc13x0-cc26x0/srf06/cc1350/Makefile.cc1350 deleted file mode 100644 index 2376346bb..000000000 --- a/arch/platform/simplelink/cc13x0-cc26x0/srf06/cc1350/Makefile.cc1350 +++ /dev/null @@ -1,22 +0,0 @@ -################################################################################ -# SimpleLink Device makefile - -SDK_BOARD_NAME := CC1350DK_7XD - -SDK_BOARD_PATH := $(SDK_BOARDS)/$(SDK_BOARD_NAME) - -SDK_BOARD_PATH_EXISTS := $(shell test ! -d $(SDK_BOARD_PATH); echo $$?) -ifeq ($(SDK_BOARD_PATH_EXISTS),0) - $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported by the specified Simplelink SDK) -endif - -DEFINES += SUPPORTS_PROP_MODE=1 -DEFINES += SUPPORTS_IEEE_MODE=1 - -# Add to the source dirs -BOARD_SOURCEFILES += $(SDK_BOARD_NAME).c - -EXTERNALDIRS += $(SDK_BOARD_PATH) - -# Include the common srf06 makefile -include $(PLATFORM_ROOT_DIR)/srf06/Makefile.srf06 diff --git a/arch/platform/simplelink/cc13x0-cc26x0/srf06/cc2650/Makefile.cc2650 b/arch/platform/simplelink/cc13x0-cc26x0/srf06/cc2650/Makefile.cc2650 deleted file mode 100644 index d8dd24c2c..000000000 --- a/arch/platform/simplelink/cc13x0-cc26x0/srf06/cc2650/Makefile.cc2650 +++ /dev/null @@ -1,22 +0,0 @@ -################################################################################ -# SimpleLink Device makefile - -SDK_BOARD_NAME := CC2650DK_7ID - -SDK_BOARD_PATH := $(SDK_BOARDS)/$(SDK_BOARD_NAME) - -SDK_BOARD_PATH_EXISTS := $(shell test ! -d $(SDK_BOARD_PATH); echo $$?) -ifeq ($(SDK_BOARD_PATH_EXISTS),0) - $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported by the specified Simplelink SDK) -endif - -DEFINES += SUPPORTS_PROP_MODE=0 -DEFINES += SUPPORTS_IEEE_MODE=1 - -# Add to the source dirs -BOARD_SOURCEFILES += $(SDK_BOARD_NAME).c - -EXTERNALDIRS += $(SDK_BOARD_PATH) - -# Include the common launchpad makefile -include $(PLATFORM_ROOT_DIR)/srf06/Makefile.srf06 diff --git a/arch/platform/simplelink/cc13x2-cc26x2/Makefile.cc13x2-cc26x2 b/arch/platform/simplelink/cc13x2-cc26x2/Makefile.cc13x2-cc26x2 deleted file mode 100644 index 6f7c6f1be..000000000 --- a/arch/platform/simplelink/cc13x2-cc26x2/Makefile.cc13x2-cc26x2 +++ /dev/null @@ -1,103 +0,0 @@ -################################################################################ -# SimpleLink MCU platform makefile - -# Make sure path to Simplelink SDK is specified as absolute path -SIMPLELINK_SDK := $(abspath $(SIMPLELINK_SDK)) - -################################################################################ -# Device Family -DEVICE_FAMILY_H := $(SIMPLELINK_SDK)/source/ti/devices/DeviceFamily.h - -# The define of the Device Family ID is on the format of either -# #define DeviceFamily_ID_ -# or -# #define DeviceFamily_ID_ -# We are interested in the right-hand side of the define, i.e. the third word on the line, -# as it either defines a number or an another Device Family ID. -DEVICE_DEFINE := $(shell cat $(DEVICE_FAMILY_H) \ - | grep "\#define DeviceFamily_ID_$(SIMPLELINK_DEVICE_UC)\\b" \ - | awk '{print $$3}') - -# If the define is a number, then the device family name is the resulting device name; -# Else, it points to a sub-name of the device family, e.g. DeviceFamily_ID_CC13X2_V1. -# This line checks if the extracted define is a number or not, based on this SO post: -# https://stackoverflow.com/a/19116862/5099169 -IS_NUMBER := $(shell if [ "$(DEVICE_DEFINE)" -eq "$(DEVICE_DEFINE)" ] 2>/dev/null; then echo 1 ; else echo 0 ; fi) - -ifeq ($(IS_NUMBER),1) -# The define points to a number, meaning the device family name is the same as the -# specified device name in lower case, e.g. -# cc13x2 -DEVICE_FAMILY_NAME := $(SIMPLELINK_DEVICE_LC) -else -# The define points to a sub-name of the device family. The resulting device family name -# is therefore the name after specified after ID in lower case, e.g. -# DeviceFamily_ID_CC13X2_V1 -# will result in -# cc13x2_v1 -DEVICE_FAMILY_NAME := $(shell echo "$(DEVICE_DEFINE)" \ - | sed -E "s/DeviceFamily_ID_(.+)/\1/" \ - | tr A-Z a-z ) -endif - -# The DeviceFamily_constructPath() macro in DeviceFamily.h will always construct the -# correct path for device specific files. In this case, constructing the device specific -# root path. Note that the returned path is encased in angular brackets, <...>, -# and is therefore extracted with sed. -SDK_DEVICE_DIR := $(shell echo "DeviceFamily_constructPath(dummy)" \ - | gcc -x c -E -D$(DEVICE_FAMILY) -include $(DEVICE_FAMILY_H) - \ - | tail -1 \ - | sed -E "s:<(.+)/dummy>:\1:") - -################################################################################ -# Simplelink SDK paths - -SDK_KERNEL := $(SIMPLELINK_SDK)/kernel/nortos -SDK_SOURCE := $(SIMPLELINK_SDK)/source -SDK_BOARDS := $(SDK_SOURCE)/ti/boards -SDK_DRIVERS := $(SDK_SOURCE)/ti/drivers -SDK_DEVICE := $(SDK_SOURCE)/$(SDK_DEVICE_DIR) - -################################################################################ -# Board and BSP selection -BOARD_TYPES = launchpad - -SIMPLELINK_BOARDS := $(foreach BOARD_TYPE, $(BOARD_TYPES), \ - $(shell ls -d $(PLATFORM_ROOT_DIR)/$(BOARD_TYPES)/*/ \ - | sed 's/.$$//' \ - | rev \ - | cut -d / -f -2 \ - | rev)) - -ifeq ($(filter $(SIMPLELINK_BOARD),$(SIMPLELINK_BOARDS)),) - $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported for Device '$(SIMPLELINK_DEVICE)') -endif - -################################################################################ -# Directory and source configurations - -# Add to the source dirs -CONTIKI_TARGET_DIRS += . -CONTIKI_TARGET_DIRS += common -CONTIKI_TARGET_DIRS += $(shell echo $(dir $(SIMPLELINK_BOARD)) | sed 's:/$$::') - -# Include the board-specific Makefile -include $(PLATFORM_ROOT_DIR)/$(SIMPLELINK_BOARD)/Makefile.$(notdir $(SIMPLELINK_BOARD)) - -CONTIKI_TARGET_SOURCEFILES += platform.c -CONTIKI_TARGET_SOURCEFILES += $(BOARD_SOURCEFILES) - -CONTIKI_SOURCEFILES += $(CONTIKI_TARGET_SOURCEFILES) - -# Define the CPU directory and pull in the correct CPU makefile. This will -# be defined by one of the makefiles included above and it can be either -# Makefile.cc26xx or Makefile.cc13xx -CONTIKI_CPU=$(CONTIKI)/arch/cpu/cc13xx-cc26xx -include $(CONTIKI_CPU)/Makefile.cc13x2-cc26x2 - -MODULES += os/net os/net/mac os/net/mac/framer - -################################################################################ -# Display all supported Boards for the given -simplelink_boards: - @echo "$(SIMPLELINK_BOARDS) (current: $(SIMPLELINK_BOARD))" diff --git a/arch/platform/simplelink/cc13x2-cc26x2/launchpad/Makefile.launchpad b/arch/platform/simplelink/cc13x2-cc26x2/launchpad/Makefile.launchpad deleted file mode 100644 index 60306469a..000000000 --- a/arch/platform/simplelink/cc13x2-cc26x2/launchpad/Makefile.launchpad +++ /dev/null @@ -1,12 +0,0 @@ -################################################################################ -# SimpleLink LaunchPad makefile - -DEFINES += BOARD_LAUNCHPAD=1 - -# leds-arch.c/h etc. -BOARD_SOURCEFILES += launchpad-sensors.c button-sensor-arch.c leds-arch.c - -CONTIKI_TARGET_DIRS += launchpad - -### Signal that we can be programmed with cc2538-bsl -BOARD_SUPPORTS_BSL=0 diff --git a/arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc1312r1/Makefile.cc1312r1 b/arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc1312r1/Makefile.cc1312r1 deleted file mode 100644 index 880c7a995..000000000 --- a/arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc1312r1/Makefile.cc1312r1 +++ /dev/null @@ -1,22 +0,0 @@ -################################################################################ -# SimpleLink Device makefile - -SDK_BOARD_NAME := CC1312R1_LAUNCHXL - -SDK_BOARD_PATH := $(SDK_BOARDS)/$(SDK_BOARD_NAME) - -SDK_BOARD_PATH_EXISTS := $(shell test ! -d $(SDK_BOARD_PATH); echo $$?) -ifeq ($(SDK_BOARD_PATH_EXISTS),0) - $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported by the specified Simplelink SDK) -endif - -DEFINES += SUPPORTS_PROP_MODE=1 -DEFINES += SUPPORTS_IEEE_MODE=0 - -# Add to the source dirs -BOARD_SOURCEFILES += $(SDK_BOARD_NAME).c - -EXTERNALDIRS += $(SDK_BOARD_PATH) - -# Include the common launchpad makefile -include $(PLATFORM_ROOT_DIR)/launchpad/Makefile.launchpad diff --git a/arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc1352p1/Makefile.cc1352p1 b/arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc1352p1/Makefile.cc1352p1 deleted file mode 100644 index ba161e6ab..000000000 --- a/arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc1352p1/Makefile.cc1352p1 +++ /dev/null @@ -1,22 +0,0 @@ -################################################################################ -# SimpleLink Device makefile - -SDK_BOARD_NAME := CC1352P1_LAUNCHXL - -SDK_BOARD_PATH := $(SDK_BOARDS)/$(SDK_BOARD_NAME) - -SDK_BOARD_PATH_EXISTS := $(shell test ! -d $(SDK_BOARD_PATH); echo $$?) -ifeq ($(SDK_BOARD_PATH_EXISTS),0) - $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported by the specified Simplelink SDK) -endif - -DEFINES += SUPPORTS_PROP_MODE=1 -DEFINES += SUPPORTS_IEEE_MODE=1 - -# Add to the source dirs -BOARD_SOURCEFILES += $(SDK_BOARD_NAME).c - -EXTERNALDIRS += $(SDK_BOARD_PATH) - -# Include the common launchpad makefile -include $(PLATFORM_ROOT_DIR)/launchpad/Makefile.launchpad diff --git a/arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc1352r1/Makefile.cc1352r1 b/arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc1352r1/Makefile.cc1352r1 deleted file mode 100644 index 7149d55b4..000000000 --- a/arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc1352r1/Makefile.cc1352r1 +++ /dev/null @@ -1,22 +0,0 @@ -################################################################################ -# SimpleLink Device makefile - -SDK_BOARD_NAME := CC1352R1_LAUNCHXL - -# Check that the provided Simplelink SDK supports this device. Simply checking -# whether a folder with the name of $(SDK_BOARD_NAME) exists in the board folder -# is sufficient, # i.e. folder exists in /source/ti/boards. -SDK_BOARD_PATH := $(SDK_BOARDS)/$(SDK_BOARD_NAME) -SDK_BOARD_PATH_EXISTS := $(shell test ! -d $(SDK_BOARD_PATH); echo $$?) -ifeq ($(SDK_BOARD_PATH_EXISTS),0) - $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported by the specified Simplelink SDK) -endif - -DEFINES += SUPPORTS_PROP_MODE=1 -DEFINES += SUPPORTS_IEEE_MODE=1 - -# Add to the source dirs -BOARD_SOURCEFILES += $(SDK_BOARD_NAME).c - -# Include the common launchpad makefile -include $(PLATFORM_ROOT_DIR)/launchpad/Makefile.launchpad diff --git a/arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc26x2r1/Makefile.cc26x2r1 b/arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc26x2r1/Makefile.cc26x2r1 deleted file mode 100644 index f42409d8e..000000000 --- a/arch/platform/simplelink/cc13x2-cc26x2/launchpad/cc26x2r1/Makefile.cc26x2r1 +++ /dev/null @@ -1,22 +0,0 @@ -################################################################################ -# SimpleLink Device makefile - -SDK_BOARD_NAME := CC26X2R1_LAUNCHXL - -SDK_BOARD_PATH := $(SDK_BOARDS)/$(SDK_BOARD_NAME) - -SDK_BOARD_PATH_EXISTS := $(shell test ! -d $(SDK_BOARD_PATH); echo $$?) -ifeq ($(SDK_BOARD_PATH_EXISTS),0) - $(error Simplelink Board '$(SIMPLELINK_BOARD)' is not supported by the specified Simplelink SDK) -endif - -DEFINES += SUPPORTS_PROP_MODE=0 -DEFINES += SUPPORTS_IEEE_MODE=1 - -# Add to the source dirs -BOARD_SOURCEFILES += $(SDK_BOARD_NAME).c - -EXTERNALDIRS += $(SDK_BOARD_PATH) - -# Include the common launchpad makefile -include $(PLATFORM_ROOT_DIR)/launchpad/Makefile.launchpad diff --git a/arch/platform/simplelink/cc13x2-cc26x2/platform.c b/arch/platform/simplelink/cc13x2-cc26x2/platform.c deleted file mode 100644 index c5718a103..000000000 --- a/arch/platform/simplelink/cc13x2-cc26x2/platform.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/*---------------------------------------------------------------------------*/ -/** - * \addtogroup cc13xx-cc26xx-platforms - * @{ - * - * \defgroup LaunchPads - * - * This platform supports a number of different boards: - * - The TI CC1310 LaunchPad - * - The TI CC1350 LaunchPad - * - The TI CC2640 LaunchPad - * - The TI CC2650 LaunchPad - * - The TI CC1312R1 LaunchPad - * - The TI CC1352R1 LaunchPad - * - The TI CC1352P1 LaunchPad - * - The TI CC26X2R1 LaunchPad - * @{ - */ -/*---------------------------------------------------------------------------*/ -/* Simplelink SDK includes */ -#include -#include -#include -#include -#include -#include -#include -#include -/*---------------------------------------------------------------------------*/ -/* Contiki API */ -#include "contiki.h" -#include "contiki-net.h" -#include "sys/clock.h" -#include "sys/rtimer.h" -#include "sys/node-id.h" -#include "sys/platform.h" -#include "dev/serial-line.h" -#include "dev/leds.h" -#include "net/mac/framer/frame802154.h" -#include "lib/sensors.h" -/*---------------------------------------------------------------------------*/ -/* Arch driver implementations */ -#include "uart0-arch.h" -/*---------------------------------------------------------------------------*/ -//#include "gpio-interrupt.h" -#include "ieee-addr.h" -#include "dev/rf-common.h" -#include "lib/random.h" -#include "button-sensor.h" -/*---------------------------------------------------------------------------*/ -#include -/*---------------------------------------------------------------------------*/ -/* Log configuration */ -#include "sys/log.h" -#define LOG_MODULE "CC26xx/CC13xx" -#define LOG_LEVEL LOG_LEVEL_DBG -/*---------------------------------------------------------------------------*/ -unsigned short g_nodeId = 0; -/*---------------------------------------------------------------------------*/ -/** \brief Board specific initialization */ -void board_init(void); -/*---------------------------------------------------------------------------*/ -static void -fade(unsigned char l) -{ - volatile int i; - for(int k = 0; k < 800; ++k) { - int j = k > 400 ? 800 - k : k; - - leds_on(l); - for(i = 0; i < j; ++i) { - __asm("nop"); - } - leds_off(l); - for(i = 0; i < 400 - j; ++i) { - __asm("nop"); - } - } -} -/*---------------------------------------------------------------------------*/ -static void -set_rf_params(void) -{ - uint16_t short_addr; - uint8_t ext_addr[8]; - - ieee_addr_cpy_to(ext_addr, sizeof(ext_addr)); - - short_addr = ext_addr[7]; - short_addr |= ext_addr[6] << 8; - - 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_object(RADIO_PARAM_64BIT_ADDR, ext_addr, sizeof(ext_addr)); - - /* also set the global node id */ - g_nodeId = short_addr; -} -/*---------------------------------------------------------------------------*/ -void -platform_init_stage_one(void) -{ - // Enable flash cache - VIMSModeSet(VIMS_BASE, VIMS_MODE_ENABLED); - // Configure round robin arbitration and prefetching - VIMSConfigure(VIMS_BASE, true, true); - - Board_initGeneral(); - GPIO_init(); - - // NoRTOS_start only enables HWI - NoRTOS_start(); - - // Contiki drivers init - leds_init(); - -// ti_lib_int_master_disable(); -// -// /* Set the LF XOSC as the LF system clock source */ -// oscillators_select_lf_xosc(); -// -// lpm_init(); -// - fade(LEDS_RED); -// -// /* -// * Disable I/O pad sleep mode and open I/O latches in the AON IOC interface -// * This is only relevant when returning from shutdown (which is what froze -// * latches in the first place. Before doing these things though, we should -// * allow software to first regain control of pins -// */ -// ti_lib_pwr_ctrl_io_freeze_disable(); -// -// ti_lib_int_master_enable(); -// - fade(LEDS_GREEN); -} -/*---------------------------------------------------------------------------*/ -void -platform_init_stage_two(void) -{ -#if SIMPLELINK_UART_CONF_ENABLE - uart0_init(); -#endif - - serial_line_init(); - -#if BUILD_WITH_SHELL - uart0_set_callback(serial_line_input_byte); -#endif - - // random_init(0x1234); - - /* Populate linkaddr_node_addr */ - ieee_addr_cpy_to(linkaddr_node_addr.u8, LINKADDR_SIZE); - - fade(LEDS_RED); -} -/*---------------------------------------------------------------------------*/ -void -platform_init_stage_three(void) -{ - radio_value_t chan, pan; - - set_rf_params(); - - NETSTACK_RADIO.get_value(RADIO_PARAM_CHANNEL, &chan); - NETSTACK_RADIO.get_value(RADIO_PARAM_PAN_ID, &pan); - - LOG_DBG("With DriverLib v%u.%u\n", DRIVERLIB_RELEASE_GROUP, - DRIVERLIB_RELEASE_BUILD); - LOG_DBG("IEEE 802.15.4: %s, Sub-GHz: %s, BLE: %s, Prop: %s\n", - ChipInfo_SupportsIEEE_802_15_4() ? "Yes" : "No", - ChipInfo_ChipFamilyIs_CC13x0() ? "Yes" : "No", - ChipInfo_SupportsBLE() ? "Yes" : "No", - ChipInfo_SupportsPROPRIETARY() ? "Yes" : "No"); - LOG_INFO("RF: Channel %d, PANID 0x%04X\n", chan, pan); - LOG_INFO("Node ID: %d\n", g_nodeId); - - process_start(&sensors_process, NULL); - fade(LEDS_GREEN); -} -/*---------------------------------------------------------------------------*/ -void -platform_idle(void) -{ - // Drop to some low power mode - Power_idleFunc(); -} -/*---------------------------------------------------------------------------*/ -/** - * @} - * @} - */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx new file mode 100644 index 000000000..45f946e92 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -0,0 +1,65 @@ +################################################################################ +### SimpleLink MCU platform makefile + +################################################################################ +# Board and BSP selection +BOARD_PLATFORMS = launchpad sensortag srf06 + +# Assigned lazily to avoid breaking environments which doesn't have cd and find +BOARDS = $(foreach BOARD_TYPE, $(BOARD_PLATFORMS), \ + $(shell cd $(FAMILY_PATH); find $(BOARD_TYPE)/* -type d -print)) + +BOARD_EXISTS := $(shell [ -d "$(FAMILY_PATH)/$(BOARD)" ]; echo $$?) + +ifneq ($(BOARD_EXISTS),0) + $(error Simplelink Board '$(BOARD)' is not supported for Simplelink Family '$(FAMILY)') +endif + +################################################################################ +# Directory and source configurations + +# Include the board-specific Makefile +BOARD_PATH := $(FAMILY_PATH)/$(BOARD) +include $(BOARD_PATH)/Makefile.$(notdir $(BOARD)) + +# Add to the source dirs +TARGET_FAMILY_DIRS += common +TARGET_FAMILY_DIRS += $(BOARD) + +CONTIKI_TARGET_DIRS += $(FAMILY) +CONTIKI_TARGET_DIRS += $(addprefix $(FAMILY)/, $(TARGET_FAMILY_DIRS)) + +DEFINES += DeviceFamily_$(DEVICE_FAMILY) +DEFINES += $(BOARD_TYPE) +DEFINES += SUPPORTS_PROP_MODE=$(SUPPORTS_PROP_MODE) +DEFINES += SUPPORTS_IEEE_MODE=$(SUPPORTS_IEEE_MODE) + +### If the user-specified a Node ID, pass a define +ifdef NODEID + DEFINES += IEEE_ADDR_NODE_ID=$(NODEID) +endif + +CONTIKI_TARGET_SOURCEFILES += platform.c +CONTIKI_TARGET_SOURCEFILES += $(BOARD_SOURCEFILES) + +CONTIKI_SOURCEFILES += $(CONTIKI_TARGET_SOURCEFILES) + +# TODO fix for CC26x0 +ifeq ($(DEVICE_FAMILY),CC26X0) + # Pull in the correct CPU makefile + CPU_FAMILY = cc26x0 +else + # Pull in the correct CPU makefile + CPU_FAMILY = cc13xx-cc26xx +endif + +# Define the CPU directory and pull in the correct CPU Makefile +CONTIKI_CPU := $(realpath $(CONTIKI)/arch/cpu/cc13xx-cc26xx) +include $(CONTIKI_CPU)/Makefile.$(CPU_FAMILY) + +MODULES += os/net os/net/mac os/net/mac/framer + +################################################################################ +# Display all supported Boards for the given SimpleLink Family +simplelink_boards: + @echo "$(BOARDS) (current: $(BOARD))" diff --git a/arch/platform/simplelink/cc13x0-cc26x0/common/button-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/common/button-sensor.h similarity index 100% rename from arch/platform/simplelink/cc13x0-cc26x0/common/button-sensor.h rename to arch/platform/simplelink/cc13xx-cc26xx/common/button-sensor.h diff --git a/arch/platform/simplelink/cc13x2-cc26x2/contiki-conf.h b/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h similarity index 97% rename from arch/platform/simplelink/cc13x2-cc26x2/contiki-conf.h rename to arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h index a841b89ae..46339a9b2 100644 --- a/arch/platform/simplelink/cc13x2-cc26x2/contiki-conf.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h @@ -63,8 +63,8 @@ * Override button symbols from dev/button-sensor.h, for the examples that * include it */ -#define button_sensor button_left_sensor -#define button_sensor2 button_right_sensor +#define btn1_sensor button_left_sensor +#define btn2_sensor button_right_sensor /** @} */ /*---------------------------------------------------------------------------*/ /* Platform-specific define to signify sensor reading failure */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/Makefile.launchpad b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/Makefile.launchpad new file mode 100644 index 000000000..2aedcefdc --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/Makefile.launchpad @@ -0,0 +1,10 @@ +################################################################################ +# SimpleLink LaunchPad makefile + +BOARD_TYPE = BOARD_LAUNCHPAD + +# leds-arch.c/h etc. +BOARD_SOURCEFILES += launchpad.c launchpad-sensors.c +BOARD_SOURCEFILES += button-sensor-arch.c leds-arch.c ext-flash.c + +TARGET_FAMILY_DIRS += launchpad diff --git a/arch/platform/simplelink/cc13x0-cc26x0/launchpad/launchpad-sensors.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-peripherals.h similarity index 81% rename from arch/platform/simplelink/cc13x0-cc26x0/launchpad/launchpad-sensors.c rename to arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-peripherals.h index c333e62f5..3e1220234 100644 --- a/arch/platform/simplelink/cc13x0-cc26x0/launchpad/launchpad-sensors.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-peripherals.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,28 +28,29 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /*---------------------------------------------------------------------------*/ -/** - * \addtogroup simplelink-peripherals +/** \addtogroup cc26xx-srf-tag + * @{ + * + * \defgroup launchpad-peripherals LaunchPad peripherals + * + * Defines related to LaunchPad peripherals. + * * @{ * * \file - * Generic module controlling Simplelink sensors + * Header file with definitions related to LaunchPad peripherals + * + * \note Do not include this file directly. */ /*---------------------------------------------------------------------------*/ -#include -#include +#ifndef BOARD_PERIPHERALS_H_ +#define BOARD_PERIPHERALS_H_ /*---------------------------------------------------------------------------*/ -#include "common/button-sensor.h" +#include "ext-flash.h" /*---------------------------------------------------------------------------*/ -/* Exports a global symbol to be used by the sensor API */ -SENSORS( -#ifdef BUTTON_SENSOR_ARCH_BTN1 - &button_sensor, -#endif -#ifdef BUTTON_SENSOR_ARCH_BTN2 - &button_sensor2, -#endif - NULL -); +#endif /* BOARD_PERIPHERALS_H_ */ /*---------------------------------------------------------------------------*/ -/** @} */ +/** + * @} + * @} + */ diff --git a/arch/platform/simplelink/cc13x2-cc26x2/launchpad/button-sensor-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c similarity index 99% rename from arch/platform/simplelink/cc13x2-cc26x2/launchpad/button-sensor-arch.c rename to arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c index 03292c580..b6ecdbc23 100644 --- a/arch/platform/simplelink/cc13x2-cc26x2/launchpad/button-sensor-arch.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c @@ -81,7 +81,7 @@ button_press_cb(uint8_t index, BtnTimer *btnTimer, const struct sensors_sensor * timer_set(&btnTimer->debounce, DEBOUNCE_DURATION); // Start press duration counter on press (falling), notify on release (rising) - if(GPIO_read(index) == 0) { + if (GPIO_read(index) == 0) { btnTimer->start = clock_time(); btnTimer->duration = 0; } else { diff --git a/arch/platform/simplelink/cc13x0-cc26x0/launchpad/button-sensor-arch.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.h similarity index 100% rename from arch/platform/simplelink/cc13x0-cc26x0/launchpad/button-sensor-arch.h rename to arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.h diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Board.h new file mode 100644 index 000000000..4bf1f5d17 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Board.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2015-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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 __BOARD_H +#define __BOARD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "CC1310_LAUNCHXL.h" + +#define Board_initGeneral() CC1310_LAUNCHXL_initGeneral() +#define Board_shutDownExtFlash() CC1310_LAUNCHXL_shutDownExtFlash() +#define Board_wakeUpExtFlash() CC1310_LAUNCHXL_wakeUpExtFlash() + +/* These #defines allow us to reuse TI-RTOS across other device families */ + +#define Board_ADC0 CC1310_LAUNCHXL_ADC0 +#define Board_ADC1 CC1310_LAUNCHXL_ADC1 + +#define Board_ADCBUF0 CC1310_LAUNCHXL_ADCBUF0 +#define Board_ADCBUF0CHANNEL0 CC1310_LAUNCHXL_ADCBUF0CHANNEL0 +#define Board_ADCBUF0CHANNEL1 CC1310_LAUNCHXL_ADCBUF0CHANNEL1 + +#define Board_CRYPTO0 CC1310_LAUNCHXL_CRYPTO0 + +#define Board_DIO0 CC1310_LAUNCHXL_DIO0 +#define Board_DIO1 CC1310_LAUNCHXL_DIO1 +#define Board_DIO12 CC1310_LAUNCHXL_DIO12 +#define Board_DIO15 CC1310_LAUNCHXL_DIO15 +#define Board_DIO16_TDO CC1310_LAUNCHXL_DIO16_TDO +#define Board_DIO17_TDI CC1310_LAUNCHXL_DIO17_TDI +#define Board_DIO21 CC1310_LAUNCHXL_DIO21 +#define Board_DIO22 CC1310_LAUNCHXL_DIO22 + +#define Board_GPIO_BUTTON0 CC1310_LAUNCHXL_GPIO_S1 +#define Board_GPIO_BUTTON1 CC1310_LAUNCHXL_GPIO_S2 +#define Board_GPIO_BTN1 CC1310_LAUNCHXL_GPIO_S1 +#define Board_GPIO_BTN2 CC1310_LAUNCHXL_GPIO_S2 +#define Board_GPIO_LED0 CC1310_LAUNCHXL_GPIO_LED_RED +#define Board_GPIO_LED1 CC1310_LAUNCHXL_GPIO_LED_GREEN +#define Board_GPIO_RLED CC1310_LAUNCHXL_GPIO_LED_RED +#define Board_GPIO_GLED CC1310_LAUNCHXL_GPIO_LED_GREEN +#define Board_GPIO_LED_ON CC1310_LAUNCHXL_GPIO_LED_ON +#define Board_GPIO_LED_OFF CC1310_LAUNCHXL_GPIO_LED_OFF + +#define Board_GPTIMER0A CC1310_LAUNCHXL_GPTIMER0A +#define Board_GPTIMER0B CC1310_LAUNCHXL_GPTIMER0B +#define Board_GPTIMER1A CC1310_LAUNCHXL_GPTIMER1A +#define Board_GPTIMER1B CC1310_LAUNCHXL_GPTIMER1B +#define Board_GPTIMER2A CC1310_LAUNCHXL_GPTIMER2A +#define Board_GPTIMER2B CC1310_LAUNCHXL_GPTIMER2B +#define Board_GPTIMER3A CC1310_LAUNCHXL_GPTIMER3A +#define Board_GPTIMER3B CC1310_LAUNCHXL_GPTIMER3B + +#define Board_I2C0 CC1310_LAUNCHXL_I2C0 +#define Board_I2C_TMP CC1310_LAUNCHXL_I2C0 + +#define Board_NVSINTERNAL CC1310_LAUNCHXL_NVSCC26XX0 +#define Board_NVSEXTERNAL CC1310_LAUNCHXL_NVSSPI25X0 + +#define Board_PIN_BUTTON0 CC1310_LAUNCHXL_PIN_BTN1 +#define Board_PIN_BUTTON1 CC1310_LAUNCHXL_PIN_BTN2 +#define Board_PIN_BTN1 CC1310_LAUNCHXL_PIN_BTN1 +#define Board_PIN_BTN2 CC1310_LAUNCHXL_PIN_BTN2 +#define Board_PIN_LED0 CC1310_LAUNCHXL_PIN_RLED +#define Board_PIN_LED1 CC1310_LAUNCHXL_PIN_GLED +#define Board_PIN_LED2 CC1310_LAUNCHXL_PIN_RLED +#define Board_PIN_RLED CC1310_LAUNCHXL_PIN_RLED +#define Board_PIN_GLED CC1310_LAUNCHXL_PIN_GLED + +#define Board_PWM0 CC1310_LAUNCHXL_PWM0 +#define Board_PWM1 CC1310_LAUNCHXL_PWM1 +#define Board_PWM2 CC1310_LAUNCHXL_PWM2 +#define Board_PWM3 CC1310_LAUNCHXL_PWM3 +#define Board_PWM4 CC1310_LAUNCHXL_PWM4 +#define Board_PWM5 CC1310_LAUNCHXL_PWM5 +#define Board_PWM6 CC1310_LAUNCHXL_PWM6 +#define Board_PWM7 CC1310_LAUNCHXL_PWM7 + +#define Board_SD0 CC1310_LAUNCHXL_SDSPI0 + +#define Board_SPI0 CC1310_LAUNCHXL_SPI0 +#define Board_SPI1 CC1310_LAUNCHXL_SPI1 +#define Board_SPI_FLASH_CS CC1310_LAUNCHXL_SPI_FLASH_CS +#define Board_FLASH_CS_ON 0 +#define Board_FLASH_CS_OFF 1 + +#define Board_SPI_MASTER CC1310_LAUNCHXL_SPI0 +#define Board_SPI_SLAVE CC1310_LAUNCHXL_SPI0 +#define Board_SPI_MASTER_READY CC1310_LAUNCHXL_SPI_MASTER_READY +#define Board_SPI_SLAVE_READY CC1310_LAUNCHXL_SPI_SLAVE_READY + +#define Board_UART0 CC1310_LAUNCHXL_UART0 + +#define Board_WATCHDOG0 CC1310_LAUNCHXL_WATCHDOG0 + +/* Board specific I2C addresses */ +#define Board_TMP_ADDR (0x40) +#define Board_SENSORS_BP_TMP_ADDR Board_TMP_ADDR + +#ifdef __cplusplus +} +#endif + +#endif /* __BOARD_H */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.c new file mode 100644 index 000000000..e073794c0 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.c @@ -0,0 +1,911 @@ +/* + * Copyright (c) 2015-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +/* + * ====================== CC1310_LAUNCHXL.c =================================== + * This file is responsible for setting up the board specific items for the + * CC1310_LAUNCHXL board. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "CC1310_LAUNCHXL.h" + +/* + * =============================== ADCBuf =============================== + */ +#include +#include + +ADCBufCC26XX_Object adcBufCC26xxObjects[CC1310_LAUNCHXL_ADCBUFCOUNT]; + +/* + * This table converts a virtual adc channel into a dio and internal analogue + * input signal. This table is necessary for the functioning of the adcBuf + * driver. Comment out unused entries to save flash. Dio and internal signal + * pairs are hardwired. Do not remap them in the table. You may reorder entire + * entries. The mapping of dio and internal signals is package dependent. + */ +const ADCBufCC26XX_AdcChannelLutEntry ADCBufCC26XX_adcChannelLut[CC1310_LAUNCHXL_ADCBUF0CHANNELCOUNT] = { + {CC1310_LAUNCHXL_DIO23_ANALOG, ADC_COMPB_IN_AUXIO7}, + {CC1310_LAUNCHXL_DIO24_ANALOG, ADC_COMPB_IN_AUXIO6}, + {CC1310_LAUNCHXL_DIO25_ANALOG, ADC_COMPB_IN_AUXIO5}, + {CC1310_LAUNCHXL_DIO26_ANALOG, ADC_COMPB_IN_AUXIO4}, + {CC1310_LAUNCHXL_DIO27_ANALOG, ADC_COMPB_IN_AUXIO3}, + {CC1310_LAUNCHXL_DIO28_ANALOG, ADC_COMPB_IN_AUXIO2}, + {CC1310_LAUNCHXL_DIO29_ANALOG, ADC_COMPB_IN_AUXIO1}, + {CC1310_LAUNCHXL_DIO30_ANALOG, ADC_COMPB_IN_AUXIO0}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VDDS}, + {PIN_UNASSIGNED, ADC_COMPB_IN_DCOUPL}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VSS}, +}; + +const ADCBufCC26XX_HWAttrs adcBufCC26xxHWAttrs[CC1310_LAUNCHXL_ADCBUFCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + .adcChannelLut = ADCBufCC26XX_adcChannelLut, + .gpTimerUnit = CC1310_LAUNCHXL_GPTIMER0A, + .gptDMAChannelMask = 1 << UDMA_CHAN_TIMER0_A, + } +}; + +const ADCBuf_Config ADCBuf_config[CC1310_LAUNCHXL_ADCBUFCOUNT] = { + { + &ADCBufCC26XX_fxnTable, + &adcBufCC26xxObjects[CC1310_LAUNCHXL_ADCBUF0], + &adcBufCC26xxHWAttrs[CC1310_LAUNCHXL_ADCBUF0] + }, +}; + +const uint_least8_t ADCBuf_count = CC1310_LAUNCHXL_ADCBUFCOUNT; + +/* + * =============================== ADC =============================== + */ +#include +#include + +ADCCC26XX_Object adcCC26xxObjects[CC1310_LAUNCHXL_ADCCOUNT]; + + +const ADCCC26XX_HWAttrs adcCC26xxHWAttrs[CC1310_LAUNCHXL_ADCCOUNT] = { + { + .adcDIO = CC1310_LAUNCHXL_DIO23_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO7, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1310_LAUNCHXL_DIO24_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO6, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1310_LAUNCHXL_DIO25_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO5, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1310_LAUNCHXL_DIO26_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO4, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1310_LAUNCHXL_DIO27_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO3, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1310_LAUNCHXL_DIO28_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO2, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1310_LAUNCHXL_DIO29_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO1, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1310_LAUNCHXL_DIO30_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO0, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_10P9_MS, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_DCOUPL, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VSS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VDDS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + } +}; + +const ADC_Config ADC_config[CC1310_LAUNCHXL_ADCCOUNT] = { + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1310_LAUNCHXL_ADC0], &adcCC26xxHWAttrs[CC1310_LAUNCHXL_ADC0]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1310_LAUNCHXL_ADC1], &adcCC26xxHWAttrs[CC1310_LAUNCHXL_ADC1]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1310_LAUNCHXL_ADC2], &adcCC26xxHWAttrs[CC1310_LAUNCHXL_ADC2]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1310_LAUNCHXL_ADC3], &adcCC26xxHWAttrs[CC1310_LAUNCHXL_ADC3]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1310_LAUNCHXL_ADC4], &adcCC26xxHWAttrs[CC1310_LAUNCHXL_ADC4]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1310_LAUNCHXL_ADC5], &adcCC26xxHWAttrs[CC1310_LAUNCHXL_ADC5]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1310_LAUNCHXL_ADC6], &adcCC26xxHWAttrs[CC1310_LAUNCHXL_ADC6]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1310_LAUNCHXL_ADC7], &adcCC26xxHWAttrs[CC1310_LAUNCHXL_ADC7]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1310_LAUNCHXL_ADCDCOUPL], &adcCC26xxHWAttrs[CC1310_LAUNCHXL_ADCDCOUPL]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1310_LAUNCHXL_ADCVSS], &adcCC26xxHWAttrs[CC1310_LAUNCHXL_ADCVSS]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1310_LAUNCHXL_ADCVDDS], &adcCC26xxHWAttrs[CC1310_LAUNCHXL_ADCVDDS]}, +}; + +const uint_least8_t ADC_count = CC1310_LAUNCHXL_ADCCOUNT; + +/* + * =============================== Crypto =============================== + */ +#include + +CryptoCC26XX_Object cryptoCC26XXObjects[CC1310_LAUNCHXL_CRYPTOCOUNT]; + +const CryptoCC26XX_HWAttrs cryptoCC26XXHWAttrs[CC1310_LAUNCHXL_CRYPTOCOUNT] = { + { + .baseAddr = CRYPTO_BASE, + .powerMngrId = PowerCC26XX_PERIPH_CRYPTO, + .intNum = INT_CRYPTO_RESULT_AVAIL_IRQ, + .intPriority = ~0, + } +}; + +const CryptoCC26XX_Config CryptoCC26XX_config[CC1310_LAUNCHXL_CRYPTOCOUNT] = { + { + .object = &cryptoCC26XXObjects[CC1310_LAUNCHXL_CRYPTO0], + .hwAttrs = &cryptoCC26XXHWAttrs[CC1310_LAUNCHXL_CRYPTO0] + } +}; + +/* + * =============================== Display =============================== + */ +#include +#include +#include + +#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE +#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 +#endif + +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 +#endif + +DisplayUart_Object displayUartObject; +DisplaySharp_Object displaySharpObject; + +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; +static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; + +const DisplayUart_HWAttrs displayUartHWAttrs = { + .uartIdx = CC1310_LAUNCHXL_UART0, + .baudRate = 115200, + .mutexTimeout = (unsigned int)(-1), + .strBuf = uartStringBuf, + .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, +}; + +const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { + .spiIndex = CC1310_LAUNCHXL_SPI0, + .csPin = CC1310_LAUNCHXL_GPIO_LCD_CS, + .powerPin = CC1310_LAUNCHXL_GPIO_LCD_POWER, + .enablePin = CC1310_LAUNCHXL_GPIO_LCD_ENABLE, + .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, + .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, + .displayBuf = sharpDisplayBuf, +}; + +#ifndef BOARD_DISPLAY_USE_UART +#define BOARD_DISPLAY_USE_UART 1 +#endif +#ifndef BOARD_DISPLAY_USE_UART_ANSI +#define BOARD_DISPLAY_USE_UART_ANSI 0 +#endif +#ifndef BOARD_DISPLAY_USE_LCD +#define BOARD_DISPLAY_USE_LCD 0 +#endif + +/* + * This #if/#else is needed to workaround a problem with the + * IAR compiler. The IAR compiler doesn't like the empty array + * initialization. (IAR Error[Pe1345]) + */ +#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) + +const Display_Config Display_config[] = { +#if (BOARD_DISPLAY_USE_UART) + { +# if (BOARD_DISPLAY_USE_UART_ANSI) + .fxnTablePtr = &DisplayUartAnsi_fxnTable, +# else /* Default to minimal UART with no cursor placement */ + .fxnTablePtr = &DisplayUartMin_fxnTable, +# endif + .object = &displayUartObject, + .hwAttrs = &displayUartHWAttrs, + }, +#endif +#if (BOARD_DISPLAY_USE_LCD) + { + .fxnTablePtr = &DisplaySharp_fxnTable, + .object = &displaySharpObject, + .hwAttrs = &displaySharpHWattrs + }, +#endif +}; + +const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); + +#else + +const Display_Config *Display_config = NULL; +const uint_least8_t Display_count = 0; + +#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ + +/* + * =============================== GPIO =============================== + */ +#include +#include + +/* + * Array of Pin configurations + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC1310_LAUNCHXL.h + * NOTE: Pins not used for interrupts should be placed at the end of the + * array. Callback entries can be omitted from callbacks array to + * reduce memory usage. + */ +GPIO_PinConfig gpioPinConfigs[] = { + /* Input pins */ + GPIOCC26XX_DIO_13 | GPIO_DO_NOT_CONFIG, /* Button 0 */ + GPIOCC26XX_DIO_14 | GPIO_DO_NOT_CONFIG, /* Button 1 */ + + GPIOCC26XX_DIO_15 | GPIO_DO_NOT_CONFIG, /* CC1310_LAUNCHXL_SPI_MASTER_READY */ + GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG, /* CC1310_LAUNCHXL_SPI_SLAVE_READY */ + + /* Output pins */ + GPIOCC26XX_DIO_07 | GPIO_DO_NOT_CONFIG, /* Green LED */ + GPIOCC26XX_DIO_06 | GPIO_DO_NOT_CONFIG, /* Red LED */ + + /* SPI Flash CSN */ + GPIOCC26XX_DIO_20 | GPIO_DO_NOT_CONFIG, + + /* SD CS */ + GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG, + + /* Sharp Display - GPIO configurations will be done in the Display files */ + GPIOCC26XX_DIO_24 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ + GPIOCC26XX_DIO_22 | GPIO_DO_NOT_CONFIG, /* LCD power control */ + GPIOCC26XX_DIO_23 | GPIO_DO_NOT_CONFIG, /*LCD enable */ + +}; + +/* + * Array of callback function pointers + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC1310_LAUNCH.h + * NOTE: Pins not used for interrupts can be omitted from callbacks array to + * reduce memory usage (if placed at end of gpioPinConfigs array). + */ +GPIO_CallbackFxn gpioCallbackFunctions[] = { + NULL, /* Button 0 */ + NULL, /* Button 1 */ + NULL, /* CC1310_LAUNCHXL_SPI_MASTER_READY */ + NULL, /* CC1310_LAUNCHXL_SPI_SLAVE_READY */ +}; + +const GPIOCC26XX_Config GPIOCC26XX_config = { + .pinConfigs = (GPIO_PinConfig *)gpioPinConfigs, + .callbacks = (GPIO_CallbackFxn *)gpioCallbackFunctions, + .numberOfPinConfigs = CC1310_LAUNCHXL_GPIOCOUNT, + .numberOfCallbacks = sizeof(gpioCallbackFunctions)/sizeof(GPIO_CallbackFxn), + .intPriority = (~0) +}; + +/* + * =============================== GPTimer =============================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +#include + +GPTimerCC26XX_Object gptimerCC26XXObjects[CC1310_LAUNCHXL_GPTIMERCOUNT]; + +const GPTimerCC26XX_HWAttrs gptimerCC26xxHWAttrs[CC1310_LAUNCHXL_GPTIMERPARTSCOUNT] = { + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0A, }, + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0B, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1A, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1B, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2A, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2B, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3A, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3B, }, +}; + +const GPTimerCC26XX_Config GPTimerCC26XX_config[CC1310_LAUNCHXL_GPTIMERPARTSCOUNT] = { + { &gptimerCC26XXObjects[CC1310_LAUNCHXL_GPTIMER0], &gptimerCC26xxHWAttrs[CC1310_LAUNCHXL_GPTIMER0A], GPT_A }, + { &gptimerCC26XXObjects[CC1310_LAUNCHXL_GPTIMER0], &gptimerCC26xxHWAttrs[CC1310_LAUNCHXL_GPTIMER0B], GPT_B }, + { &gptimerCC26XXObjects[CC1310_LAUNCHXL_GPTIMER1], &gptimerCC26xxHWAttrs[CC1310_LAUNCHXL_GPTIMER1A], GPT_A }, + { &gptimerCC26XXObjects[CC1310_LAUNCHXL_GPTIMER1], &gptimerCC26xxHWAttrs[CC1310_LAUNCHXL_GPTIMER1B], GPT_B }, + { &gptimerCC26XXObjects[CC1310_LAUNCHXL_GPTIMER2], &gptimerCC26xxHWAttrs[CC1310_LAUNCHXL_GPTIMER2A], GPT_A }, + { &gptimerCC26XXObjects[CC1310_LAUNCHXL_GPTIMER2], &gptimerCC26xxHWAttrs[CC1310_LAUNCHXL_GPTIMER2B], GPT_B }, + { &gptimerCC26XXObjects[CC1310_LAUNCHXL_GPTIMER3], &gptimerCC26xxHWAttrs[CC1310_LAUNCHXL_GPTIMER3A], GPT_A }, + { &gptimerCC26XXObjects[CC1310_LAUNCHXL_GPTIMER3], &gptimerCC26xxHWAttrs[CC1310_LAUNCHXL_GPTIMER3B], GPT_B }, +}; + +/* + * =============================== I2C =============================== +*/ +#include +#include + +I2CCC26XX_Object i2cCC26xxObjects[CC1310_LAUNCHXL_I2CCOUNT]; + +const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1310_LAUNCHXL_I2CCOUNT] = { + { + .baseAddr = I2C0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_I2C0, + .intNum = INT_I2C_IRQ, + .intPriority = ~0, + .swiPriority = 0, + .sdaPin = CC1310_LAUNCHXL_I2C0_SDA0, + .sclPin = CC1310_LAUNCHXL_I2C0_SCL0, + } +}; + +const I2C_Config I2C_config[CC1310_LAUNCHXL_I2CCOUNT] = { + { + .fxnTablePtr = &I2CCC26XX_fxnTable, + .object = &i2cCC26xxObjects[CC1310_LAUNCHXL_I2C0], + .hwAttrs = &i2cCC26xxHWAttrs[CC1310_LAUNCHXL_I2C0] + } +}; + +const uint_least8_t I2C_count = CC1310_LAUNCHXL_I2CCOUNT; + +/* + * =============================== NVS =============================== + */ +#include +#include +#include + +#define NVS_REGIONS_BASE 0x1A000 +#define SECTORSIZE 0x1000 +#define REGIONSIZE (SECTORSIZE * 4) +#define SPIREGIONSIZE (SECTORSIZE * 32) +#define VERIFYBUFSIZE 64 + +static uint8_t verifyBuf[VERIFYBUFSIZE]; + +/* + * Reserve flash sectors for NVS driver use by placing an uninitialized byte + * array at the desired flash address. + */ +#if defined(__TI_COMPILER_VERSION__) + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +#pragma LOCATION(flashBuf, NVS_REGIONS_BASE); +#pragma NOINIT(flashBuf); +static char flashBuf[REGIONSIZE]; + +#elif defined(__IAR_SYSTEMS_ICC__) + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +static __no_init char flashBuf[REGIONSIZE] @ NVS_REGIONS_BASE; + +#elif defined(__GNUC__) + +/* + * Place the flash buffers in the .nvs section created in the gcc linker file. + * The .nvs section enforces alignment on a sector boundary but may + * be placed anywhere in flash memory. If desired the .nvs section can be set + * to a fixed address by changing the following in the gcc linker file: + * + * .nvs (FIXED_FLASH_ADDR) (NOLOAD) : AT (FIXED_FLASH_ADDR) { + * *(.nvs) + * } > REGION_TEXT + */ +__attribute__ ((section (".nvs"))) +static char flashBuf[REGIONSIZE]; + +#endif + +/* Allocate objects for NVS and NVS SPI */ +NVSCC26XX_Object nvsCC26xxObjects[1]; +NVSSPI25X_Object nvsSPI25XObjects[1]; + +/* Hardware attributes for NVS */ +const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { + { + .regionBase = (void *)flashBuf, + .regionSize = REGIONSIZE, + }, +}; + +/* Hardware attributes for NVS SPI */ +const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { + { + .regionBaseOffset = 0, + .regionSize = SPIREGIONSIZE, + .sectorSize = SECTORSIZE, + .verifyBuf = verifyBuf, + .verifyBufSize = VERIFYBUFSIZE, + .spiHandle = NULL, + .spiIndex = 0, + .spiBitRate = 4000000, + .spiCsnGpioIndex = CC1310_LAUNCHXL_GPIO_SPI_FLASH_CS, + }, +}; + +/* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ +const NVS_Config NVS_config[CC1310_LAUNCHXL_NVSCOUNT] = { + { + .fxnTablePtr = &NVSCC26XX_fxnTable, + .object = &nvsCC26xxObjects[0], + .hwAttrs = &nvsCC26xxHWAttrs[0], + }, + { + .fxnTablePtr = &NVSSPI25X_fxnTable, + .object = &nvsSPI25XObjects[0], + .hwAttrs = &nvsSPI25XHWAttrs[0], + }, +}; + +const uint_least8_t NVS_count = CC1310_LAUNCHXL_NVSCOUNT; + +/* + * =============================== PIN =============================== + */ +#include +#include + +const PIN_Config BoardGpioInitTable[] = { + + CC1310_LAUNCHXL_PIN_RLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC1310_LAUNCHXL_PIN_GLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC1310_LAUNCHXL_PIN_BTN1 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC1310_LAUNCHXL_PIN_BTN2 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC1310_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ + CC1310_LAUNCHXL_UART_RX | PIN_INPUT_EN | PIN_PULLDOWN, /* UART RX via debugger back channel */ + CC1310_LAUNCHXL_UART_TX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* UART TX via debugger back channel */ + CC1310_LAUNCHXL_SPI0_MOSI | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master out - slave in */ + CC1310_LAUNCHXL_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master in - slave out */ + CC1310_LAUNCHXL_SPI0_CLK | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI clock */ + + PIN_TERMINATE +}; + +const PINCC26XX_HWAttrs PINCC26XX_hwAttrs = { + .intPriority = ~0, + .swiPriority = 0 +}; + +/* + * =============================== Power =============================== + */ +#include +#include + +const PowerCC26XX_Config PowerCC26XX_config = { + .policyInitFxn = NULL, + .policyFxn = &PowerCC26XX_standbyPolicy, + .calibrateFxn = &PowerCC26XX_calibrate, + .enablePolicy = true, + .calibrateRCOSC_LF = true, + .calibrateRCOSC_HF = true, +}; + +/* + * =============================== PWM =============================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +#include +#include + +PWMTimerCC26XX_Object pwmtimerCC26xxObjects[CC1310_LAUNCHXL_PWMCOUNT]; + +const PWMTimerCC26XX_HwAttrs pwmtimerCC26xxHWAttrs[CC1310_LAUNCHXL_PWMCOUNT] = { + { .pwmPin = CC1310_LAUNCHXL_PWMPIN0, .gpTimerUnit = CC1310_LAUNCHXL_GPTIMER0A }, + { .pwmPin = CC1310_LAUNCHXL_PWMPIN1, .gpTimerUnit = CC1310_LAUNCHXL_GPTIMER0B }, + { .pwmPin = CC1310_LAUNCHXL_PWMPIN2, .gpTimerUnit = CC1310_LAUNCHXL_GPTIMER1A }, + { .pwmPin = CC1310_LAUNCHXL_PWMPIN3, .gpTimerUnit = CC1310_LAUNCHXL_GPTIMER1B }, + { .pwmPin = CC1310_LAUNCHXL_PWMPIN4, .gpTimerUnit = CC1310_LAUNCHXL_GPTIMER2A }, + { .pwmPin = CC1310_LAUNCHXL_PWMPIN5, .gpTimerUnit = CC1310_LAUNCHXL_GPTIMER2B }, + { .pwmPin = CC1310_LAUNCHXL_PWMPIN6, .gpTimerUnit = CC1310_LAUNCHXL_GPTIMER3A }, + { .pwmPin = CC1310_LAUNCHXL_PWMPIN7, .gpTimerUnit = CC1310_LAUNCHXL_GPTIMER3B }, +}; + +const PWM_Config PWM_config[CC1310_LAUNCHXL_PWMCOUNT] = { + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1310_LAUNCHXL_PWM0], &pwmtimerCC26xxHWAttrs[CC1310_LAUNCHXL_PWM0] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1310_LAUNCHXL_PWM1], &pwmtimerCC26xxHWAttrs[CC1310_LAUNCHXL_PWM1] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1310_LAUNCHXL_PWM2], &pwmtimerCC26xxHWAttrs[CC1310_LAUNCHXL_PWM2] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1310_LAUNCHXL_PWM3], &pwmtimerCC26xxHWAttrs[CC1310_LAUNCHXL_PWM3] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1310_LAUNCHXL_PWM4], &pwmtimerCC26xxHWAttrs[CC1310_LAUNCHXL_PWM4] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1310_LAUNCHXL_PWM5], &pwmtimerCC26xxHWAttrs[CC1310_LAUNCHXL_PWM5] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1310_LAUNCHXL_PWM6], &pwmtimerCC26xxHWAttrs[CC1310_LAUNCHXL_PWM6] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1310_LAUNCHXL_PWM7], &pwmtimerCC26xxHWAttrs[CC1310_LAUNCHXL_PWM7] }, +}; + +const uint_least8_t PWM_count = CC1310_LAUNCHXL_PWMCOUNT; + +/* + * =============================== RF Driver =============================== + */ +#include + +const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { + .hwiPriority = ~0, /* Lowest HWI priority */ + .swiPriority = 0, /* Lowest SWI priority */ + .xoscHfAlwaysNeeded = true, /* Keep XOSC dependency while in stanby */ + .globalCallback = NULL, /* No board specific callback */ + .globalEventMask = 0 /* No events subscribed to */ +}; + +/* + * =============================== SD =============================== + */ +#include +#include + +SDSPI_Object sdspiObjects[CC1310_LAUNCHXL_SDCOUNT]; + +const SDSPI_HWAttrs sdspiHWAttrs[CC1310_LAUNCHXL_SDCOUNT] = { + { + .spiIndex = CC1310_LAUNCHXL_SPI0, + .spiCsGpioIndex = CC1310_LAUNCHXL_SDSPI_CS + } +}; + +const SD_Config SD_config[CC1310_LAUNCHXL_SDCOUNT] = { + { + .fxnTablePtr = &SDSPI_fxnTable, + .object = &sdspiObjects[CC1310_LAUNCHXL_SDSPI0], + .hwAttrs = &sdspiHWAttrs[CC1310_LAUNCHXL_SDSPI0] + }, +}; + +const uint_least8_t SD_count = CC1310_LAUNCHXL_SDCOUNT; + +/* + * =============================== SPI DMA =============================== + */ +#include +#include + +SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1310_LAUNCHXL_SPICOUNT]; + +/* + * NOTE: The SPI instances below can be used by the SD driver to communicate + * with a SD card via SPI. The 'defaultTxBufValue' fields below are set to 0xFF + * to satisfy the SDSPI driver requirement. + */ +const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1310_LAUNCHXL_SPICOUNT] = { + { + .baseAddr = SSI0_BASE, + .intNum = INT_SSI0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .powerMngrId = PowerCC26XX_PERIPH_SSI0, + .defaultTxBufValue = 0xFF, + .rxChannelBitMask = 1< +#include + +UARTCC26XX_Object uartCC26XXObjects[CC1310_LAUNCHXL_UARTCOUNT]; + +uint8_t uartCC26XXRingBuffer[CC1310_LAUNCHXL_UARTCOUNT][32]; + +const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1310_LAUNCHXL_UARTCOUNT] = { + { + .baseAddr = UART0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UART0, + .intNum = INT_UART0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .txPin = CC1310_LAUNCHXL_UART_TX, + .rxPin = CC1310_LAUNCHXL_UART_RX, + .ctsPin = PIN_UNASSIGNED, + .rtsPin = PIN_UNASSIGNED, + .ringBufPtr = uartCC26XXRingBuffer[CC1310_LAUNCHXL_UART0], + .ringBufSize = sizeof(uartCC26XXRingBuffer[CC1310_LAUNCHXL_UART0]), + .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, + .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, + .errorFxn = NULL + } +}; + +const UART_Config UART_config[CC1310_LAUNCHXL_UARTCOUNT] = { + { + .fxnTablePtr = &UARTCC26XX_fxnTable, + .object = &uartCC26XXObjects[CC1310_LAUNCHXL_UART0], + .hwAttrs = &uartCC26XXHWAttrs[CC1310_LAUNCHXL_UART0] + }, +}; + +const uint_least8_t UART_count = CC1310_LAUNCHXL_UARTCOUNT; + +/* + * =============================== UDMA =============================== + */ +#include + +UDMACC26XX_Object udmaObjects[CC1310_LAUNCHXL_UDMACOUNT]; + +const UDMACC26XX_HWAttrs udmaHWAttrs[CC1310_LAUNCHXL_UDMACOUNT] = { + { + .baseAddr = UDMA0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UDMA, + .intNum = INT_DMA_ERR, + .intPriority = ~0 + } +}; + +const UDMACC26XX_Config UDMACC26XX_config[CC1310_LAUNCHXL_UDMACOUNT] = { + { + .object = &udmaObjects[CC1310_LAUNCHXL_UDMA0], + .hwAttrs = &udmaHWAttrs[CC1310_LAUNCHXL_UDMA0] + }, +}; + +/* + * =============================== Watchdog =============================== + */ +#include +#include + +WatchdogCC26XX_Object watchdogCC26XXObjects[CC1310_LAUNCHXL_WATCHDOGCOUNT]; + +const WatchdogCC26XX_HWAttrs watchdogCC26XXHWAttrs[CC1310_LAUNCHXL_WATCHDOGCOUNT] = { + { + .baseAddr = WDT_BASE, + .reloadValue = 1000 /* Reload value in milliseconds */ + }, +}; + +const Watchdog_Config Watchdog_config[CC1310_LAUNCHXL_WATCHDOGCOUNT] = { + { + .fxnTablePtr = &WatchdogCC26XX_fxnTable, + .object = &watchdogCC26XXObjects[CC1310_LAUNCHXL_WATCHDOG0], + .hwAttrs = &watchdogCC26XXHWAttrs[CC1310_LAUNCHXL_WATCHDOG0] + }, +}; + +const uint_least8_t Watchdog_count = CC1310_LAUNCHXL_WATCHDOGCOUNT; + +/* + * ======== CC1310_LAUNCHXL_wakeUpExtFlash ======== + */ +void CC1310_LAUNCHXL_wakeUpExtFlash(void) +{ + PIN_Config extFlashPinTable[] = { + CC1310_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + /* + * To wake up we need to toggle the chip select at + * least 20 ns and ten wait at least 35 us. + */ + + /* Toggle chip select for ~20ns to wake ext. flash */ + PIN_setOutputValue(extFlashPinHandle, CC1310_LAUNCHXL_SPI_FLASH_CS, 0); + /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ + CPUdelay(1); + PIN_setOutputValue(extFlashPinHandle, CC1310_LAUNCHXL_SPI_FLASH_CS, 1); + /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ + CPUdelay(560); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC1310_LAUNCHXL_sendExtFlashByte ======== + */ +void CC1310_LAUNCHXL_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) +{ + uint8_t i; + + PIN_setOutputValue(pinHandle, CC1310_LAUNCHXL_SPI_FLASH_CS, 0); + + for (i = 0; i < 8; i++) { + PIN_setOutputValue(pinHandle, CC1310_LAUNCHXL_SPI0_CLK, 0); + PIN_setOutputValue(pinHandle, CC1310_LAUNCHXL_SPI0_MOSI, (byte >> (7 - i)) & 0x01); + PIN_setOutputValue(pinHandle, CC1310_LAUNCHXL_SPI0_CLK, 1); + + /* + * Waste a few cycles to keep the CLK high for at + * least 45% of the period. + * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. + */ + CPUdelay(8); + } + + PIN_setOutputValue(pinHandle, CC1310_LAUNCHXL_SPI0_CLK, 0); + PIN_setOutputValue(pinHandle, CC1310_LAUNCHXL_SPI_FLASH_CS, 1); + + /* + * Keep CS high at least 40 us + * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us + */ + CPUdelay(700); +} + +/* + * ======== CC1310_LAUNCHXL_shutDownExtFlash ======== + */ +void CC1310_LAUNCHXL_shutDownExtFlash(void) +{ + /* To be sure we are putting the flash into sleep and not waking it, we first have to make a wake up call */ + CC1310_LAUNCHXL_wakeUpExtFlash(); + + PIN_Config extFlashPinTable[] = { + CC1310_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + CC1310_LAUNCHXL_SPI0_CLK | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + CC1310_LAUNCHXL_SPI0_MOSI | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + CC1310_LAUNCHXL_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + uint8_t extFlashShutdown = 0xB9; + + CC1310_LAUNCHXL_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC1310_LAUNCHXL_initGeneral ======== + */ +void CC1310_LAUNCHXL_initGeneral(void) +{ + Power_init(); + + if (PIN_init(BoardGpioInitTable) != PIN_SUCCESS) { + /* Error with PIN_init */ + while (1); + } + + /* Shut down external flash as default */ + CC1310_LAUNCHXL_shutDownExtFlash(); +} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h new file mode 100644 index 000000000..28e3136ca --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2015-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ +/** ============================================================================ + * @file CC1310_LAUNCHXL.h + * + * @brief CC1310 LaunchPad Board Specific header file. + * + * The CC1310_LAUNCHXL header file should be included in an application as + * follows: + * @code + * #include "CC1310_LAUNCHXL.h" + * @endcode + * + * ============================================================================ + */ +#ifndef __CC1310_LAUNCHXL_BOARD_H__ +#define __CC1310_LAUNCHXL_BOARD_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes */ +#include +#include + +/* Externs */ +extern const PIN_Config BoardGpioInitTable[]; + +/* Defines */ +#define CC1310_LAUNCHXL + +/* Mapping of pins to board signals using general board aliases + * + */ + +/* Analog capable DIOs */ +#define CC1310_LAUNCHXL_DIO23_ANALOG IOID_23 +#define CC1310_LAUNCHXL_DIO24_ANALOG IOID_24 +#define CC1310_LAUNCHXL_DIO25_ANALOG IOID_25 +#define CC1310_LAUNCHXL_DIO26_ANALOG IOID_26 +#define CC1310_LAUNCHXL_DIO27_ANALOG IOID_27 +#define CC1310_LAUNCHXL_DIO28_ANALOG IOID_28 +#define CC1310_LAUNCHXL_DIO29_ANALOG IOID_29 +#define CC1310_LAUNCHXL_DIO30_ANALOG IOID_30 + +/* Digital IOs */ +#define CC1310_LAUNCHXL_DIO0 IOID_0 +#define CC1310_LAUNCHXL_DIO1 IOID_1 +#define CC1310_LAUNCHXL_DIO12 IOID_12 +#define CC1310_LAUNCHXL_DIO15 IOID_15 +#define CC1310_LAUNCHXL_DIO16_TDO IOID_16 +#define CC1310_LAUNCHXL_DIO17_TDI IOID_17 +#define CC1310_LAUNCHXL_DIO21 IOID_21 +#define CC1310_LAUNCHXL_DIO22 IOID_22 + +/* Discrete Inputs */ +#define CC1310_LAUNCHXL_PIN_BTN1 IOID_13 +#define CC1310_LAUNCHXL_PIN_BTN2 IOID_14 + +/* GPIO */ +#define CC1310_LAUNCHXL_GPIO_LED_ON 1 +#define CC1310_LAUNCHXL_GPIO_LED_OFF 0 + +/* I2C */ +#define CC1310_LAUNCHXL_I2C0_SCL0 IOID_4 +#define CC1310_LAUNCHXL_I2C0_SDA0 IOID_5 + +/* LEDs */ +#define CC1310_LAUNCHXL_PIN_LED_ON 1 +#define CC1310_LAUNCHXL_PIN_LED_OFF 0 +#define CC1310_LAUNCHXL_PIN_RLED IOID_6 +#define CC1310_LAUNCHXL_PIN_GLED IOID_7 + +/* PWM Outputs */ +#define CC1310_LAUNCHXL_PWMPIN0 CC1310_LAUNCHXL_PIN_RLED +#define CC1310_LAUNCHXL_PWMPIN1 CC1310_LAUNCHXL_PIN_GLED +#define CC1310_LAUNCHXL_PWMPIN2 PIN_UNASSIGNED +#define CC1310_LAUNCHXL_PWMPIN3 PIN_UNASSIGNED +#define CC1310_LAUNCHXL_PWMPIN4 PIN_UNASSIGNED +#define CC1310_LAUNCHXL_PWMPIN5 PIN_UNASSIGNED +#define CC1310_LAUNCHXL_PWMPIN6 PIN_UNASSIGNED +#define CC1310_LAUNCHXL_PWMPIN7 PIN_UNASSIGNED + +/* SPI */ +#define CC1310_LAUNCHXL_SPI_FLASH_CS IOID_20 +#define CC1310_LAUNCHXL_FLASH_CS_ON 0 +#define CC1310_LAUNCHXL_FLASH_CS_OFF 1 + +/* SPI Board */ +#define CC1310_LAUNCHXL_SPI0_MISO IOID_8 /* RF1.20 */ +#define CC1310_LAUNCHXL_SPI0_MOSI IOID_9 /* RF1.18 */ +#define CC1310_LAUNCHXL_SPI0_CLK IOID_10 /* RF1.16 */ +#define CC1310_LAUNCHXL_SPI0_CSN PIN_UNASSIGNED +#define CC1310_LAUNCHXL_SPI1_MISO PIN_UNASSIGNED +#define CC1310_LAUNCHXL_SPI1_MOSI PIN_UNASSIGNED +#define CC1310_LAUNCHXL_SPI1_CLK PIN_UNASSIGNED +#define CC1310_LAUNCHXL_SPI1_CSN PIN_UNASSIGNED + +/* UART Board */ +#define CC1310_LAUNCHXL_UART_RX IOID_2 /* RXD */ +#define CC1310_LAUNCHXL_UART_TX IOID_3 /* TXD */ +#define CC1310_LAUNCHXL_UART_CTS IOID_19 /* CTS */ +#define CC1310_LAUNCHXL_UART_RTS IOID_18 /* RTS */ + +/*! + * @brief Initialize the general board specific settings + * + * This function initializes the general board specific settings. + */ +void CC1310_LAUNCHXL_initGeneral(void); + +/*! + * @brief Turn off the external flash on LaunchPads + * + */ +void CC1310_LAUNCHXL_shutDownExtFlash(void); + +/*! + * @brief Wake up the external flash present on the board files + * + * This function toggles the chip select for the amount of time needed + * to wake the chip up. + */ +void CC1310_LAUNCHXL_wakeUpExtFlash(void); + +/*! + * @def CC1310_LAUNCHXL_ADCBufName + * @brief Enum of ADCBufs + */ +typedef enum CC1310_LAUNCHXL_ADCBufName { + CC1310_LAUNCHXL_ADCBUF0 = 0, + + CC1310_LAUNCHXL_ADCBUFCOUNT +} CC1310_LAUNCHXL_ADCBufName; + +/*! + * @def CC1310_LAUNCHXL_ADCBuf0SourceName + * @brief Enum of ADCBuf channels + */ +typedef enum CC1310_LAUNCHXL_ADCBuf0ChannelName { + CC1310_LAUNCHXL_ADCBUF0CHANNEL0 = 0, + CC1310_LAUNCHXL_ADCBUF0CHANNEL1, + CC1310_LAUNCHXL_ADCBUF0CHANNEL2, + CC1310_LAUNCHXL_ADCBUF0CHANNEL3, + CC1310_LAUNCHXL_ADCBUF0CHANNEL4, + CC1310_LAUNCHXL_ADCBUF0CHANNEL5, + CC1310_LAUNCHXL_ADCBUF0CHANNEL6, + CC1310_LAUNCHXL_ADCBUF0CHANNEL7, + CC1310_LAUNCHXL_ADCBUF0CHANNELVDDS, + CC1310_LAUNCHXL_ADCBUF0CHANNELDCOUPL, + CC1310_LAUNCHXL_ADCBUF0CHANNELVSS, + + CC1310_LAUNCHXL_ADCBUF0CHANNELCOUNT +} CC1310_LAUNCHXL_ADCBuf0ChannelName; + +/*! + * @def CC1310_LAUNCHXL_ADCName + * @brief Enum of ADCs + */ +typedef enum CC1310_LAUNCHXL_ADCName { + CC1310_LAUNCHXL_ADC0 = 0, + CC1310_LAUNCHXL_ADC1, + CC1310_LAUNCHXL_ADC2, + CC1310_LAUNCHXL_ADC3, + CC1310_LAUNCHXL_ADC4, + CC1310_LAUNCHXL_ADC5, + CC1310_LAUNCHXL_ADC6, + CC1310_LAUNCHXL_ADC7, + CC1310_LAUNCHXL_ADCDCOUPL, + CC1310_LAUNCHXL_ADCVSS, + CC1310_LAUNCHXL_ADCVDDS, + + CC1310_LAUNCHXL_ADCCOUNT +} CC1310_LAUNCHXL_ADCName; + +/*! + * @def CC1310_LAUNCHXL_CryptoName + * @brief Enum of Crypto names + */ +typedef enum CC1310_LAUNCHXL_CryptoName { + CC1310_LAUNCHXL_CRYPTO0 = 0, + + CC1310_LAUNCHXL_CRYPTOCOUNT +} CC1310_LAUNCHXL_CryptoName; + +/*! + * @def CC1310_LAUNCHXL_GPIOName + * @brief Enum of GPIO names + */ +typedef enum CC1310_LAUNCHXL_GPIOName { + CC1310_LAUNCHXL_GPIO_S1 = 0, + CC1310_LAUNCHXL_GPIO_S2, + CC1310_LAUNCHXL_SPI_MASTER_READY, + CC1310_LAUNCHXL_SPI_SLAVE_READY, + CC1310_LAUNCHXL_GPIO_LED_GREEN, + CC1310_LAUNCHXL_GPIO_LED_RED, + CC1310_LAUNCHXL_GPIO_SPI_FLASH_CS, + CC1310_LAUNCHXL_SDSPI_CS, + CC1310_LAUNCHXL_GPIO_LCD_CS, + CC1310_LAUNCHXL_GPIO_LCD_POWER, + CC1310_LAUNCHXL_GPIO_LCD_ENABLE, + CC1310_LAUNCHXL_GPIOCOUNT +} CC1310_LAUNCHXL_GPIOName; + +/*! + * @def CC1310_LAUNCHXL_GPTimerName + * @brief Enum of GPTimer parts + */ +typedef enum CC1310_LAUNCHXL_GPTimerName { + CC1310_LAUNCHXL_GPTIMER0A = 0, + CC1310_LAUNCHXL_GPTIMER0B, + CC1310_LAUNCHXL_GPTIMER1A, + CC1310_LAUNCHXL_GPTIMER1B, + CC1310_LAUNCHXL_GPTIMER2A, + CC1310_LAUNCHXL_GPTIMER2B, + CC1310_LAUNCHXL_GPTIMER3A, + CC1310_LAUNCHXL_GPTIMER3B, + + CC1310_LAUNCHXL_GPTIMERPARTSCOUNT +} CC1310_LAUNCHXL_GPTimerName; + +/*! + * @def CC1310_LAUNCHXL_GPTimers + * @brief Enum of GPTimers + */ +typedef enum CC1310_LAUNCHXL_GPTimers { + CC1310_LAUNCHXL_GPTIMER0 = 0, + CC1310_LAUNCHXL_GPTIMER1, + CC1310_LAUNCHXL_GPTIMER2, + CC1310_LAUNCHXL_GPTIMER3, + + CC1310_LAUNCHXL_GPTIMERCOUNT +} CC1310_LAUNCHXL_GPTimers; + +/*! + * @def CC1310_LAUNCHXL_I2CName + * @brief Enum of I2C names + */ +typedef enum CC1310_LAUNCHXL_I2CName { + CC1310_LAUNCHXL_I2C0 = 0, + + CC1310_LAUNCHXL_I2CCOUNT +} CC1310_LAUNCHXL_I2CName; + +/*! + * @def CC1310_LAUNCHXL_NVSName + * @brief Enum of NVS names + */ +typedef enum CC1310_LAUNCHXL_NVSName { + CC1310_LAUNCHXL_NVSCC26XX0 = 0, + CC1310_LAUNCHXL_NVSSPI25X0, + + CC1310_LAUNCHXL_NVSCOUNT +} CC1310_LAUNCHXL_NVSName; + +/*! + * @def CC1310_LAUNCHXL_PWM + * @brief Enum of PWM outputs + */ +typedef enum CC1310_LAUNCHXL_PWMName { + CC1310_LAUNCHXL_PWM0 = 0, + CC1310_LAUNCHXL_PWM1, + CC1310_LAUNCHXL_PWM2, + CC1310_LAUNCHXL_PWM3, + CC1310_LAUNCHXL_PWM4, + CC1310_LAUNCHXL_PWM5, + CC1310_LAUNCHXL_PWM6, + CC1310_LAUNCHXL_PWM7, + + CC1310_LAUNCHXL_PWMCOUNT +} CC1310_LAUNCHXL_PWMName; + +/*! + * @def CC1310_LAUNCHXL_SDName + * @brief Enum of SD names + */ +typedef enum CC1310_LAUNCHXL_SDName { + CC1310_LAUNCHXL_SDSPI0 = 0, + + CC1310_LAUNCHXL_SDCOUNT +} CC1310_LAUNCHXL_SDName; + +/*! + * @def CC1310_LAUNCHXL_SPIName + * @brief Enum of SPI names + */ +typedef enum CC1310_LAUNCHXL_SPIName { + CC1310_LAUNCHXL_SPI0 = 0, + CC1310_LAUNCHXL_SPI1, + + CC1310_LAUNCHXL_SPICOUNT +} CC1310_LAUNCHXL_SPIName; + +/*! + * @def CC1310_LAUNCHXL_UARTName + * @brief Enum of UARTs + */ +typedef enum CC1310_LAUNCHXL_UARTName { + CC1310_LAUNCHXL_UART0 = 0, + + CC1310_LAUNCHXL_UARTCOUNT +} CC1310_LAUNCHXL_UARTName; + +/*! + * @def CC1310_LAUNCHXL_UDMAName + * @brief Enum of DMA buffers + */ +typedef enum CC1310_LAUNCHXL_UDMAName { + CC1310_LAUNCHXL_UDMA0 = 0, + + CC1310_LAUNCHXL_UDMACOUNT +} CC1310_LAUNCHXL_UDMAName; + +/*! + * @def CC1310_LAUNCHXL_WatchdogName + * @brief Enum of Watchdogs + */ +typedef enum CC1310_LAUNCHXL_WatchdogName { + CC1310_LAUNCHXL_WATCHDOG0 = 0, + + CC1310_LAUNCHXL_WATCHDOGCOUNT +} CC1310_LAUNCHXL_WatchdogName; + + +#ifdef __cplusplus +} +#endif + +#endif /* __CC1310_LAUNCHXL_BOARD_H__ */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Makefile.cc1310 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Makefile.cc1310 new file mode 100644 index 000000000..c372170bb --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Makefile.cc1310 @@ -0,0 +1,16 @@ +################################################################################ +# SimpleLink Device makefile + +SUBFAMILY = cc13x0-cc26x0 +DEVICE_FAMILY = CC13X0 + +BOARD_SOURCEFILES += CC1310_LAUNCHXL.c + +SUPPORTS_PROP_MODE = 1 +SUPPORTS_IEEE_MODE = 0 + +### Signal that we can be programmed with cc2538-bsl +BOARD_SUPPORTS_BSL = 1 + +# Include the common board makefile +include $(FAMILY_PATH)/launchpad/Makefile.launchpad diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Board.h new file mode 100644 index 000000000..091059d77 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Board.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2015-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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 __BOARD_H +#define __BOARD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "CC1312R1_LAUNCHXL.h" + +#define Board_initGeneral() CC1312R1_LAUNCHXL_initGeneral() +#define Board_shutDownExtFlash() CC1312R1_LAUNCHXL_shutDownExtFlash() +#define Board_wakeUpExtFlash() CC1312R1_LAUNCHXL_wakeUpExtFlash() + +/* These #defines allow us to reuse TI-RTOS across other device families */ + +#define Board_ADC0 CC1312R1_LAUNCHXL_ADC0 +#define Board_ADC1 CC1312R1_LAUNCHXL_ADC1 + +#define Board_ADCBUF0 CC1312R1_LAUNCHXL_ADCBUF0 +#define Board_ADCBUF0CHANNEL0 CC1312R1_LAUNCHXL_ADCBUF0CHANNEL0 +#define Board_ADCBUF0CHANNEL1 CC1312R1_LAUNCHXL_ADCBUF0CHANNEL1 + +#define Board_ECDH0 CC1312R1_LAUNCHXL_ECDH0 +#define Board_ECDSA0 CC1312R1_LAUNCHXL_ECDSA0 +#define Board_ECJPAKE0 CC1312R1_LAUNCHXL_ECJPAKE0 +#define Board_AESCCM0 CC1312R1_LAUNCHXL_AESCCM0 +#define Board_AESECB0 CC1312R1_LAUNCHXL_AESECB0 +#define Board_SHA20 CC1312R1_LAUNCHXL_SHA20 + +#define Board_DIO0 CC1312R1_LAUNCHXL_DIO0 +#define Board_DIO1 CC1312R1_LAUNCHXL_DIO1 +#define Board_DIO12 CC1312R1_LAUNCHXL_DIO12 +#define Board_DIO15 CC1312R1_LAUNCHXL_DIO15 +#define Board_DIO16_TDO CC1312R1_LAUNCHXL_DIO16_TDO +#define Board_DIO17_TDI CC1312R1_LAUNCHXL_DIO17_TDI +#define Board_DIO21 CC1312R1_LAUNCHXL_DIO21 +#define Board_DIO22 CC1312R1_LAUNCHXL_DIO22 + +#define Board_GPIO_BUTTON0 CC1312R1_LAUNCHXL_GPIO_S1 +#define Board_GPIO_BUTTON1 CC1312R1_LAUNCHXL_GPIO_S2 +#define Board_GPIO_BTN1 CC1312R1_LAUNCHXL_GPIO_S1 +#define Board_GPIO_BTN2 CC1312R1_LAUNCHXL_GPIO_S2 +#define Board_GPIO_LED0 CC1312R1_LAUNCHXL_GPIO_LED_RED +#define Board_GPIO_LED1 CC1312R1_LAUNCHXL_GPIO_LED_GREEN +#define Board_GPIO_RLED CC1312R1_LAUNCHXL_GPIO_LED_RED +#define Board_GPIO_GLED CC1312R1_LAUNCHXL_GPIO_LED_GREEN +#define Board_GPIO_LED_ON CC1312R1_LAUNCHXL_GPIO_LED_ON +#define Board_GPIO_LED_OFF CC1312R1_LAUNCHXL_GPIO_LED_OFF + +#define Board_GPTIMER0A CC1312R1_LAUNCHXL_GPTIMER0A +#define Board_GPTIMER0B CC1312R1_LAUNCHXL_GPTIMER0B +#define Board_GPTIMER1A CC1312R1_LAUNCHXL_GPTIMER1A +#define Board_GPTIMER1B CC1312R1_LAUNCHXL_GPTIMER1B +#define Board_GPTIMER2A CC1312R1_LAUNCHXL_GPTIMER2A +#define Board_GPTIMER2B CC1312R1_LAUNCHXL_GPTIMER2B +#define Board_GPTIMER3A CC1312R1_LAUNCHXL_GPTIMER3A +#define Board_GPTIMER3B CC1312R1_LAUNCHXL_GPTIMER3B + +#define Board_I2C0 CC1312R1_LAUNCHXL_I2C0 +#define Board_I2C_TMP CC1312R1_LAUNCHXL_I2C0 + +#define Board_NVSINTERNAL CC1312R1_LAUNCHXL_NVSCC26XX0 +#define Board_NVSEXTERNAL CC1312R1_LAUNCHXL_NVSSPI25X0 + +#define Board_PIN_BUTTON0 CC1312R1_LAUNCHXL_PIN_BTN1 +#define Board_PIN_BUTTON1 CC1312R1_LAUNCHXL_PIN_BTN2 +#define Board_PIN_BTN1 CC1312R1_LAUNCHXL_PIN_BTN1 +#define Board_PIN_BTN2 CC1312R1_LAUNCHXL_PIN_BTN2 +#define Board_PIN_LED0 CC1312R1_LAUNCHXL_PIN_RLED +#define Board_PIN_LED1 CC1312R1_LAUNCHXL_PIN_GLED +#define Board_PIN_LED2 CC1312R1_LAUNCHXL_PIN_RLED +#define Board_PIN_RLED CC1312R1_LAUNCHXL_PIN_RLED +#define Board_PIN_GLED CC1312R1_LAUNCHXL_PIN_GLED + +#define Board_PWM0 CC1312R1_LAUNCHXL_PWM0 +#define Board_PWM1 CC1312R1_LAUNCHXL_PWM1 +#define Board_PWM2 CC1312R1_LAUNCHXL_PWM2 +#define Board_PWM3 CC1312R1_LAUNCHXL_PWM3 +#define Board_PWM4 CC1312R1_LAUNCHXL_PWM4 +#define Board_PWM5 CC1312R1_LAUNCHXL_PWM5 +#define Board_PWM6 CC1312R1_LAUNCHXL_PWM6 +#define Board_PWM7 CC1312R1_LAUNCHXL_PWM7 + +#define Board_SD0 CC1312R1_LAUNCHXL_SDSPI0 + +#define Board_SPI0 CC1312R1_LAUNCHXL_SPI0 +#define Board_SPI1 CC1312R1_LAUNCHXL_SPI1 +#define Board_SPI_FLASH_CS CC1312R1_LAUNCHXL_SPI_FLASH_CS +#define Board_FLASH_CS_ON 0 +#define Board_FLASH_CS_OFF 1 + +#define Board_SPI_MASTER CC1312R1_LAUNCHXL_SPI0 +#define Board_SPI_SLAVE CC1312R1_LAUNCHXL_SPI0 +#define Board_SPI_MASTER_READY CC1312R1_LAUNCHXL_SPI_MASTER_READY +#define Board_SPI_SLAVE_READY CC1312R1_LAUNCHXL_SPI_SLAVE_READY + +#define Board_UART0 CC1312R1_LAUNCHXL_UART0 +#define Board_UART1 CC1312R1_LAUNCHXL_UART1 + +#define Board_WATCHDOG0 CC1312R1_LAUNCHXL_WATCHDOG0 + +/* Board specific I2C addresses */ +#define Board_TMP_ADDR (0x40) +#define Board_SENSORS_BP_TMP_ADDR Board_TMP_ADDR + +#ifdef __cplusplus +} +#endif + +#endif /* __BOARD_H */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.c new file mode 100644 index 000000000..f36786ed7 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.c @@ -0,0 +1,1033 @@ +/* + * Copyright (c) 2015-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +/* + * ====================== CC1312R1_LAUNCHXL.c =================================== + * This file is responsible for setting up the board specific items for the + * CC1312R1_LAUNCHXL board. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "CC1312R1_LAUNCHXL.h" + +/* + * =============================== ADCBuf =============================== + */ +#include +#include + +ADCBufCC26X2_Object adcBufCC26xxObjects[CC1312R1_LAUNCHXL_ADCBUFCOUNT]; + +/* + * This table converts a virtual adc channel into a dio and internal analogue + * input signal. This table is necessary for the functioning of the adcBuf + * driver. Comment out unused entries to save flash. Dio and internal signal + * pairs are hardwired. Do not remap them in the table. You may reorder entire + * entries. The mapping of dio and internal signals is package dependent. + */ +const ADCBufCC26X2_AdcChannelLutEntry ADCBufCC26X2_adcChannelLut[CC1312R1_LAUNCHXL_ADCBUF0CHANNELCOUNT] = { + {CC1312R1_LAUNCHXL_DIO23_ANALOG, ADC_COMPB_IN_AUXIO7}, + {CC1312R1_LAUNCHXL_DIO24_ANALOG, ADC_COMPB_IN_AUXIO6}, + {CC1312R1_LAUNCHXL_DIO25_ANALOG, ADC_COMPB_IN_AUXIO5}, + {CC1312R1_LAUNCHXL_DIO26_ANALOG, ADC_COMPB_IN_AUXIO4}, + {CC1312R1_LAUNCHXL_DIO27_ANALOG, ADC_COMPB_IN_AUXIO3}, + {CC1312R1_LAUNCHXL_DIO28_ANALOG, ADC_COMPB_IN_AUXIO2}, + {CC1312R1_LAUNCHXL_DIO29_ANALOG, ADC_COMPB_IN_AUXIO1}, + {CC1312R1_LAUNCHXL_DIO30_ANALOG, ADC_COMPB_IN_AUXIO0}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VDDS}, + {PIN_UNASSIGNED, ADC_COMPB_IN_DCOUPL}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VSS}, +}; + +const ADCBufCC26X2_HWAttrs adcBufCC26xxHWAttrs[CC1312R1_LAUNCHXL_ADCBUFCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + .adcChannelLut = ADCBufCC26X2_adcChannelLut, + .gpTimerUnit = CC1312R1_LAUNCHXL_GPTIMER0A, + } +}; + +const ADCBuf_Config ADCBuf_config[CC1312R1_LAUNCHXL_ADCBUFCOUNT] = { + { + &ADCBufCC26X2_fxnTable, + &adcBufCC26xxObjects[CC1312R1_LAUNCHXL_ADCBUF0], + &adcBufCC26xxHWAttrs[CC1312R1_LAUNCHXL_ADCBUF0] + }, +}; + +const uint_least8_t ADCBuf_count = CC1312R1_LAUNCHXL_ADCBUFCOUNT; + +/* + * =============================== ADC =============================== + */ +#include +#include + +ADCCC26XX_Object adcCC26xxObjects[CC1312R1_LAUNCHXL_ADCCOUNT]; + + +const ADCCC26XX_HWAttrs adcCC26xxHWAttrs[CC1312R1_LAUNCHXL_ADCCOUNT] = { + { + .adcDIO = CC1312R1_LAUNCHXL_DIO23_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO7, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1312R1_LAUNCHXL_DIO24_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO6, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1312R1_LAUNCHXL_DIO25_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO5, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1312R1_LAUNCHXL_DIO26_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO4, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1312R1_LAUNCHXL_DIO27_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO3, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1312R1_LAUNCHXL_DIO28_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO2, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1312R1_LAUNCHXL_DIO29_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO1, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1312R1_LAUNCHXL_DIO30_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO0, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_10P9_MS, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_DCOUPL, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VSS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VDDS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + } +}; + +const ADC_Config ADC_config[CC1312R1_LAUNCHXL_ADCCOUNT] = { + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1312R1_LAUNCHXL_ADC0], &adcCC26xxHWAttrs[CC1312R1_LAUNCHXL_ADC0]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1312R1_LAUNCHXL_ADC1], &adcCC26xxHWAttrs[CC1312R1_LAUNCHXL_ADC1]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1312R1_LAUNCHXL_ADC2], &adcCC26xxHWAttrs[CC1312R1_LAUNCHXL_ADC2]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1312R1_LAUNCHXL_ADC3], &adcCC26xxHWAttrs[CC1312R1_LAUNCHXL_ADC3]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1312R1_LAUNCHXL_ADC4], &adcCC26xxHWAttrs[CC1312R1_LAUNCHXL_ADC4]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1312R1_LAUNCHXL_ADC5], &adcCC26xxHWAttrs[CC1312R1_LAUNCHXL_ADC5]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1312R1_LAUNCHXL_ADC6], &adcCC26xxHWAttrs[CC1312R1_LAUNCHXL_ADC6]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1312R1_LAUNCHXL_ADC7], &adcCC26xxHWAttrs[CC1312R1_LAUNCHXL_ADC7]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1312R1_LAUNCHXL_ADCDCOUPL], &adcCC26xxHWAttrs[CC1312R1_LAUNCHXL_ADCDCOUPL]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1312R1_LAUNCHXL_ADCVSS], &adcCC26xxHWAttrs[CC1312R1_LAUNCHXL_ADCVSS]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1312R1_LAUNCHXL_ADCVDDS], &adcCC26xxHWAttrs[CC1312R1_LAUNCHXL_ADCVDDS]}, +}; + +const uint_least8_t ADC_count = CC1312R1_LAUNCHXL_ADCCOUNT; + +/* + * =============================== ECDH =============================== + */ +#include +#include + +ECDHCC26X2_Object ecdhCC26X2Objects[CC1312R1_LAUNCHXL_ECDHCOUNT]; + +const ECDHCC26X2_HWAttrs ecdhCC26X2HWAttrs[CC1312R1_LAUNCHXL_ECDHCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const ECDH_Config ECDH_config[CC1312R1_LAUNCHXL_ECDHCOUNT] = { + { + .object = &ecdhCC26X2Objects[CC1312R1_LAUNCHXL_ECDH0], + .hwAttrs = &ecdhCC26X2HWAttrs[CC1312R1_LAUNCHXL_ECDH0] + }, +}; + +const uint_least8_t ECDH_count = CC1312R1_LAUNCHXL_ECDHCOUNT; + +/* + * =============================== ECDSA =============================== + */ +#include +#include + +ECDSACC26X2_Object ecdsaCC26X2Objects[CC1312R1_LAUNCHXL_ECDSACOUNT]; + +const ECDSACC26X2_HWAttrs ecdsaCC26X2HWAttrs[CC1312R1_LAUNCHXL_ECDSACOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const ECDSA_Config ECDSA_config[CC1312R1_LAUNCHXL_ECDSACOUNT] = { + { + .object = &ecdsaCC26X2Objects[CC1312R1_LAUNCHXL_ECDSA0], + .hwAttrs = &ecdsaCC26X2HWAttrs[CC1312R1_LAUNCHXL_ECDSA0] + }, +}; + +const uint_least8_t ECDSA_count = CC1312R1_LAUNCHXL_ECDSACOUNT; + +/* + * =============================== ECJPAKE =============================== + */ +#include +#include + +ECJPAKECC26X2_Object ecjpakeCC26X2Objects[CC1312R1_LAUNCHXL_ECJPAKECOUNT]; + +const ECJPAKECC26X2_HWAttrs ecjpakeCC26X2HWAttrs[CC1312R1_LAUNCHXL_ECJPAKECOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const ECJPAKE_Config ECJPAKE_config[CC1312R1_LAUNCHXL_ECJPAKECOUNT] = { + { + .object = &ecjpakeCC26X2Objects[CC1312R1_LAUNCHXL_ECJPAKE0], + .hwAttrs = &ecjpakeCC26X2HWAttrs[CC1312R1_LAUNCHXL_ECJPAKE0] + }, +}; + +const uint_least8_t ECJPAKE_count = CC1312R1_LAUNCHXL_ECJPAKECOUNT; + + +/* + * =============================== SHA2 =============================== + */ +#include +#include + +SHA2CC26X2_Object sha2CC26X2Objects[CC1312R1_LAUNCHXL_SHA2COUNT]; + +const SHA2CC26X2_HWAttrs sha2CC26X2HWAttrs[CC1312R1_LAUNCHXL_SHA2COUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const SHA2_Config SHA2_config[CC1312R1_LAUNCHXL_SHA2COUNT] = { + { + .object = &sha2CC26X2Objects[CC1312R1_LAUNCHXL_SHA20], + .hwAttrs = &sha2CC26X2HWAttrs[CC1312R1_LAUNCHXL_SHA20] + }, +}; + +const uint_least8_t SHA2_count = CC1312R1_LAUNCHXL_SHA2COUNT; + +/* + * =============================== AESCCM =============================== + */ +#include +#include + +AESCCMCC26XX_Object aesccmCC26XXObjects[CC1312R1_LAUNCHXL_AESCCMCOUNT]; + +const AESCCMCC26XX_HWAttrs aesccmCC26XXHWAttrs[CC1312R1_LAUNCHXL_AESCCMCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const AESCCM_Config AESCCM_config[CC1312R1_LAUNCHXL_AESCCMCOUNT] = { + { + .object = &aesccmCC26XXObjects[CC1312R1_LAUNCHXL_AESCCM0], + .hwAttrs = &aesccmCC26XXHWAttrs[CC1312R1_LAUNCHXL_AESCCM0] + }, +}; + +const uint_least8_t AESCCM_count = CC1312R1_LAUNCHXL_AESCCMCOUNT; + +/* + * =============================== AESECB =============================== + */ +#include +#include + +AESECBCC26XX_Object aesecbCC26XXObjects[CC1312R1_LAUNCHXL_AESECBCOUNT]; + +const AESECBCC26XX_HWAttrs aesecbCC26XXHWAttrs[CC1312R1_LAUNCHXL_AESECBCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const AESECB_Config AESECB_config[CC1312R1_LAUNCHXL_AESECBCOUNT] = { + { + .object = &aesecbCC26XXObjects[CC1312R1_LAUNCHXL_AESECB0], + .hwAttrs = &aesecbCC26XXHWAttrs[CC1312R1_LAUNCHXL_AESECB0] + }, +}; + +const uint_least8_t AESECB_count = CC1312R1_LAUNCHXL_AESECBCOUNT; + +/* + * =============================== Display =============================== + */ +#include +#include +#include + +#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE +#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 +#endif + +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 +#endif + +DisplayUart_Object displayUartObject; +DisplaySharp_Object displaySharpObject; + +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; +static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; + +const DisplayUart_HWAttrs displayUartHWAttrs = { + .uartIdx = CC1312R1_LAUNCHXL_UART0, + .baudRate = 115200, + .mutexTimeout = (unsigned int)(-1), + .strBuf = uartStringBuf, + .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, +}; + +const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { + .spiIndex = CC1312R1_LAUNCHXL_SPI0, + .csPin = CC1312R1_LAUNCHXL_GPIO_LCD_CS, + .powerPin = CC1312R1_LAUNCHXL_GPIO_LCD_POWER, + .enablePin = CC1312R1_LAUNCHXL_GPIO_LCD_ENABLE, + .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, + .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, + .displayBuf = sharpDisplayBuf, +}; + +#ifndef BOARD_DISPLAY_USE_UART +#define BOARD_DISPLAY_USE_UART 1 +#endif +#ifndef BOARD_DISPLAY_USE_UART_ANSI +#define BOARD_DISPLAY_USE_UART_ANSI 0 +#endif +#ifndef BOARD_DISPLAY_USE_LCD +#define BOARD_DISPLAY_USE_LCD 0 +#endif + +/* + * This #if/#else is needed to workaround a problem with the + * IAR compiler. The IAR compiler doesn't like the empty array + * initialization. (IAR Error[Pe1345]) + */ +#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) + +const Display_Config Display_config[] = { +#if (BOARD_DISPLAY_USE_UART) + { +# if (BOARD_DISPLAY_USE_UART_ANSI) + .fxnTablePtr = &DisplayUartAnsi_fxnTable, +# else /* Default to minimal UART with no cursor placement */ + .fxnTablePtr = &DisplayUartMin_fxnTable, +# endif + .object = &displayUartObject, + .hwAttrs = &displayUartHWAttrs, + }, +#endif +#if (BOARD_DISPLAY_USE_LCD) + { + .fxnTablePtr = &DisplaySharp_fxnTable, + .object = &displaySharpObject, + .hwAttrs = &displaySharpHWattrs + }, +#endif +}; + +const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); + +#else + +const Display_Config *Display_config = NULL; +const uint_least8_t Display_count = 0; + +#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ + +/* + * =============================== GPIO =============================== + */ +#include +#include + +/* + * Array of Pin configurations + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC1312R1_LAUNCHXL.h + * NOTE: Pins not used for interrupts should be placed at the end of the + * array. Callback entries can be omitted from callbacks array to + * reduce memory usage. + */ +GPIO_PinConfig gpioPinConfigs[] = { + /* Input pins */ + GPIOCC26XX_DIO_13 | GPIO_DO_NOT_CONFIG, /* Button 0 */ + GPIOCC26XX_DIO_14 | GPIO_DO_NOT_CONFIG, /* Button 1 */ + + GPIOCC26XX_DIO_15 | GPIO_DO_NOT_CONFIG, /* CC1312R1_LAUNCHXL_SPI_MASTER_READY */ + GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG, /* CC1312R1_LAUNCHXL_SPI_SLAVE_READY */ + + /* Output pins */ + GPIOCC26XX_DIO_07 | GPIO_DO_NOT_CONFIG, /* Green LED */ + GPIOCC26XX_DIO_06 | GPIO_DO_NOT_CONFIG, /* Red LED */ + + /* SPI Flash CSN */ + GPIOCC26XX_DIO_20 | GPIO_DO_NOT_CONFIG, + + /* SD CS */ + GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG, + + /* Sharp Display - GPIO configurations will be done in the Display files */ + GPIOCC26XX_DIO_24 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ + GPIOCC26XX_DIO_22 | GPIO_DO_NOT_CONFIG, /* LCD power control */ + GPIOCC26XX_DIO_23 | GPIO_DO_NOT_CONFIG, /*LCD enable */ + +}; + +/* + * Array of callback function pointers + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC1312R1_LAUNCH.h + * NOTE: Pins not used for interrupts can be omitted from callbacks array to + * reduce memory usage (if placed at end of gpioPinConfigs array). + */ +GPIO_CallbackFxn gpioCallbackFunctions[] = { + NULL, /* Button 0 */ + NULL, /* Button 1 */ + NULL, /* CC1312R1_LAUNCHXL_SPI_MASTER_READY */ + NULL, /* CC1312R1_LAUNCHXL_SPI_SLAVE_READY */ +}; + +const GPIOCC26XX_Config GPIOCC26XX_config = { + .pinConfigs = (GPIO_PinConfig *)gpioPinConfigs, + .callbacks = (GPIO_CallbackFxn *)gpioCallbackFunctions, + .numberOfPinConfigs = CC1312R1_LAUNCHXL_GPIOCOUNT, + .numberOfCallbacks = sizeof(gpioCallbackFunctions)/sizeof(GPIO_CallbackFxn), + .intPriority = (~0) +}; + +/* + * =============================== GPTimer =============================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +#include + +GPTimerCC26XX_Object gptimerCC26XXObjects[CC1312R1_LAUNCHXL_GPTIMERCOUNT]; + +const GPTimerCC26XX_HWAttrs gptimerCC26xxHWAttrs[CC1312R1_LAUNCHXL_GPTIMERPARTSCOUNT] = { + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0A, }, + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0B, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1A, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1B, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2A, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2B, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3A, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3B, }, +}; + +const GPTimerCC26XX_Config GPTimerCC26XX_config[CC1312R1_LAUNCHXL_GPTIMERPARTSCOUNT] = { + { &gptimerCC26XXObjects[CC1312R1_LAUNCHXL_GPTIMER0], &gptimerCC26xxHWAttrs[CC1312R1_LAUNCHXL_GPTIMER0A], GPT_A }, + { &gptimerCC26XXObjects[CC1312R1_LAUNCHXL_GPTIMER0], &gptimerCC26xxHWAttrs[CC1312R1_LAUNCHXL_GPTIMER0B], GPT_B }, + { &gptimerCC26XXObjects[CC1312R1_LAUNCHXL_GPTIMER1], &gptimerCC26xxHWAttrs[CC1312R1_LAUNCHXL_GPTIMER1A], GPT_A }, + { &gptimerCC26XXObjects[CC1312R1_LAUNCHXL_GPTIMER1], &gptimerCC26xxHWAttrs[CC1312R1_LAUNCHXL_GPTIMER1B], GPT_B }, + { &gptimerCC26XXObjects[CC1312R1_LAUNCHXL_GPTIMER2], &gptimerCC26xxHWAttrs[CC1312R1_LAUNCHXL_GPTIMER2A], GPT_A }, + { &gptimerCC26XXObjects[CC1312R1_LAUNCHXL_GPTIMER2], &gptimerCC26xxHWAttrs[CC1312R1_LAUNCHXL_GPTIMER2B], GPT_B }, + { &gptimerCC26XXObjects[CC1312R1_LAUNCHXL_GPTIMER3], &gptimerCC26xxHWAttrs[CC1312R1_LAUNCHXL_GPTIMER3A], GPT_A }, + { &gptimerCC26XXObjects[CC1312R1_LAUNCHXL_GPTIMER3], &gptimerCC26xxHWAttrs[CC1312R1_LAUNCHXL_GPTIMER3B], GPT_B }, +}; + +/* + * =============================== I2C =============================== +*/ +#include +#include + +I2CCC26XX_Object i2cCC26xxObjects[CC1312R1_LAUNCHXL_I2CCOUNT]; + +const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1312R1_LAUNCHXL_I2CCOUNT] = { + { + .baseAddr = I2C0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_I2C0, + .intNum = INT_I2C_IRQ, + .intPriority = ~0, + .swiPriority = 0, + .sdaPin = CC1312R1_LAUNCHXL_I2C0_SDA0, + .sclPin = CC1312R1_LAUNCHXL_I2C0_SCL0, + } +}; + +const I2C_Config I2C_config[CC1312R1_LAUNCHXL_I2CCOUNT] = { + { + .fxnTablePtr = &I2CCC26XX_fxnTable, + .object = &i2cCC26xxObjects[CC1312R1_LAUNCHXL_I2C0], + .hwAttrs = &i2cCC26xxHWAttrs[CC1312R1_LAUNCHXL_I2C0] + } +}; + +const uint_least8_t I2C_count = CC1312R1_LAUNCHXL_I2CCOUNT; + +/* + * =============================== NVS =============================== + */ +#include +#include +#include + +#define NVS_REGIONS_BASE 0x48000 +#define SECTORSIZE 0x2000 +#define REGIONSIZE (SECTORSIZE * 4) +#define SPISECTORSIZE 0x1000 +#define SPIREGIONSIZE (SPISECTORSIZE * 32) +#define VERIFYBUFSIZE 64 + +static uint8_t verifyBuf[VERIFYBUFSIZE]; + +/* + * Reserve flash sectors for NVS driver use by placing an uninitialized byte + * array at the desired flash address. + */ +#if defined(__TI_COMPILER_VERSION__) + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +#pragma LOCATION(flashBuf, NVS_REGIONS_BASE); +#pragma NOINIT(flashBuf); +static char flashBuf[REGIONSIZE]; + +#elif defined(__IAR_SYSTEMS_ICC__) + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +static __no_init char flashBuf[REGIONSIZE] @ NVS_REGIONS_BASE; + +#elif defined(__GNUC__) + +/* + * Place the flash buffers in the .nvs section created in the gcc linker file. + * The .nvs section enforces alignment on a sector boundary but may + * be placed anywhere in flash memory. If desired the .nvs section can be set + * to a fixed address by changing the following in the gcc linker file: + * + * .nvs (FIXED_FLASH_ADDR) (NOLOAD) : AT (FIXED_FLASH_ADDR) { + * *(.nvs) + * } > REGION_TEXT + */ +__attribute__ ((section (".nvs"))) +static char flashBuf[REGIONSIZE]; + +#endif + +/* Allocate objects for NVS and NVS SPI */ +NVSCC26XX_Object nvsCC26xxObjects[1]; +NVSSPI25X_Object nvsSPI25XObjects[1]; + +/* Hardware attributes for NVS */ +const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { + { + .regionBase = (void *)flashBuf, + .regionSize = REGIONSIZE, + }, +}; + +/* Hardware attributes for NVS SPI */ +const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { + { + .regionBaseOffset = 0, + .regionSize = SPIREGIONSIZE, + .sectorSize = SPISECTORSIZE, + .verifyBuf = verifyBuf, + .verifyBufSize = VERIFYBUFSIZE, + .spiHandle = NULL, + .spiIndex = 0, + .spiBitRate = 4000000, + .spiCsnGpioIndex = CC1312R1_LAUNCHXL_GPIO_SPI_FLASH_CS, + }, +}; + +/* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ +const NVS_Config NVS_config[CC1312R1_LAUNCHXL_NVSCOUNT] = { + { + .fxnTablePtr = &NVSCC26XX_fxnTable, + .object = &nvsCC26xxObjects[0], + .hwAttrs = &nvsCC26xxHWAttrs[0], + }, + { + .fxnTablePtr = &NVSSPI25X_fxnTable, + .object = &nvsSPI25XObjects[0], + .hwAttrs = &nvsSPI25XHWAttrs[0], + }, +}; + +const uint_least8_t NVS_count = CC1312R1_LAUNCHXL_NVSCOUNT; + +/* + * =============================== PIN =============================== + */ +#include +#include + +const PIN_Config BoardGpioInitTable[] = { + + CC1312R1_LAUNCHXL_PIN_RLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC1312R1_LAUNCHXL_PIN_GLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC1312R1_LAUNCHXL_PIN_BTN1 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC1312R1_LAUNCHXL_PIN_BTN2 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC1312R1_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ + CC1312R1_LAUNCHXL_UART_RX | PIN_INPUT_EN | PIN_PULLDOWN, /* UART RX via debugger back channel */ + CC1312R1_LAUNCHXL_UART_TX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* UART TX via debugger back channel */ + CC1312R1_LAUNCHXL_SPI0_MOSI | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master out - slave in */ + CC1312R1_LAUNCHXL_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master in - slave out */ + CC1312R1_LAUNCHXL_SPI0_CLK | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI clock */ + + PIN_TERMINATE +}; + +const PINCC26XX_HWAttrs PINCC26XX_hwAttrs = { + .intPriority = ~0, + .swiPriority = 0 +}; + +/* + * =============================== Power =============================== + */ +#include +#include + +const PowerCC26X2_Config PowerCC26X2_config = { + .policyInitFxn = NULL, + .policyFxn = &PowerCC26XX_standbyPolicy, + .calibrateFxn = &PowerCC26XX_calibrate, + .enablePolicy = true, + .calibrateRCOSC_LF = true, + .calibrateRCOSC_HF = true, +}; + +/* + * =============================== PWM =============================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +#include +#include + +PWMTimerCC26XX_Object pwmtimerCC26xxObjects[CC1312R1_LAUNCHXL_PWMCOUNT]; + +const PWMTimerCC26XX_HwAttrs pwmtimerCC26xxHWAttrs[CC1312R1_LAUNCHXL_PWMCOUNT] = { + { .pwmPin = CC1312R1_LAUNCHXL_PWMPIN0, .gpTimerUnit = CC1312R1_LAUNCHXL_GPTIMER0A }, + { .pwmPin = CC1312R1_LAUNCHXL_PWMPIN1, .gpTimerUnit = CC1312R1_LAUNCHXL_GPTIMER0B }, + { .pwmPin = CC1312R1_LAUNCHXL_PWMPIN2, .gpTimerUnit = CC1312R1_LAUNCHXL_GPTIMER1A }, + { .pwmPin = CC1312R1_LAUNCHXL_PWMPIN3, .gpTimerUnit = CC1312R1_LAUNCHXL_GPTIMER1B }, + { .pwmPin = CC1312R1_LAUNCHXL_PWMPIN4, .gpTimerUnit = CC1312R1_LAUNCHXL_GPTIMER2A }, + { .pwmPin = CC1312R1_LAUNCHXL_PWMPIN5, .gpTimerUnit = CC1312R1_LAUNCHXL_GPTIMER2B }, + { .pwmPin = CC1312R1_LAUNCHXL_PWMPIN6, .gpTimerUnit = CC1312R1_LAUNCHXL_GPTIMER3A }, + { .pwmPin = CC1312R1_LAUNCHXL_PWMPIN7, .gpTimerUnit = CC1312R1_LAUNCHXL_GPTIMER3B }, +}; + +const PWM_Config PWM_config[CC1312R1_LAUNCHXL_PWMCOUNT] = { + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1312R1_LAUNCHXL_PWM0], &pwmtimerCC26xxHWAttrs[CC1312R1_LAUNCHXL_PWM0] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1312R1_LAUNCHXL_PWM1], &pwmtimerCC26xxHWAttrs[CC1312R1_LAUNCHXL_PWM1] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1312R1_LAUNCHXL_PWM2], &pwmtimerCC26xxHWAttrs[CC1312R1_LAUNCHXL_PWM2] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1312R1_LAUNCHXL_PWM3], &pwmtimerCC26xxHWAttrs[CC1312R1_LAUNCHXL_PWM3] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1312R1_LAUNCHXL_PWM4], &pwmtimerCC26xxHWAttrs[CC1312R1_LAUNCHXL_PWM4] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1312R1_LAUNCHXL_PWM5], &pwmtimerCC26xxHWAttrs[CC1312R1_LAUNCHXL_PWM5] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1312R1_LAUNCHXL_PWM6], &pwmtimerCC26xxHWAttrs[CC1312R1_LAUNCHXL_PWM6] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1312R1_LAUNCHXL_PWM7], &pwmtimerCC26xxHWAttrs[CC1312R1_LAUNCHXL_PWM7] }, +}; + +const uint_least8_t PWM_count = CC1312R1_LAUNCHXL_PWMCOUNT; + +/* + * =============================== RF Driver =============================== + */ +#include + +const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { + .hwiPriority = ~0, /* Lowest HWI priority */ + .swiPriority = 0, /* Lowest SWI priority */ + .xoscHfAlwaysNeeded = true, /* Keep XOSC dependency while in stanby */ + .globalCallback = NULL, /* No board specific callback */ + .globalEventMask = 0 /* No events subscribed to */ +}; + +/* + * =============================== SD =============================== + */ +#include +#include + +SDSPI_Object sdspiObjects[CC1312R1_LAUNCHXL_SDCOUNT]; + +const SDSPI_HWAttrs sdspiHWAttrs[CC1312R1_LAUNCHXL_SDCOUNT] = { + { + .spiIndex = CC1312R1_LAUNCHXL_SPI0, + .spiCsGpioIndex = CC1312R1_LAUNCHXL_SDSPI_CS + } +}; + +const SD_Config SD_config[CC1312R1_LAUNCHXL_SDCOUNT] = { + { + .fxnTablePtr = &SDSPI_fxnTable, + .object = &sdspiObjects[CC1312R1_LAUNCHXL_SDSPI0], + .hwAttrs = &sdspiHWAttrs[CC1312R1_LAUNCHXL_SDSPI0] + }, +}; + +const uint_least8_t SD_count = CC1312R1_LAUNCHXL_SDCOUNT; + +/* + * =============================== SPI DMA =============================== + */ +#include +#include + +SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1312R1_LAUNCHXL_SPICOUNT]; + +/* + * NOTE: The SPI instances below can be used by the SD driver to communicate + * with a SD card via SPI. The 'defaultTxBufValue' fields below are set to 0xFF + * to satisfy the SDSPI driver requirement. + */ +const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1312R1_LAUNCHXL_SPICOUNT] = { + { + .baseAddr = SSI0_BASE, + .intNum = INT_SSI0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .powerMngrId = PowerCC26XX_PERIPH_SSI0, + .defaultTxBufValue = 0xFF, + .rxChannelBitMask = 1< +#include + +UARTCC26XX_Object uartCC26XXObjects[CC1312R1_LAUNCHXL_UARTCOUNT]; + +uint8_t uartCC26XXRingBuffer[CC1312R1_LAUNCHXL_UARTCOUNT][32]; + +const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1312R1_LAUNCHXL_UARTCOUNT] = { + { + .baseAddr = UART0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UART0, + .intNum = INT_UART0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .txPin = CC1312R1_LAUNCHXL_UART_TX, + .rxPin = CC1312R1_LAUNCHXL_UART_RX, + .ctsPin = PIN_UNASSIGNED, + .rtsPin = PIN_UNASSIGNED, + .ringBufPtr = uartCC26XXRingBuffer[CC1312R1_LAUNCHXL_UART0], + .ringBufSize = sizeof(uartCC26XXRingBuffer[CC1312R1_LAUNCHXL_UART0]), + .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, + .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, + .errorFxn = NULL + } +}; + +const UART_Config UART_config[CC1312R1_LAUNCHXL_UARTCOUNT] = { + { + .fxnTablePtr = &UARTCC26XX_fxnTable, + .object = &uartCC26XXObjects[CC1312R1_LAUNCHXL_UART0], + .hwAttrs = &uartCC26XXHWAttrs[CC1312R1_LAUNCHXL_UART0] + }, +}; + +const uint_least8_t UART_count = CC1312R1_LAUNCHXL_UARTCOUNT; + +/* + * =============================== UDMA =============================== + */ +#include + +UDMACC26XX_Object udmaObjects[CC1312R1_LAUNCHXL_UDMACOUNT]; + +const UDMACC26XX_HWAttrs udmaHWAttrs[CC1312R1_LAUNCHXL_UDMACOUNT] = { + { + .baseAddr = UDMA0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UDMA, + .intNum = INT_DMA_ERR, + .intPriority = ~0 + } +}; + +const UDMACC26XX_Config UDMACC26XX_config[CC1312R1_LAUNCHXL_UDMACOUNT] = { + { + .object = &udmaObjects[CC1312R1_LAUNCHXL_UDMA0], + .hwAttrs = &udmaHWAttrs[CC1312R1_LAUNCHXL_UDMA0] + }, +}; + +/* + * =============================== Watchdog =============================== + */ +#include +#include + +WatchdogCC26XX_Object watchdogCC26XXObjects[CC1312R1_LAUNCHXL_WATCHDOGCOUNT]; + +const WatchdogCC26XX_HWAttrs watchdogCC26XXHWAttrs[CC1312R1_LAUNCHXL_WATCHDOGCOUNT] = { + { + .baseAddr = WDT_BASE, + .reloadValue = 1000 /* Reload value in milliseconds */ + }, +}; + +const Watchdog_Config Watchdog_config[CC1312R1_LAUNCHXL_WATCHDOGCOUNT] = { + { + .fxnTablePtr = &WatchdogCC26XX_fxnTable, + .object = &watchdogCC26XXObjects[CC1312R1_LAUNCHXL_WATCHDOG0], + .hwAttrs = &watchdogCC26XXHWAttrs[CC1312R1_LAUNCHXL_WATCHDOG0] + }, +}; + +const uint_least8_t Watchdog_count = CC1312R1_LAUNCHXL_WATCHDOGCOUNT; + +/* + * ======== CC1312R1_LAUNCHXL_wakeUpExtFlash ======== + */ +void CC1312R1_LAUNCHXL_wakeUpExtFlash(void) +{ + PIN_Config extFlashPinTable[] = { + CC1312R1_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + /* + * To wake up we need to toggle the chip select at + * least 20 ns and ten wait at least 35 us. + */ + + /* Toggle chip select for ~20ns to wake ext. flash */ + PIN_setOutputValue(extFlashPinHandle, CC1312R1_LAUNCHXL_SPI_FLASH_CS, 0); + /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ + CPUdelay(1); + PIN_setOutputValue(extFlashPinHandle, CC1312R1_LAUNCHXL_SPI_FLASH_CS, 1); + /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ + CPUdelay(560); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC1312R1_LAUNCHXL_sendExtFlashByte ======== + */ +void CC1312R1_LAUNCHXL_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) +{ + uint8_t i; + + PIN_setOutputValue(pinHandle, CC1312R1_LAUNCHXL_SPI_FLASH_CS, 0); + + for (i = 0; i < 8; i++) { + PIN_setOutputValue(pinHandle, CC1312R1_LAUNCHXL_SPI0_CLK, 0); + PIN_setOutputValue(pinHandle, CC1312R1_LAUNCHXL_SPI0_MOSI, (byte >> (7 - i)) & 0x01); + PIN_setOutputValue(pinHandle, CC1312R1_LAUNCHXL_SPI0_CLK, 1); + + /* + * Waste a few cycles to keep the CLK high for at + * least 45% of the period. + * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. + */ + CPUdelay(8); + } + + PIN_setOutputValue(pinHandle, CC1312R1_LAUNCHXL_SPI0_CLK, 0); + PIN_setOutputValue(pinHandle, CC1312R1_LAUNCHXL_SPI_FLASH_CS, 1); + + /* + * Keep CS high atleast 40 us + * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us + */ + CPUdelay(700); +} + +/* + * ======== CC1312R1_LAUNCHXL_shutDownExtFlash ======== + */ +void CC1312R1_LAUNCHXL_shutDownExtFlash(void) +{ + /* To be sure we are putting the flash into sleep and not waking it, we first have to make a wake up call */ + CC1312R1_LAUNCHXL_wakeUpExtFlash(); + + PIN_Config extFlashPinTable[] = { + CC1312R1_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + CC1312R1_LAUNCHXL_SPI0_CLK | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + CC1312R1_LAUNCHXL_SPI0_MOSI | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + CC1312R1_LAUNCHXL_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + uint8_t extFlashShutdown = 0xB9; + + CC1312R1_LAUNCHXL_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC1312R1_LAUNCHXL_initGeneral ======== + */ +void CC1312R1_LAUNCHXL_initGeneral(void) +{ + Power_init(); + + if (PIN_init(BoardGpioInitTable) != PIN_SUCCESS) { + /* Error with PIN_init */ + while (1); + } + + /* Shut down external flash as default */ + CC1312R1_LAUNCHXL_shutDownExtFlash(); +} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h new file mode 100644 index 000000000..e1cefe24e --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h @@ -0,0 +1,418 @@ +/* + * Copyright (c) 2015-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ +/** ============================================================================ + * @file CC1312R1_LAUNCHXL.h + * + * @brief CC1312R1 LaunchPad Board Specific header file. + * + * The CC1312R1_LAUNCHXL header file should be included in an application as + * follows: + * @code + * #include "CC1312R1_LAUNCHXL.h" + * @endcode + * + * ============================================================================ + */ +#ifndef __CC1312R1_LAUNCHXL_BOARD_H__ +#define __CC1312R1_LAUNCHXL_BOARD_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes */ +#include +#include + +/* Externs */ +extern const PIN_Config BoardGpioInitTable[]; + +/* Defines */ +#define CC1312R1_LAUNCHXL + +/* Mapping of pins to board signals using general board aliases + * + */ + +/* Analog capable DIOs */ +#define CC1312R1_LAUNCHXL_DIO23_ANALOG IOID_23 +#define CC1312R1_LAUNCHXL_DIO24_ANALOG IOID_24 +#define CC1312R1_LAUNCHXL_DIO25_ANALOG IOID_25 +#define CC1312R1_LAUNCHXL_DIO26_ANALOG IOID_26 +#define CC1312R1_LAUNCHXL_DIO27_ANALOG IOID_27 +#define CC1312R1_LAUNCHXL_DIO28_ANALOG IOID_28 +#define CC1312R1_LAUNCHXL_DIO29_ANALOG IOID_29 +#define CC1312R1_LAUNCHXL_DIO30_ANALOG IOID_30 + +/* Digital IOs */ +#define CC1312R1_LAUNCHXL_DIO0 IOID_0 +#define CC1312R1_LAUNCHXL_DIO1 IOID_1 +#define CC1312R1_LAUNCHXL_DIO12 IOID_12 +#define CC1312R1_LAUNCHXL_DIO15 IOID_15 +#define CC1312R1_LAUNCHXL_DIO16_TDO IOID_16 +#define CC1312R1_LAUNCHXL_DIO17_TDI IOID_17 +#define CC1312R1_LAUNCHXL_DIO21 IOID_21 +#define CC1312R1_LAUNCHXL_DIO22 IOID_22 + +/* Discrete Inputs */ +#define CC1312R1_LAUNCHXL_PIN_BTN1 IOID_13 +#define CC1312R1_LAUNCHXL_PIN_BTN2 IOID_14 + +/* GPIO */ +#define CC1312R1_LAUNCHXL_GPIO_LED_ON 1 +#define CC1312R1_LAUNCHXL_GPIO_LED_OFF 0 + +/* I2C */ +#define CC1312R1_LAUNCHXL_I2C0_SCL0 IOID_4 +#define CC1312R1_LAUNCHXL_I2C0_SDA0 IOID_5 + +/* LEDs */ +#define CC1312R1_LAUNCHXL_PIN_LED_ON 1 +#define CC1312R1_LAUNCHXL_PIN_LED_OFF 0 +#define CC1312R1_LAUNCHXL_PIN_RLED IOID_6 +#define CC1312R1_LAUNCHXL_PIN_GLED IOID_7 + +/* PWM Outputs */ +#define CC1312R1_LAUNCHXL_PWMPIN0 CC1312R1_LAUNCHXL_PIN_RLED +#define CC1312R1_LAUNCHXL_PWMPIN1 CC1312R1_LAUNCHXL_PIN_GLED +#define CC1312R1_LAUNCHXL_PWMPIN2 PIN_UNASSIGNED +#define CC1312R1_LAUNCHXL_PWMPIN3 PIN_UNASSIGNED +#define CC1312R1_LAUNCHXL_PWMPIN4 PIN_UNASSIGNED +#define CC1312R1_LAUNCHXL_PWMPIN5 PIN_UNASSIGNED +#define CC1312R1_LAUNCHXL_PWMPIN6 PIN_UNASSIGNED +#define CC1312R1_LAUNCHXL_PWMPIN7 PIN_UNASSIGNED + +/* SPI */ +#define CC1312R1_LAUNCHXL_SPI_FLASH_CS IOID_20 +#define CC1312R1_LAUNCHXL_FLASH_CS_ON 0 +#define CC1312R1_LAUNCHXL_FLASH_CS_OFF 1 + +/* SPI Board */ +#define CC1312R1_LAUNCHXL_SPI0_MISO IOID_8 /* RF1.20 */ +#define CC1312R1_LAUNCHXL_SPI0_MOSI IOID_9 /* RF1.18 */ +#define CC1312R1_LAUNCHXL_SPI0_CLK IOID_10 /* RF1.16 */ +#define CC1312R1_LAUNCHXL_SPI0_CSN PIN_UNASSIGNED +#define CC1312R1_LAUNCHXL_SPI1_MISO PIN_UNASSIGNED +#define CC1312R1_LAUNCHXL_SPI1_MOSI PIN_UNASSIGNED +#define CC1312R1_LAUNCHXL_SPI1_CLK PIN_UNASSIGNED +#define CC1312R1_LAUNCHXL_SPI1_CSN PIN_UNASSIGNED + +/* UART Board */ +#define CC1312R1_LAUNCHXL_UART0_RX IOID_2 /* RXD */ +#define CC1312R1_LAUNCHXL_UART0_TX IOID_3 /* TXD */ +#define CC1312R1_LAUNCHXL_UART0_CTS IOID_19 /* CTS */ +#define CC1312R1_LAUNCHXL_UART0_RTS IOID_18 /* RTS */ +#define CC1312R1_LAUNCHXL_UART1_RX PIN_UNASSIGNED +#define CC1312R1_LAUNCHXL_UART1_TX PIN_UNASSIGNED +#define CC1312R1_LAUNCHXL_UART1_CTS PIN_UNASSIGNED +#define CC1312R1_LAUNCHXL_UART1_RTS PIN_UNASSIGNED +/* For backward compatibility */ +#define CC1312R1_LAUNCHXL_UART_RX CC1312R1_LAUNCHXL_UART0_RX +#define CC1312R1_LAUNCHXL_UART_TX CC1312R1_LAUNCHXL_UART0_TX +#define CC1312R1_LAUNCHXL_UART_CTS CC1312R1_LAUNCHXL_UART0_CTS +#define CC1312R1_LAUNCHXL_UART_RTS CC1312R1_LAUNCHXL_UART0_RTS + +/*! + * @brief Initialize the general board specific settings + * + * This function initializes the general board specific settings. + */ +void CC1312R1_LAUNCHXL_initGeneral(void); + +/*! + * @brief Turn off the external flash on LaunchPads + * + */ +void CC1312R1_LAUNCHXL_shutDownExtFlash(void); + +/*! + * @brief Wake up the external flash present on the board files + * + * This function toggles the chip select for the amount of time needed + * to wake the chip up. + */ +void CC1312R1_LAUNCHXL_wakeUpExtFlash(void); + +/*! + * @def CC1312R1_LAUNCHXL_ADCBufName + * @brief Enum of ADCBufs + */ +typedef enum CC1312R1_LAUNCHXL_ADCBufName { + CC1312R1_LAUNCHXL_ADCBUF0 = 0, + + CC1312R1_LAUNCHXL_ADCBUFCOUNT +} CC1312R1_LAUNCHXL_ADCBufName; + +/*! + * @def CC1312R1_LAUNCHXL_ADCBuf0SourceName + * @brief Enum of ADCBuf channels + */ +typedef enum CC1312R1_LAUNCHXL_ADCBuf0ChannelName { + CC1312R1_LAUNCHXL_ADCBUF0CHANNEL0 = 0, + CC1312R1_LAUNCHXL_ADCBUF0CHANNEL1, + CC1312R1_LAUNCHXL_ADCBUF0CHANNEL2, + CC1312R1_LAUNCHXL_ADCBUF0CHANNEL3, + CC1312R1_LAUNCHXL_ADCBUF0CHANNEL4, + CC1312R1_LAUNCHXL_ADCBUF0CHANNEL5, + CC1312R1_LAUNCHXL_ADCBUF0CHANNEL6, + CC1312R1_LAUNCHXL_ADCBUF0CHANNEL7, + CC1312R1_LAUNCHXL_ADCBUF0CHANNELVDDS, + CC1312R1_LAUNCHXL_ADCBUF0CHANNELDCOUPL, + CC1312R1_LAUNCHXL_ADCBUF0CHANNELVSS, + + CC1312R1_LAUNCHXL_ADCBUF0CHANNELCOUNT +} CC1312R1_LAUNCHXL_ADCBuf0ChannelName; + +/*! + * @def CC1312R1_LAUNCHXL_ADCName + * @brief Enum of ADCs + */ +typedef enum CC1312R1_LAUNCHXL_ADCName { + CC1312R1_LAUNCHXL_ADC0 = 0, + CC1312R1_LAUNCHXL_ADC1, + CC1312R1_LAUNCHXL_ADC2, + CC1312R1_LAUNCHXL_ADC3, + CC1312R1_LAUNCHXL_ADC4, + CC1312R1_LAUNCHXL_ADC5, + CC1312R1_LAUNCHXL_ADC6, + CC1312R1_LAUNCHXL_ADC7, + CC1312R1_LAUNCHXL_ADCDCOUPL, + CC1312R1_LAUNCHXL_ADCVSS, + CC1312R1_LAUNCHXL_ADCVDDS, + + CC1312R1_LAUNCHXL_ADCCOUNT +} CC1312R1_LAUNCHXL_ADCName; + +/*! + * @def CC1312R1_LAUNCHXL_ECDHName + * @brief Enum of ECDH names + */ +typedef enum CC1312R1_LAUNCHXL_ECDHName { + CC1312R1_LAUNCHXL_ECDH0 = 0, + + CC1312R1_LAUNCHXL_ECDHCOUNT +} CC1312R1_LAUNCHXL_ECDHName; + +/*! + * @def CC1312R1_LAUNCHXL_ECDSAName + * @brief Enum of ECDSA names + */ +typedef enum CC1312R1_LAUNCHXL_ECDSAName { + CC1312R1_LAUNCHXL_ECDSA0 = 0, + + CC1312R1_LAUNCHXL_ECDSACOUNT +} CC1312R1_LAUNCHXL_ECDSAName; + +/*! + * @def CC1312R1_LAUNCHXL_ECJPAKEName + * @brief Enum of ECJPAKE names + */ +typedef enum CC1312R1_LAUNCHXL_ECJPAKEName { + CC1312R1_LAUNCHXL_ECJPAKE0 = 0, + + CC1312R1_LAUNCHXL_ECJPAKECOUNT +} CC1312R1_LAUNCHXL_ECJPAKEName; + +/*! + * @def CC1312R1_LAUNCHXL_AESCCMName + * @brief Enum of AESCCM names + */ +typedef enum CC1312R1_LAUNCHXL_AESCCMName { + CC1312R1_LAUNCHXL_AESCCM0 = 0, + + CC1312R1_LAUNCHXL_AESCCMCOUNT +} CC1312R1_LAUNCHXL_AESCCMName; + +/*! + * @def CC1312R1_LAUNCHXL_AESECBName + * @brief Enum of AESECB names + */ +typedef enum CC1312R1_LAUNCHXL_AESECBName { + CC1312R1_LAUNCHXL_AESECB0 = 0, + + CC1312R1_LAUNCHXL_AESECBCOUNT +} CC1312R1_LAUNCHXL_AESECBName; + +/*! + * @def CC1312R1_LAUNCHXL_SHA2Name + * @brief Enum of SHA2 names + */ +typedef enum CC1312R1_LAUNCHXL_SHA2Name { + CC1312R1_LAUNCHXL_SHA20 = 0, + + CC1312R1_LAUNCHXL_SHA2COUNT +} CC1312R1_LAUNCHXL_SHA2Name; + +/*! + * @def CC1312R1_LAUNCHXL_GPIOName + * @brief Enum of GPIO names + */ +typedef enum CC1312R1_LAUNCHXL_GPIOName { + CC1312R1_LAUNCHXL_GPIO_S1 = 0, + CC1312R1_LAUNCHXL_GPIO_S2, + CC1312R1_LAUNCHXL_SPI_MASTER_READY, + CC1312R1_LAUNCHXL_SPI_SLAVE_READY, + CC1312R1_LAUNCHXL_GPIO_LED_GREEN, + CC1312R1_LAUNCHXL_GPIO_LED_RED, + CC1312R1_LAUNCHXL_GPIO_SPI_FLASH_CS, + CC1312R1_LAUNCHXL_SDSPI_CS, + CC1312R1_LAUNCHXL_GPIO_LCD_CS, + CC1312R1_LAUNCHXL_GPIO_LCD_POWER, + CC1312R1_LAUNCHXL_GPIO_LCD_ENABLE, + CC1312R1_LAUNCHXL_GPIOCOUNT +} CC1312R1_LAUNCHXL_GPIOName; + +/*! + * @def CC1312R1_LAUNCHXL_GPTimerName + * @brief Enum of GPTimer parts + */ +typedef enum CC1312R1_LAUNCHXL_GPTimerName { + CC1312R1_LAUNCHXL_GPTIMER0A = 0, + CC1312R1_LAUNCHXL_GPTIMER0B, + CC1312R1_LAUNCHXL_GPTIMER1A, + CC1312R1_LAUNCHXL_GPTIMER1B, + CC1312R1_LAUNCHXL_GPTIMER2A, + CC1312R1_LAUNCHXL_GPTIMER2B, + CC1312R1_LAUNCHXL_GPTIMER3A, + CC1312R1_LAUNCHXL_GPTIMER3B, + + CC1312R1_LAUNCHXL_GPTIMERPARTSCOUNT +} CC1312R1_LAUNCHXL_GPTimerName; + +/*! + * @def CC1312R1_LAUNCHXL_GPTimers + * @brief Enum of GPTimers + */ +typedef enum CC1312R1_LAUNCHXL_GPTimers { + CC1312R1_LAUNCHXL_GPTIMER0 = 0, + CC1312R1_LAUNCHXL_GPTIMER1, + CC1312R1_LAUNCHXL_GPTIMER2, + CC1312R1_LAUNCHXL_GPTIMER3, + + CC1312R1_LAUNCHXL_GPTIMERCOUNT +} CC1312R1_LAUNCHXL_GPTimers; + +/*! + * @def CC1312R1_LAUNCHXL_I2CName + * @brief Enum of I2C names + */ +typedef enum CC1312R1_LAUNCHXL_I2CName { + CC1312R1_LAUNCHXL_I2C0 = 0, + + CC1312R1_LAUNCHXL_I2CCOUNT +} CC1312R1_LAUNCHXL_I2CName; + +/*! + * @def CC1312R1_LAUNCHXL_NVSName + * @brief Enum of NVS names + */ +typedef enum CC1312R1_LAUNCHXL_NVSName { + CC1312R1_LAUNCHXL_NVSCC26XX0 = 0, + CC1312R1_LAUNCHXL_NVSSPI25X0, + + CC1312R1_LAUNCHXL_NVSCOUNT +} CC1312R1_LAUNCHXL_NVSName; + +/*! + * @def CC1312R1_LAUNCHXL_PWM + * @brief Enum of PWM outputs + */ +typedef enum CC1312R1_LAUNCHXL_PWMName { + CC1312R1_LAUNCHXL_PWM0 = 0, + CC1312R1_LAUNCHXL_PWM1, + CC1312R1_LAUNCHXL_PWM2, + CC1312R1_LAUNCHXL_PWM3, + CC1312R1_LAUNCHXL_PWM4, + CC1312R1_LAUNCHXL_PWM5, + CC1312R1_LAUNCHXL_PWM6, + CC1312R1_LAUNCHXL_PWM7, + + CC1312R1_LAUNCHXL_PWMCOUNT +} CC1312R1_LAUNCHXL_PWMName; + +/*! + * @def CC1312R1_LAUNCHXL_SDName + * @brief Enum of SD names + */ +typedef enum CC1312R1_LAUNCHXL_SDName { + CC1312R1_LAUNCHXL_SDSPI0 = 0, + + CC1312R1_LAUNCHXL_SDCOUNT +} CC1312R1_LAUNCHXL_SDName; + +/*! + * @def CC1312R1_LAUNCHXL_SPIName + * @brief Enum of SPI names + */ +typedef enum CC1312R1_LAUNCHXL_SPIName { + CC1312R1_LAUNCHXL_SPI0 = 0, + CC1312R1_LAUNCHXL_SPI1, + + CC1312R1_LAUNCHXL_SPICOUNT +} CC1312R1_LAUNCHXL_SPIName; + +/*! + * @def CC1312R1_LAUNCHXL_UARTName + * @brief Enum of UARTs + */ +typedef enum CC1312R1_LAUNCHXL_UARTName { + CC1312R1_LAUNCHXL_UART0 = 0, + + CC1312R1_LAUNCHXL_UARTCOUNT +} CC1312R1_LAUNCHXL_UARTName; + +/*! + * @def CC1312R1_LAUNCHXL_UDMAName + * @brief Enum of DMA buffers + */ +typedef enum CC1312R1_LAUNCHXL_UDMAName { + CC1312R1_LAUNCHXL_UDMA0 = 0, + + CC1312R1_LAUNCHXL_UDMACOUNT +} CC1312R1_LAUNCHXL_UDMAName; + +/*! + * @def CC1312R1_LAUNCHXL_WatchdogName + * @brief Enum of Watchdogs + */ +typedef enum CC1312R1_LAUNCHXL_WatchdogName { + CC1312R1_LAUNCHXL_WATCHDOG0 = 0, + + CC1312R1_LAUNCHXL_WATCHDOGCOUNT +} CC1312R1_LAUNCHXL_WatchdogName; + + +#ifdef __cplusplus +} +#endif + +#endif /* __CC1312R1_LAUNCHXL_BOARD_H__ */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 new file mode 100644 index 000000000..08ca5b89e --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 @@ -0,0 +1,16 @@ +################################################################################ +# SimpleLink Device makefile + +SUBFAMILY = cc13x2-cc26x2 +DEVICE_FAMILY = CC13X2 + +BOARD_SOURCEFILES += CC1312R1_LAUNCHXL.c + +SUPPORTS_PROP_MODE = 1 +SUPPORTS_IEEE_MODE = 0 + +### Signal that we can be programmed with cc2538-bsl +BOARD_SUPPORTS_BSL = 0 + +# Include the common board makefile +include $(FAMILY_PATH)/launchpad/Makefile.launchpad diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Board.h new file mode 100644 index 000000000..d1e4119a9 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Board.h @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2017-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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 __BOARD_H +#define __BOARD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "CC1350_LAUNCHXL_433.h" + +#define Board_initGeneral() CC1350_LAUNCHXL_433_initGeneral() +#define Board_shutDownExtFlash() CC1350_LAUNCHXL_433_shutDownExtFlash() +#define Board_wakeUpExtFlash() CC1350_LAUNCHXL_433_wakeUpExtFlash() + +/* These #defines allow us to reuse TI-RTOS across other device families */ + +#define Board_ADC0 CC1350_LAUNCHXL_433_ADC0 +#define Board_ADC1 CC1350_LAUNCHXL_433_ADC1 + +#define Board_ADCBUF0 CC1350_LAUNCHXL_433_ADCBUF0 +#define Board_ADCBUF0CHANNEL0 CC1350_LAUNCHXL_433_ADCBUF0CHANNEL0 +#define Board_ADCBUF0CHANNEL1 CC1350_LAUNCHXL_433_ADCBUF0CHANNEL1 + +#define Board_CRYPTO0 CC1350_LAUNCHXL_433_CRYPTO0 + +#define Board_DIO0 CC1350_LAUNCHXL_433_DIO0 +#define Board_DIO1_RFSW CC1350_LAUNCHXL_433_DIO1_RF_SUB1GHZ +#define Board_DIO12 CC1350_LAUNCHXL_433_DIO12 +#define Board_DIO15 CC1350_LAUNCHXL_433_DIO15 +#define Board_DIO16_TDO CC1350_LAUNCHXL_433_DIO16_TDO +#define Board_DIO17_TDI CC1350_LAUNCHXL_433_DIO17_TDI +#define Board_DIO21 CC1350_LAUNCHXL_433_DIO21 +#define Board_DIO22 CC1350_LAUNCHXL_433_DIO22 +#define Board_DIO30_SWPWR CC1350_LAUNCHXL_433_DIO30_RF_POWER + +#define Board_DIO23_ANALOG CC1350_LAUNCHXL_433_DIO23_ANALOG +#define Board_DIO24_ANALOG CC1350_LAUNCHXL_433_DIO24_ANALOG +#define Board_DIO25_ANALOG CC1350_LAUNCHXL_433_DIO25_ANALOG +#define Board_DIO26_ANALOG CC1350_LAUNCHXL_433_DIO26_ANALOG +#define Board_DIO27_ANALOG CC1350_LAUNCHXL_433_DIO27_ANALOG +#define Board_DIO28_ANALOG CC1350_LAUNCHXL_433_DIO28_ANALOG +#define Board_DIO29_ANALOG CC1350_LAUNCHXL_433_DIO29_ANALOG +#define Board_DIO30_ANALOG CC1350_LAUNCHXL_433_DIO30_ANALOG + +#define Board_GPIO_BUTTON0 CC1350_LAUNCHXL_433_GPIO_S1 +#define Board_GPIO_BUTTON1 CC1350_LAUNCHXL_433_GPIO_S2 +#define Board_GPIO_BTN1 CC1350_LAUNCHXL_433_GPIO_S1 +#define Board_GPIO_BTN2 CC1350_LAUNCHXL_433_GPIO_S2 +#define Board_GPIO_LED0 CC1350_LAUNCHXL_433_GPIO_LED_RED +#define Board_GPIO_LED1 CC1350_LAUNCHXL_433_GPIO_LED_GREEN +#define Board_GPIO_RLED CC1350_LAUNCHXL_433_GPIO_LED_RED +#define Board_GPIO_GLED CC1350_LAUNCHXL_433_GPIO_LED_GREEN +#define Board_GPIO_LED_ON CC1350_LAUNCHXL_433_GPIO_LED_ON +#define Board_GPIO_LED_OFF CC1350_LAUNCHXL_433_GPIO_LED_OFF + +#define Board_GPTIMER0A CC1350_LAUNCHXL_433_GPTIMER0A +#define Board_GPTIMER0B CC1350_LAUNCHXL_433_GPTIMER0B +#define Board_GPTIMER1A CC1350_LAUNCHXL_433_GPTIMER1A +#define Board_GPTIMER1B CC1350_LAUNCHXL_433_GPTIMER1B +#define Board_GPTIMER2A CC1350_LAUNCHXL_433_GPTIMER2A +#define Board_GPTIMER2B CC1350_LAUNCHXL_433_GPTIMER2B +#define Board_GPTIMER3A CC1350_LAUNCHXL_433_GPTIMER3A +#define Board_GPTIMER3B CC1350_LAUNCHXL_433_GPTIMER3B + +#define Board_NVSINTERNAL CC1350_LAUNCHXL_433_NVSCC26XX0 +#define Board_NVSEXTERNAL CC1350_LAUNCHXL_433_NVSSPI25X0 + +#define Board_I2C0 CC1350_LAUNCHXL_433_I2C0 +#define Board_I2C_TMP CC1350_LAUNCHXL_433_I2C0 + +#define Board_PIN_BUTTON0 CC1350_LAUNCHXL_433_PIN_BTN1 +#define Board_PIN_BUTTON1 CC1350_LAUNCHXL_433_PIN_BTN2 +#define Board_PIN_BTN1 CC1350_LAUNCHXL_433_PIN_BTN1 +#define Board_PIN_BTN2 CC1350_LAUNCHXL_433_PIN_BTN2 +#define Board_PIN_LED0 CC1350_LAUNCHXL_433_PIN_RLED +#define Board_PIN_LED1 CC1350_LAUNCHXL_433_PIN_GLED +#define Board_PIN_LED2 CC1350_LAUNCHXL_433_PIN_RLED +#define Board_PIN_RLED CC1350_LAUNCHXL_433_PIN_RLED +#define Board_PIN_GLED CC1350_LAUNCHXL_433_PIN_GLED + +#define Board_PWM0 CC1350_LAUNCHXL_433_PWM0 +#define Board_PWM1 CC1350_LAUNCHXL_433_PWM1 +#define Board_PWM2 CC1350_LAUNCHXL_433_PWM2 +#define Board_PWM3 CC1350_LAUNCHXL_433_PWM3 +#define Board_PWM4 CC1350_LAUNCHXL_433_PWM4 +#define Board_PWM5 CC1350_LAUNCHXL_433_PWM5 +#define Board_PWM6 CC1350_LAUNCHXL_433_PWM6 +#define Board_PWM7 CC1350_LAUNCHXL_433_PWM7 + +#define Board_SD0 CC1350_LAUNCHXL_433_SDSPI0 + +#define Board_SPI0 CC1350_LAUNCHXL_433_SPI0 +#define Board_SPI1 CC1350_LAUNCHXL_433_SPI1 +#define Board_SPI_FLASH_CS CC1350_LAUNCHXL_433_SPI_FLASH_CS +#define Board_FLASH_CS_ON (0) +#define Board_FLASH_CS_OFF (1) + +#define Board_SPI_MASTER CC1350_LAUNCHXL_433_SPI0 +#define Board_SPI_SLAVE CC1350_LAUNCHXL_433_SPI0 +#define Board_SPI_MASTER_READY CC1350_LAUNCHXL_433_SPI_MASTER_READY +#define Board_SPI_SLAVE_READY CC1350_LAUNCHXL_433_SPI_SLAVE_READY + +#define Board_UART0 CC1350_LAUNCHXL_433_UART0 + +#define Board_WATCHDOG0 CC1350_LAUNCHXL_433_WATCHDOG0 + +/* Board specific I2C addresses */ +#define Board_TMP_ADDR (0x40) +#define Board_SENSORS_BP_TMP_ADDR Board_TMP_ADDR + +#ifdef __cplusplus +} +#endif + +#endif /* __BOARD_H */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.c new file mode 100644 index 000000000..d6b8f33cd --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.c @@ -0,0 +1,945 @@ +/* + * Copyright (c) 2017-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +/* + * ============================ CC1350_LAUNCHXL_433.c ============================ + * This file is responsible for setting up the board specific items for the + * CC1350_LAUNCHXL_433 board. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "CC1350_LAUNCHXL_433.h" + +/* + * =============================== ADCBuf =============================== + */ +#include +#include + +ADCBufCC26XX_Object adcBufCC26XXobjects[CC1350_LAUNCHXL_433_ADCBUFCOUNT]; + +/* + * This table converts a virtual adc channel into a dio and internal analogue + * input signal. This table is necessary for the functioning of the adcBuf + * driver. Comment out unused entries to save flash. Dio and internal signal + * pairs are hardwired. Do not remap them in the table. You may reorder entire + * entries. The mapping of dio and internal signals is package dependent. + */ +const ADCBufCC26XX_AdcChannelLutEntry ADCBufCC26XX_adcChannelLut[CC1350_LAUNCHXL_433_ADCBUF0CHANNELCOUNT] = { + {CC1350_LAUNCHXL_433_DIO23_ANALOG, ADC_COMPB_IN_AUXIO7}, + {CC1350_LAUNCHXL_433_DIO24_ANALOG, ADC_COMPB_IN_AUXIO6}, + {CC1350_LAUNCHXL_433_DIO25_ANALOG, ADC_COMPB_IN_AUXIO5}, + {CC1350_LAUNCHXL_433_DIO26_ANALOG, ADC_COMPB_IN_AUXIO4}, + {CC1350_LAUNCHXL_433_DIO27_ANALOG, ADC_COMPB_IN_AUXIO3}, + {CC1350_LAUNCHXL_433_DIO28_ANALOG, ADC_COMPB_IN_AUXIO2}, + {CC1350_LAUNCHXL_433_DIO29_ANALOG, ADC_COMPB_IN_AUXIO1}, + {CC1350_LAUNCHXL_433_DIO30_ANALOG, ADC_COMPB_IN_AUXIO0}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VDDS}, + {PIN_UNASSIGNED, ADC_COMPB_IN_DCOUPL}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VSS}, +}; + +const ADCBufCC26XX_HWAttrs adcBufCC26XXHWAttrs[CC1350_LAUNCHXL_433_ADCBUFCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + .adcChannelLut = ADCBufCC26XX_adcChannelLut, + .gpTimerUnit = CC1350_LAUNCHXL_433_GPTIMER0A, + .gptDMAChannelMask = 1 << UDMA_CHAN_TIMER0_A, + } +}; + +const ADCBuf_Config ADCBuf_config[CC1350_LAUNCHXL_433_ADCBUFCOUNT] = { + { + &ADCBufCC26XX_fxnTable, + &adcBufCC26XXobjects[CC1350_LAUNCHXL_433_ADCBUF0], + &adcBufCC26XXHWAttrs[CC1350_LAUNCHXL_433_ADCBUF0] + }, +}; + +const uint_least8_t ADCBuf_count = CC1350_LAUNCHXL_433_ADCBUFCOUNT; + +/* + * =============================== ADC =============================== + */ +#include +#include + +ADCCC26XX_Object adcCC26xxObjects[CC1350_LAUNCHXL_433_ADCCOUNT]; + +const ADCCC26XX_HWAttrs adcCC26xxHWAttrs[CC1350_LAUNCHXL_433_ADCCOUNT] = { + { + .adcDIO = CC1350_LAUNCHXL_433_DIO23_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO7, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1350_LAUNCHXL_433_DIO24_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO6, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1350_LAUNCHXL_433_DIO25_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO5, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1350_LAUNCHXL_433_DIO26_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO4, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1350_LAUNCHXL_433_DIO27_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO3, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1350_LAUNCHXL_433_DIO28_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO2, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1350_LAUNCHXL_433_DIO29_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO1, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1350_LAUNCHXL_433_DIO30_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO0, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_10P9_MS, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_DCOUPL, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VSS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VDDS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + } +}; + +const ADC_Config ADC_config[CC1350_LAUNCHXL_433_ADCCOUNT] = { + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1350_LAUNCHXL_433_ADC0], &adcCC26xxHWAttrs[CC1350_LAUNCHXL_433_ADC0]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1350_LAUNCHXL_433_ADC1], &adcCC26xxHWAttrs[CC1350_LAUNCHXL_433_ADC1]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1350_LAUNCHXL_433_ADC2], &adcCC26xxHWAttrs[CC1350_LAUNCHXL_433_ADC2]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1350_LAUNCHXL_433_ADC3], &adcCC26xxHWAttrs[CC1350_LAUNCHXL_433_ADC3]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1350_LAUNCHXL_433_ADC4], &adcCC26xxHWAttrs[CC1350_LAUNCHXL_433_ADC4]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1350_LAUNCHXL_433_ADC5], &adcCC26xxHWAttrs[CC1350_LAUNCHXL_433_ADC5]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1350_LAUNCHXL_433_ADC6], &adcCC26xxHWAttrs[CC1350_LAUNCHXL_433_ADC6]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1350_LAUNCHXL_433_ADC7], &adcCC26xxHWAttrs[CC1350_LAUNCHXL_433_ADC7]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1350_LAUNCHXL_433_ADCDCOUPL], &adcCC26xxHWAttrs[CC1350_LAUNCHXL_433_ADCDCOUPL]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1350_LAUNCHXL_433_ADCVSS], &adcCC26xxHWAttrs[CC1350_LAUNCHXL_433_ADCVSS]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1350_LAUNCHXL_433_ADCVDDS], &adcCC26xxHWAttrs[CC1350_LAUNCHXL_433_ADCVDDS]}, +}; + +const uint_least8_t ADC_count = CC1350_LAUNCHXL_433_ADCCOUNT; + +/* + * =============================== Crypto =============================== + */ +#include + +CryptoCC26XX_Object cryptoCC26XXObjects[CC1350_LAUNCHXL_433_CRYPTOCOUNT]; + +const CryptoCC26XX_HWAttrs cryptoCC26XXHWAttrs[CC1350_LAUNCHXL_433_CRYPTOCOUNT] = { + { + .baseAddr = CRYPTO_BASE, + .powerMngrId = PowerCC26XX_PERIPH_CRYPTO, + .intNum = INT_CRYPTO_RESULT_AVAIL_IRQ, + .intPriority = ~0, + } +}; + +const CryptoCC26XX_Config CryptoCC26XX_config[CC1350_LAUNCHXL_433_CRYPTOCOUNT] = { + { + .object = &cryptoCC26XXObjects[CC1350_LAUNCHXL_433_CRYPTO0], + .hwAttrs = &cryptoCC26XXHWAttrs[CC1350_LAUNCHXL_433_CRYPTO0] + }, +}; + +/* + * =============================== Display =============================== + */ +#include +#include +#include + +#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE +#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 +#endif + +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 +#endif + +DisplayUart_Object displayUartObject; +DisplaySharp_Object displaySharpObject; + +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; +static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; + +const DisplayUart_HWAttrs displayUartHWAttrs = { + .uartIdx = CC1350_LAUNCHXL_433_UART0, + .baudRate = 115200, + .mutexTimeout = (unsigned int)(-1), + .strBuf = uartStringBuf, + .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, +}; + +const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { + .spiIndex = CC1350_LAUNCHXL_433_SPI0, + .csPin = CC1350_LAUNCHXL_433_GPIO_LCD_CS, + .powerPin = CC1350_LAUNCHXL_433_GPIO_LCD_POWER, + .enablePin = CC1350_LAUNCHXL_433_GPIO_LCD_ENABLE, + .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, + .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, + .displayBuf = sharpDisplayBuf, +}; + +#ifndef BOARD_DISPLAY_USE_UART +#define BOARD_DISPLAY_USE_UART 1 +#endif +#ifndef BOARD_DISPLAY_USE_UART_ANSI +#define BOARD_DISPLAY_USE_UART_ANSI 0 +#endif +#ifndef BOARD_DISPLAY_USE_LCD +#define BOARD_DISPLAY_USE_LCD 0 +#endif + +/* + * This #if/#else is needed to workaround a problem with the + * IAR compiler. The IAR compiler doesn't like the empty array + * initialization. (IAR Error[Pe1345]) + */ +#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) + +const Display_Config Display_config[] = { +#if (BOARD_DISPLAY_USE_UART) + { +# if (BOARD_DISPLAY_USE_UART_ANSI) + .fxnTablePtr = &DisplayUartAnsi_fxnTable, +# else /* Default to minimal UART with no cursor placement */ + .fxnTablePtr = &DisplayUartMin_fxnTable, +# endif + .object = &displayUartObject, + .hwAttrs = &displayUartHWAttrs, + }, +#endif +#if (BOARD_DISPLAY_USE_LCD) + { + .fxnTablePtr = &DisplaySharp_fxnTable, + .object = &displaySharpObject, + .hwAttrs = &displaySharpHWattrs + }, +#endif +}; + +const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); + +#else + +const Display_Config *Display_config = NULL; +const uint_least8_t Display_count = 0; + +#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ + +/* + * =============================== GPIO =============================== + */ +#include +#include + +/* + * Array of Pin configurations + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC1350_LAUNCHXL_433.h + * NOTE: Pins not used for interrupts should be placed at the end of the + * array. Callback entries can be omitted from callbacks array to + * reduce memory usage. + */ +GPIO_PinConfig gpioPinConfigs[] = { + /* Input pins */ + GPIOCC26XX_DIO_13 | GPIO_DO_NOT_CONFIG, /* Button 0 */ + GPIOCC26XX_DIO_14 | GPIO_DO_NOT_CONFIG, /* Button 1 */ + + GPIOCC26XX_DIO_15 | GPIO_DO_NOT_CONFIG, /* CC1350_LAUNCHXL_433_SPI_MASTER_READY */ + GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG, /* CC1350_LAUNCHXL_433_SPI_SLAVE_READY */ + + /* Output pins */ + GPIOCC26XX_DIO_07 | GPIO_DO_NOT_CONFIG, /* Green LED */ + GPIOCC26XX_DIO_06 | GPIO_DO_NOT_CONFIG, /* Red LED */ + + /* SPI Flash CSN */ + GPIOCC26XX_DIO_20 | GPIO_DO_NOT_CONFIG, + + /* SD CS */ + GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG, + + /* Sharp Display - GPIO configurations will be done in the Display files */ + GPIOCC26XX_DIO_24 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ + GPIOCC26XX_DIO_22 | GPIO_DO_NOT_CONFIG, /* LCD power control */ + GPIOCC26XX_DIO_23 | GPIO_DO_NOT_CONFIG, /*LCD enable */ + +}; + +/* + * Array of callback function pointers + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC1350_LAUNCHXL_433.h + * NOTE: Pins not used for interrupts can be omitted from callbacks array to + * reduce memory usage (if placed at end of gpioPinConfigs array). + */ +GPIO_CallbackFxn gpioCallbackFunctions[] = { + NULL, /* Button 0 */ + NULL, /* Button 1 */ + NULL, /* CC1350_LAUNCHXL_433_SPI_MASTER_READY */ + NULL, /* CC1350_LAUNCHXL_433_SPI_SLAVE_READY */ +}; + +const GPIOCC26XX_Config GPIOCC26XX_config = { + .pinConfigs = (GPIO_PinConfig *)gpioPinConfigs, + .callbacks = (GPIO_CallbackFxn *)gpioCallbackFunctions, + .numberOfPinConfigs = sizeof(gpioPinConfigs)/sizeof(GPIO_PinConfig), + .numberOfCallbacks = sizeof(gpioCallbackFunctions)/sizeof(GPIO_CallbackFxn), + .intPriority = (~0) +}; + +/* + * =============================== GPTimer =============================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +#include + +GPTimerCC26XX_Object gptimerCC26XXObjects[CC1350_LAUNCHXL_433_GPTIMERCOUNT]; + +const GPTimerCC26XX_HWAttrs gptimerCC26xxHWAttrs[CC1350_LAUNCHXL_433_GPTIMERPARTSCOUNT] = { + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0A, }, + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0B, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1A, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1B, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2A, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2B, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3A, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3B, }, +}; + +const GPTimerCC26XX_Config GPTimerCC26XX_config[CC1350_LAUNCHXL_433_GPTIMERPARTSCOUNT] = { + { &gptimerCC26XXObjects[CC1350_LAUNCHXL_433_GPTIMER0], &gptimerCC26xxHWAttrs[CC1350_LAUNCHXL_433_GPTIMER0A], GPT_A }, + { &gptimerCC26XXObjects[CC1350_LAUNCHXL_433_GPTIMER0], &gptimerCC26xxHWAttrs[CC1350_LAUNCHXL_433_GPTIMER0B], GPT_B }, + { &gptimerCC26XXObjects[CC1350_LAUNCHXL_433_GPTIMER1], &gptimerCC26xxHWAttrs[CC1350_LAUNCHXL_433_GPTIMER1A], GPT_A }, + { &gptimerCC26XXObjects[CC1350_LAUNCHXL_433_GPTIMER1], &gptimerCC26xxHWAttrs[CC1350_LAUNCHXL_433_GPTIMER1B], GPT_B }, + { &gptimerCC26XXObjects[CC1350_LAUNCHXL_433_GPTIMER2], &gptimerCC26xxHWAttrs[CC1350_LAUNCHXL_433_GPTIMER2A], GPT_A }, + { &gptimerCC26XXObjects[CC1350_LAUNCHXL_433_GPTIMER2], &gptimerCC26xxHWAttrs[CC1350_LAUNCHXL_433_GPTIMER2B], GPT_B }, + { &gptimerCC26XXObjects[CC1350_LAUNCHXL_433_GPTIMER3], &gptimerCC26xxHWAttrs[CC1350_LAUNCHXL_433_GPTIMER3A], GPT_A }, + { &gptimerCC26XXObjects[CC1350_LAUNCHXL_433_GPTIMER3], &gptimerCC26xxHWAttrs[CC1350_LAUNCHXL_433_GPTIMER3B], GPT_B }, +}; + +/* + * =============================== I2C =============================== +*/ +#include +#include + +I2CCC26XX_Object i2cCC26xxObjects[CC1350_LAUNCHXL_433_I2CCOUNT]; + +const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1350_LAUNCHXL_433_I2CCOUNT] = { + { + .baseAddr = I2C0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_I2C0, + .intNum = INT_I2C_IRQ, + .intPriority = ~0, + .swiPriority = 0, + .sdaPin = CC1350_LAUNCHXL_433_I2C0_SDA0, + .sclPin = CC1350_LAUNCHXL_433_I2C0_SCL0, + } +}; + +const I2C_Config I2C_config[CC1350_LAUNCHXL_433_I2CCOUNT] = { + { + .fxnTablePtr = &I2CCC26XX_fxnTable, + .object = &i2cCC26xxObjects[CC1350_LAUNCHXL_433_I2C0], + .hwAttrs = &i2cCC26xxHWAttrs[CC1350_LAUNCHXL_433_I2C0] + }, +}; + +const uint_least8_t I2C_count = CC1350_LAUNCHXL_433_I2CCOUNT; + +/* + * =============================== NVS =============================== + */ +#include +#include +#include + +#define NVS_REGIONS_BASE 0x1A000 +#define SECTORSIZE 0x1000 +#define REGIONSIZE (SECTORSIZE * 4) +#define SPIREGIONSIZE (SECTORSIZE * 32) +#define VERIFYBUFSIZE 64 + +static uint8_t verifyBuf[VERIFYBUFSIZE]; + +/* + * Reserve flash sectors for NVS driver use by placing an uninitialized byte + * array at the desired flash address. + */ +#if defined(__TI_COMPILER_VERSION__) + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +#pragma LOCATION(flashBuf, NVS_REGIONS_BASE); +#pragma NOINIT(flashBuf); +static char flashBuf[REGIONSIZE]; + +#elif defined(__IAR_SYSTEMS_ICC__) + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +static __no_init char flashBuf[REGIONSIZE] @ NVS_REGIONS_BASE; + +#elif defined(__GNUC__) + +/* + * Place the flash buffers in the .nvs section created in the gcc linker file. + * The .nvs section enforces alignment on a sector boundary but may + * be placed anywhere in flash memory. If desired the .nvs section can be set + * to a fixed address by changing the following in the gcc linker file: + * + * .nvs (FIXED_FLASH_ADDR) (NOLOAD) : AT (FIXED_FLASH_ADDR) { + * *(.nvs) + * } > REGION_TEXT + */ +__attribute__ ((section (".nvs"))) +static char flashBuf[REGIONSIZE]; + +#endif + +/* Allocate objects for NVS and NVS SPI */ +NVSCC26XX_Object nvsCC26xxObjects[1]; +NVSSPI25X_Object nvsSPI25XObjects[1]; + +/* Hardware attributes for NVS */ +const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { + { + .regionBase = (void *)flashBuf, + .regionSize = REGIONSIZE, + }, +}; + +/* Hardware attributes for NVS SPI */ +const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { + { + .regionBaseOffset = 0, + .regionSize = SPIREGIONSIZE, + .sectorSize = SECTORSIZE, + .verifyBuf = verifyBuf, + .verifyBufSize = VERIFYBUFSIZE, + .spiHandle = NULL, + .spiIndex = 0, + .spiBitRate = 4000000, + .spiCsnGpioIndex = CC1350_LAUNCHXL_433_GPIO_SPI_FLASH_CS, + }, +}; + +/* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ +const NVS_Config NVS_config[CC1350_LAUNCHXL_433_NVSCOUNT] = { + { + .fxnTablePtr = &NVSCC26XX_fxnTable, + .object = &nvsCC26xxObjects[0], + .hwAttrs = &nvsCC26xxHWAttrs[0], + }, + { + .fxnTablePtr = &NVSSPI25X_fxnTable, + .object = &nvsSPI25XObjects[0], + .hwAttrs = &nvsSPI25XHWAttrs[0], + }, +}; + +const uint_least8_t NVS_count = CC1350_LAUNCHXL_433_NVSCOUNT; + +/* + * =============================== PIN =============================== + */ +#include +#include + +const PIN_Config BoardGpioInitTable[] = { + + CC1350_LAUNCHXL_433_PIN_RLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC1350_LAUNCHXL_433_PIN_GLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC1350_LAUNCHXL_433_PIN_BTN1 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC1350_LAUNCHXL_433_PIN_BTN2 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC1350_LAUNCHXL_433_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ + CC1350_LAUNCHXL_433_UART_RX | PIN_INPUT_EN | PIN_PULLDOWN, /* UART RX via debugger back channel */ + CC1350_LAUNCHXL_433_UART_TX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* UART TX via debugger back channel */ + CC1350_LAUNCHXL_433_DIO1_RF_SUB1GHZ | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* RF SW Switch defaults to 2.4 GHz path*/ + CC1350_LAUNCHXL_433_DIO30_RF_POWER | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* External RF Switch is powered off by default */ + CC1350_LAUNCHXL_433_SPI0_MOSI | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master out - slave in */ + CC1350_LAUNCHXL_433_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master in - slave out */ + CC1350_LAUNCHXL_433_SPI0_CLK | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI clock */ + PIN_TERMINATE +}; + +const PINCC26XX_HWAttrs PINCC26XX_hwAttrs = { + .intPriority = ~0, + .swiPriority = 0 +}; + +/* + * =============================== Power =============================== + */ +#include +#include + +const PowerCC26XX_Config PowerCC26XX_config = { + .policyInitFxn = NULL, + .policyFxn = &PowerCC26XX_standbyPolicy, + .calibrateFxn = &PowerCC26XX_calibrate, + .enablePolicy = true, + .calibrateRCOSC_LF = true, + .calibrateRCOSC_HF = true, +}; + +/* + * =============================== PWM =============================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +#include +#include + +PWMTimerCC26XX_Object pwmtimerCC26xxObjects[CC1350_LAUNCHXL_433_PWMCOUNT]; + +const PWMTimerCC26XX_HwAttrs pwmtimerCC26xxHWAttrs[CC1350_LAUNCHXL_433_PWMCOUNT] = { + { .pwmPin = CC1350_LAUNCHXL_433_PWMPIN0, .gpTimerUnit = CC1350_LAUNCHXL_433_GPTIMER0A }, + { .pwmPin = CC1350_LAUNCHXL_433_PWMPIN1, .gpTimerUnit = CC1350_LAUNCHXL_433_GPTIMER0B }, + { .pwmPin = CC1350_LAUNCHXL_433_PWMPIN2, .gpTimerUnit = CC1350_LAUNCHXL_433_GPTIMER1A }, + { .pwmPin = CC1350_LAUNCHXL_433_PWMPIN3, .gpTimerUnit = CC1350_LAUNCHXL_433_GPTIMER1B }, + { .pwmPin = CC1350_LAUNCHXL_433_PWMPIN4, .gpTimerUnit = CC1350_LAUNCHXL_433_GPTIMER2A }, + { .pwmPin = CC1350_LAUNCHXL_433_PWMPIN5, .gpTimerUnit = CC1350_LAUNCHXL_433_GPTIMER2B }, + { .pwmPin = CC1350_LAUNCHXL_433_PWMPIN6, .gpTimerUnit = CC1350_LAUNCHXL_433_GPTIMER3A }, + { .pwmPin = CC1350_LAUNCHXL_433_PWMPIN7, .gpTimerUnit = CC1350_LAUNCHXL_433_GPTIMER3B }, +}; + +const PWM_Config PWM_config[CC1350_LAUNCHXL_433_PWMCOUNT] = { + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350_LAUNCHXL_433_PWM0], &pwmtimerCC26xxHWAttrs[CC1350_LAUNCHXL_433_PWM0] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350_LAUNCHXL_433_PWM1], &pwmtimerCC26xxHWAttrs[CC1350_LAUNCHXL_433_PWM1] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350_LAUNCHXL_433_PWM2], &pwmtimerCC26xxHWAttrs[CC1350_LAUNCHXL_433_PWM2] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350_LAUNCHXL_433_PWM3], &pwmtimerCC26xxHWAttrs[CC1350_LAUNCHXL_433_PWM3] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350_LAUNCHXL_433_PWM4], &pwmtimerCC26xxHWAttrs[CC1350_LAUNCHXL_433_PWM4] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350_LAUNCHXL_433_PWM5], &pwmtimerCC26xxHWAttrs[CC1350_LAUNCHXL_433_PWM5] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350_LAUNCHXL_433_PWM6], &pwmtimerCC26xxHWAttrs[CC1350_LAUNCHXL_433_PWM6] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350_LAUNCHXL_433_PWM7], &pwmtimerCC26xxHWAttrs[CC1350_LAUNCHXL_433_PWM7] }, +}; + +const uint_least8_t PWM_count = CC1350_LAUNCHXL_433_PWMCOUNT; + +/* + * =============================== RF Driver =============================== + */ +#include + +/* + * Board-specific callback function to set the correct antenna path. + * + * This function is called by the RF driver on global driver events. It contains + * a default implementation to set the correct antenna path. + */ +static void CC1350_LAUNCHXL_433_rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void *arg); + +const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { + .hwiPriority = ~0, /* Lowest HWI priority */ + .swiPriority = 0, /* Lowest SWI priority */ + .xoscHfAlwaysNeeded = true, /* Keep XOSC dependency while in stanby */ + .globalCallback = &CC1350_LAUNCHXL_433_rfDriverCallback, /* Register the board specific callback */ + .globalEventMask = RF_GlobalEventRadioSetup | RF_GlobalEventRadioPowerDown /* Subscribe the callback to both events */ +}; + +/* + * =============================== SD =============================== + */ +#include +#include + +SDSPI_Object sdspiObjects[CC1350_LAUNCHXL_433_SDCOUNT]; + +const SDSPI_HWAttrs sdspiHWAttrs[CC1350_LAUNCHXL_433_SDCOUNT] = { + { + .spiIndex = CC1350_LAUNCHXL_433_SPI0, + .spiCsGpioIndex = CC1350_LAUNCHXL_433_SDSPI_CS + } +}; + +const SD_Config SD_config[CC1350_LAUNCHXL_433_SDCOUNT] = { + { + .fxnTablePtr = &SDSPI_fxnTable, + .object = &sdspiObjects[CC1350_LAUNCHXL_433_SDSPI0], + .hwAttrs = &sdspiHWAttrs[CC1350_LAUNCHXL_433_SDSPI0] + }, +}; + +const uint_least8_t SD_count = CC1350_LAUNCHXL_433_SDCOUNT; + +/* + * =============================== SPI DMA =============================== + */ +#include +#include + +SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1350_LAUNCHXL_433_SPICOUNT]; + +/* + * NOTE: The SPI instances below can be used by the SD driver to communicate + * with a SD card via SPI. The 'defaultTxBufValue' fields below are set to 0xFF + * to satisfy the SDSPI driver requirement. + */ +const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1350_LAUNCHXL_433_SPICOUNT] = { + { + .baseAddr = SSI0_BASE, + .intNum = INT_SSI0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .powerMngrId = PowerCC26XX_PERIPH_SSI0, + .defaultTxBufValue = 0xFF, + .rxChannelBitMask = 1< +#include + +UARTCC26XX_Object uartCC26XXObjects[CC1350_LAUNCHXL_433_UARTCOUNT]; + +uint8_t uartCC26XXRingBuffer[CC1350_LAUNCHXL_433_UARTCOUNT][32]; + +const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1350_LAUNCHXL_433_UARTCOUNT] = { + { + .baseAddr = UART0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UART0, + .intNum = INT_UART0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .txPin = CC1350_LAUNCHXL_433_UART_TX, + .rxPin = CC1350_LAUNCHXL_433_UART_RX, + .ctsPin = PIN_UNASSIGNED, + .rtsPin = PIN_UNASSIGNED, + .ringBufPtr = uartCC26XXRingBuffer[CC1350_LAUNCHXL_433_UART0], + .ringBufSize = sizeof(uartCC26XXRingBuffer[CC1350_LAUNCHXL_433_UART0]), + .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, + .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, + .errorFxn = NULL + } +}; + +const UART_Config UART_config[CC1350_LAUNCHXL_433_UARTCOUNT] = { + { + .fxnTablePtr = &UARTCC26XX_fxnTable, + .object = &uartCC26XXObjects[CC1350_LAUNCHXL_433_UART0], + .hwAttrs = &uartCC26XXHWAttrs[CC1350_LAUNCHXL_433_UART0] + }, +}; + +const uint_least8_t UART_count = CC1350_LAUNCHXL_433_UARTCOUNT; + +/* + * =============================== UDMA =============================== + */ +#include + +UDMACC26XX_Object udmaObjects[CC1350_LAUNCHXL_433_UDMACOUNT]; + +const UDMACC26XX_HWAttrs udmaHWAttrs[CC1350_LAUNCHXL_433_UDMACOUNT] = { + { + .baseAddr = UDMA0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UDMA, + .intNum = INT_DMA_ERR, + .intPriority = ~0 + } +}; + +const UDMACC26XX_Config UDMACC26XX_config[CC1350_LAUNCHXL_433_UDMACOUNT] = { + { + .object = &udmaObjects[CC1350_LAUNCHXL_433_UDMA0], + .hwAttrs = &udmaHWAttrs[CC1350_LAUNCHXL_433_UDMA0] + }, +}; + +/* + * =============================== Watchdog =============================== + */ +#include +#include + +WatchdogCC26XX_Object watchdogCC26XXObjects[CC1350_LAUNCHXL_433_WATCHDOGCOUNT]; + +const WatchdogCC26XX_HWAttrs watchdogCC26XXHWAttrs[CC1350_LAUNCHXL_433_WATCHDOGCOUNT] = { + { + .baseAddr = WDT_BASE, + .reloadValue = 1000 /* Reload value in milliseconds */ + }, +}; + +const Watchdog_Config Watchdog_config[CC1350_LAUNCHXL_433_WATCHDOGCOUNT] = { + { + .fxnTablePtr = &WatchdogCC26XX_fxnTable, + .object = &watchdogCC26XXObjects[CC1350_LAUNCHXL_433_WATCHDOG0], + .hwAttrs = &watchdogCC26XXHWAttrs[CC1350_LAUNCHXL_433_WATCHDOG0] + }, +}; + +const uint_least8_t Watchdog_count = CC1350_LAUNCHXL_433_WATCHDOGCOUNT; + +/* + * ======== CC1350_LAUNCHXL_433_wakeUpExtFlash ======== + */ +void CC1350_LAUNCHXL_433_wakeUpExtFlash(void) +{ + PIN_Config extFlashPinTable[] = { + CC1350_LAUNCHXL_433_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + /* + * To wake up we need to toggle the chip select at + * least 20 ns and ten wait at least 35 us. + */ + + /* Toggle chip select for ~20ns to wake ext. flash */ + PIN_setOutputValue(extFlashPinHandle, CC1350_LAUNCHXL_433_SPI_FLASH_CS, 0); + /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ + CPUdelay(1); + PIN_setOutputValue(extFlashPinHandle, CC1350_LAUNCHXL_433_SPI_FLASH_CS, 1); + /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ + CPUdelay(560); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC1350_LAUNCHXL_433_sendExtFlashByte ======== + */ +void CC1350_LAUNCHXL_433_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) +{ + uint8_t i; + + PIN_setOutputValue(pinHandle, CC1350_LAUNCHXL_433_SPI_FLASH_CS, 0); + + for (i = 0; i < 8; i++) { + PIN_setOutputValue(pinHandle, CC1350_LAUNCHXL_433_SPI0_CLK, 0); + PIN_setOutputValue(pinHandle, CC1350_LAUNCHXL_433_SPI0_MOSI, (byte >> (7 - i)) & 0x01); + PIN_setOutputValue(pinHandle, CC1350_LAUNCHXL_433_SPI0_CLK, 1); + + /* + * Waste a few cycles to keep the CLK high for at + * least 45% of the period. + * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. + */ + CPUdelay(8); + } + + PIN_setOutputValue(pinHandle, CC1350_LAUNCHXL_433_SPI0_CLK, 0); + PIN_setOutputValue(pinHandle, CC1350_LAUNCHXL_433_SPI_FLASH_CS, 1); + + /* + * Keep CS high at least 40 us + * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us + */ + CPUdelay(700); +} + +/* + * ======== CC1350_LAUNCHXL_433_shutDownExtFlash ======== + */ +void CC1350_LAUNCHXL_433_shutDownExtFlash(void) +{ + /* To be sure we are putting the flash into sleep and not waking it, we first have to make a wake up call */ + CC1350_LAUNCHXL_433_wakeUpExtFlash(); + + PIN_Config extFlashPinTable[] = { + CC1350_LAUNCHXL_433_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + CC1350_LAUNCHXL_433_SPI0_CLK | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + CC1350_LAUNCHXL_433_SPI0_MOSI | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + CC1350_LAUNCHXL_433_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + uint8_t extFlashShutdown = 0xB9; + + CC1350_LAUNCHXL_433_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC1350_LAUNCHXL_433_initGeneral ======== + */ +void CC1350_LAUNCHXL_433_initGeneral(void) +{ + Power_init(); + + if ( PIN_init(BoardGpioInitTable) != PIN_SUCCESS) { + /* Error with PIN_init */ + while (1); + } + + /* Shut down external flash as default */ + CC1350_LAUNCHXL_433_shutDownExtFlash(); +} + +/* + * ======== CC1350_LAUNCHXL_433_rfDriverCallback ======== + * This is an implementation for the CC1350 launchpad which uses a + * single signal for antenna switching. + */ +void CC1350_LAUNCHXL_433_rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void *arg) +{ + (void)client; + RF_RadioSetup* setupCommand = (RF_RadioSetup*)arg; + + if (events & RF_GlobalEventRadioSetup) { + /* Power up the antenna switch */ + PINCC26XX_setOutputValue(CC1350_LAUNCHXL_433_DIO30_RF_POWER, 1); + + if (setupCommand->common.commandNo == CMD_PROP_RADIO_DIV_SETUP) { + /* Sub-1 GHz, requires antenna switch high */ + PINCC26XX_setOutputValue(CC1350_LAUNCHXL_433_DIO1_RF_SUB1GHZ, 1); + } + + } else if (events & RF_GlobalEventRadioPowerDown) { + /* Disable antenna switch to save current */ + PINCC26XX_setOutputValue(CC1350_LAUNCHXL_433_DIO30_RF_POWER, 0); + PINCC26XX_setOutputValue(CC1350_LAUNCHXL_433_DIO1_RF_SUB1GHZ, 0); + } +} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h new file mode 100644 index 000000000..eb68e92b6 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2017-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ +/** ============================================================================ + * @file CC1350_LAUNCHXL_433.h + * + * @brief CC1350 LaunchPad Board Specific header file. + * + * The CC1350_LAUNCHXL_433 header file should be included in an application as + * follows: + * @code + * #include "CC1350_LAUNCHXL_433.h" + * @endcode + * + * ============================================================================ + */ +#ifndef __CC1350_LAUNCHXL_433_BOARD_H__ +#define __CC1350_LAUNCHXL_433_BOARD_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes */ +#include +#include + +/* Externs */ +extern const PIN_Config BoardGpioInitTable[]; + +/* Defines */ +#define CC1350_LAUNCHXL_433 + +/* Mapping of pins to board signals using general board aliases + * + */ + +/* Analog Capable DIOs */ +#define CC1350_LAUNCHXL_433_DIO23_ANALOG IOID_23 +#define CC1350_LAUNCHXL_433_DIO24_ANALOG IOID_24 +#define CC1350_LAUNCHXL_433_DIO25_ANALOG IOID_25 +#define CC1350_LAUNCHXL_433_DIO26_ANALOG IOID_26 +#define CC1350_LAUNCHXL_433_DIO27_ANALOG IOID_27 +#define CC1350_LAUNCHXL_433_DIO28_ANALOG IOID_28 +#define CC1350_LAUNCHXL_433_DIO29_ANALOG IOID_29 +#define CC1350_LAUNCHXL_433_DIO30_ANALOG IOID_30 + +/* Digital IOs */ +#define CC1350_LAUNCHXL_433_DIO0 IOID_0 +#define CC1350_LAUNCHXL_433_DIO1_RF_SUB1GHZ IOID_1 +#define CC1350_LAUNCHXL_433_DIO12 IOID_12 +#define CC1350_LAUNCHXL_433_DIO15 IOID_15 +#define CC1350_LAUNCHXL_433_DIO16_TDO IOID_16 +#define CC1350_LAUNCHXL_433_DIO17_TDI IOID_17 +#define CC1350_LAUNCHXL_433_DIO21 IOID_21 +#define CC1350_LAUNCHXL_433_DIO22 IOID_22 +#define CC1350_LAUNCHXL_433_DIO30_RF_POWER IOID_30 + +/* Discrete Inputs */ +#define CC1350_LAUNCHXL_433_PIN_BTN1 IOID_13 +#define CC1350_LAUNCHXL_433_PIN_BTN2 IOID_14 + + +/* GPIO */ +#define CC1350_LAUNCHXL_433_GPIO_LED_ON 1 +#define CC1350_LAUNCHXL_433_GPIO_LED_OFF 0 + +/* I2C */ +#define CC1350_LAUNCHXL_433_I2C0_SCL0 IOID_4 +#define CC1350_LAUNCHXL_433_I2C0_SDA0 IOID_5 + + +/* LEDs */ +#define CC1350_LAUNCHXL_433_PIN_LED_ON 1 +#define CC1350_LAUNCHXL_433_PIN_LED_OFF 0 +#define CC1350_LAUNCHXL_433_PIN_RLED IOID_6 +#define CC1350_LAUNCHXL_433_PIN_GLED IOID_7 + +/* PWM Outputs */ +#define CC1350_LAUNCHXL_433_PWMPIN0 CC1350_LAUNCHXL_433_PIN_RLED +#define CC1350_LAUNCHXL_433_PWMPIN1 CC1350_LAUNCHXL_433_PIN_GLED +#define CC1350_LAUNCHXL_433_PWMPIN2 PIN_UNASSIGNED +#define CC1350_LAUNCHXL_433_PWMPIN3 PIN_UNASSIGNED +#define CC1350_LAUNCHXL_433_PWMPIN4 PIN_UNASSIGNED +#define CC1350_LAUNCHXL_433_PWMPIN5 PIN_UNASSIGNED +#define CC1350_LAUNCHXL_433_PWMPIN6 PIN_UNASSIGNED +#define CC1350_LAUNCHXL_433_PWMPIN7 PIN_UNASSIGNED + +/* SPI */ +#define CC1350_LAUNCHXL_433_SPI_FLASH_CS IOID_20 +#define CC1350_LAUNCHXL_433_FLASH_CS_ON 0 +#define CC1350_LAUNCHXL_433_FLASH_CS_OFF 1 + +/* SPI Board */ +#define CC1350_LAUNCHXL_433_SPI0_MISO IOID_8 /* RF1.20 */ +#define CC1350_LAUNCHXL_433_SPI0_MOSI IOID_9 /* RF1.18 */ +#define CC1350_LAUNCHXL_433_SPI0_CLK IOID_10 /* RF1.16 */ +#define CC1350_LAUNCHXL_433_SPI0_CSN PIN_UNASSIGNED +#define CC1350_LAUNCHXL_433_SPI1_MISO PIN_UNASSIGNED +#define CC1350_LAUNCHXL_433_SPI1_MOSI PIN_UNASSIGNED +#define CC1350_LAUNCHXL_433_SPI1_CLK PIN_UNASSIGNED +#define CC1350_LAUNCHXL_433_SPI1_CSN PIN_UNASSIGNED + +/* UART Board */ +#define CC1350_LAUNCHXL_433_UART_RX IOID_2 /* RXD */ +#define CC1350_LAUNCHXL_433_UART_TX IOID_3 /* TXD */ +#define CC1350_LAUNCHXL_433_UART_CTS IOID_19 /* CTS */ +#define CC1350_LAUNCHXL_433_UART_RTS IOID_18 /* RTS */ + +/*! + * @brief Initialize the general board specific settings + * + * This function initializes the general board specific settings. + */ +void CC1350_LAUNCHXL_433_initGeneral(void); + +/*! + * @brief Turn off the external flash on LaunchPads + * + */ +void CC1350_LAUNCHXL_433_shutDownExtFlash(void); + +/*! + * @brief Wake up the external flash present on the board files + * + * This function toggles the chip select for the amount of time needed + * to wake the chip up. + */ +void CC1350_LAUNCHXL_433_wakeUpExtFlash(void); + +/*! + * @def CC1350_LAUNCHXL_433_ADCBufName + * @brief Enum of ADCBufs + */ +typedef enum CC1350_LAUNCHXL_433_ADCBufName { + CC1350_LAUNCHXL_433_ADCBUF0 = 0, + + CC1350_LAUNCHXL_433_ADCBUFCOUNT +} CC1350_LAUNCHXL_433_ADCBufName; + +/*! + * @def CC1350_LAUNCHXL_433_ADCBuf0SourceName + * @brief Enum of ADCBuf channels + */ +typedef enum CC1350_LAUNCHXL_433_ADCBuf0ChannelName { + CC1350_LAUNCHXL_433_ADCBUF0CHANNEL0 = 0, + CC1350_LAUNCHXL_433_ADCBUF0CHANNEL1, + CC1350_LAUNCHXL_433_ADCBUF0CHANNEL2, + CC1350_LAUNCHXL_433_ADCBUF0CHANNEL3, + CC1350_LAUNCHXL_433_ADCBUF0CHANNEL4, + CC1350_LAUNCHXL_433_ADCBUF0CHANNEL5, + CC1350_LAUNCHXL_433_ADCBUF0CHANNEL6, + CC1350_LAUNCHXL_433_ADCBUF0CHANNEL7, + CC1350_LAUNCHXL_433_ADCBUF0CHANNELVDDS, + CC1350_LAUNCHXL_433_ADCBUF0CHANNELDCOUPL, + CC1350_LAUNCHXL_433_ADCBUF0CHANNELVSS, + + CC1350_LAUNCHXL_433_ADCBUF0CHANNELCOUNT +} CC1350_LAUNCHXL_433_ADCBuf0ChannelName; + +/*! + * @def CC1350_LAUNCHXL_433_ADCName + * @brief Enum of ADCs + */ +typedef enum CC1350_LAUNCHXL_433_ADCName { + CC1350_LAUNCHXL_433_ADC0 = 0, + CC1350_LAUNCHXL_433_ADC1, + CC1350_LAUNCHXL_433_ADC2, + CC1350_LAUNCHXL_433_ADC3, + CC1350_LAUNCHXL_433_ADC4, + CC1350_LAUNCHXL_433_ADC5, + CC1350_LAUNCHXL_433_ADC6, + CC1350_LAUNCHXL_433_ADC7, + CC1350_LAUNCHXL_433_ADCDCOUPL, + CC1350_LAUNCHXL_433_ADCVSS, + CC1350_LAUNCHXL_433_ADCVDDS, + + CC1350_LAUNCHXL_433_ADCCOUNT +} CC1350_LAUNCHXL_433_ADCName; + +/*! + * @def CC1350_LAUNCHXL_433_CryptoName + * @brief Enum of Crypto names + */ +typedef enum CC1350_LAUNCHXL_433_CryptoName { + CC1350_LAUNCHXL_433_CRYPTO0 = 0, + + CC1350_LAUNCHXL_433_CRYPTOCOUNT +} CC1350_LAUNCHXL_433_CryptoName; + +/*! + * @def CC1350_LAUNCHXL_433_GPIOName + * @brief Enum of GPIO names + */ +typedef enum CC1350_LAUNCHXL_433_GPIOName { + CC1350_LAUNCHXL_433_GPIO_S1 = 0, + CC1350_LAUNCHXL_433_GPIO_S2, + CC1350_LAUNCHXL_433_SPI_MASTER_READY, + CC1350_LAUNCHXL_433_SPI_SLAVE_READY, + CC1350_LAUNCHXL_433_GPIO_LED_GREEN, + CC1350_LAUNCHXL_433_GPIO_LED_RED, + CC1350_LAUNCHXL_433_GPIO_SPI_FLASH_CS, + CC1350_LAUNCHXL_433_SDSPI_CS, + CC1350_LAUNCHXL_433_GPIO_LCD_CS, + CC1350_LAUNCHXL_433_GPIO_LCD_POWER, + CC1350_LAUNCHXL_433_GPIO_LCD_ENABLE, + CC1350_LAUNCHXL_433_GPIOCOUNT +} CC1350_LAUNCHXL_433_GPIOName; + +/*! + * @def CC1350_LAUNCHXL_433_GPTimerName + * @brief Enum of GPTimer parts + */ +typedef enum CC1350_LAUNCHXL_433_GPTimerName { + CC1350_LAUNCHXL_433_GPTIMER0A = 0, + CC1350_LAUNCHXL_433_GPTIMER0B, + CC1350_LAUNCHXL_433_GPTIMER1A, + CC1350_LAUNCHXL_433_GPTIMER1B, + CC1350_LAUNCHXL_433_GPTIMER2A, + CC1350_LAUNCHXL_433_GPTIMER2B, + CC1350_LAUNCHXL_433_GPTIMER3A, + CC1350_LAUNCHXL_433_GPTIMER3B, + + CC1350_LAUNCHXL_433_GPTIMERPARTSCOUNT +} CC1350_LAUNCHXL_433_GPTimerName; + +/*! + * @def CC1350_LAUNCHXL_433_GPTimers + * @brief Enum of GPTimers + */ +typedef enum CC1350_LAUNCHXL_433_GPTimers { + CC1350_LAUNCHXL_433_GPTIMER0 = 0, + CC1350_LAUNCHXL_433_GPTIMER1, + CC1350_LAUNCHXL_433_GPTIMER2, + CC1350_LAUNCHXL_433_GPTIMER3, + + CC1350_LAUNCHXL_433_GPTIMERCOUNT +} CC1350_LAUNCHXL_433_GPTimers; + +/*! + * @def CC1350_LAUNCHXL_433_I2CName + * @brief Enum of I2C names + */ +typedef enum CC1350_LAUNCHXL_433_I2CName { + CC1350_LAUNCHXL_433_I2C0 = 0, + + CC1350_LAUNCHXL_433_I2CCOUNT +} CC1350_LAUNCHXL_433_I2CName; + +/*! + * @def CC1350_LAUNCHXL_433_NVSName + * @brief Enum of NVS names + */ +typedef enum CC1350_LAUNCHXL_433_NVSName { + CC1350_LAUNCHXL_433_NVSCC26XX0 = 0, + CC1350_LAUNCHXL_433_NVSSPI25X0, + + CC1350_LAUNCHXL_433_NVSCOUNT +} CC1350_LAUNCHXL_433_NVSName; + +/*! + * @def CC1350_LAUNCHXL_433_PWM + * @brief Enum of PWM outputs + */ +typedef enum CC1350_LAUNCHXL_433_PWMName { + CC1350_LAUNCHXL_433_PWM0 = 0, + CC1350_LAUNCHXL_433_PWM1, + CC1350_LAUNCHXL_433_PWM2, + CC1350_LAUNCHXL_433_PWM3, + CC1350_LAUNCHXL_433_PWM4, + CC1350_LAUNCHXL_433_PWM5, + CC1350_LAUNCHXL_433_PWM6, + CC1350_LAUNCHXL_433_PWM7, + + CC1350_LAUNCHXL_433_PWMCOUNT +} CC1350_LAUNCHXL_433_PWMName; + +/*! + * @def CC1350_LAUNCHXL_433_SDName + * @brief Enum of SD names + */ +typedef enum CC1350_LAUNCHXL_433_SDName { + CC1350_LAUNCHXL_433_SDSPI0 = 0, + + CC1350_LAUNCHXL_433_SDCOUNT +} CC1350_LAUNCHXL_433_SDName; + +/*! + * @def CC1350_LAUNCHXL_433_SPIName + * @brief Enum of SPI names + */ +typedef enum CC1350_LAUNCHXL_433_SPIName { + CC1350_LAUNCHXL_433_SPI0 = 0, + CC1350_LAUNCHXL_433_SPI1, + + CC1350_LAUNCHXL_433_SPICOUNT +} CC1350_LAUNCHXL_433_SPIName; + +/*! + * @def CC1350_LAUNCHXL_433_UARTName + * @brief Enum of UARTs + */ +typedef enum CC1350_LAUNCHXL_433_UARTName { + CC1350_LAUNCHXL_433_UART0 = 0, + + CC1350_LAUNCHXL_433_UARTCOUNT +} CC1350_LAUNCHXL_433_UARTName; + +/*! + * @def CC1350_LAUNCHXL_433_UDMAName + * @brief Enum of DMA buffers + */ +typedef enum CC1350_LAUNCHXL_433_UDMAName { + CC1350_LAUNCHXL_433_UDMA0 = 0, + + CC1350_LAUNCHXL_433_UDMACOUNT +} CC1350_LAUNCHXL_433_UDMAName; + +/*! + * @def CC1350_LAUNCHXL_433_WatchdogName + * @brief Enum of Watchdogs + */ +typedef enum CC1350_LAUNCHXL_433_WatchdogName { + CC1350_LAUNCHXL_433_WATCHDOG0 = 0, + + CC1350_LAUNCHXL_433_WATCHDOGCOUNT +} CC1350_LAUNCHXL_433_WatchdogName; + +#ifdef __cplusplus +} +#endif + +#endif /* __CC1350_LAUNCHXL_433_BOARD_H__ */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Makefile.cc1350-4 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Makefile.cc1350-4 new file mode 100644 index 000000000..23e5803f3 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Makefile.cc1350-4 @@ -0,0 +1,16 @@ +################################################################################ +# SimpleLink Device makefile + +SUBFAMILY = cc13x0-cc26x0 +DEVICE_FAMILY = CC13X0 + +BOARD_SOURCEFILES += CC1350_LAUNCHXL_433.c + +SUPPORTS_PROP_MODE = 1 +SUPPORTS_IEEE_MODE = 1 + +### Signal that we can be programmed with cc2538-bsl +BOARD_SUPPORTS_BSL = 1 + +# Include the common board makefile +include $(FAMILY_PATH)/launchpad/Makefile.launchpad diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Board.h new file mode 100644 index 000000000..a3dd8068f --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Board.h @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2015-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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 __BOARD_H +#define __BOARD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "CC1350_LAUNCHXL.h" + +#define Board_initGeneral() CC1350_LAUNCHXL_initGeneral() +#define Board_shutDownExtFlash() CC1350_LAUNCHXL_shutDownExtFlash() +#define Board_wakeUpExtFlash() CC1350_LAUNCHXL_wakeUpExtFlash() + +/* These #defines allow us to reuse TI-RTOS across other device families */ +#define Board_ADC0 CC1350_LAUNCHXL_ADC0 +#define Board_ADC1 CC1350_LAUNCHXL_ADC1 + +#define Board_ADCBUF0 CC1350_LAUNCHXL_ADCBUF0 +#define Board_ADCBUF0CHANNEL0 CC1350_LAUNCHXL_ADCBUF0CHANNEL0 +#define Board_ADCBUF0CHANNEL1 CC1350_LAUNCHXL_ADCBUF0CHANNEL1 + +#define Board_CRYPTO0 CC1350_LAUNCHXL_CRYPTO0 + +#define Board_DIO0 CC1350_LAUNCHXL_DIO0 +#define Board_DIO1_RFSW CC1350_LAUNCHXL_DIO1_RF_SUB1GHZ +#define Board_DIO12 CC1350_LAUNCHXL_DIO12 +#define Board_DIO15 CC1350_LAUNCHXL_DIO15 +#define Board_DIO16_TDO CC1350_LAUNCHXL_DIO16_TDO +#define Board_DIO17_TDI CC1350_LAUNCHXL_DIO17_TDI +#define Board_DIO21 CC1350_LAUNCHXL_DIO21 +#define Board_DIO22 CC1350_LAUNCHXL_DIO22 +#define Board_DIO30_SWPWR CC1350_LAUNCHXL_DIO30_RF_POWER + +#define Board_DIO23_ANALOG CC1350_LAUNCHXL_DIO23_ANALOG +#define Board_DIO24_ANALOG CC1350_LAUNCHXL_DIO24_ANALOG +#define Board_DIO25_ANALOG CC1350_LAUNCHXL_DIO25_ANALOG +#define Board_DIO26_ANALOG CC1350_LAUNCHXL_DIO26_ANALOG +#define Board_DIO27_ANALOG CC1350_LAUNCHXL_DIO27_ANALOG +#define Board_DIO28_ANALOG CC1350_LAUNCHXL_DIO28_ANALOG +#define Board_DIO29_ANALOG CC1350_LAUNCHXL_DIO29_ANALOG +#define Board_DIO30_ANALOG CC1350_LAUNCHXL_DIO30_ANALOG + +#define Board_GPIO_BUTTON0 CC1350_LAUNCHXL_GPIO_S1 +#define Board_GPIO_BUTTON1 CC1350_LAUNCHXL_GPIO_S2 +#define Board_GPIO_BTN1 CC1350_LAUNCHXL_GPIO_S1 +#define Board_GPIO_BTN2 CC1350_LAUNCHXL_GPIO_S2 +#define Board_GPIO_LED0 CC1350_LAUNCHXL_GPIO_LED_RED +#define Board_GPIO_LED1 CC1350_LAUNCHXL_GPIO_LED_GREEN +#define Board_GPIO_RLED CC1350_LAUNCHXL_GPIO_LED_RED +#define Board_GPIO_GLED CC1350_LAUNCHXL_GPIO_LED_GREEN +#define Board_GPIO_LED_ON CC1350_LAUNCHXL_GPIO_LED_ON +#define Board_GPIO_LED_OFF CC1350_LAUNCHXL_GPIO_LED_OFF + +#define Board_GPTIMER0A CC1350_LAUNCHXL_GPTIMER0A +#define Board_GPTIMER0B CC1350_LAUNCHXL_GPTIMER0B +#define Board_GPTIMER1A CC1350_LAUNCHXL_GPTIMER1A +#define Board_GPTIMER1B CC1350_LAUNCHXL_GPTIMER1B +#define Board_GPTIMER2A CC1350_LAUNCHXL_GPTIMER2A +#define Board_GPTIMER2B CC1350_LAUNCHXL_GPTIMER2B +#define Board_GPTIMER3A CC1350_LAUNCHXL_GPTIMER3A +#define Board_GPTIMER3B CC1350_LAUNCHXL_GPTIMER3B + +#define Board_NVSINTERNAL CC1350_LAUNCHXL_NVSCC26XX0 +#define Board_NVSEXTERNAL CC1350_LAUNCHXL_NVSSPI25X0 + +#define Board_I2C0 CC1350_LAUNCHXL_I2C0 +#define Board_I2C_TMP CC1350_LAUNCHXL_I2C0 + +#define Board_PIN_BUTTON0 CC1350_LAUNCHXL_PIN_BTN1 +#define Board_PIN_BUTTON1 CC1350_LAUNCHXL_PIN_BTN2 +#define Board_PIN_BTN1 CC1350_LAUNCHXL_PIN_BTN1 +#define Board_PIN_BTN2 CC1350_LAUNCHXL_PIN_BTN2 +#define Board_PIN_LED0 CC1350_LAUNCHXL_PIN_RLED +#define Board_PIN_LED1 CC1350_LAUNCHXL_PIN_GLED +#define Board_PIN_LED2 CC1350_LAUNCHXL_PIN_RLED +#define Board_PIN_RLED CC1350_LAUNCHXL_PIN_RLED +#define Board_PIN_GLED CC1350_LAUNCHXL_PIN_GLED + +#define Board_PWM0 CC1350_LAUNCHXL_PWM0 +#define Board_PWM1 CC1350_LAUNCHXL_PWM1 +#define Board_PWM2 CC1350_LAUNCHXL_PWM2 +#define Board_PWM3 CC1350_LAUNCHXL_PWM3 +#define Board_PWM4 CC1350_LAUNCHXL_PWM4 +#define Board_PWM5 CC1350_LAUNCHXL_PWM5 +#define Board_PWM6 CC1350_LAUNCHXL_PWM6 +#define Board_PWM7 CC1350_LAUNCHXL_PWM7 + +#define Board_SD0 CC1350_LAUNCHXL_SDSPI0 + +#define Board_SPI0 CC1350_LAUNCHXL_SPI0 +#define Board_SPI1 CC1350_LAUNCHXL_SPI1 +#define Board_SPI_FLASH_CS CC1350_LAUNCHXL_SPI_FLASH_CS +#define Board_FLASH_CS_ON (0) +#define Board_FLASH_CS_OFF (1) + +#define Board_SPI_MASTER CC1350_LAUNCHXL_SPI0 +#define Board_SPI_SLAVE CC1350_LAUNCHXL_SPI0 +#define Board_SPI_MASTER_READY CC1350_LAUNCHXL_SPI_MASTER_READY +#define Board_SPI_SLAVE_READY CC1350_LAUNCHXL_SPI_SLAVE_READY + +#define Board_UART0 CC1350_LAUNCHXL_UART0 + +#define Board_WATCHDOG0 CC1350_LAUNCHXL_WATCHDOG0 + +/* Board specific I2C addresses */ +#define Board_TMP_ADDR (0x40) +#define Board_SENSORS_BP_TMP_ADDR Board_TMP_ADDR + +#ifdef __cplusplus +} +#endif + +#endif /* __BOARD_H */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c new file mode 100644 index 000000000..0ead97912 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c @@ -0,0 +1,946 @@ +/* + * Copyright (c) 2015-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +/* + * ============================ CC1350_LAUNCHXL.c ============================ + * This file is responsible for setting up the board specific items for the + * CC1350_LAUNCHXL board. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "CC1350_LAUNCHXL.h" + +/* + * =============================== ADCBuf =============================== + */ +#include +#include + +ADCBufCC26XX_Object adcBufCC26XXobjects[CC1350_LAUNCHXL_ADCBUFCOUNT]; + +/* + * This table converts a virtual adc channel into a dio and internal analogue + * input signal. This table is necessary for the functioning of the adcBuf + * driver. Comment out unused entries to save flash. Dio and internal signal + * pairs are hardwired. Do not remap them in the table. You may reorder entire + * entries. The mapping of dio and internal signals is package dependent. + */ +const ADCBufCC26XX_AdcChannelLutEntry ADCBufCC26XX_adcChannelLut[CC1350_LAUNCHXL_ADCBUF0CHANNELCOUNT] = { + {CC1350_LAUNCHXL_DIO23_ANALOG, ADC_COMPB_IN_AUXIO7}, + {CC1350_LAUNCHXL_DIO24_ANALOG, ADC_COMPB_IN_AUXIO6}, + {CC1350_LAUNCHXL_DIO25_ANALOG, ADC_COMPB_IN_AUXIO5}, + {CC1350_LAUNCHXL_DIO26_ANALOG, ADC_COMPB_IN_AUXIO4}, + {CC1350_LAUNCHXL_DIO27_ANALOG, ADC_COMPB_IN_AUXIO3}, + {CC1350_LAUNCHXL_DIO28_ANALOG, ADC_COMPB_IN_AUXIO2}, + {CC1350_LAUNCHXL_DIO29_ANALOG, ADC_COMPB_IN_AUXIO1}, + {CC1350_LAUNCHXL_DIO30_ANALOG, ADC_COMPB_IN_AUXIO0}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VDDS}, + {PIN_UNASSIGNED, ADC_COMPB_IN_DCOUPL}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VSS}, +}; + +const ADCBufCC26XX_HWAttrs adcBufCC26XXHWAttrs[CC1350_LAUNCHXL_ADCBUFCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + .adcChannelLut = ADCBufCC26XX_adcChannelLut, + .gpTimerUnit = CC1350_LAUNCHXL_GPTIMER0A, + .gptDMAChannelMask = 1 << UDMA_CHAN_TIMER0_A, + } +}; + +const ADCBuf_Config ADCBuf_config[CC1350_LAUNCHXL_ADCBUFCOUNT] = { + { + &ADCBufCC26XX_fxnTable, + &adcBufCC26XXobjects[CC1350_LAUNCHXL_ADCBUF0], + &adcBufCC26XXHWAttrs[CC1350_LAUNCHXL_ADCBUF0] + }, +}; + +const uint_least8_t ADCBuf_count = CC1350_LAUNCHXL_ADCBUFCOUNT; + +/* + * =============================== ADC =============================== + */ +#include +#include + +ADCCC26XX_Object adcCC26xxObjects[CC1350_LAUNCHXL_ADCCOUNT]; + +const ADCCC26XX_HWAttrs adcCC26xxHWAttrs[CC1350_LAUNCHXL_ADCCOUNT] = { + { + .adcDIO = CC1350_LAUNCHXL_DIO23_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO7, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1350_LAUNCHXL_DIO24_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO6, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1350_LAUNCHXL_DIO25_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO5, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1350_LAUNCHXL_DIO26_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO4, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1350_LAUNCHXL_DIO27_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO3, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1350_LAUNCHXL_DIO28_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO2, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1350_LAUNCHXL_DIO29_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO1, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1350_LAUNCHXL_DIO30_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO0, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_10P9_MS, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_DCOUPL, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VSS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VDDS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + } +}; + +const ADC_Config ADC_config[CC1350_LAUNCHXL_ADCCOUNT] = { + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1350_LAUNCHXL_ADC0], &adcCC26xxHWAttrs[CC1350_LAUNCHXL_ADC0]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1350_LAUNCHXL_ADC1], &adcCC26xxHWAttrs[CC1350_LAUNCHXL_ADC1]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1350_LAUNCHXL_ADC2], &adcCC26xxHWAttrs[CC1350_LAUNCHXL_ADC2]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1350_LAUNCHXL_ADC3], &adcCC26xxHWAttrs[CC1350_LAUNCHXL_ADC3]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1350_LAUNCHXL_ADC4], &adcCC26xxHWAttrs[CC1350_LAUNCHXL_ADC4]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1350_LAUNCHXL_ADC5], &adcCC26xxHWAttrs[CC1350_LAUNCHXL_ADC5]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1350_LAUNCHXL_ADC6], &adcCC26xxHWAttrs[CC1350_LAUNCHXL_ADC6]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1350_LAUNCHXL_ADC7], &adcCC26xxHWAttrs[CC1350_LAUNCHXL_ADC7]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1350_LAUNCHXL_ADCDCOUPL], &adcCC26xxHWAttrs[CC1350_LAUNCHXL_ADCDCOUPL]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1350_LAUNCHXL_ADCVSS], &adcCC26xxHWAttrs[CC1350_LAUNCHXL_ADCVSS]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1350_LAUNCHXL_ADCVDDS], &adcCC26xxHWAttrs[CC1350_LAUNCHXL_ADCVDDS]}, +}; + +const uint_least8_t ADC_count = CC1350_LAUNCHXL_ADCCOUNT; + +/* + * =============================== Crypto =============================== + */ +#include + +CryptoCC26XX_Object cryptoCC26XXObjects[CC1350_LAUNCHXL_CRYPTOCOUNT]; + +const CryptoCC26XX_HWAttrs cryptoCC26XXHWAttrs[CC1350_LAUNCHXL_CRYPTOCOUNT] = { + { + .baseAddr = CRYPTO_BASE, + .powerMngrId = PowerCC26XX_PERIPH_CRYPTO, + .intNum = INT_CRYPTO_RESULT_AVAIL_IRQ, + .intPriority = ~0, + } +}; + +const CryptoCC26XX_Config CryptoCC26XX_config[CC1350_LAUNCHXL_CRYPTOCOUNT] = { + { + .object = &cryptoCC26XXObjects[CC1350_LAUNCHXL_CRYPTO0], + .hwAttrs = &cryptoCC26XXHWAttrs[CC1350_LAUNCHXL_CRYPTO0] + }, +}; + +/* + * =============================== Display =============================== + */ +#include +#include +#include + +#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE +#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 +#endif + +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 +#endif + +DisplayUart_Object displayUartObject; +DisplaySharp_Object displaySharpObject; + +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; +static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; + +const DisplayUart_HWAttrs displayUartHWAttrs = { + .uartIdx = CC1350_LAUNCHXL_UART0, + .baudRate = 115200, + .mutexTimeout = (unsigned int)(-1), + .strBuf = uartStringBuf, + .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, +}; + +const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { + .spiIndex = CC1350_LAUNCHXL_SPI0, + .csPin = CC1350_LAUNCHXL_GPIO_LCD_CS, + .powerPin = CC1350_LAUNCHXL_GPIO_LCD_POWER, + .enablePin = CC1350_LAUNCHXL_GPIO_LCD_ENABLE, + .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, + .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, + .displayBuf = sharpDisplayBuf, +}; + +#ifndef BOARD_DISPLAY_USE_UART +#define BOARD_DISPLAY_USE_UART 1 +#endif +#ifndef BOARD_DISPLAY_USE_UART_ANSI +#define BOARD_DISPLAY_USE_UART_ANSI 0 +#endif +#ifndef BOARD_DISPLAY_USE_LCD +#define BOARD_DISPLAY_USE_LCD 0 +#endif + +/* + * This #if/#else is needed to workaround a problem with the + * IAR compiler. The IAR compiler doesn't like the empty array + * initialization. (IAR Error[Pe1345]) + */ +#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) + +const Display_Config Display_config[] = { +#if (BOARD_DISPLAY_USE_UART) + { +# if (BOARD_DISPLAY_USE_UART_ANSI) + .fxnTablePtr = &DisplayUartAnsi_fxnTable, +# else /* Default to minimal UART with no cursor placement */ + .fxnTablePtr = &DisplayUartMin_fxnTable, +# endif + .object = &displayUartObject, + .hwAttrs = &displayUartHWAttrs, + }, +#endif +#if (BOARD_DISPLAY_USE_LCD) + { + .fxnTablePtr = &DisplaySharp_fxnTable, + .object = &displaySharpObject, + .hwAttrs = &displaySharpHWattrs + }, +#endif +}; + +const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); + +#else + +const Display_Config *Display_config = NULL; +const uint_least8_t Display_count = 0; + +#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ + +/* + * =============================== GPIO =============================== + */ +#include +#include + +/* + * Array of Pin configurations + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC1350_LAUNCHXL.h + * NOTE: Pins not used for interrupts should be placed at the end of the + * array. Callback entries can be omitted from callbacks array to + * reduce memory usage. + */ +GPIO_PinConfig gpioPinConfigs[] = { + /* Input pins */ + GPIOCC26XX_DIO_13 | GPIO_DO_NOT_CONFIG, /* Button 0 */ + GPIOCC26XX_DIO_14 | GPIO_DO_NOT_CONFIG, /* Button 1 */ + + GPIOCC26XX_DIO_15 | GPIO_DO_NOT_CONFIG, /* CC1350_LAUNCHXL_SPI_MASTER_READY */ + GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG, /* CC1350_LAUNCHXL_SPI_SLAVE_READY */ + + /* Output pins */ + GPIOCC26XX_DIO_07 | GPIO_DO_NOT_CONFIG, /* Green LED */ + GPIOCC26XX_DIO_06 | GPIO_DO_NOT_CONFIG, /* Red LED */ + + /* SPI Flash CSN */ + GPIOCC26XX_DIO_20 | GPIO_DO_NOT_CONFIG, + + /* SD CS */ + GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG, + + /* Sharp Display - GPIO configurations will be done in the Display files */ + GPIOCC26XX_DIO_24 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ + GPIOCC26XX_DIO_22 | GPIO_DO_NOT_CONFIG, /* LCD power control */ + GPIOCC26XX_DIO_23 | GPIO_DO_NOT_CONFIG, /*LCD enable */ + +}; + +/* + * Array of callback function pointers + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC1350_LAUNCHXL.h + * NOTE: Pins not used for interrupts can be omitted from callbacks array to + * reduce memory usage (if placed at end of gpioPinConfigs array). + */ +GPIO_CallbackFxn gpioCallbackFunctions[] = { + NULL, /* Button 0 */ + NULL, /* Button 1 */ + NULL, /* CC1350_LAUNCHXL_SPI_MASTER_READY */ + NULL, /* CC1350_LAUNCHXL_SPI_SLAVE_READY */ +}; + +const GPIOCC26XX_Config GPIOCC26XX_config = { + .pinConfigs = (GPIO_PinConfig *)gpioPinConfigs, + .callbacks = (GPIO_CallbackFxn *)gpioCallbackFunctions, + .numberOfPinConfigs = sizeof(gpioPinConfigs)/sizeof(GPIO_PinConfig), + .numberOfCallbacks = sizeof(gpioCallbackFunctions)/sizeof(GPIO_CallbackFxn), + .intPriority = (~0) +}; + +/* + * =============================== GPTimer =============================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +#include + +GPTimerCC26XX_Object gptimerCC26XXObjects[CC1350_LAUNCHXL_GPTIMERCOUNT]; + +const GPTimerCC26XX_HWAttrs gptimerCC26xxHWAttrs[CC1350_LAUNCHXL_GPTIMERPARTSCOUNT] = { + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0A, }, + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0B, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1A, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1B, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2A, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2B, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3A, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3B, }, +}; + +const GPTimerCC26XX_Config GPTimerCC26XX_config[CC1350_LAUNCHXL_GPTIMERPARTSCOUNT] = { + { &gptimerCC26XXObjects[CC1350_LAUNCHXL_GPTIMER0], &gptimerCC26xxHWAttrs[CC1350_LAUNCHXL_GPTIMER0A], GPT_A }, + { &gptimerCC26XXObjects[CC1350_LAUNCHXL_GPTIMER0], &gptimerCC26xxHWAttrs[CC1350_LAUNCHXL_GPTIMER0B], GPT_B }, + { &gptimerCC26XXObjects[CC1350_LAUNCHXL_GPTIMER1], &gptimerCC26xxHWAttrs[CC1350_LAUNCHXL_GPTIMER1A], GPT_A }, + { &gptimerCC26XXObjects[CC1350_LAUNCHXL_GPTIMER1], &gptimerCC26xxHWAttrs[CC1350_LAUNCHXL_GPTIMER1B], GPT_B }, + { &gptimerCC26XXObjects[CC1350_LAUNCHXL_GPTIMER2], &gptimerCC26xxHWAttrs[CC1350_LAUNCHXL_GPTIMER2A], GPT_A }, + { &gptimerCC26XXObjects[CC1350_LAUNCHXL_GPTIMER2], &gptimerCC26xxHWAttrs[CC1350_LAUNCHXL_GPTIMER2B], GPT_B }, + { &gptimerCC26XXObjects[CC1350_LAUNCHXL_GPTIMER3], &gptimerCC26xxHWAttrs[CC1350_LAUNCHXL_GPTIMER3A], GPT_A }, + { &gptimerCC26XXObjects[CC1350_LAUNCHXL_GPTIMER3], &gptimerCC26xxHWAttrs[CC1350_LAUNCHXL_GPTIMER3B], GPT_B }, +}; + +/* + * =============================== I2C =============================== +*/ +#include +#include + +I2CCC26XX_Object i2cCC26xxObjects[CC1350_LAUNCHXL_I2CCOUNT]; + +const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1350_LAUNCHXL_I2CCOUNT] = { + { + .baseAddr = I2C0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_I2C0, + .intNum = INT_I2C_IRQ, + .intPriority = ~0, + .swiPriority = 0, + .sdaPin = CC1350_LAUNCHXL_I2C0_SDA0, + .sclPin = CC1350_LAUNCHXL_I2C0_SCL0, + } +}; + +const I2C_Config I2C_config[CC1350_LAUNCHXL_I2CCOUNT] = { + { + .fxnTablePtr = &I2CCC26XX_fxnTable, + .object = &i2cCC26xxObjects[CC1350_LAUNCHXL_I2C0], + .hwAttrs = &i2cCC26xxHWAttrs[CC1350_LAUNCHXL_I2C0] + }, +}; + +const uint_least8_t I2C_count = CC1350_LAUNCHXL_I2CCOUNT; + +/* + * =============================== NVS =============================== + */ +#include +#include +#include + +#define NVS_REGIONS_BASE 0x1A000 +#define SECTORSIZE 0x1000 +#define REGIONSIZE (SECTORSIZE * 4) +#define SPIREGIONSIZE (SECTORSIZE * 32) +#define VERIFYBUFSIZE 64 + +static uint8_t verifyBuf[VERIFYBUFSIZE]; + +/* + * Reserve flash sectors for NVS driver use by placing an uninitialized byte + * array at the desired flash address. + */ +#if defined(__TI_COMPILER_VERSION__) + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +#pragma LOCATION(flashBuf, NVS_REGIONS_BASE); +#pragma NOINIT(flashBuf); +static char flashBuf[REGIONSIZE]; + +#elif defined(__IAR_SYSTEMS_ICC__) + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +static __no_init char flashBuf[REGIONSIZE] @ NVS_REGIONS_BASE; + +#elif defined(__GNUC__) + +/* + * Place the flash buffers in the .nvs section created in the gcc linker file. + * The .nvs section enforces alignment on a sector boundary but may + * be placed anywhere in flash memory. If desired the .nvs section can be set + * to a fixed address by changing the following in the gcc linker file: + * + * .nvs (FIXED_FLASH_ADDR) (NOLOAD) : AT (FIXED_FLASH_ADDR) { + * *(.nvs) + * } > REGION_TEXT + */ +__attribute__ ((section (".nvs"))) +static char flashBuf[REGIONSIZE]; + +#endif + +/* Allocate objects for NVS and NVS SPI */ +NVSCC26XX_Object nvsCC26xxObjects[1]; +NVSSPI25X_Object nvsSPI25XObjects[1]; + +/* Hardware attributes for NVS */ +const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { + { + .regionBase = (void *)flashBuf, + .regionSize = REGIONSIZE, + }, +}; + +/* Hardware attributes for NVS SPI */ +const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { + { + .regionBaseOffset = 0, + .regionSize = SPIREGIONSIZE, + .sectorSize = SECTORSIZE, + .verifyBuf = verifyBuf, + .verifyBufSize = VERIFYBUFSIZE, + .spiHandle = NULL, + .spiIndex = 0, + .spiBitRate = 4000000, + .spiCsnGpioIndex = CC1350_LAUNCHXL_GPIO_SPI_FLASH_CS, + }, +}; + +/* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ +const NVS_Config NVS_config[CC1350_LAUNCHXL_NVSCOUNT] = { + { + .fxnTablePtr = &NVSCC26XX_fxnTable, + .object = &nvsCC26xxObjects[0], + .hwAttrs = &nvsCC26xxHWAttrs[0], + }, + { + .fxnTablePtr = &NVSSPI25X_fxnTable, + .object = &nvsSPI25XObjects[0], + .hwAttrs = &nvsSPI25XHWAttrs[0], + }, +}; + +const uint_least8_t NVS_count = CC1350_LAUNCHXL_NVSCOUNT; + +/* + * =============================== PIN =============================== + */ +#include +#include + +const PIN_Config BoardGpioInitTable[] = { + + CC1350_LAUNCHXL_PIN_RLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC1350_LAUNCHXL_PIN_GLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC1350_LAUNCHXL_PIN_BTN1 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC1350_LAUNCHXL_PIN_BTN2 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC1350_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ + CC1350_LAUNCHXL_UART_RX | PIN_INPUT_EN | PIN_PULLDOWN, /* UART RX via debugger back channel */ + CC1350_LAUNCHXL_UART_TX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* UART TX via debugger back channel */ + CC1350_LAUNCHXL_DIO1_RF_SUB1GHZ | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* RF SW Switch defaults to 2.4 GHz path*/ + CC1350_LAUNCHXL_DIO30_RF_POWER | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* External RF Switch is powered off by default */ + CC1350_LAUNCHXL_SPI0_MOSI | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master out - slave in */ + CC1350_LAUNCHXL_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master in - slave out */ + CC1350_LAUNCHXL_SPI0_CLK | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI clock */ + PIN_TERMINATE +}; + +const PINCC26XX_HWAttrs PINCC26XX_hwAttrs = { + .intPriority = ~0, + .swiPriority = 0 +}; + +/* + * =============================== Power =============================== + */ +#include +#include + +const PowerCC26XX_Config PowerCC26XX_config = { + .policyInitFxn = NULL, + .policyFxn = &PowerCC26XX_standbyPolicy, + .calibrateFxn = &PowerCC26XX_calibrate, + .enablePolicy = true, + .calibrateRCOSC_LF = true, + .calibrateRCOSC_HF = true, +}; + +/* + * =============================== PWM =============================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +#include +#include + +PWMTimerCC26XX_Object pwmtimerCC26xxObjects[CC1350_LAUNCHXL_PWMCOUNT]; + +const PWMTimerCC26XX_HwAttrs pwmtimerCC26xxHWAttrs[CC1350_LAUNCHXL_PWMCOUNT] = { + { .pwmPin = CC1350_LAUNCHXL_PWMPIN0, .gpTimerUnit = CC1350_LAUNCHXL_GPTIMER0A }, + { .pwmPin = CC1350_LAUNCHXL_PWMPIN1, .gpTimerUnit = CC1350_LAUNCHXL_GPTIMER0B }, + { .pwmPin = CC1350_LAUNCHXL_PWMPIN2, .gpTimerUnit = CC1350_LAUNCHXL_GPTIMER1A }, + { .pwmPin = CC1350_LAUNCHXL_PWMPIN3, .gpTimerUnit = CC1350_LAUNCHXL_GPTIMER1B }, + { .pwmPin = CC1350_LAUNCHXL_PWMPIN4, .gpTimerUnit = CC1350_LAUNCHXL_GPTIMER2A }, + { .pwmPin = CC1350_LAUNCHXL_PWMPIN5, .gpTimerUnit = CC1350_LAUNCHXL_GPTIMER2B }, + { .pwmPin = CC1350_LAUNCHXL_PWMPIN6, .gpTimerUnit = CC1350_LAUNCHXL_GPTIMER3A }, + { .pwmPin = CC1350_LAUNCHXL_PWMPIN7, .gpTimerUnit = CC1350_LAUNCHXL_GPTIMER3B }, +}; + +const PWM_Config PWM_config[CC1350_LAUNCHXL_PWMCOUNT] = { + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350_LAUNCHXL_PWM0], &pwmtimerCC26xxHWAttrs[CC1350_LAUNCHXL_PWM0] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350_LAUNCHXL_PWM1], &pwmtimerCC26xxHWAttrs[CC1350_LAUNCHXL_PWM1] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350_LAUNCHXL_PWM2], &pwmtimerCC26xxHWAttrs[CC1350_LAUNCHXL_PWM2] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350_LAUNCHXL_PWM3], &pwmtimerCC26xxHWAttrs[CC1350_LAUNCHXL_PWM3] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350_LAUNCHXL_PWM4], &pwmtimerCC26xxHWAttrs[CC1350_LAUNCHXL_PWM4] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350_LAUNCHXL_PWM5], &pwmtimerCC26xxHWAttrs[CC1350_LAUNCHXL_PWM5] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350_LAUNCHXL_PWM6], &pwmtimerCC26xxHWAttrs[CC1350_LAUNCHXL_PWM6] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350_LAUNCHXL_PWM7], &pwmtimerCC26xxHWAttrs[CC1350_LAUNCHXL_PWM7] }, +}; + +const uint_least8_t PWM_count = CC1350_LAUNCHXL_PWMCOUNT; + +/* + * =============================== RF Driver =============================== + */ +#include + +/* + * Board-specific callback function to set the correct antenna path. + * + * This function is called by the RF driver on global driver events. It contains + * a default implementation to set the correct antenna path. + */ +static void CC1350_LAUNCHXL_rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void *arg); + +const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { + .hwiPriority = ~0, /* Lowest HWI priority */ + .swiPriority = 0, /* Lowest SWI priority */ + .xoscHfAlwaysNeeded = true, /* Keep XOSC dependency while in stanby */ + .globalCallback = &CC1350_LAUNCHXL_rfDriverCallback, /* Register the board specific callback */ + .globalEventMask = RF_GlobalEventRadioSetup | RF_GlobalEventRadioPowerDown /* Subscribe the callback to both events */ +}; + +/* + * =============================== SD =============================== + */ +#include +#include + +SDSPI_Object sdspiObjects[CC1350_LAUNCHXL_SDCOUNT]; + +const SDSPI_HWAttrs sdspiHWAttrs[CC1350_LAUNCHXL_SDCOUNT] = { + { + .spiIndex = CC1350_LAUNCHXL_SPI0, + .spiCsGpioIndex = CC1350_LAUNCHXL_SDSPI_CS + } +}; + +const SD_Config SD_config[CC1350_LAUNCHXL_SDCOUNT] = { + { + .fxnTablePtr = &SDSPI_fxnTable, + .object = &sdspiObjects[CC1350_LAUNCHXL_SDSPI0], + .hwAttrs = &sdspiHWAttrs[CC1350_LAUNCHXL_SDSPI0] + }, +}; + +const uint_least8_t SD_count = CC1350_LAUNCHXL_SDCOUNT; + +/* + * =============================== SPI DMA =============================== + */ +#include +#include + +SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1350_LAUNCHXL_SPICOUNT]; + +/* + * NOTE: The SPI instances below can be used by the SD driver to communicate + * with a SD card via SPI. The 'defaultTxBufValue' fields below are set to 0xFF + * to satisfy the SDSPI driver requirement. + */ +const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1350_LAUNCHXL_SPICOUNT] = { + { + .baseAddr = SSI0_BASE, + .intNum = INT_SSI0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .powerMngrId = PowerCC26XX_PERIPH_SSI0, + .defaultTxBufValue = 0xFF, + .rxChannelBitMask = 1< +#include + +UARTCC26XX_Object uartCC26XXObjects[CC1350_LAUNCHXL_UARTCOUNT]; + +uint8_t uartCC26XXRingBuffer[CC1350_LAUNCHXL_UARTCOUNT][32]; + +const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1350_LAUNCHXL_UARTCOUNT] = { + { + .baseAddr = UART0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UART0, + .intNum = INT_UART0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .txPin = CC1350_LAUNCHXL_UART_TX, + .rxPin = CC1350_LAUNCHXL_UART_RX, + .ctsPin = PIN_UNASSIGNED, + .rtsPin = PIN_UNASSIGNED, + .ringBufPtr = uartCC26XXRingBuffer[CC1350_LAUNCHXL_UART0], + .ringBufSize = sizeof(uartCC26XXRingBuffer[CC1350_LAUNCHXL_UART0]), + .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, + .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, + .errorFxn = NULL + } +}; + +const UART_Config UART_config[CC1350_LAUNCHXL_UARTCOUNT] = { + { + .fxnTablePtr = &UARTCC26XX_fxnTable, + .object = &uartCC26XXObjects[CC1350_LAUNCHXL_UART0], + .hwAttrs = &uartCC26XXHWAttrs[CC1350_LAUNCHXL_UART0] + }, +}; + +const uint_least8_t UART_count = CC1350_LAUNCHXL_UARTCOUNT; + +/* + * =============================== UDMA =============================== + */ +#include + +UDMACC26XX_Object udmaObjects[CC1350_LAUNCHXL_UDMACOUNT]; + +const UDMACC26XX_HWAttrs udmaHWAttrs[CC1350_LAUNCHXL_UDMACOUNT] = { + { + .baseAddr = UDMA0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UDMA, + .intNum = INT_DMA_ERR, + .intPriority = ~0 + } +}; + +const UDMACC26XX_Config UDMACC26XX_config[CC1350_LAUNCHXL_UDMACOUNT] = { + { + .object = &udmaObjects[CC1350_LAUNCHXL_UDMA0], + .hwAttrs = &udmaHWAttrs[CC1350_LAUNCHXL_UDMA0] + }, +}; + +/* + * =============================== Watchdog =============================== + */ +#include +#include + +WatchdogCC26XX_Object watchdogCC26XXObjects[CC1350_LAUNCHXL_WATCHDOGCOUNT]; + +const WatchdogCC26XX_HWAttrs watchdogCC26XXHWAttrs[CC1350_LAUNCHXL_WATCHDOGCOUNT] = { + { + .baseAddr = WDT_BASE, + .reloadValue = 1000 /* Reload value in milliseconds */ + }, +}; + +const Watchdog_Config Watchdog_config[CC1350_LAUNCHXL_WATCHDOGCOUNT] = { + { + .fxnTablePtr = &WatchdogCC26XX_fxnTable, + .object = &watchdogCC26XXObjects[CC1350_LAUNCHXL_WATCHDOG0], + .hwAttrs = &watchdogCC26XXHWAttrs[CC1350_LAUNCHXL_WATCHDOG0] + }, +}; + +const uint_least8_t Watchdog_count = CC1350_LAUNCHXL_WATCHDOGCOUNT; + +/* + * ======== CC1350_LAUNCHXL_wakeUpExtFlash ======== + */ +void CC1350_LAUNCHXL_wakeUpExtFlash(void) +{ + PIN_Config extFlashPinTable[] = { + CC1350_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + /* + * To wake up we need to toggle the chip select at + * least 20 ns and ten wait at least 35 us. + */ + + /* Toggle chip select for ~20ns to wake ext. flash */ + PIN_setOutputValue(extFlashPinHandle, CC1350_LAUNCHXL_SPI_FLASH_CS, 0); + /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ + CPUdelay(1); + PIN_setOutputValue(extFlashPinHandle, CC1350_LAUNCHXL_SPI_FLASH_CS, 1); + /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ + CPUdelay(560); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC1350_LAUNCHXL_sendExtFlashByte ======== + */ +void CC1350_LAUNCHXL_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) +{ + uint8_t i; + + PIN_setOutputValue(pinHandle, CC1350_LAUNCHXL_SPI_FLASH_CS, 0); + + for (i = 0; i < 8; i++) { + PIN_setOutputValue(pinHandle, CC1350_LAUNCHXL_SPI0_CLK, 0); + PIN_setOutputValue(pinHandle, CC1350_LAUNCHXL_SPI0_MOSI, (byte >> (7 - i)) & 0x01); + PIN_setOutputValue(pinHandle, CC1350_LAUNCHXL_SPI0_CLK, 1); + + /* + * Waste a few cycles to keep the CLK high for at + * least 45% of the period. + * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. + */ + CPUdelay(8); + } + + PIN_setOutputValue(pinHandle, CC1350_LAUNCHXL_SPI0_CLK, 0); + PIN_setOutputValue(pinHandle, CC1350_LAUNCHXL_SPI_FLASH_CS, 1); + + /* + * Keep CS high at least 40 us + * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us + */ + CPUdelay(700); +} + +/* + * ======== CC1350_LAUNCHXL_shutDownExtFlash ======== + */ +void CC1350_LAUNCHXL_shutDownExtFlash(void) +{ + /* To be sure we are putting the flash into sleep and not waking it, we first have to make a wake up call */ + CC1350_LAUNCHXL_wakeUpExtFlash(); + + + PIN_Config extFlashPinTable[] = { + CC1350_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + CC1350_LAUNCHXL_SPI0_CLK | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + CC1350_LAUNCHXL_SPI0_MOSI | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + CC1350_LAUNCHXL_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + uint8_t extFlashShutdown = 0xB9; + + CC1350_LAUNCHXL_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC1350_LAUNCHXL_initGeneral ======== + */ +void CC1350_LAUNCHXL_initGeneral(void) +{ + Power_init(); + + if (PIN_init(BoardGpioInitTable) != PIN_SUCCESS) { + /* Error with PIN_init */ + while (1); + } + + /* Shut down external flash as default */ + CC1350_LAUNCHXL_shutDownExtFlash(); +} + +/* + * ======== CC1350_LAUNCHXL_rfDriverCallback ======== + * This is an implementation for the CC1350 launchpad which uses a + * single signal for antenna switching. + */ +void CC1350_LAUNCHXL_rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void *arg) +{ + (void)client; + RF_RadioSetup* setupCommand = (RF_RadioSetup*)arg; + + if (events & RF_GlobalEventRadioSetup) { + /* Power up the antenna switch */ + PINCC26XX_setOutputValue(CC1350_LAUNCHXL_DIO30_RF_POWER, 1); + + if (setupCommand->common.commandNo == CMD_PROP_RADIO_DIV_SETUP) { + /* Sub-1 GHz, requires antenna switch high */ + PINCC26XX_setOutputValue(CC1350_LAUNCHXL_DIO1_RF_SUB1GHZ, 1); + } + + } else if (events & RF_GlobalEventRadioPowerDown) { + /* Disable antenna switch to save current */ + PINCC26XX_setOutputValue(CC1350_LAUNCHXL_DIO30_RF_POWER, 0); + PINCC26XX_setOutputValue(CC1350_LAUNCHXL_DIO1_RF_SUB1GHZ, 0); + } +} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h new file mode 100644 index 000000000..20be159af --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2015-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ +/** ============================================================================ + * @file CC1350_LAUNCHXL.h + * + * @brief CC1350 LaunchPad Board Specific header file. + * + * The CC1350_LAUNCHXL header file should be included in an application as + * follows: + * @code + * #include "CC1350_LAUNCHXL.h" + * @endcode + * + * ============================================================================ + */ +#ifndef __CC1350_LAUNCHXL_BOARD_H__ +#define __CC1350_LAUNCHXL_BOARD_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes */ +#include +#include + +/* Externs */ +extern const PIN_Config BoardGpioInitTable[]; + +/* Defines */ +#define CC1350_LAUNCHXL + +/* Mapping of pins to board signals using general board aliases + * + */ + +/* Analog Capable DIOs */ +#define CC1350_LAUNCHXL_DIO23_ANALOG IOID_23 +#define CC1350_LAUNCHXL_DIO24_ANALOG IOID_24 +#define CC1350_LAUNCHXL_DIO25_ANALOG IOID_25 +#define CC1350_LAUNCHXL_DIO26_ANALOG IOID_26 +#define CC1350_LAUNCHXL_DIO27_ANALOG IOID_27 +#define CC1350_LAUNCHXL_DIO28_ANALOG IOID_28 +#define CC1350_LAUNCHXL_DIO29_ANALOG IOID_29 +#define CC1350_LAUNCHXL_DIO30_ANALOG IOID_30 + +/* Digital IOs */ +#define CC1350_LAUNCHXL_DIO0 IOID_0 +#define CC1350_LAUNCHXL_DIO1_RF_SUB1GHZ IOID_1 +#define CC1350_LAUNCHXL_DIO12 IOID_12 +#define CC1350_LAUNCHXL_DIO15 IOID_15 +#define CC1350_LAUNCHXL_DIO16_TDO IOID_16 +#define CC1350_LAUNCHXL_DIO17_TDI IOID_17 +#define CC1350_LAUNCHXL_DIO21 IOID_21 +#define CC1350_LAUNCHXL_DIO22 IOID_22 +#define CC1350_LAUNCHXL_DIO30_RF_POWER IOID_30 + +/* Discrete Inputs */ +#define CC1350_LAUNCHXL_PIN_BTN1 IOID_13 +#define CC1350_LAUNCHXL_PIN_BTN2 IOID_14 + + +/* GPIO */ +#define CC1350_LAUNCHXL_GPIO_LED_ON 1 +#define CC1350_LAUNCHXL_GPIO_LED_OFF 0 + +/* I2C */ +#define CC1350_LAUNCHXL_I2C0_SCL0 IOID_4 +#define CC1350_LAUNCHXL_I2C0_SDA0 IOID_5 + + +/* LEDs */ +#define CC1350_LAUNCHXL_PIN_LED_ON 1 +#define CC1350_LAUNCHXL_PIN_LED_OFF 0 +#define CC1350_LAUNCHXL_PIN_RLED IOID_6 +#define CC1350_LAUNCHXL_PIN_GLED IOID_7 + +/* PWM Outputs */ +#define CC1350_LAUNCHXL_PWMPIN0 CC1350_LAUNCHXL_PIN_RLED +#define CC1350_LAUNCHXL_PWMPIN1 CC1350_LAUNCHXL_PIN_GLED +#define CC1350_LAUNCHXL_PWMPIN2 PIN_UNASSIGNED +#define CC1350_LAUNCHXL_PWMPIN3 PIN_UNASSIGNED +#define CC1350_LAUNCHXL_PWMPIN4 PIN_UNASSIGNED +#define CC1350_LAUNCHXL_PWMPIN5 PIN_UNASSIGNED +#define CC1350_LAUNCHXL_PWMPIN6 PIN_UNASSIGNED +#define CC1350_LAUNCHXL_PWMPIN7 PIN_UNASSIGNED + +/* SPI */ +#define CC1350_LAUNCHXL_SPI_FLASH_CS IOID_20 +#define CC1350_LAUNCHXL_FLASH_CS_ON 0 +#define CC1350_LAUNCHXL_FLASH_CS_OFF 1 + +/* SPI Board */ +#define CC1350_LAUNCHXL_SPI0_MISO IOID_8 /* RF1.20 */ +#define CC1350_LAUNCHXL_SPI0_MOSI IOID_9 /* RF1.18 */ +#define CC1350_LAUNCHXL_SPI0_CLK IOID_10 /* RF1.16 */ +#define CC1350_LAUNCHXL_SPI0_CSN PIN_UNASSIGNED +#define CC1350_LAUNCHXL_SPI1_MISO PIN_UNASSIGNED +#define CC1350_LAUNCHXL_SPI1_MOSI PIN_UNASSIGNED +#define CC1350_LAUNCHXL_SPI1_CLK PIN_UNASSIGNED +#define CC1350_LAUNCHXL_SPI1_CSN PIN_UNASSIGNED + +/* UART Board */ +#define CC1350_LAUNCHXL_UART_RX IOID_2 /* RXD */ +#define CC1350_LAUNCHXL_UART_TX IOID_3 /* TXD */ +#define CC1350_LAUNCHXL_UART_CTS IOID_19 /* CTS */ +#define CC1350_LAUNCHXL_UART_RTS IOID_18 /* RTS */ + +/*! + * @brief Initialize the general board specific settings + * + * This function initializes the general board specific settings. + */ +void CC1350_LAUNCHXL_initGeneral(void); + +/*! + * @brief Turn off the external flash on LaunchPads + * + */ +void CC1350_LAUNCHXL_shutDownExtFlash(void); + +/*! + * @brief Wake up the external flash present on the board files + * + * This function toggles the chip select for the amount of time needed + * to wake the chip up. + */ +void CC1350_LAUNCHXL_wakeUpExtFlash(void); + +/*! + * @def CC1350_LAUNCHXL_ADCBufName + * @brief Enum of ADCBufs + */ +typedef enum CC1350_LAUNCHXL_ADCBufName { + CC1350_LAUNCHXL_ADCBUF0 = 0, + + CC1350_LAUNCHXL_ADCBUFCOUNT +} CC1350_LAUNCHXL_ADCBufName; + +/*! + * @def CC1350_LAUNCHXL_ADCBuf0SourceName + * @brief Enum of ADCBuf channels + */ +typedef enum CC1350_LAUNCHXL_ADCBuf0ChannelName { + CC1350_LAUNCHXL_ADCBUF0CHANNEL0 = 0, + CC1350_LAUNCHXL_ADCBUF0CHANNEL1, + CC1350_LAUNCHXL_ADCBUF0CHANNEL2, + CC1350_LAUNCHXL_ADCBUF0CHANNEL3, + CC1350_LAUNCHXL_ADCBUF0CHANNEL4, + CC1350_LAUNCHXL_ADCBUF0CHANNEL5, + CC1350_LAUNCHXL_ADCBUF0CHANNEL6, + CC1350_LAUNCHXL_ADCBUF0CHANNEL7, + CC1350_LAUNCHXL_ADCBUF0CHANNELVDDS, + CC1350_LAUNCHXL_ADCBUF0CHANNELDCOUPL, + CC1350_LAUNCHXL_ADCBUF0CHANNELVSS, + + CC1350_LAUNCHXL_ADCBUF0CHANNELCOUNT +} CC1350_LAUNCHXL_ADCBuf0ChannelName; + +/*! + * @def CC1350_LAUNCHXL_ADCName + * @brief Enum of ADCs + */ +typedef enum CC1350_LAUNCHXL_ADCName { + CC1350_LAUNCHXL_ADC0 = 0, + CC1350_LAUNCHXL_ADC1, + CC1350_LAUNCHXL_ADC2, + CC1350_LAUNCHXL_ADC3, + CC1350_LAUNCHXL_ADC4, + CC1350_LAUNCHXL_ADC5, + CC1350_LAUNCHXL_ADC6, + CC1350_LAUNCHXL_ADC7, + CC1350_LAUNCHXL_ADCDCOUPL, + CC1350_LAUNCHXL_ADCVSS, + CC1350_LAUNCHXL_ADCVDDS, + + CC1350_LAUNCHXL_ADCCOUNT +} CC1350_LAUNCHXL_ADCName; + +/*! + * @def CC1350_LAUNCHXL_CryptoName + * @brief Enum of Crypto names + */ +typedef enum CC1350_LAUNCHXL_CryptoName { + CC1350_LAUNCHXL_CRYPTO0 = 0, + + CC1350_LAUNCHXL_CRYPTOCOUNT +} CC1350_LAUNCHXL_CryptoName; + +/*! + * @def CC1350_LAUNCHXL_GPIOName + * @brief Enum of GPIO names + */ +typedef enum CC1350_LAUNCHXL_GPIOName { + CC1350_LAUNCHXL_GPIO_S1 = 0, + CC1350_LAUNCHXL_GPIO_S2, + CC1350_LAUNCHXL_SPI_MASTER_READY, + CC1350_LAUNCHXL_SPI_SLAVE_READY, + CC1350_LAUNCHXL_GPIO_LED_GREEN, + CC1350_LAUNCHXL_GPIO_LED_RED, + CC1350_LAUNCHXL_GPIO_SPI_FLASH_CS, + CC1350_LAUNCHXL_SDSPI_CS, + CC1350_LAUNCHXL_GPIO_LCD_CS, + CC1350_LAUNCHXL_GPIO_LCD_POWER, + CC1350_LAUNCHXL_GPIO_LCD_ENABLE, + CC1350_LAUNCHXL_GPIOCOUNT +} CC1350_LAUNCHXL_GPIOName; + +/*! + * @def CC1350_LAUNCHXL_GPTimerName + * @brief Enum of GPTimer parts + */ +typedef enum CC1350_LAUNCHXL_GPTimerName { + CC1350_LAUNCHXL_GPTIMER0A = 0, + CC1350_LAUNCHXL_GPTIMER0B, + CC1350_LAUNCHXL_GPTIMER1A, + CC1350_LAUNCHXL_GPTIMER1B, + CC1350_LAUNCHXL_GPTIMER2A, + CC1350_LAUNCHXL_GPTIMER2B, + CC1350_LAUNCHXL_GPTIMER3A, + CC1350_LAUNCHXL_GPTIMER3B, + + CC1350_LAUNCHXL_GPTIMERPARTSCOUNT +} CC1350_LAUNCHXL_GPTimerName; + +/*! + * @def CC1350_LAUNCHXL_GPTimers + * @brief Enum of GPTimers + */ +typedef enum CC1350_LAUNCHXL_GPTimers { + CC1350_LAUNCHXL_GPTIMER0 = 0, + CC1350_LAUNCHXL_GPTIMER1, + CC1350_LAUNCHXL_GPTIMER2, + CC1350_LAUNCHXL_GPTIMER3, + + CC1350_LAUNCHXL_GPTIMERCOUNT +} CC1350_LAUNCHXL_GPTimers; + +/*! + * @def CC1350_LAUNCHXL_I2CName + * @brief Enum of I2C names + */ +typedef enum CC1350_LAUNCHXL_I2CName { + CC1350_LAUNCHXL_I2C0 = 0, + + CC1350_LAUNCHXL_I2CCOUNT +} CC1350_LAUNCHXL_I2CName; + +/*! + * @def CC1350_LAUNCHXL_NVSName + * @brief Enum of NVS names + */ +typedef enum CC1350_LAUNCHXL_NVSName { + CC1350_LAUNCHXL_NVSCC26XX0 = 0, + CC1350_LAUNCHXL_NVSSPI25X0, + + CC1350_LAUNCHXL_NVSCOUNT +} CC1350_LAUNCHXL_NVSName; + +/*! + * @def CC1350_LAUNCHXL_PWM + * @brief Enum of PWM outputs + */ +typedef enum CC1350_LAUNCHXL_PWMName { + CC1350_LAUNCHXL_PWM0 = 0, + CC1350_LAUNCHXL_PWM1, + CC1350_LAUNCHXL_PWM2, + CC1350_LAUNCHXL_PWM3, + CC1350_LAUNCHXL_PWM4, + CC1350_LAUNCHXL_PWM5, + CC1350_LAUNCHXL_PWM6, + CC1350_LAUNCHXL_PWM7, + + CC1350_LAUNCHXL_PWMCOUNT +} CC1350_LAUNCHXL_PWMName; + +/*! + * @def CC1350_LAUNCHXL_SDName + * @brief Enum of SD names + */ +typedef enum CC1350_LAUNCHXL_SDName { + CC1350_LAUNCHXL_SDSPI0 = 0, + + CC1350_LAUNCHXL_SDCOUNT +} CC1350_LAUNCHXL_SDName; + +/*! + * @def CC1350_LAUNCHXL_SPIName + * @brief Enum of SPI names + */ +typedef enum CC1350_LAUNCHXL_SPIName { + CC1350_LAUNCHXL_SPI0 = 0, + CC1350_LAUNCHXL_SPI1, + + CC1350_LAUNCHXL_SPICOUNT +} CC1350_LAUNCHXL_SPIName; + +/*! + * @def CC1350_LAUNCHXL_UARTName + * @brief Enum of UARTs + */ +typedef enum CC1350_LAUNCHXL_UARTName { + CC1350_LAUNCHXL_UART0 = 0, + + CC1350_LAUNCHXL_UARTCOUNT +} CC1350_LAUNCHXL_UARTName; + +/*! + * @def CC1350_LAUNCHXL_UDMAName + * @brief Enum of DMA buffers + */ +typedef enum CC1350_LAUNCHXL_UDMAName { + CC1350_LAUNCHXL_UDMA0 = 0, + + CC1350_LAUNCHXL_UDMACOUNT +} CC1350_LAUNCHXL_UDMAName; + +/*! + * @def CC1350_LAUNCHXL_WatchdogName + * @brief Enum of Watchdogs + */ +typedef enum CC1350_LAUNCHXL_WatchdogName { + CC1350_LAUNCHXL_WATCHDOG0 = 0, + + CC1350_LAUNCHXL_WATCHDOGCOUNT +} CC1350_LAUNCHXL_WatchdogName; + +#ifdef __cplusplus +} +#endif + +#endif /* __CC1350_LAUNCHXL_BOARD_H__ */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Makefile.cc1350 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Makefile.cc1350 new file mode 100644 index 000000000..51a6a0a44 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Makefile.cc1350 @@ -0,0 +1,16 @@ +################################################################################ +# SimpleLink Device makefile + +SUBFAMILY = cc13x0-cc26x0 +DEVICE_FAMILY = CC13X0 + +BOARD_SOURCEFILES += CC1350_LAUNCHXL.c + +SUPPORTS_PROP_MODE = 1 +SUPPORTS_IEEE_MODE = 1 + +### Signal that we can be programmed with cc2538-bsl +BOARD_SUPPORTS_BSL = 1 + +# Include the common board makefile +include $(FAMILY_PATH)/launchpad/Makefile.launchpad diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Board.h new file mode 100644 index 000000000..325472c6e --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Board.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2017-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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 __BOARD_H +#define __BOARD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "CC1352P1_LAUNCHXL.h" + +#define Board_initGeneral() CC1352P1_LAUNCHXL_initGeneral() +#define Board_shutDownExtFlash() CC1352P1_LAUNCHXL_shutDownExtFlash() +#define Board_wakeUpExtFlash() CC1352P1_LAUNCHXL_wakeUpExtFlash() + +/* These #defines allow us to reuse TI-RTOS across other device families */ + +#define Board_ADC0 CC1352P1_LAUNCHXL_ADC0 +#define Board_ADC1 CC1352P1_LAUNCHXL_ADC1 + +#define Board_ADCBUF0 CC1352P1_LAUNCHXL_ADCBUF0 +#define Board_ADCBUF0CHANNEL0 CC1352P1_LAUNCHXL_ADCBUF0CHANNEL0 +#define Board_ADCBUF0CHANNEL1 CC1352P1_LAUNCHXL_ADCBUF0CHANNEL1 + +#define Board_CRYPTO0 CC1352P1_LAUNCHXL_CRYPTO0 +#define Board_ECDH0 CC1352P1_LAUNCHXL_ECDH0 +#define Board_ECDSA0 CC1352P1_LAUNCHXL_ECDSA0 +#define Board_ECJPAKE0 CC1352P1_LAUNCHXL_ECJPAKE0 +#define Board_AESCCM0 CC1352P1_LAUNCHXL_AESCCM0 +#define Board_AESECB0 CC1352P1_LAUNCHXL_AESECB0 +#define Board_SHA20 CC1352P1_LAUNCHXL_SHA20 + +#define Board_DIO12 CC1352P1_LAUNCHXL_DIO12 +#define Board_DIO15 CC1352P1_LAUNCHXL_DIO15 +#define Board_DIO16_TDO CC1352P1_LAUNCHXL_DIO16_TDO +#define Board_DIO17_TDI CC1352P1_LAUNCHXL_DIO17_TDI +#define Board_DIO21 CC1352P1_LAUNCHXL_DIO21 +#define Board_DIO22 CC1352P1_LAUNCHXL_DIO22 + +#define Board_DIO23_ANALOG CC1352P1_LAUNCHXL_DIO23_ANALOG +#define Board_DIO24_ANALOG CC1352P1_LAUNCHXL_DIO24_ANALOG +#define Board_DIO25_ANALOG CC1352P1_LAUNCHXL_DIO25_ANALOG +#define Board_DIO26_ANALOG CC1352P1_LAUNCHXL_DIO26_ANALOG +#define Board_DIO27_ANALOG CC1352P1_LAUNCHXL_DIO27_ANALOG +#define Board_DIO28_ANALOG CC1352P1_LAUNCHXL_DIO28_ANALOG +#define Board_DIO29_ANALOG CC1352P1_LAUNCHXL_DIO29_ANALOG +#define Board_DIO30_RFSW CC1352P1_LAUNCHXL_DIO30_RF_SUB1GHZ + +#define Board_GPIO_BUTTON0 CC1352P1_LAUNCHXL_GPIO_S1 +#define Board_GPIO_BUTTON1 CC1352P1_LAUNCHXL_GPIO_S2 +#define Board_GPIO_BTN1 CC1352P1_LAUNCHXL_GPIO_S1 +#define Board_GPIO_BTN2 CC1352P1_LAUNCHXL_GPIO_S2 +#define Board_GPIO_LED0 CC1352P1_LAUNCHXL_GPIO_LED_RED +#define Board_GPIO_LED1 CC1352P1_LAUNCHXL_GPIO_LED_GREEN +#define Board_GPIO_LED2 CC1352P1_LAUNCHXL_GPIO_LED_RED +#define Board_GPIO_RLED CC1352P1_LAUNCHXL_GPIO_LED_RED +#define Board_GPIO_GLED CC1352P1_LAUNCHXL_GPIO_LED_GREEN +#define Board_GPIO_LED_ON CC1352P1_LAUNCHXL_GPIO_LED_ON +#define Board_GPIO_LED_OFF CC1352P1_LAUNCHXL_GPIO_LED_OFF + +#define Board_GPTIMER0A CC1352P1_LAUNCHXL_GPTIMER0A +#define Board_GPTIMER0B CC1352P1_LAUNCHXL_GPTIMER0B +#define Board_GPTIMER1A CC1352P1_LAUNCHXL_GPTIMER1A +#define Board_GPTIMER1B CC1352P1_LAUNCHXL_GPTIMER1B +#define Board_GPTIMER2A CC1352P1_LAUNCHXL_GPTIMER2A +#define Board_GPTIMER2B CC1352P1_LAUNCHXL_GPTIMER2B +#define Board_GPTIMER3A CC1352P1_LAUNCHXL_GPTIMER3A +#define Board_GPTIMER3B CC1352P1_LAUNCHXL_GPTIMER3B + +#define Board_I2C0 CC1352P1_LAUNCHXL_I2C0 +#define Board_I2C_TMP Board_I2C0 + +#define Board_NVSINTERNAL CC1352P1_LAUNCHXL_NVSCC26XX0 +#define Board_NVSEXTERNAL CC1352P1_LAUNCHXL_NVSSPI25X0 + +#define Board_PIN_BUTTON0 CC1352P1_LAUNCHXL_PIN_BTN1 +#define Board_PIN_BUTTON1 CC1352P1_LAUNCHXL_PIN_BTN2 +#define Board_PIN_BTN1 CC1352P1_LAUNCHXL_PIN_BTN1 +#define Board_PIN_BTN2 CC1352P1_LAUNCHXL_PIN_BTN2 +#define Board_PIN_LED0 CC1352P1_LAUNCHXL_PIN_RLED +#define Board_PIN_LED1 CC1352P1_LAUNCHXL_PIN_GLED +#define Board_PIN_LED2 CC1352P1_LAUNCHXL_PIN_RLED +#define Board_PIN_RLED CC1352P1_LAUNCHXL_PIN_RLED +#define Board_PIN_GLED CC1352P1_LAUNCHXL_PIN_GLED + +#define Board_PWM0 CC1352P1_LAUNCHXL_PWM0 +#define Board_PWM1 CC1352P1_LAUNCHXL_PWM1 +#define Board_PWM2 CC1352P1_LAUNCHXL_PWM2 +#define Board_PWM3 CC1352P1_LAUNCHXL_PWM3 +#define Board_PWM4 CC1352P1_LAUNCHXL_PWM4 +#define Board_PWM5 CC1352P1_LAUNCHXL_PWM5 +#define Board_PWM6 CC1352P1_LAUNCHXL_PWM6 +#define Board_PWM7 CC1352P1_LAUNCHXL_PWM7 + +#define Board_SD0 CC1352P1_LAUNCHXL_SDSPI0 + +#define Board_SPI0 CC1352P1_LAUNCHXL_SPI0 +#define Board_SPI1 CC1352P1_LAUNCHXL_SPI1 +#define Board_SPI_FLASH_CS CC1352P1_LAUNCHXL_SPI_FLASH_CS +#define Board_FLASH_CS_ON 0 +#define Board_FLASH_CS_OFF 1 + +#define Board_SPI_MASTER CC1352P1_LAUNCHXL_SPI0 +#define Board_SPI_SLAVE CC1352P1_LAUNCHXL_SPI0 +#define Board_SPI_MASTER_READY CC1352P1_LAUNCHXL_SPI_MASTER_READY +#define Board_SPI_SLAVE_READY CC1352P1_LAUNCHXL_SPI_SLAVE_READY + +#define Board_UART0 CC1352P1_LAUNCHXL_UART0 +#define Board_UART1 CC1352P1_LAUNCHXL_UART1 + +#define Board_WATCHDOG0 CC1352P1_LAUNCHXL_WATCHDOG0 + +/* Board specific I2C addresses */ +#define Board_TMP_ADDR (0x40) +#define Board_SENSORS_BP_TMP_ADDR Board_TMP_ADDR + +#ifdef __cplusplus +} +#endif + +#endif /* __BOARD_H */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.c new file mode 100644 index 000000000..bf5054458 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.c @@ -0,0 +1,1127 @@ +/* + * Copyright (c) 2017-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +/* + * ====================== CC1352P1_LAUNCHXL.c =================================== + * This file is responsible for setting up the board specific items for the + * CC1352P1_LAUNCHXL board. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "CC1352P1_LAUNCHXL.h" + +/* + * =============================== ADCBuf =============================== + */ +#include +#include + +ADCBufCC26X2_Object adcBufCC26xxObjects[CC1352P1_LAUNCHXL_ADCBUFCOUNT]; + +/* + * This table converts a virtual adc channel into a dio and internal analogue + * input signal. This table is necessary for the functioning of the adcBuf + * driver. Comment out unused entries to save flash. Dio and internal signal + * pairs are hardwired. Do not remap them in the table. You may reorder entire + * entries. The mapping of dio and internal signals is package dependent. + */ +const ADCBufCC26X2_AdcChannelLutEntry ADCBufCC26X2_adcChannelLut[CC1352P1_LAUNCHXL_ADCBUF0CHANNELCOUNT] = { + {CC1352P1_LAUNCHXL_DIO23_ANALOG, ADC_COMPB_IN_AUXIO7}, + {CC1352P1_LAUNCHXL_DIO24_ANALOG, ADC_COMPB_IN_AUXIO6}, + {CC1352P1_LAUNCHXL_DIO25_ANALOG, ADC_COMPB_IN_AUXIO5}, + {CC1352P1_LAUNCHXL_DIO26_ANALOG, ADC_COMPB_IN_AUXIO4}, + {CC1352P1_LAUNCHXL_DIO27_ANALOG, ADC_COMPB_IN_AUXIO3}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VDDS}, + {PIN_UNASSIGNED, ADC_COMPB_IN_DCOUPL}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VSS}, +}; + +const ADCBufCC26X2_HWAttrs adcBufCC26xxHWAttrs[CC1352P1_LAUNCHXL_ADCBUFCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + .adcChannelLut = ADCBufCC26X2_adcChannelLut, + .gpTimerUnit = CC1352P1_LAUNCHXL_GPTIMER0A, + } +}; + +const ADCBuf_Config ADCBuf_config[CC1352P1_LAUNCHXL_ADCBUFCOUNT] = { + { + &ADCBufCC26X2_fxnTable, + &adcBufCC26xxObjects[CC1352P1_LAUNCHXL_ADCBUF0], + &adcBufCC26xxHWAttrs[CC1352P1_LAUNCHXL_ADCBUF0] + }, +}; + +const uint_least8_t ADCBuf_count = CC1352P1_LAUNCHXL_ADCBUFCOUNT; + +/* + * =============================== ADC =============================== + */ +#include +#include + +ADCCC26XX_Object adcCC26xxObjects[CC1352P1_LAUNCHXL_ADCCOUNT]; + +const ADCCC26XX_HWAttrs adcCC26xxHWAttrs[CC1352P1_LAUNCHXL_ADCCOUNT] = { + { + .adcDIO = CC1352P1_LAUNCHXL_DIO23_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO7, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1352P1_LAUNCHXL_DIO24_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO6, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1352P1_LAUNCHXL_DIO25_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO5, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1352P1_LAUNCHXL_DIO26_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO4, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1352P1_LAUNCHXL_DIO27_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO3, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_DCOUPL, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VSS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VDDS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + } +}; + +const ADC_Config ADC_config[CC1352P1_LAUNCHXL_ADCCOUNT] = { + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352P1_LAUNCHXL_ADC0], &adcCC26xxHWAttrs[CC1352P1_LAUNCHXL_ADC0]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352P1_LAUNCHXL_ADC1], &adcCC26xxHWAttrs[CC1352P1_LAUNCHXL_ADC1]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352P1_LAUNCHXL_ADC2], &adcCC26xxHWAttrs[CC1352P1_LAUNCHXL_ADC2]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352P1_LAUNCHXL_ADC3], &adcCC26xxHWAttrs[CC1352P1_LAUNCHXL_ADC3]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352P1_LAUNCHXL_ADC4], &adcCC26xxHWAttrs[CC1352P1_LAUNCHXL_ADC4]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352P1_LAUNCHXL_ADCDCOUPL], &adcCC26xxHWAttrs[CC1352P1_LAUNCHXL_ADCDCOUPL]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352P1_LAUNCHXL_ADCVSS], &adcCC26xxHWAttrs[CC1352P1_LAUNCHXL_ADCVSS]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352P1_LAUNCHXL_ADCVDDS], &adcCC26xxHWAttrs[CC1352P1_LAUNCHXL_ADCVDDS]}, +}; + +const uint_least8_t ADC_count = CC1352P1_LAUNCHXL_ADCCOUNT; + +/* + * =============================== ECDH =============================== + */ +#include +#include + +ECDHCC26X2_Object ecdhCC26X2Objects[CC1352P1_LAUNCHXL_ECDHCOUNT]; + +const ECDHCC26X2_HWAttrs ecdhCC26X2HWAttrs[CC1352P1_LAUNCHXL_ECDHCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const ECDH_Config ECDH_config[CC1352P1_LAUNCHXL_ECDHCOUNT] = { + { + .object = &ecdhCC26X2Objects[CC1352P1_LAUNCHXL_ECDH0], + .hwAttrs = &ecdhCC26X2HWAttrs[CC1352P1_LAUNCHXL_ECDH0] + }, +}; + +const uint_least8_t ECDH_count = CC1352P1_LAUNCHXL_ECDHCOUNT; + +/* + * =============================== ECDSA =============================== + */ +#include +#include + +ECDSACC26X2_Object ecdsaCC26X2Objects[CC1352P1_LAUNCHXL_ECDSACOUNT]; + +const ECDSACC26X2_HWAttrs ecdsaCC26X2HWAttrs[CC1352P1_LAUNCHXL_ECDSACOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const ECDSA_Config ECDSA_config[CC1352P1_LAUNCHXL_ECDSACOUNT] = { + { + .object = &ecdsaCC26X2Objects[CC1352P1_LAUNCHXL_ECDSA0], + .hwAttrs = &ecdsaCC26X2HWAttrs[CC1352P1_LAUNCHXL_ECDSA0] + }, +}; + +const uint_least8_t ECDSA_count = CC1352P1_LAUNCHXL_ECDSACOUNT; + +/* + * =============================== ECJPAKE =============================== + */ +#include +#include + +ECJPAKECC26X2_Object ecjpakeCC26X2Objects[CC1352P1_LAUNCHXL_ECJPAKECOUNT]; + +const ECJPAKECC26X2_HWAttrs ecjpakeCC26X2HWAttrs[CC1352P1_LAUNCHXL_ECJPAKECOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const ECJPAKE_Config ECJPAKE_config[CC1352P1_LAUNCHXL_ECJPAKECOUNT] = { + { + .object = &ecjpakeCC26X2Objects[CC1352P1_LAUNCHXL_ECJPAKE0], + .hwAttrs = &ecjpakeCC26X2HWAttrs[CC1352P1_LAUNCHXL_ECJPAKE0] + }, +}; + +const uint_least8_t ECJPAKE_count = CC1352P1_LAUNCHXL_ECJPAKECOUNT; + + +/* + * =============================== SHA2 =============================== + */ +#include +#include + +SHA2CC26X2_Object sha2CC26X2Objects[CC1352P1_LAUNCHXL_SHA2COUNT]; + +const SHA2CC26X2_HWAttrs sha2CC26X2HWAttrs[CC1352P1_LAUNCHXL_SHA2COUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const SHA2_Config SHA2_config[CC1352P1_LAUNCHXL_SHA2COUNT] = { + { + .object = &sha2CC26X2Objects[CC1352P1_LAUNCHXL_SHA20], + .hwAttrs = &sha2CC26X2HWAttrs[CC1352P1_LAUNCHXL_SHA20] + }, +}; + +const uint_least8_t SHA2_count = CC1352P1_LAUNCHXL_SHA2COUNT; + +/* + * =============================== AESCCM =============================== + */ +#include +#include + +AESCCMCC26XX_Object aesccmCC26XXObjects[CC1352P1_LAUNCHXL_AESCCMCOUNT]; + +const AESCCMCC26XX_HWAttrs aesccmCC26XXHWAttrs[CC1352P1_LAUNCHXL_AESCCMCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const AESCCM_Config AESCCM_config[CC1352P1_LAUNCHXL_AESCCMCOUNT] = { + { + .object = &aesccmCC26XXObjects[CC1352P1_LAUNCHXL_AESCCM0], + .hwAttrs = &aesccmCC26XXHWAttrs[CC1352P1_LAUNCHXL_AESCCM0] + }, +}; + +const uint_least8_t AESCCM_count = CC1352P1_LAUNCHXL_AESCCMCOUNT; + +/* + * =============================== AESECB =============================== + */ +#include +#include + +AESECBCC26XX_Object aesecbCC26XXObjects[CC1352P1_LAUNCHXL_AESECBCOUNT]; + +const AESECBCC26XX_HWAttrs aesecbCC26XXHWAttrs[CC1352P1_LAUNCHXL_AESECBCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const AESECB_Config AESECB_config[CC1352P1_LAUNCHXL_AESECBCOUNT] = { + { + .object = &aesecbCC26XXObjects[CC1352P1_LAUNCHXL_AESECB0], + .hwAttrs = &aesecbCC26XXHWAttrs[CC1352P1_LAUNCHXL_AESECB0] + }, +}; + +const uint_least8_t AESECB_count = CC1352P1_LAUNCHXL_AESECBCOUNT; + +/* + * =============================== Display =============================== + */ +#include +#include +#include + +#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE +#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 +#endif + +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 +#endif + +DisplayUart_Object displayUartObject; +DisplaySharp_Object displaySharpObject; + +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; +static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; + +const DisplayUart_HWAttrs displayUartHWAttrs = { + .uartIdx = CC1352P1_LAUNCHXL_UART0, + .baudRate = 115200, + .mutexTimeout = (unsigned int)(-1), + .strBuf = uartStringBuf, + .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, +}; + +const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { + .spiIndex = CC1352P1_LAUNCHXL_SPI0, + .csPin = CC1352P1_LAUNCHXL_GPIO_LCD_CS, + .powerPin = CC1352P1_LAUNCHXL_GPIO_DIO_19, + .enablePin = CC1352P1_LAUNCHXL_GPIO_LCD_ENABLE, + .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, + .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, + .displayBuf = sharpDisplayBuf, +}; + +#ifndef BOARD_DISPLAY_USE_UART +#define BOARD_DISPLAY_USE_UART 1 +#endif +#ifndef BOARD_DISPLAY_USE_UART_ANSI +#define BOARD_DISPLAY_USE_UART_ANSI 0 +#endif +#ifndef BOARD_DISPLAY_USE_LCD +#define BOARD_DISPLAY_USE_LCD 0 +#endif + +/* + * This #if/#else is needed to workaround a problem with the + * IAR compiler. The IAR compiler doesn't like the empty array + * initialization. (IAR Error[Pe1345]) + */ +#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) + +const Display_Config Display_config[] = { +#if (BOARD_DISPLAY_USE_UART) + { +# if (BOARD_DISPLAY_USE_UART_ANSI) + .fxnTablePtr = &DisplayUartAnsi_fxnTable, +# else /* Default to minimal UART with no cursor placement */ + .fxnTablePtr = &DisplayUartMin_fxnTable, +# endif + .object = &displayUartObject, + .hwAttrs = &displayUartHWAttrs, + }, +#endif +#if (BOARD_DISPLAY_USE_LCD) + { + .fxnTablePtr = &DisplaySharp_fxnTable, + .object = &displaySharpObject, + .hwAttrs = &displaySharpHWattrs + }, +#endif +}; + +const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); + +#else + +const Display_Config *Display_config = NULL; +const uint_least8_t Display_count = 0; + +#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ + +/* + * =============================== GPIO =============================== + */ +#include +#include + +/* + * Array of Pin configurations + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC1352P1_LAUNCHXL.h + * NOTE: Pins not used for interrupts should be placed at the end of the + * array. Callback entries can be omitted from callbacks array to + * reduce memory usage. + */ +GPIO_PinConfig gpioPinConfigs[] = { + /* Input pins */ + GPIOCC26XX_DIO_15 | GPIO_DO_NOT_CONFIG, /* Button 0 */ + GPIOCC26XX_DIO_14 | GPIO_DO_NOT_CONFIG, /* Button 1 */ + + GPIOCC26XX_DIO_15 | GPIO_DO_NOT_CONFIG, /* CC1352P1_LAUNCHXL_SPI_MASTER_READY */ + GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG, /* CC1352P1_LAUNCHXL_SPI_SLAVE_READY */ + + /* Output pins */ + GPIOCC26XX_DIO_07 | GPIO_DO_NOT_CONFIG, /* Green LED */ + GPIOCC26XX_DIO_06 | GPIO_DO_NOT_CONFIG, /* Red LED */ + + /* SPI Flash CSN */ + GPIOCC26XX_DIO_20 | GPIO_DO_NOT_CONFIG, + + /* + * DIO 19 is used for LCD power control and SD chip select. This is due to + * DIO21 & DIO22 moving on this LaunchPad. DIO 19 can also be used as a + * UART CTS pin. + */ + GPIOCC26XX_DIO_19 | GPIO_DO_NOT_CONFIG, + + /* Sharp Display - GPIO configurations will be done in the Display files */ + GPIOCC26XX_DIO_24 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ + GPIOCC26XX_DIO_23 | GPIO_DO_NOT_CONFIG, /*LCD enable */ + +}; + +/* + * Array of callback function pointers + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC1352P_LAUNCH.h + * NOTE: Pins not used for interrupts can be omitted from callbacks array to + * reduce memory usage (if placed at end of gpioPinConfigs array). + */ +GPIO_CallbackFxn gpioCallbackFunctions[] = { + NULL, /* Button 0 */ + NULL, /* Button 1 */ + NULL, /* CC1352P1_LAUNCHXL_SPI_MASTER_READY */ + NULL, /* CC1352P1_LAUNCHXL_SPI_SLAVE_READY */ +}; + +const GPIOCC26XX_Config GPIOCC26XX_config = { + .pinConfigs = (GPIO_PinConfig *)gpioPinConfigs, + .callbacks = (GPIO_CallbackFxn *)gpioCallbackFunctions, + .numberOfPinConfigs = CC1352P1_LAUNCHXL_GPIOCOUNT, + .numberOfCallbacks = sizeof(gpioCallbackFunctions)/sizeof(GPIO_CallbackFxn), + .intPriority = (~0) +}; + +/* + * =============================== GPTimer =============================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +#include + +GPTimerCC26XX_Object gptimerCC26XXObjects[CC1352P1_LAUNCHXL_GPTIMERCOUNT]; + +const GPTimerCC26XX_HWAttrs gptimerCC26xxHWAttrs[CC1352P1_LAUNCHXL_GPTIMERPARTSCOUNT] = { + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0A, }, + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0B, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1A, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1B, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2A, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2B, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3A, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3B, }, +}; + +const GPTimerCC26XX_Config GPTimerCC26XX_config[CC1352P1_LAUNCHXL_GPTIMERPARTSCOUNT] = { + { &gptimerCC26XXObjects[CC1352P1_LAUNCHXL_GPTIMER0], &gptimerCC26xxHWAttrs[CC1352P1_LAUNCHXL_GPTIMER0A], GPT_A }, + { &gptimerCC26XXObjects[CC1352P1_LAUNCHXL_GPTIMER0], &gptimerCC26xxHWAttrs[CC1352P1_LAUNCHXL_GPTIMER0B], GPT_B }, + { &gptimerCC26XXObjects[CC1352P1_LAUNCHXL_GPTIMER1], &gptimerCC26xxHWAttrs[CC1352P1_LAUNCHXL_GPTIMER1A], GPT_A }, + { &gptimerCC26XXObjects[CC1352P1_LAUNCHXL_GPTIMER1], &gptimerCC26xxHWAttrs[CC1352P1_LAUNCHXL_GPTIMER1B], GPT_B }, + { &gptimerCC26XXObjects[CC1352P1_LAUNCHXL_GPTIMER2], &gptimerCC26xxHWAttrs[CC1352P1_LAUNCHXL_GPTIMER2A], GPT_A }, + { &gptimerCC26XXObjects[CC1352P1_LAUNCHXL_GPTIMER2], &gptimerCC26xxHWAttrs[CC1352P1_LAUNCHXL_GPTIMER2B], GPT_B }, + { &gptimerCC26XXObjects[CC1352P1_LAUNCHXL_GPTIMER3], &gptimerCC26xxHWAttrs[CC1352P1_LAUNCHXL_GPTIMER3A], GPT_A }, + { &gptimerCC26XXObjects[CC1352P1_LAUNCHXL_GPTIMER3], &gptimerCC26xxHWAttrs[CC1352P1_LAUNCHXL_GPTIMER3B], GPT_B }, +}; + +/* + * =============================== I2C =============================== +*/ +#include +#include + +I2CCC26XX_Object i2cCC26xxObjects[CC1352P1_LAUNCHXL_I2CCOUNT]; + +const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1352P1_LAUNCHXL_I2CCOUNT] = { + { + .baseAddr = I2C0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_I2C0, + .intNum = INT_I2C_IRQ, + .intPriority = ~0, + .swiPriority = 0, + .sdaPin = CC1352P1_LAUNCHXL_I2C0_SDA0, + .sclPin = CC1352P1_LAUNCHXL_I2C0_SCL0, + } +}; + +const I2C_Config I2C_config[CC1352P1_LAUNCHXL_I2CCOUNT] = { + { + .fxnTablePtr = &I2CCC26XX_fxnTable, + .object = &i2cCC26xxObjects[CC1352P1_LAUNCHXL_I2C0], + .hwAttrs = &i2cCC26xxHWAttrs[CC1352P1_LAUNCHXL_I2C0] + }, +}; + +const uint_least8_t I2C_count = CC1352P1_LAUNCHXL_I2CCOUNT; + +/* + * =============================== NVS =============================== + */ +#include +#include +#include + +#define NVS_REGIONS_BASE 0x48000 +#define SECTORSIZE 0x2000 +#define REGIONSIZE (SECTORSIZE * 4) +#define SPISECTORSIZE 0x1000 +#define SPIREGIONSIZE (SPISECTORSIZE * 32) +#define VERIFYBUFSIZE 64 + +static uint8_t verifyBuf[VERIFYBUFSIZE]; + +/* + * Reserve flash sectors for NVS driver use by placing an uninitialized byte + * array at the desired flash address. + */ +#if defined(__TI_COMPILER_VERSION__) + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +#pragma LOCATION(flashBuf, NVS_REGIONS_BASE); +#pragma NOINIT(flashBuf); +static char flashBuf[REGIONSIZE]; + +#elif defined(__IAR_SYSTEMS_ICC__) + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +static __no_init char flashBuf[REGIONSIZE] @ NVS_REGIONS_BASE; + +#elif defined(__GNUC__) + +/* + * Place the flash buffers in the .nvs section created in the gcc linker file. + * The .nvs section enforces alignment on a sector boundary but may + * be placed anywhere in flash memory. If desired the .nvs section can be set + * to a fixed address by changing the following in the gcc linker file: + * + * .nvs (FIXED_FLASH_ADDR) (NOLOAD) : AT (FIXED_FLASH_ADDR) { + * *(.nvs) + * } > REGION_TEXT + */ +__attribute__ ((section (".nvs"))) +static char flashBuf[REGIONSIZE]; + +#endif + +/* Allocate objects for NVS and NVS SPI */ +NVSCC26XX_Object nvsCC26xxObjects[1]; +NVSSPI25X_Object nvsSPI25XObjects[1]; + +/* Hardware attributes for NVS */ +const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { + { + .regionBase = (void *)flashBuf, + .regionSize = REGIONSIZE, + }, +}; + +/* Hardware attributes for NVS SPI */ +const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { + { + .regionBaseOffset = 0, + .regionSize = SPIREGIONSIZE, + .sectorSize = SPISECTORSIZE, + .verifyBuf = verifyBuf, + .verifyBufSize = VERIFYBUFSIZE, + .spiHandle = NULL, + .spiIndex = 0, + .spiBitRate = 4000000, + .spiCsnGpioIndex = CC1352P1_LAUNCHXL_GPIO_SPI_FLASH_CS, + }, +}; + +/* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ +const NVS_Config NVS_config[CC1352P1_LAUNCHXL_NVSCOUNT] = { + { + .fxnTablePtr = &NVSCC26XX_fxnTable, + .object = &nvsCC26xxObjects[0], + .hwAttrs = &nvsCC26xxHWAttrs[0], + }, + { + .fxnTablePtr = &NVSSPI25X_fxnTable, + .object = &nvsSPI25XObjects[0], + .hwAttrs = &nvsSPI25XHWAttrs[0], + }, +}; + +const uint_least8_t NVS_count = CC1352P1_LAUNCHXL_NVSCOUNT; + +/* + * =============================== PIN =============================== + */ +#include +#include + +const PIN_Config BoardGpioInitTable[] = { + + CC1352P1_LAUNCHXL_PIN_RLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC1352P1_LAUNCHXL_PIN_GLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC1352P1_LAUNCHXL_PIN_BTN1 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC1352P1_LAUNCHXL_PIN_BTN2 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC1352P1_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ + CC1352P1_LAUNCHXL_UART0_RX | PIN_INPUT_EN | PIN_PULLDOWN, /* UART RX via debugger back channel */ + CC1352P1_LAUNCHXL_UART0_TX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* UART TX via debugger back channel */ + CC1352P1_LAUNCHXL_SPI0_MOSI | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master out - slave in */ + CC1352P1_LAUNCHXL_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master in - slave out */ + CC1352P1_LAUNCHXL_SPI0_CLK | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI clock */ + CC1352P1_LAUNCHXL_DIO28_RF_24GHZ | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Path disabled */ + CC1352P1_LAUNCHXL_DIO29_RF_HIGH_PA | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Path disabled */ + CC1352P1_LAUNCHXL_DIO30_RF_SUB1GHZ | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Path disabled */ + PIN_TERMINATE +}; + +const PINCC26XX_HWAttrs PINCC26XX_hwAttrs = { + .intPriority = ~0, + .swiPriority = 0 +}; + +/* + * =============================== Power =============================== + */ +#include +#include + +const PowerCC26X2_Config PowerCC26X2_config = { + .policyInitFxn = NULL, + .policyFxn = &PowerCC26XX_standbyPolicy, + .calibrateFxn = &PowerCC26XX_calibrate, + .enablePolicy = true, + .calibrateRCOSC_LF = true, + .calibrateRCOSC_HF = true, +}; + +/* + * =============================== PWM =============================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +#include +#include + +PWMTimerCC26XX_Object pwmtimerCC26xxObjects[CC1352P1_LAUNCHXL_PWMCOUNT]; + +const PWMTimerCC26XX_HwAttrs pwmtimerCC26xxHWAttrs[CC1352P1_LAUNCHXL_PWMCOUNT] = { + { .pwmPin = CC1352P1_LAUNCHXL_PWMPIN0, .gpTimerUnit = CC1352P1_LAUNCHXL_GPTIMER0A }, + { .pwmPin = CC1352P1_LAUNCHXL_PWMPIN1, .gpTimerUnit = CC1352P1_LAUNCHXL_GPTIMER0B }, + { .pwmPin = CC1352P1_LAUNCHXL_PWMPIN2, .gpTimerUnit = CC1352P1_LAUNCHXL_GPTIMER1A }, + { .pwmPin = CC1352P1_LAUNCHXL_PWMPIN3, .gpTimerUnit = CC1352P1_LAUNCHXL_GPTIMER1B }, + { .pwmPin = CC1352P1_LAUNCHXL_PWMPIN4, .gpTimerUnit = CC1352P1_LAUNCHXL_GPTIMER2A }, + { .pwmPin = CC1352P1_LAUNCHXL_PWMPIN5, .gpTimerUnit = CC1352P1_LAUNCHXL_GPTIMER2B }, + { .pwmPin = CC1352P1_LAUNCHXL_PWMPIN6, .gpTimerUnit = CC1352P1_LAUNCHXL_GPTIMER3A }, + { .pwmPin = CC1352P1_LAUNCHXL_PWMPIN7, .gpTimerUnit = CC1352P1_LAUNCHXL_GPTIMER3B }, +}; + +const PWM_Config PWM_config[CC1352P1_LAUNCHXL_PWMCOUNT] = { + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352P1_LAUNCHXL_PWM0], &pwmtimerCC26xxHWAttrs[CC1352P1_LAUNCHXL_PWM0] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352P1_LAUNCHXL_PWM1], &pwmtimerCC26xxHWAttrs[CC1352P1_LAUNCHXL_PWM1] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352P1_LAUNCHXL_PWM2], &pwmtimerCC26xxHWAttrs[CC1352P1_LAUNCHXL_PWM2] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352P1_LAUNCHXL_PWM3], &pwmtimerCC26xxHWAttrs[CC1352P1_LAUNCHXL_PWM3] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352P1_LAUNCHXL_PWM4], &pwmtimerCC26xxHWAttrs[CC1352P1_LAUNCHXL_PWM4] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352P1_LAUNCHXL_PWM5], &pwmtimerCC26xxHWAttrs[CC1352P1_LAUNCHXL_PWM5] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352P1_LAUNCHXL_PWM6], &pwmtimerCC26xxHWAttrs[CC1352P1_LAUNCHXL_PWM6] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352P1_LAUNCHXL_PWM7], &pwmtimerCC26xxHWAttrs[CC1352P1_LAUNCHXL_PWM7] }, +}; + +const uint_least8_t PWM_count = CC1352P1_LAUNCHXL_PWMCOUNT; + +/* + * =============================== RF Driver =============================== + */ +#include + +/* + * Board-specific callback function to set the correct antenna path. + * + * This function is called by the RF driver on global driver events. It contains + * a default implementation to set the correct antenna path. + */ +static void CC1352P1_LAUNCHXL_rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void* arg); + +const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { + .hwiPriority = ~0, /* Lowest HWI priority */ + .swiPriority = 0, /* Lowest SWI priority */ + .xoscHfAlwaysNeeded = true, /* Keep XOSC dependency while in stanby */ + .globalCallback = &CC1352P1_LAUNCHXL_rfDriverCallback, /* Register the board specific callback */ + .globalEventMask = RF_GlobalEventRadioSetup | RF_GlobalEventRadioPowerDown /* Subscribe the callback to both events */ +}; + +/* + * =============================== SD =============================== + */ +#include +#include + +SDSPI_Object sdspiObjects[CC1352P1_LAUNCHXL_SDCOUNT]; + +const SDSPI_HWAttrs sdspiHWAttrs[CC1352P1_LAUNCHXL_SDCOUNT] = { + { + .spiIndex = CC1352P1_LAUNCHXL_SPI0, + .spiCsGpioIndex = CC1352P1_LAUNCHXL_GPIO_DIO_19 + } +}; + +const SD_Config SD_config[CC1352P1_LAUNCHXL_SDCOUNT] = { + { + .fxnTablePtr = &SDSPI_fxnTable, + .object = &sdspiObjects[CC1352P1_LAUNCHXL_SDSPI0], + .hwAttrs = &sdspiHWAttrs[CC1352P1_LAUNCHXL_SDSPI0] + }, +}; + +const uint_least8_t SD_count = CC1352P1_LAUNCHXL_SDCOUNT; + +/* + * =============================== SPI DMA =============================== + */ +#include +#include + +SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1352P1_LAUNCHXL_SPICOUNT]; + +/* + * NOTE: The SPI instances below can be used by the SD driver to communicate + * with a SD card via SPI. The 'defaultTxBufValue' fields below are set to 0xFF + * to satisfy the SDSPI driver requirement. + */ +const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1352P1_LAUNCHXL_SPICOUNT] = { + { + .baseAddr = SSI0_BASE, + .intNum = INT_SSI0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .powerMngrId = PowerCC26XX_PERIPH_SSI0, + .defaultTxBufValue = 0xFF, + .rxChannelBitMask = 1< +#include + +UARTCC26XX_Object uartCC26XXObjects[CC1352P1_LAUNCHXL_UARTCOUNT]; + +uint8_t uartCC26XXRingBuffer[CC1352P1_LAUNCHXL_UARTCOUNT][32]; + +const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1352P1_LAUNCHXL_UARTCOUNT] = { + { + .baseAddr = UART0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UART0, + .intNum = INT_UART0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .txPin = CC1352P1_LAUNCHXL_UART0_TX, + .rxPin = CC1352P1_LAUNCHXL_UART0_RX, + .ctsPin = PIN_UNASSIGNED, + .rtsPin = PIN_UNASSIGNED, + .ringBufPtr = uartCC26XXRingBuffer[CC1352P1_LAUNCHXL_UART0], + .ringBufSize = sizeof(uartCC26XXRingBuffer[CC1352P1_LAUNCHXL_UART0]), + .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, + .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, + .errorFxn = NULL + }, + { + .baseAddr = UART1_BASE, + .powerMngrId = PowerCC26X2_PERIPH_UART1, + .intNum = INT_UART1_COMB, + .intPriority = ~0, + .swiPriority = 0, + .txPin = CC1352P1_LAUNCHXL_UART1_TX, + .rxPin = CC1352P1_LAUNCHXL_UART1_RX, + .ctsPin = PIN_UNASSIGNED, + .rtsPin = PIN_UNASSIGNED, + .ringBufPtr = uartCC26XXRingBuffer[CC1352P1_LAUNCHXL_UART1], + .ringBufSize = sizeof(uartCC26XXRingBuffer[CC1352P1_LAUNCHXL_UART1]), + .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, + .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, + .errorFxn = NULL + } +}; + +const UART_Config UART_config[CC1352P1_LAUNCHXL_UARTCOUNT] = { + { + .fxnTablePtr = &UARTCC26XX_fxnTable, + .object = &uartCC26XXObjects[CC1352P1_LAUNCHXL_UART0], + .hwAttrs = &uartCC26XXHWAttrs[CC1352P1_LAUNCHXL_UART0] + }, + { + .fxnTablePtr = &UARTCC26XX_fxnTable, + .object = &uartCC26XXObjects[CC1352P1_LAUNCHXL_UART1], + .hwAttrs = &uartCC26XXHWAttrs[CC1352P1_LAUNCHXL_UART1] + }, +}; + +const uint_least8_t UART_count = CC1352P1_LAUNCHXL_UARTCOUNT; + +/* + * =============================== UDMA =============================== + */ +#include + +UDMACC26XX_Object udmaObjects[CC1352P1_LAUNCHXL_UDMACOUNT]; + +const UDMACC26XX_HWAttrs udmaHWAttrs[CC1352P1_LAUNCHXL_UDMACOUNT] = { + { + .baseAddr = UDMA0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UDMA, + .intNum = INT_DMA_ERR, + .intPriority = ~0 + } +}; + +const UDMACC26XX_Config UDMACC26XX_config[CC1352P1_LAUNCHXL_UDMACOUNT] = { + { + .object = &udmaObjects[CC1352P1_LAUNCHXL_UDMA0], + .hwAttrs = &udmaHWAttrs[CC1352P1_LAUNCHXL_UDMA0] + }, +}; + + + +/* + * =============================== Watchdog =============================== + */ +#include +#include + +WatchdogCC26XX_Object watchdogCC26XXObjects[CC1352P1_LAUNCHXL_WATCHDOGCOUNT]; + +const WatchdogCC26XX_HWAttrs watchdogCC26XXHWAttrs[CC1352P1_LAUNCHXL_WATCHDOGCOUNT] = { + { + .baseAddr = WDT_BASE, + .reloadValue = 1000 /* Reload value in milliseconds */ + }, +}; + +const Watchdog_Config Watchdog_config[CC1352P1_LAUNCHXL_WATCHDOGCOUNT] = { + { + .fxnTablePtr = &WatchdogCC26XX_fxnTable, + .object = &watchdogCC26XXObjects[CC1352P1_LAUNCHXL_WATCHDOG0], + .hwAttrs = &watchdogCC26XXHWAttrs[CC1352P1_LAUNCHXL_WATCHDOG0] + }, +}; + +const uint_least8_t Watchdog_count = CC1352P1_LAUNCHXL_WATCHDOGCOUNT; + +/* + * ======== CC1352P1_LAUNCHXL_wakeUpExtFlash ======== + */ +void CC1352P1_LAUNCHXL_wakeUpExtFlash(void) +{ + PIN_Config extFlashPinTable[] = { + CC1352P1_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + /* + * To wake up we need to toggle the chip select at + * least 20 ns and ten wait at least 35 us. + */ + + /* Toggle chip select for ~20ns to wake ext. flash */ + PIN_setOutputValue(extFlashPinHandle, CC1352P1_LAUNCHXL_SPI_FLASH_CS, 0); + /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ + CPUdelay(1); + PIN_setOutputValue(extFlashPinHandle, CC1352P1_LAUNCHXL_SPI_FLASH_CS, 1); + /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ + CPUdelay(560); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC1352P1_LAUNCHXL_sendExtFlashByte ======== + */ +void CC1352P1_LAUNCHXL_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) +{ + uint8_t i; + + PIN_setOutputValue(pinHandle, CC1352P1_LAUNCHXL_SPI_FLASH_CS, 0); + + for (i = 0; i < 8; i++) { + PIN_setOutputValue(pinHandle, CC1352P1_LAUNCHXL_SPI0_CLK, 0); + PIN_setOutputValue(pinHandle, CC1352P1_LAUNCHXL_SPI0_MOSI, (byte >> (7 - i)) & 0x01); + PIN_setOutputValue(pinHandle, CC1352P1_LAUNCHXL_SPI0_CLK, 1); + + /* + * Waste a few cycles to keep the CLK high for at + * least 45% of the period. + * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. + */ + CPUdelay(8); + } + + PIN_setOutputValue(pinHandle, CC1352P1_LAUNCHXL_SPI0_CLK, 0); + PIN_setOutputValue(pinHandle, CC1352P1_LAUNCHXL_SPI_FLASH_CS, 1); + + /* + * Keep CS high at least 40 us + * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us + */ + CPUdelay(700); +} + +/* + * ======== CC1352P1_LAUNCHXL_shutDownExtFlash ======== + */ +void CC1352P1_LAUNCHXL_shutDownExtFlash(void) +{ + /* To be sure we are putting the flash into sleep and not waking it, we first have to make a wake up call */ + CC1352P1_LAUNCHXL_wakeUpExtFlash(); + + PIN_Config extFlashPinTable[] = { + CC1352P1_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + CC1352P1_LAUNCHXL_SPI0_CLK | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + CC1352P1_LAUNCHXL_SPI0_MOSI | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + CC1352P1_LAUNCHXL_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + uint8_t extFlashShutdown = 0xB9; + + CC1352P1_LAUNCHXL_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC1352P1_LAUNCHXL_initGeneral ======== + */ +void CC1352P1_LAUNCHXL_initGeneral(void) +{ + Power_init(); + + if (PIN_init(BoardGpioInitTable) != PIN_SUCCESS) { + /* Error with PIN_init */ + while (1); + } + + CC1352P1_LAUNCHXL_initAntennaSwitch(); + + /* Shut down external flash as default */ + CC1352P1_LAUNCHXL_shutDownExtFlash(); +} + + +/* + * ======== Antenna switching ======== + */ +static PIN_Handle CC1352P1_antennaPins; +static PIN_State CC1352P1_antennaState; + +void CC1352P1_LAUNCHXL_initAntennaSwitch() +{ + PIN_Config antennaConfig[] = { + CC1352P1_LAUNCHXL_DIO28_RF_24GHZ | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Path disabled */ + CC1352P1_LAUNCHXL_DIO29_RF_HIGH_PA | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Path disabled */ + CC1352P1_LAUNCHXL_DIO30_RF_SUB1GHZ | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Path disabled */ + PIN_TERMINATE + }; + CC1352P1_antennaPins = PIN_open(&CC1352P1_antennaState, antennaConfig); +} + +/* + * ======== CC1352P1_LAUNCHXL_rfDriverCallback ======== + * Sets up the antenna switch depending on the current PHY configuration. + * Truth table: + * + * Path DIO28 DIO29 DIO30 + * =========== ===== ===== ===== + * Off 0 0 0 + * Sub-1 GHz 0 0 1 + * 2.4 GHz 1 0 0 + * 20 dBm TX 0 1 0 + */ +void CC1352P1_LAUNCHXL_rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void* arg) +{ + /* Switch off all paths first. Needs to be done anyway in every sub-case below. */ + PINCC26XX_setOutputValue(CC1352P1_LAUNCHXL_DIO28_RF_24GHZ, 0); + PINCC26XX_setOutputValue(CC1352P1_LAUNCHXL_DIO29_RF_HIGH_PA, 0); + PINCC26XX_setOutputValue(CC1352P1_LAUNCHXL_DIO30_RF_SUB1GHZ, 0); + + if (events & RF_GlobalEventRadioSetup) { + /* Decode the current PA configuration. */ + RF_TxPowerTable_PAType paType = (RF_TxPowerTable_PAType)RF_getTxPower(client).paType; + + /* Decode the generic argument as a setup command. */ + RF_RadioSetup* setupCommand = (RF_RadioSetup*)arg; + + if (setupCommand->common.commandNo == CMD_PROP_RADIO_DIV_SETUP) { + /* Sub-1 GHz */ + if (paType == RF_TxPowerTable_HighPA) { + /* PA enable --> HIGH PA + * LNA enable --> Sub-1 GHz + */ + PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO28_RF_24GHZ, PINCC26XX_MUX_GPIO); + // Note: RFC_GPO3 is a work-around because the RFC_GPO1 (PA enable signal) is sometimes not + // de-asserted on CC1352 Rev A. + PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO29_RF_HIGH_PA, PINCC26XX_MUX_RFC_GPO3); + PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO30_RF_SUB1GHZ, PINCC26XX_MUX_RFC_GPO0); + } else { + /* RF core active --> Sub-1 GHz */ + PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO28_RF_24GHZ, PINCC26XX_MUX_GPIO); + PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO29_RF_HIGH_PA, PINCC26XX_MUX_GPIO); + PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO30_RF_SUB1GHZ, PINCC26XX_MUX_GPIO); + PINCC26XX_setOutputValue(CC1352P1_LAUNCHXL_DIO30_RF_SUB1GHZ, 1); + } + } else { + /* 2.4 GHz */ + if (paType == RF_TxPowerTable_HighPA) + { + /* PA enable --> HIGH PA + * LNA enable --> 2.4 GHz + */ + PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO28_RF_24GHZ, PINCC26XX_MUX_RFC_GPO0); + // Note: RFC_GPO3 is a work-around because the RFC_GPO1 (PA enable signal) is sometimes not + // de-asserted on CC1352 Rev A. + PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO29_RF_HIGH_PA, PINCC26XX_MUX_RFC_GPO3); + PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO30_RF_SUB1GHZ, PINCC26XX_MUX_GPIO); + } else { + /* RF core active --> 2.4 GHz */ + PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO28_RF_24GHZ, PINCC26XX_MUX_GPIO); + PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO29_RF_HIGH_PA, PINCC26XX_MUX_GPIO); + PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO30_RF_SUB1GHZ, PINCC26XX_MUX_GPIO); + PINCC26XX_setOutputValue(CC1352P1_LAUNCHXL_DIO28_RF_24GHZ, 1); + } + } + } else { + /* Reset the IO multiplexer to GPIO functionality */ + PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO28_RF_24GHZ, PINCC26XX_MUX_GPIO); + PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO29_RF_HIGH_PA, PINCC26XX_MUX_GPIO); + PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO30_RF_SUB1GHZ, PINCC26XX_MUX_GPIO); + } +} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h new file mode 100644 index 000000000..3932531c4 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h @@ -0,0 +1,431 @@ +/* + * Copyright (c) 2017-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ +/** =========================================================================== + * @file CC1352P1_LAUNCHXL.h + * + * @brief CC1352P1_LAUNCHXL Board Specific header file. + * + * The CC1352P1_LAUNCHXL header file should be included in an application as + * follows: + * @code + * #include "CC1352P1_LAUNCHXL.h" + * @endcode + * + * =========================================================================== + */ +#ifndef __CC1352P1_LAUNCHXL_BOARD_H__ +#define __CC1352P1_LAUNCHXL_BOARD_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes */ +#include +#include + +/* Externs */ +extern const PIN_Config BoardGpioInitTable[]; + +/* Defines */ +#define CC1352P1_LAUNCHXL + +/* Mapping of pins to board signals using general board aliases + * + */ + +/* Mapping of pins to board signals using general board aliases + * + */ +/* Analog Capable DIOs */ +#define CC1352P1_LAUNCHXL_DIO23_ANALOG IOID_23 +#define CC1352P1_LAUNCHXL_DIO24_ANALOG IOID_24 +#define CC1352P1_LAUNCHXL_DIO25_ANALOG IOID_25 +#define CC1352P1_LAUNCHXL_DIO26_ANALOG IOID_26 +#define CC1352P1_LAUNCHXL_DIO27_ANALOG IOID_27 + +/* RF Antenna Switch */ +#define CC1352P1_LAUNCHXL_DIO28_RF_24GHZ IOID_28 +#define CC1352P1_LAUNCHXL_DIO29_RF_HIGH_PA IOID_29 +#define CC1352P1_LAUNCHXL_DIO30_RF_SUB1GHZ IOID_30 + +/* Digital IOs */ +#define CC1352P1_LAUNCHXL_DIO12 IOID_12 +#define CC1352P1_LAUNCHXL_DIO15 IOID_15 +#define CC1352P1_LAUNCHXL_DIO16_TDO IOID_16 +#define CC1352P1_LAUNCHXL_DIO17_TDI IOID_17 +#define CC1352P1_LAUNCHXL_DIO21 IOID_21 +#define CC1352P1_LAUNCHXL_DIO22 IOID_22 + +/* Discrete Inputs */ +#define CC1352P1_LAUNCHXL_PIN_BTN1 IOID_15 +#define CC1352P1_LAUNCHXL_PIN_BTN2 IOID_14 + +/* GPIO */ +#define CC1352P1_LAUNCHXL_GPIO_LED_ON 1 +#define CC1352P1_LAUNCHXL_GPIO_LED_OFF 0 + +/* I2C */ +#define CC1352P1_LAUNCHXL_I2C0_SCL0 IOID_22 +#define CC1352P1_LAUNCHXL_I2C0_SDA0 IOID_5 + +/* LEDs */ +#define CC1352P1_LAUNCHXL_PIN_LED_ON 1 +#define CC1352P1_LAUNCHXL_PIN_LED_OFF 0 +#define CC1352P1_LAUNCHXL_PIN_RLED IOID_6 +#define CC1352P1_LAUNCHXL_PIN_GLED IOID_7 + +/* PWM Outputs */ +#define CC1352P1_LAUNCHXL_PWMPIN0 CC1352P1_LAUNCHXL_PIN_RLED +#define CC1352P1_LAUNCHXL_PWMPIN1 CC1352P1_LAUNCHXL_PIN_GLED +#define CC1352P1_LAUNCHXL_PWMPIN2 PIN_UNASSIGNED +#define CC1352P1_LAUNCHXL_PWMPIN3 PIN_UNASSIGNED +#define CC1352P1_LAUNCHXL_PWMPIN4 PIN_UNASSIGNED +#define CC1352P1_LAUNCHXL_PWMPIN5 PIN_UNASSIGNED +#define CC1352P1_LAUNCHXL_PWMPIN6 PIN_UNASSIGNED +#define CC1352P1_LAUNCHXL_PWMPIN7 PIN_UNASSIGNED + +/* SPI */ +#define CC1352P1_LAUNCHXL_SPI_FLASH_CS IOID_20 +#define CC1352P1_LAUNCHXL_FLASH_CS_ON 0 +#define CC1352P1_LAUNCHXL_FLASH_CS_OFF 1 + +/* SPI Board */ +#define CC1352P1_LAUNCHXL_SPI0_MISO IOID_8 /* RF1.20 */ +#define CC1352P1_LAUNCHXL_SPI0_MOSI IOID_9 /* RF1.18 */ +#define CC1352P1_LAUNCHXL_SPI0_CLK IOID_10 /* RF1.16 */ +#define CC1352P1_LAUNCHXL_SPI0_CSN PIN_UNASSIGNED +#define CC1352P1_LAUNCHXL_SPI1_MISO PIN_UNASSIGNED +#define CC1352P1_LAUNCHXL_SPI1_MOSI PIN_UNASSIGNED +#define CC1352P1_LAUNCHXL_SPI1_CLK PIN_UNASSIGNED +#define CC1352P1_LAUNCHXL_SPI1_CSN PIN_UNASSIGNED + +/* UART Board */ +#define CC1352P1_LAUNCHXL_UART0_RX IOID_12 /* RXD */ +#define CC1352P1_LAUNCHXL_UART0_TX IOID_13 /* TXD */ +#define CC1352P1_LAUNCHXL_UART0_CTS IOID_19 /* CTS */ +#define CC1352P1_LAUNCHXL_UART0_RTS IOID_18 /* RTS */ +#define CC1352P1_LAUNCHXL_UART1_RX PIN_UNASSIGNED +#define CC1352P1_LAUNCHXL_UART1_TX PIN_UNASSIGNED +#define CC1352P1_LAUNCHXL_UART1_CTS PIN_UNASSIGNED +#define CC1352P1_LAUNCHXL_UART1_RTS PIN_UNASSIGNED +/* For backward compatibility */ +#define CC1352P1_LAUNCHXL_UART_RX CC1352P1_LAUNCHXL_UART0_RX +#define CC1352P1_LAUNCHXL_UART_TX CC1352P1_LAUNCHXL_UART0_TX +#define CC1352P1_LAUNCHXL_UART_CTS CC1352P1_LAUNCHXL_UART0_CTS +#define CC1352P1_LAUNCHXL_UART_RTS CC1352P1_LAUNCHXL_UART0_RTS + +/*! + * @brief Initialize the general board specific settings + * + * This function initializes the general board specific settings. + */ +void CC1352P1_LAUNCHXL_initGeneral(void); + +/*! + * @brief Shut down the external flash present on the board files + * + * This function bitbangs the SPI sequence necessary to turn off + * the external flash on LaunchPads. + */ +void CC1352P1_LAUNCHXL_shutDownExtFlash(void); + +/*! + * @brief Wake up the external flash present on the board files + * + * This function toggles the chip select for the amount of time needed + * to wake the chip up. + */ +void CC1352P1_LAUNCHXL_wakeUpExtFlash(void); + + +/*! + * \brief Initializes the antenna switch IOs. + * + * This function sets up the antenna switch and occupies + * the necessary IO pins. After calling this function, they + * cannot be used in the application anymore. + */ +void CC1352P1_LAUNCHXL_initAntennaSwitch(void); + +/*! + * @def CC1352P1_LAUNCHXL_ADCBufName + * @brief Enum of ADCs + */ +typedef enum CC1352P1_LAUNCHXL_ADCBufName { + CC1352P1_LAUNCHXL_ADCBUF0 = 0, + + CC1352P1_LAUNCHXL_ADCBUFCOUNT +} CC1352P1_LAUNCHXL_ADCBufName; + +/*! + * @def CC1352P1_LAUNCHXL_ADCBuf0SourceName + * @brief Enum of ADCBuf channels + */ +typedef enum CC1352P1_LAUNCHXL_ADCBuf0ChannelName { + CC1352P1_LAUNCHXL_ADCBUF0CHANNEL0 = 0, + CC1352P1_LAUNCHXL_ADCBUF0CHANNEL1, + CC1352P1_LAUNCHXL_ADCBUF0CHANNEL2, + CC1352P1_LAUNCHXL_ADCBUF0CHANNEL3, + CC1352P1_LAUNCHXL_ADCBUF0CHANNEL4, + CC1352P1_LAUNCHXL_ADCBUF0CHANNEL5, + CC1352P1_LAUNCHXL_ADCBUF0CHANNEL6, + CC1352P1_LAUNCHXL_ADCBUF0CHANNELVDDS, + CC1352P1_LAUNCHXL_ADCBUF0CHANNELDCOUPL, + CC1352P1_LAUNCHXL_ADCBUF0CHANNELVSS, + + CC1352P1_LAUNCHXL_ADCBUF0CHANNELCOUNT +} CC1352P1_LAUNCHXL_ADCBuf0ChannelName; + +/*! + * @def CC1352P1_LAUNCHXL_ADCName + * @brief Enum of ADCs + */ +typedef enum CC1352P1_LAUNCHXL_ADCName { + CC1352P1_LAUNCHXL_ADC0 = 0, + CC1352P1_LAUNCHXL_ADC1, + CC1352P1_LAUNCHXL_ADC2, + CC1352P1_LAUNCHXL_ADC3, + CC1352P1_LAUNCHXL_ADC4, + CC1352P1_LAUNCHXL_ADC5, + CC1352P1_LAUNCHXL_ADC6, + CC1352P1_LAUNCHXL_ADCDCOUPL, + CC1352P1_LAUNCHXL_ADCVSS, + CC1352P1_LAUNCHXL_ADCVDDS, + + CC1352P1_LAUNCHXL_ADCCOUNT +} CC1352P1_LAUNCHXL_ADCName; + +/*! + * @def CC1352P1_LAUNCHXL_ECDHName + * @brief Enum of ECDH names + */ +typedef enum CC1352P1_LAUNCHXL_ECDHName { + CC1352P1_LAUNCHXL_ECDH0 = 0, + + CC1352P1_LAUNCHXL_ECDHCOUNT +} CC1352P1_LAUNCHXL_ECDHName; + +/*! + * @def CC1352P1_LAUNCHXL_ECDSAName + * @brief Enum of ECDSA names + */ +typedef enum CC1352P1_LAUNCHXL_ECDSAName { + CC1352P1_LAUNCHXL_ECDSA0 = 0, + + CC1352P1_LAUNCHXL_ECDSACOUNT +} CC1352P1_LAUNCHXL_ECDSAName; + +/*! + * @def CC1352P1_LAUNCHXL_ECJPAKEName + * @brief Enum of ECJPAKE names + */ +typedef enum CC1352P1_LAUNCHXL_ECJPAKEName { + CC1352P1_LAUNCHXL_ECJPAKE0 = 0, + + CC1352P1_LAUNCHXL_ECJPAKECOUNT +} CC1352P1_LAUNCHXL_ECJPAKEName; + +/*! + * @def CC1352P1_LAUNCHXL_AESCCMName + * @brief Enum of AESCCM names + */ +typedef enum CC1352P1_LAUNCHXL_AESCCMName { + CC1352P1_LAUNCHXL_AESCCM0 = 0, + + CC1352P1_LAUNCHXL_AESCCMCOUNT +} CC1352P1_LAUNCHXL_AESCCMName; + +/*! + * @def CC1352P1_LAUNCHXL_AESECBName + * @brief Enum of AESECB names + */ +typedef enum CC1352P1_LAUNCHXL_AESECBName { + CC1352P1_LAUNCHXL_AESECB0 = 0, + + CC1352P1_LAUNCHXL_AESECBCOUNT +} CC1352P1_LAUNCHXL_AESECBName; + +/*! + * @def CC1352P1_LAUNCHXL_SHA2Name + * @brief Enum of SHA2 names + */ +typedef enum CC1352P1_LAUNCHXL_SHA2Name { + CC1352P1_LAUNCHXL_SHA20 = 0, + + CC1352P1_LAUNCHXL_SHA2COUNT +} CC1352P1_LAUNCHXL_SHA2Name; + +/*! + * @def CC1352P1_LAUNCHXL_GPIOName + * @brief Enum of GPIO names + */ +typedef enum CC1352P1_LAUNCHXL_GPIOName { + CC1352P1_LAUNCHXL_GPIO_S1 = 0, + CC1352P1_LAUNCHXL_GPIO_S2, + CC1352P1_LAUNCHXL_SPI_MASTER_READY, + CC1352P1_LAUNCHXL_SPI_SLAVE_READY, + CC1352P1_LAUNCHXL_GPIO_LED_GREEN, + CC1352P1_LAUNCHXL_GPIO_LED_RED, + CC1352P1_LAUNCHXL_GPIO_SPI_FLASH_CS, + CC1352P1_LAUNCHXL_GPIO_DIO_19, + CC1352P1_LAUNCHXL_GPIO_LCD_CS, + CC1352P1_LAUNCHXL_GPIO_LCD_ENABLE, + CC1352P1_LAUNCHXL_GPIOCOUNT +} CC1352P1_LAUNCHXL_GPIOName; + +/*! + * @def CC1352P1_LAUNCHXL_GPTimerName + * @brief Enum of GPTimer parts + */ +typedef enum CC1352P1_LAUNCHXL_GPTimerName { + CC1352P1_LAUNCHXL_GPTIMER0A = 0, + CC1352P1_LAUNCHXL_GPTIMER0B, + CC1352P1_LAUNCHXL_GPTIMER1A, + CC1352P1_LAUNCHXL_GPTIMER1B, + CC1352P1_LAUNCHXL_GPTIMER2A, + CC1352P1_LAUNCHXL_GPTIMER2B, + CC1352P1_LAUNCHXL_GPTIMER3A, + CC1352P1_LAUNCHXL_GPTIMER3B, + + CC1352P1_LAUNCHXL_GPTIMERPARTSCOUNT +} CC1352P1_LAUNCHXL_GPTimerName; + +/*! + * @def CC1352P1_LAUNCHXL_GPTimers + * @brief Enum of GPTimers + */ +typedef enum CC1352P1_LAUNCHXL_GPTimers { + CC1352P1_LAUNCHXL_GPTIMER0 = 0, + CC1352P1_LAUNCHXL_GPTIMER1, + CC1352P1_LAUNCHXL_GPTIMER2, + CC1352P1_LAUNCHXL_GPTIMER3, + + CC1352P1_LAUNCHXL_GPTIMERCOUNT +} CC1352P1_LAUNCHXL_GPTimers; + +/*! + * @def CC1352P1_LAUNCHXL_I2CName + * @brief Enum of I2C names + */ +typedef enum CC1352P1_LAUNCHXL_I2CName { + CC1352P1_LAUNCHXL_I2C0 = 0, + + CC1352P1_LAUNCHXL_I2CCOUNT +} CC1352P1_LAUNCHXL_I2CName; + +/*! + * @def CC1352P1_LAUNCHXL_NVSName + * @brief Enum of NVS names + */ +typedef enum CC1352P1_LAUNCHXL_NVSName { + CC1352P1_LAUNCHXL_NVSCC26XX0 = 0, + CC1352P1_LAUNCHXL_NVSSPI25X0, + + CC1352P1_LAUNCHXL_NVSCOUNT +} CC1352P1_LAUNCHXL_NVSName; + +/*! + * @def CC1352P1_LAUNCHXL_PWM + * @brief Enum of PWM outputs + */ +typedef enum CC1352P1_LAUNCHXL_PWMName { + CC1352P1_LAUNCHXL_PWM0 = 0, + CC1352P1_LAUNCHXL_PWM1, + CC1352P1_LAUNCHXL_PWM2, + CC1352P1_LAUNCHXL_PWM3, + CC1352P1_LAUNCHXL_PWM4, + CC1352P1_LAUNCHXL_PWM5, + CC1352P1_LAUNCHXL_PWM6, + CC1352P1_LAUNCHXL_PWM7, + + CC1352P1_LAUNCHXL_PWMCOUNT +} CC1352P1_LAUNCHXL_PWMName; + +/*! + * @def CC1352P1_LAUNCHXL_SDName + * @brief Enum of SD names + */ +typedef enum CC1352P1_LAUNCHXL_SDName { + CC1352P1_LAUNCHXL_SDSPI0 = 0, + + CC1352P1_LAUNCHXL_SDCOUNT +} CC1352P1_LAUNCHXL_SDName; + +/*! + * @def CC1352P1_LAUNCHXL_SPIName + * @brief Enum of SPI names + */ +typedef enum CC1352P1_LAUNCHXL_SPIName { + CC1352P1_LAUNCHXL_SPI0 = 0, + CC1352P1_LAUNCHXL_SPI1, + + CC1352P1_LAUNCHXL_SPICOUNT +} CC1352P1_LAUNCHXL_SPIName; + +/*! + * @def CC1352P1_LAUNCHXL_UARTName + * @brief Enum of UARTs + */ +typedef enum CC1352P1_LAUNCHXL_UARTName { + CC1352P1_LAUNCHXL_UART0 = 0, + CC1352P1_LAUNCHXL_UART1, + + CC1352P1_LAUNCHXL_UARTCOUNT +} CC1352P1_LAUNCHXL_UARTName; + +/*! + * @def CC1352P1_LAUNCHXL_UDMAName + * @brief Enum of DMA buffers + */ +typedef enum CC1352P1_LAUNCHXL_UDMAName { + CC1352P1_LAUNCHXL_UDMA0 = 0, + + CC1352P1_LAUNCHXL_UDMACOUNT +} CC1352P1_LAUNCHXL_UDMAName; + +/*! + * @def CC1352P1_LAUNCHXL_WatchdogName + * @brief Enum of Watchdogs + */ +typedef enum CC1352P1_LAUNCHXL_WatchdogName { + CC1352P1_LAUNCHXL_WATCHDOG0 = 0, + + CC1352P1_LAUNCHXL_WATCHDOGCOUNT +} CC1352P1_LAUNCHXL_WatchdogName; + + +#ifdef __cplusplus +} +#endif + +#endif /* __CC1352P1_LAUNCHXL_BOARD_H__ */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 new file mode 100644 index 000000000..cdbb5c3e8 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 @@ -0,0 +1,16 @@ +################################################################################ +# SimpleLink Device makefile + +SUBFAMILY = cc13x2-cc26x2 +DEVICE_FAMILY = CC13X2 + +BOARD_SOURCEFILES += CC1352P1_LAUNCHXL.c + +SUPPORTS_PROP_MODE = 1 +SUPPORTS_IEEE_MODE = 1 + +### Signal that we can be programmed with cc2538-bsl +BOARD_SUPPORTS_BSL = 0 + +# Include the common board makefile +include $(FAMILY_PATH)/launchpad/Makefile.launchpad diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h new file mode 100644 index 000000000..b9e9ce7cf --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2017-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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 __BOARD_H +#define __BOARD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "CC1352R1_LAUNCHXL.h" + +#define Board_initGeneral() CC1352R1_LAUNCHXL_initGeneral() +#define Board_shutDownExtFlash() CC1352R1_LAUNCHXL_shutDownExtFlash() +#define Board_wakeUpExtFlash() CC1352R1_LAUNCHXL_wakeUpExtFlash() + +/* These #defines allow us to reuse TI-RTOS across other device families */ + +#define Board_ADC0 CC1352R1_LAUNCHXL_ADC0 +#define Board_ADC1 CC1352R1_LAUNCHXL_ADC1 + +#define Board_ADCBUF0 CC1352R1_LAUNCHXL_ADCBUF0 +#define Board_ADCBUF0CHANNEL0 CC1352R1_LAUNCHXL_ADCBUF0CHANNEL0 +#define Board_ADCBUF0CHANNEL1 CC1352R1_LAUNCHXL_ADCBUF0CHANNEL1 + +#define Board_ECDH0 CC1352R1_LAUNCHXL_ECDH0 +#define Board_ECDSA0 CC1352R1_LAUNCHXL_ECDSA0 +#define Board_ECJPAKE0 CC1352R1_LAUNCHXL_ECJPAKE0 +#define Board_AESCCM0 CC1352R1_LAUNCHXL_AESCCM0 +#define Board_AESECB0 CC1352R1_LAUNCHXL_AESECB0 +#define Board_SHA20 CC1352R1_LAUNCHXL_SHA20 + +#define Board_DIO12 CC1352R1_LAUNCHXL_DIO12 +#define Board_DIO15 CC1352R1_LAUNCHXL_DIO15 +#define Board_DIO16_TDO CC1352R1_LAUNCHXL_DIO16_TDO +#define Board_DIO17_TDI CC1352R1_LAUNCHXL_DIO17_TDI +#define Board_DIO21 CC1352R1_LAUNCHXL_DIO21 +#define Board_DIO22 CC1352R1_LAUNCHXL_DIO22 + +#define Board_DIO23_ANALOG CC1352R1_LAUNCHXL_DIO23_ANALOG +#define Board_DIO24_ANALOG CC1352R1_LAUNCHXL_DIO24_ANALOG +#define Board_DIO25_ANALOG CC1352R1_LAUNCHXL_DIO25_ANALOG +#define Board_DIO26_ANALOG CC1352R1_LAUNCHXL_DIO26_ANALOG +#define Board_DIO27_ANALOG CC1352R1_LAUNCHXL_DIO27_ANALOG +#define Board_DIO28_ANALOG CC1352R1_LAUNCHXL_DIO28_ANALOG +#define Board_DIO29_ANALOG CC1352R1_LAUNCHXL_DIO29_ANALOG +#define Board_DIO30_RFSW CC1352R1_LAUNCHXL_DIO30_RF_SUB1GHZ + +#define Board_GPIO_BUTTON0 CC1352R1_LAUNCHXL_GPIO_S1 +#define Board_GPIO_BUTTON1 CC1352R1_LAUNCHXL_GPIO_S2 +#define Board_GPIO_BTN1 CC1352R1_LAUNCHXL_GPIO_S1 +#define Board_GPIO_BTN2 CC1352R1_LAUNCHXL_GPIO_S2 +#define Board_GPIO_LED0 CC1352R1_LAUNCHXL_GPIO_LED_RED +#define Board_GPIO_LED1 CC1352R1_LAUNCHXL_GPIO_LED_GREEN +#define Board_GPIO_LED2 CC1352R1_LAUNCHXL_GPIO_LED_RED +#define Board_GPIO_RLED CC1352R1_LAUNCHXL_GPIO_LED_RED +#define Board_GPIO_GLED CC1352R1_LAUNCHXL_GPIO_LED_GREEN +#define Board_GPIO_LED_ON CC1352R1_LAUNCHXL_GPIO_LED_ON +#define Board_GPIO_LED_OFF CC1352R1_LAUNCHXL_GPIO_LED_OFF + +#define Board_GPTIMER0A CC1352R1_LAUNCHXL_GPTIMER0A +#define Board_GPTIMER0B CC1352R1_LAUNCHXL_GPTIMER0B +#define Board_GPTIMER1A CC1352R1_LAUNCHXL_GPTIMER1A +#define Board_GPTIMER1B CC1352R1_LAUNCHXL_GPTIMER1B +#define Board_GPTIMER2A CC1352R1_LAUNCHXL_GPTIMER2A +#define Board_GPTIMER2B CC1352R1_LAUNCHXL_GPTIMER2B +#define Board_GPTIMER3A CC1352R1_LAUNCHXL_GPTIMER3A +#define Board_GPTIMER3B CC1352R1_LAUNCHXL_GPTIMER3B + +#define Board_I2C0 CC1352R1_LAUNCHXL_I2C0 +#define Board_I2C_TMP Board_I2C0 + +#define Board_NVSINTERNAL CC1352R1_LAUNCHXL_NVSCC26XX0 +#define Board_NVSEXTERNAL CC1352R1_LAUNCHXL_NVSSPI25X0 + +#define Board_PIN_BUTTON0 CC1352R1_LAUNCHXL_PIN_BTN1 +#define Board_PIN_BUTTON1 CC1352R1_LAUNCHXL_PIN_BTN2 +#define Board_PIN_BTN1 CC1352R1_LAUNCHXL_PIN_BTN1 +#define Board_PIN_BTN2 CC1352R1_LAUNCHXL_PIN_BTN2 +#define Board_PIN_LED0 CC1352R1_LAUNCHXL_PIN_RLED +#define Board_PIN_LED1 CC1352R1_LAUNCHXL_PIN_GLED +#define Board_PIN_LED2 CC1352R1_LAUNCHXL_PIN_RLED +#define Board_PIN_RLED CC1352R1_LAUNCHXL_PIN_RLED +#define Board_PIN_GLED CC1352R1_LAUNCHXL_PIN_GLED + +#define Board_PWM0 CC1352R1_LAUNCHXL_PWM0 +#define Board_PWM1 CC1352R1_LAUNCHXL_PWM1 +#define Board_PWM2 CC1352R1_LAUNCHXL_PWM2 +#define Board_PWM3 CC1352R1_LAUNCHXL_PWM3 +#define Board_PWM4 CC1352R1_LAUNCHXL_PWM4 +#define Board_PWM5 CC1352R1_LAUNCHXL_PWM5 +#define Board_PWM6 CC1352R1_LAUNCHXL_PWM6 +#define Board_PWM7 CC1352R1_LAUNCHXL_PWM7 + +#define Board_SD0 CC1352R1_LAUNCHXL_SDSPI0 + +#define Board_SPI0 CC1352R1_LAUNCHXL_SPI0 +#define Board_SPI1 CC1352R1_LAUNCHXL_SPI1 +#define Board_SPI_FLASH_CS CC1352R1_LAUNCHXL_SPI_FLASH_CS +#define Board_FLASH_CS_ON 0 +#define Board_FLASH_CS_OFF 1 + +#define Board_SPI_MASTER CC1352R1_LAUNCHXL_SPI0 +#define Board_SPI_SLAVE CC1352R1_LAUNCHXL_SPI0 +#define Board_SPI_MASTER_READY CC1352R1_LAUNCHXL_SPI_MASTER_READY +#define Board_SPI_SLAVE_READY CC1352R1_LAUNCHXL_SPI_SLAVE_READY + +#define Board_UART0 CC1352R1_LAUNCHXL_UART0 +#define Board_UART1 CC1352R1_LAUNCHXL_UART1 + +#define Board_WATCHDOG0 CC1352R1_LAUNCHXL_WATCHDOG0 + +/* Board specific I2C addresses */ +#define Board_TMP_ADDR (0x40) +#define Board_SENSORS_BP_TMP_ADDR Board_TMP_ADDR + +#ifdef __cplusplus +} +#endif + +#endif /* __BOARD_H */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c new file mode 100644 index 000000000..63547e44f --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c @@ -0,0 +1,1072 @@ +/* + * Copyright (c) 2017-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +/* + * ====================== CC1352R1_LAUNCHXL.c =================================== + * This file is responsible for setting up the board specific items for the + * CC1352R1_LAUNCHXL board. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "CC1352R1_LAUNCHXL.h" + +/* + * =============================== ADCBuf =============================== + */ +#include +#include + +ADCBufCC26X2_Object adcBufCC26xxObjects[CC1352R1_LAUNCHXL_ADCBUFCOUNT]; + +/* + * This table converts a virtual adc channel into a dio and internal analogue + * input signal. This table is necessary for the functioning of the adcBuf + * driver. Comment out unused entries to save flash. Dio and internal signal + * pairs are hardwired. Do not remap them in the table. You may reorder entire + * entries. The mapping of dio and internal signals is package dependent. + */ +const ADCBufCC26X2_AdcChannelLutEntry ADCBufCC26X2_adcChannelLut[CC1352R1_LAUNCHXL_ADCBUF0CHANNELCOUNT] = { + {CC1352R1_LAUNCHXL_DIO23_ANALOG, ADC_COMPB_IN_AUXIO7}, + {CC1352R1_LAUNCHXL_DIO24_ANALOG, ADC_COMPB_IN_AUXIO6}, + {CC1352R1_LAUNCHXL_DIO25_ANALOG, ADC_COMPB_IN_AUXIO5}, + {CC1352R1_LAUNCHXL_DIO26_ANALOG, ADC_COMPB_IN_AUXIO4}, + {CC1352R1_LAUNCHXL_DIO27_ANALOG, ADC_COMPB_IN_AUXIO3}, + {CC1352R1_LAUNCHXL_DIO28_ANALOG, ADC_COMPB_IN_AUXIO2}, + {CC1352R1_LAUNCHXL_DIO29_ANALOG, ADC_COMPB_IN_AUXIO1}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VDDS}, + {PIN_UNASSIGNED, ADC_COMPB_IN_DCOUPL}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VSS}, +}; + +const ADCBufCC26X2_HWAttrs adcBufCC26xxHWAttrs[CC1352R1_LAUNCHXL_ADCBUFCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + .adcChannelLut = ADCBufCC26X2_adcChannelLut, + .gpTimerUnit = CC1352R1_LAUNCHXL_GPTIMER0A, + } +}; + +const ADCBuf_Config ADCBuf_config[CC1352R1_LAUNCHXL_ADCBUFCOUNT] = { + { + &ADCBufCC26X2_fxnTable, + &adcBufCC26xxObjects[CC1352R1_LAUNCHXL_ADCBUF0], + &adcBufCC26xxHWAttrs[CC1352R1_LAUNCHXL_ADCBUF0] + }, +}; + +const uint_least8_t ADCBuf_count = CC1352R1_LAUNCHXL_ADCBUFCOUNT; + +/* + * =============================== ADC =============================== + */ +#include +#include + +ADCCC26XX_Object adcCC26xxObjects[CC1352R1_LAUNCHXL_ADCCOUNT]; + +const ADCCC26XX_HWAttrs adcCC26xxHWAttrs[CC1352R1_LAUNCHXL_ADCCOUNT] = { + { + .adcDIO = CC1352R1_LAUNCHXL_DIO23_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO7, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1352R1_LAUNCHXL_DIO24_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO6, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1352R1_LAUNCHXL_DIO25_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO5, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1352R1_LAUNCHXL_DIO26_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO4, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1352R1_LAUNCHXL_DIO27_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO3, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1352R1_LAUNCHXL_DIO28_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO2, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1352R1_LAUNCHXL_DIO29_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO1, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_DCOUPL, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VSS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VDDS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + } +}; + +const ADC_Config ADC_config[CC1352R1_LAUNCHXL_ADCCOUNT] = { + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352R1_LAUNCHXL_ADC0], &adcCC26xxHWAttrs[CC1352R1_LAUNCHXL_ADC0]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352R1_LAUNCHXL_ADC1], &adcCC26xxHWAttrs[CC1352R1_LAUNCHXL_ADC1]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352R1_LAUNCHXL_ADC2], &adcCC26xxHWAttrs[CC1352R1_LAUNCHXL_ADC2]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352R1_LAUNCHXL_ADC3], &adcCC26xxHWAttrs[CC1352R1_LAUNCHXL_ADC3]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352R1_LAUNCHXL_ADC4], &adcCC26xxHWAttrs[CC1352R1_LAUNCHXL_ADC4]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352R1_LAUNCHXL_ADC5], &adcCC26xxHWAttrs[CC1352R1_LAUNCHXL_ADC5]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352R1_LAUNCHXL_ADC6], &adcCC26xxHWAttrs[CC1352R1_LAUNCHXL_ADC6]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352R1_LAUNCHXL_ADCDCOUPL], &adcCC26xxHWAttrs[CC1352R1_LAUNCHXL_ADCDCOUPL]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352R1_LAUNCHXL_ADCVSS], &adcCC26xxHWAttrs[CC1352R1_LAUNCHXL_ADCVSS]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352R1_LAUNCHXL_ADCVDDS], &adcCC26xxHWAttrs[CC1352R1_LAUNCHXL_ADCVDDS]}, +}; + +const uint_least8_t ADC_count = CC1352R1_LAUNCHXL_ADCCOUNT; + +/* + * =============================== ECDH =============================== + */ +#include +#include + +ECDHCC26X2_Object ecdhCC26X2Objects[CC1352R1_LAUNCHXL_ECDHCOUNT]; + +const ECDHCC26X2_HWAttrs ecdhCC26X2HWAttrs[CC1352R1_LAUNCHXL_ECDHCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const ECDH_Config ECDH_config[CC1352R1_LAUNCHXL_ECDHCOUNT] = { + { + .object = &ecdhCC26X2Objects[CC1352R1_LAUNCHXL_ECDH0], + .hwAttrs = &ecdhCC26X2HWAttrs[CC1352R1_LAUNCHXL_ECDH0] + }, +}; + +const uint_least8_t ECDH_count = CC1352R1_LAUNCHXL_ECDHCOUNT; + +/* + * =============================== ECDSA =============================== + */ +#include +#include + +ECDSACC26X2_Object ecdsaCC26X2Objects[CC1352R1_LAUNCHXL_ECDSACOUNT]; + +const ECDSACC26X2_HWAttrs ecdsaCC26X2HWAttrs[CC1352R1_LAUNCHXL_ECDSACOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const ECDSA_Config ECDSA_config[CC1352R1_LAUNCHXL_ECDSACOUNT] = { + { + .object = &ecdsaCC26X2Objects[CC1352R1_LAUNCHXL_ECDSA0], + .hwAttrs = &ecdsaCC26X2HWAttrs[CC1352R1_LAUNCHXL_ECDSA0] + }, +}; + +const uint_least8_t ECDSA_count = CC1352R1_LAUNCHXL_ECDSACOUNT; + +/* + * =============================== ECJPAKE =============================== + */ +#include +#include + +ECJPAKECC26X2_Object ecjpakeCC26X2Objects[CC1352R1_LAUNCHXL_ECJPAKECOUNT]; + +const ECJPAKECC26X2_HWAttrs ecjpakeCC26X2HWAttrs[CC1352R1_LAUNCHXL_ECJPAKECOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const ECJPAKE_Config ECJPAKE_config[CC1352R1_LAUNCHXL_ECJPAKECOUNT] = { + { + .object = &ecjpakeCC26X2Objects[CC1352R1_LAUNCHXL_ECJPAKE0], + .hwAttrs = &ecjpakeCC26X2HWAttrs[CC1352R1_LAUNCHXL_ECJPAKE0] + }, +}; + +const uint_least8_t ECJPAKE_count = CC1352R1_LAUNCHXL_ECJPAKECOUNT; + + +/* + * =============================== SHA2 =============================== + */ +#include +#include + +SHA2CC26X2_Object sha2CC26X2Objects[CC1352R1_LAUNCHXL_SHA2COUNT]; + +const SHA2CC26X2_HWAttrs sha2CC26X2HWAttrs[CC1352R1_LAUNCHXL_SHA2COUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const SHA2_Config SHA2_config[CC1352R1_LAUNCHXL_SHA2COUNT] = { + { + .object = &sha2CC26X2Objects[CC1352R1_LAUNCHXL_SHA20], + .hwAttrs = &sha2CC26X2HWAttrs[CC1352R1_LAUNCHXL_SHA20] + }, +}; + +const uint_least8_t SHA2_count = CC1352R1_LAUNCHXL_SHA2COUNT; + +/* + * =============================== AESCCM =============================== + */ +#include +#include + +AESCCMCC26XX_Object aesccmCC26XXObjects[CC1352R1_LAUNCHXL_AESCCMCOUNT]; + +const AESCCMCC26XX_HWAttrs aesccmCC26XXHWAttrs[CC1352R1_LAUNCHXL_AESCCMCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const AESCCM_Config AESCCM_config[CC1352R1_LAUNCHXL_AESCCMCOUNT] = { + { + .object = &aesccmCC26XXObjects[CC1352R1_LAUNCHXL_AESCCM0], + .hwAttrs = &aesccmCC26XXHWAttrs[CC1352R1_LAUNCHXL_AESCCM0] + }, +}; + +const uint_least8_t AESCCM_count = CC1352R1_LAUNCHXL_AESCCMCOUNT; + +/* + * =============================== AESECB =============================== + */ +#include +#include + +AESECBCC26XX_Object aesecbCC26XXObjects[CC1352R1_LAUNCHXL_AESECBCOUNT]; + +const AESECBCC26XX_HWAttrs aesecbCC26XXHWAttrs[CC1352R1_LAUNCHXL_AESECBCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const AESECB_Config AESECB_config[CC1352R1_LAUNCHXL_AESECBCOUNT] = { + { + .object = &aesecbCC26XXObjects[CC1352R1_LAUNCHXL_AESECB0], + .hwAttrs = &aesecbCC26XXHWAttrs[CC1352R1_LAUNCHXL_AESECB0] + }, +}; + +const uint_least8_t AESECB_count = CC1352R1_LAUNCHXL_AESECBCOUNT; + +/* + * =============================== Display =============================== + */ +#include +#include +#include + +#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE +#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 +#endif + +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 +#endif + +DisplayUart_Object displayUartObject; +DisplaySharp_Object displaySharpObject; + +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; +static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; + +const DisplayUart_HWAttrs displayUartHWAttrs = { + .uartIdx = CC1352R1_LAUNCHXL_UART0, + .baudRate = 115200, + .mutexTimeout = (unsigned int)(-1), + .strBuf = uartStringBuf, + .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, +}; + +const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { + .spiIndex = CC1352R1_LAUNCHXL_SPI0, + .csPin = CC1352R1_LAUNCHXL_GPIO_LCD_CS, + .powerPin = CC1352R1_LAUNCHXL_GPIO_LCD_POWER, + .enablePin = CC1352R1_LAUNCHXL_GPIO_LCD_ENABLE, + .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, + .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, + .displayBuf = sharpDisplayBuf, +}; + +#ifndef BOARD_DISPLAY_USE_UART +#define BOARD_DISPLAY_USE_UART 1 +#endif +#ifndef BOARD_DISPLAY_USE_UART_ANSI +#define BOARD_DISPLAY_USE_UART_ANSI 0 +#endif +#ifndef BOARD_DISPLAY_USE_LCD +#define BOARD_DISPLAY_USE_LCD 0 +#endif + +/* + * This #if/#else is needed to workaround a problem with the + * IAR compiler. The IAR compiler doesn't like the empty array + * initialization. (IAR Error[Pe1345]) + */ +#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) + +const Display_Config Display_config[] = { +#if (BOARD_DISPLAY_USE_UART) + { +# if (BOARD_DISPLAY_USE_UART_ANSI) + .fxnTablePtr = &DisplayUartAnsi_fxnTable, +# else /* Default to minimal UART with no cursor placement */ + .fxnTablePtr = &DisplayUartMin_fxnTable, +# endif + .object = &displayUartObject, + .hwAttrs = &displayUartHWAttrs, + }, +#endif +#if (BOARD_DISPLAY_USE_LCD) + { + .fxnTablePtr = &DisplaySharp_fxnTable, + .object = &displaySharpObject, + .hwAttrs = &displaySharpHWattrs + }, +#endif +}; + +const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); + +#else + +const Display_Config *Display_config = NULL; +const uint_least8_t Display_count = 0; + +#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ + +/* + * =============================== GPIO =============================== + */ +#include +#include + +/* + * Array of Pin configurations + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC1352R1_LAUNCHXL.h + * NOTE: Pins not used for interrupts should be placed at the end of the + * array. Callback entries can be omitted from callbacks array to + * reduce memory usage. + */ +GPIO_PinConfig gpioPinConfigs[] = { + /* Input pins */ + GPIOCC26XX_DIO_15 | GPIO_DO_NOT_CONFIG, /* Button 0 */ + GPIOCC26XX_DIO_14 | GPIO_DO_NOT_CONFIG, /* Button 1 */ + + GPIOCC26XX_DIO_15 | GPIO_DO_NOT_CONFIG, /* CC1352R1_LAUNCHXL_SPI_MASTER_READY */ + GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG, /* CC1352R1_LAUNCHXL_SPI_SLAVE_READY */ + + /* Output pins */ + GPIOCC26XX_DIO_07 | GPIO_DO_NOT_CONFIG, /* Green LED */ + GPIOCC26XX_DIO_06 | GPIO_DO_NOT_CONFIG, /* Red LED */ + + /* SPI Flash CSN */ + GPIOCC26XX_DIO_20 | GPIO_DO_NOT_CONFIG, + + /* SD CS */ + GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG, + + /* Sharp Display - GPIO configurations will be done in the Display files */ + GPIOCC26XX_DIO_24 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ + GPIOCC26XX_DIO_22 | GPIO_DO_NOT_CONFIG, /* LCD power control */ + GPIOCC26XX_DIO_23 | GPIO_DO_NOT_CONFIG, /* LCD enable */ + +}; + +/* + * Array of callback function pointers + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC1352R1_LAUNCH.h + * NOTE: Pins not used for interrupts can be omitted from callbacks array to + * reduce memory usage (if placed at end of gpioPinConfigs array). + */ +GPIO_CallbackFxn gpioCallbackFunctions[] = { + NULL, /* Button 0 */ + NULL, /* Button 1 */ + NULL, /* CC1352R1_LAUNCHXL_SPI_MASTER_READY */ + NULL, /* CC1352R1_LAUNCHXL_SPI_SLAVE_READY */ +}; + +const GPIOCC26XX_Config GPIOCC26XX_config = { + .pinConfigs = (GPIO_PinConfig *)gpioPinConfigs, + .callbacks = (GPIO_CallbackFxn *)gpioCallbackFunctions, + .numberOfPinConfigs = CC1352R1_LAUNCHXL_GPIOCOUNT, + .numberOfCallbacks = sizeof(gpioCallbackFunctions)/sizeof(GPIO_CallbackFxn), + .intPriority = (~0) +}; + +/* + * =============================== GPTimer =============================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +#include + +GPTimerCC26XX_Object gptimerCC26XXObjects[CC1352R1_LAUNCHXL_GPTIMERCOUNT]; + +const GPTimerCC26XX_HWAttrs gptimerCC26xxHWAttrs[CC1352R1_LAUNCHXL_GPTIMERPARTSCOUNT] = { + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0A, }, + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0B, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1A, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1B, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2A, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2B, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3A, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3B, }, +}; + +const GPTimerCC26XX_Config GPTimerCC26XX_config[CC1352R1_LAUNCHXL_GPTIMERPARTSCOUNT] = { + { &gptimerCC26XXObjects[CC1352R1_LAUNCHXL_GPTIMER0], &gptimerCC26xxHWAttrs[CC1352R1_LAUNCHXL_GPTIMER0A], GPT_A }, + { &gptimerCC26XXObjects[CC1352R1_LAUNCHXL_GPTIMER0], &gptimerCC26xxHWAttrs[CC1352R1_LAUNCHXL_GPTIMER0B], GPT_B }, + { &gptimerCC26XXObjects[CC1352R1_LAUNCHXL_GPTIMER1], &gptimerCC26xxHWAttrs[CC1352R1_LAUNCHXL_GPTIMER1A], GPT_A }, + { &gptimerCC26XXObjects[CC1352R1_LAUNCHXL_GPTIMER1], &gptimerCC26xxHWAttrs[CC1352R1_LAUNCHXL_GPTIMER1B], GPT_B }, + { &gptimerCC26XXObjects[CC1352R1_LAUNCHXL_GPTIMER2], &gptimerCC26xxHWAttrs[CC1352R1_LAUNCHXL_GPTIMER2A], GPT_A }, + { &gptimerCC26XXObjects[CC1352R1_LAUNCHXL_GPTIMER2], &gptimerCC26xxHWAttrs[CC1352R1_LAUNCHXL_GPTIMER2B], GPT_B }, + { &gptimerCC26XXObjects[CC1352R1_LAUNCHXL_GPTIMER3], &gptimerCC26xxHWAttrs[CC1352R1_LAUNCHXL_GPTIMER3A], GPT_A }, + { &gptimerCC26XXObjects[CC1352R1_LAUNCHXL_GPTIMER3], &gptimerCC26xxHWAttrs[CC1352R1_LAUNCHXL_GPTIMER3B], GPT_B }, +}; + +/* + * =============================== I2C =============================== +*/ +#include +#include + +I2CCC26XX_Object i2cCC26xxObjects[CC1352R1_LAUNCHXL_I2CCOUNT]; + +const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1352R1_LAUNCHXL_I2CCOUNT] = { + { + .baseAddr = I2C0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_I2C0, + .intNum = INT_I2C_IRQ, + .intPriority = ~0, + .swiPriority = 0, + .sdaPin = CC1352R1_LAUNCHXL_I2C0_SDA0, + .sclPin = CC1352R1_LAUNCHXL_I2C0_SCL0, + } +}; + +const I2C_Config I2C_config[CC1352R1_LAUNCHXL_I2CCOUNT] = { + { + .fxnTablePtr = &I2CCC26XX_fxnTable, + .object = &i2cCC26xxObjects[CC1352R1_LAUNCHXL_I2C0], + .hwAttrs = &i2cCC26xxHWAttrs[CC1352R1_LAUNCHXL_I2C0] + }, +}; + +const uint_least8_t I2C_count = CC1352R1_LAUNCHXL_I2CCOUNT; + +/* + * =============================== NVS =============================== + */ +#include +#include +#include + +#define NVS_REGIONS_BASE 0x48000 +#define SECTORSIZE 0x2000 +#define REGIONSIZE (SECTORSIZE * 4) +#define SPISECTORSIZE 0x1000 +#define SPIREGIONSIZE (SPISECTORSIZE * 32) +#define VERIFYBUFSIZE 64 + +static uint8_t verifyBuf[VERIFYBUFSIZE]; + +/* + * Reserve flash sectors for NVS driver use by placing an uninitialized byte + * array at the desired flash address. + */ +#if defined(__TI_COMPILER_VERSION__) + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +#pragma LOCATION(flashBuf, NVS_REGIONS_BASE); +#pragma NOINIT(flashBuf); +static char flashBuf[REGIONSIZE]; + +#elif defined(__IAR_SYSTEMS_ICC__) + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +static __no_init char flashBuf[REGIONSIZE] @ NVS_REGIONS_BASE; + +#elif defined(__GNUC__) + +/* + * Place the flash buffers in the .nvs section created in the gcc linker file. + * The .nvs section enforces alignment on a sector boundary but may + * be placed anywhere in flash memory. If desired the .nvs section can be set + * to a fixed address by changing the following in the gcc linker file: + * + * .nvs (FIXED_FLASH_ADDR) (NOLOAD) : AT (FIXED_FLASH_ADDR) { + * *(.nvs) + * } > REGION_TEXT + */ +__attribute__ ((section (".nvs"))) +static char flashBuf[REGIONSIZE]; + +#endif + +/* Allocate objects for NVS and NVS SPI */ +NVSCC26XX_Object nvsCC26xxObjects[1]; +NVSSPI25X_Object nvsSPI25XObjects[1]; + +/* Hardware attributes for NVS */ +const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { + { + .regionBase = (void *)flashBuf, + .regionSize = REGIONSIZE, + }, +}; + +/* Hardware attributes for NVS SPI */ +const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { + { + .regionBaseOffset = 0, + .regionSize = SPIREGIONSIZE, + .sectorSize = SPISECTORSIZE, + .verifyBuf = verifyBuf, + .verifyBufSize = VERIFYBUFSIZE, + .spiHandle = NULL, + .spiIndex = 0, + .spiBitRate = 4000000, + .spiCsnGpioIndex = CC1352R1_LAUNCHXL_GPIO_SPI_FLASH_CS, + }, +}; + +/* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ +const NVS_Config NVS_config[CC1352R1_LAUNCHXL_NVSCOUNT] = { + { + .fxnTablePtr = &NVSCC26XX_fxnTable, + .object = &nvsCC26xxObjects[0], + .hwAttrs = &nvsCC26xxHWAttrs[0], + }, + { + .fxnTablePtr = &NVSSPI25X_fxnTable, + .object = &nvsSPI25XObjects[0], + .hwAttrs = &nvsSPI25XHWAttrs[0], + }, +}; + +const uint_least8_t NVS_count = CC1352R1_LAUNCHXL_NVSCOUNT; + +/* + * =============================== PIN =============================== + */ +#include +#include + +const PIN_Config BoardGpioInitTable[] = { + + CC1352R1_LAUNCHXL_PIN_RLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC1352R1_LAUNCHXL_PIN_GLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC1352R1_LAUNCHXL_PIN_BTN1 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC1352R1_LAUNCHXL_PIN_BTN2 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC1352R1_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ + CC1352R1_LAUNCHXL_UART0_RX | PIN_INPUT_EN | PIN_PULLDOWN, /* UART RX via debugger back channel */ + CC1352R1_LAUNCHXL_UART0_TX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* UART TX via debugger back channel */ + CC1352R1_LAUNCHXL_SPI0_MOSI | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master out - slave in */ + CC1352R1_LAUNCHXL_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master in - slave out */ + CC1352R1_LAUNCHXL_SPI0_CLK | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI clock */ + CC1352R1_LAUNCHXL_DIO30_RF_SUB1GHZ | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* RF SW Switch defaults to 2.4GHz path */ + PIN_TERMINATE +}; + +const PINCC26XX_HWAttrs PINCC26XX_hwAttrs = { + .intPriority = ~0, + .swiPriority = 0 +}; + +/* + * =============================== Power =============================== + */ +#include +#include + +const PowerCC26X2_Config PowerCC26X2_config = { + .policyInitFxn = NULL, + .policyFxn = &PowerCC26XX_standbyPolicy, + .calibrateFxn = &PowerCC26XX_calibrate, + .enablePolicy = true, + .calibrateRCOSC_LF = true, + .calibrateRCOSC_HF = true, +}; + +/* + * =============================== PWM =============================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +#include +#include + +PWMTimerCC26XX_Object pwmtimerCC26xxObjects[CC1352R1_LAUNCHXL_PWMCOUNT]; + +const PWMTimerCC26XX_HwAttrs pwmtimerCC26xxHWAttrs[CC1352R1_LAUNCHXL_PWMCOUNT] = { + { .pwmPin = CC1352R1_LAUNCHXL_PWMPIN0, .gpTimerUnit = CC1352R1_LAUNCHXL_GPTIMER0A }, + { .pwmPin = CC1352R1_LAUNCHXL_PWMPIN1, .gpTimerUnit = CC1352R1_LAUNCHXL_GPTIMER0B }, + { .pwmPin = CC1352R1_LAUNCHXL_PWMPIN2, .gpTimerUnit = CC1352R1_LAUNCHXL_GPTIMER1A }, + { .pwmPin = CC1352R1_LAUNCHXL_PWMPIN3, .gpTimerUnit = CC1352R1_LAUNCHXL_GPTIMER1B }, + { .pwmPin = CC1352R1_LAUNCHXL_PWMPIN4, .gpTimerUnit = CC1352R1_LAUNCHXL_GPTIMER2A }, + { .pwmPin = CC1352R1_LAUNCHXL_PWMPIN5, .gpTimerUnit = CC1352R1_LAUNCHXL_GPTIMER2B }, + { .pwmPin = CC1352R1_LAUNCHXL_PWMPIN6, .gpTimerUnit = CC1352R1_LAUNCHXL_GPTIMER3A }, + { .pwmPin = CC1352R1_LAUNCHXL_PWMPIN7, .gpTimerUnit = CC1352R1_LAUNCHXL_GPTIMER3B }, +}; + +const PWM_Config PWM_config[CC1352R1_LAUNCHXL_PWMCOUNT] = { + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352R1_LAUNCHXL_PWM0], &pwmtimerCC26xxHWAttrs[CC1352R1_LAUNCHXL_PWM0] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352R1_LAUNCHXL_PWM1], &pwmtimerCC26xxHWAttrs[CC1352R1_LAUNCHXL_PWM1] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352R1_LAUNCHXL_PWM2], &pwmtimerCC26xxHWAttrs[CC1352R1_LAUNCHXL_PWM2] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352R1_LAUNCHXL_PWM3], &pwmtimerCC26xxHWAttrs[CC1352R1_LAUNCHXL_PWM3] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352R1_LAUNCHXL_PWM4], &pwmtimerCC26xxHWAttrs[CC1352R1_LAUNCHXL_PWM4] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352R1_LAUNCHXL_PWM5], &pwmtimerCC26xxHWAttrs[CC1352R1_LAUNCHXL_PWM5] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352R1_LAUNCHXL_PWM6], &pwmtimerCC26xxHWAttrs[CC1352R1_LAUNCHXL_PWM6] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352R1_LAUNCHXL_PWM7], &pwmtimerCC26xxHWAttrs[CC1352R1_LAUNCHXL_PWM7] }, +}; + +const uint_least8_t PWM_count = CC1352R1_LAUNCHXL_PWMCOUNT; + +/* + * =============================== RF Driver =============================== + */ +#include + +/* + * Board-specific callback function to set the correct antenna path. + * + * This function is called by the RF driver on global driver events. It contains + * a default implementation to set the correct antenna path. + */ +static void CC1352R1_LAUNCHXL_rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void *arg); + +const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { + .hwiPriority = ~0, /* Lowest HWI priority */ + .swiPriority = 0, /* Lowest SWI priority */ + .xoscHfAlwaysNeeded = true, /* Keep XOSC dependency while in stanby */ + .globalCallback = &CC1352R1_LAUNCHXL_rfDriverCallback, /* Register the board specific callback */ + .globalEventMask = RF_GlobalEventRadioSetup | RF_GlobalEventRadioPowerDown /* Subscribe the callback to both events */ +}; + +/* + * =============================== SD =============================== + */ +#include +#include + +SDSPI_Object sdspiObjects[CC1352R1_LAUNCHXL_SDCOUNT]; + +const SDSPI_HWAttrs sdspiHWAttrs[CC1352R1_LAUNCHXL_SDCOUNT] = { + { + .spiIndex = CC1352R1_LAUNCHXL_SPI0, + .spiCsGpioIndex = CC1352R1_LAUNCHXL_SDSPI_CS + } +}; + +const SD_Config SD_config[CC1352R1_LAUNCHXL_SDCOUNT] = { + { + .fxnTablePtr = &SDSPI_fxnTable, + .object = &sdspiObjects[CC1352R1_LAUNCHXL_SDSPI0], + .hwAttrs = &sdspiHWAttrs[CC1352R1_LAUNCHXL_SDSPI0] + }, +}; + +const uint_least8_t SD_count = CC1352R1_LAUNCHXL_SDCOUNT; + +/* + * =============================== SPI DMA =============================== + */ +#include +#include + +SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1352R1_LAUNCHXL_SPICOUNT]; + +/* + * NOTE: The SPI instances below can be used by the SD driver to communicate + * with a SD card via SPI. The 'defaultTxBufValue' fields below are set to 0xFF + * to satisfy the SDSPI driver requirement. + */ +const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1352R1_LAUNCHXL_SPICOUNT] = { + { + .baseAddr = SSI0_BASE, + .intNum = INT_SSI0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .powerMngrId = PowerCC26XX_PERIPH_SSI0, + .defaultTxBufValue = 0xFF, + .rxChannelBitMask = 1< +#include + +UARTCC26XX_Object uartCC26XXObjects[CC1352R1_LAUNCHXL_UARTCOUNT]; + +uint8_t uartCC26XXRingBuffer[CC1352R1_LAUNCHXL_UARTCOUNT][32]; + +const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1352R1_LAUNCHXL_UARTCOUNT] = { + { + .baseAddr = UART0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UART0, + .intNum = INT_UART0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .txPin = CC1352R1_LAUNCHXL_UART0_TX, + .rxPin = CC1352R1_LAUNCHXL_UART0_RX, + .ctsPin = PIN_UNASSIGNED, + .rtsPin = PIN_UNASSIGNED, + .ringBufPtr = uartCC26XXRingBuffer[CC1352R1_LAUNCHXL_UART0], + .ringBufSize = sizeof(uartCC26XXRingBuffer[CC1352R1_LAUNCHXL_UART0]), + .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, + .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, + .errorFxn = NULL + }, + { + .baseAddr = UART1_BASE, + .powerMngrId = PowerCC26X2_PERIPH_UART1, + .intNum = INT_UART1_COMB, + .intPriority = ~0, + .swiPriority = 0, + .txPin = CC1352R1_LAUNCHXL_UART1_TX, + .rxPin = CC1352R1_LAUNCHXL_UART1_RX, + .ctsPin = PIN_UNASSIGNED, + .rtsPin = PIN_UNASSIGNED, + .ringBufPtr = uartCC26XXRingBuffer[CC1352R1_LAUNCHXL_UART1], + .ringBufSize = sizeof(uartCC26XXRingBuffer[CC1352R1_LAUNCHXL_UART1]), + .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, + .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, + .errorFxn = NULL + } +}; + +const UART_Config UART_config[CC1352R1_LAUNCHXL_UARTCOUNT] = { + { + .fxnTablePtr = &UARTCC26XX_fxnTable, + .object = &uartCC26XXObjects[CC1352R1_LAUNCHXL_UART0], + .hwAttrs = &uartCC26XXHWAttrs[CC1352R1_LAUNCHXL_UART0] + }, + { + .fxnTablePtr = &UARTCC26XX_fxnTable, + .object = &uartCC26XXObjects[CC1352R1_LAUNCHXL_UART1], + .hwAttrs = &uartCC26XXHWAttrs[CC1352R1_LAUNCHXL_UART1] + }, +}; + +const uint_least8_t UART_count = CC1352R1_LAUNCHXL_UARTCOUNT; + +/* + * =============================== UDMA =============================== + */ +#include + +UDMACC26XX_Object udmaObjects[CC1352R1_LAUNCHXL_UDMACOUNT]; + +const UDMACC26XX_HWAttrs udmaHWAttrs[CC1352R1_LAUNCHXL_UDMACOUNT] = { + { + .baseAddr = UDMA0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UDMA, + .intNum = INT_DMA_ERR, + .intPriority = ~0 + } +}; + +const UDMACC26XX_Config UDMACC26XX_config[CC1352R1_LAUNCHXL_UDMACOUNT] = { + { + .object = &udmaObjects[CC1352R1_LAUNCHXL_UDMA0], + .hwAttrs = &udmaHWAttrs[CC1352R1_LAUNCHXL_UDMA0] + }, +}; + + + +/* + * =============================== Watchdog =============================== + */ +#include +#include + +WatchdogCC26XX_Object watchdogCC26XXObjects[CC1352R1_LAUNCHXL_WATCHDOGCOUNT]; + +const WatchdogCC26XX_HWAttrs watchdogCC26XXHWAttrs[CC1352R1_LAUNCHXL_WATCHDOGCOUNT] = { + { + .baseAddr = WDT_BASE, + .reloadValue = 1000 /* Reload value in milliseconds */ + }, +}; + +const Watchdog_Config Watchdog_config[CC1352R1_LAUNCHXL_WATCHDOGCOUNT] = { + { + .fxnTablePtr = &WatchdogCC26XX_fxnTable, + .object = &watchdogCC26XXObjects[CC1352R1_LAUNCHXL_WATCHDOG0], + .hwAttrs = &watchdogCC26XXHWAttrs[CC1352R1_LAUNCHXL_WATCHDOG0] + }, +}; + +const uint_least8_t Watchdog_count = CC1352R1_LAUNCHXL_WATCHDOGCOUNT; + +/* + * ======== CC1352R1_LAUNCHXL_wakeUpExtFlash ======== + */ +void CC1352R1_LAUNCHXL_wakeUpExtFlash(void) +{ + PIN_Config extFlashPinTable[] = { + CC1352R1_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + /* + * To wake up we need to toggle the chip select at + * least 20 ns and ten wait at least 35 us. + */ + + /* Toggle chip select for ~20ns to wake ext. flash */ + PIN_setOutputValue(extFlashPinHandle, CC1352R1_LAUNCHXL_SPI_FLASH_CS, 0); + /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ + CPUdelay(1); + PIN_setOutputValue(extFlashPinHandle, CC1352R1_LAUNCHXL_SPI_FLASH_CS, 1); + /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ + CPUdelay(560); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC1352R1_LAUNCHXL_sendExtFlashByte ======== + */ +void CC1352R1_LAUNCHXL_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) +{ + uint8_t i; + + PIN_setOutputValue(pinHandle, CC1352R1_LAUNCHXL_SPI_FLASH_CS, 0); + + for (i = 0; i < 8; i++) { + PIN_setOutputValue(pinHandle, CC1352R1_LAUNCHXL_SPI0_CLK, 0); + PIN_setOutputValue(pinHandle, CC1352R1_LAUNCHXL_SPI0_MOSI, (byte >> (7 - i)) & 0x01); + PIN_setOutputValue(pinHandle, CC1352R1_LAUNCHXL_SPI0_CLK, 1); + + /* + * Waste a few cycles to keep the CLK high for at + * least 45% of the period. + * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. + */ + CPUdelay(8); + } + + PIN_setOutputValue(pinHandle, CC1352R1_LAUNCHXL_SPI0_CLK, 0); + PIN_setOutputValue(pinHandle, CC1352R1_LAUNCHXL_SPI_FLASH_CS, 1); + + /* + * Keep CS high at least 40 us + * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us + */ + CPUdelay(700); +} + +/* + * ======== CC1352R1_LAUNCHXL_shutDownExtFlash ======== + */ +void CC1352R1_LAUNCHXL_shutDownExtFlash(void) +{ + /* To be sure we are putting the flash into sleep and not waking it, we first have to make a wake up call */ + CC1352R1_LAUNCHXL_wakeUpExtFlash(); + + PIN_Config extFlashPinTable[] = { + CC1352R1_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + CC1352R1_LAUNCHXL_SPI0_CLK | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + CC1352R1_LAUNCHXL_SPI0_MOSI | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + CC1352R1_LAUNCHXL_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + uint8_t extFlashShutdown = 0xB9; + + CC1352R1_LAUNCHXL_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC1352R1_LAUNCHXL_initGeneral ======== + */ +void CC1352R1_LAUNCHXL_initGeneral(void) +{ + Power_init(); + + if (PIN_init(BoardGpioInitTable) != PIN_SUCCESS) { + /* Error with PIN_init */ + while (1); + } + + /* Shut down external flash as default */ + CC1352R1_LAUNCHXL_shutDownExtFlash(); +} + +/* + * ======== CC1352R1_LAUNCHXL_rfDriverCallback ======== + * This is an implementation for the CC1352R1 launchpad which uses a + * single signal for antenna switching. + */ +void CC1352R1_LAUNCHXL_rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void *arg) +{ + (void)client; + RF_RadioSetup* setupCommand = (RF_RadioSetup*)arg; + + if ((events & RF_GlobalEventRadioSetup) + && (setupCommand->common.commandNo == CMD_PROP_RADIO_DIV_SETUP)) { + /* Sub-1 GHz, requires antenna switch high */ + PINCC26XX_setOutputValue(CC1352R1_LAUNCHXL_DIO30_RF_SUB1GHZ, 1); + } else if (events & RF_GlobalEventRadioPowerDown) { + /* Disable antenna switch to save current */ + PINCC26XX_setOutputValue(CC1352R1_LAUNCHXL_DIO30_RF_SUB1GHZ, 0); + } +} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h new file mode 100644 index 000000000..104c36be2 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h @@ -0,0 +1,423 @@ +/* + * Copyright (c) 2017-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ +/** =========================================================================== + * @file CC1352R1_LAUNCHXL.h + * + * @brief CC1352R1_LAUNCHXL Board Specific header file. + * + * The CC1352R1_LAUNCHXL header file should be included in an application as + * follows: + * @code + * #include "CC1352R1_LAUNCHXL.h" + * @endcode + * + * =========================================================================== + */ +#ifndef __CC1352R1_LAUNCHXL_BOARD_H__ +#define __CC1352R1_LAUNCHXL_BOARD_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes */ +#include +#include + +/* Externs */ +extern const PIN_Config BoardGpioInitTable[]; + +/* Defines */ +#define CC1352R1_LAUNCHXL + +/* Mapping of pins to board signals using general board aliases + * + */ + +/* Mapping of pins to board signals using general board aliases + * + */ +/* Analog Capable DIOs */ +#define CC1352R1_LAUNCHXL_DIO23_ANALOG IOID_23 +#define CC1352R1_LAUNCHXL_DIO24_ANALOG IOID_24 +#define CC1352R1_LAUNCHXL_DIO25_ANALOG IOID_25 +#define CC1352R1_LAUNCHXL_DIO26_ANALOG IOID_26 +#define CC1352R1_LAUNCHXL_DIO27_ANALOG IOID_27 +#define CC1352R1_LAUNCHXL_DIO28_ANALOG IOID_28 +#define CC1352R1_LAUNCHXL_DIO29_ANALOG IOID_29 + +/* Antenna switch */ +#define CC1352R1_LAUNCHXL_DIO30_RF_SUB1GHZ IOID_30 + +/* Digital IOs */ +#define CC1352R1_LAUNCHXL_DIO12 IOID_12 +#define CC1352R1_LAUNCHXL_DIO15 IOID_15 +#define CC1352R1_LAUNCHXL_DIO16_TDO IOID_16 +#define CC1352R1_LAUNCHXL_DIO17_TDI IOID_17 +#define CC1352R1_LAUNCHXL_DIO21 IOID_21 +#define CC1352R1_LAUNCHXL_DIO22 IOID_22 + +/* Discrete Inputs */ +#define CC1352R1_LAUNCHXL_PIN_BTN1 IOID_15 +#define CC1352R1_LAUNCHXL_PIN_BTN2 IOID_14 + +/* GPIO */ +#define CC1352R1_LAUNCHXL_GPIO_LED_ON 1 +#define CC1352R1_LAUNCHXL_GPIO_LED_OFF 0 + +/* I2C */ +#define CC1352R1_LAUNCHXL_I2C0_SCL0 IOID_4 +#define CC1352R1_LAUNCHXL_I2C0_SDA0 IOID_5 + + +/* LEDs */ +#define CC1352R1_LAUNCHXL_PIN_LED_ON 1 +#define CC1352R1_LAUNCHXL_PIN_LED_OFF 0 +#define CC1352R1_LAUNCHXL_PIN_RLED IOID_6 +#define CC1352R1_LAUNCHXL_PIN_GLED IOID_7 + +/* PWM Outputs */ +#define CC1352R1_LAUNCHXL_PWMPIN0 CC1352R1_LAUNCHXL_PIN_RLED +#define CC1352R1_LAUNCHXL_PWMPIN1 CC1352R1_LAUNCHXL_PIN_GLED +#define CC1352R1_LAUNCHXL_PWMPIN2 PIN_UNASSIGNED +#define CC1352R1_LAUNCHXL_PWMPIN3 PIN_UNASSIGNED +#define CC1352R1_LAUNCHXL_PWMPIN4 PIN_UNASSIGNED +#define CC1352R1_LAUNCHXL_PWMPIN5 PIN_UNASSIGNED +#define CC1352R1_LAUNCHXL_PWMPIN6 PIN_UNASSIGNED +#define CC1352R1_LAUNCHXL_PWMPIN7 PIN_UNASSIGNED + +/* SPI */ +#define CC1352R1_LAUNCHXL_SPI_FLASH_CS IOID_20 +#define CC1352R1_LAUNCHXL_FLASH_CS_ON 0 +#define CC1352R1_LAUNCHXL_FLASH_CS_OFF 1 + +/* SPI Board */ +#define CC1352R1_LAUNCHXL_SPI0_MISO IOID_8 /* RF1.20 */ +#define CC1352R1_LAUNCHXL_SPI0_MOSI IOID_9 /* RF1.18 */ +#define CC1352R1_LAUNCHXL_SPI0_CLK IOID_10 /* RF1.16 */ +#define CC1352R1_LAUNCHXL_SPI0_CSN PIN_UNASSIGNED +#define CC1352R1_LAUNCHXL_SPI1_MISO PIN_UNASSIGNED +#define CC1352R1_LAUNCHXL_SPI1_MOSI PIN_UNASSIGNED +#define CC1352R1_LAUNCHXL_SPI1_CLK PIN_UNASSIGNED +#define CC1352R1_LAUNCHXL_SPI1_CSN PIN_UNASSIGNED + +/* UART Board */ +#define CC1352R1_LAUNCHXL_UART0_RX IOID_12 /* RXD */ +#define CC1352R1_LAUNCHXL_UART0_TX IOID_13 /* TXD */ +#define CC1352R1_LAUNCHXL_UART0_CTS IOID_19 /* CTS */ +#define CC1352R1_LAUNCHXL_UART0_RTS IOID_18 /* RTS */ +#define CC1352R1_LAUNCHXL_UART1_RX PIN_UNASSIGNED +#define CC1352R1_LAUNCHXL_UART1_TX PIN_UNASSIGNED +#define CC1352R1_LAUNCHXL_UART1_CTS PIN_UNASSIGNED +#define CC1352R1_LAUNCHXL_UART1_RTS PIN_UNASSIGNED +/* For backward compatibility */ +#define CC1352R1_LAUNCHXL_UART_RX CC1352R1_LAUNCHXL_UART0_RX +#define CC1352R1_LAUNCHXL_UART_TX CC1352R1_LAUNCHXL_UART0_TX +#define CC1352R1_LAUNCHXL_UART_CTS CC1352R1_LAUNCHXL_UART0_CTS +#define CC1352R1_LAUNCHXL_UART_RTS CC1352R1_LAUNCHXL_UART0_RTS + +/*! + * @brief Initialize the general board specific settings + * + * This function initializes the general board specific settings. + */ +void CC1352R1_LAUNCHXL_initGeneral(void); + +/*! + * @brief Shut down the external flash present on the board files + * + * This function bitbangs the SPI sequence necessary to turn off + * the external flash on LaunchPads. + */ +void CC1352R1_LAUNCHXL_shutDownExtFlash(void); + +/*! + * @brief Wake up the external flash present on the board files + * + * This function toggles the chip select for the amount of time needed + * to wake the chip up. + */ +void CC1352R1_LAUNCHXL_wakeUpExtFlash(void); + +/*! + * @def CC1352R1_LAUNCHXL_ADCBufName + * @brief Enum of ADCs + */ +typedef enum CC1352R1_LAUNCHXL_ADCBufName { + CC1352R1_LAUNCHXL_ADCBUF0 = 0, + + CC1352R1_LAUNCHXL_ADCBUFCOUNT +} CC1352R1_LAUNCHXL_ADCBufName; + +/*! + * @def CC1352R1_LAUNCHXL_ADCBuf0SourceName + * @brief Enum of ADCBuf channels + */ +typedef enum CC1352R1_LAUNCHXL_ADCBuf0ChannelName { + CC1352R1_LAUNCHXL_ADCBUF0CHANNEL0 = 0, + CC1352R1_LAUNCHXL_ADCBUF0CHANNEL1, + CC1352R1_LAUNCHXL_ADCBUF0CHANNEL2, + CC1352R1_LAUNCHXL_ADCBUF0CHANNEL3, + CC1352R1_LAUNCHXL_ADCBUF0CHANNEL4, + CC1352R1_LAUNCHXL_ADCBUF0CHANNEL5, + CC1352R1_LAUNCHXL_ADCBUF0CHANNEL6, + CC1352R1_LAUNCHXL_ADCBUF0CHANNELVDDS, + CC1352R1_LAUNCHXL_ADCBUF0CHANNELDCOUPL, + CC1352R1_LAUNCHXL_ADCBUF0CHANNELVSS, + + CC1352R1_LAUNCHXL_ADCBUF0CHANNELCOUNT +} CC1352R1_LAUNCHXL_ADCBuf0ChannelName; + +/*! + * @def CC1352R1_LAUNCHXL_ADCName + * @brief Enum of ADCs + */ +typedef enum CC1352R1_LAUNCHXL_ADCName { + CC1352R1_LAUNCHXL_ADC0 = 0, + CC1352R1_LAUNCHXL_ADC1, + CC1352R1_LAUNCHXL_ADC2, + CC1352R1_LAUNCHXL_ADC3, + CC1352R1_LAUNCHXL_ADC4, + CC1352R1_LAUNCHXL_ADC5, + CC1352R1_LAUNCHXL_ADC6, + CC1352R1_LAUNCHXL_ADCDCOUPL, + CC1352R1_LAUNCHXL_ADCVSS, + CC1352R1_LAUNCHXL_ADCVDDS, + + CC1352R1_LAUNCHXL_ADCCOUNT +} CC1352R1_LAUNCHXL_ADCName; + +/*! + * @def CC1352R1_LAUNCHXL_ECDHName + * @brief Enum of ECDH names + */ +typedef enum CC1352R1_LAUNCHXL_ECDHName { + CC1352R1_LAUNCHXL_ECDH0 = 0, + + CC1352R1_LAUNCHXL_ECDHCOUNT +} CC1352R1_LAUNCHXL_ECDHName; + +/*! + * @def CC1352R1_LAUNCHXL_ECDSAName + * @brief Enum of ECDSA names + */ +typedef enum CC1352R1_LAUNCHXL_ECDSAName { + CC1352R1_LAUNCHXL_ECDSA0 = 0, + + CC1352R1_LAUNCHXL_ECDSACOUNT +} CC1352R1_LAUNCHXL_ECDSAName; + +/*! + * @def CC1352R1_LAUNCHXL_ECJPAKEName + * @brief Enum of ECJPAKE names + */ +typedef enum CC1352R1_LAUNCHXL_ECJPAKEName { + CC1352R1_LAUNCHXL_ECJPAKE0 = 0, + + CC1352R1_LAUNCHXL_ECJPAKECOUNT +} CC1352R1_LAUNCHXL_ECJPAKEName; + +/*! + * @def CC1352R1_LAUNCHXL_AESCCMName + * @brief Enum of AESCCM names + */ +typedef enum CC1352R1_LAUNCHXL_AESCCMName { + CC1352R1_LAUNCHXL_AESCCM0 = 0, + + CC1352R1_LAUNCHXL_AESCCMCOUNT +} CC1352R1_LAUNCHXL_AESCCMName; + +/*! + * @def CC1352R1_LAUNCHXL_AESECBName + * @brief Enum of AESECB names + */ +typedef enum CC1352R1_LAUNCHXL_AESECBName { + CC1352R1_LAUNCHXL_AESECB0 = 0, + + CC1352R1_LAUNCHXL_AESECBCOUNT +} CC1352R1_LAUNCHXL_AESECBName; + +/*! + * @def CC1352R1_LAUNCHXL_SHA2Name + * @brief Enum of SHA2 names + */ +typedef enum CC1352R1_LAUNCHXL_SHA2Name { + CC1352R1_LAUNCHXL_SHA20 = 0, + + CC1352R1_LAUNCHXL_SHA2COUNT +} CC1352R1_LAUNCHXL_SHA2Name; + +/*! + * @def CC1352R1_LAUNCHXL_GPIOName + * @brief Enum of GPIO names + */ +typedef enum CC1352R1_LAUNCHXL_GPIOName { + CC1352R1_LAUNCHXL_GPIO_S1 = 0, + CC1352R1_LAUNCHXL_GPIO_S2, + CC1352R1_LAUNCHXL_SPI_MASTER_READY, + CC1352R1_LAUNCHXL_SPI_SLAVE_READY, + CC1352R1_LAUNCHXL_GPIO_LED_GREEN, + CC1352R1_LAUNCHXL_GPIO_LED_RED, + CC1352R1_LAUNCHXL_GPIO_SPI_FLASH_CS, + CC1352R1_LAUNCHXL_SDSPI_CS, + CC1352R1_LAUNCHXL_GPIO_LCD_CS, + CC1352R1_LAUNCHXL_GPIO_LCD_POWER, + CC1352R1_LAUNCHXL_GPIO_LCD_ENABLE, + CC1352R1_LAUNCHXL_GPIOCOUNT +} CC1352R1_LAUNCHXL_GPIOName; + +/*! + * @def CC1352R1_LAUNCHXL_GPTimerName + * @brief Enum of GPTimer parts + */ +typedef enum CC1352R1_LAUNCHXL_GPTimerName { + CC1352R1_LAUNCHXL_GPTIMER0A = 0, + CC1352R1_LAUNCHXL_GPTIMER0B, + CC1352R1_LAUNCHXL_GPTIMER1A, + CC1352R1_LAUNCHXL_GPTIMER1B, + CC1352R1_LAUNCHXL_GPTIMER2A, + CC1352R1_LAUNCHXL_GPTIMER2B, + CC1352R1_LAUNCHXL_GPTIMER3A, + CC1352R1_LAUNCHXL_GPTIMER3B, + + CC1352R1_LAUNCHXL_GPTIMERPARTSCOUNT +} CC1352R1_LAUNCHXL_GPTimerName; + +/*! + * @def CC1352R1_LAUNCHXL_GPTimers + * @brief Enum of GPTimers + */ +typedef enum CC1352R1_LAUNCHXL_GPTimers { + CC1352R1_LAUNCHXL_GPTIMER0 = 0, + CC1352R1_LAUNCHXL_GPTIMER1, + CC1352R1_LAUNCHXL_GPTIMER2, + CC1352R1_LAUNCHXL_GPTIMER3, + + CC1352R1_LAUNCHXL_GPTIMERCOUNT +} CC1352R1_LAUNCHXL_GPTimers; + +/*! + * @def CC1352R1_LAUNCHXL_I2CName + * @brief Enum of I2C names + */ +typedef enum CC1352R1_LAUNCHXL_I2CName { + CC1352R1_LAUNCHXL_I2C0 = 0, + + CC1352R1_LAUNCHXL_I2CCOUNT +} CC1352R1_LAUNCHXL_I2CName; + +/*! + * @def CC1352R1_LAUNCHXL_NVSName + * @brief Enum of NVS names + */ +typedef enum CC1352R1_LAUNCHXL_NVSName { + CC1352R1_LAUNCHXL_NVSCC26XX0 = 0, + CC1352R1_LAUNCHXL_NVSSPI25X0, + + CC1352R1_LAUNCHXL_NVSCOUNT +} CC1352R1_LAUNCHXL_NVSName; + +/*! + * @def CC1352R1_LAUNCHXL_PWM + * @brief Enum of PWM outputs + */ +typedef enum CC1352R1_LAUNCHXL_PWMName { + CC1352R1_LAUNCHXL_PWM0 = 0, + CC1352R1_LAUNCHXL_PWM1, + CC1352R1_LAUNCHXL_PWM2, + CC1352R1_LAUNCHXL_PWM3, + CC1352R1_LAUNCHXL_PWM4, + CC1352R1_LAUNCHXL_PWM5, + CC1352R1_LAUNCHXL_PWM6, + CC1352R1_LAUNCHXL_PWM7, + + CC1352R1_LAUNCHXL_PWMCOUNT +} CC1352R1_LAUNCHXL_PWMName; + +/*! + * @def CC1352R1_LAUNCHXL_SDName + * @brief Enum of SD names + */ +typedef enum CC1352R1_LAUNCHXL_SDName { + CC1352R1_LAUNCHXL_SDSPI0 = 0, + + CC1352R1_LAUNCHXL_SDCOUNT +} CC1352R1_LAUNCHXL_SDName; + +/*! + * @def CC1352R1_LAUNCHXL_SPIName + * @brief Enum of SPI names + */ +typedef enum CC1352R1_LAUNCHXL_SPIName { + CC1352R1_LAUNCHXL_SPI0 = 0, + CC1352R1_LAUNCHXL_SPI1, + + CC1352R1_LAUNCHXL_SPICOUNT +} CC1352R1_LAUNCHXL_SPIName; + +/*! + * @def CC1352R1_LAUNCHXL_UARTName + * @brief Enum of UARTs + */ +typedef enum CC1352R1_LAUNCHXL_UARTName { + CC1352R1_LAUNCHXL_UART0 = 0, + CC1352R1_LAUNCHXL_UART1, + + CC1352R1_LAUNCHXL_UARTCOUNT +} CC1352R1_LAUNCHXL_UARTName; + +/*! + * @def CC1352R1_LAUNCHXL_UDMAName + * @brief Enum of DMA buffers + */ +typedef enum CC1352R1_LAUNCHXL_UDMAName { + CC1352R1_LAUNCHXL_UDMA0 = 0, + + CC1352R1_LAUNCHXL_UDMACOUNT +} CC1352R1_LAUNCHXL_UDMAName; + +/*! + * @def CC1352R1_LAUNCHXL_WatchdogName + * @brief Enum of Watchdogs + */ +typedef enum CC1352R1_LAUNCHXL_WatchdogName { + CC1352R1_LAUNCHXL_WATCHDOG0 = 0, + + CC1352R1_LAUNCHXL_WATCHDOGCOUNT +} CC1352R1_LAUNCHXL_WatchdogName; + + +#ifdef __cplusplus +} +#endif + +#endif /* __CC1352R1_LAUNCHXL_BOARD_H__ */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 new file mode 100644 index 000000000..6a38d4b40 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 @@ -0,0 +1,16 @@ +################################################################################ +# SimpleLink Device makefile + +SUBFAMILY = cc13x2-cc26x2 +DEVICE_FAMILY = CC13X2 + +BOARD_SOURCEFILES += CC1352R1_LAUNCHXL.c + +SUPPORTS_PROP_MODE = 1 +SUPPORTS_IEEE_MODE = 1 + +### Signal that we can be programmed with cc2538-bsl +BOARD_SUPPORTS_BSL = 0 + +# Include the common board makefile +include $(FAMILY_PATH)/launchpad/Makefile.launchpad diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Board.h new file mode 100644 index 000000000..be7b817db --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Board.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2015-2016, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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 __BOARD_H +#define __BOARD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "CC2650_LAUNCHXL.h" + +/* These #defines allow us to reuse TI-RTOS across other device families */ +#define Board_LED0 Board_RLED +#define Board_LED1 Board_GLED +#define Board_LED2 Board_LED0 + +#define Board_BUTTON0 Board_BTN1 +#define Board_BUTTON1 Board_BTN2 + +#define Board_UART0 Board_UART +#define Board_AES0 Board_AES +#define Board_WATCHDOG0 CC2650_LAUNCHXL_WATCHDOG0 + +#define Board_ADC0 CC2650_LAUNCHXL_ADCVSS +#define Board_ADC1 CC2650_LAUNCHXL_ADCVDDS + +#define Board_ADCBuf0 CC2650_LAUNCHXL_ADCBuf0 +#define Board_ADCBufChannel0 (0) +#define Board_ADCBufChannel1 (1) + +#define Board_initGeneral() { \ + Power_init(); \ + if (PIN_init(BoardGpioInitTable) != PIN_SUCCESS) \ + {System_abort("Error with PIN_init\n"); \ + } \ +} + +#define Board_initGPIO() +#define Board_initPWM() PWM_init() +#define Board_initSPI() SPI_init() +#define Board_initUART() UART_init() +#define Board_initWatchdog() Watchdog_init() +#define Board_initADCBuf() ADCBuf_init() +#define Board_initADC() ADC_init() +#define GPIO_toggle(n) +#define GPIO_write(n,m) + +#ifdef __cplusplus +} +#endif + +#endif /* __BOARD_H */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.c new file mode 100644 index 000000000..3571cca94 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.c @@ -0,0 +1,752 @@ +/* + * Copyright (c) 2016, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +/* + * ====================== CC2650_LAUNCHXL.c =================================== + * This file is responsible for setting up the board specific items for the + * CC2650 LaunchPad. + */ + + +/* + * ====================== Includes ============================================ + */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/* + * ========================= IO driver initialization ========================= + * From main, PIN_init(BoardGpioInitTable) should be called to setup safe + * settings for this board. + * When a pin is allocated and then de-allocated, it will revert to the state + * configured in this table. + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(BoardGpioInitTable, ".const:BoardGpioInitTable") +#pragma DATA_SECTION(PINCC26XX_hwAttrs, ".const:PINCC26XX_hwAttrs") +#endif + +const PIN_Config BoardGpioInitTable[] = { + + Board_RLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + Board_GLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + Board_BTN1 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + Board_BTN2 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + Board_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ + Board_UART_RX | PIN_INPUT_EN | PIN_PULLDOWN, /* UART RX via debugger back channel */ + Board_UART_TX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* UART TX via debugger back channel */ + Board_SPI0_MOSI | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master out - slave in */ + Board_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master in - slave out */ + Board_SPI0_CLK | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI clock */ + + PIN_TERMINATE +}; + +const PINCC26XX_HWAttrs PINCC26XX_hwAttrs = { + .intPriority = ~0, + .swiPriority = 0 +}; +/*============================================================================*/ + +/* + * ============================= Power begin ================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(PowerCC26XX_config, ".const:PowerCC26XX_config") +#endif +const PowerCC26XX_Config PowerCC26XX_config = { + .policyInitFxn = NULL, + .policyFxn = &PowerCC26XX_standbyPolicy, + .calibrateFxn = &PowerCC26XX_calibrate, + .enablePolicy = TRUE, + .calibrateRCOSC_LF = TRUE, + .calibrateRCOSC_HF = TRUE, +}; +/* + * ============================= Power end ==================================== + */ + +/* + * ============================= UART begin =================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(UART_config, ".const:UART_config") +#pragma DATA_SECTION(uartCC26XXHWAttrs, ".const:uartCC26XXHWAttrs") +#endif + +/* Include drivers */ +#include +#include + +/* UART objects */ +UARTCC26XX_Object uartCC26XXObjects[CC2650_LAUNCHXL_UARTCOUNT]; +unsigned char uartCC26XXRingBuffer[CC2650_LAUNCHXL_UARTCOUNT][32]; + +/* UART hardware parameter structure, also used to assign UART pins */ +const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC2650_LAUNCHXL_UARTCOUNT] = { + { + .baseAddr = UART0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UART0, + .intNum = INT_UART0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .txPin = Board_UART_TX, + .rxPin = Board_UART_RX, + .ctsPin = PIN_UNASSIGNED, + .rtsPin = PIN_UNASSIGNED, + .ringBufPtr = uartCC26XXRingBuffer[0], + .ringBufSize = sizeof(uartCC26XXRingBuffer[0]) + } +}; + +/* UART configuration structure */ +const UART_Config UART_config[] = { + { + .fxnTablePtr = &UARTCC26XX_fxnTable, + .object = &uartCC26XXObjects[0], + .hwAttrs = &uartCC26XXHWAttrs[0] + }, + {NULL, NULL, NULL} +}; +/* + * ============================= UART end ===================================== + */ + +/* + * ============================= UDMA begin =================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(UDMACC26XX_config, ".const:UDMACC26XX_config") +#pragma DATA_SECTION(udmaHWAttrs, ".const:udmaHWAttrs") +#endif + +/* Include drivers */ +#include + +/* UDMA objects */ +UDMACC26XX_Object udmaObjects[CC2650_LAUNCHXL_UDMACOUNT]; + +/* UDMA configuration structure */ +const UDMACC26XX_HWAttrs udmaHWAttrs[CC2650_LAUNCHXL_UDMACOUNT] = { + { + .baseAddr = UDMA0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UDMA, + .intNum = INT_DMA_ERR, + .intPriority = ~0 + } +}; + +/* UDMA configuration structure */ +const UDMACC26XX_Config UDMACC26XX_config[] = { + { + .object = &udmaObjects[0], + .hwAttrs = &udmaHWAttrs[0] + }, + {NULL, NULL} +}; +/* + * ============================= UDMA end ===================================== + */ + +/* + * ========================== SPI DMA begin =================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(SPI_config, ".const:SPI_config") +#pragma DATA_SECTION(spiCC26XXDMAHWAttrs, ".const:spiCC26XXDMAHWAttrs") +#endif + +/* Include drivers */ +#include + +/* SPI objects */ +SPICC26XXDMA_Object spiCC26XXDMAObjects[CC2650_LAUNCHXL_SPICOUNT]; + +/* SPI configuration structure, describing which pins are to be used */ +const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC2650_LAUNCHXL_SPICOUNT] = { + { + .baseAddr = SSI0_BASE, + .intNum = INT_SSI0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .powerMngrId = PowerCC26XX_PERIPH_SSI0, + .defaultTxBufValue = 0, + .rxChannelBitMask = 1< + +/* I2C objects */ +I2CCC26XX_Object i2cCC26xxObjects[CC2650_LAUNCHXL_I2CCOUNT]; + +/* I2C configuration structure, describing which pins are to be used */ +const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC2650_LAUNCHXL_I2CCOUNT] = { + { + .baseAddr = I2C0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_I2C0, + .intNum = INT_I2C_IRQ, + .intPriority = ~0, + .swiPriority = 0, + .sdaPin = Board_I2C0_SDA0, + .sclPin = Board_I2C0_SCL0, + } +}; + +/* I2C configuration structure */ +const I2C_Config I2C_config[] = { + { + .fxnTablePtr = &I2CCC26XX_fxnTable, + .object = &i2cCC26xxObjects[0], + .hwAttrs = &i2cCC26xxHWAttrs[0] + }, + {NULL, NULL, NULL} +}; +/* + * ========================== I2C end ========================================= + */ + +/* + * ========================== Crypto begin ==================================== + * NOTE: The Crypto implementation should be considered experimental + * and not validated! + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(CryptoCC26XX_config, ".const:CryptoCC26XX_config") +#pragma DATA_SECTION(cryptoCC26XXHWAttrs, ".const:cryptoCC26XXHWAttrs") +#endif + +/* Include drivers */ +#include + +/* Crypto objects */ +CryptoCC26XX_Object cryptoCC26XXObjects[CC2650_LAUNCHXL_CRYPTOCOUNT]; + +/* Crypto configuration structure, describing which pins are to be used */ +const CryptoCC26XX_HWAttrs cryptoCC26XXHWAttrs[CC2650_LAUNCHXL_CRYPTOCOUNT] = { + { + .baseAddr = CRYPTO_BASE, + .powerMngrId = PowerCC26XX_PERIPH_CRYPTO, + .intNum = INT_CRYPTO_RESULT_AVAIL_IRQ, + .intPriority = ~0, + } +}; + +/* Crypto configuration structure */ +const CryptoCC26XX_Config CryptoCC26XX_config[] = { + { + .object = &cryptoCC26XXObjects[0], + .hwAttrs = &cryptoCC26XXHWAttrs[0] + }, + {NULL, NULL} +}; +/* + * ========================== Crypto end ====================================== + */ + + +/* + * ========================= RF driver begin ================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(RFCC26XX_hwAttrs, ".const:RFCC26XX_hwAttrs") +#endif + +/* Include drivers */ +#include + +/* RF hwi and swi priority */ +const RFCC26XX_HWAttrs RFCC26XX_hwAttrs = { + .hwiCpe0Priority = ~0, + .hwiHwPriority = ~0, + .swiCpe0Priority = 0, + .swiHwPriority = 0, +}; + +/* + * ========================== RF driver end =================================== + */ + +/* + * ========================= Display begin ==================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(Display_config, ".const:Display_config") +#pragma DATA_SECTION(displaySharpHWattrs, ".const:displaySharpHWattrs") +#pragma DATA_SECTION(displayUartHWAttrs, ".const:displayUartHWAttrs") +#endif + +#include +#include +#include + +/* Structures for UartPlain Blocking */ +DisplayUart_Object displayUartObject; + +#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE +#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 +#endif +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; + +const DisplayUart_HWAttrs displayUartHWAttrs = { + .uartIdx = Board_UART, + .baudRate = 115200, + .mutexTimeout = BIOS_WAIT_FOREVER, + .strBuf = uartStringBuf, + .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, +}; + +/* Structures for SHARP */ +DisplaySharp_Object displaySharpObject; + +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 // 96->96x96 is the most common board, alternative is 128->128x128. +#endif +static uint8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; + +const DisplaySharp_HWAttrs displaySharpHWattrs = { + .spiIndex = Board_SPI0, + .csPin = Board_LCD_CS, + .extcominPin = Board_LCD_EXTCOMIN, + .powerPin = Board_LCD_POWER, + .enablePin = Board_LCD_ENABLE, + .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, + .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, + .displayBuf = sharpDisplayBuf, +}; + +/* Array of displays */ +const Display_Config Display_config[] = { +#if !defined(BOARD_DISPLAY_EXCLUDE_UART) + { + .fxnTablePtr = &DisplayUart_fxnTable, + .object = &displayUartObject, + .hwAttrs = &displayUartHWAttrs, + }, +#endif +#if !defined(BOARD_DISPLAY_EXCLUDE_LCD) + { + .fxnTablePtr = &DisplaySharp_fxnTable, + .object = &displaySharpObject, + .hwAttrs = &displaySharpHWattrs + }, +#endif + { NULL, NULL, NULL } // Terminator +}; + +/* + * ========================= Display end ====================================== + */ + +/* + * ============================ GPTimer begin ================================= + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(GPTimerCC26XX_config, ".const:GPTimerCC26XX_config") +#pragma DATA_SECTION(gptimerCC26xxHWAttrs, ".const:gptimerCC26xxHWAttrs") +#endif + +/* GPTimer hardware attributes, one per timer part (Timer 0A, 0B, 1A, 1B..) */ +const GPTimerCC26XX_HWAttrs gptimerCC26xxHWAttrs[CC2650_LAUNCHXL_GPTIMERPARTSCOUNT] = { + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0A, }, + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0B, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1A, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1B, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2A, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2B, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3A, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3B, }, +}; + +/* GPTimer objects, one per full-width timer (A+B) (Timer 0, Timer 1..) */ +GPTimerCC26XX_Object gptimerCC26XXObjects[CC2650_LAUNCHXL_GPTIMERCOUNT]; + +/* GPTimer configuration (used as GPTimer_Handle by driver and application) */ +const GPTimerCC26XX_Config GPTimerCC26XX_config[CC2650_LAUNCHXL_GPTIMERPARTSCOUNT] = { + { &gptimerCC26XXObjects[0], &gptimerCC26xxHWAttrs[0], GPT_A }, + { &gptimerCC26XXObjects[0], &gptimerCC26xxHWAttrs[1], GPT_B }, + { &gptimerCC26XXObjects[1], &gptimerCC26xxHWAttrs[2], GPT_A }, + { &gptimerCC26XXObjects[1], &gptimerCC26xxHWAttrs[3], GPT_B }, + { &gptimerCC26XXObjects[2], &gptimerCC26xxHWAttrs[4], GPT_A }, + { &gptimerCC26XXObjects[2], &gptimerCC26xxHWAttrs[5], GPT_B }, + { &gptimerCC26XXObjects[3], &gptimerCC26xxHWAttrs[6], GPT_A }, + { &gptimerCC26XXObjects[3], &gptimerCC26xxHWAttrs[7], GPT_B }, +}; + +/* + * ============================ GPTimer end =================================== + */ + + + +/* + * ============================= PWM begin ==================================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(PWM_config, ".const:PWM_config") +#pragma DATA_SECTION(pwmtimerCC26xxHWAttrs, ".const:pwmtimerCC26xxHWAttrs") +#endif + +/* PWM configuration, one per PWM output. */ +PWMTimerCC26XX_HwAttrs pwmtimerCC26xxHWAttrs[CC2650_LAUNCHXL_PWMCOUNT] = { + { .pwmPin = Board_PWMPIN0, .gpTimerUnit = Board_GPTIMER0A }, + { .pwmPin = Board_PWMPIN1, .gpTimerUnit = Board_GPTIMER0B }, + { .pwmPin = Board_PWMPIN2, .gpTimerUnit = Board_GPTIMER1A }, + { .pwmPin = Board_PWMPIN3, .gpTimerUnit = Board_GPTIMER1B }, + { .pwmPin = Board_PWMPIN4, .gpTimerUnit = Board_GPTIMER2A }, + { .pwmPin = Board_PWMPIN5, .gpTimerUnit = Board_GPTIMER2B }, + { .pwmPin = Board_PWMPIN6, .gpTimerUnit = Board_GPTIMER3A }, + { .pwmPin = Board_PWMPIN7, .gpTimerUnit = Board_GPTIMER3B }, +}; + +/* PWM object, one per PWM output */ +PWMTimerCC26XX_Object pwmtimerCC26xxObjects[CC2650_LAUNCHXL_PWMCOUNT]; + +extern const PWM_FxnTable PWMTimerCC26XX_fxnTable; + +/* PWM configuration (used as PWM_Handle by driver and application) */ +const PWM_Config PWM_config[CC2650_LAUNCHXL_PWMCOUNT + 1] = { + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[0], &pwmtimerCC26xxHWAttrs[0] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[1], &pwmtimerCC26xxHWAttrs[1] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[2], &pwmtimerCC26xxHWAttrs[2] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[3], &pwmtimerCC26xxHWAttrs[3] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[4], &pwmtimerCC26xxHWAttrs[4] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[5], &pwmtimerCC26xxHWAttrs[5] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[6], &pwmtimerCC26xxHWAttrs[6] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[7], &pwmtimerCC26xxHWAttrs[7] }, + { NULL, NULL, NULL } +}; + + +/* + * ============================= PWM end ====================================== + */ + +/* + * ========================== ADCBuf begin ========================================= + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(ADCBuf_config, ".const:ADCBuf_config") +#pragma DATA_SECTION(adcBufCC26xxHWAttrs, ".const:adcBufCC26xxHWAttrs") +#pragma DATA_SECTION(ADCBufCC26XX_adcChannelLut, ".const:ADCBufCC26XX_adcChannelLut") +#endif + +/* Include drivers */ +#include +#include + +/* ADCBuf objects */ +ADCBufCC26XX_Object adcBufCC26xxObjects[CC2650_LAUNCHXL_ADCBufCOUNT]; + +/* + * This table converts a virtual adc channel into a dio and internal analogue input signal. + * This table is necessary for the functioning of the adcBuf driver. + * Comment out unused entries to save flash. + * Dio and internal signal pairs are hardwired. Do not remap them in the table. You may reorder entire entries though. + * The mapping of dio and internal signals is package dependent. + */ +const ADCBufCC26XX_AdcChannelLutEntry ADCBufCC26XX_adcChannelLut[] = { + {PIN_UNASSIGNED, ADC_COMPB_IN_VDDS}, + {PIN_UNASSIGNED, ADC_COMPB_IN_DCOUPL}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VSS}, + {Board_DIO23_ANALOG, ADC_COMPB_IN_AUXIO7}, + {Board_DIO24_ANALOG, ADC_COMPB_IN_AUXIO6}, + {Board_DIO25_ANALOG, ADC_COMPB_IN_AUXIO5}, + {Board_DIO26_ANALOG, ADC_COMPB_IN_AUXIO4}, + {Board_DIO27_ANALOG, ADC_COMPB_IN_AUXIO3}, + {Board_DIO28_ANALOG, ADC_COMPB_IN_AUXIO2}, + {Board_DIO29_ANALOG, ADC_COMPB_IN_AUXIO1}, + {Board_DIO30_ANALOG, ADC_COMPB_IN_AUXIO0}, +}; + +const ADCBufCC26XX_HWAttrs adcBufCC26xxHWAttrs[CC2650_LAUNCHXL_ADCBufCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + .adcChannelLut = ADCBufCC26XX_adcChannelLut, + .gpTimerUnit = Board_GPTIMER0A, + .gptDMAChannelMask = 1 << UDMA_CHAN_TIMER0_A, + } +}; + +const ADCBuf_Config ADCBuf_config[] = { + {&ADCBufCC26XX_fxnTable, &adcBufCC26xxObjects[0], &adcBufCC26xxHWAttrs[0]}, + {NULL, NULL, NULL}, +}; +/* + * ========================== ADCBuf end ========================================= + */ + + + +/* + * ========================== ADC begin ========================================= + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(ADC_config, ".const:ADC_config") +#pragma DATA_SECTION(adcCC26xxHWAttrs, ".const:adcCC26xxHWAttrs") +#endif + +/* Include drivers */ +#include +#include + +/* ADC objects */ +ADCCC26XX_Object adcCC26xxObjects[CC2650_LAUNCHXL_ADCCOUNT]; + + +const ADCCC26XX_HWAttrs adcCC26xxHWAttrs[CC2650_LAUNCHXL_ADCCOUNT] = { + { + .adcDIO = Board_DIO23_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO7, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + }, + { + .adcDIO = Board_DIO24_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO6, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + }, + { + .adcDIO = Board_DIO25_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO5, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + }, + { + .adcDIO = Board_DIO26_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO4, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + }, + { + .adcDIO = Board_DIO27_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO3, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + }, + { + .adcDIO = Board_DIO28_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO2, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + }, + { + .adcDIO = Board_DIO29_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO1, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + }, + { + .adcDIO = Board_DIO30_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO0, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_10P9_MS, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_DCOUPL, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VSS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VDDS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + } +}; + +const ADC_Config ADC_config[] = { + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[0], &adcCC26xxHWAttrs[0]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[1], &adcCC26xxHWAttrs[1]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[2], &adcCC26xxHWAttrs[2]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[3], &adcCC26xxHWAttrs[3]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[4], &adcCC26xxHWAttrs[4]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[5], &adcCC26xxHWAttrs[5]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[6], &adcCC26xxHWAttrs[6]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[7], &adcCC26xxHWAttrs[7]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[8], &adcCC26xxHWAttrs[8]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[9], &adcCC26xxHWAttrs[9]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[10], &adcCC26xxHWAttrs[10]}, + {NULL, NULL, NULL}, +}; + +/* + * ========================== ADC end ========================================= + */ + +/* + * =============================== Watchdog =============================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(Watchdog_config, ".const:Watchdog_config") +#pragma DATA_SECTION(watchdogCC26XXHWAttrs, ".const:watchdogCC26XXHWAttrs") +#endif + +#include +#include + +WatchdogCC26XX_Object watchdogCC26XXObjects[CC2650_LAUNCHXL_WATCHDOGCOUNT]; + +const WatchdogCC26XX_HWAttrs watchdogCC26XXHWAttrs[CC2650_LAUNCHXL_WATCHDOGCOUNT] = { + { + .baseAddr = WDT_BASE, + .intNum = INT_WDT_IRQ, + .reloadValue = 1000 /* Reload value in milliseconds */ + }, +}; + +const Watchdog_Config Watchdog_config[] = { + { + .fxnTablePtr = &WatchdogCC26XX_fxnTable, + .object = &watchdogCC26XXObjects[0], + .hwAttrs = &watchdogCC26XXHWAttrs[0] + }, + {NULL, NULL, NULL}, +}; + +/* + * ======== CC26XX_LAUNCHXL_initWatchdog ======== + */ +void CC26XX_LAUNCHXL_initWatchdog(void) +{ + Watchdog_init(); +} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h new file mode 100644 index 000000000..4ca05d632 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2015-2016, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ +/** ============================================================================ + * @file CC2650_LAUNCHXL.h + * + * @brief CC2650 LaunchPad Board Specific header file. + * + * NB! This is the board file for CC2650 LaunchPad PCB version 1.1 + * + * ============================================================================ + */ +#ifndef __CC2650_LAUNCHXL_BOARD_H__ +#define __CC2650_LAUNCHXL_BOARD_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** ============================================================================ + * Includes + * ==========================================================================*/ +#include +#include + +/** ============================================================================ + * Externs + * ==========================================================================*/ +extern const PIN_Config BoardGpioInitTable[]; + +/** ============================================================================ + * Defines + * ==========================================================================*/ + +/* Same RF Configuration as 7x7 EM */ +#define CC2650EM_7ID +#define CC2650_LAUNCHXL + +/* Mapping of pins to board signals using general board aliases + * + */ + +/* Discrete outputs */ +#define Board_RLED IOID_6 +#define Board_GLED IOID_7 +#define Board_LED_ON 1 +#define Board_LED_OFF 0 + +/* Discrete inputs */ +#define Board_BTN1 IOID_13 +#define Board_BTN2 IOID_14 + +/* UART Board */ +#define Board_UART_RX IOID_2 /* RXD */ +#define Board_UART_TX IOID_3 /* TXD */ +#define Board_UART_CTS IOID_19 /* CTS */ +#define Board_UART_RTS IOID_18 /* RTS */ + +/* SPI Board */ +#define Board_SPI0_MISO IOID_8 /* RF1.20 */ +#define Board_SPI0_MOSI IOID_9 /* RF1.18 */ +#define Board_SPI0_CLK IOID_10 /* RF1.16 */ +#define Board_SPI0_CSN PIN_UNASSIGNED +#define Board_SPI1_MISO PIN_UNASSIGNED +#define Board_SPI1_MOSI PIN_UNASSIGNED +#define Board_SPI1_CLK PIN_UNASSIGNED +#define Board_SPI1_CSN PIN_UNASSIGNED + +/* I2C */ +#define Board_I2C0_SCL0 IOID_4 +#define Board_I2C0_SDA0 IOID_5 + +/* SPI */ +#define Board_SPI_FLASH_CS IOID_20 +#define Board_FLASH_CS_ON 0 +#define Board_FLASH_CS_OFF 1 + +/* Booster pack generic */ +#define Board_DIO0 IOID_0 +#define Board_DIO1_RFSW IOID_1 +#define Board_DIO12 IOID_12 +#define Board_DIO15 IOID_15 +#define Board_DIO16_TDO IOID_16 +#define Board_DIO17_TDI IOID_17 +#define Board_DIO21 IOID_21 +#define Board_DIO22 IOID_22 + +#define Board_DIO23_ANALOG IOID_23 +#define Board_DIO24_ANALOG IOID_24 +#define Board_DIO25_ANALOG IOID_25 +#define Board_DIO26_ANALOG IOID_26 +#define Board_DIO27_ANALOG IOID_27 +#define Board_DIO28_ANALOG IOID_28 +#define Board_DIO29_ANALOG IOID_29 +#define Board_DIO30_ANALOG IOID_30 + +/* Booster pack LCD (430BOOST - Sharp96 Rev 1.1) */ +#define Board_LCD_CS IOID_24 // SPI chip select +#define Board_LCD_EXTCOMIN IOID_12 // External COM inversion +#define Board_LCD_ENABLE IOID_22 // LCD enable +#define Board_LCD_POWER IOID_23 // LCD power control +#define Board_LCD_CS_ON 1 +#define Board_LCD_CS_OFF 0 + +/* PWM outputs */ +#define Board_PWMPIN0 Board_RLED +#define Board_PWMPIN1 Board_GLED +#define Board_PWMPIN2 PIN_UNASSIGNED +#define Board_PWMPIN3 PIN_UNASSIGNED +#define Board_PWMPIN4 PIN_UNASSIGNED +#define Board_PWMPIN5 PIN_UNASSIGNED +#define Board_PWMPIN6 PIN_UNASSIGNED +#define Board_PWMPIN7 PIN_UNASSIGNED + +/** ============================================================================ + * Instance identifiers + * ==========================================================================*/ +/* Generic I2C instance identifiers */ +#define Board_I2C CC2650_LAUNCHXL_I2C0 +/* Generic SPI instance identifiers */ +#define Board_SPI0 CC2650_LAUNCHXL_SPI0 +#define Board_SPI1 CC2650_LAUNCHXL_SPI1 +/* Generic UART instance identifiers */ +#define Board_UART CC2650_LAUNCHXL_UART0 +/* Generic Crypto instance identifiers */ +#define Board_CRYPTO CC2650_LAUNCHXL_CRYPTO0 +/* Generic GPTimer instance identifiers */ +#define Board_GPTIMER0A CC2650_LAUNCHXL_GPTIMER0A +#define Board_GPTIMER0B CC2650_LAUNCHXL_GPTIMER0B +#define Board_GPTIMER1A CC2650_LAUNCHXL_GPTIMER1A +#define Board_GPTIMER1B CC2650_LAUNCHXL_GPTIMER1B +#define Board_GPTIMER2A CC2650_LAUNCHXL_GPTIMER2A +#define Board_GPTIMER2B CC2650_LAUNCHXL_GPTIMER2B +#define Board_GPTIMER3A CC2650_LAUNCHXL_GPTIMER3A +#define Board_GPTIMER3B CC2650_LAUNCHXL_GPTIMER3B +/* Generic PWM instance identifiers */ +#define Board_PWM0 CC2650_LAUNCHXL_PWM0 +#define Board_PWM1 CC2650_LAUNCHXL_PWM1 +#define Board_PWM2 CC2650_LAUNCHXL_PWM2 +#define Board_PWM3 CC2650_LAUNCHXL_PWM3 +#define Board_PWM4 CC2650_LAUNCHXL_PWM4 +#define Board_PWM5 CC2650_LAUNCHXL_PWM5 +#define Board_PWM6 CC2650_LAUNCHXL_PWM6 +#define Board_PWM7 CC2650_LAUNCHXL_PWM7 + +/** ============================================================================ + * Number of peripherals and their names + * ==========================================================================*/ + +/*! + * @def CC2650_LAUNCHXL_I2CName + * @brief Enum of I2C names on the CC2650 dev board + */ +typedef enum CC2650_LAUNCHXL_I2CName { + CC2650_LAUNCHXL_I2C0 = 0, + + CC2650_LAUNCHXL_I2CCOUNT +} CC2650_LAUNCHXL_I2CName; + +/*! + * @def CC2650_LAUNCHXL_CryptoName + * @brief Enum of Crypto names on the CC2650 dev board + */ +typedef enum CC2650_LAUNCHXL_CryptoName { + CC2650_LAUNCHXL_CRYPTO0 = 0, + + CC2650_LAUNCHXL_CRYPTOCOUNT +} CC2650_LAUNCHXL_CryptoName; + + +/*! + * @def CC2650_LAUNCHXL_SPIName + * @brief Enum of SPI names on the CC2650 dev board + */ +typedef enum CC2650_LAUNCHXL_SPIName { + CC2650_LAUNCHXL_SPI0 = 0, + CC2650_LAUNCHXL_SPI1, + + CC2650_LAUNCHXL_SPICOUNT +} CC2650_LAUNCHXL_SPIName; + +/*! + * @def CC2650_LAUNCHXL_UARTName + * @brief Enum of UARTs on the CC2650 dev board + */ +typedef enum CC2650_LAUNCHXL_UARTName { + CC2650_LAUNCHXL_UART0 = 0, + + CC2650_LAUNCHXL_UARTCOUNT +} CC2650_LAUNCHXL_UARTName; + +/*! + * @def CC2650_LAUNCHXL_UdmaName + * @brief Enum of DMA buffers + */ +typedef enum CC2650_LAUNCHXL_UdmaName { + CC2650_LAUNCHXL_UDMA0 = 0, + + CC2650_LAUNCHXL_UDMACOUNT +} CC2650_LAUNCHXL_UdmaName; + +/*! + * @def CC2650_LAUNCHXL_GPTimerName + * @brief Enum of GPTimer parts + */ +typedef enum CC2650_LAUNCHXL_GPTimerName +{ + CC2650_LAUNCHXL_GPTIMER0A = 0, + CC2650_LAUNCHXL_GPTIMER0B, + CC2650_LAUNCHXL_GPTIMER1A, + CC2650_LAUNCHXL_GPTIMER1B, + CC2650_LAUNCHXL_GPTIMER2A, + CC2650_LAUNCHXL_GPTIMER2B, + CC2650_LAUNCHXL_GPTIMER3A, + CC2650_LAUNCHXL_GPTIMER3B, + CC2650_LAUNCHXL_GPTIMERPARTSCOUNT +} CC2650_LAUNCHXL_GPTimerName; + +/*! + * @def CC2650_LAUNCHXL_GPTimers + * @brief Enum of GPTimers + */ +typedef enum CC2650_LAUNCHXL_GPTimers +{ + CC2650_LAUNCHXL_GPTIMER0 = 0, + CC2650_LAUNCHXL_GPTIMER1, + CC2650_LAUNCHXL_GPTIMER2, + CC2650_LAUNCHXL_GPTIMER3, + CC2650_LAUNCHXL_GPTIMERCOUNT +} CC2650_LAUNCHXL_GPTimers; + +/*! + * @def CC2650_LAUNCHXL_PWM + * @brief Enum of PWM outputs on the board + */ +typedef enum CC2650_LAUNCHXL_PWM +{ + CC2650_LAUNCHXL_PWM0 = 0, + CC2650_LAUNCHXL_PWM1, + CC2650_LAUNCHXL_PWM2, + CC2650_LAUNCHXL_PWM3, + CC2650_LAUNCHXL_PWM4, + CC2650_LAUNCHXL_PWM5, + CC2650_LAUNCHXL_PWM6, + CC2650_LAUNCHXL_PWM7, + CC2650_LAUNCHXL_PWMCOUNT +} CC2650_LAUNCHXL_PWM; + +/*! + * @def CC2650_LAUNCHXL_ADCBufName + * @brief Enum of ADCs + */ +typedef enum CC2650_LAUNCHXL_ADCBufName { + CC2650_LAUNCHXL_ADCBuf0 = 0, + CC2650_LAUNCHXL_ADCBufCOUNT +} CC2650_LAUNCHXL_ADCBufName; + + +/*! + * @def CC2650_LAUNCHXL_ADCName + * @brief Enum of ADCs + */ +typedef enum CC2650_LAUNCHXL_ADCName { + CC2650_LAUNCHXL_ADC0 = 0, + CC2650_LAUNCHXL_ADC1, + CC2650_LAUNCHXL_ADC2, + CC2650_LAUNCHXL_ADC3, + CC2650_LAUNCHXL_ADC4, + CC2650_LAUNCHXL_ADC5, + CC2650_LAUNCHXL_ADC6, + CC2650_LAUNCHXL_ADC7, + CC2650_LAUNCHXL_ADCDCOUPL, + CC2650_LAUNCHXL_ADCVSS, + CC2650_LAUNCHXL_ADCVDDS, + CC2650_LAUNCHXL_ADCCOUNT +} CC2650_LAUNCHXL_ADCName; + +/*! + * @def CC2650_LAUNCHXL_WatchdogName + * @brief Enum of Watchdogs on the CC2650_LAUNCHXL dev board + */ +typedef enum CC2650_LAUNCHXL_WatchdogName { + CC2650_LAUNCHXL_WATCHDOG0 = 0, + + CC2650_LAUNCHXL_WATCHDOGCOUNT +} CC2650_LAUNCHXL_WatchdogName; + +#ifdef __cplusplus +} +#endif + +#endif /* __CC2650_LAUNCHXL_BOARD_H__ */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Makefile.cc2650 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Makefile.cc2650 new file mode 100644 index 000000000..1856533f2 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Makefile.cc2650 @@ -0,0 +1,16 @@ +################################################################################ +# SimpleLink Device makefile + +SUBFAMILY = cc13x0-cc26x0 +DEVICE_FAMILY = CC26X0 + +BOARD_SOURCEFILES += CC2650_LAUNCHXL.c + +SUPPORTS_PROP_MODE = 1 +SUPPORTS_IEEE_MODE = 1 + +### Signal that we can be programmed with cc2538-bsl +BOARD_SUPPORTS_BSL = 1 + +# Include the common board makefile +include $(FAMILY_PATH)/launchpad/Makefile.launchpad diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Board.h new file mode 100644 index 000000000..be6ccc8bd --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Board.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2015-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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 __BOARD_H +#define __BOARD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "CC26X2R1_LAUNCHXL.h" + +#define Board_initGeneral() CC26X2R1_LAUNCHXL_initGeneral() + +#define Board_shutDownExtFlash() CC26X2R1_LAUNCHXL_shutDownExtFlash() + +#define Board_wakeUpExtFlash() CC26X2R1_LAUNCHXL_wakeUpExtFlash() + +/* These #defines allow us to reuse TI-RTOS across other device families */ + +#define Board_ADC0 CC26X2R1_LAUNCHXL_ADC0 +#define Board_ADC1 CC26X2R1_LAUNCHXL_ADC1 + +#define Board_ADCBUF0 CC26X2R1_LAUNCHXL_ADCBUF0 +#define Board_ADCBUF0CHANNEL0 CC26X2R1_LAUNCHXL_ADCBUF0CHANNEL0 +#define Board_ADCBUF0CHANNEL1 CC26X2R1_LAUNCHXL_ADCBUF0CHANNEL1 + +#define Board_ECDH0 CC26X2R1_LAUNCHXL_ECDH0 +#define Board_ECDSA0 CC26X2R1_LAUNCHXL_ECDSA0 +#define Board_ECJPAKE0 CC26X2R1_LAUNCHXL_ECJPAKE0 +#define Board_AESCCM0 CC26X2R1_LAUNCHXL_AESCCM0 +#define Board_AESECB0 CC26X2R1_LAUNCHXL_AESECB0 +#define Board_SHA20 CC26X2R1_LAUNCHXL_SHA20 + +#define Board_DIO0 CC26X2R1_LAUNCHXL_DIO0 +#define Board_DIO1_RFSW CC26X2R1_LAUNCHXL_DIO1_RFSW +#define Board_DIO12 CC26X2R1_LAUNCHXL_DIO12 +#define Board_DIO15 CC26X2R1_LAUNCHXL_DIO15 +#define Board_DIO16_TDO CC26X2R1_LAUNCHXL_DIO16_TDO +#define Board_DIO17_TDI CC26X2R1_LAUNCHXL_DIO17_TDI +#define Board_DIO21 CC26X2R1_LAUNCHXL_DIO21 +#define Board_DIO22 CC26X2R1_LAUNCHXL_DIO22 + +#define Board_DIO23_ANALOG CC26X2R1_LAUNCHXL_DIO23_ANALOG +#define Board_DIO24_ANALOG CC26X2R1_LAUNCHXL_DIO24_ANALOG +#define Board_DIO25_ANALOG CC26X2R1_LAUNCHXL_DIO25_ANALOG +#define Board_DIO26_ANALOG CC26X2R1_LAUNCHXL_DIO26_ANALOG +#define Board_DIO27_ANALOG CC26X2R1_LAUNCHXL_DIO27_ANALOG +#define Board_DIO28_ANALOG CC26X2R1_LAUNCHXL_DIO28_ANALOG +#define Board_DIO29_ANALOG CC26X2R1_LAUNCHXL_DIO29_ANALOG +#define Board_DIO30_ANALOG CC26X2R1_LAUNCHXL_DIO30_ANALOG + +#define Board_GPIO_BUTTON0 CC26X2R1_LAUNCHXL_GPIO_S1 +#define Board_GPIO_BUTTON1 CC26X2R1_LAUNCHXL_GPIO_S2 +#define Board_GPIO_BTN1 CC26X2R1_LAUNCHXL_GPIO_S1 +#define Board_GPIO_BTN2 CC26X2R1_LAUNCHXL_GPIO_S2 +#define Board_GPIO_LED0 CC26X2R1_LAUNCHXL_GPIO_LED_RED +#define Board_GPIO_LED1 CC26X2R1_LAUNCHXL_GPIO_LED_GREEN +#define Board_GPIO_LED2 CC26X2R1_LAUNCHXL_GPIO_LED_RED +#define Board_GPIO_RLED CC26X2R1_LAUNCHXL_GPIO_LED_RED +#define Board_GPIO_GLED CC26X2R1_LAUNCHXL_GPIO_LED_GREEN +#define Board_GPIO_LED_ON CC26X2R1_LAUNCHXL_GPIO_LED_ON +#define Board_GPIO_LED_OFF CC26X2R1_LAUNCHXL_GPIO_LED_OFF + +#define Board_GPTIMER0A CC26X2R1_LAUNCHXL_GPTIMER0A +#define Board_GPTIMER0B CC26X2R1_LAUNCHXL_GPTIMER0B +#define Board_GPTIMER1A CC26X2R1_LAUNCHXL_GPTIMER1A +#define Board_GPTIMER1B CC26X2R1_LAUNCHXL_GPTIMER1B +#define Board_GPTIMER2A CC26X2R1_LAUNCHXL_GPTIMER2A +#define Board_GPTIMER2B CC26X2R1_LAUNCHXL_GPTIMER2B +#define Board_GPTIMER3A CC26X2R1_LAUNCHXL_GPTIMER3A +#define Board_GPTIMER3B CC26X2R1_LAUNCHXL_GPTIMER3B + +#define Board_I2C0 CC26X2R1_LAUNCHXL_I2C0 +#define Board_I2C_TMP Board_I2C0 + +#define Board_NVSINTERNAL CC26X2R1_LAUNCHXL_NVSCC26XX0 +#define Board_NVSEXTERNAL CC26X2R1_LAUNCHXL_NVSSPI25X0 + +#define Board_PIN_BUTTON0 CC26X2R1_LAUNCHXL_PIN_BTN1 +#define Board_PIN_BUTTON1 CC26X2R1_LAUNCHXL_PIN_BTN2 +#define Board_PIN_BTN1 CC26X2R1_LAUNCHXL_PIN_BTN1 +#define Board_PIN_BTN2 CC26X2R1_LAUNCHXL_PIN_BTN2 +#define Board_PIN_LED0 CC26X2R1_LAUNCHXL_PIN_RLED +#define Board_PIN_LED1 CC26X2R1_LAUNCHXL_PIN_GLED +#define Board_PIN_LED2 CC26X2R1_LAUNCHXL_PIN_RLED +#define Board_PIN_RLED CC26X2R1_LAUNCHXL_PIN_RLED +#define Board_PIN_GLED CC26X2R1_LAUNCHXL_PIN_GLED + +#define Board_PWM0 CC26X2R1_LAUNCHXL_PWM0 +#define Board_PWM1 CC26X2R1_LAUNCHXL_PWM1 +#define Board_PWM2 CC26X2R1_LAUNCHXL_PWM2 +#define Board_PWM3 CC26X2R1_LAUNCHXL_PWM3 +#define Board_PWM4 CC26X2R1_LAUNCHXL_PWM4 +#define Board_PWM5 CC26X2R1_LAUNCHXL_PWM5 +#define Board_PWM6 CC26X2R1_LAUNCHXL_PWM6 +#define Board_PWM7 CC26X2R1_LAUNCHXL_PWM7 + +#define Board_SD0 CC26X2R1_LAUNCHXL_SDSPI0 + +#define Board_SPI0 CC26X2R1_LAUNCHXL_SPI0 +#define Board_SPI1 CC26X2R1_LAUNCHXL_SPI1 +#define Board_SPI_FLASH_CS CC26X2R1_LAUNCHXL_SPI_FLASH_CS +#define Board_FLASH_CS_ON 0 +#define Board_FLASH_CS_OFF 1 + +#define Board_SPI_MASTER CC26X2R1_LAUNCHXL_SPI0 +#define Board_SPI_SLAVE CC26X2R1_LAUNCHXL_SPI0 +#define Board_SPI_MASTER_READY CC26X2R1_LAUNCHXL_SPI_MASTER_READY +#define Board_SPI_SLAVE_READY CC26X2R1_LAUNCHXL_SPI_SLAVE_READY + +#define Board_UART0 CC26X2R1_LAUNCHXL_UART0 +#define Board_UART1 CC26X2R1_LAUNCHXL_UART1 + +#define Board_WATCHDOG0 CC26X2R1_LAUNCHXL_WATCHDOG0 + +/* Board specific I2C addresses */ +#define Board_TMP_ADDR (0x40) +#define Board_SENSORS_BP_TMP_ADDR Board_TMP_ADDR + +#ifdef __cplusplus +} +#endif + +#endif /* __BOARD_H */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c new file mode 100644 index 000000000..09d556caf --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c @@ -0,0 +1,1056 @@ +/* + * Copyright (c) 2016-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +/* + * ====================== CC26X2R1_LAUNCHXL.c =================================== + * This file is responsible for setting up the board specific items for the + * CC26X2R1_LAUNCHXL board. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "CC26X2R1_LAUNCHXL.h" + +/* + * =============================== ADCBuf =============================== + */ +#include +#include + +ADCBufCC26X2_Object adcBufCC26xxObjects[CC26X2R1_LAUNCHXL_ADCBUFCOUNT]; + +/* + * This table converts a virtual adc channel into a dio and internal analogue + * input signal. This table is necessary for the functioning of the adcBuf + * driver. Comment out unused entries to save flash. Dio and internal signal + * pairs are hardwired. Do not remap them in the table. You may reorder entire + * entries. The mapping of dio and internal signals is package dependent. + */ +const ADCBufCC26X2_AdcChannelLutEntry ADCBufCC26X2_adcChannelLut[CC26X2R1_LAUNCHXL_ADCBUF0CHANNELCOUNT] = { + {CC26X2R1_LAUNCHXL_DIO23_ANALOG, ADC_COMPB_IN_AUXIO7}, + {CC26X2R1_LAUNCHXL_DIO24_ANALOG, ADC_COMPB_IN_AUXIO6}, + {CC26X2R1_LAUNCHXL_DIO25_ANALOG, ADC_COMPB_IN_AUXIO5}, + {CC26X2R1_LAUNCHXL_DIO26_ANALOG, ADC_COMPB_IN_AUXIO4}, + {CC26X2R1_LAUNCHXL_DIO27_ANALOG, ADC_COMPB_IN_AUXIO3}, + {CC26X2R1_LAUNCHXL_DIO28_ANALOG, ADC_COMPB_IN_AUXIO2}, + {CC26X2R1_LAUNCHXL_DIO29_ANALOG, ADC_COMPB_IN_AUXIO1}, + {CC26X2R1_LAUNCHXL_DIO30_ANALOG, ADC_COMPB_IN_AUXIO0}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VDDS}, + {PIN_UNASSIGNED, ADC_COMPB_IN_DCOUPL}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VSS}, +}; + +const ADCBufCC26X2_HWAttrs adcBufCC26xxHWAttrs[CC26X2R1_LAUNCHXL_ADCBUFCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + .adcChannelLut = ADCBufCC26X2_adcChannelLut, + .gpTimerUnit = CC26X2R1_LAUNCHXL_GPTIMER0A, + } +}; + +const ADCBuf_Config ADCBuf_config[CC26X2R1_LAUNCHXL_ADCBUFCOUNT] = { + { + &ADCBufCC26X2_fxnTable, + &adcBufCC26xxObjects[CC26X2R1_LAUNCHXL_ADCBUF0], + &adcBufCC26xxHWAttrs[CC26X2R1_LAUNCHXL_ADCBUF0] + }, +}; + +const uint_least8_t ADCBuf_count = CC26X2R1_LAUNCHXL_ADCBUFCOUNT; + +/* + * =============================== ADC =============================== + */ +#include +#include + +ADCCC26XX_Object adcCC26xxObjects[CC26X2R1_LAUNCHXL_ADCCOUNT]; + +const ADCCC26XX_HWAttrs adcCC26xxHWAttrs[CC26X2R1_LAUNCHXL_ADCCOUNT] = { + { + .adcDIO = CC26X2R1_LAUNCHXL_DIO23_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO7, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC26X2R1_LAUNCHXL_DIO24_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO6, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC26X2R1_LAUNCHXL_DIO25_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO5, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC26X2R1_LAUNCHXL_DIO26_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO4, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC26X2R1_LAUNCHXL_DIO27_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO3, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC26X2R1_LAUNCHXL_DIO28_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO2, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC26X2R1_LAUNCHXL_DIO29_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO1, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC26X2R1_LAUNCHXL_DIO30_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO0, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_10P9_MS, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_DCOUPL, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VSS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VDDS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + } +}; + +const ADC_Config ADC_config[CC26X2R1_LAUNCHXL_ADCCOUNT] = { + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC26X2R1_LAUNCHXL_ADC0], &adcCC26xxHWAttrs[CC26X2R1_LAUNCHXL_ADC0]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC26X2R1_LAUNCHXL_ADC1], &adcCC26xxHWAttrs[CC26X2R1_LAUNCHXL_ADC1]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC26X2R1_LAUNCHXL_ADC2], &adcCC26xxHWAttrs[CC26X2R1_LAUNCHXL_ADC2]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC26X2R1_LAUNCHXL_ADC3], &adcCC26xxHWAttrs[CC26X2R1_LAUNCHXL_ADC3]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC26X2R1_LAUNCHXL_ADC4], &adcCC26xxHWAttrs[CC26X2R1_LAUNCHXL_ADC4]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC26X2R1_LAUNCHXL_ADC5], &adcCC26xxHWAttrs[CC26X2R1_LAUNCHXL_ADC5]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC26X2R1_LAUNCHXL_ADC6], &adcCC26xxHWAttrs[CC26X2R1_LAUNCHXL_ADC6]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC26X2R1_LAUNCHXL_ADC7], &adcCC26xxHWAttrs[CC26X2R1_LAUNCHXL_ADC7]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC26X2R1_LAUNCHXL_ADCDCOUPL], &adcCC26xxHWAttrs[CC26X2R1_LAUNCHXL_ADCDCOUPL]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC26X2R1_LAUNCHXL_ADCVSS], &adcCC26xxHWAttrs[CC26X2R1_LAUNCHXL_ADCVSS]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC26X2R1_LAUNCHXL_ADCVDDS], &adcCC26xxHWAttrs[CC26X2R1_LAUNCHXL_ADCVDDS]}, +}; + +const uint_least8_t ADC_count = CC26X2R1_LAUNCHXL_ADCCOUNT; + + +/* + * =============================== ECDH =============================== + */ +#include +#include + +ECDHCC26X2_Object ecdhCC26X2Objects[CC26X2R1_LAUNCHXL_ECDHCOUNT]; + +const ECDHCC26X2_HWAttrs ecdhCC26X2HWAttrs[CC26X2R1_LAUNCHXL_ECDHCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const ECDH_Config ECDH_config[CC26X2R1_LAUNCHXL_ECDHCOUNT] = { + { + .object = &ecdhCC26X2Objects[CC26X2R1_LAUNCHXL_ECDH0], + .hwAttrs = &ecdhCC26X2HWAttrs[CC26X2R1_LAUNCHXL_ECDH0] + }, +}; + +const uint_least8_t ECDH_count = CC26X2R1_LAUNCHXL_ECDHCOUNT; + +/* + * =============================== ECDSA =============================== + */ +#include +#include + +ECDSACC26X2_Object ecdsaCC26X2Objects[CC26X2R1_LAUNCHXL_ECDSACOUNT]; + +const ECDSACC26X2_HWAttrs ecdsaCC26X2HWAttrs[CC26X2R1_LAUNCHXL_ECDSACOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const ECDSA_Config ECDSA_config[CC26X2R1_LAUNCHXL_ECDSACOUNT] = { + { + .object = &ecdsaCC26X2Objects[CC26X2R1_LAUNCHXL_ECDSA0], + .hwAttrs = &ecdsaCC26X2HWAttrs[CC26X2R1_LAUNCHXL_ECDSA0] + }, +}; + +const uint_least8_t ECDSA_count = CC26X2R1_LAUNCHXL_ECDSACOUNT; + +/* + * =============================== ECJPAKE =============================== + */ +#include +#include + +ECJPAKECC26X2_Object ecjpakeCC26X2Objects[CC26X2R1_LAUNCHXL_ECJPAKECOUNT]; + +const ECJPAKECC26X2_HWAttrs ecjpakeCC26X2HWAttrs[CC26X2R1_LAUNCHXL_ECJPAKECOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const ECJPAKE_Config ECJPAKE_config[CC26X2R1_LAUNCHXL_ECJPAKECOUNT] = { + { + .object = &ecjpakeCC26X2Objects[CC26X2R1_LAUNCHXL_ECJPAKE0], + .hwAttrs = &ecjpakeCC26X2HWAttrs[CC26X2R1_LAUNCHXL_ECJPAKE0] + }, +}; + +const uint_least8_t ECJPAKE_count = CC26X2R1_LAUNCHXL_ECJPAKECOUNT; + +/* + * =============================== SHA2 =============================== + */ +#include +#include + +SHA2CC26X2_Object sha2CC26X2Objects[CC26X2R1_LAUNCHXL_SHA2COUNT]; + +const SHA2CC26X2_HWAttrs sha2CC26X2HWAttrs[CC26X2R1_LAUNCHXL_SHA2COUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const SHA2_Config SHA2_config[CC26X2R1_LAUNCHXL_SHA2COUNT] = { + { + .object = &sha2CC26X2Objects[CC26X2R1_LAUNCHXL_SHA20], + .hwAttrs = &sha2CC26X2HWAttrs[CC26X2R1_LAUNCHXL_SHA20] + }, +}; + +const uint_least8_t SHA2_count = CC26X2R1_LAUNCHXL_SHA2COUNT; + +/* + * =============================== AESCCM =============================== + */ +#include +#include + +AESCCMCC26XX_Object aesccmCC26XXObjects[CC26X2R1_LAUNCHXL_AESCCMCOUNT]; + +const AESCCMCC26XX_HWAttrs aesccmCC26XXHWAttrs[CC26X2R1_LAUNCHXL_AESCCMCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const AESCCM_Config AESCCM_config[CC26X2R1_LAUNCHXL_AESCCMCOUNT] = { + { + .object = &aesccmCC26XXObjects[CC26X2R1_LAUNCHXL_AESCCM0], + .hwAttrs = &aesccmCC26XXHWAttrs[CC26X2R1_LAUNCHXL_AESCCM0] + }, +}; + +const uint_least8_t AESCCM_count = CC26X2R1_LAUNCHXL_AESCCMCOUNT; + +/* + * =============================== AESECB =============================== + */ +#include +#include + +AESECBCC26XX_Object aesecbCC26XXObjects[CC26X2R1_LAUNCHXL_AESECBCOUNT]; + +const AESECBCC26XX_HWAttrs aesecbCC26XXHWAttrs[CC26X2R1_LAUNCHXL_AESECBCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const AESECB_Config AESECB_config[CC26X2R1_LAUNCHXL_AESECBCOUNT] = { + { + .object = &aesecbCC26XXObjects[CC26X2R1_LAUNCHXL_AESECB0], + .hwAttrs = &aesecbCC26XXHWAttrs[CC26X2R1_LAUNCHXL_AESECB0] + }, +}; + +const uint_least8_t AESECB_count = CC26X2R1_LAUNCHXL_AESECBCOUNT; + + +/* + * =============================== Display =============================== + */ +#include +#include +#include + +#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE +#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 +#endif + +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 +#endif + +DisplayUart_Object displayUartObject; +DisplaySharp_Object displaySharpObject; + +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; +static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; + +const DisplayUart_HWAttrs displayUartHWAttrs = { + .uartIdx = CC26X2R1_LAUNCHXL_UART0, + .baudRate = 115200, + .mutexTimeout = (unsigned int)(-1), + .strBuf = uartStringBuf, + .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, +}; + +const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { + .spiIndex = CC26X2R1_LAUNCHXL_SPI0, + .csPin = CC26X2R1_LAUNCHXL_GPIO_LCD_CS, + .powerPin = CC26X2R1_LAUNCHXL_GPIO_LCD_POWER, + .enablePin = CC26X2R1_LAUNCHXL_GPIO_LCD_ENABLE, + .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, + .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, + .displayBuf = sharpDisplayBuf, +}; + +#ifndef BOARD_DISPLAY_USE_UART +#define BOARD_DISPLAY_USE_UART 1 +#endif +#ifndef BOARD_DISPLAY_USE_UART_ANSI +#define BOARD_DISPLAY_USE_UART_ANSI 0 +#endif +#ifndef BOARD_DISPLAY_USE_LCD +#define BOARD_DISPLAY_USE_LCD 0 +#endif + +/* + * This #if/#else is needed to workaround a problem with the + * IAR compiler. The IAR compiler doesn't like the empty array + * initialization. (IAR Error[Pe1345]) + */ +#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) + +const Display_Config Display_config[] = { +#if (BOARD_DISPLAY_USE_UART) + { +# if (BOARD_DISPLAY_USE_UART_ANSI) + .fxnTablePtr = &DisplayUartAnsi_fxnTable, +# else /* Default to minimal UART with no cursor placement */ + .fxnTablePtr = &DisplayUartMin_fxnTable, +# endif + .object = &displayUartObject, + .hwAttrs = &displayUartHWAttrs, + }, +#endif +#if (BOARD_DISPLAY_USE_LCD) + { + .fxnTablePtr = &DisplaySharp_fxnTable, + .object = &displaySharpObject, + .hwAttrs = &displaySharpHWattrs + }, +#endif +}; + +const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); + +#else + +const Display_Config *Display_config = NULL; +const uint_least8_t Display_count = 0; + +#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ + +/* + * =============================== GPIO =============================== + */ +#include +#include + +/* + * Array of Pin configurations + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC26X2R1_LAUNCHXL.h + * NOTE: Pins not used for interrupts should be placed at the end of the + * array. Callback entries can be omitted from callbacks array to + * reduce memory usage. + */ +GPIO_PinConfig gpioPinConfigs[] = { + /* Input pins */ + GPIOCC26XX_DIO_13 | GPIO_DO_NOT_CONFIG, /* Button 0 */ + GPIOCC26XX_DIO_14 | GPIO_DO_NOT_CONFIG, /* Button 1 */ + + GPIOCC26XX_DIO_15 | GPIO_DO_NOT_CONFIG, /* CC26X2R1_LAUNCHXL_SPI_MASTER_READY */ + GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG, /* CC26X2R1_LAUNCHXL_SPI_SLAVE_READY */ + + /* Output pins */ + GPIOCC26XX_DIO_07 | GPIO_DO_NOT_CONFIG, /* Green LED */ + GPIOCC26XX_DIO_06 | GPIO_DO_NOT_CONFIG, /* Red LED */ + + /* SPI Flash CSN */ + GPIOCC26XX_DIO_20 | GPIO_DO_NOT_CONFIG, + + /* SD CS */ + GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG, + + /* Sharp Display - GPIO configurations will be done in the Display files */ + GPIOCC26XX_DIO_24 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ + GPIOCC26XX_DIO_22 | GPIO_DO_NOT_CONFIG, /* LCD power control */ + GPIOCC26XX_DIO_23 | GPIO_DO_NOT_CONFIG, /*LCD enable */ + +}; + +/* + * Array of callback function pointers + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC26X2R1_LAUNCH.h + * NOTE: Pins not used for interrupts can be omitted from callbacks array to + * reduce memory usage (if placed at end of gpioPinConfigs array). + */ +GPIO_CallbackFxn gpioCallbackFunctions[] = { + NULL, /* Button 0 */ + NULL, /* Button 1 */ + NULL, /* CC26X2R1_LAUNCHXL_SPI_MASTER_READY */ + NULL, /* CC26X2R1_LAUNCHXL_SPI_SLAVE_READY */ +}; + +const GPIOCC26XX_Config GPIOCC26XX_config = { + .pinConfigs = (GPIO_PinConfig *)gpioPinConfigs, + .callbacks = (GPIO_CallbackFxn *)gpioCallbackFunctions, + .numberOfPinConfigs = CC26X2R1_LAUNCHXL_GPIOCOUNT, + .numberOfCallbacks = sizeof(gpioCallbackFunctions)/sizeof(GPIO_CallbackFxn), + .intPriority = (~0) +}; + +/* + * =============================== GPTimer =============================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +#include + +GPTimerCC26XX_Object gptimerCC26XXObjects[CC26X2R1_LAUNCHXL_GPTIMERCOUNT]; + +const GPTimerCC26XX_HWAttrs gptimerCC26xxHWAttrs[CC26X2R1_LAUNCHXL_GPTIMERPARTSCOUNT] = { + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0A, }, + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0B, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1A, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1B, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2A, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2B, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3A, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3B, }, +}; + +const GPTimerCC26XX_Config GPTimerCC26XX_config[CC26X2R1_LAUNCHXL_GPTIMERPARTSCOUNT] = { + { &gptimerCC26XXObjects[CC26X2R1_LAUNCHXL_GPTIMER0], &gptimerCC26xxHWAttrs[CC26X2R1_LAUNCHXL_GPTIMER0A], GPT_A }, + { &gptimerCC26XXObjects[CC26X2R1_LAUNCHXL_GPTIMER0], &gptimerCC26xxHWAttrs[CC26X2R1_LAUNCHXL_GPTIMER0B], GPT_B }, + { &gptimerCC26XXObjects[CC26X2R1_LAUNCHXL_GPTIMER1], &gptimerCC26xxHWAttrs[CC26X2R1_LAUNCHXL_GPTIMER1A], GPT_A }, + { &gptimerCC26XXObjects[CC26X2R1_LAUNCHXL_GPTIMER1], &gptimerCC26xxHWAttrs[CC26X2R1_LAUNCHXL_GPTIMER1B], GPT_B }, + { &gptimerCC26XXObjects[CC26X2R1_LAUNCHXL_GPTIMER2], &gptimerCC26xxHWAttrs[CC26X2R1_LAUNCHXL_GPTIMER2A], GPT_A }, + { &gptimerCC26XXObjects[CC26X2R1_LAUNCHXL_GPTIMER2], &gptimerCC26xxHWAttrs[CC26X2R1_LAUNCHXL_GPTIMER2B], GPT_B }, + { &gptimerCC26XXObjects[CC26X2R1_LAUNCHXL_GPTIMER3], &gptimerCC26xxHWAttrs[CC26X2R1_LAUNCHXL_GPTIMER3A], GPT_A }, + { &gptimerCC26XXObjects[CC26X2R1_LAUNCHXL_GPTIMER3], &gptimerCC26xxHWAttrs[CC26X2R1_LAUNCHXL_GPTIMER3B], GPT_B }, +}; + +/* + * =============================== I2C =============================== +*/ +#include +#include + +I2CCC26XX_Object i2cCC26xxObjects[CC26X2R1_LAUNCHXL_I2CCOUNT]; + +const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC26X2R1_LAUNCHXL_I2CCOUNT] = { + { + .baseAddr = I2C0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_I2C0, + .intNum = INT_I2C_IRQ, + .intPriority = ~0, + .swiPriority = 0, + .sdaPin = CC26X2R1_LAUNCHXL_I2C0_SDA0, + .sclPin = CC26X2R1_LAUNCHXL_I2C0_SCL0, + } +}; + +const I2C_Config I2C_config[CC26X2R1_LAUNCHXL_I2CCOUNT] = { + { + .fxnTablePtr = &I2CCC26XX_fxnTable, + .object = &i2cCC26xxObjects[CC26X2R1_LAUNCHXL_I2C0], + .hwAttrs = &i2cCC26xxHWAttrs[CC26X2R1_LAUNCHXL_I2C0] + }, +}; + +const uint_least8_t I2C_count = CC26X2R1_LAUNCHXL_I2CCOUNT; + +/* + * =============================== NVS =============================== + */ +#include +#include +#include + +#define NVS_REGIONS_BASE 0x48000 +#define SECTORSIZE 0x2000 +#define REGIONSIZE (SECTORSIZE * 4) +#define SPISECTORSIZE 0x1000 +#define SPIREGIONSIZE (SPISECTORSIZE * 32) +#define VERIFYBUFSIZE 64 + +static uint8_t verifyBuf[VERIFYBUFSIZE]; + +/* + * Reserve flash sectors for NVS driver use by placing an uninitialized byte + * array at the desired flash address. + */ +#if defined(__TI_COMPILER_VERSION__) + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +#pragma LOCATION(flashBuf, NVS_REGIONS_BASE); +#pragma NOINIT(flashBuf); +static char flashBuf[REGIONSIZE]; + +#elif defined(__IAR_SYSTEMS_ICC__) + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +static __no_init char flashBuf[REGIONSIZE] @ NVS_REGIONS_BASE; + +#elif defined(__GNUC__) + +/* + * Place the flash buffers in the .nvs section created in the gcc linker file. + * The .nvs section enforces alignment on a sector boundary but may + * be placed anywhere in flash memory. If desired the .nvs section can be set + * to a fixed address by changing the following in the gcc linker file: + * + * .nvs (FIXED_FLASH_ADDR) (NOLOAD) : AT (FIXED_FLASH_ADDR) { + * *(.nvs) + * } > REGION_TEXT + */ +__attribute__ ((section (".nvs"))) +static char flashBuf[REGIONSIZE]; + +#endif + +/* Allocate objects for NVS and NVS SPI */ +NVSCC26XX_Object nvsCC26xxObjects[1]; +NVSSPI25X_Object nvsSPI25XObjects[1]; + +/* Hardware attributes for NVS */ +const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { + { + .regionBase = (void *)flashBuf, + .regionSize = REGIONSIZE, + }, +}; + +/* Hardware attributes for NVS SPI */ +const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { + { + .regionBaseOffset = 0, + .regionSize = SPIREGIONSIZE, + .sectorSize = SPISECTORSIZE, + .verifyBuf = verifyBuf, + .verifyBufSize = VERIFYBUFSIZE, + .spiHandle = NULL, + .spiIndex = 0, + .spiBitRate = 4000000, + .spiCsnGpioIndex = CC26X2R1_LAUNCHXL_GPIO_SPI_FLASH_CS, + }, +}; + +/* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ +const NVS_Config NVS_config[CC26X2R1_LAUNCHXL_NVSCOUNT] = { + { + .fxnTablePtr = &NVSCC26XX_fxnTable, + .object = &nvsCC26xxObjects[0], + .hwAttrs = &nvsCC26xxHWAttrs[0], + }, + { + .fxnTablePtr = &NVSSPI25X_fxnTable, + .object = &nvsSPI25XObjects[0], + .hwAttrs = &nvsSPI25XHWAttrs[0], + }, +}; + +const uint_least8_t NVS_count = CC26X2R1_LAUNCHXL_NVSCOUNT; + +/* + * =============================== PIN =============================== + */ +#include +#include + +const PIN_Config BoardGpioInitTable[] = { + + CC26X2R1_LAUNCHXL_PIN_RLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC26X2R1_LAUNCHXL_PIN_GLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC26X2R1_LAUNCHXL_PIN_BTN1 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC26X2R1_LAUNCHXL_PIN_BTN2 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC26X2R1_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ + CC26X2R1_LAUNCHXL_UART0_RX | PIN_INPUT_EN | PIN_PULLDOWN, /* UART RX via debugger back channel */ + CC26X2R1_LAUNCHXL_UART0_TX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* UART TX via debugger back channel */ + CC26X2R1_LAUNCHXL_SPI0_MOSI | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master out - slave in */ + CC26X2R1_LAUNCHXL_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master in - slave out */ + CC26X2R1_LAUNCHXL_SPI0_CLK | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI clock */ + + PIN_TERMINATE +}; + +const PINCC26XX_HWAttrs PINCC26XX_hwAttrs = { + .intPriority = ~0, + .swiPriority = 0 +}; + +/* + * =============================== Power =============================== + */ +#include +#include + +const PowerCC26X2_Config PowerCC26X2_config = { + .policyInitFxn = NULL, + .policyFxn = &PowerCC26XX_standbyPolicy, + .calibrateFxn = &PowerCC26XX_calibrate, + .enablePolicy = true, + .calibrateRCOSC_LF = true, + .calibrateRCOSC_HF = true, +}; + +/* + * =============================== PWM =============================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +#include +#include + +PWMTimerCC26XX_Object pwmtimerCC26xxObjects[CC26X2R1_LAUNCHXL_PWMCOUNT]; + +const PWMTimerCC26XX_HwAttrs pwmtimerCC26xxHWAttrs[CC26X2R1_LAUNCHXL_PWMCOUNT] = { + { .pwmPin = CC26X2R1_LAUNCHXL_PWMPIN0, .gpTimerUnit = CC26X2R1_LAUNCHXL_GPTIMER0A }, + { .pwmPin = CC26X2R1_LAUNCHXL_PWMPIN1, .gpTimerUnit = CC26X2R1_LAUNCHXL_GPTIMER0B }, + { .pwmPin = CC26X2R1_LAUNCHXL_PWMPIN2, .gpTimerUnit = CC26X2R1_LAUNCHXL_GPTIMER1A }, + { .pwmPin = CC26X2R1_LAUNCHXL_PWMPIN3, .gpTimerUnit = CC26X2R1_LAUNCHXL_GPTIMER1B }, + { .pwmPin = CC26X2R1_LAUNCHXL_PWMPIN4, .gpTimerUnit = CC26X2R1_LAUNCHXL_GPTIMER2A }, + { .pwmPin = CC26X2R1_LAUNCHXL_PWMPIN5, .gpTimerUnit = CC26X2R1_LAUNCHXL_GPTIMER2B }, + { .pwmPin = CC26X2R1_LAUNCHXL_PWMPIN6, .gpTimerUnit = CC26X2R1_LAUNCHXL_GPTIMER3A }, + { .pwmPin = CC26X2R1_LAUNCHXL_PWMPIN7, .gpTimerUnit = CC26X2R1_LAUNCHXL_GPTIMER3B }, +}; + +const PWM_Config PWM_config[CC26X2R1_LAUNCHXL_PWMCOUNT] = { + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC26X2R1_LAUNCHXL_PWM0], &pwmtimerCC26xxHWAttrs[CC26X2R1_LAUNCHXL_PWM0] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC26X2R1_LAUNCHXL_PWM1], &pwmtimerCC26xxHWAttrs[CC26X2R1_LAUNCHXL_PWM1] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC26X2R1_LAUNCHXL_PWM2], &pwmtimerCC26xxHWAttrs[CC26X2R1_LAUNCHXL_PWM2] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC26X2R1_LAUNCHXL_PWM3], &pwmtimerCC26xxHWAttrs[CC26X2R1_LAUNCHXL_PWM3] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC26X2R1_LAUNCHXL_PWM4], &pwmtimerCC26xxHWAttrs[CC26X2R1_LAUNCHXL_PWM4] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC26X2R1_LAUNCHXL_PWM5], &pwmtimerCC26xxHWAttrs[CC26X2R1_LAUNCHXL_PWM5] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC26X2R1_LAUNCHXL_PWM6], &pwmtimerCC26xxHWAttrs[CC26X2R1_LAUNCHXL_PWM6] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC26X2R1_LAUNCHXL_PWM7], &pwmtimerCC26xxHWAttrs[CC26X2R1_LAUNCHXL_PWM7] }, +}; + +const uint_least8_t PWM_count = CC26X2R1_LAUNCHXL_PWMCOUNT; + +/* + * =============================== RF Driver =============================== + */ +#include + +const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { + .hwiPriority = ~0, /* Lowest HWI priority */ + .swiPriority = 0, /* Lowest SWI priority */ + .xoscHfAlwaysNeeded = true, /* Keep XOSC dependency while in stanby */ + .globalCallback = NULL, /* No board specific callback */ + .globalEventMask = 0 /* No events subscribed to */ +}; + +/* + * =============================== SD =============================== + */ +#include +#include + +SDSPI_Object sdspiObjects[CC26X2R1_LAUNCHXL_SDCOUNT]; + +const SDSPI_HWAttrs sdspiHWAttrs[CC26X2R1_LAUNCHXL_SDCOUNT] = { + { + .spiIndex = CC26X2R1_LAUNCHXL_SPI0, + .spiCsGpioIndex = CC26X2R1_LAUNCHXL_SDSPI_CS + } +}; + +const SD_Config SD_config[CC26X2R1_LAUNCHXL_SDCOUNT] = { + { + .fxnTablePtr = &SDSPI_fxnTable, + .object = &sdspiObjects[CC26X2R1_LAUNCHXL_SDSPI0], + .hwAttrs = &sdspiHWAttrs[CC26X2R1_LAUNCHXL_SDSPI0] + }, +}; + +const uint_least8_t SD_count = CC26X2R1_LAUNCHXL_SDCOUNT; + +/* + * =============================== SPI DMA =============================== + */ +#include +#include + +SPICC26XXDMA_Object spiCC26XXDMAObjects[CC26X2R1_LAUNCHXL_SPICOUNT]; + +/* + * NOTE: The SPI instances below can be used by the SD driver to communicate + * with a SD card via SPI. The 'defaultTxBufValue' fields below are set to 0xFF + * to satisfy the SDSPI driver requirement. + */ +const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC26X2R1_LAUNCHXL_SPICOUNT] = { + { + .baseAddr = SSI0_BASE, + .intNum = INT_SSI0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .powerMngrId = PowerCC26XX_PERIPH_SSI0, + .defaultTxBufValue = 0xFF, + .rxChannelBitMask = 1< +#include + +UARTCC26XX_Object uartCC26XXObjects[CC26X2R1_LAUNCHXL_UARTCOUNT]; + +uint8_t uartCC26XXRingBuffer[CC26X2R1_LAUNCHXL_UARTCOUNT][32]; + +const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC26X2R1_LAUNCHXL_UARTCOUNT] = { + { + .baseAddr = UART0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UART0, + .intNum = INT_UART0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .txPin = CC26X2R1_LAUNCHXL_UART0_TX, + .rxPin = CC26X2R1_LAUNCHXL_UART0_RX, + .ctsPin = PIN_UNASSIGNED, + .rtsPin = PIN_UNASSIGNED, + .ringBufPtr = uartCC26XXRingBuffer[CC26X2R1_LAUNCHXL_UART0], + .ringBufSize = sizeof(uartCC26XXRingBuffer[CC26X2R1_LAUNCHXL_UART0]), + .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, + .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, + .errorFxn = NULL + }, + { + .baseAddr = UART1_BASE, + .powerMngrId = PowerCC26X2_PERIPH_UART1, + .intNum = INT_UART1_COMB, + .intPriority = ~0, + .swiPriority = 0, + .txPin = CC26X2R1_LAUNCHXL_UART1_TX, + .rxPin = CC26X2R1_LAUNCHXL_UART1_RX, + .ctsPin = PIN_UNASSIGNED, + .rtsPin = PIN_UNASSIGNED, + .ringBufPtr = uartCC26XXRingBuffer[CC26X2R1_LAUNCHXL_UART1], + .ringBufSize = sizeof(uartCC26XXRingBuffer[CC26X2R1_LAUNCHXL_UART1]), + .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, + .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, + .errorFxn = NULL + } +}; + +const UART_Config UART_config[CC26X2R1_LAUNCHXL_UARTCOUNT] = { + { + .fxnTablePtr = &UARTCC26XX_fxnTable, + .object = &uartCC26XXObjects[CC26X2R1_LAUNCHXL_UART0], + .hwAttrs = &uartCC26XXHWAttrs[CC26X2R1_LAUNCHXL_UART0] + }, + { + .fxnTablePtr = &UARTCC26XX_fxnTable, + .object = &uartCC26XXObjects[CC26X2R1_LAUNCHXL_UART1], + .hwAttrs = &uartCC26XXHWAttrs[CC26X2R1_LAUNCHXL_UART1] + }, +}; + +const uint_least8_t UART_count = CC26X2R1_LAUNCHXL_UARTCOUNT; + +/* + * =============================== UDMA =============================== + */ +#include + +UDMACC26XX_Object udmaObjects[CC26X2R1_LAUNCHXL_UDMACOUNT]; + +const UDMACC26XX_HWAttrs udmaHWAttrs[CC26X2R1_LAUNCHXL_UDMACOUNT] = { + { + .baseAddr = UDMA0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UDMA, + .intNum = INT_DMA_ERR, + .intPriority = ~0 + } +}; + +const UDMACC26XX_Config UDMACC26XX_config[CC26X2R1_LAUNCHXL_UDMACOUNT] = { + { + .object = &udmaObjects[CC26X2R1_LAUNCHXL_UDMA0], + .hwAttrs = &udmaHWAttrs[CC26X2R1_LAUNCHXL_UDMA0] + }, +}; + + + +/* + * =============================== Watchdog =============================== + */ +#include +#include + +WatchdogCC26XX_Object watchdogCC26XXObjects[CC26X2R1_LAUNCHXL_WATCHDOGCOUNT]; + +const WatchdogCC26XX_HWAttrs watchdogCC26XXHWAttrs[CC26X2R1_LAUNCHXL_WATCHDOGCOUNT] = { + { + .baseAddr = WDT_BASE, + .reloadValue = 1000 /* Reload value in milliseconds */ + }, +}; + +const Watchdog_Config Watchdog_config[CC26X2R1_LAUNCHXL_WATCHDOGCOUNT] = { + { + .fxnTablePtr = &WatchdogCC26XX_fxnTable, + .object = &watchdogCC26XXObjects[CC26X2R1_LAUNCHXL_WATCHDOG0], + .hwAttrs = &watchdogCC26XXHWAttrs[CC26X2R1_LAUNCHXL_WATCHDOG0] + }, +}; + +const uint_least8_t Watchdog_count = CC26X2R1_LAUNCHXL_WATCHDOGCOUNT; + +/* + * ======== CC26X2R1_LAUNCHXL_wakeUpExtFlash ======== + */ +void CC26X2R1_LAUNCHXL_wakeUpExtFlash(void) +{ + PIN_Config extFlashPinTable[] = { + CC26X2R1_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + /* + * To wake up we need to toggle the chip select at + * least 20 ns and ten wait at least 35 us. + */ + + /* Toggle chip select for ~20ns to wake ext. flash */ + PIN_setOutputValue(extFlashPinHandle, CC26X2R1_LAUNCHXL_SPI_FLASH_CS, 0); + /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ + CPUdelay(1); + PIN_setOutputValue(extFlashPinHandle, CC26X2R1_LAUNCHXL_SPI_FLASH_CS, 1); + /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ + CPUdelay(560); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC26X2R1_LAUNCHXL_sendExtFlashByte ======== + */ +void CC26X2R1_LAUNCHXL_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) +{ + uint8_t i; + + PIN_setOutputValue(pinHandle, CC26X2R1_LAUNCHXL_SPI_FLASH_CS, 0); + + for (i = 0; i < 8; i++) { + PIN_setOutputValue(pinHandle, CC26X2R1_LAUNCHXL_SPI0_CLK, 0); + PIN_setOutputValue(pinHandle, CC26X2R1_LAUNCHXL_SPI0_MOSI, (byte >> (7 - i)) & 0x01); + PIN_setOutputValue(pinHandle, CC26X2R1_LAUNCHXL_SPI0_CLK, 1); + + /* + * Waste a few cycles to keep the CLK high for at + * least 45% of the period. + * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. + */ + CPUdelay(8); + } + + PIN_setOutputValue(pinHandle, CC26X2R1_LAUNCHXL_SPI0_CLK, 0); + PIN_setOutputValue(pinHandle, CC26X2R1_LAUNCHXL_SPI_FLASH_CS, 1); + + /* + * Keep CS high at least 40 us + * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us + */ + CPUdelay(700); +} + +/* + * ======== CC26X2R1_LAUNCHXL_shutDownExtFlash ======== + */ +void CC26X2R1_LAUNCHXL_shutDownExtFlash(void) +{ + /* To be sure we are putting the flash into sleep and not waking it, we first have to make a wake up call */ + CC26X2R1_LAUNCHXL_wakeUpExtFlash(); + + PIN_Config extFlashPinTable[] = { + CC26X2R1_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + CC26X2R1_LAUNCHXL_SPI0_CLK | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + CC26X2R1_LAUNCHXL_SPI0_MOSI | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + CC26X2R1_LAUNCHXL_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + uint8_t extFlashShutdown = 0xB9; + + CC26X2R1_LAUNCHXL_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC26X2R1_LAUNCHXL_initGeneral ======== + */ +void CC26X2R1_LAUNCHXL_initGeneral(void) +{ + Power_init(); + + if (PIN_init(BoardGpioInitTable) != PIN_SUCCESS) { + /* Error with PIN_init */ + while (1); + } + + /* Shut down external flash as default */ + CC26X2R1_LAUNCHXL_shutDownExtFlash(); +} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h new file mode 100644 index 000000000..7fdc20e09 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h @@ -0,0 +1,424 @@ +/* + * Copyright (c) 2015-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ +/** ============================================================================ + * @file CC26X2R1_LAUNCHXL.h + * + * @brief CC26X2R1_LAUNCHXL Board Specific header file. + * + * The CC26X2R1_LAUNCHXL header file should be included in an application as + * follows: + * @code + * #include "CC26X2R1_LAUNCHXL.h" + * @endcode + * + * ============================================================================ + */ +#ifndef __CC26X2R1_LAUNCHXL_BOARD_H__ +#define __CC26X2R1_LAUNCHXL_BOARD_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes */ +#include +#include + +/* Externs */ +extern const PIN_Config BoardGpioInitTable[]; + +/* Defines */ +#define CC26X2R1_LAUNCHXL +/* Mapping of pins to board signals using general board aliases + * + */ + +/* Mapping of pins to board signals using general board aliases + * + */ + +/* Analog Capable DIOs */ +#define CC26X2R1_LAUNCHXL_DIO23_ANALOG IOID_23 +#define CC26X2R1_LAUNCHXL_DIO24_ANALOG IOID_24 +#define CC26X2R1_LAUNCHXL_DIO25_ANALOG IOID_25 +#define CC26X2R1_LAUNCHXL_DIO26_ANALOG IOID_26 +#define CC26X2R1_LAUNCHXL_DIO27_ANALOG IOID_27 +#define CC26X2R1_LAUNCHXL_DIO28_ANALOG IOID_28 +#define CC26X2R1_LAUNCHXL_DIO29_ANALOG IOID_29 +#define CC26X2R1_LAUNCHXL_DIO30_ANALOG IOID_30 + +/* Digital IOs */ +#define CC26X2R1_LAUNCHXL_DIO0 IOID_0 +#define CC26X2R1_LAUNCHXL_DIO1_RFSW IOID_1 +#define CC26X2R1_LAUNCHXL_DIO12 IOID_12 +#define CC26X2R1_LAUNCHXL_DIO15 IOID_15 +#define CC26X2R1_LAUNCHXL_DIO16_TDO IOID_16 +#define CC26X2R1_LAUNCHXL_DIO17_TDI IOID_17 +#define CC26X2R1_LAUNCHXL_DIO21 IOID_21 +#define CC26X2R1_LAUNCHXL_DIO22 IOID_22 + +/* Discrete Inputs */ +#define CC26X2R1_LAUNCHXL_PIN_BTN1 IOID_13 +#define CC26X2R1_LAUNCHXL_PIN_BTN2 IOID_14 + +/* GPIO */ +#define CC26X2R1_LAUNCHXL_GPIO_LED_ON 1 +#define CC26X2R1_LAUNCHXL_GPIO_LED_OFF 0 + +/* I2C */ +#define CC26X2R1_LAUNCHXL_I2C0_SCL0 IOID_4 +#define CC26X2R1_LAUNCHXL_I2C0_SDA0 IOID_5 + +/* LEDs */ +#define CC26X2R1_LAUNCHXL_PIN_LED_ON 1 +#define CC26X2R1_LAUNCHXL_PIN_LED_OFF 0 +#define CC26X2R1_LAUNCHXL_PIN_RLED IOID_6 +#define CC26X2R1_LAUNCHXL_PIN_GLED IOID_7 + +/* PWM Outputs */ +#define CC26X2R1_LAUNCHXL_PWMPIN0 CC26X2R1_LAUNCHXL_PIN_RLED +#define CC26X2R1_LAUNCHXL_PWMPIN1 CC26X2R1_LAUNCHXL_PIN_GLED +#define CC26X2R1_LAUNCHXL_PWMPIN2 PIN_UNASSIGNED +#define CC26X2R1_LAUNCHXL_PWMPIN3 PIN_UNASSIGNED +#define CC26X2R1_LAUNCHXL_PWMPIN4 PIN_UNASSIGNED +#define CC26X2R1_LAUNCHXL_PWMPIN5 PIN_UNASSIGNED +#define CC26X2R1_LAUNCHXL_PWMPIN6 PIN_UNASSIGNED +#define CC26X2R1_LAUNCHXL_PWMPIN7 PIN_UNASSIGNED + +/* SPI */ +#define CC26X2R1_LAUNCHXL_SPI_FLASH_CS IOID_20 +#define CC26X2R1_LAUNCHXL_FLASH_CS_ON 0 +#define CC26X2R1_LAUNCHXL_FLASH_CS_OFF 1 + +/* SPI Board */ +#define CC26X2R1_LAUNCHXL_SPI0_MISO IOID_8 /* RF1.20 */ +#define CC26X2R1_LAUNCHXL_SPI0_MOSI IOID_9 /* RF1.18 */ +#define CC26X2R1_LAUNCHXL_SPI0_CLK IOID_10 /* RF1.16 */ +#define CC26X2R1_LAUNCHXL_SPI0_CSN PIN_UNASSIGNED +#define CC26X2R1_LAUNCHXL_SPI1_MISO PIN_UNASSIGNED +#define CC26X2R1_LAUNCHXL_SPI1_MOSI PIN_UNASSIGNED +#define CC26X2R1_LAUNCHXL_SPI1_CLK PIN_UNASSIGNED +#define CC26X2R1_LAUNCHXL_SPI1_CSN PIN_UNASSIGNED + +/* UART Board */ +#define CC26X2R1_LAUNCHXL_UART0_RX IOID_2 /* RXD */ +#define CC26X2R1_LAUNCHXL_UART0_TX IOID_3 /* TXD */ +#define CC26X2R1_LAUNCHXL_UART0_CTS IOID_19 /* CTS */ +#define CC26X2R1_LAUNCHXL_UART0_RTS IOID_18 /* RTS */ +#define CC26X2R1_LAUNCHXL_UART1_RX PIN_UNASSIGNED +#define CC26X2R1_LAUNCHXL_UART1_TX PIN_UNASSIGNED +#define CC26X2R1_LAUNCHXL_UART1_CTS PIN_UNASSIGNED +#define CC26X2R1_LAUNCHXL_UART1_RTS PIN_UNASSIGNED +/* For backward compatibility */ +#define CC26X2R1_LAUNCHXL_UART_RX CC26X2R1_LAUNCHXL_UART0_RX +#define CC26X2R1_LAUNCHXL_UART_TX CC26X2R1_LAUNCHXL_UART0_TX +#define CC26X2R1_LAUNCHXL_UART_CTS CC26X2R1_LAUNCHXL_UART0_CTS +#define CC26X2R1_LAUNCHXL_UART_RTS CC26X2R1_LAUNCHXL_UART0_RTS + +/*! + * @brief Initialize the general board specific settings + * + * This function initializes the general board specific settings. + */ +void CC26X2R1_LAUNCHXL_initGeneral(void); + +/*! + * @brief Shut down the external flash present on the board files + * + * This function bitbangs the SPI sequence necessary to turn off + * the external flash on LaunchPads. + */ +void CC26X2R1_LAUNCHXL_shutDownExtFlash(void); + +/*! + * @brief Wake up the external flash present on the board files + * + * This function toggles the chip select for the amount of time needed + * to wake the chip up. + */ +void CC26X2R1_LAUNCHXL_wakeUpExtFlash(void); + + +/*! + * @def CC26X2R1_LAUNCHXL_ADCBufName + * @brief Enum of ADCs + */ +typedef enum CC26X2R1_LAUNCHXL_ADCBufName { + CC26X2R1_LAUNCHXL_ADCBUF0 = 0, + + CC26X2R1_LAUNCHXL_ADCBUFCOUNT +} CC26X2R1_LAUNCHXL_ADCBufName; + +/*! + * @def CC26X2R1_LAUNCHXL_ADCBuf0SourceName + * @brief Enum of ADCBuf channels + */ +typedef enum CC26X2R1_LAUNCHXL_ADCBuf0ChannelName { + CC26X2R1_LAUNCHXL_ADCBUF0CHANNEL0 = 0, + CC26X2R1_LAUNCHXL_ADCBUF0CHANNEL1, + CC26X2R1_LAUNCHXL_ADCBUF0CHANNEL2, + CC26X2R1_LAUNCHXL_ADCBUF0CHANNEL3, + CC26X2R1_LAUNCHXL_ADCBUF0CHANNEL4, + CC26X2R1_LAUNCHXL_ADCBUF0CHANNEL5, + CC26X2R1_LAUNCHXL_ADCBUF0CHANNEL6, + CC26X2R1_LAUNCHXL_ADCBUF0CHANNEL7, + CC26X2R1_LAUNCHXL_ADCBUF0CHANNELVDDS, + CC26X2R1_LAUNCHXL_ADCBUF0CHANNELDCOUPL, + CC26X2R1_LAUNCHXL_ADCBUF0CHANNELVSS, + + CC26X2R1_LAUNCHXL_ADCBUF0CHANNELCOUNT +} CC26X2R1_LAUNCHXL_ADCBuf0ChannelName; + +/*! + * @def CC26X2R1_LAUNCHXL_ADCName + * @brief Enum of ADCs + */ +typedef enum CC26X2R1_LAUNCHXL_ADCName { + CC26X2R1_LAUNCHXL_ADC0 = 0, + CC26X2R1_LAUNCHXL_ADC1, + CC26X2R1_LAUNCHXL_ADC2, + CC26X2R1_LAUNCHXL_ADC3, + CC26X2R1_LAUNCHXL_ADC4, + CC26X2R1_LAUNCHXL_ADC5, + CC26X2R1_LAUNCHXL_ADC6, + CC26X2R1_LAUNCHXL_ADC7, + CC26X2R1_LAUNCHXL_ADCDCOUPL, + CC26X2R1_LAUNCHXL_ADCVSS, + CC26X2R1_LAUNCHXL_ADCVDDS, + + CC26X2R1_LAUNCHXL_ADCCOUNT +} CC26X2R1_LAUNCHXL_ADCName; + +/*! + * @def CC26X2R1_LAUNCHXL_ECDHName + * @brief Enum of ECDH names + */ +typedef enum CC26X2R1_LAUNCHXL_ECDHName { + CC26X2R1_LAUNCHXL_ECDH0 = 0, + + CC26X2R1_LAUNCHXL_ECDHCOUNT +} CC26X2R1_LAUNCHXL_ECDHName; + +/*! + * @def CC26X2R1_LAUNCHXL_ECDSAName + * @brief Enum of ECDSA names + */ +typedef enum CC26X2R1_LAUNCHXL_ECDSAName { + CC26X2R1_LAUNCHXL_ECDSA0 = 0, + + CC26X2R1_LAUNCHXL_ECDSACOUNT +} CC26X2R1_LAUNCHXL_ECDSAName; + +/*! + * @def CC26X2R1_LAUNCHXL_ECJPAKEName + * @brief Enum of ECJPAKE names + */ +typedef enum CC26X2R1_LAUNCHXL_ECJPAKEName { + CC26X2R1_LAUNCHXL_ECJPAKE0 = 0, + + CC26X2R1_LAUNCHXL_ECJPAKECOUNT +} CC26X2R1_LAUNCHXL_ECJPAKEName; + +/*! + * @def CC26X2R1_LAUNCHXL_AESCCMName + * @brief Enum of AESCCM names + */ +typedef enum CC26X2R1_LAUNCHXL_AESCCMName { + CC26X2R1_LAUNCHXL_AESCCM0 = 0, + + CC26X2R1_LAUNCHXL_AESCCMCOUNT +} CC26X2R1_LAUNCHXL_AESCCMName; + +/*! + * @def CC26X2R1_LAUNCHXL_AESECBName + * @brief Enum of AESECB names + */ +typedef enum CC26X2R1_LAUNCHXL_AESECBName { + CC26X2R1_LAUNCHXL_AESECB0 = 0, + + CC26X2R1_LAUNCHXL_AESECBCOUNT +} CC26X2R1_LAUNCHXL_AESECBName; + +/*! + * @def CC26X2R1_LAUNCHXL_SHA2Name + * @brief Enum of SHA2 names + */ +typedef enum CC26X2R1_LAUNCHXL_SHA2Name { + CC26X2R1_LAUNCHXL_SHA20 = 0, + + CC26X2R1_LAUNCHXL_SHA2COUNT +} CC26X2R1_LAUNCHXL_SHA2Name; + +/*! + * @def CC26X2R1_LAUNCHXL_GPIOName + * @brief Enum of GPIO names + */ +typedef enum CC26X2R1_LAUNCHXL_GPIOName { + CC26X2R1_LAUNCHXL_GPIO_S1 = 0, + CC26X2R1_LAUNCHXL_GPIO_S2, + CC26X2R1_LAUNCHXL_SPI_MASTER_READY, + CC26X2R1_LAUNCHXL_SPI_SLAVE_READY, + CC26X2R1_LAUNCHXL_GPIO_LED_GREEN, + CC26X2R1_LAUNCHXL_GPIO_LED_RED, + CC26X2R1_LAUNCHXL_GPIO_SPI_FLASH_CS, + CC26X2R1_LAUNCHXL_SDSPI_CS, + CC26X2R1_LAUNCHXL_GPIO_LCD_CS, + CC26X2R1_LAUNCHXL_GPIO_LCD_POWER, + CC26X2R1_LAUNCHXL_GPIO_LCD_ENABLE, + CC26X2R1_LAUNCHXL_GPIOCOUNT +} CC26X2R1_LAUNCHXL_GPIOName; + +/*! + * @def CC26X2R1_LAUNCHXL_GPTimerName + * @brief Enum of GPTimer parts + */ +typedef enum CC26X2R1_LAUNCHXL_GPTimerName { + CC26X2R1_LAUNCHXL_GPTIMER0A = 0, + CC26X2R1_LAUNCHXL_GPTIMER0B, + CC26X2R1_LAUNCHXL_GPTIMER1A, + CC26X2R1_LAUNCHXL_GPTIMER1B, + CC26X2R1_LAUNCHXL_GPTIMER2A, + CC26X2R1_LAUNCHXL_GPTIMER2B, + CC26X2R1_LAUNCHXL_GPTIMER3A, + CC26X2R1_LAUNCHXL_GPTIMER3B, + + CC26X2R1_LAUNCHXL_GPTIMERPARTSCOUNT +} CC26X2R1_LAUNCHXL_GPTimerName; + +/*! + * @def CC26X2R1_LAUNCHXL_GPTimers + * @brief Enum of GPTimers + */ +typedef enum CC26X2R1_LAUNCHXL_GPTimers { + CC26X2R1_LAUNCHXL_GPTIMER0 = 0, + CC26X2R1_LAUNCHXL_GPTIMER1, + CC26X2R1_LAUNCHXL_GPTIMER2, + CC26X2R1_LAUNCHXL_GPTIMER3, + + CC26X2R1_LAUNCHXL_GPTIMERCOUNT +} CC26X2R1_LAUNCHXL_GPTimers; + +/*! + * @def CC26X2R1_LAUNCHXL_I2CName + * @brief Enum of I2C names + */ +typedef enum CC26X2R1_LAUNCHXL_I2CName { + CC26X2R1_LAUNCHXL_I2C0 = 0, + + CC26X2R1_LAUNCHXL_I2CCOUNT +} CC26X2R1_LAUNCHXL_I2CName; + +/*! + * @def CC26X2R1_LAUNCHXL_NVSName + * @brief Enum of NVS names + */ +typedef enum CC26X2R1_LAUNCHXL_NVSName { + CC26X2R1_LAUNCHXL_NVSCC26XX0 = 0, + CC26X2R1_LAUNCHXL_NVSSPI25X0, + + CC26X2R1_LAUNCHXL_NVSCOUNT +} CC26X2R1_LAUNCHXL_NVSName; + +/*! + * @def CC26X2R1_LAUNCHXL_PWM + * @brief Enum of PWM outputs + */ +typedef enum CC26X2R1_LAUNCHXL_PWMName { + CC26X2R1_LAUNCHXL_PWM0 = 0, + CC26X2R1_LAUNCHXL_PWM1, + CC26X2R1_LAUNCHXL_PWM2, + CC26X2R1_LAUNCHXL_PWM3, + CC26X2R1_LAUNCHXL_PWM4, + CC26X2R1_LAUNCHXL_PWM5, + CC26X2R1_LAUNCHXL_PWM6, + CC26X2R1_LAUNCHXL_PWM7, + + CC26X2R1_LAUNCHXL_PWMCOUNT +} CC26X2R1_LAUNCHXL_PWMName; + +/*! + * @def CC26X2R1_LAUNCHXL_SDName + * @brief Enum of SD names + */ +typedef enum CC26X2R1_LAUNCHXL_SDName { + CC26X2R1_LAUNCHXL_SDSPI0 = 0, + + CC26X2R1_LAUNCHXL_SDCOUNT +} CC26X2R1_LAUNCHXL_SDName; + +/*! + * @def CC26X2R1_LAUNCHXL_SPIName + * @brief Enum of SPI names + */ +typedef enum CC26X2R1_LAUNCHXL_SPIName { + CC26X2R1_LAUNCHXL_SPI0 = 0, + CC26X2R1_LAUNCHXL_SPI1, + + CC26X2R1_LAUNCHXL_SPICOUNT +} CC26X2R1_LAUNCHXL_SPIName; + +/*! + * @def CC26X2R1_LAUNCHXL_UARTName + * @brief Enum of UARTs + */ +typedef enum CC26X2R1_LAUNCHXL_UARTName { + CC26X2R1_LAUNCHXL_UART0 = 0, + CC26X2R1_LAUNCHXL_UART1, + + CC26X2R1_LAUNCHXL_UARTCOUNT +} CC26X2R1_LAUNCHXL_UARTName; + +/*! + * @def CC26X2R1_LAUNCHXL_UDMAName + * @brief Enum of DMA buffers + */ +typedef enum CC26X2R1_LAUNCHXL_UDMAName { + CC26X2R1_LAUNCHXL_UDMA0 = 0, + + CC26X2R1_LAUNCHXL_UDMACOUNT +} CC26X2R1_LAUNCHXL_UDMAName; + +/*! + * @def CC26X2R1_LAUNCHXL_WatchdogName + * @brief Enum of Watchdogs + */ +typedef enum CC26X2R1_LAUNCHXL_WatchdogName { + CC26X2R1_LAUNCHXL_WATCHDOG0 = 0, + + CC26X2R1_LAUNCHXL_WATCHDOGCOUNT +} CC26X2R1_LAUNCHXL_WatchdogName; + +#ifdef __cplusplus +} +#endif + +#endif /* __CC26X2R1_LAUNCHXL_BOARD_H__ */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Makefile.cc26x2r1 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Makefile.cc26x2r1 new file mode 100644 index 000000000..124fff433 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Makefile.cc26x2r1 @@ -0,0 +1,16 @@ +################################################################################ +# SimpleLink Device makefile + +SUBFAMILY = cc13x2-cc26x2 +DEVICE_FAMILY = CC26X2 + +BOARD_SOURCEFILES += CC26X2R1_LAUNCHXL.c + +SUPPORTS_PROP_MODE = 1 +SUPPORTS_IEEE_MODE = 1 + +### Signal that we can be programmed with cc2538-bsl +BOARD_SUPPORTS_BSL = 0 + +# Include the common board makefile +include $(FAMILY_PATH)/launchpad/Makefile.launchpad diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/ext-flash.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/ext-flash.c new file mode 100644 index 000000000..b985da95a --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/ext-flash.c @@ -0,0 +1,448 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup sensortag-cc26xx-ext-flash + * @{ + * + * \file + * Sensortag/LaunchPad External Flash Driver + */ +/*---------------------------------------------------------------------------*/ +#include +#include +#include +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "ext-flash.h" +#include "ti-lib.h" +/*---------------------------------------------------------------------------*/ +#include +#include +#include +/*---------------------------------------------------------------------------*/ +static SPI_Handle spiHandle = NULL; +/*---------------------------------------------------------------------------*/ +#define SPI_BIT_RATE 4000000 + +/* Instruction codes */ +#define BLS_CODE_PROGRAM 0x02 /**< Page Program */ +#define BLS_CODE_READ 0x03 /**< Read Data */ +#define BLS_CODE_READ_STATUS 0x05 /**< Read Status Register */ +#define BLS_CODE_WRITE_ENABLE 0x06 /**< Write Enable */ +#define BLS_CODE_SECTOR_ERASE 0x20 /**< Sector Erase */ +#define BLS_CODE_MDID 0x90 /**< Manufacturer Device ID */ + +#define BLS_CODE_DP 0xB9 /**< Power down */ +#define BLS_CODE_RDP 0xAB /**< Power standby */ + +/* Erase instructions */ +#define BLS_CODE_ERASE_4K 0x20 /**< Sector Erase */ +#define BLS_CODE_ERASE_32K 0x52 +#define BLS_CODE_ERASE_64K 0xD8 +#define BLS_CODE_ERASE_ALL 0xC7 /**< Mass Erase */ + +/* Bitmasks of the status register */ +#define BLS_STATUS_SRWD_BM 0x80 +#define BLS_STATUS_BP_BM 0x0C +#define BLS_STATUS_WEL_BM 0x02 +#define BLS_STATUS_WIP_BM 0x01 + +#define BLS_STATUS_BIT_BUSY 0x01 /**< Busy bit of the status register */ + +/* Part specific constants */ +#define BLS_PROGRAM_PAGE_SIZE 0x100 /**< Page size 0x100 */ +#define BLS_ERASE_SECTOR_SIZE 0x1000 /**< Sector size 0x1000 */ +/*---------------------------------------------------------------------------*/ +typedef struct +{ + uint8_t manfId; /**< Manufacturer ID */ + uint8_t devId; /**< Device ID */ +} ExtFlashInfo; +/* Supported flash devices */ +static const ExtFlashInfo supported_devices[] = +{ + { + .manfId = 0xC2, /**< Macronics MX25R1635F */ + .devId = 0x15 + }, + { + .manfId = 0xC2, /**< Macronics MX25R8035F */ + .devId = 0x14 + }, + { + .manfId = 0xEF, /**< WinBond W25X40CL */ + .devId = 0x12 + }, + { + .manfId = 0xEF, /**< WinBond W25X20CL */ + .devId = 0x11 + } +}; +/*---------------------------------------------------------------------------*/ +static bool +spi_write(const uint8_t *buf, size_t len) +{ + SPI_Transaction spiTransaction; + spiTransaction.count = len; + spiTransaction.txBuf = (void *)buf; + spiTransaction.rxBuf = NULL; + + return SPI_transfer(spiHandle, &spiTransaction); +} +/*---------------------------------------------------------------------------*/ +static bool +spi_read(uint8_t *buf, size_t len) +{ + SPI_Transaction spiTransaction; + spiTransaction.count = len; + spiTransaction.txBuf = NULL; + spiTransaction.rxBuf = buf; + + return SPI_transfer(spiHandle, &spiTransaction); +} +/*---------------------------------------------------------------------------*/ +static void +select(void) +{ + ti_lib_gpio_clear_dio(Board_SPI_FLASH_CS); +} +/*---------------------------------------------------------------------------*/ +static void +deselect(void) +{ + ti_lib_gpio_set_dio(Board_SPI_FLASH_CS); +} +/*---------------------------------------------------------------------------*/ +static bool +wait_ready(void) +{ + const uint8_t wbuf[] = { BLS_CODE_READ_STATUS }; + uint8_t rbuf[1] = { 0x0 }; + + /* TODO are 1000 tries enough? */ + for (size_t i = 0; i < 1000; ++i) { + select(); + + const bool spi_ok = spi_write(wbuf, sizeof(wbuf)) + && spi_read(rbuf, sizeof(rbuf)); + + deselect(); + + if (!spi_ok) { + /* Error */ + return false; + } + if (!(rbuf[0] & BLS_STATUS_BIT_BUSY)) { + /* Now ready */ + return true; + } + } + + return false; +} +/*---------------------------------------------------------------------------*/ +static bool +power_standby(void) +{ + const uint8_t cmd[] = { BLS_CODE_RDP }; + + select(); + + const bool spi_ok = spi_write(cmd, sizeof(cmd)); + + deselect(); + + if (!spi_ok) { + return false; + } + + /* Waking up of the device is manufacturer dependent. + * for a Winond chip-set, once the request to wake up the flash has been + * send, CS needs to stay high at least 3us (for Winbond part) + * for chip-set like Macronix, it can take up to 35us. + * 3 cycles per loop: 560 loops @ 48 MHz = 35 us */ + ti_lib_cpu_delay(560); + + return wait_ready(); +} +/*---------------------------------------------------------------------------*/ +static bool +power_down(void) +{ + const uint8_t cmd[] = { BLS_CODE_DP }; + + select(); + + const bool spi_ok = spi_write(cmd, sizeof(cmd)); + + deselect(); + + return spi_ok; +} +/*---------------------------------------------------------------------------*/ +static bool +write_enable(void) +{ + const uint8_t wbuf[] = { BLS_CODE_WRITE_ENABLE }; + + select(); + + const bool spi_ok = spi_write(wbuf, sizeof(wbuf)); + + deselect(); + + return spi_ok; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Verify the flash part. + * \retval bool true on success; else, false + */ +static bool +verify_part(void) +{ + const uint8_t wbuf[] = { BLS_CODE_MDID, 0xFF, 0xFF, 0x00 }; + uint8_t rbuf[2] = { 0x0 }; + + const bool spi_ok = spi_write(wbuf, sizeof(wbuf)) + && spi_read(rbuf, sizeof(rbuf)); + + if (!spi_ok) { + return false; + } + + const ExtFlashInfo curr_device = { + .manfId = rbuf[0], + .devId = rbuf[1] + }; + + const size_t num_devices = sizeof(supported_devices) / sizeof(supported_devices[0]); + for (size_t i = 0; i < num_devices; ++i) { + if (curr_device.manfId == supported_devices[i].manfId && + curr_device.devId == supported_devices[i].devId) { + return true; + } + } + + return false; +} +/*---------------------------------------------------------------------------*/ +bool +ext_flash_open() +{ + if (spiHandle != NULL) { + return false; + } + + SPI_Params spiParams; + SPI_Params_init(&spiParams); + spiParams.bitRate = SPI_BIT_RATE; + spiParams.mode = SPI_MASTER; + spiParams.transferMode = SPI_MODE_BLOCKING; + + spiHandle = SPI_open(Board_SPI0, &spiParams); + + if (spiHandle == NULL) { + return false; + } + + ti_lib_ioc_pin_type_gpio_output(Board_SPI_FLASH_CS); + deselect(); + + const bool is_powered = power_standby(); + if (!is_powered) { + ext_flash_close(); + return false; + } + + return verify_part(); +} +/*---------------------------------------------------------------------------*/ +void +ext_flash_close() +{ + if (spiHandle == NULL) { + return; + } + + power_down(); + SPI_close(spiHandle); +} +/*---------------------------------------------------------------------------*/ +bool +ext_flash_read(size_t offset, size_t length, uint8_t *buf) +{ + if (spiHandle == NULL || buf == NULL) { + return false; + } + + if (length == 0) { + return true; + } + + const bool is_ready = wait_ready(); + if (!is_ready) { + return false; + } + + const uint8_t wbuf[] = { + BLS_CODE_READ, + (offset >> 16) & 0xFF, + (offset >> 8) & 0xFF, + (offset >> 0) & 0xFF, + }; + + select(); + + const bool spi_ok = spi_write(wbuf, sizeof(wbuf)) + && spi_read(buf, length); + + deselect(); + + return (spi_ok); +} +/*---------------------------------------------------------------------------*/ +bool +ext_flash_write(size_t offset, size_t length, const uint8_t *buf) +{ + if (spiHandle == NULL || buf == NULL) { + return false; + } + + uint8_t wbuf[4] = { BLS_CODE_PROGRAM, 0, 0, 0 }; + + while (length > 0) + { + /* Wait till previous erase/program operation completes */ + if (!wait_ready()) { + return false; + } + + /* Enable writing */ + if (!write_enable()) { + return false; + } + + /* Interim length per instruction */ + size_t ilen = BLS_PROGRAM_PAGE_SIZE - (offset % BLS_PROGRAM_PAGE_SIZE); + if (length < ilen) { + ilen = length; + } + + wbuf[1] = (offset >> 16) & 0xFF; + wbuf[2] = (offset >> 8) & 0xFF; + wbuf[3] = (offset >> 0) & 0xFF; + + offset += ilen; + length -= ilen; + + /* Up to 100ns CS hold time (which is not clear + * whether it's application only in between reads) + * is not imposed here since above instructions + * should be enough to delay + * as much. */ + select(); + + const bool spi_ok = spi_write(wbuf, sizeof(wbuf)) + && spi_write(buf, ilen); + + buf += ilen; + + deselect(); + + if (!spi_ok) { + return false; + } + } + + return true; +} +/*---------------------------------------------------------------------------*/ +bool +ext_flash_erase(size_t offset, size_t length) +{ + /* Note that Block erase might be more efficient when the floor map + * is well planned for OTA but to simplify for the temporary implemetation, + * sector erase is used blindly. */ + uint8_t wbuf[4] = { BLS_CODE_SECTOR_ERASE, 0x0, 0x0, 0x0 }; + + const size_t endoffset = offset + length - 1; + offset = (offset / BLS_ERASE_SECTOR_SIZE) * BLS_ERASE_SECTOR_SIZE; + const size_t numsectors = (endoffset - offset + BLS_ERASE_SECTOR_SIZE - 1) / BLS_ERASE_SECTOR_SIZE; + + for (size_t i = 0; i < numsectors; ++i) { + /* Wait till previous erase/program operation completes */ + if (!wait_ready()) { + return false; + } + + /* Enable writing */ + if (!write_enable()) { + return false; + } + + wbuf[1] = (offset >> 16) & 0xFF; + wbuf[2] = (offset >> 8) & 0xFF; + wbuf[3] = (offset >> 0) & 0xFF; + + select(); + + const bool spi_ok = spi_write(wbuf, sizeof(wbuf)); + + deselect(); + + if (!spi_ok) { + return false; + } + + offset += BLS_ERASE_SECTOR_SIZE; + } + + return true; +} +/*---------------------------------------------------------------------------*/ +bool +ext_flash_test(void) +{ + const bool ret = ext_flash_open(); + ext_flash_close(); + + return ret; +} +/*---------------------------------------------------------------------------*/ +void +ext_flash_init() +{ + GPIO_init(); + SPI_init(); +} +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/ext-flash.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/ext-flash.h new file mode 100644 index 000000000..5f2717edb --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/ext-flash.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup common-cc26xx-peripherals + * @{ + * + * \defgroup sensortag-cc26xx-ext-flash SensorTag/LaunchPad External Flash + * @{ + * + * \file + * Header file for the Sensortag/LaunchPad External Flash Driver + */ +/*---------------------------------------------------------------------------*/ +#ifndef EXT_FLASH_H_ +#define EXT_FLASH_H_ +/*---------------------------------------------------------------------------*/ +#include +#include +#include +/*---------------------------------------------------------------------------*/ +/** + * \brief Initialize storage driver. + * \return True when successful. + */ +bool ext_flash_open(void); + +/** + * \brief Close the storage driver + * + * This call will put the device in its lower power mode (power down). + */ +void ext_flash_close(void); + +/** + * \brief Read storage content + * \param offset Address to read from + * \param length Number of bytes to read + * \param buf Buffer where to store the read bytes + * \return True when successful. + * + * buf must be allocated by the caller + */ +bool ext_flash_read(size_t offset, size_t length, uint8_t *buf); + +/** + * \brief Erase storage sectors corresponding to the range. + * \param offset Address to start erasing + * \param length Number of bytes to erase + * \return True when successful. + * + * The erase operation will be sector-wise, therefore a call to this function + * will generally start the erase procedure at an address lower than offset + */ +bool ext_flash_erase(size_t offset, size_t length); + +/** + * \brief Write to storage sectors. + * \param offset Address to write to + * \param length Number of bytes to write + * \param buf Buffer holding the bytes to be written + * + * \return True when successful. + */ +bool ext_flash_write(size_t offset, size_t length, const uint8_t *buf); + +/** + * \brief Test the flash (power on self-test) + * \return True when successful. + */ +bool ext_flash_test(void); + +/** + * \brief Initialise the external flash + * + * This function will explicitly put the part in its lowest power mode + * (power-down). + * + * In order to perform any operation, the caller must first wake the device + * up by calling ext_flash_open() + */ +void ext_flash_init(void); +/*---------------------------------------------------------------------------*/ +#endif /* EXT_FLASH_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/platform/simplelink/cc13x2-cc26x2/launchpad/launchpad-sensors.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/launchpad-sensors.c similarity index 100% rename from arch/platform/simplelink/cc13x2-cc26x2/launchpad/launchpad-sensors.c rename to arch/platform/simplelink/cc13xx-cc26xx/launchpad/launchpad-sensors.c diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/launchpad.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/launchpad.c new file mode 100644 index 000000000..469dea72d --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/launchpad.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup launchpad-peripherals + * @{ + * + * \file + * LaunchPad-specific board initialisation driver + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +/*---------------------------------------------------------------------------*/ +#include "Board.h" +#include "ti/drivers/dpl/HwiP.h" +/*---------------------------------------------------------------------------*/ +#include +#include +#include +/*---------------------------------------------------------------------------*/ +void +board_init() +{ + /* Disable interrupts */ + const uintptr_t key = HwiP_disable(); + + Board_initGeneral(); + Board_shutDownExtFlash(); + + /* Restore interrupts. */ + HwiP_restore(key); +} +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13x0-cc26x0/launchpad/leds-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/leds-arch.c similarity index 100% rename from arch/platform/simplelink/cc13x0-cc26x0/launchpad/leds-arch.c rename to arch/platform/simplelink/cc13xx-cc26xx/launchpad/leds-arch.c diff --git a/arch/platform/simplelink/cc13x0-cc26x0/platform.c b/arch/platform/simplelink/cc13xx-cc26xx/platform.c similarity index 100% rename from arch/platform/simplelink/cc13x0-cc26x0/platform.c rename to arch/platform/simplelink/cc13xx-cc26xx/platform.c diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/Makefile.sensortag b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/Makefile.sensortag new file mode 100644 index 000000000..49d892f54 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/Makefile.sensortag @@ -0,0 +1,10 @@ +################################################################################ +# SimpleLink LaunchPad makefile + +BOARD_TYPE = BOARD_SENSORTAG + +# leds-arch.c/h etc. +BOARD_SOURCEFILES += sensortag.c sensortag-sensors.c +BOARD_SOURCEFILES += button-sensor-arch.c leds-arch.c + +TARGET_FAMILY_DIRS += sensortag \ No newline at end of file diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c new file mode 100644 index 000000000..e27a54610 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c @@ -0,0 +1,392 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup sensortag-cc26xx-bmp-sensor + * @{ + * + * \file + * Driver for the Sensortag BMP280 Altimeter / Pressure Sensor + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "lib/sensors.h" +#include "bmp-280-sensor.h" +#include "sys/ctimer.h" +#include "sensor-common.h" +#include "board-i2c.h" +#include "ti-lib.h" + +#include +#include +#include +/*---------------------------------------------------------------------------*/ +#define DEBUG 0 +#if DEBUG +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif +/*---------------------------------------------------------------------------*/ +#define BMP280_I2C_ADDRESS 0x77 +/*---------------------------------------------------------------------------*/ +/* Registers */ +#define ADDR_CALIB 0x88 +#define ADDR_PROD_ID 0xD0 +#define ADDR_RESET 0xE0 +#define ADDR_STATUS 0xF3 +#define ADDR_CTRL_MEAS 0xF4 +#define ADDR_CONFIG 0xF5 +#define ADDR_PRESS_MSB 0xF7 +#define ADDR_PRESS_LSB 0xF8 +#define ADDR_PRESS_XLSB 0xF9 +#define ADDR_TEMP_MSB 0xFA +#define ADDR_TEMP_LSB 0xFB +#define ADDR_TEMP_XLSB 0xFC +/*---------------------------------------------------------------------------*/ +/* Reset values */ +#define VAL_PROD_ID 0x58 +#define VAL_RESET 0x00 +#define VAL_STATUS 0x00 +#define VAL_CTRL_MEAS 0x00 +#define VAL_CONFIG 0x00 +#define VAL_PRESS_MSB 0x80 +#define VAL_PRESS_LSB 0x00 +#define VAL_TEMP_MSB 0x80 +#define VAL_TEMP_LSB 0x00 +/*---------------------------------------------------------------------------*/ +/* Test values */ +#define VAL_RESET_EXECUTE 0xB6 +#define VAL_CTRL_MEAS_TEST 0x55 +/*---------------------------------------------------------------------------*/ +/* Misc. */ +#define MEAS_DATA_SIZE 6 +#define CALIB_DATA_SIZE 24 +/*---------------------------------------------------------------------------*/ +#define RES_OFF 0 +#define RES_ULTRA_LOW_POWER 1 +#define RES_LOW_POWER 2 +#define RES_STANDARD 3 +#define RES_HIGH 5 +#define RES_ULTRA_HIGH 6 +/*---------------------------------------------------------------------------*/ +/* Bit fields in CTRL_MEAS register */ +#define PM_OFF 0 +#define PM_FORCED 1 +#define PM_NORMAL 3 +/*---------------------------------------------------------------------------*/ +#define OSRST(v) ((v) << 5) +#define OSRSP(v) ((v) << 2) +/*---------------------------------------------------------------------------*/ +typedef struct bmp_280_calibration { + uint16_t dig_t1; + int16_t dig_t2; + int16_t dig_t3; + uint16_t dig_p1; + int16_t dig_p2; + int16_t dig_p3; + int16_t dig_p4; + int16_t dig_p5; + int16_t dig_p6; + int16_t dig_p7; + int16_t dig_p8; + int16_t dig_p9; + int32_t t_fine; +} bmp_280_calibration_t; +/*---------------------------------------------------------------------------*/ +static uint8_t calibration_data[CALIB_DATA_SIZE]; +/*---------------------------------------------------------------------------*/ +#define SENSOR_STATUS_DISABLED 0 +#define SENSOR_STATUS_INITIALISED 1 +#define SENSOR_STATUS_NOT_READY 2 +#define SENSOR_STATUS_READY 3 + +static int enabled = SENSOR_STATUS_DISABLED; +/*---------------------------------------------------------------------------*/ +/* A buffer for the raw reading from the sensor */ +#define SENSOR_DATA_BUF_SIZE 6 + +static uint8_t sensor_value[SENSOR_DATA_BUF_SIZE]; +/*---------------------------------------------------------------------------*/ +/* Wait SENSOR_STARTUP_DELAY clock ticks for the sensor to be ready - ~80ms */ +#define SENSOR_STARTUP_DELAY 3 + +static struct ctimer startup_timer; +/*---------------------------------------------------------------------------*/ +static void +notify_ready(void *not_used) +{ + enabled = SENSOR_STATUS_READY; + sensors_changed(&bmp_280_sensor); +} +/*---------------------------------------------------------------------------*/ +static void +select_on_bus(void) +{ + /* Set up I2C */ + board_i2c_select(BOARD_I2C_INTERFACE_0, BMP280_I2C_ADDRESS); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Initalise the sensor + */ +static void +init(void) +{ + uint8_t val; + + select_on_bus(); + + /* Read and store calibration data */ + sensor_common_read_reg(ADDR_CALIB, calibration_data, CALIB_DATA_SIZE); + + /* Reset the sensor */ + val = VAL_RESET_EXECUTE; + sensor_common_write_reg(ADDR_RESET, &val, sizeof(val)); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Enable/disable measurements + * \param enable 0: disable, enable otherwise + * + * @return none + */ +static void +enable_sensor(bool enable) +{ + uint8_t val; + + select_on_bus(); + + if(enable) { + /* Enable forced mode */ + val = PM_FORCED | OSRSP(1) | OSRST(1); + } else { + val = PM_OFF; + } + sensor_common_write_reg(ADDR_CTRL_MEAS, &val, sizeof(val)); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Read temperature and pressure data + * \param data Pointer to a buffer where temperature and pressure will be + * written (6 bytes) + * \return True if valid data could be retrieved + */ +static bool +read_data(uint8_t *data) +{ + bool success; + + select_on_bus(); + + success = sensor_common_read_reg(ADDR_PRESS_MSB, data, MEAS_DATA_SIZE); + if(!success) { + sensor_common_set_error_data(data, MEAS_DATA_SIZE); + } + + return success; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Convert raw data to values in degrees C (temp) and Pascal (pressure) + * \param data Pointer to a buffer that holds raw sensor data + * \param temp Pointer to a variable where the converted temperature will be + * written + * \param press Pointer to a variable where the converted pressure will be + * written + */ +static void +convert(uint8_t *data, int32_t *temp, uint32_t *press) +{ + int32_t utemp, upress; + bmp_280_calibration_t *p = (bmp_280_calibration_t *)calibration_data; + int32_t v_x1_u32r; + int32_t v_x2_u32r; + int32_t temperature; + uint32_t pressure; + + /* Pressure */ + upress = (int32_t)((((uint32_t)(data[0])) << 12) + | (((uint32_t)(data[1])) << 4) | ((uint32_t)data[2] >> 4)); + + /* Temperature */ + utemp = (int32_t)((((uint32_t)(data[3])) << 12) | (((uint32_t)(data[4])) << 4) + | ((uint32_t)data[5] >> 4)); + + /* Compensate temperature */ + v_x1_u32r = ((((utemp >> 3) - ((int32_t)p->dig_t1 << 1))) + * ((int32_t)p->dig_t2)) >> 11; + v_x2_u32r = (((((utemp >> 4) - ((int32_t)p->dig_t1)) + * ((utemp >> 4) - ((int32_t)p->dig_t1))) >> 12) + * ((int32_t)p->dig_t3)) + >> 14; + p->t_fine = v_x1_u32r + v_x2_u32r; + temperature = (p->t_fine * 5 + 128) >> 8; + *temp = temperature; + + /* Compensate pressure */ + v_x1_u32r = (((int32_t)p->t_fine) >> 1) - (int32_t)64000; + v_x2_u32r = (((v_x1_u32r >> 2) * (v_x1_u32r >> 2)) >> 11) + * ((int32_t)p->dig_p6); + v_x2_u32r = v_x2_u32r + ((v_x1_u32r * ((int32_t)p->dig_p5)) << 1); + v_x2_u32r = (v_x2_u32r >> 2) + (((int32_t)p->dig_p4) << 16); + v_x1_u32r = + (((p->dig_p3 * (((v_x1_u32r >> 2) * (v_x1_u32r >> 2)) >> 13)) >> 3) + + ((((int32_t)p->dig_p2) * v_x1_u32r) >> 1)) >> 18; + v_x1_u32r = ((((32768 + v_x1_u32r)) * ((int32_t)p->dig_p1)) >> 15); + + if(v_x1_u32r == 0) { + return; /* Avoid exception caused by division by zero */ + } + + pressure = (((uint32_t)(((int32_t)1048576) - upress) - (v_x2_u32r >> 12))) + * 3125; + if(pressure < 0x80000000) { + pressure = (pressure << 1) / ((uint32_t)v_x1_u32r); + } else { + pressure = (pressure / (uint32_t)v_x1_u32r) * 2; + } + + v_x1_u32r = (((int32_t)p->dig_p9) + * ((int32_t)(((pressure >> 3) * (pressure >> 3)) >> 13))) >> 12; + v_x2_u32r = (((int32_t)(pressure >> 2)) * ((int32_t)p->dig_p8)) >> 13; + pressure = (uint32_t)((int32_t)pressure + + ((v_x1_u32r + v_x2_u32r + p->dig_p7) >> 4)); + + *press = pressure; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Returns a reading from the sensor + * \param type BMP_280_SENSOR_TYPE_TEMP or BMP_280_SENSOR_TYPE_PRESS + * \return Temperature (centi degrees C) or Pressure (Pascal). + */ +static int +value(int type) +{ + int rv; + int32_t temp = 0; + uint32_t pres = 0; + + if(enabled != SENSOR_STATUS_READY) { + PRINTF("Sensor disabled or starting up (%d)\n", enabled); + return CC26XX_SENSOR_READING_ERROR; + } + + if((type != BMP_280_SENSOR_TYPE_TEMP) && type != BMP_280_SENSOR_TYPE_PRESS) { + PRINTF("Invalid type\n"); + return CC26XX_SENSOR_READING_ERROR; + } else { + memset(sensor_value, 0, SENSOR_DATA_BUF_SIZE); + + rv = read_data(sensor_value); + + if(rv == 0) { + return CC26XX_SENSOR_READING_ERROR; + } + + PRINTF("val: %02x%02x%02x %02x%02x%02x\n", + sensor_value[0], sensor_value[1], sensor_value[2], + sensor_value[3], sensor_value[4], sensor_value[5]); + + convert(sensor_value, &temp, &pres); + + if(type == BMP_280_SENSOR_TYPE_TEMP) { + rv = (int)temp; + } else if(type == BMP_280_SENSOR_TYPE_PRESS) { + rv = (int)pres; + } + } + return rv; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Configuration function for the BMP280 sensor. + * + * \param type Activate, enable or disable the sensor. See below + * \param enable + * + * When type == SENSORS_HW_INIT we turn on the hardware + * When type == SENSORS_ACTIVE and enable==1 we enable the sensor + * When type == SENSORS_ACTIVE and enable==0 we disable the sensor + */ +static int +configure(int type, int enable) +{ + switch(type) { + case SENSORS_HW_INIT: + enabled = SENSOR_STATUS_INITIALISED; + init(); + enable_sensor(0); + break; + case SENSORS_ACTIVE: + /* Must be initialised first */ + if(enabled == SENSOR_STATUS_DISABLED) { + return SENSOR_STATUS_DISABLED; + } + if(enable) { + enable_sensor(1); + ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready, NULL); + enabled = SENSOR_STATUS_NOT_READY; + } else { + ctimer_stop(&startup_timer); + enable_sensor(0); + enabled = SENSOR_STATUS_INITIALISED; + } + break; + default: + break; + } + return enabled; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Returns the status of the sensor + * \param type SENSORS_ACTIVE or SENSORS_READY + * \return 1 if the sensor is enabled + */ +static int +status(int type) +{ + switch(type) { + case SENSORS_ACTIVE: + case SENSORS_READY: + return enabled; + break; + default: + break; + } + return SENSOR_STATUS_DISABLED; +} +/*---------------------------------------------------------------------------*/ +SENSORS_SENSOR(bmp_280_sensor, "BMP280", value, configure, status); +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.h new file mode 100644 index 000000000..0047aaa9a --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup sensortag-cc26xx-peripherals + * @{ + * + * \defgroup sensortag-cc26xx-bmp-sensor SensorTag 2.0 Pressure Sensor + * + * Due to the time required for the sensor to startup, this driver is meant to + * be used in an asynchronous fashion. The caller must first activate the + * sensor by calling SENSORS_ACTIVATE(). This will trigger the sensor's startup + * sequence, but the call will not wait for it to complete so that the CPU can + * perform other tasks or drop to a low power mode. + * + * Once the sensor is stable, the driver will generate a sensors_changed event. + * + * We take readings in "Forced" mode. In this mode, the BMP will take a single + * measurement and it will then automatically go to sleep. + * + * SENSORS_ACTIVATE must be called again to trigger a new reading cycle + * @{ + * + * \file + * Header file for the Sensortag BMP280 Altimeter / Pressure Sensor + */ +/*---------------------------------------------------------------------------*/ +#ifndef BMP_280_SENSOR_H_ +#define BMP_280_SENSOR_H_ +/*---------------------------------------------------------------------------*/ +#define BMP_280_SENSOR_TYPE_TEMP 1 +#define BMP_280_SENSOR_TYPE_PRESS 2 +/*---------------------------------------------------------------------------*/ +extern const struct sensors_sensor bmp_280_sensor; +/*---------------------------------------------------------------------------*/ +#endif /* BMP_280_SENSOR_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-i2c.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-i2c.c new file mode 100644 index 000000000..cc30e0fb0 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-i2c.c @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2017, University of Bristol - http://www.bris.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 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup sensortag-cc26xx-i2c + * @{ + * + * \file + * Board-specific I2C driver for the Sensortags + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "ti-lib.h" +#include "board-i2c.h" +#include "lpm.h" +#include "rtimer.h" + +#include +#include +/*---------------------------------------------------------------------------*/ +#define I2C_MAX_WAIT_TIME (RTIMER_SECOND / 10) + +#define LIMITED_BUSYWAIT(cond) do { \ + rtimer_clock_t end_time = RTIMER_NOW() + I2C_MAX_WAIT_TIME; \ + while(cond) { \ + if(!RTIMER_CLOCK_LT(RTIMER_NOW(), end_time)) { \ + return false; \ + } \ + } \ + } while(0) +/*---------------------------------------------------------------------------*/ +#define NO_INTERFACE 0xFF +/*---------------------------------------------------------------------------*/ +static uint8_t slave_addr = 0x00; +static uint8_t interface = NO_INTERFACE; +/*---------------------------------------------------------------------------*/ +static bool +accessible(void) +{ + /* First, check the PD */ + if(ti_lib_prcm_power_domain_status(PRCM_DOMAIN_SERIAL) + != PRCM_DOMAIN_POWER_ON) { + return false; + } + + /* Then check the 'run mode' clock gate */ + if(!(HWREG(PRCM_BASE + PRCM_O_I2CCLKGR) & PRCM_I2CCLKGR_CLK_EN)) { + return false; + } + + return true; +} +/*---------------------------------------------------------------------------*/ +void +board_i2c_wakeup() +{ + /* First, make sure the SERIAL PD is on */ + ti_lib_prcm_power_domain_on(PRCM_DOMAIN_SERIAL); + while((ti_lib_prcm_power_domain_status(PRCM_DOMAIN_SERIAL) + != PRCM_DOMAIN_POWER_ON)); + + /* Enable the clock to I2C */ + ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_I2C0); + ti_lib_prcm_load_set(); + while(!ti_lib_prcm_load_get()); + + /* Enable and initialize the I2C master module */ + ti_lib_i2c_master_init_exp_clk(I2C0_BASE, ti_lib_sys_ctrl_clock_get(), + true); +} +/*---------------------------------------------------------------------------*/ +static bool +i2c_status() +{ + uint32_t status; + + status = ti_lib_i2c_master_err(I2C0_BASE); + if(status & (I2C_MSTAT_DATACK_N_M | I2C_MSTAT_ADRACK_N_M)) { + ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_ERROR_STOP); + } + + return status == I2C_MASTER_ERR_NONE; +} +/*---------------------------------------------------------------------------*/ +void +board_i2c_shutdown() +{ + interface = NO_INTERFACE; + + if(accessible()) { + ti_lib_i2c_master_disable(I2C0_BASE); + } + + ti_lib_prcm_peripheral_run_disable(PRCM_PERIPH_I2C0); + ti_lib_prcm_load_set(); + while(!ti_lib_prcm_load_get()); + + /* + * Set all pins to GPIO Input and disable the output driver. Set internal + * pull to match external pull + * + * SDA and SCL: external PU resistor + * SDA HP and SCL HP: MPU PWR low + */ + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SDA_HP); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_SDA_HP, IOC_IOPULL_DOWN); + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SCL_HP); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_SCL_HP, IOC_IOPULL_DOWN); + + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SDA); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_SDA, IOC_IOPULL_UP); + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SCL); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_SCL, IOC_IOPULL_UP); +} +/*---------------------------------------------------------------------------*/ +bool +board_i2c_write(uint8_t *data, uint8_t len) +{ + uint32_t i; + bool success; + + /* Write slave address */ + ti_lib_i2c_master_slave_addr_set(I2C0_BASE, slave_addr, false); + + /* Write first byte */ + ti_lib_i2c_master_data_put(I2C0_BASE, data[0]); + + /* Check if another master has access */ + LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE)); + + /* Assert RUN + START */ + ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START); + LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE)); + success = i2c_status(); + + for(i = 1; i < len && success; i++) { + /* Write next byte */ + ti_lib_i2c_master_data_put(I2C0_BASE, data[i]); + if(i < len - 1) { + /* Clear START */ + ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_CONT); + LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE)); + success = i2c_status(); + } + } + + /* Assert stop */ + if(success) { + /* Assert STOP */ + ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH); + LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE)); + success = i2c_status(); + LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE)); + } + + return success; +} +/*---------------------------------------------------------------------------*/ +bool +board_i2c_write_single(uint8_t data) +{ + /* Write slave address */ + ti_lib_i2c_master_slave_addr_set(I2C0_BASE, slave_addr, false); + + /* Write first byte */ + ti_lib_i2c_master_data_put(I2C0_BASE, data); + + /* Check if another master has access */ + LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE)); + + /* Assert RUN + START + STOP */ + ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_SINGLE_SEND); + LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE)); + + return i2c_status(); +} +/*---------------------------------------------------------------------------*/ +bool +board_i2c_read(uint8_t *data, uint8_t len) +{ + uint8_t i; + bool success; + + /* Set slave address */ + ti_lib_i2c_master_slave_addr_set(I2C0_BASE, slave_addr, true); + + /* Check if another master has access */ + LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE)); + + /* Assert RUN + START + ACK */ + ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_START); + + i = 0; + success = true; + while(i < (len - 1) && success) { + LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE)); + success = i2c_status(); + if(success) { + data[i] = ti_lib_i2c_master_data_get(I2C0_BASE); + ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT); + i++; + } + } + + if(success) { + ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH); + LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE)); + success = i2c_status(); + if(success) { + data[len - 1] = ti_lib_i2c_master_data_get(I2C0_BASE); + LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE)); + } + } + + return success; +} +/*---------------------------------------------------------------------------*/ +bool +board_i2c_write_read(uint8_t *wdata, uint8_t wlen, uint8_t *rdata, uint8_t rlen) +{ + uint32_t i; + bool success; + + /* Set slave address for write */ + ti_lib_i2c_master_slave_addr_set(I2C0_BASE, slave_addr, false); + + /* Write first byte */ + ti_lib_i2c_master_data_put(I2C0_BASE, wdata[0]); + + /* Check if another master has access */ + LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE)); + + /* Assert RUN + START */ + ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START); + LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE)); + success = i2c_status(); + + for(i = 1; i < wlen && success; i++) { + /* Write next byte */ + ti_lib_i2c_master_data_put(I2C0_BASE, wdata[i]); + + /* Clear START */ + ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_CONT); + LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE)); + success = i2c_status(); + } + if(!success) { + return false; + } + + /* Set slave address for read */ + ti_lib_i2c_master_slave_addr_set(I2C0_BASE, slave_addr, true); + + /* Assert ACK */ + ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_START); + + i = 0; + while(i < (rlen - 1) && success) { + LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE)); + success = i2c_status(); + if(success) { + rdata[i] = ti_lib_i2c_master_data_get(I2C0_BASE); + ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT); + i++; + } + } + + if(success) { + ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH); + LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE)); + success = i2c_status(); + if(success) { + rdata[rlen - 1] = ti_lib_i2c_master_data_get(I2C0_BASE); + LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE)); + } + } + + return success; +} +/*---------------------------------------------------------------------------*/ +void +board_i2c_select(uint8_t new_interface, uint8_t address) +{ + slave_addr = address; + + if(accessible() == false) { + board_i2c_wakeup(); + } + + if(new_interface != interface) { + interface = new_interface; + + ti_lib_i2c_master_disable(I2C0_BASE); + + if(interface == BOARD_I2C_INTERFACE_0) { + ti_lib_ioc_io_port_pull_set(BOARD_IOID_SDA, IOC_NO_IOPULL); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_SCL, IOC_NO_IOPULL); + ti_lib_ioc_pin_type_i2c(I2C0_BASE, BOARD_IOID_SDA, BOARD_IOID_SCL); + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SDA_HP); + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SCL_HP); + } else if(interface == BOARD_I2C_INTERFACE_1) { + ti_lib_ioc_io_port_pull_set(BOARD_IOID_SDA_HP, IOC_NO_IOPULL); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_SCL_HP, IOC_NO_IOPULL); + ti_lib_ioc_pin_type_i2c(I2C0_BASE, BOARD_IOID_SDA_HP, BOARD_IOID_SCL_HP); + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SDA); + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SCL); + } + + /* Enable and initialize the I2C master module */ + ti_lib_i2c_master_init_exp_clk(I2C0_BASE, ti_lib_sys_ctrl_clock_get(), + true); + } +} +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-i2c.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-i2c.h new file mode 100644 index 000000000..46233c332 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-i2c.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup sensortag-cc26xx-peripherals + * @{ + * + * \defgroup sensortag-cc26xx-i2c SensorTag 2.0 I2C functions + * @{ + * + * \file + * Header file for the Sensortag I2C Driver + */ +/*---------------------------------------------------------------------------*/ +#ifndef BOARD_I2C_H_ +#define BOARD_I2C_H_ +/*---------------------------------------------------------------------------*/ +#include +#include +/*---------------------------------------------------------------------------*/ +#define BOARD_I2C_INTERFACE_0 0 +#define BOARD_I2C_INTERFACE_1 1 +/*---------------------------------------------------------------------------*/ +/** + * \brief Put the I2C controller in a known state + * + * In this state, pins SDA and SCL will be under i2c control and pins SDA HP + * and SCL HP will be configured as gpio inputs. This is equal to selecting + * BOARD_I2C_INTERFACE_0, but without selecting a slave device address + */ +#define board_i2c_deselect() board_i2c_select(BOARD_I2C_INTERFACE_0, 0) +/*---------------------------------------------------------------------------*/ +/** + * \brief Select an I2C slave + * \param interface The I2C interface to be used (BOARD_I2C_INTERFACE_0 or _1) + * \param slave_addr The slave's address + * + * The various sensors on the sensortag are connected either on interface 0 or + * 1. All sensors are connected to interface 0, with the exception of the MPU + * that is connected to 1. + */ +void board_i2c_select(uint8_t interface, uint8_t slave_addr); + +/** + * \brief Burst read from an I2C device + * \param buf Pointer to a buffer where the read data will be stored + * \param len Number of bytes to read + * \return True on success + */ +bool board_i2c_read(uint8_t *buf, uint8_t len); + +/** + * \brief Burst write to an I2C device + * \param buf Pointer to the buffer to be written + * \param len Number of bytes to write + * \return True on success + */ +bool board_i2c_write(uint8_t *buf, uint8_t len); + +/** + * \brief Single write to an I2C device + * \param data The byte to write + * \return True on success + */ +bool board_i2c_write_single(uint8_t data); + +/** + * \brief Write and read in one operation + * \param wdata Pointer to the buffer to be written + * \param wlen Number of bytes to write + * \param rdata Pointer to a buffer where the read data will be stored + * \param rlen Number of bytes to read + * \return True on success + */ +bool board_i2c_write_read(uint8_t *wdata, uint8_t wlen, uint8_t *rdata, + uint8_t rlen); + +/** + * \brief Enables the I2C peripheral with defaults + * + * This function is called to wakeup and initialise the I2C. + * + * This function can be called explicitly, but it will also be called + * automatically by board_i2c_select() when required. One of those two + * functions MUST be called before any other I2C operation after a chip + * sleep / wakeup cycle or after a call to board_i2c_shutdown(). Failing to do + * so will lead to a bus fault. + */ +void board_i2c_wakeup(void); + +/** + * \brief Stops the I2C peripheral and restores pins to s/w control + * + * This function is called automatically by the board's LPM logic, but it + * can also be called explicitly. + */ +void board_i2c_shutdown(void); +/*---------------------------------------------------------------------------*/ +#endif /* BOARD_I2C_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/platform/simplelink/cc13x0-cc26x0/contiki-conf.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-peripherals.h similarity index 67% rename from arch/platform/simplelink/cc13x0-cc26x0/contiki-conf.h rename to arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-peripherals.h index c616c7610..42e22d4c8 100644 --- a/arch/platform/simplelink/cc13x0-cc26x0/contiki-conf.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-peripherals.h @@ -27,51 +27,39 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/** - * \addtogroup cc26xx-srf-tag +/*---------------------------------------------------------------------------*/ +/** \addtogroup cc26xx-srf-tag + * @{ + * + * \defgroup sensortag-cc26xx-peripherals Sensortag CC1350/CC2650 common + * + * Defines related to Sensortag sensors. The two sensortags are identical to a + * very large extent. Everything documented within this group applies to both + * sensortags. + * * @{ * * \file - * Configuration for the srf06-cc26xx platform + * Header file with definitions related to the sensors on the Sensortags + * + * \note Do not include this file directly. */ -#ifndef CONTIKI_CONF_H -#define CONTIKI_CONF_H - -#include /*---------------------------------------------------------------------------*/ -/* Include Project Specific conf */ -#ifdef PROJECT_CONF_PATH -#include PROJECT_CONF_PATH -#endif /* PROJECT_CONF_PATH */ +#ifndef BOARD_PERIPHERALS_H_ +#define BOARD_PERIPHERALS_H_ /*---------------------------------------------------------------------------*/ -#include "simplelink-def.h" +#include "bmp-280-sensor.h" +#include "tmp-007-sensor.h" +#include "opt-3001-sensor.h" +#include "hdc-1000-sensor.h" +#include "mpu-9250-sensor.h" +#include "reed-relay.h" +#include "buzzer.h" +#include "ext-flash.h" +/*---------------------------------------------------------------------------*/ +#endif /* BOARD_PERIPHERALS_H_ */ /*---------------------------------------------------------------------------*/ /** - * \name Button configurations - * - * Configure a button as power on/off: We use the right button for both boards. - * @{ + * @} + * @} */ -#ifndef BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN -#define BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN 1 -#endif - -/* Notify various examples that we have Buttons */ -#define PLATFORM_HAS_BUTTON 1 - -/* - * Override button symbols from dev/button-sensor.h, for the examples that - * include it - */ -#define button_sensor button_left_sensor -#define button_sensor2 button_right_sensor -/** @} */ -/*---------------------------------------------------------------------------*/ -/* Platform-specific define to signify sensor reading failure */ -#define CC26XX_SENSOR_READING_ERROR 0x80000000 -/*---------------------------------------------------------------------------*/ -/* Include CPU-related configuration */ -#include "simplelink-conf.h" -#endif /* CONTIKI_CONF_H */ - -/** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor.c new file mode 100644 index 000000000..7ec0a5a18 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor.c @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup sensortag-cc26xx-button-sensor + * @{ + * + * \file + * Driver for Sensortag buttons + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "lib/sensors.h" +#include "sensortag/button-sensor.h" +#include "gpio-interrupt.h" +#include "sys/timer.h" +#include "lpm.h" + +#include "ti-lib.h" + +#include +/*---------------------------------------------------------------------------*/ +#ifdef BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN +#define BUTTON_SENSOR_ENABLE_SHUTDOWN BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN +#else +#define BUTTON_SENSOR_ENABLE_SHUTDOWN 1 +#endif +/*---------------------------------------------------------------------------*/ +#define BUTTON_GPIO_CFG (IOC_CURRENT_2MA | IOC_STRENGTH_AUTO | \ + IOC_IOPULL_UP | IOC_SLEW_DISABLE | \ + IOC_HYST_DISABLE | IOC_BOTH_EDGES | \ + IOC_INT_ENABLE | IOC_IOMODE_NORMAL | \ + IOC_NO_WAKE_UP | IOC_INPUT_ENABLE) +/*---------------------------------------------------------------------------*/ +#define DEBOUNCE_DURATION (CLOCK_SECOND >> 5) + +struct btn_timer { + struct timer debounce; + clock_time_t start; + clock_time_t duration; +}; + +static struct btn_timer left_timer, right_timer; +/*---------------------------------------------------------------------------*/ +/** + * \brief Handler for Sensortag-CC26XX button presses + */ +static void +button_press_handler(uint8_t ioid) +{ + if(ioid == BOARD_IOID_KEY_LEFT) { + if(!timer_expired(&left_timer.debounce)) { + return; + } + + timer_set(&left_timer.debounce, DEBOUNCE_DURATION); + + /* + * Start press duration counter on press (falling), notify on release + * (rising) + */ + if(ti_lib_gpio_read_dio(BOARD_IOID_KEY_LEFT) == 0) { + left_timer.start = clock_time(); + left_timer.duration = 0; + } else { + left_timer.duration = clock_time() - left_timer.start; + sensors_changed(&button_left_sensor); + } + } + + if(ioid == BOARD_IOID_KEY_RIGHT) { + if(BUTTON_SENSOR_ENABLE_SHUTDOWN == 0) { + if(!timer_expired(&right_timer.debounce)) { + return; + } + + timer_set(&right_timer.debounce, DEBOUNCE_DURATION); + + /* + * Start press duration counter on press (falling), notify on release + * (rising) + */ + if(ti_lib_gpio_read_dio(BOARD_IOID_KEY_RIGHT) == 0) { + right_timer.start = clock_time(); + right_timer.duration = 0; + } else { + right_timer.duration = clock_time() - right_timer.start; + sensors_changed(&button_right_sensor); + } + } else { + lpm_shutdown(BOARD_IOID_KEY_RIGHT, IOC_IOPULL_UP, IOC_WAKE_ON_LOW); + } + } +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Configuration function for the button sensor for all buttons. + * + * \param type This function does nothing unless type == SENSORS_ACTIVE + * \param c 0: disable the button, non-zero: enable + * \param key: One of BOARD_KEY_LEFT, BOARD_KEY_RIGHT etc + */ +static void +config_buttons(int type, int c, uint32_t key) +{ + switch(type) { + case SENSORS_HW_INIT: + ti_lib_gpio_clear_event_dio(key); + ti_lib_rom_ioc_pin_type_gpio_input(key); + ti_lib_rom_ioc_port_configure_set(key, IOC_PORT_GPIO, BUTTON_GPIO_CFG); + gpio_interrupt_register_handler(key, button_press_handler); + break; + case SENSORS_ACTIVE: + if(c) { + ti_lib_gpio_clear_event_dio(key); + ti_lib_rom_ioc_pin_type_gpio_input(key); + ti_lib_rom_ioc_port_configure_set(key, IOC_PORT_GPIO, BUTTON_GPIO_CFG); + ti_lib_rom_ioc_int_enable(key); + } else { + ti_lib_rom_ioc_int_disable(key); + } + break; + default: + break; + } +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Configuration function for the left button. + * + * Parameters are passed onto config_buttons, which does the actual + * configuration + * Parameters are ignored. They have been included because the prototype is + * dictated by the core sensor API. The return value is also required by + * the API but otherwise ignored. + * + * \param type passed to config_buttons as-is + * \param value passed to config_buttons as-is + * + * \return ignored + */ +static int +config_left(int type, int value) +{ + config_buttons(type, value, BOARD_IOID_KEY_LEFT); + + return 1; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Configuration function for the right button. + * + * Parameters are passed onto config_buttons, which does the actual + * configuration + * Parameters are ignored. They have been included because the prototype is + * dictated by the core sensor api. The return value is also required by + * the API but otherwise ignored. + * + * \param type passed to config_buttons as-is + * \param value passed to config_buttons as-is + * + * \return ignored + */ +static int +config_right(int type, int value) +{ + config_buttons(type, value, BOARD_IOID_KEY_RIGHT); + + return 1; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Status function for all buttons + * \param type SENSORS_ACTIVE or SENSORS_READY + * \param key_io_id BOARD_IOID_KEY_LEFT, BOARD_IOID_KEY_RIGHT etc + * \return 1 if the button's port interrupt is enabled (edge detect) + * + * This function will only be called by status_left, status_right and the + * called will pass the correct key_io_id + */ +static int +status(int type, uint32_t key_io_id) +{ + switch(type) { + case SENSORS_ACTIVE: + case SENSORS_READY: + if(ti_lib_ioc_port_configure_get(key_io_id) & IOC_INT_ENABLE) { + return 1; + } + break; + default: + break; + } + return 0; +} +/*---------------------------------------------------------------------------*/ +static int +value_left(int type) +{ + if(type == BUTTON_SENSOR_VALUE_STATE) { + return ti_lib_gpio_read_dio(BOARD_IOID_KEY_LEFT) == 0 ? + BUTTON_SENSOR_VALUE_PRESSED : BUTTON_SENSOR_VALUE_RELEASED; + } else if(type == BUTTON_SENSOR_VALUE_DURATION) { + return (int)left_timer.duration; + } + return 0; +} +/*---------------------------------------------------------------------------*/ +static int +value_right(int type) +{ + if(type == BUTTON_SENSOR_VALUE_STATE) { + return ti_lib_gpio_read_dio(BOARD_IOID_KEY_RIGHT) == 0 ? + BUTTON_SENSOR_VALUE_PRESSED : BUTTON_SENSOR_VALUE_RELEASED; + } else if(type == BUTTON_SENSOR_VALUE_DURATION) { + return (int)right_timer.duration; + } + return 0; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Status function for the left button. + * \param type SENSORS_ACTIVE or SENSORS_READY + * \return 1 if the button's port interrupt is enabled (edge detect) + * + * This function will call status. It will pass type verbatim and it will also + * pass the correct key_io_id + */ +static int +status_left(int type) +{ + return status(type, BOARD_IOID_KEY_LEFT); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Status function for the right button. + * \param type SENSORS_ACTIVE or SENSORS_READY + * \return 1 if the button's port interrupt is enabled (edge detect) + * + * This function will call status. It will pass type verbatim and it will also + * pass the correct key_io_id + */ +static int +status_right(int type) +{ + return status(type, BOARD_IOID_KEY_RIGHT); +} +/*---------------------------------------------------------------------------*/ +SENSORS_SENSOR(button_left_sensor, BUTTON_SENSOR, value_left, config_left, + status_left); +SENSORS_SENSOR(button_right_sensor, BUTTON_SENSOR, value_right, config_right, + status_right); +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13x2-cc26x2/common/button-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor.h similarity index 87% rename from arch/platform/simplelink/cc13x2-cc26x2/common/button-sensor.h rename to arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor.h index 8756d9b6c..1355a5855 100644 --- a/arch/platform/simplelink/cc13x2-cc26x2/common/button-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,26 +29,22 @@ */ /*---------------------------------------------------------------------------*/ /** - * \addtogroup simplelink-platform + * \addtogroup sensortag-cc26xx-peripherals * @{ * - * \defgroup simplelink-button-sensor Simplelink Button Driver + * \defgroup sensortag-cc26xx-button-sensor SensorTag 2.0 Button Sensor * * One of the buttons can be configured as general purpose or as an on/off key * @{ * * \file - * Header file for the Simplelink Button Driver + * Header file for the Sensortag Button Driver */ /*---------------------------------------------------------------------------*/ #ifndef BUTTON_SENSOR_H_ #define BUTTON_SENSOR_H_ /*---------------------------------------------------------------------------*/ -/* Contiki API */ -#include -/*---------------------------------------------------------------------------*/ -/* Board specific button sensors */ -#include "button-sensor-arch.h" +#include "lib/sensors.h" /*---------------------------------------------------------------------------*/ #define BUTTON_SENSOR "Button" /*---------------------------------------------------------------------------*/ @@ -58,6 +54,9 @@ #define BUTTON_SENSOR_VALUE_RELEASED 0 #define BUTTON_SENSOR_VALUE_PRESSED 1 /*---------------------------------------------------------------------------*/ +extern const struct sensors_sensor button_left_sensor; +extern const struct sensors_sensor button_right_sensor; +/*---------------------------------------------------------------------------*/ #endif /* BUTTON_SENSOR_H_ */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.c new file mode 100644 index 000000000..45ab751d5 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.c @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup sensortag-cc26xx-buzzer + * @{ + * + * \file + * Driver for the Sensortag Buzzer + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "buzzer.h" +#include "ti-lib.h" +#include "lpm.h" + +#include +#include +#include +/*---------------------------------------------------------------------------*/ +static uint8_t buzzer_on; +LPM_MODULE(buzzer_module, NULL, NULL, NULL, LPM_DOMAIN_PERIPH); +/*---------------------------------------------------------------------------*/ +void +buzzer_init() +{ + buzzer_on = 0; +} +/*---------------------------------------------------------------------------*/ +uint8_t +buzzer_state() +{ + return buzzer_on; +} +/*---------------------------------------------------------------------------*/ +void +buzzer_start(int freq) +{ + uint32_t load; + + /* Enable GPT0 clocks under active, sleep, deep sleep */ + ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_TIMER0); + ti_lib_prcm_peripheral_sleep_enable(PRCM_PERIPH_TIMER0); + ti_lib_prcm_peripheral_deep_sleep_enable(PRCM_PERIPH_TIMER0); + ti_lib_prcm_load_set(); + while(!ti_lib_prcm_load_get()); + + /* Drive the I/O ID with GPT0 / Timer A */ + ti_lib_ioc_port_configure_set(BOARD_IOID_BUZZER, IOC_PORT_MCU_PORT_EVENT0, + IOC_STD_OUTPUT); + + /* GPT0 / Timer A: PWM, Interrupt Enable */ + HWREG(GPT0_BASE + GPT_O_TAMR) = (TIMER_CFG_A_PWM & 0xFF) | GPT_TAMR_TAPWMIE; + + buzzer_on = 1; + + /* + * Register ourself with LPM. This will keep the PERIPH PD powered on + * during deep sleep, allowing the buzzer to keep working while the chip is + * being power-cycled + */ + lpm_register_module(&buzzer_module); + + /* Stop the timer */ + ti_lib_timer_disable(GPT0_BASE, TIMER_A); + + if(freq > 0) { + load = (GET_MCU_CLOCK / freq); + + ti_lib_timer_load_set(GPT0_BASE, TIMER_A, load); + ti_lib_timer_match_set(GPT0_BASE, TIMER_A, load / 2); + + /* Start */ + ti_lib_timer_enable(GPT0_BASE, TIMER_A); + } +} +/*---------------------------------------------------------------------------*/ +void +buzzer_stop() +{ + buzzer_on = 0; + + /* + * Unregister the buzzer module from LPM. This will effectively release our + * lock for the PERIPH PD allowing it to be powered down (unless some other + * module keeps it on) + */ + lpm_unregister_module(&buzzer_module); + + /* Stop the timer */ + ti_lib_timer_disable(GPT0_BASE, TIMER_A); + + /* + * Stop the module clock: + * + * Currently GPT0 is in use by clock_delay_usec (GPT0/TB) and by this + * module here (GPT0/TA). + * + * clock_delay_usec + * - is definitely not running when we enter here and + * - handles the module clock internally + * + * Thus, we can safely change the state of module clocks here. + */ + ti_lib_prcm_peripheral_run_disable(PRCM_PERIPH_TIMER0); + ti_lib_prcm_peripheral_sleep_disable(PRCM_PERIPH_TIMER0); + ti_lib_prcm_peripheral_deep_sleep_disable(PRCM_PERIPH_TIMER0); + ti_lib_prcm_load_set(); + while(!ti_lib_prcm_load_get()); + + /* Un-configure the pin */ + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_BUZZER); + ti_lib_ioc_io_input_set(BOARD_IOID_BUZZER, IOC_INPUT_DISABLE); +} +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.h new file mode 100644 index 000000000..679729245 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup sensortag-cc26xx-peripherals + * @{ + * + * \defgroup sensortag-cc26xx-buzzer SensorTag 2.0 Buzzer + * @{ + * + * \file + * Header file for the Sensortag Buzzer + */ +/*---------------------------------------------------------------------------*/ +#ifndef BUZZER_H_ +#define BUZZER_H_ +/*---------------------------------------------------------------------------*/ +#include +/*---------------------------------------------------------------------------*/ +/** + * \brief Initialise the buzzer + */ +void buzzer_init(void); + +/** + * \brief Start the buzzer + * \param freq The buzzer frequency + */ +void buzzer_start(int freq); + +/** + * \brief Stop the buzzer + */ +void buzzer_stop(void); + +/** + * \brief Retrieve the buzzer state + * \return 1: on, 0: off + */ +uint8_t buzzer_state(void); +/*---------------------------------------------------------------------------*/ +#endif /* BUZZER_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h new file mode 100644 index 000000000..edf32e331 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2015-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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 __BOARD_H +#define __BOARD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "CC1350STK.h" + +#define Board_initGeneral() CC1350STK_initGeneral() +#define Board_shutDownExtFlash() CC1350STK_shutDownExtFlash() +#define Board_wakeUpExtFlash() CC1350STK_wakeUpExtFlash() + +/* These #defines allow us to reuse TI-RTOS across other device families */ + +#define Board_BUZZER CC1350STK_BUZZER +#define Board_BUZZER_ON CC1350STK_LED_ON +#define Board_BUZZER_OFF CC1350STK_LED_OFF + +#define Board_CRYPTO0 CC1350STK_CRYPTO0 + +#define Board_GPIO_BUTTON0 CC1350STK_GPIO_S1 +#define Board_GPIO_BUTTON1 CC1350STK_GPIO_S2 +#define Board_GPIO_LED0 CC1350STK_GPIO_LED0 +#define Board_GPIO_LED1 CC1350STK_GPIO_LED0 +#define Board_GPIO_LED_ON CC1350STK_GPIO_LED_ON +#define Board_GPIO_LED_OFF CC1350STK_GPIO_LED_OFF + +#define Board_GPTIMER0A CC1350STK_GPTIMER0A +#define Board_GPTIMER0B CC1350STK_GPTIMER0B +#define Board_GPTIMER1A CC1350STK_GPTIMER1A +#define Board_GPTIMER1B CC1350STK_GPTIMER1B +#define Board_GPTIMER2A CC1350STK_GPTIMER2A +#define Board_GPTIMER2B CC1350STK_GPTIMER2B +#define Board_GPTIMER3A CC1350STK_GPTIMER3A +#define Board_GPTIMER3B CC1350STK_GPTIMER3B + +#define Board_I2C0 CC1350STK_I2C0 +#define Board_I2C0_SDA1 CC1350STK_I2C0_SDA1 +#define Board_I2C0_SCL1 CC1350STK_I2C0_SCL1 +#define Board_I2C_TMP CC1350STK_I2C0 + +#define Board_KEY_LEFT CC1350STK_KEY_LEFT +#define Board_KEY_RIGHT CC1350STK_KEY_RIGHT + +#define Board_MIC_POWER CC1350STK_MIC_POWER +#define Board_MIC_POWER_OM CC1350STK_MIC_POWER_ON +#define Board_MIC_POWER_OFF CC1350STK_MIC_POWER_OFF + +#define Board_MPU_INT CC1350STK_MPU_INT +#define Board_MPU_POWER CC1350STK_MPU_POWER +#define Board_MPU_POWER_OFF CC1350STK_MPU_POWER_OFF +#define Board_MPU_POWER_ON CC1350STK_MPU_POWER_ON + +#define Board_NVSINTERNAL CC1350STK_NVSCC26XX0 +#define Board_NVSEXTERNAL CC1350STK_NVSSPI25X0 + +#define Board_PDM0 CC2650STK_PDM0 + +#define Board_PIN_BUTTON0 CC1350STK_KEY_LEFT +#define Board_PIN_BUTTON1 CC1350STK_KEY_RIGHT +#define Board_PIN_LED0 CC1350STK_PIN_LED1 +#define Board_PIN_LED1 CC1350STK_PIN_LED1 +#define Board_PIN_LED2 CC1350STK_PIN_LED1 + +#define Board_PWM0 CC1350STK_PWM0 +#define Board_PWM1 CC1350STK_PWM0 +#define Board_PWM2 CC1350STK_PWM2 +#define Board_PWM3 CC1350STK_PWM3 +#define Board_PWM4 CC1350STK_PWM4 +#define Board_PWM5 CC1350STK_PWM5 +#define Board_PWM6 CC1350STK_PWM6 +#define Board_PWM7 CC1350STK_PWM7 + +#define Board_SPI0 CC1350STK_SPI0 +#define Board_SPI1 CC1350STK_SPI1 +#define Board_SPI_FLASH_CS CC1350STK_SPI_FLASH_CS +#define Board_FLASH_CS_ON CC1350STK_FLASH_CS_ON +#define Board_FLASH_CS_OFF CC1350STK_FLASH_CS_OFF + +#define Board_UART0 CC1350STK_UART0 + +#define Board_WATCHDOG0 CC1350STK_WATCHDOG0 + +/* Board specific I2C addresses */ +#define Board_BMP280_ADDR (0x77) +#define Board_HDC1000_ADDR (0x43) +#define Board_MPU9250_ADDR (0x68) +#define Board_MPU9250_MAG_ADDR (0x0C) +#define Board_OPT3001_ADDR (0x45) +#define Board_TMP_ADDR (0x44) + +#ifdef __cplusplus +} +#endif + +#endif /* __BOARD_H */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.c new file mode 100644 index 000000000..8ae1c22bc --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.c @@ -0,0 +1,756 @@ +/* + * Copyright (c) 2016-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +/* + * ====================== CC1350STK.c ========================================= + * This file is responsible for setting up the board specific items for the + * CC1350STK board. + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "CC1350STK.h" + +/* + * =============================== Crypto =============================== + */ +#include + +CryptoCC26XX_Object cryptoCC26XXObjects[CC1350STK_CRYPTOCOUNT]; + +const CryptoCC26XX_HWAttrs cryptoCC26XXHWAttrs[CC1350STK_CRYPTOCOUNT] = { + { + .baseAddr = CRYPTO_BASE, + .powerMngrId = PowerCC26XX_PERIPH_CRYPTO, + .intNum = INT_CRYPTO_RESULT_AVAIL_IRQ, + .intPriority = ~0, + } +}; + +const CryptoCC26XX_Config CryptoCC26XX_config[CC1350STK_CRYPTOCOUNT] = { + { + .object = &cryptoCC26XXObjects[CC1350STK_CRYPTO0], + .hwAttrs = &cryptoCC26XXHWAttrs[CC1350STK_CRYPTO0] + } +}; + +/* + * =============================== Display =============================== + */ +#include +#include +#include + +#ifndef CC1350STK_DISPLAY_UART_STRBUF_SIZE +#define CC1350STK_DISPLAY_UART_STRBUF_SIZE 128 +#endif + +#ifndef CC1350STK_DISPLAY_SHARP_SIZE +#define CC1350STK_DISPLAY_SHARP_SIZE 96 +#endif + +DisplayUart_Object displayUartObject; +DisplaySharp_Object displaySharpObject; + +static char uartStringBuf[CC1350STK_DISPLAY_UART_STRBUF_SIZE]; +static uint_least8_t sharpDisplayBuf[CC1350STK_DISPLAY_SHARP_SIZE * CC1350STK_DISPLAY_SHARP_SIZE / 8]; + +const DisplayUart_HWAttrs displayUartHWAttrs = { + .uartIdx = CC1350STK_UART0, + .baudRate = 115200, + .mutexTimeout = (unsigned int)(-1), + .strBuf = uartStringBuf, + .strBufLen = CC1350STK_DISPLAY_UART_STRBUF_SIZE, +}; + +const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { + .spiIndex = CC1350STK_SPI0, + .csPin = CC1350STK_GPIO_LCD_CS, + .powerPin = (uint32_t)(-1), /* no need to apply power for this LCD */ + .enablePin = CC1350STK_GPIO_LCD_ENABLE, + .pixelWidth = CC1350STK_DISPLAY_SHARP_SIZE, + .pixelHeight = CC1350STK_DISPLAY_SHARP_SIZE, + .displayBuf = sharpDisplayBuf, +}; + +/* + * The pins for the UART and Watch Devpack conflict, prefer UART by default + */ +#ifndef BOARD_DISPLAY_USE_UART +#define BOARD_DISPLAY_USE_UART 1 +#endif +#ifndef BOARD_DISPLAY_USE_UART_ANSI +#define BOARD_DISPLAY_USE_UART_ANSI 0 +#endif +#ifndef BOARD_DISPLAY_USE_LCD +#define BOARD_DISPLAY_USE_LCD 0 +#endif + +/* + * This #if/#else is needed to workaround a problem with the + * IAR compiler. The IAR compiler doesn't like the empty array + * initialization. (IAR Error[Pe1345]) + */ +#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) + +const Display_Config Display_config[] = { +#if (BOARD_DISPLAY_USE_UART) + { +# if (BOARD_DISPLAY_USE_UART_ANSI) + .fxnTablePtr = &DisplayUartAnsi_fxnTable, +# else /* Default to minimal UART with no cursor placement */ + .fxnTablePtr = &DisplayUartMin_fxnTable, +# endif + .fxnTablePtr = &DisplayUart_fxnTable, + .object = &displayUartObject, + .hwAttrs = &displayUartHWAttrs, + }, +#endif +#if (BOARD_DISPLAY_USE_LCD) + { + .fxnTablePtr = &DisplaySharp_fxnTable, + .object = &displaySharpObject, + .hwAttrs = &displaySharpHWattrs + }, +#endif +}; + +const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); + +#else + +const Display_Config *Display_config = NULL; +const uint_least8_t Display_count = 0; + +#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ + +/* + * =============================== GPIO =============================== + */ +#include +#include + +/* + * Array of Pin configurations + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC1350STK.h + * NOTE: Pins not used for interrupts should be placed at the end of the + * array. Callback entries can be omitted from callbacks array to + * reduce memory usage. + */ +GPIO_PinConfig gpioPinConfigs[] = { + /* Input pins */ + GPIOCC26XX_DIO_15 | GPIO_DO_NOT_CONFIG, /* Button 0 */ + GPIOCC26XX_DIO_04 | GPIO_DO_NOT_CONFIG, /* Button 1 */ + + /* Output pins */ + GPIOCC26XX_DIO_10 | GPIO_DO_NOT_CONFIG, /* LED */ + + /* SPI Flash CSN */ + GPIOCC26XX_DIO_14 | GPIO_DO_NOT_CONFIG, + + /* Sharp Display - GPIO configurations will be done in the Display files */ + GPIOCC26XX_DIO_20 | GPIO_DO_NOT_CONFIG, /* LCD CS */ + GPIOCC26XX_DIO_29 | GPIO_DO_NOT_CONFIG, /* LCD Enable */ +}; + +/* + * Array of callback function pointers + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC1350STK.h + * NOTE: Pins not used for interrupts can be omitted from callbacks array to + * reduce memory usage (if placed at end of gpioPinConfigs array). + */ +GPIO_CallbackFxn gpioCallbackFunctions[] = { + NULL, /* Button 0 */ + NULL, /* Button 1 */ +}; + +const GPIOCC26XX_Config GPIOCC26XX_config = { + .pinConfigs = (GPIO_PinConfig *)gpioPinConfigs, + .callbacks = (GPIO_CallbackFxn *)gpioCallbackFunctions, + .numberOfPinConfigs = CC1350STK_GPIOCOUNT, + .numberOfCallbacks = sizeof(gpioCallbackFunctions)/sizeof(GPIO_CallbackFxn), + .intPriority = (~0) +}; + +/* + * =============================== GPTimer =============================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +#include + +GPTimerCC26XX_Object gptimerCC26XXObjects[CC1350STK_GPTIMERCOUNT]; + +const GPTimerCC26XX_HWAttrs gptimerCC26xxHWAttrs[CC1350STK_GPTIMERPARTSCOUNT] = { + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0A, }, + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0B, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1A, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1B, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2A, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2B, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3A, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3B, }, +}; + +const GPTimerCC26XX_Config GPTimerCC26XX_config[CC1350STK_GPTIMERPARTSCOUNT] = { + { &gptimerCC26XXObjects[CC1350STK_GPTIMER0], &gptimerCC26xxHWAttrs[CC1350STK_GPTIMER0A], GPT_A }, + { &gptimerCC26XXObjects[CC1350STK_GPTIMER0], &gptimerCC26xxHWAttrs[CC1350STK_GPTIMER0B], GPT_B }, + { &gptimerCC26XXObjects[CC1350STK_GPTIMER1], &gptimerCC26xxHWAttrs[CC1350STK_GPTIMER1A], GPT_A }, + { &gptimerCC26XXObjects[CC1350STK_GPTIMER1], &gptimerCC26xxHWAttrs[CC1350STK_GPTIMER1B], GPT_B }, + { &gptimerCC26XXObjects[CC1350STK_GPTIMER2], &gptimerCC26xxHWAttrs[CC1350STK_GPTIMER2A], GPT_A }, + { &gptimerCC26XXObjects[CC1350STK_GPTIMER2], &gptimerCC26xxHWAttrs[CC1350STK_GPTIMER2B], GPT_B }, + { &gptimerCC26XXObjects[CC1350STK_GPTIMER3], &gptimerCC26xxHWAttrs[CC1350STK_GPTIMER3A], GPT_A }, + { &gptimerCC26XXObjects[CC1350STK_GPTIMER3], &gptimerCC26xxHWAttrs[CC1350STK_GPTIMER3B], GPT_B }, +}; + +/* + * =============================== I2C =============================== +*/ +#include +#include + +I2CCC26XX_Object i2cCC26xxObjects[CC1350STK_I2CCOUNT]; + +const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1350STK_I2CCOUNT] = { + { + .baseAddr = I2C0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_I2C0, + .intNum = INT_I2C_IRQ, + .intPriority = ~0, + .swiPriority = 0, + .sdaPin = CC1350STK_I2C0_SDA0, + .sclPin = CC1350STK_I2C0_SCL0, + } +}; + +const I2C_Config I2C_config[CC1350STK_I2CCOUNT] = { + { + .fxnTablePtr = &I2CCC26XX_fxnTable, + .object = &i2cCC26xxObjects[CC1350STK_I2C0], + .hwAttrs = &i2cCC26xxHWAttrs[CC1350STK_I2C0] + }, +}; + +const uint_least8_t I2C_count = CC1350STK_I2CCOUNT; + +/* + * =============================== NVS =============================== + */ +#include +#include +#include + +#define NVS_REGIONS_BASE 0x1A000 +#define SECTORSIZE 0x1000 +#define REGIONSIZE (SECTORSIZE * 4) +#define SPIREGIONSIZE (SECTORSIZE * 32) +#define VERIFYBUFSIZE 64 + +static uint8_t verifyBuf[VERIFYBUFSIZE]; + +/* + * Reserve flash sectors for NVS driver use by placing an uninitialized byte + * array at the desired flash address. + */ +#if defined(__TI_COMPILER_VERSION__) + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +#pragma LOCATION(flashBuf, NVS_REGIONS_BASE); +#pragma NOINIT(flashBuf); +static char flashBuf[REGIONSIZE]; + +#elif defined(__IAR_SYSTEMS_ICC__) + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +static __no_init char flashBuf[REGIONSIZE] @ NVS_REGIONS_BASE; + +#elif defined(__GNUC__) + +/* + * Place the flash buffers in the .nvs section created in the gcc linker file. + * The .nvs section enforces alignment on a sector boundary but may + * be placed anywhere in flash memory. If desired the .nvs section can be set + * to a fixed address by changing the following in the gcc linker file: + * + * .nvs (FIXED_FLASH_ADDR) (NOLOAD) : AT (FIXED_FLASH_ADDR) { + * *(.nvs) + * } > REGION_TEXT + */ +__attribute__ ((section (".nvs"))) +static char flashBuf[REGIONSIZE]; + +#endif + +/* Allocate objects for NVS and NVS SPI */ +NVSCC26XX_Object nvsCC26xxObjects[1]; +NVSSPI25X_Object nvsSPI25XObjects[1]; + +/* Hardware attributes for NVS */ +const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { + { + .regionBase = (void *)flashBuf, + .regionSize = REGIONSIZE, + }, +}; + +/* Hardware attributes for NVS SPI */ +const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { + { + .regionBaseOffset = 0, + .regionSize = SPIREGIONSIZE, + .sectorSize = SECTORSIZE, + .verifyBuf = verifyBuf, + .verifyBufSize = VERIFYBUFSIZE, + .spiHandle = NULL, + .spiIndex = 0, + .spiBitRate = 4000000, + .spiCsnGpioIndex = CC1350STK_GPIO_SPI_FLASH_CS, + }, +}; + +/* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ +const NVS_Config NVS_config[CC1350STK_NVSCOUNT] = { + { + .fxnTablePtr = &NVSCC26XX_fxnTable, + .object = &nvsCC26xxObjects[0], + .hwAttrs = &nvsCC26xxHWAttrs[0], + }, + { + .fxnTablePtr = &NVSSPI25X_fxnTable, + .object = &nvsSPI25XObjects[0], + .hwAttrs = &nvsSPI25XHWAttrs[0], + }, +}; + +const uint_least8_t NVS_count = CC1350STK_NVSCOUNT; + +/* + * =============================== PDM =============================== +*/ +#include +#include + +PDMCC26XX_Object pdmCC26XXObjects[CC1350STK_PDMCOUNT]; +PDMCC26XX_I2S_Object pdmCC26XXI2SObjects[CC1350STK_PDMCOUNT]; + +const PDMCC26XX_HWAttrs pdmCC26XXHWAttrs[CC1350STK_PDMCOUNT] = { + { + .micPower = CC1350STK_MIC_POWER, + .taskPriority = 2 + } +}; + +const PDMCC26XX_Config PDMCC26XX_config[CC1350STK_PDMCOUNT] = { + { + .object = &pdmCC26XXObjects[CC1350STK_PDM0], + .hwAttrs = &pdmCC26XXHWAttrs[CC1350STK_PDM0] + } +}; + +const PDMCC26XX_I2S_HWAttrs pdmC26XXI2SHWAttrs[CC1350STK_PDMCOUNT] = { + { + .baseAddr = I2S0_BASE, + .intNum = INT_I2S_IRQ, + .powerMngrId = PowerCC26XX_PERIPH_I2S, + .intPriority = ~0, + .mclkPin = PIN_UNASSIGNED, + .bclkPin = CC1350STK_AUDIO_CLK, + .wclkPin = PIN_UNASSIGNED, + .ad0Pin = CC1350STK_AUDIO_DI, + } +}; + +const PDMCC26XX_I2S_Config PDMCC26XX_I2S_config[CC1350STK_PDMCOUNT] = { + { + .object = &pdmCC26XXI2SObjects[CC1350STK_PDM0], + .hwAttrs = &pdmC26XXI2SHWAttrs[CC1350STK_PDM0] + } +}; + +/* + * =============================== PIN =============================== + */ +#include +#include + +const PIN_Config BoardGpioInitTable[] = { + + CC1350STK_PIN_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC1350STK_KEY_LEFT | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC1350STK_KEY_RIGHT | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC1350STK_RELAY | PIN_INPUT_EN | PIN_PULLDOWN | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Relay is active high */ + CC1350STK_MPU_INT | PIN_INPUT_EN | PIN_PULLDOWN | PIN_IRQ_NEGEDGE | PIN_HYSTERESIS, /* MPU_INT is active low */ + CC1350STK_TMP_RDY | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS, /* TMP_RDY is active high */ + CC1350STK_BUZZER | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Buzzer initially off */ + CC1350STK_MPU_POWER | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* MPU initially on */ + CC1350STK_MIC_POWER | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* MIC initially off */ + CC1350STK_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ + CC1350STK_SPI_DEVPK_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* DevPack chip select */ + CC1350STK_AUDIO_DI | PIN_INPUT_EN | PIN_PULLDOWN, /* Audio DI */ + CC1350STK_AUDIODO | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* Audio data out */ + CC1350STK_AUDIO_CLK | PIN_INPUT_EN | PIN_PULLDOWN, /* DevPack */ + CC1350STK_DP2 | PIN_INPUT_EN | PIN_PULLDOWN, /* DevPack */ + CC1350STK_DP1 | PIN_INPUT_EN | PIN_PULLDOWN, /* DevPack */ + CC1350STK_DP0 | PIN_INPUT_EN | PIN_PULLDOWN, /* DevPack */ + CC1350STK_DP3 | PIN_INPUT_EN | PIN_PULLDOWN, /* DevPack */ + CC1350STK_UART_TX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* DevPack */ + CC1350STK_UART_RX | PIN_INPUT_EN | PIN_PULLDOWN, /* DevPack */ + CC1350STK_DEVPK_ID | PIN_INPUT_EN | PIN_NOPULL, /* Device pack ID - external PU */ + CC1350STK_SPI0_MOSI | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master out - slave in */ + CC1350STK_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master in - slave out */ + CC1350STK_SPI0_CLK | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI clock */ + + PIN_TERMINATE +}; + +const PINCC26XX_HWAttrs PINCC26XX_hwAttrs = { + .intPriority = ~0, + .swiPriority = 0 +}; + +/* + * =============================== Power =============================== + */ +const PowerCC26XX_Config PowerCC26XX_config = { + .policyInitFxn = NULL, + .policyFxn = &PowerCC26XX_standbyPolicy, + .calibrateFxn = &PowerCC26XX_calibrate, + .enablePolicy = true, + .calibrateRCOSC_LF = true, + .calibrateRCOSC_HF = true, +}; + +/* + * =============================== PWM =============================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +#include +#include + +PWMTimerCC26XX_Object pwmtimerCC26xxObjects[CC1350STK_PWMCOUNT]; + +const PWMTimerCC26XX_HwAttrs pwmtimerCC26xxHWAttrs[CC1350STK_PWMCOUNT] = { + { .pwmPin = CC1350STK_PWMPIN0, .gpTimerUnit = CC1350STK_GPTIMER0A }, + { .pwmPin = CC1350STK_PWMPIN1, .gpTimerUnit = CC1350STK_GPTIMER0B }, + { .pwmPin = CC1350STK_PWMPIN2, .gpTimerUnit = CC1350STK_GPTIMER1A }, + { .pwmPin = CC1350STK_PWMPIN3, .gpTimerUnit = CC1350STK_GPTIMER1B }, + { .pwmPin = CC1350STK_PWMPIN4, .gpTimerUnit = CC1350STK_GPTIMER2A }, + { .pwmPin = CC1350STK_PWMPIN5, .gpTimerUnit = CC1350STK_GPTIMER2B }, + { .pwmPin = CC1350STK_PWMPIN6, .gpTimerUnit = CC1350STK_GPTIMER3A }, + { .pwmPin = CC1350STK_PWMPIN7, .gpTimerUnit = CC1350STK_GPTIMER3B }, +}; + +const PWM_Config PWM_config[CC1350STK_PWMCOUNT] = { + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350STK_PWM0], &pwmtimerCC26xxHWAttrs[CC1350STK_PWM0] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350STK_PWM1], &pwmtimerCC26xxHWAttrs[CC1350STK_PWM1] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350STK_PWM2], &pwmtimerCC26xxHWAttrs[CC1350STK_PWM2] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350STK_PWM3], &pwmtimerCC26xxHWAttrs[CC1350STK_PWM3] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350STK_PWM4], &pwmtimerCC26xxHWAttrs[CC1350STK_PWM4] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350STK_PWM5], &pwmtimerCC26xxHWAttrs[CC1350STK_PWM5] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350STK_PWM6], &pwmtimerCC26xxHWAttrs[CC1350STK_PWM6] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350STK_PWM7], &pwmtimerCC26xxHWAttrs[CC1350STK_PWM7] }, +}; + +const uint_least8_t PWM_count = CC1350STK_PWMCOUNT; + +/* + * =============================== RF Driver =============================== + */ +#include + +const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { + .hwiPriority = ~0, /* Lowest HWI priority */ + .swiPriority = 0, /* Lowest SWI priority */ + .xoscHfAlwaysNeeded = true, /* Keep XOSC dependency while in stanby */ + .globalCallback = NULL, /* No board specific callback */ + .globalEventMask = 0 /* No events subscribed to */ +}; + +/* + * =============================== SPI DMA =============================== + */ +#include +#include + +SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1350STK_SPICOUNT]; + +const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1350STK_SPICOUNT] = { + { + .baseAddr = SSI0_BASE, + .intNum = INT_SSI0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .powerMngrId = PowerCC26XX_PERIPH_SSI0, + .defaultTxBufValue = 0, + .rxChannelBitMask = 1< +#include + +UARTCC26XX_Object uartCC26XXObjects[CC1350STK_UARTCOUNT]; + +uint8_t uartCC26XXRingBuffer[CC1350STK_UARTCOUNT][32]; + +const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1350STK_UARTCOUNT] = { + { + .baseAddr = UART0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UART0, + .intNum = INT_UART0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .txPin = CC1350STK_UART_TX, + .rxPin = CC1350STK_UART_RX, + .ctsPin = PIN_UNASSIGNED, + .rtsPin = PIN_UNASSIGNED, + .ringBufPtr = uartCC26XXRingBuffer[CC1350STK_UART0], + .ringBufSize = sizeof(uartCC26XXRingBuffer[CC1350STK_UART0]), + .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, + .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, + .errorFxn = NULL + } +}; + +const UART_Config UART_config[CC1350STK_UARTCOUNT] = { + { + .fxnTablePtr = &UARTCC26XX_fxnTable, + .object = &uartCC26XXObjects[CC1350STK_UART0], + .hwAttrs = &uartCC26XXHWAttrs[CC1350STK_UART0] + }, +}; + +const uint_least8_t UART_count = CC1350STK_UARTCOUNT; + +/* + * =============================== UDMA =============================== + */ +#include + +UDMACC26XX_Object udmaObjects[CC1350STK_UDMACOUNT]; + +const UDMACC26XX_HWAttrs udmaHWAttrs[CC1350STK_UDMACOUNT] = { + { + .baseAddr = UDMA0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UDMA, + .intNum = INT_DMA_ERR, + .intPriority = ~0 + } +}; + +const UDMACC26XX_Config UDMACC26XX_config[CC1350STK_UDMACOUNT] = { + { + .object = &udmaObjects[CC1350STK_UDMA0], + .hwAttrs = &udmaHWAttrs[CC1350STK_UDMA0] + }, +}; + +/* + * =============================== Watchdog =============================== + */ +#include +#include + +WatchdogCC26XX_Object watchdogCC26XXObjects[CC1350STK_WATCHDOGCOUNT]; + +const WatchdogCC26XX_HWAttrs watchdogCC26XXHWAttrs[CC1350STK_WATCHDOGCOUNT] = { + { + .baseAddr = WDT_BASE, + .reloadValue = 1000 /* Reload value in milliseconds */ + }, +}; + +const Watchdog_Config Watchdog_config[CC1350STK_WATCHDOGCOUNT] = { + { + .fxnTablePtr = &WatchdogCC26XX_fxnTable, + .object = &watchdogCC26XXObjects[CC1350STK_WATCHDOG0], + .hwAttrs = &watchdogCC26XXHWAttrs[CC1350STK_WATCHDOG0] + }, +}; + +const uint_least8_t Watchdog_count = CC1350STK_WATCHDOGCOUNT; + + +/* + * ======== CC1350STK_wakeUpExtFlash ======== + */ +void CC1350STK_wakeUpExtFlash(void) +{ + PIN_Config extFlashPinTable[] = { + CC1350STK_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + /* + * To wake up we need to toggle the chip select at + * least 20 ns and ten wait at least 35 us. + */ + + /* Toggle chip select for ~20ns to wake ext. flash */ + PIN_setOutputValue(extFlashPinHandle, CC1350STK_SPI_FLASH_CS, 0); + /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ + CPUdelay(1); + PIN_setOutputValue(extFlashPinHandle, CC1350STK_SPI_FLASH_CS, 1); + /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ + CPUdelay(560); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC1350STK_sendExtFlashByte ======== + */ +void CC1350STK_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) +{ + uint8_t i; + + PIN_setOutputValue(pinHandle, CC1350STK_SPI_FLASH_CS, 0); + + for (i = 0; i < 8; i++) { + PIN_setOutputValue(pinHandle, CC1350STK_SPI0_CLK, 0); + PIN_setOutputValue(pinHandle, CC1350STK_SPI0_MOSI, (byte >> (7 - i)) & 0x01); + PIN_setOutputValue(pinHandle, CC1350STK_SPI0_CLK, 1); + + /* + * Waste a few cycles to keep the CLK high for at + * least 45% of the period. + * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. + */ + CPUdelay(8); + } + + PIN_setOutputValue(pinHandle, CC1350STK_SPI0_CLK, 0); + PIN_setOutputValue(pinHandle, CC1350STK_SPI_FLASH_CS, 1); + + /* + * Keep CS high at least 40 us + * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us + */ + CPUdelay(700); +} + +/* + * ======== CC1350STK_shutDownExtFlash ======== + */ +void CC1350STK_shutDownExtFlash(void) +{ + /* To be sure we are putting the flash into sleep and not waking it, we first have to make a wake up call */ + CC1350STK_wakeUpExtFlash(); + + PIN_Config extFlashPinTable[] = { + CC1350STK_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + CC1350STK_SPI0_CLK | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + CC1350STK_SPI0_MOSI | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, + CC1350STK_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + uint8_t extFlashShutdown = 0xB9; + + CC1350STK_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC1350STK_initGeneral ======== + */ +void CC1350STK_initGeneral(void) +{ + Power_init(); + + if ( PIN_init(BoardGpioInitTable) != PIN_SUCCESS) { + /* Error with PIN_init */ + while (1); + } + + /* Shut down external flash as default */ + CC1350STK_shutDownExtFlash(); +} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.h new file mode 100644 index 000000000..ce07503f0 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.h @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2015-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ +/** ============================================================================ + * @file CC1350STK.h + * + * @brief CC1350STK Board Specific header file. + * + * The CC1350STK header file should be included in an application as + * follows: + * @code + * #include "CC1350STK.h" + * @endcode + * ============================================================================ + */ +#ifndef __CC1350STK_BOARD_H__ +#define __CC1350STK_BOARD_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes */ +#include +#include + +/* Externs */ +extern const PIN_Config BoardGpioInitTable[]; + +/* Defines */ +#define CC1350STK + +/* Mapping of pins to board signals using general board aliases + * + */ + +/* Audio */ +#define CC1350STK_MIC_POWER IOID_13 +#define CC1350STK_MIC_POWER_ON 1 +#define CC1350STK_MIC_POWER_OFF 0 +#define CC1350STK_AUDIO_DI IOID_2 +#define CC1350STK_AUDIO_CLK IOID_3 + +/* Buzzer */ +#define CC1350STK_BUZZER IOID_21 +#define CC1350STK_BUZZER_ON 1 +#define CC1350STK_BUZZER_OFF 0 + +/* DevPack */ +#define CC1350STK_AUDIOFS_TDO IOID_16 +#define CC1350STK_AUDIODO IOID_22 +#define CC1350STK_DP2 IOID_23 +#define CC1350STK_DP1 IOID_24 +#define CC1350STK_DP0 IOID_25 +#define CC1350STK_DP3 IOID_27 +#define CC1350STK_DP4_UARTRX IOID_28 +#define CC1350STK_DP5_UARTTX IOID_29 +#define CC1350STK_DEVPK_ID IOID_30 +#define CC1350STK_SPI_DEVPK_CS IOID_20 + +/* Discrete Outputs */ +#define CC1350STK_PIN_LED1 IOID_10 +#define CC1350STK_LED_ON 1 +#define CC1350STK_LED_OFF 0 + + +/* Discrete Inputs */ +#define CC1350STK_KEY_LEFT IOID_15 +#define CC1350STK_KEY_RIGHT IOID_4 +#define CC1350STK_RELAY IOID_1 + +/* GPIO */ +#define CC1350STK_GPIO_LED_ON 1 +#define CC1350STK_GPIO_LED_OFF 0 + +/* I2C */ +#define CC1350STK_I2C0_SDA0 IOID_5 +#define CC1350STK_I2C0_SCL0 IOID_6 +#define CC1350STK_I2C0_SDA1 IOID_8 +#define CC1350STK_I2C0_SCL1 IOID_9 + +/* LED-Audio DevPack */ +#define CC1350STK_DEVPK_LIGHT_BLUE IOID_23 +#define CC1350STK_DEVPK_LIGHT_GREEN IOID_24 +#define CC1350STK_DEVPK_LIGHT_WHITE IOID_25 +#define CC1350STK_DEVPK_LIGHT_RED IOID_27 + +/* Power */ +#define CC1350STK_MPU_POWER IOID_12 +#define CC1350STK_MPU_POWER_ON 1 +#define CC1350STK_MPU_POWER_OFF 0 + +/* PWM */ +#define CC1350STK_PWMPIN0 CC1350STK_PIN_LED1 +#define CC1350STK_PWMPIN1 CC1350STK_PIN_LED1 +#define CC1350STK_PWMPIN2 PIN_UNASSIGNED +#define CC1350STK_PWMPIN3 PIN_UNASSIGNED +#define CC1350STK_PWMPIN4 PIN_UNASSIGNED +#define CC1350STK_PWMPIN5 PIN_UNASSIGNED +#define CC1350STK_PWMPIN6 PIN_UNASSIGNED +#define CC1350STK_PWMPIN7 PIN_UNASSIGNED + +/* Sensors */ +#define CC1350STK_MPU_INT IOID_7 +#define CC1350STK_TMP_RDY IOID_11 + +/* SPI */ +#define CC1350STK_SPI_FLASH_CS IOID_14 +#define CC1350STK_FLASH_CS_ON 0 +#define CC1350STK_FLASH_CS_OFF 1 + +/* SPI Board */ +#define CC1350STK_SPI0_MISO IOID_18 +#define CC1350STK_SPI0_MOSI IOID_19 +#define CC1350STK_SPI0_CLK IOID_17 +#define CC1350STK_SPI0_CSN PIN_UNASSIGNED +#define CC1350STK_SPI1_MISO PIN_UNASSIGNED +#define CC1350STK_SPI1_MOSI PIN_UNASSIGNED +#define CC1350STK_SPI1_CLK PIN_UNASSIGNED +#define CC1350STK_SPI1_CSN PIN_UNASSIGNED + +/* UART */ +#define CC1350STK_UART_TX CC1350STK_DP5_UARTTX +#define CC1350STK_UART_RX CC1350STK_DP4_UARTRX + +/*! + * @brief Initialize the general board specific settings + * + * This function initializes the general board specific settings. + */ +void CC1350STK_initGeneral(void); + +/*! + * @brief Turn off the external flash on LaunchPads + * + */ +void CC1350STK_shutDownExtFlash(void); + +/*! + * @brief Wake up the external flash present on the board files + * + * This function toggles the chip select for the amount of time needed + * to wake the chip up. + */ +void CC1350STK_wakeUpExtFlash(void); + +/*! + * @def CC1350STK_CryptoName + * @brief Enum of Crypto names + */ +typedef enum CC1350STK_CryptoName { + CC1350STK_CRYPTO0 = 0, + + CC1350STK_CRYPTOCOUNT +} CC1350STK_CryptoName; + +/*! + * @def CC1350STK_GPIOName + * @brief Enum of GPIO names + */ +typedef enum CC1350STK_GPIOName { + CC1350STK_GPIO_S1 = 0, + CC1350STK_GPIO_S2, + CC1350STK_GPIO_LED0, + CC1350STK_GPIO_SPI_FLASH_CS, + CC1350STK_GPIO_LCD_CS, + CC1350STK_GPIO_LCD_ENABLE, + + CC1350STK_GPIOCOUNT +} CC1350STK_GPIOName; + +/*! + * @def CC1350STK_GPTimerName + * @brief Enum of GPTimers parts + */ +typedef enum CC1350STK_GPTimerName { + CC1350STK_GPTIMER0A = 0, + CC1350STK_GPTIMER0B, + CC1350STK_GPTIMER1A, + CC1350STK_GPTIMER1B, + CC1350STK_GPTIMER2A, + CC1350STK_GPTIMER2B, + CC1350STK_GPTIMER3A, + CC1350STK_GPTIMER3B, + + CC1350STK_GPTIMERPARTSCOUNT +} CC1350STK_GPTimerName; + +/*! + * @def CC1350STK_GPTimers + * @brief Enum of GPTimers + */ +typedef enum CC1350STK_GPTimers { + CC1350STK_GPTIMER0 = 0, + CC1350STK_GPTIMER1, + CC1350STK_GPTIMER2, + CC1350STK_GPTIMER3, + + CC1350STK_GPTIMERCOUNT +} CC1350STK_GPTimers; + +/*! + * @def CC1350STK_I2CName + * @brief Enum of I2C names + */ +typedef enum CC1350STK_I2CName { + CC1350STK_I2C0 = 0, + + CC1350STK_I2CCOUNT +} CC1350STK_I2CName; + +/*! + * @def CC1350STK_NVSName + * @brief Enum of NVS names + */ +typedef enum CC1350STK_NVSName { + CC1350STK_NVSCC26XX0 = 0, + CC1350STK_NVSSPI25X0, + + CC1350STK_NVSCOUNT +} CC1350STK_NVSName; + +/*! + * @def CC1350STK_PdmName + * @brief Enum of PDM names + */ +typedef enum CC1350STK_PDMName { + CC1350STK_PDM0 = 0, + + CC1350STK_PDMCOUNT +} CC1350STK_PDMName; + +/*! + * @def CC1350STK_PWM + * @brief Enum of PWM outputs + */ +typedef enum CC1350STK_PWMName { + CC1350STK_PWM0 = 0, + CC1350STK_PWM1, + CC1350STK_PWM2, + CC1350STK_PWM3, + CC1350STK_PWM4, + CC1350STK_PWM5, + CC1350STK_PWM6, + CC1350STK_PWM7, + + CC1350STK_PWMCOUNT +} CC1350STK_PWMName; + +/*! + * @def CC1350STK_SPIName + * @brief Enum of SPI names + */ +typedef enum CC1350STK_SPIName { + CC1350STK_SPI0 = 0, + CC1350STK_SPI1, + + CC1350STK_SPICOUNT +} CC1350STK_SPIName; + +/*! + * @def CC1350STK_UARTName + * @brief Enum of UARTs + */ +typedef enum CC1350STK_UARTName { + CC1350STK_UART0 = 0, + + CC1350STK_UARTCOUNT +} CC1350STK_UARTName; + +/*! + * @def CC1350STK_UDMAName + * @brief Enum of DMA buffers + */ +typedef enum CC1350STK_UDMAName { + CC1350STK_UDMA0 = 0, + + CC1350STK_UDMACOUNT +} CC1350STK_UDMAName; + +/*! + * @def CC1350STK_WatchdogName + * @brief Enum of Watchdogs + */ +typedef enum CC1350STK_WatchdogName { + CC1350STK_WATCHDOG0 = 0, + + CC1350STK_WATCHDOGCOUNT +} CC1350STK_WatchdogName; + +#ifdef __cplusplus +} +#endif + +#endif /* __CC1350STK_BOARD_H__ */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Makefile.cc1350 b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Makefile.cc1350 new file mode 100644 index 000000000..48e6d054b --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Makefile.cc1350 @@ -0,0 +1,16 @@ +################################################################################ +# SimpleLink Device makefile + +SUBFAMILY = cc13x0-cc26x0 +DEVICE_FAMILY = CC13X0 + +BOARD_SOURCEFILES += CC1350STK.c + +SUPPORTS_PROP_MODE = 1 +SUPPORTS_IEEE_MODE = 1 + +### Signal that we can be programmed with cc2538-bsl +BOARD_SUPPORTS_BSL = 1 + +# Include the common board makefile +include $(FAMILY_PATH)/sensortag/Makefile.sensortag diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h new file mode 100644 index 000000000..a1614e4fc --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2015-2016, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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 __BOARD_H +#define __BOARD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "CC2650STK.h" + +/* These #defines allow us to reuse TI-RTOS across other device families */ +#define Board_LED1 Board_STK_LED1 +#define Board_LED2 Board_STK_LED2 +#define Board_LED0 Board_LED2 + +#define Board_BUTTON0 Board_KEY_LEFT +#define Board_BUTTON1 Board_KEY_RIGHT + +#define Board_I2C0 Board_I2C +#define Board_I2C_TMP Board_I2C0 +#define Board_UART0 Board_UART +#define Board_AES0 Board_AES +#define Board_WATCHDOG0 CC2650STK_WATCHDOG0 + +#define Board_initGeneral() { \ + Power_init(); \ + if (PIN_init(BoardGpioInitTable) != PIN_SUCCESS) \ + {System_abort("Error with PIN_init\n"); \ + } \ +} + +#define Board_initGPIO() +#define Board_initPWM() PWM_init() +#define Board_initI2C() I2C_init() +#define Board_initSPI() SPI_init() +#define Board_initUART() UART_init() +#define Board_initWatchdog() Watchdog_init() +#define GPIO_toggle(n) +#define GPIO_write(n,m) + +/* Board specific I2C addresses */ + +/* Interface #0 */ +#define Board_HDC1000_ADDR (0x43) +#define Board_TMP007_ADDR (0x44) +#define Board_OPT3001_ADDR (0x45) +#define Board_BMP280_ADDR (0x77) + +/* Interface #1 */ +#define Board_MPU9250_ADDR (0x68) +#define Board_MPU9250_MAG_ADDR (0x0C) + +#ifdef __cplusplus +} +#endif + +#endif /* __BOARD_H */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.c new file mode 100644 index 000000000..5e3da594e --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.c @@ -0,0 +1,647 @@ +/* + * Copyright (c) 2015-2016, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +/* + * ====================== CC2650STK.c ========================================= + * This file is responsible for setting up the board specific items for the + * CC2650 SensorTag. + */ + + +/* + * ====================== Includes ============================================ + */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/* + * ========================= IO driver initialization ========================= + * From main, PIN_init(BoardGpioInitTable) should be called to setup safe + * settings for this board. + * When a pin is allocated and then de-allocated, it will revert to the state + * configured in this table. + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(BoardGpioInitTable, ".const:BoardGpioInitTable") +#pragma DATA_SECTION(PINCC26XX_hwAttrs, ".const:PINCC26XX_hwAttrs") +#endif + +const PIN_Config BoardGpioInitTable[] = { + + Board_STK_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + Board_STK_LED2 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + Board_KEY_LEFT | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + Board_KEY_RIGHT | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + Board_RELAY | PIN_INPUT_EN | PIN_PULLDOWN | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Relay is active high */ + Board_MPU_INT | PIN_INPUT_EN | PIN_PULLDOWN | PIN_IRQ_NEGEDGE | PIN_HYSTERESIS, /* MPU_INT is active low */ + Board_TMP_RDY | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS, /* TMP_RDY is active high */ + Board_BUZZER | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Buzzer initially off */ + Board_MPU_POWER | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* MPU initially on */ + Board_MIC_POWER | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* MIC initially off */ + Board_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ + Board_SPI_DEVPK_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* DevPack chip select */ + Board_AUDIO_DI | PIN_INPUT_EN | PIN_PULLDOWN, /* Audio DI */ + Board_AUDIODO | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* Audio data out */ + Board_AUDIO_CLK | PIN_INPUT_EN | PIN_PULLDOWN, /* DevPack */ + Board_DP2 | PIN_INPUT_EN | PIN_PULLDOWN, /* DevPack */ + Board_DP1 | PIN_INPUT_EN | PIN_PULLDOWN, /* DevPack */ + Board_DP0 | PIN_INPUT_EN | PIN_PULLDOWN, /* DevPack */ + Board_DP3 | PIN_INPUT_EN | PIN_PULLDOWN, /* DevPack */ + Board_UART_RX | PIN_INPUT_EN | PIN_PULLDOWN, /* DevPack */ + Board_UART_TX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* DevPack */ + Board_DEVPK_ID | PIN_INPUT_EN | PIN_NOPULL, /* Device pack ID - external PU */ + Board_SPI0_MOSI | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master out - slave in */ + Board_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master in - slave out */ + Board_SPI0_CLK | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI clock */ + + PIN_TERMINATE +}; + +const PINCC26XX_HWAttrs PINCC26XX_hwAttrs = { + .intPriority = ~0, + .swiPriority = 0 +}; +/*============================================================================*/ + +/* + * ============================= Power begin ================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(PowerCC26XX_config, ".const:PowerCC26XX_config") +#endif +const PowerCC26XX_Config PowerCC26XX_config = { + .policyInitFxn = NULL, + .policyFxn = &PowerCC26XX_standbyPolicy, + .calibrateFxn = &PowerCC26XX_calibrate, + .enablePolicy = TRUE, + .calibrateRCOSC_LF = TRUE, + .calibrateRCOSC_HF = TRUE, +}; +/* + * ============================= Power end =================================== + */ + +/* + * ============================= UART begin =================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(UART_config, ".const:UART_config") +#pragma DATA_SECTION(uartCC26XXHWAttrs, ".const:uartCC26XXHWAttrs") +#endif + +/* Include drivers */ +#include +#include + +/* UART objects */ +UARTCC26XX_Object uartCC26XXObjects[CC2650STK_UARTCOUNT]; +unsigned char uartCC26XXRingBuffer[CC2650STK_UARTCOUNT][32]; + +/* UART hardware parameter structure, also used to assign UART pins */ +const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC2650STK_UARTCOUNT] = { + { + .baseAddr = UART0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UART0, + .intNum = INT_UART0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .txPin = Board_UART_TX, + .rxPin = Board_UART_RX, + .ctsPin = PIN_UNASSIGNED, + .rtsPin = PIN_UNASSIGNED, + .ringBufPtr = uartCC26XXRingBuffer[0], + .ringBufSize = sizeof(uartCC26XXRingBuffer[0]) + } +}; + +/* UART configuration structure */ +const UART_Config UART_config[] = { + { + .fxnTablePtr = &UARTCC26XX_fxnTable, + .object = &uartCC26XXObjects[0], + .hwAttrs = &uartCC26XXHWAttrs[0] + }, + {NULL, NULL, NULL} +}; +/* + * ============================= UART end ===================================== + */ + +/* + * ============================= UDMA begin =================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(UDMACC26XX_config, ".const:UDMACC26XX_config") +#pragma DATA_SECTION(udmaHWAttrs, ".const:udmaHWAttrs") +#endif + +/* Include drivers */ +#include + +/* UDMA objects */ +UDMACC26XX_Object udmaObjects[CC2650STK_UDMACOUNT]; + +/* UDMA configuration structure */ +const UDMACC26XX_HWAttrs udmaHWAttrs[CC2650STK_UDMACOUNT] = { + { + .baseAddr = UDMA0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UDMA, + .intNum = INT_DMA_ERR, + .intPriority = ~0 + } +}; + +/* UDMA configuration structure */ +const UDMACC26XX_Config UDMACC26XX_config[] = { + { + .object = &udmaObjects[0], + .hwAttrs = &udmaHWAttrs[0] + }, + {NULL, NULL} +}; +/* + * ============================= UDMA end ===================================== + */ + +/* + * ========================== SPI DMA begin =================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(SPI_config, ".const:SPI_config") +#pragma DATA_SECTION(spiCC26XXDMAHWAttrs, ".const:spiCC26XXDMAHWAttrs") +#endif + +/* Include drivers */ +#include + +/* SPI objects */ +SPICC26XXDMA_Object spiCC26XXDMAObjects[CC2650STK_SPICOUNT]; + +/* SPI configuration structure, describing which pins are to be used */ +const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC2650STK_SPICOUNT] = { + { + .baseAddr = SSI0_BASE, + .intNum = INT_SSI0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .powerMngrId = PowerCC26XX_PERIPH_SSI0, + .defaultTxBufValue = 0, + .rxChannelBitMask = 1< + +/* I2C objects */ +I2CCC26XX_Object i2cCC26xxObjects[CC2650STK_I2CCOUNT]; + +/* I2C configuration structure, describing which pins are to be used */ +const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC2650STK_I2CCOUNT] = { + { + .baseAddr = I2C0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_I2C0, + .intNum = INT_I2C_IRQ, + .intPriority = ~0, + .swiPriority = 0, + .sdaPin = Board_I2C0_SDA0, + .sclPin = Board_I2C0_SCL0, + } +}; + +const I2C_Config I2C_config[] = { + { + .fxnTablePtr = &I2CCC26XX_fxnTable, + .object = &i2cCC26xxObjects[0], + .hwAttrs = &i2cCC26xxHWAttrs[0] + }, + {NULL, NULL, NULL} +}; +/* + * ========================== I2C end ========================================= + */ + +/* + * ========================== Crypto begin ==================================== + * NOTE: The Crypto implementation should be considered experimental + * and not validated! + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(CryptoCC26XX_config, ".const:CryptoCC26XX_config") +#pragma DATA_SECTION(cryptoCC26XXHWAttrs, ".const:cryptoCC26XXHWAttrs") +#endif + +/* Include drivers */ +#include + +/* Crypto objects */ +CryptoCC26XX_Object cryptoCC26XXObjects[CC2650STK_CRYPTOCOUNT]; + +/* Crypto configuration structure, describing which pins are to be used */ +const CryptoCC26XX_HWAttrs cryptoCC26XXHWAttrs[CC2650STK_CRYPTOCOUNT] = { + { + .baseAddr = CRYPTO_BASE, + .powerMngrId = PowerCC26XX_PERIPH_CRYPTO, + .intNum = INT_CRYPTO_RESULT_AVAIL_IRQ, + .intPriority = ~0, + } +}; + +/* Crypto configuration structure */ +const CryptoCC26XX_Config CryptoCC26XX_config[] = { + { + .object = &cryptoCC26XXObjects[0], + .hwAttrs = &cryptoCC26XXHWAttrs[0] + }, + {NULL, NULL} +}; +/* + * ========================== Crypto end ====================================== + */ + +/* + * ============================= PDM begin ==================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(PDMCC26XX_config, ".const:PDMCC26XX_config") +#pragma DATA_SECTION(pdmCC26XXHWAttrs, ".const:pdmCC26XXHWAttrs") +#pragma DATA_SECTION(pdmC26XXI2SHWAttrs, ".const:pdmC26XXI2SHWAttrs") +#pragma DATA_SECTION(PDMCC26XX_I2S_config, ".const:PDMCC26XX_I2S_config") +#endif + +/* Include drivers */ +#include +#include + +/* PDM objects, one for PDM driver, one for PDM/I2S helper file */ +PDMCC26XX_Object pdmCC26XXObjects[CC2650STK_PDMCOUNT]; +PDMCC26XX_I2S_Object pdmCC26XXI2SObjects[CC2650STK_PDMCOUNT]; + +/* PDM driver hardware attributes */ +const PDMCC26XX_HWAttrs pdmCC26XXHWAttrs[CC2650STK_PDMCOUNT] = { + { + .micPower = Board_MIC_POWER, + .taskPriority = 2 + } +}; + +/* PDM configuration structure */ +const PDMCC26XX_Config PDMCC26XX_config[] = { + { + .object = &pdmCC26XXObjects[0], + .hwAttrs = &pdmCC26XXHWAttrs[0] + } +}; + +/* PDM_I2S hardware attributes */ +const PDMCC26XX_I2S_HWAttrs pdmC26XXI2SHWAttrs[CC2650STK_PDMCOUNT] = { + { + .baseAddr = I2S0_BASE, + .intNum = INT_I2S_IRQ, + .powerMngrId = PowerCC26XX_PERIPH_I2S, + .intPriority = ~0, + .mclkPin = PIN_UNASSIGNED, + .bclkPin = Board_AUDIO_CLK, + .wclkPin = PIN_UNASSIGNED, + .ad0Pin = Board_AUDIO_DI, + } +}; + +/* PDM_I2S configuration structure */ +const PDMCC26XX_I2S_Config PDMCC26XX_I2S_config[] = { + { + .object = &pdmCC26XXI2SObjects[0], + .hwAttrs = &pdmC26XXI2SHWAttrs[0] + }, + { NULL, NULL } +}; + +/* + * ============================= PDM end ====================================== + */ + +/* + * ========================= RF driver begin ================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(RFCC26XX_hwAttrs, ".const:RFCC26XX_hwAttrs") +#endif + +/* Include drivers */ +#include + +/* RF hwi and swi priority */ +const RFCC26XX_HWAttrs RFCC26XX_hwAttrs = { + .hwiCpe0Priority = ~0, + .hwiHwPriority = ~0, + .swiCpe0Priority = 0, + .swiHwPriority = 0, +}; + +/* + * ========================== RF driver end =================================== + */ + +/* + * ========================= Display begin ==================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(Display_config, ".const:Display_config") +#pragma DATA_SECTION(displaySharpHWattrs, ".const:displaySharpHWattrs") +#pragma DATA_SECTION(displayUartHWAttrs, ".const:displayUartHWAttrs") +#endif + +#include +#include +#include + +/* Structures for UartPlain Blocking */ +DisplayUart_Object displayUartObject; + +#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE +#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 +#endif +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; + +const DisplayUart_HWAttrs displayUartHWAttrs = { + .uartIdx = Board_UART, + .baudRate = 115200, + .mutexTimeout = BIOS_WAIT_FOREVER, + .strBuf = uartStringBuf, + .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, +}; + +/* Structures for SHARP */ +DisplaySharp_Object displaySharpObject; + +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 // 96->96x96 is the most common board, alternative is 128->128x128. +#endif +static uint8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; + +const DisplaySharp_HWAttrs displaySharpHWattrs = { + .spiIndex = Board_SPI0, + .csPin = Board_LCD_CS, + .extcominPin = Board_LCD_EXTCOMIN, + .powerPin = Board_LCD_POWER, + .enablePin = Board_LCD_ENABLE, + .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, + .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, + .displayBuf = sharpDisplayBuf, +}; + +/* As the pins for UART and Watch Devpack conflict, prefer UART by default */ +#if !defined(BOARD_DISPLAY_EXCLUDE_UART) && !defined(BOARD_DISPLAY_EXCLUDE_LCD) +# define BOARD_DISPLAY_EXCLUDE_LCD +#endif + +/* Array of displays */ +const Display_Config Display_config[] = { +#if !defined(BOARD_DISPLAY_EXCLUDE_UART) + { + .fxnTablePtr = &DisplayUart_fxnTable, + .object = &displayUartObject, + .hwAttrs = &displayUartHWAttrs, + }, +#endif +#if !defined(BOARD_DISPLAY_EXCLUDE_LCD) + { + .fxnTablePtr = &DisplaySharp_fxnTable, + .object = &displaySharpObject, + .hwAttrs = &displaySharpHWattrs + }, +#endif + { NULL, NULL, NULL } // Terminator +}; + +/* + * ========================= Display end ====================================== + */ + +/* + * ============================ GPTimer begin ================================= + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(GPTimerCC26XX_config, ".const:GPTimerCC26XX_config") +#pragma DATA_SECTION(gptimerCC26xxHWAttrs, ".const:gptimerCC26xxHWAttrs") +#endif + +/* GPTimer hardware attributes, one per timer part (Timer 0A, 0B, 1A, 1B..) */ +const GPTimerCC26XX_HWAttrs gptimerCC26xxHWAttrs[CC2650STK_GPTIMERPARTSCOUNT] = { + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0A, }, + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0B, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1A, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1B, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2A, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2B, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3A, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3B, }, +}; + +/* GPTimer objects, one per full-width timer (A+B) (Timer 0, Timer 1..) */ +GPTimerCC26XX_Object gptimerCC26XXObjects[CC2650STK_GPTIMERCOUNT]; + +/* GPTimer configuration (used as GPTimer_Handle by driver and application) */ +const GPTimerCC26XX_Config GPTimerCC26XX_config[CC2650STK_GPTIMERPARTSCOUNT] = { + { &gptimerCC26XXObjects[0], &gptimerCC26xxHWAttrs[0], GPT_A }, + { &gptimerCC26XXObjects[0], &gptimerCC26xxHWAttrs[1], GPT_B }, + { &gptimerCC26XXObjects[1], &gptimerCC26xxHWAttrs[2], GPT_A }, + { &gptimerCC26XXObjects[1], &gptimerCC26xxHWAttrs[3], GPT_B }, + { &gptimerCC26XXObjects[2], &gptimerCC26xxHWAttrs[4], GPT_A }, + { &gptimerCC26XXObjects[2], &gptimerCC26xxHWAttrs[5], GPT_B }, + { &gptimerCC26XXObjects[3], &gptimerCC26xxHWAttrs[6], GPT_A }, + { &gptimerCC26XXObjects[3], &gptimerCC26xxHWAttrs[7], GPT_B }, +}; + +/* + * ============================ GPTimer end =================================== + */ + + + +/* + * ============================= PWM begin ==================================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(PWM_config, ".const:PWM_config") +#pragma DATA_SECTION(pwmtimerCC26xxHWAttrs, ".const:pwmtimerCC26xxHWAttrs") +#endif + +/* PWM configuration, one per PWM output. */ +PWMTimerCC26XX_HwAttrs pwmtimerCC26xxHWAttrs[CC2650STK_PWMCOUNT] = { + { .pwmPin = Board_PWMPIN0, .gpTimerUnit = Board_GPTIMER0A }, + { .pwmPin = Board_PWMPIN1, .gpTimerUnit = Board_GPTIMER0B }, + { .pwmPin = Board_PWMPIN2, .gpTimerUnit = Board_GPTIMER1A }, + { .pwmPin = Board_PWMPIN3, .gpTimerUnit = Board_GPTIMER1B }, + { .pwmPin = Board_PWMPIN4, .gpTimerUnit = Board_GPTIMER2A }, + { .pwmPin = Board_PWMPIN5, .gpTimerUnit = Board_GPTIMER2B }, + { .pwmPin = Board_PWMPIN6, .gpTimerUnit = Board_GPTIMER3A }, + { .pwmPin = Board_PWMPIN7, .gpTimerUnit = Board_GPTIMER3B }, +}; + +/* PWM object, one per PWM output */ +PWMTimerCC26XX_Object pwmtimerCC26xxObjects[CC2650STK_PWMCOUNT]; + +extern const PWM_FxnTable PWMTimerCC26XX_fxnTable; + +/* PWM configuration (used as PWM_Handle by driver and application) */ +const PWM_Config PWM_config[CC2650STK_PWMCOUNT + 1] = { + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[0], &pwmtimerCC26xxHWAttrs[0] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[1], &pwmtimerCC26xxHWAttrs[1] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[2], &pwmtimerCC26xxHWAttrs[2] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[3], &pwmtimerCC26xxHWAttrs[3] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[4], &pwmtimerCC26xxHWAttrs[4] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[5], &pwmtimerCC26xxHWAttrs[5] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[6], &pwmtimerCC26xxHWAttrs[6] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[7], &pwmtimerCC26xxHWAttrs[7] }, + { NULL, NULL, NULL } +}; + + +/* + * ============================= PWM end ====================================== + */ + +/* + * =============================== Watchdog =============================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(Watchdog_config, ".const:Watchdog_config") +#pragma DATA_SECTION(watchdogCC26XXHWAttrs, ".const:watchdogCC26XXHWAttrs") +#endif + +#include +#include + +WatchdogCC26XX_Object watchdogCC26XXObjects[CC2650STK_WATCHDOGCOUNT]; + +const WatchdogCC26XX_HWAttrs watchdogCC26XXHWAttrs[CC2650STK_WATCHDOGCOUNT] = { + { + .baseAddr = WDT_BASE, + .intNum = INT_WDT_IRQ, + .reloadValue = 1000 /* Reload value in milliseconds */ + }, +}; + +const Watchdog_Config Watchdog_config[] = { + { + .fxnTablePtr = &WatchdogCC26XX_fxnTable, + .object = &watchdogCC26XXObjects[0], + .hwAttrs = &watchdogCC26XXHWAttrs[0] + }, + {NULL, NULL, NULL}, +}; + +/* + * ======== CC26XX_LAUNCHXL_initWatchdog ======== + */ +void CC26XX_LAUNCHXL_initWatchdog(void) +{ + Watchdog_init(); +} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h new file mode 100644 index 000000000..6cfd69f7d --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2015-2016, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ +/** ============================================================================ + * @file CC2650STK.h + * + * @brief CC2650SENSORTAG Board Specific header file. + * + * NB! This is the board file for PCB versions 1.2 and 1.3 + * + * ============================================================================ + */ +#ifndef __CC2650STK_SENSORTAG_BOARD_H__ +#define __CC2650STK_SENSORTAG_BOARD_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** ============================================================================ + * Includes + * ==========================================================================*/ +#include +#include + +/** ============================================================================ + * Externs + * ==========================================================================*/ +extern const PIN_Config BoardGpioInitTable[]; + +/** ============================================================================ + * Defines + * ==========================================================================*/ + +/* Same RF Configuration as 7x7 EM */ +#define CC2650EM_7ID +#define CC2650STK + +/* Mapping of pins to board signals using general board aliases + * + */ + +/* Discrete outputs */ +#define Board_STK_LED1 IOID_10 +#define Board_STK_LED2 IOID_15 +#define Board_BUZZER IOID_21 +#define Board_LED_ON 1 +#define Board_LED_OFF 0 +#define Board_BUZZER_ON 1 +#define Board_BUZZER_OFF 0 + +/* Discrete inputs */ +#define Board_KEY_LEFT IOID_0 +#define Board_KEY_RIGHT IOID_4 +#define Board_RELAY IOID_3 + +/* Sensor outputs */ +#define Board_MPU_INT IOID_7 +#define Board_TMP_RDY IOID_1 + +/* I2C */ +#define Board_I2C0_SDA0 IOID_5 +#define Board_I2C0_SCL0 IOID_6 +#define Board_I2C0_SDA1 IOID_8 +#define Board_I2C0_SCL1 IOID_9 + +/* SPI */ +#define Board_SPI_FLASH_CS IOID_14 +#define Board_SPI_DEVPK_CS IOID_20 +#define Board_FLASH_CS_ON 0 +#define Board_FLASH_CS_OFF 1 +#define Board_DEVPK_CS_ON 1 +#define Board_DEVPK_CS_OFF 0 + +#define Board_SPI0_MISO IOID_18 +#define Board_SPI0_MOSI IOID_19 +#define Board_SPI0_CLK IOID_17 +#define Board_SPI0_CSN PIN_UNASSIGNED +#define Board_SPI1_MISO PIN_UNASSIGNED +#define Board_SPI1_MOSI PIN_UNASSIGNED +#define Board_SPI1_CLK PIN_UNASSIGNED +#define Board_SPI1_CSN PIN_UNASSIGNED + +/* UART when connected to SRF06EB */ +#define Board_EB_UART_TX IOID_16 +#define Board_EB_UART_RX IOID_17 + +/* Power control */ +#define Board_MPU_POWER IOID_12 +#define Board_MPU_POWER_ON 1 +#define Board_MPU_POWER_OFF 0 + +/* Audio */ +#define Board_MIC_POWER IOID_13 +#define Board_MIC_POWER_ON 1 +#define Board_MIC_POWER_OFF 0 +#define Board_AUDIO_DI IOID_2 +#define Board_AUDIO_CLK IOID_11 + +/* UART pins used by driver */ +#define Board_UART_TX Board_DP5_UARTTX +#define Board_UART_RX Board_DP4_UARTRX + +/* DevPack common */ +#define Board_AUDIOFS_TDO IOID_16 +#define Board_AUDIODO IOID_22 +#define Board_DP2 IOID_23 +#define Board_DP1 IOID_24 +#define Board_DP0 IOID_25 +#define Board_DP3 IOID_27 +#define Board_DP4_UARTRX IOID_28 +#define Board_DP5_UARTTX IOID_29 +#define Board_DEVPK_ID IOID_30 +#define Board_SPI_DEVPK_CS IOID_20 + +/* LCD DevPack */ +#define Board_LCD_EXTCOMIN IOID_22 +#define Board_LCD_EXTMODE IOID_28 +#define Board_LCD_ENABLE IOID_29 +#define Board_LCD_POWER PIN_UNASSIGNED +#define Board_LCD_CS Board_SPI_DEVPK_CS +#define Board_LCD_CS_ON 1 +#define Board_LCD_CS_OFF 0 + +/* LED-Audio DevPack */ +#define Board_DEVPK_LIGHT_BLUE IOID_23 +#define Board_DEVPK_LIGHT_GREEN IOID_24 +#define Board_DEVPK_LIGHT_WHITE IOID_25 +#define Board_DEVPK_LIGHT_RED IOID_27 + +/* PWM outputs */ +#define Board_PWMPIN0 Board_STK_LED1 +#define Board_PWMPIN1 Board_STK_LED2 +#define Board_PWMPIN2 PIN_UNASSIGNED +#define Board_PWMPIN3 PIN_UNASSIGNED +#define Board_PWMPIN4 PIN_UNASSIGNED +#define Board_PWMPIN5 PIN_UNASSIGNED +#define Board_PWMPIN6 PIN_UNASSIGNED +#define Board_PWMPIN7 PIN_UNASSIGNED + +/** ============================================================================ + * Instance identifiers + * ==========================================================================*/ +/* Generic I2C instance identifiers */ +#define Board_I2C CC2650STK_I2C0 +/* Generic PDM instance identifiers */ +#define Board_PDM CC2650STK_PDM0 +/* Generic SPI instance identifiers */ +#define Board_SPI0 CC2650STK_SPI0 +#define Board_SPI1 CC2650STK_SPI1 +/* Generic UART instance identifiers */ +#define Board_UART CC2650STK_UART0 +/* Generic Crypto instance identifiers */ +#define Board_CRYPTO CC2650STK_CRYPTO0 +/* Generic GPTimer instance identifiers */ +#define Board_GPTIMER0A CC2650STK_GPTIMER0A +#define Board_GPTIMER0B CC2650STK_GPTIMER0B +#define Board_GPTIMER1A CC2650STK_GPTIMER1A +#define Board_GPTIMER1B CC2650STK_GPTIMER1B +#define Board_GPTIMER2A CC2650STK_GPTIMER2A +#define Board_GPTIMER2B CC2650STK_GPTIMER2B +#define Board_GPTIMER3A CC2650STK_GPTIMER3A +#define Board_GPTIMER3B CC2650STK_GPTIMER3B +/* Generic PWM instance identifiers */ +#define Board_PWM0 CC2650STK_PWM0 +#define Board_PWM1 CC2650STK_PWM1 +#define Board_PWM2 CC2650STK_PWM2 +#define Board_PWM3 CC2650STK_PWM3 +#define Board_PWM4 CC2650STK_PWM4 +#define Board_PWM5 CC2650STK_PWM5 +#define Board_PWM6 CC2650STK_PWM6 +#define Board_PWM7 CC2650STK_PWM7 + +/** ============================================================================ + * Number of peripherals and their names + * ==========================================================================*/ + +/*! + * @def CC2650STK_I2CName + * @brief Enum of I2C names on the CC2650 dev board + */ +typedef enum CC2650STK_I2CName { + CC2650STK_I2C0 = 0, + + CC2650STK_I2CCOUNT +} CC2650STK_I2CName; + +/*! + * @def CC2650STK_CryptoName + * @brief Enum of Crypto names on the CC2650 dev board + */ +typedef enum CC2650STK_CryptoName { + CC2650STK_CRYPTO0 = 0, + + CC2650STK_CRYPTOCOUNT +} CC2650STK_CryptoName; + +/*! + * @def CC2650STK_PdmName + * @brief Enum of PDM names on the CC2650 dev board + */ +typedef enum CC2650STK_PDMName { + CC2650STK_PDM0 = 0, + CC2650STK_PDMCOUNT +} CC2650STK_PDMName; + +/*! + * @def CC2650STK_SPIName + * @brief Enum of SPI names on the CC2650 dev board + */ +typedef enum CC2650STK_SPIName { + CC2650STK_SPI0 = 0, + CC2650STK_SPI1, + + CC2650STK_SPICOUNT +} CC2650STK_SPIName; + +/*! + * @def CC2650STK_UARTName + * @brief Enum of UARTs on the CC2650 dev board + */ +typedef enum CC2650STK_UARTName { + CC2650STK_UART0 = 0, + + CC2650STK_UARTCOUNT +} CC2650STK_UARTName; + +/*! + * @def CC2650STK_UdmaName + * @brief Enum of DMA buffers + */ +typedef enum CC2650STK_UdmaName { + CC2650STK_UDMA0 = 0, + + CC2650STK_UDMACOUNT +} CC2650STK_UdmaName; +/*! + * @def CC2650STK_GPTimerName + * @brief Enum of GPTimer parts + */ +typedef enum CC2650STK_GPTimerName +{ + CC2650STK_GPTIMER0A = 0, + CC2650STK_GPTIMER0B, + CC2650STK_GPTIMER1A, + CC2650STK_GPTIMER1B, + CC2650STK_GPTIMER2A, + CC2650STK_GPTIMER2B, + CC2650STK_GPTIMER3A, + CC2650STK_GPTIMER3B, + CC2650STK_GPTIMERPARTSCOUNT +} CC2650STK_GPTimerName; + +/*! + * @def CC2650STK_GPTimers + * @brief Enum of GPTimers + */ +typedef enum CC2650STK_GPTimers +{ + CC2650STK_GPTIMER0 = 0, + CC2650STK_GPTIMER1, + CC2650STK_GPTIMER2, + CC2650STK_GPTIMER3, + CC2650STK_GPTIMERCOUNT +} CC2650STK_GPTimers; + +/*! + * @def CC2650STK_PWM + * @brief Enum of PWM outputs on the board + */ +typedef enum CC2650STK_PWM +{ + CC2650STK_PWM0 = 0, + CC2650STK_PWM1, + CC2650STK_PWM2, + CC2650STK_PWM3, + CC2650STK_PWM4, + CC2650STK_PWM5, + CC2650STK_PWM6, + CC2650STK_PWM7, + CC2650STK_PWMCOUNT +} CC2650STK_PWM; + +/*! + * @def CC2650STK_WatchdogName + * @brief Enum of Watchdogs on the CC2650STK dev board + */ +typedef enum CC2650STK_WatchdogName { + CC2650STK_WATCHDOG0 = 0, + + CC2650STK_WATCHDOGCOUNT +} CC2650STK_WatchdogName; + +#ifdef __cplusplus +} +#endif + +#endif /* __CC2650STK_SENSORTAG_BOARD_H__ */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 new file mode 100644 index 000000000..2e6c713e6 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 @@ -0,0 +1,16 @@ +################################################################################ +# SimpleLink Device makefile + +SUBFAMILY = cc13x0-cc26x0 +DEVICE_FAMILY = CC26X0 + +BOARD_SOURCEFILES += CC2650STK.c + +SUPPORTS_PROP_MODE = 1 +SUPPORTS_IEEE_MODE = 1 + +### Signal that we can be programmed with cc2538-bsl +BOARD_SUPPORTS_BSL = 1 + +# Include the common board makefile +include $(FAMILY_PATH)/sensortag/Makefile.sensortag diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.c new file mode 100644 index 000000000..acc5f19be --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.c @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup sensortag-cc26xx-hdc-sensor + * @{ + * + * \file + * Driver for the Sensortag HDC sensor + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "sys/ctimer.h" +#include "lib/sensors.h" +#include "hdc-1000-sensor.h" +#include "sensor-common.h" +#include "board-i2c.h" + +#include "ti-lib.h" + +#include +#include +#include +#include +/*---------------------------------------------------------------------------*/ +#define DEBUG 0 +#if DEBUG +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif +/*---------------------------------------------------------------------------*/ +/* Sensor I2C address */ +#define SENSOR_I2C_ADDRESS 0x43 + +/* Registers */ +#define HDC1000_REG_TEMP 0x00 /* Temperature */ +#define HDC1000_REG_HUM 0x01 /* Humidity */ +#define HDC1000_REG_CONFIG 0x02 /* Configuration */ +#define HDC1000_REG_SERID_H 0xFB /* Serial ID high */ +#define HDC1000_REG_SERID_M 0xFC /* Serial ID middle */ +#define HDC1000_REG_SERID_L 0xFD /* Serial ID low */ +#define HDC1000_REG_MANF_ID 0xFE /* Manufacturer ID */ +#define HDC1000_REG_DEV_ID 0xFF /* Device ID */ + +/* Fixed values */ +#define HDC1000_VAL_MANF_ID 0x5449 +#define HDC1000_VAL_DEV_ID 0x1000 +#define HDC1000_VAL_CONFIG 0x1000 /* 14 bit, acquired in sequence */ + +/* Sensor selection/deselection */ +#define SENSOR_SELECT() board_i2c_select(BOARD_I2C_INTERFACE_0, SENSOR_I2C_ADDRESS) +#define SENSOR_DESELECT() board_i2c_deselect() +/*---------------------------------------------------------------------------*/ +/* Byte swap of 16-bit register value */ +#define HI_UINT16(a) (((a) >> 8) & 0xFF) +#define LO_UINT16(a) ((a) & 0xFF) + +#define SWAP(v) ((LO_UINT16(v) << 8) | HI_UINT16(v)) +/*---------------------------------------------------------------------------*/ +/* Raw data as returned from the sensor (Big Endian) */ +typedef struct sensor_data { + uint16_t temp; + uint16_t hum; +} sensor_data_t; + +/* Raw data, little endian */ +static uint16_t raw_temp; +static uint16_t raw_hum; +/*---------------------------------------------------------------------------*/ +static bool success; +static sensor_data_t data; +/*---------------------------------------------------------------------------*/ +static int enabled = HDC_1000_SENSOR_STATUS_DISABLED; +/*---------------------------------------------------------------------------*/ +/* + * Maximum measurement durations in clock ticks. We use 14bit resolution, thus: + * - Tmp: 6.35ms + * - RH: 6.5ms + */ +#define MEASUREMENT_DURATION 2 + +/* + * Wait SENSOR_STARTUP_DELAY clock ticks between activation and triggering a + * reading (max 15ms) + */ +#define SENSOR_STARTUP_DELAY 3 + +static struct ctimer startup_timer; +/*---------------------------------------------------------------------------*/ +/** + * \brief Initialise the humidity sensor driver + * \return True if I2C operation successful + */ +static bool +sensor_init(void) +{ + uint16_t val; + + SENSOR_SELECT(); + + /* Enable reading data in one operation */ + val = SWAP(HDC1000_VAL_CONFIG); + success = sensor_common_write_reg(HDC1000_REG_CONFIG, (uint8_t *)&val, 2); + + SENSOR_DESELECT(); + + return success; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Start measurement + */ +static void +start(void) +{ + if(success) { + SENSOR_SELECT(); + + success = board_i2c_write_single(HDC1000_REG_TEMP); + SENSOR_DESELECT(); + } +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Take readings from the sensor + * \return true of I2C operations successful + */ +static bool +read_data() +{ + bool valid; + + if(success) { + SENSOR_SELECT(); + + success = board_i2c_read((uint8_t *)&data, sizeof(data)); + SENSOR_DESELECT(); + + /* Store temperature */ + raw_temp = SWAP(data.temp); + + /* Store humidity */ + raw_hum = SWAP(data.hum); + } + + valid = success; + success = true; + + return valid; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Convert raw data to temperature and humidity + * \param temp - converted temperature + * \param hum - converted humidity + */ +static void +convert(float *temp, float *hum) +{ + /* Convert temperature to degrees C */ + *temp = ((double)raw_temp / 65536) * 165 - 40; + + /* Convert relative humidity to a %RH value */ + *hum = ((double)raw_hum / 65536) * 100; +} +/*---------------------------------------------------------------------------*/ +static void +notify_ready(void *not_used) +{ + enabled = HDC_1000_SENSOR_STATUS_READINGS_READY; + + /* Latch readings */ + read_data(); + + sensors_changed(&hdc_1000_sensor); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Returns a reading from the sensor + * \param type HDC_1000_SENSOR_TYPE_TEMP or HDC_1000_SENSOR_TYPE_HUMIDITY + * \return Temperature (centi degrees C) or Humidity (centi %RH) + */ +static int +value(int type) +{ + int rv; + float temp; + float hum; + + if(enabled != HDC_1000_SENSOR_STATUS_READINGS_READY) { + PRINTF("Sensor disabled or starting up (%d)\n", enabled); + return CC26XX_SENSOR_READING_ERROR; + } + + if((type != HDC_1000_SENSOR_TYPE_TEMP) && + type != HDC_1000_SENSOR_TYPE_HUMIDITY) { + PRINTF("Invalid type\n"); + return CC26XX_SENSOR_READING_ERROR; + } else { + convert(&temp, &hum); + PRINTF("HDC: %04X %04X t=%d h=%d\n", raw_temp, raw_hum, + (int)(temp * 100), (int)(hum * 100)); + + if(type == HDC_1000_SENSOR_TYPE_TEMP) { + rv = (int)(temp * 100); + } else if(type == HDC_1000_SENSOR_TYPE_HUMIDITY) { + rv = (int)(hum * 100); + } + } + return rv; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Configuration function for the HDC1000 sensor. + * + * \param type Activate, enable or disable the sensor. See below + * \param enable + * + * When type == SENSORS_HW_INIT we turn on the hardware + * When type == SENSORS_ACTIVE and enable==1 we enable the sensor + * When type == SENSORS_ACTIVE and enable==0 we disable the sensor + */ +static int +configure(int type, int enable) +{ + switch(type) { + case SENSORS_HW_INIT: + raw_temp = 0; + raw_hum = 0; + memset(&data, 0, sizeof(data)); + + sensor_init(); + enabled = HDC_1000_SENSOR_STATUS_INITIALISED; + break; + case SENSORS_ACTIVE: + /* Must be initialised first */ + if(enabled == HDC_1000_SENSOR_STATUS_DISABLED) { + return HDC_1000_SENSOR_STATUS_DISABLED; + } + if(enable) { + start(); + ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready, NULL); + enabled = HDC_1000_SENSOR_STATUS_TAKING_READINGS; + } else { + ctimer_stop(&startup_timer); + enabled = HDC_1000_SENSOR_STATUS_INITIALISED; + } + break; + default: + break; + } + return enabled; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Returns the status of the sensor + * \param type SENSORS_ACTIVE or SENSORS_READY + * \return One of the SENSOR_STATUS_xyz defines + */ +static int +status(int type) +{ + switch(type) { + case SENSORS_ACTIVE: + case SENSORS_READY: + return enabled; + break; + default: + break; + } + return HDC_1000_SENSOR_STATUS_DISABLED; +} +/*---------------------------------------------------------------------------*/ +SENSORS_SENSOR(hdc_1000_sensor, "HDC1000", value, configure, status); +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.h new file mode 100644 index 000000000..d3089d742 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup sensortag-cc26xx-peripherals + * @{ + * + * \defgroup sensortag-cc26xx-hdc-sensor SensorTag 2.0 TI HDC1000 Sensor + * + * Due to the time required for the sensor to startup, this driver is meant to + * be used in an asynchronous fashion. The caller must first activate the + * sensor by calling SENSORS_ACTIVATE(). This will trigger the sensor's startup + * sequence, but the call will not wait for it to complete so that the CPU can + * perform other tasks or drop to a low power mode. Once the sensor has taken + * readings, it will automatically go back to low power mode. + * + * Once the sensor is stable, the driver will retrieve readings from the sensor + * and latch them. It will then generate a sensors_changed event. + * + * The user can then retrieve readings by calling .value() and by passing + * either HDC_1000_SENSOR_TYPE_TEMP or HDC_1000_SENSOR_TYPE_HUMIDITY as the + * argument. Multiple calls to value() will not trigger new readings, they will + * simply return the most recent latched values. + * + * The user can query the sensor's status by calling .status() + * + * To get a fresh reading, the user must trigger a new reading cycle by calling + * SENSORS_ACTIVATE(). + * @{ + * + * \file + * Header file for the Sensortag TI HDC1000 sensor + */ +/*---------------------------------------------------------------------------*/ +#ifndef HDC_1000_SENSOR_H +#define HDC_1000_SENSOR_H +/*---------------------------------------------------------------------------*/ +#include "lib/sensors.h" +/*---------------------------------------------------------------------------*/ +#define HDC_1000_SENSOR_TYPE_TEMP 1 +#define HDC_1000_SENSOR_TYPE_HUMIDITY 2 +/*---------------------------------------------------------------------------*/ +/** + * \name HDC1000 driver states + * @{ + */ +#define HDC_1000_SENSOR_STATUS_DISABLED 0 /**< Not initialised */ +#define HDC_1000_SENSOR_STATUS_INITIALISED 1 /**< Initialised but idle */ +#define HDC_1000_SENSOR_STATUS_TAKING_READINGS 2 /**< Readings in progress */ +#define HDC_1000_SENSOR_STATUS_READINGS_READY 3 /**< Both readings ready */ +/** @} */ +/*---------------------------------------------------------------------------*/ +extern const struct sensors_sensor hdc_1000_sensor; +/*---------------------------------------------------------------------------*/ +#endif /* HDC_1000_SENSOR_H */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c new file mode 100644 index 000000000..a2b3651e5 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c @@ -0,0 +1,663 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup sensortag-cc26xx-mpu + * @{ + * + * \file + * Driver for the Sensortag Invensense MPU9250 motion processing unit + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "lib/sensors.h" +#include "mpu-9250-sensor.h" +#include "sys/rtimer.h" +#include "sensor-common.h" +#include "board-i2c.h" + +#include "ti-lib.h" + +#include +#include +#include +#include +/*---------------------------------------------------------------------------*/ +#define DEBUG 0 +#if DEBUG +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif +/*---------------------------------------------------------------------------*/ +/* Sensor I2C address */ +#define SENSOR_I2C_ADDRESS 0x68 +#define SENSOR_MAG_I2_ADDRESS 0x0C +/*---------------------------------------------------------------------------*/ +/* Registers */ +#define SELF_TEST_X_GYRO 0x00 /* R/W */ +#define SELF_TEST_Y_GYRO 0x01 /* R/W */ +#define SELF_TEST_Z_GYRO 0x02 /* R/W */ +#define SELF_TEST_X_ACCEL 0x0D /* R/W */ +#define SELF_TEST_Z_ACCEL 0x0E /* R/W */ +#define SELF_TEST_Y_ACCEL 0x0F /* R/W */ +/*---------------------------------------------------------------------------*/ +#define XG_OFFSET_H 0x13 /* R/W */ +#define XG_OFFSET_L 0x14 /* R/W */ +#define YG_OFFSET_H 0x15 /* R/W */ +#define YG_OFFSET_L 0x16 /* R/W */ +#define ZG_OFFSET_H 0x17 /* R/W */ +#define ZG_OFFSET_L 0x18 /* R/W */ +/*---------------------------------------------------------------------------*/ +#define SMPLRT_DIV 0x19 /* R/W */ +#define CONFIG 0x1A /* R/W */ +#define GYRO_CONFIG 0x1B /* R/W */ +#define ACCEL_CONFIG 0x1C /* R/W */ +#define ACCEL_CONFIG_2 0x1D /* R/W */ +#define LP_ACCEL_ODR 0x1E /* R/W */ +#define WOM_THR 0x1F /* R/W */ +#define FIFO_EN 0x23 /* R/W */ +/*---------------------------------------------------------------------------*/ +/* + * Registers 0x24 - 0x36 are not applicable to the SensorTag HW configuration + * (IC2 Master) + */ +#define INT_PIN_CFG 0x37 /* R/W */ +#define INT_ENABLE 0x38 /* R/W */ +#define INT_STATUS 0x3A /* R */ +#define ACCEL_XOUT_H 0x3B /* R */ +#define ACCEL_XOUT_L 0x3C /* R */ +#define ACCEL_YOUT_H 0x3D /* R */ +#define ACCEL_YOUT_L 0x3E /* R */ +#define ACCEL_ZOUT_H 0x3F /* R */ +#define ACCEL_ZOUT_L 0x40 /* R */ +#define TEMP_OUT_H 0x41 /* R */ +#define TEMP_OUT_L 0x42 /* R */ +#define GYRO_XOUT_H 0x43 /* R */ +#define GYRO_XOUT_L 0x44 /* R */ +#define GYRO_YOUT_H 0x45 /* R */ +#define GYRO_YOUT_L 0x46 /* R */ +#define GYRO_ZOUT_H 0x47 /* R */ +#define GYRO_ZOUT_L 0x48 /* R */ +/*---------------------------------------------------------------------------*/ +/* + * Registers 0x49 - 0x60 are not applicable to the SensorTag HW configuration + * (external sensor data) + * + * Registers 0x63 - 0x67 are not applicable to the SensorTag HW configuration + * (I2C master) + */ +#define SIGNAL_PATH_RESET 0x68 /* R/W */ +#define ACCEL_INTEL_CTRL 0x69 /* R/W */ +#define USER_CTRL 0x6A /* R/W */ +#define PWR_MGMT_1 0x6B /* R/W */ +#define PWR_MGMT_2 0x6C /* R/W */ +#define FIFO_COUNT_H 0x72 /* R/W */ +#define FIFO_COUNT_L 0x73 /* R/W */ +#define FIFO_R_W 0x74 /* R/W */ +#define WHO_AM_I 0x75 /* R/W */ +/*---------------------------------------------------------------------------*/ +/* Masks is mpuConfig valiable */ +#define ACC_CONFIG_MASK 0x38 +#define GYRO_CONFIG_MASK 0x07 +/*---------------------------------------------------------------------------*/ +/* Values PWR_MGMT_1 */ +#define MPU_SLEEP 0x4F /* Sleep + stop all clocks */ +#define MPU_WAKE_UP 0x09 /* Disable temp. + intern osc */ +/*---------------------------------------------------------------------------*/ +/* Values PWR_MGMT_2 */ +#define ALL_AXES 0x3F +#define GYRO_AXES 0x07 +#define ACC_AXES 0x38 +/*---------------------------------------------------------------------------*/ +/* Data sizes */ +#define DATA_SIZE 6 +/*---------------------------------------------------------------------------*/ +/* Output data rates */ +#define INV_LPA_0_3125HZ 0 +#define INV_LPA_0_625HZ 1 +#define INV_LPA_1_25HZ 2 +#define INV_LPA_2_5HZ 3 +#define INV_LPA_5HZ 4 +#define INV_LPA_10HZ 5 +#define INV_LPA_20HZ 6 +#define INV_LPA_40HZ 7 +#define INV_LPA_80HZ 8 +#define INV_LPA_160HZ 9 +#define INV_LPA_320HZ 10 +#define INV_LPA_640HZ 11 +#define INV_LPA_STOPPED 255 +/*---------------------------------------------------------------------------*/ +/* Bit values */ +#define BIT_ANY_RD_CLR 0x10 +#define BIT_RAW_RDY_EN 0x01 +#define BIT_WOM_EN 0x40 +#define BIT_LPA_CYCLE 0x20 +#define BIT_STBY_XA 0x20 +#define BIT_STBY_YA 0x10 +#define BIT_STBY_ZA 0x08 +#define BIT_STBY_XG 0x04 +#define BIT_STBY_YG 0x02 +#define BIT_STBY_ZG 0x01 +#define BIT_STBY_XYZA (BIT_STBY_XA | BIT_STBY_YA | BIT_STBY_ZA) +#define BIT_STBY_XYZG (BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG) +/*---------------------------------------------------------------------------*/ +/* User control register */ +#define BIT_ACTL 0x80 +#define BIT_LATCH_EN 0x20 +/*---------------------------------------------------------------------------*/ +/* INT Pin / Bypass Enable Configuration */ +#define BIT_AUX_IF_EN 0x20 /* I2C_MST_EN */ +#define BIT_BYPASS_EN 0x02 +/*---------------------------------------------------------------------------*/ +#define ACC_RANGE_INVALID -1 + +#define ACC_RANGE_2G 0 +#define ACC_RANGE_4G 1 +#define ACC_RANGE_8G 2 +#define ACC_RANGE_16G 3 + +#define MPU_AX_GYR_X 2 +#define MPU_AX_GYR_Y 1 +#define MPU_AX_GYR_Z 0 +#define MPU_AX_GYR 0x07 + +#define MPU_AX_ACC_X 5 +#define MPU_AX_ACC_Y 4 +#define MPU_AX_ACC_Z 3 +#define MPU_AX_ACC 0x38 + +#define MPU_AX_MAG 6 +/*---------------------------------------------------------------------------*/ +#define MPU_DATA_READY 0x01 +#define MPU_MOVEMENT 0x40 +/*---------------------------------------------------------------------------*/ +/* Sensor selection/deselection */ +#define SENSOR_SELECT() board_i2c_select(BOARD_I2C_INTERFACE_1, SENSOR_I2C_ADDRESS) +#define SENSOR_DESELECT() board_i2c_deselect() +/*---------------------------------------------------------------------------*/ +/* Delay */ +#define delay_ms(i) (ti_lib_cpu_delay(8000 * (i))) +/*---------------------------------------------------------------------------*/ +static uint8_t mpu_config; +static uint8_t acc_range; +static uint8_t acc_range_reg; +static uint8_t val; +static uint8_t interrupt_status; +/*---------------------------------------------------------------------------*/ +#define SENSOR_STATE_DISABLED 0 +#define SENSOR_STATE_BOOTING 1 +#define SENSOR_STATE_ENABLED 2 + +static int state = SENSOR_STATE_DISABLED; +static int elements = MPU_9250_SENSOR_TYPE_NONE; +/*---------------------------------------------------------------------------*/ +/* 3 16-byte words for all sensor readings */ +#define SENSOR_DATA_BUF_SIZE 3 + +static uint16_t sensor_value[SENSOR_DATA_BUF_SIZE]; +/*---------------------------------------------------------------------------*/ +/* + * Wait SENSOR_BOOT_DELAY ticks for the sensor to boot and + * SENSOR_STARTUP_DELAY for readings to be ready + * Gyro is a little slower than Acc + */ +#define SENSOR_BOOT_DELAY 8 +#define SENSOR_STARTUP_DELAY 5 + +static struct ctimer startup_timer; +/*---------------------------------------------------------------------------*/ +/* Wait for the MPU to have data ready */ +rtimer_clock_t t0; + +/* + * Wait timeout in rtimer ticks. This is just a random low number, since the + * first time we read the sensor status, it should be ready to return data + */ +#define READING_WAIT_TIMEOUT 10 +/*---------------------------------------------------------------------------*/ +/** + * \brief Place the MPU in low power mode + */ +static void +sensor_sleep(void) +{ + SENSOR_SELECT(); + + val = ALL_AXES; + sensor_common_write_reg(PWR_MGMT_2, &val, 1); + + val = MPU_SLEEP; + sensor_common_write_reg(PWR_MGMT_1, &val, 1); + SENSOR_DESELECT(); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Exit low power mode + */ +static void +sensor_wakeup(void) +{ + SENSOR_SELECT(); + val = MPU_WAKE_UP; + sensor_common_write_reg(PWR_MGMT_1, &val, 1); + + /* All axis initially disabled */ + val = ALL_AXES; + sensor_common_write_reg(PWR_MGMT_2, &val, 1); + mpu_config = 0; + + /* Restore the range */ + sensor_common_write_reg(ACCEL_CONFIG, &acc_range_reg, 1); + + /* Clear interrupts */ + sensor_common_read_reg(INT_STATUS, &val, 1); + SENSOR_DESELECT(); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Select gyro and accelerometer axes + */ +static void +select_axes(void) +{ + val = ~mpu_config; + SENSOR_SELECT(); + sensor_common_write_reg(PWR_MGMT_2, &val, 1); + SENSOR_DESELECT(); +} +/*---------------------------------------------------------------------------*/ +static void +convert_to_le(uint8_t *data, uint8_t len) +{ + int i; + for(i = 0; i < len; i += 2) { + uint8_t tmp; + tmp = data[i]; + data[i] = data[i + 1]; + data[i + 1] = tmp; + } +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Set the range of the accelerometer + * \param new_range: ACC_RANGE_2G, ACC_RANGE_4G, ACC_RANGE_8G, ACC_RANGE_16G + * \return true if the write to the sensor succeeded + */ +static bool +acc_set_range(uint8_t new_range) +{ + bool success; + + if(new_range == acc_range) { + return true; + } + + success = false; + + acc_range_reg = (new_range << 3); + + /* Apply the range */ + SENSOR_SELECT(); + success = sensor_common_write_reg(ACCEL_CONFIG, &acc_range_reg, 1); + SENSOR_DESELECT(); + + if(success) { + acc_range = new_range; + } + + return success; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Check whether a data or wake on motion interrupt has occurred + * \return Return the interrupt status + * + * This driver does not use interrupts, however this function allows us to + * determine whether a new sensor reading is available + */ +static uint8_t +int_status(void) +{ + SENSOR_SELECT(); + sensor_common_read_reg(INT_STATUS, &interrupt_status, 1); + SENSOR_DESELECT(); + + return interrupt_status; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Enable the MPU + * \param axes: Gyro bitmap [0..2], X = 1, Y = 2, Z = 4. 0 = gyro off + * Acc bitmap [3..5], X = 8, Y = 16, Z = 32. 0 = accelerometer off + */ +static void +enable_sensor(uint16_t axes) +{ + if(mpu_config == 0 && axes != 0) { + /* Wake up the sensor if it was off */ + sensor_wakeup(); + } + + mpu_config = axes; + + if(mpu_config != 0) { + /* Enable gyro + accelerometer readout */ + select_axes(); + delay_ms(10); + } else if(mpu_config == 0) { + sensor_sleep(); + } +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Read data from the accelerometer - X, Y, Z - 3 words + * \return True if a valid reading could be taken, false otherwise + */ +static bool +acc_read(uint16_t *data) +{ + bool success; + + if(interrupt_status & BIT_RAW_RDY_EN) { + /* Burst read of all accelerometer values */ + SENSOR_SELECT(); + success = sensor_common_read_reg(ACCEL_XOUT_H, (uint8_t *)data, DATA_SIZE); + SENSOR_DESELECT(); + + if(success) { + convert_to_le((uint8_t *)data, DATA_SIZE); + } else { + sensor_common_set_error_data((uint8_t *)data, DATA_SIZE); + } + } else { + /* Data not ready */ + success = false; + } + + return success; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Read data from the gyroscope - X, Y, Z - 3 words + * \return True if a valid reading could be taken, false otherwise + */ +static bool +gyro_read(uint16_t *data) +{ + bool success; + + if(interrupt_status & BIT_RAW_RDY_EN) { + /* Select this sensor */ + SENSOR_SELECT(); + + /* Burst read of all gyroscope values */ + success = sensor_common_read_reg(GYRO_XOUT_H, (uint8_t *)data, DATA_SIZE); + + if(success) { + convert_to_le((uint8_t *)data, DATA_SIZE); + } else { + sensor_common_set_error_data((uint8_t *)data, DATA_SIZE); + } + + SENSOR_DESELECT(); + } else { + success = false; + } + + return success; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Convert accelerometer raw reading to a value in G + * \param raw_data The raw accelerometer reading + * \return The converted value + */ +static float +acc_convert(int16_t raw_data) +{ + float v = 0; + + switch(acc_range) { + case ACC_RANGE_2G: + /* Calculate acceleration, unit G, range -2, +2 */ + v = (raw_data * 1.0) / (32768 / 2); + break; + case ACC_RANGE_4G: + /* Calculate acceleration, unit G, range -4, +4 */ + v = (raw_data * 1.0) / (32768 / 4); + break; + case ACC_RANGE_8G: + /* Calculate acceleration, unit G, range -8, +8 */ + v = (raw_data * 1.0) / (32768 / 8); + break; + case ACC_RANGE_16G: + /* Calculate acceleration, unit G, range -16, +16 */ + v = (raw_data * 1.0) / (32768 / 16); + break; + default: + v = 0; + break; + } + + return v; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Convert gyro raw reading to a value in deg/sec + * \param raw_data The raw accelerometer reading + * \return The converted value + */ +static float +gyro_convert(int16_t raw_data) +{ + /* calculate rotation, unit deg/s, range -250, +250 */ + return (raw_data * 1.0) / (65536 / 500); +} +/*---------------------------------------------------------------------------*/ +static void +notify_ready(void *not_used) +{ + state = SENSOR_STATE_ENABLED; + sensors_changed(&mpu_9250_sensor); +} +/*---------------------------------------------------------------------------*/ +static void +initialise(void *not_used) +{ + /* Configure the accelerometer range */ + if((elements & MPU_9250_SENSOR_TYPE_ACC) != 0) { + acc_set_range(MPU_9250_SENSOR_ACC_RANGE); + } + + enable_sensor(elements & MPU_9250_SENSOR_TYPE_ALL); + + ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready, NULL); +} +/*---------------------------------------------------------------------------*/ +static void +power_up(void) +{ + ti_lib_gpio_set_dio(BOARD_IOID_MPU_POWER); + state = SENSOR_STATE_BOOTING; + + ctimer_set(&startup_timer, SENSOR_BOOT_DELAY, initialise, NULL); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Returns a reading from the sensor + * \param type MPU_9250_SENSOR_TYPE_ACC_[XYZ] or MPU_9250_SENSOR_TYPE_GYRO_[XYZ] + * \return centi-G (ACC) or centi-Deg/Sec (Gyro) + */ +static int +value(int type) +{ + int rv; + float converted_val = 0; + + if(state == SENSOR_STATE_DISABLED) { + PRINTF("MPU: Sensor Disabled\n"); + return CC26XX_SENSOR_READING_ERROR; + } + + memset(sensor_value, 0, sizeof(sensor_value)); + + if((type & MPU_9250_SENSOR_TYPE_ACC) != 0) { + t0 = RTIMER_NOW(); + + while(!int_status() && + (RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + READING_WAIT_TIMEOUT))); + + rv = acc_read(sensor_value); + + if(rv == 0) { + return CC26XX_SENSOR_READING_ERROR; + } + + PRINTF("MPU: ACC = 0x%04x 0x%04x 0x%04x = ", + sensor_value[0], sensor_value[1], sensor_value[2]); + + /* Convert */ + if(type == MPU_9250_SENSOR_TYPE_ACC_X) { + converted_val = acc_convert(sensor_value[0]); + } else if(type == MPU_9250_SENSOR_TYPE_ACC_Y) { + converted_val = acc_convert(sensor_value[1]); + } else if(type == MPU_9250_SENSOR_TYPE_ACC_Z) { + converted_val = acc_convert(sensor_value[2]); + } + rv = (int)(converted_val * 100); + } else if((type & MPU_9250_SENSOR_TYPE_GYRO) != 0) { + t0 = RTIMER_NOW(); + + while(!int_status() && + (RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + READING_WAIT_TIMEOUT))); + + rv = gyro_read(sensor_value); + + if(rv == 0) { + return CC26XX_SENSOR_READING_ERROR; + } + + PRINTF("MPU: Gyro = 0x%04x 0x%04x 0x%04x = ", + sensor_value[0], sensor_value[1], sensor_value[2]); + + if(type == MPU_9250_SENSOR_TYPE_GYRO_X) { + converted_val = gyro_convert(sensor_value[0]); + } else if(type == MPU_9250_SENSOR_TYPE_GYRO_Y) { + converted_val = gyro_convert(sensor_value[1]); + } else if(type == MPU_9250_SENSOR_TYPE_GYRO_Z) { + converted_val = gyro_convert(sensor_value[2]); + } + rv = (int)(converted_val * 100); + } else { + PRINTF("MPU: Invalid type\n"); + rv = CC26XX_SENSOR_READING_ERROR; + } + + PRINTF("%ld\n", (long int)(converted_val * 100)); + + return rv; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Configuration function for the MPU9250 sensor. + * + * \param type Activate, enable or disable the sensor. See below + * \param enable + * + * When type == SENSORS_HW_INIT we turn on the hardware + * When type == SENSORS_ACTIVE and enable==1 we enable the sensor + * When type == SENSORS_ACTIVE and enable==0 we disable the sensor + */ +static int +configure(int type, int enable) +{ + switch(type) { + case SENSORS_HW_INIT: + ti_lib_rom_ioc_pin_type_gpio_input(BOARD_IOID_MPU_INT); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_MPU_INT, IOC_IOPULL_DOWN); + ti_lib_ioc_io_hyst_set(BOARD_IOID_MPU_INT, IOC_HYST_ENABLE); + + ti_lib_rom_ioc_pin_type_gpio_output(BOARD_IOID_MPU_POWER); + ti_lib_ioc_io_drv_strength_set(BOARD_IOID_MPU_POWER, IOC_CURRENT_4MA, + IOC_STRENGTH_MAX); + ti_lib_gpio_clear_dio(BOARD_IOID_MPU_POWER); + elements = MPU_9250_SENSOR_TYPE_NONE; + break; + case SENSORS_ACTIVE: + if(((enable & MPU_9250_SENSOR_TYPE_ACC) != 0) || + ((enable & MPU_9250_SENSOR_TYPE_GYRO) != 0)) { + PRINTF("MPU: Enabling\n"); + elements = enable & MPU_9250_SENSOR_TYPE_ALL; + + power_up(); + + state = SENSOR_STATE_BOOTING; + } else { + PRINTF("MPU: Disabling\n"); + if(HWREG(GPIO_BASE + GPIO_O_DOUT31_0) & BOARD_MPU_POWER) { + /* Then check our state */ + elements = MPU_9250_SENSOR_TYPE_NONE; + ctimer_stop(&startup_timer); + sensor_sleep(); + while(ti_lib_i2c_master_busy(I2C0_BASE)); + state = SENSOR_STATE_DISABLED; + ti_lib_gpio_clear_dio(BOARD_IOID_MPU_POWER); + } + } + break; + default: + break; + } + return state; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Returns the status of the sensor + * \param type SENSORS_ACTIVE or SENSORS_READY + * \return 1 if the sensor is enabled + */ +static int +status(int type) +{ + switch(type) { + case SENSORS_ACTIVE: + case SENSORS_READY: + return state; + break; + default: + break; + } + return SENSOR_STATE_DISABLED; +} +/*---------------------------------------------------------------------------*/ +SENSORS_SENSOR(mpu_9250_sensor, "MPU9250", value, configure, status); +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.h new file mode 100644 index 000000000..da4386412 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup sensortag-cc26xx-peripherals + * @{ + * + * \defgroup sensortag-cc26xx-mpu SensorTag 2.0 Motion Processing Unit + * + * Driver for the Invensense MPU9250 Motion Processing Unit. + * + * Due to the time required between triggering a reading and the reading + * becoming available, this driver is meant to be used in an asynchronous + * fashion. The caller must first activate the sensor by calling + * mpu_9250_sensor.configure(SENSORS_ACTIVE, xyz); + * The value for the xyz arguments depends on the required readings. If the + * caller intends to read both the accelerometer as well as the gyro then + * xyz should be MPU_9250_SENSOR_TYPE_ALL. If the caller only needs to take a + * reading from one of the two elements, xyz should be one of + * MPU_9250_SENSOR_TYPE_ACC or MPU_9250_SENSOR_TYPE_GYRO + * + * Calling .configure() will power up the sensor and initialise it. When the + * sensor is ready to provide readings, the driver will generate a + * sensors_changed event. + * + * Calls to .status() will return the driver's state which could indicate that + * the sensor is off, booting or on. + * + * Once a reading has been taken, the caller has two options: + * - Turn the sensor off by calling SENSORS_DEACTIVATE, but in order to take + * subsequent readings the sensor must be started up all over + * - Leave the sensor on. In this scenario, the caller can simply keep calling + * value() for subsequent readings, but having the sensor on will consume + * more energy, especially if both accelerometer and the gyro are on. + * @{ + * + * \file + * Header file for the Sensortag Invensense MPU9250 motion processing unit + */ +/*---------------------------------------------------------------------------*/ +#ifndef MPU_9250_SENSOR_H_ +#define MPU_9250_SENSOR_H_ +/*---------------------------------------------------------------------------*/ +/* ACC / Gyro Axes */ +#define MPU_9250_SENSOR_TYPE_GYRO_Z 0x01 +#define MPU_9250_SENSOR_TYPE_GYRO_Y 0x02 +#define MPU_9250_SENSOR_TYPE_GYRO_X 0x04 +#define MPU_9250_SENSOR_TYPE_GYRO_ALL 0x07 + +#define MPU_9250_SENSOR_TYPE_ACC_Z 0x08 +#define MPU_9250_SENSOR_TYPE_ACC_Y 0x10 +#define MPU_9250_SENSOR_TYPE_ACC_X 0x20 +#define MPU_9250_SENSOR_TYPE_ACC_ALL 0x38 + +#define MPU_9250_SENSOR_TYPE_MASK 0x3F +#define MPU_9250_SENSOR_TYPE_ACC 0x38 +#define MPU_9250_SENSOR_TYPE_GYRO 0x07 + +#define MPU_9250_SENSOR_TYPE_NONE 0 +#define MPU_9250_SENSOR_TYPE_ALL (MPU_9250_SENSOR_TYPE_ACC | \ + MPU_9250_SENSOR_TYPE_GYRO) +/*---------------------------------------------------------------------------*/ +/* Accelerometer range */ +#define MPU_9250_SENSOR_ACC_RANGE_2G 0 +#define MPU_9250_SENSOR_ACC_RANGE_4G 1 +#define MPU_9250_SENSOR_ACC_RANGE_8G 2 +#define MPU_9250_SENSOR_ACC_RANGE_16G 3 +/*---------------------------------------------------------------------------*/ +/* Accelerometer range configuration */ +#ifdef MPU_9250_SENSOR_CONF_ACC_RANGE +#define MPU_9250_SENSOR_ACC_RANGE MPU_9250_SENSOR_CONF_ACC_RANGE +#else +#define MPU_9250_SENSOR_ACC_RANGE MPU_9250_SENSOR_ACC_RANGE_2G +#endif +/*---------------------------------------------------------------------------*/ +extern const struct sensors_sensor mpu_9250_sensor; +/*---------------------------------------------------------------------------*/ +#endif /* MPU_9250_SENSOR_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.c new file mode 100644 index 000000000..39568b227 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.c @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup sensortag-cc26xx-opt-sensor + * @{ + * + * \file + * Driver for the Sensortag Opt3001 light sensor + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "lib/sensors.h" +#include "opt-3001-sensor.h" +#include "sys/ctimer.h" +#include "ti-lib.h" +#include "board-i2c.h" +#include "sensor-common.h" + +#include +#include +#include +#include +#include +/*---------------------------------------------------------------------------*/ +#define DEBUG 0 +#if DEBUG +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif +/*---------------------------------------------------------------------------*/ +/* Slave address */ +#define OPT3001_I2C_ADDRESS 0x45 +/*---------------------------------------------------------------------------*/ +/* Register addresses */ +#define REG_RESULT 0x00 +#define REG_CONFIGURATION 0x01 +#define REG_LOW_LIMIT 0x02 +#define REG_HIGH_LIMIT 0x03 + +#define REG_MANUFACTURER_ID 0x7E +#define REG_DEVICE_ID 0x7F +/*---------------------------------------------------------------------------*/ +/* + * Configuration Register Bits and Masks. + * We use uint16_t to read from / write to registers, meaning that the + * register's MSB is the variable's LSB. + */ +#define CONFIG_RN 0x00F0 /* [15..12] Range Number */ +#define CONFIG_CT 0x0008 /* [11] Conversion Time */ +#define CONFIG_M 0x0006 /* [10..9] Mode of Conversion */ +#define CONFIG_OVF 0x0001 /* [8] Overflow */ +#define CONFIG_CRF 0x8000 /* [7] Conversion Ready Field */ +#define CONFIG_FH 0x4000 /* [6] Flag High */ +#define CONFIG_FL 0x2000 /* [5] Flag Low */ +#define CONFIG_L 0x1000 /* [4] Latch */ +#define CONFIG_POL 0x0800 /* [3] Polarity */ +#define CONFIG_ME 0x0400 /* [2] Mask Exponent */ +#define CONFIG_FC 0x0300 /* [1..0] Fault Count */ + +/* Possible Values for CT */ +#define CONFIG_CT_100 0x0000 +#define CONFIG_CT_800 CONFIG_CT + +/* Possible Values for M */ +#define CONFIG_M_CONTI 0x0004 +#define CONFIG_M_SINGLE 0x0002 +#define CONFIG_M_SHUTDOWN 0x0000 + +/* Reset Value for the register 0xC810. All zeros except: */ +#define CONFIG_RN_RESET 0x00C0 +#define CONFIG_CT_RESET CONFIG_CT_800 +#define CONFIG_L_RESET 0x1000 +#define CONFIG_DEFAULTS (CONFIG_RN_RESET | CONFIG_CT_100 | CONFIG_L_RESET) + +/* Enable / Disable */ +#define CONFIG_ENABLE_CONTINUOUS (CONFIG_M_CONTI | CONFIG_DEFAULTS) +#define CONFIG_ENABLE_SINGLE_SHOT (CONFIG_M_SINGLE | CONFIG_DEFAULTS) +#define CONFIG_DISABLE CONFIG_DEFAULTS +/*---------------------------------------------------------------------------*/ +/* Register length */ +#define REGISTER_LENGTH 2 +/*---------------------------------------------------------------------------*/ +/* Sensor data size */ +#define DATA_LENGTH 2 +/*---------------------------------------------------------------------------*/ +/* + * SENSOR_STATE_SLEEPING and SENSOR_STATE_ACTIVE are mutually exclusive. + * SENSOR_STATE_DATA_READY can be ORd with both of the above. For example the + * sensor may be sleeping but with a conversion ready to read out. + */ +#define SENSOR_STATE_SLEEPING 0 +#define SENSOR_STATE_ACTIVE 1 +#define SENSOR_STATE_DATA_READY 2 + +static int state = SENSOR_STATE_SLEEPING; +/*---------------------------------------------------------------------------*/ +/* Wait SENSOR_STARTUP_DELAY for the sensor to be ready - 125ms */ +#define SENSOR_STARTUP_DELAY (CLOCK_SECOND >> 3) + +static struct ctimer startup_timer; +/*---------------------------------------------------------------------------*/ +/** + * \brief Select the sensor on the I2C bus + */ +static void +select_on_bus(void) +{ + /* Select slave and set clock rate */ + board_i2c_select(BOARD_I2C_INTERFACE_0, OPT3001_I2C_ADDRESS); +} +/*---------------------------------------------------------------------------*/ +static void +notify_ready(void *not_used) +{ + /* + * Depending on the CONFIGURATION.CONVERSION_TIME bits, a conversion will + * take either 100 or 800 ms. Here we inspect the CONVERSION_READY bit and + * if the reading is ready we notify, otherwise we just reschedule ourselves + */ + uint16_t val; + + select_on_bus(); + + sensor_common_read_reg(REG_CONFIGURATION, (uint8_t *)&val, REGISTER_LENGTH); + + if(val & CONFIG_CRF) { + sensors_changed(&opt_3001_sensor); + state = SENSOR_STATE_DATA_READY; + } else { + ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready, NULL); + } +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Turn the sensor on/off + * \param enable TRUE: on, FALSE: off + */ +static void +enable_sensor(bool enable) +{ + uint16_t val; + uint16_t had_data_ready = state & SENSOR_STATE_DATA_READY; + + select_on_bus(); + + if(enable) { + val = CONFIG_ENABLE_SINGLE_SHOT; + + /* Writing CONFIG_ENABLE_SINGLE_SHOT to M bits will clear CRF bits */ + state = SENSOR_STATE_ACTIVE; + } else { + val = CONFIG_DISABLE; + + /* Writing CONFIG_DISABLE to M bits will not clear CRF bits */ + state = SENSOR_STATE_SLEEPING | had_data_ready; + } + + sensor_common_write_reg(REG_CONFIGURATION, (uint8_t *)&val, REGISTER_LENGTH); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Read the result register + * \param raw_data Pointer to a buffer to store the reading + * \return TRUE if valid data + */ +static bool +read_data(uint16_t *raw_data) +{ + bool success; + uint16_t val; + + if((state & SENSOR_STATE_DATA_READY) != SENSOR_STATE_DATA_READY) { + return false; + } + + select_on_bus(); + + success = sensor_common_read_reg(REG_CONFIGURATION, (uint8_t *)&val, + REGISTER_LENGTH); + + if(success) { + success = sensor_common_read_reg(REG_RESULT, (uint8_t *)&val, DATA_LENGTH); + } + + if(success) { + /* Swap bytes */ + *raw_data = (val << 8) | (val >> 8 & 0xFF); + } else { + sensor_common_set_error_data((uint8_t *)raw_data, DATA_LENGTH); + } + + return success; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Convert raw data to a value in lux + * \param raw_data data Pointer to a buffer with a raw sensor reading + * \return Converted value (lux) + */ +static float +convert(uint16_t raw_data) +{ + uint16_t e, m; + + m = raw_data & 0x0FFF; + e = (raw_data & 0xF000) >> 12; + + return m * (0.01 * exp2(e)); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Returns a reading from the sensor + * \param type Ignored + * \return Illuminance in centilux + */ +static int +value(int type) +{ + int rv; + uint16_t raw_val; + float converted_val; + + rv = read_data(&raw_val); + + if(rv == false) { + return CC26XX_SENSOR_READING_ERROR; + } + + converted_val = convert(raw_val); + PRINTF("OPT: %04X r=%d (centilux)\n", raw_val, + (int)(converted_val * 100)); + + rv = (int)(converted_val * 100); + + return rv; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Configuration function for the OPT3001 sensor. + * + * \param type Activate, enable or disable the sensor. See below + * \param enable + * + * When type == SENSORS_HW_INIT we turn on the hardware + * When type == SENSORS_ACTIVE and enable==1 we enable the sensor + * When type == SENSORS_ACTIVE and enable==0 we disable the sensor + */ +static int +configure(int type, int enable) +{ + int rv = 0; + + switch(type) { + case SENSORS_HW_INIT: + /* + * Device reset won't reset the sensor, so we put it to sleep here + * explicitly + */ + enable_sensor(0); + rv = 0; + break; + case SENSORS_ACTIVE: + if(enable) { + enable_sensor(1); + ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready, NULL); + rv = 1; + } else { + ctimer_stop(&startup_timer); + enable_sensor(0); + rv = 0; + } + break; + default: + break; + } + return rv; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Returns the status of the sensor + * \param type ignored + * \return The state of the sensor SENSOR_STATE_xyz + */ +static int +status(int type) +{ + switch(type) { + case SENSORS_ACTIVE: + case SENSORS_READY: + default: + break; + } + return state; +} +/*---------------------------------------------------------------------------*/ +SENSORS_SENSOR(opt_3001_sensor, "OPT3001", value, configure, status); +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.h new file mode 100644 index 000000000..e9fa379a4 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup sensortag-cc26xx-peripherals + * @{ + * + * \defgroup sensortag-cc26xx-opt-sensor SensorTag 2.0 Light Sensor + * + * Due to the time required for the sensor to startup, this driver is meant to + * be used in an asynchronous fashion. The caller must first activate the + * sensor by calling SENSORS_ACTIVATE(). This will trigger the sensor's startup + * sequence, but the call will not wait for it to complete so that the CPU can + * perform other tasks or drop to a low power mode. + * + * Once the reading and conversion are complete, the driver will generate a + * sensors_changed event. + * + * We use single-shot readings. In this mode, the hardware automatically goes + * back to its shutdown mode after the conversion is finished. However, it will + * still respond to I2C operations, so the last conversion can still be read + * out. + * + * In order to take a new reading, the caller has to use SENSORS_ACTIVATE + * again. + * @{ + * + * \file + * Header file for the Sensortag Opt3001 light sensor + */ +/*---------------------------------------------------------------------------*/ +#ifndef OPT_3001_SENSOR_H_ +#define OPT_3001_SENSOR_H_ +/*---------------------------------------------------------------------------*/ +extern const struct sensors_sensor opt_3001_sensor; +/*---------------------------------------------------------------------------*/ +#endif /* OPT_3001_SENSOR_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/reed-relay.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/reed-relay.c new file mode 100644 index 000000000..736b2170a --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/reed-relay.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup sensortag-cc26xx-reed-relay + * @{ + * + * \file + * Driver for the Sensortag Reed Relay + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "sys/clock.h" +#include "sys/timer.h" +#include "lib/sensors.h" +#include "sensortag/reed-relay.h" +#include "gpio-interrupt.h" +#include "sys/timer.h" + +#include "ti-lib.h" + +#include +/*---------------------------------------------------------------------------*/ +static struct timer debouncetimer; +/*---------------------------------------------------------------------------*/ +#define REED_IO_CFG (IOC_CURRENT_2MA | IOC_STRENGTH_AUTO | \ + IOC_IOPULL_DOWN | IOC_SLEW_DISABLE | \ + IOC_HYST_DISABLE | IOC_BOTH_EDGES | \ + IOC_INT_DISABLE | IOC_IOMODE_NORMAL | \ + IOC_NO_WAKE_UP | IOC_INPUT_ENABLE) +/*---------------------------------------------------------------------------*/ +/** + * \brief Handler for Sensortag-CC26XX reed interrupts + */ +static void +reed_interrupt_handler(uint8_t ioid) +{ + if(!timer_expired(&debouncetimer)) { + return; + } + + sensors_changed(&reed_relay_sensor); + timer_set(&debouncetimer, CLOCK_SECOND / 2); +} +/*---------------------------------------------------------------------------*/ +static int +value(int type) +{ + return (int)ti_lib_gpio_read_dio(BOARD_IOID_REED_RELAY); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Configuration function for the button sensor for all buttons. + * + * \param type SENSORS_HW_INIT: Initialise. SENSORS_ACTIVE: Enables/Disables + * depending on 'value' + * \param value 0: disable, non-zero: enable + * \return Always returns 1 + */ +static int +configure(int type, int value) +{ + switch(type) { + case SENSORS_HW_INIT: + ti_lib_ioc_int_disable(BOARD_IOID_REED_RELAY); + ti_lib_gpio_clear_event_dio(BOARD_IOID_REED_RELAY); + + /* Enable the GPIO clock when the CM3 is running */ + ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_GPIO); + + /* S/W control, input, pull-down */ + ti_lib_ioc_port_configure_set(BOARD_IOID_REED_RELAY, IOC_PORT_GPIO, + REED_IO_CFG); + + gpio_interrupt_register_handler(BOARD_IOID_REED_RELAY, + reed_interrupt_handler); + break; + case SENSORS_ACTIVE: + if(value) { + ti_lib_ioc_int_enable(BOARD_IOID_REED_RELAY); + } else { + ti_lib_ioc_int_disable(BOARD_IOID_REED_RELAY); + } + break; + default: + break; + } + return 1; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Status function for the reed + * \param type SENSORS_ACTIVE or SENSORS_READY + * \return 1 Interrupt enabled, 0: Disabled + */ +static int +status(int type) +{ + switch(type) { + case SENSORS_ACTIVE: + case SENSORS_READY: + return (ti_lib_ioc_port_configure_get(BOARD_IOID_REED_RELAY) + & IOC_INT_ENABLE) == IOC_INT_ENABLE; + break; + default: + break; + } + return 0; +} +/*---------------------------------------------------------------------------*/ +SENSORS_SENSOR(reed_relay_sensor, "REED", value, configure, status); +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/reed-relay.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/reed-relay.h new file mode 100644 index 000000000..0ed6dd819 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/reed-relay.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup sensortag-cc26xx-peripherals + * @{ + * + * \defgroup sensortag-cc26xx-reed-relay SensorTag 2.0 Reed Relay + * + * The reed relay acts like a button without a button. To trigger the reed, + * approach a magnet to the sensortag and a sensors_changed event will be + * generated, in a fashion similar to as if a button had been pressed + * + * @{ + * + * \file + * Header file for the Sensortag Reed Relay + */ +/*---------------------------------------------------------------------------*/ +#ifndef REED_RELAY_H +#define REED_RELAY_H +/*---------------------------------------------------------------------------*/ +#include "lib/sensors.h" +/*---------------------------------------------------------------------------*/ +extern const struct sensors_sensor reed_relay_sensor; +/*---------------------------------------------------------------------------*/ +#endif /* REED_RELAY_H */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/platform/simplelink/cc13x0-cc26x0/sensortag/sensortag-sensors.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag-sensors.c similarity index 100% rename from arch/platform/simplelink/cc13x0-cc26x0/sensortag/sensortag-sensors.c rename to arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag-sensors.c diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag.c new file mode 100644 index 000000000..e2069f39f --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup sensortag-cc26xx-peripherals + * @{ + * + * \file + * Sensortag-specific board initialisation driver + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "lib/sensors.h" +#include "buzzer.h" +#include "lpm.h" +#include "ti-lib.h" +#include "board-peripherals.h" +#include "board-i2c.h" + +#include +#include +#include +/*---------------------------------------------------------------------------*/ +static void +power_domains_on(void) +{ + /* Turn on the PERIPH PD */ + ti_lib_prcm_power_domain_on(PRCM_DOMAIN_PERIPH); + + /* Wait for domains to power on */ + while((ti_lib_prcm_power_domain_status(PRCM_DOMAIN_PERIPH) + != PRCM_DOMAIN_POWER_ON)); +} +/*---------------------------------------------------------------------------*/ +static void +lpm_wakeup_handler(void) +{ + power_domains_on(); +} +/*---------------------------------------------------------------------------*/ +static void +shutdown_handler(uint8_t mode) +{ + if(mode == LPM_MODE_SHUTDOWN) { + buzzer_stop(); + SENSORS_DEACTIVATE(bmp_280_sensor); + SENSORS_DEACTIVATE(opt_3001_sensor); + SENSORS_DEACTIVATE(tmp_007_sensor); + SENSORS_DEACTIVATE(hdc_1000_sensor); + SENSORS_DEACTIVATE(mpu_9250_sensor); + ti_lib_gpio_clear_dio(BOARD_IOID_MPU_POWER); + } + + /* In all cases, stop the I2C */ + board_i2c_shutdown(); +} +/*---------------------------------------------------------------------------*/ +/* + * Declare a data structure to register with LPM. + * We don't care about what power mode we'll drop to, we don't care about + * getting notified before deep sleep. All we need is to be notified when we + * wake up so we can turn power domains back on for I2C and SSI, and to make + * sure everything on the board is off before CM3 shutdown. + */ +LPM_MODULE(sensortag_module, NULL, shutdown_handler, lpm_wakeup_handler, + LPM_DOMAIN_NONE); +/*---------------------------------------------------------------------------*/ +static void +configure_unused_pins(void) +{ + /* DP[0..3] */ + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_DP0); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_DP0, IOC_IOPULL_DOWN); + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_DP1); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_DP1, IOC_IOPULL_DOWN); + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_DP2); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_DP2, IOC_IOPULL_DOWN); + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_DP3); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_DP3, IOC_IOPULL_DOWN); + + /* Devpack ID */ + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_DEVPK_ID); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_DEVPK_ID, IOC_IOPULL_UP); + + /* Digital Microphone */ + ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_MIC_POWER); + ti_lib_gpio_clear_dio(BOARD_IOID_MIC_POWER); + ti_lib_ioc_io_drv_strength_set(BOARD_IOID_MIC_POWER, IOC_CURRENT_2MA, + IOC_STRENGTH_MIN); + + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_AUDIO_DI); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_AUDIO_DI, IOC_IOPULL_DOWN); + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_AUDIO_CLK); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_AUDIO_CLK, IOC_IOPULL_DOWN); + + /* UART over Devpack - TX only (ToDo: Map all UART pins to Debugger) */ + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_DP5_UARTTX); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_DP5_UARTTX, IOC_IOPULL_DOWN); +} +/*---------------------------------------------------------------------------*/ +void +board_init() +{ + /* Disable global interrupts */ + bool int_disabled = ti_lib_int_master_disable(); + + power_domains_on(); + + /* Enable GPIO peripheral */ + ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_GPIO); + + /* Apply settings and wait for them to take effect */ + ti_lib_prcm_load_set(); + while(!ti_lib_prcm_load_get()); + + /* I2C controller */ + board_i2c_wakeup(); + + buzzer_init(); + + /* Make sure the external flash is in the lower power mode */ + ext_flash_init(); + + lpm_register_module(&sensortag_module); + + /* For unsupported peripherals, select a default pin configuration */ + configure_unused_pins(); + + /* Re-enable interrupt if initially enabled. */ + if(!int_disabled) { + ti_lib_int_master_enable(); + } +} +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c new file mode 100644 index 000000000..c40dd2eff --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup sensortag-cc26xx-tmp-sensor + * @{ + * + * \file + * Driver for the Sensortag TI TMP007 infrared thermophile sensor + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "lib/sensors.h" +#include "tmp-007-sensor.h" +#include "sys/ctimer.h" +#include "board-i2c.h" +#include "sensor-common.h" +#include "ti-lib.h" + +#include +#include +#include +#include +/*---------------------------------------------------------------------------*/ +#define DEBUG 0 +#if DEBUG +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif +/*---------------------------------------------------------------------------*/ +/* Slave address */ +#define SENSOR_I2C_ADDRESS 0x44 +/*---------------------------------------------------------------------------*/ +/* TMP007 register addresses */ +#define TMP007_REG_ADDR_VOLTAGE 0x00 +#define TMP007_REG_ADDR_LOCAL_TEMP 0x01 +#define TMP007_REG_ADDR_CONFIG 0x02 +#define TMP007_REG_ADDR_OBJ_TEMP 0x03 +#define TMP007_REG_ADDR_STATUS 0x04 +#define TMP007_REG_PROD_ID 0x1F +/*---------------------------------------------------------------------------*/ +/* TMP007 register values */ +#define TMP007_VAL_CONFIG_ON 0x1000 /* Sensor on state */ +#define TMP007_VAL_CONFIG_OFF 0x0000 /* Sensor off state */ +#define TMP007_VAL_CONFIG_RESET 0x8000 +#define TMP007_VAL_PROD_ID 0x0078 /* Product ID */ +/*---------------------------------------------------------------------------*/ +/* Conversion ready (status register) bit values */ +#define CONV_RDY_BIT 0x4000 +/*---------------------------------------------------------------------------*/ +/* Register length */ +#define REGISTER_LENGTH 2 +/*---------------------------------------------------------------------------*/ +/* Sensor data size */ +#define DATA_SIZE 4 +/*---------------------------------------------------------------------------*/ +/* Byte swap of 16-bit register value */ +#define HI_UINT16(a) (((a) >> 8) & 0xFF) +#define LO_UINT16(a) ((a) & 0xFF) + +#define SWAP(v) ((LO_UINT16(v) << 8) | HI_UINT16(v)) +/*---------------------------------------------------------------------------*/ +#define SELECT() board_i2c_select(BOARD_I2C_INTERFACE_0, SENSOR_I2C_ADDRESS) +/*---------------------------------------------------------------------------*/ +static uint8_t buf[DATA_SIZE]; +static uint16_t val; +/*---------------------------------------------------------------------------*/ +#define SENSOR_STATUS_DISABLED 0 +#define SENSOR_STATUS_INITIALISED 1 +#define SENSOR_STATUS_NOT_READY 2 +#define SENSOR_STATUS_READY 3 + +static int enabled = SENSOR_STATUS_DISABLED; +/*---------------------------------------------------------------------------*/ +/* Wait SENSOR_STARTUP_DELAY clock ticks for the sensor to be ready - 275ms */ +#define SENSOR_STARTUP_DELAY 36 + +static struct ctimer startup_timer; +/*---------------------------------------------------------------------------*/ +/* Latched values */ +static int obj_temp_latched; +static int amb_temp_latched; +/*---------------------------------------------------------------------------*/ +static void +notify_ready(void *not_used) +{ + enabled = SENSOR_STATUS_READY; + sensors_changed(&tmp_007_sensor); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Turn the sensor on/off + */ +static bool +enable_sensor(bool enable) +{ + bool success; + + SELECT(); + + if(enable) { + val = TMP007_VAL_CONFIG_ON; + } else { + val = TMP007_VAL_CONFIG_OFF; + } + val = SWAP(val); + + success = sensor_common_write_reg(TMP007_REG_ADDR_CONFIG, (uint8_t *)&val, + REGISTER_LENGTH); + + return success; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Read the sensor value registers + * \param raw_temp Temperature in 16 bit format + * \param raw_obj_temp object temperature in 16 bit format + * \return TRUE if valid data could be retrieved + */ +static bool +read_data(uint16_t *raw_temp, uint16_t *raw_obj_temp) +{ + bool success; + + SELECT(); + + success = sensor_common_read_reg(TMP007_REG_ADDR_STATUS, (uint8_t *)&val, + REGISTER_LENGTH); + + if(success) { + val = SWAP(val); + success = val & CONV_RDY_BIT; + } + + if(success) { + success = sensor_common_read_reg(TMP007_REG_ADDR_LOCAL_TEMP, &buf[0], + REGISTER_LENGTH); + if(success) { + success = sensor_common_read_reg(TMP007_REG_ADDR_OBJ_TEMP, &buf[2], + REGISTER_LENGTH); + } + } + + if(!success) { + sensor_common_set_error_data(buf, 4); + } + + /* Swap byte order */ + *raw_temp = buf[0] << 8 | buf[1]; + *raw_obj_temp = buf[2] << 8 | buf[3]; + + return success; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Convert raw data to values in degrees C + * \param raw_temp raw ambient temperature from sensor + * \param raw_obj_temp raw object temperature from sensor + * \param obj converted object temperature + * \param amb converted ambient temperature + */ +static void +convert(uint16_t raw_temp, uint16_t raw_obj_temp, float *obj, float *amb) +{ + const float SCALE_LSB = 0.03125; + float t; + int it; + + it = (int)((raw_obj_temp) >> 2); + t = ((float)(it)) * SCALE_LSB; + *obj = t; + + it = (int)((raw_temp) >> 2); + t = (float)it; + *amb = t * SCALE_LSB; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Returns a reading from the sensor + * \param type TMP_007_SENSOR_TYPE_OBJECT or TMP_007_SENSOR_TYPE_AMBIENT + * \return Object or Ambient temperature in milli degrees C + */ +static int +value(int type) +{ + int rv; + uint16_t raw_temp; + uint16_t raw_obj_temp; + float obj_temp; + float amb_temp; + + if(enabled != SENSOR_STATUS_READY) { + PRINTF("Sensor disabled or starting up (%d)\n", enabled); + return CC26XX_SENSOR_READING_ERROR; + } + + if((type & TMP_007_SENSOR_TYPE_ALL) == 0) { + PRINTF("Invalid type\n"); + return CC26XX_SENSOR_READING_ERROR; + } + + rv = CC26XX_SENSOR_READING_ERROR; + + if(type == TMP_007_SENSOR_TYPE_ALL) { + rv = read_data(&raw_temp, &raw_obj_temp); + + if(rv == 0) { + return CC26XX_SENSOR_READING_ERROR; + } + + convert(raw_temp, raw_obj_temp, &obj_temp, &amb_temp); + PRINTF("TMP: %04X %04X o=%d a=%d\n", raw_temp, raw_obj_temp, + (int)(obj_temp * 1000), (int)(amb_temp * 1000)); + + obj_temp_latched = (int)(obj_temp * 1000); + amb_temp_latched = (int)(amb_temp * 1000); + rv = 1; + } else if(type == TMP_007_SENSOR_TYPE_OBJECT) { + rv = obj_temp_latched; + } else if(type == TMP_007_SENSOR_TYPE_AMBIENT) { + rv = amb_temp_latched; + } + + return rv; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Configuration function for the TMP007 sensor. + * + * \param type Activate, enable or disable the sensor. See below + * \param enable + * + * When type == SENSORS_HW_INIT we turn on the hardware + * When type == SENSORS_ACTIVE and enable==1 we enable the sensor + * When type == SENSORS_ACTIVE and enable==0 we disable the sensor + */ +static int +configure(int type, int enable) +{ + switch(type) { + case SENSORS_HW_INIT: + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_TMP_RDY); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_TMP_RDY, IOC_IOPULL_UP); + ti_lib_ioc_io_hyst_set(BOARD_IOID_TMP_RDY, IOC_HYST_ENABLE); + + enable_sensor(false); + enabled = SENSOR_STATUS_INITIALISED; + break; + case SENSORS_ACTIVE: + /* Must be initialised first */ + if(enabled == SENSOR_STATUS_DISABLED) { + return SENSOR_STATUS_DISABLED; + } + if(enable) { + enable_sensor(true); + ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready, NULL); + enabled = SENSOR_STATUS_NOT_READY; + } else { + ctimer_stop(&startup_timer); + enable_sensor(false); + enabled = SENSOR_STATUS_INITIALISED; + } + break; + default: + break; + } + return enabled; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Returns the status of the sensor + * \param type SENSORS_ACTIVE or SENSORS_READY + * \return 1 if the sensor is enabled + */ +static int +status(int type) +{ + switch(type) { + case SENSORS_ACTIVE: + case SENSORS_READY: + return enabled; + break; + default: + break; + } + return SENSOR_STATUS_DISABLED; +} +/*---------------------------------------------------------------------------*/ +SENSORS_SENSOR(tmp_007_sensor, "TMP007", value, configure, status); +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.h new file mode 100644 index 000000000..5260c9152 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup sensortag-cc26xx-peripherals + * @{ + * + * \defgroup sensortag-cc26xx-tmp-sensor SensorTag 2.0 IR thermophile sensor + * + * Due to the time required for the sensor to startup, this driver is meant to + * be used in an asynchronous fashion. The caller must first activate the + * sensor by calling SENSORS_ACTIVATE(). This will trigger the sensor's startup + * sequence, but the call will not wait for it to complete so that the CPU can + * perform other tasks or drop to a low power mode. + * + * Once the sensor is stable, the driver will generate a sensors_changed event. + * + * The caller should then use value(TMP_007_SENSOR_TYPE_ALL) to read sensor + * values and latch them. Once completed successfully, individual readings can + * be retrieved with calls to value(TMP_007_SENSOR_TYPE_OBJECT) or + * value(TMP_007_SENSOR_TYPE_AMBIENT). + * + * Once required readings have been taken, the caller has two options: + * - Turn the sensor off by calling SENSORS_DEACTIVATE, but in order to take + * subsequent readings SENSORS_ACTIVATE must be called again + * - Leave the sensor on. In this scenario, the caller can simply keep calling + * value(TMP_007_SENSOR_TYPE_ALL) to read and latch new values. However + * keeping the sensor on will consume more energy + * @{ + * + * \file + * Header file for the Sensortag TI TMP007 infrared thermophile sensor + */ +/*---------------------------------------------------------------------------*/ +#ifndef TMP_007_SENSOR_H_ +#define TMP_007_SENSOR_H_ +/*---------------------------------------------------------------------------*/ +#define TMP_007_SENSOR_TYPE_OBJECT 1 +#define TMP_007_SENSOR_TYPE_AMBIENT 2 +#define TMP_007_SENSOR_TYPE_ALL 3 +/*---------------------------------------------------------------------------*/ +extern const struct sensors_sensor tmp_007_sensor; +/*---------------------------------------------------------------------------*/ +#endif /* TMP_007_SENSOR_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/Makefile.srf06 b/arch/platform/simplelink/cc13xx-cc26xx/srf06/Makefile.srf06 new file mode 100644 index 000000000..19e54bb96 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/Makefile.srf06 @@ -0,0 +1,10 @@ +################################################################################ +# SimpleLink LaunchPad makefile + +BOARD_TYPE = BOARD_SRF06 + +# leds-arch.c/h etc. +BOARD_SOURCEFILES += srf06.c srf06-sensors.c +BOARD_SOURCEFILES += button-sensor-arch.c leds-arch.c + +TARGET_FAMILY_DIRS += srf06 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/als-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/als-sensor.c new file mode 100644 index 000000000..3b6fdecb9 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/als-sensor.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2016, University of Bristol - http://www.bris.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 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup srf06-common-peripherals + * @{ + * + * \file + * Driver for the SmartRF06EB ALS when a CC13xx/CC26xxEM is mounted on it + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "lib/sensors.h" +#include "srf06/als-sensor.h" +#include "sys/timer.h" +#include "dev/adc-sensor.h" +#include "dev/aux-ctrl.h" + +#include "ti-lib.h" + +#include +/*---------------------------------------------------------------------------*/ +static aux_consumer_module_t als_aux = { + .clocks = AUX_WUC_ADI_CLOCK | AUX_WUC_ANAIF_CLOCK | AUX_WUC_SMPH_CLOCK +}; +/*---------------------------------------------------------------------------*/ +static int +config(int type, int enable) +{ + switch(type) { + case SENSORS_HW_INIT: + ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_ALS_PWR); + break; + case SENSORS_ACTIVE: + ti_lib_rom_ioc_pin_type_gpio_output(BOARD_IOID_ALS_PWR); + ti_lib_rom_ioc_port_configure_set(BOARD_IOID_ALS_OUT, IOC_PORT_GPIO, + IOC_STD_OUTPUT); + ti_lib_rom_ioc_pin_type_gpio_input(BOARD_IOID_ALS_OUT); + + if(enable) { + ti_lib_gpio_set_dio(BOARD_IOID_ALS_PWR); + aux_ctrl_register_consumer(&als_aux); + ti_lib_aux_adc_select_input(ADC_COMPB_IN_AUXIO7); + clock_delay_usec(2000); + } else { + ti_lib_gpio_clear_dio(BOARD_IOID_ALS_PWR); + aux_ctrl_unregister_consumer(&als_aux); + } + break; + default: + break; + } + return 1; +} +/*---------------------------------------------------------------------------*/ +static int +value(int type) +{ + int val; + + ti_lib_aux_adc_enable_sync(AUXADC_REF_VDDS_REL, AUXADC_SAMPLE_TIME_2P7_US, + AUXADC_TRIGGER_MANUAL); + ti_lib_aux_adc_gen_manual_trigger(); + val = ti_lib_aux_adc_read_fifo(); + ti_lib_aux_adc_disable(); + + return val; +} +/*---------------------------------------------------------------------------*/ +static int +status(int type) +{ + return 1; +} +/*---------------------------------------------------------------------------*/ +SENSORS_SENSOR(als_sensor, ALS_SENSOR, value, config, status); +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13x0-cc26x0/common/als-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/als-sensor.h similarity index 94% rename from arch/platform/simplelink/cc13x0-cc26x0/common/als-sensor.h rename to arch/platform/simplelink/cc13xx-cc26xx/srf06/als-sensor.h index dcd7fa1da..5d70478f8 100644 --- a/arch/platform/simplelink/cc13x0-cc26x0/common/als-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/als-sensor.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, University of Bristol - http://www.bris.ac.uk/ + * Copyright (c) 2016, University of Bristol - http://www.bris.ac.uk/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -39,12 +39,12 @@ #ifndef ALS_SENSOR_H_ #define ALS_SENSOR_H_ /*---------------------------------------------------------------------------*/ -#include -/*---------------------------------------------------------------------------*/ -#include "als-sensor-arch.h" +#include "lib/sensors.h" /*---------------------------------------------------------------------------*/ #define ALS_SENSOR "ALS" /*---------------------------------------------------------------------------*/ +extern const struct sensors_sensor als_sensor; +/*---------------------------------------------------------------------------*/ #endif /* ALS_SENSOR_H_ */ /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/board-peripherals.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/board-peripherals.h new file mode 100644 index 000000000..c709ec963 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/board-peripherals.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** \addtogroup cc26xx-srf-tag + * @{ + * + * \defgroup srf06-common-peripherals SmartRF06EB + CC13xx/CC26xx common + * + * Defines related to the SmartRF06 Evaluation Board irrespective of the EM + * mounted on it + * + * This file provides connectivity information on LEDs, Buttons, UART and + * other peripherals + * + * @{ + */ +/*---------------------------------------------------------------------------*/ +#ifndef BOARD_PERIPHERALS_H_ +#define BOARD_PERIPHERALS_H_ +/*---------------------------------------------------------------------------*/ +#include "als-sensor.h" +/*---------------------------------------------------------------------------*/ +#endif /* BOARD_PERIPHERALS_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor.c new file mode 100644 index 000000000..23f668355 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor.c @@ -0,0 +1,491 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup srf06-common-peripherals + * @{ + * + * \file + * Driver for the SmartRF06EB buttons when a CC13xx/CC26xxEM is mounted on it + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "lib/sensors.h" +#include "srf06/button-sensor.h" +#include "gpio-interrupt.h" +#include "sys/timer.h" +#include "lpm.h" + +#include "ti-lib.h" + +#include +/*---------------------------------------------------------------------------*/ +#ifdef BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN +#define BUTTON_SENSOR_ENABLE_SHUTDOWN BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN +#else +#define BUTTON_SENSOR_ENABLE_SHUTDOWN 1 +#endif +/*---------------------------------------------------------------------------*/ +#define BUTTON_GPIO_CFG (IOC_CURRENT_2MA | IOC_STRENGTH_AUTO | \ + IOC_IOPULL_UP | IOC_SLEW_DISABLE | \ + IOC_HYST_DISABLE | IOC_BOTH_EDGES | \ + IOC_INT_ENABLE | IOC_IOMODE_NORMAL | \ + IOC_NO_WAKE_UP | IOC_INPUT_ENABLE) +/*---------------------------------------------------------------------------*/ +#define DEBOUNCE_DURATION (CLOCK_SECOND >> 5) + +struct btn_timer { + struct timer debounce; + clock_time_t start; + clock_time_t duration; +}; + +static struct btn_timer sel_timer, left_timer, right_timer, up_timer, + down_timer; +/*---------------------------------------------------------------------------*/ +/** + * \brief Handler for SmartRF button presses + */ +static void +button_press_handler(uint8_t ioid) +{ + if(ioid == BOARD_IOID_KEY_SELECT) { + if(!timer_expired(&sel_timer.debounce)) { + return; + } + + timer_set(&sel_timer.debounce, DEBOUNCE_DURATION); + + /* + * Start press duration counter on press (falling), notify on release + * (rising) + */ + if(ti_lib_gpio_read_dio(BOARD_IOID_KEY_SELECT) == 0) { + sel_timer.start = clock_time(); + sel_timer.duration = 0; + } else { + sel_timer.duration = clock_time() - sel_timer.start; + sensors_changed(&button_select_sensor); + } + } + + if(ioid == BOARD_IOID_KEY_LEFT) { + if(!timer_expired(&left_timer.debounce)) { + return; + } + + timer_set(&left_timer.debounce, DEBOUNCE_DURATION); + + /* + * Start press duration counter on press (falling), notify on release + * (rising) + */ + if(ti_lib_gpio_read_dio(BOARD_IOID_KEY_LEFT) == 0) { + left_timer.start = clock_time(); + left_timer.duration = 0; + } else { + left_timer.duration = clock_time() - left_timer.start; + sensors_changed(&button_left_sensor); + } + } + + if(ioid == BOARD_IOID_KEY_RIGHT) { + if(BUTTON_SENSOR_ENABLE_SHUTDOWN == 0) { + if(!timer_expired(&right_timer.debounce)) { + return; + } + + timer_set(&right_timer.debounce, DEBOUNCE_DURATION); + + /* + * Start press duration counter on press (falling), notify on release + * (rising) + */ + if(ti_lib_gpio_read_dio(BOARD_IOID_KEY_RIGHT) == 0) { + right_timer.start = clock_time(); + right_timer.duration = 0; + } else { + right_timer.duration = clock_time() - right_timer.start; + sensors_changed(&button_right_sensor); + } + } else { + lpm_shutdown(BOARD_IOID_KEY_RIGHT, IOC_IOPULL_UP, IOC_WAKE_ON_LOW); + } + } + + if(ioid == BOARD_IOID_KEY_UP) { + if(!timer_expired(&up_timer.debounce)) { + return; + } + + timer_set(&up_timer.debounce, DEBOUNCE_DURATION); + + /* + * Start press duration counter on press (falling), notify on release + * (rising) + */ + if(ti_lib_gpio_read_dio(BOARD_IOID_KEY_UP) == 0) { + up_timer.start = clock_time(); + up_timer.duration = 0; + } else { + up_timer.duration = clock_time() - up_timer.start; + sensors_changed(&button_up_sensor); + } + } + + if(ioid == BOARD_IOID_KEY_DOWN) { + if(!timer_expired(&down_timer.debounce)) { + return; + } + + timer_set(&down_timer.debounce, DEBOUNCE_DURATION); + + /* + * Start press duration counter on press (falling), notify on release + * (rising) + */ + if(ti_lib_gpio_read_dio(BOARD_IOID_KEY_DOWN) == 0) { + down_timer.start = clock_time(); + down_timer.duration = 0; + } else { + down_timer.duration = clock_time() - down_timer.start; + sensors_changed(&button_down_sensor); + } + } +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Configuration function for the button sensor for all buttons. + * + * \param type This function does nothing unless type == SENSORS_ACTIVE + * \param c 0: disable the button, non-zero: enable + * \param key: One of BOARD_KEY_LEFT, BOARD_KEY_RIGHT etc + */ +static void +config_buttons(int type, int c, uint32_t key) +{ + switch(type) { + case SENSORS_HW_INIT: + ti_lib_gpio_clear_event_dio(key); + ti_lib_rom_ioc_pin_type_gpio_input(key); + ti_lib_rom_ioc_port_configure_set(key, IOC_PORT_GPIO, BUTTON_GPIO_CFG); + gpio_interrupt_register_handler(key, button_press_handler); + break; + case SENSORS_ACTIVE: + if(c) { + ti_lib_gpio_clear_event_dio(key); + ti_lib_rom_ioc_pin_type_gpio_input(key); + ti_lib_rom_ioc_port_configure_set(key, IOC_PORT_GPIO, BUTTON_GPIO_CFG); + ti_lib_rom_ioc_int_enable(key); + } else { + ti_lib_rom_ioc_int_disable(key); + } + break; + default: + break; + } +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Configuration function for the select button. + * + * Parameters are passed onto config_buttons, which does the actual + * configuration + * Parameters are ignored. They have been included because the prototype is + * dictated by the core sensor api. The return value is also required by + * the API but otherwise ignored. + * + * \param type passed to config_buttons as-is + * \param value passed to config_buttons as-is + * + * \return ignored + */ +static int +config_select(int type, int value) +{ + config_buttons(type, value, BOARD_IOID_KEY_SELECT); + + return 1; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Configuration function for the left button. + * + * Parameters are passed onto config_buttons, which does the actual + * configuration + * Parameters are ignored. They have been included because the prototype is + * dictated by the core sensor api. The return value is also required by + * the API but otherwise ignored. + * + * \param type passed to config_buttons as-is + * \param value passed to config_buttons as-is + * + * \return ignored + */ +static int +config_left(int type, int value) +{ + config_buttons(type, value, BOARD_IOID_KEY_LEFT); + + return 1; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Configuration function for the right button. + * + * Parameters are passed onto config_buttons, which does the actual + * configuration + * Parameters are ignored. They have been included because the prototype is + * dictated by the core sensor api. The return value is also required by + * the API but otherwise ignored. + * + * \param type passed to config_buttons as-is + * \param value passed to config_buttons as-is + * + * \return ignored + */ +static int +config_right(int type, int value) +{ + config_buttons(type, value, BOARD_IOID_KEY_RIGHT); + + return 1; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Configuration function for the up button. + * + * Parameters are passed onto config_buttons, which does the actual + * configuration + * Parameters are ignored. They have been included because the prototype is + * dictated by the core sensor api. The return value is also required by + * the API but otherwise ignored. + * + * \param type passed to config_buttons as-is + * \param value passed to config_buttons as-is + * + * \return ignored + */ +static int +config_up(int type, int value) +{ + config_buttons(type, value, BOARD_IOID_KEY_UP); + + return 1; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Configuration function for the down button. + * + * Parameters are passed onto config_buttons, which does the actual + * configuration + * Parameters are ignored. They have been included because the prototype is + * dictated by the core sensor api. The return value is also required by + * the API but otherwise ignored. + * + * \param type passed to config_buttons as-is + * \param value passed to config_buttons as-is + * + * \return ignored + */ +static int +config_down(int type, int value) +{ + config_buttons(type, value, BOARD_IOID_KEY_DOWN); + + return 1; +} +/*---------------------------------------------------------------------------*/ +static int +value_select(int type) +{ + if(type == BUTTON_SENSOR_VALUE_STATE) { + return ti_lib_gpio_read_dio(BOARD_IOID_KEY_SELECT) == 0 ? + BUTTON_SENSOR_VALUE_PRESSED : BUTTON_SENSOR_VALUE_RELEASED; + } else if(type == BUTTON_SENSOR_VALUE_DURATION) { + return (int)sel_timer.duration; + } + return 0; +} +/*---------------------------------------------------------------------------*/ +static int +value_left(int type) +{ + if(type == BUTTON_SENSOR_VALUE_STATE) { + return ti_lib_gpio_read_dio(BOARD_IOID_KEY_LEFT) == 0 ? + BUTTON_SENSOR_VALUE_PRESSED : BUTTON_SENSOR_VALUE_RELEASED; + } else if(type == BUTTON_SENSOR_VALUE_DURATION) { + return (int)left_timer.duration; + } + return 0; +} +/*---------------------------------------------------------------------------*/ +static int +value_right(int type) +{ + if(type == BUTTON_SENSOR_VALUE_STATE) { + return ti_lib_gpio_read_dio(BOARD_IOID_KEY_RIGHT) == 0 ? + BUTTON_SENSOR_VALUE_PRESSED : BUTTON_SENSOR_VALUE_RELEASED; + } else if(type == BUTTON_SENSOR_VALUE_DURATION) { + return (int)right_timer.duration; + } + return 0; +} +/*---------------------------------------------------------------------------*/ +static int +value_up(int type) +{ + if(type == BUTTON_SENSOR_VALUE_STATE) { + return ti_lib_gpio_read_dio(BOARD_IOID_KEY_UP) == 0 ? + BUTTON_SENSOR_VALUE_PRESSED : BUTTON_SENSOR_VALUE_RELEASED; + } else if(type == BUTTON_SENSOR_VALUE_DURATION) { + return (int)up_timer.duration; + } + return 0; +} +/*---------------------------------------------------------------------------*/ +static int +value_down(int type) +{ + if(type == BUTTON_SENSOR_VALUE_STATE) { + return ti_lib_gpio_read_dio(BOARD_IOID_KEY_DOWN) == 0 ? + BUTTON_SENSOR_VALUE_PRESSED : BUTTON_SENSOR_VALUE_RELEASED; + } else if(type == BUTTON_SENSOR_VALUE_DURATION) { + return (int)down_timer.duration; + } + return 0; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Status function for all buttons + * \param type SENSORS_ACTIVE or SENSORS_READY + * \param key_io_id BOARD_IOID_KEY_LEFT, BOARD_IOID_KEY_RIGHT etc + * \return 1 if the button's port interrupt is enabled (edge detect) + * + * This function will only be called by status_left, status_right and the + * called will pass the correct key_io_id + */ +static int +status(int type, uint32_t key_io_id) +{ + switch(type) { + case SENSORS_ACTIVE: + case SENSORS_READY: + if(ti_lib_ioc_port_configure_get(key_io_id) & IOC_INT_ENABLE) { + return 1; + } + break; + default: + break; + } + return 0; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Status function for the select button. + * \param type SENSORS_ACTIVE or SENSORS_READY + * \return 1 if the button's port interrupt is enabled (edge detect) + * + * This function will call status. It will pass type verbatim and it will also + * pass the correct key_io_id + */ +static int +status_select(int type) +{ + return status(type, BOARD_IOID_KEY_SELECT); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Status function for the left button. + * \param type SENSORS_ACTIVE or SENSORS_READY + * \return 1 if the button's port interrupt is enabled (edge detect) + * + * This function will call status. It will pass type verbatim and it will also + * pass the correct key_io_id + */ +static int +status_left(int type) +{ + return status(type, BOARD_IOID_KEY_LEFT); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Status function for the right button. + * \param type SENSORS_ACTIVE or SENSORS_READY + * \return 1 if the button's port interrupt is enabled (edge detect) + * + * This function will call status. It will pass type verbatim and it will also + * pass the correct key_io_id + */ +static int +status_right(int type) +{ + return status(type, BOARD_IOID_KEY_RIGHT); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Status function for the up button. + * \param type SENSORS_ACTIVE or SENSORS_READY + * \return 1 if the button's port interrupt is enabled (edge detect) + * + * This function will call status. It will pass type verbatim and it will also + * pass the correct key_io_id + */ +static int +status_up(int type) +{ + return status(type, BOARD_IOID_KEY_UP); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Status function for the down button. + * \param type SENSORS_ACTIVE or SENSORS_READY + * \return 1 if the button's port interrupt is enabled (edge detect) + * + * This function will call status. It will pass type verbatim and it will also + * pass the correct key_io_id + */ +static int +status_down(int type) +{ + return status(type, BOARD_IOID_KEY_DOWN); +} +/*---------------------------------------------------------------------------*/ +SENSORS_SENSOR(button_select_sensor, BUTTON_SENSOR, value_select, + config_select, status_select); +SENSORS_SENSOR(button_left_sensor, BUTTON_SENSOR, value_left, config_left, + status_left); +SENSORS_SENSOR(button_right_sensor, BUTTON_SENSOR, value_right, config_right, + status_right); +SENSORS_SENSOR(button_up_sensor, BUTTON_SENSOR, value_up, config_up, status_up); +SENSORS_SENSOR(button_down_sensor, BUTTON_SENSOR, value_down, config_down, + status_down); +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor.h new file mode 100644 index 000000000..1c810c96d --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup srf06-common-peripherals + * @{ + * + * \file + * Header file for the SmartRF06EB + CC13xx/CC26xxEM Button Driver + */ +/*---------------------------------------------------------------------------*/ +#ifndef BUTTON_SENSOR_H_ +#define BUTTON_SENSOR_H_ +/*---------------------------------------------------------------------------*/ +#include "lib/sensors.h" +/*---------------------------------------------------------------------------*/ +#define BUTTON_SENSOR "Button" +/*---------------------------------------------------------------------------*/ +#define BUTTON_SENSOR_VALUE_STATE 0 +#define BUTTON_SENSOR_VALUE_DURATION 1 + +#define BUTTON_SENSOR_VALUE_RELEASED 0 +#define BUTTON_SENSOR_VALUE_PRESSED 1 +/*---------------------------------------------------------------------------*/ +extern const struct sensors_sensor button_select_sensor; +extern const struct sensors_sensor button_left_sensor; +extern const struct sensors_sensor button_right_sensor; +extern const struct sensors_sensor button_up_sensor; +extern const struct sensors_sensor button_down_sensor; +/*---------------------------------------------------------------------------*/ +#endif /* BUTTON_SENSOR_H_ */ +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Board.h new file mode 100644 index 000000000..f6dc2ba4d --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Board.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015-2016, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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 __BOARD_H +#define __BOARD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "CC1310DK_7XD.h" + +/* These #defines allow us to reuse TI-RTOS across other device families */ +#define Board_LED1 Board_DK_LED1 +#define Board_LED2 Board_DK_LED2 +#define Board_LED3 Board_DK_LED3 +#define Board_LED4 Board_DK_LED4 + +#define Board_LED0 Board_DK_LED4 + +#define Board_ADC0 CC1310DK_7XD_ADCVDDS +#define Board_ADC1 CC1310DK_7XD_ADCALS + +#define Board_ADCBuf0 CC1310DK_7XD_ADCBuf0 +#define Board_ADCBufChannel0 (0) +#define Board_ADCBufChannel1 (1) + +#define Board_BUTTON0 Board_KEY_UP +#define Board_BUTTON1 Board_KEY_DOWN + +#define Board_I2C0 Board_I2C +#define Board_UART0 Board_UART +#define Board_AES0 Board_AES +#define Board_WATCHDOG0 CC1310DK_7XD_WATCHDOG0 + +#define Board_initGeneral() { \ + Power_init(); \ + if (PIN_init(BoardGpioInitTable) != PIN_SUCCESS) \ + {System_abort("Error with PIN_init\n"); \ + } \ +} + +#define Board_initGPIO() +#define Board_initPWM() PWM_init() +#define Board_initSPI() SPI_init() +#define Board_initUART() UART_init() +#define Board_initWatchdog() Watchdog_init() +#define Board_initADCBuf() ADCBuf_init() +#define Board_initADC() ADC_init() +#define GPIO_toggle(n) +#define GPIO_write(n,m) + +#ifdef __cplusplus +} +#endif + +#endif /* __BOARD_H */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1310DK_7XD.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1310DK_7XD.c new file mode 100644 index 000000000..15e2c0f28 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1310DK_7XD.c @@ -0,0 +1,670 @@ +/* + * Copyright (c) 2015-2016, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +/* + * ====================== CC1310DK_7XD.c ============================================= + * This file is responsible for setting up the board specific items for the + * SRF06EB with the CC1310EM_7XD_7793 board. + */ + + +/* + * ====================== Includes ============================================ + */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/* + * ========================= IO driver initialization ========================= + * From main, PIN_init(BoardGpioInitTable) should be called to setup safe + * settings for this board. + * When a pin is allocated and then de-allocated, it will revert to the state + * configured in this table. + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(BoardGpioInitTable, ".const:BoardGpioInitTable") +#pragma DATA_SECTION(PINCC26XX_hwAttrs, ".const:PINCC26XX_hwAttrs") +#endif + +const PIN_Config BoardGpioInitTable[] = { + + Board_DK_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + Board_DK_LED2 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + Board_DK_LED3 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + Board_DK_LED4 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + Board_KEY_SELECT | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS, /* Button is active low */ + Board_KEY_UP | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS, /* Button is active low */ + Board_KEY_DOWN | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS, /* Button is active low */ + Board_KEY_LEFT | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS, /* Button is active low */ + Board_KEY_RIGHT | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS, /* Button is active low */ + Board_3V3_EN | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL, /* 3V3 domain off initially */ + Board_LCD_MODE | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* LCD pin high initially */ + Board_LCD_RST | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* LCD pin high initially */ + Board_LCD_CSN | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* LCD CSn deasserted initially */ + Board_ALS_PWR | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL, /* ALS power off initially */ + Board_ACC_PWR | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL, /* ACC power off initially */ + Board_ACC_CSN | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* ACC CSn deasserted initially */ + Board_SDCARD_CSN | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* SDCARD CSn deasserted initially */ + Board_UART_TX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* UART TX pin at inactive level */ + PIN_TERMINATE /* Terminate list */ +}; + +const PINCC26XX_HWAttrs PINCC26XX_hwAttrs = { + .intPriority = ~0, + .swiPriority = 0 +}; +/*============================================================================*/ + +/* + * ============================= Power begin =================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(PowerCC26XX_config, ".const:PowerCC26XX_config") +#endif +const PowerCC26XX_Config PowerCC26XX_config = { + .policyInitFxn = NULL, + .policyFxn = &PowerCC26XX_standbyPolicy, + .calibrateFxn = &PowerCC26XX_calibrate, + .enablePolicy = TRUE, + .calibrateRCOSC_LF = TRUE, + .calibrateRCOSC_HF = TRUE, +}; +/* + * ============================= Power end =================================== + */ + +/* + * ============================= UART begin =================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(UART_config, ".const:UART_config") +#pragma DATA_SECTION(uartCC26XXHWAttrs, ".const:uartCC26XXHWAttrs") +#endif + +/* Include drivers */ +#include +#include + +/* UART objects */ +UARTCC26XX_Object uartCC26XXObjects[CC1310DK_7XD_UARTCOUNT]; +unsigned char uartCC26XXRingBuffer[CC1310DK_7XD_UARTCOUNT][32]; + +/* UART hardware parameter structure, also used to assign UART pins */ +const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1310DK_7XD_UARTCOUNT] = { + { + .baseAddr = UART0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UART0, + .intNum = INT_UART0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .txPin = Board_UART_TX, + .rxPin = Board_UART_RX, + .ctsPin = PIN_UNASSIGNED, + .rtsPin = PIN_UNASSIGNED, + .ringBufPtr = uartCC26XXRingBuffer[0], + .ringBufSize = sizeof(uartCC26XXRingBuffer[0]) + } +}; + +/* UART configuration structure */ +const UART_Config UART_config[] = { + { + .fxnTablePtr = &UARTCC26XX_fxnTable, + .object = &uartCC26XXObjects[0], + .hwAttrs = &uartCC26XXHWAttrs[0] + }, + {NULL, NULL, NULL} +}; +/* + * ============================= UART end ===================================== + */ + +/* + * ============================= UDMA begin =================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(UDMACC26XX_config, ".const:UDMACC26XX_config") +#pragma DATA_SECTION(udmaHWAttrs, ".const:udmaHWAttrs") +#endif + +/* Include drivers */ +#include + +/* UDMA objects */ +UDMACC26XX_Object udmaObjects[CC1310DK_7XD_UDMACOUNT]; + +/* UDMA configuration structure */ +const UDMACC26XX_HWAttrs udmaHWAttrs[CC1310DK_7XD_UDMACOUNT] = { + { + .baseAddr = UDMA0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UDMA, + .intNum = INT_DMA_ERR, + .intPriority = ~0 + } +}; + +/* UDMA configuration structure */ +const UDMACC26XX_Config UDMACC26XX_config[] = { + { + .object = &udmaObjects[0], + .hwAttrs = &udmaHWAttrs[0] + }, + {NULL, NULL} +}; +/* + * ============================= UDMA end ===================================== + */ + +/* + * ========================== SPI DMA begin =================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(SPI_config, ".const:SPI_config") +#pragma DATA_SECTION(spiCC26XXDMAHWAttrs, ".const:spiCC26XXDMAHWAttrs") +#endif + +/* Include drivers */ +#include + +/* SPI objects */ +SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1310DK_7XD_SPICOUNT]; + +/* SPI configuration structure, describing which pins are to be used */ +const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1310DK_7XD_SPICOUNT] = { + { + .baseAddr = SSI0_BASE, + .intNum = INT_SSI0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .defaultTxBufValue = 0, + .powerMngrId = PowerCC26XX_PERIPH_SSI0, + .rxChannelBitMask = 1< + +/* LCD object */ +LCD_Object lcdObject; + +/* LCD hardware attribute structure */ +const LCD_HWAttrs lcdHWAttrs = { + .LCD_initCmd = &LCD_initCmd, + .lcdResetPin = Board_LCD_RST, /* LCD reset pin */ + .lcdModePin = Board_LCD_MODE, /* LCD mode pin */ + .lcdCsnPin = Board_LCD_CSN, /* LCD CSn pin */ + .spiIndex = Board_SPI0 +}; + +/* LCD configuration structure */ +const LCD_Config LCD_config = { + .object = &lcdObject, + .hwAttrs = &lcdHWAttrs +}; +/* + * ========================== LCD end ========================================= + */ + +/* + * ========================== Crypto begin ==================================== + * NOTE: The Crypto implementation should be considered experimental + * and not validated! + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(CryptoCC26XX_config, ".const:CryptoCC26XX_config") +#pragma DATA_SECTION(cryptoCC26XXHWAttrs, ".const:cryptoCC26XXHWAttrs") +#endif + +/* Include drivers */ +#include + +/* Crypto objects */ +CryptoCC26XX_Object cryptoCC26XXObjects[CC1310DK_7XD_CRYPTOCOUNT]; + +/* Crypto configuration structure, describing which pins are to be used */ +const CryptoCC26XX_HWAttrs cryptoCC26XXHWAttrs[CC1310DK_7XD_CRYPTOCOUNT] = { + { + .baseAddr = CRYPTO_BASE, + .powerMngrId = PowerCC26XX_PERIPH_CRYPTO, + .intNum = INT_CRYPTO_RESULT_AVAIL_IRQ, + .intPriority = ~0, + } +}; + +/* Crypto configuration structure */ +const CryptoCC26XX_Config CryptoCC26XX_config[] = { + { + .object = &cryptoCC26XXObjects[0], + .hwAttrs = &cryptoCC26XXHWAttrs[0] + }, + {NULL, NULL} +}; +/* + * ========================== Crypto end ========================================= + */ + + +/* + * ========================= RF driver begin ============================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(RFCC26XX_hwAttrs, ".const:RFCC26XX_hwAttrs") +#endif +/* Include drivers */ +#include + +/* RF hwi and swi priority */ +const RFCC26XX_HWAttrs RFCC26XX_hwAttrs = { + .hwiCpe0Priority = ~0, + .hwiHwPriority = ~0, + .swiCpe0Priority = 0, + .swiHwPriority = 0, +}; + +/* + * ========================== RF driver end ========================================= + */ + +/* + * ========================= Display begin ==================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(Display_config, ".const:Display_config") +#pragma DATA_SECTION(displayDogm1286HWattrs, ".const:displayDogm1286HWAttrs") +#pragma DATA_SECTION(displayUartHWAttrs, ".const:displayUartHWAttrs") +#endif + +#include +#include +#include + +/* Structures for UartPlain Blocking */ +DisplayUart_Object displayUartObject; + +#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE +#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 +#endif +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; + +const DisplayUart_HWAttrs displayUartHWAttrs = { + .uartIdx = Board_UART, + .baudRate = 115200, + .mutexTimeout = BIOS_WAIT_FOREVER, + .strBuf = uartStringBuf, + .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, +}; + +/* Structures for DOGM1286 */ +DisplayDogm1286_Object displayDogm1286Object; + +const DisplayDogm1286_HWAttrs displayDogm1286HWattrs = { + .lcdHandle = (LCD_Handle) & LCD_config, + .powerPin = Board_3V3_EN +}; + +/* Array of displays */ +const Display_Config Display_config[] = { +#if !defined(BOARD_DISPLAY_EXCLUDE_UART) + { + .fxnTablePtr = &DisplayUart_fxnTable, + .object = &displayUartObject, + .hwAttrs = &displayUartHWAttrs, + }, +#endif +#if !defined(BOARD_DISPLAY_EXCLUDE_LCD) + { + .fxnTablePtr = &DisplayDogm1286_fxnTable, + .object = &displayDogm1286Object, + .hwAttrs = &displayDogm1286HWattrs + }, +#endif + { NULL, NULL, NULL } // Terminator +}; + +/* + * ========================= Display end ====================================== + */ + +/* + * ============================ GPTimer begin ================================= + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(GPTimerCC26XX_config, ".const:GPTimerCC26XX_config") +#pragma DATA_SECTION(gptimerCC26xxHWAttrs, ".const:gptimerCC26xxHWAttrs") +#endif + +/* GPTimer hardware attributes, one per timer part (Timer 0A, 0B, 1A, 1B..) */ +const GPTimerCC26XX_HWAttrs gptimerCC26xxHWAttrs[CC1310DK_7XD_GPTIMERPARTSCOUNT] = { + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0A, }, + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0B, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1A, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1B, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2A, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2B, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3A, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3B, }, +}; + +/* GPTimer objects, one per full-width timer (A+B) (Timer 0, Timer 1..) */ +GPTimerCC26XX_Object gptimerCC26XXObjects[CC1310DK_7XD_GPTIMERCOUNT]; + +/* GPTimer configuration (used as GPTimer_Handle by driver and application) */ +const GPTimerCC26XX_Config GPTimerCC26XX_config[CC1310DK_7XD_GPTIMERPARTSCOUNT] = { + { &gptimerCC26XXObjects[0], &gptimerCC26xxHWAttrs[0], GPT_A }, + { &gptimerCC26XXObjects[0], &gptimerCC26xxHWAttrs[1], GPT_B }, + { &gptimerCC26XXObjects[1], &gptimerCC26xxHWAttrs[2], GPT_A }, + { &gptimerCC26XXObjects[1], &gptimerCC26xxHWAttrs[3], GPT_B }, + { &gptimerCC26XXObjects[2], &gptimerCC26xxHWAttrs[4], GPT_A }, + { &gptimerCC26XXObjects[2], &gptimerCC26xxHWAttrs[5], GPT_B }, + { &gptimerCC26XXObjects[3], &gptimerCC26xxHWAttrs[6], GPT_A }, + { &gptimerCC26XXObjects[3], &gptimerCC26xxHWAttrs[7], GPT_B }, +}; + +/* + * ============================ GPTimer end =================================== + */ + + + +/* + * ============================= PWM begin ==================================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(PWM_config, ".const:PWM_config") +#pragma DATA_SECTION(pwmtimerCC26xxHWAttrs, ".const:pwmtimerCC26xxHWAttrs") +#endif + +/* PWM configuration, one per PWM output. */ +PWMTimerCC26XX_HwAttrs pwmtimerCC26xxHWAttrs[CC1310DK_7XD_PWMCOUNT] = { + { .pwmPin = Board_PWMPIN0, .gpTimerUnit = Board_GPTIMER0A }, + { .pwmPin = Board_PWMPIN1, .gpTimerUnit = Board_GPTIMER0B }, + { .pwmPin = Board_PWMPIN2, .gpTimerUnit = Board_GPTIMER1A }, + { .pwmPin = Board_PWMPIN3, .gpTimerUnit = Board_GPTIMER1B }, + { .pwmPin = Board_PWMPIN4, .gpTimerUnit = Board_GPTIMER2A }, + { .pwmPin = Board_PWMPIN5, .gpTimerUnit = Board_GPTIMER2B }, + { .pwmPin = Board_PWMPIN6, .gpTimerUnit = Board_GPTIMER3A }, + { .pwmPin = Board_PWMPIN7, .gpTimerUnit = Board_GPTIMER3B }, +}; + +/* PWM object, one per PWM output */ +PWMTimerCC26XX_Object pwmtimerCC26xxObjects[CC1310DK_7XD_PWMCOUNT]; + +extern const PWM_FxnTable PWMTimerCC26XX_fxnTable; + +/* PWM configuration (used as PWM_Handle by driver and application) */ +const PWM_Config PWM_config[CC1310DK_7XD_PWMCOUNT + 1] = { + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[0], &pwmtimerCC26xxHWAttrs[0] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[1], &pwmtimerCC26xxHWAttrs[1] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[2], &pwmtimerCC26xxHWAttrs[2] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[3], &pwmtimerCC26xxHWAttrs[3] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[4], &pwmtimerCC26xxHWAttrs[4] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[5], &pwmtimerCC26xxHWAttrs[5] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[6], &pwmtimerCC26xxHWAttrs[6] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[7], &pwmtimerCC26xxHWAttrs[7] }, + { NULL, NULL, NULL } +}; + + +/* + * ============================= PWM end ====================================== + */ + + +/* + * ========================== ADCBuf begin ========================================= + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(ADCBuf_config, ".const:ADCBuf_config") +#pragma DATA_SECTION(adcBufCC26xxHWAttrs, ".const:adcBufCC26xxHWAttrs") +#pragma DATA_SECTION(ADCBufCC26XX_adcChannelLut, ".const:ADCBufCC26XX_adcChannelLut") +#endif + +/* Include drivers */ +#include +#include + +/* ADC objects */ +ADCBufCC26XX_Object adcBufCC26xxObjects[CC1310DK_7XD_ADCBufCOUNT]; + +/* + * This table converts a virtual adc channel into a dio and internal analogue input signal. + * This table is necessary for the functioning of the adcBuf driver. + * Comment out unused entries to save flash. + * Dio and internal signal pairs are hardwired. Do not remap them in the table. You may reorder entire entries though. + * The mapping of dio and internal signals is package dependent. + */ +const ADCBufCC26XX_AdcChannelLutEntry ADCBufCC26XX_adcChannelLut[] = { + {Board_ALS_OUT, ADC_COMPB_IN_AUXIO7}, + {PIN_UNASSIGNED, ADC_COMPB_IN_DCOUPL}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VSS}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VDDS} +}; + +const ADCBufCC26XX_HWAttrs adcBufCC26xxHWAttrs[CC1310DK_7XD_ADCBufCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + .adcChannelLut = ADCBufCC26XX_adcChannelLut, + .gpTimerUnit = Board_GPTIMER0A, + .gptDMAChannelMask = 1 << UDMA_CHAN_TIMER0_A, + } +}; + +const ADCBuf_Config ADCBuf_config[] = { + {&ADCBufCC26XX_fxnTable, &adcBufCC26xxObjects[0], &adcBufCC26xxHWAttrs[0]}, + {NULL, NULL, NULL}, +}; +/* + * ========================== ADCBuf end ========================================= + */ + + +/* + * ========================== ADC begin ========================================= + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(ADC_config, ".const:ADC_config") +#pragma DATA_SECTION(adcCC26xxHWAttrs, ".const:adcCC26xxHWAttrs") +#endif + +/* Include drivers */ +#include +#include + + +/* ADC objects */ +ADCCC26XX_Object adcCC26xxObjects[CC1310DK_7XD_ADCCOUNT]; + + +const ADCCC26XX_HWAttrs adcCC26xxHWAttrs[CC1310DK_7XD_ADCCOUNT] = { + { + .adcDIO = Board_ALS_OUT, + .adcCompBInput = ADC_COMPB_IN_AUXIO7, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_DCOUPL, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VSS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VDDS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + } +}; + +const ADC_Config ADC_config[] = { + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[0], &adcCC26xxHWAttrs[0]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[1], &adcCC26xxHWAttrs[1]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[2], &adcCC26xxHWAttrs[2]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[3], &adcCC26xxHWAttrs[3]}, + {NULL, NULL, NULL}, +}; + +/* + * ========================== ADC end ========================================= + */ + +/* + * =============================== Watchdog =============================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(Watchdog_config, ".const:Watchdog_config") +#pragma DATA_SECTION(watchdogCC26XXHWAttrs, ".const:watchdogCC26XXHWAttrs") +#endif + +#include +#include + +WatchdogCC26XX_Object watchdogCC26XXObjects[CC1310DK_7XD_WATCHDOGCOUNT]; + +const WatchdogCC26XX_HWAttrs watchdogCC26XXHWAttrs[CC1310DK_7XD_WATCHDOGCOUNT] = { + { + .baseAddr = WDT_BASE, + .intNum = INT_WDT_IRQ, + .reloadValue = 1000 /* Reload value in milliseconds */ + }, +}; + +const Watchdog_Config Watchdog_config[] = { + { + .fxnTablePtr = &WatchdogCC26XX_fxnTable, + .object = &watchdogCC26XXObjects[0], + .hwAttrs = &watchdogCC26XXHWAttrs[0] + }, + {NULL, NULL, NULL}, +}; + +/* + * ======== CC26XX_LAUNCHXL_initWatchdog ======== + */ +void CC26XX_LAUNCHXL_initWatchdog(void) +{ + Watchdog_init(); +} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1310DK_7XD.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1310DK_7XD.h new file mode 100644 index 000000000..6e5e45c19 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1310DK_7XD.h @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2015-2016, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ +/** ============================================================================ + * @file CC1310DK_7XD.h + * + * @brief CC1310EM_7XD_7793 Board Specific header file. + * The project options should point to this file if this is the + * CC1310EM you are developing code for. + * + * The CC1310 header file should be included in an application as follows: + * @code + * #include + * @endcode + * + * ============================================================================ + */ +#ifndef __CC1310EM_7XD_7793_H__ +#define __CC1310EM_7XD_7793_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** ============================================================================ + * Symbol by generic Board.c to include the correct kit specific Board.c + * ==========================================================================*/ +#define CC1310EM_7XD_7793 +#define CC1310DK_7XD + + +/** ============================================================================ + * Includes + * ==========================================================================*/ +#include +#include + +/** ============================================================================ + * Externs + * ==========================================================================*/ +extern const PIN_Config BoardGpioInitTable[]; + +/** ============================================================================ + * Defines + * ==========================================================================*/ + +/* Mapping of pins to board signals using general board aliases + * + */ +/* Leds */ +#define Board_LED_ON 1 /* LEDs on SmartRF06 EB are active high */ +#define Board_LED_OFF 0 +#define Board_DK_LED1 IOID_25 /* P2.11 */ +#define Board_DK_LED2 IOID_27 /* P2.13 */ +#define Board_DK_LED3 IOID_7 /* P1.2 */ +#define Board_DK_LED4 IOID_6 /* P1.4 */ +/* Button Board */ +#define Board_KEY_SELECT IOID_11 /* P1.14 */ +#define Board_KEY_UP IOID_19 /* P1.10 */ +#define Board_KEY_DOWN IOID_12 /* P1.12 */ +#define Board_KEY_LEFT IOID_15 /* P1.6 */ +#define Board_KEY_RIGHT IOID_18 /* P1.8 */ +/* LCD Board */ +#define Board_LCD_MODE IOID_4 /* P1.11 */ +#define Board_LCD_RST IOID_5 /* P1.13 */ +#define Board_LCD_CSN IOID_14 /* P1.17 */ +/* UART Board */ +#define Board_UART_RX IOID_2 /* P1.7 */ +#define Board_UART_TX IOID_3 /* P1.9 */ +#define Board_UART_CTS IOID_22 /* P1.3 */ +#define Board_UART_RTS IOID_21 /* P2.18 */ +/* SPI Board */ +#define Board_SPI0_MISO IOID_8 /* P1.20 */ +#define Board_SPI0_MOSI IOID_9 /* P1.18 */ +#define Board_SPI0_CLK IOID_10 /* P1.16 */ +#define Board_SPI0_CSN PIN_UNASSIGNED /* P1.14, separate CSn for LCD, SDCARD, and ACC */ +#define Board_SPI1_MISO IOID_24 /* RF2.10 for testing only */ +#define Board_SPI1_MOSI IOID_23 /* RF2.5 for testing only */ +#define Board_SPI1_CLK IOID_30 /* RF2.12 for testing only */ +#define Board_SPI1_CSN PIN_UNASSIGNED /* RF2.6 for testing only */ +/* Ambient Light Sensor */ +#define Board_ALS_OUT IOID_23 /* P2.5 */ +#define Board_ALS_PWR IOID_26 /* P2.6 */ +/* Accelerometer */ +#define Board_ACC_PWR IOID_20 /* P2.8 */ +#define Board_ACC_CSN IOID_24 /* P2.10 */ +/* SD Card */ +#define Board_SDCARD_CSN IOID_30 /* P2.12 */ +/* Power Board */ +#define Board_3V3_EN IOID_13 /* P1.15 */ +/* PWM outputs */ +#define Board_PWMPIN0 Board_DK_LED1 +#define Board_PWMPIN1 Board_DK_LED2 +#define Board_PWMPIN2 PIN_UNASSIGNED +#define Board_PWMPIN3 PIN_UNASSIGNED +#define Board_PWMPIN4 PIN_UNASSIGNED +#define Board_PWMPIN5 PIN_UNASSIGNED +#define Board_PWMPIN6 PIN_UNASSIGNED +#define Board_PWMPIN7 PIN_UNASSIGNED +/* Analog capable DIO's */ +#define Board_DIO23_ANALOG IOID_23 +#define Board_DIO24_ANALOG IOID_24 +#define Board_DIO25_ANALOG IOID_25 +#define Board_DIO26_ANALOG IOID_26 +#define Board_DIO27_ANALOG IOID_27 +#define Board_DIO28_ANALOG IOID_28 +#define Board_DIO29_ANALOG IOID_29 +#define Board_DIO30_ANALOG IOID_30 + +/** ============================================================================ + * Instance identifiers + * ==========================================================================*/ +/* Generic SPI instance identifiers */ +#define Board_SPI0 CC1310DK_7XD_SPI0 +/* Generic UART instance identifiers */ +#define Board_UART CC1310DK_7XD_UART0 +/* Generic Crypto instance identifiers */ +#define Board_CRYPTO CC1310DK_7XD_CRYPTO0 +/* Generic GPTimer instance identifiers */ +#define Board_GPTIMER0A CC1310DK_7XD_GPTIMER0A +#define Board_GPTIMER0B CC1310DK_7XD_GPTIMER0B +#define Board_GPTIMER1A CC1310DK_7XD_GPTIMER1A +#define Board_GPTIMER1B CC1310DK_7XD_GPTIMER1B +#define Board_GPTIMER2A CC1310DK_7XD_GPTIMER2A +#define Board_GPTIMER2B CC1310DK_7XD_GPTIMER2B +#define Board_GPTIMER3A CC1310DK_7XD_GPTIMER3A +#define Board_GPTIMER3B CC1310DK_7XD_GPTIMER3B +/* Generic PWM instance identifiers */ +#define Board_PWM0 CC1310DK_7XD_PWM0 +#define Board_PWM1 CC1310DK_7XD_PWM1 +#define Board_PWM2 CC1310DK_7XD_PWM2 +#define Board_PWM3 CC1310DK_7XD_PWM3 +#define Board_PWM4 CC1310DK_7XD_PWM4 +#define Board_PWM5 CC1310DK_7XD_PWM5 +#define Board_PWM6 CC1310DK_7XD_PWM6 +#define Board_PWM7 CC1310DK_7XD_PWM7 + +/** ============================================================================ + * Number of peripherals and their names + * ==========================================================================*/ + +/*! + * @def CC1310DK_7XD_CryptoName + * @brief Enum of Crypto names on the CC1310 dev board + */ +typedef enum CC1310DK_7XD_CryptoName { + CC1310DK_7XD_CRYPTO0 = 0, + CC1310DK_7XD_CRYPTOCOUNT +} CC1310DK_7XD_CryptoName; + +/*! + * @def CC1310DK_7XD_SPIName + * @brief Enum of SPI names on the CC1310 dev board + */ +typedef enum CC1310DK_7XD_SPIName { + CC1310DK_7XD_SPI0 = 0, + CC1310DK_7XD_SPI1, + CC1310DK_7XD_SPICOUNT +} CC1310DK_7XD_SPIName; + +/*! + * @def CC1310DK_7XD_UARTName + * @brief Enum of UARTs on the CC1310 dev board + */ +typedef enum CC1310DK_7XD_UARTName { + CC1310DK_7XD_UART0 = 0, + CC1310DK_7XD_UARTCOUNT +} CC1310DK_7XD_UARTName; + +/*! + * @def CC1310DK_7XD_UdmaName + * @brief Enum of DMA buffers + */ +typedef enum CC1310DK_7XD_UdmaName { + CC1310DK_7XD_UDMA0 = 0, + CC1310DK_7XD_UDMACOUNT +} CC1310DK_7XD_UdmaName; + +/*! + * @def CC1310DK_7XD_GPTimerName + * @brief Enum of GPTimer parts + */ +typedef enum CC1310DK_7XD_GPTimerName +{ + CC1310DK_7XD_GPTIMER0A = 0, + CC1310DK_7XD_GPTIMER0B, + CC1310DK_7XD_GPTIMER1A, + CC1310DK_7XD_GPTIMER1B, + CC1310DK_7XD_GPTIMER2A, + CC1310DK_7XD_GPTIMER2B, + CC1310DK_7XD_GPTIMER3A, + CC1310DK_7XD_GPTIMER3B, + CC1310DK_7XD_GPTIMERPARTSCOUNT +} CC1310DK_7XD_GPTimerName; + +/*! + * @def CC1310DK_7XD_GPTimers + * @brief Enum of GPTimers + */ +typedef enum CC1310DK_7XD_GPTimers +{ + CC1310DK_7XD_GPTIMER0 = 0, + CC1310DK_7XD_GPTIMER1, + CC1310DK_7XD_GPTIMER2, + CC1310DK_7XD_GPTIMER3, + CC1310DK_7XD_GPTIMERCOUNT +} CC1310DK_7XD_GPTimers; + +/*! + * @def CC1310DK_7XD_PWM + * @brief Enum of PWM outputs on the board + */ +typedef enum CC1310DK_7XD_PWM +{ + CC1310DK_7XD_PWM0 = 0, + CC1310DK_7XD_PWM1, + CC1310DK_7XD_PWM2, + CC1310DK_7XD_PWM3, + CC1310DK_7XD_PWM4, + CC1310DK_7XD_PWM5, + CC1310DK_7XD_PWM6, + CC1310DK_7XD_PWM7, + CC1310DK_7XD_PWMCOUNT +} CC1310DK_7XD_PWM; + +/*! + * @def CC1310DK_7XD__ADCBufName + * @brief Enum of ADC's + */ +typedef enum CC1310DK_7XD_ADCBufName { + CC1310DK_7XD_ADCBuf0 = 0, + CC1310DK_7XD_ADCBufCOUNT +} CC1310DK_7XD_ADCBufName; + +/*! + * @def CC1310DK_7XD_ADCName + * @brief Enum of ADCs + */ +typedef enum CC1310DK_7XD_ADCName { + CC1310DK_7XD_ADCALS = 0, + CC1310DK_7XD_ADCDCOUPL, + CC1310DK_7XD_ADCVSS, + CC1310DK_7XD_ADCVDDS, + CC1310DK_7XD_ADCCOUNT +} CC1310DK_7XD_ADCName; + +/*! + * @def CC1310DK_7XD_WatchdogName + * @brief Enum of Watchdogs on the CC1310DK_7XD dev board + */ +typedef enum CC1310DK_7XD_WatchdogName { + CC1310DK_7XD_WATCHDOG0 = 0, + + CC1310DK_7XD_WATCHDOGCOUNT +} CC1310DK_7XD_WatchdogName; + +#ifdef __cplusplus +} +#endif + +#endif /* __CC1310EM_H__ */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 new file mode 100644 index 000000000..4efb443ef --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 @@ -0,0 +1,16 @@ +################################################################################ +# SimpleLink Device makefile + +SUBFAMILY = cc13x0-cc26x0 +DEVICE_FAMILY = CC13X0 + +BOARD_SOURCEFILES += CC1310DK_7XD.c + +SUPPORTS_PROP_MODE = 1 +SUPPORTS_IEEE_MODE = 1 + +### Signal that we can be programmed with cc2538-bsl +BOARD_SUPPORTS_BSL = 1 + +# Include the common board makefile +include $(FAMILY_PATH)/srf06/Makefile.srf06 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Board.h new file mode 100644 index 000000000..cfc985633 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Board.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015-2016, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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 __BOARD_H +#define __BOARD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "CC2650DK_7ID.h" + +/* These #defines allow us to reuse TI-RTOS across other device families */ +#define Board_LED1 Board_DK_LED1 +#define Board_LED2 Board_DK_LED2 +#define Board_LED3 Board_DK_LED3 +#define Board_LED4 Board_DK_LED4 + +#define Board_LED0 Board_DK_LED4 + +#define Board_BUTTON0 Board_KEY_UP +#define Board_BUTTON1 Board_KEY_DOWN + +#define Board_UART0 Board_UART +#define Board_AES0 Board_AES +#define Board_WATCHDOG0 CC2650DK_7ID_WATCHDOG0 + +#define Board_ADC0 CC2650DK_7ID_ADCVDDS +#define Board_ADC1 CC2650DK_7ID_ADCALS + +#define Board_ADCBuf0 CC2650DK_7ID_ADCBuf0 +#define Board_ADCBufChannel0 (0) +#define Board_ADCBufChannel1 (1) + +#define Board_initGeneral() { \ + Power_init(); \ + if (PIN_init(BoardGpioInitTable) != PIN_SUCCESS) \ + {System_abort("Error with PIN_init\n"); \ + } \ +} + +#define Board_initGPIO() +#define Board_initPWM() PWM_init() +#define Board_initSPI() SPI_init() +#define Board_initUART() UART_init() +#define Board_initWatchdog() Watchdog_init() +#define Board_initADCBuf() ADCBuf_init() +#define Board_initADC() ADC_init() +#define GPIO_toggle(n) +#define GPIO_write(n,m) + +#ifdef __cplusplus +} +#endif + +#endif /* __BOARD_H */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c new file mode 100644 index 000000000..59d489725 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c @@ -0,0 +1,668 @@ +/* + * Copyright (c) 2015-2016, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +/* + * ====================== CC2650DK_7ID.c ============================================= + * This file is responsible for setting up the board specific items for the + * SRF06EB with the CC2650EM_7ID board. + */ + + +/* + * ====================== Includes ============================================ + */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/* + * ========================= IO driver initialization ========================= + * From main, PIN_init(BoardGpioInitTable) should be called to setup safe + * settings for this board. + * When a pin is allocated and then de-allocated, it will revert to the state + * configured in this table. + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(BoardGpioInitTable, ".const:BoardGpioInitTable") +#pragma DATA_SECTION(PINCC26XX_hwAttrs, ".const:PINCC26XX_hwAttrs") +#endif + +const PIN_Config BoardGpioInitTable[] = { + + Board_DK_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + Board_DK_LED2 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + Board_DK_LED3 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + Board_DK_LED4 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + Board_KEY_SELECT | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS, /* Button is active low */ + Board_KEY_UP | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS, /* Button is active low */ + Board_KEY_DOWN | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS, /* Button is active low */ + Board_KEY_LEFT | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS, /* Button is active low */ + Board_KEY_RIGHT | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS, /* Button is active low */ + Board_3V3_EN | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL, /* 3V3 domain off initially */ + Board_LCD_MODE | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* LCD pin high initially */ + Board_LCD_RST | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* LCD pin high initially */ + Board_LCD_CSN | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* LCD CSn deasserted initially */ + Board_ALS_PWR | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL, /* ALS power off initially */ + Board_ACC_PWR | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL, /* ACC power off initially */ + Board_ACC_CSN | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* ACC CSn deasserted initially */ + Board_SDCARD_CSN | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* SDCARD CSn deasserted initially */ + Board_UART_TX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* UART TX pin at inactive level */ + PIN_TERMINATE /* Terminate list */ +}; + +const PINCC26XX_HWAttrs PINCC26XX_hwAttrs = { + .intPriority = ~0, + .swiPriority = 0 +}; +/*============================================================================*/ + +/* + * ============================= Power begin =================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(PowerCC26XX_config, ".const:PowerCC26XX_config") +#endif +const PowerCC26XX_Config PowerCC26XX_config = { + .policyInitFxn = NULL, + .policyFxn = &PowerCC26XX_standbyPolicy, + .calibrateFxn = &PowerCC26XX_calibrate, + .enablePolicy = TRUE, + .calibrateRCOSC_LF = TRUE, + .calibrateRCOSC_HF = TRUE, +}; +/* + * ============================= Power end =================================== + */ + +/* + * ============================= UART begin =================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(UART_config, ".const:UART_config") +#pragma DATA_SECTION(uartCC26XXHWAttrs, ".const:uartCC26XXHWAttrs") +#endif + +/* Include drivers */ +#include +#include + +/* UART objects */ +UARTCC26XX_Object uartCC26XXObjects[CC2650DK_7ID_UARTCOUNT]; +unsigned char uartCC26XXRingBuffer[CC2650DK_7ID_UARTCOUNT][32]; + +/* UART hardware parameter structure, also used to assign UART pins */ +const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC2650DK_7ID_UARTCOUNT] = { + { + .baseAddr = UART0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UART0, + .intNum = INT_UART0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .txPin = Board_UART_TX, + .rxPin = Board_UART_RX, + .ctsPin = PIN_UNASSIGNED, + .rtsPin = PIN_UNASSIGNED, + .ringBufPtr = uartCC26XXRingBuffer[0], + .ringBufSize = sizeof(uartCC26XXRingBuffer[0]) + } +}; + +/* UART configuration structure */ +const UART_Config UART_config[] = { + { + .fxnTablePtr = &UARTCC26XX_fxnTable, + .object = &uartCC26XXObjects[0], + .hwAttrs = &uartCC26XXHWAttrs[0] + }, + {NULL, NULL, NULL} +}; +/* + * ============================= UART end ===================================== + */ + +/* + * ============================= UDMA begin =================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(UDMACC26XX_config, ".const:UDMACC26XX_config") +#pragma DATA_SECTION(udmaHWAttrs, ".const:udmaHWAttrs") +#endif + +/* Include drivers */ +#include + +/* UDMA objects */ +UDMACC26XX_Object udmaObjects[CC2650DK_7ID_UDMACOUNT]; + +/* UDMA configuration structure */ +const UDMACC26XX_HWAttrs udmaHWAttrs[CC2650DK_7ID_UDMACOUNT] = { + { + .baseAddr = UDMA0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UDMA, + .intNum = INT_DMA_ERR, + .intPriority = ~0 + } +}; + +/* UDMA configuration structure */ +const UDMACC26XX_Config UDMACC26XX_config[] = { + { + .object = &udmaObjects[0], + .hwAttrs = &udmaHWAttrs[0] + }, + {NULL, NULL} +}; +/* + * ============================= UDMA end ===================================== + */ + +/* + * ========================== SPI DMA begin =================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(SPI_config, ".const:SPI_config") +#pragma DATA_SECTION(spiCC26XXDMAHWAttrs, ".const:spiCC26XXDMAHWAttrs") +#endif + +/* Include drivers */ +#include + +/* SPI objects */ +SPICC26XXDMA_Object spiCC26XXDMAObjects[CC2650DK_7ID_SPICOUNT]; + +/* SPI configuration structure, describing which pins are to be used */ +const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC2650DK_7ID_SPICOUNT] = { + { + .baseAddr = SSI0_BASE, + .intNum = INT_SSI0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .powerMngrId = PowerCC26XX_PERIPH_SSI0, + .defaultTxBufValue = 0, + .rxChannelBitMask = 1< + +/* LCD object */ +LCD_Object lcdObject; + +/* LCD hardware attribute structure */ +const LCD_HWAttrs lcdHWAttrs = { + .LCD_initCmd = &LCD_initCmd, + .lcdResetPin = Board_LCD_RST, /* LCD reset pin */ + .lcdModePin = Board_LCD_MODE, /* LCD mode pin */ + .lcdCsnPin = Board_LCD_CSN, /* LCD CSn pin */ + .spiIndex = Board_SPI0 +}; + +/* LCD configuration structure */ +const LCD_Config LCD_config = { + .object = &lcdObject, + .hwAttrs = &lcdHWAttrs +}; +/* + * ========================== LCD end ========================================= + */ + +/* + * ========================== Crypto begin ==================================== + * NOTE: The Crypto implementation should be considered experimental + * and not validated! + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(CryptoCC26XX_config, ".const:CryptoCC26XX_config") +#pragma DATA_SECTION(cryptoCC26XXHWAttrs, ".const:cryptoCC26XXHWAttrs") +#endif + +/* Include drivers */ +#include + +/* Crypto objects */ +CryptoCC26XX_Object cryptoCC26XXObjects[CC2650DK_7ID_CRYPTOCOUNT]; + +/* Crypto configuration structure, describing which pins are to be used */ +const CryptoCC26XX_HWAttrs cryptoCC26XXHWAttrs[CC2650DK_7ID_CRYPTOCOUNT] = { + { + .baseAddr = CRYPTO_BASE, + .powerMngrId = PowerCC26XX_PERIPH_CRYPTO, + .intNum = INT_CRYPTO_RESULT_AVAIL_IRQ, + .intPriority = ~0, + } +}; + +/* Crypto configuration structure */ +const CryptoCC26XX_Config CryptoCC26XX_config[] = { + { + .object = &cryptoCC26XXObjects[0], + .hwAttrs = &cryptoCC26XXHWAttrs[0] + }, + {NULL, NULL} +}; +/* + * ========================== Crypto end ========================================= + */ + + +/* + * ========================= RF driver begin ============================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(RFCC26XX_hwAttrs, ".const:RFCC26XX_hwAttrs") +#endif + +/* Include drivers */ +#include + +/* RF hwi and swi priority */ +const RFCC26XX_HWAttrs RFCC26XX_hwAttrs = { + .hwiCpe0Priority = ~0, + .hwiHwPriority = ~0, + .swiCpe0Priority = 0, + .swiHwPriority = 0, +}; + +/* + * ========================== RF driver end ========================================= + */ + +/* + * ========================= Display begin ==================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(Display_config, ".const:Display_config") +#pragma DATA_SECTION(displayDogm1286HWattrs, ".const:displayDogm1286HWAttrs") +#pragma DATA_SECTION(displayUartHWAttrs, ".const:displayUartHWAttrs") +#endif + +#include +#include +#include + +/* Structures for UartPlain Blocking */ +DisplayUart_Object displayUartObject; + +#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE +#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 +#endif +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; + +const DisplayUart_HWAttrs displayUartHWAttrs = { + .uartIdx = Board_UART, + .baudRate = 115200, + .mutexTimeout = BIOS_WAIT_FOREVER, + .strBuf = uartStringBuf, + .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, +}; + +/* Structures for DOGM1286 */ +DisplayDogm1286_Object displayDogm1286Object; + +const DisplayDogm1286_HWAttrs displayDogm1286HWattrs = { + .lcdHandle = (LCD_Handle) & LCD_config, + .powerPin = Board_3V3_EN +}; + +/* Array of displays */ +const Display_Config Display_config[] = { +#if !defined(BOARD_DISPLAY_EXCLUDE_UART) + { + .fxnTablePtr = &DisplayUart_fxnTable, + .object = &displayUartObject, + .hwAttrs = &displayUartHWAttrs, + }, +#endif +#if !defined(BOARD_DISPLAY_EXCLUDE_LCD) + { + .fxnTablePtr = &DisplayDogm1286_fxnTable, + .object = &displayDogm1286Object, + .hwAttrs = &displayDogm1286HWattrs + }, +#endif + { NULL, NULL, NULL } // Terminator +}; + +/* + * ========================= Display end ====================================== + */ + +/* + * ============================ GPTimer begin ================================= + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(GPTimerCC26XX_config, ".const:GPTimerCC26XX_config") +#pragma DATA_SECTION(gptimerCC26xxHWAttrs, ".const:gptimerCC26xxHWAttrs") +#endif + +/* GPTimer hardware attributes, one per timer part (Timer 0A, 0B, 1A, 1B..) */ +const GPTimerCC26XX_HWAttrs gptimerCC26xxHWAttrs[CC2650DK_7ID_GPTIMERPARTSCOUNT] = { + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0A, }, + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0B, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1A, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1B, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2A, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2B, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3A, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3B, }, +}; + +/* GPTimer objects, one per full-width timer (A+B) (Timer 0, Timer 1..) */ +GPTimerCC26XX_Object gptimerCC26XXObjects[CC2650DK_7ID_GPTIMERCOUNT]; + +/* GPTimer configuration (used as GPTimer_Handle by driver and application) */ +const GPTimerCC26XX_Config GPTimerCC26XX_config[CC2650DK_7ID_GPTIMERPARTSCOUNT] = { + { &gptimerCC26XXObjects[0], &gptimerCC26xxHWAttrs[0], GPT_A }, + { &gptimerCC26XXObjects[0], &gptimerCC26xxHWAttrs[1], GPT_B }, + { &gptimerCC26XXObjects[1], &gptimerCC26xxHWAttrs[2], GPT_A }, + { &gptimerCC26XXObjects[1], &gptimerCC26xxHWAttrs[3], GPT_B }, + { &gptimerCC26XXObjects[2], &gptimerCC26xxHWAttrs[4], GPT_A }, + { &gptimerCC26XXObjects[2], &gptimerCC26xxHWAttrs[5], GPT_B }, + { &gptimerCC26XXObjects[3], &gptimerCC26xxHWAttrs[6], GPT_A }, + { &gptimerCC26XXObjects[3], &gptimerCC26xxHWAttrs[7], GPT_B }, +}; + +/* + * ============================ GPTimer end =================================== + */ + + + +/* + * ============================= PWM begin ==================================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(PWM_config, ".const:PWM_config") +#pragma DATA_SECTION(pwmtimerCC26xxHWAttrs, ".const:pwmtimerCC26xxHWAttrs") +#endif + +/* PWM configuration, one per PWM output. */ +PWMTimerCC26XX_HwAttrs pwmtimerCC26xxHWAttrs[CC2650DK_7ID_PWMCOUNT] = { + { .pwmPin = Board_PWMPIN0, .gpTimerUnit = Board_GPTIMER0A }, + { .pwmPin = Board_PWMPIN1, .gpTimerUnit = Board_GPTIMER0B }, + { .pwmPin = Board_PWMPIN2, .gpTimerUnit = Board_GPTIMER1A }, + { .pwmPin = Board_PWMPIN3, .gpTimerUnit = Board_GPTIMER1B }, + { .pwmPin = Board_PWMPIN4, .gpTimerUnit = Board_GPTIMER2A }, + { .pwmPin = Board_PWMPIN5, .gpTimerUnit = Board_GPTIMER2B }, + { .pwmPin = Board_PWMPIN6, .gpTimerUnit = Board_GPTIMER3A }, + { .pwmPin = Board_PWMPIN7, .gpTimerUnit = Board_GPTIMER3B }, +}; + +/* PWM object, one per PWM output */ +PWMTimerCC26XX_Object pwmtimerCC26xxObjects[CC2650DK_7ID_PWMCOUNT]; + +extern const PWM_FxnTable PWMTimerCC26XX_fxnTable; + +/* PWM configuration (used as PWM_Handle by driver and application) */ +const PWM_Config PWM_config[CC2650DK_7ID_PWMCOUNT + 1] = { + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[0], &pwmtimerCC26xxHWAttrs[0] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[1], &pwmtimerCC26xxHWAttrs[1] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[2], &pwmtimerCC26xxHWAttrs[2] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[3], &pwmtimerCC26xxHWAttrs[3] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[4], &pwmtimerCC26xxHWAttrs[4] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[5], &pwmtimerCC26xxHWAttrs[5] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[6], &pwmtimerCC26xxHWAttrs[6] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[7], &pwmtimerCC26xxHWAttrs[7] }, + { NULL, NULL, NULL } +}; + + +/* + * ============================= PWM end ====================================== + */ + +/* + * ========================== ADCBuf begin ========================================= + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(ADCBuf_config, ".const:ADCBuf_config") +#pragma DATA_SECTION(adcBufCC26xxHWAttrs, ".const:adcBufCC26xxHWAttrs") +#pragma DATA_SECTION(ADCBufCC26XX_adcChannelLut, ".const:ADCBufCC26XX_adcChannelLut") +#endif + +/* Include drivers */ +#include +#include + +/* ADC objects */ +ADCBufCC26XX_Object adcBufCC26xxObjects[CC2650DK_7ID_ADCBufCOUNT]; + +/* + * This table converts a virtual adc channel into a dio and internal analogue input signal. + * This table is necessary for the functioning of the adcBuf driver. + * Comment out unused entries to save flash. + * Dio and internal signal pairs are hardwired. Do not remap them in the table. You may reorder entire entries though. + * The mapping of dio and internal signals is package dependent. + */ +const ADCBufCC26XX_AdcChannelLutEntry ADCBufCC26XX_adcChannelLut[] = { + {Board_ALS_OUT, ADC_COMPB_IN_AUXIO7}, + {PIN_UNASSIGNED, ADC_COMPB_IN_DCOUPL}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VSS}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VDDS} +}; + +const ADCBufCC26XX_HWAttrs adcBufCC26xxHWAttrs[CC2650DK_7ID_ADCBufCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + .adcChannelLut = ADCBufCC26XX_adcChannelLut, + .gpTimerUnit = Board_GPTIMER0A, + .gptDMAChannelMask = 1 << UDMA_CHAN_TIMER0_A, + } +}; + +const ADCBuf_Config ADCBuf_config[] = { + {&ADCBufCC26XX_fxnTable, &adcBufCC26xxObjects[0], &adcBufCC26xxHWAttrs[0]}, + {NULL, NULL, NULL}, +}; +/* + * ========================== ADCBuf end ========================================= + */ + + /* + * ========================== ADC begin ========================================= + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(ADC_config, ".const:ADC_config") +#pragma DATA_SECTION(adcCC26xxHWAttrs, ".const:adcCC26xxHWAttrs") +#endif + +/* Include drivers */ +#include +#include + +/* ADC objects */ +ADCCC26XX_Object adcCC26xxObjects[CC2650DK_7ID_ADCCOUNT]; + + +const ADCCC26XX_HWAttrs adcCC26xxHWAttrs[CC2650DK_7ID_ADCCOUNT] = { + { + .adcDIO = Board_DIO23_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO7, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_DCOUPL, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VSS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VDDS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + } +}; + +const ADC_Config ADC_config[] = { + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[0], &adcCC26xxHWAttrs[0]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[1], &adcCC26xxHWAttrs[1]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[2], &adcCC26xxHWAttrs[2]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[3], &adcCC26xxHWAttrs[3]}, + {NULL, NULL, NULL}, +}; + +/* + * ========================== ADC end ========================================= + */ + +/* + * =============================== Watchdog =============================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(Watchdog_config, ".const:Watchdog_config") +#pragma DATA_SECTION(watchdogCC26XXHWAttrs, ".const:watchdogCC26XXHWAttrs") +#endif + +#include +#include + +WatchdogCC26XX_Object watchdogCC26XXObjects[CC2650DK_7ID_WATCHDOGCOUNT]; + +const WatchdogCC26XX_HWAttrs watchdogCC26XXHWAttrs[CC2650DK_7ID_WATCHDOGCOUNT] = { + { + .baseAddr = WDT_BASE, + .intNum = INT_WDT_IRQ, + .reloadValue = 1000 /* Reload value in milliseconds */ + }, +}; + +const Watchdog_Config Watchdog_config[] = { + { + .fxnTablePtr = &WatchdogCC26XX_fxnTable, + .object = &watchdogCC26XXObjects[0], + .hwAttrs = &watchdogCC26XXHWAttrs[0] + }, + {NULL, NULL, NULL}, +}; + +/* + * ======== CC26XX_LAUNCHXL_initWatchdog ======== + */ +void CC26XX_LAUNCHXL_initWatchdog(void) +{ + Watchdog_init(); +} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h new file mode 100644 index 000000000..07b7573ae --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2015-2016, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ +/** ============================================================================ + * @file CC2650DK_7ID.h + * + * @brief CC2650EM_7ID Board Specific header file. + * The project options should point to this file if this is the + * CC2650EM you are developing code for. + * + * The CC2650 header file should be included in an application as follows: + * @code + * #include + * @endcode + * + * ============================================================================ + */ +#ifndef __CC2650EM_7ID_H__ +#define __CC2650EM_7ID_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** ============================================================================ + * Symbol by generic Board.c to include the correct kit specific Board.c + * ==========================================================================*/ +#define CC2650EM_7ID +#define CC2650DK_7ID + + +/** ============================================================================ + * Includes + * ==========================================================================*/ +#include +#include + +/** ============================================================================ + * Externs + * ==========================================================================*/ +extern const PIN_Config BoardGpioInitTable[]; + +/** ============================================================================ + * Defines + * ==========================================================================*/ + +/* Mapping of pins to board signals using general board aliases + * + */ +/* Leds */ +#define Board_LED_ON 1 /* LEDs on SmartRF06 EB are active high */ +#define Board_LED_OFF 0 +#define Board_DK_LED1 IOID_25 /* P2.11 */ +#define Board_DK_LED2 IOID_27 /* P2.13 */ +#define Board_DK_LED3 IOID_7 /* P1.2 */ +#define Board_DK_LED4 IOID_6 /* P1.4 */ +/* Button Board */ +#define Board_KEY_SELECT IOID_11 /* P1.14 */ +#define Board_KEY_UP IOID_19 /* P1.10 */ +#define Board_KEY_DOWN IOID_12 /* P1.12 */ +#define Board_KEY_LEFT IOID_15 /* P1.6 */ +#define Board_KEY_RIGHT IOID_18 /* P1.8 */ +/* LCD Board */ +#define Board_LCD_MODE IOID_4 /* P1.11 */ +#define Board_LCD_RST IOID_5 /* P1.13 */ +#define Board_LCD_CSN IOID_14 /* P1.17 */ +/* UART Board */ +#define Board_UART_RX IOID_2 /* P1.7 */ +#define Board_UART_TX IOID_3 /* P1.9 */ +#define Board_UART_CTS IOID_0 /* P1.3 */ +#define Board_UART_RTS IOID_21 /* P2.18 */ +/* SPI Board */ +#define Board_SPI0_MISO IOID_8 /* P1.20 */ +#define Board_SPI0_MOSI IOID_9 /* P1.18 */ +#define Board_SPI0_CLK IOID_10 /* P1.16 */ +#define Board_SPI0_CSN PIN_UNASSIGNED /* P1.14, separate CSn for LCD, SDCARD, and ACC */ +#define Board_SPI1_MISO IOID_24 /* RF2.10 for testing only */ +#define Board_SPI1_MOSI IOID_23 /* RF2.5 for testing only */ +#define Board_SPI1_CLK IOID_30 /* RF2.12 for testing only */ +#define Board_SPI1_CSN PIN_UNASSIGNED /* RF2.6 for testing only */ +/* Ambient Light Sensor */ +#define Board_ALS_OUT IOID_23 /* P2.5 */ +#define Board_ALS_PWR IOID_26 /* P2.6 */ +/* Accelerometer */ +#define Board_ACC_PWR IOID_20 /* P2.8 */ +#define Board_ACC_CSN IOID_24 /* P2.10 */ +/* SD Card */ +#define Board_SDCARD_CSN IOID_30 /* P2.12 */ +/* Power Board */ +#define Board_3V3_EN IOID_13 /* P1.15 */ +/* PWM outputs */ +#define Board_PWMPIN0 Board_DK_LED1 +#define Board_PWMPIN1 Board_DK_LED2 +#define Board_PWMPIN2 PIN_UNASSIGNED +#define Board_PWMPIN3 PIN_UNASSIGNED +#define Board_PWMPIN4 PIN_UNASSIGNED +#define Board_PWMPIN5 PIN_UNASSIGNED +#define Board_PWMPIN6 PIN_UNASSIGNED +#define Board_PWMPIN7 PIN_UNASSIGNED +/* Analog capable DIO's */ +#define Board_DIO23_ANALOG IOID_23 +#define Board_DIO24_ANALOG IOID_24 +#define Board_DIO25_ANALOG IOID_25 +#define Board_DIO26_ANALOG IOID_26 +#define Board_DIO27_ANALOG IOID_27 +#define Board_DIO28_ANALOG IOID_28 +#define Board_DIO29_ANALOG IOID_29 +#define Board_DIO30_ANALOG IOID_30 + +/** ============================================================================ + * Instance identifiers + * ==========================================================================*/ +/* Generic SPI instance identifiers */ +#define Board_SPI0 CC2650DK_7ID_SPI0 +#define Board_SPI1 CC2650DK_7ID_SPI1 +/* Generic UART instance identifiers */ +#define Board_UART CC2650DK_7ID_UART0 +/* Generic Crypto instance identifiers */ +#define Board_CRYPTO CC2650DK_7ID_CRYPTO0 +/* Generic GPTimer instance identifiers */ +#define Board_GPTIMER0A CC2650DK_7ID_GPTIMER0A +#define Board_GPTIMER0B CC2650DK_7ID_GPTIMER0B +#define Board_GPTIMER1A CC2650DK_7ID_GPTIMER1A +#define Board_GPTIMER1B CC2650DK_7ID_GPTIMER1B +#define Board_GPTIMER2A CC2650DK_7ID_GPTIMER2A +#define Board_GPTIMER2B CC2650DK_7ID_GPTIMER2B +#define Board_GPTIMER3A CC2650DK_7ID_GPTIMER3A +#define Board_GPTIMER3B CC2650DK_7ID_GPTIMER3B +/* Generic PWM instance identifiers */ +#define Board_PWM0 CC2650DK_7ID_PWM0 +#define Board_PWM1 CC2650DK_7ID_PWM1 +#define Board_PWM2 CC2650DK_7ID_PWM2 +#define Board_PWM3 CC2650DK_7ID_PWM3 +#define Board_PWM4 CC2650DK_7ID_PWM4 +#define Board_PWM5 CC2650DK_7ID_PWM5 +#define Board_PWM6 CC2650DK_7ID_PWM6 +#define Board_PWM7 CC2650DK_7ID_PWM7 + +/** ============================================================================ + * Number of peripherals and their names + * ==========================================================================*/ + +/*! + * @def CC2650DK_7ID_CryptoName + * @brief Enum of Crypto names on the CC2650 dev board + */ +typedef enum CC2650DK_7ID_CryptoName { + CC2650DK_7ID_CRYPTO0 = 0, + CC2650DK_7ID_CRYPTOCOUNT +} CC2650DK_7ID_CryptoName; + +/*! + * @def CC2650DK_7ID_SPIName + * @brief Enum of SPI names on the CC2650 dev board + */ +typedef enum CC2650DK_7ID_SPIName { + CC2650DK_7ID_SPI0 = 0, + CC2650DK_7ID_SPI1, + CC2650DK_7ID_SPICOUNT +} CC2650DK_7ID_SPIName; + +/*! + * @def CC2650DK_7ID_UARTName + * @brief Enum of UARTs on the CC2650 dev board + */ +typedef enum CC2650DK_7ID_UARTName { + CC2650DK_7ID_UART0 = 0, + CC2650DK_7ID_UARTCOUNT +} CC2650DK_7ID_UARTName; + +/*! + * @def CC2650DK_7ID_UdmaName + * @brief Enum of DMA buffers + */ +typedef enum CC2650DK_7ID_UdmaName { + CC2650DK_7ID_UDMA0 = 0, + CC2650DK_7ID_UDMACOUNT +} CC2650DK_7ID_UdmaName; + +/*! + * @def CC2650DK_7ID_GPTimerName + * @brief Enum of GPTimer parts + */ +typedef enum CC2650DK_7ID_GPTimerName +{ + CC2650DK_7ID_GPTIMER0A = 0, + CC2650DK_7ID_GPTIMER0B, + CC2650DK_7ID_GPTIMER1A, + CC2650DK_7ID_GPTIMER1B, + CC2650DK_7ID_GPTIMER2A, + CC2650DK_7ID_GPTIMER2B, + CC2650DK_7ID_GPTIMER3A, + CC2650DK_7ID_GPTIMER3B, + CC2650DK_7ID_GPTIMERPARTSCOUNT +} CC2650DK_7ID_GPTimerName; + +/*! + * @def CC2650DK_7ID_GPTimers + * @brief Enum of GPTimers + */ +typedef enum CC2650DK_7ID_GPTimers +{ + CC2650DK_7ID_GPTIMER0 = 0, + CC2650DK_7ID_GPTIMER1, + CC2650DK_7ID_GPTIMER2, + CC2650DK_7ID_GPTIMER3, + CC2650DK_7ID_GPTIMERCOUNT +} CC2650DK_7ID_GPTimers; + +/*! + * @def CC2650DK_7ID_PWM + * @brief Enum of PWM outputs on the board + */ +typedef enum CC2650DK_7ID_PWM +{ + CC2650DK_7ID_PWM0 = 0, + CC2650DK_7ID_PWM1, + CC2650DK_7ID_PWM2, + CC2650DK_7ID_PWM3, + CC2650DK_7ID_PWM4, + CC2650DK_7ID_PWM5, + CC2650DK_7ID_PWM6, + CC2650DK_7ID_PWM7, + CC2650DK_7ID_PWMCOUNT +} CC2650DK_7ID_PWM; + +/*! + * @def CC2650DK_7ID_ADCBufName + * @brief Enum of ADCBufs + */ +typedef enum CC2650DK_7ID_ADCBufName { + CC2650DK_7ID_ADCBuf0 = 0, + CC2650DK_7ID_ADCBufCOUNT +} CC2650DK_7ID_ADCBufName; + +/*! + * @def CC2650DK_7ID_ADCName + * @brief Enum of ADCs + */ +typedef enum CC2650DK_7ID_ADCName { + CC2650DK_7ID_ADCALS = 0, + CC2650DK_7ID_ADCDCOUPL, + CC2650DK_7ID_ADCVSS, + CC2650DK_7ID_ADCVDDS, + CC2650DK_7ID_ADCCOUNT +} CC2650DK_7ID_ADCName; + +/*! + * @def CC2650DK_7ID_WatchdogName + * @brief Enum of Watchdogs on the CC2650DK_7ID dev board + */ +typedef enum CC2650DK_7ID_WatchdogName { + CC2650DK_7ID_WATCHDOG0 = 0, + + CC2650DK_7ID_WATCHDOGCOUNT +} CC2650DK_7ID_WatchdogName; + +#ifdef __cplusplus +} +#endif + +#endif /* __CC2650EM_H__ */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Makefile.cc26x0 b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Makefile.cc26x0 new file mode 100644 index 000000000..372d2103d --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Makefile.cc26x0 @@ -0,0 +1,16 @@ +################################################################################ +# SimpleLink Device makefile + +SUBFAMILY = cc13x0-cc26x0 +DEVICE_FAMILY = CC26X0 + +BOARD_SOURCEFILES += CC2650DK_7ID.c + +SUPPORTS_PROP_MODE = 1 +SUPPORTS_IEEE_MODE = 1 + +### Signal that we can be programmed with cc2538-bsl +BOARD_SUPPORTS_BSL = 1 + +# Include the common board makefile +include $(FAMILY_PATH)/srf06/Makefile.srf06 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/leds-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/leds-arch.c new file mode 100644 index 000000000..2a1627005 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/leds-arch.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup srf06-common-peripherals + * @{ + * + * \file + * Driver for the SmartRF06EB LEDs when a CC13xx/CC26xx EM is mounted on it + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "dev/leds.h" +#include "ti-lib.h" +/*---------------------------------------------------------------------------*/ +static unsigned char c; +static int inited = 0; +/*---------------------------------------------------------------------------*/ +void +leds_arch_init(void) +{ + if(inited) { + return; + } + inited = 1; + + ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_LED_1); + ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_LED_2); + ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_LED_3); + ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_LED_4); + + ti_lib_gpio_clear_multi_dio(BOARD_LED_ALL); +} +/*---------------------------------------------------------------------------*/ +unsigned char +leds_arch_get(void) +{ + return c; +} +/*---------------------------------------------------------------------------*/ +void +leds_arch_set(unsigned char leds) +{ + c = leds; + + /* Clear everything */ + ti_lib_gpio_clear_multi_dio(BOARD_LED_ALL); + + if((leds & LEDS_RED) == LEDS_RED) { + ti_lib_gpio_set_dio(BOARD_IOID_LED_1); + } + if((leds & LEDS_YELLOW) == LEDS_YELLOW) { + ti_lib_gpio_set_dio(BOARD_IOID_LED_2); + } + if((leds & LEDS_GREEN) == LEDS_GREEN) { + ti_lib_gpio_set_dio(BOARD_IOID_LED_3); + } + if((leds & LEDS_ORANGE) == LEDS_ORANGE) { + ti_lib_gpio_set_dio(BOARD_IOID_LED_4); + } +} +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13x0-cc26x0/srf06/srf06-sensors.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/srf06-sensors.c similarity index 100% rename from arch/platform/simplelink/cc13x0-cc26x0/srf06/srf06-sensors.c rename to arch/platform/simplelink/cc13xx-cc26xx/srf06/srf06-sensors.c diff --git a/arch/platform/simplelink/cc13x2-cc26x2/launchpad/leds-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/srf06.c similarity index 53% rename from arch/platform/simplelink/cc13x2-cc26x2/launchpad/leds-arch.c rename to arch/platform/simplelink/cc13xx-cc26xx/srf06/srf06.c index 7595d47d3..119f77994 100644 --- a/arch/platform/simplelink/cc13x2-cc26x2/launchpad/leds-arch.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/srf06.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,106 +29,84 @@ */ /*---------------------------------------------------------------------------*/ /** - * \addtogroup simplelink-platform + * \addtogroup srf06-common-peripherals * @{ * * \file - * Driver for LaunchPad LEDs + * Board-initialisation for the Srf06EB with a CC13xx/CC26xx EM. */ /*---------------------------------------------------------------------------*/ -/* Contiki API */ -#include -#include -/*---------------------------------------------------------------------------*/ -/* Simplelink SDK API */ -#include -#include -/*---------------------------------------------------------------------------*/ -/* Standard library */ -#include +#include "contiki.h" +#include "ti-lib.h" +#include "lpm.h" +#include "prcm.h" +#include "hw_sysctl.h" + #include +#include /*---------------------------------------------------------------------------*/ -/* Available LED configuration */ - -/* Green LED */ -#ifdef Board_GPIO_GLED -# define LEDS_ARCH_GREEN Board_GPIO_GLED -#endif - -/* Yellow LED */ -#ifdef Board_GPIO_YLED -# define LEDS_ARCH_YELLOW Board_GPIO_YLED -#endif - -/* Red LED */ -#ifdef Board_GPIO_RLED -# define LEDS_ARCH_RED Board_GPIO_RLED -#endif - -/* Blue LED */ -#ifdef Board_GPIO_BLED -# define LEDS_ARCH_BLUE Board_GPIO_BLED -#endif +static void +lpm_handler(uint8_t mode) +{ + /* Ambient light sensor (off, output low) */ + ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_ALS_PWR); + ti_lib_gpio_clear_dio(BOARD_IOID_ALS_PWR); + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_ALS_OUT); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_ALS_OUT, IOC_NO_IOPULL); +} /*---------------------------------------------------------------------------*/ -static unsigned char c; +static void +wakeup_handler(void) +{ + /* Turn on the PERIPH PD */ + ti_lib_prcm_power_domain_on(PRCM_DOMAIN_PERIPH); + while((ti_lib_prcm_power_domain_status(PRCM_DOMAIN_PERIPH) + != PRCM_DOMAIN_POWER_ON)); +} +/*---------------------------------------------------------------------------*/ +/* + * Declare a data structure to register with LPM. + * We don't care about what power mode we'll drop to, we don't care about + * getting notified before deep sleep. All we need is to be notified when we + * wake up so we can turn power domains back on + */ +LPM_MODULE(srf_module, NULL, lpm_handler, wakeup_handler, LPM_DOMAIN_NONE); +/*---------------------------------------------------------------------------*/ +static void +configure_unused_pins(void) +{ + /* Turn off 3.3-V domain (lcd/sdcard power, output low) */ + ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_3V3_EN); + ti_lib_gpio_clear_dio(BOARD_IOID_3V3_EN); + + /* Accelerometer (PWR output low, CSn output, high) */ + ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_ACC_PWR); + ti_lib_gpio_clear_dio(BOARD_IOID_ACC_PWR); +} /*---------------------------------------------------------------------------*/ void -leds_arch_init(void) +board_init() { - static bool bHasInit = false; - if(bHasInit) { - return; + uint8_t int_disabled = ti_lib_int_master_disable(); + + /* Turn on relevant PDs */ + wakeup_handler(); + + /* Enable GPIO peripheral */ + ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_GPIO); + + /* Apply settings and wait for them to take effect */ + ti_lib_prcm_load_set(); + while(!ti_lib_prcm_load_get()); + + lpm_register_module(&srf_module); + + configure_unused_pins(); + + /* Re-enable interrupt if initially enabled. */ + if(!int_disabled) { + ti_lib_int_master_enable(); } - bHasInit = true; - - // GPIO_init will most likely be called in platform.c, - // but call it here to be sure GPIO is initialized. - // Calling GPIO_init multiple times is safe. - GPIO_init(); -} -/*---------------------------------------------------------------------------*/ -unsigned char -leds_arch_get(void) -{ - return c; -} -/*---------------------------------------------------------------------------*/ -static inline void -write_led(const bool on, const uint_fast32_t gpioLed) -{ - const GPIO_PinConfig pinCfg = (on) - ? Board_GPIO_LED_ON : Board_GPIO_LED_OFF; - GPIO_write(gpioLed, pinCfg); -} -/*---------------------------------------------------------------------------*/ -void -leds_arch_set(unsigned char leds) -{ - c = leds; - -#define LED_ON(led_define) ((leds & (led_define)) == (led_define)) - - // Green LED -#ifdef LEDS_ARCH_GREEN - write_led(LED_ON(LEDS_GREEN), LEDS_ARCH_GREEN); -#endif - - // Yellow LED -#ifdef LEDS_ARCH_YELLOW - write_led(LED_ON(LEDS_YELLOW), LEDS_ARCH_YELLOW); -#endif - - // Red LED -#ifdef LEDS_ARCH_RED - write_led(LED_ON(LEDS_RED), LEDS_ARCH_RED); -#endif - - // Blue LED -#ifdef LEDS_ARCH_BLUE - write_led(LED_ON(LEDS_BLUE), LEDS_ARCH_BLUE); -#endif - -#undef LED_ON } /*---------------------------------------------------------------------------*/ /** @} */ From 745c2b24b6fbb526e2e39d349517fafbff7b1f03 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Wed, 30 May 2018 12:21:54 +0200 Subject: [PATCH 246/485] Fixed RF settings and Board files --- arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 22 +- arch/cpu/cc13xx-cc26xx/Makefile.cc26x0 | 73 - arch/cpu/cc13xx-cc26xx/Makefile.simplelink | 108 -- .../Makefile.cc13x0-cc26x0 | 0 .../rf-settings/rf-ieee-settings.h | 26 - .../rf-settings/rf-prop-settings.c | 276 ---- .../rf-settings/rf-prop-settings.h | 35 - .../Makefile.cc13x2-cc26x2 | 0 arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c | 22 +- arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c | 2 +- .../rf-settings/cc13x0/ieee-settings.c | 237 ++++ .../rf-settings/cc13x0/ieee-settings.h | 38 + .../rf-settings/cc13x0/prop-settings.c | 258 ++++ .../rf-settings/cc13x0/prop-settings.h | 34 + .../rf-settings/cc13x2/ieee-settings.c | 280 ++++ .../rf-settings/cc13x2/ieee-settings.h | 40 + .../rf-settings/cc13x2/prop-settings.c | 318 +++++ .../rf-settings/cc13x2/prop-settings.h | 40 + .../cc26x0/ieee-settings.c} | 212 ++- .../rf-settings/cc26x0/ieee-settings.h | 37 + .../rf-settings/cc26x2/ieee-settings.c | 216 +++ .../rf-settings/cc26x2/ieee-settings.h | 38 + .../simplelink/Makefile.device-family | 79 -- .../cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 14 +- .../launchpad/cc1310/Makefile.cc1310 | 2 + .../launchpad/cc1312r1/Makefile.cc1312r1 | 2 + .../launchpad/cc1350-4/Makefile.cc1350-4 | 2 + .../launchpad/cc1350/Makefile.cc1350 | 2 + .../launchpad/cc1352p1/Makefile.cc1352p1 | 2 + .../launchpad/cc1352r1/Makefile.cc1352r1 | 2 + .../cc13xx-cc26xx/launchpad/cc2650/Board.h | 124 +- .../launchpad/cc2650/CC2650_LAUNCHXL.c | 1239 +++++++++-------- .../launchpad/cc2650/CC2650_LAUNCHXL.h | 454 +++--- .../launchpad/cc2650/Makefile.cc2650 | 4 +- .../cc13xx-cc26xx/launchpad/cc26x2r1/Board.h | 2 + .../launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c | 120 +- .../launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h | 4 + .../launchpad/cc26x2r1/Makefile.cc26x2r1 | 4 +- .../sensortag/cc1350/Makefile.cc1350 | 2 + .../sensortag/cc2650/Makefile.cc2650 | 4 +- .../srf06/cc13x0/Makefile.cc13x0 | 2 + .../srf06/cc26x0/Makefile.cc26x0 | 4 +- 42 files changed, 2737 insertions(+), 1643 deletions(-) delete mode 100644 arch/cpu/cc13xx-cc26xx/Makefile.cc26x0 delete mode 100644 arch/cpu/cc13xx-cc26xx/Makefile.simplelink rename arch/cpu/cc13xx-cc26xx/{ => cc13x0-cc26x0}/Makefile.cc13x0-cc26x0 (100%) delete mode 100644 arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-ieee-settings.h delete mode 100644 arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-prop-settings.c delete mode 100644 arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-prop-settings.h rename arch/cpu/cc13xx-cc26xx/{ => cc13x2-cc26x2}/Makefile.cc13x2-cc26x2 (100%) create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h rename arch/cpu/cc13xx-cc26xx/{cc13x0-cc26x0/rf-settings/rf-ieee-settings.c => rf-settings/cc26x0/ieee-settings.c} (70%) create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h delete mode 100644 arch/platform/simplelink/Makefile.device-family diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index b0b5e1822..9dcc5d91c 100644 --- a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -23,14 +23,14 @@ DEVICE_DEFINE := $(shell cat $(DEVICE_FAMILY_H) \ # Else, it points to a sub-name of the device family, e.g. DeviceFamily_ID_CC13X2_V1. # This line checks if the extracted define is a number or not, based on this SO post: # https://stackoverflow.com/a/19116862/5099169 -IS_NUMBER := $(shell if [ "$(DEVICE_DEFINE)" -eq "$(DEVICE_DEFINE)" ] 2>/dev/null; then echo 1 ; else echo 0 ; fi) +# Return value 0 is no error, i.e. is a number. +IS_NUMBER := $(shell [ "$(DEVICE_DEFINE)" -eq "$(DEVICE_DEFINE)" ] 2>/dev/null; echo $$?) -ifeq ($(IS_NUMBER),1) +ifeq ($(IS_NUMBER),0) # The define points to a number, meaning the device family name is the same as the # specified device name in lower case, e.g. # cc13x2 - DEVICE_FAMILY_NAME := $(shell echo "$(DEVICE_FAMILY)" \ - | tr A-Z a-z) + DEVICE_FAMILY_NAME := $(DEVICE_FAMILY_LC) else # The define points to a sub-name of the device family. The resulting device family name # is therefore the name after specified after ID in lower case, e.g. @@ -72,12 +72,18 @@ CONTIKI_CPU_SOURCEFILES += watchdog-arch.c putchar-arch.c CONTIKI_CPU_SOURCEFILES += uart0-arch.c slip-arch.c CONTIKI_CPU_SOURCEFILES += batmon-sensor.c CONTIKI_CPU_SOURCEFILES += rf-common.c -CONTIKI_CPU_SOURCEFILES += rf-prop-mode.c rf-prop-settings.c -CONTIKI_CPU_SOURCEFILES += rf-ieee-mode.c rf-ieee-settings.c CONTIKI_CPU_SOURCEFILES += ieee-addr.c +ifeq ($(SUPPORTS_PROP_MODE),1) +CONTIKI_CPU_SOURCEFILES += rf-prop-mode.c prop-settings.c +endif + +ifeq ($(SUPPORTS_IEEE_MODE),1) +CONTIKI_CPU_SOURCEFILES += rf-ieee-mode.c ieee-settings.c +endif + ### CPU-dependent directories -CONTIKI_CPU_DIRS += . dev $(SUBFAMILY) $(SUBFAMILY)/rf-settings +CONTIKI_CPU_DIRS += . dev $(SUBFAMILY) rf-settings/$(DEVICE_FAMILY_LC) ### CPU-dependent debug source files ### CONTIKI_ARM_DIRS populated by Makefile.arm @@ -110,4 +116,4 @@ $(OBJECTDIR)/ccfg.o: ccfg.c FORCE | $(OBJECTDIR) $(TRACE_CC) $(Q)$(CC) $(CFLAGS) -include "ccfg-conf.h" -c $< -o $@ -include $(CONTIKI_CPU)/Makefile.$(SUBFAMILY) +include $(CONTIKI_CPU)/$(SUBFAMILY)/Makefile.$(SUBFAMILY) diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.cc26x0 b/arch/cpu/cc13xx-cc26xx/Makefile.cc26x0 deleted file mode 100644 index 61cd5c304..000000000 --- a/arch/cpu/cc13xx-cc26xx/Makefile.cc26x0 +++ /dev/null @@ -1,73 +0,0 @@ -################################################################################ -# CC13xx/CC26xx CPU makefile - -include $(CONTIKI_CPU)/Makefile.$(SUBFAMILY) - -EXTERNALDIRS += $(SDK_SOURCE) -EXTERNALDIRS += $(SDK_KERNEL) -EXTERNALDIRS += $(SDK_KERNEL)/startup -EXTERNALDIRS += $(SDK_BOARD_PATH) -EXTERNALDIRS += $(SDK_DEVICE) - -# ccfg.c comes from the board-specific folder, and startup_cc13xx_cc26xx_gcc.c -# comes from NoRTOS startup folder -#CPU_START_SOURCEFILES += ccfg.c startup_cc13xx_cc26xx_gcc.c - - -### If the user-specified a Node ID, pass a define -ifdef NODEID -DEFINES += IEEE_ADDR_NODE_ID=$(NODEID) -endif - -### CPU-dependent source files -CONTIKI_CPU_SOURCEFILES += rtimer-arch.c clock-arch.c -CONTIKI_CPU_SOURCEFILES += watchdog-arch.c putchar-arch.c -CONTIKI_CPU_SOURCEFILES += uart0-arch.c slip-arch.c -CONTIKI_CPU_SOURCEFILES += batmon-sensor.c -CONTIKI_CPU_SOURCEFILES += rf-common.c -CONTIKI_CPU_SOURCEFILES += rf-prop-mode.c rf-prop-settings.c -CONTIKI_CPU_SOURCEFILES += rf-ieee-mode.c rf-ieee-settings.c -CONTIKI_CPU_SOURCEFILES += ieee-addr.c - -### CPU-dependent directories -CONTIKI_CPU_DIRS += $(addprefix ../arm/, $(CPU_DIRS)) -CONTIKI_CPU_DIRS += . dev rf-settings cc13x2-cc26x2 - -### CPU-dependent debug source files -DEBUG_IO_SOURCEFILES += dbg-printf.c dbg-snprintf.c dbg-sprintf.c strformat.c - -CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES) $(DEBUG_IO_SOURCEFILES) - -### Simplelink SDK pre-compiled libraries -TARGET_LIBFILES += $(SDK_KERNEL)/lib/nortos_$(DEVICE_FAMILY_NAME).am4fg -TARGET_LIBFILES += $(SDK_DRIVERS)/rf/lib/rf_multiMode_$(DEVICE_FAMILY_NAME).am4fg -TARGET_LIBFILES += $(SDK_DRIVERS)/lib/drivers_$(DEVICE_FAMILY_NAME).am4fg -TARGET_LIBFILES += $(SDK_DEVICE)/driverlib/bin/gcc/driverlib.lib - -### Linker flag -LDFLAGS += --entry resetISR -LDFLAGS += -static -LDFLAGS += --specs=nano.specs -# NB! The symbol _stack, which points to the stack start, is expected to be defined, -# but should already be defined in the linker script. -LDFLAGS += -Wl,--defsym=_stack_origin=__stack_end -LDFLAGS += -Wl,--defsym=_heap=__heap_start__ -LDFLAGS += -Wl,--defsym=_eheap=__heap_end__ - -LDSCRIPT := $(CONTIKI_CPU)/$(SUBFAMILY)/$(SUBFAMILY).lds - -### Always re-build ieee-addr.o in case the command line passes a new NODEID -FORCE: - -$(OBJECTDIR)/ieee-addr.o: ieee-addr.c FORCE | $(OBJECTDIR) - $(TRACE_CC) - $(Q)$(CC) $(CFLAGS) -c $< -o $@ - -### Always re-build ccfg.c so changes to ccfg-conf.h will apply without having -### to make clean first -$(OBJECTDIR)/ccfg.o: ccfg.c FORCE | $(OBJECTDIR) - $(TRACE_CC) - $(Q)$(CC) $(CFLAGS) -include "ccfg-conf.h" -c $< -o $@ - - -include $(CONTIKI)/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.simplelink b/arch/cpu/cc13xx-cc26xx/Makefile.simplelink deleted file mode 100644 index 4036246ee..000000000 --- a/arch/cpu/cc13xx-cc26xx/Makefile.simplelink +++ /dev/null @@ -1,108 +0,0 @@ - -MODULES += os/net/mac/framer - -CPU_ABS_PATH = $(CONTIKI)/arch/cpu/cc13xx-cc26xx - -SDK_SOURCE := $(SIMPLELINK_SDK)/source -# TODO fix switch -SDK_DEVICES := $(SDK_SOURCE)/ti/devices -SDK_DEVICE := $(shell ls $(SDK_DEVICES) | grep $(SIMPLELINK_DEVICE)) -SDK_DEVICE_SOURCE := $(SDK_SOURCE)/ti/devices/$(SDK_DEVICE) -SDK_DRIVERLIB := $(SDK_DEVICE_SOURCE)/driverlib -SDK_DRIVERS := $(SDK_SOURCE)/ti/drivers -SDK_KERNEL := $(SIMPLELINK_SDK)/kernel/nortos -SDK_BOARDS := $(SDK_SOURCE)/ti/boards -SDK_STARTUP := $(SDK_DEVICE_SOURCE)/startup_files -SDK_STARTUP_SRCS := ccfg.c - -EXTERNALDIRS += $(SDK_STARTUP) - - -### MODULES will add some of these to the include path, but we need to add -### them earlier to prevent filename clashes with Contiki core files -CFLAGS += -I$(CPU_ABS_PATH) -CFLAGS += -I$(CPU_ABS_PATH)/source -CFLAGS += -I$(SDK_SOURCE) -CFLAGS += -I$(SDK_DEVICE_SOposixURCE) -CFLAGS += -I$(SDK_DEVICE_SOURCE)/inc -CFLAGS += -I$(SDK_KERNEL) -CFLAGS += -I$(SDK_KERNEL)/ - -LDFLAGS += --entry resetISR -LDFLAGS += -static -LDFLAGS += --specs=nano.specs -# NB! The symbol _stack, pointing to the stack start, is expected, -# but should already be defined in the linker script. -LDFLAGS += -Wl,--defsym=_stack_origin=__stack_end -LDFLAGS += -Wl,--defsym=_heap=__heap_start__ -LDFLAGS += -Wl,--defsym=_eheap=__heap_end__ - -ifneq ($(SIMPLELINK_BOARD),CUSTOM) - SDK_BOARDS := $(SDK_SOURCE)/ti/boards - LDSCRIPT = $(SDK_BOARDS)/$(SIMPLELINK_BOARD)/$(SIMPLELINK_BOARD)_NoRTOS.lds - CFLAGS += -I$(SDK_BOARDS)/$(SIMPLELINK_BOARD) - CONTIKI_SOURCEFILES += $(SIMPLELINK_BOARD).c -else - ifndef $(LDSCRIPT) - $(error You must speficy a custom linker script in LDSCRIPT.) - endif -endif - - -### If the user-specified a Node ID, pass a define -ifdef NODEID - CFLAGS += -DIEEE_ADDR_NODE_ID=$(NODEID) -endif - -### CPU-dependent directories -CONTIKI_ARM_DIRS += . common/dbg-io -CONTIKI_CPU_DIRS += . $(addprefix ../arm/, $(CPU_DIRS)) -CONTIKI_CPU_DIRS += dev rf-settings - -### CPU-dependent source files -CONTIKI_CPU_SOURCEFILES += rtimer-arch.c clock-arch.c -CONTIKI_CPU_SOURCEFILES += watchdog-arch.c putchar-arch.c -CONTIKI_CPU_SOURCEFILES += uart0-arch.c slip-arch.c -CONTIKI_CPU_SOURCEFILES += rf-common.c -CONTIKI_CPU_SOURCEFILES += rf-prop-mode.c rf-prop-settings.c -CONTIKI_CPU_SOURCEFILES += rf-ieee-mode.c rf-ieee-settings.c -CONTIKI_CPU_SOURCEFILES += ieee-addr.c - -### CPU-dependent debug source files -DEBUG_IO_SOURCEFILES += dbg-printf.c dbg-snprintf.c dbg-sprintf.c strformat.c - -CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES) $(DEBUG_IO_SOURCEFILES) - -CPU_START_SOURCEFILES += $(SDK_STARTUP_SRCS) - -### Always re-build ieee-addr.o in case the command line passes a new NODEID -FORCE: - -$(OBJECTDIR)/ieee-addr.o: ieee-addr.c FORCE | $(OBJECTDIR) - $(TRACE_CC) - $(Q)$(CC) $(CFLAGS) -c $< -o $@ - -### Always re-build ccfg.c so changes to ccfg-conf.h will apply without having -### to make clean first -$(OBJECTDIR)/ccfg.o: ccfg.c FORCE | $(OBJECTDIR) - $(TRACE_CC) - $(Q)$(CC) $(CFLAGS) -include "ccfg-conf.h" -c $< -o $@ - -$(OBJECTDIR)/$(SIMPLELINK_BOARD).o: $(SDK_BOARDS)/$(SIMPLELINK_BOARD)/$(SIMPLELINK_BOARD).c - $(TRACE_CC) - $(Q)$(CC) $(CFLAGS) -c $< -o $@ - -RAM_SIZE = 0x00003E00 -FLASH_SIZE = 0x0001E000 -STACK_SIZE = 0 -%.size: %.$(TARGET) - @$(SIZE) -A $< | egrep "data|bss" | awk '{s+=$$2} END {s=s+$(STACK_SIZE); f=$(RAM_SIZE)-s; printf "[RAM] used %6d, free %6d\n",s,f;}' - @$(SIZE) -A $< | egrep "text|isr_vector" | awk '{s+=$$2} END {f=$(FLASH_SIZE)-s; printf "[Flash] used %6d, free %6d\n",s,f;}' - -UART_BAUDRATE = 115200 - -login: - $(SERIALDUMP) -b$(UART_BAUDRATE) $(PORT) - -# TODO fix switch -include $(CPU_ABS_PATH)/Makefile.cc26x2_cc13x2 diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.cc13x0-cc26x0 b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/Makefile.cc13x0-cc26x0 similarity index 100% rename from arch/cpu/cc13xx-cc26xx/Makefile.cc13x0-cc26x0 rename to arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/Makefile.cc13x0-cc26x0 diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-ieee-settings.h b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-ieee-settings.h deleted file mode 100644 index c7461e2fc..000000000 --- a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-ieee-settings.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef IEEE_SETTINGS_H_ -#define IEEE_SETTINGS_H_ - -#include -#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) -#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) -#include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h) -#include - -// RF TX power table -extern RF_TxPowerTable_Entry txPowerTable[]; -extern const size_t txPowerTableLen; - -// TI-RTOS RF Mode Object -extern RF_Mode RF_ieeeMode; - -// RF Core API commands -extern rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup; -extern rfc_CMD_FS_t RF_cmdFs; -extern rfc_CMD_IEEE_RX_t RF_cmdIeeeRx; -extern rfc_CMD_IEEE_TX_t RF_cmdIeeeTx; - -// RF Core API Overrides -extern uint32_t pOverrides[]; - -#endif /* IEEE_SETTINGS_H_ */ diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-prop-settings.c b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-prop-settings.c deleted file mode 100644 index 465bd65c6..000000000 --- a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-prop-settings.c +++ /dev/null @@ -1,276 +0,0 @@ -//********************************************************************************* -// Generated by SmartRF Studio version 2.8.0 ( build #41) -// Compatible with SimpleLink SDK version: CC13x2 SDK 1.60.xx.xx -// Device: CC1352 Rev. 1.0 -// -//********************************************************************************* - - -//********************************************************************************* -// Parameter summary -// Address: off -// Address0: 0xAA -// Address1: 0xBB -// Frequency: 868.00000 MHz -// Data Format: Serial mode disable -// Deviation: 25.000 kHz -// pktLen: 30 -// 802.15.4g Mode: off -// Select bit order to transmit PSDU octets:: 1 -// Packet Length Config: Variable -// Max Packet Length: 255 -// Packet Length: 30 -// RX Filter BW: 98.0 kHz -// Symbol Rate: 50.00000 kBaud -// Sync Word Length: 32 Bits -// TX Power: 14 dBm (requires define CCFG_FORCE_VDDR_HH = 1 in ccfg.c, see CC13xx/CC26xx Technical Reference Manual) -// Whitening: No whitening - -#include -#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) -#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) -#include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h) -#include -#include DeviceFamily_constructPath(rf_patches/rf_patch_rfe_genfsk.h) - -#include "rf-common.h" - -/*---------------------------------------------------------------------------*/ -/** - * \addtogroup rf-core-prop - * @{ - * - * \file - * Default TX power settings. The board can override - */ -/*---------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------*/ -/* Default TX power settings for the 779-930MHz band */ -RF_TxPower RF_propTxPower779_930[] = { - { 14, 0xa73f }, - { 13, 0xa63f }, /* 12.5 */ - { 12, 0xb818 }, - { 11, 0x50da }, - { 10, 0x38d3 }, - { 9, 0x2ccd }, - { 8, 0x24cb }, - { 7, 0x20c9 }, - { 6, 0x1cc7 }, - { 5, 0x18c6 }, - { 4, 0x18c5 }, - { 3, 0x14c4 }, - { 2, 0x1042 }, - { 1, 0x10c3 }, - { 0, 0x0041 }, - { -10, 0x08c0 }, - {-128, 0xFFFF }, -}; -const size_t RF_propTxPower779_930Size = sizeof(RF_propTxPower779_930) / sizeof(RF_propTxPower779_930[0]); -/*---------------------------------------------------------------------------*/ -/* Default TX power settings for the 431-527MHz band */ -RF_TxPower RF_propTxPower431_527[] = { - { 15, 0x003f }, - { 14, 0xbe3f }, /* 13.7 */ - { 13, 0x6a0f }, - { 10, 0x3dcb }, - { 6, 0x22c4 }, - {-128, 0xFFFF }, -}; -const size_t RF_propTxPower431_527Size = sizeof(RF_propTxPower431_527) / sizeof(RF_propTxPower431_527[0]); -/*---------------------------------------------------------------------------*/ -/** - * @} - */ - -// TI-RTOS RF Mode Object -RF_Mode RF_propMode = -{ - .rfMode = RF_MODE_PROPRIETARY_SUB_1, - .cpePatchFxn = NULL, - .mcePatchFxn = NULL, - .rfePatchFxn = &rf_patch_rfe_genfsk, -}; - -// Overrides for CMD_PROP_RADIO_DIV_SETUP -static uint32_t pOverrides[] = -{ - // override_use_patch_prop_genfsk.xml - // PHY: Use MCE RAM patch, RFE RAM patch - MCE_RFE_OVERRIDE(1,0,0,1,0,0), - // override_synth_prop_863_930_div5.xml - // Synth: Use 48 MHz crystal as synth clock, enable extra PLL filtering - (uint32_t)0x02400403, - // Synth: Set minimum RTRIM to 7 - (uint32_t)0x00078793, - // Synth: Configure extra PLL filtering - (uint32_t)0x00108463, - // Synth: Set Fref to 4 MHz - (uint32_t)0x000684A3, - // Synth: Set loop bandwidth after lock to 20 kHz - (uint32_t)0x0A480583, - // Synth: Set loop bandwidth after lock to 20 kHz - (uint32_t)0x7AB80603, - // override_phy_tx_pa_ramp_genfsk.xml - // Tx: Configure PA ramping, set wait time before turning off (0x2F ticks à 16/24 us = 31.3 us). - HW_REG_OVERRIDE(0x6028,0x002F), - // Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[3]=1) - ADI_HALFREG_OVERRIDE(0,16,0x8,0x8), - // Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[4]=1) - ADI_HALFREG_OVERRIDE(0,17,0x1,0x1), - // override_phy_rx_aaf_bw_0xd.xml - // Rx: Set anti-aliasing filter bandwidth to 0xD (in ADI0, set IFAMPCTL3[7:4]=0xD) - ADI_HALFREG_OVERRIDE(0,61,0xF,0xD), - // override_phy_rx_rssi_offset_neg2db.xml - // Rx: Set RSSI offset to adjust reported RSSI by -2 dB - (uint32_t)0x000288A3, - // TX power override - // DC/DC regulator: In Tx with 14 dBm PA setting, use DCDCCTL5[3:0]=0xF (DITHER_EN=1 and IPEAK=7). In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). - (uint32_t)0xFFFC08C3, - (uint32_t)0xFFFFFFFF, -}; - - -// CMD_PROP_RADIO_DIV_SETUP -// Proprietary Mode Radio Setup Command for All Frequency Bands -rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup = -{ - .commandNo = 0x3807, - .status = 0x0000, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .modulation.modType = 0x1, - .modulation.deviation = 0x64, - .symbolRate.preScale = 0xf, - .symbolRate.rateWord = 0x8000, - .rxBw = 0x24, - .preamConf.nPreamBytes = 0x3, - .preamConf.preamMode = 0x0, - .formatConf.nSwBits = 0x18, - .formatConf.bBitReversal = 0x0, - .formatConf.bMsbFirst = 0x1, - .formatConf.fecMode = 0x0, - - /* 7: .4g mode with dynamic whitening and CRC choice */ - .formatConf.whitenMode = 0x7, - .config.frontEndMode = 0x00, /* Set by the driver */ - .config.biasMode = 0x00, /* Set by the driver */ - .config.analogCfgMode = 0x0, - .config.bNoFsPowerUp = 0x0, - .txPower = 0x00, /* Driver sets correct value */ - .pRegOverride = pOverrides, - .intFreq = 0x8000, - .centerFreq = 868, - .loDivider = 0x05, -}; - -// CMD_FS -// Frequency Synthesizer Programming Command -rfc_CMD_FS_t rf_cmd_prop_fs = -{ - .commandNo = 0x0803, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .frequency = 0x0364, - .fractFreq = 0x0000, - .synthConf.bTxMode = 0x0, - .synthConf.refFreq = 0x0, - .__dummy0 = 0x00, - .__dummy1 = 0x00, - .__dummy2 = 0x00, - .__dummy3 = 0x0000, -}; - -/* CMD_PROP_TX_ADV */ -rfc_CMD_PROP_TX_ADV_t rf_cmd_prop_tx_adv = -{ - .commandNo = 0x3803, - .status = 0x0000, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .pktConf.bFsOff = 0x0, - .pktConf.bUseCrc = 0x1, - .pktConf.bCrcIncSw = 0x0, /* .4g mode */ - .pktConf.bCrcIncHdr = 0x0, /* .4g mode */ - .numHdrBits = 0x10 /* 16: .4g mode */, - .pktLen = 0x0000, - .startConf.bExtTxTrig = 0x0, - .startConf.inputMode = 0x0, - .startConf.source = 0x0, - .preTrigger.triggerType = TRIG_NOW, - .preTrigger.bEnaCmd = 0x0, - .preTrigger.triggerNo = 0x0, - .preTrigger.pastTrig = 0x1, - .preTime = 0x00000000, - .syncWord = 0x0055904e, - .pPkt = 0, -}; -/*---------------------------------------------------------------------------*/ -/* CMD_PROP_RX_ADV */ -rfc_CMD_PROP_RX_ADV_t rf_cmd_prop_rx_adv = -{ - .commandNo = 0x3804, - .status = 0x0000, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .pktConf.bFsOff = 0x0, - .pktConf.bRepeatOk = 0x1, - .pktConf.bRepeatNok = 0x1, - .pktConf.bUseCrc = 0x1, - .pktConf.bCrcIncSw = 0x0, /* .4g mode */ - .pktConf.bCrcIncHdr = 0x0, /* .4g mode */ - .pktConf.endType = 0x0, - .pktConf.filterOp = 0x1, - .rxConf.bAutoFlushIgnored = 0x1, - .rxConf.bAutoFlushCrcErr = 0x1, - .rxConf.bIncludeHdr = 0x0, - .rxConf.bIncludeCrc = 0x0, - .rxConf.bAppendRssi = 0x1, - .rxConf.bAppendTimestamp = 0x0, - .rxConf.bAppendStatus = 0x1, - .syncWord0 = 0x0055904e, - .syncWord1 = 0x00000000, - .maxPktLen = 0x0000, /* To be populated by the driver. */ - .hdrConf.numHdrBits = 0x10, /* 16: .4g mode */ - .hdrConf.lenPos = 0x0, /* .4g mode */ - .hdrConf.numLenBits = 0x0B, /* 11 = 0x0B .4g mode */ - .addrConf.addrType = 0x0, - .addrConf.addrSize = 0x0, - .addrConf.addrPos = 0x0, - .addrConf.numAddr = 0x0, - .lenOffset = -4, /* .4g mode */ - .endTrigger.triggerType = TRIG_NEVER, - .endTrigger.bEnaCmd = 0x0, - .endTrigger.triggerNo = 0x0, - .endTrigger.pastTrig = 0x0, - .endTime = 0x00000000, - .pAddr = 0, - .pQueue = 0, - .pOutput = 0, -}; -/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-prop-settings.h b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-prop-settings.h deleted file mode 100644 index 947c5254e..000000000 --- a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-prop-settings.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef RF_PROP_SETTINGS_H_ -#define RF_PROP_SETTINGS_H_ - -//********************************************************************************* -// Generated by SmartRF Studio version 2.8.0 ( build #41) -// Compatible with SimpleLink SDK version: CC13x2 SDK 1.60.xx.xx -// Device: CC1352 Rev. 1.0 -// -//********************************************************************************* -#include -#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) -#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) -#include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h) -#include - -#include - -// RF TX power table -extern RF_TxPower RF_propTxPower779_930[]; -extern const size_t RF_propTxPower779_930Size; - -extern RF_TxPower RF_propTxPower431_527[]; -extern const size_t RF_propTxPower431_527Size; - -// TI-RTOS RF Mode Object -extern RF_Mode RF_propMode; - -// RF Core API commands -extern rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup; -extern rfc_CMD_FS_t rf_cmd_prop_fs; -extern rfc_CMD_PROP_TX_ADV_t rf_cmd_prop_tx_adv; -extern rfc_CMD_PROP_RX_ADV_t rf_cmd_prop_rx_adv; - - -#endif /* RF_PROP_SETTINGS_H_ */ diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.cc13x2-cc26x2 b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/Makefile.cc13x2-cc26x2 similarity index 100% rename from arch/cpu/cc13xx-cc26xx/Makefile.cc13x2-cc26x2 rename to arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/Makefile.cc13x2-cc26x2 diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c index 4c7fd69f6..3ca674ad3 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c @@ -66,7 +66,7 @@ #ifdef IEEE_MODE_CONF_RF_SETTINGS # define IEEE_MODE_RF_SETTINGS IEEE_MODE_CONF_RF_SETTINGS #else -# define IEEE_MODE_RF_SETTINGS "rf-settings/rf-ieee-settings.h" +# define IEEE_MODE_RF_SETTINGS "ieee-settings.h" #endif #include IEEE_MODE_RF_SETTINGS @@ -120,23 +120,17 @@ #endif /* Configuration for TX power table */ -#ifdef TX_POWER_CONF_DRIVER -# define TX_POWER_DRIVER TX_POWER_CONF_DRIVER +#ifdef TX_POWER_CONF_TABLE +# define TX_POWER_TABLE TX_POWER_CONF_TABLE #else -# define TX_POWER_DRIVER txPowerTable -#endif - -#ifdef TX_POWER_CONF_COUNT -# define TX_POWER_COUNT TX_POWER_CONF_COUNT -#else -# define TX_POWER_COUNT txPowerTableLen +# define TX_POWER_TABLE txPowerTable #endif /*---------------------------------------------------------------------------*/ -/* TX power convenience macros */ -static RF_TxPowerTable_Entry * const g_pTxPower = TX_POWER_DRIVER; +/* TX power table convenience macros */ +#define TX_POWER_TABLE_SIZE ((sizeof(TX_POWER_TABLE) / sizeof(TX_POWER_TABLE[0])) - 1) -#define TX_POWER_MIN (g_pTxPower[0]) -#define TX_POWER_MAX (g_pTxPower[(TX_POWER_COUNT) - 1]) +#define TX_POWER_MIN (TX_POWER_TABLE[0]) +#define TX_POWER_MAX (TX_POWER_TABLE[TX_POWER_TABLE_SIZE - 1]) #define TX_POWER_IN_RANGE(dbm) (((dbm) >= TX_POWER_MIN) && ((dbm) <= TX_POWER_MAX)) /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c index f1cc3c2e9..6053d4631 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c @@ -59,7 +59,7 @@ # define PROP_MODE_RF_SETTINGS PROP_MODE_CONF_RF_SETTINGS # undef PROP_MODE_CONF_RF_SETTINGS #else -# define PROP_MODE_RF_SETTINGS "rf-settings/rf-prop-settings.h" +# define PROP_MODE_RF_SETTINGS "prop-settings.h" #endif #include PROP_MODE_RF_SETTINGS diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c new file mode 100644 index 000000000..42a46ecbb --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c @@ -0,0 +1,237 @@ +//********************************************************************************* +// Parameter summary +// IEEE Channel: 11 +// Frequency: 2405 MHz +// SFD: 0 +// Packet Data: 255 +// Preamble (32 bit): 01010101... +// TX Power: 5 dBm + +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_ieee_cmd.h) +#include DeviceFamily_constructPath(rf_patches/rf_patch_cpe_ieee.h) + +#include + +#include "ieee-settings.h" + + +// TI-RTOS RF Mode Object +RF_Mode ieeeMode = +{ + .rfMode = RF_MODE_IEEE_15_4, + .cpePatchFxn = &rf_patch_cpe_ieee, + .mcePatchFxn = 0, + .rfePatchFxn = 0, +}; + + +// TX Power table +// The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: +// RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) +// See the Technical Reference Manual for further details about the "txPower" Command field. +// The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. +RF_TxPowerTable_Entry txPowerTable[14] = +{ + { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 6) }, + { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 6) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 6) }, + { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 1, 0, 10) }, + { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 1, 12) }, + { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(18, 1, 1, 14) }, + { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 1, 1, 18) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(33, 1, 1, 24) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 0, 0, 33) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 0, 0, 39) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 0, 0, 45) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(36, 0, 1, 73) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(48, 0, 1, 73) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; + + +// Overrides for CMD_RADIO_SETUP +uint32_t pOverrides[] = +{ + // override_synth_ieee_15_4.xml + HW_REG_OVERRIDE(0x4038,0x0035), // Synth: Set recommended RTRIM to 5 + (uint32_t)0x000784A3, // Synth: Set Fref to 3.43 MHz + (uint32_t)0xA47E0583, // Synth: Set loop bandwidth after lock to 80 kHz + (uint32_t)0xEAE00603, // Synth: Set loop bandwidth after lock to 80 kHz + (uint32_t)0x00010623, // Synth: Set loop bandwidth after lock to 80 kHz + HW32_ARRAY_OVERRIDE(0x405C,1), // Synth: Configure PLL bias + (uint32_t)0x1801F800, // Synth: Configure PLL bias + HW32_ARRAY_OVERRIDE(0x402C,1), // Synth: Configure PLL latency + (uint32_t)0x00608402, // Synth: Configure PLL latency + (uint32_t)0x02010403, // Synth: Use 24 MHz XOSC as synth clock, enable extra PLL filtering + HW32_ARRAY_OVERRIDE(0x4034,1), // Synth: Configure extra PLL filtering + (uint32_t)0x177F0408, // Synth: Configure extra PLL filtering + (uint32_t)0x38000463, // Synth: Configure extra PLL filtering + // override_phy_ieee_15_4.xml + (uint32_t)0x05000243, // Synth: Increase synth programming timeout + (uint32_t)0x002082C3, // Rx: Adjust Rx FIFO threshold to avoid overflow + // override_frontend_id.xml + (uint32_t)0x000288A3, // Rx: Set RSSI offset to adjust reported RSSI by -2 dB + (uint32_t)0x000F8883, // Rx: Configure LNA bias current trim offset + HW_REG_OVERRIDE(0x50DC,0x002B), // Rx: Adjust AGC DC filter + (uint32_t)0xFFFFFFFF, +}; + + +// Old override list +uint32_t ieee_overrides[] = { + (uint32_t)0x00354038, // Synth: Set RTRIM (POTAILRESTRIM) to 5 + (uint32_t)0x000784A3, // Synth: Set FREF = 3.43 MHz (24 MHz / 7) + (uint32_t)0xA47E0583, // Synth: Set loop bandwidth after lock to 80 kHz (K2) + (uint32_t)0xEAE00603, // Synth: Set loop bandwidth after lock to 80 kHz (K3, LSB) + (uint32_t)0x00010623, // Synth: Set loop bandwidth after lock to 80 kHz (K3, MSB) +// (uint32_t)0x1801F800, // Synth: Set ANADIV DIV_BIAS_MODE to PG1 (value) + (uint32_t)0x4001402D, // Synth: Correct CKVD latency setting (address) + (uint32_t)0x00608402, // Synth: Correct CKVD latency setting (value) +// (uint32_t)0x4001405D, // Synth: Set ANADIV DIV_BIAS_MODE to PG1 (address) + (uint32_t)0x002B50DC, // Adjust AGC DC filter + (uint32_t)0x05000243, // Increase synth programming timeout + (uint32_t)0x002082C3, // Increase synth programming timeout + (uint32_t)0xFFFFFFFF, +}; + + +// CMD_RADIO_SETUP +// Radio Setup Command for Pre-Defined Schemes +rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup = +{ + .commandNo = 0x0802, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .mode = 0x01, + .__dummy0 = 0x00, + .config.frontEndMode = 0x0, + .config.biasMode = 0x0, + .config.analogCfgMode = 0x0, + .config.bNoFsPowerUp = 0x0, + .txPower = 0x9330, + .pRegOverride = pOverrides, +}; + +// CMD_FS +// Frequency Synthesizer Programming Command +rfc_CMD_FS_t RF_cmdFs = +{ + .commandNo = 0x0803, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .frequency = 0x0965, + .fractFreq = 0x0000, + .synthConf.bTxMode = 0x1, + .synthConf.refFreq = 0x0, + .__dummy0 = 0x00, + .__dummy1 = 0x00, + .__dummy2 = 0x00, + .__dummy3 = 0x0000, +}; + +// CMD_IEEE_TX +// The command ID number 0x2C01 +rfc_CMD_IEEE_TX_t RF_cmdIeeeTx = +{ + .commandNo = 0x2C01, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .txOpt.bIncludePhyHdr = 0x0, + .txOpt.bIncludeCrc = 0x0, + .txOpt.payloadLenMsb = 0x0, + .payloadLen = 0x1E, + .pPayload = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .timeStamp = 0x00000000, +}; + +// CMD_IEEE_RX +// The command ID number 0x2801 +rfc_CMD_IEEE_RX_t RF_cmdIeeeRx = +{ + .commandNo = 0x2801, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .channel = 0x00, + .rxConfig.bAutoFlushCrc = 0x0, + .rxConfig.bAutoFlushIgn = 0x0, + .rxConfig.bIncludePhyHdr = 0x0, + .rxConfig.bIncludeCrc = 0x0, + .rxConfig.bAppendRssi = 0x1, + .rxConfig.bAppendCorrCrc = 0x1, + .rxConfig.bAppendSrcInd = 0x0, + .rxConfig.bAppendTimestamp = 0x0, + .pRxQ = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx + .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .frameFiltOpt.frameFiltEn = 0x0, + .frameFiltOpt.frameFiltStop = 0x0, + .frameFiltOpt.autoAckEn = 0x0, + .frameFiltOpt.slottedAckEn = 0x0, + .frameFiltOpt.autoPendEn = 0x0, + .frameFiltOpt.defaultPend = 0x0, + .frameFiltOpt.bPendDataReqOnly = 0x0, + .frameFiltOpt.bPanCoord = 0x0, + .frameFiltOpt.maxFrameVersion = 0x3, + .frameFiltOpt.fcfReservedMask = 0x0, + .frameFiltOpt.modifyFtFilter = 0x0, + .frameFiltOpt.bStrictLenFilter = 0x0, + .frameTypes.bAcceptFt0Beacon = 0x1, + .frameTypes.bAcceptFt1Data = 0x1, + .frameTypes.bAcceptFt2Ack = 0x1, + .frameTypes.bAcceptFt3MacCmd = 0x1, + .frameTypes.bAcceptFt4Reserved = 0x1, + .frameTypes.bAcceptFt5Reserved = 0x1, + .frameTypes.bAcceptFt6Reserved = 0x1, + .frameTypes.bAcceptFt7Reserved = 0x1, + .ccaOpt.ccaEnEnergy = 0x0, + .ccaOpt.ccaEnCorr = 0x0, + .ccaOpt.ccaEnSync = 0x0, + .ccaOpt.ccaCorrOp = 0x1, + .ccaOpt.ccaSyncOp = 0x1, + .ccaOpt.ccaCorrThr = 0x0, + .ccaRssiThr = 0x64, + .__dummy0 = 0x00, + .numExtEntries = 0x00, + .numShortEntries = 0x00, + .pExtEntryList = 0, // INSERT APPLICABLE POINTER: (uint32_t*)&xxx + .pShortEntryList = 0, // INSERT APPLICABLE POINTER: (uint32_t*)&xxx + .localExtAddr = 0x0000000012345678, + .localShortAddr = 0xABBA, + .localPanID = 0x0000, + .__dummy1 = 0x000000, + .endTrigger.triggerType = 0x1, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, +}; diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h new file mode 100644 index 000000000..0b0bf81ec --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h @@ -0,0 +1,38 @@ +#ifndef _IEEE_SETTINGS_H_ +#define _IEEE_SETTINGS_H_ + +//********************************************************************************* +// Generated by SmartRF Studio version 2.9.0 (build#85) +// Compatible with SimpleLink SDK version: No known SDK for this device +// Device: CC2650 Rev. 2.2 +// +//********************************************************************************* +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_ieee_cmd.h) + +#include + + +// TI-RTOS RF Mode Object +extern RF_Mode RF_ieeeMode; + + +// TX Power Table +extern RF_TxPowerTable_Entry txPowerTable[14]; + + +// RF Core API commands +extern rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup; +extern rfc_CMD_FS_t RF_cmdFs; +extern rfc_CMD_IEEE_TX_t RF_cmdIeeeTx; +extern rfc_CMD_IEEE_RX_t RF_cmdIeeeRx; + + +// RF Core API Overrides +extern uint32_t pOverrides[]; + + +#endif // _IEEE_SETTINGS_H_ + diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c new file mode 100644 index 000000000..b65c2a9e2 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c @@ -0,0 +1,258 @@ +//********************************************************************************* +// Generated by SmartRF Studio version 2.9.0 (build#85) +// Compatible with SimpleLink SDK version: CC13x0 SDK 2.10.xx.xx +// Device: CC1350 Rev. 2.1 +// +//********************************************************************************* + + +//********************************************************************************* +// Parameter summary +// Address: 0 +// Address0: 0xAA +// Address1: 0xBB +// Frequency: 868.00000 MHz +// Data Format: Serial mode disable +// Deviation: 25.000 kHz +// pktLen: 30 +// 802.15.4g Mode: 0 +// Select bit order to transmit PSDU octets:: 1 +// Packet Length Config: Variable +// Max Packet Length: 255 +// Packet Length: 0 +// Packet Data: 255 +// RX Filter BW: 98 kHz +// Symbol Rate: 50.00000 kBaud +// Sync Word Length: 24 Bits +// TX Power: 14 dBm (requires define CCFG_FORCE_VDDR_HH = 1 in ccfg.c, see CC13xx/CC26xx Technical Reference Manual) +// Whitening: Dynamically IEEE 802.15.4g compatible whitener and 16/32-bit CRC + +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h) +#include DeviceFamily_constructPath(rf_patches/rf_patch_cpe_genfsk.h) +#include DeviceFamily_constructPath(rf_patches/rf_patch_rfe_genfsk.h) + +#include + +#include "prop-settings.h" + + +// TI-RTOS RF Mode Object +RF_Mode RF_propMode = +{ + .rfMode = RF_MODE_PROPRIETARY_SUB_1, + .cpePatchFxn = &rf_patch_cpe_genfsk, + .mcePatchFxn = 0, + .rfePatchFxn = &rf_patch_rfe_genfsk, +}; + + +// TX Power table +// The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: +// RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) +// See the Technical Reference Manual for further details about the "txPower" Command field. +// The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. +RF_TxPowerTable_Entry txPowerTable[16] = +{ + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY( 0, 3, 0, 2) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY( 3, 3, 0, 9) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 3, 0, 11) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY( 5, 3, 0, 12) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY( 6, 3, 0, 14) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 1, 0, 12) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 3, 0, 16) }, + { 6, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 18) }, + { 7, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 21) }, + { 8, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 3, 0, 25) }, + { 9, RF_TxPowerTable_DEFAULT_PA_ENTRY(18, 3, 0, 32) }, + { 10, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 3, 0, 44) }, + { 11, RF_TxPowerTable_DEFAULT_PA_ENTRY(37, 3, 0, 72) }, + { 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(43, 0, 0, 94) }, + // This setting requires CCFG_FORCE_VDDR_HH = 1. + { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 85) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; + + +// Overrides for CMD_PROP_RADIO_DIV_SETUP +uint32_t pOverrides[] = +{ + // override_use_patch_prop_genfsk.xml + MCE_RFE_OVERRIDE(0,4,0,1,0,0), // PHY: Use MCE ROM bank 4, RFE RAM patch + // override_synth_prop_863_930_div5.xml + HW_REG_OVERRIDE(0x4038,0x0037), // Synth: Set recommended RTRIM to 7 + (uint32_t)0x000684A3, // Synth: Set Fref to 4 MHz + HW_REG_OVERRIDE(0x4020,0x7F00), // Synth: Configure fine calibration setting + HW_REG_OVERRIDE(0x4064,0x0040), // Synth: Configure fine calibration setting + (uint32_t)0xB1070503, // Synth: Configure fine calibration setting + (uint32_t)0x05330523, // Synth: Configure fine calibration setting + (uint32_t)0x0A480583, // Synth: Set loop bandwidth after lock to 20 kHz + (uint32_t)0x7AB80603, // Synth: Set loop bandwidth after lock to 20 kHz + ADI_REG_OVERRIDE(1,4,0x9F), // Synth: Configure VCO LDO (in ADI1, set VCOLDOCFG=0x9F to use voltage input reference) + ADI_HALFREG_OVERRIDE(1,7,0x4,0x4), // Synth: Configure synth LDO (in ADI1, set SLDOCTL0.COMP_CAP=1) + (uint32_t)0x02010403, // Synth: Use 24 MHz XOSC as synth clock, enable extra PLL filtering + (uint32_t)0x00108463, // Synth: Configure extra PLL filtering + (uint32_t)0x04B00243, // Synth: Increase synth programming timeout (0x04B0 RAT ticks = 300 us) + // override_phy_rx_aaf_bw_0xd.xml + ADI_HALFREG_OVERRIDE(0,61,0xF,0xD), // Rx: Set anti-aliasing filter bandwidth to 0xD (in ADI0, set IFAMPCTL3[7:4]=0xD) + // override_phy_gfsk_rx.xml + (uint32_t)0x00038883, // Rx: Set LNA bias current trim offset to 3 + HW_REG_OVERRIDE(0x6084,0x35F1), // Rx: Freeze RSSI on sync found event + // override_phy_gfsk_pa_ramp_agc_reflevel_0x1a.xml + HW_REG_OVERRIDE(0x6088,0x411A), // Tx: Configure PA ramping setting (0x41). Rx: Set AGC reference level to 0x1A. + HW_REG_OVERRIDE(0x608C,0x8213), // Tx: Configure PA ramping setting + // override_crc_ieee_802_15_4.xml + (uint32_t)0x00000943, // IEEE 802.15.4g: Fix incorrect initialization value for CRC-16 calculation (see TRM section 23.7.5.2.1) + (uint32_t)0x00000963, // IEEE 802.15.4g: Fix incorrect initialization value for CRC-16 calculation (see TRM section 23.7.5.2.1) + // override_phy_rx_rssi_offset_5db.xml + (uint32_t)0x00FB88A3, / da/ Rx: Set RSSI offset to adjust reported RSSI by +5 dB + // TX power override + ADI_REG_OVERRIDE(0,12,0xF8), // Tx: Set PA trim to max (in ADI0, set PACTL0=0xF8) + (uint32_t)0xFFFFFFFF, +}; + + +// CMD_PROP_RADIO_DIV_SETUP +// Proprietary Mode Radio Setup Command for All Frequency Bands +rfc_CMD_PROP_RADIO_DIV_SETUP_t RF_cmdPropRadioDivSetup = +{ + .commandNo = 0x3807, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .modulation.modType = 0x1, + .modulation.deviation = 0x64, + .symbolRate.preScale = 0xF, + .symbolRate.rateWord = 0x8000, + .rxBw = 0x24, + .preamConf.nPreamBytes = 0x3, + .preamConf.preamMode = 0x0, + .formatConf.nSwBits = 0x18, + .formatConf.bBitReversal = 0x0, + .formatConf.bMsbFirst = 0x1, + .formatConf.fecMode = 0x0, + .formatConf.whitenMode = 0x7, + .config.frontEndMode = 0x0, + .config.biasMode = 0x1, + .config.analogCfgMode = 0x0, + .config.bNoFsPowerUp = 0x0, + .txPower = 0xAB3F, + .pRegOverride = pOverrides, + .centerFreq = 0x0364, + .intFreq = 0x8000, + .loDivider = 0x05, +}; + +// CMD_FS +// Frequency Synthesizer Programming Command +rfc_CMD_FS_t RF_cmdFs = +{ + .commandNo = 0x0803, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .frequency = 0x0364, + .fractFreq = 0x0000, + .synthConf.bTxMode = 0x0, + .synthConf.refFreq = 0x0, + .__dummy0 = 0x00, + .__dummy1 = 0x00, + .__dummy2 = 0x00, + .__dummy3 = 0x0000, +}; + +// CMD_PROP_TX_ADV +// Proprietary Mode Advanced Transmit Command +rfc_CMD_PROP_TX_ADV_t RF_cmdPropTxAdv = +{ + .commandNo = 0x3803, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x2, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x1, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .pktConf.bFsOff = 0x0, + .pktConf.bUseCrc = 0x1, + .pktConf.bCrcIncSw = 0x0, + .pktConf.bCrcIncHdr = 0x0, + .numHdrBits = 0x10, + .pktLen = 0x0000, + .startConf.bExtTxTrig = 0x0, + .startConf.inputMode = 0x0, + .startConf.source = 0x0, + .preTrigger.triggerType = 0x4, + .preTrigger.bEnaCmd = 0x0, + .preTrigger.triggerNo = 0x0, + .preTrigger.pastTrig = 0x1, + .preTime = 0x00000000, + .syncWord = 0x0055904E, + .pPkt = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx +}; + +// CMD_PROP_RX_ADV +// Proprietary Mode Advanced Receive Command +rfc_CMD_PROP_RX_ADV_t RF_cmdPropRxAdv = +{ + .commandNo = 0x3804, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .pktConf.bFsOff = 0x0, + .pktConf.bRepeatOk = 0x0, + .pktConf.bRepeatNok = 0x0, + .pktConf.bUseCrc = 0x0, + .pktConf.bCrcIncSw = 0x0, + .pktConf.bCrcIncHdr = 0x0, + .pktConf.endType = 0x0, + .pktConf.filterOp = 0x0, + .rxConf.bAutoFlushIgnored = 0x0, + .rxConf.bAutoFlushCrcErr = 0x0, + .rxConf.bIncludeHdr = 0x0, + .rxConf.bIncludeCrc = 0x0, + .rxConf.bAppendRssi = 0x0, + .rxConf.bAppendTimestamp = 0x0, + .rxConf.bAppendStatus = 0x0, + .syncWord0 = 0x930B51DE, + .syncWord1 = 0x00000000, + .maxPktLen = 0x00FF, + .hdrConf.numHdrBits = 0x0, + .hdrConf.lenPos = 0x0, + .hdrConf.numLenBits = 0x0, + .addrConf.addrType = 0x0, + .addrConf.addrSize = 0x0, + .addrConf.addrPos = 0x0, + .addrConf.numAddr = 0x0, + .lenOffset = 0x00, + .endTrigger.triggerType = 0x0, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, + .pAddr = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .pQueue = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx + .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx +}; diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h new file mode 100644 index 000000000..6fe099252 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h @@ -0,0 +1,34 @@ +#ifndef _PROP_SETTINGS_H_ +#define _PROP_SETTINGS_H_ + +//********************************************************************************* +// Generated by SmartRF Studio version 2.9.0 (build#85) +// Compatible with SimpleLink SDK version: CC13x0 SDK 2.10.xx.xx +// Device: CC1350 Rev. 2.1 +// +//********************************************************************************* +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h) + +#include + + +// TI-RTOS RF Mode Object +extern RF_Mode RF_propMode; + + +// RF Core API commands +extern rfc_CMD_PROP_RADIO_DIV_SETUP_t RF_cmdPropRadioDivSetup; +extern rfc_CMD_FS_t RF_cmdFs; +extern rfc_CMD_PROP_TX_ADV_t RF_cmdPropTxAdv; +extern rfc_CMD_PROP_RX_ADV_t RF_cmdPropRxAdv; + + +// RF Core API Overrides +extern uint32_t pOverrides[]; + + +#endif // _PROP_SETTINGS_H_ + diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c new file mode 100644 index 000000000..1226e598c --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c @@ -0,0 +1,280 @@ +//********************************************************************************* +// Generated by SmartRF Studio version 2.9.0 (build#85) +// Compatible with SimpleLink SDK version: CC13x2 SDK 2.10.xx.xx +// Device: CC1352P Rev. 1.1 +// +//********************************************************************************* + + +//********************************************************************************* +// Parameter summary +// IEEE Channel: 11 +// Frequency: 2405 MHz +// SFD: 0 +// Packet Data: 255 +// Preamble (32 bit): 01010101... +// For Default PA: +// TX Power: 5 dBm (requires define CCFG_FORCE_VDDR_HH = 0 in ccfg.c, see CC13xx/CC26xx Technical Reference Manual) +// Enable high output power PA: false +// For High PA: +// TX Power: 20 dBm (requires define CCFG_FORCE_VDDR_HH = 0 in ccfg.c, see CC13xx/CC26xx Technical Reference Manual) +// Enable high output power PA: true + +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_ieee_cmd.h) +#include DeviceFamily_constructPath(rf_patches/rf_patch_cpe_ieee_802_15_4.h) +#include DeviceFamily_constructPath(rf_patches/rf_patch_mce_ieee_802_15_4.h) + +#include + +#include "ieee-settings.h" + + +// TI-RTOS RF Mode Object +RF_Mode RF_ieeeMode = +{ + .rfMode = RF_MODE_AUTO, + .cpePatchFxn = &rf_patch_cpe_ieee_802_15_4, + .mcePatchFxn = &rf_patch_mce_ieee_802_15_4, + .rfePatchFxn = 0, +}; + + +// TX Power table +// The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: +// RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) +// See the Technical Reference Manual for further details about the "txPower" Command field. +// The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. +RF_TxPowerTable_Entry defaultPaTxPowerTable[16] = +{ + { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 3) }, + { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 3) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 2, 0, 6) }, + { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 2, 0, 8) }, + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 11) }, + { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 2, 0, 5) }, + { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 16) }, + { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 17) }, + { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 1, 0, 20) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(25, 1, 0, 26) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 1, 0, 28) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 0, 0, 34) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 0, 0, 42) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 0, 0, 54) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; + + +// TX Power table +// The RF_TxPowerTable_HIGH_PA_ENTRY macro is defined in RF.h and requires the following arguments: +// RF_TxPowerTable_HIGH_PA_ENTRY(bias, ibboost, boost, coefficient, ldoTrim) +// See the Technical Reference Manual for further details about the "txPower" Command field. +// The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. +RF_TxPowerTable_Entry highPaTxPowerTable[16] = +{ + { 0, RF_TxPowerTable_HIGH_PA_ENTRY(29, 0, 1, 17, 1) }, + { 3, RF_TxPowerTable_HIGH_PA_ENTRY(39, 0, 1, 20, 1) }, + { 6, RF_TxPowerTable_HIGH_PA_ENTRY(46, 0, 1, 26, 7) }, + { 9, RF_TxPowerTable_HIGH_PA_ENTRY(40, 0, 1, 39, 41) }, + { 10, RF_TxPowerTable_HIGH_PA_ENTRY(23, 2, 1, 65, 5) }, + { 11, RF_TxPowerTable_HIGH_PA_ENTRY(24, 2, 1, 29, 7) }, + { 12, RF_TxPowerTable_HIGH_PA_ENTRY(19, 2, 1, 16, 25) }, + { 13, RF_TxPowerTable_HIGH_PA_ENTRY(27, 2, 1, 19, 13) }, + { 14, RF_TxPowerTable_HIGH_PA_ENTRY(24, 2, 1, 19, 27) }, + { 15, RF_TxPowerTable_HIGH_PA_ENTRY(23, 2, 1, 20, 39) }, + { 16, RF_TxPowerTable_HIGH_PA_ENTRY(34, 2, 1, 26, 23) }, + { 17, RF_TxPowerTable_HIGH_PA_ENTRY(38, 2, 1, 33, 25) }, + { 18, RF_TxPowerTable_HIGH_PA_ENTRY(30, 2, 1, 37, 53) }, + { 19, RF_TxPowerTable_HIGH_PA_ENTRY(36, 2, 1, 57, 59) }, + { 20, RF_TxPowerTable_HIGH_PA_ENTRY(56, 2, 1, 45, 63) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; + + +// Overrides for CMD_RADIO_SETUP +uint32_t pDefaultPaOverrides[] = +{ + // override_ieee_802_15_4.xml + MCE_RFE_OVERRIDE(1,0,0,0,1,0), // PHY: Use MCE RAM patch, RFE ROM bank 1 + (uint32_t)0x02400403, // Synth: Use 48 MHz crystal, enable extra PLL filtering + (uint32_t)0x001C8473, // Synth: Configure extra PLL filtering + (uint32_t)0x00088433, // Synth: Configure synth hardware + (uint32_t)0x00038793, // Synth: Set minimum RTRIM to 3 + HW32_ARRAY_OVERRIDE(0x4004,1), // Synth: Configure faster calibration + (uint32_t)0x1C0C0618, // Synth: Configure faster calibration + (uint32_t)0xC00401A1, // Synth: Configure faster calibration + (uint32_t)0x00010101, // Synth: Configure faster calibration + (uint32_t)0xC0040141, // Synth: Configure faster calibration + (uint32_t)0x00214AD3, // Synth: Configure faster calibration + (uint32_t)0x02980243, // Synth: Decrease synth programming time-out (0x0298 RAT ticks = 166 us) + (uint32_t)0xFCFC08C3, // DC/DC regulator: In Tx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). + (uint32_t)0x000F8883, // Rx: Set LNA bias current offset to +15 to saturate trim to max (default: 0) + (uint32_t)0xFFFFFFFF, +}; + + +// Overrides for CMD_RADIO_SETUP +uint32_t pHighPaOverrides[] = +{ + // override_ieee_802_15_4.xml + MCE_RFE_OVERRIDE(1,0,0,0,1,0), // PHY: Use MCE RAM patch, RFE ROM bank 1 + (uint32_t)0x02400403, // Synth: Use 48 MHz crystal, enable extra PLL filtering + (uint32_t)0x001C8473, // Synth: Configure extra PLL filtering + (uint32_t)0x00088433, // Synth: Configure synth hardware + (uint32_t)0x00038793, // Synth: Set minimum RTRIM to 3 + HW32_ARRAY_OVERRIDE(0x4004,1), // Synth: Configure faster calibration + (uint32_t)0x1C0C0618, // Synth: Configure faster calibration + (uint32_t)0xC00401A1, // Synth: Configure faster calibration + (uint32_t)0x00010101, // Synth: Configure faster calibration + (uint32_t)0xC0040141, // Synth: Configure faster calibration + (uint32_t)0x00214AD3, // Synth: Configure faster calibration + (uint32_t)0x02980243, // Synth: Decrease synth programming time-out (0x0298 RAT ticks = 166 us) + (uint32_t)0xFCFC08C3, // DC/DC regulator: In Tx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). + (uint32_t)0x000F8883, // Rx: Set LNA bias current offset to +15 to saturate trim to max (default: 0) + // override_frontend_xd.xml + // TX power override + (uint32_t)0xFD6EE02B, // txHighPA=0x3F5BB8 + (uint32_t)0xFFFFFFFF, +}; + + +// CMD_RADIO_SETUP +// Radio Setup Command for Pre-Defined Schemes +rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup = +{ + .commandNo = 0x0802, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .mode = 0x01, + .loDivider = 0x00, + .config.frontEndMode = 0x0, + .config.biasMode = 0x1, + .config.analogCfgMode = 0x0, + .config.bNoFsPowerUp = 0x0, + .txPower = 0x941E, + .pRegOverride = pOverrides, +}; + +// CMD_FS +// Frequency Synthesizer Programming Command +rfc_CMD_FS_t RF_cmdFs = +{ + .commandNo = 0x0803, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .frequency = 0x0965, + .fractFreq = 0x0000, + .synthConf.bTxMode = 0x1, + .synthConf.refFreq = 0x0, + .__dummy0 = 0x00, + .__dummy1 = 0x00, + .__dummy2 = 0x00, + .__dummy3 = 0x0000, +}; + +// CMD_IEEE_TX +// IEEE 802.15.4 Transmit Command +rfc_CMD_IEEE_TX_t RF_cmdIeeeTx = +{ + .commandNo = 0x2C01, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .txOpt.bIncludePhyHdr = 0x0, + .txOpt.bIncludeCrc = 0x0, + .txOpt.payloadLenMsb = 0x0, + .payloadLen = 0x1E, + .pPayload = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .timeStamp = 0x00000000, +}; + +// CMD_IEEE_RX +// IEEE 802.15.4 Receive Command +rfc_CMD_IEEE_RX_t RF_cmdIeeeRx = +{ + .commandNo = 0x2801, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .channel = 0x00, + .rxConfig.bAutoFlushCrc = 0x0, + .rxConfig.bAutoFlushIgn = 0x0, + .rxConfig.bIncludePhyHdr = 0x0, + .rxConfig.bIncludeCrc = 0x0, + .rxConfig.bAppendRssi = 0x1, + .rxConfig.bAppendCorrCrc = 0x1, + .rxConfig.bAppendSrcInd = 0x0, + .rxConfig.bAppendTimestamp = 0x0, + .pRxQ = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx + .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .frameFiltOpt.frameFiltEn = 0x0, + .frameFiltOpt.frameFiltStop = 0x0, + .frameFiltOpt.autoAckEn = 0x0, + .frameFiltOpt.slottedAckEn = 0x0, + .frameFiltOpt.autoPendEn = 0x0, + .frameFiltOpt.defaultPend = 0x0, + .frameFiltOpt.bPendDataReqOnly = 0x0, + .frameFiltOpt.bPanCoord = 0x0, + .frameFiltOpt.maxFrameVersion = 0x3, + .frameFiltOpt.fcfReservedMask = 0x0, + .frameFiltOpt.modifyFtFilter = 0x0, + .frameFiltOpt.bStrictLenFilter = 0x0, + .frameTypes.bAcceptFt0Beacon = 0x1, + .frameTypes.bAcceptFt1Data = 0x1, + .frameTypes.bAcceptFt2Ack = 0x1, + .frameTypes.bAcceptFt3MacCmd = 0x1, + .frameTypes.bAcceptFt4Reserved = 0x1, + .frameTypes.bAcceptFt5Reserved = 0x1, + .frameTypes.bAcceptFt6Reserved = 0x1, + .frameTypes.bAcceptFt7Reserved = 0x1, + .ccaOpt.ccaEnEnergy = 0x0, + .ccaOpt.ccaEnCorr = 0x0, + .ccaOpt.ccaEnSync = 0x0, + .ccaOpt.ccaCorrOp = 0x1, + .ccaOpt.ccaSyncOp = 0x1, + .ccaOpt.ccaCorrThr = 0x0, + .ccaRssiThr = 0x64, + .__dummy0 = 0x00, + .numExtEntries = 0x00, + .numShortEntries = 0x00, + .pExtEntryList = 0, // INSERT APPLICABLE POINTER: (uint32_t*)&xxx + .pShortEntryList = 0, // INSERT APPLICABLE POINTER: (uint32_t*)&xxx + .localExtAddr = 0x0000000012345678, + .localShortAddr = 0xABBA, + .localPanID = 0x0000, + .__dummy1 = 0x000000, + .endTrigger.triggerType = 0x1, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, +}; diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h new file mode 100644 index 000000000..90c75856b --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h @@ -0,0 +1,40 @@ +#ifndef _IEEE_SETTINGS_H_ +#define _IEEE_SETTINGS_H_ + +//********************************************************************************* +// Generated by SmartRF Studio version 2.9.0 (build#85) +// Compatible with SimpleLink SDK version: CC13x2 SDK 2.10.xx.xx +// Device: CC1352P Rev. 1.1 +// +//********************************************************************************* +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_ieee_cmd.h) + +#include + + +// TI-RTOS RF Mode Object +extern RF_Mode RF_ieeeMode; + + +// TX Power Table +extern RF_TxPowerTable_Entry defaultPaTxPowerTable[16]; +extern RF_TxPowerTable_Entry highPaTxPowerTable[16]; + + +// RF Core API commands +extern rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup; +extern rfc_CMD_FS_t RF_cmdFs; +extern rfc_CMD_IEEE_TX_t RF_cmdIeeeTx; +extern rfc_CMD_IEEE_RX_t RF_cmdIeeeRx; + + +// RF Core API Overrides +extern uint32_t pDefaultPaOverrides[]; +extern uint32_t pHighPaOverrides[]; + + +#endif // _IEEE_SETTINGS_H_ + diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c new file mode 100644 index 000000000..f9088379d --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c @@ -0,0 +1,318 @@ +//********************************************************************************* +// Parameter summary +// Address: 0 +// Address0: 0xAA +// Address1: 0xBB +// Frequency: 915.00000 MHz +// Data Format: Serial mode disable +// Deviation: 25.000 kHz +// pktLen: 30 +// 802.15.4g Mode: 0 +// Select bit order to transmit PSDU octets:: 1 +// Packet Length Config: Variable +// Max Packet Length: 255 +// Packet Length: 20 +// Packet Data: 255 +// RX Filter BW: 98.0 kHz +// Symbol Rate: 50.00000 kBaud +// Sync Word Length: 24 Bits +// For Default PA: +// TX Power: 13.5 dBm (requires define CCFG_FORCE_VDDR_HH = 1 in ccfg.c, see CC13xx/CC26xx Technical Reference Manual) +// Enable high output power PA: false +// For High PA: +// TX Power: 20 dBm (requires define CCFG_FORCE_VDDR_HH = 0 in ccfg.c, see CC13xx/CC26xx Technical Reference Manual) +// Enable high output power PA: true +// Whitening: Dynamically IEEE 802.15.4g compatible whitener and 16/32-bit CRC + +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h) +#include DeviceFamily_constructPath(rf_patches/rf_patch_cpe_prop.h) +#include DeviceFamily_constructPath(rf_patches/rf_patch_rfe_genfsk.h) +#include DeviceFamily_constructPath(rf_patches/rf_patch_mce_genfsk.h) + +#include + +#include "prop-settings.h" + + +// TI-RTOS RF Mode Object +RF_Mode RF_propMode = +{ + .rfMode = RF_MODE_AUTO, + .cpePatchFxn = &rf_patch_cpe_prop, + .mcePatchFxn = &rf_patch_mce_genfsk, + .rfePatchFxn = &rf_patch_rfe_genfsk, +}; + + +// TX Power table +// The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: +// RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) +// See the Technical Reference Manual for further details about the "txPower" Command field. +// The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. +RF_TxPowerTable_Entry defaultPaTxPowerTable[19] = +{ + { -20, RF_TxPowerTable_DEFAULT_PA_ENTRY( 0, 3, 0, 2) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY( 1, 3, 0, 3) }, + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY( 2, 3, 0, 3) }, + { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 3, 0, 6) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 8) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 3, 0, 9) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 9) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 11) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 3, 0, 12) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 3, 0, 14) }, + { 6, RF_TxPowerTable_DEFAULT_PA_ENTRY( 6, 2, 0, 14) }, + { 7, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 1, 0, 16) }, + { 8, RF_TxPowerTable_DEFAULT_PA_ENTRY( 6, 1, 0, 19) }, + { 9, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 1, 0, 25) }, + { 10, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 40) }, + { 11, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 0, 0, 71) }, + { 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 0, 64) }, + // This setting requires CCFG_FORCE_VDDR_HH = 1. + // The original PA value (13.5 dBm) have been rounded to an integer value. + { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 0) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; + + +// TX Power table +// The RF_TxPowerTable_HIGH_PA_ENTRY macro is defined in RF.h and requires the following arguments: +// RF_TxPowerTable_HIGH_PA_ENTRY(bias, ibboost, boost, coefficient, ldoTrim) +// See the Technical Reference Manual for further details about the "txPower" Command field. +// The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. +RF_TxPowerTable_Entry highPaTxPowerTable[8] = +{ + { 14, RF_TxPowerTable_HIGH_PA_ENTRY( 7, 0, 0, 23, 4) }, + { 15, RF_TxPowerTable_HIGH_PA_ENTRY(10, 0, 0, 26, 4) }, + { 16, RF_TxPowerTable_HIGH_PA_ENTRY(14, 0, 0, 33, 4) }, + { 17, RF_TxPowerTable_HIGH_PA_ENTRY(18, 0, 0, 40, 6) }, + { 18, RF_TxPowerTable_HIGH_PA_ENTRY(24, 0, 0, 51, 8) }, + { 19, RF_TxPowerTable_HIGH_PA_ENTRY(32, 0, 0, 73, 12) }, + { 20, RF_TxPowerTable_HIGH_PA_ENTRY(27, 0, 0, 85, 32) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; + + +// Overrides for CMD_PROP_RADIO_DIV_SETUP +uint32_t pDefaultPaOverrides[] = +{ + // override_use_patch_prop_genfsk.xml + MCE_RFE_OVERRIDE(1,0,0,1,0,0), // PHY: Use MCE RAM patch, RFE RAM patch + // override_synth_prop_863_930_div5.xml + (uint32_t)0x02400403, // Synth: Use 48 MHz crystal as synth clock, enable extra PLL filtering + (uint32_t)0x00068793, // Synth: Set minimum RTRIM to 6 + (uint32_t)0x001C8473, // Synth: Configure extra PLL filtering + (uint32_t)0x00088433, // Synth: Configure extra PLL filtering + (uint32_t)0x000684A3, // Synth: Set Fref to 4 MHz + HW32_ARRAY_OVERRIDE(0x4004,1), // Synth: Configure faster calibration + (uint32_t)0x180C0618, // Synth: Configure faster calibration + (uint32_t)0xC00401A1, // Synth: Configure faster calibration + (uint32_t)0x00010101, // Synth: Configure faster calibration + (uint32_t)0xC0040141, // Synth: Configure faster calibration + (uint32_t)0x00214AD3, // Synth: Configure faster calibration + (uint32_t)0x02980243, // Synth: Decrease synth programming time-out by 90 us from default (0x0298 RAT ticks = 166 us) + (uint32_t)0x0A480583, // Synth: Set loop bandwidth after lock to 20 kHz + (uint32_t)0x7AB80603, // Synth: Set loop bandwidth after lock to 20 kHz + (uint32_t)0x00000623, // Synth: Set loop bandwidth after lock to 20 kHz + // override_phy_tx_pa_ramp_genfsk_hpa.xml + HW_REG_OVERRIDE(0x6028,0x002F), // Tx: Configure PA ramping, set wait time before turning off (0x2F ticks of 16/24 us = 31.3 us). + ADI_HALFREG_OVERRIDE(0,16,0x8,0x8), // Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[3]=1) + ADI_HALFREG_OVERRIDE(0,17,0x1,0x1), // Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[4]=1) + // override_phy_rx_frontend_genfsk.xml + HW_REG_OVERRIDE(0x609C,0x001A), // Rx: Set AGC reference level to 0x1A (default: 0x2E) + (uint32_t)0x00018883, // Rx: Set LNA bias current offset to adjust +1 (default: 0) + (uint32_t)0x000288A3, // Rx: Set RSSI offset to adjust reported RSSI by -2 dB (default: 0) + // override_phy_rx_aaf_bw_0xd.xml + ADI_HALFREG_OVERRIDE(0,61,0xF,0xD), // Rx: Set anti-aliasing filter bandwidth to 0xD (in ADI0, set IFAMPCTL3[7:4]=0xD) + // TX power override + (uint32_t)0xFFFC08C3, // DC/DC regulator: In Tx with 14 dBm PA setting, use DCDCCTL5[3:0]=0xF (DITHER_EN=1 and IPEAK=7). In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). + ADI_REG_OVERRIDE(0,12,0xF8), // Tx: Set PA trim to max to maximize its output power (in ADI0, set PACTL0=0xF8) + (uint32_t)0xFFFFFFFF, +}; + + +// Overrides for CMD_PROP_RADIO_DIV_SETUP +uint32_t pHighPaOverrides[] = +{ + // override_use_patch_prop_genfsk.xml + MCE_RFE_OVERRIDE(1,0,0,1,0,0), // PHY: Use MCE RAM patch, RFE RAM patch + // override_synth_prop_863_930_div5.xml + (uint32_t)0x02400403, // Synth: Use 48 MHz crystal as synth clock, enable extra PLL filtering + (uint32_t)0x00068793, // Synth: Set minimum RTRIM to 6 + (uint32_t)0x001C8473, // Synth: Configure extra PLL filtering + (uint32_t)0x00088433, // Synth: Configure extra PLL filtering + (uint32_t)0x000684A3, // Synth: Set Fref to 4 MHz + HW32_ARRAY_OVERRIDE(0x4004,1), // Synth: Configure faster calibration + (uint32_t)0x180C0618, // Synth: Configure faster calibration + (uint32_t)0xC00401A1, // Synth: Configure faster calibration + (uint32_t)0x00010101, // Synth: Configure faster calibration + (uint32_t)0xC0040141, // Synth: Configure faster calibration + (uint32_t)0x00214AD3, // Synth: Configure faster calibration + (uint32_t)0x02980243, // Synth: Decrease synth programming time-out by 90 us from default (0x0298 RAT ticks = 166 us) + (uint32_t)0x0A480583, // Synth: Set loop bandwidth after lock to 20 kHz + (uint32_t)0x7AB80603, // Synth: Set loop bandwidth after lock to 20 kHz + (uint32_t)0x00000623, // Synth: Set loop bandwidth after lock to 20 kHz + // override_phy_tx_pa_ramp_genfsk_hpa.xml + HW_REG_OVERRIDE(0x6028,0x002F), // Tx: Configure PA ramping, set wait time before turning off (0x2F ticks of 16/24 us = 31.3 us). + ADI_HALFREG_OVERRIDE(0,16,0x8,0x8), // Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[3]=1) + ADI_HALFREG_OVERRIDE(0,17,0x1,0x1), // Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[4]=1) + // override_phy_rx_frontend_genfsk.xml + HW_REG_OVERRIDE(0x609C,0x001A), // Rx: Set AGC reference level to 0x1A (default: 0x2E) + (uint32_t)0x00018883, // Rx: Set LNA bias current offset to adjust +1 (default: 0) + (uint32_t)0x000288A3, // Rx: Set RSSI offset to adjust reported RSSI by -2 dB (default: 0) + // override_phy_rx_aaf_bw_0xd.xml + ADI_HALFREG_OVERRIDE(0,61,0xF,0xD), // Rx: Set anti-aliasing filter bandwidth to 0xD (in ADI0, set IFAMPCTL3[7:4]=0xD) + // TX power override + (uint32_t)0xFCFC08C3, // DC/DC regulator: In Tx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). + (uint32_t)0x82A86C2B, // txHighPA=0x20AA1B + (uint32_t)0xFFFFFFFF, +}; + + +// CMD_PROP_RADIO_DIV_SETUP +// Proprietary Mode Radio Setup Command for All Frequency Bands +rfc_CMD_PROP_RADIO_DIV_SETUP_t RF_cmdPropRadioDivSetup = +{ + .commandNo = 0x3807, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .modulation.modType = 0x1, + .modulation.deviation = 0x64, + .modulation.deviationStepSz = 0x0, + .symbolRate.preScale = 0xF, + .symbolRate.rateWord = 0x8000, + .symbolRate.decimMode = 0x0, + .rxBw = 0x52, + .preamConf.nPreamBytes = 0x3, + .preamConf.preamMode = 0x0, + .formatConf.nSwBits = 0x18, + .formatConf.bBitReversal = 0x0, + .formatConf.bMsbFirst = 0x1, + .formatConf.fecMode = 0x0, + .formatConf.whitenMode = 0x7, + .config.frontEndMode = 0x0, + .config.biasMode = 0x1, + .config.analogCfgMode = 0x0, + .config.bNoFsPowerUp = 0x0, + .txPower = 0x013F, + .pRegOverride = pOverrides, + .centerFreq = 0x0393, + .intFreq = 0x8000, + .loDivider = 0x05, +}; + +// CMD_FS +// Frequency Synthesizer Programming Command +rfc_CMD_FS_t RF_cmdFs = +{ + .commandNo = 0x0803, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .frequency = 0x0393, + .fractFreq = 0x0000, + .synthConf.bTxMode = 0x0, + .synthConf.refFreq = 0x0, + .__dummy0 = 0x00, + .__dummy1 = 0x00, + .__dummy2 = 0x00, + .__dummy3 = 0x0000, +}; + +// CMD_PROP_TX_ADV +// Proprietary Mode Advanced Transmit Command +rfc_CMD_PROP_TX_ADV_t RF_cmdPropTxAdv = +{ + .commandNo = 0x3803, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x2, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x1, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .pktConf.bFsOff = 0x0, + .pktConf.bUseCrc = 0x1, + .pktConf.bCrcIncSw = 0x0, + .pktConf.bCrcIncHdr = 0x0, + .numHdrBits = 0x10, + .pktLen = 0x0014, + .startConf.bExtTxTrig = 0x0, + .startConf.inputMode = 0x0, + .startConf.source = 0x0, + .preTrigger.triggerType = 0x4, + .preTrigger.bEnaCmd = 0x0, + .preTrigger.triggerNo = 0x0, + .preTrigger.pastTrig = 0x1, + .preTime = 0x00000000, + .syncWord = 0x0055904E, + .pPkt = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx +}; + +// CMD_PROP_RX_ADV +// Proprietary Mode Advanced Receive Command +rfc_CMD_PROP_RX_ADV_t RF_cmdPropRxAdv = +{ + .commandNo = 0x3804, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .pktConf.bFsOff = 0x0, + .pktConf.bRepeatOk = 0x0, + .pktConf.bRepeatNok = 0x0, + .pktConf.bUseCrc = 0x0, + .pktConf.bCrcIncSw = 0x0, + .pktConf.bCrcIncHdr = 0x0, + .pktConf.endType = 0x0, + .pktConf.filterOp = 0x0, + .rxConf.bAutoFlushIgnored = 0x0, + .rxConf.bAutoFlushCrcErr = 0x0, + .rxConf.bIncludeHdr = 0x0, + .rxConf.bIncludeCrc = 0x0, + .rxConf.bAppendRssi = 0x0, + .rxConf.bAppendTimestamp = 0x0, + .rxConf.bAppendStatus = 0x0, + .syncWord0 = 0x930B51DE, + .syncWord1 = 0x00000000, + .maxPktLen = 0x00FF, + .hdrConf.numHdrBits = 0x0, + .hdrConf.lenPos = 0x0, + .hdrConf.numLenBits = 0x0, + .addrConf.addrType = 0x0, + .addrConf.addrSize = 0x0, + .addrConf.addrPos = 0x0, + .addrConf.numAddr = 0x0, + .lenOffset = 0x00, + .endTrigger.triggerType = 0x0, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, + .pAddr = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .pQueue = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx + .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx +}; diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h new file mode 100644 index 000000000..0fbe14b28 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h @@ -0,0 +1,40 @@ +#ifndef _PROP_SETTINGS_H_ +#define _PROP_SETTINGS_H_ + +//********************************************************************************* +// Generated by SmartRF Studio version 2.9.0 (build#85) +// Compatible with SimpleLink SDK version: CC13x2 SDK 2.10.xx.xx +// Device: CC1352P Rev. 1.1 +// +//********************************************************************************* +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h) + +#include + + +// TI-RTOS RF Mode Object +extern RF_Mode RF_propMode; + + +// Tx Power Tables +extern RF_TxPowerTable_Entry defaultPaTxPowerTable[19]; +extern RF_TxPowerTable_Entry highPaTxPowerTable[8]; + + +// RF Core API commands +extern rfc_CMD_PROP_RADIO_DIV_SETUP_t RF_cmdPropRadioDivSetup; +extern rfc_CMD_FS_t RF_cmdFs; +extern rfc_CMD_PROP_TX_ADV_t RF_cmdPropTxAdv; +extern rfc_CMD_PROP_RX_ADV_t RF_cmdPropRxAdv; + + +// RF Core API Overrides +extern uint32_t pDefaultPaOverrides[]; +extern uint32_t pHighPaOverrides[]; + + +#endif // _PROP_SETTINGS_H_ + diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c similarity index 70% rename from arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-ieee-settings.c rename to arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c index f84c413d1..dea8804a8 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/rf-settings/rf-ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c @@ -1,11 +1,3 @@ -//********************************************************************************* -// Generated by SmartRF Studio version 2.8.0 ( build #41) -// Compatible with SimpleLink SDK version: CC13x2 SDK 1.60.xx.xx -// Device: CC1352 Rev. 1.0 -// -//********************************************************************************* - - //********************************************************************************* // Parameter summary // IEEE Channel: 11 @@ -18,39 +10,13 @@ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_ieee_cmd.h) +#include DeviceFamily_constructPath(rf_patches/rf_patch_cpe_ieee.h) + #include -// This is included from the local driverlib/ directory -#include "driverlib/rf_ieee_cmd.h" -// This is included from the local rf_patches/ directory -#include "rf_patches/rf_patch_cpe_ieee.h" +#include "ieee-settings.h" -#include "rf-ieee-settings.h" -/*---------------------------------------------------------------------------*/ -// TX Power table -// The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: -// RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) -// See the Technical Reference Manual for further details about the "txPower" Command field. -// The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. -RF_TxPowerTable_Entry txPowerTable[] = -{ - {-21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 6) }, - {-18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 6) }, - {-15, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 6) }, - {-12, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 1, 0, 10) }, - { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 1, 12) }, - { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(18, 1, 1, 14) }, - { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 1, 1, 18) }, - { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(33, 1, 1, 24) }, - { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 0, 0, 33) }, - { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 0, 0, 39) }, - { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 0, 0, 45) }, - { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(36, 0, 1, 73) }, - { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(48, 0, 1, 73) }, - RF_TxPowerTable_TERMINATION_ENTRY -}; - -const size_t txPowerTableLen = sizeof(txPowerTable) / sizeof(txPowerTable[0]); // TI-RTOS RF Mode Object RF_Mode RF_ieeeMode = @@ -62,10 +28,34 @@ RF_Mode RF_ieeeMode = }; +// TX Power table +// The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: +// RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) +// See the Technical Reference Manual for further details about the "txPower" Command field. +// The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. +RF_TxPowerTable_Entry txPowerTable[14] = +{ + { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 6) }, + { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 6) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 6) }, + { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 1, 0, 10) }, + { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 1, 12) }, + { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(18, 1, 1, 14) }, + { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 1, 1, 18) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(33, 1, 1, 24) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 0, 0, 33) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 0, 0, 39) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 0, 0, 45) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(36, 0, 1, 73) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(48, 0, 1, 73) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; + + // Overrides for CMD_RADIO_SETUP uint32_t pOverrides[] = { - // override_synth_ieee_15_4.xml + // override_synth_ieee_15_4.xml HW_REG_OVERRIDE(0x4038,0x0035), // Synth: Set recommended RTRIM to 5 (uint32_t)0x000784A3, // Synth: Set Fref to 3.43 MHz (uint32_t)0xA47E0583, // Synth: Set loop bandwidth after lock to 80 kHz @@ -79,11 +69,11 @@ uint32_t pOverrides[] = HW32_ARRAY_OVERRIDE(0x4034,1), // Synth: Configure extra PLL filtering (uint32_t)0x177F0408, // Synth: Configure extra PLL filtering (uint32_t)0x38000463, // Synth: Configure extra PLL filtering - (uint32_t)0x05000243, // Synth: Increase synth programming timeout // override_phy_ieee_15_4.xml + (uint32_t)0x05000243, // Synth: Increase synth programming timeout (uint32_t)0x002082C3, // Rx: Adjust Rx FIFO threshold to avoid overflow - (uint32_t)0x000288A3, // Rx: Set RSSI offset to adjust reported RSSI by -2 dB // override_frontend_id.xml + (uint32_t)0x000288A3, // Rx: Set RSSI offset to adjust reported RSSI by -2 dB (uint32_t)0x000F8883, // Rx: Configure LNA bias current trim offset HW_REG_OVERRIDE(0x50DC,0x002B), // Rx: Adjust AGC DC filter (uint32_t)0xFFFFFFFF, @@ -105,16 +95,15 @@ rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup = .condition.rule = 0x1, .condition.nSkip = 0x0, .mode = 0x01, - .loDivider = 0x00, + .__dummy0 = 0x00, .config.frontEndMode = 0x0, .config.biasMode = 0x0, .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, - .txPower = 0x001F, + .txPower = 0x9330, .pRegOverride = pOverrides, }; - // CMD_FS // Frequency Synthesizer Programming Command rfc_CMD_FS_t RF_cmdFs = @@ -131,7 +120,7 @@ rfc_CMD_FS_t RF_cmdFs = .condition.nSkip = 0x0, .frequency = 0x0965, .fractFreq = 0x0000, - .synthConf.bTxMode = 0x0, + .synthConf.bTxMode = 0x1, .synthConf.refFreq = 0x0, .__dummy0 = 0x00, .__dummy1 = 0x00, @@ -139,72 +128,8 @@ rfc_CMD_FS_t RF_cmdFs = .__dummy3 = 0x0000, }; - -// CMD_IEEE_RX -// IEEE 802.15.4 Receive Command -rfc_CMD_IEEE_RX_t RF_cmdIeeeRx = -{ - .commandNo = CMD_IEEE_RX, - .status = IDLE, - .pNextOp = NULL, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .condition.rule = COND_NEVER, - .channel = 0, - .rxConfig.bAutoFlushCrc = 0x1, - .rxConfig.bAutoFlushIgn = 0x0, - .rxConfig.bIncludePhyHdr = 0x0, - .rxConfig.bIncludeCrc = 0x1, - .rxConfig.bAppendRssi = 0x1, - .rxConfig.bAppendCorrCrc = 0x1, - .rxConfig.bAppendSrcInd = 0x0, - .rxConfig.bAppendTimestamp = 0x1, - .pRxQ = NULL, - .pOutput = NULL, - .frameFiltOpt.frameFiltEn = 0x0, - .frameFiltOpt.frameFiltStop = 0x1, - .frameFiltOpt.autoAckEn = 0x0, - .frameFiltOpt.slottedAckEn = 0x0, - .frameFiltOpt.autoPendEn = 0x0, - .frameFiltOpt.defaultPend = 0x0, - .frameFiltOpt.bPendDataReqOnly = 0x0, - .frameFiltOpt.bPanCoord = 0x0, - .frameFiltOpt.maxFrameVersion = 0x2, - .frameFiltOpt.fcfReservedMask = 0x0, - .frameFiltOpt.modifyFtFilter = 0x0, - .frameFiltOpt.bStrictLenFilter = 0x0, - .frameTypes.bAcceptFt0Beacon = 0x1, - .frameTypes.bAcceptFt1Data = 0x1, - .frameTypes.bAcceptFt2Ack = 0x1, - .frameTypes.bAcceptFt3MacCmd = 0x1, - .frameTypes.bAcceptFt4Reserved = 0x1, - .frameTypes.bAcceptFt5Reserved = 0x1, - .frameTypes.bAcceptFt6Reserved = 0x1, - .frameTypes.bAcceptFt7Reserved = 0x1, - .ccaOpt.ccaEnEnergy = 0x1, - .ccaOpt.ccaEnCorr = 0x1, - .ccaOpt.ccaEnSync = 0x1, - .ccaOpt.ccaCorrOp = 0x1, - .ccaOpt.ccaSyncOp = 0x0, - .ccaOpt.ccaCorrThr = 0x3, - .ccaRssiThr = 0x64, - .numExtEntries = 0x00, - .numShortEntries = 0x00, - .pExtEntryList = NULL, - .pShortEntryList = NULL, - .localExtAddr = 0x0000000012345678, - .localShortAddr = 0xABBA, - .localPanID = 0x0000, - .endTrigger.triggerType = TRIG_NEVER, - .endTrigger.bEnaCmd = 0x0, - .endTrigger.triggerNo = 0x0, - .endTrigger.pastTrig = 0x0, - .endTime = 0x00000000, -}; - - // CMD_IEEE_TX -// IEEE 802.15.4 Transmit Command +// The command ID number 0x2C01 rfc_CMD_IEEE_TX_t RF_cmdIeeeTx = { .commandNo = 0x2C01, @@ -225,3 +150,70 @@ rfc_CMD_IEEE_TX_t RF_cmdIeeeTx = .timeStamp = 0x00000000, }; +// CMD_IEEE_RX +// The command ID number 0x2801 +rfc_CMD_IEEE_RX_t RF_cmdIeeeRx = +{ + .commandNo = 0x2801, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .channel = 0x00, + .rxConfig.bAutoFlushCrc = 0x0, + .rxConfig.bAutoFlushIgn = 0x0, + .rxConfig.bIncludePhyHdr = 0x0, + .rxConfig.bIncludeCrc = 0x0, + .rxConfig.bAppendRssi = 0x1, + .rxConfig.bAppendCorrCrc = 0x1, + .rxConfig.bAppendSrcInd = 0x0, + .rxConfig.bAppendTimestamp = 0x0, + .pRxQ = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx + .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .frameFiltOpt.frameFiltEn = 0x0, + .frameFiltOpt.frameFiltStop = 0x0, + .frameFiltOpt.autoAckEn = 0x0, + .frameFiltOpt.slottedAckEn = 0x0, + .frameFiltOpt.autoPendEn = 0x0, + .frameFiltOpt.defaultPend = 0x0, + .frameFiltOpt.bPendDataReqOnly = 0x0, + .frameFiltOpt.bPanCoord = 0x0, + .frameFiltOpt.maxFrameVersion = 0x3, + .frameFiltOpt.fcfReservedMask = 0x0, + .frameFiltOpt.modifyFtFilter = 0x0, + .frameFiltOpt.bStrictLenFilter = 0x0, + .frameTypes.bAcceptFt0Beacon = 0x1, + .frameTypes.bAcceptFt1Data = 0x1, + .frameTypes.bAcceptFt2Ack = 0x1, + .frameTypes.bAcceptFt3MacCmd = 0x1, + .frameTypes.bAcceptFt4Reserved = 0x1, + .frameTypes.bAcceptFt5Reserved = 0x1, + .frameTypes.bAcceptFt6Reserved = 0x1, + .frameTypes.bAcceptFt7Reserved = 0x1, + .ccaOpt.ccaEnEnergy = 0x0, + .ccaOpt.ccaEnCorr = 0x0, + .ccaOpt.ccaEnSync = 0x0, + .ccaOpt.ccaCorrOp = 0x1, + .ccaOpt.ccaSyncOp = 0x1, + .ccaOpt.ccaCorrThr = 0x0, + .ccaRssiThr = 0x64, + .__dummy0 = 0x00, + .numExtEntries = 0x00, + .numShortEntries = 0x00, + .pExtEntryList = 0, // INSERT APPLICABLE POINTER: (uint32_t*)&xxx + .pShortEntryList = 0, // INSERT APPLICABLE POINTER: (uint32_t*)&xxx + .localExtAddr = 0x0000000012345678, + .localShortAddr = 0xABBA, + .localPanID = 0x0000, + .__dummy1 = 0x000000, + .endTrigger.triggerType = 0x1, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, +}; diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h new file mode 100644 index 000000000..a26616ad3 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h @@ -0,0 +1,37 @@ +#ifndef _IEEE_SETTINGS_H_ +#define _IEEE_SETTINGS_H_ + +//********************************************************************************* +// Generated by SmartRF Studio version 2.9.0 (build#85) +// Compatible with SimpleLink SDK version: No known SDK for this device +// Device: CC2650 Rev. 2.2 +// +//********************************************************************************* +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_ieee_cmd.h) + +#include + + +// TI-RTOS RF Mode Object +extern RF_Mode RF_ieeeMode; + + +// TX Power Table +extern RF_TxPowerTable_Entry txPowerTable[14]; + +// RF Core API commands +extern rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup; +extern rfc_CMD_FS_t RF_cmdFs; +extern rfc_CMD_IEEE_TX_t RF_cmdIeeeTx; +extern rfc_CMD_IEEE_RX_t RF_cmdIeeeRx; + + +// RF Core API Overrides +extern uint32_t pOverrides[]; + + +#endif // _IEEE_SETTINGS_H_ + diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c new file mode 100644 index 000000000..fba191773 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c @@ -0,0 +1,216 @@ +//********************************************************************************* +// Parameter summary +// IEEE Channel: 11 +// Frequency: 2405 MHz +// SFD: 0 +// Packet Data: 255 +// Preamble (32 bit): 01010101... +// TX Power: 5 dBm + +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_ieee_cmd.h) +#include DeviceFamily_constructPath(rf_patches/rf_patch_cpe_ieee_802_15_4.h) +#include DeviceFamily_constructPath(rf_patches/rf_patch_mce_ieee_802_15_4.h) + +#include + +#include "ieee-settings.h" + + +// TI-RTOS RF Mode Object +RF_Mode RF_propMode = +{ + .rfMode = RF_MODE_AUTO, + .cpePatchFxn = &rf_patch_cpe_ieee_802_15_4, + .mcePatchFxn = &rf_patch_mce_ieee_802_15_4, + .rfePatchFxn = 0, +}; + + +// TX Power table +// The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: +// RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) +// See the Technical Reference Manual for further details about the "txPower" Command field. +// The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. +RF_TxPowerTable_Entry txPowerTable[16] = +{ + { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY(7, 3, 0, 3) }, + { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY(9, 3, 0, 3) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 100) }, + { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(40, 2, 0, 8) }, + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 11) }, + { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 2, 0, 5) }, + { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 16) }, + { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 17) }, + { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 1, 0, 20) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(25, 1, 0, 26) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 1, 0, 28) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 0, 0, 34) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 0, 0, 42) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 0, 0, 54) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; + + +// Overrides for CMD_RADIO_SETUP +uint32_t pOverrides[] = +{ + // override_ieee_802_15_4.xml + MCE_RFE_OVERRIDE(1,0,0,0,1,0), // PHY: Use MCE RAM patch, RFE ROM bank 1 + (uint32_t)0x02400403, // Synth: Use 48 MHz crystal, enable extra PLL filtering + (uint32_t)0x001C8473, // Synth: Configure extra PLL filtering + (uint32_t)0x00088433, // Synth: Configure synth hardware + (uint32_t)0x00038793, // Synth: Set minimum RTRIM to 3 + HW32_ARRAY_OVERRIDE(0x4004,1), // Synth: Configure faster calibration + (uint32_t)0x1C0C0618, // Synth: Configure faster calibration + (uint32_t)0xC00401A1, // Synth: Configure faster calibration + (uint32_t)0x00010101, // Synth: Configure faster calibration + (uint32_t)0xC0040141, // Synth: Configure faster calibration + (uint32_t)0x00214AD3, // Synth: Configure faster calibration + (uint32_t)0x02980243, // Synth: Decrease synth programming time-out (0x0298 RAT ticks = 166 us) + (uint32_t)0xFCFC08C3, // DC/DC regulator: In Tx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). + (uint32_t)0x000F8883, // Rx: Set LNA bias current offset to +15 to saturate trim to max (default: 0) + (uint32_t)0xFFFFFFFF, +}; + + +// CMD_RADIO_SETUP +// Radio Setup Command for Pre-Defined Schemes +rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup = +{ + .commandNo = 0x0802, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .mode = 0x01, + .loDivider = 0x00, + .config.frontEndMode = 0x0, + .config.biasMode = 0x0, + .config.analogCfgMode = 0x0, + .config.bNoFsPowerUp = 0x0, + .txPower = 0x941E, + .pRegOverride = pOverrides, +}; + +// CMD_FS +// Frequency Synthesizer Programming Command +rfc_CMD_FS_t RF_cmdFs = +{ + .commandNo = 0x0803, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .frequency = 0x0965, + .fractFreq = 0x0000, + .synthConf.bTxMode = 0x1, + .synthConf.refFreq = 0x0, + .__dummy0 = 0x00, + .__dummy1 = 0x00, + .__dummy2 = 0x00, + .__dummy3 = 0x0000, +}; + +// CMD_IEEE_TX +// IEEE 802.15.4 Transmit Command +rfc_CMD_IEEE_TX_t RF_cmdIeeeTx = +{ + .commandNo = 0x2C01, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .txOpt.bIncludePhyHdr = 0x0, + .txOpt.bIncludeCrc = 0x0, + .txOpt.payloadLenMsb = 0x0, + .payloadLen = 0x1E, + .pPayload = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .timeStamp = 0x00000000, +}; + +// CMD_IEEE_RX +// IEEE 802.15.4 Receive Command +rfc_CMD_IEEE_RX_t RF_cmdIeeeRx = +{ + .commandNo = 0x2801, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .channel = 0x00, + .rxConfig.bAutoFlushCrc = 0x0, + .rxConfig.bAutoFlushIgn = 0x0, + .rxConfig.bIncludePhyHdr = 0x0, + .rxConfig.bIncludeCrc = 0x0, + .rxConfig.bAppendRssi = 0x1, + .rxConfig.bAppendCorrCrc = 0x1, + .rxConfig.bAppendSrcInd = 0x0, + .rxConfig.bAppendTimestamp = 0x0, + .pRxQ = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx + .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .frameFiltOpt.frameFiltEn = 0x0, + .frameFiltOpt.frameFiltStop = 0x0, + .frameFiltOpt.autoAckEn = 0x0, + .frameFiltOpt.slottedAckEn = 0x0, + .frameFiltOpt.autoPendEn = 0x0, + .frameFiltOpt.defaultPend = 0x0, + .frameFiltOpt.bPendDataReqOnly = 0x0, + .frameFiltOpt.bPanCoord = 0x0, + .frameFiltOpt.maxFrameVersion = 0x3, + .frameFiltOpt.fcfReservedMask = 0x0, + .frameFiltOpt.modifyFtFilter = 0x0, + .frameFiltOpt.bStrictLenFilter = 0x0, + .frameTypes.bAcceptFt0Beacon = 0x1, + .frameTypes.bAcceptFt1Data = 0x1, + .frameTypes.bAcceptFt2Ack = 0x1, + .frameTypes.bAcceptFt3MacCmd = 0x1, + .frameTypes.bAcceptFt4Reserved = 0x1, + .frameTypes.bAcceptFt5Reserved = 0x1, + .frameTypes.bAcceptFt6Reserved = 0x1, + .frameTypes.bAcceptFt7Reserved = 0x1, + .ccaOpt.ccaEnEnergy = 0x0, + .ccaOpt.ccaEnCorr = 0x0, + .ccaOpt.ccaEnSync = 0x0, + .ccaOpt.ccaCorrOp = 0x1, + .ccaOpt.ccaSyncOp = 0x1, + .ccaOpt.ccaCorrThr = 0x0, + .ccaRssiThr = 0x64, + .__dummy0 = 0x00, + .numExtEntries = 0x00, + .numShortEntries = 0x00, + .pExtEntryList = 0, // INSERT APPLICABLE POINTER: (uint32_t*)&xxx + .pShortEntryList = 0, // INSERT APPLICABLE POINTER: (uint32_t*)&xxx + .localExtAddr = 0x0000000012345678, + .localShortAddr = 0xABBA, + .localPanID = 0x0000, + .__dummy1 = 0x000000, + .endTrigger.triggerType = 0x1, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, +}; diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h new file mode 100644 index 000000000..a0cbb3abd --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h @@ -0,0 +1,38 @@ +#ifndef _IEEE_SETTINGS_H_ +#define _IEEE_SETTINGS_H_ + +//********************************************************************************* +// Generated by SmartRF Studio version 2.9.0 (build#85) +// Compatible with SimpleLink SDK version: CC26x2 SDK 2.10.xx.xx +// Device: CC2652R Rev. 1.1 +// +//********************************************************************************* +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_ieee_cmd.h) + +#include + + +// TI-RTOS RF Mode Object +extern RF_Mode RF_propMode; + + +// TX Power Table +extern RF_TxPowerTable_Entry txPowerTable[16]; + + +// RF Core API commands +extern rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup; +extern rfc_CMD_FS_t RF_cmdFs; +extern rfc_CMD_IEEE_TX_t RF_cmdIeeeTx; +extern rfc_CMD_IEEE_RX_t RF_cmdIeeeRx; + + +// RF Core API Overrides +extern uint32_t pOverrides[]; + + +#endif // _IEEE_SETTINGS_H_ + diff --git a/arch/platform/simplelink/Makefile.device-family b/arch/platform/simplelink/Makefile.device-family deleted file mode 100644 index 64af7c432..000000000 --- a/arch/platform/simplelink/Makefile.device-family +++ /dev/null @@ -1,79 +0,0 @@ -################################################################################ -# Simplelink Device family switch - -# A couple of comments: -# - CC26X0R2 is not supported even though it has its own Device SDK, because -# it is a BLE-only chip. -# - CC26X0 overrides the Device Makefile because it doesn't have its own -# Device SDK. Instead, it uses the TI-RTOS SDK, and therefore cannot -# use the same build structure as all other SimpleLink SDK Devices. - -# Device name in lower case (LC) -SIMPLELINK_FAMILY_LC := $(shell echo $(SIMPLELINK_FAMILY) | tr A-Z a-z) -# Device name in upper case (UC) -SIMPLELINK_FAMILY_UC := $(shell echo $(SIMPLELINK_FAMILY) | tr a-z A-Z) - -################################################################################ -# All supported SimpleLink Devices -SIMPLELINK_FAMILIES = cc13x0 cc13x2 cc26x0 cc26x2 - -################################################################################ -# CC13X0/CC26X0 Family - -# CC13X0 -ifeq ($(SIMPLELINK_FAMILY_LC),cc13x0) -PLATFORM_FAMILY_DIR := cc13x0-cc26x0 -DEVICE_FAMILY := DeviceFamily_CC13X0 -CFLAGS += -D$(DEVICE_FAMILY) - -# CC26X0 -else ifeq ($(SIMPLELINK_FAMILY_LC),cc26x0) -PLATFORM_FAMILY_DIR := cc13x0-cc26x0 -DEVICE_MAKEFILE := cc26x0 -DEVICE_FAMILY := DeviceFamily_CC26X0 -CFLAGS += -D$(DEVICE_FAMILY) - -################################################################################ -# CC13X2/CC26X2 Family - -# CC13X2 -else ifeq ($(SIMPLELINK_FAMILY_LC),cc13x2) -PLATFORM_FAMILY_DIR := cc13x2-cc26x2 -DEVICE_FAMILY := DeviceFamily_CC13X2 -CFLAGS += -D$(DEVICE_FAMILY) - -# CC26X2 -else ifeq ($(SIMPLELINK_FAMILY_LC),cc26x2) -PLATFORM_FAMILY_DIR := cc13x2-cc26x2 -DEVICE_FAMILY := DeviceFamily_CC26X2 -CFLAGS += -D$(DEVICE_FAMILY) - -################################################################################ -# Specified Device not supported -else - $(error Simplelink Device '$(SIMPLELINK_FAMILY)' is not supported) -endif - -################################################################################ -# By default, the Device Makefile is common for all Devices in the Device Family -# unless overriden -ifndef DEVICE_MAKEFILE -DEVICE_MAKEFILE := $(PLATFORM_FAMILY_DIR) -endif - -PLATFORM_ROOT_DIR := $(SIMPLELINK_PATH)/$(PLATFORM_FAMILY_DIR) - -# Include the Family-specific Makefile -include $(PLATFORM_ROOT_DIR)/Makefile.$(DEVICE_MAKEFILE) - -# The dirs in CONTIKI_TARGET_DIRS will be appended the target makefile directory -# in Makefile.include as part of the CONTIKI_TARGET_DIRS_CONCAT variable, -# however, this does not take into account that the Simplelink platform has one -# more indirection of directories based on device families. This fixes the added -# indirection. -CONTIKI_TARGET_DIRS := $(addprefix $(PLATFORM_FAMILY_DIR)/, $(CONTIKI_TARGET_DIRS)) - -################################################################################ -# Rule for printing supported devices -simplelink_families: - @echo "$(SIMPLELINK_FAMILIES) (current: $(SIMPLELINK_FAMILY_LC))" diff --git a/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index 45f946e92..b0f94173e 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -22,6 +22,8 @@ endif BOARD_PATH := $(FAMILY_PATH)/$(BOARD) include $(BOARD_PATH)/Makefile.$(notdir $(BOARD)) +DEVICE_FAMILY_LC := $(shell echo "$(DEVICE_FAMILY)" | tr A-Z a-z) + # Add to the source dirs TARGET_FAMILY_DIRS += common TARGET_FAMILY_DIRS += $(BOARD) @@ -44,17 +46,11 @@ CONTIKI_TARGET_SOURCEFILES += $(BOARD_SOURCEFILES) CONTIKI_SOURCEFILES += $(CONTIKI_TARGET_SOURCEFILES) -# TODO fix for CC26x0 -ifeq ($(DEVICE_FAMILY),CC26X0) - # Pull in the correct CPU makefile - CPU_FAMILY = cc26x0 -else - # Pull in the correct CPU makefile - CPU_FAMILY = cc13xx-cc26xx -endif +# Pull in the correct CPU makefile +CPU_FAMILY = cc13xx-cc26xx # Define the CPU directory and pull in the correct CPU Makefile -CONTIKI_CPU := $(realpath $(CONTIKI)/arch/cpu/cc13xx-cc26xx) +CONTIKI_CPU := $(realpath $(CONTIKI)/arch/cpu/$(CPU_FAMILY)) include $(CONTIKI_CPU)/Makefile.$(CPU_FAMILY) MODULES += os/net os/net/mac os/net/mac/framer diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Makefile.cc1310 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Makefile.cc1310 index c372170bb..557be269d 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Makefile.cc1310 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Makefile.cc1310 @@ -9,6 +9,8 @@ BOARD_SOURCEFILES += CC1310_LAUNCHXL.c SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 0 +SUPPORTS_HIGH_PA = 0 + ### Signal that we can be programmed with cc2538-bsl BOARD_SUPPORTS_BSL = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 index 08ca5b89e..f4a502c13 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 @@ -9,6 +9,8 @@ BOARD_SOURCEFILES += CC1312R1_LAUNCHXL.c SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 0 +SUPPORTS_HIGH_PA = 0 + ### Signal that we can be programmed with cc2538-bsl BOARD_SUPPORTS_BSL = 0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Makefile.cc1350-4 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Makefile.cc1350-4 index 23e5803f3..cef7ebb0d 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Makefile.cc1350-4 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Makefile.cc1350-4 @@ -9,6 +9,8 @@ BOARD_SOURCEFILES += CC1350_LAUNCHXL_433.c SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 1 +SUPPORTS_HIGH_PA = 0 + ### Signal that we can be programmed with cc2538-bsl BOARD_SUPPORTS_BSL = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Makefile.cc1350 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Makefile.cc1350 index 51a6a0a44..f8e8e4228 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Makefile.cc1350 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Makefile.cc1350 @@ -9,6 +9,8 @@ BOARD_SOURCEFILES += CC1350_LAUNCHXL.c SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 1 +SUPPORTS_HIGH_PA = 0 + ### Signal that we can be programmed with cc2538-bsl BOARD_SUPPORTS_BSL = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 index cdbb5c3e8..a26703c3d 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 @@ -9,6 +9,8 @@ BOARD_SOURCEFILES += CC1352P1_LAUNCHXL.c SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 1 +SUPPORTS_HIGH_PA = 1 + ### Signal that we can be programmed with cc2538-bsl BOARD_SUPPORTS_BSL = 0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 index 6a38d4b40..fe99fd680 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 @@ -9,6 +9,8 @@ BOARD_SOURCEFILES += CC1352R1_LAUNCHXL.c SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 1 +SUPPORTS_HIGH_PA = 0 + ### Signal that we can be programmed with cc2538-bsl BOARD_SUPPORTS_BSL = 0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Board.h index be7b817db..72f5cb42d 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Board.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, Texas Instruments Incorporated + * Copyright (c) 2015-2018, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,49 +33,111 @@ #ifndef __BOARD_H #define __BOARD_H +#define Board_CC2650_LAUNCHXL + #ifdef __cplusplus extern "C" { #endif -#include - #include "CC2650_LAUNCHXL.h" +#define Board_initGeneral() CC2650_LAUNCHXL_initGeneral() +#define Board_shutDownExtFlash() CC2650_LAUNCHXL_shutDownExtFlash() +#define Board_wakeUpExtFlash() CC2650_LAUNCHXL_wakeUpExtFlash() + /* These #defines allow us to reuse TI-RTOS across other device families */ -#define Board_LED0 Board_RLED -#define Board_LED1 Board_GLED -#define Board_LED2 Board_LED0 +#define Board_ADC0 CC2650_LAUNCHXL_ADC0 +#define Board_ADC1 CC2650_LAUNCHXL_ADC1 -#define Board_BUTTON0 Board_BTN1 -#define Board_BUTTON1 Board_BTN2 +#define Board_ADCBUF0 CC2650_LAUNCHXL_ADCBUF0 +#define Board_ADCBUF0CHANNEL0 CC2650_LAUNCHXL_ADCBUF0CHANNEL0 +#define Board_ADCBUF0CHANNEL1 CC2650_LAUNCHXL_ADCBUF0CHANNEL1 -#define Board_UART0 Board_UART -#define Board_AES0 Board_AES -#define Board_WATCHDOG0 CC2650_LAUNCHXL_WATCHDOG0 +#define Board_CRYPTO0 CC2650_LAUNCHXL_CRYPTO0 -#define Board_ADC0 CC2650_LAUNCHXL_ADCVSS -#define Board_ADC1 CC2650_LAUNCHXL_ADCVDDS +#define Board_DIO0 CC2650_LAUNCHXL_DIO0 +#define Board_DIO1_RFSW CC2650_LAUNCHXL_DIO1_RFSW +#define Board_DIO12 CC2650_LAUNCHXL_DIO12 +#define Board_DIO15 CC2650_LAUNCHXL_DIO15 +#define Board_DIO16_TDO CC2650_LAUNCHXL_DIO16_TDO +#define Board_DIO17_TDI CC2650_LAUNCHXL_DIO17_TDI +#define Board_DIO21 CC2650_LAUNCHXL_DIO21 +#define Board_DIO22 CC2650_LAUNCHXL_DIO22 -#define Board_ADCBuf0 CC2650_LAUNCHXL_ADCBuf0 -#define Board_ADCBufChannel0 (0) -#define Board_ADCBufChannel1 (1) +#define Board_DIO23_ANALOG CC2650_LAUNCHXL_DIO23_ANALOG +#define Board_DIO24_ANALOG CC2650_LAUNCHXL_DIO24_ANALOG +#define Board_DIO25_ANALOG CC2650_LAUNCHXL_DIO25_ANALOG +#define Board_DIO26_ANALOG CC2650_LAUNCHXL_DIO26_ANALOG +#define Board_DIO27_ANALOG CC2650_LAUNCHXL_DIO27_ANALOG +#define Board_DIO28_ANALOG CC2650_LAUNCHXL_DIO28_ANALOG +#define Board_DIO29_ANALOG CC2650_LAUNCHXL_DIO29_ANALOG +#define Board_DIO30_ANALOG CC2650_LAUNCHXL_DIO30_ANALOG -#define Board_initGeneral() { \ - Power_init(); \ - if (PIN_init(BoardGpioInitTable) != PIN_SUCCESS) \ - {System_abort("Error with PIN_init\n"); \ - } \ -} +#define Board_GPIO_BUTTON0 CC2650_LAUNCHXL_GPIO_S1 +#define Board_GPIO_BUTTON1 CC2650_LAUNCHXL_GPIO_S2 +#define Board_GPIO_BTN1 CC2650_LAUNCHXL_GPIO_S1 +#define Board_GPIO_BTN2 CC2650_LAUNCHXL_GPIO_S2 +#define Board_GPIO_LED0 CC2650_LAUNCHXL_GPIO_LED_RED +#define Board_GPIO_LED1 CC2650_LAUNCHXL_GPIO_LED_GREEN +#define Board_GPIO_RLED CC2650_LAUNCHXL_GPIO_LED_RED +#define Board_GPIO_GLED CC2650_LAUNCHXL_GPIO_LED_GREEN +#define Board_GPIO_LED_ON CC2650_LAUNCHXL_GPIO_LED_ON +#define Board_GPIO_LED_OFF CC2650_LAUNCHXL_GPIO_LED_OFF -#define Board_initGPIO() -#define Board_initPWM() PWM_init() -#define Board_initSPI() SPI_init() -#define Board_initUART() UART_init() -#define Board_initWatchdog() Watchdog_init() -#define Board_initADCBuf() ADCBuf_init() -#define Board_initADC() ADC_init() -#define GPIO_toggle(n) -#define GPIO_write(n,m) +#define Board_GPTIMER0A CC2650_LAUNCHXL_GPTIMER0A +#define Board_GPTIMER0B CC2650_LAUNCHXL_GPTIMER0B +#define Board_GPTIMER1A CC2650_LAUNCHXL_GPTIMER1A +#define Board_GPTIMER1B CC2650_LAUNCHXL_GPTIMER1B +#define Board_GPTIMER2A CC2650_LAUNCHXL_GPTIMER2A +#define Board_GPTIMER2B CC2650_LAUNCHXL_GPTIMER2B +#define Board_GPTIMER3A CC2650_LAUNCHXL_GPTIMER3A +#define Board_GPTIMER3B CC2650_LAUNCHXL_GPTIMER3B + +#define Board_I2C0 CC2650_LAUNCHXL_I2C0 +#define Board_I2C_TMP CC2650_LAUNCHXL_I2C0 + +#define Board_NVSINTERNAL CC2650_LAUNCHXL_NVSCC26XX0 +#define Board_NVSEXTERNAL CC2650_LAUNCHXL_NVSSPI25X0 + +#define Board_PIN_BUTTON0 CC2650_LAUNCHXL_PIN_BTN1 +#define Board_PIN_BUTTON1 CC2650_LAUNCHXL_PIN_BTN2 +#define Board_PIN_BTN1 CC2650_LAUNCHXL_PIN_BTN1 +#define Board_PIN_BTN2 CC2650_LAUNCHXL_PIN_BTN2 +#define Board_PIN_LED0 CC2650_LAUNCHXL_PIN_RLED +#define Board_PIN_LED1 CC2650_LAUNCHXL_PIN_GLED +#define Board_PIN_LED2 CC2650_LAUNCHXL_PIN_RLED +#define Board_PIN_RLED CC2650_LAUNCHXL_PIN_RLED +#define Board_PIN_GLED CC2650_LAUNCHXL_PIN_GLED + +#define Board_PWM0 CC2650_LAUNCHXL_PWM0 +#define Board_PWM1 CC2650_LAUNCHXL_PWM1 +#define Board_PWM2 CC2650_LAUNCHXL_PWM2 +#define Board_PWM3 CC2650_LAUNCHXL_PWM3 +#define Board_PWM4 CC2650_LAUNCHXL_PWM4 +#define Board_PWM5 CC2650_LAUNCHXL_PWM5 +#define Board_PWM6 CC2650_LAUNCHXL_PWM6 +#define Board_PWM7 CC2650_LAUNCHXL_PWM7 + +#define Board_SD0 CC2650_LAUNCHXL_SDSPI0 + +#define Board_SPI0 CC2650_LAUNCHXL_SPI0 +#define Board_SPI1 CC2650_LAUNCHXL_SPI1 +#define Board_SPI_FLASH_CS CC2650_LAUNCHXL_SPI_FLASH_CS +#define Board_FLASH_CS_ON 0 +#define Board_FLASH_CS_OFF 1 + +#define Board_SPI_MASTER CC2650_LAUNCHXL_SPI0 +#define Board_SPI_SLAVE CC2650_LAUNCHXL_SPI0 +#define Board_SPI_MASTER_READY CC2650_LAUNCHXL_SPI_MASTER_READY +#define Board_SPI_SLAVE_READY CC2650_LAUNCHXL_SPI_SLAVE_READY + +#define Board_UART0 CC2650_LAUNCHXL_UART0 + +#define Board_WATCHDOG0 CC2650_LAUNCHXL_WATCHDOG0 + +/* Board specific I2C addresses */ +#define Board_TMP_ADDR (0x40) +#define Board_SENSORS_BP_TMP_ADDR Board_TMP_ADDR #ifdef __cplusplus } diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.c index 3571cca94..7f2f0ef8b 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Texas Instruments Incorporated + * Copyright (c) 2016-2018, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,295 +33,202 @@ /* * ====================== CC2650_LAUNCHXL.c =================================== * This file is responsible for setting up the board specific items for the - * CC2650 LaunchPad. + * CC2650_LAUNCHXL board. */ +#include +#include +#include + +#include +#include +#include +#include + +#include "CC2650_LAUNCHXL.h" /* - * ====================== Includes ============================================ + * =============================== ADCBuf =============================== */ -#include -#include +#include +#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include +ADCBufCC26XX_Object adcBufCC26xxObjects[CC2650_LAUNCHXL_ADCBUFCOUNT]; /* - * ========================= IO driver initialization ========================= - * From main, PIN_init(BoardGpioInitTable) should be called to setup safe - * settings for this board. - * When a pin is allocated and then de-allocated, it will revert to the state - * configured in this table. + * This table converts a virtual adc channel into a dio and internal analogue + * input signal. This table is necessary for the functioning of the adcBuf + * driver. Comment out unused entries to save flash. Dio and internal signal + * pairs are hardwired. Do not remap them in the table. You may reorder entire + * entries. The mapping of dio and internal signals is package dependent. */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(BoardGpioInitTable, ".const:BoardGpioInitTable") -#pragma DATA_SECTION(PINCC26XX_hwAttrs, ".const:PINCC26XX_hwAttrs") -#endif - -const PIN_Config BoardGpioInitTable[] = { - - Board_RLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ - Board_GLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ - Board_BTN1 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ - Board_BTN2 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ - Board_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ - Board_UART_RX | PIN_INPUT_EN | PIN_PULLDOWN, /* UART RX via debugger back channel */ - Board_UART_TX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* UART TX via debugger back channel */ - Board_SPI0_MOSI | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master out - slave in */ - Board_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master in - slave out */ - Board_SPI0_CLK | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI clock */ - - PIN_TERMINATE +const ADCBufCC26XX_AdcChannelLutEntry ADCBufCC26XX_adcChannelLut[CC2650_LAUNCHXL_ADCBUF0CHANNELCOUNT] = { + {CC2650_LAUNCHXL_DIO23_ANALOG, ADC_COMPB_IN_AUXIO7}, + {CC2650_LAUNCHXL_DIO24_ANALOG, ADC_COMPB_IN_AUXIO6}, + {CC2650_LAUNCHXL_DIO25_ANALOG, ADC_COMPB_IN_AUXIO5}, + {CC2650_LAUNCHXL_DIO26_ANALOG, ADC_COMPB_IN_AUXIO4}, + {CC2650_LAUNCHXL_DIO27_ANALOG, ADC_COMPB_IN_AUXIO3}, + {CC2650_LAUNCHXL_DIO28_ANALOG, ADC_COMPB_IN_AUXIO2}, + {CC2650_LAUNCHXL_DIO29_ANALOG, ADC_COMPB_IN_AUXIO1}, + {CC2650_LAUNCHXL_DIO30_ANALOG, ADC_COMPB_IN_AUXIO0}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VDDS}, + {PIN_UNASSIGNED, ADC_COMPB_IN_DCOUPL}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VSS}, }; -const PINCC26XX_HWAttrs PINCC26XX_hwAttrs = { - .intPriority = ~0, - .swiPriority = 0 -}; -/*============================================================================*/ - -/* - * ============================= Power begin ================================== - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(PowerCC26XX_config, ".const:PowerCC26XX_config") -#endif -const PowerCC26XX_Config PowerCC26XX_config = { - .policyInitFxn = NULL, - .policyFxn = &PowerCC26XX_standbyPolicy, - .calibrateFxn = &PowerCC26XX_calibrate, - .enablePolicy = TRUE, - .calibrateRCOSC_LF = TRUE, - .calibrateRCOSC_HF = TRUE, -}; -/* - * ============================= Power end ==================================== - */ - -/* - * ============================= UART begin =================================== - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(UART_config, ".const:UART_config") -#pragma DATA_SECTION(uartCC26XXHWAttrs, ".const:uartCC26XXHWAttrs") -#endif - -/* Include drivers */ -#include -#include - -/* UART objects */ -UARTCC26XX_Object uartCC26XXObjects[CC2650_LAUNCHXL_UARTCOUNT]; -unsigned char uartCC26XXRingBuffer[CC2650_LAUNCHXL_UARTCOUNT][32]; - -/* UART hardware parameter structure, also used to assign UART pins */ -const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC2650_LAUNCHXL_UARTCOUNT] = { +const ADCBufCC26XX_HWAttrs adcBufCC26xxHWAttrs[CC2650_LAUNCHXL_ADCBUFCOUNT] = { { - .baseAddr = UART0_BASE, - .powerMngrId = PowerCC26XX_PERIPH_UART0, - .intNum = INT_UART0_COMB, - .intPriority = ~0, - .swiPriority = 0, - .txPin = Board_UART_TX, - .rxPin = Board_UART_RX, - .ctsPin = PIN_UNASSIGNED, - .rtsPin = PIN_UNASSIGNED, - .ringBufPtr = uartCC26XXRingBuffer[0], - .ringBufSize = sizeof(uartCC26XXRingBuffer[0]) + .intPriority = ~0, + .swiPriority = 0, + .adcChannelLut = ADCBufCC26XX_adcChannelLut, + .gpTimerUnit = CC2650_LAUNCHXL_GPTIMER0A, + .gptDMAChannelMask = 1 << UDMA_CHAN_TIMER0_A, } }; -/* UART configuration structure */ -const UART_Config UART_config[] = { +const ADCBuf_Config ADCBuf_config[CC2650_LAUNCHXL_ADCBUFCOUNT] = { { - .fxnTablePtr = &UARTCC26XX_fxnTable, - .object = &uartCC26XXObjects[0], - .hwAttrs = &uartCC26XXHWAttrs[0] + &ADCBufCC26XX_fxnTable, + &adcBufCC26xxObjects[CC2650_LAUNCHXL_ADCBUF0], + &adcBufCC26xxHWAttrs[CC2650_LAUNCHXL_ADCBUF0] }, - {NULL, NULL, NULL} }; -/* - * ============================= UART end ===================================== - */ + +const uint_least8_t ADCBuf_count = CC2650_LAUNCHXL_ADCBUFCOUNT; /* - * ============================= UDMA begin =================================== + * =============================== ADC =============================== */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(UDMACC26XX_config, ".const:UDMACC26XX_config") -#pragma DATA_SECTION(udmaHWAttrs, ".const:udmaHWAttrs") -#endif +#include +#include -/* Include drivers */ -#include +ADCCC26XX_Object adcCC26xxObjects[CC2650_LAUNCHXL_ADCCOUNT]; -/* UDMA objects */ -UDMACC26XX_Object udmaObjects[CC2650_LAUNCHXL_UDMACOUNT]; - -/* UDMA configuration structure */ -const UDMACC26XX_HWAttrs udmaHWAttrs[CC2650_LAUNCHXL_UDMACOUNT] = { +const ADCCC26XX_HWAttrs adcCC26xxHWAttrs[CC2650_LAUNCHXL_ADCCOUNT] = { { - .baseAddr = UDMA0_BASE, - .powerMngrId = PowerCC26XX_PERIPH_UDMA, - .intNum = INT_DMA_ERR, - .intPriority = ~0 + .adcDIO = CC2650_LAUNCHXL_DIO23_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO7, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC2650_LAUNCHXL_DIO24_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO6, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC2650_LAUNCHXL_DIO25_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO5, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC2650_LAUNCHXL_DIO26_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO4, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC2650_LAUNCHXL_DIO27_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO3, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC2650_LAUNCHXL_DIO28_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO2, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC2650_LAUNCHXL_DIO29_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO1, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC2650_LAUNCHXL_DIO30_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO0, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_10P9_MS, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_DCOUPL, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VSS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VDDS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false } }; -/* UDMA configuration structure */ -const UDMACC26XX_Config UDMACC26XX_config[] = { - { - .object = &udmaObjects[0], - .hwAttrs = &udmaHWAttrs[0] - }, - {NULL, NULL} +const ADC_Config ADC_config[CC2650_LAUNCHXL_ADCCOUNT] = { + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC2650_LAUNCHXL_ADC0], &adcCC26xxHWAttrs[CC2650_LAUNCHXL_ADC0]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC2650_LAUNCHXL_ADC1], &adcCC26xxHWAttrs[CC2650_LAUNCHXL_ADC1]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC2650_LAUNCHXL_ADC2], &adcCC26xxHWAttrs[CC2650_LAUNCHXL_ADC2]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC2650_LAUNCHXL_ADC3], &adcCC26xxHWAttrs[CC2650_LAUNCHXL_ADC3]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC2650_LAUNCHXL_ADC4], &adcCC26xxHWAttrs[CC2650_LAUNCHXL_ADC4]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC2650_LAUNCHXL_ADC5], &adcCC26xxHWAttrs[CC2650_LAUNCHXL_ADC5]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC2650_LAUNCHXL_ADC6], &adcCC26xxHWAttrs[CC2650_LAUNCHXL_ADC6]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC2650_LAUNCHXL_ADC7], &adcCC26xxHWAttrs[CC2650_LAUNCHXL_ADC7]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC2650_LAUNCHXL_ADCDCOUPL], &adcCC26xxHWAttrs[CC2650_LAUNCHXL_ADCDCOUPL]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC2650_LAUNCHXL_ADCVSS], &adcCC26xxHWAttrs[CC2650_LAUNCHXL_ADCVSS]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC2650_LAUNCHXL_ADCVDDS], &adcCC26xxHWAttrs[CC2650_LAUNCHXL_ADCVDDS]}, }; + +const uint_least8_t ADC_count = CC2650_LAUNCHXL_ADCCOUNT; + /* - * ============================= UDMA end ===================================== + * =============================== Crypto =============================== */ - -/* - * ========================== SPI DMA begin =================================== - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(SPI_config, ".const:SPI_config") -#pragma DATA_SECTION(spiCC26XXDMAHWAttrs, ".const:spiCC26XXDMAHWAttrs") -#endif - -/* Include drivers */ -#include - -/* SPI objects */ -SPICC26XXDMA_Object spiCC26XXDMAObjects[CC2650_LAUNCHXL_SPICOUNT]; - -/* SPI configuration structure, describing which pins are to be used */ -const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC2650_LAUNCHXL_SPICOUNT] = { - { - .baseAddr = SSI0_BASE, - .intNum = INT_SSI0_COMB, - .intPriority = ~0, - .swiPriority = 0, - .powerMngrId = PowerCC26XX_PERIPH_SSI0, - .defaultTxBufValue = 0, - .rxChannelBitMask = 1< - -/* I2C objects */ -I2CCC26XX_Object i2cCC26xxObjects[CC2650_LAUNCHXL_I2CCOUNT]; - -/* I2C configuration structure, describing which pins are to be used */ -const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC2650_LAUNCHXL_I2CCOUNT] = { - { - .baseAddr = I2C0_BASE, - .powerMngrId = PowerCC26XX_PERIPH_I2C0, - .intNum = INT_I2C_IRQ, - .intPriority = ~0, - .swiPriority = 0, - .sdaPin = Board_I2C0_SDA0, - .sclPin = Board_I2C0_SCL0, - } -}; - -/* I2C configuration structure */ -const I2C_Config I2C_config[] = { - { - .fxnTablePtr = &I2CCC26XX_fxnTable, - .object = &i2cCC26xxObjects[0], - .hwAttrs = &i2cCC26xxHWAttrs[0] - }, - {NULL, NULL, NULL} -}; -/* - * ========================== I2C end ========================================= - */ - -/* - * ========================== Crypto begin ==================================== - * NOTE: The Crypto implementation should be considered experimental - * and not validated! - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(CryptoCC26XX_config, ".const:CryptoCC26XX_config") -#pragma DATA_SECTION(cryptoCC26XXHWAttrs, ".const:cryptoCC26XXHWAttrs") -#endif - -/* Include drivers */ #include -/* Crypto objects */ CryptoCC26XX_Object cryptoCC26XXObjects[CC2650_LAUNCHXL_CRYPTOCOUNT]; -/* Crypto configuration structure, describing which pins are to be used */ const CryptoCC26XX_HWAttrs cryptoCC26XXHWAttrs[CC2650_LAUNCHXL_CRYPTOCOUNT] = { { .baseAddr = CRYPTO_BASE, @@ -331,125 +238,168 @@ const CryptoCC26XX_HWAttrs cryptoCC26XXHWAttrs[CC2650_LAUNCHXL_CRYPTOCOUNT] = { } }; -/* Crypto configuration structure */ -const CryptoCC26XX_Config CryptoCC26XX_config[] = { +const CryptoCC26XX_Config CryptoCC26XX_config[CC2650_LAUNCHXL_CRYPTOCOUNT] = { { - .object = &cryptoCC26XXObjects[0], - .hwAttrs = &cryptoCC26XXHWAttrs[0] + .object = &cryptoCC26XXObjects[CC2650_LAUNCHXL_CRYPTO0], + .hwAttrs = &cryptoCC26XXHWAttrs[CC2650_LAUNCHXL_CRYPTO0] }, - {NULL, NULL} -}; -/* - * ========================== Crypto end ====================================== - */ - - -/* - * ========================= RF driver begin ================================== - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(RFCC26XX_hwAttrs, ".const:RFCC26XX_hwAttrs") -#endif - -/* Include drivers */ -#include - -/* RF hwi and swi priority */ -const RFCC26XX_HWAttrs RFCC26XX_hwAttrs = { - .hwiCpe0Priority = ~0, - .hwiHwPriority = ~0, - .swiCpe0Priority = 0, - .swiHwPriority = 0, }; /* - * ========================== RF driver end =================================== + * =============================== Display =============================== */ - -/* - * ========================= Display begin ==================================== - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(Display_config, ".const:Display_config") -#pragma DATA_SECTION(displaySharpHWattrs, ".const:displaySharpHWattrs") -#pragma DATA_SECTION(displayUartHWAttrs, ".const:displayUartHWAttrs") -#endif - -#include -#include -#include - -/* Structures for UartPlain Blocking */ -DisplayUart_Object displayUartObject; +#include +#include +#include #ifndef BOARD_DISPLAY_UART_STRBUF_SIZE #define BOARD_DISPLAY_UART_STRBUF_SIZE 128 #endif -static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; - -const DisplayUart_HWAttrs displayUartHWAttrs = { - .uartIdx = Board_UART, - .baudRate = 115200, - .mutexTimeout = BIOS_WAIT_FOREVER, - .strBuf = uartStringBuf, - .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, -}; - -/* Structures for SHARP */ -DisplaySharp_Object displaySharpObject; #ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 // 96->96x96 is the most common board, alternative is 128->128x128. +#define BOARD_DISPLAY_SHARP_SIZE 96 #endif -static uint8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; -const DisplaySharp_HWAttrs displaySharpHWattrs = { - .spiIndex = Board_SPI0, - .csPin = Board_LCD_CS, - .extcominPin = Board_LCD_EXTCOMIN, - .powerPin = Board_LCD_POWER, - .enablePin = Board_LCD_ENABLE, +DisplayUart_Object displayUartObject; +DisplaySharp_Object displaySharpObject; + +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; +static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; + +const DisplayUart_HWAttrs displayUartHWAttrs = { + .uartIdx = CC2650_LAUNCHXL_UART0, + .baudRate = 115200, + .mutexTimeout = (unsigned int)(-1), + .strBuf = uartStringBuf, + .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, +}; + +const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { + .spiIndex = CC2650_LAUNCHXL_SPI0, + .csPin = CC2650_LAUNCHXL_GPIO_LCD_CS, + .powerPin = CC2650_LAUNCHXL_GPIO_LCD_POWER, + .enablePin = CC2650_LAUNCHXL_GPIO_LCD_ENABLE, .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, .displayBuf = sharpDisplayBuf, }; -/* Array of displays */ +#ifndef BOARD_DISPLAY_USE_UART +#define BOARD_DISPLAY_USE_UART 1 +#endif +#ifndef BOARD_DISPLAY_USE_UART_ANSI +#define BOARD_DISPLAY_USE_UART_ANSI 0 +#endif +#ifndef BOARD_DISPLAY_USE_LCD +#define BOARD_DISPLAY_USE_LCD 0 +#endif + +/* + * This #if/#else is needed to workaround a problem with the + * IAR compiler. The IAR compiler doesn't like the empty array + * initialization. (IAR Error[Pe1345]) + */ +#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) + const Display_Config Display_config[] = { -#if !defined(BOARD_DISPLAY_EXCLUDE_UART) +#if (BOARD_DISPLAY_USE_UART) { - .fxnTablePtr = &DisplayUart_fxnTable, +# if (BOARD_DISPLAY_USE_UART_ANSI) + .fxnTablePtr = &DisplayUartAnsi_fxnTable, +# else /* Default to minimal UART with no cursor placement */ + .fxnTablePtr = &DisplayUartMin_fxnTable, +# endif .object = &displayUartObject, .hwAttrs = &displayUartHWAttrs, }, #endif -#if !defined(BOARD_DISPLAY_EXCLUDE_LCD) +#if (BOARD_DISPLAY_USE_LCD) { .fxnTablePtr = &DisplaySharp_fxnTable, .object = &displaySharpObject, .hwAttrs = &displaySharpHWattrs }, #endif - { NULL, NULL, NULL } // Terminator +}; + +const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); + +#else + +const Display_Config *Display_config = NULL; +const uint_least8_t Display_count = 0; + +#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ + +/* + * =============================== GPIO =============================== + */ +#include +#include + +/* + * Array of Pin configurations + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC2650_LAUNCHXL.h + * NOTE: Pins not used for interrupts should be placed at the end of the + * array. Callback entries can be omitted from callbacks array to + * reduce memory usage. + */ +GPIO_PinConfig gpioPinConfigs[] = { + /* Input pins */ + GPIOCC26XX_DIO_13 | GPIO_DO_NOT_CONFIG, /* Button 0 */ + GPIOCC26XX_DIO_14 | GPIO_DO_NOT_CONFIG, /* Button 1 */ + + GPIOCC26XX_DIO_15 | GPIO_DO_NOT_CONFIG, /* CC2650_LAUNCHXL_SPI_MASTER_READY */ + GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG, /* CC2650_LAUNCHXL_SPI_SLAVE_READY */ + + /* Output pins */ + GPIOCC26XX_DIO_07 | GPIO_DO_NOT_CONFIG, /* Green LED */ + GPIOCC26XX_DIO_06 | GPIO_DO_NOT_CONFIG, /* Red LED */ + + /* SPI Flash CSN */ + GPIOCC26XX_DIO_20 | GPIO_DO_NOT_CONFIG, + + /* SD CS */ + GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG, + + /* Sharp Display - GPIO configurations will be done in the Display files */ + GPIOCC26XX_DIO_24 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ + GPIOCC26XX_DIO_22 | GPIO_DO_NOT_CONFIG, /* LCD power control */ + GPIOCC26XX_DIO_23 | GPIO_DO_NOT_CONFIG, /*LCD enable */ + }; /* - * ========================= Display end ====================================== + * Array of callback function pointers + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC2650_LAUNCH.h + * NOTE: Pins not used for interrupts can be omitted from callbacks array to + * reduce memory usage (if placed at end of gpioPinConfigs array). */ +GPIO_CallbackFxn gpioCallbackFunctions[] = { + NULL, /* Button 0 */ + NULL, /* Button 1 */ + NULL, /* CC2650_LAUNCHXL_SPI_MASTER_READY */ + NULL, /* CC2650_LAUNCHXL_SPI_SLAVE_READY */ +}; + +const GPIOCC26XX_Config GPIOCC26XX_config = { + .pinConfigs = (GPIO_PinConfig *)gpioPinConfigs, + .callbacks = (GPIO_CallbackFxn *)gpioCallbackFunctions, + .numberOfPinConfigs = CC2650_LAUNCHXL_GPIOCOUNT, + .numberOfCallbacks = sizeof(gpioCallbackFunctions)/sizeof(GPIO_CallbackFxn), + .intPriority = (~0) +}; /* - * ============================ GPTimer begin ================================= + * =============================== GPTimer =============================== * Remove unused entries to reduce flash usage both in Board.c and Board.h */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(GPTimerCC26XX_config, ".const:GPTimerCC26XX_config") -#pragma DATA_SECTION(gptimerCC26xxHWAttrs, ".const:gptimerCC26xxHWAttrs") -#endif +#include + +GPTimerCC26XX_Object gptimerCC26XXObjects[CC2650_LAUNCHXL_GPTIMERCOUNT]; -/* GPTimer hardware attributes, one per timer part (Timer 0A, 0B, 1A, 1B..) */ const GPTimerCC26XX_HWAttrs gptimerCC26xxHWAttrs[CC2650_LAUNCHXL_GPTIMERPARTSCOUNT] = { { .baseAddr = GPT0_BASE, .intNum = INT_GPT0A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0A, }, { .baseAddr = GPT0_BASE, .intNum = INT_GPT0B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0B, }, @@ -461,266 +411,399 @@ const GPTimerCC26XX_HWAttrs gptimerCC26xxHWAttrs[CC2650_LAUNCHXL_GPTIMERPARTSCOU { .baseAddr = GPT3_BASE, .intNum = INT_GPT3B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3B, }, }; -/* GPTimer objects, one per full-width timer (A+B) (Timer 0, Timer 1..) */ -GPTimerCC26XX_Object gptimerCC26XXObjects[CC2650_LAUNCHXL_GPTIMERCOUNT]; - -/* GPTimer configuration (used as GPTimer_Handle by driver and application) */ const GPTimerCC26XX_Config GPTimerCC26XX_config[CC2650_LAUNCHXL_GPTIMERPARTSCOUNT] = { - { &gptimerCC26XXObjects[0], &gptimerCC26xxHWAttrs[0], GPT_A }, - { &gptimerCC26XXObjects[0], &gptimerCC26xxHWAttrs[1], GPT_B }, - { &gptimerCC26XXObjects[1], &gptimerCC26xxHWAttrs[2], GPT_A }, - { &gptimerCC26XXObjects[1], &gptimerCC26xxHWAttrs[3], GPT_B }, - { &gptimerCC26XXObjects[2], &gptimerCC26xxHWAttrs[4], GPT_A }, - { &gptimerCC26XXObjects[2], &gptimerCC26xxHWAttrs[5], GPT_B }, - { &gptimerCC26XXObjects[3], &gptimerCC26xxHWAttrs[6], GPT_A }, - { &gptimerCC26XXObjects[3], &gptimerCC26xxHWAttrs[7], GPT_B }, + { &gptimerCC26XXObjects[CC2650_LAUNCHXL_GPTIMER0], &gptimerCC26xxHWAttrs[CC2650_LAUNCHXL_GPTIMER0A], GPT_A }, + { &gptimerCC26XXObjects[CC2650_LAUNCHXL_GPTIMER0], &gptimerCC26xxHWAttrs[CC2650_LAUNCHXL_GPTIMER0B], GPT_B }, + { &gptimerCC26XXObjects[CC2650_LAUNCHXL_GPTIMER1], &gptimerCC26xxHWAttrs[CC2650_LAUNCHXL_GPTIMER1A], GPT_A }, + { &gptimerCC26XXObjects[CC2650_LAUNCHXL_GPTIMER1], &gptimerCC26xxHWAttrs[CC2650_LAUNCHXL_GPTIMER1B], GPT_B }, + { &gptimerCC26XXObjects[CC2650_LAUNCHXL_GPTIMER2], &gptimerCC26xxHWAttrs[CC2650_LAUNCHXL_GPTIMER2A], GPT_A }, + { &gptimerCC26XXObjects[CC2650_LAUNCHXL_GPTIMER2], &gptimerCC26xxHWAttrs[CC2650_LAUNCHXL_GPTIMER2B], GPT_B }, + { &gptimerCC26XXObjects[CC2650_LAUNCHXL_GPTIMER3], &gptimerCC26xxHWAttrs[CC2650_LAUNCHXL_GPTIMER3A], GPT_A }, + { &gptimerCC26XXObjects[CC2650_LAUNCHXL_GPTIMER3], &gptimerCC26xxHWAttrs[CC2650_LAUNCHXL_GPTIMER3B], GPT_B }, }; /* - * ============================ GPTimer end =================================== - */ + * =============================== I2C =============================== +*/ +#include +#include +I2CCC26XX_Object i2cCC26xxObjects[CC2650_LAUNCHXL_I2CCOUNT]; - -/* - * ============================= PWM begin ==================================== - * Remove unused entries to reduce flash usage both in Board.c and Board.h - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(PWM_config, ".const:PWM_config") -#pragma DATA_SECTION(pwmtimerCC26xxHWAttrs, ".const:pwmtimerCC26xxHWAttrs") -#endif - -/* PWM configuration, one per PWM output. */ -PWMTimerCC26XX_HwAttrs pwmtimerCC26xxHWAttrs[CC2650_LAUNCHXL_PWMCOUNT] = { - { .pwmPin = Board_PWMPIN0, .gpTimerUnit = Board_GPTIMER0A }, - { .pwmPin = Board_PWMPIN1, .gpTimerUnit = Board_GPTIMER0B }, - { .pwmPin = Board_PWMPIN2, .gpTimerUnit = Board_GPTIMER1A }, - { .pwmPin = Board_PWMPIN3, .gpTimerUnit = Board_GPTIMER1B }, - { .pwmPin = Board_PWMPIN4, .gpTimerUnit = Board_GPTIMER2A }, - { .pwmPin = Board_PWMPIN5, .gpTimerUnit = Board_GPTIMER2B }, - { .pwmPin = Board_PWMPIN6, .gpTimerUnit = Board_GPTIMER3A }, - { .pwmPin = Board_PWMPIN7, .gpTimerUnit = Board_GPTIMER3B }, -}; - -/* PWM object, one per PWM output */ -PWMTimerCC26XX_Object pwmtimerCC26xxObjects[CC2650_LAUNCHXL_PWMCOUNT]; - -extern const PWM_FxnTable PWMTimerCC26XX_fxnTable; - -/* PWM configuration (used as PWM_Handle by driver and application) */ -const PWM_Config PWM_config[CC2650_LAUNCHXL_PWMCOUNT + 1] = { - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[0], &pwmtimerCC26xxHWAttrs[0] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[1], &pwmtimerCC26xxHWAttrs[1] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[2], &pwmtimerCC26xxHWAttrs[2] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[3], &pwmtimerCC26xxHWAttrs[3] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[4], &pwmtimerCC26xxHWAttrs[4] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[5], &pwmtimerCC26xxHWAttrs[5] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[6], &pwmtimerCC26xxHWAttrs[6] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[7], &pwmtimerCC26xxHWAttrs[7] }, - { NULL, NULL, NULL } -}; - - -/* - * ============================= PWM end ====================================== - */ - -/* - * ========================== ADCBuf begin ========================================= - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(ADCBuf_config, ".const:ADCBuf_config") -#pragma DATA_SECTION(adcBufCC26xxHWAttrs, ".const:adcBufCC26xxHWAttrs") -#pragma DATA_SECTION(ADCBufCC26XX_adcChannelLut, ".const:ADCBufCC26XX_adcChannelLut") -#endif - -/* Include drivers */ -#include -#include - -/* ADCBuf objects */ -ADCBufCC26XX_Object adcBufCC26xxObjects[CC2650_LAUNCHXL_ADCBufCOUNT]; - -/* - * This table converts a virtual adc channel into a dio and internal analogue input signal. - * This table is necessary for the functioning of the adcBuf driver. - * Comment out unused entries to save flash. - * Dio and internal signal pairs are hardwired. Do not remap them in the table. You may reorder entire entries though. - * The mapping of dio and internal signals is package dependent. - */ -const ADCBufCC26XX_AdcChannelLutEntry ADCBufCC26XX_adcChannelLut[] = { - {PIN_UNASSIGNED, ADC_COMPB_IN_VDDS}, - {PIN_UNASSIGNED, ADC_COMPB_IN_DCOUPL}, - {PIN_UNASSIGNED, ADC_COMPB_IN_VSS}, - {Board_DIO23_ANALOG, ADC_COMPB_IN_AUXIO7}, - {Board_DIO24_ANALOG, ADC_COMPB_IN_AUXIO6}, - {Board_DIO25_ANALOG, ADC_COMPB_IN_AUXIO5}, - {Board_DIO26_ANALOG, ADC_COMPB_IN_AUXIO4}, - {Board_DIO27_ANALOG, ADC_COMPB_IN_AUXIO3}, - {Board_DIO28_ANALOG, ADC_COMPB_IN_AUXIO2}, - {Board_DIO29_ANALOG, ADC_COMPB_IN_AUXIO1}, - {Board_DIO30_ANALOG, ADC_COMPB_IN_AUXIO0}, -}; - -const ADCBufCC26XX_HWAttrs adcBufCC26xxHWAttrs[CC2650_LAUNCHXL_ADCBufCOUNT] = { +const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC2650_LAUNCHXL_I2CCOUNT] = { { + .baseAddr = I2C0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_I2C0, + .intNum = INT_I2C_IRQ, .intPriority = ~0, .swiPriority = 0, - .adcChannelLut = ADCBufCC26XX_adcChannelLut, - .gpTimerUnit = Board_GPTIMER0A, - .gptDMAChannelMask = 1 << UDMA_CHAN_TIMER0_A, + .sdaPin = CC2650_LAUNCHXL_I2C0_SDA0, + .sclPin = CC2650_LAUNCHXL_I2C0_SCL0, } }; -const ADCBuf_Config ADCBuf_config[] = { - {&ADCBufCC26XX_fxnTable, &adcBufCC26xxObjects[0], &adcBufCC26xxHWAttrs[0]}, - {NULL, NULL, NULL}, +const I2C_Config I2C_config[CC2650_LAUNCHXL_I2CCOUNT] = { + { + .fxnTablePtr = &I2CCC26XX_fxnTable, + .object = &i2cCC26xxObjects[CC2650_LAUNCHXL_I2C0], + .hwAttrs = &i2cCC26xxHWAttrs[CC2650_LAUNCHXL_I2C0] + }, }; -/* - * ========================== ADCBuf end ========================================= - */ - +const uint_least8_t I2C_count = CC2650_LAUNCHXL_I2CCOUNT; /* - * ========================== ADC begin ========================================= + * =============================== NVS =============================== + */ +#include +#include +#include + +#define NVS_REGIONS_BASE 0x1A000 +#define SECTORSIZE 0x1000 +#define REGIONSIZE (SECTORSIZE * 4) + +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH + +/* + * Reserve flash sectors for NVS driver use by placing an uninitialized byte + * array at the desired flash address. */ -/* Place into subsections to allow the TI linker to remove items properly */ #if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(ADC_config, ".const:ADC_config") -#pragma DATA_SECTION(adcCC26xxHWAttrs, ".const:adcCC26xxHWAttrs") + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +#pragma LOCATION(flashBuf, NVS_REGIONS_BASE); +#pragma NOINIT(flashBuf); +static char flashBuf[REGIONSIZE]; + +#elif defined(__IAR_SYSTEMS_ICC__) + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +static __no_init char flashBuf[REGIONSIZE] @ NVS_REGIONS_BASE; + +#elif defined(__GNUC__) + +/* + * Place the flash buffers in the .nvs section created in the gcc linker file. + * The .nvs section enforces alignment on a sector boundary but may + * be placed anywhere in flash memory. If desired the .nvs section can be set + * to a fixed address by changing the following in the gcc linker file: + * + * .nvs (FIXED_FLASH_ADDR) (NOLOAD) : AT (FIXED_FLASH_ADDR) { + * *(.nvs) + * } > REGION_TEXT + */ +__attribute__ ((section (".nvs"))) +static char flashBuf[REGIONSIZE]; + #endif -/* Include drivers */ -#include -#include +/* Allocate objects for NVS Internal Regions */ +NVSCC26XX_Object nvsCC26xxObjects[1]; -/* ADC objects */ -ADCCC26XX_Object adcCC26xxObjects[CC2650_LAUNCHXL_ADCCOUNT]; - - -const ADCCC26XX_HWAttrs adcCC26xxHWAttrs[CC2650_LAUNCHXL_ADCCOUNT] = { +/* Hardware attributes for NVS Internal Regions */ +const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { { - .adcDIO = Board_DIO23_ANALOG, - .adcCompBInput = ADC_COMPB_IN_AUXIO7, - .refSource = ADCCC26XX_FIXED_REFERENCE, - .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, - .inputScalingEnabled = true, - .triggerSource = ADCCC26XX_TRIGGER_MANUAL + .regionBase = (void *)flashBuf, + .regionSize = REGIONSIZE, }, - { - .adcDIO = Board_DIO24_ANALOG, - .adcCompBInput = ADC_COMPB_IN_AUXIO6, - .refSource = ADCCC26XX_FIXED_REFERENCE, - .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, - .inputScalingEnabled = true, - .triggerSource = ADCCC26XX_TRIGGER_MANUAL - }, - { - .adcDIO = Board_DIO25_ANALOG, - .adcCompBInput = ADC_COMPB_IN_AUXIO5, - .refSource = ADCCC26XX_FIXED_REFERENCE, - .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, - .inputScalingEnabled = true, - .triggerSource = ADCCC26XX_TRIGGER_MANUAL - }, - { - .adcDIO = Board_DIO26_ANALOG, - .adcCompBInput = ADC_COMPB_IN_AUXIO4, - .refSource = ADCCC26XX_FIXED_REFERENCE, - .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, - .inputScalingEnabled = true, - .triggerSource = ADCCC26XX_TRIGGER_MANUAL - }, - { - .adcDIO = Board_DIO27_ANALOG, - .adcCompBInput = ADC_COMPB_IN_AUXIO3, - .refSource = ADCCC26XX_FIXED_REFERENCE, - .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, - .inputScalingEnabled = true, - .triggerSource = ADCCC26XX_TRIGGER_MANUAL - }, - { - .adcDIO = Board_DIO28_ANALOG, - .adcCompBInput = ADC_COMPB_IN_AUXIO2, - .refSource = ADCCC26XX_FIXED_REFERENCE, - .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, - .inputScalingEnabled = true, - .triggerSource = ADCCC26XX_TRIGGER_MANUAL - }, - { - .adcDIO = Board_DIO29_ANALOG, - .adcCompBInput = ADC_COMPB_IN_AUXIO1, - .refSource = ADCCC26XX_FIXED_REFERENCE, - .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, - .inputScalingEnabled = true, - .triggerSource = ADCCC26XX_TRIGGER_MANUAL - }, - { - .adcDIO = Board_DIO30_ANALOG, - .adcCompBInput = ADC_COMPB_IN_AUXIO0, - .refSource = ADCCC26XX_FIXED_REFERENCE, - .samplingDuration = ADCCC26XX_SAMPLING_DURATION_10P9_MS, - .inputScalingEnabled = true, - .triggerSource = ADCCC26XX_TRIGGER_MANUAL - }, - { - .adcDIO = PIN_UNASSIGNED, - .adcCompBInput = ADC_COMPB_IN_DCOUPL, - .refSource = ADCCC26XX_FIXED_REFERENCE, - .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, - .inputScalingEnabled = true, - .triggerSource = ADCCC26XX_TRIGGER_MANUAL - }, - { - .adcDIO = PIN_UNASSIGNED, - .adcCompBInput = ADC_COMPB_IN_VSS, - .refSource = ADCCC26XX_FIXED_REFERENCE, - .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, - .inputScalingEnabled = true, - .triggerSource = ADCCC26XX_TRIGGER_MANUAL - }, - { - .adcDIO = PIN_UNASSIGNED, - .adcCompBInput = ADC_COMPB_IN_VDDS, - .refSource = ADCCC26XX_FIXED_REFERENCE, - .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, - .inputScalingEnabled = true, - .triggerSource = ADCCC26XX_TRIGGER_MANUAL - } }; -const ADC_Config ADC_config[] = { - {&ADCCC26XX_fxnTable, &adcCC26xxObjects[0], &adcCC26xxHWAttrs[0]}, - {&ADCCC26XX_fxnTable, &adcCC26xxObjects[1], &adcCC26xxHWAttrs[1]}, - {&ADCCC26XX_fxnTable, &adcCC26xxObjects[2], &adcCC26xxHWAttrs[2]}, - {&ADCCC26XX_fxnTable, &adcCC26xxObjects[3], &adcCC26xxHWAttrs[3]}, - {&ADCCC26XX_fxnTable, &adcCC26xxObjects[4], &adcCC26xxHWAttrs[4]}, - {&ADCCC26XX_fxnTable, &adcCC26xxObjects[5], &adcCC26xxHWAttrs[5]}, - {&ADCCC26XX_fxnTable, &adcCC26xxObjects[6], &adcCC26xxHWAttrs[6]}, - {&ADCCC26XX_fxnTable, &adcCC26xxObjects[7], &adcCC26xxHWAttrs[7]}, - {&ADCCC26XX_fxnTable, &adcCC26xxObjects[8], &adcCC26xxHWAttrs[8]}, - {&ADCCC26XX_fxnTable, &adcCC26xxObjects[9], &adcCC26xxHWAttrs[9]}, - {&ADCCC26XX_fxnTable, &adcCC26xxObjects[10], &adcCC26xxHWAttrs[10]}, - {NULL, NULL, NULL}, +#endif /* Board_EXCLUDE_NVS_INTERNAL_FLASH */ + +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH + +#define SPISECTORSIZE 0x1000 +#define SPIREGIONSIZE (SPISECTORSIZE * 32) +#define VERIFYBUFSIZE 64 + +static uint8_t verifyBuf[VERIFYBUFSIZE]; + +/* Allocate objects for NVS External Regions */ +NVSSPI25X_Object nvsSPI25XObjects[1]; + +/* Hardware attributes for NVS External Regions */ +const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { + { + .regionBaseOffset = 0, + .regionSize = SPIREGIONSIZE, + .sectorSize = SPISECTORSIZE, + .verifyBuf = verifyBuf, + .verifyBufSize = VERIFYBUFSIZE, + .spiHandle = NULL, + .spiIndex = 0, + .spiBitRate = 4000000, + .spiCsnGpioIndex = CC2650_LAUNCHXL_GPIO_SPI_FLASH_CS, + }, +}; + +#endif /* Board_EXCLUDE_NVS_EXTERNAL_FLASH */ + +/* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ +const NVS_Config NVS_config[CC2650_LAUNCHXL_NVSCOUNT] = { +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH + { + .fxnTablePtr = &NVSCC26XX_fxnTable, + .object = &nvsCC26xxObjects[0], + .hwAttrs = &nvsCC26xxHWAttrs[0], + }, +#endif +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH + { + .fxnTablePtr = &NVSSPI25X_fxnTable, + .object = &nvsSPI25XObjects[0], + .hwAttrs = &nvsSPI25XHWAttrs[0], + }, +#endif +}; + +const uint_least8_t NVS_count = CC2650_LAUNCHXL_NVSCOUNT; + +/* + * =============================== PIN =============================== + */ +#include +#include + +const PIN_Config BoardGpioInitTable[] = { + + CC2650_LAUNCHXL_PIN_RLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC2650_LAUNCHXL_PIN_GLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC2650_LAUNCHXL_PIN_BTN1 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC2650_LAUNCHXL_PIN_BTN2 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC2650_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ + CC2650_LAUNCHXL_UART_RX | PIN_INPUT_EN | PIN_PULLDOWN, /* UART RX via debugger back channel */ + CC2650_LAUNCHXL_UART_TX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* UART TX via debugger back channel */ + CC2650_LAUNCHXL_SPI0_MOSI | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master out - slave in */ + CC2650_LAUNCHXL_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master in - slave out */ + CC2650_LAUNCHXL_SPI0_CLK | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI clock */ + + PIN_TERMINATE +}; + +const PINCC26XX_HWAttrs PINCC26XX_hwAttrs = { + .intPriority = ~0, + .swiPriority = 0 }; /* - * ========================== ADC end ========================================= + * =============================== Power =============================== */ +#include +#include + +const PowerCC26XX_Config PowerCC26XX_config = { + .policyInitFxn = NULL, + .policyFxn = &PowerCC26XX_standbyPolicy, + .calibrateFxn = &PowerCC26XX_calibrate, + .enablePolicy = true, + .calibrateRCOSC_LF = true, + .calibrateRCOSC_HF = true, +}; + +/* + * =============================== PWM =============================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +#include +#include + +PWMTimerCC26XX_Object pwmtimerCC26xxObjects[CC2650_LAUNCHXL_PWMCOUNT]; + +const PWMTimerCC26XX_HwAttrs pwmtimerCC26xxHWAttrs[CC2650_LAUNCHXL_PWMCOUNT] = { + { .pwmPin = CC2650_LAUNCHXL_PWMPIN0, .gpTimerUnit = CC2650_LAUNCHXL_GPTIMER0A }, + { .pwmPin = CC2650_LAUNCHXL_PWMPIN1, .gpTimerUnit = CC2650_LAUNCHXL_GPTIMER0B }, + { .pwmPin = CC2650_LAUNCHXL_PWMPIN2, .gpTimerUnit = CC2650_LAUNCHXL_GPTIMER1A }, + { .pwmPin = CC2650_LAUNCHXL_PWMPIN3, .gpTimerUnit = CC2650_LAUNCHXL_GPTIMER1B }, + { .pwmPin = CC2650_LAUNCHXL_PWMPIN4, .gpTimerUnit = CC2650_LAUNCHXL_GPTIMER2A }, + { .pwmPin = CC2650_LAUNCHXL_PWMPIN5, .gpTimerUnit = CC2650_LAUNCHXL_GPTIMER2B }, + { .pwmPin = CC2650_LAUNCHXL_PWMPIN6, .gpTimerUnit = CC2650_LAUNCHXL_GPTIMER3A }, + { .pwmPin = CC2650_LAUNCHXL_PWMPIN7, .gpTimerUnit = CC2650_LAUNCHXL_GPTIMER3B }, +}; + +const PWM_Config PWM_config[CC2650_LAUNCHXL_PWMCOUNT] = { + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2650_LAUNCHXL_PWM0], &pwmtimerCC26xxHWAttrs[CC2650_LAUNCHXL_PWM0] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2650_LAUNCHXL_PWM1], &pwmtimerCC26xxHWAttrs[CC2650_LAUNCHXL_PWM1] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2650_LAUNCHXL_PWM2], &pwmtimerCC26xxHWAttrs[CC2650_LAUNCHXL_PWM2] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2650_LAUNCHXL_PWM3], &pwmtimerCC26xxHWAttrs[CC2650_LAUNCHXL_PWM3] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2650_LAUNCHXL_PWM4], &pwmtimerCC26xxHWAttrs[CC2650_LAUNCHXL_PWM4] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2650_LAUNCHXL_PWM5], &pwmtimerCC26xxHWAttrs[CC2650_LAUNCHXL_PWM5] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2650_LAUNCHXL_PWM6], &pwmtimerCC26xxHWAttrs[CC2650_LAUNCHXL_PWM6] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2650_LAUNCHXL_PWM7], &pwmtimerCC26xxHWAttrs[CC2650_LAUNCHXL_PWM7] }, +}; + +const uint_least8_t PWM_count = CC2650_LAUNCHXL_PWMCOUNT; + +/* + * =============================== RF Driver =============================== + */ +#include + +const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { + .hwiPriority = ~0, /* Lowest HWI priority */ + .swiPriority = 0, /* Lowest SWI priority */ + .xoscHfAlwaysNeeded = true, /* Keep XOSC dependency while in stanby */ + .globalCallback = NULL, /* No board specific callback */ + .globalEventMask = 0 /* No events subscribed to */ +}; + +/* + * =============================== SD =============================== + */ +#include +#include + +SDSPI_Object sdspiObjects[CC2650_LAUNCHXL_SDCOUNT]; + +const SDSPI_HWAttrs sdspiHWAttrs[CC2650_LAUNCHXL_SDCOUNT] = { + { + .spiIndex = CC2650_LAUNCHXL_SPI0, + .spiCsGpioIndex = CC2650_LAUNCHXL_SDSPI_CS + } +}; + +const SD_Config SD_config[CC2650_LAUNCHXL_SDCOUNT] = { + { + .fxnTablePtr = &SDSPI_fxnTable, + .object = &sdspiObjects[CC2650_LAUNCHXL_SDSPI0], + .hwAttrs = &sdspiHWAttrs[CC2650_LAUNCHXL_SDSPI0] + }, +}; + +const uint_least8_t SD_count = CC2650_LAUNCHXL_SDCOUNT; + +/* + * =============================== SPI DMA =============================== + */ +#include +#include + +SPICC26XXDMA_Object spiCC26XXDMAObjects[CC2650_LAUNCHXL_SPICOUNT]; + +/* + * NOTE: The SPI instances below can be used by the SD driver to communicate + * with a SD card via SPI. The 'defaultTxBufValue' fields below are set to 0xFF + * to satisfy the SDSPI driver requirement. + */ +const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC2650_LAUNCHXL_SPICOUNT] = { + { + .baseAddr = SSI0_BASE, + .intNum = INT_SSI0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .powerMngrId = PowerCC26XX_PERIPH_SSI0, + .defaultTxBufValue = 0xFF, + .rxChannelBitMask = 1< +#include + +UARTCC26XX_Object uartCC26XXObjects[CC2650_LAUNCHXL_UARTCOUNT]; + +uint8_t uartCC26XXRingBuffer[CC2650_LAUNCHXL_UARTCOUNT][32]; + +const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC2650_LAUNCHXL_UARTCOUNT] = { + { + .baseAddr = UART0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UART0, + .intNum = INT_UART0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .txPin = CC2650_LAUNCHXL_UART_TX, + .rxPin = CC2650_LAUNCHXL_UART_RX, + .ctsPin = PIN_UNASSIGNED, + .rtsPin = PIN_UNASSIGNED, + .ringBufPtr = uartCC26XXRingBuffer[CC2650_LAUNCHXL_UART0], + .ringBufSize = sizeof(uartCC26XXRingBuffer[CC2650_LAUNCHXL_UART0]), + .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, + .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, + .errorFxn = NULL + } +}; + +const UART_Config UART_config[CC2650_LAUNCHXL_UARTCOUNT] = { + { + .fxnTablePtr = &UARTCC26XX_fxnTable, + .object = &uartCC26XXObjects[CC2650_LAUNCHXL_UART0], + .hwAttrs = &uartCC26XXHWAttrs[CC2650_LAUNCHXL_UART0] + }, +}; + +const uint_least8_t UART_count = CC2650_LAUNCHXL_UARTCOUNT; + +/* + * =============================== UDMA =============================== + */ +#include + +UDMACC26XX_Object udmaObjects[CC2650_LAUNCHXL_UDMACOUNT]; + +const UDMACC26XX_HWAttrs udmaHWAttrs[CC2650_LAUNCHXL_UDMACOUNT] = { + { + .baseAddr = UDMA0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UDMA, + .intNum = INT_DMA_ERR, + .intPriority = ~0 + } +}; + +const UDMACC26XX_Config UDMACC26XX_config[CC2650_LAUNCHXL_UDMACOUNT] = { + { + .object = &udmaObjects[CC2650_LAUNCHXL_UDMA0], + .hwAttrs = &udmaHWAttrs[CC2650_LAUNCHXL_UDMA0] + }, +}; + + /* * =============================== Watchdog =============================== */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(Watchdog_config, ".const:Watchdog_config") -#pragma DATA_SECTION(watchdogCC26XXHWAttrs, ".const:watchdogCC26XXHWAttrs") -#endif - #include #include @@ -728,25 +811,39 @@ WatchdogCC26XX_Object watchdogCC26XXObjects[CC2650_LAUNCHXL_WATCHDOGCOUNT]; const WatchdogCC26XX_HWAttrs watchdogCC26XXHWAttrs[CC2650_LAUNCHXL_WATCHDOGCOUNT] = { { - .baseAddr = WDT_BASE, - .intNum = INT_WDT_IRQ, + .baseAddr = WDT_BASE, .reloadValue = 1000 /* Reload value in milliseconds */ }, }; -const Watchdog_Config Watchdog_config[] = { +const Watchdog_Config Watchdog_config[CC2650_LAUNCHXL_WATCHDOGCOUNT] = { { .fxnTablePtr = &WatchdogCC26XX_fxnTable, - .object = &watchdogCC26XXObjects[0], - .hwAttrs = &watchdogCC26XXHWAttrs[0] + .object = &watchdogCC26XXObjects[CC2650_LAUNCHXL_WATCHDOG0], + .hwAttrs = &watchdogCC26XXHWAttrs[CC2650_LAUNCHXL_WATCHDOG0] }, - {NULL, NULL, NULL}, }; +const uint_least8_t Watchdog_count = CC2650_LAUNCHXL_WATCHDOGCOUNT; + /* - * ======== CC26XX_LAUNCHXL_initWatchdog ======== + * Board-specific initialization function to disable external flash. + * This function is defined in the file CC2650_LAUNCHXL_fxns.c */ -void CC26XX_LAUNCHXL_initWatchdog(void) +extern void Board_initHook(void); + +/* + * ======== CC2650_LAUNCHXL_initGeneral ======== + */ +void CC2650_LAUNCHXL_initGeneral(void) { - Watchdog_init(); + Power_init(); + + if (PIN_init(BoardGpioInitTable) != PIN_SUCCESS) { + /* Error with PIN_init */ + while (1); + } + + /* Perform board-specific initialization */ + Board_initHook(); } diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h index 4ca05d632..a5f0b28da 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, Texas Instruments Incorporated + * Copyright (c) 2015-2018, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,7 +34,11 @@ * * @brief CC2650 LaunchPad Board Specific header file. * - * NB! This is the board file for CC2650 LaunchPad PCB version 1.1 + * The CC2650_LAUNCHXL header file should be included in an application as + * follows: + * @code + * #include "CC2650_LAUNCHXL.h" + * @endcode * * ============================================================================ */ @@ -45,244 +49,139 @@ extern "C" { #endif -/** ============================================================================ - * Includes - * ==========================================================================*/ +/* Includes */ #include -#include +#include -/** ============================================================================ - * Externs - * ==========================================================================*/ +/* Externs */ extern const PIN_Config BoardGpioInitTable[]; -/** ============================================================================ - * Defines - * ==========================================================================*/ - -/* Same RF Configuration as 7x7 EM */ -#define CC2650EM_7ID +/* Defines */ #define CC2650_LAUNCHXL /* Mapping of pins to board signals using general board aliases - * + * */ -/* Discrete outputs */ -#define Board_RLED IOID_6 -#define Board_GLED IOID_7 -#define Board_LED_ON 1 -#define Board_LED_OFF 0 +/* Analog Capable DIOs */ +#define CC2650_LAUNCHXL_DIO23_ANALOG IOID_23 +#define CC2650_LAUNCHXL_DIO24_ANALOG IOID_24 +#define CC2650_LAUNCHXL_DIO25_ANALOG IOID_25 +#define CC2650_LAUNCHXL_DIO26_ANALOG IOID_26 +#define CC2650_LAUNCHXL_DIO27_ANALOG IOID_27 +#define CC2650_LAUNCHXL_DIO28_ANALOG IOID_28 +#define CC2650_LAUNCHXL_DIO29_ANALOG IOID_29 +#define CC2650_LAUNCHXL_DIO30_ANALOG IOID_30 -/* Discrete inputs */ -#define Board_BTN1 IOID_13 -#define Board_BTN2 IOID_14 +/* Digital IOs */ +#define CC2650_LAUNCHXL_DIO0 IOID_0 +#define CC2650_LAUNCHXL_DIO1_RFSW IOID_1 +#define CC2650_LAUNCHXL_DIO12 IOID_12 +#define CC2650_LAUNCHXL_DIO15 IOID_15 +#define CC2650_LAUNCHXL_DIO16_TDO IOID_16 +#define CC2650_LAUNCHXL_DIO17_TDI IOID_17 +#define CC2650_LAUNCHXL_DIO21 IOID_21 +#define CC2650_LAUNCHXL_DIO22 IOID_22 -/* UART Board */ -#define Board_UART_RX IOID_2 /* RXD */ -#define Board_UART_TX IOID_3 /* TXD */ -#define Board_UART_CTS IOID_19 /* CTS */ -#define Board_UART_RTS IOID_18 /* RTS */ +/* Discrete Inputs */ +#define CC2650_LAUNCHXL_PIN_BTN1 IOID_13 +#define CC2650_LAUNCHXL_PIN_BTN2 IOID_14 -/* SPI Board */ -#define Board_SPI0_MISO IOID_8 /* RF1.20 */ -#define Board_SPI0_MOSI IOID_9 /* RF1.18 */ -#define Board_SPI0_CLK IOID_10 /* RF1.16 */ -#define Board_SPI0_CSN PIN_UNASSIGNED -#define Board_SPI1_MISO PIN_UNASSIGNED -#define Board_SPI1_MOSI PIN_UNASSIGNED -#define Board_SPI1_CLK PIN_UNASSIGNED -#define Board_SPI1_CSN PIN_UNASSIGNED +/* GPIO */ +#define CC2650_LAUNCHXL_GPIO_LED_ON 1 +#define CC2650_LAUNCHXL_GPIO_LED_OFF 0 /* I2C */ -#define Board_I2C0_SCL0 IOID_4 -#define Board_I2C0_SDA0 IOID_5 +#define CC2650_LAUNCHXL_I2C0_SCL0 IOID_4 +#define CC2650_LAUNCHXL_I2C0_SDA0 IOID_5 + +/* LEDs */ +#define CC2650_LAUNCHXL_PIN_LED_ON 1 +#define CC2650_LAUNCHXL_PIN_LED_OFF 0 +#define CC2650_LAUNCHXL_PIN_RLED IOID_6 +#define CC2650_LAUNCHXL_PIN_GLED IOID_7 + +/* PWM Outputs */ +#define CC2650_LAUNCHXL_PWMPIN0 CC2650_LAUNCHXL_PIN_RLED +#define CC2650_LAUNCHXL_PWMPIN1 CC2650_LAUNCHXL_PIN_GLED +#define CC2650_LAUNCHXL_PWMPIN2 PIN_UNASSIGNED +#define CC2650_LAUNCHXL_PWMPIN3 PIN_UNASSIGNED +#define CC2650_LAUNCHXL_PWMPIN4 PIN_UNASSIGNED +#define CC2650_LAUNCHXL_PWMPIN5 PIN_UNASSIGNED +#define CC2650_LAUNCHXL_PWMPIN6 PIN_UNASSIGNED +#define CC2650_LAUNCHXL_PWMPIN7 PIN_UNASSIGNED /* SPI */ -#define Board_SPI_FLASH_CS IOID_20 -#define Board_FLASH_CS_ON 0 -#define Board_FLASH_CS_OFF 1 +#define CC2650_LAUNCHXL_SPI_FLASH_CS IOID_20 +#define CC2650_LAUNCHXL_FLASH_CS_ON 0 +#define CC2650_LAUNCHXL_FLASH_CS_OFF 1 -/* Booster pack generic */ -#define Board_DIO0 IOID_0 -#define Board_DIO1_RFSW IOID_1 -#define Board_DIO12 IOID_12 -#define Board_DIO15 IOID_15 -#define Board_DIO16_TDO IOID_16 -#define Board_DIO17_TDI IOID_17 -#define Board_DIO21 IOID_21 -#define Board_DIO22 IOID_22 +/* SPI Board */ +#define CC2650_LAUNCHXL_SPI0_MISO IOID_8 /* RF1.20 */ +#define CC2650_LAUNCHXL_SPI0_MOSI IOID_9 /* RF1.18 */ +#define CC2650_LAUNCHXL_SPI0_CLK IOID_10 /* RF1.16 */ +#define CC2650_LAUNCHXL_SPI0_CSN PIN_UNASSIGNED +#define CC2650_LAUNCHXL_SPI1_MISO PIN_UNASSIGNED +#define CC2650_LAUNCHXL_SPI1_MOSI PIN_UNASSIGNED +#define CC2650_LAUNCHXL_SPI1_CLK PIN_UNASSIGNED +#define CC2650_LAUNCHXL_SPI1_CSN PIN_UNASSIGNED -#define Board_DIO23_ANALOG IOID_23 -#define Board_DIO24_ANALOG IOID_24 -#define Board_DIO25_ANALOG IOID_25 -#define Board_DIO26_ANALOG IOID_26 -#define Board_DIO27_ANALOG IOID_27 -#define Board_DIO28_ANALOG IOID_28 -#define Board_DIO29_ANALOG IOID_29 -#define Board_DIO30_ANALOG IOID_30 - -/* Booster pack LCD (430BOOST - Sharp96 Rev 1.1) */ -#define Board_LCD_CS IOID_24 // SPI chip select -#define Board_LCD_EXTCOMIN IOID_12 // External COM inversion -#define Board_LCD_ENABLE IOID_22 // LCD enable -#define Board_LCD_POWER IOID_23 // LCD power control -#define Board_LCD_CS_ON 1 -#define Board_LCD_CS_OFF 0 - -/* PWM outputs */ -#define Board_PWMPIN0 Board_RLED -#define Board_PWMPIN1 Board_GLED -#define Board_PWMPIN2 PIN_UNASSIGNED -#define Board_PWMPIN3 PIN_UNASSIGNED -#define Board_PWMPIN4 PIN_UNASSIGNED -#define Board_PWMPIN5 PIN_UNASSIGNED -#define Board_PWMPIN6 PIN_UNASSIGNED -#define Board_PWMPIN7 PIN_UNASSIGNED - -/** ============================================================================ - * Instance identifiers - * ==========================================================================*/ -/* Generic I2C instance identifiers */ -#define Board_I2C CC2650_LAUNCHXL_I2C0 -/* Generic SPI instance identifiers */ -#define Board_SPI0 CC2650_LAUNCHXL_SPI0 -#define Board_SPI1 CC2650_LAUNCHXL_SPI1 -/* Generic UART instance identifiers */ -#define Board_UART CC2650_LAUNCHXL_UART0 -/* Generic Crypto instance identifiers */ -#define Board_CRYPTO CC2650_LAUNCHXL_CRYPTO0 -/* Generic GPTimer instance identifiers */ -#define Board_GPTIMER0A CC2650_LAUNCHXL_GPTIMER0A -#define Board_GPTIMER0B CC2650_LAUNCHXL_GPTIMER0B -#define Board_GPTIMER1A CC2650_LAUNCHXL_GPTIMER1A -#define Board_GPTIMER1B CC2650_LAUNCHXL_GPTIMER1B -#define Board_GPTIMER2A CC2650_LAUNCHXL_GPTIMER2A -#define Board_GPTIMER2B CC2650_LAUNCHXL_GPTIMER2B -#define Board_GPTIMER3A CC2650_LAUNCHXL_GPTIMER3A -#define Board_GPTIMER3B CC2650_LAUNCHXL_GPTIMER3B -/* Generic PWM instance identifiers */ -#define Board_PWM0 CC2650_LAUNCHXL_PWM0 -#define Board_PWM1 CC2650_LAUNCHXL_PWM1 -#define Board_PWM2 CC2650_LAUNCHXL_PWM2 -#define Board_PWM3 CC2650_LAUNCHXL_PWM3 -#define Board_PWM4 CC2650_LAUNCHXL_PWM4 -#define Board_PWM5 CC2650_LAUNCHXL_PWM5 -#define Board_PWM6 CC2650_LAUNCHXL_PWM6 -#define Board_PWM7 CC2650_LAUNCHXL_PWM7 - -/** ============================================================================ - * Number of peripherals and their names - * ==========================================================================*/ +/* UART Board */ +#define CC2650_LAUNCHXL_UART_RX IOID_2 /* RXD */ +#define CC2650_LAUNCHXL_UART_TX IOID_3 /* TXD */ +#define CC2650_LAUNCHXL_UART_CTS IOID_19 /* CTS */ +#define CC2650_LAUNCHXL_UART_RTS IOID_18 /* RTS */ /*! - * @def CC2650_LAUNCHXL_I2CName - * @brief Enum of I2C names on the CC2650 dev board + * @brief Initialize the general board specific settings + * + * This function initializes the general board specific settings. */ -typedef enum CC2650_LAUNCHXL_I2CName { - CC2650_LAUNCHXL_I2C0 = 0, - - CC2650_LAUNCHXL_I2CCOUNT -} CC2650_LAUNCHXL_I2CName; +void CC2650_LAUNCHXL_initGeneral(void); /*! - * @def CC2650_LAUNCHXL_CryptoName - * @brief Enum of Crypto names on the CC2650 dev board + * @brief Turn off the external flash on LaunchPads + * */ -typedef enum CC2650_LAUNCHXL_CryptoName { - CC2650_LAUNCHXL_CRYPTO0 = 0, - - CC2650_LAUNCHXL_CRYPTOCOUNT -} CC2650_LAUNCHXL_CryptoName; - +void CC2650_LAUNCHXL_shutDownExtFlash(void); /*! - * @def CC2650_LAUNCHXL_SPIName - * @brief Enum of SPI names on the CC2650 dev board + * @brief Wake up the external flash present on the board files + * + * This function toggles the chip select for the amount of time needed + * to wake the chip up. */ -typedef enum CC2650_LAUNCHXL_SPIName { - CC2650_LAUNCHXL_SPI0 = 0, - CC2650_LAUNCHXL_SPI1, - - CC2650_LAUNCHXL_SPICOUNT -} CC2650_LAUNCHXL_SPIName; - -/*! - * @def CC2650_LAUNCHXL_UARTName - * @brief Enum of UARTs on the CC2650 dev board - */ -typedef enum CC2650_LAUNCHXL_UARTName { - CC2650_LAUNCHXL_UART0 = 0, - - CC2650_LAUNCHXL_UARTCOUNT -} CC2650_LAUNCHXL_UARTName; - -/*! - * @def CC2650_LAUNCHXL_UdmaName - * @brief Enum of DMA buffers - */ -typedef enum CC2650_LAUNCHXL_UdmaName { - CC2650_LAUNCHXL_UDMA0 = 0, - - CC2650_LAUNCHXL_UDMACOUNT -} CC2650_LAUNCHXL_UdmaName; - -/*! - * @def CC2650_LAUNCHXL_GPTimerName - * @brief Enum of GPTimer parts - */ -typedef enum CC2650_LAUNCHXL_GPTimerName -{ - CC2650_LAUNCHXL_GPTIMER0A = 0, - CC2650_LAUNCHXL_GPTIMER0B, - CC2650_LAUNCHXL_GPTIMER1A, - CC2650_LAUNCHXL_GPTIMER1B, - CC2650_LAUNCHXL_GPTIMER2A, - CC2650_LAUNCHXL_GPTIMER2B, - CC2650_LAUNCHXL_GPTIMER3A, - CC2650_LAUNCHXL_GPTIMER3B, - CC2650_LAUNCHXL_GPTIMERPARTSCOUNT -} CC2650_LAUNCHXL_GPTimerName; - -/*! - * @def CC2650_LAUNCHXL_GPTimers - * @brief Enum of GPTimers - */ -typedef enum CC2650_LAUNCHXL_GPTimers -{ - CC2650_LAUNCHXL_GPTIMER0 = 0, - CC2650_LAUNCHXL_GPTIMER1, - CC2650_LAUNCHXL_GPTIMER2, - CC2650_LAUNCHXL_GPTIMER3, - CC2650_LAUNCHXL_GPTIMERCOUNT -} CC2650_LAUNCHXL_GPTimers; - -/*! - * @def CC2650_LAUNCHXL_PWM - * @brief Enum of PWM outputs on the board - */ -typedef enum CC2650_LAUNCHXL_PWM -{ - CC2650_LAUNCHXL_PWM0 = 0, - CC2650_LAUNCHXL_PWM1, - CC2650_LAUNCHXL_PWM2, - CC2650_LAUNCHXL_PWM3, - CC2650_LAUNCHXL_PWM4, - CC2650_LAUNCHXL_PWM5, - CC2650_LAUNCHXL_PWM6, - CC2650_LAUNCHXL_PWM7, - CC2650_LAUNCHXL_PWMCOUNT -} CC2650_LAUNCHXL_PWM; +void CC2650_LAUNCHXL_wakeUpExtFlash(void); /*! * @def CC2650_LAUNCHXL_ADCBufName * @brief Enum of ADCs */ typedef enum CC2650_LAUNCHXL_ADCBufName { - CC2650_LAUNCHXL_ADCBuf0 = 0, - CC2650_LAUNCHXL_ADCBufCOUNT + CC2650_LAUNCHXL_ADCBUF0 = 0, + + CC2650_LAUNCHXL_ADCBUFCOUNT } CC2650_LAUNCHXL_ADCBufName; +/*! + * @def CC2650_LAUNCHXL_ADCBuf0SourceName + * @brief Enum of ADCBuf channels + */ +typedef enum CC2650_LAUNCHXL_ADCBuf0ChannelName { + CC2650_LAUNCHXL_ADCBUF0CHANNEL0 = 0, + CC2650_LAUNCHXL_ADCBUF0CHANNEL1, + CC2650_LAUNCHXL_ADCBUF0CHANNEL2, + CC2650_LAUNCHXL_ADCBUF0CHANNEL3, + CC2650_LAUNCHXL_ADCBUF0CHANNEL4, + CC2650_LAUNCHXL_ADCBUF0CHANNEL5, + CC2650_LAUNCHXL_ADCBUF0CHANNEL6, + CC2650_LAUNCHXL_ADCBUF0CHANNEL7, + CC2650_LAUNCHXL_ADCBUF0CHANNELVDDS, + CC2650_LAUNCHXL_ADCBUF0CHANNELDCOUPL, + CC2650_LAUNCHXL_ADCBUF0CHANNELVSS, + + CC2650_LAUNCHXL_ADCBUF0CHANNELCOUNT +} CC2650_LAUNCHXL_ADCBuf0ChannelName; /*! * @def CC2650_LAUNCHXL_ADCName @@ -300,12 +199,155 @@ typedef enum CC2650_LAUNCHXL_ADCName { CC2650_LAUNCHXL_ADCDCOUPL, CC2650_LAUNCHXL_ADCVSS, CC2650_LAUNCHXL_ADCVDDS, + CC2650_LAUNCHXL_ADCCOUNT } CC2650_LAUNCHXL_ADCName; +/*! + * @def CC2650_LAUNCHXL_CryptoName + * @brief Enum of Crypto names + */ +typedef enum CC2650_LAUNCHXL_CryptoName { + CC2650_LAUNCHXL_CRYPTO0 = 0, + + CC2650_LAUNCHXL_CRYPTOCOUNT +} CC2650_LAUNCHXL_CryptoName; + +/*! + * @def CC2650_LAUNCHXL_GPIOName + * @brief Enum of GPIO names + */ +typedef enum CC2650_LAUNCHXL_GPIOName { + CC2650_LAUNCHXL_GPIO_S1 = 0, + CC2650_LAUNCHXL_GPIO_S2, + CC2650_LAUNCHXL_SPI_MASTER_READY, + CC2650_LAUNCHXL_SPI_SLAVE_READY, + CC2650_LAUNCHXL_GPIO_LED_GREEN, + CC2650_LAUNCHXL_GPIO_LED_RED, + CC2650_LAUNCHXL_GPIO_SPI_FLASH_CS, + CC2650_LAUNCHXL_SDSPI_CS, + CC2650_LAUNCHXL_GPIO_LCD_CS, + CC2650_LAUNCHXL_GPIO_LCD_POWER, + CC2650_LAUNCHXL_GPIO_LCD_ENABLE, + CC2650_LAUNCHXL_GPIOCOUNT +} CC2650_LAUNCHXL_GPIOName; + +/*! + * @def CC2650_LAUNCHXL_GPTimerName + * @brief Enum of GPTimer parts + */ +typedef enum CC2650_LAUNCHXL_GPTimerName { + CC2650_LAUNCHXL_GPTIMER0A = 0, + CC2650_LAUNCHXL_GPTIMER0B, + CC2650_LAUNCHXL_GPTIMER1A, + CC2650_LAUNCHXL_GPTIMER1B, + CC2650_LAUNCHXL_GPTIMER2A, + CC2650_LAUNCHXL_GPTIMER2B, + CC2650_LAUNCHXL_GPTIMER3A, + CC2650_LAUNCHXL_GPTIMER3B, + + CC2650_LAUNCHXL_GPTIMERPARTSCOUNT +} CC2650_LAUNCHXL_GPTimerName; + +/*! + * @def CC2650_LAUNCHXL_GPTimers + * @brief Enum of GPTimers + */ +typedef enum CC2650_LAUNCHXL_GPTimers { + CC2650_LAUNCHXL_GPTIMER0 = 0, + CC2650_LAUNCHXL_GPTIMER1, + CC2650_LAUNCHXL_GPTIMER2, + CC2650_LAUNCHXL_GPTIMER3, + + CC2650_LAUNCHXL_GPTIMERCOUNT +} CC2650_LAUNCHXL_GPTimers; + +/*! + * @def CC2650_LAUNCHXL_I2CName + * @brief Enum of I2C names + */ +typedef enum CC2650_LAUNCHXL_I2CName { + CC2650_LAUNCHXL_I2C0 = 0, + + CC2650_LAUNCHXL_I2CCOUNT +} CC2650_LAUNCHXL_I2CName; + +/*! + * @def CC2650_LAUNCHXL_NVSName + * @brief Enum of NVS names + */ +typedef enum CC2650_LAUNCHXL_NVSName { +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH + CC2650_LAUNCHXL_NVSCC26XX0 = 0, +#endif +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH + CC2650_LAUNCHXL_NVSSPI25X0, +#endif + + CC2650_LAUNCHXL_NVSCOUNT +} CC2650_LAUNCHXL_NVSName; + +/*! + * @def CC2650_LAUNCHXL_PWM + * @brief Enum of PWM outputs + */ +typedef enum CC2650_LAUNCHXL_PWMName { + CC2650_LAUNCHXL_PWM0 = 0, + CC2650_LAUNCHXL_PWM1, + CC2650_LAUNCHXL_PWM2, + CC2650_LAUNCHXL_PWM3, + CC2650_LAUNCHXL_PWM4, + CC2650_LAUNCHXL_PWM5, + CC2650_LAUNCHXL_PWM6, + CC2650_LAUNCHXL_PWM7, + + CC2650_LAUNCHXL_PWMCOUNT +} CC2650_LAUNCHXL_PWMName; + +/*! + * @def CC2650_LAUNCHXL_SDName + * @brief Enum of SD names + */ +typedef enum CC2650_LAUNCHXL_SDName { + CC2650_LAUNCHXL_SDSPI0 = 0, + + CC2650_LAUNCHXL_SDCOUNT +} CC2650_LAUNCHXL_SDName; + +/*! + * @def CC2650_LAUNCHXL_SPIName + * @brief Enum of SPI names + */ +typedef enum CC2650_LAUNCHXL_SPIName { + CC2650_LAUNCHXL_SPI0 = 0, + CC2650_LAUNCHXL_SPI1, + + CC2650_LAUNCHXL_SPICOUNT +} CC2650_LAUNCHXL_SPIName; + +/*! + * @def CC2650_LAUNCHXL_UARTName + * @brief Enum of UARTs + */ +typedef enum CC2650_LAUNCHXL_UARTName { + CC2650_LAUNCHXL_UART0 = 0, + + CC2650_LAUNCHXL_UARTCOUNT +} CC2650_LAUNCHXL_UARTName; + +/*! + * @def CC2650_LAUNCHXL_UDMAName + * @brief Enum of DMA buffers + */ +typedef enum CC2650_LAUNCHXL_UDMAName { + CC2650_LAUNCHXL_UDMA0 = 0, + + CC2650_LAUNCHXL_UDMACOUNT +} CC2650_LAUNCHXL_UDMAName; + /*! * @def CC2650_LAUNCHXL_WatchdogName - * @brief Enum of Watchdogs on the CC2650_LAUNCHXL dev board + * @brief Enum of Watchdogs */ typedef enum CC2650_LAUNCHXL_WatchdogName { CC2650_LAUNCHXL_WATCHDOG0 = 0, diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Makefile.cc2650 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Makefile.cc2650 index 1856533f2..8236f6360 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Makefile.cc2650 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Makefile.cc2650 @@ -6,9 +6,11 @@ DEVICE_FAMILY = CC26X0 BOARD_SOURCEFILES += CC2650_LAUNCHXL.c -SUPPORTS_PROP_MODE = 1 +SUPPORTS_PROP_MODE = 0 SUPPORTS_IEEE_MODE = 1 +SUPPORTS_HIGH_PA = 0 + ### Signal that we can be programmed with cc2538-bsl BOARD_SUPPORTS_BSL = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Board.h index be6ccc8bd..8940527b9 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Board.h @@ -33,6 +33,8 @@ #ifndef __BOARD_H #define __BOARD_H +#define Board_CC26X2R1_LAUNCHXL + #ifdef __cplusplus extern "C" { #endif diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c index 09d556caf..f654ab3f8 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c @@ -584,11 +584,8 @@ const uint_least8_t I2C_count = CC26X2R1_LAUNCHXL_I2CCOUNT; #define NVS_REGIONS_BASE 0x48000 #define SECTORSIZE 0x2000 #define REGIONSIZE (SECTORSIZE * 4) -#define SPISECTORSIZE 0x1000 -#define SPIREGIONSIZE (SPISECTORSIZE * 32) -#define VERIFYBUFSIZE 64 -static uint8_t verifyBuf[VERIFYBUFSIZE]; +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH /* * Reserve flash sectors for NVS driver use by placing an uninitialized byte @@ -627,11 +624,10 @@ static char flashBuf[REGIONSIZE]; #endif -/* Allocate objects for NVS and NVS SPI */ +/* Allocate objects for NVS Internal Regions */ NVSCC26XX_Object nvsCC26xxObjects[1]; -NVSSPI25X_Object nvsSPI25XObjects[1]; -/* Hardware attributes for NVS */ +/* Hardware attributes for NVS Internal Regions */ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { { .regionBase = (void *)flashBuf, @@ -639,7 +635,20 @@ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { }, }; -/* Hardware attributes for NVS SPI */ +#endif /* Board_EXCLUDE_NVS_INTERNAL_FLASH */ + +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH + +#define SPISECTORSIZE 0x1000 +#define SPIREGIONSIZE (SPISECTORSIZE * 32) +#define VERIFYBUFSIZE 64 + +static uint8_t verifyBuf[VERIFYBUFSIZE]; + +/* Allocate objects for NVS External Regions */ +NVSSPI25X_Object nvsSPI25XObjects[1]; + +/* Hardware attributes for NVS External Regions */ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { { .regionBaseOffset = 0, @@ -654,18 +663,24 @@ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { }, }; +#endif /* Board_EXCLUDE_NVS_EXTERNAL_FLASH */ + /* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ const NVS_Config NVS_config[CC26X2R1_LAUNCHXL_NVSCOUNT] = { +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH { .fxnTablePtr = &NVSCC26XX_fxnTable, .object = &nvsCC26xxObjects[0], .hwAttrs = &nvsCC26xxHWAttrs[0], }, +#endif +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH { .fxnTablePtr = &NVSSPI25X_fxnTable, .object = &nvsSPI25XObjects[0], .hwAttrs = &nvsSPI25XHWAttrs[0], }, +#endif }; const uint_least8_t NVS_count = CC26X2R1_LAUNCHXL_NVSCOUNT; @@ -955,89 +970,10 @@ const Watchdog_Config Watchdog_config[CC26X2R1_LAUNCHXL_WATCHDOGCOUNT] = { const uint_least8_t Watchdog_count = CC26X2R1_LAUNCHXL_WATCHDOGCOUNT; /* - * ======== CC26X2R1_LAUNCHXL_wakeUpExtFlash ======== + * Board-specific initialization function to disable external flash. + * This function is defined in the file CC26X2R1_LAUNCHXL_fxns.c */ -void CC26X2R1_LAUNCHXL_wakeUpExtFlash(void) -{ - PIN_Config extFlashPinTable[] = { - CC26X2R1_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - PIN_TERMINATE - }; - PIN_State extFlashPinState; - PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); - - /* - * To wake up we need to toggle the chip select at - * least 20 ns and ten wait at least 35 us. - */ - - /* Toggle chip select for ~20ns to wake ext. flash */ - PIN_setOutputValue(extFlashPinHandle, CC26X2R1_LAUNCHXL_SPI_FLASH_CS, 0); - /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ - CPUdelay(1); - PIN_setOutputValue(extFlashPinHandle, CC26X2R1_LAUNCHXL_SPI_FLASH_CS, 1); - /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ - CPUdelay(560); - - PIN_close(extFlashPinHandle); -} - -/* - * ======== CC26X2R1_LAUNCHXL_sendExtFlashByte ======== - */ -void CC26X2R1_LAUNCHXL_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) -{ - uint8_t i; - - PIN_setOutputValue(pinHandle, CC26X2R1_LAUNCHXL_SPI_FLASH_CS, 0); - - for (i = 0; i < 8; i++) { - PIN_setOutputValue(pinHandle, CC26X2R1_LAUNCHXL_SPI0_CLK, 0); - PIN_setOutputValue(pinHandle, CC26X2R1_LAUNCHXL_SPI0_MOSI, (byte >> (7 - i)) & 0x01); - PIN_setOutputValue(pinHandle, CC26X2R1_LAUNCHXL_SPI0_CLK, 1); - - /* - * Waste a few cycles to keep the CLK high for at - * least 45% of the period. - * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. - */ - CPUdelay(8); - } - - PIN_setOutputValue(pinHandle, CC26X2R1_LAUNCHXL_SPI0_CLK, 0); - PIN_setOutputValue(pinHandle, CC26X2R1_LAUNCHXL_SPI_FLASH_CS, 1); - - /* - * Keep CS high at least 40 us - * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us - */ - CPUdelay(700); -} - -/* - * ======== CC26X2R1_LAUNCHXL_shutDownExtFlash ======== - */ -void CC26X2R1_LAUNCHXL_shutDownExtFlash(void) -{ - /* To be sure we are putting the flash into sleep and not waking it, we first have to make a wake up call */ - CC26X2R1_LAUNCHXL_wakeUpExtFlash(); - - PIN_Config extFlashPinTable[] = { - CC26X2R1_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - CC26X2R1_LAUNCHXL_SPI0_CLK | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - CC26X2R1_LAUNCHXL_SPI0_MOSI | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - CC26X2R1_LAUNCHXL_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, - PIN_TERMINATE - }; - PIN_State extFlashPinState; - PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); - - uint8_t extFlashShutdown = 0xB9; - - CC26X2R1_LAUNCHXL_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); - - PIN_close(extFlashPinHandle); -} +extern void Board_initHook(void); /* * ======== CC26X2R1_LAUNCHXL_initGeneral ======== @@ -1051,6 +987,6 @@ void CC26X2R1_LAUNCHXL_initGeneral(void) while (1); } - /* Shut down external flash as default */ - CC26X2R1_LAUNCHXL_shutDownExtFlash(); + /* Perform board-specific initialization */ + Board_initHook(); } diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h index 7fdc20e09..db519d9f9 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h @@ -342,8 +342,12 @@ typedef enum CC26X2R1_LAUNCHXL_I2CName { * @brief Enum of NVS names */ typedef enum CC26X2R1_LAUNCHXL_NVSName { +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH CC26X2R1_LAUNCHXL_NVSCC26XX0 = 0, +#endif +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH CC26X2R1_LAUNCHXL_NVSSPI25X0, +#endif CC26X2R1_LAUNCHXL_NVSCOUNT } CC26X2R1_LAUNCHXL_NVSName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Makefile.cc26x2r1 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Makefile.cc26x2r1 index 124fff433..c1ef73bb4 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Makefile.cc26x2r1 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Makefile.cc26x2r1 @@ -6,9 +6,11 @@ DEVICE_FAMILY = CC26X2 BOARD_SOURCEFILES += CC26X2R1_LAUNCHXL.c -SUPPORTS_PROP_MODE = 1 +SUPPORTS_PROP_MODE = 0 SUPPORTS_IEEE_MODE = 1 +SUPPORTS_HIGH_PA = 0 + ### Signal that we can be programmed with cc2538-bsl BOARD_SUPPORTS_BSL = 0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Makefile.cc1350 b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Makefile.cc1350 index 48e6d054b..5e4c5c260 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Makefile.cc1350 +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Makefile.cc1350 @@ -9,6 +9,8 @@ BOARD_SOURCEFILES += CC1350STK.c SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 1 +SUPPORTS_HIGH_PA = 0 + ### Signal that we can be programmed with cc2538-bsl BOARD_SUPPORTS_BSL = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 index 2e6c713e6..f0fdb2e67 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 @@ -6,9 +6,11 @@ DEVICE_FAMILY = CC26X0 BOARD_SOURCEFILES += CC2650STK.c -SUPPORTS_PROP_MODE = 1 +SUPPORTS_PROP_MODE = 0 SUPPORTS_IEEE_MODE = 1 +SUPPORTS_HIGH_PA = 0 + ### Signal that we can be programmed with cc2538-bsl BOARD_SUPPORTS_BSL = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 index 4efb443ef..d666d4f9f 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 @@ -9,6 +9,8 @@ BOARD_SOURCEFILES += CC1310DK_7XD.c SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 1 +SUPPORTS_HIGH_PA = 0 + ### Signal that we can be programmed with cc2538-bsl BOARD_SUPPORTS_BSL = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Makefile.cc26x0 b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Makefile.cc26x0 index 372d2103d..a27625228 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Makefile.cc26x0 +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Makefile.cc26x0 @@ -6,9 +6,11 @@ DEVICE_FAMILY = CC26X0 BOARD_SOURCEFILES += CC2650DK_7ID.c -SUPPORTS_PROP_MODE = 1 +SUPPORTS_PROP_MODE = 0 SUPPORTS_IEEE_MODE = 1 +SUPPORTS_HIGH_PA = 0 + ### Signal that we can be programmed with cc2538-bsl BOARD_SUPPORTS_BSL = 1 From 40227d0817a44d38c4f9a8f8a46d13377612697b Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Thu, 31 May 2018 17:17:07 +0200 Subject: [PATCH 247/485] Fixed RF Settings, Board files, Sensortag sensors --- .../{simplelink-def.h => cc13xx-cc26xx-def.h} | 2 +- .../cc13x2-cc26x2/cc13x2-cc26x2-def.h | 104 -- .../cc13xx-cc26xx-def.h} | 6 +- .../cc13x2-cc26x2/simplelink-def.h | 104 -- ...simplelink-conf.h => cc13xx-cc26xx-conf.h} | 128 +-- arch/cpu/cc13xx-cc26xx/ccfg-conf.h | 78 +- arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c | 6 +- arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c | 114 +- .../rf-settings/cc13x0/ieee-settings.c | 17 +- .../rf-settings/cc13x0/ieee-settings.h | 10 +- .../rf-settings/cc13x0/prop-settings.c | 10 +- .../rf-settings/cc13x0/prop-settings.h | 8 +- .../rf-settings/cc13x2/ieee-settings.c | 10 +- .../rf-settings/cc13x2/ieee-settings.h | 8 +- .../rf-settings/cc13x2/prop-settings.c | 10 +- .../rf-settings/cc13x2/prop-settings.h | 8 +- .../cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 3 + .../simplelink/cc13xx-cc26xx/contiki-conf.h | 18 +- .../launchpad/Makefile.launchpad | 2 + .../cc13xx-cc26xx/launchpad/cc1310/Board.h | 2 + .../launchpad/cc1310/CC1310_LAUNCHXL.c | 121 +- .../launchpad/cc1310/CC1310_LAUNCHXL.h | 4 + .../launchpad/cc1310/CC1310_LAUNCHXL_fxns.c | 157 +++ .../launchpad/cc1310/Makefile.cc1310 | 3 +- .../cc13xx-cc26xx/launchpad/cc1312r1/Board.h | 2 + .../launchpad/cc1312r1/CC1312R1_LAUNCHXL.c | 120 +- .../launchpad/cc1312r1/CC1312R1_LAUNCHXL.h | 4 + .../cc1312r1/CC1312R1_LAUNCHXL_fxns.c | 155 +++ .../launchpad/cc1312r1/Makefile.cc1312r1 | 3 +- .../cc13xx-cc26xx/launchpad/cc1350-4/Board.h | 9 + .../launchpad/cc1350-4/CC1350_LAUNCHXL_433.c | 171 +-- .../launchpad/cc1350-4/CC1350_LAUNCHXL_433.h | 4 + .../cc1350-4/CC1350_LAUNCHXL_433_fxns.c | 191 ++++ .../launchpad/cc1350-4/Makefile.cc1350-4 | 3 +- .../cc13xx-cc26xx/launchpad/cc1350/Board.h | 9 + .../launchpad/cc1350/CC1350_LAUNCHXL.c | 170 +-- .../launchpad/cc1350/CC1350_LAUNCHXL.h | 4 + .../launchpad/cc1350/CC1350_LAUNCHXL_fxns.c | 193 ++++ .../launchpad/cc1350/Makefile.cc1350 | 3 +- .../cc13xx-cc26xx/launchpad/cc1352p1/Board.h | 11 + .../launchpad/cc1352p1/CC1352P1_LAUNCHXL.c | 235 +--- .../launchpad/cc1352p1/CC1352P1_LAUNCHXL.h | 4 + .../cc1352p1/CC1352P1_LAUNCHXL_fxns.c | 255 +++++ .../launchpad/cc1352p1/Makefile.cc1352p1 | 3 +- .../cc13xx-cc26xx/launchpad/cc1352p_2/Board.h | 162 +++ .../launchpad/cc1352p_2/CC1352P_2_LAUNCHXL.c | 976 ++++++++++++++++ .../launchpad/cc1352p_2/CC1352P_2_LAUNCHXL.h | 435 +++++++ .../cc1352p_2/CC1352P_2_LAUNCHXL_fxns.c | 255 +++++ .../launchpad/cc1352p_2/Makefile.cc1352p_2 | 19 + .../cc13xx-cc26xx/launchpad/cc1352p_4/Board.h | 162 +++ .../launchpad/cc1352p_4/CC1352P_4_LAUNCHXL.c | 976 ++++++++++++++++ .../launchpad/cc1352p_4/CC1352P_4_LAUNCHXL.h | 435 +++++++ .../cc1352p_4/CC1352P_4_LAUNCHXL_fxns.c | 255 +++++ .../launchpad/cc1352p_4/Makefile.cc1352p_4 | 19 + .../cc13xx-cc26xx/launchpad/cc1352r1/Board.h | 8 + .../launchpad/cc1352r1/CC1352R1_LAUNCHXL.c | 163 +-- .../launchpad/cc1352r1/CC1352R1_LAUNCHXL.h | 4 + .../cc1352r1/CC1352R1_LAUNCHXL_fxns.c | 186 +++ .../launchpad/cc1352r1/Makefile.cc1352r1 | 3 +- .../launchpad/cc2650/CC2650_LAUNCHXL_fxns.c | 156 +++ .../launchpad/cc2650/Makefile.cc2650 | 3 +- .../cc26x2r1/CC26X2R1_LAUNCHXL_fxns.c | 156 +++ .../launchpad/cc26x2r1/Makefile.cc26x2r1 | 3 +- .../sensortag/Makefile.sensortag | 6 + .../cc13xx-cc26xx/sensortag/bmp-280-sensor.c | 329 +++--- .../cc13xx-cc26xx/sensortag/bmp-280-sensor.h | 10 +- .../cc13xx-cc26xx/sensortag/board-i2c.c | 343 ------ .../cc13xx-cc26xx/sensortag/board-i2c.h | 131 --- .../sensortag/button-sensor-arch.c | 198 ++++ .../{button-sensor.h => button-sensor-arch.h} | 27 +- .../cc13xx-cc26xx/sensortag/button-sensor.c | 281 ----- .../cc13xx-cc26xx/sensortag/buzzer.c | 179 +-- .../cc13xx-cc26xx/sensortag/buzzer.h | 7 +- .../cc13xx-cc26xx/sensortag/cc1350/Board.h | 5 + .../sensortag/cc1350/CC1350STK.c | 90 +- .../sensortag/cc1350/CC1350STK_fxns.c | 152 +++ .../sensortag/cc1350/Makefile.cc1350 | 3 +- .../cc13xx-cc26xx/sensortag/cc2650/Board.h | 116 +- .../sensortag/cc2650/CC2650STK.c | 1015 +++++++++-------- .../sensortag/cc2650/CC2650STK.h | 461 ++++---- .../sensortag/cc2650/CC2650STK_fxns.c | 152 +++ .../sensortag/cc2650/Makefile.cc2650 | 3 +- .../cc13xx-cc26xx/sensortag/hdc-1000-sensor.c | 203 ++-- .../cc13xx-cc26xx/sensortag/hdc-1000-sensor.h | 19 +- .../cc13xx-cc26xx/sensortag/leds-arch.c | 99 ++ .../cc13xx-cc26xx/sensortag/mpu-9250-sensor.c | 674 +++++------ .../cc13xx-cc26xx/sensortag/mpu-9250-sensor.h | 67 +- .../cc13xx-cc26xx/sensortag/opt-3001-sensor.c | 318 +++--- .../cc13xx-cc26xx/sensortag/opt-3001-sensor.h | 11 + .../cc13xx-cc26xx/sensortag/reed-relay.c | 74 +- .../cc13xx-cc26xx/sensortag/reed-relay.h | 2 + .../cc13xx-cc26xx/sensortag/sensortag.c | 129 +-- .../cc13xx-cc26xx/sensortag/tmp-007-sensor.c | 311 ++--- .../cc13xx-cc26xx/sensortag/tmp-007-sensor.h | 19 +- .../cc13xx-cc26xx/srf06/Makefile.srf06 | 2 + .../srf06/cc13x0/Makefile.cc13x0 | 1 + .../srf06/cc26x0/Makefile.cc26x0 | 1 + 97 files changed, 8328 insertions(+), 3968 deletions(-) rename arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/{simplelink-def.h => cc13xx-cc26xx-def.h} (99%) delete mode 100644 arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2-def.h rename arch/cpu/cc13xx-cc26xx/{cc13x0-cc26x0/cc13x0-cc26x0-def.h => cc13x2-cc26x2/cc13xx-cc26xx-def.h} (95%) delete mode 100644 arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/simplelink-def.h rename arch/cpu/cc13xx-cc26xx/{simplelink-conf.h => cc13xx-cc26xx-conf.h} (59%) create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL_fxns.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL_fxns.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433_fxns.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL_fxns.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL_fxns.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/Board.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/CC1352P_2_LAUNCHXL.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/CC1352P_2_LAUNCHXL.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/CC1352P_2_LAUNCHXL_fxns.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/Makefile.cc1352p_2 create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/Board.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/CC1352P_4_LAUNCHXL.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/CC1352P_4_LAUNCHXL.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/CC1352P_4_LAUNCHXL_fxns.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/Makefile.cc1352p_4 create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL_fxns.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL_fxns.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL_fxns.c delete mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-i2c.c delete mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-i2c.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor-arch.c rename arch/platform/simplelink/cc13xx-cc26xx/sensortag/{button-sensor.h => button-sensor-arch.h} (73%) delete mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK_fxns.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK_fxns.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/leds-arch.c diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/simplelink-def.h b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13xx-cc26xx-def.h similarity index 99% rename from arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/simplelink-def.h rename to arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13xx-cc26xx-def.h index 40785b20c..563bbff56 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/simplelink-def.h +++ b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13xx-cc26xx-def.h @@ -32,7 +32,7 @@ #ifndef CC13XX_CC26XX_DEF_H_ #define CC13XX_CC26XX_DEF_H_ /*---------------------------------------------------------------------------*/ -#include "cm4/cm4-def.h" +#include /*---------------------------------------------------------------------------*/ /* TSCH related defines */ diff --git a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2-def.h b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2-def.h deleted file mode 100644 index 5a1d855eb..000000000 --- a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2-def.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2017, 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 CC13XX_CC26XX_DEF_H_ -#define CC13XX_CC26XX_DEF_H_ -/*---------------------------------------------------------------------------*/ -#include -/*---------------------------------------------------------------------------*/ -/* TSCH related defines */ - -/* Delay between GO signal and SFD */ -#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(81)) -/* Delay between GO signal and start listening. - * This value is so small because the radio is constantly on within each timeslot. */ -#define RADIO_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(15)) -/* Delay between the SFD finishes arriving and it is detected in software. */ -#define RADIO_DELAY_BEFORE_DETECT ((unsigned)US_TO_RTIMERTICKS(352)) - -/* Timer conversion; radio is running at 4 MHz */ -#define RADIO_TIMER_SECOND 4000000u -#if (RTIMER_SECOND % 256) || (RADIO_TIMER_SECOND % 256) -#error RADIO_TO_RTIMER macro must be fixed! -#endif -#define RADIO_TO_RTIMER(X) ((uint32_t)(((uint64_t)(X) * (RTIMER_SECOND / 256)) / (RADIO_TIMER_SECOND / 256))) -#define USEC_TO_RADIO(X) ((X) * 4) - -/* The PHY header (preamble + SFD, 4+1 bytes) duration is equivalent to 10 symbols */ -#define RADIO_IEEE_802154_PHY_HEADER_DURATION_USEC 160 - -/* Do not turn off TSCH within a timeslot: not enough time */ -#define TSCH_CONF_RADIO_ON_DURING_TIMESLOT 1 - -/* Disable TSCH frame filtering */ -#define TSCH_CONF_HW_FRAME_FILTERING 0 - -/* Use hardware timestamps */ -#ifndef TSCH_CONF_RESYNC_WITH_SFD_TIMESTAMPS -#define TSCH_CONF_RESYNC_WITH_SFD_TIMESTAMPS 1 -#define TSCH_CONF_TIMESYNC_REMOVE_JITTER 0 -#endif - -#ifndef TSCH_CONF_BASE_DRIFT_PPM -/* The drift compared to "true" 10ms slots. - * Enable adaptive sync to enable compensation for this. - * Slot length 10000 usec - * 328 ticks - * Tick duration 30.517578125 usec - * Real slot duration 10009.765625 usec - * Target - real duration = -9.765625 usec - * TSCH_CONF_BASE_DRIFT_PPM -977 - */ -#define TSCH_CONF_BASE_DRIFT_PPM -977 -#endif - -/* 10 times per second */ -#ifndef TSCH_CONF_CHANNEL_SCAN_DURATION -#define TSCH_CONF_CHANNEL_SCAN_DURATION (CLOCK_SECOND / 10) -#endif - -/* Slightly reduce the TSCH guard time (from 2200 usec to 1800 usec) to make sure - * the CC26xx radio has sufficient time to start up. */ -#ifndef TSCH_CONF_RX_WAIT -#define TSCH_CONF_RX_WAIT 1800 -#endif -/*---------------------------------------------------------------------------*/ -#define RTIMER_ARCH_SECOND 65536 -/*---------------------------------------------------------------------------*/ -/* Path to CMSIS header */ -#define CMSIS_CONF_HEADER_PATH "cc13x2-cc26x2-cm4.h" - -/* Path to headers with implementation of mutexes and memory barriers */ -#define MUTEX_CONF_ARCH_HEADER_PATH "mutex-cortex.h" -#define MEMORY_BARRIER_CONF_ARCH_HEADER_PATH "memory-barrier-cortex.h" -/*---------------------------------------------------------------------------*/ -#endif /* CC13XX_CC26XX_DEF_H_ */ -/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0-def.h b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13xx-cc26xx-def.h similarity index 95% rename from arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0-def.h rename to arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13xx-cc26xx-def.h index 5a1d855eb..7d54aa45a 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0-def.h +++ b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13xx-cc26xx-def.h @@ -37,12 +37,12 @@ /* TSCH related defines */ /* Delay between GO signal and SFD */ -#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(81)) +#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(81)) /* Delay between GO signal and start listening. * This value is so small because the radio is constantly on within each timeslot. */ -#define RADIO_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(15)) +#define RADIO_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(15)) /* Delay between the SFD finishes arriving and it is detected in software. */ -#define RADIO_DELAY_BEFORE_DETECT ((unsigned)US_TO_RTIMERTICKS(352)) +#define RADIO_DELAY_BEFORE_DETECT ((unsigned)US_TO_RTIMERTICKS(352)) /* Timer conversion; radio is running at 4 MHz */ #define RADIO_TIMER_SECOND 4000000u diff --git a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/simplelink-def.h b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/simplelink-def.h deleted file mode 100644 index ada97c4b5..000000000 --- a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/simplelink-def.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2017, 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 CC13XX_CC26XX_DEF_H_ -#define CC13XX_CC26XX_DEF_H_ -/*---------------------------------------------------------------------------*/ -#include "cm4/cm4-def.h" -/*---------------------------------------------------------------------------*/ -/* TSCH related defines */ - -/* Delay between GO signal and SFD */ -#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(81)) -/* Delay between GO signal and start listening. - * This value is so small because the radio is constantly on within each timeslot. */ -#define RADIO_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(15)) -/* Delay between the SFD finishes arriving and it is detected in software. */ -#define RADIO_DELAY_BEFORE_DETECT ((unsigned)US_TO_RTIMERTICKS(352)) - -/* Timer conversion; radio is running at 4 MHz */ -#define RADIO_TIMER_SECOND 4000000u -#if (RTIMER_SECOND % 256) || (RADIO_TIMER_SECOND % 256) -#error RADIO_TO_RTIMER macro must be fixed! -#endif -#define RADIO_TO_RTIMER(X) ((uint32_t)(((uint64_t)(X) * (RTIMER_SECOND / 256)) / (RADIO_TIMER_SECOND / 256))) -#define USEC_TO_RADIO(X) ((X) * 4) - -/* The PHY header (preamble + SFD, 4+1 bytes) duration is equivalent to 10 symbols */ -#define RADIO_IEEE_802154_PHY_HEADER_DURATION_USEC 160 - -/* Do not turn off TSCH within a timeslot: not enough time */ -#define TSCH_CONF_RADIO_ON_DURING_TIMESLOT 1 - -/* Disable TSCH frame filtering */ -#define TSCH_CONF_HW_FRAME_FILTERING 0 - -/* Use hardware timestamps */ -#ifndef TSCH_CONF_RESYNC_WITH_SFD_TIMESTAMPS -#define TSCH_CONF_RESYNC_WITH_SFD_TIMESTAMPS 1 -#define TSCH_CONF_TIMESYNC_REMOVE_JITTER 0 -#endif - -#ifndef TSCH_CONF_BASE_DRIFT_PPM -/* The drift compared to "true" 10ms slots. - * Enable adaptive sync to enable compensation for this. - * Slot length 10000 usec - * 328 ticks - * Tick duration 30.517578125 usec - * Real slot duration 10009.765625 usec - * Target - real duration = -9.765625 usec - * TSCH_CONF_BASE_DRIFT_PPM -977 - */ -#define TSCH_CONF_BASE_DRIFT_PPM -977 -#endif - -/* 10 times per second */ -#ifndef TSCH_CONF_CHANNEL_SCAN_DURATION -#define TSCH_CONF_CHANNEL_SCAN_DURATION (CLOCK_SECOND / 10) -#endif - -/* Slightly reduce the TSCH guard time (from 2200 usec to 1800 usec) to make sure - * the CC26xx radio has sufficient time to start up. */ -#ifndef TSCH_CONF_RX_WAIT -#define TSCH_CONF_RX_WAIT 1800 -#endif -/*---------------------------------------------------------------------------*/ -#define RTIMER_ARCH_SECOND 65536 -/*---------------------------------------------------------------------------*/ -/* Path to CMSIS header */ -#define CMSIS_CONF_HEADER_PATH "cc13x2-cc26x2-cm4.h" - -/* Path to headers with implementation of mutexes and memory barriers */ -#define MUTEX_CONF_ARCH_HEADER_PATH "mutex-cortex.h" -#define MEMORY_BARRIER_CONF_ARCH_HEADER_PATH "memory-barrier-cortex.h" -/*---------------------------------------------------------------------------*/ -#endif /* CC13XX_CC26XX_DEF_H_ */ -/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/simplelink-conf.h b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h similarity index 59% rename from arch/cpu/cc13xx-cc26xx/simplelink-conf.h rename to arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h index 48844ae96..fe91d840c 100644 --- a/arch/cpu/cc13xx-cc26xx/simplelink-conf.h +++ b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h @@ -30,7 +30,7 @@ */ /*---------------------------------------------------------------------------*/ /** - * \addtogroup cc26xx + * \addtogroup cc13xx-cc26xx * @{ * * \file @@ -40,6 +40,8 @@ #ifndef SIMPLELINK_CONF_H_ #define SIMPLELINK_CONF_H_ /*---------------------------------------------------------------------------*/ +#include "cc13xx-cc26xx-def.h" +/*---------------------------------------------------------------------------*/ /** * \name Network Stack Configuration * @@ -51,51 +53,74 @@ * You need to set this to 1 to use TSCH with its default 2.2ms or larger guard time. */ #ifndef CC2650_FAST_RADIO_STARTUP -#define CC2650_FAST_RADIO_STARTUP (MAC_CONF_WITH_TSCH) +#define CC2650_FAST_RADIO_STARTUP (MAC_CONF_WITH_TSCH) #endif #ifdef RF_CHANNEL -#define RF_CORE_CONF_CHANNEL RF_CHANNEL +#define RF_CORE_CONF_CHANNEL RF_CHANNEL #endif #ifndef RF_CORE_CONF_CHANNEL -#define RF_CORE_CONF_CHANNEL 25 +#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 +#define PROP_MODE_CONF_RX_BUF_CNT 4 #endif -/* - * Auto-configure Prop-mode radio if we are running on CC13xx, unless the - * project has specified otherwise. Depending on the final mode, determine a - * default channel (again, if unspecified) and configure RDC params - */ -#if CPU_FAMILY_CC13XX -#ifndef CC13XX_CONF_PROP_MODE -#define CC13XX_CONF_PROP_MODE 1 -#endif /* CC13XX_CONF_PROP_MODE */ -#endif /* CPU_FAMILY_CC13XX */ +/* Configure Radio mode, i.e. prop or ieee */ +/* CC13xx supports both IEEE and Prop mode, depending on which device */ +/* CC26xx only supports IEEE mode */ +#if defined(DEVICE_LINE_CC13XX) -#if CC13XX_CONF_PROP_MODE -#define NETSTACK_CONF_RADIO prop_mode_driver +/* Default mode should be prop for prop-only devices (CC1310, CC1312); + * Else, IEEE mode is default. */ +# ifndef CC13XX_CONF_PROP_MODE +# if (SUPPORTS_IEEE_MODE == 0) +# define CC13XX_CONF_PROP_MODE 1 +# else +# define CC13XX_CONF_PROP_MODE 0 +# endif +# endif -#ifndef RF_CORE_CONF_CHANNEL -#define RF_CORE_CONF_CHANNEL 0 -#endif -#define CSMA_CONF_ACK_WAIT_TIME (RTIMER_SECOND / 400) -#define CSMA_CONF_AFTER_ACK_DETECTED_WAIT_TIME (RTIMER_SECOND / 1000) -#define CSMA_CONF_SEND_SOFT_ACK 1 +# if (CC13XX_CONF_PROP_MODE == 1) && (SUPPORTS_PROP_MODE == 1) +/*----- CC13xx Prop Mode ----------------------------------------------------*/ +# define NETSTACK_CONF_RADIO prop_mode_driver -#else /* CC13XX_CONF_PROP_MODE */ -#define NETSTACK_CONF_RADIO ieee_mode_driver +# define CSMA_CONF_ACK_WAIT_TIME (RTIMER_SECOND / 400) +# define CSMA_CONF_AFTER_ACK_DETECTED_WAIT_TIME \ + (RTIMER_SECOND / 1000) +# define CSMA_CONF_SEND_SOFT_ACK 1 -#define CSMA_CONF_SEND_SOFT_ACK 0 -#endif /* CC13XX_CONF_PROP_MODE */ +# elif (CC13XX_CONF_PROP_MODE == 0) && (SUPPORTS_IEEE_MODE == 1) +/*----- CC13xx IEEE Mode ----------------------------------------------------*/ +# define NETSTACK_CONF_RADIO ieee_mode_driver -#define NETSTACK_RADIO_MAX_PAYLOAD_LEN 125 +# define CSMA_CONF_SEND_SOFT_ACK 0 + +# else +# error "Invalid radio mode configuration of CC13xx device" +# endif /* (CC13XX_CONF_PROP_MODE == 1) && (SUPPORTS_PROP_MODE == 1) */ + +#elif defined(DEVICE_LINE_CC26XX) + +# if (SUPPORTS_IEEE_MODE == 1) +/*----- CC26xx IEEE Mode ----------------------------------------------------*/ +# define NETSTACK_CONF_RADIO ieee_mode_driver + +# define CSMA_CONF_SEND_SOFT_ACK 0 + +# else +# error "IEEE mode only supported by CC26xx devices" +# endif /* (SUPPORTS_IEEE_MODE == 1) */ + +#else +# error "Unsupported Device Line defined" +#endif /* defined(DEVICE_LINE_CC13xx) */ + +#define NETSTACK_RADIO_MAX_PAYLOAD_LEN 125 /** @} */ /*---------------------------------------------------------------------------*/ @@ -111,7 +136,7 @@ * 1 => Use a hardcoded address, configured by IEEE_ADDR_CONF_ADDRESS */ #ifndef IEEE_ADDR_CONF_HARDCODED -#define IEEE_ADDR_CONF_HARDCODED 0 +#define IEEE_ADDR_CONF_HARDCODED 0 #endif /** @@ -119,7 +144,7 @@ * is defined as 1 */ #ifndef IEEE_ADDR_CONF_ADDRESS -#define IEEE_ADDR_CONF_ADDRESS { 0x00, 0x12, 0x4B, 0x00, 0x89, 0xAB, 0xCD, 0xEF } +#define IEEE_ADDR_CONF_ADDRESS { 0x00, 0x12, 0x4B, 0x00, 0x89, 0xAB, 0xCD, 0xEF } #endif /** @} */ /*---------------------------------------------------------------------------*/ @@ -131,15 +156,15 @@ /* RF Config */ #ifndef IEEE_MODE_CONF_AUTOACK -#define IEEE_MODE_CONF_AUTOACK 1 /**< RF H/W generates ACKs */ +#define IEEE_MODE_CONF_AUTOACK 1 /**< RF H/W generates ACKs */ #endif #ifndef IEEE_MODE_CONF_PROMISCOUS -#define IEEE_MODE_CONF_PROMISCOUS 0 /**< 1 to enable promiscous mode */ +#define IEEE_MODE_CONF_PROMISCOUS 0 /**< 1 to enable promiscous mode */ #endif #ifndef RF_BLE_CONF_ENABLED -#define RF_BLE_CONF_ENABLED 0 /**< 0 to disable BLE support */ +#define RF_BLE_CONF_ENABLED 0 /**< 0 to disable BLE support */ #endif /** @} */ /*---------------------------------------------------------------------------*/ @@ -149,16 +174,16 @@ * @{ */ #ifndef SIMPLELINK_UART_CONF_ENABLE -#define SIMPLELINK_UART_CONF_ENABLE 1 /**< Enable/Disable UART I/O */ +#define SIMPLELINK_UART_CONF_ENABLE 1 /**< Enable/Disable UART I/O */ #endif #ifndef SIMPLELINK_UART_CONF_BAUD_RATE -#define SIMPLELINK_UART_CONF_BAUD_RATE 115200 /**< Default UART0 baud rate */ +#define SIMPLELINK_UART_CONF_BAUD_RATE 115200 /**< Default UART0 baud rate */ #endif /* Enable I/O over the Debugger Devpack - Only relevant for the SensorTag */ #ifndef BOARD_CONF_DEBUGGER_DEVPACK -#define BOARD_CONF_DEBUGGER_DEVPACK 1 +#define BOARD_CONF_DEBUGGER_DEVPACK 1 #endif #ifndef SLIP_ARCH_CONF_ENABLED @@ -168,35 +193,10 @@ * keep using SLIP */ #if defined(UIP_FALLBACK_INTERFACE) || defined(CMD_CONF_OUTPUT) -#define SLIP_ARCH_CONF_ENABLED 1 -#endif -#endif -/** @} */ -/*---------------------------------------------------------------------------*/ -/** - * \name JTAG interface configuration - * - * Enable/Disable the JTAG DAP and TAP interfaces on the chip. - * Setting this to 0 will disable access to the debug interface - * to secure deployed images. - * @{ - */ -#ifndef CCXXWARE_CONF_JTAG_INTERFACE_ENABLE -#define CCXXWARE_CONF_JTAG_INTERFACE_ENABLE 1 -#endif -/** @} */ -/*---------------------------------------------------------------------------*/ -/** - * \name ROM Bootloader configuration - * - * Enable/Disable the ROM bootloader in your image, if the board supports it. - * Look in board.h to choose the DIO and corresponding level that will cause - * the chip to enter bootloader mode. - * @{ - */ -#ifndef ROM_BOOTLOADER_ENABLE -#define ROM_BOOTLOADER_ENABLE 0 +#define SLIP_ARCH_CONF_ENABLED 1 #endif + +#endif /* SLIP_ARCH_CONF_ENABLED */ /** @} */ /*---------------------------------------------------------------------------*/ #endif /* SIMPLELINK_CONF_H_ */ diff --git a/arch/cpu/cc13xx-cc26xx/ccfg-conf.h b/arch/cpu/cc13xx-cc26xx/ccfg-conf.h index 0f5c4894e..9c1cf3263 100644 --- a/arch/cpu/cc13xx-cc26xx/ccfg-conf.h +++ b/arch/cpu/cc13xx-cc26xx/ccfg-conf.h @@ -27,47 +27,73 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ +/*---------------------------------------------------------------------------*/ /** - * \addtogroup cc26xx - * @{ - * - * \defgroup cc26xx-ccxxware-conf CCxxware-specific configuration - * + * \addtogroup cc13xx-cc26xx * @{ * * \file - * CCxxware-specific configuration for the cc26xx-cc13xx CPU family + * Customer Configuration (CCFG) for the cc13xx-cc26xx CPU family */ +/*---------------------------------------------------------------------------*/ #ifndef CCFG_CONF_H_ #define CCFG_CONF_H_ - +/*---------------------------------------------------------------------------*/ #include "contiki-conf.h" - /*---------------------------------------------------------------------------*/ /** - * \brief JTAG interface configuration + * \name JTAG interface configuration * - * Those values are not meant to be modified by the user + * Enable/Disable the JTAG DAP and TAP interfaces on the chip. + * Setting this to 0 will disable access to the debug interface + * to secure deployed images. * @{ */ -#if CCXXWARE_CONF_JTAG_INTERFACE_ENABLE -#define SET_CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE 0xC5 -#define SET_CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE 0xC5 -#define SET_CCFG_CCFG_TAP_DAP_0_PRCM_TAP_ENABLE 0xC5 -#define SET_CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE 0xC5 -#define SET_CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE 0xC5 -#define SET_CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE 0xC5 -#define SET_CCFG_CCFG_TAP_DAP_1_WUC_TAP_ENABLE 0xC5 -#else -#define SET_CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE 0x00 -#define SET_CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE 0x00 -#define SET_CCFG_CCFG_TAP_DAP_0_PRCM_TAP_ENABLE 0x00 -#define SET_CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE 0x00 -#define SET_CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE 0x00 -#define SET_CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE 0x00 -#define SET_CCFG_CCFG_TAP_DAP_1_WUC_TAP_ENABLE 0x00 +#if CCFG_CONF_JTAG_INTERFACE_DISABLE +# define SET_CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE 0x00 +# define SET_CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE 0x00 +# define SET_CCFG_CCFG_TAP_DAP_0_PRCM_TAP_ENABLE 0x00 +# define SET_CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE 0x00 +# define SET_CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE 0x00 +# define SET_CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE 0x00 +# define SET_CCFG_CCFG_TAP_DAP_1_WUC_TAP_ENABLE 0x00 +#endif /* CCFG_CONF_JTAG_INTERFACE_DISABLE */ +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \name TX Power Boost Mode + * + * CC13xx only: Enable/Disable boost mode, which enables maximum +14 dBm + * output power with the default PA front-end configuration. + * @{ + */ +#if defined(DEVICE_LINE_CC13XX) && CC13XX_CONF_TXPOWER_BOOST_MODE +# define CCFG_FORCE_VDDR_HH 1 +#endif /* CCFG_CONF_TXPOWER_BOOST_MODE */ +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \name ROM Bootloader configuration + * + * Enable/Disable the ROM bootloader in your image, if the board supports it. + * Look in board.h to choose the DIO and corresponding level that will cause + * the chip to enter bootloader mode. + * @{ + */ +#ifndef CCFG_CONF_ROM_BOOTLOADER_ENABLE +#define CCFG_CONF_ROM_BOOTLOADER_ENABLE 0 +#endif + +#if CCFG_CONF_ROM_BOOTLOADER_ENABLE +# define SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE 0xC5 +# define SET_CCFG_BL_CONFIG_BL_LEVEL 0x00 +# if defined(CCFG_CONF_BL_PIN_NUMBER) +# define SET_CCFG_BL_CONFIG_BL_PIN_NUMBER CCFG_CONF_BL_PIN_NUMBER +# endif +# define SET_CCFG_BL_CONFIG_BL_ENABLE 0xC5 #endif /** @} */ +/*---------------------------------------------------------------------------*/ #endif /* CCFG_CONF_H_ */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c index 3ca674ad3..8d8c16e47 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c @@ -123,7 +123,7 @@ #ifdef TX_POWER_CONF_TABLE # define TX_POWER_TABLE TX_POWER_CONF_TABLE #else -# define TX_POWER_TABLE txPowerTable +# define TX_POWER_TABLE ieeeTxPowerTable #endif /*---------------------------------------------------------------------------*/ /* TX power table convenience macros */ @@ -173,7 +173,7 @@ static RF_Handle g_rfHandle; /* RF Core command pointers */ static volatile rfc_CMD_RADIO_SETUP_t *g_vpCmdRadioSetup = &RF_cmdRadioSetup; -static volatile rfc_CMD_FS_t *g_vpCmdFs = &RF_cmdFs; +static volatile rfc_CMD_FS_t *g_vpCmdFs = &RF_cmdIeeeFs; static volatile rfc_CMD_IEEE_TX_t *g_vpCmdTx = &RF_cmdIeeeTx; static volatile rfc_CMD_IEEE_RX_t *g_vpCmdRx = &RF_cmdIeeeRx; @@ -420,7 +420,7 @@ set_channel(uint8_t channel) static int set_tx_power(const radio_value_t dbm) { - const RF_TxPowerTable_Value txPowerTableValue = RF_TxPowerTable_findValue(txPowerTable, (int8_t)dbm); + const RF_TxPowerTable_Value txPowerTableValue = RF_TxPowerTable_findValue(TX_POWER_TABLE, (int8_t)dbm); if (txPowerTableValue.rawValue == RF_TxPowerTable_INVALID_VALUE) { return CMD_RESULT_ERROR; } diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c index 6053d4631..26c2a3637 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c @@ -46,18 +46,18 @@ #include "dev/watchdog.h" /*---------------------------------------------------------------------------*/ /* RF Core Mailbox API */ -#include -#include -#include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_data_entry.h) +#include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_prop_mailbox.h) + #include /*---------------------------------------------------------------------------*/ /* RF settings */ -/* RF settings */ #ifdef PROP_MODE_CONF_RF_SETTINGS # define PROP_MODE_RF_SETTINGS PROP_MODE_CONF_RF_SETTINGS -# undef PROP_MODE_CONF_RF_SETTINGS #else # define PROP_MODE_RF_SETTINGS "prop-settings.h" #endif @@ -164,32 +164,20 @@ static rfc_propRxOutput_t rx_stats; /* How long to wait for the RF to enter RX in rf_cmd_ieee_rx */ #define ENTER_RX_WAIT_TIMEOUT (RTIMER_SECOND >> 10) /*---------------------------------------------------------------------------*/ -/* TX power table for the 431-527MHz band */ -#ifdef PROP_MODE_CONF_TX_POWER_431_527 -#define PROP_MODE_TX_POWER_431_527 PROP_MODE_CONF_TX_POWER_431_527 +/* Configuration for TX power table */ +#ifdef TX_POWER_CONF_TABLE +# define TX_POWER_TABLE TX_POWER_CONF_TABLE #else -#define PROP_MODE_TX_POWER_431_527 RF_propTxPower431_527 +# define TX_POWER_TABLE propTxPowerTable #endif /*---------------------------------------------------------------------------*/ -/* TX power table for the 779-930MHz band */ -#ifdef PROP_MODE_CONF_TX_POWER_779_930 -#define PROP_MODE_TX_POWER_779_930 PROP_MODE_CONF_TX_POWER_779_930 -#else -#define PROP_MODE_TX_POWER_779_930 RF_propTxPower779_930 -#endif -/*---------------------------------------------------------------------------*/ -/* Select power table based on the frequency band */ -#if DOT_15_4G_FREQUENCY_BAND_ID==DOT_15_4G_FREQUENCY_BAND_470 -#define TX_POWER_DRIVER PROP_MODE_TX_POWER_431_527 -#else -#define TX_POWER_DRIVER PROP_MODE_TX_POWER_779_930 -#endif +/* TX power table convenience macros */ +#define TX_POWER_TABLE_SIZE ((sizeof(TX_POWER_TABLE) / sizeof(TX_POWER_TABLE[0])) - 1) -/* Max and Min Output Power in dBm */ -#define OUTPUT_POWER_MAX (TX_POWER_DRIVER[0].dbm) +#define TX_POWER_MIN (TX_POWER_TABLE[0].power) +#define TX_POWER_MAX (TX_POWER_TABLE[TX_POWER_TABLE_SIZE - 1].power) -/* Default TX Power - position in output_power[] */ -static const RF_TxPower *tx_power_current = &TX_POWER_DRIVER[0]; +#define TX_POWER_IN_RANGE(dbm) (((dbm) >= TX_POWER_MIN) && ((dbm) <= TX_POWER_MAX)) /*---------------------------------------------------------------------------*/ #ifdef PROP_MODE_CONF_RX_BUF_CNT #define PROP_MODE_RX_BUF_CNT PROP_MODE_CONF_RX_BUF_CNT @@ -221,10 +209,10 @@ volatile static uint8_t *rx_read_entry; static uint8_t tx_buf[TX_BUF_HDR_LEN + TX_BUF_PAYLOAD_LEN] CC_ALIGN(4); /*---------------------------------------------------------------------------*/ -volatile static rfc_CMD_PROP_RADIO_DIV_SETUP_t *gvp_cmd_radio_div_setup = &rf_cmd_prop_radio_div_setup; -volatile static rfc_CMD_FS_t *gvp_cmd_fs = &rf_cmd_prop_fs; -volatile static rfc_CMD_PROP_TX_ADV_t *gvp_cmd_tx_adv = &rf_cmd_prop_tx_adv; -volatile static rfc_CMD_PROP_RX_ADV_t *gvp_cmd_rx_adv = &rf_cmd_prop_rx_adv; +volatile static rfc_CMD_PROP_RADIO_DIV_SETUP_t *gvp_cmd_radio_div_setup = &RF_cmdPropRadioDivSetup; +volatile static rfc_CMD_FS_t *gvp_cmd_fs = &RF_cmdPropFs; +volatile static rfc_CMD_PROP_TX_ADV_t *gvp_cmd_tx_adv = &RF_cmdPropTxAdv; +volatile static rfc_CMD_PROP_RX_ADV_t *gvp_cmd_rx_adv = &RF_cmdPropRxAdv; /*---------------------------------------------------------------------------*/ /* RF driver */ static RF_Object rfObject; @@ -378,60 +366,30 @@ set_channel(uint8_t channel) RF_postCmd(rfHandle, (RF_Op*)gvp_cmd_fs, RF_PriorityNormal, NULL, 0); } /*---------------------------------------------------------------------------*/ -static size_t -get_tx_power_array_last_element(void) -{ - const RF_TxPower *array = TX_POWER_DRIVER; - uint8_t count = 0; - - while(array->power != TX_POWER_UNKNOWN) { - count++; - array++; - } - return count - 1; -} -/*---------------------------------------------------------------------------*/ /* Returns the current TX power in dBm */ static radio_value_t get_tx_power(void) { - return tx_power_current->dbm; + const RF_TxPowerTable_Value value = RF_getTxPower(rfHandle); + return (radio_value_t)RF_TxPowerTable_findPowerLevel(TX_POWER_TABLE, value); } /*---------------------------------------------------------------------------*/ /* * The caller must make sure to send a new CMD_PROP_RADIO_DIV_SETUP to the * radio after calling this function. */ -static void +static radio_result_t set_tx_power(const radio_value_t power) { - if (power > OUTPUT_POWER_MAX) - { - tx_power_current = &TX_POWER_DRIVER[0]; + if (!TX_POWER_IN_RANGE(power)) { + return RADIO_RESULT_INVALID_VALUE; } - else - { - size_t i; - for (i = 0; TX_POWER_DRIVER[i + 1].power != TX_POWER_UNKNOWN; ++i) - { - if (power > TX_POWER_DRIVER[i + 1].dbm) - { - break; - } - } + const RF_TxPowerTable_Value value = RF_TxPowerTable_findValue(TX_POWER_TABLE, power); + RF_Stat stat = RF_setTxPower(rfHandle, value); - tx_power_current = &TX_POWER_DRIVER[i]; - } - - rfc_CMD_SET_TX_POWER_t cmd_set_tx_power; - memset(&cmd_set_tx_power, 0x00, sizeof(rfc_CMD_SET_TX_POWER_t)); - cmd_set_tx_power.commandNo = CMD_SET_TX_POWER; - cmd_set_tx_power.txPower = tx_power_current->power; - - RF_Stat stat = RF_runImmediateCmd(rfHandle, (uint32_t*)&cmd_set_tx_power); - if (stat != RF_StatCmdDoneSuccess) { - PRINTF("set_tx_power: stat=0x%02X\n", stat); - } + return (stat == RF_StatSuccess) + ? RADIO_RESULT_OK + : RADIO_RESULT_ERROR; } /*---------------------------------------------------------------------------*/ static void @@ -719,10 +677,10 @@ get_value(radio_param_t param, radio_value_t *value) *value = DOT_15_4G_CHANNEL_MAX; return RADIO_RESULT_OK; case RADIO_CONST_TXPOWER_MIN: - *value = TX_POWER_DRIVER[get_tx_power_array_last_element()].dbm; + *value = (radio_value_t)TX_POWER_MIN; return RADIO_RESULT_OK; case RADIO_CONST_TXPOWER_MAX: - *value = OUTPUT_POWER_MAX; + *value = (radio_value_t)TX_POWER_MAX; return RADIO_RESULT_OK; default: return RADIO_RESULT_NOT_SUPPORTED; @@ -758,12 +716,8 @@ set_value(radio_param_t param, radio_value_t value) set_channel((uint8_t)value); break; case RADIO_PARAM_TXPOWER: - if(value < TX_POWER_DRIVER[get_tx_power_array_last_element()].dbm || - value > OUTPUT_POWER_MAX) { - return RADIO_RESULT_INVALID_VALUE; - } - set_tx_power(value); - return RADIO_RESULT_OK; + return set_tx_power(value); + case RADIO_PARAM_RX_MODE: return RADIO_RESULT_OK; case RADIO_PARAM_CCA_THRESHOLD: diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c index 42a46ecbb..0cd20bb45 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c @@ -10,8 +10,10 @@ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) -#include DeviceFamily_constructPath(driverlib/rf_ieee_cmd.h) -#include DeviceFamily_constructPath(rf_patches/rf_patch_cpe_ieee.h) +// This must be included "locally" frm the cpu directory, +// as it isn't defined in CC13x0 driverlib +#include "driverlib/rf_ieee_cmd.h" +#include "rf_patches/rf_patch_cpe_ieee.h" #include @@ -19,7 +21,7 @@ // TI-RTOS RF Mode Object -RF_Mode ieeeMode = +RF_Mode RF_ieeeMode = { .rfMode = RF_MODE_IEEE_15_4, .cpePatchFxn = &rf_patch_cpe_ieee, @@ -33,7 +35,7 @@ RF_Mode ieeeMode = // RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) // See the Technical Reference Manual for further details about the "txPower" Command field. // The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. -RF_TxPowerTable_Entry txPowerTable[14] = +RF_TxPowerTable_Entry ieeeTxPowerTable[14] = { { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 6) }, { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 6) }, @@ -53,7 +55,7 @@ RF_TxPowerTable_Entry txPowerTable[14] = // Overrides for CMD_RADIO_SETUP -uint32_t pOverrides[] = +uint32_t pIeeeOverrides[] = { // override_synth_ieee_15_4.xml HW_REG_OVERRIDE(0x4038,0x0035), // Synth: Set recommended RTRIM to 5 @@ -113,18 +115,17 @@ rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup = .condition.rule = 0x1, .condition.nSkip = 0x0, .mode = 0x01, - .__dummy0 = 0x00, .config.frontEndMode = 0x0, .config.biasMode = 0x0, .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, .txPower = 0x9330, - .pRegOverride = pOverrides, + .pRegOverride = pIeeeOverrides, }; // CMD_FS // Frequency Synthesizer Programming Command -rfc_CMD_FS_t RF_cmdFs = +rfc_CMD_FS_t RF_cmdIeeeFs = { .commandNo = 0x0803, .status = 0x0000, diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h index 0b0bf81ec..5d00932ff 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h @@ -10,7 +10,9 @@ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) -#include DeviceFamily_constructPath(driverlib/rf_ieee_cmd.h) +// This must be included "locally" frm the cpu directory, +// as it isn't defined in CC13x0 driverlib +#include "driverlib/rf_ieee_cmd.h" #include @@ -20,18 +22,18 @@ extern RF_Mode RF_ieeeMode; // TX Power Table -extern RF_TxPowerTable_Entry txPowerTable[14]; +extern RF_TxPowerTable_Entry ieeeTxPowerTable[14]; // RF Core API commands extern rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup; -extern rfc_CMD_FS_t RF_cmdFs; +extern rfc_CMD_FS_t RF_cmdIeeeFs; extern rfc_CMD_IEEE_TX_t RF_cmdIeeeTx; extern rfc_CMD_IEEE_RX_t RF_cmdIeeeRx; // RF Core API Overrides -extern uint32_t pOverrides[]; +extern uint32_t pIeeeOverrides[]; #endif // _IEEE_SETTINGS_H_ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c index b65c2a9e2..1f86d67ec 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c @@ -54,7 +54,7 @@ RF_Mode RF_propMode = // RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) // See the Technical Reference Manual for further details about the "txPower" Command field. // The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. -RF_TxPowerTable_Entry txPowerTable[16] = +RF_TxPowerTable_Entry propTxPowerTable[16] = { { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY( 0, 3, 0, 2) }, { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY( 3, 3, 0, 9) }, @@ -77,7 +77,7 @@ RF_TxPowerTable_Entry txPowerTable[16] = // Overrides for CMD_PROP_RADIO_DIV_SETUP -uint32_t pOverrides[] = +uint32_t pPropOverrides[] = { // override_use_patch_prop_genfsk.xml MCE_RFE_OVERRIDE(0,4,0,1,0,0), // PHY: Use MCE ROM bank 4, RFE RAM patch @@ -107,7 +107,7 @@ uint32_t pOverrides[] = (uint32_t)0x00000943, // IEEE 802.15.4g: Fix incorrect initialization value for CRC-16 calculation (see TRM section 23.7.5.2.1) (uint32_t)0x00000963, // IEEE 802.15.4g: Fix incorrect initialization value for CRC-16 calculation (see TRM section 23.7.5.2.1) // override_phy_rx_rssi_offset_5db.xml - (uint32_t)0x00FB88A3, / da/ Rx: Set RSSI offset to adjust reported RSSI by +5 dB + (uint32_t)0x00FB88A3, // Rx: Set RSSI offset to adjust reported RSSI by +5 dB // TX power override ADI_REG_OVERRIDE(0,12,0xF8), // Tx: Set PA trim to max (in ADI0, set PACTL0=0xF8) (uint32_t)0xFFFFFFFF, @@ -145,7 +145,7 @@ rfc_CMD_PROP_RADIO_DIV_SETUP_t RF_cmdPropRadioDivSetup = .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, .txPower = 0xAB3F, - .pRegOverride = pOverrides, + .pRegOverride = pPropOverrides, .centerFreq = 0x0364, .intFreq = 0x8000, .loDivider = 0x05, @@ -153,7 +153,7 @@ rfc_CMD_PROP_RADIO_DIV_SETUP_t RF_cmdPropRadioDivSetup = // CMD_FS // Frequency Synthesizer Programming Command -rfc_CMD_FS_t RF_cmdFs = +rfc_CMD_FS_t RF_cmdPropFs = { .commandNo = 0x0803, .status = 0x0000, diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h index 6fe099252..85fedc8fd 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h @@ -19,15 +19,19 @@ extern RF_Mode RF_propMode; +// TX Power Table +extern RF_TxPowerTable_Entry propTxPowerTable[16]; + + // RF Core API commands extern rfc_CMD_PROP_RADIO_DIV_SETUP_t RF_cmdPropRadioDivSetup; -extern rfc_CMD_FS_t RF_cmdFs; +extern rfc_CMD_FS_t RF_cmdPropFs; extern rfc_CMD_PROP_TX_ADV_t RF_cmdPropTxAdv; extern rfc_CMD_PROP_RX_ADV_t RF_cmdPropRxAdv; // RF Core API Overrides -extern uint32_t pOverrides[]; +extern uint32_t pPropOverrides[]; #endif // _PROP_SETTINGS_H_ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c index 1226e598c..bedbbc792 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c @@ -47,7 +47,7 @@ RF_Mode RF_ieeeMode = // RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) // See the Technical Reference Manual for further details about the "txPower" Command field. // The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. -RF_TxPowerTable_Entry defaultPaTxPowerTable[16] = +RF_TxPowerTable_Entry ieeeDefaultPaTxPowerTable[16] = { { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 3) }, { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 3) }, @@ -73,7 +73,7 @@ RF_TxPowerTable_Entry defaultPaTxPowerTable[16] = // RF_TxPowerTable_HIGH_PA_ENTRY(bias, ibboost, boost, coefficient, ldoTrim) // See the Technical Reference Manual for further details about the "txPower" Command field. // The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. -RF_TxPowerTable_Entry highPaTxPowerTable[16] = +RF_TxPowerTable_Entry ieeeHighPaTxPowerTable[16] = { { 0, RF_TxPowerTable_HIGH_PA_ENTRY(29, 0, 1, 17, 1) }, { 3, RF_TxPowerTable_HIGH_PA_ENTRY(39, 0, 1, 20, 1) }, @@ -95,7 +95,7 @@ RF_TxPowerTable_Entry highPaTxPowerTable[16] = // Overrides for CMD_RADIO_SETUP -uint32_t pDefaultPaOverrides[] = +uint32_t pIeeeDefaultPaOverrides[] = { // override_ieee_802_15_4.xml MCE_RFE_OVERRIDE(1,0,0,0,1,0), // PHY: Use MCE RAM patch, RFE ROM bank 1 @@ -117,7 +117,7 @@ uint32_t pDefaultPaOverrides[] = // Overrides for CMD_RADIO_SETUP -uint32_t pHighPaOverrides[] = +uint32_t pIeeeHighPaOverrides[] = { // override_ieee_802_15_4.xml MCE_RFE_OVERRIDE(1,0,0,0,1,0), // PHY: Use MCE RAM patch, RFE ROM bank 1 @@ -162,7 +162,7 @@ rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup = .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, .txPower = 0x941E, - .pRegOverride = pOverrides, + .pRegOverride = pIeeeDefaultPaOverrides, }; // CMD_FS diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h index 90c75856b..ed9a7c7e0 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h @@ -20,8 +20,8 @@ extern RF_Mode RF_ieeeMode; // TX Power Table -extern RF_TxPowerTable_Entry defaultPaTxPowerTable[16]; -extern RF_TxPowerTable_Entry highPaTxPowerTable[16]; +extern RF_TxPowerTable_Entry ieeeDefaultPaTxPowerTable[16]; +extern RF_TxPowerTable_Entry ieeeHighPaTxPowerTable[16]; // RF Core API commands @@ -32,8 +32,8 @@ extern rfc_CMD_IEEE_RX_t RF_cmdIeeeRx; // RF Core API Overrides -extern uint32_t pDefaultPaOverrides[]; -extern uint32_t pHighPaOverrides[]; +extern uint32_t pIeeeDefaultPaOverrides[]; +extern uint32_t pIeeeHighPaOverrides[]; #endif // _IEEE_SETTINGS_H_ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c index f9088379d..e17b71954 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c @@ -52,7 +52,7 @@ RF_Mode RF_propMode = // RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) // See the Technical Reference Manual for further details about the "txPower" Command field. // The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. -RF_TxPowerTable_Entry defaultPaTxPowerTable[19] = +RF_TxPowerTable_Entry propDefaultPaTxPowerTable[19] = { { -20, RF_TxPowerTable_DEFAULT_PA_ENTRY( 0, 3, 0, 2) }, { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY( 1, 3, 0, 3) }, @@ -83,7 +83,7 @@ RF_TxPowerTable_Entry defaultPaTxPowerTable[19] = // RF_TxPowerTable_HIGH_PA_ENTRY(bias, ibboost, boost, coefficient, ldoTrim) // See the Technical Reference Manual for further details about the "txPower" Command field. // The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. -RF_TxPowerTable_Entry highPaTxPowerTable[8] = +RF_TxPowerTable_Entry propHighPaTxPowerTable[8] = { { 14, RF_TxPowerTable_HIGH_PA_ENTRY( 7, 0, 0, 23, 4) }, { 15, RF_TxPowerTable_HIGH_PA_ENTRY(10, 0, 0, 26, 4) }, @@ -97,7 +97,7 @@ RF_TxPowerTable_Entry highPaTxPowerTable[8] = // Overrides for CMD_PROP_RADIO_DIV_SETUP -uint32_t pDefaultPaOverrides[] = +uint32_t pPropDefaultPaOverrides[] = { // override_use_patch_prop_genfsk.xml MCE_RFE_OVERRIDE(1,0,0,1,0,0), // PHY: Use MCE RAM patch, RFE RAM patch @@ -135,7 +135,7 @@ uint32_t pDefaultPaOverrides[] = // Overrides for CMD_PROP_RADIO_DIV_SETUP -uint32_t pHighPaOverrides[] = +uint32_t pPropHighPaOverrides[] = { // override_use_patch_prop_genfsk.xml MCE_RFE_OVERRIDE(1,0,0,1,0,0), // PHY: Use MCE RAM patch, RFE RAM patch @@ -205,7 +205,7 @@ rfc_CMD_PROP_RADIO_DIV_SETUP_t RF_cmdPropRadioDivSetup = .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, .txPower = 0x013F, - .pRegOverride = pOverrides, + .pRegOverride = pPropDefaultPaOverrides, .centerFreq = 0x0393, .intFreq = 0x8000, .loDivider = 0x05, diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h index 0fbe14b28..87cbfa562 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h @@ -20,8 +20,8 @@ extern RF_Mode RF_propMode; // Tx Power Tables -extern RF_TxPowerTable_Entry defaultPaTxPowerTable[19]; -extern RF_TxPowerTable_Entry highPaTxPowerTable[8]; +extern RF_TxPowerTable_Entry propDefaultPaTxPowerTable[19]; +extern RF_TxPowerTable_Entry propHighPaTxPowerTable[8]; // RF Core API commands @@ -32,8 +32,8 @@ extern rfc_CMD_PROP_RX_ADV_t RF_cmdPropRxAdv; // RF Core API Overrides -extern uint32_t pDefaultPaOverrides[]; -extern uint32_t pHighPaOverrides[]; +extern uint32_t pPropDefaultPaOverrides[]; +extern uint32_t pPropHighPaOverrides[]; #endif // _PROP_SETTINGS_H_ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index b0f94173e..c7287da4b 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -32,9 +32,12 @@ CONTIKI_TARGET_DIRS += $(FAMILY) CONTIKI_TARGET_DIRS += $(addprefix $(FAMILY)/, $(TARGET_FAMILY_DIRS)) DEFINES += DeviceFamily_$(DEVICE_FAMILY) +DEFINES += DEVICE_LINE_$(DEVICE_LINE) DEFINES += $(BOARD_TYPE) +DEFINES += PLATFORM_HAS_BUTTON=$(PLATFORM_HAS_BUTTON) DEFINES += SUPPORTS_PROP_MODE=$(SUPPORTS_PROP_MODE) DEFINES += SUPPORTS_IEEE_MODE=$(SUPPORTS_IEEE_MODE) +DEFINES += SUPPORTS_HIGH_PA=$(SUPPORTS_HIGH_PA) ### If the user-specified a Node ID, pass a define ifdef NODEID diff --git a/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h b/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h index 46339a9b2..f577cfc3d 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h @@ -34,18 +34,15 @@ * \file * Configuration for the srf06-cc26xx platform */ -#ifndef CONTIKI_CONF_H -#define CONTIKI_CONF_H - -#include +/*---------------------------------------------------------------------------*/ +#ifndef CONTIKI_CONF_H_ +#define CONTIKI_CONF_H_ /*---------------------------------------------------------------------------*/ /* Include Project Specific conf */ #ifdef PROJECT_CONF_PATH #include PROJECT_CONF_PATH #endif /* PROJECT_CONF_PATH */ /*---------------------------------------------------------------------------*/ -#include "simplelink-def.h" -/*---------------------------------------------------------------------------*/ /** * \name Button configurations * @@ -56,9 +53,6 @@ #define BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN 1 #endif -/* Notify various examples that we have Buttons */ -#define PLATFORM_HAS_BUTTON 1 - /* * Override button symbols from dev/button-sensor.h, for the examples that * include it @@ -68,11 +62,11 @@ /** @} */ /*---------------------------------------------------------------------------*/ /* Platform-specific define to signify sensor reading failure */ +/* TODO: remove */ #define CC26XX_SENSOR_READING_ERROR 0x80000000 /*---------------------------------------------------------------------------*/ /* Include CPU-related configuration */ -#include "simplelink-conf.h" +#include "cc13xx-cc26xx-conf.h" /*---------------------------------------------------------------------------*/ -#endif /* CONTIKI_CONF_H */ - +#endif /* CONTIKI_CONF_H_ */ /** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/Makefile.launchpad b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/Makefile.launchpad index 2aedcefdc..d2d1bf777 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/Makefile.launchpad +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/Makefile.launchpad @@ -3,6 +3,8 @@ BOARD_TYPE = BOARD_LAUNCHPAD +PLATFORM_HAS_BUTTON = 1 + # leds-arch.c/h etc. BOARD_SOURCEFILES += launchpad.c launchpad-sensors.c BOARD_SOURCEFILES += button-sensor-arch.c leds-arch.c ext-flash.c diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Board.h index 4bf1f5d17..c73198659 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Board.h @@ -33,6 +33,8 @@ #ifndef __BOARD_H #define __BOARD_H +#define Board_CC1310_LAUNCHXL + #ifdef __cplusplus extern "C" { #endif diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.c index e073794c0..d2601e3f2 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.c @@ -463,10 +463,8 @@ const uint_least8_t I2C_count = CC1310_LAUNCHXL_I2CCOUNT; #define NVS_REGIONS_BASE 0x1A000 #define SECTORSIZE 0x1000 #define REGIONSIZE (SECTORSIZE * 4) -#define SPIREGIONSIZE (SECTORSIZE * 32) -#define VERIFYBUFSIZE 64 -static uint8_t verifyBuf[VERIFYBUFSIZE]; +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH /* * Reserve flash sectors for NVS driver use by placing an uninitialized byte @@ -505,11 +503,10 @@ static char flashBuf[REGIONSIZE]; #endif -/* Allocate objects for NVS and NVS SPI */ +/* Allocate objects for NVS Internal Regions */ NVSCC26XX_Object nvsCC26xxObjects[1]; -NVSSPI25X_Object nvsSPI25XObjects[1]; -/* Hardware attributes for NVS */ +/* Hardware attributes for NVS Internal Regions */ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { { .regionBase = (void *)flashBuf, @@ -517,12 +514,25 @@ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { }, }; -/* Hardware attributes for NVS SPI */ +#endif /* Board_EXCLUDE_NVS_INTERNAL_FLASH */ + +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH + +#define SPISECTORSIZE 0x1000 +#define SPIREGIONSIZE (SPISECTORSIZE * 32) +#define VERIFYBUFSIZE 64 + +static uint8_t verifyBuf[VERIFYBUFSIZE]; + +/* Allocate objects for NVS External Regions */ +NVSSPI25X_Object nvsSPI25XObjects[1]; + +/* Hardware attributes for NVS External Regions */ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { { .regionBaseOffset = 0, .regionSize = SPIREGIONSIZE, - .sectorSize = SECTORSIZE, + .sectorSize = SPISECTORSIZE, .verifyBuf = verifyBuf, .verifyBufSize = VERIFYBUFSIZE, .spiHandle = NULL, @@ -532,18 +542,24 @@ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { }, }; +#endif /* Board_EXCLUDE_NVS_EXTERNAL_FLASH */ + /* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ const NVS_Config NVS_config[CC1310_LAUNCHXL_NVSCOUNT] = { +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH { .fxnTablePtr = &NVSCC26XX_fxnTable, .object = &nvsCC26xxObjects[0], .hwAttrs = &nvsCC26xxHWAttrs[0], }, +#endif +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH { .fxnTablePtr = &NVSSPI25X_fxnTable, .object = &nvsSPI25XObjects[0], .hwAttrs = &nvsSPI25XHWAttrs[0], }, +#endif }; const uint_least8_t NVS_count = CC1310_LAUNCHXL_NVSCOUNT; @@ -810,89 +826,10 @@ const Watchdog_Config Watchdog_config[CC1310_LAUNCHXL_WATCHDOGCOUNT] = { const uint_least8_t Watchdog_count = CC1310_LAUNCHXL_WATCHDOGCOUNT; /* - * ======== CC1310_LAUNCHXL_wakeUpExtFlash ======== + * Board-specific initialization function to disable external flash. + * This function is defined in the file CC1310_LAUNCHXL_fxns.c */ -void CC1310_LAUNCHXL_wakeUpExtFlash(void) -{ - PIN_Config extFlashPinTable[] = { - CC1310_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - PIN_TERMINATE - }; - PIN_State extFlashPinState; - PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); - - /* - * To wake up we need to toggle the chip select at - * least 20 ns and ten wait at least 35 us. - */ - - /* Toggle chip select for ~20ns to wake ext. flash */ - PIN_setOutputValue(extFlashPinHandle, CC1310_LAUNCHXL_SPI_FLASH_CS, 0); - /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ - CPUdelay(1); - PIN_setOutputValue(extFlashPinHandle, CC1310_LAUNCHXL_SPI_FLASH_CS, 1); - /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ - CPUdelay(560); - - PIN_close(extFlashPinHandle); -} - -/* - * ======== CC1310_LAUNCHXL_sendExtFlashByte ======== - */ -void CC1310_LAUNCHXL_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) -{ - uint8_t i; - - PIN_setOutputValue(pinHandle, CC1310_LAUNCHXL_SPI_FLASH_CS, 0); - - for (i = 0; i < 8; i++) { - PIN_setOutputValue(pinHandle, CC1310_LAUNCHXL_SPI0_CLK, 0); - PIN_setOutputValue(pinHandle, CC1310_LAUNCHXL_SPI0_MOSI, (byte >> (7 - i)) & 0x01); - PIN_setOutputValue(pinHandle, CC1310_LAUNCHXL_SPI0_CLK, 1); - - /* - * Waste a few cycles to keep the CLK high for at - * least 45% of the period. - * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. - */ - CPUdelay(8); - } - - PIN_setOutputValue(pinHandle, CC1310_LAUNCHXL_SPI0_CLK, 0); - PIN_setOutputValue(pinHandle, CC1310_LAUNCHXL_SPI_FLASH_CS, 1); - - /* - * Keep CS high at least 40 us - * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us - */ - CPUdelay(700); -} - -/* - * ======== CC1310_LAUNCHXL_shutDownExtFlash ======== - */ -void CC1310_LAUNCHXL_shutDownExtFlash(void) -{ - /* To be sure we are putting the flash into sleep and not waking it, we first have to make a wake up call */ - CC1310_LAUNCHXL_wakeUpExtFlash(); - - PIN_Config extFlashPinTable[] = { - CC1310_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - CC1310_LAUNCHXL_SPI0_CLK | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - CC1310_LAUNCHXL_SPI0_MOSI | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - CC1310_LAUNCHXL_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, - PIN_TERMINATE - }; - PIN_State extFlashPinState; - PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); - - uint8_t extFlashShutdown = 0xB9; - - CC1310_LAUNCHXL_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); - - PIN_close(extFlashPinHandle); -} +extern void Board_initHook(void); /* * ======== CC1310_LAUNCHXL_initGeneral ======== @@ -906,6 +843,6 @@ void CC1310_LAUNCHXL_initGeneral(void) while (1); } - /* Shut down external flash as default */ - CC1310_LAUNCHXL_shutDownExtFlash(); + /* Perform board-specific initialization */ + Board_initHook(); } diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h index 28e3136ca..6eb2364ee 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h @@ -277,8 +277,12 @@ typedef enum CC1310_LAUNCHXL_I2CName { * @brief Enum of NVS names */ typedef enum CC1310_LAUNCHXL_NVSName { +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH CC1310_LAUNCHXL_NVSCC26XX0 = 0, +#endif +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH CC1310_LAUNCHXL_NVSSPI25X0, +#endif CC1310_LAUNCHXL_NVSCOUNT } CC1310_LAUNCHXL_NVSName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL_fxns.c new file mode 100644 index 000000000..9656aa821 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL_fxns.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +/* + * ======== CC1310_LAUNCHXL_fxns.c ======== + * This file contains the board-specific initialization functions. + */ + +#include +#include +#include + +#include +#include + +#include + +#include "Board.h" + + +/* + * ======== CC1310_LAUNCHXL_sendExtFlashByte ======== + */ +void CC1310_LAUNCHXL_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) +{ + uint8_t i; + + /* SPI Flash CS */ + PIN_setOutputValue(pinHandle, IOID_20, 0); + + for (i = 0; i < 8; i++) { + PIN_setOutputValue(pinHandle, IOID_10, 0); /* SPI Flash CLK */ + + /* SPI Flash MOSI */ + PIN_setOutputValue(pinHandle, IOID_9, (byte >> (7 - i)) & 0x01); + PIN_setOutputValue(pinHandle, IOID_10, 1); /* SPI Flash CLK */ + + /* + * Waste a few cycles to keep the CLK high for at + * least 45% of the period. + * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. + */ + CPUdelay(8); + } + + PIN_setOutputValue(pinHandle, IOID_10, 0); /* CLK */ + PIN_setOutputValue(pinHandle, IOID_20, 1); /* CS */ + + /* + * Keep CS high at least 40 us + * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us + */ + CPUdelay(700); +} + +/* + * ======== CC1310_LAUNCHXL_wakeUpExtFlash ======== + */ +void CC1310_LAUNCHXL_wakeUpExtFlash(void) +{ + PIN_Config extFlashPinTable[] = { + /* SPI Flash CS */ + IOID_20 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + /* + * To wake up we need to toggle the chip select at + * least 20 ns and ten wait at least 35 us. + */ + + /* Toggle chip select for ~20ns to wake ext. flash */ + PIN_setOutputValue(extFlashPinHandle, IOID_20, 0); + /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ + CPUdelay(1); + PIN_setOutputValue(extFlashPinHandle, IOID_20, 1); + /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ + CPUdelay(560); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC1310_LAUNCHXL_shutDownExtFlash ======== + */ +void CC1310_LAUNCHXL_shutDownExtFlash(void) +{ + /* + * To be sure we are putting the flash into sleep and not waking it, + * we first have to make a wake up call + */ + CC1310_LAUNCHXL_wakeUpExtFlash(); + + PIN_Config extFlashPinTable[] = { + /* SPI Flash CS*/ + IOID_20 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash CLK */ + IOID_10 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash MOSI */ + IOID_9 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash MISO */ + IOID_8 | PIN_INPUT_EN | PIN_PULLDOWN, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + uint8_t extFlashShutdown = 0xB9; + + CC1310_LAUNCHXL_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== Board_initHook ======== + * Called by Board_init() to perform board-specific initialization. + */ +void Board_initHook() +{ + CC1310_LAUNCHXL_shutDownExtFlash(); +} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Makefile.cc1310 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Makefile.cc1310 index 557be269d..c141e580d 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Makefile.cc1310 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Makefile.cc1310 @@ -3,8 +3,9 @@ SUBFAMILY = cc13x0-cc26x0 DEVICE_FAMILY = CC13X0 +DEVICE_LINE = CC13XX -BOARD_SOURCEFILES += CC1310_LAUNCHXL.c +BOARD_SOURCEFILES += CC1310_LAUNCHXL.c CC1310_LAUNCHXL_fxns.c SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Board.h index 091059d77..d5db0c364 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Board.h @@ -33,6 +33,8 @@ #ifndef __BOARD_H #define __BOARD_H +#define Board_CC1312R1_LAUNCHXL + #ifdef __cplusplus extern "C" { #endif diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.c index f36786ed7..9b0be9686 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.c @@ -584,11 +584,8 @@ const uint_least8_t I2C_count = CC1312R1_LAUNCHXL_I2CCOUNT; #define NVS_REGIONS_BASE 0x48000 #define SECTORSIZE 0x2000 #define REGIONSIZE (SECTORSIZE * 4) -#define SPISECTORSIZE 0x1000 -#define SPIREGIONSIZE (SPISECTORSIZE * 32) -#define VERIFYBUFSIZE 64 -static uint8_t verifyBuf[VERIFYBUFSIZE]; +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH /* * Reserve flash sectors for NVS driver use by placing an uninitialized byte @@ -627,11 +624,10 @@ static char flashBuf[REGIONSIZE]; #endif -/* Allocate objects for NVS and NVS SPI */ +/* Allocate objects for NVS Internal Regions */ NVSCC26XX_Object nvsCC26xxObjects[1]; -NVSSPI25X_Object nvsSPI25XObjects[1]; -/* Hardware attributes for NVS */ +/* Hardware attributes for NVS Internal Regions */ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { { .regionBase = (void *)flashBuf, @@ -639,7 +635,20 @@ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { }, }; -/* Hardware attributes for NVS SPI */ +#endif /* Board_EXCLUDE_NVS_INTERNAL_FLASH */ + +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH + +#define SPISECTORSIZE 0x1000 +#define SPIREGIONSIZE (SPISECTORSIZE * 32) +#define VERIFYBUFSIZE 64 + +static uint8_t verifyBuf[VERIFYBUFSIZE]; + +/* Allocate objects for NVS External Regions */ +NVSSPI25X_Object nvsSPI25XObjects[1]; + +/* Hardware attributes for NVS External Regions */ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { { .regionBaseOffset = 0, @@ -654,18 +663,24 @@ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { }, }; +#endif /* Board_EXCLUDE_NVS_EXTERNAL_FLASH */ + /* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ const NVS_Config NVS_config[CC1312R1_LAUNCHXL_NVSCOUNT] = { +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH { .fxnTablePtr = &NVSCC26XX_fxnTable, .object = &nvsCC26xxObjects[0], .hwAttrs = &nvsCC26xxHWAttrs[0], }, +#endif +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH { .fxnTablePtr = &NVSSPI25X_fxnTable, .object = &nvsSPI25XObjects[0], .hwAttrs = &nvsSPI25XHWAttrs[0], }, +#endif }; const uint_least8_t NVS_count = CC1312R1_LAUNCHXL_NVSCOUNT; @@ -932,89 +947,10 @@ const Watchdog_Config Watchdog_config[CC1312R1_LAUNCHXL_WATCHDOGCOUNT] = { const uint_least8_t Watchdog_count = CC1312R1_LAUNCHXL_WATCHDOGCOUNT; /* - * ======== CC1312R1_LAUNCHXL_wakeUpExtFlash ======== + * Board-specific initialization function to disable external flash. + * This function is defined in the file CC1312R1_LAUNCHXL_fxns.c */ -void CC1312R1_LAUNCHXL_wakeUpExtFlash(void) -{ - PIN_Config extFlashPinTable[] = { - CC1312R1_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - PIN_TERMINATE - }; - PIN_State extFlashPinState; - PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); - - /* - * To wake up we need to toggle the chip select at - * least 20 ns and ten wait at least 35 us. - */ - - /* Toggle chip select for ~20ns to wake ext. flash */ - PIN_setOutputValue(extFlashPinHandle, CC1312R1_LAUNCHXL_SPI_FLASH_CS, 0); - /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ - CPUdelay(1); - PIN_setOutputValue(extFlashPinHandle, CC1312R1_LAUNCHXL_SPI_FLASH_CS, 1); - /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ - CPUdelay(560); - - PIN_close(extFlashPinHandle); -} - -/* - * ======== CC1312R1_LAUNCHXL_sendExtFlashByte ======== - */ -void CC1312R1_LAUNCHXL_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) -{ - uint8_t i; - - PIN_setOutputValue(pinHandle, CC1312R1_LAUNCHXL_SPI_FLASH_CS, 0); - - for (i = 0; i < 8; i++) { - PIN_setOutputValue(pinHandle, CC1312R1_LAUNCHXL_SPI0_CLK, 0); - PIN_setOutputValue(pinHandle, CC1312R1_LAUNCHXL_SPI0_MOSI, (byte >> (7 - i)) & 0x01); - PIN_setOutputValue(pinHandle, CC1312R1_LAUNCHXL_SPI0_CLK, 1); - - /* - * Waste a few cycles to keep the CLK high for at - * least 45% of the period. - * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. - */ - CPUdelay(8); - } - - PIN_setOutputValue(pinHandle, CC1312R1_LAUNCHXL_SPI0_CLK, 0); - PIN_setOutputValue(pinHandle, CC1312R1_LAUNCHXL_SPI_FLASH_CS, 1); - - /* - * Keep CS high atleast 40 us - * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us - */ - CPUdelay(700); -} - -/* - * ======== CC1312R1_LAUNCHXL_shutDownExtFlash ======== - */ -void CC1312R1_LAUNCHXL_shutDownExtFlash(void) -{ - /* To be sure we are putting the flash into sleep and not waking it, we first have to make a wake up call */ - CC1312R1_LAUNCHXL_wakeUpExtFlash(); - - PIN_Config extFlashPinTable[] = { - CC1312R1_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - CC1312R1_LAUNCHXL_SPI0_CLK | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - CC1312R1_LAUNCHXL_SPI0_MOSI | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - CC1312R1_LAUNCHXL_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, - PIN_TERMINATE - }; - PIN_State extFlashPinState; - PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); - - uint8_t extFlashShutdown = 0xB9; - - CC1312R1_LAUNCHXL_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); - - PIN_close(extFlashPinHandle); -} +extern void Board_initHook(void); /* * ======== CC1312R1_LAUNCHXL_initGeneral ======== @@ -1028,6 +964,6 @@ void CC1312R1_LAUNCHXL_initGeneral(void) while (1); } - /* Shut down external flash as default */ - CC1312R1_LAUNCHXL_shutDownExtFlash(); + /* Perform board-specific initialization */ + Board_initHook(); } diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h index e1cefe24e..fd2043ce7 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h @@ -336,8 +336,12 @@ typedef enum CC1312R1_LAUNCHXL_I2CName { * @brief Enum of NVS names */ typedef enum CC1312R1_LAUNCHXL_NVSName { +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH CC1312R1_LAUNCHXL_NVSCC26XX0 = 0, +#endif +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH CC1312R1_LAUNCHXL_NVSSPI25X0, +#endif CC1312R1_LAUNCHXL_NVSCOUNT } CC1312R1_LAUNCHXL_NVSName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL_fxns.c new file mode 100644 index 000000000..77a830b4d --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL_fxns.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +/* + * ======== CC1312R1_LAUNCHXL_fxns.c ======== + * This file contains the board-specific initialization functions. + */ + +#include +#include +#include + +#include +#include +#include + +#include "Board.h" + +/* + * ======== CC1312R1_LAUNCHXL_sendExtFlashByte ======== + */ +void CC1312R1_LAUNCHXL_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) +{ + uint8_t i; + + /* SPI Flash CS */ + PIN_setOutputValue(pinHandle, IOID_20, 0); + + for (i = 0; i < 8; i++) { + PIN_setOutputValue(pinHandle, IOID_10, 0); /* SPI Flash CLK */ + + /* SPI Flash MOSI */ + PIN_setOutputValue(pinHandle, IOID_9, (byte >> (7 - i)) & 0x01); + PIN_setOutputValue(pinHandle, IOID_10, 1); /* SPI Flash CLK */ + + /* + * Waste a few cycles to keep the CLK high for at + * least 45% of the period. + * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. + */ + CPUdelay(8); + } + + PIN_setOutputValue(pinHandle, IOID_10, 0); /* CLK */ + PIN_setOutputValue(pinHandle, IOID_20, 1); /* CS */ + + /* + * Keep CS high at least 40 us + * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us + */ + CPUdelay(700); +} + +/* + * ======== CC1312R1_LAUNCHXL_wakeUpExtFlash ======== + */ +void CC1312R1_LAUNCHXL_wakeUpExtFlash(void) +{ + PIN_Config extFlashPinTable[] = { + /* SPI Flash CS */ + IOID_20 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + /* + * To wake up we need to toggle the chip select at + * least 20 ns and ten wait at least 35 us. + */ + + /* Toggle chip select for ~20ns to wake ext. flash */ + PIN_setOutputValue(extFlashPinHandle, IOID_20, 0); + /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ + CPUdelay(1); + PIN_setOutputValue(extFlashPinHandle, IOID_20, 1); + /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ + CPUdelay(560); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC1312R1_LAUNCHXL_shutDownExtFlash ======== + */ +void CC1312R1_LAUNCHXL_shutDownExtFlash(void) +{ + /* + * To be sure we are putting the flash into sleep and not waking it, + * we first have to make a wake up call + */ + CC1312R1_LAUNCHXL_wakeUpExtFlash(); + + PIN_Config extFlashPinTable[] = { + /* SPI Flash CS*/ + IOID_20 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash CLK */ + IOID_10 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash MOSI */ + IOID_9 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash MISO */ + IOID_8 | PIN_INPUT_EN | PIN_PULLDOWN, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + uint8_t extFlashShutdown = 0xB9; + + CC1312R1_LAUNCHXL_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== Board_initHook ======== + * Called by Board_init() to perform board-specific initialization. + */ +void Board_initHook() +{ + CC1312R1_LAUNCHXL_shutDownExtFlash(); +} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 index f4a502c13..6feb804df 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 @@ -3,8 +3,9 @@ SUBFAMILY = cc13x2-cc26x2 DEVICE_FAMILY = CC13X2 +DEVICE_LINE = CC13XX -BOARD_SOURCEFILES += CC1312R1_LAUNCHXL.c +BOARD_SOURCEFILES += CC1312R1_LAUNCHXL.c CC1312R1_LAUNCHXL_fxns.c SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Board.h index d1e4119a9..394f3a3cd 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Board.h @@ -33,6 +33,8 @@ #ifndef __BOARD_H #define __BOARD_H +#define Board_CC1350_LAUNCHXL_433 + #ifdef __cplusplus extern "C" { #endif @@ -73,6 +75,13 @@ extern "C" { #define Board_DIO29_ANALOG CC1350_LAUNCHXL_433_DIO29_ANALOG #define Board_DIO30_ANALOG CC1350_LAUNCHXL_433_DIO30_ANALOG +/* + * Board_RF_SUB1GHZ and Board_RF_POWER are the names generated by SysConfig. + * Define them here so that RF callback function can reference them. + */ +#define Board_RF_SUB1GHZ CC1350_LAUNCHXL_433_DIO1_RF_SUB1GHZ +#define Board_RF_POWER CC1350_LAUNCHXL_433_DIO30_RF_POWER + #define Board_GPIO_BUTTON0 CC1350_LAUNCHXL_433_GPIO_S1 #define Board_GPIO_BUTTON1 CC1350_LAUNCHXL_433_GPIO_S2 #define Board_GPIO_BTN1 CC1350_LAUNCHXL_433_GPIO_S1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.c index d6b8f33cd..9679f7599 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.c @@ -462,10 +462,8 @@ const uint_least8_t I2C_count = CC1350_LAUNCHXL_433_I2CCOUNT; #define NVS_REGIONS_BASE 0x1A000 #define SECTORSIZE 0x1000 #define REGIONSIZE (SECTORSIZE * 4) -#define SPIREGIONSIZE (SECTORSIZE * 32) -#define VERIFYBUFSIZE 64 -static uint8_t verifyBuf[VERIFYBUFSIZE]; +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH /* * Reserve flash sectors for NVS driver use by placing an uninitialized byte @@ -504,11 +502,10 @@ static char flashBuf[REGIONSIZE]; #endif -/* Allocate objects for NVS and NVS SPI */ +/* Allocate objects for NVS Internal Regions */ NVSCC26XX_Object nvsCC26xxObjects[1]; -NVSSPI25X_Object nvsSPI25XObjects[1]; -/* Hardware attributes for NVS */ +/* Hardware attributes for NVS Internal Regions */ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { { .regionBase = (void *)flashBuf, @@ -516,12 +513,25 @@ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { }, }; -/* Hardware attributes for NVS SPI */ +#endif /* Board_EXCLUDE_NVS_INTERNAL_FLASH */ + +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH + +#define SPISECTORSIZE 0x1000 +#define SPIREGIONSIZE (SPISECTORSIZE * 32) +#define VERIFYBUFSIZE 64 + +static uint8_t verifyBuf[VERIFYBUFSIZE]; + +/* Allocate objects for NVS External Regions */ +NVSSPI25X_Object nvsSPI25XObjects[1]; + +/* Hardware attributes for NVS External Regions */ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { { .regionBaseOffset = 0, .regionSize = SPIREGIONSIZE, - .sectorSize = SECTORSIZE, + .sectorSize = SPISECTORSIZE, .verifyBuf = verifyBuf, .verifyBufSize = VERIFYBUFSIZE, .spiHandle = NULL, @@ -531,18 +541,24 @@ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { }, }; +#endif /* Board_EXCLUDE_NVS_EXTERNAL_FLASH */ + /* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ const NVS_Config NVS_config[CC1350_LAUNCHXL_433_NVSCOUNT] = { +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH { .fxnTablePtr = &NVSCC26XX_fxnTable, .object = &nvsCC26xxObjects[0], .hwAttrs = &nvsCC26xxHWAttrs[0], }, +#endif +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH { .fxnTablePtr = &NVSSPI25X_fxnTable, .object = &nvsSPI25XObjects[0], .hwAttrs = &nvsSPI25XHWAttrs[0], }, +#endif }; const uint_least8_t NVS_count = CC1350_LAUNCHXL_433_NVSCOUNT; @@ -629,19 +645,23 @@ const uint_least8_t PWM_count = CC1350_LAUNCHXL_433_PWMCOUNT; #include /* - * Board-specific callback function to set the correct antenna path. + * Board-specific callback function to set the correct antenna path. * - * This function is called by the RF driver on global driver events. It contains - * a default implementation to set the correct antenna path. + * This function is called by the RF driver on global driver events. + * It contains a default implementation to set the correct antenna path. + * This function is defined in the file CC1350_LAUNCHXL_433_fxns.c */ -static void CC1350_LAUNCHXL_433_rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void *arg); +extern void rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void *arg); const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { - .hwiPriority = ~0, /* Lowest HWI priority */ - .swiPriority = 0, /* Lowest SWI priority */ - .xoscHfAlwaysNeeded = true, /* Keep XOSC dependency while in stanby */ - .globalCallback = &CC1350_LAUNCHXL_433_rfDriverCallback, /* Register the board specific callback */ - .globalEventMask = RF_GlobalEventRadioSetup | RF_GlobalEventRadioPowerDown /* Subscribe the callback to both events */ + .hwiPriority = ~0, /* Lowest HWI priority */ + .swiPriority = 0, /* Lowest SWI priority */ + .xoscHfAlwaysNeeded = true, /* Keep XOSC dependency while in stanby */ + + /* Register the board specific callback */ + .globalCallback = &rfDriverCallback, + /* Subscribe the callback to both events */ + .globalEventMask = RF_GlobalEventRadioSetup | RF_GlobalEventRadioPowerDown }; /* @@ -818,89 +838,10 @@ const Watchdog_Config Watchdog_config[CC1350_LAUNCHXL_433_WATCHDOGCOUNT] = { const uint_least8_t Watchdog_count = CC1350_LAUNCHXL_433_WATCHDOGCOUNT; /* - * ======== CC1350_LAUNCHXL_433_wakeUpExtFlash ======== + * Board-specific initialization function to disable external flash. + * This function is defined in the file CC1350_LAUNCHXL_433_fxns.c */ -void CC1350_LAUNCHXL_433_wakeUpExtFlash(void) -{ - PIN_Config extFlashPinTable[] = { - CC1350_LAUNCHXL_433_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - PIN_TERMINATE - }; - PIN_State extFlashPinState; - PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); - - /* - * To wake up we need to toggle the chip select at - * least 20 ns and ten wait at least 35 us. - */ - - /* Toggle chip select for ~20ns to wake ext. flash */ - PIN_setOutputValue(extFlashPinHandle, CC1350_LAUNCHXL_433_SPI_FLASH_CS, 0); - /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ - CPUdelay(1); - PIN_setOutputValue(extFlashPinHandle, CC1350_LAUNCHXL_433_SPI_FLASH_CS, 1); - /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ - CPUdelay(560); - - PIN_close(extFlashPinHandle); -} - -/* - * ======== CC1350_LAUNCHXL_433_sendExtFlashByte ======== - */ -void CC1350_LAUNCHXL_433_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) -{ - uint8_t i; - - PIN_setOutputValue(pinHandle, CC1350_LAUNCHXL_433_SPI_FLASH_CS, 0); - - for (i = 0; i < 8; i++) { - PIN_setOutputValue(pinHandle, CC1350_LAUNCHXL_433_SPI0_CLK, 0); - PIN_setOutputValue(pinHandle, CC1350_LAUNCHXL_433_SPI0_MOSI, (byte >> (7 - i)) & 0x01); - PIN_setOutputValue(pinHandle, CC1350_LAUNCHXL_433_SPI0_CLK, 1); - - /* - * Waste a few cycles to keep the CLK high for at - * least 45% of the period. - * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. - */ - CPUdelay(8); - } - - PIN_setOutputValue(pinHandle, CC1350_LAUNCHXL_433_SPI0_CLK, 0); - PIN_setOutputValue(pinHandle, CC1350_LAUNCHXL_433_SPI_FLASH_CS, 1); - - /* - * Keep CS high at least 40 us - * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us - */ - CPUdelay(700); -} - -/* - * ======== CC1350_LAUNCHXL_433_shutDownExtFlash ======== - */ -void CC1350_LAUNCHXL_433_shutDownExtFlash(void) -{ - /* To be sure we are putting the flash into sleep and not waking it, we first have to make a wake up call */ - CC1350_LAUNCHXL_433_wakeUpExtFlash(); - - PIN_Config extFlashPinTable[] = { - CC1350_LAUNCHXL_433_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - CC1350_LAUNCHXL_433_SPI0_CLK | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - CC1350_LAUNCHXL_433_SPI0_MOSI | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - CC1350_LAUNCHXL_433_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, - PIN_TERMINATE - }; - PIN_State extFlashPinState; - PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); - - uint8_t extFlashShutdown = 0xB9; - - CC1350_LAUNCHXL_433_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); - - PIN_close(extFlashPinHandle); -} +extern void Board_initHook(void); /* * ======== CC1350_LAUNCHXL_433_initGeneral ======== @@ -909,37 +850,11 @@ void CC1350_LAUNCHXL_433_initGeneral(void) { Power_init(); - if ( PIN_init(BoardGpioInitTable) != PIN_SUCCESS) { + if (PIN_init(BoardGpioInitTable) != PIN_SUCCESS) { /* Error with PIN_init */ while (1); } - /* Shut down external flash as default */ - CC1350_LAUNCHXL_433_shutDownExtFlash(); -} - -/* - * ======== CC1350_LAUNCHXL_433_rfDriverCallback ======== - * This is an implementation for the CC1350 launchpad which uses a - * single signal for antenna switching. - */ -void CC1350_LAUNCHXL_433_rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void *arg) -{ - (void)client; - RF_RadioSetup* setupCommand = (RF_RadioSetup*)arg; - - if (events & RF_GlobalEventRadioSetup) { - /* Power up the antenna switch */ - PINCC26XX_setOutputValue(CC1350_LAUNCHXL_433_DIO30_RF_POWER, 1); - - if (setupCommand->common.commandNo == CMD_PROP_RADIO_DIV_SETUP) { - /* Sub-1 GHz, requires antenna switch high */ - PINCC26XX_setOutputValue(CC1350_LAUNCHXL_433_DIO1_RF_SUB1GHZ, 1); - } - - } else if (events & RF_GlobalEventRadioPowerDown) { - /* Disable antenna switch to save current */ - PINCC26XX_setOutputValue(CC1350_LAUNCHXL_433_DIO30_RF_POWER, 0); - PINCC26XX_setOutputValue(CC1350_LAUNCHXL_433_DIO1_RF_SUB1GHZ, 0); - } + /* Perform board-specific initialization */ + Board_initHook(); } diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h index eb68e92b6..fa3a63316 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h @@ -280,8 +280,12 @@ typedef enum CC1350_LAUNCHXL_433_I2CName { * @brief Enum of NVS names */ typedef enum CC1350_LAUNCHXL_433_NVSName { +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH CC1350_LAUNCHXL_433_NVSCC26XX0 = 0, +#endif +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH CC1350_LAUNCHXL_433_NVSSPI25X0, +#endif CC1350_LAUNCHXL_433_NVSCOUNT } CC1350_LAUNCHXL_433_NVSName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433_fxns.c new file mode 100644 index 000000000..2d2a27784 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433_fxns.c @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ +/* + * ======== CC1350_LAUNCHXL_433_fxns.c ======== + * This file contains the board-specific initialization functions, and + * RF callback function for antenna switching. + */ +#include +#include +#include + +#include +#include + +#include +#include + +#include "Board.h" + + +/* + * ======== CC1350_LAUNCHXL_433_sendExtFlashByte ======== + */ +void CC1350_LAUNCHXL_433_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) +{ + uint8_t i; + + /* SPI Flash CS */ + PIN_setOutputValue(pinHandle, IOID_20, 0); + + for (i = 0; i < 8; i++) { + PIN_setOutputValue(pinHandle, IOID_10, 0); /* SPI Flash CLK */ + + /* SPI Flash MOSI */ + PIN_setOutputValue(pinHandle, IOID_9, (byte >> (7 - i)) & 0x01); + PIN_setOutputValue(pinHandle, IOID_10, 1); /* SPI Flash CLK */ + + /* + * Waste a few cycles to keep the CLK high for at + * least 45% of the period. + * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. + */ + CPUdelay(8); + } + + PIN_setOutputValue(pinHandle, IOID_10, 0); /* CLK */ + PIN_setOutputValue(pinHandle, IOID_20, 1); /* CS */ + + /* + * Keep CS high at least 40 us + * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us + */ + CPUdelay(700); +} + +/* + * ======== CC1350_LAUNCHXL_433_wakeUpExtFlash ======== + */ +void CC1350_LAUNCHXL_433_wakeUpExtFlash(void) +{ + PIN_Config extFlashPinTable[] = { + /* SPI Flash CS */ + IOID_20 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + /* + * To wake up we need to toggle the chip select at + * least 20 ns and ten wait at least 35 us. + */ + + /* Toggle chip select for ~20ns to wake ext. flash */ + PIN_setOutputValue(extFlashPinHandle, IOID_20, 0); + /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ + CPUdelay(1); + PIN_setOutputValue(extFlashPinHandle, IOID_20, 1); + /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ + CPUdelay(560); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC1350_LAUNCHXL_433_shutDownExtFlash ======== + */ +void CC1350_LAUNCHXL_433_shutDownExtFlash(void) +{ + /* + * To be sure we are putting the flash into sleep and not waking it, + * we first have to make a wake up call + */ + CC1350_LAUNCHXL_433_wakeUpExtFlash(); + + PIN_Config extFlashPinTable[] = { + /* SPI Flash CS*/ + IOID_20 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash CLK */ + IOID_10 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash MOSI */ + IOID_9 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash MISO */ + IOID_8 | PIN_INPUT_EN | PIN_PULLDOWN, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + uint8_t extFlashShutdown = 0xB9; + + CC1350_LAUNCHXL_433_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== Board_initHook ======== + * Called by Board_init() to perform board-specific initialization. + */ +void Board_initHook() +{ + CC1350_LAUNCHXL_433_shutDownExtFlash(); +} + +/* + * For the SysConfig generated Board.h file, Board_RF_SUB1GHZ will not be + * defined unless the RF module is added to the configuration. Therefore, + * we don't include this code if Board_RF_SUB1GHZ is not defined. + */ +#if defined(Board_RF_SUB1GHZ) + +/* + * ======== CC1350_LAUNCHXL_433_rfDriverCallback ======== + * This is an implementation for the CC1350 launchpad which uses a + * single signal for antenna switching. + */ +void rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void *arg) +{ + (void)client; + RF_RadioSetup* setupCommand = (RF_RadioSetup*)arg; + + if (events & RF_GlobalEventRadioSetup) { + /* Power up the antenna switch */ + PINCC26XX_setOutputValue(Board_RF_POWER, 1); + + if (setupCommand->common.commandNo == CMD_PROP_RADIO_DIV_SETUP) { + /* Sub-1 GHz, requires antenna switch high */ + PINCC26XX_setOutputValue(Board_RF_SUB1GHZ, 1); + } + } + else if (events & RF_GlobalEventRadioPowerDown) { + /* Disable antenna switch to save current */ + PINCC26XX_setOutputValue(Board_RF_POWER, 0); + PINCC26XX_setOutputValue(Board_RF_SUB1GHZ, 0); + } +} +#endif diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Makefile.cc1350-4 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Makefile.cc1350-4 index cef7ebb0d..659621677 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Makefile.cc1350-4 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Makefile.cc1350-4 @@ -3,8 +3,9 @@ SUBFAMILY = cc13x0-cc26x0 DEVICE_FAMILY = CC13X0 +DEVICE_LINE = CC13XX -BOARD_SOURCEFILES += CC1350_LAUNCHXL_433.c +BOARD_SOURCEFILES += CC1350_LAUNCHXL_433.c CC1310_LAUNCHXL_433_fxns.c SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Board.h index a3dd8068f..a67b34ddb 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Board.h @@ -33,6 +33,8 @@ #ifndef __BOARD_H #define __BOARD_H +#define Board_CC1350_LAUNCHXL + #ifdef __cplusplus extern "C" { #endif @@ -72,6 +74,13 @@ extern "C" { #define Board_DIO29_ANALOG CC1350_LAUNCHXL_DIO29_ANALOG #define Board_DIO30_ANALOG CC1350_LAUNCHXL_DIO30_ANALOG +/* + * Board_RF_SUB1GHZ and Board_RF_POWER are the names generated by SysConfig. + * Define them here so that RF callback function can reference them. + */ +#define Board_RF_SUB1GHZ CC1350_LAUNCHXL_DIO1_RF_SUB1GHZ +#define Board_RF_POWER CC1350_LAUNCHXL_DIO30_RF_POWER + #define Board_GPIO_BUTTON0 CC1350_LAUNCHXL_GPIO_S1 #define Board_GPIO_BUTTON1 CC1350_LAUNCHXL_GPIO_S2 #define Board_GPIO_BTN1 CC1350_LAUNCHXL_GPIO_S1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c index 0ead97912..92ce04a9d 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c @@ -462,10 +462,8 @@ const uint_least8_t I2C_count = CC1350_LAUNCHXL_I2CCOUNT; #define NVS_REGIONS_BASE 0x1A000 #define SECTORSIZE 0x1000 #define REGIONSIZE (SECTORSIZE * 4) -#define SPIREGIONSIZE (SECTORSIZE * 32) -#define VERIFYBUFSIZE 64 -static uint8_t verifyBuf[VERIFYBUFSIZE]; +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH /* * Reserve flash sectors for NVS driver use by placing an uninitialized byte @@ -504,11 +502,10 @@ static char flashBuf[REGIONSIZE]; #endif -/* Allocate objects for NVS and NVS SPI */ +/* Allocate objects for NVS Internal Regions */ NVSCC26XX_Object nvsCC26xxObjects[1]; -NVSSPI25X_Object nvsSPI25XObjects[1]; -/* Hardware attributes for NVS */ +/* Hardware attributes for NVS Internal Regions */ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { { .regionBase = (void *)flashBuf, @@ -516,12 +513,25 @@ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { }, }; -/* Hardware attributes for NVS SPI */ +#endif /* Board_EXCLUDE_NVS_INTERNAL_FLASH */ + +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH + +#define SPISECTORSIZE 0x1000 +#define SPIREGIONSIZE (SPISECTORSIZE * 32) +#define VERIFYBUFSIZE 64 + +static uint8_t verifyBuf[VERIFYBUFSIZE]; + +/* Allocate objects for NVS External Regions */ +NVSSPI25X_Object nvsSPI25XObjects[1]; + +/* Hardware attributes for NVS External Regions */ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { { .regionBaseOffset = 0, .regionSize = SPIREGIONSIZE, - .sectorSize = SECTORSIZE, + .sectorSize = SPISECTORSIZE, .verifyBuf = verifyBuf, .verifyBufSize = VERIFYBUFSIZE, .spiHandle = NULL, @@ -531,18 +541,24 @@ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { }, }; +#endif /* Board_EXCLUDE_NVS_EXTERNAL_FLASH */ + /* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ const NVS_Config NVS_config[CC1350_LAUNCHXL_NVSCOUNT] = { +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH { .fxnTablePtr = &NVSCC26XX_fxnTable, .object = &nvsCC26xxObjects[0], .hwAttrs = &nvsCC26xxHWAttrs[0], }, +#endif +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH { .fxnTablePtr = &NVSSPI25X_fxnTable, .object = &nvsSPI25XObjects[0], .hwAttrs = &nvsSPI25XHWAttrs[0], }, +#endif }; const uint_least8_t NVS_count = CC1350_LAUNCHXL_NVSCOUNT; @@ -629,19 +645,23 @@ const uint_least8_t PWM_count = CC1350_LAUNCHXL_PWMCOUNT; #include /* - * Board-specific callback function to set the correct antenna path. + * Board-specific callback function to set the correct antenna path. * - * This function is called by the RF driver on global driver events. It contains - * a default implementation to set the correct antenna path. + * This function is called by the RF driver on global driver events. + * It contains a default implementation to set the correct antenna path. + * This function is defined in the file CC1350_LAUNCHXL_fxns.c */ -static void CC1350_LAUNCHXL_rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void *arg); +extern void rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void *arg); const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { - .hwiPriority = ~0, /* Lowest HWI priority */ - .swiPriority = 0, /* Lowest SWI priority */ - .xoscHfAlwaysNeeded = true, /* Keep XOSC dependency while in stanby */ - .globalCallback = &CC1350_LAUNCHXL_rfDriverCallback, /* Register the board specific callback */ - .globalEventMask = RF_GlobalEventRadioSetup | RF_GlobalEventRadioPowerDown /* Subscribe the callback to both events */ + .hwiPriority = ~0, /* Lowest HWI priority */ + .swiPriority = 0, /* Lowest SWI priority */ + .xoscHfAlwaysNeeded = true, /* Keep XOSC dependency while in stanby */ + + /* Register the board specific callback */ + .globalCallback = &rfDriverCallback, + /* Subscribe the callback to both events */ + .globalEventMask = RF_GlobalEventRadioSetup | RF_GlobalEventRadioPowerDown }; /* @@ -818,90 +838,10 @@ const Watchdog_Config Watchdog_config[CC1350_LAUNCHXL_WATCHDOGCOUNT] = { const uint_least8_t Watchdog_count = CC1350_LAUNCHXL_WATCHDOGCOUNT; /* - * ======== CC1350_LAUNCHXL_wakeUpExtFlash ======== + * Board-specific initialization function to disable external flash. + * This function is defined in the file CC1350_LAUNCHXL_fxns.c */ -void CC1350_LAUNCHXL_wakeUpExtFlash(void) -{ - PIN_Config extFlashPinTable[] = { - CC1350_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - PIN_TERMINATE - }; - PIN_State extFlashPinState; - PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); - - /* - * To wake up we need to toggle the chip select at - * least 20 ns and ten wait at least 35 us. - */ - - /* Toggle chip select for ~20ns to wake ext. flash */ - PIN_setOutputValue(extFlashPinHandle, CC1350_LAUNCHXL_SPI_FLASH_CS, 0); - /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ - CPUdelay(1); - PIN_setOutputValue(extFlashPinHandle, CC1350_LAUNCHXL_SPI_FLASH_CS, 1); - /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ - CPUdelay(560); - - PIN_close(extFlashPinHandle); -} - -/* - * ======== CC1350_LAUNCHXL_sendExtFlashByte ======== - */ -void CC1350_LAUNCHXL_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) -{ - uint8_t i; - - PIN_setOutputValue(pinHandle, CC1350_LAUNCHXL_SPI_FLASH_CS, 0); - - for (i = 0; i < 8; i++) { - PIN_setOutputValue(pinHandle, CC1350_LAUNCHXL_SPI0_CLK, 0); - PIN_setOutputValue(pinHandle, CC1350_LAUNCHXL_SPI0_MOSI, (byte >> (7 - i)) & 0x01); - PIN_setOutputValue(pinHandle, CC1350_LAUNCHXL_SPI0_CLK, 1); - - /* - * Waste a few cycles to keep the CLK high for at - * least 45% of the period. - * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. - */ - CPUdelay(8); - } - - PIN_setOutputValue(pinHandle, CC1350_LAUNCHXL_SPI0_CLK, 0); - PIN_setOutputValue(pinHandle, CC1350_LAUNCHXL_SPI_FLASH_CS, 1); - - /* - * Keep CS high at least 40 us - * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us - */ - CPUdelay(700); -} - -/* - * ======== CC1350_LAUNCHXL_shutDownExtFlash ======== - */ -void CC1350_LAUNCHXL_shutDownExtFlash(void) -{ - /* To be sure we are putting the flash into sleep and not waking it, we first have to make a wake up call */ - CC1350_LAUNCHXL_wakeUpExtFlash(); - - - PIN_Config extFlashPinTable[] = { - CC1350_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - CC1350_LAUNCHXL_SPI0_CLK | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - CC1350_LAUNCHXL_SPI0_MOSI | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - CC1350_LAUNCHXL_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, - PIN_TERMINATE - }; - PIN_State extFlashPinState; - PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); - - uint8_t extFlashShutdown = 0xB9; - - CC1350_LAUNCHXL_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); - - PIN_close(extFlashPinHandle); -} +extern void Board_initHook(void); /* * ======== CC1350_LAUNCHXL_initGeneral ======== @@ -915,32 +855,6 @@ void CC1350_LAUNCHXL_initGeneral(void) while (1); } - /* Shut down external flash as default */ - CC1350_LAUNCHXL_shutDownExtFlash(); -} - -/* - * ======== CC1350_LAUNCHXL_rfDriverCallback ======== - * This is an implementation for the CC1350 launchpad which uses a - * single signal for antenna switching. - */ -void CC1350_LAUNCHXL_rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void *arg) -{ - (void)client; - RF_RadioSetup* setupCommand = (RF_RadioSetup*)arg; - - if (events & RF_GlobalEventRadioSetup) { - /* Power up the antenna switch */ - PINCC26XX_setOutputValue(CC1350_LAUNCHXL_DIO30_RF_POWER, 1); - - if (setupCommand->common.commandNo == CMD_PROP_RADIO_DIV_SETUP) { - /* Sub-1 GHz, requires antenna switch high */ - PINCC26XX_setOutputValue(CC1350_LAUNCHXL_DIO1_RF_SUB1GHZ, 1); - } - - } else if (events & RF_GlobalEventRadioPowerDown) { - /* Disable antenna switch to save current */ - PINCC26XX_setOutputValue(CC1350_LAUNCHXL_DIO30_RF_POWER, 0); - PINCC26XX_setOutputValue(CC1350_LAUNCHXL_DIO1_RF_SUB1GHZ, 0); - } + /* Perform board-specific initialization */ + Board_initHook(); } diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h index 20be159af..be952b936 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h @@ -280,8 +280,12 @@ typedef enum CC1350_LAUNCHXL_I2CName { * @brief Enum of NVS names */ typedef enum CC1350_LAUNCHXL_NVSName { +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH CC1350_LAUNCHXL_NVSCC26XX0 = 0, +#endif +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH CC1350_LAUNCHXL_NVSSPI25X0, +#endif CC1350_LAUNCHXL_NVSCOUNT } CC1350_LAUNCHXL_NVSName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL_fxns.c new file mode 100644 index 000000000..a60df3e65 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL_fxns.c @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +/* + * ======== CC1350_LAUNCHXL_fxns.c ======== + * This file contains the board-specific initialization functions, and + * RF callback function for antenna switching. + */ + +#include +#include +#include + +#include +#include + +#include +#include + +#include "Board.h" + + +/* + * ======== CC1350_LAUNCHXL_sendExtFlashByte ======== + */ +void CC1350_LAUNCHXL_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) +{ + uint8_t i; + + /* SPI Flash CS */ + PIN_setOutputValue(pinHandle, IOID_20, 0); + + for (i = 0; i < 8; i++) { + PIN_setOutputValue(pinHandle, IOID_10, 0); /* SPI Flash CLK */ + + /* SPI Flash MOSI */ + PIN_setOutputValue(pinHandle, IOID_9, (byte >> (7 - i)) & 0x01); + PIN_setOutputValue(pinHandle, IOID_10, 1); /* SPI Flash CLK */ + + /* + * Waste a few cycles to keep the CLK high for at + * least 45% of the period. + * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. + */ + CPUdelay(8); + } + + PIN_setOutputValue(pinHandle, IOID_10, 0); /* CLK */ + PIN_setOutputValue(pinHandle, IOID_20, 1); /* CS */ + + /* + * Keep CS high at least 40 us + * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us + */ + CPUdelay(700); +} + +/* + * ======== CC1350_LAUNCHXL_wakeUpExtFlash ======== + */ +void CC1350_LAUNCHXL_wakeUpExtFlash(void) +{ + PIN_Config extFlashPinTable[] = { + /* SPI Flash CS */ + IOID_20 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + /* + * To wake up we need to toggle the chip select at + * least 20 ns and ten wait at least 35 us. + */ + + /* Toggle chip select for ~20ns to wake ext. flash */ + PIN_setOutputValue(extFlashPinHandle, IOID_20, 0); + /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ + CPUdelay(1); + PIN_setOutputValue(extFlashPinHandle, IOID_20, 1); + /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ + CPUdelay(560); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC1350_LAUNCHXL_shutDownExtFlash ======== + */ +void CC1350_LAUNCHXL_shutDownExtFlash(void) +{ + /* + * To be sure we are putting the flash into sleep and not waking it, + * we first have to make a wake up call + */ + CC1350_LAUNCHXL_wakeUpExtFlash(); + + PIN_Config extFlashPinTable[] = { + /* SPI Flash CS*/ + IOID_20 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash CLK */ + IOID_10 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash MOSI */ + IOID_9 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash MISO */ + IOID_8 | PIN_INPUT_EN | PIN_PULLDOWN, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + uint8_t extFlashShutdown = 0xB9; + + CC1350_LAUNCHXL_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== Board_initHook ======== + * Called by Board_init() to perform board-specific initialization. + */ +void Board_initHook() +{ + CC1350_LAUNCHXL_shutDownExtFlash(); +} + +/* + * For the SysConfig generated Board.h file, Board_RF_SUB1GHZ will not be + * defined unless the RF module is added to the configuration. Therefore, + * we don't include this code if Board_RF_SUB1GHZ is not defined. + */ +#if defined(Board_RF_SUB1GHZ) + +/* + * ======== rfDriverCallback ======== + * This is an implementation for the CC1350 launchpad which uses a + * single signal for antenna switching. + */ +void rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void *arg) +{ + (void)client; + RF_RadioSetup* setupCommand = (RF_RadioSetup*)arg; + + if (events & RF_GlobalEventRadioSetup) { + /* Power up the antenna switch */ + PINCC26XX_setOutputValue(Board_RF_POWER, 1); + + if (setupCommand->common.commandNo == CMD_PROP_RADIO_DIV_SETUP) { + /* Sub-1 GHz, requires antenna switch high */ + PINCC26XX_setOutputValue(Board_RF_SUB1GHZ, 1); + } + } + else if (events & RF_GlobalEventRadioPowerDown) { + /* Disable antenna switch to save current */ + PINCC26XX_setOutputValue(Board_RF_POWER, 0); + PINCC26XX_setOutputValue(Board_RF_SUB1GHZ, 0); + } +} +#endif diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Makefile.cc1350 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Makefile.cc1350 index f8e8e4228..e365c81ad 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Makefile.cc1350 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Makefile.cc1350 @@ -3,8 +3,9 @@ SUBFAMILY = cc13x0-cc26x0 DEVICE_FAMILY = CC13X0 +DEVICE_LINE = CC13XX -BOARD_SOURCEFILES += CC1350_LAUNCHXL.c +BOARD_SOURCEFILES += CC1350_LAUNCHXL.c CC1350_LAUNCHXL_fxns.c SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Board.h index 325472c6e..c078fe636 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Board.h @@ -33,6 +33,8 @@ #ifndef __BOARD_H #define __BOARD_H +#define Board_CC1352P1_LAUNCHXL + #ifdef __cplusplus extern "C" { #endif @@ -76,6 +78,15 @@ extern "C" { #define Board_DIO29_ANALOG CC1352P1_LAUNCHXL_DIO29_ANALOG #define Board_DIO30_RFSW CC1352P1_LAUNCHXL_DIO30_RF_SUB1GHZ +/* + * Board_RF_SUB1GHZ, Board_RF_HIGH_PA, and Board_RF_24GHZ are the names + * generated by SysConfig. Define them here so that the RF callback function + * can reference them. + */ +#define Board_RF_24GHZ CC1352P1_LAUNCHXL_DIO28_RF_24GHZ +#define Board_RF_HIGH_PA CC1352P1_LAUNCHXL_DIO29_RF_HIGH_PA +#define Board_RF_SUB1GHZ CC1352P1_LAUNCHXL_DIO30_RF_SUB1GHZ + #define Board_GPIO_BUTTON0 CC1352P1_LAUNCHXL_GPIO_S1 #define Board_GPIO_BUTTON1 CC1352P1_LAUNCHXL_GPIO_S2 #define Board_GPIO_BTN1 CC1352P1_LAUNCHXL_GPIO_S1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.c index bf5054458..9a42399a8 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.c @@ -553,11 +553,8 @@ const uint_least8_t I2C_count = CC1352P1_LAUNCHXL_I2CCOUNT; #define NVS_REGIONS_BASE 0x48000 #define SECTORSIZE 0x2000 #define REGIONSIZE (SECTORSIZE * 4) -#define SPISECTORSIZE 0x1000 -#define SPIREGIONSIZE (SPISECTORSIZE * 32) -#define VERIFYBUFSIZE 64 -static uint8_t verifyBuf[VERIFYBUFSIZE]; +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH /* * Reserve flash sectors for NVS driver use by placing an uninitialized byte @@ -596,11 +593,10 @@ static char flashBuf[REGIONSIZE]; #endif -/* Allocate objects for NVS and NVS SPI */ +/* Allocate objects for NVS Internal Regions */ NVSCC26XX_Object nvsCC26xxObjects[1]; -NVSSPI25X_Object nvsSPI25XObjects[1]; -/* Hardware attributes for NVS */ +/* Hardware attributes for NVS Internal Regions */ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { { .regionBase = (void *)flashBuf, @@ -608,7 +604,20 @@ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { }, }; -/* Hardware attributes for NVS SPI */ +#endif /* Board_EXCLUDE_NVS_INTERNAL_FLASH */ + +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH + +#define SPISECTORSIZE 0x1000 +#define SPIREGIONSIZE (SPISECTORSIZE * 32) +#define VERIFYBUFSIZE 64 + +static uint8_t verifyBuf[VERIFYBUFSIZE]; + +/* Allocate objects for NVS External Regions */ +NVSSPI25X_Object nvsSPI25XObjects[1]; + +/* Hardware attributes for NVS External Regions */ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { { .regionBaseOffset = 0, @@ -623,18 +632,24 @@ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { }, }; +#endif /* Board_EXCLUDE_NVS_EXTERNAL_FLASH */ + /* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ const NVS_Config NVS_config[CC1352P1_LAUNCHXL_NVSCOUNT] = { +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH { .fxnTablePtr = &NVSCC26XX_fxnTable, .object = &nvsCC26xxObjects[0], .hwAttrs = &nvsCC26xxHWAttrs[0], }, +#endif +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH { .fxnTablePtr = &NVSSPI25X_fxnTable, .object = &nvsSPI25XObjects[0], .hwAttrs = &nvsSPI25XHWAttrs[0], }, +#endif }; const uint_least8_t NVS_count = CC1352P1_LAUNCHXL_NVSCOUNT; @@ -722,19 +737,24 @@ const uint_least8_t PWM_count = CC1352P1_LAUNCHXL_PWMCOUNT; #include /* - * Board-specific callback function to set the correct antenna path. + * Board-specific callback function to set the correct antenna path. * - * This function is called by the RF driver on global driver events. It contains - * a default implementation to set the correct antenna path. + * This function is called by the RF driver on global driver events. + * It contains a default implementation to set the correct antenna path. + * This function is defined in the file CC1352P1_LAUNCHXL_fxns.c */ -static void CC1352P1_LAUNCHXL_rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void* arg); +extern void rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void* arg); const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { - .hwiPriority = ~0, /* Lowest HWI priority */ - .swiPriority = 0, /* Lowest SWI priority */ - .xoscHfAlwaysNeeded = true, /* Keep XOSC dependency while in stanby */ - .globalCallback = &CC1352P1_LAUNCHXL_rfDriverCallback, /* Register the board specific callback */ - .globalEventMask = RF_GlobalEventRadioSetup | RF_GlobalEventRadioPowerDown /* Subscribe the callback to both events */ + .hwiPriority = ~0, /* Lowest HWI priority */ + .swiPriority = 0, /* Lowest SWI priority */ + .xoscHfAlwaysNeeded = true, /* Keep XOSC dependency while in stanby */ + + /* Register the board specific callback */ + .globalCallback = &rfDriverCallback, + + /* Subscribe the callback to both events */ + .globalEventMask = RF_GlobalEventRadioSetup | RF_GlobalEventRadioPowerDown }; /* @@ -934,89 +954,10 @@ const Watchdog_Config Watchdog_config[CC1352P1_LAUNCHXL_WATCHDOGCOUNT] = { const uint_least8_t Watchdog_count = CC1352P1_LAUNCHXL_WATCHDOGCOUNT; /* - * ======== CC1352P1_LAUNCHXL_wakeUpExtFlash ======== + * Board-specific initialization function to disable external flash. + * This function is defined in the file CC1352P1_LAUNCHXL_fxns.c */ -void CC1352P1_LAUNCHXL_wakeUpExtFlash(void) -{ - PIN_Config extFlashPinTable[] = { - CC1352P1_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - PIN_TERMINATE - }; - PIN_State extFlashPinState; - PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); - - /* - * To wake up we need to toggle the chip select at - * least 20 ns and ten wait at least 35 us. - */ - - /* Toggle chip select for ~20ns to wake ext. flash */ - PIN_setOutputValue(extFlashPinHandle, CC1352P1_LAUNCHXL_SPI_FLASH_CS, 0); - /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ - CPUdelay(1); - PIN_setOutputValue(extFlashPinHandle, CC1352P1_LAUNCHXL_SPI_FLASH_CS, 1); - /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ - CPUdelay(560); - - PIN_close(extFlashPinHandle); -} - -/* - * ======== CC1352P1_LAUNCHXL_sendExtFlashByte ======== - */ -void CC1352P1_LAUNCHXL_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) -{ - uint8_t i; - - PIN_setOutputValue(pinHandle, CC1352P1_LAUNCHXL_SPI_FLASH_CS, 0); - - for (i = 0; i < 8; i++) { - PIN_setOutputValue(pinHandle, CC1352P1_LAUNCHXL_SPI0_CLK, 0); - PIN_setOutputValue(pinHandle, CC1352P1_LAUNCHXL_SPI0_MOSI, (byte >> (7 - i)) & 0x01); - PIN_setOutputValue(pinHandle, CC1352P1_LAUNCHXL_SPI0_CLK, 1); - - /* - * Waste a few cycles to keep the CLK high for at - * least 45% of the period. - * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. - */ - CPUdelay(8); - } - - PIN_setOutputValue(pinHandle, CC1352P1_LAUNCHXL_SPI0_CLK, 0); - PIN_setOutputValue(pinHandle, CC1352P1_LAUNCHXL_SPI_FLASH_CS, 1); - - /* - * Keep CS high at least 40 us - * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us - */ - CPUdelay(700); -} - -/* - * ======== CC1352P1_LAUNCHXL_shutDownExtFlash ======== - */ -void CC1352P1_LAUNCHXL_shutDownExtFlash(void) -{ - /* To be sure we are putting the flash into sleep and not waking it, we first have to make a wake up call */ - CC1352P1_LAUNCHXL_wakeUpExtFlash(); - - PIN_Config extFlashPinTable[] = { - CC1352P1_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - CC1352P1_LAUNCHXL_SPI0_CLK | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - CC1352P1_LAUNCHXL_SPI0_MOSI | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - CC1352P1_LAUNCHXL_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, - PIN_TERMINATE - }; - PIN_State extFlashPinState; - PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); - - uint8_t extFlashShutdown = 0xB9; - - CC1352P1_LAUNCHXL_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); - - PIN_close(extFlashPinHandle); -} +extern void Board_initHook(void); /* * ======== CC1352P1_LAUNCHXL_initGeneral ======== @@ -1030,98 +971,6 @@ void CC1352P1_LAUNCHXL_initGeneral(void) while (1); } - CC1352P1_LAUNCHXL_initAntennaSwitch(); - - /* Shut down external flash as default */ - CC1352P1_LAUNCHXL_shutDownExtFlash(); -} - - -/* - * ======== Antenna switching ======== - */ -static PIN_Handle CC1352P1_antennaPins; -static PIN_State CC1352P1_antennaState; - -void CC1352P1_LAUNCHXL_initAntennaSwitch() -{ - PIN_Config antennaConfig[] = { - CC1352P1_LAUNCHXL_DIO28_RF_24GHZ | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Path disabled */ - CC1352P1_LAUNCHXL_DIO29_RF_HIGH_PA | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Path disabled */ - CC1352P1_LAUNCHXL_DIO30_RF_SUB1GHZ | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Path disabled */ - PIN_TERMINATE - }; - CC1352P1_antennaPins = PIN_open(&CC1352P1_antennaState, antennaConfig); -} - -/* - * ======== CC1352P1_LAUNCHXL_rfDriverCallback ======== - * Sets up the antenna switch depending on the current PHY configuration. - * Truth table: - * - * Path DIO28 DIO29 DIO30 - * =========== ===== ===== ===== - * Off 0 0 0 - * Sub-1 GHz 0 0 1 - * 2.4 GHz 1 0 0 - * 20 dBm TX 0 1 0 - */ -void CC1352P1_LAUNCHXL_rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void* arg) -{ - /* Switch off all paths first. Needs to be done anyway in every sub-case below. */ - PINCC26XX_setOutputValue(CC1352P1_LAUNCHXL_DIO28_RF_24GHZ, 0); - PINCC26XX_setOutputValue(CC1352P1_LAUNCHXL_DIO29_RF_HIGH_PA, 0); - PINCC26XX_setOutputValue(CC1352P1_LAUNCHXL_DIO30_RF_SUB1GHZ, 0); - - if (events & RF_GlobalEventRadioSetup) { - /* Decode the current PA configuration. */ - RF_TxPowerTable_PAType paType = (RF_TxPowerTable_PAType)RF_getTxPower(client).paType; - - /* Decode the generic argument as a setup command. */ - RF_RadioSetup* setupCommand = (RF_RadioSetup*)arg; - - if (setupCommand->common.commandNo == CMD_PROP_RADIO_DIV_SETUP) { - /* Sub-1 GHz */ - if (paType == RF_TxPowerTable_HighPA) { - /* PA enable --> HIGH PA - * LNA enable --> Sub-1 GHz - */ - PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO28_RF_24GHZ, PINCC26XX_MUX_GPIO); - // Note: RFC_GPO3 is a work-around because the RFC_GPO1 (PA enable signal) is sometimes not - // de-asserted on CC1352 Rev A. - PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO29_RF_HIGH_PA, PINCC26XX_MUX_RFC_GPO3); - PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO30_RF_SUB1GHZ, PINCC26XX_MUX_RFC_GPO0); - } else { - /* RF core active --> Sub-1 GHz */ - PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO28_RF_24GHZ, PINCC26XX_MUX_GPIO); - PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO29_RF_HIGH_PA, PINCC26XX_MUX_GPIO); - PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO30_RF_SUB1GHZ, PINCC26XX_MUX_GPIO); - PINCC26XX_setOutputValue(CC1352P1_LAUNCHXL_DIO30_RF_SUB1GHZ, 1); - } - } else { - /* 2.4 GHz */ - if (paType == RF_TxPowerTable_HighPA) - { - /* PA enable --> HIGH PA - * LNA enable --> 2.4 GHz - */ - PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO28_RF_24GHZ, PINCC26XX_MUX_RFC_GPO0); - // Note: RFC_GPO3 is a work-around because the RFC_GPO1 (PA enable signal) is sometimes not - // de-asserted on CC1352 Rev A. - PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO29_RF_HIGH_PA, PINCC26XX_MUX_RFC_GPO3); - PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO30_RF_SUB1GHZ, PINCC26XX_MUX_GPIO); - } else { - /* RF core active --> 2.4 GHz */ - PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO28_RF_24GHZ, PINCC26XX_MUX_GPIO); - PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO29_RF_HIGH_PA, PINCC26XX_MUX_GPIO); - PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO30_RF_SUB1GHZ, PINCC26XX_MUX_GPIO); - PINCC26XX_setOutputValue(CC1352P1_LAUNCHXL_DIO28_RF_24GHZ, 1); - } - } - } else { - /* Reset the IO multiplexer to GPIO functionality */ - PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO28_RF_24GHZ, PINCC26XX_MUX_GPIO); - PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO29_RF_HIGH_PA, PINCC26XX_MUX_GPIO); - PINCC26XX_setMux(CC1352P1_antennaPins, CC1352P1_LAUNCHXL_DIO30_RF_SUB1GHZ, PINCC26XX_MUX_GPIO); - } + /* Perform board-specific initialization */ + Board_initHook(); } diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h index 3932531c4..de1c315dd 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h @@ -348,8 +348,12 @@ typedef enum CC1352P1_LAUNCHXL_I2CName { * @brief Enum of NVS names */ typedef enum CC1352P1_LAUNCHXL_NVSName { +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH CC1352P1_LAUNCHXL_NVSCC26XX0 = 0, +#endif +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH CC1352P1_LAUNCHXL_NVSSPI25X0, +#endif CC1352P1_LAUNCHXL_NVSCOUNT } CC1352P1_LAUNCHXL_NVSName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL_fxns.c new file mode 100644 index 000000000..cdfa6342e --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL_fxns.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +/* + * ======== CC1352P1_LAUNCHXL_fxns.c ======== + * This file contains the board-specific initialization functions, and + * RF callback function for antenna switching. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "Board.h" + +/* + * ======== CC1352P1_LAUNCHXL_sendExtFlashByte ======== + */ +void CC1352P1_LAUNCHXL_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) +{ + uint8_t i; + + /* SPI Flash CS */ + PIN_setOutputValue(pinHandle, IOID_20, 0); + + for (i = 0; i < 8; i++) { + PIN_setOutputValue(pinHandle, IOID_10, 0); /* SPI Flash CLK */ + + /* SPI Flash MOSI */ + PIN_setOutputValue(pinHandle, IOID_9, (byte >> (7 - i)) & 0x01); + PIN_setOutputValue(pinHandle, IOID_10, 1); /* SPI Flash CLK */ + + /* + * Waste a few cycles to keep the CLK high for at + * least 45% of the period. + * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. + */ + CPUdelay(8); + } + + PIN_setOutputValue(pinHandle, IOID_10, 0); /* CLK */ + PIN_setOutputValue(pinHandle, IOID_20, 1); /* CS */ + + /* + * Keep CS high at least 40 us + * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us + */ + CPUdelay(700); +} + +/* + * ======== CC1352P1_LAUNCHXL_wakeUpExtFlash ======== + */ +void CC1352P1_LAUNCHXL_wakeUpExtFlash(void) +{ + PIN_Config extFlashPinTable[] = { + /* SPI Flash CS */ + IOID_20 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + /* + * To wake up we need to toggle the chip select at + * least 20 ns and ten wait at least 35 us. + */ + + /* Toggle chip select for ~20ns to wake ext. flash */ + PIN_setOutputValue(extFlashPinHandle, IOID_20, 0); + /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ + CPUdelay(1); + PIN_setOutputValue(extFlashPinHandle, IOID_20, 1); + /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ + CPUdelay(560); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC1352P1_LAUNCHXL_shutDownExtFlash ======== + */ +void CC1352P1_LAUNCHXL_shutDownExtFlash(void) +{ + /* To be sure we are putting the flash into sleep and not waking it, we first have to make a wake up call */ + CC1352P1_LAUNCHXL_wakeUpExtFlash(); + + PIN_Config extFlashPinTable[] = { + /* SPI Flash CS*/ + IOID_20 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash CLK */ + IOID_10 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash MOSI */ + IOID_9 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash MISO */ + IOID_8 | PIN_INPUT_EN | PIN_PULLDOWN, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + uint8_t extFlashShutdown = 0xB9; + + CC1352P1_LAUNCHXL_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); + + PIN_close(extFlashPinHandle); +} + +/* + * For the SysConfig generated Board.h file, Board_RF_SUB1GHZ will not be + * defined unless the RF module is added to the configuration. Therefore, + * we don't include this code if Board_RF_SUB1GHZ is not defined. + */ +#if defined(Board_RF_SUB1GHZ) + +/* + * ======== Antenna switching ======== + */ +static PIN_Handle antennaPins; +static PIN_State antennaState; + +void initAntennaSwitch() +{ + PIN_Config antennaConfig[] = { + Board_RF_24GHZ | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Path disabled */ + Board_RF_HIGH_PA | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Path disabled */ + Board_RF_SUB1GHZ | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Path disabled */ + PIN_TERMINATE + }; + antennaPins = PIN_open(&antennaState, antennaConfig); +} + +/* + * ======== rfDriverCallback ======== + * Sets up the antenna switch depending on the current PHY configuration. + * Truth table: + * + * Path DIO28 DIO29 DIO30 + * =========== ===== ===== ===== + * Off 0 0 0 + * Sub-1 GHz 0 0 1 + * 2.4 GHz 1 0 0 + * 20 dBm TX 0 1 0 + */ +void rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void *arg) +{ + /* Switch off all paths first. Needs to be done anyway in every sub-case below. */ + PINCC26XX_setOutputValue(Board_RF_24GHZ, 0); + PINCC26XX_setOutputValue(Board_RF_HIGH_PA, 0); + PINCC26XX_setOutputValue(Board_RF_SUB1GHZ, 0); + + if (events & RF_GlobalEventRadioSetup) { + /* Decode the current PA configuration. */ + RF_TxPowerTable_PAType paType = (RF_TxPowerTable_PAType)RF_getTxPower(client).paType; + + /* Decode the generic argument as a setup command. */ + RF_RadioSetup* setupCommand = (RF_RadioSetup*)arg; + + if (setupCommand->common.commandNo == CMD_PROP_RADIO_DIV_SETUP) { + /* Sub-1 GHz */ + if (paType == RF_TxPowerTable_HighPA) { + /* PA enable --> HIGH PA + * LNA enable --> Sub-1 GHz + */ + PINCC26XX_setMux(antennaPins, Board_RF_24GHZ, PINCC26XX_MUX_GPIO); + // Note: RFC_GPO3 is a work-around because the RFC_GPO1 (PA enable signal) is sometimes not + // de-asserted on CC1352 Rev A. + PINCC26XX_setMux(antennaPins, Board_RF_HIGH_PA, PINCC26XX_MUX_RFC_GPO3); + PINCC26XX_setMux(antennaPins, Board_RF_SUB1GHZ, PINCC26XX_MUX_RFC_GPO0); + } else { + /* RF core active --> Sub-1 GHz */ + PINCC26XX_setMux(antennaPins, Board_RF_24GHZ, PINCC26XX_MUX_GPIO); + PINCC26XX_setMux(antennaPins, Board_RF_HIGH_PA, PINCC26XX_MUX_GPIO); + PINCC26XX_setMux(antennaPins, Board_RF_SUB1GHZ, PINCC26XX_MUX_GPIO); + PINCC26XX_setOutputValue(Board_RF_SUB1GHZ, 1); + } + } else { + /* 2.4 GHz */ + if (paType == RF_TxPowerTable_HighPA) + { + /* PA enable --> HIGH PA + * LNA enable --> 2.4 GHz + */ + PINCC26XX_setMux(antennaPins, Board_RF_24GHZ, PINCC26XX_MUX_RFC_GPO0); + // Note: RFC_GPO3 is a work-around because the RFC_GPO1 (PA enable signal) is sometimes not + // de-asserted on CC1352 Rev A. + PINCC26XX_setMux(antennaPins, Board_RF_HIGH_PA, PINCC26XX_MUX_RFC_GPO3); + PINCC26XX_setMux(antennaPins, Board_RF_SUB1GHZ, PINCC26XX_MUX_GPIO); + } else { + /* RF core active --> 2.4 GHz */ + PINCC26XX_setMux(antennaPins, Board_RF_24GHZ, PINCC26XX_MUX_GPIO); + PINCC26XX_setMux(antennaPins, Board_RF_HIGH_PA, PINCC26XX_MUX_GPIO); + PINCC26XX_setMux(antennaPins, Board_RF_SUB1GHZ, PINCC26XX_MUX_GPIO); + PINCC26XX_setOutputValue(Board_RF_24GHZ, 1); + } + } + } else { + /* Reset the IO multiplexer to GPIO functionality */ + PINCC26XX_setMux(antennaPins, Board_RF_24GHZ, PINCC26XX_MUX_GPIO); + PINCC26XX_setMux(antennaPins, Board_RF_HIGH_PA, PINCC26XX_MUX_GPIO); + PINCC26XX_setMux(antennaPins, Board_RF_SUB1GHZ, PINCC26XX_MUX_GPIO); + } +} +#endif + +/* + * ======== Board_initHook ======== + * Called by Board_init() to perform board-specific initialization. + */ +void Board_initHook() +{ +#if defined(Board_RF_SUB1GHZ) + initAntennaSwitch(); +#endif + + CC1352P1_LAUNCHXL_shutDownExtFlash(); +} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 index a26703c3d..d24e181a4 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 @@ -3,8 +3,9 @@ SUBFAMILY = cc13x2-cc26x2 DEVICE_FAMILY = CC13X2 +DEVICE_LINE = CC13XX -BOARD_SOURCEFILES += CC1352P1_LAUNCHXL.c +BOARD_SOURCEFILES += CC1352P1_LAUNCHXL.c CC1312P1_LAUNCHXL_fxns.c SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/Board.h new file mode 100644 index 000000000..7fe300916 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/Board.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2017-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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 __BOARD_H +#define __BOARD_H + +#define Board_CC1352P_2_LAUNCHXL + +#ifdef __cplusplus +extern "C" { +#endif + +#include "CC1352P_2_LAUNCHXL.h" + +#define Board_initGeneral() CC1352P_2_LAUNCHXL_initGeneral() +#define Board_shutDownExtFlash() CC1352P_2_LAUNCHXL_shutDownExtFlash() +#define Board_wakeUpExtFlash() CC1352P_2_LAUNCHXL_wakeUpExtFlash() + +/* These #defines allow us to reuse TI-RTOS across other device families */ + +#define Board_ADC0 CC1352P_2_LAUNCHXL_ADC0 +#define Board_ADC1 CC1352P_2_LAUNCHXL_ADC1 + +#define Board_ADCBUF0 CC1352P_2_LAUNCHXL_ADCBUF0 +#define Board_ADCBUF0CHANNEL0 CC1352P_2_LAUNCHXL_ADCBUF0CHANNEL0 +#define Board_ADCBUF0CHANNEL1 CC1352P_2_LAUNCHXL_ADCBUF0CHANNEL1 + +#define Board_CRYPTO0 CC1352P_2_LAUNCHXL_CRYPTO0 +#define Board_ECDH0 CC1352P_2_LAUNCHXL_ECDH0 +#define Board_ECDSA0 CC1352P_2_LAUNCHXL_ECDSA0 +#define Board_ECJPAKE0 CC1352P_2_LAUNCHXL_ECJPAKE0 +#define Board_AESCCM0 CC1352P_2_LAUNCHXL_AESCCM0 +#define Board_AESECB0 CC1352P_2_LAUNCHXL_AESECB0 +#define Board_SHA20 CC1352P_2_LAUNCHXL_SHA20 + +#define Board_DIO12 CC1352P_2_LAUNCHXL_DIO12 +#define Board_DIO15 CC1352P_2_LAUNCHXL_DIO15 +#define Board_DIO16_TDO CC1352P_2_LAUNCHXL_DIO16_TDO +#define Board_DIO17_TDI CC1352P_2_LAUNCHXL_DIO17_TDI +#define Board_DIO21 CC1352P_2_LAUNCHXL_DIO21 +#define Board_DIO22 CC1352P_2_LAUNCHXL_DIO22 + +#define Board_DIO23_ANALOG CC1352P_2_LAUNCHXL_DIO23_ANALOG +#define Board_DIO24_ANALOG CC1352P_2_LAUNCHXL_DIO24_ANALOG +#define Board_DIO25_ANALOG CC1352P_2_LAUNCHXL_DIO25_ANALOG +#define Board_DIO26_ANALOG CC1352P_2_LAUNCHXL_DIO26_ANALOG +#define Board_DIO27_ANALOG CC1352P_2_LAUNCHXL_DIO27_ANALOG +#define Board_DIO28_ANALOG CC1352P_2_LAUNCHXL_DIO28_ANALOG +#define Board_DIO29_ANALOG CC1352P_2_LAUNCHXL_DIO29_ANALOG +#define Board_DIO30_RFSW CC1352P_2_LAUNCHXL_DIO30_RF_SUB1GHZ + +/* + * Board_RF_SUB1GHZ, Board_RF_HIGH_PA, and Board_RF_24GHZ are the names + * generated by SysConfig. Define them here so that the RF callback function + * can reference them. + */ +#define Board_RF_24GHZ CC1352P_2_LAUNCHXL_DIO28_RF_24GHZ +#define Board_RF_HIGH_PA CC1352P_2_LAUNCHXL_DIO29_RF_HIGH_PA +#define Board_RF_SUB1GHZ CC1352P_2_LAUNCHXL_DIO30_RF_SUB1GHZ + +#define Board_GPIO_BUTTON0 CC1352P_2_LAUNCHXL_GPIO_S1 +#define Board_GPIO_BUTTON1 CC1352P_2_LAUNCHXL_GPIO_S2 +#define Board_GPIO_BTN1 CC1352P_2_LAUNCHXL_GPIO_S1 +#define Board_GPIO_BTN2 CC1352P_2_LAUNCHXL_GPIO_S2 +#define Board_GPIO_LED0 CC1352P_2_LAUNCHXL_GPIO_LED_RED +#define Board_GPIO_LED1 CC1352P_2_LAUNCHXL_GPIO_LED_GREEN +#define Board_GPIO_LED2 CC1352P_2_LAUNCHXL_GPIO_LED_RED +#define Board_GPIO_RLED CC1352P_2_LAUNCHXL_GPIO_LED_RED +#define Board_GPIO_GLED CC1352P_2_LAUNCHXL_GPIO_LED_GREEN +#define Board_GPIO_LED_ON CC1352P_2_LAUNCHXL_GPIO_LED_ON +#define Board_GPIO_LED_OFF CC1352P_2_LAUNCHXL_GPIO_LED_OFF + +#define Board_GPTIMER0A CC1352P_2_LAUNCHXL_GPTIMER0A +#define Board_GPTIMER0B CC1352P_2_LAUNCHXL_GPTIMER0B +#define Board_GPTIMER1A CC1352P_2_LAUNCHXL_GPTIMER1A +#define Board_GPTIMER1B CC1352P_2_LAUNCHXL_GPTIMER1B +#define Board_GPTIMER2A CC1352P_2_LAUNCHXL_GPTIMER2A +#define Board_GPTIMER2B CC1352P_2_LAUNCHXL_GPTIMER2B +#define Board_GPTIMER3A CC1352P_2_LAUNCHXL_GPTIMER3A +#define Board_GPTIMER3B CC1352P_2_LAUNCHXL_GPTIMER3B + +#define Board_I2C0 CC1352P_2_LAUNCHXL_I2C0 +#define Board_I2C_TMP Board_I2C0 + +#define Board_NVSINTERNAL CC1352P_2_LAUNCHXL_NVSCC26XX0 +#define Board_NVSEXTERNAL CC1352P_2_LAUNCHXL_NVSSPI25X0 + +#define Board_PIN_BUTTON0 CC1352P_2_LAUNCHXL_PIN_BTN1 +#define Board_PIN_BUTTON1 CC1352P_2_LAUNCHXL_PIN_BTN2 +#define Board_PIN_BTN1 CC1352P_2_LAUNCHXL_PIN_BTN1 +#define Board_PIN_BTN2 CC1352P_2_LAUNCHXL_PIN_BTN2 +#define Board_PIN_LED0 CC1352P_2_LAUNCHXL_PIN_RLED +#define Board_PIN_LED1 CC1352P_2_LAUNCHXL_PIN_GLED +#define Board_PIN_LED2 CC1352P_2_LAUNCHXL_PIN_RLED +#define Board_PIN_RLED CC1352P_2_LAUNCHXL_PIN_RLED +#define Board_PIN_GLED CC1352P_2_LAUNCHXL_PIN_GLED + +#define Board_PWM0 CC1352P_2_LAUNCHXL_PWM0 +#define Board_PWM1 CC1352P_2_LAUNCHXL_PWM1 +#define Board_PWM2 CC1352P_2_LAUNCHXL_PWM2 +#define Board_PWM3 CC1352P_2_LAUNCHXL_PWM3 +#define Board_PWM4 CC1352P_2_LAUNCHXL_PWM4 +#define Board_PWM5 CC1352P_2_LAUNCHXL_PWM5 +#define Board_PWM6 CC1352P_2_LAUNCHXL_PWM6 +#define Board_PWM7 CC1352P_2_LAUNCHXL_PWM7 + +#define Board_SD0 CC1352P_2_LAUNCHXL_SDSPI0 + +#define Board_SPI0 CC1352P_2_LAUNCHXL_SPI0 +#define Board_SPI1 CC1352P_2_LAUNCHXL_SPI1 +#define Board_SPI_FLASH_CS CC1352P_2_LAUNCHXL_SPI_FLASH_CS +#define Board_FLASH_CS_ON 0 +#define Board_FLASH_CS_OFF 1 + +#define Board_SPI_MASTER CC1352P_2_LAUNCHXL_SPI0 +#define Board_SPI_SLAVE CC1352P_2_LAUNCHXL_SPI0 +#define Board_SPI_MASTER_READY CC1352P_2_LAUNCHXL_SPI_MASTER_READY +#define Board_SPI_SLAVE_READY CC1352P_2_LAUNCHXL_SPI_SLAVE_READY + +#define Board_UART0 CC1352P_2_LAUNCHXL_UART0 +#define Board_UART1 CC1352P_2_LAUNCHXL_UART1 + +#define Board_WATCHDOG0 CC1352P_2_LAUNCHXL_WATCHDOG0 + +/* Board specific I2C addresses */ +#define Board_TMP_ADDR (0x40) +#define Board_SENSORS_BP_TMP_ADDR Board_TMP_ADDR + +#ifdef __cplusplus +} +#endif + +#endif /* __BOARD_H */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/CC1352P_2_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/CC1352P_2_LAUNCHXL.c new file mode 100644 index 000000000..d78087e3d --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/CC1352P_2_LAUNCHXL.c @@ -0,0 +1,976 @@ +/* + * Copyright (c) 2017-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +/* + * ====================== CC1352P_2_LAUNCHXL.c =================================== + * This file is responsible for setting up the board specific items for the + * CC1352P_2_LAUNCHXL board. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "CC1352P_2_LAUNCHXL.h" + +/* + * =============================== ADCBuf =============================== + */ +#include +#include + +ADCBufCC26X2_Object adcBufCC26xxObjects[CC1352P_2_LAUNCHXL_ADCBUFCOUNT]; + +/* + * This table converts a virtual adc channel into a dio and internal analogue + * input signal. This table is necessary for the functioning of the adcBuf + * driver. Comment out unused entries to save flash. Dio and internal signal + * pairs are hardwired. Do not remap them in the table. You may reorder entire + * entries. The mapping of dio and internal signals is package dependent. + */ +const ADCBufCC26X2_AdcChannelLutEntry ADCBufCC26X2_adcChannelLut[CC1352P_2_LAUNCHXL_ADCBUF0CHANNELCOUNT] = { + {CC1352P_2_LAUNCHXL_DIO23_ANALOG, ADC_COMPB_IN_AUXIO7}, + {CC1352P_2_LAUNCHXL_DIO24_ANALOG, ADC_COMPB_IN_AUXIO6}, + {CC1352P_2_LAUNCHXL_DIO25_ANALOG, ADC_COMPB_IN_AUXIO5}, + {CC1352P_2_LAUNCHXL_DIO26_ANALOG, ADC_COMPB_IN_AUXIO4}, + {CC1352P_2_LAUNCHXL_DIO27_ANALOG, ADC_COMPB_IN_AUXIO3}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VDDS}, + {PIN_UNASSIGNED, ADC_COMPB_IN_DCOUPL}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VSS}, +}; + +const ADCBufCC26X2_HWAttrs adcBufCC26xxHWAttrs[CC1352P_2_LAUNCHXL_ADCBUFCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + .adcChannelLut = ADCBufCC26X2_adcChannelLut, + .gpTimerUnit = CC1352P_2_LAUNCHXL_GPTIMER0A, + } +}; + +const ADCBuf_Config ADCBuf_config[CC1352P_2_LAUNCHXL_ADCBUFCOUNT] = { + { + &ADCBufCC26X2_fxnTable, + &adcBufCC26xxObjects[CC1352P_2_LAUNCHXL_ADCBUF0], + &adcBufCC26xxHWAttrs[CC1352P_2_LAUNCHXL_ADCBUF0] + }, +}; + +const uint_least8_t ADCBuf_count = CC1352P_2_LAUNCHXL_ADCBUFCOUNT; + +/* + * =============================== ADC =============================== + */ +#include +#include + +ADCCC26XX_Object adcCC26xxObjects[CC1352P_2_LAUNCHXL_ADCCOUNT]; + +const ADCCC26XX_HWAttrs adcCC26xxHWAttrs[CC1352P_2_LAUNCHXL_ADCCOUNT] = { + { + .adcDIO = CC1352P_2_LAUNCHXL_DIO23_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO7, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1352P_2_LAUNCHXL_DIO24_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO6, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1352P_2_LAUNCHXL_DIO25_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO5, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1352P_2_LAUNCHXL_DIO26_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO4, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1352P_2_LAUNCHXL_DIO27_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO3, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_DCOUPL, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VSS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VDDS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + } +}; + +const ADC_Config ADC_config[CC1352P_2_LAUNCHXL_ADCCOUNT] = { + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352P_2_LAUNCHXL_ADC0], &adcCC26xxHWAttrs[CC1352P_2_LAUNCHXL_ADC0]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352P_2_LAUNCHXL_ADC1], &adcCC26xxHWAttrs[CC1352P_2_LAUNCHXL_ADC1]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352P_2_LAUNCHXL_ADC2], &adcCC26xxHWAttrs[CC1352P_2_LAUNCHXL_ADC2]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352P_2_LAUNCHXL_ADC3], &adcCC26xxHWAttrs[CC1352P_2_LAUNCHXL_ADC3]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352P_2_LAUNCHXL_ADC4], &adcCC26xxHWAttrs[CC1352P_2_LAUNCHXL_ADC4]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352P_2_LAUNCHXL_ADCDCOUPL], &adcCC26xxHWAttrs[CC1352P_2_LAUNCHXL_ADCDCOUPL]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352P_2_LAUNCHXL_ADCVSS], &adcCC26xxHWAttrs[CC1352P_2_LAUNCHXL_ADCVSS]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352P_2_LAUNCHXL_ADCVDDS], &adcCC26xxHWAttrs[CC1352P_2_LAUNCHXL_ADCVDDS]}, +}; + +const uint_least8_t ADC_count = CC1352P_2_LAUNCHXL_ADCCOUNT; + +/* + * =============================== ECDH =============================== + */ +#include +#include + +ECDHCC26X2_Object ecdhCC26X2Objects[CC1352P_2_LAUNCHXL_ECDHCOUNT]; + +const ECDHCC26X2_HWAttrs ecdhCC26X2HWAttrs[CC1352P_2_LAUNCHXL_ECDHCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const ECDH_Config ECDH_config[CC1352P_2_LAUNCHXL_ECDHCOUNT] = { + { + .object = &ecdhCC26X2Objects[CC1352P_2_LAUNCHXL_ECDH0], + .hwAttrs = &ecdhCC26X2HWAttrs[CC1352P_2_LAUNCHXL_ECDH0] + }, +}; + +const uint_least8_t ECDH_count = CC1352P_2_LAUNCHXL_ECDHCOUNT; + +/* + * =============================== ECDSA =============================== + */ +#include +#include + +ECDSACC26X2_Object ecdsaCC26X2Objects[CC1352P_2_LAUNCHXL_ECDSACOUNT]; + +const ECDSACC26X2_HWAttrs ecdsaCC26X2HWAttrs[CC1352P_2_LAUNCHXL_ECDSACOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const ECDSA_Config ECDSA_config[CC1352P_2_LAUNCHXL_ECDSACOUNT] = { + { + .object = &ecdsaCC26X2Objects[CC1352P_2_LAUNCHXL_ECDSA0], + .hwAttrs = &ecdsaCC26X2HWAttrs[CC1352P_2_LAUNCHXL_ECDSA0] + }, +}; + +const uint_least8_t ECDSA_count = CC1352P_2_LAUNCHXL_ECDSACOUNT; + +/* + * =============================== ECJPAKE =============================== + */ +#include +#include + +ECJPAKECC26X2_Object ecjpakeCC26X2Objects[CC1352P_2_LAUNCHXL_ECJPAKECOUNT]; + +const ECJPAKECC26X2_HWAttrs ecjpakeCC26X2HWAttrs[CC1352P_2_LAUNCHXL_ECJPAKECOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const ECJPAKE_Config ECJPAKE_config[CC1352P_2_LAUNCHXL_ECJPAKECOUNT] = { + { + .object = &ecjpakeCC26X2Objects[CC1352P_2_LAUNCHXL_ECJPAKE0], + .hwAttrs = &ecjpakeCC26X2HWAttrs[CC1352P_2_LAUNCHXL_ECJPAKE0] + }, +}; + +const uint_least8_t ECJPAKE_count = CC1352P_2_LAUNCHXL_ECJPAKECOUNT; + + +/* + * =============================== SHA2 =============================== + */ +#include +#include + +SHA2CC26X2_Object sha2CC26X2Objects[CC1352P_2_LAUNCHXL_SHA2COUNT]; + +const SHA2CC26X2_HWAttrs sha2CC26X2HWAttrs[CC1352P_2_LAUNCHXL_SHA2COUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const SHA2_Config SHA2_config[CC1352P_2_LAUNCHXL_SHA2COUNT] = { + { + .object = &sha2CC26X2Objects[CC1352P_2_LAUNCHXL_SHA20], + .hwAttrs = &sha2CC26X2HWAttrs[CC1352P_2_LAUNCHXL_SHA20] + }, +}; + +const uint_least8_t SHA2_count = CC1352P_2_LAUNCHXL_SHA2COUNT; + +/* + * =============================== AESCCM =============================== + */ +#include +#include + +AESCCMCC26XX_Object aesccmCC26XXObjects[CC1352P_2_LAUNCHXL_AESCCMCOUNT]; + +const AESCCMCC26XX_HWAttrs aesccmCC26XXHWAttrs[CC1352P_2_LAUNCHXL_AESCCMCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const AESCCM_Config AESCCM_config[CC1352P_2_LAUNCHXL_AESCCMCOUNT] = { + { + .object = &aesccmCC26XXObjects[CC1352P_2_LAUNCHXL_AESCCM0], + .hwAttrs = &aesccmCC26XXHWAttrs[CC1352P_2_LAUNCHXL_AESCCM0] + }, +}; + +const uint_least8_t AESCCM_count = CC1352P_2_LAUNCHXL_AESCCMCOUNT; + +/* + * =============================== AESECB =============================== + */ +#include +#include + +AESECBCC26XX_Object aesecbCC26XXObjects[CC1352P_2_LAUNCHXL_AESECBCOUNT]; + +const AESECBCC26XX_HWAttrs aesecbCC26XXHWAttrs[CC1352P_2_LAUNCHXL_AESECBCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const AESECB_Config AESECB_config[CC1352P_2_LAUNCHXL_AESECBCOUNT] = { + { + .object = &aesecbCC26XXObjects[CC1352P_2_LAUNCHXL_AESECB0], + .hwAttrs = &aesecbCC26XXHWAttrs[CC1352P_2_LAUNCHXL_AESECB0] + }, +}; + +const uint_least8_t AESECB_count = CC1352P_2_LAUNCHXL_AESECBCOUNT; + +/* + * =============================== Display =============================== + */ +#include +#include +#include + +#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE +#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 +#endif + +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 +#endif + +DisplayUart_Object displayUartObject; +DisplaySharp_Object displaySharpObject; + +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; +static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; + +const DisplayUart_HWAttrs displayUartHWAttrs = { + .uartIdx = CC1352P_2_LAUNCHXL_UART0, + .baudRate = 115200, + .mutexTimeout = (unsigned int)(-1), + .strBuf = uartStringBuf, + .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, +}; + +const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { + .spiIndex = CC1352P_2_LAUNCHXL_SPI0, + .csPin = CC1352P_2_LAUNCHXL_GPIO_LCD_CS, + .powerPin = CC1352P_2_LAUNCHXL_GPIO_DIO_19, + .enablePin = CC1352P_2_LAUNCHXL_GPIO_LCD_ENABLE, + .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, + .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, + .displayBuf = sharpDisplayBuf, +}; + +#ifndef BOARD_DISPLAY_USE_UART +#define BOARD_DISPLAY_USE_UART 1 +#endif +#ifndef BOARD_DISPLAY_USE_UART_ANSI +#define BOARD_DISPLAY_USE_UART_ANSI 0 +#endif +#ifndef BOARD_DISPLAY_USE_LCD +#define BOARD_DISPLAY_USE_LCD 0 +#endif + +/* + * This #if/#else is needed to workaround a problem with the + * IAR compiler. The IAR compiler doesn't like the empty array + * initialization. (IAR Error[Pe1345]) + */ +#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) + +const Display_Config Display_config[] = { +#if (BOARD_DISPLAY_USE_UART) + { +# if (BOARD_DISPLAY_USE_UART_ANSI) + .fxnTablePtr = &DisplayUartAnsi_fxnTable, +# else /* Default to minimal UART with no cursor placement */ + .fxnTablePtr = &DisplayUartMin_fxnTable, +# endif + .object = &displayUartObject, + .hwAttrs = &displayUartHWAttrs, + }, +#endif +#if (BOARD_DISPLAY_USE_LCD) + { + .fxnTablePtr = &DisplaySharp_fxnTable, + .object = &displaySharpObject, + .hwAttrs = &displaySharpHWattrs + }, +#endif +}; + +const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); + +#else + +const Display_Config *Display_config = NULL; +const uint_least8_t Display_count = 0; + +#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ + +/* + * =============================== GPIO =============================== + */ +#include +#include + +/* + * Array of Pin configurations + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC1352P_2_LAUNCHXL.h + * NOTE: Pins not used for interrupts should be placed at the end of the + * array. Callback entries can be omitted from callbacks array to + * reduce memory usage. + */ +GPIO_PinConfig gpioPinConfigs[] = { + /* Input pins */ + GPIOCC26XX_DIO_15 | GPIO_DO_NOT_CONFIG, /* Button 0 */ + GPIOCC26XX_DIO_14 | GPIO_DO_NOT_CONFIG, /* Button 1 */ + + GPIOCC26XX_DIO_15 | GPIO_DO_NOT_CONFIG, /* CC1352P_2_LAUNCHXL_SPI_MASTER_READY */ + GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG, /* CC1352P_2_LAUNCHXL_SPI_SLAVE_READY */ + + /* Output pins */ + GPIOCC26XX_DIO_07 | GPIO_DO_NOT_CONFIG, /* Green LED */ + GPIOCC26XX_DIO_06 | GPIO_DO_NOT_CONFIG, /* Red LED */ + + /* SPI Flash CSN */ + GPIOCC26XX_DIO_20 | GPIO_DO_NOT_CONFIG, + + /* + * DIO 19 is used for LCD power control and SD chip select. This is due to + * DIO21 & DIO22 moving on this LaunchPad. DIO 19 can also be used as a + * UART CTS pin. + */ + GPIOCC26XX_DIO_19 | GPIO_DO_NOT_CONFIG, + + /* Sharp Display - GPIO configurations will be done in the Display files */ + GPIOCC26XX_DIO_24 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ + GPIOCC26XX_DIO_23 | GPIO_DO_NOT_CONFIG, /*LCD enable */ + +}; + +/* + * Array of callback function pointers + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC1352P_LAUNCH.h + * NOTE: Pins not used for interrupts can be omitted from callbacks array to + * reduce memory usage (if placed at end of gpioPinConfigs array). + */ +GPIO_CallbackFxn gpioCallbackFunctions[] = { + NULL, /* Button 0 */ + NULL, /* Button 1 */ + NULL, /* CC1352P_2_LAUNCHXL_SPI_MASTER_READY */ + NULL, /* CC1352P_2_LAUNCHXL_SPI_SLAVE_READY */ +}; + +const GPIOCC26XX_Config GPIOCC26XX_config = { + .pinConfigs = (GPIO_PinConfig *)gpioPinConfigs, + .callbacks = (GPIO_CallbackFxn *)gpioCallbackFunctions, + .numberOfPinConfigs = CC1352P_2_LAUNCHXL_GPIOCOUNT, + .numberOfCallbacks = sizeof(gpioCallbackFunctions)/sizeof(GPIO_CallbackFxn), + .intPriority = (~0) +}; + +/* + * =============================== GPTimer =============================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +#include + +GPTimerCC26XX_Object gptimerCC26XXObjects[CC1352P_2_LAUNCHXL_GPTIMERCOUNT]; + +const GPTimerCC26XX_HWAttrs gptimerCC26xxHWAttrs[CC1352P_2_LAUNCHXL_GPTIMERPARTSCOUNT] = { + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0A, }, + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0B, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1A, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1B, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2A, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2B, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3A, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3B, }, +}; + +const GPTimerCC26XX_Config GPTimerCC26XX_config[CC1352P_2_LAUNCHXL_GPTIMERPARTSCOUNT] = { + { &gptimerCC26XXObjects[CC1352P_2_LAUNCHXL_GPTIMER0], &gptimerCC26xxHWAttrs[CC1352P_2_LAUNCHXL_GPTIMER0A], GPT_A }, + { &gptimerCC26XXObjects[CC1352P_2_LAUNCHXL_GPTIMER0], &gptimerCC26xxHWAttrs[CC1352P_2_LAUNCHXL_GPTIMER0B], GPT_B }, + { &gptimerCC26XXObjects[CC1352P_2_LAUNCHXL_GPTIMER1], &gptimerCC26xxHWAttrs[CC1352P_2_LAUNCHXL_GPTIMER1A], GPT_A }, + { &gptimerCC26XXObjects[CC1352P_2_LAUNCHXL_GPTIMER1], &gptimerCC26xxHWAttrs[CC1352P_2_LAUNCHXL_GPTIMER1B], GPT_B }, + { &gptimerCC26XXObjects[CC1352P_2_LAUNCHXL_GPTIMER2], &gptimerCC26xxHWAttrs[CC1352P_2_LAUNCHXL_GPTIMER2A], GPT_A }, + { &gptimerCC26XXObjects[CC1352P_2_LAUNCHXL_GPTIMER2], &gptimerCC26xxHWAttrs[CC1352P_2_LAUNCHXL_GPTIMER2B], GPT_B }, + { &gptimerCC26XXObjects[CC1352P_2_LAUNCHXL_GPTIMER3], &gptimerCC26xxHWAttrs[CC1352P_2_LAUNCHXL_GPTIMER3A], GPT_A }, + { &gptimerCC26XXObjects[CC1352P_2_LAUNCHXL_GPTIMER3], &gptimerCC26xxHWAttrs[CC1352P_2_LAUNCHXL_GPTIMER3B], GPT_B }, +}; + +/* + * =============================== I2C =============================== +*/ +#include +#include + +I2CCC26XX_Object i2cCC26xxObjects[CC1352P_2_LAUNCHXL_I2CCOUNT]; + +const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1352P_2_LAUNCHXL_I2CCOUNT] = { + { + .baseAddr = I2C0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_I2C0, + .intNum = INT_I2C_IRQ, + .intPriority = ~0, + .swiPriority = 0, + .sdaPin = CC1352P_2_LAUNCHXL_I2C0_SDA0, + .sclPin = CC1352P_2_LAUNCHXL_I2C0_SCL0, + } +}; + +const I2C_Config I2C_config[CC1352P_2_LAUNCHXL_I2CCOUNT] = { + { + .fxnTablePtr = &I2CCC26XX_fxnTable, + .object = &i2cCC26xxObjects[CC1352P_2_LAUNCHXL_I2C0], + .hwAttrs = &i2cCC26xxHWAttrs[CC1352P_2_LAUNCHXL_I2C0] + }, +}; + +const uint_least8_t I2C_count = CC1352P_2_LAUNCHXL_I2CCOUNT; + +/* + * =============================== NVS =============================== + */ +#include +#include +#include + +#define NVS_REGIONS_BASE 0x48000 +#define SECTORSIZE 0x2000 +#define REGIONSIZE (SECTORSIZE * 4) + +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH + +/* + * Reserve flash sectors for NVS driver use by placing an uninitialized byte + * array at the desired flash address. + */ +#if defined(__TI_COMPILER_VERSION__) + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +#pragma LOCATION(flashBuf, NVS_REGIONS_BASE); +#pragma NOINIT(flashBuf); +static char flashBuf[REGIONSIZE]; + +#elif defined(__IAR_SYSTEMS_ICC__) + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +static __no_init char flashBuf[REGIONSIZE] @ NVS_REGIONS_BASE; + +#elif defined(__GNUC__) + +/* + * Place the flash buffers in the .nvs section created in the gcc linker file. + * The .nvs section enforces alignment on a sector boundary but may + * be placed anywhere in flash memory. If desired the .nvs section can be set + * to a fixed address by changing the following in the gcc linker file: + * + * .nvs (FIXED_FLASH_ADDR) (NOLOAD) : AT (FIXED_FLASH_ADDR) { + * *(.nvs) + * } > REGION_TEXT + */ +__attribute__ ((section (".nvs"))) +static char flashBuf[REGIONSIZE]; + +#endif + +/* Allocate objects for NVS Internal Regions */ +NVSCC26XX_Object nvsCC26xxObjects[1]; + +/* Hardware attributes for NVS Internal Regions */ +const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { + { + .regionBase = (void *)flashBuf, + .regionSize = REGIONSIZE, + }, +}; + +#endif /* Board_EXCLUDE_NVS_INTERNAL_FLASH */ + +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH + +#define SPISECTORSIZE 0x1000 +#define SPIREGIONSIZE (SPISECTORSIZE * 32) +#define VERIFYBUFSIZE 64 + +static uint8_t verifyBuf[VERIFYBUFSIZE]; + +/* Allocate objects for NVS External Regions */ +NVSSPI25X_Object nvsSPI25XObjects[1]; + +/* Hardware attributes for NVS External Regions */ +const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { + { + .regionBaseOffset = 0, + .regionSize = SPIREGIONSIZE, + .sectorSize = SPISECTORSIZE, + .verifyBuf = verifyBuf, + .verifyBufSize = VERIFYBUFSIZE, + .spiHandle = NULL, + .spiIndex = 0, + .spiBitRate = 4000000, + .spiCsnGpioIndex = CC1352P_2_LAUNCHXL_GPIO_SPI_FLASH_CS, + }, +}; + +#endif /* Board_EXCLUDE_NVS_EXTERNAL_FLASH */ + +/* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ +const NVS_Config NVS_config[CC1352P_2_LAUNCHXL_NVSCOUNT] = { +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH + { + .fxnTablePtr = &NVSCC26XX_fxnTable, + .object = &nvsCC26xxObjects[0], + .hwAttrs = &nvsCC26xxHWAttrs[0], + }, +#endif +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH + { + .fxnTablePtr = &NVSSPI25X_fxnTable, + .object = &nvsSPI25XObjects[0], + .hwAttrs = &nvsSPI25XHWAttrs[0], + }, +#endif +}; + +const uint_least8_t NVS_count = CC1352P_2_LAUNCHXL_NVSCOUNT; + +/* + * =============================== PIN =============================== + */ +#include +#include + +const PIN_Config BoardGpioInitTable[] = { + + CC1352P_2_LAUNCHXL_PIN_RLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC1352P_2_LAUNCHXL_PIN_GLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC1352P_2_LAUNCHXL_PIN_BTN1 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC1352P_2_LAUNCHXL_PIN_BTN2 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC1352P_2_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ + CC1352P_2_LAUNCHXL_UART0_RX | PIN_INPUT_EN | PIN_PULLDOWN, /* UART RX via debugger back channel */ + CC1352P_2_LAUNCHXL_UART0_TX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* UART TX via debugger back channel */ + CC1352P_2_LAUNCHXL_SPI0_MOSI | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master out - slave in */ + CC1352P_2_LAUNCHXL_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master in - slave out */ + CC1352P_2_LAUNCHXL_SPI0_CLK | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI clock */ + CC1352P_2_LAUNCHXL_DIO28_RF_24GHZ | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Path disabled */ + CC1352P_2_LAUNCHXL_DIO29_RF_HIGH_PA | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Path disabled */ + CC1352P_2_LAUNCHXL_DIO30_RF_SUB1GHZ | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Path disabled */ + PIN_TERMINATE +}; + +const PINCC26XX_HWAttrs PINCC26XX_hwAttrs = { + .intPriority = ~0, + .swiPriority = 0 +}; + +/* + * =============================== Power =============================== + */ +#include +#include + +const PowerCC26X2_Config PowerCC26X2_config = { + .policyInitFxn = NULL, + .policyFxn = &PowerCC26XX_standbyPolicy, + .calibrateFxn = &PowerCC26XX_calibrate, + .enablePolicy = true, + .calibrateRCOSC_LF = true, + .calibrateRCOSC_HF = true, +}; + +/* + * =============================== PWM =============================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +#include +#include + +PWMTimerCC26XX_Object pwmtimerCC26xxObjects[CC1352P_2_LAUNCHXL_PWMCOUNT]; + +const PWMTimerCC26XX_HwAttrs pwmtimerCC26xxHWAttrs[CC1352P_2_LAUNCHXL_PWMCOUNT] = { + { .pwmPin = CC1352P_2_LAUNCHXL_PWMPIN0, .gpTimerUnit = CC1352P_2_LAUNCHXL_GPTIMER0A }, + { .pwmPin = CC1352P_2_LAUNCHXL_PWMPIN1, .gpTimerUnit = CC1352P_2_LAUNCHXL_GPTIMER0B }, + { .pwmPin = CC1352P_2_LAUNCHXL_PWMPIN2, .gpTimerUnit = CC1352P_2_LAUNCHXL_GPTIMER1A }, + { .pwmPin = CC1352P_2_LAUNCHXL_PWMPIN3, .gpTimerUnit = CC1352P_2_LAUNCHXL_GPTIMER1B }, + { .pwmPin = CC1352P_2_LAUNCHXL_PWMPIN4, .gpTimerUnit = CC1352P_2_LAUNCHXL_GPTIMER2A }, + { .pwmPin = CC1352P_2_LAUNCHXL_PWMPIN5, .gpTimerUnit = CC1352P_2_LAUNCHXL_GPTIMER2B }, + { .pwmPin = CC1352P_2_LAUNCHXL_PWMPIN6, .gpTimerUnit = CC1352P_2_LAUNCHXL_GPTIMER3A }, + { .pwmPin = CC1352P_2_LAUNCHXL_PWMPIN7, .gpTimerUnit = CC1352P_2_LAUNCHXL_GPTIMER3B }, +}; + +const PWM_Config PWM_config[CC1352P_2_LAUNCHXL_PWMCOUNT] = { + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352P_2_LAUNCHXL_PWM0], &pwmtimerCC26xxHWAttrs[CC1352P_2_LAUNCHXL_PWM0] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352P_2_LAUNCHXL_PWM1], &pwmtimerCC26xxHWAttrs[CC1352P_2_LAUNCHXL_PWM1] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352P_2_LAUNCHXL_PWM2], &pwmtimerCC26xxHWAttrs[CC1352P_2_LAUNCHXL_PWM2] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352P_2_LAUNCHXL_PWM3], &pwmtimerCC26xxHWAttrs[CC1352P_2_LAUNCHXL_PWM3] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352P_2_LAUNCHXL_PWM4], &pwmtimerCC26xxHWAttrs[CC1352P_2_LAUNCHXL_PWM4] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352P_2_LAUNCHXL_PWM5], &pwmtimerCC26xxHWAttrs[CC1352P_2_LAUNCHXL_PWM5] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352P_2_LAUNCHXL_PWM6], &pwmtimerCC26xxHWAttrs[CC1352P_2_LAUNCHXL_PWM6] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352P_2_LAUNCHXL_PWM7], &pwmtimerCC26xxHWAttrs[CC1352P_2_LAUNCHXL_PWM7] }, +}; + +const uint_least8_t PWM_count = CC1352P_2_LAUNCHXL_PWMCOUNT; + +/* + * =============================== RF Driver =============================== + */ +#include + +/* + * Board-specific callback function to set the correct antenna path. + * + * This function is called by the RF driver on global driver events. + * It contains a default implementation to set the correct antenna path. + * This function is defined in the file CC1352P_2_LAUNCHXL_fxns.c + */ +extern void rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void* arg); + +const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { + .hwiPriority = ~0, /* Lowest HWI priority */ + .swiPriority = 0, /* Lowest SWI priority */ + .xoscHfAlwaysNeeded = true, /* Keep XOSC dependency while in stanby */ + + /* Register the board specific callback */ + .globalCallback = &rfDriverCallback, + + /* Subscribe the callback to both events */ + .globalEventMask = RF_GlobalEventRadioSetup | RF_GlobalEventRadioPowerDown +}; + +/* + * =============================== SD =============================== + */ +#include +#include + +SDSPI_Object sdspiObjects[CC1352P_2_LAUNCHXL_SDCOUNT]; + +const SDSPI_HWAttrs sdspiHWAttrs[CC1352P_2_LAUNCHXL_SDCOUNT] = { + { + .spiIndex = CC1352P_2_LAUNCHXL_SPI0, + .spiCsGpioIndex = CC1352P_2_LAUNCHXL_GPIO_DIO_19 + } +}; + +const SD_Config SD_config[CC1352P_2_LAUNCHXL_SDCOUNT] = { + { + .fxnTablePtr = &SDSPI_fxnTable, + .object = &sdspiObjects[CC1352P_2_LAUNCHXL_SDSPI0], + .hwAttrs = &sdspiHWAttrs[CC1352P_2_LAUNCHXL_SDSPI0] + }, +}; + +const uint_least8_t SD_count = CC1352P_2_LAUNCHXL_SDCOUNT; + +/* + * =============================== SPI DMA =============================== + */ +#include +#include + +SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1352P_2_LAUNCHXL_SPICOUNT]; + +/* + * NOTE: The SPI instances below can be used by the SD driver to communicate + * with a SD card via SPI. The 'defaultTxBufValue' fields below are set to 0xFF + * to satisfy the SDSPI driver requirement. + */ +const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1352P_2_LAUNCHXL_SPICOUNT] = { + { + .baseAddr = SSI0_BASE, + .intNum = INT_SSI0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .powerMngrId = PowerCC26XX_PERIPH_SSI0, + .defaultTxBufValue = 0xFF, + .rxChannelBitMask = 1< +#include + +UARTCC26XX_Object uartCC26XXObjects[CC1352P_2_LAUNCHXL_UARTCOUNT]; + +uint8_t uartCC26XXRingBuffer[CC1352P_2_LAUNCHXL_UARTCOUNT][32]; + +const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1352P_2_LAUNCHXL_UARTCOUNT] = { + { + .baseAddr = UART0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UART0, + .intNum = INT_UART0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .txPin = CC1352P_2_LAUNCHXL_UART0_TX, + .rxPin = CC1352P_2_LAUNCHXL_UART0_RX, + .ctsPin = PIN_UNASSIGNED, + .rtsPin = PIN_UNASSIGNED, + .ringBufPtr = uartCC26XXRingBuffer[CC1352P_2_LAUNCHXL_UART0], + .ringBufSize = sizeof(uartCC26XXRingBuffer[CC1352P_2_LAUNCHXL_UART0]), + .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, + .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, + .errorFxn = NULL + }, + { + .baseAddr = UART1_BASE, + .powerMngrId = PowerCC26X2_PERIPH_UART1, + .intNum = INT_UART1_COMB, + .intPriority = ~0, + .swiPriority = 0, + .txPin = CC1352P_2_LAUNCHXL_UART1_TX, + .rxPin = CC1352P_2_LAUNCHXL_UART1_RX, + .ctsPin = PIN_UNASSIGNED, + .rtsPin = PIN_UNASSIGNED, + .ringBufPtr = uartCC26XXRingBuffer[CC1352P_2_LAUNCHXL_UART1], + .ringBufSize = sizeof(uartCC26XXRingBuffer[CC1352P_2_LAUNCHXL_UART1]), + .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, + .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, + .errorFxn = NULL + } +}; + +const UART_Config UART_config[CC1352P_2_LAUNCHXL_UARTCOUNT] = { + { + .fxnTablePtr = &UARTCC26XX_fxnTable, + .object = &uartCC26XXObjects[CC1352P_2_LAUNCHXL_UART0], + .hwAttrs = &uartCC26XXHWAttrs[CC1352P_2_LAUNCHXL_UART0] + }, + { + .fxnTablePtr = &UARTCC26XX_fxnTable, + .object = &uartCC26XXObjects[CC1352P_2_LAUNCHXL_UART1], + .hwAttrs = &uartCC26XXHWAttrs[CC1352P_2_LAUNCHXL_UART1] + }, +}; + +const uint_least8_t UART_count = CC1352P_2_LAUNCHXL_UARTCOUNT; + +/* + * =============================== UDMA =============================== + */ +#include + +UDMACC26XX_Object udmaObjects[CC1352P_2_LAUNCHXL_UDMACOUNT]; + +const UDMACC26XX_HWAttrs udmaHWAttrs[CC1352P_2_LAUNCHXL_UDMACOUNT] = { + { + .baseAddr = UDMA0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UDMA, + .intNum = INT_DMA_ERR, + .intPriority = ~0 + } +}; + +const UDMACC26XX_Config UDMACC26XX_config[CC1352P_2_LAUNCHXL_UDMACOUNT] = { + { + .object = &udmaObjects[CC1352P_2_LAUNCHXL_UDMA0], + .hwAttrs = &udmaHWAttrs[CC1352P_2_LAUNCHXL_UDMA0] + }, +}; + + + +/* + * =============================== Watchdog =============================== + */ +#include +#include + +WatchdogCC26XX_Object watchdogCC26XXObjects[CC1352P_2_LAUNCHXL_WATCHDOGCOUNT]; + +const WatchdogCC26XX_HWAttrs watchdogCC26XXHWAttrs[CC1352P_2_LAUNCHXL_WATCHDOGCOUNT] = { + { + .baseAddr = WDT_BASE, + .reloadValue = 1000 /* Reload value in milliseconds */ + }, +}; + +const Watchdog_Config Watchdog_config[CC1352P_2_LAUNCHXL_WATCHDOGCOUNT] = { + { + .fxnTablePtr = &WatchdogCC26XX_fxnTable, + .object = &watchdogCC26XXObjects[CC1352P_2_LAUNCHXL_WATCHDOG0], + .hwAttrs = &watchdogCC26XXHWAttrs[CC1352P_2_LAUNCHXL_WATCHDOG0] + }, +}; + +const uint_least8_t Watchdog_count = CC1352P_2_LAUNCHXL_WATCHDOGCOUNT; + +/* + * Board-specific initialization function to disable external flash. + * This function is defined in the file CC1352P_2_LAUNCHXL_fxns.c + */ +extern void Board_initHook(void); + +/* + * ======== CC1352P_2_LAUNCHXL_initGeneral ======== + */ +void CC1352P_2_LAUNCHXL_initGeneral(void) +{ + Power_init(); + + if (PIN_init(BoardGpioInitTable) != PIN_SUCCESS) { + /* Error with PIN_init */ + while (1); + } + + /* Perform board-specific initialization */ + Board_initHook(); +} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/CC1352P_2_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/CC1352P_2_LAUNCHXL.h new file mode 100644 index 000000000..443f9badb --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/CC1352P_2_LAUNCHXL.h @@ -0,0 +1,435 @@ +/* + * Copyright (c) 2017-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ +/** =========================================================================== + * @file CC1352P_2_LAUNCHXL.h + * + * @brief CC1352P_2_LAUNCHXL Board Specific header file. + * + * The CC1352P_2_LAUNCHXL header file should be included in an application as + * follows: + * @code + * #include "CC1352P_2_LAUNCHXL.h" + * @endcode + * + * =========================================================================== + */ +#ifndef __CC1352P_2_LAUNCHXL_BOARD_H__ +#define __CC1352P_2_LAUNCHXL_BOARD_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes */ +#include +#include + +/* Externs */ +extern const PIN_Config BoardGpioInitTable[]; + +/* Defines */ +#define CC1352P_2_LAUNCHXL + +/* Mapping of pins to board signals using general board aliases + * + */ + +/* Mapping of pins to board signals using general board aliases + * + */ +/* Analog Capable DIOs */ +#define CC1352P_2_LAUNCHXL_DIO23_ANALOG IOID_23 +#define CC1352P_2_LAUNCHXL_DIO24_ANALOG IOID_24 +#define CC1352P_2_LAUNCHXL_DIO25_ANALOG IOID_25 +#define CC1352P_2_LAUNCHXL_DIO26_ANALOG IOID_26 +#define CC1352P_2_LAUNCHXL_DIO27_ANALOG IOID_27 + +/* RF Antenna Switch */ +#define CC1352P_2_LAUNCHXL_DIO28_RF_24GHZ IOID_28 +#define CC1352P_2_LAUNCHXL_DIO29_RF_HIGH_PA IOID_29 +#define CC1352P_2_LAUNCHXL_DIO30_RF_SUB1GHZ IOID_30 + +/* Digital IOs */ +#define CC1352P_2_LAUNCHXL_DIO12 IOID_12 +#define CC1352P_2_LAUNCHXL_DIO15 IOID_15 +#define CC1352P_2_LAUNCHXL_DIO16_TDO IOID_16 +#define CC1352P_2_LAUNCHXL_DIO17_TDI IOID_17 +#define CC1352P_2_LAUNCHXL_DIO21 IOID_21 +#define CC1352P_2_LAUNCHXL_DIO22 IOID_22 + +/* Discrete Inputs */ +#define CC1352P_2_LAUNCHXL_PIN_BTN1 IOID_15 +#define CC1352P_2_LAUNCHXL_PIN_BTN2 IOID_14 + +/* GPIO */ +#define CC1352P_2_LAUNCHXL_GPIO_LED_ON 1 +#define CC1352P_2_LAUNCHXL_GPIO_LED_OFF 0 + +/* I2C */ +#define CC1352P_2_LAUNCHXL_I2C0_SCL0 IOID_22 +#define CC1352P_2_LAUNCHXL_I2C0_SDA0 IOID_5 + +/* LEDs */ +#define CC1352P_2_LAUNCHXL_PIN_LED_ON 1 +#define CC1352P_2_LAUNCHXL_PIN_LED_OFF 0 +#define CC1352P_2_LAUNCHXL_PIN_RLED IOID_6 +#define CC1352P_2_LAUNCHXL_PIN_GLED IOID_7 + +/* PWM Outputs */ +#define CC1352P_2_LAUNCHXL_PWMPIN0 CC1352P_2_LAUNCHXL_PIN_RLED +#define CC1352P_2_LAUNCHXL_PWMPIN1 CC1352P_2_LAUNCHXL_PIN_GLED +#define CC1352P_2_LAUNCHXL_PWMPIN2 PIN_UNASSIGNED +#define CC1352P_2_LAUNCHXL_PWMPIN3 PIN_UNASSIGNED +#define CC1352P_2_LAUNCHXL_PWMPIN4 PIN_UNASSIGNED +#define CC1352P_2_LAUNCHXL_PWMPIN5 PIN_UNASSIGNED +#define CC1352P_2_LAUNCHXL_PWMPIN6 PIN_UNASSIGNED +#define CC1352P_2_LAUNCHXL_PWMPIN7 PIN_UNASSIGNED + +/* SPI */ +#define CC1352P_2_LAUNCHXL_SPI_FLASH_CS IOID_20 +#define CC1352P_2_LAUNCHXL_FLASH_CS_ON 0 +#define CC1352P_2_LAUNCHXL_FLASH_CS_OFF 1 + +/* SPI Board */ +#define CC1352P_2_LAUNCHXL_SPI0_MISO IOID_8 /* RF1.20 */ +#define CC1352P_2_LAUNCHXL_SPI0_MOSI IOID_9 /* RF1.18 */ +#define CC1352P_2_LAUNCHXL_SPI0_CLK IOID_10 /* RF1.16 */ +#define CC1352P_2_LAUNCHXL_SPI0_CSN PIN_UNASSIGNED +#define CC1352P_2_LAUNCHXL_SPI1_MISO PIN_UNASSIGNED +#define CC1352P_2_LAUNCHXL_SPI1_MOSI PIN_UNASSIGNED +#define CC1352P_2_LAUNCHXL_SPI1_CLK PIN_UNASSIGNED +#define CC1352P_2_LAUNCHXL_SPI1_CSN PIN_UNASSIGNED + +/* UART Board */ +#define CC1352P_2_LAUNCHXL_UART0_RX IOID_12 /* RXD */ +#define CC1352P_2_LAUNCHXL_UART0_TX IOID_13 /* TXD */ +#define CC1352P_2_LAUNCHXL_UART0_CTS IOID_19 /* CTS */ +#define CC1352P_2_LAUNCHXL_UART0_RTS IOID_18 /* RTS */ +#define CC1352P_2_LAUNCHXL_UART1_RX PIN_UNASSIGNED +#define CC1352P_2_LAUNCHXL_UART1_TX PIN_UNASSIGNED +#define CC1352P_2_LAUNCHXL_UART1_CTS PIN_UNASSIGNED +#define CC1352P_2_LAUNCHXL_UART1_RTS PIN_UNASSIGNED +/* For backward compatibility */ +#define CC1352P_2_LAUNCHXL_UART_RX CC1352P_2_LAUNCHXL_UART0_RX +#define CC1352P_2_LAUNCHXL_UART_TX CC1352P_2_LAUNCHXL_UART0_TX +#define CC1352P_2_LAUNCHXL_UART_CTS CC1352P_2_LAUNCHXL_UART0_CTS +#define CC1352P_2_LAUNCHXL_UART_RTS CC1352P_2_LAUNCHXL_UART0_RTS + +/*! + * @brief Initialize the general board specific settings + * + * This function initializes the general board specific settings. + */ +void CC1352P_2_LAUNCHXL_initGeneral(void); + +/*! + * @brief Shut down the external flash present on the board files + * + * This function bitbangs the SPI sequence necessary to turn off + * the external flash on LaunchPads. + */ +void CC1352P_2_LAUNCHXL_shutDownExtFlash(void); + +/*! + * @brief Wake up the external flash present on the board files + * + * This function toggles the chip select for the amount of time needed + * to wake the chip up. + */ +void CC1352P_2_LAUNCHXL_wakeUpExtFlash(void); + + +/*! + * \brief Initializes the antenna switch IOs. + * + * This function sets up the antenna switch and occupies + * the necessary IO pins. After calling this function, they + * cannot be used in the application anymore. + */ +void CC1352P_2_LAUNCHXL_initAntennaSwitch(void); + +/*! + * @def CC1352P_2_LAUNCHXL_ADCBufName + * @brief Enum of ADCs + */ +typedef enum CC1352P_2_LAUNCHXL_ADCBufName { + CC1352P_2_LAUNCHXL_ADCBUF0 = 0, + + CC1352P_2_LAUNCHXL_ADCBUFCOUNT +} CC1352P_2_LAUNCHXL_ADCBufName; + +/*! + * @def CC1352P_2_LAUNCHXL_ADCBuf0SourceName + * @brief Enum of ADCBuf channels + */ +typedef enum CC1352P_2_LAUNCHXL_ADCBuf0ChannelName { + CC1352P_2_LAUNCHXL_ADCBUF0CHANNEL0 = 0, + CC1352P_2_LAUNCHXL_ADCBUF0CHANNEL1, + CC1352P_2_LAUNCHXL_ADCBUF0CHANNEL2, + CC1352P_2_LAUNCHXL_ADCBUF0CHANNEL3, + CC1352P_2_LAUNCHXL_ADCBUF0CHANNEL4, + CC1352P_2_LAUNCHXL_ADCBUF0CHANNEL5, + CC1352P_2_LAUNCHXL_ADCBUF0CHANNEL6, + CC1352P_2_LAUNCHXL_ADCBUF0CHANNELVDDS, + CC1352P_2_LAUNCHXL_ADCBUF0CHANNELDCOUPL, + CC1352P_2_LAUNCHXL_ADCBUF0CHANNELVSS, + + CC1352P_2_LAUNCHXL_ADCBUF0CHANNELCOUNT +} CC1352P_2_LAUNCHXL_ADCBuf0ChannelName; + +/*! + * @def CC1352P_2_LAUNCHXL_ADCName + * @brief Enum of ADCs + */ +typedef enum CC1352P_2_LAUNCHXL_ADCName { + CC1352P_2_LAUNCHXL_ADC0 = 0, + CC1352P_2_LAUNCHXL_ADC1, + CC1352P_2_LAUNCHXL_ADC2, + CC1352P_2_LAUNCHXL_ADC3, + CC1352P_2_LAUNCHXL_ADC4, + CC1352P_2_LAUNCHXL_ADC5, + CC1352P_2_LAUNCHXL_ADC6, + CC1352P_2_LAUNCHXL_ADCDCOUPL, + CC1352P_2_LAUNCHXL_ADCVSS, + CC1352P_2_LAUNCHXL_ADCVDDS, + + CC1352P_2_LAUNCHXL_ADCCOUNT +} CC1352P_2_LAUNCHXL_ADCName; + +/*! + * @def CC1352P_2_LAUNCHXL_ECDHName + * @brief Enum of ECDH names + */ +typedef enum CC1352P_2_LAUNCHXL_ECDHName { + CC1352P_2_LAUNCHXL_ECDH0 = 0, + + CC1352P_2_LAUNCHXL_ECDHCOUNT +} CC1352P_2_LAUNCHXL_ECDHName; + +/*! + * @def CC1352P_2_LAUNCHXL_ECDSAName + * @brief Enum of ECDSA names + */ +typedef enum CC1352P_2_LAUNCHXL_ECDSAName { + CC1352P_2_LAUNCHXL_ECDSA0 = 0, + + CC1352P_2_LAUNCHXL_ECDSACOUNT +} CC1352P_2_LAUNCHXL_ECDSAName; + +/*! + * @def CC1352P_2_LAUNCHXL_ECJPAKEName + * @brief Enum of ECJPAKE names + */ +typedef enum CC1352P_2_LAUNCHXL_ECJPAKEName { + CC1352P_2_LAUNCHXL_ECJPAKE0 = 0, + + CC1352P_2_LAUNCHXL_ECJPAKECOUNT +} CC1352P_2_LAUNCHXL_ECJPAKEName; + +/*! + * @def CC1352P_2_LAUNCHXL_AESCCMName + * @brief Enum of AESCCM names + */ +typedef enum CC1352P_2_LAUNCHXL_AESCCMName { + CC1352P_2_LAUNCHXL_AESCCM0 = 0, + + CC1352P_2_LAUNCHXL_AESCCMCOUNT +} CC1352P_2_LAUNCHXL_AESCCMName; + +/*! + * @def CC1352P_2_LAUNCHXL_AESECBName + * @brief Enum of AESECB names + */ +typedef enum CC1352P_2_LAUNCHXL_AESECBName { + CC1352P_2_LAUNCHXL_AESECB0 = 0, + + CC1352P_2_LAUNCHXL_AESECBCOUNT +} CC1352P_2_LAUNCHXL_AESECBName; + +/*! + * @def CC1352P_2_LAUNCHXL_SHA2Name + * @brief Enum of SHA2 names + */ +typedef enum CC1352P_2_LAUNCHXL_SHA2Name { + CC1352P_2_LAUNCHXL_SHA20 = 0, + + CC1352P_2_LAUNCHXL_SHA2COUNT +} CC1352P_2_LAUNCHXL_SHA2Name; + +/*! + * @def CC1352P_2_LAUNCHXL_GPIOName + * @brief Enum of GPIO names + */ +typedef enum CC1352P_2_LAUNCHXL_GPIOName { + CC1352P_2_LAUNCHXL_GPIO_S1 = 0, + CC1352P_2_LAUNCHXL_GPIO_S2, + CC1352P_2_LAUNCHXL_SPI_MASTER_READY, + CC1352P_2_LAUNCHXL_SPI_SLAVE_READY, + CC1352P_2_LAUNCHXL_GPIO_LED_GREEN, + CC1352P_2_LAUNCHXL_GPIO_LED_RED, + CC1352P_2_LAUNCHXL_GPIO_SPI_FLASH_CS, + CC1352P_2_LAUNCHXL_GPIO_DIO_19, + CC1352P_2_LAUNCHXL_GPIO_LCD_CS, + CC1352P_2_LAUNCHXL_GPIO_LCD_ENABLE, + CC1352P_2_LAUNCHXL_GPIOCOUNT +} CC1352P_2_LAUNCHXL_GPIOName; + +/*! + * @def CC1352P_2_LAUNCHXL_GPTimerName + * @brief Enum of GPTimer parts + */ +typedef enum CC1352P_2_LAUNCHXL_GPTimerName { + CC1352P_2_LAUNCHXL_GPTIMER0A = 0, + CC1352P_2_LAUNCHXL_GPTIMER0B, + CC1352P_2_LAUNCHXL_GPTIMER1A, + CC1352P_2_LAUNCHXL_GPTIMER1B, + CC1352P_2_LAUNCHXL_GPTIMER2A, + CC1352P_2_LAUNCHXL_GPTIMER2B, + CC1352P_2_LAUNCHXL_GPTIMER3A, + CC1352P_2_LAUNCHXL_GPTIMER3B, + + CC1352P_2_LAUNCHXL_GPTIMERPARTSCOUNT +} CC1352P_2_LAUNCHXL_GPTimerName; + +/*! + * @def CC1352P_2_LAUNCHXL_GPTimers + * @brief Enum of GPTimers + */ +typedef enum CC1352P_2_LAUNCHXL_GPTimers { + CC1352P_2_LAUNCHXL_GPTIMER0 = 0, + CC1352P_2_LAUNCHXL_GPTIMER1, + CC1352P_2_LAUNCHXL_GPTIMER2, + CC1352P_2_LAUNCHXL_GPTIMER3, + + CC1352P_2_LAUNCHXL_GPTIMERCOUNT +} CC1352P_2_LAUNCHXL_GPTimers; + +/*! + * @def CC1352P_2_LAUNCHXL_I2CName + * @brief Enum of I2C names + */ +typedef enum CC1352P_2_LAUNCHXL_I2CName { + CC1352P_2_LAUNCHXL_I2C0 = 0, + + CC1352P_2_LAUNCHXL_I2CCOUNT +} CC1352P_2_LAUNCHXL_I2CName; + +/*! + * @def CC1352P_2_LAUNCHXL_NVSName + * @brief Enum of NVS names + */ +typedef enum CC1352P_2_LAUNCHXL_NVSName { +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH + CC1352P_2_LAUNCHXL_NVSCC26XX0 = 0, +#endif +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH + CC1352P_2_LAUNCHXL_NVSSPI25X0, +#endif + + CC1352P_2_LAUNCHXL_NVSCOUNT +} CC1352P_2_LAUNCHXL_NVSName; + +/*! + * @def CC1352P_2_LAUNCHXL_PWM + * @brief Enum of PWM outputs + */ +typedef enum CC1352P_2_LAUNCHXL_PWMName { + CC1352P_2_LAUNCHXL_PWM0 = 0, + CC1352P_2_LAUNCHXL_PWM1, + CC1352P_2_LAUNCHXL_PWM2, + CC1352P_2_LAUNCHXL_PWM3, + CC1352P_2_LAUNCHXL_PWM4, + CC1352P_2_LAUNCHXL_PWM5, + CC1352P_2_LAUNCHXL_PWM6, + CC1352P_2_LAUNCHXL_PWM7, + + CC1352P_2_LAUNCHXL_PWMCOUNT +} CC1352P_2_LAUNCHXL_PWMName; + +/*! + * @def CC1352P_2_LAUNCHXL_SDName + * @brief Enum of SD names + */ +typedef enum CC1352P_2_LAUNCHXL_SDName { + CC1352P_2_LAUNCHXL_SDSPI0 = 0, + + CC1352P_2_LAUNCHXL_SDCOUNT +} CC1352P_2_LAUNCHXL_SDName; + +/*! + * @def CC1352P_2_LAUNCHXL_SPIName + * @brief Enum of SPI names + */ +typedef enum CC1352P_2_LAUNCHXL_SPIName { + CC1352P_2_LAUNCHXL_SPI0 = 0, + CC1352P_2_LAUNCHXL_SPI1, + + CC1352P_2_LAUNCHXL_SPICOUNT +} CC1352P_2_LAUNCHXL_SPIName; + +/*! + * @def CC1352P_2_LAUNCHXL_UARTName + * @brief Enum of UARTs + */ +typedef enum CC1352P_2_LAUNCHXL_UARTName { + CC1352P_2_LAUNCHXL_UART0 = 0, + CC1352P_2_LAUNCHXL_UART1, + + CC1352P_2_LAUNCHXL_UARTCOUNT +} CC1352P_2_LAUNCHXL_UARTName; + +/*! + * @def CC1352P_2_LAUNCHXL_UDMAName + * @brief Enum of DMA buffers + */ +typedef enum CC1352P_2_LAUNCHXL_UDMAName { + CC1352P_2_LAUNCHXL_UDMA0 = 0, + + CC1352P_2_LAUNCHXL_UDMACOUNT +} CC1352P_2_LAUNCHXL_UDMAName; + +/*! + * @def CC1352P_2_LAUNCHXL_WatchdogName + * @brief Enum of Watchdogs + */ +typedef enum CC1352P_2_LAUNCHXL_WatchdogName { + CC1352P_2_LAUNCHXL_WATCHDOG0 = 0, + + CC1352P_2_LAUNCHXL_WATCHDOGCOUNT +} CC1352P_2_LAUNCHXL_WatchdogName; + + +#ifdef __cplusplus +} +#endif + +#endif /* __CC1352P_2_LAUNCHXL_BOARD_H__ */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/CC1352P_2_LAUNCHXL_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/CC1352P_2_LAUNCHXL_fxns.c new file mode 100644 index 000000000..b346056a3 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/CC1352P_2_LAUNCHXL_fxns.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +/* + * ======== CC1352P_2_LAUNCHXL_fxns.c ======== + * This file contains the board-specific initialization functions, and + * RF callback function for antenna switching. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "Board.h" + +/* + * ======== CC1352P_2_LAUNCHXL_sendExtFlashByte ======== + */ +void CC1352P_2_LAUNCHXL_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) +{ + uint8_t i; + + /* SPI Flash CS */ + PIN_setOutputValue(pinHandle, IOID_20, 0); + + for (i = 0; i < 8; i++) { + PIN_setOutputValue(pinHandle, IOID_10, 0); /* SPI Flash CLK */ + + /* SPI Flash MOSI */ + PIN_setOutputValue(pinHandle, IOID_9, (byte >> (7 - i)) & 0x01); + PIN_setOutputValue(pinHandle, IOID_10, 1); /* SPI Flash CLK */ + + /* + * Waste a few cycles to keep the CLK high for at + * least 45% of the period. + * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. + */ + CPUdelay(8); + } + + PIN_setOutputValue(pinHandle, IOID_10, 0); /* CLK */ + PIN_setOutputValue(pinHandle, IOID_20, 1); /* CS */ + + /* + * Keep CS high at least 40 us + * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us + */ + CPUdelay(700); +} + +/* + * ======== CC1352P_2_LAUNCHXL_wakeUpExtFlash ======== + */ +void CC1352P_2_LAUNCHXL_wakeUpExtFlash(void) +{ + PIN_Config extFlashPinTable[] = { + /* SPI Flash CS */ + IOID_20 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + /* + * To wake up we need to toggle the chip select at + * least 20 ns and ten wait at least 35 us. + */ + + /* Toggle chip select for ~20ns to wake ext. flash */ + PIN_setOutputValue(extFlashPinHandle, IOID_20, 0); + /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ + CPUdelay(1); + PIN_setOutputValue(extFlashPinHandle, IOID_20, 1); + /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ + CPUdelay(560); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC1352P_2_LAUNCHXL_shutDownExtFlash ======== + */ +void CC1352P_2_LAUNCHXL_shutDownExtFlash(void) +{ + /* To be sure we are putting the flash into sleep and not waking it, we first have to make a wake up call */ + CC1352P_2_LAUNCHXL_wakeUpExtFlash(); + + PIN_Config extFlashPinTable[] = { + /* SPI Flash CS*/ + IOID_20 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash CLK */ + IOID_10 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash MOSI */ + IOID_9 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash MISO */ + IOID_8 | PIN_INPUT_EN | PIN_PULLDOWN, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + uint8_t extFlashShutdown = 0xB9; + + CC1352P_2_LAUNCHXL_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); + + PIN_close(extFlashPinHandle); +} + +/* + * For the SysConfig generated Board.h file, Board_RF_SUB1GHZ will not be + * defined unless the RF module is added to the configuration. Therefore, + * we don't include this code if Board_RF_SUB1GHZ is not defined. + */ +#if defined(Board_RF_SUB1GHZ) + +/* + * ======== Antenna switching ======== + */ +static PIN_Handle antennaPins; +static PIN_State antennaState; + +void initAntennaSwitch() +{ + PIN_Config antennaConfig[] = { + Board_RF_24GHZ | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Path disabled */ + Board_RF_HIGH_PA | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Path disabled */ + Board_RF_SUB1GHZ | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Path disabled */ + PIN_TERMINATE + }; + antennaPins = PIN_open(&antennaState, antennaConfig); +} + +/* + * ======== rfDriverCallback ======== + * Sets up the antenna switch depending on the current PHY configuration. + * Truth table: + * + * Path DIO28 DIO29 DIO30 + * =========== ===== ===== ===== + * Off 0 0 0 + * Sub-1 GHz 0 0 1 + * 2.4 GHz 1 0 0 + * 20 dBm TX 0 1 0 + */ +void rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void *arg) +{ + /* Switch off all paths first. Needs to be done anyway in every sub-case below. */ + PINCC26XX_setOutputValue(Board_RF_24GHZ, 0); + PINCC26XX_setOutputValue(Board_RF_HIGH_PA, 0); + PINCC26XX_setOutputValue(Board_RF_SUB1GHZ, 0); + + if (events & RF_GlobalEventRadioSetup) { + /* Decode the current PA configuration. */ + RF_TxPowerTable_PAType paType = (RF_TxPowerTable_PAType)RF_getTxPower(client).paType; + + /* Decode the generic argument as a setup command. */ + RF_RadioSetup* setupCommand = (RF_RadioSetup*)arg; + + if (setupCommand->common.commandNo == CMD_PROP_RADIO_DIV_SETUP) { + /* Sub-1 GHz */ + if (paType == RF_TxPowerTable_HighPA) { + /* PA enable --> HIGH PA + * LNA enable --> Sub-1 GHz + */ + PINCC26XX_setMux(antennaPins, Board_RF_24GHZ, PINCC26XX_MUX_GPIO); + // Note: RFC_GPO3 is a work-around because the RFC_GPO1 (PA enable signal) is sometimes not + // de-asserted on CC1352 Rev A. + PINCC26XX_setMux(antennaPins, Board_RF_HIGH_PA, PINCC26XX_MUX_RFC_GPO3); + PINCC26XX_setMux(antennaPins, Board_RF_SUB1GHZ, PINCC26XX_MUX_RFC_GPO0); + } else { + /* RF core active --> Sub-1 GHz */ + PINCC26XX_setMux(antennaPins, Board_RF_24GHZ, PINCC26XX_MUX_GPIO); + PINCC26XX_setMux(antennaPins, Board_RF_HIGH_PA, PINCC26XX_MUX_GPIO); + PINCC26XX_setMux(antennaPins, Board_RF_SUB1GHZ, PINCC26XX_MUX_GPIO); + PINCC26XX_setOutputValue(Board_RF_SUB1GHZ, 1); + } + } else { + /* 2.4 GHz */ + if (paType == RF_TxPowerTable_HighPA) + { + /* PA enable --> HIGH PA + * LNA enable --> 2.4 GHz + */ + PINCC26XX_setMux(antennaPins, Board_RF_24GHZ, PINCC26XX_MUX_RFC_GPO0); + // Note: RFC_GPO3 is a work-around because the RFC_GPO1 (PA enable signal) is sometimes not + // de-asserted on CC1352 Rev A. + PINCC26XX_setMux(antennaPins, Board_RF_HIGH_PA, PINCC26XX_MUX_RFC_GPO3); + PINCC26XX_setMux(antennaPins, Board_RF_SUB1GHZ, PINCC26XX_MUX_GPIO); + } else { + /* RF core active --> 2.4 GHz */ + PINCC26XX_setMux(antennaPins, Board_RF_24GHZ, PINCC26XX_MUX_GPIO); + PINCC26XX_setMux(antennaPins, Board_RF_HIGH_PA, PINCC26XX_MUX_GPIO); + PINCC26XX_setMux(antennaPins, Board_RF_SUB1GHZ, PINCC26XX_MUX_GPIO); + PINCC26XX_setOutputValue(Board_RF_24GHZ, 1); + } + } + } else { + /* Reset the IO multiplexer to GPIO functionality */ + PINCC26XX_setMux(antennaPins, Board_RF_24GHZ, PINCC26XX_MUX_GPIO); + PINCC26XX_setMux(antennaPins, Board_RF_HIGH_PA, PINCC26XX_MUX_GPIO); + PINCC26XX_setMux(antennaPins, Board_RF_SUB1GHZ, PINCC26XX_MUX_GPIO); + } +} +#endif + +/* + * ======== Board_initHook ======== + * Called by Board_init() to perform board-specific initialization. + */ +void Board_initHook() +{ +#if defined(Board_RF_SUB1GHZ) + initAntennaSwitch(); +#endif + + CC1352P_2_LAUNCHXL_shutDownExtFlash(); +} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/Makefile.cc1352p_2 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/Makefile.cc1352p_2 new file mode 100644 index 000000000..3e7db941d --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/Makefile.cc1352p_2 @@ -0,0 +1,19 @@ +################################################################################ +# SimpleLink Device makefile + +SUBFAMILY = cc13x2-cc26x2 +DEVICE_FAMILY = CC13X2 +DEVICE_LINE = CC13XX + +BOARD_SOURCEFILES += CC1352P_2_LAUNCHXL.c CC1352P_2_LAUNCHXL_fxns.c + +SUPPORTS_PROP_MODE = 1 +SUPPORTS_IEEE_MODE = 1 + +SUPPORTS_HIGH_PA = 1 + +### Signal that we can be programmed with cc2538-bsl +BOARD_SUPPORTS_BSL = 0 + +# Include the common board makefile +include $(FAMILY_PATH)/launchpad/Makefile.launchpad diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/Board.h new file mode 100644 index 000000000..752f8d88f --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/Board.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2017-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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 __BOARD_H +#define __BOARD_H + +#define Board_CC1352P_4_LAUNCHXL + +#ifdef __cplusplus +extern "C" { +#endif + +#include "CC1352P_4_LAUNCHXL.h" + +#define Board_initGeneral() CC1352P_4_LAUNCHXL_initGeneral() +#define Board_shutDownExtFlash() CC1352P_4_LAUNCHXL_shutDownExtFlash() +#define Board_wakeUpExtFlash() CC1352P_4_LAUNCHXL_wakeUpExtFlash() + +/* These #defines allow us to reuse TI-RTOS across other device families */ + +#define Board_ADC0 CC1352P_4_LAUNCHXL_ADC0 +#define Board_ADC1 CC1352P_4_LAUNCHXL_ADC1 + +#define Board_ADCBUF0 CC1352P_4_LAUNCHXL_ADCBUF0 +#define Board_ADCBUF0CHANNEL0 CC1352P_4_LAUNCHXL_ADCBUF0CHANNEL0 +#define Board_ADCBUF0CHANNEL1 CC1352P_4_LAUNCHXL_ADCBUF0CHANNEL1 + +#define Board_CRYPTO0 CC1352P_4_LAUNCHXL_CRYPTO0 +#define Board_ECDH0 CC1352P_4_LAUNCHXL_ECDH0 +#define Board_ECDSA0 CC1352P_4_LAUNCHXL_ECDSA0 +#define Board_ECJPAKE0 CC1352P_4_LAUNCHXL_ECJPAKE0 +#define Board_AESCCM0 CC1352P_4_LAUNCHXL_AESCCM0 +#define Board_AESECB0 CC1352P_4_LAUNCHXL_AESECB0 +#define Board_SHA20 CC1352P_4_LAUNCHXL_SHA20 + +#define Board_DIO12 CC1352P_4_LAUNCHXL_DIO12 +#define Board_DIO15 CC1352P_4_LAUNCHXL_DIO15 +#define Board_DIO16_TDO CC1352P_4_LAUNCHXL_DIO16_TDO +#define Board_DIO17_TDI CC1352P_4_LAUNCHXL_DIO17_TDI +#define Board_DIO21 CC1352P_4_LAUNCHXL_DIO21 +#define Board_DIO22 CC1352P_4_LAUNCHXL_DIO22 + +#define Board_DIO23_ANALOG CC1352P_4_LAUNCHXL_DIO23_ANALOG +#define Board_DIO24_ANALOG CC1352P_4_LAUNCHXL_DIO24_ANALOG +#define Board_DIO25_ANALOG CC1352P_4_LAUNCHXL_DIO25_ANALOG +#define Board_DIO26_ANALOG CC1352P_4_LAUNCHXL_DIO26_ANALOG +#define Board_DIO27_ANALOG CC1352P_4_LAUNCHXL_DIO27_ANALOG +#define Board_DIO28_ANALOG CC1352P_4_LAUNCHXL_DIO28_ANALOG +#define Board_DIO29_ANALOG CC1352P_4_LAUNCHXL_DIO29_ANALOG +#define Board_DIO30_RFSW CC1352P_4_LAUNCHXL_DIO30_RF_SUB1GHZ + +/* + * Board_RF_SUB1GHZ, Board_RF_HIGH_PA, and Board_RF_24GHZ are the names + * generated by SysConfig. Define them here so that the RF callback function + * can reference them. + */ +#define Board_RF_24GHZ CC1352P_4_LAUNCHXL_DIO28_RF_24GHZ +#define Board_RF_HIGH_PA CC1352P_4_LAUNCHXL_DIO29_RF_HIGH_PA +#define Board_RF_SUB1GHZ CC1352P_4_LAUNCHXL_DIO30_RF_SUB1GHZ + +#define Board_GPIO_BUTTON0 CC1352P_4_LAUNCHXL_GPIO_S1 +#define Board_GPIO_BUTTON1 CC1352P_4_LAUNCHXL_GPIO_S2 +#define Board_GPIO_BTN1 CC1352P_4_LAUNCHXL_GPIO_S1 +#define Board_GPIO_BTN2 CC1352P_4_LAUNCHXL_GPIO_S2 +#define Board_GPIO_LED0 CC1352P_4_LAUNCHXL_GPIO_LED_RED +#define Board_GPIO_LED1 CC1352P_4_LAUNCHXL_GPIO_LED_GREEN +#define Board_GPIO_LED2 CC1352P_4_LAUNCHXL_GPIO_LED_RED +#define Board_GPIO_RLED CC1352P_4_LAUNCHXL_GPIO_LED_RED +#define Board_GPIO_GLED CC1352P_4_LAUNCHXL_GPIO_LED_GREEN +#define Board_GPIO_LED_ON CC1352P_4_LAUNCHXL_GPIO_LED_ON +#define Board_GPIO_LED_OFF CC1352P_4_LAUNCHXL_GPIO_LED_OFF + +#define Board_GPTIMER0A CC1352P_4_LAUNCHXL_GPTIMER0A +#define Board_GPTIMER0B CC1352P_4_LAUNCHXL_GPTIMER0B +#define Board_GPTIMER1A CC1352P_4_LAUNCHXL_GPTIMER1A +#define Board_GPTIMER1B CC1352P_4_LAUNCHXL_GPTIMER1B +#define Board_GPTIMER2A CC1352P_4_LAUNCHXL_GPTIMER2A +#define Board_GPTIMER2B CC1352P_4_LAUNCHXL_GPTIMER2B +#define Board_GPTIMER3A CC1352P_4_LAUNCHXL_GPTIMER3A +#define Board_GPTIMER3B CC1352P_4_LAUNCHXL_GPTIMER3B + +#define Board_I2C0 CC1352P_4_LAUNCHXL_I2C0 +#define Board_I2C_TMP Board_I2C0 + +#define Board_NVSINTERNAL CC1352P_4_LAUNCHXL_NVSCC26XX0 +#define Board_NVSEXTERNAL CC1352P_4_LAUNCHXL_NVSSPI25X0 + +#define Board_PIN_BUTTON0 CC1352P_4_LAUNCHXL_PIN_BTN1 +#define Board_PIN_BUTTON1 CC1352P_4_LAUNCHXL_PIN_BTN2 +#define Board_PIN_BTN1 CC1352P_4_LAUNCHXL_PIN_BTN1 +#define Board_PIN_BTN2 CC1352P_4_LAUNCHXL_PIN_BTN2 +#define Board_PIN_LED0 CC1352P_4_LAUNCHXL_PIN_RLED +#define Board_PIN_LED1 CC1352P_4_LAUNCHXL_PIN_GLED +#define Board_PIN_LED2 CC1352P_4_LAUNCHXL_PIN_RLED +#define Board_PIN_RLED CC1352P_4_LAUNCHXL_PIN_RLED +#define Board_PIN_GLED CC1352P_4_LAUNCHXL_PIN_GLED + +#define Board_PWM0 CC1352P_4_LAUNCHXL_PWM0 +#define Board_PWM1 CC1352P_4_LAUNCHXL_PWM1 +#define Board_PWM2 CC1352P_4_LAUNCHXL_PWM2 +#define Board_PWM3 CC1352P_4_LAUNCHXL_PWM3 +#define Board_PWM4 CC1352P_4_LAUNCHXL_PWM4 +#define Board_PWM5 CC1352P_4_LAUNCHXL_PWM5 +#define Board_PWM6 CC1352P_4_LAUNCHXL_PWM6 +#define Board_PWM7 CC1352P_4_LAUNCHXL_PWM7 + +#define Board_SD0 CC1352P_4_LAUNCHXL_SDSPI0 + +#define Board_SPI0 CC1352P_4_LAUNCHXL_SPI0 +#define Board_SPI1 CC1352P_4_LAUNCHXL_SPI1 +#define Board_SPI_FLASH_CS CC1352P_4_LAUNCHXL_SPI_FLASH_CS +#define Board_FLASH_CS_ON 0 +#define Board_FLASH_CS_OFF 1 + +#define Board_SPI_MASTER CC1352P_4_LAUNCHXL_SPI0 +#define Board_SPI_SLAVE CC1352P_4_LAUNCHXL_SPI0 +#define Board_SPI_MASTER_READY CC1352P_4_LAUNCHXL_SPI_MASTER_READY +#define Board_SPI_SLAVE_READY CC1352P_4_LAUNCHXL_SPI_SLAVE_READY + +#define Board_UART0 CC1352P_4_LAUNCHXL_UART0 +#define Board_UART1 CC1352P_4_LAUNCHXL_UART1 + +#define Board_WATCHDOG0 CC1352P_4_LAUNCHXL_WATCHDOG0 + +/* Board specific I2C addresses */ +#define Board_TMP_ADDR (0x40) +#define Board_SENSORS_BP_TMP_ADDR Board_TMP_ADDR + +#ifdef __cplusplus +} +#endif + +#endif /* __BOARD_H */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/CC1352P_4_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/CC1352P_4_LAUNCHXL.c new file mode 100644 index 000000000..0d5346cf5 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/CC1352P_4_LAUNCHXL.c @@ -0,0 +1,976 @@ +/* + * Copyright (c) 2017-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +/* + * ====================== CC1352P_4_LAUNCHXL.c =================================== + * This file is responsible for setting up the board specific items for the + * CC1352P_4_LAUNCHXL board. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "CC1352P_4_LAUNCHXL.h" + +/* + * =============================== ADCBuf =============================== + */ +#include +#include + +ADCBufCC26X2_Object adcBufCC26xxObjects[CC1352P_4_LAUNCHXL_ADCBUFCOUNT]; + +/* + * This table converts a virtual adc channel into a dio and internal analogue + * input signal. This table is necessary for the functioning of the adcBuf + * driver. Comment out unused entries to save flash. Dio and internal signal + * pairs are hardwired. Do not remap them in the table. You may reorder entire + * entries. The mapping of dio and internal signals is package dependent. + */ +const ADCBufCC26X2_AdcChannelLutEntry ADCBufCC26X2_adcChannelLut[CC1352P_4_LAUNCHXL_ADCBUF0CHANNELCOUNT] = { + {CC1352P_4_LAUNCHXL_DIO23_ANALOG, ADC_COMPB_IN_AUXIO7}, + {CC1352P_4_LAUNCHXL_DIO24_ANALOG, ADC_COMPB_IN_AUXIO6}, + {CC1352P_4_LAUNCHXL_DIO25_ANALOG, ADC_COMPB_IN_AUXIO5}, + {CC1352P_4_LAUNCHXL_DIO26_ANALOG, ADC_COMPB_IN_AUXIO4}, + {CC1352P_4_LAUNCHXL_DIO27_ANALOG, ADC_COMPB_IN_AUXIO3}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VDDS}, + {PIN_UNASSIGNED, ADC_COMPB_IN_DCOUPL}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VSS}, +}; + +const ADCBufCC26X2_HWAttrs adcBufCC26xxHWAttrs[CC1352P_4_LAUNCHXL_ADCBUFCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + .adcChannelLut = ADCBufCC26X2_adcChannelLut, + .gpTimerUnit = CC1352P_4_LAUNCHXL_GPTIMER0A, + } +}; + +const ADCBuf_Config ADCBuf_config[CC1352P_4_LAUNCHXL_ADCBUFCOUNT] = { + { + &ADCBufCC26X2_fxnTable, + &adcBufCC26xxObjects[CC1352P_4_LAUNCHXL_ADCBUF0], + &adcBufCC26xxHWAttrs[CC1352P_4_LAUNCHXL_ADCBUF0] + }, +}; + +const uint_least8_t ADCBuf_count = CC1352P_4_LAUNCHXL_ADCBUFCOUNT; + +/* + * =============================== ADC =============================== + */ +#include +#include + +ADCCC26XX_Object adcCC26xxObjects[CC1352P_4_LAUNCHXL_ADCCOUNT]; + +const ADCCC26XX_HWAttrs adcCC26xxHWAttrs[CC1352P_4_LAUNCHXL_ADCCOUNT] = { + { + .adcDIO = CC1352P_4_LAUNCHXL_DIO23_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO7, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1352P_4_LAUNCHXL_DIO24_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO6, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1352P_4_LAUNCHXL_DIO25_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO5, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1352P_4_LAUNCHXL_DIO26_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO4, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = CC1352P_4_LAUNCHXL_DIO27_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO3, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_DCOUPL, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VSS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VDDS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + } +}; + +const ADC_Config ADC_config[CC1352P_4_LAUNCHXL_ADCCOUNT] = { + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352P_4_LAUNCHXL_ADC0], &adcCC26xxHWAttrs[CC1352P_4_LAUNCHXL_ADC0]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352P_4_LAUNCHXL_ADC1], &adcCC26xxHWAttrs[CC1352P_4_LAUNCHXL_ADC1]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352P_4_LAUNCHXL_ADC2], &adcCC26xxHWAttrs[CC1352P_4_LAUNCHXL_ADC2]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352P_4_LAUNCHXL_ADC3], &adcCC26xxHWAttrs[CC1352P_4_LAUNCHXL_ADC3]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352P_4_LAUNCHXL_ADC4], &adcCC26xxHWAttrs[CC1352P_4_LAUNCHXL_ADC4]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352P_4_LAUNCHXL_ADCDCOUPL], &adcCC26xxHWAttrs[CC1352P_4_LAUNCHXL_ADCDCOUPL]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352P_4_LAUNCHXL_ADCVSS], &adcCC26xxHWAttrs[CC1352P_4_LAUNCHXL_ADCVSS]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1352P_4_LAUNCHXL_ADCVDDS], &adcCC26xxHWAttrs[CC1352P_4_LAUNCHXL_ADCVDDS]}, +}; + +const uint_least8_t ADC_count = CC1352P_4_LAUNCHXL_ADCCOUNT; + +/* + * =============================== ECDH =============================== + */ +#include +#include + +ECDHCC26X2_Object ecdhCC26X2Objects[CC1352P_4_LAUNCHXL_ECDHCOUNT]; + +const ECDHCC26X2_HWAttrs ecdhCC26X2HWAttrs[CC1352P_4_LAUNCHXL_ECDHCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const ECDH_Config ECDH_config[CC1352P_4_LAUNCHXL_ECDHCOUNT] = { + { + .object = &ecdhCC26X2Objects[CC1352P_4_LAUNCHXL_ECDH0], + .hwAttrs = &ecdhCC26X2HWAttrs[CC1352P_4_LAUNCHXL_ECDH0] + }, +}; + +const uint_least8_t ECDH_count = CC1352P_4_LAUNCHXL_ECDHCOUNT; + +/* + * =============================== ECDSA =============================== + */ +#include +#include + +ECDSACC26X2_Object ecdsaCC26X2Objects[CC1352P_4_LAUNCHXL_ECDSACOUNT]; + +const ECDSACC26X2_HWAttrs ecdsaCC26X2HWAttrs[CC1352P_4_LAUNCHXL_ECDSACOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const ECDSA_Config ECDSA_config[CC1352P_4_LAUNCHXL_ECDSACOUNT] = { + { + .object = &ecdsaCC26X2Objects[CC1352P_4_LAUNCHXL_ECDSA0], + .hwAttrs = &ecdsaCC26X2HWAttrs[CC1352P_4_LAUNCHXL_ECDSA0] + }, +}; + +const uint_least8_t ECDSA_count = CC1352P_4_LAUNCHXL_ECDSACOUNT; + +/* + * =============================== ECJPAKE =============================== + */ +#include +#include + +ECJPAKECC26X2_Object ecjpakeCC26X2Objects[CC1352P_4_LAUNCHXL_ECJPAKECOUNT]; + +const ECJPAKECC26X2_HWAttrs ecjpakeCC26X2HWAttrs[CC1352P_4_LAUNCHXL_ECJPAKECOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const ECJPAKE_Config ECJPAKE_config[CC1352P_4_LAUNCHXL_ECJPAKECOUNT] = { + { + .object = &ecjpakeCC26X2Objects[CC1352P_4_LAUNCHXL_ECJPAKE0], + .hwAttrs = &ecjpakeCC26X2HWAttrs[CC1352P_4_LAUNCHXL_ECJPAKE0] + }, +}; + +const uint_least8_t ECJPAKE_count = CC1352P_4_LAUNCHXL_ECJPAKECOUNT; + + +/* + * =============================== SHA2 =============================== + */ +#include +#include + +SHA2CC26X2_Object sha2CC26X2Objects[CC1352P_4_LAUNCHXL_SHA2COUNT]; + +const SHA2CC26X2_HWAttrs sha2CC26X2HWAttrs[CC1352P_4_LAUNCHXL_SHA2COUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const SHA2_Config SHA2_config[CC1352P_4_LAUNCHXL_SHA2COUNT] = { + { + .object = &sha2CC26X2Objects[CC1352P_4_LAUNCHXL_SHA20], + .hwAttrs = &sha2CC26X2HWAttrs[CC1352P_4_LAUNCHXL_SHA20] + }, +}; + +const uint_least8_t SHA2_count = CC1352P_4_LAUNCHXL_SHA2COUNT; + +/* + * =============================== AESCCM =============================== + */ +#include +#include + +AESCCMCC26XX_Object aesccmCC26XXObjects[CC1352P_4_LAUNCHXL_AESCCMCOUNT]; + +const AESCCMCC26XX_HWAttrs aesccmCC26XXHWAttrs[CC1352P_4_LAUNCHXL_AESCCMCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const AESCCM_Config AESCCM_config[CC1352P_4_LAUNCHXL_AESCCMCOUNT] = { + { + .object = &aesccmCC26XXObjects[CC1352P_4_LAUNCHXL_AESCCM0], + .hwAttrs = &aesccmCC26XXHWAttrs[CC1352P_4_LAUNCHXL_AESCCM0] + }, +}; + +const uint_least8_t AESCCM_count = CC1352P_4_LAUNCHXL_AESCCMCOUNT; + +/* + * =============================== AESECB =============================== + */ +#include +#include + +AESECBCC26XX_Object aesecbCC26XXObjects[CC1352P_4_LAUNCHXL_AESECBCOUNT]; + +const AESECBCC26XX_HWAttrs aesecbCC26XXHWAttrs[CC1352P_4_LAUNCHXL_AESECBCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + } +}; + +const AESECB_Config AESECB_config[CC1352P_4_LAUNCHXL_AESECBCOUNT] = { + { + .object = &aesecbCC26XXObjects[CC1352P_4_LAUNCHXL_AESECB0], + .hwAttrs = &aesecbCC26XXHWAttrs[CC1352P_4_LAUNCHXL_AESECB0] + }, +}; + +const uint_least8_t AESECB_count = CC1352P_4_LAUNCHXL_AESECBCOUNT; + +/* + * =============================== Display =============================== + */ +#include +#include +#include + +#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE +#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 +#endif + +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 +#endif + +DisplayUart_Object displayUartObject; +DisplaySharp_Object displaySharpObject; + +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; +static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; + +const DisplayUart_HWAttrs displayUartHWAttrs = { + .uartIdx = CC1352P_4_LAUNCHXL_UART0, + .baudRate = 115200, + .mutexTimeout = (unsigned int)(-1), + .strBuf = uartStringBuf, + .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, +}; + +const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { + .spiIndex = CC1352P_4_LAUNCHXL_SPI0, + .csPin = CC1352P_4_LAUNCHXL_GPIO_LCD_CS, + .powerPin = CC1352P_4_LAUNCHXL_GPIO_DIO_19, + .enablePin = CC1352P_4_LAUNCHXL_GPIO_LCD_ENABLE, + .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, + .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, + .displayBuf = sharpDisplayBuf, +}; + +#ifndef BOARD_DISPLAY_USE_UART +#define BOARD_DISPLAY_USE_UART 1 +#endif +#ifndef BOARD_DISPLAY_USE_UART_ANSI +#define BOARD_DISPLAY_USE_UART_ANSI 0 +#endif +#ifndef BOARD_DISPLAY_USE_LCD +#define BOARD_DISPLAY_USE_LCD 0 +#endif + +/* + * This #if/#else is needed to workaround a problem with the + * IAR compiler. The IAR compiler doesn't like the empty array + * initialization. (IAR Error[Pe1345]) + */ +#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) + +const Display_Config Display_config[] = { +#if (BOARD_DISPLAY_USE_UART) + { +# if (BOARD_DISPLAY_USE_UART_ANSI) + .fxnTablePtr = &DisplayUartAnsi_fxnTable, +# else /* Default to minimal UART with no cursor placement */ + .fxnTablePtr = &DisplayUartMin_fxnTable, +# endif + .object = &displayUartObject, + .hwAttrs = &displayUartHWAttrs, + }, +#endif +#if (BOARD_DISPLAY_USE_LCD) + { + .fxnTablePtr = &DisplaySharp_fxnTable, + .object = &displaySharpObject, + .hwAttrs = &displaySharpHWattrs + }, +#endif +}; + +const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); + +#else + +const Display_Config *Display_config = NULL; +const uint_least8_t Display_count = 0; + +#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ + +/* + * =============================== GPIO =============================== + */ +#include +#include + +/* + * Array of Pin configurations + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC1352P_4_LAUNCHXL.h + * NOTE: Pins not used for interrupts should be placed at the end of the + * array. Callback entries can be omitted from callbacks array to + * reduce memory usage. + */ +GPIO_PinConfig gpioPinConfigs[] = { + /* Input pins */ + GPIOCC26XX_DIO_15 | GPIO_DO_NOT_CONFIG, /* Button 0 */ + GPIOCC26XX_DIO_14 | GPIO_DO_NOT_CONFIG, /* Button 1 */ + + GPIOCC26XX_DIO_15 | GPIO_DO_NOT_CONFIG, /* CC1352P_4_LAUNCHXL_SPI_MASTER_READY */ + GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG, /* CC1352P_4_LAUNCHXL_SPI_SLAVE_READY */ + + /* Output pins */ + GPIOCC26XX_DIO_07 | GPIO_DO_NOT_CONFIG, /* Green LED */ + GPIOCC26XX_DIO_06 | GPIO_DO_NOT_CONFIG, /* Red LED */ + + /* SPI Flash CSN */ + GPIOCC26XX_DIO_20 | GPIO_DO_NOT_CONFIG, + + /* + * DIO 19 is used for LCD power control and SD chip select. This is due to + * DIO21 & DIO22 moving on this LaunchPad. DIO 19 can also be used as a + * UART CTS pin. + */ + GPIOCC26XX_DIO_19 | GPIO_DO_NOT_CONFIG, + + /* Sharp Display - GPIO configurations will be done in the Display files */ + GPIOCC26XX_DIO_24 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ + GPIOCC26XX_DIO_23 | GPIO_DO_NOT_CONFIG, /*LCD enable */ + +}; + +/* + * Array of callback function pointers + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC1352P_LAUNCH.h + * NOTE: Pins not used for interrupts can be omitted from callbacks array to + * reduce memory usage (if placed at end of gpioPinConfigs array). + */ +GPIO_CallbackFxn gpioCallbackFunctions[] = { + NULL, /* Button 0 */ + NULL, /* Button 1 */ + NULL, /* CC1352P_4_LAUNCHXL_SPI_MASTER_READY */ + NULL, /* CC1352P_4_LAUNCHXL_SPI_SLAVE_READY */ +}; + +const GPIOCC26XX_Config GPIOCC26XX_config = { + .pinConfigs = (GPIO_PinConfig *)gpioPinConfigs, + .callbacks = (GPIO_CallbackFxn *)gpioCallbackFunctions, + .numberOfPinConfigs = CC1352P_4_LAUNCHXL_GPIOCOUNT, + .numberOfCallbacks = sizeof(gpioCallbackFunctions)/sizeof(GPIO_CallbackFxn), + .intPriority = (~0) +}; + +/* + * =============================== GPTimer =============================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +#include + +GPTimerCC26XX_Object gptimerCC26XXObjects[CC1352P_4_LAUNCHXL_GPTIMERCOUNT]; + +const GPTimerCC26XX_HWAttrs gptimerCC26xxHWAttrs[CC1352P_4_LAUNCHXL_GPTIMERPARTSCOUNT] = { + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0A, }, + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0B, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1A, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1B, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2A, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2B, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3A, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3B, }, +}; + +const GPTimerCC26XX_Config GPTimerCC26XX_config[CC1352P_4_LAUNCHXL_GPTIMERPARTSCOUNT] = { + { &gptimerCC26XXObjects[CC1352P_4_LAUNCHXL_GPTIMER0], &gptimerCC26xxHWAttrs[CC1352P_4_LAUNCHXL_GPTIMER0A], GPT_A }, + { &gptimerCC26XXObjects[CC1352P_4_LAUNCHXL_GPTIMER0], &gptimerCC26xxHWAttrs[CC1352P_4_LAUNCHXL_GPTIMER0B], GPT_B }, + { &gptimerCC26XXObjects[CC1352P_4_LAUNCHXL_GPTIMER1], &gptimerCC26xxHWAttrs[CC1352P_4_LAUNCHXL_GPTIMER1A], GPT_A }, + { &gptimerCC26XXObjects[CC1352P_4_LAUNCHXL_GPTIMER1], &gptimerCC26xxHWAttrs[CC1352P_4_LAUNCHXL_GPTIMER1B], GPT_B }, + { &gptimerCC26XXObjects[CC1352P_4_LAUNCHXL_GPTIMER2], &gptimerCC26xxHWAttrs[CC1352P_4_LAUNCHXL_GPTIMER2A], GPT_A }, + { &gptimerCC26XXObjects[CC1352P_4_LAUNCHXL_GPTIMER2], &gptimerCC26xxHWAttrs[CC1352P_4_LAUNCHXL_GPTIMER2B], GPT_B }, + { &gptimerCC26XXObjects[CC1352P_4_LAUNCHXL_GPTIMER3], &gptimerCC26xxHWAttrs[CC1352P_4_LAUNCHXL_GPTIMER3A], GPT_A }, + { &gptimerCC26XXObjects[CC1352P_4_LAUNCHXL_GPTIMER3], &gptimerCC26xxHWAttrs[CC1352P_4_LAUNCHXL_GPTIMER3B], GPT_B }, +}; + +/* + * =============================== I2C =============================== +*/ +#include +#include + +I2CCC26XX_Object i2cCC26xxObjects[CC1352P_4_LAUNCHXL_I2CCOUNT]; + +const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1352P_4_LAUNCHXL_I2CCOUNT] = { + { + .baseAddr = I2C0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_I2C0, + .intNum = INT_I2C_IRQ, + .intPriority = ~0, + .swiPriority = 0, + .sdaPin = CC1352P_4_LAUNCHXL_I2C0_SDA0, + .sclPin = CC1352P_4_LAUNCHXL_I2C0_SCL0, + } +}; + +const I2C_Config I2C_config[CC1352P_4_LAUNCHXL_I2CCOUNT] = { + { + .fxnTablePtr = &I2CCC26XX_fxnTable, + .object = &i2cCC26xxObjects[CC1352P_4_LAUNCHXL_I2C0], + .hwAttrs = &i2cCC26xxHWAttrs[CC1352P_4_LAUNCHXL_I2C0] + }, +}; + +const uint_least8_t I2C_count = CC1352P_4_LAUNCHXL_I2CCOUNT; + +/* + * =============================== NVS =============================== + */ +#include +#include +#include + +#define NVS_REGIONS_BASE 0x48000 +#define SECTORSIZE 0x2000 +#define REGIONSIZE (SECTORSIZE * 4) + +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH + +/* + * Reserve flash sectors for NVS driver use by placing an uninitialized byte + * array at the desired flash address. + */ +#if defined(__TI_COMPILER_VERSION__) + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +#pragma LOCATION(flashBuf, NVS_REGIONS_BASE); +#pragma NOINIT(flashBuf); +static char flashBuf[REGIONSIZE]; + +#elif defined(__IAR_SYSTEMS_ICC__) + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +static __no_init char flashBuf[REGIONSIZE] @ NVS_REGIONS_BASE; + +#elif defined(__GNUC__) + +/* + * Place the flash buffers in the .nvs section created in the gcc linker file. + * The .nvs section enforces alignment on a sector boundary but may + * be placed anywhere in flash memory. If desired the .nvs section can be set + * to a fixed address by changing the following in the gcc linker file: + * + * .nvs (FIXED_FLASH_ADDR) (NOLOAD) : AT (FIXED_FLASH_ADDR) { + * *(.nvs) + * } > REGION_TEXT + */ +__attribute__ ((section (".nvs"))) +static char flashBuf[REGIONSIZE]; + +#endif + +/* Allocate objects for NVS Internal Regions */ +NVSCC26XX_Object nvsCC26xxObjects[1]; + +/* Hardware attributes for NVS Internal Regions */ +const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { + { + .regionBase = (void *)flashBuf, + .regionSize = REGIONSIZE, + }, +}; + +#endif /* Board_EXCLUDE_NVS_INTERNAL_FLASH */ + +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH + +#define SPISECTORSIZE 0x1000 +#define SPIREGIONSIZE (SPISECTORSIZE * 32) +#define VERIFYBUFSIZE 64 + +static uint8_t verifyBuf[VERIFYBUFSIZE]; + +/* Allocate objects for NVS External Regions */ +NVSSPI25X_Object nvsSPI25XObjects[1]; + +/* Hardware attributes for NVS External Regions */ +const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { + { + .regionBaseOffset = 0, + .regionSize = SPIREGIONSIZE, + .sectorSize = SPISECTORSIZE, + .verifyBuf = verifyBuf, + .verifyBufSize = VERIFYBUFSIZE, + .spiHandle = NULL, + .spiIndex = 0, + .spiBitRate = 4000000, + .spiCsnGpioIndex = CC1352P_4_LAUNCHXL_GPIO_SPI_FLASH_CS, + }, +}; + +#endif /* Board_EXCLUDE_NVS_EXTERNAL_FLASH */ + +/* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ +const NVS_Config NVS_config[CC1352P_4_LAUNCHXL_NVSCOUNT] = { +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH + { + .fxnTablePtr = &NVSCC26XX_fxnTable, + .object = &nvsCC26xxObjects[0], + .hwAttrs = &nvsCC26xxHWAttrs[0], + }, +#endif +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH + { + .fxnTablePtr = &NVSSPI25X_fxnTable, + .object = &nvsSPI25XObjects[0], + .hwAttrs = &nvsSPI25XHWAttrs[0], + }, +#endif +}; + +const uint_least8_t NVS_count = CC1352P_4_LAUNCHXL_NVSCOUNT; + +/* + * =============================== PIN =============================== + */ +#include +#include + +const PIN_Config BoardGpioInitTable[] = { + + CC1352P_4_LAUNCHXL_PIN_RLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC1352P_4_LAUNCHXL_PIN_GLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC1352P_4_LAUNCHXL_PIN_BTN1 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC1352P_4_LAUNCHXL_PIN_BTN2 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC1352P_4_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ + CC1352P_4_LAUNCHXL_UART0_RX | PIN_INPUT_EN | PIN_PULLDOWN, /* UART RX via debugger back channel */ + CC1352P_4_LAUNCHXL_UART0_TX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* UART TX via debugger back channel */ + CC1352P_4_LAUNCHXL_SPI0_MOSI | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master out - slave in */ + CC1352P_4_LAUNCHXL_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master in - slave out */ + CC1352P_4_LAUNCHXL_SPI0_CLK | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI clock */ + CC1352P_4_LAUNCHXL_DIO28_RF_24GHZ | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Path disabled */ + CC1352P_4_LAUNCHXL_DIO29_RF_HIGH_PA | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Path disabled */ + CC1352P_4_LAUNCHXL_DIO30_RF_SUB1GHZ | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Path disabled */ + PIN_TERMINATE +}; + +const PINCC26XX_HWAttrs PINCC26XX_hwAttrs = { + .intPriority = ~0, + .swiPriority = 0 +}; + +/* + * =============================== Power =============================== + */ +#include +#include + +const PowerCC26X2_Config PowerCC26X2_config = { + .policyInitFxn = NULL, + .policyFxn = &PowerCC26XX_standbyPolicy, + .calibrateFxn = &PowerCC26XX_calibrate, + .enablePolicy = true, + .calibrateRCOSC_LF = true, + .calibrateRCOSC_HF = true, +}; + +/* + * =============================== PWM =============================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +#include +#include + +PWMTimerCC26XX_Object pwmtimerCC26xxObjects[CC1352P_4_LAUNCHXL_PWMCOUNT]; + +const PWMTimerCC26XX_HwAttrs pwmtimerCC26xxHWAttrs[CC1352P_4_LAUNCHXL_PWMCOUNT] = { + { .pwmPin = CC1352P_4_LAUNCHXL_PWMPIN0, .gpTimerUnit = CC1352P_4_LAUNCHXL_GPTIMER0A }, + { .pwmPin = CC1352P_4_LAUNCHXL_PWMPIN1, .gpTimerUnit = CC1352P_4_LAUNCHXL_GPTIMER0B }, + { .pwmPin = CC1352P_4_LAUNCHXL_PWMPIN2, .gpTimerUnit = CC1352P_4_LAUNCHXL_GPTIMER1A }, + { .pwmPin = CC1352P_4_LAUNCHXL_PWMPIN3, .gpTimerUnit = CC1352P_4_LAUNCHXL_GPTIMER1B }, + { .pwmPin = CC1352P_4_LAUNCHXL_PWMPIN4, .gpTimerUnit = CC1352P_4_LAUNCHXL_GPTIMER2A }, + { .pwmPin = CC1352P_4_LAUNCHXL_PWMPIN5, .gpTimerUnit = CC1352P_4_LAUNCHXL_GPTIMER2B }, + { .pwmPin = CC1352P_4_LAUNCHXL_PWMPIN6, .gpTimerUnit = CC1352P_4_LAUNCHXL_GPTIMER3A }, + { .pwmPin = CC1352P_4_LAUNCHXL_PWMPIN7, .gpTimerUnit = CC1352P_4_LAUNCHXL_GPTIMER3B }, +}; + +const PWM_Config PWM_config[CC1352P_4_LAUNCHXL_PWMCOUNT] = { + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352P_4_LAUNCHXL_PWM0], &pwmtimerCC26xxHWAttrs[CC1352P_4_LAUNCHXL_PWM0] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352P_4_LAUNCHXL_PWM1], &pwmtimerCC26xxHWAttrs[CC1352P_4_LAUNCHXL_PWM1] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352P_4_LAUNCHXL_PWM2], &pwmtimerCC26xxHWAttrs[CC1352P_4_LAUNCHXL_PWM2] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352P_4_LAUNCHXL_PWM3], &pwmtimerCC26xxHWAttrs[CC1352P_4_LAUNCHXL_PWM3] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352P_4_LAUNCHXL_PWM4], &pwmtimerCC26xxHWAttrs[CC1352P_4_LAUNCHXL_PWM4] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352P_4_LAUNCHXL_PWM5], &pwmtimerCC26xxHWAttrs[CC1352P_4_LAUNCHXL_PWM5] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352P_4_LAUNCHXL_PWM6], &pwmtimerCC26xxHWAttrs[CC1352P_4_LAUNCHXL_PWM6] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1352P_4_LAUNCHXL_PWM7], &pwmtimerCC26xxHWAttrs[CC1352P_4_LAUNCHXL_PWM7] }, +}; + +const uint_least8_t PWM_count = CC1352P_4_LAUNCHXL_PWMCOUNT; + +/* + * =============================== RF Driver =============================== + */ +#include + +/* + * Board-specific callback function to set the correct antenna path. + * + * This function is called by the RF driver on global driver events. + * It contains a default implementation to set the correct antenna path. + * This function is defined in the file CC1352P_4_LAUNCHXL_fxns.c + */ +extern void rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void* arg); + +const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { + .hwiPriority = ~0, /* Lowest HWI priority */ + .swiPriority = 0, /* Lowest SWI priority */ + .xoscHfAlwaysNeeded = true, /* Keep XOSC dependency while in stanby */ + + /* Register the board specific callback */ + .globalCallback = &rfDriverCallback, + + /* Subscribe the callback to both events */ + .globalEventMask = RF_GlobalEventRadioSetup | RF_GlobalEventRadioPowerDown +}; + +/* + * =============================== SD =============================== + */ +#include +#include + +SDSPI_Object sdspiObjects[CC1352P_4_LAUNCHXL_SDCOUNT]; + +const SDSPI_HWAttrs sdspiHWAttrs[CC1352P_4_LAUNCHXL_SDCOUNT] = { + { + .spiIndex = CC1352P_4_LAUNCHXL_SPI0, + .spiCsGpioIndex = CC1352P_4_LAUNCHXL_GPIO_DIO_19 + } +}; + +const SD_Config SD_config[CC1352P_4_LAUNCHXL_SDCOUNT] = { + { + .fxnTablePtr = &SDSPI_fxnTable, + .object = &sdspiObjects[CC1352P_4_LAUNCHXL_SDSPI0], + .hwAttrs = &sdspiHWAttrs[CC1352P_4_LAUNCHXL_SDSPI0] + }, +}; + +const uint_least8_t SD_count = CC1352P_4_LAUNCHXL_SDCOUNT; + +/* + * =============================== SPI DMA =============================== + */ +#include +#include + +SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1352P_4_LAUNCHXL_SPICOUNT]; + +/* + * NOTE: The SPI instances below can be used by the SD driver to communicate + * with a SD card via SPI. The 'defaultTxBufValue' fields below are set to 0xFF + * to satisfy the SDSPI driver requirement. + */ +const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1352P_4_LAUNCHXL_SPICOUNT] = { + { + .baseAddr = SSI0_BASE, + .intNum = INT_SSI0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .powerMngrId = PowerCC26XX_PERIPH_SSI0, + .defaultTxBufValue = 0xFF, + .rxChannelBitMask = 1< +#include + +UARTCC26XX_Object uartCC26XXObjects[CC1352P_4_LAUNCHXL_UARTCOUNT]; + +uint8_t uartCC26XXRingBuffer[CC1352P_4_LAUNCHXL_UARTCOUNT][32]; + +const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1352P_4_LAUNCHXL_UARTCOUNT] = { + { + .baseAddr = UART0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UART0, + .intNum = INT_UART0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .txPin = CC1352P_4_LAUNCHXL_UART0_TX, + .rxPin = CC1352P_4_LAUNCHXL_UART0_RX, + .ctsPin = PIN_UNASSIGNED, + .rtsPin = PIN_UNASSIGNED, + .ringBufPtr = uartCC26XXRingBuffer[CC1352P_4_LAUNCHXL_UART0], + .ringBufSize = sizeof(uartCC26XXRingBuffer[CC1352P_4_LAUNCHXL_UART0]), + .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, + .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, + .errorFxn = NULL + }, + { + .baseAddr = UART1_BASE, + .powerMngrId = PowerCC26X2_PERIPH_UART1, + .intNum = INT_UART1_COMB, + .intPriority = ~0, + .swiPriority = 0, + .txPin = CC1352P_4_LAUNCHXL_UART1_TX, + .rxPin = CC1352P_4_LAUNCHXL_UART1_RX, + .ctsPin = PIN_UNASSIGNED, + .rtsPin = PIN_UNASSIGNED, + .ringBufPtr = uartCC26XXRingBuffer[CC1352P_4_LAUNCHXL_UART1], + .ringBufSize = sizeof(uartCC26XXRingBuffer[CC1352P_4_LAUNCHXL_UART1]), + .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, + .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, + .errorFxn = NULL + } +}; + +const UART_Config UART_config[CC1352P_4_LAUNCHXL_UARTCOUNT] = { + { + .fxnTablePtr = &UARTCC26XX_fxnTable, + .object = &uartCC26XXObjects[CC1352P_4_LAUNCHXL_UART0], + .hwAttrs = &uartCC26XXHWAttrs[CC1352P_4_LAUNCHXL_UART0] + }, + { + .fxnTablePtr = &UARTCC26XX_fxnTable, + .object = &uartCC26XXObjects[CC1352P_4_LAUNCHXL_UART1], + .hwAttrs = &uartCC26XXHWAttrs[CC1352P_4_LAUNCHXL_UART1] + }, +}; + +const uint_least8_t UART_count = CC1352P_4_LAUNCHXL_UARTCOUNT; + +/* + * =============================== UDMA =============================== + */ +#include + +UDMACC26XX_Object udmaObjects[CC1352P_4_LAUNCHXL_UDMACOUNT]; + +const UDMACC26XX_HWAttrs udmaHWAttrs[CC1352P_4_LAUNCHXL_UDMACOUNT] = { + { + .baseAddr = UDMA0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UDMA, + .intNum = INT_DMA_ERR, + .intPriority = ~0 + } +}; + +const UDMACC26XX_Config UDMACC26XX_config[CC1352P_4_LAUNCHXL_UDMACOUNT] = { + { + .object = &udmaObjects[CC1352P_4_LAUNCHXL_UDMA0], + .hwAttrs = &udmaHWAttrs[CC1352P_4_LAUNCHXL_UDMA0] + }, +}; + + + +/* + * =============================== Watchdog =============================== + */ +#include +#include + +WatchdogCC26XX_Object watchdogCC26XXObjects[CC1352P_4_LAUNCHXL_WATCHDOGCOUNT]; + +const WatchdogCC26XX_HWAttrs watchdogCC26XXHWAttrs[CC1352P_4_LAUNCHXL_WATCHDOGCOUNT] = { + { + .baseAddr = WDT_BASE, + .reloadValue = 1000 /* Reload value in milliseconds */ + }, +}; + +const Watchdog_Config Watchdog_config[CC1352P_4_LAUNCHXL_WATCHDOGCOUNT] = { + { + .fxnTablePtr = &WatchdogCC26XX_fxnTable, + .object = &watchdogCC26XXObjects[CC1352P_4_LAUNCHXL_WATCHDOG0], + .hwAttrs = &watchdogCC26XXHWAttrs[CC1352P_4_LAUNCHXL_WATCHDOG0] + }, +}; + +const uint_least8_t Watchdog_count = CC1352P_4_LAUNCHXL_WATCHDOGCOUNT; + +/* + * Board-specific initialization function to disable external flash. + * This function is defined in the file CC1352P_4_LAUNCHXL_fxns.c + */ +extern void Board_initHook(void); + +/* + * ======== CC1352P_4_LAUNCHXL_initGeneral ======== + */ +void CC1352P_4_LAUNCHXL_initGeneral(void) +{ + Power_init(); + + if (PIN_init(BoardGpioInitTable) != PIN_SUCCESS) { + /* Error with PIN_init */ + while (1); + } + + /* Perform board-specific initialization */ + Board_initHook(); +} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/CC1352P_4_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/CC1352P_4_LAUNCHXL.h new file mode 100644 index 000000000..bd8bc2594 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/CC1352P_4_LAUNCHXL.h @@ -0,0 +1,435 @@ +/* + * Copyright (c) 2017-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ +/** =========================================================================== + * @file CC1352P_4_LAUNCHXL.h + * + * @brief CC1352P_4_LAUNCHXL Board Specific header file. + * + * The CC1352P_4_LAUNCHXL header file should be included in an application as + * follows: + * @code + * #include "CC1352P_4_LAUNCHXL.h" + * @endcode + * + * =========================================================================== + */ +#ifndef __CC1352P_4_LAUNCHXL_BOARD_H__ +#define __CC1352P_4_LAUNCHXL_BOARD_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes */ +#include +#include + +/* Externs */ +extern const PIN_Config BoardGpioInitTable[]; + +/* Defines */ +#define CC1352P_4_LAUNCHXL + +/* Mapping of pins to board signals using general board aliases + * + */ + +/* Mapping of pins to board signals using general board aliases + * + */ +/* Analog Capable DIOs */ +#define CC1352P_4_LAUNCHXL_DIO23_ANALOG IOID_23 +#define CC1352P_4_LAUNCHXL_DIO24_ANALOG IOID_24 +#define CC1352P_4_LAUNCHXL_DIO25_ANALOG IOID_25 +#define CC1352P_4_LAUNCHXL_DIO26_ANALOG IOID_26 +#define CC1352P_4_LAUNCHXL_DIO27_ANALOG IOID_27 + +/* RF Antenna Switch */ +#define CC1352P_4_LAUNCHXL_DIO28_RF_24GHZ IOID_28 +#define CC1352P_4_LAUNCHXL_DIO29_RF_HIGH_PA IOID_29 +#define CC1352P_4_LAUNCHXL_DIO30_RF_SUB1GHZ IOID_30 + +/* Digital IOs */ +#define CC1352P_4_LAUNCHXL_DIO12 IOID_12 +#define CC1352P_4_LAUNCHXL_DIO15 IOID_15 +#define CC1352P_4_LAUNCHXL_DIO16_TDO IOID_16 +#define CC1352P_4_LAUNCHXL_DIO17_TDI IOID_17 +#define CC1352P_4_LAUNCHXL_DIO21 IOID_21 +#define CC1352P_4_LAUNCHXL_DIO22 IOID_22 + +/* Discrete Inputs */ +#define CC1352P_4_LAUNCHXL_PIN_BTN1 IOID_15 +#define CC1352P_4_LAUNCHXL_PIN_BTN2 IOID_14 + +/* GPIO */ +#define CC1352P_4_LAUNCHXL_GPIO_LED_ON 1 +#define CC1352P_4_LAUNCHXL_GPIO_LED_OFF 0 + +/* I2C */ +#define CC1352P_4_LAUNCHXL_I2C0_SCL0 IOID_21 +#define CC1352P_4_LAUNCHXL_I2C0_SDA0 IOID_5 + +/* LEDs */ +#define CC1352P_4_LAUNCHXL_PIN_LED_ON 1 +#define CC1352P_4_LAUNCHXL_PIN_LED_OFF 0 +#define CC1352P_4_LAUNCHXL_PIN_RLED IOID_6 +#define CC1352P_4_LAUNCHXL_PIN_GLED IOID_7 + +/* PWM Outputs */ +#define CC1352P_4_LAUNCHXL_PWMPIN0 CC1352P_4_LAUNCHXL_PIN_RLED +#define CC1352P_4_LAUNCHXL_PWMPIN1 CC1352P_4_LAUNCHXL_PIN_GLED +#define CC1352P_4_LAUNCHXL_PWMPIN2 PIN_UNASSIGNED +#define CC1352P_4_LAUNCHXL_PWMPIN3 PIN_UNASSIGNED +#define CC1352P_4_LAUNCHXL_PWMPIN4 PIN_UNASSIGNED +#define CC1352P_4_LAUNCHXL_PWMPIN5 PIN_UNASSIGNED +#define CC1352P_4_LAUNCHXL_PWMPIN6 PIN_UNASSIGNED +#define CC1352P_4_LAUNCHXL_PWMPIN7 PIN_UNASSIGNED + +/* SPI */ +#define CC1352P_4_LAUNCHXL_SPI_FLASH_CS IOID_20 +#define CC1352P_4_LAUNCHXL_FLASH_CS_ON 0 +#define CC1352P_4_LAUNCHXL_FLASH_CS_OFF 1 + +/* SPI Board */ +#define CC1352P_4_LAUNCHXL_SPI0_MISO IOID_8 /* RF1.20 */ +#define CC1352P_4_LAUNCHXL_SPI0_MOSI IOID_9 /* RF1.18 */ +#define CC1352P_4_LAUNCHXL_SPI0_CLK IOID_10 /* RF1.16 */ +#define CC1352P_4_LAUNCHXL_SPI0_CSN PIN_UNASSIGNED +#define CC1352P_4_LAUNCHXL_SPI1_MISO PIN_UNASSIGNED +#define CC1352P_4_LAUNCHXL_SPI1_MOSI PIN_UNASSIGNED +#define CC1352P_4_LAUNCHXL_SPI1_CLK PIN_UNASSIGNED +#define CC1352P_4_LAUNCHXL_SPI1_CSN PIN_UNASSIGNED + +/* UART Board */ +#define CC1352P_4_LAUNCHXL_UART0_RX IOID_12 /* RXD */ +#define CC1352P_4_LAUNCHXL_UART0_TX IOID_13 /* TXD */ +#define CC1352P_4_LAUNCHXL_UART0_CTS PIN_UNASSIGNED /* CTS */ +#define CC1352P_4_LAUNCHXL_UART0_RTS IOID_18 /* RTS */ +#define CC1352P_4_LAUNCHXL_UART1_RX PIN_UNASSIGNED +#define CC1352P_4_LAUNCHXL_UART1_TX PIN_UNASSIGNED +#define CC1352P_4_LAUNCHXL_UART1_CTS PIN_UNASSIGNED +#define CC1352P_4_LAUNCHXL_UART1_RTS PIN_UNASSIGNED +/* For backward compatibility */ +#define CC1352P_4_LAUNCHXL_UART_RX CC1352P_4_LAUNCHXL_UART0_RX +#define CC1352P_4_LAUNCHXL_UART_TX CC1352P_4_LAUNCHXL_UART0_TX +#define CC1352P_4_LAUNCHXL_UART_CTS CC1352P_4_LAUNCHXL_UART0_CTS +#define CC1352P_4_LAUNCHXL_UART_RTS CC1352P_4_LAUNCHXL_UART0_RTS + +/*! + * @brief Initialize the general board specific settings + * + * This function initializes the general board specific settings. + */ +void CC1352P_4_LAUNCHXL_initGeneral(void); + +/*! + * @brief Shut down the external flash present on the board files + * + * This function bitbangs the SPI sequence necessary to turn off + * the external flash on LaunchPads. + */ +void CC1352P_4_LAUNCHXL_shutDownExtFlash(void); + +/*! + * @brief Wake up the external flash present on the board files + * + * This function toggles the chip select for the amount of time needed + * to wake the chip up. + */ +void CC1352P_4_LAUNCHXL_wakeUpExtFlash(void); + + +/*! + * \brief Initializes the antenna switch IOs. + * + * This function sets up the antenna switch and occupies + * the necessary IO pins. After calling this function, they + * cannot be used in the application anymore. + */ +void CC1352P_4_LAUNCHXL_initAntennaSwitch(void); + +/*! + * @def CC1352P_4_LAUNCHXL_ADCBufName + * @brief Enum of ADCs + */ +typedef enum CC1352P_4_LAUNCHXL_ADCBufName { + CC1352P_4_LAUNCHXL_ADCBUF0 = 0, + + CC1352P_4_LAUNCHXL_ADCBUFCOUNT +} CC1352P_4_LAUNCHXL_ADCBufName; + +/*! + * @def CC1352P_4_LAUNCHXL_ADCBuf0SourceName + * @brief Enum of ADCBuf channels + */ +typedef enum CC1352P_4_LAUNCHXL_ADCBuf0ChannelName { + CC1352P_4_LAUNCHXL_ADCBUF0CHANNEL0 = 0, + CC1352P_4_LAUNCHXL_ADCBUF0CHANNEL1, + CC1352P_4_LAUNCHXL_ADCBUF0CHANNEL2, + CC1352P_4_LAUNCHXL_ADCBUF0CHANNEL3, + CC1352P_4_LAUNCHXL_ADCBUF0CHANNEL4, + CC1352P_4_LAUNCHXL_ADCBUF0CHANNEL5, + CC1352P_4_LAUNCHXL_ADCBUF0CHANNEL6, + CC1352P_4_LAUNCHXL_ADCBUF0CHANNELVDDS, + CC1352P_4_LAUNCHXL_ADCBUF0CHANNELDCOUPL, + CC1352P_4_LAUNCHXL_ADCBUF0CHANNELVSS, + + CC1352P_4_LAUNCHXL_ADCBUF0CHANNELCOUNT +} CC1352P_4_LAUNCHXL_ADCBuf0ChannelName; + +/*! + * @def CC1352P_4_LAUNCHXL_ADCName + * @brief Enum of ADCs + */ +typedef enum CC1352P_4_LAUNCHXL_ADCName { + CC1352P_4_LAUNCHXL_ADC0 = 0, + CC1352P_4_LAUNCHXL_ADC1, + CC1352P_4_LAUNCHXL_ADC2, + CC1352P_4_LAUNCHXL_ADC3, + CC1352P_4_LAUNCHXL_ADC4, + CC1352P_4_LAUNCHXL_ADC5, + CC1352P_4_LAUNCHXL_ADC6, + CC1352P_4_LAUNCHXL_ADCDCOUPL, + CC1352P_4_LAUNCHXL_ADCVSS, + CC1352P_4_LAUNCHXL_ADCVDDS, + + CC1352P_4_LAUNCHXL_ADCCOUNT +} CC1352P_4_LAUNCHXL_ADCName; + +/*! + * @def CC1352P_4_LAUNCHXL_ECDHName + * @brief Enum of ECDH names + */ +typedef enum CC1352P_4_LAUNCHXL_ECDHName { + CC1352P_4_LAUNCHXL_ECDH0 = 0, + + CC1352P_4_LAUNCHXL_ECDHCOUNT +} CC1352P_4_LAUNCHXL_ECDHName; + +/*! + * @def CC1352P_4_LAUNCHXL_ECDSAName + * @brief Enum of ECDSA names + */ +typedef enum CC1352P_4_LAUNCHXL_ECDSAName { + CC1352P_4_LAUNCHXL_ECDSA0 = 0, + + CC1352P_4_LAUNCHXL_ECDSACOUNT +} CC1352P_4_LAUNCHXL_ECDSAName; + +/*! + * @def CC1352P_4_LAUNCHXL_ECJPAKEName + * @brief Enum of ECJPAKE names + */ +typedef enum CC1352P_4_LAUNCHXL_ECJPAKEName { + CC1352P_4_LAUNCHXL_ECJPAKE0 = 0, + + CC1352P_4_LAUNCHXL_ECJPAKECOUNT +} CC1352P_4_LAUNCHXL_ECJPAKEName; + +/*! + * @def CC1352P_4_LAUNCHXL_AESCCMName + * @brief Enum of AESCCM names + */ +typedef enum CC1352P_4_LAUNCHXL_AESCCMName { + CC1352P_4_LAUNCHXL_AESCCM0 = 0, + + CC1352P_4_LAUNCHXL_AESCCMCOUNT +} CC1352P_4_LAUNCHXL_AESCCMName; + +/*! + * @def CC1352P_4_LAUNCHXL_AESECBName + * @brief Enum of AESECB names + */ +typedef enum CC1352P_4_LAUNCHXL_AESECBName { + CC1352P_4_LAUNCHXL_AESECB0 = 0, + + CC1352P_4_LAUNCHXL_AESECBCOUNT +} CC1352P_4_LAUNCHXL_AESECBName; + +/*! + * @def CC1352P_4_LAUNCHXL_SHA2Name + * @brief Enum of SHA2 names + */ +typedef enum CC1352P_4_LAUNCHXL_SHA2Name { + CC1352P_4_LAUNCHXL_SHA20 = 0, + + CC1352P_4_LAUNCHXL_SHA2COUNT +} CC1352P_4_LAUNCHXL_SHA2Name; + +/*! + * @def CC1352P_4_LAUNCHXL_GPIOName + * @brief Enum of GPIO names + */ +typedef enum CC1352P_4_LAUNCHXL_GPIOName { + CC1352P_4_LAUNCHXL_GPIO_S1 = 0, + CC1352P_4_LAUNCHXL_GPIO_S2, + CC1352P_4_LAUNCHXL_SPI_MASTER_READY, + CC1352P_4_LAUNCHXL_SPI_SLAVE_READY, + CC1352P_4_LAUNCHXL_GPIO_LED_GREEN, + CC1352P_4_LAUNCHXL_GPIO_LED_RED, + CC1352P_4_LAUNCHXL_GPIO_SPI_FLASH_CS, + CC1352P_4_LAUNCHXL_GPIO_DIO_19, + CC1352P_4_LAUNCHXL_GPIO_LCD_CS, + CC1352P_4_LAUNCHXL_GPIO_LCD_ENABLE, + CC1352P_4_LAUNCHXL_GPIOCOUNT +} CC1352P_4_LAUNCHXL_GPIOName; + +/*! + * @def CC1352P_4_LAUNCHXL_GPTimerName + * @brief Enum of GPTimer parts + */ +typedef enum CC1352P_4_LAUNCHXL_GPTimerName { + CC1352P_4_LAUNCHXL_GPTIMER0A = 0, + CC1352P_4_LAUNCHXL_GPTIMER0B, + CC1352P_4_LAUNCHXL_GPTIMER1A, + CC1352P_4_LAUNCHXL_GPTIMER1B, + CC1352P_4_LAUNCHXL_GPTIMER2A, + CC1352P_4_LAUNCHXL_GPTIMER2B, + CC1352P_4_LAUNCHXL_GPTIMER3A, + CC1352P_4_LAUNCHXL_GPTIMER3B, + + CC1352P_4_LAUNCHXL_GPTIMERPARTSCOUNT +} CC1352P_4_LAUNCHXL_GPTimerName; + +/*! + * @def CC1352P_4_LAUNCHXL_GPTimers + * @brief Enum of GPTimers + */ +typedef enum CC1352P_4_LAUNCHXL_GPTimers { + CC1352P_4_LAUNCHXL_GPTIMER0 = 0, + CC1352P_4_LAUNCHXL_GPTIMER1, + CC1352P_4_LAUNCHXL_GPTIMER2, + CC1352P_4_LAUNCHXL_GPTIMER3, + + CC1352P_4_LAUNCHXL_GPTIMERCOUNT +} CC1352P_4_LAUNCHXL_GPTimers; + +/*! + * @def CC1352P_4_LAUNCHXL_I2CName + * @brief Enum of I2C names + */ +typedef enum CC1352P_4_LAUNCHXL_I2CName { + CC1352P_4_LAUNCHXL_I2C0 = 0, + + CC1352P_4_LAUNCHXL_I2CCOUNT +} CC1352P_4_LAUNCHXL_I2CName; + +/*! + * @def CC1352P_4_LAUNCHXL_NVSName + * @brief Enum of NVS names + */ +typedef enum CC1352P_4_LAUNCHXL_NVSName { +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH + CC1352P_4_LAUNCHXL_NVSCC26XX0 = 0, +#endif +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH + CC1352P_4_LAUNCHXL_NVSSPI25X0, +#endif + + CC1352P_4_LAUNCHXL_NVSCOUNT +} CC1352P_4_LAUNCHXL_NVSName; + +/*! + * @def CC1352P_4_LAUNCHXL_PWM + * @brief Enum of PWM outputs + */ +typedef enum CC1352P_4_LAUNCHXL_PWMName { + CC1352P_4_LAUNCHXL_PWM0 = 0, + CC1352P_4_LAUNCHXL_PWM1, + CC1352P_4_LAUNCHXL_PWM2, + CC1352P_4_LAUNCHXL_PWM3, + CC1352P_4_LAUNCHXL_PWM4, + CC1352P_4_LAUNCHXL_PWM5, + CC1352P_4_LAUNCHXL_PWM6, + CC1352P_4_LAUNCHXL_PWM7, + + CC1352P_4_LAUNCHXL_PWMCOUNT +} CC1352P_4_LAUNCHXL_PWMName; + +/*! + * @def CC1352P_4_LAUNCHXL_SDName + * @brief Enum of SD names + */ +typedef enum CC1352P_4_LAUNCHXL_SDName { + CC1352P_4_LAUNCHXL_SDSPI0 = 0, + + CC1352P_4_LAUNCHXL_SDCOUNT +} CC1352P_4_LAUNCHXL_SDName; + +/*! + * @def CC1352P_4_LAUNCHXL_SPIName + * @brief Enum of SPI names + */ +typedef enum CC1352P_4_LAUNCHXL_SPIName { + CC1352P_4_LAUNCHXL_SPI0 = 0, + CC1352P_4_LAUNCHXL_SPI1, + + CC1352P_4_LAUNCHXL_SPICOUNT +} CC1352P_4_LAUNCHXL_SPIName; + +/*! + * @def CC1352P_4_LAUNCHXL_UARTName + * @brief Enum of UARTs + */ +typedef enum CC1352P_4_LAUNCHXL_UARTName { + CC1352P_4_LAUNCHXL_UART0 = 0, + CC1352P_4_LAUNCHXL_UART1, + + CC1352P_4_LAUNCHXL_UARTCOUNT +} CC1352P_4_LAUNCHXL_UARTName; + +/*! + * @def CC1352P_4_LAUNCHXL_UDMAName + * @brief Enum of DMA buffers + */ +typedef enum CC1352P_4_LAUNCHXL_UDMAName { + CC1352P_4_LAUNCHXL_UDMA0 = 0, + + CC1352P_4_LAUNCHXL_UDMACOUNT +} CC1352P_4_LAUNCHXL_UDMAName; + +/*! + * @def CC1352P_4_LAUNCHXL_WatchdogName + * @brief Enum of Watchdogs + */ +typedef enum CC1352P_4_LAUNCHXL_WatchdogName { + CC1352P_4_LAUNCHXL_WATCHDOG0 = 0, + + CC1352P_4_LAUNCHXL_WATCHDOGCOUNT +} CC1352P_4_LAUNCHXL_WatchdogName; + + +#ifdef __cplusplus +} +#endif + +#endif /* __CC1352P_4_LAUNCHXL_BOARD_H__ */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/CC1352P_4_LAUNCHXL_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/CC1352P_4_LAUNCHXL_fxns.c new file mode 100644 index 000000000..8a703efe7 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/CC1352P_4_LAUNCHXL_fxns.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +/* + * ======== CC1352P_4_LAUNCHXL_fxns.c ======== + * This file contains the board-specific initialization functions, and + * RF callback function for antenna switching. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "Board.h" + +/* + * ======== CC1352P_4_LAUNCHXL_sendExtFlashByte ======== + */ +void CC1352P_4_LAUNCHXL_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) +{ + uint8_t i; + + /* SPI Flash CS */ + PIN_setOutputValue(pinHandle, IOID_20, 0); + + for (i = 0; i < 8; i++) { + PIN_setOutputValue(pinHandle, IOID_10, 0); /* SPI Flash CLK */ + + /* SPI Flash MOSI */ + PIN_setOutputValue(pinHandle, IOID_9, (byte >> (7 - i)) & 0x01); + PIN_setOutputValue(pinHandle, IOID_10, 1); /* SPI Flash CLK */ + + /* + * Waste a few cycles to keep the CLK high for at + * least 45% of the period. + * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. + */ + CPUdelay(8); + } + + PIN_setOutputValue(pinHandle, IOID_10, 0); /* CLK */ + PIN_setOutputValue(pinHandle, IOID_20, 1); /* CS */ + + /* + * Keep CS high at least 40 us + * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us + */ + CPUdelay(700); +} + +/* + * ======== CC1352P_4_LAUNCHXL_wakeUpExtFlash ======== + */ +void CC1352P_4_LAUNCHXL_wakeUpExtFlash(void) +{ + PIN_Config extFlashPinTable[] = { + /* SPI Flash CS */ + IOID_20 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + /* + * To wake up we need to toggle the chip select at + * least 20 ns and ten wait at least 35 us. + */ + + /* Toggle chip select for ~20ns to wake ext. flash */ + PIN_setOutputValue(extFlashPinHandle, IOID_20, 0); + /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ + CPUdelay(1); + PIN_setOutputValue(extFlashPinHandle, IOID_20, 1); + /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ + CPUdelay(560); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC1352P_4_LAUNCHXL_shutDownExtFlash ======== + */ +void CC1352P_4_LAUNCHXL_shutDownExtFlash(void) +{ + /* To be sure we are putting the flash into sleep and not waking it, we first have to make a wake up call */ + CC1352P_4_LAUNCHXL_wakeUpExtFlash(); + + PIN_Config extFlashPinTable[] = { + /* SPI Flash CS*/ + IOID_20 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash CLK */ + IOID_10 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash MOSI */ + IOID_9 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash MISO */ + IOID_8 | PIN_INPUT_EN | PIN_PULLDOWN, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + uint8_t extFlashShutdown = 0xB9; + + CC1352P_4_LAUNCHXL_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); + + PIN_close(extFlashPinHandle); +} + +/* + * For the SysConfig generated Board.h file, Board_RF_SUB1GHZ will not be + * defined unless the RF module is added to the configuration. Therefore, + * we don't include this code if Board_RF_SUB1GHZ is not defined. + */ +#if defined(Board_RF_SUB1GHZ) + +/* + * ======== Antenna switching ======== + */ +static PIN_Handle antennaPins; +static PIN_State antennaState; + +void initAntennaSwitch() +{ + PIN_Config antennaConfig[] = { + Board_RF_24GHZ | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Path disabled */ + Board_RF_HIGH_PA | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Path disabled */ + Board_RF_SUB1GHZ | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Path disabled */ + PIN_TERMINATE + }; + antennaPins = PIN_open(&antennaState, antennaConfig); +} + +/* + * ======== rfDriverCallback ======== + * Sets up the antenna switch depending on the current PHY configuration. + * Truth table: + * + * Path DIO28 DIO29 DIO30 + * =========== ===== ===== ===== + * Off 0 0 0 + * Sub-1 GHz 0 0 1 + * 2.4 GHz 1 0 0 + * 20 dBm TX 0 1 0 + */ +void rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void *arg) +{ + /* Switch off all paths first. Needs to be done anyway in every sub-case below. */ + PINCC26XX_setOutputValue(Board_RF_24GHZ, 0); + PINCC26XX_setOutputValue(Board_RF_HIGH_PA, 0); + PINCC26XX_setOutputValue(Board_RF_SUB1GHZ, 0); + + if (events & RF_GlobalEventRadioSetup) { + /* Decode the current PA configuration. */ + RF_TxPowerTable_PAType paType = (RF_TxPowerTable_PAType)RF_getTxPower(client).paType; + + /* Decode the generic argument as a setup command. */ + RF_RadioSetup* setupCommand = (RF_RadioSetup*)arg; + + if (setupCommand->common.commandNo == CMD_PROP_RADIO_DIV_SETUP) { + /* Sub-1 GHz */ + if (paType == RF_TxPowerTable_HighPA) { + /* PA enable --> HIGH PA + * LNA enable --> Sub-1 GHz + */ + PINCC26XX_setMux(antennaPins, Board_RF_24GHZ, PINCC26XX_MUX_GPIO); + // Note: RFC_GPO3 is a work-around because the RFC_GPO1 (PA enable signal) is sometimes not + // de-asserted on CC1352 Rev A. + PINCC26XX_setMux(antennaPins, Board_RF_HIGH_PA, PINCC26XX_MUX_RFC_GPO3); + PINCC26XX_setMux(antennaPins, Board_RF_SUB1GHZ, PINCC26XX_MUX_RFC_GPO0); + } else { + /* RF core active --> Sub-1 GHz */ + PINCC26XX_setMux(antennaPins, Board_RF_24GHZ, PINCC26XX_MUX_GPIO); + PINCC26XX_setMux(antennaPins, Board_RF_HIGH_PA, PINCC26XX_MUX_GPIO); + PINCC26XX_setMux(antennaPins, Board_RF_SUB1GHZ, PINCC26XX_MUX_GPIO); + PINCC26XX_setOutputValue(Board_RF_SUB1GHZ, 1); + } + } else { + /* 2.4 GHz */ + if (paType == RF_TxPowerTable_HighPA) + { + /* PA enable --> HIGH PA + * LNA enable --> 2.4 GHz + */ + PINCC26XX_setMux(antennaPins, Board_RF_24GHZ, PINCC26XX_MUX_RFC_GPO0); + // Note: RFC_GPO3 is a work-around because the RFC_GPO1 (PA enable signal) is sometimes not + // de-asserted on CC1352 Rev A. + PINCC26XX_setMux(antennaPins, Board_RF_HIGH_PA, PINCC26XX_MUX_RFC_GPO3); + PINCC26XX_setMux(antennaPins, Board_RF_SUB1GHZ, PINCC26XX_MUX_GPIO); + } else { + /* RF core active --> 2.4 GHz */ + PINCC26XX_setMux(antennaPins, Board_RF_24GHZ, PINCC26XX_MUX_GPIO); + PINCC26XX_setMux(antennaPins, Board_RF_HIGH_PA, PINCC26XX_MUX_GPIO); + PINCC26XX_setMux(antennaPins, Board_RF_SUB1GHZ, PINCC26XX_MUX_GPIO); + PINCC26XX_setOutputValue(Board_RF_24GHZ, 1); + } + } + } else { + /* Reset the IO multiplexer to GPIO functionality */ + PINCC26XX_setMux(antennaPins, Board_RF_24GHZ, PINCC26XX_MUX_GPIO); + PINCC26XX_setMux(antennaPins, Board_RF_HIGH_PA, PINCC26XX_MUX_GPIO); + PINCC26XX_setMux(antennaPins, Board_RF_SUB1GHZ, PINCC26XX_MUX_GPIO); + } +} +#endif + +/* + * ======== Board_initHook ======== + * Called by Board_init() to perform board-specific initialization. + */ +void Board_initHook() +{ +#if defined(Board_RF_SUB1GHZ) + initAntennaSwitch(); +#endif + + CC1352P_4_LAUNCHXL_shutDownExtFlash(); +} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/Makefile.cc1352p_4 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/Makefile.cc1352p_4 new file mode 100644 index 000000000..df7cb99a6 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/Makefile.cc1352p_4 @@ -0,0 +1,19 @@ +################################################################################ +# SimpleLink Device makefile + +SUBFAMILY = cc13x2-cc26x2 +DEVICE_FAMILY = CC13X2 +DEVICE_LINE = CC13XX + +BOARD_SOURCEFILES += CC1352P_4_LAUNCHXL.c CC1352P_4_LAUNCHXL_fxns.c + +SUPPORTS_PROP_MODE = 1 +SUPPORTS_IEEE_MODE = 1 + +SUPPORTS_HIGH_PA = 1 + +### Signal that we can be programmed with cc2538-bsl +BOARD_SUPPORTS_BSL = 0 + +# Include the common board makefile +include $(FAMILY_PATH)/launchpad/Makefile.launchpad diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h index b9e9ce7cf..9cc52d689 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h @@ -33,6 +33,8 @@ #ifndef __BOARD_H #define __BOARD_H +#define Board_CC1352R1_LAUNCHXL + #ifdef __cplusplus extern "C" { #endif @@ -75,6 +77,12 @@ extern "C" { #define Board_DIO29_ANALOG CC1352R1_LAUNCHXL_DIO29_ANALOG #define Board_DIO30_RFSW CC1352R1_LAUNCHXL_DIO30_RF_SUB1GHZ +/* + * Board_RF_SUB1GHZ is the name generated by SysConfig. Define it + * here so that RF callback function can reference it. + */ +#define Board_RF_SUB1GHZ CC1352R1_LAUNCHXL_DIO30_RF_SUB1GHZ + #define Board_GPIO_BUTTON0 CC1352R1_LAUNCHXL_GPIO_S1 #define Board_GPIO_BUTTON1 CC1352R1_LAUNCHXL_GPIO_S2 #define Board_GPIO_BTN1 CC1352R1_LAUNCHXL_GPIO_S1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c index 63547e44f..81d6c6e44 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c @@ -572,11 +572,8 @@ const uint_least8_t I2C_count = CC1352R1_LAUNCHXL_I2CCOUNT; #define NVS_REGIONS_BASE 0x48000 #define SECTORSIZE 0x2000 #define REGIONSIZE (SECTORSIZE * 4) -#define SPISECTORSIZE 0x1000 -#define SPIREGIONSIZE (SPISECTORSIZE * 32) -#define VERIFYBUFSIZE 64 -static uint8_t verifyBuf[VERIFYBUFSIZE]; +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH /* * Reserve flash sectors for NVS driver use by placing an uninitialized byte @@ -615,11 +612,10 @@ static char flashBuf[REGIONSIZE]; #endif -/* Allocate objects for NVS and NVS SPI */ +/* Allocate objects for NVS Internal Regions */ NVSCC26XX_Object nvsCC26xxObjects[1]; -NVSSPI25X_Object nvsSPI25XObjects[1]; -/* Hardware attributes for NVS */ +/* Hardware attributes for NVS Internal Regions */ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { { .regionBase = (void *)flashBuf, @@ -627,7 +623,20 @@ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { }, }; -/* Hardware attributes for NVS SPI */ +#endif /* Board_EXCLUDE_NVS_INTERNAL_FLASH */ + +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH + +#define SPISECTORSIZE 0x1000 +#define SPIREGIONSIZE (SPISECTORSIZE * 32) +#define VERIFYBUFSIZE 64 + +static uint8_t verifyBuf[VERIFYBUFSIZE]; + +/* Allocate objects for NVS External Regions */ +NVSSPI25X_Object nvsSPI25XObjects[1]; + +/* Hardware attributes for NVS External Regions */ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { { .regionBaseOffset = 0, @@ -642,18 +651,24 @@ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { }, }; +#endif /* Board_EXCLUDE_NVS_EXTERNAL_FLASH */ + /* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ const NVS_Config NVS_config[CC1352R1_LAUNCHXL_NVSCOUNT] = { +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH { .fxnTablePtr = &NVSCC26XX_fxnTable, .object = &nvsCC26xxObjects[0], .hwAttrs = &nvsCC26xxHWAttrs[0], }, +#endif +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH { .fxnTablePtr = &NVSSPI25X_fxnTable, .object = &nvsSPI25XObjects[0], .hwAttrs = &nvsSPI25XHWAttrs[0], }, +#endif }; const uint_least8_t NVS_count = CC1352R1_LAUNCHXL_NVSCOUNT; @@ -739,19 +754,24 @@ const uint_least8_t PWM_count = CC1352R1_LAUNCHXL_PWMCOUNT; #include /* - * Board-specific callback function to set the correct antenna path. + * Board-specific callback function to set the correct antenna path. * - * This function is called by the RF driver on global driver events. It contains - * a default implementation to set the correct antenna path. + * This function is called by the RF driver on global driver events. + * It contains a default implementation to set the correct antenna path. + * This function is defined in the file CC1352R1_LAUNCHXL_fxns.c */ -static void CC1352R1_LAUNCHXL_rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void *arg); +extern void rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void *arg); const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { - .hwiPriority = ~0, /* Lowest HWI priority */ - .swiPriority = 0, /* Lowest SWI priority */ - .xoscHfAlwaysNeeded = true, /* Keep XOSC dependency while in stanby */ - .globalCallback = &CC1352R1_LAUNCHXL_rfDriverCallback, /* Register the board specific callback */ - .globalEventMask = RF_GlobalEventRadioSetup | RF_GlobalEventRadioPowerDown /* Subscribe the callback to both events */ + .hwiPriority = ~0, /* Lowest HWI priority */ + .swiPriority = 0, /* Lowest SWI priority */ + .xoscHfAlwaysNeeded = true, /* Keep XOSC dependency while in stanby */ + + /* Register the board specific callback */ + .globalCallback = &rfDriverCallback, + + /* Subscribe the callback to both events */ + .globalEventMask = RF_GlobalEventRadioSetup | RF_GlobalEventRadioPowerDown }; /* @@ -951,89 +971,10 @@ const Watchdog_Config Watchdog_config[CC1352R1_LAUNCHXL_WATCHDOGCOUNT] = { const uint_least8_t Watchdog_count = CC1352R1_LAUNCHXL_WATCHDOGCOUNT; /* - * ======== CC1352R1_LAUNCHXL_wakeUpExtFlash ======== + * Board-specific initialization function to disable external flash. + * This function is defined in the file CC1352R1_LAUNCHXL_fxns.c */ -void CC1352R1_LAUNCHXL_wakeUpExtFlash(void) -{ - PIN_Config extFlashPinTable[] = { - CC1352R1_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - PIN_TERMINATE - }; - PIN_State extFlashPinState; - PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); - - /* - * To wake up we need to toggle the chip select at - * least 20 ns and ten wait at least 35 us. - */ - - /* Toggle chip select for ~20ns to wake ext. flash */ - PIN_setOutputValue(extFlashPinHandle, CC1352R1_LAUNCHXL_SPI_FLASH_CS, 0); - /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ - CPUdelay(1); - PIN_setOutputValue(extFlashPinHandle, CC1352R1_LAUNCHXL_SPI_FLASH_CS, 1); - /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ - CPUdelay(560); - - PIN_close(extFlashPinHandle); -} - -/* - * ======== CC1352R1_LAUNCHXL_sendExtFlashByte ======== - */ -void CC1352R1_LAUNCHXL_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) -{ - uint8_t i; - - PIN_setOutputValue(pinHandle, CC1352R1_LAUNCHXL_SPI_FLASH_CS, 0); - - for (i = 0; i < 8; i++) { - PIN_setOutputValue(pinHandle, CC1352R1_LAUNCHXL_SPI0_CLK, 0); - PIN_setOutputValue(pinHandle, CC1352R1_LAUNCHXL_SPI0_MOSI, (byte >> (7 - i)) & 0x01); - PIN_setOutputValue(pinHandle, CC1352R1_LAUNCHXL_SPI0_CLK, 1); - - /* - * Waste a few cycles to keep the CLK high for at - * least 45% of the period. - * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. - */ - CPUdelay(8); - } - - PIN_setOutputValue(pinHandle, CC1352R1_LAUNCHXL_SPI0_CLK, 0); - PIN_setOutputValue(pinHandle, CC1352R1_LAUNCHXL_SPI_FLASH_CS, 1); - - /* - * Keep CS high at least 40 us - * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us - */ - CPUdelay(700); -} - -/* - * ======== CC1352R1_LAUNCHXL_shutDownExtFlash ======== - */ -void CC1352R1_LAUNCHXL_shutDownExtFlash(void) -{ - /* To be sure we are putting the flash into sleep and not waking it, we first have to make a wake up call */ - CC1352R1_LAUNCHXL_wakeUpExtFlash(); - - PIN_Config extFlashPinTable[] = { - CC1352R1_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - CC1352R1_LAUNCHXL_SPI0_CLK | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - CC1352R1_LAUNCHXL_SPI0_MOSI | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - CC1352R1_LAUNCHXL_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, - PIN_TERMINATE - }; - PIN_State extFlashPinState; - PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); - - uint8_t extFlashShutdown = 0xB9; - - CC1352R1_LAUNCHXL_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); - - PIN_close(extFlashPinHandle); -} +extern void Board_initHook(void); /* * ======== CC1352R1_LAUNCHXL_initGeneral ======== @@ -1047,26 +988,6 @@ void CC1352R1_LAUNCHXL_initGeneral(void) while (1); } - /* Shut down external flash as default */ - CC1352R1_LAUNCHXL_shutDownExtFlash(); -} - -/* - * ======== CC1352R1_LAUNCHXL_rfDriverCallback ======== - * This is an implementation for the CC1352R1 launchpad which uses a - * single signal for antenna switching. - */ -void CC1352R1_LAUNCHXL_rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void *arg) -{ - (void)client; - RF_RadioSetup* setupCommand = (RF_RadioSetup*)arg; - - if ((events & RF_GlobalEventRadioSetup) - && (setupCommand->common.commandNo == CMD_PROP_RADIO_DIV_SETUP)) { - /* Sub-1 GHz, requires antenna switch high */ - PINCC26XX_setOutputValue(CC1352R1_LAUNCHXL_DIO30_RF_SUB1GHZ, 1); - } else if (events & RF_GlobalEventRadioPowerDown) { - /* Disable antenna switch to save current */ - PINCC26XX_setOutputValue(CC1352R1_LAUNCHXL_DIO30_RF_SUB1GHZ, 0); - } + /* Perform board-specific initialization */ + Board_initHook(); } diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h index 104c36be2..0f165943b 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h @@ -340,8 +340,12 @@ typedef enum CC1352R1_LAUNCHXL_I2CName { * @brief Enum of NVS names */ typedef enum CC1352R1_LAUNCHXL_NVSName { +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH CC1352R1_LAUNCHXL_NVSCC26XX0 = 0, +#endif +#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH CC1352R1_LAUNCHXL_NVSSPI25X0, +#endif CC1352R1_LAUNCHXL_NVSCOUNT } CC1352R1_LAUNCHXL_NVSName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL_fxns.c new file mode 100644 index 000000000..9ee574235 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL_fxns.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +/* + * ======== CC1352R1_LAUNCHXL_fxns.c ======== + * This file contains the board-specific initialization functions, and + * RF callback function for antenna switching. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "Board.h" + +/* + * ======== CC1352R1_LAUNCHXL_sendExtFlashByte ======== + */ +void CC1352R1_LAUNCHXL_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) +{ + uint8_t i; + + /* SPI Flash CS */ + PIN_setOutputValue(pinHandle, IOID_20, 0); + + for (i = 0; i < 8; i++) { + PIN_setOutputValue(pinHandle, IOID_10, 0); /* SPI Flash CLK */ + + /* SPI Flash MOSI */ + PIN_setOutputValue(pinHandle, IOID_9, (byte >> (7 - i)) & 0x01); + PIN_setOutputValue(pinHandle, IOID_10, 1); /* SPI Flash CLK */ + + /* + * Waste a few cycles to keep the CLK high for at + * least 45% of the period. + * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. + */ + CPUdelay(8); + } + + PIN_setOutputValue(pinHandle, IOID_10, 0); /* CLK */ + PIN_setOutputValue(pinHandle, IOID_20, 1); /* CS */ + + /* + * Keep CS high at least 40 us + * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us + */ + CPUdelay(700); +} + +/* + * ======== CC1352R1_LAUNCHXL_wakeUpExtFlash ======== + */ +void CC1352R1_LAUNCHXL_wakeUpExtFlash(void) +{ + PIN_Config extFlashPinTable[] = { + /* SPI Flash CS */ + IOID_20 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + /* + * To wake up we need to toggle the chip select at + * least 20 ns and ten wait at least 35 us. + */ + + /* Toggle chip select for ~20ns to wake ext. flash */ + PIN_setOutputValue(extFlashPinHandle, IOID_20, 0); + /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ + CPUdelay(1); + PIN_setOutputValue(extFlashPinHandle, IOID_20, 1); + /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ + CPUdelay(560); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC1352R1_LAUNCHXL_shutDownExtFlash ======== + */ +void CC1352R1_LAUNCHXL_shutDownExtFlash(void) +{ + /* + * To be sure we are putting the flash into sleep and not waking it, + * we first have to make a wake up call + */ + CC1352R1_LAUNCHXL_wakeUpExtFlash(); + + PIN_Config extFlashPinTable[] = { + /* SPI Flash CS*/ + IOID_20 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash CLK */ + IOID_10 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash MOSI */ + IOID_9 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash MISO */ + IOID_8 | PIN_INPUT_EN | PIN_PULLDOWN, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + uint8_t extFlashShutdown = 0xB9; + + CC1352R1_LAUNCHXL_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== Board_initHook ======== + * Called by Board_init() to perform board-specific initialization. + */ +void Board_initHook() +{ + CC1352R1_LAUNCHXL_shutDownExtFlash(); +} + +/* + * For the SysConfig generated Board.h file, Board_RF_SUB1GHZ will not be + * defined unless the RF module is added to the configuration. Therefore, + * we don't include this code if Board_RF_SUB1GHZ is not defined. + */ +#if defined(Board_RF_SUB1GHZ) + +/* + * ======== rfDriverCallback ======== + * This is an implementation for the CC1352R1 launchpad which uses a + * single signal for antenna switching. + */ +void rfDriverCallback(RF_Handle client, RF_GlobalEvent events, void *arg) +{ + (void)client; + RF_RadioSetup* setupCommand = (RF_RadioSetup*)arg; + + if ((events & RF_GlobalEventRadioSetup) && + (setupCommand->common.commandNo == CMD_PROP_RADIO_DIV_SETUP)) { + /* Sub-1 GHz, requires antenna switch high */ + PINCC26XX_setOutputValue(Board_RF_SUB1GHZ, 1); + } + else if (events & RF_GlobalEventRadioPowerDown) { + /* Disable antenna switch to save current */ + PINCC26XX_setOutputValue(Board_RF_SUB1GHZ, 0); + } +} +#endif diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 index fe99fd680..272482360 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 @@ -3,8 +3,9 @@ SUBFAMILY = cc13x2-cc26x2 DEVICE_FAMILY = CC13X2 +DEVICE_LINE = CC13XX -BOARD_SOURCEFILES += CC1352R1_LAUNCHXL.c +BOARD_SOURCEFILES += CC1352R1_LAUNCHXL.c CC1352R1_LAUNCHXL_fxns.c SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL_fxns.c new file mode 100644 index 000000000..5562bd0a0 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL_fxns.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +/* + * ======== CC2650_LAUNCHXL_fxns.c ======== + * This file contains the board-specific initialization functions. + */ + +#include +#include +#include + +#include +#include + +#include + +#include "Board.h" + +/* + * ======== CC2650_LAUNCHXL_sendExtFlashByte ======== + */ +void CC2650_LAUNCHXL_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) +{ + uint8_t i; + + /* SPI Flash CS */ + PIN_setOutputValue(pinHandle, IOID_20, 0); + + for (i = 0; i < 8; i++) { + PIN_setOutputValue(pinHandle, IOID_10, 0); /* SPI Flash CLK */ + + /* SPI Flash MOSI */ + PIN_setOutputValue(pinHandle, IOID_9, (byte >> (7 - i)) & 0x01); + PIN_setOutputValue(pinHandle, IOID_10, 1); /* SPI Flash CLK */ + + /* + * Waste a few cycles to keep the CLK high for at + * least 45% of the period. + * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. + */ + CPUdelay(8); + } + + PIN_setOutputValue(pinHandle, IOID_10, 0); /* CLK */ + PIN_setOutputValue(pinHandle, IOID_20, 1); /* CS */ + + /* + * Keep CS high at least 40 us + * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us + */ + CPUdelay(700); +} + +/* + * ======== CC2650_LAUNCHXL_wakeUpExtFlash ======== + */ +void CC2650_LAUNCHXL_wakeUpExtFlash(void) +{ + PIN_Config extFlashPinTable[] = { + /* SPI Flash CS */ + IOID_20 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + /* + * To wake up we need to toggle the chip select at + * least 20 ns and ten wait at least 35 us. + */ + + /* Toggle chip select for ~20ns to wake ext. flash */ + PIN_setOutputValue(extFlashPinHandle, IOID_20, 0); + /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ + CPUdelay(1); + PIN_setOutputValue(extFlashPinHandle, IOID_20, 1); + /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ + CPUdelay(560); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC2650_LAUNCHXL_shutDownExtFlash ======== + */ +void CC2650_LAUNCHXL_shutDownExtFlash(void) +{ + /* + * To be sure we are putting the flash into sleep and not waking it, + * we first have to make a wake up call + */ + CC2650_LAUNCHXL_wakeUpExtFlash(); + + PIN_Config extFlashPinTable[] = { + /* SPI Flash CS*/ + IOID_20 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash CLK */ + IOID_10 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash MOSI */ + IOID_9 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash MISO */ + IOID_8 | PIN_INPUT_EN | PIN_PULLDOWN, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + uint8_t extFlashShutdown = 0xB9; + + CC2650_LAUNCHXL_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== Board_initHook ======== + * Called by Board_init() to perform board-specific initialization. + */ +void Board_initHook() +{ + CC2650_LAUNCHXL_shutDownExtFlash(); +} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Makefile.cc2650 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Makefile.cc2650 index 8236f6360..19d47535f 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Makefile.cc2650 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Makefile.cc2650 @@ -3,8 +3,9 @@ SUBFAMILY = cc13x0-cc26x0 DEVICE_FAMILY = CC26X0 +DEVICE_LINE = CC26XX -BOARD_SOURCEFILES += CC2650_LAUNCHXL.c +BOARD_SOURCEFILES += CC2650_LAUNCHXL.c CC2650_LAUNCHXL_fxns.c SUPPORTS_PROP_MODE = 0 SUPPORTS_IEEE_MODE = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL_fxns.c new file mode 100644 index 000000000..6c288ab0b --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL_fxns.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +/* + * =================== CC26X2R1_LAUNCHXL_fxns.c ============================ + * This file contains the board-specific initialization functions. + */ + +#include +#include +#include + +#include +#include + +#include + +#include "Board.h" + +/* + * ======== CC26X2R1_LAUNCHXL_sendExtFlashByte ======== + */ +void CC26X2R1_LAUNCHXL_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) +{ + uint8_t i; + + /* SPI Flash CS */ + PIN_setOutputValue(pinHandle, IOID_20, 0); + + for (i = 0; i < 8; i++) { + PIN_setOutputValue(pinHandle, IOID_10, 0); /* SPI Flash CLK */ + + /* SPI Flash MOSI */ + PIN_setOutputValue(pinHandle, IOID_9, (byte >> (7 - i)) & 0x01); + PIN_setOutputValue(pinHandle, IOID_10, 1); /* SPI Flash CLK */ + + /* + * Waste a few cycles to keep the CLK high for at + * least 45% of the period. + * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. + */ + CPUdelay(8); + } + + PIN_setOutputValue(pinHandle, IOID_10, 0); /* CLK */ + PIN_setOutputValue(pinHandle, IOID_20, 1); /* CS */ + + /* + * Keep CS high at least 40 us + * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us + */ + CPUdelay(700); +} + +/* + * ======== CC26X2R1_LAUNCHXL_wakeUpExtFlash ======== + */ +void CC26X2R1_LAUNCHXL_wakeUpExtFlash(void) +{ + PIN_Config extFlashPinTable[] = { + /* SPI Flash CS */ + IOID_20 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + /* + * To wake up we need to toggle the chip select at + * least 20 ns and ten wait at least 35 us. + */ + + /* Toggle chip select for ~20ns to wake ext. flash */ + PIN_setOutputValue(extFlashPinHandle, IOID_20, 0); + /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ + CPUdelay(1); + PIN_setOutputValue(extFlashPinHandle, IOID_20, 1); + /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ + CPUdelay(560); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC26X2R1_LAUNCHXL_shutDownExtFlash ======== + */ +void CC26X2R1_LAUNCHXL_shutDownExtFlash(void) +{ + /* + * To be sure we are putting the flash into sleep and not waking it, + * we first have to make a wake up call + */ + CC26X2R1_LAUNCHXL_wakeUpExtFlash(); + + PIN_Config extFlashPinTable[] = { + /* SPI Flash CS*/ + IOID_20 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash CLK */ + IOID_10 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash MOSI */ + IOID_9 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash MISO */ + IOID_8 | PIN_INPUT_EN | PIN_PULLDOWN, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + uint8_t extFlashShutdown = 0xB9; + + CC26X2R1_LAUNCHXL_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== Board_initHook ======== + * Called by Board_init() to perform board-specific initialization. + */ +void Board_initHook() +{ + CC26X2R1_LAUNCHXL_shutDownExtFlash(); +} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Makefile.cc26x2r1 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Makefile.cc26x2r1 index c1ef73bb4..f1e64bac3 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Makefile.cc26x2r1 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Makefile.cc26x2r1 @@ -3,8 +3,9 @@ SUBFAMILY = cc13x2-cc26x2 DEVICE_FAMILY = CC26X2 +DEVICE_LINE = CC26XX -BOARD_SOURCEFILES += CC26X2R1_LAUNCHXL.c +BOARD_SOURCEFILES += CC26X2R1_LAUNCHXL.c CC26X2R1_LAUNCHXL_fxns.c SUPPORTS_PROP_MODE = 0 SUPPORTS_IEEE_MODE = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/Makefile.sensortag b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/Makefile.sensortag index 49d892f54..42d91898e 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/Makefile.sensortag +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/Makefile.sensortag @@ -3,8 +3,14 @@ BOARD_TYPE = BOARD_SENSORTAG +PLATFORM_HAS_BUTTON = 1 + # leds-arch.c/h etc. BOARD_SOURCEFILES += sensortag.c sensortag-sensors.c BOARD_SOURCEFILES += button-sensor-arch.c leds-arch.c +BOARD_SOURCEFILES += bmp-280-sensor.c hdc-1000-sensor.c +BOARD_SOURCEFILES += mpu-9250-sensor.c opt-3001-sensor.c +BOARD_SOURCEFILES += reed-relay.c tmp-007-sensor.c +BOARD_SOURCEFILES += buzzer.c TARGET_FAMILY_DIRS += sensortag \ No newline at end of file diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c index e27a54610..c13c520eb 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c @@ -38,15 +38,16 @@ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "lib/sensors.h" -#include "bmp-280-sensor.h" #include "sys/ctimer.h" -#include "sensor-common.h" -#include "board-i2c.h" -#include "ti-lib.h" - +/*---------------------------------------------------------------------------*/ +#include +#include +/*---------------------------------------------------------------------------*/ +#include "bmp-280-sensor.h" +/*---------------------------------------------------------------------------*/ +#include #include #include -#include /*---------------------------------------------------------------------------*/ #define DEBUG 0 #if DEBUG @@ -55,7 +56,11 @@ #define PRINTF(...) #endif /*---------------------------------------------------------------------------*/ -#define BMP280_I2C_ADDRESS 0x77 +#ifndef Board_BMP280_ADDR +# error "Board file doesn't define I2C address Board_BMP280_ADDR" +#endif +/* Sensor I2C address */ +#define BMP280_I2C_ADDRESS Board_BMP280_ADDR /*---------------------------------------------------------------------------*/ /* Registers */ #define ADDR_CALIB 0x88 @@ -105,35 +110,33 @@ #define OSRST(v) ((v) << 5) #define OSRSP(v) ((v) << 2) /*---------------------------------------------------------------------------*/ -typedef struct bmp_280_calibration { +typedef struct { uint16_t dig_t1; - int16_t dig_t2; - int16_t dig_t3; + int16_t dig_t2; + int16_t dig_t3; uint16_t dig_p1; - int16_t dig_p2; - int16_t dig_p3; - int16_t dig_p4; - int16_t dig_p5; - int16_t dig_p6; - int16_t dig_p7; - int16_t dig_p8; - int16_t dig_p9; - int32_t t_fine; -} bmp_280_calibration_t; + int16_t dig_p2; + int16_t dig_p3; + int16_t dig_p4; + int16_t dig_p5; + int16_t dig_p6; + int16_t dig_p7; + int16_t dig_p8; + int16_t dig_p9; +} BMP_280_Calibration; /*---------------------------------------------------------------------------*/ -static uint8_t calibration_data[CALIB_DATA_SIZE]; +static BMP_280_Calibration calib_data; /*---------------------------------------------------------------------------*/ -#define SENSOR_STATUS_DISABLED 0 -#define SENSOR_STATUS_INITIALISED 1 -#define SENSOR_STATUS_NOT_READY 2 -#define SENSOR_STATUS_READY 3 +static I2C_Handle i2cHandle; +/*---------------------------------------------------------------------------*/ +typedef enum { + SENSOR_STATUS_DISABLED, + SENSOR_STATUS_INITIALISED, + SENSOR_STATUS_NOT_READY, + SENSOR_STATUS_READY +} SENSOR_STATUS; -static int enabled = SENSOR_STATUS_DISABLED; -/*---------------------------------------------------------------------------*/ -/* A buffer for the raw reading from the sensor */ -#define SENSOR_DATA_BUF_SIZE 6 - -static uint8_t sensor_value[SENSOR_DATA_BUF_SIZE]; +static volatile SENSOR_STATUS sensor_status = SENSOR_STATUS_DISABLED; /*---------------------------------------------------------------------------*/ /* Wait SENSOR_STARTUP_DELAY clock ticks for the sensor to be ready - ~80ms */ #define SENSOR_STARTUP_DELAY 3 @@ -141,35 +144,60 @@ static uint8_t sensor_value[SENSOR_DATA_BUF_SIZE]; static struct ctimer startup_timer; /*---------------------------------------------------------------------------*/ static void -notify_ready(void *not_used) +notify_ready(void *unused) { - enabled = SENSOR_STATUS_READY; + (void)unused; + + sensor_status = SENSOR_STATUS_READY; sensors_changed(&bmp_280_sensor); } /*---------------------------------------------------------------------------*/ -static void -select_on_bus(void) +static bool +i2c_write_read(void *writeBuf, size_t writeCount, void *readBuf, size_t readCount) { - /* Set up I2C */ - board_i2c_select(BOARD_I2C_INTERFACE_0, BMP280_I2C_ADDRESS); + I2C_Transaction i2cTransaction = { + .writeBuf = writeBuf, + .writeCount = writeCount, + .readBuf = readBuf, + .readCount = readCount, + .slaveAddress = BMP280_I2C_ADDRESS, + }; + + return I2C_transfer(i2cHandle, &i2cTransaction); } + +#define i2c_write(writeBuf, writeCount) i2c_write_read(writeBuf, writeCount, NULL, 0) +#define i2c_read(readBuf, readCount) i2c_write_read(NULL, 0, readBuf, readCount) /*---------------------------------------------------------------------------*/ /** * \brief Initalise the sensor + * + * @return true if success; else, false on error */ -static void +static bool init(void) { - uint8_t val; + if (i2cHandle) { + return true; + } - select_on_bus(); + I2C_Params i2cParams; + I2C_Params_init(&i2cParams); + i2cParams.transferMode = I2C_MODE_BLOCKING; + i2cParams.bitRate = I2C_400kHz; + + i2cHandle = I2C_open(Board_I2C0, &i2cParams); + if (i2cHandle == NULL) { + return false; + } + + uint8_t reset_data[] = { ADDR_RESET, VAL_RESET_EXECUTE }; /* Read and store calibration data */ - sensor_common_read_reg(ADDR_CALIB, calibration_data, CALIB_DATA_SIZE); - - /* Reset the sensor */ - val = VAL_RESET_EXECUTE; - sensor_common_write_reg(ADDR_RESET, &val, sizeof(val)); + uint8_t calib_reg = ADDR_CALIB; + return i2c_write_read(&calib_reg, sizeof(calib_reg), &calib_data, sizeof(calib_data)) + /* then reset the sensor */ + && i2c_write(reset_data, sizeof(reset_data)); } /*---------------------------------------------------------------------------*/ /** @@ -178,20 +206,15 @@ init(void) * * @return none */ -static void +static bool enable_sensor(bool enable) { - uint8_t val; + uint8_t val = (enable) + ? PM_FORCED | OSRSP(1) | OSRST(1) + : PM_OFF; - select_on_bus(); - - if(enable) { - /* Enable forced mode */ - val = PM_FORCED | OSRSP(1) | OSRST(1); - } else { - val = PM_OFF; - } - sensor_common_write_reg(ADDR_CTRL_MEAS, &val, sizeof(val)); + uint8_t ctrl_meas_data[] = { ADDR_CTRL_MEAS, val }; + return i2c_write(&ctrl_meas_data, sizeof(ctrl_meas_data)); } /*---------------------------------------------------------------------------*/ /** @@ -201,18 +224,10 @@ enable_sensor(bool enable) * \return True if valid data could be retrieved */ static bool -read_data(uint8_t *data) +read_data(uint8_t *data, size_t count) { - bool success; - - select_on_bus(); - - success = sensor_common_read_reg(ADDR_PRESS_MSB, data, MEAS_DATA_SIZE); - if(!success) { - sensor_common_set_error_data(data, MEAS_DATA_SIZE); - } - - return success; + uint8_t press_msb_reg = ADDR_PRESS_MSB; + return i2c_write_read(&press_msb_reg, sizeof(press_msb_reg), data, count); } /*---------------------------------------------------------------------------*/ /** @@ -226,60 +241,97 @@ read_data(uint8_t *data) static void convert(uint8_t *data, int32_t *temp, uint32_t *press) { - int32_t utemp, upress; - bmp_280_calibration_t *p = (bmp_280_calibration_t *)calibration_data; - int32_t v_x1_u32r; - int32_t v_x2_u32r; - int32_t temperature; - uint32_t pressure; + BMP_280_Calibration *p = &calib_data; /* Pressure */ - upress = (int32_t)((((uint32_t)(data[0])) << 12) - | (((uint32_t)(data[1])) << 4) | ((uint32_t)data[2] >> 4)); - + const int32_t upress = (int32_t)( + (((uint32_t)data[0]) << 12) | + (((uint32_t)data[1]) << 4) | + (((uint32_t)data[2]) >> 4) + ); /* Temperature */ - utemp = (int32_t)((((uint32_t)(data[3])) << 12) | (((uint32_t)(data[4])) << 4) - | ((uint32_t)data[5] >> 4)); + const int32_t utemp = (int32_t)( + (((uint32_t)data[3]) << 12) | + (((uint32_t)data[4]) << 4) | + (((uint32_t)data[5]) >> 4) + ); /* Compensate temperature */ - v_x1_u32r = ((((utemp >> 3) - ((int32_t)p->dig_t1 << 1))) - * ((int32_t)p->dig_t2)) >> 11; - v_x2_u32r = (((((utemp >> 4) - ((int32_t)p->dig_t1)) - * ((utemp >> 4) - ((int32_t)p->dig_t1))) >> 12) - * ((int32_t)p->dig_t3)) - >> 14; - p->t_fine = v_x1_u32r + v_x2_u32r; - temperature = (p->t_fine * 5 + 128) >> 8; + int32_t v_x1_u32r = ( ( + (utemp >> 3) - ((int32_t)p->dig_t1 << 1) + ) * (int32_t)p->dig_t2 + ) >> 11; + int32_t v_x2_u32r = ( ( ( ( + (utemp >> 4) - (int32_t)p->dig_t1 + ) * ( + (utemp >> 4) - (int32_t)p->dig_t1 + ) + ) >> 12 + ) * (int32_t)p->dig_t3 + ) >> 14; + + const uint32_t t_fine = v_x1_u32r + v_x2_u32r; + const int32_t temperature = (t_fine * 5 + 128) >> 8; *temp = temperature; /* Compensate pressure */ - v_x1_u32r = (((int32_t)p->t_fine) >> 1) - (int32_t)64000; - v_x2_u32r = (((v_x1_u32r >> 2) * (v_x1_u32r >> 2)) >> 11) - * ((int32_t)p->dig_p6); - v_x2_u32r = v_x2_u32r + ((v_x1_u32r * ((int32_t)p->dig_p5)) << 1); - v_x2_u32r = (v_x2_u32r >> 2) + (((int32_t)p->dig_p4) << 16); - v_x1_u32r = - (((p->dig_p3 * (((v_x1_u32r >> 2) * (v_x1_u32r >> 2)) >> 13)) >> 3) - + ((((int32_t)p->dig_p2) * v_x1_u32r) >> 1)) >> 18; - v_x1_u32r = ((((32768 + v_x1_u32r)) * ((int32_t)p->dig_p1)) >> 15); + v_x1_u32r = ((int32_t)t_fine >> 1) - (int32_t)64000; + v_x2_u32r = ( ( + (v_x1_u32r >> 2) * (v_x1_u32r >> 2) + ) >> 11 + ) * (int32_t)p->dig_p6; + v_x2_u32r = ( ( + v_x1_u32r * (int32_t)p->dig_p5 + ) << 1 + ) + v_x2_u32r; + v_x2_u32r = (v_x2_u32r >> 2) + ((int32_t)p->dig_p4 << 16); + v_x1_u32r = ( ( ( ( ( + (v_x1_u32r >> 2) * (v_x1_u32r >> 2) + ) >> 13 + ) * p->dig_p3 + ) >> 3 + ) + ( ( + (int32_t)p->dig_p2 * v_x1_u32r + ) >> 1 + ) + ) >> 18; + v_x1_u32r = ( + (32768 + v_x1_u32r) * (int32_t)p->dig_p1 + ) >> 15; - if(v_x1_u32r == 0) { - return; /* Avoid exception caused by division by zero */ + if (v_x1_u32r == 0) { + /* Avoid exception caused by division by zero */ + *press = 0; + return; } - pressure = (((uint32_t)(((int32_t)1048576) - upress) - (v_x2_u32r >> 12))) - * 3125; - if(pressure < 0x80000000) { - pressure = (pressure << 1) / ((uint32_t)v_x1_u32r); + uint32_t pressure = ( ( + (uint32_t)((int32_t)1048576 - upress) + ) - ( + v_x2_u32r >> 12 + ) + ) * 3125; + if ((int32_t)pressure < 0) { + pressure = (pressure << 1) / (uint32_t)v_x1_u32r; } else { pressure = (pressure / (uint32_t)v_x1_u32r) * 2; } - v_x1_u32r = (((int32_t)p->dig_p9) - * ((int32_t)(((pressure >> 3) * (pressure >> 3)) >> 13))) >> 12; - v_x2_u32r = (((int32_t)(pressure >> 2)) * ((int32_t)p->dig_p8)) >> 13; - pressure = (uint32_t)((int32_t)pressure - + ((v_x1_u32r + v_x2_u32r + p->dig_p7) >> 4)); + v_x1_u32r = ( ( + (int32_t)( ( + (pressure >> 3) * (pressure >> 3) + ) >> 13 + ) + ) * (int32_t)p->dig_p9 + ) >> 12; + v_x2_u32r = ( + (int32_t)(pressure >> 2) * (int32_t)p->dig_p8 + ) >> 13; + pressure = (uint32_t)( ( ( + v_x1_u32r + v_x2_u32r + p->dig_p7 + ) >> 4 + ) + (int32_t)pressure + ); *press = pressure; } @@ -292,25 +344,23 @@ convert(uint8_t *data, int32_t *temp, uint32_t *press) static int value(int type) { - int rv; int32_t temp = 0; uint32_t pres = 0; - if(enabled != SENSOR_STATUS_READY) { - PRINTF("Sensor disabled or starting up (%d)\n", enabled); - return CC26XX_SENSOR_READING_ERROR; + if (sensor_status != SENSOR_STATUS_READY) { + PRINTF("Sensor disabled or starting up (%d)\n", sensor_status); + return BMP_280_READING_ERROR; } - if((type != BMP_280_SENSOR_TYPE_TEMP) && type != BMP_280_SENSOR_TYPE_PRESS) { - PRINTF("Invalid type\n"); - return CC26XX_SENSOR_READING_ERROR; - } else { - memset(sensor_value, 0, SENSOR_DATA_BUF_SIZE); + /* A buffer for the raw reading from the sensor */ + uint8_t sensor_value[MEAS_DATA_SIZE]; - rv = read_data(sensor_value); - - if(rv == 0) { - return CC26XX_SENSOR_READING_ERROR; + switch (type) { + case BMP_280_SENSOR_TYPE_TEMP: + case BMP_280_SENSOR_TYPE_PRESS: + memset(sensor_value, 0, MEAS_DATA_SIZE); + if (!read_data(sensor_value, MEAS_DATA_SIZE)) { + return BMP_280_READING_ERROR; } PRINTF("val: %02x%02x%02x %02x%02x%02x\n", @@ -320,12 +370,17 @@ value(int type) convert(sensor_value, &temp, &pres); if(type == BMP_280_SENSOR_TYPE_TEMP) { - rv = (int)temp; + return (int)temp; } else if(type == BMP_280_SENSOR_TYPE_PRESS) { - rv = (int)pres; + return (int)pres; + } else { + return 0; } + + default: + PRINTF("Invalid BMP 208 Sensor Type\n"); + return BMP_280_READING_ERROR; } - return rv; } /*---------------------------------------------------------------------------*/ /** @@ -343,29 +398,34 @@ configure(int type, int enable) { switch(type) { case SENSORS_HW_INIT: - enabled = SENSOR_STATUS_INITIALISED; - init(); - enable_sensor(0); + if (init()) { + enable_sensor(false); + sensor_status = SENSOR_STATUS_INITIALISED; + } else { + sensor_status = SENSOR_STATUS_DISABLED; + } break; + case SENSORS_ACTIVE: /* Must be initialised first */ - if(enabled == SENSOR_STATUS_DISABLED) { - return SENSOR_STATUS_DISABLED; + if (sensor_status == SENSOR_STATUS_DISABLED) { + break; } - if(enable) { - enable_sensor(1); + if (enable) { + enable_sensor(true); ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready, NULL); - enabled = SENSOR_STATUS_NOT_READY; + sensor_status = SENSOR_STATUS_NOT_READY; } else { ctimer_stop(&startup_timer); - enable_sensor(0); - enabled = SENSOR_STATUS_INITIALISED; + enable_sensor(false); + sensor_status = SENSOR_STATUS_INITIALISED; } break; + default: break; } - return enabled; + return sensor_status; } /*---------------------------------------------------------------------------*/ /** @@ -379,8 +439,7 @@ status(int type) switch(type) { case SENSORS_ACTIVE: case SENSORS_READY: - return enabled; - break; + return sensor_status; default: break; } diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.h index 0047aaa9a..2c2735ed9 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.h @@ -55,8 +55,14 @@ #ifndef BMP_280_SENSOR_H_ #define BMP_280_SENSOR_H_ /*---------------------------------------------------------------------------*/ -#define BMP_280_SENSOR_TYPE_TEMP 1 -#define BMP_280_SENSOR_TYPE_PRESS 2 +#include "lib/sensors.h" +/*---------------------------------------------------------------------------*/ +typedef enum { + BMP_280_SENSOR_TYPE_TEMP, + BMP_280_SENSOR_TYPE_PRESS +} BMP_280_SENSOR_TYPE; +/*---------------------------------------------------------------------------*/ +#define BMP_280_READING_ERROR -1 /*---------------------------------------------------------------------------*/ extern const struct sensors_sensor bmp_280_sensor; /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-i2c.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-i2c.c deleted file mode 100644 index cc30e0fb0..000000000 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-i2c.c +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * Copyright (c) 2017, University of Bristol - http://www.bris.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 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. - */ -/*---------------------------------------------------------------------------*/ -/** - * \addtogroup sensortag-cc26xx-i2c - * @{ - * - * \file - * Board-specific I2C driver for the Sensortags - */ -/*---------------------------------------------------------------------------*/ -#include "contiki.h" -#include "ti-lib.h" -#include "board-i2c.h" -#include "lpm.h" -#include "rtimer.h" - -#include -#include -/*---------------------------------------------------------------------------*/ -#define I2C_MAX_WAIT_TIME (RTIMER_SECOND / 10) - -#define LIMITED_BUSYWAIT(cond) do { \ - rtimer_clock_t end_time = RTIMER_NOW() + I2C_MAX_WAIT_TIME; \ - while(cond) { \ - if(!RTIMER_CLOCK_LT(RTIMER_NOW(), end_time)) { \ - return false; \ - } \ - } \ - } while(0) -/*---------------------------------------------------------------------------*/ -#define NO_INTERFACE 0xFF -/*---------------------------------------------------------------------------*/ -static uint8_t slave_addr = 0x00; -static uint8_t interface = NO_INTERFACE; -/*---------------------------------------------------------------------------*/ -static bool -accessible(void) -{ - /* First, check the PD */ - if(ti_lib_prcm_power_domain_status(PRCM_DOMAIN_SERIAL) - != PRCM_DOMAIN_POWER_ON) { - return false; - } - - /* Then check the 'run mode' clock gate */ - if(!(HWREG(PRCM_BASE + PRCM_O_I2CCLKGR) & PRCM_I2CCLKGR_CLK_EN)) { - return false; - } - - return true; -} -/*---------------------------------------------------------------------------*/ -void -board_i2c_wakeup() -{ - /* First, make sure the SERIAL PD is on */ - ti_lib_prcm_power_domain_on(PRCM_DOMAIN_SERIAL); - while((ti_lib_prcm_power_domain_status(PRCM_DOMAIN_SERIAL) - != PRCM_DOMAIN_POWER_ON)); - - /* Enable the clock to I2C */ - ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_I2C0); - ti_lib_prcm_load_set(); - while(!ti_lib_prcm_load_get()); - - /* Enable and initialize the I2C master module */ - ti_lib_i2c_master_init_exp_clk(I2C0_BASE, ti_lib_sys_ctrl_clock_get(), - true); -} -/*---------------------------------------------------------------------------*/ -static bool -i2c_status() -{ - uint32_t status; - - status = ti_lib_i2c_master_err(I2C0_BASE); - if(status & (I2C_MSTAT_DATACK_N_M | I2C_MSTAT_ADRACK_N_M)) { - ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_ERROR_STOP); - } - - return status == I2C_MASTER_ERR_NONE; -} -/*---------------------------------------------------------------------------*/ -void -board_i2c_shutdown() -{ - interface = NO_INTERFACE; - - if(accessible()) { - ti_lib_i2c_master_disable(I2C0_BASE); - } - - ti_lib_prcm_peripheral_run_disable(PRCM_PERIPH_I2C0); - ti_lib_prcm_load_set(); - while(!ti_lib_prcm_load_get()); - - /* - * Set all pins to GPIO Input and disable the output driver. Set internal - * pull to match external pull - * - * SDA and SCL: external PU resistor - * SDA HP and SCL HP: MPU PWR low - */ - ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SDA_HP); - ti_lib_ioc_io_port_pull_set(BOARD_IOID_SDA_HP, IOC_IOPULL_DOWN); - ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SCL_HP); - ti_lib_ioc_io_port_pull_set(BOARD_IOID_SCL_HP, IOC_IOPULL_DOWN); - - ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SDA); - ti_lib_ioc_io_port_pull_set(BOARD_IOID_SDA, IOC_IOPULL_UP); - ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SCL); - ti_lib_ioc_io_port_pull_set(BOARD_IOID_SCL, IOC_IOPULL_UP); -} -/*---------------------------------------------------------------------------*/ -bool -board_i2c_write(uint8_t *data, uint8_t len) -{ - uint32_t i; - bool success; - - /* Write slave address */ - ti_lib_i2c_master_slave_addr_set(I2C0_BASE, slave_addr, false); - - /* Write first byte */ - ti_lib_i2c_master_data_put(I2C0_BASE, data[0]); - - /* Check if another master has access */ - LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE)); - - /* Assert RUN + START */ - ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START); - LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE)); - success = i2c_status(); - - for(i = 1; i < len && success; i++) { - /* Write next byte */ - ti_lib_i2c_master_data_put(I2C0_BASE, data[i]); - if(i < len - 1) { - /* Clear START */ - ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_CONT); - LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE)); - success = i2c_status(); - } - } - - /* Assert stop */ - if(success) { - /* Assert STOP */ - ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH); - LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE)); - success = i2c_status(); - LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE)); - } - - return success; -} -/*---------------------------------------------------------------------------*/ -bool -board_i2c_write_single(uint8_t data) -{ - /* Write slave address */ - ti_lib_i2c_master_slave_addr_set(I2C0_BASE, slave_addr, false); - - /* Write first byte */ - ti_lib_i2c_master_data_put(I2C0_BASE, data); - - /* Check if another master has access */ - LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE)); - - /* Assert RUN + START + STOP */ - ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_SINGLE_SEND); - LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE)); - - return i2c_status(); -} -/*---------------------------------------------------------------------------*/ -bool -board_i2c_read(uint8_t *data, uint8_t len) -{ - uint8_t i; - bool success; - - /* Set slave address */ - ti_lib_i2c_master_slave_addr_set(I2C0_BASE, slave_addr, true); - - /* Check if another master has access */ - LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE)); - - /* Assert RUN + START + ACK */ - ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_START); - - i = 0; - success = true; - while(i < (len - 1) && success) { - LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE)); - success = i2c_status(); - if(success) { - data[i] = ti_lib_i2c_master_data_get(I2C0_BASE); - ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT); - i++; - } - } - - if(success) { - ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH); - LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE)); - success = i2c_status(); - if(success) { - data[len - 1] = ti_lib_i2c_master_data_get(I2C0_BASE); - LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE)); - } - } - - return success; -} -/*---------------------------------------------------------------------------*/ -bool -board_i2c_write_read(uint8_t *wdata, uint8_t wlen, uint8_t *rdata, uint8_t rlen) -{ - uint32_t i; - bool success; - - /* Set slave address for write */ - ti_lib_i2c_master_slave_addr_set(I2C0_BASE, slave_addr, false); - - /* Write first byte */ - ti_lib_i2c_master_data_put(I2C0_BASE, wdata[0]); - - /* Check if another master has access */ - LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE)); - - /* Assert RUN + START */ - ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START); - LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE)); - success = i2c_status(); - - for(i = 1; i < wlen && success; i++) { - /* Write next byte */ - ti_lib_i2c_master_data_put(I2C0_BASE, wdata[i]); - - /* Clear START */ - ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_CONT); - LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE)); - success = i2c_status(); - } - if(!success) { - return false; - } - - /* Set slave address for read */ - ti_lib_i2c_master_slave_addr_set(I2C0_BASE, slave_addr, true); - - /* Assert ACK */ - ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_START); - - i = 0; - while(i < (rlen - 1) && success) { - LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE)); - success = i2c_status(); - if(success) { - rdata[i] = ti_lib_i2c_master_data_get(I2C0_BASE); - ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT); - i++; - } - } - - if(success) { - ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH); - LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE)); - success = i2c_status(); - if(success) { - rdata[rlen - 1] = ti_lib_i2c_master_data_get(I2C0_BASE); - LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE)); - } - } - - return success; -} -/*---------------------------------------------------------------------------*/ -void -board_i2c_select(uint8_t new_interface, uint8_t address) -{ - slave_addr = address; - - if(accessible() == false) { - board_i2c_wakeup(); - } - - if(new_interface != interface) { - interface = new_interface; - - ti_lib_i2c_master_disable(I2C0_BASE); - - if(interface == BOARD_I2C_INTERFACE_0) { - ti_lib_ioc_io_port_pull_set(BOARD_IOID_SDA, IOC_NO_IOPULL); - ti_lib_ioc_io_port_pull_set(BOARD_IOID_SCL, IOC_NO_IOPULL); - ti_lib_ioc_pin_type_i2c(I2C0_BASE, BOARD_IOID_SDA, BOARD_IOID_SCL); - ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SDA_HP); - ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SCL_HP); - } else if(interface == BOARD_I2C_INTERFACE_1) { - ti_lib_ioc_io_port_pull_set(BOARD_IOID_SDA_HP, IOC_NO_IOPULL); - ti_lib_ioc_io_port_pull_set(BOARD_IOID_SCL_HP, IOC_NO_IOPULL); - ti_lib_ioc_pin_type_i2c(I2C0_BASE, BOARD_IOID_SDA_HP, BOARD_IOID_SCL_HP); - ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SDA); - ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SCL); - } - - /* Enable and initialize the I2C master module */ - ti_lib_i2c_master_init_exp_clk(I2C0_BASE, ti_lib_sys_ctrl_clock_get(), - true); - } -} -/*---------------------------------------------------------------------------*/ -/** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-i2c.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-i2c.h deleted file mode 100644 index 46233c332..000000000 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-i2c.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/*---------------------------------------------------------------------------*/ -/** - * \addtogroup sensortag-cc26xx-peripherals - * @{ - * - * \defgroup sensortag-cc26xx-i2c SensorTag 2.0 I2C functions - * @{ - * - * \file - * Header file for the Sensortag I2C Driver - */ -/*---------------------------------------------------------------------------*/ -#ifndef BOARD_I2C_H_ -#define BOARD_I2C_H_ -/*---------------------------------------------------------------------------*/ -#include -#include -/*---------------------------------------------------------------------------*/ -#define BOARD_I2C_INTERFACE_0 0 -#define BOARD_I2C_INTERFACE_1 1 -/*---------------------------------------------------------------------------*/ -/** - * \brief Put the I2C controller in a known state - * - * In this state, pins SDA and SCL will be under i2c control and pins SDA HP - * and SCL HP will be configured as gpio inputs. This is equal to selecting - * BOARD_I2C_INTERFACE_0, but without selecting a slave device address - */ -#define board_i2c_deselect() board_i2c_select(BOARD_I2C_INTERFACE_0, 0) -/*---------------------------------------------------------------------------*/ -/** - * \brief Select an I2C slave - * \param interface The I2C interface to be used (BOARD_I2C_INTERFACE_0 or _1) - * \param slave_addr The slave's address - * - * The various sensors on the sensortag are connected either on interface 0 or - * 1. All sensors are connected to interface 0, with the exception of the MPU - * that is connected to 1. - */ -void board_i2c_select(uint8_t interface, uint8_t slave_addr); - -/** - * \brief Burst read from an I2C device - * \param buf Pointer to a buffer where the read data will be stored - * \param len Number of bytes to read - * \return True on success - */ -bool board_i2c_read(uint8_t *buf, uint8_t len); - -/** - * \brief Burst write to an I2C device - * \param buf Pointer to the buffer to be written - * \param len Number of bytes to write - * \return True on success - */ -bool board_i2c_write(uint8_t *buf, uint8_t len); - -/** - * \brief Single write to an I2C device - * \param data The byte to write - * \return True on success - */ -bool board_i2c_write_single(uint8_t data); - -/** - * \brief Write and read in one operation - * \param wdata Pointer to the buffer to be written - * \param wlen Number of bytes to write - * \param rdata Pointer to a buffer where the read data will be stored - * \param rlen Number of bytes to read - * \return True on success - */ -bool board_i2c_write_read(uint8_t *wdata, uint8_t wlen, uint8_t *rdata, - uint8_t rlen); - -/** - * \brief Enables the I2C peripheral with defaults - * - * This function is called to wakeup and initialise the I2C. - * - * This function can be called explicitly, but it will also be called - * automatically by board_i2c_select() when required. One of those two - * functions MUST be called before any other I2C operation after a chip - * sleep / wakeup cycle or after a call to board_i2c_shutdown(). Failing to do - * so will lead to a bus fault. - */ -void board_i2c_wakeup(void); - -/** - * \brief Stops the I2C peripheral and restores pins to s/w control - * - * This function is called automatically by the board's LPM logic, but it - * can also be called explicitly. - */ -void board_i2c_shutdown(void); -/*---------------------------------------------------------------------------*/ -#endif /* BOARD_I2C_H_ */ -/*---------------------------------------------------------------------------*/ -/** - * @} - * @} - */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor-arch.c new file mode 100644 index 000000000..6e581f646 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor-arch.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup launchpad-button-sensor + * @{ + * + * \file + * Driver for LaunchPad buttons + */ +/*---------------------------------------------------------------------------*/ +#include +#include +#include +/*---------------------------------------------------------------------------*/ +#include +#include +#include +/*---------------------------------------------------------------------------*/ +#include +/*---------------------------------------------------------------------------*/ +#include "button-sensor.h" +#include "button-sensor-arch.h" +/*---------------------------------------------------------------------------*/ +/* Sensortag has 2 buttons: BTN1 and BTN2 */ +/* Map the GPIO defines from the Board file */ +#define BTN1_GPIO Board_KEY_LEFT +#define BTN2_GPIO Board_KEY_RIGHT +/*---------------------------------------------------------------------------*/ +#ifdef BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN +# define BUTTON_SENSOR_ENABLE_SHUTDOWN BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN +#else +# define BUTTON_SENSOR_ENABLE_SHUTDOWN 1 +#endif +/*---------------------------------------------------------------------------*/ +#define DEBOUNCE_DURATION (CLOCK_SECOND >> 5) +/*---------------------------------------------------------------------------*/ +typedef struct { + struct timer debounce; + clock_time_t start; + clock_time_t duration; +} BtnTimer; +/*---------------------------------------------------------------------------*/ +static BtnTimer g_btn1Timer; +static BtnTimer g_btn2Timer; +/*---------------------------------------------------------------------------*/ +static void +button_press_cb(uint8_t index, BtnTimer *btnTimer, const struct sensors_sensor *btnSensor) +{ + if (!timer_expired(&btnTimer->debounce)) { + return; + } + + timer_set(&btnTimer->debounce, DEBOUNCE_DURATION); + + // Start press duration counter on press (falling), notify on release (rising) + if (GPIO_read(index) == 0) { + btnTimer->start = clock_time(); + btnTimer->duration = 0; + } else { + btnTimer->duration = clock_time() - btnTimer->start; + sensors_changed(btnSensor); + } +} +/*---------------------------------------------------------------------------*/ +static int +button_value(int type, uint8_t index, BtnTimer *btnTimer) +{ + if (type == BUTTON_SENSOR_VALUE_STATE) { + return (GPIO_read(index) == 0) + ? BUTTON_SENSOR_VALUE_PRESSED + : BUTTON_SENSOR_VALUE_RELEASED; + } else if (type == BUTTON_SENSOR_VALUE_DURATION) { + return (int)btnTimer->duration; + } + return 0; +} +/*---------------------------------------------------------------------------*/ +static int +button_config(int type, int value, uint8_t index, GPIO_CallbackFxn callback) +{ + switch (type) { + case SENSORS_HW_INIT: + GPIO_clearInt(index); + GPIO_setCallback(index, callback); + break; + + case SENSORS_ACTIVE: + if (value) { + GPIO_clearInt(index); + GPIO_enableInt(index); + } else { + GPIO_disableInt(index); + } + break; + } + + return 1; +} +/*---------------------------------------------------------------------------*/ +static int +button_status(int type, uint8_t index) +{ + switch(type) { + case SENSORS_ACTIVE: /* fallthrough */ + case SENSORS_READY: { + GPIO_PinConfig pinCfg = 0; + GPIO_getConfig(index, &pinCfg); + return (pinCfg & GPIO_CFG_IN_INT_NONE) == 0; + } + } + return 0; +} +/*---------------------------------------------------------------------------*/ +static void +btn1_press_cb(unsigned char unusued) +{ + button_press_cb(BTN1_GPIO, &g_btn1Timer, &btn1_sensor); +} +/*---------------------------------------------------------------------------*/ +static int +btn1_value(int type) +{ + return button_value(type, BTN1_GPIO, &g_btn1Timer); +} +/*---------------------------------------------------------------------------*/ +static int +btn1_config(int type, int value) +{ + return button_config(type, value, BTN1_GPIO, btn1_press_cb); +} +/*---------------------------------------------------------------------------*/ +static int +btn1_status(int type) +{ + return button_status(type, BTN1_GPIO); +} +/*---------------------------------------------------------------------------*/ +static void +btn2_press_cb(unsigned char unusued) +{ + if (BUTTON_SENSOR_ENABLE_SHUTDOWN) { + Power_shutdown(Power_ENTERING_SHUTDOWN, 0); + return; + } + + button_press_cb(BTN2_GPIO, &g_btn2Timer, &btn2_sensor); +} +/*---------------------------------------------------------------------------*/ +static int +btn2_value(int type) +{ + return button_value(type, BTN2_GPIO, &g_btn2Timer); +} +/*---------------------------------------------------------------------------*/ +static int +btn2_config(int type, int value) +{ + return button_config(type, value, BTN2_GPIO, btn2_press_cb); +} +/*---------------------------------------------------------------------------*/ +static int +btn2_status(int type) +{ + return button_status(type, BTN1_GPIO); +} +/*---------------------------------------------------------------------------*/ +SENSORS_SENSOR(btn1_sensor, BUTTON_SENSOR, btn1_value, btn1_config, btn1_status); +SENSORS_SENSOR(btn2_sensor, BUTTON_SENSOR, btn2_value, btn2_config, btn2_status); +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor-arch.h similarity index 73% rename from arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor.h rename to arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor-arch.h index 1355a5855..abcb3ef34 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor-arch.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018 Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,35 +29,28 @@ */ /*---------------------------------------------------------------------------*/ /** - * \addtogroup sensortag-cc26xx-peripherals + * \addtogroup simplelink-platform * @{ * - * \defgroup sensortag-cc26xx-button-sensor SensorTag 2.0 Button Sensor + * \defgroup simplelink-button-sensor Simplelink Button Driver * * One of the buttons can be configured as general purpose or as an on/off key * @{ * * \file - * Header file for the Sensortag Button Driver + * Header file for the Simplelink Button Driver */ /*---------------------------------------------------------------------------*/ -#ifndef BUTTON_SENSOR_H_ -#define BUTTON_SENSOR_H_ +#ifndef BUTTON_SENSOR_ARCH_H_ +#define BUTTON_SENSOR_ARCH_H_ /*---------------------------------------------------------------------------*/ +/* Contiki API */ #include "lib/sensors.h" /*---------------------------------------------------------------------------*/ -#define BUTTON_SENSOR "Button" +extern const struct sensors_sensor btn1_sensor; +extern const struct sensors_sensor btn2_sensor; /*---------------------------------------------------------------------------*/ -#define BUTTON_SENSOR_VALUE_STATE 0 -#define BUTTON_SENSOR_VALUE_DURATION 1 - -#define BUTTON_SENSOR_VALUE_RELEASED 0 -#define BUTTON_SENSOR_VALUE_PRESSED 1 -/*---------------------------------------------------------------------------*/ -extern const struct sensors_sensor button_left_sensor; -extern const struct sensors_sensor button_right_sensor; -/*---------------------------------------------------------------------------*/ -#endif /* BUTTON_SENSOR_H_ */ +#endif /* BUTTON_SENSOR_ARCH_H_ */ /*---------------------------------------------------------------------------*/ /** * @} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor.c deleted file mode 100644 index 7ec0a5a18..000000000 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor.c +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/*---------------------------------------------------------------------------*/ -/** - * \addtogroup sensortag-cc26xx-button-sensor - * @{ - * - * \file - * Driver for Sensortag buttons - */ -/*---------------------------------------------------------------------------*/ -#include "contiki.h" -#include "lib/sensors.h" -#include "sensortag/button-sensor.h" -#include "gpio-interrupt.h" -#include "sys/timer.h" -#include "lpm.h" - -#include "ti-lib.h" - -#include -/*---------------------------------------------------------------------------*/ -#ifdef BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN -#define BUTTON_SENSOR_ENABLE_SHUTDOWN BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN -#else -#define BUTTON_SENSOR_ENABLE_SHUTDOWN 1 -#endif -/*---------------------------------------------------------------------------*/ -#define BUTTON_GPIO_CFG (IOC_CURRENT_2MA | IOC_STRENGTH_AUTO | \ - IOC_IOPULL_UP | IOC_SLEW_DISABLE | \ - IOC_HYST_DISABLE | IOC_BOTH_EDGES | \ - IOC_INT_ENABLE | IOC_IOMODE_NORMAL | \ - IOC_NO_WAKE_UP | IOC_INPUT_ENABLE) -/*---------------------------------------------------------------------------*/ -#define DEBOUNCE_DURATION (CLOCK_SECOND >> 5) - -struct btn_timer { - struct timer debounce; - clock_time_t start; - clock_time_t duration; -}; - -static struct btn_timer left_timer, right_timer; -/*---------------------------------------------------------------------------*/ -/** - * \brief Handler for Sensortag-CC26XX button presses - */ -static void -button_press_handler(uint8_t ioid) -{ - if(ioid == BOARD_IOID_KEY_LEFT) { - if(!timer_expired(&left_timer.debounce)) { - return; - } - - timer_set(&left_timer.debounce, DEBOUNCE_DURATION); - - /* - * Start press duration counter on press (falling), notify on release - * (rising) - */ - if(ti_lib_gpio_read_dio(BOARD_IOID_KEY_LEFT) == 0) { - left_timer.start = clock_time(); - left_timer.duration = 0; - } else { - left_timer.duration = clock_time() - left_timer.start; - sensors_changed(&button_left_sensor); - } - } - - if(ioid == BOARD_IOID_KEY_RIGHT) { - if(BUTTON_SENSOR_ENABLE_SHUTDOWN == 0) { - if(!timer_expired(&right_timer.debounce)) { - return; - } - - timer_set(&right_timer.debounce, DEBOUNCE_DURATION); - - /* - * Start press duration counter on press (falling), notify on release - * (rising) - */ - if(ti_lib_gpio_read_dio(BOARD_IOID_KEY_RIGHT) == 0) { - right_timer.start = clock_time(); - right_timer.duration = 0; - } else { - right_timer.duration = clock_time() - right_timer.start; - sensors_changed(&button_right_sensor); - } - } else { - lpm_shutdown(BOARD_IOID_KEY_RIGHT, IOC_IOPULL_UP, IOC_WAKE_ON_LOW); - } - } -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Configuration function for the button sensor for all buttons. - * - * \param type This function does nothing unless type == SENSORS_ACTIVE - * \param c 0: disable the button, non-zero: enable - * \param key: One of BOARD_KEY_LEFT, BOARD_KEY_RIGHT etc - */ -static void -config_buttons(int type, int c, uint32_t key) -{ - switch(type) { - case SENSORS_HW_INIT: - ti_lib_gpio_clear_event_dio(key); - ti_lib_rom_ioc_pin_type_gpio_input(key); - ti_lib_rom_ioc_port_configure_set(key, IOC_PORT_GPIO, BUTTON_GPIO_CFG); - gpio_interrupt_register_handler(key, button_press_handler); - break; - case SENSORS_ACTIVE: - if(c) { - ti_lib_gpio_clear_event_dio(key); - ti_lib_rom_ioc_pin_type_gpio_input(key); - ti_lib_rom_ioc_port_configure_set(key, IOC_PORT_GPIO, BUTTON_GPIO_CFG); - ti_lib_rom_ioc_int_enable(key); - } else { - ti_lib_rom_ioc_int_disable(key); - } - break; - default: - break; - } -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Configuration function for the left button. - * - * Parameters are passed onto config_buttons, which does the actual - * configuration - * Parameters are ignored. They have been included because the prototype is - * dictated by the core sensor API. The return value is also required by - * the API but otherwise ignored. - * - * \param type passed to config_buttons as-is - * \param value passed to config_buttons as-is - * - * \return ignored - */ -static int -config_left(int type, int value) -{ - config_buttons(type, value, BOARD_IOID_KEY_LEFT); - - return 1; -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Configuration function for the right button. - * - * Parameters are passed onto config_buttons, which does the actual - * configuration - * Parameters are ignored. They have been included because the prototype is - * dictated by the core sensor api. The return value is also required by - * the API but otherwise ignored. - * - * \param type passed to config_buttons as-is - * \param value passed to config_buttons as-is - * - * \return ignored - */ -static int -config_right(int type, int value) -{ - config_buttons(type, value, BOARD_IOID_KEY_RIGHT); - - return 1; -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Status function for all buttons - * \param type SENSORS_ACTIVE or SENSORS_READY - * \param key_io_id BOARD_IOID_KEY_LEFT, BOARD_IOID_KEY_RIGHT etc - * \return 1 if the button's port interrupt is enabled (edge detect) - * - * This function will only be called by status_left, status_right and the - * called will pass the correct key_io_id - */ -static int -status(int type, uint32_t key_io_id) -{ - switch(type) { - case SENSORS_ACTIVE: - case SENSORS_READY: - if(ti_lib_ioc_port_configure_get(key_io_id) & IOC_INT_ENABLE) { - return 1; - } - break; - default: - break; - } - return 0; -} -/*---------------------------------------------------------------------------*/ -static int -value_left(int type) -{ - if(type == BUTTON_SENSOR_VALUE_STATE) { - return ti_lib_gpio_read_dio(BOARD_IOID_KEY_LEFT) == 0 ? - BUTTON_SENSOR_VALUE_PRESSED : BUTTON_SENSOR_VALUE_RELEASED; - } else if(type == BUTTON_SENSOR_VALUE_DURATION) { - return (int)left_timer.duration; - } - return 0; -} -/*---------------------------------------------------------------------------*/ -static int -value_right(int type) -{ - if(type == BUTTON_SENSOR_VALUE_STATE) { - return ti_lib_gpio_read_dio(BOARD_IOID_KEY_RIGHT) == 0 ? - BUTTON_SENSOR_VALUE_PRESSED : BUTTON_SENSOR_VALUE_RELEASED; - } else if(type == BUTTON_SENSOR_VALUE_DURATION) { - return (int)right_timer.duration; - } - return 0; -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Status function for the left button. - * \param type SENSORS_ACTIVE or SENSORS_READY - * \return 1 if the button's port interrupt is enabled (edge detect) - * - * This function will call status. It will pass type verbatim and it will also - * pass the correct key_io_id - */ -static int -status_left(int type) -{ - return status(type, BOARD_IOID_KEY_LEFT); -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Status function for the right button. - * \param type SENSORS_ACTIVE or SENSORS_READY - * \return 1 if the button's port interrupt is enabled (edge detect) - * - * This function will call status. It will pass type verbatim and it will also - * pass the correct key_io_id - */ -static int -status_right(int type) -{ - return status(type, BOARD_IOID_KEY_RIGHT); -} -/*---------------------------------------------------------------------------*/ -SENSORS_SENSOR(button_left_sensor, BUTTON_SENSOR, value_left, config_left, - status_left); -SENSORS_SENSOR(button_right_sensor, BUTTON_SENSOR, value_right, config_right, - status_right); -/*---------------------------------------------------------------------------*/ -/** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.c index 45ab751d5..c79b7f401 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.c @@ -38,106 +38,119 @@ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "buzzer.h" -#include "ti-lib.h" -#include "lpm.h" - +/*---------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +/*---------------------------------------------------------------------------*/ #include #include #include /*---------------------------------------------------------------------------*/ -static uint8_t buzzer_on; -LPM_MODULE(buzzer_module, NULL, NULL, NULL, LPM_DOMAIN_PERIPH); +/* Configure BUZZER pin */ +#ifndef Board_BUZZER +# error "Board file doesn't define pin Board_BUZZER" +#endif +#define BUZZER_PIN Board_BUZZER /*---------------------------------------------------------------------------*/ -void +static const PIN_Config pin_table[] = { + BUZZER_PIN | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW, + PIN_TERMINATE +}; + +static PIN_State pin_state; +static PIN_Handle pin_handle; + +static GPTimerCC26XX_Handle gpt_handle; + +static bool has_init; +static volatile bool is_running; +/*---------------------------------------------------------------------------*/ +bool buzzer_init() { - buzzer_on = 0; -} -/*---------------------------------------------------------------------------*/ -uint8_t -buzzer_state() -{ - return buzzer_on; -} -/*---------------------------------------------------------------------------*/ -void -buzzer_start(int freq) -{ - uint32_t load; - - /* Enable GPT0 clocks under active, sleep, deep sleep */ - ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_TIMER0); - ti_lib_prcm_peripheral_sleep_enable(PRCM_PERIPH_TIMER0); - ti_lib_prcm_peripheral_deep_sleep_enable(PRCM_PERIPH_TIMER0); - ti_lib_prcm_load_set(); - while(!ti_lib_prcm_load_get()); - - /* Drive the I/O ID with GPT0 / Timer A */ - ti_lib_ioc_port_configure_set(BOARD_IOID_BUZZER, IOC_PORT_MCU_PORT_EVENT0, - IOC_STD_OUTPUT); - - /* GPT0 / Timer A: PWM, Interrupt Enable */ - HWREG(GPT0_BASE + GPT_O_TAMR) = (TIMER_CFG_A_PWM & 0xFF) | GPT_TAMR_TAPWMIE; - - buzzer_on = 1; - - /* - * Register ourself with LPM. This will keep the PERIPH PD powered on - * during deep sleep, allowing the buzzer to keep working while the chip is - * being power-cycled - */ - lpm_register_module(&buzzer_module); - - /* Stop the timer */ - ti_lib_timer_disable(GPT0_BASE, TIMER_A); - - if(freq > 0) { - load = (GET_MCU_CLOCK / freq); - - ti_lib_timer_load_set(GPT0_BASE, TIMER_A, load); - ti_lib_timer_match_set(GPT0_BASE, TIMER_A, load / 2); - - /* Start */ - ti_lib_timer_enable(GPT0_BASE, TIMER_A); + if (has_init) { + return true; } + + GPTimerCC26XX_Params gpt_params; + GPTimerCC26XX_Params_init(&gpt_params); + gpt_params.mode = GPT_CONFIG_16BIT; + gpt_params.mode = GPT_MODE_PERIODIC_UP; + gpt_params.debugStallMode = GPTimerCC26XX_DEBUG_STALL_OFF; + + gpt_handle = GPTimerCC26XX_open(Board_GPTIMER0A, &gpt_params); + if (!gpt_handle) { + PIN_close(pin_handle); + return false; + } + + is_running = false; + + has_init = true; + return true; +} +/*---------------------------------------------------------------------------*/ +bool +buzzer_running() +{ + return is_running; +} +/*---------------------------------------------------------------------------*/ +bool +buzzer_start(uint32_t freq) +{ + if (!has_init) { + return false; + } + + if (freq == 0) { + return false; + } + + if (is_running) { + return true; + } + + pin_handle = PIN_open(&pin_state, pin_table); + if (!pin_handle) { + return false; + } + + Power_setDependency(PowerCC26XX_XOSC_HF ); + + PINCC26XX_setMux(pin_handle, BUZZER_PIN, GPT_PIN_0A); + + // MCU runs at 48 MHz + GPTimerCC26XX_Value load_value = 48000000 / freq; + + GPTimerCC26XX_setLoadValue(gpt_handle, load_value); + GPTimerCC26XX_start(gpt_handle); + + is_running = true; + return true; } /*---------------------------------------------------------------------------*/ void buzzer_stop() { - buzzer_on = 0; + if (!gpt_handle) { + return; + } - /* - * Unregister the buzzer module from LPM. This will effectively release our - * lock for the PERIPH PD allowing it to be powered down (unless some other - * module keeps it on) - */ - lpm_unregister_module(&buzzer_module); + if (!is_running) { + return; + } - /* Stop the timer */ - ti_lib_timer_disable(GPT0_BASE, TIMER_A); + Power_releaseDependency(PowerCC26XX_XOSC_HF ); - /* - * Stop the module clock: - * - * Currently GPT0 is in use by clock_delay_usec (GPT0/TB) and by this - * module here (GPT0/TA). - * - * clock_delay_usec - * - is definitely not running when we enter here and - * - handles the module clock internally - * - * Thus, we can safely change the state of module clocks here. - */ - ti_lib_prcm_peripheral_run_disable(PRCM_PERIPH_TIMER0); - ti_lib_prcm_peripheral_sleep_disable(PRCM_PERIPH_TIMER0); - ti_lib_prcm_peripheral_deep_sleep_disable(PRCM_PERIPH_TIMER0); - ti_lib_prcm_load_set(); - while(!ti_lib_prcm_load_get()); + GPTimerCC26XX_stop(gpt_handle); + PIN_close(pin_handle); - /* Un-configure the pin */ - ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_BUZZER); - ti_lib_ioc_io_input_set(BOARD_IOID_BUZZER, IOC_INPUT_DISABLE); + is_running = false; } /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.h index 679729245..31a92ad17 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.h @@ -43,17 +43,18 @@ #define BUZZER_H_ /*---------------------------------------------------------------------------*/ #include +#include /*---------------------------------------------------------------------------*/ /** * \brief Initialise the buzzer */ -void buzzer_init(void); +bool buzzer_init(void); /** * \brief Start the buzzer * \param freq The buzzer frequency */ -void buzzer_start(int freq); +bool buzzer_start(uint32_t freq); /** * \brief Stop the buzzer @@ -64,7 +65,7 @@ void buzzer_stop(void); * \brief Retrieve the buzzer state * \return 1: on, 0: off */ -uint8_t buzzer_state(void); +bool buzzer_running(void); /*---------------------------------------------------------------------------*/ #endif /* BUZZER_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h index edf32e331..85f0452a2 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h @@ -33,6 +33,8 @@ #ifndef __BOARD_H #define __BOARD_H +#define Board_CC1350STK + #ifdef __cplusplus extern "C" { #endif @@ -74,6 +76,7 @@ extern "C" { #define Board_KEY_LEFT CC1350STK_KEY_LEFT #define Board_KEY_RIGHT CC1350STK_KEY_RIGHT +#define Board_RELAY CC1350STK_RELAY #define Board_MIC_POWER CC1350STK_MIC_POWER #define Board_MIC_POWER_OM CC1350STK_MIC_POWER_ON @@ -84,6 +87,8 @@ extern "C" { #define Board_MPU_POWER_OFF CC1350STK_MPU_POWER_OFF #define Board_MPU_POWER_ON CC1350STK_MPU_POWER_ON +#define Board_TMP_RDY CC1350STK_TMP_RDY + #define Board_NVSINTERNAL CC1350STK_NVSCC26XX0 #define Board_NVSEXTERNAL CC1350STK_NVSSPI25X0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.c index 8ae1c22bc..916dfda20 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.c @@ -653,91 +653,11 @@ const Watchdog_Config Watchdog_config[CC1350STK_WATCHDOGCOUNT] = { const uint_least8_t Watchdog_count = CC1350STK_WATCHDOGCOUNT; - /* - * ======== CC1350STK_wakeUpExtFlash ======== + * Board-specific initialization function to disable external flash. + * This function is defined in the file CC1350STK_fxns.c */ -void CC1350STK_wakeUpExtFlash(void) -{ - PIN_Config extFlashPinTable[] = { - CC1350STK_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - PIN_TERMINATE - }; - PIN_State extFlashPinState; - PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); - - /* - * To wake up we need to toggle the chip select at - * least 20 ns and ten wait at least 35 us. - */ - - /* Toggle chip select for ~20ns to wake ext. flash */ - PIN_setOutputValue(extFlashPinHandle, CC1350STK_SPI_FLASH_CS, 0); - /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ - CPUdelay(1); - PIN_setOutputValue(extFlashPinHandle, CC1350STK_SPI_FLASH_CS, 1); - /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ - CPUdelay(560); - - PIN_close(extFlashPinHandle); -} - -/* - * ======== CC1350STK_sendExtFlashByte ======== - */ -void CC1350STK_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) -{ - uint8_t i; - - PIN_setOutputValue(pinHandle, CC1350STK_SPI_FLASH_CS, 0); - - for (i = 0; i < 8; i++) { - PIN_setOutputValue(pinHandle, CC1350STK_SPI0_CLK, 0); - PIN_setOutputValue(pinHandle, CC1350STK_SPI0_MOSI, (byte >> (7 - i)) & 0x01); - PIN_setOutputValue(pinHandle, CC1350STK_SPI0_CLK, 1); - - /* - * Waste a few cycles to keep the CLK high for at - * least 45% of the period. - * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. - */ - CPUdelay(8); - } - - PIN_setOutputValue(pinHandle, CC1350STK_SPI0_CLK, 0); - PIN_setOutputValue(pinHandle, CC1350STK_SPI_FLASH_CS, 1); - - /* - * Keep CS high at least 40 us - * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us - */ - CPUdelay(700); -} - -/* - * ======== CC1350STK_shutDownExtFlash ======== - */ -void CC1350STK_shutDownExtFlash(void) -{ - /* To be sure we are putting the flash into sleep and not waking it, we first have to make a wake up call */ - CC1350STK_wakeUpExtFlash(); - - PIN_Config extFlashPinTable[] = { - CC1350STK_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - CC1350STK_SPI0_CLK | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - CC1350STK_SPI0_MOSI | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED, - CC1350STK_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, - PIN_TERMINATE - }; - PIN_State extFlashPinState; - PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); - - uint8_t extFlashShutdown = 0xB9; - - CC1350STK_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); - - PIN_close(extFlashPinHandle); -} +extern void Board_initHook(void); /* * ======== CC1350STK_initGeneral ======== @@ -751,6 +671,6 @@ void CC1350STK_initGeneral(void) while (1); } - /* Shut down external flash as default */ - CC1350STK_shutDownExtFlash(); + /* Perform board-specific initialization */ + Board_initHook(); } diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK_fxns.c new file mode 100644 index 000000000..16cdde8bd --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK_fxns.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ +/* + * ====================== CC1350STK_fxns.c ========================================= + * This file contains the board-specific initialization functions. + */ + +#include +#include +#include + +#include +#include + +#include "Board.h" + +/* + * ======== CC1350STK_sendExtFlashByte ======== + */ +void CC1350STK_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) +{ + uint8_t i; + + /* SPI Flash CS */ + PIN_setOutputValue(pinHandle, IOID_14, 0); + + for (i = 0; i < 8; i++) { + PIN_setOutputValue(pinHandle, IOID_17, 0); /* SPI Flash CLK */ + + /* SPI Flash MOSI */ + PIN_setOutputValue(pinHandle, IOID_19, (byte >> (7 - i)) & 0x01); + PIN_setOutputValue(pinHandle, IOID_17, 1); + + /* + * Waste a few cycles to keep the CLK high for at + * least 45% of the period. + * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. + */ + CPUdelay(8); + } + + PIN_setOutputValue(pinHandle, IOID_17, 0); + PIN_setOutputValue(pinHandle, IOID_14, 1); + + /* + * Keep CS high at least 40 us + * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us + */ + CPUdelay(700); +} + +/* + * ======== CC1350STK_wakeUpExtFlash ======== + */ +void CC1350STK_wakeUpExtFlash(void) +{ + PIN_Config extFlashPinTable[] = { + IOID_14 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + /* + * To wake up we need to toggle the chip select at + * least 20 ns and ten wait at least 35 us. + */ + + /* Toggle chip select for ~20ns to wake ext. flash */ + PIN_setOutputValue(extFlashPinHandle, IOID_14, 0); + /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ + CPUdelay(1); + PIN_setOutputValue(extFlashPinHandle, IOID_14, 1); + /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ + CPUdelay(560); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC1350STK_shutDownExtFlash ======== + */ +void CC1350STK_shutDownExtFlash(void) +{ + /* + * To be sure we are putting the flash into sleep and not waking it, + * we first have to make a wake up call + */ + CC1350STK_wakeUpExtFlash(); + + PIN_Config extFlashPinTable[] = { + /* SPI Flash CS*/ + IOID_14 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash CLK */ + IOID_17 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash MOSI */ + IOID_19 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash MISO */ + IOID_18 | PIN_INPUT_EN | PIN_PULLDOWN, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + uint8_t extFlashShutdown = 0xB9; + + CC1350STK_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== Board_initHook ======== + * Called by Board_init() to perform board-specific initialization. + */ +void Board_initHook() +{ + CC1350STK_shutDownExtFlash(); +} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Makefile.cc1350 b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Makefile.cc1350 index 5e4c5c260..444d11048 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Makefile.cc1350 +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Makefile.cc1350 @@ -3,8 +3,9 @@ SUBFAMILY = cc13x0-cc26x0 DEVICE_FAMILY = CC13X0 +DEVICE_LINE = CC13XX -BOARD_SOURCEFILES += CC1350STK.c +BOARD_SOURCEFILES += CC1350STK.c CC1350STK_fxns.c SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h index a1614e4fc..410c2508b 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, Texas Instruments Incorporated + * Copyright (c) 2015-2018, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,55 +33,97 @@ #ifndef __BOARD_H #define __BOARD_H +#define Board_CC2650STK + #ifdef __cplusplus extern "C" { #endif -#include - #include "CC2650STK.h" +#define Board_initGeneral() CC2650STK_initGeneral() +#define Board_shutDownExtFlash() CC2650STK_shutDownExtFlash() +#define Board_wakeUpExtFlash() CC2650STK_wakeUpExtFlash() + /* These #defines allow us to reuse TI-RTOS across other device families */ -#define Board_LED1 Board_STK_LED1 -#define Board_LED2 Board_STK_LED2 -#define Board_LED0 Board_LED2 -#define Board_BUTTON0 Board_KEY_LEFT -#define Board_BUTTON1 Board_KEY_RIGHT +#define Board_BUZZER CC2650STK_BUZZER +#define Board_BUZZER_ON CC2650STK_LED_ON +#define Board_BUZZER_OFF CC2650STK_LED_OFF -#define Board_I2C0 Board_I2C -#define Board_I2C_TMP Board_I2C0 -#define Board_UART0 Board_UART -#define Board_AES0 Board_AES -#define Board_WATCHDOG0 CC2650STK_WATCHDOG0 +#define Board_CRYPTO0 CC2650STK_CRYPTO0 -#define Board_initGeneral() { \ - Power_init(); \ - if (PIN_init(BoardGpioInitTable) != PIN_SUCCESS) \ - {System_abort("Error with PIN_init\n"); \ - } \ -} +#define Board_GPIO_BUTTON0 CC2650STK_GPIO_S1 +#define Board_GPIO_BUTTON1 CC2650STK_GPIO_S2 +#define Board_GPIO_LED0 CC2650STK_GPIO_LED0 +#define Board_GPIO_LED1 CC2650STK_GPIO_LED0 +#define Board_GPIO_LED_ON CC2650STK_GPIO_LED_ON +#define Board_GPIO_LED_OFF CC2650STK_GPIO_LED_OFF -#define Board_initGPIO() -#define Board_initPWM() PWM_init() -#define Board_initI2C() I2C_init() -#define Board_initSPI() SPI_init() -#define Board_initUART() UART_init() -#define Board_initWatchdog() Watchdog_init() -#define GPIO_toggle(n) -#define GPIO_write(n,m) +#define Board_GPTIMER0A CC2650STK_GPTIMER0A +#define Board_GPTIMER0B CC2650STK_GPTIMER0B +#define Board_GPTIMER1A CC2650STK_GPTIMER1A +#define Board_GPTIMER1B CC2650STK_GPTIMER1B +#define Board_GPTIMER2A CC2650STK_GPTIMER2A +#define Board_GPTIMER2B CC2650STK_GPTIMER2B +#define Board_GPTIMER3A CC2650STK_GPTIMER3A +#define Board_GPTIMER3B CC2650STK_GPTIMER3B + +#define Board_I2C0 CC2650STK_I2C0 +#define Board_I2C0_SDA1 CC2650STK_I2C0_SDA1 +#define Board_I2C0_SCL1 CC2650STK_I2C0_SCL1 +#define Board_I2C_TMP CC2650STK_I2C0 + +#define Board_KEY_LEFT CC2650STK_KEY_LEFT +#define Board_KEY_RIGHT CC2650STK_KEY_RIGHT +#define Board_RELAY CC2650STK_RELAY + +#define Board_MIC_POWER CC2650STK_MIC_POWER +#define Board_MIC_POWER_OM CC2650STK_MIC_POWER_ON +#define Board_MIC_POWER_OFF CC2650STK_MIC_POWER_OFF + +#define Board_MPU_INT CC2650STK_MPU_INT +#define Board_MPU_POWER CC2650STK_MPU_POWER +#define Board_MPU_POWER_OFF CC2650STK_MPU_POWER_OFF +#define Board_MPU_POWER_ON CC2650STK_MPU_POWER_ON + +#define Board_NVSINTERNAL CC2650STK_NVSCC26XX0 +#define Board_NVSEXTERNAL CC2650STK_NVSSPI25X0 + +#define Board_PDM0 CC2650STK_PDM0 + +#define Board_PIN_BUTTON0 CC2650STK_KEY_LEFT +#define Board_PIN_BUTTON1 CC2650STK_KEY_RIGHT +#define Board_PIN_LED0 CC2650STK_PIN_LED1 +#define Board_PIN_LED1 CC2650STK_PIN_LED1 +#define Board_PIN_LED2 CC2650STK_PIN_LED1 + +#define Board_PWM0 CC2650STK_PWM0 +#define Board_PWM1 CC2650STK_PWM0 +#define Board_PWM2 CC2650STK_PWM2 +#define Board_PWM3 CC2650STK_PWM3 +#define Board_PWM4 CC2650STK_PWM4 +#define Board_PWM5 CC2650STK_PWM5 +#define Board_PWM6 CC2650STK_PWM6 +#define Board_PWM7 CC2650STK_PWM7 + +#define Board_SPI0 CC2650STK_SPI0 +#define Board_SPI1 CC2650STK_SPI1 +#define Board_SPI_FLASH_CS CC2650STK_SPI_FLASH_CS +#define Board_FLASH_CS_ON CC2650STK_FLASH_CS_ON +#define Board_FLASH_CS_OFF CC2650STK_FLASH_CS_OFF + +#define Board_UART0 CC2650STK_UART0 + +#define Board_WATCHDOG0 CC2650STK_WATCHDOG0 /* Board specific I2C addresses */ - -/* Interface #0 */ -#define Board_HDC1000_ADDR (0x43) -#define Board_TMP007_ADDR (0x44) -#define Board_OPT3001_ADDR (0x45) -#define Board_BMP280_ADDR (0x77) - -/* Interface #1 */ -#define Board_MPU9250_ADDR (0x68) -#define Board_MPU9250_MAG_ADDR (0x0C) +#define Board_BMP280_ADDR (0x77) +#define Board_HDC1000_ADDR (0x43) +#define Board_MPU9250_ADDR (0x68) +#define Board_MPU9250_MAG_ADDR (0x0C) +#define Board_OPT3001_ADDR (0x45) +#define Board_TMP_ADDR (0x44) #ifdef __cplusplus } diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.c index 5e3da594e..14c6ca382 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, Texas Instruments Incorporated + * Copyright (c) 2016-2018, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,309 +33,30 @@ /* * ====================== CC2650STK.c ========================================= * This file is responsible for setting up the board specific items for the - * CC2650 SensorTag. + * CC2650STK board. */ +#include +#include +#include -/* - * ====================== Includes ============================================ - */ -#include -#include - -#include -#include -#include -#include -#include -#include #include #include -#include -#include -#include -#include +#include +#include +#include +#include -#include +#include "CC2650STK.h" /* - * ========================= IO driver initialization ========================= - * From main, PIN_init(BoardGpioInitTable) should be called to setup safe - * settings for this board. - * When a pin is allocated and then de-allocated, it will revert to the state - * configured in this table. + * =============================== Crypto =============================== */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(BoardGpioInitTable, ".const:BoardGpioInitTable") -#pragma DATA_SECTION(PINCC26XX_hwAttrs, ".const:PINCC26XX_hwAttrs") -#endif - -const PIN_Config BoardGpioInitTable[] = { - - Board_STK_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ - Board_STK_LED2 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ - Board_KEY_LEFT | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ - Board_KEY_RIGHT | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ - Board_RELAY | PIN_INPUT_EN | PIN_PULLDOWN | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Relay is active high */ - Board_MPU_INT | PIN_INPUT_EN | PIN_PULLDOWN | PIN_IRQ_NEGEDGE | PIN_HYSTERESIS, /* MPU_INT is active low */ - Board_TMP_RDY | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS, /* TMP_RDY is active high */ - Board_BUZZER | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Buzzer initially off */ - Board_MPU_POWER | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* MPU initially on */ - Board_MIC_POWER | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* MIC initially off */ - Board_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ - Board_SPI_DEVPK_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* DevPack chip select */ - Board_AUDIO_DI | PIN_INPUT_EN | PIN_PULLDOWN, /* Audio DI */ - Board_AUDIODO | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* Audio data out */ - Board_AUDIO_CLK | PIN_INPUT_EN | PIN_PULLDOWN, /* DevPack */ - Board_DP2 | PIN_INPUT_EN | PIN_PULLDOWN, /* DevPack */ - Board_DP1 | PIN_INPUT_EN | PIN_PULLDOWN, /* DevPack */ - Board_DP0 | PIN_INPUT_EN | PIN_PULLDOWN, /* DevPack */ - Board_DP3 | PIN_INPUT_EN | PIN_PULLDOWN, /* DevPack */ - Board_UART_RX | PIN_INPUT_EN | PIN_PULLDOWN, /* DevPack */ - Board_UART_TX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* DevPack */ - Board_DEVPK_ID | PIN_INPUT_EN | PIN_NOPULL, /* Device pack ID - external PU */ - Board_SPI0_MOSI | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master out - slave in */ - Board_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master in - slave out */ - Board_SPI0_CLK | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI clock */ - - PIN_TERMINATE -}; - -const PINCC26XX_HWAttrs PINCC26XX_hwAttrs = { - .intPriority = ~0, - .swiPriority = 0 -}; -/*============================================================================*/ - -/* - * ============================= Power begin ================================== - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(PowerCC26XX_config, ".const:PowerCC26XX_config") -#endif -const PowerCC26XX_Config PowerCC26XX_config = { - .policyInitFxn = NULL, - .policyFxn = &PowerCC26XX_standbyPolicy, - .calibrateFxn = &PowerCC26XX_calibrate, - .enablePolicy = TRUE, - .calibrateRCOSC_LF = TRUE, - .calibrateRCOSC_HF = TRUE, -}; -/* - * ============================= Power end =================================== - */ - -/* - * ============================= UART begin =================================== - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(UART_config, ".const:UART_config") -#pragma DATA_SECTION(uartCC26XXHWAttrs, ".const:uartCC26XXHWAttrs") -#endif - -/* Include drivers */ -#include -#include - -/* UART objects */ -UARTCC26XX_Object uartCC26XXObjects[CC2650STK_UARTCOUNT]; -unsigned char uartCC26XXRingBuffer[CC2650STK_UARTCOUNT][32]; - -/* UART hardware parameter structure, also used to assign UART pins */ -const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC2650STK_UARTCOUNT] = { - { - .baseAddr = UART0_BASE, - .powerMngrId = PowerCC26XX_PERIPH_UART0, - .intNum = INT_UART0_COMB, - .intPriority = ~0, - .swiPriority = 0, - .txPin = Board_UART_TX, - .rxPin = Board_UART_RX, - .ctsPin = PIN_UNASSIGNED, - .rtsPin = PIN_UNASSIGNED, - .ringBufPtr = uartCC26XXRingBuffer[0], - .ringBufSize = sizeof(uartCC26XXRingBuffer[0]) - } -}; - -/* UART configuration structure */ -const UART_Config UART_config[] = { - { - .fxnTablePtr = &UARTCC26XX_fxnTable, - .object = &uartCC26XXObjects[0], - .hwAttrs = &uartCC26XXHWAttrs[0] - }, - {NULL, NULL, NULL} -}; -/* - * ============================= UART end ===================================== - */ - -/* - * ============================= UDMA begin =================================== - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(UDMACC26XX_config, ".const:UDMACC26XX_config") -#pragma DATA_SECTION(udmaHWAttrs, ".const:udmaHWAttrs") -#endif - -/* Include drivers */ -#include - -/* UDMA objects */ -UDMACC26XX_Object udmaObjects[CC2650STK_UDMACOUNT]; - -/* UDMA configuration structure */ -const UDMACC26XX_HWAttrs udmaHWAttrs[CC2650STK_UDMACOUNT] = { - { - .baseAddr = UDMA0_BASE, - .powerMngrId = PowerCC26XX_PERIPH_UDMA, - .intNum = INT_DMA_ERR, - .intPriority = ~0 - } -}; - -/* UDMA configuration structure */ -const UDMACC26XX_Config UDMACC26XX_config[] = { - { - .object = &udmaObjects[0], - .hwAttrs = &udmaHWAttrs[0] - }, - {NULL, NULL} -}; -/* - * ============================= UDMA end ===================================== - */ - -/* - * ========================== SPI DMA begin =================================== - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(SPI_config, ".const:SPI_config") -#pragma DATA_SECTION(spiCC26XXDMAHWAttrs, ".const:spiCC26XXDMAHWAttrs") -#endif - -/* Include drivers */ -#include - -/* SPI objects */ -SPICC26XXDMA_Object spiCC26XXDMAObjects[CC2650STK_SPICOUNT]; - -/* SPI configuration structure, describing which pins are to be used */ -const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC2650STK_SPICOUNT] = { - { - .baseAddr = SSI0_BASE, - .intNum = INT_SSI0_COMB, - .intPriority = ~0, - .swiPriority = 0, - .powerMngrId = PowerCC26XX_PERIPH_SSI0, - .defaultTxBufValue = 0, - .rxChannelBitMask = 1< - -/* I2C objects */ -I2CCC26XX_Object i2cCC26xxObjects[CC2650STK_I2CCOUNT]; - -/* I2C configuration structure, describing which pins are to be used */ -const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC2650STK_I2CCOUNT] = { - { - .baseAddr = I2C0_BASE, - .powerMngrId = PowerCC26XX_PERIPH_I2C0, - .intNum = INT_I2C_IRQ, - .intPriority = ~0, - .swiPriority = 0, - .sdaPin = Board_I2C0_SDA0, - .sclPin = Board_I2C0_SCL0, - } -}; - -const I2C_Config I2C_config[] = { - { - .fxnTablePtr = &I2CCC26XX_fxnTable, - .object = &i2cCC26xxObjects[0], - .hwAttrs = &i2cCC26xxHWAttrs[0] - }, - {NULL, NULL, NULL} -}; -/* - * ========================== I2C end ========================================= - */ - -/* - * ========================== Crypto begin ==================================== - * NOTE: The Crypto implementation should be considered experimental - * and not validated! - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(CryptoCC26XX_config, ".const:CryptoCC26XX_config") -#pragma DATA_SECTION(cryptoCC26XXHWAttrs, ".const:cryptoCC26XXHWAttrs") -#endif - -/* Include drivers */ #include -/* Crypto objects */ CryptoCC26XX_Object cryptoCC26XXObjects[CC2650STK_CRYPTOCOUNT]; -/* Crypto configuration structure, describing which pins are to be used */ const CryptoCC26XX_HWAttrs cryptoCC26XXHWAttrs[CC2650STK_CRYPTOCOUNT] = { { .baseAddr = CRYPTO_BASE, @@ -345,191 +66,161 @@ const CryptoCC26XX_HWAttrs cryptoCC26XXHWAttrs[CC2650STK_CRYPTOCOUNT] = { } }; -/* Crypto configuration structure */ -const CryptoCC26XX_Config CryptoCC26XX_config[] = { +const CryptoCC26XX_Config CryptoCC26XX_config[CC2650STK_CRYPTOCOUNT] = { { - .object = &cryptoCC26XXObjects[0], - .hwAttrs = &cryptoCC26XXHWAttrs[0] - }, - {NULL, NULL} -}; -/* - * ========================== Crypto end ====================================== - */ - -/* - * ============================= PDM begin ==================================== - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(PDMCC26XX_config, ".const:PDMCC26XX_config") -#pragma DATA_SECTION(pdmCC26XXHWAttrs, ".const:pdmCC26XXHWAttrs") -#pragma DATA_SECTION(pdmC26XXI2SHWAttrs, ".const:pdmC26XXI2SHWAttrs") -#pragma DATA_SECTION(PDMCC26XX_I2S_config, ".const:PDMCC26XX_I2S_config") -#endif - -/* Include drivers */ -#include -#include - -/* PDM objects, one for PDM driver, one for PDM/I2S helper file */ -PDMCC26XX_Object pdmCC26XXObjects[CC2650STK_PDMCOUNT]; -PDMCC26XX_I2S_Object pdmCC26XXI2SObjects[CC2650STK_PDMCOUNT]; - -/* PDM driver hardware attributes */ -const PDMCC26XX_HWAttrs pdmCC26XXHWAttrs[CC2650STK_PDMCOUNT] = { - { - .micPower = Board_MIC_POWER, - .taskPriority = 2 + .object = &cryptoCC26XXObjects[CC2650STK_CRYPTO0], + .hwAttrs = &cryptoCC26XXHWAttrs[CC2650STK_CRYPTO0] } }; -/* PDM configuration structure */ -const PDMCC26XX_Config PDMCC26XX_config[] = { - { - .object = &pdmCC26XXObjects[0], - .hwAttrs = &pdmCC26XXHWAttrs[0] - } -}; - -/* PDM_I2S hardware attributes */ -const PDMCC26XX_I2S_HWAttrs pdmC26XXI2SHWAttrs[CC2650STK_PDMCOUNT] = { - { - .baseAddr = I2S0_BASE, - .intNum = INT_I2S_IRQ, - .powerMngrId = PowerCC26XX_PERIPH_I2S, - .intPriority = ~0, - .mclkPin = PIN_UNASSIGNED, - .bclkPin = Board_AUDIO_CLK, - .wclkPin = PIN_UNASSIGNED, - .ad0Pin = Board_AUDIO_DI, - } -}; - -/* PDM_I2S configuration structure */ -const PDMCC26XX_I2S_Config PDMCC26XX_I2S_config[] = { - { - .object = &pdmCC26XXI2SObjects[0], - .hwAttrs = &pdmC26XXI2SHWAttrs[0] - }, - { NULL, NULL } -}; - /* - * ============================= PDM end ====================================== + * =============================== Display =============================== */ +#include +#include +#include -/* - * ========================= RF driver begin ================================== - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(RFCC26XX_hwAttrs, ".const:RFCC26XX_hwAttrs") +#ifndef CC2650STK_DISPLAY_UART_STRBUF_SIZE +#define CC2650STK_DISPLAY_UART_STRBUF_SIZE 128 #endif -/* Include drivers */ -#include - -/* RF hwi and swi priority */ -const RFCC26XX_HWAttrs RFCC26XX_hwAttrs = { - .hwiCpe0Priority = ~0, - .hwiHwPriority = ~0, - .swiCpe0Priority = 0, - .swiHwPriority = 0, -}; - -/* - * ========================== RF driver end =================================== - */ - -/* - * ========================= Display begin ==================================== - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(Display_config, ".const:Display_config") -#pragma DATA_SECTION(displaySharpHWattrs, ".const:displaySharpHWattrs") -#pragma DATA_SECTION(displayUartHWAttrs, ".const:displayUartHWAttrs") +#ifndef CC2650STK_DISPLAY_SHARP_SIZE +#define CC2650STK_DISPLAY_SHARP_SIZE 96 #endif -#include -#include -#include +DisplayUart_Object displayUartObject; +DisplaySharp_Object displaySharpObject; -/* Structures for UartPlain Blocking */ -DisplayUart_Object displayUartObject; - -#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE -#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 -#endif -static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; +static char uartStringBuf[CC2650STK_DISPLAY_UART_STRBUF_SIZE]; +static uint_least8_t sharpDisplayBuf[CC2650STK_DISPLAY_SHARP_SIZE * CC2650STK_DISPLAY_SHARP_SIZE / 8]; const DisplayUart_HWAttrs displayUartHWAttrs = { - .uartIdx = Board_UART, - .baudRate = 115200, - .mutexTimeout = BIOS_WAIT_FOREVER, - .strBuf = uartStringBuf, - .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, + .uartIdx = CC2650STK_UART0, + .baudRate = 115200, + .mutexTimeout = (unsigned int)(-1), + .strBuf = uartStringBuf, + .strBufLen = CC2650STK_DISPLAY_UART_STRBUF_SIZE, }; -/* Structures for SHARP */ -DisplaySharp_Object displaySharpObject; - -#ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 // 96->96x96 is the most common board, alternative is 128->128x128. -#endif -static uint8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; - -const DisplaySharp_HWAttrs displaySharpHWattrs = { - .spiIndex = Board_SPI0, - .csPin = Board_LCD_CS, - .extcominPin = Board_LCD_EXTCOMIN, - .powerPin = Board_LCD_POWER, - .enablePin = Board_LCD_ENABLE, - .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, - .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, +const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { + .spiIndex = CC2650STK_SPI0, + .csPin = CC2650STK_GPIO_LCD_CS, + .powerPin = (uint32_t)(-1), /* no need to apply power for this LCD */ + .enablePin = CC2650STK_GPIO_LCD_ENABLE, + .pixelWidth = CC2650STK_DISPLAY_SHARP_SIZE, + .pixelHeight = CC2650STK_DISPLAY_SHARP_SIZE, .displayBuf = sharpDisplayBuf, }; -/* As the pins for UART and Watch Devpack conflict, prefer UART by default */ -#if !defined(BOARD_DISPLAY_EXCLUDE_UART) && !defined(BOARD_DISPLAY_EXCLUDE_LCD) -# define BOARD_DISPLAY_EXCLUDE_LCD +/* + * The pins for the UART and Watch Devpack conflict, prefer UART by default + */ +#ifndef BOARD_DISPLAY_USE_UART +#define BOARD_DISPLAY_USE_UART 1 +#endif +#ifndef BOARD_DISPLAY_USE_UART_ANSI +#define BOARD_DISPLAY_USE_UART_ANSI 0 +#endif +#ifndef BOARD_DISPLAY_USE_LCD +#define BOARD_DISPLAY_USE_LCD 0 #endif -/* Array of displays */ +/* + * This #if/#else is needed to workaround a problem with the + * IAR compiler. The IAR compiler doesn't like the empty array + * initialization. (IAR Error[Pe1345]) + */ +#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) + const Display_Config Display_config[] = { -#if !defined(BOARD_DISPLAY_EXCLUDE_UART) +#if (BOARD_DISPLAY_USE_UART) { +# if (BOARD_DISPLAY_USE_UART_ANSI) + .fxnTablePtr = &DisplayUartAnsi_fxnTable, +# else /* Default to minimal UART with no cursor placement */ + .fxnTablePtr = &DisplayUartMin_fxnTable, +# endif .fxnTablePtr = &DisplayUart_fxnTable, .object = &displayUartObject, .hwAttrs = &displayUartHWAttrs, }, #endif -#if !defined(BOARD_DISPLAY_EXCLUDE_LCD) +#if (BOARD_DISPLAY_USE_LCD) { .fxnTablePtr = &DisplaySharp_fxnTable, .object = &displaySharpObject, .hwAttrs = &displaySharpHWattrs }, #endif - { NULL, NULL, NULL } // Terminator +}; + +const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); + +#else + +const Display_Config *Display_config = NULL; +const uint_least8_t Display_count = 0; + +#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ + +/* + * =============================== GPIO =============================== + */ +#include +#include + +/* + * Array of Pin configurations + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC2650STK.h + * NOTE: Pins not used for interrupts should be placed at the end of the + * array. Callback entries can be omitted from callbacks array to + * reduce memory usage. + */ +GPIO_PinConfig gpioPinConfigs[] = { + /* Input pins */ + GPIOCC26XX_DIO_15 | GPIO_DO_NOT_CONFIG, /* Button 0 */ + GPIOCC26XX_DIO_04 | GPIO_DO_NOT_CONFIG, /* Button 1 */ + + /* Output pins */ + GPIOCC26XX_DIO_10 | GPIO_DO_NOT_CONFIG, /* LED */ + + /* SPI Flash CSN */ + GPIOCC26XX_DIO_14 | GPIO_DO_NOT_CONFIG, + + /* Sharp Display - GPIO configurations will be done in the Display files */ + GPIOCC26XX_DIO_20 | GPIO_DO_NOT_CONFIG, /* LCD CS */ + GPIOCC26XX_DIO_29 | GPIO_DO_NOT_CONFIG, /* LCD Enable */ }; /* - * ========================= Display end ====================================== + * Array of callback function pointers + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC2650STK.h + * NOTE: Pins not used for interrupts can be omitted from callbacks array to + * reduce memory usage (if placed at end of gpioPinConfigs array). */ +GPIO_CallbackFxn gpioCallbackFunctions[] = { + NULL, /* Button 0 */ + NULL, /* Button 1 */ +}; + +const GPIOCC26XX_Config GPIOCC26XX_config = { + .pinConfigs = (GPIO_PinConfig *)gpioPinConfigs, + .callbacks = (GPIO_CallbackFxn *)gpioCallbackFunctions, + .numberOfPinConfigs = CC2650STK_GPIOCOUNT, + .numberOfCallbacks = sizeof(gpioCallbackFunctions)/sizeof(GPIO_CallbackFxn), + .intPriority = (~0) +}; /* - * ============================ GPTimer begin ================================= + * =============================== GPTimer =============================== * Remove unused entries to reduce flash usage both in Board.c and Board.h */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(GPTimerCC26XX_config, ".const:GPTimerCC26XX_config") -#pragma DATA_SECTION(gptimerCC26xxHWAttrs, ".const:gptimerCC26xxHWAttrs") -#endif +#include + +GPTimerCC26XX_Object gptimerCC26XXObjects[CC2650STK_GPTIMERCOUNT]; -/* GPTimer hardware attributes, one per timer part (Timer 0A, 0B, 1A, 1B..) */ const GPTimerCC26XX_HWAttrs gptimerCC26xxHWAttrs[CC2650STK_GPTIMERPARTSCOUNT] = { { .baseAddr = GPT0_BASE, .intNum = INT_GPT0A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0A, }, { .baseAddr = GPT0_BASE, .intNum = INT_GPT0B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0B, }, @@ -541,81 +232,405 @@ const GPTimerCC26XX_HWAttrs gptimerCC26xxHWAttrs[CC2650STK_GPTIMERPARTSCOUNT] = { .baseAddr = GPT3_BASE, .intNum = INT_GPT3B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3B, }, }; -/* GPTimer objects, one per full-width timer (A+B) (Timer 0, Timer 1..) */ -GPTimerCC26XX_Object gptimerCC26XXObjects[CC2650STK_GPTIMERCOUNT]; - -/* GPTimer configuration (used as GPTimer_Handle by driver and application) */ const GPTimerCC26XX_Config GPTimerCC26XX_config[CC2650STK_GPTIMERPARTSCOUNT] = { - { &gptimerCC26XXObjects[0], &gptimerCC26xxHWAttrs[0], GPT_A }, - { &gptimerCC26XXObjects[0], &gptimerCC26xxHWAttrs[1], GPT_B }, - { &gptimerCC26XXObjects[1], &gptimerCC26xxHWAttrs[2], GPT_A }, - { &gptimerCC26XXObjects[1], &gptimerCC26xxHWAttrs[3], GPT_B }, - { &gptimerCC26XXObjects[2], &gptimerCC26xxHWAttrs[4], GPT_A }, - { &gptimerCC26XXObjects[2], &gptimerCC26xxHWAttrs[5], GPT_B }, - { &gptimerCC26XXObjects[3], &gptimerCC26xxHWAttrs[6], GPT_A }, - { &gptimerCC26XXObjects[3], &gptimerCC26xxHWAttrs[7], GPT_B }, + { &gptimerCC26XXObjects[CC2650STK_GPTIMER0], &gptimerCC26xxHWAttrs[CC2650STK_GPTIMER0A], GPT_A }, + { &gptimerCC26XXObjects[CC2650STK_GPTIMER0], &gptimerCC26xxHWAttrs[CC2650STK_GPTIMER0B], GPT_B }, + { &gptimerCC26XXObjects[CC2650STK_GPTIMER1], &gptimerCC26xxHWAttrs[CC2650STK_GPTIMER1A], GPT_A }, + { &gptimerCC26XXObjects[CC2650STK_GPTIMER1], &gptimerCC26xxHWAttrs[CC2650STK_GPTIMER1B], GPT_B }, + { &gptimerCC26XXObjects[CC2650STK_GPTIMER2], &gptimerCC26xxHWAttrs[CC2650STK_GPTIMER2A], GPT_A }, + { &gptimerCC26XXObjects[CC2650STK_GPTIMER2], &gptimerCC26xxHWAttrs[CC2650STK_GPTIMER2B], GPT_B }, + { &gptimerCC26XXObjects[CC2650STK_GPTIMER3], &gptimerCC26xxHWAttrs[CC2650STK_GPTIMER3A], GPT_A }, + { &gptimerCC26XXObjects[CC2650STK_GPTIMER3], &gptimerCC26xxHWAttrs[CC2650STK_GPTIMER3B], GPT_B }, }; /* - * ============================ GPTimer end =================================== - */ + * =============================== I2C =============================== +*/ +#include +#include +I2CCC26XX_Object i2cCC26xxObjects[CC2650STK_I2CCOUNT]; +const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC2650STK_I2CCOUNT] = { + { + .baseAddr = I2C0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_I2C0, + .intNum = INT_I2C_IRQ, + .intPriority = ~0, + .swiPriority = 0, + .sdaPin = CC2650STK_I2C0_SDA0, + .sclPin = CC2650STK_I2C0_SCL0, + } +}; + +const I2C_Config I2C_config[CC2650STK_I2CCOUNT] = { + { + .fxnTablePtr = &I2CCC26XX_fxnTable, + .object = &i2cCC26xxObjects[CC2650STK_I2C0], + .hwAttrs = &i2cCC26xxHWAttrs[CC2650STK_I2C0] + }, +}; + +const uint_least8_t I2C_count = CC2650STK_I2CCOUNT; /* - * ============================= PWM begin ==================================== - * Remove unused entries to reduce flash usage both in Board.c and Board.h + * =============================== NVS =============================== + */ +#include +#include +#include + +#define NVS_REGIONS_BASE 0x1A000 +#define SECTORSIZE 0x1000 +#define REGIONSIZE (SECTORSIZE * 4) +#define SPIREGIONSIZE (SECTORSIZE * 32) +#define VERIFYBUFSIZE 64 + +static uint8_t verifyBuf[VERIFYBUFSIZE]; + +/* + * Reserve flash sectors for NVS driver use by placing an uninitialized byte + * array at the desired flash address. */ -/* Place into subsections to allow the TI linker to remove items properly */ #if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(PWM_config, ".const:PWM_config") -#pragma DATA_SECTION(pwmtimerCC26xxHWAttrs, ".const:pwmtimerCC26xxHWAttrs") + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +#pragma LOCATION(flashBuf, NVS_REGIONS_BASE); +#pragma NOINIT(flashBuf); +static char flashBuf[REGIONSIZE]; + +#elif defined(__IAR_SYSTEMS_ICC__) + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +static __no_init char flashBuf[REGIONSIZE] @ NVS_REGIONS_BASE; + +#elif defined(__GNUC__) + +/* + * Place the flash buffers in the .nvs section created in the gcc linker file. + * The .nvs section enforces alignment on a sector boundary but may + * be placed anywhere in flash memory. If desired the .nvs section can be set + * to a fixed address by changing the following in the gcc linker file: + * + * .nvs (FIXED_FLASH_ADDR) (NOLOAD) : AT (FIXED_FLASH_ADDR) { + * *(.nvs) + * } > REGION_TEXT + */ +__attribute__ ((section (".nvs"))) +static char flashBuf[REGIONSIZE]; + #endif -/* PWM configuration, one per PWM output. */ -PWMTimerCC26XX_HwAttrs pwmtimerCC26xxHWAttrs[CC2650STK_PWMCOUNT] = { - { .pwmPin = Board_PWMPIN0, .gpTimerUnit = Board_GPTIMER0A }, - { .pwmPin = Board_PWMPIN1, .gpTimerUnit = Board_GPTIMER0B }, - { .pwmPin = Board_PWMPIN2, .gpTimerUnit = Board_GPTIMER1A }, - { .pwmPin = Board_PWMPIN3, .gpTimerUnit = Board_GPTIMER1B }, - { .pwmPin = Board_PWMPIN4, .gpTimerUnit = Board_GPTIMER2A }, - { .pwmPin = Board_PWMPIN5, .gpTimerUnit = Board_GPTIMER2B }, - { .pwmPin = Board_PWMPIN6, .gpTimerUnit = Board_GPTIMER3A }, - { .pwmPin = Board_PWMPIN7, .gpTimerUnit = Board_GPTIMER3B }, +/* Allocate objects for NVS and NVS SPI */ +NVSCC26XX_Object nvsCC26xxObjects[1]; +NVSSPI25X_Object nvsSPI25XObjects[1]; + +/* Hardware attributes for NVS */ +const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { + { + .regionBase = (void *)flashBuf, + .regionSize = REGIONSIZE, + }, }; -/* PWM object, one per PWM output */ -PWMTimerCC26XX_Object pwmtimerCC26xxObjects[CC2650STK_PWMCOUNT]; - -extern const PWM_FxnTable PWMTimerCC26XX_fxnTable; - -/* PWM configuration (used as PWM_Handle by driver and application) */ -const PWM_Config PWM_config[CC2650STK_PWMCOUNT + 1] = { - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[0], &pwmtimerCC26xxHWAttrs[0] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[1], &pwmtimerCC26xxHWAttrs[1] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[2], &pwmtimerCC26xxHWAttrs[2] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[3], &pwmtimerCC26xxHWAttrs[3] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[4], &pwmtimerCC26xxHWAttrs[4] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[5], &pwmtimerCC26xxHWAttrs[5] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[6], &pwmtimerCC26xxHWAttrs[6] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[7], &pwmtimerCC26xxHWAttrs[7] }, - { NULL, NULL, NULL } +/* Hardware attributes for NVS SPI */ +const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { + { + .regionBaseOffset = 0, + .regionSize = SPIREGIONSIZE, + .sectorSize = SECTORSIZE, + .verifyBuf = verifyBuf, + .verifyBufSize = VERIFYBUFSIZE, + .spiHandle = NULL, + .spiIndex = 0, + .spiBitRate = 4000000, + .spiCsnGpioIndex = CC2650STK_GPIO_SPI_FLASH_CS, + }, }; +/* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ +const NVS_Config NVS_config[CC2650STK_NVSCOUNT] = { + { + .fxnTablePtr = &NVSCC26XX_fxnTable, + .object = &nvsCC26xxObjects[0], + .hwAttrs = &nvsCC26xxHWAttrs[0], + }, + { + .fxnTablePtr = &NVSSPI25X_fxnTable, + .object = &nvsSPI25XObjects[0], + .hwAttrs = &nvsSPI25XHWAttrs[0], + }, +}; + +const uint_least8_t NVS_count = CC2650STK_NVSCOUNT; /* - * ============================= PWM end ====================================== + * =============================== PDM =============================== +*/ +#include +#include + +PDMCC26XX_Object pdmCC26XXObjects[CC2650STK_PDMCOUNT]; +PDMCC26XX_I2S_Object pdmCC26XXI2SObjects[CC2650STK_PDMCOUNT]; + +const PDMCC26XX_HWAttrs pdmCC26XXHWAttrs[CC2650STK_PDMCOUNT] = { + { + .micPower = CC2650STK_MIC_POWER, + .taskPriority = 2 + } +}; + +const PDMCC26XX_Config PDMCC26XX_config[CC2650STK_PDMCOUNT] = { + { + .object = &pdmCC26XXObjects[CC2650STK_PDM0], + .hwAttrs = &pdmCC26XXHWAttrs[CC2650STK_PDM0] + } +}; + +const PDMCC26XX_I2S_HWAttrs pdmC26XXI2SHWAttrs[CC2650STK_PDMCOUNT] = { + { + .baseAddr = I2S0_BASE, + .intNum = INT_I2S_IRQ, + .powerMngrId = PowerCC26XX_PERIPH_I2S, + .intPriority = ~0, + .mclkPin = PIN_UNASSIGNED, + .bclkPin = CC2650STK_AUDIO_CLK, + .wclkPin = PIN_UNASSIGNED, + .ad0Pin = CC2650STK_AUDIO_DI, + } +}; + +const PDMCC26XX_I2S_Config PDMCC26XX_I2S_config[CC2650STK_PDMCOUNT] = { + { + .object = &pdmCC26XXI2SObjects[CC2650STK_PDM0], + .hwAttrs = &pdmC26XXI2SHWAttrs[CC2650STK_PDM0] + } +}; + +/* + * =============================== PIN =============================== */ +#include +#include + +const PIN_Config BoardGpioInitTable[] = { + + CC2650STK_PIN_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC2650STK_KEY_LEFT | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC2650STK_KEY_RIGHT | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC2650STK_RELAY | PIN_INPUT_EN | PIN_PULLDOWN | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Relay is active high */ + CC2650STK_MPU_INT | PIN_INPUT_EN | PIN_PULLDOWN | PIN_IRQ_NEGEDGE | PIN_HYSTERESIS, /* MPU_INT is active low */ + CC2650STK_TMP_RDY | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS, /* TMP_RDY is active high */ + CC2650STK_BUZZER | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Buzzer initially off */ + CC2650STK_MPU_POWER | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* MPU initially on */ + CC2650STK_MIC_POWER | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* MIC initially off */ + CC2650STK_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ + CC2650STK_SPI_DEVPK_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* DevPack chip select */ + CC2650STK_AUDIO_DI | PIN_INPUT_EN | PIN_PULLDOWN, /* Audio DI */ + CC2650STK_AUDIODO | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* Audio data out */ + CC2650STK_AUDIO_CLK | PIN_INPUT_EN | PIN_PULLDOWN, /* DevPack */ + CC2650STK_DP2 | PIN_INPUT_EN | PIN_PULLDOWN, /* DevPack */ + CC2650STK_DP1 | PIN_INPUT_EN | PIN_PULLDOWN, /* DevPack */ + CC2650STK_DP0 | PIN_INPUT_EN | PIN_PULLDOWN, /* DevPack */ + CC2650STK_DP3 | PIN_INPUT_EN | PIN_PULLDOWN, /* DevPack */ + CC2650STK_UART_TX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* DevPack */ + CC2650STK_UART_RX | PIN_INPUT_EN | PIN_PULLDOWN, /* DevPack */ + CC2650STK_DEVPK_ID | PIN_INPUT_EN | PIN_NOPULL, /* Device pack ID - external PU */ + CC2650STK_SPI0_MOSI | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master out - slave in */ + CC2650STK_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master in - slave out */ + CC2650STK_SPI0_CLK | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI clock */ + + PIN_TERMINATE +}; + +const PINCC26XX_HWAttrs PINCC26XX_hwAttrs = { + .intPriority = ~0, + .swiPriority = 0 +}; + +/* + * =============================== Power =============================== + */ +const PowerCC26XX_Config PowerCC26XX_config = { + .policyInitFxn = NULL, + .policyFxn = &PowerCC26XX_standbyPolicy, + .calibrateFxn = &PowerCC26XX_calibrate, + .enablePolicy = true, + .calibrateRCOSC_LF = true, + .calibrateRCOSC_HF = true, +}; + +/* + * =============================== PWM =============================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +#include +#include + +PWMTimerCC26XX_Object pwmtimerCC26xxObjects[CC2650STK_PWMCOUNT]; + +const PWMTimerCC26XX_HwAttrs pwmtimerCC26xxHWAttrs[CC2650STK_PWMCOUNT] = { + { .pwmPin = CC2650STK_PWMPIN0, .gpTimerUnit = CC2650STK_GPTIMER0A }, + { .pwmPin = CC2650STK_PWMPIN1, .gpTimerUnit = CC2650STK_GPTIMER0B }, + { .pwmPin = CC2650STK_PWMPIN2, .gpTimerUnit = CC2650STK_GPTIMER1A }, + { .pwmPin = CC2650STK_PWMPIN3, .gpTimerUnit = CC2650STK_GPTIMER1B }, + { .pwmPin = CC2650STK_PWMPIN4, .gpTimerUnit = CC2650STK_GPTIMER2A }, + { .pwmPin = CC2650STK_PWMPIN5, .gpTimerUnit = CC2650STK_GPTIMER2B }, + { .pwmPin = CC2650STK_PWMPIN6, .gpTimerUnit = CC2650STK_GPTIMER3A }, + { .pwmPin = CC2650STK_PWMPIN7, .gpTimerUnit = CC2650STK_GPTIMER3B }, +}; + +const PWM_Config PWM_config[CC2650STK_PWMCOUNT] = { + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2650STK_PWM0], &pwmtimerCC26xxHWAttrs[CC2650STK_PWM0] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2650STK_PWM1], &pwmtimerCC26xxHWAttrs[CC2650STK_PWM1] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2650STK_PWM2], &pwmtimerCC26xxHWAttrs[CC2650STK_PWM2] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2650STK_PWM3], &pwmtimerCC26xxHWAttrs[CC2650STK_PWM3] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2650STK_PWM4], &pwmtimerCC26xxHWAttrs[CC2650STK_PWM4] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2650STK_PWM5], &pwmtimerCC26xxHWAttrs[CC2650STK_PWM5] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2650STK_PWM6], &pwmtimerCC26xxHWAttrs[CC2650STK_PWM6] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2650STK_PWM7], &pwmtimerCC26xxHWAttrs[CC2650STK_PWM7] }, +}; + +const uint_least8_t PWM_count = CC2650STK_PWMCOUNT; + +/* + * =============================== RF Driver =============================== + */ +#include + +const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { + .hwiPriority = ~0, /* Lowest HWI priority */ + .swiPriority = 0, /* Lowest SWI priority */ + .xoscHfAlwaysNeeded = true, /* Keep XOSC dependency while in stanby */ + .globalCallback = NULL, /* No board specific callback */ + .globalEventMask = 0 /* No events subscribed to */ +}; + +/* + * =============================== SPI DMA =============================== + */ +#include +#include + +SPICC26XXDMA_Object spiCC26XXDMAObjects[CC2650STK_SPICOUNT]; + +const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC2650STK_SPICOUNT] = { + { + .baseAddr = SSI0_BASE, + .intNum = INT_SSI0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .powerMngrId = PowerCC26XX_PERIPH_SSI0, + .defaultTxBufValue = 0, + .rxChannelBitMask = 1< +#include + +UARTCC26XX_Object uartCC26XXObjects[CC2650STK_UARTCOUNT]; + +uint8_t uartCC26XXRingBuffer[CC2650STK_UARTCOUNT][32]; + +const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC2650STK_UARTCOUNT] = { + { + .baseAddr = UART0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UART0, + .intNum = INT_UART0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .txPin = CC2650STK_UART_TX, + .rxPin = CC2650STK_UART_RX, + .ctsPin = PIN_UNASSIGNED, + .rtsPin = PIN_UNASSIGNED, + .ringBufPtr = uartCC26XXRingBuffer[CC2650STK_UART0], + .ringBufSize = sizeof(uartCC26XXRingBuffer[CC2650STK_UART0]), + .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, + .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, + .errorFxn = NULL + } +}; + +const UART_Config UART_config[CC2650STK_UARTCOUNT] = { + { + .fxnTablePtr = &UARTCC26XX_fxnTable, + .object = &uartCC26XXObjects[CC2650STK_UART0], + .hwAttrs = &uartCC26XXHWAttrs[CC2650STK_UART0] + }, +}; + +const uint_least8_t UART_count = CC2650STK_UARTCOUNT; + +/* + * =============================== UDMA =============================== + */ +#include + +UDMACC26XX_Object udmaObjects[CC2650STK_UDMACOUNT]; + +const UDMACC26XX_HWAttrs udmaHWAttrs[CC2650STK_UDMACOUNT] = { + { + .baseAddr = UDMA0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UDMA, + .intNum = INT_DMA_ERR, + .intPriority = ~0 + } +}; + +const UDMACC26XX_Config UDMACC26XX_config[CC2650STK_UDMACOUNT] = { + { + .object = &udmaObjects[CC2650STK_UDMA0], + .hwAttrs = &udmaHWAttrs[CC2650STK_UDMA0] + }, +}; /* * =============================== Watchdog =============================== */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(Watchdog_config, ".const:Watchdog_config") -#pragma DATA_SECTION(watchdogCC26XXHWAttrs, ".const:watchdogCC26XXHWAttrs") -#endif - #include #include @@ -623,25 +638,39 @@ WatchdogCC26XX_Object watchdogCC26XXObjects[CC2650STK_WATCHDOGCOUNT]; const WatchdogCC26XX_HWAttrs watchdogCC26XXHWAttrs[CC2650STK_WATCHDOGCOUNT] = { { - .baseAddr = WDT_BASE, - .intNum = INT_WDT_IRQ, + .baseAddr = WDT_BASE, .reloadValue = 1000 /* Reload value in milliseconds */ }, }; -const Watchdog_Config Watchdog_config[] = { +const Watchdog_Config Watchdog_config[CC2650STK_WATCHDOGCOUNT] = { { .fxnTablePtr = &WatchdogCC26XX_fxnTable, - .object = &watchdogCC26XXObjects[0], - .hwAttrs = &watchdogCC26XXHWAttrs[0] + .object = &watchdogCC26XXObjects[CC2650STK_WATCHDOG0], + .hwAttrs = &watchdogCC26XXHWAttrs[CC2650STK_WATCHDOG0] }, - {NULL, NULL, NULL}, }; +const uint_least8_t Watchdog_count = CC2650STK_WATCHDOGCOUNT; + /* - * ======== CC26XX_LAUNCHXL_initWatchdog ======== + * Board-specific initialization function to disable external flash. + * This function is defined in the file CC2650STK_fxns.c */ -void CC26XX_LAUNCHXL_initWatchdog(void) +extern void Board_initHook(void); + +/* + * ======== CC2650STK_initGeneral ======== + */ +void CC2650STK_initGeneral(void) { - Watchdog_init(); + Power_init(); + + if ( PIN_init(BoardGpioInitTable) != PIN_SUCCESS) { + /* Error with PIN_init */ + while (1); + } + + /* Perform board-specific initialization */ + Board_initHook(); } diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h index 6cfd69f7d..ce07503f0 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, Texas Instruments Incorporated + * Copyright (c) 2015-2018, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,297 +30,294 @@ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** ============================================================================ - * @file CC2650STK.h + * @file CC1350STK.h * - * @brief CC2650SENSORTAG Board Specific header file. - * - * NB! This is the board file for PCB versions 1.2 and 1.3 + * @brief CC1350STK Board Specific header file. * + * The CC1350STK header file should be included in an application as + * follows: + * @code + * #include "CC1350STK.h" + * @endcode * ============================================================================ */ -#ifndef __CC2650STK_SENSORTAG_BOARD_H__ -#define __CC2650STK_SENSORTAG_BOARD_H__ +#ifndef __CC1350STK_BOARD_H__ +#define __CC1350STK_BOARD_H__ #ifdef __cplusplus extern "C" { #endif -/** ============================================================================ - * Includes - * ==========================================================================*/ +/* Includes */ #include -#include +#include -/** ============================================================================ - * Externs - * ==========================================================================*/ +/* Externs */ extern const PIN_Config BoardGpioInitTable[]; -/** ============================================================================ - * Defines - * ==========================================================================*/ - -/* Same RF Configuration as 7x7 EM */ -#define CC2650EM_7ID -#define CC2650STK +/* Defines */ +#define CC1350STK /* Mapping of pins to board signals using general board aliases - * + * */ -/* Discrete outputs */ -#define Board_STK_LED1 IOID_10 -#define Board_STK_LED2 IOID_15 -#define Board_BUZZER IOID_21 -#define Board_LED_ON 1 -#define Board_LED_OFF 0 -#define Board_BUZZER_ON 1 -#define Board_BUZZER_OFF 0 - -/* Discrete inputs */ -#define Board_KEY_LEFT IOID_0 -#define Board_KEY_RIGHT IOID_4 -#define Board_RELAY IOID_3 - -/* Sensor outputs */ -#define Board_MPU_INT IOID_7 -#define Board_TMP_RDY IOID_1 - -/* I2C */ -#define Board_I2C0_SDA0 IOID_5 -#define Board_I2C0_SCL0 IOID_6 -#define Board_I2C0_SDA1 IOID_8 -#define Board_I2C0_SCL1 IOID_9 - -/* SPI */ -#define Board_SPI_FLASH_CS IOID_14 -#define Board_SPI_DEVPK_CS IOID_20 -#define Board_FLASH_CS_ON 0 -#define Board_FLASH_CS_OFF 1 -#define Board_DEVPK_CS_ON 1 -#define Board_DEVPK_CS_OFF 0 - -#define Board_SPI0_MISO IOID_18 -#define Board_SPI0_MOSI IOID_19 -#define Board_SPI0_CLK IOID_17 -#define Board_SPI0_CSN PIN_UNASSIGNED -#define Board_SPI1_MISO PIN_UNASSIGNED -#define Board_SPI1_MOSI PIN_UNASSIGNED -#define Board_SPI1_CLK PIN_UNASSIGNED -#define Board_SPI1_CSN PIN_UNASSIGNED - -/* UART when connected to SRF06EB */ -#define Board_EB_UART_TX IOID_16 -#define Board_EB_UART_RX IOID_17 - -/* Power control */ -#define Board_MPU_POWER IOID_12 -#define Board_MPU_POWER_ON 1 -#define Board_MPU_POWER_OFF 0 - /* Audio */ -#define Board_MIC_POWER IOID_13 -#define Board_MIC_POWER_ON 1 -#define Board_MIC_POWER_OFF 0 -#define Board_AUDIO_DI IOID_2 -#define Board_AUDIO_CLK IOID_11 +#define CC1350STK_MIC_POWER IOID_13 +#define CC1350STK_MIC_POWER_ON 1 +#define CC1350STK_MIC_POWER_OFF 0 +#define CC1350STK_AUDIO_DI IOID_2 +#define CC1350STK_AUDIO_CLK IOID_3 -/* UART pins used by driver */ -#define Board_UART_TX Board_DP5_UARTTX -#define Board_UART_RX Board_DP4_UARTRX +/* Buzzer */ +#define CC1350STK_BUZZER IOID_21 +#define CC1350STK_BUZZER_ON 1 +#define CC1350STK_BUZZER_OFF 0 -/* DevPack common */ -#define Board_AUDIOFS_TDO IOID_16 -#define Board_AUDIODO IOID_22 -#define Board_DP2 IOID_23 -#define Board_DP1 IOID_24 -#define Board_DP0 IOID_25 -#define Board_DP3 IOID_27 -#define Board_DP4_UARTRX IOID_28 -#define Board_DP5_UARTTX IOID_29 -#define Board_DEVPK_ID IOID_30 -#define Board_SPI_DEVPK_CS IOID_20 +/* DevPack */ +#define CC1350STK_AUDIOFS_TDO IOID_16 +#define CC1350STK_AUDIODO IOID_22 +#define CC1350STK_DP2 IOID_23 +#define CC1350STK_DP1 IOID_24 +#define CC1350STK_DP0 IOID_25 +#define CC1350STK_DP3 IOID_27 +#define CC1350STK_DP4_UARTRX IOID_28 +#define CC1350STK_DP5_UARTTX IOID_29 +#define CC1350STK_DEVPK_ID IOID_30 +#define CC1350STK_SPI_DEVPK_CS IOID_20 -/* LCD DevPack */ -#define Board_LCD_EXTCOMIN IOID_22 -#define Board_LCD_EXTMODE IOID_28 -#define Board_LCD_ENABLE IOID_29 -#define Board_LCD_POWER PIN_UNASSIGNED -#define Board_LCD_CS Board_SPI_DEVPK_CS -#define Board_LCD_CS_ON 1 -#define Board_LCD_CS_OFF 0 +/* Discrete Outputs */ +#define CC1350STK_PIN_LED1 IOID_10 +#define CC1350STK_LED_ON 1 +#define CC1350STK_LED_OFF 0 + + +/* Discrete Inputs */ +#define CC1350STK_KEY_LEFT IOID_15 +#define CC1350STK_KEY_RIGHT IOID_4 +#define CC1350STK_RELAY IOID_1 + +/* GPIO */ +#define CC1350STK_GPIO_LED_ON 1 +#define CC1350STK_GPIO_LED_OFF 0 + +/* I2C */ +#define CC1350STK_I2C0_SDA0 IOID_5 +#define CC1350STK_I2C0_SCL0 IOID_6 +#define CC1350STK_I2C0_SDA1 IOID_8 +#define CC1350STK_I2C0_SCL1 IOID_9 /* LED-Audio DevPack */ -#define Board_DEVPK_LIGHT_BLUE IOID_23 -#define Board_DEVPK_LIGHT_GREEN IOID_24 -#define Board_DEVPK_LIGHT_WHITE IOID_25 -#define Board_DEVPK_LIGHT_RED IOID_27 +#define CC1350STK_DEVPK_LIGHT_BLUE IOID_23 +#define CC1350STK_DEVPK_LIGHT_GREEN IOID_24 +#define CC1350STK_DEVPK_LIGHT_WHITE IOID_25 +#define CC1350STK_DEVPK_LIGHT_RED IOID_27 -/* PWM outputs */ -#define Board_PWMPIN0 Board_STK_LED1 -#define Board_PWMPIN1 Board_STK_LED2 -#define Board_PWMPIN2 PIN_UNASSIGNED -#define Board_PWMPIN3 PIN_UNASSIGNED -#define Board_PWMPIN4 PIN_UNASSIGNED -#define Board_PWMPIN5 PIN_UNASSIGNED -#define Board_PWMPIN6 PIN_UNASSIGNED -#define Board_PWMPIN7 PIN_UNASSIGNED +/* Power */ +#define CC1350STK_MPU_POWER IOID_12 +#define CC1350STK_MPU_POWER_ON 1 +#define CC1350STK_MPU_POWER_OFF 0 -/** ============================================================================ - * Instance identifiers - * ==========================================================================*/ -/* Generic I2C instance identifiers */ -#define Board_I2C CC2650STK_I2C0 -/* Generic PDM instance identifiers */ -#define Board_PDM CC2650STK_PDM0 -/* Generic SPI instance identifiers */ -#define Board_SPI0 CC2650STK_SPI0 -#define Board_SPI1 CC2650STK_SPI1 -/* Generic UART instance identifiers */ -#define Board_UART CC2650STK_UART0 -/* Generic Crypto instance identifiers */ -#define Board_CRYPTO CC2650STK_CRYPTO0 -/* Generic GPTimer instance identifiers */ -#define Board_GPTIMER0A CC2650STK_GPTIMER0A -#define Board_GPTIMER0B CC2650STK_GPTIMER0B -#define Board_GPTIMER1A CC2650STK_GPTIMER1A -#define Board_GPTIMER1B CC2650STK_GPTIMER1B -#define Board_GPTIMER2A CC2650STK_GPTIMER2A -#define Board_GPTIMER2B CC2650STK_GPTIMER2B -#define Board_GPTIMER3A CC2650STK_GPTIMER3A -#define Board_GPTIMER3B CC2650STK_GPTIMER3B -/* Generic PWM instance identifiers */ -#define Board_PWM0 CC2650STK_PWM0 -#define Board_PWM1 CC2650STK_PWM1 -#define Board_PWM2 CC2650STK_PWM2 -#define Board_PWM3 CC2650STK_PWM3 -#define Board_PWM4 CC2650STK_PWM4 -#define Board_PWM5 CC2650STK_PWM5 -#define Board_PWM6 CC2650STK_PWM6 -#define Board_PWM7 CC2650STK_PWM7 +/* PWM */ +#define CC1350STK_PWMPIN0 CC1350STK_PIN_LED1 +#define CC1350STK_PWMPIN1 CC1350STK_PIN_LED1 +#define CC1350STK_PWMPIN2 PIN_UNASSIGNED +#define CC1350STK_PWMPIN3 PIN_UNASSIGNED +#define CC1350STK_PWMPIN4 PIN_UNASSIGNED +#define CC1350STK_PWMPIN5 PIN_UNASSIGNED +#define CC1350STK_PWMPIN6 PIN_UNASSIGNED +#define CC1350STK_PWMPIN7 PIN_UNASSIGNED -/** ============================================================================ - * Number of peripherals and their names - * ==========================================================================*/ +/* Sensors */ +#define CC1350STK_MPU_INT IOID_7 +#define CC1350STK_TMP_RDY IOID_11 + +/* SPI */ +#define CC1350STK_SPI_FLASH_CS IOID_14 +#define CC1350STK_FLASH_CS_ON 0 +#define CC1350STK_FLASH_CS_OFF 1 + +/* SPI Board */ +#define CC1350STK_SPI0_MISO IOID_18 +#define CC1350STK_SPI0_MOSI IOID_19 +#define CC1350STK_SPI0_CLK IOID_17 +#define CC1350STK_SPI0_CSN PIN_UNASSIGNED +#define CC1350STK_SPI1_MISO PIN_UNASSIGNED +#define CC1350STK_SPI1_MOSI PIN_UNASSIGNED +#define CC1350STK_SPI1_CLK PIN_UNASSIGNED +#define CC1350STK_SPI1_CSN PIN_UNASSIGNED + +/* UART */ +#define CC1350STK_UART_TX CC1350STK_DP5_UARTTX +#define CC1350STK_UART_RX CC1350STK_DP4_UARTRX /*! - * @def CC2650STK_I2CName - * @brief Enum of I2C names on the CC2650 dev board + * @brief Initialize the general board specific settings + * + * This function initializes the general board specific settings. */ -typedef enum CC2650STK_I2CName { - CC2650STK_I2C0 = 0, - - CC2650STK_I2CCOUNT -} CC2650STK_I2CName; +void CC1350STK_initGeneral(void); /*! - * @def CC2650STK_CryptoName - * @brief Enum of Crypto names on the CC2650 dev board + * @brief Turn off the external flash on LaunchPads + * */ -typedef enum CC2650STK_CryptoName { - CC2650STK_CRYPTO0 = 0, - - CC2650STK_CRYPTOCOUNT -} CC2650STK_CryptoName; +void CC1350STK_shutDownExtFlash(void); /*! - * @def CC2650STK_PdmName - * @brief Enum of PDM names on the CC2650 dev board + * @brief Wake up the external flash present on the board files + * + * This function toggles the chip select for the amount of time needed + * to wake the chip up. */ -typedef enum CC2650STK_PDMName { - CC2650STK_PDM0 = 0, - CC2650STK_PDMCOUNT -} CC2650STK_PDMName; +void CC1350STK_wakeUpExtFlash(void); /*! - * @def CC2650STK_SPIName - * @brief Enum of SPI names on the CC2650 dev board + * @def CC1350STK_CryptoName + * @brief Enum of Crypto names */ -typedef enum CC2650STK_SPIName { - CC2650STK_SPI0 = 0, - CC2650STK_SPI1, +typedef enum CC1350STK_CryptoName { + CC1350STK_CRYPTO0 = 0, - CC2650STK_SPICOUNT -} CC2650STK_SPIName; + CC1350STK_CRYPTOCOUNT +} CC1350STK_CryptoName; /*! - * @def CC2650STK_UARTName - * @brief Enum of UARTs on the CC2650 dev board + * @def CC1350STK_GPIOName + * @brief Enum of GPIO names */ -typedef enum CC2650STK_UARTName { - CC2650STK_UART0 = 0, +typedef enum CC1350STK_GPIOName { + CC1350STK_GPIO_S1 = 0, + CC1350STK_GPIO_S2, + CC1350STK_GPIO_LED0, + CC1350STK_GPIO_SPI_FLASH_CS, + CC1350STK_GPIO_LCD_CS, + CC1350STK_GPIO_LCD_ENABLE, - CC2650STK_UARTCOUNT -} CC2650STK_UARTName; + CC1350STK_GPIOCOUNT +} CC1350STK_GPIOName; /*! - * @def CC2650STK_UdmaName - * @brief Enum of DMA buffers + * @def CC1350STK_GPTimerName + * @brief Enum of GPTimers parts */ -typedef enum CC2650STK_UdmaName { - CC2650STK_UDMA0 = 0, +typedef enum CC1350STK_GPTimerName { + CC1350STK_GPTIMER0A = 0, + CC1350STK_GPTIMER0B, + CC1350STK_GPTIMER1A, + CC1350STK_GPTIMER1B, + CC1350STK_GPTIMER2A, + CC1350STK_GPTIMER2B, + CC1350STK_GPTIMER3A, + CC1350STK_GPTIMER3B, - CC2650STK_UDMACOUNT -} CC2650STK_UdmaName; -/*! - * @def CC2650STK_GPTimerName - * @brief Enum of GPTimer parts - */ -typedef enum CC2650STK_GPTimerName -{ - CC2650STK_GPTIMER0A = 0, - CC2650STK_GPTIMER0B, - CC2650STK_GPTIMER1A, - CC2650STK_GPTIMER1B, - CC2650STK_GPTIMER2A, - CC2650STK_GPTIMER2B, - CC2650STK_GPTIMER3A, - CC2650STK_GPTIMER3B, - CC2650STK_GPTIMERPARTSCOUNT -} CC2650STK_GPTimerName; + CC1350STK_GPTIMERPARTSCOUNT +} CC1350STK_GPTimerName; /*! - * @def CC2650STK_GPTimers + * @def CC1350STK_GPTimers * @brief Enum of GPTimers */ -typedef enum CC2650STK_GPTimers -{ - CC2650STK_GPTIMER0 = 0, - CC2650STK_GPTIMER1, - CC2650STK_GPTIMER2, - CC2650STK_GPTIMER3, - CC2650STK_GPTIMERCOUNT -} CC2650STK_GPTimers; +typedef enum CC1350STK_GPTimers { + CC1350STK_GPTIMER0 = 0, + CC1350STK_GPTIMER1, + CC1350STK_GPTIMER2, + CC1350STK_GPTIMER3, + + CC1350STK_GPTIMERCOUNT +} CC1350STK_GPTimers; /*! - * @def CC2650STK_PWM - * @brief Enum of PWM outputs on the board + * @def CC1350STK_I2CName + * @brief Enum of I2C names */ -typedef enum CC2650STK_PWM -{ - CC2650STK_PWM0 = 0, - CC2650STK_PWM1, - CC2650STK_PWM2, - CC2650STK_PWM3, - CC2650STK_PWM4, - CC2650STK_PWM5, - CC2650STK_PWM6, - CC2650STK_PWM7, - CC2650STK_PWMCOUNT -} CC2650STK_PWM; +typedef enum CC1350STK_I2CName { + CC1350STK_I2C0 = 0, + + CC1350STK_I2CCOUNT +} CC1350STK_I2CName; /*! - * @def CC2650STK_WatchdogName - * @brief Enum of Watchdogs on the CC2650STK dev board + * @def CC1350STK_NVSName + * @brief Enum of NVS names */ -typedef enum CC2650STK_WatchdogName { - CC2650STK_WATCHDOG0 = 0, +typedef enum CC1350STK_NVSName { + CC1350STK_NVSCC26XX0 = 0, + CC1350STK_NVSSPI25X0, - CC2650STK_WATCHDOGCOUNT -} CC2650STK_WatchdogName; + CC1350STK_NVSCOUNT +} CC1350STK_NVSName; + +/*! + * @def CC1350STK_PdmName + * @brief Enum of PDM names + */ +typedef enum CC1350STK_PDMName { + CC1350STK_PDM0 = 0, + + CC1350STK_PDMCOUNT +} CC1350STK_PDMName; + +/*! + * @def CC1350STK_PWM + * @brief Enum of PWM outputs + */ +typedef enum CC1350STK_PWMName { + CC1350STK_PWM0 = 0, + CC1350STK_PWM1, + CC1350STK_PWM2, + CC1350STK_PWM3, + CC1350STK_PWM4, + CC1350STK_PWM5, + CC1350STK_PWM6, + CC1350STK_PWM7, + + CC1350STK_PWMCOUNT +} CC1350STK_PWMName; + +/*! + * @def CC1350STK_SPIName + * @brief Enum of SPI names + */ +typedef enum CC1350STK_SPIName { + CC1350STK_SPI0 = 0, + CC1350STK_SPI1, + + CC1350STK_SPICOUNT +} CC1350STK_SPIName; + +/*! + * @def CC1350STK_UARTName + * @brief Enum of UARTs + */ +typedef enum CC1350STK_UARTName { + CC1350STK_UART0 = 0, + + CC1350STK_UARTCOUNT +} CC1350STK_UARTName; + +/*! + * @def CC1350STK_UDMAName + * @brief Enum of DMA buffers + */ +typedef enum CC1350STK_UDMAName { + CC1350STK_UDMA0 = 0, + + CC1350STK_UDMACOUNT +} CC1350STK_UDMAName; + +/*! + * @def CC1350STK_WatchdogName + * @brief Enum of Watchdogs + */ +typedef enum CC1350STK_WatchdogName { + CC1350STK_WATCHDOG0 = 0, + + CC1350STK_WATCHDOGCOUNT +} CC1350STK_WatchdogName; #ifdef __cplusplus } #endif -#endif /* __CC2650STK_SENSORTAG_BOARD_H__ */ +#endif /* __CC1350STK_BOARD_H__ */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK_fxns.c new file mode 100644 index 000000000..1a56667da --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK_fxns.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ +/* + * ====================== CC2650STK_fxns.c ========================================= + * This file contains the board-specific initialization functions. + */ + +#include +#include +#include + +#include +#include + +#include "Board.h" + +/* + * ======== CC2650STK_sendExtFlashByte ======== + */ +void CC2650STK_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte) +{ + uint8_t i; + + /* SPI Flash CS */ + PIN_setOutputValue(pinHandle, IOID_14, 0); + + for (i = 0; i < 8; i++) { + PIN_setOutputValue(pinHandle, IOID_17, 0); /* SPI Flash CLK */ + + /* SPI Flash MOSI */ + PIN_setOutputValue(pinHandle, IOID_19, (byte >> (7 - i)) & 0x01); + PIN_setOutputValue(pinHandle, IOID_17, 1); + + /* + * Waste a few cycles to keep the CLK high for at + * least 45% of the period. + * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us. + */ + CPUdelay(8); + } + + PIN_setOutputValue(pinHandle, IOID_17, 0); + PIN_setOutputValue(pinHandle, IOID_14, 1); + + /* + * Keep CS high at least 40 us + * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us + */ + CPUdelay(700); +} + +/* + * ======== CC2650STK_wakeUpExtFlash ======== + */ +void CC2650STK_wakeUpExtFlash(void) +{ + PIN_Config extFlashPinTable[] = { + IOID_14 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + /* + * To wake up we need to toggle the chip select at + * least 20 ns and ten wait at least 35 us. + */ + + /* Toggle chip select for ~20ns to wake ext. flash */ + PIN_setOutputValue(extFlashPinHandle, IOID_14, 0); + /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */ + CPUdelay(1); + PIN_setOutputValue(extFlashPinHandle, IOID_14, 1); + /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */ + CPUdelay(560); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== CC2650STK_shutDownExtFlash ======== + */ +void CC2650STK_shutDownExtFlash(void) +{ + /* + * To be sure we are putting the flash into sleep and not waking it, + * we first have to make a wake up call + */ + CC2650STK_wakeUpExtFlash(); + + PIN_Config extFlashPinTable[] = { + /* SPI Flash CS*/ + IOID_14 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash CLK */ + IOID_17 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash MOSI */ + IOID_19 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | + PIN_INPUT_DIS | PIN_DRVSTR_MED, + /* SPI Flash MISO */ + IOID_18 | PIN_INPUT_EN | PIN_PULLDOWN, + PIN_TERMINATE + }; + PIN_State extFlashPinState; + PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable); + + uint8_t extFlashShutdown = 0xB9; + + CC2650STK_sendExtFlashByte(extFlashPinHandle, extFlashShutdown); + + PIN_close(extFlashPinHandle); +} + +/* + * ======== Board_initHook ======== + * Called by Board_init() to perform board-specific initialization. + */ +void Board_initHook() +{ + CC2650STK_shutDownExtFlash(); +} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 index f0fdb2e67..b3e796d82 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 @@ -3,8 +3,9 @@ SUBFAMILY = cc13x0-cc26x0 DEVICE_FAMILY = CC26X0 +DEVICE_LINE = CC26XX -BOARD_SOURCEFILES += CC2650STK.c +BOARD_SOURCEFILES += CC2650STK.c CC2650STK_fxns.c SUPPORTS_PROP_MODE = 0 SUPPORTS_IEEE_MODE = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.c index acc5f19be..7e8f9ccb0 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.c @@ -40,11 +40,11 @@ #include "sys/ctimer.h" #include "lib/sensors.h" #include "hdc-1000-sensor.h" -#include "sensor-common.h" -#include "board-i2c.h" - -#include "ti-lib.h" +/*---------------------------------------------------------------------------*/ +#include +#include +/*---------------------------------------------------------------------------*/ #include #include #include @@ -57,9 +57,12 @@ #define PRINTF(...) #endif /*---------------------------------------------------------------------------*/ +#ifndef Board_HDC1000_ADDR +# error "Board file doesn't define I2C address Board_HDC1000_ADDR" +#endif /* Sensor I2C address */ -#define SENSOR_I2C_ADDRESS 0x43 - +#define HDC1000_I2C_ADDRESS Board_HDC1000_ADDR +/*---------------------------------------------------------------------------*/ /* Registers */ #define HDC1000_REG_TEMP 0x00 /* Temperature */ #define HDC1000_REG_HUM 0x01 /* Humidity */ @@ -83,22 +86,21 @@ #define HI_UINT16(a) (((a) >> 8) & 0xFF) #define LO_UINT16(a) ((a) & 0xFF) -#define SWAP(v) ((LO_UINT16(v) << 8) | HI_UINT16(v)) +#define SWAP16(v) ((LO_UINT16(v) << 8) | HI_UINT16(v)) + +#define LSB16(v) (LO_UINT16(v)), (HI_UINT16(v)) +/*---------------------------------------------------------------------------*/ +static I2C_Handle i2cHandle; /*---------------------------------------------------------------------------*/ /* Raw data as returned from the sensor (Big Endian) */ -typedef struct sensor_data { +typedef struct { uint16_t temp; uint16_t hum; -} sensor_data_t; +} HDC_1000_SensorData; -/* Raw data, little endian */ -static uint16_t raw_temp; -static uint16_t raw_hum; +static HDC_1000_SensorData sensor_data; /*---------------------------------------------------------------------------*/ -static bool success; -static sensor_data_t data; -/*---------------------------------------------------------------------------*/ -static int enabled = HDC_1000_SENSOR_STATUS_DISABLED; +static volatile HDC_1000_SENSOR_STATUS sensor_status = HDC_1000_SENSOR_STATUS_DISABLED; /*---------------------------------------------------------------------------*/ /* * Maximum measurement durations in clock ticks. We use 14bit resolution, thus: @@ -115,6 +117,25 @@ static int enabled = HDC_1000_SENSOR_STATUS_DISABLED; static struct ctimer startup_timer; /*---------------------------------------------------------------------------*/ +static bool +i2c_transaction(void *writeBuf, size_t writeCount, void *readBuf, size_t readCount) +{ + I2C_Transaction i2cTransaction = { + .writeBuf = writeBuf, + .writeCount = writeCount, + .readBuf = readBuf, + .readCount = readCount, + .slaveAddress = HDC1000_I2C_ADDRESS, + }; + + return I2C_transfer(i2cHandle, &i2cTransaction); +} + +#define i2c_write(writeBuf, writeCount) i2c_transaction(writeBuf, writeCount, NULL, 0) +#define i2c_read(readBuf, readCount) i2c_transaction(NULL, 0, readBuf, readCount) +#define i2c_write_read(writeBuf, writeCount, readBuf, readCount) \ + i2c_transaction(writeBuf, writeCount, readBuf, readCount) +/*---------------------------------------------------------------------------*/ /** * \brief Initialise the humidity sensor driver * \return True if I2C operation successful @@ -122,59 +143,36 @@ static struct ctimer startup_timer; static bool sensor_init(void) { - uint16_t val; + if (i2cHandle) { + return true; + } - SENSOR_SELECT(); + I2C_Params i2cParams; + I2C_Params_init(&i2cParams); + i2cParams.transferMode = I2C_MODE_BLOCKING; + i2cParams.bitRate = I2C_400kHz; - /* Enable reading data in one operation */ - val = SWAP(HDC1000_VAL_CONFIG); - success = sensor_common_write_reg(HDC1000_REG_CONFIG, (uint8_t *)&val, 2); + i2cHandle = I2C_open(Board_I2C0, &i2cParams); + if (i2cHandle == NULL) { + return false; + } - SENSOR_DESELECT(); + // Enable reading data in one operation + uint8_t config_data[] = { HDC1000_REG_CONFIG, LSB16(HDC1000_VAL_CONFIG) }; - return success; + return i2c_write(config_data, sizeof(config_data)); } /*---------------------------------------------------------------------------*/ /** * \brief Start measurement - */ -static void -start(void) -{ - if(success) { - SENSOR_SELECT(); - - success = board_i2c_write_single(HDC1000_REG_TEMP); - SENSOR_DESELECT(); - } -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Take readings from the sensor - * \return true of I2C operations successful + * \return True if I2C operation successful */ static bool -read_data() +start(void) { - bool valid; + uint8_t temp_reg[] = { HDC1000_REG_TEMP }; - if(success) { - SENSOR_SELECT(); - - success = board_i2c_read((uint8_t *)&data, sizeof(data)); - SENSOR_DESELECT(); - - /* Store temperature */ - raw_temp = SWAP(data.temp); - - /* Store humidity */ - raw_hum = SWAP(data.hum); - } - - valid = success; - success = true; - - return valid; + return i2c_write(temp_reg, sizeof(temp_reg)); } /*---------------------------------------------------------------------------*/ /** @@ -183,22 +181,26 @@ read_data() * \param hum - converted humidity */ static void -convert(float *temp, float *hum) +convert(int32_t *temp, int32_t *hum) { - /* Convert temperature to degrees C */ - *temp = ((double)raw_temp / 65536) * 165 - 40; + int32_t raw_temp = SWAP16(sensor_data.temp); + int32_t raw_hum = SWAP16(sensor_data.hum); + /* Convert temperature to degrees C */ + *temp = raw_temp * 100 * 165 / 65536 - 40000; /* Convert relative humidity to a %RH value */ - *hum = ((double)raw_hum / 65536) * 100; + *hum = raw_hum * 100 * 100 / 65536; } /*---------------------------------------------------------------------------*/ static void notify_ready(void *not_used) { - enabled = HDC_1000_SENSOR_STATUS_READINGS_READY; - /* Latch readings */ - read_data(); + if (i2c_read(&sensor_data, sizeof(sensor_data))) { + sensor_status = HDC_1000_SENSOR_STATUS_READINGS_READY; + } else { + sensor_status = HDC_1000_SENSOR_STATUS_I2C_ERROR; + } sensors_changed(&hdc_1000_sensor); } @@ -211,31 +213,32 @@ notify_ready(void *not_used) static int value(int type) { - int rv; - float temp; - float hum; + int32_t temp = 0; + int32_t hum = 0; - if(enabled != HDC_1000_SENSOR_STATUS_READINGS_READY) { - PRINTF("Sensor disabled or starting up (%d)\n", enabled); - return CC26XX_SENSOR_READING_ERROR; + if (sensor_status != HDC_1000_SENSOR_STATUS_READINGS_READY) { + PRINTF("Sensor disabled or starting up (%d)\n", sensor_status); + return HDC_1000_READING_ERROR; } - if((type != HDC_1000_SENSOR_TYPE_TEMP) && - type != HDC_1000_SENSOR_TYPE_HUMIDITY) { - PRINTF("Invalid type\n"); - return CC26XX_SENSOR_READING_ERROR; - } else { + switch (type) { + case HDC_1000_SENSOR_TYPE_TEMP: + case HDC_1000_SENSOR_TYPE_HUMIDITY: convert(&temp, &hum); - PRINTF("HDC: %04X %04X t=%d h=%d\n", raw_temp, raw_hum, - (int)(temp * 100), (int)(hum * 100)); + PRINTF("HDC: t=%d h=%d\n", (int)temp, (int)hum); - if(type == HDC_1000_SENSOR_TYPE_TEMP) { - rv = (int)(temp * 100); - } else if(type == HDC_1000_SENSOR_TYPE_HUMIDITY) { - rv = (int)(hum * 100); + if (type == HDC_1000_SENSOR_TYPE_TEMP) { + return (int)temp; + } else if (type == HDC_1000_SENSOR_TYPE_HUMIDITY) { + return (int)hum; + } else { + return HDC_1000_READING_ERROR; } + + default: + PRINTF("Invalid type\n"); + return HDC_1000_READING_ERROR; } - return rv; } /*---------------------------------------------------------------------------*/ /** @@ -251,33 +254,40 @@ value(int type) static int configure(int type, int enable) { - switch(type) { + switch (type) { case SENSORS_HW_INIT: - raw_temp = 0; - raw_hum = 0; - memset(&data, 0, sizeof(data)); + memset(&sensor_data, 0, sizeof(sensor_data)); - sensor_init(); - enabled = HDC_1000_SENSOR_STATUS_INITIALISED; + if (sensor_init()) { + sensor_status = HDC_1000_SENSOR_STATUS_INITIALISED; + } else { + sensor_status = HDC_1000_SENSOR_STATUS_I2C_ERROR; + } break; + case SENSORS_ACTIVE: /* Must be initialised first */ - if(enabled == HDC_1000_SENSOR_STATUS_DISABLED) { - return HDC_1000_SENSOR_STATUS_DISABLED; + if (sensor_status == HDC_1000_SENSOR_STATUS_DISABLED) { + break; } - if(enable) { - start(); + + if (enable) { + if (!start()) { + sensor_status = HDC_1000_SENSOR_STATUS_I2C_ERROR; + break; + } ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready, NULL); - enabled = HDC_1000_SENSOR_STATUS_TAKING_READINGS; + sensor_status = HDC_1000_SENSOR_STATUS_TAKING_READINGS; } else { ctimer_stop(&startup_timer); - enabled = HDC_1000_SENSOR_STATUS_INITIALISED; + sensor_status = HDC_1000_SENSOR_STATUS_INITIALISED; } break; + default: break; } - return enabled; + return sensor_status; } /*---------------------------------------------------------------------------*/ /** @@ -291,8 +301,9 @@ status(int type) switch(type) { case SENSORS_ACTIVE: case SENSORS_READY: - return enabled; + return sensor_status; break; + default: break; } diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.h index d3089d742..f2112f76f 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.h @@ -64,19 +64,26 @@ /*---------------------------------------------------------------------------*/ #include "lib/sensors.h" /*---------------------------------------------------------------------------*/ -#define HDC_1000_SENSOR_TYPE_TEMP 1 -#define HDC_1000_SENSOR_TYPE_HUMIDITY 2 +typedef enum { + HDC_1000_SENSOR_TYPE_TEMP, + HDC_1000_SENSOR_TYPE_HUMIDITY +} HDC_1000_SENSOR_TYPE; /*---------------------------------------------------------------------------*/ /** * \name HDC1000 driver states * @{ */ -#define HDC_1000_SENSOR_STATUS_DISABLED 0 /**< Not initialised */ -#define HDC_1000_SENSOR_STATUS_INITIALISED 1 /**< Initialised but idle */ -#define HDC_1000_SENSOR_STATUS_TAKING_READINGS 2 /**< Readings in progress */ -#define HDC_1000_SENSOR_STATUS_READINGS_READY 3 /**< Both readings ready */ +typedef enum { + HDC_1000_SENSOR_STATUS_DISABLED, /**< Not initialised */ + HDC_1000_SENSOR_STATUS_INITIALISED, /**< Initialised but idle */ + HDC_1000_SENSOR_STATUS_TAKING_READINGS, /**< Readings in progress */ + HDC_1000_SENSOR_STATUS_I2C_ERROR, /**< I2C transaction failed */ + HDC_1000_SENSOR_STATUS_READINGS_READY /**< Both readings ready */ +} HDC_1000_SENSOR_STATUS; /** @} */ /*---------------------------------------------------------------------------*/ +#define HDC_1000_READING_ERROR -1 +/*---------------------------------------------------------------------------*/ extern const struct sensors_sensor hdc_1000_sensor; /*---------------------------------------------------------------------------*/ #endif /* HDC_1000_SENSOR_H */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/leds-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/leds-arch.c new file mode 100644 index 000000000..aa1de6db5 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/leds-arch.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup simplelink-platform + * @{ + * + * \file + * Driver for LaunchPad LEDs + */ +/*---------------------------------------------------------------------------*/ +/* Contiki API */ +#include +#include +/*---------------------------------------------------------------------------*/ +/* Simplelink SDK API */ +#include + +#include +/*---------------------------------------------------------------------------*/ +/* Standard library */ +#include +#include +/*---------------------------------------------------------------------------*/ +/* Available LED configuration */ + +/* LED */ +#define LEDS_ARCH Board_GPIO_LED0 +/*---------------------------------------------------------------------------*/ +static volatile unsigned char c; +/*---------------------------------------------------------------------------*/ +void +leds_arch_init(void) +{ + static bool bHasInit = false; + if(bHasInit) { + return; + } + bHasInit = true; + + // GPIO_init will most likely be called in platform.c, + // but call it here to be sure GPIO is initialized. + // Calling GPIO_init multiple times is safe. + GPIO_init(); +} +/*---------------------------------------------------------------------------*/ +unsigned char +leds_arch_get(void) +{ + return c; +} +/*---------------------------------------------------------------------------*/ +static inline void +write_led(const bool on, const uint_fast32_t gpioLed) +{ + const GPIO_PinConfig pinCfg = (on) + ? Board_GPIO_LED_ON + : Board_GPIO_LED_OFF; + GPIO_write(gpioLed, pinCfg); +} +/*---------------------------------------------------------------------------*/ +void +leds_arch_set(unsigned char leds) +{ + c = leds; + + // Green LED + uint_fast32_t gpioOn = (leds & (LEDS_ARCH)) == (LEDS_ARCH); + write_led(gpioOn, LEDS_ARCH); +} +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c index a2b3651e5..399ab04a2 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c @@ -38,13 +38,15 @@ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "lib/sensors.h" -#include "mpu-9250-sensor.h" #include "sys/rtimer.h" -#include "sensor-common.h" -#include "board-i2c.h" - -#include "ti-lib.h" - +#include "mpu-9250-sensor.h" +/*---------------------------------------------------------------------------*/ +#include +#include +#include DeviceFamily_constructPath(driverlib/cpu.h) +#include +#include +/*---------------------------------------------------------------------------*/ #include #include #include @@ -57,55 +59,61 @@ #define PRINTF(...) #endif /*---------------------------------------------------------------------------*/ +#ifndef Board_MPU9250_ADDR +# error "Board file doesn't define I2C address Board_MPU9250_ADDR" +#endif +#ifndef Board_MPU9250_MAG_ADDR +# error "Board file doesn't define I2C address Board_MPU9250_MAG_ADDR" +#endif /* Sensor I2C address */ -#define SENSOR_I2C_ADDRESS 0x68 -#define SENSOR_MAG_I2_ADDRESS 0x0C -/*---------------------------------------------------------------------------*/ +#define MPU_9250_I2C_ADDRESS Board_MPU9250_ADDR +#define MPU_9250_MAG_I2C_ADDRESS Board_MPU9250_MAG_ADDR +/*-------------a--------------------------------------------------------------*/ /* Registers */ -#define SELF_TEST_X_GYRO 0x00 /* R/W */ -#define SELF_TEST_Y_GYRO 0x01 /* R/W */ -#define SELF_TEST_Z_GYRO 0x02 /* R/W */ -#define SELF_TEST_X_ACCEL 0x0D /* R/W */ -#define SELF_TEST_Z_ACCEL 0x0E /* R/W */ -#define SELF_TEST_Y_ACCEL 0x0F /* R/W */ +#define REG_SELF_TEST_X_GYRO 0x00 /* R/W */ +#define REG_SELF_TEST_Y_GYRO 0x01 /* R/W */ +#define REG_SELF_TEST_Z_GYRO 0x02 /* R/W */ +#define REG_SELF_TEST_X_ACCEL 0x0D /* R/W */ +#define REG_SELF_TEST_Z_ACCEL 0x0E /* R/W */ +#define REG_SELF_TEST_Y_ACCEL 0x0F /* R/W */ /*---------------------------------------------------------------------------*/ -#define XG_OFFSET_H 0x13 /* R/W */ -#define XG_OFFSET_L 0x14 /* R/W */ -#define YG_OFFSET_H 0x15 /* R/W */ -#define YG_OFFSET_L 0x16 /* R/W */ -#define ZG_OFFSET_H 0x17 /* R/W */ -#define ZG_OFFSET_L 0x18 /* R/W */ +#define REG_XG_OFFSET_H 0x13 /* R/W */ +#define REG_XG_OFFSET_L 0x14 /* R/W */ +#define REG_YG_OFFSET_H 0x15 /* R/W */ +#define REG_YG_OFFSET_L 0x16 /* R/W */ +#define REG_ZG_OFFSET_H 0x17 /* R/W */ +#define REG_ZG_OFFSET_L 0x18 /* R/W */ /*---------------------------------------------------------------------------*/ -#define SMPLRT_DIV 0x19 /* R/W */ -#define CONFIG 0x1A /* R/W */ -#define GYRO_CONFIG 0x1B /* R/W */ -#define ACCEL_CONFIG 0x1C /* R/W */ -#define ACCEL_CONFIG_2 0x1D /* R/W */ -#define LP_ACCEL_ODR 0x1E /* R/W */ -#define WOM_THR 0x1F /* R/W */ -#define FIFO_EN 0x23 /* R/W */ +#define REG_SMPLRT_DIV 0x19 /* R/W */ +#define REG_CONFIG 0x1A /* R/W */ +#define REG_GYRO_CONFIG 0x1B /* R/W */ +#define REG_ACCEL_CONFIG 0x1C /* R/W */ +#define REG_ACCEL_CONFIG_2 0x1D /* R/W */ +#define REG_LP_ACCEL_ODR 0x1E /* R/W */ +#define REG_WOM_THR 0x1F /* R/W */ +#define REG_FIFO_EN 0x23 /* R/W */ /*---------------------------------------------------------------------------*/ /* * Registers 0x24 - 0x36 are not applicable to the SensorTag HW configuration * (IC2 Master) */ -#define INT_PIN_CFG 0x37 /* R/W */ -#define INT_ENABLE 0x38 /* R/W */ -#define INT_STATUS 0x3A /* R */ -#define ACCEL_XOUT_H 0x3B /* R */ -#define ACCEL_XOUT_L 0x3C /* R */ -#define ACCEL_YOUT_H 0x3D /* R */ -#define ACCEL_YOUT_L 0x3E /* R */ -#define ACCEL_ZOUT_H 0x3F /* R */ -#define ACCEL_ZOUT_L 0x40 /* R */ -#define TEMP_OUT_H 0x41 /* R */ -#define TEMP_OUT_L 0x42 /* R */ -#define GYRO_XOUT_H 0x43 /* R */ -#define GYRO_XOUT_L 0x44 /* R */ -#define GYRO_YOUT_H 0x45 /* R */ -#define GYRO_YOUT_L 0x46 /* R */ -#define GYRO_ZOUT_H 0x47 /* R */ -#define GYRO_ZOUT_L 0x48 /* R */ +#define REG_INT_PIN_CFG 0x37 /* R/W */ +#define REG_INT_ENABLE 0x38 /* R/W */ +#define REG_INT_STATUS 0x3A /* R */ +#define REG_ACCEL_XOUT_H 0x3B /* R */ +#define REG_ACCEL_XOUT_L 0x3C /* R */ +#define REG_ACCEL_YOUT_H 0x3D /* R */ +#define REG_ACCEL_YOUT_L 0x3E /* R */ +#define REG_ACCEL_ZOUT_H 0x3F /* R */ +#define REG_ACCEL_ZOUT_L 0x40 /* R */ +#define REG_TEMP_OUT_H 0x41 /* R */ +#define REG_TEMP_OUT_L 0x42 /* R */ +#define REG_GYRO_XOUT_H 0x43 /* R */ +#define REG_GYRO_XOUT_L 0x44 /* R */ +#define REG_GYRO_YOUT_H 0x45 /* R */ +#define REG_GYRO_YOUT_L 0x46 /* R */ +#define REG_GYRO_ZOUT_H 0x47 /* R */ +#define REG_GYRO_ZOUT_L 0x48 /* R */ /*---------------------------------------------------------------------------*/ /* * Registers 0x49 - 0x60 are not applicable to the SensorTag HW configuration @@ -114,31 +122,28 @@ * Registers 0x63 - 0x67 are not applicable to the SensorTag HW configuration * (I2C master) */ -#define SIGNAL_PATH_RESET 0x68 /* R/W */ -#define ACCEL_INTEL_CTRL 0x69 /* R/W */ -#define USER_CTRL 0x6A /* R/W */ -#define PWR_MGMT_1 0x6B /* R/W */ -#define PWR_MGMT_2 0x6C /* R/W */ -#define FIFO_COUNT_H 0x72 /* R/W */ -#define FIFO_COUNT_L 0x73 /* R/W */ -#define FIFO_R_W 0x74 /* R/W */ -#define WHO_AM_I 0x75 /* R/W */ +#define REG_SIG_PATH_RST 0x68 /* R/W */ +#define REG_ACC_INTEL_CTRL 0x69 /* R/W */ +#define REG_USER_CTRL 0x6A /* R/W */ +#define REG_PWR_MGMT_1 0x6B /* R/W */ +#define REG_PWR_MGMT_2 0x6C /* R/W */ +#define REG_FIFO_COUNT_H 0x72 /* R/W */ +#define REG_FIFO_COUNT_L 0x73 /* R/W */ +#define REG_FIFO_R_W 0x74 /* R/W */ +#define REG_WHO_AM_I 0x75 /* R/W */ /*---------------------------------------------------------------------------*/ /* Masks is mpuConfig valiable */ #define ACC_CONFIG_MASK 0x38 #define GYRO_CONFIG_MASK 0x07 /*---------------------------------------------------------------------------*/ /* Values PWR_MGMT_1 */ -#define MPU_SLEEP 0x4F /* Sleep + stop all clocks */ -#define MPU_WAKE_UP 0x09 /* Disable temp. + intern osc */ +#define PWR_MGMT_1_VAL_MPU_SLEEP 0x4F /* Sleep + stop all clocks */ +#define PWR_MGMT_1_VAL_MPU_WAKE_UP 0x09 /* Disable temp. + intern osc */ /*---------------------------------------------------------------------------*/ /* Values PWR_MGMT_2 */ -#define ALL_AXES 0x3F -#define GYRO_AXES 0x07 -#define ACC_AXES 0x38 -/*---------------------------------------------------------------------------*/ -/* Data sizes */ -#define DATA_SIZE 6 +#define PWR_MGMT_2_VAL_ALL_AXES 0x3F +#define PWR_MGMT_2_VAL_GYRO_AXES 0x07 +#define PWR_MGMT_2_VAL_ACC_AXES 0x38 /*---------------------------------------------------------------------------*/ /* Output data rates */ #define INV_LPA_0_3125HZ 0 @@ -169,60 +174,29 @@ #define BIT_STBY_XYZA (BIT_STBY_XA | BIT_STBY_YA | BIT_STBY_ZA) #define BIT_STBY_XYZG (BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG) /*---------------------------------------------------------------------------*/ -/* User control register */ -#define BIT_ACTL 0x80 -#define BIT_LATCH_EN 0x20 -/*---------------------------------------------------------------------------*/ -/* INT Pin / Bypass Enable Configuration */ -#define BIT_AUX_IF_EN 0x20 /* I2C_MST_EN */ -#define BIT_BYPASS_EN 0x02 -/*---------------------------------------------------------------------------*/ -#define ACC_RANGE_INVALID -1 +static PIN_Config mpu_9250_pin_table[] = { + Board_MPU_INT | PIN_INPUT_EN | PIN_PULLDOWN | PIN_HYSTERESIS, + Board_MPU_POWER | PIN_GPIO_OUTPUT_EN | PIN_DRVSTR_MAX | PIN_GPIO_LOW, + PIN_TERMINATE +}; -#define ACC_RANGE_2G 0 -#define ACC_RANGE_4G 1 -#define ACC_RANGE_8G 2 -#define ACC_RANGE_16G 3 +static PIN_State pinState; +static PIN_Handle pinHandle; +static I2C_Handle i2cHandle; -#define MPU_AX_GYR_X 2 -#define MPU_AX_GYR_Y 1 -#define MPU_AX_GYR_Z 0 -#define MPU_AX_GYR 0x07 +/*---------------------------------------------------------------------------*/ +typedef struct { + volatile MPU_9250_SENSOR_STATUS status; + volatile MPU_9250_SENSOR_TYPE type; + MPU_9250_SENSOR_ACC_RANGE acc_range; +} MPU_9250_Object; -#define MPU_AX_ACC_X 5 -#define MPU_AX_ACC_Y 4 -#define MPU_AX_ACC_Z 3 -#define MPU_AX_ACC 0x38 - -#define MPU_AX_MAG 6 -/*---------------------------------------------------------------------------*/ -#define MPU_DATA_READY 0x01 -#define MPU_MOVEMENT 0x40 -/*---------------------------------------------------------------------------*/ -/* Sensor selection/deselection */ -#define SENSOR_SELECT() board_i2c_select(BOARD_I2C_INTERFACE_1, SENSOR_I2C_ADDRESS) -#define SENSOR_DESELECT() board_i2c_deselect() -/*---------------------------------------------------------------------------*/ -/* Delay */ -#define delay_ms(i) (ti_lib_cpu_delay(8000 * (i))) -/*---------------------------------------------------------------------------*/ -static uint8_t mpu_config; -static uint8_t acc_range; -static uint8_t acc_range_reg; -static uint8_t val; -static uint8_t interrupt_status; -/*---------------------------------------------------------------------------*/ -#define SENSOR_STATE_DISABLED 0 -#define SENSOR_STATE_BOOTING 1 -#define SENSOR_STATE_ENABLED 2 - -static int state = SENSOR_STATE_DISABLED; -static int elements = MPU_9250_SENSOR_TYPE_NONE; +static MPU_9250_Object mpu_9250; /*---------------------------------------------------------------------------*/ /* 3 16-byte words for all sensor readings */ #define SENSOR_DATA_BUF_SIZE 3 - -static uint16_t sensor_value[SENSOR_DATA_BUF_SIZE]; +/* Data sizes */ +#define DATA_SIZE 6 /*---------------------------------------------------------------------------*/ /* * Wait SENSOR_BOOT_DELAY ticks for the sensor to boot and @@ -234,8 +208,6 @@ static uint16_t sensor_value[SENSOR_DATA_BUF_SIZE]; static struct ctimer startup_timer; /*---------------------------------------------------------------------------*/ -/* Wait for the MPU to have data ready */ -rtimer_clock_t t0; /* * Wait timeout in rtimer ticks. This is just a random low number, since the @@ -243,20 +215,69 @@ rtimer_clock_t t0; */ #define READING_WAIT_TIMEOUT 10 /*---------------------------------------------------------------------------*/ +/* Code in flash, cache disabled: 7 cycles per loop */ +/* ui32Count = [delay in us] * [CPU clock in MHz] / [cycles per loop] */ +#define delay_ms(ms) CPUdelay((ms) * 1000 * 48 / 7) +/*---------------------------------------------------------------------------*/ +static bool +i2c_transaction(void *writeBuf, size_t writeCount, void *readBuf, size_t readCount) +{ + I2C_Transaction i2cTransaction = { + .writeBuf = writeBuf, + .writeCount = writeCount, + .readBuf = readBuf, + .readCount = readCount, + .slaveAddress = MPU_9250_I2C_ADDRESS, + }; + + return I2C_transfer(i2cHandle, &i2cTransaction); +} + +#define i2c_write(writeBuf, writeCount) i2c_transaction(writeBuf, writeCount, NULL, 0) +#define i2c_read(readBuf, readCount) i2c_transaction(NULL, 0, readBuf, readCount) +#define i2c_write_read(writeBuf, writeCount, readBuf, readCount) \ + i2c_transaction(writeBuf, writeCount, readBuf, readCount) +/*---------------------------------------------------------------------------*/ +static bool +sensor_init(void) +{ + pinHandle = PIN_open(&pinState, mpu_9250_pin_table); + if (pinHandle == NULL) { + return false; + } + + I2C_Params i2cParams; + I2C_Params_init(&i2cParams); + i2cParams.transferMode = I2C_MODE_BLOCKING; + i2cParams.bitRate = I2C_400kHz; + + i2cHandle = I2C_open(Board_I2C0, &i2cParams); + if (i2cHandle == NULL) { + PIN_close(&pinState); + return false; + } + + mpu_9250.type = MPU_9250_SENSOR_TYPE_NONE; + mpu_9250.status = MPU_9250_SENSOR_STATUS_DISABLED; + mpu_9250.acc_range = MPU_9250_SENSOR_ACC_RANGE_ARG; + + return true; +} +/*---------------------------------------------------------------------------*/ /** * \brief Place the MPU in low power mode */ static void sensor_sleep(void) { - SENSOR_SELECT(); - - val = ALL_AXES; - sensor_common_write_reg(PWR_MGMT_2, &val, 1); - - val = MPU_SLEEP; - sensor_common_write_reg(PWR_MGMT_1, &val, 1); - SENSOR_DESELECT(); + { + uint8_t all_axes_data[] = { REG_PWR_MGMT_2, PWR_MGMT_2_VAL_ALL_AXES }; + i2c_write(all_axes_data, sizeof(all_axes_data)); + } + { + uint8_t mpu_sleep_data[] = { REG_PWR_MGMT_1, PWR_MGMT_1_VAL_MPU_SLEEP }; + i2c_write(mpu_sleep_data, sizeof(mpu_sleep_data)); + } } /*---------------------------------------------------------------------------*/ /** @@ -265,33 +286,41 @@ sensor_sleep(void) static void sensor_wakeup(void) { - SENSOR_SELECT(); - val = MPU_WAKE_UP; - sensor_common_write_reg(PWR_MGMT_1, &val, 1); - - /* All axis initially disabled */ - val = ALL_AXES; - sensor_common_write_reg(PWR_MGMT_2, &val, 1); - mpu_config = 0; - - /* Restore the range */ - sensor_common_write_reg(ACCEL_CONFIG, &acc_range_reg, 1); - - /* Clear interrupts */ - sensor_common_read_reg(INT_STATUS, &val, 1); - SENSOR_DESELECT(); + { + uint8_t mpu_wakeup_data[] = { REG_PWR_MGMT_1, PWR_MGMT_1_VAL_MPU_WAKE_UP }; + i2c_write(mpu_wakeup_data, sizeof(mpu_wakeup_data)); + } + { + /* All axis initially disabled */ + uint8_t all_axes_data[] = { REG_PWR_MGMT_2, PWR_MGMT_2_VAL_ALL_AXES }; + i2c_write(all_axes_data, sizeof(all_axes_data)); + } + { + /* Restore the range */ + uint8_t accel_cfg_data[] = { REG_ACCEL_CONFIG, mpu_9250.acc_range }; + i2c_write(accel_cfg_data, sizeof(accel_cfg_data)); + } + { + /* Clear interrupts */ + uint8_t int_status_data[] = { REG_INT_STATUS }; + uint8_t dummy; + i2c_write_read(int_status_data, sizeof(int_status_data), &dummy, 1); + } } /*---------------------------------------------------------------------------*/ -/** - * \brief Select gyro and accelerometer axes - */ static void -select_axes(void) +sensor_set_acc_range(MPU_9250_SENSOR_ACC_RANGE acc_range) { - val = ~mpu_config; - SENSOR_SELECT(); - sensor_common_write_reg(PWR_MGMT_2, &val, 1); - SENSOR_DESELECT(); + /* Apply the range */ + uint8_t accel_cfg_data[] = { REG_ACCEL_CONFIG, acc_range }; + i2c_write(accel_cfg_data, sizeof(accel_cfg_data)); +} +/*---------------------------------------------------------------------------*/ +static void +sensor_set_axes(MPU_9250_SENSOR_TYPE sensor_type) +{ + uint8_t _data[] = { REG_PWR_MGMT_2, ~(uint8_t)sensor_type }; + i2c_write(_data, sizeof(_data)); } /*---------------------------------------------------------------------------*/ static void @@ -306,36 +335,6 @@ convert_to_le(uint8_t *data, uint8_t len) } } /*---------------------------------------------------------------------------*/ -/** - * \brief Set the range of the accelerometer - * \param new_range: ACC_RANGE_2G, ACC_RANGE_4G, ACC_RANGE_8G, ACC_RANGE_16G - * \return true if the write to the sensor succeeded - */ -static bool -acc_set_range(uint8_t new_range) -{ - bool success; - - if(new_range == acc_range) { - return true; - } - - success = false; - - acc_range_reg = (new_range << 3); - - /* Apply the range */ - SENSOR_SELECT(); - success = sensor_common_write_reg(ACCEL_CONFIG, &acc_range_reg, 1); - SENSOR_DESELECT(); - - if(success) { - acc_range = new_range; - } - - return success; -} -/*---------------------------------------------------------------------------*/ /** * \brief Check whether a data or wake on motion interrupt has occurred * \return Return the interrupt status @@ -343,38 +342,13 @@ acc_set_range(uint8_t new_range) * This driver does not use interrupts, however this function allows us to * determine whether a new sensor reading is available */ -static uint8_t -int_status(void) +static bool +sensor_data_ready(uint8_t* int_status) { - SENSOR_SELECT(); - sensor_common_read_reg(INT_STATUS, &interrupt_status, 1); - SENSOR_DESELECT(); + uint8_t int_status_data[] = { REG_INT_STATUS }; + const bool spi_ok = i2c_write_read(int_status_data, sizeof(int_status_data), int_status, 1); - return interrupt_status; -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Enable the MPU - * \param axes: Gyro bitmap [0..2], X = 1, Y = 2, Z = 4. 0 = gyro off - * Acc bitmap [3..5], X = 8, Y = 16, Z = 32. 0 = accelerometer off - */ -static void -enable_sensor(uint16_t axes) -{ - if(mpu_config == 0 && axes != 0) { - /* Wake up the sensor if it was off */ - sensor_wakeup(); - } - - mpu_config = axes; - - if(mpu_config != 0) { - /* Enable gyro + accelerometer readout */ - select_axes(); - delay_ms(10); - } else if(mpu_config == 0) { - sensor_sleep(); - } + return spi_ok && (*int_status != 0); } /*---------------------------------------------------------------------------*/ /** @@ -382,27 +356,22 @@ enable_sensor(uint16_t axes) * \return True if a valid reading could be taken, false otherwise */ static bool -acc_read(uint16_t *data) +acc_read(uint8_t int_status, uint16_t *data) { - bool success; - - if(interrupt_status & BIT_RAW_RDY_EN) { - /* Burst read of all accelerometer values */ - SENSOR_SELECT(); - success = sensor_common_read_reg(ACCEL_XOUT_H, (uint8_t *)data, DATA_SIZE); - SENSOR_DESELECT(); - - if(success) { - convert_to_le((uint8_t *)data, DATA_SIZE); - } else { - sensor_common_set_error_data((uint8_t *)data, DATA_SIZE); - } - } else { - /* Data not ready */ - success = false; + if (!(int_status & BIT_RAW_RDY_EN)) { + return false; } - return success; + /* Burst read of all accelerometer values */ + uint8_t accel_xout_h[] = { REG_ACCEL_XOUT_H }; + bool spi_ok = i2c_write_read(accel_xout_h, sizeof(accel_xout_h), data, DATA_SIZE); + if (!spi_ok) { + return false; + } + + convert_to_le((uint8_t*)data, DATA_SIZE); + + return true; } /*---------------------------------------------------------------------------*/ /** @@ -410,29 +379,22 @@ acc_read(uint16_t *data) * \return True if a valid reading could be taken, false otherwise */ static bool -gyro_read(uint16_t *data) +gyro_read(uint8_t int_status, uint16_t *data) { - bool success; - - if(interrupt_status & BIT_RAW_RDY_EN) { - /* Select this sensor */ - SENSOR_SELECT(); - - /* Burst read of all gyroscope values */ - success = sensor_common_read_reg(GYRO_XOUT_H, (uint8_t *)data, DATA_SIZE); - - if(success) { - convert_to_le((uint8_t *)data, DATA_SIZE); - } else { - sensor_common_set_error_data((uint8_t *)data, DATA_SIZE); - } - - SENSOR_DESELECT(); - } else { - success = false; + if (!(int_status & BIT_RAW_RDY_EN)) { + return false; } - return success; + /* Burst read of all accelerometer values */ + uint8_t gyro_xout_h[] = { REG_GYRO_XOUT_H }; + bool spi_ok = i2c_write_read(gyro_xout_h, sizeof(gyro_xout_h), data, DATA_SIZE); + if (!spi_ok) { + return false; + } + + convert_to_le((uint8_t*)data, DATA_SIZE); + + return true; } /*---------------------------------------------------------------------------*/ /** @@ -440,34 +402,16 @@ gyro_read(uint16_t *data) * \param raw_data The raw accelerometer reading * \return The converted value */ -static float -acc_convert(int16_t raw_data) +static int32_t +acc_convert(int32_t raw_data) { - float v = 0; - - switch(acc_range) { - case ACC_RANGE_2G: - /* Calculate acceleration, unit G, range -2, +2 */ - v = (raw_data * 1.0) / (32768 / 2); - break; - case ACC_RANGE_4G: - /* Calculate acceleration, unit G, range -4, +4 */ - v = (raw_data * 1.0) / (32768 / 4); - break; - case ACC_RANGE_8G: - /* Calculate acceleration, unit G, range -8, +8 */ - v = (raw_data * 1.0) / (32768 / 8); - break; - case ACC_RANGE_16G: - /* Calculate acceleration, unit G, range -16, +16 */ - v = (raw_data * 1.0) / (32768 / 16); - break; - default: - v = 0; - break; + switch (mpu_9250.acc_range) { + case MPU_9250_SENSOR_ACC_RANGE_2G: return raw_data * 100 * 2 / 32768; + case MPU_9250_SENSOR_ACC_RANGE_4G: return raw_data * 100 * 4 / 32768; + case MPU_9250_SENSOR_ACC_RANGE_8G: return raw_data * 100 * 8 / 32768; + case MPU_9250_SENSOR_ACC_RANGE_16G: return raw_data * 100 * 16 / 32768; } - - return v; + return 0; } /*---------------------------------------------------------------------------*/ /** @@ -475,40 +419,44 @@ acc_convert(int16_t raw_data) * \param raw_data The raw accelerometer reading * \return The converted value */ -static float -gyro_convert(int16_t raw_data) +static int32_t +gyro_convert(int32_t raw_data) { /* calculate rotation, unit deg/s, range -250, +250 */ - return (raw_data * 1.0) / (65536 / 500); + return raw_data * 100 * 500 / 65536; } /*---------------------------------------------------------------------------*/ static void -notify_ready(void *not_used) +notify_ready_cb(void *unused) { - state = SENSOR_STATE_ENABLED; + (void)unused; + + mpu_9250.status = MPU_9250_SENSOR_STATUS_READY; sensors_changed(&mpu_9250_sensor); } /*---------------------------------------------------------------------------*/ static void -initialise(void *not_used) +initialise_cb(void *unused) { - /* Configure the accelerometer range */ - if((elements & MPU_9250_SENSOR_TYPE_ACC) != 0) { - acc_set_range(MPU_9250_SENSOR_ACC_RANGE); + (void)unused; + + if (mpu_9250.type == MPU_9250_SENSOR_TYPE_NONE) { + return; } - enable_sensor(elements & MPU_9250_SENSOR_TYPE_ALL); + /* Wake up the sensor */ + sensor_wakeup(); - ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready, NULL); -} -/*---------------------------------------------------------------------------*/ -static void -power_up(void) -{ - ti_lib_gpio_set_dio(BOARD_IOID_MPU_POWER); - state = SENSOR_STATE_BOOTING; + /* Configure the accelerometer range */ + if ((mpu_9250.type & MPU_9250_SENSOR_TYPE_ACC) != 0) { + sensor_set_acc_range(mpu_9250.acc_range); + } - ctimer_set(&startup_timer, SENSOR_BOOT_DELAY, initialise, NULL); + /* Enable gyro + accelerometer readout */ + sensor_set_axes(mpu_9250.type); + delay_ms(10); + + ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready_cb, NULL); } /*---------------------------------------------------------------------------*/ /** @@ -519,71 +467,67 @@ power_up(void) static int value(int type) { - int rv; - float converted_val = 0; - - if(state == SENSOR_STATE_DISABLED) { + if(mpu_9250.status == MPU_9250_SENSOR_STATUS_DISABLED) { PRINTF("MPU: Sensor Disabled\n"); - return CC26XX_SENSOR_READING_ERROR; + return MPU_9250_READING_ERROR; } + if (mpu_9250.type == MPU_9250_SENSOR_TYPE_NONE) { + return MPU_9250_READING_ERROR; + } + + uint8_t int_status = 0; + const rtimer_clock_t t0 = RTIMER_NOW(); + while (!sensor_data_ready(&int_status)) { + if (!(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + READING_WAIT_TIMEOUT))) { + return MPU_9250_READING_ERROR; + } + } + + uint16_t sensor_value[SENSOR_DATA_BUF_SIZE]; memset(sensor_value, 0, sizeof(sensor_value)); - if((type & MPU_9250_SENSOR_TYPE_ACC) != 0) { - t0 = RTIMER_NOW(); + /* Read accel data */ + if ((type & MPU_9250_SENSOR_TYPE_ACC) != 0) { - while(!int_status() && - (RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + READING_WAIT_TIMEOUT))); - - rv = acc_read(sensor_value); - - if(rv == 0) { - return CC26XX_SENSOR_READING_ERROR; + if (!acc_read(int_status, sensor_value)) { + return MPU_9250_READING_ERROR; } PRINTF("MPU: ACC = 0x%04x 0x%04x 0x%04x = ", sensor_value[0], sensor_value[1], sensor_value[2]); /* Convert */ - if(type == MPU_9250_SENSOR_TYPE_ACC_X) { - converted_val = acc_convert(sensor_value[0]); - } else if(type == MPU_9250_SENSOR_TYPE_ACC_Y) { - converted_val = acc_convert(sensor_value[1]); - } else if(type == MPU_9250_SENSOR_TYPE_ACC_Z) { - converted_val = acc_convert(sensor_value[2]); + switch (type) { + case MPU_9250_SENSOR_TYPE_ACC_X: return acc_convert(sensor_value[0]); + case MPU_9250_SENSOR_TYPE_ACC_Y: return acc_convert(sensor_value[1]); + case MPU_9250_SENSOR_TYPE_ACC_Z: return acc_convert(sensor_value[2]); + default: return MPU_9250_READING_ERROR; } - rv = (int)(converted_val * 100); + + /* Read gyro data */ } else if((type & MPU_9250_SENSOR_TYPE_GYRO) != 0) { - t0 = RTIMER_NOW(); - while(!int_status() && - (RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + READING_WAIT_TIMEOUT))); - - rv = gyro_read(sensor_value); - - if(rv == 0) { - return CC26XX_SENSOR_READING_ERROR; + if (!gyro_read(int_status, sensor_value)) { + return MPU_9250_READING_ERROR; } PRINTF("MPU: Gyro = 0x%04x 0x%04x 0x%04x = ", sensor_value[0], sensor_value[1], sensor_value[2]); - if(type == MPU_9250_SENSOR_TYPE_GYRO_X) { - converted_val = gyro_convert(sensor_value[0]); - } else if(type == MPU_9250_SENSOR_TYPE_GYRO_Y) { - converted_val = gyro_convert(sensor_value[1]); - } else if(type == MPU_9250_SENSOR_TYPE_GYRO_Z) { - converted_val = gyro_convert(sensor_value[2]); + /* Convert */ + switch (type) { + case MPU_9250_SENSOR_TYPE_GYRO_X: return gyro_convert(sensor_value[0]); + case MPU_9250_SENSOR_TYPE_GYRO_Y: return gyro_convert(sensor_value[1]); + case MPU_9250_SENSOR_TYPE_GYRO_Z: return gyro_convert(sensor_value[2]); + default: return MPU_9250_READING_ERROR; } - rv = (int)(converted_val * 100); + + /* Invalid sensor type */ } else { PRINTF("MPU: Invalid type\n"); - rv = CC26XX_SENSOR_READING_ERROR; + return MPU_9250_READING_ERROR; } - - PRINTF("%ld\n", (long int)(converted_val * 100)); - - return rv; } /*---------------------------------------------------------------------------*/ /** @@ -599,44 +543,49 @@ value(int type) static int configure(int type, int enable) { + // Mask enable + const MPU_9250_SENSOR_TYPE enable_type = enable & MPU_9250_SENSOR_TYPE_ALL; + switch(type) { case SENSORS_HW_INIT: - ti_lib_rom_ioc_pin_type_gpio_input(BOARD_IOID_MPU_INT); - ti_lib_ioc_io_port_pull_set(BOARD_IOID_MPU_INT, IOC_IOPULL_DOWN); - ti_lib_ioc_io_hyst_set(BOARD_IOID_MPU_INT, IOC_HYST_ENABLE); - - ti_lib_rom_ioc_pin_type_gpio_output(BOARD_IOID_MPU_POWER); - ti_lib_ioc_io_drv_strength_set(BOARD_IOID_MPU_POWER, IOC_CURRENT_4MA, - IOC_STRENGTH_MAX); - ti_lib_gpio_clear_dio(BOARD_IOID_MPU_POWER); - elements = MPU_9250_SENSOR_TYPE_NONE; - break; - case SENSORS_ACTIVE: - if(((enable & MPU_9250_SENSOR_TYPE_ACC) != 0) || - ((enable & MPU_9250_SENSOR_TYPE_GYRO) != 0)) { - PRINTF("MPU: Enabling\n"); - elements = enable & MPU_9250_SENSOR_TYPE_ALL; - - power_up(); - - state = SENSOR_STATE_BOOTING; + if (sensor_init()) { + mpu_9250.status = MPU_9250_SENSOR_STATUS_ENABLED; } else { - PRINTF("MPU: Disabling\n"); - if(HWREG(GPIO_BASE + GPIO_O_DOUT31_0) & BOARD_MPU_POWER) { - /* Then check our state */ - elements = MPU_9250_SENSOR_TYPE_NONE; - ctimer_stop(&startup_timer); - sensor_sleep(); - while(ti_lib_i2c_master_busy(I2C0_BASE)); - state = SENSOR_STATE_DISABLED; - ti_lib_gpio_clear_dio(BOARD_IOID_MPU_POWER); - } + mpu_9250.status = MPU_9250_SENSOR_STATUS_DISABLED; } break; + + case SENSORS_ACTIVE: + if (enable_type != MPU_9250_SENSOR_TYPE_NONE) { + PRINTF("MPU: Enabling\n"); + + mpu_9250.type = enable_type; + mpu_9250.status = MPU_9250_SENSOR_STATUS_BOOTING; + + PIN_setOutputValue(pinHandle, Board_MPU_POWER, 1); + + ctimer_set(&startup_timer, SENSOR_BOOT_DELAY, initialise_cb, NULL); + } else { + PRINTF("MPU: Disabling\n"); + + ctimer_stop(&startup_timer); + + if (PIN_getOutputValue(Board_MPU_POWER)) { + sensor_sleep(); + + I2C_cancel(i2cHandle); + PIN_setOutputValue(pinHandle, Board_MPU_POWER, 0); + } + + mpu_9250.type = MPU_9250_SENSOR_TYPE_NONE; + mpu_9250.status = MPU_9250_SENSOR_STATUS_DISABLED; + } + break; + default: break; } - return state; + return mpu_9250.status; } /*---------------------------------------------------------------------------*/ /** @@ -647,15 +596,14 @@ configure(int type, int enable) static int status(int type) { - switch(type) { + switch (type) { case SENSORS_ACTIVE: case SENSORS_READY: - return state; - break; + return mpu_9250.status; + default: - break; + return MPU_9250_SENSOR_STATUS_DISABLED; } - return SENSOR_STATE_DISABLED; } /*---------------------------------------------------------------------------*/ SENSORS_SENSOR(mpu_9250_sensor, "MPU9250", value, configure, status); diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.h index da4386412..e27c75dde 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.h @@ -68,36 +68,53 @@ #ifndef MPU_9250_SENSOR_H_ #define MPU_9250_SENSOR_H_ /*---------------------------------------------------------------------------*/ +#include "contiki-conf.h" +/*---------------------------------------------------------------------------*/ +#define MPU_9250_READING_ERROR -1 +/*---------------------------------------------------------------------------*/ /* ACC / Gyro Axes */ -#define MPU_9250_SENSOR_TYPE_GYRO_Z 0x01 -#define MPU_9250_SENSOR_TYPE_GYRO_Y 0x02 -#define MPU_9250_SENSOR_TYPE_GYRO_X 0x04 -#define MPU_9250_SENSOR_TYPE_GYRO_ALL 0x07 - -#define MPU_9250_SENSOR_TYPE_ACC_Z 0x08 -#define MPU_9250_SENSOR_TYPE_ACC_Y 0x10 -#define MPU_9250_SENSOR_TYPE_ACC_X 0x20 -#define MPU_9250_SENSOR_TYPE_ACC_ALL 0x38 - -#define MPU_9250_SENSOR_TYPE_MASK 0x3F -#define MPU_9250_SENSOR_TYPE_ACC 0x38 -#define MPU_9250_SENSOR_TYPE_GYRO 0x07 - -#define MPU_9250_SENSOR_TYPE_NONE 0 -#define MPU_9250_SENSOR_TYPE_ALL (MPU_9250_SENSOR_TYPE_ACC | \ - MPU_9250_SENSOR_TYPE_GYRO) +typedef enum { + MPU_9250_SENSOR_TYPE_NONE = (0), /* 0b000000 = 0x00 */ + MPU_9250_SENSOR_TYPE_GYRO_X = (1 << 0), /* 0b000001 = 0x01 */ + MPU_9250_SENSOR_TYPE_GYRO_Y = (1 << 1), /* 0b000010 = 0x02 */ + MPU_9250_SENSOR_TYPE_GYRO_Z = (1 << 2), /* 0b000100 = 0x04 */ + MPU_9250_SENSOR_TYPE_ACC_X = (1 << 3), /* 0b001000 = 0x08 */ + MPU_9250_SENSOR_TYPE_ACC_Y = (1 << 4), /* 0b010000 = 0x10 */ + MPU_9250_SENSOR_TYPE_ACC_Z = (1 << 5), /* 0b100000 = 0x20 */ + MPU_9250_SENSOR_TYPE_GYRO = MPU_9250_SENSOR_TYPE_GYRO_X + | MPU_9250_SENSOR_TYPE_GYRO_Y + | MPU_9250_SENSOR_TYPE_GYRO_Z, + /* 0b000111 = 0x07 */ + MPU_9250_SENSOR_TYPE_ACC = MPU_9250_SENSOR_TYPE_ACC_X + | MPU_9250_SENSOR_TYPE_ACC_Y + | MPU_9250_SENSOR_TYPE_ACC_Z, + /* 0b111000 = 0x38 */ + MPU_9250_SENSOR_TYPE_ALL = MPU_9250_SENSOR_TYPE_GYRO + | MPU_9250_SENSOR_TYPE_ACC + /* 0b111111 = 0x3F */ +} MPU_9250_SENSOR_TYPE; /*---------------------------------------------------------------------------*/ /* Accelerometer range */ -#define MPU_9250_SENSOR_ACC_RANGE_2G 0 -#define MPU_9250_SENSOR_ACC_RANGE_4G 1 -#define MPU_9250_SENSOR_ACC_RANGE_8G 2 -#define MPU_9250_SENSOR_ACC_RANGE_16G 3 +typedef enum { + MPU_9250_SENSOR_ACC_RANGE_2G = 0, + MPU_9250_SENSOR_ACC_RANGE_4G = 1, + MPU_9250_SENSOR_ACC_RANGE_8G = 2, + MPU_9250_SENSOR_ACC_RANGE_16G = 3 +} MPU_9250_SENSOR_ACC_RANGE; /*---------------------------------------------------------------------------*/ -/* Accelerometer range configuration */ -#ifdef MPU_9250_SENSOR_CONF_ACC_RANGE -#define MPU_9250_SENSOR_ACC_RANGE MPU_9250_SENSOR_CONF_ACC_RANGE +/* Sensor status */ +typedef enum { + MPU_9250_SENSOR_STATUS_DISABLED, + MPU_9250_SENSOR_STATUS_ENABLED, + MPU_9250_SENSOR_STATUS_BOOTING, + MPU_9250_SENSOR_STATUS_READY +} MPU_9250_SENSOR_STATUS; +/*---------------------------------------------------------------------------*/ +/* Accelerometer range configuration, type MPU_9250_SENSOR_ACC_RANGE */ +#ifdef MPU_9250_SENSOR_CONF_ACC_RANGE_ARG +# define MPU_9250_SENSOR_ACC_RANGE_ARG MPU_9250_SENSOR_CONF_ACC_RANGE #else -#define MPU_9250_SENSOR_ACC_RANGE MPU_9250_SENSOR_ACC_RANGE_2G +# define MPU_9250_SENSOR_ACC_RANGE_ARG MPU_9250_SENSOR_ACC_RANGE_2G #endif /*---------------------------------------------------------------------------*/ extern const struct sensors_sensor mpu_9250_sensor; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.c index 39568b227..470d3102e 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.c @@ -38,17 +38,16 @@ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "lib/sensors.h" -#include "opt-3001-sensor.h" #include "sys/ctimer.h" -#include "ti-lib.h" -#include "board-i2c.h" -#include "sensor-common.h" - +#include "opt-3001-sensor.h" +/*---------------------------------------------------------------------------*/ +#include +#include +/*---------------------------------------------------------------------------*/ #include #include #include #include -#include /*---------------------------------------------------------------------------*/ #define DEBUG 0 #if DEBUG @@ -57,8 +56,11 @@ #define PRINTF(...) #endif /*---------------------------------------------------------------------------*/ +#ifndef Board_OPT3001_ADDR +# error "Board file doesn't define I2C address Board_OPT3001_ADDR" +#endif /* Slave address */ -#define OPT3001_I2C_ADDRESS 0x45 +#define OPT_3001_I2C_ADDRESS Board_OPT3001_ADDR /*---------------------------------------------------------------------------*/ /* Register addresses */ #define REG_RESULT 0x00 @@ -74,37 +76,37 @@ * We use uint16_t to read from / write to registers, meaning that the * register's MSB is the variable's LSB. */ -#define CONFIG_RN 0x00F0 /* [15..12] Range Number */ -#define CONFIG_CT 0x0008 /* [11] Conversion Time */ -#define CONFIG_M 0x0006 /* [10..9] Mode of Conversion */ -#define CONFIG_OVF 0x0001 /* [8] Overflow */ -#define CONFIG_CRF 0x8000 /* [7] Conversion Ready Field */ -#define CONFIG_FH 0x4000 /* [6] Flag High */ -#define CONFIG_FL 0x2000 /* [5] Flag Low */ -#define CONFIG_L 0x1000 /* [4] Latch */ -#define CONFIG_POL 0x0800 /* [3] Polarity */ -#define CONFIG_ME 0x0400 /* [2] Mask Exponent */ -#define CONFIG_FC 0x0300 /* [1..0] Fault Count */ +#define CFG_RN 0x00F0 /* [15..12] Range Number */ +#define CFG_CT 0x0008 /* [11] Conversion Time */ +#define CFG_M 0x0006 /* [10..9] Mode of Conversion */ +#define CFG_OVF 0x0001 /* [8] Overflow */ +#define CFG_CRF 0x8000 /* [7] Conversion Ready Field */ +#define CFG_FH 0x4000 /* [6] Flag High */ +#define CFG_FL 0x2000 /* [5] Flag Low */ +#define CFG_L 0x1000 /* [4] Latch */ +#define CFG_POL 0x0800 /* [3] Polarity */ +#define CFG_ME 0x0400 /* [2] Mask Exponent */ +#define CFG_FC 0x0300 /* [1..0] Fault Count */ /* Possible Values for CT */ -#define CONFIG_CT_100 0x0000 -#define CONFIG_CT_800 CONFIG_CT +#define CFG_CT_100 0x0000 +#define CFG_CT_800 CFG_CT /* Possible Values for M */ -#define CONFIG_M_CONTI 0x0004 -#define CONFIG_M_SINGLE 0x0002 -#define CONFIG_M_SHUTDOWN 0x0000 +#define CFG_M_CONTI 0x0004 +#define CFG_M_SINGLE 0x0002 +#define CFG_M_SHUTDOWN 0x0000 /* Reset Value for the register 0xC810. All zeros except: */ -#define CONFIG_RN_RESET 0x00C0 -#define CONFIG_CT_RESET CONFIG_CT_800 -#define CONFIG_L_RESET 0x1000 -#define CONFIG_DEFAULTS (CONFIG_RN_RESET | CONFIG_CT_100 | CONFIG_L_RESET) +#define CFG_RN_RESET 0x00C0 +#define CFG_CT_RESET CFG_CT_800 +#define CFG_L_RESET 0x1000 +#define CFG_DEFAULTS (CFG_RN_RESET | CFG_CT_100 | CFG_L_RESET) /* Enable / Disable */ -#define CONFIG_ENABLE_CONTINUOUS (CONFIG_M_CONTI | CONFIG_DEFAULTS) -#define CONFIG_ENABLE_SINGLE_SHOT (CONFIG_M_SINGLE | CONFIG_DEFAULTS) -#define CONFIG_DISABLE CONFIG_DEFAULTS +#define CFG_ENABLE_CONTINUOUS (CFG_M_CONTI | CFG_DEFAULTS) +#define CFG_ENABLE_SINGLE_SHOT (CFG_M_SINGLE | CFG_DEFAULTS) +#define CFG_DISABLE CFG_DEFAULTS /*---------------------------------------------------------------------------*/ /* Register length */ #define REGISTER_LENGTH 2 @@ -112,129 +114,106 @@ /* Sensor data size */ #define DATA_LENGTH 2 /*---------------------------------------------------------------------------*/ -/* - * SENSOR_STATE_SLEEPING and SENSOR_STATE_ACTIVE are mutually exclusive. - * SENSOR_STATE_DATA_READY can be ORd with both of the above. For example the - * sensor may be sleeping but with a conversion ready to read out. - */ -#define SENSOR_STATE_SLEEPING 0 -#define SENSOR_STATE_ACTIVE 1 -#define SENSOR_STATE_DATA_READY 2 +/* Byte swap of 16-bit register value */ +#define HI_UINT16(a) (((a) >> 8) & 0xFF) +#define LO_UINT16(a) ((a) & 0xFF) -static int state = SENSOR_STATE_SLEEPING; +#define SWAP16(v) ((LO_UINT16(v) << 8) | HI_UINT16(v)) + +#define LSB16(v) (LO_UINT16(v)), (HI_UINT16(v)) +#define MSB16(v) (HI_UINT16(v)), (LO_UINT16(v)) +/*---------------------------------------------------------------------------*/ +typedef struct { + volatile OPT_3001_STATUS status; +} OPT_3001_Object; + +static OPT_3001_Object opt_3001; /*---------------------------------------------------------------------------*/ /* Wait SENSOR_STARTUP_DELAY for the sensor to be ready - 125ms */ #define SENSOR_STARTUP_DELAY (CLOCK_SECOND >> 3) static struct ctimer startup_timer; /*---------------------------------------------------------------------------*/ -/** - * \brief Select the sensor on the I2C bus - */ -static void -select_on_bus(void) -{ - /* Select slave and set clock rate */ - board_i2c_select(BOARD_I2C_INTERFACE_0, OPT3001_I2C_ADDRESS); -} +static I2C_Handle i2cHandle; /*---------------------------------------------------------------------------*/ -static void -notify_ready(void *not_used) +static bool +i2c_write_read(void *writeBuf, size_t writeCount, void *readBuf, size_t readCount) { - /* - * Depending on the CONFIGURATION.CONVERSION_TIME bits, a conversion will - * take either 100 or 800 ms. Here we inspect the CONVERSION_READY bit and - * if the reading is ready we notify, otherwise we just reschedule ourselves - */ - uint16_t val; + I2C_Transaction i2cTransaction = { + .writeBuf = writeBuf, + .writeCount = writeCount, + .readBuf = readBuf, + .readCount = readCount, + .slaveAddress = OPT_3001_I2C_ADDRESS, + }; - select_on_bus(); + return I2C_transfer(i2cHandle, &i2cTransaction); +} - sensor_common_read_reg(REG_CONFIGURATION, (uint8_t *)&val, REGISTER_LENGTH); - - if(val & CONFIG_CRF) { - sensors_changed(&opt_3001_sensor); - state = SENSOR_STATE_DATA_READY; - } else { - ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready, NULL); +#define i2c_write(writeBuf, writeCount) i2c_write_read(writeBuf, writeCount, NULL, 0) +#define i2c_read(readBuf, readCount) i2c_write_read(NULL, 0, readBuf, readCount) +/*---------------------------------------------------------------------------*/ +static bool +sensor_init(void) +{ + if (i2cHandle) { + return true; } + + I2C_Params i2cParams; + I2C_Params_init(&i2cParams); + i2cParams.transferMode = I2C_MODE_BLOCKING; + i2cParams.bitRate = I2C_400kHz; + + i2cHandle = I2C_open(Board_I2C0, &i2cParams); + if (i2cHandle == NULL) { + return false; + } + + opt_3001.status = OPT_3001_STATUS_DISABLED; + + return true; } /*---------------------------------------------------------------------------*/ /** * \brief Turn the sensor on/off * \param enable TRUE: on, FALSE: off */ -static void -enable_sensor(bool enable) -{ - uint16_t val; - uint16_t had_data_ready = state & SENSOR_STATE_DATA_READY; - - select_on_bus(); - - if(enable) { - val = CONFIG_ENABLE_SINGLE_SHOT; - - /* Writing CONFIG_ENABLE_SINGLE_SHOT to M bits will clear CRF bits */ - state = SENSOR_STATE_ACTIVE; - } else { - val = CONFIG_DISABLE; - - /* Writing CONFIG_DISABLE to M bits will not clear CRF bits */ - state = SENSOR_STATE_SLEEPING | had_data_ready; - } - - sensor_common_write_reg(REG_CONFIGURATION, (uint8_t *)&val, REGISTER_LENGTH); -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Read the result register - * \param raw_data Pointer to a buffer to store the reading - * \return TRUE if valid data - */ static bool -read_data(uint16_t *raw_data) +sensor_enable(bool enable) { - bool success; - uint16_t val; + uint16_t data = (enable) + ? CFG_ENABLE_SINGLE_SHOT + : CFG_DISABLE; - if((state & SENSOR_STATE_DATA_READY) != SENSOR_STATE_DATA_READY) { - return false; - } - - select_on_bus(); - - success = sensor_common_read_reg(REG_CONFIGURATION, (uint8_t *)&val, - REGISTER_LENGTH); - - if(success) { - success = sensor_common_read_reg(REG_RESULT, (uint8_t *)&val, DATA_LENGTH); - } - - if(success) { - /* Swap bytes */ - *raw_data = (val << 8) | (val >> 8 & 0xFF); - } else { - sensor_common_set_error_data((uint8_t *)raw_data, DATA_LENGTH); - } - - return success; + uint8_t cfg_data[] = { REG_CONFIGURATION, LSB16(data) }; + return i2c_write(cfg_data, sizeof(cfg_data)); } /*---------------------------------------------------------------------------*/ -/** - * \brief Convert raw data to a value in lux - * \param raw_data data Pointer to a buffer with a raw sensor reading - * \return Converted value (lux) - */ -static float -convert(uint16_t raw_data) +static void +notify_ready_cb(void *not_used) { - uint16_t e, m; + /* + * Depending on the CONFIGURATION.CONVERSION_TIME bits, a conversion will + * take either 100 or 800 ms. Here we inspect the CONVERSION_READY bit and + * if the reading is ready we notify, otherwise we just reschedule ourselves + */ - m = raw_data & 0x0FFF; - e = (raw_data & 0xF000) >> 12; + uint8_t cfg_data[] = { REG_CONFIGURATION }; + uint16_t cfg_value = 0; - return m * (0.01 * exp2(e)); + bool spi_ok = i2c_write_read(cfg_data, sizeof(cfg_data), &cfg_value, sizeof(cfg_value)); + if (!spi_ok) { + opt_3001.status = OPT_3001_STATUS_I2C_ERROR; + return; + } + + if (cfg_value & CFG_CRF) { + opt_3001.status = OPT_3001_STATUS_DATA_READY; + sensors_changed(&opt_3001_sensor); + } else { + ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready_cb, NULL); + } } /*---------------------------------------------------------------------------*/ /** @@ -245,23 +224,38 @@ convert(uint16_t raw_data) static int value(int type) { - int rv; - uint16_t raw_val; - float converted_val; - - rv = read_data(&raw_val); - - if(rv == false) { - return CC26XX_SENSOR_READING_ERROR; + if (opt_3001.status != OPT_3001_STATUS_DATA_READY) { + return MPU_9250_READING_ERROR; } - converted_val = convert(raw_val); - PRINTF("OPT: %04X r=%d (centilux)\n", raw_val, - (int)(converted_val * 100)); + uint8_t cfg_data[] = { REG_CONFIGURATION }; + uint16_t cfg_value = 0; - rv = (int)(converted_val * 100); + bool spi_ok = i2c_write_read(cfg_data, sizeof(cfg_data), &cfg_value, sizeof(cfg_value)); + if (!spi_ok) { + opt_3001.status = OPT_3001_STATUS_I2C_ERROR; + return MPU_9250_READING_ERROR; + } - return rv; + uint8_t result_data[] = { REG_RESULT }; + uint16_t result_value = 0; + + spi_ok = i2c_write_read(result_data, sizeof(result_data), &result_value, sizeof(result_value)); + if (!spi_ok) { + opt_3001.status = OPT_3001_STATUS_I2C_ERROR; + return MPU_9250_READING_ERROR; + } + + result_value = SWAP16(result_value); + + uint32_t e = (result_value & 0x0FFF) >> 0; + uint32_t m = (result_value & 0xF000) >> 12; + uint32_t converted = m * 100 * (1 << e); + + PRINTF("OPT: %04X r=%d (centilux)\n", result_value, + (int)(converted)); + + return (int)converted; } /*---------------------------------------------------------------------------*/ /** @@ -278,30 +272,32 @@ static int configure(int type, int enable) { int rv = 0; - switch(type) { case SENSORS_HW_INIT: - /* - * Device reset won't reset the sensor, so we put it to sleep here - * explicitly - */ - enable_sensor(0); - rv = 0; - break; - case SENSORS_ACTIVE: - if(enable) { - enable_sensor(1); - ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready, NULL); - rv = 1; + if (sensor_init()) { + opt_3001.status = OPT_3001_STATUS_STANDBY; } else { - ctimer_stop(&startup_timer); - enable_sensor(0); - rv = 0; + opt_3001.status = OPT_3001_STATUS_DISABLED; + rv = MPU_9250_READING_ERROR; } break; + + case SENSORS_ACTIVE: + if(enable) { + sensor_enable(true); + ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready_cb, NULL); + + opt_3001.status = OPT_3001_STATUS_BOOTING; + } else { + ctimer_stop(&startup_timer); + sensor_enable(false); + } + break; + default: break; } + return rv; } /*---------------------------------------------------------------------------*/ @@ -313,13 +309,9 @@ configure(int type, int enable) static int status(int type) { - switch(type) { - case SENSORS_ACTIVE: - case SENSORS_READY: - default: - break; - } - return state; + (void)type; + + return opt_3001.status; } /*---------------------------------------------------------------------------*/ SENSORS_SENSOR(opt_3001_sensor, "OPT3001", value, configure, status); diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.h index e9fa379a4..4b3a84a5a 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.h @@ -59,6 +59,17 @@ #ifndef OPT_3001_SENSOR_H_ #define OPT_3001_SENSOR_H_ /*---------------------------------------------------------------------------*/ +#define MPU_9250_READING_ERROR -1 +/*---------------------------------------------------------------------------*/ +typedef enum { + OPT_3001_STATUS_DISABLED, + OPT_3001_STATUS_STANDBY, + OPT_3001_STATUS_BOOTING, + OPT_3001_STATUS_ACTIVE, + OPT_3001_STATUS_DATA_READY, + OPT_3001_STATUS_I2C_ERROR, +} OPT_3001_STATUS; +/*---------------------------------------------------------------------------*/ extern const struct sensors_sensor opt_3001_sensor; /*---------------------------------------------------------------------------*/ #endif /* OPT_3001_SENSOR_H_ */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/reed-relay.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/reed-relay.c index 736b2170a..9b8426553 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/reed-relay.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/reed-relay.c @@ -40,40 +40,56 @@ #include "sys/clock.h" #include "sys/timer.h" #include "lib/sensors.h" -#include "sensortag/reed-relay.h" -#include "gpio-interrupt.h" #include "sys/timer.h" - -#include "ti-lib.h" - +#include "reed-relay.h" +/*---------------------------------------------------------------------------*/ +#include +#include +/*---------------------------------------------------------------------------*/ #include /*---------------------------------------------------------------------------*/ static struct timer debouncetimer; /*---------------------------------------------------------------------------*/ -#define REED_IO_CFG (IOC_CURRENT_2MA | IOC_STRENGTH_AUTO | \ - IOC_IOPULL_DOWN | IOC_SLEW_DISABLE | \ - IOC_HYST_DISABLE | IOC_BOTH_EDGES | \ - IOC_INT_DISABLE | IOC_IOMODE_NORMAL | \ - IOC_NO_WAKE_UP | IOC_INPUT_ENABLE) +static PIN_Config reed_pin_table[] = { + Board_RELAY | PIN_INPUT_EN | PIN_PULLDOWN | PIN_IRQ_DIS, + PIN_TERMINATE +}; + +static PIN_State pin_state; +static PIN_Handle pin_handle; +/*---------------------------------------------------------------------------*/ +static bool +sensor_init(void) +{ + if (pin_handle) { + return true; + } + + pin_handle = PIN_open(&pin_state, reed_pin_table); + return pin_handle != NULL; +} /*---------------------------------------------------------------------------*/ /** * \brief Handler for Sensortag-CC26XX reed interrupts */ static void -reed_interrupt_handler(uint8_t ioid) +reed_relay_isr(PIN_Handle handle, PIN_Id pinId) { - if(!timer_expired(&debouncetimer)) { + (void)handle; + (void)pinId; + + if (!timer_expired(&debouncetimer)) { return; } - sensors_changed(&reed_relay_sensor); timer_set(&debouncetimer, CLOCK_SECOND / 2); + sensors_changed(&reed_relay_sensor); } /*---------------------------------------------------------------------------*/ static int value(int type) { - return (int)ti_lib_gpio_read_dio(BOARD_IOID_REED_RELAY); + return (int)PIN_getInputValue(Board_RELAY); } /*---------------------------------------------------------------------------*/ /** @@ -89,26 +105,22 @@ configure(int type, int value) { switch(type) { case SENSORS_HW_INIT: - ti_lib_ioc_int_disable(BOARD_IOID_REED_RELAY); - ti_lib_gpio_clear_event_dio(BOARD_IOID_REED_RELAY); + if (!sensor_init()) { + return REED_RELAY_READING_ERROR; + } - /* Enable the GPIO clock when the CM3 is running */ - ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_GPIO); - - /* S/W control, input, pull-down */ - ti_lib_ioc_port_configure_set(BOARD_IOID_REED_RELAY, IOC_PORT_GPIO, - REED_IO_CFG); - - gpio_interrupt_register_handler(BOARD_IOID_REED_RELAY, - reed_interrupt_handler); + PIN_setInterrupt(pin_handle, Board_RELAY | PIN_IRQ_DIS); + PIN_registerIntCb(pin_handle, reed_relay_isr); break; + case SENSORS_ACTIVE: - if(value) { - ti_lib_ioc_int_enable(BOARD_IOID_REED_RELAY); + if (value) { + PIN_setInterrupt(pin_handle, Board_RELAY | PIN_IRQ_NEGEDGE); } else { - ti_lib_ioc_int_disable(BOARD_IOID_REED_RELAY); + PIN_setInterrupt(pin_handle, Board_RELAY | PIN_IRQ_DIS); } break; + default: break; } @@ -123,12 +135,12 @@ configure(int type, int value) static int status(int type) { - switch(type) { + switch (type) { case SENSORS_ACTIVE: case SENSORS_READY: - return (ti_lib_ioc_port_configure_get(BOARD_IOID_REED_RELAY) - & IOC_INT_ENABLE) == IOC_INT_ENABLE; + return (PIN_getConfig(Board_RELAY) & PIN_BM_IRQ) != 0; break; + default: break; } diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/reed-relay.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/reed-relay.h index 0ed6dd819..e1a55eabc 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/reed-relay.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/reed-relay.h @@ -49,6 +49,8 @@ /*---------------------------------------------------------------------------*/ #include "lib/sensors.h" /*---------------------------------------------------------------------------*/ +#define REED_RELAY_READING_ERROR -1 +/*---------------------------------------------------------------------------*/ extern const struct sensors_sensor reed_relay_sensor; /*---------------------------------------------------------------------------*/ #endif /* REED_RELAY_H */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag.c index e2069f39f..2f953e681 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag.c @@ -37,126 +37,35 @@ */ /*---------------------------------------------------------------------------*/ #include "contiki.h" -#include "lib/sensors.h" -#include "buzzer.h" -#include "lpm.h" -#include "ti-lib.h" -#include "board-peripherals.h" -#include "board-i2c.h" - +/*---------------------------------------------------------------------------*/ +#include "Board.h" +#include "ti/drivers/dpl/HwiP.h" +#include "ti/drivers/GPIO.h" +#include "ti/drivers/I2C.h" +#include "ti/drivers/PIN.h" +#include "ti/drivers/SPI.h" +/*---------------------------------------------------------------------------*/ #include #include #include /*---------------------------------------------------------------------------*/ -static void -power_domains_on(void) -{ - /* Turn on the PERIPH PD */ - ti_lib_prcm_power_domain_on(PRCM_DOMAIN_PERIPH); - - /* Wait for domains to power on */ - while((ti_lib_prcm_power_domain_status(PRCM_DOMAIN_PERIPH) - != PRCM_DOMAIN_POWER_ON)); -} -/*---------------------------------------------------------------------------*/ -static void -lpm_wakeup_handler(void) -{ - power_domains_on(); -} -/*---------------------------------------------------------------------------*/ -static void -shutdown_handler(uint8_t mode) -{ - if(mode == LPM_MODE_SHUTDOWN) { - buzzer_stop(); - SENSORS_DEACTIVATE(bmp_280_sensor); - SENSORS_DEACTIVATE(opt_3001_sensor); - SENSORS_DEACTIVATE(tmp_007_sensor); - SENSORS_DEACTIVATE(hdc_1000_sensor); - SENSORS_DEACTIVATE(mpu_9250_sensor); - ti_lib_gpio_clear_dio(BOARD_IOID_MPU_POWER); - } - - /* In all cases, stop the I2C */ - board_i2c_shutdown(); -} -/*---------------------------------------------------------------------------*/ -/* - * Declare a data structure to register with LPM. - * We don't care about what power mode we'll drop to, we don't care about - * getting notified before deep sleep. All we need is to be notified when we - * wake up so we can turn power domains back on for I2C and SSI, and to make - * sure everything on the board is off before CM3 shutdown. - */ -LPM_MODULE(sensortag_module, NULL, shutdown_handler, lpm_wakeup_handler, - LPM_DOMAIN_NONE); -/*---------------------------------------------------------------------------*/ -static void -configure_unused_pins(void) -{ - /* DP[0..3] */ - ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_DP0); - ti_lib_ioc_io_port_pull_set(BOARD_IOID_DP0, IOC_IOPULL_DOWN); - ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_DP1); - ti_lib_ioc_io_port_pull_set(BOARD_IOID_DP1, IOC_IOPULL_DOWN); - ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_DP2); - ti_lib_ioc_io_port_pull_set(BOARD_IOID_DP2, IOC_IOPULL_DOWN); - ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_DP3); - ti_lib_ioc_io_port_pull_set(BOARD_IOID_DP3, IOC_IOPULL_DOWN); - - /* Devpack ID */ - ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_DEVPK_ID); - ti_lib_ioc_io_port_pull_set(BOARD_IOID_DEVPK_ID, IOC_IOPULL_UP); - - /* Digital Microphone */ - ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_MIC_POWER); - ti_lib_gpio_clear_dio(BOARD_IOID_MIC_POWER); - ti_lib_ioc_io_drv_strength_set(BOARD_IOID_MIC_POWER, IOC_CURRENT_2MA, - IOC_STRENGTH_MIN); - - ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_AUDIO_DI); - ti_lib_ioc_io_port_pull_set(BOARD_IOID_AUDIO_DI, IOC_IOPULL_DOWN); - ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_AUDIO_CLK); - ti_lib_ioc_io_port_pull_set(BOARD_IOID_AUDIO_CLK, IOC_IOPULL_DOWN); - - /* UART over Devpack - TX only (ToDo: Map all UART pins to Debugger) */ - ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_DP5_UARTTX); - ti_lib_ioc_io_port_pull_set(BOARD_IOID_DP5_UARTTX, IOC_IOPULL_DOWN); -} -/*---------------------------------------------------------------------------*/ void board_init() { - /* Disable global interrupts */ - bool int_disabled = ti_lib_int_master_disable(); + /* Disable interrupts */ + const uintptr_t key = HwiP_disable(); - power_domains_on(); + // Board_initGeneral() will call Power_init() + // Board_initGeneral() will call PIN_init(BoardGpioInitTable) + Board_initGeneral(); + Board_shutDownExtFlash(); - /* Enable GPIO peripheral */ - ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_GPIO); + GPIO_init(); + I2C_init(); + SPI_init(); - /* Apply settings and wait for them to take effect */ - ti_lib_prcm_load_set(); - while(!ti_lib_prcm_load_get()); - - /* I2C controller */ - board_i2c_wakeup(); - - buzzer_init(); - - /* Make sure the external flash is in the lower power mode */ - ext_flash_init(); - - lpm_register_module(&sensortag_module); - - /* For unsupported peripherals, select a default pin configuration */ - configure_unused_pins(); - - /* Re-enable interrupt if initially enabled. */ - if(!int_disabled) { - ti_lib_int_master_enable(); - } + /* Restore interrupts. */ + HwiP_restore(key); } /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c index c40dd2eff..3cc154a08 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c @@ -38,16 +38,16 @@ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "lib/sensors.h" -#include "tmp-007-sensor.h" #include "sys/ctimer.h" -#include "board-i2c.h" -#include "sensor-common.h" -#include "ti-lib.h" - +#include "tmp-007-sensor.h" +/*---------------------------------------------------------------------------*/ +#include +#include +#include +/*---------------------------------------------------------------------------*/ #include #include #include -#include /*---------------------------------------------------------------------------*/ #define DEBUG 0 #if DEBUG @@ -57,24 +57,33 @@ #endif /*---------------------------------------------------------------------------*/ /* Slave address */ -#define SENSOR_I2C_ADDRESS 0x44 +#ifndef Board_TMP_ADDR +# error "Board file doesn't define I2C address Board_TMP_ADDR" +#endif +#define TMP_007_I2C_ADDRESS Board_TMP_ADDR + +/* MPU Interrupt pin */ +#ifndef Board_TMP_RDY +# error "Board file doesn't define interrupt pin Board_TMP_RDY" +#endif +#define TMP_007_TMP_RDY Board_TMP_RDY /*---------------------------------------------------------------------------*/ /* TMP007 register addresses */ -#define TMP007_REG_ADDR_VOLTAGE 0x00 -#define TMP007_REG_ADDR_LOCAL_TEMP 0x01 -#define TMP007_REG_ADDR_CONFIG 0x02 -#define TMP007_REG_ADDR_OBJ_TEMP 0x03 -#define TMP007_REG_ADDR_STATUS 0x04 -#define TMP007_REG_PROD_ID 0x1F +#define REG_VOLTAGE 0x00 +#define REG_LOCAL_TEMP 0x01 +#define REG_CONFIG 0x02 +#define REG_OBJ_TEMP 0x03 +#define REG_STATUS 0x04 +#define REG_PROD_ID 0x1F /*---------------------------------------------------------------------------*/ /* TMP007 register values */ -#define TMP007_VAL_CONFIG_ON 0x1000 /* Sensor on state */ -#define TMP007_VAL_CONFIG_OFF 0x0000 /* Sensor off state */ -#define TMP007_VAL_CONFIG_RESET 0x8000 -#define TMP007_VAL_PROD_ID 0x0078 /* Product ID */ +#define VAL_CONFIG_ON 0x1000 /* Sensor on state */ +#define VAL_CONFIG_OFF 0x0000 /* Sensor off state */ +#define VAL_CONFIG_RESET 0x8000 +#define VAL_PROD_ID 0x0078 /* Product ID */ /*---------------------------------------------------------------------------*/ /* Conversion ready (status register) bit values */ -#define CONV_RDY_BIT 0x4000 +#define CONV_RDY_BIT 0x4000 /*---------------------------------------------------------------------------*/ /* Register length */ #define REGISTER_LENGTH 2 @@ -86,33 +95,84 @@ #define HI_UINT16(a) (((a) >> 8) & 0xFF) #define LO_UINT16(a) ((a) & 0xFF) -#define SWAP(v) ((LO_UINT16(v) << 8) | HI_UINT16(v)) -/*---------------------------------------------------------------------------*/ -#define SELECT() board_i2c_select(BOARD_I2C_INTERFACE_0, SENSOR_I2C_ADDRESS) -/*---------------------------------------------------------------------------*/ -static uint8_t buf[DATA_SIZE]; -static uint16_t val; -/*---------------------------------------------------------------------------*/ -#define SENSOR_STATUS_DISABLED 0 -#define SENSOR_STATUS_INITIALISED 1 -#define SENSOR_STATUS_NOT_READY 2 -#define SENSOR_STATUS_READY 3 +#define SWAP16(v) ((LO_UINT16(v) << 8) | HI_UINT16(v)) -static int enabled = SENSOR_STATUS_DISABLED; +#define LSB16(v) (LO_UINT16(v)), (HI_UINT16(v)) +#define MSB16(v) (HI_UINT16(v)), (LO_UINT16(v)) +/*---------------------------------------------------------------------------*/ +static const PIN_Config pin_table[] = { + TMP_007_TMP_RDY | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS | PIN_IRQ_NEGEDGE, + PIN_TERMINATE +}; + +static PIN_State pin_state; +static PIN_Handle pin_handle; + +static I2C_Handle i2c_handle; +/*---------------------------------------------------------------------------*/ +typedef struct { + TMP_007_TYPE type; + volatile TMP_007_STATUS status; + uint16_t local_tmp_latched; + uint16_t obj_tmp_latched; +} TMP_007_Object; + +static TMP_007_Object tmp_007; /*---------------------------------------------------------------------------*/ /* Wait SENSOR_STARTUP_DELAY clock ticks for the sensor to be ready - 275ms */ #define SENSOR_STARTUP_DELAY 36 static struct ctimer startup_timer; /*---------------------------------------------------------------------------*/ -/* Latched values */ -static int obj_temp_latched; -static int amb_temp_latched; +static bool +i2c_write_read(void *writeBuf, size_t writeCount, void *readBuf, size_t readCount) +{ + I2C_Transaction i2c_transaction = { + .writeBuf = writeBuf, + .writeCount = writeCount, + .readBuf = readBuf, + .readCount = readCount, + .slaveAddress = TMP_007_I2C_ADDRESS, + }; + + return I2C_transfer(i2c_handle, &i2c_transaction); +} + +#define i2c_write(writeBuf, writeCount) i2c_write_read(writeBuf, writeCount, NULL, 0) +#define i2c_read(readBuf, readCount) i2c_write_read(NULL, 0, readBuf, readCount) +/*---------------------------------------------------------------------------*/ +static bool +sensor_init(void) +{ + if (pin_handle && i2c_handle) { + return true; + } + + pin_handle = PIN_open(&pin_state, pin_table); + if (!pin_handle) { + return false; + } + + I2C_Params i2c_params; + I2C_Params_init(&i2c_params); + i2c_params.transferMode = I2C_MODE_BLOCKING; + i2c_params.bitRate = I2C_400kHz; + + i2c_handle = I2C_open(Board_I2C0, &i2c_params); + if (i2c_handle == NULL) { + PIN_close(pin_handle); + return false; + } + + tmp_007.status = TMP_007_STATUS_DISABLED; + + return true; +} /*---------------------------------------------------------------------------*/ static void -notify_ready(void *not_used) +notify_ready_cb(void *not_used) { - enabled = SENSOR_STATUS_READY; + tmp_007.status = TMP_007_STATUS_READY; sensors_changed(&tmp_007_sensor); } /*---------------------------------------------------------------------------*/ @@ -122,21 +182,13 @@ notify_ready(void *not_used) static bool enable_sensor(bool enable) { - bool success; + uint16_t cfg_value = (enable) + ? VAL_CONFIG_ON + : VAL_CONFIG_OFF; - SELECT(); + uint8_t cfg_data[] = { REG_CONFIG, LSB16(cfg_value) }; - if(enable) { - val = TMP007_VAL_CONFIG_ON; - } else { - val = TMP007_VAL_CONFIG_OFF; - } - val = SWAP(val); - - success = sensor_common_write_reg(TMP007_REG_ADDR_CONFIG, (uint8_t *)&val, - REGISTER_LENGTH); - - return success; + return i2c_write(cfg_data, sizeof(cfg_data)); } /*---------------------------------------------------------------------------*/ /** @@ -146,38 +198,46 @@ enable_sensor(bool enable) * \return TRUE if valid data could be retrieved */ static bool -read_data(uint16_t *raw_temp, uint16_t *raw_obj_temp) +read_data(uint16_t *local_tmp, uint16_t *obj_tmp) { - bool success; + bool spi_ok = false; - SELECT(); + uint8_t status_data[] = { REG_STATUS }; + uint16_t status_value = 0; - success = sensor_common_read_reg(TMP007_REG_ADDR_STATUS, (uint8_t *)&val, - REGISTER_LENGTH); + spi_ok = i2c_write_read(status_data, sizeof(status_data), + &status_value, sizeof(status_value)); + if (!spi_ok) { + return false; + } + status_value = SWAP16(status_value); - if(success) { - val = SWAP(val); - success = val & CONV_RDY_BIT; + if ((status_value & CONV_RDY_BIT) == 0) { + return false; } - if(success) { - success = sensor_common_read_reg(TMP007_REG_ADDR_LOCAL_TEMP, &buf[0], - REGISTER_LENGTH); - if(success) { - success = sensor_common_read_reg(TMP007_REG_ADDR_OBJ_TEMP, &buf[2], - REGISTER_LENGTH); - } + uint8_t local_temp_data[] = { REG_LOCAL_TEMP }; + uint16_t local_temp_value = 0; + + spi_ok = i2c_write_read(local_temp_data, sizeof(local_temp_data), + &local_temp_value, sizeof(local_temp_value)); + if (!spi_ok) { + return false; } - if(!success) { - sensor_common_set_error_data(buf, 4); + uint8_t obj_temp_data[] = { REG_OBJ_TEMP }; + uint16_t obj_temp_value = 0; + + spi_ok = i2c_write_read(obj_temp_data, sizeof(obj_temp_data), + &obj_temp_value, sizeof(obj_temp_value)); + if (!spi_ok) { + return false; } - /* Swap byte order */ - *raw_temp = buf[0] << 8 | buf[1]; - *raw_obj_temp = buf[2] << 8 | buf[3]; + *local_tmp = SWAP16(local_temp_value); + *obj_tmp = SWAP16(obj_temp_value); - return success; + return true; } /*---------------------------------------------------------------------------*/ /** @@ -188,19 +248,16 @@ read_data(uint16_t *raw_temp, uint16_t *raw_obj_temp) * \param amb converted ambient temperature */ static void -convert(uint16_t raw_temp, uint16_t raw_obj_temp, float *obj, float *amb) +convert(uint16_t* local_tmp, uint16_t* obj_tmp) { - const float SCALE_LSB = 0.03125; - float t; - int it; + uint32_t local = (uint32_t)*local_tmp; + uint32_t obj = (uint32_t)*obj_tmp; - it = (int)((raw_obj_temp) >> 2); - t = ((float)(it)) * SCALE_LSB; - *obj = t; + local = (local >> 2) * 3125 / 100; + obj = (obj >> 2) * 3125 / 100; - it = (int)((raw_temp) >> 2); - t = (float)it; - *amb = t * SCALE_LSB; + *local_tmp = (uint16_t)local; + *obj_tmp = (uint16_t)obj; } /*---------------------------------------------------------------------------*/ /** @@ -211,45 +268,39 @@ convert(uint16_t raw_temp, uint16_t raw_obj_temp, float *obj, float *amb) static int value(int type) { - int rv; - uint16_t raw_temp; - uint16_t raw_obj_temp; - float obj_temp; - float amb_temp; + uint16_t raw_local_tmp = 0, local_tmp = 0; + uint16_t raw_obj_tmp = 0, obj_tmp = 0; - if(enabled != SENSOR_STATUS_READY) { - PRINTF("Sensor disabled or starting up (%d)\n", enabled); - return CC26XX_SENSOR_READING_ERROR; + if (tmp_007.status != TMP_007_STATUS_READY) { + PRINTF("Sensor disabled or starting up (%d)\n", tmp_007.status); + return TMP_007_READING_ERROR; } - if((type & TMP_007_SENSOR_TYPE_ALL) == 0) { - PRINTF("Invalid type\n"); - return CC26XX_SENSOR_READING_ERROR; - } + switch (type) { + case TMP_007_TYPE_OBJECT: return tmp_007.obj_tmp_latched; + case TMP_007_TYPE_AMBIENT: return tmp_007.local_tmp_latched; - rv = CC26XX_SENSOR_READING_ERROR; - - if(type == TMP_007_SENSOR_TYPE_ALL) { - rv = read_data(&raw_temp, &raw_obj_temp); - - if(rv == 0) { - return CC26XX_SENSOR_READING_ERROR; + case TMP_007_TYPE_ALL: + if (!read_data(&raw_local_tmp, &raw_obj_tmp)) { + return TMP_007_READING_ERROR; } - convert(raw_temp, raw_obj_temp, &obj_temp, &amb_temp); - PRINTF("TMP: %04X %04X o=%d a=%d\n", raw_temp, raw_obj_temp, - (int)(obj_temp * 1000), (int)(amb_temp * 1000)); + local_tmp = raw_local_tmp; + obj_tmp = raw_obj_tmp; + convert(&local_tmp, &obj_tmp); - obj_temp_latched = (int)(obj_temp * 1000); - amb_temp_latched = (int)(amb_temp * 1000); - rv = 1; - } else if(type == TMP_007_SENSOR_TYPE_OBJECT) { - rv = obj_temp_latched; - } else if(type == TMP_007_SENSOR_TYPE_AMBIENT) { - rv = amb_temp_latched; + PRINTF("TMP: %04X %04X o=%d a=%d\n", raw_local_tmp, raw_obj_tmp, + (int)(local_tmp), (int)(obj_tmp)); + + tmp_007.local_tmp_latched = (int)(local_tmp); + tmp_007.obj_tmp_latched = (int)(obj_tmp); + + return 0; + + default: + PRINTF("Invalid type (%d)\n", type); + return TMP_007_READING_ERROR; } - - return rv; } /*---------------------------------------------------------------------------*/ /** @@ -265,34 +316,38 @@ value(int type) static int configure(int type, int enable) { - switch(type) { + switch (type) { case SENSORS_HW_INIT: - ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_TMP_RDY); - ti_lib_ioc_io_port_pull_set(BOARD_IOID_TMP_RDY, IOC_IOPULL_UP); - ti_lib_ioc_io_hyst_set(BOARD_IOID_TMP_RDY, IOC_HYST_ENABLE); + if (!sensor_init()) { + return TMP_007_STATUS_DISABLED; + } enable_sensor(false); - enabled = SENSOR_STATUS_INITIALISED; + + tmp_007.status = TMP_007_STATUS_INITIALIZED; break; + case SENSORS_ACTIVE: /* Must be initialised first */ - if(enabled == SENSOR_STATUS_DISABLED) { - return SENSOR_STATUS_DISABLED; + if (tmp_007.status == TMP_007_STATUS_DISABLED) { + return TMP_007_STATUS_DISABLED; } - if(enable) { + if (enable) { enable_sensor(true); - ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready, NULL); - enabled = SENSOR_STATUS_NOT_READY; + ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready_cb, NULL); + tmp_007.status = TMP_007_STATUS_NOT_READY; } else { ctimer_stop(&startup_timer); enable_sensor(false); - enabled = SENSOR_STATUS_INITIALISED; + tmp_007.status = TMP_007_STATUS_INITIALIZED; } break; + default: break; } - return enabled; + + return tmp_007.status; } /*---------------------------------------------------------------------------*/ /** @@ -303,15 +358,9 @@ configure(int type, int enable) static int status(int type) { - switch(type) { - case SENSORS_ACTIVE: - case SENSORS_READY: - return enabled; - break; - default: - break; - } - return SENSOR_STATUS_DISABLED; + (void)type; + + return tmp_007.status; } /*---------------------------------------------------------------------------*/ SENSORS_SENSOR(tmp_007_sensor, "TMP007", value, configure, status); diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.h index 5260c9152..0ba8dcfcb 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.h @@ -62,9 +62,22 @@ #ifndef TMP_007_SENSOR_H_ #define TMP_007_SENSOR_H_ /*---------------------------------------------------------------------------*/ -#define TMP_007_SENSOR_TYPE_OBJECT 1 -#define TMP_007_SENSOR_TYPE_AMBIENT 2 -#define TMP_007_SENSOR_TYPE_ALL 3 +typedef enum { + TMP_007_TYPE_OBJECT = (1 << 0), + TMP_007_TYPE_AMBIENT = (1 << 1), + TMP_007_TYPE_ALL = TMP_007_TYPE_OBJECT + | TMP_007_TYPE_AMBIENT, +} TMP_007_TYPE; +/*---------------------------------------------------------------------------*/ +typedef enum { + TMP_007_STATUS_DISABLED, + TMP_007_STATUS_INITIALIZED, + TMP_007_STATUS_NOT_READY, + TMP_007_STATUS_READY, + TMP_007_STATUS_I2C_ERROR, +} TMP_007_STATUS; +/*---------------------------------------------------------------------------*/ +#define TMP_007_READING_ERROR -1 /*---------------------------------------------------------------------------*/ extern const struct sensors_sensor tmp_007_sensor; /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/Makefile.srf06 b/arch/platform/simplelink/cc13xx-cc26xx/srf06/Makefile.srf06 index 19e54bb96..e15684248 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/Makefile.srf06 +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/Makefile.srf06 @@ -3,6 +3,8 @@ BOARD_TYPE = BOARD_SRF06 +PLATFORM_HAS_BUTTON = 1 + # leds-arch.c/h etc. BOARD_SOURCEFILES += srf06.c srf06-sensors.c BOARD_SOURCEFILES += button-sensor-arch.c leds-arch.c diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 index d666d4f9f..0069d0241 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 @@ -3,6 +3,7 @@ SUBFAMILY = cc13x0-cc26x0 DEVICE_FAMILY = CC13X0 +DEVICE_LINE = CC13XX BOARD_SOURCEFILES += CC1310DK_7XD.c diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Makefile.cc26x0 b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Makefile.cc26x0 index a27625228..ee23f7a3e 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Makefile.cc26x0 +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Makefile.cc26x0 @@ -3,6 +3,7 @@ SUBFAMILY = cc13x0-cc26x0 DEVICE_FAMILY = CC26X0 +DEVICE_LINE = CC26XX BOARD_SOURCEFILES += CC2650DK_7ID.c From 2d69241381cbb27aa6ee67c205c5b23d221a767d Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Thu, 31 May 2018 18:21:14 +0200 Subject: [PATCH 248/485] Fixed CC2650STK board files, and leds-arch for sensortag --- .../rf-settings/cc26x0/ieee-settings.c | 8 +- .../rf-settings/cc26x0/ieee-settings.h | 6 +- .../simplelink/cc13xx-cc26xx/contiki-conf.h | 2 + .../simplelink/cc13xx-cc26xx/platform.c | 47 ++- .../cc13xx-cc26xx/sensortag/cc1350/Board.h | 14 + .../sensortag/cc1350/CC1350STK.h | 3 +- .../sensortag/cc1350/Makefile.cc1350 | 1 + .../sensortag/{ => cc1350}/leds-arch.c | 42 ++- .../cc13xx-cc26xx/sensortag/cc2650/Board.h | 18 +- .../sensortag/cc2650/CC2650STK.c | 9 +- .../sensortag/cc2650/CC2650STK.h | 314 +++++++++--------- .../sensortag/cc2650/CC2650STK_fxns.c | 5 +- .../sensortag/cc2650/Makefile.cc2650 | 1 + .../sensortag/cc2650/leds-arch.c | 102 ++++++ .../cc13xx-cc26xx/sensortag/sensortag.c | 9 +- 15 files changed, 353 insertions(+), 228 deletions(-) rename arch/platform/simplelink/cc13xx-cc26xx/sensortag/{ => cc1350}/leds-arch.c (79%) create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/leds-arch.c diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c index dea8804a8..9ed0c5629 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c @@ -33,7 +33,7 @@ RF_Mode RF_ieeeMode = // RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) // See the Technical Reference Manual for further details about the "txPower" Command field. // The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. -RF_TxPowerTable_Entry txPowerTable[14] = +RF_TxPowerTable_Entry ieeeTxPowerTable[14] = { { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 6) }, { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 6) }, @@ -53,7 +53,7 @@ RF_TxPowerTable_Entry txPowerTable[14] = // Overrides for CMD_RADIO_SETUP -uint32_t pOverrides[] = +uint32_t pIeeeOverrides[] = { // override_synth_ieee_15_4.xml HW_REG_OVERRIDE(0x4038,0x0035), // Synth: Set recommended RTRIM to 5 @@ -101,12 +101,12 @@ rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup = .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, .txPower = 0x9330, - .pRegOverride = pOverrides, + .pRegOverride = pIeeeOverrides, }; // CMD_FS // Frequency Synthesizer Programming Command -rfc_CMD_FS_t RF_cmdFs = +rfc_CMD_FS_t RF_cmdIeeeFs = { .commandNo = 0x0803, .status = 0x0000, diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h index a26616ad3..1a762a23a 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h @@ -20,17 +20,17 @@ extern RF_Mode RF_ieeeMode; // TX Power Table -extern RF_TxPowerTable_Entry txPowerTable[14]; +extern RF_TxPowerTable_Entry ieeeTxPowerTable[14]; // RF Core API commands extern rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup; -extern rfc_CMD_FS_t RF_cmdFs; +extern rfc_CMD_FS_t RF_cmdIeeeFs; extern rfc_CMD_IEEE_TX_t RF_cmdIeeeTx; extern rfc_CMD_IEEE_RX_t RF_cmdIeeeRx; // RF Core API Overrides -extern uint32_t pOverrides[]; +extern uint32_t pIeeeOverrides[]; #endif // _IEEE_SETTINGS_H_ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h b/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h index f577cfc3d..468e74170 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h @@ -38,6 +38,8 @@ #ifndef CONTIKI_CONF_H_ #define CONTIKI_CONF_H_ /*---------------------------------------------------------------------------*/ +#include +/*---------------------------------------------------------------------------*/ /* Include Project Specific conf */ #ifdef PROJECT_CONF_PATH #include PROJECT_CONF_PATH diff --git a/arch/platform/simplelink/cc13xx-cc26xx/platform.c b/arch/platform/simplelink/cc13xx-cc26xx/platform.c index c5718a103..ab29bce0d 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/platform.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/platform.c @@ -48,13 +48,17 @@ /*---------------------------------------------------------------------------*/ /* Simplelink SDK includes */ #include -#include -#include -#include -#include -#include -#include #include +#include +#include DeviceFamily_constructPath(driverlib/driverlib_release.h) +#include DeviceFamily_constructPath(driverlib/chipinfo.h) +#include DeviceFamily_constructPath(driverlib/vims.h) +#include DeviceFamily_constructPath(driverlib/interrupt.h) +#include +#include +#include +#include +#include /*---------------------------------------------------------------------------*/ /* Contiki API */ #include "contiki.h" @@ -135,34 +139,23 @@ platform_init_stage_one(void) // Configure round robin arbitration and prefetching VIMSConfigure(VIMS_BASE, true, true); - Board_initGeneral(); - GPIO_init(); - // NoRTOS_start only enables HWI NoRTOS_start(); + // Board_initGeneral() will call Power_init() + // Board_initGeneral() will call PIN_init(BoardGpioInitTable) + Board_initGeneral(); + Board_shutDownExtFlash(); + // Contiki drivers init leds_init(); -// ti_lib_int_master_disable(); -// -// /* Set the LF XOSC as the LF system clock source */ -// oscillators_select_lf_xosc(); -// -// lpm_init(); -// fade(LEDS_RED); -// -// /* -// * Disable I/O pad sleep mode and open I/O latches in the AON IOC interface -// * This is only relevant when returning from shutdown (which is what froze -// * latches in the first place. Before doing these things though, we should -// * allow software to first regain control of pins -// */ -// ti_lib_pwr_ctrl_io_freeze_disable(); -// -// ti_lib_int_master_enable(); -// + + GPIO_init(); + I2C_init(); + SPI_init(); + fade(LEDS_GREEN); } /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h index 85f0452a2..0ef38605b 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h @@ -45,6 +45,20 @@ extern "C" { #define Board_shutDownExtFlash() CC1350STK_shutDownExtFlash() #define Board_wakeUpExtFlash() CC1350STK_wakeUpExtFlash() +/*---------------------------------------------------------------------------*/ +/** + * \name LED configurations + * + * Those values are not meant to be modified by the user + * @{ + */ +#define LEDS_RED (1 << 0) +#define LEDS_GREEN LEDS_RED +#define LEDS_YELLOW LEDS_RED +#define LEDS_ORANGE LEDS_RED + +#define LEDS_CONF_ALL (LEDS_RED) +/*---------------------------------------------------------------------------*/ /* These #defines allow us to reuse TI-RTOS across other device families */ #define Board_BUZZER CC1350STK_BUZZER diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.h index ce07503f0..4d3b707af 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.h @@ -50,7 +50,8 @@ extern "C" { /* Includes */ #include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) /* Externs */ extern const PIN_Config BoardGpioInitTable[]; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Makefile.cc1350 b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Makefile.cc1350 index 444d11048..44939378c 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Makefile.cc1350 +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Makefile.cc1350 @@ -6,6 +6,7 @@ DEVICE_FAMILY = CC13X0 DEVICE_LINE = CC13XX BOARD_SOURCEFILES += CC1350STK.c CC1350STK_fxns.c +BOARD_SOURCEFILES += leds-arch.c SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/leds-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/leds-arch.c similarity index 79% rename from arch/platform/simplelink/cc13xx-cc26xx/sensortag/leds-arch.c rename to arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/leds-arch.c index aa1de6db5..227f79908 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/leds-arch.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/leds-arch.c @@ -43,17 +43,20 @@ /* Simplelink SDK API */ #include -#include +#include /*---------------------------------------------------------------------------*/ /* Standard library */ #include #include /*---------------------------------------------------------------------------*/ -/* Available LED configuration */ +static const PIN_Config pin_table[] = { + Board_PIN_LED0 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, + PIN_TERMINATE +}; + +static PIN_State pin_state; +static PIN_Handle pin_handle; -/* LED */ -#define LEDS_ARCH Board_GPIO_LED0 -/*---------------------------------------------------------------------------*/ static volatile unsigned char c; /*---------------------------------------------------------------------------*/ void @@ -63,12 +66,14 @@ leds_arch_init(void) if(bHasInit) { return; } - bHasInit = true; - // GPIO_init will most likely be called in platform.c, - // but call it here to be sure GPIO is initialized. - // Calling GPIO_init multiple times is safe. - GPIO_init(); + // PIN_init() called from Board_initGeneral() + pin_handle = PIN_open(&pin_state, pin_table); + if (!pin_handle) { + return; + } + + bHasInit = true; } /*---------------------------------------------------------------------------*/ unsigned char @@ -77,23 +82,16 @@ leds_arch_get(void) return c; } /*---------------------------------------------------------------------------*/ -static inline void -write_led(const bool on, const uint_fast32_t gpioLed) -{ - const GPIO_PinConfig pinCfg = (on) - ? Board_GPIO_LED_ON - : Board_GPIO_LED_OFF; - GPIO_write(gpioLed, pinCfg); -} -/*---------------------------------------------------------------------------*/ void leds_arch_set(unsigned char leds) { c = leds; - // Green LED - uint_fast32_t gpioOn = (leds & (LEDS_ARCH)) == (LEDS_ARCH); - write_led(gpioOn, LEDS_ARCH); + PIN_setPortOutputValue(pin_handle, 0); + + if (leds & LEDS_RED) { + PIN_setOutputValue(pin_handle, Board_PIN_LED0, 1); + } } /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h index 410c2508b..db34c35d3 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h @@ -45,6 +45,20 @@ extern "C" { #define Board_shutDownExtFlash() CC2650STK_shutDownExtFlash() #define Board_wakeUpExtFlash() CC2650STK_wakeUpExtFlash() +/*---------------------------------------------------------------------------*/ +/** + * \name LED configurations + * + * Those values are not meant to be modified by the user + * @{ + */ +#define LEDS_RED (1 << 0) +#define LEDS_GREEN (1 << 1) +#define LEDS_YELLOW LEDS_GREEN +#define LEDS_ORANGE LEDS_RED + +#define LEDS_CONF_ALL (LEDS_RED | LEDS_GREEN) +/*---------------------------------------------------------------------------*/ /* These #defines allow us to reuse TI-RTOS across other device families */ #define Board_BUZZER CC2650STK_BUZZER @@ -87,6 +101,8 @@ extern "C" { #define Board_MPU_POWER_OFF CC2650STK_MPU_POWER_OFF #define Board_MPU_POWER_ON CC2650STK_MPU_POWER_ON +#define Board_TMP_RDY CC2650STK_TMP_RDY + #define Board_NVSINTERNAL CC2650STK_NVSCC26XX0 #define Board_NVSEXTERNAL CC2650STK_NVSSPI25X0 @@ -94,7 +110,7 @@ extern "C" { #define Board_PIN_BUTTON0 CC2650STK_KEY_LEFT #define Board_PIN_BUTTON1 CC2650STK_KEY_RIGHT -#define Board_PIN_LED0 CC2650STK_PIN_LED1 +#define Board_PIN_LED0 CC2650STK_PIN_LED0 #define Board_PIN_LED1 CC2650STK_PIN_LED1 #define Board_PIN_LED2 CC2650STK_PIN_LED1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.c index 14c6ca382..79df88f05 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.c @@ -43,10 +43,11 @@ #include #include -#include -#include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/udma.h) +#include DeviceFamily_constructPath(inc/hw_ints.h) +#include DeviceFamily_constructPath(inc/hw_memmap.h) #include "CC2650STK.h" diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h index ce07503f0..8511cd524 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h @@ -30,19 +30,19 @@ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** ============================================================================ - * @file CC1350STK.h + * @file CC2650STK.h * - * @brief CC1350STK Board Specific header file. + * @brief CC2650STK Board Specific header file. * - * The CC1350STK header file should be included in an application as + * The CC2650STK header file should be included in an application as * follows: * @code - * #include "CC1350STK.h" + * #include "CC2650STK.h" * @endcode * ============================================================================ */ -#ifndef __CC1350STK_BOARD_H__ -#define __CC1350STK_BOARD_H__ +#ifndef __CC2650STK_BOARD_H__ +#define __CC2650STK_BOARD_H__ #ifdef __cplusplus extern "C" { @@ -50,119 +50,121 @@ extern "C" { /* Includes */ #include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) /* Externs */ extern const PIN_Config BoardGpioInitTable[]; /* Defines */ -#define CC1350STK +#define CC2650STK /* Mapping of pins to board signals using general board aliases * */ /* Audio */ -#define CC1350STK_MIC_POWER IOID_13 -#define CC1350STK_MIC_POWER_ON 1 -#define CC1350STK_MIC_POWER_OFF 0 -#define CC1350STK_AUDIO_DI IOID_2 -#define CC1350STK_AUDIO_CLK IOID_3 +#define CC2650STK_MIC_POWER IOID_13 +#define CC2650STK_MIC_POWER_ON 1 +#define CC2650STK_MIC_POWER_OFF 0 +#define CC2650STK_AUDIO_DI IOID_2 +#define CC2650STK_AUDIO_CLK IOID_11 /* Buzzer */ -#define CC1350STK_BUZZER IOID_21 -#define CC1350STK_BUZZER_ON 1 -#define CC1350STK_BUZZER_OFF 0 +#define CC2650STK_BUZZER IOID_21 +#define CC2650STK_BUZZER_ON 1 +#define CC2650STK_BUZZER_OFF 0 /* DevPack */ -#define CC1350STK_AUDIOFS_TDO IOID_16 -#define CC1350STK_AUDIODO IOID_22 -#define CC1350STK_DP2 IOID_23 -#define CC1350STK_DP1 IOID_24 -#define CC1350STK_DP0 IOID_25 -#define CC1350STK_DP3 IOID_27 -#define CC1350STK_DP4_UARTRX IOID_28 -#define CC1350STK_DP5_UARTTX IOID_29 -#define CC1350STK_DEVPK_ID IOID_30 -#define CC1350STK_SPI_DEVPK_CS IOID_20 +#define CC2650STK_AUDIOFS_TDO IOID_16 +#define CC2650STK_AUDIODO IOID_22 +#define CC2650STK_DP2 IOID_23 +#define CC2650STK_DP1 IOID_24 +#define CC2650STK_DP0 IOID_25 +#define CC2650STK_DP3 IOID_27 +#define CC2650STK_DP4_UARTRX IOID_28 +#define CC2650STK_DP5_UARTTX IOID_29 +#define CC2650STK_DEVPK_ID IOID_30 +#define CC2650STK_SPI_DEVPK_CS IOID_20 /* Discrete Outputs */ -#define CC1350STK_PIN_LED1 IOID_10 -#define CC1350STK_LED_ON 1 -#define CC1350STK_LED_OFF 0 +#define CC2650STK_PIN_LED0 IOID_10 +#define CC2650STK_PIN_LED1 IOID_15 +#define CC2650STK_LED_ON 1 +#define CC2650STK_LED_OFF 0 /* Discrete Inputs */ -#define CC1350STK_KEY_LEFT IOID_15 -#define CC1350STK_KEY_RIGHT IOID_4 -#define CC1350STK_RELAY IOID_1 +#define CC2650STK_KEY_LEFT IOID_0 +#define CC2650STK_KEY_RIGHT IOID_4 +#define CC2650STK_RELAY IOID_3 /* GPIO */ -#define CC1350STK_GPIO_LED_ON 1 -#define CC1350STK_GPIO_LED_OFF 0 +#define CC2650STK_GPIO_LED_ON 1 +#define CC2650STK_GPIO_LED_OFF 0 /* I2C */ -#define CC1350STK_I2C0_SDA0 IOID_5 -#define CC1350STK_I2C0_SCL0 IOID_6 -#define CC1350STK_I2C0_SDA1 IOID_8 -#define CC1350STK_I2C0_SCL1 IOID_9 +#define CC2650STK_I2C0_SDA0 IOID_5 +#define CC2650STK_I2C0_SCL0 IOID_6 +#define CC2650STK_I2C0_SDA1 IOID_8 +#define CC2650STK_I2C0_SCL1 IOID_9 /* LED-Audio DevPack */ -#define CC1350STK_DEVPK_LIGHT_BLUE IOID_23 -#define CC1350STK_DEVPK_LIGHT_GREEN IOID_24 -#define CC1350STK_DEVPK_LIGHT_WHITE IOID_25 -#define CC1350STK_DEVPK_LIGHT_RED IOID_27 +#define CC2650STK_DEVPK_LIGHT_BLUE IOID_23 +#define CC2650STK_DEVPK_LIGHT_GREEN IOID_24 +#define CC2650STK_DEVPK_LIGHT_WHITE IOID_25 +#define CC2650STK_DEVPK_LIGHT_RED IOID_27 /* Power */ -#define CC1350STK_MPU_POWER IOID_12 -#define CC1350STK_MPU_POWER_ON 1 -#define CC1350STK_MPU_POWER_OFF 0 +#define CC2650STK_MPU_POWER IOID_12 +#define CC2650STK_MPU_POWER_ON 1 +#define CC2650STK_MPU_POWER_OFF 0 /* PWM */ -#define CC1350STK_PWMPIN0 CC1350STK_PIN_LED1 -#define CC1350STK_PWMPIN1 CC1350STK_PIN_LED1 -#define CC1350STK_PWMPIN2 PIN_UNASSIGNED -#define CC1350STK_PWMPIN3 PIN_UNASSIGNED -#define CC1350STK_PWMPIN4 PIN_UNASSIGNED -#define CC1350STK_PWMPIN5 PIN_UNASSIGNED -#define CC1350STK_PWMPIN6 PIN_UNASSIGNED -#define CC1350STK_PWMPIN7 PIN_UNASSIGNED +#define CC2650STK_PWMPIN0 CC2650STK_PIN_LED1 +#define CC2650STK_PWMPIN1 CC2650STK_PIN_LED1 +#define CC2650STK_PWMPIN2 PIN_UNASSIGNED +#define CC2650STK_PWMPIN3 PIN_UNASSIGNED +#define CC2650STK_PWMPIN4 PIN_UNASSIGNED +#define CC2650STK_PWMPIN5 PIN_UNASSIGNED +#define CC2650STK_PWMPIN6 PIN_UNASSIGNED +#define CC2650STK_PWMPIN7 PIN_UNASSIGNED /* Sensors */ -#define CC1350STK_MPU_INT IOID_7 -#define CC1350STK_TMP_RDY IOID_11 +#define CC2650STK_MPU_INT IOID_7 +#define CC2650STK_TMP_RDY IOID_1 /* SPI */ -#define CC1350STK_SPI_FLASH_CS IOID_14 -#define CC1350STK_FLASH_CS_ON 0 -#define CC1350STK_FLASH_CS_OFF 1 +#define CC2650STK_SPI_FLASH_CS IOID_14 +#define CC2650STK_FLASH_CS_ON 0 +#define CC2650STK_FLASH_CS_OFF 1 /* SPI Board */ -#define CC1350STK_SPI0_MISO IOID_18 -#define CC1350STK_SPI0_MOSI IOID_19 -#define CC1350STK_SPI0_CLK IOID_17 -#define CC1350STK_SPI0_CSN PIN_UNASSIGNED -#define CC1350STK_SPI1_MISO PIN_UNASSIGNED -#define CC1350STK_SPI1_MOSI PIN_UNASSIGNED -#define CC1350STK_SPI1_CLK PIN_UNASSIGNED -#define CC1350STK_SPI1_CSN PIN_UNASSIGNED +#define CC2650STK_SPI0_MISO IOID_18 +#define CC2650STK_SPI0_MOSI IOID_19 +#define CC2650STK_SPI0_CLK IOID_17 +#define CC2650STK_SPI0_CSN PIN_UNASSIGNED +#define CC2650STK_SPI1_MISO PIN_UNASSIGNED +#define CC2650STK_SPI1_MOSI PIN_UNASSIGNED +#define CC2650STK_SPI1_CLK PIN_UNASSIGNED +#define CC2650STK_SPI1_CSN PIN_UNASSIGNED /* UART */ -#define CC1350STK_UART_TX CC1350STK_DP5_UARTTX -#define CC1350STK_UART_RX CC1350STK_DP4_UARTRX +#define CC2650STK_UART_TX CC2650STK_DP5_UARTTX +#define CC2650STK_UART_RX CC2650STK_DP4_UARTRX /*! * @brief Initialize the general board specific settings * * This function initializes the general board specific settings. */ -void CC1350STK_initGeneral(void); +void CC2650STK_initGeneral(void); /*! * @brief Turn off the external flash on LaunchPads * */ -void CC1350STK_shutDownExtFlash(void); +void CC2650STK_shutDownExtFlash(void); /*! * @brief Wake up the external flash present on the board files @@ -170,154 +172,154 @@ void CC1350STK_shutDownExtFlash(void); * This function toggles the chip select for the amount of time needed * to wake the chip up. */ -void CC1350STK_wakeUpExtFlash(void); +void CC2650STK_wakeUpExtFlash(void); /*! - * @def CC1350STK_CryptoName + * @def CC2650STK_CryptoName * @brief Enum of Crypto names */ -typedef enum CC1350STK_CryptoName { - CC1350STK_CRYPTO0 = 0, +typedef enum CC2650STK_CryptoName { + CC2650STK_CRYPTO0 = 0, - CC1350STK_CRYPTOCOUNT -} CC1350STK_CryptoName; + CC2650STK_CRYPTOCOUNT +} CC2650STK_CryptoName; /*! - * @def CC1350STK_GPIOName + * @def CC2650STK_GPIOName * @brief Enum of GPIO names */ -typedef enum CC1350STK_GPIOName { - CC1350STK_GPIO_S1 = 0, - CC1350STK_GPIO_S2, - CC1350STK_GPIO_LED0, - CC1350STK_GPIO_SPI_FLASH_CS, - CC1350STK_GPIO_LCD_CS, - CC1350STK_GPIO_LCD_ENABLE, +typedef enum CC2650STK_GPIOName { + CC2650STK_GPIO_S1 = 0, + CC2650STK_GPIO_S2, + CC2650STK_GPIO_LED0, + CC2650STK_GPIO_SPI_FLASH_CS, + CC2650STK_GPIO_LCD_CS, + CC2650STK_GPIO_LCD_ENABLE, - CC1350STK_GPIOCOUNT -} CC1350STK_GPIOName; + CC2650STK_GPIOCOUNT +} CC2650STK_GPIOName; /*! - * @def CC1350STK_GPTimerName + * @def CC2650STK_GPTimerName * @brief Enum of GPTimers parts */ -typedef enum CC1350STK_GPTimerName { - CC1350STK_GPTIMER0A = 0, - CC1350STK_GPTIMER0B, - CC1350STK_GPTIMER1A, - CC1350STK_GPTIMER1B, - CC1350STK_GPTIMER2A, - CC1350STK_GPTIMER2B, - CC1350STK_GPTIMER3A, - CC1350STK_GPTIMER3B, +typedef enum CC2650STK_GPTimerName { + CC2650STK_GPTIMER0A = 0, + CC2650STK_GPTIMER0B, + CC2650STK_GPTIMER1A, + CC2650STK_GPTIMER1B, + CC2650STK_GPTIMER2A, + CC2650STK_GPTIMER2B, + CC2650STK_GPTIMER3A, + CC2650STK_GPTIMER3B, - CC1350STK_GPTIMERPARTSCOUNT -} CC1350STK_GPTimerName; + CC2650STK_GPTIMERPARTSCOUNT +} CC2650STK_GPTimerName; /*! - * @def CC1350STK_GPTimers + * @def CC2650STK_GPTimers * @brief Enum of GPTimers */ -typedef enum CC1350STK_GPTimers { - CC1350STK_GPTIMER0 = 0, - CC1350STK_GPTIMER1, - CC1350STK_GPTIMER2, - CC1350STK_GPTIMER3, +typedef enum CC2650STK_GPTimers { + CC2650STK_GPTIMER0 = 0, + CC2650STK_GPTIMER1, + CC2650STK_GPTIMER2, + CC2650STK_GPTIMER3, - CC1350STK_GPTIMERCOUNT -} CC1350STK_GPTimers; + CC2650STK_GPTIMERCOUNT +} CC2650STK_GPTimers; /*! - * @def CC1350STK_I2CName + * @def CC2650STK_I2CName * @brief Enum of I2C names */ -typedef enum CC1350STK_I2CName { - CC1350STK_I2C0 = 0, +typedef enum CC2650STK_I2CName { + CC2650STK_I2C0 = 0, - CC1350STK_I2CCOUNT -} CC1350STK_I2CName; + CC2650STK_I2CCOUNT +} CC2650STK_I2CName; /*! - * @def CC1350STK_NVSName + * @def CC2650STK_NVSName * @brief Enum of NVS names */ -typedef enum CC1350STK_NVSName { - CC1350STK_NVSCC26XX0 = 0, - CC1350STK_NVSSPI25X0, +typedef enum CC2650STK_NVSName { + CC2650STK_NVSCC26XX0 = 0, + CC2650STK_NVSSPI25X0, - CC1350STK_NVSCOUNT -} CC1350STK_NVSName; + CC2650STK_NVSCOUNT +} CC2650STK_NVSName; /*! - * @def CC1350STK_PdmName + * @def CC2650STK_PdmName * @brief Enum of PDM names */ -typedef enum CC1350STK_PDMName { - CC1350STK_PDM0 = 0, +typedef enum CC2650STK_PDMName { + CC2650STK_PDM0 = 0, - CC1350STK_PDMCOUNT -} CC1350STK_PDMName; + CC2650STK_PDMCOUNT +} CC2650STK_PDMName; /*! - * @def CC1350STK_PWM + * @def CC2650STK_PWM * @brief Enum of PWM outputs */ -typedef enum CC1350STK_PWMName { - CC1350STK_PWM0 = 0, - CC1350STK_PWM1, - CC1350STK_PWM2, - CC1350STK_PWM3, - CC1350STK_PWM4, - CC1350STK_PWM5, - CC1350STK_PWM6, - CC1350STK_PWM7, +typedef enum CC2650STK_PWMName { + CC2650STK_PWM0 = 0, + CC2650STK_PWM1, + CC2650STK_PWM2, + CC2650STK_PWM3, + CC2650STK_PWM4, + CC2650STK_PWM5, + CC2650STK_PWM6, + CC2650STK_PWM7, - CC1350STK_PWMCOUNT -} CC1350STK_PWMName; + CC2650STK_PWMCOUNT +} CC2650STK_PWMName; /*! - * @def CC1350STK_SPIName + * @def CC2650STK_SPIName * @brief Enum of SPI names */ -typedef enum CC1350STK_SPIName { - CC1350STK_SPI0 = 0, - CC1350STK_SPI1, +typedef enum CC2650STK_SPIName { + CC2650STK_SPI0 = 0, + CC2650STK_SPI1, - CC1350STK_SPICOUNT -} CC1350STK_SPIName; + CC2650STK_SPICOUNT +} CC2650STK_SPIName; /*! - * @def CC1350STK_UARTName + * @def CC2650STK_UARTName * @brief Enum of UARTs */ -typedef enum CC1350STK_UARTName { - CC1350STK_UART0 = 0, +typedef enum CC2650STK_UARTName { + CC2650STK_UART0 = 0, - CC1350STK_UARTCOUNT -} CC1350STK_UARTName; + CC2650STK_UARTCOUNT +} CC2650STK_UARTName; /*! - * @def CC1350STK_UDMAName + * @def CC2650STK_UDMAName * @brief Enum of DMA buffers */ -typedef enum CC1350STK_UDMAName { - CC1350STK_UDMA0 = 0, +typedef enum CC2650STK_UDMAName { + CC2650STK_UDMA0 = 0, - CC1350STK_UDMACOUNT -} CC1350STK_UDMAName; + CC2650STK_UDMACOUNT +} CC2650STK_UDMAName; /*! - * @def CC1350STK_WatchdogName + * @def CC2650STK_WatchdogName * @brief Enum of Watchdogs */ -typedef enum CC1350STK_WatchdogName { - CC1350STK_WATCHDOG0 = 0, +typedef enum CC2650STK_WatchdogName { + CC2650STK_WATCHDOG0 = 0, - CC1350STK_WATCHDOGCOUNT -} CC1350STK_WatchdogName; + CC2650STK_WATCHDOGCOUNT +} CC2650STK_WatchdogName; #ifdef __cplusplus } #endif -#endif /* __CC1350STK_BOARD_H__ */ +#endif /* __CC2650STK_BOARD_H__ */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK_fxns.c index 1a56667da..3312a1702 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK_fxns.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK_fxns.c @@ -38,8 +38,9 @@ #include #include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/cpu.h) #include "Board.h" diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 index b3e796d82..5e1a70c88 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 @@ -6,6 +6,7 @@ DEVICE_FAMILY = CC26X0 DEVICE_LINE = CC26XX BOARD_SOURCEFILES += CC2650STK.c CC2650STK_fxns.c +BOARD_SOURCEFILES += leds-arch.c SUPPORTS_PROP_MODE = 0 SUPPORTS_IEEE_MODE = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/leds-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/leds-arch.c new file mode 100644 index 000000000..463349854 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/leds-arch.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup simplelink-platform + * @{ + * + * \file + * Driver for LaunchPad LEDs + */ +/*---------------------------------------------------------------------------*/ +/* Contiki API */ +#include +#include +/*---------------------------------------------------------------------------*/ +/* Simplelink SDK API */ +#include + +#include +/*---------------------------------------------------------------------------*/ +/* Standard library */ +#include +#include +/*---------------------------------------------------------------------------*/ +static const PIN_Config pin_table[] = { + Board_PIN_LED0 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, + Board_PIN_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, + PIN_TERMINATE +}; + +static PIN_State pin_state; +static PIN_Handle pin_handle; + +static volatile unsigned char c; +/*---------------------------------------------------------------------------*/ +void +leds_arch_init(void) +{ + static bool bHasInit = false; + if(bHasInit) { + return; + } + + // PIN_init() called from Board_initGeneral() + pin_handle = PIN_open(&pin_state, pin_table); + if (!pin_handle) { + return; + } + + bHasInit = true; +} +/*---------------------------------------------------------------------------*/ +unsigned char +leds_arch_get(void) +{ + return c; +} +/*---------------------------------------------------------------------------*/ +void +leds_arch_set(unsigned char leds) +{ + c = leds; + + PIN_setPortOutputValue(pin_handle, 0); + + if (leds & LEDS_RED) { + PIN_setOutputValue(pin_handle, Board_PIN_LED0, 1); + } + + if (leds & LEDS_GREEN) { + PIN_setOutputValue(pin_handle, Board_PIN_LED1, 1); + } +} +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag.c index 2f953e681..7f1e3b816 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag.c @@ -39,7 +39,6 @@ #include "contiki.h" /*---------------------------------------------------------------------------*/ #include "Board.h" -#include "ti/drivers/dpl/HwiP.h" #include "ti/drivers/GPIO.h" #include "ti/drivers/I2C.h" #include "ti/drivers/PIN.h" @@ -50,11 +49,8 @@ #include /*---------------------------------------------------------------------------*/ void -board_init() +board_init(void) { - /* Disable interrupts */ - const uintptr_t key = HwiP_disable(); - // Board_initGeneral() will call Power_init() // Board_initGeneral() will call PIN_init(BoardGpioInitTable) Board_initGeneral(); @@ -63,9 +59,6 @@ board_init() GPIO_init(); I2C_init(); SPI_init(); - - /* Restore interrupts. */ - HwiP_restore(key); } /*---------------------------------------------------------------------------*/ /** @} */ From 7b812e73c9bea2c115d3bee0382ce7155accc22a Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Thu, 7 Jun 2018 10:29:47 +0200 Subject: [PATCH 249/485] Fixed naming and alignment of RF settings, Watchdog driver, Board files --- arch/cpu/arm/Makefile.arm | 6 + arch/cpu/arm/cortex-m/cm3/Makefile.cm3 | 15 +- arch/cpu/arm/cortex-m/cm4/Makefile.cm4 | 7 +- .../cc13x0-cc26x0/cc13x0-cc26x0.lds | 6 +- .../cc13x2-cc26x2/cc13x2-cc26x2.lds | 5 +- arch/cpu/cc13xx-cc26xx/dev/ieee-addr.c | 16 +- arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c | 258 ++++++++++-------- arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c | 93 ++++--- .../dev/startup_cc13xx_cc26xx_gcc.c | 4 + arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c | 8 +- arch/cpu/cc13xx-cc26xx/dev/watchdog-arch.c | 75 ++--- .../rf-settings/cc13x0/ieee-settings.c | 36 +-- .../rf-settings/cc13x0/ieee-settings.h | 5 +- .../rf-settings/cc13x0/prop-settings.c | 4 +- .../rf-settings/cc13x2/ieee-settings.c | 8 +- .../rf-settings/cc13x2/ieee-settings.h | 3 +- .../rf-settings/cc13x2/prop-settings.c | 8 +- .../rf-settings/cc13x2/prop-settings.h | 2 +- .../rf-settings/cc26x0/ieee-settings.c | 4 +- .../rf-settings/cc26x0/ieee-settings.h | 1 + .../rf-settings/cc26x2/ieee-settings.c | 12 +- .../rf-settings/cc26x2/ieee-settings.h | 11 +- .../cc13xx-cc26xx/launchpad/cc1310/Board.h | 14 + .../cc13xx-cc26xx/launchpad/cc1312r1/Board.h | 14 + .../launchpad/cc1312r1/Makefile.cc1312r1 | 2 + .../cc13xx-cc26xx/launchpad/cc1350-4/Board.h | 14 + .../cc13xx-cc26xx/launchpad/cc1350/Board.h | 14 + .../launchpad/cc1350/CC1350_LAUNCHXL.c | 5 +- .../cc13xx-cc26xx/launchpad/cc1352p1/Board.h | 14 + .../launchpad/cc1352p1/Makefile.cc1352p1 | 3 + .../cc13xx-cc26xx/launchpad/cc1352p_2/Board.h | 14 + .../launchpad/cc1352p_2/Makefile.cc1352p_2 | 3 + .../cc13xx-cc26xx/launchpad/cc1352p_4/Board.h | 14 + .../launchpad/cc1352p_4/Makefile.cc1352p_4 | 3 + .../cc13xx-cc26xx/launchpad/cc1352r1/Board.h | 14 + .../launchpad/cc1352r1/Makefile.cc1352r1 | 3 + .../cc13xx-cc26xx/launchpad/cc2650/Board.h | 14 + .../cc13xx-cc26xx/launchpad/cc26x2r1/Board.h | 14 + .../cc13xx-cc26xx/launchpad/ext-flash.c | 50 +++- .../cc13xx-cc26xx/launchpad/leds-arch.c | 80 ++---- .../simplelink/cc13xx-cc26xx/platform.c | 39 +-- .../cc13xx-cc26xx/sensortag/sensortag.c | 8 - 42 files changed, 547 insertions(+), 376 deletions(-) diff --git a/arch/cpu/arm/Makefile.arm b/arch/cpu/arm/Makefile.arm index dd00aae6d..2c1a4bf7b 100644 --- a/arch/cpu/arm/Makefile.arm +++ b/arch/cpu/arm/Makefile.arm @@ -15,6 +15,12 @@ CFLAGS += -mthumb -mabi=aapcs -mlittle-endian CFLAGS += -Werror -Wall CFLAGS += -std=c99 CFLAGS += -ffunction-sections -fdata-sections -fno-strict-aliasing +# A weird behaviour of GCC garbage collection has been observed, where unitialized +# global variables put in the COMMON section weren't analyzed by the garbage collector +# at all. No idea why. The fix is to dissallow the common section, which subsequently +# places all unitialized global variables in the .bss section and enables the +# garbage collector to analyze the variables. +CFLAGS += -fno-common CFLAGS += -fshort-enums -fomit-frame-pointer -fno-builtin LDFLAGS += -mthumb -mlittle-endian diff --git a/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 b/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 index 934e233e6..29adac8e8 100644 --- a/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 +++ b/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 @@ -4,23 +4,28 @@ CFLAGS += -mcpu=cortex-m3 LDFLAGS += -mcpu=cortex-m3 -nostartfiles LDFLAGS += -T $(LDSCRIPT) -LDFLAGS += -Wl,--gc-sections,--sort-section=alignment -LDFLAGS += -Wl,-Map=$(CONTIKI_NG_PROJECT_MAP),--cref,--no-warn-mismatch +LDFLAGS += -Wl,--gc-sections +LDFLAGS += -Wl,--sort-section=alignment +LDFLAGS += -Wl,-Map=$(@:.elf=-$(TARGET).map) +LDFLAGS += -Wl,--cref +LDFLAGS += -Wl,--no-warn-mismatch + +TARGET_LIBFLAGS := -Wl,--start-group $(TARGET_LIBFILES) -lc -lgcc -lm -lnosys -Wl,--end-group OBJCOPY_FLAGS += --gap-fill 0xff ### Build syscalls for newlib MODULES += os/lib/newlib -CPU_STARTFILES = ${addprefix $(OBJECTDIR)/,${call oname, $(CPU_START_SOURCEFILES)}} +CPU_STARTFILES := ${addprefix $(OBJECTDIR)/,${call oname, $(CPU_START_SOURCEFILES)}} ### Compilation rules CUSTOM_RULE_LINK = 1 .SECONDEXPANSION: -%.elf: $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(LDSCRIPT) +%.elf: $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(TRACE_LD) - $(Q)$(LD) $(LDFLAGS) ${filter-out $(LDSCRIPT) %.a,$^} ${filter %.a,$^} $(TARGET_LIBFILES) -lm -o $@ + $(Q)$(LD) $(LDFLAGS) ${filter %.o %.a,$^} $(TARGET_LIBFLAGS) -o $@ include $(CONTIKI)/arch/cpu/arm/cortex-m/Makefile.cortex-m diff --git a/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 b/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 index 886b33ad4..180c5cd5a 100644 --- a/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 +++ b/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 @@ -4,8 +4,11 @@ CFLAGS += -mcpu=cortex-m4 LDFLAGS += -mcpu=cortex-m4 -nostartfiles LDFLAGS += -T $(LDSCRIPT) -LDFLAGS += -Wl,--gc-sections,--sort-section=alignment -LDFLAGS += -Wl,-Map=$(@:.elf=-$(TARGET).map),--cref,--no-warn-mismatch +LDFLAGS += -Wl,--gc-sections +LDFLAGS += -Wl,--sort-section=alignment +LDFLAGS += -Wl,-Map=$(@:.elf=-$(TARGET).map) +LDFLAGS += -Wl,--cref +LDFLAGS += -Wl,--no-warn-mismatch TARGET_LIBFLAGS := -Wl,--start-group $(TARGET_LIBFILES) -lc -lgcc -lm -lnosys -Wl,--end-group diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds index 594779b1b..0e8e66510 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds +++ b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds @@ -34,7 +34,7 @@ * Default Linker script for the Texas Instruments CC1310 */ -STACKSIZE = 1024; +MIN_STACKSIZE = 0x600; HEAPSIZE = 256; MEMORY @@ -46,6 +46,7 @@ MEMORY */ FLASH_CCFG (RX) : ORIGIN = 0x0001ffa8, LENGTH = 0x00000058 SRAM (RWX) : ORIGIN = 0x20000000, LENGTH = 0x00005000 + GPRAM (RWX) : ORIGIN = 0x11000000, LENGTH = 0x00002000 } REGION_ALIAS("REGION_TEXT", FLASH); @@ -192,6 +193,8 @@ SECTIONS { __HeapLimit = __heap_end__; } > REGION_HEAP AT> REGION_HEAP + PROVIDE(STACKSIZE = ORIGIN(SRAM) + LENGTH(SRAM) - ALIGN(0x8)); + .stack (NOLOAD) : ALIGN(0x8) { _stack = .; __stack = .; @@ -199,5 +202,6 @@ SECTIONS { . += STACKSIZE; _stack_end = .; __stack_end = .; + ASSERT(STACKSIZE >= MIN_STACKSIZE, "Error: No room left for the stack"); } > REGION_STACK AT> REGION_STACK } diff --git a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds index 91c5e1bd0..9da90ebcd 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds +++ b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds @@ -34,7 +34,7 @@ * Default Linker script for the Texas Instruments CC1352 */ -STACKSIZE = 1024; +MIN_STACKSIZE = 0x600; HEAPSIZE = 256; /* Size of heap buffer used by HeapMem */ MEMORY @@ -193,6 +193,8 @@ SECTIONS { __HeapLimit = __heap_end__; } > REGION_HEAP AT> REGION_HEAP + PROVIDE(STACKSIZE = ORIGIN(SRAM) + LENGTH(SRAM) - ALIGN(0x8)); + .stack (NOLOAD) : ALIGN(0x8) { _stack = .; __stack = .; @@ -200,5 +202,6 @@ SECTIONS { . += STACKSIZE; _stack_end = .; __stack_end = .; + ASSERT(STACKSIZE >= MIN_STACKSIZE, "Error: No room left for the stack"); } > REGION_STACK AT> REGION_STACK } diff --git a/arch/cpu/cc13xx-cc26xx/dev/ieee-addr.c b/arch/cpu/cc13xx-cc26xx/dev/ieee-addr.c index 144240cc4..b28d7ab9c 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/ieee-addr.c +++ b/arch/cpu/cc13xx-cc26xx/dev/ieee-addr.c @@ -40,10 +40,18 @@ #include "contiki.h" #include "net/linkaddr.h" #include "ieee-addr.h" - +/*---------------------------------------------------------------------------*/ +#include +#include DeviceFamily_constructPath(inc/hw_memmap.h) +#include DeviceFamily_constructPath(inc/hw_fcfg1.h) +#include DeviceFamily_constructPath(inc/hw_ccfg.h) +/*---------------------------------------------------------------------------*/ #include #include /*---------------------------------------------------------------------------*/ +#define IEEE_MAC_PRIMARY_ADDRESS (FCFG1_BASE + FCFG1_O_MAC_15_4_0) +#define IEEE_MAC_SECONDARY_ADDRESS (CCFG_BASE + CCFG_O_IEEE_MAC_0) +/*---------------------------------------------------------------------------*/ void ieee_addr_cpy_to(uint8_t *dst, uint8_t len) { @@ -55,7 +63,7 @@ ieee_addr_cpy_to(uint8_t *dst, uint8_t len) int i; /* Reading from primary location... */ - uint8_t *location = (uint8_t *)IEEE_ADDR_LOCATION_PRIMARY; + const uint8_t *location = (uint8_t *)IEEE_MAC_PRIMARY_ADDRESS; /* * ...unless we can find a byte != 0xFF in secondary @@ -65,9 +73,9 @@ ieee_addr_cpy_to(uint8_t *dst, uint8_t len) * actual number of bytes the caller wants to copy over. */ for(i = 0; i < 8; i++) { - if(((uint8_t *)IEEE_ADDR_LOCATION_SECONDARY)[i] != 0xFF) { + if(((uint8_t *)IEEE_MAC_SECONDARY_ADDRESS)[i] != 0xFF) { /* A byte in the secondary location is not 0xFF. Use the secondary */ - location = (uint8_t *)IEEE_ADDR_LOCATION_SECONDARY; + location = (uint8_t *)IEEE_MAC_SECONDARY_ADDRESS; break; } } diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c index 8d8c16e47..08e95a983 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c @@ -51,11 +51,16 @@ #include "sys/cc.h" /*---------------------------------------------------------------------------*/ /* RF driver and RF Core API */ -#include -#include -#include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_data_entry.h) +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +// rf_ieee_cmd and rf_ieee_mailbox included by RF settings because of the +// discrepancy between CC13x0 and CC13x2 IEEE support. CC13x0 doesn't provide +// RFCore definitions of IEEE commandos, and are therefore included locally +// from the Contiki build system. CC13x2 includes these normally from driverlib. +// This is taken care of RF settings. + #include /*---------------------------------------------------------------------------*/ /* SimpleLink Platform RF dev */ @@ -120,8 +125,8 @@ #endif /* Configuration for TX power table */ -#ifdef TX_POWER_CONF_TABLE -# define TX_POWER_TABLE TX_POWER_CONF_TABLE +#ifdef IEEE_MODE_CONF_TX_POWER_TABLE +# define TX_POWER_TABLE IEEE_MODE_CONF_TX_POWER_TABLE #else # define TX_POWER_TABLE ieeeTxPowerTable #endif @@ -143,7 +148,7 @@ #define IEEE_MODE_CHAN_MIN 11 #define IEEE_MODE_CHAN_MAX 26 -#define IEEE_MODE_CHAN_IN_RANGE(ch) (((ch) >= IEEE_MODE_CHAN_MIN) && ((ch) <= IEEE_MODE_CHAN_MAX)) +#define IEEE_MODE_CHAN_IN_RANGE(ch) ((IEEE_MODE_CHAN_MIN <= (ch)) && ((ch) <= IEEE_MODE_CHAN_MAX)) /* Sanity check of default IEEE channel */ #if !IEEE_MODE_CHAN_IN_RANGE(IEEE_MODE_CHANNEL) @@ -172,10 +177,10 @@ static RF_Object g_rfObj; static RF_Handle g_rfHandle; /* RF Core command pointers */ -static volatile rfc_CMD_RADIO_SETUP_t *g_vpCmdRadioSetup = &RF_cmdRadioSetup; -static volatile rfc_CMD_FS_t *g_vpCmdFs = &RF_cmdIeeeFs; -static volatile rfc_CMD_IEEE_TX_t *g_vpCmdTx = &RF_cmdIeeeTx; -static volatile rfc_CMD_IEEE_RX_t *g_vpCmdRx = &RF_cmdIeeeRx; +#define cmd_radio_setup ((volatile rfc_CMD_RADIO_SETUP_t*)&RF_cmdRadioSetup) +#define cmd_fs ((volatile rfc_CMD_FS_t*) &RF_cmdIeeeFs) +#define cmd_tx ((volatile rfc_CMD_IEEE_TX_t*) &RF_cmdIeeeTx) +#define cmd_rx ((volatile rfc_CMD_IEEE_RX_t*) &RF_cmdIeeeRx) /* RF command handles */ static RF_CmdHandle g_cmdTxHandle; @@ -231,12 +236,6 @@ static volatile uint32_t g_ratOverflowCount; /*---------------------------------------------------------------------------*/ /* Global state */ -/* Current RX channel */ -static volatile uint8_t g_currChannel; - -/* Current TX power */ -static volatile RF_TxPower *g_pCurrTxPower; - /* Are we currently in poll mode? */ static volatile bool g_bPollMode = false; @@ -251,7 +250,7 @@ static volatile uint32_t g_lastTimestamp; typedef enum { POWER_STATE_ON = (1 << 0), POWER_STATE_OFF = (1 << 1), - POWER_STATE_RESTART = (1 << 2), + POWER_STATE_RESTART = POWER_STATE_ON | POWER_STATE_OFF, } PowerState; /*---------------------------------------------------------------------------*/ /* Forward declarations of static functions */ @@ -310,9 +309,11 @@ rf_error_cb(RF_Handle h, RF_CmdHandle ch, RF_EventMask e) { // See SWRZ062B: Synth failed to calibrate, CMD_FS must be repeated if ((ch == RF_ERROR_CMDFS_SYNTH_PROG) && - (g_vpCmdFs->status == ERROR_SYNTH_PROG)) { + (cmd_fs->status == ERROR_SYNTH_PROG)) { // Call CMD_FS async, a synth error will trigger rf_error_cb once more - RF_postCmd(g_rfHandle, (RF_Op*)g_vpCmdFs, RF_PriorityNormal, NULL, 0); + const uint8_t stop_gracefully = 1; + RF_flushCmd(g_rfHandle, RF_CMDHANDLE_FLUSH_ALL, stop_gracefully); + RF_postCmd(g_rfHandle, (RF_Op*)cmd_fs, RF_PriorityNormal, NULL, 0); } } /*---------------------------------------------------------------------------*/ @@ -338,22 +339,22 @@ init_data_queue(void) static void init_rf_params(void) { - g_vpCmdRx->pRxQ = &g_rxDataQueue; - g_vpCmdRx->pOutput = &g_rxStats; + cmd_rx->pRxQ = &g_rxDataQueue; + cmd_rx->pOutput = &g_rxStats; #if IEEE_MODE_PROMISCOUS - g_vpCmdRx->frameFiltOpt.frameFiltEn = 0; + cmd_rx->frameFiltOpt.frameFiltEn = 0; #else - g_vpCmdRx->frameFiltOpt.frameFiltEn = 1; + cmd_rx->frameFiltOpt.frameFiltEn = 1; #endif #if IEEE_MODE_AUTOACK - g_vpCmdRx->frameFiltOpt.autoAckEn = 1; + cmd_rx->frameFiltOpt.autoAckEn = 1; #else - g_vpCmdRx->frameFiltOpt.autoAckEn = 0; + cmd_rx->frameFiltOpt.autoAckEn = 0; #endif - g_vpCmdRx->ccaRssiThr = IEEE_MODE_RSSI_THRESHOLD; + cmd_rx->ccaRssiThr = IEEE_MODE_RSSI_THRESHOLD; // Initialize address filter command g_cmdModFilt.commandNo = CMD_IEEE_MOD_FILT; @@ -364,28 +365,28 @@ init_rf_params(void) static void init_rx_buffers(void) { -#define getEntry(n) (&(g_rxBufs[(n)].dataEntry)) +#define GET_ENTRY(n) (&(g_rxBufs[(n)].dataEntry)) rfc_dataEntry_t *entry = NULL; - const uint16_t length = sizeof(g_rxBufs[0].buf) - 8; + const size_t length = sizeof(g_rxBufs[0].buf) - 8; size_t i; for (i = 0; i < (size_t)(RX_BUF_ENTRIES - 1); ++i) { - entry = getEntry(i); - entry->pNextEntry = (uint8_t*)getEntry(i + 1); + entry = GET_ENTRY(i); + entry->pNextEntry = (uint8_t*)GET_ENTRY(i + 1); entry->config.lenSz = DATA_ENTRY_LENSZ_BYTE; - entry->length = length; + entry->length = (uint16_t)length; } - entry = getEntry(RX_BUF_ENTRIES - 1); - entry->pNextEntry = (uint8_t*)getEntry(0); + entry = GET_ENTRY(RX_BUF_ENTRIES - 1); + entry->pNextEntry = (uint8_t*)GET_ENTRY(0); entry->config.lenSz = DATA_ENTRY_LENSZ_BYTE; - entry->length = length; + entry->length = (uint16_t)length; #undef getEntry } /*---------------------------------------------------------------------------*/ -static void +static bool set_channel(uint8_t channel) { if (!IEEE_MODE_CHAN_IN_RANGE(channel)) { @@ -393,41 +394,62 @@ set_channel(uint8_t channel) channel, IEEE_MODE_CHANNEL); channel = IEEE_MODE_CHANNEL; } - if (channel == g_currChannel) { + if (channel == cmd_rx->channel) { // We are already calibrated to this channel - return; + return true; } - g_currChannel = channel; + + cmd_rx->channel = 0; + // freq = freq_base + freq_spacing * (channel - channel_min) - const uint32_t newFreq = (uint32_t)IEEE_MODE_FREQ_BASE + - (uint32_t)IEEE_MODE_FREQ_SPACING * ((uint32_t)channel - (uint32_t)IEEE_MODE_CHAN_MIN); - const uint16_t freq = (uint16_t)(newFreq / 1000); - const uint16_t frac = (uint16_t)((newFreq - (freq * 1000)) * 65536 / 1000); + const uint32_t newFreq = (uint32_t)(IEEE_MODE_FREQ_BASE + IEEE_MODE_FREQ_SPACING * ((uint32_t)channel - IEEE_MODE_CHAN_MIN)); + const uint32_t freq = newFreq / 1000; + const uint32_t frac = (newFreq - (freq * 1000)) * 65536 / 1000; PRINTF("set_channel: %d = 0x%04X.0x%04X (%lu)\n", - channel, freq, frac, newFreq); + channel, (uint16_t)freq, (uint16_t)frac, newFreq); - g_vpCmdFs->frequency = freq; - g_vpCmdFs->fractFreq = frac; + cmd_fs->frequency = (uint16_t)freq; + cmd_fs->fractFreq = (uint16_t)frac; + + const bool rx_active = (cmd_rx->status == ACTIVE); + + if (rx_active) { + const uint8_t stop_gracefully = 1; + RF_flushCmd(g_rfHandle, RF_CMDHANDLE_FLUSH_ALL, stop_gracefully); + } // Start FS command asynchronously. We don't care when it is finished - RF_postCmd(g_rfHandle, (RF_Op*)g_vpCmdFs, RF_PriorityNormal, NULL, 0); - if (g_vpCmdRx->status == ACTIVE) { - set_rx(POWER_STATE_RESTART); + RF_EventMask events = 0; + uint8_t tries = 0; + bool cmd_ok = false; + do { + events = RF_runCmd(g_rfHandle, (RF_Op*)cmd_fs, RF_PriorityNormal, NULL, 0); + cmd_ok = ((events & RF_EventLastCmdDone) != 0) + && (cmd_fs->status == DONE_OK); + } while (!cmd_ok && (tries++ < 3)); + + if (!cmd_ok) { + return false; } + + cmd_rx->channel = channel; + + if (rx_active) { + set_rx(POWER_STATE_ON); + } + + return true; } /*---------------------------------------------------------------------------*/ static int set_tx_power(const radio_value_t dbm) { - const RF_TxPowerTable_Value txPowerTableValue = RF_TxPowerTable_findValue(TX_POWER_TABLE, (int8_t)dbm); - if (txPowerTableValue.rawValue == RF_TxPowerTable_INVALID_VALUE) { - return CMD_RESULT_ERROR; - } + const RF_TxPowerTable_Value tx_power_table_value = RF_TxPowerTable_findValue(TX_POWER_TABLE, (int8_t)dbm); + const RF_Stat stat = RF_setTxPower(g_rfHandle, tx_power_table_value); - const RF_Stat stat = RF_setTxPower(g_rfHandle, txPowerTableValue); if (stat != RF_StatSuccess) { - PRINTF("RF_setTxPower: stat=0x%02X\n", stat); + PRINTF("set_tx_power: stat=0x%02X\n", stat); return CMD_RESULT_ERROR; } return CMD_RESULT_OK; @@ -436,9 +458,14 @@ set_tx_power(const radio_value_t dbm) static radio_value_t get_tx_power(void) { - return (g_pCurrTxPower) - ? g_pCurrTxPower->power - : (radio_value_t)TX_POWER_UNKNOWN; + const RF_TxPowerTable_Value tx_power_table_value = RF_getTxPower(g_rfHandle); + const int8_t dbm = RF_TxPowerTable_findPowerLevel(TX_POWER_TABLE, tx_power_table_value); + + if (dbm == RF_TxPowerTable_INVALID_DBM) { + PRINTF("get_tx_power: invalid dbm received=%d\n", dbm); + } + + return (radio_value_t)dbm; } /*---------------------------------------------------------------------------*/ static void @@ -505,14 +532,12 @@ init(void) { RF_Params params; RF_Params_init(¶ms); - // Disable automatic power-down just to not interfere with stack timing - params.nInactivityTimeout = 0; params.pErrCb = rf_error_cb; init_rf_params(); init_data_queue(); - g_rfHandle = RF_open(&g_rfObj, &RF_ieeeMode, (RF_RadioSetup*)g_vpCmdRadioSetup, ¶ms); + g_rfHandle = RF_open(&g_rfObj, &RF_ieeeMode, (RF_RadioSetup*)cmd_radio_setup, ¶ms); assert(g_rfHandle != NULL); set_channel(IEEE_MODE_CHANNEL); @@ -552,26 +577,23 @@ rf_is_on(void) static int set_rx(const PowerState state) { - if (state & (POWER_STATE_OFF | POWER_STATE_RESTART)) { + if (state & POWER_STATE_OFF) { // Stop RX gracefully, don't care about the result - const uint8_t stopGracefully = 1; - RF_cancelCmd(g_rfHandle, g_cmdRxHandle, stopGracefully); + const uint8_t stop_gracefully = 1; + RF_cancelCmd(g_rfHandle, g_cmdRxHandle, stop_gracefully); } - if (state & (POWER_STATE_ON | POWER_STATE_RESTART)) { - if (g_vpCmdRx->status == ACTIVE) { + if (state & POWER_STATE_ON) { + if (cmd_rx->status == ACTIVE) { PRINTF("set_rx(on): already in RX\n"); return CMD_RESULT_OK; } - RF_ScheduleCmdParams schedParams = { - .endTime = 0, - .priority = RF_PriorityNormal, - //.bIeeeBgCmd = true, - }; + RF_ScheduleCmdParams schedParams; + RF_ScheduleCmdParams_init(&schedParams); - g_vpCmdRx->status = IDLE; - g_cmdRxHandle = RF_scheduleCmd(g_rfHandle, (RF_Op*)g_vpCmdRx, &schedParams, rx_cb, + cmd_rx->status = IDLE; + g_cmdRxHandle = RF_scheduleCmd(g_rfHandle, (RF_Op*)cmd_rx, &schedParams, rx_cb, RF_EventRxOk | RF_EventRxBufFull | RF_EventRxEntryDone); if ((g_cmdRxHandle == RF_ALLOC_ERROR) || (g_cmdRxHandle == RF_SCHEDULE_CMD_ERROR)) { PRINTF("transmit: unable to allocate RX command\n"); @@ -586,25 +608,22 @@ static int transmit_aux(unsigned short transmit_len) { // Configure TX command - g_vpCmdTx->payloadLen = (uint8_t)transmit_len; - g_vpCmdTx->pPayload = &g_txBuf[TX_BUF_HDR_LEN]; - g_vpCmdTx->startTime = 0; - g_vpCmdTx->startTrigger.triggerType = TRIG_NOW; + cmd_tx->payloadLen = (uint8_t)transmit_len; + cmd_tx->pPayload = &g_txBuf[TX_BUF_HDR_LEN]; + cmd_tx->startTime = 0; + cmd_tx->startTrigger.triggerType = TRIG_NOW; - RF_ScheduleCmdParams schedParams = { - .endTime = 0, - .priority = RF_PriorityNormal, - //.bIeeeBgCmd = false, - }; + RF_ScheduleCmdParams schedParams; + RF_ScheduleCmdParams_init(&schedParams); // As IEEE_TX is a FG command, the TX operation will be executed // either way if RX is running or not - g_vpCmdTx->status = IDLE; - g_cmdTxHandle = RF_scheduleCmd(g_rfHandle, (RF_Op*)g_vpCmdTx, &schedParams, NULL, 0); + cmd_tx->status = IDLE; + g_cmdTxHandle = RF_scheduleCmd(g_rfHandle, (RF_Op*)cmd_tx, &schedParams, NULL, 0); if ((g_cmdTxHandle == RF_ALLOC_ERROR) || (g_cmdTxHandle == RF_SCHEDULE_CMD_ERROR)) { // Failure sending the CMD_IEEE_TX command PRINTF("transmit: failed to allocate TX command cmdHandle=%d, status=%04x\n", - g_cmdTxHandle, g_vpCmdTx->status); + g_cmdTxHandle, cmd_tx->status); return RADIO_TX_ERR; } @@ -614,7 +633,7 @@ transmit_aux(unsigned short transmit_len) RF_EventMask events = RF_pendCmd(g_rfHandle, g_cmdTxHandle, 0); if ((events & (RF_EventFGCmdDone | RF_EventLastFGCmdDone)) == 0) { PRINTF("transmit: TX command error events=0x%08llx, status=0x%04x\n", - events, g_vpCmdTx->status); + events, cmd_tx->status); return RADIO_TX_ERR; } @@ -624,7 +643,7 @@ transmit_aux(unsigned short transmit_len) static int transmit(unsigned short transmit_len) { - const bool was_rx = (g_vpCmdRx->status == ACTIVE); + const bool was_rx = (cmd_rx->status == ACTIVE); if (g_bSendOnCca && channel_clear() != 1) { PRINTF("transmit: channel wasn't clear\n"); @@ -734,7 +753,7 @@ channel_clear_aux(void) static int channel_clear(void) { - const bool was_rx = (g_vpCmdRx->status == ACTIVE); + const bool was_rx = (cmd_rx->status == ACTIVE); if (!was_rx && set_rx(POWER_STATE_ON) != CMD_RESULT_OK) { PRINTF("channel_clear: unable to start RX\n"); return CHANNEL_CLEAR_ERROR; @@ -752,7 +771,7 @@ static int receiving_packet(void) { // If we are not in RX, we are not receiving - if (g_vpCmdRx->status != ACTIVE) { + if (cmd_rx->status != ACTIVE) { PRINTF("receiving_packet: not in RX\n"); return 0; } @@ -854,23 +873,23 @@ get_value(radio_param_t param, radio_value_t *value) return RADIO_RESULT_OK; case RADIO_PARAM_CHANNEL: - *value = (radio_value_t)g_currChannel; + *value = (radio_value_t)cmd_rx->channel; return RADIO_RESULT_OK; case RADIO_PARAM_PAN_ID: - *value = (radio_value_t)g_vpCmdRx->localPanID; + *value = (radio_value_t)cmd_rx->localPanID; return RADIO_RESULT_OK; case RADIO_PARAM_16BIT_ADDR: - *value = (radio_value_t)g_vpCmdRx->localShortAddr; + *value = (radio_value_t)cmd_rx->localShortAddr; return RADIO_RESULT_OK; case RADIO_PARAM_RX_MODE: *value = 0; - if (g_vpCmdRx->frameFiltOpt.frameFiltEn) { + if (cmd_rx->frameFiltOpt.frameFiltEn) { *value |= (radio_value_t)RADIO_RX_MODE_ADDRESS_FILTER; } - if (g_vpCmdRx->frameFiltOpt.autoAckEn) { + if (cmd_rx->frameFiltOpt.autoAckEn) { *value |= (radio_value_t)RADIO_RX_MODE_AUTOACK; } if (g_bPollMode) { @@ -889,7 +908,7 @@ get_value(radio_param_t param, radio_value_t *value) : RADIO_RESULT_OK; case RADIO_PARAM_CCA_THRESHOLD: - *value = g_vpCmdRx->ccaRssiThr; + *value = cmd_rx->ccaRssiThr; return RADIO_RESULT_OK; case RADIO_PARAM_RSSI: @@ -930,24 +949,21 @@ get_value(radio_param_t param, radio_value_t *value) static radio_result_t set_value(radio_param_t param, radio_value_t value) { - switch(param) { + switch (param) { case RADIO_PARAM_POWER_MODE: - switch (value) { - case RADIO_POWER_MODE_ON: + if (value == RADIO_POWER_MODE_ON) { if (on() != CMD_RESULT_OK) { PRINTF("set_value: on() failed (1)\n"); return RADIO_RESULT_ERROR; } return RADIO_RESULT_OK; - - case RADIO_POWER_MODE_OFF: + } else if (value == RADIO_POWER_MODE_OFF) { off(); return RADIO_RESULT_OK; - - default: - return RADIO_RESULT_INVALID_VALUE; } + return RADIO_RESULT_INVALID_VALUE; + case RADIO_PARAM_CHANNEL: if (!IEEE_MODE_CHAN_IN_RANGE(value)) { return RADIO_RESULT_INVALID_VALUE; @@ -956,7 +972,7 @@ set_value(radio_param_t param, radio_value_t value) return RADIO_RESULT_OK; case RADIO_PARAM_PAN_ID: - g_vpCmdRx->localPanID = (uint16_t)value; + cmd_rx->localPanID = (uint16_t)value; if (rf_is_on() && set_rx(POWER_STATE_RESTART) != CMD_RESULT_OK) { PRINTF("failed to restart RX"); return RADIO_RESULT_ERROR; @@ -964,7 +980,7 @@ set_value(radio_param_t param, radio_value_t value) return RADIO_RESULT_OK; case RADIO_PARAM_16BIT_ADDR: - g_vpCmdRx->localShortAddr = (uint16_t)value; + cmd_rx->localShortAddr = (uint16_t)value; if (rf_is_on() && set_rx(POWER_STATE_RESTART) != CMD_RESULT_OK) { PRINTF("failed to restart RX"); return RADIO_RESULT_ERROR; @@ -977,15 +993,15 @@ set_value(radio_param_t param, radio_value_t value) return RADIO_RESULT_INVALID_VALUE; } - g_vpCmdRx->frameFiltOpt.frameFiltEn = (value & RADIO_RX_MODE_ADDRESS_FILTER) != 0; - g_vpCmdRx->frameFiltOpt.frameFiltStop = 1; - g_vpCmdRx->frameFiltOpt.autoAckEn = (value & RADIO_RX_MODE_AUTOACK) != 0; - g_vpCmdRx->frameFiltOpt.slottedAckEn = 0; - g_vpCmdRx->frameFiltOpt.autoPendEn = 0; - g_vpCmdRx->frameFiltOpt.defaultPend = 0; - g_vpCmdRx->frameFiltOpt.bPendDataReqOnly = 0; - g_vpCmdRx->frameFiltOpt.bPanCoord = 0; - g_vpCmdRx->frameFiltOpt.bStrictLenFilter = 0; + cmd_rx->frameFiltOpt.frameFiltEn = (value & RADIO_RX_MODE_ADDRESS_FILTER) != 0; + cmd_rx->frameFiltOpt.frameFiltStop = 1; + cmd_rx->frameFiltOpt.autoAckEn = (value & RADIO_RX_MODE_AUTOACK) != 0; + cmd_rx->frameFiltOpt.slottedAckEn = 0; + cmd_rx->frameFiltOpt.autoPendEn = 0; + cmd_rx->frameFiltOpt.defaultPend = 0; + cmd_rx->frameFiltOpt.bPendDataReqOnly = 0; + cmd_rx->frameFiltOpt.bPanCoord = 0; + cmd_rx->frameFiltOpt.bStrictLenFilter = 0; const bool bOldPollMode = g_bPollMode; g_bPollMode = (value & RADIO_RX_MODE_POLL_MODE) != 0; @@ -1022,7 +1038,7 @@ set_value(radio_param_t param, radio_value_t value) : RADIO_RESULT_OK; case RADIO_PARAM_CCA_THRESHOLD: - g_vpCmdRx->ccaRssiThr = (int8_t)value; + cmd_rx->ccaRssiThr = (int8_t)value; if (rf_is_on() && set_rx(POWER_STATE_RESTART) != CMD_RESULT_OK) { PRINTF("failed to restart RX"); return RADIO_RESULT_ERROR; @@ -1043,12 +1059,12 @@ get_object(radio_param_t param, void *dest, size_t size) switch (param) { case RADIO_PARAM_64BIT_ADDR: { - const size_t srcSize = sizeof(g_vpCmdRx->localExtAddr); + const size_t srcSize = sizeof(cmd_rx->localExtAddr); if(size != srcSize) { return RADIO_RESULT_INVALID_VALUE; } - const uint8_t *pSrc = (const uint8_t *)&g_vpCmdRx->localExtAddr; + const uint8_t *pSrc = (uint8_t *)&(cmd_rx->localExtAddr); uint8_t *pDest = dest; for(size_t i = 0; i < srcSize; ++i) { pDest[i] = pSrc[srcSize - 1 - i]; @@ -1079,18 +1095,18 @@ set_object(radio_param_t param, const void *src, size_t size) switch (param) { case RADIO_PARAM_64BIT_ADDR: { - const size_t destSize = sizeof(g_vpCmdRx->localExtAddr); + const size_t destSize = sizeof(cmd_rx->localExtAddr); if (size != destSize) { return RADIO_RESULT_INVALID_VALUE; } const uint8_t *pSrc = (const uint8_t *)src; - uint8_t *pDest = (uint8_t *)&g_vpCmdRx->localExtAddr; + uint8_t *pDest = (uint8_t *)&cmd_rx->localExtAddr; for (size_t i = 0; i < destSize; ++i) { pDest[i] = pSrc[destSize - 1 - i]; } - const bool is_rx = (g_vpCmdRx->status == ACTIVE); + const bool is_rx = (cmd_rx->status == ACTIVE); if (is_rx && set_rx(POWER_STATE_RESTART) != CMD_RESULT_OK) { return RADIO_RESULT_ERROR; } diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c index 26c2a3637..be893e8bc 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c @@ -165,8 +165,8 @@ static rfc_propRxOutput_t rx_stats; #define ENTER_RX_WAIT_TIMEOUT (RTIMER_SECOND >> 10) /*---------------------------------------------------------------------------*/ /* Configuration for TX power table */ -#ifdef TX_POWER_CONF_TABLE -# define TX_POWER_TABLE TX_POWER_CONF_TABLE +#ifdef PROP_MODE_CONF_TX_POWER_TABLE +# define TX_POWER_TABLE PROP_MODE_CONF_TX_POWER_TABLE #else # define TX_POWER_TABLE propTxPowerTable #endif @@ -209,18 +209,18 @@ volatile static uint8_t *rx_read_entry; static uint8_t tx_buf[TX_BUF_HDR_LEN + TX_BUF_PAYLOAD_LEN] CC_ALIGN(4); /*---------------------------------------------------------------------------*/ -volatile static rfc_CMD_PROP_RADIO_DIV_SETUP_t *gvp_cmd_radio_div_setup = &RF_cmdPropRadioDivSetup; -volatile static rfc_CMD_FS_t *gvp_cmd_fs = &RF_cmdPropFs; -volatile static rfc_CMD_PROP_TX_ADV_t *gvp_cmd_tx_adv = &RF_cmdPropTxAdv; -volatile static rfc_CMD_PROP_RX_ADV_t *gvp_cmd_rx_adv = &RF_cmdPropRxAdv; +#define cmd_radio_setup ((volatile rfc_CMD_PROP_RADIO_DIV_SETUP_t *)&RF_cmdPropRadioDivSetup) +#define cmd_fs ((volatile rfc_CMD_FS_t *)&RF_cmdPropFs) +#define cmd_tx ((volatile rfc_CMD_PROP_TX_ADV_t *)&RF_cmdPropTxAdv) +#define cmd_rx ((volatile rfc_CMD_PROP_RX_ADV_t *)&RF_cmdPropRxAdv) /*---------------------------------------------------------------------------*/ /* RF driver */ static RF_Object rfObject; static RF_Handle rfHandle; /*---------------------------------------------------------------------------*/ -static inline bool rf_is_transmitting(void) { return gvp_cmd_tx_adv->status == ACTIVE; } -static inline bool rf_is_receiving(void) { return gvp_cmd_rx_adv->status == ACTIVE; } -static inline bool rf_is_on(void) { return rf_is_transmitting() || rf_is_receiving(); } +static CC_INLINE bool rf_is_transmitting(void) { return cmd_tx->status == ACTIVE; } +static CC_INLINE bool rf_is_receiving(void) { return cmd_rx->status == ACTIVE; } +static CC_INLINE bool rf_is_on(void) { return rf_is_transmitting() || rf_is_receiving(); } /*---------------------------------------------------------------------------*/ static void rf_rx_callback(RF_Handle client, RF_CmdHandle command, RF_EventMask events) @@ -233,15 +233,15 @@ rf_rx_callback(RF_Handle client, RF_CmdHandle command, RF_EventMask events) static CmdResult rf_start_rx() { - gvp_cmd_rx_adv->status = IDLE; + cmd_rx->status = IDLE; /* * Set the max Packet length. This is for the payload only, therefore * 2047 - length offset */ - gvp_cmd_rx_adv->maxPktLen = DOT_4G_MAX_FRAME_LEN - gvp_cmd_rx_adv->lenOffset; + cmd_rx->maxPktLen = DOT_4G_MAX_FRAME_LEN - cmd_rx->lenOffset; - RF_CmdHandle rxCmdHandle = RF_postCmd(rfHandle, (RF_Op*)gvp_cmd_rx_adv, RF_PriorityNormal, + RF_CmdHandle rxCmdHandle = RF_postCmd(rfHandle, (RF_Op*)cmd_rx, RF_PriorityNormal, &rf_rx_callback, RF_EventRxEntryDone); if (rxCmdHandle == RF_ALLOC_ERROR) { return CMD_RESULT_ERROR; @@ -254,7 +254,7 @@ rf_start_rx() if (!rf_is_receiving()) { PRINTF("RF_cmdPropRxAdv: handle=0x%08lx, status=0x%04x\n", - (unsigned long)rxCmdHandle, gvp_cmd_rx_adv->status); + (unsigned long)rxCmdHandle, cmd_rx->status); rf_switch_off(); return CMD_RESULT_ERROR; } @@ -275,10 +275,10 @@ rf_stop_rx(void) /* Todo: maybe do a RF_pendCmd() to synchronize with command execution. */ - if(gvp_cmd_rx_adv->status != PROP_DONE_STOPPED && - gvp_cmd_rx_adv->status != PROP_DONE_ABORT) { + if(cmd_rx->status != PROP_DONE_STOPPED && + cmd_rx->status != PROP_DONE_ABORT) { PRINTF("RF_cmdPropRxAdv cancel: status=0x%04x\n", - gvp_cmd_rx_adv->status); + cmd_rx->status); return CMD_RESULT_ERROR; } @@ -290,8 +290,8 @@ rf_stop_rx(void) static CmdResult rf_run_setup() { - RF_runCmd(rfHandle, (RF_Op*)gvp_cmd_radio_div_setup, RF_PriorityNormal, NULL, 0); - if (gvp_cmd_radio_div_setup->status != PROP_DONE_OK) { + RF_runCmd(rfHandle, (RF_Op*)cmd_radio_setup, RF_PriorityNormal, NULL, 0); + if (cmd_radio_setup->status != PROP_DONE_OK) { return CMD_RESULT_ERROR; } @@ -329,7 +329,7 @@ get_channel(void) { uint32_t freq_khz; - freq_khz = gvp_cmd_fs->frequency * 1000; + freq_khz = cmd_fs->frequency * 1000; /* * For some channels, fractFreq * 1000 / 65536 will return 324.99xx. @@ -337,7 +337,7 @@ get_channel(void) * function returning channel - 1 instead of channel. Thus, we do a quick * positive integer round up. */ - freq_khz += (((gvp_cmd_fs->fractFreq * 1000) + 65535) / 65536); + freq_khz += (((cmd_fs->fractFreq * 1000) + 65535) / 65536); return (freq_khz - DOT_15_4G_CHAN0_FREQUENCY) / DOT_15_4G_CHANNEL_SPACING; } @@ -353,9 +353,9 @@ set_channel(uint8_t channel) PRINTF("set_channel: %u = 0x%04x.0x%04x (%lu)\n", channel, freq, frac, new_freq); - gvp_cmd_radio_div_setup->centerFreq = freq; - gvp_cmd_fs->frequency = freq; - gvp_cmd_fs->fractFreq = frac; + cmd_radio_setup->centerFreq = freq; + cmd_fs->frequency = freq; + cmd_fs->fractFreq = frac; // Todo: Need to re-run setup command when deviation from previous frequency // is too large @@ -363,7 +363,7 @@ set_channel(uint8_t channel) // We don't care whether the FS command is successful because subsequent // TX and RX commands will tell us indirectly. - RF_postCmd(rfHandle, (RF_Op*)gvp_cmd_fs, RF_PriorityNormal, NULL, 0); + RF_postCmd(rfHandle, (RF_Op*)cmd_fs, RF_PriorityNormal, NULL, 0); } /*---------------------------------------------------------------------------*/ /* Returns the current TX power in dBm */ @@ -454,11 +454,11 @@ transmit(unsigned short transmit_len) * pktLen: Total number of bytes in the TX buffer, including the header if * one exists, but not including the CRC (which is not present in the buffer) */ - gvp_cmd_tx_adv->pktLen = transmit_len + DOT_4G_PHR_LEN; - gvp_cmd_tx_adv->pPkt = tx_buf; + cmd_tx->pktLen = transmit_len + DOT_4G_PHR_LEN; + cmd_tx->pPkt = tx_buf; // TODO: Register callback - RF_runCmd(rfHandle, (RF_Op*)gvp_cmd_tx_adv, RF_PriorityNormal, NULL, 0); + RF_runCmd(rfHandle, (RF_Op*)cmd_tx, RF_PriorityNormal, NULL, 0); // if (txHandle == RF_ALLOC_ERROR) // { // /* Failure sending the CMD_PROP_TX command */ @@ -474,20 +474,20 @@ transmit(unsigned short transmit_len) // /* Idle away while the command is running */ // RF_pendCmd(rfHandle, txHandle, RF_EventLastCmdDone); - if(gvp_cmd_tx_adv->status == PROP_DONE_OK) { + if(cmd_tx->status == PROP_DONE_OK) { /* Sent OK */ ret = RADIO_TX_OK; } else { /* Operation completed, but frame was not sent */ PRINTF("transmit: Not Sent OK status=0x%04x\n", - gvp_cmd_tx_adv->status); + cmd_tx->status); ret = RADIO_TX_ERR; } ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); /* Workaround. Set status to IDLE */ - gvp_cmd_tx_adv->status = IDLE; + cmd_tx->status = IDLE; if (was_off) { RF_yield(rfHandle); @@ -636,7 +636,7 @@ rf_switch_off(void) RF_yield(rfHandle); /* We pulled the plug, so we need to restore the status manually */ - gvp_cmd_rx_adv->status = IDLE; + cmd_rx->status = IDLE; return CMD_RESULT_OK; } @@ -644,44 +644,50 @@ rf_switch_off(void) static radio_result_t get_value(radio_param_t param, radio_value_t *value) { - if(!value) { + if (!value) { return RADIO_RESULT_INVALID_VALUE; } - switch(param) { + switch (param) { case RADIO_PARAM_POWER_MODE: /* On / off */ *value = rf_is_on() ? RADIO_POWER_MODE_ON : RADIO_POWER_MODE_OFF; return RADIO_RESULT_OK; + case RADIO_PARAM_CHANNEL: *value = (radio_value_t)get_channel(); return RADIO_RESULT_OK; + case RADIO_PARAM_TXPOWER: *value = get_tx_power(); return RADIO_RESULT_OK; + case RADIO_PARAM_CCA_THRESHOLD: *value = rssi_threshold; return RADIO_RESULT_OK; + case RADIO_PARAM_RSSI: *value = get_rssi(); + return (*value == RF_CMD_CCA_REQ_RSSI_UNKNOWN) + ? RADIO_RESULT_ERROR + : RADIO_RESULT_OK; - if(*value == RF_CMD_CCA_REQ_RSSI_UNKNOWN) { - return RADIO_RESULT_ERROR; - } else { - return RADIO_RESULT_OK; - } case RADIO_CONST_CHANNEL_MIN: *value = 0; return RADIO_RESULT_OK; + case RADIO_CONST_CHANNEL_MAX: *value = DOT_15_4G_CHANNEL_MAX; return RADIO_RESULT_OK; + case RADIO_CONST_TXPOWER_MIN: *value = (radio_value_t)TX_POWER_MIN; return RADIO_RESULT_OK; + case RADIO_CONST_TXPOWER_MAX: *value = (radio_value_t)TX_POWER_MAX; return RADIO_RESULT_OK; + default: return RADIO_RESULT_NOT_SUPPORTED; } @@ -701,6 +707,7 @@ set_value(radio_param_t param, radio_value_t value) return RADIO_RESULT_OK; } return RADIO_RESULT_INVALID_VALUE; + case RADIO_PARAM_CHANNEL: if(value < 0 || value > DOT_15_4G_CHANNEL_MAX) { @@ -715,15 +722,17 @@ set_value(radio_param_t param, radio_value_t value) set_channel((uint8_t)value); break; + case RADIO_PARAM_TXPOWER: return set_tx_power(value); case RADIO_PARAM_RX_MODE: return RADIO_RESULT_OK; + case RADIO_PARAM_CCA_THRESHOLD: rssi_threshold = (int8_t)value; return RADIO_RESULT_OK; - break; + default: return RADIO_RESULT_NOT_SUPPORTED; } @@ -768,7 +777,7 @@ rf_init(void) // Disable automatic power-down just to not interfere with stack timing params.nInactivityTimeout = 0; - rfHandle = RF_open(&rfObject, &RF_propMode, (RF_RadioSetup*)gvp_cmd_radio_div_setup, ¶ms); + rfHandle = RF_open(&rfObject, &RF_propMode, (RF_RadioSetup*)cmd_radio_setup, ¶ms); assert(rfHandle != NULL); /* Initialise RX buffers */ @@ -781,8 +790,8 @@ rf_init(void) /* Initialize current read pointer to first element (used in ISR) */ rx_read_entry = rx_buf[0]; - gvp_cmd_rx_adv->pQueue = &rx_data_queue; - gvp_cmd_rx_adv->pOutput = (uint8_t *)&rx_stats; + cmd_rx->pQueue = &rx_data_queue; + cmd_rx->pOutput = (uint8_t *)&rx_stats; set_channel(RF_CORE_CHANNEL); diff --git a/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c b/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c index 6a0042618..ac35116ef 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c +++ b/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c @@ -246,6 +246,8 @@ nmiISR(void) } } +volatile int x__; + //***************************************************************************** // // This is the code that gets called when the processor receives a fault @@ -256,6 +258,7 @@ nmiISR(void) static void faultISR(void) { + x__ = 0; /* Enter an infinite loop. */ while(1) { @@ -273,6 +276,7 @@ faultISR(void) static void busFaultHandler(void) { + x__ = 0; /* Enter an infinite loop. */ while(1) { diff --git a/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c b/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c index 3c662d0d2..00390a3e5 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c @@ -37,6 +37,7 @@ */ /*---------------------------------------------------------------------------*/ #include + #include /*---------------------------------------------------------------------------*/ #include @@ -64,7 +65,7 @@ uart0_cb(UART_Handle handle, void *buf, size_t count) const uart0_input_cb currCb = g_input_cb; // Call the callback. Note this might reset g_input_cb currCb(g_char_buf); - // If the callback pointer didn't change after the call, do another read. + // If g_input_cb didn't change after the call, do another read. // Else, the uart0_set_callback was called with a different callback pointer // and triggered an another read. if (currCb == g_input_cb) { @@ -78,8 +79,6 @@ uart0_init(void) if (g_bIsInit) { return; } g_bIsInit = true; - UART_init(); - UART_Params params; UART_Params_init(¶ms); #ifdef SIMPLELINK_UART_CONF_BAUD_RATE @@ -118,8 +117,7 @@ uart0_set_callback(uart0_input_cb input_cb) g_input_cb = input_cb; if (input_cb) { return UART_read(gh_uart, &g_char_buf, 1); - } - else { + } else { UART_readCancel(gh_uart); return UART_STATUS_SUCCESS; } diff --git a/arch/cpu/cc13xx-cc26xx/dev/watchdog-arch.c b/arch/cpu/cc13xx-cc26xx/dev/watchdog-arch.c index ac137e577..f5eb3537d 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/watchdog-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/watchdog-arch.c @@ -42,12 +42,14 @@ * \file * Implementation of the CC13xx/CC26xx watchdog driver. */ -#include -#include - +/*---------------------------------------------------------------------------*/ #include "contiki.h" #include "dev/watchdog.h" +/*---------------------------------------------------------------------------*/ +#include +#include +/*---------------------------------------------------------------------------*/ #include #include /*---------------------------------------------------------------------------*/ @@ -56,49 +58,8 @@ #else #define CONTIKI_WATCHDOG_TIMER_TOP 0xFFFFF #endif - -#ifdef CONTIKI_WATCHDOG_CONF_LOCK_CONFIG -#define CONTIKI_WATCHDOG_LOCK_CONFIG CONTIKI_WATCHDOG_CONF_LOCK_CONFIG -#else -#define CONTIKI_WATCHDOG_LOCK_CONFIG 1 -#endif - -#define LOCK_INTERRUPTS_DISABLED 0x01 -#define LOCK_REGISTERS_UNLOCKED 0x02 /*---------------------------------------------------------------------------*/ -static uint32_t -unlock_config(void) -{ - uint32_t ret = 0; - bool int_status; - - if(CONTIKI_WATCHDOG_LOCK_CONFIG) { - int_status = IntMasterDisable(); - - if(WatchdogLockState()) { - ret |= LOCK_REGISTERS_UNLOCKED; - WatchdogUnlock(); - } - - ret |= (int_status) ? (0) : (LOCK_INTERRUPTS_DISABLED); - } - - return ret; -} -/*---------------------------------------------------------------------------*/ -static void -lock_config(uint32_t status) -{ - if(CONTIKI_WATCHDOG_LOCK_CONFIG) { - - if(status & LOCK_REGISTERS_UNLOCKED) { - WatchdogLock(); - } - if(status & LOCK_INTERRUPTS_DISABLED) { - IntMasterEnable(); - } - } -} +static Watchdog_Handle wd_handle; /*---------------------------------------------------------------------------*/ /** * \brief Initialises the CC26xx WDT @@ -109,8 +70,14 @@ lock_config(uint32_t status) void watchdog_init(void) { - WatchdogReloadSet(CONTIKI_WATCHDOG_TIMER_TOP); - lock_config(LOCK_REGISTERS_UNLOCKED); + Watchdog_init(); + + Watchdog_Params params; + Watchdog_Params_init(¶ms); + params.resetMode = Watchdog_RESET_ON; + params.debugStallMode = Watchdog_DEBUG_STALL_ON; + + wd_handle = Watchdog_open(Board_WATCHDOG0, ¶ms); } /*---------------------------------------------------------------------------*/ /** @@ -119,12 +86,7 @@ watchdog_init(void) void watchdog_start(void) { - uint32_t lock_status = unlock_config(); - watchdog_periodic(); - WatchdogResetEnable(); - - lock_config(lock_status); } /*---------------------------------------------------------------------------*/ /** @@ -133,8 +95,7 @@ watchdog_start(void) void watchdog_periodic(void) { - WatchdogReloadSet(CONTIKI_WATCHDOG_TIMER_TOP); - WatchdogIntClear(); + Watchdog_setReload(wd_handle, CONTIKI_WATCHDOG_TIMER_TOP); } /*---------------------------------------------------------------------------*/ /** @@ -143,11 +104,7 @@ watchdog_periodic(void) void watchdog_stop(void) { - uint32_t lock_status = unlock_config(); - - WatchdogResetDisable(); - - lock_config(lock_status); + Watchdog_clear(wd_handle); } /*---------------------------------------------------------------------------*/ /** diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c index 0cd20bb45..b6f05f337 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c @@ -7,13 +7,14 @@ // Preamble (32 bit): 01010101... // TX Power: 5 dBm +#include "sys/cc.h" + #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) // This must be included "locally" frm the cpu directory, // as it isn't defined in CC13x0 driverlib #include "driverlib/rf_ieee_cmd.h" -#include "rf_patches/rf_patch_cpe_ieee.h" #include @@ -24,7 +25,7 @@ RF_Mode RF_ieeeMode = { .rfMode = RF_MODE_IEEE_15_4, - .cpePatchFxn = &rf_patch_cpe_ieee, + .cpePatchFxn = 0, .mcePatchFxn = 0, .rfePatchFxn = 0, }; @@ -54,8 +55,8 @@ RF_TxPowerTable_Entry ieeeTxPowerTable[14] = }; -// Overrides for CMD_RADIO_SETUP -uint32_t pIeeeOverrides[] = +// Overrides for CMD_RADIO_SETUP (CC2650) +uint32_t pIeeeOverrides[] CC_ALIGN(4) = { // override_synth_ieee_15_4.xml HW_REG_OVERRIDE(0x4038,0x0035), // Synth: Set recommended RTRIM to 5 @@ -83,19 +84,20 @@ uint32_t pIeeeOverrides[] = // Old override list -uint32_t ieee_overrides[] = { - (uint32_t)0x00354038, // Synth: Set RTRIM (POTAILRESTRIM) to 5 - (uint32_t)0x000784A3, // Synth: Set FREF = 3.43 MHz (24 MHz / 7) - (uint32_t)0xA47E0583, // Synth: Set loop bandwidth after lock to 80 kHz (K2) - (uint32_t)0xEAE00603, // Synth: Set loop bandwidth after lock to 80 kHz (K3, LSB) - (uint32_t)0x00010623, // Synth: Set loop bandwidth after lock to 80 kHz (K3, MSB) -// (uint32_t)0x1801F800, // Synth: Set ANADIV DIV_BIAS_MODE to PG1 (value) - (uint32_t)0x4001402D, // Synth: Correct CKVD latency setting (address) - (uint32_t)0x00608402, // Synth: Correct CKVD latency setting (value) -// (uint32_t)0x4001405D, // Synth: Set ANADIV DIV_BIAS_MODE to PG1 (address) - (uint32_t)0x002B50DC, // Adjust AGC DC filter - (uint32_t)0x05000243, // Increase synth programming timeout - (uint32_t)0x002082C3, // Increase synth programming timeout +uint32_t pIeeeOverridesOld[] CC_ALIGN(4) = +{ + (uint32_t)0x00354038, /* Synth: Set RTRIM (POTAILRESTRIM) to 5 */ + (uint32_t)0x4001402D, /* Synth: Correct CKVD latency setting (address) */ + (uint32_t)0x00608402, /* Synth: Correct CKVD latency setting (value) */ +// (uint32_t)0x4001405D, /* Synth: Set ANADIV DIV_BIAS_MODE to PG1 (address) */ +// (uint32_t)0x1801F800, /* Synth: Set ANADIV DIV_BIAS_MODE to PG1 (value) */ + (uint32_t)0x000784A3, /* Synth: Set FREF = 3.43 MHz (24 MHz / 7) */ + (uint32_t)0xA47E0583, /* Synth: Set loop bandwidth after lock to 80 kHz (K2) */ + (uint32_t)0xEAE00603, /* Synth: Set loop bandwidth after lock to 80 kHz (K3, LSB) */ + (uint32_t)0x00010623, /* Synth: Set loop bandwidth after lock to 80 kHz (K3, MSB) */ + (uint32_t)0x002B50DC, /* Adjust AGC DC filter */ + (uint32_t)0x05000243, /* Increase synth programming timeout */ + (uint32_t)0x002082C3, /* Increase synth programming timeout */ (uint32_t)0xFFFFFFFF, }; diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h index 5d00932ff..01b773215 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h @@ -10,9 +10,10 @@ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) -// This must be included "locally" frm the cpu directory, -// as it isn't defined in CC13x0 driverlib +// These two headers must be included "locally" frm the cpu directory, +// as they aren't defined in CC13x0 driverlib #include "driverlib/rf_ieee_cmd.h" +#include "driverlib/rf_ieee_mailbox.h" #include diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c index 1f86d67ec..702295391 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c @@ -27,6 +27,8 @@ // TX Power: 14 dBm (requires define CCFG_FORCE_VDDR_HH = 1 in ccfg.c, see CC13xx/CC26xx Technical Reference Manual) // Whitening: Dynamically IEEE 802.15.4g compatible whitener and 16/32-bit CRC +#include "sys/cc.h" + #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) @@ -77,7 +79,7 @@ RF_TxPowerTable_Entry propTxPowerTable[16] = // Overrides for CMD_PROP_RADIO_DIV_SETUP -uint32_t pPropOverrides[] = +uint32_t pPropOverrides[] CC_ALIGN(4) = { // override_use_patch_prop_genfsk.xml MCE_RFE_OVERRIDE(0,4,0,1,0,0), // PHY: Use MCE ROM bank 4, RFE RAM patch diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c index bedbbc792..efb1882da 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c @@ -20,6 +20,8 @@ // TX Power: 20 dBm (requires define CCFG_FORCE_VDDR_HH = 0 in ccfg.c, see CC13xx/CC26xx Technical Reference Manual) // Enable high output power PA: true +#include "sys/cc.h" + #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) @@ -95,7 +97,7 @@ RF_TxPowerTable_Entry ieeeHighPaTxPowerTable[16] = // Overrides for CMD_RADIO_SETUP -uint32_t pIeeeDefaultPaOverrides[] = +uint32_t pIeeeDefaultPaOverrides[] CC_ALIGN(4) = { // override_ieee_802_15_4.xml MCE_RFE_OVERRIDE(1,0,0,0,1,0), // PHY: Use MCE RAM patch, RFE ROM bank 1 @@ -117,7 +119,7 @@ uint32_t pIeeeDefaultPaOverrides[] = // Overrides for CMD_RADIO_SETUP -uint32_t pIeeeHighPaOverrides[] = +uint32_t pIeeeHighPaOverrides[] CC_ALIGN(4) = { // override_ieee_802_15_4.xml MCE_RFE_OVERRIDE(1,0,0,0,1,0), // PHY: Use MCE RAM patch, RFE ROM bank 1 @@ -167,7 +169,7 @@ rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup = // CMD_FS // Frequency Synthesizer Programming Command -rfc_CMD_FS_t RF_cmdFs = +rfc_CMD_FS_t RF_cmdIeeeFs = { .commandNo = 0x0803, .status = 0x0000, diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h index ed9a7c7e0..8a37b35fe 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h @@ -11,6 +11,7 @@ #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) #include DeviceFamily_constructPath(driverlib/rf_ieee_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_ieee_mailbox.h) #include @@ -26,7 +27,7 @@ extern RF_TxPowerTable_Entry ieeeHighPaTxPowerTable[16]; // RF Core API commands extern rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup; -extern rfc_CMD_FS_t RF_cmdFs; +extern rfc_CMD_FS_t RF_cmdIeeeFs; extern rfc_CMD_IEEE_TX_t RF_cmdIeeeTx; extern rfc_CMD_IEEE_RX_t RF_cmdIeeeRx; diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c index e17b71954..f6928f04c 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c @@ -24,6 +24,8 @@ // Enable high output power PA: true // Whitening: Dynamically IEEE 802.15.4g compatible whitener and 16/32-bit CRC +#include "sys/cc.h" + #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) @@ -97,7 +99,7 @@ RF_TxPowerTable_Entry propHighPaTxPowerTable[8] = // Overrides for CMD_PROP_RADIO_DIV_SETUP -uint32_t pPropDefaultPaOverrides[] = +uint32_t pPropDefaultPaOverrides[] CC_ALIGN(4) = { // override_use_patch_prop_genfsk.xml MCE_RFE_OVERRIDE(1,0,0,1,0,0), // PHY: Use MCE RAM patch, RFE RAM patch @@ -135,7 +137,7 @@ uint32_t pPropDefaultPaOverrides[] = // Overrides for CMD_PROP_RADIO_DIV_SETUP -uint32_t pPropHighPaOverrides[] = +uint32_t pPropHighPaOverrides[] CC_ALIGN(4) = { // override_use_patch_prop_genfsk.xml MCE_RFE_OVERRIDE(1,0,0,1,0,0), // PHY: Use MCE RAM patch, RFE RAM patch @@ -213,7 +215,7 @@ rfc_CMD_PROP_RADIO_DIV_SETUP_t RF_cmdPropRadioDivSetup = // CMD_FS // Frequency Synthesizer Programming Command -rfc_CMD_FS_t RF_cmdFs = +rfc_CMD_FS_t RF_cmdPropFs = { .commandNo = 0x0803, .status = 0x0000, diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h index 87cbfa562..a3f758abd 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h @@ -26,7 +26,7 @@ extern RF_TxPowerTable_Entry propHighPaTxPowerTable[8]; // RF Core API commands extern rfc_CMD_PROP_RADIO_DIV_SETUP_t RF_cmdPropRadioDivSetup; -extern rfc_CMD_FS_t RF_cmdFs; +extern rfc_CMD_FS_t RF_cmdPropFs; extern rfc_CMD_PROP_TX_ADV_t RF_cmdPropTxAdv; extern rfc_CMD_PROP_RX_ADV_t RF_cmdPropRxAdv; diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c index 9ed0c5629..15527b039 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c @@ -7,6 +7,8 @@ // Preamble (32 bit): 01010101... // TX Power: 5 dBm +#include "sys/cc.h" + #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) @@ -53,7 +55,7 @@ RF_TxPowerTable_Entry ieeeTxPowerTable[14] = // Overrides for CMD_RADIO_SETUP -uint32_t pIeeeOverrides[] = +uint32_t pIeeeOverrides[] CC_ALIGN(4) = { // override_synth_ieee_15_4.xml HW_REG_OVERRIDE(0x4038,0x0035), // Synth: Set recommended RTRIM to 5 diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h index 1a762a23a..5c6cb3d5a 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h @@ -11,6 +11,7 @@ #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) #include DeviceFamily_constructPath(driverlib/rf_ieee_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_ieee_mailbox.h) #include diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c index fba191773..20fbc6627 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c @@ -7,6 +7,8 @@ // Preamble (32 bit): 01010101... // TX Power: 5 dBm +#include "sys/cc.h" + #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) @@ -20,7 +22,7 @@ // TI-RTOS RF Mode Object -RF_Mode RF_propMode = +RF_Mode RF_ieeeMode = { .rfMode = RF_MODE_AUTO, .cpePatchFxn = &rf_patch_cpe_ieee_802_15_4, @@ -34,7 +36,7 @@ RF_Mode RF_propMode = // RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) // See the Technical Reference Manual for further details about the "txPower" Command field. // The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. -RF_TxPowerTable_Entry txPowerTable[16] = +RF_TxPowerTable_Entry ieeeTxPowerTable[16] = { { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY(7, 3, 0, 3) }, { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY(9, 3, 0, 3) }, @@ -56,7 +58,7 @@ RF_TxPowerTable_Entry txPowerTable[16] = // Overrides for CMD_RADIO_SETUP -uint32_t pOverrides[] = +uint32_t pIeeeOverrides[] CC_ALIGN(4) = { // override_ieee_802_15_4.xml MCE_RFE_OVERRIDE(1,0,0,0,1,0), // PHY: Use MCE RAM patch, RFE ROM bank 1 @@ -98,12 +100,12 @@ rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup = .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, .txPower = 0x941E, - .pRegOverride = pOverrides, + .pRegOverride = pIeeeOverrides, }; // CMD_FS // Frequency Synthesizer Programming Command -rfc_CMD_FS_t RF_cmdFs = +rfc_CMD_FS_t RF_cmdIeeeFs = { .commandNo = 0x0803, .status = 0x0000, diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h index a0cbb3abd..251bcb14c 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h @@ -10,28 +10,29 @@ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) -#include DeviceFamily_constructPath(driverlib/rf_ieee_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_ieee_cmd.h +#include DeviceFamily_constructPath(driverlib/rf_ieee_mailbox.h)) #include // TI-RTOS RF Mode Object -extern RF_Mode RF_propMode; +extern RF_Mode RF_ieeeMode; // TX Power Table -extern RF_TxPowerTable_Entry txPowerTable[16]; +extern RF_TxPowerTable_Entry ieeeTxPowerTable[16]; // RF Core API commands extern rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup; -extern rfc_CMD_FS_t RF_cmdFs; +extern rfc_CMD_FS_t RF_cmdIeeeFs; extern rfc_CMD_IEEE_TX_t RF_cmdIeeeTx; extern rfc_CMD_IEEE_RX_t RF_cmdIeeeRx; // RF Core API Overrides -extern uint32_t pOverrides[]; +extern uint32_t pIeeeOverrides[]; #endif // _IEEE_SETTINGS_H_ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Board.h index c73198659..66afbb6c6 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Board.h @@ -45,6 +45,20 @@ extern "C" { #define Board_shutDownExtFlash() CC1310_LAUNCHXL_shutDownExtFlash() #define Board_wakeUpExtFlash() CC1310_LAUNCHXL_wakeUpExtFlash() +/*---------------------------------------------------------------------------*/ +/** + * \name LED configurations + * + * Those values are not meant to be modified by the user + * @{ + */ +#define LEDS_RED (1 << 0) +#define LEDS_GREEN (1 << 1) +#define LEDS_YELLOW LEDS_GREEN +#define LEDS_ORANGE LEDS_RED + +#define LEDS_CONF_ALL (LEDS_RED | LEDS_GREEN) +/*---------------------------------------------------------------------------*/ /* These #defines allow us to reuse TI-RTOS across other device families */ #define Board_ADC0 CC1310_LAUNCHXL_ADC0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Board.h index d5db0c364..77179e057 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Board.h @@ -45,6 +45,20 @@ extern "C" { #define Board_shutDownExtFlash() CC1312R1_LAUNCHXL_shutDownExtFlash() #define Board_wakeUpExtFlash() CC1312R1_LAUNCHXL_wakeUpExtFlash() +/*---------------------------------------------------------------------------*/ +/** + * \name LED configurations + * + * Those values are not meant to be modified by the user + * @{ + */ +#define LEDS_RED (1 << 0) +#define LEDS_GREEN (1 << 1) +#define LEDS_YELLOW LEDS_GREEN +#define LEDS_ORANGE LEDS_RED + +#define LEDS_CONF_ALL (LEDS_RED | LEDS_GREEN) +/*---------------------------------------------------------------------------*/ /* These #defines allow us to reuse TI-RTOS across other device families */ #define Board_ADC0 CC1312R1_LAUNCHXL_ADC0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 index 6feb804df..495dc498d 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 @@ -7,6 +7,8 @@ DEVICE_LINE = CC13XX BOARD_SOURCEFILES += CC1312R1_LAUNCHXL.c CC1312R1_LAUNCHXL_fxns.c +DEFINES += PROP_MODE_CONF_TX_POWER_TABLE=propDefaultPaTxPowerTable + SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Board.h index 394f3a3cd..3859a6d26 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Board.h @@ -45,6 +45,20 @@ extern "C" { #define Board_shutDownExtFlash() CC1350_LAUNCHXL_433_shutDownExtFlash() #define Board_wakeUpExtFlash() CC1350_LAUNCHXL_433_wakeUpExtFlash() +/*---------------------------------------------------------------------------*/ +/** + * \name LED configurations + * + * Those values are not meant to be modified by the user + * @{ + */ +#define LEDS_RED (1 << 0) +#define LEDS_GREEN (1 << 1) +#define LEDS_YELLOW LEDS_GREEN +#define LEDS_ORANGE LEDS_RED + +#define LEDS_CONF_ALL (LEDS_RED | LEDS_GREEN) +/*---------------------------------------------------------------------------*/ /* These #defines allow us to reuse TI-RTOS across other device families */ #define Board_ADC0 CC1350_LAUNCHXL_433_ADC0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Board.h index a67b34ddb..0e8542d00 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Board.h @@ -45,6 +45,20 @@ extern "C" { #define Board_shutDownExtFlash() CC1350_LAUNCHXL_shutDownExtFlash() #define Board_wakeUpExtFlash() CC1350_LAUNCHXL_wakeUpExtFlash() +/*---------------------------------------------------------------------------*/ +/** + * \name LED configurations + * + * Those values are not meant to be modified by the user + * @{ + */ +#define LEDS_RED (1 << 0) +#define LEDS_GREEN (1 << 1) +#define LEDS_YELLOW LEDS_GREEN +#define LEDS_ORANGE LEDS_RED + +#define LEDS_CONF_ALL (LEDS_RED | LEDS_GREEN) +/*---------------------------------------------------------------------------*/ /* These #defines allow us to reuse TI-RTOS across other device families */ #define Board_ADC0 CC1350_LAUNCHXL_ADC0 #define Board_ADC1 CC1350_LAUNCHXL_ADC1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c index 92ce04a9d..2a4f4dee7 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c @@ -53,7 +53,7 @@ #include #include -ADCBufCC26XX_Object adcBufCC26XXobjects[CC1350_LAUNCHXL_ADCBUFCOUNT]; +static ADCBufCC26XX_Object adcBufCC26XXobjects[CC1350_LAUNCHXL_ADCBUFCOUNT]; /* * This table converts a virtual adc channel into a dio and internal analogue @@ -90,6 +90,7 @@ const ADCBuf_Config ADCBuf_config[CC1350_LAUNCHXL_ADCBUFCOUNT] = { { &ADCBufCC26XX_fxnTable, &adcBufCC26XXobjects[CC1350_LAUNCHXL_ADCBUF0], + //NULL, &adcBufCC26XXHWAttrs[CC1350_LAUNCHXL_ADCBUF0] }, }; @@ -102,7 +103,7 @@ const uint_least8_t ADCBuf_count = CC1350_LAUNCHXL_ADCBUFCOUNT; #include #include -ADCCC26XX_Object adcCC26xxObjects[CC1350_LAUNCHXL_ADCCOUNT]; +static ADCCC26XX_Object adcCC26xxObjects[CC1350_LAUNCHXL_ADCCOUNT]; const ADCCC26XX_HWAttrs adcCC26xxHWAttrs[CC1350_LAUNCHXL_ADCCOUNT] = { { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Board.h index c078fe636..a74df419a 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Board.h @@ -45,6 +45,20 @@ extern "C" { #define Board_shutDownExtFlash() CC1352P1_LAUNCHXL_shutDownExtFlash() #define Board_wakeUpExtFlash() CC1352P1_LAUNCHXL_wakeUpExtFlash() +/*---------------------------------------------------------------------------*/ +/** + * \name LED configurations + * + * Those values are not meant to be modified by the user + * @{ + */ +#define LEDS_RED (1 << 0) +#define LEDS_GREEN (1 << 1) +#define LEDS_YELLOW LEDS_GREEN +#define LEDS_ORANGE LEDS_RED + +#define LEDS_CONF_ALL (LEDS_RED | LEDS_GREEN) +/*---------------------------------------------------------------------------*/ /* These #defines allow us to reuse TI-RTOS across other device families */ #define Board_ADC0 CC1352P1_LAUNCHXL_ADC0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 index d24e181a4..accb29899 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 @@ -7,6 +7,9 @@ DEVICE_LINE = CC13XX BOARD_SOURCEFILES += CC1352P1_LAUNCHXL.c CC1312P1_LAUNCHXL_fxns.c +DEFINES += PROP_MODE_CONF_TX_POWER_TABLE=propDefaultPaTxPowerTable +DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE=ieeeDefaultPaTxPowerTable + SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/Board.h index 7fe300916..e251723cd 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/Board.h @@ -45,6 +45,20 @@ extern "C" { #define Board_shutDownExtFlash() CC1352P_2_LAUNCHXL_shutDownExtFlash() #define Board_wakeUpExtFlash() CC1352P_2_LAUNCHXL_wakeUpExtFlash() +/*---------------------------------------------------------------------------*/ +/** + * \name LED configurations + * + * Those values are not meant to be modified by the user + * @{ + */ +#define LEDS_RED (1 << 0) +#define LEDS_GREEN (1 << 1) +#define LEDS_YELLOW LEDS_GREEN +#define LEDS_ORANGE LEDS_RED + +#define LEDS_CONF_ALL (LEDS_RED | LEDS_GREEN) +/*---------------------------------------------------------------------------*/ /* These #defines allow us to reuse TI-RTOS across other device families */ #define Board_ADC0 CC1352P_2_LAUNCHXL_ADC0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/Makefile.cc1352p_2 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/Makefile.cc1352p_2 index 3e7db941d..4c9558719 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/Makefile.cc1352p_2 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/Makefile.cc1352p_2 @@ -7,6 +7,9 @@ DEVICE_LINE = CC13XX BOARD_SOURCEFILES += CC1352P_2_LAUNCHXL.c CC1352P_2_LAUNCHXL_fxns.c +DEFINES += PROP_MODE_CONF_TX_POWER_TABLE=propDefaultPaTxPowerTable +DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE=ieeeDefaultPaTxPowerTable + SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/Board.h index 752f8d88f..f36390cea 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/Board.h @@ -45,6 +45,20 @@ extern "C" { #define Board_shutDownExtFlash() CC1352P_4_LAUNCHXL_shutDownExtFlash() #define Board_wakeUpExtFlash() CC1352P_4_LAUNCHXL_wakeUpExtFlash() +/*---------------------------------------------------------------------------*/ +/** + * \name LED configurations + * + * Those values are not meant to be modified by the user + * @{ + */ +#define LEDS_RED (1 << 0) +#define LEDS_GREEN (1 << 1) +#define LEDS_YELLOW LEDS_GREEN +#define LEDS_ORANGE LEDS_RED + +#define LEDS_CONF_ALL (LEDS_RED | LEDS_GREEN) +/*---------------------------------------------------------------------------*/ /* These #defines allow us to reuse TI-RTOS across other device families */ #define Board_ADC0 CC1352P_4_LAUNCHXL_ADC0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/Makefile.cc1352p_4 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/Makefile.cc1352p_4 index df7cb99a6..a9365a51a 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/Makefile.cc1352p_4 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/Makefile.cc1352p_4 @@ -7,6 +7,9 @@ DEVICE_LINE = CC13XX BOARD_SOURCEFILES += CC1352P_4_LAUNCHXL.c CC1352P_4_LAUNCHXL_fxns.c +DEFINES += PROP_MODE_CONF_TX_POWER_TABLE=propDefaultPaTxPowerTable +DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE=ieeeDefaultPaTxPowerTable + SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h index 9cc52d689..2c46e0b7c 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h @@ -45,6 +45,20 @@ extern "C" { #define Board_shutDownExtFlash() CC1352R1_LAUNCHXL_shutDownExtFlash() #define Board_wakeUpExtFlash() CC1352R1_LAUNCHXL_wakeUpExtFlash() +/*---------------------------------------------------------------------------*/ +/** + * \name LED configurations + * + * Those values are not meant to be modified by the user + * @{ + */ +#define LEDS_RED (1 << 0) +#define LEDS_GREEN (1 << 1) +#define LEDS_YELLOW LEDS_GREEN +#define LEDS_ORANGE LEDS_RED + +#define LEDS_CONF_ALL (LEDS_RED | LEDS_GREEN) +/*---------------------------------------------------------------------------*/ /* These #defines allow us to reuse TI-RTOS across other device families */ #define Board_ADC0 CC1352R1_LAUNCHXL_ADC0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 index 272482360..8214b275e 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 @@ -7,6 +7,9 @@ DEVICE_LINE = CC13XX BOARD_SOURCEFILES += CC1352R1_LAUNCHXL.c CC1352R1_LAUNCHXL_fxns.c +DEFINES += PROP_MODE_CONF_TX_POWER_TABLE=propDefaultPaTxPowerTable +DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE=ieeeDefaultPaTxPowerTable + SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Board.h index 72f5cb42d..07668d60f 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Board.h @@ -45,6 +45,20 @@ extern "C" { #define Board_shutDownExtFlash() CC2650_LAUNCHXL_shutDownExtFlash() #define Board_wakeUpExtFlash() CC2650_LAUNCHXL_wakeUpExtFlash() +/*---------------------------------------------------------------------------*/ +/** + * \name LED configurations + * + * Those values are not meant to be modified by the user + * @{ + */ +#define LEDS_RED (1 << 0) +#define LEDS_GREEN (1 << 1) +#define LEDS_YELLOW LEDS_GREEN +#define LEDS_ORANGE LEDS_RED + +#define LEDS_CONF_ALL (LEDS_RED | LEDS_GREEN) +/*---------------------------------------------------------------------------*/ /* These #defines allow us to reuse TI-RTOS across other device families */ #define Board_ADC0 CC2650_LAUNCHXL_ADC0 #define Board_ADC1 CC2650_LAUNCHXL_ADC1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Board.h index 8940527b9..c984f711b 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Board.h @@ -47,6 +47,20 @@ extern "C" { #define Board_wakeUpExtFlash() CC26X2R1_LAUNCHXL_wakeUpExtFlash() +/*---------------------------------------------------------------------------*/ +/** + * \name LED configurations + * + * Those values are not meant to be modified by the user + * @{ + */ +#define LEDS_RED (1 << 0) +#define LEDS_GREEN (1 << 1) +#define LEDS_YELLOW LEDS_GREEN +#define LEDS_ORANGE LEDS_RED + +#define LEDS_CONF_ALL (LEDS_RED | LEDS_GREEN) +/*---------------------------------------------------------------------------*/ /* These #defines allow us to reuse TI-RTOS across other device families */ #define Board_ADC0 CC26X2R1_LAUNCHXL_ADC0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/ext-flash.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/ext-flash.c index b985da95a..a78a5e764 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/ext-flash.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/ext-flash.c @@ -37,7 +37,7 @@ */ /*---------------------------------------------------------------------------*/ #include -#include +#include #include /*---------------------------------------------------------------------------*/ #include "contiki.h" @@ -48,7 +48,17 @@ #include #include /*---------------------------------------------------------------------------*/ -static SPI_Handle spiHandle = NULL; +static PIN_Config pin_table[] = { + Board_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, + PIN_TERMINATE +}; + +static PIN_State pin_state; +static PIN_Handle pin_handle; + +static SPI_Handle spi_handle; + +static bool ext_flash_opened; /*---------------------------------------------------------------------------*/ #define SPI_BIT_RATE 4000000 @@ -115,7 +125,7 @@ spi_write(const uint8_t *buf, size_t len) spiTransaction.txBuf = (void *)buf; spiTransaction.rxBuf = NULL; - return SPI_transfer(spiHandle, &spiTransaction); + return SPI_transfer(spi_handle, &spiTransaction); } /*---------------------------------------------------------------------------*/ static bool @@ -126,19 +136,19 @@ spi_read(uint8_t *buf, size_t len) spiTransaction.txBuf = NULL; spiTransaction.rxBuf = buf; - return SPI_transfer(spiHandle, &spiTransaction); + return SPI_transfer(spi_handle, &spiTransaction); } /*---------------------------------------------------------------------------*/ static void select(void) { - ti_lib_gpio_clear_dio(Board_SPI_FLASH_CS); + PIN_setOutputValue(pin_handle, Board_SPI_FLASH_CS, 1); } /*---------------------------------------------------------------------------*/ static void deselect(void) { - ti_lib_gpio_set_dio(Board_SPI_FLASH_CS); + PIN_setOutputValue(pin_handle, Board_SPI_FLASH_CS, 0); } /*---------------------------------------------------------------------------*/ static bool @@ -258,7 +268,13 @@ verify_part(void) bool ext_flash_open() { - if (spiHandle != NULL) { + if (ext_flash_opened) { + return true; + } + + pin_handle = PIN_open(&pin_state, pin_table); + + if (pin_handle == NULL) { return false; } @@ -268,13 +284,15 @@ ext_flash_open() spiParams.mode = SPI_MASTER; spiParams.transferMode = SPI_MODE_BLOCKING; - spiHandle = SPI_open(Board_SPI0, &spiParams); + spi_handle = SPI_open(Board_SPI0, &spiParams); - if (spiHandle == NULL) { + if (spi_handle == NULL) { + PIN_close(pin_handle); return false; } - ti_lib_ioc_pin_type_gpio_output(Board_SPI_FLASH_CS); + ext_flash_opened = true; + deselect(); const bool is_powered = power_standby(); @@ -289,18 +307,21 @@ ext_flash_open() void ext_flash_close() { - if (spiHandle == NULL) { + if (!ext_flash_opened) { return; } + ext_flash_opened = false; power_down(); - SPI_close(spiHandle); + + SPI_close(spi_handle); + PIN_close(pin_handle); } /*---------------------------------------------------------------------------*/ bool ext_flash_read(size_t offset, size_t length, uint8_t *buf) { - if (spiHandle == NULL || buf == NULL) { + if (spi_handle == NULL || buf == NULL) { return false; } @@ -333,7 +354,7 @@ ext_flash_read(size_t offset, size_t length, uint8_t *buf) bool ext_flash_write(size_t offset, size_t length, const uint8_t *buf) { - if (spiHandle == NULL || buf == NULL) { + if (spi_handle == NULL || buf == NULL) { return false; } @@ -441,7 +462,6 @@ ext_flash_test(void) void ext_flash_init() { - GPIO_init(); SPI_init(); } /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/leds-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/leds-arch.c index 7595d47d3..463349854 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/leds-arch.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/leds-arch.c @@ -42,35 +42,23 @@ /*---------------------------------------------------------------------------*/ /* Simplelink SDK API */ #include -#include + +#include /*---------------------------------------------------------------------------*/ /* Standard library */ #include #include /*---------------------------------------------------------------------------*/ -/* Available LED configuration */ +static const PIN_Config pin_table[] = { + Board_PIN_LED0 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, + Board_PIN_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, + PIN_TERMINATE +}; -/* Green LED */ -#ifdef Board_GPIO_GLED -# define LEDS_ARCH_GREEN Board_GPIO_GLED -#endif +static PIN_State pin_state; +static PIN_Handle pin_handle; -/* Yellow LED */ -#ifdef Board_GPIO_YLED -# define LEDS_ARCH_YELLOW Board_GPIO_YLED -#endif - -/* Red LED */ -#ifdef Board_GPIO_RLED -# define LEDS_ARCH_RED Board_GPIO_RLED -#endif - -/* Blue LED */ -#ifdef Board_GPIO_BLED -# define LEDS_ARCH_BLUE Board_GPIO_BLED -#endif -/*---------------------------------------------------------------------------*/ -static unsigned char c; +static volatile unsigned char c; /*---------------------------------------------------------------------------*/ void leds_arch_init(void) @@ -79,12 +67,14 @@ leds_arch_init(void) if(bHasInit) { return; } - bHasInit = true; - // GPIO_init will most likely be called in platform.c, - // but call it here to be sure GPIO is initialized. - // Calling GPIO_init multiple times is safe. - GPIO_init(); + // PIN_init() called from Board_initGeneral() + pin_handle = PIN_open(&pin_state, pin_table); + if (!pin_handle) { + return; + } + + bHasInit = true; } /*---------------------------------------------------------------------------*/ unsigned char @@ -93,42 +83,20 @@ leds_arch_get(void) return c; } /*---------------------------------------------------------------------------*/ -static inline void -write_led(const bool on, const uint_fast32_t gpioLed) -{ - const GPIO_PinConfig pinCfg = (on) - ? Board_GPIO_LED_ON : Board_GPIO_LED_OFF; - GPIO_write(gpioLed, pinCfg); -} -/*---------------------------------------------------------------------------*/ void leds_arch_set(unsigned char leds) { c = leds; -#define LED_ON(led_define) ((leds & (led_define)) == (led_define)) + PIN_setPortOutputValue(pin_handle, 0); - // Green LED -#ifdef LEDS_ARCH_GREEN - write_led(LED_ON(LEDS_GREEN), LEDS_ARCH_GREEN); -#endif + if (leds & LEDS_RED) { + PIN_setOutputValue(pin_handle, Board_PIN_LED0, 1); + } - // Yellow LED -#ifdef LEDS_ARCH_YELLOW - write_led(LED_ON(LEDS_YELLOW), LEDS_ARCH_YELLOW); -#endif - - // Red LED -#ifdef LEDS_ARCH_RED - write_led(LED_ON(LEDS_RED), LEDS_ARCH_RED); -#endif - - // Blue LED -#ifdef LEDS_ARCH_BLUE - write_led(LED_ON(LEDS_BLUE), LEDS_ARCH_BLUE); -#endif - -#undef LED_ON + if (leds & LEDS_GREEN) { + PIN_setOutputValue(pin_handle, Board_PIN_LED1, 1); + } } /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/platform.c b/arch/platform/simplelink/cc13xx-cc26xx/platform.c index ab29bce0d..e196efc9a 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/platform.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/platform.c @@ -49,16 +49,20 @@ /* Simplelink SDK includes */ #include #include + #include #include DeviceFamily_constructPath(driverlib/driverlib_release.h) #include DeviceFamily_constructPath(driverlib/chipinfo.h) #include DeviceFamily_constructPath(driverlib/vims.h) -#include DeviceFamily_constructPath(driverlib/interrupt.h) +#include DeviceFamily_constructPath(inc/hw_cpu_scs.h) + +#include #include #include #include #include #include +#include /*---------------------------------------------------------------------------*/ /* Contiki API */ #include "contiki.h" @@ -114,17 +118,15 @@ fade(unsigned char l) static void set_rf_params(void) { - uint16_t short_addr; uint8_t ext_addr[8]; ieee_addr_cpy_to(ext_addr, sizeof(ext_addr)); - short_addr = ext_addr[7]; - short_addr |= ext_addr[6] << 8; + uint16_t short_addr = (ext_addr[7] << 0) + | (ext_addr[6] << 8); 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_object(RADIO_PARAM_64BIT_ADDR, ext_addr, sizeof(ext_addr)); /* also set the global node id */ @@ -134,29 +136,34 @@ set_rf_params(void) void platform_init_stage_one(void) { + DRIVERLIB_ASSERT_CURR_RELEASE(); + + // TODO: TEMPORARY WHILE DEVELOP. REMOVE + HWREG(CPU_SCS_BASE + CPU_SCS_O_ACTLR) = CPU_SCS_ACTLR_DISDEFWBUF; + // Enable flash cache VIMSModeSet(VIMS_BASE, VIMS_MODE_ENABLED); // Configure round robin arbitration and prefetching VIMSConfigure(VIMS_BASE, true, true); - // NoRTOS_start only enables HWI - NoRTOS_start(); - // Board_initGeneral() will call Power_init() // Board_initGeneral() will call PIN_init(BoardGpioInitTable) Board_initGeneral(); - Board_shutDownExtFlash(); // Contiki drivers init leds_init(); fade(LEDS_RED); - GPIO_init(); + // TI Drivers init I2C_init(); SPI_init(); + UART_init(); fade(LEDS_GREEN); + + // NoRTOS should be called last + NoRTOS_start(); } /*---------------------------------------------------------------------------*/ void @@ -172,7 +179,7 @@ platform_init_stage_two(void) uart0_set_callback(serial_line_input_byte); #endif - // random_init(0x1234); + random_init(0x1234); /* Populate linkaddr_node_addr */ ieee_addr_cpy_to(linkaddr_node_addr.u8, LINKADDR_SIZE); @@ -183,7 +190,7 @@ platform_init_stage_two(void) void platform_init_stage_three(void) { - radio_value_t chan, pan; + radio_value_t chan = 0, pan = 0; set_rf_params(); @@ -192,15 +199,15 @@ platform_init_stage_three(void) LOG_DBG("With DriverLib v%u.%u\n", DRIVERLIB_RELEASE_GROUP, DRIVERLIB_RELEASE_BUILD); - LOG_DBG("IEEE 802.15.4: %s, Sub-GHz: %s, BLE: %s, Prop: %s\n", + LOG_DBG("IEEE 802.15.4: %s, Sub-GHz: %s, BLE: %s\n", ChipInfo_SupportsIEEE_802_15_4() ? "Yes" : "No", - ChipInfo_ChipFamilyIs_CC13x0() ? "Yes" : "No", - ChipInfo_SupportsBLE() ? "Yes" : "No", - ChipInfo_SupportsPROPRIETARY() ? "Yes" : "No"); + ChipInfo_SupportsPROPRIETARY() ? "Yes" : "No", + ChipInfo_SupportsBLE() ? "Yes" : "No"); LOG_INFO("RF: Channel %d, PANID 0x%04X\n", chan, pan); LOG_INFO("Node ID: %d\n", g_nodeId); process_start(&sensors_process, NULL); + fade(LEDS_GREEN); } /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag.c index 7f1e3b816..c3043f20e 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag.c @@ -51,14 +51,6 @@ void board_init(void) { - // Board_initGeneral() will call Power_init() - // Board_initGeneral() will call PIN_init(BoardGpioInitTable) - Board_initGeneral(); - Board_shutDownExtFlash(); - - GPIO_init(); - I2C_init(); - SPI_init(); } /*---------------------------------------------------------------------------*/ /** @} */ From f9fcbd6a77bef44d50b5acf4c7bbe45a1fd1485f Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Mon, 11 Jun 2018 18:38:35 +0200 Subject: [PATCH 250/485] Fixed IEEE settings, aligned naming of RF commands --- .../rf-settings/rf-ieee-settings.c | 208 ------------- .../rf-settings/rf-ieee-settings.h | 26 -- .../rf-settings/rf-prop-settings.c | 278 ------------------ .../rf-settings/rf-prop-settings.h | 35 --- arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c | 138 ++++----- arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c | 10 +- .../rf-settings/cc13x0/ieee-settings.c | 171 ++++++----- .../rf-settings/cc13x0/ieee-settings.h | 75 +++-- .../rf-settings/cc13x0/prop-settings.c | 136 +++++---- .../rf-settings/cc13x0/prop-settings.h | 76 +++-- .../rf-settings/cc13x2/ieee-settings.c | 182 ++++++------ .../rf-settings/cc13x2/ieee-settings.h | 80 +++-- .../rf-settings/cc13x2/prop-settings.c | 180 +++++++----- .../rf-settings/cc13x2/prop-settings.h | 80 +++-- .../rf-settings/cc26x0/ieee-settings.c | 166 ++++++----- .../rf-settings/cc26x0/ieee-settings.h | 74 +++-- .../rf-settings/cc26x2/ieee-settings.c | 140 +++++---- .../rf-settings/cc26x2/ieee-settings.h | 74 +++-- .../launchpad/cc1312r1/Makefile.cc1312r1 | 3 +- .../launchpad/cc1352p1/Makefile.cc1352p1 | 7 +- .../launchpad/cc1352p_2/Makefile.cc1352p_2 | 7 +- .../launchpad/cc1352p_4/Makefile.cc1352p_4 | 7 +- .../launchpad/cc1352r1/Makefile.cc1352r1 | 7 +- .../simplelink/cc13xx-cc26xx/platform.c | 3 - 24 files changed, 948 insertions(+), 1215 deletions(-) delete mode 100644 arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/rf-settings/rf-ieee-settings.c delete mode 100644 arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/rf-settings/rf-ieee-settings.h delete mode 100644 arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/rf-settings/rf-prop-settings.c delete mode 100644 arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/rf-settings/rf-prop-settings.h diff --git a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/rf-settings/rf-ieee-settings.c b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/rf-settings/rf-ieee-settings.c deleted file mode 100644 index 9b6c27cc6..000000000 --- a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/rf-settings/rf-ieee-settings.c +++ /dev/null @@ -1,208 +0,0 @@ -//********************************************************************************* -// Generated by SmartRF Studio version 2.8.0 ( build #41) -// Compatible with SimpleLink SDK version: CC13x2 SDK 1.60.xx.xx -// Device: CC1352 Rev. 1.0 -// -//********************************************************************************* - - -//********************************************************************************* -// Parameter summary -// IEEE Channel: 11 -// Frequency: 2405 MHz -// SFD: 0 -// Preamble (32 bit): 01010101... -// TX Power: 5 dBm - -#include -#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) -#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) -#include DeviceFamily_constructPath(driverlib/rf_ieee_cmd.h) -#include -#include DeviceFamily_constructPath(rf_patches/rf_patch_cpe_ieee_802_15_4.h) -#include DeviceFamily_constructPath(rf_patches/rf_patch_mce_ieee_802_15_4.h) - -#include "rf-common.h" - -/*---------------------------------------------------------------------------*/ -/* Default TX power settings for the 2.4 GHz band */ -RF_TxPower RF_ieeeTxPower[] = { - { 5, 0x9330 }, - { 4, 0x9324 }, - { 3, 0x5a1c }, - { 2, 0x4e18 }, - { 1, 0x4214 }, - { 0, 0x3161 }, - { -3, 0x2558 }, - { -6, 0x1d52 }, - { -9, 0x194e }, - { -12, 0x144b }, - { -15, 0x0ccb }, - { -18, 0x0cc9 }, - { -21, 0x0cc7 }, - {-128, 0xFFFF }, -}; -const size_t RF_ieeeTxPowerLen = sizeof(RF_ieeeTxPower) / sizeof(RF_ieeeTxPower[0]); - - -// TI-RTOS RF Mode Object -RF_Mode RF_ieeeMode = -{ - .rfMode = RF_MODE_AUTO, - .cpePatchFxn = &rf_patch_cpe_ieee_802_15_4, - .mcePatchFxn = &rf_patch_mce_ieee_802_15_4, - .rfePatchFxn = 0, -}; - - -// Overrides for CMD_RADIO_SETUP -static uint32_t pOverrides[] = -{ - // override_use_patch_ieee_802_15_4.xml - // PHY: Use MCE RAM patch, RFE ROM bank 1 - MCE_RFE_OVERRIDE(1,0,0,0,1,0), - // override_synth_ieee_802_15_4.xml - // Synth: Use 48 MHz crystal - (uint32_t)0x00408403, - // override_dcdc_rx_tx_common.xml - // DC/DC regulator: In Tx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). - (uint32_t)0xFCFC08C3, - (uint32_t)0xFFFFFFFF, -}; - - -// CMD_RADIO_SETUP -// Radio Setup Command for Pre-Defined Schemes -rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup = -{ - .commandNo = 0x0802, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .mode = 0x01, - .loDivider = 0x00, - .config.frontEndMode = 0x0, - .config.biasMode = 0x0, - .config.analogCfgMode = 0x0, - .config.bNoFsPowerUp = 0x0, - .txPower = 0x001F, - .pRegOverride = pOverrides, -}; - - -// CMD_FS -// Frequency Synthesizer Programming Command -rfc_CMD_FS_t RF_cmdFs = -{ - .commandNo = 0x0803, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .frequency = 0x0965, - .fractFreq = 0x0000, - .synthConf.bTxMode = 0x0, - .synthConf.refFreq = 0x0, - .__dummy0 = 0x00, - .__dummy1 = 0x00, - .__dummy2 = 0x00, - .__dummy3 = 0x0000, -}; - - -// CMD_IEEE_RX -// IEEE 802.15.4 Receive Command -rfc_CMD_IEEE_RX_t RF_cmdIeeeRx = -{ - .commandNo = CMD_IEEE_RX, - .status = IDLE, - .pNextOp = NULL, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .condition.rule = COND_NEVER, - .channel = 0, - .rxConfig.bAutoFlushCrc = 0x1, - .rxConfig.bAutoFlushIgn = 0x0, - .rxConfig.bIncludePhyHdr = 0x0, - .rxConfig.bIncludeCrc = 0x1, - .rxConfig.bAppendRssi = 0x1, - .rxConfig.bAppendCorrCrc = 0x1, - .rxConfig.bAppendSrcInd = 0x0, - .rxConfig.bAppendTimestamp = 0x1, - .pRxQ = NULL, - .pOutput = NULL, - .frameFiltOpt.frameFiltEn = 0x0, - .frameFiltOpt.frameFiltStop = 0x1, - .frameFiltOpt.autoAckEn = 0x0, - .frameFiltOpt.slottedAckEn = 0x0, - .frameFiltOpt.autoPendEn = 0x0, - .frameFiltOpt.defaultPend = 0x0, - .frameFiltOpt.bPendDataReqOnly = 0x0, - .frameFiltOpt.bPanCoord = 0x0, - .frameFiltOpt.maxFrameVersion = 0x2, - .frameFiltOpt.fcfReservedMask = 0x0, - .frameFiltOpt.modifyFtFilter = 0x0, - .frameFiltOpt.bStrictLenFilter = 0x0, - .frameTypes.bAcceptFt0Beacon = 0x1, - .frameTypes.bAcceptFt1Data = 0x1, - .frameTypes.bAcceptFt2Ack = 0x1, - .frameTypes.bAcceptFt3MacCmd = 0x1, - .frameTypes.bAcceptFt4Reserved = 0x1, - .frameTypes.bAcceptFt5Reserved = 0x1, - .frameTypes.bAcceptFt6Reserved = 0x1, - .frameTypes.bAcceptFt7Reserved = 0x1, - .ccaOpt.ccaEnEnergy = 0x1, - .ccaOpt.ccaEnCorr = 0x1, - .ccaOpt.ccaEnSync = 0x1, - .ccaOpt.ccaCorrOp = 0x1, - .ccaOpt.ccaSyncOp = 0x0, - .ccaOpt.ccaCorrThr = 0x3, - .ccaRssiThr = 0x64, - .numExtEntries = 0x00, - .numShortEntries = 0x00, - .pExtEntryList = NULL, - .pShortEntryList = NULL, - .localExtAddr = 0x0000000012345678, - .localShortAddr = 0xABBA, - .localPanID = 0x0000, - .endTrigger.triggerType = TRIG_NEVER, - .endTrigger.bEnaCmd = 0x0, - .endTrigger.triggerNo = 0x0, - .endTrigger.pastTrig = 0x0, - .endTime = 0x00000000, -}; - - -// CMD_IEEE_TX -// IEEE 802.15.4 Transmit Command -rfc_CMD_IEEE_TX_t RF_cmdIeeeTx = -{ - .commandNo = 0x2C01, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .txOpt.bIncludePhyHdr = 0x0, - .txOpt.bIncludeCrc = 0x0, - .txOpt.payloadLenMsb = 0x0, - .payloadLen = 0x1E, - .pPayload = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .timeStamp = 0x00000000, -}; - diff --git a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/rf-settings/rf-ieee-settings.h b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/rf-settings/rf-ieee-settings.h deleted file mode 100644 index d3c973b48..000000000 --- a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/rf-settings/rf-ieee-settings.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef IEEE_SETTINGS_H_ -#define IEEE_SETTINGS_H_ - - -#include -#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) -#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) -#include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h) -#include - -#include - -// RF TX power table -extern RF_TxPower RF_ieeeTxPower[]; -extern const size_t RF_ieeeTxPowerLen; - -// TI-RTOS RF Mode Object -extern RF_Mode RF_ieeeMode; - -// RF Core API commands -extern rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup; -extern rfc_CMD_FS_t RF_cmdFs; -extern rfc_CMD_IEEE_RX_t RF_cmdIeeeRx; -extern rfc_CMD_IEEE_TX_t RF_cmdIeeeTx; - -#endif /* IEEE_SETTINGS_H_ */ diff --git a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/rf-settings/rf-prop-settings.c b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/rf-settings/rf-prop-settings.c deleted file mode 100644 index 2c654cf24..000000000 --- a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/rf-settings/rf-prop-settings.c +++ /dev/null @@ -1,278 +0,0 @@ -//********************************************************************************* -// Generated by SmartRF Studio version 2.8.0 ( build #41) -// Compatible with SimpleLink SDK version: CC13x2 SDK 1.60.xx.xx -// Device: CC1352 Rev. 1.0 -// -//********************************************************************************* - - -//********************************************************************************* -// Parameter summary -// Address: off -// Address0: 0xAA -// Address1: 0xBB -// Frequency: 868.00000 MHz -// Data Format: Serial mode disable -// Deviation: 25.000 kHz -// pktLen: 30 -// 802.15.4g Mode: off -// Select bit order to transmit PSDU octets:: 1 -// Packet Length Config: Variable -// Max Packet Length: 255 -// Packet Length: 30 -// RX Filter BW: 98.0 kHz -// Symbol Rate: 50.00000 kBaud -// Sync Word Length: 32 Bits -// TX Power: 14 dBm (requires define CCFG_FORCE_VDDR_HH = 1 in ccfg.c, see CC13xx/CC26xx Technical Reference Manual) -// Whitening: No whitening - -#include -#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) -#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) -#include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h) -#include -#include DeviceFamily_constructPath(rf_patches/rf_patch_cpe_prop.h) -#include DeviceFamily_constructPath(rf_patches/rf_patch_rfe_genfsk.h) -#include DeviceFamily_constructPath(rf_patches/rf_patch_mce_genfsk.h) - -#include "rf-common.h" - -/*---------------------------------------------------------------------------*/ -/** - * \addtogroup rf-core-prop - * @{ - * - * \file - * Default TX power settings. The board can override - */ -/*---------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------*/ -/* Default TX power settings for the 779-930MHz band */ -RF_TxPower RF_propTxPower779_930[] = { - { 14, 0xa73f }, - { 13, 0xa63f }, /* 12.5 */ - { 12, 0xb818 }, - { 11, 0x50da }, - { 10, 0x38d3 }, - { 9, 0x2ccd }, - { 8, 0x24cb }, - { 7, 0x20c9 }, - { 6, 0x1cc7 }, - { 5, 0x18c6 }, - { 4, 0x18c5 }, - { 3, 0x14c4 }, - { 2, 0x1042 }, - { 1, 0x10c3 }, - { 0, 0x0041 }, - { -10, 0x08c0 }, - {-128, 0xFFFF }, -}; -const size_t RF_propTxPower779_930Size = sizeof(RF_propTxPower779_930) / sizeof(RF_propTxPower779_930[0]); -/*---------------------------------------------------------------------------*/ -/* Default TX power settings for the 431-527MHz band */ -RF_TxPower RF_propTxPower431_527[] = { - { 15, 0x003f }, - { 14, 0xbe3f }, /* 13.7 */ - { 13, 0x6a0f }, - { 10, 0x3dcb }, - { 6, 0x22c4 }, - {-128, 0xFFFF }, -}; -const size_t RF_propTxPower431_527Size = sizeof(RF_propTxPower431_527) / sizeof(RF_propTxPower431_527[0]); -/*---------------------------------------------------------------------------*/ -/** - * @} - */ - -// TI-RTOS RF Mode Object -RF_Mode RF_propMode = -{ - .rfMode = RF_MODE_AUTO, - .cpePatchFxn = &rf_patch_cpe_prop, - .mcePatchFxn = &rf_patch_mce_genfsk, - .rfePatchFxn = &rf_patch_rfe_genfsk, -}; - -// Overrides for CMD_PROP_RADIO_DIV_SETUP -static uint32_t pOverrides[] = -{ - // override_use_patch_prop_genfsk.xml - // PHY: Use MCE RAM patch, RFE RAM patch - MCE_RFE_OVERRIDE(1,0,0,1,0,0), - // override_synth_prop_863_930_div5.xml - // Synth: Use 48 MHz crystal as synth clock, enable extra PLL filtering - (uint32_t)0x02400403, - // Synth: Set minimum RTRIM to 7 - (uint32_t)0x00078793, - // Synth: Configure extra PLL filtering - (uint32_t)0x00108463, - // Synth: Set Fref to 4 MHz - (uint32_t)0x000684A3, - // Synth: Set loop bandwidth after lock to 20 kHz - (uint32_t)0x0A480583, - // Synth: Set loop bandwidth after lock to 20 kHz - (uint32_t)0x7AB80603, - // override_phy_tx_pa_ramp_genfsk.xml - // Tx: Configure PA ramping, set wait time before turning off (0x2F ticks à 16/24 us = 31.3 us). - HW_REG_OVERRIDE(0x6028,0x002F), - // Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[3]=1) - ADI_HALFREG_OVERRIDE(0,16,0x8,0x8), - // Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[4]=1) - ADI_HALFREG_OVERRIDE(0,17,0x1,0x1), - // override_phy_rx_aaf_bw_0xd.xml - // Rx: Set anti-aliasing filter bandwidth to 0xD (in ADI0, set IFAMPCTL3[7:4]=0xD) - ADI_HALFREG_OVERRIDE(0,61,0xF,0xD), - // override_phy_rx_rssi_offset_neg2db.xml - // Rx: Set RSSI offset to adjust reported RSSI by -2 dB - (uint32_t)0x000288A3, - // TX power override - // DC/DC regulator: In Tx with 14 dBm PA setting, use DCDCCTL5[3:0]=0xF (DITHER_EN=1 and IPEAK=7). In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). - (uint32_t)0xFFFC08C3, - (uint32_t)0xFFFFFFFF, -}; - - -// CMD_PROP_RADIO_DIV_SETUP -// Proprietary Mode Radio Setup Command for All Frequency Bands -rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup = -{ - .commandNo = 0x3807, - .status = 0x0000, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .modulation.modType = 0x1, - .modulation.deviation = 0x64, - .symbolRate.preScale = 0xf, - .symbolRate.rateWord = 0x8000, - .rxBw = 0x24, - .preamConf.nPreamBytes = 0x3, - .preamConf.preamMode = 0x0, - .formatConf.nSwBits = 0x18, - .formatConf.bBitReversal = 0x0, - .formatConf.bMsbFirst = 0x1, - .formatConf.fecMode = 0x0, - - /* 7: .4g mode with dynamic whitening and CRC choice */ - .formatConf.whitenMode = 0x7, - .config.frontEndMode = 0x00, /* Set by the driver */ - .config.biasMode = 0x00, /* Set by the driver */ - .config.analogCfgMode = 0x0, - .config.bNoFsPowerUp = 0x0, - .txPower = 0x00, /* Driver sets correct value */ - .pRegOverride = pOverrides, - .intFreq = 0x8000, - .centerFreq = 868, - .loDivider = 0x05, -}; - -// CMD_FS -// Frequency Synthesizer Programming Command -rfc_CMD_FS_t rf_cmd_prop_fs = -{ - .commandNo = 0x0803, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .frequency = 0x0364, - .fractFreq = 0x0000, - .synthConf.bTxMode = 0x0, - .synthConf.refFreq = 0x0, - .__dummy0 = 0x00, - .__dummy1 = 0x00, - .__dummy2 = 0x00, - .__dummy3 = 0x0000, -}; - -/* CMD_PROP_TX_ADV */ -rfc_CMD_PROP_TX_ADV_t rf_cmd_prop_tx_adv = -{ - .commandNo = 0x3803, - .status = 0x0000, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .pktConf.bFsOff = 0x0, - .pktConf.bUseCrc = 0x1, - .pktConf.bCrcIncSw = 0x0, /* .4g mode */ - .pktConf.bCrcIncHdr = 0x0, /* .4g mode */ - .numHdrBits = 0x10 /* 16: .4g mode */, - .pktLen = 0x0000, - .startConf.bExtTxTrig = 0x0, - .startConf.inputMode = 0x0, - .startConf.source = 0x0, - .preTrigger.triggerType = TRIG_NOW, - .preTrigger.bEnaCmd = 0x0, - .preTrigger.triggerNo = 0x0, - .preTrigger.pastTrig = 0x1, - .preTime = 0x00000000, - .syncWord = 0x0055904e, - .pPkt = 0, -}; -/*---------------------------------------------------------------------------*/ -/* CMD_PROP_RX_ADV */ -rfc_CMD_PROP_RX_ADV_t rf_cmd_prop_rx_adv = -{ - .commandNo = 0x3804, - .status = 0x0000, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .pktConf.bFsOff = 0x0, - .pktConf.bRepeatOk = 0x1, - .pktConf.bRepeatNok = 0x1, - .pktConf.bUseCrc = 0x1, - .pktConf.bCrcIncSw = 0x0, /* .4g mode */ - .pktConf.bCrcIncHdr = 0x0, /* .4g mode */ - .pktConf.endType = 0x0, - .pktConf.filterOp = 0x1, - .rxConf.bAutoFlushIgnored = 0x1, - .rxConf.bAutoFlushCrcErr = 0x1, - .rxConf.bIncludeHdr = 0x0, - .rxConf.bIncludeCrc = 0x0, - .rxConf.bAppendRssi = 0x1, - .rxConf.bAppendTimestamp = 0x0, - .rxConf.bAppendStatus = 0x1, - .syncWord0 = 0x0055904e, - .syncWord1 = 0x00000000, - .maxPktLen = 0x0000, /* To be populated by the driver. */ - .hdrConf.numHdrBits = 0x10, /* 16: .4g mode */ - .hdrConf.lenPos = 0x0, /* .4g mode */ - .hdrConf.numLenBits = 0x0B, /* 11 = 0x0B .4g mode */ - .addrConf.addrType = 0x0, - .addrConf.addrSize = 0x0, - .addrConf.addrPos = 0x0, - .addrConf.numAddr = 0x0, - .lenOffset = -4, /* .4g mode */ - .endTrigger.triggerType = TRIG_NEVER, - .endTrigger.bEnaCmd = 0x0, - .endTrigger.triggerNo = 0x0, - .endTrigger.pastTrig = 0x0, - .endTime = 0x00000000, - .pAddr = 0, - .pQueue = 0, - .pOutput = 0, -}; -/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/rf-settings/rf-prop-settings.h b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/rf-settings/rf-prop-settings.h deleted file mode 100644 index 947c5254e..000000000 --- a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/rf-settings/rf-prop-settings.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef RF_PROP_SETTINGS_H_ -#define RF_PROP_SETTINGS_H_ - -//********************************************************************************* -// Generated by SmartRF Studio version 2.8.0 ( build #41) -// Compatible with SimpleLink SDK version: CC13x2 SDK 1.60.xx.xx -// Device: CC1352 Rev. 1.0 -// -//********************************************************************************* -#include -#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) -#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) -#include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h) -#include - -#include - -// RF TX power table -extern RF_TxPower RF_propTxPower779_930[]; -extern const size_t RF_propTxPower779_930Size; - -extern RF_TxPower RF_propTxPower431_527[]; -extern const size_t RF_propTxPower431_527Size; - -// TI-RTOS RF Mode Object -extern RF_Mode RF_propMode; - -// RF Core API commands -extern rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup; -extern rfc_CMD_FS_t rf_cmd_prop_fs; -extern rfc_CMD_PROP_TX_ADV_t rf_cmd_prop_tx_adv; -extern rfc_CMD_PROP_RX_ADV_t rf_cmd_prop_rx_adv; - - -#endif /* RF_PROP_SETTINGS_H_ */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c index 08e95a983..4940ff50b 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c @@ -128,12 +128,16 @@ #ifdef IEEE_MODE_CONF_TX_POWER_TABLE # define TX_POWER_TABLE IEEE_MODE_CONF_TX_POWER_TABLE #else -# define TX_POWER_TABLE ieeeTxPowerTable +# define TX_POWER_TABLE rf_ieee_tx_power_table +#endif + +#ifdef IEEE_MODE_CONF_TX_POWER_TABLE_SIZE +# define TX_POWER_TABLE_SIZE IEEE_MODE_CONF_TX_POWER_TABLE_SIZE +#else +# define TX_POWER_TABLE_SIZE RF_IEEE_TX_POWER_TABLE_SIZE #endif /*---------------------------------------------------------------------------*/ /* TX power table convenience macros */ -#define TX_POWER_TABLE_SIZE ((sizeof(TX_POWER_TABLE) / sizeof(TX_POWER_TABLE[0])) - 1) - #define TX_POWER_MIN (TX_POWER_TABLE[0]) #define TX_POWER_MAX (TX_POWER_TABLE[TX_POWER_TABLE_SIZE - 1]) @@ -160,7 +164,7 @@ /* How long to wait for an ongoing ACK TX to finish before starting frame TX */ #define TIMEOUT_TX_WAIT (RTIMER_SECOND >> 11) -/* How long to wait for the RF to enter RX in RF_cmdIeeeRx */ +/* How long to wait for the RF to enter RX in cmd_rx */ #define TIMEOUT_ENTER_RX_WAIT (RTIMER_SECOND >> 10) /* How long to wait for the RF to react on CMD_ABORT: around 1 msec */ @@ -177,10 +181,10 @@ static RF_Object g_rfObj; static RF_Handle g_rfHandle; /* RF Core command pointers */ -#define cmd_radio_setup ((volatile rfc_CMD_RADIO_SETUP_t*)&RF_cmdRadioSetup) -#define cmd_fs ((volatile rfc_CMD_FS_t*) &RF_cmdIeeeFs) -#define cmd_tx ((volatile rfc_CMD_IEEE_TX_t*) &RF_cmdIeeeTx) -#define cmd_rx ((volatile rfc_CMD_IEEE_RX_t*) &RF_cmdIeeeRx) +#define cmd_radio_setup (*(volatile rfc_CMD_RADIO_SETUP_t*)&rf_cmd_ieee_radio_setup) +#define cmd_fs (*(volatile rfc_CMD_FS_t*) &rf_cmd_ieee_fs) +#define cmd_tx (*(volatile rfc_CMD_IEEE_TX_t*) &rf_cmd_ieee_tx) +#define cmd_rx (*(volatile rfc_CMD_IEEE_RX_t*) &rf_cmd_ieee_rx) /* RF command handles */ static RF_CmdHandle g_cmdTxHandle; @@ -309,11 +313,11 @@ rf_error_cb(RF_Handle h, RF_CmdHandle ch, RF_EventMask e) { // See SWRZ062B: Synth failed to calibrate, CMD_FS must be repeated if ((ch == RF_ERROR_CMDFS_SYNTH_PROG) && - (cmd_fs->status == ERROR_SYNTH_PROG)) { + (cmd_fs.status == ERROR_SYNTH_PROG)) { // Call CMD_FS async, a synth error will trigger rf_error_cb once more const uint8_t stop_gracefully = 1; RF_flushCmd(g_rfHandle, RF_CMDHANDLE_FLUSH_ALL, stop_gracefully); - RF_postCmd(g_rfHandle, (RF_Op*)cmd_fs, RF_PriorityNormal, NULL, 0); + RF_postCmd(g_rfHandle, (RF_Op*)&cmd_fs, RF_PriorityNormal, NULL, 0); } } /*---------------------------------------------------------------------------*/ @@ -339,27 +343,29 @@ init_data_queue(void) static void init_rf_params(void) { - cmd_rx->pRxQ = &g_rxDataQueue; - cmd_rx->pOutput = &g_rxStats; + cmd_rx.channel = RF_CORE_CHANNEL; + + cmd_rx.pRxQ = &g_rxDataQueue; + cmd_rx.pOutput = &g_rxStats; #if IEEE_MODE_PROMISCOUS - cmd_rx->frameFiltOpt.frameFiltEn = 0; + cmd_rx.frameFiltOpt.frameFiltEn = 0; #else - cmd_rx->frameFiltOpt.frameFiltEn = 1; + cmd_rx.frameFiltOpt.frameFiltEn = 1; #endif #if IEEE_MODE_AUTOACK - cmd_rx->frameFiltOpt.autoAckEn = 1; + cmd_rx.frameFiltOpt.autoAckEn = 1; #else - cmd_rx->frameFiltOpt.autoAckEn = 0; + cmd_rx.frameFiltOpt.autoAckEn = 0; #endif - cmd_rx->ccaRssiThr = IEEE_MODE_RSSI_THRESHOLD; + cmd_rx.ccaRssiThr = IEEE_MODE_RSSI_THRESHOLD; // Initialize address filter command g_cmdModFilt.commandNo = CMD_IEEE_MOD_FILT; - memcpy(&g_cmdModFilt.newFrameFiltOpt, &RF_cmdIeeeRx.frameFiltOpt, sizeof(RF_cmdIeeeRx.frameFiltOpt)); - memcpy(&g_cmdModFilt.newFrameTypes, &RF_cmdIeeeRx.frameTypes, sizeof(RF_cmdIeeeRx.frameTypes)); + memcpy(&(g_cmdModFilt.newFrameFiltOpt), &(rf_cmd_ieee_rx.frameFiltOpt), sizeof(rf_cmd_ieee_rx.frameFiltOpt)); + memcpy(&(g_cmdModFilt.newFrameTypes), &(rf_cmd_ieee_rx.frameTypes), sizeof(rf_cmd_ieee_rx.frameTypes)); } /*---------------------------------------------------------------------------*/ static void @@ -394,12 +400,12 @@ set_channel(uint8_t channel) channel, IEEE_MODE_CHANNEL); channel = IEEE_MODE_CHANNEL; } - if (channel == cmd_rx->channel) { + if (channel == cmd_rx.channel) { // We are already calibrated to this channel return true; } - cmd_rx->channel = 0; + cmd_rx.channel = 0; // freq = freq_base + freq_spacing * (channel - channel_min) const uint32_t newFreq = (uint32_t)(IEEE_MODE_FREQ_BASE + IEEE_MODE_FREQ_SPACING * ((uint32_t)channel - IEEE_MODE_CHAN_MIN)); @@ -409,10 +415,10 @@ set_channel(uint8_t channel) PRINTF("set_channel: %d = 0x%04X.0x%04X (%lu)\n", channel, (uint16_t)freq, (uint16_t)frac, newFreq); - cmd_fs->frequency = (uint16_t)freq; - cmd_fs->fractFreq = (uint16_t)frac; + cmd_fs.frequency = (uint16_t)freq; + cmd_fs.fractFreq = (uint16_t)frac; - const bool rx_active = (cmd_rx->status == ACTIVE); + const bool rx_active = (cmd_rx.status == ACTIVE); if (rx_active) { const uint8_t stop_gracefully = 1; @@ -424,16 +430,16 @@ set_channel(uint8_t channel) uint8_t tries = 0; bool cmd_ok = false; do { - events = RF_runCmd(g_rfHandle, (RF_Op*)cmd_fs, RF_PriorityNormal, NULL, 0); + events = RF_runCmd(g_rfHandle, (RF_Op*)&cmd_fs, RF_PriorityNormal, NULL, 0); cmd_ok = ((events & RF_EventLastCmdDone) != 0) - && (cmd_fs->status == DONE_OK); + && (cmd_fs.status == DONE_OK); } while (!cmd_ok && (tries++ < 3)); if (!cmd_ok) { return false; } - cmd_rx->channel = channel; + cmd_rx.channel = channel; if (rx_active) { set_rx(POWER_STATE_ON); @@ -537,7 +543,7 @@ init(void) init_rf_params(); init_data_queue(); - g_rfHandle = RF_open(&g_rfObj, &RF_ieeeMode, (RF_RadioSetup*)cmd_radio_setup, ¶ms); + g_rfHandle = RF_open(&g_rfObj, &rf_ieee_mode, (RF_RadioSetup*)&cmd_radio_setup, ¶ms); assert(g_rfHandle != NULL); set_channel(IEEE_MODE_CHANNEL); @@ -584,7 +590,7 @@ set_rx(const PowerState state) } if (state & POWER_STATE_ON) { - if (cmd_rx->status == ACTIVE) { + if (cmd_rx.status == ACTIVE) { PRINTF("set_rx(on): already in RX\n"); return CMD_RESULT_OK; } @@ -592,8 +598,8 @@ set_rx(const PowerState state) RF_ScheduleCmdParams schedParams; RF_ScheduleCmdParams_init(&schedParams); - cmd_rx->status = IDLE; - g_cmdRxHandle = RF_scheduleCmd(g_rfHandle, (RF_Op*)cmd_rx, &schedParams, rx_cb, + cmd_rx.status = IDLE; + g_cmdRxHandle = RF_scheduleCmd(g_rfHandle, (RF_Op*)&cmd_rx, &schedParams, rx_cb, RF_EventRxOk | RF_EventRxBufFull | RF_EventRxEntryDone); if ((g_cmdRxHandle == RF_ALLOC_ERROR) || (g_cmdRxHandle == RF_SCHEDULE_CMD_ERROR)) { PRINTF("transmit: unable to allocate RX command\n"); @@ -608,22 +614,22 @@ static int transmit_aux(unsigned short transmit_len) { // Configure TX command - cmd_tx->payloadLen = (uint8_t)transmit_len; - cmd_tx->pPayload = &g_txBuf[TX_BUF_HDR_LEN]; - cmd_tx->startTime = 0; - cmd_tx->startTrigger.triggerType = TRIG_NOW; + cmd_tx.payloadLen = (uint8_t)transmit_len; + cmd_tx.pPayload = &g_txBuf[TX_BUF_HDR_LEN]; + cmd_tx.startTime = 0; + cmd_tx.startTrigger.triggerType = TRIG_NOW; RF_ScheduleCmdParams schedParams; RF_ScheduleCmdParams_init(&schedParams); // As IEEE_TX is a FG command, the TX operation will be executed // either way if RX is running or not - cmd_tx->status = IDLE; - g_cmdTxHandle = RF_scheduleCmd(g_rfHandle, (RF_Op*)cmd_tx, &schedParams, NULL, 0); + cmd_tx.status = IDLE; + g_cmdTxHandle = RF_scheduleCmd(g_rfHandle, (RF_Op*)&cmd_tx, &schedParams, NULL, 0); if ((g_cmdTxHandle == RF_ALLOC_ERROR) || (g_cmdTxHandle == RF_SCHEDULE_CMD_ERROR)) { // Failure sending the CMD_IEEE_TX command PRINTF("transmit: failed to allocate TX command cmdHandle=%d, status=%04x\n", - g_cmdTxHandle, cmd_tx->status); + g_cmdTxHandle, cmd_tx.status); return RADIO_TX_ERR; } @@ -633,7 +639,7 @@ transmit_aux(unsigned short transmit_len) RF_EventMask events = RF_pendCmd(g_rfHandle, g_cmdTxHandle, 0); if ((events & (RF_EventFGCmdDone | RF_EventLastFGCmdDone)) == 0) { PRINTF("transmit: TX command error events=0x%08llx, status=0x%04x\n", - events, cmd_tx->status); + events, cmd_tx.status); return RADIO_TX_ERR; } @@ -643,7 +649,7 @@ transmit_aux(unsigned short transmit_len) static int transmit(unsigned short transmit_len) { - const bool was_rx = (cmd_rx->status == ACTIVE); + const bool was_rx = (cmd_rx.status == ACTIVE); if (g_bSendOnCca && channel_clear() != 1) { PRINTF("transmit: channel wasn't clear\n"); @@ -753,7 +759,7 @@ channel_clear_aux(void) static int channel_clear(void) { - const bool was_rx = (cmd_rx->status == ACTIVE); + const bool was_rx = (cmd_rx.status == ACTIVE); if (!was_rx && set_rx(POWER_STATE_ON) != CMD_RESULT_OK) { PRINTF("channel_clear: unable to start RX\n"); return CHANNEL_CLEAR_ERROR; @@ -771,7 +777,7 @@ static int receiving_packet(void) { // If we are not in RX, we are not receiving - if (cmd_rx->status != ACTIVE) { + if (cmd_rx.status != ACTIVE) { PRINTF("receiving_packet: not in RX\n"); return 0; } @@ -873,23 +879,23 @@ get_value(radio_param_t param, radio_value_t *value) return RADIO_RESULT_OK; case RADIO_PARAM_CHANNEL: - *value = (radio_value_t)cmd_rx->channel; + *value = (radio_value_t)cmd_rx.channel; return RADIO_RESULT_OK; case RADIO_PARAM_PAN_ID: - *value = (radio_value_t)cmd_rx->localPanID; + *value = (radio_value_t)cmd_rx.localPanID; return RADIO_RESULT_OK; case RADIO_PARAM_16BIT_ADDR: - *value = (radio_value_t)cmd_rx->localShortAddr; + *value = (radio_value_t)cmd_rx.localShortAddr; return RADIO_RESULT_OK; case RADIO_PARAM_RX_MODE: *value = 0; - if (cmd_rx->frameFiltOpt.frameFiltEn) { + if (cmd_rx.frameFiltOpt.frameFiltEn) { *value |= (radio_value_t)RADIO_RX_MODE_ADDRESS_FILTER; } - if (cmd_rx->frameFiltOpt.autoAckEn) { + if (cmd_rx.frameFiltOpt.autoAckEn) { *value |= (radio_value_t)RADIO_RX_MODE_AUTOACK; } if (g_bPollMode) { @@ -908,7 +914,7 @@ get_value(radio_param_t param, radio_value_t *value) : RADIO_RESULT_OK; case RADIO_PARAM_CCA_THRESHOLD: - *value = cmd_rx->ccaRssiThr; + *value = cmd_rx.ccaRssiThr; return RADIO_RESULT_OK; case RADIO_PARAM_RSSI: @@ -972,7 +978,7 @@ set_value(radio_param_t param, radio_value_t value) return RADIO_RESULT_OK; case RADIO_PARAM_PAN_ID: - cmd_rx->localPanID = (uint16_t)value; + cmd_rx.localPanID = (uint16_t)value; if (rf_is_on() && set_rx(POWER_STATE_RESTART) != CMD_RESULT_OK) { PRINTF("failed to restart RX"); return RADIO_RESULT_ERROR; @@ -980,7 +986,7 @@ set_value(radio_param_t param, radio_value_t value) return RADIO_RESULT_OK; case RADIO_PARAM_16BIT_ADDR: - cmd_rx->localShortAddr = (uint16_t)value; + cmd_rx.localShortAddr = (uint16_t)value; if (rf_is_on() && set_rx(POWER_STATE_RESTART) != CMD_RESULT_OK) { PRINTF("failed to restart RX"); return RADIO_RESULT_ERROR; @@ -993,21 +999,21 @@ set_value(radio_param_t param, radio_value_t value) return RADIO_RESULT_INVALID_VALUE; } - cmd_rx->frameFiltOpt.frameFiltEn = (value & RADIO_RX_MODE_ADDRESS_FILTER) != 0; - cmd_rx->frameFiltOpt.frameFiltStop = 1; - cmd_rx->frameFiltOpt.autoAckEn = (value & RADIO_RX_MODE_AUTOACK) != 0; - cmd_rx->frameFiltOpt.slottedAckEn = 0; - cmd_rx->frameFiltOpt.autoPendEn = 0; - cmd_rx->frameFiltOpt.defaultPend = 0; - cmd_rx->frameFiltOpt.bPendDataReqOnly = 0; - cmd_rx->frameFiltOpt.bPanCoord = 0; - cmd_rx->frameFiltOpt.bStrictLenFilter = 0; + cmd_rx.frameFiltOpt.frameFiltEn = (value & RADIO_RX_MODE_ADDRESS_FILTER) != 0; + cmd_rx.frameFiltOpt.frameFiltStop = 1; + cmd_rx.frameFiltOpt.autoAckEn = (value & RADIO_RX_MODE_AUTOACK) != 0; + cmd_rx.frameFiltOpt.slottedAckEn = 0; + cmd_rx.frameFiltOpt.autoPendEn = 0; + cmd_rx.frameFiltOpt.defaultPend = 0; + cmd_rx.frameFiltOpt.bPendDataReqOnly = 0; + cmd_rx.frameFiltOpt.bPanCoord = 0; + cmd_rx.frameFiltOpt.bStrictLenFilter = 0; const bool bOldPollMode = g_bPollMode; g_bPollMode = (value & RADIO_RX_MODE_POLL_MODE) != 0; if (g_bPollMode == bOldPollMode) { // Do not turn the radio off and on, just send an update command - memcpy(&g_cmdModFilt.newFrameFiltOpt, &RF_cmdIeeeRx.frameFiltOpt, sizeof(RF_cmdIeeeRx.frameFiltOpt)); + memcpy(&g_cmdModFilt.newFrameFiltOpt, &(rf_cmd_ieee_rx.frameFiltOpt), sizeof(rf_cmd_ieee_rx.frameFiltOpt)); const RF_Stat stat = RF_runImmediateCmd(g_rfHandle, (uint32_t*)&g_cmdModFilt); if (stat != RF_StatCmdDoneSuccess) { PRINTF("setting address filter failed: stat=0x%02X\n", stat); @@ -1038,7 +1044,7 @@ set_value(radio_param_t param, radio_value_t value) : RADIO_RESULT_OK; case RADIO_PARAM_CCA_THRESHOLD: - cmd_rx->ccaRssiThr = (int8_t)value; + cmd_rx.ccaRssiThr = (int8_t)value; if (rf_is_on() && set_rx(POWER_STATE_RESTART) != CMD_RESULT_OK) { PRINTF("failed to restart RX"); return RADIO_RESULT_ERROR; @@ -1059,12 +1065,12 @@ get_object(radio_param_t param, void *dest, size_t size) switch (param) { case RADIO_PARAM_64BIT_ADDR: { - const size_t srcSize = sizeof(cmd_rx->localExtAddr); + const size_t srcSize = sizeof(cmd_rx.localExtAddr); if(size != srcSize) { return RADIO_RESULT_INVALID_VALUE; } - const uint8_t *pSrc = (uint8_t *)&(cmd_rx->localExtAddr); + const uint8_t *pSrc = (uint8_t *)&(cmd_rx.localExtAddr); uint8_t *pDest = dest; for(size_t i = 0; i < srcSize; ++i) { pDest[i] = pSrc[srcSize - 1 - i]; @@ -1095,18 +1101,18 @@ set_object(radio_param_t param, const void *src, size_t size) switch (param) { case RADIO_PARAM_64BIT_ADDR: { - const size_t destSize = sizeof(cmd_rx->localExtAddr); + const size_t destSize = sizeof(cmd_rx.localExtAddr); if (size != destSize) { return RADIO_RESULT_INVALID_VALUE; } const uint8_t *pSrc = (const uint8_t *)src; - uint8_t *pDest = (uint8_t *)&cmd_rx->localExtAddr; + uint8_t *pDest = (uint8_t *)&(cmd_rx.localExtAddr); for (size_t i = 0; i < destSize; ++i) { pDest[i] = pSrc[destSize - 1 - i]; } - const bool is_rx = (cmd_rx->status == ACTIVE); + const bool is_rx = (cmd_rx.status == ACTIVE); if (is_rx && set_rx(POWER_STATE_RESTART) != CMD_RESULT_OK) { return RADIO_RESULT_ERROR; } diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c index be893e8bc..70d355623 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c @@ -209,10 +209,10 @@ volatile static uint8_t *rx_read_entry; static uint8_t tx_buf[TX_BUF_HDR_LEN + TX_BUF_PAYLOAD_LEN] CC_ALIGN(4); /*---------------------------------------------------------------------------*/ -#define cmd_radio_setup ((volatile rfc_CMD_PROP_RADIO_DIV_SETUP_t *)&RF_cmdPropRadioDivSetup) -#define cmd_fs ((volatile rfc_CMD_FS_t *)&RF_cmdPropFs) -#define cmd_tx ((volatile rfc_CMD_PROP_TX_ADV_t *)&RF_cmdPropTxAdv) -#define cmd_rx ((volatile rfc_CMD_PROP_RX_ADV_t *)&RF_cmdPropRxAdv) +#define cmd_radio_setup ((volatile rfc_CMD_PROP_RADIO_DIV_SETUP_t *)&rf_cmd_prop_radio_div_setup) +#define cmd_fs ((volatile rfc_CMD_FS_t *) &rf_cmd_prop_fs) +#define cmd_tx ((volatile rfc_CMD_PROP_TX_ADV_t *) &rf_cmd_prop_tx_adv) +#define cmd_rx ((volatile rfc_CMD_PROP_RX_ADV_t *) &rf_cmd_prop_rx_adv) /*---------------------------------------------------------------------------*/ /* RF driver */ static RF_Object rfObject; @@ -777,7 +777,7 @@ rf_init(void) // Disable automatic power-down just to not interfere with stack timing params.nInactivityTimeout = 0; - rfHandle = RF_open(&rfObject, &RF_propMode, (RF_RadioSetup*)cmd_radio_setup, ¶ms); + rfHandle = RF_open(&rfObject, &rf_prop_mode, (RF_RadioSetup*)cmd_radio_setup, ¶ms); assert(rfHandle != NULL); /* Initialise RX buffers */ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c index b6f05f337..0acff3cbf 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c @@ -1,4 +1,33 @@ -//********************************************************************************* +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ // Parameter summary // IEEE Channel: 11 // Frequency: 2405 MHz @@ -6,9 +35,9 @@ // Packet Data: 255 // Preamble (32 bit): 01010101... // TX Power: 5 dBm - +/*---------------------------------------------------------------------------*/ #include "sys/cc.h" - +/*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) @@ -17,26 +46,24 @@ #include "driverlib/rf_ieee_cmd.h" #include - +/*---------------------------------------------------------------------------*/ #include "ieee-settings.h" - - +/*---------------------------------------------------------------------------*/ // TI-RTOS RF Mode Object -RF_Mode RF_ieeeMode = +RF_Mode rf_ieee_mode = { .rfMode = RF_MODE_IEEE_15_4, .cpePatchFxn = 0, .mcePatchFxn = 0, .rfePatchFxn = 0, }; - - +/*---------------------------------------------------------------------------*/ // TX Power table // The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: // RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) // See the Technical Reference Manual for further details about the "txPower" Command field. // The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. -RF_TxPowerTable_Entry ieeeTxPowerTable[14] = +RF_TxPowerTable_Entry rf_ieee_tx_power_table[RF_IEEE_TX_POWER_TABLE_SIZE+1] = { { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 6) }, { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 6) }, @@ -53,10 +80,9 @@ RF_TxPowerTable_Entry ieeeTxPowerTable[14] = { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(48, 0, 1, 73) }, RF_TxPowerTable_TERMINATION_ENTRY }; - - +/*---------------------------------------------------------------------------*/ // Overrides for CMD_RADIO_SETUP (CC2650) -uint32_t pIeeeOverrides[] CC_ALIGN(4) = +uint32_t rf_ieee_overrides[] CC_ALIGN(4) = { // override_synth_ieee_15_4.xml HW_REG_OVERRIDE(0x4038,0x0035), // Synth: Set recommended RTRIM to 5 @@ -81,10 +107,9 @@ uint32_t pIeeeOverrides[] CC_ALIGN(4) = HW_REG_OVERRIDE(0x50DC,0x002B), // Rx: Adjust AGC DC filter (uint32_t)0xFFFFFFFF, }; - - +/*---------------------------------------------------------------------------*/ // Old override list -uint32_t pIeeeOverridesOld[] CC_ALIGN(4) = +uint32_t rf_ieee_overrides_old[] CC_ALIGN(4) = { (uint32_t)0x00354038, /* Synth: Set RTRIM (POTAILRESTRIM) to 5 */ (uint32_t)0x4001402D, /* Synth: Correct CKVD latency setting (address) */ @@ -100,47 +125,46 @@ uint32_t pIeeeOverridesOld[] CC_ALIGN(4) = (uint32_t)0x002082C3, /* Increase synth programming timeout */ (uint32_t)0xFFFFFFFF, }; - - +/*---------------------------------------------------------------------------*/ // CMD_RADIO_SETUP // Radio Setup Command for Pre-Defined Schemes -rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup = +rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup = { - .commandNo = 0x0802, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .commandNo = CMD_RADIO_SETUP, + .status = IDLE, + .pNextOp = 0, .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, + .startTrigger.triggerType = TRIG_NOW, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, .mode = 0x01, .config.frontEndMode = 0x0, - .config.biasMode = 0x0, + .config.biasMode = 0x1, .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, - .txPower = 0x9330, - .pRegOverride = pIeeeOverrides, + .txPower = 0x9330, /* 5 dBm default */ + .pRegOverride = rf_ieee_overrides, }; - +/*---------------------------------------------------------------------------*/ // CMD_FS // Frequency Synthesizer Programming Command -rfc_CMD_FS_t RF_cmdIeeeFs = +rfc_CMD_FS_t rf_cmd_ieee_fs = { - .commandNo = 0x0803, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .commandNo = CMD_FS, + .status = IDLE, + .pNextOp = 0, .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, + .startTrigger.triggerType = TRIG_NOW, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, - .frequency = 0x0965, - .fractFreq = 0x0000, + .frequency = 0x0965, /* set by driver */ + .fractFreq = 0x0000, /* set by driver */ .synthConf.bTxMode = 0x1, .synthConf.refFreq = 0x0, .__dummy0 = 0x00, @@ -148,63 +172,63 @@ rfc_CMD_FS_t RF_cmdIeeeFs = .__dummy2 = 0x00, .__dummy3 = 0x0000, }; - +/*---------------------------------------------------------------------------*/ // CMD_IEEE_TX // The command ID number 0x2C01 -rfc_CMD_IEEE_TX_t RF_cmdIeeeTx = +rfc_CMD_IEEE_TX_t rf_cmd_ieee_tx = { - .commandNo = 0x2C01, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .commandNo = CMD_IEEE_TX, + .status = IDLE, + .pNextOp = 0, .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, + .startTrigger.triggerType = TRIG_NOW, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, .txOpt.bIncludePhyHdr = 0x0, .txOpt.bIncludeCrc = 0x0, .txOpt.payloadLenMsb = 0x0, - .payloadLen = 0x1E, - .pPayload = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .payloadLen = 0x0, /* set by driver */ + .pPayload = 0, /* set by driver */ .timeStamp = 0x00000000, }; - +/*---------------------------------------------------------------------------*/ // CMD_IEEE_RX // The command ID number 0x2801 -rfc_CMD_IEEE_RX_t RF_cmdIeeeRx = +rfc_CMD_IEEE_RX_t rf_cmd_ieee_xx = { - .commandNo = 0x2801, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .commandNo = CMD_IEEE_RX, + .status = IDLE, + .pNextOp = 0, .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, + .startTrigger.triggerType = TRIG_NOW, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, - .channel = 0x00, - .rxConfig.bAutoFlushCrc = 0x0, + .channel = 0x00, /* set by driver */ + .rxConfig.bAutoFlushCrc = 0x1, .rxConfig.bAutoFlushIgn = 0x0, .rxConfig.bIncludePhyHdr = 0x0, - .rxConfig.bIncludeCrc = 0x0, + .rxConfig.bIncludeCrc = 0x1, .rxConfig.bAppendRssi = 0x1, .rxConfig.bAppendCorrCrc = 0x1, .rxConfig.bAppendSrcInd = 0x0, - .rxConfig.bAppendTimestamp = 0x0, - .pRxQ = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx - .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .frameFiltOpt.frameFiltEn = 0x0, - .frameFiltOpt.frameFiltStop = 0x0, - .frameFiltOpt.autoAckEn = 0x0, + .rxConfig.bAppendTimestamp = 0x1, + .pRxQ = 0, /* set by driver */ + .pOutput = 0, /* set by driver */ + .frameFiltOpt.frameFiltEn = 0x0, /* set by driver */ + .frameFiltOpt.frameFiltStop = 0x1, + .frameFiltOpt.autoAckEn = 0x0, /* set by driver */ .frameFiltOpt.slottedAckEn = 0x0, .frameFiltOpt.autoPendEn = 0x0, .frameFiltOpt.defaultPend = 0x0, .frameFiltOpt.bPendDataReqOnly = 0x0, .frameFiltOpt.bPanCoord = 0x0, - .frameFiltOpt.maxFrameVersion = 0x3, + .frameFiltOpt.maxFrameVersion = 0x2, .frameFiltOpt.fcfReservedMask = 0x0, .frameFiltOpt.modifyFtFilter = 0x0, .frameFiltOpt.bStrictLenFilter = 0x0, @@ -216,25 +240,26 @@ rfc_CMD_IEEE_RX_t RF_cmdIeeeRx = .frameTypes.bAcceptFt5Reserved = 0x1, .frameTypes.bAcceptFt6Reserved = 0x1, .frameTypes.bAcceptFt7Reserved = 0x1, - .ccaOpt.ccaEnEnergy = 0x0, - .ccaOpt.ccaEnCorr = 0x0, - .ccaOpt.ccaEnSync = 0x0, + .ccaOpt.ccaEnEnergy = 0x1, + .ccaOpt.ccaEnCorr = 0x1, + .ccaOpt.ccaEnSync = 0x1, .ccaOpt.ccaCorrOp = 0x1, - .ccaOpt.ccaSyncOp = 0x1, - .ccaOpt.ccaCorrThr = 0x0, - .ccaRssiThr = 0x64, + .ccaOpt.ccaSyncOp = 0x0, + .ccaOpt.ccaCorrThr = 0x3, + .ccaRssiThr = 0x0, /* set by driver */ .__dummy0 = 0x00, .numExtEntries = 0x00, .numShortEntries = 0x00, - .pExtEntryList = 0, // INSERT APPLICABLE POINTER: (uint32_t*)&xxx - .pShortEntryList = 0, // INSERT APPLICABLE POINTER: (uint32_t*)&xxx - .localExtAddr = 0x0000000012345678, - .localShortAddr = 0xABBA, + .pExtEntryList = 0, + .pShortEntryList = 0, + .localExtAddr = 0x0, /* set by driver */ + .localShortAddr = 0x0, /* set by driver */ .localPanID = 0x0000, .__dummy1 = 0x000000, - .endTrigger.triggerType = 0x1, + .endTrigger.triggerType = TRIG_NEVER, .endTrigger.bEnaCmd = 0x0, .endTrigger.triggerNo = 0x0, .endTrigger.pastTrig = 0x0, .endTime = 0x00000000, }; +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h index 01b773215..20f4e2656 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h @@ -1,12 +1,36 @@ -#ifndef _IEEE_SETTINGS_H_ -#define _IEEE_SETTINGS_H_ - -//********************************************************************************* -// Generated by SmartRF Studio version 2.9.0 (build#85) -// Compatible with SimpleLink SDK version: No known SDK for this device -// Device: CC2650 Rev. 2.2 -// -//********************************************************************************* +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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 IEEE_SETTINGS_H_ +#define IEEE_SETTINGS_H_ +/*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) @@ -16,26 +40,23 @@ #include "driverlib/rf_ieee_mailbox.h" #include - - +/*---------------------------------------------------------------------------*/ // TI-RTOS RF Mode Object -extern RF_Mode RF_ieeeMode; - - +extern RF_Mode rf_ieee_mode; +/*---------------------------------------------------------------------------*/ // TX Power Table -extern RF_TxPowerTable_Entry ieeeTxPowerTable[14]; - +#define RF_IEEE_TX_POWER_TABLE_SIZE 13 +extern RF_TxPowerTable_Entry rf_ieee_tx_power_table[RF_IEEE_TX_POWER_TABLE_SIZE+1]; +/*---------------------------------------------------------------------------*/ // RF Core API commands -extern rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup; -extern rfc_CMD_FS_t RF_cmdIeeeFs; -extern rfc_CMD_IEEE_TX_t RF_cmdIeeeTx; -extern rfc_CMD_IEEE_RX_t RF_cmdIeeeRx; - - +extern rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup; +extern rfc_CMD_FS_t rf_cmd_ieee_fs; +extern rfc_CMD_IEEE_TX_t rf_cmd_ieee_tx; +extern rfc_CMD_IEEE_RX_t rf_cmd_ieee_xx; +/*---------------------------------------------------------------------------*/ // RF Core API Overrides -extern uint32_t pIeeeOverrides[]; - - -#endif // _IEEE_SETTINGS_H_ - +extern uint32_t rf_ieee_overrides[]; +/*---------------------------------------------------------------------------*/ +#endif /* IEEE_SETTINGS_H_ */ +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c index 702295391..e0608075a 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c @@ -1,12 +1,33 @@ -//********************************************************************************* -// Generated by SmartRF Studio version 2.9.0 (build#85) -// Compatible with SimpleLink SDK version: CC13x0 SDK 2.10.xx.xx -// Device: CC1350 Rev. 2.1 -// -//********************************************************************************* - - -//********************************************************************************* +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ // Parameter summary // Address: 0 // Address0: 0xAA @@ -26,9 +47,9 @@ // Sync Word Length: 24 Bits // TX Power: 14 dBm (requires define CCFG_FORCE_VDDR_HH = 1 in ccfg.c, see CC13xx/CC26xx Technical Reference Manual) // Whitening: Dynamically IEEE 802.15.4g compatible whitener and 16/32-bit CRC - +/*---------------------------------------------------------------------------*/ #include "sys/cc.h" - +/*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) @@ -37,26 +58,24 @@ #include DeviceFamily_constructPath(rf_patches/rf_patch_rfe_genfsk.h) #include - +/*---------------------------------------------------------------------------*/ #include "prop-settings.h" - - +/*---------------------------------------------------------------------------*/ // TI-RTOS RF Mode Object -RF_Mode RF_propMode = +RF_Mode rf_prop_mode = { .rfMode = RF_MODE_PROPRIETARY_SUB_1, .cpePatchFxn = &rf_patch_cpe_genfsk, .mcePatchFxn = 0, .rfePatchFxn = &rf_patch_rfe_genfsk, }; - - +/*---------------------------------------------------------------------------*/ // TX Power table // The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: // RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) // See the Technical Reference Manual for further details about the "txPower" Command field. // The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. -RF_TxPowerTable_Entry propTxPowerTable[16] = +RF_TxPowerTable_Entry rf_prop_tx_power_table[RF_PROP_TX_POWER_TABLE_SIZE+1] = { { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY( 0, 3, 0, 2) }, { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY( 3, 3, 0, 9) }, @@ -76,10 +95,9 @@ RF_TxPowerTable_Entry propTxPowerTable[16] = { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 85) }, RF_TxPowerTable_TERMINATION_ENTRY }; - - +/*---------------------------------------------------------------------------*/ // Overrides for CMD_PROP_RADIO_DIV_SETUP -uint32_t pPropOverrides[] CC_ALIGN(4) = +uint32_t p_prop_overrides[] CC_ALIGN(4) = { // override_use_patch_prop_genfsk.xml MCE_RFE_OVERRIDE(0,4,0,1,0,0), // PHY: Use MCE ROM bank 4, RFE RAM patch @@ -114,15 +132,14 @@ uint32_t pPropOverrides[] CC_ALIGN(4) = ADI_REG_OVERRIDE(0,12,0xF8), // Tx: Set PA trim to max (in ADI0, set PACTL0=0xF8) (uint32_t)0xFFFFFFFF, }; - - +/*---------------------------------------------------------------------------*/ // CMD_PROP_RADIO_DIV_SETUP // Proprietary Mode Radio Setup Command for All Frequency Bands -rfc_CMD_PROP_RADIO_DIV_SETUP_t RF_cmdPropRadioDivSetup = +rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup = { .commandNo = 0x3807, .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .pNextOp = 0, .startTime = 0x00000000, .startTrigger.triggerType = 0x0, .startTrigger.bEnaCmd = 0x0, @@ -134,7 +151,7 @@ rfc_CMD_PROP_RADIO_DIV_SETUP_t RF_cmdPropRadioDivSetup = .modulation.deviation = 0x64, .symbolRate.preScale = 0xF, .symbolRate.rateWord = 0x8000, - .rxBw = 0x24, + .rxBw = 0x52, .preamConf.nPreamBytes = 0x3, .preamConf.preamMode = 0x0, .formatConf.nSwBits = 0x18, @@ -152,14 +169,14 @@ rfc_CMD_PROP_RADIO_DIV_SETUP_t RF_cmdPropRadioDivSetup = .intFreq = 0x8000, .loDivider = 0x05, }; - +/*---------------------------------------------------------------------------*/ // CMD_FS // Frequency Synthesizer Programming Command -rfc_CMD_FS_t RF_cmdPropFs = +rfc_CMD_FS_t rf_cmd_prop_fs = { .commandNo = 0x0803, .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .pNextOp = 0, .startTime = 0x00000000, .startTrigger.triggerType = 0x0, .startTrigger.bEnaCmd = 0x0, @@ -176,14 +193,14 @@ rfc_CMD_FS_t RF_cmdPropFs = .__dummy2 = 0x00, .__dummy3 = 0x0000, }; - +/*---------------------------------------------------------------------------*/ // CMD_PROP_TX_ADV // Proprietary Mode Advanced Transmit Command -rfc_CMD_PROP_TX_ADV_t RF_cmdPropTxAdv = +rfc_CMD_PROP_TX_ADV_t rf_cmd_prop_tx_adv = { - .commandNo = 0x3803, + .commandNo = CMD_PROP_TX_ADV, .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .pNextOp = 0, .startTime = 0x00000000, .startTrigger.triggerType = 0x2, .startTrigger.bEnaCmd = 0x0, @@ -200,61 +217,62 @@ rfc_CMD_PROP_TX_ADV_t RF_cmdPropTxAdv = .startConf.bExtTxTrig = 0x0, .startConf.inputMode = 0x0, .startConf.source = 0x0, - .preTrigger.triggerType = 0x4, + .preTrigger.triggerType = TRIG_REL_START, .preTrigger.bEnaCmd = 0x0, .preTrigger.triggerNo = 0x0, .preTrigger.pastTrig = 0x1, .preTime = 0x00000000, .syncWord = 0x0055904E, - .pPkt = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .pPkt = 0, /* set by driver */ }; - +/*---------------------------------------------------------------------------*/ // CMD_PROP_RX_ADV // Proprietary Mode Advanced Receive Command -rfc_CMD_PROP_RX_ADV_t RF_cmdPropRxAdv = +rfc_CMD_PROP_RX_ADV_t rf_cmd_prop_rx_adv = { - .commandNo = 0x3804, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .commandNo = CMD_PROP_RX_ADV, + .status = IDLE, + .pNextOp = 0, .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, + .startTrigger.triggerType = TRIG_NOW, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, .pktConf.bFsOff = 0x0, - .pktConf.bRepeatOk = 0x0, - .pktConf.bRepeatNok = 0x0, - .pktConf.bUseCrc = 0x0, + .pktConf.bRepeatOk = 0x1, + .pktConf.bRepeatNok = 0x1, + .pktConf.bUseCrc = 0x1, .pktConf.bCrcIncSw = 0x0, .pktConf.bCrcIncHdr = 0x0, .pktConf.endType = 0x0, - .pktConf.filterOp = 0x0, - .rxConf.bAutoFlushIgnored = 0x0, - .rxConf.bAutoFlushCrcErr = 0x0, + .pktConf.filterOp = 0x1, + .rxConf.bAutoFlushIgnored = 0x1, + .rxConf.bAutoFlushCrcErr = 0x1, .rxConf.bIncludeHdr = 0x0, .rxConf.bIncludeCrc = 0x0, - .rxConf.bAppendRssi = 0x0, + .rxConf.bAppendRssi = 0x1, .rxConf.bAppendTimestamp = 0x0, - .rxConf.bAppendStatus = 0x0, - .syncWord0 = 0x930B51DE, + .rxConf.bAppendStatus = 0x1, + .syncWord0 = 0x0055904E, .syncWord1 = 0x00000000, - .maxPktLen = 0x00FF, - .hdrConf.numHdrBits = 0x0, + .maxPktLen = 0x0, /* set by driver */ + .hdrConf.numHdrBits = 0x10, .hdrConf.lenPos = 0x0, - .hdrConf.numLenBits = 0x0, + .hdrConf.numLenBits = 0x0B, .addrConf.addrType = 0x0, .addrConf.addrSize = 0x0, .addrConf.addrPos = 0x0, .addrConf.numAddr = 0x0, - .lenOffset = 0x00, - .endTrigger.triggerType = 0x0, + .lenOffset = 0xFC, + .endTrigger.triggerType = TRIG_NEVER, .endTrigger.bEnaCmd = 0x0, .endTrigger.triggerNo = 0x0, .endTrigger.pastTrig = 0x0, .endTime = 0x00000000, - .pAddr = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .pQueue = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx - .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .pAddr = 0, /* set by driver */ + .pQueue = 0, /* set by driver */ + .pOutput = 0, /* set by driver */ }; +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h index 85fedc8fd..ec580734d 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h @@ -1,38 +1,58 @@ -#ifndef _PROP_SETTINGS_H_ -#define _PROP_SETTINGS_H_ - -//********************************************************************************* -// Generated by SmartRF Studio version 2.9.0 (build#85) -// Compatible with SimpleLink SDK version: CC13x0 SDK 2.10.xx.xx -// Device: CC1350 Rev. 2.1 -// -//********************************************************************************* +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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 PROP_SETTINGS_H_ +#define PROP_SETTINGS_H_ +/*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) #include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h) #include - - +/*---------------------------------------------------------------------------*/ // TI-RTOS RF Mode Object -extern RF_Mode RF_propMode; - - +extern RF_Mode rf_prop_mode; +/*---------------------------------------------------------------------------*/ // TX Power Table -extern RF_TxPowerTable_Entry propTxPowerTable[16]; - - +#define RF_PROP_TX_POWER_TABLE_SIZE 15 +extern RF_TxPowerTable_Entry rf_prop_tx_power_table[PROP_TX_POWER_TABLE_SIZE+1]; +/*---------------------------------------------------------------------------*/ // RF Core API commands -extern rfc_CMD_PROP_RADIO_DIV_SETUP_t RF_cmdPropRadioDivSetup; -extern rfc_CMD_FS_t RF_cmdPropFs; -extern rfc_CMD_PROP_TX_ADV_t RF_cmdPropTxAdv; -extern rfc_CMD_PROP_RX_ADV_t RF_cmdPropRxAdv; - - +extern rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup; +extern rfc_CMD_FS_t rf_cmd_prop_fs; +extern rfc_CMD_PROP_TX_ADV_t rf_cmd_prop_tx_adv; +extern rfc_CMD_PROP_RX_ADV_t rf_cmd_prop_rx_adv; +/*---------------------------------------------------------------------------*/ // RF Core API Overrides -extern uint32_t pPropOverrides[]; - - -#endif // _PROP_SETTINGS_H_ - +extern uint32_t p_prop_overrides[]; +/*---------------------------------------------------------------------------*/ +#endif /* PROP_SETTINGS_H_ */ +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c index efb1882da..efa12e2f6 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c @@ -1,12 +1,33 @@ -//********************************************************************************* -// Generated by SmartRF Studio version 2.9.0 (build#85) -// Compatible with SimpleLink SDK version: CC13x2 SDK 2.10.xx.xx -// Device: CC1352P Rev. 1.1 -// -//********************************************************************************* - - -//********************************************************************************* +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ // Parameter summary // IEEE Channel: 11 // Frequency: 2405 MHz @@ -19,9 +40,9 @@ // For High PA: // TX Power: 20 dBm (requires define CCFG_FORCE_VDDR_HH = 0 in ccfg.c, see CC13xx/CC26xx Technical Reference Manual) // Enable high output power PA: true - +/*---------------------------------------------------------------------------*/ #include "sys/cc.h" - +/*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) @@ -30,26 +51,24 @@ #include DeviceFamily_constructPath(rf_patches/rf_patch_mce_ieee_802_15_4.h) #include - +/*---------------------------------------------------------------------------*/ #include "ieee-settings.h" - - +/*---------------------------------------------------------------------------*/ // TI-RTOS RF Mode Object -RF_Mode RF_ieeeMode = +RF_Mode rf_ieee_mode = { .rfMode = RF_MODE_AUTO, .cpePatchFxn = &rf_patch_cpe_ieee_802_15_4, .mcePatchFxn = &rf_patch_mce_ieee_802_15_4, .rfePatchFxn = 0, }; - - +/*---------------------------------------------------------------------------*/ // TX Power table // The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: // RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) // See the Technical Reference Manual for further details about the "txPower" Command field. // The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. -RF_TxPowerTable_Entry ieeeDefaultPaTxPowerTable[16] = +RF_TxPowerTable_Entry rf_ieee_tx_power_table_default_pa[RF_IEEE_TX_POWER_TABLE_DEFAULT_PA_SIZE+1] = { { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 3) }, { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 3) }, @@ -68,14 +87,13 @@ RF_TxPowerTable_Entry ieeeDefaultPaTxPowerTable[16] = { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, RF_TxPowerTable_TERMINATION_ENTRY }; - - +/*---------------------------------------------------------------------------*/ // TX Power table // The RF_TxPowerTable_HIGH_PA_ENTRY macro is defined in RF.h and requires the following arguments: // RF_TxPowerTable_HIGH_PA_ENTRY(bias, ibboost, boost, coefficient, ldoTrim) // See the Technical Reference Manual for further details about the "txPower" Command field. // The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. -RF_TxPowerTable_Entry ieeeHighPaTxPowerTable[16] = +RF_TxPowerTable_Entry rf_ieee_tx_power_table_high_pa[RF_IEEE_TX_POWER_TABLE_HIGH_PA_SIZE+1] = { { 0, RF_TxPowerTable_HIGH_PA_ENTRY(29, 0, 1, 17, 1) }, { 3, RF_TxPowerTable_HIGH_PA_ENTRY(39, 0, 1, 20, 1) }, @@ -94,10 +112,9 @@ RF_TxPowerTable_Entry ieeeHighPaTxPowerTable[16] = { 20, RF_TxPowerTable_HIGH_PA_ENTRY(56, 2, 1, 45, 63) }, RF_TxPowerTable_TERMINATION_ENTRY }; - - +/*---------------------------------------------------------------------------*/ // Overrides for CMD_RADIO_SETUP -uint32_t pIeeeDefaultPaOverrides[] CC_ALIGN(4) = +uint32_t rf_ieee_overrides_default_pa[] CC_ALIGN(4) = { // override_ieee_802_15_4.xml MCE_RFE_OVERRIDE(1,0,0,0,1,0), // PHY: Use MCE RAM patch, RFE ROM bank 1 @@ -116,10 +133,9 @@ uint32_t pIeeeDefaultPaOverrides[] CC_ALIGN(4) = (uint32_t)0x000F8883, // Rx: Set LNA bias current offset to +15 to saturate trim to max (default: 0) (uint32_t)0xFFFFFFFF, }; - - +/*---------------------------------------------------------------------------*/ // Overrides for CMD_RADIO_SETUP -uint32_t pIeeeHighPaOverrides[] CC_ALIGN(4) = +uint32_t rf_ieee_overrides_high_pa[] CC_ALIGN(4) = { // override_ieee_802_15_4.xml MCE_RFE_OVERRIDE(1,0,0,0,1,0), // PHY: Use MCE RAM patch, RFE ROM bank 1 @@ -141,21 +157,20 @@ uint32_t pIeeeHighPaOverrides[] CC_ALIGN(4) = (uint32_t)0xFD6EE02B, // txHighPA=0x3F5BB8 (uint32_t)0xFFFFFFFF, }; - - +/*---------------------------------------------------------------------------*/ // CMD_RADIO_SETUP // Radio Setup Command for Pre-Defined Schemes -rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup = +rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup = { - .commandNo = 0x0802, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .commandNo = CMD_RADIO_SETUP, + .status = IDLE, + .pNextOp = 0, .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, + .startTrigger.triggerType = TRIG_NOW, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, .mode = 0x01, .loDivider = 0x00, @@ -163,26 +178,26 @@ rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup = .config.biasMode = 0x1, .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, - .txPower = 0x941E, - .pRegOverride = pIeeeDefaultPaOverrides, + .txPower = 0x941E, /* 5 dBm default */ + .pRegOverride = rf_ieee_overrides_default_pa, }; - +/*---------------------------------------------------------------------------*/ // CMD_FS // Frequency Synthesizer Programming Command -rfc_CMD_FS_t RF_cmdIeeeFs = +rfc_CMD_FS_t rf_cmd_ieee_fs = { - .commandNo = 0x0803, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .commandNo = CMD_FS, + .status = IDLE, + .pNextOp = 0, .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, + .startTrigger.triggerType = TRIG_NOW, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, - .frequency = 0x0965, - .fractFreq = 0x0000, + .frequency = 0x0965, /* set by driver */ + .fractFreq = 0x0000, /* set by driver */ .synthConf.bTxMode = 0x1, .synthConf.refFreq = 0x0, .__dummy0 = 0x00, @@ -190,63 +205,63 @@ rfc_CMD_FS_t RF_cmdIeeeFs = .__dummy2 = 0x00, .__dummy3 = 0x0000, }; - +/*---------------------------------------------------------------------------*/ // CMD_IEEE_TX // IEEE 802.15.4 Transmit Command -rfc_CMD_IEEE_TX_t RF_cmdIeeeTx = +rfc_CMD_IEEE_TX_t rf_cmd_ieee_tx = { - .commandNo = 0x2C01, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .commandNo = CMD_IEEE_TX, + .status = IDLE, + .pNextOp = 0, .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, + .startTrigger.triggerType = TRIG_NOW, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, .txOpt.bIncludePhyHdr = 0x0, .txOpt.bIncludeCrc = 0x0, .txOpt.payloadLenMsb = 0x0, - .payloadLen = 0x1E, - .pPayload = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .payloadLen = 0x0, /* set by driver */ + .pPayload = 0, /* set by driver */ .timeStamp = 0x00000000, }; - +/*---------------------------------------------------------------------------*/ // CMD_IEEE_RX // IEEE 802.15.4 Receive Command -rfc_CMD_IEEE_RX_t RF_cmdIeeeRx = +rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx = { - .commandNo = 0x2801, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .commandNo = CMD_IEEE_RX, + .status = IDLE, + .pNextOp = 0, .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, + .startTrigger.triggerType = TRIG_NOW, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, - .channel = 0x00, - .rxConfig.bAutoFlushCrc = 0x0, + .channel = 0x00, /* set by driver */ + .rxConfig.bAutoFlushCrc = 0x1, .rxConfig.bAutoFlushIgn = 0x0, .rxConfig.bIncludePhyHdr = 0x0, - .rxConfig.bIncludeCrc = 0x0, + .rxConfig.bIncludeCrc = 0x1, .rxConfig.bAppendRssi = 0x1, .rxConfig.bAppendCorrCrc = 0x1, .rxConfig.bAppendSrcInd = 0x0, - .rxConfig.bAppendTimestamp = 0x0, - .pRxQ = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx - .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .frameFiltOpt.frameFiltEn = 0x0, - .frameFiltOpt.frameFiltStop = 0x0, - .frameFiltOpt.autoAckEn = 0x0, + .rxConfig.bAppendTimestamp = 0x1, + .pRxQ = 0, /* set by driver */ + .pOutput = 0, /* set by driver */ + .frameFiltOpt.frameFiltEn = 0x0, /* set by driver */ + .frameFiltOpt.frameFiltStop = 0x1, + .frameFiltOpt.autoAckEn = 0x0, /* set by driver */ .frameFiltOpt.slottedAckEn = 0x0, .frameFiltOpt.autoPendEn = 0x0, .frameFiltOpt.defaultPend = 0x0, .frameFiltOpt.bPendDataReqOnly = 0x0, .frameFiltOpt.bPanCoord = 0x0, - .frameFiltOpt.maxFrameVersion = 0x3, + .frameFiltOpt.maxFrameVersion = 0x2, .frameFiltOpt.fcfReservedMask = 0x0, .frameFiltOpt.modifyFtFilter = 0x0, .frameFiltOpt.bStrictLenFilter = 0x0, @@ -258,25 +273,26 @@ rfc_CMD_IEEE_RX_t RF_cmdIeeeRx = .frameTypes.bAcceptFt5Reserved = 0x1, .frameTypes.bAcceptFt6Reserved = 0x1, .frameTypes.bAcceptFt7Reserved = 0x1, - .ccaOpt.ccaEnEnergy = 0x0, - .ccaOpt.ccaEnCorr = 0x0, - .ccaOpt.ccaEnSync = 0x0, + .ccaOpt.ccaEnEnergy = 0x1, + .ccaOpt.ccaEnCorr = 0x1, + .ccaOpt.ccaEnSync = 0x1, .ccaOpt.ccaCorrOp = 0x1, - .ccaOpt.ccaSyncOp = 0x1, - .ccaOpt.ccaCorrThr = 0x0, - .ccaRssiThr = 0x64, + .ccaOpt.ccaSyncOp = 0x0, + .ccaOpt.ccaCorrThr = 0x3, + .ccaRssiThr = 0x0, /* set by driver */ .__dummy0 = 0x00, .numExtEntries = 0x00, .numShortEntries = 0x00, - .pExtEntryList = 0, // INSERT APPLICABLE POINTER: (uint32_t*)&xxx - .pShortEntryList = 0, // INSERT APPLICABLE POINTER: (uint32_t*)&xxx - .localExtAddr = 0x0000000012345678, - .localShortAddr = 0xABBA, + .pExtEntryList = 0, + .pShortEntryList = 0, + .localExtAddr = 0x0, /* set by driver */ + .localShortAddr = 0x0, /* set by driver */ .localPanID = 0x0000, .__dummy1 = 0x000000, - .endTrigger.triggerType = 0x1, + .endTrigger.triggerType = TRIG_NEVER, .endTrigger.bEnaCmd = 0x0, .endTrigger.triggerNo = 0x0, .endTrigger.pastTrig = 0x0, .endTime = 0x00000000, }; +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h index 8a37b35fe..fdb722ab8 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h @@ -1,12 +1,36 @@ -#ifndef _IEEE_SETTINGS_H_ -#define _IEEE_SETTINGS_H_ - -//********************************************************************************* -// Generated by SmartRF Studio version 2.9.0 (build#85) -// Compatible with SimpleLink SDK version: CC13x2 SDK 2.10.xx.xx -// Device: CC1352P Rev. 1.1 -// -//********************************************************************************* +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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 IEEE_SETTINGS_H_ +#define IEEE_SETTINGS_H_ +/*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) @@ -14,28 +38,26 @@ #include DeviceFamily_constructPath(driverlib/rf_ieee_mailbox.h) #include - - +/*---------------------------------------------------------------------------*/ // TI-RTOS RF Mode Object -extern RF_Mode RF_ieeeMode; - - +extern RF_Mode rf_ieee_mode; +/*---------------------------------------------------------------------------*/ // TX Power Table -extern RF_TxPowerTable_Entry ieeeDefaultPaTxPowerTable[16]; -extern RF_TxPowerTable_Entry ieeeHighPaTxPowerTable[16]; - +#define RF_IEEE_TX_POWER_TABLE_DEFAULT_PA_SIZE 15 +#define RF_IEEE_TX_POWER_TABLE_HIGH_PA_SIZE 15 +extern RF_TxPowerTable_Entry rf_ieee_tx_power_table_default_pa[RF_IEEE_TX_POWER_TABLE_DEFAULT_PA_SIZE+1]; +extern RF_TxPowerTable_Entry rf_ieee_tx_power_table_high_pa[RF_IEEE_TX_POWER_TABLE_HIGH_PA_SIZE+1]; +/*---------------------------------------------------------------------------*/ // RF Core API commands -extern rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup; -extern rfc_CMD_FS_t RF_cmdIeeeFs; -extern rfc_CMD_IEEE_TX_t RF_cmdIeeeTx; -extern rfc_CMD_IEEE_RX_t RF_cmdIeeeRx; - - +extern rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup; +extern rfc_CMD_FS_t rf_cmd_ieee_fs; +extern rfc_CMD_IEEE_TX_t rf_cmd_ieee_tx; +extern rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx; +/*---------------------------------------------------------------------------*/ // RF Core API Overrides -extern uint32_t pIeeeDefaultPaOverrides[]; -extern uint32_t pIeeeHighPaOverrides[]; - - -#endif // _IEEE_SETTINGS_H_ - +extern uint32_t rf_ieee_overrides_default_pa[]; +extern uint32_t rf_ieee_overrides_high_pa[]; +/*---------------------------------------------------------------------------*/ +#endif /* IEEE_SETTINGS_H_ */ +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c index f6928f04c..c3a286058 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c @@ -1,4 +1,33 @@ -//********************************************************************************* +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ // Parameter summary // Address: 0 // Address0: 0xAA @@ -23,9 +52,9 @@ // TX Power: 20 dBm (requires define CCFG_FORCE_VDDR_HH = 0 in ccfg.c, see CC13xx/CC26xx Technical Reference Manual) // Enable high output power PA: true // Whitening: Dynamically IEEE 802.15.4g compatible whitener and 16/32-bit CRC - +/*---------------------------------------------------------------------------*/ #include "sys/cc.h" - +/*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) @@ -35,26 +64,24 @@ #include DeviceFamily_constructPath(rf_patches/rf_patch_mce_genfsk.h) #include - +/*---------------------------------------------------------------------------*/ #include "prop-settings.h" - - +/*---------------------------------------------------------------------------*/ // TI-RTOS RF Mode Object -RF_Mode RF_propMode = +RF_Mode rf_prop_mode = { .rfMode = RF_MODE_AUTO, .cpePatchFxn = &rf_patch_cpe_prop, .mcePatchFxn = &rf_patch_mce_genfsk, .rfePatchFxn = &rf_patch_rfe_genfsk, }; - - +/*---------------------------------------------------------------------------*/ // TX Power table // The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: // RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) // See the Technical Reference Manual for further details about the "txPower" Command field. // The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. -RF_TxPowerTable_Entry propDefaultPaTxPowerTable[19] = +RF_TxPowerTable_Entry rf_prop_tx_power_table_default_pa[RF_PROP_TX_POWER_TABLE_DEFAULT_PA_SIZE+1] = { { -20, RF_TxPowerTable_DEFAULT_PA_ENTRY( 0, 3, 0, 2) }, { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY( 1, 3, 0, 3) }, @@ -78,14 +105,13 @@ RF_TxPowerTable_Entry propDefaultPaTxPowerTable[19] = { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 0) }, RF_TxPowerTable_TERMINATION_ENTRY }; - - +/*---------------------------------------------------------------------------*/ // TX Power table // The RF_TxPowerTable_HIGH_PA_ENTRY macro is defined in RF.h and requires the following arguments: // RF_TxPowerTable_HIGH_PA_ENTRY(bias, ibboost, boost, coefficient, ldoTrim) // See the Technical Reference Manual for further details about the "txPower" Command field. // The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. -RF_TxPowerTable_Entry propHighPaTxPowerTable[8] = +RF_TxPowerTable_Entry rf_prop_tx_power_table_high_pa[RF_PROP_TX_POWER_TABLE_HIGH_PA_SIZE+1] = { { 14, RF_TxPowerTable_HIGH_PA_ENTRY( 7, 0, 0, 23, 4) }, { 15, RF_TxPowerTable_HIGH_PA_ENTRY(10, 0, 0, 26, 4) }, @@ -96,10 +122,9 @@ RF_TxPowerTable_Entry propHighPaTxPowerTable[8] = { 20, RF_TxPowerTable_HIGH_PA_ENTRY(27, 0, 0, 85, 32) }, RF_TxPowerTable_TERMINATION_ENTRY }; - - +/*---------------------------------------------------------------------------*/ // Overrides for CMD_PROP_RADIO_DIV_SETUP -uint32_t pPropDefaultPaOverrides[] CC_ALIGN(4) = +uint32_t rf_prop_overrides_default_pa[] CC_ALIGN(4) = { // override_use_patch_prop_genfsk.xml MCE_RFE_OVERRIDE(1,0,0,1,0,0), // PHY: Use MCE RAM patch, RFE RAM patch @@ -134,10 +159,9 @@ uint32_t pPropDefaultPaOverrides[] CC_ALIGN(4) = ADI_REG_OVERRIDE(0,12,0xF8), // Tx: Set PA trim to max to maximize its output power (in ADI0, set PACTL0=0xF8) (uint32_t)0xFFFFFFFF, }; - - +/*---------------------------------------------------------------------------*/ // Overrides for CMD_PROP_RADIO_DIV_SETUP -uint32_t pPropHighPaOverrides[] CC_ALIGN(4) = +uint32_t rf_prop_overrides_high_pa[] CC_ALIGN(4) = { // override_use_patch_prop_genfsk.xml MCE_RFE_OVERRIDE(1,0,0,1,0,0), // PHY: Use MCE RAM patch, RFE RAM patch @@ -172,21 +196,20 @@ uint32_t pPropHighPaOverrides[] CC_ALIGN(4) = (uint32_t)0x82A86C2B, // txHighPA=0x20AA1B (uint32_t)0xFFFFFFFF, }; - - +/*---------------------------------------------------------------------------*/ // CMD_PROP_RADIO_DIV_SETUP // Proprietary Mode Radio Setup Command for All Frequency Bands -rfc_CMD_PROP_RADIO_DIV_SETUP_t RF_cmdPropRadioDivSetup = +rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup = { - .commandNo = 0x3807, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .commandNo = CMD_PROP_RADIO_DIV_SETUP, + .status = IDLE, + .pNextOp = 0, .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, + .startTrigger.triggerType = TRIG_NOW, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, .modulation.modType = 0x1, .modulation.deviation = 0x64, @@ -202,33 +225,33 @@ rfc_CMD_PROP_RADIO_DIV_SETUP_t RF_cmdPropRadioDivSetup = .formatConf.bMsbFirst = 0x1, .formatConf.fecMode = 0x0, .formatConf.whitenMode = 0x7, - .config.frontEndMode = 0x0, - .config.biasMode = 0x1, + .config.frontEndMode = 0x0, /* set by driver */ + .config.biasMode = 0x0, /* set by driver */ .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, - .txPower = 0x013F, - .pRegOverride = pPropDefaultPaOverrides, - .centerFreq = 0x0393, - .intFreq = 0x8000, - .loDivider = 0x05, + .txPower = 0x013F, /* default 13.5 dBm */ + .pRegOverride = rf_prop_overrides_default_pa, + .centerFreq = 0x0393, /* set by driver */ + .intFreq = 0x8000, /* set by driver */ + .loDivider = 0x05, /* set by driver */ }; - +/*---------------------------------------------------------------------------*/ // CMD_FS // Frequency Synthesizer Programming Command -rfc_CMD_FS_t RF_cmdPropFs = +rfc_CMD_FS_t rf_cmd_prop_fs = { - .commandNo = 0x0803, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .commandNo = CMD_FS, + .status = IDLE, + .pNextOp = 0, .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, + .startTrigger.triggerType = TRIG_NOW, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, - .frequency = 0x0393, - .fractFreq = 0x0000, + .frequency = 0x0393, /* set by driver */ + .fractFreq = 0x0000, /* set by driver */ .synthConf.bTxMode = 0x0, .synthConf.refFreq = 0x0, .__dummy0 = 0x00, @@ -236,85 +259,86 @@ rfc_CMD_FS_t RF_cmdPropFs = .__dummy2 = 0x00, .__dummy3 = 0x0000, }; - +/*---------------------------------------------------------------------------*/ // CMD_PROP_TX_ADV // Proprietary Mode Advanced Transmit Command -rfc_CMD_PROP_TX_ADV_t RF_cmdPropTxAdv = +rfc_CMD_PROP_TX_ADV_t rf_cmd_prop_tx_adv = { - .commandNo = 0x3803, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .commandNo = CMD_PROP_TX_ADV, + .status = IDLE, + .pNextOp = 0, .startTime = 0x00000000, - .startTrigger.triggerType = 0x2, + .startTrigger.triggerType = TRIG_NOW, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x1, - .condition.rule = 0x1, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, .pktConf.bFsOff = 0x0, .pktConf.bUseCrc = 0x1, .pktConf.bCrcIncSw = 0x0, .pktConf.bCrcIncHdr = 0x0, .numHdrBits = 0x10, - .pktLen = 0x0014, + .pktLen = 0x0, /* set by driver */ .startConf.bExtTxTrig = 0x0, .startConf.inputMode = 0x0, .startConf.source = 0x0, - .preTrigger.triggerType = 0x4, + .preTrigger.triggerType = TRIG_REL_START, .preTrigger.bEnaCmd = 0x0, .preTrigger.triggerNo = 0x0, .preTrigger.pastTrig = 0x1, .preTime = 0x00000000, .syncWord = 0x0055904E, - .pPkt = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .pPkt = 0, }; - +/*---------------------------------------------------------------------------*/ // CMD_PROP_RX_ADV // Proprietary Mode Advanced Receive Command -rfc_CMD_PROP_RX_ADV_t RF_cmdPropRxAdv = +rfc_CMD_PROP_RX_ADV_t rf_cmd_prop_rx_adv = { - .commandNo = 0x3804, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .commandNo = CMD_PROP_RX_ADV, + .status = IDLE, + .pNextOp = 0, .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, + .startTrigger.triggerType = TRIG_NOW, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, .pktConf.bFsOff = 0x0, - .pktConf.bRepeatOk = 0x0, - .pktConf.bRepeatNok = 0x0, - .pktConf.bUseCrc = 0x0, + .pktConf.bRepeatOk = 0x1, + .pktConf.bRepeatNok = 0x1, + .pktConf.bUseCrc = 0x1, .pktConf.bCrcIncSw = 0x0, .pktConf.bCrcIncHdr = 0x0, .pktConf.endType = 0x0, - .pktConf.filterOp = 0x0, - .rxConf.bAutoFlushIgnored = 0x0, - .rxConf.bAutoFlushCrcErr = 0x0, + .pktConf.filterOp = 0x1, + .rxConf.bAutoFlushIgnored = 0x1, + .rxConf.bAutoFlushCrcErr = 0x1, .rxConf.bIncludeHdr = 0x0, .rxConf.bIncludeCrc = 0x0, - .rxConf.bAppendRssi = 0x0, + .rxConf.bAppendRssi = 0x1, .rxConf.bAppendTimestamp = 0x0, - .rxConf.bAppendStatus = 0x0, - .syncWord0 = 0x930B51DE, + .rxConf.bAppendStatus = 0x1, + .syncWord0 = 0x0055904E, .syncWord1 = 0x00000000, - .maxPktLen = 0x00FF, - .hdrConf.numHdrBits = 0x0, + .maxPktLen = 0x0, /* set by driver */ + .hdrConf.numHdrBits = 0x10, .hdrConf.lenPos = 0x0, - .hdrConf.numLenBits = 0x0, + .hdrConf.numLenBits = 0x0B, .addrConf.addrType = 0x0, .addrConf.addrSize = 0x0, .addrConf.addrPos = 0x0, .addrConf.numAddr = 0x0, - .lenOffset = 0x00, - .endTrigger.triggerType = 0x0, + .lenOffset = 0xFC, + .endTrigger.triggerType = TRIG_NEVER, .endTrigger.bEnaCmd = 0x0, .endTrigger.triggerNo = 0x0, .endTrigger.pastTrig = 0x0, .endTime = 0x00000000, - .pAddr = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .pQueue = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx - .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .pAddr = 0, /* set by driver */ + .pQueue = 0, /* set by driver */ + .pOutput = 0, /* set by driver */ }; +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h index a3f758abd..d9b6046a1 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h @@ -1,40 +1,62 @@ -#ifndef _PROP_SETTINGS_H_ -#define _PROP_SETTINGS_H_ - -//********************************************************************************* -// Generated by SmartRF Studio version 2.9.0 (build#85) -// Compatible with SimpleLink SDK version: CC13x2 SDK 2.10.xx.xx -// Device: CC1352P Rev. 1.1 -// -//********************************************************************************* +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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 PROP_SETTINGS_H_ +#define PROP_SETTINGS_H_ +/*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) #include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h) #include - - +/*---------------------------------------------------------------------------*/ // TI-RTOS RF Mode Object -extern RF_Mode RF_propMode; - - +extern RF_Mode rf_prop_mode; +/*---------------------------------------------------------------------------*/ // Tx Power Tables -extern RF_TxPowerTable_Entry propDefaultPaTxPowerTable[19]; -extern RF_TxPowerTable_Entry propHighPaTxPowerTable[8]; - +#define RF_PROP_TX_POWER_TABLE_DEFAULT_PA_SIZE 18 +#define RF_PROP_TX_POWER_TABLE_HIGH_PA_SIZE 7 +extern RF_TxPowerTable_Entry rf_prop_tx_power_table_default_pa[RF_PROP_TX_POWER_TABLE_DEFAULT_PA_SIZE+1]; +extern RF_TxPowerTable_Entry rf_prop_tx_power_table_high_pa[RF_PROP_TX_POWER_TABLE_HIGH_PA_SIZE+1]; +/*---------------------------------------------------------------------------*/ // RF Core API commands -extern rfc_CMD_PROP_RADIO_DIV_SETUP_t RF_cmdPropRadioDivSetup; -extern rfc_CMD_FS_t RF_cmdPropFs; -extern rfc_CMD_PROP_TX_ADV_t RF_cmdPropTxAdv; -extern rfc_CMD_PROP_RX_ADV_t RF_cmdPropRxAdv; - - +extern rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup; +extern rfc_CMD_FS_t rf_cmd_prop_fs; +extern rfc_CMD_PROP_TX_ADV_t rf_cmd_prop_tx_adv; +extern rfc_CMD_PROP_RX_ADV_t rf_cmd_prop_rx_adv; +/*---------------------------------------------------------------------------*/ // RF Core API Overrides -extern uint32_t pPropDefaultPaOverrides[]; -extern uint32_t pPropHighPaOverrides[]; - - -#endif // _PROP_SETTINGS_H_ - +extern uint32_t rf_prop_overrides_default_pa[]; +extern uint32_t rf_prop_overrides_high_pa[]; +/*---------------------------------------------------------------------------*/ +#endif /* PROP_SETTINGS_H_ */ +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c index 15527b039..92720c63b 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c @@ -1,4 +1,33 @@ -//********************************************************************************* +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ // Parameter summary // IEEE Channel: 11 // Frequency: 2405 MHz @@ -6,9 +35,9 @@ // Packet Data: 255 // Preamble (32 bit): 01010101... // TX Power: 5 dBm - +/*---------------------------------------------------------------------------*/ #include "sys/cc.h" - +/*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) @@ -16,26 +45,24 @@ #include DeviceFamily_constructPath(rf_patches/rf_patch_cpe_ieee.h) #include - +/*---------------------------------------------------------------------------*/ #include "ieee-settings.h" - - +/*---------------------------------------------------------------------------*/ // TI-RTOS RF Mode Object -RF_Mode RF_ieeeMode = +RF_Mode rf_ieee_mode = { .rfMode = RF_MODE_IEEE_15_4, .cpePatchFxn = &rf_patch_cpe_ieee, .mcePatchFxn = 0, .rfePatchFxn = 0, }; - - +/*---------------------------------------------------------------------------*/ // TX Power table // The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: // RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) // See the Technical Reference Manual for further details about the "txPower" Command field. // The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. -RF_TxPowerTable_Entry ieeeTxPowerTable[14] = +RF_TxPowerTable_Entry rf_ieee_tx_power_table[RF_IEEE_TX_POWER_TABLE_SIZE+1] = { { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 6) }, { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 6) }, @@ -52,10 +79,9 @@ RF_TxPowerTable_Entry ieeeTxPowerTable[14] = { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(48, 0, 1, 73) }, RF_TxPowerTable_TERMINATION_ENTRY }; - - +/*---------------------------------------------------------------------------*/ // Overrides for CMD_RADIO_SETUP -uint32_t pIeeeOverrides[] CC_ALIGN(4) = +uint32_t rf_ieee_overrides[] CC_ALIGN(4) = { // override_synth_ieee_15_4.xml HW_REG_OVERRIDE(0x4038,0x0035), // Synth: Set recommended RTRIM to 5 @@ -80,48 +106,47 @@ uint32_t pIeeeOverrides[] CC_ALIGN(4) = HW_REG_OVERRIDE(0x50DC,0x002B), // Rx: Adjust AGC DC filter (uint32_t)0xFFFFFFFF, }; - - +/*---------------------------------------------------------------------------*/ // CMD_RADIO_SETUP // Radio Setup Command for Pre-Defined Schemes -rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup = +rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup = { - .commandNo = 0x0802, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .commandNo = CMD_RADIO_SETUP, + .status = IDLE, + .pNextOp = 0, .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, + .startTrigger.triggerType = TRIG_NOW, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, .mode = 0x01, .__dummy0 = 0x00, .config.frontEndMode = 0x0, - .config.biasMode = 0x0, + .config.biasMode = 0x1, .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, - .txPower = 0x9330, - .pRegOverride = pIeeeOverrides, + .txPower = 0x9330, /* 5 dBm default */ + .pRegOverride = rf_ieee_overrides, }; - +/*---------------------------------------------------------------------------*/ // CMD_FS // Frequency Synthesizer Programming Command -rfc_CMD_FS_t RF_cmdIeeeFs = +rfc_CMD_FS_t rf_cmd_ieee_fs = { - .commandNo = 0x0803, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .commandNo = CMD_FS, + .status = IDLE, + .pNextOp = 0, .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, + .startTrigger.triggerType = TRIG_NOW, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, - .frequency = 0x0965, - .fractFreq = 0x0000, + .frequency = 0x0965, /* set by driver */ + .fractFreq = 0x0000, /* set by driver */ .synthConf.bTxMode = 0x1, .synthConf.refFreq = 0x0, .__dummy0 = 0x00, @@ -129,63 +154,63 @@ rfc_CMD_FS_t RF_cmdIeeeFs = .__dummy2 = 0x00, .__dummy3 = 0x0000, }; - +/*---------------------------------------------------------------------------*/ // CMD_IEEE_TX // The command ID number 0x2C01 -rfc_CMD_IEEE_TX_t RF_cmdIeeeTx = +rfc_CMD_IEEE_TX_t rf_cmd_ieee_tx = { - .commandNo = 0x2C01, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .commandNo = CMD_IEEE_TX, + .status = IDLE, + .pNextOp = 0, .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, + .startTrigger.triggerType = TRIG_NOW, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, .txOpt.bIncludePhyHdr = 0x0, .txOpt.bIncludeCrc = 0x0, .txOpt.payloadLenMsb = 0x0, - .payloadLen = 0x1E, - .pPayload = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .payloadLen = 0x0, /* set by driver */ + .pPayload = 0, /* set by driver */ .timeStamp = 0x00000000, }; - +/*---------------------------------------------------------------------------*/ // CMD_IEEE_RX // The command ID number 0x2801 -rfc_CMD_IEEE_RX_t RF_cmdIeeeRx = +rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx = { - .commandNo = 0x2801, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .commandNo = CMD_IEEE_RX, + .status = IDLE, + .pNextOp = 0, .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, + .startTrigger.triggerType = TRIG_NOW, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, - .channel = 0x00, - .rxConfig.bAutoFlushCrc = 0x0, + .channel = 0x00, /* set by driver */ + .rxConfig.bAutoFlushCrc = 0x1, .rxConfig.bAutoFlushIgn = 0x0, .rxConfig.bIncludePhyHdr = 0x0, - .rxConfig.bIncludeCrc = 0x0, + .rxConfig.bIncludeCrc = 0x1, .rxConfig.bAppendRssi = 0x1, .rxConfig.bAppendCorrCrc = 0x1, .rxConfig.bAppendSrcInd = 0x0, - .rxConfig.bAppendTimestamp = 0x0, - .pRxQ = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx - .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .frameFiltOpt.frameFiltEn = 0x0, - .frameFiltOpt.frameFiltStop = 0x0, - .frameFiltOpt.autoAckEn = 0x0, + .rxConfig.bAppendTimestamp = 0x1, + .pRxQ = 0, /* set by driver */ + .pOutput = 0, /* set by driver */ + .frameFiltOpt.frameFiltEn = 0x0, /* set by driver */ + .frameFiltOpt.frameFiltStop = 0x1, + .frameFiltOpt.autoAckEn = 0x0, /* set by driver */ .frameFiltOpt.slottedAckEn = 0x0, .frameFiltOpt.autoPendEn = 0x0, .frameFiltOpt.defaultPend = 0x0, .frameFiltOpt.bPendDataReqOnly = 0x0, .frameFiltOpt.bPanCoord = 0x0, - .frameFiltOpt.maxFrameVersion = 0x3, + .frameFiltOpt.maxFrameVersion = 0x2, .frameFiltOpt.fcfReservedMask = 0x0, .frameFiltOpt.modifyFtFilter = 0x0, .frameFiltOpt.bStrictLenFilter = 0x0, @@ -197,25 +222,26 @@ rfc_CMD_IEEE_RX_t RF_cmdIeeeRx = .frameTypes.bAcceptFt5Reserved = 0x1, .frameTypes.bAcceptFt6Reserved = 0x1, .frameTypes.bAcceptFt7Reserved = 0x1, - .ccaOpt.ccaEnEnergy = 0x0, - .ccaOpt.ccaEnCorr = 0x0, - .ccaOpt.ccaEnSync = 0x0, + .ccaOpt.ccaEnEnergy = 0x1, + .ccaOpt.ccaEnCorr = 0x1, + .ccaOpt.ccaEnSync = 0x1, .ccaOpt.ccaCorrOp = 0x1, - .ccaOpt.ccaSyncOp = 0x1, - .ccaOpt.ccaCorrThr = 0x0, - .ccaRssiThr = 0x64, + .ccaOpt.ccaSyncOp = 0x0, + .ccaOpt.ccaCorrThr = 0x3, + .ccaRssiThr = 0x0, /* set by driver */ .__dummy0 = 0x00, .numExtEntries = 0x00, .numShortEntries = 0x00, - .pExtEntryList = 0, // INSERT APPLICABLE POINTER: (uint32_t*)&xxx - .pShortEntryList = 0, // INSERT APPLICABLE POINTER: (uint32_t*)&xxx - .localExtAddr = 0x0000000012345678, - .localShortAddr = 0xABBA, + .pExtEntryList = 0, + .pShortEntryList = 0, + .localExtAddr = 0x0, /* set by driver */ + .localShortAddr = 0x0, /* set by driver */ .localPanID = 0x0000, .__dummy1 = 0x000000, - .endTrigger.triggerType = 0x1, + .endTrigger.triggerType = TRIG_NEVER, .endTrigger.bEnaCmd = 0x0, .endTrigger.triggerNo = 0x0, .endTrigger.pastTrig = 0x0, .endTime = 0x00000000, }; +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h index 5c6cb3d5a..ff63f2c7e 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h @@ -1,12 +1,36 @@ -#ifndef _IEEE_SETTINGS_H_ -#define _IEEE_SETTINGS_H_ - -//********************************************************************************* -// Generated by SmartRF Studio version 2.9.0 (build#85) -// Compatible with SimpleLink SDK version: No known SDK for this device -// Device: CC2650 Rev. 2.2 -// -//********************************************************************************* +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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 IEEE_SETTINGS_H_ +#define IEEE_SETTINGS_H_ +/*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) @@ -14,25 +38,23 @@ #include DeviceFamily_constructPath(driverlib/rf_ieee_mailbox.h) #include - - +/*---------------------------------------------------------------------------*/ // TI-RTOS RF Mode Object -extern RF_Mode RF_ieeeMode; - - +extern RF_Mode rf_ieee_mode; +/*---------------------------------------------------------------------------*/ // TX Power Table -extern RF_TxPowerTable_Entry ieeeTxPowerTable[14]; +#define RF_IEEE_TX_POWER_TABLE_SIZE 14 +extern RF_TxPowerTable_Entry rf_ieee_tx_power_table[RF_IEEE_TX_POWER_TABLE_SIZE+1]; +/*---------------------------------------------------------------------------*/ // RF Core API commands -extern rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup; -extern rfc_CMD_FS_t RF_cmdIeeeFs; -extern rfc_CMD_IEEE_TX_t RF_cmdIeeeTx; -extern rfc_CMD_IEEE_RX_t RF_cmdIeeeRx; - - +extern rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup; +extern rfc_CMD_FS_t rf_cmd_ieee_fs; +extern rfc_CMD_IEEE_TX_t rf_cmd_ieee_tx; +extern rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx; +/*---------------------------------------------------------------------------*/ // RF Core API Overrides -extern uint32_t pIeeeOverrides[]; - - -#endif // _IEEE_SETTINGS_H_ - +extern uint32_t rf_ieee_overrides[]; +/*---------------------------------------------------------------------------*/ +#endif /* IEEE_SETTINGS_H_ */ +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c index 20fbc6627..91db86f41 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c @@ -1,4 +1,33 @@ -//********************************************************************************* +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ // Parameter summary // IEEE Channel: 11 // Frequency: 2405 MHz @@ -6,9 +35,9 @@ // Packet Data: 255 // Preamble (32 bit): 01010101... // TX Power: 5 dBm - +/*---------------------------------------------------------------------------*/ #include "sys/cc.h" - +/*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) @@ -17,26 +46,24 @@ #include DeviceFamily_constructPath(rf_patches/rf_patch_mce_ieee_802_15_4.h) #include - +/*---------------------------------------------------------------------------*/ #include "ieee-settings.h" - - +/*---------------------------------------------------------------------------*/ // TI-RTOS RF Mode Object -RF_Mode RF_ieeeMode = +RF_Mode rf_ieee_mode = { .rfMode = RF_MODE_AUTO, .cpePatchFxn = &rf_patch_cpe_ieee_802_15_4, .mcePatchFxn = &rf_patch_mce_ieee_802_15_4, .rfePatchFxn = 0, }; - - +/*---------------------------------------------------------------------------*/ // TX Power table // The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: // RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) // See the Technical Reference Manual for further details about the "txPower" Command field. // The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. -RF_TxPowerTable_Entry ieeeTxPowerTable[16] = +RF_TxPowerTable_Entry rf_ieee_tx_power_table[RF_IEEE_TX_POWER_TABLE_SIZE+1] = { { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY(7, 3, 0, 3) }, { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY(9, 3, 0, 3) }, @@ -55,10 +82,9 @@ RF_TxPowerTable_Entry ieeeTxPowerTable[16] = { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, RF_TxPowerTable_TERMINATION_ENTRY }; - - +/*---------------------------------------------------------------------------*/ // Overrides for CMD_RADIO_SETUP -uint32_t pIeeeOverrides[] CC_ALIGN(4) = +uint32_t rf_ieee_overrides[] CC_ALIGN(4) = { // override_ieee_802_15_4.xml MCE_RFE_OVERRIDE(1,0,0,0,1,0), // PHY: Use MCE RAM patch, RFE ROM bank 1 @@ -77,45 +103,44 @@ uint32_t pIeeeOverrides[] CC_ALIGN(4) = (uint32_t)0x000F8883, // Rx: Set LNA bias current offset to +15 to saturate trim to max (default: 0) (uint32_t)0xFFFFFFFF, }; - - +/*---------------------------------------------------------------------------*/ // CMD_RADIO_SETUP // Radio Setup Command for Pre-Defined Schemes -rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup = +rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup = { - .commandNo = 0x0802, + .commandNo = CMD_RADIO_SETUP, .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .pNextOp = 0, .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, + .startTrigger.triggerType = TRIG_NOW, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, .mode = 0x01, .loDivider = 0x00, .config.frontEndMode = 0x0, - .config.biasMode = 0x0, + .config.biasMode = 0x1, .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, - .txPower = 0x941E, - .pRegOverride = pIeeeOverrides, + .txPower = 0x941E, /* 5 dBm default */ + .pRegOverride = rf_ieee_overrides, }; - +/*---------------------------------------------------------------------------*/ // CMD_FS // Frequency Synthesizer Programming Command -rfc_CMD_FS_t RF_cmdIeeeFs = +rfc_CMD_FS_t rf_cmd_ieee_fs = { - .commandNo = 0x0803, + .commandNo = CMD_FS, .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .pNextOp = 0, .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, + .startTrigger.triggerType = TRIG_NOW, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, .frequency = 0x0965, .fractFreq = 0x0000, @@ -126,36 +151,36 @@ rfc_CMD_FS_t RF_cmdIeeeFs = .__dummy2 = 0x00, .__dummy3 = 0x0000, }; - +/*---------------------------------------------------------------------------*/ // CMD_IEEE_TX // IEEE 802.15.4 Transmit Command -rfc_CMD_IEEE_TX_t RF_cmdIeeeTx = +rfc_CMD_IEEE_TX_t rf_cmd_ieee_tx = { - .commandNo = 0x2C01, + .commandNo = CMD_IEEE_RX, .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .pNextOp = 0, .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, + .startTrigger.triggerType = TRIG_NOW, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, .txOpt.bIncludePhyHdr = 0x0, .txOpt.bIncludeCrc = 0x0, .txOpt.payloadLenMsb = 0x0, - .payloadLen = 0x1E, - .pPayload = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .payloadLen = 0x0, /* set by driver */ + .pPayload = 0, /* set by driver */ .timeStamp = 0x00000000, }; - +/*---------------------------------------------------------------------------*/ // CMD_IEEE_RX // IEEE 802.15.4 Receive Command -rfc_CMD_IEEE_RX_t RF_cmdIeeeRx = +rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx = { .commandNo = 0x2801, .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .pNextOp = 0, .startTime = 0x00000000, .startTrigger.triggerType = 0x0, .startTrigger.bEnaCmd = 0x0, @@ -172,17 +197,17 @@ rfc_CMD_IEEE_RX_t RF_cmdIeeeRx = .rxConfig.bAppendCorrCrc = 0x1, .rxConfig.bAppendSrcInd = 0x0, .rxConfig.bAppendTimestamp = 0x0, - .pRxQ = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx - .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .frameFiltOpt.frameFiltEn = 0x0, - .frameFiltOpt.frameFiltStop = 0x0, - .frameFiltOpt.autoAckEn = 0x0, + .pRxQ = 0, /* set by driver */ + .pOutput = 0, /* set by driver */ + .frameFiltOpt.frameFiltEn = 0x0, /* set by driver */ + .frameFiltOpt.frameFiltStop = 0x1, + .frameFiltOpt.autoAckEn = 0x0, /* set by driver */ .frameFiltOpt.slottedAckEn = 0x0, .frameFiltOpt.autoPendEn = 0x0, .frameFiltOpt.defaultPend = 0x0, .frameFiltOpt.bPendDataReqOnly = 0x0, .frameFiltOpt.bPanCoord = 0x0, - .frameFiltOpt.maxFrameVersion = 0x3, + .frameFiltOpt.maxFrameVersion = 0x2, .frameFiltOpt.fcfReservedMask = 0x0, .frameFiltOpt.modifyFtFilter = 0x0, .frameFiltOpt.bStrictLenFilter = 0x0, @@ -194,25 +219,26 @@ rfc_CMD_IEEE_RX_t RF_cmdIeeeRx = .frameTypes.bAcceptFt5Reserved = 0x1, .frameTypes.bAcceptFt6Reserved = 0x1, .frameTypes.bAcceptFt7Reserved = 0x1, - .ccaOpt.ccaEnEnergy = 0x0, - .ccaOpt.ccaEnCorr = 0x0, - .ccaOpt.ccaEnSync = 0x0, + .ccaOpt.ccaEnEnergy = 0x1, + .ccaOpt.ccaEnCorr = 0x1, + .ccaOpt.ccaEnSync = 0x1, .ccaOpt.ccaCorrOp = 0x1, - .ccaOpt.ccaSyncOp = 0x1, - .ccaOpt.ccaCorrThr = 0x0, - .ccaRssiThr = 0x64, + .ccaOpt.ccaSyncOp = 0x0, + .ccaOpt.ccaCorrThr = 0x3, + .ccaRssiThr = 0x0, /* set by driver */ .__dummy0 = 0x00, .numExtEntries = 0x00, .numShortEntries = 0x00, - .pExtEntryList = 0, // INSERT APPLICABLE POINTER: (uint32_t*)&xxx - .pShortEntryList = 0, // INSERT APPLICABLE POINTER: (uint32_t*)&xxx - .localExtAddr = 0x0000000012345678, - .localShortAddr = 0xABBA, + .pExtEntryList = 0, + .pShortEntryList = 0, + .localExtAddr = 0x0, /* set by driver */ + .localShortAddr = 0x0, /* set by driver */ .localPanID = 0x0000, .__dummy1 = 0x000000, - .endTrigger.triggerType = 0x1, + .endTrigger.triggerType = TRIG_NEVER, .endTrigger.bEnaCmd = 0x0, .endTrigger.triggerNo = 0x0, .endTrigger.pastTrig = 0x0, .endTime = 0x00000000, }; +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h index 251bcb14c..a97730988 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h @@ -1,12 +1,36 @@ -#ifndef _IEEE_SETTINGS_H_ -#define _IEEE_SETTINGS_H_ - -//********************************************************************************* -// Generated by SmartRF Studio version 2.9.0 (build#85) -// Compatible with SimpleLink SDK version: CC26x2 SDK 2.10.xx.xx -// Device: CC2652R Rev. 1.1 -// -//********************************************************************************* +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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 IEEE_SETTINGS_H_ +#define IEEE_SETTINGS_H_ +/*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) @@ -14,26 +38,24 @@ #include DeviceFamily_constructPath(driverlib/rf_ieee_mailbox.h)) #include - - +/*---------------------------------------------------------------------------*/ // TI-RTOS RF Mode Object -extern RF_Mode RF_ieeeMode; - - +extern RF_Mode rf_ieee_mode; +/*---------------------------------------------------------------------------*/ // TX Power Table -extern RF_TxPowerTable_Entry ieeeTxPowerTable[16]; - +#define RF_IEEE_TX_POWER_TABLE_SIZE 15 +extern RF_TxPowerTable_Entry rf_ieee_tx_power_table[RF_IEEE_TX_POWER_TABLE_SIZE+1]; +/*---------------------------------------------------------------------------*/ // RF Core API commands -extern rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup; -extern rfc_CMD_FS_t RF_cmdIeeeFs; -extern rfc_CMD_IEEE_TX_t RF_cmdIeeeTx; -extern rfc_CMD_IEEE_RX_t RF_cmdIeeeRx; - - +extern rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup; +extern rfc_CMD_FS_t rf_cmd_ieee_fs; +extern rfc_CMD_IEEE_TX_t rf_cmd_ieee_tx; +extern rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx; +/*---------------------------------------------------------------------------*/ // RF Core API Overrides -extern uint32_t pIeeeOverrides[]; - - -#endif // _IEEE_SETTINGS_H_ +extern uint32_t rf_ieee_overrides[]; +/*---------------------------------------------------------------------------*/ +#endif /* IEEE_SETTINGS_H_ */ +/*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 index 495dc498d..e71992113 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 @@ -7,7 +7,8 @@ DEVICE_LINE = CC13XX BOARD_SOURCEFILES += CC1312R1_LAUNCHXL.c CC1312R1_LAUNCHXL_fxns.c -DEFINES += PROP_MODE_CONF_TX_POWER_TABLE=propDefaultPaTxPowerTable +DEFINES += PROP_MODE_CONF_TX_POWER_TABLE=rf_prop_tx_power_table_default_pa +DEFINES += PROP_MODE_CONF_TX_POWER_TABLE_SIZE=RF_PROP_TX_POWER_TABLE_DEFAULT_PA_SIZE SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 index accb29899..0dbb6622e 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 @@ -7,8 +7,11 @@ DEVICE_LINE = CC13XX BOARD_SOURCEFILES += CC1352P1_LAUNCHXL.c CC1312P1_LAUNCHXL_fxns.c -DEFINES += PROP_MODE_CONF_TX_POWER_TABLE=propDefaultPaTxPowerTable -DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE=ieeeDefaultPaTxPowerTable +DEFINES += PROP_MODE_CONF_TX_POWER_TABLE=rf_prop_tx_power_table_default_pa +DEFINES += PROP_MODE_CONF_TX_POWER_TABLE_SIZE=RF_PROP_TX_POWER_TABLE_DEFAULT_PA_SIZE + +DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE=rf_ieee_tx_power_table_default_pa +DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE_SIZE=RF_IEEE_TX_POWER_TABLE_DEFAULT_PA_SIZE SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/Makefile.cc1352p_2 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/Makefile.cc1352p_2 index 4c9558719..e8608fae7 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/Makefile.cc1352p_2 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/Makefile.cc1352p_2 @@ -7,8 +7,11 @@ DEVICE_LINE = CC13XX BOARD_SOURCEFILES += CC1352P_2_LAUNCHXL.c CC1352P_2_LAUNCHXL_fxns.c -DEFINES += PROP_MODE_CONF_TX_POWER_TABLE=propDefaultPaTxPowerTable -DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE=ieeeDefaultPaTxPowerTable +DEFINES += PROP_MODE_CONF_TX_POWER_TABLE=rf_prop_tx_power_table_default_pa +DEFINES += PROP_MODE_CONF_TX_POWER_TABLE_SIZE=RF_PROP_TX_POWER_TABLE_DEFAULT_PA_SIZE + +DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE=rf_ieee_tx_power_table_default_pa +DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE_SIZE=RF_IEEE_TX_POWER_TABLE_DEFAULT_PA_SIZE SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/Makefile.cc1352p_4 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/Makefile.cc1352p_4 index a9365a51a..8288e292c 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/Makefile.cc1352p_4 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/Makefile.cc1352p_4 @@ -7,8 +7,11 @@ DEVICE_LINE = CC13XX BOARD_SOURCEFILES += CC1352P_4_LAUNCHXL.c CC1352P_4_LAUNCHXL_fxns.c -DEFINES += PROP_MODE_CONF_TX_POWER_TABLE=propDefaultPaTxPowerTable -DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE=ieeeDefaultPaTxPowerTable +DEFINES += PROP_MODE_CONF_TX_POWER_TABLE=rf_prop_tx_power_table_default_pa +DEFINES += PROP_MODE_CONF_TX_POWER_TABLE_SIZE=RF_PROP_TX_POWER_TABLE_DEFAULT_PA_SIZE + +DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE=rf_ieee_tx_power_table_default_pa +DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE_SIZE=RF_IEEE_TX_POWER_TABLE_DEFAULT_PA_SIZE SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 index 8214b275e..31434afb6 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 @@ -7,8 +7,11 @@ DEVICE_LINE = CC13XX BOARD_SOURCEFILES += CC1352R1_LAUNCHXL.c CC1352R1_LAUNCHXL_fxns.c -DEFINES += PROP_MODE_CONF_TX_POWER_TABLE=propDefaultPaTxPowerTable -DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE=ieeeDefaultPaTxPowerTable +DEFINES += PROP_MODE_CONF_TX_POWER_TABLE=rf_prop_tx_power_table_default_pa +DEFINES += PROP_MODE_CONF_TX_POWER_TABLE_SIZE=RF_PROP_TX_POWER_TABLE_DEFAULT_PA_SIZE + +DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE=rf_ieee_tx_power_table_default_pa +DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE_SIZE=RF_IEEE_TX_POWER_TABLE_DEFAULT_PA_SIZE SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/platform.c b/arch/platform/simplelink/cc13xx-cc26xx/platform.c index e196efc9a..0ced25f26 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/platform.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/platform.c @@ -169,10 +169,7 @@ platform_init_stage_one(void) void platform_init_stage_two(void) { -#if SIMPLELINK_UART_CONF_ENABLE uart0_init(); -#endif - serial_line_init(); #if BUILD_WITH_SHELL From f6b016c5d4cf4c67b6f96f91b6398073a93644b3 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Fri, 15 Jun 2018 16:37:51 +0200 Subject: [PATCH 251/485] Working prop-mode --- arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h | 85 +- arch/cpu/cc13xx-cc26xx/dev/rf-common.c | 11 +- arch/cpu/cc13xx-cc26xx/dev/rf-common.h | 26 +- arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c | 27 +- arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c | 797 ++++++++++-------- .../rf-settings/cc13x0/prop-settings.c | 20 +- .../rf-settings/cc13x0/prop-settings.h | 2 +- .../rf-settings/cc26x2/ieee-settings.c | 28 +- .../rf-settings/cc26x2/ieee-settings.h | 4 +- .../simplelink/cc13xx-cc26xx/contiki-conf.h | 4 +- .../launchpad/button-sensor-arch.c | 120 +-- .../launchpad/launchpad-sensors.c | 8 +- os/sys/cc.h | 4 + 13 files changed, 593 insertions(+), 543 deletions(-) diff --git a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h index fe91d840c..f86ceb521 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h +++ b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h @@ -56,12 +56,10 @@ #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 +#ifdef RF_CORE_CONF_CHANNEL +#define RF_CHANNEL RF_CORE_CONF_CHANNEL +#else +#define RF_CHANNEL 25 #endif /* Number of Prop Mode RX buffers */ @@ -70,54 +68,59 @@ #endif /* Configure Radio mode, i.e. prop or ieee */ + + +/*----- CC13xx Device Line --------------------------------------------------*/ /* CC13xx supports both IEEE and Prop mode, depending on which device */ -/* CC26xx only supports IEEE mode */ #if defined(DEVICE_LINE_CC13XX) -/* Default mode should be prop for prop-only devices (CC1310, CC1312); +/* Default mode should be prop for prop-only devices (CC1310, CC1312R); * Else, IEEE mode is default. */ -# ifndef CC13XX_CONF_PROP_MODE -# if (SUPPORTS_IEEE_MODE == 0) -# define CC13XX_CONF_PROP_MODE 1 -# else -# define CC13XX_CONF_PROP_MODE 0 -# endif -# endif - - -# if (CC13XX_CONF_PROP_MODE == 1) && (SUPPORTS_PROP_MODE == 1) -/*----- CC13xx Prop Mode ----------------------------------------------------*/ -# define NETSTACK_CONF_RADIO prop_mode_driver - -# define CSMA_CONF_ACK_WAIT_TIME (RTIMER_SECOND / 400) -# define CSMA_CONF_AFTER_ACK_DETECTED_WAIT_TIME \ - (RTIMER_SECOND / 1000) -# define CSMA_CONF_SEND_SOFT_ACK 1 - -# elif (CC13XX_CONF_PROP_MODE == 0) && (SUPPORTS_IEEE_MODE == 1) -/*----- CC13xx IEEE Mode ----------------------------------------------------*/ -# define NETSTACK_CONF_RADIO ieee_mode_driver - -# define CSMA_CONF_SEND_SOFT_ACK 0 - +# ifndef CC13XX_CONF_PROP_MODE +# if (SUPPORTS_IEEE_MODE == 0) +# define CC13XX_CONF_PROP_MODE 1 # else -# error "Invalid radio mode configuration of CC13xx device" -# endif /* (CC13XX_CONF_PROP_MODE == 1) && (SUPPORTS_PROP_MODE == 1) */ +# define CC13XX_CONF_PROP_MODE 0 +# endif +# endif +# if (CC13XX_CONF_PROP_MODE == 1) && (SUPPORTS_PROP_MODE == 1) +/*----- CC13xx Prop Mode ----------------------------------------------------*/ +# define NETSTACK_CONF_RADIO prop_mode_driver + +# define CSMA_CONF_ACK_WAIT_TIME (RTIMER_SECOND / 300) +# define CSMA_CONF_AFTER_ACK_DETECTED_WAIT_TIME (RTIMER_SECOND / 1000) +# define CSMA_CONF_SEND_SOFT_ACK 1 + +# elif (CC13XX_CONF_PROP_MODE == 0) && (SUPPORTS_IEEE_MODE == 1) +/*----- CC13xx IEEE Mode ----------------------------------------------------*/ +# define NETSTACK_CONF_RADIO ieee_mode_driver + +# define CSMA_CONF_SEND_SOFT_ACK 0 + +# else +/*----- CC13xx Non-supported Mode -------------------------------------------*/ +# error "Invalid radio mode configuration of CC13xx device" +# endif /* (CC13XX_CONF_PROP_MODE == 1) && (SUPPORTS_PROP_MODE == 1) */ + +/*----- CC26xx Device Line --------------------------------------------------*/ +/* CC26xx only supports IEEE mode */ #elif defined(DEVICE_LINE_CC26XX) -# if (SUPPORTS_IEEE_MODE == 1) +# if (SUPPORTS_IEEE_MODE == 1) /*----- CC26xx IEEE Mode ----------------------------------------------------*/ -# define NETSTACK_CONF_RADIO ieee_mode_driver +# define NETSTACK_CONF_RADIO ieee_mode_driver -# define CSMA_CONF_SEND_SOFT_ACK 0 +# define CSMA_CONF_SEND_SOFT_ACK 0 -# else -# error "IEEE mode only supported by CC26xx devices" -# endif /* (SUPPORTS_IEEE_MODE == 1) */ +# else +/*----- CC26xx Non-supported Mode -------------------------------------------*/ +# error "IEEE mode only supported by CC26xx devices" +# endif /* (SUPPORTS_IEEE_MODE == 1) */ +/*----- Unsupported device line ---------------------------------------------*/ #else -# error "Unsupported Device Line defined" +# error "Unsupported Device Line defined" #endif /* defined(DEVICE_LINE_CC13xx) */ #define NETSTACK_RADIO_MAX_PAYLOAD_LEN 125 diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-common.c b/arch/cpu/cc13xx-cc26xx/dev/rf-common.c index 76d6f31f2..92339e1ab 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-common.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-common.c @@ -39,25 +39,18 @@ #include #include #include -#include #include #include #include /*---------------------------------------------------------------------------*/ -#include -#include -#include -#include -#include -/*---------------------------------------------------------------------------*/ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "RF" #define LOG_LEVEL LOG_LEVEL_DBG /*---------------------------------------------------------------------------*/ -PROCESS(RF_coreProcess, "SimpleLink RF process"); +PROCESS(rf_process, "SimpleLink RF Process"); /*---------------------------------------------------------------------------*/ -PROCESS_THREAD(RF_coreProcess, ev, data) +PROCESS_THREAD(rf_process, ev, data) { int len; diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-common.h b/arch/cpu/cc13xx-cc26xx/dev/rf-common.h index cd646064f..9c3f244b9 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-common.h +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-common.h @@ -43,34 +43,12 @@ #ifndef RF_COMMON_H_ #define RF_COMMON_H_ /*---------------------------------------------------------------------------*/ -/* Contiki API */ -#include -#include -/*---------------------------------------------------------------------------*/ -/* Standard library */ -#include -/*---------------------------------------------------------------------------*/ -#ifdef RF_CORE_CONF_CHANNEL -# define RF_CORE_CHANNEL RF_CORE_CONF_CHANNEL -#else -# define RF_CORE_CHANNEL 25 -#endif -/*---------------------------------------------------------------------------*/ typedef enum { CMD_RESULT_ERROR = 0, CMD_RESULT_OK = 1, -} CmdResult; +} cmd_result_t; /*---------------------------------------------------------------------------*/ -typedef struct { - radio_value_t dbm; - uint16_t power; ///< Value for the .txPower field -} RF_TxPower; - -#define TX_POWER_UNKNOWN 0xFFFF -/*---------------------------------------------------------------------------*/ -#define RSSI_UNKNOWN -128 -/*---------------------------------------------------------------------------*/ -PROCESS_NAME(RF_coreProcess); +PROCESS_NAME(rf_process); /*---------------------------------------------------------------------------*/ #endif /* RF_COMMON_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c index 4940ff50b..69ec00233 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c @@ -121,7 +121,7 @@ #ifdef IEEE_MODE_CONF_CHANNEL # define IEEE_MODE_CHANNEL IEEE_MODE_CONF_CHANNEL #else -# define IEEE_MODE_CHANNEL RF_CORE_CHANNEL +# define IEEE_MODE_CHANNEL RF_CHANNEL #endif /* Configuration for TX power table */ @@ -301,10 +301,7 @@ static void rx_cb(RF_Handle h, RF_CmdHandle ch, RF_EventMask e) { if (e & RF_EventRxOk) { - process_poll(&RF_coreProcess); - } - if (e & RF_EventRxBufFull) { - + process_poll(&rf_process); } } /*---------------------------------------------------------------------------*/ @@ -343,7 +340,7 @@ init_data_queue(void) static void init_rf_params(void) { - cmd_rx.channel = RF_CORE_CHANNEL; + cmd_rx.channel = IEEE_MODE_CHANNEL; cmd_rx.pRxQ = &g_rxDataQueue; cmd_rx.pOutput = &g_rxStats; @@ -555,7 +552,7 @@ init(void) ctimer_set(&g_ratOverflowTimer, RAT_OVERFLOW_PERIOD_SECONDS * CLOCK_SECOND / 2, rat_overflow_cb, NULL); - process_start(&RF_coreProcess, NULL); + process_start(&rf_process, NULL); return CMD_RESULT_OK; } @@ -812,23 +809,25 @@ pending_packet(void) const rfc_dataEntry_t *const pStartEntry = (rfc_dataEntry_t *)g_rxDataQueue.pCurrEntry; volatile const rfc_dataEntry_t *pCurrEntry = pStartEntry; + int rv = 0; + // Check all RX buffers and check their statuses, stopping when looping the circular buffer - int bIsPending = 0; do { const uint8_t status = pCurrEntry->status; if ((status == DATA_ENTRY_FINISHED) || (status == DATA_ENTRY_BUSY)) { - bIsPending = 1; - if (!g_bPollMode) { - process_poll(&RF_coreProcess); - } + rv += 1; } pCurrEntry = (rfc_dataEntry_t *)pCurrEntry->pNextEntry; } while (pCurrEntry != pStartEntry); + if ((rv > 0) && !g_bPollMode) { + process_poll(&rf_process); + } + // If we didn't find an entry at status finished or busy, no frames are pending - return bIsPending; + return rv; } /*---------------------------------------------------------------------------*/ static int @@ -909,7 +908,7 @@ get_value(radio_param_t param, radio_value_t *value) case RADIO_PARAM_TXPOWER: *value = get_tx_power(); - return (*value == TX_POWER_UNKNOWN) + return (*value == RF_TxPowerTable_INVALID_DBM) ? RADIO_RESULT_ERROR : RADIO_RESULT_OK; diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c index 70d355623..c1642a2ba 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c @@ -57,9 +57,9 @@ /*---------------------------------------------------------------------------*/ /* RF settings */ #ifdef PROP_MODE_CONF_RF_SETTINGS -# define PROP_MODE_RF_SETTINGS PROP_MODE_CONF_RF_SETTINGS +# define PROP_MODE_RF_SETTINGS PROP_MODE_CONF_RF_SETTINGS #else -# define PROP_MODE_RF_SETTINGS "prop-settings.h" +# define PROP_MODE_RF_SETTINGS "prop-settings.h" #endif #include PROP_MODE_RF_SETTINGS @@ -75,37 +75,31 @@ #include /*---------------------------------------------------------------------------*/ #ifdef NDEBUG -# define PRINTF(...) +# define PRINTF(...) #else -# define PRINTF(...) printf(__VA_ARGS__) +# define PRINTF(...) printf(__VA_ARGS__) +#endif +/*---------------------------------------------------------------------------*/ +/* Configuration for default Prop channel */ +#ifdef PROP_MODE_CONF_CHANNEL +# define PROP_MODE_CHANNEL PROP_MODE_CONF_CHANNEL +#else +# define PROP_MODE_CHANNEL RF_CHANNEL #endif /*---------------------------------------------------------------------------*/ /* Data whitener. 1: Whitener, 0: No whitener */ #ifdef PROP_MODE_CONF_DW -# define PROP_MODE_DW PROP_MODE_CONF_DW +# define PROP_MODE_DW PROP_MODE_CONF_DW #else -# define PROP_MODE_DW 0 +# define PROP_MODE_DW 0 #endif #ifdef PROP_MODE_CONF_USE_CRC16 -# define PROP_MODE_USE_CRC16 PROP_MODE_CONF_USE_CRC16 +# define PROP_MODE_USE_CRC16 PROP_MODE_CONF_USE_CRC16 #else -# define PROP_MODE_USE_CRC16 0 +# define PROP_MODE_USE_CRC16 0 #endif /*---------------------------------------------------------------------------*/ -/** - * \brief Returns the current status of a running Radio Op command - * \param a A pointer with the buffer used to initiate the command - * \return The value of the Radio Op buffer's status field - * - * This macro can be used to e.g. return the status of a previously - * initiated background operation, or of an immediate command - */ -#define RF_RADIO_OP_GET_STATUS(a) GET_FIELD_V(a, radioOp, status) -/*---------------------------------------------------------------------------*/ -/* Special value returned by CMD_IEEE_CCA_REQ when an RSSI is not available */ -#define RF_CMD_CCA_REQ_RSSI_UNKNOWN -128 - /* Used for the return value of channel_clear */ #define RF_CCA_CLEAR 1 #define RF_CCA_BUSY 0 @@ -122,17 +116,10 @@ #define RF_CMD_CCA_REQ_CCA_STATE_INVALID 2 /* 10 */ #ifdef PROP_MODE_CONF_RSSI_THRESHOLD -#define PROP_MODE_RSSI_THRESHOLD PROP_MODE_CONF_RSSI_THRESHOLD +# define PROP_MODE_RSSI_THRESHOLD PROP_MODE_CONF_RSSI_THRESHOLD #else -#define PROP_MODE_RSSI_THRESHOLD 0xA6 +# define PROP_MODE_RSSI_THRESHOLD 0xA6 #endif - -static int8_t rssi_threshold = PROP_MODE_RSSI_THRESHOLD; -/*---------------------------------------------------------------------------*/ -static int rf_switch_on(void); -static int rf_switch_off(void); - -static rfc_propRxOutput_t rx_stats; /*---------------------------------------------------------------------------*/ /* Defines and variables related to the .15.4g PHY HDR */ #define DOT_4G_MAX_FRAME_LEN 2047 @@ -144,31 +131,28 @@ static rfc_propRxOutput_t rx_stats; #if PROP_MODE_USE_CRC16 /* CRC16 */ -#define DOT_4G_PHR_CRC_BIT DOT_4G_PHR_CRC16 -#define CRC_LEN 2 +# define DOT_4G_PHR_CRC_BIT DOT_4G_PHR_CRC16 +# define CRC_LEN 2 #else /* CRC32 */ -#define DOT_4G_PHR_CRC_BIT 0 -#define CRC_LEN 4 -#endif +# define DOT_4G_PHR_CRC_BIT 0 +# define CRC_LEN 4 +#endif /* PROP_MODE_USE_CRC16 */ #if PROP_MODE_DW -#define DOT_4G_PHR_DW_BIT DOT_4G_PHR_DW +# define DOT_4G_PHR_DW_BIT DOT_4G_PHR_DW #else -#define DOT_4G_PHR_DW_BIT 0 + #define DOT_4G_PHR_DW_BIT 0 #endif /*---------------------------------------------------------------------------*/ -/* How long to wait for an ongoing ACK TX to finish before starting frame TX */ -#define TX_WAIT_TIMEOUT (RTIMER_SECOND >> 11) - /* How long to wait for the RF to enter RX in rf_cmd_ieee_rx */ #define ENTER_RX_WAIT_TIMEOUT (RTIMER_SECOND >> 10) /*---------------------------------------------------------------------------*/ /* Configuration for TX power table */ #ifdef PROP_MODE_CONF_TX_POWER_TABLE -# define TX_POWER_TABLE PROP_MODE_CONF_TX_POWER_TABLE +# define TX_POWER_TABLE PROP_MODE_CONF_TX_POWER_TABLE #else -# define TX_POWER_TABLE propTxPowerTable +# define TX_POWER_TABLE propTxPowerTable #endif /*---------------------------------------------------------------------------*/ /* TX power table convenience macros */ @@ -179,119 +163,131 @@ static rfc_propRxOutput_t rx_stats; #define TX_POWER_IN_RANGE(dbm) (((dbm) >= TX_POWER_MIN) && ((dbm) <= TX_POWER_MAX)) /*---------------------------------------------------------------------------*/ +/* TX buf configuration */ +#define TX_BUF_HDR_LEN 2 +#define TX_BUF_PAYLOAD_LEN 180 + +#define TX_BUF_SIZE (TX_BUF_HDR_LEN + TX_BUF_PAYLOAD_LEN) + +/* RX buf configuration */ #ifdef PROP_MODE_CONF_RX_BUF_CNT -#define PROP_MODE_RX_BUF_CNT PROP_MODE_CONF_RX_BUF_CNT +# define RX_BUF_CNT PROP_MODE_CONF_RX_BUF_CNT #else -#define PROP_MODE_RX_BUF_CNT 4 +# define RX_BUF_CNT 4 #endif + +#define RX_BUF_SIZE 140 /*---------------------------------------------------------------------------*/ #define DATA_ENTRY_LENSZ_NONE 0 #define DATA_ENTRY_LENSZ_BYTE 1 #define DATA_ENTRY_LENSZ_WORD 2 /* 2 bytes */ - -/* - * RX buffers. - * PROP_MODE_RX_BUF_CNT buffers of RX_BUF_SIZE bytes each. The start of each - * buffer must be 4-byte aligned, therefore RX_BUF_SIZE must divide by 4 - */ -#define RX_BUF_SIZE 140 -static uint8_t rx_buf[PROP_MODE_RX_BUF_CNT][RX_BUF_SIZE] CC_ALIGN(4); - -/* The RX Data Queue */ -static dataQueue_t rx_data_queue = { 0 }; - -/* Receive entry pointer to keep track of read items */ -volatile static uint8_t *rx_read_entry; /*---------------------------------------------------------------------------*/ -/* The outgoing frame buffer */ -#define TX_BUF_PAYLOAD_LEN 180 -#define TX_BUF_HDR_LEN 2 +#define MAC_RADIO_RECEIVER_SENSITIVITY_DBM -110 +#define MAC_RADIO_RECEIVER_SATURATION_DBM 10 +#define MAC_SPEC_ED_MIN_DBM_ABOVE_RECEIVER_SENSITIVITY 10 +#define MAC_SPEC_ED_MAX 0xFF -static uint8_t tx_buf[TX_BUF_HDR_LEN + TX_BUF_PAYLOAD_LEN] CC_ALIGN(4); +#define ED_RF_POWER_MIN_DBM (MAC_RADIO_RECEIVER_SENSITIVITY_DBM + MAC_SPEC_ED_MIN_DBM_ABOVE_RECEIVER_SENSITIVITY) +#define ED_RF_POWER_MAX_DBM MAC_RADIO_RECEIVER_SATURATION_DBM /*---------------------------------------------------------------------------*/ -#define cmd_radio_setup ((volatile rfc_CMD_PROP_RADIO_DIV_SETUP_t *)&rf_cmd_prop_radio_div_setup) -#define cmd_fs ((volatile rfc_CMD_FS_t *) &rf_cmd_prop_fs) -#define cmd_tx ((volatile rfc_CMD_PROP_TX_ADV_t *) &rf_cmd_prop_tx_adv) -#define cmd_rx ((volatile rfc_CMD_PROP_RX_ADV_t *) &rf_cmd_prop_rx_adv) +typedef struct { + /* Outgoing frame buffer */ + uint8_t tx_buf[TX_BUF_SIZE] CC_ALIGN(4); + /* Incoming frame buffer */ + uint8_t rx_buf[RX_BUF_CNT][RX_BUF_SIZE] CC_ALIGN(4); + + /* RX Data Queue */ + dataQueue_t rx_data_queue; + /* RX Statistics struct */ + rfc_propRxOutput_t rx_stats; + /* Receive entry pointer to keep track of read items */ + volatile uint8_t* rx_read_entry; + + /* RSSI Threshold */ + int8_t rssi_threshold; + + /* Indicates RF is supposed to be on or off */ + uint8_t rf_is_on; + + /* RF driver */ + RF_Object rf_object; + RF_Handle rf_handle; +} prop_radio_t; + +static prop_radio_t prop_radio; /*---------------------------------------------------------------------------*/ -/* RF driver */ -static RF_Object rfObject; -static RF_Handle rfHandle; +#define cmd_radio_setup (*(volatile rfc_CMD_PROP_RADIO_DIV_SETUP_t *)&rf_cmd_prop_radio_div_setup) +#define cmd_fs (*(volatile rfc_CMD_FS_t *) &rf_cmd_prop_fs) +#define cmd_tx (*(volatile rfc_CMD_PROP_TX_ADV_t *) &rf_cmd_prop_tx_adv) +#define cmd_rx (*(volatile rfc_CMD_PROP_RX_ADV_t *) &rf_cmd_prop_rx_adv) /*---------------------------------------------------------------------------*/ -static CC_INLINE bool rf_is_transmitting(void) { return cmd_tx->status == ACTIVE; } -static CC_INLINE bool rf_is_receiving(void) { return cmd_rx->status == ACTIVE; } -static CC_INLINE bool rf_is_on(void) { return rf_is_transmitting() || rf_is_receiving(); } +static CC_INLINE bool tx_active(void) { return cmd_tx.status == ACTIVE; } +static CC_INLINE bool rx_active(void) { return cmd_rx.status == ACTIVE; } +/*---------------------------------------------------------------------------*/ +static int on(void); +static int off(void); /*---------------------------------------------------------------------------*/ static void -rf_rx_callback(RF_Handle client, RF_CmdHandle command, RF_EventMask events) +cmd_rx_cb(RF_Handle client, RF_CmdHandle command, RF_EventMask events) { - if (events & RF_EventRxEntryDone) { - process_poll(&RF_coreProcess); - } + /* Unused arguments */ + (void)client; + (void)command; + + if (events & RF_EventRxEntryDone) { + process_poll(&rf_process); + } } /*---------------------------------------------------------------------------*/ -static CmdResult -rf_start_rx() +static cmd_result_t +start_rx(void) { - cmd_rx->status = IDLE; + cmd_rx.status = IDLE; + RF_CmdHandle rx_handle = RF_postCmd(prop_radio.rf_handle, (RF_Op*)&cmd_rx, RF_PriorityNormal, + &cmd_rx_cb, RF_EventRxEntryDone); + if (rx_handle == RF_ALLOC_ERROR) { + PRINTF("start_rx: RF_ALLOC_ERROR for cmd_rx\n"); + return CMD_RESULT_ERROR; + } - /* - * Set the max Packet length. This is for the payload only, therefore - * 2047 - length offset - */ - cmd_rx->maxPktLen = DOT_4G_MAX_FRAME_LEN - cmd_rx->lenOffset; + /* Wait to enter RX */ + const rtimer_clock_t t0 = RTIMER_NOW(); + while (!rx_active() && + (RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + ENTER_RX_WAIT_TIMEOUT))); - RF_CmdHandle rxCmdHandle = RF_postCmd(rfHandle, (RF_Op*)cmd_rx, RF_PriorityNormal, - &rf_rx_callback, RF_EventRxEntryDone); - if (rxCmdHandle == RF_ALLOC_ERROR) { - return CMD_RESULT_ERROR; - } + if (!rx_active()) { + PRINTF("cmd_rx: status=0x%04x\n", cmd_rx.status); + return CMD_RESULT_ERROR; + } - /* Wait to enter RX */ - const rtimer_clock_t t0 = RTIMER_NOW(); - while (!rf_is_receiving() && - (RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + ENTER_RX_WAIT_TIMEOUT))); - - if (!rf_is_receiving()) { - PRINTF("RF_cmdPropRxAdv: handle=0x%08lx, status=0x%04x\n", - (unsigned long)rxCmdHandle, cmd_rx->status); - rf_switch_off(); - return CMD_RESULT_ERROR; - } - - return CMD_RESULT_OK; + return CMD_RESULT_OK; } /*---------------------------------------------------------------------------*/ -static CmdResult -rf_stop_rx(void) +static cmd_result_t +stop_rx(void) { - /* If we are off, do nothing */ - if (!rf_is_receiving()) { - return CMD_RESULT_OK; - } + /* Abort any ongoing operation. Don't care about the result. */ + RF_cancelCmd(prop_radio.rf_handle, RF_CMDHANDLE_FLUSH_ALL, 1); - /* Abort any ongoing operation. Don't care about the result. */ - RF_cancelCmd(rfHandle, RF_CMDHANDLE_FLUSH_ALL, 1); + /* Todo: maybe do a RF_pendCmd() to synchronize with command execution. */ - /* Todo: maybe do a RF_pendCmd() to synchronize with command execution. */ + if(cmd_rx.status != PROP_DONE_STOPPED && + cmd_rx.status != PROP_DONE_ABORT) { + PRINTF("RF_cmdPropRxAdv cancel: status=0x%04x\n", + cmd_rx.status); + return CMD_RESULT_ERROR; + } - if(cmd_rx->status != PROP_DONE_STOPPED && - cmd_rx->status != PROP_DONE_ABORT) { - PRINTF("RF_cmdPropRxAdv cancel: status=0x%04x\n", - cmd_rx->status); - return CMD_RESULT_ERROR; - } - - /* Stopped gracefully */ - ENERGEST_OFF(ENERGEST_TYPE_LISTEN); - return CMD_RESULT_OK; + /* Stopped gracefully */ + ENERGEST_OFF(ENERGEST_TYPE_LISTEN); + return CMD_RESULT_OK; } /*---------------------------------------------------------------------------*/ -static CmdResult +static cmd_result_t rf_run_setup() { - RF_runCmd(rfHandle, (RF_Op*)cmd_radio_setup, RF_PriorityNormal, NULL, 0); - if (cmd_radio_setup->status != PROP_DONE_OK) { + RF_runCmd(prop_radio.rf_handle, (RF_Op*)&cmd_radio_setup, RF_PriorityNormal, NULL, 0); + if (cmd_radio_setup.status != PROP_DONE_OK) { return CMD_RESULT_ERROR; } @@ -301,35 +297,33 @@ rf_run_setup() static radio_value_t get_rssi(void) { - if (rf_is_transmitting()) { - PRINTF("get_rssi: called while in TX\n"); - return RF_GET_RSSI_ERROR_VAL; - } + if (tx_active()) { + PRINTF("get_rssi: called while in TX\n"); + return RF_GET_RSSI_ERROR_VAL; + } - const bool was_off = !rf_is_receiving(); - if (was_off && rf_start_rx() == CMD_RESULT_ERROR) { - PRINTF("get_rssi: unable to start RX\n"); - return RF_GET_RSSI_ERROR_VAL; - } + const bool was_off = !rx_active(); + if (was_off && start_rx() == CMD_RESULT_ERROR) { + PRINTF("get_rssi: unable to start RX\n"); + return RF_GET_RSSI_ERROR_VAL; + } - int8_t rssi = RF_GET_RSSI_ERROR_VAL; - while(rssi == RF_GET_RSSI_ERROR_VAL || rssi == 0) { - rssi = RF_getRssi(rfHandle); - } + int8_t rssi = RF_GET_RSSI_ERROR_VAL; + while(rssi == RF_GET_RSSI_ERROR_VAL || rssi == 0) { + rssi = RF_getRssi(prop_radio.rf_handle); + } - if(was_off) { - rf_switch_off(); - } + if (was_off) { + stop_rx(); + } - return rssi; + return rssi; } /*---------------------------------------------------------------------------*/ static uint8_t get_channel(void) { - uint32_t freq_khz; - - freq_khz = cmd_fs->frequency * 1000; + uint32_t freq_khz = cmd_fs.frequency * 1000; /* * For some channels, fractFreq * 1000 / 65536 will return 324.99xx. @@ -337,40 +331,48 @@ get_channel(void) * function returning channel - 1 instead of channel. Thus, we do a quick * positive integer round up. */ - freq_khz += (((cmd_fs->fractFreq * 1000) + 65535) / 65536); + freq_khz += (((cmd_fs.fractFreq * 1000) + 65535) / 65536); return (freq_khz - DOT_15_4G_CHAN0_FREQUENCY) / DOT_15_4G_CHANNEL_SPACING; } /*---------------------------------------------------------------------------*/ -static void +static cmd_result_t set_channel(uint8_t channel) { - uint32_t new_freq = DOT_15_4G_CHAN0_FREQUENCY + (channel * DOT_15_4G_CHANNEL_SPACING); + uint32_t new_freq = DOT_15_4G_CHAN0_FREQUENCY + (channel * DOT_15_4G_CHANNEL_SPACING); - uint16_t freq = (uint16_t)(new_freq / 1000); - uint16_t frac = (new_freq - (freq * 1000)) * 65536 / 1000; + uint16_t freq = (uint16_t)(new_freq / 1000); + uint16_t frac = (new_freq - (freq * 1000)) * 65536 / 1000; - PRINTF("set_channel: %u = 0x%04x.0x%04x (%lu)\n", - channel, freq, frac, new_freq); + PRINTF("set_channel: %u = 0x%04x.0x%04x (%lu)\n", + channel, freq, frac, new_freq); - cmd_radio_setup->centerFreq = freq; - cmd_fs->frequency = freq; - cmd_fs->fractFreq = frac; + cmd_radio_setup.centerFreq = freq; + cmd_fs.frequency = freq; + cmd_fs.fractFreq = frac; - // Todo: Need to re-run setup command when deviation from previous frequency - // is too large - // rf_run_setup(); + // We don't care whether the FS command is successful because subsequent + // TX and RX commands will tell us indirectly. + RF_EventMask rf_events = RF_runCmd(prop_radio.rf_handle, (RF_Op*)&cmd_fs, + RF_PriorityNormal, NULL, 0); + if ((rf_events & (RF_EventCmdDone | RF_EventLastCmdDone)) == 0) { + PRINTF("set_channel: RF_runCmd failed, events=0x%llx\n", rf_events); + return CMD_RESULT_ERROR; + } - // We don't care whether the FS command is successful because subsequent - // TX and RX commands will tell us indirectly. - RF_postCmd(rfHandle, (RF_Op*)cmd_fs, RF_PriorityNormal, NULL, 0); + if (cmd_fs.status != DONE_OK) { + PRINTF("set_channel: cmd_fs failed, status=0x%04x\n", cmd_fs.status); + return CMD_RESULT_ERROR; + } + + return CMD_RESULT_OK; } /*---------------------------------------------------------------------------*/ /* Returns the current TX power in dBm */ static radio_value_t get_tx_power(void) { - const RF_TxPowerTable_Value value = RF_getTxPower(rfHandle); + const RF_TxPowerTable_Value value = RF_getTxPower(prop_radio.rf_handle); return (radio_value_t)RF_TxPowerTable_findPowerLevel(TX_POWER_TABLE, value); } /*---------------------------------------------------------------------------*/ @@ -385,80 +387,97 @@ set_tx_power(const radio_value_t power) return RADIO_RESULT_INVALID_VALUE; } const RF_TxPowerTable_Value value = RF_TxPowerTable_findValue(TX_POWER_TABLE, power); - RF_Stat stat = RF_setTxPower(rfHandle, value); + RF_Stat stat = RF_setTxPower(prop_radio.rf_handle, value); return (stat == RF_StatSuccess) ? RADIO_RESULT_OK : RADIO_RESULT_ERROR; } /*---------------------------------------------------------------------------*/ +static uint8_t +calculate_lqi(int8_t rssi) +{ + /* Note : Currently the LQI value is simply the energy detect measurement. + * A more accurate value could be derived by using the correlation + * value along with the RSSI value. */ + rssi = CLAMP(rssi, ED_RF_POWER_MIN_DBM, ED_RF_POWER_MAX_DBM); + + /* Create energy detect measurement by normalizing and scaling RF power level. + * Note : The division operation below is designed for maximum accuracy and + * best granularity. This is done by grouping the math operations to + * compute the entire numerator before doing any division. */ + return (MAC_SPEC_ED_MAX * (rssi - ED_RF_POWER_MIN_DBM)) / (ED_RF_POWER_MAX_DBM - ED_RF_POWER_MIN_DBM); +} +/*---------------------------------------------------------------------------*/ static void init_rx_buffers(void) { - rfc_dataEntry_t *entry; - int i; - - for(i = 0; i < PROP_MODE_RX_BUF_CNT; i++) { - entry = (rfc_dataEntry_t *)rx_buf[i]; - entry->status = DATA_ENTRY_PENDING; - entry->config.type = DATA_ENTRY_TYPE_GEN; - entry->config.lenSz = DATA_ENTRY_LENSZ_WORD; - entry->length = RX_BUF_SIZE - 8; - entry->pNextEntry = rx_buf[i + 1]; + size_t i = 0; + for (i = 0; i < RX_BUF_CNT; i++) { + const rfc_dataEntry_t data_entry = { + .status = DATA_ENTRY_PENDING, + .config.type = DATA_ENTRY_TYPE_GEN, + .config.lenSz = DATA_ENTRY_LENSZ_WORD, + .length = RX_BUF_SIZE - sizeof(rfc_dataEntry_t), /* TODO is this sizeof sound? */ + /* Point to fist entry if this is last entry, else point to next entry */ + .pNextEntry = (i == (RX_BUF_CNT - 1)) + ? prop_radio.rx_buf[0] + : prop_radio.rx_buf[i] + }; + /* Write back data entry struct */ + *(rfc_dataEntry_t *)prop_radio.rx_buf[i] = data_entry; } - - ((rfc_dataEntry_t *)rx_buf[PROP_MODE_RX_BUF_CNT - 1])->pNextEntry = rx_buf[0]; } /*---------------------------------------------------------------------------*/ static int prepare(const void *payload, unsigned short payload_len) { - int len = MIN(payload_len, TX_BUF_PAYLOAD_LEN); + int len = MIN(payload_len, TX_BUF_PAYLOAD_LEN); - memcpy(&tx_buf[TX_BUF_HDR_LEN], payload, len); - return 0; + memcpy(prop_radio.tx_buf + TX_BUF_HDR_LEN, payload, len); + return 0; } /*---------------------------------------------------------------------------*/ static int transmit(unsigned short transmit_len) { - int ret; - uint8_t was_off = 0; + int ret; + uint8_t was_off = 0; - if (rf_is_transmitting()) { - PRINTF("transmit: not allowed while transmitting\n"); - return RADIO_TX_ERR; - } else if (rf_is_receiving()) { - rf_stop_rx(); - } else { - was_off = 1; - } + if (tx_active()) { + PRINTF("transmit: not allowed while transmitting\n"); + return RADIO_TX_ERR; + } else if (rx_active()) { + stop_rx(); + } else { + was_off = 1; + } - /* Length in .15.4g PHY HDR. Includes the CRC but not the HDR itself */ - uint16_t total_length; + /* Length in .15.4g PHY HDR. Includes the CRC but not the HDR itself */ + uint16_t total_length; - /* - * Prepare the .15.4g PHY header - * MS=0, Length MSBits=0, DW and CRC configurable - * Total length = transmit_len (payload) + CRC length - * - * The Radio will flip the bits around, so tx_buf[0] must have the length - * LSBs (PHR[15:8] and tx_buf[1] will have PHR[7:0] - */ - total_length = transmit_len + CRC_LEN; + /* + * Prepare the .15.4g PHY header + * MS=0, Length MSBits=0, DW and CRC configurable + * Total length = transmit_len (payload) + CRC length + * + * The Radio will flip the bits around, so tx_buf[0] must have the length + * LSBs (PHR[15:8] and tx_buf[1] will have PHR[7:0] + */ + total_length = transmit_len + CRC_LEN; - tx_buf[0] = total_length & 0xFF; - tx_buf[1] = (total_length >> 8) + DOT_4G_PHR_DW_BIT + DOT_4G_PHR_CRC_BIT; + prop_radio.tx_buf[0] = total_length & 0xFF; + prop_radio.tx_buf[1] = (total_length >> 8) + DOT_4G_PHR_DW_BIT + DOT_4G_PHR_CRC_BIT; - /* - * pktLen: Total number of bytes in the TX buffer, including the header if - * one exists, but not including the CRC (which is not present in the buffer) - */ - cmd_tx->pktLen = transmit_len + DOT_4G_PHR_LEN; - cmd_tx->pPkt = tx_buf; + /* + * pktLen: Total number of bytes in the TX buffer, including the header if + * one exists, but not including the CRC (which is not present in the buffer) + */ + cmd_tx.pktLen = transmit_len + DOT_4G_PHR_LEN; + cmd_tx.pPkt = prop_radio.tx_buf; - // TODO: Register callback - RF_runCmd(rfHandle, (RF_Op*)cmd_tx, RF_PriorityNormal, NULL, 0); + // TODO: Register callback + RF_runCmd(prop_radio.rf_handle, (RF_Op*)&cmd_tx, RF_PriorityNormal, NULL, 0); // if (txHandle == RF_ALLOC_ERROR) // { // /* Failure sending the CMD_PROP_TX command */ @@ -472,173 +491,194 @@ transmit(unsigned short transmit_len) // // watchdog_periodic(); // // /* Idle away while the command is running */ -// RF_pendCmd(rfHandle, txHandle, RF_EventLastCmdDone); +// RF_pendCmd(rf_handle, txHandle, RF_EventLastCmdDone); - if(cmd_tx->status == PROP_DONE_OK) { - /* Sent OK */ - ret = RADIO_TX_OK; - } else { - /* Operation completed, but frame was not sent */ - PRINTF("transmit: Not Sent OK status=0x%04x\n", - cmd_tx->status); - ret = RADIO_TX_ERR; - } + if(cmd_tx.status == PROP_DONE_OK) { + /* Sent OK */ + ret = RADIO_TX_OK; + } else { + /* Operation completed, but frame was not sent */ + PRINTF("transmit: Not Sent OK status=0x%04x\n", + cmd_tx.status); + ret = RADIO_TX_ERR; + } - ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); + ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); - /* Workaround. Set status to IDLE */ - cmd_tx->status = IDLE; + /* Workaround. Set status to IDLE */ + cmd_tx.status = IDLE; - if (was_off) { - RF_yield(rfHandle); - } else { - rf_start_rx(); - } + if (was_off) { + RF_yield(prop_radio.rf_handle); + } else { + start_rx(); + } - return ret; + return ret; } /*---------------------------------------------------------------------------*/ static int send(const void *payload, unsigned short payload_len) { - prepare(payload, payload_len); - return transmit(payload_len); + prepare(payload, payload_len); + return transmit(payload_len); } /*---------------------------------------------------------------------------*/ static int -read_frame(void *buf, unsigned short buf_len) +read(void *buf, unsigned short buf_len) { - rfc_dataEntryGeneral_t *entry = (rfc_dataEntryGeneral_t *)rx_read_entry; - uint8_t *data_ptr = &entry->data; - int len = 0; + rfc_dataEntryGeneral_t *entry = (rfc_dataEntryGeneral_t *)prop_radio.rx_read_entry; + uint8_t *data_ptr = &entry->data; + uint16_t len = 0; - if(entry->status == DATA_ENTRY_FINISHED) { + if (entry->status != DATA_ENTRY_FINISHED) { + return 0; + } - /* - * First 2 bytes in the data entry are the length. - * Our data entry consists of: Payload + RSSI (1 byte) + Status (1 byte) - * This length includes all of those. - */ - len = (*(uint16_t *)data_ptr); - data_ptr += 2; - len -= 2; + /* First 2 bytes in the data entry are the length. + * Our data entry consists of: Payload + RSSI (1 byte) + Status (1 byte) + * This length includes all of those. */ + len = *(uint16_t *)data_ptr; + data_ptr += 2; + len -= 2; - if(len > 0) { - if(len <= buf_len) { - memcpy(buf, data_ptr, len); - } + const bool len_ok = (0 < len) && (len <= (uint16_t)buf_len); + if (len_ok) { + memcpy(buf, data_ptr, len); - packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (int8_t)data_ptr[len]); - packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, 0x7F); - } + int8_t rssi = (int8_t)data_ptr[len]; + uint8_t lqi = calculate_lqi(rssi); - /* Move read entry pointer to next entry */ - rx_read_entry = entry->pNextEntry; - entry->status = DATA_ENTRY_PENDING; - } + packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (packetbuf_attr_t)rssi); + packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, (packetbuf_attr_t)lqi); + } - return len; + /* Move read entry pointer to next entry */ + prop_radio.rx_read_entry = entry->pNextEntry; + entry->status = DATA_ENTRY_PENDING; + + return (len_ok) + ? (int)len + : 0; } /*---------------------------------------------------------------------------*/ static int channel_clear(void) { - uint8_t was_off = 0; - int8_t rssi = RF_CMD_CCA_REQ_RSSI_UNKNOWN; - -// /* -// * If we are in the middle of a BLE operation, we got called by ContikiMAC -// * from within an interrupt context. Indicate a clear channel -// */ -// if(rf_ble_is_active() == RF_BLE_ACTIVE) { -// return RF_CCA_CLEAR; -// } - - if (rf_is_transmitting()) { - PRINTF("channel_clear: called while in TX\n"); - return RF_CCA_CLEAR; - } else if (!rf_is_receiving()) { - was_off = 1; - rf_start_rx(); - } - - while(rssi == RF_CMD_CCA_REQ_RSSI_UNKNOWN || rssi == 0) { - rssi = RF_getRssi(rfHandle); - } - - if(was_off) { - rf_switch_off(); - } - - if(rssi >= rssi_threshold) { - return RF_CCA_BUSY; - } - + if (tx_active()) { + PRINTF("channel_clear: called while in TX\n"); return RF_CCA_CLEAR; + } + + const bool rx_was_off = !rx_active(); + if (rx_was_off) { + start_rx(); + } + + int8_t rssi = RF_GET_RSSI_ERROR_VAL; + while (rssi == RF_GET_RSSI_ERROR_VAL || rssi == 0) { + rssi = RF_getRssi(prop_radio.rf_handle); + } + + if (rx_was_off) { + stop_rx(); + } + + if(rssi >= prop_radio.rssi_threshold) { + return RF_CCA_BUSY; + } + + return RF_CCA_CLEAR; } /*---------------------------------------------------------------------------*/ static int receiving_packet(void) { - if(!rf_is_receiving()) { - return 0; - } + if (!rx_active()) { + return 0; + } - if(channel_clear() == RF_CCA_CLEAR) { - return 0; - } + if (channel_clear() == RF_CCA_CLEAR) { + return 0; + } - return 1; + return 1; } /*---------------------------------------------------------------------------*/ static int pending_packet(void) { - int rv = 0; - volatile rfc_dataEntry_t *entry = (rfc_dataEntry_t *)rx_data_queue.pCurrEntry; + const rfc_dataEntry_t *const first_entry = (rfc_dataEntry_t *)prop_radio.rx_data_queue.pCurrEntry; + volatile const rfc_dataEntry_t *entry = first_entry; - /* Go through all RX buffers and check their status */ - do { - if(entry->status == DATA_ENTRY_FINISHED) { - rv += 1; - process_poll(&RF_coreProcess); - } + int rv = 0; - entry = (rfc_dataEntry_t *)entry->pNextEntry; - } while(entry != (rfc_dataEntry_t *)rx_data_queue.pCurrEntry); + /* Go through RX Circular buffer and check their status */ + do { + const uint8_t status = entry->status; + if ((status == DATA_ENTRY_FINISHED) || + (status == DATA_ENTRY_BUSY)) { + rv += 1; + } - /* If we didn't find an entry at status finished, no frames are pending */ - return rv; + entry = (rfc_dataEntry_t *)entry->pNextEntry; + } while (entry != first_entry); + + if (rv > 0) { + process_poll(&rf_process); + } + + /* If we didn't find an entry at status finished, no frames are pending */ + return rv; } /*---------------------------------------------------------------------------*/ static int -rf_switch_on(void) +on(void) { - init_rx_buffers(); - return rf_start_rx(); -} -/*---------------------------------------------------------------------------*/ -static int -rf_switch_off(void) -{ -// /* -// * If we are in the middle of a BLE operation, we got called by ContikiMAC -// * from within an interrupt context. Abort, but pretend everything is OK. -// */ -// if(rf_ble_is_active() == RF_BLE_ACTIVE) { -// return CMD_RESULT_OK; -// } - - // Force abort of any ongoing RF operation. - RF_cancelCmd(rfHandle, RF_CMDHANDLE_FLUSH_ALL, 0); - - // Trigger a manual power-down - RF_yield(rfHandle); - - /* We pulled the plug, so we need to restore the status manually */ - cmd_rx->status = IDLE; - + if (prop_radio.rf_is_on) { + PRINTF("RF on: Radio already in RX\n"); return CMD_RESULT_OK; + } + + /* Reset all RF command statuses */ + cmd_radio_setup.status = IDLE; + cmd_fs.status = IDLE; + cmd_tx.status = IDLE; + cmd_rx.status = IDLE; + + init_rx_buffers(); + + const int rx_ok = start_rx(); + if (!rx_ok) { + off(); + return CMD_RESULT_ERROR; + } + + prop_radio.rf_is_on = true; + return CMD_RESULT_OK; +} +/*---------------------------------------------------------------------------*/ +static int +off(void) +{ + if (!prop_radio.rf_is_on) { + return CMD_RESULT_OK; + } + + // Force abort of any ongoing RF operation. + RF_flushCmd(prop_radio.rf_handle, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY); + + // Trigger a manual power-down + RF_yield(prop_radio.rf_handle); + + /* We pulled the plug, so we need to restore the status manually */ + cmd_radio_setup.status = IDLE; + cmd_fs.status = IDLE; + cmd_tx.status = IDLE; + cmd_rx.status = IDLE; + + prop_radio.rf_is_on = false; + return CMD_RESULT_OK; } /*---------------------------------------------------------------------------*/ static radio_result_t @@ -651,7 +691,10 @@ get_value(radio_param_t param, radio_value_t *value) switch (param) { case RADIO_PARAM_POWER_MODE: /* On / off */ - *value = rf_is_on() ? RADIO_POWER_MODE_ON : RADIO_POWER_MODE_OFF; + *value = (prop_radio.rf_is_on) + ? RADIO_POWER_MODE_ON + : RADIO_POWER_MODE_OFF; + return RADIO_RESULT_OK; case RADIO_PARAM_CHANNEL: @@ -663,12 +706,12 @@ get_value(radio_param_t param, radio_value_t *value) return RADIO_RESULT_OK; case RADIO_PARAM_CCA_THRESHOLD: - *value = rssi_threshold; + *value = prop_radio.rssi_threshold; return RADIO_RESULT_OK; case RADIO_PARAM_RSSI: *value = get_rssi(); - return (*value == RF_CMD_CCA_REQ_RSSI_UNKNOWN) + return (*value == RF_GET_RSSI_ERROR_VAL) ? RADIO_RESULT_ERROR : RADIO_RESULT_OK; @@ -703,7 +746,7 @@ set_value(radio_param_t param, radio_value_t value) return RADIO_RESULT_OK; } if(value == RADIO_POWER_MODE_OFF) { - rf_switch_off(); + off(); return RADIO_RESULT_OK; } return RADIO_RESULT_INVALID_VALUE; @@ -730,7 +773,7 @@ set_value(radio_param_t param, radio_value_t value) return RADIO_RESULT_OK; case RADIO_PARAM_CCA_THRESHOLD: - rssi_threshold = (int8_t)value; + prop_radio.rssi_threshold = (int8_t)value; return RADIO_RESULT_OK; default: @@ -738,20 +781,20 @@ set_value(radio_param_t param, radio_value_t value) } /* If we reach here we had no errors. Apply new settings */ - if (rf_is_receiving()) { - rf_stop_rx(); - if (rf_run_setup() != CMD_RESULT_OK) { - return RADIO_RESULT_ERROR; - } - rf_start_rx(); - } else if (rf_is_transmitting()) { - // Should not happen. TX is always synchronous and blocking. - // Todo: maybe remove completely here. - PRINTF("set_value: cannot apply new value while transmitting. \n"); + if (rx_active()) { + stop_rx(); + if (rf_run_setup() != CMD_RESULT_OK) { return RADIO_RESULT_ERROR; + } + start_rx(); + } else if (tx_active()) { + // Should not happen. TX is always synchronous and blocking. + // Todo: maybe remove completely here. + PRINTF("set_value: cannot apply new value while transmitting. \n"); + return RADIO_RESULT_ERROR; } else { - // was powered off. Nothing to do. New values will be - // applied automatically on next power-up. + // was powered off. Nothing to do. New values will be + // applied automatically on next power-up. } return RADIO_RESULT_OK; @@ -770,49 +813,63 @@ set_object(radio_param_t param, const void *src, size_t size) } /*---------------------------------------------------------------------------*/ static int -rf_init(void) +init(void) { - RF_Params params; - RF_Params_init(¶ms); - // Disable automatic power-down just to not interfere with stack timing - params.nInactivityTimeout = 0; + /* Zero initalize TX and RX buffers */ + memset(prop_radio.tx_buf, 0x0, sizeof(prop_radio.tx_buf)); + memset(prop_radio.rx_buf, 0x0, sizeof(prop_radio.rx_buf)); - rfHandle = RF_open(&rfObject, &rf_prop_mode, (RF_RadioSetup*)cmd_radio_setup, ¶ms); - assert(rfHandle != NULL); + /* Circular buffer, no last entry */ + prop_radio.rx_data_queue.pCurrEntry = prop_radio.rx_buf[0]; + prop_radio.rx_data_queue.pLastEntry = NULL; - /* Initialise RX buffers */ - memset(rx_buf, 0, sizeof(rx_buf)); + /* Initialize current read pointer to first element (used in ISR) */ + prop_radio.rx_read_entry = prop_radio.rx_buf[0]; - /* Set of RF Core data queue. Circular buffer, no last entry */ - rx_data_queue.pCurrEntry = rx_buf[0]; - rx_data_queue.pLastEntry = NULL; + /* Set configured RSSI threshold */ + prop_radio.rssi_threshold = PROP_MODE_RSSI_THRESHOLD; - /* Initialize current read pointer to first element (used in ISR) */ - rx_read_entry = rx_buf[0]; + /* RX is off */ + prop_radio.rf_is_on = false; - cmd_rx->pQueue = &rx_data_queue; - cmd_rx->pOutput = (uint8_t *)&rx_stats; + /* Configure RX command */ + cmd_rx.maxPktLen = DOT_4G_MAX_FRAME_LEN - cmd_rx.lenOffset; + cmd_rx.pQueue = &prop_radio.rx_data_queue; + cmd_rx.pOutput = (uint8_t *)&prop_radio.rx_stats; - set_channel(RF_CORE_CHANNEL); + /* Init RF params and specify non-default params */ + RF_Params rf_params; + RF_Params_init(&rf_params); + rf_params.nInactivityTimeout = 2000; /* 2 ms */ - ENERGEST_ON(ENERGEST_TYPE_LISTEN); + /* Open RF Driver */ + prop_radio.rf_handle = RF_open(&prop_radio.rf_object, &rf_prop_mode, + (RF_RadioSetup*)&cmd_radio_setup, &rf_params); + if (prop_radio.rf_handle == NULL) { + return CMD_RESULT_ERROR; + } - process_start(&RF_coreProcess, NULL); + set_channel(PROP_MODE_CHANNEL); - return CMD_RESULT_OK; + ENERGEST_ON(ENERGEST_TYPE_LISTEN); + + /* Start RF process */ + process_start(&rf_process, NULL); + + return CMD_RESULT_OK; } /*---------------------------------------------------------------------------*/ const struct radio_driver prop_mode_driver = { - rf_init, + init, prepare, transmit, send, - read_frame, + read, channel_clear, receiving_packet, pending_packet, - rf_switch_on, - rf_switch_off, + on, + off, get_value, set_value, get_object, diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c index e0608075a..8c79d3ab7 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c @@ -97,7 +97,7 @@ RF_TxPowerTable_Entry rf_prop_tx_power_table[RF_PROP_TX_POWER_TABLE_SIZE+1] = }; /*---------------------------------------------------------------------------*/ // Overrides for CMD_PROP_RADIO_DIV_SETUP -uint32_t p_prop_overrides[] CC_ALIGN(4) = +uint32_t rf_prop_overrides[] CC_ALIGN(4) = { // override_use_patch_prop_genfsk.xml MCE_RFE_OVERRIDE(0,4,0,1,0,0), // PHY: Use MCE ROM bank 4, RFE RAM patch @@ -137,15 +137,15 @@ uint32_t p_prop_overrides[] CC_ALIGN(4) = // Proprietary Mode Radio Setup Command for All Frequency Bands rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup = { - .commandNo = 0x3807, - .status = 0x0000, + .commandNo = CMD_PROP_RADIO_DIV_SETUP, + .status = IDLE, .pNextOp = 0, .startTime = 0x00000000, .startTrigger.triggerType = 0x0, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, .modulation.modType = 0x1, .modulation.deviation = 0x64, @@ -164,7 +164,7 @@ rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup = .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, .txPower = 0xAB3F, - .pRegOverride = pPropOverrides, + .pRegOverride = rf_prop_overrides, .centerFreq = 0x0364, .intFreq = 0x8000, .loDivider = 0x05, @@ -174,15 +174,15 @@ rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup = // Frequency Synthesizer Programming Command rfc_CMD_FS_t rf_cmd_prop_fs = { - .commandNo = 0x0803, - .status = 0x0000, + .commandNo = CMD_FS, + .status = IDLE, .pNextOp = 0, .startTime = 0x00000000, .startTrigger.triggerType = 0x0, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, .frequency = 0x0364, .fractFreq = 0x0000, @@ -199,14 +199,14 @@ rfc_CMD_FS_t rf_cmd_prop_fs = rfc_CMD_PROP_TX_ADV_t rf_cmd_prop_tx_adv = { .commandNo = CMD_PROP_TX_ADV, - .status = 0x0000, + .status = IDLE, .pNextOp = 0, .startTime = 0x00000000, .startTrigger.triggerType = 0x2, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x1, - .condition.rule = 0x1, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, .pktConf.bFsOff = 0x0, .pktConf.bUseCrc = 0x1, diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h index ec580734d..e6dd45962 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h @@ -52,7 +52,7 @@ extern rfc_CMD_PROP_TX_ADV_t rf_cmd_prop_tx_adv; extern rfc_CMD_PROP_RX_ADV_t rf_cmd_prop_rx_adv; /*---------------------------------------------------------------------------*/ // RF Core API Overrides -extern uint32_t p_prop_overrides[]; +extern uint32_t rf_prop_overrides[]; /*---------------------------------------------------------------------------*/ #endif /* PROP_SETTINGS_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c index 91db86f41..709314db6 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c @@ -109,7 +109,7 @@ uint32_t rf_ieee_overrides[] CC_ALIGN(4) = rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup = { .commandNo = CMD_RADIO_SETUP, - .status = 0x0000, + .status = IDLE, .pNextOp = 0, .startTime = 0x00000000, .startTrigger.triggerType = TRIG_NOW, @@ -133,7 +133,7 @@ rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup = rfc_CMD_FS_t rf_cmd_ieee_fs = { .commandNo = CMD_FS, - .status = 0x0000, + .status = IDLE, .pNextOp = 0, .startTime = 0x00000000, .startTrigger.triggerType = TRIG_NOW, @@ -142,8 +142,8 @@ rfc_CMD_FS_t rf_cmd_ieee_fs = .startTrigger.pastTrig = 0x0, .condition.rule = COND_NEVER, .condition.nSkip = 0x0, - .frequency = 0x0965, - .fractFreq = 0x0000, + .frequency = 0x0965, /* set by driver */ + .fractFreq = 0x0000, /* set by driver */ .synthConf.bTxMode = 0x1, .synthConf.refFreq = 0x0, .__dummy0 = 0x00, @@ -156,8 +156,8 @@ rfc_CMD_FS_t rf_cmd_ieee_fs = // IEEE 802.15.4 Transmit Command rfc_CMD_IEEE_TX_t rf_cmd_ieee_tx = { - .commandNo = CMD_IEEE_RX, - .status = 0x0000, + .commandNo = CMD_IEEE_TX, + .status = IDLE, .pNextOp = 0, .startTime = 0x00000000, .startTrigger.triggerType = TRIG_NOW, @@ -178,25 +178,25 @@ rfc_CMD_IEEE_TX_t rf_cmd_ieee_tx = // IEEE 802.15.4 Receive Command rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx = { - .commandNo = 0x2801, - .status = 0x0000, + .commandNo = CMD_IEEE_RX, + .status = IDLE, .pNextOp = 0, .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, + .startTrigger.triggerType = TRIG_NOW, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, - .channel = 0x00, - .rxConfig.bAutoFlushCrc = 0x0, + .channel = 0x00, /* set by driver */ + .rxConfig.bAutoFlushCrc = 0x1, .rxConfig.bAutoFlushIgn = 0x0, .rxConfig.bIncludePhyHdr = 0x0, - .rxConfig.bIncludeCrc = 0x0, + .rxConfig.bIncludeCrc = 0x1, .rxConfig.bAppendRssi = 0x1, .rxConfig.bAppendCorrCrc = 0x1, .rxConfig.bAppendSrcInd = 0x0, - .rxConfig.bAppendTimestamp = 0x0, + .rxConfig.bAppendTimestamp = 0x1, .pRxQ = 0, /* set by driver */ .pOutput = 0, /* set by driver */ .frameFiltOpt.frameFiltEn = 0x0, /* set by driver */ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h index a97730988..f92283afc 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h @@ -34,8 +34,8 @@ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) -#include DeviceFamily_constructPath(driverlib/rf_ieee_cmd.h -#include DeviceFamily_constructPath(driverlib/rf_ieee_mailbox.h)) +#include DeviceFamily_constructPath(driverlib/rf_ieee_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_ieee_mailbox.h) #include /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h b/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h index 468e74170..afb69933b 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h @@ -59,8 +59,8 @@ * Override button symbols from dev/button-sensor.h, for the examples that * include it */ -#define btn1_sensor button_left_sensor -#define btn2_sensor button_right_sensor +#define button_left_sensor btn1_sensor +#define button_right_sensor btn2_sensor /** @} */ /*---------------------------------------------------------------------------*/ /* Platform-specific define to signify sensor reading failure */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c index b6ecdbc23..efc24a7c2 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c @@ -41,23 +41,24 @@ #include /*---------------------------------------------------------------------------*/ #include -#include +#include #include /*---------------------------------------------------------------------------*/ #include +#include /*---------------------------------------------------------------------------*/ #include "button-sensor.h" #include "button-sensor-arch.h" /*---------------------------------------------------------------------------*/ /* LaunchPad has 2 buttons: BTN1 and BTN2 */ /* Map the GPIO defines from the Board file */ -#define BTN1_GPIO Board_GPIO_BTN1 -#define BTN2_GPIO Board_GPIO_BTN2 +#define BTN1_PIN Board_PIN_BTN1 +#define BTN2_PIN Board_PIN_BTN2 /*---------------------------------------------------------------------------*/ #ifdef BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN # define BUTTON_SENSOR_ENABLE_SHUTDOWN BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN #else -# define BUTTON_SENSOR_ENABLE_SHUTDOWN 1 +# define BUTTON_SENSOR_ENABLE_SHUTDOWN 0 #endif /*---------------------------------------------------------------------------*/ #define DEBOUNCE_DURATION (CLOCK_SECOND >> 5) @@ -68,56 +69,92 @@ typedef struct { clock_time_t duration; } BtnTimer; /*---------------------------------------------------------------------------*/ -static BtnTimer g_btn1Timer; -static BtnTimer g_btn2Timer; +static BtnTimer btn1_timer; +static BtnTimer btn2_timer; +/*---------------------------------------------------------------------------*/ +static const PIN_Config btn_pin_table[] = { + BTN1_PIN | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + BTN2_PIN | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + PIN_TERMINATE +}; + +static PIN_State pin_state; +static PIN_Handle pin_handle; /*---------------------------------------------------------------------------*/ static void -button_press_cb(uint8_t index, BtnTimer *btnTimer, const struct sensors_sensor *btnSensor) +button_press_cb(PIN_Handle handle, PIN_Id pin_id) { - if (!timer_expired(&btnTimer->debounce)) { +#ifdef BUTTON_SENSOR_ENABLE_SHUTDOWN + if (pin_id == BTN2_PIN) { + Power_shutdown(Power_ENTERING_SHUTDOWN, 0); + return; + } +#endif + + BtnTimer *btn_timer = NULL; + const struct sensors_sensor *btn_sensor = NULL; + + switch (pin_id) { + case BTN1_PIN: btn_timer = &btn1_timer; + btn_sensor = &btn1_sensor; break; + case BTN2_PIN: btn_timer = &btn2_timer; + btn_sensor = &btn2_sensor; break; + default: return; /* No matching PIN */ + } + + if (!timer_expired(&btn_timer->debounce)) { return; } - timer_set(&btnTimer->debounce, DEBOUNCE_DURATION); + timer_set(&btn_timer->debounce, DEBOUNCE_DURATION); // Start press duration counter on press (falling), notify on release (rising) - if (GPIO_read(index) == 0) { - btnTimer->start = clock_time(); - btnTimer->duration = 0; + if (PIN_getInputValue(pin_id) == 0) { + btn_timer->start = clock_time(); + btn_timer->duration = 0; } else { - btnTimer->duration = clock_time() - btnTimer->start; - sensors_changed(btnSensor); + btn_timer->duration = clock_time() - btn_timer->start; + sensors_changed(btn_sensor); } } /*---------------------------------------------------------------------------*/ static int -button_value(int type, uint8_t index, BtnTimer *btnTimer) +button_value(int type, uint8_t pin, BtnTimer *btn_timer) { if (type == BUTTON_SENSOR_VALUE_STATE) { - return (GPIO_read(index) == 0) + return (PIN_getInputValue(pin) == 0) ? BUTTON_SENSOR_VALUE_PRESSED : BUTTON_SENSOR_VALUE_RELEASED; } else if (type == BUTTON_SENSOR_VALUE_DURATION) { - return (int)btnTimer->duration; + return (int)btn_timer->duration; } return 0; } /*---------------------------------------------------------------------------*/ static int -button_config(int type, int value, uint8_t index, GPIO_CallbackFxn callback) +button_config(int type, int value, uint8_t pin) { switch (type) { case SENSORS_HW_INIT: - GPIO_clearInt(index); - GPIO_setCallback(index, callback); + // Open PIN handle + if (pin_handle) { + return 1; + } + pin_handle = PIN_open(&pin_state, btn_pin_table); + if (!pin_handle) { + return 0; + } + // Register button callback function + PIN_registerIntCb(pin_handle, button_press_cb); break; case SENSORS_ACTIVE: if (value) { - GPIO_clearInt(index); - GPIO_enableInt(index); + // Enable interrupts on both edges + PIN_setInterrupt(pin_handle, pin | PIN_IRQ_BOTHEDGES); } else { - GPIO_disableInt(index); + // Disable pin interrupts + PIN_setInterrupt(pin_handle, pin | PIN_IRQ_DIS); } break; } @@ -126,70 +163,53 @@ button_config(int type, int value, uint8_t index, GPIO_CallbackFxn callback) } /*---------------------------------------------------------------------------*/ static int -button_status(int type, uint8_t index) +button_status(int type, uint8_t pin) { switch(type) { case SENSORS_ACTIVE: /* fallthrough */ case SENSORS_READY: { - GPIO_PinConfig pinCfg = 0; - GPIO_getConfig(index, &pinCfg); - return (pinCfg & GPIO_CFG_IN_INT_NONE) == 0; + PIN_Config pin_cfg = PIN_getConfig(pin); + return (pin_cfg & PIN_BM_IRQ) == PIN_IRQ_DIS; } + default: break; } return 0; } /*---------------------------------------------------------------------------*/ -static void -btn1_press_cb(unsigned char unusued) -{ - button_press_cb(BTN1_GPIO, &g_btn1Timer, &btn1_sensor); -} -/*---------------------------------------------------------------------------*/ static int btn1_value(int type) { - return button_value(type, BTN1_GPIO, &g_btn1Timer); + return button_value(type, BTN1_PIN, &btn1_timer); } /*---------------------------------------------------------------------------*/ static int btn1_config(int type, int value) { - return button_config(type, value, BTN1_GPIO, btn1_press_cb); + return button_config(type, value, BTN1_PIN); } /*---------------------------------------------------------------------------*/ static int btn1_status(int type) { - return button_status(type, BTN1_GPIO); -} -/*---------------------------------------------------------------------------*/ -static void -btn2_press_cb(unsigned char unusued) -{ - if (BUTTON_SENSOR_ENABLE_SHUTDOWN) { - Power_shutdown(Power_ENTERING_SHUTDOWN, 0); - return; - } - - button_press_cb(BTN2_GPIO, &g_btn2Timer, &btn2_sensor); + return button_status(type, BTN1_PIN); } /*---------------------------------------------------------------------------*/ static int btn2_value(int type) { - return button_value(type, BTN2_GPIO, &g_btn2Timer); + return button_value(type, BTN2_PIN, &btn2_timer); } /*---------------------------------------------------------------------------*/ static int btn2_config(int type, int value) { - return button_config(type, value, BTN2_GPIO, btn2_press_cb); + return button_config(type, value, BTN2_PIN); } /*---------------------------------------------------------------------------*/ static int btn2_status(int type) { - return button_status(type, BTN1_GPIO); + return button_status(type, BTN2_PIN); } /*---------------------------------------------------------------------------*/ SENSORS_SENSOR(btn1_sensor, BUTTON_SENSOR, btn1_value, btn1_config, btn1_status); diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/launchpad-sensors.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/launchpad-sensors.c index c9c7b6d2e..f2a669037 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/launchpad-sensors.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/launchpad-sensors.c @@ -43,12 +43,8 @@ /*---------------------------------------------------------------------------*/ /* Exports a global symbol to be used by the sensor API */ SENSORS( -#ifdef BUTTON_SENSOR_ARCH_BTN1 - &button_sensor, -#endif -#ifdef BUTTON_SENSOR_ARCH_BTN2 - &button_sensor2, -#endif + &btn1_sensor, + &btn2_sensor, NULL ); /*---------------------------------------------------------------------------*/ diff --git a/os/sys/cc.h b/os/sys/cc.h index 6670eca46..2fa5439df 100644 --- a/os/sys/cc.h +++ b/os/sys/cc.h @@ -145,6 +145,10 @@ #define ABS(n) (((n) < 0) ? -(n) : (n)) #endif +#ifndef CLAMP +#define CLAMP(v, vmin, vmax) (MAX(MIN(v, vmax), vmin)) +#endif + #define CC_CONCAT2(s1, s2) s1##s2 /** From 12a6eefa850676895a6e29d0a9e5ec7df181d07c Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Mon, 18 Jun 2018 19:23:50 +0200 Subject: [PATCH 252/485] Lots of fixes for prop-mode and ieee-mode --- arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c | 169 ++++++----- arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c | 262 +++++++++++------- .../cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 2 +- .../simplelink/cc13xx-cc26xx/contiki-conf.h | 2 +- .../launchpad/button-sensor-arch.c | 2 +- 5 files changed, 257 insertions(+), 180 deletions(-) diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c index 69ec00233..e9443a68e 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c @@ -176,6 +176,10 @@ /* How long to wait for the rx read entry to become ready */ #define TIMEOUT_DATA_ENTRY_BUSY (RTIMER_SECOND / 250) /*---------------------------------------------------------------------------*/ +#define CCA_STATE_IDLE 0 +#define CCA_STATE_BUSY 1 +#define CCA_STATE_INVALID 2 +/*---------------------------------------------------------------------------*/ /* TI-RTOS RF driver object */ static RF_Object g_rfObj; static RF_Handle g_rfHandle; @@ -204,23 +208,39 @@ static uint8_t g_txBuf[TX_BUF_HDR_LEN + TX_BUF_PAYLOAD_LEN] CC_ALIGN(4); /*---------------------------------------------------------------------------*/ /* RX Data Queue */ static dataQueue_t g_rxDataQueue; -/* Receive entry pointer to keep track of read items */ -volatile static uint8_t *g_pRxReadEntry; - +/*---------------------------------------------------------------------------*/ /* Constants for receive buffers */ #define DATA_ENTRY_LENSZ_NONE 0 #define DATA_ENTRY_LENSZ_BYTE 1 #define DATA_ENTRY_LENSZ_WORD 2 /* 2 bytes */ -#define RX_BUF_ENTRIES 4 +#define DATA_ENTRY_LENSZ DATA_ENTRY_LENSZ_BYTE +typedef uint8_t lensz_t; + +#define FRAME_OFFSET DATA_ENTRY_LENSZ +#define FRAME_SHAVE 8 /* FCS (2) + RSSI (1) + Status (1) + Timestamp (4) */ +/*---------------------------------------------------------------------------*/ +/* RX buf configuration */ +#ifdef IEEE_MODE_CONF_RX_BUF_CNT +# define RX_BUF_CNT IEEE_MODE_CONF_RX_BUF_CNT +#else +# define RX_BUF_CNT 4 +#endif + #define RX_BUF_SIZE 144 /* Receive buffer entries with room for 1 IEEE 802.15.4 frame in each */ +typedef rfc_dataEntryGeneral_t data_entry_t; + typedef union { - rfc_dataEntry_t dataEntry; - uint8_t buf[RX_BUF_SIZE] CC_ALIGN(4); -} RxBuf; -static RxBuf g_rxBufs[RX_BUF_ENTRIES]; + data_entry_t data_entry; + uint8_t buf[RX_BUF_SIZE]; +} rx_buf_t CC_ALIGN(4); + +static rx_buf_t rx_bufs[RX_BUF_CNT]; + +/* Receive entry pointer to keep track of read items */ +static data_entry_t *rx_read_entry; /*---------------------------------------------------------------------------*/ /* RAT overflow upkeep */ static struct ctimer g_ratOverflowTimer; @@ -331,10 +351,10 @@ static void init_data_queue(void) { // Initialize RF core data queue, circular buffer - g_rxDataQueue.pCurrEntry = g_rxBufs[0].buf; + g_rxDataQueue.pCurrEntry = rx_bufs[0].buf; g_rxDataQueue.pLastEntry = NULL; // Set current read pointer to first element - g_pRxReadEntry = g_rxDataQueue.pCurrEntry; + rx_read_entry = &rx_bufs[0].data_entry; } /*---------------------------------------------------------------------------*/ static void @@ -368,25 +388,20 @@ init_rf_params(void) static void init_rx_buffers(void) { -#define GET_ENTRY(n) (&(g_rxBufs[(n)].dataEntry)) - - rfc_dataEntry_t *entry = NULL; - const size_t length = sizeof(g_rxBufs[0].buf) - 8; - - size_t i; - for (i = 0; i < (size_t)(RX_BUF_ENTRIES - 1); ++i) { - entry = GET_ENTRY(i); - entry->pNextEntry = (uint8_t*)GET_ENTRY(i + 1); - entry->config.lenSz = DATA_ENTRY_LENSZ_BYTE; - entry->length = (uint16_t)length; + size_t i = 0; + for (i = 0; i < RX_BUF_CNT; ++i) { + const data_entry_t data_entry = { + .status = DATA_ENTRY_PENDING, + .config.type = DATA_ENTRY_TYPE_GEN, + .config.lenSz = DATA_ENTRY_LENSZ, + .length = RX_BUF_SIZE - sizeof(data_entry_t), /* TODO: is this sizeof sound? */ + /* Point to fist entry if this is last entry, else point to next entry */ + .pNextEntry = (i == (RX_BUF_CNT - 1)) + ? rx_bufs[0].buf + : rx_bufs[i].buf + }; + rx_bufs[i].data_entry = data_entry; } - - entry = GET_ENTRY(RX_BUF_ENTRIES - 1); - entry->pNextEntry = (uint8_t*)GET_ENTRY(0); - entry->config.lenSz = DATA_ENTRY_LENSZ_BYTE; - entry->length = (uint16_t)length; - -#undef getEntry } /*---------------------------------------------------------------------------*/ static bool @@ -613,8 +628,6 @@ transmit_aux(unsigned short transmit_len) // Configure TX command cmd_tx.payloadLen = (uint8_t)transmit_len; cmd_tx.pPayload = &g_txBuf[TX_BUF_HDR_LEN]; - cmd_tx.startTime = 0; - cmd_tx.startTrigger.triggerType = TRIG_NOW; RF_ScheduleCmdParams schedParams; RF_ScheduleCmdParams_init(&schedParams); @@ -672,68 +685,88 @@ send(const void *payload, unsigned short payload_len) static void release_data_entry(void) { - rfc_dataEntryGeneral_t *pEntry = (rfc_dataEntryGeneral_t *)g_pRxReadEntry; + data_entry_t *const data_entry = rx_read_entry; + uint8_t *const frame_ptr = (uint8_t*)&data_entry->data; + // Clear the length byte and set status to 0: "Pending" - g_pRxReadEntry[8] = 0; - pEntry->status = DATA_ENTRY_PENDING; - // Set next entry - g_pRxReadEntry = pEntry->pNextEntry; + *(lensz_t*)frame_ptr = 0; + data_entry->status = DATA_ENTRY_PENDING; + rx_read_entry = (data_entry_t*)data_entry->pNextEntry; } /*---------------------------------------------------------------------------*/ static int read(void *buf, unsigned short buf_len) { - volatile rfc_dataEntryGeneral_t *pEntry = (rfc_dataEntryGeneral_t *)g_pRxReadEntry; + volatile data_entry_t *data_entry = rx_read_entry; const rtimer_clock_t t0 = RTIMER_NOW(); // Only wait if the Radio timer is accessing the entry - while ((pEntry->status == DATA_ENTRY_BUSY) && + while ((data_entry->status == DATA_ENTRY_BUSY) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + TIMEOUT_DATA_ENTRY_BUSY)); - if (pEntry->status != DATA_ENTRY_FINISHED) { + if (data_entry->status != DATA_ENTRY_FINISHED) { // No available data return 0; } - // FIXME: something is wrong here about length constraints - const uint8_t frame_len = g_pRxReadEntry[8]; - if (frame_len < 8) { - PRINTF("read_frame: frame too short len=%d\n", frame_len); + /* First byte in the data entry is the length. + * Data frame is on the following format: + * Length (1) + Payload (N) + FCS (2) + RSSI (1) + Status (1) + Timestamp (4) + * Data frame DOES NOT contain the following: + * no PHY Header bytes + * no Source Index bytes + * +--------+---------+---------+--------+--------+-----------+ + * | 1 byte | N bytes | 2 bytes | 1 byte | 1 byte | 4 bytes | + * +--------+---------+---------+--------+--------+-----------+ + * | Length | Payload | FCS | RSSI | Status | Timestamp | + * +--------+---------+---------+--------+--------+-----------+ + * Length bytes equal total length of entire frame excluding itself, + * i.e.: Length = N + FCS (2) + RSSI (1) + Status (1) + Timestamp (4) + * = N + 8 + * N = Length - 8 */ + + uint8_t *const frame_ptr = (uint8_t*)&data_entry->data; + const lensz_t frame_len = *(lensz_t*)frame_ptr; + + /* Sanity check that Frame is at least Frame Shave bytes long */ + if (frame_len < FRAME_SHAVE) { + PRINTF("read: frame too short len=%d\n", frame_len); release_data_entry(); return 0; } - const uint8_t payload_len = frame_len - 8; + const uint8_t *payload_ptr = frame_ptr + sizeof(lensz_t); + const unsigned short payload_len = (unsigned short)(frame_len - FRAME_SHAVE); + /* Sanity check that Payload fits in Buffer */ if (payload_len > buf_len) { - PRINTF("read_frame: frame larger than buffer\n"); + PRINTF("read: payload too large for buffer len=%d buf_len=%d\n", payload_len, buf_len); release_data_entry(); return 0; } - const uint8_t *pData = (uint8_t *)&g_pRxReadEntry[9]; - memcpy(buf, pData, payload_len); + memcpy(buf, payload_ptr, payload_len); - g_lastRssi = (int8_t)(pData[payload_len + 2]); - g_lastCorrLqi = (uint8_t)(pData[payload_len + 3]) & STATUS_CORRELATION; - - uint32_t ratTimestamp; - memcpy(&ratTimestamp, pData + payload_len + 4, sizeof(ratTimestamp)); + /* RSSI stored FCS (2) bytes after payload */ + g_lastRssi = (int8_t)payload_ptr[payload_len + 2]; + /* LQI retrieved from Status byte, FCS (2) + RSSI (1) bytes after payload */ + g_lastCorrLqi = ((uint8_t)payload_ptr[payload_len + 3]) & STATUS_CORRELATION; + /* Timestamp stored FCS (2) + RSSI (1) + Status (1) bytes after payload */ + const uint32_t ratTimestamp = *(uint32_t*)(payload_ptr + payload_len + 4); g_lastTimestamp = rat_to_timestamp(ratTimestamp); if (!g_bPollMode) { // Not in poll mode: packetbuf should not be accessed in interrupt context. // In poll mode, the last packet RSSI and link quality can be obtained through // RADIO_PARAM_LAST_RSSI and RADIO_PARAM_LAST_LINK_QUALITY - packetbuf_set_attr(PACKETBUF_ATTR_RSSI, g_lastRssi); - packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, g_lastCorrLqi); + packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (packetbuf_attr_t)g_lastRssi); + packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, (packetbuf_attr_t)g_lastCorrLqi); } release_data_entry(); - - return payload_len; + return (int)payload_len; } /*---------------------------------------------------------------------------*/ static int @@ -779,28 +812,18 @@ receiving_packet(void) return 0; } - rfc_CMD_IEEE_CCA_REQ_t RF_cmdIeeeCaaReq; - memset(&RF_cmdIeeeCaaReq, 0x0, sizeof(rfc_CMD_IEEE_CCA_REQ_t)); - RF_cmdIeeeCaaReq.commandNo = CMD_IEEE_CCA_REQ; + rfc_CMD_IEEE_CCA_REQ_t cca_req; + memset(&cca_req, 0x0, sizeof(rfc_CMD_IEEE_CCA_REQ_t)); + cca_req.commandNo = CMD_IEEE_CCA_REQ; - const RF_Stat stat = RF_runImmediateCmd(g_rfHandle, (uint32_t*)&RF_cmdIeeeCaaReq); + const RF_Stat stat = RF_runImmediateCmd(g_rfHandle, (uint32_t*)&cca_req); if (stat != RF_StatCmdDoneSuccess) { PRINTF("receiving_packet: CCA request failed stat=0x%02X\n", stat); return 0; } - // If the radio is transmitting an ACK or is suspended for running a TX operation, - // ccaEnergy, ccaCorr and ccaSync are all busy (1) - if ((RF_cmdIeeeCaaReq.ccaInfo.ccaEnergy == 1) && - (RF_cmdIeeeCaaReq.ccaInfo.ccaCorr == 1) && - (RF_cmdIeeeCaaReq.ccaInfo.ccaSync == 1)) { - PRINTF("receiving_packet: we were TXing\n"); - return 0; - } - - // We are on and not in TX, then we are in RX if a CCA sync has been seen, - // i.e. ccaSync is busy (1) - return (RF_cmdIeeeCaaReq.ccaInfo.ccaSync == 1); + // We are in RX if a CCA sync has been seen, i.e. ccaSync is busy (1) + return (cca_req.ccaInfo.ccaSync == CCA_STATE_BUSY); } /*---------------------------------------------------------------------------*/ static int @@ -853,8 +876,8 @@ off(void) // Reset RX buffers if there was an ongoing RX size_t i; - for (i = 0; i < RX_BUF_ENTRIES; ++i) { - rfc_dataEntry_t *entry = &(g_rxBufs[i].dataEntry); + for (i = 0; i < RX_BUF_CNT; ++i) { + data_entry_t *entry = &rx_bufs[i].data_entry; if (entry->status == DATA_ENTRY_BUSY) { entry->status = DATA_ENTRY_PENDING; } diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c index c1642a2ba..0eb08470f 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c @@ -111,9 +111,9 @@ * Values of the individual bits of the ccaInfo field in CMD_IEEE_CCA_REQ's * status struct */ -#define RF_CMD_CCA_REQ_CCA_STATE_IDLE 0 /* 00 */ -#define RF_CMD_CCA_REQ_CCA_STATE_BUSY 1 /* 01 */ -#define RF_CMD_CCA_REQ_CCA_STATE_INVALID 2 /* 10 */ +#define RF_CMD_CCA_REQ_CCA_STATE_IDLE 0 /* 0b00 */ +#define RF_CMD_CCA_REQ_CCA_STATE_BUSY 1 /* 0b01 */ +#define RF_CMD_CCA_REQ_CCA_STATE_INVALID 2 /* 0b10 */ #ifdef PROP_MODE_CONF_RSSI_THRESHOLD # define PROP_MODE_RSSI_THRESHOLD PROP_MODE_CONF_RSSI_THRESHOLD @@ -147,6 +147,9 @@ /*---------------------------------------------------------------------------*/ /* How long to wait for the RF to enter RX in rf_cmd_ieee_rx */ #define ENTER_RX_WAIT_TIMEOUT (RTIMER_SECOND >> 10) + +/* How long to wait for the rx read entry to become ready */ +#define TIMEOUT_DATA_ENTRY_BUSY (RTIMER_SECOND / 250) /*---------------------------------------------------------------------------*/ /* Configuration for TX power table */ #ifdef PROP_MODE_CONF_TX_POWER_TABLE @@ -178,9 +181,15 @@ #define RX_BUF_SIZE 140 /*---------------------------------------------------------------------------*/ -#define DATA_ENTRY_LENSZ_NONE 0 -#define DATA_ENTRY_LENSZ_BYTE 1 +#define DATA_ENTRY_LENSZ_NONE 0 /* 0 bytes */ +#define DATA_ENTRY_LENSZ_BYTE 1 /* 1 byte */ #define DATA_ENTRY_LENSZ_WORD 2 /* 2 bytes */ + +#define DATA_ENTRY_LENSZ DATA_ENTRY_LENSZ_WORD +typedef uint16_t lensz_t; + +#define FRAME_OFFSET DATA_ENTRY_LENSZ +#define FRAME_SHAVE 2 /* RSSI (1) + Status (1) */ /*---------------------------------------------------------------------------*/ #define MAC_RADIO_RECEIVER_SENSITIVITY_DBM -110 #define MAC_RADIO_RECEIVER_SATURATION_DBM 10 @@ -190,18 +199,25 @@ #define ED_RF_POWER_MIN_DBM (MAC_RADIO_RECEIVER_SENSITIVITY_DBM + MAC_SPEC_ED_MIN_DBM_ABOVE_RECEIVER_SENSITIVITY) #define ED_RF_POWER_MAX_DBM MAC_RADIO_RECEIVER_SATURATION_DBM /*---------------------------------------------------------------------------*/ +typedef rfc_dataEntryGeneral_t data_entry_t; + +typedef union { + data_entry_t data_entry; + uint8_t buf[RX_BUF_SIZE]; +} rx_buf_t CC_ALIGN(4); + typedef struct { /* Outgoing frame buffer */ uint8_t tx_buf[TX_BUF_SIZE] CC_ALIGN(4); /* Incoming frame buffer */ - uint8_t rx_buf[RX_BUF_CNT][RX_BUF_SIZE] CC_ALIGN(4); + rx_buf_t rx_bufs[RX_BUF_CNT]; /* RX Data Queue */ dataQueue_t rx_data_queue; /* RX Statistics struct */ rfc_propRxOutput_t rx_stats; /* Receive entry pointer to keep track of read items */ - volatile uint8_t* rx_read_entry; + data_entry_t* rx_read_entry; /* RSSI Threshold */ int8_t rssi_threshold; @@ -267,14 +283,12 @@ static cmd_result_t stop_rx(void) { /* Abort any ongoing operation. Don't care about the result. */ - RF_cancelCmd(prop_radio.rf_handle, RF_CMDHANDLE_FLUSH_ALL, 1); + RF_cancelCmd(prop_radio.rf_handle, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY); - /* Todo: maybe do a RF_pendCmd() to synchronize with command execution. */ - - if(cmd_rx.status != PROP_DONE_STOPPED && - cmd_rx.status != PROP_DONE_ABORT) { - PRINTF("RF_cmdPropRxAdv cancel: status=0x%04x\n", - cmd_rx.status); + if (cmd_rx.status != PROP_DONE_STOPPED && + cmd_rx.status != PROP_DONE_ABORT) { + PRINTF("RF_cmdPropRxAdv cancel: status=0x%04x\n", + cmd_rx.status); return CMD_RESULT_ERROR; } @@ -286,12 +300,13 @@ stop_rx(void) static cmd_result_t rf_run_setup() { - RF_runCmd(prop_radio.rf_handle, (RF_Op*)&cmd_radio_setup, RF_PriorityNormal, NULL, 0); - if (cmd_radio_setup.status != PROP_DONE_OK) { - return CMD_RESULT_ERROR; - } + // TODO not the right way to do this. + RF_runCmd(prop_radio.rf_handle, (RF_Op*)&cmd_radio_setup, RF_PriorityNormal, NULL, 0); + if (cmd_radio_setup.status != PROP_DONE_OK) { + return CMD_RESULT_ERROR; + } - return CMD_RESULT_OK; + return CMD_RESULT_OK; } /*---------------------------------------------------------------------------*/ static radio_value_t @@ -413,19 +428,19 @@ static void init_rx_buffers(void) { size_t i = 0; - for (i = 0; i < RX_BUF_CNT; i++) { - const rfc_dataEntry_t data_entry = { + for (i = 0; i < RX_BUF_CNT; ++i) { + const data_entry_t data_entry = { .status = DATA_ENTRY_PENDING, .config.type = DATA_ENTRY_TYPE_GEN, - .config.lenSz = DATA_ENTRY_LENSZ_WORD, - .length = RX_BUF_SIZE - sizeof(rfc_dataEntry_t), /* TODO is this sizeof sound? */ + .config.lenSz = DATA_ENTRY_LENSZ, + .length = RX_BUF_SIZE - sizeof(data_entry_t), /* TODO: is this sizeof sound? */ /* Point to fist entry if this is last entry, else point to next entry */ .pNextEntry = (i == (RX_BUF_CNT - 1)) - ? prop_radio.rx_buf[0] - : prop_radio.rx_buf[i] + ? prop_radio.rx_bufs[0].buf + : prop_radio.rx_bufs[i].buf }; /* Write back data entry struct */ - *(rfc_dataEntry_t *)prop_radio.rx_buf[i] = data_entry; + prop_radio.rx_bufs[i].data_entry = data_entry; } } /*---------------------------------------------------------------------------*/ @@ -441,62 +456,54 @@ prepare(const void *payload, unsigned short payload_len) static int transmit(unsigned short transmit_len) { - int ret; - uint8_t was_off = 0; + int ret = RADIO_TX_OK; if (tx_active()) { PRINTF("transmit: not allowed while transmitting\n"); return RADIO_TX_ERR; - } else if (rx_active()) { + } + + const bool rx_is_on = rx_active(); + if (rx_is_on) { stop_rx(); - } else { - was_off = 1; } /* Length in .15.4g PHY HDR. Includes the CRC but not the HDR itself */ - uint16_t total_length; - - /* - * Prepare the .15.4g PHY header - * MS=0, Length MSBits=0, DW and CRC configurable - * Total length = transmit_len (payload) + CRC length - * - * The Radio will flip the bits around, so tx_buf[0] must have the length - * LSBs (PHR[15:8] and tx_buf[1] will have PHR[7:0] - */ - total_length = transmit_len + CRC_LEN; - + uint16_t total_length = transmit_len + CRC_LEN; + /* Prepare the .15.4g PHY header + * MS=0, Length MSBits=0, DW and CRC configurable + * Total length = transmit_len (payload) + CRC length + * + * The Radio will flip the bits around, so tx_buf[0] must have the length + * LSBs (PHR[15:8] and tx_buf[1] will have PHR[7:0] */ prop_radio.tx_buf[0] = total_length & 0xFF; prop_radio.tx_buf[1] = (total_length >> 8) + DOT_4G_PHR_DW_BIT + DOT_4G_PHR_CRC_BIT; - /* - * pktLen: Total number of bytes in the TX buffer, including the header if - * one exists, but not including the CRC (which is not present in the buffer) - */ + /* pktLen: Total number of bytes in the TX buffer, including the header if + * one exists, but not including the CRC (which is not present in the buffer) */ cmd_tx.pktLen = transmit_len + DOT_4G_PHR_LEN; cmd_tx.pPkt = prop_radio.tx_buf; - // TODO: Register callback - RF_runCmd(prop_radio.rf_handle, (RF_Op*)&cmd_tx, RF_PriorityNormal, NULL, 0); -// if (txHandle == RF_ALLOC_ERROR) -// { -// /* Failure sending the CMD_PROP_TX command */ -// PRINTF("transmit: PROP_TX_ERR ret=%d, CMDSTA=0x%08lx, status=0x%04x\n", -// ret, cmd_status, cmd_tx_adv->status); -// return RADIO_TX_ERR; -// } -// -// ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); -// -// // watchdog_periodic(); -// -// /* Idle away while the command is running */ -// RF_pendCmd(rf_handle, txHandle, RF_EventLastCmdDone); + RF_CmdHandle tx_handle = RF_postCmd(prop_radio.rf_handle, (RF_Op*)&cmd_tx, RF_PriorityNormal, NULL, 0); + if (tx_handle == RF_ALLOC_ERROR) { + /* Failure sending the CMD_PROP_TX command */ + PRINTF("transmit: unable to allocate RF command handle\n"); + return RADIO_TX_ERR; + } - if(cmd_tx.status == PROP_DONE_OK) { - /* Sent OK */ - ret = RADIO_TX_OK; - } else { + ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); + + // watchdog_periodic(); + + /* Idle away while the command is running */ + RF_EventMask rf_events = RF_pendCmd(prop_radio.rf_handle, tx_handle, RF_EventLastCmdDone); + + if ((rf_events & (RF_EventCmdDone | RF_EventLastCmdDone)) == 0) { + PRINTF("transmit: RF_pendCmd failed, events=0x%llx\n", rf_events); + ret = RADIO_TX_ERR; + } + + else if (cmd_tx.status != PROP_DONE_OK) { /* Operation completed, but frame was not sent */ PRINTF("transmit: Not Sent OK status=0x%04x\n", cmd_tx.status); @@ -508,9 +515,7 @@ transmit(unsigned short transmit_len) /* Workaround. Set status to IDLE */ cmd_tx.status = IDLE; - if (was_off) { - RF_yield(prop_radio.rf_handle); - } else { + if (rx_is_on) { start_rx(); } @@ -524,42 +529,82 @@ send(const void *payload, unsigned short payload_len) return transmit(payload_len); } /*---------------------------------------------------------------------------*/ +static void +release_data_entry(void) +{ + data_entry_t *const data_entry = prop_radio.rx_read_entry; + uint8_t *const frame_ptr = (uint8_t*)&data_entry->data; + + // Clear the Length byte(s) and set status to 0: "Pending" + *(lensz_t*)frame_ptr = 0; + data_entry->status = DATA_ENTRY_PENDING; + prop_radio.rx_read_entry = (data_entry_t*)data_entry->pNextEntry; +} +/*---------------------------------------------------------------------------*/ static int read(void *buf, unsigned short buf_len) { - rfc_dataEntryGeneral_t *entry = (rfc_dataEntryGeneral_t *)prop_radio.rx_read_entry; - uint8_t *data_ptr = &entry->data; - uint16_t len = 0; + volatile data_entry_t *data_entry = prop_radio.rx_read_entry; - if (entry->status != DATA_ENTRY_FINISHED) { + const rtimer_clock_t t0 = RTIMER_NOW(); + // Only wait if the Radio timer is accessing the entry + while ((data_entry->status == DATA_ENTRY_BUSY) && + RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + TIMEOUT_DATA_ENTRY_BUSY)); + + if (data_entry->status != DATA_ENTRY_FINISHED) { + // No available data return 0; } /* First 2 bytes in the data entry are the length. - * Our data entry consists of: Payload + RSSI (1 byte) + Status (1 byte) - * This length includes all of those. */ - len = *(uint16_t *)data_ptr; - data_ptr += 2; - len -= 2; + * Data frame is on the following format: + * Length (2) + Payload (N) + RSSI (1) + Status (1) + * Data frame DOES NOT contain the following: + * no Header/PHY bytes + * no appended Received CRC bytes + * no Timestamp bytes + * +---------+---------+--------+--------+ + * | 2 bytes | N bytes | 1 byte | 1 byte | + * +---------+---------+--------+--------+ + * | Length | Payload | RSSI | Status | + * +---------+---------+--------+--------+ + * Length bytes equal total length of entire frame excluding itself, + * i.e.: Length = N + RSSI (1) + Status (1) + * = N + 2 + * N = Length - 2 */ - const bool len_ok = (0 < len) && (len <= (uint16_t)buf_len); - if (len_ok) { - memcpy(buf, data_ptr, len); + uint8_t *const frame_ptr = (uint8_t*)&data_entry->data; + const lensz_t frame_len = *(lensz_t*)frame_ptr; - int8_t rssi = (int8_t)data_ptr[len]; - uint8_t lqi = calculate_lqi(rssi); - - packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (packetbuf_attr_t)rssi); - packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, (packetbuf_attr_t)lqi); + /* Sanity check that Frame is at least Frame Shave bytes long */ + if (frame_len < FRAME_SHAVE) { + PRINTF("read: frame too short len=%d\n", frame_len); + release_data_entry(); + return 0; } - /* Move read entry pointer to next entry */ - prop_radio.rx_read_entry = entry->pNextEntry; - entry->status = DATA_ENTRY_PENDING; + const uint8_t *payload_ptr = frame_ptr + sizeof(lensz_t); + const unsigned short payload_len = (unsigned short)(frame_len - FRAME_SHAVE); - return (len_ok) - ? (int)len - : 0; + /* Sanity check that Payload fits in Buffer */ + if (payload_len > buf_len) { + PRINTF("read: payload too large for buffer len=%d buf_len=%d\n", payload_len, buf_len); + release_data_entry(); + return 0; + } + + memcpy(buf, payload_ptr, payload_len); + + /* RSSI stored after payload */ + const int8_t rssi = (int8_t)payload_ptr[payload_len]; + /* LQI calculated from RSSI */ + const uint8_t lqi = calculate_lqi(rssi); + + packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (packetbuf_attr_t)rssi); + packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, (packetbuf_attr_t)lqi); + + release_data_entry(); + return (int)payload_len; } /*---------------------------------------------------------------------------*/ static int @@ -595,11 +640,11 @@ static int receiving_packet(void) { if (!rx_active()) { - return 0; + return 0; } if (channel_clear() == RF_CCA_CLEAR) { - return 0; + return 0; } return 1; @@ -636,12 +681,11 @@ static int on(void) { if (prop_radio.rf_is_on) { - PRINTF("RF on: Radio already in RX\n"); + PRINTF("on: Radio already on\n"); return CMD_RESULT_OK; } /* Reset all RF command statuses */ - cmd_radio_setup.status = IDLE; cmd_fs.status = IDLE; cmd_tx.status = IDLE; cmd_rx.status = IDLE; @@ -662,6 +706,7 @@ static int off(void) { if (!prop_radio.rf_is_on) { + PRINTF("off: Radio already off\n"); return CMD_RESULT_OK; } @@ -672,11 +717,19 @@ off(void) RF_yield(prop_radio.rf_handle); /* We pulled the plug, so we need to restore the status manually */ - cmd_radio_setup.status = IDLE; cmd_fs.status = IDLE; cmd_tx.status = IDLE; cmd_rx.status = IDLE; + // Reset RX buffers if there was an ongoing RX + size_t i; + for (i = 0; i < RX_BUF_CNT; ++i) { + data_entry_t *entry = &prop_radio.rx_bufs[i].data_entry; + if (entry->status == DATA_ENTRY_BUSY) { + entry->status = DATA_ENTRY_PENDING; + } + } + prop_radio.rf_is_on = false; return CMD_RESULT_OK; } @@ -783,6 +836,7 @@ set_value(radio_param_t param, radio_value_t value) /* If we reach here we had no errors. Apply new settings */ if (rx_active()) { stop_rx(); + // TODO fix this if (rf_run_setup() != CMD_RESULT_OK) { return RADIO_RESULT_ERROR; } @@ -803,28 +857,28 @@ set_value(radio_param_t param, radio_value_t value) static radio_result_t get_object(radio_param_t param, void *dest, size_t size) { - return RADIO_RESULT_NOT_SUPPORTED; + return RADIO_RESULT_NOT_SUPPORTED; } /*---------------------------------------------------------------------------*/ static radio_result_t set_object(radio_param_t param, const void *src, size_t size) { - return RADIO_RESULT_NOT_SUPPORTED; + return RADIO_RESULT_NOT_SUPPORTED; } /*---------------------------------------------------------------------------*/ static int init(void) { /* Zero initalize TX and RX buffers */ - memset(prop_radio.tx_buf, 0x0, sizeof(prop_radio.tx_buf)); - memset(prop_radio.rx_buf, 0x0, sizeof(prop_radio.rx_buf)); + memset(prop_radio.tx_buf, 0x0, sizeof(prop_radio.tx_buf)); + memset(prop_radio.rx_bufs, 0x0, sizeof(prop_radio.rx_bufs)); /* Circular buffer, no last entry */ - prop_radio.rx_data_queue.pCurrEntry = prop_radio.rx_buf[0]; + prop_radio.rx_data_queue.pCurrEntry = prop_radio.rx_bufs[0].buf; prop_radio.rx_data_queue.pLastEntry = NULL; /* Initialize current read pointer to first element (used in ISR) */ - prop_radio.rx_read_entry = prop_radio.rx_buf[0]; + prop_radio.rx_read_entry = &prop_radio.rx_bufs[0].data_entry; /* Set configured RSSI threshold */ prop_radio.rssi_threshold = PROP_MODE_RSSI_THRESHOLD; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index c7287da4b..f0a866f24 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -6,7 +6,7 @@ BOARD_PLATFORMS = launchpad sensortag srf06 # Assigned lazily to avoid breaking environments which doesn't have cd and find -BOARDS = $(foreach BOARD_TYPE, $(BOARD_PLATFORMS), \ +BOARDS := $(foreach BOARD_TYPE, $(BOARD_PLATFORMS), \ $(shell cd $(FAMILY_PATH); find $(BOARD_TYPE)/* -type d -print)) BOARD_EXISTS := $(shell [ -d "$(FAMILY_PATH)/$(BOARD)" ]; echo $$?) diff --git a/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h b/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h index afb69933b..bd5cbb195 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h @@ -52,7 +52,7 @@ * @{ */ #ifndef BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN -#define BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN 1 +#define BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN 0 #endif /* diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c index efc24a7c2..6950b16f1 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c @@ -84,7 +84,7 @@ static PIN_Handle pin_handle; static void button_press_cb(PIN_Handle handle, PIN_Id pin_id) { -#ifdef BUTTON_SENSOR_ENABLE_SHUTDOWN +#if BUTTON_SENSOR_ENABLE_SHUTDOWN if (pin_id == BTN2_PIN) { Power_shutdown(Power_ENTERING_SHUTDOWN, 0); return; From d312dd9ebb2bd7fd33781aa3d8b7084dcd200012 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Tue, 19 Jun 2018 14:55:18 +0200 Subject: [PATCH 253/485] Refactoring of prop/ieee-mode --- .../cc13x0-cc26x0/cc13xx-cc26xx-def.h | 11 +- .../cc13x2-cc26x2/cc13xx-cc26xx-def.h | 12 +- arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c | 692 +++++++++--------- arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c | 167 ++--- 4 files changed, 439 insertions(+), 443 deletions(-) diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13xx-cc26xx-def.h b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13xx-cc26xx-def.h index 563bbff56..41eee3d87 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13xx-cc26xx-def.h +++ b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13xx-cc26xx-def.h @@ -45,12 +45,13 @@ #define RADIO_DELAY_BEFORE_DETECT ((unsigned)US_TO_RTIMERTICKS(352)) /* Timer conversion; radio is running at 4 MHz */ -#define RADIO_TIMER_SECOND 4000000u -#if (RTIMER_SECOND % 256) || (RADIO_TIMER_SECOND % 256) -#error RADIO_TO_RTIMER macro must be fixed! +#define RAT_SECOND 4000000u +#define RAT_TO_RTIMER(X) ((uint32_t)(((uint64_t)(X) * (RTIMER_SECOND / 256)) / (RAT_SECOND / 256))) +#define USEC_TO_RAT(X) ((X) * 4) + +#if (RTIMER_SECOND % 256) || (RAT_SECOND % 256) +# error RAT_TO_RTIMER macro must be fixed! #endif -#define RADIO_TO_RTIMER(X) ((uint32_t)(((uint64_t)(X) * (RTIMER_SECOND / 256)) / (RADIO_TIMER_SECOND / 256))) -#define USEC_TO_RADIO(X) ((X) * 4) /* The PHY header (preamble + SFD, 4+1 bytes) duration is equivalent to 10 symbols */ #define RADIO_IEEE_802154_PHY_HEADER_DURATION_USEC 160 diff --git a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13xx-cc26xx-def.h b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13xx-cc26xx-def.h index 7d54aa45a..507db4470 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13xx-cc26xx-def.h +++ b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13xx-cc26xx-def.h @@ -45,11 +45,15 @@ #define RADIO_DELAY_BEFORE_DETECT ((unsigned)US_TO_RTIMERTICKS(352)) /* Timer conversion; radio is running at 4 MHz */ -#define RADIO_TIMER_SECOND 4000000u -#if (RTIMER_SECOND % 256) || (RADIO_TIMER_SECOND % 256) -#error RADIO_TO_RTIMER macro must be fixed! +/* Timer conversion; radio is running at 4 MHz */ +#define RAT_SECOND 4000000u +#define RAT_TO_RTIMER(X) ((uint32_t)(((uint64_t)(X) * (RTIMER_SECOND / 256)) / (RAT_SECOND / 256))) +#define USEC_TO_RAT(X) ((X) * 4) + +#if (RTIMER_SECOND % 256) || (RAT_SECOND % 256) +# error RAT_TO_RTIMER macro must be fixed! #endif -#define RADIO_TO_RTIMER(X) ((uint32_t)(((uint64_t)(X) * (RTIMER_SECOND / 256)) / (RADIO_TIMER_SECOND / 256))) + #define USEC_TO_RADIO(X) ((X) * 4) /* The PHY header (preamble + SFD, 4+1 bytes) duration is equivalent to 10 symbols */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c index e9443a68e..dfe3a0d3c 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c @@ -55,11 +55,11 @@ #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) #include DeviceFamily_constructPath(driverlib/rf_data_entry.h) #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) -// rf_ieee_cmd and rf_ieee_mailbox included by RF settings because of the -// discrepancy between CC13x0 and CC13x2 IEEE support. CC13x0 doesn't provide -// RFCore definitions of IEEE commandos, and are therefore included locally -// from the Contiki build system. CC13x2 includes these normally from driverlib. -// This is taken care of RF settings. +/* rf_ieee_cmd and rf_ieee_mailbox included by RF settings because of the + * discrepancy between CC13x0 and CC13x2 IEEE support. CC13x0 doesn't provide + * RFCore definitions of IEEE commandos, and are therefore included locally + * from the Contiki build system. CC13x2 includes these normally from driverlib. + * This is taken care of RF settings. */ #include /*---------------------------------------------------------------------------*/ @@ -81,7 +81,6 @@ #include #include #include -#include /*---------------------------------------------------------------------------*/ /* Log configuration */ #include "sys/log.h" @@ -138,8 +137,8 @@ #endif /*---------------------------------------------------------------------------*/ /* TX power table convenience macros */ -#define TX_POWER_MIN (TX_POWER_TABLE[0]) -#define TX_POWER_MAX (TX_POWER_TABLE[TX_POWER_TABLE_SIZE - 1]) +#define TX_POWER_MIN (TX_POWER_TABLE[0].power) +#define TX_POWER_MAX (TX_POWER_TABLE[TX_POWER_TABLE_SIZE - 1].power) #define TX_POWER_IN_RANGE(dbm) (((dbm) >= TX_POWER_MIN) && ((dbm) <= TX_POWER_MAX)) /*---------------------------------------------------------------------------*/ @@ -161,65 +160,26 @@ /*---------------------------------------------------------------------------*/ /* Timeout constants */ -/* How long to wait for an ongoing ACK TX to finish before starting frame TX */ -#define TIMEOUT_TX_WAIT (RTIMER_SECOND >> 11) - -/* How long to wait for the RF to enter RX in cmd_rx */ -#define TIMEOUT_ENTER_RX_WAIT (RTIMER_SECOND >> 10) - -/* How long to wait for the RF to react on CMD_ABORT: around 1 msec */ -#define TIMEOUT_RF_TURN_OFF_WAIT (RTIMER_SECOND >> 10) - -/* How long to wait for the RF to finish TX of a packet or an ACK */ -#define TIMEOUT_TX_FINISH_WAIT (RTIMER_SECOND >> 7) - /* How long to wait for the rx read entry to become ready */ #define TIMEOUT_DATA_ENTRY_BUSY (RTIMER_SECOND / 250) /*---------------------------------------------------------------------------*/ -#define CCA_STATE_IDLE 0 -#define CCA_STATE_BUSY 1 -#define CCA_STATE_INVALID 2 +#define RAT_RANGE (~(uint32_t)0) +#define RAT_ONE_QUARTER (RAT_RANGE / (uint32_t)4) +#define RAT_THREE_QUARTERS ((RAT_RANGE * (uint32_t)3) / (uint32_t)4) + +/* XXX: don't know what exactly is this, looks like the time to TX 3 octets */ +#define RAT_TIMESTAMP_OFFSET -(USEC_TO_RADIO(32 * 3) - 1) /* -95.75 usec */ /*---------------------------------------------------------------------------*/ -/* TI-RTOS RF driver object */ -static RF_Object g_rfObj; -static RF_Handle g_rfHandle; - -/* RF Core command pointers */ -#define cmd_radio_setup (*(volatile rfc_CMD_RADIO_SETUP_t*)&rf_cmd_ieee_radio_setup) -#define cmd_fs (*(volatile rfc_CMD_FS_t*) &rf_cmd_ieee_fs) -#define cmd_tx (*(volatile rfc_CMD_IEEE_TX_t*) &rf_cmd_ieee_tx) -#define cmd_rx (*(volatile rfc_CMD_IEEE_RX_t*) &rf_cmd_ieee_rx) - -/* RF command handles */ -static RF_CmdHandle g_cmdTxHandle; -static RF_CmdHandle g_cmdRxHandle; - -/* Global RF Core commands */ -static rfc_CMD_IEEE_MOD_FILT_t g_cmdModFilt; - -/* RF stats data structure */ -static rfc_ieeeRxOutput_t g_rxStats; +#define STATUS_CORRELATION 0x3f /* bits 0-5 */ +#define STATUS_REJECT_FRAME 0x40 /* bit 6 */ +#define STATUS_CRC_FAIL 0x80 /* bit 7 */ /*---------------------------------------------------------------------------*/ -/* The outgoing frame buffer */ -#define TX_BUF_PAYLOAD_LEN 180 +/* TX buf configuration */ #define TX_BUF_HDR_LEN 2 +#define TX_BUF_PAYLOAD_LEN 180 -static uint8_t g_txBuf[TX_BUF_HDR_LEN + TX_BUF_PAYLOAD_LEN] CC_ALIGN(4); -/*---------------------------------------------------------------------------*/ -/* RX Data Queue */ -static dataQueue_t g_rxDataQueue; -/*---------------------------------------------------------------------------*/ -/* Constants for receive buffers */ -#define DATA_ENTRY_LENSZ_NONE 0 -#define DATA_ENTRY_LENSZ_BYTE 1 -#define DATA_ENTRY_LENSZ_WORD 2 /* 2 bytes */ +#define TX_BUF_SIZE (TX_BUF_HDR_LEN + TX_BUF_PAYLOAD_LEN) -#define DATA_ENTRY_LENSZ DATA_ENTRY_LENSZ_BYTE -typedef uint8_t lensz_t; - -#define FRAME_OFFSET DATA_ENTRY_LENSZ -#define FRAME_SHAVE 8 /* FCS (2) + RSSI (1) + Status (1) + Timestamp (4) */ -/*---------------------------------------------------------------------------*/ /* RX buf configuration */ #ifdef IEEE_MODE_CONF_RX_BUF_CNT # define RX_BUF_CNT IEEE_MODE_CONF_RX_BUF_CNT @@ -228,48 +188,19 @@ typedef uint8_t lensz_t; #endif #define RX_BUF_SIZE 144 - -/* Receive buffer entries with room for 1 IEEE 802.15.4 frame in each */ -typedef rfc_dataEntryGeneral_t data_entry_t; - -typedef union { - data_entry_t data_entry; - uint8_t buf[RX_BUF_SIZE]; -} rx_buf_t CC_ALIGN(4); - -static rx_buf_t rx_bufs[RX_BUF_CNT]; - -/* Receive entry pointer to keep track of read items */ -static data_entry_t *rx_read_entry; /*---------------------------------------------------------------------------*/ -/* RAT overflow upkeep */ -static struct ctimer g_ratOverflowTimer; -static rtimer_clock_t g_ratLastOverflow; -static volatile uint32_t g_ratOverflowCount; +/* Size of the Length representation in Data Entry, one byte in this case */ +typedef uint8_t lensz_t; -#define RAT_RANGE (~(uint32_t)0) -#define RAT_OVERFLOW_PERIOD_SECONDS (RAT_RANGE / (uint32_t)RADIO_TIMER_SECOND) -/* XXX: don't know what exactly is this, looks like the time to TX 3 octets */ -#define RAT_TIMESTAMP_OFFSET -(USEC_TO_RADIO(32 * 3) - 1) /* -95.75 usec */ +#define FRAME_OFFSET sizeof(lensz_t) +#define FRAME_SHAVE 8 /* FCS (2) + RSSI (1) + Status (1) + Timestamp (4) */ /*---------------------------------------------------------------------------*/ -#define STATUS_CORRELATION 0x3f // bits 0-5 -#define STATUS_REJECT_FRAME 0x40 // bit 6 -#define STATUS_CRC_FAIL 0x80 // bit 7 -/*---------------------------------------------------------------------------*/ -#define CHANNEL_CLEAR_ERROR -1 -/*---------------------------------------------------------------------------*/ -/* Global state */ - -/* Are we currently in poll mode? */ -static volatile bool g_bPollMode = false; - -/* Enable/disable CCA before sending */ -static volatile bool g_bSendOnCca = false; - -/* Last RX operation stats */ -static volatile int8_t g_lastRssi; -static volatile uint8_t g_lastCorrLqi; -static volatile uint32_t g_lastTimestamp; +/* Used for checking result of CCA_REQ command */ +typedef enum { + CCA_STATE_IDLE = 0, + CCA_STATE_BUSY = 1, + CCA_STATE_INVALID = 2 +} cca_state_t; /*---------------------------------------------------------------------------*/ typedef enum { POWER_STATE_ON = (1 << 0), @@ -277,10 +208,75 @@ typedef enum { POWER_STATE_RESTART = POWER_STATE_ON | POWER_STATE_OFF, } PowerState; /*---------------------------------------------------------------------------*/ +/* RF Core typedefs */ +typedef dataQueue_t data_queue_t; +typedef rfc_dataEntryGeneral_t data_entry_t; +typedef rfc_ieeeRxOutput_t rx_output_t; +typedef rfc_CMD_IEEE_MOD_FILT_t cmd_mod_filt_t; +typedef rfc_CMD_IEEE_CCA_REQ_t cmd_cca_req_t; + +/* Receive buffer entries with room for 1 IEEE 802.15.4 frame in each */ +typedef union { + data_entry_t data_entry; + uint8_t buf[RX_BUF_SIZE]; +} rx_buf_t CC_ALIGN(4); + +typedef struct { + /* Outgoing frame buffer */ + uint8_t tx_buf[TX_BUF_SIZE] CC_ALIGN(4); + /* Ingoing frame buffers */ + rx_buf_t rx_bufs[RX_BUF_CNT]; + + /* RX Data Queue */ + data_queue_t rx_data_queue; + /* RF Statistics struct */ + rx_output_t rx_stats; + /* Receive entry pointer to keep track of read items */ + data_entry_t* rx_read_entry; + + /* Indicates RF is supposed to be on or off */ + bool rf_is_on; + /* Enable/disable CCA before sending */ + bool send_on_cca; + /* Are we currently in poll mode? */ + bool poll_mode; + + /* Last RX operation stats */ + struct { + int8_t rssi; + uint8_t corr_lqi; + uint32_t timestamp; + } last; + + /* RAT Overflow Upkeep */ + struct { + struct ctimer overflow_timer; + rtimer_clock_t last_overflow; + volatile uint32_t overflow_count; + } rat; + + /* RF driver */ + RF_Object rf_object; + RF_Handle rf_handle; +} ieee_radio_t; + +static ieee_radio_t ieee_radio; + +/* Global RF Core commands */ +static cmd_mod_filt_t cmd_mod_filt; +/*---------------------------------------------------------------------------*/ +/* RF Command volatile objects */ +#define cmd_radio_setup (*(volatile rfc_CMD_RADIO_SETUP_t*)&rf_cmd_ieee_radio_setup) +#define cmd_fs (*(volatile rfc_CMD_FS_t*) &rf_cmd_ieee_fs) +#define cmd_tx (*(volatile rfc_CMD_IEEE_TX_t*) &rf_cmd_ieee_tx) +#define cmd_rx (*(volatile rfc_CMD_IEEE_RX_t*) &rf_cmd_ieee_rx) +/*---------------------------------------------------------------------------*/ +static CC_INLINE bool tx_active(void) { return cmd_tx.status == ACTIVE; } +static CC_INLINE bool rx_active(void) { return cmd_rx.status == ACTIVE; } +/*---------------------------------------------------------------------------*/ /* Forward declarations of static functions */ static int set_rx(const PowerState); static void check_rat_overflow(void); -static bool rf_is_on(void); static uint32_t rat_to_timestamp(const uint32_t); /*---------------------------------------------------------------------------*/ /* Forward declarations of Radio driver functions */ @@ -318,43 +314,34 @@ const struct radio_driver ieee_mode_driver = { }; /*---------------------------------------------------------------------------*/ static void -rx_cb(RF_Handle h, RF_CmdHandle ch, RF_EventMask e) +rx_cb(RF_Handle client, RF_CmdHandle command, RF_EventMask events) { - if (e & RF_EventRxOk) { + /* Unused arguments */ + (void)client; + (void)command; + + if (events & RF_EventRxOk) { process_poll(&rf_process); } } /*---------------------------------------------------------------------------*/ static void -rf_error_cb(RF_Handle h, RF_CmdHandle ch, RF_EventMask e) -{ - // See SWRZ062B: Synth failed to calibrate, CMD_FS must be repeated - if ((ch == RF_ERROR_CMDFS_SYNTH_PROG) && - (cmd_fs.status == ERROR_SYNTH_PROG)) { - // Call CMD_FS async, a synth error will trigger rf_error_cb once more - const uint8_t stop_gracefully = 1; - RF_flushCmd(g_rfHandle, RF_CMDHANDLE_FLUSH_ALL, stop_gracefully); - RF_postCmd(g_rfHandle, (RF_Op*)&cmd_fs, RF_PriorityNormal, NULL, 0); - } -} -/*---------------------------------------------------------------------------*/ -static void rat_overflow_cb(void *arg) { check_rat_overflow(); - // Check next time after half of the RAT interval - ctimer_set(&g_ratOverflowTimer, RAT_OVERFLOW_PERIOD_SECONDS * CLOCK_SECOND / 2, - rat_overflow_cb, NULL); + /* Check next time after half of the RAT interval */ + const clock_time_t two_quarters = (2 * RAT_ONE_QUARTER * CLOCK_SECOND) / RAT_SECOND; + ctimer_set(&ieee_radio.rat.overflow_timer, two_quarters, rat_overflow_cb, NULL); } /*---------------------------------------------------------------------------*/ static void init_data_queue(void) { - // Initialize RF core data queue, circular buffer - g_rxDataQueue.pCurrEntry = rx_bufs[0].buf; - g_rxDataQueue.pLastEntry = NULL; - // Set current read pointer to first element - rx_read_entry = &rx_bufs[0].data_entry; + /* Initialize RF core data queue, circular buffer */ + ieee_radio.rx_data_queue.pCurrEntry = ieee_radio.rx_bufs[0].buf; + ieee_radio.rx_data_queue.pLastEntry = NULL; + /* Set current read pointer to first element */ + ieee_radio.rx_read_entry = &ieee_radio.rx_bufs[0].data_entry; } /*---------------------------------------------------------------------------*/ static void @@ -362,8 +349,8 @@ init_rf_params(void) { cmd_rx.channel = IEEE_MODE_CHANNEL; - cmd_rx.pRxQ = &g_rxDataQueue; - cmd_rx.pOutput = &g_rxStats; + cmd_rx.pRxQ = &ieee_radio.rx_data_queue; + cmd_rx.pOutput = &ieee_radio.rx_stats; #if IEEE_MODE_PROMISCOUS cmd_rx.frameFiltOpt.frameFiltEn = 0; @@ -379,10 +366,10 @@ init_rf_params(void) cmd_rx.ccaRssiThr = IEEE_MODE_RSSI_THRESHOLD; - // Initialize address filter command - g_cmdModFilt.commandNo = CMD_IEEE_MOD_FILT; - memcpy(&(g_cmdModFilt.newFrameFiltOpt), &(rf_cmd_ieee_rx.frameFiltOpt), sizeof(rf_cmd_ieee_rx.frameFiltOpt)); - memcpy(&(g_cmdModFilt.newFrameTypes), &(rf_cmd_ieee_rx.frameTypes), sizeof(rf_cmd_ieee_rx.frameTypes)); + /* Initialize address filter command */ + cmd_mod_filt.commandNo = CMD_IEEE_MOD_FILT; + memcpy(&(cmd_mod_filt.newFrameFiltOpt), &(rf_cmd_ieee_rx.frameFiltOpt), sizeof(rf_cmd_ieee_rx.frameFiltOpt)); + memcpy(&(cmd_mod_filt.newFrameTypes), &(rf_cmd_ieee_rx.frameTypes), sizeof(rf_cmd_ieee_rx.frameTypes)); } /*---------------------------------------------------------------------------*/ static void @@ -393,56 +380,55 @@ init_rx_buffers(void) const data_entry_t data_entry = { .status = DATA_ENTRY_PENDING, .config.type = DATA_ENTRY_TYPE_GEN, - .config.lenSz = DATA_ENTRY_LENSZ, - .length = RX_BUF_SIZE - sizeof(data_entry_t), /* TODO: is this sizeof sound? */ + .config.lenSz = sizeof(lensz_t), + .length = RX_BUF_SIZE - sizeof(data_entry_t), /* TODO: is this sizeof sound? */ /* Point to fist entry if this is last entry, else point to next entry */ .pNextEntry = (i == (RX_BUF_CNT - 1)) - ? rx_bufs[0].buf - : rx_bufs[i].buf + ? ieee_radio.rx_bufs[0].buf + : ieee_radio.rx_bufs[i].buf }; - rx_bufs[i].data_entry = data_entry; + ieee_radio.rx_bufs[i].data_entry = data_entry; } } /*---------------------------------------------------------------------------*/ -static bool -set_channel(uint8_t channel) +static cmd_result_t +set_channel(uint32_t channel) { if (!IEEE_MODE_CHAN_IN_RANGE(channel)) { PRINTF("set_channel: illegal channel %d, defaults to %d\n", - channel, IEEE_MODE_CHANNEL); + (int)channel, IEEE_MODE_CHANNEL); channel = IEEE_MODE_CHANNEL; } if (channel == cmd_rx.channel) { - // We are already calibrated to this channel + /* We are already calibrated to this channel */ return true; } cmd_rx.channel = 0; - // freq = freq_base + freq_spacing * (channel - channel_min) - const uint32_t newFreq = (uint32_t)(IEEE_MODE_FREQ_BASE + IEEE_MODE_FREQ_SPACING * ((uint32_t)channel - IEEE_MODE_CHAN_MIN)); - const uint32_t freq = newFreq / 1000; - const uint32_t frac = (newFreq - (freq * 1000)) * 65536 / 1000; + /* freq = freq_base + freq_spacing * (channel - channel_min) */ + const uint32_t new_freq = IEEE_MODE_FREQ_BASE + IEEE_MODE_FREQ_SPACING * (channel - IEEE_MODE_CHAN_MIN); + const uint32_t freq = new_freq / 1000; + const uint32_t frac = ((new_freq - (freq * 1000)) * 65536) / 1000; PRINTF("set_channel: %d = 0x%04X.0x%04X (%lu)\n", - channel, (uint16_t)freq, (uint16_t)frac, newFreq); + (int)channel, (uint16_t)freq, (uint16_t)frac, new_freq); cmd_fs.frequency = (uint16_t)freq; cmd_fs.fractFreq = (uint16_t)frac; - const bool rx_active = (cmd_rx.status == ACTIVE); + const bool was_on = rx_active(); - if (rx_active) { - const uint8_t stop_gracefully = 1; - RF_flushCmd(g_rfHandle, RF_CMDHANDLE_FLUSH_ALL, stop_gracefully); + if (was_on) { + RF_flushCmd(ieee_radio.rf_handle, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY); } - // Start FS command asynchronously. We don't care when it is finished + /* Start FS command asynchronously. We don't care when it is finished */ RF_EventMask events = 0; uint8_t tries = 0; bool cmd_ok = false; do { - events = RF_runCmd(g_rfHandle, (RF_Op*)&cmd_fs, RF_PriorityNormal, NULL, 0); + events = RF_runCmd(ieee_radio.rf_handle, (RF_Op*)&cmd_fs, RF_PriorityNormal, NULL, 0); cmd_ok = ((events & RF_EventLastCmdDone) != 0) && (cmd_fs.status == DONE_OK); } while (!cmd_ok && (tries++ < 3)); @@ -453,120 +439,133 @@ set_channel(uint8_t channel) cmd_rx.channel = channel; - if (rx_active) { + if (was_on) { set_rx(POWER_STATE_ON); } return true; } /*---------------------------------------------------------------------------*/ -static int -set_tx_power(const radio_value_t dbm) +static radio_result_t +set_tx_power(const radio_value_t dBm) { - const RF_TxPowerTable_Value tx_power_table_value = RF_TxPowerTable_findValue(TX_POWER_TABLE, (int8_t)dbm); - const RF_Stat stat = RF_setTxPower(g_rfHandle, tx_power_table_value); - - if (stat != RF_StatSuccess) { - PRINTF("set_tx_power: stat=0x%02X\n", stat); - return CMD_RESULT_ERROR; + if (!TX_POWER_IN_RANGE(dBm)) { + return RADIO_RESULT_INVALID_VALUE; } - return CMD_RESULT_OK; + + const RF_TxPowerTable_Value tx_power_table_value = RF_TxPowerTable_findValue(TX_POWER_TABLE, (int8_t)dBm); + const RF_Stat stat = RF_setTxPower(ieee_radio.rf_handle, tx_power_table_value); + + return (stat == RF_StatSuccess) + ? RADIO_RESULT_OK + : RADIO_RESULT_ERROR; } /*---------------------------------------------------------------------------*/ static radio_value_t get_tx_power(void) { - const RF_TxPowerTable_Value tx_power_table_value = RF_getTxPower(g_rfHandle); - const int8_t dbm = RF_TxPowerTable_findPowerLevel(TX_POWER_TABLE, tx_power_table_value); - - if (dbm == RF_TxPowerTable_INVALID_DBM) { - PRINTF("get_tx_power: invalid dbm received=%d\n", dbm); - } - - return (radio_value_t)dbm; + const RF_TxPowerTable_Value value = RF_getTxPower(ieee_radio.rf_handle); + return (radio_value_t)RF_TxPowerTable_findPowerLevel(TX_POWER_TABLE, value); } /*---------------------------------------------------------------------------*/ static void set_send_on_cca(bool enable) { - g_bSendOnCca = enable; + ieee_radio.send_on_cca = enable; } /*---------------------------------------------------------------------------*/ static void check_rat_overflow(void) { - const bool was_off = !rf_is_on(); - if (was_off) { - RF_runDirectCmd(g_rfHandle, CMD_NOP); - } - const uint32_t currentValue = RF_getCurrentTime(); + const bool was_off = !rx_active(); - static uint32_t lastValue; - static bool bFirstTime = true; - if (bFirstTime) { - // First time checking overflow will only store the current value - bFirstTime = false; + if (was_off) { + RF_runDirectCmd(ieee_radio.rf_handle, CMD_NOP); + } + + const uint32_t current_value = RF_getCurrentTime(); + + static bool initial_iteration = true; + static uint32_t last_value; + + if (initial_iteration) { + /* First time checking overflow will only store the current value */ + initial_iteration = false; } else { - // Overflow happens in the last quarter of the RAT range - if (currentValue + RAT_RANGE / 4 < lastValue) { - // Overflow detected - g_ratLastOverflow = RTIMER_NOW(); - g_ratOverflowCount += 1; + /* Overflow happens in the last quarter of the RAT range */ + if ((current_value + RAT_ONE_QUARTER) < last_value) { + /* Overflow detected */ + ieee_radio.rat.last_overflow = RTIMER_NOW(); + ieee_radio.rat.overflow_count += 1; } } - lastValue = currentValue; + last_value = current_value; if (was_off) { - off(); + RF_yield(ieee_radio.rf_handle); } } /*---------------------------------------------------------------------------*/ static uint32_t -rat_to_timestamp(const uint32_t ratTimestamp) +rat_to_timestamp(const uint32_t rat_ticks) { check_rat_overflow(); - uint64_t adjustedOverflowCount = g_ratOverflowCount; + uint64_t adjusted_overflow_count = ieee_radio.rat.overflow_count; - // If the timestamp is in the 4th quarter and the last overflow was recently, - // assume that the timestamp refers to the time before the overflow - if(ratTimestamp > (uint32_t)(RAT_RANGE * 3 / 4)) { - if(RTIMER_CLOCK_LT(RTIMER_NOW(), - g_ratLastOverflow + RAT_OVERFLOW_PERIOD_SECONDS * RTIMER_SECOND / 4)) { - adjustedOverflowCount -= 1; + /* If the timestamp is in the 4th quarter and the last overflow was recently, + * assume that the timestamp refers to the time before the overflow */ + if (rat_ticks > RAT_THREE_QUARTERS) { + const rtimer_clock_t one_quarter = (RAT_ONE_QUARTER * RTIMER_SECOND) / RAT_SECOND; + if (RTIMER_CLOCK_LT(RTIMER_NOW(), ieee_radio.rat.last_overflow + one_quarter)) { + adjusted_overflow_count -= 1; } } - // Add the overflowed time to the timestamp - const uint64_t ratTimestamp64 = (uint64_t)ratTimestamp + (uint64_t)RAT_RANGE * adjustedOverflowCount; + /* Add the overflowed time to the timestamp */ + const uint64_t rat_ticks_adjusted = (uint64_t)rat_ticks + (uint64_t)RAT_RANGE * adjusted_overflow_count; - // Correct timestamp so that it refers to the end of the SFD and convert to RTIMER - return RADIO_TO_RTIMER(ratTimestamp64 + RAT_TIMESTAMP_OFFSET); + /* Correct timestamp so that it refers to the end of the SFD and convert to RTIMER */ + return RAT_TO_RTIMER(rat_ticks_adjusted + RAT_TIMESTAMP_OFFSET); } /*---------------------------------------------------------------------------*/ static int init(void) { - RF_Params params; - RF_Params_init(¶ms); - params.pErrCb = rf_error_cb; + if (ieee_radio.rf_handle) { + PRINTF("init: Radio already initialized\n"); + return CMD_RESULT_OK; + } + + /* RX is off */ + ieee_radio.rf_is_on = false; init_rf_params(); init_data_queue(); - g_rfHandle = RF_open(&g_rfObj, &rf_ieee_mode, (RF_RadioSetup*)&cmd_radio_setup, ¶ms); - assert(g_rfHandle != NULL); + /* Init RF params and specify non-default params */ + RF_Params rf_params; + RF_Params_init(&rf_params); + rf_params.nInactivityTimeout = 2000; /* 2 ms */ + + ieee_radio.rf_handle = RF_open(&ieee_radio.rf_object, &rf_ieee_mode, + (RF_RadioSetup*)&cmd_radio_setup, &rf_params); + if (ieee_radio.rf_handle == NULL) { + PRINTF("init: unable to open RF driver\n"); + return CMD_RESULT_ERROR; + } set_channel(IEEE_MODE_CHANNEL); ENERGEST_ON(ENERGEST_TYPE_LISTEN); - // Start RAT overflow upkeep + /* Start RAT overflow upkeep */ check_rat_overflow(); - ctimer_set(&g_ratOverflowTimer, RAT_OVERFLOW_PERIOD_SECONDS * CLOCK_SECOND / 2, - rat_overflow_cb, NULL); + clock_time_t two_quarters = (2 * RAT_ONE_QUARTER * CLOCK_SECOND) / RAT_SECOND; + ctimer_set(&ieee_radio.rat.overflow_timer, two_quarters, rat_overflow_cb, NULL); + /* Start RF process */ process_start(&rf_process, NULL); return CMD_RESULT_OK; @@ -577,28 +576,16 @@ prepare(const void *payload, unsigned short payload_len) { const size_t len = MIN((size_t)payload_len, (size_t)TX_BUF_PAYLOAD_LEN); - memcpy(&g_txBuf[TX_BUF_HDR_LEN], payload, len); + memcpy(&ieee_radio.tx_buf[TX_BUF_HDR_LEN], payload, len); return 0; } /*---------------------------------------------------------------------------*/ -static bool -rf_is_on(void) -{ - RF_InfoVal infoVal; - memset(&infoVal, 0x0, sizeof(RF_InfoVal)); - const RF_Stat stat = RF_getInfo(g_rfHandle, RF_GET_RADIO_STATE, &infoVal); - return (stat == RF_StatSuccess) - ? infoVal.bRadioState // 0: Radio OFF, 1: Radio ON - : false; -} -/*---------------------------------------------------------------------------*/ static int set_rx(const PowerState state) { if (state & POWER_STATE_OFF) { - // Stop RX gracefully, don't care about the result - const uint8_t stop_gracefully = 1; - RF_cancelCmd(g_rfHandle, g_cmdRxHandle, stop_gracefully); + /* Stop RX gracefully, don't care about the result */ + RF_cancelCmd(ieee_radio.rf_handle, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY); } if (state & POWER_STATE_ON) { @@ -607,14 +594,14 @@ set_rx(const PowerState state) return CMD_RESULT_OK; } - RF_ScheduleCmdParams schedParams; - RF_ScheduleCmdParams_init(&schedParams); + RF_ScheduleCmdParams sched_params; + RF_ScheduleCmdParams_init(&sched_params); cmd_rx.status = IDLE; - g_cmdRxHandle = RF_scheduleCmd(g_rfHandle, (RF_Op*)&cmd_rx, &schedParams, rx_cb, - RF_EventRxOk | RF_EventRxBufFull | RF_EventRxEntryDone); - if ((g_cmdRxHandle == RF_ALLOC_ERROR) || (g_cmdRxHandle == RF_SCHEDULE_CMD_ERROR)) { - PRINTF("transmit: unable to allocate RX command\n"); + RF_CmdHandle rx_handle = RF_scheduleCmd(ieee_radio.rf_handle, (RF_Op*)&cmd_rx, &sched_params, rx_cb, + RF_EventRxOk | RF_EventRxBufFull | RF_EventRxEntryDone); + if ((rx_handle == RF_ALLOC_ERROR) || (rx_handle == RF_SCHEDULE_CMD_ERROR)) { + PRINTF("transmit: unable to schedule RX command cmd_handle=%d\n", rx_handle); return CMD_RESULT_ERROR; } } @@ -625,31 +612,32 @@ set_rx(const PowerState state) static int transmit_aux(unsigned short transmit_len) { - // Configure TX command + /* Configure TX command */ cmd_tx.payloadLen = (uint8_t)transmit_len; - cmd_tx.pPayload = &g_txBuf[TX_BUF_HDR_LEN]; + cmd_tx.pPayload = &ieee_radio.tx_buf[TX_BUF_HDR_LEN]; - RF_ScheduleCmdParams schedParams; - RF_ScheduleCmdParams_init(&schedParams); + RF_ScheduleCmdParams sched_params; + RF_ScheduleCmdParams_init(&sched_params); - // As IEEE_TX is a FG command, the TX operation will be executed - // either way if RX is running or not + /* As IEEE_TX is a FG command, the TX operation will be executed + * either way if RX is running or not */ cmd_tx.status = IDLE; - g_cmdTxHandle = RF_scheduleCmd(g_rfHandle, (RF_Op*)&cmd_tx, &schedParams, NULL, 0); - if ((g_cmdTxHandle == RF_ALLOC_ERROR) || (g_cmdTxHandle == RF_SCHEDULE_CMD_ERROR)) { - // Failure sending the CMD_IEEE_TX command - PRINTF("transmit: failed to allocate TX command cmdHandle=%d, status=%04x\n", - g_cmdTxHandle, cmd_tx.status); + RF_CmdHandle tx_handle = RF_scheduleCmd(ieee_radio.rf_handle, (RF_Op*)&cmd_tx, &sched_params, + NULL, 0); + if ((tx_handle == RF_ALLOC_ERROR) || (tx_handle == RF_SCHEDULE_CMD_ERROR)) { + /* Failure sending the CMD_IEEE_TX command */ + PRINTF("transmit: unable to schedule TX command cmd_handle=%d, status=%04x\n", + tx_handle, cmd_tx.status); return RADIO_TX_ERR; } ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT); - // Wait until TX operation finishes - RF_EventMask events = RF_pendCmd(g_rfHandle, g_cmdTxHandle, 0); - if ((events & (RF_EventFGCmdDone | RF_EventLastFGCmdDone)) == 0) { - PRINTF("transmit: TX command error events=0x%08llx, status=0x%04x\n", - events, cmd_tx.status); + /* Wait until TX operation finishes */ + RF_EventMask tx_events = RF_pendCmd(ieee_radio.rf_handle, tx_handle, 0); + if ((tx_events & (RF_EventFGCmdDone | RF_EventLastFGCmdDone)) == 0) { + PRINTF("transmit: TX command pend error events=0x%08llx, status=0x%04x\n", + tx_events, cmd_tx.status); return RADIO_TX_ERR; } @@ -659,9 +647,7 @@ transmit_aux(unsigned short transmit_len) static int transmit(unsigned short transmit_len) { - const bool was_rx = (cmd_rx.status == ACTIVE); - - if (g_bSendOnCca && channel_clear() != 1) { + if (ieee_radio.send_on_cca && channel_clear() != 1) { PRINTF("transmit: channel wasn't clear\n"); return RADIO_TX_COLLISION; } @@ -669,9 +655,6 @@ transmit(unsigned short transmit_len) const int rv = transmit_aux(transmit_len); ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN); - if (!was_rx) { - off(); - } return rv; } /*---------------------------------------------------------------------------*/ @@ -685,28 +668,27 @@ send(const void *payload, unsigned short payload_len) static void release_data_entry(void) { - data_entry_t *const data_entry = rx_read_entry; + data_entry_t *const data_entry = ieee_radio.rx_read_entry; uint8_t *const frame_ptr = (uint8_t*)&data_entry->data; - - // Clear the length byte and set status to 0: "Pending" + /* Clear the length byte and set status to 0: "Pending" */ *(lensz_t*)frame_ptr = 0; data_entry->status = DATA_ENTRY_PENDING; - rx_read_entry = (data_entry_t*)data_entry->pNextEntry; + ieee_radio.rx_read_entry = (data_entry_t*)data_entry->pNextEntry; } /*---------------------------------------------------------------------------*/ static int read(void *buf, unsigned short buf_len) { - volatile data_entry_t *data_entry = rx_read_entry; + volatile data_entry_t *data_entry = ieee_radio.rx_read_entry; const rtimer_clock_t t0 = RTIMER_NOW(); - // Only wait if the Radio timer is accessing the entry + /* Only wait if the Radio timer is accessing the entry */ while ((data_entry->status == DATA_ENTRY_BUSY) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + TIMEOUT_DATA_ENTRY_BUSY)); if (data_entry->status != DATA_ENTRY_FINISHED) { - // No available data + /* No available data */ return 0; } @@ -746,143 +728,166 @@ read(void *buf, unsigned short buf_len) return 0; } - memcpy(buf, payload_ptr, payload_len); /* RSSI stored FCS (2) bytes after payload */ - g_lastRssi = (int8_t)payload_ptr[payload_len + 2]; + ieee_radio.last.rssi = (int8_t)payload_ptr[payload_len + 2]; /* LQI retrieved from Status byte, FCS (2) + RSSI (1) bytes after payload */ - g_lastCorrLqi = ((uint8_t)payload_ptr[payload_len + 3]) & STATUS_CORRELATION; + ieee_radio.last.corr_lqi = ((uint8_t)payload_ptr[payload_len + 3]) & STATUS_CORRELATION; /* Timestamp stored FCS (2) + RSSI (1) + Status (1) bytes after payload */ - const uint32_t ratTimestamp = *(uint32_t*)(payload_ptr + payload_len + 4); - g_lastTimestamp = rat_to_timestamp(ratTimestamp); + const uint32_t rat_ticks = *(uint32_t*)(payload_ptr + payload_len + 4); + ieee_radio.last.timestamp = rat_to_timestamp(rat_ticks); - if (!g_bPollMode) { - // Not in poll mode: packetbuf should not be accessed in interrupt context. - // In poll mode, the last packet RSSI and link quality can be obtained through - // RADIO_PARAM_LAST_RSSI and RADIO_PARAM_LAST_LINK_QUALITY - packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (packetbuf_attr_t)g_lastRssi); - packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, (packetbuf_attr_t)g_lastCorrLqi); + if (!ieee_radio.poll_mode) { + /* Not in poll mode: packetbuf should not be accessed in interrupt context. */ + /* In poll mode, the last packet RSSI and link quality can be obtained through */ + /* RADIO_PARAM_LAST_RSSI and RADIO_PARAM_LAST_LINK_QUALITY */ + packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (packetbuf_attr_t)ieee_radio.last.rssi); + packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, (packetbuf_attr_t)ieee_radio.last.corr_lqi); } release_data_entry(); return (int)payload_len; } /*---------------------------------------------------------------------------*/ -static int -channel_clear_aux(void) +static cmd_result_t +cca_request(cmd_cca_req_t *cmd_cca_req) { - rfc_CMD_IEEE_CCA_REQ_t RF_cmdIeeeCaaReq; - memset(&RF_cmdIeeeCaaReq, 0x0, sizeof(rfc_CMD_IEEE_CCA_REQ_t)); - RF_cmdIeeeCaaReq.commandNo = CMD_IEEE_CCA_REQ; + const bool rx_is_off = !rx_active(); - const RF_Stat stat = RF_runImmediateCmd(g_rfHandle, (uint32_t*)&RF_cmdIeeeCaaReq); - if (stat != RF_StatCmdDoneSuccess) { - PRINTF("channel_clear: CCA request failed stat=0x%02X\n", stat); + if (rx_is_off && set_rx(POWER_STATE_ON) != CMD_RESULT_OK) { return CMD_RESULT_ERROR; } - // Channel is clear if CCA state is idle (0) or invalid (2), i.e. not busy (1) - return (RF_cmdIeeeCaaReq.ccaInfo.ccaState != 1); + const RF_Stat stat = RF_runImmediateCmd(ieee_radio.rf_handle, (uint32_t*)&cmd_cca_req); + + if (rx_is_off) { + set_rx(POWER_STATE_OFF); + } + + return (stat == RF_StatCmdDoneSuccess) + ? CMD_RESULT_OK + : CMD_RESULT_ERROR; } /*---------------------------------------------------------------------------*/ static int channel_clear(void) { - const bool was_rx = (cmd_rx.status == ACTIVE); - if (!was_rx && set_rx(POWER_STATE_ON) != CMD_RESULT_OK) { - PRINTF("channel_clear: unable to start RX\n"); - return CHANNEL_CLEAR_ERROR; + cmd_cca_req_t cmd_cca_req; + memset(&cmd_cca_req, 0x0, sizeof(cmd_cca_req_t)); + cmd_cca_req.commandNo = CMD_IEEE_CCA_REQ; + + if (cca_request(&cmd_cca_req) != CMD_RESULT_OK) { + return 0; } - const int rv = channel_clear_aux(); - - if (!was_rx) { - set_rx(POWER_STATE_OFF); - } - return rv; + /* Channel is clear if CCA state is IDLE */ + return (cmd_cca_req.ccaInfo.ccaState == CCA_STATE_IDLE); } /*---------------------------------------------------------------------------*/ static int receiving_packet(void) { - // If we are not in RX, we are not receiving - if (cmd_rx.status != ACTIVE) { - PRINTF("receiving_packet: not in RX\n"); + cmd_cca_req_t cmd_cca_req; + memset(&cmd_cca_req, 0x0, sizeof(cmd_cca_req_t)); + cmd_cca_req.commandNo = CMD_IEEE_CCA_REQ; + + if (cca_request(&cmd_cca_req) != CMD_RESULT_OK) { return 0; } - rfc_CMD_IEEE_CCA_REQ_t cca_req; - memset(&cca_req, 0x0, sizeof(rfc_CMD_IEEE_CCA_REQ_t)); - cca_req.commandNo = CMD_IEEE_CCA_REQ; - - const RF_Stat stat = RF_runImmediateCmd(g_rfHandle, (uint32_t*)&cca_req); - if (stat != RF_StatCmdDoneSuccess) { - PRINTF("receiving_packet: CCA request failed stat=0x%02X\n", stat); + /* If we are transmitting (can only be an ACK here), we are not receiving */ + if ((cmd_cca_req.ccaInfo.ccaEnergy == CCA_STATE_BUSY) && + (cmd_cca_req.ccaInfo.ccaCorr == CCA_STATE_BUSY) && + (cmd_cca_req.ccaInfo.ccaSync == CCA_STATE_BUSY)) { + PRINTF("receiving_packet: we were TXing ACK\n"); return 0; } - // We are in RX if a CCA sync has been seen, i.e. ccaSync is busy (1) - return (cca_req.ccaInfo.ccaSync == CCA_STATE_BUSY); + /* We are receiving a packet if a CCA sync has been seen, i.e. ccaSync is busy (1) */ + return (cmd_cca_req.ccaInfo.ccaSync == CCA_STATE_BUSY); } /*---------------------------------------------------------------------------*/ static int pending_packet(void) { - const rfc_dataEntry_t *const pStartEntry = (rfc_dataEntry_t *)g_rxDataQueue.pCurrEntry; - volatile const rfc_dataEntry_t *pCurrEntry = pStartEntry; + const data_entry_t *const read_entry = ieee_radio.rx_read_entry; + volatile const data_entry_t *curr_entry = read_entry; - int rv = 0; + int num_pending = 0; - // Check all RX buffers and check their statuses, stopping when looping the circular buffer + /* Go through RX Circular buffer and check their status */ do { - const uint8_t status = pCurrEntry->status; + const uint8_t status = curr_entry->status; if ((status == DATA_ENTRY_FINISHED) || (status == DATA_ENTRY_BUSY)) { - rv += 1; + num_pending += 1; } - pCurrEntry = (rfc_dataEntry_t *)pCurrEntry->pNextEntry; - } while (pCurrEntry != pStartEntry); + /* Stop when we have looped the circular buffer */ + curr_entry = (data_entry_t *)curr_entry->pNextEntry; + } while (curr_entry != read_entry); - if ((rv > 0) && !g_bPollMode) { + if ((num_pending > 0) && !ieee_radio.poll_mode) { process_poll(&rf_process); } - // If we didn't find an entry at status finished or busy, no frames are pending - return rv; + /* If we didn't find an entry at status finished or busy, no frames are pending */ + return num_pending; } /*---------------------------------------------------------------------------*/ static int on(void) { + if (ieee_radio.rf_is_on) { + PRINTF("on: Radio already on\n"); + return CMD_RESULT_OK; + } + + /* Reset all RF command statuses */ + cmd_fs.status = IDLE; + cmd_tx.status = IDLE; + cmd_rx.status = IDLE; + init_rx_buffers(); - const int rv = set_rx(POWER_STATE_ON); + const int rx_ok = set_rx(POWER_STATE_ON); + if (!rx_ok) { + off(); + return CMD_RESULT_ERROR; + } ENERGEST_ON(ENERGEST_TYPE_LISTEN); - return rv; + ieee_radio.rf_is_on = true; + return rx_ok; } /*---------------------------------------------------------------------------*/ static int off(void) { - const uint8_t stopGracefully = 1; - RF_flushCmd(g_rfHandle, RF_CMDHANDLE_FLUSH_ALL, stopGracefully); - RF_yield(g_rfHandle); + if (!ieee_radio.rf_is_on) { + PRINTF("off: Radio already off\n"); + return CMD_RESULT_OK; + } + + /* Force abort of any ongoing RF operation */ + RF_flushCmd(ieee_radio.rf_handle, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY); + /* Trigger a manual power-down */ + RF_yield(ieee_radio.rf_handle); ENERGEST_OFF(ENERGEST_TYPE_LISTEN); - // Reset RX buffers if there was an ongoing RX + /* Reset RX buffers if there was an ongoing RX */ size_t i; for (i = 0; i < RX_BUF_CNT; ++i) { - data_entry_t *entry = &rx_bufs[i].data_entry; + data_entry_t *entry = &ieee_radio.rx_bufs[i].data_entry; if (entry->status == DATA_ENTRY_BUSY) { entry->status = DATA_ENTRY_PENDING; } } + ieee_radio.rf_is_on = false; return CMD_RESULT_OK; } /*---------------------------------------------------------------------------*/ @@ -895,7 +900,7 @@ get_value(radio_param_t param, radio_value_t *value) switch (param) { case RADIO_PARAM_POWER_MODE: - *value = rf_is_on() + *value = (ieee_radio.rf_is_on) ? RADIO_POWER_MODE_ON : RADIO_POWER_MODE_OFF; return RADIO_RESULT_OK; @@ -920,7 +925,7 @@ get_value(radio_param_t param, radio_value_t *value) if (cmd_rx.frameFiltOpt.autoAckEn) { *value |= (radio_value_t)RADIO_RX_MODE_AUTOACK; } - if (g_bPollMode) { + if (ieee_radio.poll_mode) { *value |= (radio_value_t)RADIO_RX_MODE_POLL_MODE; } return RADIO_RESULT_OK; @@ -940,7 +945,7 @@ get_value(radio_param_t param, radio_value_t *value) return RADIO_RESULT_OK; case RADIO_PARAM_RSSI: - *value = RF_getRssi(g_rfHandle); + *value = RF_getRssi(ieee_radio.rf_handle); return (*value == RF_GET_RSSI_ERROR_VAL) ? RADIO_RESULT_ERROR : RADIO_RESULT_OK; @@ -954,19 +959,19 @@ get_value(radio_param_t param, radio_value_t *value) return RADIO_RESULT_OK; case RADIO_CONST_TXPOWER_MIN: - *value = (radio_value_t)(TX_POWER_MIN.power); + *value = (radio_value_t)TX_POWER_MIN; return RADIO_RESULT_OK; case RADIO_CONST_TXPOWER_MAX: - *value = (radio_value_t)(TX_POWER_MAX.power); + *value = (radio_value_t)TX_POWER_MAX; return RADIO_RESULT_OK; case RADIO_PARAM_LAST_RSSI: - *value = (radio_value_t)g_lastRssi; + *value = (radio_value_t)ieee_radio.last.rssi; return RADIO_RESULT_OK; case RADIO_PARAM_LAST_LINK_QUALITY: - *value = (radio_value_t)g_lastCorrLqi; + *value = (radio_value_t)ieee_radio.last.corr_lqi; return RADIO_RESULT_OK; default: @@ -1001,7 +1006,7 @@ set_value(radio_param_t param, radio_value_t value) case RADIO_PARAM_PAN_ID: cmd_rx.localPanID = (uint16_t)value; - if (rf_is_on() && set_rx(POWER_STATE_RESTART) != CMD_RESULT_OK) { + if (ieee_radio.rf_is_on && set_rx(POWER_STATE_RESTART) != CMD_RESULT_OK) { PRINTF("failed to restart RX"); return RADIO_RESULT_ERROR; } @@ -1009,7 +1014,7 @@ set_value(radio_param_t param, radio_value_t value) case RADIO_PARAM_16BIT_ADDR: cmd_rx.localShortAddr = (uint16_t)value; - if (rf_is_on() && set_rx(POWER_STATE_RESTART) != CMD_RESULT_OK) { + if (ieee_radio.rf_is_on && set_rx(POWER_STATE_RESTART) != CMD_RESULT_OK) { PRINTF("failed to restart RX"); return RADIO_RESULT_ERROR; } @@ -1021,29 +1026,29 @@ set_value(radio_param_t param, radio_value_t value) return RADIO_RESULT_INVALID_VALUE; } - cmd_rx.frameFiltOpt.frameFiltEn = (value & RADIO_RX_MODE_ADDRESS_FILTER) != 0; - cmd_rx.frameFiltOpt.frameFiltStop = 1; - cmd_rx.frameFiltOpt.autoAckEn = (value & RADIO_RX_MODE_AUTOACK) != 0; - cmd_rx.frameFiltOpt.slottedAckEn = 0; - cmd_rx.frameFiltOpt.autoPendEn = 0; - cmd_rx.frameFiltOpt.defaultPend = 0; + cmd_rx.frameFiltOpt.frameFiltEn = (value & RADIO_RX_MODE_ADDRESS_FILTER) != 0; + cmd_rx.frameFiltOpt.frameFiltStop = 1; + cmd_rx.frameFiltOpt.autoAckEn = (value & RADIO_RX_MODE_AUTOACK) != 0; + cmd_rx.frameFiltOpt.slottedAckEn = 0; + cmd_rx.frameFiltOpt.autoPendEn = 0; + cmd_rx.frameFiltOpt.defaultPend = 0; cmd_rx.frameFiltOpt.bPendDataReqOnly = 0; - cmd_rx.frameFiltOpt.bPanCoord = 0; + cmd_rx.frameFiltOpt.bPanCoord = 0; cmd_rx.frameFiltOpt.bStrictLenFilter = 0; - const bool bOldPollMode = g_bPollMode; - g_bPollMode = (value & RADIO_RX_MODE_POLL_MODE) != 0; - if (g_bPollMode == bOldPollMode) { - // Do not turn the radio off and on, just send an update command - memcpy(&g_cmdModFilt.newFrameFiltOpt, &(rf_cmd_ieee_rx.frameFiltOpt), sizeof(rf_cmd_ieee_rx.frameFiltOpt)); - const RF_Stat stat = RF_runImmediateCmd(g_rfHandle, (uint32_t*)&g_cmdModFilt); + const bool old_poll_mode = ieee_radio.poll_mode; + ieee_radio.poll_mode = (value & RADIO_RX_MODE_POLL_MODE) != 0; + if (old_poll_mode == ieee_radio.poll_mode) { + /* Do not turn the radio off and on, just send an update command */ + memcpy(&cmd_mod_filt.newFrameFiltOpt, &(rf_cmd_ieee_rx.frameFiltOpt), sizeof(rf_cmd_ieee_rx.frameFiltOpt)); + const RF_Stat stat = RF_runImmediateCmd(ieee_radio.rf_handle, (uint32_t*)&cmd_mod_filt); if (stat != RF_StatCmdDoneSuccess) { PRINTF("setting address filter failed: stat=0x%02X\n", stat); return RADIO_RESULT_ERROR; } return RADIO_RESULT_OK; } - if (rf_is_on() && set_rx(POWER_STATE_RESTART) != CMD_RESULT_OK) { + if (ieee_radio.rf_is_on && set_rx(POWER_STATE_RESTART) != CMD_RESULT_OK) { PRINTF("failed to restart RX"); return RADIO_RESULT_ERROR; } @@ -1058,16 +1063,11 @@ set_value(radio_param_t param, radio_value_t value) return RADIO_RESULT_OK; case RADIO_PARAM_TXPOWER: - if(value < TX_POWER_MIN.power || value > TX_POWER_MAX.power) { - return RADIO_RESULT_INVALID_VALUE; - } - return (set_tx_power(value) != CMD_RESULT_OK) - ? RADIO_RESULT_ERROR - : RADIO_RESULT_OK; + return set_tx_power(value); case RADIO_PARAM_CCA_THRESHOLD: cmd_rx.ccaRssiThr = (int8_t)value; - if (rf_is_on() && set_rx(POWER_STATE_RESTART) != CMD_RESULT_OK) { + if (ieee_radio.rf_is_on && set_rx(POWER_STATE_RESTART) != CMD_RESULT_OK) { PRINTF("failed to restart RX"); return RADIO_RESULT_ERROR; } @@ -1105,7 +1105,7 @@ get_object(radio_param_t param, void *dest, size_t size) return RADIO_RESULT_INVALID_VALUE; } - *(rtimer_clock_t *)dest = g_lastTimestamp; + *(rtimer_clock_t *)dest = ieee_radio.last.timestamp; return RADIO_RESULT_OK; diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c index 0eb08470f..b7d2c58f6 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c @@ -100,21 +100,14 @@ # define PROP_MODE_USE_CRC16 0 #endif /*---------------------------------------------------------------------------*/ -/* Used for the return value of channel_clear */ -#define RF_CCA_CLEAR 1 -#define RF_CCA_BUSY 0 +/* Used for checking result of CCA_REQ command */ +#define CCA_STATE_IDLE 0 +#define CCA_STATE_BUSY 1 +#define CCA_STATE_INVALID 2 /* Used as an error return value for get_cca_info */ #define RF_GET_CCA_INFO_ERROR 0xFF -/* - * Values of the individual bits of the ccaInfo field in CMD_IEEE_CCA_REQ's - * status struct - */ -#define RF_CMD_CCA_REQ_CCA_STATE_IDLE 0 /* 0b00 */ -#define RF_CMD_CCA_REQ_CCA_STATE_BUSY 1 /* 0b01 */ -#define RF_CMD_CCA_REQ_CCA_STATE_INVALID 2 /* 0b10 */ - #ifdef PROP_MODE_CONF_RSSI_THRESHOLD # define PROP_MODE_RSSI_THRESHOLD PROP_MODE_CONF_RSSI_THRESHOLD #else @@ -159,12 +152,12 @@ #endif /*---------------------------------------------------------------------------*/ /* TX power table convenience macros */ -#define TX_POWER_TABLE_SIZE ((sizeof(TX_POWER_TABLE) / sizeof(TX_POWER_TABLE[0])) - 1) +#define TX_POWER_TABLE_SIZE ((sizeof(TX_POWER_TABLE) / sizeof(TX_POWER_TABLE[0])) - 1) -#define TX_POWER_MIN (TX_POWER_TABLE[0].power) -#define TX_POWER_MAX (TX_POWER_TABLE[TX_POWER_TABLE_SIZE - 1].power) +#define TX_POWER_MIN (TX_POWER_TABLE[0].power) +#define TX_POWER_MAX (TX_POWER_TABLE[TX_POWER_TABLE_SIZE - 1].power) -#define TX_POWER_IN_RANGE(dbm) (((dbm) >= TX_POWER_MIN) && ((dbm) <= TX_POWER_MAX)) +#define TX_POWER_IN_RANGE(dbm) ((TX_POWER_MIN <= (dbm)) && ((dbm) <= TX_POWER_MAX)) /*---------------------------------------------------------------------------*/ /* TX buf configuration */ #define TX_BUF_HDR_LEN 2 @@ -181,14 +174,10 @@ #define RX_BUF_SIZE 140 /*---------------------------------------------------------------------------*/ -#define DATA_ENTRY_LENSZ_NONE 0 /* 0 bytes */ -#define DATA_ENTRY_LENSZ_BYTE 1 /* 1 byte */ -#define DATA_ENTRY_LENSZ_WORD 2 /* 2 bytes */ +/* Size of the Length field in Data Entry, two bytes in this case */ +typedef uint16_t lensz_t; -#define DATA_ENTRY_LENSZ DATA_ENTRY_LENSZ_WORD -typedef uint16_t lensz_t; - -#define FRAME_OFFSET DATA_ENTRY_LENSZ +#define FRAME_OFFSET sizeof(lensz_t) #define FRAME_SHAVE 2 /* RSSI (1) + Status (1) */ /*---------------------------------------------------------------------------*/ #define MAC_RADIO_RECEIVER_SENSITIVITY_DBM -110 @@ -199,8 +188,12 @@ typedef uint16_t lensz_t; #define ED_RF_POWER_MIN_DBM (MAC_RADIO_RECEIVER_SENSITIVITY_DBM + MAC_SPEC_ED_MIN_DBM_ABOVE_RECEIVER_SENSITIVITY) #define ED_RF_POWER_MAX_DBM MAC_RADIO_RECEIVER_SATURATION_DBM /*---------------------------------------------------------------------------*/ +/* RF Core typedefs */ +typedef dataQueue_t data_queue_t; typedef rfc_dataEntryGeneral_t data_entry_t; +typedef rfc_propRxOutput_t rx_output_t; +/* Receive buffer entries with room for 1 IEEE 802.15.4 frame in each */ typedef union { data_entry_t data_entry; uint8_t buf[RX_BUF_SIZE]; @@ -209,13 +202,13 @@ typedef union { typedef struct { /* Outgoing frame buffer */ uint8_t tx_buf[TX_BUF_SIZE] CC_ALIGN(4); - /* Incoming frame buffer */ + /* Incoming frame buffers */ rx_buf_t rx_bufs[RX_BUF_CNT]; /* RX Data Queue */ - dataQueue_t rx_data_queue; + data_queue_t rx_data_queue; /* RX Statistics struct */ - rfc_propRxOutput_t rx_stats; + rx_output_t rx_stats; /* Receive entry pointer to keep track of read items */ data_entry_t* rx_read_entry; @@ -300,7 +293,7 @@ stop_rx(void) static cmd_result_t rf_run_setup() { - // TODO not the right way to do this. + /* TODO not the right way to do this. */ RF_runCmd(prop_radio.rf_handle, (RF_Op*)&cmd_radio_setup, RF_PriorityNormal, NULL, 0); if (cmd_radio_setup.status != PROP_DONE_OK) { return CMD_RESULT_ERROR; @@ -352,22 +345,21 @@ get_channel(void) } /*---------------------------------------------------------------------------*/ static cmd_result_t -set_channel(uint8_t channel) +set_channel(uint32_t channel) { - uint32_t new_freq = DOT_15_4G_CHAN0_FREQUENCY + (channel * DOT_15_4G_CHANNEL_SPACING); - - uint16_t freq = (uint16_t)(new_freq / 1000); - uint16_t frac = (new_freq - (freq * 1000)) * 65536 / 1000; + const uint32_t new_freq = DOT_15_4G_CHAN0_FREQUENCY + (channel * DOT_15_4G_CHANNEL_SPACING); + const uint32_t freq = new_freq / 1000; + const uint32_t frac = ((new_freq - (freq * 1000)) * 65536) / 1000; PRINTF("set_channel: %u = 0x%04x.0x%04x (%lu)\n", - channel, freq, frac, new_freq); + (int)channel, (uint16_t)freq, (uint16_t)frac, new_freq); cmd_radio_setup.centerFreq = freq; - cmd_fs.frequency = freq; - cmd_fs.fractFreq = frac; + cmd_fs.frequency = (uint16_t)freq; + cmd_fs.fractFreq = (uint16_t)frac; - // We don't care whether the FS command is successful because subsequent - // TX and RX commands will tell us indirectly. + /* We don't care whether the FS command is successful because subsequent */ + /* TX and RX commands will tell us indirectly. */ RF_EventMask rf_events = RF_runCmd(prop_radio.rf_handle, (RF_Op*)&cmd_fs, RF_PriorityNormal, NULL, 0); if ((rf_events & (RF_EventCmdDone | RF_EventLastCmdDone)) == 0) { @@ -384,6 +376,22 @@ set_channel(uint8_t channel) } /*---------------------------------------------------------------------------*/ /* Returns the current TX power in dBm */ +static radio_result_t +set_tx_power(const radio_value_t dBm) +{ + if (!TX_POWER_IN_RANGE(dBm)) { + return RADIO_RESULT_INVALID_VALUE; + } + + const RF_TxPowerTable_Value value = RF_TxPowerTable_findValue(TX_POWER_TABLE, (int8_t)dBm); + const RF_Stat stat = RF_setTxPower(prop_radio.rf_handle, value); + + return (stat == RF_StatSuccess) + ? RADIO_RESULT_OK + : RADIO_RESULT_ERROR; +} +/*---------------------------------------------------------------------------*/ +/* Returns the current TX power in dBm */ static radio_value_t get_tx_power(void) { @@ -391,24 +399,6 @@ get_tx_power(void) return (radio_value_t)RF_TxPowerTable_findPowerLevel(TX_POWER_TABLE, value); } /*---------------------------------------------------------------------------*/ -/* - * The caller must make sure to send a new CMD_PROP_RADIO_DIV_SETUP to the - * radio after calling this function. - */ -static radio_result_t -set_tx_power(const radio_value_t power) -{ - if (!TX_POWER_IN_RANGE(power)) { - return RADIO_RESULT_INVALID_VALUE; - } - const RF_TxPowerTable_Value value = RF_TxPowerTable_findValue(TX_POWER_TABLE, power); - RF_Stat stat = RF_setTxPower(prop_radio.rf_handle, value); - - return (stat == RF_StatSuccess) - ? RADIO_RESULT_OK - : RADIO_RESULT_ERROR; -} -/*---------------------------------------------------------------------------*/ static uint8_t calculate_lqi(int8_t rssi) { @@ -432,7 +422,7 @@ init_rx_buffers(void) const data_entry_t data_entry = { .status = DATA_ENTRY_PENDING, .config.type = DATA_ENTRY_TYPE_GEN, - .config.lenSz = DATA_ENTRY_LENSZ, + .config.lenSz = sizeof(lensz_t), .length = RX_BUF_SIZE - sizeof(data_entry_t), /* TODO: is this sizeof sound? */ /* Point to fist entry if this is last entry, else point to next entry */ .pNextEntry = (i == (RX_BUF_CNT - 1)) @@ -493,7 +483,7 @@ transmit(unsigned short transmit_len) ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); - // watchdog_periodic(); + /* watchdog_periodic(); */ /* Idle away while the command is running */ RF_EventMask rf_events = RF_pendCmd(prop_radio.rf_handle, tx_handle, RF_EventLastCmdDone); @@ -535,7 +525,7 @@ release_data_entry(void) data_entry_t *const data_entry = prop_radio.rx_read_entry; uint8_t *const frame_ptr = (uint8_t*)&data_entry->data; - // Clear the Length byte(s) and set status to 0: "Pending" + /* Clear the Length byte(s) and set status to 0: "Pending" */ *(lensz_t*)frame_ptr = 0; data_entry->status = DATA_ENTRY_PENDING; prop_radio.rx_read_entry = (data_entry_t*)data_entry->pNextEntry; @@ -547,12 +537,12 @@ read(void *buf, unsigned short buf_len) volatile data_entry_t *data_entry = prop_radio.rx_read_entry; const rtimer_clock_t t0 = RTIMER_NOW(); - // Only wait if the Radio timer is accessing the entry + /* Only wait if the Radio timer is accessing the entry */ while ((data_entry->status == DATA_ENTRY_BUSY) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + TIMEOUT_DATA_ENTRY_BUSY)); if (data_entry->status != DATA_ENTRY_FINISHED) { - // No available data + /* No available data */ return 0; } @@ -612,7 +602,7 @@ channel_clear(void) { if (tx_active()) { PRINTF("channel_clear: called while in TX\n"); - return RF_CCA_CLEAR; + return CCA_STATE_IDLE; } const bool rx_was_off = !rx_active(); @@ -630,10 +620,10 @@ channel_clear(void) } if(rssi >= prop_radio.rssi_threshold) { - return RF_CCA_BUSY; + return CCA_STATE_BUSY; } - return RF_CCA_CLEAR; + return CCA_STATE_IDLE; } /*---------------------------------------------------------------------------*/ static int @@ -643,7 +633,7 @@ receiving_packet(void) return 0; } - if (channel_clear() == RF_CCA_CLEAR) { + if (channel_clear() == CCA_STATE_IDLE) { return 0; } @@ -653,28 +643,29 @@ receiving_packet(void) static int pending_packet(void) { - const rfc_dataEntry_t *const first_entry = (rfc_dataEntry_t *)prop_radio.rx_data_queue.pCurrEntry; - volatile const rfc_dataEntry_t *entry = first_entry; + const data_entry_t *const read_entry = prop_radio.rx_read_entry; + volatile const data_entry_t *curr_entry = read_entry; - int rv = 0; + int num_pending = 0; /* Go through RX Circular buffer and check their status */ do { - const uint8_t status = entry->status; + const uint8_t status = curr_entry->status; if ((status == DATA_ENTRY_FINISHED) || (status == DATA_ENTRY_BUSY)) { - rv += 1; + num_pending += 1; } - entry = (rfc_dataEntry_t *)entry->pNextEntry; - } while (entry != first_entry); + /* Stop when we have looped the circular buffer */ + curr_entry = (data_entry_t *)curr_entry->pNextEntry; + } while (curr_entry != read_entry); - if (rv > 0) { + if (num_pending > 0) { process_poll(&rf_process); } /* If we didn't find an entry at status finished, no frames are pending */ - return rv; + return num_pending; } /*---------------------------------------------------------------------------*/ static int @@ -710,18 +701,12 @@ off(void) return CMD_RESULT_OK; } - // Force abort of any ongoing RF operation. + /* Force abort of any ongoing RF operation */ RF_flushCmd(prop_radio.rf_handle, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY); - - // Trigger a manual power-down + /* Trigger a manual power-down */ RF_yield(prop_radio.rf_handle); - /* We pulled the plug, so we need to restore the status manually */ - cmd_fs.status = IDLE; - cmd_tx.status = IDLE; - cmd_rx.status = IDLE; - - // Reset RX buffers if there was an ongoing RX + /* Reset RX buffers if there was an ongoing RX */ size_t i; for (i = 0; i < RX_BUF_CNT; ++i) { data_entry_t *entry = &prop_radio.rx_bufs[i].data_entry; @@ -795,7 +780,7 @@ set_value(radio_param_t param, radio_value_t value) switch(param) { case RADIO_PARAM_POWER_MODE: if(value == RADIO_POWER_MODE_ON) { - // Powering on happens implicitly + /* Powering on happens implicitly */ return RADIO_RESULT_OK; } if(value == RADIO_POWER_MODE_OFF) { @@ -836,19 +821,19 @@ set_value(radio_param_t param, radio_value_t value) /* If we reach here we had no errors. Apply new settings */ if (rx_active()) { stop_rx(); - // TODO fix this + /* TODO fix this */ if (rf_run_setup() != CMD_RESULT_OK) { return RADIO_RESULT_ERROR; } start_rx(); } else if (tx_active()) { - // Should not happen. TX is always synchronous and blocking. - // Todo: maybe remove completely here. + /* Should not happen. TX is always synchronous and blocking. */ + /* Todo: maybe remove completely here. */ PRINTF("set_value: cannot apply new value while transmitting. \n"); return RADIO_RESULT_ERROR; } else { - // was powered off. Nothing to do. New values will be - // applied automatically on next power-up. + /* was powered off. Nothing to do. New values will be */ + /* applied automatically on next power-up. */ } return RADIO_RESULT_OK; @@ -869,6 +854,11 @@ set_object(radio_param_t param, const void *src, size_t size) static int init(void) { + if (prop_radio.rf_handle) { + PRINTF("init: Radio already initialized\n"); + return CMD_RESULT_OK; + } + /* Zero initalize TX and RX buffers */ memset(prop_radio.tx_buf, 0x0, sizeof(prop_radio.tx_buf)); memset(prop_radio.rx_bufs, 0x0, sizeof(prop_radio.rx_bufs)); @@ -894,12 +884,13 @@ init(void) /* Init RF params and specify non-default params */ RF_Params rf_params; RF_Params_init(&rf_params); - rf_params.nInactivityTimeout = 2000; /* 2 ms */ + rf_params.nInactivityTimeout = 2000; /* 2 ms */ /* Open RF Driver */ prop_radio.rf_handle = RF_open(&prop_radio.rf_object, &rf_prop_mode, (RF_RadioSetup*)&cmd_radio_setup, &rf_params); if (prop_radio.rf_handle == NULL) { + PRINTF("init: unable to open RF driver\n"); return CMD_RESULT_ERROR; } From f3a030b0a4ec4d0e260ceb0d873cfcb854f0911e Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Wed, 20 Jun 2018 13:23:24 +0200 Subject: [PATCH 254/485] Fixed button-sensor for launchpad --- arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 2 +- .../cc13xx-cc26xx/common/button-sensor.h | 14 +++++++---- .../simplelink/cc13xx-cc26xx/contiki-conf.h | 8 ++----- .../launchpad/button-sensor-arch.c | 19 ++++++++------- .../launchpad/button-sensor-arch.h | 6 ++--- .../launchpad/launchpad-sensors.c | 4 ++-- .../simplelink/cc13xx-cc26xx/platform.c | 23 +++++++++++-------- 7 files changed, 42 insertions(+), 34 deletions(-) diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index 9dcc5d91c..a9b36ab17 100644 --- a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -47,7 +47,7 @@ endif # root path. Note that the returned path is encased in angular brackets, <...>, # and is therefore extracted with sed. SDK_DEVICE_DIR := $(shell echo "DeviceFamily_constructPath(dummy)" \ - | arm-none-eabi-gcc -x c -E -DDeviceFamily_$(DEVICE_FAMILY) -include $(DEVICE_FAMILY_H) - \ + | arm-none-eabi-cpp -x c -E -DDeviceFamily_$(DEVICE_FAMILY) -include $(DEVICE_FAMILY_H) - \ | tail -1 \ | sed -E 's:<(.+)/dummy>:\1:') diff --git a/arch/platform/simplelink/cc13xx-cc26xx/common/button-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/common/button-sensor.h index 8756d9b6c..a27a97cf6 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/common/button-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/common/button-sensor.h @@ -45,18 +45,22 @@ #define BUTTON_SENSOR_H_ /*---------------------------------------------------------------------------*/ /* Contiki API */ -#include +#include "lib/sensors.h" /*---------------------------------------------------------------------------*/ /* Board specific button sensors */ #include "button-sensor-arch.h" /*---------------------------------------------------------------------------*/ #define BUTTON_SENSOR "Button" /*---------------------------------------------------------------------------*/ -#define BUTTON_SENSOR_VALUE_STATE 0 -#define BUTTON_SENSOR_VALUE_DURATION 1 +typedef enum { + BUTTON_SENSOR_TYPE_STATE, + BUTTON_SENSOR_TYPE_DURATION +} button_sensor_type_t; -#define BUTTON_SENSOR_VALUE_RELEASED 0 -#define BUTTON_SENSOR_VALUE_PRESSED 1 +typedef enum { + BUTTON_SENSOR_VALUE_RELEASED, + BUTTON_SENSOR_VALUE_PRESSED +} button_sensor_value_t; /*---------------------------------------------------------------------------*/ #endif /* BUTTON_SENSOR_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h b/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h index bd5cbb195..99a424dbd 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h @@ -59,14 +59,10 @@ * Override button symbols from dev/button-sensor.h, for the examples that * include it */ -#define button_left_sensor btn1_sensor -#define button_right_sensor btn2_sensor +#define button_sensor button_left_sensor +#define button_sensor2 button_right_sensor /** @} */ /*---------------------------------------------------------------------------*/ -/* Platform-specific define to signify sensor reading failure */ -/* TODO: remove */ -#define CC26XX_SENSOR_READING_ERROR 0x80000000 -/*---------------------------------------------------------------------------*/ /* Include CPU-related configuration */ #include "cc13xx-cc26xx-conf.h" /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c index 6950b16f1..f9c3300bf 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c @@ -48,7 +48,6 @@ #include /*---------------------------------------------------------------------------*/ #include "button-sensor.h" -#include "button-sensor-arch.h" /*---------------------------------------------------------------------------*/ /* LaunchPad has 2 buttons: BTN1 and BTN2 */ /* Map the GPIO defines from the Board file */ @@ -96,9 +95,9 @@ button_press_cb(PIN_Handle handle, PIN_Id pin_id) switch (pin_id) { case BTN1_PIN: btn_timer = &btn1_timer; - btn_sensor = &btn1_sensor; break; + btn_sensor = &button_left_sensor; break; case BTN2_PIN: btn_timer = &btn2_timer; - btn_sensor = &btn2_sensor; break; + btn_sensor = &button_right_sensor; break; default: return; /* No matching PIN */ } @@ -121,14 +120,18 @@ button_press_cb(PIN_Handle handle, PIN_Id pin_id) static int button_value(int type, uint8_t pin, BtnTimer *btn_timer) { - if (type == BUTTON_SENSOR_VALUE_STATE) { + switch (type) { + case BUTTON_SENSOR_TYPE_STATE: return (PIN_getInputValue(pin) == 0) ? BUTTON_SENSOR_VALUE_PRESSED : BUTTON_SENSOR_VALUE_RELEASED; - } else if (type == BUTTON_SENSOR_VALUE_DURATION) { + + case BUTTON_SENSOR_TYPE_DURATION: return (int)btn_timer->duration; + + default: + return 0; } - return 0; } /*---------------------------------------------------------------------------*/ static int @@ -212,7 +215,7 @@ btn2_status(int type) return button_status(type, BTN2_PIN); } /*---------------------------------------------------------------------------*/ -SENSORS_SENSOR(btn1_sensor, BUTTON_SENSOR, btn1_value, btn1_config, btn1_status); -SENSORS_SENSOR(btn2_sensor, BUTTON_SENSOR, btn2_value, btn2_config, btn2_status); +SENSORS_SENSOR(button_left_sensor, BUTTON_SENSOR, btn1_value, btn1_config, btn1_status); +SENSORS_SENSOR(button_right_sensor, BUTTON_SENSOR, btn2_value, btn2_config, btn2_status); /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.h index ecd04e8b6..9fca110ae 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.h @@ -45,10 +45,10 @@ #define BUTTON_SENSOR_ARCH_H_ /*---------------------------------------------------------------------------*/ /* Contiki API */ -#include +#include "lib/sensors.h" /*---------------------------------------------------------------------------*/ -extern const struct sensors_sensor btn1_sensor; -extern const struct sensors_sensor btn2_sensor; +extern const struct sensors_sensor button_left_sensor; +extern const struct sensors_sensor button_right_sensor; /*---------------------------------------------------------------------------*/ #endif /* BUTTON_SENSOR_ARCH_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/launchpad-sensors.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/launchpad-sensors.c index f2a669037..af783f88a 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/launchpad-sensors.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/launchpad-sensors.c @@ -43,8 +43,8 @@ /*---------------------------------------------------------------------------*/ /* Exports a global symbol to be used by the sensor API */ SENSORS( - &btn1_sensor, - &btn2_sensor, + &button_left_sensor, + &button_right_sensor, NULL ); /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/platform.c b/arch/platform/simplelink/cc13xx-cc26xx/platform.c index 0ced25f26..a7c2e326e 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/platform.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/platform.c @@ -79,7 +79,6 @@ /* Arch driver implementations */ #include "uart0-arch.h" /*---------------------------------------------------------------------------*/ -//#include "gpio-interrupt.h" #include "ieee-addr.h" #include "dev/rf-common.h" #include "lib/random.h" @@ -94,8 +93,11 @@ /*---------------------------------------------------------------------------*/ unsigned short g_nodeId = 0; /*---------------------------------------------------------------------------*/ -/** \brief Board specific initialization */ -void board_init(void); +/* + * Board-specific initialization function. + * This function is defined in the file _fxns.c + */ +extern void Board_initHook(void); /*---------------------------------------------------------------------------*/ static void fade(unsigned char l) @@ -138,17 +140,20 @@ platform_init_stage_one(void) { DRIVERLIB_ASSERT_CURR_RELEASE(); - // TODO: TEMPORARY WHILE DEVELOP. REMOVE - HWREG(CPU_SCS_BASE + CPU_SCS_O_ACTLR) = CPU_SCS_ACTLR_DISDEFWBUF; - // Enable flash cache VIMSModeSet(VIMS_BASE, VIMS_MODE_ENABLED); // Configure round robin arbitration and prefetching VIMSConfigure(VIMS_BASE, true, true); - // Board_initGeneral() will call Power_init() - // Board_initGeneral() will call PIN_init(BoardGpioInitTable) - Board_initGeneral(); + Power_init(); + + if (PIN_init(BoardGpioInitTable) != PIN_SUCCESS) { + /* Error with PIN_init */ + while (1); + } + + /* Perform board-specific initialization */ + Board_initHook(); // Contiki drivers init leds_init(); From d4828c7baf5edbf809cd14b0b3205ebf6dd16e4d Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Fri, 29 Jun 2018 19:03:17 +0200 Subject: [PATCH 255/485] Fixed GPIO HAL issue. --- arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 13 +- .../cc13x0-cc26x0/cc13x0-cc26x0.lds | 4 +- .../cc13x2-cc26x2/cc13x2-cc26x2.lds | 4 +- arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h | 46 +++--- arch/cpu/cc13xx-cc26xx/dev/clock-arch.c | 4 +- .../dev/{putchar-arch.c => dbg-arch.c} | 61 +++----- arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h | 55 +++---- arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c | 135 ++++++++++++++++++ .../dev/{debug-uart.h => gpio-hal-arch.h} | 52 +++++-- .../dev/{dbg.h => int-master-arch.c} | 53 ++++--- arch/cpu/cc13xx-cc26xx/dev/rf-common.h | 2 + arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c | 2 - arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h | 1 + .../cc13xx-cc26xx/launchpad/cc1352r1/Board.h | 10 +- .../cc13xx-cc26xx/launchpad/leds-arch.c | 59 +------- .../simplelink/cc13xx-cc26xx/platform.c | 27 ++-- os/dev/button-hal.c | 5 +- os/dev/gpio-hal.c | 1 + os/dev/gpio-hal.h | 44 ++++-- os/sys/timer.c | 4 +- 20 files changed, 362 insertions(+), 220 deletions(-) rename arch/cpu/cc13xx-cc26xx/dev/{putchar-arch.c => dbg-arch.c} (77%) create mode 100644 arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c rename arch/cpu/cc13xx-cc26xx/dev/{debug-uart.h => gpio-hal-arch.h} (57%) rename arch/cpu/cc13xx-cc26xx/dev/{dbg.h => int-master-arch.c} (67%) diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index a9b36ab17..35e88181a 100644 --- a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -68,12 +68,15 @@ EXTERNALDIRS += $(SDK_DEVICE)/startup_files ### CPU-dependent source files CONTIKI_CPU_SOURCEFILES += rtimer-arch.c clock-arch.c -CONTIKI_CPU_SOURCEFILES += watchdog-arch.c putchar-arch.c +CONTIKI_CPU_SOURCEFILES += watchdog-arch.c dbg-arch.c CONTIKI_CPU_SOURCEFILES += uart0-arch.c slip-arch.c -CONTIKI_CPU_SOURCEFILES += batmon-sensor.c -CONTIKI_CPU_SOURCEFILES += rf-common.c +CONTIKI_CPU_SOURCEFILES += batmon-sensor.c gpio-hal-arch.c +CONTIKI_CPU_SOURCEFILES += rf-common.c int-master-arch.c CONTIKI_CPU_SOURCEFILES += ieee-addr.c +### CPU-dependent debug source files +MODULES += os/lib/dbg-io + ifeq ($(SUPPORTS_PROP_MODE),1) CONTIKI_CPU_SOURCEFILES += rf-prop-mode.c prop-settings.c endif @@ -85,10 +88,6 @@ endif ### CPU-dependent directories CONTIKI_CPU_DIRS += . dev $(SUBFAMILY) rf-settings/$(DEVICE_FAMILY_LC) -### CPU-dependent debug source files -### CONTIKI_ARM_DIRS populated by Makefile.arm -DEBUG_IO_SOURCEFILES += dbg-printf.c dbg-snprintf.c dbg-sprintf.c strformat.c - CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES) $(DEBUG_IO_SOURCEFILES) ### Linker flag diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds index 0e8e66510..dd4732580 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds +++ b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds @@ -34,8 +34,8 @@ * Default Linker script for the Texas Instruments CC1310 */ -MIN_STACKSIZE = 0x600; -HEAPSIZE = 256; +MIN_STACKSIZE = 0x800; /* 2048 bytes */ +HEAPSIZE = 0x100; /* 256 bytes */ MEMORY { diff --git a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds index 9da90ebcd..cdfb619b2 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds +++ b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds @@ -34,8 +34,8 @@ * Default Linker script for the Texas Instruments CC1352 */ -MIN_STACKSIZE = 0x600; -HEAPSIZE = 256; /* Size of heap buffer used by HeapMem */ +MIN_STACKSIZE = 0x800; /* 2048 bytes */ +HEAPSIZE = 0x100; /* 256 bytes */ MEMORY { diff --git a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h index f86ceb521..fc5243b51 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h +++ b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h @@ -42,6 +42,10 @@ /*---------------------------------------------------------------------------*/ #include "cc13xx-cc26xx-def.h" /*---------------------------------------------------------------------------*/ + +#define GPIO_HAL_CONF_ARCH_SW_TOGGLE 0 +#define GPIO_HAL_CONF_ARCH_HDR_PATH "dev/gpio-hal-arch.h" + /** * \name Network Stack Configuration * @@ -56,10 +60,27 @@ #define CC2650_FAST_RADIO_STARTUP (MAC_CONF_WITH_TSCH) #endif -#ifdef RF_CORE_CONF_CHANNEL -#define RF_CHANNEL RF_CORE_CONF_CHANNEL +#define RF_CORE_MODE_SUB_1_GHZ (1 << 0) +#define RF_CORE_MODE_2_4_GHZ (1 << 1) + +#define RF_CORE_MODE_MASK ( RF_CORE_MODE_SUB_1_GHZ \ + | RF_CORE_MODE_2_4_GHZ \ + ) + +/* Default RF mode is 2.4 GHz */ +#ifdef RF_CORE_CONF_MODE +# if !(RF_CORE_CONF_MODE & RF_CORE_MODE_MASK) +# error "Invalid RF_CORE_CONF_MODE" +# endif +# define RF_CORE_MODE RF_CORE_CONF_MODE #else -#define RF_CHANNEL 25 +# define RF_CORE_MODE RF_CORE_MODE_2_4_GHZ +#endif + +#ifdef RF_CORE_CONF_CHANNEL +# define RF_CHANNEL RF_CORE_CONF_CHANNEL +#else +# define RF_CHANNEL 25 #endif /* Number of Prop Mode RX buffers */ @@ -69,22 +90,11 @@ /* Configure Radio mode, i.e. prop or ieee */ - /*----- CC13xx Device Line --------------------------------------------------*/ /* CC13xx supports both IEEE and Prop mode, depending on which device */ #if defined(DEVICE_LINE_CC13XX) -/* Default mode should be prop for prop-only devices (CC1310, CC1312R); - * Else, IEEE mode is default. */ -# ifndef CC13XX_CONF_PROP_MODE -# if (SUPPORTS_IEEE_MODE == 0) -# define CC13XX_CONF_PROP_MODE 1 -# else -# define CC13XX_CONF_PROP_MODE 0 -# endif -# endif - -# if (CC13XX_CONF_PROP_MODE == 1) && (SUPPORTS_PROP_MODE == 1) +# if (RF_CORE_MODE == RF_CORE_MODE_SUB_1_GHZ) && (SUPPORTS_PROP_MODE) /*----- CC13xx Prop Mode ----------------------------------------------------*/ # define NETSTACK_CONF_RADIO prop_mode_driver @@ -92,7 +102,7 @@ # define CSMA_CONF_AFTER_ACK_DETECTED_WAIT_TIME (RTIMER_SECOND / 1000) # define CSMA_CONF_SEND_SOFT_ACK 1 -# elif (CC13XX_CONF_PROP_MODE == 0) && (SUPPORTS_IEEE_MODE == 1) +# elif (RF_CORE_MODE == RF_CORE_MODE_2_4_GHZ) && (SUPPORTS_IEEE_MODE) /*----- CC13xx IEEE Mode ----------------------------------------------------*/ # define NETSTACK_CONF_RADIO ieee_mode_driver @@ -101,13 +111,13 @@ # else /*----- CC13xx Non-supported Mode -------------------------------------------*/ # error "Invalid radio mode configuration of CC13xx device" -# endif /* (CC13XX_CONF_PROP_MODE == 1) && (SUPPORTS_PROP_MODE == 1) */ +# endif /* (RF_CORE_IS_SUB_1_GHZ == 1) && (SUPPORTS_PROP_MODE == 1) */ /*----- CC26xx Device Line --------------------------------------------------*/ /* CC26xx only supports IEEE mode */ #elif defined(DEVICE_LINE_CC26XX) -# if (SUPPORTS_IEEE_MODE == 1) +# if (SUPPORTS_IEEE_MODE) /*----- CC26xx IEEE Mode ----------------------------------------------------*/ # define NETSTACK_CONF_RADIO ieee_mode_driver diff --git a/arch/cpu/cc13xx-cc26xx/dev/clock-arch.c b/arch/cpu/cc13xx-cc26xx/dev/clock-arch.c index 784530de9..e39d54f4c 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/clock-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/clock-arch.c @@ -73,7 +73,7 @@ clock_init(void) ClockP_construct(&etimerClock, (ClockP_Fxn)&clock_update, CLOCK_TICKS_SECOND, ¶ms); } /*---------------------------------------------------------------------------*/ -CCIF clock_time_t +clock_time_t clock_time(void) { uint64_t count_read; @@ -100,7 +100,7 @@ clock_update(void) } } /*---------------------------------------------------------------------------*/ -CCIF unsigned long +unsigned long clock_seconds(void) { uint64_t count_read; diff --git a/arch/cpu/cc13xx-cc26xx/dev/putchar-arch.c b/arch/cpu/cc13xx-cc26xx/dev/dbg-arch.c similarity index 77% rename from arch/cpu/cc13xx-cc26xx/dev/putchar-arch.c rename to arch/cpu/cc13xx-cc26xx/dev/dbg-arch.c index d5dd4ac49..a12a877ed 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/putchar-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/dbg-arch.c @@ -28,60 +28,39 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /*---------------------------------------------------------------------------*/ +#include "sys/cc.h" +/*---------------------------------------------------------------------------*/ #include +#include #include - +/*---------------------------------------------------------------------------*/ #include "uart0-arch.h" - - -#undef putchar -#undef puts /*---------------------------------------------------------------------------*/ int -putchar(int c) +dbg_putchar(int c) { const unsigned char ch = (unsigned char)c; - return (uart0_write(&ch, 1) == 1) - ? (int)ch - : EOF; -} -/*---------------------------------------------------------------------------*/ -int -puts(const char *str) -{ - if(!str) - { - return EOF; - } - const size_t len = strlen(str); - const unsigned char newline = '\n'; - - if ((uart0_write(str, len) != len) && - (uart0_write(&newline, 1) != 1)) - { - return EOF; - } - - return len + 1; + const int num_bytes = (int)uart0_write(&ch, 1); + return (num_bytes > 0) + ? num_bytes + : 0; } /*---------------------------------------------------------------------------*/ unsigned int -dbg_send_bytes(const unsigned char *s, unsigned int len) +dbg_send_bytes(const unsigned char *seq, unsigned int len) { - if(!s || strlen((const char *)s) < len) - { - return EOF; + const size_t seq_len = strlen((const char *)seq); + + const size_t max_len = MIN(seq_len, (size_t)len); + + if (max_len == 0) { + return 0; } - const unsigned char newline = '\n'; - - if ((uart0_write(s, len) != len) && - (uart0_write(&newline, 1) != 1)) - { - return EOF; - } - - return len + 1; + const int num_bytes = (int)uart0_write(seq, max_len); + return (num_bytes > 0) + ? num_bytes + : 0; } /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h b/arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h index 7282ac9ba..9e9ae696d 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h +++ b/arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h @@ -79,45 +79,46 @@ * DOT_15_4G_CHAN0_FREQUENCY is specified here in KHz */ #if DOT_15_4G_FREQUENCY_BAND_ID==DOT_15_4G_FREQUENCY_BAND_470 -#define DOT_15_4G_CHANNEL_MAX 198 -#define DOT_15_4G_CHANNEL_SPACING 200 -#define DOT_15_4G_CHAN0_FREQUENCY 470200 -#define PROP_MODE_CONF_LO_DIVIDER 0x0A -#define SMARTRF_SETTINGS_CONF_BAND_OVERRIDES HW32_ARRAY_OVERRIDE(0x405C,1), \ - (uint32_t)0x18000280, +# define DOT_15_4G_CHANNEL_MAX 198 +# define DOT_15_4G_CHANNEL_SPACING 200 +# define DOT_15_4G_CHAN0_FREQUENCY 470200 +# define PROP_MODE_CONF_LO_DIVIDER 0x0A +# define SMARTRF_SETTINGS_CONF_BAND_OVERRIDES \ + HW32_ARRAY_OVERRIDE(0x405C,1), \ + (uint32_t)0x18000280, #elif DOT_15_4G_FREQUENCY_BAND_ID==DOT_15_4G_FREQUENCY_BAND_780 -#define DOT_15_4G_CHANNEL_MAX 38 -#define DOT_15_4G_CHANNEL_SPACING 200 -#define DOT_15_4G_CHAN0_FREQUENCY 779200 -#define PROP_MODE_CONF_LO_DIVIDER 0x06 +# define DOT_15_4G_CHANNEL_MAX 38 +# define DOT_15_4G_CHANNEL_SPACING 200 +# define DOT_15_4G_CHAN0_FREQUENCY 779200 +# define PROP_MODE_CONF_LO_DIVIDER 0x06 #elif DOT_15_4G_FREQUENCY_BAND_ID==DOT_15_4G_FREQUENCY_BAND_863 -#define DOT_15_4G_CHANNEL_MAX 33 -#define DOT_15_4G_CHANNEL_SPACING 200 -#define DOT_15_4G_CHAN0_FREQUENCY 863125 -#define PROP_MODE_CONF_LO_DIVIDER 0x05 +# define DOT_15_4G_CHANNEL_MAX 33 +# define DOT_15_4G_CHANNEL_SPACING 200 +# define DOT_15_4G_CHAN0_FREQUENCY 863125 +# define PROP_MODE_CONF_LO_DIVIDER 0x05 #elif DOT_15_4G_FREQUENCY_BAND_ID==DOT_15_4G_FREQUENCY_BAND_915 -#define DOT_15_4G_CHANNEL_MAX 128 -#define DOT_15_4G_CHANNEL_SPACING 200 -#define DOT_15_4G_CHAN0_FREQUENCY 902200 -#define PROP_MODE_CONF_LO_DIVIDER 0x05 +# define DOT_15_4G_CHANNEL_MAX 128 +# define DOT_15_4G_CHANNEL_SPACING 200 +# define DOT_15_4G_CHAN0_FREQUENCY 902200 +# define PROP_MODE_CONF_LO_DIVIDER 0x05 #elif DOT_15_4G_FREQUENCY_BAND_ID==DOT_15_4G_FREQUENCY_BAND_920 -#define DOT_15_4G_CHANNEL_MAX 37 -#define DOT_15_4G_CHANNEL_SPACING 200 -#define DOT_15_4G_CHAN0_FREQUENCY 920600 -#define PROP_MODE_CONF_LO_DIVIDER 0x05 +# define DOT_15_4G_CHANNEL_MAX 37 +# define DOT_15_4G_CHANNEL_SPACING 200 +# define DOT_15_4G_CHAN0_FREQUENCY 920600 +# define PROP_MODE_CONF_LO_DIVIDER 0x05 #elif DOT_15_4G_FREQUENCY_BAND_ID==DOT_15_4G_FREQUENCY_BAND_950 -#define DOT_15_4G_CHANNEL_MAX 32 -#define DOT_15_4G_CHANNEL_SPACING 200 -#define DOT_15_4G_CHAN0_FREQUENCY 951000 -#define PROP_MODE_CONF_LO_DIVIDER 0x05 +# define DOT_15_4G_CHANNEL_MAX 32 +# define DOT_15_4G_CHANNEL_SPACING 200 +# define DOT_15_4G_CHAN0_FREQUENCY 951000 +# define PROP_MODE_CONF_LO_DIVIDER 0x05 #else -#error The selected frequency band is not supported +# error The selected IEEE 802.15.4g frequency band is not supported #endif /*---------------------------------------------------------------------------*/ #endif /* DOT_15_4G_H_ */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c b/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c new file mode 100644 index 000000000..b34200d68 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2017, 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup cc26xx-gpio-hal + * @{ + * + * \file + * Implementation file for the CC13xx/CC26xx GPIO HAL functions + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "dev/gpio-hal.h" + +#include +#include DeviceFamily_constructPath(driverlib/gpio.h) +#include DeviceFamily_constructPath(driverlib/ioc.h) + +#include +/*---------------------------------------------------------------------------*/ +#define CONFIG_MASK (IOC_IOPULL_M | IOC_INT_M | IOC_IOMODE_OPEN_SRC_INV) +/*---------------------------------------------------------------------------*/ +void +gpio_hal_arch_interrupt_enable(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg) +{ + GPIO_clearEventDio(pin); + gpio_hal_arch_pin_cfg_set(pin, cfg); + IOCIntEnable(pin); +} +/*---------------------------------------------------------------------------*/ +void +gpio_hal_arch_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg) +{ + /* Clear settings that we are about to change, keep everything else */ + uint32_t config = IOCPortConfigureGet(pin); + config &= ~CONFIG_MASK; + + switch (cfg & GPIO_HAL_PIN_CFG_INT_MASK) { + case GPIO_HAL_PIN_CFG_INT_DISABLE: config |= (IOC_NO_EDGE | IOC_INT_DISABLE); break; + case GPIO_HAL_PIN_CFG_INT_FALLING: config |= (IOC_FALLING_EDGE | IOC_INT_ENABLE); break; + case GPIO_HAL_PIN_CFG_INT_RISING: config |= (IOC_RISING_EDGE | IOC_INT_ENABLE); break; + case GPIO_HAL_PIN_CFG_INT_BOTH: config |= (IOC_BOTH_EDGES | IOC_INT_ENABLE); break; + default: {} + } + + switch (cfg & GPIO_HAL_PIN_CFG_PULL_MASK) { + case GPIO_HAL_PIN_CFG_PULL_NONE: config |= IOC_NO_IOPULL; break; + case GPIO_HAL_PIN_CFG_PULL_DOWN: config |= IOC_IOPULL_DOWN; break; + case GPIO_HAL_PIN_CFG_PULL_UP: config |= IOC_IOPULL_UP; break; + default: {} + } + + IOCPortConfigureSet(pin, IOC_PORT_GPIO, config); +} +/*---------------------------------------------------------------------------*/ +gpio_hal_pin_cfg_t +gpio_hal_arch_pin_cfg_get(gpio_hal_pin_t pin) +{ + gpio_hal_pin_cfg_t cfg = 0; + uint32_t config = IOCPortConfigureGet(pin); + + switch (config & IOC_IOPULL_M) { + case IOC_IOPULL_UP: cfg |= GPIO_HAL_PIN_CFG_PULL_UP; break; + case IOC_IOPULL_DOWN: cfg |= GPIO_HAL_PIN_CFG_PULL_DOWN; break; + case IOC_NO_IOPULL: cfg |= GPIO_HAL_PIN_CFG_PULL_NONE; break; + default: {} + } + + /* Interrupt enable/disable */ + uint32_t tmp = config & IOC_INT_M; + if (tmp & IOC_INT_ENABLE) { + switch (tmp) { + case IOC_FALLING_EDGE: cfg |= GPIO_HAL_PIN_CFG_INT_FALLING; break; + case IOC_RISING_EDGE: cfg |= GPIO_HAL_PIN_CFG_INT_RISING; break; + case IOC_BOTH_EDGES: cfg |= GPIO_HAL_PIN_CFG_INT_BOTH; break; + default: {} + } + } else { + cfg |= GPIO_HAL_PIN_CFG_INT_DISABLE; + } + + return cfg; +} +/*---------------------------------------------------------------------------*/ +gpio_hal_pin_mask_t +gpio_hal_arch_read_pins(gpio_hal_pin_mask_t pins) +{ + /* For pins configured as output we need to read DOUT31_0 */ + gpio_hal_pin_mask_t oe_pins = GPIO_getOutputEnableMultiDio(pins); + + pins &= ~oe_pins; + + return (HWREG(GPIO_BASE + GPIO_O_DOUT31_0) & oe_pins) | + GPIO_readMultiDio(pins); +} +/*---------------------------------------------------------------------------*/ +uint8_t +gpio_hal_arch_read_pin(gpio_hal_pin_t pin) +{ + if (GPIO_getOutputEnableDio(pin)) { + return (HWREG(GPIO_BASE + GPIO_O_DOUT31_0) >> pin) & 1; + } + + return GPIO_readDio(pin); +} +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/debug-uart.h b/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.h similarity index 57% rename from arch/cpu/cc13xx-cc26xx/dev/debug-uart.h rename to arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.h index c2d9b0ffb..6fd5a520c 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/debug-uart.h +++ b/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.h @@ -1,16 +1,16 @@ /* - * Copyright (c) 2012, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2017, 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. @@ -30,20 +30,50 @@ */ /*---------------------------------------------------------------------------*/ /** - * \addtogroup cc26xx-char-io + * \addtogroup cc26xx + * @{ + * + * \defgroup cc26xx-gpio-hal CC13xx/CC26xx GPIO HAL implementation + * * @{ * * \file - * This file is here because DBG I/O expects it to be. It just includes - * our own dbg.h which has a non-misleading name and which also adheres - * to Contiki's naming convention + * Header file for the CC13xx/CC26xx GPIO HAL functions + * + * \note + * Do not include this header directly */ /*---------------------------------------------------------------------------*/ -#ifndef DEBUG_UART_H_ -#define DEBUG_UART_H_ +#ifndef GPIO_HAL_ARCH_H_ +#define GPIO_HAL_ARCH_H_ /*---------------------------------------------------------------------------*/ -#include "dbg.h" +#include "contiki.h" + +#include +#include DeviceFamily_constructPath(driverlib/gpio.h) +#include DeviceFamily_constructPath(driverlib/ioc.h) + +#include /*---------------------------------------------------------------------------*/ -#endif /* DEBUG_UART_H_ */ +#define gpio_hal_arch_init() do { /* do nothing */ } while (0) +#define gpio_hal_arch_interrupt_disable(p) IOCIntDisable(p) + +#define gpio_hal_arch_pin_set_input(p) IOCPinTypeGpioInput(p) +#define gpio_hal_arch_pin_set_output(p) IOCPinTypeGpioOutput(p) + +#define gpio_hal_arch_set_pin(p) GPIO_setDio(p) +#define gpio_hal_arch_clear_pin(p) GPIO_clearDio(p) +#define gpio_hal_arch_toggle_pin(p) GPIO_toggleDio(p) +#define gpio_hal_arch_write_pin(p, v) GPIO_writeDio(p, v) + +#define gpio_hal_arch_set_pins(p) GPIO_setMultiDio(p) +#define gpio_hal_arch_clear_pins(p) GPIO_clearMultiDio(p) +#define gpio_hal_arch_toggle_pins(p) GPIO_toggleMultiDio(p) +#define gpio_hal_arch_write_pins(p, v) GPIO_writeMultiDio(p, v) /*---------------------------------------------------------------------------*/ -/** @} */ +#endif /* GPIO_HAL_ARCH_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/dbg.h b/arch/cpu/cc13xx-cc26xx/dev/int-master-arch.c similarity index 67% rename from arch/cpu/cc13xx-cc26xx/dev/dbg.h rename to arch/cpu/cc13xx-cc26xx/dev/int-master-arch.c index 4460b6eb4..c06cc364f 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/dbg.h +++ b/arch/cpu/cc13xx-cc26xx/dev/int-master-arch.c @@ -1,10 +1,11 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2017, 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 @@ -32,32 +33,48 @@ * \addtogroup cc26xx * @{ * - * \defgroup cc26xx-char-io CC13xx/CC26xx Character I/O + * \defgroup cc26xx-interrupts CC13xx-CC26xx master interrupt manipulation + * + * Master interrupt manipulation routines for the CC13xx and CC26xx CPUs * - * CC13xx/CC26xx CPU-specific functions for debugging and SLIP I/O * @{ * * \file - * Header file for the CC13xx/CC26xx Debug I/O module + * Master interrupt manipulation implementation for the TI CC13xx/CC26xx */ -#ifndef DBG_H_ -#define DBG_H_ /*---------------------------------------------------------------------------*/ #include "contiki.h" + +#include "sys/int-master.h" /*---------------------------------------------------------------------------*/ -/** - * \brief Print a stream of bytes - * \param seq A pointer to the stream - * \param len The number of bytes to print - * \return The number of printed bytes - * - * This function is an arch-specific implementation required by the dbg-io - * API in cpu/arm/common/dbg-io. It prints a stream of bytes over the - * peripheral used by the platform. - */ -unsigned int dbg_send_bytes(const unsigned char *seq, unsigned int len); +#include +#include DeviceFamily_constructPath(driverlib/cpu.h) + +#include /*---------------------------------------------------------------------------*/ -#endif /* DBG_H_ */ +void +int_master_enable(void) +{ + HwiP_enable(); +} +/*---------------------------------------------------------------------------*/ +int_master_status_t +int_master_read_and_disable(void) +{ + return HwiP_disable(); +} +/*---------------------------------------------------------------------------*/ +void +int_master_status_set(int_master_status_t status) +{ + HwiP_restore(status); +} +/*---------------------------------------------------------------------------*/ +bool +int_master_is_enabled(void) +{ + return CPUprimask() ? false : true; +} /*---------------------------------------------------------------------------*/ /** * @} diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-common.h b/arch/cpu/cc13xx-cc26xx/dev/rf-common.h index 9c3f244b9..f67466613 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-common.h +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-common.h @@ -43,6 +43,8 @@ #ifndef RF_COMMON_H_ #define RF_COMMON_H_ /*---------------------------------------------------------------------------*/ +#include "contiki.h" +/*---------------------------------------------------------------------------*/ typedef enum { CMD_RESULT_ERROR = 0, CMD_RESULT_OK = 1, diff --git a/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c b/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c index 00390a3e5..f2b22b54d 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c @@ -44,7 +44,6 @@ /*---------------------------------------------------------------------------*/ #include #include -#include /*---------------------------------------------------------------------------*/ #include "uart0-arch.h" /*---------------------------------------------------------------------------*/ @@ -91,7 +90,6 @@ uart0_init(void) params.readReturnMode = UART_RETURN_NEWLINE; gh_uart = UART_open(Board_UART0, ¶ms); - assert(gh_uart != NULL); } /*---------------------------------------------------------------------------*/ int_fast32_t diff --git a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h index 7d87670c5..2e83336d9 100644 --- a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h +++ b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h @@ -53,6 +53,7 @@ #include /*---------------------------------------------------------------------------*/ +#define gpio_hal_arch_init() do { /* do nothing */ } while (0) #define gpio_hal_arch_interrupt_enable(p) interrupt_enable(p) #define gpio_hal_arch_interrupt_disable(p) ti_lib_rom_ioc_int_disable(p) diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h index 2c46e0b7c..148f96146 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h @@ -52,12 +52,12 @@ extern "C" { * Those values are not meant to be modified by the user * @{ */ -#define LEDS_RED (1 << 0) -#define LEDS_GREEN (1 << 1) -#define LEDS_YELLOW LEDS_GREEN -#define LEDS_ORANGE LEDS_RED +#define LEDS_CONF_COUNT 2 -#define LEDS_CONF_ALL (LEDS_RED | LEDS_GREEN) +#define LEDS_CONF_RED 0 +#define LEDS_CONF_GREEN 1 + +#define LEDS_CONF_ALL ((1 << LEDS_CONF_COUNT) - 1) /*---------------------------------------------------------------------------*/ /* These #defines allow us to reuse TI-RTOS across other device families */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/leds-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/leds-arch.c index 463349854..97c912a84 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/leds-arch.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/leds-arch.c @@ -37,66 +37,17 @@ */ /*---------------------------------------------------------------------------*/ /* Contiki API */ -#include -#include +#include "contiki.h" +#include "dev/leds.h" /*---------------------------------------------------------------------------*/ -/* Simplelink SDK API */ #include - -#include /*---------------------------------------------------------------------------*/ /* Standard library */ #include -#include /*---------------------------------------------------------------------------*/ -static const PIN_Config pin_table[] = { - Board_PIN_LED0 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, - Board_PIN_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, - PIN_TERMINATE +const leds_t leds_arch_leds[] = { + { .pin = Board_PIN_LED0, .negative_logic = false }, + { .pin = Board_PIN_LED1, .negative_logic = false }, }; - -static PIN_State pin_state; -static PIN_Handle pin_handle; - -static volatile unsigned char c; -/*---------------------------------------------------------------------------*/ -void -leds_arch_init(void) -{ - static bool bHasInit = false; - if(bHasInit) { - return; - } - - // PIN_init() called from Board_initGeneral() - pin_handle = PIN_open(&pin_state, pin_table); - if (!pin_handle) { - return; - } - - bHasInit = true; -} -/*---------------------------------------------------------------------------*/ -unsigned char -leds_arch_get(void) -{ - return c; -} -/*---------------------------------------------------------------------------*/ -void -leds_arch_set(unsigned char leds) -{ - c = leds; - - PIN_setPortOutputValue(pin_handle, 0); - - if (leds & LEDS_RED) { - PIN_setOutputValue(pin_handle, Board_PIN_LED0, 1); - } - - if (leds & LEDS_GREEN) { - PIN_setOutputValue(pin_handle, Board_PIN_LED1, 1); - } -} /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/platform.c b/arch/platform/simplelink/cc13xx-cc26xx/platform.c index a7c2e326e..a773d3ff0 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/platform.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/platform.c @@ -71,6 +71,7 @@ #include "sys/rtimer.h" #include "sys/node-id.h" #include "sys/platform.h" +#include "dev/gpio-hal.h" #include "dev/serial-line.h" #include "dev/leds.h" #include "net/mac/framer/frame802154.h" @@ -85,6 +86,7 @@ #include "button-sensor.h" /*---------------------------------------------------------------------------*/ #include +#include /*---------------------------------------------------------------------------*/ /* Log configuration */ #include "sys/log.h" @@ -107,13 +109,9 @@ fade(unsigned char l) int j = k > 400 ? 800 - k : k; leds_on(l); - for(i = 0; i < j; ++i) { - __asm("nop"); - } + for(i = 0; i < j; ++i) { __asm("nop"); } leds_off(l); - for(i = 0; i < 400 - j; ++i) { - __asm("nop"); - } + for(i = 0; i < 400 - j; ++i) { __asm("nop"); } } } /*---------------------------------------------------------------------------*/ @@ -121,6 +119,7 @@ static void set_rf_params(void) { uint8_t ext_addr[8]; + memset(ext_addr, 0x0, sizeof(ext_addr)); ieee_addr_cpy_to(ext_addr, sizeof(ext_addr)); @@ -140,9 +139,9 @@ platform_init_stage_one(void) { DRIVERLIB_ASSERT_CURR_RELEASE(); - // Enable flash cache + /* Enable flash cache */ VIMSModeSet(VIMS_BASE, VIMS_MODE_ENABLED); - // Configure round robin arbitration and prefetching + /* Configure round robin arbitration and prefetching */ VIMSConfigure(VIMS_BASE, true, true); Power_init(); @@ -155,19 +154,20 @@ platform_init_stage_one(void) /* Perform board-specific initialization */ Board_initHook(); - // Contiki drivers init + /* Contiki drivers init */ + gpio_hal_init(); leds_init(); fade(LEDS_RED); - // TI Drivers init + /* TI Drivers init */ I2C_init(); SPI_init(); UART_init(); fade(LEDS_GREEN); - // NoRTOS should be called last + /* NoRTOS should be called last */ NoRTOS_start(); } /*---------------------------------------------------------------------------*/ @@ -205,6 +205,9 @@ platform_init_stage_three(void) ChipInfo_SupportsIEEE_802_15_4() ? "Yes" : "No", ChipInfo_SupportsPROPRIETARY() ? "Yes" : "No", ChipInfo_SupportsBLE() ? "Yes" : "No"); + + LOG_INFO("Operating frequency on %s\n", + (RF_CORE_MODE == RF_CORE_MODE_SUB_1_GHZ) ? "Sub-1 GHz" : "2.4 GHz"); LOG_INFO("RF: Channel %d, PANID 0x%04X\n", chan, pan); LOG_INFO("Node ID: %d\n", g_nodeId); @@ -216,7 +219,7 @@ platform_init_stage_three(void) void platform_idle(void) { - // Drop to some low power mode + /* Drop to some low power mode */ Power_idleFunc(); } /*---------------------------------------------------------------------------*/ diff --git a/os/dev/button-hal.c b/os/dev/button-hal.c index 58cded790..a1255e7f7 100644 --- a/os/dev/button-hal.c +++ b/os/dev/button-hal.c @@ -178,11 +178,10 @@ button_hal_init() button_event_handler.handler = press_release_handler; for(button = button_hal_buttons; *button != NULL; button++) { - cfg = GPIO_HAL_PIN_CFG_EDGE_BOTH | GPIO_HAL_PIN_CFG_INT_ENABLE | - (*button)->pull; + cfg = (*button)->pull; gpio_hal_arch_pin_set_input((*button)->pin); gpio_hal_arch_pin_cfg_set((*button)->pin, cfg); - gpio_hal_arch_interrupt_enable((*button)->pin); + gpio_hal_arch_interrupt_enable((*button)->pin, GPIO_HAL_PIN_CFG_INT_BOTH); button_event_handler.pin_mask |= gpio_hal_pin_to_mask((*button)->pin); } diff --git a/os/dev/gpio-hal.c b/os/dev/gpio-hal.c index 658152293..949d829a7 100644 --- a/os/dev/gpio-hal.c +++ b/os/dev/gpio-hal.c @@ -75,6 +75,7 @@ void gpio_hal_init() { list_init(handlers); + gpio_hal_arch_init(); } /*---------------------------------------------------------------------------*/ #if GPIO_HAL_ARCH_SW_TOGGLE diff --git a/os/dev/gpio-hal.h b/os/dev/gpio-hal.h index b6af7bf74..1ca1c141c 100644 --- a/os/dev/gpio-hal.h +++ b/os/dev/gpio-hal.h @@ -82,7 +82,7 @@ typedef uint8_t gpio_hal_pin_t; * A logical representation of a pin's configuration. It is an OR combination * of GPIO_HAL_PIN_CFG_xyz macros. */ -typedef uint8_t gpio_hal_pin_cfg_t; +typedef uint32_t gpio_hal_pin_cfg_t; #ifdef GPIO_HAL_CONF_PIN_COUNT #define GPIO_HAL_PIN_COUNT GPIO_HAL_CONF_PIN_COUNT @@ -101,21 +101,23 @@ typedef uint32_t gpio_hal_pin_mask_t; typedef void (*gpio_hal_callback_t)(gpio_hal_pin_mask_t pin_mask); /*---------------------------------------------------------------------------*/ -#define GPIO_HAL_PIN_CFG_PULL_NONE 0x00 -#define GPIO_HAL_PIN_CFG_PULL_UP 0x01 -#define GPIO_HAL_PIN_CFG_PULL_DOWN 0x02 -#define GPIO_HAL_PIN_CFG_PULL_MASK (GPIO_HAL_PIN_CFG_PULL_UP | \ - GPIO_HAL_PIN_CFG_PULL_DOWN) +#define GPIO_HAL_PIN_CFG_PULL_NONE (0) +#define GPIO_HAL_PIN_CFG_PULL_UP (1 << 0) +#define GPIO_HAL_PIN_CFG_PULL_DOWN (1 << 1) -#define GPIO_HAL_PIN_CFG_EDGE_NONE 0x00 -#define GPIO_HAL_PIN_CFG_EDGE_RISING 0x04 -#define GPIO_HAL_PIN_CFG_EDGE_FALLING 0x08 -#define GPIO_HAL_PIN_CFG_EDGE_BOTH (GPIO_HAL_PIN_CFG_EDGE_RISING | \ - GPIO_HAL_PIN_CFG_EDGE_FALLING) +#define GPIO_HAL_PIN_CFG_PULL_MASK ( GPIO_HAL_PIN_CFG_PULL_UP \ + | GPIO_HAL_PIN_CFG_PULL_DOWN \ + ) -#define GPIO_HAL_PIN_CFG_INT_DISABLE 0x00 -#define GPIO_HAL_PIN_CFG_INT_ENABLE 0x80 -#define GPIO_HAL_PIN_CFG_INT_MASK 0x80 +#define GPIO_HAL_PIN_CFG_INT_DISABLE (0) +#define GPIO_HAL_PIN_CFG_INT_FALLING (1 << 2) +#define GPIO_HAL_PIN_CFG_INT_RISING (1 << 3) +#define GPIO_HAL_PIN_CFG_INT_BOTH (1 << 4) + +#define GPIO_HAL_PIN_CFG_INT_MASK ( GPIO_HAL_PIN_CFG_INT_RISING \ + | GPIO_HAL_PIN_CFG_INT_FALLING \ + | GPIO_HAL_PIN_CFG_INT_BOTH \ + ) /*---------------------------------------------------------------------------*/ /** * \brief Datatype for GPIO event handlers @@ -233,6 +235,18 @@ void gpio_hal_event_handler(gpio_hal_pin_mask_t pins); #include GPIO_HAL_CONF_ARCH_HDR_PATH #endif /* GPIO_HAL_CONF_ARCH_HDR_PATH */ /*---------------------------------------------------------------------------*/ +#ifndef gpio_hal_arch_init +/** + * \brief Perform architecture specific gpio initaliaztion + * + * It is the platform developer's responsibility to provide an implementation. + * + * The implementation can be provided as a global symbol, an inline function + * or a function-like macro, as described above. + */ +void gpio_hal_arch_init(void); +#endif +/*---------------------------------------------------------------------------*/ #ifndef gpio_hal_arch_interrupt_enable /** * \brief Enable interrupts for a gpio pin @@ -243,7 +257,7 @@ void gpio_hal_event_handler(gpio_hal_pin_mask_t pins); * The implementation can be provided as a global symbol, an inline function * or a function-like macro, as described above. */ -void gpio_hal_arch_interrupt_enable(gpio_hal_pin_t pin); +void gpio_hal_arch_interrupt_enable(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg); #endif /*---------------------------------------------------------------------------*/ #ifndef gpio_hal_arch_interrupt_disable diff --git a/os/sys/timer.c b/os/sys/timer.c index 1eeae64de..068d57777 100644 --- a/os/sys/timer.c +++ b/os/sys/timer.c @@ -84,7 +84,9 @@ timer_set(struct timer *t, clock_time_t interval) void timer_reset(struct timer *t) { - t->start += t->interval; + if(timer_expired(t)) { + t->start += t->interval; + } } /*---------------------------------------------------------------------------*/ /** From bb00eaa04118f2a1fc33076cff592538a0314202 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Wed, 4 Jul 2018 19:33:03 +0200 Subject: [PATCH 256/485] Normalized GPIO HAL, fixed LEDS & Buttons HAL, and aligned sensortag and SRF06 boards --- .../cc13x0-cc26x0/cc13xx-cc26xx-def.h | 6 +- arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h | 2 +- arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c | 206 +++- arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.h | 23 +- arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c | 2 +- arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c | 2 +- .../rf-settings/cc13x0/ieee-settings.c | 20 +- .../rf-settings/cc13x0/ieee-settings.h | 2 +- .../rf-settings/cc13x0/prop-settings.h | 3 +- .../simplelink/cc13xx-cc26xx/contiki-conf.h | 20 +- .../cc13xx-cc26xx/custom/Makefile.custom | 15 + .../launchpad/Makefile.launchpad | 4 +- .../{button-sensor-arch.h => board-conf.h} | 38 +- .../launchpad/board-peripherals.h | 4 + .../launchpad/button-sensor-arch.c | 197 +-- .../cc13xx-cc26xx/launchpad/cc1310/Board.h | 18 +- .../cc13xx-cc26xx/launchpad/cc1312r1/Board.h | 18 +- .../cc13xx-cc26xx/launchpad/cc1350-4/Board.h | 14 - .../launchpad/cc1350-4/Makefile.cc1350-4 | 2 +- .../cc13xx-cc26xx/launchpad/cc1350/Board.h | 15 +- .../{cc1352p_2 => cc1352p-2}/Board.h | 14 - .../CC1352P_2_LAUNCHXL.c | 0 .../CC1352P_2_LAUNCHXL.h | 0 .../CC1352P_2_LAUNCHXL_fxns.c | 0 .../Makefile.cc1352p-2} | 0 .../{cc1352p_4 => cc1352p-4}/Board.h | 14 - .../CC1352P_4_LAUNCHXL.c | 0 .../CC1352P_4_LAUNCHXL.h | 0 .../CC1352P_4_LAUNCHXL_fxns.c | 0 .../Makefile.cc1352p-4} | 0 .../cc13xx-cc26xx/launchpad/cc1352p1/Board.h | 14 - .../launchpad/cc1352p1/Makefile.cc1352p1 | 2 +- .../cc13xx-cc26xx/launchpad/cc1352r1/Board.h | 14 - .../cc13xx-cc26xx/launchpad/cc2650/Board.h | 15 +- .../cc13xx-cc26xx/launchpad/cc26x2r1/Board.h | 14 - .../launchpad/launchpad-sensors.c | 51 - .../simplelink/cc13xx-cc26xx/platform.c | 12 + .../sensortag/Makefile.sensortag | 7 +- .../sensortag/{reed-relay.h => board-conf.h} | 29 +- .../sensortag/board-peripherals.h | 5 +- .../sensortag/button-sensor-arch.c | 180 +-- .../cc13xx-cc26xx/sensortag/cc1350/Board.h | 18 +- .../sensortag/cc1350/leds-arch.c | 53 +- .../cc1350/leds-arch.h} | 49 +- .../cc13xx-cc26xx/sensortag/cc2650/Board.h | 18 +- .../sensortag/cc2650/leds-arch.c | 59 +- .../leds-arch.h} | 37 +- .../cc13xx-cc26xx/sensortag/ext-flash.c | 468 +++++++ .../sensortag/{sensortag.c => ext-flash.h} | 90 +- .../cc13xx-cc26xx/sensortag/reed-relay.c | 152 --- .../sensortag/sensortag-sensors.c | 19 +- .../cc13xx-cc26xx/srf06/Makefile.srf06 | 3 +- .../cc13xx-cc26xx/srf06/als-sensor.c | 59 +- .../button-sensor.h => srf06/board-conf.h} | 55 +- .../cc13xx-cc26xx/srf06/board-peripherals.h | 19 +- .../cc13xx-cc26xx/srf06/button-sensor-arch.c | 91 ++ .../cc13xx-cc26xx/srf06/cc13x0/Board.h | 146 ++- .../cc13xx-cc26xx/srf06/cc13x0/CC1310DK_7XD.c | 670 ----------- .../cc13xx-cc26xx/srf06/cc13x0/CC1310DK_7XD.h | 289 ----- .../cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c | 749 ++++++++++++ .../cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h | 367 ++++++ .../srf06/cc13x0/CC1350DK_7XD_fxns.c | 72 ++ .../srf06/cc13x0/Makefile.cc13x0 | 2 +- .../cc13xx-cc26xx/srf06/cc26x0/Board.h | 145 ++- .../cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c | 1071 +++++++++-------- .../cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h | 465 ++++--- .../srf06/cc26x0/CC2650DK_7ID_fxns.c | 72 ++ .../srf06/cc26x0/Makefile.cc26x0 | 2 +- .../cc13xx-cc26xx/srf06/leds-arch.c | 58 +- .../cc13xx-cc26xx/srf06/srf06-sensors.c | 18 +- .../simplelink/cc13xx-cc26xx/srf06/srf06.c | 112 -- os/dev/button-hal.h | 1 + os/dev/gpio-hal.h | 79 +- 73 files changed, 3509 insertions(+), 2981 deletions(-) create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/custom/Makefile.custom rename arch/platform/simplelink/cc13xx-cc26xx/launchpad/{button-sensor-arch.h => board-conf.h} (73%) rename arch/platform/simplelink/cc13xx-cc26xx/launchpad/{cc1352p_2 => cc1352p-2}/Board.h (94%) rename arch/platform/simplelink/cc13xx-cc26xx/launchpad/{cc1352p_2 => cc1352p-2}/CC1352P_2_LAUNCHXL.c (100%) rename arch/platform/simplelink/cc13xx-cc26xx/launchpad/{cc1352p_2 => cc1352p-2}/CC1352P_2_LAUNCHXL.h (100%) rename arch/platform/simplelink/cc13xx-cc26xx/launchpad/{cc1352p_2 => cc1352p-2}/CC1352P_2_LAUNCHXL_fxns.c (100%) rename arch/platform/simplelink/cc13xx-cc26xx/launchpad/{cc1352p_2/Makefile.cc1352p_2 => cc1352p-2/Makefile.cc1352p-2} (100%) rename arch/platform/simplelink/cc13xx-cc26xx/launchpad/{cc1352p_4 => cc1352p-4}/Board.h (94%) rename arch/platform/simplelink/cc13xx-cc26xx/launchpad/{cc1352p_4 => cc1352p-4}/CC1352P_4_LAUNCHXL.c (100%) rename arch/platform/simplelink/cc13xx-cc26xx/launchpad/{cc1352p_4 => cc1352p-4}/CC1352P_4_LAUNCHXL.h (100%) rename arch/platform/simplelink/cc13xx-cc26xx/launchpad/{cc1352p_4 => cc1352p-4}/CC1352P_4_LAUNCHXL_fxns.c (100%) rename arch/platform/simplelink/cc13xx-cc26xx/launchpad/{cc1352p_4/Makefile.cc1352p_4 => cc1352p-4/Makefile.cc1352p-4} (100%) delete mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/launchpad-sensors.c rename arch/platform/simplelink/cc13xx-cc26xx/sensortag/{reed-relay.h => board-conf.h} (77%) rename arch/platform/simplelink/cc13xx-cc26xx/{launchpad/launchpad.c => sensortag/cc1350/leds-arch.h} (77%) rename arch/platform/simplelink/cc13xx-cc26xx/sensortag/{button-sensor-arch.h => cc2650/leds-arch.h} (74%) create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/ext-flash.c rename arch/platform/simplelink/cc13xx-cc26xx/sensortag/{sensortag.c => ext-flash.h} (52%) delete mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/reed-relay.c rename arch/platform/simplelink/cc13xx-cc26xx/{common/button-sensor.h => srf06/board-conf.h} (68%) create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor-arch.c delete mode 100644 arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1310DK_7XD.c delete mode 100644 arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1310DK_7XD.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD_fxns.c create mode 100644 arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID_fxns.c delete mode 100644 arch/platform/simplelink/cc13xx-cc26xx/srf06/srf06.c diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13xx-cc26xx-def.h b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13xx-cc26xx-def.h index 41eee3d87..bca8365c7 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13xx-cc26xx-def.h +++ b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13xx-cc26xx-def.h @@ -37,12 +37,12 @@ /* TSCH related defines */ /* Delay between GO signal and SFD */ -#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(81)) +#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(81)) /* Delay between GO signal and start listening. * This value is so small because the radio is constantly on within each timeslot. */ -#define RADIO_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(15)) +#define RADIO_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(15)) /* Delay between the SFD finishes arriving and it is detected in software. */ -#define RADIO_DELAY_BEFORE_DETECT ((unsigned)US_TO_RTIMERTICKS(352)) +#define RADIO_DELAY_BEFORE_DETECT ((unsigned)US_TO_RTIMERTICKS(352)) /* Timer conversion; radio is running at 4 MHz */ #define RAT_SECOND 4000000u diff --git a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h index fc5243b51..c457a814f 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h +++ b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h @@ -117,7 +117,7 @@ /* CC26xx only supports IEEE mode */ #elif defined(DEVICE_LINE_CC26XX) -# if (SUPPORTS_IEEE_MODE) +# if (RF_CORE_MODE == RF_CORE_MODE_2_4_GHZ) && (SUPPORTS_IEEE_MODE) /*----- CC26xx IEEE Mode ----------------------------------------------------*/ # define NETSTACK_CONF_RADIO ieee_mode_driver diff --git a/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c b/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c index b34200d68..38ebe4a0c 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c @@ -42,70 +42,184 @@ #include #include DeviceFamily_constructPath(driverlib/gpio.h) -#include DeviceFamily_constructPath(driverlib/ioc.h) + +#include +#include #include /*---------------------------------------------------------------------------*/ -#define CONFIG_MASK (IOC_IOPULL_M | IOC_INT_M | IOC_IOMODE_OPEN_SRC_INV) +static PIN_Config pin_config[] = +{ + PIN_TERMINATE +}; + +static PIN_State pin_state; +static PIN_Handle pin_handle; +/*---------------------------------------------------------------------------*/ +static void +from_hal_cfg(gpio_hal_pin_cfg_t cfg, PIN_Config *pin_cfg, PIN_Config *pin_mask) +{ + cfg &= GPIO_HAL_PIN_BM_ALL; + + /* Input config */ + if (cfg & GPIO_HAL_PIN_BM_INPUT) { + *pin_mask |= PIN_BM_INPUT_MODE; + + if ((cfg & GPIO_HAL_PIN_BM_INPUT_HYSTERESIS) == GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS) { + *pin_cfg |= PIN_HYSTERESIS; + } + + switch (cfg & GPIO_HAL_PIN_BM_INPUT_PULLING) { + case GPIO_HAL_PIN_CFG_INPUT_NOPULL: *pin_cfg |= PIN_NOPULL; break; + case GPIO_HAL_PIN_CFG_INPUT_PULLUP: *pin_cfg |= PIN_PULLUP; break; + case GPIO_HAL_PIN_CFG_INPUT_PULLDOWN: *pin_cfg |= PIN_PULLDOWN; break; + } + } + + /* Output config */ + if (cfg & GPIO_HAL_PIN_BM_OUTPUT) { + *pin_mask |= PIN_BM_OUTPUT_MODE; + + switch (cfg & GPIO_HAL_PIN_BM_OUTPUT_BUF) { + case GPIO_HAL_PIN_CFG_OUTPUT_PUSHPULL: *pin_cfg |= PIN_PUSHPULL; break; + case GPIO_HAL_PIN_CFG_OUTPUT_OPENDRAIN: *pin_cfg |= PIN_OPENDRAIN; break; + case GPIO_HAL_PIN_CFG_OUTPUT_OPENSOURCE: *pin_cfg |= PIN_OPENSOURCE; break; + } + + if ((cfg & GPIO_HAL_PIN_BM_OUTPUT_SLEWCTRL) == GPIO_HAL_PIN_CFG_OUTPUT_SLEWCTRL) { + *pin_cfg |= PIN_SLEWCTRL; + } + + switch (cfg & GPIO_HAL_PIN_BM_OUTPUT_DRVSTR) { + case GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MIN: *pin_cfg |= PIN_DRVSTR_MIN; break; + case GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MED: *pin_cfg |= PIN_DRVSTR_MED; break; + case GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MAX: *pin_cfg |= PIN_DRVSTR_MAX; break; + } + } + + /* Interrupt config */ + if (cfg & GPIO_HAL_PIN_BM_INT) { + *pin_mask |= PIN_BM_IRQ; + + switch (cfg & GPIO_HAL_PIN_BM_OUTPUT_BUF) { + case GPIO_HAL_PIN_CFG_INT_DISABLE: *pin_cfg |= PIN_IRQ_DIS; break; + case GPIO_HAL_PIN_CFG_INT_FALLING: *pin_cfg |= PIN_IRQ_NEGEDGE; break; + case GPIO_HAL_PIN_CFG_INT_RISING: *pin_cfg |= PIN_IRQ_POSEDGE; break; + case GPIO_HAL_PIN_CFG_INT_BOTH: *pin_cfg |= PIN_IRQ_BOTHEDGES; break; + } + } +} +/*---------------------------------------------------------------------------*/ +static void +to_hal_cfg(PIN_Config pin_cfg, gpio_hal_pin_cfg_t *cfg) +{ + /* Input config */ + if (pin_cfg & PIN_BM_INPUT_MODE) { + if ((pin_cfg & PIN_BM_HYSTERESIS) == PIN_HYSTERESIS) { + *cfg |= GPIO_HAL_PIN_BM_INPUT_HYSTERESIS; + } + + switch (pin_cfg & PIN_BM_PULLING) { + case PIN_NOPULL: *cfg |= GPIO_HAL_PIN_CFG_INPUT_NOPULL; break; + case PIN_PULLUP: *cfg |= GPIO_HAL_PIN_CFG_INPUT_PULLUP; break; + case PIN_PULLDOWN: *cfg |= GPIO_HAL_PIN_CFG_INPUT_PULLDOWN; break; + } + } + + /* Output config */ + if (pin_cfg & PIN_BM_OUTPUT_MODE) { + switch (pin_cfg & PIN_BM_OUTPUT_BUF) { + case PIN_PUSHPULL: *cfg |= GPIO_HAL_PIN_CFG_OUTPUT_PUSHPULL; break; + case PIN_OPENDRAIN: *cfg |= GPIO_HAL_PIN_CFG_OUTPUT_OPENDRAIN; break; + case PIN_OPENSOURCE: *cfg |= GPIO_HAL_PIN_CFG_OUTPUT_OPENSOURCE; break; + } + + if ((pin_cfg & PIN_BM_SLEWCTRL) == PIN_SLEWCTRL) { + *cfg |= GPIO_HAL_PIN_CFG_OUTPUT_SLEWCTRL; + } + + switch (pin_cfg & PIN_BM_DRVSTR) { + case PIN_DRVSTR_MIN: *cfg |= GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MIN; break; + case PIN_DRVSTR_MED: *cfg |= GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MED; break; + case PIN_DRVSTR_MAX: *cfg |= GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MAX; break; + } + } + + /* Interrupt config */ + if (pin_cfg & PIN_BM_IRQ) { + switch (pin_cfg & PIN_BM_IRQ) { + case PIN_IRQ_DIS: *cfg |= GPIO_HAL_PIN_CFG_INT_DISABLE; break; + case PIN_IRQ_NEGEDGE: *cfg |= GPIO_HAL_PIN_CFG_INT_FALLING; break; + case PIN_IRQ_POSEDGE: *cfg |= GPIO_HAL_PIN_CFG_INT_RISING; break; + case PIN_IRQ_BOTHEDGES: *cfg |= GPIO_HAL_PIN_CFG_INT_BOTH; break; + } + } +} +/*---------------------------------------------------------------------------*/ +static void +gpio_int_cb(PIN_Handle handle, PIN_Id pin_id) +{ + /* Unused args */ + (void)handle; + + gpio_hal_event_handler(gpio_hal_pin_to_mask(pin_id)); +} + +/*---------------------------------------------------------------------------*/ +void +gpio_hal_arch_init(void) +{ + /* No error checking */ + pin_handle = PIN_open(&pin_state, pin_config); + PIN_registerIntCb(pin_handle, gpio_int_cb); +} /*---------------------------------------------------------------------------*/ void gpio_hal_arch_interrupt_enable(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg) { - GPIO_clearEventDio(pin); - gpio_hal_arch_pin_cfg_set(pin, cfg); - IOCIntEnable(pin); + PIN_add(pin_handle, PIN_getConfig(pin)); + + cfg &= GPIO_HAL_PIN_BM_INT; + + PIN_Config int_cfg = PIN_IRQ_DIS; + switch (cfg) { + case GPIO_HAL_PIN_CFG_INT_FALLING: int_cfg |= PIN_IRQ_NEGEDGE; break; + case GPIO_HAL_PIN_CFG_INT_RISING: int_cfg |= PIN_IRQ_POSEDGE; break; + case GPIO_HAL_PIN_CFG_INT_BOTH: int_cfg |= PIN_IRQ_BOTHEDGES; break; + } + + PIN_setInterrupt(pin_handle, pin | int_cfg); +} +/*---------------------------------------------------------------------------*/ +void +gpio_hal_arch_interrupt_disable(gpio_hal_pin_t pin) +{ + PIN_add(pin_handle, PIN_getConfig(pin)); + + PIN_setInterrupt(pin_handle, pin | PIN_IRQ_DIS); } /*---------------------------------------------------------------------------*/ void gpio_hal_arch_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg) { + PIN_add(pin_handle, PIN_getConfig(pin)); + /* Clear settings that we are about to change, keep everything else */ - uint32_t config = IOCPortConfigureGet(pin); - config &= ~CONFIG_MASK; + PIN_Config pin_cfg = 0; + PIN_Config pin_mask = 0; - switch (cfg & GPIO_HAL_PIN_CFG_INT_MASK) { - case GPIO_HAL_PIN_CFG_INT_DISABLE: config |= (IOC_NO_EDGE | IOC_INT_DISABLE); break; - case GPIO_HAL_PIN_CFG_INT_FALLING: config |= (IOC_FALLING_EDGE | IOC_INT_ENABLE); break; - case GPIO_HAL_PIN_CFG_INT_RISING: config |= (IOC_RISING_EDGE | IOC_INT_ENABLE); break; - case GPIO_HAL_PIN_CFG_INT_BOTH: config |= (IOC_BOTH_EDGES | IOC_INT_ENABLE); break; - default: {} - } + from_hal_cfg(cfg, &pin_cfg, &pin_mask); - switch (cfg & GPIO_HAL_PIN_CFG_PULL_MASK) { - case GPIO_HAL_PIN_CFG_PULL_NONE: config |= IOC_NO_IOPULL; break; - case GPIO_HAL_PIN_CFG_PULL_DOWN: config |= IOC_IOPULL_DOWN; break; - case GPIO_HAL_PIN_CFG_PULL_UP: config |= IOC_IOPULL_UP; break; - default: {} - } - - IOCPortConfigureSet(pin, IOC_PORT_GPIO, config); + PIN_setConfig(pin_handle, pin_mask, pin | pin_cfg); } /*---------------------------------------------------------------------------*/ gpio_hal_pin_cfg_t gpio_hal_arch_pin_cfg_get(gpio_hal_pin_t pin) { + PIN_Config pin_cfg = PIN_getConfig(pin); gpio_hal_pin_cfg_t cfg = 0; - uint32_t config = IOCPortConfigureGet(pin); - switch (config & IOC_IOPULL_M) { - case IOC_IOPULL_UP: cfg |= GPIO_HAL_PIN_CFG_PULL_UP; break; - case IOC_IOPULL_DOWN: cfg |= GPIO_HAL_PIN_CFG_PULL_DOWN; break; - case IOC_NO_IOPULL: cfg |= GPIO_HAL_PIN_CFG_PULL_NONE; break; - default: {} - } - - /* Interrupt enable/disable */ - uint32_t tmp = config & IOC_INT_M; - if (tmp & IOC_INT_ENABLE) { - switch (tmp) { - case IOC_FALLING_EDGE: cfg |= GPIO_HAL_PIN_CFG_INT_FALLING; break; - case IOC_RISING_EDGE: cfg |= GPIO_HAL_PIN_CFG_INT_RISING; break; - case IOC_BOTH_EDGES: cfg |= GPIO_HAL_PIN_CFG_INT_BOTH; break; - default: {} - } - } else { - cfg |= GPIO_HAL_PIN_CFG_INT_DISABLE; - } + to_hal_cfg(pin_cfg, &cfg); return cfg; } @@ -125,11 +239,9 @@ gpio_hal_arch_read_pins(gpio_hal_pin_mask_t pins) uint8_t gpio_hal_arch_read_pin(gpio_hal_pin_t pin) { - if (GPIO_getOutputEnableDio(pin)) { - return (HWREG(GPIO_BASE + GPIO_O_DOUT31_0) >> pin) & 1; - } - - return GPIO_readDio(pin); + return (GPIO_getOutputEnableDio(pin)) + ? PINCC26XX_getOutputValue(pin) + : PINCC26XX_getInputValue(pin); } /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.h b/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.h index 6fd5a520c..d175ec301 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.h +++ b/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.h @@ -50,21 +50,24 @@ #include "contiki.h" #include -#include DeviceFamily_constructPath(driverlib/gpio.h) #include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/gpio.h) + +#include +#include #include +#include /*---------------------------------------------------------------------------*/ -#define gpio_hal_arch_init() do { /* do nothing */ } while (0) -#define gpio_hal_arch_interrupt_disable(p) IOCIntDisable(p) +#define gpio_hal_arch_pin_set_input(p) PINCC26XX_setOutputEnable(p, false) +#define gpio_hal_arch_pin_set_output(p) PINCC26XX_setOutputEnable(p, true) -#define gpio_hal_arch_pin_set_input(p) IOCPinTypeGpioInput(p) -#define gpio_hal_arch_pin_set_output(p) IOCPinTypeGpioOutput(p) - -#define gpio_hal_arch_set_pin(p) GPIO_setDio(p) -#define gpio_hal_arch_clear_pin(p) GPIO_clearDio(p) -#define gpio_hal_arch_toggle_pin(p) GPIO_toggleDio(p) -#define gpio_hal_arch_write_pin(p, v) GPIO_writeDio(p, v) +#define gpio_hal_arch_set_pin(p) PINCC26XX_setOutputValue(p, 1) +#define gpio_hal_arch_clear_pin(p) PINCC26XX_setOutputValue(p, 0) +#define gpio_hal_arch_toggle_pin(p) PINCC26XX_setOutputValue(p, \ + PINCC26XX_getOutputValue(p) \ + ? 0 : 1) +#define gpio_hal_arch_write_pin(p, v) PINCC26XX_setOutputValue(p, v) #define gpio_hal_arch_set_pins(p) GPIO_setMultiDio(p) #define gpio_hal_arch_clear_pins(p) GPIO_clearMultiDio(p) diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c index dfe3a0d3c..397d24005 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c @@ -168,7 +168,7 @@ #define RAT_THREE_QUARTERS ((RAT_RANGE * (uint32_t)3) / (uint32_t)4) /* XXX: don't know what exactly is this, looks like the time to TX 3 octets */ -#define RAT_TIMESTAMP_OFFSET -(USEC_TO_RADIO(32 * 3) - 1) /* -95.75 usec */ +#define RAT_TIMESTAMP_OFFSET -(USEC_TO_RAT(32 * 3) - 1) /* -95.75 usec */ /*---------------------------------------------------------------------------*/ #define STATUS_CORRELATION 0x3f /* bits 0-5 */ #define STATUS_REJECT_FRAME 0x40 /* bit 6 */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c index b7d2c58f6..418ec46db 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c @@ -148,7 +148,7 @@ #ifdef PROP_MODE_CONF_TX_POWER_TABLE # define TX_POWER_TABLE PROP_MODE_CONF_TX_POWER_TABLE #else -# define TX_POWER_TABLE propTxPowerTable +# define TX_POWER_TABLE rf_prop_tx_power_table #endif /*---------------------------------------------------------------------------*/ /* TX power table convenience macros */ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c index 0acff3cbf..cfe9ef9a7 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c @@ -108,24 +108,6 @@ uint32_t rf_ieee_overrides[] CC_ALIGN(4) = (uint32_t)0xFFFFFFFF, }; /*---------------------------------------------------------------------------*/ -// Old override list -uint32_t rf_ieee_overrides_old[] CC_ALIGN(4) = -{ - (uint32_t)0x00354038, /* Synth: Set RTRIM (POTAILRESTRIM) to 5 */ - (uint32_t)0x4001402D, /* Synth: Correct CKVD latency setting (address) */ - (uint32_t)0x00608402, /* Synth: Correct CKVD latency setting (value) */ -// (uint32_t)0x4001405D, /* Synth: Set ANADIV DIV_BIAS_MODE to PG1 (address) */ -// (uint32_t)0x1801F800, /* Synth: Set ANADIV DIV_BIAS_MODE to PG1 (value) */ - (uint32_t)0x000784A3, /* Synth: Set FREF = 3.43 MHz (24 MHz / 7) */ - (uint32_t)0xA47E0583, /* Synth: Set loop bandwidth after lock to 80 kHz (K2) */ - (uint32_t)0xEAE00603, /* Synth: Set loop bandwidth after lock to 80 kHz (K3, LSB) */ - (uint32_t)0x00010623, /* Synth: Set loop bandwidth after lock to 80 kHz (K3, MSB) */ - (uint32_t)0x002B50DC, /* Adjust AGC DC filter */ - (uint32_t)0x05000243, /* Increase synth programming timeout */ - (uint32_t)0x002082C3, /* Increase synth programming timeout */ - (uint32_t)0xFFFFFFFF, -}; -/*---------------------------------------------------------------------------*/ // CMD_RADIO_SETUP // Radio Setup Command for Pre-Defined Schemes rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup = @@ -197,7 +179,7 @@ rfc_CMD_IEEE_TX_t rf_cmd_ieee_tx = /*---------------------------------------------------------------------------*/ // CMD_IEEE_RX // The command ID number 0x2801 -rfc_CMD_IEEE_RX_t rf_cmd_ieee_xx = +rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx = { .commandNo = CMD_IEEE_RX, .status = IDLE, diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h index 20f4e2656..5276887b4 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h @@ -53,7 +53,7 @@ extern RF_TxPowerTable_Entry rf_ieee_tx_power_table[RF_IEEE_TX_POWER_TABLE_SIZE+ extern rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup; extern rfc_CMD_FS_t rf_cmd_ieee_fs; extern rfc_CMD_IEEE_TX_t rf_cmd_ieee_tx; -extern rfc_CMD_IEEE_RX_t rf_cmd_ieee_xx; +extern rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx; /*---------------------------------------------------------------------------*/ // RF Core API Overrides extern uint32_t rf_ieee_overrides[]; diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h index e6dd45962..cd95a3ace 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h @@ -43,7 +43,8 @@ extern RF_Mode rf_prop_mode; /*---------------------------------------------------------------------------*/ // TX Power Table #define RF_PROP_TX_POWER_TABLE_SIZE 15 -extern RF_TxPowerTable_Entry rf_prop_tx_power_table[PROP_TX_POWER_TABLE_SIZE+1]; + +extern RF_TxPowerTable_Entry rf_prop_tx_power_table[RF_PROP_TX_POWER_TABLE_SIZE+1]; /*---------------------------------------------------------------------------*/ // RF Core API commands extern rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h b/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h index 99a424dbd..69659c0b1 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h @@ -39,30 +39,14 @@ #define CONTIKI_CONF_H_ /*---------------------------------------------------------------------------*/ #include + +#include "board-conf.h" /*---------------------------------------------------------------------------*/ /* Include Project Specific conf */ #ifdef PROJECT_CONF_PATH #include PROJECT_CONF_PATH #endif /* PROJECT_CONF_PATH */ /*---------------------------------------------------------------------------*/ -/** - * \name Button configurations - * - * Configure a button as power on/off: We use the right button for both boards. - * @{ - */ -#ifndef BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN -#define BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN 0 -#endif - -/* - * Override button symbols from dev/button-sensor.h, for the examples that - * include it - */ -#define button_sensor button_left_sensor -#define button_sensor2 button_right_sensor -/** @} */ -/*---------------------------------------------------------------------------*/ /* Include CPU-related configuration */ #include "cc13xx-cc26xx-conf.h" /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/custom/Makefile.custom b/arch/platform/simplelink/cc13xx-cc26xx/custom/Makefile.custom new file mode 100644 index 000000000..31da88d0a --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/custom/Makefile.custom @@ -0,0 +1,15 @@ +################################################################################ +# SimpleLink LaunchPad makefile + +BOARD_TYPE = BOARD_SENSORTAG + +PLATFORM_HAS_BUTTON = 1 + +# leds-arch.c/h etc. +BOARD_SOURCEFILES += sensortag-sensors.c +BOARD_SOURCEFILES += button-sensor-arch.c ext-flash.c +BOARD_SOURCEFILES += bmp-280-sensor.c hdc-1000-sensor.c +BOARD_SOURCEFILES += mpu-9250-sensor.c opt-3001-sensor.c +BOARD_SOURCEFILES += tmp-007-sensor.c buzzer.c + +TARGET_FAMILY_DIRS += sensortag \ No newline at end of file diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/Makefile.launchpad b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/Makefile.launchpad index d2d1bf777..c8524692e 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/Makefile.launchpad +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/Makefile.launchpad @@ -6,7 +6,7 @@ BOARD_TYPE = BOARD_LAUNCHPAD PLATFORM_HAS_BUTTON = 1 # leds-arch.c/h etc. -BOARD_SOURCEFILES += launchpad.c launchpad-sensors.c -BOARD_SOURCEFILES += button-sensor-arch.c leds-arch.c ext-flash.c +BOARD_SOURCEFILES += button-sensor-arch.c leds-arch.c +BOARD_SOURCEFILES += ext-flash.c TARGET_FAMILY_DIRS += launchpad diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-conf.h similarity index 73% rename from arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.h rename to arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-conf.h index 9fca110ae..9a123bcf1 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-conf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,29 +28,41 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /*---------------------------------------------------------------------------*/ -/** - * \addtogroup simplelink-platform +/** \addtogroup cc26xx-srf-tag * @{ * - * \defgroup simplelink-button-sensor Simplelink Button Driver + * \defgroup launchpad-peripherals LaunchPad peripherals + * + * Defines related to LaunchPad peripherals. * - * One of the buttons can be configured as general purpose or as an on/off key * @{ * * \file - * Header file for the Simplelink Button Driver + * Header file with definitions related to LaunchPad peripherals + * + * \note Do not include this file directly. */ /*---------------------------------------------------------------------------*/ -#ifndef BUTTON_SENSOR_ARCH_H_ -#define BUTTON_SENSOR_ARCH_H_ +#ifndef BOARD_CONF_H_ +#define BOARD_CONF_H_ /*---------------------------------------------------------------------------*/ -/* Contiki API */ -#include "lib/sensors.h" +/** + * \name LED configurations + * + * Those values are not meant to be modified by the user + * @{ + */ +#define LEDS_CONF_COUNT 2 + +#define LEDS_CONF_RED 0 +#define LEDS_CONF_GREEN 1 + +#define LEDS_CONF_ALL ((1 << LEDS_CONF_COUNT) - 1) /*---------------------------------------------------------------------------*/ -extern const struct sensors_sensor button_left_sensor; -extern const struct sensors_sensor button_right_sensor; +#define BUTTON_HAL_ID_KEY_LEFT 0 +#define BUTTON_HAL_ID_KEY_RIGHT 1 /*---------------------------------------------------------------------------*/ -#endif /* BUTTON_SENSOR_ARCH_H_ */ +#endif /* BOARD_CONF_H_ */ /*---------------------------------------------------------------------------*/ /** * @} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-peripherals.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-peripherals.h index 3e1220234..6b9fae675 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-peripherals.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-peripherals.h @@ -48,6 +48,10 @@ /*---------------------------------------------------------------------------*/ #include "ext-flash.h" /*---------------------------------------------------------------------------*/ +#include "board-conf.h" +/*---------------------------------------------------------------------------*/ +#define BOARD_CONF_HAS_SENSORS 0 +/*---------------------------------------------------------------------------*/ #endif /* BOARD_PERIPHERALS_H_ */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c index f9c3300bf..073c620e6 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c @@ -36,186 +36,29 @@ * Driver for LaunchPad buttons */ /*---------------------------------------------------------------------------*/ -#include -#include -#include -/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "dev/button-hal.h" + #include -#include -#include /*---------------------------------------------------------------------------*/ -#include -#include -/*---------------------------------------------------------------------------*/ -#include "button-sensor.h" -/*---------------------------------------------------------------------------*/ -/* LaunchPad has 2 buttons: BTN1 and BTN2 */ -/* Map the GPIO defines from the Board file */ -#define BTN1_PIN Board_PIN_BTN1 -#define BTN2_PIN Board_PIN_BTN2 -/*---------------------------------------------------------------------------*/ -#ifdef BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN -# define BUTTON_SENSOR_ENABLE_SHUTDOWN BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN -#else -# define BUTTON_SENSOR_ENABLE_SHUTDOWN 0 -#endif -/*---------------------------------------------------------------------------*/ -#define DEBOUNCE_DURATION (CLOCK_SECOND >> 5) -/*---------------------------------------------------------------------------*/ -typedef struct { - struct timer debounce; - clock_time_t start; - clock_time_t duration; -} BtnTimer; -/*---------------------------------------------------------------------------*/ -static BtnTimer btn1_timer; -static BtnTimer btn2_timer; -/*---------------------------------------------------------------------------*/ -static const PIN_Config btn_pin_table[] = { - BTN1_PIN | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ - BTN2_PIN | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ - PIN_TERMINATE -}; +/* Key left button, AKA BTN-1 */ +BUTTON_HAL_BUTTON(key_left, /**< Name */ + "Key Left", /**< Description */ + Board_PIN_BTN1, /**< PIN */ + GPIO_HAL_PIN_CFG_INPUT_PULLUP | + GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_KEY_LEFT, /**< Unique ID */ + true); /**< Negative logic */ -static PIN_State pin_state; -static PIN_Handle pin_handle; +/* Key right button, AKA BTN-2 */ +BUTTON_HAL_BUTTON(key_right, /**< Name */ + "Key Right", /**< Description */ + Board_PIN_BTN2, /**< PIN */ + GPIO_HAL_PIN_CFG_INPUT_PULLUP | + GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_KEY_RIGHT, /**< Unique ID */ + true); /**< Negative logic */ /*---------------------------------------------------------------------------*/ -static void -button_press_cb(PIN_Handle handle, PIN_Id pin_id) -{ -#if BUTTON_SENSOR_ENABLE_SHUTDOWN - if (pin_id == BTN2_PIN) { - Power_shutdown(Power_ENTERING_SHUTDOWN, 0); - return; - } -#endif - - BtnTimer *btn_timer = NULL; - const struct sensors_sensor *btn_sensor = NULL; - - switch (pin_id) { - case BTN1_PIN: btn_timer = &btn1_timer; - btn_sensor = &button_left_sensor; break; - case BTN2_PIN: btn_timer = &btn2_timer; - btn_sensor = &button_right_sensor; break; - default: return; /* No matching PIN */ - } - - if (!timer_expired(&btn_timer->debounce)) { - return; - } - - timer_set(&btn_timer->debounce, DEBOUNCE_DURATION); - - // Start press duration counter on press (falling), notify on release (rising) - if (PIN_getInputValue(pin_id) == 0) { - btn_timer->start = clock_time(); - btn_timer->duration = 0; - } else { - btn_timer->duration = clock_time() - btn_timer->start; - sensors_changed(btn_sensor); - } -} -/*---------------------------------------------------------------------------*/ -static int -button_value(int type, uint8_t pin, BtnTimer *btn_timer) -{ - switch (type) { - case BUTTON_SENSOR_TYPE_STATE: - return (PIN_getInputValue(pin) == 0) - ? BUTTON_SENSOR_VALUE_PRESSED - : BUTTON_SENSOR_VALUE_RELEASED; - - case BUTTON_SENSOR_TYPE_DURATION: - return (int)btn_timer->duration; - - default: - return 0; - } -} -/*---------------------------------------------------------------------------*/ -static int -button_config(int type, int value, uint8_t pin) -{ - switch (type) { - case SENSORS_HW_INIT: - // Open PIN handle - if (pin_handle) { - return 1; - } - pin_handle = PIN_open(&pin_state, btn_pin_table); - if (!pin_handle) { - return 0; - } - // Register button callback function - PIN_registerIntCb(pin_handle, button_press_cb); - break; - - case SENSORS_ACTIVE: - if (value) { - // Enable interrupts on both edges - PIN_setInterrupt(pin_handle, pin | PIN_IRQ_BOTHEDGES); - } else { - // Disable pin interrupts - PIN_setInterrupt(pin_handle, pin | PIN_IRQ_DIS); - } - break; - } - - return 1; -} -/*---------------------------------------------------------------------------*/ -static int -button_status(int type, uint8_t pin) -{ - switch(type) { - case SENSORS_ACTIVE: /* fallthrough */ - case SENSORS_READY: { - PIN_Config pin_cfg = PIN_getConfig(pin); - return (pin_cfg & PIN_BM_IRQ) == PIN_IRQ_DIS; - } - default: break; - } - return 0; -} -/*---------------------------------------------------------------------------*/ -static int -btn1_value(int type) -{ - return button_value(type, BTN1_PIN, &btn1_timer); -} -/*---------------------------------------------------------------------------*/ -static int -btn1_config(int type, int value) -{ - return button_config(type, value, BTN1_PIN); -} -/*---------------------------------------------------------------------------*/ -static int -btn1_status(int type) -{ - return button_status(type, BTN1_PIN); -} -/*---------------------------------------------------------------------------*/ -static int -btn2_value(int type) -{ - return button_value(type, BTN2_PIN, &btn2_timer); -} -/*---------------------------------------------------------------------------*/ -static int -btn2_config(int type, int value) -{ - return button_config(type, value, BTN2_PIN); -} -/*---------------------------------------------------------------------------*/ -static int -btn2_status(int type) -{ - return button_status(type, BTN2_PIN); -} -/*---------------------------------------------------------------------------*/ -SENSORS_SENSOR(button_left_sensor, BUTTON_SENSOR, btn1_value, btn1_config, btn1_status); -SENSORS_SENSOR(button_right_sensor, BUTTON_SENSOR, btn2_value, btn2_config, btn2_status); +BUTTON_HAL_BUTTONS(&key_left, &key_right); /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Board.h index 66afbb6c6..30aafeffe 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Board.h @@ -41,24 +41,10 @@ extern "C" { #include "CC1310_LAUNCHXL.h" -#define Board_initGeneral() CC1310_LAUNCHXL_initGeneral() +#define Board_initGeneral() CC1310_LAUNCHXL_initGeneral() #define Board_shutDownExtFlash() CC1310_LAUNCHXL_shutDownExtFlash() -#define Board_wakeUpExtFlash() CC1310_LAUNCHXL_wakeUpExtFlash() +#define Board_wakeUpExtFlash() CC1310_LAUNCHXL_wakeUpExtFlash() -/*---------------------------------------------------------------------------*/ -/** - * \name LED configurations - * - * Those values are not meant to be modified by the user - * @{ - */ -#define LEDS_RED (1 << 0) -#define LEDS_GREEN (1 << 1) -#define LEDS_YELLOW LEDS_GREEN -#define LEDS_ORANGE LEDS_RED - -#define LEDS_CONF_ALL (LEDS_RED | LEDS_GREEN) -/*---------------------------------------------------------------------------*/ /* These #defines allow us to reuse TI-RTOS across other device families */ #define Board_ADC0 CC1310_LAUNCHXL_ADC0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Board.h index 77179e057..3a08792dd 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Board.h @@ -41,24 +41,10 @@ extern "C" { #include "CC1312R1_LAUNCHXL.h" -#define Board_initGeneral() CC1312R1_LAUNCHXL_initGeneral() +#define Board_initGeneral() CC1312R1_LAUNCHXL_initGeneral() #define Board_shutDownExtFlash() CC1312R1_LAUNCHXL_shutDownExtFlash() -#define Board_wakeUpExtFlash() CC1312R1_LAUNCHXL_wakeUpExtFlash() +#define Board_wakeUpExtFlash() CC1312R1_LAUNCHXL_wakeUpExtFlash() -/*---------------------------------------------------------------------------*/ -/** - * \name LED configurations - * - * Those values are not meant to be modified by the user - * @{ - */ -#define LEDS_RED (1 << 0) -#define LEDS_GREEN (1 << 1) -#define LEDS_YELLOW LEDS_GREEN -#define LEDS_ORANGE LEDS_RED - -#define LEDS_CONF_ALL (LEDS_RED | LEDS_GREEN) -/*---------------------------------------------------------------------------*/ /* These #defines allow us to reuse TI-RTOS across other device families */ #define Board_ADC0 CC1312R1_LAUNCHXL_ADC0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Board.h index 3859a6d26..394f3a3cd 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Board.h @@ -45,20 +45,6 @@ extern "C" { #define Board_shutDownExtFlash() CC1350_LAUNCHXL_433_shutDownExtFlash() #define Board_wakeUpExtFlash() CC1350_LAUNCHXL_433_wakeUpExtFlash() -/*---------------------------------------------------------------------------*/ -/** - * \name LED configurations - * - * Those values are not meant to be modified by the user - * @{ - */ -#define LEDS_RED (1 << 0) -#define LEDS_GREEN (1 << 1) -#define LEDS_YELLOW LEDS_GREEN -#define LEDS_ORANGE LEDS_RED - -#define LEDS_CONF_ALL (LEDS_RED | LEDS_GREEN) -/*---------------------------------------------------------------------------*/ /* These #defines allow us to reuse TI-RTOS across other device families */ #define Board_ADC0 CC1350_LAUNCHXL_433_ADC0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Makefile.cc1350-4 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Makefile.cc1350-4 index 659621677..620b36fb6 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Makefile.cc1350-4 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Makefile.cc1350-4 @@ -5,7 +5,7 @@ SUBFAMILY = cc13x0-cc26x0 DEVICE_FAMILY = CC13X0 DEVICE_LINE = CC13XX -BOARD_SOURCEFILES += CC1350_LAUNCHXL_433.c CC1310_LAUNCHXL_433_fxns.c +BOARD_SOURCEFILES += CC1350_LAUNCHXL_433.c CC1350_LAUNCHXL_433_fxns.c SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Board.h index 0e8542d00..a695a57cc 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Board.h @@ -45,21 +45,8 @@ extern "C" { #define Board_shutDownExtFlash() CC1350_LAUNCHXL_shutDownExtFlash() #define Board_wakeUpExtFlash() CC1350_LAUNCHXL_wakeUpExtFlash() -/*---------------------------------------------------------------------------*/ -/** - * \name LED configurations - * - * Those values are not meant to be modified by the user - * @{ - */ -#define LEDS_RED (1 << 0) -#define LEDS_GREEN (1 << 1) -#define LEDS_YELLOW LEDS_GREEN -#define LEDS_ORANGE LEDS_RED - -#define LEDS_CONF_ALL (LEDS_RED | LEDS_GREEN) -/*---------------------------------------------------------------------------*/ /* These #defines allow us to reuse TI-RTOS across other device families */ + #define Board_ADC0 CC1350_LAUNCHXL_ADC0 #define Board_ADC1 CC1350_LAUNCHXL_ADC1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/Board.h similarity index 94% rename from arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/Board.h rename to arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/Board.h index e251723cd..7fe300916 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/Board.h @@ -45,20 +45,6 @@ extern "C" { #define Board_shutDownExtFlash() CC1352P_2_LAUNCHXL_shutDownExtFlash() #define Board_wakeUpExtFlash() CC1352P_2_LAUNCHXL_wakeUpExtFlash() -/*---------------------------------------------------------------------------*/ -/** - * \name LED configurations - * - * Those values are not meant to be modified by the user - * @{ - */ -#define LEDS_RED (1 << 0) -#define LEDS_GREEN (1 << 1) -#define LEDS_YELLOW LEDS_GREEN -#define LEDS_ORANGE LEDS_RED - -#define LEDS_CONF_ALL (LEDS_RED | LEDS_GREEN) -/*---------------------------------------------------------------------------*/ /* These #defines allow us to reuse TI-RTOS across other device families */ #define Board_ADC0 CC1352P_2_LAUNCHXL_ADC0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/CC1352P_2_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.c similarity index 100% rename from arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/CC1352P_2_LAUNCHXL.c rename to arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.c diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/CC1352P_2_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h similarity index 100% rename from arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/CC1352P_2_LAUNCHXL.h rename to arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/CC1352P_2_LAUNCHXL_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL_fxns.c similarity index 100% rename from arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/CC1352P_2_LAUNCHXL_fxns.c rename to arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL_fxns.c diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/Makefile.cc1352p_2 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/Makefile.cc1352p-2 similarity index 100% rename from arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_2/Makefile.cc1352p_2 rename to arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/Makefile.cc1352p-2 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/Board.h similarity index 94% rename from arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/Board.h rename to arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/Board.h index f36390cea..752f8d88f 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/Board.h @@ -45,20 +45,6 @@ extern "C" { #define Board_shutDownExtFlash() CC1352P_4_LAUNCHXL_shutDownExtFlash() #define Board_wakeUpExtFlash() CC1352P_4_LAUNCHXL_wakeUpExtFlash() -/*---------------------------------------------------------------------------*/ -/** - * \name LED configurations - * - * Those values are not meant to be modified by the user - * @{ - */ -#define LEDS_RED (1 << 0) -#define LEDS_GREEN (1 << 1) -#define LEDS_YELLOW LEDS_GREEN -#define LEDS_ORANGE LEDS_RED - -#define LEDS_CONF_ALL (LEDS_RED | LEDS_GREEN) -/*---------------------------------------------------------------------------*/ /* These #defines allow us to reuse TI-RTOS across other device families */ #define Board_ADC0 CC1352P_4_LAUNCHXL_ADC0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/CC1352P_4_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.c similarity index 100% rename from arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/CC1352P_4_LAUNCHXL.c rename to arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.c diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/CC1352P_4_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.h similarity index 100% rename from arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/CC1352P_4_LAUNCHXL.h rename to arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.h diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/CC1352P_4_LAUNCHXL_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL_fxns.c similarity index 100% rename from arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/CC1352P_4_LAUNCHXL_fxns.c rename to arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL_fxns.c diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/Makefile.cc1352p_4 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/Makefile.cc1352p-4 similarity index 100% rename from arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p_4/Makefile.cc1352p_4 rename to arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/Makefile.cc1352p-4 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Board.h index a74df419a..c078fe636 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Board.h @@ -45,20 +45,6 @@ extern "C" { #define Board_shutDownExtFlash() CC1352P1_LAUNCHXL_shutDownExtFlash() #define Board_wakeUpExtFlash() CC1352P1_LAUNCHXL_wakeUpExtFlash() -/*---------------------------------------------------------------------------*/ -/** - * \name LED configurations - * - * Those values are not meant to be modified by the user - * @{ - */ -#define LEDS_RED (1 << 0) -#define LEDS_GREEN (1 << 1) -#define LEDS_YELLOW LEDS_GREEN -#define LEDS_ORANGE LEDS_RED - -#define LEDS_CONF_ALL (LEDS_RED | LEDS_GREEN) -/*---------------------------------------------------------------------------*/ /* These #defines allow us to reuse TI-RTOS across other device families */ #define Board_ADC0 CC1352P1_LAUNCHXL_ADC0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 index 0dbb6622e..9ea537df7 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 @@ -5,7 +5,7 @@ SUBFAMILY = cc13x2-cc26x2 DEVICE_FAMILY = CC13X2 DEVICE_LINE = CC13XX -BOARD_SOURCEFILES += CC1352P1_LAUNCHXL.c CC1312P1_LAUNCHXL_fxns.c +BOARD_SOURCEFILES += CC1352P1_LAUNCHXL.c CC1352P1_LAUNCHXL_fxns.c DEFINES += PROP_MODE_CONF_TX_POWER_TABLE=rf_prop_tx_power_table_default_pa DEFINES += PROP_MODE_CONF_TX_POWER_TABLE_SIZE=RF_PROP_TX_POWER_TABLE_DEFAULT_PA_SIZE diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h index 148f96146..9cc52d689 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h @@ -45,20 +45,6 @@ extern "C" { #define Board_shutDownExtFlash() CC1352R1_LAUNCHXL_shutDownExtFlash() #define Board_wakeUpExtFlash() CC1352R1_LAUNCHXL_wakeUpExtFlash() -/*---------------------------------------------------------------------------*/ -/** - * \name LED configurations - * - * Those values are not meant to be modified by the user - * @{ - */ -#define LEDS_CONF_COUNT 2 - -#define LEDS_CONF_RED 0 -#define LEDS_CONF_GREEN 1 - -#define LEDS_CONF_ALL ((1 << LEDS_CONF_COUNT) - 1) -/*---------------------------------------------------------------------------*/ /* These #defines allow us to reuse TI-RTOS across other device families */ #define Board_ADC0 CC1352R1_LAUNCHXL_ADC0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Board.h index 07668d60f..5088d0ea6 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Board.h @@ -45,21 +45,8 @@ extern "C" { #define Board_shutDownExtFlash() CC2650_LAUNCHXL_shutDownExtFlash() #define Board_wakeUpExtFlash() CC2650_LAUNCHXL_wakeUpExtFlash() -/*---------------------------------------------------------------------------*/ -/** - * \name LED configurations - * - * Those values are not meant to be modified by the user - * @{ - */ -#define LEDS_RED (1 << 0) -#define LEDS_GREEN (1 << 1) -#define LEDS_YELLOW LEDS_GREEN -#define LEDS_ORANGE LEDS_RED - -#define LEDS_CONF_ALL (LEDS_RED | LEDS_GREEN) -/*---------------------------------------------------------------------------*/ /* These #defines allow us to reuse TI-RTOS across other device families */ + #define Board_ADC0 CC2650_LAUNCHXL_ADC0 #define Board_ADC1 CC2650_LAUNCHXL_ADC1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Board.h index c984f711b..8940527b9 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Board.h @@ -47,20 +47,6 @@ extern "C" { #define Board_wakeUpExtFlash() CC26X2R1_LAUNCHXL_wakeUpExtFlash() -/*---------------------------------------------------------------------------*/ -/** - * \name LED configurations - * - * Those values are not meant to be modified by the user - * @{ - */ -#define LEDS_RED (1 << 0) -#define LEDS_GREEN (1 << 1) -#define LEDS_YELLOW LEDS_GREEN -#define LEDS_ORANGE LEDS_RED - -#define LEDS_CONF_ALL (LEDS_RED | LEDS_GREEN) -/*---------------------------------------------------------------------------*/ /* These #defines allow us to reuse TI-RTOS across other device families */ #define Board_ADC0 CC26X2R1_LAUNCHXL_ADC0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/launchpad-sensors.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/launchpad-sensors.c deleted file mode 100644 index af783f88a..000000000 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/launchpad-sensors.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/*---------------------------------------------------------------------------*/ -/** - * \addtogroup simplelink-peripherals - * @{ - * - * \file - * Generic module controlling Simplelink sensors - */ -/*---------------------------------------------------------------------------*/ -#include -#include -/*---------------------------------------------------------------------------*/ -#include "button-sensor.h" -/*---------------------------------------------------------------------------*/ -/* Exports a global symbol to be used by the sensor API */ -SENSORS( - &button_left_sensor, - &button_right_sensor, - NULL -); -/*---------------------------------------------------------------------------*/ -/** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/platform.c b/arch/platform/simplelink/cc13xx-cc26xx/platform.c index a773d3ff0..948f5e589 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/platform.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/platform.c @@ -71,6 +71,7 @@ #include "sys/rtimer.h" #include "sys/node-id.h" #include "sys/platform.h" +#include "dev/button-hal.h" #include "dev/gpio-hal.h" #include "dev/serial-line.h" #include "dev/leds.h" @@ -78,6 +79,7 @@ #include "lib/sensors.h" /*---------------------------------------------------------------------------*/ /* Arch driver implementations */ +#include "board-peripherals.h" #include "uart0-arch.h" /*---------------------------------------------------------------------------*/ #include "ieee-addr.h" @@ -101,6 +103,12 @@ unsigned short g_nodeId = 0; */ extern void Board_initHook(void); /*---------------------------------------------------------------------------*/ +#ifdef BOARD_CONF_HAS_SENSORS +#define BOARD_HAS_SENSORS BOARD_CONF_HAS_SENSORS +#else +#define BOARD_HAS_SENSORS 1 +#endif +/*---------------------------------------------------------------------------*/ static void fade(unsigned char l) { @@ -186,6 +194,8 @@ platform_init_stage_two(void) /* Populate linkaddr_node_addr */ ieee_addr_cpy_to(linkaddr_node_addr.u8, LINKADDR_SIZE); + button_hal_init(); + fade(LEDS_RED); } /*---------------------------------------------------------------------------*/ @@ -211,7 +221,9 @@ platform_init_stage_three(void) LOG_INFO("RF: Channel %d, PANID 0x%04X\n", chan, pan); LOG_INFO("Node ID: %d\n", g_nodeId); +#if BOARD_HAS_SENSORS process_start(&sensors_process, NULL); +#endif fade(LEDS_GREEN); } diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/Makefile.sensortag b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/Makefile.sensortag index 42d91898e..31da88d0a 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/Makefile.sensortag +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/Makefile.sensortag @@ -6,11 +6,10 @@ BOARD_TYPE = BOARD_SENSORTAG PLATFORM_HAS_BUTTON = 1 # leds-arch.c/h etc. -BOARD_SOURCEFILES += sensortag.c sensortag-sensors.c -BOARD_SOURCEFILES += button-sensor-arch.c leds-arch.c +BOARD_SOURCEFILES += sensortag-sensors.c +BOARD_SOURCEFILES += button-sensor-arch.c ext-flash.c BOARD_SOURCEFILES += bmp-280-sensor.c hdc-1000-sensor.c BOARD_SOURCEFILES += mpu-9250-sensor.c opt-3001-sensor.c -BOARD_SOURCEFILES += reed-relay.c tmp-007-sensor.c -BOARD_SOURCEFILES += buzzer.c +BOARD_SOURCEFILES += tmp-007-sensor.c buzzer.c TARGET_FAMILY_DIRS += sensortag \ No newline at end of file diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/reed-relay.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h similarity index 77% rename from arch/platform/simplelink/cc13xx-cc26xx/sensortag/reed-relay.h rename to arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h index e1a55eabc..1bd6b92c6 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/reed-relay.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h @@ -28,32 +28,33 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /*---------------------------------------------------------------------------*/ -/** - * \addtogroup sensortag-cc26xx-peripherals +/** \addtogroup cc26xx-srf-tag * @{ * - * \defgroup sensortag-cc26xx-reed-relay SensorTag 2.0 Reed Relay + * \defgroup sensortag-cc26xx-peripherals Sensortag CC1350/CC2650 common * - * The reed relay acts like a button without a button. To trigger the reed, - * approach a magnet to the sensortag and a sensors_changed event will be - * generated, in a fashion similar to as if a button had been pressed + * Defines related to Sensortag sensors. The two sensortags are identical to a + * very large extent. Everything documented within this group applies to both + * sensortags. * * @{ * * \file - * Header file for the Sensortag Reed Relay + * Header file with definitions related to the sensors on the Sensortags + * + * \note Do not include this file directly. */ /*---------------------------------------------------------------------------*/ -#ifndef REED_RELAY_H -#define REED_RELAY_H +#ifndef BOARD_CONF_H_ +#define BOARD_CONF_H_ /*---------------------------------------------------------------------------*/ -#include "lib/sensors.h" +#include "leds-arch.h" /*---------------------------------------------------------------------------*/ -#define REED_RELAY_READING_ERROR -1 +#define BUTTON_HAL_ID_KEY_LEFT 0 +#define BUTTON_HAL_ID_KEY_RIGHT 1 +#define BUTTON_HAL_ID_REED_RELAY 2 /*---------------------------------------------------------------------------*/ -extern const struct sensors_sensor reed_relay_sensor; -/*---------------------------------------------------------------------------*/ -#endif /* REED_RELAY_H */ +#endif /* BOARD_CONF_H_ */ /*---------------------------------------------------------------------------*/ /** * @} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-peripherals.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-peripherals.h index 42e22d4c8..403428872 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-peripherals.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-peripherals.h @@ -53,10 +53,13 @@ #include "opt-3001-sensor.h" #include "hdc-1000-sensor.h" #include "mpu-9250-sensor.h" -#include "reed-relay.h" #include "buzzer.h" #include "ext-flash.h" /*---------------------------------------------------------------------------*/ +#include "board-conf.h" +/*---------------------------------------------------------------------------*/ +#define BOARD_CONF_HAS_SENSORS 1 +/*---------------------------------------------------------------------------*/ #endif /* BOARD_PERIPHERALS_H_ */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor-arch.c index 6e581f646..5c4cc20f4 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor-arch.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor-arch.c @@ -36,163 +36,37 @@ * Driver for LaunchPad buttons */ /*---------------------------------------------------------------------------*/ -#include -#include -#include -/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "dev/button-hal.h" + #include -#include -#include /*---------------------------------------------------------------------------*/ -#include -/*---------------------------------------------------------------------------*/ -#include "button-sensor.h" -#include "button-sensor-arch.h" -/*---------------------------------------------------------------------------*/ -/* Sensortag has 2 buttons: BTN1 and BTN2 */ -/* Map the GPIO defines from the Board file */ -#define BTN1_GPIO Board_KEY_LEFT -#define BTN2_GPIO Board_KEY_RIGHT -/*---------------------------------------------------------------------------*/ -#ifdef BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN -# define BUTTON_SENSOR_ENABLE_SHUTDOWN BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN -#else -# define BUTTON_SENSOR_ENABLE_SHUTDOWN 1 -#endif -/*---------------------------------------------------------------------------*/ -#define DEBOUNCE_DURATION (CLOCK_SECOND >> 5) -/*---------------------------------------------------------------------------*/ -typedef struct { - struct timer debounce; - clock_time_t start; - clock_time_t duration; -} BtnTimer; -/*---------------------------------------------------------------------------*/ -static BtnTimer g_btn1Timer; -static BtnTimer g_btn2Timer; -/*---------------------------------------------------------------------------*/ -static void -button_press_cb(uint8_t index, BtnTimer *btnTimer, const struct sensors_sensor *btnSensor) -{ - if (!timer_expired(&btnTimer->debounce)) { - return; - } +/* Key left button, AKA BTN-1 */ +BUTTON_HAL_BUTTON(key_left, /**< Name */ + "Key Left", /**< Description */ + Board_KEY_LEFT, /**< PIN */ + GPIO_HAL_PIN_CFG_INPUT_PULLUP | + GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_KEY_LEFT, /**< Unique ID */ + true); /**< Negative logic */ - timer_set(&btnTimer->debounce, DEBOUNCE_DURATION); +/* Key right button, AKA BTN-2 */ +BUTTON_HAL_BUTTON(key_right, /**< Name */ + "Key Right", /**< Description */ + Board_KEY_RIGHT, /**< PIN */ + GPIO_HAL_PIN_CFG_INPUT_PULLUP | + GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_KEY_RIGHT, /**< Unique ID */ + true); /**< Negative logic */ - // Start press duration counter on press (falling), notify on release (rising) - if (GPIO_read(index) == 0) { - btnTimer->start = clock_time(); - btnTimer->duration = 0; - } else { - btnTimer->duration = clock_time() - btnTimer->start; - sensors_changed(btnSensor); - } -} +BUTTON_HAL_BUTTON(reed_relay, /**< Name */ + "Reed Relay", /**< Description */ + Board_RELAY, /**< PIN */ + GPIO_HAL_PIN_CFG_INPUT_PULLDOWN | + GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_REED_RELAY, /**< Unique ID */ + true); /**< Negative logic */ /*---------------------------------------------------------------------------*/ -static int -button_value(int type, uint8_t index, BtnTimer *btnTimer) -{ - if (type == BUTTON_SENSOR_VALUE_STATE) { - return (GPIO_read(index) == 0) - ? BUTTON_SENSOR_VALUE_PRESSED - : BUTTON_SENSOR_VALUE_RELEASED; - } else if (type == BUTTON_SENSOR_VALUE_DURATION) { - return (int)btnTimer->duration; - } - return 0; -} -/*---------------------------------------------------------------------------*/ -static int -button_config(int type, int value, uint8_t index, GPIO_CallbackFxn callback) -{ - switch (type) { - case SENSORS_HW_INIT: - GPIO_clearInt(index); - GPIO_setCallback(index, callback); - break; - - case SENSORS_ACTIVE: - if (value) { - GPIO_clearInt(index); - GPIO_enableInt(index); - } else { - GPIO_disableInt(index); - } - break; - } - - return 1; -} -/*---------------------------------------------------------------------------*/ -static int -button_status(int type, uint8_t index) -{ - switch(type) { - case SENSORS_ACTIVE: /* fallthrough */ - case SENSORS_READY: { - GPIO_PinConfig pinCfg = 0; - GPIO_getConfig(index, &pinCfg); - return (pinCfg & GPIO_CFG_IN_INT_NONE) == 0; - } - } - return 0; -} -/*---------------------------------------------------------------------------*/ -static void -btn1_press_cb(unsigned char unusued) -{ - button_press_cb(BTN1_GPIO, &g_btn1Timer, &btn1_sensor); -} -/*---------------------------------------------------------------------------*/ -static int -btn1_value(int type) -{ - return button_value(type, BTN1_GPIO, &g_btn1Timer); -} -/*---------------------------------------------------------------------------*/ -static int -btn1_config(int type, int value) -{ - return button_config(type, value, BTN1_GPIO, btn1_press_cb); -} -/*---------------------------------------------------------------------------*/ -static int -btn1_status(int type) -{ - return button_status(type, BTN1_GPIO); -} -/*---------------------------------------------------------------------------*/ -static void -btn2_press_cb(unsigned char unusued) -{ - if (BUTTON_SENSOR_ENABLE_SHUTDOWN) { - Power_shutdown(Power_ENTERING_SHUTDOWN, 0); - return; - } - - button_press_cb(BTN2_GPIO, &g_btn2Timer, &btn2_sensor); -} -/*---------------------------------------------------------------------------*/ -static int -btn2_value(int type) -{ - return button_value(type, BTN2_GPIO, &g_btn2Timer); -} -/*---------------------------------------------------------------------------*/ -static int -btn2_config(int type, int value) -{ - return button_config(type, value, BTN2_GPIO, btn2_press_cb); -} -/*---------------------------------------------------------------------------*/ -static int -btn2_status(int type) -{ - return button_status(type, BTN1_GPIO); -} -/*---------------------------------------------------------------------------*/ -SENSORS_SENSOR(btn1_sensor, BUTTON_SENSOR, btn1_value, btn1_config, btn1_status); -SENSORS_SENSOR(btn2_sensor, BUTTON_SENSOR, btn2_value, btn2_config, btn2_status); +BUTTON_HAL_BUTTONS(&key_left, &key_right, &reed_relay); /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h index 0ef38605b..58e661f78 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h @@ -41,24 +41,10 @@ extern "C" { #include "CC1350STK.h" -#define Board_initGeneral() CC1350STK_initGeneral() +#define Board_initGeneral() CC1350STK_initGeneral() #define Board_shutDownExtFlash() CC1350STK_shutDownExtFlash() -#define Board_wakeUpExtFlash() CC1350STK_wakeUpExtFlash() +#define Board_wakeUpExtFlash() CC1350STK_wakeUpExtFlash() -/*---------------------------------------------------------------------------*/ -/** - * \name LED configurations - * - * Those values are not meant to be modified by the user - * @{ - */ -#define LEDS_RED (1 << 0) -#define LEDS_GREEN LEDS_RED -#define LEDS_YELLOW LEDS_RED -#define LEDS_ORANGE LEDS_RED - -#define LEDS_CONF_ALL (LEDS_RED) -/*---------------------------------------------------------------------------*/ /* These #defines allow us to reuse TI-RTOS across other device families */ #define Board_BUZZER CC1350STK_BUZZER diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/leds-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/leds-arch.c index 227f79908..e391b0179 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/leds-arch.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/leds-arch.c @@ -37,61 +37,16 @@ */ /*---------------------------------------------------------------------------*/ /* Contiki API */ -#include -#include +#include "contiki.h" +#include "dev/leds.h" /*---------------------------------------------------------------------------*/ /* Simplelink SDK API */ #include - -#include /*---------------------------------------------------------------------------*/ -/* Standard library */ #include -#include /*---------------------------------------------------------------------------*/ -static const PIN_Config pin_table[] = { - Board_PIN_LED0 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, - PIN_TERMINATE +const leds_t leds_arch_leds[] = { + { .pin = Board_PIN_LED0, .negative_logic = false }, }; - -static PIN_State pin_state; -static PIN_Handle pin_handle; - -static volatile unsigned char c; -/*---------------------------------------------------------------------------*/ -void -leds_arch_init(void) -{ - static bool bHasInit = false; - if(bHasInit) { - return; - } - - // PIN_init() called from Board_initGeneral() - pin_handle = PIN_open(&pin_state, pin_table); - if (!pin_handle) { - return; - } - - bHasInit = true; -} -/*---------------------------------------------------------------------------*/ -unsigned char -leds_arch_get(void) -{ - return c; -} -/*---------------------------------------------------------------------------*/ -void -leds_arch_set(unsigned char leds) -{ - c = leds; - - PIN_setPortOutputValue(pin_handle, 0); - - if (leds & LEDS_RED) { - PIN_setOutputValue(pin_handle, Board_PIN_LED0, 1); - } -} /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/launchpad.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/leds-arch.h similarity index 77% rename from arch/platform/simplelink/cc13xx-cc26xx/launchpad/launchpad.c rename to arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/leds-arch.h index 469dea72d..14b15d048 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/launchpad.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/leds-arch.h @@ -28,34 +28,39 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /*---------------------------------------------------------------------------*/ -/** - * \addtogroup launchpad-peripherals +/** \addtogroup cc26xx-srf-tag + * @{ + * + * \defgroup launchpad-peripherals LaunchPad peripherals + * + * Defines related to LaunchPad peripherals. + * * @{ * * \file - * LaunchPad-specific board initialisation driver + * Header file with definitions related to LaunchPad peripherals + * + * \note Do not include this file directly. */ /*---------------------------------------------------------------------------*/ -#include "contiki.h" +#ifndef LEDS_ARCH_H_ +#define LEDS_ARCH_H_ /*---------------------------------------------------------------------------*/ -#include "Board.h" -#include "ti/drivers/dpl/HwiP.h" -/*---------------------------------------------------------------------------*/ -#include -#include -#include -/*---------------------------------------------------------------------------*/ -void -board_init() -{ - /* Disable interrupts */ - const uintptr_t key = HwiP_disable(); +/** + * \name LED configurations + * + * Those values are not meant to be modified by the user + * @{ + */ +#define LEDS_CONF_COUNT 1 - Board_initGeneral(); - Board_shutDownExtFlash(); +#define LEDS_CONF_RED 0 - /* Restore interrupts. */ - HwiP_restore(key); -} +#define LEDS_CONF_ALL ((1 << LEDS_CONF_COUNT) - 1) /*---------------------------------------------------------------------------*/ -/** @} */ +#endif /* LEDS_ARCH_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h index db34c35d3..830bbf63c 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h @@ -41,24 +41,10 @@ extern "C" { #include "CC2650STK.h" -#define Board_initGeneral() CC2650STK_initGeneral() +#define Board_initGeneral() CC2650STK_initGeneral() #define Board_shutDownExtFlash() CC2650STK_shutDownExtFlash() -#define Board_wakeUpExtFlash() CC2650STK_wakeUpExtFlash() +#define Board_wakeUpExtFlash() CC2650STK_wakeUpExtFlash() -/*---------------------------------------------------------------------------*/ -/** - * \name LED configurations - * - * Those values are not meant to be modified by the user - * @{ - */ -#define LEDS_RED (1 << 0) -#define LEDS_GREEN (1 << 1) -#define LEDS_YELLOW LEDS_GREEN -#define LEDS_ORANGE LEDS_RED - -#define LEDS_CONF_ALL (LEDS_RED | LEDS_GREEN) -/*---------------------------------------------------------------------------*/ /* These #defines allow us to reuse TI-RTOS across other device families */ #define Board_BUZZER CC2650STK_BUZZER diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/leds-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/leds-arch.c index 463349854..3078ea040 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/leds-arch.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/leds-arch.c @@ -37,66 +37,17 @@ */ /*---------------------------------------------------------------------------*/ /* Contiki API */ -#include -#include +#include "contiki.h" +#include "dev/leds.h" /*---------------------------------------------------------------------------*/ /* Simplelink SDK API */ #include - -#include /*---------------------------------------------------------------------------*/ -/* Standard library */ #include -#include /*---------------------------------------------------------------------------*/ -static const PIN_Config pin_table[] = { - Board_PIN_LED0 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, - Board_PIN_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, - PIN_TERMINATE +const leds_t leds_arch_leds[] = { + { .pin = Board_PIN_LED0, .negative_logic = false }, + { .pin = Board_PIN_LED1, .negative_logic = false }, }; - -static PIN_State pin_state; -static PIN_Handle pin_handle; - -static volatile unsigned char c; -/*---------------------------------------------------------------------------*/ -void -leds_arch_init(void) -{ - static bool bHasInit = false; - if(bHasInit) { - return; - } - - // PIN_init() called from Board_initGeneral() - pin_handle = PIN_open(&pin_state, pin_table); - if (!pin_handle) { - return; - } - - bHasInit = true; -} -/*---------------------------------------------------------------------------*/ -unsigned char -leds_arch_get(void) -{ - return c; -} -/*---------------------------------------------------------------------------*/ -void -leds_arch_set(unsigned char leds) -{ - c = leds; - - PIN_setPortOutputValue(pin_handle, 0); - - if (leds & LEDS_RED) { - PIN_setOutputValue(pin_handle, Board_PIN_LED0, 1); - } - - if (leds & LEDS_GREEN) { - PIN_setOutputValue(pin_handle, Board_PIN_LED1, 1); - } -} /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor-arch.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/leds-arch.h similarity index 74% rename from arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor-arch.h rename to arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/leds-arch.h index abcb3ef34..e002e7650 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor-arch.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/leds-arch.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,29 +28,38 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /*---------------------------------------------------------------------------*/ -/** - * \addtogroup simplelink-platform +/** \addtogroup cc26xx-srf-tag * @{ * - * \defgroup simplelink-button-sensor Simplelink Button Driver + * \defgroup launchpad-peripherals LaunchPad peripherals + * + * Defines related to LaunchPad peripherals. * - * One of the buttons can be configured as general purpose or as an on/off key * @{ * * \file - * Header file for the Simplelink Button Driver + * Header file with definitions related to LaunchPad peripherals + * + * \note Do not include this file directly. */ /*---------------------------------------------------------------------------*/ -#ifndef BUTTON_SENSOR_ARCH_H_ -#define BUTTON_SENSOR_ARCH_H_ +#ifndef LEDS_ARCH_H_ +#define LEDS_ARCH_H_ /*---------------------------------------------------------------------------*/ -/* Contiki API */ -#include "lib/sensors.h" +/** + * \name LED configurations + * + * Those values are not meant to be modified by the user + * @{ + */ +#define LEDS_CONF_COUNT 2 + +#define LEDS_CONF_RED 0 +#define LEDS_CONF_GREEN 1 + +#define LEDS_CONF_ALL ((1 << LEDS_CONF_COUNT) - 1) /*---------------------------------------------------------------------------*/ -extern const struct sensors_sensor btn1_sensor; -extern const struct sensors_sensor btn2_sensor; -/*---------------------------------------------------------------------------*/ -#endif /* BUTTON_SENSOR_ARCH_H_ */ +#endif /* LEDS_ARCH_H_ */ /*---------------------------------------------------------------------------*/ /** * @} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/ext-flash.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/ext-flash.c new file mode 100644 index 000000000..a78a5e764 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/ext-flash.c @@ -0,0 +1,468 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup sensortag-cc26xx-ext-flash + * @{ + * + * \file + * Sensortag/LaunchPad External Flash Driver + */ +/*---------------------------------------------------------------------------*/ +#include +#include +#include +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "ext-flash.h" +#include "ti-lib.h" +/*---------------------------------------------------------------------------*/ +#include +#include +#include +/*---------------------------------------------------------------------------*/ +static PIN_Config pin_table[] = { + Board_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, + PIN_TERMINATE +}; + +static PIN_State pin_state; +static PIN_Handle pin_handle; + +static SPI_Handle spi_handle; + +static bool ext_flash_opened; +/*---------------------------------------------------------------------------*/ +#define SPI_BIT_RATE 4000000 + +/* Instruction codes */ +#define BLS_CODE_PROGRAM 0x02 /**< Page Program */ +#define BLS_CODE_READ 0x03 /**< Read Data */ +#define BLS_CODE_READ_STATUS 0x05 /**< Read Status Register */ +#define BLS_CODE_WRITE_ENABLE 0x06 /**< Write Enable */ +#define BLS_CODE_SECTOR_ERASE 0x20 /**< Sector Erase */ +#define BLS_CODE_MDID 0x90 /**< Manufacturer Device ID */ + +#define BLS_CODE_DP 0xB9 /**< Power down */ +#define BLS_CODE_RDP 0xAB /**< Power standby */ + +/* Erase instructions */ +#define BLS_CODE_ERASE_4K 0x20 /**< Sector Erase */ +#define BLS_CODE_ERASE_32K 0x52 +#define BLS_CODE_ERASE_64K 0xD8 +#define BLS_CODE_ERASE_ALL 0xC7 /**< Mass Erase */ + +/* Bitmasks of the status register */ +#define BLS_STATUS_SRWD_BM 0x80 +#define BLS_STATUS_BP_BM 0x0C +#define BLS_STATUS_WEL_BM 0x02 +#define BLS_STATUS_WIP_BM 0x01 + +#define BLS_STATUS_BIT_BUSY 0x01 /**< Busy bit of the status register */ + +/* Part specific constants */ +#define BLS_PROGRAM_PAGE_SIZE 0x100 /**< Page size 0x100 */ +#define BLS_ERASE_SECTOR_SIZE 0x1000 /**< Sector size 0x1000 */ +/*---------------------------------------------------------------------------*/ +typedef struct +{ + uint8_t manfId; /**< Manufacturer ID */ + uint8_t devId; /**< Device ID */ +} ExtFlashInfo; +/* Supported flash devices */ +static const ExtFlashInfo supported_devices[] = +{ + { + .manfId = 0xC2, /**< Macronics MX25R1635F */ + .devId = 0x15 + }, + { + .manfId = 0xC2, /**< Macronics MX25R8035F */ + .devId = 0x14 + }, + { + .manfId = 0xEF, /**< WinBond W25X40CL */ + .devId = 0x12 + }, + { + .manfId = 0xEF, /**< WinBond W25X20CL */ + .devId = 0x11 + } +}; +/*---------------------------------------------------------------------------*/ +static bool +spi_write(const uint8_t *buf, size_t len) +{ + SPI_Transaction spiTransaction; + spiTransaction.count = len; + spiTransaction.txBuf = (void *)buf; + spiTransaction.rxBuf = NULL; + + return SPI_transfer(spi_handle, &spiTransaction); +} +/*---------------------------------------------------------------------------*/ +static bool +spi_read(uint8_t *buf, size_t len) +{ + SPI_Transaction spiTransaction; + spiTransaction.count = len; + spiTransaction.txBuf = NULL; + spiTransaction.rxBuf = buf; + + return SPI_transfer(spi_handle, &spiTransaction); +} +/*---------------------------------------------------------------------------*/ +static void +select(void) +{ + PIN_setOutputValue(pin_handle, Board_SPI_FLASH_CS, 1); +} +/*---------------------------------------------------------------------------*/ +static void +deselect(void) +{ + PIN_setOutputValue(pin_handle, Board_SPI_FLASH_CS, 0); +} +/*---------------------------------------------------------------------------*/ +static bool +wait_ready(void) +{ + const uint8_t wbuf[] = { BLS_CODE_READ_STATUS }; + uint8_t rbuf[1] = { 0x0 }; + + /* TODO are 1000 tries enough? */ + for (size_t i = 0; i < 1000; ++i) { + select(); + + const bool spi_ok = spi_write(wbuf, sizeof(wbuf)) + && spi_read(rbuf, sizeof(rbuf)); + + deselect(); + + if (!spi_ok) { + /* Error */ + return false; + } + if (!(rbuf[0] & BLS_STATUS_BIT_BUSY)) { + /* Now ready */ + return true; + } + } + + return false; +} +/*---------------------------------------------------------------------------*/ +static bool +power_standby(void) +{ + const uint8_t cmd[] = { BLS_CODE_RDP }; + + select(); + + const bool spi_ok = spi_write(cmd, sizeof(cmd)); + + deselect(); + + if (!spi_ok) { + return false; + } + + /* Waking up of the device is manufacturer dependent. + * for a Winond chip-set, once the request to wake up the flash has been + * send, CS needs to stay high at least 3us (for Winbond part) + * for chip-set like Macronix, it can take up to 35us. + * 3 cycles per loop: 560 loops @ 48 MHz = 35 us */ + ti_lib_cpu_delay(560); + + return wait_ready(); +} +/*---------------------------------------------------------------------------*/ +static bool +power_down(void) +{ + const uint8_t cmd[] = { BLS_CODE_DP }; + + select(); + + const bool spi_ok = spi_write(cmd, sizeof(cmd)); + + deselect(); + + return spi_ok; +} +/*---------------------------------------------------------------------------*/ +static bool +write_enable(void) +{ + const uint8_t wbuf[] = { BLS_CODE_WRITE_ENABLE }; + + select(); + + const bool spi_ok = spi_write(wbuf, sizeof(wbuf)); + + deselect(); + + return spi_ok; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Verify the flash part. + * \retval bool true on success; else, false + */ +static bool +verify_part(void) +{ + const uint8_t wbuf[] = { BLS_CODE_MDID, 0xFF, 0xFF, 0x00 }; + uint8_t rbuf[2] = { 0x0 }; + + const bool spi_ok = spi_write(wbuf, sizeof(wbuf)) + && spi_read(rbuf, sizeof(rbuf)); + + if (!spi_ok) { + return false; + } + + const ExtFlashInfo curr_device = { + .manfId = rbuf[0], + .devId = rbuf[1] + }; + + const size_t num_devices = sizeof(supported_devices) / sizeof(supported_devices[0]); + for (size_t i = 0; i < num_devices; ++i) { + if (curr_device.manfId == supported_devices[i].manfId && + curr_device.devId == supported_devices[i].devId) { + return true; + } + } + + return false; +} +/*---------------------------------------------------------------------------*/ +bool +ext_flash_open() +{ + if (ext_flash_opened) { + return true; + } + + pin_handle = PIN_open(&pin_state, pin_table); + + if (pin_handle == NULL) { + return false; + } + + SPI_Params spiParams; + SPI_Params_init(&spiParams); + spiParams.bitRate = SPI_BIT_RATE; + spiParams.mode = SPI_MASTER; + spiParams.transferMode = SPI_MODE_BLOCKING; + + spi_handle = SPI_open(Board_SPI0, &spiParams); + + if (spi_handle == NULL) { + PIN_close(pin_handle); + return false; + } + + ext_flash_opened = true; + + deselect(); + + const bool is_powered = power_standby(); + if (!is_powered) { + ext_flash_close(); + return false; + } + + return verify_part(); +} +/*---------------------------------------------------------------------------*/ +void +ext_flash_close() +{ + if (!ext_flash_opened) { + return; + } + ext_flash_opened = false; + + power_down(); + + SPI_close(spi_handle); + PIN_close(pin_handle); +} +/*---------------------------------------------------------------------------*/ +bool +ext_flash_read(size_t offset, size_t length, uint8_t *buf) +{ + if (spi_handle == NULL || buf == NULL) { + return false; + } + + if (length == 0) { + return true; + } + + const bool is_ready = wait_ready(); + if (!is_ready) { + return false; + } + + const uint8_t wbuf[] = { + BLS_CODE_READ, + (offset >> 16) & 0xFF, + (offset >> 8) & 0xFF, + (offset >> 0) & 0xFF, + }; + + select(); + + const bool spi_ok = spi_write(wbuf, sizeof(wbuf)) + && spi_read(buf, length); + + deselect(); + + return (spi_ok); +} +/*---------------------------------------------------------------------------*/ +bool +ext_flash_write(size_t offset, size_t length, const uint8_t *buf) +{ + if (spi_handle == NULL || buf == NULL) { + return false; + } + + uint8_t wbuf[4] = { BLS_CODE_PROGRAM, 0, 0, 0 }; + + while (length > 0) + { + /* Wait till previous erase/program operation completes */ + if (!wait_ready()) { + return false; + } + + /* Enable writing */ + if (!write_enable()) { + return false; + } + + /* Interim length per instruction */ + size_t ilen = BLS_PROGRAM_PAGE_SIZE - (offset % BLS_PROGRAM_PAGE_SIZE); + if (length < ilen) { + ilen = length; + } + + wbuf[1] = (offset >> 16) & 0xFF; + wbuf[2] = (offset >> 8) & 0xFF; + wbuf[3] = (offset >> 0) & 0xFF; + + offset += ilen; + length -= ilen; + + /* Up to 100ns CS hold time (which is not clear + * whether it's application only in between reads) + * is not imposed here since above instructions + * should be enough to delay + * as much. */ + select(); + + const bool spi_ok = spi_write(wbuf, sizeof(wbuf)) + && spi_write(buf, ilen); + + buf += ilen; + + deselect(); + + if (!spi_ok) { + return false; + } + } + + return true; +} +/*---------------------------------------------------------------------------*/ +bool +ext_flash_erase(size_t offset, size_t length) +{ + /* Note that Block erase might be more efficient when the floor map + * is well planned for OTA but to simplify for the temporary implemetation, + * sector erase is used blindly. */ + uint8_t wbuf[4] = { BLS_CODE_SECTOR_ERASE, 0x0, 0x0, 0x0 }; + + const size_t endoffset = offset + length - 1; + offset = (offset / BLS_ERASE_SECTOR_SIZE) * BLS_ERASE_SECTOR_SIZE; + const size_t numsectors = (endoffset - offset + BLS_ERASE_SECTOR_SIZE - 1) / BLS_ERASE_SECTOR_SIZE; + + for (size_t i = 0; i < numsectors; ++i) { + /* Wait till previous erase/program operation completes */ + if (!wait_ready()) { + return false; + } + + /* Enable writing */ + if (!write_enable()) { + return false; + } + + wbuf[1] = (offset >> 16) & 0xFF; + wbuf[2] = (offset >> 8) & 0xFF; + wbuf[3] = (offset >> 0) & 0xFF; + + select(); + + const bool spi_ok = spi_write(wbuf, sizeof(wbuf)); + + deselect(); + + if (!spi_ok) { + return false; + } + + offset += BLS_ERASE_SECTOR_SIZE; + } + + return true; +} +/*---------------------------------------------------------------------------*/ +bool +ext_flash_test(void) +{ + const bool ret = ext_flash_open(); + ext_flash_close(); + + return ret; +} +/*---------------------------------------------------------------------------*/ +void +ext_flash_init() +{ + SPI_init(); +} +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/ext-flash.h similarity index 52% rename from arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag.c rename to arch/platform/simplelink/cc13xx-cc26xx/sensortag/ext-flash.h index c3043f20e..5f2717edb 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/ext-flash.h @@ -29,28 +29,88 @@ */ /*---------------------------------------------------------------------------*/ /** - * \addtogroup sensortag-cc26xx-peripherals + * \addtogroup common-cc26xx-peripherals + * @{ + * + * \defgroup sensortag-cc26xx-ext-flash SensorTag/LaunchPad External Flash * @{ * * \file - * Sensortag-specific board initialisation driver + * Header file for the Sensortag/LaunchPad External Flash Driver */ /*---------------------------------------------------------------------------*/ -#include "contiki.h" -/*---------------------------------------------------------------------------*/ -#include "Board.h" -#include "ti/drivers/GPIO.h" -#include "ti/drivers/I2C.h" -#include "ti/drivers/PIN.h" -#include "ti/drivers/SPI.h" +#ifndef EXT_FLASH_H_ +#define EXT_FLASH_H_ /*---------------------------------------------------------------------------*/ #include -#include +#include #include /*---------------------------------------------------------------------------*/ -void -board_init(void) -{ -} +/** + * \brief Initialize storage driver. + * \return True when successful. + */ +bool ext_flash_open(void); + +/** + * \brief Close the storage driver + * + * This call will put the device in its lower power mode (power down). + */ +void ext_flash_close(void); + +/** + * \brief Read storage content + * \param offset Address to read from + * \param length Number of bytes to read + * \param buf Buffer where to store the read bytes + * \return True when successful. + * + * buf must be allocated by the caller + */ +bool ext_flash_read(size_t offset, size_t length, uint8_t *buf); + +/** + * \brief Erase storage sectors corresponding to the range. + * \param offset Address to start erasing + * \param length Number of bytes to erase + * \return True when successful. + * + * The erase operation will be sector-wise, therefore a call to this function + * will generally start the erase procedure at an address lower than offset + */ +bool ext_flash_erase(size_t offset, size_t length); + +/** + * \brief Write to storage sectors. + * \param offset Address to write to + * \param length Number of bytes to write + * \param buf Buffer holding the bytes to be written + * + * \return True when successful. + */ +bool ext_flash_write(size_t offset, size_t length, const uint8_t *buf); + +/** + * \brief Test the flash (power on self-test) + * \return True when successful. + */ +bool ext_flash_test(void); + +/** + * \brief Initialise the external flash + * + * This function will explicitly put the part in its lowest power mode + * (power-down). + * + * In order to perform any operation, the caller must first wake the device + * up by calling ext_flash_open() + */ +void ext_flash_init(void); /*---------------------------------------------------------------------------*/ -/** @} */ +#endif /* EXT_FLASH_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/reed-relay.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/reed-relay.c deleted file mode 100644 index 9b8426553..000000000 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/reed-relay.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/*---------------------------------------------------------------------------*/ -/** - * \addtogroup sensortag-cc26xx-reed-relay - * @{ - * - * \file - * Driver for the Sensortag Reed Relay - */ -/*---------------------------------------------------------------------------*/ -#include "contiki.h" -#include "sys/clock.h" -#include "sys/timer.h" -#include "lib/sensors.h" -#include "sys/timer.h" -#include "reed-relay.h" -/*---------------------------------------------------------------------------*/ -#include -#include -/*---------------------------------------------------------------------------*/ -#include -/*---------------------------------------------------------------------------*/ -static struct timer debouncetimer; -/*---------------------------------------------------------------------------*/ -static PIN_Config reed_pin_table[] = { - Board_RELAY | PIN_INPUT_EN | PIN_PULLDOWN | PIN_IRQ_DIS, - PIN_TERMINATE -}; - -static PIN_State pin_state; -static PIN_Handle pin_handle; -/*---------------------------------------------------------------------------*/ -static bool -sensor_init(void) -{ - if (pin_handle) { - return true; - } - - pin_handle = PIN_open(&pin_state, reed_pin_table); - return pin_handle != NULL; -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Handler for Sensortag-CC26XX reed interrupts - */ -static void -reed_relay_isr(PIN_Handle handle, PIN_Id pinId) -{ - (void)handle; - (void)pinId; - - if (!timer_expired(&debouncetimer)) { - return; - } - - timer_set(&debouncetimer, CLOCK_SECOND / 2); - sensors_changed(&reed_relay_sensor); -} -/*---------------------------------------------------------------------------*/ -static int -value(int type) -{ - return (int)PIN_getInputValue(Board_RELAY); -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Configuration function for the button sensor for all buttons. - * - * \param type SENSORS_HW_INIT: Initialise. SENSORS_ACTIVE: Enables/Disables - * depending on 'value' - * \param value 0: disable, non-zero: enable - * \return Always returns 1 - */ -static int -configure(int type, int value) -{ - switch(type) { - case SENSORS_HW_INIT: - if (!sensor_init()) { - return REED_RELAY_READING_ERROR; - } - - PIN_setInterrupt(pin_handle, Board_RELAY | PIN_IRQ_DIS); - PIN_registerIntCb(pin_handle, reed_relay_isr); - break; - - case SENSORS_ACTIVE: - if (value) { - PIN_setInterrupt(pin_handle, Board_RELAY | PIN_IRQ_NEGEDGE); - } else { - PIN_setInterrupt(pin_handle, Board_RELAY | PIN_IRQ_DIS); - } - break; - - default: - break; - } - return 1; -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Status function for the reed - * \param type SENSORS_ACTIVE or SENSORS_READY - * \return 1 Interrupt enabled, 0: Disabled - */ -static int -status(int type) -{ - switch (type) { - case SENSORS_ACTIVE: - case SENSORS_READY: - return (PIN_getConfig(Board_RELAY) & PIN_BM_IRQ) != 0; - break; - - default: - break; - } - return 0; -} -/*---------------------------------------------------------------------------*/ -SENSORS_SENSOR(reed_relay_sensor, "REED", value, configure, status); -/*---------------------------------------------------------------------------*/ -/** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag-sensors.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag-sensors.c index c333e62f5..fb7390e06 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag-sensors.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag-sensors.c @@ -36,20 +36,13 @@ * Generic module controlling Simplelink sensors */ /*---------------------------------------------------------------------------*/ -#include -#include -/*---------------------------------------------------------------------------*/ -#include "common/button-sensor.h" +#include "contiki.h" +#include "lib/sensors.h" + +#include "board-peripherals.h" /*---------------------------------------------------------------------------*/ /* Exports a global symbol to be used by the sensor API */ -SENSORS( -#ifdef BUTTON_SENSOR_ARCH_BTN1 - &button_sensor, -#endif -#ifdef BUTTON_SENSOR_ARCH_BTN2 - &button_sensor2, -#endif - NULL -); +SENSORS(&bmp_280_sensor, &tmp_007_sensor, &opt_3001_sensor, &hdc_1000_sensor, + &mpu_9250_sensor); /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/Makefile.srf06 b/arch/platform/simplelink/cc13xx-cc26xx/srf06/Makefile.srf06 index e15684248..b15d7db32 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/Makefile.srf06 +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/Makefile.srf06 @@ -6,7 +6,8 @@ BOARD_TYPE = BOARD_SRF06 PLATFORM_HAS_BUTTON = 1 # leds-arch.c/h etc. -BOARD_SOURCEFILES += srf06.c srf06-sensors.c +BOARD_SOURCEFILES += srf06-sensors.c BOARD_SOURCEFILES += button-sensor-arch.c leds-arch.c +BOARD_SOURCEFILES += als-sensor.c TARGET_FAMILY_DIRS += srf06 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/als-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/als-sensor.c index 3b6fdecb9..aa16dd2ae 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/als-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/als-sensor.c @@ -37,43 +37,53 @@ */ /*---------------------------------------------------------------------------*/ #include "contiki.h" +#include "dev/gpio-hal.h" #include "lib/sensors.h" -#include "srf06/als-sensor.h" #include "sys/timer.h" -#include "dev/adc-sensor.h" -#include "dev/aux-ctrl.h" -#include "ti-lib.h" +#include "als-sensor.h" + +#include + +#include #include /*---------------------------------------------------------------------------*/ -static aux_consumer_module_t als_aux = { - .clocks = AUX_WUC_ADI_CLOCK | AUX_WUC_ANAIF_CLOCK | AUX_WUC_SMPH_CLOCK -}; +static ADC_Handle adc_handle; +/*---------------------------------------------------------------------------*/ +static int +init(void) +{ + ADC_Params adc_params; + ADC_Params_init(&adc_params); + + adc_handle = ADC_open(Board_ADCALS, &adc_params); + if (adc_handle == NULL) { + return 0; + } + + return 1; +} /*---------------------------------------------------------------------------*/ static int config(int type, int enable) { switch(type) { case SENSORS_HW_INIT: - ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_ALS_PWR); - break; + return init(); + case SENSORS_ACTIVE: - ti_lib_rom_ioc_pin_type_gpio_output(BOARD_IOID_ALS_PWR); - ti_lib_rom_ioc_port_configure_set(BOARD_IOID_ALS_OUT, IOC_PORT_GPIO, - IOC_STD_OUTPUT); - ti_lib_rom_ioc_pin_type_gpio_input(BOARD_IOID_ALS_OUT); + gpio_hal_arch_pin_set_output(Board_ALS_PWR); + gpio_hal_arch_pin_set_input(Board_ALS_OUT); if(enable) { - ti_lib_gpio_set_dio(BOARD_IOID_ALS_PWR); - aux_ctrl_register_consumer(&als_aux); - ti_lib_aux_adc_select_input(ADC_COMPB_IN_AUXIO7); + gpio_hal_arch_set_pin(Board_ALS_PWR); clock_delay_usec(2000); } else { - ti_lib_gpio_clear_dio(BOARD_IOID_ALS_PWR); - aux_ctrl_unregister_consumer(&als_aux); + gpio_hal_arch_clear_pin(Board_ALS_PWR); } break; + default: break; } @@ -83,15 +93,14 @@ config(int type, int enable) static int value(int type) { - int val; - ti_lib_aux_adc_enable_sync(AUXADC_REF_VDDS_REL, AUXADC_SAMPLE_TIME_2P7_US, - AUXADC_TRIGGER_MANUAL); - ti_lib_aux_adc_gen_manual_trigger(); - val = ti_lib_aux_adc_read_fifo(); - ti_lib_aux_adc_disable(); + uint16_t adc_value = 0; + int_fast16_t res = ADC_convert(adc_handle, &adc_value); + if (res != ADC_STATUS_SUCCESS) { + return -1; + } - return val; + return (int)adc_value; } /*---------------------------------------------------------------------------*/ static int diff --git a/arch/platform/simplelink/cc13xx-cc26xx/common/button-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/board-conf.h similarity index 68% rename from arch/platform/simplelink/cc13xx-cc26xx/common/button-sensor.h rename to arch/platform/simplelink/cc13xx-cc26xx/srf06/board-conf.h index a27a97cf6..d0e612b2b 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/common/button-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/board-conf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,41 +28,46 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /*---------------------------------------------------------------------------*/ -/** - * \addtogroup simplelink-platform +/** \addtogroup cc26xx-srf-tag * @{ * - * \defgroup simplelink-button-sensor Simplelink Button Driver + * \defgroup launchpad-peripherals LaunchPad peripherals + * + * Defines related to LaunchPad peripherals. * - * One of the buttons can be configured as general purpose or as an on/off key * @{ * * \file - * Header file for the Simplelink Button Driver + * Header file with definitions related to LaunchPad peripherals + * + * \note Do not include this file directly. */ /*---------------------------------------------------------------------------*/ -#ifndef BUTTON_SENSOR_H_ -#define BUTTON_SENSOR_H_ +#ifndef BOARD_CONF_H_ +#define BOARD_CONF_H_ /*---------------------------------------------------------------------------*/ -/* Contiki API */ -#include "lib/sensors.h" -/*---------------------------------------------------------------------------*/ -/* Board specific button sensors */ -#include "button-sensor-arch.h" -/*---------------------------------------------------------------------------*/ -#define BUTTON_SENSOR "Button" -/*---------------------------------------------------------------------------*/ -typedef enum { - BUTTON_SENSOR_TYPE_STATE, - BUTTON_SENSOR_TYPE_DURATION -} button_sensor_type_t; +/** + * \name LED configurations + * + * Those values are not meant to be modified by the user + * @{ + */ +#define LEDS_CONF_COUNT 4 -typedef enum { - BUTTON_SENSOR_VALUE_RELEASED, - BUTTON_SENSOR_VALUE_PRESSED -} button_sensor_value_t; +#define LEDS_CONF_RED 0 +#define LEDS_CONF_YELLOW 1 +#define LEDS_CONF_GREEN 2 +#define LEDS_CONF_ORANGE 3 + +#define LEDS_CONF_ALL ((1 << LEDS_CONF_COUNT) - 1) /*---------------------------------------------------------------------------*/ -#endif /* BUTTON_SENSOR_H_ */ +#define BUTTON_HAL_ID_KEY_LEFT 0 +#define BUTTON_HAL_ID_KEY_RIGHT 1 +#define BUTTON_HAL_ID_KEY_UP 2 +#define BUTTON_HAL_ID_KEY_DOWN 3 +#define BUTTON_HAL_ID_KEY_SELECT 4 +/*---------------------------------------------------------------------------*/ +#endif /* BOARD_CONF_H_ */ /*---------------------------------------------------------------------------*/ /** * @} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/board-peripherals.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/board-peripherals.h index c709ec963..c76057d59 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/board-peripherals.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/board-peripherals.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,15 +31,16 @@ /** \addtogroup cc26xx-srf-tag * @{ * - * \defgroup srf06-common-peripherals SmartRF06EB + CC13xx/CC26xx common + * \defgroup launchpad-peripherals LaunchPad peripherals * - * Defines related to the SmartRF06 Evaluation Board irrespective of the EM - * mounted on it - * - * This file provides connectivity information on LEDs, Buttons, UART and - * other peripherals + * Defines related to LaunchPad peripherals. * * @{ + * + * \file + * Header file with definitions related to LaunchPad peripherals + * + * \note Do not include this file directly. */ /*---------------------------------------------------------------------------*/ #ifndef BOARD_PERIPHERALS_H_ @@ -47,6 +48,10 @@ /*---------------------------------------------------------------------------*/ #include "als-sensor.h" /*---------------------------------------------------------------------------*/ +#include "board-conf.h" +/*---------------------------------------------------------------------------*/ +#define BOARD_CONF_HAS_SENSORS 1 +/*---------------------------------------------------------------------------*/ #endif /* BOARD_PERIPHERALS_H_ */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor-arch.c new file mode 100644 index 000000000..a0cea3b1c --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor-arch.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup launchpad-button-sensor + * @{ + * + * \file + * Driver for LaunchPad buttons + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "dev/button-hal.h" + +#include +/*---------------------------------------------------------------------------*/ +/* Key select button */ +BUTTON_HAL_BUTTON(key_select, /**< Name */ + "Key Select", /**< Description */ + Board_KEY_SELECT, /**< PIN */ + GPIO_HAL_PIN_CFG_INPUT_PULLUP | + GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_KEY_SELECT, /**< Unique ID */ + true); /**< Negative logic */ + +/* Key up button */ +BUTTON_HAL_BUTTON(key_up, /**< Name */ + "Key Up", /**< Description */ + Board_KEY_UP, /**< PIN */ + GPIO_HAL_PIN_CFG_INPUT_PULLUP | + GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_KEY_UP, /**< Unique ID */ + true); /**< Negative logic */ + +/* Key down button */ +BUTTON_HAL_BUTTON(key_down, /**< Name */ + "Key Down", /**< Description */ + Board_KEY_DOWN, /**< PIN */ + GPIO_HAL_PIN_CFG_INPUT_PULLUP | + GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_KEY_DOWN, /**< Unique ID */ + true); /**< Negative logic */ + +/* Key left button */ +BUTTON_HAL_BUTTON(key_left, /**< Name */ + "Key Left", /**< Description */ + Board_KEY_LEFT, /**< PIN */ + GPIO_HAL_PIN_CFG_INPUT_PULLUP | + GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_KEY_LEFT, /**< Unique ID */ + true); /**< Negative logic */ + +/* Key right button */ +BUTTON_HAL_BUTTON(key_right, /**< Name */ + "Key Right", /**< Description */ + Board_KEY_RIGHT, /**< PIN */ + GPIO_HAL_PIN_CFG_INPUT_PULLUP | + GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_KEY_RIGHT, /**< Unique ID */ + true); /**< Negative logic */ +/*---------------------------------------------------------------------------*/ +BUTTON_HAL_BUTTONS(&key_select, &key_up, &key_down, &key_left, &key_right); +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Board.h index f6dc2ba4d..3f2c0421d 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Board.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, Texas Instruments Incorporated + * Copyright (c) 2015-2018, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,53 +33,131 @@ #ifndef __BOARD_H #define __BOARD_H +#define Board_CC1350DK_7XD + #ifdef __cplusplus extern "C" { #endif -#include +#include "CC1350DK_7XD.h" -#include "CC1310DK_7XD.h" +#define Board_initGeneral() CC1350DK_7XD_initGeneral() +#define Board_shutDownExtFlash() CC1350DK_7XD_shutDownExtFlash() +#define Board_wakeUpExtFlash() CC1350DK_7XD_wakeUpExtFlash() /* These #defines allow us to reuse TI-RTOS across other device families */ -#define Board_LED1 Board_DK_LED1 -#define Board_LED2 Board_DK_LED2 -#define Board_LED3 Board_DK_LED3 -#define Board_LED4 Board_DK_LED4 -#define Board_LED0 Board_DK_LED4 +#define Board_ADCALS CC1350DK_7XD_ADCALS -#define Board_ADC0 CC1310DK_7XD_ADCVDDS -#define Board_ADC1 CC1310DK_7XD_ADCALS +#define Board_ADC0 CC1350DK_7XD_ADCVDDS +#define Board_ADC1 CC1350DK_7XD_ADCALS -#define Board_ADCBuf0 CC1310DK_7XD_ADCBuf0 -#define Board_ADCBufChannel0 (0) -#define Board_ADCBufChannel1 (1) +#define Board_ADCBUF0 CC1350DK_7XD_ADCBUF0 +#define Board_ADCBUF0CHANNEL0 CC1350DK_7XD_ADCBUF0CHANNELVDDS +#define Board_ADCBUF0CHANNEL1 CC1350DK_7XD_ADCBUF0CHANNELADCALS -#define Board_BUTTON0 Board_KEY_UP -#define Board_BUTTON1 Board_KEY_DOWN +#define Board_CRYPTO0 CC1350DK_7XD_CRYPTO0 -#define Board_I2C0 Board_I2C -#define Board_UART0 Board_UART -#define Board_AES0 Board_AES -#define Board_WATCHDOG0 CC1310DK_7XD_WATCHDOG0 +#define Board_DIO0 CC1350DK_7XD_DIO0 +#define Board_DIO1_RFSW CC1350DK_7XD_DIO1_RFSW +#define Board_DIO12 CC1350DK_7XD_DIO12 +#define Board_DIO15 CC1350DK_7XD_DIO15 +#define Board_DIO16_TDO CC1350DK_7XD_DIO16_TDO +#define Board_DIO17_TDI CC1350DK_7XD_DIO17_TDI +#define Board_DIO21 CC1350DK_7XD_DIO21 +#define Board_DIO22 CC1350DK_7XD_DIO22 -#define Board_initGeneral() { \ - Power_init(); \ - if (PIN_init(BoardGpioInitTable) != PIN_SUCCESS) \ - {System_abort("Error with PIN_init\n"); \ - } \ -} +#define Board_DIO23_ANALOG CC1350DK_7XD_DIO23_ANALOG +#define Board_DIO24_ANALOG CC1350DK_7XD_DIO24_ANALOG +#define Board_DIO25_ANALOG CC1350DK_7XD_DIO25_ANALOG +#define Board_DIO26_ANALOG CC1350DK_7XD_DIO26_ANALOG +#define Board_DIO27_ANALOG CC1350DK_7XD_DIO27_ANALOG +#define Board_DIO28_ANALOG CC1350DK_7XD_DIO28_ANALOG +#define Board_DIO29_ANALOG CC1350DK_7XD_DIO29_ANALOG +#define Board_DIO30_ANALOG CC1350DK_7XD_DIO30_ANALOG -#define Board_initGPIO() -#define Board_initPWM() PWM_init() -#define Board_initSPI() SPI_init() -#define Board_initUART() UART_init() -#define Board_initWatchdog() Watchdog_init() -#define Board_initADCBuf() ADCBuf_init() -#define Board_initADC() ADC_init() -#define GPIO_toggle(n) -#define GPIO_write(n,m) +#define Board_GPIO_BTN0 CC1350DK_7XD_PIN_KEY_SELECT +#define Board_GPIO_BTN1 CC1350DK_7XD_PIN_KEY_UP +#define Board_GPIO_BTN2 CC1350DK_7XD_PIN_KEY_DOWN +#define Board_GPIO_BTN3 CC1350DK_7XD_PIN_KEY_LEFT +#define Board_GPIO_BTN4 CC1350DK_7XD_PIN_KEY_RIGHT +#define Board_GPIO_LED0 CC1350DK_7XD_PIN_LED1 +#define Board_GPIO_LED1 CC1350DK_7XD_PIN_LED2 +#define Board_GPIO_LED2 CC1350DK_7XD_PIN_LED3 +#define Board_GPIO_LED3 CC1350DK_7XD_PIN_LED4 +#define Board_GPIO_LED_ON CC1350DK_7XD_GPIO_LED_ON +#define Board_GPIO_LED_OFF CC1350DK_7XD_GPIO_LED_OFF + +#define Board_GPTIMER0A CC1350DK_7XD_GPTIMER0A +#define Board_GPTIMER0B CC1350DK_7XD_GPTIMER0B +#define Board_GPTIMER1A CC1350DK_7XD_GPTIMER1A +#define Board_GPTIMER1B CC1350DK_7XD_GPTIMER1B +#define Board_GPTIMER2A CC1350DK_7XD_GPTIMER2A +#define Board_GPTIMER2B CC1350DK_7XD_GPTIMER2B +#define Board_GPTIMER3A CC1350DK_7XD_GPTIMER3A +#define Board_GPTIMER3B CC1350DK_7XD_GPTIMER3B + +#define Board_I2C0 CC1350DK_7XD_I2C0 + +#define Board_NVSINTERNAL CC1350DK_7XD_NVSCC26XX0 + +#define Board_KEY_SELECT CC1350DK_7XD_PIN_KEY_SELECT +#define Board_KEY_UP CC1350DK_7XD_PIN_KEY_UP +#define Board_KEY_DOWN CC1350DK_7XD_PIN_KEY_DOWN +#define Board_KEY_LEFT CC1350DK_7XD_PIN_KEY_LEFT +#define Board_KEY_RIGHT CC1350DK_7XD_PIN_KEY_RIGHT + +#define Board_PIN_BUTTON0 CC1350DK_7XD_PIN_KEY_SELECT +#define Board_PIN_BUTTON1 CC1350DK_7XD_PIN_KEY_UP +#define Board_PIN_BUTTON2 CC1350DK_7XD_PIN_KEY_DOWN +#define Board_PIN_BUTTON3 CC1350DK_7XD_PIN_KEY_LEFT +#define Board_PIN_BUTTON4 CC1350DK_7XD_PIN_KEY_RIGHT +#define Board_PIN_BTN1 CC1350DK_7XD_PIN_KEY_SELECT +#define Board_PIN_BTN2 CC1350DK_7XD_PIN_KEY_UP +#define Board_PIN_BTN3 CC1350DK_7XD_PIN_KEY_DOWN +#define Board_PIN_BTN4 CC1350DK_7XD_PIN_KEY_LEFT +#define Board_PIN_BTN5 CC1350DK_7XD_PIN_KEY_RIGHT +#define Board_PIN_LED0 CC1350DK_7XD_PIN_LED1 +#define Board_PIN_LED1 CC1350DK_7XD_PIN_LED2 +#define Board_PIN_LED2 CC1350DK_7XD_PIN_LED3 +#define Board_PIN_LED3 CC1350DK_7XD_PIN_LED4 + +#define Board_PWM0 CC1350DK_7XD_PWM0 +#define Board_PWM1 CC1350DK_7XD_PWM1 +#define Board_PWM2 CC1350DK_7XD_PWM2 +#define Board_PWM3 CC1350DK_7XD_PWM3 +#define Board_PWM4 CC1350DK_7XD_PWM4 +#define Board_PWM5 CC1350DK_7XD_PWM5 +#define Board_PWM6 CC1350DK_7XD_PWM6 +#define Board_PWM7 CC1350DK_7XD_PWM7 + +#define Board_SD0 CC1350DK_7XD_SDSPI0 + +#define Board_SPI0 CC1350DK_7XD_SPI0 +#define Board_SPI1 CC1350DK_7XD_SPI1 +#define Board_FLASH_CS_ON 0 +#define Board_FLASH_CS_OFF 1 + +#define Board_SPI_MASTER CC1350DK_7XD_SPI0 +#define Board_SPI_SLAVE CC1350DK_7XD_SPI0 +#define Board_SPI_MASTER_READY CC1350DK_7XD_SPI_MASTER_READY +#define Board_SPI_SLAVE_READY CC1350DK_7XD_SPI_SLAVE_READY + +#define Board_UART0 CC1350DK_7XD_UART0 + +#define Board_WATCHDOG0 CC1350DK_7XD_WATCHDOG0 + +#define Board_SDCARD_CS CC1350DK_7XD_SDCARD_CS + +#define Board_LCD_MODE CC1350DK_7XD_LCD_MODE +#define Board_LCD_RST CC1350DK_7XD_LCD_RST +#define Board_LCD_CS CC1350DK_7XD_LCD_CS + +#define Board_ALS_OUT CC1350DK_7XD_ALS_OUT +#define Board_ALS_PWR CC1350DK_7XD_ALS_PWR + +#define Board_ACC_PWR CC1350DK_7XD_ACC_PWR +#define Board_ACC_CS CC1350DK_7XD_ACC_CS #ifdef __cplusplus } diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1310DK_7XD.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1310DK_7XD.c deleted file mode 100644 index 15e2c0f28..000000000 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1310DK_7XD.c +++ /dev/null @@ -1,670 +0,0 @@ -/* - * Copyright (c) 2015-2016, Texas Instruments Incorporated - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. - */ - -/* - * ====================== CC1310DK_7XD.c ============================================= - * This file is responsible for setting up the board specific items for the - * SRF06EB with the CC1310EM_7XD_7793 board. - */ - - -/* - * ====================== Includes ============================================ - */ -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -/* - * ========================= IO driver initialization ========================= - * From main, PIN_init(BoardGpioInitTable) should be called to setup safe - * settings for this board. - * When a pin is allocated and then de-allocated, it will revert to the state - * configured in this table. - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(BoardGpioInitTable, ".const:BoardGpioInitTable") -#pragma DATA_SECTION(PINCC26XX_hwAttrs, ".const:PINCC26XX_hwAttrs") -#endif - -const PIN_Config BoardGpioInitTable[] = { - - Board_DK_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ - Board_DK_LED2 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ - Board_DK_LED3 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ - Board_DK_LED4 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ - Board_KEY_SELECT | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS, /* Button is active low */ - Board_KEY_UP | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS, /* Button is active low */ - Board_KEY_DOWN | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS, /* Button is active low */ - Board_KEY_LEFT | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS, /* Button is active low */ - Board_KEY_RIGHT | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS, /* Button is active low */ - Board_3V3_EN | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL, /* 3V3 domain off initially */ - Board_LCD_MODE | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* LCD pin high initially */ - Board_LCD_RST | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* LCD pin high initially */ - Board_LCD_CSN | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* LCD CSn deasserted initially */ - Board_ALS_PWR | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL, /* ALS power off initially */ - Board_ACC_PWR | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL, /* ACC power off initially */ - Board_ACC_CSN | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* ACC CSn deasserted initially */ - Board_SDCARD_CSN | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* SDCARD CSn deasserted initially */ - Board_UART_TX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* UART TX pin at inactive level */ - PIN_TERMINATE /* Terminate list */ -}; - -const PINCC26XX_HWAttrs PINCC26XX_hwAttrs = { - .intPriority = ~0, - .swiPriority = 0 -}; -/*============================================================================*/ - -/* - * ============================= Power begin =================================== - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(PowerCC26XX_config, ".const:PowerCC26XX_config") -#endif -const PowerCC26XX_Config PowerCC26XX_config = { - .policyInitFxn = NULL, - .policyFxn = &PowerCC26XX_standbyPolicy, - .calibrateFxn = &PowerCC26XX_calibrate, - .enablePolicy = TRUE, - .calibrateRCOSC_LF = TRUE, - .calibrateRCOSC_HF = TRUE, -}; -/* - * ============================= Power end =================================== - */ - -/* - * ============================= UART begin =================================== - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(UART_config, ".const:UART_config") -#pragma DATA_SECTION(uartCC26XXHWAttrs, ".const:uartCC26XXHWAttrs") -#endif - -/* Include drivers */ -#include -#include - -/* UART objects */ -UARTCC26XX_Object uartCC26XXObjects[CC1310DK_7XD_UARTCOUNT]; -unsigned char uartCC26XXRingBuffer[CC1310DK_7XD_UARTCOUNT][32]; - -/* UART hardware parameter structure, also used to assign UART pins */ -const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1310DK_7XD_UARTCOUNT] = { - { - .baseAddr = UART0_BASE, - .powerMngrId = PowerCC26XX_PERIPH_UART0, - .intNum = INT_UART0_COMB, - .intPriority = ~0, - .swiPriority = 0, - .txPin = Board_UART_TX, - .rxPin = Board_UART_RX, - .ctsPin = PIN_UNASSIGNED, - .rtsPin = PIN_UNASSIGNED, - .ringBufPtr = uartCC26XXRingBuffer[0], - .ringBufSize = sizeof(uartCC26XXRingBuffer[0]) - } -}; - -/* UART configuration structure */ -const UART_Config UART_config[] = { - { - .fxnTablePtr = &UARTCC26XX_fxnTable, - .object = &uartCC26XXObjects[0], - .hwAttrs = &uartCC26XXHWAttrs[0] - }, - {NULL, NULL, NULL} -}; -/* - * ============================= UART end ===================================== - */ - -/* - * ============================= UDMA begin =================================== - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(UDMACC26XX_config, ".const:UDMACC26XX_config") -#pragma DATA_SECTION(udmaHWAttrs, ".const:udmaHWAttrs") -#endif - -/* Include drivers */ -#include - -/* UDMA objects */ -UDMACC26XX_Object udmaObjects[CC1310DK_7XD_UDMACOUNT]; - -/* UDMA configuration structure */ -const UDMACC26XX_HWAttrs udmaHWAttrs[CC1310DK_7XD_UDMACOUNT] = { - { - .baseAddr = UDMA0_BASE, - .powerMngrId = PowerCC26XX_PERIPH_UDMA, - .intNum = INT_DMA_ERR, - .intPriority = ~0 - } -}; - -/* UDMA configuration structure */ -const UDMACC26XX_Config UDMACC26XX_config[] = { - { - .object = &udmaObjects[0], - .hwAttrs = &udmaHWAttrs[0] - }, - {NULL, NULL} -}; -/* - * ============================= UDMA end ===================================== - */ - -/* - * ========================== SPI DMA begin =================================== - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(SPI_config, ".const:SPI_config") -#pragma DATA_SECTION(spiCC26XXDMAHWAttrs, ".const:spiCC26XXDMAHWAttrs") -#endif - -/* Include drivers */ -#include - -/* SPI objects */ -SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1310DK_7XD_SPICOUNT]; - -/* SPI configuration structure, describing which pins are to be used */ -const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1310DK_7XD_SPICOUNT] = { - { - .baseAddr = SSI0_BASE, - .intNum = INT_SSI0_COMB, - .intPriority = ~0, - .swiPriority = 0, - .defaultTxBufValue = 0, - .powerMngrId = PowerCC26XX_PERIPH_SSI0, - .rxChannelBitMask = 1< - -/* LCD object */ -LCD_Object lcdObject; - -/* LCD hardware attribute structure */ -const LCD_HWAttrs lcdHWAttrs = { - .LCD_initCmd = &LCD_initCmd, - .lcdResetPin = Board_LCD_RST, /* LCD reset pin */ - .lcdModePin = Board_LCD_MODE, /* LCD mode pin */ - .lcdCsnPin = Board_LCD_CSN, /* LCD CSn pin */ - .spiIndex = Board_SPI0 -}; - -/* LCD configuration structure */ -const LCD_Config LCD_config = { - .object = &lcdObject, - .hwAttrs = &lcdHWAttrs -}; -/* - * ========================== LCD end ========================================= - */ - -/* - * ========================== Crypto begin ==================================== - * NOTE: The Crypto implementation should be considered experimental - * and not validated! - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(CryptoCC26XX_config, ".const:CryptoCC26XX_config") -#pragma DATA_SECTION(cryptoCC26XXHWAttrs, ".const:cryptoCC26XXHWAttrs") -#endif - -/* Include drivers */ -#include - -/* Crypto objects */ -CryptoCC26XX_Object cryptoCC26XXObjects[CC1310DK_7XD_CRYPTOCOUNT]; - -/* Crypto configuration structure, describing which pins are to be used */ -const CryptoCC26XX_HWAttrs cryptoCC26XXHWAttrs[CC1310DK_7XD_CRYPTOCOUNT] = { - { - .baseAddr = CRYPTO_BASE, - .powerMngrId = PowerCC26XX_PERIPH_CRYPTO, - .intNum = INT_CRYPTO_RESULT_AVAIL_IRQ, - .intPriority = ~0, - } -}; - -/* Crypto configuration structure */ -const CryptoCC26XX_Config CryptoCC26XX_config[] = { - { - .object = &cryptoCC26XXObjects[0], - .hwAttrs = &cryptoCC26XXHWAttrs[0] - }, - {NULL, NULL} -}; -/* - * ========================== Crypto end ========================================= - */ - - -/* - * ========================= RF driver begin ============================================== - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(RFCC26XX_hwAttrs, ".const:RFCC26XX_hwAttrs") -#endif -/* Include drivers */ -#include - -/* RF hwi and swi priority */ -const RFCC26XX_HWAttrs RFCC26XX_hwAttrs = { - .hwiCpe0Priority = ~0, - .hwiHwPriority = ~0, - .swiCpe0Priority = 0, - .swiHwPriority = 0, -}; - -/* - * ========================== RF driver end ========================================= - */ - -/* - * ========================= Display begin ==================================== - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(Display_config, ".const:Display_config") -#pragma DATA_SECTION(displayDogm1286HWattrs, ".const:displayDogm1286HWAttrs") -#pragma DATA_SECTION(displayUartHWAttrs, ".const:displayUartHWAttrs") -#endif - -#include -#include -#include - -/* Structures for UartPlain Blocking */ -DisplayUart_Object displayUartObject; - -#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE -#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 -#endif -static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; - -const DisplayUart_HWAttrs displayUartHWAttrs = { - .uartIdx = Board_UART, - .baudRate = 115200, - .mutexTimeout = BIOS_WAIT_FOREVER, - .strBuf = uartStringBuf, - .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, -}; - -/* Structures for DOGM1286 */ -DisplayDogm1286_Object displayDogm1286Object; - -const DisplayDogm1286_HWAttrs displayDogm1286HWattrs = { - .lcdHandle = (LCD_Handle) & LCD_config, - .powerPin = Board_3V3_EN -}; - -/* Array of displays */ -const Display_Config Display_config[] = { -#if !defined(BOARD_DISPLAY_EXCLUDE_UART) - { - .fxnTablePtr = &DisplayUart_fxnTable, - .object = &displayUartObject, - .hwAttrs = &displayUartHWAttrs, - }, -#endif -#if !defined(BOARD_DISPLAY_EXCLUDE_LCD) - { - .fxnTablePtr = &DisplayDogm1286_fxnTable, - .object = &displayDogm1286Object, - .hwAttrs = &displayDogm1286HWattrs - }, -#endif - { NULL, NULL, NULL } // Terminator -}; - -/* - * ========================= Display end ====================================== - */ - -/* - * ============================ GPTimer begin ================================= - * Remove unused entries to reduce flash usage both in Board.c and Board.h - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(GPTimerCC26XX_config, ".const:GPTimerCC26XX_config") -#pragma DATA_SECTION(gptimerCC26xxHWAttrs, ".const:gptimerCC26xxHWAttrs") -#endif - -/* GPTimer hardware attributes, one per timer part (Timer 0A, 0B, 1A, 1B..) */ -const GPTimerCC26XX_HWAttrs gptimerCC26xxHWAttrs[CC1310DK_7XD_GPTIMERPARTSCOUNT] = { - { .baseAddr = GPT0_BASE, .intNum = INT_GPT0A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0A, }, - { .baseAddr = GPT0_BASE, .intNum = INT_GPT0B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0B, }, - { .baseAddr = GPT1_BASE, .intNum = INT_GPT1A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1A, }, - { .baseAddr = GPT1_BASE, .intNum = INT_GPT1B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1B, }, - { .baseAddr = GPT2_BASE, .intNum = INT_GPT2A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2A, }, - { .baseAddr = GPT2_BASE, .intNum = INT_GPT2B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2B, }, - { .baseAddr = GPT3_BASE, .intNum = INT_GPT3A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3A, }, - { .baseAddr = GPT3_BASE, .intNum = INT_GPT3B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3B, }, -}; - -/* GPTimer objects, one per full-width timer (A+B) (Timer 0, Timer 1..) */ -GPTimerCC26XX_Object gptimerCC26XXObjects[CC1310DK_7XD_GPTIMERCOUNT]; - -/* GPTimer configuration (used as GPTimer_Handle by driver and application) */ -const GPTimerCC26XX_Config GPTimerCC26XX_config[CC1310DK_7XD_GPTIMERPARTSCOUNT] = { - { &gptimerCC26XXObjects[0], &gptimerCC26xxHWAttrs[0], GPT_A }, - { &gptimerCC26XXObjects[0], &gptimerCC26xxHWAttrs[1], GPT_B }, - { &gptimerCC26XXObjects[1], &gptimerCC26xxHWAttrs[2], GPT_A }, - { &gptimerCC26XXObjects[1], &gptimerCC26xxHWAttrs[3], GPT_B }, - { &gptimerCC26XXObjects[2], &gptimerCC26xxHWAttrs[4], GPT_A }, - { &gptimerCC26XXObjects[2], &gptimerCC26xxHWAttrs[5], GPT_B }, - { &gptimerCC26XXObjects[3], &gptimerCC26xxHWAttrs[6], GPT_A }, - { &gptimerCC26XXObjects[3], &gptimerCC26xxHWAttrs[7], GPT_B }, -}; - -/* - * ============================ GPTimer end =================================== - */ - - - -/* - * ============================= PWM begin ==================================== - * Remove unused entries to reduce flash usage both in Board.c and Board.h - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(PWM_config, ".const:PWM_config") -#pragma DATA_SECTION(pwmtimerCC26xxHWAttrs, ".const:pwmtimerCC26xxHWAttrs") -#endif - -/* PWM configuration, one per PWM output. */ -PWMTimerCC26XX_HwAttrs pwmtimerCC26xxHWAttrs[CC1310DK_7XD_PWMCOUNT] = { - { .pwmPin = Board_PWMPIN0, .gpTimerUnit = Board_GPTIMER0A }, - { .pwmPin = Board_PWMPIN1, .gpTimerUnit = Board_GPTIMER0B }, - { .pwmPin = Board_PWMPIN2, .gpTimerUnit = Board_GPTIMER1A }, - { .pwmPin = Board_PWMPIN3, .gpTimerUnit = Board_GPTIMER1B }, - { .pwmPin = Board_PWMPIN4, .gpTimerUnit = Board_GPTIMER2A }, - { .pwmPin = Board_PWMPIN5, .gpTimerUnit = Board_GPTIMER2B }, - { .pwmPin = Board_PWMPIN6, .gpTimerUnit = Board_GPTIMER3A }, - { .pwmPin = Board_PWMPIN7, .gpTimerUnit = Board_GPTIMER3B }, -}; - -/* PWM object, one per PWM output */ -PWMTimerCC26XX_Object pwmtimerCC26xxObjects[CC1310DK_7XD_PWMCOUNT]; - -extern const PWM_FxnTable PWMTimerCC26XX_fxnTable; - -/* PWM configuration (used as PWM_Handle by driver and application) */ -const PWM_Config PWM_config[CC1310DK_7XD_PWMCOUNT + 1] = { - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[0], &pwmtimerCC26xxHWAttrs[0] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[1], &pwmtimerCC26xxHWAttrs[1] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[2], &pwmtimerCC26xxHWAttrs[2] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[3], &pwmtimerCC26xxHWAttrs[3] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[4], &pwmtimerCC26xxHWAttrs[4] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[5], &pwmtimerCC26xxHWAttrs[5] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[6], &pwmtimerCC26xxHWAttrs[6] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[7], &pwmtimerCC26xxHWAttrs[7] }, - { NULL, NULL, NULL } -}; - - -/* - * ============================= PWM end ====================================== - */ - - -/* - * ========================== ADCBuf begin ========================================= - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(ADCBuf_config, ".const:ADCBuf_config") -#pragma DATA_SECTION(adcBufCC26xxHWAttrs, ".const:adcBufCC26xxHWAttrs") -#pragma DATA_SECTION(ADCBufCC26XX_adcChannelLut, ".const:ADCBufCC26XX_adcChannelLut") -#endif - -/* Include drivers */ -#include -#include - -/* ADC objects */ -ADCBufCC26XX_Object adcBufCC26xxObjects[CC1310DK_7XD_ADCBufCOUNT]; - -/* - * This table converts a virtual adc channel into a dio and internal analogue input signal. - * This table is necessary for the functioning of the adcBuf driver. - * Comment out unused entries to save flash. - * Dio and internal signal pairs are hardwired. Do not remap them in the table. You may reorder entire entries though. - * The mapping of dio and internal signals is package dependent. - */ -const ADCBufCC26XX_AdcChannelLutEntry ADCBufCC26XX_adcChannelLut[] = { - {Board_ALS_OUT, ADC_COMPB_IN_AUXIO7}, - {PIN_UNASSIGNED, ADC_COMPB_IN_DCOUPL}, - {PIN_UNASSIGNED, ADC_COMPB_IN_VSS}, - {PIN_UNASSIGNED, ADC_COMPB_IN_VDDS} -}; - -const ADCBufCC26XX_HWAttrs adcBufCC26xxHWAttrs[CC1310DK_7XD_ADCBufCOUNT] = { - { - .intPriority = ~0, - .swiPriority = 0, - .adcChannelLut = ADCBufCC26XX_adcChannelLut, - .gpTimerUnit = Board_GPTIMER0A, - .gptDMAChannelMask = 1 << UDMA_CHAN_TIMER0_A, - } -}; - -const ADCBuf_Config ADCBuf_config[] = { - {&ADCBufCC26XX_fxnTable, &adcBufCC26xxObjects[0], &adcBufCC26xxHWAttrs[0]}, - {NULL, NULL, NULL}, -}; -/* - * ========================== ADCBuf end ========================================= - */ - - -/* - * ========================== ADC begin ========================================= - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(ADC_config, ".const:ADC_config") -#pragma DATA_SECTION(adcCC26xxHWAttrs, ".const:adcCC26xxHWAttrs") -#endif - -/* Include drivers */ -#include -#include - - -/* ADC objects */ -ADCCC26XX_Object adcCC26xxObjects[CC1310DK_7XD_ADCCOUNT]; - - -const ADCCC26XX_HWAttrs adcCC26xxHWAttrs[CC1310DK_7XD_ADCCOUNT] = { - { - .adcDIO = Board_ALS_OUT, - .adcCompBInput = ADC_COMPB_IN_AUXIO7, - .refSource = ADCCC26XX_FIXED_REFERENCE, - .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, - .inputScalingEnabled = true, - .triggerSource = ADCCC26XX_TRIGGER_MANUAL - }, - { - .adcDIO = PIN_UNASSIGNED, - .adcCompBInput = ADC_COMPB_IN_DCOUPL, - .refSource = ADCCC26XX_FIXED_REFERENCE, - .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, - .inputScalingEnabled = true, - .triggerSource = ADCCC26XX_TRIGGER_MANUAL - }, - { - .adcDIO = PIN_UNASSIGNED, - .adcCompBInput = ADC_COMPB_IN_VSS, - .refSource = ADCCC26XX_FIXED_REFERENCE, - .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, - .inputScalingEnabled = true, - .triggerSource = ADCCC26XX_TRIGGER_MANUAL - }, - { - .adcDIO = PIN_UNASSIGNED, - .adcCompBInput = ADC_COMPB_IN_VDDS, - .refSource = ADCCC26XX_FIXED_REFERENCE, - .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, - .inputScalingEnabled = true, - .triggerSource = ADCCC26XX_TRIGGER_MANUAL - } -}; - -const ADC_Config ADC_config[] = { - {&ADCCC26XX_fxnTable, &adcCC26xxObjects[0], &adcCC26xxHWAttrs[0]}, - {&ADCCC26XX_fxnTable, &adcCC26xxObjects[1], &adcCC26xxHWAttrs[1]}, - {&ADCCC26XX_fxnTable, &adcCC26xxObjects[2], &adcCC26xxHWAttrs[2]}, - {&ADCCC26XX_fxnTable, &adcCC26xxObjects[3], &adcCC26xxHWAttrs[3]}, - {NULL, NULL, NULL}, -}; - -/* - * ========================== ADC end ========================================= - */ - -/* - * =============================== Watchdog =============================== - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(Watchdog_config, ".const:Watchdog_config") -#pragma DATA_SECTION(watchdogCC26XXHWAttrs, ".const:watchdogCC26XXHWAttrs") -#endif - -#include -#include - -WatchdogCC26XX_Object watchdogCC26XXObjects[CC1310DK_7XD_WATCHDOGCOUNT]; - -const WatchdogCC26XX_HWAttrs watchdogCC26XXHWAttrs[CC1310DK_7XD_WATCHDOGCOUNT] = { - { - .baseAddr = WDT_BASE, - .intNum = INT_WDT_IRQ, - .reloadValue = 1000 /* Reload value in milliseconds */ - }, -}; - -const Watchdog_Config Watchdog_config[] = { - { - .fxnTablePtr = &WatchdogCC26XX_fxnTable, - .object = &watchdogCC26XXObjects[0], - .hwAttrs = &watchdogCC26XXHWAttrs[0] - }, - {NULL, NULL, NULL}, -}; - -/* - * ======== CC26XX_LAUNCHXL_initWatchdog ======== - */ -void CC26XX_LAUNCHXL_initWatchdog(void) -{ - Watchdog_init(); -} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1310DK_7XD.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1310DK_7XD.h deleted file mode 100644 index 6e5e45c19..000000000 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1310DK_7XD.h +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright (c) 2015-2016, Texas Instruments Incorporated - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. - */ -/** ============================================================================ - * @file CC1310DK_7XD.h - * - * @brief CC1310EM_7XD_7793 Board Specific header file. - * The project options should point to this file if this is the - * CC1310EM you are developing code for. - * - * The CC1310 header file should be included in an application as follows: - * @code - * #include - * @endcode - * - * ============================================================================ - */ -#ifndef __CC1310EM_7XD_7793_H__ -#define __CC1310EM_7XD_7793_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -/** ============================================================================ - * Symbol by generic Board.c to include the correct kit specific Board.c - * ==========================================================================*/ -#define CC1310EM_7XD_7793 -#define CC1310DK_7XD - - -/** ============================================================================ - * Includes - * ==========================================================================*/ -#include -#include - -/** ============================================================================ - * Externs - * ==========================================================================*/ -extern const PIN_Config BoardGpioInitTable[]; - -/** ============================================================================ - * Defines - * ==========================================================================*/ - -/* Mapping of pins to board signals using general board aliases - * - */ -/* Leds */ -#define Board_LED_ON 1 /* LEDs on SmartRF06 EB are active high */ -#define Board_LED_OFF 0 -#define Board_DK_LED1 IOID_25 /* P2.11 */ -#define Board_DK_LED2 IOID_27 /* P2.13 */ -#define Board_DK_LED3 IOID_7 /* P1.2 */ -#define Board_DK_LED4 IOID_6 /* P1.4 */ -/* Button Board */ -#define Board_KEY_SELECT IOID_11 /* P1.14 */ -#define Board_KEY_UP IOID_19 /* P1.10 */ -#define Board_KEY_DOWN IOID_12 /* P1.12 */ -#define Board_KEY_LEFT IOID_15 /* P1.6 */ -#define Board_KEY_RIGHT IOID_18 /* P1.8 */ -/* LCD Board */ -#define Board_LCD_MODE IOID_4 /* P1.11 */ -#define Board_LCD_RST IOID_5 /* P1.13 */ -#define Board_LCD_CSN IOID_14 /* P1.17 */ -/* UART Board */ -#define Board_UART_RX IOID_2 /* P1.7 */ -#define Board_UART_TX IOID_3 /* P1.9 */ -#define Board_UART_CTS IOID_22 /* P1.3 */ -#define Board_UART_RTS IOID_21 /* P2.18 */ -/* SPI Board */ -#define Board_SPI0_MISO IOID_8 /* P1.20 */ -#define Board_SPI0_MOSI IOID_9 /* P1.18 */ -#define Board_SPI0_CLK IOID_10 /* P1.16 */ -#define Board_SPI0_CSN PIN_UNASSIGNED /* P1.14, separate CSn for LCD, SDCARD, and ACC */ -#define Board_SPI1_MISO IOID_24 /* RF2.10 for testing only */ -#define Board_SPI1_MOSI IOID_23 /* RF2.5 for testing only */ -#define Board_SPI1_CLK IOID_30 /* RF2.12 for testing only */ -#define Board_SPI1_CSN PIN_UNASSIGNED /* RF2.6 for testing only */ -/* Ambient Light Sensor */ -#define Board_ALS_OUT IOID_23 /* P2.5 */ -#define Board_ALS_PWR IOID_26 /* P2.6 */ -/* Accelerometer */ -#define Board_ACC_PWR IOID_20 /* P2.8 */ -#define Board_ACC_CSN IOID_24 /* P2.10 */ -/* SD Card */ -#define Board_SDCARD_CSN IOID_30 /* P2.12 */ -/* Power Board */ -#define Board_3V3_EN IOID_13 /* P1.15 */ -/* PWM outputs */ -#define Board_PWMPIN0 Board_DK_LED1 -#define Board_PWMPIN1 Board_DK_LED2 -#define Board_PWMPIN2 PIN_UNASSIGNED -#define Board_PWMPIN3 PIN_UNASSIGNED -#define Board_PWMPIN4 PIN_UNASSIGNED -#define Board_PWMPIN5 PIN_UNASSIGNED -#define Board_PWMPIN6 PIN_UNASSIGNED -#define Board_PWMPIN7 PIN_UNASSIGNED -/* Analog capable DIO's */ -#define Board_DIO23_ANALOG IOID_23 -#define Board_DIO24_ANALOG IOID_24 -#define Board_DIO25_ANALOG IOID_25 -#define Board_DIO26_ANALOG IOID_26 -#define Board_DIO27_ANALOG IOID_27 -#define Board_DIO28_ANALOG IOID_28 -#define Board_DIO29_ANALOG IOID_29 -#define Board_DIO30_ANALOG IOID_30 - -/** ============================================================================ - * Instance identifiers - * ==========================================================================*/ -/* Generic SPI instance identifiers */ -#define Board_SPI0 CC1310DK_7XD_SPI0 -/* Generic UART instance identifiers */ -#define Board_UART CC1310DK_7XD_UART0 -/* Generic Crypto instance identifiers */ -#define Board_CRYPTO CC1310DK_7XD_CRYPTO0 -/* Generic GPTimer instance identifiers */ -#define Board_GPTIMER0A CC1310DK_7XD_GPTIMER0A -#define Board_GPTIMER0B CC1310DK_7XD_GPTIMER0B -#define Board_GPTIMER1A CC1310DK_7XD_GPTIMER1A -#define Board_GPTIMER1B CC1310DK_7XD_GPTIMER1B -#define Board_GPTIMER2A CC1310DK_7XD_GPTIMER2A -#define Board_GPTIMER2B CC1310DK_7XD_GPTIMER2B -#define Board_GPTIMER3A CC1310DK_7XD_GPTIMER3A -#define Board_GPTIMER3B CC1310DK_7XD_GPTIMER3B -/* Generic PWM instance identifiers */ -#define Board_PWM0 CC1310DK_7XD_PWM0 -#define Board_PWM1 CC1310DK_7XD_PWM1 -#define Board_PWM2 CC1310DK_7XD_PWM2 -#define Board_PWM3 CC1310DK_7XD_PWM3 -#define Board_PWM4 CC1310DK_7XD_PWM4 -#define Board_PWM5 CC1310DK_7XD_PWM5 -#define Board_PWM6 CC1310DK_7XD_PWM6 -#define Board_PWM7 CC1310DK_7XD_PWM7 - -/** ============================================================================ - * Number of peripherals and their names - * ==========================================================================*/ - -/*! - * @def CC1310DK_7XD_CryptoName - * @brief Enum of Crypto names on the CC1310 dev board - */ -typedef enum CC1310DK_7XD_CryptoName { - CC1310DK_7XD_CRYPTO0 = 0, - CC1310DK_7XD_CRYPTOCOUNT -} CC1310DK_7XD_CryptoName; - -/*! - * @def CC1310DK_7XD_SPIName - * @brief Enum of SPI names on the CC1310 dev board - */ -typedef enum CC1310DK_7XD_SPIName { - CC1310DK_7XD_SPI0 = 0, - CC1310DK_7XD_SPI1, - CC1310DK_7XD_SPICOUNT -} CC1310DK_7XD_SPIName; - -/*! - * @def CC1310DK_7XD_UARTName - * @brief Enum of UARTs on the CC1310 dev board - */ -typedef enum CC1310DK_7XD_UARTName { - CC1310DK_7XD_UART0 = 0, - CC1310DK_7XD_UARTCOUNT -} CC1310DK_7XD_UARTName; - -/*! - * @def CC1310DK_7XD_UdmaName - * @brief Enum of DMA buffers - */ -typedef enum CC1310DK_7XD_UdmaName { - CC1310DK_7XD_UDMA0 = 0, - CC1310DK_7XD_UDMACOUNT -} CC1310DK_7XD_UdmaName; - -/*! - * @def CC1310DK_7XD_GPTimerName - * @brief Enum of GPTimer parts - */ -typedef enum CC1310DK_7XD_GPTimerName -{ - CC1310DK_7XD_GPTIMER0A = 0, - CC1310DK_7XD_GPTIMER0B, - CC1310DK_7XD_GPTIMER1A, - CC1310DK_7XD_GPTIMER1B, - CC1310DK_7XD_GPTIMER2A, - CC1310DK_7XD_GPTIMER2B, - CC1310DK_7XD_GPTIMER3A, - CC1310DK_7XD_GPTIMER3B, - CC1310DK_7XD_GPTIMERPARTSCOUNT -} CC1310DK_7XD_GPTimerName; - -/*! - * @def CC1310DK_7XD_GPTimers - * @brief Enum of GPTimers - */ -typedef enum CC1310DK_7XD_GPTimers -{ - CC1310DK_7XD_GPTIMER0 = 0, - CC1310DK_7XD_GPTIMER1, - CC1310DK_7XD_GPTIMER2, - CC1310DK_7XD_GPTIMER3, - CC1310DK_7XD_GPTIMERCOUNT -} CC1310DK_7XD_GPTimers; - -/*! - * @def CC1310DK_7XD_PWM - * @brief Enum of PWM outputs on the board - */ -typedef enum CC1310DK_7XD_PWM -{ - CC1310DK_7XD_PWM0 = 0, - CC1310DK_7XD_PWM1, - CC1310DK_7XD_PWM2, - CC1310DK_7XD_PWM3, - CC1310DK_7XD_PWM4, - CC1310DK_7XD_PWM5, - CC1310DK_7XD_PWM6, - CC1310DK_7XD_PWM7, - CC1310DK_7XD_PWMCOUNT -} CC1310DK_7XD_PWM; - -/*! - * @def CC1310DK_7XD__ADCBufName - * @brief Enum of ADC's - */ -typedef enum CC1310DK_7XD_ADCBufName { - CC1310DK_7XD_ADCBuf0 = 0, - CC1310DK_7XD_ADCBufCOUNT -} CC1310DK_7XD_ADCBufName; - -/*! - * @def CC1310DK_7XD_ADCName - * @brief Enum of ADCs - */ -typedef enum CC1310DK_7XD_ADCName { - CC1310DK_7XD_ADCALS = 0, - CC1310DK_7XD_ADCDCOUPL, - CC1310DK_7XD_ADCVSS, - CC1310DK_7XD_ADCVDDS, - CC1310DK_7XD_ADCCOUNT -} CC1310DK_7XD_ADCName; - -/*! - * @def CC1310DK_7XD_WatchdogName - * @brief Enum of Watchdogs on the CC1310DK_7XD dev board - */ -typedef enum CC1310DK_7XD_WatchdogName { - CC1310DK_7XD_WATCHDOG0 = 0, - - CC1310DK_7XD_WATCHDOGCOUNT -} CC1310DK_7XD_WatchdogName; - -#ifdef __cplusplus -} -#endif - -#endif /* __CC1310EM_H__ */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c new file mode 100644 index 000000000..00cb5d8e0 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c @@ -0,0 +1,749 @@ +/* + * Copyright (c) 2016-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +/* + * ====================== CC1350DK_7XD.c =================================== + * This file is responsible for setting up the board specific items for the + * CC1350DK_7XD board. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "CC1350DK_7XD.h" + +/* + * =============================== ADCBuf =============================== + */ +#include +#include + +ADCBufCC26XX_Object adcBufCC26xxObjects[CC1350DK_7XD_ADCBUFCOUNT]; + +/* + * This table converts a virtual adc channel into a dio and internal analogue + * input signal. This table is necessary for the functioning of the adcBuf + * driver. Comment out unused entries to save flash. Dio and internal signal + * pairs are hardwired. Do not remap them in the table. You may reorder entire + * entries. The mapping of dio and internal signals is package dependent. + */ +const ADCBufCC26XX_AdcChannelLutEntry ADCBufCC26XX_adcChannelLut[CC1350DK_7XD_ADCBUF0CHANNELCOUNT] = { + {CC1350DK_7XD_ALS_OUT, ADC_COMPB_IN_AUXIO7}, + {PIN_UNASSIGNED, ADC_COMPB_IN_DCOUPL}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VSS}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VDDS}, +}; + +const ADCBufCC26XX_HWAttrs adcBufCC26xxHWAttrs[CC1350DK_7XD_ADCBUFCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + .adcChannelLut = ADCBufCC26XX_adcChannelLut, + .gpTimerUnit = CC1350DK_7XD_GPTIMER0A, + .gptDMAChannelMask = 1 << UDMA_CHAN_TIMER0_A, + } +}; + +const ADCBuf_Config ADCBuf_config[CC1350DK_7XD_ADCBUFCOUNT] = { + { + &ADCBufCC26XX_fxnTable, + &adcBufCC26xxObjects[CC1350DK_7XD_ADCBUF0], + &adcBufCC26xxHWAttrs[CC1350DK_7XD_ADCBUF0] + }, +}; + +const uint_least8_t ADCBuf_count = CC1350DK_7XD_ADCBUFCOUNT; + +/* + * =============================== ADC =============================== + */ +#include +#include + +ADCCC26XX_Object adcCC26xxObjects[CC1350DK_7XD_ADCCOUNT]; + +const ADCCC26XX_HWAttrs adcCC26xxHWAttrs[CC1350DK_7XD_ADCCOUNT] = { + { + .adcDIO = CC1350DK_7XD_DIO23_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO7, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_DCOUPL, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VSS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VDDS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + } +}; + +const ADC_Config ADC_config[CC1350DK_7XD_ADCCOUNT] = { + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1350DK_7XD_ADCALS], &adcCC26xxHWAttrs[CC1350DK_7XD_ADCALS]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1350DK_7XD_ADCDCOUPL], &adcCC26xxHWAttrs[CC1350DK_7XD_ADCDCOUPL]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1350DK_7XD_ADCVSS], &adcCC26xxHWAttrs[CC1350DK_7XD_ADCVSS]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC1350DK_7XD_ADCVDDS], &adcCC26xxHWAttrs[CC1350DK_7XD_ADCVDDS]}, +}; + +const uint_least8_t ADC_count = CC1350DK_7XD_ADCCOUNT; + +/* + * =============================== Crypto =============================== + */ +#include + +CryptoCC26XX_Object cryptoCC26XXObjects[CC1350DK_7XD_CRYPTOCOUNT]; + +const CryptoCC26XX_HWAttrs cryptoCC26XXHWAttrs[CC1350DK_7XD_CRYPTOCOUNT] = { + { + .baseAddr = CRYPTO_BASE, + .powerMngrId = PowerCC26XX_PERIPH_CRYPTO, + .intNum = INT_CRYPTO_RESULT_AVAIL_IRQ, + .intPriority = ~0, + } +}; + +const CryptoCC26XX_Config CryptoCC26XX_config[CC1350DK_7XD_CRYPTOCOUNT] = { + { + .object = &cryptoCC26XXObjects[CC1350DK_7XD_CRYPTO0], + .hwAttrs = &cryptoCC26XXHWAttrs[CC1350DK_7XD_CRYPTO0] + }, +}; + +/* + * =============================== Display =============================== + */ +#include +#include +#include + +#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE +#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 +#endif + +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 +#endif + +DisplayUart_Object displayUartObject; +DisplaySharp_Object displaySharpObject; + +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; +static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; + +const DisplayUart_HWAttrs displayUartHWAttrs = { + .uartIdx = CC1350DK_7XD_UART0, + .baudRate = 115200, + .mutexTimeout = (unsigned int)(-1), + .strBuf = uartStringBuf, + .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, +}; + +const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { + .spiIndex = CC1350DK_7XD_SPI0, + .csPin = CC1350DK_7XD_GPIO_LCD_CS, + .powerPin = CC1350DK_7XD_GPIO_LCD_POWER, + .enablePin = CC1350DK_7XD_GPIO_LCD_ENABLE, + .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, + .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, + .displayBuf = sharpDisplayBuf, +}; + +#ifndef BOARD_DISPLAY_USE_UART +#define BOARD_DISPLAY_USE_UART 1 +#endif +#ifndef BOARD_DISPLAY_USE_UART_ANSI +#define BOARD_DISPLAY_USE_UART_ANSI 0 +#endif +#ifndef BOARD_DISPLAY_USE_LCD +#define BOARD_DISPLAY_USE_LCD 0 +#endif + +/* + * This #if/#else is needed to workaround a problem with the + * IAR compiler. The IAR compiler doesn't like the empty array + * initialization. (IAR Error[Pe1345]) + */ +#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) + +const Display_Config Display_config[] = { +#if (BOARD_DISPLAY_USE_UART) + { +# if (BOARD_DISPLAY_USE_UART_ANSI) + .fxnTablePtr = &DisplayUartAnsi_fxnTable, +# else /* Default to minimal UART with no cursor placement */ + .fxnTablePtr = &DisplayUartMin_fxnTable, +# endif + .object = &displayUartObject, + .hwAttrs = &displayUartHWAttrs, + }, +#endif +#if (BOARD_DISPLAY_USE_LCD) + { + .fxnTablePtr = &DisplaySharp_fxnTable, + .object = &displaySharpObject, + .hwAttrs = &displaySharpHWattrs + }, +#endif +}; + +const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); + +#else + +const Display_Config *Display_config = NULL; +const uint_least8_t Display_count = 0; + +#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ + +/* + * =============================== GPIO =============================== + */ +#include +#include + +/* + * Array of Pin configurations + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC1350DK_7XD.h + * NOTE: Pins not used for interrupts should be placed at the end of the + * array. Callback entries can be omitted from callbacks array to + * reduce memory usage. + */ +GPIO_PinConfig gpioPinConfigs[] = { + /* Input pins */ + GPIOCC26XX_DIO_11 | GPIO_DO_NOT_CONFIG, /* Key Select */ + GPIOCC26XX_DIO_19 | GPIO_DO_NOT_CONFIG, /* Key Up */ + GPIOCC26XX_DIO_12 | GPIO_DO_NOT_CONFIG, /* Key Down */ + GPIOCC26XX_DIO_15 | GPIO_DO_NOT_CONFIG, /* Key Left */ + GPIOCC26XX_DIO_18 | GPIO_DO_NOT_CONFIG, /* Key Right */ + + GPIOCC26XX_DIO_15 | GPIO_DO_NOT_CONFIG, /* CC1350DK_7XD_SPI_MASTER_READY */ + GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG, /* CC1350DK_7XD_SPI_SLAVE_READY */ + + /* Output pins */ + GPIOCC26XX_DIO_25 | GPIO_DO_NOT_CONFIG, /* LED 1 */ + GPIOCC26XX_DIO_27 | GPIO_DO_NOT_CONFIG, /* LED 2 */ + GPIOCC26XX_DIO_07 | GPIO_DO_NOT_CONFIG, /* LED 3 */ + GPIOCC26XX_DIO_06 | GPIO_DO_NOT_CONFIG, /* LED 4 */ + + /* SDCARD */ + GPIOCC26XX_DIO_30 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ + + /* Accelerometer */ + GPIOCC26XX_DIO_24 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ + + /* Sharp Display - GPIO configurations will be done in the Display files */ + GPIOCC26XX_DIO_14 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ + GPIOCC26XX_DIO_05 | GPIO_DO_NOT_CONFIG, /* LCD power control */ + GPIOCC26XX_DIO_04 | GPIO_DO_NOT_CONFIG, /* LCD enable */ + +}; + +/* + * Array of callback function pointers + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC2650_LAUNCH.h + * NOTE: Pins not used for interrupts can be omitted from callbacks array to + * reduce memory usage (if placed at end of gpioPinConfigs array). + */ +GPIO_CallbackFxn gpioCallbackFunctions[] = { + NULL, /* Button 0 */ + NULL, /* Button 1 */ + NULL, /* CC1350DK_7XD_SPI_MASTER_READY */ + NULL, /* CC1350DK_7XD_SPI_SLAVE_READY */ +}; + +const GPIOCC26XX_Config GPIOCC26XX_config = { + .pinConfigs = (GPIO_PinConfig *)gpioPinConfigs, + .callbacks = (GPIO_CallbackFxn *)gpioCallbackFunctions, + .numberOfPinConfigs = CC1350DK_7XD_GPIOCOUNT, + .numberOfCallbacks = sizeof(gpioCallbackFunctions)/sizeof(GPIO_CallbackFxn), + .intPriority = (~0) +}; + +/* + * =============================== GPTimer =============================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +#include + +GPTimerCC26XX_Object gptimerCC26XXObjects[CC1350DK_7XD_GPTIMERCOUNT]; + +const GPTimerCC26XX_HWAttrs gptimerCC26xxHWAttrs[CC1350DK_7XD_GPTIMERPARTSCOUNT] = { + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0A, }, + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0B, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1A, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1B, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2A, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2B, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3A, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3B, }, +}; + +const GPTimerCC26XX_Config GPTimerCC26XX_config[CC1350DK_7XD_GPTIMERPARTSCOUNT] = { + { &gptimerCC26XXObjects[CC1350DK_7XD_GPTIMER0], &gptimerCC26xxHWAttrs[CC1350DK_7XD_GPTIMER0A], GPT_A }, + { &gptimerCC26XXObjects[CC1350DK_7XD_GPTIMER0], &gptimerCC26xxHWAttrs[CC1350DK_7XD_GPTIMER0B], GPT_B }, + { &gptimerCC26XXObjects[CC1350DK_7XD_GPTIMER1], &gptimerCC26xxHWAttrs[CC1350DK_7XD_GPTIMER1A], GPT_A }, + { &gptimerCC26XXObjects[CC1350DK_7XD_GPTIMER1], &gptimerCC26xxHWAttrs[CC1350DK_7XD_GPTIMER1B], GPT_B }, + { &gptimerCC26XXObjects[CC1350DK_7XD_GPTIMER2], &gptimerCC26xxHWAttrs[CC1350DK_7XD_GPTIMER2A], GPT_A }, + { &gptimerCC26XXObjects[CC1350DK_7XD_GPTIMER2], &gptimerCC26xxHWAttrs[CC1350DK_7XD_GPTIMER2B], GPT_B }, + { &gptimerCC26XXObjects[CC1350DK_7XD_GPTIMER3], &gptimerCC26xxHWAttrs[CC1350DK_7XD_GPTIMER3A], GPT_A }, + { &gptimerCC26XXObjects[CC1350DK_7XD_GPTIMER3], &gptimerCC26xxHWAttrs[CC1350DK_7XD_GPTIMER3B], GPT_B }, +}; + +/* + * =============================== I2C =============================== +*/ +#include +#include + +I2CCC26XX_Object i2cCC26xxObjects[CC1350DK_7XD_I2CCOUNT]; + +const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1350DK_7XD_I2CCOUNT] = { + { + .baseAddr = I2C0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_I2C0, + .intNum = INT_I2C_IRQ, + .intPriority = ~0, + .swiPriority = 0, + .sdaPin = CC1350DK_7XD_I2C0_SDA0, + .sclPin = CC1350DK_7XD_I2C0_SCL0, + } +}; + +const I2C_Config I2C_config[CC1350DK_7XD_I2CCOUNT] = { + { + .fxnTablePtr = &I2CCC26XX_fxnTable, + .object = &i2cCC26xxObjects[CC1350DK_7XD_I2C0], + .hwAttrs = &i2cCC26xxHWAttrs[CC1350DK_7XD_I2C0] + }, +}; + +const uint_least8_t I2C_count = CC1350DK_7XD_I2CCOUNT; + +/* + * =============================== NVS =============================== + */ +#include +#include +#include + +#define NVS_REGIONS_BASE 0x1A000 +#define SECTORSIZE 0x1000 +#define REGIONSIZE (SECTORSIZE * 4) + +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH + +/* + * Reserve flash sectors for NVS driver use by placing an uninitialized byte + * array at the desired flash address. + */ +#if defined(__TI_COMPILER_VERSION__) + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +#pragma LOCATION(flashBuf, NVS_REGIONS_BASE); +#pragma NOINIT(flashBuf); +static char flashBuf[REGIONSIZE]; + +#elif defined(__IAR_SYSTEMS_ICC__) + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +static __no_init char flashBuf[REGIONSIZE] @ NVS_REGIONS_BASE; + +#elif defined(__GNUC__) + +/* + * Place the flash buffers in the .nvs section created in the gcc linker file. + * The .nvs section enforces alignment on a sector boundary but may + * be placed anywhere in flash memory. If desired the .nvs section can be set + * to a fixed address by changing the following in the gcc linker file: + * + * .nvs (FIXED_FLASH_ADDR) (NOLOAD) : AT (FIXED_FLASH_ADDR) { + * *(.nvs) + * } > REGION_TEXT + */ +__attribute__ ((section (".nvs"))) +static char flashBuf[REGIONSIZE]; + +#endif + +/* Allocate objects for NVS Internal Regions */ +NVSCC26XX_Object nvsCC26xxObjects[1]; + +/* Hardware attributes for NVS Internal Regions */ +const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { + { + .regionBase = (void *)flashBuf, + .regionSize = REGIONSIZE, + }, +}; + +#endif /* Board_EXCLUDE_NVS_INTERNAL_FLASH */ + +/* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ +const NVS_Config NVS_config[CC1350DK_7XD_NVSCOUNT] = { +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH + { + .fxnTablePtr = &NVSCC26XX_fxnTable, + .object = &nvsCC26xxObjects[0], + .hwAttrs = &nvsCC26xxHWAttrs[0], + }, +#endif +}; + +const uint_least8_t NVS_count = CC1350DK_7XD_NVSCOUNT; + +/* + * =============================== PIN =============================== + */ +#include +#include + +const PIN_Config BoardGpioInitTable[] = { + + CC1350DK_7XD_PIN_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC1350DK_7XD_PIN_LED2 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC1350DK_7XD_PIN_LED3 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC1350DK_7XD_PIN_LED4 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC1350DK_7XD_PIN_KEY_SELECT | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC1350DK_7XD_PIN_KEY_UP | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC1350DK_7XD_PIN_KEY_DOWN | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC1350DK_7XD_PIN_KEY_LEFT | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC1350DK_7XD_PIN_KEY_UP | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC1350DK_7XD_SDCARD_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ + CC1350DK_7XD_LCD_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ + CC1350DK_7XD_ACC_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ + CC1350DK_7XD_UART_RX | PIN_INPUT_EN | PIN_PULLDOWN, /* UART RX via debugger back channel */ + CC1350DK_7XD_UART_TX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* UART TX via debugger back channel */ + CC1350DK_7XD_SPI0_MOSI | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master out - slave in */ + CC1350DK_7XD_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master in - slave out */ + CC1350DK_7XD_SPI0_CLK | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI clock */ + + PIN_TERMINATE +}; + +const PINCC26XX_HWAttrs PINCC26XX_hwAttrs = { + .intPriority = ~0, + .swiPriority = 0 +}; + +/* + * =============================== Power =============================== + */ +#include +#include + +const PowerCC26XX_Config PowerCC26XX_config = { + .policyInitFxn = NULL, + .policyFxn = &PowerCC26XX_standbyPolicy, + .calibrateFxn = &PowerCC26XX_calibrate, + .enablePolicy = true, + .calibrateRCOSC_LF = true, + .calibrateRCOSC_HF = true, +}; + +/* + * =============================== PWM =============================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +#include +#include + +PWMTimerCC26XX_Object pwmtimerCC26xxObjects[CC1350DK_7XD_PWMCOUNT]; + +const PWMTimerCC26XX_HwAttrs pwmtimerCC26xxHWAttrs[CC1350DK_7XD_PWMCOUNT] = { + { .pwmPin = CC1350DK_7XD_PWMPIN0, .gpTimerUnit = CC1350DK_7XD_GPTIMER0A }, + { .pwmPin = CC1350DK_7XD_PWMPIN1, .gpTimerUnit = CC1350DK_7XD_GPTIMER0B }, + { .pwmPin = CC1350DK_7XD_PWMPIN2, .gpTimerUnit = CC1350DK_7XD_GPTIMER1A }, + { .pwmPin = CC1350DK_7XD_PWMPIN3, .gpTimerUnit = CC1350DK_7XD_GPTIMER1B }, + { .pwmPin = CC1350DK_7XD_PWMPIN4, .gpTimerUnit = CC1350DK_7XD_GPTIMER2A }, + { .pwmPin = CC1350DK_7XD_PWMPIN5, .gpTimerUnit = CC1350DK_7XD_GPTIMER2B }, + { .pwmPin = CC1350DK_7XD_PWMPIN6, .gpTimerUnit = CC1350DK_7XD_GPTIMER3A }, + { .pwmPin = CC1350DK_7XD_PWMPIN7, .gpTimerUnit = CC1350DK_7XD_GPTIMER3B }, +}; + +const PWM_Config PWM_config[CC1350DK_7XD_PWMCOUNT] = { + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350DK_7XD_PWM0], &pwmtimerCC26xxHWAttrs[CC1350DK_7XD_PWM0] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350DK_7XD_PWM1], &pwmtimerCC26xxHWAttrs[CC1350DK_7XD_PWM1] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350DK_7XD_PWM2], &pwmtimerCC26xxHWAttrs[CC1350DK_7XD_PWM2] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350DK_7XD_PWM3], &pwmtimerCC26xxHWAttrs[CC1350DK_7XD_PWM3] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350DK_7XD_PWM4], &pwmtimerCC26xxHWAttrs[CC1350DK_7XD_PWM4] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350DK_7XD_PWM5], &pwmtimerCC26xxHWAttrs[CC1350DK_7XD_PWM5] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350DK_7XD_PWM6], &pwmtimerCC26xxHWAttrs[CC1350DK_7XD_PWM6] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC1350DK_7XD_PWM7], &pwmtimerCC26xxHWAttrs[CC1350DK_7XD_PWM7] }, +}; + +const uint_least8_t PWM_count = CC1350DK_7XD_PWMCOUNT; + +/* + * =============================== RF Driver =============================== + */ +#include + +const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { + .hwiPriority = ~0, /* Lowest HWI priority */ + .swiPriority = 0, /* Lowest SWI priority */ + .xoscHfAlwaysNeeded = true, /* Keep XOSC dependency while in stanby */ + .globalCallback = NULL, /* No board specific callback */ + .globalEventMask = 0 /* No events subscribed to */ +}; + +/* + * =============================== SD =============================== + */ +#include +#include + +SDSPI_Object sdspiObjects[CC1350DK_7XD_SDCOUNT]; + +const SDSPI_HWAttrs sdspiHWAttrs[CC1350DK_7XD_SDCOUNT] = { + { + .spiIndex = CC1350DK_7XD_SPI0, + .spiCsGpioIndex = CC1350DK_7XD_SDCARD_CS + } +}; + +const SD_Config SD_config[CC1350DK_7XD_SDCOUNT] = { + { + .fxnTablePtr = &SDSPI_fxnTable, + .object = &sdspiObjects[CC1350DK_7XD_SDSPI0], + .hwAttrs = &sdspiHWAttrs[CC1350DK_7XD_SDSPI0] + }, +}; + +const uint_least8_t SD_count = CC1350DK_7XD_SDCOUNT; + +/* + * =============================== SPI DMA =============================== + */ +#include +#include + +SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1350DK_7XD_SPICOUNT]; + +/* + * NOTE: The SPI instances below can be used by the SD driver to communicate + * with a SD card via SPI. The 'defaultTxBufValue' fields below are set to 0xFF + * to satisfy the SDSPI driver requirement. + */ +const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1350DK_7XD_SPICOUNT] = { + { + .baseAddr = SSI0_BASE, + .intNum = INT_SSI0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .powerMngrId = PowerCC26XX_PERIPH_SSI0, + .defaultTxBufValue = 0xFF, + .rxChannelBitMask = 1< +#include + +UARTCC26XX_Object uartCC26XXObjects[CC1350DK_7XD_UARTCOUNT]; + +uint8_t uartCC26XXRingBuffer[CC1350DK_7XD_UARTCOUNT][32]; + +const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1350DK_7XD_UARTCOUNT] = { + { + .baseAddr = UART0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UART0, + .intNum = INT_UART0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .txPin = CC1350DK_7XD_UART_TX, + .rxPin = CC1350DK_7XD_UART_RX, + .ctsPin = PIN_UNASSIGNED, + .rtsPin = PIN_UNASSIGNED, + .ringBufPtr = uartCC26XXRingBuffer[CC1350DK_7XD_UART0], + .ringBufSize = sizeof(uartCC26XXRingBuffer[CC1350DK_7XD_UART0]), + .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, + .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, + .errorFxn = NULL + } +}; + +const UART_Config UART_config[CC1350DK_7XD_UARTCOUNT] = { + { + .fxnTablePtr = &UARTCC26XX_fxnTable, + .object = &uartCC26XXObjects[CC1350DK_7XD_UART0], + .hwAttrs = &uartCC26XXHWAttrs[CC1350DK_7XD_UART0] + }, +}; + +const uint_least8_t UART_count = CC1350DK_7XD_UARTCOUNT; + +/* + * =============================== UDMA =============================== + */ +#include + +UDMACC26XX_Object udmaObjects[CC1350DK_7XD_UDMACOUNT]; + +const UDMACC26XX_HWAttrs udmaHWAttrs[CC1350DK_7XD_UDMACOUNT] = { + { + .baseAddr = UDMA0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UDMA, + .intNum = INT_DMA_ERR, + .intPriority = ~0 + } +}; + +const UDMACC26XX_Config UDMACC26XX_config[CC1350DK_7XD_UDMACOUNT] = { + { + .object = &udmaObjects[CC1350DK_7XD_UDMA0], + .hwAttrs = &udmaHWAttrs[CC1350DK_7XD_UDMA0] + }, +}; + + + +/* + * =============================== Watchdog =============================== + */ +#include +#include + +WatchdogCC26XX_Object watchdogCC26XXObjects[CC1350DK_7XD_WATCHDOGCOUNT]; + +const WatchdogCC26XX_HWAttrs watchdogCC26XXHWAttrs[CC1350DK_7XD_WATCHDOGCOUNT] = { + { + .baseAddr = WDT_BASE, + .reloadValue = 1000 /* Reload value in milliseconds */ + }, +}; + +const Watchdog_Config Watchdog_config[CC1350DK_7XD_WATCHDOGCOUNT] = { + { + .fxnTablePtr = &WatchdogCC26XX_fxnTable, + .object = &watchdogCC26XXObjects[CC1350DK_7XD_WATCHDOG0], + .hwAttrs = &watchdogCC26XXHWAttrs[CC1350DK_7XD_WATCHDOG0] + }, +}; + +const uint_least8_t Watchdog_count = CC1350DK_7XD_WATCHDOGCOUNT; + +/* + * Board-specific initialization function to disable external flash. + * This function is defined in the file CC1350DK_7XD_fxns.c + */ +extern void Board_initHook(void); + +/* + * ======== CC1350DK_7XD_initGeneral ======== + */ +void CC1350DK_7XD_initGeneral(void) +{ + Power_init(); + + if (PIN_init(BoardGpioInitTable) != PIN_SUCCESS) { + /* Error with PIN_init */ + while (1); + } + + /* Perform board-specific initialization */ + Board_initHook(); +} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h new file mode 100644 index 000000000..b6fa91497 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2015-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ +/** ============================================================================ + * @file CC1350DK_7XD.h + * + * @brief CC2650 LaunchPad Board Specific header file. + * + * The CC1350DK_7XD header file should be included in an application as + * follows: + * @code + * #include "CC1350DK_7XD.h" + * @endcode + * + * ============================================================================ + */ +#ifndef __CC1350DK_7XD_BOARD_H__ +#define __CC1350DK_7XD_BOARD_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes */ +#include +#include + +/* Externs */ +extern const PIN_Config BoardGpioInitTable[]; + +/* Defines */ +#define CC1350DK_7XD + +/* Mapping of pins to board signals using general board aliases + * + */ + +/* Analog Capable DIOs */ +#define CC1350DK_7XD_DIO23_ANALOG IOID_23 +#define CC1350DK_7XD_DIO24_ANALOG IOID_24 +#define CC1350DK_7XD_DIO25_ANALOG IOID_25 +#define CC1350DK_7XD_DIO26_ANALOG IOID_26 +#define CC1350DK_7XD_DIO27_ANALOG IOID_27 +#define CC1350DK_7XD_DIO28_ANALOG IOID_28 +#define CC1350DK_7XD_DIO29_ANALOG IOID_29 +#define CC1350DK_7XD_DIO30_ANALOG IOID_30 + +/* Digital IOs */ +#define CC1350DK_7XD_DIO0 IOID_0 +#define CC1350DK_7XD_DIO1_RFSW IOID_1 +#define CC1350DK_7XD_DIO12 IOID_12 +#define CC1350DK_7XD_DIO15 IOID_15 +#define CC1350DK_7XD_DIO16_TDO IOID_16 +#define CC1350DK_7XD_DIO17_TDI IOID_17 +#define CC1350DK_7XD_DIO21 IOID_21 +#define CC1350DK_7XD_DIO22 IOID_22 + +/* Discrete Inputs */ +#define CC1350DK_7XD_PIN_KEY_SELECT IOID_11 +#define CC1350DK_7XD_PIN_KEY_UP IOID_19 +#define CC1350DK_7XD_PIN_KEY_DOWN IOID_12 +#define CC1350DK_7XD_PIN_KEY_LEFT IOID_15 +#define CC1350DK_7XD_PIN_KEY_RIGHT IOID_18 + +/* GPIO */ +#define CC1350DK_7XD_GPIO_LED_ON 1 +#define CC1350DK_7XD_GPIO_LED_OFF 0 + +/* I2C */ +#define CC1350DK_7XD_I2C0_SCL0 PIN_UNASSIGNED +#define CC1350DK_7XD_I2C0_SDA0 PIN_UNASSIGNED + +/* LEDs */ +#define CC1350DK_7XD_PIN_LED_ON 1 +#define CC1350DK_7XD_PIN_LED_OFF 0 +#define CC1350DK_7XD_PIN_LED1 IOID_25 +#define CC1350DK_7XD_PIN_LED2 IOID_27 +#define CC1350DK_7XD_PIN_LED3 IOID_7 +#define CC1350DK_7XD_PIN_LED4 IOID_6 + +/* PWM Outputs */ +#define CC1350DK_7XD_PWMPIN0 CC1350DK_7XD_PIN_LED1 +#define CC1350DK_7XD_PWMPIN1 CC1350DK_7XD_PIN_LED2 +#define CC1350DK_7XD_PWMPIN2 PIN_UNASSIGNED +#define CC1350DK_7XD_PWMPIN3 PIN_UNASSIGNED +#define CC1350DK_7XD_PWMPIN4 PIN_UNASSIGNED +#define CC1350DK_7XD_PWMPIN5 PIN_UNASSIGNED +#define CC1350DK_7XD_PWMPIN6 PIN_UNASSIGNED +#define CC1350DK_7XD_PWMPIN7 PIN_UNASSIGNED + +/* SPI Board */ +#define CC1350DK_7XD_SPI0_MISO IOID_8 +#define CC1350DK_7XD_SPI0_MOSI IOID_9 +#define CC1350DK_7XD_SPI0_CLK IOID_10 +#define CC1350DK_7XD_SPI0_CSN PIN_UNASSIGNED +#define CC1350DK_7XD_SPI1_MISO PIN_UNASSIGNED +#define CC1350DK_7XD_SPI1_MOSI PIN_UNASSIGNED +#define CC1350DK_7XD_SPI1_CLK PIN_UNASSIGNED +#define CC1350DK_7XD_SPI1_CSN PIN_UNASSIGNED + +/* UART Board */ +#define CC1350DK_7XD_UART_RX IOID_2 +#define CC1350DK_7XD_UART_TX IOID_3 +#define CC1350DK_7XD_UART_CTS IOID_22 +#define CC1350DK_7XD_UART_RTS IOID_21 + +/* SD Card */ +#define CC1350DK_7XD_SDCARD_CS IOID_30 + +/* LCD Board */ +#define CC1350DK_7XD_LCD_MODE IOID_4 +#define CC1350DK_7XD_LCD_RST IOID_5 +#define CC1350DK_7XD_LCD_CS IOID_14 + +/* Ambient Light Sensor */ +#define CC1350DK_7XD_ALS_OUT IOID_23 +#define CC1350DK_7XD_ALS_PWR IOID_26 + +/* Accelerometer */ +#define CC1350DK_7XD_ACC_PWR IOID_20 +#define CC1350DK_7XD_ACC_CS IOID_24 + +/*! + * @brief Initialize the general board specific settings + * + * This function initializes the general board specific settings. + */ +void CC1350DK_7XD_initGeneral(void); + +/*! + * @brief Turn off the external flash on LaunchPads + * + */ +void CC1350DK_7XD_shutDownExtFlash(void); + +/*! + * @brief Wake up the external flash present on the board files + * + * This function toggles the chip select for the amount of time needed + * to wake the chip up. + */ +void CC1350DK_7XD_wakeUpExtFlash(void); + +/*! + * @def CC1350DK_7XD_ADCBufName + * @brief Enum of ADCs + */ +typedef enum CC1350DK_7XD_ADCBufName { + CC1350DK_7XD_ADCBUF0 = 0, + + CC1350DK_7XD_ADCBUFCOUNT +} CC1350DK_7XD_ADCBufName; + +/*! + * @def CC1350DK_7XD_ADCBuf0SourceName + * @brief Enum of ADCBuf channels + */ +typedef enum CC1350DK_7XD_ADCBuf0ChannelName { + CC1350DK_7XD_ADCBUF0CHANNELADCALS = 0, + CC1350DK_7XD_ADCBUF0CHANNELVDDS, + CC1350DK_7XD_ADCBUF0CHANNELDCOUPL, + CC1350DK_7XD_ADCBUF0CHANNELVSS, + + CC1350DK_7XD_ADCBUF0CHANNELCOUNT +} CC1350DK_7XD_ADCBuf0ChannelName; + +/*! + * @def CC1350DK_7XD_ADCName + * @brief Enum of ADCs + */ +typedef enum CC1350DK_7XD_ADCName { + CC1350DK_7XD_ADCALS = 0, + CC1350DK_7XD_ADCDCOUPL, + CC1350DK_7XD_ADCVSS, + CC1350DK_7XD_ADCVDDS, + + CC1350DK_7XD_ADCCOUNT +} CC1350DK_7XD_ADCName; + +/*! + * @def CC1350DK_7XD_CryptoName + * @brief Enum of Crypto names + */ +typedef enum CC1350DK_7XD_CryptoName { + CC1350DK_7XD_CRYPTO0 = 0, + + CC1350DK_7XD_CRYPTOCOUNT +} CC1350DK_7XD_CryptoName; + +/*! + * @def CC1350DK_7XD_GPIOName + * @brief Enum of GPIO names + */ +typedef enum CC1350DK_7XD_GPIOName { + CC1350DK_7XD_GPIO_KEY_SELECT = 0, + CC1350DK_7XD_GPIO_KEY_UP, + CC1350DK_7XD_GPIO_KEY_DOWN, + CC1350DK_7XD_GPIO_KEY_LEFT, + CC1350DK_7XD_GPIO_KEY_RIGHT, + CC1350DK_7XD_SPI_MASTER_READY, + CC1350DK_7XD_SPI_SLAVE_READY, + CC1350DK_7XD_GPIO_LED1, + CC1350DK_7XD_GPIO_LED2, + CC1350DK_7XD_GPIO_LED3, + CC1350DK_7XD_GPIO_LED4, + CC1350DK_7XD_GPIO_SDCARD_CS, + CC1350DK_7XD_GPIO_ACC_CS, + CC1350DK_7XD_GPIO_LCD_CS, + CC1350DK_7XD_GPIO_LCD_POWER, + CC1350DK_7XD_GPIO_LCD_ENABLE, + + CC1350DK_7XD_GPIOCOUNT +} CC1350DK_7XD_GPIOName; + +/*! + * @def CC1350DK_7XD_GPTimerName + * @brief Enum of GPTimer parts + */ +typedef enum CC1350DK_7XD_GPTimerName { + CC1350DK_7XD_GPTIMER0A = 0, + CC1350DK_7XD_GPTIMER0B, + CC1350DK_7XD_GPTIMER1A, + CC1350DK_7XD_GPTIMER1B, + CC1350DK_7XD_GPTIMER2A, + CC1350DK_7XD_GPTIMER2B, + CC1350DK_7XD_GPTIMER3A, + CC1350DK_7XD_GPTIMER3B, + + CC1350DK_7XD_GPTIMERPARTSCOUNT +} CC1350DK_7XD_GPTimerName; + +/*! + * @def CC1350DK_7XD_GPTimers + * @brief Enum of GPTimers + */ +typedef enum CC1350DK_7XD_GPTimers { + CC1350DK_7XD_GPTIMER0 = 0, + CC1350DK_7XD_GPTIMER1, + CC1350DK_7XD_GPTIMER2, + CC1350DK_7XD_GPTIMER3, + + CC1350DK_7XD_GPTIMERCOUNT +} CC1350DK_7XD_GPTimers; + +/*! + * @def CC1350DK_7XD_I2CName + * @brief Enum of I2C names + */ +typedef enum CC1350DK_7XD_I2CName { + CC1350DK_7XD_I2C0 = 0, + + CC1350DK_7XD_I2CCOUNT +} CC1350DK_7XD_I2CName; + +/*! + * @def CC1350DK_7XD_NVSName + * @brief Enum of NVS names + */ +typedef enum CC1350DK_7XD_NVSName { +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH + CC1350DK_7XD_NVSCC26XX0 = 0, +#endif + + CC1350DK_7XD_NVSCOUNT +} CC1350DK_7XD_NVSName; + +/*! + * @def CC1350DK_7XD_PWM + * @brief Enum of PWM outputs + */ +typedef enum CC1350DK_7XD_PWMName { + CC1350DK_7XD_PWM0 = 0, + CC1350DK_7XD_PWM1, + CC1350DK_7XD_PWM2, + CC1350DK_7XD_PWM3, + CC1350DK_7XD_PWM4, + CC1350DK_7XD_PWM5, + CC1350DK_7XD_PWM6, + CC1350DK_7XD_PWM7, + + CC1350DK_7XD_PWMCOUNT +} CC1350DK_7XD_PWMName; + +/*! + * @def CC1350DK_7XD_SDName + * @brief Enum of SD names + */ +typedef enum CC1350DK_7XD_SDName { + CC1350DK_7XD_SDSPI0 = 0, + + CC1350DK_7XD_SDCOUNT +} CC1350DK_7XD_SDName; + +/*! + * @def CC1350DK_7XD_SPIName + * @brief Enum of SPI names + */ +typedef enum CC1350DK_7XD_SPIName { + CC1350DK_7XD_SPI0 = 0, + CC1350DK_7XD_SPI1, + + CC1350DK_7XD_SPICOUNT +} CC1350DK_7XD_SPIName; + +/*! + * @def CC1350DK_7XD_UARTName + * @brief Enum of UARTs + */ +typedef enum CC1350DK_7XD_UARTName { + CC1350DK_7XD_UART0 = 0, + + CC1350DK_7XD_UARTCOUNT +} CC1350DK_7XD_UARTName; + +/*! + * @def CC1350DK_7XD_UDMAName + * @brief Enum of DMA buffers + */ +typedef enum CC1350DK_7XD_UDMAName { + CC1350DK_7XD_UDMA0 = 0, + + CC1350DK_7XD_UDMACOUNT +} CC1350DK_7XD_UDMAName; + +/*! + * @def CC1350DK_7XD_WatchdogName + * @brief Enum of Watchdogs + */ +typedef enum CC1350DK_7XD_WatchdogName { + CC1350DK_7XD_WATCHDOG0 = 0, + + CC1350DK_7XD_WATCHDOGCOUNT +} CC1350DK_7XD_WatchdogName; + +#ifdef __cplusplus +} +#endif + +#endif /* __CC1350DK_7XD_BOARD_H__ */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD_fxns.c new file mode 100644 index 000000000..e012731c6 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD_fxns.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +/* + * ======== CC1350DK_7XD_fxns.c ======== + * This file contains the board-specific initialization functions. + */ + +#include +#include +#include + +#include +#include + +#include + +#include "Board.h" + +/* + * ======== CC1350DK_7XD_wakeUpExtFlash ======== + */ +void CC1350DK_7XD_wakeUpExtFlash(void) +{ + /* No external flash on CC1350DK_7XD */ +} + +/* + * ======== CC1350DK_7XD_shutDownExtFlash ======== + */ +void CC1350DK_7XD_shutDownExtFlash(void) +{ + /* No external flash on CC1350DK_7XD */ +} + +/* + * ======== Board_initHook ======== + * Called by Board_init() to perform board-specific initialization. + */ +void Board_initHook() +{ + CC1350DK_7XD_shutDownExtFlash(); +} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 index 0069d0241..849ebc663 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 @@ -5,7 +5,7 @@ SUBFAMILY = cc13x0-cc26x0 DEVICE_FAMILY = CC13X0 DEVICE_LINE = CC13XX -BOARD_SOURCEFILES += CC1310DK_7XD.c +BOARD_SOURCEFILES += CC1310DK_7XD.c CC1310DK_7XD_fxns.c SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Board.h index cfc985633..b1a7b6a94 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Board.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, Texas Instruments Incorporated + * Copyright (c) 2015-2018, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,52 +33,131 @@ #ifndef __BOARD_H #define __BOARD_H +#define Board_CC2650DK_7ID + #ifdef __cplusplus extern "C" { #endif -#include - #include "CC2650DK_7ID.h" +#define Board_initGeneral() CC2650DK_7ID_initGeneral() +#define Board_shutDownExtFlash() CC2650DK_7ID_shutDownExtFlash() +#define Board_wakeUpExtFlash() CC2650DK_7ID_wakeUpExtFlash() + /* These #defines allow us to reuse TI-RTOS across other device families */ -#define Board_LED1 Board_DK_LED1 -#define Board_LED2 Board_DK_LED2 -#define Board_LED3 Board_DK_LED3 -#define Board_LED4 Board_DK_LED4 -#define Board_LED0 Board_DK_LED4 +#define Board_ADCALS CC2650DK_7ID_ADCALS -#define Board_BUTTON0 Board_KEY_UP -#define Board_BUTTON1 Board_KEY_DOWN +#define Board_ADC0 CC2650DK_7ID_ADCVDDS +#define Board_ADC1 CC2650DK_7ID_ADCALS -#define Board_UART0 Board_UART -#define Board_AES0 Board_AES -#define Board_WATCHDOG0 CC2650DK_7ID_WATCHDOG0 +#define Board_ADCBUF0 CC2650DK_7ID_ADCBUF0 +#define Board_ADCBUF0CHANNEL0 CC2650DK_7ID_ADCBUF0CHANNELVDDS +#define Board_ADCBUF0CHANNEL1 CC2650DK_7ID_ADCBUF0CHANNELADCALS -#define Board_ADC0 CC2650DK_7ID_ADCVDDS -#define Board_ADC1 CC2650DK_7ID_ADCALS +#define Board_CRYPTO0 CC2650DK_7ID_CRYPTO0 -#define Board_ADCBuf0 CC2650DK_7ID_ADCBuf0 -#define Board_ADCBufChannel0 (0) -#define Board_ADCBufChannel1 (1) +#define Board_DIO0 CC2650DK_7ID_DIO0 +#define Board_DIO1_RFSW CC2650DK_7ID_DIO1_RFSW +#define Board_DIO12 CC2650DK_7ID_DIO12 +#define Board_DIO15 CC2650DK_7ID_DIO15 +#define Board_DIO16_TDO CC2650DK_7ID_DIO16_TDO +#define Board_DIO17_TDI CC2650DK_7ID_DIO17_TDI +#define Board_DIO21 CC2650DK_7ID_DIO21 +#define Board_DIO22 CC2650DK_7ID_DIO22 -#define Board_initGeneral() { \ - Power_init(); \ - if (PIN_init(BoardGpioInitTable) != PIN_SUCCESS) \ - {System_abort("Error with PIN_init\n"); \ - } \ -} +#define Board_DIO23_ANALOG CC2650DK_7ID_DIO23_ANALOG +#define Board_DIO24_ANALOG CC2650DK_7ID_DIO24_ANALOG +#define Board_DIO25_ANALOG CC2650DK_7ID_DIO25_ANALOG +#define Board_DIO26_ANALOG CC2650DK_7ID_DIO26_ANALOG +#define Board_DIO27_ANALOG CC2650DK_7ID_DIO27_ANALOG +#define Board_DIO28_ANALOG CC2650DK_7ID_DIO28_ANALOG +#define Board_DIO29_ANALOG CC2650DK_7ID_DIO29_ANALOG +#define Board_DIO30_ANALOG CC2650DK_7ID_DIO30_ANALOG -#define Board_initGPIO() -#define Board_initPWM() PWM_init() -#define Board_initSPI() SPI_init() -#define Board_initUART() UART_init() -#define Board_initWatchdog() Watchdog_init() -#define Board_initADCBuf() ADCBuf_init() -#define Board_initADC() ADC_init() -#define GPIO_toggle(n) -#define GPIO_write(n,m) +#define Board_GPIO_BTN0 CC2650DK_7ID_PIN_KEY_SELECT +#define Board_GPIO_BTN1 CC2650DK_7ID_PIN_KEY_UP +#define Board_GPIO_BTN2 CC2650DK_7ID_PIN_KEY_DOWN +#define Board_GPIO_BTN3 CC2650DK_7ID_PIN_KEY_LEFT +#define Board_GPIO_BTN4 CC2650DK_7ID_PIN_KEY_RIGHT +#define Board_GPIO_LED0 CC2650DK_7ID_PIN_LED1 +#define Board_GPIO_LED1 CC2650DK_7ID_PIN_LED2 +#define Board_GPIO_LED2 CC2650DK_7ID_PIN_LED3 +#define Board_GPIO_LED3 CC2650DK_7ID_PIN_LED4 +#define Board_GPIO_LED_ON CC2650DK_7ID_GPIO_LED_ON +#define Board_GPIO_LED_OFF CC2650DK_7ID_GPIO_LED_OFF + +#define Board_GPTIMER0A CC2650DK_7ID_GPTIMER0A +#define Board_GPTIMER0B CC2650DK_7ID_GPTIMER0B +#define Board_GPTIMER1A CC2650DK_7ID_GPTIMER1A +#define Board_GPTIMER1B CC2650DK_7ID_GPTIMER1B +#define Board_GPTIMER2A CC2650DK_7ID_GPTIMER2A +#define Board_GPTIMER2B CC2650DK_7ID_GPTIMER2B +#define Board_GPTIMER3A CC2650DK_7ID_GPTIMER3A +#define Board_GPTIMER3B CC2650DK_7ID_GPTIMER3B + +#define Board_I2C0 CC2650DK_7ID_I2C0 + +#define Board_NVSINTERNAL CC2650DK_7ID_NVSCC26XX0 + +#define Board_KEY_SELECT CC2650DK_7ID_PIN_KEY_SELECT +#define Board_KEY_UP CC2650DK_7ID_PIN_KEY_UP +#define Board_KEY_DOWN CC2650DK_7ID_PIN_KEY_DOWN +#define Board_KEY_LEFT CC2650DK_7ID_PIN_KEY_LEFT +#define Board_KEY_RIGHT CC2650DK_7ID_PIN_KEY_RIGHT + +#define Board_PIN_BUTTON0 CC2650DK_7ID_PIN_KEY_SELECT +#define Board_PIN_BUTTON1 CC2650DK_7ID_PIN_KEY_UP +#define Board_PIN_BUTTON2 CC2650DK_7ID_PIN_KEY_DOWN +#define Board_PIN_BUTTON3 CC2650DK_7ID_PIN_KEY_LEFT +#define Board_PIN_BUTTON4 CC2650DK_7ID_PIN_KEY_RIGHT +#define Board_PIN_BTN1 CC2650DK_7ID_PIN_KEY_SELECT +#define Board_PIN_BTN2 CC2650DK_7ID_PIN_KEY_UP +#define Board_PIN_BTN3 CC2650DK_7ID_PIN_KEY_DOWN +#define Board_PIN_BTN4 CC2650DK_7ID_PIN_KEY_LEFT +#define Board_PIN_BTN5 CC2650DK_7ID_PIN_KEY_RIGHT +#define Board_PIN_LED0 CC2650DK_7ID_PIN_LED1 +#define Board_PIN_LED1 CC2650DK_7ID_PIN_LED2 +#define Board_PIN_LED2 CC2650DK_7ID_PIN_LED3 +#define Board_PIN_LED3 CC2650DK_7ID_PIN_LED4 + +#define Board_PWM0 CC2650DK_7ID_PWM0 +#define Board_PWM1 CC2650DK_7ID_PWM1 +#define Board_PWM2 CC2650DK_7ID_PWM2 +#define Board_PWM3 CC2650DK_7ID_PWM3 +#define Board_PWM4 CC2650DK_7ID_PWM4 +#define Board_PWM5 CC2650DK_7ID_PWM5 +#define Board_PWM6 CC2650DK_7ID_PWM6 +#define Board_PWM7 CC2650DK_7ID_PWM7 + +#define Board_SD0 CC2650DK_7ID_SDSPI0 + +#define Board_SPI0 CC2650DK_7ID_SPI0 +#define Board_SPI1 CC2650DK_7ID_SPI1 +#define Board_FLASH_CS_ON 0 +#define Board_FLASH_CS_OFF 1 + +#define Board_SPI_MASTER CC2650DK_7ID_SPI0 +#define Board_SPI_SLAVE CC2650DK_7ID_SPI0 +#define Board_SPI_MASTER_READY CC2650DK_7ID_SPI_MASTER_READY +#define Board_SPI_SLAVE_READY CC2650DK_7ID_SPI_SLAVE_READY + +#define Board_UART0 CC2650DK_7ID_UART0 + +#define Board_WATCHDOG0 CC2650DK_7ID_WATCHDOG0 + +#define Board_SDCARD_CS CC2650DK_7ID_SDCARD_CS + +#define Board_LCD_MODE CC2650DK_7ID_LCD_MODE +#define Board_LCD_RST CC2650DK_7ID_LCD_RST +#define Board_LCD_CS CC2650DK_7ID_LCD_CS + +#define Board_ALS_OUT CC2650DK_7ID_ALS_OUT +#define Board_ALS_PWR CC2650DK_7ID_ALS_PWR + +#define Board_ACC_PWR CC2650DK_7ID_ACC_PWR +#define Board_ACC_CS CC2650DK_7ID_ACC_CS #ifdef __cplusplus } diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c index 59d489725..51df6137c 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, Texas Instruments Incorporated + * Copyright (c) 2016-2018, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,296 +31,127 @@ */ /* - * ====================== CC2650DK_7ID.c ============================================= + * ====================== CC2650DK_7ID.c =================================== * This file is responsible for setting up the board specific items for the - * SRF06EB with the CC2650EM_7ID board. + * CC2650DK_7ID board. */ +#include +#include +#include + +#include +#include +#include +#include + +#include "CC2650DK_7ID.h" /* - * ====================== Includes ============================================ + * =============================== ADCBuf =============================== */ -#include -#include +#include +#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include +ADCBufCC26XX_Object adcBufCC26xxObjects[CC2650DK_7ID_ADCBUFCOUNT]; /* - * ========================= IO driver initialization ========================= - * From main, PIN_init(BoardGpioInitTable) should be called to setup safe - * settings for this board. - * When a pin is allocated and then de-allocated, it will revert to the state - * configured in this table. + * This table converts a virtual adc channel into a dio and internal analogue + * input signal. This table is necessary for the functioning of the adcBuf + * driver. Comment out unused entries to save flash. Dio and internal signal + * pairs are hardwired. Do not remap them in the table. You may reorder entire + * entries. The mapping of dio and internal signals is package dependent. */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(BoardGpioInitTable, ".const:BoardGpioInitTable") -#pragma DATA_SECTION(PINCC26XX_hwAttrs, ".const:PINCC26XX_hwAttrs") -#endif - -const PIN_Config BoardGpioInitTable[] = { - - Board_DK_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ - Board_DK_LED2 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ - Board_DK_LED3 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ - Board_DK_LED4 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ - Board_KEY_SELECT | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS, /* Button is active low */ - Board_KEY_UP | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS, /* Button is active low */ - Board_KEY_DOWN | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS, /* Button is active low */ - Board_KEY_LEFT | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS, /* Button is active low */ - Board_KEY_RIGHT | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS, /* Button is active low */ - Board_3V3_EN | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL, /* 3V3 domain off initially */ - Board_LCD_MODE | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* LCD pin high initially */ - Board_LCD_RST | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* LCD pin high initially */ - Board_LCD_CSN | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* LCD CSn deasserted initially */ - Board_ALS_PWR | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL, /* ALS power off initially */ - Board_ACC_PWR | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL, /* ACC power off initially */ - Board_ACC_CSN | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* ACC CSn deasserted initially */ - Board_SDCARD_CSN | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* SDCARD CSn deasserted initially */ - Board_UART_TX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* UART TX pin at inactive level */ - PIN_TERMINATE /* Terminate list */ +const ADCBufCC26XX_AdcChannelLutEntry ADCBufCC26XX_adcChannelLut[CC2650DK_7ID_ADCBUF0CHANNELCOUNT] = { + {CC2650DK_7ID_ALS_OUT, ADC_COMPB_IN_AUXIO7}, + {PIN_UNASSIGNED, ADC_COMPB_IN_DCOUPL}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VSS}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VDDS}, }; -const PINCC26XX_HWAttrs PINCC26XX_hwAttrs = { - .intPriority = ~0, - .swiPriority = 0 -}; -/*============================================================================*/ - -/* - * ============================= Power begin =================================== - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(PowerCC26XX_config, ".const:PowerCC26XX_config") -#endif -const PowerCC26XX_Config PowerCC26XX_config = { - .policyInitFxn = NULL, - .policyFxn = &PowerCC26XX_standbyPolicy, - .calibrateFxn = &PowerCC26XX_calibrate, - .enablePolicy = TRUE, - .calibrateRCOSC_LF = TRUE, - .calibrateRCOSC_HF = TRUE, -}; -/* - * ============================= Power end =================================== - */ - -/* - * ============================= UART begin =================================== - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(UART_config, ".const:UART_config") -#pragma DATA_SECTION(uartCC26XXHWAttrs, ".const:uartCC26XXHWAttrs") -#endif - -/* Include drivers */ -#include -#include - -/* UART objects */ -UARTCC26XX_Object uartCC26XXObjects[CC2650DK_7ID_UARTCOUNT]; -unsigned char uartCC26XXRingBuffer[CC2650DK_7ID_UARTCOUNT][32]; - -/* UART hardware parameter structure, also used to assign UART pins */ -const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC2650DK_7ID_UARTCOUNT] = { +const ADCBufCC26XX_HWAttrs adcBufCC26xxHWAttrs[CC2650DK_7ID_ADCBUFCOUNT] = { { - .baseAddr = UART0_BASE, - .powerMngrId = PowerCC26XX_PERIPH_UART0, - .intNum = INT_UART0_COMB, - .intPriority = ~0, - .swiPriority = 0, - .txPin = Board_UART_TX, - .rxPin = Board_UART_RX, - .ctsPin = PIN_UNASSIGNED, - .rtsPin = PIN_UNASSIGNED, - .ringBufPtr = uartCC26XXRingBuffer[0], - .ringBufSize = sizeof(uartCC26XXRingBuffer[0]) + .intPriority = ~0, + .swiPriority = 0, + .adcChannelLut = ADCBufCC26XX_adcChannelLut, + .gpTimerUnit = CC2650DK_7ID_GPTIMER0A, + .gptDMAChannelMask = 1 << UDMA_CHAN_TIMER0_A, } }; -/* UART configuration structure */ -const UART_Config UART_config[] = { +const ADCBuf_Config ADCBuf_config[CC2650DK_7ID_ADCBUFCOUNT] = { { - .fxnTablePtr = &UARTCC26XX_fxnTable, - .object = &uartCC26XXObjects[0], - .hwAttrs = &uartCC26XXHWAttrs[0] + &ADCBufCC26XX_fxnTable, + &adcBufCC26xxObjects[CC2650DK_7ID_ADCBUF0], + &adcBufCC26xxHWAttrs[CC2650DK_7ID_ADCBUF0] }, - {NULL, NULL, NULL} }; -/* - * ============================= UART end ===================================== - */ + +const uint_least8_t ADCBuf_count = CC2650DK_7ID_ADCBUFCOUNT; /* - * ============================= UDMA begin =================================== + * =============================== ADC =============================== */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(UDMACC26XX_config, ".const:UDMACC26XX_config") -#pragma DATA_SECTION(udmaHWAttrs, ".const:udmaHWAttrs") -#endif +#include +#include -/* Include drivers */ -#include +ADCCC26XX_Object adcCC26xxObjects[CC2650DK_7ID_ADCCOUNT]; -/* UDMA objects */ -UDMACC26XX_Object udmaObjects[CC2650DK_7ID_UDMACOUNT]; - -/* UDMA configuration structure */ -const UDMACC26XX_HWAttrs udmaHWAttrs[CC2650DK_7ID_UDMACOUNT] = { +const ADCCC26XX_HWAttrs adcCC26xxHWAttrs[CC2650DK_7ID_ADCCOUNT] = { { - .baseAddr = UDMA0_BASE, - .powerMngrId = PowerCC26XX_PERIPH_UDMA, - .intNum = INT_DMA_ERR, - .intPriority = ~0 + .adcDIO = CC2650DK_7ID_DIO23_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO7, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_DCOUPL, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VSS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VDDS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL, + .returnAdjustedVal = false } }; -/* UDMA configuration structure */ -const UDMACC26XX_Config UDMACC26XX_config[] = { - { - .object = &udmaObjects[0], - .hwAttrs = &udmaHWAttrs[0] - }, - {NULL, NULL} +const ADC_Config ADC_config[CC2650DK_7ID_ADCCOUNT] = { + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC2650DK_7ID_ADCALS], &adcCC26xxHWAttrs[CC2650DK_7ID_ADCALS]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC2650DK_7ID_ADCDCOUPL], &adcCC26xxHWAttrs[CC2650DK_7ID_ADCDCOUPL]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC2650DK_7ID_ADCVSS], &adcCC26xxHWAttrs[CC2650DK_7ID_ADCVSS]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[CC2650DK_7ID_ADCVDDS], &adcCC26xxHWAttrs[CC2650DK_7ID_ADCVDDS]}, }; + +const uint_least8_t ADC_count = CC2650DK_7ID_ADCCOUNT; + /* - * ============================= UDMA end ===================================== + * =============================== Crypto =============================== */ - -/* - * ========================== SPI DMA begin =================================== - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(SPI_config, ".const:SPI_config") -#pragma DATA_SECTION(spiCC26XXDMAHWAttrs, ".const:spiCC26XXDMAHWAttrs") -#endif - -/* Include drivers */ -#include - -/* SPI objects */ -SPICC26XXDMA_Object spiCC26XXDMAObjects[CC2650DK_7ID_SPICOUNT]; - -/* SPI configuration structure, describing which pins are to be used */ -const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC2650DK_7ID_SPICOUNT] = { - { - .baseAddr = SSI0_BASE, - .intNum = INT_SSI0_COMB, - .intPriority = ~0, - .swiPriority = 0, - .powerMngrId = PowerCC26XX_PERIPH_SSI0, - .defaultTxBufValue = 0, - .rxChannelBitMask = 1< - -/* LCD object */ -LCD_Object lcdObject; - -/* LCD hardware attribute structure */ -const LCD_HWAttrs lcdHWAttrs = { - .LCD_initCmd = &LCD_initCmd, - .lcdResetPin = Board_LCD_RST, /* LCD reset pin */ - .lcdModePin = Board_LCD_MODE, /* LCD mode pin */ - .lcdCsnPin = Board_LCD_CSN, /* LCD CSn pin */ - .spiIndex = Board_SPI0 -}; - -/* LCD configuration structure */ -const LCD_Config LCD_config = { - .object = &lcdObject, - .hwAttrs = &lcdHWAttrs -}; -/* - * ========================== LCD end ========================================= - */ - -/* - * ========================== Crypto begin ==================================== - * NOTE: The Crypto implementation should be considered experimental - * and not validated! - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(CryptoCC26XX_config, ".const:CryptoCC26XX_config") -#pragma DATA_SECTION(cryptoCC26XXHWAttrs, ".const:cryptoCC26XXHWAttrs") -#endif - -/* Include drivers */ #include -/* Crypto objects */ CryptoCC26XX_Object cryptoCC26XXObjects[CC2650DK_7ID_CRYPTOCOUNT]; -/* Crypto configuration structure, describing which pins are to be used */ const CryptoCC26XX_HWAttrs cryptoCC26XXHWAttrs[CC2650DK_7ID_CRYPTOCOUNT] = { { .baseAddr = CRYPTO_BASE, @@ -330,114 +161,173 @@ const CryptoCC26XX_HWAttrs cryptoCC26XXHWAttrs[CC2650DK_7ID_CRYPTOCOUNT] = { } }; -/* Crypto configuration structure */ -const CryptoCC26XX_Config CryptoCC26XX_config[] = { +const CryptoCC26XX_Config CryptoCC26XX_config[CC2650DK_7ID_CRYPTOCOUNT] = { { - .object = &cryptoCC26XXObjects[0], - .hwAttrs = &cryptoCC26XXHWAttrs[0] + .object = &cryptoCC26XXObjects[CC2650DK_7ID_CRYPTO0], + .hwAttrs = &cryptoCC26XXHWAttrs[CC2650DK_7ID_CRYPTO0] }, - {NULL, NULL} -}; -/* - * ========================== Crypto end ========================================= - */ - - -/* - * ========================= RF driver begin ============================================== - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(RFCC26XX_hwAttrs, ".const:RFCC26XX_hwAttrs") -#endif - -/* Include drivers */ -#include - -/* RF hwi and swi priority */ -const RFCC26XX_HWAttrs RFCC26XX_hwAttrs = { - .hwiCpe0Priority = ~0, - .hwiHwPriority = ~0, - .swiCpe0Priority = 0, - .swiHwPriority = 0, }; /* - * ========================== RF driver end ========================================= + * =============================== Display =============================== */ - -/* - * ========================= Display begin ==================================== - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(Display_config, ".const:Display_config") -#pragma DATA_SECTION(displayDogm1286HWattrs, ".const:displayDogm1286HWAttrs") -#pragma DATA_SECTION(displayUartHWAttrs, ".const:displayUartHWAttrs") -#endif - -#include -#include -#include - -/* Structures for UartPlain Blocking */ -DisplayUart_Object displayUartObject; +#include +#include +#include #ifndef BOARD_DISPLAY_UART_STRBUF_SIZE #define BOARD_DISPLAY_UART_STRBUF_SIZE 128 #endif + +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 +#endif + +DisplayUart_Object displayUartObject; +DisplaySharp_Object displaySharpObject; + static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; +static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; const DisplayUart_HWAttrs displayUartHWAttrs = { - .uartIdx = Board_UART, - .baudRate = 115200, - .mutexTimeout = BIOS_WAIT_FOREVER, - .strBuf = uartStringBuf, - .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, + .uartIdx = CC2650DK_7ID_UART0, + .baudRate = 115200, + .mutexTimeout = (unsigned int)(-1), + .strBuf = uartStringBuf, + .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, }; -/* Structures for DOGM1286 */ -DisplayDogm1286_Object displayDogm1286Object; - -const DisplayDogm1286_HWAttrs displayDogm1286HWattrs = { - .lcdHandle = (LCD_Handle) & LCD_config, - .powerPin = Board_3V3_EN +const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { + .spiIndex = CC2650DK_7ID_SPI0, + .csPin = CC2650DK_7ID_GPIO_LCD_CS, + .powerPin = CC2650DK_7ID_GPIO_LCD_POWER, + .enablePin = CC2650DK_7ID_GPIO_LCD_ENABLE, + .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, + .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, + .displayBuf = sharpDisplayBuf, }; -/* Array of displays */ +#ifndef BOARD_DISPLAY_USE_UART +#define BOARD_DISPLAY_USE_UART 1 +#endif +#ifndef BOARD_DISPLAY_USE_UART_ANSI +#define BOARD_DISPLAY_USE_UART_ANSI 0 +#endif +#ifndef BOARD_DISPLAY_USE_LCD +#define BOARD_DISPLAY_USE_LCD 0 +#endif + +/* + * This #if/#else is needed to workaround a problem with the + * IAR compiler. The IAR compiler doesn't like the empty array + * initialization. (IAR Error[Pe1345]) + */ +#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) + const Display_Config Display_config[] = { -#if !defined(BOARD_DISPLAY_EXCLUDE_UART) +#if (BOARD_DISPLAY_USE_UART) { - .fxnTablePtr = &DisplayUart_fxnTable, +# if (BOARD_DISPLAY_USE_UART_ANSI) + .fxnTablePtr = &DisplayUartAnsi_fxnTable, +# else /* Default to minimal UART with no cursor placement */ + .fxnTablePtr = &DisplayUartMin_fxnTable, +# endif .object = &displayUartObject, .hwAttrs = &displayUartHWAttrs, }, #endif -#if !defined(BOARD_DISPLAY_EXCLUDE_LCD) +#if (BOARD_DISPLAY_USE_LCD) { - .fxnTablePtr = &DisplayDogm1286_fxnTable, - .object = &displayDogm1286Object, - .hwAttrs = &displayDogm1286HWattrs + .fxnTablePtr = &DisplaySharp_fxnTable, + .object = &displaySharpObject, + .hwAttrs = &displaySharpHWattrs }, #endif - { NULL, NULL, NULL } // Terminator +}; + +const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); + +#else + +const Display_Config *Display_config = NULL; +const uint_least8_t Display_count = 0; + +#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ + +/* + * =============================== GPIO =============================== + */ +#include +#include + +/* + * Array of Pin configurations + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC2650DK_7ID.h + * NOTE: Pins not used for interrupts should be placed at the end of the + * array. Callback entries can be omitted from callbacks array to + * reduce memory usage. + */ +GPIO_PinConfig gpioPinConfigs[] = { + /* Input pins */ + GPIOCC26XX_DIO_11 | GPIO_DO_NOT_CONFIG, /* Key Select */ + GPIOCC26XX_DIO_19 | GPIO_DO_NOT_CONFIG, /* Key Up */ + GPIOCC26XX_DIO_12 | GPIO_DO_NOT_CONFIG, /* Key Down */ + GPIOCC26XX_DIO_15 | GPIO_DO_NOT_CONFIG, /* Key Left */ + GPIOCC26XX_DIO_18 | GPIO_DO_NOT_CONFIG, /* Key Right */ + + GPIOCC26XX_DIO_15 | GPIO_DO_NOT_CONFIG, /* CC2650DK_7ID_SPI_MASTER_READY */ + GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG, /* CC2650DK_7ID_SPI_SLAVE_READY */ + + /* Output pins */ + GPIOCC26XX_DIO_25 | GPIO_DO_NOT_CONFIG, /* LED 1 */ + GPIOCC26XX_DIO_27 | GPIO_DO_NOT_CONFIG, /* LED 2 */ + GPIOCC26XX_DIO_07 | GPIO_DO_NOT_CONFIG, /* LED 3 */ + GPIOCC26XX_DIO_06 | GPIO_DO_NOT_CONFIG, /* LED 4 */ + + /* SDCARD */ + GPIOCC26XX_DIO_30 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ + + /* Accelerometer */ + GPIOCC26XX_DIO_24 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ + + /* Sharp Display - GPIO configurations will be done in the Display files */ + GPIOCC26XX_DIO_14 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ + GPIOCC26XX_DIO_05 | GPIO_DO_NOT_CONFIG, /* LCD power control */ + GPIOCC26XX_DIO_04 | GPIO_DO_NOT_CONFIG, /* LCD enable */ + }; /* - * ========================= Display end ====================================== + * Array of callback function pointers + * NOTE: The order of the pin configurations must coincide with what was + * defined in CC2650_LAUNCH.h + * NOTE: Pins not used for interrupts can be omitted from callbacks array to + * reduce memory usage (if placed at end of gpioPinConfigs array). */ +GPIO_CallbackFxn gpioCallbackFunctions[] = { + NULL, /* Button 0 */ + NULL, /* Button 1 */ + NULL, /* CC2650DK_7ID_SPI_MASTER_READY */ + NULL, /* CC2650DK_7ID_SPI_SLAVE_READY */ +}; + +const GPIOCC26XX_Config GPIOCC26XX_config = { + .pinConfigs = (GPIO_PinConfig *)gpioPinConfigs, + .callbacks = (GPIO_CallbackFxn *)gpioCallbackFunctions, + .numberOfPinConfigs = CC2650DK_7ID_GPIOCOUNT, + .numberOfCallbacks = sizeof(gpioCallbackFunctions)/sizeof(GPIO_CallbackFxn), + .intPriority = (~0) +}; /* - * ============================ GPTimer begin ================================= + * =============================== GPTimer =============================== * Remove unused entries to reduce flash usage both in Board.c and Board.h */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(GPTimerCC26XX_config, ".const:GPTimerCC26XX_config") -#pragma DATA_SECTION(gptimerCC26xxHWAttrs, ".const:gptimerCC26xxHWAttrs") -#endif +#include + +GPTimerCC26XX_Object gptimerCC26XXObjects[CC2650DK_7ID_GPTIMERCOUNT]; -/* GPTimer hardware attributes, one per timer part (Timer 0A, 0B, 1A, 1B..) */ const GPTimerCC26XX_HWAttrs gptimerCC26xxHWAttrs[CC2650DK_7ID_GPTIMERPARTSCOUNT] = { { .baseAddr = GPT0_BASE, .intNum = INT_GPT0A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0A, }, { .baseAddr = GPT0_BASE, .intNum = INT_GPT0B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0B, }, @@ -449,194 +339,371 @@ const GPTimerCC26XX_HWAttrs gptimerCC26xxHWAttrs[CC2650DK_7ID_GPTIMERPARTSCOUNT] { .baseAddr = GPT3_BASE, .intNum = INT_GPT3B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3B, }, }; -/* GPTimer objects, one per full-width timer (A+B) (Timer 0, Timer 1..) */ -GPTimerCC26XX_Object gptimerCC26XXObjects[CC2650DK_7ID_GPTIMERCOUNT]; - -/* GPTimer configuration (used as GPTimer_Handle by driver and application) */ const GPTimerCC26XX_Config GPTimerCC26XX_config[CC2650DK_7ID_GPTIMERPARTSCOUNT] = { - { &gptimerCC26XXObjects[0], &gptimerCC26xxHWAttrs[0], GPT_A }, - { &gptimerCC26XXObjects[0], &gptimerCC26xxHWAttrs[1], GPT_B }, - { &gptimerCC26XXObjects[1], &gptimerCC26xxHWAttrs[2], GPT_A }, - { &gptimerCC26XXObjects[1], &gptimerCC26xxHWAttrs[3], GPT_B }, - { &gptimerCC26XXObjects[2], &gptimerCC26xxHWAttrs[4], GPT_A }, - { &gptimerCC26XXObjects[2], &gptimerCC26xxHWAttrs[5], GPT_B }, - { &gptimerCC26XXObjects[3], &gptimerCC26xxHWAttrs[6], GPT_A }, - { &gptimerCC26XXObjects[3], &gptimerCC26xxHWAttrs[7], GPT_B }, + { &gptimerCC26XXObjects[CC2650DK_7ID_GPTIMER0], &gptimerCC26xxHWAttrs[CC2650DK_7ID_GPTIMER0A], GPT_A }, + { &gptimerCC26XXObjects[CC2650DK_7ID_GPTIMER0], &gptimerCC26xxHWAttrs[CC2650DK_7ID_GPTIMER0B], GPT_B }, + { &gptimerCC26XXObjects[CC2650DK_7ID_GPTIMER1], &gptimerCC26xxHWAttrs[CC2650DK_7ID_GPTIMER1A], GPT_A }, + { &gptimerCC26XXObjects[CC2650DK_7ID_GPTIMER1], &gptimerCC26xxHWAttrs[CC2650DK_7ID_GPTIMER1B], GPT_B }, + { &gptimerCC26XXObjects[CC2650DK_7ID_GPTIMER2], &gptimerCC26xxHWAttrs[CC2650DK_7ID_GPTIMER2A], GPT_A }, + { &gptimerCC26XXObjects[CC2650DK_7ID_GPTIMER2], &gptimerCC26xxHWAttrs[CC2650DK_7ID_GPTIMER2B], GPT_B }, + { &gptimerCC26XXObjects[CC2650DK_7ID_GPTIMER3], &gptimerCC26xxHWAttrs[CC2650DK_7ID_GPTIMER3A], GPT_A }, + { &gptimerCC26XXObjects[CC2650DK_7ID_GPTIMER3], &gptimerCC26xxHWAttrs[CC2650DK_7ID_GPTIMER3B], GPT_B }, }; /* - * ============================ GPTimer end =================================== - */ + * =============================== I2C =============================== +*/ +#include +#include +I2CCC26XX_Object i2cCC26xxObjects[CC2650DK_7ID_I2CCOUNT]; - -/* - * ============================= PWM begin ==================================== - * Remove unused entries to reduce flash usage both in Board.c and Board.h - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(PWM_config, ".const:PWM_config") -#pragma DATA_SECTION(pwmtimerCC26xxHWAttrs, ".const:pwmtimerCC26xxHWAttrs") -#endif - -/* PWM configuration, one per PWM output. */ -PWMTimerCC26XX_HwAttrs pwmtimerCC26xxHWAttrs[CC2650DK_7ID_PWMCOUNT] = { - { .pwmPin = Board_PWMPIN0, .gpTimerUnit = Board_GPTIMER0A }, - { .pwmPin = Board_PWMPIN1, .gpTimerUnit = Board_GPTIMER0B }, - { .pwmPin = Board_PWMPIN2, .gpTimerUnit = Board_GPTIMER1A }, - { .pwmPin = Board_PWMPIN3, .gpTimerUnit = Board_GPTIMER1B }, - { .pwmPin = Board_PWMPIN4, .gpTimerUnit = Board_GPTIMER2A }, - { .pwmPin = Board_PWMPIN5, .gpTimerUnit = Board_GPTIMER2B }, - { .pwmPin = Board_PWMPIN6, .gpTimerUnit = Board_GPTIMER3A }, - { .pwmPin = Board_PWMPIN7, .gpTimerUnit = Board_GPTIMER3B }, -}; - -/* PWM object, one per PWM output */ -PWMTimerCC26XX_Object pwmtimerCC26xxObjects[CC2650DK_7ID_PWMCOUNT]; - -extern const PWM_FxnTable PWMTimerCC26XX_fxnTable; - -/* PWM configuration (used as PWM_Handle by driver and application) */ -const PWM_Config PWM_config[CC2650DK_7ID_PWMCOUNT + 1] = { - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[0], &pwmtimerCC26xxHWAttrs[0] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[1], &pwmtimerCC26xxHWAttrs[1] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[2], &pwmtimerCC26xxHWAttrs[2] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[3], &pwmtimerCC26xxHWAttrs[3] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[4], &pwmtimerCC26xxHWAttrs[4] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[5], &pwmtimerCC26xxHWAttrs[5] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[6], &pwmtimerCC26xxHWAttrs[6] }, - { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[7], &pwmtimerCC26xxHWAttrs[7] }, - { NULL, NULL, NULL } -}; - - -/* - * ============================= PWM end ====================================== - */ - -/* - * ========================== ADCBuf begin ========================================= - */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(ADCBuf_config, ".const:ADCBuf_config") -#pragma DATA_SECTION(adcBufCC26xxHWAttrs, ".const:adcBufCC26xxHWAttrs") -#pragma DATA_SECTION(ADCBufCC26XX_adcChannelLut, ".const:ADCBufCC26XX_adcChannelLut") -#endif - -/* Include drivers */ -#include -#include - -/* ADC objects */ -ADCBufCC26XX_Object adcBufCC26xxObjects[CC2650DK_7ID_ADCBufCOUNT]; - -/* - * This table converts a virtual adc channel into a dio and internal analogue input signal. - * This table is necessary for the functioning of the adcBuf driver. - * Comment out unused entries to save flash. - * Dio and internal signal pairs are hardwired. Do not remap them in the table. You may reorder entire entries though. - * The mapping of dio and internal signals is package dependent. - */ -const ADCBufCC26XX_AdcChannelLutEntry ADCBufCC26XX_adcChannelLut[] = { - {Board_ALS_OUT, ADC_COMPB_IN_AUXIO7}, - {PIN_UNASSIGNED, ADC_COMPB_IN_DCOUPL}, - {PIN_UNASSIGNED, ADC_COMPB_IN_VSS}, - {PIN_UNASSIGNED, ADC_COMPB_IN_VDDS} -}; - -const ADCBufCC26XX_HWAttrs adcBufCC26xxHWAttrs[CC2650DK_7ID_ADCBufCOUNT] = { +const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC2650DK_7ID_I2CCOUNT] = { { + .baseAddr = I2C0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_I2C0, + .intNum = INT_I2C_IRQ, .intPriority = ~0, .swiPriority = 0, - .adcChannelLut = ADCBufCC26XX_adcChannelLut, - .gpTimerUnit = Board_GPTIMER0A, - .gptDMAChannelMask = 1 << UDMA_CHAN_TIMER0_A, + .sdaPin = CC2650DK_7ID_I2C0_SDA0, + .sclPin = CC2650DK_7ID_I2C0_SCL0, } }; -const ADCBuf_Config ADCBuf_config[] = { - {&ADCBufCC26XX_fxnTable, &adcBufCC26xxObjects[0], &adcBufCC26xxHWAttrs[0]}, - {NULL, NULL, NULL}, +const I2C_Config I2C_config[CC2650DK_7ID_I2CCOUNT] = { + { + .fxnTablePtr = &I2CCC26XX_fxnTable, + .object = &i2cCC26xxObjects[CC2650DK_7ID_I2C0], + .hwAttrs = &i2cCC26xxHWAttrs[CC2650DK_7ID_I2C0] + }, }; -/* - * ========================== ADCBuf end ========================================= - */ - /* - * ========================== ADC begin ========================================= +const uint_least8_t I2C_count = CC2650DK_7ID_I2CCOUNT; + +/* + * =============================== NVS =============================== + */ +#include +#include +#include + +#define NVS_REGIONS_BASE 0x1A000 +#define SECTORSIZE 0x1000 +#define REGIONSIZE (SECTORSIZE * 4) + +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH + +/* + * Reserve flash sectors for NVS driver use by placing an uninitialized byte + * array at the desired flash address. */ -/* Place into subsections to allow the TI linker to remove items properly */ #if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(ADC_config, ".const:ADC_config") -#pragma DATA_SECTION(adcCC26xxHWAttrs, ".const:adcCC26xxHWAttrs") + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +#pragma LOCATION(flashBuf, NVS_REGIONS_BASE); +#pragma NOINIT(flashBuf); +static char flashBuf[REGIONSIZE]; + +#elif defined(__IAR_SYSTEMS_ICC__) + +/* + * Place uninitialized array at NVS_REGIONS_BASE + */ +static __no_init char flashBuf[REGIONSIZE] @ NVS_REGIONS_BASE; + +#elif defined(__GNUC__) + +/* + * Place the flash buffers in the .nvs section created in the gcc linker file. + * The .nvs section enforces alignment on a sector boundary but may + * be placed anywhere in flash memory. If desired the .nvs section can be set + * to a fixed address by changing the following in the gcc linker file: + * + * .nvs (FIXED_FLASH_ADDR) (NOLOAD) : AT (FIXED_FLASH_ADDR) { + * *(.nvs) + * } > REGION_TEXT + */ +__attribute__ ((section (".nvs"))) +static char flashBuf[REGIONSIZE]; + #endif -/* Include drivers */ -#include -#include +/* Allocate objects for NVS Internal Regions */ +NVSCC26XX_Object nvsCC26xxObjects[1]; -/* ADC objects */ -ADCCC26XX_Object adcCC26xxObjects[CC2650DK_7ID_ADCCOUNT]; - - -const ADCCC26XX_HWAttrs adcCC26xxHWAttrs[CC2650DK_7ID_ADCCOUNT] = { - { - .adcDIO = Board_DIO23_ANALOG, - .adcCompBInput = ADC_COMPB_IN_AUXIO7, - .refSource = ADCCC26XX_FIXED_REFERENCE, - .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, - .inputScalingEnabled = true, - .triggerSource = ADCCC26XX_TRIGGER_MANUAL - }, +/* Hardware attributes for NVS Internal Regions */ +const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { { - .adcDIO = PIN_UNASSIGNED, - .adcCompBInput = ADC_COMPB_IN_DCOUPL, - .refSource = ADCCC26XX_FIXED_REFERENCE, - .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, - .inputScalingEnabled = true, - .triggerSource = ADCCC26XX_TRIGGER_MANUAL + .regionBase = (void *)flashBuf, + .regionSize = REGIONSIZE, }, - { - .adcDIO = PIN_UNASSIGNED, - .adcCompBInput = ADC_COMPB_IN_VSS, - .refSource = ADCCC26XX_FIXED_REFERENCE, - .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, - .inputScalingEnabled = true, - .triggerSource = ADCCC26XX_TRIGGER_MANUAL - }, - { - .adcDIO = PIN_UNASSIGNED, - .adcCompBInput = ADC_COMPB_IN_VDDS, - .refSource = ADCCC26XX_FIXED_REFERENCE, - .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, - .inputScalingEnabled = true, - .triggerSource = ADCCC26XX_TRIGGER_MANUAL - } }; -const ADC_Config ADC_config[] = { - {&ADCCC26XX_fxnTable, &adcCC26xxObjects[0], &adcCC26xxHWAttrs[0]}, - {&ADCCC26XX_fxnTable, &adcCC26xxObjects[1], &adcCC26xxHWAttrs[1]}, - {&ADCCC26XX_fxnTable, &adcCC26xxObjects[2], &adcCC26xxHWAttrs[2]}, - {&ADCCC26XX_fxnTable, &adcCC26xxObjects[3], &adcCC26xxHWAttrs[3]}, - {NULL, NULL, NULL}, +#endif /* Board_EXCLUDE_NVS_INTERNAL_FLASH */ + +/* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ +const NVS_Config NVS_config[CC2650DK_7ID_NVSCOUNT] = { +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH + { + .fxnTablePtr = &NVSCC26XX_fxnTable, + .object = &nvsCC26xxObjects[0], + .hwAttrs = &nvsCC26xxHWAttrs[0], + }, +#endif +}; + +const uint_least8_t NVS_count = CC2650DK_7ID_NVSCOUNT; + +/* + * =============================== PIN =============================== + */ +#include +#include + +const PIN_Config BoardGpioInitTable[] = { + + CC2650DK_7ID_PIN_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC2650DK_7ID_PIN_LED2 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC2650DK_7ID_PIN_LED3 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC2650DK_7ID_PIN_LED4 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + CC2650DK_7ID_PIN_KEY_SELECT | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC2650DK_7ID_PIN_KEY_UP | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC2650DK_7ID_PIN_KEY_DOWN | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC2650DK_7ID_PIN_KEY_LEFT | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC2650DK_7ID_PIN_KEY_UP | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + CC2650DK_7ID_SDCARD_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ + CC2650DK_7ID_LCD_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ + CC2650DK_7ID_ACC_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ + CC2650DK_7ID_UART_RX | PIN_INPUT_EN | PIN_PULLDOWN, /* UART RX via debugger back channel */ + CC2650DK_7ID_UART_TX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* UART TX via debugger back channel */ + CC2650DK_7ID_SPI0_MOSI | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master out - slave in */ + CC2650DK_7ID_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master in - slave out */ + CC2650DK_7ID_SPI0_CLK | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI clock */ + + PIN_TERMINATE +}; + +const PINCC26XX_HWAttrs PINCC26XX_hwAttrs = { + .intPriority = ~0, + .swiPriority = 0 }; /* - * ========================== ADC end ========================================= + * =============================== Power =============================== */ +#include +#include + +const PowerCC26XX_Config PowerCC26XX_config = { + .policyInitFxn = NULL, + .policyFxn = &PowerCC26XX_standbyPolicy, + .calibrateFxn = &PowerCC26XX_calibrate, + .enablePolicy = true, + .calibrateRCOSC_LF = true, + .calibrateRCOSC_HF = true, +}; + +/* + * =============================== PWM =============================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +#include +#include + +PWMTimerCC26XX_Object pwmtimerCC26xxObjects[CC2650DK_7ID_PWMCOUNT]; + +const PWMTimerCC26XX_HwAttrs pwmtimerCC26xxHWAttrs[CC2650DK_7ID_PWMCOUNT] = { + { .pwmPin = CC2650DK_7ID_PWMPIN0, .gpTimerUnit = CC2650DK_7ID_GPTIMER0A }, + { .pwmPin = CC2650DK_7ID_PWMPIN1, .gpTimerUnit = CC2650DK_7ID_GPTIMER0B }, + { .pwmPin = CC2650DK_7ID_PWMPIN2, .gpTimerUnit = CC2650DK_7ID_GPTIMER1A }, + { .pwmPin = CC2650DK_7ID_PWMPIN3, .gpTimerUnit = CC2650DK_7ID_GPTIMER1B }, + { .pwmPin = CC2650DK_7ID_PWMPIN4, .gpTimerUnit = CC2650DK_7ID_GPTIMER2A }, + { .pwmPin = CC2650DK_7ID_PWMPIN5, .gpTimerUnit = CC2650DK_7ID_GPTIMER2B }, + { .pwmPin = CC2650DK_7ID_PWMPIN6, .gpTimerUnit = CC2650DK_7ID_GPTIMER3A }, + { .pwmPin = CC2650DK_7ID_PWMPIN7, .gpTimerUnit = CC2650DK_7ID_GPTIMER3B }, +}; + +const PWM_Config PWM_config[CC2650DK_7ID_PWMCOUNT] = { + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2650DK_7ID_PWM0], &pwmtimerCC26xxHWAttrs[CC2650DK_7ID_PWM0] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2650DK_7ID_PWM1], &pwmtimerCC26xxHWAttrs[CC2650DK_7ID_PWM1] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2650DK_7ID_PWM2], &pwmtimerCC26xxHWAttrs[CC2650DK_7ID_PWM2] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2650DK_7ID_PWM3], &pwmtimerCC26xxHWAttrs[CC2650DK_7ID_PWM3] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2650DK_7ID_PWM4], &pwmtimerCC26xxHWAttrs[CC2650DK_7ID_PWM4] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2650DK_7ID_PWM5], &pwmtimerCC26xxHWAttrs[CC2650DK_7ID_PWM5] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2650DK_7ID_PWM6], &pwmtimerCC26xxHWAttrs[CC2650DK_7ID_PWM6] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2650DK_7ID_PWM7], &pwmtimerCC26xxHWAttrs[CC2650DK_7ID_PWM7] }, +}; + +const uint_least8_t PWM_count = CC2650DK_7ID_PWMCOUNT; + +/* + * =============================== RF Driver =============================== + */ +#include + +const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { + .hwiPriority = ~0, /* Lowest HWI priority */ + .swiPriority = 0, /* Lowest SWI priority */ + .xoscHfAlwaysNeeded = true, /* Keep XOSC dependency while in stanby */ + .globalCallback = NULL, /* No board specific callback */ + .globalEventMask = 0 /* No events subscribed to */ +}; + +/* + * =============================== SD =============================== + */ +#include +#include + +SDSPI_Object sdspiObjects[CC2650DK_7ID_SDCOUNT]; + +const SDSPI_HWAttrs sdspiHWAttrs[CC2650DK_7ID_SDCOUNT] = { + { + .spiIndex = CC2650DK_7ID_SPI0, + .spiCsGpioIndex = CC2650DK_7ID_SDCARD_CS + } +}; + +const SD_Config SD_config[CC2650DK_7ID_SDCOUNT] = { + { + .fxnTablePtr = &SDSPI_fxnTable, + .object = &sdspiObjects[CC2650DK_7ID_SDSPI0], + .hwAttrs = &sdspiHWAttrs[CC2650DK_7ID_SDSPI0] + }, +}; + +const uint_least8_t SD_count = CC2650DK_7ID_SDCOUNT; + +/* + * =============================== SPI DMA =============================== + */ +#include +#include + +SPICC26XXDMA_Object spiCC26XXDMAObjects[CC2650DK_7ID_SPICOUNT]; + +/* + * NOTE: The SPI instances below can be used by the SD driver to communicate + * with a SD card via SPI. The 'defaultTxBufValue' fields below are set to 0xFF + * to satisfy the SDSPI driver requirement. + */ +const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC2650DK_7ID_SPICOUNT] = { + { + .baseAddr = SSI0_BASE, + .intNum = INT_SSI0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .powerMngrId = PowerCC26XX_PERIPH_SSI0, + .defaultTxBufValue = 0xFF, + .rxChannelBitMask = 1< +#include + +UARTCC26XX_Object uartCC26XXObjects[CC2650DK_7ID_UARTCOUNT]; + +uint8_t uartCC26XXRingBuffer[CC2650DK_7ID_UARTCOUNT][32]; + +const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC2650DK_7ID_UARTCOUNT] = { + { + .baseAddr = UART0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UART0, + .intNum = INT_UART0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .txPin = CC2650DK_7ID_UART_TX, + .rxPin = CC2650DK_7ID_UART_RX, + .ctsPin = PIN_UNASSIGNED, + .rtsPin = PIN_UNASSIGNED, + .ringBufPtr = uartCC26XXRingBuffer[CC2650DK_7ID_UART0], + .ringBufSize = sizeof(uartCC26XXRingBuffer[CC2650DK_7ID_UART0]), + .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, + .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, + .errorFxn = NULL + } +}; + +const UART_Config UART_config[CC2650DK_7ID_UARTCOUNT] = { + { + .fxnTablePtr = &UARTCC26XX_fxnTable, + .object = &uartCC26XXObjects[CC2650DK_7ID_UART0], + .hwAttrs = &uartCC26XXHWAttrs[CC2650DK_7ID_UART0] + }, +}; + +const uint_least8_t UART_count = CC2650DK_7ID_UARTCOUNT; + +/* + * =============================== UDMA =============================== + */ +#include + +UDMACC26XX_Object udmaObjects[CC2650DK_7ID_UDMACOUNT]; + +const UDMACC26XX_HWAttrs udmaHWAttrs[CC2650DK_7ID_UDMACOUNT] = { + { + .baseAddr = UDMA0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UDMA, + .intNum = INT_DMA_ERR, + .intPriority = ~0 + } +}; + +const UDMACC26XX_Config UDMACC26XX_config[CC2650DK_7ID_UDMACOUNT] = { + { + .object = &udmaObjects[CC2650DK_7ID_UDMA0], + .hwAttrs = &udmaHWAttrs[CC2650DK_7ID_UDMA0] + }, +}; + + /* * =============================== Watchdog =============================== */ -/* Place into subsections to allow the TI linker to remove items properly */ -#if defined(__TI_COMPILER_VERSION__) -#pragma DATA_SECTION(Watchdog_config, ".const:Watchdog_config") -#pragma DATA_SECTION(watchdogCC26XXHWAttrs, ".const:watchdogCC26XXHWAttrs") -#endif - #include #include @@ -644,25 +711,39 @@ WatchdogCC26XX_Object watchdogCC26XXObjects[CC2650DK_7ID_WATCHDOGCOUNT]; const WatchdogCC26XX_HWAttrs watchdogCC26XXHWAttrs[CC2650DK_7ID_WATCHDOGCOUNT] = { { - .baseAddr = WDT_BASE, - .intNum = INT_WDT_IRQ, + .baseAddr = WDT_BASE, .reloadValue = 1000 /* Reload value in milliseconds */ }, }; -const Watchdog_Config Watchdog_config[] = { +const Watchdog_Config Watchdog_config[CC2650DK_7ID_WATCHDOGCOUNT] = { { .fxnTablePtr = &WatchdogCC26XX_fxnTable, - .object = &watchdogCC26XXObjects[0], - .hwAttrs = &watchdogCC26XXHWAttrs[0] + .object = &watchdogCC26XXObjects[CC2650DK_7ID_WATCHDOG0], + .hwAttrs = &watchdogCC26XXHWAttrs[CC2650DK_7ID_WATCHDOG0] }, - {NULL, NULL, NULL}, }; +const uint_least8_t Watchdog_count = CC2650DK_7ID_WATCHDOGCOUNT; + /* - * ======== CC26XX_LAUNCHXL_initWatchdog ======== + * Board-specific initialization function to disable external flash. + * This function is defined in the file CC2650DK_7ID_fxns.c */ -void CC26XX_LAUNCHXL_initWatchdog(void) +extern void Board_initHook(void); + +/* + * ======== CC2650DK_7ID_initGeneral ======== + */ +void CC2650DK_7ID_initGeneral(void) { - Watchdog_init(); + Power_init(); + + if (PIN_init(BoardGpioInitTable) != PIN_SUCCESS) { + /* Error with PIN_init */ + while (1); + } + + /* Perform board-specific initialization */ + Board_initHook(); } diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h index 07b7573ae..3b2017de9 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, Texas Instruments Incorporated + * Copyright (c) 2015-2018, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,235 +32,166 @@ /** ============================================================================ * @file CC2650DK_7ID.h * - * @brief CC2650EM_7ID Board Specific header file. - * The project options should point to this file if this is the - * CC2650EM you are developing code for. + * @brief CC2650 LaunchPad Board Specific header file. * - * The CC2650 header file should be included in an application as follows: + * The CC2650DK_7ID header file should be included in an application as + * follows: * @code - * #include + * #include "CC2650DK_7ID.h" * @endcode * * ============================================================================ */ -#ifndef __CC2650EM_7ID_H__ -#define __CC2650EM_7ID_H__ +#ifndef __CC2650DK_7ID_BOARD_H__ +#define __CC2650DK_7ID_BOARD_H__ #ifdef __cplusplus extern "C" { #endif -/** ============================================================================ - * Symbol by generic Board.c to include the correct kit specific Board.c - * ==========================================================================*/ -#define CC2650EM_7ID -#define CC2650DK_7ID - - -/** ============================================================================ - * Includes - * ==========================================================================*/ +/* Includes */ #include -#include +#include -/** ============================================================================ - * Externs - * ==========================================================================*/ +/* Externs */ extern const PIN_Config BoardGpioInitTable[]; -/** ============================================================================ - * Defines - * ==========================================================================*/ +/* Defines */ +#define CC2650DK_7ID /* Mapping of pins to board signals using general board aliases - * + * */ -/* Leds */ -#define Board_LED_ON 1 /* LEDs on SmartRF06 EB are active high */ -#define Board_LED_OFF 0 -#define Board_DK_LED1 IOID_25 /* P2.11 */ -#define Board_DK_LED2 IOID_27 /* P2.13 */ -#define Board_DK_LED3 IOID_7 /* P1.2 */ -#define Board_DK_LED4 IOID_6 /* P1.4 */ -/* Button Board */ -#define Board_KEY_SELECT IOID_11 /* P1.14 */ -#define Board_KEY_UP IOID_19 /* P1.10 */ -#define Board_KEY_DOWN IOID_12 /* P1.12 */ -#define Board_KEY_LEFT IOID_15 /* P1.6 */ -#define Board_KEY_RIGHT IOID_18 /* P1.8 */ -/* LCD Board */ -#define Board_LCD_MODE IOID_4 /* P1.11 */ -#define Board_LCD_RST IOID_5 /* P1.13 */ -#define Board_LCD_CSN IOID_14 /* P1.17 */ -/* UART Board */ -#define Board_UART_RX IOID_2 /* P1.7 */ -#define Board_UART_TX IOID_3 /* P1.9 */ -#define Board_UART_CTS IOID_0 /* P1.3 */ -#define Board_UART_RTS IOID_21 /* P2.18 */ + +/* Analog Capable DIOs */ +#define CC2650DK_7ID_DIO23_ANALOG IOID_23 +#define CC2650DK_7ID_DIO24_ANALOG IOID_24 +#define CC2650DK_7ID_DIO25_ANALOG IOID_25 +#define CC2650DK_7ID_DIO26_ANALOG IOID_26 +#define CC2650DK_7ID_DIO27_ANALOG IOID_27 +#define CC2650DK_7ID_DIO28_ANALOG IOID_28 +#define CC2650DK_7ID_DIO29_ANALOG IOID_29 +#define CC2650DK_7ID_DIO30_ANALOG IOID_30 + +/* Digital IOs */ +#define CC2650DK_7ID_DIO0 IOID_0 +#define CC2650DK_7ID_DIO1_RFSW IOID_1 +#define CC2650DK_7ID_DIO12 IOID_12 +#define CC2650DK_7ID_DIO15 IOID_15 +#define CC2650DK_7ID_DIO16_TDO IOID_16 +#define CC2650DK_7ID_DIO17_TDI IOID_17 +#define CC2650DK_7ID_DIO21 IOID_21 +#define CC2650DK_7ID_DIO22 IOID_22 + +/* Discrete Inputs */ +#define CC2650DK_7ID_PIN_KEY_SELECT IOID_11 +#define CC2650DK_7ID_PIN_KEY_UP IOID_19 +#define CC2650DK_7ID_PIN_KEY_DOWN IOID_12 +#define CC2650DK_7ID_PIN_KEY_LEFT IOID_15 +#define CC2650DK_7ID_PIN_KEY_RIGHT IOID_18 + +/* GPIO */ +#define CC2650DK_7ID_GPIO_LED_ON 1 +#define CC2650DK_7ID_GPIO_LED_OFF 0 + +/* I2C */ +#define CC2650DK_7ID_I2C0_SCL0 PIN_UNASSIGNED +#define CC2650DK_7ID_I2C0_SDA0 PIN_UNASSIGNED + +/* LEDs */ +#define CC2650DK_7ID_PIN_LED_ON 1 +#define CC2650DK_7ID_PIN_LED_OFF 0 +#define CC2650DK_7ID_PIN_LED1 IOID_25 +#define CC2650DK_7ID_PIN_LED2 IOID_27 +#define CC2650DK_7ID_PIN_LED3 IOID_7 +#define CC2650DK_7ID_PIN_LED4 IOID_6 + +/* PWM Outputs */ +#define CC2650DK_7ID_PWMPIN0 CC2650DK_7ID_PIN_LED1 +#define CC2650DK_7ID_PWMPIN1 CC2650DK_7ID_PIN_LED2 +#define CC2650DK_7ID_PWMPIN2 PIN_UNASSIGNED +#define CC2650DK_7ID_PWMPIN3 PIN_UNASSIGNED +#define CC2650DK_7ID_PWMPIN4 PIN_UNASSIGNED +#define CC2650DK_7ID_PWMPIN5 PIN_UNASSIGNED +#define CC2650DK_7ID_PWMPIN6 PIN_UNASSIGNED +#define CC2650DK_7ID_PWMPIN7 PIN_UNASSIGNED + /* SPI Board */ -#define Board_SPI0_MISO IOID_8 /* P1.20 */ -#define Board_SPI0_MOSI IOID_9 /* P1.18 */ -#define Board_SPI0_CLK IOID_10 /* P1.16 */ -#define Board_SPI0_CSN PIN_UNASSIGNED /* P1.14, separate CSn for LCD, SDCARD, and ACC */ -#define Board_SPI1_MISO IOID_24 /* RF2.10 for testing only */ -#define Board_SPI1_MOSI IOID_23 /* RF2.5 for testing only */ -#define Board_SPI1_CLK IOID_30 /* RF2.12 for testing only */ -#define Board_SPI1_CSN PIN_UNASSIGNED /* RF2.6 for testing only */ -/* Ambient Light Sensor */ -#define Board_ALS_OUT IOID_23 /* P2.5 */ -#define Board_ALS_PWR IOID_26 /* P2.6 */ -/* Accelerometer */ -#define Board_ACC_PWR IOID_20 /* P2.8 */ -#define Board_ACC_CSN IOID_24 /* P2.10 */ +#define CC2650DK_7ID_SPI0_MISO IOID_8 +#define CC2650DK_7ID_SPI0_MOSI IOID_9 +#define CC2650DK_7ID_SPI0_CLK IOID_10 +#define CC2650DK_7ID_SPI0_CSN PIN_UNASSIGNED +#define CC2650DK_7ID_SPI1_MISO PIN_UNASSIGNED +#define CC2650DK_7ID_SPI1_MOSI PIN_UNASSIGNED +#define CC2650DK_7ID_SPI1_CLK PIN_UNASSIGNED +#define CC2650DK_7ID_SPI1_CSN PIN_UNASSIGNED + +/* UART Board */ +#define CC2650DK_7ID_UART_RX IOID_2 +#define CC2650DK_7ID_UART_TX IOID_3 +#define CC2650DK_7ID_UART_CTS IOID_0 +#define CC2650DK_7ID_UART_RTS IOID_21 + /* SD Card */ -#define Board_SDCARD_CSN IOID_30 /* P2.12 */ -/* Power Board */ -#define Board_3V3_EN IOID_13 /* P1.15 */ -/* PWM outputs */ -#define Board_PWMPIN0 Board_DK_LED1 -#define Board_PWMPIN1 Board_DK_LED2 -#define Board_PWMPIN2 PIN_UNASSIGNED -#define Board_PWMPIN3 PIN_UNASSIGNED -#define Board_PWMPIN4 PIN_UNASSIGNED -#define Board_PWMPIN5 PIN_UNASSIGNED -#define Board_PWMPIN6 PIN_UNASSIGNED -#define Board_PWMPIN7 PIN_UNASSIGNED -/* Analog capable DIO's */ -#define Board_DIO23_ANALOG IOID_23 -#define Board_DIO24_ANALOG IOID_24 -#define Board_DIO25_ANALOG IOID_25 -#define Board_DIO26_ANALOG IOID_26 -#define Board_DIO27_ANALOG IOID_27 -#define Board_DIO28_ANALOG IOID_28 -#define Board_DIO29_ANALOG IOID_29 -#define Board_DIO30_ANALOG IOID_30 +#define CC2650DK_7ID_SDCARD_CS IOID_30 -/** ============================================================================ - * Instance identifiers - * ==========================================================================*/ -/* Generic SPI instance identifiers */ -#define Board_SPI0 CC2650DK_7ID_SPI0 -#define Board_SPI1 CC2650DK_7ID_SPI1 -/* Generic UART instance identifiers */ -#define Board_UART CC2650DK_7ID_UART0 -/* Generic Crypto instance identifiers */ -#define Board_CRYPTO CC2650DK_7ID_CRYPTO0 -/* Generic GPTimer instance identifiers */ -#define Board_GPTIMER0A CC2650DK_7ID_GPTIMER0A -#define Board_GPTIMER0B CC2650DK_7ID_GPTIMER0B -#define Board_GPTIMER1A CC2650DK_7ID_GPTIMER1A -#define Board_GPTIMER1B CC2650DK_7ID_GPTIMER1B -#define Board_GPTIMER2A CC2650DK_7ID_GPTIMER2A -#define Board_GPTIMER2B CC2650DK_7ID_GPTIMER2B -#define Board_GPTIMER3A CC2650DK_7ID_GPTIMER3A -#define Board_GPTIMER3B CC2650DK_7ID_GPTIMER3B -/* Generic PWM instance identifiers */ -#define Board_PWM0 CC2650DK_7ID_PWM0 -#define Board_PWM1 CC2650DK_7ID_PWM1 -#define Board_PWM2 CC2650DK_7ID_PWM2 -#define Board_PWM3 CC2650DK_7ID_PWM3 -#define Board_PWM4 CC2650DK_7ID_PWM4 -#define Board_PWM5 CC2650DK_7ID_PWM5 -#define Board_PWM6 CC2650DK_7ID_PWM6 -#define Board_PWM7 CC2650DK_7ID_PWM7 +/* LCD Board */ +#define CC2650DK_7ID_LCD_MODE IOID_4 +#define CC2650DK_7ID_LCD_RST IOID_5 +#define CC2650DK_7ID_LCD_CS IOID_14 -/** ============================================================================ - * Number of peripherals and their names - * ==========================================================================*/ +/* Ambient Light Sensor */ +#define CC2650DK_7ID_ALS_OUT IOID_23 +#define CC2650DK_7ID_ALS_PWR IOID_26 + +/* Accelerometer */ +#define CC2650DK_7ID_ACC_PWR IOID_20 +#define CC2650DK_7ID_ACC_CS IOID_24 /*! - * @def CC2650DK_7ID_CryptoName - * @brief Enum of Crypto names on the CC2650 dev board + * @brief Initialize the general board specific settings + * + * This function initializes the general board specific settings. */ -typedef enum CC2650DK_7ID_CryptoName { - CC2650DK_7ID_CRYPTO0 = 0, - CC2650DK_7ID_CRYPTOCOUNT -} CC2650DK_7ID_CryptoName; +void CC2650DK_7ID_initGeneral(void); /*! - * @def CC2650DK_7ID_SPIName - * @brief Enum of SPI names on the CC2650 dev board + * @brief Turn off the external flash on LaunchPads + * */ -typedef enum CC2650DK_7ID_SPIName { - CC2650DK_7ID_SPI0 = 0, - CC2650DK_7ID_SPI1, - CC2650DK_7ID_SPICOUNT -} CC2650DK_7ID_SPIName; +void CC2650DK_7ID_shutDownExtFlash(void); /*! - * @def CC2650DK_7ID_UARTName - * @brief Enum of UARTs on the CC2650 dev board + * @brief Wake up the external flash present on the board files + * + * This function toggles the chip select for the amount of time needed + * to wake the chip up. */ -typedef enum CC2650DK_7ID_UARTName { - CC2650DK_7ID_UART0 = 0, - CC2650DK_7ID_UARTCOUNT -} CC2650DK_7ID_UARTName; - -/*! - * @def CC2650DK_7ID_UdmaName - * @brief Enum of DMA buffers - */ -typedef enum CC2650DK_7ID_UdmaName { - CC2650DK_7ID_UDMA0 = 0, - CC2650DK_7ID_UDMACOUNT -} CC2650DK_7ID_UdmaName; - -/*! - * @def CC2650DK_7ID_GPTimerName - * @brief Enum of GPTimer parts - */ -typedef enum CC2650DK_7ID_GPTimerName -{ - CC2650DK_7ID_GPTIMER0A = 0, - CC2650DK_7ID_GPTIMER0B, - CC2650DK_7ID_GPTIMER1A, - CC2650DK_7ID_GPTIMER1B, - CC2650DK_7ID_GPTIMER2A, - CC2650DK_7ID_GPTIMER2B, - CC2650DK_7ID_GPTIMER3A, - CC2650DK_7ID_GPTIMER3B, - CC2650DK_7ID_GPTIMERPARTSCOUNT -} CC2650DK_7ID_GPTimerName; - -/*! - * @def CC2650DK_7ID_GPTimers - * @brief Enum of GPTimers - */ -typedef enum CC2650DK_7ID_GPTimers -{ - CC2650DK_7ID_GPTIMER0 = 0, - CC2650DK_7ID_GPTIMER1, - CC2650DK_7ID_GPTIMER2, - CC2650DK_7ID_GPTIMER3, - CC2650DK_7ID_GPTIMERCOUNT -} CC2650DK_7ID_GPTimers; - -/*! - * @def CC2650DK_7ID_PWM - * @brief Enum of PWM outputs on the board - */ -typedef enum CC2650DK_7ID_PWM -{ - CC2650DK_7ID_PWM0 = 0, - CC2650DK_7ID_PWM1, - CC2650DK_7ID_PWM2, - CC2650DK_7ID_PWM3, - CC2650DK_7ID_PWM4, - CC2650DK_7ID_PWM5, - CC2650DK_7ID_PWM6, - CC2650DK_7ID_PWM7, - CC2650DK_7ID_PWMCOUNT -} CC2650DK_7ID_PWM; +void CC2650DK_7ID_wakeUpExtFlash(void); /*! * @def CC2650DK_7ID_ADCBufName - * @brief Enum of ADCBufs + * @brief Enum of ADCs */ typedef enum CC2650DK_7ID_ADCBufName { - CC2650DK_7ID_ADCBuf0 = 0, - CC2650DK_7ID_ADCBufCOUNT + CC2650DK_7ID_ADCBUF0 = 0, + + CC2650DK_7ID_ADCBUFCOUNT } CC2650DK_7ID_ADCBufName; +/*! + * @def CC2650DK_7ID_ADCBuf0SourceName + * @brief Enum of ADCBuf channels + */ +typedef enum CC2650DK_7ID_ADCBuf0ChannelName { + CC2650DK_7ID_ADCBUF0CHANNELADCALS = 0, + CC2650DK_7ID_ADCBUF0CHANNELVDDS, + CC2650DK_7ID_ADCBUF0CHANNELDCOUPL, + CC2650DK_7ID_ADCBUF0CHANNELVSS, + + CC2650DK_7ID_ADCBUF0CHANNELCOUNT +} CC2650DK_7ID_ADCBuf0ChannelName; + /*! * @def CC2650DK_7ID_ADCName * @brief Enum of ADCs @@ -270,12 +201,158 @@ typedef enum CC2650DK_7ID_ADCName { CC2650DK_7ID_ADCDCOUPL, CC2650DK_7ID_ADCVSS, CC2650DK_7ID_ADCVDDS, + CC2650DK_7ID_ADCCOUNT } CC2650DK_7ID_ADCName; +/*! + * @def CC2650DK_7ID_CryptoName + * @brief Enum of Crypto names + */ +typedef enum CC2650DK_7ID_CryptoName { + CC2650DK_7ID_CRYPTO0 = 0, + + CC2650DK_7ID_CRYPTOCOUNT +} CC2650DK_7ID_CryptoName; + +/*! + * @def CC2650DK_7ID_GPIOName + * @brief Enum of GPIO names + */ +typedef enum CC2650DK_7ID_GPIOName { + CC2650DK_7ID_GPIO_KEY_SELECT = 0, + CC2650DK_7ID_GPIO_KEY_UP, + CC2650DK_7ID_GPIO_KEY_DOWN, + CC2650DK_7ID_GPIO_KEY_LEFT, + CC2650DK_7ID_GPIO_KEY_RIGHT, + CC2650DK_7ID_SPI_MASTER_READY, + CC2650DK_7ID_SPI_SLAVE_READY, + CC2650DK_7ID_GPIO_LED1, + CC2650DK_7ID_GPIO_LED2, + CC2650DK_7ID_GPIO_LED3, + CC2650DK_7ID_GPIO_LED4, + CC2650DK_7ID_GPIO_SDCARD_CS, + CC2650DK_7ID_GPIO_ACC_CS, + CC2650DK_7ID_GPIO_LCD_CS, + CC2650DK_7ID_GPIO_LCD_POWER, + CC2650DK_7ID_GPIO_LCD_ENABLE, + + CC2650DK_7ID_GPIOCOUNT +} CC2650DK_7ID_GPIOName; + +/*! + * @def CC2650DK_7ID_GPTimerName + * @brief Enum of GPTimer parts + */ +typedef enum CC2650DK_7ID_GPTimerName { + CC2650DK_7ID_GPTIMER0A = 0, + CC2650DK_7ID_GPTIMER0B, + CC2650DK_7ID_GPTIMER1A, + CC2650DK_7ID_GPTIMER1B, + CC2650DK_7ID_GPTIMER2A, + CC2650DK_7ID_GPTIMER2B, + CC2650DK_7ID_GPTIMER3A, + CC2650DK_7ID_GPTIMER3B, + + CC2650DK_7ID_GPTIMERPARTSCOUNT +} CC2650DK_7ID_GPTimerName; + +/*! + * @def CC2650DK_7ID_GPTimers + * @brief Enum of GPTimers + */ +typedef enum CC2650DK_7ID_GPTimers { + CC2650DK_7ID_GPTIMER0 = 0, + CC2650DK_7ID_GPTIMER1, + CC2650DK_7ID_GPTIMER2, + CC2650DK_7ID_GPTIMER3, + + CC2650DK_7ID_GPTIMERCOUNT +} CC2650DK_7ID_GPTimers; + +/*! + * @def CC2650DK_7ID_I2CName + * @brief Enum of I2C names + */ +typedef enum CC2650DK_7ID_I2CName { + CC2650DK_7ID_I2C0 = 0, + + CC2650DK_7ID_I2CCOUNT +} CC2650DK_7ID_I2CName; + +/*! + * @def CC2650DK_7ID_NVSName + * @brief Enum of NVS names + */ +typedef enum CC2650DK_7ID_NVSName { +#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH + CC2650DK_7ID_NVSCC26XX0 = 0, +#endif + + CC2650DK_7ID_NVSCOUNT +} CC2650DK_7ID_NVSName; + +/*! + * @def CC2650DK_7ID_PWM + * @brief Enum of PWM outputs + */ +typedef enum CC2650DK_7ID_PWMName { + CC2650DK_7ID_PWM0 = 0, + CC2650DK_7ID_PWM1, + CC2650DK_7ID_PWM2, + CC2650DK_7ID_PWM3, + CC2650DK_7ID_PWM4, + CC2650DK_7ID_PWM5, + CC2650DK_7ID_PWM6, + CC2650DK_7ID_PWM7, + + CC2650DK_7ID_PWMCOUNT +} CC2650DK_7ID_PWMName; + +/*! + * @def CC2650DK_7ID_SDName + * @brief Enum of SD names + */ +typedef enum CC2650DK_7ID_SDName { + CC2650DK_7ID_SDSPI0 = 0, + + CC2650DK_7ID_SDCOUNT +} CC2650DK_7ID_SDName; + +/*! + * @def CC2650DK_7ID_SPIName + * @brief Enum of SPI names + */ +typedef enum CC2650DK_7ID_SPIName { + CC2650DK_7ID_SPI0 = 0, + CC2650DK_7ID_SPI1, + + CC2650DK_7ID_SPICOUNT +} CC2650DK_7ID_SPIName; + +/*! + * @def CC2650DK_7ID_UARTName + * @brief Enum of UARTs + */ +typedef enum CC2650DK_7ID_UARTName { + CC2650DK_7ID_UART0 = 0, + + CC2650DK_7ID_UARTCOUNT +} CC2650DK_7ID_UARTName; + +/*! + * @def CC2650DK_7ID_UDMAName + * @brief Enum of DMA buffers + */ +typedef enum CC2650DK_7ID_UDMAName { + CC2650DK_7ID_UDMA0 = 0, + + CC2650DK_7ID_UDMACOUNT +} CC2650DK_7ID_UDMAName; + /*! * @def CC2650DK_7ID_WatchdogName - * @brief Enum of Watchdogs on the CC2650DK_7ID dev board + * @brief Enum of Watchdogs */ typedef enum CC2650DK_7ID_WatchdogName { CC2650DK_7ID_WATCHDOG0 = 0, @@ -287,4 +364,4 @@ typedef enum CC2650DK_7ID_WatchdogName { } #endif -#endif /* __CC2650EM_H__ */ +#endif /* __CC2650DK_7ID_BOARD_H__ */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID_fxns.c new file mode 100644 index 000000000..b742aad53 --- /dev/null +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID_fxns.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +/* + * ======== CC2650DK_7ID_fxns.c ======== + * This file contains the board-specific initialization functions. + */ + +#include +#include +#include + +#include +#include + +#include + +#include "Board.h" + +/* + * ======== CC2650DK_7ID_wakeUpExtFlash ======== + */ +void CC2650DK_7ID_wakeUpExtFlash(void) +{ + /* No external flash on CC2650DK_7ID */ +} + +/* + * ======== CC2650DK_7ID_shutDownExtFlash ======== + */ +void CC2650DK_7ID_shutDownExtFlash(void) +{ + /* No external flash on CC2650DK_7ID */ +} + +/* + * ======== Board_initHook ======== + * Called by Board_init() to perform board-specific initialization. + */ +void Board_initHook() +{ + CC2650DK_7ID_shutDownExtFlash(); +} diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Makefile.cc26x0 b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Makefile.cc26x0 index ee23f7a3e..7882c9674 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Makefile.cc26x0 +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Makefile.cc26x0 @@ -5,7 +5,7 @@ SUBFAMILY = cc13x0-cc26x0 DEVICE_FAMILY = CC26X0 DEVICE_LINE = CC26XX -BOARD_SOURCEFILES += CC2650DK_7ID.c +BOARD_SOURCEFILES += CC2650DK_7ID.c CC2650DK_7ID_fxns.c SUPPORTS_PROP_MODE = 0 SUPPORTS_IEEE_MODE = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/leds-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/leds-arch.c index 2a1627005..e5eae9d0f 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/leds-arch.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/leds-arch.c @@ -29,62 +29,26 @@ */ /*---------------------------------------------------------------------------*/ /** - * \addtogroup srf06-common-peripherals + * \addtogroup simplelink-platform * @{ * * \file - * Driver for the SmartRF06EB LEDs when a CC13xx/CC26xx EM is mounted on it + * Driver for LaunchPad LEDs */ /*---------------------------------------------------------------------------*/ +/* Contiki API */ #include "contiki.h" #include "dev/leds.h" -#include "ti-lib.h" -/*---------------------------------------------------------------------------*/ -static unsigned char c; -static int inited = 0; -/*---------------------------------------------------------------------------*/ -void -leds_arch_init(void) -{ - if(inited) { - return; - } - inited = 1; - ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_LED_1); - ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_LED_2); - ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_LED_3); - ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_LED_4); +#include - ti_lib_gpio_clear_multi_dio(BOARD_LED_ALL); -} +#include /*---------------------------------------------------------------------------*/ -unsigned char -leds_arch_get(void) -{ - return c; -} -/*---------------------------------------------------------------------------*/ -void -leds_arch_set(unsigned char leds) -{ - c = leds; - - /* Clear everything */ - ti_lib_gpio_clear_multi_dio(BOARD_LED_ALL); - - if((leds & LEDS_RED) == LEDS_RED) { - ti_lib_gpio_set_dio(BOARD_IOID_LED_1); - } - if((leds & LEDS_YELLOW) == LEDS_YELLOW) { - ti_lib_gpio_set_dio(BOARD_IOID_LED_2); - } - if((leds & LEDS_GREEN) == LEDS_GREEN) { - ti_lib_gpio_set_dio(BOARD_IOID_LED_3); - } - if((leds & LEDS_ORANGE) == LEDS_ORANGE) { - ti_lib_gpio_set_dio(BOARD_IOID_LED_4); - } -} +const leds_t leds_arch_leds[] = { + { .pin = Board_PIN_LED0, .negative_logic = false }, + { .pin = Board_PIN_LED1, .negative_logic = false }, + { .pin = Board_PIN_LED2, .negative_logic = false }, + { .pin = Board_PIN_LED3, .negative_logic = false }, +}; /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/srf06-sensors.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/srf06-sensors.c index c333e62f5..7e4468cbd 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/srf06-sensors.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/srf06-sensors.c @@ -36,20 +36,12 @@ * Generic module controlling Simplelink sensors */ /*---------------------------------------------------------------------------*/ -#include -#include -/*---------------------------------------------------------------------------*/ -#include "common/button-sensor.h" +#include "contiki.h" +#include "lib/sensors.h" + +#include "board-peripherals.h" /*---------------------------------------------------------------------------*/ /* Exports a global symbol to be used by the sensor API */ -SENSORS( -#ifdef BUTTON_SENSOR_ARCH_BTN1 - &button_sensor, -#endif -#ifdef BUTTON_SENSOR_ARCH_BTN2 - &button_sensor2, -#endif - NULL -); +SENSORS(&als_sensor); /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/srf06.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/srf06.c deleted file mode 100644 index 119f77994..000000000 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/srf06.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/*---------------------------------------------------------------------------*/ -/** - * \addtogroup srf06-common-peripherals - * @{ - * - * \file - * Board-initialisation for the Srf06EB with a CC13xx/CC26xx EM. - */ -/*---------------------------------------------------------------------------*/ -#include "contiki.h" -#include "ti-lib.h" -#include "lpm.h" -#include "prcm.h" -#include "hw_sysctl.h" - -#include -#include -/*---------------------------------------------------------------------------*/ -static void -lpm_handler(uint8_t mode) -{ - /* Ambient light sensor (off, output low) */ - ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_ALS_PWR); - ti_lib_gpio_clear_dio(BOARD_IOID_ALS_PWR); - ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_ALS_OUT); - ti_lib_ioc_io_port_pull_set(BOARD_IOID_ALS_OUT, IOC_NO_IOPULL); -} -/*---------------------------------------------------------------------------*/ -static void -wakeup_handler(void) -{ - /* Turn on the PERIPH PD */ - ti_lib_prcm_power_domain_on(PRCM_DOMAIN_PERIPH); - while((ti_lib_prcm_power_domain_status(PRCM_DOMAIN_PERIPH) - != PRCM_DOMAIN_POWER_ON)); -} -/*---------------------------------------------------------------------------*/ -/* - * Declare a data structure to register with LPM. - * We don't care about what power mode we'll drop to, we don't care about - * getting notified before deep sleep. All we need is to be notified when we - * wake up so we can turn power domains back on - */ -LPM_MODULE(srf_module, NULL, lpm_handler, wakeup_handler, LPM_DOMAIN_NONE); -/*---------------------------------------------------------------------------*/ -static void -configure_unused_pins(void) -{ - /* Turn off 3.3-V domain (lcd/sdcard power, output low) */ - ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_3V3_EN); - ti_lib_gpio_clear_dio(BOARD_IOID_3V3_EN); - - /* Accelerometer (PWR output low, CSn output, high) */ - ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_ACC_PWR); - ti_lib_gpio_clear_dio(BOARD_IOID_ACC_PWR); -} -/*---------------------------------------------------------------------------*/ -void -board_init() -{ - uint8_t int_disabled = ti_lib_int_master_disable(); - - /* Turn on relevant PDs */ - wakeup_handler(); - - /* Enable GPIO peripheral */ - ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_GPIO); - - /* Apply settings and wait for them to take effect */ - ti_lib_prcm_load_set(); - while(!ti_lib_prcm_load_get()); - - lpm_register_module(&srf_module); - - configure_unused_pins(); - - /* Re-enable interrupt if initially enabled. */ - if(!int_disabled) { - ti_lib_int_master_enable(); - } -} -/*---------------------------------------------------------------------------*/ -/** @} */ diff --git a/os/dev/button-hal.h b/os/dev/button-hal.h index c1822ff8e..0be0c9d40 100644 --- a/os/dev/button-hal.h +++ b/os/dev/button-hal.h @@ -83,6 +83,7 @@ #include "dev/gpio-hal.h" #include "sys/clock.h" #include "sys/ctimer.h" +#include "sys/process.h" #include #include diff --git a/os/dev/gpio-hal.h b/os/dev/gpio-hal.h index 1ca1c141c..bbfa35dff 100644 --- a/os/dev/gpio-hal.h +++ b/os/dev/gpio-hal.h @@ -74,7 +74,7 @@ /** * \brief GPIO pin number representation */ -typedef uint8_t gpio_hal_pin_t; +typedef uint_fast8_t gpio_hal_pin_t; /** * \brief GPIO pin configuration @@ -82,7 +82,7 @@ typedef uint8_t gpio_hal_pin_t; * A logical representation of a pin's configuration. It is an OR combination * of GPIO_HAL_PIN_CFG_xyz macros. */ -typedef uint32_t gpio_hal_pin_cfg_t; +typedef uint_least32_t gpio_hal_pin_cfg_t; #ifdef GPIO_HAL_CONF_PIN_COUNT #define GPIO_HAL_PIN_COUNT GPIO_HAL_CONF_PIN_COUNT @@ -90,34 +90,73 @@ typedef uint32_t gpio_hal_pin_cfg_t; #define GPIO_HAL_PIN_COUNT 32 #endif -#if GPIO_HAL_PIN_COUNT > 32 -typedef uint64_t gpio_hal_pin_mask_t; -#else /** * \brief GPIO pin mask representation */ -typedef uint32_t gpio_hal_pin_mask_t; +#if GPIO_HAL_PIN_COUNT > 32 +typedef uint_least64_t gpio_hal_pin_mask_t; +#else +typedef uint_least32_t gpio_hal_pin_mask_t; #endif typedef void (*gpio_hal_callback_t)(gpio_hal_pin_mask_t pin_mask); /*---------------------------------------------------------------------------*/ -#define GPIO_HAL_PIN_CFG_PULL_NONE (0) -#define GPIO_HAL_PIN_CFG_PULL_UP (1 << 0) -#define GPIO_HAL_PIN_CFG_PULL_DOWN (1 << 1) +/* + * Configuration bits + * bit 8 -> bit 0 -> + * xxxxxxff eedccbba + * + * Input config: + * a - 1 bit - hystersis + * b - 2 bits - pulling + * + * Output config: + * c - 2 bits - output buffer + * d - 1 bit - slew control + * e - 2 bits - drive strength + * + * Interrupt config: + * f - 2 bits - interrupt mode + * + * Unused config: + * x: unused + */ -#define GPIO_HAL_PIN_CFG_PULL_MASK ( GPIO_HAL_PIN_CFG_PULL_UP \ - | GPIO_HAL_PIN_CFG_PULL_DOWN \ - ) +#define GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS (1 << 0) +#define GPIO_HAL_PIN_CFG_INPUT_NOPULL (0 << 1) +#define GPIO_HAL_PIN_CFG_INPUT_PULLUP (1 << 1) +#define GPIO_HAL_PIN_CFG_INPUT_PULLDOWN (2 << 1) -#define GPIO_HAL_PIN_CFG_INT_DISABLE (0) -#define GPIO_HAL_PIN_CFG_INT_FALLING (1 << 2) -#define GPIO_HAL_PIN_CFG_INT_RISING (1 << 3) -#define GPIO_HAL_PIN_CFG_INT_BOTH (1 << 4) +#define GPIO_HAL_PIN_BM_INPUT_HYSTERESIS (0b00000001 << 0) +#define GPIO_HAL_PIN_BM_INPUT_PULLING (0b00000110 << 0) +#define GPIO_HAL_PIN_BM_INPUT ( GPIO_HAL_PIN_BM_INPUT_HYSTERESIS \ + | GPIO_HAL_PIN_BM_INPUT_PULLING) -#define GPIO_HAL_PIN_CFG_INT_MASK ( GPIO_HAL_PIN_CFG_INT_RISING \ - | GPIO_HAL_PIN_CFG_INT_FALLING \ - | GPIO_HAL_PIN_CFG_INT_BOTH \ - ) +#define GPIO_HAL_PIN_CFG_OUTPUT_PUSHPULL (0 << 3) +#define GPIO_HAL_PIN_CFG_OUTPUT_OPENDRAIN (1 << 3) +#define GPIO_HAL_PIN_CFG_OUTPUT_OPENSOURCE (2 << 3) +#define GPIO_HAL_PIN_CFG_OUTPUT_SLEWCTRL (1 << 5) +#define GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MIN (0 << 6) +#define GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MED (1 << 6) +#define GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MAX (2 << 6) + +#define GPIO_HAL_PIN_BM_OUTPUT_BUF (0b00011000 << 0) +#define GPIO_HAL_PIN_BM_OUTPUT_SLEWCTRL (0b00100000 << 0) +#define GPIO_HAL_PIN_BM_OUTPUT_DRVSTR (0b11000000 << 0) +#define GPIO_HAL_PIN_BM_OUTPUT ( GPIO_HAL_PIN_BM_OUTPUT_BUF \ + | GPIO_HAL_PIN_BM_OUTPUT_SLEWCTRL \ + | GPIO_HAL_PIN_BM_OUTPUT_DRVSTR) + +#define GPIO_HAL_PIN_CFG_INT_DISABLE (0 << 8) +#define GPIO_HAL_PIN_CFG_INT_FALLING (1 << 8) +#define GPIO_HAL_PIN_CFG_INT_RISING (2 << 8) +#define GPIO_HAL_PIN_CFG_INT_BOTH (3 << 8) + +#define GPIO_HAL_PIN_BM_INT (0b00000011 << 8) + +#define GPIO_HAL_PIN_BM_ALL ( GPIO_HAL_PIN_BM_INPUT \ + | GPIO_HAL_PIN_BM_OUTPUT \ + | GPIO_HAL_PIN_BM_INT) /*---------------------------------------------------------------------------*/ /** * \brief Datatype for GPIO event handlers From 924e4f5ea5cd1ae980e6a01c637f45aa63e7f145 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Wed, 4 Jul 2018 19:35:13 +0200 Subject: [PATCH 257/485] Removed unused files. --- .../cc13xx-cc26xx/srf06/button-sensor.c | 491 ------------------ .../cc13xx-cc26xx/srf06/button-sensor.h | 60 --- 2 files changed, 551 deletions(-) delete mode 100644 arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor.c delete mode 100644 arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor.h diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor.c deleted file mode 100644 index 23f668355..000000000 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor.c +++ /dev/null @@ -1,491 +0,0 @@ -/* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/*---------------------------------------------------------------------------*/ -/** - * \addtogroup srf06-common-peripherals - * @{ - * - * \file - * Driver for the SmartRF06EB buttons when a CC13xx/CC26xxEM is mounted on it - */ -/*---------------------------------------------------------------------------*/ -#include "contiki.h" -#include "lib/sensors.h" -#include "srf06/button-sensor.h" -#include "gpio-interrupt.h" -#include "sys/timer.h" -#include "lpm.h" - -#include "ti-lib.h" - -#include -/*---------------------------------------------------------------------------*/ -#ifdef BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN -#define BUTTON_SENSOR_ENABLE_SHUTDOWN BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN -#else -#define BUTTON_SENSOR_ENABLE_SHUTDOWN 1 -#endif -/*---------------------------------------------------------------------------*/ -#define BUTTON_GPIO_CFG (IOC_CURRENT_2MA | IOC_STRENGTH_AUTO | \ - IOC_IOPULL_UP | IOC_SLEW_DISABLE | \ - IOC_HYST_DISABLE | IOC_BOTH_EDGES | \ - IOC_INT_ENABLE | IOC_IOMODE_NORMAL | \ - IOC_NO_WAKE_UP | IOC_INPUT_ENABLE) -/*---------------------------------------------------------------------------*/ -#define DEBOUNCE_DURATION (CLOCK_SECOND >> 5) - -struct btn_timer { - struct timer debounce; - clock_time_t start; - clock_time_t duration; -}; - -static struct btn_timer sel_timer, left_timer, right_timer, up_timer, - down_timer; -/*---------------------------------------------------------------------------*/ -/** - * \brief Handler for SmartRF button presses - */ -static void -button_press_handler(uint8_t ioid) -{ - if(ioid == BOARD_IOID_KEY_SELECT) { - if(!timer_expired(&sel_timer.debounce)) { - return; - } - - timer_set(&sel_timer.debounce, DEBOUNCE_DURATION); - - /* - * Start press duration counter on press (falling), notify on release - * (rising) - */ - if(ti_lib_gpio_read_dio(BOARD_IOID_KEY_SELECT) == 0) { - sel_timer.start = clock_time(); - sel_timer.duration = 0; - } else { - sel_timer.duration = clock_time() - sel_timer.start; - sensors_changed(&button_select_sensor); - } - } - - if(ioid == BOARD_IOID_KEY_LEFT) { - if(!timer_expired(&left_timer.debounce)) { - return; - } - - timer_set(&left_timer.debounce, DEBOUNCE_DURATION); - - /* - * Start press duration counter on press (falling), notify on release - * (rising) - */ - if(ti_lib_gpio_read_dio(BOARD_IOID_KEY_LEFT) == 0) { - left_timer.start = clock_time(); - left_timer.duration = 0; - } else { - left_timer.duration = clock_time() - left_timer.start; - sensors_changed(&button_left_sensor); - } - } - - if(ioid == BOARD_IOID_KEY_RIGHT) { - if(BUTTON_SENSOR_ENABLE_SHUTDOWN == 0) { - if(!timer_expired(&right_timer.debounce)) { - return; - } - - timer_set(&right_timer.debounce, DEBOUNCE_DURATION); - - /* - * Start press duration counter on press (falling), notify on release - * (rising) - */ - if(ti_lib_gpio_read_dio(BOARD_IOID_KEY_RIGHT) == 0) { - right_timer.start = clock_time(); - right_timer.duration = 0; - } else { - right_timer.duration = clock_time() - right_timer.start; - sensors_changed(&button_right_sensor); - } - } else { - lpm_shutdown(BOARD_IOID_KEY_RIGHT, IOC_IOPULL_UP, IOC_WAKE_ON_LOW); - } - } - - if(ioid == BOARD_IOID_KEY_UP) { - if(!timer_expired(&up_timer.debounce)) { - return; - } - - timer_set(&up_timer.debounce, DEBOUNCE_DURATION); - - /* - * Start press duration counter on press (falling), notify on release - * (rising) - */ - if(ti_lib_gpio_read_dio(BOARD_IOID_KEY_UP) == 0) { - up_timer.start = clock_time(); - up_timer.duration = 0; - } else { - up_timer.duration = clock_time() - up_timer.start; - sensors_changed(&button_up_sensor); - } - } - - if(ioid == BOARD_IOID_KEY_DOWN) { - if(!timer_expired(&down_timer.debounce)) { - return; - } - - timer_set(&down_timer.debounce, DEBOUNCE_DURATION); - - /* - * Start press duration counter on press (falling), notify on release - * (rising) - */ - if(ti_lib_gpio_read_dio(BOARD_IOID_KEY_DOWN) == 0) { - down_timer.start = clock_time(); - down_timer.duration = 0; - } else { - down_timer.duration = clock_time() - down_timer.start; - sensors_changed(&button_down_sensor); - } - } -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Configuration function for the button sensor for all buttons. - * - * \param type This function does nothing unless type == SENSORS_ACTIVE - * \param c 0: disable the button, non-zero: enable - * \param key: One of BOARD_KEY_LEFT, BOARD_KEY_RIGHT etc - */ -static void -config_buttons(int type, int c, uint32_t key) -{ - switch(type) { - case SENSORS_HW_INIT: - ti_lib_gpio_clear_event_dio(key); - ti_lib_rom_ioc_pin_type_gpio_input(key); - ti_lib_rom_ioc_port_configure_set(key, IOC_PORT_GPIO, BUTTON_GPIO_CFG); - gpio_interrupt_register_handler(key, button_press_handler); - break; - case SENSORS_ACTIVE: - if(c) { - ti_lib_gpio_clear_event_dio(key); - ti_lib_rom_ioc_pin_type_gpio_input(key); - ti_lib_rom_ioc_port_configure_set(key, IOC_PORT_GPIO, BUTTON_GPIO_CFG); - ti_lib_rom_ioc_int_enable(key); - } else { - ti_lib_rom_ioc_int_disable(key); - } - break; - default: - break; - } -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Configuration function for the select button. - * - * Parameters are passed onto config_buttons, which does the actual - * configuration - * Parameters are ignored. They have been included because the prototype is - * dictated by the core sensor api. The return value is also required by - * the API but otherwise ignored. - * - * \param type passed to config_buttons as-is - * \param value passed to config_buttons as-is - * - * \return ignored - */ -static int -config_select(int type, int value) -{ - config_buttons(type, value, BOARD_IOID_KEY_SELECT); - - return 1; -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Configuration function for the left button. - * - * Parameters are passed onto config_buttons, which does the actual - * configuration - * Parameters are ignored. They have been included because the prototype is - * dictated by the core sensor api. The return value is also required by - * the API but otherwise ignored. - * - * \param type passed to config_buttons as-is - * \param value passed to config_buttons as-is - * - * \return ignored - */ -static int -config_left(int type, int value) -{ - config_buttons(type, value, BOARD_IOID_KEY_LEFT); - - return 1; -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Configuration function for the right button. - * - * Parameters are passed onto config_buttons, which does the actual - * configuration - * Parameters are ignored. They have been included because the prototype is - * dictated by the core sensor api. The return value is also required by - * the API but otherwise ignored. - * - * \param type passed to config_buttons as-is - * \param value passed to config_buttons as-is - * - * \return ignored - */ -static int -config_right(int type, int value) -{ - config_buttons(type, value, BOARD_IOID_KEY_RIGHT); - - return 1; -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Configuration function for the up button. - * - * Parameters are passed onto config_buttons, which does the actual - * configuration - * Parameters are ignored. They have been included because the prototype is - * dictated by the core sensor api. The return value is also required by - * the API but otherwise ignored. - * - * \param type passed to config_buttons as-is - * \param value passed to config_buttons as-is - * - * \return ignored - */ -static int -config_up(int type, int value) -{ - config_buttons(type, value, BOARD_IOID_KEY_UP); - - return 1; -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Configuration function for the down button. - * - * Parameters are passed onto config_buttons, which does the actual - * configuration - * Parameters are ignored. They have been included because the prototype is - * dictated by the core sensor api. The return value is also required by - * the API but otherwise ignored. - * - * \param type passed to config_buttons as-is - * \param value passed to config_buttons as-is - * - * \return ignored - */ -static int -config_down(int type, int value) -{ - config_buttons(type, value, BOARD_IOID_KEY_DOWN); - - return 1; -} -/*---------------------------------------------------------------------------*/ -static int -value_select(int type) -{ - if(type == BUTTON_SENSOR_VALUE_STATE) { - return ti_lib_gpio_read_dio(BOARD_IOID_KEY_SELECT) == 0 ? - BUTTON_SENSOR_VALUE_PRESSED : BUTTON_SENSOR_VALUE_RELEASED; - } else if(type == BUTTON_SENSOR_VALUE_DURATION) { - return (int)sel_timer.duration; - } - return 0; -} -/*---------------------------------------------------------------------------*/ -static int -value_left(int type) -{ - if(type == BUTTON_SENSOR_VALUE_STATE) { - return ti_lib_gpio_read_dio(BOARD_IOID_KEY_LEFT) == 0 ? - BUTTON_SENSOR_VALUE_PRESSED : BUTTON_SENSOR_VALUE_RELEASED; - } else if(type == BUTTON_SENSOR_VALUE_DURATION) { - return (int)left_timer.duration; - } - return 0; -} -/*---------------------------------------------------------------------------*/ -static int -value_right(int type) -{ - if(type == BUTTON_SENSOR_VALUE_STATE) { - return ti_lib_gpio_read_dio(BOARD_IOID_KEY_RIGHT) == 0 ? - BUTTON_SENSOR_VALUE_PRESSED : BUTTON_SENSOR_VALUE_RELEASED; - } else if(type == BUTTON_SENSOR_VALUE_DURATION) { - return (int)right_timer.duration; - } - return 0; -} -/*---------------------------------------------------------------------------*/ -static int -value_up(int type) -{ - if(type == BUTTON_SENSOR_VALUE_STATE) { - return ti_lib_gpio_read_dio(BOARD_IOID_KEY_UP) == 0 ? - BUTTON_SENSOR_VALUE_PRESSED : BUTTON_SENSOR_VALUE_RELEASED; - } else if(type == BUTTON_SENSOR_VALUE_DURATION) { - return (int)up_timer.duration; - } - return 0; -} -/*---------------------------------------------------------------------------*/ -static int -value_down(int type) -{ - if(type == BUTTON_SENSOR_VALUE_STATE) { - return ti_lib_gpio_read_dio(BOARD_IOID_KEY_DOWN) == 0 ? - BUTTON_SENSOR_VALUE_PRESSED : BUTTON_SENSOR_VALUE_RELEASED; - } else if(type == BUTTON_SENSOR_VALUE_DURATION) { - return (int)down_timer.duration; - } - return 0; -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Status function for all buttons - * \param type SENSORS_ACTIVE or SENSORS_READY - * \param key_io_id BOARD_IOID_KEY_LEFT, BOARD_IOID_KEY_RIGHT etc - * \return 1 if the button's port interrupt is enabled (edge detect) - * - * This function will only be called by status_left, status_right and the - * called will pass the correct key_io_id - */ -static int -status(int type, uint32_t key_io_id) -{ - switch(type) { - case SENSORS_ACTIVE: - case SENSORS_READY: - if(ti_lib_ioc_port_configure_get(key_io_id) & IOC_INT_ENABLE) { - return 1; - } - break; - default: - break; - } - return 0; -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Status function for the select button. - * \param type SENSORS_ACTIVE or SENSORS_READY - * \return 1 if the button's port interrupt is enabled (edge detect) - * - * This function will call status. It will pass type verbatim and it will also - * pass the correct key_io_id - */ -static int -status_select(int type) -{ - return status(type, BOARD_IOID_KEY_SELECT); -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Status function for the left button. - * \param type SENSORS_ACTIVE or SENSORS_READY - * \return 1 if the button's port interrupt is enabled (edge detect) - * - * This function will call status. It will pass type verbatim and it will also - * pass the correct key_io_id - */ -static int -status_left(int type) -{ - return status(type, BOARD_IOID_KEY_LEFT); -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Status function for the right button. - * \param type SENSORS_ACTIVE or SENSORS_READY - * \return 1 if the button's port interrupt is enabled (edge detect) - * - * This function will call status. It will pass type verbatim and it will also - * pass the correct key_io_id - */ -static int -status_right(int type) -{ - return status(type, BOARD_IOID_KEY_RIGHT); -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Status function for the up button. - * \param type SENSORS_ACTIVE or SENSORS_READY - * \return 1 if the button's port interrupt is enabled (edge detect) - * - * This function will call status. It will pass type verbatim and it will also - * pass the correct key_io_id - */ -static int -status_up(int type) -{ - return status(type, BOARD_IOID_KEY_UP); -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Status function for the down button. - * \param type SENSORS_ACTIVE or SENSORS_READY - * \return 1 if the button's port interrupt is enabled (edge detect) - * - * This function will call status. It will pass type verbatim and it will also - * pass the correct key_io_id - */ -static int -status_down(int type) -{ - return status(type, BOARD_IOID_KEY_DOWN); -} -/*---------------------------------------------------------------------------*/ -SENSORS_SENSOR(button_select_sensor, BUTTON_SENSOR, value_select, - config_select, status_select); -SENSORS_SENSOR(button_left_sensor, BUTTON_SENSOR, value_left, config_left, - status_left); -SENSORS_SENSOR(button_right_sensor, BUTTON_SENSOR, value_right, config_right, - status_right); -SENSORS_SENSOR(button_up_sensor, BUTTON_SENSOR, value_up, config_up, status_up); -SENSORS_SENSOR(button_down_sensor, BUTTON_SENSOR, value_down, config_down, - status_down); -/*---------------------------------------------------------------------------*/ -/** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor.h deleted file mode 100644 index 1c810c96d..000000000 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/*---------------------------------------------------------------------------*/ -/** - * \addtogroup srf06-common-peripherals - * @{ - * - * \file - * Header file for the SmartRF06EB + CC13xx/CC26xxEM Button Driver - */ -/*---------------------------------------------------------------------------*/ -#ifndef BUTTON_SENSOR_H_ -#define BUTTON_SENSOR_H_ -/*---------------------------------------------------------------------------*/ -#include "lib/sensors.h" -/*---------------------------------------------------------------------------*/ -#define BUTTON_SENSOR "Button" -/*---------------------------------------------------------------------------*/ -#define BUTTON_SENSOR_VALUE_STATE 0 -#define BUTTON_SENSOR_VALUE_DURATION 1 - -#define BUTTON_SENSOR_VALUE_RELEASED 0 -#define BUTTON_SENSOR_VALUE_PRESSED 1 -/*---------------------------------------------------------------------------*/ -extern const struct sensors_sensor button_select_sensor; -extern const struct sensors_sensor button_left_sensor; -extern const struct sensors_sensor button_right_sensor; -extern const struct sensors_sensor button_up_sensor; -extern const struct sensors_sensor button_down_sensor; -/*---------------------------------------------------------------------------*/ -#endif /* BUTTON_SENSOR_H_ */ -/*---------------------------------------------------------------------------*/ -/** @} */ From 326974031efaa2f5c8b2172086caafa4fcfb21e3 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Fri, 6 Jul 2018 18:23:07 +0200 Subject: [PATCH 258/485] Added BLE settings --- .../rf-settings/cc13x0/ble-settings.c | 220 +++++++++++++ .../rf-settings/cc13x0/ble-settings.h | 59 ++++ .../rf-settings/cc13x2/ble-settings.c | 308 ++++++++++++++++++ .../rf-settings/cc13x2/ble-settings.h | 44 +++ .../rf-settings/cc26x0/ble-settings.c | 256 +++++++++++++++ .../rf-settings/cc26x0/ble-settings.h | 41 +++ .../rf-settings/cc26x2/ble-settings.c | 308 ++++++++++++++++++ .../rf-settings/cc26x2/ble-settings.h | 44 +++ 8 files changed, 1280 insertions(+) create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.c create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.h create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.c create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.h create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.c create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.h create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.c create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.h diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.c new file mode 100644 index 000000000..c8a350ca8 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.c @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +// Parameter summary +// Adv. Address: 010203040506 +// Adv. Data: 255 +// BLE Channel: 17 +// Frequency: 2440 MHz +// PDU Payload length: 30 +// TX Power: 9 dBm (requires define CCFG_FORCE_VDDR_HH = 1 in ccfg.c, see CC13xx/CC26xx Technical Reference Manual) +// Whitening: true +/*---------------------------------------------------------------------------*/ +#include "sys/cc.h" +/*---------------------------------------------------------------------------*/ +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_ble_cmd.h) +#include DeviceFamily_constructPath(rf_patches/rf_patch_cpe_ble.h) +#include DeviceFamily_constructPath(rf_patches/rf_patch_rfe_ble.h) + +#include +/*---------------------------------------------------------------------------*/ +#include "ble-settings.h" +/*---------------------------------------------------------------------------*/ +// TI-RTOS RF Mode Object +RF_Mode RF_ble = +{ + .rfMode = RF_MODE_BLE, + .cpePatchFxn = &rf_patch_cpe_ble, + .mcePatchFxn = 0, + .rfePatchFxn = &rf_patch_rfe_ble, +}; +/*---------------------------------------------------------------------------*/ +// TX Power table +// The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: +// RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) +// See the Technical Reference Manual for further details about the "txPower" Command field. +// The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. +RF_TxPowerTable_Entry txPowerTable[TX_POWER_TABLE_SIZE] = +{ + { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 3, 1, 6) }, + { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 1, 6) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 3, 1, 10) }, + { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 3, 1, 12) }, + { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(26, 3, 1, 14) }, + { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(35, 3, 1, 18) }, + { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(47, 3, 1, 22) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(29, 0, 1, 45) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(33, 0, 1, 49) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(38, 0, 1, 55) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(44, 0, 1, 63) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(52, 0, 1, 59) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(60, 0, 1, 47) }, + { 6, RF_TxPowerTable_DEFAULT_PA_ENTRY(38, 0, 1, 49) }, // This setting requires CCFG_FORCE_VDDR_HH = 1. + { 7, RF_TxPowerTable_DEFAULT_PA_ENTRY(46, 0, 1, 59) }, // This setting requires CCFG_FORCE_VDDR_HH = 1. + { 8, RF_TxPowerTable_DEFAULT_PA_ENTRY(55, 0, 1, 51) }, // This setting requires CCFG_FORCE_VDDR_HH = 1. + { 9, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 30) }, // This setting requires CCFG_FORCE_VDDR_HH = 1. + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +// Overrides for CMD_RADIO_SETUP +uint32_t rf_ble_overrides[] CC_ALIGN(4) = +{ + // override_use_patch_ble_1mbps.xml + MCE_RFE_OVERRIDE(0,0,0,1,0,0), // PHY: Use MCE ROM, RFE RAM patch + // override_synth_ble_1mbps.xml + HW_REG_OVERRIDE(0x4038,0x0034), // Synth: Set recommended RTRIM to 4 + (uint32_t)0x000784A3, // Synth: Set Fref to 3.43 MHz + HW_REG_OVERRIDE(0x4020,0x7F00), // Synth: Configure fine calibration setting + HW_REG_OVERRIDE(0x4064,0x0040), // Synth: Configure fine calibration setting + (uint32_t)0xB1070503, // Synth: Configure fine calibration setting + (uint32_t)0x05330523, // Synth: Configure fine calibration setting + (uint32_t)0xA47E0583, // Synth: Set loop bandwidth after lock to 80 kHz + (uint32_t)0xEAE00603, // Synth: Set loop bandwidth after lock to 80 kHz + (uint32_t)0x00010623, // Synth: Set loop bandwidth after lock to 80 kHz + HW32_ARRAY_OVERRIDE(0x405C,1), // Synth: Configure PLL bias + (uint32_t)0x18000000, // Synth: Configure PLL bias + ADI_REG_OVERRIDE(1,4,0x9F), // Synth: Configure VCO LDO (in ADI1, set VCOLDOCFG=0x9F to use voltage input reference) + ADI_HALFREG_OVERRIDE(1,7,0x4,0x4), // Synth: Configure synth LDO (in ADI1, set SLDOCTL0.COMP_CAP=1) + // override_phy_ble_1mbps.xml + (uint32_t)0x013800C3, // Tx: Configure symbol shape for BLE frequency deviation requirements + HW_REG_OVERRIDE(0x6088, 0x0045), // Rx: Configure AGC reference level + HW_REG_OVERRIDE(0x6084, 0x05FD), // Rx: Configure AGC gain level + (uint32_t)0x00038883, // Rx: Configure LNA bias current trim offset + // override_frontend_xd.xml + (uint32_t)0x00F388A3, // Rx: Set RSSI offset to adjust reported RSSI by +13 dB + // TX power override + ADI_REG_OVERRIDE(0,12,0xF8), // Tx: Set PA trim to max (in ADI0, set PACTL0=0xF8) + (uint32_t)0xFFFFFFFF, +}; +/*---------------------------------------------------------------------------*/ +// CMD_RADIO_SETUP +// Radio Setup Command for Pre-Defined Schemes +rfc_CMD_RADIO_SETUP_t rf_ble_cmd_radiosetup = +{ + .commandNo = 0x0802, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .mode = 0x00, + .loDivider = 0x00, + .config.frontEndMode = 0x0, + .config.biasMode = 0x1, + .config.analogCfgMode = 0x0, + .config.bNoFsPowerUp = 0x0, + .txPower = 0x3D3F, + .pRegOverride = rf_ble_overrides, +}; +/*---------------------------------------------------------------------------*/ +// CMD_FS +// Frequency Synthesizer Programming Command +rfc_CMD_FS_t rf_ble_cmd_fs = +{ + .commandNo = 0x0803, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .frequency = 0x0988, + .fractFreq = 0x0000, + .synthConf.bTxMode = 0x0, + .synthConf.refFreq = 0x0, + .__dummy0 = 0x00, + .__dummy1 = 0x00, + .__dummy2 = 0x00, + .__dummy3 = 0x0000, +}; +/*---------------------------------------------------------------------------*/ +// Structure for CMD_BLE_ADV_NC.pParams +rfc_bleAdvPar_t rf_ble_adv_par = +{ + .pRxQ = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx + .rxConfig.bAutoFlushIgnored = 0x0, + .rxConfig.bAutoFlushCrcErr = 0x0, + .rxConfig.bAutoFlushEmpty = 0x0, + .rxConfig.bIncludeLenByte = 0x0, + .rxConfig.bIncludeCrc = 0x0, + .rxConfig.bAppendRssi = 0x0, + .rxConfig.bAppendStatus = 0x0, + .rxConfig.bAppendTimestamp = 0x0, + .advConfig.advFilterPolicy = 0x0, + .advConfig.deviceAddrType = 0x0, + .advConfig.peerAddrType = 0x0, + .advConfig.bStrictLenFilter = 0x0, + .advConfig.rpaMode = 0x0, + .advLen = 0x18, + .scanRspLen = 0x00, + .pAdvData = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .pScanRspData = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .pDeviceAddress = 0, // INSERT APPLICABLE POINTER: (uint16_t*)&xxx + .pWhiteList = 0, // INSERT APPLICABLE POINTER: (uint32_t*)&xxx + .__dummy0 = 0x0000, + .__dummy1 = 0x00, + .endTrigger.triggerType = 0x1, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, +}; +/*---------------------------------------------------------------------------*/ +// CMD_BLE_ADV_NC +// BLE Non-Connectable Advertiser Command +rfc_CMD_BLE_ADV_NC_t rf_ble_cmd_ble_adv_nc = +{ + .commandNo = 0x1805, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .channel = 0x8C, + .whitening.init = 0x51, + .whitening.bOverride = 0x1, + .pParams = &rf_ble_adv_par, + .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx +}; +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.h new file mode 100644 index 000000000..4edba3386 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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 BLE_SETTINGS_H_ +#define BLE_SETTINGS_H_ +/*---------------------------------------------------------------------------*/ +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_ble_cmd.h) + +#include +/*---------------------------------------------------------------------------*/ +// TX Power table size definition +#define RF_BLE_TX_POWER_TABLE_SIZE 17 + +// TX Power Table Object +extern RF_TxPowerTable_Entry rf_ble_tx_power_table[RF_BLE_TX_POWER_TABLE_SIZE+1]; +/*---------------------------------------------------------------------------*/ +// TI-RTOS RF Mode Object +extern RF_Mode rf_ble_mode; +/*---------------------------------------------------------------------------*/ +// RF Core API commands +extern rfc_CMD_RADIO_SETUP_t rf_ble_cmd_radiosetup; +extern rfc_CMD_FS_t rf_ble_cmd_fs; +extern rfc_CMD_BLE_ADV_NC_t rf_ble_cmd_ble_adv_nc; +/*---------------------------------------------------------------------------*/ +// RF Core API Overrides +extern uint32_t rf_ble_overrides[]; +/*---------------------------------------------------------------------------*/ +#endif /* BLE_SETTINGS_H_ */ +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.c new file mode 100644 index 000000000..0a41cefd5 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.c @@ -0,0 +1,308 @@ +//********************************************************************************* +// Generated by SmartRF Studio version 2.10.0 (build#106) +// Compatible with SimpleLink SDK version: CC13x2 SDK 2.20.xx.xx +// Device: CC1352R Rev. 1.1 +// +//********************************************************************************* + + +//********************************************************************************* +// Parameter summary +// Adv. Address: 010203040506 +// Adv. Data: dummy +// BLE Channel: 17 +// Extended Header: 09 09 010203040506 babe +// Frequency: 2440 MHz +// PDU Payload length:: 30 +// TX Power: 5 dBm (requires define CCFG_FORCE_VDDR_HH = 0 in ccfg.c, see CC13xx/CC26xx Technical Reference Manual) +// Whitening: true + +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_ble_cmd.h) +#include +#include DeviceFamily_constructPath(rf_patches/rf_patch_cpe_bt5.h) +#include DeviceFamily_constructPath(rf_patches/rf_patch_rfe_bt5.h) +#include DeviceFamily_constructPath(rf_patches/rf_patch_mce_bt5.h) +#include "ble-settings.h" + + +// TI-RTOS RF Mode Object +RF_Mode RF_prop = +{ + .rfMode = RF_MODE_AUTO, + .cpePatchFxn = &rf_patch_cpe_bt5, + .mcePatchFxn = &rf_patch_mce_bt5, + .rfePatchFxn = &rf_patch_rfe_bt5, +}; + +// TX Power table +// The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: +// RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) +// See the Technical Reference Manual for further details about the "txPower" Command field. +// The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. +RF_TxPowerTable_Entry txPowerTable[TX_POWER_TABLE_SIZE] = +{ + {-21, RF_TxPowerTable_DEFAULT_PA_ENTRY(7, 3, 0, 3) }, + {-18, RF_TxPowerTable_DEFAULT_PA_ENTRY(9, 3, 0, 3) }, + {-15, RF_TxPowerTable_DEFAULT_PA_ENTRY(8, 2, 0, 6) }, + {-12, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 2, 0, 8) }, + {-10, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 11) }, + {-9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 2, 0, 5) }, + {-6, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 16) }, + {-5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 17) }, + {-3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 1, 0, 20) }, + {0, RF_TxPowerTable_DEFAULT_PA_ENTRY(25, 1, 0, 26) }, + {1, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 1, 0, 28) }, + {2, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 0, 0, 34) }, + {3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 0, 0, 42) }, + {4, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 0, 0, 54) }, + {5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; + + +// Overrides for CMD_BLE5_RADIO_SETUP +uint32_t pOverridesCommon[] = +{ + // override_ble5_setup_override_common.xml + // Synth: Use 48 MHz crystal, enable extra PLL filtering + (uint32_t)0x02400403, + // Synth: Configure extra PLL filtering + (uint32_t)0x001C8473, + // Synth: Configure synth hardware + (uint32_t)0x00088433, + // Synth: Set minimum RTRIM to 3 + (uint32_t)0x00038793, + // Synth: Configure faster calibration + HW32_ARRAY_OVERRIDE(0x4004,1), + // Synth: Configure faster calibration + (uint32_t)0x1C0C0618, + // Synth: Configure faster calibration + (uint32_t)0xC00401A1, + // Synth: Configure faster calibration + (uint32_t)0x00010101, + // Synth: Configure faster calibration + (uint32_t)0xC0040141, + // Synth: Configure faster calibration + (uint32_t)0x00214AD3, + // Synth: Decrease synth programming time-out (0x0298 RAT ticks = 166 us) + (uint32_t)0x02980243, + // DC/DC regulator: In Tx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). + (uint32_t)0xFCFC08C3, + // Rx: Set LNA bias current offset to adjust +3 (default: 0) + (uint32_t)0x00038883, + // Rx: Set RSSI offset to adjust reported RSSI by -2 dB (default: 0) + (uint32_t)0x000288A3, + // Bluetooth 5: Compensate for reduced pilot tone length + (uint32_t)0x01080263, + // Bluetooth 5: Compensate for reduced pilot tone length + (uint32_t)0x08E90AA3, + // Bluetooth 5: Compensate for reduced pilot tone length + (uint32_t)0x00068BA3, + // Bluetooth 5: Set correct total clock accuracy for received AuxPtr assuming local sleep clock of 50 ppm + (uint32_t)0x0E490C83, + // override_frontend_id.xml + (uint32_t)0xFFFFFFFF, +}; + + +// Overrides for CMD_BLE5_RADIO_SETUP +uint32_t pOverrides1Mbps[] = +{ + // override_ble5_setup_override_1mbps.xml + // PHY: Use MCE RAM patch (mode 0), RFE RAM patch (mode 0) + MCE_RFE_OVERRIDE(1,0,0,1,0,0), + // Bluetooth 5: Reduce pilot tone length + HW_REG_OVERRIDE(0x5320,0x0240), + // Bluetooth 5: Compensate for reduced pilot tone length + (uint32_t)0x013302A3, + (uint32_t)0xFFFFFFFF, +}; + + +// Overrides for CMD_BLE5_RADIO_SETUP +uint32_t pOverrides2Mbps[] = +{ + // override_ble5_setup_override_2mbps.xml + // PHY: Use MCE RAM patch (mode 2), RFE RAM patch (mode 2) + MCE_RFE_OVERRIDE(1,0,2,1,0,2), + // Bluetooth 5: Reduce pilot tone length + HW_REG_OVERRIDE(0x5320,0x0240), + // Bluetooth 5: Compensate for reduced pilot tone length + (uint32_t)0x00D102A3, + (uint32_t)0xFFFFFFFF, +}; + + +// Overrides for CMD_BLE5_RADIO_SETUP +uint32_t pOverridesCoded[] = +{ + // override_ble5_setup_override_coded.xml + // PHY: Use MCE RAM patch (mode 1), RFE RAM patch (mode 1) + MCE_RFE_OVERRIDE(1,0,1,1,0,1), + // Bluetooth 5: Reduce pilot tone length + HW_REG_OVERRIDE(0x5320,0x0240), + // Bluetooth 5: Compensate for reduced pilot tone length + (uint32_t)0x078902A3, + (uint32_t)0xFFFFFFFF, +}; + + +// CMD_BLE5_RADIO_SETUP +// Bluetooth 5 Radio Setup Command for all PHYs +rfc_CMD_BLE5_RADIO_SETUP_t RF_cmdBle5RadioSetup = +{ + .commandNo = 0x1820, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .defaultPhy.mainMode = 0x0, + .defaultPhy.coding = 0x0, + .loDivider = 0x00, + .config.frontEndMode = 0x0, + .config.biasMode = 0x0, + .config.analogCfgMode = 0x0, + .config.bNoFsPowerUp = 0x0, + .txPower = 0x941E, + .pRegOverrideCommon = pOverridesCommon, + .pRegOverride1Mbps = pOverrides1Mbps, + .pRegOverride2Mbps = pOverrides2Mbps, + .pRegOverrideCoded = pOverridesCoded, +}; + +// CMD_FS +// Frequency Synthesizer Programming Command +rfc_CMD_FS_t RF_cmdFs = +{ + .commandNo = 0x0803, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .frequency = 0x0988, + .fractFreq = 0x0000, + .synthConf.bTxMode = 0x0, + .synthConf.refFreq = 0x0, + .__dummy0 = 0x00, + .__dummy1 = 0x00, + .__dummy2 = 0x00, + .__dummy3 = 0x0000, +}; + +// Structure for CMD_BLE5_ADV_AUX.pParams +rfc_ble5AdvAuxPar_t ble5AdvAuxPar = +{ + .pRxQ = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx + .rxConfig.bAutoFlushIgnored = 0x0, + .rxConfig.bAutoFlushCrcErr = 0x0, + .rxConfig.bAutoFlushEmpty = 0x0, + .rxConfig.bIncludeLenByte = 0x0, + .rxConfig.bIncludeCrc = 0x0, + .rxConfig.bAppendRssi = 0x0, + .rxConfig.bAppendStatus = 0x0, + .rxConfig.bAppendTimestamp = 0x0, + .advConfig.advFilterPolicy = 0x0, + .advConfig.deviceAddrType = 0x0, + .advConfig.targetAddrType = 0x0, + .advConfig.bStrictLenFilter = 0x0, + .advConfig.bDirected = 0x0, + .advConfig.privIgnMode = 0x0, + .advConfig.rpaMode = 0x0, + .__dummy0 = 0x00, + .auxPtrTargetType = 0x00, + .auxPtrTargetTime = 0x00000000, + .pAdvPkt = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .pRspPkt = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .pDeviceAddress = 0, // INSERT APPLICABLE POINTER: (uint16_t*)&xxx + .pWhiteList = 0, // INSERT APPLICABLE POINTER: (uint32_t*)&xxx +}; + +// CMD_BLE5_ADV_AUX +// Bluetooth 5 Secondary Channel Advertiser Command +rfc_CMD_BLE5_ADV_AUX_t RF_cmdBle5AdvAux = +{ + .commandNo = 0x1824, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .channel = 0x8C, + .whitening.init = 0x51, + .whitening.bOverride = 0x1, + .phyMode.mainMode = 0x0, + .phyMode.coding = 0x0, + .rangeDelay = 0x00, + .txPower = 0x0000, + .pParams = &ble5AdvAuxPar, + .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .tx20Power = 0x00000000, +}; + +// Structure for CMD_BLE5_GENERIC_RX.pParams +rfc_bleGenericRxPar_t bleGenericRxPar = +{ + .pRxQ = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx + .rxConfig.bAutoFlushIgnored = 0x0, + .rxConfig.bAutoFlushCrcErr = 0x0, + .rxConfig.bAutoFlushEmpty = 0x0, + .rxConfig.bIncludeLenByte = 0x1, + .rxConfig.bIncludeCrc = 0x1, + .rxConfig.bAppendRssi = 0x1, + .rxConfig.bAppendStatus = 0x1, + .rxConfig.bAppendTimestamp = 0x0, + .bRepeat = 0x01, + .__dummy0 = 0x0000, + .accessAddress = 0x8E89BED6, + .crcInit0 = 0x55, + .crcInit1 = 0x55, + .crcInit2 = 0x55, + .endTrigger.triggerType = 0x1, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000001, +}; + +// CMD_BLE5_GENERIC_RX +// Bluetooth 5 Generic Receiver Command +rfc_CMD_BLE5_GENERIC_RX_t RF_cmdBle5GenericRx = +{ + .commandNo = 0x1829, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .channel = 0x8C, + .whitening.init = 0x51, + .whitening.bOverride = 0x1, + .phyMode.mainMode = 0x0, + .phyMode.coding = 0x0, + .rangeDelay = 0x00, + .txPower = 0x0000, + .pParams = &bleGenericRxPar, + .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .tx20Power = 0x00000000, +}; diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.h new file mode 100644 index 000000000..748abf786 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.h @@ -0,0 +1,44 @@ +#ifndef _BLE-SETTINGS_H_ +#define _BLE-SETTINGS_H_ + +//********************************************************************************* +// Generated by SmartRF Studio version 2.10.0 (build#106) +// Compatible with SimpleLink SDK version: CC13x2 SDK 2.20.xx.xx +// Device: CC1352R Rev. 1.1 +// +//********************************************************************************* +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_ble_cmd.h) +#include + + +// TX Power table size definition +#define TX_POWER_TABLE_SIZE 16 + + +// TX Power Table Object +extern RF_TxPowerTable_Entry txPowerTable[TX_POWER_TABLE_SIZE]; + + +// TI-RTOS RF Mode Object +extern RF_Mode RF_prop; + + +// RF Core API commands +extern rfc_CMD_BLE5_RADIO_SETUP_t RF_cmdBle5RadioSetup; +extern rfc_CMD_FS_t RF_cmdFs; +extern rfc_CMD_BLE5_ADV_AUX_t RF_cmdBle5AdvAux; +extern rfc_CMD_BLE5_GENERIC_RX_t RF_cmdBle5GenericRx; + + +// RF Core API Overrides +extern uint32_t pOverridesCommon[]; +extern uint32_t pOverrides1Mbps[]; +extern uint32_t pOverrides2Mbps[]; +extern uint32_t pOverridesCoded[]; + + +#endif // _BLE-SETTINGS_H_ + diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.c new file mode 100644 index 000000000..39f2b8691 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.c @@ -0,0 +1,256 @@ +//********************************************************************************* +// Generated by SmartRF Studio version 2.10.0 (build#106) +// Compatible with SimpleLink SDK version: No known SDK for this device +// Device: CC2650 Rev. 2.2 +// +//********************************************************************************* + + +//********************************************************************************* +// Parameter summary +// Adv. Address: 010203040506 +// Adv. Data: 255 +// BLE Channel: 17 +// Frequency: 2440 MHz +// PDU Payload length:: 30 +// TX Power: 5 dBm +// Whitening: true + +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_ble_cmd.h) +#include +#include DeviceFamily_constructPath(rf_patches/rf_patch_cpe_ble.h) +#include DeviceFamily_constructPath(rf_patches/rf_patch_rfe_ble.h) +#include "ieee_settings.h" + + +// TI-RTOS RF Mode Object +RF_Mode RF_ble = +{ + .rfMode = RF_MODE_BLE, + .cpePatchFxn = &rf_patch_cpe_ble, + .mcePatchFxn = 0, + .rfePatchFxn = &rf_patch_rfe_ble, +}; + +// TX Power table +// The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: +// RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) +// See the Technical Reference Manual for further details about the "txPower" Command field. +// The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. +RF_TxPowerTable_Entry txPowerTable[TX_POWER_TABLE_SIZE] = +{ + {-21, RF_TxPowerTable_DEFAULT_PA_ENTRY(7, 3, 0, 6) }, + {-18, RF_TxPowerTable_DEFAULT_PA_ENTRY(9, 3, 0, 6) }, + {-15, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 6) }, + {-12, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 1, 0, 10) }, + {-9, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 1, 12) }, + {-6, RF_TxPowerTable_DEFAULT_PA_ENTRY(18, 1, 1, 14) }, + {-3, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 1, 1, 18) }, + {0, RF_TxPowerTable_DEFAULT_PA_ENTRY(33, 1, 1, 24) }, + {1, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 0, 0, 33) }, + {2, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 0, 0, 39) }, + {3, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 0, 0, 45) }, + {4, RF_TxPowerTable_DEFAULT_PA_ENTRY(36, 0, 1, 73) }, + {5, RF_TxPowerTable_DEFAULT_PA_ENTRY(48, 0, 1, 73) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; + + +// Overrides for CMD_RADIO_SETUP +uint32_t pOverrides[] = +{ + // override_use_patch_ble_1mbps.xml + // PHY: Use MCE ROM, RFE RAM patch + MCE_RFE_OVERRIDE(0,0,0,1,0,0), + // override_synth_ble_1mbps.xml + // Synth: Set recommended RTRIM to 5 + HW_REG_OVERRIDE(0x4038,0x0035), + // Synth: Set Fref to 3.43 MHz + (uint32_t)0x000784A3, + // Synth: Set loop bandwidth after lock to 80 kHz + (uint32_t)0xA47E0583, + // Synth: Set loop bandwidth after lock to 80 kHz + (uint32_t)0xEAE00603, + // Synth: Set loop bandwidth after lock to 80 kHz + (uint32_t)0x00010623, + // Synth: Configure PLL bias + HW32_ARRAY_OVERRIDE(0x405C,1), + // Synth: Configure PLL bias + (uint32_t)0x1801F800, + // Synth: Configure PLL latency + HW32_ARRAY_OVERRIDE(0x402C,1), + // Synth: Configure PLL latency + (uint32_t)0x00608402, + // Synth: Use 24 MHz XOSC as synth clock, enable extra PLL filtering + (uint32_t)0x02010403, + // Synth: Configure extra PLL filtering + HW32_ARRAY_OVERRIDE(0x4034,1), + // Synth: Configure extra PLL filtering + (uint32_t)0x177F0408, + // Synth: Configure extra PLL filtering + (uint32_t)0x38000463, + // override_phy_ble_1mbps.xml + // Tx: Configure symbol shape for BLE frequency deviation requirements + (uint32_t)0x013800C3, + // Rx: Configure AGC reference level + HW_REG_OVERRIDE(0x6088, 0x0045), + // Tx: Configure pilot tone length to ensure stable frequency before start of packet + HW_REG_OVERRIDE(0x52AC, 0x0360), + // Tx: Compensate timing offset to match new pilot tone setting + (uint32_t)0x01AD02A3, + // Tx: Compensate timing offset to match new pilot tone setting + (uint32_t)0x01680263, + // override_frontend_id.xml + (uint32_t)0xFFFFFFFF, +}; + + +// CMD_RADIO_SETUP +// Radio Setup Command for Pre-Defined Schemes +rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup = +{ + .commandNo = 0x0802, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .mode = 0x00, + .__dummy0 = 0x00, + .config.frontEndMode = 0x0, + .config.biasMode = 0x0, + .config.analogCfgMode = 0x0, + .config.bNoFsPowerUp = 0x0, + .txPower = 0x9330, + .pRegOverride = pOverrides, +}; + +// CMD_FS +// Frequency Synthesizer Programming Command +rfc_CMD_FS_t RF_cmdFs = +{ + .commandNo = 0x0803, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .frequency = 0x0988, + .fractFreq = 0x0000, + .synthConf.bTxMode = 0x0, + .synthConf.refFreq = 0x0, + .__dummy0 = 0x00, + .__dummy1 = 0x00, + .__dummy2 = 0x00, + .__dummy3 = 0x0000, +}; + +// Structure for CMD_BLE_ADV_NC.pParams +rfc_bleAdvPar_t bleAdvPar = +{ + .pRxQ = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx + .rxConfig.bAutoFlushIgnored = 0x0, + .rxConfig.bAutoFlushCrcErr = 0x0, + .rxConfig.bAutoFlushEmpty = 0x0, + .rxConfig.bIncludeLenByte = 0x0, + .rxConfig.bIncludeCrc = 0x0, + .rxConfig.bAppendRssi = 0x0, + .rxConfig.bAppendStatus = 0x0, + .rxConfig.bAppendTimestamp = 0x0, + .advConfig.advFilterPolicy = 0x0, + .advConfig.deviceAddrType = 0x0, + .advConfig.peerAddrType = 0x0, + .advConfig.bStrictLenFilter = 0x0, + .advConfig.rpaMode = 0x0, + .advLen = 0x18, + .scanRspLen = 0x00, + .pAdvData = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .pScanRspData = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .pDeviceAddress = 0, // INSERT APPLICABLE POINTER: (uint16_t*)&xxx + .pWhiteList = 0, // INSERT APPLICABLE POINTER: (uint32_t*)&xxx + .__dummy0 = 0x0000, + .__dummy1 = 0x00, + .endTrigger.triggerType = 0x1, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, +}; + +// CMD_BLE_ADV_NC +// BLE Non-Connectable Advertiser Command +rfc_CMD_BLE_ADV_NC_t RF_cmdBleAdvNc = +{ + .commandNo = 0x1805, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .channel = 0x8C, + .whitening.init = 0x51, + .whitening.bOverride = 0x1, + .pParams = &bleAdvPar, + .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx +}; + +// Structure for CMD_BLE_GENERIC_RX.pParams +rfc_bleGenericRxPar_t bleGenericRxPar = +{ + .pRxQ = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx + .rxConfig.bAutoFlushIgnored = 0x0, + .rxConfig.bAutoFlushCrcErr = 0x0, + .rxConfig.bAutoFlushEmpty = 0x0, + .rxConfig.bIncludeLenByte = 0x1, + .rxConfig.bIncludeCrc = 0x1, + .rxConfig.bAppendRssi = 0x1, + .rxConfig.bAppendStatus = 0x1, + .rxConfig.bAppendTimestamp = 0x0, + .bRepeat = 0x01, + .__dummy0 = 0x0000, + .accessAddress = 0x8E89BED6, + .crcInit0 = 0x55, + .crcInit1 = 0x55, + .crcInit2 = 0x55, + .endTrigger.triggerType = 0x1, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000001, +}; + +// CMD_BLE_GENERIC_RX +// BLE Generic Receiver Command +rfc_CMD_BLE_GENERIC_RX_t RF_cmdBleGenericRx = +{ + .commandNo = 0x1809, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .channel = 0x8C, + .whitening.init = 0x51, + .whitening.bOverride = 0x1, + .pParams = &bleGenericRxPar, + .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx +}; diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.h new file mode 100644 index 000000000..7bdf9b309 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.h @@ -0,0 +1,41 @@ +#ifndef _BLE-SETTINGS_H_ +#define _BLE-SETTINGS_H_ + +//********************************************************************************* +// Generated by SmartRF Studio version 2.10.0 (build#106) +// Compatible with SimpleLink SDK version: No known SDK for this device +// Device: CC2650 Rev. 2.2 +// +//********************************************************************************* +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_ble_cmd.h) +#include + + +// TX Power table size definition +#define TX_POWER_TABLE_SIZE 14 + + +// TX Power Table Object +extern RF_TxPowerTable_Entry txPowerTable[TX_POWER_TABLE_SIZE]; + + +// TI-RTOS RF Mode Object +extern RF_Mode RF_ble; + + +// RF Core API commands +extern rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup; +extern rfc_CMD_FS_t RF_cmdFs; +extern rfc_CMD_BLE_ADV_NC_t RF_cmdBleAdvNc; +extern rfc_CMD_BLE_GENERIC_RX_t RF_cmdBleGenericRx; + + +// RF Core API Overrides +extern uint32_t pOverrides[]; + + +#endif // _BLE-SETTINGS_H_ + diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.c new file mode 100644 index 000000000..69758f60f --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.c @@ -0,0 +1,308 @@ +//********************************************************************************* +// Generated by SmartRF Studio version 2.10.0 (build#106) +// Compatible with SimpleLink SDK version: CC26x2 SDK 2.20.xx.xx +// Device: CC2652R Rev. 1.1 (Rev. C) +// +//********************************************************************************* + + +//********************************************************************************* +// Parameter summary +// Adv. Address: 010203040506 +// Adv. Data: dummy +// BLE Channel: 17 +// Extended Header: 09 09 010203040506 babe +// Frequency: 2440 MHz +// PDU Payload length:: 30 +// TX Power: 5 dBm +// Whitening: true + +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_ble_cmd.h) +#include +#include DeviceFamily_constructPath(rf_patches/rf_patch_cpe_bt5.h) +#include DeviceFamily_constructPath(rf_patches/rf_patch_rfe_bt5.h) +#include DeviceFamily_constructPath(rf_patches/rf_patch_mce_bt5.h) +#include "ble-settings.h" + + +// TI-RTOS RF Mode Object +RF_Mode RF_prop = +{ + .rfMode = RF_MODE_AUTO, + .cpePatchFxn = &rf_patch_cpe_bt5, + .mcePatchFxn = &rf_patch_mce_bt5, + .rfePatchFxn = &rf_patch_rfe_bt5, +}; + +// TX Power table +// The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: +// RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) +// See the Technical Reference Manual for further details about the "txPower" Command field. +// The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. +RF_TxPowerTable_Entry txPowerTable[TX_POWER_TABLE_SIZE] = +{ + {-21, RF_TxPowerTable_DEFAULT_PA_ENTRY(7, 3, 0, 3) }, + {-18, RF_TxPowerTable_DEFAULT_PA_ENTRY(9, 3, 0, 3) }, + {-15, RF_TxPowerTable_DEFAULT_PA_ENTRY(8, 2, 0, 6) }, + {-12, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 2, 0, 8) }, + {-10, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 11) }, + {-9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 2, 0, 5) }, + {-6, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 16) }, + {-5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 17) }, + {-3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 1, 0, 20) }, + {0, RF_TxPowerTable_DEFAULT_PA_ENTRY(25, 1, 0, 26) }, + {1, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 1, 0, 28) }, + {2, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 0, 0, 34) }, + {3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 0, 0, 42) }, + {4, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 0, 0, 54) }, + {5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; + + +// Overrides for CMD_BLE5_RADIO_SETUP +uint32_t pOverridesCommon[] = +{ + // override_ble5_setup_override_common.xml + // Synth: Use 48 MHz crystal, enable extra PLL filtering + (uint32_t)0x02400403, + // Synth: Configure extra PLL filtering + (uint32_t)0x001C8473, + // Synth: Configure synth hardware + (uint32_t)0x00088433, + // Synth: Set minimum RTRIM to 3 + (uint32_t)0x00038793, + // Synth: Configure faster calibration + HW32_ARRAY_OVERRIDE(0x4004,1), + // Synth: Configure faster calibration + (uint32_t)0x1C0C0618, + // Synth: Configure faster calibration + (uint32_t)0xC00401A1, + // Synth: Configure faster calibration + (uint32_t)0x00010101, + // Synth: Configure faster calibration + (uint32_t)0xC0040141, + // Synth: Configure faster calibration + (uint32_t)0x00214AD3, + // Synth: Decrease synth programming time-out (0x0298 RAT ticks = 166 us) + (uint32_t)0x02980243, + // DC/DC regulator: In Tx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). + (uint32_t)0xFCFC08C3, + // Rx: Set LNA bias current offset to adjust +3 (default: 0) + (uint32_t)0x00038883, + // Rx: Set RSSI offset to adjust reported RSSI by -2 dB (default: 0) + (uint32_t)0x000288A3, + // Bluetooth 5: Compensate for reduced pilot tone length + (uint32_t)0x01080263, + // Bluetooth 5: Compensate for reduced pilot tone length + (uint32_t)0x08E90AA3, + // Bluetooth 5: Compensate for reduced pilot tone length + (uint32_t)0x00068BA3, + // Bluetooth 5: Set correct total clock accuracy for received AuxPtr assuming local sleep clock of 50 ppm + (uint32_t)0x0E490C83, + // override_frontend_id.xml + (uint32_t)0xFFFFFFFF, +}; + + +// Overrides for CMD_BLE5_RADIO_SETUP +uint32_t pOverrides1Mbps[] = +{ + // override_ble5_setup_override_1mbps.xml + // PHY: Use MCE RAM patch (mode 0), RFE RAM patch (mode 0) + MCE_RFE_OVERRIDE(1,0,0,1,0,0), + // Bluetooth 5: Reduce pilot tone length + HW_REG_OVERRIDE(0x5320,0x0240), + // Bluetooth 5: Compensate for reduced pilot tone length + (uint32_t)0x013302A3, + (uint32_t)0xFFFFFFFF, +}; + + +// Overrides for CMD_BLE5_RADIO_SETUP +uint32_t pOverrides2Mbps[] = +{ + // override_ble5_setup_override_2mbps.xml + // PHY: Use MCE RAM patch (mode 2), RFE RAM patch (mode 2) + MCE_RFE_OVERRIDE(1,0,2,1,0,2), + // Bluetooth 5: Reduce pilot tone length + HW_REG_OVERRIDE(0x5320,0x0240), + // Bluetooth 5: Compensate for reduced pilot tone length + (uint32_t)0x00D102A3, + (uint32_t)0xFFFFFFFF, +}; + + +// Overrides for CMD_BLE5_RADIO_SETUP +uint32_t pOverridesCoded[] = +{ + // override_ble5_setup_override_coded.xml + // PHY: Use MCE RAM patch (mode 1), RFE RAM patch (mode 1) + MCE_RFE_OVERRIDE(1,0,1,1,0,1), + // Bluetooth 5: Reduce pilot tone length + HW_REG_OVERRIDE(0x5320,0x0240), + // Bluetooth 5: Compensate for reduced pilot tone length + (uint32_t)0x078902A3, + (uint32_t)0xFFFFFFFF, +}; + + +// CMD_BLE5_RADIO_SETUP +// Bluetooth 5 Radio Setup Command for all PHYs +rfc_CMD_BLE5_RADIO_SETUP_t RF_cmdBle5RadioSetup = +{ + .commandNo = 0x1820, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .defaultPhy.mainMode = 0x0, + .defaultPhy.coding = 0x0, + .loDivider = 0x00, + .config.frontEndMode = 0x0, + .config.biasMode = 0x0, + .config.analogCfgMode = 0x0, + .config.bNoFsPowerUp = 0x0, + .txPower = 0x941E, + .pRegOverrideCommon = pOverridesCommon, + .pRegOverride1Mbps = pOverrides1Mbps, + .pRegOverride2Mbps = pOverrides2Mbps, + .pRegOverrideCoded = pOverridesCoded, +}; + +// CMD_FS +// Frequency Synthesizer Programming Command +rfc_CMD_FS_t RF_cmdFs = +{ + .commandNo = 0x0803, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .frequency = 0x0988, + .fractFreq = 0x0000, + .synthConf.bTxMode = 0x0, + .synthConf.refFreq = 0x0, + .__dummy0 = 0x00, + .__dummy1 = 0x00, + .__dummy2 = 0x00, + .__dummy3 = 0x0000, +}; + +// Structure for CMD_BLE5_ADV_AUX.pParams +rfc_ble5AdvAuxPar_t ble5AdvAuxPar = +{ + .pRxQ = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx + .rxConfig.bAutoFlushIgnored = 0x0, + .rxConfig.bAutoFlushCrcErr = 0x0, + .rxConfig.bAutoFlushEmpty = 0x0, + .rxConfig.bIncludeLenByte = 0x0, + .rxConfig.bIncludeCrc = 0x0, + .rxConfig.bAppendRssi = 0x0, + .rxConfig.bAppendStatus = 0x0, + .rxConfig.bAppendTimestamp = 0x0, + .advConfig.advFilterPolicy = 0x0, + .advConfig.deviceAddrType = 0x0, + .advConfig.targetAddrType = 0x0, + .advConfig.bStrictLenFilter = 0x0, + .advConfig.bDirected = 0x0, + .advConfig.privIgnMode = 0x0, + .advConfig.rpaMode = 0x0, + .__dummy0 = 0x00, + .auxPtrTargetType = 0x00, + .auxPtrTargetTime = 0x00000000, + .pAdvPkt = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .pRspPkt = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .pDeviceAddress = 0, // INSERT APPLICABLE POINTER: (uint16_t*)&xxx + .pWhiteList = 0, // INSERT APPLICABLE POINTER: (uint32_t*)&xxx +}; + +// CMD_BLE5_ADV_AUX +// Bluetooth 5 Secondary Channel Advertiser Command +rfc_CMD_BLE5_ADV_AUX_t RF_cmdBle5AdvAux = +{ + .commandNo = 0x1824, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .channel = 0x8C, + .whitening.init = 0x51, + .whitening.bOverride = 0x1, + .phyMode.mainMode = 0x0, + .phyMode.coding = 0x0, + .rangeDelay = 0x00, + .txPower = 0x0000, + .pParams = &ble5AdvAuxPar, + .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .tx20Power = 0x00000000, +}; + +// Structure for CMD_BLE5_GENERIC_RX.pParams +rfc_bleGenericRxPar_t bleGenericRxPar = +{ + .pRxQ = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx + .rxConfig.bAutoFlushIgnored = 0x0, + .rxConfig.bAutoFlushCrcErr = 0x0, + .rxConfig.bAutoFlushEmpty = 0x0, + .rxConfig.bIncludeLenByte = 0x1, + .rxConfig.bIncludeCrc = 0x1, + .rxConfig.bAppendRssi = 0x1, + .rxConfig.bAppendStatus = 0x1, + .rxConfig.bAppendTimestamp = 0x0, + .bRepeat = 0x01, + .__dummy0 = 0x0000, + .accessAddress = 0x8E89BED6, + .crcInit0 = 0x55, + .crcInit1 = 0x55, + .crcInit2 = 0x55, + .endTrigger.triggerType = 0x1, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000001, +}; + +// CMD_BLE5_GENERIC_RX +// Bluetooth 5 Generic Receiver Command +rfc_CMD_BLE5_GENERIC_RX_t RF_cmdBle5GenericRx = +{ + .commandNo = 0x1829, + .status = 0x0000, + .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .startTime = 0x00000000, + .startTrigger.triggerType = 0x0, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = 0x1, + .condition.nSkip = 0x0, + .channel = 0x8C, + .whitening.init = 0x51, + .whitening.bOverride = 0x1, + .phyMode.mainMode = 0x0, + .phyMode.coding = 0x0, + .rangeDelay = 0x00, + .txPower = 0x0000, + .pParams = &bleGenericRxPar, + .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .tx20Power = 0x00000000, +}; diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.h new file mode 100644 index 000000000..4cf6518d6 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.h @@ -0,0 +1,44 @@ +#ifndef _BLE-SETTINGS_H_ +#define _BLE-SETTINGS_H_ + +//********************************************************************************* +// Generated by SmartRF Studio version 2.10.0 (build#106) +// Compatible with SimpleLink SDK version: CC26x2 SDK 2.20.xx.xx +// Device: CC2652R Rev. 1.1 (Rev. C) +// +//********************************************************************************* +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_ble_cmd.h) +#include + + +// TX Power table size definition +#define TX_POWER_TABLE_SIZE 16 + + +// TX Power Table Object +extern RF_TxPowerTable_Entry txPowerTable[TX_POWER_TABLE_SIZE]; + + +// TI-RTOS RF Mode Object +extern RF_Mode RF_prop; + + +// RF Core API commands +extern rfc_CMD_BLE5_RADIO_SETUP_t RF_cmdBle5RadioSetup; +extern rfc_CMD_FS_t RF_cmdFs; +extern rfc_CMD_BLE5_ADV_AUX_t RF_cmdBle5AdvAux; +extern rfc_CMD_BLE5_GENERIC_RX_t RF_cmdBle5GenericRx; + + +// RF Core API Overrides +extern uint32_t pOverridesCommon[]; +extern uint32_t pOverrides1Mbps[]; +extern uint32_t pOverrides2Mbps[]; +extern uint32_t pOverridesCoded[]; + + +#endif // _BLE-SETTINGS_H_ + From 315bfc00d348343e6e2343f33170beb01dc5da83 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Fri, 6 Jul 2018 18:23:43 +0200 Subject: [PATCH 259/485] Added SUPPORT_BLE_BEACON flag --- arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 16 ++++++++++++---- .../launchpad/cc1310/Makefile.cc1310 | 5 +++-- .../launchpad/cc1312r1/Makefile.cc1312r1 | 5 +++-- .../launchpad/cc1350-4/Makefile.cc1350-4 | 5 +++-- .../launchpad/cc1350/Makefile.cc1350 | 5 +++-- .../launchpad/cc1352p-2/Makefile.cc1352p-2 | 5 +++-- .../launchpad/cc1352p-4/Makefile.cc1352p-4 | 5 +++-- .../launchpad/cc1352p1/Makefile.cc1352p1 | 5 +++-- .../launchpad/cc1352r1/Makefile.cc1352r1 | 5 +++-- .../launchpad/cc2650/Makefile.cc2650 | 5 +++-- .../launchpad/cc26x2r1/Makefile.cc26x2r1 | 5 +++-- .../sensortag/cc1350/Makefile.cc1350 | 5 +++-- .../sensortag/cc2650/Makefile.cc2650 | 5 +++-- .../cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 | 5 +++-- .../cc13xx-cc26xx/srf06/cc26x0/Makefile.cc26x0 | 5 +++-- 15 files changed, 54 insertions(+), 32 deletions(-) diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index 35e88181a..686ebb556 100644 --- a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -71,11 +71,12 @@ CONTIKI_CPU_SOURCEFILES += rtimer-arch.c clock-arch.c CONTIKI_CPU_SOURCEFILES += watchdog-arch.c dbg-arch.c CONTIKI_CPU_SOURCEFILES += uart0-arch.c slip-arch.c CONTIKI_CPU_SOURCEFILES += batmon-sensor.c gpio-hal-arch.c -CONTIKI_CPU_SOURCEFILES += rf-common.c int-master-arch.c -CONTIKI_CPU_SOURCEFILES += ieee-addr.c +CONTIKI_CPU_SOURCEFILES += int-master-arch.c -### CPU-dependent debug source files -MODULES += os/lib/dbg-io +### RF source files +CONTIKI_CPU_SOURCEFILES += rf-core.c +CONTIKI_CPU_SOURCEFILES += ieee-addr.c ble-addr.c +CONTIKI_CPU_SOURCEFILES += rf-ble-beacon.c ifeq ($(SUPPORTS_PROP_MODE),1) CONTIKI_CPU_SOURCEFILES += rf-prop-mode.c prop-settings.c @@ -85,6 +86,13 @@ ifeq ($(SUPPORTS_IEEE_MODE),1) CONTIKI_CPU_SOURCEFILES += rf-ieee-mode.c ieee-settings.c endif +ifeq ($(SUPPORTS_BLE_BEACON),1) +CONTIKI_CPU_SOURCEFILES += rf-ble-beacond.c ble-settings.c +endif + +### CPU-dependent debug source files +MODULES += os/lib/dbg-io + ### CPU-dependent directories CONTIKI_CPU_DIRS += . dev $(SUBFAMILY) rf-settings/$(DEVICE_FAMILY_LC) diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Makefile.cc1310 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Makefile.cc1310 index c141e580d..257308196 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Makefile.cc1310 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Makefile.cc1310 @@ -7,8 +7,9 @@ DEVICE_LINE = CC13XX BOARD_SOURCEFILES += CC1310_LAUNCHXL.c CC1310_LAUNCHXL_fxns.c -SUPPORTS_PROP_MODE = 1 -SUPPORTS_IEEE_MODE = 0 +SUPPORTS_PROP_MODE = 1 +SUPPORTS_IEEE_MODE = 0 +SUPPORTS_BLE_BEACON = 0 SUPPORTS_HIGH_PA = 0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 index e71992113..7b773d7be 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 @@ -10,8 +10,9 @@ BOARD_SOURCEFILES += CC1312R1_LAUNCHXL.c CC1312R1_LAUNCHXL_fxns.c DEFINES += PROP_MODE_CONF_TX_POWER_TABLE=rf_prop_tx_power_table_default_pa DEFINES += PROP_MODE_CONF_TX_POWER_TABLE_SIZE=RF_PROP_TX_POWER_TABLE_DEFAULT_PA_SIZE -SUPPORTS_PROP_MODE = 1 -SUPPORTS_IEEE_MODE = 0 +SUPPORTS_PROP_MODE = 1 +SUPPORTS_IEEE_MODE = 0 +SUPPORTS_BLE_BEACON = 0 SUPPORTS_HIGH_PA = 0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Makefile.cc1350-4 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Makefile.cc1350-4 index 620b36fb6..df701aa49 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Makefile.cc1350-4 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Makefile.cc1350-4 @@ -7,8 +7,9 @@ DEVICE_LINE = CC13XX BOARD_SOURCEFILES += CC1350_LAUNCHXL_433.c CC1350_LAUNCHXL_433_fxns.c -SUPPORTS_PROP_MODE = 1 -SUPPORTS_IEEE_MODE = 1 +SUPPORTS_PROP_MODE = 1 +SUPPORTS_IEEE_MODE = 1 +SUPPORTS_BLE_BEACON = 1 SUPPORTS_HIGH_PA = 0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Makefile.cc1350 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Makefile.cc1350 index e365c81ad..45c9212e1 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Makefile.cc1350 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Makefile.cc1350 @@ -7,8 +7,9 @@ DEVICE_LINE = CC13XX BOARD_SOURCEFILES += CC1350_LAUNCHXL.c CC1350_LAUNCHXL_fxns.c -SUPPORTS_PROP_MODE = 1 -SUPPORTS_IEEE_MODE = 1 +SUPPORTS_PROP_MODE = 1 +SUPPORTS_IEEE_MODE = 1 +SUPPORTS_BLE_BEACON = 1 SUPPORTS_HIGH_PA = 0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/Makefile.cc1352p-2 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/Makefile.cc1352p-2 index e8608fae7..651336ad3 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/Makefile.cc1352p-2 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/Makefile.cc1352p-2 @@ -13,8 +13,9 @@ DEFINES += PROP_MODE_CONF_TX_POWER_TABLE_SIZE=RF_PROP_TX_POWER_TABLE_DEFAULT_PA_ DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE=rf_ieee_tx_power_table_default_pa DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE_SIZE=RF_IEEE_TX_POWER_TABLE_DEFAULT_PA_SIZE -SUPPORTS_PROP_MODE = 1 -SUPPORTS_IEEE_MODE = 1 +SUPPORTS_PROP_MODE = 1 +SUPPORTS_IEEE_MODE = 1 +SUPPORTS_BLE_BEACON = 1 SUPPORTS_HIGH_PA = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/Makefile.cc1352p-4 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/Makefile.cc1352p-4 index 8288e292c..b03e44903 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/Makefile.cc1352p-4 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/Makefile.cc1352p-4 @@ -13,8 +13,9 @@ DEFINES += PROP_MODE_CONF_TX_POWER_TABLE_SIZE=RF_PROP_TX_POWER_TABLE_DEFAULT_PA_ DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE=rf_ieee_tx_power_table_default_pa DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE_SIZE=RF_IEEE_TX_POWER_TABLE_DEFAULT_PA_SIZE -SUPPORTS_PROP_MODE = 1 -SUPPORTS_IEEE_MODE = 1 +SUPPORTS_PROP_MODE = 1 +SUPPORTS_IEEE_MODE = 1 +SUPPORTS_BLE_BEACON = 1 SUPPORTS_HIGH_PA = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 index 9ea537df7..b628d1aae 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 @@ -13,8 +13,9 @@ DEFINES += PROP_MODE_CONF_TX_POWER_TABLE_SIZE=RF_PROP_TX_POWER_TABLE_DEFAULT_PA_ DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE=rf_ieee_tx_power_table_default_pa DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE_SIZE=RF_IEEE_TX_POWER_TABLE_DEFAULT_PA_SIZE -SUPPORTS_PROP_MODE = 1 -SUPPORTS_IEEE_MODE = 1 +SUPPORTS_PROP_MODE = 1 +SUPPORTS_IEEE_MODE = 1 +SUPPORTS_BLE_BEACON = 1 SUPPORTS_HIGH_PA = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 index 31434afb6..fc9b5c1c5 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 @@ -13,8 +13,9 @@ DEFINES += PROP_MODE_CONF_TX_POWER_TABLE_SIZE=RF_PROP_TX_POWER_TABLE_DEFAULT_PA_ DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE=rf_ieee_tx_power_table_default_pa DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE_SIZE=RF_IEEE_TX_POWER_TABLE_DEFAULT_PA_SIZE -SUPPORTS_PROP_MODE = 1 -SUPPORTS_IEEE_MODE = 1 +SUPPORTS_PROP_MODE = 1 +SUPPORTS_IEEE_MODE = 1 +SUPPORTS_BLE_BEACON = 1 SUPPORTS_HIGH_PA = 0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Makefile.cc2650 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Makefile.cc2650 index 19d47535f..51e402012 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Makefile.cc2650 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Makefile.cc2650 @@ -7,8 +7,9 @@ DEVICE_LINE = CC26XX BOARD_SOURCEFILES += CC2650_LAUNCHXL.c CC2650_LAUNCHXL_fxns.c -SUPPORTS_PROP_MODE = 0 -SUPPORTS_IEEE_MODE = 1 +SUPPORTS_PROP_MODE = 0 +SUPPORTS_IEEE_MODE = 1 +SUPPORTS_BLE_BEACON = 1 SUPPORTS_HIGH_PA = 0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Makefile.cc26x2r1 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Makefile.cc26x2r1 index f1e64bac3..16891656a 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Makefile.cc26x2r1 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Makefile.cc26x2r1 @@ -7,8 +7,9 @@ DEVICE_LINE = CC26XX BOARD_SOURCEFILES += CC26X2R1_LAUNCHXL.c CC26X2R1_LAUNCHXL_fxns.c -SUPPORTS_PROP_MODE = 0 -SUPPORTS_IEEE_MODE = 1 +SUPPORTS_PROP_MODE = 0 +SUPPORTS_IEEE_MODE = 1 +SUPPORTS_BLE_BEACON = 1 SUPPORTS_HIGH_PA = 0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Makefile.cc1350 b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Makefile.cc1350 index 44939378c..475ada460 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Makefile.cc1350 +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Makefile.cc1350 @@ -8,8 +8,9 @@ DEVICE_LINE = CC13XX BOARD_SOURCEFILES += CC1350STK.c CC1350STK_fxns.c BOARD_SOURCEFILES += leds-arch.c -SUPPORTS_PROP_MODE = 1 -SUPPORTS_IEEE_MODE = 1 +SUPPORTS_PROP_MODE = 1 +SUPPORTS_IEEE_MODE = 1 +SUPPORTS_BLE_BEACON = 1 SUPPORTS_HIGH_PA = 0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 index 5e1a70c88..02366870d 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 @@ -8,8 +8,9 @@ DEVICE_LINE = CC26XX BOARD_SOURCEFILES += CC2650STK.c CC2650STK_fxns.c BOARD_SOURCEFILES += leds-arch.c -SUPPORTS_PROP_MODE = 0 -SUPPORTS_IEEE_MODE = 1 +SUPPORTS_PROP_MODE = 0 +SUPPORTS_IEEE_MODE = 1 +SUPPORTS_BLE_BEACON = 1 SUPPORTS_HIGH_PA = 0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 index 849ebc663..f79529781 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 @@ -7,8 +7,9 @@ DEVICE_LINE = CC13XX BOARD_SOURCEFILES += CC1310DK_7XD.c CC1310DK_7XD_fxns.c -SUPPORTS_PROP_MODE = 1 -SUPPORTS_IEEE_MODE = 1 +SUPPORTS_PROP_MODE = 1 +SUPPORTS_IEEE_MODE = 1 +SUPPORTS_BLE_BEACON = 1 SUPPORTS_HIGH_PA = 0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Makefile.cc26x0 b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Makefile.cc26x0 index 7882c9674..2b8693a2a 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Makefile.cc26x0 +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Makefile.cc26x0 @@ -7,8 +7,9 @@ DEVICE_LINE = CC26XX BOARD_SOURCEFILES += CC2650DK_7ID.c CC2650DK_7ID_fxns.c -SUPPORTS_PROP_MODE = 0 -SUPPORTS_IEEE_MODE = 1 +SUPPORTS_PROP_MODE = 0 +SUPPORTS_IEEE_MODE = 1 +SUPPORTS_BLE_BEACON = 1 SUPPORTS_HIGH_PA = 0 From 676b3dbcc199bdb1fadc2d949aa801f67b1408a6 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Fri, 6 Jul 2018 18:24:35 +0200 Subject: [PATCH 260/485] Added BLE and IEEE MAC address functions --- arch/cpu/cc13xx-cc26xx/dev/ble-addr.c | 128 +++++++++++++++++++++++++ arch/cpu/cc13xx-cc26xx/dev/ble-addr.h | 81 ++++++++++++++++ arch/cpu/cc13xx-cc26xx/dev/ieee-addr.c | 42 +++++--- arch/cpu/cc13xx-cc26xx/dev/ieee-addr.h | 23 +---- 4 files changed, 239 insertions(+), 35 deletions(-) create mode 100644 arch/cpu/cc13xx-cc26xx/dev/ble-addr.c create mode 100644 arch/cpu/cc13xx-cc26xx/dev/ble-addr.h diff --git a/arch/cpu/cc13xx-cc26xx/dev/ble-addr.c b/arch/cpu/cc13xx-cc26xx/dev/ble-addr.c new file mode 100644 index 000000000..c61c3af95 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/dev/ble-addr.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2016, Michael Spoerk + * 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. + * + */ +/** + * \file + * Driver for the retrieval of an BLE address from flash + * + * \author + * Michael Spoerk + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" + +#include "dev/ble-hal.h" +#include "net/linkaddr.h" + +#include "ble-addr.h" + +#include +/*---------------------------------------------------------------------------*/ +#include +#include DeviceFamily_constructPath(inc/hw_memmap.h) +#include DeviceFamily_constructPath(inc/hw_fcfg1.h) +#include DeviceFamily_constructPath(inc/hw_ccfg.h) +/*---------------------------------------------------------------------------*/ +#define BLE_MAC_PRIMARY_ADDRESS (FCFG1_BASE + FCFG1_O_MAC_BLE_0) +#define BLE_MAC_SECONDARY_ADDRESS (CCFG_BASE + CCFG_O_IEEE_BLE_0) +/*---------------------------------------------------------------------------*/ +int +ble_addr_cpy(uint8_t *dst) +{ + if(!dst) { + return -1; + } + + int i; + + const uint8_t * const primary = (uint8_t *)BLE_MAC_PRIMARY_ADDRESS; + const uint8_t * const secondary = (uint8_t *)BLE_MAC_SECONDARY_ADDRESS; + + /* Reading from primary location... */ + const uint8_t *ble_addr = primary; + + /* + * ...unless we can find a byte != 0xFF in secondary + * + * Intentionally checking all bytes here instead of len, because we + * are checking validity of the entire address irrespective of the + * actual number of bytes the caller wants to copy over. + */ + for(i = 0; i < BLE_ADDR_SIZE; i++) { + if(HWREG(secondary + i) != 0xFF) { + /* A byte in the secondary location is not 0xFF. Use the secondary */ + ble_addr = secondary; + break; + } + } + + /* + * We have chosen what address to read the BLE address from. Do so, + * inverting byte order + */ + for(i = 0; i < BLE_ADDR_SIZE; i++) { + dst[i] = HWREG(ble_addr + BLE_ADDR_SIZE - 1 - i); + } + + return 0; +} +/*---------------------------------------------------------------------------*/ +int +ble_addr_to_eui64(uint8_t *dst, uint8_t *src) +{ + if (!dst || !src) { + return -1; + } + + memcpy(dst, src, 3); + dst[3] = 0xFF; + dst[4] = 0xFE; + memcpy(&dst[5], &src[3], 3); + + return 0; +} +/*---------------------------------------------------------------------------*/ +int +ble_addr_to_eui64_cpy(uint8_t *dst) +{ + if (!dst) { + return -1; + } + + int res; + uint8_t ble_addr[BLE_ADDR_SIZE]; + + res = ble_addr_cpy_to(ble_addr); + if (res) { + return -1; + } + + return ble_addr_to_eui64(dst, ble_addr); +} diff --git a/arch/cpu/cc13xx-cc26xx/dev/ble-addr.h b/arch/cpu/cc13xx-cc26xx/dev/ble-addr.h new file mode 100644 index 000000000..7e9853633 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/dev/ble-addr.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2016, Michael Spoerk + * 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. + * + */ +/** + * \file + * Driver for the retrieval of an BLE address from flash + * + * \author + * Michael Spoerk + */ +/*---------------------------------------------------------------------------*/ +#ifndef BLE_ADDR_H_ +#define BLE_ADDR_H_ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" + +#include +/*---------------------------------------------------------------------------*/ +/** + * \brief Copy the node's factory BLE address to a destination memory area + * \param dst A pointer to the destination area where the BLE address is to be + * written + * \return 0 : Returned successfully + * -1 : Returned with error + * + * This function will copy 6 bytes and it will invert byte order in + * the process. The factory address on devices is normally little-endian, + * therefore you should expect dst to store the address in a big-endian order. + */ +int ble_addr_cpy(uint8_t *dst); +/*---------------------------------------------------------------------------*/ +/** + * \brief Copy the node's BLE address to a destination memory area and converts + * it into a EUI64 address in the process + * \param dst A pointer to the destination area where the EUI64 address is to be + * written + * \param src A pointer to the BLE address that is to be copied + * \return 0 : Returned successfully + * -1 : Returned with error + */ +int ble_addr_to_eui64(uint8_t *dst, uint8_t *src); +/*---------------------------------------------------------------------------*/ +/** + * \brief Copy the node's EUI64 address that is based on its factory BLE address + * to a destination memory area + * \param dst A pointer to the destination area where the EUI64 address is to be + * written + * \return 0 : Returned successfully + * -1 : Returned with error + */ +int ble_addr_to_eui64_cpy(uint8_t *dst); +/*---------------------------------------------------------------------------*/ +#endif /* BLE_ADDR_H_ */ +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/dev/ieee-addr.c b/arch/cpu/cc13xx-cc26xx/dev/ieee-addr.c index b28d7ab9c..69dbba695 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/ieee-addr.c +++ b/arch/cpu/cc13xx-cc26xx/dev/ieee-addr.c @@ -39,6 +39,7 @@ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "net/linkaddr.h" + #include "ieee-addr.h" /*---------------------------------------------------------------------------*/ #include @@ -50,49 +51,60 @@ #include /*---------------------------------------------------------------------------*/ #define IEEE_MAC_PRIMARY_ADDRESS (FCFG1_BASE + FCFG1_O_MAC_15_4_0) -#define IEEE_MAC_SECONDARY_ADDRESS (CCFG_BASE + CCFG_O_IEEE_MAC_0) +#define IEEE_MAC_SECONDARY_ADDRESS (CCFG_BASE + CCFG_O_IEEE_MAC_0) /*---------------------------------------------------------------------------*/ -void +#define IEEE_ADDR_SIZE 8 +/*---------------------------------------------------------------------------*/ +int ieee_addr_cpy_to(uint8_t *dst, uint8_t len) { - if(IEEE_ADDR_CONF_HARDCODED) { - uint8_t ieee_addr_hc[8] = IEEE_ADDR_CONF_ADDRESS; + if (len > IEEE_ADDR_SIZE) { + return -1; + } - memcpy(dst, &ieee_addr_hc[8 - len], len); + if(IEEE_ADDR_CONF_HARDCODED) { + const uint8_t ieee_addr_hc[IEEE_ADDR_SIZE] = IEEE_ADDR_CONF_ADDRESS; + + memcpy(dst, &ieee_addr_hc[IEEE_ADDR_SIZE - len], len); } else { int i; + const uint8_t * const primary = (uint8_t *)IEEE_MAC_PRIMARY_ADDRESS; + const uint8_t * const secondary = (uint8_t *)IEEE_MAC_SECONDARY_ADDRESS; + /* Reading from primary location... */ - const uint8_t *location = (uint8_t *)IEEE_MAC_PRIMARY_ADDRESS; + const uint8_t *ieee_addr = primary; /* * ...unless we can find a byte != 0xFF in secondary * * Intentionally checking all 8 bytes here instead of len, because we - * are checking validity of the entire IEEE address irrespective of the + * are checking validity of the entire address irrespective of the * actual number of bytes the caller wants to copy over. */ - for(i = 0; i < 8; i++) { - if(((uint8_t *)IEEE_MAC_SECONDARY_ADDRESS)[i] != 0xFF) { + for(i = 0; i < IEEE_ADDR_SIZE; i++) { + if(HWREG(secondary + i) != 0xFF) { /* A byte in the secondary location is not 0xFF. Use the secondary */ - location = (uint8_t *)IEEE_MAC_SECONDARY_ADDRESS; + ieee_addr = secondary; break; } } /* - * We have chosen what address to read the IEEE address from. Do so, + * We have chosen what address to read the address from. Do so, * inverting byte order */ for(i = 0; i < len; i++) { - dst[i] = location[len - 1 - i]; + dst[i] = HWREG(ieee_addr + len - 1 - i); } } -#if IEEE_ADDR_NODE_ID - dst[len - 1] = IEEE_ADDR_NODE_ID & 0xFF; - dst[len - 2] = IEEE_ADDR_NODE_ID >> 8; +#ifdef IEEE_ADDR_NODE_ID + dst[len - 1] = (IEEE_ADDR_NODE_ID >> 0) & 0xFF; + dst[len - 2] = (IEEE_ADDR_NODE_ID >> 8) & 0xFF; #endif + + return 0; } /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/ieee-addr.h b/arch/cpu/cc13xx-cc26xx/dev/ieee-addr.h index 87d07d7e6..167b75623 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/ieee-addr.h +++ b/arch/cpu/cc13xx-cc26xx/dev/ieee-addr.h @@ -65,37 +65,20 @@ #define IEEE_ADDR_H_ /*---------------------------------------------------------------------------*/ #include "contiki.h" - -#include -/*---------------------------------------------------------------------------*/ -/** - * \name IEEE address locations - * - * The address of the secondary location can be configured by the platform - * or example - * - * @{ - */ -#define IEEE_ADDR_LOCATION_PRIMARY 0x500012F0 /**< Primary IEEE address location */ - -#ifdef IEEE_ADDR_CONF_LOCATION_SECONDARY -#define IEEE_ADDR_LOCATION_SECONDARY IEEE_ADDR_CONF_LOCATION_SECONDARY -#else -#define IEEE_ADDR_LOCATION_SECONDARY 0x00057FC8 /**< Secondary IEEE address location */ -#endif -/** @} */ /*---------------------------------------------------------------------------*/ /** * \brief Copy the node's IEEE address to a destination memory area * \param dst A pointer to the destination area where the IEEE address is to be * written * \param len The number of bytes to write to destination area + * \return 0 : Returned successfully + * -1 : Returned with error * * This function will copy \e len LS bytes and it will invert byte order in * the process. The factory address on devices is normally little-endian, * therefore you should expect dst to store the address in a big-endian order. */ -void ieee_addr_cpy_to(uint8_t *dst, uint8_t len); +int ieee_addr_cpy_to(uint8_t *dst, uint8_t len); /*---------------------------------------------------------------------------*/ #endif /* IEEE_ADDR_H_ */ /*---------------------------------------------------------------------------*/ From f307794b39c8431b6d90154d80dea1f0da39f3df Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Mon, 9 Jul 2018 20:13:01 +0200 Subject: [PATCH 261/485] Reworked RF driver into scheduler --- arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 8 +- arch/cpu/cc13xx-cc26xx/dev/ble-addr.c | 2 +- arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h | 3 + arch/cpu/cc13xx-cc26xx/dev/ieee-addr.c | 10 +- arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.c | 474 ++++++++++++++++++ arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.h | 131 +++++ arch/cpu/cc13xx-cc26xx/dev/rf-common.c | 76 --- arch/cpu/cc13xx-cc26xx/dev/rf-core.c | 437 ++++++++++++++++ .../dev/{rf-common.h => rf-core.h} | 37 +- arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c | 433 +++++++--------- arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c | 445 ++++++---------- .../rf-settings/cc13x0/ble-settings.c | 30 +- .../rf-settings/cc13x0/ble-settings.h | 4 +- .../rf-settings/cc13x2/ble-settings.c | 279 ++++------- .../rf-settings/cc13x2/ble-settings.h | 84 ++-- .../rf-settings/netstack-settings.h | 97 ++++ .../simplelink/cc13xx-cc26xx/platform.c | 2 +- 17 files changed, 1694 insertions(+), 858 deletions(-) create mode 100644 arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.c create mode 100644 arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.h delete mode 100644 arch/cpu/cc13xx-cc26xx/dev/rf-common.c create mode 100644 arch/cpu/cc13xx-cc26xx/dev/rf-core.c rename arch/cpu/cc13xx-cc26xx/dev/{rf-common.h => rf-core.h} (68%) create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/netstack-settings.h diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index 686ebb556..a0f4c688c 100644 --- a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -76,7 +76,7 @@ CONTIKI_CPU_SOURCEFILES += int-master-arch.c ### RF source files CONTIKI_CPU_SOURCEFILES += rf-core.c CONTIKI_CPU_SOURCEFILES += ieee-addr.c ble-addr.c -CONTIKI_CPU_SOURCEFILES += rf-ble-beacon.c +#CONTIKI_CPU_SOURCEFILES += rf-ble-beacond.c ifeq ($(SUPPORTS_PROP_MODE),1) CONTIKI_CPU_SOURCEFILES += rf-prop-mode.c prop-settings.c @@ -87,14 +87,16 @@ CONTIKI_CPU_SOURCEFILES += rf-ieee-mode.c ieee-settings.c endif ifeq ($(SUPPORTS_BLE_BEACON),1) -CONTIKI_CPU_SOURCEFILES += rf-ble-beacond.c ble-settings.c +CONTIKI_CPU_SOURCEFILES += ble-settings.c +#CONTIKI_CPU_SOURCEFILES += rf-ble-beacond.c endif ### CPU-dependent debug source files MODULES += os/lib/dbg-io ### CPU-dependent directories -CONTIKI_CPU_DIRS += . dev $(SUBFAMILY) rf-settings/$(DEVICE_FAMILY_LC) +CONTIKI_CPU_DIRS += . dev $(SUBFAMILY) +CONTIKI_CPU_DIRS += rf-settings rf-settings/$(DEVICE_FAMILY_LC) CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES) $(DEBUG_IO_SOURCEFILES) diff --git a/arch/cpu/cc13xx-cc26xx/dev/ble-addr.c b/arch/cpu/cc13xx-cc26xx/dev/ble-addr.c index c61c3af95..f6343367c 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/ble-addr.c +++ b/arch/cpu/cc13xx-cc26xx/dev/ble-addr.c @@ -119,7 +119,7 @@ ble_addr_to_eui64_cpy(uint8_t *dst) int res; uint8_t ble_addr[BLE_ADDR_SIZE]; - res = ble_addr_cpy_to(ble_addr); + res = ble_addr_cpy(ble_addr); if (res) { return -1; } diff --git a/arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h b/arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h index 9e9ae696d..f46a7401c 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h +++ b/arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h @@ -121,6 +121,9 @@ # error The selected IEEE 802.15.4g frequency band is not supported #endif /*---------------------------------------------------------------------------*/ +#define DOT_15_4_G_CHANNEL_IN_RANGE(channel) \ + (((channel) >= 0) && ((channel) <= DOT_15_4G_CHANNEL_MAX)) +/*---------------------------------------------------------------------------*/ #endif /* DOT_15_4G_H_ */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/cpu/cc13xx-cc26xx/dev/ieee-addr.c b/arch/cpu/cc13xx-cc26xx/dev/ieee-addr.c index 69dbba695..3d9b4c9f8 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/ieee-addr.c +++ b/arch/cpu/cc13xx-cc26xx/dev/ieee-addr.c @@ -69,11 +69,11 @@ ieee_addr_cpy_to(uint8_t *dst, uint8_t len) } else { int i; - const uint8_t * const primary = (uint8_t *)IEEE_MAC_PRIMARY_ADDRESS; - const uint8_t * const secondary = (uint8_t *)IEEE_MAC_SECONDARY_ADDRESS; + volatile const uint8_t * const primary = (uint8_t *)IEEE_MAC_PRIMARY_ADDRESS; + volatile const uint8_t * const secondary = (uint8_t *)IEEE_MAC_SECONDARY_ADDRESS; /* Reading from primary location... */ - const uint8_t *ieee_addr = primary; + volatile const uint8_t *ieee_addr = primary; /* * ...unless we can find a byte != 0xFF in secondary @@ -83,7 +83,7 @@ ieee_addr_cpy_to(uint8_t *dst, uint8_t len) * actual number of bytes the caller wants to copy over. */ for(i = 0; i < IEEE_ADDR_SIZE; i++) { - if(HWREG(secondary + i) != 0xFF) { + if(secondary[i] != 0xFF) { /* A byte in the secondary location is not 0xFF. Use the secondary */ ieee_addr = secondary; break; @@ -95,7 +95,7 @@ ieee_addr_cpy_to(uint8_t *dst, uint8_t len) * inverting byte order */ for(i = 0; i < len; i++) { - dst[i] = HWREG(ieee_addr + len - 1 - i); + dst[i] = ieee_addr[len - 1 - i]; } } diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.c b/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.c new file mode 100644 index 000000000..25d14190a --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.c @@ -0,0 +1,474 @@ +/* + * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2017, 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 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup rf-core-ble + * @{ + * + * \file + * Implementation of the CC13xx/CC26xx RF BLE driver + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "sys/process.h" +#include "sys/clock.h" +#include "sys/cc.h" +#include "sys/etimer.h" +#include "net/netstack.h" +#include "net/linkaddr.h" + +#include "netstack-settings.h" +/*---------------------------------------------------------------------------*/ +#include +#include DeviceFamily_constructPath(driverlib/chipinfo.h) +#include DeviceFamily_constructPath(driverlib/rf_ble_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) + +#include +#include +/*---------------------------------------------------------------------------*/ +#include +#include +#include +#include +/*---------------------------------------------------------------------------*/ +#define DEBUG 0 +#if DEBUG +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif +/*---------------------------------------------------------------------------*/ +#if RF_BLE_BEACOND_ENABLED +/*---------------------------------------------------------------------------*/ +rf_ble_beacond_result_e +rf_ble_beacond_config(clock_time_t interval, const char *name) +{ + return RF_BLE_BEACOND_DISABLED; +} +/*---------------------------------------------------------------------------*/ +rf_ble_beacond_result_e +rf_ble_beacond_start(void) +{ + return RF_BLE_BEACOND_DISABLED; +} +/*---------------------------------------------------------------------------*/ +rf_ble_beacond_result_e rf_ble_beacond_stop(void) +{ + return RF_BLE_BEACOND_DISABLED; +} +/*---------------------------------------------------------------------------*/ +uint8_t +rf_ble_is_active(void) +{ + return 0; +} +/*---------------------------------------------------------------------------*/ +rf_ble_beacond_result_e +rf_ble_set_tx_power(radio_value_t power) +{ + return RF_BLE_BEACOND_DISABLED; +} +/*---------------------------------------------------------------------------*/ +radio_value_t +rf_ble_get_tx_power(void); +{ + return (radio_value_t)0; +} +/*---------------------------------------------------------------------------*/ +#else /* RF_BLE_BEACOND_ENABLED */ +/*---------------------------------------------------------------------------*/ +/* BLE Advertisement channels. Not to be changed by the user. */ +typedef enum { + BLE_ADV_CHANNEL_37 = (1 << 0), + BLE_ADV_CHANNEL_38 = (1 << 1), + BLE_ADV_CHANNEL_39 = (1 << 2), + + BLE_ADV_CHANNEL_MASK = BLE_ADV_CHANNEL_37 + | BLE_ADV_CHANNEL_38 + | BLE_ADV_CHANNEL_39, +} ble_adv_channel_e; +/*---------------------------------------------------------------------------*/ +/* Maximum BLE advertisement size. Not to be changed by the user. */ +#define BLE_ADV_MAX_SIZE 31 +/*---------------------------------------------------------------------------*/ +/* BLE Intervals: Send a burst of advertisements every BLE_ADV_INTERVAL secs */ +#define BLE_ADV_INTERVAL (CLOCK_SECOND * 5) +#define BLE_ADV_DUTY_CYCLE (CLOCK_SECOND / 10) +#define BLE_ADV_MESSAGES 10 + +/* BLE Advertisement-related macros */ +#define BLE_ADV_TYPE_DEVINFO 0x01 +#define BLE_ADV_TYPE_NAME 0x09 +#define BLE_ADV_TYPE_MANUFACTURER 0xFF +#define BLE_ADV_NAME_BUF_LEN BLE_ADV_MAX_SIZE +#define BLE_ADV_PAYLOAD_BUF_LEN 64 +#define BLE_UUID_SIZE 16 +/*---------------------------------------------------------------------------*/ +typedef struct { + /* Outgoing frame buffer */ + uint8_t tx_buf[BLE_ADV_PAYLOAD_BUF_LEN] CC_ALIGN(4); + uint8_t ble_params_buf[32] CC_ALIGN(4); + + /* Config data */ + size_t adv_name_len; + char adv_name[BLE_ADV_NAME_BUF_LEN]; + + /* Indicates whether deamon is active or not */ + bool is_active; + + /* Periodic timer for sending out BLE advertisements */ + clock_time_t ble_adv_interval; + struct etimer ble_adv_et + + /* RF driver */ + RF_Object rf_object; + RF_Handle rf_handle; +} ble_beacond_t; + +static ble_beacond_t ble_beacond; +/*---------------------------------------------------------------------------*/ +/* Configuration for TX power table */ +#ifdef BLE_MODE_CONF_TX_POWER_TABLE +# define TX_POWER_TABLE BLE_MODE_CONF_TX_POWER_TABLE +#else +# define TX_POWER_TABLE rf_ble_tx_power_table +#endif + +#ifdef BLE_MODE_CONF_TX_POWER_TABLE_SIZE +# define TX_POWER_TABLE_SIZE BLE_MODE_CONF_TX_POWER_TABLE_SIZE +#else +# define TX_POWER_TABLE_SIZE RF_BLE_TX_POWER_TABLE_SIZE +#endif + +/* TX power table convenience macros */ +#define TX_POWER_MIN (TX_POWER_TABLE[0].power) +#define TX_POWER_MAX (TX_POWER_TABLE[TX_POWER_TABLE_SIZE - 1].power) + +#define TX_POWER_IN_RANGE(dbm) (((dbm) >= TX_POWER_MIN) && ((dbm) <= TX_POWER_MAX)) +/*---------------------------------------------------------------------------*/ +PROCESS(ble_beacon_process, "CC13xx / CC26xx RF BLE Beacon Process"); +/*---------------------------------------------------------------------------*/ +static int +send_ble_adv_nc(int channel, uint8_t *adv_payload, int adv_payload_len) +{ + uint32_t cmd_status; + rfc_CMD_BLE_ADV_NC_t cmd; + rfc_bleAdvPar_t *params; + + params = (rfc_bleAdvPar_t *)ble_params_buf; + + /* Clear both buffers */ + memset(&cmd, 0x00, sizeof(cmd)); + memset(ble_params_buf, 0x00, sizeof(ble_params_buf)); + + /* Adv NC */ + cmd.commandNo = CMD_BLE_ADV_NC; + cmd.condition.rule = COND_NEVER; + cmd.whitening.bOverride = 0; + cmd.whitening.init = 0; + cmd.pParams = params; + cmd.channel = channel; + + /* Set up BLE Advertisement parameters */ + params->pDeviceAddress = (uint16_t *)BLE_ADDRESS_PTR; + params->endTrigger.triggerType = TRIG_NEVER; + params->endTime = TRIG_NEVER; + + /* Set up BLE Advertisement parameters */ + params = (rfc_bleAdvPar_t *)ble_params_buf; + params->advLen = adv_payload_len; + params->pAdvData = adv_payload; + + if(rf_core_send_cmd((uint32_t)&cmd, &cmd_status) == RF_CORE_CMD_ERROR) { + PRINTF("send_ble_adv_nc: Chan=%d CMDSTA=0x%08lx, status=0x%04x\n", + channel, cmd_status, cmd.status); + return RF_CORE_CMD_ERROR; + } + + /* Wait until the command is done */ + if(rf_core_wait_cmd_done(&cmd) != RF_CORE_CMD_OK) { + PRINTF("send_ble_adv_nc: Chan=%d CMDSTA=0x%08lx, status=0x%04x\n", + channel, cmd_status, cmd.status); + return RF_CORE_CMD_ERROR; + } + + return RF_CORE_CMD_OK; +} +/*---------------------------------------------------------------------------*/ +rf_ble_beacond_result_e +rf_ble_beacond_config(clock_time_t interval, const char *name) +{ + if(name != NULL) { + const size_t name_len = strlen(name); + if(name_len == 0 || name_len >= BLE_ADV_NAME_BUF_LEN) { + return RF_BLE_BEACOND_ERROR; + } + + /* name_len + 1 for zero termination char */ + ble_beacond_cfg.adv_name_len = name_len + 1; + memcpy(ble_beacond_cfg.adv_name, name, name_len + 1); + } + + if(interval != 0) { + ble_beacond_cfg.ble_adv_interval = interval; + } + + return RF_BLE_BEACOND_OK; +} +/*---------------------------------------------------------------------------*/ +rf_ble_beacond_result_e +rf_ble_beacond_start(void) +{ + /* Check if RF handle has already been opened */ + if (ble_beacond.rf_handle != NULL) { + return RF_BLE_BEACOND_OK; + } + + /* Sanity check of Beacond config */ + if(beacond_config.adv_name_len == 0) { + return RF_BLE_BEACOND_ERROR; + } + + /* Open RF handle */ + RF_Params rf_params; + RF_Params_init(&rf_params); + + ble_beacond.rf_handle = RF_open(&ble_beacond.rf_object, &rf_ble_mode, + (RF_RadioSetup*)&rf_cmd_ieee_radio_setup, &rf_params); + + if (ble_beacond.rf_handle == NULL) { + PRINTF("init: unable to open BLE RF driver\n"); + return RF_BLE_BEACOND_ERROR; + } + + ble_beacond.is_active = false; + + process_start(&ble_beacon_process, NULL); + + return RF_BLE_BEACOND_OK; +} +/*---------------------------------------------------------------------------*/ +rf_ble_beacond_result_e +rf_ble_beacond_stop() +{ + if (ble_beacond.rf_handle == NULL) { + return RF_BLE_BEACOND_OK; + } + + /* Force abort of any ongoing RF operation */ + RF_flushCmd(ieee_radio.rf_handle, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY); + RF_close(ble_beacond.rf_handle); + + ble_beacond.rf_handle = NULL; + + process_exit(&ble_beacon_process); + + return RF_BLE_BEACOND_OK; +} +/*---------------------------------------------------------------------------*/ +uint8_t +rf_ble_is_active() +{ + return ble_beacon_on; +} +/*---------------------------------------------------------------------------*/ +rf_ble_beacond_result_e +rf_ble_set_tx_power(radio_value_t dBm) +{ + if (!TX_POWER_IN_RANGE(dBm)) { + return RADIO_RESULT_INVALID_VALUE; + } + + const RF_Stat stat = RF_setTxPower( + ble_beacond.rf_handle, + RF_TxPowerTable_findValue(TX_POWER_TABLE, (int8_t)dBm) + ); + + return (stat == RF_StatSuccess) + ? RF_BLE_BEACOND_OK + : RF_BLE_BEACOND_ERROR; +} +/*---------------------------------------------------------------------------*/ +radio_value_t +rf_ble_get_tx_power(void) +{ + return (radio_value_t)RF_TxPowerTable_findPowerLevel( + TX_POWER_TABLE, + RF_getTxPower(ble_beacond.rf_handle) + ); +} +/*---------------------------------------------------------------------------*/ +static rf_ble_beacond_result_e +rf_ble_beacon_single(uint8_t channel, uint8_t *data, uint8_t len) +{ + uint32_t cmd_status; + bool interrupts_disabled; + uint8_t j, channel_selected; + uint8_t was_on; + + /* Adhere to the maximum BLE advertisement payload size */ + if(len > BLE_ADV_NAME_BUF_LEN) { + len = BLE_ADV_NAME_BUF_LEN; + } + + /* + * Under ContikiMAC, some IEEE-related operations will be called from an + * interrupt context. We need those to see that we are in BLE mode. + */ + const uintptr_t key = HwiP_disable(); + + /* + * First, determine our state: + * + * If we are running CSMA, we are likely in IEEE RX mode. We need to + * abort the IEEE BG Op before entering BLE mode. + * If we are ContikiMAC, we are likely off, in which case we need to + * boot the CPE before entering BLE mode + */ + was_on = rf_core_is_accessible(); + + if(was_on) { + /* + * We were on: If we are in the process of receiving a frame, abort the + * BLE beacon burst. Otherwise, terminate the primary radio Op so we + * can switch to BLE mode + */ + if(NETSTACK_RADIO.receiving_packet()) { + PRINTF("rf_ble_beacon_single: We were receiving\n"); + + /* Abort this pass */ + return; + } + + rf_core_primary_mode_abort(); + } else { + + oscillators_request_hf_xosc(); + + /* We were off: Boot the CPE */ + if(rf_core_boot() != RF_CORE_CMD_OK) { + /* Abort this pass */ + PRINTF("rf_ble_beacon_single: rf_core_boot() failed\n"); + return; + } + + oscillators_switch_to_hf_xosc(); + + /* Enter BLE mode */ + if(rf_radio_setup() != RF_CORE_CMD_OK) { + /* Continue so we can at least try to restore our previous state */ + PRINTF("rf_ble_beacon_single: Error entering BLE mode\n"); + } else { + + for(j = 0; j < 3; j++) { + channel_selected = (channel >> j) & 0x01; + if(channel_selected == 1) { + if(send_ble_adv_nc(37 + j, data, len) != RF_CORE_CMD_OK) { + /* Continue... */ + PRINTF("rf_ble_beacon_single: Channel=%d, " + "Error advertising\n", 37 + j); + } + } + } + } + + /* Send a CMD_STOP command to RF Core */ + if(rf_core_send_cmd(CMDR_DIR_CMD(CMD_STOP), &cmd_status) != RF_CORE_CMD_OK) { + /* Continue... */ + PRINTF("rf_ble_beacon_single: status=0x%08lx\n", cmd_status); + } + + if(was_on) { + /* We were on, go back to previous primary mode */ + rf_core_primary_mode_restore(); + } else { + /* We were off. Shut back off */ + rf_core_power_down(); + + /* Switch HF clock source to the RCOSC to preserve power */ + oscillators_switch_to_hf_rc(); + } + } + + HwiP_restore(key); +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(ble_beacon_process, ev, data) +{ + static size_t i; + static size_t p; + + PROCESS_BEGIN(); + + while(1) { + etimer_set(&beacond_config.ble_adv_et, beacond_config.ble_adv_interval); + + PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&ble_adv_et) || + (ev == PROCESS_EVENT_EXIT)); + + if(ev == PROCESS_EVENT_EXIT) { + PROCESS_EXIT(); + } + + /* Set the adv payload each pass: The device name may have changed */ + p = 0; + + /* device info */ + payload[p++] = (uint8_t)0x02; /* 2 bytes */ + payload[p++] = (uint8_t)BLE_ADV_TYPE_DEVINFO; + payload[p++] = (uint8_t)0x1a; /* LE general discoverable + BR/EDR */ + payload[p++] = (uint8_t)beacond_config.adv_name_len; + payload[p++] = (uint8_t)BLE_ADV_TYPE_NAME; + memcpy(payload + p, beacond_config.adv_name, beacond_config.adv_name_len); + p += beacond_config.adv_name_len; + + /* + * Send BLE_ADV_MESSAGES beacon bursts. Each burst on all three + * channels, with a BLE_ADV_DUTY_CYCLE interval between bursts + */ + rf_ble_beacon_single(BLE_ADV_CHANNEL_ALL, payload, p); + for(i = 1; i < BLE_ADV_MESSAGES; i++) { + etimer_set(&beacond_config.ble_adv_et, BLE_ADV_DUTY_CYCLE); + PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&ble_adv_et)); + + rf_ble_beacon_single(BLE_ADV_CHANNEL_ALL, payload, p); + } + } + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +#endif /* RF_BLE_BEACOND_ENABLED */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.h b/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.h new file mode 100644 index 000000000..ddbe26fff --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2017, 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 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup rf-core + * @{ + * + * \defgroup rf-core-ble CC13xx/CC26xx BLE driver + * + * @{ + * + * \file + * Header file for the CC13xx/CC26xx BLE driver + */ +/*---------------------------------------------------------------------------*/ +#ifndef RF_BLE_BEACOND_H_ +#define RF_BLE_BEACOND_H_ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" + +#include +/*---------------------------------------------------------------------------*/ +#ifdef RF_BLE_BEACON_CONF_ENABLED +#define RF_BLE_BEACON_ENABLED RF_BLE_BEACON_CONF_ENABLED +#else +#define RF_BLE_BEACON_ENABLED 1 +#endif +/*---------------------------------------------------------------------------*/ +typedef enum { + RF_BLE_BEACOND_OK, + RF_BLE_BEACOND_ERROR, + RF_BLE_BEACOND_DISABLED, +} rf_ble_beacond_result_e; +/** + * \brief Set the device name to use with the BLE advertisement/beacon daemon + * \param interval The interval (ticks) between two consecutive beacon bursts + * \param name The device name to advertise + * + * If name is NULL it will be ignored. If interval==0 it will be ignored. Thus, + * this function can be used to configure a single parameter at a time if so + * desired. + */ +rf_ble_beacond_result_e rf_ble_beacond_config(clock_time_t interval, const char *name); + +/** + * \brief Start the BLE advertisement/beacon daemon + * \return RF_CORE_CMD_OK: Success, RF_CORE_CMD_ERROR: Failure + * + * Before calling this function, the name to advertise must first be set by + * calling rf_ble_beacond_config(). Otherwise, this function will return an + * error. + */ +rf_ble_beacond_result_e rf_ble_beacond_start(void); + +/** + * \brief Stop the BLE advertisement/beacon daemon + */ +rf_ble_beacond_result_e rf_ble_beacond_stop(void); + +/** + * \brief Check whether the BLE beacond is currently active + * \retval 1 The radio is in BLE mode + * \retval 0 The BLE daemon is not active, or disabled + */ +uint8_t rf_ble_is_active(void); + +/** + * \brief Set TX power for BLE advertisements + * \param dBm The 'at least' TX power in dBm, values avove 5 dBm will be ignored + * + * Set TX power to 'at least' power dBm. + * This works with a lookup table. If the value of 'power' does not exist in + * the lookup table, TXPOWER will be set to the immediately higher available + * value + */ +rf_ble_beacond_result_e rf_ble_set_tx_power(radio_value_t dBm); + +/** + * \brief Get TX power for BLE advertisements + * \return The TX power for BLE advertisements + */ +radio_value_t rf_ble_get_tx_power(void); + +/** + * \brief Transmit a single BLE advertisement in one or more advertisement channels + * \param channel Bitmask of advertisement channels to be used: use + * BLE_ADV_CHANNEL_37 for channel 37, BLE_ADV_CHANNEL_38 for channel 38, + * BLE_ADV_CHANNEL_39 for channel 39, or any 'or' combination of those + * \param data A pointer to the advertisement data buffer + * \param len The length of the advertisement data. If more than BLE_ADV_MAX_SIZE, + * the first BLE_ADV_MAX_SIZE bytes will be used. + * + * Transmits a given advertisement payload once in one or any arbitrary combination + * of advertisement channels. + */ +rf_ble_beacond_result_e rf_ble_beacon_single(uint8_t channel, uint8_t *data, uint8_t len); +/*---------------------------------------------------------------------------*/ +#endif /* RF_BLE_BEACOND_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-common.c b/arch/cpu/cc13xx-cc26xx/dev/rf-common.c deleted file mode 100644 index 92339e1ab..000000000 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-common.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/*---------------------------------------------------------------------------*/ -/** - * \addtogroup simplelink - * @{ - * - * \file - * Implementation of common CC13xx/CC26xx RF functionality - */ -/*---------------------------------------------------------------------------*/ -#include -#include -#include -#include -#include -#include -/*---------------------------------------------------------------------------*/ -/* Log configuration */ -#include "sys/log.h" -#define LOG_MODULE "RF" -#define LOG_LEVEL LOG_LEVEL_DBG -/*---------------------------------------------------------------------------*/ -PROCESS(rf_process, "SimpleLink RF Process"); -/*---------------------------------------------------------------------------*/ -PROCESS_THREAD(rf_process, ev, data) -{ - int len; - - PROCESS_BEGIN(); - - while(1) { - PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL); - do { - //watchdog_periodic(); - packetbuf_clear(); - len = NETSTACK_RADIO.read(packetbuf_dataptr(), PACKETBUF_SIZE); - - if(len > 0) { - packetbuf_set_datalen(len); - - NETSTACK_MAC.input(); - } - } while(len > 0); - } - PROCESS_END(); -} -/*---------------------------------------------------------------------------*/ -/** @} */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-core.c b/arch/cpu/cc13xx-cc26xx/dev/rf-core.c new file mode 100644 index 000000000..17a8919f7 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-core.c @@ -0,0 +1,437 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup simplelink + * @{ + * + * \file + * Implementation of common CC13xx/CC26xx RF functionality + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "dev/watchdog.h" +#include "sys/cc.h" +#include "sys/process.h" +#include "sys/energest.h" +#include "net/netstack.h" +#include "net/packetbuf.h" +#include "net/mac/mac.h" + +#include "rf-core.h" +/*---------------------------------------------------------------------------*/ +#include +#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) + +#include +/*---------------------------------------------------------------------------*/ +#include "netstack-settings.h" +/*---------------------------------------------------------------------------*/ +#include +#include +#include +/*---------------------------------------------------------------------------*/ +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "RF Core" +#define LOG_LEVEL LOG_LEVEL_DBG +/*---------------------------------------------------------------------------*/ +#ifdef NDEBUG +# define PRINTF(...) +#else +# define PRINTF(...) printf(__VA_ARGS__) +#endif +/*---------------------------------------------------------------------------*/ +#define CMD_FS_RETRIES 3 + +#define RF_EVENTS_CMD_DONE (RF_EventCmdDone | RF_EventLastCmdDone | \ + RF_EventFGCmdDone | RF_EventLastFGCmdDone) + +#define CMD_STATUS(cmd) (CC_ACCESS_NOW(RF_Op, cmd).status) + +#define CMD_HANDLE_OK(handle) (((handle) != RF_ALLOC_ERROR) && \ + ((handle) != RF_SCHEDULE_CMD_ERROR)) + +#define EVENTS_CMD_DONE(events) (((events) & RF_EVENTS_CMD_DONE) != 0) +/*---------------------------------------------------------------------------*/ +static RF_Object rf_netstack; +static RF_Object rf_ble; + +typedef struct { + RF_CmdHandle handle; + RF_Callback cb; + RF_EventMask bm_event; +} rf_cmd_t; + +static rf_cmd_t netstack_rx; +/*---------------------------------------------------------------------------*/ +static inline bool +cmd_rx_is_active(void) +{ + /* + * Active in this case means RX command is either running to be running, + * that is ACTIVE for running or PENDING for to be running. + */ + const uint16_t status = CMD_STATUS(netstack_cmd_rx); + return (status == ACTIVE) || + (status == PENDING); +} +/*---------------------------------------------------------------------------*/ +static uint_fast8_t +cmd_rx_disable(void) +{ + const bool is_active = cmd_rx_is_active(); + + if (is_active) { + CMD_STATUS(netstack_cmd_rx) = DONE_STOPPED; + RF_cancelCmd(&rf_netstack, netstack_rx.handle, RF_ABORT_GRACEFULLY); + netstack_rx.handle = 0; + } + + return (uint_fast8_t)is_active; +} +/*---------------------------------------------------------------------------*/ +static rf_result_t +cmd_rx_restore(uint_fast8_t rx_key) +{ + const bool was_active = (rx_key != 0) ? true : false; + + if (!was_active) { + return RF_RESULT_OK; + } + + RF_ScheduleCmdParams sched_params; + RF_ScheduleCmdParams_init(&sched_params); + + sched_params.priority = RF_PriorityNormal; + sched_params.endTime = 0; + sched_params.allowDelay = RF_AllowDelayAny; + + CMD_STATUS(netstack_cmd_rx) = PENDING; + + netstack_rx.handle = RF_scheduleCmd(&rf_netstack, + (RF_Op*)&netstack_cmd_rx, + &sched_params, + netstack_rx.cb, + netstack_rx.bm_event + ); + + if (!CMD_HANDLE_OK(netstack_rx.handle)) { + PRINTF("cmd_rx_restore: unable to schedule RX command handle=%d status=0x%04x", + netstack_rx.handle, CMD_STATUS(netstack_cmd_rx)); + return RF_RESULT_ERROR; + } + + return RF_RESULT_OK; +} +/*---------------------------------------------------------------------------*/ +rf_result_t +rf_yield(void) +{ + /* Force abort of any ongoing RF operation */ + RF_flushCmd(&rf_netstack, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY); + RF_flushCmd(&rf_ble, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY); + + /* Trigger a manual power-down */ + RF_yield(&rf_netstack); + RF_yield(&rf_ble); + + ENERGEST_OFF(ENERGEST_TYPE_LISTEN); + + return RF_RESULT_OK; +} +/*---------------------------------------------------------------------------*/ +rf_result_t +rf_set_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8_t dbm) +{ + const RF_Stat stat = RF_setTxPower(handle, + RF_TxPowerTable_findValue(table, dbm) + ); + + return (stat == RF_StatSuccess) + ? RF_RESULT_OK + : RF_RESULT_ERROR; +} +/*---------------------------------------------------------------------------*/ +rf_result_t +rf_get_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8_t *dbm) +{ + *dbm = RF_TxPowerTable_findPowerLevel(table, + RF_getTxPower(handle) + ); + + return (*dbm != RF_TxPowerTable_INVALID_DBM) + ? RF_RESULT_OK + : RF_RESULT_ERROR; +} +/*---------------------------------------------------------------------------*/ +RF_Handle +netstack_open(RF_Params *params) +{ + return RF_open(&rf_netstack, &netstack_mode, (RF_RadioSetup*)&netstack_cmd_radio_setup, params); +} +/*---------------------------------------------------------------------------*/ +rf_result_t +netstack_sched_fs(void) +{ + const uint_fast8_t rx_key = cmd_rx_disable(); + + /* + * For IEEE-mode, restarting IEEE_RX recalibrates the synth by using the + * channel field in the IEEE_RX commando. It is assumed this field is + * already configured before this functions is called. + * However, if IEEE_RX wasn't active, manually calibrate the synth + * with CMD_FS. + * + * For Prop-mode, the synth is always manually calibrated with CMD_FS. + */ +#if (RF_CORE_CONF_MODE == RF_CORE_MODE_2_4_GHZ) + if (rx_key) { + cmd_rx_restore(rx_key); + return RF_RESULT_OK; + } +#endif /* RF_CORE_CONF_MODE == RF_CORE_MODE_2_4_GHZ */ + + RF_EventMask events; + bool synth_error = false; + uint8_t num_tries = 0; + + do { + CMD_STATUS(netstack_cmd_fs) = PENDING; + + events = RF_runCmd(&rf_netstack, + (RF_Op*)&netstack_cmd_fs, + RF_PriorityNormal, + NULL, + 0 + ); + + synth_error = (EVENTS_CMD_DONE(events)) + && (CMD_STATUS(netstack_cmd_fs) == ERROR_SYNTH_PROG); + + } while (synth_error && (num_tries++ < CMD_FS_RETRIES)); + + cmd_rx_restore(rx_key); + + return (CMD_STATUS(netstack_cmd_fs) == DONE_OK) + ? RF_RESULT_OK + : RF_RESULT_ERROR; +} +/*---------------------------------------------------------------------------*/ +rf_result_t +netstack_sched_tx(RF_Callback cb, RF_EventMask bm_event) +{ + RF_ScheduleCmdParams sched_params; + RF_ScheduleCmdParams_init(&sched_params); + + sched_params.priority = RF_PriorityNormal; + sched_params.endTime = 0; + sched_params.allowDelay = RF_AllowDelayAny; + + CMD_STATUS(netstack_cmd_tx) = PENDING; + + RF_CmdHandle tx_handle = RF_scheduleCmd(&rf_netstack, + (RF_Op*)&netstack_cmd_tx, + &sched_params, + cb, + bm_event + ); + + if (!CMD_HANDLE_OK(tx_handle)) { + PRINTF("netstack_sched_tx: unable to schedule TX command handle=%d status=0x%04x\n", + tx_handle, CMD_STATUS(netstack_cmd_tx)); + return RF_RESULT_ERROR; + } + + /* + * IEEE_TX can be scheduled while IEEE_RX is running, as the radio supports + * FG commandos to be scheduled while a BG commando is running. + * For Prop-mode, RX must be turned off as usual. + */ + const uint_fast8_t rx_key = (RF_CORE_CONF_MODE != RF_CORE_MODE_2_4_GHZ) + ? cmd_rx_disable() + : false; + + if (rx_key) { + ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT); + } else { + ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); + } + + /* Wait until TX operation finishes */ + RF_EventMask tx_events = RF_pendCmd(&rf_netstack, tx_handle, 0); + + if (rx_key) { + ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN); + } else { + ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); + } + + cmd_rx_restore(rx_key); + + if (!EVENTS_CMD_DONE(tx_events)) { + PRINTF("netstack_sched_tx: TX command pend error events=0x%08llx status=0x%04x\n", + tx_events, CMD_STATUS(netstack_cmd_tx)); + return RF_RESULT_ERROR; + } + + return RF_RESULT_OK; +} +/*---------------------------------------------------------------------------*/ +rf_result_t +netstack_sched_rx(RF_Callback cb, RF_EventMask bm_event) +{ + if (cmd_rx_is_active()) { + PRINTF("netstack_sched_rx: already in RX\n"); + return RF_RESULT_OK; + } + + RF_ScheduleCmdParams sched_params; + RF_ScheduleCmdParams_init(&sched_params); + + sched_params.priority = RF_PriorityNormal; + sched_params.endTime = 0; + sched_params.allowDelay = RF_AllowDelayAny; + + CMD_STATUS(netstack_cmd_rx) = PENDING; + + netstack_rx.cb = cb; + netstack_rx.bm_event = bm_event; + netstack_rx.handle = RF_scheduleCmd(&rf_netstack, + (RF_Op*)&netstack_cmd_rx, + &sched_params, + cb, + bm_event + ); + + if (!CMD_HANDLE_OK(netstack_rx.handle)) { + PRINTF("netstack_sched_rx: unable to schedule RX command handle=%d status=0x%04x\n", + netstack_rx.handle, CMD_STATUS(netstack_cmd_rx)); + return RF_RESULT_ERROR; + } + + ENERGEST_ON(ENERGEST_TYPE_LISTEN); + + return RF_RESULT_OK; +} +/*---------------------------------------------------------------------------*/ +rf_result_t +netstack_stop_rx(void) +{ + if (!cmd_rx_is_active()) { + PRINTF("netstack_stop_rx: RX not active\n"); + return RF_RESULT_OK; + } + + CMD_STATUS(netstack_cmd_rx) = DONE_STOPPED; + const RF_Stat stat = RF_cancelCmd(&rf_netstack, netstack_rx.handle, RF_ABORT_GRACEFULLY); + netstack_rx.handle = 0; + + ENERGEST_OFF(ENERGEST_TYPE_LISTEN); + + return (stat == RF_StatSuccess) + ? RF_RESULT_OK + : RF_RESULT_ERROR; +} +/*---------------------------------------------------------------------------*/ +RF_Handle +ble_open(RF_Params *params) +{ + return RF_open(&rf_ble, &ble_mode, (RF_RadioSetup*)&ble_cmd_radio_setup, params); +} +/*---------------------------------------------------------------------------*/ +rf_result_t +ble_sched_beacon(RF_Callback cb, RF_EventMask bm_event) +{ + RF_ScheduleCmdParams sched_params; + RF_ScheduleCmdParams_init(&sched_params); + + sched_params.priority = RF_PriorityNormal; + sched_params.endTime = 0; + sched_params.allowDelay = RF_AllowDelayAny; + + CMD_STATUS(ble_cmd_beacon) = PENDING; + + RF_CmdHandle beacon_handle = RF_scheduleCmd(&rf_ble, + (RF_Op*)&ble_cmd_beacon, + &sched_params, + cb, + bm_event + ); + + if (!CMD_HANDLE_OK(beacon_handle)) { + PRINTF("ble_sched_beacon: unable to schedule BLE Beacon command handle=%d status=0x%04x\n", + beacon_handle, CMD_STATUS(ble_cmd_beacon)); + return RF_RESULT_ERROR; + } + + const uint_fast8_t rx_key = cmd_rx_disable(); + + /* Wait until Beacon operation finishes */ + RF_EventMask beacon_events = RF_pendCmd(&rf_ble, beacon_handle, 0); + if (!EVENTS_CMD_DONE(beacon_events)) { + PRINTF("ble_sched_beacon: Beacon command pend error events=0x%08llx status=0x%04x\n", + beacon_events, CMD_STATUS(ble_cmd_beacon)); + + cmd_rx_restore(rx_key); + return RF_RESULT_ERROR; + } + + cmd_rx_restore(rx_key); + return RF_RESULT_OK; +} +/*---------------------------------------------------------------------------*/ +PROCESS(rf_core_process, "RF Core Process"); +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(rf_core_process, ev, data) +{ + int len; + + PROCESS_BEGIN(); + + while(1) { + PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL); + do { + //watchdog_periodic(); + packetbuf_clear(); + len = NETSTACK_RADIO.read(packetbuf_dataptr(), PACKETBUF_SIZE); + + if(len > 0) { + packetbuf_set_datalen(len); + + NETSTACK_MAC.input(); + } + } while(len > 0); + } + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-common.h b/arch/cpu/cc13xx-cc26xx/dev/rf-core.h similarity index 68% rename from arch/cpu/cc13xx-cc26xx/dev/rf-common.h rename to arch/cpu/cc13xx-cc26xx/dev/rf-core.h index f67466613..e018dfd0c 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-common.h +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-core.h @@ -40,19 +40,42 @@ * Header file of common CC13xx/CC26xx RF functionality */ /*---------------------------------------------------------------------------*/ -#ifndef RF_COMMON_H_ -#define RF_COMMON_H_ +#ifndef RF_CORE_H_ +#define RF_CORE_H_ /*---------------------------------------------------------------------------*/ #include "contiki.h" + +#include "rf-ble-beacond.h" + +#include /*---------------------------------------------------------------------------*/ typedef enum { - CMD_RESULT_ERROR = 0, - CMD_RESULT_OK = 1, -} cmd_result_t; + RF_RESULT_OK = 0, + RF_RESULT_ERROR, +} rf_result_t; /*---------------------------------------------------------------------------*/ -PROCESS_NAME(rf_process); +PROCESS_NAME(rf_core_process); /*---------------------------------------------------------------------------*/ -#endif /* RF_COMMON_H_ */ +/* Common */ +rf_result_t rf_yield(void); + +rf_result_t rf_set_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8_t dbm); +rf_result_t rf_get_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8_t *dbm); +/*---------------------------------------------------------------------------*/ +/* Netstack radio: IEEE-mode or prop-mode */ +RF_Handle netstack_open(RF_Params *params); + +rf_result_t netstack_sched_fs(void); +rf_result_t netstack_sched_tx(RF_Callback cb, RF_EventMask bm_event); +rf_result_t netstack_sched_rx(RF_Callback cb, RF_EventMask bm_event); +rf_result_t netstack_stop_rx(void); +/*---------------------------------------------------------------------------*/ +/* BLE radio: BLE Beacon Daemon */ +RF_Handle ble_open(RF_Params *params); + +rf_result_t ble_sched_beacon(RF_Callback cb, RF_EventMask bm_event); +/*---------------------------------------------------------------------------*/ +#endif /* RF_CORE_H_ */ /*---------------------------------------------------------------------------*/ /** * @} diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c index 397d24005..f902e76a5 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c @@ -64,17 +64,9 @@ #include /*---------------------------------------------------------------------------*/ /* SimpleLink Platform RF dev */ -#include "rf-common.h" #include "dot-15-4g.h" -/*---------------------------------------------------------------------------*/ -/* RF settings */ -#ifdef IEEE_MODE_CONF_RF_SETTINGS -# define IEEE_MODE_RF_SETTINGS IEEE_MODE_CONF_RF_SETTINGS -#else -# define IEEE_MODE_RF_SETTINGS "ieee-settings.h" -#endif - -#include IEEE_MODE_RF_SETTINGS +#include "rf-core.h" +#include "netstack-settings.h" /*---------------------------------------------------------------------------*/ #include #include @@ -162,6 +154,9 @@ /* How long to wait for the rx read entry to become ready */ #define TIMEOUT_DATA_ENTRY_BUSY (RTIMER_SECOND / 250) + +/* How long to wait for RX to become active after scheduled */ +#define TIMEOUT_ENTER_RX_WAIT (RTIMER_SECOND >> 10) /*---------------------------------------------------------------------------*/ #define RAT_RANGE (~(uint32_t)0) #define RAT_ONE_QUARTER (RAT_RANGE / (uint32_t)4) @@ -170,6 +165,8 @@ /* XXX: don't know what exactly is this, looks like the time to TX 3 octets */ #define RAT_TIMESTAMP_OFFSET -(USEC_TO_RAT(32 * 3) - 1) /* -95.75 usec */ /*---------------------------------------------------------------------------*/ +#define CMD_RX_EVENTS (RF_EventRxOk | RF_EventRxBufFull | RF_EventRxEntryDone) +/*---------------------------------------------------------------------------*/ #define STATUS_CORRELATION 0x3f /* bits 0-5 */ #define STATUS_REJECT_FRAME 0x40 /* bit 6 */ #define STATUS_CRC_FAIL 0x80 /* bit 7 */ @@ -202,12 +199,6 @@ typedef enum { CCA_STATE_INVALID = 2 } cca_state_t; /*---------------------------------------------------------------------------*/ -typedef enum { - POWER_STATE_ON = (1 << 0), - POWER_STATE_OFF = (1 << 1), - POWER_STATE_RESTART = POWER_STATE_ON | POWER_STATE_OFF, -} PowerState; -/*---------------------------------------------------------------------------*/ /* RF Core typedefs */ typedef dataQueue_t data_queue_t; typedef rfc_dataEntryGeneral_t data_entry_t; @@ -256,7 +247,6 @@ typedef struct { } rat; /* RF driver */ - RF_Object rf_object; RF_Handle rf_handle; } ieee_radio_t; @@ -271,11 +261,9 @@ static cmd_mod_filt_t cmd_mod_filt; #define cmd_tx (*(volatile rfc_CMD_IEEE_TX_t*) &rf_cmd_ieee_tx) #define cmd_rx (*(volatile rfc_CMD_IEEE_RX_t*) &rf_cmd_ieee_rx) /*---------------------------------------------------------------------------*/ -static CC_INLINE bool tx_active(void) { return cmd_tx.status == ACTIVE; } -static CC_INLINE bool rx_active(void) { return cmd_rx.status == ACTIVE; } +static inline bool rx_is_active(void) { return cmd_rx.status == ACTIVE; } /*---------------------------------------------------------------------------*/ -/* Forward declarations of static functions */ -static int set_rx(const PowerState); +/* Forward declarations of local functions */ static void check_rat_overflow(void); static uint32_t rat_to_timestamp(const uint32_t); /*---------------------------------------------------------------------------*/ @@ -321,7 +309,11 @@ rx_cb(RF_Handle client, RF_CmdHandle command, RF_EventMask events) (void)command; if (events & RF_EventRxOk) { - process_poll(&rf_process); + process_poll(&rf_core_process); + } + + if (events & RF_EventRxBufFull) { + } } /*---------------------------------------------------------------------------*/ @@ -347,8 +339,6 @@ init_data_queue(void) static void init_rf_params(void) { - cmd_rx.channel = IEEE_MODE_CHANNEL; - cmd_rx.pRxQ = &ieee_radio.rx_data_queue; cmd_rx.pOutput = &ieee_radio.rx_stats; @@ -373,9 +363,9 @@ init_rf_params(void) } /*---------------------------------------------------------------------------*/ static void -init_rx_buffers(void) +init_rx_bufs(void) { - size_t i = 0; + size_t i; for (i = 0; i < RX_BUF_CNT; ++i) { const data_entry_t data_entry = { .status = DATA_ENTRY_PENDING, @@ -391,7 +381,16 @@ init_rx_buffers(void) } } /*---------------------------------------------------------------------------*/ -static cmd_result_t +static void +reset_rx_bufs(void) +{ + size_t i; + for (i = 0; i < RX_BUF_CNT; ++i) { + ieee_radio.rx_bufs[i].data_entry.status = DATA_ENTRY_PENDING; + } +} +/*---------------------------------------------------------------------------*/ +static rf_result_t set_channel(uint32_t channel) { if (!IEEE_MODE_CHAN_IN_RANGE(channel)) { @@ -399,73 +398,31 @@ set_channel(uint32_t channel) (int)channel, IEEE_MODE_CHANNEL); channel = IEEE_MODE_CHANNEL; } + + /* + * cmd_rx.channel is initialized to 0, causing any initial call to + * set_channel() to cause a synth calibration, since channel must be in + * range 11-26. + */ if (channel == cmd_rx.channel) { /* We are already calibrated to this channel */ - return true; - } - - cmd_rx.channel = 0; - - /* freq = freq_base + freq_spacing * (channel - channel_min) */ - const uint32_t new_freq = IEEE_MODE_FREQ_BASE + IEEE_MODE_FREQ_SPACING * (channel - IEEE_MODE_CHAN_MIN); - const uint32_t freq = new_freq / 1000; - const uint32_t frac = ((new_freq - (freq * 1000)) * 65536) / 1000; - - PRINTF("set_channel: %d = 0x%04X.0x%04X (%lu)\n", - (int)channel, (uint16_t)freq, (uint16_t)frac, new_freq); - - cmd_fs.frequency = (uint16_t)freq; - cmd_fs.fractFreq = (uint16_t)frac; - - const bool was_on = rx_active(); - - if (was_on) { - RF_flushCmd(ieee_radio.rf_handle, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY); - } - - /* Start FS command asynchronously. We don't care when it is finished */ - RF_EventMask events = 0; - uint8_t tries = 0; - bool cmd_ok = false; - do { - events = RF_runCmd(ieee_radio.rf_handle, (RF_Op*)&cmd_fs, RF_PriorityNormal, NULL, 0); - cmd_ok = ((events & RF_EventLastCmdDone) != 0) - && (cmd_fs.status == DONE_OK); - } while (!cmd_ok && (tries++ < 3)); - - if (!cmd_ok) { - return false; + return true; } cmd_rx.channel = channel; - if (was_on) { - set_rx(POWER_STATE_ON); - } + /* freq = freq_base + freq_spacing * (channel - channel_min) */ + const uint32_t new_freq = IEEE_MODE_FREQ_BASE + IEEE_MODE_FREQ_SPACING * (channel - IEEE_MODE_CHAN_MIN); + const uint16_t freq = (uint16_t)(new_freq / 1000); + const uint16_t frac = (uint16_t)(((new_freq - (freq * 1000)) * 0x10000) / 1000); - return true; -} -/*---------------------------------------------------------------------------*/ -static radio_result_t -set_tx_power(const radio_value_t dBm) -{ - if (!TX_POWER_IN_RANGE(dBm)) { - return RADIO_RESULT_INVALID_VALUE; - } + PRINTF("set_channel: %d = 0x%04X.0x%04X (%lu)\n", + (int)channel, freq, frac, new_freq); - const RF_TxPowerTable_Value tx_power_table_value = RF_TxPowerTable_findValue(TX_POWER_TABLE, (int8_t)dBm); - const RF_Stat stat = RF_setTxPower(ieee_radio.rf_handle, tx_power_table_value); + cmd_fs.frequency = freq; + cmd_fs.fractFreq = frac; - return (stat == RF_StatSuccess) - ? RADIO_RESULT_OK - : RADIO_RESULT_ERROR; -} -/*---------------------------------------------------------------------------*/ -static radio_value_t -get_tx_power(void) -{ - const RF_TxPowerTable_Value value = RF_getTxPower(ieee_radio.rf_handle); - return (radio_value_t)RF_TxPowerTable_findPowerLevel(TX_POWER_TABLE, value); + return netstack_sched_fs(); } /*---------------------------------------------------------------------------*/ static void @@ -477,7 +434,7 @@ set_send_on_cca(bool enable) static void check_rat_overflow(void) { - const bool was_off = !rx_active(); + const bool was_off = !rx_is_active(); if (was_off) { RF_runDirectCmd(ieee_radio.rf_handle, CMD_NOP); @@ -535,7 +492,7 @@ init(void) { if (ieee_radio.rf_handle) { PRINTF("init: Radio already initialized\n"); - return CMD_RESULT_OK; + return RF_RESULT_OK; } /* RX is off */ @@ -549,11 +506,11 @@ init(void) RF_Params_init(&rf_params); rf_params.nInactivityTimeout = 2000; /* 2 ms */ - ieee_radio.rf_handle = RF_open(&ieee_radio.rf_object, &rf_ieee_mode, - (RF_RadioSetup*)&cmd_radio_setup, &rf_params); + ieee_radio.rf_handle = netstack_open(&rf_params); + if (ieee_radio.rf_handle == NULL) { - PRINTF("init: unable to open RF driver\n"); - return CMD_RESULT_ERROR; + PRINTF("init: unable to open IEEE RF driver\n"); + return RF_RESULT_ERROR; } set_channel(IEEE_MODE_CHANNEL); @@ -566,9 +523,9 @@ init(void) ctimer_set(&ieee_radio.rat.overflow_timer, two_quarters, rat_overflow_cb, NULL); /* Start RF process */ - process_start(&rf_process, NULL); + process_start(&rf_core_process, NULL); - return CMD_RESULT_OK; + return RF_RESULT_OK; } /*---------------------------------------------------------------------------*/ static int @@ -576,86 +533,30 @@ prepare(const void *payload, unsigned short payload_len) { const size_t len = MIN((size_t)payload_len, (size_t)TX_BUF_PAYLOAD_LEN); - memcpy(&ieee_radio.tx_buf[TX_BUF_HDR_LEN], payload, len); + + memcpy(ieee_radio.tx_buf + TX_BUF_HDR_LEN, payload, len); return 0; } /*---------------------------------------------------------------------------*/ static int -set_rx(const PowerState state) -{ - if (state & POWER_STATE_OFF) { - /* Stop RX gracefully, don't care about the result */ - RF_cancelCmd(ieee_radio.rf_handle, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY); - } - - if (state & POWER_STATE_ON) { - if (cmd_rx.status == ACTIVE) { - PRINTF("set_rx(on): already in RX\n"); - return CMD_RESULT_OK; - } - - RF_ScheduleCmdParams sched_params; - RF_ScheduleCmdParams_init(&sched_params); - - cmd_rx.status = IDLE; - RF_CmdHandle rx_handle = RF_scheduleCmd(ieee_radio.rf_handle, (RF_Op*)&cmd_rx, &sched_params, rx_cb, - RF_EventRxOk | RF_EventRxBufFull | RF_EventRxEntryDone); - if ((rx_handle == RF_ALLOC_ERROR) || (rx_handle == RF_SCHEDULE_CMD_ERROR)) { - PRINTF("transmit: unable to schedule RX command cmd_handle=%d\n", rx_handle); - return CMD_RESULT_ERROR; - } - } - - return CMD_RESULT_OK; -} -/*---------------------------------------------------------------------------*/ -static int -transmit_aux(unsigned short transmit_len) -{ - /* Configure TX command */ - cmd_tx.payloadLen = (uint8_t)transmit_len; - cmd_tx.pPayload = &ieee_radio.tx_buf[TX_BUF_HDR_LEN]; - - RF_ScheduleCmdParams sched_params; - RF_ScheduleCmdParams_init(&sched_params); - - /* As IEEE_TX is a FG command, the TX operation will be executed - * either way if RX is running or not */ - cmd_tx.status = IDLE; - RF_CmdHandle tx_handle = RF_scheduleCmd(ieee_radio.rf_handle, (RF_Op*)&cmd_tx, &sched_params, - NULL, 0); - if ((tx_handle == RF_ALLOC_ERROR) || (tx_handle == RF_SCHEDULE_CMD_ERROR)) { - /* Failure sending the CMD_IEEE_TX command */ - PRINTF("transmit: unable to schedule TX command cmd_handle=%d, status=%04x\n", - tx_handle, cmd_tx.status); - return RADIO_TX_ERR; - } - - ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT); - - /* Wait until TX operation finishes */ - RF_EventMask tx_events = RF_pendCmd(ieee_radio.rf_handle, tx_handle, 0); - if ((tx_events & (RF_EventFGCmdDone | RF_EventLastFGCmdDone)) == 0) { - PRINTF("transmit: TX command pend error events=0x%08llx, status=0x%04x\n", - tx_events, cmd_tx.status); - return RADIO_TX_ERR; - } - - return RADIO_TX_OK; -} -/*---------------------------------------------------------------------------*/ -static int transmit(unsigned short transmit_len) { + rf_result_t res; + if (ieee_radio.send_on_cca && channel_clear() != 1) { PRINTF("transmit: channel wasn't clear\n"); return RADIO_TX_COLLISION; } - const int rv = transmit_aux(transmit_len); - ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN); + /* Configure TX command */ + cmd_tx.payloadLen = (uint8_t)transmit_len; + cmd_tx.pPayload = &ieee_radio.tx_buf[TX_BUF_HDR_LEN]; - return rv; + res = netstack_sched_tx(NULL, 0); + + return (res == RF_RESULT_OK) + ? RADIO_TX_OK + : RADIO_TX_ERR; } /*---------------------------------------------------------------------------*/ static int @@ -692,7 +593,8 @@ read(void *buf, unsigned short buf_len) return 0; } - /* First byte in the data entry is the length. + /* + * First byte in the data entry is the length. * Data frame is on the following format: * Length (1) + Payload (N) + FCS (2) + RSSI (1) + Status (1) + Timestamp (4) * Data frame DOES NOT contain the following: @@ -705,9 +607,9 @@ read(void *buf, unsigned short buf_len) * +--------+---------+---------+--------+--------+-----------+ * Length bytes equal total length of entire frame excluding itself, * i.e.: Length = N + FCS (2) + RSSI (1) + Status (1) + Timestamp (4) - * = N + 8 - * N = Length - 8 */ - + * Length = N + 8 + * N = Length - 8 + */ uint8_t *const frame_ptr = (uint8_t*)&data_entry->data; const lensz_t frame_len = *(lensz_t*)frame_ptr; @@ -750,24 +652,36 @@ read(void *buf, unsigned short buf_len) return (int)payload_len; } /*---------------------------------------------------------------------------*/ -static cmd_result_t +static rf_result_t cca_request(cmd_cca_req_t *cmd_cca_req) { - const bool rx_is_off = !rx_active(); + rf_result_t res; - if (rx_is_off && set_rx(POWER_STATE_ON) != CMD_RESULT_OK) { - return CMD_RESULT_ERROR; + const bool rx_is_idle = !rx_is_active(); + + if (rx_is_idle) { + res = netstack_sched_rx(rx_cb, CMD_RX_EVENTS); + if (res != RF_RESULT_OK) { + return RF_RESULT_ERROR; + } } - const RF_Stat stat = RF_runImmediateCmd(ieee_radio.rf_handle, (uint32_t*)&cmd_cca_req); + const rtimer_clock_t t0 = RTIMER_NOW(); + while ((cmd_rx.status != ACTIVE) && + RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + TIMEOUT_ENTER_RX_WAIT)); - if (rx_is_off) { - set_rx(POWER_STATE_OFF); + RF_Stat stat = RF_StatRadioInactiveError; + if (rx_is_active()) { + stat = RF_runImmediateCmd(ieee_radio.rf_handle, (uint32_t*)&cmd_cca_req); + } + + if (rx_is_idle) { + netstack_stop_rx(); } return (stat == RF_StatCmdDoneSuccess) - ? CMD_RESULT_OK - : CMD_RESULT_ERROR; + ? RF_RESULT_OK + : RF_RESULT_ERROR; } /*---------------------------------------------------------------------------*/ static int @@ -777,7 +691,7 @@ channel_clear(void) memset(&cmd_cca_req, 0x0, sizeof(cmd_cca_req_t)); cmd_cca_req.commandNo = CMD_IEEE_CCA_REQ; - if (cca_request(&cmd_cca_req) != CMD_RESULT_OK) { + if (cca_request(&cmd_cca_req) != RF_RESULT_OK) { return 0; } @@ -792,7 +706,7 @@ receiving_packet(void) memset(&cmd_cca_req, 0x0, sizeof(cmd_cca_req_t)); cmd_cca_req.commandNo = CMD_IEEE_CCA_REQ; - if (cca_request(&cmd_cca_req) != CMD_RESULT_OK) { + if (cca_request(&cmd_cca_req) != RF_RESULT_OK) { return 0; } @@ -816,7 +730,7 @@ pending_packet(void) int num_pending = 0; - /* Go through RX Circular buffer and check their status */ + /* Go through RX Circular buffer and check each data entry status */ do { const uint8_t status = curr_entry->status; if ((status == DATA_ENTRY_FINISHED) || @@ -829,7 +743,7 @@ pending_packet(void) } while (curr_entry != read_entry); if ((num_pending > 0) && !ieee_radio.poll_mode) { - process_poll(&rf_process); + process_poll(&rf_core_process); } /* If we didn't find an entry at status finished or busy, no frames are pending */ @@ -839,28 +753,23 @@ pending_packet(void) static int on(void) { + rf_result_t res; + if (ieee_radio.rf_is_on) { PRINTF("on: Radio already on\n"); - return CMD_RESULT_OK; + return RF_RESULT_OK; } - /* Reset all RF command statuses */ - cmd_fs.status = IDLE; - cmd_tx.status = IDLE; - cmd_rx.status = IDLE; + init_rx_bufs(); - init_rx_buffers(); + res = netstack_sched_rx(rx_cb, CMD_RX_EVENTS); - const int rx_ok = set_rx(POWER_STATE_ON); - if (!rx_ok) { - off(); - return CMD_RESULT_ERROR; + if (res != RF_RESULT_OK) { + return RF_RESULT_ERROR; } - ENERGEST_ON(ENERGEST_TYPE_LISTEN); - ieee_radio.rf_is_on = true; - return rx_ok; + return RF_RESULT_OK; } /*---------------------------------------------------------------------------*/ static int @@ -868,55 +777,51 @@ off(void) { if (!ieee_radio.rf_is_on) { PRINTF("off: Radio already off\n"); - return CMD_RESULT_OK; + return RF_RESULT_OK; } - /* Force abort of any ongoing RF operation */ - RF_flushCmd(ieee_radio.rf_handle, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY); - /* Trigger a manual power-down */ - RF_yield(ieee_radio.rf_handle); + rf_yield(); - ENERGEST_OFF(ENERGEST_TYPE_LISTEN); - - /* Reset RX buffers if there was an ongoing RX */ - size_t i; - for (i = 0; i < RX_BUF_CNT; ++i) { - data_entry_t *entry = &ieee_radio.rx_bufs[i].data_entry; - if (entry->status == DATA_ENTRY_BUSY) { - entry->status = DATA_ENTRY_PENDING; - } - } + reset_rx_bufs(); ieee_radio.rf_is_on = false; - return CMD_RESULT_OK; + return RF_RESULT_OK; } /*---------------------------------------------------------------------------*/ static radio_result_t get_value(radio_param_t param, radio_value_t *value) { + rf_result_t res; + if (!value) { return RADIO_RESULT_INVALID_VALUE; } switch (param) { + + /* Power Mode */ case RADIO_PARAM_POWER_MODE: *value = (ieee_radio.rf_is_on) ? RADIO_POWER_MODE_ON : RADIO_POWER_MODE_OFF; return RADIO_RESULT_OK; + /* Channel */ case RADIO_PARAM_CHANNEL: *value = (radio_value_t)cmd_rx.channel; return RADIO_RESULT_OK; + /* PAN ID */ case RADIO_PARAM_PAN_ID: *value = (radio_value_t)cmd_rx.localPanID; return RADIO_RESULT_OK; + /* 16-bit address */ case RADIO_PARAM_16BIT_ADDR: *value = (radio_value_t)cmd_rx.localShortAddr; return RADIO_RESULT_OK; + /* RX mode */ case RADIO_PARAM_RX_MODE: *value = 0; if (cmd_rx.frameFiltOpt.frameFiltEn) { @@ -930,30 +835,37 @@ get_value(radio_param_t param, radio_value_t *value) } return RADIO_RESULT_OK; + /* TX mode */ case RADIO_PARAM_TX_MODE: *value = 0; return RADIO_RESULT_OK; + /* TX power */ case RADIO_PARAM_TXPOWER: - *value = get_tx_power(); - return (*value == RF_TxPowerTable_INVALID_DBM) - ? RADIO_RESULT_ERROR - : RADIO_RESULT_OK; + res = rf_get_tx_power(ieee_radio.rf_handle, TX_POWER_TABLE, (int8_t*)&value); + return ((res == RF_RESULT_OK) && + (*value != RF_TxPowerTable_INVALID_DBM)) + ? RADIO_RESULT_OK + : RADIO_RESULT_ERROR; + /* CCA threshold */ case RADIO_PARAM_CCA_THRESHOLD: *value = cmd_rx.ccaRssiThr; return RADIO_RESULT_OK; + /* RSSI */ case RADIO_PARAM_RSSI: *value = RF_getRssi(ieee_radio.rf_handle); return (*value == RF_GET_RSSI_ERROR_VAL) ? RADIO_RESULT_ERROR : RADIO_RESULT_OK; + /* Channel min */ case RADIO_CONST_CHANNEL_MIN: *value = (radio_value_t)IEEE_MODE_CHAN_MIN; return RADIO_RESULT_OK; + /* Channel max */ case RADIO_CONST_CHANNEL_MAX: *value = (radio_value_t)IEEE_MODE_CHAN_MAX; return RADIO_RESULT_OK; @@ -962,14 +874,17 @@ get_value(radio_param_t param, radio_value_t *value) *value = (radio_value_t)TX_POWER_MIN; return RADIO_RESULT_OK; + /* TX power max */ case RADIO_CONST_TXPOWER_MAX: *value = (radio_value_t)TX_POWER_MAX; return RADIO_RESULT_OK; + /* Last RSSI */ case RADIO_PARAM_LAST_RSSI: *value = (radio_value_t)ieee_radio.last.rssi; return RADIO_RESULT_OK; + /* Last link quality */ case RADIO_PARAM_LAST_LINK_QUALITY: *value = (radio_value_t)ieee_radio.last.corr_lqi; return RADIO_RESULT_OK; @@ -982,14 +897,18 @@ get_value(radio_param_t param, radio_value_t *value) static radio_result_t set_value(radio_param_t param, radio_value_t value) { + rf_result_t res; + switch (param) { + + /* Power Mode */ case RADIO_PARAM_POWER_MODE: + if (value == RADIO_POWER_MODE_ON) { - if (on() != CMD_RESULT_OK) { - PRINTF("set_value: on() failed (1)\n"); - return RADIO_RESULT_ERROR; - } - return RADIO_RESULT_OK; + return (on() == RF_RESULT_OK) + ? RADIO_RESULT_OK + : RADIO_RESULT_ERROR; + } else if (value == RADIO_POWER_MODE_OFF) { off(); return RADIO_RESULT_OK; @@ -997,6 +916,7 @@ set_value(radio_param_t param, radio_value_t value) return RADIO_RESULT_INVALID_VALUE; + /* Channel */ case RADIO_PARAM_CHANNEL: if (!IEEE_MODE_CHAN_IN_RANGE(value)) { return RADIO_RESULT_INVALID_VALUE; @@ -1004,22 +924,33 @@ set_value(radio_param_t param, radio_value_t value) set_channel((uint8_t)value); return RADIO_RESULT_OK; + /* PAN ID */ case RADIO_PARAM_PAN_ID: cmd_rx.localPanID = (uint16_t)value; - if (ieee_radio.rf_is_on && set_rx(POWER_STATE_RESTART) != CMD_RESULT_OK) { - PRINTF("failed to restart RX"); - return RADIO_RESULT_ERROR; + if (!ieee_radio.rf_is_on) { + return RADIO_RESULT_OK; } - return RADIO_RESULT_OK; + netstack_stop_rx(); + res = netstack_sched_rx(rx_cb, CMD_RX_EVENTS); + return (res == RF_RESULT_OK) + ? RADIO_RESULT_OK + : RADIO_RESULT_ERROR; + + /* 16bit address */ case RADIO_PARAM_16BIT_ADDR: cmd_rx.localShortAddr = (uint16_t)value; - if (ieee_radio.rf_is_on && set_rx(POWER_STATE_RESTART) != CMD_RESULT_OK) { - PRINTF("failed to restart RX"); - return RADIO_RESULT_ERROR; + if (!ieee_radio.rf_is_on) { + return RADIO_RESULT_OK; } - return RADIO_RESULT_OK; + netstack_stop_rx(); + res = netstack_sched_rx(rx_cb, CMD_RX_EVENTS); + return (res == RF_RESULT_OK) + ? RADIO_RESULT_OK + : RADIO_RESULT_ERROR; + + /* RX Mode */ case RADIO_PARAM_RX_MODE: { if (value & ~(RADIO_RX_MODE_ADDRESS_FILTER | RADIO_RX_MODE_AUTOACK | RADIO_RX_MODE_POLL_MODE)) { @@ -1048,13 +979,18 @@ set_value(radio_param_t param, radio_value_t value) } return RADIO_RESULT_OK; } - if (ieee_radio.rf_is_on && set_rx(POWER_STATE_RESTART) != CMD_RESULT_OK) { - PRINTF("failed to restart RX"); - return RADIO_RESULT_ERROR; + if (!ieee_radio.rf_is_on) { + return RADIO_RESULT_OK; } - return RADIO_RESULT_OK; + + netstack_stop_rx(); + res = netstack_sched_rx(rx_cb, CMD_RX_EVENTS); + return (res == RF_RESULT_OK) + ? RADIO_RESULT_OK + : RADIO_RESULT_ERROR; } + /* TX Mode */ case RADIO_PARAM_TX_MODE: if(value & ~(RADIO_TX_MODE_SEND_ON_CCA)) { return RADIO_RESULT_INVALID_VALUE; @@ -1062,16 +998,28 @@ set_value(radio_param_t param, radio_value_t value) set_send_on_cca((value & RADIO_TX_MODE_SEND_ON_CCA) != 0); return RADIO_RESULT_OK; + /* TX Power */ case RADIO_PARAM_TXPOWER: - return set_tx_power(value); + if (!TX_POWER_IN_RANGE((int8_t)value)) { + return RADIO_RESULT_INVALID_VALUE; + } + res = rf_set_tx_power(ieee_radio.rf_handle, TX_POWER_TABLE, (int8_t)value); + return (res == RF_RESULT_OK) + ? RADIO_RESULT_OK + : RADIO_RESULT_ERROR; + /* CCA Threshold */ case RADIO_PARAM_CCA_THRESHOLD: cmd_rx.ccaRssiThr = (int8_t)value; - if (ieee_radio.rf_is_on && set_rx(POWER_STATE_RESTART) != CMD_RESULT_OK) { - PRINTF("failed to restart RX"); - return RADIO_RESULT_ERROR; + if (!ieee_radio.rf_is_on) { + return RADIO_RESULT_OK; } - return RADIO_RESULT_OK; + + netstack_stop_rx(); + res = netstack_sched_rx(rx_cb, CMD_RX_EVENTS); + return (res == RF_RESULT_OK) + ? RADIO_RESULT_OK + : RADIO_RESULT_ERROR; default: return RADIO_RESULT_NOT_SUPPORTED; @@ -1086,6 +1034,7 @@ get_object(radio_param_t param, void *dest, size_t size) } switch (param) { + /* 64bit address */ case RADIO_PARAM_64BIT_ADDR: { const size_t srcSize = sizeof(cmd_rx.localExtAddr); if(size != srcSize) { @@ -1100,6 +1049,7 @@ get_object(radio_param_t param, void *dest, size_t size) return RADIO_RESULT_OK; } + /* Last packet timestamp */ case RADIO_PARAM_LAST_PACKET_TIMESTAMP: if(size != sizeof(rtimer_clock_t)) { return RADIO_RESULT_INVALID_VALUE; @@ -1117,11 +1067,14 @@ get_object(radio_param_t param, void *dest, size_t size) static radio_result_t set_object(radio_param_t param, const void *src, size_t size) { + rf_result_t res; + if (!src) { return RADIO_RESULT_INVALID_VALUE; } switch (param) { + /* 64-bit address */ case RADIO_PARAM_64BIT_ADDR: { const size_t destSize = sizeof(cmd_rx.localExtAddr); if (size != destSize) { @@ -1129,16 +1082,20 @@ set_object(radio_param_t param, const void *src, size_t size) } const uint8_t *pSrc = (const uint8_t *)src; - uint8_t *pDest = (uint8_t *)&(cmd_rx.localExtAddr); + volatile uint8_t *pDest = (uint8_t *)&(cmd_rx.localExtAddr); for (size_t i = 0; i < destSize; ++i) { pDest[i] = pSrc[destSize - 1 - i]; } - const bool is_rx = (cmd_rx.status == ACTIVE); - if (is_rx && set_rx(POWER_STATE_RESTART) != CMD_RESULT_OK) { - return RADIO_RESULT_ERROR; + if (!rx_is_active()) { + return RADIO_RESULT_OK; } - return RADIO_RESULT_OK; + + netstack_stop_rx(); + res = netstack_sched_rx(rx_cb, CMD_RX_EVENTS); + return (res == RF_RESULT_OK) + ? RADIO_RESULT_OK + : RADIO_RESULT_ERROR; } default: return RADIO_RESULT_NOT_SUPPORTED; diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c index 418ec46db..330f4cd73 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c @@ -55,18 +55,10 @@ #include /*---------------------------------------------------------------------------*/ -/* RF settings */ -#ifdef PROP_MODE_CONF_RF_SETTINGS -# define PROP_MODE_RF_SETTINGS PROP_MODE_CONF_RF_SETTINGS -#else -# define PROP_MODE_RF_SETTINGS "prop-settings.h" -#endif - -#include PROP_MODE_RF_SETTINGS -/*---------------------------------------------------------------------------*/ /* Platform RF dev */ -#include "rf-common.h" #include "dot-15-4g.h" +#include "rf-core.h" +#include "netstack-settings.h" /*---------------------------------------------------------------------------*/ #include #include @@ -139,11 +131,13 @@ #endif /*---------------------------------------------------------------------------*/ /* How long to wait for the RF to enter RX in rf_cmd_ieee_rx */ -#define ENTER_RX_WAIT_TIMEOUT (RTIMER_SECOND >> 10) +#define TIMEOUT_ENTER_RX_WAIT (RTIMER_SECOND >> 10) /* How long to wait for the rx read entry to become ready */ #define TIMEOUT_DATA_ENTRY_BUSY (RTIMER_SECOND / 250) /*---------------------------------------------------------------------------*/ +#define CMD_RX_EVENTS (RF_EventRxOk | RF_EventRxBufFull | RF_EventRxEntryDone) +/*---------------------------------------------------------------------------*/ /* Configuration for TX power table */ #ifdef PROP_MODE_CONF_TX_POWER_TABLE # define TX_POWER_TABLE PROP_MODE_CONF_TX_POWER_TABLE @@ -214,12 +208,12 @@ typedef struct { /* RSSI Threshold */ int8_t rssi_threshold; + uint16_t channel; /* Indicates RF is supposed to be on or off */ uint8_t rf_is_on; /* RF driver */ - RF_Object rf_object; RF_Handle rf_handle; } prop_radio_t; @@ -230,99 +224,67 @@ static prop_radio_t prop_radio; #define cmd_tx (*(volatile rfc_CMD_PROP_TX_ADV_t *) &rf_cmd_prop_tx_adv) #define cmd_rx (*(volatile rfc_CMD_PROP_RX_ADV_t *) &rf_cmd_prop_rx_adv) /*---------------------------------------------------------------------------*/ -static CC_INLINE bool tx_active(void) { return cmd_tx.status == ACTIVE; } -static CC_INLINE bool rx_active(void) { return cmd_rx.status == ACTIVE; } +static inline bool tx_is_active(void) { return cmd_tx.status == ACTIVE; } +static inline bool rx_is_active(void) { return cmd_rx.status == ACTIVE; } /*---------------------------------------------------------------------------*/ static int on(void); static int off(void); /*---------------------------------------------------------------------------*/ static void -cmd_rx_cb(RF_Handle client, RF_CmdHandle command, RF_EventMask events) +rx_cb(RF_Handle client, RF_CmdHandle command, RF_EventMask events) { /* Unused arguments */ (void)client; (void)command; if (events & RF_EventRxEntryDone) { - process_poll(&rf_process); + process_poll(&rf_core_process); } } /*---------------------------------------------------------------------------*/ -static cmd_result_t -start_rx(void) +static void +init_data_queue(void) { - cmd_rx.status = IDLE; - RF_CmdHandle rx_handle = RF_postCmd(prop_radio.rf_handle, (RF_Op*)&cmd_rx, RF_PriorityNormal, - &cmd_rx_cb, RF_EventRxEntryDone); - if (rx_handle == RF_ALLOC_ERROR) { - PRINTF("start_rx: RF_ALLOC_ERROR for cmd_rx\n"); - return CMD_RESULT_ERROR; - } - - /* Wait to enter RX */ - const rtimer_clock_t t0 = RTIMER_NOW(); - while (!rx_active() && - (RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + ENTER_RX_WAIT_TIMEOUT))); - - if (!rx_active()) { - PRINTF("cmd_rx: status=0x%04x\n", cmd_rx.status); - return CMD_RESULT_ERROR; - } - - return CMD_RESULT_OK; + /* Initialize RF core data queue, circular buffer */ + prop_radio.rx_data_queue.pCurrEntry = prop_radio.rx_bufs[0].buf; + prop_radio.rx_data_queue.pLastEntry = NULL; + /* Set current read pointer to first element */ + prop_radio.rx_read_entry = &prop_radio.rx_bufs[0].data_entry; } /*---------------------------------------------------------------------------*/ -static cmd_result_t -stop_rx(void) +static void +init_rf_params(void) { - /* Abort any ongoing operation. Don't care about the result. */ - RF_cancelCmd(prop_radio.rf_handle, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY); - - if (cmd_rx.status != PROP_DONE_STOPPED && - cmd_rx.status != PROP_DONE_ABORT) { - PRINTF("RF_cmdPropRxAdv cancel: status=0x%04x\n", - cmd_rx.status); - return CMD_RESULT_ERROR; - } - - /* Stopped gracefully */ - ENERGEST_OFF(ENERGEST_TYPE_LISTEN); - return CMD_RESULT_OK; + cmd_rx.maxPktLen = DOT_4G_MAX_FRAME_LEN - cmd_rx.lenOffset; + cmd_rx.pQueue = &prop_radio.rx_data_queue; + cmd_rx.pOutput = (uint8_t *)&prop_radio.rx_stats; } /*---------------------------------------------------------------------------*/ -static cmd_result_t -rf_run_setup() -{ - /* TODO not the right way to do this. */ - RF_runCmd(prop_radio.rf_handle, (RF_Op*)&cmd_radio_setup, RF_PriorityNormal, NULL, 0); - if (cmd_radio_setup.status != PROP_DONE_OK) { - return CMD_RESULT_ERROR; - } - - return CMD_RESULT_OK; -} -/*---------------------------------------------------------------------------*/ -static radio_value_t +static int8_t get_rssi(void) { - if (tx_active()) { - PRINTF("get_rssi: called while in TX\n"); - return RF_GET_RSSI_ERROR_VAL; + rf_result_t res; + + const bool rx_is_idle = !rx_is_active(); + + if (rx_is_idle) { + res = netstack_sched_rx(rx_cb, CMD_RX_EVENTS); + if (res != RF_RESULT_OK) { + return RF_GET_RSSI_ERROR_VAL; + } } - const bool was_off = !rx_active(); - if (was_off && start_rx() == CMD_RESULT_ERROR) { - PRINTF("get_rssi: unable to start RX\n"); - return RF_GET_RSSI_ERROR_VAL; - } + const rtimer_clock_t t0 = RTIMER_NOW(); + while ((cmd_rx.status != ACTIVE) && + RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + TIMEOUT_ENTER_RX_WAIT)); int8_t rssi = RF_GET_RSSI_ERROR_VAL; - while(rssi == RF_GET_RSSI_ERROR_VAL || rssi == 0) { + if (rx_is_active()) { rssi = RF_getRssi(prop_radio.rf_handle); } - if (was_off) { - stop_rx(); + if (rx_is_idle) { + netstack_stop_rx(); } return rssi; @@ -344,59 +306,40 @@ get_channel(void) return (freq_khz - DOT_15_4G_CHAN0_FREQUENCY) / DOT_15_4G_CHANNEL_SPACING; } /*---------------------------------------------------------------------------*/ -static cmd_result_t -set_channel(uint32_t channel) +static rf_result_t +set_channel(uint16_t channel) { - const uint32_t new_freq = DOT_15_4G_CHAN0_FREQUENCY + (channel * DOT_15_4G_CHANNEL_SPACING); - const uint32_t freq = new_freq / 1000; - const uint32_t frac = ((new_freq - (freq * 1000)) * 65536) / 1000; + rf_result_t res; + + if (!DOT_15_4_G_CHANNEL_IN_RANGE(channel)) { + PRINTF("set_channel: illegal channel %d, defaults to %d\n", + (int)channel, DOT_15_4G_CHANNEL_MAX); + channel = DOT_15_4G_CHANNEL_MAX; + } + + if (channel == prop_radio.channel) { + /* We are already calibrated to this channel */ + return RF_RESULT_OK; + } + + const uint32_t new_freq = DOT_15_4G_CHAN0_FREQUENCY + ((uint32_t)channel * DOT_15_4G_CHANNEL_SPACING); + const uint16_t freq = (uint16_t)(new_freq / 1000); + const uint16_t frac = (uint16_t)(((new_freq - (freq * 1000)) * 0x10000) / 1000); PRINTF("set_channel: %u = 0x%04x.0x%04x (%lu)\n", - (int)channel, (uint16_t)freq, (uint16_t)frac, new_freq); + (int)channel, freq, frac, new_freq); - cmd_radio_setup.centerFreq = freq; - cmd_fs.frequency = (uint16_t)freq; - cmd_fs.fractFreq = (uint16_t)frac; + cmd_fs.frequency = freq; + cmd_fs.fractFreq = frac; - /* We don't care whether the FS command is successful because subsequent */ - /* TX and RX commands will tell us indirectly. */ - RF_EventMask rf_events = RF_runCmd(prop_radio.rf_handle, (RF_Op*)&cmd_fs, - RF_PriorityNormal, NULL, 0); - if ((rf_events & (RF_EventCmdDone | RF_EventLastCmdDone)) == 0) { - PRINTF("set_channel: RF_runCmd failed, events=0x%llx\n", rf_events); - return CMD_RESULT_ERROR; + res = netstack_sched_fs(); + + if (res != RF_RESULT_OK) { + return res; } - if (cmd_fs.status != DONE_OK) { - PRINTF("set_channel: cmd_fs failed, status=0x%04x\n", cmd_fs.status); - return CMD_RESULT_ERROR; - } - - return CMD_RESULT_OK; -} -/*---------------------------------------------------------------------------*/ -/* Returns the current TX power in dBm */ -static radio_result_t -set_tx_power(const radio_value_t dBm) -{ - if (!TX_POWER_IN_RANGE(dBm)) { - return RADIO_RESULT_INVALID_VALUE; - } - - const RF_TxPowerTable_Value value = RF_TxPowerTable_findValue(TX_POWER_TABLE, (int8_t)dBm); - const RF_Stat stat = RF_setTxPower(prop_radio.rf_handle, value); - - return (stat == RF_StatSuccess) - ? RADIO_RESULT_OK - : RADIO_RESULT_ERROR; -} -/*---------------------------------------------------------------------------*/ -/* Returns the current TX power in dBm */ -static radio_value_t -get_tx_power(void) -{ - const RF_TxPowerTable_Value value = RF_getTxPower(prop_radio.rf_handle); - return (radio_value_t)RF_TxPowerTable_findPowerLevel(TX_POWER_TABLE, value); + prop_radio.channel = channel; + return RF_RESULT_OK; } /*---------------------------------------------------------------------------*/ static uint8_t @@ -415,7 +358,7 @@ calculate_lqi(int8_t rssi) } /*---------------------------------------------------------------------------*/ static void -init_rx_buffers(void) +init_rx_bufs(void) { size_t i = 0; for (i = 0; i < RX_BUF_CNT; ++i) { @@ -434,10 +377,20 @@ init_rx_buffers(void) } } /*---------------------------------------------------------------------------*/ +static void +reset_rx_bufs(void) +{ + size_t i; + for (i = 0; i < RX_BUF_CNT; ++i) { + prop_radio.rx_bufs[i].data_entry.status = DATA_ENTRY_PENDING; + } +} +/*---------------------------------------------------------------------------*/ static int prepare(const void *payload, unsigned short payload_len) { - int len = MIN(payload_len, TX_BUF_PAYLOAD_LEN); + const size_t len = MIN((size_t)payload_len, + (size_t)TX_BUF_PAYLOAD_LEN); memcpy(prop_radio.tx_buf + TX_BUF_HDR_LEN, payload, len); return 0; @@ -446,26 +399,23 @@ prepare(const void *payload, unsigned short payload_len) static int transmit(unsigned short transmit_len) { - int ret = RADIO_TX_OK; + rf_result_t res; - if (tx_active()) { + if (tx_is_active()) { PRINTF("transmit: not allowed while transmitting\n"); return RADIO_TX_ERR; } - const bool rx_is_on = rx_active(); - if (rx_is_on) { - stop_rx(); - } - /* Length in .15.4g PHY HDR. Includes the CRC but not the HDR itself */ - uint16_t total_length = transmit_len + CRC_LEN; - /* Prepare the .15.4g PHY header + const uint16_t total_length = transmit_len + CRC_LEN; + /* + * Prepare the .15.4g PHY header * MS=0, Length MSBits=0, DW and CRC configurable * Total length = transmit_len (payload) + CRC length * * The Radio will flip the bits around, so tx_buf[0] must have the length - * LSBs (PHR[15:8] and tx_buf[1] will have PHR[7:0] */ + * LSBs (PHR[15:8] and tx_buf[1] will have PHR[7:0] + */ prop_radio.tx_buf[0] = total_length & 0xFF; prop_radio.tx_buf[1] = (total_length >> 8) + DOT_4G_PHR_DW_BIT + DOT_4G_PHR_CRC_BIT; @@ -474,42 +424,11 @@ transmit(unsigned short transmit_len) cmd_tx.pktLen = transmit_len + DOT_4G_PHR_LEN; cmd_tx.pPkt = prop_radio.tx_buf; - RF_CmdHandle tx_handle = RF_postCmd(prop_radio.rf_handle, (RF_Op*)&cmd_tx, RF_PriorityNormal, NULL, 0); - if (tx_handle == RF_ALLOC_ERROR) { - /* Failure sending the CMD_PROP_TX command */ - PRINTF("transmit: unable to allocate RF command handle\n"); - return RADIO_TX_ERR; - } + res = netstack_sched_tx(NULL, 0); - ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); - - /* watchdog_periodic(); */ - - /* Idle away while the command is running */ - RF_EventMask rf_events = RF_pendCmd(prop_radio.rf_handle, tx_handle, RF_EventLastCmdDone); - - if ((rf_events & (RF_EventCmdDone | RF_EventLastCmdDone)) == 0) { - PRINTF("transmit: RF_pendCmd failed, events=0x%llx\n", rf_events); - ret = RADIO_TX_ERR; - } - - else if (cmd_tx.status != PROP_DONE_OK) { - /* Operation completed, but frame was not sent */ - PRINTF("transmit: Not Sent OK status=0x%04x\n", - cmd_tx.status); - ret = RADIO_TX_ERR; - } - - ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); - - /* Workaround. Set status to IDLE */ - cmd_tx.status = IDLE; - - if (rx_is_on) { - start_rx(); - } - - return ret; + return (res == RF_RESULT_OK) + ? RADIO_TX_OK + : RADIO_TX_ERR; } /*---------------------------------------------------------------------------*/ static int @@ -597,47 +516,44 @@ read(void *buf, unsigned short buf_len) return (int)payload_len; } /*---------------------------------------------------------------------------*/ +static uint8_t +cca_request(void) +{ + const int8_t rssi = get_rssi(); + + if (rssi == RF_GET_RSSI_ERROR_VAL) { + return CCA_STATE_INVALID; + } + + return (rssi < prop_radio.rssi_threshold) + ? CCA_STATE_IDLE + : CCA_STATE_BUSY; +} +/*---------------------------------------------------------------------------*/ static int channel_clear(void) { - if (tx_active()) { + if (tx_is_active()) { PRINTF("channel_clear: called while in TX\n"); - return CCA_STATE_IDLE; + return 0; } - const bool rx_was_off = !rx_active(); - if (rx_was_off) { - start_rx(); - } + const uint8_t cca_state = cca_request(); - int8_t rssi = RF_GET_RSSI_ERROR_VAL; - while (rssi == RF_GET_RSSI_ERROR_VAL || rssi == 0) { - rssi = RF_getRssi(prop_radio.rf_handle); - } - - if (rx_was_off) { - stop_rx(); - } - - if(rssi >= prop_radio.rssi_threshold) { - return CCA_STATE_BUSY; - } - - return CCA_STATE_IDLE; + /* Channel is clear if CCA state is IDLE */ + return (cca_state == CCA_STATE_IDLE); } /*---------------------------------------------------------------------------*/ static int receiving_packet(void) { - if (!rx_active()) { + if (!rx_is_active()) { return 0; } - if (channel_clear() == CCA_STATE_IDLE) { - return 0; - } + const uint8_t cca_state = cca_request(); - return 1; + return (cca_state == CCA_STATE_BUSY); } /*---------------------------------------------------------------------------*/ static int @@ -661,7 +577,7 @@ pending_packet(void) } while (curr_entry != read_entry); if (num_pending > 0) { - process_poll(&rf_process); + process_poll(&rf_core_process); } /* If we didn't find an entry at status finished, no frames are pending */ @@ -671,26 +587,23 @@ pending_packet(void) static int on(void) { + rf_result_t res; + if (prop_radio.rf_is_on) { PRINTF("on: Radio already on\n"); - return CMD_RESULT_OK; + return RF_RESULT_OK; } - /* Reset all RF command statuses */ - cmd_fs.status = IDLE; - cmd_tx.status = IDLE; - cmd_rx.status = IDLE; + init_rx_bufs(); - init_rx_buffers(); + res = netstack_sched_rx(rx_cb, CMD_RX_EVENTS); - const int rx_ok = start_rx(); - if (!rx_ok) { - off(); - return CMD_RESULT_ERROR; + if (res != RF_RESULT_OK) { + return RF_RESULT_ERROR; } prop_radio.rf_is_on = true; - return CMD_RESULT_OK; + return RF_RESULT_OK; } /*---------------------------------------------------------------------------*/ static int @@ -698,30 +611,22 @@ off(void) { if (!prop_radio.rf_is_on) { PRINTF("off: Radio already off\n"); - return CMD_RESULT_OK; + return RF_RESULT_OK; } - /* Force abort of any ongoing RF operation */ - RF_flushCmd(prop_radio.rf_handle, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY); - /* Trigger a manual power-down */ - RF_yield(prop_radio.rf_handle); + rf_yield(); - /* Reset RX buffers if there was an ongoing RX */ - size_t i; - for (i = 0; i < RX_BUF_CNT; ++i) { - data_entry_t *entry = &prop_radio.rx_bufs[i].data_entry; - if (entry->status == DATA_ENTRY_BUSY) { - entry->status = DATA_ENTRY_PENDING; - } - } + reset_rx_bufs(); prop_radio.rf_is_on = false; - return CMD_RESULT_OK; + return RF_RESULT_OK; } /*---------------------------------------------------------------------------*/ static radio_result_t get_value(radio_param_t param, radio_value_t *value) { + rf_result_t res; + if (!value) { return RADIO_RESULT_INVALID_VALUE; } @@ -740,8 +645,11 @@ get_value(radio_param_t param, radio_value_t *value) return RADIO_RESULT_OK; case RADIO_PARAM_TXPOWER: - *value = get_tx_power(); - return RADIO_RESULT_OK; + res = rf_get_tx_power(prop_radio.rf_handle, TX_POWER_TABLE, (int8_t*)&value); + return ((res == RF_RESULT_OK) && + (*value != RF_TxPowerTable_INVALID_DBM)) + ? RADIO_RESULT_OK + : RADIO_RESULT_ERROR; case RADIO_PARAM_CCA_THRESHOLD: *value = prop_radio.rssi_threshold; @@ -777,35 +685,37 @@ get_value(radio_param_t param, radio_value_t *value) static radio_result_t set_value(radio_param_t param, radio_value_t value) { + rf_result_t res; + switch(param) { case RADIO_PARAM_POWER_MODE: + if(value == RADIO_POWER_MODE_ON) { - /* Powering on happens implicitly */ - return RADIO_RESULT_OK; - } - if(value == RADIO_POWER_MODE_OFF) { + return (on() == RF_RESULT_OK) + ? RADIO_RESULT_OK + : RADIO_RESULT_ERROR; + + } else if(value == RADIO_POWER_MODE_OFF) { off(); return RADIO_RESULT_OK; } + return RADIO_RESULT_INVALID_VALUE; case RADIO_PARAM_CHANNEL: - if(value < 0 || - value > DOT_15_4G_CHANNEL_MAX) { - return RADIO_RESULT_INVALID_VALUE; - } - - if(get_channel() == (uint8_t)value) { - /* We already have that very same channel configured. - * Nothing to do here. */ - return RADIO_RESULT_OK; - } - - set_channel((uint8_t)value); - break; + res = set_channel((uint16_t)value); + return (res == RF_RESULT_OK) + ? RADIO_RESULT_OK + : RADIO_RESULT_ERROR; case RADIO_PARAM_TXPOWER: - return set_tx_power(value); + if (!TX_POWER_IN_RANGE((int8_t)value)) { + return RADIO_RESULT_INVALID_VALUE; + } + res = rf_set_tx_power(prop_radio.rf_handle, TX_POWER_TABLE, (int8_t)value); + return (res == RF_RESULT_OK) + ? RADIO_RESULT_OK + : RADIO_RESULT_ERROR; case RADIO_PARAM_RX_MODE: return RADIO_RESULT_OK; @@ -817,26 +727,6 @@ set_value(radio_param_t param, radio_value_t value) default: return RADIO_RESULT_NOT_SUPPORTED; } - - /* If we reach here we had no errors. Apply new settings */ - if (rx_active()) { - stop_rx(); - /* TODO fix this */ - if (rf_run_setup() != CMD_RESULT_OK) { - return RADIO_RESULT_ERROR; - } - start_rx(); - } else if (tx_active()) { - /* Should not happen. TX is always synchronous and blocking. */ - /* Todo: maybe remove completely here. */ - PRINTF("set_value: cannot apply new value while transmitting. \n"); - return RADIO_RESULT_ERROR; - } else { - /* was powered off. Nothing to do. New values will be */ - /* applied automatically on next power-up. */ - } - - return RADIO_RESULT_OK; } /*---------------------------------------------------------------------------*/ static radio_result_t @@ -856,30 +746,17 @@ init(void) { if (prop_radio.rf_handle) { PRINTF("init: Radio already initialized\n"); - return CMD_RESULT_OK; + return RF_RESULT_OK; } - /* Zero initalize TX and RX buffers */ - memset(prop_radio.tx_buf, 0x0, sizeof(prop_radio.tx_buf)); - memset(prop_radio.rx_bufs, 0x0, sizeof(prop_radio.rx_bufs)); - - /* Circular buffer, no last entry */ - prop_radio.rx_data_queue.pCurrEntry = prop_radio.rx_bufs[0].buf; - prop_radio.rx_data_queue.pLastEntry = NULL; - - /* Initialize current read pointer to first element (used in ISR) */ - prop_radio.rx_read_entry = &prop_radio.rx_bufs[0].data_entry; - - /* Set configured RSSI threshold */ - prop_radio.rssi_threshold = PROP_MODE_RSSI_THRESHOLD; - /* RX is off */ prop_radio.rf_is_on = false; - /* Configure RX command */ - cmd_rx.maxPktLen = DOT_4G_MAX_FRAME_LEN - cmd_rx.lenOffset; - cmd_rx.pQueue = &prop_radio.rx_data_queue; - cmd_rx.pOutput = (uint8_t *)&prop_radio.rx_stats; + /* Set configured RSSI threshold */ + prop_radio.rssi_threshold = PROP_MODE_RSSI_THRESHOLD; + + init_rf_params(); + init_data_queue(); /* Init RF params and specify non-default params */ RF_Params rf_params; @@ -887,11 +764,11 @@ init(void) rf_params.nInactivityTimeout = 2000; /* 2 ms */ /* Open RF Driver */ - prop_radio.rf_handle = RF_open(&prop_radio.rf_object, &rf_prop_mode, - (RF_RadioSetup*)&cmd_radio_setup, &rf_params); + prop_radio.rf_handle = netstack_open(&rf_params); + if (prop_radio.rf_handle == NULL) { PRINTF("init: unable to open RF driver\n"); - return CMD_RESULT_ERROR; + return RF_RESULT_ERROR; } set_channel(PROP_MODE_CHANNEL); @@ -899,9 +776,9 @@ init(void) ENERGEST_ON(ENERGEST_TYPE_LISTEN); /* Start RF process */ - process_start(&rf_process, NULL); + process_start(&rf_core_process, NULL); - return CMD_RESULT_OK; + return RF_RESULT_OK; } /*---------------------------------------------------------------------------*/ const struct radio_driver prop_mode_driver = { diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.c index c8a350ca8..53509c1bf 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.c @@ -51,7 +51,7 @@ #include "ble-settings.h" /*---------------------------------------------------------------------------*/ // TI-RTOS RF Mode Object -RF_Mode RF_ble = +RF_Mode rf_ble_mode = { .rfMode = RF_MODE_BLE, .cpePatchFxn = &rf_patch_cpe_ble, @@ -64,7 +64,7 @@ RF_Mode RF_ble = // RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) // See the Technical Reference Manual for further details about the "txPower" Command field. // The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. -RF_TxPowerTable_Entry txPowerTable[TX_POWER_TABLE_SIZE] = +RF_TxPowerTable_Entry rf_ble_tx_power_table[RF_BLE_TX_POWER_TABLE_SIZE+1] = { { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 3, 1, 6) }, { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 1, 6) }, @@ -119,7 +119,7 @@ uint32_t rf_ble_overrides[] CC_ALIGN(4) = /*---------------------------------------------------------------------------*/ // CMD_RADIO_SETUP // Radio Setup Command for Pre-Defined Schemes -rfc_CMD_RADIO_SETUP_t rf_ble_cmd_radiosetup = +rfc_CMD_RADIO_SETUP_t rf_ble_cmd_radio_setup = { .commandNo = 0x0802, .status = 0x0000, @@ -141,30 +141,6 @@ rfc_CMD_RADIO_SETUP_t rf_ble_cmd_radiosetup = .pRegOverride = rf_ble_overrides, }; /*---------------------------------------------------------------------------*/ -// CMD_FS -// Frequency Synthesizer Programming Command -rfc_CMD_FS_t rf_ble_cmd_fs = -{ - .commandNo = 0x0803, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .frequency = 0x0988, - .fractFreq = 0x0000, - .synthConf.bTxMode = 0x0, - .synthConf.refFreq = 0x0, - .__dummy0 = 0x00, - .__dummy1 = 0x00, - .__dummy2 = 0x00, - .__dummy3 = 0x0000, -}; -/*---------------------------------------------------------------------------*/ // Structure for CMD_BLE_ADV_NC.pParams rfc_bleAdvPar_t rf_ble_adv_par = { diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.h index 4edba3386..3da978339 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.h @@ -48,8 +48,8 @@ extern RF_TxPowerTable_Entry rf_ble_tx_power_table[RF_BLE_TX_POWER_TABLE_SIZE+1] extern RF_Mode rf_ble_mode; /*---------------------------------------------------------------------------*/ // RF Core API commands -extern rfc_CMD_RADIO_SETUP_t rf_ble_cmd_radiosetup; -extern rfc_CMD_FS_t rf_ble_cmd_fs; +extern rfc_CMD_RADIO_SETUP_t rf_ble_cmd_radio_setup; +extern rfc_bleAdvPar_t rf_ble_adv_par; extern rfc_CMD_BLE_ADV_NC_t rf_ble_cmd_ble_adv_nc; /*---------------------------------------------------------------------------*/ // RF Core API Overrides diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.c index 0a41cefd5..86fbd4f47 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.c @@ -1,49 +1,73 @@ -//********************************************************************************* -// Generated by SmartRF Studio version 2.10.0 (build#106) -// Compatible with SimpleLink SDK version: CC13x2 SDK 2.20.xx.xx -// Device: CC1352R Rev. 1.1 -// -//********************************************************************************* - - -//********************************************************************************* +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ // Parameter summary -// Adv. Address: 010203040506 -// Adv. Data: dummy -// BLE Channel: 17 -// Extended Header: 09 09 010203040506 babe +// Adv. Address: 010203040506 +// Adv. Data: dummy +// BLE Channel: 17 +// Extended Header: 09 09 010203040506 babe // Frequency: 2440 MHz -// PDU Payload length:: 30 +// PDU Payload length:: 30 // TX Power: 5 dBm (requires define CCFG_FORCE_VDDR_HH = 0 in ccfg.c, see CC13xx/CC26xx Technical Reference Manual) -// Whitening: true - +// Whitening: true +/*---------------------------------------------------------------------------*/ +#include "sys/cc.h" +/*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) #include DeviceFamily_constructPath(driverlib/rf_ble_cmd.h) -#include #include DeviceFamily_constructPath(rf_patches/rf_patch_cpe_bt5.h) #include DeviceFamily_constructPath(rf_patches/rf_patch_rfe_bt5.h) #include DeviceFamily_constructPath(rf_patches/rf_patch_mce_bt5.h) + +#include + #include "ble-settings.h" - - +/*---------------------------------------------------------------------------*/ // TI-RTOS RF Mode Object -RF_Mode RF_prop = +RF_Mode rf_ble_mode = { .rfMode = RF_MODE_AUTO, .cpePatchFxn = &rf_patch_cpe_bt5, .mcePatchFxn = &rf_patch_mce_bt5, .rfePatchFxn = &rf_patch_rfe_bt5, }; - +/*---------------------------------------------------------------------------*/ // TX Power table // The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: // RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) // See the Technical Reference Manual for further details about the "txPower" Command field. // The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. -RF_TxPowerTable_Entry txPowerTable[TX_POWER_TABLE_SIZE] = -{ +RF_TxPowerTable_Entry rf_ble_tx_power_table[RF_BLE_TX_POWER_TABLE_SIZE+1] = +{ {-21, RF_TxPowerTable_DEFAULT_PA_ENTRY(7, 3, 0, 3) }, {-18, RF_TxPowerTable_DEFAULT_PA_ENTRY(9, 3, 0, 3) }, {-15, RF_TxPowerTable_DEFAULT_PA_ENTRY(8, 2, 0, 6) }, @@ -61,98 +85,65 @@ RF_TxPowerTable_Entry txPowerTable[TX_POWER_TABLE_SIZE] = {5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, RF_TxPowerTable_TERMINATION_ENTRY }; - - +/*---------------------------------------------------------------------------*/ // Overrides for CMD_BLE5_RADIO_SETUP -uint32_t pOverridesCommon[] = +uint32_t rf_ble_overrides_common[] CC_ALIGN(4) = { - // override_ble5_setup_override_common.xml - // Synth: Use 48 MHz crystal, enable extra PLL filtering - (uint32_t)0x02400403, - // Synth: Configure extra PLL filtering - (uint32_t)0x001C8473, - // Synth: Configure synth hardware - (uint32_t)0x00088433, - // Synth: Set minimum RTRIM to 3 - (uint32_t)0x00038793, - // Synth: Configure faster calibration - HW32_ARRAY_OVERRIDE(0x4004,1), - // Synth: Configure faster calibration - (uint32_t)0x1C0C0618, - // Synth: Configure faster calibration - (uint32_t)0xC00401A1, - // Synth: Configure faster calibration - (uint32_t)0x00010101, - // Synth: Configure faster calibration - (uint32_t)0xC0040141, - // Synth: Configure faster calibration - (uint32_t)0x00214AD3, - // Synth: Decrease synth programming time-out (0x0298 RAT ticks = 166 us) - (uint32_t)0x02980243, - // DC/DC regulator: In Tx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). - (uint32_t)0xFCFC08C3, - // Rx: Set LNA bias current offset to adjust +3 (default: 0) - (uint32_t)0x00038883, - // Rx: Set RSSI offset to adjust reported RSSI by -2 dB (default: 0) - (uint32_t)0x000288A3, - // Bluetooth 5: Compensate for reduced pilot tone length - (uint32_t)0x01080263, - // Bluetooth 5: Compensate for reduced pilot tone length - (uint32_t)0x08E90AA3, - // Bluetooth 5: Compensate for reduced pilot tone length - (uint32_t)0x00068BA3, - // Bluetooth 5: Set correct total clock accuracy for received AuxPtr assuming local sleep clock of 50 ppm - (uint32_t)0x0E490C83, - // override_frontend_id.xml + // override_ble5_setup_override_common.xml + (uint32_t)0x02400403, // Synth: Use 48 MHz crystal, enable extra PLL filtering + (uint32_t)0x001C8473, // Synth: Configure extra PLL filtering + (uint32_t)0x00088433, // Synth: Configure synth hardware + (uint32_t)0x00038793, // Synth: Set minimum RTRIM to 3 + HW32_ARRAY_OVERRIDE(0x4004,1), // Synth: Configure faster calibration + (uint32_t)0x1C0C0618, // Synth: Configure faster calibration + (uint32_t)0xC00401A1, // Synth: Configure faster calibration + (uint32_t)0x00010101, // Synth: Configure faster calibration + (uint32_t)0xC0040141, // Synth: Configure faster calibration + (uint32_t)0x00214AD3, // Synth: Configure faster calibration + (uint32_t)0x02980243, // Synth: Decrease synth programming time-out (0x0298 RAT ticks = 166 us) + (uint32_t)0xFCFC08C3, // DC/DC regulator: In Tx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). + (uint32_t)0x00038883, // Rx: Set LNA bias current offset to adjust +3 (default: 0) + (uint32_t)0x000288A3, // Rx: Set RSSI offset to adjust reported RSSI by -2 dB (default: 0) + (uint32_t)0x01080263, // Bluetooth 5: Compensate for reduced pilot tone length + (uint32_t)0x08E90AA3, // Bluetooth 5: Compensate for reduced pilot tone length + (uint32_t)0x00068BA3, // Bluetooth 5: Compensate for reduced pilot tone length + (uint32_t)0x0E490C83, // Bluetooth 5: Set correct total clock accuracy for received AuxPtr assuming local sleep clock of 50 ppm (uint32_t)0xFFFFFFFF, }; - - +/*---------------------------------------------------------------------------*/ // Overrides for CMD_BLE5_RADIO_SETUP -uint32_t pOverrides1Mbps[] = +uint32_t rf_ble_overrides_1mbps[] CC_ALIGN(4) = { - // override_ble5_setup_override_1mbps.xml - // PHY: Use MCE RAM patch (mode 0), RFE RAM patch (mode 0) - MCE_RFE_OVERRIDE(1,0,0,1,0,0), - // Bluetooth 5: Reduce pilot tone length - HW_REG_OVERRIDE(0x5320,0x0240), - // Bluetooth 5: Compensate for reduced pilot tone length - (uint32_t)0x013302A3, + // override_ble5_setup_override_1mbps.xml + MCE_RFE_OVERRIDE(1,0,0,1,0,0), // PHY: Use MCE RAM patch (mode 0), RFE RAM patch (mode 0) + HW_REG_OVERRIDE(0x5320,0x0240), // Bluetooth 5: Reduce pilot tone length + (uint32_t)0x013302A3, // Bluetooth 5: Compensate for reduced pilot tone length (uint32_t)0xFFFFFFFF, }; - - +/*---------------------------------------------------------------------------*/ // Overrides for CMD_BLE5_RADIO_SETUP -uint32_t pOverrides2Mbps[] = +uint32_t rf_ble_overrides_2mbps[] CC_ALIGN(4) = { - // override_ble5_setup_override_2mbps.xml - // PHY: Use MCE RAM patch (mode 2), RFE RAM patch (mode 2) - MCE_RFE_OVERRIDE(1,0,2,1,0,2), - // Bluetooth 5: Reduce pilot tone length - HW_REG_OVERRIDE(0x5320,0x0240), - // Bluetooth 5: Compensate for reduced pilot tone length - (uint32_t)0x00D102A3, + // override_ble5_setup_override_2mbps.xml + MCE_RFE_OVERRIDE(1,0,2,1,0,2), // PHY: Use MCE RAM patch (mode 2), RFE RAM patch (mode 2) + HW_REG_OVERRIDE(0x5320,0x0240), // Bluetooth 5: Reduce pilot tone length + (uint32_t)0x00D102A3, // Bluetooth 5: Compensate for reduced pilot tone length (uint32_t)0xFFFFFFFF, }; - - +/*---------------------------------------------------------------------------*/ // Overrides for CMD_BLE5_RADIO_SETUP -uint32_t pOverridesCoded[] = +uint32_t rf_ble_overrides_coded[] CC_ALIGN(4) = { - // override_ble5_setup_override_coded.xml - // PHY: Use MCE RAM patch (mode 1), RFE RAM patch (mode 1) - MCE_RFE_OVERRIDE(1,0,1,1,0,1), - // Bluetooth 5: Reduce pilot tone length - HW_REG_OVERRIDE(0x5320,0x0240), - // Bluetooth 5: Compensate for reduced pilot tone length - (uint32_t)0x078902A3, + // override_ble5_setup_override_coded.xml + MCE_RFE_OVERRIDE(1,0,1,1,0,1), // PHY: Use MCE RAM patch (mode 1), RFE RAM patch (mode 1) + HW_REG_OVERRIDE(0x5320,0x0240), // Bluetooth 5: Reduce pilot tone length + (uint32_t)0x078902A3, // Bluetooth 5: Compensate for reduced pilot tone length (uint32_t)0xFFFFFFFF, }; - - +/*---------------------------------------------------------------------------*/ // CMD_BLE5_RADIO_SETUP // Bluetooth 5 Radio Setup Command for all PHYs -rfc_CMD_BLE5_RADIO_SETUP_t RF_cmdBle5RadioSetup = +rfc_CMD_BLE5_RADIO_SETUP_t rf_cmd_ble5_radio_setup = { .commandNo = 0x1820, .status = 0x0000, @@ -172,38 +163,14 @@ rfc_CMD_BLE5_RADIO_SETUP_t RF_cmdBle5RadioSetup = .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, .txPower = 0x941E, - .pRegOverrideCommon = pOverridesCommon, - .pRegOverride1Mbps = pOverrides1Mbps, - .pRegOverride2Mbps = pOverrides2Mbps, - .pRegOverrideCoded = pOverridesCoded, + .pRegOverrideCommon = rf_ble_overrides_common, + .pRegOverride1Mbps = rf_ble_overrides_1mbps, + .pRegOverride2Mbps = rf_ble_overrides_2mbps, + .pRegOverrideCoded = rf_ble_overrides_coded, }; - -// CMD_FS -// Frequency Synthesizer Programming Command -rfc_CMD_FS_t RF_cmdFs = -{ - .commandNo = 0x0803, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .frequency = 0x0988, - .fractFreq = 0x0000, - .synthConf.bTxMode = 0x0, - .synthConf.refFreq = 0x0, - .__dummy0 = 0x00, - .__dummy1 = 0x00, - .__dummy2 = 0x00, - .__dummy3 = 0x0000, -}; - +/*---------------------------------------------------------------------------*/ // Structure for CMD_BLE5_ADV_AUX.pParams -rfc_ble5AdvAuxPar_t ble5AdvAuxPar = +rfc_ble5AdvAuxPar_t rf_ble5_adv_aux_par = { .pRxQ = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx .rxConfig.bAutoFlushIgnored = 0x0, @@ -229,10 +196,10 @@ rfc_ble5AdvAuxPar_t ble5AdvAuxPar = .pDeviceAddress = 0, // INSERT APPLICABLE POINTER: (uint16_t*)&xxx .pWhiteList = 0, // INSERT APPLICABLE POINTER: (uint32_t*)&xxx }; - +/*---------------------------------------------------------------------------*/ // CMD_BLE5_ADV_AUX // Bluetooth 5 Secondary Channel Advertiser Command -rfc_CMD_BLE5_ADV_AUX_t RF_cmdBle5AdvAux = +rfc_CMD_BLE5_ADV_AUX_t rf_cmd_ble5_adv_aux = { .commandNo = 0x1824, .status = 0x0000, @@ -251,58 +218,8 @@ rfc_CMD_BLE5_ADV_AUX_t RF_cmdBle5AdvAux = .phyMode.coding = 0x0, .rangeDelay = 0x00, .txPower = 0x0000, - .pParams = &ble5AdvAuxPar, - .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .tx20Power = 0x00000000, -}; - -// Structure for CMD_BLE5_GENERIC_RX.pParams -rfc_bleGenericRxPar_t bleGenericRxPar = -{ - .pRxQ = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx - .rxConfig.bAutoFlushIgnored = 0x0, - .rxConfig.bAutoFlushCrcErr = 0x0, - .rxConfig.bAutoFlushEmpty = 0x0, - .rxConfig.bIncludeLenByte = 0x1, - .rxConfig.bIncludeCrc = 0x1, - .rxConfig.bAppendRssi = 0x1, - .rxConfig.bAppendStatus = 0x1, - .rxConfig.bAppendTimestamp = 0x0, - .bRepeat = 0x01, - .__dummy0 = 0x0000, - .accessAddress = 0x8E89BED6, - .crcInit0 = 0x55, - .crcInit1 = 0x55, - .crcInit2 = 0x55, - .endTrigger.triggerType = 0x1, - .endTrigger.bEnaCmd = 0x0, - .endTrigger.triggerNo = 0x0, - .endTrigger.pastTrig = 0x0, - .endTime = 0x00000001, -}; - -// CMD_BLE5_GENERIC_RX -// Bluetooth 5 Generic Receiver Command -rfc_CMD_BLE5_GENERIC_RX_t RF_cmdBle5GenericRx = -{ - .commandNo = 0x1829, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .channel = 0x8C, - .whitening.init = 0x51, - .whitening.bOverride = 0x1, - .phyMode.mainMode = 0x0, - .phyMode.coding = 0x0, - .rangeDelay = 0x00, - .txPower = 0x0000, - .pParams = &bleGenericRxPar, + .pParams = &rf_ble5_adv_aux_par, .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx .tx20Power = 0x00000000, }; +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.h index 748abf786..423a4bff0 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.h @@ -1,44 +1,62 @@ -#ifndef _BLE-SETTINGS_H_ -#define _BLE-SETTINGS_H_ - -//********************************************************************************* -// Generated by SmartRF Studio version 2.10.0 (build#106) -// Compatible with SimpleLink SDK version: CC13x2 SDK 2.20.xx.xx -// Device: CC1352R Rev. 1.1 -// -//********************************************************************************* +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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 BLE_SETTINGS_H_ +#define BLE_SETTINGS_H_ +/*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) #include DeviceFamily_constructPath(driverlib/rf_ble_cmd.h) + #include - - +/*---------------------------------------------------------------------------*/ // TX Power table size definition -#define TX_POWER_TABLE_SIZE 16 - +#define RF_BLE_TX_POWER_TABLE_SIZE 15 // TX Power Table Object -extern RF_TxPowerTable_Entry txPowerTable[TX_POWER_TABLE_SIZE]; - - +extern RF_TxPowerTable_Entry rf_ble_tx_power_table[RF_BLE_TX_POWER_TABLE_SIZE+1]; +/*---------------------------------------------------------------------------*/ // TI-RTOS RF Mode Object -extern RF_Mode RF_prop; - - +extern RF_Mode rf_ble_mode; +/*---------------------------------------------------------------------------*/ // RF Core API commands -extern rfc_CMD_BLE5_RADIO_SETUP_t RF_cmdBle5RadioSetup; -extern rfc_CMD_FS_t RF_cmdFs; -extern rfc_CMD_BLE5_ADV_AUX_t RF_cmdBle5AdvAux; -extern rfc_CMD_BLE5_GENERIC_RX_t RF_cmdBle5GenericRx; - - +extern rfc_CMD_BLE5_RADIO_SETUP_t rf_cmd_ble5_radio_setup; +extern rfc_ble5AdvAuxPar_t rf_ble5_adv_aux_par; +extern rfc_CMD_BLE5_ADV_AUX_t rf_cmd_ble5_adv_aux; +/*---------------------------------------------------------------------------*/ // RF Core API Overrides -extern uint32_t pOverridesCommon[]; -extern uint32_t pOverrides1Mbps[]; -extern uint32_t pOverrides2Mbps[]; -extern uint32_t pOverridesCoded[]; - - -#endif // _BLE-SETTINGS_H_ - +extern uint32_t rf_ble_overrides_common[]; +extern uint32_t rf_ble_overrides_1mbps[]; +extern uint32_t rf_ble_overrides_2mbps[]; +extern uint32_t rf_ble_overrides_coded[]; +/*---------------------------------------------------------------------------*/ +#endif /* BLE_SETTINGS_H_ */ +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/netstack-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/netstack-settings.h new file mode 100644 index 000000000..16751b840 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/netstack-settings.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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 NETSTACK_SETTINGS_H_ +#define NETSTACK_SETTINGS_H_ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" + +#include +/*---------------------------------------------------------------------------*/ +#ifdef RF_CORE_CONF_PROP_RF_SETTINGS +# define RF_CORE_PROP_RF_SETTINGS RF_CORE_CONF_PROP_RF_SETTINGS +#else +# define RF_CORE_PROP_RF_SETTINGS "prop-settings.h" +#endif + +#include RF_CORE_PROP_RF_SETTINGS + +#ifdef RF_CORE_CONF_IEEE_RF_SETTINGS +# define RF_CORE_IEEE_RF_SETTINGS RF_CORE_CONF_IEEE_RF_SETTINGS +#else +# define RF_CORE_IEEE_RF_SETTINGS "ieee-settings.h" +#endif + +#include RF_CORE_IEEE_RF_SETTINGS +/*---------------------------------------------------------------------------*/ +/* Prop-mode RF settings */ +#if (RF_CORE_CONF_MODE == RF_CORE_MODE_SUB_1_GHZ) + +#define netstack_mode rf_prop_mode +#define netstack_cmd_radio_setup rf_cmd_prop_radio_div_setup +#define netstack_cmd_fs rf_cmd_prop_fs +#define netstack_cmd_tx rf_cmd_prop_tx_adv +#define netstack_cmd_rx rf_cmd_prop_rx_adv +/*---------------------------------------------------------------------------*/ +/* IEEE-mode RF settings */ +#elif (RF_CORE_CONF_MODE == RF_CORE_MODE_2_4_GHZ) + +#define netstack_mode rf_ieee_mode +#define netstack_cmd_radio_setup rf_cmd_ieee_radio_setup +#define netstack_cmd_fs rf_cmd_ieee_fs +#define netstack_cmd_tx rf_cmd_ieee_tx +#define netstack_cmd_rx rf_cmd_ieee_rx +/*---------------------------------------------------------------------------*/ +#else +# error "Unsupported RF_CORE_MODE" +#endif +/*---------------------------------------------------------------------------*/ +#include "ble-settings.h" + +#if (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0) + +#define ble_mode rf_ble_mode +#define ble_cmd_radio_setup rf_ble_cmd_radio_setup +#define ble_adv_par rf_ble_adv_par +#define ble_cmd_beacon rf_ble_cmd_ble_adv_nc + +#elif (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X2_CC26X2) + +#define ble_mode rf_ble_mode +#define ble_cmd_radio_setup rf_cmd_ble5_radio_setup +#define ble_adv_par rf_ble5_adv_aux_par +#define ble_cmd_beacon rf_cmd_ble5_adv_aux + +#else +# error "Unsupported DeviceFamily_PARENT for BLE settings" +#endif +/*---------------------------------------------------------------------------*/ +#endif /* NETSTACK_SETTINGS_H_ */ +/*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/platform.c b/arch/platform/simplelink/cc13xx-cc26xx/platform.c index 948f5e589..0c9accfa6 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/platform.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/platform.c @@ -83,7 +83,7 @@ #include "uart0-arch.h" /*---------------------------------------------------------------------------*/ #include "ieee-addr.h" -#include "dev/rf-common.h" +#include "rf-core.h" #include "lib/random.h" #include "button-sensor.h" /*---------------------------------------------------------------------------*/ From 41cb9dd66c2e643ebb9ab3f603ed5b64d06a5187 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Tue, 10 Jul 2018 18:57:01 +0200 Subject: [PATCH 262/485] Implemented RX_ACK for IEEE-mode --- arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c | 67 ++++++++++++++++--- .../rf-settings/cc13x0/ieee-settings.c | 22 ++++++ .../rf-settings/cc13x0/ieee-settings.h | 1 + .../rf-settings/cc13x2/ieee-settings.c | 22 ++++++ .../rf-settings/cc13x2/ieee-settings.h | 1 + .../rf-settings/cc26x0/ieee-settings.c | 22 ++++++ .../rf-settings/cc26x0/ieee-settings.h | 1 + .../rf-settings/cc26x2/ieee-settings.c | 22 ++++++ .../rf-settings/cc26x2/ieee-settings.h | 1 + 9 files changed, 149 insertions(+), 10 deletions(-) diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c index f902e76a5..400b18ff9 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c @@ -171,11 +171,13 @@ #define STATUS_REJECT_FRAME 0x40 /* bit 6 */ #define STATUS_CRC_FAIL 0x80 /* bit 7 */ /*---------------------------------------------------------------------------*/ -/* TX buf configuration */ -#define TX_BUF_HDR_LEN 2 -#define TX_BUF_PAYLOAD_LEN 180 +#define FRAME_FCF_OFFSET 0 +#define FRAME_SEQNUM_OFFSET 2 -#define TX_BUF_SIZE (TX_BUF_HDR_LEN + TX_BUF_PAYLOAD_LEN) +#define FRAME_ACK_REQUEST 0x20 /* bit 5 */ + +/* TX buf configuration */ +#define TX_BUF_SIZE 180 /* RX buf configuration */ #ifdef IEEE_MODE_CONF_RX_BUF_CNT @@ -260,6 +262,7 @@ static cmd_mod_filt_t cmd_mod_filt; #define cmd_fs (*(volatile rfc_CMD_FS_t*) &rf_cmd_ieee_fs) #define cmd_tx (*(volatile rfc_CMD_IEEE_TX_t*) &rf_cmd_ieee_tx) #define cmd_rx (*(volatile rfc_CMD_IEEE_RX_t*) &rf_cmd_ieee_rx) +#define cmd_rx_ack (*(volatile rfc_CMD_IEEE_RX_ACK_t*)&rf_cmd_ieee_rx_ack) /*---------------------------------------------------------------------------*/ static inline bool rx_is_active(void) { return cmd_rx.status == ACTIVE; } /*---------------------------------------------------------------------------*/ @@ -356,6 +359,17 @@ init_rf_params(void) cmd_rx.ccaRssiThr = IEEE_MODE_RSSI_THRESHOLD; + cmd_tx.pNextOp = (RF_Op*)&cmd_rx_ack; + cmd_tx.condition.rule = COND_NEVER; /* Initially ACK turned off */ + + cmd_rx_ack.startTrigger.triggerType = TRIG_NOW; + cmd_rx_ack.endTrigger.triggerType = TRIG_REL_SUBMIT; + /* + * ACK packet is transmitted 192 us after the end of the received packet. + * See TRM Section ACK Transmission for more info. + */ + cmd_rx_ack.endTime = RF_convertUsToRatTicks(195); + /* Initialize address filter command */ cmd_mod_filt.commandNo = CMD_IEEE_MOD_FILT; memcpy(&(cmd_mod_filt.newFrameFiltOpt), &(rf_cmd_ieee_rx.frameFiltOpt), sizeof(rf_cmd_ieee_rx.frameFiltOpt)); @@ -532,9 +546,9 @@ static int prepare(const void *payload, unsigned short payload_len) { const size_t len = MIN((size_t)payload_len, - (size_t)TX_BUF_PAYLOAD_LEN); + (size_t)TX_BUF_SIZE); - memcpy(ieee_radio.tx_buf + TX_BUF_HDR_LEN, payload, len); + memcpy(ieee_radio.tx_buf, payload, len); return 0; } /*---------------------------------------------------------------------------*/ @@ -548,15 +562,48 @@ transmit(unsigned short transmit_len) return RADIO_TX_COLLISION; } + /* + * Are we expecting ACK? The ACK Request flag is in the first Frame + * Control Field byte, that is the first byte in the frame. + */ + const bool ack_request = (bool)(ieee_radio.tx_buf[FRAME_FCF_OFFSET] & FRAME_ACK_REQUEST); + if (ack_request) { + /* Yes, turn on chaining */ + cmd_tx.condition.rule = COND_STOP_ON_FALSE; + + /* Reset CMD_IEEE_RX_ACK command */ + cmd_rx_ack.status = IDLE; + /* Sequence number is the third byte in the frame */ + cmd_rx_ack.seqNo = ieee_radio.tx_buf[FRAME_SEQNUM_OFFSET]; + } else { + /* No, turn off chaining */ + cmd_tx.condition.rule = COND_NEVER; + } + /* Configure TX command */ cmd_tx.payloadLen = (uint8_t)transmit_len; - cmd_tx.pPayload = &ieee_radio.tx_buf[TX_BUF_HDR_LEN]; + cmd_tx.pPayload = ieee_radio.tx_buf; res = netstack_sched_tx(NULL, 0); - return (res == RF_RESULT_OK) - ? RADIO_TX_OK - : RADIO_TX_ERR; + if (res != RF_RESULT_OK) { + return RADIO_TX_ERR; + } + + if (ack_request) { + switch(cmd_rx_ack.status) { + /* CMD_IEEE_RX_ACK timed out, i.e. never received ACK */ + case IEEE_DONE_TIMEOUT: return RADIO_TX_NOACK; + /* An ACK was received with either pending data bit set or cleared */ + case IEEE_DONE_ACK: /* fallthrough */ + case IEEE_DONE_ACKPEND: return RADIO_TX_OK; + /* Any other statuses are errors */ + default: return RADIO_TX_ERR; + } + } + + /* No ACK expected, TX OK */ + return RADIO_TX_OK; } /*---------------------------------------------------------------------------*/ static int diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c index cfe9ef9a7..7a455862c 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c @@ -245,3 +245,25 @@ rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx = .endTime = 0x00000000, }; /*---------------------------------------------------------------------------*/ +// CMD_IEEE_RX_ACK +// IEEE 802.15.4 Receive ACK Command +rfc_CMD_IEEE_RX_ACK_t rf_cmd_ieee_rx_ack = +{ + .commandNo = CMD_IEEE_RX_ACK, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .seqNo = 0x0, + .endTrigger.triggerType = TRIG_NEVER, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, +}; +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h index 5276887b4..305b56855 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h @@ -54,6 +54,7 @@ extern rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup; extern rfc_CMD_FS_t rf_cmd_ieee_fs; extern rfc_CMD_IEEE_TX_t rf_cmd_ieee_tx; extern rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx; +extern rfc_CMD_IEEE_RX_ACK_t rf_cmd_ieee_rx_ack; /*---------------------------------------------------------------------------*/ // RF Core API Overrides extern uint32_t rf_ieee_overrides[]; diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c index efa12e2f6..86892b571 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c @@ -296,3 +296,25 @@ rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx = .endTime = 0x00000000, }; /*---------------------------------------------------------------------------*/ +// CMD_IEEE_RX_ACK +// IEEE 802.15.4 Receive ACK Command +rfc_CMD_IEEE_RX_ACK_t rf_cmd_ieee_rx_ack = +{ + .commandNo = CMD_IEEE_RX_ACK, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .seqNo = 0x0, + .endTrigger.triggerType = TRIG_NEVER, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, +}; +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h index fdb722ab8..5f6a6eb2e 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h @@ -54,6 +54,7 @@ extern rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup; extern rfc_CMD_FS_t rf_cmd_ieee_fs; extern rfc_CMD_IEEE_TX_t rf_cmd_ieee_tx; extern rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx; +extern rfc_CMD_IEEE_RX_ACK_t rf_cmd_ieee_rx_ack; /*---------------------------------------------------------------------------*/ // RF Core API Overrides extern uint32_t rf_ieee_overrides_default_pa[]; diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c index 92720c63b..f2fb6963c 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c @@ -245,3 +245,25 @@ rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx = .endTime = 0x00000000, }; /*---------------------------------------------------------------------------*/ +// CMD_IEEE_RX_ACK +// IEEE 802.15.4 Receive ACK Command +rfc_CMD_IEEE_RX_ACK_t rf_cmd_ieee_rx_ack = +{ + .commandNo = CMD_IEEE_RX_ACK, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .seqNo = 0x0, + .endTrigger.triggerType = TRIG_NEVER, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, +}; +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h index ff63f2c7e..55434276c 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h @@ -52,6 +52,7 @@ extern rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup; extern rfc_CMD_FS_t rf_cmd_ieee_fs; extern rfc_CMD_IEEE_TX_t rf_cmd_ieee_tx; extern rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx; +extern rfc_CMD_IEEE_RX_ACK_t rf_cmd_ieee_rx_ack; /*---------------------------------------------------------------------------*/ // RF Core API Overrides extern uint32_t rf_ieee_overrides[]; diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c index 709314db6..17c9b686f 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c @@ -242,3 +242,25 @@ rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx = .endTime = 0x00000000, }; /*---------------------------------------------------------------------------*/ +// CMD_IEEE_RX_ACK +// IEEE 802.15.4 Receive ACK Command +rfc_CMD_IEEE_RX_ACK_t rf_cmd_ieee_rx_ack = +{ + .commandNo = CMD_IEEE_RX_ACK, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .seqNo = 0x0, + .endTrigger.triggerType = TRIG_NEVER, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, +}; +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h index f92283afc..7572a36fd 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h @@ -52,6 +52,7 @@ extern rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup; extern rfc_CMD_FS_t rf_cmd_ieee_fs; extern rfc_CMD_IEEE_TX_t rf_cmd_ieee_tx; extern rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx; +extern rfc_CMD_IEEE_RX_ACK_t rf_cmd_ieee_rx_ack; /*---------------------------------------------------------------------------*/ // RF Core API Overrides extern uint32_t rf_ieee_overrides[]; From 10805cbbe7a8c221952f0aa4d1630311984d71ac Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Tue, 10 Jul 2018 20:29:30 +0200 Subject: [PATCH 263/485] Fixed wrong prop-settins for CC13x0 --- .../rf-settings/cc13x0/prop-settings.c | 36 +++++++++---------- .../rf-settings/cc13x0/prop-settings.h | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c index 8c79d3ab7..ee344ac67 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c @@ -77,22 +77,22 @@ RF_Mode rf_prop_mode = // The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. RF_TxPowerTable_Entry rf_prop_tx_power_table[RF_PROP_TX_POWER_TABLE_SIZE+1] = { - { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY( 0, 3, 0, 2) }, - { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY( 3, 3, 0, 9) }, - { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 3, 0, 11) }, - { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY( 5, 3, 0, 12) }, - { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY( 6, 3, 0, 14) }, - { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 1, 0, 12) }, - { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 3, 0, 16) }, - { 6, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 18) }, - { 7, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 21) }, - { 8, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 3, 0, 25) }, - { 9, RF_TxPowerTable_DEFAULT_PA_ENTRY(18, 3, 0, 32) }, - { 10, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 3, 0, 44) }, - { 11, RF_TxPowerTable_DEFAULT_PA_ENTRY(37, 3, 0, 72) }, - { 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(43, 0, 0, 94) }, - // This setting requires CCFG_FORCE_VDDR_HH = 1. - { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 85) }, + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY( 0, 3, 0, 4) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY( 1, 1, 0, 0) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY( 3, 3, 0, 8) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY( 2, 1, 0, 8) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 3, 0, 10) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY( 5, 3, 0, 12) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY( 6, 3, 0, 12) }, + { 6, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 14) }, + { 7, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 16) }, + { 8, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 18) }, + { 9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 3, 0, 22) }, + { 10, RF_TxPowerTable_DEFAULT_PA_ENTRY(19, 3, 0, 28) }, + { 11, RF_TxPowerTable_DEFAULT_PA_ENTRY(26, 3, 0, 40) }, + { 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 0, 0, 92) }, + { 13, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 0, 83) }, // The original PA value (12.5 dBm) have been rounded to an integer value. + { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 83) }, // This setting requires CCFG_FORCE_VDDR_HH = 1. RF_TxPowerTable_TERMINATION_ENTRY }; /*---------------------------------------------------------------------------*/ @@ -151,7 +151,7 @@ rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup = .modulation.deviation = 0x64, .symbolRate.preScale = 0xF, .symbolRate.rateWord = 0x8000, - .rxBw = 0x52, + .rxBw = 0x24, .preamConf.nPreamBytes = 0x3, .preamConf.preamMode = 0x0, .formatConf.nSwBits = 0x18, @@ -163,7 +163,7 @@ rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup = .config.biasMode = 0x1, .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, - .txPower = 0xAB3F, + .txPower = 0xA73F, .pRegOverride = rf_prop_overrides, .centerFreq = 0x0364, .intFreq = 0x8000, diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h index cd95a3ace..d31c495bb 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h @@ -42,7 +42,7 @@ extern RF_Mode rf_prop_mode; /*---------------------------------------------------------------------------*/ // TX Power Table -#define RF_PROP_TX_POWER_TABLE_SIZE 15 +#define RF_PROP_TX_POWER_TABLE_SIZE 16 extern RF_TxPowerTable_Entry rf_prop_tx_power_table[RF_PROP_TX_POWER_TABLE_SIZE+1]; /*---------------------------------------------------------------------------*/ From 32fed691d43fa952f0862a2e3642699f8b9c6e49 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Tue, 10 Jul 2018 20:29:46 +0200 Subject: [PATCH 264/485] Added HardFault debugger function --- .../dev/startup_cc13xx_cc26xx_gcc.c | 36 ++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c b/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c index ac35116ef..019a14d69 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c +++ b/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c @@ -248,6 +248,29 @@ nmiISR(void) volatile int x__; +volatile uint32_t r0; +volatile uint32_t r1; +volatile uint32_t r2; +volatile uint32_t r3; +volatile uint32_t r12; +volatile uint32_t lr; +volatile uint32_t pc; +volatile uint32_t psr; + +void debugHardfault(uint32_t *sp) +{ + r0 = sp[0]; + r1 = sp[1]; + r2 = sp[2]; + r3 = sp[3]; + r12 = sp[4]; + lr = sp[5]; + pc = sp[6]; + psr = sp[7]; + + while(1); +} + //***************************************************************************** // // This is the code that gets called when the processor receives a fault @@ -258,11 +281,14 @@ volatile int x__; static void faultISR(void) { - x__ = 0; - /* Enter an infinite loop. */ - while(1) - { - } + __asm volatile + ( + "tst lr, #4 \n" + "ite eq \n" + "mrseq r0, msp \n" + "mrsne r0, psp \n" + "b debugHardfault \n" + ); } //***************************************************************************** From 9be3c05daaad512a86b1234461767f26c13b92c8 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Wed, 11 Jul 2018 10:27:57 +0200 Subject: [PATCH 265/485] Fixed bug in CMD_PROP_TX_ADV settings --- arch/cpu/cc13xx-cc26xx/dev/rf-core.c | 2 +- .../cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c | 12 ++++++------ .../cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-core.c b/arch/cpu/cc13xx-cc26xx/dev/rf-core.c index 17a8919f7..694eb2c00 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-core.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-core.c @@ -273,7 +273,7 @@ netstack_sched_tx(RF_Callback cb, RF_EventMask bm_event) /* * IEEE_TX can be scheduled while IEEE_RX is running, as the radio supports - * FG commandos to be scheduled while a BG commando is running. + * FG commands to be scheduled while a BG command is running. * For Prop-mode, RX must be turned off as usual. */ const uint_fast8_t rx_key = (RF_CORE_CONF_MODE != RF_CORE_MODE_2_4_GHZ) diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c index ee344ac67..82eb40180 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c @@ -141,7 +141,7 @@ rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup = .status = IDLE, .pNextOp = 0, .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, + .startTrigger.triggerType = TRIG_NOW, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, @@ -152,7 +152,7 @@ rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup = .symbolRate.preScale = 0xF, .symbolRate.rateWord = 0x8000, .rxBw = 0x24, - .preamConf.nPreamBytes = 0x3, + .preamConf.nPreamBytes = 0x7, .preamConf.preamMode = 0x0, .formatConf.nSwBits = 0x18, .formatConf.bBitReversal = 0x0, @@ -178,7 +178,7 @@ rfc_CMD_FS_t rf_cmd_prop_fs = .status = IDLE, .pNextOp = 0, .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, + .startTrigger.triggerType = TRIG_NOW, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, @@ -202,10 +202,10 @@ rfc_CMD_PROP_TX_ADV_t rf_cmd_prop_tx_adv = .status = IDLE, .pNextOp = 0, .startTime = 0x00000000, - .startTrigger.triggerType = 0x2, + .startTrigger.triggerType = TRIG_NOW, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x1, + .startTrigger.pastTrig = 0x0, .condition.rule = COND_NEVER, .condition.nSkip = 0x0, .pktConf.bFsOff = 0x0, @@ -213,7 +213,7 @@ rfc_CMD_PROP_TX_ADV_t rf_cmd_prop_tx_adv = .pktConf.bCrcIncSw = 0x0, .pktConf.bCrcIncHdr = 0x0, .numHdrBits = 0x10, - .pktLen = 0x0000, + .pktLen = 0x0, /* set by driver */ .startConf.bExtTxTrig = 0x0, .startConf.inputMode = 0x0, .startConf.source = 0x0, diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c index c3a286058..7cc4d0046 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c @@ -218,7 +218,7 @@ rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup = .symbolRate.rateWord = 0x8000, .symbolRate.decimMode = 0x0, .rxBw = 0x52, - .preamConf.nPreamBytes = 0x3, + .preamConf.nPreamBytes = 0x7, .preamConf.preamMode = 0x0, .formatConf.nSwBits = 0x18, .formatConf.bBitReversal = 0x0, @@ -289,7 +289,7 @@ rfc_CMD_PROP_TX_ADV_t rf_cmd_prop_tx_adv = .preTrigger.pastTrig = 0x1, .preTime = 0x00000000, .syncWord = 0x0055904E, - .pPkt = 0, + .pPkt = 0, /* set by driver */ }; /*---------------------------------------------------------------------------*/ // CMD_PROP_RX_ADV From e0bd086b3bd784a3e0a5fc202f23fb9eefcf2b8e Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Thu, 12 Jul 2018 10:44:14 +0200 Subject: [PATCH 266/485] Ported BLE beacond, fixed IEEE_RX_ACK. --- arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 5 +- arch/cpu/cc13xx-cc26xx/dev/ble-addr.c | 52 +- arch/cpu/cc13xx-cc26xx/dev/ble-addr.h | 3 + arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.c | 376 ++++-------- arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.h | 35 +- arch/cpu/cc13xx-cc26xx/dev/rf-core.c | 155 +++-- arch/cpu/cc13xx-cc26xx/dev/rf-core.h | 9 +- arch/cpu/cc13xx-cc26xx/dev/rf-data-queue.c | 166 ++++++ arch/cpu/cc13xx-cc26xx/dev/rf-data-queue.h | 54 ++ arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c | 197 ++----- arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c | 136 +---- .../rf-settings/cc13x0/ble-settings.c | 262 ++++----- .../rf-settings/cc13x0/ble-settings.h | 10 +- .../rf-settings/cc13x0/ieee-settings.c | 392 ++++++------- .../rf-settings/cc13x0/ieee-settings.h | 14 +- .../rf-settings/cc13x0/prop-settings.c | 424 +++++++------- .../rf-settings/cc13x0/prop-settings.h | 8 +- .../rf-settings/cc13x2/ble-settings.c | 295 +++++----- .../rf-settings/cc13x2/ble-settings.h | 10 +- .../rf-settings/cc13x2/ieee-settings.c | 477 +++++++-------- .../rf-settings/cc13x2/ieee-settings.h | 8 +- .../rf-settings/cc13x2/prop-settings.c | 541 +++++++++--------- .../rf-settings/cc13x2/prop-settings.h | 8 +- .../rf-settings/cc26x0/ble-settings.c | 410 ++++++------- .../rf-settings/cc26x0/ble-settings.h | 88 +-- .../rf-settings/cc26x0/ieee-settings.c | 387 +++++++------ .../rf-settings/cc26x0/ieee-settings.h | 8 +- .../rf-settings/cc26x2/ble-settings.c | 488 +++++++--------- .../rf-settings/cc26x2/ble-settings.h | 94 +-- .../rf-settings/cc26x2/ieee-settings.c | 381 ++++++------ .../rf-settings/cc26x2/ieee-settings.h | 8 +- .../rf-settings/netstack-settings.h | 28 +- .../simplelink/cc13xx-cc26xx/platform.c | 3 + 33 files changed, 2747 insertions(+), 2785 deletions(-) create mode 100644 arch/cpu/cc13xx-cc26xx/dev/rf-data-queue.c create mode 100644 arch/cpu/cc13xx-cc26xx/dev/rf-data-queue.h diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index a0f4c688c..c27795655 100644 --- a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -74,9 +74,9 @@ CONTIKI_CPU_SOURCEFILES += batmon-sensor.c gpio-hal-arch.c CONTIKI_CPU_SOURCEFILES += int-master-arch.c ### RF source files -CONTIKI_CPU_SOURCEFILES += rf-core.c +CONTIKI_CPU_SOURCEFILES += rf-core.c rf-data-queue.c CONTIKI_CPU_SOURCEFILES += ieee-addr.c ble-addr.c -#CONTIKI_CPU_SOURCEFILES += rf-ble-beacond.c +CONTIKI_CPU_SOURCEFILES += rf-ble-beacond.c ifeq ($(SUPPORTS_PROP_MODE),1) CONTIKI_CPU_SOURCEFILES += rf-prop-mode.c prop-settings.c @@ -88,7 +88,6 @@ endif ifeq ($(SUPPORTS_BLE_BEACON),1) CONTIKI_CPU_SOURCEFILES += ble-settings.c -#CONTIKI_CPU_SOURCEFILES += rf-ble-beacond.c endif ### CPU-dependent debug source files diff --git a/arch/cpu/cc13xx-cc26xx/dev/ble-addr.c b/arch/cpu/cc13xx-cc26xx/dev/ble-addr.c index f6343367c..11f4adf63 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/ble-addr.c +++ b/arch/cpu/cc13xx-cc26xx/dev/ble-addr.c @@ -53,6 +53,32 @@ #define BLE_MAC_PRIMARY_ADDRESS (FCFG1_BASE + FCFG1_O_MAC_BLE_0) #define BLE_MAC_SECONDARY_ADDRESS (CCFG_BASE + CCFG_O_IEEE_BLE_0) /*---------------------------------------------------------------------------*/ +uint8_t* +ble_addr_ptr(void) +{ + volatile const uint8_t * const primary = (uint8_t *)BLE_MAC_PRIMARY_ADDRESS; + volatile const uint8_t * const secondary = (uint8_t *)BLE_MAC_SECONDARY_ADDRESS; + + /* + * Reading from primary location... + * ...unless we can find a byte != 0xFF in secondary + * + * Intentionally checking all bytes here instead of len, because we + * are checking validity of the entire address irrespective of the + * actual number of bytes the caller wants to copy over. + */ + size_t i; + for(i = 0; i < BLE_ADDR_SIZE; i++) { + if(secondary[i] != 0xFF) { + /* A byte in secondary is not 0xFF. Use secondary address. */ + return (uint8_t*)secondary; + } + } + + /* All bytes in secondary is 0xFF. Use primary address. */ + return (uint8_t*)primary; +} +/*---------------------------------------------------------------------------*/ int ble_addr_cpy(uint8_t *dst) { @@ -60,35 +86,15 @@ ble_addr_cpy(uint8_t *dst) return -1; } - int i; - - const uint8_t * const primary = (uint8_t *)BLE_MAC_PRIMARY_ADDRESS; - const uint8_t * const secondary = (uint8_t *)BLE_MAC_SECONDARY_ADDRESS; - - /* Reading from primary location... */ - const uint8_t *ble_addr = primary; - - /* - * ...unless we can find a byte != 0xFF in secondary - * - * Intentionally checking all bytes here instead of len, because we - * are checking validity of the entire address irrespective of the - * actual number of bytes the caller wants to copy over. - */ - for(i = 0; i < BLE_ADDR_SIZE; i++) { - if(HWREG(secondary + i) != 0xFF) { - /* A byte in the secondary location is not 0xFF. Use the secondary */ - ble_addr = secondary; - break; - } - } + volatile const uint8_t *const ble_addr = ble_addr_ptr(); /* * We have chosen what address to read the BLE address from. Do so, * inverting byte order */ + size_t i; for(i = 0; i < BLE_ADDR_SIZE; i++) { - dst[i] = HWREG(ble_addr + BLE_ADDR_SIZE - 1 - i); + dst[i] = ble_addr[BLE_ADDR_SIZE - 1 - i]; } return 0; diff --git a/arch/cpu/cc13xx-cc26xx/dev/ble-addr.h b/arch/cpu/cc13xx-cc26xx/dev/ble-addr.h index 7e9853633..9a7901675 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/ble-addr.h +++ b/arch/cpu/cc13xx-cc26xx/dev/ble-addr.h @@ -28,6 +28,7 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. * */ +/*---------------------------------------------------------------------------*/ /** * \file * Driver for the retrieval of an BLE address from flash @@ -43,6 +44,8 @@ #include /*---------------------------------------------------------------------------*/ +uint8_t* ble_addr_ptr(void); +/*---------------------------------------------------------------------------*/ /** * \brief Copy the node's factory BLE address to a destination memory area * \param dst A pointer to the destination area where the BLE address is to be diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.c b/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.c index 25d14190a..2643f4f0f 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.c @@ -45,7 +45,7 @@ #include "net/netstack.h" #include "net/linkaddr.h" -#include "netstack-settings.h" +#include "rf-ble-beacond.h" /*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/chipinfo.h) @@ -53,7 +53,10 @@ #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) #include -#include +/*---------------------------------------------------------------------------*/ +#include "netstack-settings.h" +#include "rf-core.h" +#include "ble-addr.h" /*---------------------------------------------------------------------------*/ #include #include @@ -67,42 +70,25 @@ #define PRINTF(...) #endif /*---------------------------------------------------------------------------*/ -#if RF_BLE_BEACOND_ENABLED +#if !(RF_BLE_BEACOND_ENABLED) /*---------------------------------------------------------------------------*/ -rf_ble_beacond_result_e -rf_ble_beacond_config(clock_time_t interval, const char *name) -{ - return RF_BLE_BEACOND_DISABLED; -} +rf_ble_beacond_result_t +rf_ble_beacond_init(void) { return RF_BLE_BEACOND_DISABLED; } /*---------------------------------------------------------------------------*/ -rf_ble_beacond_result_e -rf_ble_beacond_start(void) -{ - return RF_BLE_BEACOND_DISABLED; -} +rf_ble_beacond_result_t +rf_ble_beacond_start(clock_time_t interval, const char *name) { return RF_BLE_BEACOND_DISABLED; } /*---------------------------------------------------------------------------*/ -rf_ble_beacond_result_e rf_ble_beacond_stop(void) -{ - return RF_BLE_BEACOND_DISABLED; -} +rf_ble_beacond_result_t +rf_ble_beacond_stop(void) { return RF_BLE_BEACOND_DISABLED; } /*---------------------------------------------------------------------------*/ -uint8_t -rf_ble_is_active(void) -{ - return 0; -} +int8_t +rf_ble_is_active(void) { return -1; } /*---------------------------------------------------------------------------*/ -rf_ble_beacond_result_e -rf_ble_set_tx_power(radio_value_t power) -{ - return RF_BLE_BEACOND_DISABLED; -} +rf_ble_beacond_result_t +rf_ble_set_tx_power(int8_t power) { return RF_BLE_BEACOND_DISABLED; } /*---------------------------------------------------------------------------*/ -radio_value_t -rf_ble_get_tx_power(void); -{ - return (radio_value_t)0; -} +int8_t +rf_ble_get_tx_power(void) { return ~(int8_t)(0); } /*---------------------------------------------------------------------------*/ #else /* RF_BLE_BEACOND_ENABLED */ /*---------------------------------------------------------------------------*/ @@ -115,20 +101,23 @@ typedef enum { BLE_ADV_CHANNEL_MASK = BLE_ADV_CHANNEL_37 | BLE_ADV_CHANNEL_38 | BLE_ADV_CHANNEL_39, -} ble_adv_channel_e; +} ble_adv_channel_t; + +#define BLE_ADV_CHANNEL_MIN 37 +#define BLE_ADV_CHANNEL_MAX 39 /*---------------------------------------------------------------------------*/ /* Maximum BLE advertisement size. Not to be changed by the user. */ -#define BLE_ADV_MAX_SIZE 31 +#define BLE_ADV_MAX_SIZE 31 /*---------------------------------------------------------------------------*/ /* BLE Intervals: Send a burst of advertisements every BLE_ADV_INTERVAL secs */ -#define BLE_ADV_INTERVAL (CLOCK_SECOND * 5) -#define BLE_ADV_DUTY_CYCLE (CLOCK_SECOND / 10) -#define BLE_ADV_MESSAGES 10 +#define BLE_ADV_INTERVAL (CLOCK_SECOND * 5) +#define BLE_ADV_DUTY_CYCLE (CLOCK_SECOND / 10) +#define BLE_ADV_MESSAGES 10 /* BLE Advertisement-related macros */ -#define BLE_ADV_TYPE_DEVINFO 0x01 -#define BLE_ADV_TYPE_NAME 0x09 -#define BLE_ADV_TYPE_MANUFACTURER 0xFF +#define BLE_ADV_TYPE_DEVINFO 0x01 +#define BLE_ADV_TYPE_NAME 0x09 +#define BLE_ADV_TYPE_MANUFACTURER 0xFF #define BLE_ADV_NAME_BUF_LEN BLE_ADV_MAX_SIZE #define BLE_ADV_PAYLOAD_BUF_LEN 64 #define BLE_UUID_SIZE 16 @@ -136,7 +125,6 @@ typedef enum { typedef struct { /* Outgoing frame buffer */ uint8_t tx_buf[BLE_ADV_PAYLOAD_BUF_LEN] CC_ALIGN(4); - uint8_t ble_params_buf[32] CC_ALIGN(4); /* Config data */ size_t adv_name_len; @@ -147,10 +135,9 @@ typedef struct { /* Periodic timer for sending out BLE advertisements */ clock_time_t ble_adv_interval; - struct etimer ble_adv_et + struct etimer ble_adv_et; /* RF driver */ - RF_Object rf_object; RF_Handle rf_handle; } ble_beacond_t; @@ -175,264 +162,142 @@ static ble_beacond_t ble_beacond; #define TX_POWER_IN_RANGE(dbm) (((dbm) >= TX_POWER_MIN) && ((dbm) <= TX_POWER_MAX)) /*---------------------------------------------------------------------------*/ -PROCESS(ble_beacon_process, "CC13xx / CC26xx RF BLE Beacon Process"); +PROCESS(ble_beacond_process, "RF BLE Beacon Daemon Process"); /*---------------------------------------------------------------------------*/ -static int -send_ble_adv_nc(int channel, uint8_t *adv_payload, int adv_payload_len) +rf_ble_beacond_result_t +rf_ble_beacond_init(void) { - uint32_t cmd_status; - rfc_CMD_BLE_ADV_NC_t cmd; - rfc_bleAdvPar_t *params; + ble_adv_par.pDeviceAddress = (uint16_t *)ble_addr_ptr(); - params = (rfc_bleAdvPar_t *)ble_params_buf; - - /* Clear both buffers */ - memset(&cmd, 0x00, sizeof(cmd)); - memset(ble_params_buf, 0x00, sizeof(ble_params_buf)); - - /* Adv NC */ - cmd.commandNo = CMD_BLE_ADV_NC; - cmd.condition.rule = COND_NEVER; - cmd.whitening.bOverride = 0; - cmd.whitening.init = 0; - cmd.pParams = params; - cmd.channel = channel; - - /* Set up BLE Advertisement parameters */ - params->pDeviceAddress = (uint16_t *)BLE_ADDRESS_PTR; - params->endTrigger.triggerType = TRIG_NEVER; - params->endTime = TRIG_NEVER; - - /* Set up BLE Advertisement parameters */ - params = (rfc_bleAdvPar_t *)ble_params_buf; - params->advLen = adv_payload_len; - params->pAdvData = adv_payload; - - if(rf_core_send_cmd((uint32_t)&cmd, &cmd_status) == RF_CORE_CMD_ERROR) { - PRINTF("send_ble_adv_nc: Chan=%d CMDSTA=0x%08lx, status=0x%04x\n", - channel, cmd_status, cmd.status); - return RF_CORE_CMD_ERROR; - } - - /* Wait until the command is done */ - if(rf_core_wait_cmd_done(&cmd) != RF_CORE_CMD_OK) { - PRINTF("send_ble_adv_nc: Chan=%d CMDSTA=0x%08lx, status=0x%04x\n", - channel, cmd_status, cmd.status); - return RF_CORE_CMD_ERROR; - } - - return RF_CORE_CMD_OK; -} -/*---------------------------------------------------------------------------*/ -rf_ble_beacond_result_e -rf_ble_beacond_config(clock_time_t interval, const char *name) -{ - if(name != NULL) { - const size_t name_len = strlen(name); - if(name_len == 0 || name_len >= BLE_ADV_NAME_BUF_LEN) { - return RF_BLE_BEACOND_ERROR; - } - - /* name_len + 1 for zero termination char */ - ble_beacond_cfg.adv_name_len = name_len + 1; - memcpy(ble_beacond_cfg.adv_name, name, name_len + 1); - } - - if(interval != 0) { - ble_beacond_cfg.ble_adv_interval = interval; - } - - return RF_BLE_BEACOND_OK; -} -/*---------------------------------------------------------------------------*/ -rf_ble_beacond_result_e -rf_ble_beacond_start(void) -{ - /* Check if RF handle has already been opened */ - if (ble_beacond.rf_handle != NULL) { - return RF_BLE_BEACOND_OK; - } - - /* Sanity check of Beacond config */ - if(beacond_config.adv_name_len == 0) { - return RF_BLE_BEACOND_ERROR; - } - - /* Open RF handle */ RF_Params rf_params; RF_Params_init(&rf_params); - ble_beacond.rf_handle = RF_open(&ble_beacond.rf_object, &rf_ble_mode, - (RF_RadioSetup*)&rf_cmd_ieee_radio_setup, &rf_params); + /* Should immediately turn off radio if possible */ + rf_params.nInactivityTimeout = 0; - if (ble_beacond.rf_handle == NULL) { - PRINTF("init: unable to open BLE RF driver\n"); + ble_beacond.handle = ble_open(&rf_params); + + if (ble_beacond.handle == NULL) { return RF_BLE_BEACOND_ERROR; } - ble_beacond.is_active = false; - - process_start(&ble_beacon_process, NULL); - return RF_BLE_BEACOND_OK; } /*---------------------------------------------------------------------------*/ -rf_ble_beacond_result_e -rf_ble_beacond_stop() +rf_ble_beacond_result_t +rf_ble_beacond_start(clock_time_t interval, const char *name) { - if (ble_beacond.rf_handle == NULL) { - return RF_BLE_BEACOND_OK; + if (interval == 0) { + return RF_BLE_BEACOND_ERROR; } - /* Force abort of any ongoing RF operation */ - RF_flushCmd(ieee_radio.rf_handle, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY); - RF_close(ble_beacond.rf_handle); + if (name == NULL) { + return RF_BLE_BEACOND_ERROR; + } - ble_beacond.rf_handle = NULL; + ble_beacond.ble_adv_interval = interval; - process_exit(&ble_beacon_process); + const size_t name_len = strlen(name); + + if ((name_len == 0) || + (name_len >= BLE_ADV_NAME_BUF_LEN)) { + return RF_BLE_BEACOND_ERROR; + } + + ble_beacond.adv_name_len = name_len; + memcpy(ble_beacond.adv_name, name, name_len); + + ble_beacond.is_active = true; + + process_start(&ble_beacond_process, NULL); return RF_BLE_BEACOND_OK; } /*---------------------------------------------------------------------------*/ -uint8_t -rf_ble_is_active() +rf_ble_beacond_result_t +rf_ble_beacond_stop(void) { - return ble_beacon_on; + ble_beacond.is_active = false; + + process_exit(&ble_beacond_process); + + return RF_BLE_BEACOND_OK; } /*---------------------------------------------------------------------------*/ -rf_ble_beacond_result_e -rf_ble_set_tx_power(radio_value_t dBm) +int8_t +rf_ble_is_active(void) { + return (int8_t)ble_beacond.is_active; +} +/*---------------------------------------------------------------------------*/ +rf_ble_beacond_result_t +rf_ble_set_tx_power(int8_t dBm) +{ + rf_result_t res; + if (!TX_POWER_IN_RANGE(dBm)) { return RADIO_RESULT_INVALID_VALUE; } - const RF_Stat stat = RF_setTxPower( - ble_beacond.rf_handle, - RF_TxPowerTable_findValue(TX_POWER_TABLE, (int8_t)dBm) - ); + res = rf_set_tx_power(ble_beacond.rf_handle, TX_POWER_TABLE, dbm); - return (stat == RF_StatSuccess) + return (res == RF_RESULT_OK) ? RF_BLE_BEACOND_OK : RF_BLE_BEACOND_ERROR; } /*---------------------------------------------------------------------------*/ -radio_value_t +int8_t rf_ble_get_tx_power(void) { - return (radio_value_t)RF_TxPowerTable_findPowerLevel( - TX_POWER_TABLE, - RF_getTxPower(ble_beacond.rf_handle) - ); + rf_result_t res; + + int8_t dbm; + res = rf_get_tx_power(ble_beacond.rf_handle, TX_POWER_TABLE, &dbm) + + if (res != RF_RESULT_OK) { + return ~(int8_t)0; + } + + return dbm; } /*---------------------------------------------------------------------------*/ -static rf_ble_beacond_result_e -rf_ble_beacon_single(uint8_t channel, uint8_t *data, uint8_t len) +static rf_ble_beacond_result_t +ble_beacon_burst(uint8_t channels_bm, uint8_t *data, uint8_t len) { - uint32_t cmd_status; - bool interrupts_disabled; - uint8_t j, channel_selected; - uint8_t was_on; + rf_result_t res; - /* Adhere to the maximum BLE advertisement payload size */ - if(len > BLE_ADV_NAME_BUF_LEN) { - len = BLE_ADV_NAME_BUF_LEN; - } - - /* - * Under ContikiMAC, some IEEE-related operations will be called from an - * interrupt context. We need those to see that we are in BLE mode. - */ - const uintptr_t key = HwiP_disable(); - - /* - * First, determine our state: - * - * If we are running CSMA, we are likely in IEEE RX mode. We need to - * abort the IEEE BG Op before entering BLE mode. - * If we are ContikiMAC, we are likely off, in which case we need to - * boot the CPE before entering BLE mode - */ - was_on = rf_core_is_accessible(); - - if(was_on) { - /* - * We were on: If we are in the process of receiving a frame, abort the - * BLE beacon burst. Otherwise, terminate the primary radio Op so we - * can switch to BLE mode - */ - if(NETSTACK_RADIO.receiving_packet()) { - PRINTF("rf_ble_beacon_single: We were receiving\n"); - - /* Abort this pass */ - return; + uint8_t channel; + for (channel = BLE_ADV_CHANNEL_MIN; channel <= BLE_ADV_CHANNEL_MAX; ++channel) { + const uint8_t channel_bv = (1 << (channel - BLE_ADV_CHANNEL_MIN)); + if ((channel_bv & channels_bm) == 0) { + continue; } - rf_core_primary_mode_abort(); - } else { + ble_adv_par.advLen = len; + ble_adv_par.pAdvData = data; - oscillators_request_hf_xosc(); + ble_cmd_beacon.channel = channel; - /* We were off: Boot the CPE */ - if(rf_core_boot() != RF_CORE_CMD_OK) { - /* Abort this pass */ - PRINTF("rf_ble_beacon_single: rf_core_boot() failed\n"); - return; - } + res = ble_sched_beacon(NULL, 0); - oscillators_switch_to_hf_xosc(); - - /* Enter BLE mode */ - if(rf_radio_setup() != RF_CORE_CMD_OK) { - /* Continue so we can at least try to restore our previous state */ - PRINTF("rf_ble_beacon_single: Error entering BLE mode\n"); - } else { - - for(j = 0; j < 3; j++) { - channel_selected = (channel >> j) & 0x01; - if(channel_selected == 1) { - if(send_ble_adv_nc(37 + j, data, len) != RF_CORE_CMD_OK) { - /* Continue... */ - PRINTF("rf_ble_beacon_single: Channel=%d, " - "Error advertising\n", 37 + j); - } - } - } - } - - /* Send a CMD_STOP command to RF Core */ - if(rf_core_send_cmd(CMDR_DIR_CMD(CMD_STOP), &cmd_status) != RF_CORE_CMD_OK) { - /* Continue... */ - PRINTF("rf_ble_beacon_single: status=0x%08lx\n", cmd_status); - } - - if(was_on) { - /* We were on, go back to previous primary mode */ - rf_core_primary_mode_restore(); - } else { - /* We were off. Shut back off */ - rf_core_power_down(); - - /* Switch HF clock source to the RCOSC to preserve power */ - oscillators_switch_to_hf_rc(); + if (res != RF_RESULT_OK) { + return RF_BLE_BEACOND_ERROR; } } - HwiP_restore(key); + return RF_BLE_BEACOND_OK; } /*---------------------------------------------------------------------------*/ -PROCESS_THREAD(ble_beacon_process, ev, data) +PROCESS_THREAD(ble_beacond_process, ev, data) { static size_t i; - static size_t p; + static size_t len; PROCESS_BEGIN(); while(1) { etimer_set(&beacond_config.ble_adv_et, beacond_config.ble_adv_interval); - - PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&ble_adv_et) || + PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&beacond_config.ble_adv_et) || (ev == PROCESS_EVENT_EXIT)); if(ev == PROCESS_EVENT_EXIT) { @@ -440,27 +305,28 @@ PROCESS_THREAD(ble_beacon_process, ev, data) } /* Set the adv payload each pass: The device name may have changed */ - p = 0; + len = 0; - /* device info */ - payload[p++] = (uint8_t)0x02; /* 2 bytes */ - payload[p++] = (uint8_t)BLE_ADV_TYPE_DEVINFO; - payload[p++] = (uint8_t)0x1a; /* LE general discoverable + BR/EDR */ - payload[p++] = (uint8_t)beacond_config.adv_name_len; - payload[p++] = (uint8_t)BLE_ADV_TYPE_NAME; - memcpy(payload + p, beacond_config.adv_name, beacond_config.adv_name_len); - p += beacond_config.adv_name_len; + /* Device info */ + beacond_config.tx_buf[len++] = (uint8_t)0x02; /* 2 bytes */ + beacond_config.tx_buf[len++] = (uint8_t)BLE_ADV_TYPE_DEVINFO; + beacond_config.tx_buf[len++] = (uint8_t)0x1A; /* LE general discoverable + BR/EDR */ + beacond_config.tx_buf[len++] = (uint8_t)beacond_config.adv_name_len; + beacond_config.tx_buf[len++] = (uint8_t)BLE_ADV_TYPE_NAME; + + memcpy(beacond_config.tx_buf + len, beacond_config.adv_name, beacond_config.adv_name_len); + len += beacond_config.adv_name_len; /* * Send BLE_ADV_MESSAGES beacon bursts. Each burst on all three * channels, with a BLE_ADV_DUTY_CYCLE interval between bursts */ - rf_ble_beacon_single(BLE_ADV_CHANNEL_ALL, payload, p); - for(i = 1; i < BLE_ADV_MESSAGES; i++) { + ble_beacon_burst(BLE_ADV_CHANNEL_ALL, beacond_config.tx_buf, len); + for(i = 1; i < BLE_ADV_MESSAGES; ++i) { etimer_set(&beacond_config.ble_adv_et, BLE_ADV_DUTY_CYCLE); PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&ble_adv_et)); - rf_ble_beacon_single(BLE_ADV_CHANNEL_ALL, payload, p); + ble_beacon_burst(BLE_ADV_CHANNEL_ALL, beacond_config.tx_buf, len); } } PROCESS_END(); diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.h b/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.h index ddbe26fff..45f02f062 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.h +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.h @@ -58,7 +58,7 @@ typedef enum { RF_BLE_BEACOND_OK, RF_BLE_BEACOND_ERROR, RF_BLE_BEACOND_DISABLED, -} rf_ble_beacond_result_e; +} rf_ble_beacond_result_t; /** * \brief Set the device name to use with the BLE advertisement/beacon daemon * \param interval The interval (ticks) between two consecutive beacon bursts @@ -68,7 +68,7 @@ typedef enum { * this function can be used to configure a single parameter at a time if so * desired. */ -rf_ble_beacond_result_e rf_ble_beacond_config(clock_time_t interval, const char *name); +rf_ble_beacond_result_t rf_ble_beacond_init(void); /** * \brief Start the BLE advertisement/beacon daemon @@ -78,50 +78,37 @@ rf_ble_beacond_result_e rf_ble_beacond_config(clock_time_t interval, const char * calling rf_ble_beacond_config(). Otherwise, this function will return an * error. */ -rf_ble_beacond_result_e rf_ble_beacond_start(void); +rf_ble_beacond_result_t rf_ble_beacond_start(clock_time_t interval, const char *name); /** * \brief Stop the BLE advertisement/beacon daemon */ -rf_ble_beacond_result_e rf_ble_beacond_stop(void); +rf_ble_beacond_result_t rf_ble_beacond_stop(void); /** * \brief Check whether the BLE beacond is currently active - * \retval 1 The radio is in BLE mode - * \retval 0 The BLE daemon is not active, or disabled + * \retval 1 BLE daemon is active + * \retval 0 BLE daemon is inactive + * \retval -1 BLE daemon is disabled */ -uint8_t rf_ble_is_active(void); +int8_t rf_ble_is_active(void); /** * \brief Set TX power for BLE advertisements - * \param dBm The 'at least' TX power in dBm, values avove 5 dBm will be ignored + * \param dbm The 'at least' TX power in dBm, values avove 5 dBm will be ignored * * Set TX power to 'at least' power dBm. * This works with a lookup table. If the value of 'power' does not exist in * the lookup table, TXPOWER will be set to the immediately higher available * value */ -rf_ble_beacond_result_e rf_ble_set_tx_power(radio_value_t dBm); +rf_ble_beacond_result_t rf_ble_set_tx_power(int8_t dbm); /** * \brief Get TX power for BLE advertisements * \return The TX power for BLE advertisements */ -radio_value_t rf_ble_get_tx_power(void); - -/** - * \brief Transmit a single BLE advertisement in one or more advertisement channels - * \param channel Bitmask of advertisement channels to be used: use - * BLE_ADV_CHANNEL_37 for channel 37, BLE_ADV_CHANNEL_38 for channel 38, - * BLE_ADV_CHANNEL_39 for channel 39, or any 'or' combination of those - * \param data A pointer to the advertisement data buffer - * \param len The length of the advertisement data. If more than BLE_ADV_MAX_SIZE, - * the first BLE_ADV_MAX_SIZE bytes will be used. - * - * Transmits a given advertisement payload once in one or any arbitrary combination - * of advertisement channels. - */ -rf_ble_beacond_result_e rf_ble_beacon_single(uint8_t channel, uint8_t *data, uint8_t len); +int8_t rf_ble_get_tx_power(void); /*---------------------------------------------------------------------------*/ #endif /* RF_BLE_BEACOND_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-core.c b/arch/cpu/cc13xx-cc26xx/dev/rf-core.c index 694eb2c00..05b19e7b2 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-core.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-core.c @@ -53,6 +53,7 @@ #include /*---------------------------------------------------------------------------*/ +#include "rf-data-queue.h" #include "netstack-settings.h" /*---------------------------------------------------------------------------*/ #include @@ -85,13 +86,27 @@ static RF_Object rf_netstack; static RF_Object rf_ble; -typedef struct { - RF_CmdHandle handle; - RF_Callback cb; - RF_EventMask bm_event; -} rf_cmd_t; +static RF_CmdHandle cmd_rx_handle; +/*---------------------------------------------------------------------------*/ +static void +cmd_rx_cb(RF_Handle client, RF_CmdHandle command, RF_EventMask events) +{ + /* Unused arguments */ + (void)client; + (void)command; -static rf_cmd_t netstack_rx; + if (events & RF_EventRxEntryDone) { + process_poll(&rf_core_process); + } + + if (events & RF_EventRxBufFull) { + data_queue_reset(); + /* TODO: Check status of RX to verify RX was running before rescheduling */ + netstack_sched_rx(); + + process_poll(&rf_core_process); + } +} /*---------------------------------------------------------------------------*/ static inline bool cmd_rx_is_active(void) @@ -112,8 +127,8 @@ cmd_rx_disable(void) if (is_active) { CMD_STATUS(netstack_cmd_rx) = DONE_STOPPED; - RF_cancelCmd(&rf_netstack, netstack_rx.handle, RF_ABORT_GRACEFULLY); - netstack_rx.handle = 0; + RF_cancelCmd(&rf_netstack, cmd_rx_handle, RF_ABORT_GRACEFULLY); + cmd_rx_handle = 0; } return (uint_fast8_t)is_active; @@ -137,16 +152,16 @@ cmd_rx_restore(uint_fast8_t rx_key) CMD_STATUS(netstack_cmd_rx) = PENDING; - netstack_rx.handle = RF_scheduleCmd(&rf_netstack, + cmd_rx_handle = RF_scheduleCmd(&rf_netstack, (RF_Op*)&netstack_cmd_rx, &sched_params, - netstack_rx.cb, - netstack_rx.bm_event + cmd_rx_cb, + RF_EventRxEntryDone | RF_EventRxBufFull ); - if (!CMD_HANDLE_OK(netstack_rx.handle)) { + if (!CMD_HANDLE_OK(cmd_rx_handle)) { PRINTF("cmd_rx_restore: unable to schedule RX command handle=%d status=0x%04x", - netstack_rx.handle, CMD_STATUS(netstack_cmd_rx)); + cmd_rx_handle, CMD_STATUS(netstack_cmd_rx)); return RF_RESULT_ERROR; } @@ -196,7 +211,11 @@ rf_get_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8_t *dbm) RF_Handle netstack_open(RF_Params *params) { - return RF_open(&rf_netstack, &netstack_mode, (RF_RadioSetup*)&netstack_cmd_radio_setup, params); + return RF_open(&rf_netstack, + &netstack_mode, + (RF_RadioSetup*)&netstack_cmd_radio_setup, + params + ); } /*---------------------------------------------------------------------------*/ rf_result_t @@ -247,7 +266,78 @@ netstack_sched_fs(void) } /*---------------------------------------------------------------------------*/ rf_result_t -netstack_sched_tx(RF_Callback cb, RF_EventMask bm_event) +netstack_sched_ieee_tx(bool recieve_ack) +{ + rf_result_t res; + + RF_ScheduleCmdParams sched_params; + RF_ScheduleCmdParams_init(&sched_params); + + sched_params.priority = RF_PriorityNormal; + sched_params.endTime = 0; + sched_params.allowDelay = RF_AllowDelayAny; + + const bool is_active = cmd_rx_is_active(); + const bool rx_ack_required = (recieve_ack && !is_active); + + /* + * If we expect ACK after transmission, RX must be running to be able to + * run the RX_ACK command. Therefore, turn on RX before starting the + * chained TX command. + */ + if (rx_ack_required) { + res = netstack_sched_rx(); + if (res != RF_RESULT_OK) { + return res; + } + } + + CMD_STATUS(netstack_cmd_tx) = PENDING; + + RF_CmdHandle tx_handle = RF_scheduleCmd(&rf_netstack, + (RF_Op*)&netstack_cmd_tx, + &sched_params, + NULL, + 0 + ); + + if (!CMD_HANDLE_OK(tx_handle)) { + PRINTF("netstack_sched_tx: unable to schedule TX command handle=%d status=0x%04x\n", + tx_handle, CMD_STATUS(netstack_cmd_tx)); + return RF_RESULT_ERROR; + } + + if (is_active) { + ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT); + } else { + ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); + } + + /* Wait until TX operation finishes */ + RF_EventMask tx_events = RF_pendCmd(&rf_netstack, tx_handle, 0); + + /* Stop RX if it was turned on only for ACK */ + if (rx_ack_required) { + netstack_stop_rx(); + } + + if (is_active) { + ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN); + } else { + ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); + } + + if (!EVENTS_CMD_DONE(tx_events)) { + PRINTF("netstack_sched_tx: TX command pend error events=0x%08llx status=0x%04x\n", + tx_events, CMD_STATUS(netstack_cmd_tx)); + return RF_RESULT_ERROR; + } + + return RF_RESULT_OK; +} +/*---------------------------------------------------------------------------*/ +rf_result_t +netstack_sched_prop_tx(void) { RF_ScheduleCmdParams sched_params; RF_ScheduleCmdParams_init(&sched_params); @@ -261,8 +351,8 @@ netstack_sched_tx(RF_Callback cb, RF_EventMask bm_event) RF_CmdHandle tx_handle = RF_scheduleCmd(&rf_netstack, (RF_Op*)&netstack_cmd_tx, &sched_params, - cb, - bm_event + NULL, + 0 ); if (!CMD_HANDLE_OK(tx_handle)) { @@ -272,13 +362,10 @@ netstack_sched_tx(RF_Callback cb, RF_EventMask bm_event) } /* - * IEEE_TX can be scheduled while IEEE_RX is running, as the radio supports - * FG commands to be scheduled while a BG command is running. - * For Prop-mode, RX must be turned off as usual. + * Prop TX requires any on-going RX operation to be stopped to be + * able to transmit. Therefore, disable RX if running. */ - const uint_fast8_t rx_key = (RF_CORE_CONF_MODE != RF_CORE_MODE_2_4_GHZ) - ? cmd_rx_disable() - : false; + const bool rx_key = cmd_rx_disable(); if (rx_key) { ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT); @@ -289,14 +376,14 @@ netstack_sched_tx(RF_Callback cb, RF_EventMask bm_event) /* Wait until TX operation finishes */ RF_EventMask tx_events = RF_pendCmd(&rf_netstack, tx_handle, 0); + cmd_rx_restore(rx_key); + if (rx_key) { ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN); } else { ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); } - cmd_rx_restore(rx_key); - if (!EVENTS_CMD_DONE(tx_events)) { PRINTF("netstack_sched_tx: TX command pend error events=0x%08llx status=0x%04x\n", tx_events, CMD_STATUS(netstack_cmd_tx)); @@ -307,7 +394,7 @@ netstack_sched_tx(RF_Callback cb, RF_EventMask bm_event) } /*---------------------------------------------------------------------------*/ rf_result_t -netstack_sched_rx(RF_Callback cb, RF_EventMask bm_event) +netstack_sched_rx(void) { if (cmd_rx_is_active()) { PRINTF("netstack_sched_rx: already in RX\n"); @@ -323,18 +410,16 @@ netstack_sched_rx(RF_Callback cb, RF_EventMask bm_event) CMD_STATUS(netstack_cmd_rx) = PENDING; - netstack_rx.cb = cb; - netstack_rx.bm_event = bm_event; - netstack_rx.handle = RF_scheduleCmd(&rf_netstack, + cmd_rx_handle = RF_scheduleCmd(&rf_netstack, (RF_Op*)&netstack_cmd_rx, &sched_params, - cb, - bm_event + cmd_rx_cb, + RF_EventRxEntryDone | RF_EventRxBufFull ); - if (!CMD_HANDLE_OK(netstack_rx.handle)) { + if (!CMD_HANDLE_OK(cmd_rx_handle)) { PRINTF("netstack_sched_rx: unable to schedule RX command handle=%d status=0x%04x\n", - netstack_rx.handle, CMD_STATUS(netstack_cmd_rx)); + cmd_rx_handle, CMD_STATUS(netstack_cmd_rx)); return RF_RESULT_ERROR; } @@ -352,8 +437,8 @@ netstack_stop_rx(void) } CMD_STATUS(netstack_cmd_rx) = DONE_STOPPED; - const RF_Stat stat = RF_cancelCmd(&rf_netstack, netstack_rx.handle, RF_ABORT_GRACEFULLY); - netstack_rx.handle = 0; + const RF_Stat stat = RF_cancelCmd(&rf_netstack, cmd_rx_handle, RF_ABORT_GRACEFULLY); + cmd_rx_handle = 0; ENERGEST_OFF(ENERGEST_TYPE_LISTEN); diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-core.h b/arch/cpu/cc13xx-cc26xx/dev/rf-core.h index e018dfd0c..7ce6738e8 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-core.h +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-core.h @@ -46,9 +46,11 @@ #include "contiki.h" #include "rf-ble-beacond.h" - +/*---------------------------------------------------------------------------*/ #include /*---------------------------------------------------------------------------*/ +#include +/*---------------------------------------------------------------------------*/ typedef enum { RF_RESULT_OK = 0, RF_RESULT_ERROR, @@ -66,8 +68,9 @@ rf_result_t rf_get_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8 RF_Handle netstack_open(RF_Params *params); rf_result_t netstack_sched_fs(void); -rf_result_t netstack_sched_tx(RF_Callback cb, RF_EventMask bm_event); -rf_result_t netstack_sched_rx(RF_Callback cb, RF_EventMask bm_event); +rf_result_t netstack_sched_ieee_tx(bool recieve_ack); +rf_result_t netstack_sched_prop_tx(void); +rf_result_t netstack_sched_rx(void); rf_result_t netstack_stop_rx(void); /*---------------------------------------------------------------------------*/ /* BLE radio: BLE Beacon Daemon */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-data-queue.c b/arch/cpu/cc13xx-cc26xx/dev/rf-data-queue.c new file mode 100644 index 000000000..875edab4b --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-data-queue.c @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup simplelink + * @{ + * + * \file + * Implementation of common CC13xx/CC26xx RF functionality + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "sys/cc.h" + +#include "rf-data-queue.h" +/*---------------------------------------------------------------------------*/ +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_data_entry.h) +/*---------------------------------------------------------------------------*/ +#include +#include +/*---------------------------------------------------------------------------*/ +/* RX buf configuration */ + +#ifdef RF_CORE_CONF_RX_BUF_CNT +# define RX_BUF_CNT RF_CORE_CONF_RX_BUF_CNT +#else +# define RX_BUF_CNT 4 +#endif + +#ifdef RF_CORE_CONF_RX_BUF_SIZE +# define RX_BUF_SIZE RF_CORE_CONF_RX_BUF_SIZE +#else +# define RX_BUF_SIZE 144 +#endif +/*---------------------------------------------------------------------------*/ +/* Receive buffer entries with room for 1 IEEE 802.15.4 frame in each */ +typedef union { + data_entry_t data_entry; + uint8_t buf[RX_BUF_SIZE]; +} rx_buf_t CC_ALIGN(4); +/*---------------------------------------------------------------------------*/ +typedef struct { + /* RX bufs */ + rx_buf_t bufs[RX_BUF_CNT]; + /* RFC data queue object */ + data_queue_t data_queue; + /* Current data entry in use by RF */ + data_entry_t* curr_entry; + /* Size in bytes of length field in data entry */ + size_t lensz; +} rx_data_queue_t; + +static rx_data_queue_t rx_data_queue; +/*---------------------------------------------------------------------------*/ +static void +rx_bufs_init(void) +{ + size_t i; + for (i = 0; i < RX_BUF_CNT; ++i) { + data_entry_t *const data_entry = &(rx_data_queue.bufs[i].data_entry); + + data_entry->status = DATA_ENTRY_PENDING; + data_entry->config.type = DATA_ENTRY_TYPE_GEN; + data_entry->config.lenSz = rx_data_queue.lensz; + data_entry->length = RX_BUF_SIZE - sizeof(data_entry_t); /* TODO: is this sizeof sound? */ + /* Point to fist entry if this is last entry, else point to next entry */ + data_entry->pNextEntry = (i == (RX_BUF_CNT - 1)) + ? rx_data_queue.bufs[0].buf + : rx_data_queue.bufs[i].buf; + } +} +/*---------------------------------------------------------------------------*/ +static void +rx_bufs_reset(void) +{ + size_t i; + for (i = 0; i < RX_BUF_CNT; ++i) { + data_entry_t *const data_entry = &(rx_data_queue.bufs[i].data_entry); + + /* Clear length bytes */ + memset(&(data_entry->data), 0x0, rx_data_queue.lensz); + /* Set status to Pending */ + data_entry->status = DATA_ENTRY_PENDING; + } +} +/*---------------------------------------------------------------------------*/ +data_queue_t* +data_queue_init(size_t lensz) +{ + rx_data_queue.lensz = lensz; + + /* Initialize RX buffers */ + rx_bufs_init(); + + /* Configure data queue as circular buffer */ + rx_data_queue.data_queue.pCurrEntry = rx_data_queue.bufs[0].buf; + rx_data_queue.data_queue.pLastEntry = NULL; + + /* Set current read pointer to first element */ + rx_data_queue.curr_entry = &(rx_data_queue.bufs[0].data_entry); + + return &rx_data_queue.data_queue; +} +/*---------------------------------------------------------------------------*/ +void +data_queue_reset(void) +{ + rx_bufs_reset(); + + /* Only need to reconfigure pCurrEntry */ + rx_data_queue.data_queue.pCurrEntry = rx_data_queue.bufs[0].buf; + + /* Set current read pointer to first element */ + rx_data_queue.curr_entry = &(rx_data_queue.bufs[0].data_entry); +} +/*---------------------------------------------------------------------------*/ +data_entry_t* +data_queue_current_entry(void) +{ + return rx_data_queue.curr_entry; +} +/*---------------------------------------------------------------------------*/ +void +data_queue_release_entry(void) +{ + data_entry_t *const curr_entry = rx_data_queue.curr_entry; + uint8_t *const frame_ptr = (uint8_t*)&(curr_entry->data); + + /* Clear length bytes */ + memset(frame_ptr, 0x0, rx_data_queue.lensz); + /* Set status to Pending */ + curr_entry->status = DATA_ENTRY_PENDING; + + /* Move current entry to the next entry */ + rx_data_queue.curr_entry = (data_entry_t*)(curr_entry->pNextEntry); +} +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-data-queue.h b/arch/cpu/cc13xx-cc26xx/dev/rf-data-queue.h new file mode 100644 index 000000000..9a95f2f5d --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-data-queue.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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 RF_DATA_QUEUE_H_ +#define RF_DATA_QUEUE_H_ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +/*---------------------------------------------------------------------------*/ +#include +#include DeviceFamily_constructPath(driverlib/rf_mailbox.h) +#include DeviceFamily_constructPath(driverlib/rf_data_entry.h) +/*---------------------------------------------------------------------------*/ +#include +/*---------------------------------------------------------------------------*/ +typedef dataQueue_t data_queue_t; +typedef rfc_dataEntryGeneral_t data_entry_t; +/*---------------------------------------------------------------------------*/ +data_queue_t* data_queue_init(size_t lensz); +/*---------------------------------------------------------------------------*/ +void data_queue_reset(void); +/*---------------------------------------------------------------------------*/ +data_entry_t* data_queue_current_entry(void); +/*---------------------------------------------------------------------------*/ +void data_queue_release_entry(void); +/*---------------------------------------------------------------------------*/ +#endif /* RF_DATA_QUEUE_H_ */ +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c index 400b18ff9..87b6068c2 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c @@ -55,16 +55,18 @@ #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) #include DeviceFamily_constructPath(driverlib/rf_data_entry.h) #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) -/* rf_ieee_cmd and rf_ieee_mailbox included by RF settings because of the +/* + * rf_ieee_cmd.h and rf_ieee_mailbox.h are included by RF settings because a * discrepancy between CC13x0 and CC13x2 IEEE support. CC13x0 doesn't provide - * RFCore definitions of IEEE commandos, and are therefore included locally + * RFCore definitions of IEEE commands, and are therefore included locally * from the Contiki build system. CC13x2 includes these normally from driverlib. - * This is taken care of RF settings. */ + * This is taken care of RF settings. + */ #include /*---------------------------------------------------------------------------*/ /* SimpleLink Platform RF dev */ -#include "dot-15-4g.h" +#include "rf-data-queue.h" #include "rf-core.h" #include "netstack-settings.h" /*---------------------------------------------------------------------------*/ @@ -76,7 +78,7 @@ /*---------------------------------------------------------------------------*/ /* Log configuration */ #include "sys/log.h" -#define LOG_MODULE "RF" +#define LOG_MODULE "RF IEEE Mode" #define LOG_LEVEL LOG_LEVEL_NONE /*---------------------------------------------------------------------------*/ #ifdef NDEBUG @@ -144,6 +146,10 @@ #define IEEE_MODE_CHAN_MAX 26 #define IEEE_MODE_CHAN_IN_RANGE(ch) ((IEEE_MODE_CHAN_MIN <= (ch)) && ((ch) <= IEEE_MODE_CHAN_MAX)) + /* freq(channel) = freq_base + freq_spacing * (channel - channel_min) */ +#define IEEE_MODE_FREQ(chan) \ + ((uint32_t)IEEE_MODE_FREQ_BASE + (uint32_t)IEEE_MODE_FREQ_SPACING * \ + ((uint32_t)(channel) - (uint32_t)IEEE_MODE_CHAN_MIN)) /* Sanity check of default IEEE channel */ #if !IEEE_MODE_CHAN_IN_RANGE(IEEE_MODE_CHANNEL) @@ -165,8 +171,6 @@ /* XXX: don't know what exactly is this, looks like the time to TX 3 octets */ #define RAT_TIMESTAMP_OFFSET -(USEC_TO_RAT(32 * 3) - 1) /* -95.75 usec */ /*---------------------------------------------------------------------------*/ -#define CMD_RX_EVENTS (RF_EventRxOk | RF_EventRxBufFull | RF_EventRxEntryDone) -/*---------------------------------------------------------------------------*/ #define STATUS_CORRELATION 0x3f /* bits 0-5 */ #define STATUS_REJECT_FRAME 0x40 /* bit 6 */ #define STATUS_CRC_FAIL 0x80 /* bit 7 */ @@ -178,15 +182,6 @@ /* TX buf configuration */ #define TX_BUF_SIZE 180 - -/* RX buf configuration */ -#ifdef IEEE_MODE_CONF_RX_BUF_CNT -# define RX_BUF_CNT IEEE_MODE_CONF_RX_BUF_CNT -#else -# define RX_BUF_CNT 4 -#endif - -#define RX_BUF_SIZE 144 /*---------------------------------------------------------------------------*/ /* Size of the Length representation in Data Entry, one byte in this case */ typedef uint8_t lensz_t; @@ -202,30 +197,16 @@ typedef enum { } cca_state_t; /*---------------------------------------------------------------------------*/ /* RF Core typedefs */ -typedef dataQueue_t data_queue_t; -typedef rfc_dataEntryGeneral_t data_entry_t; typedef rfc_ieeeRxOutput_t rx_output_t; typedef rfc_CMD_IEEE_MOD_FILT_t cmd_mod_filt_t; typedef rfc_CMD_IEEE_CCA_REQ_t cmd_cca_req_t; -/* Receive buffer entries with room for 1 IEEE 802.15.4 frame in each */ -typedef union { - data_entry_t data_entry; - uint8_t buf[RX_BUF_SIZE]; -} rx_buf_t CC_ALIGN(4); - typedef struct { /* Outgoing frame buffer */ uint8_t tx_buf[TX_BUF_SIZE] CC_ALIGN(4); - /* Ingoing frame buffers */ - rx_buf_t rx_bufs[RX_BUF_CNT]; - /* RX Data Queue */ - data_queue_t rx_data_queue; /* RF Statistics struct */ rx_output_t rx_stats; - /* Receive entry pointer to keep track of read items */ - data_entry_t* rx_read_entry; /* Indicates RF is supposed to be on or off */ bool rf_is_on; @@ -305,22 +286,6 @@ const struct radio_driver ieee_mode_driver = { }; /*---------------------------------------------------------------------------*/ static void -rx_cb(RF_Handle client, RF_CmdHandle command, RF_EventMask events) -{ - /* Unused arguments */ - (void)client; - (void)command; - - if (events & RF_EventRxOk) { - process_poll(&rf_core_process); - } - - if (events & RF_EventRxBufFull) { - - } -} -/*---------------------------------------------------------------------------*/ -static void rat_overflow_cb(void *arg) { check_rat_overflow(); @@ -330,82 +295,50 @@ rat_overflow_cb(void *arg) } /*---------------------------------------------------------------------------*/ static void -init_data_queue(void) -{ - /* Initialize RF core data queue, circular buffer */ - ieee_radio.rx_data_queue.pCurrEntry = ieee_radio.rx_bufs[0].buf; - ieee_radio.rx_data_queue.pLastEntry = NULL; - /* Set current read pointer to first element */ - ieee_radio.rx_read_entry = &ieee_radio.rx_bufs[0].data_entry; -} -/*---------------------------------------------------------------------------*/ -static void init_rf_params(void) { - cmd_rx.pRxQ = &ieee_radio.rx_data_queue; - cmd_rx.pOutput = &ieee_radio.rx_stats; + data_queue_t *rx_q = data_queue_init(sizeof(lensz_t)); + + cmd_rx.pRxQ = rx_q; + cmd_rx.pOutput = &ieee_radio.rx_stats; #if IEEE_MODE_PROMISCOUS - cmd_rx.frameFiltOpt.frameFiltEn = 0; + cmd_rx.frameFiltOpt.frameFiltEn = 0; #else - cmd_rx.frameFiltOpt.frameFiltEn = 1; + cmd_rx.frameFiltOpt.frameFiltEn = 1; #endif #if IEEE_MODE_AUTOACK - cmd_rx.frameFiltOpt.autoAckEn = 1; + cmd_rx.frameFiltOpt.autoAckEn = 1; #else - cmd_rx.frameFiltOpt.autoAckEn = 0; + cmd_rx.frameFiltOpt.autoAckEn = 0; #endif - cmd_rx.ccaRssiThr = IEEE_MODE_RSSI_THRESHOLD; + cmd_rx.ccaRssiThr = IEEE_MODE_RSSI_THRESHOLD; - cmd_tx.pNextOp = (RF_Op*)&cmd_rx_ack; - cmd_tx.condition.rule = COND_NEVER; /* Initially ACK turned off */ + cmd_tx.pNextOp = (RF_Op*)&cmd_rx_ack; + cmd_tx.condition.rule = COND_NEVER; /* Initially ACK turned off */ - cmd_rx_ack.startTrigger.triggerType = TRIG_NOW; - cmd_rx_ack.endTrigger.triggerType = TRIG_REL_SUBMIT; - /* - * ACK packet is transmitted 192 us after the end of the received packet. - * See TRM Section ACK Transmission for more info. - */ - cmd_rx_ack.endTime = RF_convertUsToRatTicks(195); + /* + * ACK packet is transmitted 192 us after the end of the received packet, + * takes 352 us for ACK transmission, total of 546 us of expected time to + * recieve ACK in ideal conditions. 700 us endTime for CMD_IEEE_RX_ACK + * should give some margins. + * The ACK frame consists of 6 bytes of SHR/PDR and 5 bytes of PSDU, total + * of 11 bytes. 11 bytes x 32 us/byte equals 352 us of ACK transmission time. + */ + cmd_rx_ack.startTrigger.triggerType = TRIG_NOW; + cmd_rx_ack.endTrigger.triggerType = TRIG_REL_START; + cmd_rx_ack.endTime = RF_convertUsToRatTicks(700); - /* Initialize address filter command */ - cmd_mod_filt.commandNo = CMD_IEEE_MOD_FILT; - memcpy(&(cmd_mod_filt.newFrameFiltOpt), &(rf_cmd_ieee_rx.frameFiltOpt), sizeof(rf_cmd_ieee_rx.frameFiltOpt)); - memcpy(&(cmd_mod_filt.newFrameTypes), &(rf_cmd_ieee_rx.frameTypes), sizeof(rf_cmd_ieee_rx.frameTypes)); -} -/*---------------------------------------------------------------------------*/ -static void -init_rx_bufs(void) -{ - size_t i; - for (i = 0; i < RX_BUF_CNT; ++i) { - const data_entry_t data_entry = { - .status = DATA_ENTRY_PENDING, - .config.type = DATA_ENTRY_TYPE_GEN, - .config.lenSz = sizeof(lensz_t), - .length = RX_BUF_SIZE - sizeof(data_entry_t), /* TODO: is this sizeof sound? */ - /* Point to fist entry if this is last entry, else point to next entry */ - .pNextEntry = (i == (RX_BUF_CNT - 1)) - ? ieee_radio.rx_bufs[0].buf - : ieee_radio.rx_bufs[i].buf - }; - ieee_radio.rx_bufs[i].data_entry = data_entry; - } -} -/*---------------------------------------------------------------------------*/ -static void -reset_rx_bufs(void) -{ - size_t i; - for (i = 0; i < RX_BUF_CNT; ++i) { - ieee_radio.rx_bufs[i].data_entry.status = DATA_ENTRY_PENDING; - } + /* Initialize address filter command */ + cmd_mod_filt.commandNo = CMD_IEEE_MOD_FILT; + memcpy(&(cmd_mod_filt.newFrameFiltOpt), &(rf_cmd_ieee_rx.frameFiltOpt), sizeof(rf_cmd_ieee_rx.frameFiltOpt)); + memcpy(&(cmd_mod_filt.newFrameTypes), &(rf_cmd_ieee_rx.frameTypes), sizeof(rf_cmd_ieee_rx.frameTypes)); } /*---------------------------------------------------------------------------*/ static rf_result_t -set_channel(uint32_t channel) +set_channel(uint8_t channel) { if (!IEEE_MODE_CHAN_IN_RANGE(channel)) { PRINTF("set_channel: illegal channel %d, defaults to %d\n", @@ -425,8 +358,7 @@ set_channel(uint32_t channel) cmd_rx.channel = channel; - /* freq = freq_base + freq_spacing * (channel - channel_min) */ - const uint32_t new_freq = IEEE_MODE_FREQ_BASE + IEEE_MODE_FREQ_SPACING * (channel - IEEE_MODE_CHAN_MIN); + const uint32_t new_freq = IEEE_MODE_FREQ(channel); const uint16_t freq = (uint16_t)(new_freq / 1000); const uint16_t frac = (uint16_t)(((new_freq - (freq * 1000)) * 0x10000) / 1000); @@ -513,7 +445,6 @@ init(void) ieee_radio.rf_is_on = false; init_rf_params(); - init_data_queue(); /* Init RF params and specify non-default params */ RF_Params rf_params; @@ -527,7 +458,7 @@ init(void) return RF_RESULT_ERROR; } - set_channel(IEEE_MODE_CHANNEL); + set_channel((uint8_t)IEEE_MODE_CHANNEL); ENERGEST_ON(ENERGEST_TYPE_LISTEN); @@ -584,7 +515,7 @@ transmit(unsigned short transmit_len) cmd_tx.payloadLen = (uint8_t)transmit_len; cmd_tx.pPayload = ieee_radio.tx_buf; - res = netstack_sched_tx(NULL, 0); + res = netstack_sched_ieee_tx(ack_request); if (res != RF_RESULT_OK) { return RADIO_TX_ERR; @@ -613,22 +544,10 @@ send(const void *payload, unsigned short payload_len) return transmit(payload_len); } /*---------------------------------------------------------------------------*/ -static void -release_data_entry(void) -{ - data_entry_t *const data_entry = ieee_radio.rx_read_entry; - uint8_t *const frame_ptr = (uint8_t*)&data_entry->data; - - /* Clear the length byte and set status to 0: "Pending" */ - *(lensz_t*)frame_ptr = 0; - data_entry->status = DATA_ENTRY_PENDING; - ieee_radio.rx_read_entry = (data_entry_t*)data_entry->pNextEntry; -} -/*---------------------------------------------------------------------------*/ static int read(void *buf, unsigned short buf_len) { - volatile data_entry_t *data_entry = ieee_radio.rx_read_entry; + volatile data_entry_t *data_entry = data_queue_current_entry(); const rtimer_clock_t t0 = RTIMER_NOW(); /* Only wait if the Radio timer is accessing the entry */ @@ -653,7 +572,7 @@ read(void *buf, unsigned short buf_len) * | Length | Payload | FCS | RSSI | Status | Timestamp | * +--------+---------+---------+--------+--------+-----------+ * Length bytes equal total length of entire frame excluding itself, - * i.e.: Length = N + FCS (2) + RSSI (1) + Status (1) + Timestamp (4) + * Length = N + FCS (2) + RSSI (1) + Status (1) + Timestamp (4) * Length = N + 8 * N = Length - 8 */ @@ -663,7 +582,8 @@ read(void *buf, unsigned short buf_len) /* Sanity check that Frame is at least Frame Shave bytes long */ if (frame_len < FRAME_SHAVE) { PRINTF("read: frame too short len=%d\n", frame_len); - release_data_entry(); + + data_queue_release_entry(); return 0; } @@ -673,7 +593,8 @@ read(void *buf, unsigned short buf_len) /* Sanity check that Payload fits in Buffer */ if (payload_len > buf_len) { PRINTF("read: payload too large for buffer len=%d buf_len=%d\n", payload_len, buf_len); - release_data_entry(); + + data_queue_release_entry(); return 0; } @@ -682,7 +603,7 @@ read(void *buf, unsigned short buf_len) /* RSSI stored FCS (2) bytes after payload */ ieee_radio.last.rssi = (int8_t)payload_ptr[payload_len + 2]; /* LQI retrieved from Status byte, FCS (2) + RSSI (1) bytes after payload */ - ieee_radio.last.corr_lqi = ((uint8_t)payload_ptr[payload_len + 3]) & STATUS_CORRELATION; + ieee_radio.last.corr_lqi = (uint8_t)(payload_ptr[payload_len + 3] & STATUS_CORRELATION); /* Timestamp stored FCS (2) + RSSI (1) + Status (1) bytes after payload */ const uint32_t rat_ticks = *(uint32_t*)(payload_ptr + payload_len + 4); ieee_radio.last.timestamp = rat_to_timestamp(rat_ticks); @@ -695,7 +616,7 @@ read(void *buf, unsigned short buf_len) packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, (packetbuf_attr_t)ieee_radio.last.corr_lqi); } - release_data_entry(); + data_queue_release_entry(); return (int)payload_len; } /*---------------------------------------------------------------------------*/ @@ -707,7 +628,7 @@ cca_request(cmd_cca_req_t *cmd_cca_req) const bool rx_is_idle = !rx_is_active(); if (rx_is_idle) { - res = netstack_sched_rx(rx_cb, CMD_RX_EVENTS); + res = netstack_sched_rx(); if (res != RF_RESULT_OK) { return RF_RESULT_ERROR; } @@ -772,7 +693,7 @@ receiving_packet(void) static int pending_packet(void) { - const data_entry_t *const read_entry = ieee_radio.rx_read_entry; + const data_entry_t *const read_entry = data_queue_current_entry(); volatile const data_entry_t *curr_entry = read_entry; int num_pending = 0; @@ -807,9 +728,9 @@ on(void) return RF_RESULT_OK; } - init_rx_bufs(); + data_queue_reset(); - res = netstack_sched_rx(rx_cb, CMD_RX_EVENTS); + res = netstack_sched_rx(); if (res != RF_RESULT_OK) { return RF_RESULT_ERROR; @@ -829,8 +750,6 @@ off(void) rf_yield(); - reset_rx_bufs(); - ieee_radio.rf_is_on = false; return RF_RESULT_OK; } @@ -979,7 +898,7 @@ set_value(radio_param_t param, radio_value_t value) } netstack_stop_rx(); - res = netstack_sched_rx(rx_cb, CMD_RX_EVENTS); + res = netstack_sched_rx(); return (res == RF_RESULT_OK) ? RADIO_RESULT_OK : RADIO_RESULT_ERROR; @@ -992,7 +911,7 @@ set_value(radio_param_t param, radio_value_t value) } netstack_stop_rx(); - res = netstack_sched_rx(rx_cb, CMD_RX_EVENTS); + res = netstack_sched_rx(); return (res == RF_RESULT_OK) ? RADIO_RESULT_OK : RADIO_RESULT_ERROR; @@ -1031,7 +950,7 @@ set_value(radio_param_t param, radio_value_t value) } netstack_stop_rx(); - res = netstack_sched_rx(rx_cb, CMD_RX_EVENTS); + res = netstack_sched_rx(); return (res == RF_RESULT_OK) ? RADIO_RESULT_OK : RADIO_RESULT_ERROR; @@ -1063,7 +982,7 @@ set_value(radio_param_t param, radio_value_t value) } netstack_stop_rx(); - res = netstack_sched_rx(rx_cb, CMD_RX_EVENTS); + res = netstack_sched_rx(); return (res == RF_RESULT_OK) ? RADIO_RESULT_OK : RADIO_RESULT_ERROR; @@ -1139,7 +1058,7 @@ set_object(radio_param_t param, const void *src, size_t size) } netstack_stop_rx(); - res = netstack_sched_rx(rx_cb, CMD_RX_EVENTS); + res = netstack_sched_rx(); return (res == RF_RESULT_OK) ? RADIO_RESULT_OK : RADIO_RESULT_ERROR; diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c index 330f4cd73..55986391a 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c @@ -58,6 +58,7 @@ /* Platform RF dev */ #include "dot-15-4g.h" #include "rf-core.h" +#include "rf-data-queue.h" #include "netstack-settings.h" /*---------------------------------------------------------------------------*/ #include @@ -66,6 +67,11 @@ #include #include /*---------------------------------------------------------------------------*/ +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "RF Prop Mode" +#define LOG_LEVEL LOG_LEVEL_NONE +/*---------------------------------------------------------------------------*/ #ifdef NDEBUG # define PRINTF(...) #else @@ -136,8 +142,6 @@ /* How long to wait for the rx read entry to become ready */ #define TIMEOUT_DATA_ENTRY_BUSY (RTIMER_SECOND / 250) /*---------------------------------------------------------------------------*/ -#define CMD_RX_EVENTS (RF_EventRxOk | RF_EventRxBufFull | RF_EventRxEntryDone) -/*---------------------------------------------------------------------------*/ /* Configuration for TX power table */ #ifdef PROP_MODE_CONF_TX_POWER_TABLE # define TX_POWER_TABLE PROP_MODE_CONF_TX_POWER_TABLE @@ -158,15 +162,6 @@ #define TX_BUF_PAYLOAD_LEN 180 #define TX_BUF_SIZE (TX_BUF_HDR_LEN + TX_BUF_PAYLOAD_LEN) - -/* RX buf configuration */ -#ifdef PROP_MODE_CONF_RX_BUF_CNT -# define RX_BUF_CNT PROP_MODE_CONF_RX_BUF_CNT -#else -# define RX_BUF_CNT 4 -#endif - -#define RX_BUF_SIZE 140 /*---------------------------------------------------------------------------*/ /* Size of the Length field in Data Entry, two bytes in this case */ typedef uint16_t lensz_t; @@ -183,28 +178,14 @@ typedef uint16_t lensz_t; #define ED_RF_POWER_MAX_DBM MAC_RADIO_RECEIVER_SATURATION_DBM /*---------------------------------------------------------------------------*/ /* RF Core typedefs */ -typedef dataQueue_t data_queue_t; -typedef rfc_dataEntryGeneral_t data_entry_t; typedef rfc_propRxOutput_t rx_output_t; -/* Receive buffer entries with room for 1 IEEE 802.15.4 frame in each */ -typedef union { - data_entry_t data_entry; - uint8_t buf[RX_BUF_SIZE]; -} rx_buf_t CC_ALIGN(4); - typedef struct { /* Outgoing frame buffer */ uint8_t tx_buf[TX_BUF_SIZE] CC_ALIGN(4); - /* Incoming frame buffers */ - rx_buf_t rx_bufs[RX_BUF_CNT]; - /* RX Data Queue */ - data_queue_t rx_data_queue; /* RX Statistics struct */ rx_output_t rx_stats; - /* Receive entry pointer to keep track of read items */ - data_entry_t* rx_read_entry; /* RSSI Threshold */ int8_t rssi_threshold; @@ -231,32 +212,12 @@ static int on(void); static int off(void); /*---------------------------------------------------------------------------*/ static void -rx_cb(RF_Handle client, RF_CmdHandle command, RF_EventMask events) -{ - /* Unused arguments */ - (void)client; - (void)command; - - if (events & RF_EventRxEntryDone) { - process_poll(&rf_core_process); - } -} -/*---------------------------------------------------------------------------*/ -static void -init_data_queue(void) -{ - /* Initialize RF core data queue, circular buffer */ - prop_radio.rx_data_queue.pCurrEntry = prop_radio.rx_bufs[0].buf; - prop_radio.rx_data_queue.pLastEntry = NULL; - /* Set current read pointer to first element */ - prop_radio.rx_read_entry = &prop_radio.rx_bufs[0].data_entry; -} -/*---------------------------------------------------------------------------*/ -static void init_rf_params(void) { + data_queue_t *data_queue = data_queue_init(sizeof(lensz_t)); + cmd_rx.maxPktLen = DOT_4G_MAX_FRAME_LEN - cmd_rx.lenOffset; - cmd_rx.pQueue = &prop_radio.rx_data_queue; + cmd_rx.pQueue = data_queue; cmd_rx.pOutput = (uint8_t *)&prop_radio.rx_stats; } /*---------------------------------------------------------------------------*/ @@ -268,7 +229,7 @@ get_rssi(void) const bool rx_is_idle = !rx_is_active(); if (rx_is_idle) { - res = netstack_sched_rx(rx_cb, CMD_RX_EVENTS); + res = netstack_sched_rx(); if (res != RF_RESULT_OK) { return RF_GET_RSSI_ERROR_VAL; } @@ -357,35 +318,6 @@ calculate_lqi(int8_t rssi) return (MAC_SPEC_ED_MAX * (rssi - ED_RF_POWER_MIN_DBM)) / (ED_RF_POWER_MAX_DBM - ED_RF_POWER_MIN_DBM); } /*---------------------------------------------------------------------------*/ -static void -init_rx_bufs(void) -{ - size_t i = 0; - for (i = 0; i < RX_BUF_CNT; ++i) { - const data_entry_t data_entry = { - .status = DATA_ENTRY_PENDING, - .config.type = DATA_ENTRY_TYPE_GEN, - .config.lenSz = sizeof(lensz_t), - .length = RX_BUF_SIZE - sizeof(data_entry_t), /* TODO: is this sizeof sound? */ - /* Point to fist entry if this is last entry, else point to next entry */ - .pNextEntry = (i == (RX_BUF_CNT - 1)) - ? prop_radio.rx_bufs[0].buf - : prop_radio.rx_bufs[i].buf - }; - /* Write back data entry struct */ - prop_radio.rx_bufs[i].data_entry = data_entry; - } -} -/*---------------------------------------------------------------------------*/ -static void -reset_rx_bufs(void) -{ - size_t i; - for (i = 0; i < RX_BUF_CNT; ++i) { - prop_radio.rx_bufs[i].data_entry.status = DATA_ENTRY_PENDING; - } -} -/*---------------------------------------------------------------------------*/ static int prepare(const void *payload, unsigned short payload_len) { @@ -416,15 +348,15 @@ transmit(unsigned short transmit_len) * The Radio will flip the bits around, so tx_buf[0] must have the length * LSBs (PHR[15:8] and tx_buf[1] will have PHR[7:0] */ - prop_radio.tx_buf[0] = total_length & 0xFF; - prop_radio.tx_buf[1] = (total_length >> 8) + DOT_4G_PHR_DW_BIT + DOT_4G_PHR_CRC_BIT; + prop_radio.tx_buf[0] = ((total_length >> 0) & 0xFF); + prop_radio.tx_buf[1] = ((total_length >> 8) & 0xFF) + DOT_4G_PHR_DW_BIT + DOT_4G_PHR_CRC_BIT; /* pktLen: Total number of bytes in the TX buffer, including the header if * one exists, but not including the CRC (which is not present in the buffer) */ cmd_tx.pktLen = transmit_len + DOT_4G_PHR_LEN; cmd_tx.pPkt = prop_radio.tx_buf; - res = netstack_sched_tx(NULL, 0); + res = netstack_sched_prop_tx(); return (res == RF_RESULT_OK) ? RADIO_TX_OK @@ -438,25 +370,13 @@ send(const void *payload, unsigned short payload_len) return transmit(payload_len); } /*---------------------------------------------------------------------------*/ -static void -release_data_entry(void) -{ - data_entry_t *const data_entry = prop_radio.rx_read_entry; - uint8_t *const frame_ptr = (uint8_t*)&data_entry->data; - - /* Clear the Length byte(s) and set status to 0: "Pending" */ - *(lensz_t*)frame_ptr = 0; - data_entry->status = DATA_ENTRY_PENDING; - prop_radio.rx_read_entry = (data_entry_t*)data_entry->pNextEntry; -} -/*---------------------------------------------------------------------------*/ static int read(void *buf, unsigned short buf_len) { - volatile data_entry_t *data_entry = prop_radio.rx_read_entry; + volatile data_entry_t *data_entry = data_queue_current_entry(); const rtimer_clock_t t0 = RTIMER_NOW(); - /* Only wait if the Radio timer is accessing the entry */ + /* Only wait if the Radio is accessing the entry */ while ((data_entry->status == DATA_ENTRY_BUSY) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + TIMEOUT_DATA_ENTRY_BUSY)); @@ -465,7 +385,8 @@ read(void *buf, unsigned short buf_len) return 0; } - /* First 2 bytes in the data entry are the length. + /* + * First 2 bytes in the data entry are the length. * Data frame is on the following format: * Length (2) + Payload (N) + RSSI (1) + Status (1) * Data frame DOES NOT contain the following: @@ -478,17 +399,18 @@ read(void *buf, unsigned short buf_len) * | Length | Payload | RSSI | Status | * +---------+---------+--------+--------+ * Length bytes equal total length of entire frame excluding itself, - * i.e.: Length = N + RSSI (1) + Status (1) + * Length = N + RSSI (1) + Status (1) * = N + 2 - * N = Length - 2 */ - + * N = Length - 2 + */ uint8_t *const frame_ptr = (uint8_t*)&data_entry->data; const lensz_t frame_len = *(lensz_t*)frame_ptr; /* Sanity check that Frame is at least Frame Shave bytes long */ if (frame_len < FRAME_SHAVE) { PRINTF("read: frame too short len=%d\n", frame_len); - release_data_entry(); + + data_queue_release_entry(); return 0; } @@ -498,7 +420,8 @@ read(void *buf, unsigned short buf_len) /* Sanity check that Payload fits in Buffer */ if (payload_len > buf_len) { PRINTF("read: payload too large for buffer len=%d buf_len=%d\n", payload_len, buf_len); - release_data_entry(); + + data_queue_release_entry(); return 0; } @@ -512,7 +435,7 @@ read(void *buf, unsigned short buf_len) packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (packetbuf_attr_t)rssi); packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, (packetbuf_attr_t)lqi); - release_data_entry(); + data_queue_release_entry(); return (int)payload_len; } /*---------------------------------------------------------------------------*/ @@ -559,7 +482,7 @@ receiving_packet(void) static int pending_packet(void) { - const data_entry_t *const read_entry = prop_radio.rx_read_entry; + const data_entry_t *const read_entry = data_queue_current_entry(); volatile const data_entry_t *curr_entry = read_entry; int num_pending = 0; @@ -594,9 +517,9 @@ on(void) return RF_RESULT_OK; } - init_rx_bufs(); + data_queue_reset(); - res = netstack_sched_rx(rx_cb, CMD_RX_EVENTS); + res = netstack_sched_rx(); if (res != RF_RESULT_OK) { return RF_RESULT_ERROR; @@ -616,8 +539,6 @@ off(void) rf_yield(); - reset_rx_bufs(); - prop_radio.rf_is_on = false; return RF_RESULT_OK; } @@ -756,7 +677,6 @@ init(void) prop_radio.rssi_threshold = PROP_MODE_RSSI_THRESHOLD; init_rf_params(); - init_data_queue(); /* Init RF params and specify non-default params */ RF_Params rf_params; diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.c index 53509c1bf..b7a9194ed 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.c @@ -28,14 +28,17 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /*---------------------------------------------------------------------------*/ -// Parameter summary -// Adv. Address: 010203040506 -// Adv. Data: 255 -// BLE Channel: 17 -// Frequency: 2440 MHz -// PDU Payload length: 30 -// TX Power: 9 dBm (requires define CCFG_FORCE_VDDR_HH = 1 in ccfg.c, see CC13xx/CC26xx Technical Reference Manual) -// Whitening: true +/* + * Parameter summary + * Adv. Address: 010203040506 + * Adv. Data: 255 + * BLE Channel: 17 + * Frequency: 2440 MHz + * PDU Payload length: 30 + * TX Power: 9 dBm (requires define CCFG_FORCE_VDDR_HH = 1 in ccfg.c, + * see CC13xx/CC26xx Technical Reference Manual) + * Whitening: true + */ /*---------------------------------------------------------------------------*/ #include "sys/cc.h" /*---------------------------------------------------------------------------*/ @@ -50,147 +53,150 @@ /*---------------------------------------------------------------------------*/ #include "ble-settings.h" /*---------------------------------------------------------------------------*/ -// TI-RTOS RF Mode Object +/* TI-RTOS RF Mode Object */ RF_Mode rf_ble_mode = { - .rfMode = RF_MODE_BLE, - .cpePatchFxn = &rf_patch_cpe_ble, - .mcePatchFxn = 0, - .rfePatchFxn = &rf_patch_rfe_ble, + .rfMode = RF_MODE_BLE, + .cpePatchFxn = &rf_patch_cpe_ble, + .mcePatchFxn = 0, + .rfePatchFxn = &rf_patch_rfe_ble, }; /*---------------------------------------------------------------------------*/ -// TX Power table -// The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: -// RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) -// See the Technical Reference Manual for further details about the "txPower" Command field. -// The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. +/* TX Power table */ +/* The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: */ +/* RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) */ +/* See the Technical Reference Manual for further details about the "txPower" Command field. */ +/* The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. */ RF_TxPowerTable_Entry rf_ble_tx_power_table[RF_BLE_TX_POWER_TABLE_SIZE+1] = { - { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 3, 1, 6) }, - { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 1, 6) }, - { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 3, 1, 10) }, - { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 3, 1, 12) }, - { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(26, 3, 1, 14) }, - { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(35, 3, 1, 18) }, - { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(47, 3, 1, 22) }, - { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(29, 0, 1, 45) }, - { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(33, 0, 1, 49) }, - { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(38, 0, 1, 55) }, - { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(44, 0, 1, 63) }, - { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(52, 0, 1, 59) }, - { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(60, 0, 1, 47) }, - { 6, RF_TxPowerTable_DEFAULT_PA_ENTRY(38, 0, 1, 49) }, // This setting requires CCFG_FORCE_VDDR_HH = 1. - { 7, RF_TxPowerTable_DEFAULT_PA_ENTRY(46, 0, 1, 59) }, // This setting requires CCFG_FORCE_VDDR_HH = 1. - { 8, RF_TxPowerTable_DEFAULT_PA_ENTRY(55, 0, 1, 51) }, // This setting requires CCFG_FORCE_VDDR_HH = 1. - { 9, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 30) }, // This setting requires CCFG_FORCE_VDDR_HH = 1. - RF_TxPowerTable_TERMINATION_ENTRY + { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 3, 1, 6) }, + { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 1, 6) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 3, 1, 10) }, + { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 3, 1, 12) }, + { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(26, 3, 1, 14) }, + { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(35, 3, 1, 18) }, + { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(47, 3, 1, 22) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(29, 0, 1, 45) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(33, 0, 1, 49) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(38, 0, 1, 55) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(44, 0, 1, 63) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(52, 0, 1, 59) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(60, 0, 1, 47) }, + /* This setting requires CCFG_FORCE_VDDR_HH = 1. */ + { 6, RF_TxPowerTable_DEFAULT_PA_ENTRY(38, 0, 1, 49) }, + /* This setting requires CCFG_FORCE_VDDR_HH = 1. */ + { 7, RF_TxPowerTable_DEFAULT_PA_ENTRY(46, 0, 1, 59) }, + /* This setting requires CCFG_FORCE_VDDR_HH = 1. */ + { 8, RF_TxPowerTable_DEFAULT_PA_ENTRY(55, 0, 1, 51) }, + /* This setting requires CCFG_FORCE_VDDR_HH = 1. */ + { 9, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 30) }, + RF_TxPowerTable_TERMINATION_ENTRY }; /*---------------------------------------------------------------------------*/ -// Overrides for CMD_RADIO_SETUP +/* Overrides for CMD_RADIO_SETUP */ uint32_t rf_ble_overrides[] CC_ALIGN(4) = { - // override_use_patch_ble_1mbps.xml - MCE_RFE_OVERRIDE(0,0,0,1,0,0), // PHY: Use MCE ROM, RFE RAM patch - // override_synth_ble_1mbps.xml - HW_REG_OVERRIDE(0x4038,0x0034), // Synth: Set recommended RTRIM to 4 - (uint32_t)0x000784A3, // Synth: Set Fref to 3.43 MHz - HW_REG_OVERRIDE(0x4020,0x7F00), // Synth: Configure fine calibration setting - HW_REG_OVERRIDE(0x4064,0x0040), // Synth: Configure fine calibration setting - (uint32_t)0xB1070503, // Synth: Configure fine calibration setting - (uint32_t)0x05330523, // Synth: Configure fine calibration setting - (uint32_t)0xA47E0583, // Synth: Set loop bandwidth after lock to 80 kHz - (uint32_t)0xEAE00603, // Synth: Set loop bandwidth after lock to 80 kHz - (uint32_t)0x00010623, // Synth: Set loop bandwidth after lock to 80 kHz - HW32_ARRAY_OVERRIDE(0x405C,1), // Synth: Configure PLL bias - (uint32_t)0x18000000, // Synth: Configure PLL bias - ADI_REG_OVERRIDE(1,4,0x9F), // Synth: Configure VCO LDO (in ADI1, set VCOLDOCFG=0x9F to use voltage input reference) - ADI_HALFREG_OVERRIDE(1,7,0x4,0x4), // Synth: Configure synth LDO (in ADI1, set SLDOCTL0.COMP_CAP=1) - // override_phy_ble_1mbps.xml - (uint32_t)0x013800C3, // Tx: Configure symbol shape for BLE frequency deviation requirements - HW_REG_OVERRIDE(0x6088, 0x0045), // Rx: Configure AGC reference level - HW_REG_OVERRIDE(0x6084, 0x05FD), // Rx: Configure AGC gain level - (uint32_t)0x00038883, // Rx: Configure LNA bias current trim offset - // override_frontend_xd.xml - (uint32_t)0x00F388A3, // Rx: Set RSSI offset to adjust reported RSSI by +13 dB - // TX power override - ADI_REG_OVERRIDE(0,12,0xF8), // Tx: Set PA trim to max (in ADI0, set PACTL0=0xF8) - (uint32_t)0xFFFFFFFF, + /* override_use_patch_ble_1mbps.xml */ + MCE_RFE_OVERRIDE(0,0,0,1,0,0), /* PHY: Use MCE ROM, RFE RAM patch */ + /* override_synth_ble_1mbps.xml */ + HW_REG_OVERRIDE(0x4038,0x0034), /* Synth: Set recommended RTRIM to 4 */ + (uint32_t)0x000784A3, /* Synth: Set Fref to 3.43 MHz */ + HW_REG_OVERRIDE(0x4020,0x7F00), /* Synth: Configure fine calibration setting */ + HW_REG_OVERRIDE(0x4064,0x0040), /* Synth: Configure fine calibration setting */ + (uint32_t)0xB1070503, /* Synth: Configure fine calibration setting */ + (uint32_t)0x05330523, /* Synth: Configure fine calibration setting */ + (uint32_t)0xA47E0583, /* Synth: Set loop bandwidth after lock to 80 kHz */ + (uint32_t)0xEAE00603, /* Synth: Set loop bandwidth after lock to 80 kHz */ + (uint32_t)0x00010623, /* Synth: Set loop bandwidth after lock to 80 kHz */ + HW32_ARRAY_OVERRIDE(0x405C,1), /* Synth: Configure PLL bias */ + (uint32_t)0x18000000, /* Synth: Configure PLL bias */ + /* Synth: Configure VCO LDO */ + ADI_REG_OVERRIDE(1,4,0x9F), /* (in ADI1, set VCOLDOCFG=0x9F to use voltage input reference) */ + ADI_HALFREG_OVERRIDE(1,7,0x4,0x4), /* Synth: Configure synth LDO (in ADI1, set SLDOCTL0.COMP_CAP=1) */ + /* override_phy_ble_1mbps.xml */ + (uint32_t)0x013800C3, /* Tx: Configure symbol shape for BLE frequency deviation requirements */ + HW_REG_OVERRIDE(0x6088, 0x0045), /* Rx: Configure AGC reference level */ + HW_REG_OVERRIDE(0x6084, 0x05FD), /* Rx: Configure AGC gain level */ + (uint32_t)0x00038883, /* Rx: Configure LNA bias current trim offset */ + /* override_frontend_xd.xml */ + (uint32_t)0x00F388A3, /* Rx: Set RSSI offset to adjust reported RSSI by +13 dB */ + /* TX power override */ + ADI_REG_OVERRIDE(0,12,0xF8), /* Tx: Set PA trim to max (in ADI0, set PACTL0=0xF8) */ + (uint32_t)0xFFFFFFFF, }; /*---------------------------------------------------------------------------*/ -// CMD_RADIO_SETUP -// Radio Setup Command for Pre-Defined Schemes +/* CMD_RADIO_SETUP: Radio Setup Command for Pre-Defined Schemes */ rfc_CMD_RADIO_SETUP_t rf_ble_cmd_radio_setup = { - .commandNo = 0x0802, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .mode = 0x00, - .loDivider = 0x00, - .config.frontEndMode = 0x0, - .config.biasMode = 0x1, - .config.analogCfgMode = 0x0, - .config.bNoFsPowerUp = 0x0, - .txPower = 0x3D3F, - .pRegOverride = rf_ble_overrides, + .commandNo = CMD_RADIO_SETUP, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .mode = 0x00, + .loDivider = 0x00, + .config.frontEndMode = 0x0, + .config.biasMode = 0x1, + .config.analogCfgMode = 0x0, + .config.bNoFsPowerUp = 0x0, + .txPower = 0x3D3F, + .pRegOverride = rf_ble_overrides, }; /*---------------------------------------------------------------------------*/ -// Structure for CMD_BLE_ADV_NC.pParams +/* Structure for CMD_BLE_ADV_NC.pParams */ rfc_bleAdvPar_t rf_ble_adv_par = { - .pRxQ = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx - .rxConfig.bAutoFlushIgnored = 0x0, - .rxConfig.bAutoFlushCrcErr = 0x0, - .rxConfig.bAutoFlushEmpty = 0x0, - .rxConfig.bIncludeLenByte = 0x0, - .rxConfig.bIncludeCrc = 0x0, - .rxConfig.bAppendRssi = 0x0, - .rxConfig.bAppendStatus = 0x0, - .rxConfig.bAppendTimestamp = 0x0, - .advConfig.advFilterPolicy = 0x0, - .advConfig.deviceAddrType = 0x0, - .advConfig.peerAddrType = 0x0, - .advConfig.bStrictLenFilter = 0x0, - .advConfig.rpaMode = 0x0, - .advLen = 0x18, - .scanRspLen = 0x00, - .pAdvData = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .pScanRspData = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .pDeviceAddress = 0, // INSERT APPLICABLE POINTER: (uint16_t*)&xxx - .pWhiteList = 0, // INSERT APPLICABLE POINTER: (uint32_t*)&xxx - .__dummy0 = 0x0000, - .__dummy1 = 0x00, - .endTrigger.triggerType = 0x1, - .endTrigger.bEnaCmd = 0x0, - .endTrigger.triggerNo = 0x0, - .endTrigger.pastTrig = 0x0, - .endTime = 0x00000000, + .pRxQ = 0, + .rxConfig.bAutoFlushIgnored = 0x0, + .rxConfig.bAutoFlushCrcErr = 0x0, + .rxConfig.bAutoFlushEmpty = 0x0, + .rxConfig.bIncludeLenByte = 0x0, + .rxConfig.bIncludeCrc = 0x0, + .rxConfig.bAppendRssi = 0x0, + .rxConfig.bAppendStatus = 0x0, + .rxConfig.bAppendTimestamp = 0x0, + .advConfig.advFilterPolicy = 0x0, + .advConfig.deviceAddrType = 0x0, + .advConfig.peerAddrType = 0x0, + .advConfig.bStrictLenFilter = 0x0, + .advConfig.rpaMode = 0x0, + .advLen = 0x18, + .scanRspLen = 0x00, + .pAdvData = 0, + .pScanRspData = 0, + .pDeviceAddress = 0, + .pWhiteList = 0, + .__dummy0 = 0x0000, + .__dummy1 = 0x00, + .endTrigger.triggerType = TRIG_NEVER, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, }; /*---------------------------------------------------------------------------*/ -// CMD_BLE_ADV_NC -// BLE Non-Connectable Advertiser Command +/* CMD_BLE_ADV_NC: BLE Non-Connectable Advertiser Command */ rfc_CMD_BLE_ADV_NC_t rf_ble_cmd_ble_adv_nc = { - .commandNo = 0x1805, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .channel = 0x8C, - .whitening.init = 0x51, - .whitening.bOverride = 0x1, - .pParams = &rf_ble_adv_par, - .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .commandNo = CMD_BLE_ADV_NC, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .channel = 0x8C, + .whitening.init = 0x51, + .whitening.bOverride = 0x1, + .pParams = &rf_ble_adv_par, + .pOutput = 0, }; /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.h index 3da978339..83d2614aa 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.h @@ -38,21 +38,21 @@ #include /*---------------------------------------------------------------------------*/ -// TX Power table size definition +/* TX Power table size definition */ #define RF_BLE_TX_POWER_TABLE_SIZE 17 -// TX Power Table Object +/* TX Power Table Object */ extern RF_TxPowerTable_Entry rf_ble_tx_power_table[RF_BLE_TX_POWER_TABLE_SIZE+1]; /*---------------------------------------------------------------------------*/ -// TI-RTOS RF Mode Object +/* TI-RTOS RF Mode Object */ extern RF_Mode rf_ble_mode; /*---------------------------------------------------------------------------*/ -// RF Core API commands +/* RF Core API commands */ extern rfc_CMD_RADIO_SETUP_t rf_ble_cmd_radio_setup; extern rfc_bleAdvPar_t rf_ble_adv_par; extern rfc_CMD_BLE_ADV_NC_t rf_ble_cmd_ble_adv_nc; /*---------------------------------------------------------------------------*/ -// RF Core API Overrides +/* RF Core API Overrides */ extern uint32_t rf_ble_overrides[]; /*---------------------------------------------------------------------------*/ #endif /* BLE_SETTINGS_H_ */ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c index 7a455862c..d51fec78c 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c @@ -28,242 +28,244 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /*---------------------------------------------------------------------------*/ -// Parameter summary -// IEEE Channel: 11 -// Frequency: 2405 MHz -// SFD: 0 -// Packet Data: 255 -// Preamble (32 bit): 01010101... -// TX Power: 5 dBm +/* + * Parameter summary + * IEEE Channel: 11 + * Frequency: 2405 MHz + * SFD: 0 + * Packet Data: 255 + * Preamble (32 bit): 01010101... + * TX Power: 5 dBm (requires define CCFG_FORCE_VDDR_HH = 0 in ccfg.c, + * see CC13xx/CC26xx Technical Reference Manual) + */ /*---------------------------------------------------------------------------*/ #include "sys/cc.h" /*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) -// This must be included "locally" frm the cpu directory, -// as it isn't defined in CC13x0 driverlib +/* + * rf_ieee_cmd.h must be included "locally" from the arch/cpu directory, + * as it isn't defined in CC13x0 driverlib. + */ #include "driverlib/rf_ieee_cmd.h" #include /*---------------------------------------------------------------------------*/ #include "ieee-settings.h" /*---------------------------------------------------------------------------*/ -// TI-RTOS RF Mode Object +/* TI-RTOS RF Mode Object */ RF_Mode rf_ieee_mode = { - .rfMode = RF_MODE_IEEE_15_4, - .cpePatchFxn = 0, - .mcePatchFxn = 0, - .rfePatchFxn = 0, + .rfMode = RF_MODE_IEEE_15_4, + .cpePatchFxn = 0, + .mcePatchFxn = 0, + .rfePatchFxn = 0, }; /*---------------------------------------------------------------------------*/ -// TX Power table -// The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: -// RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) -// See the Technical Reference Manual for further details about the "txPower" Command field. -// The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. +/* + * TX Power table + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ RF_TxPowerTable_Entry rf_ieee_tx_power_table[RF_IEEE_TX_POWER_TABLE_SIZE+1] = { - { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 6) }, - { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 6) }, - { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 6) }, - { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 1, 0, 10) }, - { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 1, 12) }, - { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(18, 1, 1, 14) }, - { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 1, 1, 18) }, - { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(33, 1, 1, 24) }, - { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 0, 0, 33) }, - { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 0, 0, 39) }, - { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 0, 0, 45) }, - { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(36, 0, 1, 73) }, - { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(48, 0, 1, 73) }, - RF_TxPowerTable_TERMINATION_ENTRY + { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 6) }, + { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 6) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 6) }, + { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 1, 0, 10) }, + { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 1, 12) }, + { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(18, 1, 1, 14) }, + { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 1, 1, 18) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(33, 1, 1, 24) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 0, 0, 33) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 0, 0, 39) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 0, 0, 45) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(36, 0, 1, 73) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(48, 0, 1, 73) }, + RF_TxPowerTable_TERMINATION_ENTRY }; /*---------------------------------------------------------------------------*/ -// Overrides for CMD_RADIO_SETUP (CC2650) +/* Overrides for CMD_RADIO_SETUP */ uint32_t rf_ieee_overrides[] CC_ALIGN(4) = { - // override_synth_ieee_15_4.xml - HW_REG_OVERRIDE(0x4038,0x0035), // Synth: Set recommended RTRIM to 5 - (uint32_t)0x000784A3, // Synth: Set Fref to 3.43 MHz - (uint32_t)0xA47E0583, // Synth: Set loop bandwidth after lock to 80 kHz - (uint32_t)0xEAE00603, // Synth: Set loop bandwidth after lock to 80 kHz - (uint32_t)0x00010623, // Synth: Set loop bandwidth after lock to 80 kHz - HW32_ARRAY_OVERRIDE(0x405C,1), // Synth: Configure PLL bias - (uint32_t)0x1801F800, // Synth: Configure PLL bias - HW32_ARRAY_OVERRIDE(0x402C,1), // Synth: Configure PLL latency - (uint32_t)0x00608402, // Synth: Configure PLL latency - (uint32_t)0x02010403, // Synth: Use 24 MHz XOSC as synth clock, enable extra PLL filtering - HW32_ARRAY_OVERRIDE(0x4034,1), // Synth: Configure extra PLL filtering - (uint32_t)0x177F0408, // Synth: Configure extra PLL filtering - (uint32_t)0x38000463, // Synth: Configure extra PLL filtering - // override_phy_ieee_15_4.xml - (uint32_t)0x05000243, // Synth: Increase synth programming timeout - (uint32_t)0x002082C3, // Rx: Adjust Rx FIFO threshold to avoid overflow - // override_frontend_id.xml - (uint32_t)0x000288A3, // Rx: Set RSSI offset to adjust reported RSSI by -2 dB - (uint32_t)0x000F8883, // Rx: Configure LNA bias current trim offset - HW_REG_OVERRIDE(0x50DC,0x002B), // Rx: Adjust AGC DC filter - (uint32_t)0xFFFFFFFF, + /* override_synth_ieee_15_4.xml */ + HW_REG_OVERRIDE(0x4038,0x0035), /* Synth: Set recommended RTRIM to 5 */ + (uint32_t)0x000784A3, /* Synth: Set Fref to 3.43 MHz */ + (uint32_t)0xA47E0583, /* Synth: Set loop bandwidth after lock to 80 kHz */ + (uint32_t)0xEAE00603, /* Synth: Set loop bandwidth after lock to 80 kHz */ + (uint32_t)0x00010623, /* Synth: Set loop bandwidth after lock to 80 kHz */ + HW32_ARRAY_OVERRIDE(0x405C,1), /* Synth: Configure PLL bias */ + (uint32_t)0x1801F800, /* Synth: Configure PLL bias */ + HW32_ARRAY_OVERRIDE(0x402C,1), /* Synth: Configure PLL latency */ + (uint32_t)0x00608402, /* Synth: Configure PLL latency */ + (uint32_t)0x02010403, /* Synth: Use 24 MHz XOSC as synth clock, enable extra PLL filtering */ + HW32_ARRAY_OVERRIDE(0x4034,1), /* Synth: Configure extra PLL filtering */ + (uint32_t)0x177F0408, /* Synth: Configure extra PLL filtering */ + (uint32_t)0x38000463, /* Synth: Configure extra PLL filtering */ + /* override_phy_ieee_15_4.xml */ + (uint32_t)0x05000243, /* Synth: Increase synth programming timeout */ + (uint32_t)0x002082C3, /* Rx: Adjust Rx FIFO threshold to avoid overflow */ + /* override_frontend_id.xml */ + (uint32_t)0x000288A3, /* Rx: Set RSSI offset to adjust reported RSSI by -2 dB */ + (uint32_t)0x000F8883, /* Rx: Configure LNA bias current trim offset */ + HW_REG_OVERRIDE(0x50DC,0x002B), /* Rx: Adjust AGC DC filter */ + (uint32_t)0xFFFFFFFF, }; /*---------------------------------------------------------------------------*/ -// CMD_RADIO_SETUP -// Radio Setup Command for Pre-Defined Schemes +/* CMD_RADIO_SETUP: Radio Setup Command for Pre-Defined Schemes */ rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup = { - .commandNo = CMD_RADIO_SETUP, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .mode = 0x01, - .config.frontEndMode = 0x0, - .config.biasMode = 0x1, - .config.analogCfgMode = 0x0, - .config.bNoFsPowerUp = 0x0, - .txPower = 0x9330, /* 5 dBm default */ - .pRegOverride = rf_ieee_overrides, + .commandNo = CMD_RADIO_SETUP, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .mode = 0x01, + .config.frontEndMode = 0x0, + .config.biasMode = 0x1, + .config.analogCfgMode = 0x0, + .config.bNoFsPowerUp = 0x0, + .txPower = 0x9330, /* 5 dBm default */ + .pRegOverride = rf_ieee_overrides, }; /*---------------------------------------------------------------------------*/ -// CMD_FS -// Frequency Synthesizer Programming Command +/* CMD_FS: Frequency Synthesizer Programming Command */ rfc_CMD_FS_t rf_cmd_ieee_fs = { - .commandNo = CMD_FS, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .frequency = 0x0965, /* set by driver */ - .fractFreq = 0x0000, /* set by driver */ - .synthConf.bTxMode = 0x1, - .synthConf.refFreq = 0x0, - .__dummy0 = 0x00, - .__dummy1 = 0x00, - .__dummy2 = 0x00, - .__dummy3 = 0x0000, + .commandNo = CMD_FS, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .frequency = 0x0965, /* set by driver */ + .fractFreq = 0x0000, /* set by driver */ + .synthConf.bTxMode = 0x1, + .synthConf.refFreq = 0x0, + .__dummy0 = 0x00, + .__dummy1 = 0x00, + .__dummy2 = 0x00, + .__dummy3 = 0x0000, }; /*---------------------------------------------------------------------------*/ -// CMD_IEEE_TX -// The command ID number 0x2C01 +/* CMD_IEEE_TX: IEEE 802.15.4 Transmit Command */ rfc_CMD_IEEE_TX_t rf_cmd_ieee_tx = { - .commandNo = CMD_IEEE_TX, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .txOpt.bIncludePhyHdr = 0x0, - .txOpt.bIncludeCrc = 0x0, - .txOpt.payloadLenMsb = 0x0, - .payloadLen = 0x0, /* set by driver */ - .pPayload = 0, /* set by driver */ - .timeStamp = 0x00000000, + .commandNo = CMD_IEEE_TX, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .txOpt.bIncludePhyHdr = 0x0, + .txOpt.bIncludeCrc = 0x0, + .txOpt.payloadLenMsb = 0x0, + .payloadLen = 0x0, /* set by driver */ + .pPayload = 0, /* set by driver */ + .timeStamp = 0x00000000, }; /*---------------------------------------------------------------------------*/ -// CMD_IEEE_RX -// The command ID number 0x2801 +/* CMD_IEEE_RX: IEEE 802.15.4 Receive Command */ rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx = { - .commandNo = CMD_IEEE_RX, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .channel = 0x00, /* set by driver */ - .rxConfig.bAutoFlushCrc = 0x1, - .rxConfig.bAutoFlushIgn = 0x0, - .rxConfig.bIncludePhyHdr = 0x0, - .rxConfig.bIncludeCrc = 0x1, - .rxConfig.bAppendRssi = 0x1, - .rxConfig.bAppendCorrCrc = 0x1, - .rxConfig.bAppendSrcInd = 0x0, - .rxConfig.bAppendTimestamp = 0x1, - .pRxQ = 0, /* set by driver */ - .pOutput = 0, /* set by driver */ - .frameFiltOpt.frameFiltEn = 0x0, /* set by driver */ - .frameFiltOpt.frameFiltStop = 0x1, - .frameFiltOpt.autoAckEn = 0x0, /* set by driver */ - .frameFiltOpt.slottedAckEn = 0x0, - .frameFiltOpt.autoPendEn = 0x0, - .frameFiltOpt.defaultPend = 0x0, - .frameFiltOpt.bPendDataReqOnly = 0x0, - .frameFiltOpt.bPanCoord = 0x0, - .frameFiltOpt.maxFrameVersion = 0x2, - .frameFiltOpt.fcfReservedMask = 0x0, - .frameFiltOpt.modifyFtFilter = 0x0, - .frameFiltOpt.bStrictLenFilter = 0x0, - .frameTypes.bAcceptFt0Beacon = 0x1, - .frameTypes.bAcceptFt1Data = 0x1, - .frameTypes.bAcceptFt2Ack = 0x1, - .frameTypes.bAcceptFt3MacCmd = 0x1, - .frameTypes.bAcceptFt4Reserved = 0x1, - .frameTypes.bAcceptFt5Reserved = 0x1, - .frameTypes.bAcceptFt6Reserved = 0x1, - .frameTypes.bAcceptFt7Reserved = 0x1, - .ccaOpt.ccaEnEnergy = 0x1, - .ccaOpt.ccaEnCorr = 0x1, - .ccaOpt.ccaEnSync = 0x1, - .ccaOpt.ccaCorrOp = 0x1, - .ccaOpt.ccaSyncOp = 0x0, - .ccaOpt.ccaCorrThr = 0x3, - .ccaRssiThr = 0x0, /* set by driver */ - .__dummy0 = 0x00, - .numExtEntries = 0x00, - .numShortEntries = 0x00, - .pExtEntryList = 0, - .pShortEntryList = 0, - .localExtAddr = 0x0, /* set by driver */ - .localShortAddr = 0x0, /* set by driver */ - .localPanID = 0x0000, - .__dummy1 = 0x000000, - .endTrigger.triggerType = TRIG_NEVER, - .endTrigger.bEnaCmd = 0x0, - .endTrigger.triggerNo = 0x0, - .endTrigger.pastTrig = 0x0, - .endTime = 0x00000000, + .commandNo = CMD_IEEE_RX, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .channel = 0x00, /* set by driver */ + .rxConfig.bAutoFlushCrc = 0x1, + .rxConfig.bAutoFlushIgn = 0x0, + .rxConfig.bIncludePhyHdr = 0x0, + .rxConfig.bIncludeCrc = 0x1, + .rxConfig.bAppendRssi = 0x1, + .rxConfig.bAppendCorrCrc = 0x1, + .rxConfig.bAppendSrcInd = 0x0, + .rxConfig.bAppendTimestamp = 0x1, + .pRxQ = 0, /* set by driver */ + .pOutput = 0, /* set by driver */ + .frameFiltOpt.frameFiltEn = 0x0, /* set by driver */ + .frameFiltOpt.frameFiltStop = 0x1, + .frameFiltOpt.autoAckEn = 0x0, /* set by driver */ + .frameFiltOpt.slottedAckEn = 0x0, + .frameFiltOpt.autoPendEn = 0x0, + .frameFiltOpt.defaultPend = 0x0, + .frameFiltOpt.bPendDataReqOnly = 0x0, + .frameFiltOpt.bPanCoord = 0x0, + .frameFiltOpt.maxFrameVersion = 0x2, + .frameFiltOpt.fcfReservedMask = 0x0, + .frameFiltOpt.modifyFtFilter = 0x0, + .frameFiltOpt.bStrictLenFilter = 0x0, + .frameTypes.bAcceptFt0Beacon = 0x1, + .frameTypes.bAcceptFt1Data = 0x1, + .frameTypes.bAcceptFt2Ack = 0x1, + .frameTypes.bAcceptFt3MacCmd = 0x1, + .frameTypes.bAcceptFt4Reserved = 0x1, + .frameTypes.bAcceptFt5Reserved = 0x1, + .frameTypes.bAcceptFt6Reserved = 0x1, + .frameTypes.bAcceptFt7Reserved = 0x1, + .ccaOpt.ccaEnEnergy = 0x1, + .ccaOpt.ccaEnCorr = 0x1, + .ccaOpt.ccaEnSync = 0x1, + .ccaOpt.ccaCorrOp = 0x1, + .ccaOpt.ccaSyncOp = 0x0, + .ccaOpt.ccaCorrThr = 0x3, + .ccaRssiThr = 0x0, /* set by driver */ + .__dummy0 = 0x00, + .numExtEntries = 0x00, + .numShortEntries = 0x00, + .pExtEntryList = 0, + .pShortEntryList = 0, + .localExtAddr = 0x0, /* set by driver */ + .localShortAddr = 0x0, /* set by driver */ + .localPanID = 0x0000, + .__dummy1 = 0x000000, + .endTrigger.triggerType = TRIG_NEVER, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, }; /*---------------------------------------------------------------------------*/ -// CMD_IEEE_RX_ACK -// IEEE 802.15.4 Receive ACK Command +/* CMD_IEEE_RX_ACK: IEEE 802.15.4 Receive ACK Command */ rfc_CMD_IEEE_RX_ACK_t rf_cmd_ieee_rx_ack = { - .commandNo = CMD_IEEE_RX_ACK, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .seqNo = 0x0, - .endTrigger.triggerType = TRIG_NEVER, - .endTrigger.bEnaCmd = 0x0, - .endTrigger.triggerNo = 0x0, - .endTrigger.pastTrig = 0x0, - .endTime = 0x00000000, + .commandNo = CMD_IEEE_RX_ACK, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .seqNo = 0x0, + .endTrigger.triggerType = TRIG_NEVER, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, }; /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h index 305b56855..5f66f8b5d 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h @@ -34,29 +34,31 @@ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) -// These two headers must be included "locally" frm the cpu directory, -// as they aren't defined in CC13x0 driverlib +/* + * These two headers must be included "locally" from the arch/cpu directory, + * as they aren't defined in CC13x0 driverlib. + */ #include "driverlib/rf_ieee_cmd.h" #include "driverlib/rf_ieee_mailbox.h" #include /*---------------------------------------------------------------------------*/ -// TI-RTOS RF Mode Object +/* TI-RTOS RF Mode Object */ extern RF_Mode rf_ieee_mode; /*---------------------------------------------------------------------------*/ -// TX Power Table +/* TX Power Table */ #define RF_IEEE_TX_POWER_TABLE_SIZE 13 extern RF_TxPowerTable_Entry rf_ieee_tx_power_table[RF_IEEE_TX_POWER_TABLE_SIZE+1]; /*---------------------------------------------------------------------------*/ -// RF Core API commands +/* RF Core API commands */ extern rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup; extern rfc_CMD_FS_t rf_cmd_ieee_fs; extern rfc_CMD_IEEE_TX_t rf_cmd_ieee_tx; extern rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx; extern rfc_CMD_IEEE_RX_ACK_t rf_cmd_ieee_rx_ack; /*---------------------------------------------------------------------------*/ -// RF Core API Overrides +/* RF Core API Overrides */ extern uint32_t rf_ieee_overrides[]; /*---------------------------------------------------------------------------*/ #endif /* IEEE_SETTINGS_H_ */ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c index 82eb40180..e32d93d31 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c @@ -28,25 +28,28 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /*---------------------------------------------------------------------------*/ -// Parameter summary -// Address: 0 -// Address0: 0xAA -// Address1: 0xBB -// Frequency: 868.00000 MHz -// Data Format: Serial mode disable -// Deviation: 25.000 kHz -// pktLen: 30 -// 802.15.4g Mode: 0 -// Select bit order to transmit PSDU octets:: 1 -// Packet Length Config: Variable -// Max Packet Length: 255 -// Packet Length: 0 -// Packet Data: 255 -// RX Filter BW: 98 kHz -// Symbol Rate: 50.00000 kBaud -// Sync Word Length: 24 Bits -// TX Power: 14 dBm (requires define CCFG_FORCE_VDDR_HH = 1 in ccfg.c, see CC13xx/CC26xx Technical Reference Manual) -// Whitening: Dynamically IEEE 802.15.4g compatible whitener and 16/32-bit CRC +/* + * Parameter summary + * Address: 0 + * Address0: 0xAA + * Address1: 0xBB + * Frequency: 868.00000 MHz + * Data Format: Serial mode disable + * Deviation: 25.000 kHz + * pktLen: 30 + * 802.15.4g Mode: 0 + * Select bit order to transmit PSDU octets:: 1 + * Packet Length Config: Variable + * Max Packet Length: 255 + * Packet Length: 0 + * Packet Data: 255 + * RX Filter BW: 98 kHz + * Symbol Rate: 50.00000 kBaud + * Sync Word Length: 24 Bits + * TX Power: 14 dBm (requires define CCFG_FORCE_VDDR_HH = 1 in ccfg.c, + * see CC13xx/CC26xx Technical Reference Manual) + * Whitening: Dynamically IEEE 802.15.4g compatible whitener and 16/32-bit CRC + */ /*---------------------------------------------------------------------------*/ #include "sys/cc.h" /*---------------------------------------------------------------------------*/ @@ -61,218 +64,227 @@ /*---------------------------------------------------------------------------*/ #include "prop-settings.h" /*---------------------------------------------------------------------------*/ -// TI-RTOS RF Mode Object +/* TI-RTOS RF Mode Object */ RF_Mode rf_prop_mode = { - .rfMode = RF_MODE_PROPRIETARY_SUB_1, - .cpePatchFxn = &rf_patch_cpe_genfsk, - .mcePatchFxn = 0, - .rfePatchFxn = &rf_patch_rfe_genfsk, + .rfMode = RF_MODE_PROPRIETARY_SUB_1, + .cpePatchFxn = &rf_patch_cpe_genfsk, + .mcePatchFxn = 0, + .rfePatchFxn = &rf_patch_rfe_genfsk, }; /*---------------------------------------------------------------------------*/ -// TX Power table -// The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: -// RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) -// See the Technical Reference Manual for further details about the "txPower" Command field. -// The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. +/* + * TX Power table + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ RF_TxPowerTable_Entry rf_prop_tx_power_table[RF_PROP_TX_POWER_TABLE_SIZE+1] = { - { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY( 0, 3, 0, 4) }, - { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY( 1, 1, 0, 0) }, - { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY( 3, 3, 0, 8) }, - { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY( 2, 1, 0, 8) }, - { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 3, 0, 10) }, - { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY( 5, 3, 0, 12) }, - { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY( 6, 3, 0, 12) }, - { 6, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 14) }, - { 7, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 16) }, - { 8, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 18) }, - { 9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 3, 0, 22) }, - { 10, RF_TxPowerTable_DEFAULT_PA_ENTRY(19, 3, 0, 28) }, - { 11, RF_TxPowerTable_DEFAULT_PA_ENTRY(26, 3, 0, 40) }, - { 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 0, 0, 92) }, - { 13, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 0, 83) }, // The original PA value (12.5 dBm) have been rounded to an integer value. - { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 83) }, // This setting requires CCFG_FORCE_VDDR_HH = 1. - RF_TxPowerTable_TERMINATION_ENTRY + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY( 0, 3, 0, 4) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY( 1, 1, 0, 0) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY( 3, 3, 0, 8) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY( 2, 1, 0, 8) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 3, 0, 10) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY( 5, 3, 0, 12) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY( 6, 3, 0, 12) }, + { 6, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 14) }, + { 7, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 16) }, + { 8, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 18) }, + { 9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 3, 0, 22) }, + { 10, RF_TxPowerTable_DEFAULT_PA_ENTRY(19, 3, 0, 28) }, + { 11, RF_TxPowerTable_DEFAULT_PA_ENTRY(26, 3, 0, 40) }, + { 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 0, 0, 92) }, + /* The original PA value (12.5 dBm) have been rounded to an integer value. */ + { 13, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 0, 83) }, + /* This setting requires CCFG_FORCE_VDDR_HH = 1. */ + { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 83) }, + RF_TxPowerTable_TERMINATION_ENTRY }; /*---------------------------------------------------------------------------*/ -// Overrides for CMD_PROP_RADIO_DIV_SETUP +/* Overrides for CMD_PROP_RADIO_DIV_SETUP */ uint32_t rf_prop_overrides[] CC_ALIGN(4) = { - // override_use_patch_prop_genfsk.xml - MCE_RFE_OVERRIDE(0,4,0,1,0,0), // PHY: Use MCE ROM bank 4, RFE RAM patch - // override_synth_prop_863_930_div5.xml - HW_REG_OVERRIDE(0x4038,0x0037), // Synth: Set recommended RTRIM to 7 - (uint32_t)0x000684A3, // Synth: Set Fref to 4 MHz - HW_REG_OVERRIDE(0x4020,0x7F00), // Synth: Configure fine calibration setting - HW_REG_OVERRIDE(0x4064,0x0040), // Synth: Configure fine calibration setting - (uint32_t)0xB1070503, // Synth: Configure fine calibration setting - (uint32_t)0x05330523, // Synth: Configure fine calibration setting - (uint32_t)0x0A480583, // Synth: Set loop bandwidth after lock to 20 kHz - (uint32_t)0x7AB80603, // Synth: Set loop bandwidth after lock to 20 kHz - ADI_REG_OVERRIDE(1,4,0x9F), // Synth: Configure VCO LDO (in ADI1, set VCOLDOCFG=0x9F to use voltage input reference) - ADI_HALFREG_OVERRIDE(1,7,0x4,0x4), // Synth: Configure synth LDO (in ADI1, set SLDOCTL0.COMP_CAP=1) - (uint32_t)0x02010403, // Synth: Use 24 MHz XOSC as synth clock, enable extra PLL filtering - (uint32_t)0x00108463, // Synth: Configure extra PLL filtering - (uint32_t)0x04B00243, // Synth: Increase synth programming timeout (0x04B0 RAT ticks = 300 us) - // override_phy_rx_aaf_bw_0xd.xml - ADI_HALFREG_OVERRIDE(0,61,0xF,0xD), // Rx: Set anti-aliasing filter bandwidth to 0xD (in ADI0, set IFAMPCTL3[7:4]=0xD) - // override_phy_gfsk_rx.xml - (uint32_t)0x00038883, // Rx: Set LNA bias current trim offset to 3 - HW_REG_OVERRIDE(0x6084,0x35F1), // Rx: Freeze RSSI on sync found event - // override_phy_gfsk_pa_ramp_agc_reflevel_0x1a.xml - HW_REG_OVERRIDE(0x6088,0x411A), // Tx: Configure PA ramping setting (0x41). Rx: Set AGC reference level to 0x1A. - HW_REG_OVERRIDE(0x608C,0x8213), // Tx: Configure PA ramping setting - // override_crc_ieee_802_15_4.xml - (uint32_t)0x00000943, // IEEE 802.15.4g: Fix incorrect initialization value for CRC-16 calculation (see TRM section 23.7.5.2.1) - (uint32_t)0x00000963, // IEEE 802.15.4g: Fix incorrect initialization value for CRC-16 calculation (see TRM section 23.7.5.2.1) - // override_phy_rx_rssi_offset_5db.xml - (uint32_t)0x00FB88A3, // Rx: Set RSSI offset to adjust reported RSSI by +5 dB - // TX power override - ADI_REG_OVERRIDE(0,12,0xF8), // Tx: Set PA trim to max (in ADI0, set PACTL0=0xF8) - (uint32_t)0xFFFFFFFF, + /* override_use_patch_prop_genfsk.xml */ + MCE_RFE_OVERRIDE(0,4,0,1,0,0), /* PHY: Use MCE ROM bank 4, RFE RAM patch */ + /* override_synth_prop_863_930_div5.xml */ + HW_REG_OVERRIDE(0x4038,0x0037), /* Synth: Set recommended RTRIM to 7 */ + (uint32_t)0x000684A3, /* Synth: Set Fref to 4 MHz */ + HW_REG_OVERRIDE(0x4020,0x7F00), /* Synth: Configure fine calibration setting */ + HW_REG_OVERRIDE(0x4064,0x0040), /* Synth: Configure fine calibration setting */ + (uint32_t)0xB1070503, /* Synth: Configure fine calibration setting */ + (uint32_t)0x05330523, /* Synth: Configure fine calibration setting */ + (uint32_t)0x0A480583, /* Synth: Set loop bandwidth after lock to 20 kHz */ + (uint32_t)0x7AB80603, /* Synth: Set loop bandwidth after lock to 20 kHz */ + /* Synth: Configure VCO LDO */ + ADI_REG_OVERRIDE(1,4,0x9F), /* (in ADI1, set VCOLDOCFG=0x9F to use voltage input reference) */ + ADI_HALFREG_OVERRIDE(1,7,0x4,0x4), /* Synth: Configure synth LDO (in ADI1, set SLDOCTL0.COMP_CAP=1) */ + (uint32_t)0x02010403, /* Synth: Use 24 MHz XOSC as synth clock, enable extra PLL filtering */ + (uint32_t)0x00108463, /* Synth: Configure extra PLL filtering */ + (uint32_t)0x04B00243, /* Synth: Increase synth programming timeout (0x04B0 RAT ticks = 300 us) */ + /* override_phy_rx_aaf_bw_0xd.xml */ + /* Rx: Set anti-aliasing filter bandwidth to 0xD */ + ADI_HALFREG_OVERRIDE(0,61,0xF,0xD), /* (in ADI0, set IFAMPCTL3[7:4]=0xD) */ + /* override_phy_gfsk_rx.xml */ + (uint32_t)0x00038883, /* Rx: Set LNA bias current trim offset to 3 */ + HW_REG_OVERRIDE(0x6084,0x35F1), /* Rx: Freeze RSSI on sync found event */ + /* override_phy_gfsk_pa_ramp_agc_reflevel_0x1a.xml */ + /* Tx: Configure PA ramping setting (0x41). */ + HW_REG_OVERRIDE(0x6088,0x411A), /* Rx: Set AGC reference level to 0x1A. */ + HW_REG_OVERRIDE(0x608C,0x8213), /* Tx: Configure PA ramping setting */ + /* override_crc_ieee_802_15_4.xml */ + /* IEEE 802.15.4g: Fix incorrect initialization value for */ + (uint32_t)0x00000943, /* CRC-16 calculation (see TRM section 23.7.5.2.1) */ + /* IEEE 802.15.4g: Fix incorrect initialization value for */ + (uint32_t)0x00000963, /* CRC-16 calculation (see TRM section 23.7.5.2.1) */ + /* override_phy_rx_rssi_offset_5db.xml */ + (uint32_t)0x00FB88A3, /* Rx: Set RSSI offset to adjust reported RSSI by +5 dB */ + /* TX power override */ + ADI_REG_OVERRIDE(0,12,0xF8), /* Tx: Set PA trim to max (in ADI0, set PACTL0=0xF8) */ + (uint32_t)0xFFFFFFFF, }; /*---------------------------------------------------------------------------*/ -// CMD_PROP_RADIO_DIV_SETUP -// Proprietary Mode Radio Setup Command for All Frequency Bands +/* CMD_PROP_RADIO_DIV_SETUP */ +/* Proprietary Mode Radio Setup Command for All Frequency Bands */ rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup = { - .commandNo = CMD_PROP_RADIO_DIV_SETUP, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .modulation.modType = 0x1, - .modulation.deviation = 0x64, - .symbolRate.preScale = 0xF, - .symbolRate.rateWord = 0x8000, - .rxBw = 0x24, - .preamConf.nPreamBytes = 0x7, - .preamConf.preamMode = 0x0, - .formatConf.nSwBits = 0x18, - .formatConf.bBitReversal = 0x0, - .formatConf.bMsbFirst = 0x1, - .formatConf.fecMode = 0x0, - .formatConf.whitenMode = 0x7, - .config.frontEndMode = 0x0, - .config.biasMode = 0x1, - .config.analogCfgMode = 0x0, - .config.bNoFsPowerUp = 0x0, - .txPower = 0xA73F, - .pRegOverride = rf_prop_overrides, - .centerFreq = 0x0364, - .intFreq = 0x8000, - .loDivider = 0x05, + .commandNo = CMD_PROP_RADIO_DIV_SETUP, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .modulation.modType = 0x1, + .modulation.deviation = 0x64, + .symbolRate.preScale = 0xF, + .symbolRate.rateWord = 0x8000, + .rxBw = 0x24, + .preamConf.nPreamBytes = 0x7, + .preamConf.preamMode = 0x0, + .formatConf.nSwBits = 0x18, + .formatConf.bBitReversal = 0x0, + .formatConf.bMsbFirst = 0x1, + .formatConf.fecMode = 0x0, + .formatConf.whitenMode = 0x7, + .config.frontEndMode = 0x0, /* set by driver */ + .config.biasMode = 0x1, /* set by driver */ + .config.analogCfgMode = 0x0, + .config.bNoFsPowerUp = 0x0, + .txPower = 0xA73F, + .pRegOverride = rf_prop_overrides, + .centerFreq = 0x0364, /* set by driver */ + .intFreq = 0x8000, /* set by driver */ + .loDivider = 0x05, /* set by driver */ }; /*---------------------------------------------------------------------------*/ -// CMD_FS -// Frequency Synthesizer Programming Command +/* CMD_FS */ +/* Frequency Synthesizer Programming Command */ rfc_CMD_FS_t rf_cmd_prop_fs = { - .commandNo = CMD_FS, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .frequency = 0x0364, - .fractFreq = 0x0000, - .synthConf.bTxMode = 0x0, - .synthConf.refFreq = 0x0, - .__dummy0 = 0x00, - .__dummy1 = 0x00, - .__dummy2 = 0x00, - .__dummy3 = 0x0000, + .commandNo = CMD_FS, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .frequency = 0x0364, /* set by driver */ + .fractFreq = 0x0000, /* set by driver */ + .synthConf.bTxMode = 0x0, + .synthConf.refFreq = 0x0, + .__dummy0 = 0x00, + .__dummy1 = 0x00, + .__dummy2 = 0x00, + .__dummy3 = 0x0000, }; /*---------------------------------------------------------------------------*/ -// CMD_PROP_TX_ADV -// Proprietary Mode Advanced Transmit Command +/* CMD_PROP_TX_ADV */ +/* Proprietary Mode Advanced Transmit Command */ rfc_CMD_PROP_TX_ADV_t rf_cmd_prop_tx_adv = { - .commandNo = CMD_PROP_TX_ADV, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .pktConf.bFsOff = 0x0, - .pktConf.bUseCrc = 0x1, - .pktConf.bCrcIncSw = 0x0, - .pktConf.bCrcIncHdr = 0x0, - .numHdrBits = 0x10, - .pktLen = 0x0, /* set by driver */ - .startConf.bExtTxTrig = 0x0, - .startConf.inputMode = 0x0, - .startConf.source = 0x0, - .preTrigger.triggerType = TRIG_REL_START, - .preTrigger.bEnaCmd = 0x0, - .preTrigger.triggerNo = 0x0, - .preTrigger.pastTrig = 0x1, - .preTime = 0x00000000, - .syncWord = 0x0055904E, - .pPkt = 0, /* set by driver */ + .commandNo = CMD_PROP_TX_ADV, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .pktConf.bFsOff = 0x0, + .pktConf.bUseCrc = 0x1, + .pktConf.bCrcIncSw = 0x0, + .pktConf.bCrcIncHdr = 0x0, + .numHdrBits = 0x10, + .pktLen = 0x0, /* set by driver */ + .startConf.bExtTxTrig = 0x0, + .startConf.inputMode = 0x0, + .startConf.source = 0x0, + .preTrigger.triggerType = TRIG_REL_START, + .preTrigger.bEnaCmd = 0x0, + .preTrigger.triggerNo = 0x0, + .preTrigger.pastTrig = 0x1, + .preTime = 0x00000000, + .syncWord = 0x0055904E, + .pPkt = 0, /* set by driver */ }; /*---------------------------------------------------------------------------*/ -// CMD_PROP_RX_ADV -// Proprietary Mode Advanced Receive Command +/* CMD_PROP_RX_ADV */ +/* Proprietary Mode Advanced Receive Command */ rfc_CMD_PROP_RX_ADV_t rf_cmd_prop_rx_adv = { - .commandNo = CMD_PROP_RX_ADV, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .pktConf.bFsOff = 0x0, - .pktConf.bRepeatOk = 0x1, - .pktConf.bRepeatNok = 0x1, - .pktConf.bUseCrc = 0x1, - .pktConf.bCrcIncSw = 0x0, - .pktConf.bCrcIncHdr = 0x0, - .pktConf.endType = 0x0, - .pktConf.filterOp = 0x1, - .rxConf.bAutoFlushIgnored = 0x1, - .rxConf.bAutoFlushCrcErr = 0x1, - .rxConf.bIncludeHdr = 0x0, - .rxConf.bIncludeCrc = 0x0, - .rxConf.bAppendRssi = 0x1, - .rxConf.bAppendTimestamp = 0x0, - .rxConf.bAppendStatus = 0x1, - .syncWord0 = 0x0055904E, - .syncWord1 = 0x00000000, - .maxPktLen = 0x0, /* set by driver */ - .hdrConf.numHdrBits = 0x10, - .hdrConf.lenPos = 0x0, - .hdrConf.numLenBits = 0x0B, - .addrConf.addrType = 0x0, - .addrConf.addrSize = 0x0, - .addrConf.addrPos = 0x0, - .addrConf.numAddr = 0x0, - .lenOffset = 0xFC, - .endTrigger.triggerType = TRIG_NEVER, - .endTrigger.bEnaCmd = 0x0, - .endTrigger.triggerNo = 0x0, - .endTrigger.pastTrig = 0x0, - .endTime = 0x00000000, - .pAddr = 0, /* set by driver */ - .pQueue = 0, /* set by driver */ - .pOutput = 0, /* set by driver */ + .commandNo = CMD_PROP_RX_ADV, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .pktConf.bFsOff = 0x0, + .pktConf.bRepeatOk = 0x1, + .pktConf.bRepeatNok = 0x1, + .pktConf.bUseCrc = 0x1, + .pktConf.bCrcIncSw = 0x0, + .pktConf.bCrcIncHdr = 0x0, + .pktConf.endType = 0x0, + .pktConf.filterOp = 0x1, + .rxConf.bAutoFlushIgnored = 0x1, + .rxConf.bAutoFlushCrcErr = 0x1, + .rxConf.bIncludeHdr = 0x0, + .rxConf.bIncludeCrc = 0x0, + .rxConf.bAppendRssi = 0x1, + .rxConf.bAppendTimestamp = 0x0, + .rxConf.bAppendStatus = 0x1, + .syncWord0 = 0x0055904E, + .syncWord1 = 0x00000000, + .maxPktLen = 0x0, /* set by driver */ + .hdrConf.numHdrBits = 0x10, + .hdrConf.lenPos = 0x0, + .hdrConf.numLenBits = 0x0B, + .addrConf.addrType = 0x0, + .addrConf.addrSize = 0x0, + .addrConf.addrPos = 0x0, + .addrConf.numAddr = 0x0, + .lenOffset = 0xFC, + .endTrigger.triggerType = TRIG_NEVER, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, + .pAddr = 0, /* set by driver */ + .pQueue = 0, /* set by driver */ + .pOutput = 0, /* set by driver */ }; /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h index d31c495bb..ecb25dde0 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h @@ -38,21 +38,21 @@ #include /*---------------------------------------------------------------------------*/ -// TI-RTOS RF Mode Object +/* TI-RTOS RF Mode Object */ extern RF_Mode rf_prop_mode; /*---------------------------------------------------------------------------*/ -// TX Power Table +/* TX Power Table */ #define RF_PROP_TX_POWER_TABLE_SIZE 16 extern RF_TxPowerTable_Entry rf_prop_tx_power_table[RF_PROP_TX_POWER_TABLE_SIZE+1]; /*---------------------------------------------------------------------------*/ -// RF Core API commands +/* RF Core API commands */ extern rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup; extern rfc_CMD_FS_t rf_cmd_prop_fs; extern rfc_CMD_PROP_TX_ADV_t rf_cmd_prop_tx_adv; extern rfc_CMD_PROP_RX_ADV_t rf_cmd_prop_rx_adv; /*---------------------------------------------------------------------------*/ -// RF Core API Overrides +/* RF Core API Overrides */ extern uint32_t rf_prop_overrides[]; /*---------------------------------------------------------------------------*/ #endif /* PROP_SETTINGS_H_ */ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.c index 86fbd4f47..de3b03f8c 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.c @@ -28,15 +28,18 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /*---------------------------------------------------------------------------*/ -// Parameter summary -// Adv. Address: 010203040506 -// Adv. Data: dummy -// BLE Channel: 17 -// Extended Header: 09 09 010203040506 babe -// Frequency: 2440 MHz -// PDU Payload length:: 30 -// TX Power: 5 dBm (requires define CCFG_FORCE_VDDR_HH = 0 in ccfg.c, see CC13xx/CC26xx Technical Reference Manual) -// Whitening: true +/* + * Parameter summary + * Adv. Address: 010203040506 + * Adv. Data: dummy + * BLE Channel: 17 + * Extended Header: 09 09 010203040506 babe + * Frequency: 2440 MHz + * PDU Payload length:: 30 + * TX Power: 5 dBm (requires define CCFG_FORCE_VDDR_HH = 0 in ccfg + * see CC13xx/CC26xx Technical Reference Manual) + * Whitening: true + */ /*---------------------------------------------------------------------------*/ #include "sys/cc.h" /*---------------------------------------------------------------------------*/ @@ -49,177 +52,179 @@ #include DeviceFamily_constructPath(rf_patches/rf_patch_mce_bt5.h) #include - +/*---------------------------------------------------------------------------*/ #include "ble-settings.h" /*---------------------------------------------------------------------------*/ -// TI-RTOS RF Mode Object +/* TI-RTOS RF Mode Object */ RF_Mode rf_ble_mode = { - .rfMode = RF_MODE_AUTO, - .cpePatchFxn = &rf_patch_cpe_bt5, - .mcePatchFxn = &rf_patch_mce_bt5, - .rfePatchFxn = &rf_patch_rfe_bt5, + .rfMode = RF_MODE_AUTO, + .cpePatchFxn = &rf_patch_cpe_bt5, + .mcePatchFxn = &rf_patch_mce_bt5, + .rfePatchFxn = &rf_patch_rfe_bt5, }; /*---------------------------------------------------------------------------*/ -// TX Power table -// The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: -// RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) -// See the Technical Reference Manual for further details about the "txPower" Command field. -// The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. +/* + * TX Power table + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ RF_TxPowerTable_Entry rf_ble_tx_power_table[RF_BLE_TX_POWER_TABLE_SIZE+1] = { - {-21, RF_TxPowerTable_DEFAULT_PA_ENTRY(7, 3, 0, 3) }, - {-18, RF_TxPowerTable_DEFAULT_PA_ENTRY(9, 3, 0, 3) }, - {-15, RF_TxPowerTable_DEFAULT_PA_ENTRY(8, 2, 0, 6) }, - {-12, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 2, 0, 8) }, - {-10, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 11) }, - {-9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 2, 0, 5) }, - {-6, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 16) }, - {-5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 17) }, - {-3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 1, 0, 20) }, - {0, RF_TxPowerTable_DEFAULT_PA_ENTRY(25, 1, 0, 26) }, - {1, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 1, 0, 28) }, - {2, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 0, 0, 34) }, - {3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 0, 0, 42) }, - {4, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 0, 0, 54) }, - {5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, - RF_TxPowerTable_TERMINATION_ENTRY + { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 3) }, + { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 3) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 2, 0, 6) }, + { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 2, 0, 8) }, + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 11) }, + { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 2, 0, 5) }, + { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 16) }, + { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 17) }, + { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 1, 0, 20) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(25, 1, 0, 26) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 1, 0, 28) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 0, 0, 34) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 0, 0, 42) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 0, 0, 54) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, + RF_TxPowerTable_TERMINATION_ENTRY }; /*---------------------------------------------------------------------------*/ -// Overrides for CMD_BLE5_RADIO_SETUP +/* Overrides for CMD_BLE5_RADIO_SETUP */ uint32_t rf_ble_overrides_common[] CC_ALIGN(4) = { - // override_ble5_setup_override_common.xml - (uint32_t)0x02400403, // Synth: Use 48 MHz crystal, enable extra PLL filtering - (uint32_t)0x001C8473, // Synth: Configure extra PLL filtering - (uint32_t)0x00088433, // Synth: Configure synth hardware - (uint32_t)0x00038793, // Synth: Set minimum RTRIM to 3 - HW32_ARRAY_OVERRIDE(0x4004,1), // Synth: Configure faster calibration - (uint32_t)0x1C0C0618, // Synth: Configure faster calibration - (uint32_t)0xC00401A1, // Synth: Configure faster calibration - (uint32_t)0x00010101, // Synth: Configure faster calibration - (uint32_t)0xC0040141, // Synth: Configure faster calibration - (uint32_t)0x00214AD3, // Synth: Configure faster calibration - (uint32_t)0x02980243, // Synth: Decrease synth programming time-out (0x0298 RAT ticks = 166 us) - (uint32_t)0xFCFC08C3, // DC/DC regulator: In Tx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). - (uint32_t)0x00038883, // Rx: Set LNA bias current offset to adjust +3 (default: 0) - (uint32_t)0x000288A3, // Rx: Set RSSI offset to adjust reported RSSI by -2 dB (default: 0) - (uint32_t)0x01080263, // Bluetooth 5: Compensate for reduced pilot tone length - (uint32_t)0x08E90AA3, // Bluetooth 5: Compensate for reduced pilot tone length - (uint32_t)0x00068BA3, // Bluetooth 5: Compensate for reduced pilot tone length - (uint32_t)0x0E490C83, // Bluetooth 5: Set correct total clock accuracy for received AuxPtr assuming local sleep clock of 50 ppm - (uint32_t)0xFFFFFFFF, + /* override_ble5_setup_override_common.xml */ + (uint32_t)0x02400403, /* Synth: Use 48 MHz crystal, enable extra PLL filtering */ + (uint32_t)0x001C8473, /* Synth: Configure extra PLL filtering */ + (uint32_t)0x00088433, /* Synth: Configure synth hardware */ + (uint32_t)0x00038793, /* Synth: Set minimum RTRIM to 3 */ + HW32_ARRAY_OVERRIDE(0x4004,1), /* Synth: Configure faster calibration */ + (uint32_t)0x1C0C0618, /* Synth: Configure faster calibration */ + (uint32_t)0xC00401A1, /* Synth: Configure faster calibration */ + (uint32_t)0x00010101, /* Synth: Configure faster calibration */ + (uint32_t)0xC0040141, /* Synth: Configure faster calibration */ + (uint32_t)0x00214AD3, /* Synth: Configure faster calibration */ + (uint32_t)0x02980243, /* Synth: Decrease synth programming time-out (0x0298 RAT ticks = 166 us) */ + /* DC/DC regulator: In Tx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). */ + (uint32_t)0xFCFC08C3, /* In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). */ + (uint32_t)0x00038883, /* Rx: Set LNA bias current offset to adjust +3 (default: 0) */ + (uint32_t)0x000288A3, /* Rx: Set RSSI offset to adjust reported RSSI by -2 dB (default: 0) */ + (uint32_t)0x01080263, /* Bluetooth 5: Compensate for reduced pilot tone length */ + (uint32_t)0x08E90AA3, /* Bluetooth 5: Compensate for reduced pilot tone length */ + (uint32_t)0x00068BA3, /* Bluetooth 5: Compensate for reduced pilot tone length */ + /* Bluetooth 5: Set correct total clock accuracy for received AuxPtr */ + (uint32_t)0x0E490C83, /* assuming local sleep clock of 50 ppm */ + (uint32_t)0xFFFFFFFF, }; /*---------------------------------------------------------------------------*/ -// Overrides for CMD_BLE5_RADIO_SETUP +/* Overrides for CMD_BLE5_RADIO_SETUP */ uint32_t rf_ble_overrides_1mbps[] CC_ALIGN(4) = { - // override_ble5_setup_override_1mbps.xml - MCE_RFE_OVERRIDE(1,0,0,1,0,0), // PHY: Use MCE RAM patch (mode 0), RFE RAM patch (mode 0) - HW_REG_OVERRIDE(0x5320,0x0240), // Bluetooth 5: Reduce pilot tone length - (uint32_t)0x013302A3, // Bluetooth 5: Compensate for reduced pilot tone length - (uint32_t)0xFFFFFFFF, + /* override_ble5_setup_override_1mbps.xml */ + MCE_RFE_OVERRIDE(1,0,0,1,0,0), /* PHY: Use MCE RAM patch (mode 0), RFE RAM patch (mode 0) */ + HW_REG_OVERRIDE(0x5320,0x0240), /* Bluetooth 5: Reduce pilot tone length */ + (uint32_t)0x013302A3, /* Bluetooth 5: Compensate for reduced pilot tone length */ + (uint32_t)0xFFFFFFFF, }; /*---------------------------------------------------------------------------*/ -// Overrides for CMD_BLE5_RADIO_SETUP +/* Overrides for CMD_BLE5_RADIO_SETUP */ uint32_t rf_ble_overrides_2mbps[] CC_ALIGN(4) = { - // override_ble5_setup_override_2mbps.xml - MCE_RFE_OVERRIDE(1,0,2,1,0,2), // PHY: Use MCE RAM patch (mode 2), RFE RAM patch (mode 2) - HW_REG_OVERRIDE(0x5320,0x0240), // Bluetooth 5: Reduce pilot tone length - (uint32_t)0x00D102A3, // Bluetooth 5: Compensate for reduced pilot tone length - (uint32_t)0xFFFFFFFF, + /* override_ble5_setup_override_2mbps.xml */ + MCE_RFE_OVERRIDE(1,0,2,1,0,2), /* PHY: Use MCE RAM patch (mode 2), RFE RAM patch (mode 2) */ + HW_REG_OVERRIDE(0x5320,0x0240), /* Bluetooth 5: Reduce pilot tone length */ + (uint32_t)0x00D102A3, /* Bluetooth 5: Compensate for reduced pilot tone length */ + (uint32_t)0xFFFFFFFF, }; /*---------------------------------------------------------------------------*/ -// Overrides for CMD_BLE5_RADIO_SETUP +/* Overrides for CMD_BLE5_RADIO_SETUP */ uint32_t rf_ble_overrides_coded[] CC_ALIGN(4) = { - // override_ble5_setup_override_coded.xml - MCE_RFE_OVERRIDE(1,0,1,1,0,1), // PHY: Use MCE RAM patch (mode 1), RFE RAM patch (mode 1) - HW_REG_OVERRIDE(0x5320,0x0240), // Bluetooth 5: Reduce pilot tone length - (uint32_t)0x078902A3, // Bluetooth 5: Compensate for reduced pilot tone length - (uint32_t)0xFFFFFFFF, + /* override_ble5_setup_override_coded.xml */ + MCE_RFE_OVERRIDE(1,0,1,1,0,1), /* PHY: Use MCE RAM patch (mode 1), RFE RAM patch (mode 1) */ + HW_REG_OVERRIDE(0x5320,0x0240), /* Bluetooth 5: Reduce pilot tone length */ + (uint32_t)0x078902A3, /* Bluetooth 5: Compensate for reduced pilot tone length */ + (uint32_t)0xFFFFFFFF, }; /*---------------------------------------------------------------------------*/ -// CMD_BLE5_RADIO_SETUP -// Bluetooth 5 Radio Setup Command for all PHYs +/* CMD_BLE5_RADIO_SETUP: Bluetooth 5 Radio Setup Command for all PHYs */ rfc_CMD_BLE5_RADIO_SETUP_t rf_cmd_ble5_radio_setup = { - .commandNo = 0x1820, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .defaultPhy.mainMode = 0x0, - .defaultPhy.coding = 0x0, - .loDivider = 0x00, - .config.frontEndMode = 0x0, - .config.biasMode = 0x0, - .config.analogCfgMode = 0x0, - .config.bNoFsPowerUp = 0x0, - .txPower = 0x941E, - .pRegOverrideCommon = rf_ble_overrides_common, - .pRegOverride1Mbps = rf_ble_overrides_1mbps, - .pRegOverride2Mbps = rf_ble_overrides_2mbps, - .pRegOverrideCoded = rf_ble_overrides_coded, + .commandNo = CMD_BLE5_RADIO_SETUP, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .defaultPhy.mainMode = 0x0, + .defaultPhy.coding = 0x0, + .loDivider = 0x00, + .config.frontEndMode = 0x0, + .config.biasMode = 0x0, + .config.analogCfgMode = 0x0, + .config.bNoFsPowerUp = 0x0, + .txPower = 0x941E, + .pRegOverrideCommon = rf_ble_overrides_common, + .pRegOverride1Mbps = rf_ble_overrides_1mbps, + .pRegOverride2Mbps = rf_ble_overrides_2mbps, + .pRegOverrideCoded = rf_ble_overrides_coded, }; /*---------------------------------------------------------------------------*/ -// Structure for CMD_BLE5_ADV_AUX.pParams +/* Structure for CMD_BLE5_ADV_AUX.pParams */ rfc_ble5AdvAuxPar_t rf_ble5_adv_aux_par = { - .pRxQ = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx - .rxConfig.bAutoFlushIgnored = 0x0, - .rxConfig.bAutoFlushCrcErr = 0x0, - .rxConfig.bAutoFlushEmpty = 0x0, - .rxConfig.bIncludeLenByte = 0x0, - .rxConfig.bIncludeCrc = 0x0, - .rxConfig.bAppendRssi = 0x0, - .rxConfig.bAppendStatus = 0x0, - .rxConfig.bAppendTimestamp = 0x0, - .advConfig.advFilterPolicy = 0x0, - .advConfig.deviceAddrType = 0x0, - .advConfig.targetAddrType = 0x0, - .advConfig.bStrictLenFilter = 0x0, - .advConfig.bDirected = 0x0, - .advConfig.privIgnMode = 0x0, - .advConfig.rpaMode = 0x0, - .__dummy0 = 0x00, - .auxPtrTargetType = 0x00, - .auxPtrTargetTime = 0x00000000, - .pAdvPkt = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .pRspPkt = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .pDeviceAddress = 0, // INSERT APPLICABLE POINTER: (uint16_t*)&xxx - .pWhiteList = 0, // INSERT APPLICABLE POINTER: (uint32_t*)&xxx + .pRxQ = 0, + .rxConfig.bAutoFlushIgnored = 0x0, + .rxConfig.bAutoFlushCrcErr = 0x0, + .rxConfig.bAutoFlushEmpty = 0x0, + .rxConfig.bIncludeLenByte = 0x0, + .rxConfig.bIncludeCrc = 0x0, + .rxConfig.bAppendRssi = 0x0, + .rxConfig.bAppendStatus = 0x0, + .rxConfig.bAppendTimestamp = 0x0, + .advConfig.advFilterPolicy = 0x0, + .advConfig.deviceAddrType = 0x0, + .advConfig.targetAddrType = 0x0, + .advConfig.bStrictLenFilter = 0x0, + .advConfig.bDirected = 0x0, + .advConfig.privIgnMode = 0x0, + .advConfig.rpaMode = 0x0, + .__dummy0 = 0x00, + .auxPtrTargetType = 0x00, + .auxPtrTargetTime = 0x00000000, + .pAdvPkt = 0, + .pRspPkt = 0, + .pDeviceAddress = 0, + .pWhiteList = 0, }; /*---------------------------------------------------------------------------*/ -// CMD_BLE5_ADV_AUX -// Bluetooth 5 Secondary Channel Advertiser Command +/* CMD_BLE5_ADV_AUX: Bluetooth 5 Secondary Channel Advertiser Command */ rfc_CMD_BLE5_ADV_AUX_t rf_cmd_ble5_adv_aux = { - .commandNo = 0x1824, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .channel = 0x8C, - .whitening.init = 0x51, - .whitening.bOverride = 0x1, - .phyMode.mainMode = 0x0, - .phyMode.coding = 0x0, - .rangeDelay = 0x00, - .txPower = 0x0000, - .pParams = &rf_ble5_adv_aux_par, - .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .tx20Power = 0x00000000, + .commandNo = CMD_BLE5_ADV_AUX, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .channel = 0x8C, + .whitening.init = 0x51, + .whitening.bOverride = 0x1, + .phyMode.mainMode = 0x0, + .phyMode.coding = 0x0, + .rangeDelay = 0x00, + .txPower = 0x0000, + .pParams = &rf_ble5_adv_aux_par, + .pOutput = 0, + .tx20Power = 0x00000000, }; /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.h index 423a4bff0..695d27e24 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.h @@ -38,21 +38,21 @@ #include /*---------------------------------------------------------------------------*/ -// TX Power table size definition +/* TX Power table size definition */ #define RF_BLE_TX_POWER_TABLE_SIZE 15 -// TX Power Table Object +/* TX Power Table Object */ extern RF_TxPowerTable_Entry rf_ble_tx_power_table[RF_BLE_TX_POWER_TABLE_SIZE+1]; /*---------------------------------------------------------------------------*/ -// TI-RTOS RF Mode Object +/* TI-RTOS RF Mode Object */ extern RF_Mode rf_ble_mode; /*---------------------------------------------------------------------------*/ -// RF Core API commands +/* RF Core API commands */ extern rfc_CMD_BLE5_RADIO_SETUP_t rf_cmd_ble5_radio_setup; extern rfc_ble5AdvAuxPar_t rf_ble5_adv_aux_par; extern rfc_CMD_BLE5_ADV_AUX_t rf_cmd_ble5_adv_aux; /*---------------------------------------------------------------------------*/ -// RF Core API Overrides +/* RF Core API Overrides */ extern uint32_t rf_ble_overrides_common[]; extern uint32_t rf_ble_overrides_1mbps[]; extern uint32_t rf_ble_overrides_2mbps[]; diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c index 86892b571..4eabcf367 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c @@ -28,18 +28,22 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /*---------------------------------------------------------------------------*/ -// Parameter summary -// IEEE Channel: 11 -// Frequency: 2405 MHz -// SFD: 0 -// Packet Data: 255 -// Preamble (32 bit): 01010101... -// For Default PA: -// TX Power: 5 dBm (requires define CCFG_FORCE_VDDR_HH = 0 in ccfg.c, see CC13xx/CC26xx Technical Reference Manual) -// Enable high output power PA: false -// For High PA: -// TX Power: 20 dBm (requires define CCFG_FORCE_VDDR_HH = 0 in ccfg.c, see CC13xx/CC26xx Technical Reference Manual) -// Enable high output power PA: true +/* + * Parameter summary + * IEEE Channel: 11 + * Frequency: 2405 MHz + * SFD: 0 + * Packet Data: 255 + * Preamble (32 bit): 01010101... + * For Default PA: + * Enable high output power PA: false + * TX Power: 5 dBm (requires define CCFG_FORCE_VDDR_HH = 0 in ccfg.c, + * see CC13xx/CC26xx Technical Reference Manual) + * For High PA: + * Enable high output power PA: true + * TX Power: 20 dBm (requires define CCFG_FORCE_VDDR_HH = 0 in ccfg.c, + * see CC13xx/CC26xx Technical Reference Manual) + */ /*---------------------------------------------------------------------------*/ #include "sys/cc.h" /*---------------------------------------------------------------------------*/ @@ -54,267 +58,268 @@ /*---------------------------------------------------------------------------*/ #include "ieee-settings.h" /*---------------------------------------------------------------------------*/ -// TI-RTOS RF Mode Object +/* TI-RTOS RF Mode Object */ RF_Mode rf_ieee_mode = { - .rfMode = RF_MODE_AUTO, - .cpePatchFxn = &rf_patch_cpe_ieee_802_15_4, - .mcePatchFxn = &rf_patch_mce_ieee_802_15_4, - .rfePatchFxn = 0, + .rfMode = RF_MODE_AUTO, + .cpePatchFxn = &rf_patch_cpe_ieee_802_15_4, + .mcePatchFxn = &rf_patch_mce_ieee_802_15_4, + .rfePatchFxn = 0, }; /*---------------------------------------------------------------------------*/ -// TX Power table -// The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: -// RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) -// See the Technical Reference Manual for further details about the "txPower" Command field. -// The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. +/* + * TX Power table + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ RF_TxPowerTable_Entry rf_ieee_tx_power_table_default_pa[RF_IEEE_TX_POWER_TABLE_DEFAULT_PA_SIZE+1] = { - { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 3) }, - { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 3) }, - { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 2, 0, 6) }, - { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 2, 0, 8) }, - { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 11) }, - { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 2, 0, 5) }, - { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 16) }, - { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 17) }, - { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 1, 0, 20) }, - { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(25, 1, 0, 26) }, - { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 1, 0, 28) }, - { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 0, 0, 34) }, - { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 0, 0, 42) }, - { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 0, 0, 54) }, - { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, - RF_TxPowerTable_TERMINATION_ENTRY + { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 3) }, + { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 3) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 2, 0, 6) }, + { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 2, 0, 8) }, + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 11) }, + { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 2, 0, 5) }, + { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 16) }, + { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 17) }, + { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 1, 0, 20) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(25, 1, 0, 26) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 1, 0, 28) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 0, 0, 34) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 0, 0, 42) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 0, 0, 54) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, + RF_TxPowerTable_TERMINATION_ENTRY }; /*---------------------------------------------------------------------------*/ -// TX Power table -// The RF_TxPowerTable_HIGH_PA_ENTRY macro is defined in RF.h and requires the following arguments: -// RF_TxPowerTable_HIGH_PA_ENTRY(bias, ibboost, boost, coefficient, ldoTrim) -// See the Technical Reference Manual for further details about the "txPower" Command field. -// The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. +/* + * TX Power table + * The RF_TxPowerTable_HIGH_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_HIGH_PA_ENTRY(bias, ibboost, boost, coefficient, ldoTrim) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ RF_TxPowerTable_Entry rf_ieee_tx_power_table_high_pa[RF_IEEE_TX_POWER_TABLE_HIGH_PA_SIZE+1] = { - { 0, RF_TxPowerTable_HIGH_PA_ENTRY(29, 0, 1, 17, 1) }, - { 3, RF_TxPowerTable_HIGH_PA_ENTRY(39, 0, 1, 20, 1) }, - { 6, RF_TxPowerTable_HIGH_PA_ENTRY(46, 0, 1, 26, 7) }, - { 9, RF_TxPowerTable_HIGH_PA_ENTRY(40, 0, 1, 39, 41) }, - { 10, RF_TxPowerTable_HIGH_PA_ENTRY(23, 2, 1, 65, 5) }, - { 11, RF_TxPowerTable_HIGH_PA_ENTRY(24, 2, 1, 29, 7) }, - { 12, RF_TxPowerTable_HIGH_PA_ENTRY(19, 2, 1, 16, 25) }, - { 13, RF_TxPowerTable_HIGH_PA_ENTRY(27, 2, 1, 19, 13) }, - { 14, RF_TxPowerTable_HIGH_PA_ENTRY(24, 2, 1, 19, 27) }, - { 15, RF_TxPowerTable_HIGH_PA_ENTRY(23, 2, 1, 20, 39) }, - { 16, RF_TxPowerTable_HIGH_PA_ENTRY(34, 2, 1, 26, 23) }, - { 17, RF_TxPowerTable_HIGH_PA_ENTRY(38, 2, 1, 33, 25) }, - { 18, RF_TxPowerTable_HIGH_PA_ENTRY(30, 2, 1, 37, 53) }, - { 19, RF_TxPowerTable_HIGH_PA_ENTRY(36, 2, 1, 57, 59) }, - { 20, RF_TxPowerTable_HIGH_PA_ENTRY(56, 2, 1, 45, 63) }, - RF_TxPowerTable_TERMINATION_ENTRY + { 0, RF_TxPowerTable_HIGH_PA_ENTRY(29, 0, 1, 17, 1) }, + { 3, RF_TxPowerTable_HIGH_PA_ENTRY(39, 0, 1, 20, 1) }, + { 6, RF_TxPowerTable_HIGH_PA_ENTRY(46, 0, 1, 26, 7) }, + { 9, RF_TxPowerTable_HIGH_PA_ENTRY(40, 0, 1, 39, 41) }, + { 10, RF_TxPowerTable_HIGH_PA_ENTRY(23, 2, 1, 65, 5) }, + { 11, RF_TxPowerTable_HIGH_PA_ENTRY(24, 2, 1, 29, 7) }, + { 12, RF_TxPowerTable_HIGH_PA_ENTRY(19, 2, 1, 16, 25) }, + { 13, RF_TxPowerTable_HIGH_PA_ENTRY(27, 2, 1, 19, 13) }, + { 14, RF_TxPowerTable_HIGH_PA_ENTRY(24, 2, 1, 19, 27) }, + { 15, RF_TxPowerTable_HIGH_PA_ENTRY(23, 2, 1, 20, 39) }, + { 16, RF_TxPowerTable_HIGH_PA_ENTRY(34, 2, 1, 26, 23) }, + { 17, RF_TxPowerTable_HIGH_PA_ENTRY(38, 2, 1, 33, 25) }, + { 18, RF_TxPowerTable_HIGH_PA_ENTRY(30, 2, 1, 37, 53) }, + { 19, RF_TxPowerTable_HIGH_PA_ENTRY(36, 2, 1, 57, 59) }, + { 20, RF_TxPowerTable_HIGH_PA_ENTRY(56, 2, 1, 45, 63) }, + RF_TxPowerTable_TERMINATION_ENTRY }; /*---------------------------------------------------------------------------*/ -// Overrides for CMD_RADIO_SETUP +/* Overrides for CMD_RADIO_SETUP with default PA */ uint32_t rf_ieee_overrides_default_pa[] CC_ALIGN(4) = { - // override_ieee_802_15_4.xml - MCE_RFE_OVERRIDE(1,0,0,0,1,0), // PHY: Use MCE RAM patch, RFE ROM bank 1 - (uint32_t)0x02400403, // Synth: Use 48 MHz crystal, enable extra PLL filtering - (uint32_t)0x001C8473, // Synth: Configure extra PLL filtering - (uint32_t)0x00088433, // Synth: Configure synth hardware - (uint32_t)0x00038793, // Synth: Set minimum RTRIM to 3 - HW32_ARRAY_OVERRIDE(0x4004,1), // Synth: Configure faster calibration - (uint32_t)0x1C0C0618, // Synth: Configure faster calibration - (uint32_t)0xC00401A1, // Synth: Configure faster calibration - (uint32_t)0x00010101, // Synth: Configure faster calibration - (uint32_t)0xC0040141, // Synth: Configure faster calibration - (uint32_t)0x00214AD3, // Synth: Configure faster calibration - (uint32_t)0x02980243, // Synth: Decrease synth programming time-out (0x0298 RAT ticks = 166 us) - (uint32_t)0xFCFC08C3, // DC/DC regulator: In Tx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). - (uint32_t)0x000F8883, // Rx: Set LNA bias current offset to +15 to saturate trim to max (default: 0) - (uint32_t)0xFFFFFFFF, + /* override_ieee_802_15_4.xml */ + MCE_RFE_OVERRIDE(1,0,0,0,1,0), /* PHY: Use MCE RAM patch, RFE ROM bank 1 */ + (uint32_t)0x02400403, /* Synth: Use 48 MHz crystal, enable extra PLL filtering */ + (uint32_t)0x001C8473, /* Synth: Configure extra PLL filtering */ + (uint32_t)0x00088433, /* Synth: Configure synth hardware */ + (uint32_t)0x00038793, /* Synth: Set minimum RTRIM to 3 */ + HW32_ARRAY_OVERRIDE(0x4004,1), /* Synth: Configure faster calibration */ + (uint32_t)0x1C0C0618, /* Synth: Configure faster calibration */ + (uint32_t)0xC00401A1, /* Synth: Configure faster calibration */ + (uint32_t)0x00010101, /* Synth: Configure faster calibration */ + (uint32_t)0xC0040141, /* Synth: Configure faster calibration */ + (uint32_t)0x00214AD3, /* Synth: Configure faster calibration */ + (uint32_t)0x02980243, /* Synth: Decrease synth programming time-out (0x0298 RAT ticks = 166 us) */ + /* DC/DC regulator: In Tx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). */ + (uint32_t)0xFCFC08C3, /* In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). */ + (uint32_t)0x000F8883, /* Rx: Set LNA bias current offset to +15 to saturate trim to max (default: 0) */ + (uint32_t)0xFFFFFFFF, }; /*---------------------------------------------------------------------------*/ -// Overrides for CMD_RADIO_SETUP +/* Overrides for CMD_RADIO_SETUP with high PA */ uint32_t rf_ieee_overrides_high_pa[] CC_ALIGN(4) = { - // override_ieee_802_15_4.xml - MCE_RFE_OVERRIDE(1,0,0,0,1,0), // PHY: Use MCE RAM patch, RFE ROM bank 1 - (uint32_t)0x02400403, // Synth: Use 48 MHz crystal, enable extra PLL filtering - (uint32_t)0x001C8473, // Synth: Configure extra PLL filtering - (uint32_t)0x00088433, // Synth: Configure synth hardware - (uint32_t)0x00038793, // Synth: Set minimum RTRIM to 3 - HW32_ARRAY_OVERRIDE(0x4004,1), // Synth: Configure faster calibration - (uint32_t)0x1C0C0618, // Synth: Configure faster calibration - (uint32_t)0xC00401A1, // Synth: Configure faster calibration - (uint32_t)0x00010101, // Synth: Configure faster calibration - (uint32_t)0xC0040141, // Synth: Configure faster calibration - (uint32_t)0x00214AD3, // Synth: Configure faster calibration - (uint32_t)0x02980243, // Synth: Decrease synth programming time-out (0x0298 RAT ticks = 166 us) - (uint32_t)0xFCFC08C3, // DC/DC regulator: In Tx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). - (uint32_t)0x000F8883, // Rx: Set LNA bias current offset to +15 to saturate trim to max (default: 0) - // override_frontend_xd.xml - // TX power override - (uint32_t)0xFD6EE02B, // txHighPA=0x3F5BB8 - (uint32_t)0xFFFFFFFF, + /* override_ieee_802_15_4.xml */ + MCE_RFE_OVERRIDE(1,0,0,0,1,0), /* PHY: Use MCE RAM patch, RFE ROM bank 1 */ + (uint32_t)0x02400403, /* Synth: Use 48 MHz crystal, enable extra PLL filtering */ + (uint32_t)0x001C8473, /* Synth: Configure extra PLL filtering */ + (uint32_t)0x00088433, /* Synth: Configure synth hardware */ + (uint32_t)0x00038793, /* Synth: Set minimum RTRIM to 3 */ + HW32_ARRAY_OVERRIDE(0x4004,1), /* Synth: Configure faster calibration */ + (uint32_t)0x1C0C0618, /* Synth: Configure faster calibration */ + (uint32_t)0xC00401A1, /* Synth: Configure faster calibration */ + (uint32_t)0x00010101, /* Synth: Configure faster calibration */ + (uint32_t)0xC0040141, /* Synth: Configure faster calibration */ + (uint32_t)0x00214AD3, /* Synth: Configure faster calibration */ + (uint32_t)0x02980243, /* Synth: Decrease synth programming time-out (0x0298 RAT ticks = 166 us) */ + /* DC/DC regulator: In Tx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). */ + (uint32_t)0xFCFC08C3, /* In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). */ + (uint32_t)0x000F8883, /* Rx: Set LNA bias current offset to +15 to saturate trim to max (default: 0) */ + /* override_frontend_xd.xml */ + /* TX power override */ + (uint32_t)0xFD6EE02B, /* txHighPA=0x3F5BB8 */ + (uint32_t)0xFFFFFFFF, }; /*---------------------------------------------------------------------------*/ -// CMD_RADIO_SETUP -// Radio Setup Command for Pre-Defined Schemes +/* CMD_RADIO_SETUP: Radio Setup Command for Pre-Defined Schemes */ rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup = { - .commandNo = CMD_RADIO_SETUP, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .mode = 0x01, - .loDivider = 0x00, - .config.frontEndMode = 0x0, - .config.biasMode = 0x1, - .config.analogCfgMode = 0x0, - .config.bNoFsPowerUp = 0x0, - .txPower = 0x941E, /* 5 dBm default */ - .pRegOverride = rf_ieee_overrides_default_pa, + .commandNo = CMD_RADIO_SETUP, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .mode = 0x01, + .loDivider = 0x00, + .config.frontEndMode = 0x0, + .config.biasMode = 0x1, + .config.analogCfgMode = 0x0, + .config.bNoFsPowerUp = 0x0, + .txPower = 0x941E, /* 5 dBm default */ + .pRegOverride = rf_ieee_overrides_default_pa, }; /*---------------------------------------------------------------------------*/ -// CMD_FS -// Frequency Synthesizer Programming Command +/* CMD_FS: Frequency Synthesizer Programming Command */ rfc_CMD_FS_t rf_cmd_ieee_fs = { - .commandNo = CMD_FS, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .frequency = 0x0965, /* set by driver */ - .fractFreq = 0x0000, /* set by driver */ - .synthConf.bTxMode = 0x1, - .synthConf.refFreq = 0x0, - .__dummy0 = 0x00, - .__dummy1 = 0x00, - .__dummy2 = 0x00, - .__dummy3 = 0x0000, + .commandNo = CMD_FS, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .frequency = 0x0965, /* set by driver */ + .fractFreq = 0x0000, /* set by driver */ + .synthConf.bTxMode = 0x1, + .synthConf.refFreq = 0x0, + .__dummy0 = 0x00, + .__dummy1 = 0x00, + .__dummy2 = 0x00, + .__dummy3 = 0x0000, }; /*---------------------------------------------------------------------------*/ -// CMD_IEEE_TX -// IEEE 802.15.4 Transmit Command +/* CMD_IEEE_TX: IEEE 802.15.4 Transmit Command */ rfc_CMD_IEEE_TX_t rf_cmd_ieee_tx = { - .commandNo = CMD_IEEE_TX, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .txOpt.bIncludePhyHdr = 0x0, - .txOpt.bIncludeCrc = 0x0, - .txOpt.payloadLenMsb = 0x0, - .payloadLen = 0x0, /* set by driver */ - .pPayload = 0, /* set by driver */ - .timeStamp = 0x00000000, + .commandNo = CMD_IEEE_TX, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .txOpt.bIncludePhyHdr = 0x0, + .txOpt.bIncludeCrc = 0x0, + .txOpt.payloadLenMsb = 0x0, + .payloadLen = 0x0, /* set by driver */ + .pPayload = 0, /* set by driver */ + .timeStamp = 0x00000000, }; /*---------------------------------------------------------------------------*/ -// CMD_IEEE_RX -// IEEE 802.15.4 Receive Command +/* CMD_IEEE_RX: IEEE 802.15.4 Receive Command */ rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx = { - .commandNo = CMD_IEEE_RX, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .channel = 0x00, /* set by driver */ - .rxConfig.bAutoFlushCrc = 0x1, - .rxConfig.bAutoFlushIgn = 0x0, - .rxConfig.bIncludePhyHdr = 0x0, - .rxConfig.bIncludeCrc = 0x1, - .rxConfig.bAppendRssi = 0x1, - .rxConfig.bAppendCorrCrc = 0x1, - .rxConfig.bAppendSrcInd = 0x0, - .rxConfig.bAppendTimestamp = 0x1, - .pRxQ = 0, /* set by driver */ - .pOutput = 0, /* set by driver */ - .frameFiltOpt.frameFiltEn = 0x0, /* set by driver */ - .frameFiltOpt.frameFiltStop = 0x1, - .frameFiltOpt.autoAckEn = 0x0, /* set by driver */ - .frameFiltOpt.slottedAckEn = 0x0, - .frameFiltOpt.autoPendEn = 0x0, - .frameFiltOpt.defaultPend = 0x0, - .frameFiltOpt.bPendDataReqOnly = 0x0, - .frameFiltOpt.bPanCoord = 0x0, - .frameFiltOpt.maxFrameVersion = 0x2, - .frameFiltOpt.fcfReservedMask = 0x0, - .frameFiltOpt.modifyFtFilter = 0x0, - .frameFiltOpt.bStrictLenFilter = 0x0, - .frameTypes.bAcceptFt0Beacon = 0x1, - .frameTypes.bAcceptFt1Data = 0x1, - .frameTypes.bAcceptFt2Ack = 0x1, - .frameTypes.bAcceptFt3MacCmd = 0x1, - .frameTypes.bAcceptFt4Reserved = 0x1, - .frameTypes.bAcceptFt5Reserved = 0x1, - .frameTypes.bAcceptFt6Reserved = 0x1, - .frameTypes.bAcceptFt7Reserved = 0x1, - .ccaOpt.ccaEnEnergy = 0x1, - .ccaOpt.ccaEnCorr = 0x1, - .ccaOpt.ccaEnSync = 0x1, - .ccaOpt.ccaCorrOp = 0x1, - .ccaOpt.ccaSyncOp = 0x0, - .ccaOpt.ccaCorrThr = 0x3, - .ccaRssiThr = 0x0, /* set by driver */ - .__dummy0 = 0x00, - .numExtEntries = 0x00, - .numShortEntries = 0x00, - .pExtEntryList = 0, - .pShortEntryList = 0, - .localExtAddr = 0x0, /* set by driver */ - .localShortAddr = 0x0, /* set by driver */ - .localPanID = 0x0000, - .__dummy1 = 0x000000, - .endTrigger.triggerType = TRIG_NEVER, - .endTrigger.bEnaCmd = 0x0, - .endTrigger.triggerNo = 0x0, - .endTrigger.pastTrig = 0x0, - .endTime = 0x00000000, + .commandNo = CMD_IEEE_RX, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .channel = 0x00, /* set by driver */ + .rxConfig.bAutoFlushCrc = 0x1, + .rxConfig.bAutoFlushIgn = 0x0, + .rxConfig.bIncludePhyHdr = 0x0, + .rxConfig.bIncludeCrc = 0x1, + .rxConfig.bAppendRssi = 0x1, + .rxConfig.bAppendCorrCrc = 0x1, + .rxConfig.bAppendSrcInd = 0x0, + .rxConfig.bAppendTimestamp = 0x1, + .pRxQ = 0, /* set by driver */ + .pOutput = 0, /* set by driver */ + .frameFiltOpt.frameFiltEn = 0x0, /* set by driver */ + .frameFiltOpt.frameFiltStop = 0x1, + .frameFiltOpt.autoAckEn = 0x0, /* set by driver */ + .frameFiltOpt.slottedAckEn = 0x0, + .frameFiltOpt.autoPendEn = 0x0, + .frameFiltOpt.defaultPend = 0x0, + .frameFiltOpt.bPendDataReqOnly = 0x0, + .frameFiltOpt.bPanCoord = 0x0, + .frameFiltOpt.maxFrameVersion = 0x2, + .frameFiltOpt.fcfReservedMask = 0x0, + .frameFiltOpt.modifyFtFilter = 0x0, + .frameFiltOpt.bStrictLenFilter = 0x0, + .frameTypes.bAcceptFt0Beacon = 0x1, + .frameTypes.bAcceptFt1Data = 0x1, + .frameTypes.bAcceptFt2Ack = 0x1, + .frameTypes.bAcceptFt3MacCmd = 0x1, + .frameTypes.bAcceptFt4Reserved = 0x1, + .frameTypes.bAcceptFt5Reserved = 0x1, + .frameTypes.bAcceptFt6Reserved = 0x1, + .frameTypes.bAcceptFt7Reserved = 0x1, + .ccaOpt.ccaEnEnergy = 0x1, + .ccaOpt.ccaEnCorr = 0x1, + .ccaOpt.ccaEnSync = 0x1, + .ccaOpt.ccaCorrOp = 0x1, + .ccaOpt.ccaSyncOp = 0x0, + .ccaOpt.ccaCorrThr = 0x3, + .ccaRssiThr = 0x0, /* set by driver */ + .__dummy0 = 0x00, + .numExtEntries = 0x00, + .numShortEntries = 0x00, + .pExtEntryList = 0, + .pShortEntryList = 0, + .localExtAddr = 0x0, /* set by driver */ + .localShortAddr = 0x0, /* set by driver */ + .localPanID = 0x0000, + .__dummy1 = 0x000000, + .endTrigger.triggerType = TRIG_NEVER, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, }; /*---------------------------------------------------------------------------*/ -// CMD_IEEE_RX_ACK -// IEEE 802.15.4 Receive ACK Command +/* CMD_IEEE_RX_ACK: IEEE 802.15.4 Receive ACK Command */ rfc_CMD_IEEE_RX_ACK_t rf_cmd_ieee_rx_ack = { - .commandNo = CMD_IEEE_RX_ACK, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .seqNo = 0x0, - .endTrigger.triggerType = TRIG_NEVER, - .endTrigger.bEnaCmd = 0x0, - .endTrigger.triggerNo = 0x0, - .endTrigger.pastTrig = 0x0, - .endTime = 0x00000000, + .commandNo = CMD_IEEE_RX_ACK, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .seqNo = 0x0, + .endTrigger.triggerType = TRIG_NEVER, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, }; /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h index 5f6a6eb2e..b187c833f 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h @@ -39,24 +39,24 @@ #include /*---------------------------------------------------------------------------*/ -// TI-RTOS RF Mode Object +/* TI-RTOS RF Mode Object */ extern RF_Mode rf_ieee_mode; /*---------------------------------------------------------------------------*/ -// TX Power Table +/* TX Power Table */ #define RF_IEEE_TX_POWER_TABLE_DEFAULT_PA_SIZE 15 #define RF_IEEE_TX_POWER_TABLE_HIGH_PA_SIZE 15 extern RF_TxPowerTable_Entry rf_ieee_tx_power_table_default_pa[RF_IEEE_TX_POWER_TABLE_DEFAULT_PA_SIZE+1]; extern RF_TxPowerTable_Entry rf_ieee_tx_power_table_high_pa[RF_IEEE_TX_POWER_TABLE_HIGH_PA_SIZE+1]; /*---------------------------------------------------------------------------*/ -// RF Core API commands +/* RF Core API commands */ extern rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup; extern rfc_CMD_FS_t rf_cmd_ieee_fs; extern rfc_CMD_IEEE_TX_t rf_cmd_ieee_tx; extern rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx; extern rfc_CMD_IEEE_RX_ACK_t rf_cmd_ieee_rx_ack; /*---------------------------------------------------------------------------*/ -// RF Core API Overrides +/* RF Core API Overrides */ extern uint32_t rf_ieee_overrides_default_pa[]; extern uint32_t rf_ieee_overrides_high_pa[]; /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c index 7cc4d0046..ffea53182 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c @@ -28,30 +28,34 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /*---------------------------------------------------------------------------*/ -// Parameter summary -// Address: 0 -// Address0: 0xAA -// Address1: 0xBB -// Frequency: 915.00000 MHz -// Data Format: Serial mode disable -// Deviation: 25.000 kHz -// pktLen: 30 -// 802.15.4g Mode: 0 -// Select bit order to transmit PSDU octets:: 1 -// Packet Length Config: Variable -// Max Packet Length: 255 -// Packet Length: 20 -// Packet Data: 255 -// RX Filter BW: 98.0 kHz -// Symbol Rate: 50.00000 kBaud -// Sync Word Length: 24 Bits -// For Default PA: -// TX Power: 13.5 dBm (requires define CCFG_FORCE_VDDR_HH = 1 in ccfg.c, see CC13xx/CC26xx Technical Reference Manual) -// Enable high output power PA: false -// For High PA: -// TX Power: 20 dBm (requires define CCFG_FORCE_VDDR_HH = 0 in ccfg.c, see CC13xx/CC26xx Technical Reference Manual) -// Enable high output power PA: true -// Whitening: Dynamically IEEE 802.15.4g compatible whitener and 16/32-bit CRC +/* + * Parameter summary + * Address: 0 + * Address0: 0xAA + * Address1: 0xBB + * Frequency: 915.00000 MHz + * Data Format: Serial mode disable + * Deviation: 25.000 kHz + * pktLen: 30 + * 802.15.4g Mode: 0 + * Select bit order to transmit PSDU octets:: 1 + * Packet Length Config: Variable + * Max Packet Length: 255 + * Packet Length: 20 + * Packet Data: 255 + * RX Filter BW: 98.0 kHz + * Symbol Rate: 50.00000 kBaud + * Sync Word Length: 24 Bits + * For Default PA: + * Enable high output power PA: false + * TX Power: 13.5 dBm (requires define CCFG_FORCE_VDDR_HH = 1 in ccfg.c, + * see CC13xx/CC26xx Technical Reference Manual) + * For High PA: + * Enable high output power PA: true + * TX Power: 20 dBm (requires define CCFG_FORCE_VDDR_HH = 0 in ccfg.c, + * see CC13xx/CC26xx Technical Reference Manual) + * Whitening: Dynamically IEEE 802.15.4g compatible whitener and 16/32-bit CRC + */ /*---------------------------------------------------------------------------*/ #include "sys/cc.h" /*---------------------------------------------------------------------------*/ @@ -67,278 +71,289 @@ /*---------------------------------------------------------------------------*/ #include "prop-settings.h" /*---------------------------------------------------------------------------*/ -// TI-RTOS RF Mode Object +/* TI-RTOS RF Mode Object */ RF_Mode rf_prop_mode = { - .rfMode = RF_MODE_AUTO, - .cpePatchFxn = &rf_patch_cpe_prop, - .mcePatchFxn = &rf_patch_mce_genfsk, - .rfePatchFxn = &rf_patch_rfe_genfsk, + .rfMode = RF_MODE_AUTO, + .cpePatchFxn = &rf_patch_cpe_prop, + .mcePatchFxn = &rf_patch_mce_genfsk, + .rfePatchFxn = &rf_patch_rfe_genfsk, }; /*---------------------------------------------------------------------------*/ -// TX Power table -// The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: -// RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) -// See the Technical Reference Manual for further details about the "txPower" Command field. -// The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. +/* + * TX Power table + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ RF_TxPowerTable_Entry rf_prop_tx_power_table_default_pa[RF_PROP_TX_POWER_TABLE_DEFAULT_PA_SIZE+1] = { - { -20, RF_TxPowerTable_DEFAULT_PA_ENTRY( 0, 3, 0, 2) }, - { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY( 1, 3, 0, 3) }, - { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY( 2, 3, 0, 3) }, - { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 3, 0, 6) }, - { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 8) }, - { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 3, 0, 9) }, - { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 9) }, - { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 11) }, - { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 3, 0, 12) }, - { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 3, 0, 14) }, - { 6, RF_TxPowerTable_DEFAULT_PA_ENTRY( 6, 2, 0, 14) }, - { 7, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 1, 0, 16) }, - { 8, RF_TxPowerTable_DEFAULT_PA_ENTRY( 6, 1, 0, 19) }, - { 9, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 1, 0, 25) }, - { 10, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 40) }, - { 11, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 0, 0, 71) }, - { 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 0, 64) }, - // This setting requires CCFG_FORCE_VDDR_HH = 1. - // The original PA value (13.5 dBm) have been rounded to an integer value. - { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 0) }, - RF_TxPowerTable_TERMINATION_ENTRY + { -20, RF_TxPowerTable_DEFAULT_PA_ENTRY( 0, 3, 0, 2) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY( 1, 3, 0, 3) }, + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY( 2, 3, 0, 3) }, + { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 3, 0, 6) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 8) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 3, 0, 9) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 9) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 11) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 3, 0, 12) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 3, 0, 14) }, + { 6, RF_TxPowerTable_DEFAULT_PA_ENTRY( 6, 2, 0, 14) }, + { 7, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 1, 0, 16) }, + { 8, RF_TxPowerTable_DEFAULT_PA_ENTRY( 6, 1, 0, 19) }, + { 9, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 1, 0, 25) }, + { 10, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 40) }, + { 11, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 0, 0, 71) }, + { 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 0, 64) }, + /* The original PA value (13.5 dBm) have been rounded to an integer value. */ + /* This setting requires CCFG_FORCE_VDDR_HH = 1. */ + { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 0) }, + RF_TxPowerTable_TERMINATION_ENTRY }; /*---------------------------------------------------------------------------*/ -// TX Power table -// The RF_TxPowerTable_HIGH_PA_ENTRY macro is defined in RF.h and requires the following arguments: -// RF_TxPowerTable_HIGH_PA_ENTRY(bias, ibboost, boost, coefficient, ldoTrim) -// See the Technical Reference Manual for further details about the "txPower" Command field. -// The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. +/* + * TX Power table + * The RF_TxPowerTable_HIGH_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_HIGH_PA_ENTRY(bias, ibboost, boost, coefficient, ldoTrim) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ RF_TxPowerTable_Entry rf_prop_tx_power_table_high_pa[RF_PROP_TX_POWER_TABLE_HIGH_PA_SIZE+1] = { - { 14, RF_TxPowerTable_HIGH_PA_ENTRY( 7, 0, 0, 23, 4) }, - { 15, RF_TxPowerTable_HIGH_PA_ENTRY(10, 0, 0, 26, 4) }, - { 16, RF_TxPowerTable_HIGH_PA_ENTRY(14, 0, 0, 33, 4) }, - { 17, RF_TxPowerTable_HIGH_PA_ENTRY(18, 0, 0, 40, 6) }, - { 18, RF_TxPowerTable_HIGH_PA_ENTRY(24, 0, 0, 51, 8) }, - { 19, RF_TxPowerTable_HIGH_PA_ENTRY(32, 0, 0, 73, 12) }, - { 20, RF_TxPowerTable_HIGH_PA_ENTRY(27, 0, 0, 85, 32) }, - RF_TxPowerTable_TERMINATION_ENTRY + { 14, RF_TxPowerTable_HIGH_PA_ENTRY( 7, 0, 0, 23, 4) }, + { 15, RF_TxPowerTable_HIGH_PA_ENTRY(10, 0, 0, 26, 4) }, + { 16, RF_TxPowerTable_HIGH_PA_ENTRY(14, 0, 0, 33, 4) }, + { 17, RF_TxPowerTable_HIGH_PA_ENTRY(18, 0, 0, 40, 6) }, + { 18, RF_TxPowerTable_HIGH_PA_ENTRY(24, 0, 0, 51, 8) }, + { 19, RF_TxPowerTable_HIGH_PA_ENTRY(32, 0, 0, 73, 12) }, + { 20, RF_TxPowerTable_HIGH_PA_ENTRY(27, 0, 0, 85, 32) }, + RF_TxPowerTable_TERMINATION_ENTRY }; /*---------------------------------------------------------------------------*/ -// Overrides for CMD_PROP_RADIO_DIV_SETUP +/* Overrides for CMD_PROP_RADIO_DIV_SETUP with defualt PA */ uint32_t rf_prop_overrides_default_pa[] CC_ALIGN(4) = { - // override_use_patch_prop_genfsk.xml - MCE_RFE_OVERRIDE(1,0,0,1,0,0), // PHY: Use MCE RAM patch, RFE RAM patch - // override_synth_prop_863_930_div5.xml - (uint32_t)0x02400403, // Synth: Use 48 MHz crystal as synth clock, enable extra PLL filtering - (uint32_t)0x00068793, // Synth: Set minimum RTRIM to 6 - (uint32_t)0x001C8473, // Synth: Configure extra PLL filtering - (uint32_t)0x00088433, // Synth: Configure extra PLL filtering - (uint32_t)0x000684A3, // Synth: Set Fref to 4 MHz - HW32_ARRAY_OVERRIDE(0x4004,1), // Synth: Configure faster calibration - (uint32_t)0x180C0618, // Synth: Configure faster calibration - (uint32_t)0xC00401A1, // Synth: Configure faster calibration - (uint32_t)0x00010101, // Synth: Configure faster calibration - (uint32_t)0xC0040141, // Synth: Configure faster calibration - (uint32_t)0x00214AD3, // Synth: Configure faster calibration - (uint32_t)0x02980243, // Synth: Decrease synth programming time-out by 90 us from default (0x0298 RAT ticks = 166 us) - (uint32_t)0x0A480583, // Synth: Set loop bandwidth after lock to 20 kHz - (uint32_t)0x7AB80603, // Synth: Set loop bandwidth after lock to 20 kHz - (uint32_t)0x00000623, // Synth: Set loop bandwidth after lock to 20 kHz - // override_phy_tx_pa_ramp_genfsk_hpa.xml - HW_REG_OVERRIDE(0x6028,0x002F), // Tx: Configure PA ramping, set wait time before turning off (0x2F ticks of 16/24 us = 31.3 us). - ADI_HALFREG_OVERRIDE(0,16,0x8,0x8), // Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[3]=1) - ADI_HALFREG_OVERRIDE(0,17,0x1,0x1), // Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[4]=1) - // override_phy_rx_frontend_genfsk.xml - HW_REG_OVERRIDE(0x609C,0x001A), // Rx: Set AGC reference level to 0x1A (default: 0x2E) - (uint32_t)0x00018883, // Rx: Set LNA bias current offset to adjust +1 (default: 0) - (uint32_t)0x000288A3, // Rx: Set RSSI offset to adjust reported RSSI by -2 dB (default: 0) - // override_phy_rx_aaf_bw_0xd.xml - ADI_HALFREG_OVERRIDE(0,61,0xF,0xD), // Rx: Set anti-aliasing filter bandwidth to 0xD (in ADI0, set IFAMPCTL3[7:4]=0xD) - // TX power override - (uint32_t)0xFFFC08C3, // DC/DC regulator: In Tx with 14 dBm PA setting, use DCDCCTL5[3:0]=0xF (DITHER_EN=1 and IPEAK=7). In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). - ADI_REG_OVERRIDE(0,12,0xF8), // Tx: Set PA trim to max to maximize its output power (in ADI0, set PACTL0=0xF8) - (uint32_t)0xFFFFFFFF, + /* override_use_patch_prop_genfsk.xml */ + MCE_RFE_OVERRIDE(1,0,0,1,0,0), /* PHY: Use MCE RAM patch, RFE RAM patch */ + /* override_synth_prop_863_930_div5.xml */ + (uint32_t)0x02400403, /* Synth: Use 48 MHz crystal as synth clock, enable extra PLL filtering */ + (uint32_t)0x00068793, /* Synth: Set minimum RTRIM to 6 */ + (uint32_t)0x001C8473, /* Synth: Configure extra PLL filtering */ + (uint32_t)0x00088433, /* Synth: Configure extra PLL filtering */ + (uint32_t)0x000684A3, /* Synth: Set Fref to 4 MHz */ + HW32_ARRAY_OVERRIDE(0x4004,1), /* Synth: Configure faster calibration */ + (uint32_t)0x180C0618, /* Synth: Configure faster calibration */ + (uint32_t)0xC00401A1, /* Synth: Configure faster calibration */ + (uint32_t)0x00010101, /* Synth: Configure faster calibration */ + (uint32_t)0xC0040141, /* Synth: Configure faster calibration */ + (uint32_t)0x00214AD3, /* Synth: Configure faster calibration */ + /* Synth: Decrease synth programming time-out by 90 us from default */ + (uint32_t)0x02980243, /* (0x0298 RAT ticks = 166 us) */ + (uint32_t)0x0A480583, /* Synth: Set loop bandwidth after lock to 20 kHz */ + (uint32_t)0x7AB80603, /* Synth: Set loop bandwidth after lock to 20 kHz */ + (uint32_t)0x00000623, /* Synth: Set loop bandwidth after lock to 20 kHz */ + /* override_phy_tx_pa_ramp_genfsk_hpa.xml */ + /* Tx: Configure PA ramping, set wait time before turning off */ + HW_REG_OVERRIDE(0x6028,0x002F), /* (0x2F ticks of 16/24 us = 31.3 us). */ + ADI_HALFREG_OVERRIDE(0,16,0x8,0x8), /* Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[3]=1) */ + ADI_HALFREG_OVERRIDE(0,17,0x1,0x1), /* Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[4]=1) */ + /* override_phy_rx_frontend_genfsk.xml */ + HW_REG_OVERRIDE(0x609C,0x001A), /* Rx: Set AGC reference level to 0x1A (default: 0x2E) */ + (uint32_t)0x00018883, /* Rx: Set LNA bias current offset to adjust +1 (default: 0) */ + (uint32_t)0x000288A3, /* Rx: Set RSSI offset to adjust reported RSSI by -2 dB (default: 0) */ + /* override_phy_rx_aaf_bw_0xd.xml */ + /* Rx: Set anti-aliasing filter bandwidth to 0xD */ + ADI_HALFREG_OVERRIDE(0,61,0xF,0xD), /* (in ADI0, set IFAMPCTL3[7:4]=0xD) */ + /* TX power override */ + /* DC/DC regulator: In Tx with 14 dBm PA setting, */ + /* use DCDCCTL5[3:0]=0xF (DITHER_EN=1 and IPEAK=7). */ + (uint32_t)0xFFFC08C3, /* In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). */ + /* Tx: Set PA trim to max to maximize its output power */ + ADI_REG_OVERRIDE(0,12,0xF8), /* (in ADI0, set PACTL0=0xF8) */ + (uint32_t)0xFFFFFFFF, }; /*---------------------------------------------------------------------------*/ -// Overrides for CMD_PROP_RADIO_DIV_SETUP +/* Overrides for CMD_PROP_RADIO_DIV_SETUP with high PA */ uint32_t rf_prop_overrides_high_pa[] CC_ALIGN(4) = { - // override_use_patch_prop_genfsk.xml - MCE_RFE_OVERRIDE(1,0,0,1,0,0), // PHY: Use MCE RAM patch, RFE RAM patch - // override_synth_prop_863_930_div5.xml - (uint32_t)0x02400403, // Synth: Use 48 MHz crystal as synth clock, enable extra PLL filtering - (uint32_t)0x00068793, // Synth: Set minimum RTRIM to 6 - (uint32_t)0x001C8473, // Synth: Configure extra PLL filtering - (uint32_t)0x00088433, // Synth: Configure extra PLL filtering - (uint32_t)0x000684A3, // Synth: Set Fref to 4 MHz - HW32_ARRAY_OVERRIDE(0x4004,1), // Synth: Configure faster calibration - (uint32_t)0x180C0618, // Synth: Configure faster calibration - (uint32_t)0xC00401A1, // Synth: Configure faster calibration - (uint32_t)0x00010101, // Synth: Configure faster calibration - (uint32_t)0xC0040141, // Synth: Configure faster calibration - (uint32_t)0x00214AD3, // Synth: Configure faster calibration - (uint32_t)0x02980243, // Synth: Decrease synth programming time-out by 90 us from default (0x0298 RAT ticks = 166 us) - (uint32_t)0x0A480583, // Synth: Set loop bandwidth after lock to 20 kHz - (uint32_t)0x7AB80603, // Synth: Set loop bandwidth after lock to 20 kHz - (uint32_t)0x00000623, // Synth: Set loop bandwidth after lock to 20 kHz - // override_phy_tx_pa_ramp_genfsk_hpa.xml - HW_REG_OVERRIDE(0x6028,0x002F), // Tx: Configure PA ramping, set wait time before turning off (0x2F ticks of 16/24 us = 31.3 us). - ADI_HALFREG_OVERRIDE(0,16,0x8,0x8), // Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[3]=1) - ADI_HALFREG_OVERRIDE(0,17,0x1,0x1), // Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[4]=1) - // override_phy_rx_frontend_genfsk.xml - HW_REG_OVERRIDE(0x609C,0x001A), // Rx: Set AGC reference level to 0x1A (default: 0x2E) - (uint32_t)0x00018883, // Rx: Set LNA bias current offset to adjust +1 (default: 0) - (uint32_t)0x000288A3, // Rx: Set RSSI offset to adjust reported RSSI by -2 dB (default: 0) - // override_phy_rx_aaf_bw_0xd.xml - ADI_HALFREG_OVERRIDE(0,61,0xF,0xD), // Rx: Set anti-aliasing filter bandwidth to 0xD (in ADI0, set IFAMPCTL3[7:4]=0xD) - // TX power override - (uint32_t)0xFCFC08C3, // DC/DC regulator: In Tx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). - (uint32_t)0x82A86C2B, // txHighPA=0x20AA1B - (uint32_t)0xFFFFFFFF, + /* override_use_patch_prop_genfsk.xml */ + MCE_RFE_OVERRIDE(1,0,0,1,0,0), /* PHY: Use MCE RAM patch, RFE RAM patch */ + /* override_synth_prop_863_930_div5.xml */ + (uint32_t)0x02400403, /* Synth: Use 48 MHz crystal as synth clock, enable extra PLL filtering */ + (uint32_t)0x00068793, /* Synth: Set minimum RTRIM to 6 */ + (uint32_t)0x001C8473, /* Synth: Configure extra PLL filtering */ + (uint32_t)0x00088433, /* Synth: Configure extra PLL filtering */ + (uint32_t)0x000684A3, /* Synth: Set Fref to 4 MHz */ + HW32_ARRAY_OVERRIDE(0x4004,1), /* Synth: Configure faster calibration */ + (uint32_t)0x180C0618, /* Synth: Configure faster calibration */ + (uint32_t)0xC00401A1, /* Synth: Configure faster calibration */ + (uint32_t)0x00010101, /* Synth: Configure faster calibration */ + (uint32_t)0xC0040141, /* Synth: Configure faster calibration */ + (uint32_t)0x00214AD3, /* Synth: Configure faster calibration */ + /* Synth: Decrease synth programming time-out by 90 us from default */ + (uint32_t)0x02980243, /* (0x0298 RAT ticks = 166 us) */ + (uint32_t)0x0A480583, /* Synth: Set loop bandwidth after lock to 20 kHz */ + (uint32_t)0x7AB80603, /* Synth: Set loop bandwidth after lock to 20 kHz */ + (uint32_t)0x00000623, /* Synth: Set loop bandwidth after lock to 20 kHz */ + /* override_phy_tx_pa_ramp_genfsk_hpa.xml */ + /* Tx: Configure PA ramping, set wait time before turning off */ + HW_REG_OVERRIDE(0x6028,0x002F), /* (0x2F ticks of 16/24 us = 31.3 us). */ + ADI_HALFREG_OVERRIDE(0,16,0x8,0x8), /* Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[3]=1) */ + ADI_HALFREG_OVERRIDE(0,17,0x1,0x1), /* Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[4]=1) */ + /* override_phy_rx_frontend_genfsk.xml */ + HW_REG_OVERRIDE(0x609C,0x001A), /* Rx: Set AGC reference level to 0x1A (default: 0x2E) */ + (uint32_t)0x00018883, /* Rx: Set LNA bias current offset to adjust +1 (default: 0) */ + (uint32_t)0x000288A3, /* Rx: Set RSSI offset to adjust reported RSSI by -2 dB (default: 0) */ + /* override_phy_rx_aaf_bw_0xd.xml */ + /* Rx: Set anti-aliasing filter bandwidth to 0xD */ + ADI_HALFREG_OVERRIDE(0,61,0xF,0xD), /* (in ADI0, set IFAMPCTL3[7:4]=0xD) */ + /* TX power override */ + /* DC/DC regulator: */ + /* In Tx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). */ + (uint32_t)0xFCFC08C3, /* In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). */ + (uint32_t)0x82A86C2B, /* txHighPA=0x20AA1B */ + (uint32_t)0xFFFFFFFF, }; /*---------------------------------------------------------------------------*/ -// CMD_PROP_RADIO_DIV_SETUP -// Proprietary Mode Radio Setup Command for All Frequency Bands +/* CMD_PROP_RADIO_DIV_SETUP: Proprietary Mode Radio Setup Command for All Frequency Bands */ rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup = { - .commandNo = CMD_PROP_RADIO_DIV_SETUP, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .modulation.modType = 0x1, - .modulation.deviation = 0x64, - .modulation.deviationStepSz = 0x0, - .symbolRate.preScale = 0xF, - .symbolRate.rateWord = 0x8000, - .symbolRate.decimMode = 0x0, - .rxBw = 0x52, - .preamConf.nPreamBytes = 0x7, - .preamConf.preamMode = 0x0, - .formatConf.nSwBits = 0x18, - .formatConf.bBitReversal = 0x0, - .formatConf.bMsbFirst = 0x1, - .formatConf.fecMode = 0x0, - .formatConf.whitenMode = 0x7, - .config.frontEndMode = 0x0, /* set by driver */ - .config.biasMode = 0x0, /* set by driver */ - .config.analogCfgMode = 0x0, - .config.bNoFsPowerUp = 0x0, - .txPower = 0x013F, /* default 13.5 dBm */ - .pRegOverride = rf_prop_overrides_default_pa, - .centerFreq = 0x0393, /* set by driver */ - .intFreq = 0x8000, /* set by driver */ - .loDivider = 0x05, /* set by driver */ + .commandNo = CMD_PROP_RADIO_DIV_SETUP, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .modulation.modType = 0x1, + .modulation.deviation = 0x64, + .modulation.deviationStepSz = 0x0, + .symbolRate.preScale = 0xF, + .symbolRate.rateWord = 0x8000, + .symbolRate.decimMode = 0x0, + .rxBw = 0x52, + .preamConf.nPreamBytes = 0x7, + .preamConf.preamMode = 0x0, + .formatConf.nSwBits = 0x18, + .formatConf.bBitReversal = 0x0, + .formatConf.bMsbFirst = 0x1, + .formatConf.fecMode = 0x0, + .formatConf.whitenMode = 0x7, + .config.frontEndMode = 0x0, /* set by driver */ + .config.biasMode = 0x0, /* set by driver */ + .config.analogCfgMode = 0x0, + .config.bNoFsPowerUp = 0x0, + .txPower = 0x013F, /* default 13.5 dBm */ + .pRegOverride = rf_prop_overrides_default_pa, + .centerFreq = 0x0393, /* set by driver */ + .intFreq = 0x8000, /* set by driver */ + .loDivider = 0x05, /* set by driver */ }; /*---------------------------------------------------------------------------*/ -// CMD_FS -// Frequency Synthesizer Programming Command +/* CMD_FS: Frequency Synthesizer Programming Command */ rfc_CMD_FS_t rf_cmd_prop_fs = { - .commandNo = CMD_FS, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .frequency = 0x0393, /* set by driver */ - .fractFreq = 0x0000, /* set by driver */ - .synthConf.bTxMode = 0x0, - .synthConf.refFreq = 0x0, - .__dummy0 = 0x00, - .__dummy1 = 0x00, - .__dummy2 = 0x00, - .__dummy3 = 0x0000, + .commandNo = CMD_FS, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .frequency = 0x0393, /* set by driver */ + .fractFreq = 0x0000, /* set by driver */ + .synthConf.bTxMode = 0x0, + .synthConf.refFreq = 0x0, + .__dummy0 = 0x00, + .__dummy1 = 0x00, + .__dummy2 = 0x00, + .__dummy3 = 0x0000, }; /*---------------------------------------------------------------------------*/ -// CMD_PROP_TX_ADV -// Proprietary Mode Advanced Transmit Command +/* CMD_PROP_TX_ADV: Proprietary Mode Advanced Transmit Command */ rfc_CMD_PROP_TX_ADV_t rf_cmd_prop_tx_adv = { - .commandNo = CMD_PROP_TX_ADV, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .pktConf.bFsOff = 0x0, - .pktConf.bUseCrc = 0x1, - .pktConf.bCrcIncSw = 0x0, - .pktConf.bCrcIncHdr = 0x0, - .numHdrBits = 0x10, - .pktLen = 0x0, /* set by driver */ - .startConf.bExtTxTrig = 0x0, - .startConf.inputMode = 0x0, - .startConf.source = 0x0, - .preTrigger.triggerType = TRIG_REL_START, - .preTrigger.bEnaCmd = 0x0, - .preTrigger.triggerNo = 0x0, - .preTrigger.pastTrig = 0x1, - .preTime = 0x00000000, - .syncWord = 0x0055904E, - .pPkt = 0, /* set by driver */ + .commandNo = CMD_PROP_TX_ADV, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .pktConf.bFsOff = 0x0, + .pktConf.bUseCrc = 0x1, + .pktConf.bCrcIncSw = 0x0, + .pktConf.bCrcIncHdr = 0x0, + .numHdrBits = 0x10, + .pktLen = 0x0, /* set by driver */ + .startConf.bExtTxTrig = 0x0, + .startConf.inputMode = 0x0, + .startConf.source = 0x0, + .preTrigger.triggerType = TRIG_REL_START, + .preTrigger.bEnaCmd = 0x0, + .preTrigger.triggerNo = 0x0, + .preTrigger.pastTrig = 0x1, + .preTime = 0x00000000, + .syncWord = 0x0055904E, + .pPkt = 0, /* set by driver */ }; /*---------------------------------------------------------------------------*/ -// CMD_PROP_RX_ADV -// Proprietary Mode Advanced Receive Command +/* CMD_PROP_RX_ADV: Proprietary Mode Advanced Receive Command */ rfc_CMD_PROP_RX_ADV_t rf_cmd_prop_rx_adv = { - .commandNo = CMD_PROP_RX_ADV, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .pktConf.bFsOff = 0x0, - .pktConf.bRepeatOk = 0x1, - .pktConf.bRepeatNok = 0x1, - .pktConf.bUseCrc = 0x1, - .pktConf.bCrcIncSw = 0x0, - .pktConf.bCrcIncHdr = 0x0, - .pktConf.endType = 0x0, - .pktConf.filterOp = 0x1, - .rxConf.bAutoFlushIgnored = 0x1, - .rxConf.bAutoFlushCrcErr = 0x1, - .rxConf.bIncludeHdr = 0x0, - .rxConf.bIncludeCrc = 0x0, - .rxConf.bAppendRssi = 0x1, - .rxConf.bAppendTimestamp = 0x0, - .rxConf.bAppendStatus = 0x1, - .syncWord0 = 0x0055904E, - .syncWord1 = 0x00000000, - .maxPktLen = 0x0, /* set by driver */ - .hdrConf.numHdrBits = 0x10, - .hdrConf.lenPos = 0x0, - .hdrConf.numLenBits = 0x0B, - .addrConf.addrType = 0x0, - .addrConf.addrSize = 0x0, - .addrConf.addrPos = 0x0, - .addrConf.numAddr = 0x0, - .lenOffset = 0xFC, - .endTrigger.triggerType = TRIG_NEVER, - .endTrigger.bEnaCmd = 0x0, - .endTrigger.triggerNo = 0x0, - .endTrigger.pastTrig = 0x0, - .endTime = 0x00000000, - .pAddr = 0, /* set by driver */ - .pQueue = 0, /* set by driver */ - .pOutput = 0, /* set by driver */ + .commandNo = CMD_PROP_RX_ADV, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .pktConf.bFsOff = 0x0, + .pktConf.bRepeatOk = 0x1, + .pktConf.bRepeatNok = 0x1, + .pktConf.bUseCrc = 0x1, + .pktConf.bCrcIncSw = 0x0, + .pktConf.bCrcIncHdr = 0x0, + .pktConf.endType = 0x0, + .pktConf.filterOp = 0x1, + .rxConf.bAutoFlushIgnored = 0x1, + .rxConf.bAutoFlushCrcErr = 0x1, + .rxConf.bIncludeHdr = 0x0, + .rxConf.bIncludeCrc = 0x0, + .rxConf.bAppendRssi = 0x1, + .rxConf.bAppendTimestamp = 0x0, + .rxConf.bAppendStatus = 0x1, + .syncWord0 = 0x0055904E, + .syncWord1 = 0x00000000, + .maxPktLen = 0x0, /* set by driver */ + .hdrConf.numHdrBits = 0x10, + .hdrConf.lenPos = 0x0, + .hdrConf.numLenBits = 0x0B, + .addrConf.addrType = 0x0, + .addrConf.addrSize = 0x0, + .addrConf.addrPos = 0x0, + .addrConf.numAddr = 0x0, + .lenOffset = 0xFC, + .endTrigger.triggerType = TRIG_NEVER, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, + .pAddr = 0, /* set by driver */ + .pQueue = 0, /* set by driver */ + .pOutput = 0, /* set by driver */ }; /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h index d9b6046a1..226c34d30 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h @@ -38,23 +38,23 @@ #include /*---------------------------------------------------------------------------*/ -// TI-RTOS RF Mode Object +/* TI-RTOS RF Mode Object */ extern RF_Mode rf_prop_mode; /*---------------------------------------------------------------------------*/ -// Tx Power Tables +/* Tx Power Tables */ #define RF_PROP_TX_POWER_TABLE_DEFAULT_PA_SIZE 18 #define RF_PROP_TX_POWER_TABLE_HIGH_PA_SIZE 7 extern RF_TxPowerTable_Entry rf_prop_tx_power_table_default_pa[RF_PROP_TX_POWER_TABLE_DEFAULT_PA_SIZE+1]; extern RF_TxPowerTable_Entry rf_prop_tx_power_table_high_pa[RF_PROP_TX_POWER_TABLE_HIGH_PA_SIZE+1]; /*---------------------------------------------------------------------------*/ -// RF Core API commands +/* RF Core API commands */ extern rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup; extern rfc_CMD_FS_t rf_cmd_prop_fs; extern rfc_CMD_PROP_TX_ADV_t rf_cmd_prop_tx_adv; extern rfc_CMD_PROP_RX_ADV_t rf_cmd_prop_rx_adv; /*---------------------------------------------------------------------------*/ -// RF Core API Overrides +/* RF Core API Overrides */ extern uint32_t rf_prop_overrides_default_pa[]; extern uint32_t rf_prop_overrides_high_pa[]; /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.c index 39f2b8691..d803b0b60 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.c @@ -1,256 +1,192 @@ -//********************************************************************************* -// Generated by SmartRF Studio version 2.10.0 (build#106) -// Compatible with SimpleLink SDK version: No known SDK for this device -// Device: CC2650 Rev. 2.2 -// -//********************************************************************************* - - -//********************************************************************************* -// Parameter summary -// Adv. Address: 010203040506 -// Adv. Data: 255 -// BLE Channel: 17 -// Frequency: 2440 MHz -// PDU Payload length:: 30 -// TX Power: 5 dBm -// Whitening: true - +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/* + * Parameter summary + * Adv. Address: 010203040506 + * Adv. Data: 255 + * BLE Channel: 17 + * Frequency: 2440 MHz + * PDU Payload length:: 30 + * TX Power: 5 dBm + * Whitening: true + */ +/*---------------------------------------------------------------------------*/ +#include "sys/cc.h" +/*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) #include DeviceFamily_constructPath(driverlib/rf_ble_cmd.h) -#include #include DeviceFamily_constructPath(rf_patches/rf_patch_cpe_ble.h) #include DeviceFamily_constructPath(rf_patches/rf_patch_rfe_ble.h) + +#include +/*---------------------------------------------------------------------------*/ #include "ieee_settings.h" - - -// TI-RTOS RF Mode Object -RF_Mode RF_ble = +/*---------------------------------------------------------------------------*/ +/* TI-RTOS RF Mode Object */ +RF_Mode rf_ble_mode = { - .rfMode = RF_MODE_BLE, - .cpePatchFxn = &rf_patch_cpe_ble, - .mcePatchFxn = 0, - .rfePatchFxn = &rf_patch_rfe_ble, + .rfMode = RF_MODE_BLE, + .cpePatchFxn = &rf_patch_cpe_ble, + .mcePatchFxn = 0, + .rfePatchFxn = &rf_patch_rfe_ble, }; - -// TX Power table -// The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: -// RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) -// See the Technical Reference Manual for further details about the "txPower" Command field. -// The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. -RF_TxPowerTable_Entry txPowerTable[TX_POWER_TABLE_SIZE] = -{ - {-21, RF_TxPowerTable_DEFAULT_PA_ENTRY(7, 3, 0, 6) }, - {-18, RF_TxPowerTable_DEFAULT_PA_ENTRY(9, 3, 0, 6) }, - {-15, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 6) }, - {-12, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 1, 0, 10) }, - {-9, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 1, 12) }, - {-6, RF_TxPowerTable_DEFAULT_PA_ENTRY(18, 1, 1, 14) }, - {-3, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 1, 1, 18) }, - {0, RF_TxPowerTable_DEFAULT_PA_ENTRY(33, 1, 1, 24) }, - {1, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 0, 0, 33) }, - {2, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 0, 0, 39) }, - {3, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 0, 0, 45) }, - {4, RF_TxPowerTable_DEFAULT_PA_ENTRY(36, 0, 1, 73) }, - {5, RF_TxPowerTable_DEFAULT_PA_ENTRY(48, 0, 1, 73) }, - RF_TxPowerTable_TERMINATION_ENTRY -}; - - -// Overrides for CMD_RADIO_SETUP -uint32_t pOverrides[] = +/*---------------------------------------------------------------------------*/ +/* + * TX Power table + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +RF_TxPowerTable_Entry rf_ble_tx_power_table[RF_BLE_TX_POWER_TABLE_SIZE+1] = { - // override_use_patch_ble_1mbps.xml - // PHY: Use MCE ROM, RFE RAM patch - MCE_RFE_OVERRIDE(0,0,0,1,0,0), - // override_synth_ble_1mbps.xml - // Synth: Set recommended RTRIM to 5 - HW_REG_OVERRIDE(0x4038,0x0035), - // Synth: Set Fref to 3.43 MHz - (uint32_t)0x000784A3, - // Synth: Set loop bandwidth after lock to 80 kHz - (uint32_t)0xA47E0583, - // Synth: Set loop bandwidth after lock to 80 kHz - (uint32_t)0xEAE00603, - // Synth: Set loop bandwidth after lock to 80 kHz - (uint32_t)0x00010623, - // Synth: Configure PLL bias - HW32_ARRAY_OVERRIDE(0x405C,1), - // Synth: Configure PLL bias - (uint32_t)0x1801F800, - // Synth: Configure PLL latency - HW32_ARRAY_OVERRIDE(0x402C,1), - // Synth: Configure PLL latency - (uint32_t)0x00608402, - // Synth: Use 24 MHz XOSC as synth clock, enable extra PLL filtering - (uint32_t)0x02010403, - // Synth: Configure extra PLL filtering - HW32_ARRAY_OVERRIDE(0x4034,1), - // Synth: Configure extra PLL filtering - (uint32_t)0x177F0408, - // Synth: Configure extra PLL filtering - (uint32_t)0x38000463, - // override_phy_ble_1mbps.xml - // Tx: Configure symbol shape for BLE frequency deviation requirements - (uint32_t)0x013800C3, - // Rx: Configure AGC reference level - HW_REG_OVERRIDE(0x6088, 0x0045), - // Tx: Configure pilot tone length to ensure stable frequency before start of packet - HW_REG_OVERRIDE(0x52AC, 0x0360), - // Tx: Compensate timing offset to match new pilot tone setting - (uint32_t)0x01AD02A3, - // Tx: Compensate timing offset to match new pilot tone setting - (uint32_t)0x01680263, - // override_frontend_id.xml - (uint32_t)0xFFFFFFFF, + { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 6) }, + { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 6) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 6) }, + { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 1, 0, 10) }, + { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 1, 12) }, + { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(18, 1, 1, 14) }, + { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 1, 1, 18) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(33, 1, 1, 24) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 0, 0, 33) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 0, 0, 39) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 0, 0, 45) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(36, 0, 1, 73) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(48, 0, 1, 73) }, + RF_TxPowerTable_TERMINATION_ENTRY }; - - -// CMD_RADIO_SETUP -// Radio Setup Command for Pre-Defined Schemes -rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup = +/*---------------------------------------------------------------------------*/ +/* Overrides for CMD_RADIO_SETUP */ +uint32_t rf_ble_overrides[] CC_ALIGN(4) = { - .commandNo = 0x0802, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .mode = 0x00, - .__dummy0 = 0x00, - .config.frontEndMode = 0x0, - .config.biasMode = 0x0, - .config.analogCfgMode = 0x0, - .config.bNoFsPowerUp = 0x0, - .txPower = 0x9330, - .pRegOverride = pOverrides, + /* override_use_patch_ble_1mbps.xml */ + MCE_RFE_OVERRIDE(0,0,0,1,0,0), /* PHY: Use MCE ROM, RFE RAM patch */ + /* override_synth_ble_1mbps.xml */ + HW_REG_OVERRIDE(0x4038,0x0035), /* Synth: Set recommended RTRIM to 5 */ + (uint32_t)0x000784A3, /* Synth: Set Fref to 3.43 MHz */ + (uint32_t)0xA47E0583, /* Synth: Set loop bandwidth after lock to 80 kHz */ + (uint32_t)0xEAE00603, /* Synth: Set loop bandwidth after lock to 80 kHz */ + (uint32_t)0x00010623, /* Synth: Set loop bandwidth after lock to 80 kHz */ + HW32_ARRAY_OVERRIDE(0x405C,1), /* Synth: Configure PLL bias */ + (uint32_t)0x1801F800, /* Synth: Configure PLL bias */ + HW32_ARRAY_OVERRIDE(0x402C,1), /* Synth: Configure PLL latency */ + (uint32_t)0x00608402, /* Synth: Configure PLL latency */ + (uint32_t)0x02010403, /* Synth: Use 24 MHz XOSC as synth clock, enable extra PLL filtering */ + HW32_ARRAY_OVERRIDE(0x4034,1), /* Synth: Configure extra PLL filtering */ + (uint32_t)0x177F0408, /* Synth: Configure extra PLL filtering */ + (uint32_t)0x38000463, /* Synth: Configure extra PLL filtering */ + /* override_phy_ble_1mbps.xml */ + (uint32_t)0x013800C3, /* Tx: Configure symbol shape for BLE frequency deviation requirements */ + HW_REG_OVERRIDE(0x6088, 0x0045), /* Rx: Configure AGC reference level */ + /* Tx: Configure pilot tone length to ensure stable frequency */ + HW_REG_OVERRIDE(0x52AC, 0x0360), /* before start of packet */ + (uint32_t)0x01AD02A3, /* Tx: Compensate timing offset to match new pilot tone setting */ + (uint32_t)0x01680263, /* Tx: Compensate timing offset to match new pilot tone setting */ + (uint32_t)0xFFFFFFFF, }; - -// CMD_FS -// Frequency Synthesizer Programming Command -rfc_CMD_FS_t RF_cmdFs = +/*---------------------------------------------------------------------------*/ +/* CMD_RADIO_SETUP: Radio Setup Command for Pre-Defined Schemes */ +rfc_CMD_RADIO_SETUP_t rf_ble_cmd_radio_setup = { - .commandNo = 0x0803, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .frequency = 0x0988, - .fractFreq = 0x0000, - .synthConf.bTxMode = 0x0, - .synthConf.refFreq = 0x0, - .__dummy0 = 0x00, - .__dummy1 = 0x00, - .__dummy2 = 0x00, - .__dummy3 = 0x0000, + .commandNo = CMD_RADIO_SETUP, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .mode = 0x00, + .__dummy0 = 0x00, + .config.frontEndMode = 0x0, + .config.biasMode = 0x0, + .config.analogCfgMode = 0x0, + .config.bNoFsPowerUp = 0x0, + .txPower = 0x9330, + .pRegOverride = rf_ble_overrides, }; - -// Structure for CMD_BLE_ADV_NC.pParams -rfc_bleAdvPar_t bleAdvPar = +/*---------------------------------------------------------------------------*/ +/* Structure for CMD_BLE_ADV_NC.pParams */ +rfc_bleAdvPar_t rf_ble_adv_par = { - .pRxQ = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx - .rxConfig.bAutoFlushIgnored = 0x0, - .rxConfig.bAutoFlushCrcErr = 0x0, - .rxConfig.bAutoFlushEmpty = 0x0, - .rxConfig.bIncludeLenByte = 0x0, - .rxConfig.bIncludeCrc = 0x0, - .rxConfig.bAppendRssi = 0x0, - .rxConfig.bAppendStatus = 0x0, - .rxConfig.bAppendTimestamp = 0x0, - .advConfig.advFilterPolicy = 0x0, - .advConfig.deviceAddrType = 0x0, - .advConfig.peerAddrType = 0x0, - .advConfig.bStrictLenFilter = 0x0, - .advConfig.rpaMode = 0x0, - .advLen = 0x18, - .scanRspLen = 0x00, - .pAdvData = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .pScanRspData = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .pDeviceAddress = 0, // INSERT APPLICABLE POINTER: (uint16_t*)&xxx - .pWhiteList = 0, // INSERT APPLICABLE POINTER: (uint32_t*)&xxx - .__dummy0 = 0x0000, - .__dummy1 = 0x00, - .endTrigger.triggerType = 0x1, - .endTrigger.bEnaCmd = 0x0, - .endTrigger.triggerNo = 0x0, - .endTrigger.pastTrig = 0x0, - .endTime = 0x00000000, + .pRxQ = 0, + .rxConfig.bAutoFlushIgnored = 0x0, + .rxConfig.bAutoFlushCrcErr = 0x0, + .rxConfig.bAutoFlushEmpty = 0x0, + .rxConfig.bIncludeLenByte = 0x0, + .rxConfig.bIncludeCrc = 0x0, + .rxConfig.bAppendRssi = 0x0, + .rxConfig.bAppendStatus = 0x0, + .rxConfig.bAppendTimestamp = 0x0, + .advConfig.advFilterPolicy = 0x0, + .advConfig.deviceAddrType = 0x0, + .advConfig.peerAddrType = 0x0, + .advConfig.bStrictLenFilter = 0x0, + .advConfig.rpaMode = 0x0, + .advLen = 0x18, + .scanRspLen = 0x00, + .pAdvData = 0, + .pScanRspData = 0, + .pDeviceAddress = 0, + .pWhiteList = 0, + .__dummy0 = 0x0000, + .__dummy1 = 0x00, + .endTrigger.triggerType = TRIG_NEVER, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, }; - -// CMD_BLE_ADV_NC -// BLE Non-Connectable Advertiser Command -rfc_CMD_BLE_ADV_NC_t RF_cmdBleAdvNc = +/*---------------------------------------------------------------------------*/ +/* CMD_BLE_ADV_NC: BLE Non-Connectable Advertiser Command */ +rfc_CMD_BLE_ADV_NC_t rf_ble_cmd_ble_adv_nc = { - .commandNo = 0x1805, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .channel = 0x8C, - .whitening.init = 0x51, - .whitening.bOverride = 0x1, - .pParams = &bleAdvPar, - .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx -}; - -// Structure for CMD_BLE_GENERIC_RX.pParams -rfc_bleGenericRxPar_t bleGenericRxPar = -{ - .pRxQ = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx - .rxConfig.bAutoFlushIgnored = 0x0, - .rxConfig.bAutoFlushCrcErr = 0x0, - .rxConfig.bAutoFlushEmpty = 0x0, - .rxConfig.bIncludeLenByte = 0x1, - .rxConfig.bIncludeCrc = 0x1, - .rxConfig.bAppendRssi = 0x1, - .rxConfig.bAppendStatus = 0x1, - .rxConfig.bAppendTimestamp = 0x0, - .bRepeat = 0x01, - .__dummy0 = 0x0000, - .accessAddress = 0x8E89BED6, - .crcInit0 = 0x55, - .crcInit1 = 0x55, - .crcInit2 = 0x55, - .endTrigger.triggerType = 0x1, - .endTrigger.bEnaCmd = 0x0, - .endTrigger.triggerNo = 0x0, - .endTrigger.pastTrig = 0x0, - .endTime = 0x00000001, -}; - -// CMD_BLE_GENERIC_RX -// BLE Generic Receiver Command -rfc_CMD_BLE_GENERIC_RX_t RF_cmdBleGenericRx = -{ - .commandNo = 0x1809, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .channel = 0x8C, - .whitening.init = 0x51, - .whitening.bOverride = 0x1, - .pParams = &bleGenericRxPar, - .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx + .commandNo = CMD_BLE_ADV_NC, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .channel = 0x8C, + .whitening.init = 0x51, + .whitening.bOverride = 0x1, + .pParams = &rf_ble_adv_par, + .pOutput = 0, }; +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.h index 7bdf9b309..63afd846b 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.h @@ -1,41 +1,59 @@ -#ifndef _BLE-SETTINGS_H_ -#define _BLE-SETTINGS_H_ - -//********************************************************************************* -// Generated by SmartRF Studio version 2.10.0 (build#106) -// Compatible with SimpleLink SDK version: No known SDK for this device -// Device: CC2650 Rev. 2.2 -// -//********************************************************************************* +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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 BLE_SETTINGS_H_ +#define BLE_SETTINGS_H_ +/*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) #include DeviceFamily_constructPath(driverlib/rf_ble_cmd.h) + #include +/*---------------------------------------------------------------------------*/ +/* TX Power table size definition */ +#define RF_BLE_TX_POWER_TABLE_SIZE 13 - -// TX Power table size definition -#define TX_POWER_TABLE_SIZE 14 - - -// TX Power Table Object -extern RF_TxPowerTable_Entry txPowerTable[TX_POWER_TABLE_SIZE]; - - -// TI-RTOS RF Mode Object -extern RF_Mode RF_ble; - - -// RF Core API commands -extern rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup; -extern rfc_CMD_FS_t RF_cmdFs; -extern rfc_CMD_BLE_ADV_NC_t RF_cmdBleAdvNc; -extern rfc_CMD_BLE_GENERIC_RX_t RF_cmdBleGenericRx; - - -// RF Core API Overrides -extern uint32_t pOverrides[]; - - -#endif // _BLE-SETTINGS_H_ - +/* TX Power Table Object */ +extern RF_TxPowerTable_Entry rf_ble_tx_power_table[RF_BLE_TX_POWER_TABLE_SIZE+1]; +/*---------------------------------------------------------------------------*/ +/* TI-RTOS RF Mode Object */ +extern RF_Mode rf_ble_mode; +/*---------------------------------------------------------------------------*/ +/* RF Core API commands */ +extern rfc_CMD_RADIO_SETUP_t rf_ble_cmd_radio_setup; +extern rfc_CMD_FS_t rf_ble_cmd_fs; +extern rfc_CMD_BLE_ADV_NC_t rf_ble_cmd_ble_adv_nc; +/*---------------------------------------------------------------------------*/ +/* RF Core API Overrides */ +extern uint32_t rf_ble_overrides[]; +/*---------------------------------------------------------------------------*/ +#endif /* BLE_SETTINGS_H_ */ +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c index f2fb6963c..96468c78b 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c @@ -28,13 +28,15 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /*---------------------------------------------------------------------------*/ -// Parameter summary -// IEEE Channel: 11 -// Frequency: 2405 MHz -// SFD: 0 -// Packet Data: 255 -// Preamble (32 bit): 01010101... -// TX Power: 5 dBm +/* + * Parameter summary + * IEEE Channel: 11 + * Frequency: 2405 MHz + * SFD: 0 + * Packet Data: 255 + * Preamble (32 bit): 01010101... + * TX Power: 5 dBm + */ /*---------------------------------------------------------------------------*/ #include "sys/cc.h" /*---------------------------------------------------------------------------*/ @@ -48,222 +50,219 @@ /*---------------------------------------------------------------------------*/ #include "ieee-settings.h" /*---------------------------------------------------------------------------*/ -// TI-RTOS RF Mode Object +/* TI-RTOS RF Mode Object */ RF_Mode rf_ieee_mode = { - .rfMode = RF_MODE_IEEE_15_4, - .cpePatchFxn = &rf_patch_cpe_ieee, - .mcePatchFxn = 0, - .rfePatchFxn = 0, + .rfMode = RF_MODE_IEEE_15_4, + .cpePatchFxn = &rf_patch_cpe_ieee, + .mcePatchFxn = 0, + .rfePatchFxn = 0, }; /*---------------------------------------------------------------------------*/ -// TX Power table -// The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: -// RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) -// See the Technical Reference Manual for further details about the "txPower" Command field. -// The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. +/* + * TX Power table + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ RF_TxPowerTable_Entry rf_ieee_tx_power_table[RF_IEEE_TX_POWER_TABLE_SIZE+1] = { - { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 6) }, - { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 6) }, - { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 6) }, - { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 1, 0, 10) }, - { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 1, 12) }, - { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(18, 1, 1, 14) }, - { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 1, 1, 18) }, - { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(33, 1, 1, 24) }, - { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 0, 0, 33) }, - { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 0, 0, 39) }, - { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 0, 0, 45) }, - { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(36, 0, 1, 73) }, - { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(48, 0, 1, 73) }, - RF_TxPowerTable_TERMINATION_ENTRY + { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 6) }, + { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 6) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 6) }, + { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 1, 0, 10) }, + { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 1, 12) }, + { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(18, 1, 1, 14) }, + { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 1, 1, 18) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(33, 1, 1, 24) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 0, 0, 33) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 0, 0, 39) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 0, 0, 45) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(36, 0, 1, 73) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(48, 0, 1, 73) }, + RF_TxPowerTable_TERMINATION_ENTRY }; /*---------------------------------------------------------------------------*/ -// Overrides for CMD_RADIO_SETUP +/* Overrides for CMD_RADIO_SETUP */ uint32_t rf_ieee_overrides[] CC_ALIGN(4) = { - // override_synth_ieee_15_4.xml - HW_REG_OVERRIDE(0x4038,0x0035), // Synth: Set recommended RTRIM to 5 - (uint32_t)0x000784A3, // Synth: Set Fref to 3.43 MHz - (uint32_t)0xA47E0583, // Synth: Set loop bandwidth after lock to 80 kHz - (uint32_t)0xEAE00603, // Synth: Set loop bandwidth after lock to 80 kHz - (uint32_t)0x00010623, // Synth: Set loop bandwidth after lock to 80 kHz - HW32_ARRAY_OVERRIDE(0x405C,1), // Synth: Configure PLL bias - (uint32_t)0x1801F800, // Synth: Configure PLL bias - HW32_ARRAY_OVERRIDE(0x402C,1), // Synth: Configure PLL latency - (uint32_t)0x00608402, // Synth: Configure PLL latency - (uint32_t)0x02010403, // Synth: Use 24 MHz XOSC as synth clock, enable extra PLL filtering - HW32_ARRAY_OVERRIDE(0x4034,1), // Synth: Configure extra PLL filtering - (uint32_t)0x177F0408, // Synth: Configure extra PLL filtering - (uint32_t)0x38000463, // Synth: Configure extra PLL filtering - // override_phy_ieee_15_4.xml - (uint32_t)0x05000243, // Synth: Increase synth programming timeout - (uint32_t)0x002082C3, // Rx: Adjust Rx FIFO threshold to avoid overflow - // override_frontend_id.xml - (uint32_t)0x000288A3, // Rx: Set RSSI offset to adjust reported RSSI by -2 dB - (uint32_t)0x000F8883, // Rx: Configure LNA bias current trim offset - HW_REG_OVERRIDE(0x50DC,0x002B), // Rx: Adjust AGC DC filter - (uint32_t)0xFFFFFFFF, + /* override_synth_ieee_15_4.xml */ + HW_REG_OVERRIDE(0x4038,0x0035), /* Synth: Set recommended RTRIM to 5 */ + (uint32_t)0x000784A3, /* Synth: Set Fref to 3.43 MHz */ + (uint32_t)0xA47E0583, /* Synth: Set loop bandwidth after lock to 80 kHz */ + (uint32_t)0xEAE00603, /* Synth: Set loop bandwidth after lock to 80 kHz */ + (uint32_t)0x00010623, /* Synth: Set loop bandwidth after lock to 80 kHz */ + HW32_ARRAY_OVERRIDE(0x405C,1), /* Synth: Configure PLL bias */ + (uint32_t)0x1801F800, /* Synth: Configure PLL bias */ + HW32_ARRAY_OVERRIDE(0x402C,1), /* Synth: Configure PLL latency */ + (uint32_t)0x00608402, /* Synth: Configure PLL latency */ + (uint32_t)0x02010403, /* Synth: Use 24 MHz XOSC as synth clock, enable extra PLL filtering */ + HW32_ARRAY_OVERRIDE(0x4034,1), /* Synth: Configure extra PLL filtering */ + (uint32_t)0x177F0408, /* Synth: Configure extra PLL filtering */ + (uint32_t)0x38000463, /* Synth: Configure extra PLL filtering */ + /* override_phy_ieee_15_4.xml */ + (uint32_t)0x05000243, /* Synth: Increase synth programming timeout */ + (uint32_t)0x002082C3, /* Rx: Adjust Rx FIFO threshold to avoid overflow */ + /* override_frontend_id.xml */ + (uint32_t)0x000288A3, /* Rx: Set RSSI offset to adjust reported RSSI by -2 dB */ + (uint32_t)0x000F8883, /* Rx: Configure LNA bias current trim offset */ + HW_REG_OVERRIDE(0x50DC,0x002B), /* Rx: Adjust AGC DC filter */ + (uint32_t)0xFFFFFFFF, }; /*---------------------------------------------------------------------------*/ -// CMD_RADIO_SETUP -// Radio Setup Command for Pre-Defined Schemes +/* CMD_RADIO_SETUP: Radio Setup Command for Pre-Defined Schemes */ rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup = { - .commandNo = CMD_RADIO_SETUP, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .mode = 0x01, - .__dummy0 = 0x00, - .config.frontEndMode = 0x0, - .config.biasMode = 0x1, - .config.analogCfgMode = 0x0, - .config.bNoFsPowerUp = 0x0, - .txPower = 0x9330, /* 5 dBm default */ - .pRegOverride = rf_ieee_overrides, + .commandNo = CMD_RADIO_SETUP, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .mode = 0x01, + .__dummy0 = 0x00, + .config.frontEndMode = 0x0, + .config.biasMode = 0x1, + .config.analogCfgMode = 0x0, + .config.bNoFsPowerUp = 0x0, + .txPower = 0x9330, /* 5 dBm default */ + .pRegOverride = rf_ieee_overrides, }; /*---------------------------------------------------------------------------*/ -// CMD_FS -// Frequency Synthesizer Programming Command +/* CMD_FS: Frequency Synthesizer Programming Command */ rfc_CMD_FS_t rf_cmd_ieee_fs = { - .commandNo = CMD_FS, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .frequency = 0x0965, /* set by driver */ - .fractFreq = 0x0000, /* set by driver */ - .synthConf.bTxMode = 0x1, - .synthConf.refFreq = 0x0, - .__dummy0 = 0x00, - .__dummy1 = 0x00, - .__dummy2 = 0x00, - .__dummy3 = 0x0000, + .commandNo = CMD_FS, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .frequency = 0x0965, /* set by driver */ + .fractFreq = 0x0000, /* set by driver */ + .synthConf.bTxMode = 0x1, + .synthConf.refFreq = 0x0, + .__dummy0 = 0x00, + .__dummy1 = 0x00, + .__dummy2 = 0x00, + .__dummy3 = 0x0000, }; /*---------------------------------------------------------------------------*/ -// CMD_IEEE_TX -// The command ID number 0x2C01 +/* CMD_IEEE_TX: IEEE 802.15.4 Transmit Command */ rfc_CMD_IEEE_TX_t rf_cmd_ieee_tx = { - .commandNo = CMD_IEEE_TX, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .txOpt.bIncludePhyHdr = 0x0, - .txOpt.bIncludeCrc = 0x0, - .txOpt.payloadLenMsb = 0x0, - .payloadLen = 0x0, /* set by driver */ - .pPayload = 0, /* set by driver */ - .timeStamp = 0x00000000, + .commandNo = CMD_IEEE_TX, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .txOpt.bIncludePhyHdr = 0x0, + .txOpt.bIncludeCrc = 0x0, + .txOpt.payloadLenMsb = 0x0, + .payloadLen = 0x0, /* set by driver */ + .pPayload = 0, /* set by driver */ + .timeStamp = 0x00000000, }; /*---------------------------------------------------------------------------*/ -// CMD_IEEE_RX -// The command ID number 0x2801 +/* CMD_IEEE_RX: IEEE 802.15.4 Receive Command */ rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx = { - .commandNo = CMD_IEEE_RX, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .channel = 0x00, /* set by driver */ - .rxConfig.bAutoFlushCrc = 0x1, - .rxConfig.bAutoFlushIgn = 0x0, - .rxConfig.bIncludePhyHdr = 0x0, - .rxConfig.bIncludeCrc = 0x1, - .rxConfig.bAppendRssi = 0x1, - .rxConfig.bAppendCorrCrc = 0x1, - .rxConfig.bAppendSrcInd = 0x0, - .rxConfig.bAppendTimestamp = 0x1, - .pRxQ = 0, /* set by driver */ - .pOutput = 0, /* set by driver */ - .frameFiltOpt.frameFiltEn = 0x0, /* set by driver */ - .frameFiltOpt.frameFiltStop = 0x1, - .frameFiltOpt.autoAckEn = 0x0, /* set by driver */ - .frameFiltOpt.slottedAckEn = 0x0, - .frameFiltOpt.autoPendEn = 0x0, - .frameFiltOpt.defaultPend = 0x0, - .frameFiltOpt.bPendDataReqOnly = 0x0, - .frameFiltOpt.bPanCoord = 0x0, - .frameFiltOpt.maxFrameVersion = 0x2, - .frameFiltOpt.fcfReservedMask = 0x0, - .frameFiltOpt.modifyFtFilter = 0x0, - .frameFiltOpt.bStrictLenFilter = 0x0, - .frameTypes.bAcceptFt0Beacon = 0x1, - .frameTypes.bAcceptFt1Data = 0x1, - .frameTypes.bAcceptFt2Ack = 0x1, - .frameTypes.bAcceptFt3MacCmd = 0x1, - .frameTypes.bAcceptFt4Reserved = 0x1, - .frameTypes.bAcceptFt5Reserved = 0x1, - .frameTypes.bAcceptFt6Reserved = 0x1, - .frameTypes.bAcceptFt7Reserved = 0x1, - .ccaOpt.ccaEnEnergy = 0x1, - .ccaOpt.ccaEnCorr = 0x1, - .ccaOpt.ccaEnSync = 0x1, - .ccaOpt.ccaCorrOp = 0x1, - .ccaOpt.ccaSyncOp = 0x0, - .ccaOpt.ccaCorrThr = 0x3, - .ccaRssiThr = 0x0, /* set by driver */ - .__dummy0 = 0x00, - .numExtEntries = 0x00, - .numShortEntries = 0x00, - .pExtEntryList = 0, - .pShortEntryList = 0, - .localExtAddr = 0x0, /* set by driver */ - .localShortAddr = 0x0, /* set by driver */ - .localPanID = 0x0000, - .__dummy1 = 0x000000, - .endTrigger.triggerType = TRIG_NEVER, - .endTrigger.bEnaCmd = 0x0, - .endTrigger.triggerNo = 0x0, - .endTrigger.pastTrig = 0x0, - .endTime = 0x00000000, + .commandNo = CMD_IEEE_RX, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .channel = 0x00, /* set by driver */ + .rxConfig.bAutoFlushCrc = 0x1, + .rxConfig.bAutoFlushIgn = 0x0, + .rxConfig.bIncludePhyHdr = 0x0, + .rxConfig.bIncludeCrc = 0x1, + .rxConfig.bAppendRssi = 0x1, + .rxConfig.bAppendCorrCrc = 0x1, + .rxConfig.bAppendSrcInd = 0x0, + .rxConfig.bAppendTimestamp = 0x1, + .pRxQ = 0, /* set by driver */ + .pOutput = 0, /* set by driver */ + .frameFiltOpt.frameFiltEn = 0x0, /* set by driver */ + .frameFiltOpt.frameFiltStop = 0x1, + .frameFiltOpt.autoAckEn = 0x0, /* set by driver */ + .frameFiltOpt.slottedAckEn = 0x0, + .frameFiltOpt.autoPendEn = 0x0, + .frameFiltOpt.defaultPend = 0x0, + .frameFiltOpt.bPendDataReqOnly = 0x0, + .frameFiltOpt.bPanCoord = 0x0, + .frameFiltOpt.maxFrameVersion = 0x2, + .frameFiltOpt.fcfReservedMask = 0x0, + .frameFiltOpt.modifyFtFilter = 0x0, + .frameFiltOpt.bStrictLenFilter = 0x0, + .frameTypes.bAcceptFt0Beacon = 0x1, + .frameTypes.bAcceptFt1Data = 0x1, + .frameTypes.bAcceptFt2Ack = 0x1, + .frameTypes.bAcceptFt3MacCmd = 0x1, + .frameTypes.bAcceptFt4Reserved = 0x1, + .frameTypes.bAcceptFt5Reserved = 0x1, + .frameTypes.bAcceptFt6Reserved = 0x1, + .frameTypes.bAcceptFt7Reserved = 0x1, + .ccaOpt.ccaEnEnergy = 0x1, + .ccaOpt.ccaEnCorr = 0x1, + .ccaOpt.ccaEnSync = 0x1, + .ccaOpt.ccaCorrOp = 0x1, + .ccaOpt.ccaSyncOp = 0x0, + .ccaOpt.ccaCorrThr = 0x3, + .ccaRssiThr = 0x0, /* set by driver */ + .__dummy0 = 0x00, + .numExtEntries = 0x00, + .numShortEntries = 0x00, + .pExtEntryList = 0, + .pShortEntryList = 0, + .localExtAddr = 0x0, /* set by driver */ + .localShortAddr = 0x0, /* set by driver */ + .localPanID = 0x0000, + .__dummy1 = 0x000000, + .endTrigger.triggerType = TRIG_NEVER, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, }; /*---------------------------------------------------------------------------*/ -// CMD_IEEE_RX_ACK -// IEEE 802.15.4 Receive ACK Command +/* CMD_IEEE_RX_ACK: IEEE 802.15.4 Receive ACK Command */ rfc_CMD_IEEE_RX_ACK_t rf_cmd_ieee_rx_ack = { - .commandNo = CMD_IEEE_RX_ACK, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .seqNo = 0x0, - .endTrigger.triggerType = TRIG_NEVER, - .endTrigger.bEnaCmd = 0x0, - .endTrigger.triggerNo = 0x0, - .endTrigger.pastTrig = 0x0, - .endTime = 0x00000000, + .commandNo = CMD_IEEE_RX_ACK, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .seqNo = 0x0, + .endTrigger.triggerType = TRIG_NEVER, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, }; /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h index 55434276c..3a4a7236d 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h @@ -39,22 +39,22 @@ #include /*---------------------------------------------------------------------------*/ -// TI-RTOS RF Mode Object +/* TI-RTOS RF Mode Object */ extern RF_Mode rf_ieee_mode; /*---------------------------------------------------------------------------*/ -// TX Power Table +/* TX Power Table */ #define RF_IEEE_TX_POWER_TABLE_SIZE 14 extern RF_TxPowerTable_Entry rf_ieee_tx_power_table[RF_IEEE_TX_POWER_TABLE_SIZE+1]; /*---------------------------------------------------------------------------*/ -// RF Core API commands +/* RF Core API commands */ extern rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup; extern rfc_CMD_FS_t rf_cmd_ieee_fs; extern rfc_CMD_IEEE_TX_t rf_cmd_ieee_tx; extern rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx; extern rfc_CMD_IEEE_RX_ACK_t rf_cmd_ieee_rx_ack; /*---------------------------------------------------------------------------*/ -// RF Core API Overrides +/* RF Core API Overrides */ extern uint32_t rf_ieee_overrides[]; /*---------------------------------------------------------------------------*/ #endif /* IEEE_SETTINGS_H_ */ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.c index 69758f60f..c39fc4207 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.c @@ -1,308 +1,230 @@ -//********************************************************************************* -// Generated by SmartRF Studio version 2.10.0 (build#106) -// Compatible with SimpleLink SDK version: CC26x2 SDK 2.20.xx.xx -// Device: CC2652R Rev. 1.1 (Rev. C) -// -//********************************************************************************* - - -//********************************************************************************* -// Parameter summary -// Adv. Address: 010203040506 -// Adv. Data: dummy -// BLE Channel: 17 -// Extended Header: 09 09 010203040506 babe -// Frequency: 2440 MHz -// PDU Payload length:: 30 -// TX Power: 5 dBm -// Whitening: true - +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/* + * Parameter summary + * Adv. Address: 010203040506 + * Adv. Data: dummy + * BLE Channel: 17 + * Extended Header: 09 09 010203040506 babe + * Frequency: 2440 MHz + * PDU Payload length:: 30 + * TX Power: 5 dBm + * Whitening: true + */ +/*---------------------------------------------------------------------------*/ +#include "sys/cc.h" +/*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) #include DeviceFamily_constructPath(driverlib/rf_ble_cmd.h) -#include #include DeviceFamily_constructPath(rf_patches/rf_patch_cpe_bt5.h) #include DeviceFamily_constructPath(rf_patches/rf_patch_rfe_bt5.h) #include DeviceFamily_constructPath(rf_patches/rf_patch_mce_bt5.h) + +#include +/*---------------------------------------------------------------------------*/ #include "ble-settings.h" - - -// TI-RTOS RF Mode Object -RF_Mode RF_prop = +/*---------------------------------------------------------------------------*/ +/* TI-RTOS RF Mode Object */ +RF_Mode rf_ble_mode = { - .rfMode = RF_MODE_AUTO, - .cpePatchFxn = &rf_patch_cpe_bt5, - .mcePatchFxn = &rf_patch_mce_bt5, - .rfePatchFxn = &rf_patch_rfe_bt5, + .rfMode = RF_MODE_AUTO, + .cpePatchFxn = &rf_patch_cpe_bt5, + .mcePatchFxn = &rf_patch_mce_bt5, + .rfePatchFxn = &rf_patch_rfe_bt5, }; - -// TX Power table -// The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: -// RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) -// See the Technical Reference Manual for further details about the "txPower" Command field. -// The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. -RF_TxPowerTable_Entry txPowerTable[TX_POWER_TABLE_SIZE] = -{ - {-21, RF_TxPowerTable_DEFAULT_PA_ENTRY(7, 3, 0, 3) }, - {-18, RF_TxPowerTable_DEFAULT_PA_ENTRY(9, 3, 0, 3) }, - {-15, RF_TxPowerTable_DEFAULT_PA_ENTRY(8, 2, 0, 6) }, - {-12, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 2, 0, 8) }, - {-10, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 11) }, - {-9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 2, 0, 5) }, - {-6, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 16) }, - {-5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 17) }, - {-3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 1, 0, 20) }, - {0, RF_TxPowerTable_DEFAULT_PA_ENTRY(25, 1, 0, 26) }, - {1, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 1, 0, 28) }, - {2, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 0, 0, 34) }, - {3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 0, 0, 42) }, - {4, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 0, 0, 54) }, - {5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, - RF_TxPowerTable_TERMINATION_ENTRY -}; - - -// Overrides for CMD_BLE5_RADIO_SETUP -uint32_t pOverridesCommon[] = +/*---------------------------------------------------------------------------*/ +/* + * TX Power table + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +RF_TxPowerTable_Entry rf_ble_tx_power_table[RF_BLE_TX_POWER_TABLE_SIZE+1] = { - // override_ble5_setup_override_common.xml - // Synth: Use 48 MHz crystal, enable extra PLL filtering - (uint32_t)0x02400403, - // Synth: Configure extra PLL filtering - (uint32_t)0x001C8473, - // Synth: Configure synth hardware - (uint32_t)0x00088433, - // Synth: Set minimum RTRIM to 3 - (uint32_t)0x00038793, - // Synth: Configure faster calibration - HW32_ARRAY_OVERRIDE(0x4004,1), - // Synth: Configure faster calibration - (uint32_t)0x1C0C0618, - // Synth: Configure faster calibration - (uint32_t)0xC00401A1, - // Synth: Configure faster calibration - (uint32_t)0x00010101, - // Synth: Configure faster calibration - (uint32_t)0xC0040141, - // Synth: Configure faster calibration - (uint32_t)0x00214AD3, - // Synth: Decrease synth programming time-out (0x0298 RAT ticks = 166 us) - (uint32_t)0x02980243, - // DC/DC regulator: In Tx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). - (uint32_t)0xFCFC08C3, - // Rx: Set LNA bias current offset to adjust +3 (default: 0) - (uint32_t)0x00038883, - // Rx: Set RSSI offset to adjust reported RSSI by -2 dB (default: 0) - (uint32_t)0x000288A3, - // Bluetooth 5: Compensate for reduced pilot tone length - (uint32_t)0x01080263, - // Bluetooth 5: Compensate for reduced pilot tone length - (uint32_t)0x08E90AA3, - // Bluetooth 5: Compensate for reduced pilot tone length - (uint32_t)0x00068BA3, - // Bluetooth 5: Set correct total clock accuracy for received AuxPtr assuming local sleep clock of 50 ppm - (uint32_t)0x0E490C83, - // override_frontend_id.xml - (uint32_t)0xFFFFFFFF, + { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 3) }, + { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 3) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 2, 0, 6) }, + { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 2, 0, 8) }, + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 11) }, + { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 2, 0, 5) }, + { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 16) }, + { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 17) }, + { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 1, 0, 20) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(25, 1, 0, 26) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 1, 0, 28) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 0, 0, 34) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 0, 0, 42) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 0, 0, 54) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, + RF_TxPowerTable_TERMINATION_ENTRY }; - - -// Overrides for CMD_BLE5_RADIO_SETUP -uint32_t pOverrides1Mbps[] = +/*---------------------------------------------------------------------------*/ +/* Overrides for CMD_BLE5_RADIO_SETUP */ +uint32_t rf_ble_overrides_common[] CC_ALIGN(4) = { - // override_ble5_setup_override_1mbps.xml - // PHY: Use MCE RAM patch (mode 0), RFE RAM patch (mode 0) - MCE_RFE_OVERRIDE(1,0,0,1,0,0), - // Bluetooth 5: Reduce pilot tone length - HW_REG_OVERRIDE(0x5320,0x0240), - // Bluetooth 5: Compensate for reduced pilot tone length - (uint32_t)0x013302A3, - (uint32_t)0xFFFFFFFF, + /* override_ble5_setup_override_common.xml */ + (uint32_t)0x02400403, /* Synth: Use 48 MHz crystal, enable extra PLL filtering */ + (uint32_t)0x001C8473, /* Synth: Configure extra PLL filtering */ + (uint32_t)0x00088433, /* Synth: Configure synth hardware */ + (uint32_t)0x00038793, /* Synth: Set minimum RTRIM to 3 */ + HW32_ARRAY_OVERRIDE(0x4004,1), /* Synth: Configure faster calibration */ + (uint32_t)0x1C0C0618, /* Synth: Configure faster calibration */ + (uint32_t)0xC00401A1, /* Synth: Configure faster calibration */ + (uint32_t)0x00010101, /* Synth: Configure faster calibration */ + (uint32_t)0xC0040141, /* Synth: Configure faster calibration */ + (uint32_t)0x00214AD3, /* Synth: Configure faster calibration */ + (uint32_t)0x02980243, /* Synth: Decrease synth programming time-out (0x0298 RAT ticks = 166 us) */ + /* DC/DC regulator: */ + /* In Tx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). */ + (uint32_t)0xFCFC08C3, /* In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). */ + (uint32_t)0x00038883, /* Rx: Set LNA bias current offset to adjust +3 (default: 0) */ + (uint32_t)0x000288A3, /* Rx: Set RSSI offset to adjust reported RSSI by -2 dB (default: 0) */ + (uint32_t)0x01080263, /* Bluetooth 5: Compensate for reduced pilot tone length */ + (uint32_t)0x08E90AA3, /* Bluetooth 5: Compensate for reduced pilot tone length */ + (uint32_t)0x00068BA3, /* Bluetooth 5: Compensate for reduced pilot tone length */ + /* Bluetooth 5: Set correct total clock accuracy for received AuxPtr */ + (uint32_t)0x0E490C83, /* assuming local sleep clock of 50 ppm */ + (uint32_t)0xFFFFFFFF, }; - - -// Overrides for CMD_BLE5_RADIO_SETUP -uint32_t pOverrides2Mbps[] = +/*---------------------------------------------------------------------------*/ +/* Overrides for CMD_BLE5_RADIO_SETUP */ +uint32_t rf_ble_overrides_1mbps[] CC_ALIGN(4) = { - // override_ble5_setup_override_2mbps.xml - // PHY: Use MCE RAM patch (mode 2), RFE RAM patch (mode 2) - MCE_RFE_OVERRIDE(1,0,2,1,0,2), - // Bluetooth 5: Reduce pilot tone length - HW_REG_OVERRIDE(0x5320,0x0240), - // Bluetooth 5: Compensate for reduced pilot tone length - (uint32_t)0x00D102A3, - (uint32_t)0xFFFFFFFF, + /* override_ble5_setup_override_1mbps.xml */ + MCE_RFE_OVERRIDE(1,0,0,1,0,0), /* PHY: Use MCE RAM patch (mode 0), RFE RAM patch (mode 0) */ + HW_REG_OVERRIDE(0x5320,0x0240), /* Bluetooth 5: Reduce pilot tone length */ + (uint32_t)0x013302A3, /* Bluetooth 5: Compensate for reduced pilot tone length */ + (uint32_t)0xFFFFFFFF, }; - - -// Overrides for CMD_BLE5_RADIO_SETUP -uint32_t pOverridesCoded[] = +/*---------------------------------------------------------------------------*/ +/* Overrides for CMD_BLE5_RADIO_SETUP */ +uint32_t rf_ble_overrides_2mbps[] CC_ALIGN(4) = { - // override_ble5_setup_override_coded.xml - // PHY: Use MCE RAM patch (mode 1), RFE RAM patch (mode 1) - MCE_RFE_OVERRIDE(1,0,1,1,0,1), - // Bluetooth 5: Reduce pilot tone length - HW_REG_OVERRIDE(0x5320,0x0240), - // Bluetooth 5: Compensate for reduced pilot tone length - (uint32_t)0x078902A3, - (uint32_t)0xFFFFFFFF, + /* override_ble5_setup_override_2mbps.xml */ + MCE_RFE_OVERRIDE(1,0,2,1,0,2), /* PHY: Use MCE RAM patch (mode 2), RFE RAM patch (mode 2) */ + HW_REG_OVERRIDE(0x5320,0x0240), /* Bluetooth 5: Reduce pilot tone length */ + (uint32_t)0x00D102A3, /* Bluetooth 5: Compensate for reduced pilot tone length */ + (uint32_t)0xFFFFFFFF, }; - - -// CMD_BLE5_RADIO_SETUP -// Bluetooth 5 Radio Setup Command for all PHYs +/*---------------------------------------------------------------------------*/ +/* Overrides for CMD_BLE5_RADIO_SETUP */ +uint32_t rf_ble_overrides_coded[] CC_ALIGN(4) = +{ + /* override_ble5_setup_override_coded.xml */ + MCE_RFE_OVERRIDE(1,0,1,1,0,1), /* PHY: Use MCE RAM patch (mode 1), RFE RAM patch (mode 1) */ + HW_REG_OVERRIDE(0x5320,0x0240), /* Bluetooth 5: Reduce pilot tone length */ + (uint32_t)0x078902A3, /* Bluetooth 5: Compensate for reduced pilot tone length */ + (uint32_t)0xFFFFFFFF, +}; +/*---------------------------------------------------------------------------*/ +/* CMD_BLE5_RADIO_SETUP: Bluetooth 5 Radio Setup Command for all PHYs */ rfc_CMD_BLE5_RADIO_SETUP_t RF_cmdBle5RadioSetup = { - .commandNo = 0x1820, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .defaultPhy.mainMode = 0x0, - .defaultPhy.coding = 0x0, - .loDivider = 0x00, - .config.frontEndMode = 0x0, - .config.biasMode = 0x0, - .config.analogCfgMode = 0x0, - .config.bNoFsPowerUp = 0x0, - .txPower = 0x941E, - .pRegOverrideCommon = pOverridesCommon, - .pRegOverride1Mbps = pOverrides1Mbps, - .pRegOverride2Mbps = pOverrides2Mbps, - .pRegOverrideCoded = pOverridesCoded, + .commandNo = CMD_BLE5_RADIO_SETUP, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .defaultPhy.mainMode = 0x0, + .defaultPhy.coding = 0x0, + .loDivider = 0x00, + .config.frontEndMode = 0x0, + .config.biasMode = 0x0, + .config.analogCfgMode = 0x0, + .config.bNoFsPowerUp = 0x0, + .txPower = 0x941E, + .pRegOverrideCommon = rf_ble_overrides_common, + .pRegOverride1Mbps = rf_ble_overrides_1mbps, + .pRegOverride2Mbps = rf_ble_overrides_2mbps, + .pRegOverrideCoded = rf_ble_overrides_coded, }; - -// CMD_FS -// Frequency Synthesizer Programming Command -rfc_CMD_FS_t RF_cmdFs = +/*---------------------------------------------------------------------------*/ +/* Structure for CMD_BLE5_ADV_AUX.pParams */ +rfc_ble5AdvAuxPar_t rf_ble5_adv_aux_par = { - .commandNo = 0x0803, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .frequency = 0x0988, - .fractFreq = 0x0000, - .synthConf.bTxMode = 0x0, - .synthConf.refFreq = 0x0, - .__dummy0 = 0x00, - .__dummy1 = 0x00, - .__dummy2 = 0x00, - .__dummy3 = 0x0000, + .pRxQ = 0, + .rxConfig.bAutoFlushIgnored = 0x0, + .rxConfig.bAutoFlushCrcErr = 0x0, + .rxConfig.bAutoFlushEmpty = 0x0, + .rxConfig.bIncludeLenByte = 0x0, + .rxConfig.bIncludeCrc = 0x0, + .rxConfig.bAppendRssi = 0x0, + .rxConfig.bAppendStatus = 0x0, + .rxConfig.bAppendTimestamp = 0x0, + .advConfig.advFilterPolicy = 0x0, + .advConfig.deviceAddrType = 0x0, + .advConfig.targetAddrType = 0x0, + .advConfig.bStrictLenFilter = 0x0, + .advConfig.bDirected = 0x0, + .advConfig.privIgnMode = 0x0, + .advConfig.rpaMode = 0x0, + .__dummy0 = 0x00, + .auxPtrTargetType = 0x00, + .auxPtrTargetTime = 0x00000000, + .pAdvPkt = 0, + .pRspPkt = 0, + .pDeviceAddress = 0, + .pWhiteList = 0, }; - -// Structure for CMD_BLE5_ADV_AUX.pParams -rfc_ble5AdvAuxPar_t ble5AdvAuxPar = +/*---------------------------------------------------------------------------*/ +/* CMD_BLE5_ADV_AUX: Bluetooth 5 Secondary Channel Advertiser Command */ +rfc_CMD_BLE5_ADV_AUX_t rf_cmd_ble5_adv_aux = { - .pRxQ = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx - .rxConfig.bAutoFlushIgnored = 0x0, - .rxConfig.bAutoFlushCrcErr = 0x0, - .rxConfig.bAutoFlushEmpty = 0x0, - .rxConfig.bIncludeLenByte = 0x0, - .rxConfig.bIncludeCrc = 0x0, - .rxConfig.bAppendRssi = 0x0, - .rxConfig.bAppendStatus = 0x0, - .rxConfig.bAppendTimestamp = 0x0, - .advConfig.advFilterPolicy = 0x0, - .advConfig.deviceAddrType = 0x0, - .advConfig.targetAddrType = 0x0, - .advConfig.bStrictLenFilter = 0x0, - .advConfig.bDirected = 0x0, - .advConfig.privIgnMode = 0x0, - .advConfig.rpaMode = 0x0, - .__dummy0 = 0x00, - .auxPtrTargetType = 0x00, - .auxPtrTargetTime = 0x00000000, - .pAdvPkt = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .pRspPkt = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .pDeviceAddress = 0, // INSERT APPLICABLE POINTER: (uint16_t*)&xxx - .pWhiteList = 0, // INSERT APPLICABLE POINTER: (uint32_t*)&xxx -}; - -// CMD_BLE5_ADV_AUX -// Bluetooth 5 Secondary Channel Advertiser Command -rfc_CMD_BLE5_ADV_AUX_t RF_cmdBle5AdvAux = -{ - .commandNo = 0x1824, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .channel = 0x8C, - .whitening.init = 0x51, - .whitening.bOverride = 0x1, - .phyMode.mainMode = 0x0, - .phyMode.coding = 0x0, - .rangeDelay = 0x00, - .txPower = 0x0000, - .pParams = &ble5AdvAuxPar, - .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .tx20Power = 0x00000000, -}; - -// Structure for CMD_BLE5_GENERIC_RX.pParams -rfc_bleGenericRxPar_t bleGenericRxPar = -{ - .pRxQ = 0, // INSERT APPLICABLE POINTER: (dataQueue_t*)&xxx - .rxConfig.bAutoFlushIgnored = 0x0, - .rxConfig.bAutoFlushCrcErr = 0x0, - .rxConfig.bAutoFlushEmpty = 0x0, - .rxConfig.bIncludeLenByte = 0x1, - .rxConfig.bIncludeCrc = 0x1, - .rxConfig.bAppendRssi = 0x1, - .rxConfig.bAppendStatus = 0x1, - .rxConfig.bAppendTimestamp = 0x0, - .bRepeat = 0x01, - .__dummy0 = 0x0000, - .accessAddress = 0x8E89BED6, - .crcInit0 = 0x55, - .crcInit1 = 0x55, - .crcInit2 = 0x55, - .endTrigger.triggerType = 0x1, - .endTrigger.bEnaCmd = 0x0, - .endTrigger.triggerNo = 0x0, - .endTrigger.pastTrig = 0x0, - .endTime = 0x00000001, -}; - -// CMD_BLE5_GENERIC_RX -// Bluetooth 5 Generic Receiver Command -rfc_CMD_BLE5_GENERIC_RX_t RF_cmdBle5GenericRx = -{ - .commandNo = 0x1829, - .status = 0x0000, - .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, - .condition.nSkip = 0x0, - .channel = 0x8C, - .whitening.init = 0x51, - .whitening.bOverride = 0x1, - .phyMode.mainMode = 0x0, - .phyMode.coding = 0x0, - .rangeDelay = 0x00, - .txPower = 0x0000, - .pParams = &bleGenericRxPar, - .pOutput = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx - .tx20Power = 0x00000000, + .commandNo = CMD_BLE5_ADV_AUX, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .channel = 0x8C, + .whitening.init = 0x51, + .whitening.bOverride = 0x1, + .phyMode.mainMode = 0x0, + .phyMode.coding = 0x0, + .rangeDelay = 0x00, + .txPower = 0x0000, + .pParams = &rf_ble5_adv_aux_par, + .pOutput = 0, + .tx20Power = 0x00000000, }; +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.h index 4cf6518d6..81b4a0fea 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.h @@ -1,44 +1,62 @@ -#ifndef _BLE-SETTINGS_H_ -#define _BLE-SETTINGS_H_ - -//********************************************************************************* -// Generated by SmartRF Studio version 2.10.0 (build#106) -// Compatible with SimpleLink SDK version: CC26x2 SDK 2.20.xx.xx -// Device: CC2652R Rev. 1.1 (Rev. C) -// -//********************************************************************************* +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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 BLE_SETTINGS_H_ +#define BLE_SETTINGS_H_ +/*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) #include DeviceFamily_constructPath(driverlib/rf_ble_cmd.h) + #include +/*---------------------------------------------------------------------------*/ +/* TX Power table size definition */ +#define RF_BLE_TX_POWER_TABLE_SIZE 15 - -// TX Power table size definition -#define TX_POWER_TABLE_SIZE 16 - - -// TX Power Table Object -extern RF_TxPowerTable_Entry txPowerTable[TX_POWER_TABLE_SIZE]; - - -// TI-RTOS RF Mode Object -extern RF_Mode RF_prop; - - -// RF Core API commands -extern rfc_CMD_BLE5_RADIO_SETUP_t RF_cmdBle5RadioSetup; -extern rfc_CMD_FS_t RF_cmdFs; -extern rfc_CMD_BLE5_ADV_AUX_t RF_cmdBle5AdvAux; -extern rfc_CMD_BLE5_GENERIC_RX_t RF_cmdBle5GenericRx; - - -// RF Core API Overrides -extern uint32_t pOverridesCommon[]; -extern uint32_t pOverrides1Mbps[]; -extern uint32_t pOverrides2Mbps[]; -extern uint32_t pOverridesCoded[]; - - -#endif // _BLE-SETTINGS_H_ - +/* TX Power Table Object */ +extern RF_TxPowerTable_Entry rf_ble_tx_power_table[RF_BLE_TX_POWER_TABLE_SIZE+1]; +/*---------------------------------------------------------------------------*/ +/* TI-RTOS RF Mode Object */ +extern RF_Mode rf_ble_mode; +/*---------------------------------------------------------------------------*/ +/* RF Core API commands */ +extern rfc_CMD_BLE5_RADIO_SETUP_t rf_cmd_ble5_radio_setup; +extern rfc_ble5AdvAuxPar_t rf_ble5_adv_aux_par; +extern rfc_CMD_BLE5_ADV_AUX_t rf_cmd_ble5_adv_aux; +/*---------------------------------------------------------------------------*/ +/* RF Core API Overrides */ +extern uint32_t rf_ble_overrides_common[]; +extern uint32_t rf_ble_overrides_1mbps[]; +extern uint32_t rf_ble_overrides_2mbps[]; +extern uint32_t rf_ble_overrides_coded[]; +/*---------------------------------------------------------------------------*/ +#endif /* BLE_SETTINGS_H_ */ +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c index 17c9b686f..3f6d4f7ed 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c @@ -28,13 +28,15 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /*---------------------------------------------------------------------------*/ -// Parameter summary -// IEEE Channel: 11 -// Frequency: 2405 MHz -// SFD: 0 -// Packet Data: 255 -// Preamble (32 bit): 01010101... -// TX Power: 5 dBm +/* + * Parameter summary + * IEEE Channel: 11 + * Frequency: 2405 MHz + * SFD: 0 + * Packet Data: 255 + * Preamble (32 bit): 01010101... + * TX Power: 5 dBm + */ /*---------------------------------------------------------------------------*/ #include "sys/cc.h" /*---------------------------------------------------------------------------*/ @@ -49,218 +51,217 @@ /*---------------------------------------------------------------------------*/ #include "ieee-settings.h" /*---------------------------------------------------------------------------*/ -// TI-RTOS RF Mode Object +/* TI-RTOS RF Mode Object */ RF_Mode rf_ieee_mode = { - .rfMode = RF_MODE_AUTO, - .cpePatchFxn = &rf_patch_cpe_ieee_802_15_4, - .mcePatchFxn = &rf_patch_mce_ieee_802_15_4, - .rfePatchFxn = 0, + .rfMode = RF_MODE_AUTO, + .cpePatchFxn = &rf_patch_cpe_ieee_802_15_4, + .mcePatchFxn = &rf_patch_mce_ieee_802_15_4, + .rfePatchFxn = 0, }; /*---------------------------------------------------------------------------*/ -// TX Power table -// The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: -// RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) -// See the Technical Reference Manual for further details about the "txPower" Command field. -// The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. +/* + * TX Power table + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ RF_TxPowerTable_Entry rf_ieee_tx_power_table[RF_IEEE_TX_POWER_TABLE_SIZE+1] = { - { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY(7, 3, 0, 3) }, - { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY(9, 3, 0, 3) }, - { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 100) }, - { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(40, 2, 0, 8) }, - { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 11) }, - { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 2, 0, 5) }, - { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 16) }, - { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 17) }, - { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 1, 0, 20) }, - { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(25, 1, 0, 26) }, - { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 1, 0, 28) }, - { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 0, 0, 34) }, - { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 0, 0, 42) }, - { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 0, 0, 54) }, - { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, - RF_TxPowerTable_TERMINATION_ENTRY + { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY(7, 3, 0, 3) }, + { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY(9, 3, 0, 3) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 100) }, + { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(40, 2, 0, 8) }, + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 11) }, + { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 2, 0, 5) }, + { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 16) }, + { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 17) }, + { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 1, 0, 20) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(25, 1, 0, 26) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 1, 0, 28) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 0, 0, 34) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 0, 0, 42) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 0, 0, 54) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, + RF_TxPowerTable_TERMINATION_ENTRY }; /*---------------------------------------------------------------------------*/ -// Overrides for CMD_RADIO_SETUP +/* Overrides for CMD_RADIO_SETUP */ uint32_t rf_ieee_overrides[] CC_ALIGN(4) = { - // override_ieee_802_15_4.xml - MCE_RFE_OVERRIDE(1,0,0,0,1,0), // PHY: Use MCE RAM patch, RFE ROM bank 1 - (uint32_t)0x02400403, // Synth: Use 48 MHz crystal, enable extra PLL filtering - (uint32_t)0x001C8473, // Synth: Configure extra PLL filtering - (uint32_t)0x00088433, // Synth: Configure synth hardware - (uint32_t)0x00038793, // Synth: Set minimum RTRIM to 3 - HW32_ARRAY_OVERRIDE(0x4004,1), // Synth: Configure faster calibration - (uint32_t)0x1C0C0618, // Synth: Configure faster calibration - (uint32_t)0xC00401A1, // Synth: Configure faster calibration - (uint32_t)0x00010101, // Synth: Configure faster calibration - (uint32_t)0xC0040141, // Synth: Configure faster calibration - (uint32_t)0x00214AD3, // Synth: Configure faster calibration - (uint32_t)0x02980243, // Synth: Decrease synth programming time-out (0x0298 RAT ticks = 166 us) - (uint32_t)0xFCFC08C3, // DC/DC regulator: In Tx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). - (uint32_t)0x000F8883, // Rx: Set LNA bias current offset to +15 to saturate trim to max (default: 0) - (uint32_t)0xFFFFFFFF, + /* override_ieee_802_15_4.xml */ + MCE_RFE_OVERRIDE(1,0,0,0,1,0), /* PHY: Use MCE RAM patch, RFE ROM bank 1 */ + (uint32_t)0x02400403, /* Synth: Use 48 MHz crystal, enable extra PLL filtering */ + (uint32_t)0x001C8473, /* Synth: Configure extra PLL filtering */ + (uint32_t)0x00088433, /* Synth: Configure synth hardware */ + (uint32_t)0x00038793, /* Synth: Set minimum RTRIM to 3 */ + HW32_ARRAY_OVERRIDE(0x4004,1), /* Synth: Configure faster calibration */ + (uint32_t)0x1C0C0618, /* Synth: Configure faster calibration */ + (uint32_t)0xC00401A1, /* Synth: Configure faster calibration */ + (uint32_t)0x00010101, /* Synth: Configure faster calibration */ + (uint32_t)0xC0040141, /* Synth: Configure faster calibration */ + (uint32_t)0x00214AD3, /* Synth: Configure faster calibration */ + (uint32_t)0x02980243, /* Synth: Decrease synth programming time-out (0x0298 RAT ticks = 166 us) */ + /* DC/DC regulator: */ + /* In Tx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). */ + (uint32_t)0xFCFC08C3, /* In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). */ + (uint32_t)0x000F8883, /* Rx: Set LNA bias current offset to +15 to saturate trim to max (default: 0) */ + (uint32_t)0xFFFFFFFF, }; /*---------------------------------------------------------------------------*/ -// CMD_RADIO_SETUP -// Radio Setup Command for Pre-Defined Schemes +/* CMD_RADIO_SETUP: Radio Setup Command for Pre-Defined Schemes */ rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup = { - .commandNo = CMD_RADIO_SETUP, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .mode = 0x01, - .loDivider = 0x00, - .config.frontEndMode = 0x0, - .config.biasMode = 0x1, - .config.analogCfgMode = 0x0, - .config.bNoFsPowerUp = 0x0, - .txPower = 0x941E, /* 5 dBm default */ - .pRegOverride = rf_ieee_overrides, + .commandNo = CMD_RADIO_SETUP, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .mode = 0x01, + .loDivider = 0x00, + .config.frontEndMode = 0x0, + .config.biasMode = 0x1, + .config.analogCfgMode = 0x0, + .config.bNoFsPowerUp = 0x0, + .txPower = 0x941E, /* 5 dBm default */ + .pRegOverride = rf_ieee_overrides, }; /*---------------------------------------------------------------------------*/ -// CMD_FS -// Frequency Synthesizer Programming Command +/* CMD_FS: Frequency Synthesizer Programming Command */ rfc_CMD_FS_t rf_cmd_ieee_fs = { - .commandNo = CMD_FS, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .frequency = 0x0965, /* set by driver */ - .fractFreq = 0x0000, /* set by driver */ - .synthConf.bTxMode = 0x1, - .synthConf.refFreq = 0x0, - .__dummy0 = 0x00, - .__dummy1 = 0x00, - .__dummy2 = 0x00, - .__dummy3 = 0x0000, + .commandNo = CMD_FS, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .frequency = 0x0965, /* set by driver */ + .fractFreq = 0x0000, /* set by driver */ + .synthConf.bTxMode = 0x1, + .synthConf.refFreq = 0x0, + .__dummy0 = 0x00, + .__dummy1 = 0x00, + .__dummy2 = 0x00, + .__dummy3 = 0x0000, }; /*---------------------------------------------------------------------------*/ -// CMD_IEEE_TX -// IEEE 802.15.4 Transmit Command +/* CMD_IEEE_TX: IEEE 802.15.4 Transmit Command */ rfc_CMD_IEEE_TX_t rf_cmd_ieee_tx = { - .commandNo = CMD_IEEE_TX, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .txOpt.bIncludePhyHdr = 0x0, - .txOpt.bIncludeCrc = 0x0, - .txOpt.payloadLenMsb = 0x0, - .payloadLen = 0x0, /* set by driver */ - .pPayload = 0, /* set by driver */ - .timeStamp = 0x00000000, + .commandNo = CMD_IEEE_TX, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .txOpt.bIncludePhyHdr = 0x0, + .txOpt.bIncludeCrc = 0x0, + .txOpt.payloadLenMsb = 0x0, + .payloadLen = 0x0, /* set by driver */ + .pPayload = 0, /* set by driver */ + .timeStamp = 0x00000000, }; /*---------------------------------------------------------------------------*/ -// CMD_IEEE_RX -// IEEE 802.15.4 Receive Command +/* CMD_IEEE_RX: IEEE 802.15.4 Receive Command */ rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx = { - .commandNo = CMD_IEEE_RX, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .channel = 0x00, /* set by driver */ - .rxConfig.bAutoFlushCrc = 0x1, - .rxConfig.bAutoFlushIgn = 0x0, - .rxConfig.bIncludePhyHdr = 0x0, - .rxConfig.bIncludeCrc = 0x1, - .rxConfig.bAppendRssi = 0x1, - .rxConfig.bAppendCorrCrc = 0x1, - .rxConfig.bAppendSrcInd = 0x0, - .rxConfig.bAppendTimestamp = 0x1, - .pRxQ = 0, /* set by driver */ - .pOutput = 0, /* set by driver */ - .frameFiltOpt.frameFiltEn = 0x0, /* set by driver */ - .frameFiltOpt.frameFiltStop = 0x1, - .frameFiltOpt.autoAckEn = 0x0, /* set by driver */ - .frameFiltOpt.slottedAckEn = 0x0, - .frameFiltOpt.autoPendEn = 0x0, - .frameFiltOpt.defaultPend = 0x0, - .frameFiltOpt.bPendDataReqOnly = 0x0, - .frameFiltOpt.bPanCoord = 0x0, - .frameFiltOpt.maxFrameVersion = 0x2, - .frameFiltOpt.fcfReservedMask = 0x0, - .frameFiltOpt.modifyFtFilter = 0x0, - .frameFiltOpt.bStrictLenFilter = 0x0, - .frameTypes.bAcceptFt0Beacon = 0x1, - .frameTypes.bAcceptFt1Data = 0x1, - .frameTypes.bAcceptFt2Ack = 0x1, - .frameTypes.bAcceptFt3MacCmd = 0x1, - .frameTypes.bAcceptFt4Reserved = 0x1, - .frameTypes.bAcceptFt5Reserved = 0x1, - .frameTypes.bAcceptFt6Reserved = 0x1, - .frameTypes.bAcceptFt7Reserved = 0x1, - .ccaOpt.ccaEnEnergy = 0x1, - .ccaOpt.ccaEnCorr = 0x1, - .ccaOpt.ccaEnSync = 0x1, - .ccaOpt.ccaCorrOp = 0x1, - .ccaOpt.ccaSyncOp = 0x0, - .ccaOpt.ccaCorrThr = 0x3, - .ccaRssiThr = 0x0, /* set by driver */ - .__dummy0 = 0x00, - .numExtEntries = 0x00, - .numShortEntries = 0x00, - .pExtEntryList = 0, - .pShortEntryList = 0, - .localExtAddr = 0x0, /* set by driver */ - .localShortAddr = 0x0, /* set by driver */ - .localPanID = 0x0000, - .__dummy1 = 0x000000, - .endTrigger.triggerType = TRIG_NEVER, - .endTrigger.bEnaCmd = 0x0, - .endTrigger.triggerNo = 0x0, - .endTrigger.pastTrig = 0x0, - .endTime = 0x00000000, + .commandNo = CMD_IEEE_RX, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .channel = 0x00, /* set by driver */ + .rxConfig.bAutoFlushCrc = 0x1, + .rxConfig.bAutoFlushIgn = 0x0, + .rxConfig.bIncludePhyHdr = 0x0, + .rxConfig.bIncludeCrc = 0x1, + .rxConfig.bAppendRssi = 0x1, + .rxConfig.bAppendCorrCrc = 0x1, + .rxConfig.bAppendSrcInd = 0x0, + .rxConfig.bAppendTimestamp = 0x1, + .pRxQ = 0, /* set by driver */ + .pOutput = 0, /* set by driver */ + .frameFiltOpt.frameFiltEn = 0x0, /* set by driver */ + .frameFiltOpt.frameFiltStop = 0x1, + .frameFiltOpt.autoAckEn = 0x0, /* set by driver */ + .frameFiltOpt.slottedAckEn = 0x0, + .frameFiltOpt.autoPendEn = 0x0, + .frameFiltOpt.defaultPend = 0x0, + .frameFiltOpt.bPendDataReqOnly = 0x0, + .frameFiltOpt.bPanCoord = 0x0, + .frameFiltOpt.maxFrameVersion = 0x2, + .frameFiltOpt.fcfReservedMask = 0x0, + .frameFiltOpt.modifyFtFilter = 0x0, + .frameFiltOpt.bStrictLenFilter = 0x0, + .frameTypes.bAcceptFt0Beacon = 0x1, + .frameTypes.bAcceptFt1Data = 0x1, + .frameTypes.bAcceptFt2Ack = 0x1, + .frameTypes.bAcceptFt3MacCmd = 0x1, + .frameTypes.bAcceptFt4Reserved = 0x1, + .frameTypes.bAcceptFt5Reserved = 0x1, + .frameTypes.bAcceptFt6Reserved = 0x1, + .frameTypes.bAcceptFt7Reserved = 0x1, + .ccaOpt.ccaEnEnergy = 0x1, + .ccaOpt.ccaEnCorr = 0x1, + .ccaOpt.ccaEnSync = 0x1, + .ccaOpt.ccaCorrOp = 0x1, + .ccaOpt.ccaSyncOp = 0x0, + .ccaOpt.ccaCorrThr = 0x3, + .ccaRssiThr = 0x0, /* set by driver */ + .__dummy0 = 0x00, + .numExtEntries = 0x00, + .numShortEntries = 0x00, + .pExtEntryList = 0, + .pShortEntryList = 0, + .localExtAddr = 0x0, /* set by driver */ + .localShortAddr = 0x0, /* set by driver */ + .localPanID = 0x0000, + .__dummy1 = 0x000000, + .endTrigger.triggerType = TRIG_NEVER, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, }; /*---------------------------------------------------------------------------*/ -// CMD_IEEE_RX_ACK -// IEEE 802.15.4 Receive ACK Command +/* CMD_IEEE_RX_ACK: IEEE 802.15.4 Receive ACK Command */ rfc_CMD_IEEE_RX_ACK_t rf_cmd_ieee_rx_ack = { - .commandNo = CMD_IEEE_RX_ACK, - .status = IDLE, - .pNextOp = 0, - .startTime = 0x00000000, - .startTrigger.triggerType = TRIG_NOW, - .startTrigger.bEnaCmd = 0x0, - .startTrigger.triggerNo = 0x0, - .startTrigger.pastTrig = 0x0, - .condition.rule = COND_NEVER, - .condition.nSkip = 0x0, - .seqNo = 0x0, - .endTrigger.triggerType = TRIG_NEVER, - .endTrigger.bEnaCmd = 0x0, - .endTrigger.triggerNo = 0x0, - .endTrigger.pastTrig = 0x0, - .endTime = 0x00000000, + .commandNo = CMD_IEEE_RX_ACK, + .status = IDLE, + .pNextOp = 0, + .startTime = 0x00000000, + .startTrigger.triggerType = TRIG_NOW, + .startTrigger.bEnaCmd = 0x0, + .startTrigger.triggerNo = 0x0, + .startTrigger.pastTrig = 0x0, + .condition.rule = COND_NEVER, + .condition.nSkip = 0x0, + .seqNo = 0x0, + .endTrigger.triggerType = TRIG_NEVER, + .endTrigger.bEnaCmd = 0x0, + .endTrigger.triggerNo = 0x0, + .endTrigger.pastTrig = 0x0, + .endTime = 0x00000000, }; /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h index 7572a36fd..d2f65aee5 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h @@ -39,22 +39,22 @@ #include /*---------------------------------------------------------------------------*/ -// TI-RTOS RF Mode Object +/* TI-RTOS RF Mode Object */ extern RF_Mode rf_ieee_mode; /*---------------------------------------------------------------------------*/ -// TX Power Table +/* TX Power Table */ #define RF_IEEE_TX_POWER_TABLE_SIZE 15 extern RF_TxPowerTable_Entry rf_ieee_tx_power_table[RF_IEEE_TX_POWER_TABLE_SIZE+1]; /*---------------------------------------------------------------------------*/ -// RF Core API commands +/* RF Core API commands */ extern rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup; extern rfc_CMD_FS_t rf_cmd_ieee_fs; extern rfc_CMD_IEEE_TX_t rf_cmd_ieee_tx; extern rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx; extern rfc_CMD_IEEE_RX_ACK_t rf_cmd_ieee_rx_ack; /*---------------------------------------------------------------------------*/ -// RF Core API Overrides +/* RF Core API Overrides */ extern uint32_t rf_ieee_overrides[]; /*---------------------------------------------------------------------------*/ #endif /* IEEE_SETTINGS_H_ */ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/netstack-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/netstack-settings.h index 16751b840..0da5aa33d 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/netstack-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/netstack-settings.h @@ -32,28 +32,35 @@ #define NETSTACK_SETTINGS_H_ /*---------------------------------------------------------------------------*/ #include "contiki.h" - +/*---------------------------------------------------------------------------*/ #include /*---------------------------------------------------------------------------*/ +/* Prop-mode RF settings configuration */ #ifdef RF_CORE_CONF_PROP_RF_SETTINGS -# define RF_CORE_PROP_RF_SETTINGS RF_CORE_CONF_PROP_RF_SETTINGS +# define RF_CORE_PROP_RF_SETTINGS RF_CORE_CONF_PROP_RF_SETTINGS #else -# define RF_CORE_PROP_RF_SETTINGS "prop-settings.h" +# define RF_CORE_PROP_RF_SETTINGS "prop-settings.h" #endif -#include RF_CORE_PROP_RF_SETTINGS - +/* IEEE-mode RF settings configuration */ #ifdef RF_CORE_CONF_IEEE_RF_SETTINGS -# define RF_CORE_IEEE_RF_SETTINGS RF_CORE_CONF_IEEE_RF_SETTINGS +# define RF_CORE_IEEE_RF_SETTINGS RF_CORE_CONF_IEEE_RF_SETTINGS #else -# define RF_CORE_IEEE_RF_SETTINGS "ieee-settings.h" +# define RF_CORE_IEEE_RF_SETTINGS "ieee-settings.h" #endif -#include RF_CORE_IEEE_RF_SETTINGS +/* BLE RF settings configuration */ +#ifdef RF_CORE_CONF_BLE_RF_SETTINGS +# define RF_CORE_BLE_RF_SETTINGS RF_CORE_CONF_BLE_RF_SETTINGS +#else +# define RF_CORE_BLE_RF_SETTINGS "ble-settings.h" +#endif /*---------------------------------------------------------------------------*/ /* Prop-mode RF settings */ #if (RF_CORE_CONF_MODE == RF_CORE_MODE_SUB_1_GHZ) +#include RF_CORE_PROP_RF_SETTINGS + #define netstack_mode rf_prop_mode #define netstack_cmd_radio_setup rf_cmd_prop_radio_div_setup #define netstack_cmd_fs rf_cmd_prop_fs @@ -63,6 +70,8 @@ /* IEEE-mode RF settings */ #elif (RF_CORE_CONF_MODE == RF_CORE_MODE_2_4_GHZ) +#include RF_CORE_IEEE_RF_SETTINGS + #define netstack_mode rf_ieee_mode #define netstack_cmd_radio_setup rf_cmd_ieee_radio_setup #define netstack_cmd_fs rf_cmd_ieee_fs @@ -73,7 +82,8 @@ # error "Unsupported RF_CORE_MODE" #endif /*---------------------------------------------------------------------------*/ -#include "ble-settings.h" +/* BLE RF settings */ +#include RF_CORE_BLE_RF_SETTINGS #if (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0) diff --git a/arch/platform/simplelink/cc13xx-cc26xx/platform.c b/arch/platform/simplelink/cc13xx-cc26xx/platform.c index 0c9accfa6..5a699bb34 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/platform.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/platform.c @@ -84,6 +84,7 @@ /*---------------------------------------------------------------------------*/ #include "ieee-addr.h" #include "rf-core.h" +#include "rf-ble-beacond.h" #include "lib/random.h" #include "button-sensor.h" /*---------------------------------------------------------------------------*/ @@ -202,6 +203,8 @@ platform_init_stage_two(void) void platform_init_stage_three(void) { + rf_ble_beacond_init(); + radio_value_t chan = 0, pan = 0; set_rf_params(); From c170a90976966d37a0bc0ddb6757879d0689c346 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Fri, 13 Jul 2018 14:34:08 +0200 Subject: [PATCH 267/485] Fixed RX buf full error --- arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 5 - .../cc13x0-cc26x0/cc13x0-cc26x0.lds | 129 +++++++++++------- .../cc13x2-cc26x2/cc13x2-cc26x2.lds | 123 ++++++++++------- arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h | 129 ++++++++++-------- arch/cpu/cc13xx-cc26xx/dev/rf-core.c | 21 ++- arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c | 1 + arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c | 15 +- .../rf-settings/cc13x0/prop-settings.h | 1 + .../rf-settings/cc13x2/prop-settings.h | 1 + 9 files changed, 254 insertions(+), 171 deletions(-) diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index c27795655..083bf3f88 100644 --- a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -103,11 +103,6 @@ CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES) $(DEBUG_IO_SOURCEFILES) LDFLAGS += --entry resetISR LDFLAGS += -static LDFLAGS += --specs=nano.specs -# NB! The symbol _stack, which points to the stack start, is expected to be defined, -# but should already be defined in the linker script. -LDFLAGS += -Wl,--defsym=_stack_origin=__stack_end -LDFLAGS += -Wl,--defsym=_heap=__heap_start__ -LDFLAGS += -Wl,--defsym=_eheap=__heap_end__ LDSCRIPT := $(CONTIKI_CPU)/$(SUBFAMILY)/$(SUBFAMILY).lds diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds index dd4732580..4d71d6b45 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds +++ b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.lds @@ -49,24 +49,25 @@ MEMORY GPRAM (RWX) : ORIGIN = 0x11000000, LENGTH = 0x00002000 } -REGION_ALIAS("REGION_TEXT", FLASH); -REGION_ALIAS("REGION_BSS", SRAM); -REGION_ALIAS("REGION_DATA", SRAM); -REGION_ALIAS("REGION_STACK", SRAM); -REGION_ALIAS("REGION_HEAP", SRAM); +REGION_ALIAS("REGION_TEXT", FLASH); +REGION_ALIAS("REGION_BSS", SRAM); +REGION_ALIAS("REGION_DATA", SRAM); +REGION_ALIAS("REGION_STACK", SRAM); +REGION_ALIAS("REGION_HEAP", SRAM); REGION_ALIAS("REGION_ARM_EXIDX", FLASH); REGION_ALIAS("REGION_ARM_EXTAB", FLASH); SECTIONS { - PROVIDE (_resetVecs_base_address = - DEFINED(_resetVecs_base_address) ? _resetVecs_base_address : 0x0); + PROVIDE (_resetVecs_base_addr = DEFINED(_resetVecs_base_addr) + ? _resetVecs_base_addr + : 0x0); - .resetVecs (_resetVecs_base_address) : AT (_resetVecs_base_address) { + .resetVecs (_resetVecs_base_addr) : AT (_resetVecs_base_addr) { KEEP (*(.resetVecs)) } > REGION_TEXT - .ramVecs (NOLOAD) : ALIGN(1024){ + .ramVecs (NOLOAD) : ALIGN(1024) { KEEP (*(.ramVecs)) } > REGION_DATA @@ -81,44 +82,61 @@ SECTIONS { /* * Define absolute addresses for the DMA channels. * DMA channels must always be allocated at a fixed offset from the DMA base address. + * CTEA := Control Table Entry Address * --------- DO NOT MODIFY ----------- */ - DMA_SPI0_RX_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x30); - DMA_SPI0_TX_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x40); - DMA_ADC_PRI_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x70); - DMA_GPT0A_PRI_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x90); - DMA_SPI1_RX_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x100); - DMA_SPI1_TX_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x110); - DMA_ADC_ALT_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x270); - DMA_GPT0A_ALT_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x290); + DMA_SPI0_RX_CTEA = (UDMACC26XX_CONFIG_BASE + 0x30); + DMA_SPI0_TX_CTEA = (UDMACC26XX_CONFIG_BASE + 0x40); + DMA_ADC_PRI_CTEA = (UDMACC26XX_CONFIG_BASE + 0x70); + DMA_GPT0A_PRI_CTEA = (UDMACC26XX_CONFIG_BASE + 0x90); + DMA_SPI1_RX_CTEA = (UDMACC26XX_CONFIG_BASE + 0x100); + DMA_SPI1_TX_CTEA = (UDMACC26XX_CONFIG_BASE + 0x110); + DMA_ADC_ALT_CTEA = (UDMACC26XX_CONFIG_BASE + 0x270); + DMA_GPT0A_ALT_CTEA = (UDMACC26XX_CONFIG_BASE + 0x290); /* * Allocate SPI0, SPI1, ADC, and GPTimer0 DMA descriptors at absolute addresses. * --------- DO NOT MODIFY ----------- */ UDMACC26XX_dmaSpi0RxControlTableEntry_is_placed = 0; - .dmaSpi0RxControlTableEntry DMA_SPI0_RX_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_SPI0_RX_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaSpi0RxControlTableEntry)} > REGION_DATA + .dmaSpi0RxControlTableEntry DMA_SPI0_RX_CTEA : AT (DMA_SPI0_RX_CTEA) { + *(.dmaSpi0RxControlTableEntry) + } > REGION_DATA UDMACC26XX_dmaSpi0TxControlTableEntry_is_placed = 0; - .dmaSpi0TxControlTableEntry DMA_SPI0_TX_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_SPI0_TX_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaSpi0TxControlTableEntry)} > REGION_DATA + .dmaSpi0TxControlTableEntry DMA_SPI0_TX_CTEA : AT (DMA_SPI0_TX_CTEA) { + *(.dmaSpi0TxControlTableEntry) + } > REGION_DATA UDMACC26XX_dmaADCPriControlTableEntry_is_placed = 0; - .dmaADCPriControlTableEntry DMA_ADC_PRI_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_ADC_PRI_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaADCPriControlTableEntry)} > REGION_DATA + .dmaADCPriControlTableEntry DMA_ADC_PRI_CTEA : AT (DMA_ADC_PRI_CTEA) { + *(.dmaADCPriControlTableEntry) + } > REGION_DATA UDMACC26XX_dmaGPT0APriControlTableEntry_is_placed = 0; - .dmaGPT0APriControlTableEntry DMA_GPT0A_PRI_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_GPT0A_PRI_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaGPT0APriControlTableEntry)} > REGION_DATA + .dmaGPT0APriControlTableEntry DMA_GPT0A_PRI_CTEA : AT (DMA_GPT0A_PRI_CTEA) { + *(.dmaGPT0APriControlTableEntry) + } > REGION_DATA UDMACC26XX_dmaSpi1RxControlTableEntry_is_placed = 0; - .dmaSpi1RxControlTableEntry DMA_SPI1_RX_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_SPI1_RX_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaSpi1RxControlTableEntry)} > REGION_DATA + .dmaSpi1RxControlTableEntry DMA_SPI1_RX_CTEA : AT (DMA_SPI1_RX_CTEA) { + *(.dmaSpi1RxControlTableEntry) + } > REGION_DATA UDMACC26XX_dmaSpi1TxControlTableEntry_is_placed = 0; - .dmaSpi1TxControlTableEntry DMA_SPI1_TX_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_SPI1_TX_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaSpi1TxControlTableEntry)} > REGION_DATA + .dmaSpi1TxControlTableEntry DMA_SPI1_TX_CTEA : AT (DMA_SPI1_TX_CTEA) { + *(.dmaSpi1TxControlTableEntry) + } > REGION_DATA UDMACC26XX_dmaADCAltControlTableEntry_is_placed = 0; - .dmaADCAltControlTableEntry DMA_ADC_ALT_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_ADC_ALT_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaADCAltControlTableEntry)} > REGION_DATA + .dmaADCAltControlTableEntry DMA_ADC_ALT_CTEA : AT (DMA_ADC_ALT_CTEA) { + *(.dmaADCAltControlTableEntry) + } > REGION_DATA UDMACC26XX_dmaGPT0AAltControlTableEntry_is_placed = 0; - .dmaGPT0AAltControlTableEntry DMA_GPT0A_ALT_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_GPT0A_ALT_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaGPT0AAltControlTableEntry)} > REGION_DATA + .dmaGPT0AAltControlTableEntry DMA_GPT0A_ALT_CTEA : AT (DMA_GPT0A_ALT_CTEA) { + *(.dmaGPT0AAltControlTableEntry) + } > REGION_DATA .text : { CREATE_OBJECT_SYMBOLS @@ -136,21 +154,21 @@ SECTIONS { *(.fini*) } > REGION_TEXT AT> REGION_TEXT - PROVIDE (__etext = .); - PROVIDE (_etext = .); - PROVIDE (etext = .); + PROVIDE(__etext = .); + PROVIDE(_etext = .); + PROVIDE(etext = .); .rodata : { *(.rodata) *(.rodata.*) } > REGION_TEXT AT> REGION_TEXT - .data : ALIGN(4) { - __data_load__ = LOADADDR (.data); + .data : ALIGN(0x4) { + __data_load__ = LOADADDR(.data); __data_start__ = .; *(.data) *(.data.*) - . = ALIGN (4); + . = ALIGN (0x4); __data_end__ = .; } > REGION_DATA AT> REGION_TEXT @@ -169,7 +187,7 @@ SECTIONS { } > REGION_TEXT .ccfg : { - KEEP (*(.ccfg)) + KEEP(*(.ccfg)) } > FLASH_CCFG AT> FLASH_CCFG .bss : { @@ -178,30 +196,41 @@ SECTIONS { *(.bss) *(.bss.*) *(COMMON) - . = ALIGN (4); + . = ALIGN(0x4); __bss_end__ = .; } > REGION_BSS AT> REGION_BSS - .heap : { - __heap_start__ = .; - end = __heap_start__; - _end = end; - __end = end; - . = . + HEAPSIZE; + /* Start of heap must be 4 byte aligned */ + .heap (NOLOAD) : ALIGN(0x4) { + PROVIDE(__heap_start__ = .); + PROVIDE(_heap = __heap_start__); + PROVIDE(end = __heap_start__); + PROVIDE(_end = __heap_start__); + PROVIDE(__end = __heap_start__); + + . += HEAPSIZE; KEEP(*(.heap)) - __heap_end__ = .; - __HeapLimit = __heap_end__; + + PROVIDE(__heap_end__ = .); + PROVIDE(_eheap = __heap_end__); + PROVIDE(__HeapLimit = __heap_end__); } > REGION_HEAP AT> REGION_HEAP - PROVIDE(STACKSIZE = ORIGIN(SRAM) + LENGTH(SRAM) - ALIGN(0x8)); + PROVIDE(__stack_size = ORIGIN(SRAM) + LENGTH(SRAM) - ALIGN(0x8)); - .stack (NOLOAD) : ALIGN(0x8) { - _stack = .; - __stack = .; - KEEP(*(.stack)) - . += STACKSIZE; - _stack_end = .; - __stack_end = .; - ASSERT(STACKSIZE >= MIN_STACKSIZE, "Error: No room left for the stack"); + /* Start of stack must be 8 byte aligned */ + .stack (NOLOAD) : { + PROVIDE(_stack = ALIGN(0x8)); + PROVIDE(__stack = _stack); + + PROVIDE(_stack_end = ORIGIN(SRAM) + LENGTH(SRAM)); + PROVIDE(__stack_end = _stack_end); + PROVIDE(_stack_origin = _stack_end); + + /* Note that the stack check library requires the symbols */ + /* "_stack" and "_stack_origin" to be defined. */ + + /* Assert that we have enough stack */ + ASSERT(__stack_size >= MIN_STACKSIZE, "Error: No room left for the stack"); } > REGION_STACK AT> REGION_STACK } diff --git a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds index cdfb619b2..d8699f651 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds +++ b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.lds @@ -49,24 +49,25 @@ MEMORY GPRAM (RWX) : ORIGIN = 0x11000000, LENGTH = 0x00002000 } -REGION_ALIAS("REGION_TEXT", FLASH); -REGION_ALIAS("REGION_BSS", SRAM); -REGION_ALIAS("REGION_DATA", SRAM); -REGION_ALIAS("REGION_STACK", SRAM); -REGION_ALIAS("REGION_HEAP", SRAM); +REGION_ALIAS("REGION_TEXT", FLASH); +REGION_ALIAS("REGION_BSS", SRAM); +REGION_ALIAS("REGION_DATA", SRAM); +REGION_ALIAS("REGION_STACK", SRAM); +REGION_ALIAS("REGION_HEAP", SRAM); REGION_ALIAS("REGION_ARM_EXIDX", FLASH); REGION_ALIAS("REGION_ARM_EXTAB", FLASH); SECTIONS { - PROVIDE (_resetVecs_base_address = - DEFINED(_resetVecs_base_address) ? _resetVecs_base_address : 0x0); + PROVIDE (_resetVecs_base_addr = DEFINED(_resetVecs_base_addr) + ? _resetVecs_base_addr + : 0x0); - .resetVecs (_resetVecs_base_address) : AT (_resetVecs_base_address) { + .resetVecs (_resetVecs_base_addr) : AT (_resetVecs_base_addr) { KEEP (*(.resetVecs)) } > REGION_TEXT - .ramVecs (NOLOAD) : ALIGN(1024){ + .ramVecs (NOLOAD) : ALIGN(1024) { KEEP (*(.ramVecs)) } > REGION_DATA @@ -81,44 +82,61 @@ SECTIONS { /* * Define absolute addresses for the DMA channels. * DMA channels must always be allocated at a fixed offset from the DMA base address. + * CTEA := Control Table Entry Address * --------- DO NOT MODIFY ----------- */ - DMA_SPI0_RX_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x30); - DMA_SPI0_TX_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x40); - DMA_ADC_PRI_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x70); - DMA_GPT0A_PRI_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x90); - DMA_SPI1_RX_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x100); - DMA_SPI1_TX_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x110); - DMA_ADC_ALT_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x270); - DMA_GPT0A_ALT_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x290); + DMA_SPI0_RX_CTEA = (UDMACC26XX_CONFIG_BASE + 0x30); + DMA_SPI0_TX_CTEA = (UDMACC26XX_CONFIG_BASE + 0x40); + DMA_ADC_PRI_CTEA = (UDMACC26XX_CONFIG_BASE + 0x70); + DMA_GPT0A_PRI_CTEA = (UDMACC26XX_CONFIG_BASE + 0x90); + DMA_SPI1_RX_CTEA = (UDMACC26XX_CONFIG_BASE + 0x100); + DMA_SPI1_TX_CTEA = (UDMACC26XX_CONFIG_BASE + 0x110); + DMA_ADC_ALT_CTEA = (UDMACC26XX_CONFIG_BASE + 0x270); + DMA_GPT0A_ALT_CTEA = (UDMACC26XX_CONFIG_BASE + 0x290); /* * Allocate SPI0, SPI1, ADC, and GPTimer0 DMA descriptors at absolute addresses. * --------- DO NOT MODIFY ----------- */ UDMACC26XX_dmaSpi0RxControlTableEntry_is_placed = 0; - .dmaSpi0RxControlTableEntry DMA_SPI0_RX_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_SPI0_RX_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaSpi0RxControlTableEntry)} > REGION_DATA + .dmaSpi0RxControlTableEntry DMA_SPI0_RX_CTEA : AT (DMA_SPI0_RX_CTEA) { + *(.dmaSpi0RxControlTableEntry) + } > REGION_DATA UDMACC26XX_dmaSpi0TxControlTableEntry_is_placed = 0; - .dmaSpi0TxControlTableEntry DMA_SPI0_TX_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_SPI0_TX_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaSpi0TxControlTableEntry)} > REGION_DATA + .dmaSpi0TxControlTableEntry DMA_SPI0_TX_CTEA : AT (DMA_SPI0_TX_CTEA) { + *(.dmaSpi0TxControlTableEntry) + } > REGION_DATA UDMACC26XX_dmaADCPriControlTableEntry_is_placed = 0; - .dmaADCPriControlTableEntry DMA_ADC_PRI_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_ADC_PRI_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaADCPriControlTableEntry)} > REGION_DATA + .dmaADCPriControlTableEntry DMA_ADC_PRI_CTEA : AT (DMA_ADC_PRI_CTEA) { + *(.dmaADCPriControlTableEntry) + } > REGION_DATA UDMACC26XX_dmaGPT0APriControlTableEntry_is_placed = 0; - .dmaGPT0APriControlTableEntry DMA_GPT0A_PRI_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_GPT0A_PRI_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaGPT0APriControlTableEntry)} > REGION_DATA + .dmaGPT0APriControlTableEntry DMA_GPT0A_PRI_CTEA : AT (DMA_GPT0A_PRI_CTEA) { + *(.dmaGPT0APriControlTableEntry) + } > REGION_DATA UDMACC26XX_dmaSpi1RxControlTableEntry_is_placed = 0; - .dmaSpi1RxControlTableEntry DMA_SPI1_RX_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_SPI1_RX_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaSpi1RxControlTableEntry)} > REGION_DATA + .dmaSpi1RxControlTableEntry DMA_SPI1_RX_CTEA : AT (DMA_SPI1_RX_CTEA) { + *(.dmaSpi1RxControlTableEntry) + } > REGION_DATA UDMACC26XX_dmaSpi1TxControlTableEntry_is_placed = 0; - .dmaSpi1TxControlTableEntry DMA_SPI1_TX_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_SPI1_TX_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaSpi1TxControlTableEntry)} > REGION_DATA + .dmaSpi1TxControlTableEntry DMA_SPI1_TX_CTEA : AT (DMA_SPI1_TX_CTEA) { + *(.dmaSpi1TxControlTableEntry) + } > REGION_DATA UDMACC26XX_dmaADCAltControlTableEntry_is_placed = 0; - .dmaADCAltControlTableEntry DMA_ADC_ALT_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_ADC_ALT_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaADCAltControlTableEntry)} > REGION_DATA + .dmaADCAltControlTableEntry DMA_ADC_ALT_CTEA : AT (DMA_ADC_ALT_CTEA) { + *(.dmaADCAltControlTableEntry) + } > REGION_DATA UDMACC26XX_dmaGPT0AAltControlTableEntry_is_placed = 0; - .dmaGPT0AAltControlTableEntry DMA_GPT0A_ALT_CONTROL_TABLE_ENTRY_ADDRESS : AT (DMA_GPT0A_ALT_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaGPT0AAltControlTableEntry)} > REGION_DATA + .dmaGPT0AAltControlTableEntry DMA_GPT0A_ALT_CTEA : AT (DMA_GPT0A_ALT_CTEA) { + *(.dmaGPT0AAltControlTableEntry) + } > REGION_DATA .text : { CREATE_OBJECT_SYMBOLS @@ -145,12 +163,12 @@ SECTIONS { *(.rodata.*) } > REGION_TEXT AT> REGION_TEXT - .data : ALIGN(4) { - __data_load__ = LOADADDR (.data); + .data : ALIGN(0x4) { + __data_load__ = LOADADDR(.data); __data_start__ = .; *(.data) *(.data.*) - . = ALIGN (4); + . = ALIGN (0x4); __data_end__ = .; } > REGION_DATA AT> REGION_TEXT @@ -169,7 +187,7 @@ SECTIONS { } > REGION_TEXT .ccfg : { - KEEP (*(.ccfg)) + KEEP(*(.ccfg)) } > FLASH_CCFG AT> FLASH_CCFG .bss : { @@ -178,30 +196,41 @@ SECTIONS { *(.bss) *(.bss.*) *(COMMON) - . = ALIGN (4); + . = ALIGN(0x4); __bss_end__ = .; } > REGION_BSS AT> REGION_BSS - .heap : { - __heap_start__ = .; - end = __heap_start__; - _end = end; - __end = end; - . = . + HEAPSIZE; + /* Start of heap must be 4 byte aligned */ + .heap (NOLOAD) : ALIGN(0x4) { + PROVIDE(__heap_start__ = .); + PROVIDE(_heap = __heap_start__); + PROVIDE(end = __heap_start__); + PROVIDE(_end = __heap_start__); + PROVIDE(__end = __heap_start__); + + . += HEAPSIZE; KEEP(*(.heap)) - __heap_end__ = .; - __HeapLimit = __heap_end__; + + PROVIDE(__heap_end__ = .); + PROVIDE(_eheap = __heap_end__); + PROVIDE(__HeapLimit = __heap_end__); } > REGION_HEAP AT> REGION_HEAP - PROVIDE(STACKSIZE = ORIGIN(SRAM) + LENGTH(SRAM) - ALIGN(0x8)); + PROVIDE(__stack_size = ORIGIN(SRAM) + LENGTH(SRAM) - ALIGN(0x8)); - .stack (NOLOAD) : ALIGN(0x8) { - _stack = .; - __stack = .; - KEEP(*(.stack)) - . += STACKSIZE; - _stack_end = .; - __stack_end = .; - ASSERT(STACKSIZE >= MIN_STACKSIZE, "Error: No room left for the stack"); + /* Start of stack must be 8 byte aligned */ + .stack (NOLOAD) : { + PROVIDE(_stack = ALIGN(0x8)); + PROVIDE(__stack = _stack); + + PROVIDE(_stack_end = ORIGIN(SRAM) + LENGTH(SRAM)); + PROVIDE(__stack_end = _stack_end); + PROVIDE(_stack_origin = _stack_end); + + /* Note that the stack check library requires the symbols */ + /* "_stack" and "_stack_origin" to be defined. */ + + /* Assert that we have enough stack */ + ASSERT(__stack_size >= MIN_STACKSIZE, "Error: No room left for the stack"); } > REGION_STACK AT> REGION_STACK } diff --git a/arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h b/arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h index f46a7401c..2634e954d 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h +++ b/arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h @@ -46,29 +46,30 @@ /*---------------------------------------------------------------------------*/ #include "contiki.h" -#include "driverlib/rf_mailbox.h" +#include +#include DeviceFamily_constructPath(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_FREQ_BAND_169 0 /* 169.400–169.475 (Europe) - 169 MHz band */ +#define DOT_15_4G_FREQ_BAND_450 1 /* 450–470 (US FCC Part 22/90) - 450 MHz band */ +#define DOT_15_4G_FREQ_BAND_470 2 /* 470–510 (China) - 470 MHz band */ +#define DOT_15_4G_FREQ_BAND_780 3 /* 779–787 (China) - 780 MHz band */ +#define DOT_15_4G_FREQ_BAND_863 4 /* 863–870 (Europe) - 863 MHz band */ +#define DOT_15_4G_FREQ_BAND_896 5 /* 896–901 (US FCC Part 90) - 896 MHz band */ +#define DOT_15_4G_FREQ_BAND_901 6 /* 901–902 (US FCC Part 24) - 901 MHz band */ +#define DOT_15_4G_FREQ_BAND_915 7 /* 902–928 (US) - 915 MHz band */ +#define DOT_15_4G_FREQ_BAND_917 8 /* 917–923.5 (Korea) - 917 MHz band */ +#define DOT_15_4G_FREQ_BAND_920 9 /* 920–928 (Japan) - 920 MHz band */ +#define DOT_15_4G_FREQ_BAND_928 10 /* 928–960 (US, non-contiguous) - 928 MHz band */ +#define DOT_15_4G_FREQ_BAND_950 11 /* 950–958 (Japan) - 950 MHz band */ +#define DOT_15_4G_FREQ_BAND_1427 12 /* 1427–1518 (US and Canada, non-contiguous) - 1427 MHz band */ +#define DOT_15_4G_FREQ_BAND_2450 13 /* 2400–2483.5 2450 MHz band */ /*---------------------------------------------------------------------------*/ /* Default band selection to band 4 - 863MHz */ -#ifdef DOT_15_4G_CONF_FREQUENCY_BAND_ID -#define DOT_15_4G_FREQUENCY_BAND_ID DOT_15_4G_CONF_FREQUENCY_BAND_ID +#ifdef DOT_15_4G_CONF_FREQ_BAND_ID +# define DOT_15_4G_FREQ_BAND_ID DOT_15_4G_CONF_FREQ_BAND_ID #else -#define DOT_15_4G_FREQUENCY_BAND_ID DOT_15_4G_FREQUENCY_BAND_863 +# define DOT_15_4G_FREQ_BAND_ID DOT_15_4G_FREQ_BAND_863 #endif /*---------------------------------------------------------------------------*/ /* @@ -76,53 +77,71 @@ * currently only support some of the bands defined in .15.4g and for those * bands we only support operating mode #1 (Table 134). * - * DOT_15_4G_CHAN0_FREQUENCY is specified here in KHz + * DOT_15_4G_CHAN0_FREQ is specified here in KHz */ -#if DOT_15_4G_FREQUENCY_BAND_ID==DOT_15_4G_FREQUENCY_BAND_470 -# define DOT_15_4G_CHANNEL_MAX 198 -# define DOT_15_4G_CHANNEL_SPACING 200 -# define DOT_15_4G_CHAN0_FREQUENCY 470200 -# define PROP_MODE_CONF_LO_DIVIDER 0x0A -# define SMARTRF_SETTINGS_CONF_BAND_OVERRIDES \ - HW32_ARRAY_OVERRIDE(0x405C,1), \ - (uint32_t)0x18000280, +#if DOT_15_4G_FREQ_BAND_ID==DOT_15_4G_FREQ_BAND_470 +# define DOT_15_4G_CHAN_MIN 0 +# define DOT_15_4G_CHAN_MAX 198 +# define DOT_15_4G_FREQ_SPACING 200 +# define DOT_15_4G_CHAN0_FREQ 470200 -#elif DOT_15_4G_FREQUENCY_BAND_ID==DOT_15_4G_FREQUENCY_BAND_780 -# define DOT_15_4G_CHANNEL_MAX 38 -# define DOT_15_4G_CHANNEL_SPACING 200 -# define DOT_15_4G_CHAN0_FREQUENCY 779200 -# define PROP_MODE_CONF_LO_DIVIDER 0x06 +# define PROP_MODE_CONF_LO_DIVIDER 0x0A -#elif DOT_15_4G_FREQUENCY_BAND_ID==DOT_15_4G_FREQUENCY_BAND_863 -# define DOT_15_4G_CHANNEL_MAX 33 -# define DOT_15_4G_CHANNEL_SPACING 200 -# define DOT_15_4G_CHAN0_FREQUENCY 863125 -# define PROP_MODE_CONF_LO_DIVIDER 0x05 +#elif DOT_15_4G_FREQ_BAND_ID==DOT_15_4G_FREQ_BAND_780 +# define DOT_15_4G_CHAN_MIN 0 +# define DOT_15_4G_CHAN_MAX 38 +# define DOT_15_4G_FREQ_SPACING 200 +# define DOT_15_4G_CHAN0_FREQ 779200 -#elif DOT_15_4G_FREQUENCY_BAND_ID==DOT_15_4G_FREQUENCY_BAND_915 -# define DOT_15_4G_CHANNEL_MAX 128 -# define DOT_15_4G_CHANNEL_SPACING 200 -# define DOT_15_4G_CHAN0_FREQUENCY 902200 -# define PROP_MODE_CONF_LO_DIVIDER 0x05 +# define PROP_MODE_CONF_LO_DIVIDER 0x06 -#elif DOT_15_4G_FREQUENCY_BAND_ID==DOT_15_4G_FREQUENCY_BAND_920 -# define DOT_15_4G_CHANNEL_MAX 37 -# define DOT_15_4G_CHANNEL_SPACING 200 -# define DOT_15_4G_CHAN0_FREQUENCY 920600 -# define PROP_MODE_CONF_LO_DIVIDER 0x05 +#elif DOT_15_4G_FREQ_BAND_ID==DOT_15_4G_FREQ_BAND_863 +# define DOT_15_4G_CHAN_MIN 0 +# define DOT_15_4G_CHAN_MAX 33 +# define DOT_15_4G_FREQ_SPACING 200 +# define DOT_15_4G_CHAN0_FREQ 863125 -#elif DOT_15_4G_FREQUENCY_BAND_ID==DOT_15_4G_FREQUENCY_BAND_950 -# define DOT_15_4G_CHANNEL_MAX 32 -# define DOT_15_4G_CHANNEL_SPACING 200 -# define DOT_15_4G_CHAN0_FREQUENCY 951000 -# define PROP_MODE_CONF_LO_DIVIDER 0x05 +# define PROP_MODE_CONF_LO_DIVIDER 0x05 + +#elif DOT_15_4G_FREQ_BAND_ID==DOT_15_4G_FREQ_BAND_915 +# define DOT_15_4G_CHAN_MIN 0 +# define DOT_15_4G_CHAN_MAX 128 +# define DOT_15_4G_FREQ_SPACING 200 +# define DOT_15_4G_CHAN0_FREQ 902200 + +# define PROP_MODE_CONF_LO_DIVIDER 0x05 + +#elif DOT_15_4G_FREQ_BAND_ID==DOT_15_4G_FREQ_BAND_920 +# define DOT_15_4G_CHAN_MIN 0 +# define DOT_15_4G_CHAN_MAX 37 +# define DOT_15_4G_FREQ_SPACING 200 +# define DOT_15_4G_CHAN0_FREQ 920600 + +# define PROP_MODE_CONF_LO_DIVIDER 0x05 + +#elif DOT_15_4G_FREQ_BAND_ID==DOT_15_4G_FREQ_BAND_950 +# define DOT_15_4G_CHAN_MIN 0 +# define DOT_15_4G_CHAN_MAX 32 +# define DOT_15_4G_FREQ_SPACING 200 +# define DOT_15_4G_CHAN0_FREQ 951000 + +# define PROP_MODE_CONF_LO_DIVIDER 0x05 + +#elif DOT_15_4G_FREQ_BAND_ID==DOT_15_4G_FREQ_BAND_2450 +# define DOT_15_4G_CHAN_MIN 11 +# define DOT_15_4G_CHAN_MAX 26 +# define DOT_15_4G_FREQ_SPACING 5000 +# define DOT_15_4G_CHAN0_FREQ 2405000 #else -# error The selected IEEE 802.15.4g frequency band is not supported +# error The selected IEEE 802.15.4g frequency band is not supported #endif /*---------------------------------------------------------------------------*/ -#define DOT_15_4_G_CHANNEL_IN_RANGE(channel) \ - (((channel) >= 0) && ((channel) <= DOT_15_4G_CHANNEL_MAX)) +#define DOT_15_4_G_FREQ(chan) \ + (DOT_15_4G_CHAN0_FREQ + DOT_15_4G_FREQ_SPACING * ((chan) - DOT_15_4G_CHAN_MIN)) + +#define DOT_15_4_G_CHAN_IN_RANGE(chan) \ + (((chan) >= DOT_15_4G_CHAN_MIN) && ((chan) <= DOT_15_4G_CHAN_MAX)) /*---------------------------------------------------------------------------*/ #endif /* DOT_15_4G_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-core.c b/arch/cpu/cc13xx-cc26xx/dev/rf-core.c index 05b19e7b2..45be6509b 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-core.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-core.c @@ -87,6 +87,8 @@ static RF_Object rf_netstack; static RF_Object rf_ble; static RF_CmdHandle cmd_rx_handle; + +static volatile bool rx_buf_full; /*---------------------------------------------------------------------------*/ static void cmd_rx_cb(RF_Handle client, RF_CmdHandle command, RF_EventMask events) @@ -100,9 +102,7 @@ cmd_rx_cb(RF_Handle client, RF_CmdHandle command, RF_EventMask events) } if (events & RF_EventRxBufFull) { - data_queue_reset(); - /* TODO: Check status of RX to verify RX was running before rescheduling */ - netstack_sched_rx(); + rx_buf_full = true; process_poll(&rf_core_process); } @@ -224,10 +224,10 @@ netstack_sched_fs(void) const uint_fast8_t rx_key = cmd_rx_disable(); /* - * For IEEE-mode, restarting IEEE_RX recalibrates the synth by using the - * channel field in the IEEE_RX commando. It is assumed this field is - * already configured before this functions is called. - * However, if IEEE_RX wasn't active, manually calibrate the synth + * For IEEE-mode, restarting CMD_IEEE_RX re-calibrates the synth by using the + * channel field in the CMD_IEEE_RX command. It is assumed this field is + * already configured before this function is called. + * However, if CMD_IEEE_RX wasn't active, manually calibrate the synth * with CMD_FS. * * For Prop-mode, the synth is always manually calibrated with CMD_FS. @@ -504,11 +504,18 @@ PROCESS_THREAD(rf_core_process, ev, data) while(1) { PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL); + do { //watchdog_periodic(); packetbuf_clear(); len = NETSTACK_RADIO.read(packetbuf_dataptr(), PACKETBUF_SIZE); + if (rx_buf_full) { + PRINTF("rf_core: RX buf full, restart RX\n"); + rx_buf_full = false; + netstack_sched_rx(); + } + if(len > 0) { packetbuf_set_datalen(len); diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c index 87b6068c2..69b9f5327 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c @@ -69,6 +69,7 @@ #include "rf-data-queue.h" #include "rf-core.h" #include "netstack-settings.h" +#include RF_CORE_IEEE_RF_SETTINGS /*---------------------------------------------------------------------------*/ #include #include diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c index 55986391a..131051285 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c @@ -60,6 +60,7 @@ #include "rf-core.h" #include "rf-data-queue.h" #include "netstack-settings.h" +#include RF_CORE_PROP_RF_SETTINGS /*---------------------------------------------------------------------------*/ #include #include @@ -264,7 +265,7 @@ get_channel(void) */ freq_khz += (((cmd_fs.fractFreq * 1000) + 65535) / 65536); - return (freq_khz - DOT_15_4G_CHAN0_FREQUENCY) / DOT_15_4G_CHANNEL_SPACING; + return (uint8_t)((freq_khz - DOT_15_4G_CHAN0_FREQ) / DOT_15_4G_FREQ_SPACING); } /*---------------------------------------------------------------------------*/ static rf_result_t @@ -272,10 +273,10 @@ set_channel(uint16_t channel) { rf_result_t res; - if (!DOT_15_4_G_CHANNEL_IN_RANGE(channel)) { + if (!DOT_15_4_G_CHAN_IN_RANGE(channel)) { PRINTF("set_channel: illegal channel %d, defaults to %d\n", - (int)channel, DOT_15_4G_CHANNEL_MAX); - channel = DOT_15_4G_CHANNEL_MAX; + (int)channel, DOT_15_4G_CHAN_MAX); + channel = DOT_15_4G_CHAN_MAX; } if (channel == prop_radio.channel) { @@ -283,7 +284,7 @@ set_channel(uint16_t channel) return RF_RESULT_OK; } - const uint32_t new_freq = DOT_15_4G_CHAN0_FREQUENCY + ((uint32_t)channel * DOT_15_4G_CHANNEL_SPACING); + const uint32_t new_freq = DOT_15_4_G_FREQ(channel); const uint16_t freq = (uint16_t)(new_freq / 1000); const uint16_t frac = (uint16_t)(((new_freq - (freq * 1000)) * 0x10000) / 1000); @@ -583,11 +584,11 @@ get_value(radio_param_t param, radio_value_t *value) : RADIO_RESULT_OK; case RADIO_CONST_CHANNEL_MIN: - *value = 0; + *value = DOT_15_4G_CHAN_MIN; return RADIO_RESULT_OK; case RADIO_CONST_CHANNEL_MAX: - *value = DOT_15_4G_CHANNEL_MAX; + *value = DOT_15_4G_CHAN_MAX; return RADIO_RESULT_OK; case RADIO_CONST_TXPOWER_MIN: diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h index ecb25dde0..1e5169459 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h @@ -35,6 +35,7 @@ #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) #include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_prop_mailbox.h) #include /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h index 226c34d30..b19e76a9f 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h @@ -35,6 +35,7 @@ #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) #include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_prop_mailbox.h) #include /*---------------------------------------------------------------------------*/ From 8cd6017305b12c0d9dc243d0b56661a13f6473d0 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Fri, 13 Jul 2018 19:09:02 +0200 Subject: [PATCH 268/485] Cleanup in config --- arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h | 177 ++++--- arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h | 7 + arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.c | 47 +- arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.h | 6 - arch/cpu/cc13xx-cc26xx/dev/rf-core.c | 11 +- arch/cpu/cc13xx-cc26xx/dev/rf-core.h | 12 +- arch/cpu/cc13xx-cc26xx/dev/rf-data-queue.c | 15 +- arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c | 61 +-- arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c | 15 +- .../dev/startup_cc13xx_cc26xx_gcc.c | 34 +- arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c | 29 +- .../rf-settings/netstack-settings.h | 30 +- .../launchpad/Makefile.launchpad | 1 - .../launchpad/board-peripherals.h | 2 - .../launchpad/cc1352r1/CC1352R1_LAUNCHXL.c | 50 +- .../launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c | 47 +- .../cc13xx-cc26xx/launchpad/ext-flash.c | 468 ------------------ .../cc13xx-cc26xx/launchpad/ext-flash.h | 116 ----- .../simplelink/cc13xx-cc26xx/platform.c | 26 +- 19 files changed, 338 insertions(+), 816 deletions(-) delete mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/ext-flash.c delete mode 100644 arch/platform/simplelink/cc13xx-cc26xx/launchpad/ext-flash.h diff --git a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h index c457a814f..47aba1d9b 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h +++ b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h @@ -34,106 +34,133 @@ * @{ * * \file - * Header with configuration defines common to all CC13xx/CC26xx platforms + * Header with configuration defines common to the CC13xx/CC26xx platform. + * + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #ifndef SIMPLELINK_CONF_H_ #define SIMPLELINK_CONF_H_ /*---------------------------------------------------------------------------*/ #include "cc13xx-cc26xx-def.h" -/*---------------------------------------------------------------------------*/ +#include "rf-core.h" +/*---------------------------------------------------------------------------*/ +/* GPIO HAL configuration. */ #define GPIO_HAL_CONF_ARCH_SW_TOGGLE 0 #define GPIO_HAL_CONF_ARCH_HDR_PATH "dev/gpio-hal-arch.h" -/** - * \name Network Stack Configuration - * - * @{ - */ +/*---------------------------------------------------------------------------*/ +/* RF configuration */ /* - * If set, the systems keeps the HF crystal oscillator on even when the radio is off. - * You need to set this to 1 to use TSCH with its default 2.2ms or larger guard time. + * If set, the systems keeps the HF crystal oscillator on even when the + * radio is off. You need to set this to 1 to use TSCH with its default 2.2ms + * or larger guard time. */ -#ifndef CC2650_FAST_RADIO_STARTUP -#define CC2650_FAST_RADIO_STARTUP (MAC_CONF_WITH_TSCH) +#ifndef RF_CONF_FAST_RADIO_STARTUP +# define RF_FAST_RADIO_STARTUP (MAC_CONF_WITH_TSCH) +#else +# define RF_FAST_RADIO_STARTUP 0 #endif -#define RF_CORE_MODE_SUB_1_GHZ (1 << 0) -#define RF_CORE_MODE_2_4_GHZ (1 << 1) - -#define RF_CORE_MODE_MASK ( RF_CORE_MODE_SUB_1_GHZ \ - | RF_CORE_MODE_2_4_GHZ \ - ) - -/* Default RF mode is 2.4 GHz */ -#ifdef RF_CORE_CONF_MODE -# if !(RF_CORE_CONF_MODE & RF_CORE_MODE_MASK) -# error "Invalid RF_CORE_CONF_MODE" +/* + * Configure RF mode. That is, whether to run on Sub-1 GHz (Prop-mode) or + * 2.4 GHz (IEEE-mode). + */ +#ifdef RF_CONF_MODE +/* Sanity check a valid configuration is given */ +# if !(RF_CONF_MODE & RF_MODE_BM) +# error "Invalid RF_CONF_MODE" # endif -# define RF_CORE_MODE RF_CORE_CONF_MODE + +# define RF_MODE RF_CONF_MODE +#endif /* RF_CONF_MODE */ + +/* Number of RX buffers */ +#ifdef RF_CONF_RX_BUF_CNT +# define RF_RX_BUF_CNT RF_CONF_RX_BUF_CNT #else -# define RF_CORE_MODE RF_CORE_MODE_2_4_GHZ +# define RF_RX_BUF_CNT 4 #endif -#ifdef RF_CORE_CONF_CHANNEL -# define RF_CHANNEL RF_CORE_CONF_CHANNEL +/* Size of each RX buffer in bytes */ +#ifdef RF_CONF_RX_BUF_SIZE +# define RF_RX_BUF_SIZE RF_CONF_RX_BUF_SIZE #else -# define RF_CHANNEL 25 +# define RF_RX_BUF_SIZE 144 #endif -/* Number of Prop Mode RX buffers */ -#ifndef PROP_MODE_CONF_RX_BUF_CNT -#define PROP_MODE_CONF_RX_BUF_CNT 4 +/* Enable/disable BLE beacon */ +#ifdef RF_CONF_BLE_BEACON_ENABLE +# define RF_BLE_BEACON_ENABLE RF_CONF_BLE_BEACON_ENABLE +#else +# define RF_BLE_BEACON_ENABLE 0 #endif -/* Configure Radio mode, i.e. prop or ieee */ - /*----- CC13xx Device Line --------------------------------------------------*/ /* CC13xx supports both IEEE and Prop mode, depending on which device */ #if defined(DEVICE_LINE_CC13XX) -# if (RF_CORE_MODE == RF_CORE_MODE_SUB_1_GHZ) && (SUPPORTS_PROP_MODE) +/* Default to Prop-mode for CC13xx devices if not configured */ +# ifndef RF_MODE +# define RF_MODE RF_MODE_SUB_1_GHZ +# endif + +# if (RF_MODE == RF_MODE_SUB_1_GHZ) && (SUPPORTS_PROP_MODE) /*----- CC13xx Prop Mode ----------------------------------------------------*/ +/* Netstack configuration */ # define NETSTACK_CONF_RADIO prop_mode_driver +/* CSMA configuration */ # define CSMA_CONF_ACK_WAIT_TIME (RTIMER_SECOND / 300) # define CSMA_CONF_AFTER_ACK_DETECTED_WAIT_TIME (RTIMER_SECOND / 1000) # define CSMA_CONF_SEND_SOFT_ACK 1 -# elif (RF_CORE_MODE == RF_CORE_MODE_2_4_GHZ) && (SUPPORTS_IEEE_MODE) +# elif (RF_MODE == RF_MODE_2_4_GHZ) && (SUPPORTS_IEEE_MODE) /*----- CC13xx IEEE Mode ----------------------------------------------------*/ +/* Netstack configuration */ # define NETSTACK_CONF_RADIO ieee_mode_driver +/* CSMA configuration */ # define CSMA_CONF_SEND_SOFT_ACK 0 # else /*----- CC13xx Non-supported Mode -------------------------------------------*/ # error "Invalid radio mode configuration of CC13xx device" -# endif /* (RF_CORE_IS_SUB_1_GHZ == 1) && (SUPPORTS_PROP_MODE == 1) */ +# endif /* CC13xx RF Mode configuration */ /*----- CC26xx Device Line --------------------------------------------------*/ /* CC26xx only supports IEEE mode */ #elif defined(DEVICE_LINE_CC26XX) -# if (RF_CORE_MODE == RF_CORE_MODE_2_4_GHZ) && (SUPPORTS_IEEE_MODE) +/* Default to IEEE-mode for CC13xx devices if not configured */ +# ifndef RF_MODE +# define RF_MODE RF_MODE_2_4_GHZ +# endif + +# if (RF_MODE == RF_MODE_2_4_GHZ) && (SUPPORTS_IEEE_MODE) /*----- CC26xx IEEE Mode ----------------------------------------------------*/ +/* Netstack configuration */ # define NETSTACK_CONF_RADIO ieee_mode_driver +/* CSMA configuration */ # define CSMA_CONF_SEND_SOFT_ACK 0 +/* Frequncy band configuration */ +# undef DOT_15_4G_FREQ_BAND_ID +# define DOT_15_4G_CONF_FREQ_BAND_ID DOT_15_4G_FREQ_BAND_2450 + # else /*----- CC26xx Non-supported Mode -------------------------------------------*/ # error "IEEE mode only supported by CC26xx devices" -# endif /* (SUPPORTS_IEEE_MODE == 1) */ +# endif /* CC26xx RF Mode configuration */ /*----- Unsupported device line ---------------------------------------------*/ #else # error "Unsupported Device Line defined" -#endif /* defined(DEVICE_LINE_CC13xx) */ - -#define NETSTACK_RADIO_MAX_PAYLOAD_LEN 125 +#endif /* Unsupported device line */ /** @} */ /*---------------------------------------------------------------------------*/ @@ -175,30 +202,68 @@ #ifndef IEEE_MODE_CONF_PROMISCOUS #define IEEE_MODE_CONF_PROMISCOUS 0 /**< 1 to enable promiscous mode */ #endif +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \name TI Drivers Configuration + * + * @{ + */ -#ifndef RF_BLE_CONF_ENABLED -#define RF_BLE_CONF_ENABLED 0 /**< 0 to disable BLE support */ +/* UART */ +#ifndef TI_UART_CONF_ENABLE +#define TI_UART_CONF_ENABLE 1 +#endif + +#ifndef TI_UART_CONF_UART0_ENABLE +#define TI_UART_CONF_UART0_ENABLE TI_UART_CONF_ENABLE +#endif + +#ifndef TI_UART_CONF_UART1_ENABLE +#define TI_UART_CONF_UART1_ENABLE 1 +#endif + +#ifndef TI_UART_CONF_BAUD_RATE +#define TI_UART_CONF_BAUD_RATE 115200 +#endif + +/* SPI */ +#ifndef TI_SPI_CONF_ENABLE +#define TI_SPI_CONF_ENABLE 1 +#endif + +#ifndef TI_SPI_CONF_SPI0_ENABLE +#define TI_SPI_CONF_SPI0_ENABLE TI_SPI_CONF_ENABLE +#endif + +#ifndef TI_SPI_CONF_SPI1_ENABLE +#define TI_SPI_CONF_SPI1_ENABLE 1 +#endif + +/* I2C */ +#ifndef TI_I2C_CONF_ENABLE +#define TI_I2C_CONF_ENABLE 1 +#endif + +/* NVS */ +#ifndef TI_NVS_CONF_ENABLE +#define TI_NVS_CONF_ENABLE 1 +#endif + +#ifndef TI_NVS_CONF_NVS_INTERNAL_ENABLE +#define TI_NVS_CONF_NVS_INTERNAL_ENABLE TI_NVS_CONF_ENABLE +#endif + +#ifndef TI_NVS_CONF_NVS_EXTERNAL_ENABLE +#define TI_NVS_CONF_NVS_EXTERNAL_ENABLE TI_NVS_CONF_ENABLE #endif /** @} */ /*---------------------------------------------------------------------------*/ /** - * \name Character I/O Configuration + * \name Misc. Configuration * * @{ */ -#ifndef SIMPLELINK_UART_CONF_ENABLE -#define SIMPLELINK_UART_CONF_ENABLE 1 /**< Enable/Disable UART I/O */ -#endif - -#ifndef SIMPLELINK_UART_CONF_BAUD_RATE -#define SIMPLELINK_UART_CONF_BAUD_RATE 115200 /**< Default UART0 baud rate */ -#endif - -/* Enable I/O over the Debugger Devpack - Only relevant for the SensorTag */ -#ifndef BOARD_CONF_DEBUGGER_DEVPACK -#define BOARD_CONF_DEBUGGER_DEVPACK 1 -#endif - #ifndef SLIP_ARCH_CONF_ENABLED /* * Determine whether we need SLIP diff --git a/arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h b/arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h index 2634e954d..e12fe2ffc 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h +++ b/arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h @@ -143,6 +143,13 @@ #define DOT_15_4_G_CHAN_IN_RANGE(chan) \ (((chan) >= DOT_15_4G_CHAN_MIN) && ((chan) <= DOT_15_4G_CHAN_MAX)) /*---------------------------------------------------------------------------*/ +#define DOT_15_4_G_DEFAULT_CHAN IEEE802154_DEFAULT_CHANNEL + +/* Sanity check default channel */ +#if !(DOT_15_4_G_CHAN_IN_RANGE(DOT_15_4_G_DEFAULT_CHAN)) +# error IEEE802154_DEFAULT_CHANNEL is not in valid channel range +#endif +/*---------------------------------------------------------------------------*/ #endif /* DOT_15_4G_H_ */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.c b/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.c index 2643f4f0f..442bd979a 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.c @@ -63,34 +63,13 @@ #include #include /*---------------------------------------------------------------------------*/ -#define DEBUG 0 -#if DEBUG +#if 0 #define PRINTF(...) printf(__VA_ARGS__) #else #define PRINTF(...) #endif /*---------------------------------------------------------------------------*/ -#if !(RF_BLE_BEACOND_ENABLED) -/*---------------------------------------------------------------------------*/ -rf_ble_beacond_result_t -rf_ble_beacond_init(void) { return RF_BLE_BEACOND_DISABLED; } -/*---------------------------------------------------------------------------*/ -rf_ble_beacond_result_t -rf_ble_beacond_start(clock_time_t interval, const char *name) { return RF_BLE_BEACOND_DISABLED; } -/*---------------------------------------------------------------------------*/ -rf_ble_beacond_result_t -rf_ble_beacond_stop(void) { return RF_BLE_BEACOND_DISABLED; } -/*---------------------------------------------------------------------------*/ -int8_t -rf_ble_is_active(void) { return -1; } -/*---------------------------------------------------------------------------*/ -rf_ble_beacond_result_t -rf_ble_set_tx_power(int8_t power) { return RF_BLE_BEACOND_DISABLED; } -/*---------------------------------------------------------------------------*/ -int8_t -rf_ble_get_tx_power(void) { return ~(int8_t)(0); } -/*---------------------------------------------------------------------------*/ -#else /* RF_BLE_BEACOND_ENABLED */ +#if RF_BLE_BEACON_ENABLE /*---------------------------------------------------------------------------*/ /* BLE Advertisement channels. Not to be changed by the user. */ typedef enum { @@ -332,7 +311,27 @@ PROCESS_THREAD(ble_beacond_process, ev, data) PROCESS_END(); } /*---------------------------------------------------------------------------*/ -#endif /* RF_BLE_BEACOND_ENABLED */ +#else /* RF_BLE_BEACON_ENABLE */ +/*---------------------------------------------------------------------------*/ +rf_ble_beacond_result_t +rf_ble_beacond_init(void) { return RF_BLE_BEACOND_DISABLED; } +/*---------------------------------------------------------------------------*/ +rf_ble_beacond_result_t +rf_ble_beacond_start(clock_time_t interval, const char *name) { return RF_BLE_BEACOND_DISABLED; } +/*---------------------------------------------------------------------------*/ +rf_ble_beacond_result_t +rf_ble_beacond_stop(void) { return RF_BLE_BEACOND_DISABLED; } +/*---------------------------------------------------------------------------*/ +int8_t +rf_ble_is_active(void) { return -1; } +/*---------------------------------------------------------------------------*/ +rf_ble_beacond_result_t +rf_ble_set_tx_power(int8_t power) { return RF_BLE_BEACOND_DISABLED; } +/*---------------------------------------------------------------------------*/ +int8_t +rf_ble_get_tx_power(void) { return ~(int8_t)(0); } +/*---------------------------------------------------------------------------*/ +#endif /* RF_BLE_BEACON_ENABLE */ /*---------------------------------------------------------------------------*/ /** * @} diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.h b/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.h index 45f02f062..da672b800 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.h +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.h @@ -48,12 +48,6 @@ #include /*---------------------------------------------------------------------------*/ -#ifdef RF_BLE_BEACON_CONF_ENABLED -#define RF_BLE_BEACON_ENABLED RF_BLE_BEACON_CONF_ENABLED -#else -#define RF_BLE_BEACON_ENABLED 1 -#endif -/*---------------------------------------------------------------------------*/ typedef enum { RF_BLE_BEACOND_OK, RF_BLE_BEACOND_ERROR, diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-core.c b/arch/cpu/cc13xx-cc26xx/dev/rf-core.c index 45be6509b..d9f6cf928 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-core.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-core.c @@ -60,12 +60,7 @@ #include #include /*---------------------------------------------------------------------------*/ -/* Log configuration */ -#include "sys/log.h" -#define LOG_MODULE "RF Core" -#define LOG_LEVEL LOG_LEVEL_DBG -/*---------------------------------------------------------------------------*/ -#ifdef NDEBUG +#if 0 # define PRINTF(...) #else # define PRINTF(...) printf(__VA_ARGS__) @@ -173,11 +168,15 @@ rf_yield(void) { /* Force abort of any ongoing RF operation */ RF_flushCmd(&rf_netstack, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY); +#if RF_BLE_BEACON_ENABLE RF_flushCmd(&rf_ble, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY); +#endif /* Trigger a manual power-down */ RF_yield(&rf_netstack); +#if RF_BLE_BEACON_ENABLE RF_yield(&rf_ble); +#endif ENERGEST_OFF(ENERGEST_TYPE_LISTEN); diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-core.h b/arch/cpu/cc13xx-cc26xx/dev/rf-core.h index 7ce6738e8..ad789c8e1 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-core.h +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-core.h @@ -44,6 +44,7 @@ #define RF_CORE_H_ /*---------------------------------------------------------------------------*/ #include "contiki.h" +#include "sys/process.h" #include "rf-ble-beacond.h" /*---------------------------------------------------------------------------*/ @@ -51,13 +52,20 @@ /*---------------------------------------------------------------------------*/ #include /*---------------------------------------------------------------------------*/ +#define RF_MODE_SUB_1_GHZ (1 << 0) +#define RF_MODE_2_4_GHZ (1 << 1) + +#define RF_MODE_BM ( RF_MODE_SUB_1_GHZ \ + | RF_MODE_2_4_GHZ \ + ) +/*---------------------------------------------------------------------------*/ +PROCESS_NAME(rf_core_process); +/*---------------------------------------------------------------------------*/ typedef enum { RF_RESULT_OK = 0, RF_RESULT_ERROR, } rf_result_t; /*---------------------------------------------------------------------------*/ -PROCESS_NAME(rf_core_process); -/*---------------------------------------------------------------------------*/ /* Common */ rf_result_t rf_yield(void); diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-data-queue.c b/arch/cpu/cc13xx-cc26xx/dev/rf-data-queue.c index 875edab4b..32bab1242 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-data-queue.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-data-queue.c @@ -46,21 +46,12 @@ #include DeviceFamily_constructPath(driverlib/rf_data_entry.h) /*---------------------------------------------------------------------------*/ #include +#include #include /*---------------------------------------------------------------------------*/ /* RX buf configuration */ - -#ifdef RF_CORE_CONF_RX_BUF_CNT -# define RX_BUF_CNT RF_CORE_CONF_RX_BUF_CNT -#else -# define RX_BUF_CNT 4 -#endif - -#ifdef RF_CORE_CONF_RX_BUF_SIZE -# define RX_BUF_SIZE RF_CORE_CONF_RX_BUF_SIZE -#else -# define RX_BUF_SIZE 144 -#endif +#define RX_BUF_CNT RF_RX_BUF_CNT +#define RX_BUF_SIZE RF_RX_BUF_SIZE /*---------------------------------------------------------------------------*/ /* Receive buffer entries with room for 1 IEEE 802.15.4 frame in each */ typedef union { diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c index 69b9f5327..177415290 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c @@ -68,8 +68,9 @@ /* SimpleLink Platform RF dev */ #include "rf-data-queue.h" #include "rf-core.h" +#include "dot-15-4g.h" #include "netstack-settings.h" -#include RF_CORE_IEEE_RF_SETTINGS +#include RF_IEEE_SETTINGS /*---------------------------------------------------------------------------*/ #include #include @@ -77,15 +78,10 @@ #include #include /*---------------------------------------------------------------------------*/ -/* Log configuration */ -#include "sys/log.h" -#define LOG_MODULE "RF IEEE Mode" -#define LOG_LEVEL LOG_LEVEL_NONE -/*---------------------------------------------------------------------------*/ -#ifdef NDEBUG -# define PRINTF(...) +#if 0 +# define PRINTF(...) #else -# define PRINTF(...) printf(__VA_ARGS__) +# define PRINTF(...) printf(__VA_ARGS__) #endif /*---------------------------------------------------------------------------*/ /* Configuration parameters */ @@ -111,13 +107,6 @@ # define IEEE_MODE_RSSI_THRESHOLD 0xA6 #endif /* IEEE_MODE_CONF_RSSI_THRESHOLD */ -/* Configuration for default IEEE channel */ -#ifdef IEEE_MODE_CONF_CHANNEL -# define IEEE_MODE_CHANNEL IEEE_MODE_CONF_CHANNEL -#else -# define IEEE_MODE_CHANNEL RF_CHANNEL -#endif - /* Configuration for TX power table */ #ifdef IEEE_MODE_CONF_TX_POWER_TABLE # define TX_POWER_TABLE IEEE_MODE_CONF_TX_POWER_TABLE @@ -137,26 +126,6 @@ #define TX_POWER_IN_RANGE(dbm) (((dbm) >= TX_POWER_MIN) && ((dbm) <= TX_POWER_MAX)) /*---------------------------------------------------------------------------*/ -/* IEEE channel-to-frequency conversion constants */ -/* Channel frequency base: 2.405 GHz */ -/* Channel frequency spacing: 5 MHz */ -/* Channel range: 11 - 26 */ -#define IEEE_MODE_FREQ_BASE 2405000 -#define IEEE_MODE_FREQ_SPACING 5000 -#define IEEE_MODE_CHAN_MIN 11 -#define IEEE_MODE_CHAN_MAX 26 - -#define IEEE_MODE_CHAN_IN_RANGE(ch) ((IEEE_MODE_CHAN_MIN <= (ch)) && ((ch) <= IEEE_MODE_CHAN_MAX)) - /* freq(channel) = freq_base + freq_spacing * (channel - channel_min) */ -#define IEEE_MODE_FREQ(chan) \ - ((uint32_t)IEEE_MODE_FREQ_BASE + (uint32_t)IEEE_MODE_FREQ_SPACING * \ - ((uint32_t)(channel) - (uint32_t)IEEE_MODE_CHAN_MIN)) - -/* Sanity check of default IEEE channel */ -#if !IEEE_MODE_CHAN_IN_RANGE(IEEE_MODE_CHANNEL) -# error "Default IEEE channel IEEE_MODE_CHANNEL is outside allowed channel range" -#endif -/*---------------------------------------------------------------------------*/ /* Timeout constants */ /* How long to wait for the rx read entry to become ready */ @@ -341,10 +310,10 @@ init_rf_params(void) static rf_result_t set_channel(uint8_t channel) { - if (!IEEE_MODE_CHAN_IN_RANGE(channel)) { + if (!DOT_15_4_G_CHAN_IN_RANGE(channel)) { PRINTF("set_channel: illegal channel %d, defaults to %d\n", - (int)channel, IEEE_MODE_CHANNEL); - channel = IEEE_MODE_CHANNEL; + (int)channel, DOT_15_4_G_DEFAULT_CHAN); + channel = DOT_15_4_G_DEFAULT_CHAN; } /* @@ -359,9 +328,9 @@ set_channel(uint8_t channel) cmd_rx.channel = channel; - const uint32_t new_freq = IEEE_MODE_FREQ(channel); - const uint16_t freq = (uint16_t)(new_freq / 1000); - const uint16_t frac = (uint16_t)(((new_freq - (freq * 1000)) * 0x10000) / 1000); + const uint32_t new_freq = (uint32_t)DOT_15_4_G_FREQ(channel); + const uint16_t freq = (uint16_t)(new_freq / 1000); + const uint16_t frac = (uint16_t)(((new_freq - (freq * 1000)) * 0x10000) / 1000); PRINTF("set_channel: %d = 0x%04X.0x%04X (%lu)\n", (int)channel, freq, frac, new_freq); @@ -459,7 +428,7 @@ init(void) return RF_RESULT_ERROR; } - set_channel((uint8_t)IEEE_MODE_CHANNEL); + set_channel(DOT_15_4_G_DEFAULT_CHAN); ENERGEST_ON(ENERGEST_TYPE_LISTEN); @@ -829,12 +798,12 @@ get_value(radio_param_t param, radio_value_t *value) /* Channel min */ case RADIO_CONST_CHANNEL_MIN: - *value = (radio_value_t)IEEE_MODE_CHAN_MIN; + *value = (radio_value_t)DOT_15_4G_CHAN_MIN; return RADIO_RESULT_OK; /* Channel max */ case RADIO_CONST_CHANNEL_MAX: - *value = (radio_value_t)IEEE_MODE_CHAN_MAX; + *value = (radio_value_t)DOT_15_4G_CHAN_MAX; return RADIO_RESULT_OK; case RADIO_CONST_TXPOWER_MIN: @@ -885,7 +854,7 @@ set_value(radio_param_t param, radio_value_t value) /* Channel */ case RADIO_PARAM_CHANNEL: - if (!IEEE_MODE_CHAN_IN_RANGE(value)) { + if (!DOT_15_4_G_CHAN_IN_RANGE(value)) { return RADIO_RESULT_INVALID_VALUE; } set_channel((uint8_t)value); diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c index 131051285..4758e01ce 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c @@ -73,19 +73,12 @@ #define LOG_MODULE "RF Prop Mode" #define LOG_LEVEL LOG_LEVEL_NONE /*---------------------------------------------------------------------------*/ -#ifdef NDEBUG +#if 0 # define PRINTF(...) #else # define PRINTF(...) printf(__VA_ARGS__) #endif /*---------------------------------------------------------------------------*/ -/* Configuration for default Prop channel */ -#ifdef PROP_MODE_CONF_CHANNEL -# define PROP_MODE_CHANNEL PROP_MODE_CONF_CHANNEL -#else -# define PROP_MODE_CHANNEL RF_CHANNEL -#endif -/*---------------------------------------------------------------------------*/ /* Data whitener. 1: Whitener, 0: No whitener */ #ifdef PROP_MODE_CONF_DW # define PROP_MODE_DW PROP_MODE_CONF_DW @@ -275,8 +268,8 @@ set_channel(uint16_t channel) if (!DOT_15_4_G_CHAN_IN_RANGE(channel)) { PRINTF("set_channel: illegal channel %d, defaults to %d\n", - (int)channel, DOT_15_4G_CHAN_MAX); - channel = DOT_15_4G_CHAN_MAX; + (int)channel, IEEE802154_DEFAULT_CHANNEL); + channel = IEEE802154_DEFAULT_CHANNEL; } if (channel == prop_radio.channel) { @@ -692,7 +685,7 @@ init(void) return RF_RESULT_ERROR; } - set_channel(PROP_MODE_CHANNEL); + set_channel(IEEE802154_DEFAULT_CHANNEL); ENERGEST_ON(ENERGEST_TYPE_LISTEN); diff --git a/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c b/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c index 019a14d69..6efdf5569 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c +++ b/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c @@ -248,25 +248,25 @@ nmiISR(void) volatile int x__; -volatile uint32_t r0; -volatile uint32_t r1; -volatile uint32_t r2; -volatile uint32_t r3; -volatile uint32_t r12; -volatile uint32_t lr; -volatile uint32_t pc; -volatile uint32_t psr; - void debugHardfault(uint32_t *sp) { - r0 = sp[0]; - r1 = sp[1]; - r2 = sp[2]; - r3 = sp[3]; - r12 = sp[4]; - lr = sp[5]; - pc = sp[6]; - psr = sp[7]; + volatile uint32_t r0; + volatile uint32_t r1; + volatile uint32_t r2; + volatile uint32_t r3; + volatile uint32_t r12; + volatile uint32_t lr; + volatile uint32_t pc; + volatile uint32_t psr; + + (void)(r0 = sp[0]); + (void)(r1 = sp[1]); + (void)(r2 = sp[2]); + (void)(r3 = sp[3]); + (void)(r12 = sp[4]); + (void)(lr = sp[5]); + (void)(pc = sp[6]); + (void)(psr = sp[7]); while(1); } diff --git a/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c b/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c index f2b22b54d..7a00d55f2 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c @@ -59,14 +59,18 @@ uart0_cb(UART_Handle handle, void *buf, size_t count) { if (!g_input_cb) { return; } - // Save the current callback function, as this might be overwritten after - // the callback is called. + /* + * Save the current callback function, as this might be overwritten after + * the callback is called. + */ const uart0_input_cb currCb = g_input_cb; - // Call the callback. Note this might reset g_input_cb + /* Call the callback. Note this might reset g_input_cb */ currCb(g_char_buf); - // If g_input_cb didn't change after the call, do another read. - // Else, the uart0_set_callback was called with a different callback pointer - // and triggered an another read. + /* + * If g_input_cb didn't change after the call, do another read. + * Else, the uart0_set_callback was called with a different callback pointer + * and triggered an another read. + */ if (currCb == g_input_cb) { UART_read(gh_uart, &g_char_buf, 1); } @@ -80,13 +84,12 @@ uart0_init(void) UART_Params params; UART_Params_init(¶ms); -#ifdef SIMPLELINK_UART_CONF_BAUD_RATE - params.baudRate = SIMPLELINK_UART_CONF_BAUD_RATE; -#endif - params.readMode = UART_MODE_CALLBACK; - params.writeMode = UART_MODE_BLOCKING; - params.readCallback = uart0_cb; - params.readDataMode = UART_DATA_TEXT; + + params.baudRate = TI_UART_CONF_BAUD_RATE; + params.readMode = UART_MODE_CALLBACK; + params.writeMode = UART_MODE_BLOCKING; + params.readCallback = uart0_cb; + params.readDataMode = UART_DATA_TEXT; params.readReturnMode = UART_RETURN_NEWLINE; gh_uart = UART_open(Board_UART0, ¶ms); diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/netstack-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/netstack-settings.h index 0da5aa33d..03bcfe2bb 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/netstack-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/netstack-settings.h @@ -36,30 +36,30 @@ #include /*---------------------------------------------------------------------------*/ /* Prop-mode RF settings configuration */ -#ifdef RF_CORE_CONF_PROP_RF_SETTINGS -# define RF_CORE_PROP_RF_SETTINGS RF_CORE_CONF_PROP_RF_SETTINGS +#ifdef RF_CONF_PROP_SETTINGS +# define RF_PROP_SETTINGS RF_CONF_PROP_SETTINGS #else -# define RF_CORE_PROP_RF_SETTINGS "prop-settings.h" +# define RF_PROP_SETTINGS "prop-settings.h" #endif /* IEEE-mode RF settings configuration */ -#ifdef RF_CORE_CONF_IEEE_RF_SETTINGS -# define RF_CORE_IEEE_RF_SETTINGS RF_CORE_CONF_IEEE_RF_SETTINGS +#ifdef RF_CONF_IEEE_SETTINGS +# define RF_IEEE_SETTINGS RF_CONF_IEEE_SETTINGS #else -# define RF_CORE_IEEE_RF_SETTINGS "ieee-settings.h" +# define RF_IEEE_SETTINGS "ieee-settings.h" #endif /* BLE RF settings configuration */ -#ifdef RF_CORE_CONF_BLE_RF_SETTINGS -# define RF_CORE_BLE_RF_SETTINGS RF_CORE_CONF_BLE_RF_SETTINGS +#ifdef RF_CONF_BLE_SETTINGS +# define RF_BLE_SETTINGS RF_CONF_BLE_SETTINGS #else -# define RF_CORE_BLE_RF_SETTINGS "ble-settings.h" +# define RF_BLE_SETTINGS "ble-settings.h" #endif /*---------------------------------------------------------------------------*/ /* Prop-mode RF settings */ -#if (RF_CORE_CONF_MODE == RF_CORE_MODE_SUB_1_GHZ) +#if (RF_MODE == RF_MODE_SUB_1_GHZ) -#include RF_CORE_PROP_RF_SETTINGS +#include RF_PROP_SETTINGS #define netstack_mode rf_prop_mode #define netstack_cmd_radio_setup rf_cmd_prop_radio_div_setup @@ -68,9 +68,9 @@ #define netstack_cmd_rx rf_cmd_prop_rx_adv /*---------------------------------------------------------------------------*/ /* IEEE-mode RF settings */ -#elif (RF_CORE_CONF_MODE == RF_CORE_MODE_2_4_GHZ) +#elif (RF_MODE == RF_MODE_2_4_GHZ) -#include RF_CORE_IEEE_RF_SETTINGS +#include RF_IEEE_SETTINGS #define netstack_mode rf_ieee_mode #define netstack_cmd_radio_setup rf_cmd_ieee_radio_setup @@ -79,11 +79,11 @@ #define netstack_cmd_rx rf_cmd_ieee_rx /*---------------------------------------------------------------------------*/ #else -# error "Unsupported RF_CORE_MODE" +# error "Unsupported RF_MODE" #endif /*---------------------------------------------------------------------------*/ /* BLE RF settings */ -#include RF_CORE_BLE_RF_SETTINGS +#include RF_BLE_SETTINGS #if (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0) diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/Makefile.launchpad b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/Makefile.launchpad index c8524692e..6dabff9bf 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/Makefile.launchpad +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/Makefile.launchpad @@ -7,6 +7,5 @@ PLATFORM_HAS_BUTTON = 1 # leds-arch.c/h etc. BOARD_SOURCEFILES += button-sensor-arch.c leds-arch.c -BOARD_SOURCEFILES += ext-flash.c TARGET_FAMILY_DIRS += launchpad diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-peripherals.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-peripherals.h index 6b9fae675..9b45e3bc7 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-peripherals.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-peripherals.h @@ -46,8 +46,6 @@ #ifndef BOARD_PERIPHERALS_H_ #define BOARD_PERIPHERALS_H_ /*---------------------------------------------------------------------------*/ -#include "ext-flash.h" -/*---------------------------------------------------------------------------*/ #include "board-conf.h" /*---------------------------------------------------------------------------*/ #define BOARD_CONF_HAS_SENSORS 0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c index 81d6c6e44..b460191bc 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c @@ -36,6 +36,8 @@ * CC1352R1_LAUNCHXL board. */ +#include "contiki.h" + #include #include #include @@ -538,6 +540,8 @@ const GPTimerCC26XX_Config GPTimerCC26XX_config[CC1352R1_LAUNCHXL_GPTIMERPARTSCO #include #include +#if TI_I2C_CONF_ENABLE + I2CCC26XX_Object i2cCC26xxObjects[CC1352R1_LAUNCHXL_I2CCOUNT]; const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1352R1_LAUNCHXL_I2CCOUNT] = { @@ -562,6 +566,8 @@ const I2C_Config I2C_config[CC1352R1_LAUNCHXL_I2CCOUNT] = { const uint_least8_t I2C_count = CC1352R1_LAUNCHXL_I2CCOUNT; +#endif /* TI_I2C_CONF_ENABLE */ + /* * =============================== NVS =============================== */ @@ -573,7 +579,9 @@ const uint_least8_t I2C_count = CC1352R1_LAUNCHXL_I2CCOUNT; #define SECTORSIZE 0x2000 #define REGIONSIZE (SECTORSIZE * 4) -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_ENABLE + +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE /* * Reserve flash sectors for NVS driver use by placing an uninitialized byte @@ -623,9 +631,9 @@ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { }, }; -#endif /* Board_EXCLUDE_NVS_INTERNAL_FLASH */ +#endif /* TI_NVS_CONF_NVS_INTERNAL_ENABLE */ -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE #define SPISECTORSIZE 0x1000 #define SPIREGIONSIZE (SPISECTORSIZE * 32) @@ -651,18 +659,18 @@ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { }, }; -#endif /* Board_EXCLUDE_NVS_EXTERNAL_FLASH */ +#endif /* TI_NVS_CONF_NVS_EXTERNAL_ENABLE */ /* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ const NVS_Config NVS_config[CC1352R1_LAUNCHXL_NVSCOUNT] = { -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE { .fxnTablePtr = &NVSCC26XX_fxnTable, .object = &nvsCC26xxObjects[0], .hwAttrs = &nvsCC26xxHWAttrs[0], }, #endif -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE { .fxnTablePtr = &NVSSPI25X_fxnTable, .object = &nvsSPI25XObjects[0], @@ -673,6 +681,8 @@ const NVS_Config NVS_config[CC1352R1_LAUNCHXL_NVSCOUNT] = { const uint_least8_t NVS_count = CC1352R1_LAUNCHXL_NVSCOUNT; +#endif /* TI_NVS_CONF_ENABLE */ + /* * =============================== PIN =============================== */ @@ -805,6 +815,8 @@ const uint_least8_t SD_count = CC1352R1_LAUNCHXL_SDCOUNT; #include #include +#if TI_SPI_CONF_ENABLE + SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1352R1_LAUNCHXL_SPICOUNT]; /* @@ -813,6 +825,7 @@ SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1352R1_LAUNCHXL_SPICOUNT]; * to satisfy the SDSPI driver requirement. */ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1352R1_LAUNCHXL_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .baseAddr = SSI0_BASE, .intNum = INT_SSI0_COMB, @@ -828,6 +841,8 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1352R1_LAUNCHXL_SPICOUNT] = { .csnPin = CC1352R1_LAUNCHXL_SPI0_CSN, .minDmaTransferSize = 10 }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .baseAddr = SSI1_BASE, .intNum = INT_SSI1_COMB, @@ -842,35 +857,45 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1352R1_LAUNCHXL_SPICOUNT] = { .clkPin = CC1352R1_LAUNCHXL_SPI1_CLK, .csnPin = CC1352R1_LAUNCHXL_SPI1_CSN, .minDmaTransferSize = 10 - } + }, +#endif }; const SPI_Config SPI_config[CC1352R1_LAUNCHXL_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC1352R1_LAUNCHXL_SPI0], .hwAttrs = &spiCC26XXDMAHWAttrs[CC1352R1_LAUNCHXL_SPI0] }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC1352R1_LAUNCHXL_SPI1], .hwAttrs = &spiCC26XXDMAHWAttrs[CC1352R1_LAUNCHXL_SPI1] }, +#endif }; const uint_least8_t SPI_count = CC1352R1_LAUNCHXL_SPICOUNT; +#endif /* TI_SPI_CONF_ENABLE */ + /* * =============================== UART =============================== */ #include #include +#if TI_UART_CONF_ENABLE + UARTCC26XX_Object uartCC26XXObjects[CC1352R1_LAUNCHXL_UARTCOUNT]; uint8_t uartCC26XXRingBuffer[CC1352R1_LAUNCHXL_UARTCOUNT][32]; const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1352R1_LAUNCHXL_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .baseAddr = UART0_BASE, .powerMngrId = PowerCC26XX_PERIPH_UART0, @@ -887,6 +912,8 @@ const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1352R1_LAUNCHXL_UARTCOUNT] = { .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, .errorFxn = NULL }, +#endif +#if TI_UART_CONF_UART1_ENABLE { .baseAddr = UART1_BASE, .powerMngrId = PowerCC26X2_PERIPH_UART1, @@ -902,24 +929,31 @@ const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1352R1_LAUNCHXL_UARTCOUNT] = { .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, .errorFxn = NULL - } + }, +#endif }; const UART_Config UART_config[CC1352R1_LAUNCHXL_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .fxnTablePtr = &UARTCC26XX_fxnTable, .object = &uartCC26XXObjects[CC1352R1_LAUNCHXL_UART0], .hwAttrs = &uartCC26XXHWAttrs[CC1352R1_LAUNCHXL_UART0] }, +#endif +#if TI_UART_CONF_UART1_ENABLE { .fxnTablePtr = &UARTCC26XX_fxnTable, .object = &uartCC26XXObjects[CC1352R1_LAUNCHXL_UART1], .hwAttrs = &uartCC26XXHWAttrs[CC1352R1_LAUNCHXL_UART1] }, +#endif }; const uint_least8_t UART_count = CC1352R1_LAUNCHXL_UARTCOUNT; +#endif /* TI_UART_CONF_ENABLE */ + /* * =============================== UDMA =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c index f654ab3f8..188605db9 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c @@ -35,6 +35,7 @@ * This file is responsible for setting up the board specific items for the * CC26X2R1_LAUNCHXL board. */ +#include "contiki.h" #include #include @@ -550,6 +551,8 @@ const GPTimerCC26XX_Config GPTimerCC26XX_config[CC26X2R1_LAUNCHXL_GPTIMERPARTSCO #include #include +#if TI_I2C_CONF_ENABLE + I2CCC26XX_Object i2cCC26xxObjects[CC26X2R1_LAUNCHXL_I2CCOUNT]; const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC26X2R1_LAUNCHXL_I2CCOUNT] = { @@ -574,6 +577,8 @@ const I2C_Config I2C_config[CC26X2R1_LAUNCHXL_I2CCOUNT] = { const uint_least8_t I2C_count = CC26X2R1_LAUNCHXL_I2CCOUNT; +#endif /* TI_I2C_CONF_ENABLE */ + /* * =============================== NVS =============================== */ @@ -585,7 +590,9 @@ const uint_least8_t I2C_count = CC26X2R1_LAUNCHXL_I2CCOUNT; #define SECTORSIZE 0x2000 #define REGIONSIZE (SECTORSIZE * 4) -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_ENABLE + +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE /* * Reserve flash sectors for NVS driver use by placing an uninitialized byte @@ -635,9 +642,9 @@ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { }, }; -#endif /* Board_EXCLUDE_NVS_INTERNAL_FLASH */ +#endif /* TI_NVS_CONF_NVS_INTERNAL_ENABLE */ -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE #define SPISECTORSIZE 0x1000 #define SPIREGIONSIZE (SPISECTORSIZE * 32) @@ -667,14 +674,14 @@ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { /* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ const NVS_Config NVS_config[CC26X2R1_LAUNCHXL_NVSCOUNT] = { -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE { .fxnTablePtr = &NVSCC26XX_fxnTable, .object = &nvsCC26xxObjects[0], .hwAttrs = &nvsCC26xxHWAttrs[0], }, #endif -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE { .fxnTablePtr = &NVSSPI25X_fxnTable, .object = &nvsSPI25XObjects[0], @@ -685,6 +692,8 @@ const NVS_Config NVS_config[CC26X2R1_LAUNCHXL_NVSCOUNT] = { const uint_least8_t NVS_count = CC26X2R1_LAUNCHXL_NVSCOUNT; +#endif /* TI_NVS_CONF_ENABLE */ + /* * =============================== PIN =============================== */ @@ -804,6 +813,8 @@ const uint_least8_t SD_count = CC26X2R1_LAUNCHXL_SDCOUNT; #include #include +#if TI_SPI_CONF_ENABLE + SPICC26XXDMA_Object spiCC26XXDMAObjects[CC26X2R1_LAUNCHXL_SPICOUNT]; /* @@ -812,6 +823,7 @@ SPICC26XXDMA_Object spiCC26XXDMAObjects[CC26X2R1_LAUNCHXL_SPICOUNT]; * to satisfy the SDSPI driver requirement. */ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC26X2R1_LAUNCHXL_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .baseAddr = SSI0_BASE, .intNum = INT_SSI0_COMB, @@ -827,6 +839,8 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC26X2R1_LAUNCHXL_SPICOUNT] = { .csnPin = CC26X2R1_LAUNCHXL_SPI0_CSN, .minDmaTransferSize = 10 }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .baseAddr = SSI1_BASE, .intNum = INT_SSI1_COMB, @@ -841,35 +855,45 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC26X2R1_LAUNCHXL_SPICOUNT] = { .clkPin = CC26X2R1_LAUNCHXL_SPI1_CLK, .csnPin = CC26X2R1_LAUNCHXL_SPI1_CSN, .minDmaTransferSize = 10 - } + }, +#endif }; const SPI_Config SPI_config[CC26X2R1_LAUNCHXL_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC26X2R1_LAUNCHXL_SPI0], .hwAttrs = &spiCC26XXDMAHWAttrs[CC26X2R1_LAUNCHXL_SPI0] }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC26X2R1_LAUNCHXL_SPI1], .hwAttrs = &spiCC26XXDMAHWAttrs[CC26X2R1_LAUNCHXL_SPI1] }, +#endif }; const uint_least8_t SPI_count = CC26X2R1_LAUNCHXL_SPICOUNT; +#endif /* TI_SPI_CONF_ENABLE */ + /* * =============================== UART =============================== */ #include #include +#if TI_UART_CONF_ENABLE + UARTCC26XX_Object uartCC26XXObjects[CC26X2R1_LAUNCHXL_UARTCOUNT]; uint8_t uartCC26XXRingBuffer[CC26X2R1_LAUNCHXL_UARTCOUNT][32]; const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC26X2R1_LAUNCHXL_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .baseAddr = UART0_BASE, .powerMngrId = PowerCC26XX_PERIPH_UART0, @@ -886,6 +910,8 @@ const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC26X2R1_LAUNCHXL_UARTCOUNT] = { .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, .errorFxn = NULL }, +#endif +#if TI_UART_CONF_UART1_ENABLE { .baseAddr = UART1_BASE, .powerMngrId = PowerCC26X2_PERIPH_UART1, @@ -901,24 +927,31 @@ const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC26X2R1_LAUNCHXL_UARTCOUNT] = { .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, .errorFxn = NULL - } + }, +#endif }; const UART_Config UART_config[CC26X2R1_LAUNCHXL_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .fxnTablePtr = &UARTCC26XX_fxnTable, .object = &uartCC26XXObjects[CC26X2R1_LAUNCHXL_UART0], .hwAttrs = &uartCC26XXHWAttrs[CC26X2R1_LAUNCHXL_UART0] }, +#endif +#if TI_UART_CONF_UART1_ENABLE { .fxnTablePtr = &UARTCC26XX_fxnTable, .object = &uartCC26XXObjects[CC26X2R1_LAUNCHXL_UART1], .hwAttrs = &uartCC26XXHWAttrs[CC26X2R1_LAUNCHXL_UART1] }, +#endif }; const uint_least8_t UART_count = CC26X2R1_LAUNCHXL_UARTCOUNT; +#endif /* TI_UART_CONF_ENABLE */ + /* * =============================== UDMA =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/ext-flash.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/ext-flash.c deleted file mode 100644 index a78a5e764..000000000 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/ext-flash.c +++ /dev/null @@ -1,468 +0,0 @@ -/* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/*---------------------------------------------------------------------------*/ -/** - * \addtogroup sensortag-cc26xx-ext-flash - * @{ - * - * \file - * Sensortag/LaunchPad External Flash Driver - */ -/*---------------------------------------------------------------------------*/ -#include -#include -#include -/*---------------------------------------------------------------------------*/ -#include "contiki.h" -#include "ext-flash.h" -#include "ti-lib.h" -/*---------------------------------------------------------------------------*/ -#include -#include -#include -/*---------------------------------------------------------------------------*/ -static PIN_Config pin_table[] = { - Board_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, - PIN_TERMINATE -}; - -static PIN_State pin_state; -static PIN_Handle pin_handle; - -static SPI_Handle spi_handle; - -static bool ext_flash_opened; -/*---------------------------------------------------------------------------*/ -#define SPI_BIT_RATE 4000000 - -/* Instruction codes */ -#define BLS_CODE_PROGRAM 0x02 /**< Page Program */ -#define BLS_CODE_READ 0x03 /**< Read Data */ -#define BLS_CODE_READ_STATUS 0x05 /**< Read Status Register */ -#define BLS_CODE_WRITE_ENABLE 0x06 /**< Write Enable */ -#define BLS_CODE_SECTOR_ERASE 0x20 /**< Sector Erase */ -#define BLS_CODE_MDID 0x90 /**< Manufacturer Device ID */ - -#define BLS_CODE_DP 0xB9 /**< Power down */ -#define BLS_CODE_RDP 0xAB /**< Power standby */ - -/* Erase instructions */ -#define BLS_CODE_ERASE_4K 0x20 /**< Sector Erase */ -#define BLS_CODE_ERASE_32K 0x52 -#define BLS_CODE_ERASE_64K 0xD8 -#define BLS_CODE_ERASE_ALL 0xC7 /**< Mass Erase */ - -/* Bitmasks of the status register */ -#define BLS_STATUS_SRWD_BM 0x80 -#define BLS_STATUS_BP_BM 0x0C -#define BLS_STATUS_WEL_BM 0x02 -#define BLS_STATUS_WIP_BM 0x01 - -#define BLS_STATUS_BIT_BUSY 0x01 /**< Busy bit of the status register */ - -/* Part specific constants */ -#define BLS_PROGRAM_PAGE_SIZE 0x100 /**< Page size 0x100 */ -#define BLS_ERASE_SECTOR_SIZE 0x1000 /**< Sector size 0x1000 */ -/*---------------------------------------------------------------------------*/ -typedef struct -{ - uint8_t manfId; /**< Manufacturer ID */ - uint8_t devId; /**< Device ID */ -} ExtFlashInfo; -/* Supported flash devices */ -static const ExtFlashInfo supported_devices[] = -{ - { - .manfId = 0xC2, /**< Macronics MX25R1635F */ - .devId = 0x15 - }, - { - .manfId = 0xC2, /**< Macronics MX25R8035F */ - .devId = 0x14 - }, - { - .manfId = 0xEF, /**< WinBond W25X40CL */ - .devId = 0x12 - }, - { - .manfId = 0xEF, /**< WinBond W25X20CL */ - .devId = 0x11 - } -}; -/*---------------------------------------------------------------------------*/ -static bool -spi_write(const uint8_t *buf, size_t len) -{ - SPI_Transaction spiTransaction; - spiTransaction.count = len; - spiTransaction.txBuf = (void *)buf; - spiTransaction.rxBuf = NULL; - - return SPI_transfer(spi_handle, &spiTransaction); -} -/*---------------------------------------------------------------------------*/ -static bool -spi_read(uint8_t *buf, size_t len) -{ - SPI_Transaction spiTransaction; - spiTransaction.count = len; - spiTransaction.txBuf = NULL; - spiTransaction.rxBuf = buf; - - return SPI_transfer(spi_handle, &spiTransaction); -} -/*---------------------------------------------------------------------------*/ -static void -select(void) -{ - PIN_setOutputValue(pin_handle, Board_SPI_FLASH_CS, 1); -} -/*---------------------------------------------------------------------------*/ -static void -deselect(void) -{ - PIN_setOutputValue(pin_handle, Board_SPI_FLASH_CS, 0); -} -/*---------------------------------------------------------------------------*/ -static bool -wait_ready(void) -{ - const uint8_t wbuf[] = { BLS_CODE_READ_STATUS }; - uint8_t rbuf[1] = { 0x0 }; - - /* TODO are 1000 tries enough? */ - for (size_t i = 0; i < 1000; ++i) { - select(); - - const bool spi_ok = spi_write(wbuf, sizeof(wbuf)) - && spi_read(rbuf, sizeof(rbuf)); - - deselect(); - - if (!spi_ok) { - /* Error */ - return false; - } - if (!(rbuf[0] & BLS_STATUS_BIT_BUSY)) { - /* Now ready */ - return true; - } - } - - return false; -} -/*---------------------------------------------------------------------------*/ -static bool -power_standby(void) -{ - const uint8_t cmd[] = { BLS_CODE_RDP }; - - select(); - - const bool spi_ok = spi_write(cmd, sizeof(cmd)); - - deselect(); - - if (!spi_ok) { - return false; - } - - /* Waking up of the device is manufacturer dependent. - * for a Winond chip-set, once the request to wake up the flash has been - * send, CS needs to stay high at least 3us (for Winbond part) - * for chip-set like Macronix, it can take up to 35us. - * 3 cycles per loop: 560 loops @ 48 MHz = 35 us */ - ti_lib_cpu_delay(560); - - return wait_ready(); -} -/*---------------------------------------------------------------------------*/ -static bool -power_down(void) -{ - const uint8_t cmd[] = { BLS_CODE_DP }; - - select(); - - const bool spi_ok = spi_write(cmd, sizeof(cmd)); - - deselect(); - - return spi_ok; -} -/*---------------------------------------------------------------------------*/ -static bool -write_enable(void) -{ - const uint8_t wbuf[] = { BLS_CODE_WRITE_ENABLE }; - - select(); - - const bool spi_ok = spi_write(wbuf, sizeof(wbuf)); - - deselect(); - - return spi_ok; -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Verify the flash part. - * \retval bool true on success; else, false - */ -static bool -verify_part(void) -{ - const uint8_t wbuf[] = { BLS_CODE_MDID, 0xFF, 0xFF, 0x00 }; - uint8_t rbuf[2] = { 0x0 }; - - const bool spi_ok = spi_write(wbuf, sizeof(wbuf)) - && spi_read(rbuf, sizeof(rbuf)); - - if (!spi_ok) { - return false; - } - - const ExtFlashInfo curr_device = { - .manfId = rbuf[0], - .devId = rbuf[1] - }; - - const size_t num_devices = sizeof(supported_devices) / sizeof(supported_devices[0]); - for (size_t i = 0; i < num_devices; ++i) { - if (curr_device.manfId == supported_devices[i].manfId && - curr_device.devId == supported_devices[i].devId) { - return true; - } - } - - return false; -} -/*---------------------------------------------------------------------------*/ -bool -ext_flash_open() -{ - if (ext_flash_opened) { - return true; - } - - pin_handle = PIN_open(&pin_state, pin_table); - - if (pin_handle == NULL) { - return false; - } - - SPI_Params spiParams; - SPI_Params_init(&spiParams); - spiParams.bitRate = SPI_BIT_RATE; - spiParams.mode = SPI_MASTER; - spiParams.transferMode = SPI_MODE_BLOCKING; - - spi_handle = SPI_open(Board_SPI0, &spiParams); - - if (spi_handle == NULL) { - PIN_close(pin_handle); - return false; - } - - ext_flash_opened = true; - - deselect(); - - const bool is_powered = power_standby(); - if (!is_powered) { - ext_flash_close(); - return false; - } - - return verify_part(); -} -/*---------------------------------------------------------------------------*/ -void -ext_flash_close() -{ - if (!ext_flash_opened) { - return; - } - ext_flash_opened = false; - - power_down(); - - SPI_close(spi_handle); - PIN_close(pin_handle); -} -/*---------------------------------------------------------------------------*/ -bool -ext_flash_read(size_t offset, size_t length, uint8_t *buf) -{ - if (spi_handle == NULL || buf == NULL) { - return false; - } - - if (length == 0) { - return true; - } - - const bool is_ready = wait_ready(); - if (!is_ready) { - return false; - } - - const uint8_t wbuf[] = { - BLS_CODE_READ, - (offset >> 16) & 0xFF, - (offset >> 8) & 0xFF, - (offset >> 0) & 0xFF, - }; - - select(); - - const bool spi_ok = spi_write(wbuf, sizeof(wbuf)) - && spi_read(buf, length); - - deselect(); - - return (spi_ok); -} -/*---------------------------------------------------------------------------*/ -bool -ext_flash_write(size_t offset, size_t length, const uint8_t *buf) -{ - if (spi_handle == NULL || buf == NULL) { - return false; - } - - uint8_t wbuf[4] = { BLS_CODE_PROGRAM, 0, 0, 0 }; - - while (length > 0) - { - /* Wait till previous erase/program operation completes */ - if (!wait_ready()) { - return false; - } - - /* Enable writing */ - if (!write_enable()) { - return false; - } - - /* Interim length per instruction */ - size_t ilen = BLS_PROGRAM_PAGE_SIZE - (offset % BLS_PROGRAM_PAGE_SIZE); - if (length < ilen) { - ilen = length; - } - - wbuf[1] = (offset >> 16) & 0xFF; - wbuf[2] = (offset >> 8) & 0xFF; - wbuf[3] = (offset >> 0) & 0xFF; - - offset += ilen; - length -= ilen; - - /* Up to 100ns CS hold time (which is not clear - * whether it's application only in between reads) - * is not imposed here since above instructions - * should be enough to delay - * as much. */ - select(); - - const bool spi_ok = spi_write(wbuf, sizeof(wbuf)) - && spi_write(buf, ilen); - - buf += ilen; - - deselect(); - - if (!spi_ok) { - return false; - } - } - - return true; -} -/*---------------------------------------------------------------------------*/ -bool -ext_flash_erase(size_t offset, size_t length) -{ - /* Note that Block erase might be more efficient when the floor map - * is well planned for OTA but to simplify for the temporary implemetation, - * sector erase is used blindly. */ - uint8_t wbuf[4] = { BLS_CODE_SECTOR_ERASE, 0x0, 0x0, 0x0 }; - - const size_t endoffset = offset + length - 1; - offset = (offset / BLS_ERASE_SECTOR_SIZE) * BLS_ERASE_SECTOR_SIZE; - const size_t numsectors = (endoffset - offset + BLS_ERASE_SECTOR_SIZE - 1) / BLS_ERASE_SECTOR_SIZE; - - for (size_t i = 0; i < numsectors; ++i) { - /* Wait till previous erase/program operation completes */ - if (!wait_ready()) { - return false; - } - - /* Enable writing */ - if (!write_enable()) { - return false; - } - - wbuf[1] = (offset >> 16) & 0xFF; - wbuf[2] = (offset >> 8) & 0xFF; - wbuf[3] = (offset >> 0) & 0xFF; - - select(); - - const bool spi_ok = spi_write(wbuf, sizeof(wbuf)); - - deselect(); - - if (!spi_ok) { - return false; - } - - offset += BLS_ERASE_SECTOR_SIZE; - } - - return true; -} -/*---------------------------------------------------------------------------*/ -bool -ext_flash_test(void) -{ - const bool ret = ext_flash_open(); - ext_flash_close(); - - return ret; -} -/*---------------------------------------------------------------------------*/ -void -ext_flash_init() -{ - SPI_init(); -} -/*---------------------------------------------------------------------------*/ -/** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/ext-flash.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/ext-flash.h deleted file mode 100644 index 5f2717edb..000000000 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/ext-flash.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/*---------------------------------------------------------------------------*/ -/** - * \addtogroup common-cc26xx-peripherals - * @{ - * - * \defgroup sensortag-cc26xx-ext-flash SensorTag/LaunchPad External Flash - * @{ - * - * \file - * Header file for the Sensortag/LaunchPad External Flash Driver - */ -/*---------------------------------------------------------------------------*/ -#ifndef EXT_FLASH_H_ -#define EXT_FLASH_H_ -/*---------------------------------------------------------------------------*/ -#include -#include -#include -/*---------------------------------------------------------------------------*/ -/** - * \brief Initialize storage driver. - * \return True when successful. - */ -bool ext_flash_open(void); - -/** - * \brief Close the storage driver - * - * This call will put the device in its lower power mode (power down). - */ -void ext_flash_close(void); - -/** - * \brief Read storage content - * \param offset Address to read from - * \param length Number of bytes to read - * \param buf Buffer where to store the read bytes - * \return True when successful. - * - * buf must be allocated by the caller - */ -bool ext_flash_read(size_t offset, size_t length, uint8_t *buf); - -/** - * \brief Erase storage sectors corresponding to the range. - * \param offset Address to start erasing - * \param length Number of bytes to erase - * \return True when successful. - * - * The erase operation will be sector-wise, therefore a call to this function - * will generally start the erase procedure at an address lower than offset - */ -bool ext_flash_erase(size_t offset, size_t length); - -/** - * \brief Write to storage sectors. - * \param offset Address to write to - * \param length Number of bytes to write - * \param buf Buffer holding the bytes to be written - * - * \return True when successful. - */ -bool ext_flash_write(size_t offset, size_t length, const uint8_t *buf); - -/** - * \brief Test the flash (power on self-test) - * \return True when successful. - */ -bool ext_flash_test(void); - -/** - * \brief Initialise the external flash - * - * This function will explicitly put the part in its lowest power mode - * (power-down). - * - * In order to perform any operation, the caller must first wake the device - * up by calling ext_flash_open() - */ -void ext_flash_init(void); -/*---------------------------------------------------------------------------*/ -#endif /* EXT_FLASH_H_ */ -/*---------------------------------------------------------------------------*/ -/** - * @} - * @} - */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/platform.c b/arch/platform/simplelink/cc13xx-cc26xx/platform.c index 5a699bb34..f5a23fee6 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/platform.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/platform.c @@ -57,8 +57,8 @@ #include DeviceFamily_constructPath(inc/hw_cpu_scs.h) #include -#include #include +#include #include #include #include @@ -170,9 +170,19 @@ platform_init_stage_one(void) fade(LEDS_RED); /* TI Drivers init */ - I2C_init(); - SPI_init(); +#if TI_UART_CONF_ENABLE UART_init(); + uart0_init(); +#endif +#if TI_I2C_CONF_ENABLE + I2C_init(); +#endif +#if TI_SPI_CONF_ENABLE + SPI_init(); +#endif +#if TI_NVS_CONF_ENABLE + NVS_init(); +#endif fade(LEDS_GREEN); @@ -183,7 +193,6 @@ platform_init_stage_one(void) void platform_init_stage_two(void) { - uart0_init(); serial_line_init(); #if BUILD_WITH_SHELL @@ -203,7 +212,9 @@ platform_init_stage_two(void) void platform_init_stage_three(void) { +#if RF_BLE_BEACON_ENABLE rf_ble_beacond_init(); +#endif radio_value_t chan = 0, pan = 0; @@ -219,8 +230,11 @@ platform_init_stage_three(void) ChipInfo_SupportsPROPRIETARY() ? "Yes" : "No", ChipInfo_SupportsBLE() ? "Yes" : "No"); - LOG_INFO("Operating frequency on %s\n", - (RF_CORE_MODE == RF_CORE_MODE_SUB_1_GHZ) ? "Sub-1 GHz" : "2.4 GHz"); +#if (RF_MODE == RF_MODE_SUB_1_GHZ) + LOG_INFO("Operating frequency on Sub-1 GHz\n"); +#else + LOG_INFO("Operating frequency on 2.4 GHz\n"); +#endif LOG_INFO("RF: Channel %d, PANID 0x%04X\n", chan, pan); LOG_INFO("Node ID: %d\n", g_nodeId); From f4a8cba3715195a0b86d6c686b3bfe643db31dd1 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Mon, 16 Jul 2018 16:39:19 +0200 Subject: [PATCH 269/485] Rehauled doxygen commenting and fixed TI drivers configuration --- arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h | 33 +- arch/cpu/cc13xx-cc26xx/doxygen-group.txt | 16 + .../rf-settings/cc26x0/ble-settings.c | 2 +- .../simplelink/cc13xx-cc26xx/contiki-conf.h | 20 +- .../cc13xx-cc26xx/launchpad/board-conf.h | 37 +- .../launchpad/board-peripherals.h | 18 +- .../launchpad/button-sensor-arch.c | 44 +- .../launchpad/cc1310/CC1310_LAUNCHXL.c | 111 +++-- .../launchpad/cc1310/CC1310_LAUNCHXL.h | 14 +- .../launchpad/cc1312r1/CC1312R1_LAUNCHXL.c | 111 +++-- .../launchpad/cc1312r1/CC1312R1_LAUNCHXL.h | 14 +- .../launchpad/cc1350-4/CC1350_LAUNCHXL_433.c | 103 ++-- .../launchpad/cc1350-4/CC1350_LAUNCHXL_433.h | 2 + .../launchpad/cc1350/CC1350_LAUNCHXL.c | 109 ++-- .../launchpad/cc1350/CC1350_LAUNCHXL.h | 14 +- .../launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.c | 113 +++-- .../launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h | 20 +- .../launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.c | 113 +++-- .../launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.h | 20 +- .../launchpad/cc1352p1/CC1352P1_LAUNCHXL.c | 113 +++-- .../launchpad/cc1352p1/CC1352P1_LAUNCHXL.h | 16 +- .../launchpad/cc1352r1/CC1352R1_LAUNCHXL.c | 65 ++- .../launchpad/cc1352r1/CC1352R1_LAUNCHXL.h | 16 +- .../launchpad/cc2650/CC2650_LAUNCHXL.c | 107 ++-- .../launchpad/cc2650/CC2650_LAUNCHXL.h | 14 +- .../launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c | 67 ++- .../launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h | 16 +- .../cc13xx-cc26xx/launchpad/leds-arch.c | 12 +- .../simplelink/cc13xx-cc26xx/platform.c | 107 ++-- .../sensortag/Makefile.sensortag | 2 +- .../cc13xx-cc26xx/sensortag/bmp-280-sensor.c | 96 ++-- .../cc13xx-cc26xx/sensortag/bmp-280-sensor.h | 17 +- .../cc13xx-cc26xx/sensortag/board-conf.h | 40 +- .../sensortag/board-peripherals.h | 27 +- .../sensortag/button-sensor-arch.c | 56 ++- .../cc13xx-cc26xx/sensortag/buzzer.c | 14 +- .../cc13xx-cc26xx/sensortag/buzzer.h | 23 +- .../sensortag/cc1350/CC1350STK.c | 119 +++-- .../sensortag/cc1350/CC1350STK.h | 14 + .../sensortag/cc1350/leds-arch.c | 11 +- .../sensortag/cc1350/leds-arch.h | 22 +- .../sensortag/cc2650/CC2650STK.c | 121 +++-- .../sensortag/cc2650/CC2650STK.h | 15 + .../sensortag/cc2650/leds-arch.c | 12 +- .../sensortag/cc2650/leds-arch.h | 22 +- .../cc13xx-cc26xx/sensortag/ext-flash.c | 468 ------------------ .../cc13xx-cc26xx/sensortag/ext-flash.h | 116 ----- .../cc13xx-cc26xx/sensortag/hdc-1000-sensor.c | 142 +++--- .../cc13xx-cc26xx/sensortag/hdc-1000-sensor.h | 23 +- .../cc13xx-cc26xx/sensortag/mpu-9250-sensor.c | 158 +++--- .../cc13xx-cc26xx/sensortag/mpu-9250-sensor.h | 89 ++-- .../cc13xx-cc26xx/sensortag/opt-3001-sensor.c | 211 +++++--- .../cc13xx-cc26xx/sensortag/opt-3001-sensor.h | 46 +- .../sensortag/sensortag-sensors.c | 10 +- .../cc13xx-cc26xx/sensortag/tmp-007-sensor.c | 166 ++++--- .../cc13xx-cc26xx/sensortag/tmp-007-sensor.h | 52 +- .../cc13xx-cc26xx/srf06/als-sensor.c | 13 +- .../cc13xx-cc26xx/srf06/als-sensor.h | 9 +- .../cc13xx-cc26xx/srf06/board-conf.h | 39 +- .../cc13xx-cc26xx/srf06/board-peripherals.h | 20 +- .../cc13xx-cc26xx/srf06/button-sensor-arch.c | 85 ++-- .../cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c | 102 +++- .../cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h | 12 +- .../srf06/cc13x0/Makefile.cc13x0 | 2 +- .../cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c | 103 +++- .../cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h | 12 +- .../cc13xx-cc26xx/srf06/leds-arch.c | 19 +- .../cc13xx-cc26xx/srf06/srf06-sensors.c | 7 +- 68 files changed, 2252 insertions(+), 1710 deletions(-) create mode 100644 arch/cpu/cc13xx-cc26xx/doxygen-group.txt delete mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/ext-flash.c delete mode 100644 arch/platform/simplelink/cc13xx-cc26xx/sensortag/ext-flash.h diff --git a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h index 47aba1d9b..365b1e27a 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h +++ b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h @@ -220,7 +220,7 @@ #endif #ifndef TI_UART_CONF_UART1_ENABLE -#define TI_UART_CONF_UART1_ENABLE 1 +#define TI_UART_CONF_UART1_ENABLE 0 #endif #ifndef TI_UART_CONF_BAUD_RATE @@ -237,7 +237,7 @@ #endif #ifndef TI_SPI_CONF_SPI1_ENABLE -#define TI_SPI_CONF_SPI1_ENABLE 1 +#define TI_SPI_CONF_SPI1_ENABLE 0 #endif /* I2C */ @@ -245,6 +245,10 @@ #define TI_I2C_CONF_ENABLE 1 #endif +#ifndef TI_I2C_CONF_I2C0_ENABLE +#define TI_I2C_CONF_I2C0_ENABLE TI_I2C_CONF_ENABLE +#endif + /* NVS */ #ifndef TI_NVS_CONF_ENABLE #define TI_NVS_CONF_ENABLE 1 @@ -257,6 +261,31 @@ #ifndef TI_NVS_CONF_NVS_EXTERNAL_ENABLE #define TI_NVS_CONF_NVS_EXTERNAL_ENABLE TI_NVS_CONF_ENABLE #endif + +/* Display */ +#ifndef TI_DISPLAY_CONF_ENABLE +#define TI_DISPLAY_CONF_ENABLE 0 +#endif + +/* UART Display uses UART0 */ +#ifndef TI_DISPLAY_CONF_UART_ENABLE +#define TI_DISPLAY_CONF_UART_ENABLE TI_UART_CONF_UART0_ENABLE +#endif + +#ifndef TI_DISPLAY_CONF_USE_UART_ANSI +#define TI_DISPLAY_CONF_USE_UART_ANSI 0 +#endif + +/* LCD Display uses SPI0 */ +#ifndef TI_DISPLAY_CONF_LCD_ENABLE +#define TI_DISPLAY_CONF_LCD_ENABLE TI_SPI_CONF_SPI0_ENABLE +#endif + +/* SD card */ +#ifndef TI_SD_CONF_ENABLE +#define TI_SD_CONF_ENABLE 0 +#endif + /** @} */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/cpu/cc13xx-cc26xx/doxygen-group.txt b/arch/cpu/cc13xx-cc26xx/doxygen-group.txt new file mode 100644 index 000000000..ca6159c44 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/doxygen-group.txt @@ -0,0 +1,16 @@ +/** + * \defgroup cc13xx-cc26xx-cpu The TI SimpleLink CC13xx and CC26xx SoC + * + * This group documents the TI CC13xx and CC26xx CPUs. The two CPU families are + * very similar, with the main difference being related to radio capability. + * + * Documentation in this group should be considered to be applicable to both + * families, unless explicitly stated otherwise. + * + * \ingroup cpu + */ + +/** + * \defgroup cc13xx-cc26xx-platform TI SimpleLink CC13xx/CC26xx platform + * \ingroup platform + */ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.c index d803b0b60..048c9399d 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.c @@ -50,7 +50,7 @@ #include /*---------------------------------------------------------------------------*/ -#include "ieee_settings.h" +#include "ble-settings.h" /*---------------------------------------------------------------------------*/ /* TI-RTOS RF Mode Object */ RF_Mode rf_ble_mode = diff --git a/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h b/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h index 69659c0b1..212f4fd48 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,27 +28,33 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /** - * \addtogroup cc26xx-srf-tag + * \addtogroup cc13xx-cc26xx-platform * @{ * * \file - * Configuration for the srf06-cc26xx platform + * Configuration for the SimpleLink CC13xx/CC26xx platform. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #ifndef CONTIKI_CONF_H_ #define CONTIKI_CONF_H_ /*---------------------------------------------------------------------------*/ -#include - #include "board-conf.h" /*---------------------------------------------------------------------------*/ /* Include Project Specific conf */ #ifdef PROJECT_CONF_PATH #include PROJECT_CONF_PATH -#endif /* PROJECT_CONF_PATH */ +#endif /*---------------------------------------------------------------------------*/ /* Include CPU-related configuration */ #include "cc13xx-cc26xx-conf.h" /*---------------------------------------------------------------------------*/ +/* Must be included after cc13xx-cc26xx-conf.h */ +#include +/*---------------------------------------------------------------------------*/ #endif /* CONTIKI_CONF_H_ */ -/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * @} + */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-conf.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-conf.h index 9a123bcf1..f700baa08 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-conf.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-conf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,27 +27,31 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ -/** \addtogroup cc26xx-srf-tag +/** + * \addtogroup cc13xx-cc26xx-platform * @{ * * \defgroup launchpad-peripherals LaunchPad peripherals * - * Defines related to LaunchPad peripherals. + * Defines related to configuring LaunchPad peripherals. All LaunchPads + * are identical to a very large extent. Everything documented within this + * group applies to both sensortags * * @{ * * \file - * Header file with definitions related to LaunchPad peripherals - * - * \note Do not include this file directly. + * Header file with definitions related to LaunchPad boards. + * \author + * Edvard Pettersen + * \note + * This file should not be included directly */ /*---------------------------------------------------------------------------*/ #ifndef BOARD_CONF_H_ #define BOARD_CONF_H_ /*---------------------------------------------------------------------------*/ /** - * \name LED configurations + * \name LED configurations for the dev/leds.h API. * * Those values are not meant to be modified by the user * @{ @@ -58,9 +62,26 @@ #define LEDS_CONF_GREEN 1 #define LEDS_CONF_ALL ((1 << LEDS_CONF_COUNT) - 1) +/** @} */ /*---------------------------------------------------------------------------*/ +/** + * \name Button configurations for the dev/button-hal.h API. + * + * Those values are not meant to be modified by the user + * @{ + */ #define BUTTON_HAL_ID_KEY_LEFT 0 #define BUTTON_HAL_ID_KEY_RIGHT 1 +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \name LaunchPad does not have any sensors. + * + * Those values are not meant to be modified by the user + * @{ + */ +#define BOARD_CONF_HAS_SENSORS 0 +/** @} */ /*---------------------------------------------------------------------------*/ #endif /* BOARD_CONF_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-peripherals.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-peripherals.h index 9b45e3bc7..528ddb26f 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-peripherals.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/board-peripherals.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,20 +27,22 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ -/** \addtogroup cc26xx-srf-tag +/** + * \addtogroup cc13xx-cc26xx-platform * @{ * * \defgroup launchpad-peripherals LaunchPad peripherals * - * Defines related to LaunchPad peripherals. + * Defines related to configuring LaunchPad peripherals. All + * LaunchPads are identical to a very large extent. Everything + * documented within this group applies to all LaunchPads. * * @{ * * \file - * Header file with definitions related to LaunchPad peripherals - * - * \note Do not include this file directly. + * Header file with definitions related to LaunchPad boards. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #ifndef BOARD_PERIPHERALS_H_ @@ -48,8 +50,6 @@ /*---------------------------------------------------------------------------*/ #include "board-conf.h" /*---------------------------------------------------------------------------*/ -#define BOARD_CONF_HAS_SENSORS 0 -/*---------------------------------------------------------------------------*/ #endif /* BOARD_PERIPHERALS_H_ */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c index 073c620e6..239869616 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c @@ -27,37 +27,41 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup launchpad-button-sensor + * \addtogroup launchpad-peripherals * @{ * * \file - * Driver for LaunchPad buttons + * Button HAL definitions for the LaunchPad buttons. Common across + * all CC13xx/CC26xx LaunchPad boards. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "dev/button-hal.h" - +/*---------------------------------------------------------------------------*/ #include /*---------------------------------------------------------------------------*/ -/* Key left button, AKA BTN-1 */ -BUTTON_HAL_BUTTON(key_left, /**< Name */ - "Key Left", /**< Description */ - Board_PIN_BTN1, /**< PIN */ - GPIO_HAL_PIN_CFG_INPUT_PULLUP | - GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ - BUTTON_HAL_ID_KEY_LEFT, /**< Unique ID */ - true); /**< Negative logic */ +/* Key left button, AKA BTN-1. */ +BUTTON_HAL_BUTTON( + key_left, /**< Name */ + "Key Left", /**< Description */ + Board_PIN_BTN1, /**< Board PIN */ + GPIO_HAL_PIN_CFG_INPUT_PULLUP | + GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_KEY_LEFT, /**< Unique ID */ + true); /**< Negative logic */ -/* Key right button, AKA BTN-2 */ -BUTTON_HAL_BUTTON(key_right, /**< Name */ - "Key Right", /**< Description */ - Board_PIN_BTN2, /**< PIN */ - GPIO_HAL_PIN_CFG_INPUT_PULLUP | - GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ - BUTTON_HAL_ID_KEY_RIGHT, /**< Unique ID */ - true); /**< Negative logic */ +/* Key right button, AKA BTN-2. */ +BUTTON_HAL_BUTTON( + key_right, /**< Name */ + "Key Right", /**< Description */ + Board_PIN_BTN2, /**< Board PIN */ + GPIO_HAL_PIN_CFG_INPUT_PULLUP | + GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_KEY_RIGHT, /**< Unique ID */ + true); /**< Negative logic */ /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTONS(&key_left, &key_right); /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.c index d2601e3f2..df5454f5d 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.c @@ -253,19 +253,21 @@ const CryptoCC26XX_Config CryptoCC26XX_config[CC1310_LAUNCHXL_CRYPTOCOUNT] = { #include #include +#if TI_DISPLAY_CONF_ENABLE + +#if TI_DISPLAY_CONF_UART_ENABLE + +#if !(TI_UART_CONF_UART0_ENABLE) +#error "Display UART driver requires UART0" +#endif + #ifndef BOARD_DISPLAY_UART_STRBUF_SIZE #define BOARD_DISPLAY_UART_STRBUF_SIZE 128 #endif -#ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 -#endif +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; DisplayUart_Object displayUartObject; -DisplaySharp_Object displaySharpObject; - -static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; -static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; const DisplayUart_HWAttrs displayUartHWAttrs = { .uartIdx = CC1310_LAUNCHXL_UART0, @@ -275,6 +277,22 @@ const DisplayUart_HWAttrs displayUartHWAttrs = { .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, }; +#endif /* TI_DISPLAY_CONF_UART_ENABLE */ + +#if TI_DISPLAY_CONF_LCD_ENABLE + +#if !(TI_SPI_CONF_SPI0_ENABLE) +#error "Display LCD driver requires SPI0" +#endif + +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 +#endif + +static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; + +DisplaySharp_Object displaySharpObject; + const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .spiIndex = CC1310_LAUNCHXL_SPI0, .csPin = CC1310_LAUNCHXL_GPIO_LCD_CS, @@ -285,27 +303,18 @@ const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .displayBuf = sharpDisplayBuf, }; -#ifndef BOARD_DISPLAY_USE_UART -#define BOARD_DISPLAY_USE_UART 1 -#endif -#ifndef BOARD_DISPLAY_USE_UART_ANSI -#define BOARD_DISPLAY_USE_UART_ANSI 0 -#endif -#ifndef BOARD_DISPLAY_USE_LCD -#define BOARD_DISPLAY_USE_LCD 0 -#endif +#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ /* * This #if/#else is needed to workaround a problem with the * IAR compiler. The IAR compiler doesn't like the empty array * initialization. (IAR Error[Pe1345]) */ -#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) const Display_Config Display_config[] = { -#if (BOARD_DISPLAY_USE_UART) +#if TI_DISPLAY_CONF_UART_ENABLE { -# if (BOARD_DISPLAY_USE_UART_ANSI) +# if TI_DISPLAY_CONF_USE_UART_ANSI .fxnTablePtr = &DisplayUartAnsi_fxnTable, # else /* Default to minimal UART with no cursor placement */ .fxnTablePtr = &DisplayUartMin_fxnTable, @@ -314,7 +323,7 @@ const Display_Config Display_config[] = { .hwAttrs = &displayUartHWAttrs, }, #endif -#if (BOARD_DISPLAY_USE_LCD) +#if TI_DISPLAY_CONF_LCD_ENABLE { .fxnTablePtr = &DisplaySharp_fxnTable, .object = &displaySharpObject, @@ -330,7 +339,7 @@ const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Conf const Display_Config *Display_config = NULL; const uint_least8_t Display_count = 0; -#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ +#endif /* TI_DISPLAY_CONF_ENABLE */ /* * =============================== GPIO =============================== @@ -429,9 +438,12 @@ const GPTimerCC26XX_Config GPTimerCC26XX_config[CC1310_LAUNCHXL_GPTIMERPARTSCOUN #include #include +#if TI_I2C_CONF_ENABLE + I2CCC26XX_Object i2cCC26xxObjects[CC1310_LAUNCHXL_I2CCOUNT]; const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1310_LAUNCHXL_I2CCOUNT] = { +#if TI_I2C_CONF_I2C0_ENABLE { .baseAddr = I2C0_BASE, .powerMngrId = PowerCC26XX_PERIPH_I2C0, @@ -440,19 +452,24 @@ const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1310_LAUNCHXL_I2CCOUNT] = { .swiPriority = 0, .sdaPin = CC1310_LAUNCHXL_I2C0_SDA0, .sclPin = CC1310_LAUNCHXL_I2C0_SCL0, - } + }, +#endif }; const I2C_Config I2C_config[CC1310_LAUNCHXL_I2CCOUNT] = { +#if TI_I2C_CONF_I2C0_ENABLE { .fxnTablePtr = &I2CCC26XX_fxnTable, .object = &i2cCC26xxObjects[CC1310_LAUNCHXL_I2C0], .hwAttrs = &i2cCC26xxHWAttrs[CC1310_LAUNCHXL_I2C0] - } + }, +#endif }; const uint_least8_t I2C_count = CC1310_LAUNCHXL_I2CCOUNT; +#endif /* TI_I2C_CONF_ENABLE */ + /* * =============================== NVS =============================== */ @@ -464,7 +481,9 @@ const uint_least8_t I2C_count = CC1310_LAUNCHXL_I2CCOUNT; #define SECTORSIZE 0x1000 #define REGIONSIZE (SECTORSIZE * 4) -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_ENABLE + +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE /* * Reserve flash sectors for NVS driver use by placing an uninitialized byte @@ -514,9 +533,9 @@ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { }, }; -#endif /* Board_EXCLUDE_NVS_INTERNAL_FLASH */ +#endif /* TI_NVS_CONF_NVS_INTERNAL_ENABLE */ -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE #define SPISECTORSIZE 0x1000 #define SPIREGIONSIZE (SPISECTORSIZE * 32) @@ -542,18 +561,18 @@ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { }, }; -#endif /* Board_EXCLUDE_NVS_EXTERNAL_FLASH */ +#endif /* TI_NVS_CONF_NVS_EXTERNAL_ENABLE */ /* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ const NVS_Config NVS_config[CC1310_LAUNCHXL_NVSCOUNT] = { -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE { .fxnTablePtr = &NVSCC26XX_fxnTable, .object = &nvsCC26xxObjects[0], .hwAttrs = &nvsCC26xxHWAttrs[0], }, #endif -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE { .fxnTablePtr = &NVSSPI25X_fxnTable, .object = &nvsSPI25XObjects[0], @@ -564,6 +583,8 @@ const NVS_Config NVS_config[CC1310_LAUNCHXL_NVSCOUNT] = { const uint_least8_t NVS_count = CC1310_LAUNCHXL_NVSCOUNT; +#endif /* TI_NVS_CONF_ENABLE */ + /* * =============================== PIN =============================== */ @@ -658,6 +679,12 @@ const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { #include #include +#if TI_SD_CONF_ENABLE + +#if !(TI_SPI_CONF_SPI0_ENABLE) +#error "SD driver requires SPI0 enabled" +#endif + SDSPI_Object sdspiObjects[CC1310_LAUNCHXL_SDCOUNT]; const SDSPI_HWAttrs sdspiHWAttrs[CC1310_LAUNCHXL_SDCOUNT] = { @@ -677,12 +704,16 @@ const SD_Config SD_config[CC1310_LAUNCHXL_SDCOUNT] = { const uint_least8_t SD_count = CC1310_LAUNCHXL_SDCOUNT; +#endif /* TI_SD_CONF_ENABLE */ + /* * =============================== SPI DMA =============================== */ #include #include +#if TI_SPI_CONF_ENABLE + SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1310_LAUNCHXL_SPICOUNT]; /* @@ -691,6 +722,7 @@ SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1310_LAUNCHXL_SPICOUNT]; * to satisfy the SDSPI driver requirement. */ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1310_LAUNCHXL_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .baseAddr = SSI0_BASE, .intNum = INT_SSI0_COMB, @@ -706,6 +738,8 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1310_LAUNCHXL_SPICOUNT] = { .csnPin = CC1310_LAUNCHXL_SPI0_CSN, .minDmaTransferSize = 10 }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .baseAddr = SSI1_BASE, .intNum = INT_SSI1_COMB, @@ -720,35 +754,45 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1310_LAUNCHXL_SPICOUNT] = { .clkPin = CC1310_LAUNCHXL_SPI1_CLK, .csnPin = CC1310_LAUNCHXL_SPI1_CSN, .minDmaTransferSize = 10 - } + }, +#endif }; const SPI_Config SPI_config[CC1310_LAUNCHXL_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC1310_LAUNCHXL_SPI0], .hwAttrs = &spiCC26XXDMAHWAttrs[CC1310_LAUNCHXL_SPI0] }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC1310_LAUNCHXL_SPI1], .hwAttrs = &spiCC26XXDMAHWAttrs[CC1310_LAUNCHXL_SPI1] }, +#endif }; const uint_least8_t SPI_count = CC1310_LAUNCHXL_SPICOUNT; +#endif /* TI_SPI_CONF_ENABLE */ + /* * =============================== UART =============================== */ #include #include +#if TI_UART_CONF_ENABLE + UARTCC26XX_Object uartCC26XXObjects[CC1310_LAUNCHXL_UARTCOUNT]; uint8_t uartCC26XXRingBuffer[CC1310_LAUNCHXL_UARTCOUNT][32]; const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1310_LAUNCHXL_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .baseAddr = UART0_BASE, .powerMngrId = PowerCC26XX_PERIPH_UART0, @@ -764,19 +808,24 @@ const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1310_LAUNCHXL_UARTCOUNT] = { .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, .errorFxn = NULL - } + }, +#endif }; const UART_Config UART_config[CC1310_LAUNCHXL_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .fxnTablePtr = &UARTCC26XX_fxnTable, .object = &uartCC26XXObjects[CC1310_LAUNCHXL_UART0], .hwAttrs = &uartCC26XXHWAttrs[CC1310_LAUNCHXL_UART0] }, +#endif }; const uint_least8_t UART_count = CC1310_LAUNCHXL_UARTCOUNT; +#endif /* TI_UART_CONF_ENABLE */ + /* * =============================== UDMA =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h index 6eb2364ee..51ff78942 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h @@ -49,6 +49,8 @@ extern "C" { #endif +#include "contiki-conf.h" + /* Includes */ #include #include @@ -267,7 +269,9 @@ typedef enum CC1310_LAUNCHXL_GPTimers { * @brief Enum of I2C names */ typedef enum CC1310_LAUNCHXL_I2CName { +#if TI_I2C_CONF_I2C0_ENABLE CC1310_LAUNCHXL_I2C0 = 0, +#endif CC1310_LAUNCHXL_I2CCOUNT } CC1310_LAUNCHXL_I2CName; @@ -277,10 +281,10 @@ typedef enum CC1310_LAUNCHXL_I2CName { * @brief Enum of NVS names */ typedef enum CC1310_LAUNCHXL_NVSName { -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE CC1310_LAUNCHXL_NVSCC26XX0 = 0, #endif -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE CC1310_LAUNCHXL_NVSSPI25X0, #endif @@ -319,8 +323,12 @@ typedef enum CC1310_LAUNCHXL_SDName { * @brief Enum of SPI names */ typedef enum CC1310_LAUNCHXL_SPIName { +#if TI_SPI_CONF_SPI0_ENABLE CC1310_LAUNCHXL_SPI0 = 0, +#endif +#if TI_SPI_CONF_SPI1_ENABLE CC1310_LAUNCHXL_SPI1, +#endif CC1310_LAUNCHXL_SPICOUNT } CC1310_LAUNCHXL_SPIName; @@ -330,7 +338,9 @@ typedef enum CC1310_LAUNCHXL_SPIName { * @brief Enum of UARTs */ typedef enum CC1310_LAUNCHXL_UARTName { +#if TI_UART_CONF_UART0_ENABLE CC1310_LAUNCHXL_UART0 = 0, +#endif CC1310_LAUNCHXL_UARTCOUNT } CC1310_LAUNCHXL_UARTName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.c index 9b0be9686..20372347e 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.c @@ -374,19 +374,21 @@ const uint_least8_t AESECB_count = CC1312R1_LAUNCHXL_AESECBCOUNT; #include #include +#if TI_DISPLAY_CONF_ENABLE + +#if TI_DISPLAY_CONF_UART_ENABLE + +#if !(TI_UART_CONF_UART0_ENABLE) +#error "Display UART driver requires UART0" +#endif + #ifndef BOARD_DISPLAY_UART_STRBUF_SIZE #define BOARD_DISPLAY_UART_STRBUF_SIZE 128 #endif -#ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 -#endif +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; DisplayUart_Object displayUartObject; -DisplaySharp_Object displaySharpObject; - -static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; -static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; const DisplayUart_HWAttrs displayUartHWAttrs = { .uartIdx = CC1312R1_LAUNCHXL_UART0, @@ -396,6 +398,22 @@ const DisplayUart_HWAttrs displayUartHWAttrs = { .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, }; +#endif /* TI_DISPLAY_CONF_UART_ENABLE */ + +#if TI_DISPLAY_CONF_LCD_ENABLE + +#if !(TI_SPI_CONF_SPI0_ENABLE) +#error "Display LCD driver requires SPI0" +#endif + +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 +#endif + +DisplaySharp_Object displaySharpObject; + +static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; + const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .spiIndex = CC1312R1_LAUNCHXL_SPI0, .csPin = CC1312R1_LAUNCHXL_GPIO_LCD_CS, @@ -406,27 +424,18 @@ const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .displayBuf = sharpDisplayBuf, }; -#ifndef BOARD_DISPLAY_USE_UART -#define BOARD_DISPLAY_USE_UART 1 -#endif -#ifndef BOARD_DISPLAY_USE_UART_ANSI -#define BOARD_DISPLAY_USE_UART_ANSI 0 -#endif -#ifndef BOARD_DISPLAY_USE_LCD -#define BOARD_DISPLAY_USE_LCD 0 -#endif +#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ /* * This #if/#else is needed to workaround a problem with the * IAR compiler. The IAR compiler doesn't like the empty array * initialization. (IAR Error[Pe1345]) */ -#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) const Display_Config Display_config[] = { -#if (BOARD_DISPLAY_USE_UART) +#if TI_DISPLAY_CONF_UART_ENABLE { -# if (BOARD_DISPLAY_USE_UART_ANSI) +# if TI_DISPLAY_CONF_USE_UART_ANSI .fxnTablePtr = &DisplayUartAnsi_fxnTable, # else /* Default to minimal UART with no cursor placement */ .fxnTablePtr = &DisplayUartMin_fxnTable, @@ -435,7 +444,7 @@ const Display_Config Display_config[] = { .hwAttrs = &displayUartHWAttrs, }, #endif -#if (BOARD_DISPLAY_USE_LCD) +#if TI_DISPLAY_CONF_LCD_ENABLE { .fxnTablePtr = &DisplaySharp_fxnTable, .object = &displaySharpObject, @@ -451,7 +460,7 @@ const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Conf const Display_Config *Display_config = NULL; const uint_least8_t Display_count = 0; -#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ +#endif /* TI_DISPLAY_CONF_ENABLE */ /* * =============================== GPIO =============================== @@ -550,9 +559,12 @@ const GPTimerCC26XX_Config GPTimerCC26XX_config[CC1312R1_LAUNCHXL_GPTIMERPARTSCO #include #include +#if TI_I2C_CONF_ENABLE + I2CCC26XX_Object i2cCC26xxObjects[CC1312R1_LAUNCHXL_I2CCOUNT]; const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1312R1_LAUNCHXL_I2CCOUNT] = { +#if TI_I2C_CONF_I2C0_ENABLE { .baseAddr = I2C0_BASE, .powerMngrId = PowerCC26XX_PERIPH_I2C0, @@ -561,19 +573,24 @@ const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1312R1_LAUNCHXL_I2CCOUNT] = { .swiPriority = 0, .sdaPin = CC1312R1_LAUNCHXL_I2C0_SDA0, .sclPin = CC1312R1_LAUNCHXL_I2C0_SCL0, - } + }, +#endif }; const I2C_Config I2C_config[CC1312R1_LAUNCHXL_I2CCOUNT] = { +#if TI_I2C_CONF_I2C0_ENABLE { .fxnTablePtr = &I2CCC26XX_fxnTable, .object = &i2cCC26xxObjects[CC1312R1_LAUNCHXL_I2C0], .hwAttrs = &i2cCC26xxHWAttrs[CC1312R1_LAUNCHXL_I2C0] - } + }, +#endif }; const uint_least8_t I2C_count = CC1312R1_LAUNCHXL_I2CCOUNT; +#endif /* TI_I2C_CONF_ENABLE */ + /* * =============================== NVS =============================== */ @@ -585,7 +602,9 @@ const uint_least8_t I2C_count = CC1312R1_LAUNCHXL_I2CCOUNT; #define SECTORSIZE 0x2000 #define REGIONSIZE (SECTORSIZE * 4) -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_ENABLE + +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE /* * Reserve flash sectors for NVS driver use by placing an uninitialized byte @@ -635,9 +654,9 @@ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { }, }; -#endif /* Board_EXCLUDE_NVS_INTERNAL_FLASH */ +#endif /* TI_NVS_CONF_NVS_INTERNAL_ENABLE */ -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE #define SPISECTORSIZE 0x1000 #define SPIREGIONSIZE (SPISECTORSIZE * 32) @@ -663,18 +682,18 @@ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { }, }; -#endif /* Board_EXCLUDE_NVS_EXTERNAL_FLASH */ +#endif /* TI_NVS_CONF_NVS_EXTERNAL_ENABLE */ /* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ const NVS_Config NVS_config[CC1312R1_LAUNCHXL_NVSCOUNT] = { -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE { .fxnTablePtr = &NVSCC26XX_fxnTable, .object = &nvsCC26xxObjects[0], .hwAttrs = &nvsCC26xxHWAttrs[0], }, #endif -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE { .fxnTablePtr = &NVSSPI25X_fxnTable, .object = &nvsSPI25XObjects[0], @@ -685,6 +704,8 @@ const NVS_Config NVS_config[CC1312R1_LAUNCHXL_NVSCOUNT] = { const uint_least8_t NVS_count = CC1312R1_LAUNCHXL_NVSCOUNT; +#endif /* TI_NVS_CONF_ENABLE */ + /* * =============================== PIN =============================== */ @@ -779,6 +800,12 @@ const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { #include #include +#if TI_SD_CONF_ENABLE + +#if !(TI_SPI_CONF_SPI0_ENABLE) +#error "SD driver requires SPI0 enabled" +#endif + SDSPI_Object sdspiObjects[CC1312R1_LAUNCHXL_SDCOUNT]; const SDSPI_HWAttrs sdspiHWAttrs[CC1312R1_LAUNCHXL_SDCOUNT] = { @@ -798,12 +825,16 @@ const SD_Config SD_config[CC1312R1_LAUNCHXL_SDCOUNT] = { const uint_least8_t SD_count = CC1312R1_LAUNCHXL_SDCOUNT; +#endif /* TI_SD_CONF_ENABLE */ + /* * =============================== SPI DMA =============================== */ #include #include +#if TI_SPI_CONF_ENABLE + SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1312R1_LAUNCHXL_SPICOUNT]; /* @@ -812,6 +843,7 @@ SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1312R1_LAUNCHXL_SPICOUNT]; * to satisfy the SDSPI driver requirement. */ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1312R1_LAUNCHXL_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .baseAddr = SSI0_BASE, .intNum = INT_SSI0_COMB, @@ -827,6 +859,8 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1312R1_LAUNCHXL_SPICOUNT] = { .csnPin = CC1312R1_LAUNCHXL_SPI0_CSN, .minDmaTransferSize = 10 }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .baseAddr = SSI1_BASE, .intNum = INT_SSI1_COMB, @@ -841,35 +875,45 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1312R1_LAUNCHXL_SPICOUNT] = { .clkPin = CC1312R1_LAUNCHXL_SPI1_CLK, .csnPin = CC1312R1_LAUNCHXL_SPI1_CSN, .minDmaTransferSize = 10 - } + }, +#endif }; const SPI_Config SPI_config[CC1312R1_LAUNCHXL_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC1312R1_LAUNCHXL_SPI0], .hwAttrs = &spiCC26XXDMAHWAttrs[CC1312R1_LAUNCHXL_SPI0] }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC1312R1_LAUNCHXL_SPI1], .hwAttrs = &spiCC26XXDMAHWAttrs[CC1312R1_LAUNCHXL_SPI1] }, +#endif }; const uint_least8_t SPI_count = CC1312R1_LAUNCHXL_SPICOUNT; +#endif /* TI_SPI_CONF_ENABLE */ + /* * =============================== UART =============================== */ #include #include +#if TI_UART_CONF_ENABLE + UARTCC26XX_Object uartCC26XXObjects[CC1312R1_LAUNCHXL_UARTCOUNT]; uint8_t uartCC26XXRingBuffer[CC1312R1_LAUNCHXL_UARTCOUNT][32]; const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1312R1_LAUNCHXL_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .baseAddr = UART0_BASE, .powerMngrId = PowerCC26XX_PERIPH_UART0, @@ -885,19 +929,24 @@ const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1312R1_LAUNCHXL_UARTCOUNT] = { .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, .errorFxn = NULL - } + }, +#endif }; const UART_Config UART_config[CC1312R1_LAUNCHXL_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .fxnTablePtr = &UARTCC26XX_fxnTable, .object = &uartCC26XXObjects[CC1312R1_LAUNCHXL_UART0], .hwAttrs = &uartCC26XXHWAttrs[CC1312R1_LAUNCHXL_UART0] }, +#endif }; const uint_least8_t UART_count = CC1312R1_LAUNCHXL_UARTCOUNT; +#endif /* TI_UART_CONF_ENABLE */ + /* * =============================== UDMA =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h index fd2043ce7..c70e28755 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h @@ -49,6 +49,8 @@ extern "C" { #endif +#include "contiki-conf.h" + /* Includes */ #include #include @@ -326,7 +328,9 @@ typedef enum CC1312R1_LAUNCHXL_GPTimers { * @brief Enum of I2C names */ typedef enum CC1312R1_LAUNCHXL_I2CName { +#if TI_I2C_CONF_I2C0_ENABLE CC1312R1_LAUNCHXL_I2C0 = 0, +#endif CC1312R1_LAUNCHXL_I2CCOUNT } CC1312R1_LAUNCHXL_I2CName; @@ -336,10 +340,10 @@ typedef enum CC1312R1_LAUNCHXL_I2CName { * @brief Enum of NVS names */ typedef enum CC1312R1_LAUNCHXL_NVSName { -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE CC1312R1_LAUNCHXL_NVSCC26XX0 = 0, #endif -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE CC1312R1_LAUNCHXL_NVSSPI25X0, #endif @@ -378,8 +382,12 @@ typedef enum CC1312R1_LAUNCHXL_SDName { * @brief Enum of SPI names */ typedef enum CC1312R1_LAUNCHXL_SPIName { +#if TI_SPI_CONF_SPI0_ENABLE CC1312R1_LAUNCHXL_SPI0 = 0, +#endif +#if TI_SPI_CONF_SPI1_ENABLE CC1312R1_LAUNCHXL_SPI1, +#endif CC1312R1_LAUNCHXL_SPICOUNT } CC1312R1_LAUNCHXL_SPIName; @@ -389,7 +397,9 @@ typedef enum CC1312R1_LAUNCHXL_SPIName { * @brief Enum of UARTs */ typedef enum CC1312R1_LAUNCHXL_UARTName { +#if TI_UART_CONF_UART0_ENABLE CC1312R1_LAUNCHXL_UART0 = 0, +#endif CC1312R1_LAUNCHXL_UARTCOUNT } CC1312R1_LAUNCHXL_UARTName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.c index 9679f7599..55b30637d 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.c @@ -252,19 +252,21 @@ const CryptoCC26XX_Config CryptoCC26XX_config[CC1350_LAUNCHXL_433_CRYPTOCOUNT] = #include #include +#if TI_DISPLAY_CONF_ENABLE + +#if TI_DISPLAY_CONF_UART_ENABLE + +#if !(TI_UART_CONF_UART0_ENABLE) +#error "Display UART driver requires UART0" +#endif + #ifndef BOARD_DISPLAY_UART_STRBUF_SIZE #define BOARD_DISPLAY_UART_STRBUF_SIZE 128 #endif -#ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 -#endif +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; DisplayUart_Object displayUartObject; -DisplaySharp_Object displaySharpObject; - -static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; -static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; const DisplayUart_HWAttrs displayUartHWAttrs = { .uartIdx = CC1350_LAUNCHXL_433_UART0, @@ -274,6 +276,22 @@ const DisplayUart_HWAttrs displayUartHWAttrs = { .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, }; +#endif /* TI_DISPLAY_CONF_UART_ENABLE */ + +#if TI_DISPLAY_CONF_LCD_ENABLE + +#if !(TI_SPI_CONF_SPI0_ENABLE) +#error "Display LCD driver requires SPI0" +#endif + +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 +#endif + +static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; + +DisplaySharp_Object displaySharpObject; + const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .spiIndex = CC1350_LAUNCHXL_433_SPI0, .csPin = CC1350_LAUNCHXL_433_GPIO_LCD_CS, @@ -284,27 +302,18 @@ const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .displayBuf = sharpDisplayBuf, }; -#ifndef BOARD_DISPLAY_USE_UART -#define BOARD_DISPLAY_USE_UART 1 -#endif -#ifndef BOARD_DISPLAY_USE_UART_ANSI -#define BOARD_DISPLAY_USE_UART_ANSI 0 -#endif -#ifndef BOARD_DISPLAY_USE_LCD -#define BOARD_DISPLAY_USE_LCD 0 -#endif +#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ /* * This #if/#else is needed to workaround a problem with the * IAR compiler. The IAR compiler doesn't like the empty array * initialization. (IAR Error[Pe1345]) */ -#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) const Display_Config Display_config[] = { -#if (BOARD_DISPLAY_USE_UART) +#if TI_DISPLAY_CONF_UART_ENABLE { -# if (BOARD_DISPLAY_USE_UART_ANSI) +# if TI_DISPLAY_CONF_USE_UART_ANSI .fxnTablePtr = &DisplayUartAnsi_fxnTable, # else /* Default to minimal UART with no cursor placement */ .fxnTablePtr = &DisplayUartMin_fxnTable, @@ -313,7 +322,7 @@ const Display_Config Display_config[] = { .hwAttrs = &displayUartHWAttrs, }, #endif -#if (BOARD_DISPLAY_USE_LCD) +#if TI_DISPLAY_CONF_LCD_ENABLE { .fxnTablePtr = &DisplaySharp_fxnTable, .object = &displaySharpObject, @@ -329,7 +338,7 @@ const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Conf const Display_Config *Display_config = NULL; const uint_least8_t Display_count = 0; -#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ +#endif /* TI_DISPLAY_CONF_ENABLE */ /* * =============================== GPIO =============================== @@ -428,6 +437,8 @@ const GPTimerCC26XX_Config GPTimerCC26XX_config[CC1350_LAUNCHXL_433_GPTIMERPARTS #include #include +#if TI_I2C_CONF_ENABLE + I2CCC26XX_Object i2cCC26xxObjects[CC1350_LAUNCHXL_433_I2CCOUNT]; const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1350_LAUNCHXL_433_I2CCOUNT] = { @@ -452,6 +463,8 @@ const I2C_Config I2C_config[CC1350_LAUNCHXL_433_I2CCOUNT] = { const uint_least8_t I2C_count = CC1350_LAUNCHXL_433_I2CCOUNT; +#endif /* TI_I2C_CONF_ENABLE */ + /* * =============================== NVS =============================== */ @@ -463,7 +476,9 @@ const uint_least8_t I2C_count = CC1350_LAUNCHXL_433_I2CCOUNT; #define SECTORSIZE 0x1000 #define REGIONSIZE (SECTORSIZE * 4) -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_ENABLE + +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE /* * Reserve flash sectors for NVS driver use by placing an uninitialized byte @@ -513,9 +528,9 @@ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { }, }; -#endif /* Board_EXCLUDE_NVS_INTERNAL_FLASH */ +#endif /* TI_NVS_CONF_NVS_INTERNAL_ENABLE */ -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE #define SPISECTORSIZE 0x1000 #define SPIREGIONSIZE (SPISECTORSIZE * 32) @@ -541,18 +556,18 @@ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { }, }; -#endif /* Board_EXCLUDE_NVS_EXTERNAL_FLASH */ +#endif /* TI_NVS_CONF_NVS_EXTERNAL_ENABLE */ /* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ const NVS_Config NVS_config[CC1350_LAUNCHXL_433_NVSCOUNT] = { -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE { .fxnTablePtr = &NVSCC26XX_fxnTable, .object = &nvsCC26xxObjects[0], .hwAttrs = &nvsCC26xxHWAttrs[0], }, #endif -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE { .fxnTablePtr = &NVSSPI25X_fxnTable, .object = &nvsSPI25XObjects[0], @@ -563,6 +578,8 @@ const NVS_Config NVS_config[CC1350_LAUNCHXL_433_NVSCOUNT] = { const uint_least8_t NVS_count = CC1350_LAUNCHXL_433_NVSCOUNT; +#endif /* TI_NVS_CONF_ENABLE */ + /* * =============================== PIN =============================== */ @@ -670,6 +687,12 @@ const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { #include #include +#if TI_SD_CONF_ENABLE + +#if !(TI_SPI_CONF_SPI0_ENABLE) +#error "SD driver requires SPI0 enabled" +#endif + SDSPI_Object sdspiObjects[CC1350_LAUNCHXL_433_SDCOUNT]; const SDSPI_HWAttrs sdspiHWAttrs[CC1350_LAUNCHXL_433_SDCOUNT] = { @@ -689,12 +712,16 @@ const SD_Config SD_config[CC1350_LAUNCHXL_433_SDCOUNT] = { const uint_least8_t SD_count = CC1350_LAUNCHXL_433_SDCOUNT; +#endif /* TI_SD_CONF_ENABLE */ + /* * =============================== SPI DMA =============================== */ #include #include +#if TI_SPI_CONF_ENABLE + SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1350_LAUNCHXL_433_SPICOUNT]; /* @@ -703,6 +730,7 @@ SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1350_LAUNCHXL_433_SPICOUNT]; * to satisfy the SDSPI driver requirement. */ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1350_LAUNCHXL_433_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .baseAddr = SSI0_BASE, .intNum = INT_SSI0_COMB, @@ -718,6 +746,8 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1350_LAUNCHXL_433_SPICOUNT] = .csnPin = CC1350_LAUNCHXL_433_SPI0_CSN, .minDmaTransferSize = 10 }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .baseAddr = SSI1_BASE, .intNum = INT_SSI1_COMB, @@ -732,35 +762,45 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1350_LAUNCHXL_433_SPICOUNT] = .clkPin = CC1350_LAUNCHXL_433_SPI1_CLK, .csnPin = CC1350_LAUNCHXL_433_SPI1_CSN, .minDmaTransferSize = 10 - } + }, +#endif }; const SPI_Config SPI_config[CC1350_LAUNCHXL_433_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC1350_LAUNCHXL_433_SPI0], .hwAttrs = &spiCC26XXDMAHWAttrs[CC1350_LAUNCHXL_433_SPI0] }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC1350_LAUNCHXL_433_SPI1], .hwAttrs = &spiCC26XXDMAHWAttrs[CC1350_LAUNCHXL_433_SPI1] }, +#endif }; const uint_least8_t SPI_count = CC1350_LAUNCHXL_433_SPICOUNT; +#endif /* TI_SPI_CONF_ENABLE */ + /* * =============================== UART =============================== */ #include #include +#if TI_UART_CONF_ENABLE + UARTCC26XX_Object uartCC26XXObjects[CC1350_LAUNCHXL_433_UARTCOUNT]; uint8_t uartCC26XXRingBuffer[CC1350_LAUNCHXL_433_UARTCOUNT][32]; const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1350_LAUNCHXL_433_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .baseAddr = UART0_BASE, .powerMngrId = PowerCC26XX_PERIPH_UART0, @@ -776,19 +816,24 @@ const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1350_LAUNCHXL_433_UARTCOUNT] = { .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, .errorFxn = NULL - } + }, +#endif }; const UART_Config UART_config[CC1350_LAUNCHXL_433_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .fxnTablePtr = &UARTCC26XX_fxnTable, .object = &uartCC26XXObjects[CC1350_LAUNCHXL_433_UART0], .hwAttrs = &uartCC26XXHWAttrs[CC1350_LAUNCHXL_433_UART0] }, +#endif }; const uint_least8_t UART_count = CC1350_LAUNCHXL_433_UARTCOUNT; +#endif /* TI_UART_CONF_ENABLE */ + /* * =============================== UDMA =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h index fa3a63316..9e9bee949 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h @@ -49,6 +49,8 @@ extern "C" { #endif +#include "contiki-conf.h" + /* Includes */ #include #include diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c index 2a4f4dee7..1fbff5e6d 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c @@ -253,19 +253,21 @@ const CryptoCC26XX_Config CryptoCC26XX_config[CC1350_LAUNCHXL_CRYPTOCOUNT] = { #include #include +#if TI_DISPLAY_CONF_ENABLE + +#if TI_DISPLAY_CONF_UART_ENABLE + +#if !(TI_UART_CONF_UART0_ENABLE) +#error "Display UART driver requires UART0" +#endif + #ifndef BOARD_DISPLAY_UART_STRBUF_SIZE #define BOARD_DISPLAY_UART_STRBUF_SIZE 128 #endif -#ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 -#endif +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; DisplayUart_Object displayUartObject; -DisplaySharp_Object displaySharpObject; - -static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; -static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; const DisplayUart_HWAttrs displayUartHWAttrs = { .uartIdx = CC1350_LAUNCHXL_UART0, @@ -275,6 +277,22 @@ const DisplayUart_HWAttrs displayUartHWAttrs = { .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, }; +#endif /* TI_DISPLAY_CONF_UART_ENABLE */ + +#if TI_DISPLAY_CONF_LCD_ENABLE + +#if !(TI_SPI_CONF_SPI0_ENABLE) +#error "Display LCD driver requires SPI0" +#endif + +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 +#endif + +static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; + +DisplaySharp_Object displaySharpObject; + const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .spiIndex = CC1350_LAUNCHXL_SPI0, .csPin = CC1350_LAUNCHXL_GPIO_LCD_CS, @@ -285,27 +303,18 @@ const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .displayBuf = sharpDisplayBuf, }; -#ifndef BOARD_DISPLAY_USE_UART -#define BOARD_DISPLAY_USE_UART 1 -#endif -#ifndef BOARD_DISPLAY_USE_UART_ANSI -#define BOARD_DISPLAY_USE_UART_ANSI 0 -#endif -#ifndef BOARD_DISPLAY_USE_LCD -#define BOARD_DISPLAY_USE_LCD 0 -#endif +#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ /* * This #if/#else is needed to workaround a problem with the * IAR compiler. The IAR compiler doesn't like the empty array * initialization. (IAR Error[Pe1345]) */ -#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) const Display_Config Display_config[] = { -#if (BOARD_DISPLAY_USE_UART) +#if TI_DISPLAY_CONF_UART_ENABLE { -# if (BOARD_DISPLAY_USE_UART_ANSI) +# if TI_DISPLAY_CONF_USE_UART_ANSI .fxnTablePtr = &DisplayUartAnsi_fxnTable, # else /* Default to minimal UART with no cursor placement */ .fxnTablePtr = &DisplayUartMin_fxnTable, @@ -314,7 +323,7 @@ const Display_Config Display_config[] = { .hwAttrs = &displayUartHWAttrs, }, #endif -#if (BOARD_DISPLAY_USE_LCD) +#if TI_DISPLAY_CONF_LCD_ENABLE { .fxnTablePtr = &DisplaySharp_fxnTable, .object = &displaySharpObject, @@ -330,7 +339,7 @@ const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Conf const Display_Config *Display_config = NULL; const uint_least8_t Display_count = 0; -#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ +#endif /* TI_DISPLAY_CONF_ENABLE */ /* * =============================== GPIO =============================== @@ -429,9 +438,12 @@ const GPTimerCC26XX_Config GPTimerCC26XX_config[CC1350_LAUNCHXL_GPTIMERPARTSCOUN #include #include +#if TI_I2C_CONF_ENABLE + I2CCC26XX_Object i2cCC26xxObjects[CC1350_LAUNCHXL_I2CCOUNT]; const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1350_LAUNCHXL_I2CCOUNT] = { +#if TI_I2C_CONF_I2C0_ENABLE { .baseAddr = I2C0_BASE, .powerMngrId = PowerCC26XX_PERIPH_I2C0, @@ -440,19 +452,24 @@ const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1350_LAUNCHXL_I2CCOUNT] = { .swiPriority = 0, .sdaPin = CC1350_LAUNCHXL_I2C0_SDA0, .sclPin = CC1350_LAUNCHXL_I2C0_SCL0, - } + }, +#endif }; const I2C_Config I2C_config[CC1350_LAUNCHXL_I2CCOUNT] = { +#if TI_I2C_CONF_I2C0_ENABLE { .fxnTablePtr = &I2CCC26XX_fxnTable, .object = &i2cCC26xxObjects[CC1350_LAUNCHXL_I2C0], .hwAttrs = &i2cCC26xxHWAttrs[CC1350_LAUNCHXL_I2C0] }, +#endif }; const uint_least8_t I2C_count = CC1350_LAUNCHXL_I2CCOUNT; +#endif /* TI_I2C_CONF_ENABLE */ + /* * =============================== NVS =============================== */ @@ -464,7 +481,9 @@ const uint_least8_t I2C_count = CC1350_LAUNCHXL_I2CCOUNT; #define SECTORSIZE 0x1000 #define REGIONSIZE (SECTORSIZE * 4) -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_ENABLE + +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE /* * Reserve flash sectors for NVS driver use by placing an uninitialized byte @@ -514,9 +533,9 @@ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { }, }; -#endif /* Board_EXCLUDE_NVS_INTERNAL_FLASH */ +#endif /* TI_NVS_CONF_NVS_INTERNAL_ENABLE */ -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE #define SPISECTORSIZE 0x1000 #define SPIREGIONSIZE (SPISECTORSIZE * 32) @@ -542,18 +561,18 @@ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { }, }; -#endif /* Board_EXCLUDE_NVS_EXTERNAL_FLASH */ +#endif /* TI_NVS_CONF_NVS_EXTERNAL_ENABLE */ /* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ const NVS_Config NVS_config[CC1350_LAUNCHXL_NVSCOUNT] = { -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE { .fxnTablePtr = &NVSCC26XX_fxnTable, .object = &nvsCC26xxObjects[0], .hwAttrs = &nvsCC26xxHWAttrs[0], }, #endif -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE { .fxnTablePtr = &NVSSPI25X_fxnTable, .object = &nvsSPI25XObjects[0], @@ -564,6 +583,8 @@ const NVS_Config NVS_config[CC1350_LAUNCHXL_NVSCOUNT] = { const uint_least8_t NVS_count = CC1350_LAUNCHXL_NVSCOUNT; +#endif /* TI_NVS_CONF_ENABLE */ + /* * =============================== PIN =============================== */ @@ -671,6 +692,12 @@ const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { #include #include +#if TI_SD_CONF_ENABLE + +#if !(TI_SPI_CONF_SPI0_ENABLE) +#error "SD driver requires SPI0 enabled" +#endif + SDSPI_Object sdspiObjects[CC1350_LAUNCHXL_SDCOUNT]; const SDSPI_HWAttrs sdspiHWAttrs[CC1350_LAUNCHXL_SDCOUNT] = { @@ -690,12 +717,16 @@ const SD_Config SD_config[CC1350_LAUNCHXL_SDCOUNT] = { const uint_least8_t SD_count = CC1350_LAUNCHXL_SDCOUNT; +#endif /* TI_SD_CONF_ENABLE */ + /* * =============================== SPI DMA =============================== */ #include #include +#if TI_SPI_CONF_ENABLE + SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1350_LAUNCHXL_SPICOUNT]; /* @@ -704,6 +735,7 @@ SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1350_LAUNCHXL_SPICOUNT]; * to satisfy the SDSPI driver requirement. */ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1350_LAUNCHXL_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .baseAddr = SSI0_BASE, .intNum = INT_SSI0_COMB, @@ -719,6 +751,8 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1350_LAUNCHXL_SPICOUNT] = { .csnPin = CC1350_LAUNCHXL_SPI0_CSN, .minDmaTransferSize = 10 }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .baseAddr = SSI1_BASE, .intNum = INT_SSI1_COMB, @@ -733,35 +767,45 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1350_LAUNCHXL_SPICOUNT] = { .clkPin = CC1350_LAUNCHXL_SPI1_CLK, .csnPin = CC1350_LAUNCHXL_SPI1_CSN, .minDmaTransferSize = 10 - } + }, +#endif }; const SPI_Config SPI_config[CC1350_LAUNCHXL_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC1350_LAUNCHXL_SPI0], .hwAttrs = &spiCC26XXDMAHWAttrs[CC1350_LAUNCHXL_SPI0] }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC1350_LAUNCHXL_SPI1], .hwAttrs = &spiCC26XXDMAHWAttrs[CC1350_LAUNCHXL_SPI1] }, +#endif }; const uint_least8_t SPI_count = CC1350_LAUNCHXL_SPICOUNT; +#endif /* TI_SPI_CONF_ENABLE */ + /* * =============================== UART =============================== */ #include #include +#if TI_UART_CONF_ENABLE + UARTCC26XX_Object uartCC26XXObjects[CC1350_LAUNCHXL_UARTCOUNT]; uint8_t uartCC26XXRingBuffer[CC1350_LAUNCHXL_UARTCOUNT][32]; const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1350_LAUNCHXL_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .baseAddr = UART0_BASE, .powerMngrId = PowerCC26XX_PERIPH_UART0, @@ -777,19 +821,24 @@ const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1350_LAUNCHXL_UARTCOUNT] = { .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, .errorFxn = NULL - } + }, +#endif }; const UART_Config UART_config[CC1350_LAUNCHXL_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .fxnTablePtr = &UARTCC26XX_fxnTable, .object = &uartCC26XXObjects[CC1350_LAUNCHXL_UART0], .hwAttrs = &uartCC26XXHWAttrs[CC1350_LAUNCHXL_UART0] }, +#endif }; const uint_least8_t UART_count = CC1350_LAUNCHXL_UARTCOUNT; +#endif /* TI_UART_CONF_ENABLE */ + /* * =============================== UDMA =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h index be952b936..88ffb333b 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h @@ -49,6 +49,8 @@ extern "C" { #endif +#include "contiki-conf.h" + /* Includes */ #include #include @@ -270,7 +272,9 @@ typedef enum CC1350_LAUNCHXL_GPTimers { * @brief Enum of I2C names */ typedef enum CC1350_LAUNCHXL_I2CName { +#if TI_I2C_CONF_I2C0_ENABLE CC1350_LAUNCHXL_I2C0 = 0, +#endif CC1350_LAUNCHXL_I2CCOUNT } CC1350_LAUNCHXL_I2CName; @@ -280,10 +284,10 @@ typedef enum CC1350_LAUNCHXL_I2CName { * @brief Enum of NVS names */ typedef enum CC1350_LAUNCHXL_NVSName { -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE CC1350_LAUNCHXL_NVSCC26XX0 = 0, #endif -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE CC1350_LAUNCHXL_NVSSPI25X0, #endif @@ -322,8 +326,12 @@ typedef enum CC1350_LAUNCHXL_SDName { * @brief Enum of SPI names */ typedef enum CC1350_LAUNCHXL_SPIName { +#if TI_SPI_CONF_SPI0_ENABLE CC1350_LAUNCHXL_SPI0 = 0, +#endif +#if TI_SPI_CONF_SPI1_ENABLE CC1350_LAUNCHXL_SPI1, +#endif CC1350_LAUNCHXL_SPICOUNT } CC1350_LAUNCHXL_SPIName; @@ -333,7 +341,9 @@ typedef enum CC1350_LAUNCHXL_SPIName { * @brief Enum of UARTs */ typedef enum CC1350_LAUNCHXL_UARTName { +#if TI_UART_CONF_UART0_ENABLE CC1350_LAUNCHXL_UART0 = 0, +#endif CC1350_LAUNCHXL_UARTCOUNT } CC1350_LAUNCHXL_UARTName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.c index d78087e3d..973f712ac 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.c @@ -340,19 +340,21 @@ const uint_least8_t AESECB_count = CC1352P_2_LAUNCHXL_AESECBCOUNT; #include #include +#if TI_DISPLAY_CONF_ENABLE + +#if TI_DISPLAY_CONF_UART_ENABLE + +#if !(TI_UART_CONF_UART0_ENABLE) +#error "Display UART driver requires UART0" +#endif + #ifndef BOARD_DISPLAY_UART_STRBUF_SIZE #define BOARD_DISPLAY_UART_STRBUF_SIZE 128 #endif -#ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 -#endif +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; DisplayUart_Object displayUartObject; -DisplaySharp_Object displaySharpObject; - -static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; -static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; const DisplayUart_HWAttrs displayUartHWAttrs = { .uartIdx = CC1352P_2_LAUNCHXL_UART0, @@ -362,6 +364,22 @@ const DisplayUart_HWAttrs displayUartHWAttrs = { .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, }; +#endif /* TI_DISPLAY_CONF_UART_ENABLE */ + +#if TI_DISPLAY_CONF_LCD_ENABLE + +#if !(TI_SPI_CONF_SPI0_ENABLE) +#error "Display LCD driver requires SPI0" +#endif + +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 +#endif + +static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; + +DisplaySharp_Object displaySharpObject; + const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .spiIndex = CC1352P_2_LAUNCHXL_SPI0, .csPin = CC1352P_2_LAUNCHXL_GPIO_LCD_CS, @@ -372,27 +390,18 @@ const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .displayBuf = sharpDisplayBuf, }; -#ifndef BOARD_DISPLAY_USE_UART -#define BOARD_DISPLAY_USE_UART 1 -#endif -#ifndef BOARD_DISPLAY_USE_UART_ANSI -#define BOARD_DISPLAY_USE_UART_ANSI 0 -#endif -#ifndef BOARD_DISPLAY_USE_LCD -#define BOARD_DISPLAY_USE_LCD 0 -#endif +#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ /* * This #if/#else is needed to workaround a problem with the * IAR compiler. The IAR compiler doesn't like the empty array * initialization. (IAR Error[Pe1345]) */ -#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) const Display_Config Display_config[] = { -#if (BOARD_DISPLAY_USE_UART) +#if TI_DISPLAY_CONF_UART_ENABLE { -# if (BOARD_DISPLAY_USE_UART_ANSI) +# if TI_DISPLAY_CONF_USE_UART_ANSI .fxnTablePtr = &DisplayUartAnsi_fxnTable, # else /* Default to minimal UART with no cursor placement */ .fxnTablePtr = &DisplayUartMin_fxnTable, @@ -401,7 +410,7 @@ const Display_Config Display_config[] = { .hwAttrs = &displayUartHWAttrs, }, #endif -#if (BOARD_DISPLAY_USE_LCD) +#if TI_DISPLAY_CONF_LCD_ENABLE { .fxnTablePtr = &DisplaySharp_fxnTable, .object = &displaySharpObject, @@ -417,7 +426,7 @@ const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Conf const Display_Config *Display_config = NULL; const uint_least8_t Display_count = 0; -#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ +#endif /* TI_DISPLAY_CONF_ENABLE */ /* * =============================== GPIO =============================== @@ -519,9 +528,12 @@ const GPTimerCC26XX_Config GPTimerCC26XX_config[CC1352P_2_LAUNCHXL_GPTIMERPARTSC #include #include +#if TI_I2C_CONF_ENABLE + I2CCC26XX_Object i2cCC26xxObjects[CC1352P_2_LAUNCHXL_I2CCOUNT]; const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1352P_2_LAUNCHXL_I2CCOUNT] = { +#if TI_I2C_CONF_I2C0_ENABLE { .baseAddr = I2C0_BASE, .powerMngrId = PowerCC26XX_PERIPH_I2C0, @@ -530,19 +542,24 @@ const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1352P_2_LAUNCHXL_I2CCOUNT] = { .swiPriority = 0, .sdaPin = CC1352P_2_LAUNCHXL_I2C0_SDA0, .sclPin = CC1352P_2_LAUNCHXL_I2C0_SCL0, - } + }, +#endif }; const I2C_Config I2C_config[CC1352P_2_LAUNCHXL_I2CCOUNT] = { +#if TI_I2C_CONF_I2C0_ENABLE { .fxnTablePtr = &I2CCC26XX_fxnTable, .object = &i2cCC26xxObjects[CC1352P_2_LAUNCHXL_I2C0], .hwAttrs = &i2cCC26xxHWAttrs[CC1352P_2_LAUNCHXL_I2C0] }, +#endif }; const uint_least8_t I2C_count = CC1352P_2_LAUNCHXL_I2CCOUNT; +#endif /* TI_I2C_CONF_ENABLE */ + /* * =============================== NVS =============================== */ @@ -554,7 +571,9 @@ const uint_least8_t I2C_count = CC1352P_2_LAUNCHXL_I2CCOUNT; #define SECTORSIZE 0x2000 #define REGIONSIZE (SECTORSIZE * 4) -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_ENABLE + +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE /* * Reserve flash sectors for NVS driver use by placing an uninitialized byte @@ -604,9 +623,9 @@ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { }, }; -#endif /* Board_EXCLUDE_NVS_INTERNAL_FLASH */ +#endif /* TI_NVS_CONF_NVS_INTERNAL_ENABLE */ -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE #define SPISECTORSIZE 0x1000 #define SPIREGIONSIZE (SPISECTORSIZE * 32) @@ -632,18 +651,18 @@ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { }, }; -#endif /* Board_EXCLUDE_NVS_EXTERNAL_FLASH */ +#endif /* TI_NVS_CONF_NVS_EXTERNAL_ENABLE */ /* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ const NVS_Config NVS_config[CC1352P_2_LAUNCHXL_NVSCOUNT] = { -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE { .fxnTablePtr = &NVSCC26XX_fxnTable, .object = &nvsCC26xxObjects[0], .hwAttrs = &nvsCC26xxHWAttrs[0], }, #endif -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE { .fxnTablePtr = &NVSSPI25X_fxnTable, .object = &nvsSPI25XObjects[0], @@ -654,6 +673,8 @@ const NVS_Config NVS_config[CC1352P_2_LAUNCHXL_NVSCOUNT] = { const uint_least8_t NVS_count = CC1352P_2_LAUNCHXL_NVSCOUNT; +#endif /* TI_NVS_CONF_ENABLE */ + /* * =============================== PIN =============================== */ @@ -763,6 +784,12 @@ const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { #include #include +#if TI_SD_CONF_ENABLE + +#if !(TI_SPI_CONF_SPI0_ENABLE) +#error "SD driver requires SPI0 enabled" +#endif + SDSPI_Object sdspiObjects[CC1352P_2_LAUNCHXL_SDCOUNT]; const SDSPI_HWAttrs sdspiHWAttrs[CC1352P_2_LAUNCHXL_SDCOUNT] = { @@ -782,12 +809,16 @@ const SD_Config SD_config[CC1352P_2_LAUNCHXL_SDCOUNT] = { const uint_least8_t SD_count = CC1352P_2_LAUNCHXL_SDCOUNT; +#endif /* TI_SD_CONF_ENABLE */ + /* * =============================== SPI DMA =============================== */ #include #include +#if TI_SPI_CONF_ENABLE + SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1352P_2_LAUNCHXL_SPICOUNT]; /* @@ -796,6 +827,7 @@ SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1352P_2_LAUNCHXL_SPICOUNT]; * to satisfy the SDSPI driver requirement. */ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1352P_2_LAUNCHXL_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .baseAddr = SSI0_BASE, .intNum = INT_SSI0_COMB, @@ -811,6 +843,8 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1352P_2_LAUNCHXL_SPICOUNT] = .csnPin = CC1352P_2_LAUNCHXL_SPI0_CSN, .minDmaTransferSize = 10 }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .baseAddr = SSI1_BASE, .intNum = INT_SSI1_COMB, @@ -825,35 +859,45 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1352P_2_LAUNCHXL_SPICOUNT] = .clkPin = CC1352P_2_LAUNCHXL_SPI1_CLK, .csnPin = CC1352P_2_LAUNCHXL_SPI1_CSN, .minDmaTransferSize = 10 - } + }, +#endif }; const SPI_Config SPI_config[CC1352P_2_LAUNCHXL_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC1352P_2_LAUNCHXL_SPI0], .hwAttrs = &spiCC26XXDMAHWAttrs[CC1352P_2_LAUNCHXL_SPI0] }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC1352P_2_LAUNCHXL_SPI1], .hwAttrs = &spiCC26XXDMAHWAttrs[CC1352P_2_LAUNCHXL_SPI1] }, +#endif }; const uint_least8_t SPI_count = CC1352P_2_LAUNCHXL_SPICOUNT; +#endif /* TI_SPI_CONF_ENABLE */ + /* * =============================== UART =============================== */ #include #include +#if TI_UART_CONF_ENABLE + UARTCC26XX_Object uartCC26XXObjects[CC1352P_2_LAUNCHXL_UARTCOUNT]; uint8_t uartCC26XXRingBuffer[CC1352P_2_LAUNCHXL_UARTCOUNT][32]; const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1352P_2_LAUNCHXL_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .baseAddr = UART0_BASE, .powerMngrId = PowerCC26XX_PERIPH_UART0, @@ -870,6 +914,8 @@ const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1352P_2_LAUNCHXL_UARTCOUNT] = { .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, .errorFxn = NULL }, +#endif +#if TI_UART_CONF_UART1_ENABLE { .baseAddr = UART1_BASE, .powerMngrId = PowerCC26X2_PERIPH_UART1, @@ -885,24 +931,31 @@ const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1352P_2_LAUNCHXL_UARTCOUNT] = { .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, .errorFxn = NULL - } + }, +#endif }; const UART_Config UART_config[CC1352P_2_LAUNCHXL_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .fxnTablePtr = &UARTCC26XX_fxnTable, .object = &uartCC26XXObjects[CC1352P_2_LAUNCHXL_UART0], .hwAttrs = &uartCC26XXHWAttrs[CC1352P_2_LAUNCHXL_UART0] }, +#endif +#if TI_UART_CONF_UART1_ENABLE { .fxnTablePtr = &UARTCC26XX_fxnTable, .object = &uartCC26XXObjects[CC1352P_2_LAUNCHXL_UART1], .hwAttrs = &uartCC26XXHWAttrs[CC1352P_2_LAUNCHXL_UART1] }, +#endif }; const uint_least8_t UART_count = CC1352P_2_LAUNCHXL_UARTCOUNT; +#endif /* TI_UART_CONF_ENABLE */ + /* * =============================== UDMA =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h index 443f9badb..f71a15aa6 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h @@ -49,6 +49,8 @@ extern "C" { #endif +#include "contiki-conf.h" + /* Includes */ #include #include @@ -197,8 +199,6 @@ typedef enum CC1352P_2_LAUNCHXL_ADCBuf0ChannelName { CC1352P_2_LAUNCHXL_ADCBUF0CHANNEL2, CC1352P_2_LAUNCHXL_ADCBUF0CHANNEL3, CC1352P_2_LAUNCHXL_ADCBUF0CHANNEL4, - CC1352P_2_LAUNCHXL_ADCBUF0CHANNEL5, - CC1352P_2_LAUNCHXL_ADCBUF0CHANNEL6, CC1352P_2_LAUNCHXL_ADCBUF0CHANNELVDDS, CC1352P_2_LAUNCHXL_ADCBUF0CHANNELDCOUPL, CC1352P_2_LAUNCHXL_ADCBUF0CHANNELVSS, @@ -216,8 +216,6 @@ typedef enum CC1352P_2_LAUNCHXL_ADCName { CC1352P_2_LAUNCHXL_ADC2, CC1352P_2_LAUNCHXL_ADC3, CC1352P_2_LAUNCHXL_ADC4, - CC1352P_2_LAUNCHXL_ADC5, - CC1352P_2_LAUNCHXL_ADC6, CC1352P_2_LAUNCHXL_ADCDCOUPL, CC1352P_2_LAUNCHXL_ADCVSS, CC1352P_2_LAUNCHXL_ADCVDDS, @@ -338,7 +336,9 @@ typedef enum CC1352P_2_LAUNCHXL_GPTimers { * @brief Enum of I2C names */ typedef enum CC1352P_2_LAUNCHXL_I2CName { +#if TI_I2C_CONF_I2C0_ENABLE CC1352P_2_LAUNCHXL_I2C0 = 0, +#endif CC1352P_2_LAUNCHXL_I2CCOUNT } CC1352P_2_LAUNCHXL_I2CName; @@ -348,10 +348,10 @@ typedef enum CC1352P_2_LAUNCHXL_I2CName { * @brief Enum of NVS names */ typedef enum CC1352P_2_LAUNCHXL_NVSName { -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE CC1352P_2_LAUNCHXL_NVSCC26XX0 = 0, #endif -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE CC1352P_2_LAUNCHXL_NVSSPI25X0, #endif @@ -390,8 +390,12 @@ typedef enum CC1352P_2_LAUNCHXL_SDName { * @brief Enum of SPI names */ typedef enum CC1352P_2_LAUNCHXL_SPIName { +#if TI_SPI_CONF_SPI0_ENABLE CC1352P_2_LAUNCHXL_SPI0 = 0, +#endif +#if TI_SPI_CONF_SPI1_ENABLE CC1352P_2_LAUNCHXL_SPI1, +#endif CC1352P_2_LAUNCHXL_SPICOUNT } CC1352P_2_LAUNCHXL_SPIName; @@ -401,8 +405,12 @@ typedef enum CC1352P_2_LAUNCHXL_SPIName { * @brief Enum of UARTs */ typedef enum CC1352P_2_LAUNCHXL_UARTName { +#if TI_UART_CONF_UART0_ENABLE CC1352P_2_LAUNCHXL_UART0 = 0, +#endif +#if TI_UART_CONF_UART1_ENABLE CC1352P_2_LAUNCHXL_UART1, +#endif CC1352P_2_LAUNCHXL_UARTCOUNT } CC1352P_2_LAUNCHXL_UARTName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.c index 0d5346cf5..007bcfeab 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.c @@ -340,19 +340,21 @@ const uint_least8_t AESECB_count = CC1352P_4_LAUNCHXL_AESECBCOUNT; #include #include +#if TI_DISPLAY_CONF_ENABLE + +#if TI_DISPLAY_CONF_UART_ENABLE + +#if !(TI_UART_CONF_UART0_ENABLE) +#error "Display UART driver requires UART0" +#endif + #ifndef BOARD_DISPLAY_UART_STRBUF_SIZE #define BOARD_DISPLAY_UART_STRBUF_SIZE 128 #endif -#ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 -#endif +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; DisplayUart_Object displayUartObject; -DisplaySharp_Object displaySharpObject; - -static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; -static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; const DisplayUart_HWAttrs displayUartHWAttrs = { .uartIdx = CC1352P_4_LAUNCHXL_UART0, @@ -362,6 +364,22 @@ const DisplayUart_HWAttrs displayUartHWAttrs = { .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, }; +#endif /* TI_DISPLAY_CONF_UART_ENABLE */ + +#if TI_DISPLAY_CONF_LCD_ENABLE + +#if !(TI_SPI_CONF_SPI0_ENABLE) +#error "Display LCD driver requires SPI0" +#endif + +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 +#endif + +static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; + +DisplaySharp_Object displaySharpObject; + const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .spiIndex = CC1352P_4_LAUNCHXL_SPI0, .csPin = CC1352P_4_LAUNCHXL_GPIO_LCD_CS, @@ -372,27 +390,18 @@ const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .displayBuf = sharpDisplayBuf, }; -#ifndef BOARD_DISPLAY_USE_UART -#define BOARD_DISPLAY_USE_UART 1 -#endif -#ifndef BOARD_DISPLAY_USE_UART_ANSI -#define BOARD_DISPLAY_USE_UART_ANSI 0 -#endif -#ifndef BOARD_DISPLAY_USE_LCD -#define BOARD_DISPLAY_USE_LCD 0 -#endif +#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ /* * This #if/#else is needed to workaround a problem with the * IAR compiler. The IAR compiler doesn't like the empty array * initialization. (IAR Error[Pe1345]) */ -#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) const Display_Config Display_config[] = { -#if (BOARD_DISPLAY_USE_UART) +#if TI_DISPLAY_CONF_UART_ENABLE { -# if (BOARD_DISPLAY_USE_UART_ANSI) +# if TI_DISPLAY_CONF_USE_UART_ANSI .fxnTablePtr = &DisplayUartAnsi_fxnTable, # else /* Default to minimal UART with no cursor placement */ .fxnTablePtr = &DisplayUartMin_fxnTable, @@ -401,7 +410,7 @@ const Display_Config Display_config[] = { .hwAttrs = &displayUartHWAttrs, }, #endif -#if (BOARD_DISPLAY_USE_LCD) +#if TI_DISPLAY_CONF_LCD_ENABLE { .fxnTablePtr = &DisplaySharp_fxnTable, .object = &displaySharpObject, @@ -417,7 +426,7 @@ const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Conf const Display_Config *Display_config = NULL; const uint_least8_t Display_count = 0; -#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ +#endif /* TI_DISPLAY_CONF_ENABLE */ /* * =============================== GPIO =============================== @@ -519,9 +528,12 @@ const GPTimerCC26XX_Config GPTimerCC26XX_config[CC1352P_4_LAUNCHXL_GPTIMERPARTSC #include #include +#if TI_I2C_CONF_ENABLE + I2CCC26XX_Object i2cCC26xxObjects[CC1352P_4_LAUNCHXL_I2CCOUNT]; const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1352P_4_LAUNCHXL_I2CCOUNT] = { +#if TI_I2C_CONF_I2C0_ENABLE { .baseAddr = I2C0_BASE, .powerMngrId = PowerCC26XX_PERIPH_I2C0, @@ -530,19 +542,24 @@ const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1352P_4_LAUNCHXL_I2CCOUNT] = { .swiPriority = 0, .sdaPin = CC1352P_4_LAUNCHXL_I2C0_SDA0, .sclPin = CC1352P_4_LAUNCHXL_I2C0_SCL0, - } + }, +#endif }; const I2C_Config I2C_config[CC1352P_4_LAUNCHXL_I2CCOUNT] = { +#if TI_I2C_CONF_I2C0_ENABLE { .fxnTablePtr = &I2CCC26XX_fxnTable, .object = &i2cCC26xxObjects[CC1352P_4_LAUNCHXL_I2C0], .hwAttrs = &i2cCC26xxHWAttrs[CC1352P_4_LAUNCHXL_I2C0] }, +#endif }; const uint_least8_t I2C_count = CC1352P_4_LAUNCHXL_I2CCOUNT; +#endif /* TI_I2C_CONF_ENABLE */ + /* * =============================== NVS =============================== */ @@ -554,7 +571,9 @@ const uint_least8_t I2C_count = CC1352P_4_LAUNCHXL_I2CCOUNT; #define SECTORSIZE 0x2000 #define REGIONSIZE (SECTORSIZE * 4) -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_ENABLE + +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE /* * Reserve flash sectors for NVS driver use by placing an uninitialized byte @@ -604,9 +623,9 @@ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { }, }; -#endif /* Board_EXCLUDE_NVS_INTERNAL_FLASH */ +#endif /* TI_NVS_CONF_NVS_INTERNAL_ENABLE */ -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE #define SPISECTORSIZE 0x1000 #define SPIREGIONSIZE (SPISECTORSIZE * 32) @@ -632,18 +651,18 @@ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { }, }; -#endif /* Board_EXCLUDE_NVS_EXTERNAL_FLASH */ +#endif /* TI_NVS_CONF_NVS_EXTERNAL_ENABLE */ /* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ const NVS_Config NVS_config[CC1352P_4_LAUNCHXL_NVSCOUNT] = { -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE { .fxnTablePtr = &NVSCC26XX_fxnTable, .object = &nvsCC26xxObjects[0], .hwAttrs = &nvsCC26xxHWAttrs[0], }, #endif -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE { .fxnTablePtr = &NVSSPI25X_fxnTable, .object = &nvsSPI25XObjects[0], @@ -654,6 +673,8 @@ const NVS_Config NVS_config[CC1352P_4_LAUNCHXL_NVSCOUNT] = { const uint_least8_t NVS_count = CC1352P_4_LAUNCHXL_NVSCOUNT; +#endif /* TI_NVS_CONF_ENABLE */ + /* * =============================== PIN =============================== */ @@ -763,6 +784,12 @@ const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { #include #include +#if TI_SD_CONF_ENABLE + +#if !(TI_SPI_CONF_SPI0_ENABLE) +#error "SD driver requires SPI0 enabled" +#endif + SDSPI_Object sdspiObjects[CC1352P_4_LAUNCHXL_SDCOUNT]; const SDSPI_HWAttrs sdspiHWAttrs[CC1352P_4_LAUNCHXL_SDCOUNT] = { @@ -782,6 +809,8 @@ const SD_Config SD_config[CC1352P_4_LAUNCHXL_SDCOUNT] = { const uint_least8_t SD_count = CC1352P_4_LAUNCHXL_SDCOUNT; +#endif /* TI_SD_CONF_ENABLE */ + /* * =============================== SPI DMA =============================== */ @@ -790,12 +819,15 @@ const uint_least8_t SD_count = CC1352P_4_LAUNCHXL_SDCOUNT; SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1352P_4_LAUNCHXL_SPICOUNT]; +#if TI_SPI_CONF_ENABLE + /* * NOTE: The SPI instances below can be used by the SD driver to communicate * with a SD card via SPI. The 'defaultTxBufValue' fields below are set to 0xFF * to satisfy the SDSPI driver requirement. */ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1352P_4_LAUNCHXL_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .baseAddr = SSI0_BASE, .intNum = INT_SSI0_COMB, @@ -811,6 +843,8 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1352P_4_LAUNCHXL_SPICOUNT] = .csnPin = CC1352P_4_LAUNCHXL_SPI0_CSN, .minDmaTransferSize = 10 }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .baseAddr = SSI1_BASE, .intNum = INT_SSI1_COMB, @@ -825,35 +859,45 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1352P_4_LAUNCHXL_SPICOUNT] = .clkPin = CC1352P_4_LAUNCHXL_SPI1_CLK, .csnPin = CC1352P_4_LAUNCHXL_SPI1_CSN, .minDmaTransferSize = 10 - } + }, +#endif }; const SPI_Config SPI_config[CC1352P_4_LAUNCHXL_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC1352P_4_LAUNCHXL_SPI0], .hwAttrs = &spiCC26XXDMAHWAttrs[CC1352P_4_LAUNCHXL_SPI0] }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC1352P_4_LAUNCHXL_SPI1], .hwAttrs = &spiCC26XXDMAHWAttrs[CC1352P_4_LAUNCHXL_SPI1] }, +#endif }; const uint_least8_t SPI_count = CC1352P_4_LAUNCHXL_SPICOUNT; +#endif /* TI_SPI_CONF_ENABLE */ + /* * =============================== UART =============================== */ #include #include +#if TI_UART_CONF_ENABLE + UARTCC26XX_Object uartCC26XXObjects[CC1352P_4_LAUNCHXL_UARTCOUNT]; uint8_t uartCC26XXRingBuffer[CC1352P_4_LAUNCHXL_UARTCOUNT][32]; const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1352P_4_LAUNCHXL_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .baseAddr = UART0_BASE, .powerMngrId = PowerCC26XX_PERIPH_UART0, @@ -870,6 +914,8 @@ const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1352P_4_LAUNCHXL_UARTCOUNT] = { .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, .errorFxn = NULL }, +#endif +#if TI_UART_CONF_UART1_ENABLE { .baseAddr = UART1_BASE, .powerMngrId = PowerCC26X2_PERIPH_UART1, @@ -885,24 +931,31 @@ const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1352P_4_LAUNCHXL_UARTCOUNT] = { .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, .errorFxn = NULL - } + }, +#endif }; const UART_Config UART_config[CC1352P_4_LAUNCHXL_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .fxnTablePtr = &UARTCC26XX_fxnTable, .object = &uartCC26XXObjects[CC1352P_4_LAUNCHXL_UART0], .hwAttrs = &uartCC26XXHWAttrs[CC1352P_4_LAUNCHXL_UART0] }, +#endif +#if TI_UART_CONF_UART1_ENABLE { .fxnTablePtr = &UARTCC26XX_fxnTable, .object = &uartCC26XXObjects[CC1352P_4_LAUNCHXL_UART1], .hwAttrs = &uartCC26XXHWAttrs[CC1352P_4_LAUNCHXL_UART1] }, +#endif }; const uint_least8_t UART_count = CC1352P_4_LAUNCHXL_UARTCOUNT; +#endif /* TI_UART_CONF_ENABLE */ + /* * =============================== UDMA =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.h index bd8bc2594..bee9657ea 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.h @@ -49,6 +49,8 @@ extern "C" { #endif +#include "contiki-conf.h" + /* Includes */ #include #include @@ -197,8 +199,6 @@ typedef enum CC1352P_4_LAUNCHXL_ADCBuf0ChannelName { CC1352P_4_LAUNCHXL_ADCBUF0CHANNEL2, CC1352P_4_LAUNCHXL_ADCBUF0CHANNEL3, CC1352P_4_LAUNCHXL_ADCBUF0CHANNEL4, - CC1352P_4_LAUNCHXL_ADCBUF0CHANNEL5, - CC1352P_4_LAUNCHXL_ADCBUF0CHANNEL6, CC1352P_4_LAUNCHXL_ADCBUF0CHANNELVDDS, CC1352P_4_LAUNCHXL_ADCBUF0CHANNELDCOUPL, CC1352P_4_LAUNCHXL_ADCBUF0CHANNELVSS, @@ -216,8 +216,6 @@ typedef enum CC1352P_4_LAUNCHXL_ADCName { CC1352P_4_LAUNCHXL_ADC2, CC1352P_4_LAUNCHXL_ADC3, CC1352P_4_LAUNCHXL_ADC4, - CC1352P_4_LAUNCHXL_ADC5, - CC1352P_4_LAUNCHXL_ADC6, CC1352P_4_LAUNCHXL_ADCDCOUPL, CC1352P_4_LAUNCHXL_ADCVSS, CC1352P_4_LAUNCHXL_ADCVDDS, @@ -338,7 +336,9 @@ typedef enum CC1352P_4_LAUNCHXL_GPTimers { * @brief Enum of I2C names */ typedef enum CC1352P_4_LAUNCHXL_I2CName { +#if TI_I2C_CONF_I2C0_ENABLE CC1352P_4_LAUNCHXL_I2C0 = 0, +#endif CC1352P_4_LAUNCHXL_I2CCOUNT } CC1352P_4_LAUNCHXL_I2CName; @@ -348,10 +348,10 @@ typedef enum CC1352P_4_LAUNCHXL_I2CName { * @brief Enum of NVS names */ typedef enum CC1352P_4_LAUNCHXL_NVSName { -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE CC1352P_4_LAUNCHXL_NVSCC26XX0 = 0, #endif -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE CC1352P_4_LAUNCHXL_NVSSPI25X0, #endif @@ -390,8 +390,12 @@ typedef enum CC1352P_4_LAUNCHXL_SDName { * @brief Enum of SPI names */ typedef enum CC1352P_4_LAUNCHXL_SPIName { +#if TI_SPI_CONF_SPI0_ENABLE CC1352P_4_LAUNCHXL_SPI0 = 0, +#endif +#if TI_SPI_CONF_SPI1_ENABLE CC1352P_4_LAUNCHXL_SPI1, +#endif CC1352P_4_LAUNCHXL_SPICOUNT } CC1352P_4_LAUNCHXL_SPIName; @@ -401,8 +405,12 @@ typedef enum CC1352P_4_LAUNCHXL_SPIName { * @brief Enum of UARTs */ typedef enum CC1352P_4_LAUNCHXL_UARTName { +#if TI_UART_CONF_UART0_ENABLE CC1352P_4_LAUNCHXL_UART0 = 0, +#endif +#if TI_UART_CONF_UART1_ENABLE CC1352P_4_LAUNCHXL_UART1, +#endif CC1352P_4_LAUNCHXL_UARTCOUNT } CC1352P_4_LAUNCHXL_UARTName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.c index 9a42399a8..8ec044737 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.c @@ -340,19 +340,21 @@ const uint_least8_t AESECB_count = CC1352P1_LAUNCHXL_AESECBCOUNT; #include #include +#if TI_DISPLAY_CONF_ENABLE + +#if TI_DISPLAY_CONF_UART_ENABLE + +#if !(TI_UART_CONF_UART0_ENABLE) +#error "Display UART driver requires UART0" +#endif + #ifndef BOARD_DISPLAY_UART_STRBUF_SIZE #define BOARD_DISPLAY_UART_STRBUF_SIZE 128 #endif -#ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 -#endif +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; DisplayUart_Object displayUartObject; -DisplaySharp_Object displaySharpObject; - -static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; -static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; const DisplayUart_HWAttrs displayUartHWAttrs = { .uartIdx = CC1352P1_LAUNCHXL_UART0, @@ -362,6 +364,22 @@ const DisplayUart_HWAttrs displayUartHWAttrs = { .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, }; +#endif /* TI_DISPLAY_CONF_UART_ENABLE */ + +#if TI_DISPLAY_CONF_LCD_ENABLE + +#if !(TI_SPI_CONF_SPI0_ENABLE) +#error "Display LCD driver requires SPI0" +#endif + +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 +#endif + +static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; + +DisplaySharp_Object displaySharpObject; + const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .spiIndex = CC1352P1_LAUNCHXL_SPI0, .csPin = CC1352P1_LAUNCHXL_GPIO_LCD_CS, @@ -372,27 +390,18 @@ const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .displayBuf = sharpDisplayBuf, }; -#ifndef BOARD_DISPLAY_USE_UART -#define BOARD_DISPLAY_USE_UART 1 -#endif -#ifndef BOARD_DISPLAY_USE_UART_ANSI -#define BOARD_DISPLAY_USE_UART_ANSI 0 -#endif -#ifndef BOARD_DISPLAY_USE_LCD -#define BOARD_DISPLAY_USE_LCD 0 -#endif +#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ /* * This #if/#else is needed to workaround a problem with the * IAR compiler. The IAR compiler doesn't like the empty array * initialization. (IAR Error[Pe1345]) */ -#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) const Display_Config Display_config[] = { -#if (BOARD_DISPLAY_USE_UART) +#if TI_DISPLAY_CONF_UART_ENABLE { -# if (BOARD_DISPLAY_USE_UART_ANSI) +# if TI_DISPLAY_CONF_USE_UART_ANSI .fxnTablePtr = &DisplayUartAnsi_fxnTable, # else /* Default to minimal UART with no cursor placement */ .fxnTablePtr = &DisplayUartMin_fxnTable, @@ -401,7 +410,7 @@ const Display_Config Display_config[] = { .hwAttrs = &displayUartHWAttrs, }, #endif -#if (BOARD_DISPLAY_USE_LCD) +#if TI_DISPLAY_CONF_LCD_ENABLE { .fxnTablePtr = &DisplaySharp_fxnTable, .object = &displaySharpObject, @@ -417,7 +426,7 @@ const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Conf const Display_Config *Display_config = NULL; const uint_least8_t Display_count = 0; -#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ +#endif /* TI_DISPLAY_CONF_ENABLE */ /* * =============================== GPIO =============================== @@ -519,9 +528,12 @@ const GPTimerCC26XX_Config GPTimerCC26XX_config[CC1352P1_LAUNCHXL_GPTIMERPARTSCO #include #include +#if TI_I2C_CONF_ENABLE + I2CCC26XX_Object i2cCC26xxObjects[CC1352P1_LAUNCHXL_I2CCOUNT]; const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1352P1_LAUNCHXL_I2CCOUNT] = { +#if TI_I2C_CONF_I2C0_ENABLE { .baseAddr = I2C0_BASE, .powerMngrId = PowerCC26XX_PERIPH_I2C0, @@ -530,19 +542,24 @@ const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1352P1_LAUNCHXL_I2CCOUNT] = { .swiPriority = 0, .sdaPin = CC1352P1_LAUNCHXL_I2C0_SDA0, .sclPin = CC1352P1_LAUNCHXL_I2C0_SCL0, - } + }, +#endif }; const I2C_Config I2C_config[CC1352P1_LAUNCHXL_I2CCOUNT] = { +#if TI_I2C_CONF_I2C0_ENABLE { .fxnTablePtr = &I2CCC26XX_fxnTable, .object = &i2cCC26xxObjects[CC1352P1_LAUNCHXL_I2C0], .hwAttrs = &i2cCC26xxHWAttrs[CC1352P1_LAUNCHXL_I2C0] }, +#endif }; const uint_least8_t I2C_count = CC1352P1_LAUNCHXL_I2CCOUNT; +#endif /* TI_I2C_CONF_ENABLE */ + /* * =============================== NVS =============================== */ @@ -554,7 +571,9 @@ const uint_least8_t I2C_count = CC1352P1_LAUNCHXL_I2CCOUNT; #define SECTORSIZE 0x2000 #define REGIONSIZE (SECTORSIZE * 4) -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_ENABLE + +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE /* * Reserve flash sectors for NVS driver use by placing an uninitialized byte @@ -604,9 +623,9 @@ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { }, }; -#endif /* Board_EXCLUDE_NVS_INTERNAL_FLASH */ +#endif /* TI_NVS_CONF_NVS_INTERNAL_ENABLE */ -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE #define SPISECTORSIZE 0x1000 #define SPIREGIONSIZE (SPISECTORSIZE * 32) @@ -632,18 +651,18 @@ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { }, }; -#endif /* Board_EXCLUDE_NVS_EXTERNAL_FLASH */ +#endif /* TI_NVS_CONF_NVS_EXTERNAL_ENABLE */ /* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ const NVS_Config NVS_config[CC1352P1_LAUNCHXL_NVSCOUNT] = { -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE { .fxnTablePtr = &NVSCC26XX_fxnTable, .object = &nvsCC26xxObjects[0], .hwAttrs = &nvsCC26xxHWAttrs[0], }, #endif -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE { .fxnTablePtr = &NVSSPI25X_fxnTable, .object = &nvsSPI25XObjects[0], @@ -654,6 +673,8 @@ const NVS_Config NVS_config[CC1352P1_LAUNCHXL_NVSCOUNT] = { const uint_least8_t NVS_count = CC1352P1_LAUNCHXL_NVSCOUNT; +#endif /* TI_NVS_CONF_ENABLE */ + /* * =============================== PIN =============================== */ @@ -763,6 +784,12 @@ const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { #include #include +#if TI_SD_CONF_ENABLE + +#if !(TI_SPI_CONF_SPI0_ENABLE) +#error "SD driver requires SPI0 enabled" +#endif + SDSPI_Object sdspiObjects[CC1352P1_LAUNCHXL_SDCOUNT]; const SDSPI_HWAttrs sdspiHWAttrs[CC1352P1_LAUNCHXL_SDCOUNT] = { @@ -782,12 +809,16 @@ const SD_Config SD_config[CC1352P1_LAUNCHXL_SDCOUNT] = { const uint_least8_t SD_count = CC1352P1_LAUNCHXL_SDCOUNT; +#endif /* TI_SD_CONF_ENABLE */ + /* * =============================== SPI DMA =============================== */ #include #include +#if TI_SPI_CONF_ENABLE + SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1352P1_LAUNCHXL_SPICOUNT]; /* @@ -796,6 +827,7 @@ SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1352P1_LAUNCHXL_SPICOUNT]; * to satisfy the SDSPI driver requirement. */ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1352P1_LAUNCHXL_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .baseAddr = SSI0_BASE, .intNum = INT_SSI0_COMB, @@ -811,6 +843,8 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1352P1_LAUNCHXL_SPICOUNT] = { .csnPin = CC1352P1_LAUNCHXL_SPI0_CSN, .minDmaTransferSize = 10 }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .baseAddr = SSI1_BASE, .intNum = INT_SSI1_COMB, @@ -825,35 +859,45 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1352P1_LAUNCHXL_SPICOUNT] = { .clkPin = CC1352P1_LAUNCHXL_SPI1_CLK, .csnPin = CC1352P1_LAUNCHXL_SPI1_CSN, .minDmaTransferSize = 10 - } + }, +#endif }; const SPI_Config SPI_config[CC1352P1_LAUNCHXL_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC1352P1_LAUNCHXL_SPI0], .hwAttrs = &spiCC26XXDMAHWAttrs[CC1352P1_LAUNCHXL_SPI0] }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC1352P1_LAUNCHXL_SPI1], .hwAttrs = &spiCC26XXDMAHWAttrs[CC1352P1_LAUNCHXL_SPI1] }, +#endif }; const uint_least8_t SPI_count = CC1352P1_LAUNCHXL_SPICOUNT; +#endif /* TI_SPI_CONF_ENABLE */ + /* * =============================== UART =============================== */ #include #include +#if TI_UART_CONF_ENABLE + UARTCC26XX_Object uartCC26XXObjects[CC1352P1_LAUNCHXL_UARTCOUNT]; uint8_t uartCC26XXRingBuffer[CC1352P1_LAUNCHXL_UARTCOUNT][32]; const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1352P1_LAUNCHXL_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .baseAddr = UART0_BASE, .powerMngrId = PowerCC26XX_PERIPH_UART0, @@ -870,6 +914,8 @@ const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1352P1_LAUNCHXL_UARTCOUNT] = { .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, .errorFxn = NULL }, +#endif +#if TI_UART_CONF_UART1_ENABLE { .baseAddr = UART1_BASE, .powerMngrId = PowerCC26X2_PERIPH_UART1, @@ -885,24 +931,31 @@ const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1352P1_LAUNCHXL_UARTCOUNT] = { .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, .errorFxn = NULL - } + }, +#endif }; const UART_Config UART_config[CC1352P1_LAUNCHXL_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .fxnTablePtr = &UARTCC26XX_fxnTable, .object = &uartCC26XXObjects[CC1352P1_LAUNCHXL_UART0], .hwAttrs = &uartCC26XXHWAttrs[CC1352P1_LAUNCHXL_UART0] }, +#endif +#if TI_UART_CONF_UART1_ENABLE { .fxnTablePtr = &UARTCC26XX_fxnTable, .object = &uartCC26XXObjects[CC1352P1_LAUNCHXL_UART1], .hwAttrs = &uartCC26XXHWAttrs[CC1352P1_LAUNCHXL_UART1] }, +#endif }; const uint_least8_t UART_count = CC1352P1_LAUNCHXL_UARTCOUNT; +#endif /* TI_UART_CONF_ENABLE */ + /* * =============================== UDMA =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h index de1c315dd..af3478bac 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h @@ -49,6 +49,8 @@ extern "C" { #endif +#include "contiki-conf.h" + /* Includes */ #include #include @@ -338,7 +340,9 @@ typedef enum CC1352P1_LAUNCHXL_GPTimers { * @brief Enum of I2C names */ typedef enum CC1352P1_LAUNCHXL_I2CName { +#if TI_I2C_CONF_I2C0_ENABLE CC1352P1_LAUNCHXL_I2C0 = 0, +#endif CC1352P1_LAUNCHXL_I2CCOUNT } CC1352P1_LAUNCHXL_I2CName; @@ -348,10 +352,10 @@ typedef enum CC1352P1_LAUNCHXL_I2CName { * @brief Enum of NVS names */ typedef enum CC1352P1_LAUNCHXL_NVSName { -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE CC1352P1_LAUNCHXL_NVSCC26XX0 = 0, #endif -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE CC1352P1_LAUNCHXL_NVSSPI25X0, #endif @@ -390,8 +394,12 @@ typedef enum CC1352P1_LAUNCHXL_SDName { * @brief Enum of SPI names */ typedef enum CC1352P1_LAUNCHXL_SPIName { +#if TI_SPI_CONF_SPI0_ENABLE CC1352P1_LAUNCHXL_SPI0 = 0, +#endif +#if TI_SPI_CONF_SPI1_ENABLE CC1352P1_LAUNCHXL_SPI1, +#endif CC1352P1_LAUNCHXL_SPICOUNT } CC1352P1_LAUNCHXL_SPIName; @@ -401,8 +409,12 @@ typedef enum CC1352P1_LAUNCHXL_SPIName { * @brief Enum of UARTs */ typedef enum CC1352P1_LAUNCHXL_UARTName { +#if TI_UART_CONF_UART0_ENABLE CC1352P1_LAUNCHXL_UART0 = 0, +#endif +#if TI_UART_CONF_UART1_ENABLE CC1352P1_LAUNCHXL_UART1, +#endif CC1352P1_LAUNCHXL_UARTCOUNT } CC1352P1_LAUNCHXL_UARTName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c index b460191bc..5ed8d3167 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c @@ -364,19 +364,21 @@ const uint_least8_t AESECB_count = CC1352R1_LAUNCHXL_AESECBCOUNT; #include #include +#if TI_DISPLAY_CONF_ENABLE + +#if TI_DISPLAY_CONF_UART_ENABLE + +#if !(TI_UART_CONF_UART0_ENABLE) +#error "Display UART driver requires UART0" +#endif + #ifndef BOARD_DISPLAY_UART_STRBUF_SIZE #define BOARD_DISPLAY_UART_STRBUF_SIZE 128 #endif -#ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 -#endif +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; DisplayUart_Object displayUartObject; -DisplaySharp_Object displaySharpObject; - -static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; -static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; const DisplayUart_HWAttrs displayUartHWAttrs = { .uartIdx = CC1352R1_LAUNCHXL_UART0, @@ -386,6 +388,22 @@ const DisplayUart_HWAttrs displayUartHWAttrs = { .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, }; +#endif /* TI_DISPLAY_CONF_UART_ENABLE */ + +#if TI_DISPLAY_CONF_LCD_ENABLE + +#if !(TI_SPI_CONF_SPI0_ENABLE) +#error "Display LCD driver requires SPI0" +#endif + +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 +#endif + +static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; + +DisplaySharp_Object displaySharpObject; + const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .spiIndex = CC1352R1_LAUNCHXL_SPI0, .csPin = CC1352R1_LAUNCHXL_GPIO_LCD_CS, @@ -396,27 +414,18 @@ const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .displayBuf = sharpDisplayBuf, }; -#ifndef BOARD_DISPLAY_USE_UART -#define BOARD_DISPLAY_USE_UART 1 -#endif -#ifndef BOARD_DISPLAY_USE_UART_ANSI -#define BOARD_DISPLAY_USE_UART_ANSI 0 -#endif -#ifndef BOARD_DISPLAY_USE_LCD -#define BOARD_DISPLAY_USE_LCD 0 -#endif +#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ /* * This #if/#else is needed to workaround a problem with the * IAR compiler. The IAR compiler doesn't like the empty array * initialization. (IAR Error[Pe1345]) */ -#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) const Display_Config Display_config[] = { -#if (BOARD_DISPLAY_USE_UART) +#if TI_DISPLAY_CONF_UART_ENABLE { -# if (BOARD_DISPLAY_USE_UART_ANSI) +# if TI_DISPLAY_CONF_USE_UART_ANSI .fxnTablePtr = &DisplayUartAnsi_fxnTable, # else /* Default to minimal UART with no cursor placement */ .fxnTablePtr = &DisplayUartMin_fxnTable, @@ -425,7 +434,7 @@ const Display_Config Display_config[] = { .hwAttrs = &displayUartHWAttrs, }, #endif -#if (BOARD_DISPLAY_USE_LCD) +#if TI_DISPLAY_CONF_LCD_ENABLE { .fxnTablePtr = &DisplaySharp_fxnTable, .object = &displaySharpObject, @@ -441,7 +450,7 @@ const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Conf const Display_Config *Display_config = NULL; const uint_least8_t Display_count = 0; -#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ +#endif /* TI_DISPLAY_CONF_ENABLE */ /* * =============================== GPIO =============================== @@ -545,6 +554,7 @@ const GPTimerCC26XX_Config GPTimerCC26XX_config[CC1352R1_LAUNCHXL_GPTIMERPARTSCO I2CCC26XX_Object i2cCC26xxObjects[CC1352R1_LAUNCHXL_I2CCOUNT]; const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1352R1_LAUNCHXL_I2CCOUNT] = { +#if TI_I2C_CONF_I2C0_ENABLE { .baseAddr = I2C0_BASE, .powerMngrId = PowerCC26XX_PERIPH_I2C0, @@ -553,15 +563,18 @@ const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1352R1_LAUNCHXL_I2CCOUNT] = { .swiPriority = 0, .sdaPin = CC1352R1_LAUNCHXL_I2C0_SDA0, .sclPin = CC1352R1_LAUNCHXL_I2C0_SCL0, - } + }, +#endif }; const I2C_Config I2C_config[CC1352R1_LAUNCHXL_I2CCOUNT] = { +#if TI_I2C_CONF_I2C0_ENABLE { .fxnTablePtr = &I2CCC26XX_fxnTable, .object = &i2cCC26xxObjects[CC1352R1_LAUNCHXL_I2C0], .hwAttrs = &i2cCC26xxHWAttrs[CC1352R1_LAUNCHXL_I2C0] }, +#endif }; const uint_least8_t I2C_count = CC1352R1_LAUNCHXL_I2CCOUNT; @@ -790,6 +803,12 @@ const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { #include #include +#if TI_SD_CONF_ENABLE + +#if !(TI_SPI_CONF_SPI0_ENABLE) +#error "SD driver requires SPI0 enabled" +#endif + SDSPI_Object sdspiObjects[CC1352R1_LAUNCHXL_SDCOUNT]; const SDSPI_HWAttrs sdspiHWAttrs[CC1352R1_LAUNCHXL_SDCOUNT] = { @@ -809,6 +828,8 @@ const SD_Config SD_config[CC1352R1_LAUNCHXL_SDCOUNT] = { const uint_least8_t SD_count = CC1352R1_LAUNCHXL_SDCOUNT; +#endif /* TI_SD_CONF_ENABLE */ + /* * =============================== SPI DMA =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h index 0f165943b..3dcd63af5 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h @@ -49,6 +49,8 @@ extern "C" { #endif +#include "contiki-conf.h" + /* Includes */ #include #include @@ -330,7 +332,9 @@ typedef enum CC1352R1_LAUNCHXL_GPTimers { * @brief Enum of I2C names */ typedef enum CC1352R1_LAUNCHXL_I2CName { +#if TI_I2C_CONF_I2C0_ENABLE CC1352R1_LAUNCHXL_I2C0 = 0, +#endif CC1352R1_LAUNCHXL_I2CCOUNT } CC1352R1_LAUNCHXL_I2CName; @@ -340,10 +344,10 @@ typedef enum CC1352R1_LAUNCHXL_I2CName { * @brief Enum of NVS names */ typedef enum CC1352R1_LAUNCHXL_NVSName { -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE CC1352R1_LAUNCHXL_NVSCC26XX0 = 0, #endif -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE CC1352R1_LAUNCHXL_NVSSPI25X0, #endif @@ -382,8 +386,12 @@ typedef enum CC1352R1_LAUNCHXL_SDName { * @brief Enum of SPI names */ typedef enum CC1352R1_LAUNCHXL_SPIName { +#if TI_SPI_CONF_SPI0_ENABLE CC1352R1_LAUNCHXL_SPI0 = 0, +#endif +#if TI_SPI_CONF_SPI1_ENABLE CC1352R1_LAUNCHXL_SPI1, +#endif CC1352R1_LAUNCHXL_SPICOUNT } CC1352R1_LAUNCHXL_SPIName; @@ -393,8 +401,12 @@ typedef enum CC1352R1_LAUNCHXL_SPIName { * @brief Enum of UARTs */ typedef enum CC1352R1_LAUNCHXL_UARTName { +#if TI_UART_CONF_UART0_ENABLE CC1352R1_LAUNCHXL_UART0 = 0, +#endif +#if TI_UART_CONF_UART1_ENABLE CC1352R1_LAUNCHXL_UART1, +#endif CC1352R1_LAUNCHXL_UARTCOUNT } CC1352R1_LAUNCHXL_UARTName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.c index 7f2f0ef8b..b6c799ad2 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.c @@ -252,19 +252,21 @@ const CryptoCC26XX_Config CryptoCC26XX_config[CC2650_LAUNCHXL_CRYPTOCOUNT] = { #include #include +#if TI_DISPLAY_CONF_ENABLE + +#if TI_DISPLAY_CONF_UART_ENABLE + +#if !(TI_UART_CONF_UART0_ENABLE) +#error "Display UART driver requires UART0" +#endif + #ifndef BOARD_DISPLAY_UART_STRBUF_SIZE #define BOARD_DISPLAY_UART_STRBUF_SIZE 128 #endif -#ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 -#endif +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; DisplayUart_Object displayUartObject; -DisplaySharp_Object displaySharpObject; - -static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; -static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; const DisplayUart_HWAttrs displayUartHWAttrs = { .uartIdx = CC2650_LAUNCHXL_UART0, @@ -274,6 +276,22 @@ const DisplayUart_HWAttrs displayUartHWAttrs = { .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, }; +#endif /* TI_DISPLAY_CONF_UART_ENABLE */ + +#if TI_DISPLAY_CONF_LCD_ENABLE + +#if !(TI_SPI_CONF_SPI0_ENABLE) +#error "Display LCD driver requires SPI0" +#endif + +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 +#endif + +static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; + +DisplaySharp_Object displaySharpObject; + const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .spiIndex = CC2650_LAUNCHXL_SPI0, .csPin = CC2650_LAUNCHXL_GPIO_LCD_CS, @@ -284,27 +302,18 @@ const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .displayBuf = sharpDisplayBuf, }; -#ifndef BOARD_DISPLAY_USE_UART -#define BOARD_DISPLAY_USE_UART 1 -#endif -#ifndef BOARD_DISPLAY_USE_UART_ANSI -#define BOARD_DISPLAY_USE_UART_ANSI 0 -#endif -#ifndef BOARD_DISPLAY_USE_LCD -#define BOARD_DISPLAY_USE_LCD 0 -#endif +#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ /* * This #if/#else is needed to workaround a problem with the * IAR compiler. The IAR compiler doesn't like the empty array * initialization. (IAR Error[Pe1345]) */ -#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) const Display_Config Display_config[] = { -#if (BOARD_DISPLAY_USE_UART) +#if TI_DISPLAY_CONF_UART_ENABLE { -# if (BOARD_DISPLAY_USE_UART_ANSI) +# if TI_DISPLAY_CONF_USE_UART_ANSI .fxnTablePtr = &DisplayUartAnsi_fxnTable, # else /* Default to minimal UART with no cursor placement */ .fxnTablePtr = &DisplayUartMin_fxnTable, @@ -313,7 +322,7 @@ const Display_Config Display_config[] = { .hwAttrs = &displayUartHWAttrs, }, #endif -#if (BOARD_DISPLAY_USE_LCD) +#if TI_DISPLAY_CONF_LCD_ENABLE { .fxnTablePtr = &DisplaySharp_fxnTable, .object = &displaySharpObject, @@ -329,7 +338,7 @@ const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Conf const Display_Config *Display_config = NULL; const uint_least8_t Display_count = 0; -#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ +#endif /* TI_DISPLAY_CONF_ENABLE */ /* * =============================== GPIO =============================== @@ -428,9 +437,12 @@ const GPTimerCC26XX_Config GPTimerCC26XX_config[CC2650_LAUNCHXL_GPTIMERPARTSCOUN #include #include +#if TI_I2C_CONF_ENABLE + I2CCC26XX_Object i2cCC26xxObjects[CC2650_LAUNCHXL_I2CCOUNT]; const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC2650_LAUNCHXL_I2CCOUNT] = { +#if TI_I2C_CONF_I2C0_ENABLE { .baseAddr = I2C0_BASE, .powerMngrId = PowerCC26XX_PERIPH_I2C0, @@ -439,19 +451,24 @@ const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC2650_LAUNCHXL_I2CCOUNT] = { .swiPriority = 0, .sdaPin = CC2650_LAUNCHXL_I2C0_SDA0, .sclPin = CC2650_LAUNCHXL_I2C0_SCL0, - } + }, +#endif }; const I2C_Config I2C_config[CC2650_LAUNCHXL_I2CCOUNT] = { +#if TI_I2C_CONF_I2C0_ENABLE { .fxnTablePtr = &I2CCC26XX_fxnTable, .object = &i2cCC26xxObjects[CC2650_LAUNCHXL_I2C0], .hwAttrs = &i2cCC26xxHWAttrs[CC2650_LAUNCHXL_I2C0] }, +#endif }; const uint_least8_t I2C_count = CC2650_LAUNCHXL_I2CCOUNT; +#endif /* TI_I2C_CONF_ENABLE */ + /* * =============================== NVS =============================== */ @@ -463,7 +480,9 @@ const uint_least8_t I2C_count = CC2650_LAUNCHXL_I2CCOUNT; #define SECTORSIZE 0x1000 #define REGIONSIZE (SECTORSIZE * 4) -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_ENABLE + +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE /* * Reserve flash sectors for NVS driver use by placing an uninitialized byte @@ -513,9 +532,9 @@ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { }, }; -#endif /* Board_EXCLUDE_NVS_INTERNAL_FLASH */ +#endif /* TI_NVS_CONF_NVS_INTERNAL_ENABLE */ -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE #define SPISECTORSIZE 0x1000 #define SPIREGIONSIZE (SPISECTORSIZE * 32) @@ -545,14 +564,14 @@ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { /* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ const NVS_Config NVS_config[CC2650_LAUNCHXL_NVSCOUNT] = { -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE { .fxnTablePtr = &NVSCC26XX_fxnTable, .object = &nvsCC26xxObjects[0], .hwAttrs = &nvsCC26xxHWAttrs[0], }, #endif -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE { .fxnTablePtr = &NVSSPI25X_fxnTable, .object = &nvsSPI25XObjects[0], @@ -563,6 +582,8 @@ const NVS_Config NVS_config[CC2650_LAUNCHXL_NVSCOUNT] = { const uint_least8_t NVS_count = CC2650_LAUNCHXL_NVSCOUNT; +#endif /* TI_NVS_CONF_ENABLE */ + /* * =============================== PIN =============================== */ @@ -657,6 +678,12 @@ const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { #include #include +#if TI_SD_CONF_ENABLE + +#if !(TI_SPI_CONF_SPI0_ENABLE) +#error "SD driver requires SPI0 enabled" +#endif + SDSPI_Object sdspiObjects[CC2650_LAUNCHXL_SDCOUNT]; const SDSPI_HWAttrs sdspiHWAttrs[CC2650_LAUNCHXL_SDCOUNT] = { @@ -676,12 +703,16 @@ const SD_Config SD_config[CC2650_LAUNCHXL_SDCOUNT] = { const uint_least8_t SD_count = CC2650_LAUNCHXL_SDCOUNT; +#endif /* TI_SD_CONF_ENABLE */ + /* * =============================== SPI DMA =============================== */ #include #include +#if TI_SPI_CONF_ENABLE + SPICC26XXDMA_Object spiCC26XXDMAObjects[CC2650_LAUNCHXL_SPICOUNT]; /* @@ -690,6 +721,7 @@ SPICC26XXDMA_Object spiCC26XXDMAObjects[CC2650_LAUNCHXL_SPICOUNT]; * to satisfy the SDSPI driver requirement. */ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC2650_LAUNCHXL_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .baseAddr = SSI0_BASE, .intNum = INT_SSI0_COMB, @@ -705,6 +737,8 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC2650_LAUNCHXL_SPICOUNT] = { .csnPin = CC2650_LAUNCHXL_SPI0_CSN, .minDmaTransferSize = 10 }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .baseAddr = SSI1_BASE, .intNum = INT_SSI1_COMB, @@ -719,35 +753,45 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC2650_LAUNCHXL_SPICOUNT] = { .clkPin = CC2650_LAUNCHXL_SPI1_CLK, .csnPin = CC2650_LAUNCHXL_SPI1_CSN, .minDmaTransferSize = 10 - } + }, +#endif }; const SPI_Config SPI_config[CC2650_LAUNCHXL_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC2650_LAUNCHXL_SPI0], .hwAttrs = &spiCC26XXDMAHWAttrs[CC2650_LAUNCHXL_SPI0] }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC2650_LAUNCHXL_SPI1], .hwAttrs = &spiCC26XXDMAHWAttrs[CC2650_LAUNCHXL_SPI1] }, +#endif }; const uint_least8_t SPI_count = CC2650_LAUNCHXL_SPICOUNT; +#endif /* TI_SPI_CONF_ENABLE */ + /* * =============================== UART =============================== */ #include #include +#if TI_UART_CONF_ENABLE + UARTCC26XX_Object uartCC26XXObjects[CC2650_LAUNCHXL_UARTCOUNT]; uint8_t uartCC26XXRingBuffer[CC2650_LAUNCHXL_UARTCOUNT][32]; const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC2650_LAUNCHXL_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .baseAddr = UART0_BASE, .powerMngrId = PowerCC26XX_PERIPH_UART0, @@ -763,19 +807,24 @@ const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC2650_LAUNCHXL_UARTCOUNT] = { .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, .errorFxn = NULL - } + }, +#endif }; const UART_Config UART_config[CC2650_LAUNCHXL_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .fxnTablePtr = &UARTCC26XX_fxnTable, .object = &uartCC26XXObjects[CC2650_LAUNCHXL_UART0], .hwAttrs = &uartCC26XXHWAttrs[CC2650_LAUNCHXL_UART0] }, +#endif }; const uint_least8_t UART_count = CC2650_LAUNCHXL_UARTCOUNT; +#endif /* TI_UART_CONF_ENABLE */ + /* * =============================== UDMA =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h index a5f0b28da..89244b0f6 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h @@ -49,6 +49,8 @@ extern "C" { #endif +#include "contiki-conf.h" + /* Includes */ #include #include @@ -267,7 +269,9 @@ typedef enum CC2650_LAUNCHXL_GPTimers { * @brief Enum of I2C names */ typedef enum CC2650_LAUNCHXL_I2CName { +#if TI_I2C_CONF_I2C0_ENABLE CC2650_LAUNCHXL_I2C0 = 0, +#endif CC2650_LAUNCHXL_I2CCOUNT } CC2650_LAUNCHXL_I2CName; @@ -277,10 +281,10 @@ typedef enum CC2650_LAUNCHXL_I2CName { * @brief Enum of NVS names */ typedef enum CC2650_LAUNCHXL_NVSName { -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE CC2650_LAUNCHXL_NVSCC26XX0 = 0, #endif -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE CC2650_LAUNCHXL_NVSSPI25X0, #endif @@ -319,8 +323,12 @@ typedef enum CC2650_LAUNCHXL_SDName { * @brief Enum of SPI names */ typedef enum CC2650_LAUNCHXL_SPIName { +#if TI_SPI_CONF_SPI0_ENABLE CC2650_LAUNCHXL_SPI0 = 0, +#endif +#if TI_SPI_CONF_SPI1_ENABLE CC2650_LAUNCHXL_SPI1, +#endif CC2650_LAUNCHXL_SPICOUNT } CC2650_LAUNCHXL_SPIName; @@ -330,7 +338,9 @@ typedef enum CC2650_LAUNCHXL_SPIName { * @brief Enum of UARTs */ typedef enum CC2650_LAUNCHXL_UARTName { +#if TI_UART_CONF_UART0_ENABLE CC2650_LAUNCHXL_UART0 = 0, +#endif CC2650_LAUNCHXL_UARTCOUNT } CC2650_LAUNCHXL_UARTName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c index 188605db9..b7879f5a8 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c @@ -375,19 +375,21 @@ const uint_least8_t AESECB_count = CC26X2R1_LAUNCHXL_AESECBCOUNT; #include #include +#if TI_DISPLAY_CONF_ENABLE + +#if TI_DISPLAY_CONF_UART_ENABLE + +#if !(TI_UART_CONF_UART0_ENABLE) +#error "Display UART driver requires UART0" +#endif + #ifndef BOARD_DISPLAY_UART_STRBUF_SIZE #define BOARD_DISPLAY_UART_STRBUF_SIZE 128 #endif -#ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 -#endif +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; DisplayUart_Object displayUartObject; -DisplaySharp_Object displaySharpObject; - -static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; -static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; const DisplayUart_HWAttrs displayUartHWAttrs = { .uartIdx = CC26X2R1_LAUNCHXL_UART0, @@ -397,6 +399,22 @@ const DisplayUart_HWAttrs displayUartHWAttrs = { .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, }; +#endif /* TI_DISPLAY_CONF_UART_ENABLE */ + +#if TI_DISPLAY_CONF_LCD_ENABLE + +#if !(TI_SPI_CONF_SPI0_ENABLE) +#error "Display LCD driver requires SPI0" +#endif + +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 +#endif + +static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; + +DisplaySharp_Object displaySharpObject; + const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .spiIndex = CC26X2R1_LAUNCHXL_SPI0, .csPin = CC26X2R1_LAUNCHXL_GPIO_LCD_CS, @@ -407,27 +425,18 @@ const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .displayBuf = sharpDisplayBuf, }; -#ifndef BOARD_DISPLAY_USE_UART -#define BOARD_DISPLAY_USE_UART 1 -#endif -#ifndef BOARD_DISPLAY_USE_UART_ANSI -#define BOARD_DISPLAY_USE_UART_ANSI 0 -#endif -#ifndef BOARD_DISPLAY_USE_LCD -#define BOARD_DISPLAY_USE_LCD 0 -#endif +#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ /* * This #if/#else is needed to workaround a problem with the * IAR compiler. The IAR compiler doesn't like the empty array * initialization. (IAR Error[Pe1345]) */ -#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) const Display_Config Display_config[] = { -#if (BOARD_DISPLAY_USE_UART) +#if TI_DISPLAY_CONF_UART_ENABLE { -# if (BOARD_DISPLAY_USE_UART_ANSI) +# if TI_DISPLAY_CONF_USE_UART_ANSI .fxnTablePtr = &DisplayUartAnsi_fxnTable, # else /* Default to minimal UART with no cursor placement */ .fxnTablePtr = &DisplayUartMin_fxnTable, @@ -436,7 +445,7 @@ const Display_Config Display_config[] = { .hwAttrs = &displayUartHWAttrs, }, #endif -#if (BOARD_DISPLAY_USE_LCD) +#if TI_DISPLAY_CONF_LCD_ENABLE { .fxnTablePtr = &DisplaySharp_fxnTable, .object = &displaySharpObject, @@ -452,7 +461,7 @@ const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Conf const Display_Config *Display_config = NULL; const uint_least8_t Display_count = 0; -#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ +#endif /* TI_DISPLAY_CONF_ENABLE */ /* * =============================== GPIO =============================== @@ -556,6 +565,7 @@ const GPTimerCC26XX_Config GPTimerCC26XX_config[CC26X2R1_LAUNCHXL_GPTIMERPARTSCO I2CCC26XX_Object i2cCC26xxObjects[CC26X2R1_LAUNCHXL_I2CCOUNT]; const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC26X2R1_LAUNCHXL_I2CCOUNT] = { +#if TI_I2C_CONF_I2C0_ENABLE { .baseAddr = I2C0_BASE, .powerMngrId = PowerCC26XX_PERIPH_I2C0, @@ -564,15 +574,18 @@ const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC26X2R1_LAUNCHXL_I2CCOUNT] = { .swiPriority = 0, .sdaPin = CC26X2R1_LAUNCHXL_I2C0_SDA0, .sclPin = CC26X2R1_LAUNCHXL_I2C0_SCL0, - } + }, +#endif }; const I2C_Config I2C_config[CC26X2R1_LAUNCHXL_I2CCOUNT] = { +#if TI_I2C_CONF_I2C0_ENABLE { .fxnTablePtr = &I2CCC26XX_fxnTable, .object = &i2cCC26xxObjects[CC26X2R1_LAUNCHXL_I2C0], .hwAttrs = &i2cCC26xxHWAttrs[CC26X2R1_LAUNCHXL_I2C0] }, +#endif }; const uint_least8_t I2C_count = CC26X2R1_LAUNCHXL_I2CCOUNT; @@ -670,7 +683,7 @@ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { }, }; -#endif /* Board_EXCLUDE_NVS_EXTERNAL_FLASH */ +#endif /* TI_NVS_CONF_NVS_EXTERNAL_ENABLE */ /* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ const NVS_Config NVS_config[CC26X2R1_LAUNCHXL_NVSCOUNT] = { @@ -788,6 +801,12 @@ const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { #include #include +#if TI_SD_CONF_ENABLE + +#if !(TI_SPI_CONF_SPI0_ENABLE) +#error "SD driver requires SPI0 enabled" +#endif + SDSPI_Object sdspiObjects[CC26X2R1_LAUNCHXL_SDCOUNT]; const SDSPI_HWAttrs sdspiHWAttrs[CC26X2R1_LAUNCHXL_SDCOUNT] = { @@ -807,6 +826,8 @@ const SD_Config SD_config[CC26X2R1_LAUNCHXL_SDCOUNT] = { const uint_least8_t SD_count = CC26X2R1_LAUNCHXL_SDCOUNT; +#endif /* TI_SD_CONF_ENABLE */ + /* * =============================== SPI DMA =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h index db519d9f9..155fff3f9 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h @@ -49,6 +49,8 @@ extern "C" { #endif +#include "contiki-conf.h" + /* Includes */ #include #include @@ -332,7 +334,9 @@ typedef enum CC26X2R1_LAUNCHXL_GPTimers { * @brief Enum of I2C names */ typedef enum CC26X2R1_LAUNCHXL_I2CName { +#if TI_I2C_CONF_I2C0_ENABLE CC26X2R1_LAUNCHXL_I2C0 = 0, +#endif CC26X2R1_LAUNCHXL_I2CCOUNT } CC26X2R1_LAUNCHXL_I2CName; @@ -342,10 +346,10 @@ typedef enum CC26X2R1_LAUNCHXL_I2CName { * @brief Enum of NVS names */ typedef enum CC26X2R1_LAUNCHXL_NVSName { -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE CC26X2R1_LAUNCHXL_NVSCC26XX0 = 0, #endif -#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE CC26X2R1_LAUNCHXL_NVSSPI25X0, #endif @@ -384,8 +388,12 @@ typedef enum CC26X2R1_LAUNCHXL_SDName { * @brief Enum of SPI names */ typedef enum CC26X2R1_LAUNCHXL_SPIName { +#if TI_SPI_CONF_SPI0_ENABLE CC26X2R1_LAUNCHXL_SPI0 = 0, +#endif +#if TI_SPI_CONF_SPI1_ENABLE CC26X2R1_LAUNCHXL_SPI1, +#endif CC26X2R1_LAUNCHXL_SPICOUNT } CC26X2R1_LAUNCHXL_SPIName; @@ -395,8 +403,12 @@ typedef enum CC26X2R1_LAUNCHXL_SPIName { * @brief Enum of UARTs */ typedef enum CC26X2R1_LAUNCHXL_UARTName { +#if TI_UART_CONF_UART0_ENABLE CC26X2R1_LAUNCHXL_UART0 = 0, +#endif +#if TI_UART_CONF_UART1_ENABLE CC26X2R1_LAUNCHXL_UART1, +#endif CC26X2R1_LAUNCHXL_UARTCOUNT } CC26X2R1_LAUNCHXL_UARTName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/leds-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/leds-arch.c index 97c912a84..85065e104 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/leds-arch.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/leds-arch.c @@ -27,26 +27,28 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup simplelink-platform + * \addtogroup launchpad-peripherals * @{ * * \file - * Driver for LaunchPad LEDs + * LED HAL definitions for the LaunchPad LEDs. Common across all + * CC13xx/CC26xx LaunchPad LEDs. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ -/* Contiki API */ #include "contiki.h" #include "dev/leds.h" /*---------------------------------------------------------------------------*/ #include /*---------------------------------------------------------------------------*/ -/* Standard library */ #include /*---------------------------------------------------------------------------*/ const leds_t leds_arch_leds[] = { + /* Red LED, AKA LED0 */ { .pin = Board_PIN_LED0, .negative_logic = false }, + /* Green LED, AKA LED1 */ { .pin = Board_PIN_LED1, .negative_logic = false }, }; /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/platform.c b/arch/platform/simplelink/cc13xx-cc26xx/platform.c index f5a23fee6..86342a287 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/platform.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/platform.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,25 +27,32 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup cc13xx-cc26xx-platforms + * \addtogroup cc13xx-cc26xx-platform * @{ * - * \defgroup LaunchPads - * - * This platform supports a number of different boards: - * - The TI CC1310 LaunchPad - * - The TI CC1350 LaunchPad - * - The TI CC2640 LaunchPad - * - The TI CC2650 LaunchPad - * - The TI CC1312R1 LaunchPad - * - The TI CC1352R1 LaunchPad - * - The TI CC1352P1 LaunchPad - * - The TI CC26X2R1 LaunchPad - * @{ + * \file + * Setup the SimpleLink CC13xx/CC26xx ecosystem with the + * Contiki environment. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ +/* Contiki API */ +#include "contiki.h" +#include "contiki-net.h" +#include "sys/clock.h" +#include "sys/rtimer.h" +#include "sys/node-id.h" +#include "sys/platform.h" +#include "dev/button-hal.h" +#include "dev/gpio-hal.h" +#include "dev/serial-line.h" +#include "dev/leds.h" +#include "net/mac/framer/frame802154.h" +#include "lib/random.h" +#include "lib/sensors.h" +/*---------------------------------------------------------------------------*/ /* Simplelink SDK includes */ #include #include @@ -64,20 +71,6 @@ #include #include /*---------------------------------------------------------------------------*/ -/* Contiki API */ -#include "contiki.h" -#include "contiki-net.h" -#include "sys/clock.h" -#include "sys/rtimer.h" -#include "sys/node-id.h" -#include "sys/platform.h" -#include "dev/button-hal.h" -#include "dev/gpio-hal.h" -#include "dev/serial-line.h" -#include "dev/leds.h" -#include "net/mac/framer/frame802154.h" -#include "lib/sensors.h" -/*---------------------------------------------------------------------------*/ /* Arch driver implementations */ #include "board-peripherals.h" #include "uart0-arch.h" @@ -85,7 +78,6 @@ #include "ieee-addr.h" #include "rf-core.h" #include "rf-ble-beacond.h" -#include "lib/random.h" #include "button-sensor.h" /*---------------------------------------------------------------------------*/ #include @@ -93,14 +85,12 @@ /*---------------------------------------------------------------------------*/ /* Log configuration */ #include "sys/log.h" -#define LOG_MODULE "CC26xx/CC13xx" +#define LOG_MODULE "CC13xx/CC26xx" #define LOG_LEVEL LOG_LEVEL_DBG /*---------------------------------------------------------------------------*/ -unsigned short g_nodeId = 0; -/*---------------------------------------------------------------------------*/ /* - * Board-specific initialization function. - * This function is defined in the file _fxns.c + * Board-specific initialization function. This function is defined in + * the _fxns.c file. */ extern void Board_initHook(void); /*---------------------------------------------------------------------------*/ @@ -110,37 +100,41 @@ extern void Board_initHook(void); #define BOARD_HAS_SENSORS 1 #endif /*---------------------------------------------------------------------------*/ +/* Fade a specified LED */ static void fade(unsigned char l) { volatile int i; - for(int k = 0; k < 800; ++k) { - int j = k > 400 ? 800 - k : k; + int k; + int j; + for(k = 0; k < 800; ++k) { + j = (k > 400) ? 800 - k : k; - leds_on(l); + leds_single_on(l); for(i = 0; i < j; ++i) { __asm("nop"); } - leds_off(l); + leds_single_off(l); for(i = 0; i < 400 - j; ++i) { __asm("nop"); } } } /*---------------------------------------------------------------------------*/ +/* Configure RF params for the radio driver */ static void set_rf_params(void) { uint8_t ext_addr[8]; + uint16_t short_addr; + memset(ext_addr, 0x0, sizeof(ext_addr)); ieee_addr_cpy_to(ext_addr, sizeof(ext_addr)); - uint16_t short_addr = (ext_addr[7] << 0) - | (ext_addr[6] << 8); + /* Short address is the last two bytes of the MAC address */ + short_addr = ((uint16_t)ext_addr[7] << 0) + | ((uint16_t)ext_addr[6] << 8); NETSTACK_RADIO.set_value(RADIO_PARAM_PAN_ID, IEEE802154_PANID); NETSTACK_RADIO.set_value(RADIO_PARAM_16BIT_ADDR, short_addr); NETSTACK_RADIO.set_object(RADIO_PARAM_64BIT_ADDR, ext_addr, sizeof(ext_addr)); - - /* also set the global node id */ - g_nodeId = short_addr; } /*---------------------------------------------------------------------------*/ void @@ -155,8 +149,12 @@ platform_init_stage_one(void) Power_init(); + /* BoardGpioInitTable declared in Board.h */ if (PIN_init(BoardGpioInitTable) != PIN_SUCCESS) { - /* Error with PIN_init */ + /* + * Something is seriously wrong if PIN initialization of the Board GPIO + * table fails. + */ while (1); } @@ -172,7 +170,6 @@ platform_init_stage_one(void) /* TI Drivers init */ #if TI_UART_CONF_ENABLE UART_init(); - uart0_init(); #endif #if TI_I2C_CONF_ENABLE I2C_init(); @@ -186,7 +183,7 @@ platform_init_stage_one(void) fade(LEDS_GREEN); - /* NoRTOS should be called last */ + /* NoRTOS must be called last */ NoRTOS_start(); } /*---------------------------------------------------------------------------*/ @@ -195,6 +192,10 @@ platform_init_stage_two(void) { serial_line_init(); +#if TI_UART_CONF_UART0_ENABLE + uart0_init(); +#endif + #if BUILD_WITH_SHELL uart0_set_callback(serial_line_input_byte); #endif @@ -216,7 +217,8 @@ platform_init_stage_three(void) rf_ble_beacond_init(); #endif - radio_value_t chan = 0, pan = 0; + radio_value_t chan = 0; + radio_value_t pan = 0; set_rf_params(); @@ -225,10 +227,10 @@ platform_init_stage_three(void) LOG_DBG("With DriverLib v%u.%u\n", DRIVERLIB_RELEASE_GROUP, DRIVERLIB_RELEASE_BUILD); - LOG_DBG("IEEE 802.15.4: %s, Sub-GHz: %s, BLE: %s\n", + LOG_DBG("IEEE 802.15.4: %s, Sub-1 GHz: %s, BLE: %s\n", ChipInfo_SupportsIEEE_802_15_4() ? "Yes" : "No", - ChipInfo_SupportsPROPRIETARY() ? "Yes" : "No", - ChipInfo_SupportsBLE() ? "Yes" : "No"); + ChipInfo_SupportsPROPRIETARY() ? "Yes" : "No", + ChipInfo_SupportsBLE() ? "Yes" : "No"); #if (RF_MODE == RF_MODE_SUB_1_GHZ) LOG_INFO("Operating frequency on Sub-1 GHz\n"); @@ -236,7 +238,7 @@ platform_init_stage_three(void) LOG_INFO("Operating frequency on 2.4 GHz\n"); #endif LOG_INFO("RF: Channel %d, PANID 0x%04X\n", chan, pan); - LOG_INFO("Node ID: %d\n", g_nodeId); + LOG_INFO("Node ID: %d\n", node_id); #if BOARD_HAS_SENSORS process_start(&sensors_process, NULL); @@ -253,6 +255,5 @@ platform_idle(void) } /*---------------------------------------------------------------------------*/ /** - * @} * @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/Makefile.sensortag b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/Makefile.sensortag index 31da88d0a..fe6156ea7 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/Makefile.sensortag +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/Makefile.sensortag @@ -7,7 +7,7 @@ PLATFORM_HAS_BUTTON = 1 # leds-arch.c/h etc. BOARD_SOURCEFILES += sensortag-sensors.c -BOARD_SOURCEFILES += button-sensor-arch.c ext-flash.c +BOARD_SOURCEFILES += button-sensor-arch.c BOARD_SOURCEFILES += bmp-280-sensor.c hdc-1000-sensor.c BOARD_SOURCEFILES += mpu-9250-sensor.c opt-3001-sensor.c BOARD_SOURCEFILES += tmp-007-sensor.c buzzer.c diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c index c13c520eb..372cfc81c 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,13 +27,14 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup sensortag-cc26xx-bmp-sensor + * \addtogroup sensortag-bmp-sensor * @{ * * \file - * Driver for the Sensortag BMP280 Altimeter / Pressure Sensor + * Driver for the Sensortag BMP280 Altimeter / Pressure Sensor + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #include "contiki.h" @@ -41,6 +42,7 @@ #include "sys/ctimer.h" /*---------------------------------------------------------------------------*/ #include + #include /*---------------------------------------------------------------------------*/ #include "bmp-280-sensor.h" @@ -57,7 +59,7 @@ #endif /*---------------------------------------------------------------------------*/ #ifndef Board_BMP280_ADDR -# error "Board file doesn't define I2C address Board_BMP280_ADDR" +# error "Board file doesn't define I2C address Board_BMP280_ADDR" #endif /* Sensor I2C address */ #define BMP280_I2C_ADDRESS Board_BMP280_ADDR @@ -127,7 +129,7 @@ typedef struct { /*---------------------------------------------------------------------------*/ static BMP_280_Calibration calib_data; /*---------------------------------------------------------------------------*/ -static I2C_Handle i2cHandle; +static I2C_Handle i2c_handle; /*---------------------------------------------------------------------------*/ typedef enum { SENSOR_STATUS_DISABLED, @@ -163,48 +165,53 @@ i2c_write_read(void *writeBuf, size_t writeCount, void *readBuf, size_t readCoun .slaveAddress = BMP280_I2C_ADDRESS, }; - return I2C_transfer(i2cHandle, &i2cTransaction); + return I2C_transfer(i2c_handle, &i2cTransaction); } #define i2c_write(writeBuf, writeCount) i2c_write_read(writeBuf, writeCount, NULL, 0) #define i2c_read(readBuf, readCount) i2c_write_read(NULL, 0, readBuf, readCount) /*---------------------------------------------------------------------------*/ /** - * \brief Initalise the sensor - * - * @return true if success; else, false on error + * \brief Initalise the sensor. + * \return Boolean Value descibing whether initialization were + * successful or not. + * \retval true Successful initialization + * \retval false Error during initialization */ static bool init(void) { - if (i2cHandle) { + if (i2c_handle) { return true; } I2C_Params i2cParams; I2C_Params_init(&i2cParams); + i2cParams.transferMode = I2C_MODE_BLOCKING; i2cParams.bitRate = I2C_400kHz; - i2cHandle = I2C_open(Board_I2C0, &i2cParams); - if (i2cHandle == NULL) { + i2c_handle = I2C_open(Board_I2C0, &i2cParams); + if (i2c_handle == NULL) { return false; } uint8_t reset_data[] = { ADDR_RESET, VAL_RESET_EXECUTE }; - /* Read and store calibration data */ uint8_t calib_reg = ADDR_CALIB; + /* Read and store calibration data */ return i2c_write_read(&calib_reg, sizeof(calib_reg), &calib_data, sizeof(calib_data)) /* then reset the sensor */ && i2c_write(reset_data, sizeof(reset_data)); } /*---------------------------------------------------------------------------*/ /** - * \brief Enable/disable measurements - * \param enable 0: disable, enable otherwise - * - * @return none + * \brief Enable/disable measurements. + * \param enable Enable if true; else, disable. + * \return Boolean Value descibing whether initialization were + * successful or not. + * \retval true Successful initialization + * \retval false Error during initialization */ static bool enable_sensor(bool enable) @@ -218,10 +225,13 @@ enable_sensor(bool enable) } /*---------------------------------------------------------------------------*/ /** - * \brief Read temperature and pressure data - * \param data Pointer to a buffer where temperature and pressure will be - * written (6 bytes) - * \return True if valid data could be retrieved + * \brief Read temperature and pressure data. + * \param data Pointer to a buffer where temperature and pressure will be + * written (6 bytes). + * \return Boolean Value descibing whether initialization were + * successful or not. + * \retval true Successful initialization + * \retval false Error during initialization */ static bool read_data(uint8_t *data, size_t count) @@ -231,12 +241,13 @@ read_data(uint8_t *data, size_t count) } /*---------------------------------------------------------------------------*/ /** - * \brief Convert raw data to values in degrees C (temp) and Pascal (pressure) - * \param data Pointer to a buffer that holds raw sensor data - * \param temp Pointer to a variable where the converted temperature will be - * written + * \brief Convert raw data to values in degrees C (temp) and Pascal + * (pressure). + * \param data Pointer to a buffer that holds raw sensor data. + * \param temp Pointer to a variable where the converted temperature will + * be written. * \param press Pointer to a variable where the converted pressure will be - * written + * written. */ static void convert(uint8_t *data, int32_t *temp, uint32_t *press) @@ -337,9 +348,11 @@ convert(uint8_t *data, int32_t *temp, uint32_t *press) } /*---------------------------------------------------------------------------*/ /** - * \brief Returns a reading from the sensor - * \param type BMP_280_SENSOR_TYPE_TEMP or BMP_280_SENSOR_TYPE_PRESS - * \return Temperature (centi degrees C) or Pressure (Pascal). + * \brief Returns a reading from the sensor. + * \param type Parameter of type BMP_280_SENSOR_TYPE, choosing between either + * measuring temperature or pressure. + * \return Sensor data of either Temperature (centi degrees C) or + * Pressure (Pascal). */ static int value(int type) @@ -384,14 +397,12 @@ value(int type) } /*---------------------------------------------------------------------------*/ /** - * \brief Configuration function for the BMP280 sensor. - * - * \param type Activate, enable or disable the sensor. See below - * \param enable - * - * When type == SENSORS_HW_INIT we turn on the hardware - * When type == SENSORS_ACTIVE and enable==1 we enable the sensor - * When type == SENSORS_ACTIVE and enable==0 we disable the sensor + * \brief Configuration function for the BMP280 sensor. + * \param type Activate, enable or disable the sensor. See below + * \param enable Disable sensor if 0; else, enable sensor otherwise. + * When type == SENSORS_HW_INIT we turn on the hardware. + * When type == SENSORS_ACTIVE and enable==1 we enable the sensor. + * When type == SENSORS_ACTIVE and enable==0 we disable the sensor. */ static int configure(int type, int enable) @@ -429,9 +440,9 @@ configure(int type, int enable) } /*---------------------------------------------------------------------------*/ /** - * \brief Returns the status of the sensor - * \param type SENSORS_ACTIVE or SENSORS_READY - * \return 1 if the sensor is enabled + * \brief Returns the status of the sensor. + * \param type SENSORS_ACTIVE or SENSORS_READY. + * \return Current status of the sensor. */ static int status(int type) @@ -441,9 +452,8 @@ status(int type) case SENSORS_READY: return sensor_status; default: - break; + return SENSOR_STATUS_DISABLED; } - return SENSOR_STATUS_DISABLED; } /*---------------------------------------------------------------------------*/ SENSORS_SENSOR(bmp_280_sensor, "BMP280", value, configure, status); diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.h index 2c2735ed9..3f7f846b7 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,12 +27,11 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup sensortag-cc26xx-peripherals + * \addtogroup sensortag-peripherals * @{ * - * \defgroup sensortag-cc26xx-bmp-sensor SensorTag 2.0 Pressure Sensor + * \defgroup sensortag-bmp-sensor SensorTag Pressure Sensor * * Due to the time required for the sensor to startup, this driver is meant to * be used in an asynchronous fashion. The caller must first activate the @@ -49,14 +48,22 @@ * @{ * * \file - * Header file for the Sensortag BMP280 Altimeter / Pressure Sensor + * Header file for the Sensortag BMP280 Altimeter / Pressure Sensor + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #ifndef BMP_280_SENSOR_H_ #define BMP_280_SENSOR_H_ /*---------------------------------------------------------------------------*/ +#include "contiki.h" #include "lib/sensors.h" /*---------------------------------------------------------------------------*/ +/* The BMP-280 driver uses the I2C0 peripheral to access the senssor */ +#if (TI_I2C_CONF_ENABLE == 0) || (TI_I2C_CONF_I2C0_ENABLE == 0) +# error "The BMP280 requires the I2C driver (TI_I2C_CONF_ENABLE = 1)" +#endif +/*---------------------------------------------------------------------------*/ typedef enum { BMP_280_SENSOR_TYPE_TEMP, BMP_280_SENSOR_TYPE_PRESS diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h index 1bd6b92c6..4a1822e82 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,32 +27,48 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ -/** \addtogroup cc26xx-srf-tag +/** + * \addtogroup cc13xx-cc26xx-platform * @{ * - * \defgroup sensortag-cc26xx-peripherals Sensortag CC1350/CC2650 common + * \defgroup sensortag-peripherals Sensortag peripherals * - * Defines related to Sensortag sensors. The two sensortags are identical to a - * very large extent. Everything documented within this group applies to both - * sensortags. + * Defines related to configuring SensorTag peripherals. The two sensortags, + * CC1350STK and CC2650STK, are identical to a very large extent. + * Everything documented within this group applies to both sensortags. * * @{ * * \file - * Header file with definitions related to the sensors on the Sensortags - * - * \note Do not include this file directly. + * Header file with definitions related to the sensors on the Sensortags + * \author + * Edvard Pettersen + * \note + * This file should not be included directly */ /*---------------------------------------------------------------------------*/ #ifndef BOARD_CONF_H_ #define BOARD_CONF_H_ /*---------------------------------------------------------------------------*/ -#include "leds-arch.h" -/*---------------------------------------------------------------------------*/ +/** + * \name Button configurations for the dev/button-hal.h API. + * + * Those values are not meant to be modified by the user + * @{ + */ #define BUTTON_HAL_ID_KEY_LEFT 0 #define BUTTON_HAL_ID_KEY_RIGHT 1 #define BUTTON_HAL_ID_REED_RELAY 2 +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \name SensorTag does have sensors. + * + * Those values are not meant to be modified by the user + * @{ + */ +#define BOARD_CONF_HAS_SENSORS 1 +/** @} */ /*---------------------------------------------------------------------------*/ #endif /* BOARD_CONF_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-peripherals.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-peripherals.h index 403428872..7a4f8c19b 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-peripherals.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-peripherals.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,38 +27,35 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ -/** \addtogroup cc26xx-srf-tag +/** + * \addtogroup cc13xx-cc26xx-platform * @{ * - * \defgroup sensortag-cc26xx-peripherals Sensortag CC1350/CC2650 common + * \defgroup sensortag-peripherals Sensortag peripherals * - * Defines related to Sensortag sensors. The two sensortags are identical to a - * very large extent. Everything documented within this group applies to both - * sensortags. + * Defines related to configuring SensorTag peripherals. The two sensortags, + * CC1350STK and CC2650STK, are identical to a very large extent. + * Everything documented within this group applies to both sensortags. * * @{ * * \file - * Header file with definitions related to the sensors on the Sensortags - * - * \note Do not include this file directly. + * Header file with definitions related to the sensors on the Sensortags + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #ifndef BOARD_PERIPHERALS_H_ #define BOARD_PERIPHERALS_H_ /*---------------------------------------------------------------------------*/ +#include "board-conf.h" +/*---------------------------------------------------------------------------*/ #include "bmp-280-sensor.h" #include "tmp-007-sensor.h" #include "opt-3001-sensor.h" #include "hdc-1000-sensor.h" #include "mpu-9250-sensor.h" #include "buzzer.h" -#include "ext-flash.h" -/*---------------------------------------------------------------------------*/ -#include "board-conf.h" -/*---------------------------------------------------------------------------*/ -#define BOARD_CONF_HAS_SENSORS 1 /*---------------------------------------------------------------------------*/ #endif /* BOARD_PERIPHERALS_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor-arch.c index 5c4cc20f4..63c177656 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor-arch.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/button-sensor-arch.c @@ -27,45 +27,51 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup launchpad-button-sensor + * \addtogroup sensortag-peripherals * @{ * * \file - * Driver for LaunchPad buttons + * Button HAL definitions for the SensorTag buttons. Common across + * all CC13xx/CC26xx SensorTag boards. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "dev/button-hal.h" - +/*---------------------------------------------------------------------------*/ #include /*---------------------------------------------------------------------------*/ /* Key left button, AKA BTN-1 */ -BUTTON_HAL_BUTTON(key_left, /**< Name */ - "Key Left", /**< Description */ - Board_KEY_LEFT, /**< PIN */ - GPIO_HAL_PIN_CFG_INPUT_PULLUP | - GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ - BUTTON_HAL_ID_KEY_LEFT, /**< Unique ID */ - true); /**< Negative logic */ +BUTTON_HAL_BUTTON( + key_left, /**< Name */ + "Key Left", /**< Description */ + Board_KEY_LEFT, /**< PIN */ + GPIO_HAL_PIN_CFG_INPUT_PULLUP | + GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_KEY_LEFT, /**< Unique ID */ + true); /**< Negative logic */ /* Key right button, AKA BTN-2 */ -BUTTON_HAL_BUTTON(key_right, /**< Name */ - "Key Right", /**< Description */ - Board_KEY_RIGHT, /**< PIN */ - GPIO_HAL_PIN_CFG_INPUT_PULLUP | - GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ - BUTTON_HAL_ID_KEY_RIGHT, /**< Unique ID */ - true); /**< Negative logic */ +BUTTON_HAL_BUTTON( + key_right, /**< Name */ + "Key Right", /**< Description */ + Board_KEY_RIGHT, /**< PIN */ + GPIO_HAL_PIN_CFG_INPUT_PULLUP | + GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_KEY_RIGHT, /**< Unique ID */ + true); /**< Negative logic */ -BUTTON_HAL_BUTTON(reed_relay, /**< Name */ - "Reed Relay", /**< Description */ - Board_RELAY, /**< PIN */ - GPIO_HAL_PIN_CFG_INPUT_PULLDOWN | - GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ - BUTTON_HAL_ID_REED_RELAY, /**< Unique ID */ - true); /**< Negative logic */ +/* Reed Relay button */ +BUTTON_HAL_BUTTON( + reed_relay, /**< Name */ + "Reed Relay", /**< Description */ + Board_RELAY, /**< PIN */ + GPIO_HAL_PIN_CFG_INPUT_PULLDOWN | + GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_REED_RELAY, /**< Unique ID */ + true); /**< Negative logic */ /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTONS(&key_left, &key_right, &reed_relay); /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.c index c79b7f401..2c2459225 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.c @@ -29,11 +29,13 @@ */ /*---------------------------------------------------------------------------*/ /** - * \addtogroup sensortag-cc26xx-buzzer + * \addtogroup sensortag-buzzer * @{ * * \file - * Driver for the Sensortag Buzzer + * Driver for the Sensortag Buzzer. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #include "contiki.h" @@ -78,13 +80,13 @@ buzzer_init() GPTimerCC26XX_Params gpt_params; GPTimerCC26XX_Params_init(&gpt_params); + gpt_params.mode = GPT_CONFIG_16BIT; gpt_params.mode = GPT_MODE_PERIODIC_UP; gpt_params.debugStallMode = GPTimerCC26XX_DEBUG_STALL_OFF; gpt_handle = GPTimerCC26XX_open(Board_GPTIMER0A, &gpt_params); if (!gpt_handle) { - PIN_close(pin_handle); return false; } @@ -120,7 +122,7 @@ buzzer_start(uint32_t freq) return false; } - Power_setDependency(PowerCC26XX_XOSC_HF ); + Power_setDependency(PowerCC26XX_XOSC_HF); PINCC26XX_setMux(pin_handle, BUZZER_PIN, GPT_PIN_0A); @@ -145,10 +147,12 @@ buzzer_stop() return; } - Power_releaseDependency(PowerCC26XX_XOSC_HF ); + Power_releaseDependency(PowerCC26XX_XOSC_HF); GPTimerCC26XX_stop(gpt_handle); + PIN_close(pin_handle); + pin_handle = NULL; is_running = false; } diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.h index 31a92ad17..3895be4b7 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.h @@ -27,16 +27,17 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup sensortag-cc26xx-peripherals + * \addtogroup sensortag-peripherals * @{ * - * \defgroup sensortag-cc26xx-buzzer SensorTag 2.0 Buzzer + * \defgroup sensortag-buzzer SensorTag Buzzer * @{ * * \file - * Header file for the Sensortag Buzzer + * Header file for the Sensortag Buzzer. + * \author + * Edvard Pettersen . */ /*---------------------------------------------------------------------------*/ #ifndef BUZZER_H_ @@ -46,24 +47,26 @@ #include /*---------------------------------------------------------------------------*/ /** - * \brief Initialise the buzzer + * \brief Initialise the buzzer */ bool buzzer_init(void); /** - * \brief Start the buzzer - * \param freq The buzzer frequency + * \brief Start the buzzer. + * \param freq The buzzer frequency in Hz. */ bool buzzer_start(uint32_t freq); /** - * \brief Stop the buzzer + * \brief Stop the buzzer. */ void buzzer_stop(void); /** - * \brief Retrieve the buzzer state - * \return 1: on, 0: off + * \brief Retrieve the buzzer state. + * \return Running status of the buzzer. + * \retval 0 Buzzer is off + * \retval 1 Buzzer is on */ bool buzzer_running(void); /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.c index 916dfda20..f1d8bf53d 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.c @@ -80,19 +80,21 @@ const CryptoCC26XX_Config CryptoCC26XX_config[CC1350STK_CRYPTOCOUNT] = { #include #include -#ifndef CC1350STK_DISPLAY_UART_STRBUF_SIZE -#define CC1350STK_DISPLAY_UART_STRBUF_SIZE 128 +#if TI_DISPLAY_CONF_ENABLE + +#if TI_DISPLAY_CONF_UART_ENABLE + +#if !(TI_UART_CONF_UART0_ENABLE) +#error "Display UART driver requires UART0" #endif -#ifndef CC1350STK_DISPLAY_SHARP_SIZE -#define CC1350STK_DISPLAY_SHARP_SIZE 96 +#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE +#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 #endif -DisplayUart_Object displayUartObject; -DisplaySharp_Object displaySharpObject; - static char uartStringBuf[CC1350STK_DISPLAY_UART_STRBUF_SIZE]; -static uint_least8_t sharpDisplayBuf[CC1350STK_DISPLAY_SHARP_SIZE * CC1350STK_DISPLAY_SHARP_SIZE / 8]; + +DisplayUart_Object displayUartObject; const DisplayUart_HWAttrs displayUartHWAttrs = { .uartIdx = CC1350STK_UART0, @@ -102,6 +104,22 @@ const DisplayUart_HWAttrs displayUartHWAttrs = { .strBufLen = CC1350STK_DISPLAY_UART_STRBUF_SIZE, }; +#endif /* TI_DISPLAY_CONF_UART_ENABLE */ + +#if TI_DISPLAY_CONF_LCD_ENABLE + +#if !(TI_SPI_CONF_SPI0_ENABLE) +#error "Display LCD driver requires SPI0" +#endif + +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 +#endif + +static uint_least8_t sharpDisplayBuf[CC1350STK_DISPLAY_SHARP_SIZE * CC1350STK_DISPLAY_SHARP_SIZE / 8]; + +DisplaySharp_Object displaySharpObject; + const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .spiIndex = CC1350STK_SPI0, .csPin = CC1350STK_GPIO_LCD_CS, @@ -112,30 +130,18 @@ const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .displayBuf = sharpDisplayBuf, }; -/* - * The pins for the UART and Watch Devpack conflict, prefer UART by default - */ -#ifndef BOARD_DISPLAY_USE_UART -#define BOARD_DISPLAY_USE_UART 1 -#endif -#ifndef BOARD_DISPLAY_USE_UART_ANSI -#define BOARD_DISPLAY_USE_UART_ANSI 0 -#endif -#ifndef BOARD_DISPLAY_USE_LCD -#define BOARD_DISPLAY_USE_LCD 0 -#endif +#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ /* * This #if/#else is needed to workaround a problem with the * IAR compiler. The IAR compiler doesn't like the empty array * initialization. (IAR Error[Pe1345]) */ -#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) const Display_Config Display_config[] = { -#if (BOARD_DISPLAY_USE_UART) +#if TI_DISPLAY_CONF_UART_ENABLE { -# if (BOARD_DISPLAY_USE_UART_ANSI) +# if TI_DISPLAY_CONF_USE_UART_ANSI .fxnTablePtr = &DisplayUartAnsi_fxnTable, # else /* Default to minimal UART with no cursor placement */ .fxnTablePtr = &DisplayUartMin_fxnTable, @@ -145,7 +151,7 @@ const Display_Config Display_config[] = { .hwAttrs = &displayUartHWAttrs, }, #endif -#if (BOARD_DISPLAY_USE_LCD) +#if TI_DISPLAY_CONF_LCD_ENABLE { .fxnTablePtr = &DisplaySharp_fxnTable, .object = &displaySharpObject, @@ -161,7 +167,7 @@ const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Conf const Display_Config *Display_config = NULL; const uint_least8_t Display_count = 0; -#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ +#endif /* TI_DISPLAY_CONF_ENABLE */ /* * =============================== GPIO =============================== @@ -249,9 +255,12 @@ const GPTimerCC26XX_Config GPTimerCC26XX_config[CC1350STK_GPTIMERPARTSCOUNT] = { #include #include +#if TI_I2C_CONF_ENABLE + I2CCC26XX_Object i2cCC26xxObjects[CC1350STK_I2CCOUNT]; const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1350STK_I2CCOUNT] = { +#if TI_I2C_CONF_I2C0_ENABLE { .baseAddr = I2C0_BASE, .powerMngrId = PowerCC26XX_PERIPH_I2C0, @@ -260,19 +269,24 @@ const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1350STK_I2CCOUNT] = { .swiPriority = 0, .sdaPin = CC1350STK_I2C0_SDA0, .sclPin = CC1350STK_I2C0_SCL0, - } + }, +#endif }; const I2C_Config I2C_config[CC1350STK_I2CCOUNT] = { +#if TI_I2C_CONF_I2C0_ENABLE { .fxnTablePtr = &I2CCC26XX_fxnTable, .object = &i2cCC26xxObjects[CC1350STK_I2C0], .hwAttrs = &i2cCC26xxHWAttrs[CC1350STK_I2C0] }, +#endif }; const uint_least8_t I2C_count = CC1350STK_I2CCOUNT; +#endif /* TI_I2C_CONF_ENABLE */ + /* * =============================== NVS =============================== */ @@ -283,10 +297,10 @@ const uint_least8_t I2C_count = CC1350STK_I2CCOUNT; #define NVS_REGIONS_BASE 0x1A000 #define SECTORSIZE 0x1000 #define REGIONSIZE (SECTORSIZE * 4) -#define SPIREGIONSIZE (SECTORSIZE * 32) -#define VERIFYBUFSIZE 64 -static uint8_t verifyBuf[VERIFYBUFSIZE]; +#if TI_NVS_CONF_ENABLE + +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE /* * Reserve flash sectors for NVS driver use by placing an uninitialized byte @@ -327,7 +341,6 @@ static char flashBuf[REGIONSIZE]; /* Allocate objects for NVS and NVS SPI */ NVSCC26XX_Object nvsCC26xxObjects[1]; -NVSSPI25X_Object nvsSPI25XObjects[1]; /* Hardware attributes for NVS */ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { @@ -337,12 +350,24 @@ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { }, }; +#endif /* TI_NVS_CONF_NVS_INTERNAL_ENABLE */ + +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE + +#define SPISECTORSIZE 0x1000 +#define SPIREGIONSIZE (SECTORSIZE * 32) +#define VERIFYBUFSIZE 64 + +static uint8_t verifyBuf[VERIFYBUFSIZE]; + +NVSSPI25X_Object nvsSPI25XObjects[1]; + /* Hardware attributes for NVS SPI */ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { { .regionBaseOffset = 0, .regionSize = SPIREGIONSIZE, - .sectorSize = SECTORSIZE, + .sectorSize = SPISECTORSIZE, .verifyBuf = verifyBuf, .verifyBufSize = VERIFYBUFSIZE, .spiHandle = NULL, @@ -352,22 +377,30 @@ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { }, }; +#endif /* Board_EXCLUDE_NVS_EXTERNAL_FLASH */ + /* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ const NVS_Config NVS_config[CC1350STK_NVSCOUNT] = { +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE { .fxnTablePtr = &NVSCC26XX_fxnTable, .object = &nvsCC26xxObjects[0], .hwAttrs = &nvsCC26xxHWAttrs[0], }, +#endif +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE { .fxnTablePtr = &NVSSPI25X_fxnTable, .object = &nvsSPI25XObjects[0], .hwAttrs = &nvsSPI25XHWAttrs[0], }, +#endif }; const uint_least8_t NVS_count = CC1350STK_NVSCOUNT; +#endif /* TI_NVS_CONF_ENABLE */ + /* * =============================== PDM =============================== */ @@ -516,9 +549,12 @@ const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { #include #include +#if TI_SPI_CONF_ENABLE + SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1350STK_SPICOUNT]; const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1350STK_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .baseAddr = SSI0_BASE, .intNum = INT_SSI0_COMB, @@ -534,6 +570,8 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1350STK_SPICOUNT] = { .csnPin = CC1350STK_SPI0_CSN, .minDmaTransferSize = 10 }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .baseAddr = SSI1_BASE, .intNum = INT_SSI1_COMB, @@ -548,35 +586,45 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1350STK_SPICOUNT] = { .clkPin = CC1350STK_SPI1_CLK, .csnPin = CC1350STK_SPI1_CSN, .minDmaTransferSize = 10 - } + }, +#endif }; const SPI_Config SPI_config[CC1350STK_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC1350STK_SPI0], .hwAttrs = &spiCC26XXDMAHWAttrs[CC1350STK_SPI0] }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC1350STK_SPI1], .hwAttrs = &spiCC26XXDMAHWAttrs[CC1350STK_SPI1] }, +#endif }; const uint_least8_t SPI_count = CC1350STK_SPICOUNT; +#endif /* TI_SPI_CONF_ENABLE */ + /* * =============================== UART =============================== */ #include #include +#if TI_UART_CONF_ENABLE + UARTCC26XX_Object uartCC26XXObjects[CC1350STK_UARTCOUNT]; uint8_t uartCC26XXRingBuffer[CC1350STK_UARTCOUNT][32]; const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1350STK_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .baseAddr = UART0_BASE, .powerMngrId = PowerCC26XX_PERIPH_UART0, @@ -592,19 +640,24 @@ const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1350STK_UARTCOUNT] = { .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, .errorFxn = NULL - } + }, +#endif }; const UART_Config UART_config[CC1350STK_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .fxnTablePtr = &UARTCC26XX_fxnTable, .object = &uartCC26XXObjects[CC1350STK_UART0], .hwAttrs = &uartCC26XXHWAttrs[CC1350STK_UART0] }, +#endif }; const uint_least8_t UART_count = CC1350STK_UARTCOUNT; +#endif /* TI_UART_CONF_ENABLE */ + /* * =============================== UDMA =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.h index 4d3b707af..ea857a185 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.h @@ -48,6 +48,8 @@ extern "C" { #endif +#include "contiki-conf.h" + /* Includes */ #include #include @@ -233,7 +235,9 @@ typedef enum CC1350STK_GPTimers { * @brief Enum of I2C names */ typedef enum CC1350STK_I2CName { +#if TI_I2C_CONF_I2C0_ENABLE CC1350STK_I2C0 = 0, +#endif CC1350STK_I2CCOUNT } CC1350STK_I2CName; @@ -243,8 +247,12 @@ typedef enum CC1350STK_I2CName { * @brief Enum of NVS names */ typedef enum CC1350STK_NVSName { +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE CC1350STK_NVSCC26XX0 = 0, +#endif +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE CC1350STK_NVSSPI25X0, +#endif CC1350STK_NVSCOUNT } CC1350STK_NVSName; @@ -281,8 +289,12 @@ typedef enum CC1350STK_PWMName { * @brief Enum of SPI names */ typedef enum CC1350STK_SPIName { +#if TI_SPI_CONF_SPI0_ENABLE CC1350STK_SPI0 = 0, +#endif +#if TI_SPI_CONF_SPI1_ENABLE CC1350STK_SPI1, +#endif CC1350STK_SPICOUNT } CC1350STK_SPIName; @@ -292,7 +304,9 @@ typedef enum CC1350STK_SPIName { * @brief Enum of UARTs */ typedef enum CC1350STK_UARTName { +#if TI_UART_CONF_UART0_ENABLE CC1350STK_UART0 = 0, +#endif CC1350STK_UARTCOUNT } CC1350STK_UARTName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/leds-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/leds-arch.c index e391b0179..020d538bf 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/leds-arch.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/leds-arch.c @@ -27,25 +27,26 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup simplelink-platform + * \addtogroup sensortag-peripherals * @{ * * \file - * Driver for LaunchPad LEDs + * LED HAL definitions for the CC1350STK LEDs. Is not compatible with + * the CC2650STK. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ -/* Contiki API */ #include "contiki.h" #include "dev/leds.h" /*---------------------------------------------------------------------------*/ -/* Simplelink SDK API */ #include /*---------------------------------------------------------------------------*/ #include /*---------------------------------------------------------------------------*/ const leds_t leds_arch_leds[] = { + /* Red LED, AKA LED0 */ { .pin = Board_PIN_LED0, .negative_logic = false }, }; /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/leds-arch.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/leds-arch.h index 14b15d048..535396f43 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/leds-arch.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/leds-arch.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,27 +27,21 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ -/** \addtogroup cc26xx-srf-tag - * @{ - * - * \defgroup launchpad-peripherals LaunchPad peripherals - * - * Defines related to LaunchPad peripherals. - * +/** \addtogroup sensortag-peripherals * @{ * * \file - * Header file with definitions related to LaunchPad peripherals - * - * \note Do not include this file directly. + * LED HAL definitions for the CC1350STK LEDs. Is not compatible with + * the CC2650STK. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #ifndef LEDS_ARCH_H_ #define LEDS_ARCH_H_ /*---------------------------------------------------------------------------*/ /** - * \name LED configurations + * \name LED configurations for the dev/leds.h API. * * Those values are not meant to be modified by the user * @{ @@ -57,10 +51,10 @@ #define LEDS_CONF_RED 0 #define LEDS_CONF_ALL ((1 << LEDS_CONF_COUNT) - 1) +/** @} */ /*---------------------------------------------------------------------------*/ #endif /* LEDS_ARCH_H_ */ /*---------------------------------------------------------------------------*/ /** - * @} * @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.c index 79df88f05..d070170c9 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.c @@ -81,19 +81,21 @@ const CryptoCC26XX_Config CryptoCC26XX_config[CC2650STK_CRYPTOCOUNT] = { #include #include -#ifndef CC2650STK_DISPLAY_UART_STRBUF_SIZE -#define CC2650STK_DISPLAY_UART_STRBUF_SIZE 128 +#if TI_DISPLAY_CONF_ENABLE + +#if TI_DISPLAY_CONF_UART_ENABLE + +#if !(TI_UART_CONF_UART0_ENABLE) +#error "Display UART driver requires UART0" #endif -#ifndef CC2650STK_DISPLAY_SHARP_SIZE -#define CC2650STK_DISPLAY_SHARP_SIZE 96 +#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE +#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 #endif -DisplayUart_Object displayUartObject; -DisplaySharp_Object displaySharpObject; - static char uartStringBuf[CC2650STK_DISPLAY_UART_STRBUF_SIZE]; -static uint_least8_t sharpDisplayBuf[CC2650STK_DISPLAY_SHARP_SIZE * CC2650STK_DISPLAY_SHARP_SIZE / 8]; + +DisplaySharp_Object displaySharpObject; const DisplayUart_HWAttrs displayUartHWAttrs = { .uartIdx = CC2650STK_UART0, @@ -103,6 +105,22 @@ const DisplayUart_HWAttrs displayUartHWAttrs = { .strBufLen = CC2650STK_DISPLAY_UART_STRBUF_SIZE, }; +#endif /* TI_DISPLAY_CONF_UART_ENABLE */ + +#if TI_DISPLAY_CONF_LCD_ENABLE + +#if !(TI_SPI_CONF_SPI0_ENABLE) +#error "Display LCD driver requires SPI0" +#endif + +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 +#endif + +static uint_least8_t sharpDisplayBuf[CC2650STK_DISPLAY_SHARP_SIZE * CC2650STK_DISPLAY_SHARP_SIZE / 8]; + +DisplayUart_Object displayUartObject; + const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .spiIndex = CC2650STK_SPI0, .csPin = CC2650STK_GPIO_LCD_CS, @@ -113,30 +131,18 @@ const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .displayBuf = sharpDisplayBuf, }; -/* - * The pins for the UART and Watch Devpack conflict, prefer UART by default - */ -#ifndef BOARD_DISPLAY_USE_UART -#define BOARD_DISPLAY_USE_UART 1 -#endif -#ifndef BOARD_DISPLAY_USE_UART_ANSI -#define BOARD_DISPLAY_USE_UART_ANSI 0 -#endif -#ifndef BOARD_DISPLAY_USE_LCD -#define BOARD_DISPLAY_USE_LCD 0 -#endif +#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ /* * This #if/#else is needed to workaround a problem with the * IAR compiler. The IAR compiler doesn't like the empty array * initialization. (IAR Error[Pe1345]) */ -#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) const Display_Config Display_config[] = { -#if (BOARD_DISPLAY_USE_UART) +#if TI_DISPLAY_CONF_UART_ENABLE { -# if (BOARD_DISPLAY_USE_UART_ANSI) +# if TI_DISPLAY_CONF_USE_UART_ANSI .fxnTablePtr = &DisplayUartAnsi_fxnTable, # else /* Default to minimal UART with no cursor placement */ .fxnTablePtr = &DisplayUartMin_fxnTable, @@ -146,7 +152,7 @@ const Display_Config Display_config[] = { .hwAttrs = &displayUartHWAttrs, }, #endif -#if (BOARD_DISPLAY_USE_LCD) +#if TI_DISPLAY_CONF_LCD_ENABLE { .fxnTablePtr = &DisplaySharp_fxnTable, .object = &displaySharpObject, @@ -162,7 +168,7 @@ const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Conf const Display_Config *Display_config = NULL; const uint_least8_t Display_count = 0; -#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ +#endif /* TI_DISPLAY_CONF_ENABLE */ /* * =============================== GPIO =============================== @@ -250,9 +256,12 @@ const GPTimerCC26XX_Config GPTimerCC26XX_config[CC2650STK_GPTIMERPARTSCOUNT] = { #include #include +#if TI_I2C_CONF_ENABLE + I2CCC26XX_Object i2cCC26xxObjects[CC2650STK_I2CCOUNT]; const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC2650STK_I2CCOUNT] = { +#if TI_I2C_CONF_I2C0_ENABLE { .baseAddr = I2C0_BASE, .powerMngrId = PowerCC26XX_PERIPH_I2C0, @@ -261,19 +270,24 @@ const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC2650STK_I2CCOUNT] = { .swiPriority = 0, .sdaPin = CC2650STK_I2C0_SDA0, .sclPin = CC2650STK_I2C0_SCL0, - } + }, +#endif }; const I2C_Config I2C_config[CC2650STK_I2CCOUNT] = { +#if TI_I2C_CONF_I2C0_ENABLE { .fxnTablePtr = &I2CCC26XX_fxnTable, .object = &i2cCC26xxObjects[CC2650STK_I2C0], .hwAttrs = &i2cCC26xxHWAttrs[CC2650STK_I2C0] }, +#endif }; const uint_least8_t I2C_count = CC2650STK_I2CCOUNT; +#endif /* TI_I2C_CONF_ENABLE */ + /* * =============================== NVS =============================== */ @@ -284,10 +298,10 @@ const uint_least8_t I2C_count = CC2650STK_I2CCOUNT; #define NVS_REGIONS_BASE 0x1A000 #define SECTORSIZE 0x1000 #define REGIONSIZE (SECTORSIZE * 4) -#define SPIREGIONSIZE (SECTORSIZE * 32) -#define VERIFYBUFSIZE 64 -static uint8_t verifyBuf[VERIFYBUFSIZE]; +#if TI_NVS_CONF_ENABLE + +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE /* * Reserve flash sectors for NVS driver use by placing an uninitialized byte @@ -326,9 +340,7 @@ static char flashBuf[REGIONSIZE]; #endif -/* Allocate objects for NVS and NVS SPI */ NVSCC26XX_Object nvsCC26xxObjects[1]; -NVSSPI25X_Object nvsSPI25XObjects[1]; /* Hardware attributes for NVS */ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { @@ -338,12 +350,25 @@ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { }, }; +#endif /* TI_NVS_CONF_NVS_INTERNAL_ENABLE */ + +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE + +#define SPISECTORSIZE 0x1000 +#define SPIREGIONSIZE (SPISECTORSIZE * 32) +#define VERIFYBUFSIZE 64 + +static uint8_t verifyBuf[VERIFYBUFSIZE]; + +/* Allocate objects for NVS and NVS SPI */ +NVSSPI25X_Object nvsSPI25XObjects[1]; + /* Hardware attributes for NVS SPI */ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { { .regionBaseOffset = 0, .regionSize = SPIREGIONSIZE, - .sectorSize = SECTORSIZE, + .sectorSize = SPISECTORSIZE, .verifyBuf = verifyBuf, .verifyBufSize = VERIFYBUFSIZE, .spiHandle = NULL, @@ -353,22 +378,30 @@ const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = { }, }; +#endif /* Board_EXCLUDE_NVS_EXTERNAL_FLASH */ + /* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ const NVS_Config NVS_config[CC2650STK_NVSCOUNT] = { +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE { .fxnTablePtr = &NVSCC26XX_fxnTable, .object = &nvsCC26xxObjects[0], .hwAttrs = &nvsCC26xxHWAttrs[0], }, +#endif +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE { .fxnTablePtr = &NVSSPI25X_fxnTable, .object = &nvsSPI25XObjects[0], .hwAttrs = &nvsSPI25XHWAttrs[0], }, +#endif }; const uint_least8_t NVS_count = CC2650STK_NVSCOUNT; +#endif /* TI_NVS_CONF_ENABLE */ + /* * =============================== PDM =============================== */ @@ -517,9 +550,12 @@ const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { #include #include +#if TI_SPI_CONF_ENABLE + SPICC26XXDMA_Object spiCC26XXDMAObjects[CC2650STK_SPICOUNT]; const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC2650STK_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .baseAddr = SSI0_BASE, .intNum = INT_SSI0_COMB, @@ -535,6 +571,8 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC2650STK_SPICOUNT] = { .csnPin = CC2650STK_SPI0_CSN, .minDmaTransferSize = 10 }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .baseAddr = SSI1_BASE, .intNum = INT_SSI1_COMB, @@ -549,35 +587,45 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC2650STK_SPICOUNT] = { .clkPin = CC2650STK_SPI1_CLK, .csnPin = CC2650STK_SPI1_CSN, .minDmaTransferSize = 10 - } + }, +#endif }; const SPI_Config SPI_config[CC2650STK_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC2650STK_SPI0], .hwAttrs = &spiCC26XXDMAHWAttrs[CC2650STK_SPI0] }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC2650STK_SPI1], .hwAttrs = &spiCC26XXDMAHWAttrs[CC2650STK_SPI1] }, +#endif }; const uint_least8_t SPI_count = CC2650STK_SPICOUNT; +#endif /* TI_SPI_CONF_ENABLE */ + /* * =============================== UART =============================== */ #include #include +#if TI_UART_CONF_ENABLE + UARTCC26XX_Object uartCC26XXObjects[CC2650STK_UARTCOUNT]; uint8_t uartCC26XXRingBuffer[CC2650STK_UARTCOUNT][32]; const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC2650STK_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .baseAddr = UART0_BASE, .powerMngrId = PowerCC26XX_PERIPH_UART0, @@ -593,19 +641,24 @@ const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC2650STK_UARTCOUNT] = { .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, .errorFxn = NULL - } + }, +#endif }; const UART_Config UART_config[CC2650STK_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .fxnTablePtr = &UARTCC26XX_fxnTable, .object = &uartCC26XXObjects[CC2650STK_UART0], .hwAttrs = &uartCC26XXHWAttrs[CC2650STK_UART0] }, +#endif }; const uint_least8_t UART_count = CC2650STK_UARTCOUNT; +#endif /* TI_UART_CONF_ENABLE */ + /* * =============================== UDMA =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h index 8511cd524..0264ae110 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h @@ -48,6 +48,8 @@ extern "C" { #endif +#include "contiki-conf.h" + /* Includes */ #include #include @@ -234,7 +236,9 @@ typedef enum CC2650STK_GPTimers { * @brief Enum of I2C names */ typedef enum CC2650STK_I2CName { +#if TI_I2C_CONF_I2C0_ENABLE CC2650STK_I2C0 = 0, +#endif CC2650STK_I2CCOUNT } CC2650STK_I2CName; @@ -244,8 +248,12 @@ typedef enum CC2650STK_I2CName { * @brief Enum of NVS names */ typedef enum CC2650STK_NVSName { +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE CC2650STK_NVSCC26XX0 = 0, +#endif +#if TI_NVS_CONF_NVS_EXTERNAL_ENABLE CC2650STK_NVSSPI25X0, +#endif CC2650STK_NVSCOUNT } CC2650STK_NVSName; @@ -282,8 +290,12 @@ typedef enum CC2650STK_PWMName { * @brief Enum of SPI names */ typedef enum CC2650STK_SPIName { +#if TI_SPI_CONF_SPI0_ENABLE CC2650STK_SPI0 = 0, +#endif +#if TI_SPI_CONF_SPI1_ENABLE CC2650STK_SPI1, +#endif CC2650STK_SPICOUNT } CC2650STK_SPIName; @@ -293,7 +305,10 @@ typedef enum CC2650STK_SPIName { * @brief Enum of UARTs */ typedef enum CC2650STK_UARTName { +#if TI_UART_CONF_UART0_ENABLE CC2650STK_UART0 = 0, +#endif + CC2650STK_UARTCOUNT } CC2650STK_UARTName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/leds-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/leds-arch.c index 3078ea040..97b2ca597 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/leds-arch.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/leds-arch.c @@ -27,26 +27,28 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup simplelink-platform + * \addtogroup sensortag-peripherals * @{ * * \file - * Driver for LaunchPad LEDs + * LED HAL definitions for the CC2650STK LEDs. Is not compatible with + * the CC1350STK. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ -/* Contiki API */ #include "contiki.h" #include "dev/leds.h" /*---------------------------------------------------------------------------*/ -/* Simplelink SDK API */ #include /*---------------------------------------------------------------------------*/ #include /*---------------------------------------------------------------------------*/ const leds_t leds_arch_leds[] = { + /* Red LED, AKA LED0 */ { .pin = Board_PIN_LED0, .negative_logic = false }, + /* Green LED, AKA LED1 */ { .pin = Board_PIN_LED1, .negative_logic = false }, }; /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/leds-arch.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/leds-arch.h index e002e7650..fcb89bd69 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/leds-arch.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/leds-arch.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,27 +27,21 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ -/** \addtogroup cc26xx-srf-tag - * @{ - * - * \defgroup launchpad-peripherals LaunchPad peripherals - * - * Defines related to LaunchPad peripherals. - * +/** \addtogroup sensortag-peripherals * @{ * * \file - * Header file with definitions related to LaunchPad peripherals - * - * \note Do not include this file directly. + * LED HAL definitions for the CC1350STK LEDs. Is not compatible with + * the CC2650STK. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #ifndef LEDS_ARCH_H_ #define LEDS_ARCH_H_ /*---------------------------------------------------------------------------*/ /** - * \name LED configurations + * \name LED configurations for the dev/leds.h API. * * Those values are not meant to be modified by the user * @{ @@ -58,10 +52,10 @@ #define LEDS_CONF_GREEN 1 #define LEDS_CONF_ALL ((1 << LEDS_CONF_COUNT) - 1) +/** @} */ /*---------------------------------------------------------------------------*/ #endif /* LEDS_ARCH_H_ */ /*---------------------------------------------------------------------------*/ /** - * @} * @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/ext-flash.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/ext-flash.c deleted file mode 100644 index a78a5e764..000000000 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/ext-flash.c +++ /dev/null @@ -1,468 +0,0 @@ -/* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/*---------------------------------------------------------------------------*/ -/** - * \addtogroup sensortag-cc26xx-ext-flash - * @{ - * - * \file - * Sensortag/LaunchPad External Flash Driver - */ -/*---------------------------------------------------------------------------*/ -#include -#include -#include -/*---------------------------------------------------------------------------*/ -#include "contiki.h" -#include "ext-flash.h" -#include "ti-lib.h" -/*---------------------------------------------------------------------------*/ -#include -#include -#include -/*---------------------------------------------------------------------------*/ -static PIN_Config pin_table[] = { - Board_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, - PIN_TERMINATE -}; - -static PIN_State pin_state; -static PIN_Handle pin_handle; - -static SPI_Handle spi_handle; - -static bool ext_flash_opened; -/*---------------------------------------------------------------------------*/ -#define SPI_BIT_RATE 4000000 - -/* Instruction codes */ -#define BLS_CODE_PROGRAM 0x02 /**< Page Program */ -#define BLS_CODE_READ 0x03 /**< Read Data */ -#define BLS_CODE_READ_STATUS 0x05 /**< Read Status Register */ -#define BLS_CODE_WRITE_ENABLE 0x06 /**< Write Enable */ -#define BLS_CODE_SECTOR_ERASE 0x20 /**< Sector Erase */ -#define BLS_CODE_MDID 0x90 /**< Manufacturer Device ID */ - -#define BLS_CODE_DP 0xB9 /**< Power down */ -#define BLS_CODE_RDP 0xAB /**< Power standby */ - -/* Erase instructions */ -#define BLS_CODE_ERASE_4K 0x20 /**< Sector Erase */ -#define BLS_CODE_ERASE_32K 0x52 -#define BLS_CODE_ERASE_64K 0xD8 -#define BLS_CODE_ERASE_ALL 0xC7 /**< Mass Erase */ - -/* Bitmasks of the status register */ -#define BLS_STATUS_SRWD_BM 0x80 -#define BLS_STATUS_BP_BM 0x0C -#define BLS_STATUS_WEL_BM 0x02 -#define BLS_STATUS_WIP_BM 0x01 - -#define BLS_STATUS_BIT_BUSY 0x01 /**< Busy bit of the status register */ - -/* Part specific constants */ -#define BLS_PROGRAM_PAGE_SIZE 0x100 /**< Page size 0x100 */ -#define BLS_ERASE_SECTOR_SIZE 0x1000 /**< Sector size 0x1000 */ -/*---------------------------------------------------------------------------*/ -typedef struct -{ - uint8_t manfId; /**< Manufacturer ID */ - uint8_t devId; /**< Device ID */ -} ExtFlashInfo; -/* Supported flash devices */ -static const ExtFlashInfo supported_devices[] = -{ - { - .manfId = 0xC2, /**< Macronics MX25R1635F */ - .devId = 0x15 - }, - { - .manfId = 0xC2, /**< Macronics MX25R8035F */ - .devId = 0x14 - }, - { - .manfId = 0xEF, /**< WinBond W25X40CL */ - .devId = 0x12 - }, - { - .manfId = 0xEF, /**< WinBond W25X20CL */ - .devId = 0x11 - } -}; -/*---------------------------------------------------------------------------*/ -static bool -spi_write(const uint8_t *buf, size_t len) -{ - SPI_Transaction spiTransaction; - spiTransaction.count = len; - spiTransaction.txBuf = (void *)buf; - spiTransaction.rxBuf = NULL; - - return SPI_transfer(spi_handle, &spiTransaction); -} -/*---------------------------------------------------------------------------*/ -static bool -spi_read(uint8_t *buf, size_t len) -{ - SPI_Transaction spiTransaction; - spiTransaction.count = len; - spiTransaction.txBuf = NULL; - spiTransaction.rxBuf = buf; - - return SPI_transfer(spi_handle, &spiTransaction); -} -/*---------------------------------------------------------------------------*/ -static void -select(void) -{ - PIN_setOutputValue(pin_handle, Board_SPI_FLASH_CS, 1); -} -/*---------------------------------------------------------------------------*/ -static void -deselect(void) -{ - PIN_setOutputValue(pin_handle, Board_SPI_FLASH_CS, 0); -} -/*---------------------------------------------------------------------------*/ -static bool -wait_ready(void) -{ - const uint8_t wbuf[] = { BLS_CODE_READ_STATUS }; - uint8_t rbuf[1] = { 0x0 }; - - /* TODO are 1000 tries enough? */ - for (size_t i = 0; i < 1000; ++i) { - select(); - - const bool spi_ok = spi_write(wbuf, sizeof(wbuf)) - && spi_read(rbuf, sizeof(rbuf)); - - deselect(); - - if (!spi_ok) { - /* Error */ - return false; - } - if (!(rbuf[0] & BLS_STATUS_BIT_BUSY)) { - /* Now ready */ - return true; - } - } - - return false; -} -/*---------------------------------------------------------------------------*/ -static bool -power_standby(void) -{ - const uint8_t cmd[] = { BLS_CODE_RDP }; - - select(); - - const bool spi_ok = spi_write(cmd, sizeof(cmd)); - - deselect(); - - if (!spi_ok) { - return false; - } - - /* Waking up of the device is manufacturer dependent. - * for a Winond chip-set, once the request to wake up the flash has been - * send, CS needs to stay high at least 3us (for Winbond part) - * for chip-set like Macronix, it can take up to 35us. - * 3 cycles per loop: 560 loops @ 48 MHz = 35 us */ - ti_lib_cpu_delay(560); - - return wait_ready(); -} -/*---------------------------------------------------------------------------*/ -static bool -power_down(void) -{ - const uint8_t cmd[] = { BLS_CODE_DP }; - - select(); - - const bool spi_ok = spi_write(cmd, sizeof(cmd)); - - deselect(); - - return spi_ok; -} -/*---------------------------------------------------------------------------*/ -static bool -write_enable(void) -{ - const uint8_t wbuf[] = { BLS_CODE_WRITE_ENABLE }; - - select(); - - const bool spi_ok = spi_write(wbuf, sizeof(wbuf)); - - deselect(); - - return spi_ok; -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Verify the flash part. - * \retval bool true on success; else, false - */ -static bool -verify_part(void) -{ - const uint8_t wbuf[] = { BLS_CODE_MDID, 0xFF, 0xFF, 0x00 }; - uint8_t rbuf[2] = { 0x0 }; - - const bool spi_ok = spi_write(wbuf, sizeof(wbuf)) - && spi_read(rbuf, sizeof(rbuf)); - - if (!spi_ok) { - return false; - } - - const ExtFlashInfo curr_device = { - .manfId = rbuf[0], - .devId = rbuf[1] - }; - - const size_t num_devices = sizeof(supported_devices) / sizeof(supported_devices[0]); - for (size_t i = 0; i < num_devices; ++i) { - if (curr_device.manfId == supported_devices[i].manfId && - curr_device.devId == supported_devices[i].devId) { - return true; - } - } - - return false; -} -/*---------------------------------------------------------------------------*/ -bool -ext_flash_open() -{ - if (ext_flash_opened) { - return true; - } - - pin_handle = PIN_open(&pin_state, pin_table); - - if (pin_handle == NULL) { - return false; - } - - SPI_Params spiParams; - SPI_Params_init(&spiParams); - spiParams.bitRate = SPI_BIT_RATE; - spiParams.mode = SPI_MASTER; - spiParams.transferMode = SPI_MODE_BLOCKING; - - spi_handle = SPI_open(Board_SPI0, &spiParams); - - if (spi_handle == NULL) { - PIN_close(pin_handle); - return false; - } - - ext_flash_opened = true; - - deselect(); - - const bool is_powered = power_standby(); - if (!is_powered) { - ext_flash_close(); - return false; - } - - return verify_part(); -} -/*---------------------------------------------------------------------------*/ -void -ext_flash_close() -{ - if (!ext_flash_opened) { - return; - } - ext_flash_opened = false; - - power_down(); - - SPI_close(spi_handle); - PIN_close(pin_handle); -} -/*---------------------------------------------------------------------------*/ -bool -ext_flash_read(size_t offset, size_t length, uint8_t *buf) -{ - if (spi_handle == NULL || buf == NULL) { - return false; - } - - if (length == 0) { - return true; - } - - const bool is_ready = wait_ready(); - if (!is_ready) { - return false; - } - - const uint8_t wbuf[] = { - BLS_CODE_READ, - (offset >> 16) & 0xFF, - (offset >> 8) & 0xFF, - (offset >> 0) & 0xFF, - }; - - select(); - - const bool spi_ok = spi_write(wbuf, sizeof(wbuf)) - && spi_read(buf, length); - - deselect(); - - return (spi_ok); -} -/*---------------------------------------------------------------------------*/ -bool -ext_flash_write(size_t offset, size_t length, const uint8_t *buf) -{ - if (spi_handle == NULL || buf == NULL) { - return false; - } - - uint8_t wbuf[4] = { BLS_CODE_PROGRAM, 0, 0, 0 }; - - while (length > 0) - { - /* Wait till previous erase/program operation completes */ - if (!wait_ready()) { - return false; - } - - /* Enable writing */ - if (!write_enable()) { - return false; - } - - /* Interim length per instruction */ - size_t ilen = BLS_PROGRAM_PAGE_SIZE - (offset % BLS_PROGRAM_PAGE_SIZE); - if (length < ilen) { - ilen = length; - } - - wbuf[1] = (offset >> 16) & 0xFF; - wbuf[2] = (offset >> 8) & 0xFF; - wbuf[3] = (offset >> 0) & 0xFF; - - offset += ilen; - length -= ilen; - - /* Up to 100ns CS hold time (which is not clear - * whether it's application only in between reads) - * is not imposed here since above instructions - * should be enough to delay - * as much. */ - select(); - - const bool spi_ok = spi_write(wbuf, sizeof(wbuf)) - && spi_write(buf, ilen); - - buf += ilen; - - deselect(); - - if (!spi_ok) { - return false; - } - } - - return true; -} -/*---------------------------------------------------------------------------*/ -bool -ext_flash_erase(size_t offset, size_t length) -{ - /* Note that Block erase might be more efficient when the floor map - * is well planned for OTA but to simplify for the temporary implemetation, - * sector erase is used blindly. */ - uint8_t wbuf[4] = { BLS_CODE_SECTOR_ERASE, 0x0, 0x0, 0x0 }; - - const size_t endoffset = offset + length - 1; - offset = (offset / BLS_ERASE_SECTOR_SIZE) * BLS_ERASE_SECTOR_SIZE; - const size_t numsectors = (endoffset - offset + BLS_ERASE_SECTOR_SIZE - 1) / BLS_ERASE_SECTOR_SIZE; - - for (size_t i = 0; i < numsectors; ++i) { - /* Wait till previous erase/program operation completes */ - if (!wait_ready()) { - return false; - } - - /* Enable writing */ - if (!write_enable()) { - return false; - } - - wbuf[1] = (offset >> 16) & 0xFF; - wbuf[2] = (offset >> 8) & 0xFF; - wbuf[3] = (offset >> 0) & 0xFF; - - select(); - - const bool spi_ok = spi_write(wbuf, sizeof(wbuf)); - - deselect(); - - if (!spi_ok) { - return false; - } - - offset += BLS_ERASE_SECTOR_SIZE; - } - - return true; -} -/*---------------------------------------------------------------------------*/ -bool -ext_flash_test(void) -{ - const bool ret = ext_flash_open(); - ext_flash_close(); - - return ret; -} -/*---------------------------------------------------------------------------*/ -void -ext_flash_init() -{ - SPI_init(); -} -/*---------------------------------------------------------------------------*/ -/** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/ext-flash.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/ext-flash.h deleted file mode 100644 index 5f2717edb..000000000 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/ext-flash.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/*---------------------------------------------------------------------------*/ -/** - * \addtogroup common-cc26xx-peripherals - * @{ - * - * \defgroup sensortag-cc26xx-ext-flash SensorTag/LaunchPad External Flash - * @{ - * - * \file - * Header file for the Sensortag/LaunchPad External Flash Driver - */ -/*---------------------------------------------------------------------------*/ -#ifndef EXT_FLASH_H_ -#define EXT_FLASH_H_ -/*---------------------------------------------------------------------------*/ -#include -#include -#include -/*---------------------------------------------------------------------------*/ -/** - * \brief Initialize storage driver. - * \return True when successful. - */ -bool ext_flash_open(void); - -/** - * \brief Close the storage driver - * - * This call will put the device in its lower power mode (power down). - */ -void ext_flash_close(void); - -/** - * \brief Read storage content - * \param offset Address to read from - * \param length Number of bytes to read - * \param buf Buffer where to store the read bytes - * \return True when successful. - * - * buf must be allocated by the caller - */ -bool ext_flash_read(size_t offset, size_t length, uint8_t *buf); - -/** - * \brief Erase storage sectors corresponding to the range. - * \param offset Address to start erasing - * \param length Number of bytes to erase - * \return True when successful. - * - * The erase operation will be sector-wise, therefore a call to this function - * will generally start the erase procedure at an address lower than offset - */ -bool ext_flash_erase(size_t offset, size_t length); - -/** - * \brief Write to storage sectors. - * \param offset Address to write to - * \param length Number of bytes to write - * \param buf Buffer holding the bytes to be written - * - * \return True when successful. - */ -bool ext_flash_write(size_t offset, size_t length, const uint8_t *buf); - -/** - * \brief Test the flash (power on self-test) - * \return True when successful. - */ -bool ext_flash_test(void); - -/** - * \brief Initialise the external flash - * - * This function will explicitly put the part in its lowest power mode - * (power-down). - * - * In order to perform any operation, the caller must first wake the device - * up by calling ext_flash_open() - */ -void ext_flash_init(void); -/*---------------------------------------------------------------------------*/ -#endif /* EXT_FLASH_H_ */ -/*---------------------------------------------------------------------------*/ -/** - * @} - * @} - */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.c index 7e8f9ccb0..64f1a01ce 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,13 +27,14 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup sensortag-cc26xx-hdc-sensor + * \addtogroup sensortag-hdc-sensor * @{ * * \file - * Driver for the Sensortag HDC sensor + * Driver for the Sensortag HDC1000 sensor. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #include "contiki.h" @@ -58,7 +59,7 @@ #endif /*---------------------------------------------------------------------------*/ #ifndef Board_HDC1000_ADDR -# error "Board file doesn't define I2C address Board_HDC1000_ADDR" +# error "Board file doesn't define the I2C address Board_HDC1000_ADDR" #endif /* Sensor I2C address */ #define HDC1000_I2C_ADDRESS Board_HDC1000_ADDR @@ -72,15 +73,11 @@ #define HDC1000_REG_SERID_L 0xFD /* Serial ID low */ #define HDC1000_REG_MANF_ID 0xFE /* Manufacturer ID */ #define HDC1000_REG_DEV_ID 0xFF /* Device ID */ - +/*---------------------------------------------------------------------------*/ /* Fixed values */ #define HDC1000_VAL_MANF_ID 0x5449 #define HDC1000_VAL_DEV_ID 0x1000 #define HDC1000_VAL_CONFIG 0x1000 /* 14 bit, acquired in sequence */ - -/* Sensor selection/deselection */ -#define SENSOR_SELECT() board_i2c_select(BOARD_I2C_INTERFACE_0, SENSOR_I2C_ADDRESS) -#define SENSOR_DESELECT() board_i2c_deselect() /*---------------------------------------------------------------------------*/ /* Byte swap of 16-bit register value */ #define HI_UINT16(a) (((a) >> 8) & 0xFF) @@ -90,7 +87,7 @@ #define LSB16(v) (LO_UINT16(v)), (HI_UINT16(v)) /*---------------------------------------------------------------------------*/ -static I2C_Handle i2cHandle; +static I2C_Handle i2c_handle; /*---------------------------------------------------------------------------*/ /* Raw data as returned from the sensor (Big Endian) */ typedef struct { @@ -117,43 +114,74 @@ static volatile HDC_1000_SENSOR_STATUS sensor_status = HDC_1000_SENSOR_STATUS_DI static struct ctimer startup_timer; /*---------------------------------------------------------------------------*/ +/** + * \brief Setup and peform an I2C transaction. + * \param wbuf Output buffer during the I2C transation. + * \param wcount How many bytes in the wbuf. + * \param rbuf Input buffer during the I2C transation. + * \param rcount How many bytes to read into rbuf. + * \return true if the I2C operation was successful; + * else, return false. + */ static bool -i2c_transaction(void *writeBuf, size_t writeCount, void *readBuf, size_t readCount) +i2c_write_read(void *wbuf, size_t wcount, void *rbuf, size_t rcount) { - I2C_Transaction i2cTransaction = { - .writeBuf = writeBuf, - .writeCount = writeCount, - .readBuf = readBuf, - .readCount = readCount, + I2C_Transaction i2c_transaction = { + .writeBuf = wbuf, + .writeCount = wcount, + .readBuf = rbuf, + .readCount = rcount, .slaveAddress = HDC1000_I2C_ADDRESS, }; - return I2C_transfer(i2cHandle, &i2cTransaction); + return I2C_transfer(i2c_handle, &i2c_transaction); } -#define i2c_write(writeBuf, writeCount) i2c_transaction(writeBuf, writeCount, NULL, 0) -#define i2c_read(readBuf, readCount) i2c_transaction(NULL, 0, readBuf, readCount) -#define i2c_write_read(writeBuf, writeCount, readBuf, readCount) \ - i2c_transaction(writeBuf, writeCount, readBuf, readCount) +/** + * \brief Peform a write only I2C transaction. + * \param wbuf Output buffer during the I2C transation. + * \param wcount How many bytes in the wbuf. + * \return true if the I2C operation was successful; + * else, return false. + */ +static inline bool +i2c_write(void *wbuf, size_t wcount) +{ + return i2c_write_read(wbuf, wcount, NULL, 0); +} + +/** + * \brief Peform a read only I2C transaction. + * \param rbuf Input buffer during the I2C transation. + * \param rcount How many bytes to read into rbuf. + * \return true if the I2C operation was successful; + * else, return false. + */ +static inline bool +i2c_read(void *rbuf, size_t rcount) +{ + return i2c_write_read(NULL, 0, rbuf, rcount); +} /*---------------------------------------------------------------------------*/ /** - * \brief Initialise the humidity sensor driver - * \return True if I2C operation successful + * \brief Initialize the HDC-1000 sensor driver. + * \return true if I2C operation successful; else, return false. */ static bool sensor_init(void) { - if (i2cHandle) { + if (i2c_handle) { return true; } - I2C_Params i2cParams; - I2C_Params_init(&i2cParams); - i2cParams.transferMode = I2C_MODE_BLOCKING; - i2cParams.bitRate = I2C_400kHz; + I2C_Params i2c_params; + I2C_Params_init(&i2c_params); - i2cHandle = I2C_open(Board_I2C0, &i2cParams); - if (i2cHandle == NULL) { + i2c_params.transferMode = I2C_MODE_BLOCKING; + i2c_params.bitRate = I2C_400kHz; + + i2c_handle = I2C_open(Board_I2C0, &i2c_params); + if (i2c_handle == NULL) { return false; } @@ -164,8 +192,8 @@ sensor_init(void) } /*---------------------------------------------------------------------------*/ /** - * \brief Start measurement - * \return True if I2C operation successful + * \brief Start measurement. + * \return true if I2C operation successful; else, return false. */ static bool start(void) @@ -176,9 +204,9 @@ start(void) } /*---------------------------------------------------------------------------*/ /** - * \brief Convert raw data to temperature and humidity - * \param temp - converted temperature - * \param hum - converted humidity + * \brief Convert raw data to temperature and humidity. + * \param temp Output variable to store converted temperature. + * \param hum Output variable to store converted humidity. */ static void convert(int32_t *temp, int32_t *hum) @@ -192,9 +220,15 @@ convert(int32_t *temp, int32_t *hum) *hum = raw_hum * 100 * 100 / 65536; } /*---------------------------------------------------------------------------*/ +/** + * \brief Callback when sensor is ready to read data from. + */ static void -notify_ready(void *not_used) +notify_ready(void *unused) { + /* Unused args */ + (void)unused; + /* Latch readings */ if (i2c_read(&sensor_data, sizeof(sensor_data))) { sensor_status = HDC_1000_SENSOR_STATUS_READINGS_READY; @@ -206,9 +240,9 @@ notify_ready(void *not_used) } /*---------------------------------------------------------------------------*/ /** - * \brief Returns a reading from the sensor - * \param type HDC_1000_SENSOR_TYPE_TEMP or HDC_1000_SENSOR_TYPE_HUMIDITY - * \return Temperature (centi degrees C) or Humidity (centi %RH) + * \brief Returns a reading from the sensor. + * \param type HDC_1000_SENSOR_TYPE_TEMP or HDC_1000_SENSOR_TYPE_HUMID. + * \return Temperature (centi degrees C) or Humidity (centi %RH). */ static int value(int type) @@ -223,13 +257,13 @@ value(int type) switch (type) { case HDC_1000_SENSOR_TYPE_TEMP: - case HDC_1000_SENSOR_TYPE_HUMIDITY: + case HDC_1000_SENSOR_TYPE_HUMID: convert(&temp, &hum); PRINTF("HDC: t=%d h=%d\n", (int)temp, (int)hum); if (type == HDC_1000_SENSOR_TYPE_TEMP) { return (int)temp; - } else if (type == HDC_1000_SENSOR_TYPE_HUMIDITY) { + } else if (type == HDC_1000_SENSOR_TYPE_HUMID) { return (int)hum; } else { return HDC_1000_READING_ERROR; @@ -242,14 +276,12 @@ value(int type) } /*---------------------------------------------------------------------------*/ /** - * \brief Configuration function for the HDC1000 sensor. - * - * \param type Activate, enable or disable the sensor. See below - * \param enable - * - * When type == SENSORS_HW_INIT we turn on the hardware - * When type == SENSORS_ACTIVE and enable==1 we enable the sensor - * When type == SENSORS_ACTIVE and enable==0 we disable the sensor + * \brief Configuration function for the HDC1000 sensor. + * \param type Activate, enable or disable the sensor. See below. + * \param enable Either enable or disable the sensor. + * When type == SENSORS_HW_INIT we turn on the hardware. + * When type == SENSORS_ACTIVE and enable==1 we enable the sensor. + * When type == SENSORS_ACTIVE and enable==0 we disable the sensor. */ static int configure(int type, int enable) @@ -291,9 +323,9 @@ configure(int type, int enable) } /*---------------------------------------------------------------------------*/ /** - * \brief Returns the status of the sensor - * \param type SENSORS_ACTIVE or SENSORS_READY - * \return One of the SENSOR_STATUS_xyz defines + * \brief Returns the status of the sensor. + * \param type SENSORS_ACTIVE or SENSORS_READY. + * \return One of the SENSOR_STATUS_xyz defines. */ static int status(int type) @@ -302,12 +334,10 @@ status(int type) case SENSORS_ACTIVE: case SENSORS_READY: return sensor_status; - break; default: - break; + return HDC_1000_SENSOR_STATUS_DISABLED; } - return HDC_1000_SENSOR_STATUS_DISABLED; } /*---------------------------------------------------------------------------*/ SENSORS_SENSOR(hdc_1000_sensor, "HDC1000", value, configure, status); diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.h index f2112f76f..c3d31e383 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,12 +27,12 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup sensortag-cc26xx-peripherals + * \addtogroup sensortag-peripherals * @{ * - * \defgroup sensortag-cc26xx-hdc-sensor SensorTag 2.0 TI HDC1000 Sensor + * \defgroup sensortag-hdc-sensor SensorTag HDC1000 - Temperature and + * Humidity Sensor * * Due to the time required for the sensor to startup, this driver is meant to * be used in an asynchronous fashion. The caller must first activate the @@ -45,28 +45,35 @@ * and latch them. It will then generate a sensors_changed event. * * The user can then retrieve readings by calling .value() and by passing - * either HDC_1000_SENSOR_TYPE_TEMP or HDC_1000_SENSOR_TYPE_HUMIDITY as the + * either HDC_1000_SENSOR_TYPE_TEMP or HDC_1000_SENSOR_TYPE_HUMID as the * argument. Multiple calls to value() will not trigger new readings, they will * simply return the most recent latched values. * - * The user can query the sensor's status by calling .status() + * The user can query the sensor's status by calling status(). * * To get a fresh reading, the user must trigger a new reading cycle by calling * SENSORS_ACTIVATE(). * @{ * * \file - * Header file for the Sensortag TI HDC1000 sensor + * Header file for the Sensortag HDC1000 sensor. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #ifndef HDC_1000_SENSOR_H #define HDC_1000_SENSOR_H /*---------------------------------------------------------------------------*/ +#include "contiki.h" #include "lib/sensors.h" /*---------------------------------------------------------------------------*/ +#if (TI_I2C_CONF_ENABLE == 0) || (TI_I2C_CONF_I2C0_ENABLE == 0) +# error "The HDC-1000 requires the I2C driver (TI_I2C_CONF_ENABLE = 1)" +#endif +/*---------------------------------------------------------------------------*/ typedef enum { HDC_1000_SENSOR_TYPE_TEMP, - HDC_1000_SENSOR_TYPE_HUMIDITY + HDC_1000_SENSOR_TYPE_HUMID } HDC_1000_SENSOR_TYPE; /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c index 399ab04a2..f6e9bcdca 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,23 +27,27 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup sensortag-cc26xx-mpu + * \addtogroup sensortag-mpu * @{ * * \file - * Driver for the Sensortag Invensense MPU9250 motion processing unit + * Driver for the Sensortag Invensense MPU9250 motion processing unit + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "lib/sensors.h" #include "sys/rtimer.h" + #include "mpu-9250-sensor.h" /*---------------------------------------------------------------------------*/ #include + #include #include DeviceFamily_constructPath(driverlib/cpu.h) + #include #include /*---------------------------------------------------------------------------*/ @@ -60,16 +64,17 @@ #endif /*---------------------------------------------------------------------------*/ #ifndef Board_MPU9250_ADDR -# error "Board file doesn't define I2C address Board_MPU9250_ADDR" +# error "Board file doesn't define I2C address Board_MPU9250_ADDR" #endif #ifndef Board_MPU9250_MAG_ADDR -# error "Board file doesn't define I2C address Board_MPU9250_MAG_ADDR" +# error "Board file doesn't define I2C address Board_MPU9250_MAG_ADDR" #endif + /* Sensor I2C address */ #define MPU_9250_I2C_ADDRESS Board_MPU9250_ADDR #define MPU_9250_MAG_I2C_ADDRESS Board_MPU9250_MAG_ADDR /*-------------a--------------------------------------------------------------*/ -/* Registers */ +/* Self Test Registers */ #define REG_SELF_TEST_X_GYRO 0x00 /* R/W */ #define REG_SELF_TEST_Y_GYRO 0x01 /* R/W */ #define REG_SELF_TEST_Z_GYRO 0x02 /* R/W */ @@ -77,6 +82,7 @@ #define REG_SELF_TEST_Z_ACCEL 0x0E /* R/W */ #define REG_SELF_TEST_Y_ACCEL 0x0F /* R/W */ /*---------------------------------------------------------------------------*/ +/* Axis Registers */ #define REG_XG_OFFSET_H 0x13 /* R/W */ #define REG_XG_OFFSET_L 0x14 /* R/W */ #define REG_YG_OFFSET_H 0x15 /* R/W */ @@ -84,6 +90,7 @@ #define REG_ZG_OFFSET_H 0x17 /* R/W */ #define REG_ZG_OFFSET_L 0x18 /* R/W */ /*---------------------------------------------------------------------------*/ +/* Control Registers */ #define REG_SMPLRT_DIV 0x19 /* R/W */ #define REG_CONFIG 0x1A /* R/W */ #define REG_GYRO_CONFIG 0x1B /* R/W */ @@ -180,9 +187,9 @@ static PIN_Config mpu_9250_pin_table[] = { PIN_TERMINATE }; -static PIN_State pinState; -static PIN_Handle pinHandle; -static I2C_Handle i2cHandle; +static PIN_State pin_state; +static PIN_Handle pin_handle; +static I2C_Handle i2c_handle; /*---------------------------------------------------------------------------*/ typedef struct { @@ -219,30 +226,64 @@ static struct ctimer startup_timer; /* ui32Count = [delay in us] * [CPU clock in MHz] / [cycles per loop] */ #define delay_ms(ms) CPUdelay((ms) * 1000 * 48 / 7) /*---------------------------------------------------------------------------*/ +/** + * \brief Setup and peform an I2C transaction. + * \param wbuf Output buffer during the I2C transation. + * \param wcount How many bytes in the wbuf. + * \param rbuf Input buffer during the I2C transation. + * \param rcount How many bytes to read into rbuf. + * \return true if the I2C operation was successful; + * else, return false. + */ static bool -i2c_transaction(void *writeBuf, size_t writeCount, void *readBuf, size_t readCount) +i2c_write_read(void *wbuf, size_t wcount, void *rbuf, size_t rcount) { - I2C_Transaction i2cTransaction = { - .writeBuf = writeBuf, - .writeCount = writeCount, - .readBuf = readBuf, - .readCount = readCount, + I2C_Transaction i2c_transaction = { + .writeBuf = wbuf, + .writeCount = wcount, + .readBuf = rbuf, + .readCount = rcount, .slaveAddress = MPU_9250_I2C_ADDRESS, }; - return I2C_transfer(i2cHandle, &i2cTransaction); + return I2C_transfer(i2c_handle, &i2c_transaction); } -#define i2c_write(writeBuf, writeCount) i2c_transaction(writeBuf, writeCount, NULL, 0) -#define i2c_read(readBuf, readCount) i2c_transaction(NULL, 0, readBuf, readCount) -#define i2c_write_read(writeBuf, writeCount, readBuf, readCount) \ - i2c_transaction(writeBuf, writeCount, readBuf, readCount) +/** + * \brief Peform a write only I2C transaction. + * \param wbuf Output buffer during the I2C transation. + * \param wcount How many bytes in the wbuf. + * \return true if the I2C operation was successful; + * else, return false. + */ +static inline bool +i2c_write(void *wbuf, size_t wcount) +{ + return i2c_write_read(wbuf, wcount, NULL, 0); +} + +/** + * \brief Peform a read only I2C transaction. + * \param rbuf Input buffer during the I2C transation. + * \param rcount How many bytes to read into rbuf. + * \return true if the I2C operation was successful; + * else, return false. + */ +static inline bool +i2c_read(void *rbuf, size_t rcount) +{ + return i2c_write_read(NULL, 0, rbuf, rcount); +} /*---------------------------------------------------------------------------*/ +/** + * \brief Initialize the MPU-9250 sensor driver. + * \return true if I2C operation successful; else, return false. + */ static bool sensor_init(void) { - pinHandle = PIN_open(&pinState, mpu_9250_pin_table); - if (pinHandle == NULL) { + pin_handle = PIN_open(&pin_state, mpu_9250_pin_table); + if (pin_handle == NULL) { return false; } @@ -251,9 +292,9 @@ sensor_init(void) i2cParams.transferMode = I2C_MODE_BLOCKING; i2cParams.bitRate = I2C_400kHz; - i2cHandle = I2C_open(Board_I2C0, &i2cParams); - if (i2cHandle == NULL) { - PIN_close(&pinState); + i2c_handle = I2C_open(Board_I2C0, &i2cParams); + if (i2c_handle == NULL) { + PIN_close(&pin_state); return false; } @@ -265,7 +306,7 @@ sensor_init(void) } /*---------------------------------------------------------------------------*/ /** - * \brief Place the MPU in low power mode + * \brief Place the sensor in low-power mode. */ static void sensor_sleep(void) @@ -281,7 +322,7 @@ sensor_sleep(void) } /*---------------------------------------------------------------------------*/ /** - * \brief Exit low power mode + * \brief Wakeup the sensor from low-power mode. */ static void sensor_wakeup(void) @@ -336,11 +377,11 @@ convert_to_le(uint8_t *data, uint8_t len) } /*---------------------------------------------------------------------------*/ /** - * \brief Check whether a data or wake on motion interrupt has occurred - * \return Return the interrupt status + * \brief Check whether a data or wake on motion interrupt has occurred. + * \return Return the interrupt status. * - * This driver does not use interrupts, however this function allows us to - * determine whether a new sensor reading is available + * This driver does not use interrupts, however this function allows + * us to determine whether a new sensor reading is available. */ static bool sensor_data_ready(uint8_t* int_status) @@ -352,8 +393,8 @@ sensor_data_ready(uint8_t* int_status) } /*---------------------------------------------------------------------------*/ /** - * \brief Read data from the accelerometer - X, Y, Z - 3 words - * \return True if a valid reading could be taken, false otherwise + * \brief Read data from the accelerometer, total of 3 words (X, Y, Z). + * \return true if a valid reading could be taken; otherwise, false. */ static bool acc_read(uint8_t int_status, uint16_t *data) @@ -375,8 +416,8 @@ acc_read(uint8_t int_status, uint16_t *data) } /*---------------------------------------------------------------------------*/ /** - * \brief Read data from the gyroscope - X, Y, Z - 3 words - * \return True if a valid reading could be taken, false otherwise + * \brief Read data from the accelerometer, total of 3 words (X, Y, Z). + * \return true if a valid reading could be taken; otherwise, false. */ static bool gyro_read(uint8_t int_status, uint16_t *data) @@ -398,9 +439,9 @@ gyro_read(uint8_t int_status, uint16_t *data) } /*---------------------------------------------------------------------------*/ /** - * \brief Convert accelerometer raw reading to a value in G - * \param raw_data The raw accelerometer reading - * \return The converted value + * \brief Convert accelerometer raw reading to a value in G. + * \param raw_data The raw accelerometer reading. + * \return The converted value. */ static int32_t acc_convert(int32_t raw_data) @@ -415,9 +456,9 @@ acc_convert(int32_t raw_data) } /*---------------------------------------------------------------------------*/ /** - * \brief Convert gyro raw reading to a value in deg/sec - * \param raw_data The raw accelerometer reading - * \return The converted value + * \brief Convert gyro raw reading to a value in deg/sec. + * \param raw_data The raw accelerometer reading. + * \return The converted value. */ static int32_t gyro_convert(int32_t raw_data) @@ -460,9 +501,10 @@ initialise_cb(void *unused) } /*---------------------------------------------------------------------------*/ /** - * \brief Returns a reading from the sensor - * \param type MPU_9250_SENSOR_TYPE_ACC_[XYZ] or MPU_9250_SENSOR_TYPE_GYRO_[XYZ] - * \return centi-G (ACC) or centi-Deg/Sec (Gyro) + * \brief Returns a reading from the sensor. + * \param type MPU_9250_SENSOR_TYPE_ACC_[XYZ] or + * MPU_9250_SENSOR_TYPE_GYRO_[XYZ]. + * \return Centi-G (ACC) or centi-Deg/Sec (Gyro). */ static int value(int type) @@ -531,14 +573,12 @@ value(int type) } /*---------------------------------------------------------------------------*/ /** - * \brief Configuration function for the MPU9250 sensor. - * - * \param type Activate, enable or disable the sensor. See below - * \param enable - * - * When type == SENSORS_HW_INIT we turn on the hardware - * When type == SENSORS_ACTIVE and enable==1 we enable the sensor - * When type == SENSORS_ACTIVE and enable==0 we disable the sensor + * \brief Configuration function for the MPU9250 sensor. + * \param type Activate, enable or disable the sensor. See below. + * \param enable Enable or disable sensor. + * When type == SENSORS_HW_INIT we turn on the hardware. + * When type == SENSORS_ACTIVE and enable==1 we enable the sensor. + * When type == SENSORS_ACTIVE and enable==0 we disable the sensor. */ static int configure(int type, int enable) @@ -562,7 +602,7 @@ configure(int type, int enable) mpu_9250.type = enable_type; mpu_9250.status = MPU_9250_SENSOR_STATUS_BOOTING; - PIN_setOutputValue(pinHandle, Board_MPU_POWER, 1); + PIN_setOutputValue(pin_handle, Board_MPU_POWER, 1); ctimer_set(&startup_timer, SENSOR_BOOT_DELAY, initialise_cb, NULL); } else { @@ -573,8 +613,8 @@ configure(int type, int enable) if (PIN_getOutputValue(Board_MPU_POWER)) { sensor_sleep(); - I2C_cancel(i2cHandle); - PIN_setOutputValue(pinHandle, Board_MPU_POWER, 0); + I2C_cancel(i2c_handle); + PIN_setOutputValue(pin_handle, Board_MPU_POWER, 0); } mpu_9250.type = MPU_9250_SENSOR_TYPE_NONE; @@ -589,9 +629,9 @@ configure(int type, int enable) } /*---------------------------------------------------------------------------*/ /** - * \brief Returns the status of the sensor - * \param type SENSORS_ACTIVE or SENSORS_READY - * \return 1 if the sensor is enabled + * \brief Returns the status of the sensor + * \param type SENSORS_ACTIVE or SENSORS_READY + * \return 1 if the sensor is enabled, else 0. */ static int status(int type) diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.h index e27c75dde..632d6e5b9 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,71 +27,80 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup sensortag-cc26xx-peripherals + * \addtogroup sensortag-peripherals * @{ * - * \defgroup sensortag-cc26xx-mpu SensorTag 2.0 Motion Processing Unit + * \defgroup sensortag-mpu SensorTag Motion Processing Unit * - * Driver for the Invensense MPU9250 Motion Processing Unit. + * Driver for the Invensense MPU-9250 Motion Processing Unit. * - * Due to the time required between triggering a reading and the reading - * becoming available, this driver is meant to be used in an asynchronous - * fashion. The caller must first activate the sensor by calling - * mpu_9250_sensor.configure(SENSORS_ACTIVE, xyz); - * The value for the xyz arguments depends on the required readings. If the - * caller intends to read both the accelerometer as well as the gyro then - * xyz should be MPU_9250_SENSOR_TYPE_ALL. If the caller only needs to take a - * reading from one of the two elements, xyz should be one of - * MPU_9250_SENSOR_TYPE_ACC or MPU_9250_SENSOR_TYPE_GYRO + * Due to the time required between triggering a reading and the + * reading becoming available, this driver is meant to be used in an + * asynchronous fashion. The caller must first activate the sensor by + * calling * - * Calling .configure() will power up the sensor and initialise it. When the - * sensor is ready to provide readings, the driver will generate a - * sensors_changed event. + * mpu_9250_sensor.configure(SENSORS_ACTIVE, xyz); * - * Calls to .status() will return the driver's state which could indicate that - * the sensor is off, booting or on. + * The value for the xyz arguments depends on the required readings. If + * the caller intends to read both the accelerometer as well as the gyro + * then xyz should be MPU_9250_SENSOR_TYPE_ALL. If the caller only needs + * to take a reading from one of the two elements, xyz should be one of + * MPU_9250_SENSOR_TYPE_ACC or MPU_9250_SENSOR_TYPE_GYRO * - * Once a reading has been taken, the caller has two options: - * - Turn the sensor off by calling SENSORS_DEACTIVATE, but in order to take - * subsequent readings the sensor must be started up all over - * - Leave the sensor on. In this scenario, the caller can simply keep calling - * value() for subsequent readings, but having the sensor on will consume - * more energy, especially if both accelerometer and the gyro are on. + * Calling configure() will power up the sensor and initialise it. When + * the sensor is ready to provide readings, the driver will generate a + * sensors_changed event. + * + * Calls to status() will return the driver's state which could indicate + * that the sensor is off, booting or on. + * + * Once a reading has been taken, the caller has two options: + * - Turn the sensor off by calling SENSORS_DEACTIVATE, but in order to + * take subsequent readings the sensor must be started up all over + * - Leave the sensor on. In this scenario, the caller can simply keep + * calling value() for subsequent readings, but having the sensor on + * will consume more energy, especially if both accelerometer and the + * gyro are on. * @{ * * \file - * Header file for the Sensortag Invensense MPU9250 motion processing unit + * Header file for the Sensortag Invensense MPU-9250 motion processing unit + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #ifndef MPU_9250_SENSOR_H_ #define MPU_9250_SENSOR_H_ /*---------------------------------------------------------------------------*/ -#include "contiki-conf.h" +#include "contiki.h" +/*---------------------------------------------------------------------------*/ +#if (TI_I2C_CONF_ENABLE == 0) || (TI_I2C_CONF_I2C0_ENABLE == 0) +# error "The MPU-9250 requires the I2C driver (TI_I2C_CONF_ENABLE = 1)" +#endif /*---------------------------------------------------------------------------*/ #define MPU_9250_READING_ERROR -1 /*---------------------------------------------------------------------------*/ -/* ACC / Gyro Axes */ +/* Accelerometer / Gyro Axes */ typedef enum { - MPU_9250_SENSOR_TYPE_NONE = (0), /* 0b000000 = 0x00 */ - MPU_9250_SENSOR_TYPE_GYRO_X = (1 << 0), /* 0b000001 = 0x01 */ - MPU_9250_SENSOR_TYPE_GYRO_Y = (1 << 1), /* 0b000010 = 0x02 */ - MPU_9250_SENSOR_TYPE_GYRO_Z = (1 << 2), /* 0b000100 = 0x04 */ - MPU_9250_SENSOR_TYPE_ACC_X = (1 << 3), /* 0b001000 = 0x08 */ - MPU_9250_SENSOR_TYPE_ACC_Y = (1 << 4), /* 0b010000 = 0x10 */ - MPU_9250_SENSOR_TYPE_ACC_Z = (1 << 5), /* 0b100000 = 0x20 */ + MPU_9250_SENSOR_TYPE_NONE = (0), /**< 0b000000 = 0x00 */ + MPU_9250_SENSOR_TYPE_GYRO_X = (1 << 0), /**< 0b000001 = 0x01 */ + MPU_9250_SENSOR_TYPE_GYRO_Y = (1 << 1), /**< 0b000010 = 0x02 */ + MPU_9250_SENSOR_TYPE_GYRO_Z = (1 << 2), /**< 0b000100 = 0x04 */ + MPU_9250_SENSOR_TYPE_ACC_X = (1 << 3), /**< 0b001000 = 0x08 */ + MPU_9250_SENSOR_TYPE_ACC_Y = (1 << 4), /**< 0b010000 = 0x10 */ + MPU_9250_SENSOR_TYPE_ACC_Z = (1 << 5), /**< 0b100000 = 0x20 */ MPU_9250_SENSOR_TYPE_GYRO = MPU_9250_SENSOR_TYPE_GYRO_X | MPU_9250_SENSOR_TYPE_GYRO_Y | MPU_9250_SENSOR_TYPE_GYRO_Z, - /* 0b000111 = 0x07 */ + /**< 0b000111 = 0x07 */ MPU_9250_SENSOR_TYPE_ACC = MPU_9250_SENSOR_TYPE_ACC_X | MPU_9250_SENSOR_TYPE_ACC_Y | MPU_9250_SENSOR_TYPE_ACC_Z, - /* 0b111000 = 0x38 */ + /**< 0b111000 = 0x38 */ MPU_9250_SENSOR_TYPE_ALL = MPU_9250_SENSOR_TYPE_GYRO | MPU_9250_SENSOR_TYPE_ACC - /* 0b111111 = 0x3F */ + /**< 0b111111 = 0x3F */ } MPU_9250_SENSOR_TYPE; /*---------------------------------------------------------------------------*/ /* Accelerometer range */ @@ -112,9 +121,9 @@ typedef enum { /*---------------------------------------------------------------------------*/ /* Accelerometer range configuration, type MPU_9250_SENSOR_ACC_RANGE */ #ifdef MPU_9250_SENSOR_CONF_ACC_RANGE_ARG -# define MPU_9250_SENSOR_ACC_RANGE_ARG MPU_9250_SENSOR_CONF_ACC_RANGE +# define MPU_9250_SENSOR_ACC_RANGE_ARG MPU_9250_SENSOR_CONF_ACC_RANGE #else -# define MPU_9250_SENSOR_ACC_RANGE_ARG MPU_9250_SENSOR_ACC_RANGE_2G +# define MPU_9250_SENSOR_ACC_RANGE_ARG MPU_9250_SENSOR_ACC_RANGE_2G #endif /*---------------------------------------------------------------------------*/ extern const struct sensors_sensor mpu_9250_sensor; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.c index 470d3102e..a7774414a 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,21 +27,24 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup sensortag-cc26xx-opt-sensor + * \addtogroup sensortag-opt-sensor * @{ * * \file - * Driver for the Sensortag Opt3001 light sensor + * Driver for the Sensortag OPT-3001 light sensor. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "lib/sensors.h" #include "sys/ctimer.h" + #include "opt-3001-sensor.h" /*---------------------------------------------------------------------------*/ #include + #include /*---------------------------------------------------------------------------*/ #include @@ -63,65 +66,65 @@ #define OPT_3001_I2C_ADDRESS Board_OPT3001_ADDR /*---------------------------------------------------------------------------*/ /* Register addresses */ -#define REG_RESULT 0x00 -#define REG_CONFIGURATION 0x01 -#define REG_LOW_LIMIT 0x02 -#define REG_HIGH_LIMIT 0x03 +#define REG_RESULT 0x00 +#define REG_CONFIGURATION 0x01 +#define REG_LOW_LIMIT 0x02 +#define REG_HIGH_LIMIT 0x03 -#define REG_MANUFACTURER_ID 0x7E -#define REG_DEVICE_ID 0x7F +#define REG_MANUFACTURER_ID 0x7E +#define REG_DEVICE_ID 0x7F /*---------------------------------------------------------------------------*/ /* * Configuration Register Bits and Masks. * We use uint16_t to read from / write to registers, meaning that the * register's MSB is the variable's LSB. */ -#define CFG_RN 0x00F0 /* [15..12] Range Number */ -#define CFG_CT 0x0008 /* [11] Conversion Time */ -#define CFG_M 0x0006 /* [10..9] Mode of Conversion */ -#define CFG_OVF 0x0001 /* [8] Overflow */ -#define CFG_CRF 0x8000 /* [7] Conversion Ready Field */ -#define CFG_FH 0x4000 /* [6] Flag High */ -#define CFG_FL 0x2000 /* [5] Flag Low */ -#define CFG_L 0x1000 /* [4] Latch */ -#define CFG_POL 0x0800 /* [3] Polarity */ -#define CFG_ME 0x0400 /* [2] Mask Exponent */ -#define CFG_FC 0x0300 /* [1..0] Fault Count */ - +#define CFG_RN 0x00F0 /**< [15..12] Range Number */ +#define CFG_CT 0x0008 /**< [11] Conversion Time */ +#define CFG_M 0x0006 /**< [10..9] Mode of Conversion */ +#define CFG_OVF 0x0001 /**< [8] Overflow */ +#define CFG_CRF 0x8000 /**< [7] Conversion Ready Field */ +#define CFG_FH 0x4000 /**< [6] Flag High */ +#define CFG_FL 0x2000 /**< [5] Flag Low */ +#define CFG_L 0x1000 /**< [4] Latch */ +#define CFG_POL 0x0800 /**< [3] Polarity */ +#define CFG_ME 0x0400 /**< [2] Mask Exponent */ +#define CFG_FC 0x0300 /**< [1..0] Fault Count */ +/*---------------------------------------------------------------------------*/ /* Possible Values for CT */ -#define CFG_CT_100 0x0000 -#define CFG_CT_800 CFG_CT - +#define CFG_CT_100 0x0000 +#define CFG_CT_800 CFG_CT +/*---------------------------------------------------------------------------*/ /* Possible Values for M */ -#define CFG_M_CONTI 0x0004 -#define CFG_M_SINGLE 0x0002 -#define CFG_M_SHUTDOWN 0x0000 - +#define CFG_M_CONTI 0x0004 +#define CFG_M_SINGLE 0x0002 +#define CFG_M_SHUTDOWN 0x0000 +/*---------------------------------------------------------------------------*/ /* Reset Value for the register 0xC810. All zeros except: */ -#define CFG_RN_RESET 0x00C0 -#define CFG_CT_RESET CFG_CT_800 -#define CFG_L_RESET 0x1000 -#define CFG_DEFAULTS (CFG_RN_RESET | CFG_CT_100 | CFG_L_RESET) - +#define CFG_RN_RESET 0x00C0 +#define CFG_CT_RESET CFG_CT_800 +#define CFG_L_RESET 0x1000 +#define CFG_DEFAULTS (CFG_RN_RESET | CFG_CT_100 | CFG_L_RESET) +/*---------------------------------------------------------------------------*/ /* Enable / Disable */ -#define CFG_ENABLE_CONTINUOUS (CFG_M_CONTI | CFG_DEFAULTS) -#define CFG_ENABLE_SINGLE_SHOT (CFG_M_SINGLE | CFG_DEFAULTS) -#define CFG_DISABLE CFG_DEFAULTS +#define CFG_ENABLE_CONTINUOUS (CFG_M_CONTI | CFG_DEFAULTS) +#define CFG_ENABLE_SINGLE_SHOT (CFG_M_SINGLE | CFG_DEFAULTS) +#define CFG_DISABLE CFG_DEFAULTS /*---------------------------------------------------------------------------*/ /* Register length */ -#define REGISTER_LENGTH 2 +#define REGISTER_LENGTH 2 /*---------------------------------------------------------------------------*/ /* Sensor data size */ -#define DATA_LENGTH 2 +#define DATA_LENGTH 2 /*---------------------------------------------------------------------------*/ /* Byte swap of 16-bit register value */ -#define HI_UINT16(a) (((a) >> 8) & 0xFF) -#define LO_UINT16(a) ((a) & 0xFF) +#define HI_UINT16(a) (((a) >> 8) & 0xFF) +#define LO_UINT16(a) (((a) >> 0) & 0xFF) -#define SWAP16(v) ((LO_UINT16(v) << 8) | HI_UINT16(v)) +#define SWAP16(v) ((LO_UINT16(v) << 8) | (HI_UINT16(v) << 0)) -#define LSB16(v) (LO_UINT16(v)), (HI_UINT16(v)) -#define MSB16(v) (HI_UINT16(v)), (LO_UINT16(v)) +#define LSB16(v) (LO_UINT16(v)), (HI_UINT16(v)) +#define MSB16(v) (HI_UINT16(v)), (LO_UINT16(v)) /*---------------------------------------------------------------------------*/ typedef struct { volatile OPT_3001_STATUS status; @@ -134,39 +137,76 @@ static OPT_3001_Object opt_3001; static struct ctimer startup_timer; /*---------------------------------------------------------------------------*/ -static I2C_Handle i2cHandle; +static I2C_Handle i2c_handle; /*---------------------------------------------------------------------------*/ +/** + * \brief Setup and peform an I2C transaction. + * \param wbuf Output buffer during the I2C transation. + * \param wcount How many bytes in the wbuf. + * \param rbuf Input buffer during the I2C transation. + * \param rcount How many bytes to read into rbuf. + * \return true if the I2C operation was successful; + * else, return false. + */ static bool -i2c_write_read(void *writeBuf, size_t writeCount, void *readBuf, size_t readCount) +i2c_write_read(void *wbuf, size_t wcount, void *rbuf, size_t rcount) { - I2C_Transaction i2cTransaction = { - .writeBuf = writeBuf, - .writeCount = writeCount, - .readBuf = readBuf, - .readCount = readCount, + I2C_Transaction i2c_transaction = { + .writeBuf = wbuf, + .writeCount = wcount, + .readBuf = rbuf, + .readCount = rcount, .slaveAddress = OPT_3001_I2C_ADDRESS, }; - return I2C_transfer(i2cHandle, &i2cTransaction); + return I2C_transfer(i2c_handle, &i2c_transaction); } -#define i2c_write(writeBuf, writeCount) i2c_write_read(writeBuf, writeCount, NULL, 0) -#define i2c_read(readBuf, readCount) i2c_write_read(NULL, 0, readBuf, readCount) +/** + * \brief Peform a write only I2C transaction. + * \param wbuf Output buffer during the I2C transation. + * \param wcount How many bytes in the wbuf. + * \return true if the I2C operation was successful; + * else, return false. + */ +static inline bool +i2c_write(void *wbuf, size_t wcount) +{ + return i2c_write_read(wbuf, wcount, NULL, 0); +} + +/** + * \brief Peform a read only I2C transaction. + * \param rbuf Input buffer during the I2C transation. + * \param rcount How many bytes to read into rbuf. + * \return true if the I2C operation was successful; + * else, return false. + */ +static inline bool +i2c_read(void *rbuf, size_t rcount) +{ + return i2c_write_read(NULL, 0, rbuf, rcount); +} /*---------------------------------------------------------------------------*/ +/** + * \brief Initialize the OPT-3001 sensor driver. + * \return true if I2C operation successful; else, return false. + */ static bool sensor_init(void) { - if (i2cHandle) { + if (i2c_handle) { return true; } - I2C_Params i2cParams; - I2C_Params_init(&i2cParams); - i2cParams.transferMode = I2C_MODE_BLOCKING; - i2cParams.bitRate = I2C_400kHz; + I2C_Params i2c_params; + I2C_Params_init(&i2c_params); - i2cHandle = I2C_open(Board_I2C0, &i2cParams); - if (i2cHandle == NULL) { + i2c_params.transferMode = I2C_MODE_BLOCKING; + i2c_params.bitRate = I2C_400kHz; + + i2c_handle = I2C_open(Board_I2C0, &i2c_params); + if (i2c_handle == NULL) { return false; } @@ -176,8 +216,8 @@ sensor_init(void) } /*---------------------------------------------------------------------------*/ /** - * \brief Turn the sensor on/off - * \param enable TRUE: on, FALSE: off + * \brief Turn the sensor on/off + * \param enable Enable sensor if true; else, disable sensor. */ static bool sensor_enable(bool enable) @@ -190,9 +230,15 @@ sensor_enable(bool enable) return i2c_write(cfg_data, sizeof(cfg_data)); } /*---------------------------------------------------------------------------*/ +/** + * \brief Callback when sensor is ready to read data from. + */ static void -notify_ready_cb(void *not_used) +notify_ready_cb(void *unused) { + /* Unused args */ + (void)unused; + /* * Depending on the CONFIGURATION.CONVERSION_TIME bits, a conversion will * take either 100 or 800 ms. Here we inspect the CONVERSION_READY bit and @@ -217,15 +263,18 @@ notify_ready_cb(void *not_used) } /*---------------------------------------------------------------------------*/ /** - * \brief Returns a reading from the sensor - * \param type Ignored - * \return Illuminance in centilux + * \brief Returns a reading from the sensor. + * \param type Ignored. + * \return Illuminance in centilux. */ static int value(int type) { + /* Unused args */ + (void)type; + if (opt_3001.status != OPT_3001_STATUS_DATA_READY) { - return MPU_9250_READING_ERROR; + return OPT_3001_READING_ERROR; } uint8_t cfg_data[] = { REG_CONFIGURATION }; @@ -234,7 +283,7 @@ value(int type) bool spi_ok = i2c_write_read(cfg_data, sizeof(cfg_data), &cfg_value, sizeof(cfg_value)); if (!spi_ok) { opt_3001.status = OPT_3001_STATUS_I2C_ERROR; - return MPU_9250_READING_ERROR; + return OPT_3001_READING_ERROR; } uint8_t result_data[] = { REG_RESULT }; @@ -243,7 +292,7 @@ value(int type) spi_ok = i2c_write_read(result_data, sizeof(result_data), &result_value, sizeof(result_value)); if (!spi_ok) { opt_3001.status = OPT_3001_STATUS_I2C_ERROR; - return MPU_9250_READING_ERROR; + return OPT_3001_READING_ERROR; } result_value = SWAP16(result_value); @@ -259,14 +308,13 @@ value(int type) } /*---------------------------------------------------------------------------*/ /** - * \brief Configuration function for the OPT3001 sensor. + * \brief Configuration function for the OPT3001 sensor. + * \param type Activate, enable or disable the sensor. See below. + * \param enable Enable or disable sensor. * - * \param type Activate, enable or disable the sensor. See below - * \param enable - * - * When type == SENSORS_HW_INIT we turn on the hardware - * When type == SENSORS_ACTIVE and enable==1 we enable the sensor - * When type == SENSORS_ACTIVE and enable==0 we disable the sensor + * When type == SENSORS_HW_INIT we turn on the hardware. + * When type == SENSORS_ACTIVE and enable==1 we enable the sensor. + * When type == SENSORS_ACTIVE and enable==0 we disable the sensor. */ static int configure(int type, int enable) @@ -278,7 +326,7 @@ configure(int type, int enable) opt_3001.status = OPT_3001_STATUS_STANDBY; } else { opt_3001.status = OPT_3001_STATUS_DISABLED; - rv = MPU_9250_READING_ERROR; + rv = OPT_3001_READING_ERROR; } break; @@ -302,13 +350,14 @@ configure(int type, int enable) } /*---------------------------------------------------------------------------*/ /** - * \brief Returns the status of the sensor - * \param type ignored - * \return The state of the sensor SENSOR_STATE_xyz + * \brief Returns the status of the sensor. + * \param type Ignored. + * \return The state of the sensor SENSOR_STATE_xyz. */ static int status(int type) { + /* Unused args */ (void)type; return opt_3001.status; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.h index 4b3a84a5a..06f6cca8b 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,39 +27,47 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup sensortag-cc26xx-peripherals + * \addtogroup sensortag-peripherals * @{ * - * \defgroup sensortag-cc26xx-opt-sensor SensorTag 2.0 Light Sensor + * \defgroup sensortag-opt-sensor SensorTag Optical Sensor * - * Due to the time required for the sensor to startup, this driver is meant to - * be used in an asynchronous fashion. The caller must first activate the - * sensor by calling SENSORS_ACTIVATE(). This will trigger the sensor's startup - * sequence, but the call will not wait for it to complete so that the CPU can - * perform other tasks or drop to a low power mode. + * Due to the time required for the sensor to startup, this driver is + * meant to be used in an asynchronous fashion. The caller must first + * activate the sensor by calling SENSORS_ACTIVATE(). This will trigger + * the sensor's startup sequence, but the call will not wait for it to + * complete so that the CPU can perform other tasks or drop to a low + * power mode. * - * Once the reading and conversion are complete, the driver will generate a - * sensors_changed event. + * Once the reading and conversion are complete, the driver will + * generate a sensors_changed event. * - * We use single-shot readings. In this mode, the hardware automatically goes - * back to its shutdown mode after the conversion is finished. However, it will - * still respond to I2C operations, so the last conversion can still be read - * out. + * We use single-shot readings. In this mode, the hardware + * automatically goes back to its shutdown mode after the conversion + * is finished. However, it will still respond to I2C operations, so + * the last conversion can still be read out. * - * In order to take a new reading, the caller has to use SENSORS_ACTIVATE - * again. + * In order to take a new reading, the caller has to use + * SENSORS_ACTIVATE again. * @{ * * \file - * Header file for the Sensortag Opt3001 light sensor + * Header file for the Sensortag OPT-3001 light sensor. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #ifndef OPT_3001_SENSOR_H_ #define OPT_3001_SENSOR_H_ /*---------------------------------------------------------------------------*/ -#define MPU_9250_READING_ERROR -1 +#include "contiki.h" +/*---------------------------------------------------------------------------*/ +#if (TI_I2C_CONF_ENABLE == 0) || (TI_I2C_CONF_I2C0_ENABLE == 0) +# error "The OPT-3001 requires the I2C driver (TI_I2C_CONF_ENABLE = 1)" +#endif +/*---------------------------------------------------------------------------*/ +#define OPT_3001_READING_ERROR -1 /*---------------------------------------------------------------------------*/ typedef enum { OPT_3001_STATUS_DISABLED, diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag-sensors.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag-sensors.c index fb7390e06..258f9f829 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag-sensors.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag-sensors.c @@ -27,13 +27,14 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup simplelink-peripherals + * \addtogroup sensortag-peripherals * @{ * * \file - * Generic module controlling Simplelink sensors + * Generic module controlling sensors on SensorTag. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #include "contiki.h" @@ -42,7 +43,6 @@ #include "board-peripherals.h" /*---------------------------------------------------------------------------*/ /* Exports a global symbol to be used by the sensor API */ -SENSORS(&bmp_280_sensor, &tmp_007_sensor, &opt_3001_sensor, &hdc_1000_sensor, - &mpu_9250_sensor); +SENSORS(&bmp_280_sensor, &tmp_007_sensor, &opt_3001_sensor, &hdc_1000_sensor, &mpu_9250_sensor); /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c index 3cc154a08..48c5ed5b9 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,21 +27,24 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup sensortag-cc26xx-tmp-sensor + * \addtogroup sensortag-tmp-sensor * @{ * * \file - * Driver for the Sensortag TI TMP007 infrared thermophile sensor + * Driver for the Sensortag TI TMP-007 IR Thermophile sensor. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "lib/sensors.h" #include "sys/ctimer.h" + #include "tmp-007-sensor.h" /*---------------------------------------------------------------------------*/ #include + #include #include /*---------------------------------------------------------------------------*/ @@ -58,47 +61,47 @@ /*---------------------------------------------------------------------------*/ /* Slave address */ #ifndef Board_TMP_ADDR -# error "Board file doesn't define I2C address Board_TMP_ADDR" +# error "Board file doesn't define I2C address Board_TMP_ADDR" #endif -#define TMP_007_I2C_ADDRESS Board_TMP_ADDR +#define TMP_007_I2C_ADDRESS Board_TMP_ADDR -/* MPU Interrupt pin */ +/* Sensor Interrupt pin */ #ifndef Board_TMP_RDY -# error "Board file doesn't define interrupt pin Board_TMP_RDY" +# error "Board file doesn't define interrupt pin Board_TMP_RDY" #endif -#define TMP_007_TMP_RDY Board_TMP_RDY +#define TMP_007_TMP_RDY Board_TMP_RDY /*---------------------------------------------------------------------------*/ -/* TMP007 register addresses */ -#define REG_VOLTAGE 0x00 -#define REG_LOCAL_TEMP 0x01 -#define REG_CONFIG 0x02 -#define REG_OBJ_TEMP 0x03 -#define REG_STATUS 0x04 -#define REG_PROD_ID 0x1F +/* TMP-007 register addresses */ +#define REG_VOLTAGE 0x00 +#define REG_LOCAL_TEMP 0x01 +#define REG_CONFIG 0x02 +#define REG_OBJ_TEMP 0x03 +#define REG_STATUS 0x04 +#define REG_PROD_ID 0x1F /*---------------------------------------------------------------------------*/ -/* TMP007 register values */ -#define VAL_CONFIG_ON 0x1000 /* Sensor on state */ -#define VAL_CONFIG_OFF 0x0000 /* Sensor off state */ -#define VAL_CONFIG_RESET 0x8000 -#define VAL_PROD_ID 0x0078 /* Product ID */ +/* TMP-007 register values */ +#define VAL_CONFIG_ON 0x1000 /**< Sensor on state */ +#define VAL_CONFIG_OFF 0x0000 /**< Sensor off state */ +#define VAL_CONFIG_RESET 0x8000 +#define VAL_PROD_ID 0x0078 /**< Product ID */ /*---------------------------------------------------------------------------*/ /* Conversion ready (status register) bit values */ -#define CONV_RDY_BIT 0x4000 +#define CONV_RDY_BIT 0x4000 /*---------------------------------------------------------------------------*/ /* Register length */ -#define REGISTER_LENGTH 2 +#define REGISTER_LENGTH 2 /*---------------------------------------------------------------------------*/ /* Sensor data size */ -#define DATA_SIZE 4 +#define DATA_SIZE 4 /*---------------------------------------------------------------------------*/ /* Byte swap of 16-bit register value */ -#define HI_UINT16(a) (((a) >> 8) & 0xFF) -#define LO_UINT16(a) ((a) & 0xFF) +#define HI_UINT16(a) (((a) >> 8) & 0xFF) +#define LO_UINT16(a) (((a) >> 0) & 0xFF) -#define SWAP16(v) ((LO_UINT16(v) << 8) | HI_UINT16(v)) +#define SWAP16(v) ((LO_UINT16(v) << 8) | (HI_UINT16(v) << 0)) -#define LSB16(v) (LO_UINT16(v)), (HI_UINT16(v)) -#define MSB16(v) (HI_UINT16(v)), (LO_UINT16(v)) +#define LSB16(v) (LO_UINT16(v)), (HI_UINT16(v)) +#define MSB16(v) (HI_UINT16(v)), (LO_UINT16(v)) /*---------------------------------------------------------------------------*/ static const PIN_Config pin_table[] = { TMP_007_TMP_RDY | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS | PIN_IRQ_NEGEDGE, @@ -120,27 +123,63 @@ typedef struct { static TMP_007_Object tmp_007; /*---------------------------------------------------------------------------*/ /* Wait SENSOR_STARTUP_DELAY clock ticks for the sensor to be ready - 275ms */ -#define SENSOR_STARTUP_DELAY 36 +#define SENSOR_STARTUP_DELAY 36 static struct ctimer startup_timer; /*---------------------------------------------------------------------------*/ +/** + * \brief Setup and peform an I2C transaction. + * \param wbuf Output buffer during the I2C transation. + * \param wcount How many bytes in the wbuf. + * \param rbuf Input buffer during the I2C transation. + * \param rcount How many bytes to read into rbuf. + * \return true if the I2C operation was successful; + * else, return false. + */ static bool -i2c_write_read(void *writeBuf, size_t writeCount, void *readBuf, size_t readCount) +i2c_write_read(void *wbuf, size_t wcount, void *rbuf, size_t rcount) { I2C_Transaction i2c_transaction = { - .writeBuf = writeBuf, - .writeCount = writeCount, - .readBuf = readBuf, - .readCount = readCount, + .writeBuf = wbuf, + .writeCount = wcount, + .readBuf = rbuf, + .readCount = rcount, .slaveAddress = TMP_007_I2C_ADDRESS, }; return I2C_transfer(i2c_handle, &i2c_transaction); } -#define i2c_write(writeBuf, writeCount) i2c_write_read(writeBuf, writeCount, NULL, 0) -#define i2c_read(readBuf, readCount) i2c_write_read(NULL, 0, readBuf, readCount) +/** + * \brief Peform a write only I2C transaction. + * \param wbuf Output buffer during the I2C transation. + * \param wcount How many bytes in the wbuf. + * \return true if the I2C operation was successful; + * else, return false. + */ +static inline bool +i2c_write(void *wbuf, size_t wcount) +{ + return i2c_write_read(wbuf, wcount, NULL, 0); +} + +/** + * \brief Peform a read only I2C transaction. + * \param rbuf Input buffer during the I2C transation. + * \param rcount How many bytes to read into rbuf. + * \return true if the I2C operation was successful; + * else, return false. + */ +static inline bool +i2c_read(void *rbuf, size_t rcount) +{ + return i2c_write_read(NULL, 0, rbuf, rcount); +} /*---------------------------------------------------------------------------*/ +/** + * \brief Initialize the TMP-007 sensor driver. + * \return true if I2C operation successful; else, return false. + */ static bool sensor_init(void) { @@ -155,6 +194,7 @@ sensor_init(void) I2C_Params i2c_params; I2C_Params_init(&i2c_params); + i2c_params.transferMode = I2C_MODE_BLOCKING; i2c_params.bitRate = I2C_400kHz; @@ -169,6 +209,9 @@ sensor_init(void) return true; } /*---------------------------------------------------------------------------*/ +/** + * \brief Callback when sensor is ready to read data from. + */ static void notify_ready_cb(void *not_used) { @@ -177,7 +220,7 @@ notify_ready_cb(void *not_used) } /*---------------------------------------------------------------------------*/ /** - * \brief Turn the sensor on/off + * \brief Turn the sensor on or off. */ static bool enable_sensor(bool enable) @@ -192,10 +235,12 @@ enable_sensor(bool enable) } /*---------------------------------------------------------------------------*/ /** - * \brief Read the sensor value registers - * \param raw_temp Temperature in 16 bit format - * \param raw_obj_temp object temperature in 16 bit format - * \return TRUE if valid data could be retrieved + * \brief Read the sensor value registers. + * \param raw_temp Output variable holding the Temperature in + * 16-bit format. + * \param raw_obj_temp Output variable holding the Object temperature in + * 16-bit format. + * \return true if valid data could be retrieved; else, false. */ static bool read_data(uint16_t *local_tmp, uint16_t *obj_tmp) @@ -241,11 +286,11 @@ read_data(uint16_t *local_tmp, uint16_t *obj_tmp) } /*---------------------------------------------------------------------------*/ /** - * \brief Convert raw data to values in degrees C - * \param raw_temp raw ambient temperature from sensor - * \param raw_obj_temp raw object temperature from sensor - * \param obj converted object temperature - * \param amb converted ambient temperature + * \brief Convert raw data to values in degrees Celsius. + * \param raw_temp Output variable holding the raw ambient temperature + * from sensor. + * \param raw_obj_temp Output variable holding the raw object temperature + * from sensor. */ static void convert(uint16_t* local_tmp, uint16_t* obj_tmp) @@ -261,9 +306,9 @@ convert(uint16_t* local_tmp, uint16_t* obj_tmp) } /*---------------------------------------------------------------------------*/ /** - * \brief Returns a reading from the sensor - * \param type TMP_007_SENSOR_TYPE_OBJECT or TMP_007_SENSOR_TYPE_AMBIENT - * \return Object or Ambient temperature in milli degrees C + * \brief Returns a reading from the sensor. + * \param type TMP_007_SENSOR_TYPE_OBJECT or TMP_007_SENSOR_TYPE_AMBIENT. + * \return Object or Ambient temperature in milli degrees Celsius. */ static int value(int type) @@ -304,14 +349,13 @@ value(int type) } /*---------------------------------------------------------------------------*/ /** - * \brief Configuration function for the TMP007 sensor. + * \brief Configuration function for the TMP-007 sensor. + * \param type Activate, enable or disable the sensor. See below. + * \param enable Enable or disable sensor. * - * \param type Activate, enable or disable the sensor. See below - * \param enable - * - * When type == SENSORS_HW_INIT we turn on the hardware - * When type == SENSORS_ACTIVE and enable==1 we enable the sensor - * When type == SENSORS_ACTIVE and enable==0 we disable the sensor + * When type == SENSORS_HW_INIT we turn on the hardware. + * When type == SENSORS_ACTIVE and enable==1 we enable the sensor. + * When type == SENSORS_ACTIVE and enable==0 we disable the sensor. */ static int configure(int type, int enable) @@ -351,9 +395,9 @@ configure(int type, int enable) } /*---------------------------------------------------------------------------*/ /** - * \brief Returns the status of the sensor - * \param type SENSORS_ACTIVE or SENSORS_READY - * \return 1 if the sensor is enabled + * \brief Returns the status of the sensor. + * \param type Ignored. + * \return Status of the sensor. */ static int status(int type) @@ -363,6 +407,6 @@ status(int type) return tmp_007.status; } /*---------------------------------------------------------------------------*/ -SENSORS_SENSOR(tmp_007_sensor, "TMP007", value, configure, status); +SENSORS_SENSOR(tmp_007_sensor, "TMP-007", value, configure, status); /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.h index 0ba8dcfcb..0fff84556 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,41 +27,51 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup sensortag-cc26xx-peripherals + * \addtogroup sensortag-peripherals * @{ * - * \defgroup sensortag-cc26xx-tmp-sensor SensorTag 2.0 IR thermophile sensor + * \defgroup sensortag-tmp-sensor SensorTag IR Thermophile sensor * - * Due to the time required for the sensor to startup, this driver is meant to - * be used in an asynchronous fashion. The caller must first activate the - * sensor by calling SENSORS_ACTIVATE(). This will trigger the sensor's startup - * sequence, but the call will not wait for it to complete so that the CPU can - * perform other tasks or drop to a low power mode. + * Due to the time required for the sensor to startup, this driver is + * meant to be used in an asynchronous fashion. The caller must first + * activate the sensor by calling SENSORS_ACTIVATE(). This will trigger + * the sensor's startup sequence, but the call will not wait for it to + * complete so that the CPU can perform other tasks or drop to a low + * power mode. * - * Once the sensor is stable, the driver will generate a sensors_changed event. + * Once the sensor is stable, the driver will generate a + * sensors_changed event. * - * The caller should then use value(TMP_007_SENSOR_TYPE_ALL) to read sensor - * values and latch them. Once completed successfully, individual readings can - * be retrieved with calls to value(TMP_007_SENSOR_TYPE_OBJECT) or - * value(TMP_007_SENSOR_TYPE_AMBIENT). + * The caller should then use value(TMP_007_SENSOR_TYPE_ALL) to + * read sensor values and latch them. Once completed successfully, + * individual readings can be retrieved with calls to + * value(TMP_007_SENSOR_TYPE_OBJECT) or + * value(TMP_007_SENSOR_TYPE_AMBIENT). * - * Once required readings have been taken, the caller has two options: - * - Turn the sensor off by calling SENSORS_DEACTIVATE, but in order to take - * subsequent readings SENSORS_ACTIVATE must be called again - * - Leave the sensor on. In this scenario, the caller can simply keep calling - * value(TMP_007_SENSOR_TYPE_ALL) to read and latch new values. However - * keeping the sensor on will consume more energy + * Once required readings have been taken, the caller has two options: + * - Turn the sensor off by calling SENSORS_DEACTIVATE, but in order + * to take subsequent readings SENSORS_ACTIVATE must be called again. + * - Leave the sensor on. In this scenario, the caller can simply keep + * calling value(TMP_007_SENSOR_TYPE_ALL) to read and latch new + * values. However keeping the sensor on will consume more energy. * @{ * * \file - * Header file for the Sensortag TI TMP007 infrared thermophile sensor + * Header file for the Sensortag TMP-007 IR Thermophile sensor. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #ifndef TMP_007_SENSOR_H_ #define TMP_007_SENSOR_H_ /*---------------------------------------------------------------------------*/ +#include "contiki.h" +/*---------------------------------------------------------------------------*/ +#if (TI_I2C_CONF_ENABLE == 0) || (TI_I2C_CONF_I2C0_ENABLE == 0) +# error "The BMP280 requires the I2C driver to be enabled (TI_I2C_CONF_ENABLE = 1)" +#endif +/*---------------------------------------------------------------------------*/ typedef enum { TMP_007_TYPE_OBJECT = (1 << 0), TMP_007_TYPE_AMBIENT = (1 << 1), diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/als-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/als-sensor.c index aa16dd2ae..d4a5bbb04 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/als-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/als-sensor.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, University of Bristol - http://www.bris.ac.uk/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,13 +27,14 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup srf06-common-peripherals + * \addtogroup srf06-peripherals * @{ * * \file - * Driver for the SmartRF06EB ALS when a CC13xx/CC26xxEM is mounted on it + * Driver for the SmartRF06 EB ALS sensor. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #include "contiki.h" @@ -42,11 +43,11 @@ #include "sys/timer.h" #include "als-sensor.h" - +/*---------------------------------------------------------------------------*/ #include #include - +/*---------------------------------------------------------------------------*/ #include /*---------------------------------------------------------------------------*/ static ADC_Handle adc_handle; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/als-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/als-sensor.h index 5d70478f8..dd9141fad 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/als-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/als-sensor.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, University of Bristol - http://www.bris.ac.uk/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,13 +27,14 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup srf06-common-peripherals + * \addtogroup srf06-peripherals * @{ * * \file - * Header file for the SmartRF06EB + CC13xx/CC26xxEM ALS Driver + * Header file for the SmartRF06 EB ALS sensor. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #ifndef ALS_SENSOR_H_ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/board-conf.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/board-conf.h index d0e612b2b..8fdb0895f 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/board-conf.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/board-conf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,27 +27,23 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ -/** \addtogroup cc26xx-srf-tag - * @{ - * - * \defgroup launchpad-peripherals LaunchPad peripherals - * - * Defines related to LaunchPad peripherals. - * +/** + * \addtogroup srf06-peripherals * @{ * * \file - * Header file with definitions related to LaunchPad peripherals - * - * \note Do not include this file directly. + * Header file with definitions related to SmartRF06 EB boards. + * \author + * Edvard Pettersen + * \note + * This file should not be included directly */ /*---------------------------------------------------------------------------*/ #ifndef BOARD_CONF_H_ #define BOARD_CONF_H_ /*---------------------------------------------------------------------------*/ /** - * \name LED configurations + * \name LED configurations for the dev/leds.h API. * * Those values are not meant to be modified by the user * @{ @@ -60,12 +56,29 @@ #define LEDS_CONF_ORANGE 3 #define LEDS_CONF_ALL ((1 << LEDS_CONF_COUNT) - 1) +/** @} */ /*---------------------------------------------------------------------------*/ +/** + * \name Button configurations for the dev/button-hal.h API. + * + * Those values are not meant to be modified by the user + * @{ + */ #define BUTTON_HAL_ID_KEY_LEFT 0 #define BUTTON_HAL_ID_KEY_RIGHT 1 #define BUTTON_HAL_ID_KEY_UP 2 #define BUTTON_HAL_ID_KEY_DOWN 3 #define BUTTON_HAL_ID_KEY_SELECT 4 +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \name SmartRF06 EB does have sensors. + * + * Those values are not meant to be modified by the user + * @{ + */ +#define BOARD_CONF_HAS_SENSORS 1 +/** @} */ /*---------------------------------------------------------------------------*/ #endif /* BOARD_CONF_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/board-peripherals.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/board-peripherals.h index c76057d59..5a30b5fe1 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/board-peripherals.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/board-peripherals.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,20 +27,22 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ -/** \addtogroup cc26xx-srf-tag +/** + * \addtogroup cc13xx-cc26xx-platform * @{ * - * \defgroup launchpad-peripherals LaunchPad peripherals + * \defgroup srf06-peripherals SmartRF06 Evaluation Board peripherals * - * Defines related to LaunchPad peripherals. + * Defines related to configuring SmartRF06 EB's peripherals. All + * SmartRF06 EBs are identical to a very large extent. Everything + * documented within this group applies to all SmartRF06 EBs. * * @{ * * \file - * Header file with definitions related to LaunchPad peripherals - * - * \note Do not include this file directly. + * Header file with definitions related to SmartRF06 EB boards. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #ifndef BOARD_PERIPHERALS_H_ @@ -50,8 +52,6 @@ /*---------------------------------------------------------------------------*/ #include "board-conf.h" /*---------------------------------------------------------------------------*/ -#define BOARD_CONF_HAS_SENSORS 1 -/*---------------------------------------------------------------------------*/ #endif /* BOARD_PERIPHERALS_H_ */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor-arch.c index a0cea3b1c..7c1f04df0 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor-arch.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/button-sensor-arch.c @@ -27,64 +27,71 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup launchpad-button-sensor + * \addtogroup srf06-peripherals * @{ * * \file - * Driver for LaunchPad buttons + * Button HAL definitions for the SmartRF06 Evaluation Board's buttons. + * Common across all CC13xx/CC26xx devices on SmartRF06 EB. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "dev/button-hal.h" - +/*---------------------------------------------------------------------------*/ #include /*---------------------------------------------------------------------------*/ /* Key select button */ -BUTTON_HAL_BUTTON(key_select, /**< Name */ - "Key Select", /**< Description */ - Board_KEY_SELECT, /**< PIN */ - GPIO_HAL_PIN_CFG_INPUT_PULLUP | - GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ - BUTTON_HAL_ID_KEY_SELECT, /**< Unique ID */ - true); /**< Negative logic */ +BUTTON_HAL_BUTTON( + key_select, /**< Name */ + "Key Select", /**< Description */ + Board_KEY_SELECT, /**< PIN */ + GPIO_HAL_PIN_CFG_INPUT_PULLUP | + GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_KEY_SELECT, /**< Unique ID */ + true); /**< Negative logic */ /* Key up button */ -BUTTON_HAL_BUTTON(key_up, /**< Name */ - "Key Up", /**< Description */ - Board_KEY_UP, /**< PIN */ - GPIO_HAL_PIN_CFG_INPUT_PULLUP | - GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ - BUTTON_HAL_ID_KEY_UP, /**< Unique ID */ - true); /**< Negative logic */ +BUTTON_HAL_BUTTON( + key_up, /**< Name */ + "Key Up", /**< Description */ + Board_KEY_UP, /**< PIN */ + GPIO_HAL_PIN_CFG_INPUT_PULLUP | + GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_KEY_UP, /**< Unique ID */ + true); /**< Negative logic */ /* Key down button */ -BUTTON_HAL_BUTTON(key_down, /**< Name */ - "Key Down", /**< Description */ - Board_KEY_DOWN, /**< PIN */ - GPIO_HAL_PIN_CFG_INPUT_PULLUP | - GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ - BUTTON_HAL_ID_KEY_DOWN, /**< Unique ID */ - true); /**< Negative logic */ +BUTTON_HAL_BUTTON( + key_down, /**< Name */ + "Key Down", /**< Description */ + Board_KEY_DOWN, /**< PIN */ + GPIO_HAL_PIN_CFG_INPUT_PULLUP | + GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_KEY_DOWN, /**< Unique ID */ + true); /**< Negative logic */ /* Key left button */ -BUTTON_HAL_BUTTON(key_left, /**< Name */ - "Key Left", /**< Description */ - Board_KEY_LEFT, /**< PIN */ - GPIO_HAL_PIN_CFG_INPUT_PULLUP | - GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ - BUTTON_HAL_ID_KEY_LEFT, /**< Unique ID */ - true); /**< Negative logic */ +BUTTON_HAL_BUTTON( + key_left, /**< Name */ + "Key Left", /**< Description */ + Board_KEY_LEFT, /**< PIN */ + GPIO_HAL_PIN_CFG_INPUT_PULLUP | + GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_KEY_LEFT, /**< Unique ID */ + true); /**< Negative logic */ /* Key right button */ -BUTTON_HAL_BUTTON(key_right, /**< Name */ - "Key Right", /**< Description */ - Board_KEY_RIGHT, /**< PIN */ - GPIO_HAL_PIN_CFG_INPUT_PULLUP | - GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ - BUTTON_HAL_ID_KEY_RIGHT, /**< Unique ID */ - true); /**< Negative logic */ +BUTTON_HAL_BUTTON( + key_right, /**< Name */ + "Key Right", /**< Description */ + Board_KEY_RIGHT, /**< PIN */ + GPIO_HAL_PIN_CFG_INPUT_PULLUP | + GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS, /**< Pull configuration */ + BUTTON_HAL_ID_KEY_RIGHT, /**< Unique ID */ + true); /**< Negative logic */ /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTONS(&key_select, &key_up, &key_down, &key_left, &key_right); /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c index 00cb5d8e0..3214b385a 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c @@ -175,19 +175,21 @@ const CryptoCC26XX_Config CryptoCC26XX_config[CC1350DK_7XD_CRYPTOCOUNT] = { #include #include +#if TI_DISPLAY_CONF_ENABLE + +#if TI_DISPLAY_CONF_UART_ENABLE + +#if !(TI_UART_CONF_UART0_ENABLE) +#error "Display UART driver requires UART0" +#endif + #ifndef BOARD_DISPLAY_UART_STRBUF_SIZE #define BOARD_DISPLAY_UART_STRBUF_SIZE 128 #endif -#ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 -#endif +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; DisplayUart_Object displayUartObject; -DisplaySharp_Object displaySharpObject; - -static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; -static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; const DisplayUart_HWAttrs displayUartHWAttrs = { .uartIdx = CC1350DK_7XD_UART0, @@ -197,6 +199,22 @@ const DisplayUart_HWAttrs displayUartHWAttrs = { .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, }; +#endif /* TI_DISPLAY_CONF_UART_ENABLE */ + +#if TI_DISPLAY_CONF_LCD_ENABLE + +#if !(TI_SPI_CONF_SPI0_ENABLE) +#error "Display LCD driver requires SPI0" +#endif + +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 +#endif + +static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; + +DisplaySharp_Object displaySharpObject; + const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .spiIndex = CC1350DK_7XD_SPI0, .csPin = CC1350DK_7XD_GPIO_LCD_CS, @@ -207,27 +225,18 @@ const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .displayBuf = sharpDisplayBuf, }; -#ifndef BOARD_DISPLAY_USE_UART -#define BOARD_DISPLAY_USE_UART 1 -#endif -#ifndef BOARD_DISPLAY_USE_UART_ANSI -#define BOARD_DISPLAY_USE_UART_ANSI 0 -#endif -#ifndef BOARD_DISPLAY_USE_LCD -#define BOARD_DISPLAY_USE_LCD 0 -#endif +#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ /* * This #if/#else is needed to workaround a problem with the * IAR compiler. The IAR compiler doesn't like the empty array * initialization. (IAR Error[Pe1345]) */ -#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) const Display_Config Display_config[] = { -#if (BOARD_DISPLAY_USE_UART) +#if TI_DISPLAY_CONF_UART_ENABLE { -# if (BOARD_DISPLAY_USE_UART_ANSI) +# if TI_DISPLAY_CONF_USE_UART_ANSI .fxnTablePtr = &DisplayUartAnsi_fxnTable, # else /* Default to minimal UART with no cursor placement */ .fxnTablePtr = &DisplayUartMin_fxnTable, @@ -236,7 +245,7 @@ const Display_Config Display_config[] = { .hwAttrs = &displayUartHWAttrs, }, #endif -#if (BOARD_DISPLAY_USE_LCD) +#if TI_DISPLAY_CONF_LCD_ENABLE { .fxnTablePtr = &DisplaySharp_fxnTable, .object = &displaySharpObject, @@ -252,7 +261,7 @@ const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Conf const Display_Config *Display_config = NULL; const uint_least8_t Display_count = 0; -#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ +#endif /* TI_DISPLAY_CONF_ENABLE */ /* * =============================== GPIO =============================== @@ -356,9 +365,12 @@ const GPTimerCC26XX_Config GPTimerCC26XX_config[CC1350DK_7XD_GPTIMERPARTSCOUNT] #include #include +#if TI_I2C_CONF_ENABLE + I2CCC26XX_Object i2cCC26xxObjects[CC1350DK_7XD_I2CCOUNT]; const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1350DK_7XD_I2CCOUNT] = { +#if TI_I2C_CONF_I2C0_ENABLE { .baseAddr = I2C0_BASE, .powerMngrId = PowerCC26XX_PERIPH_I2C0, @@ -367,19 +379,24 @@ const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1350DK_7XD_I2CCOUNT] = { .swiPriority = 0, .sdaPin = CC1350DK_7XD_I2C0_SDA0, .sclPin = CC1350DK_7XD_I2C0_SCL0, - } + }, +#endif }; const I2C_Config I2C_config[CC1350DK_7XD_I2CCOUNT] = { +#if TI_I2C_CONF_I2C0_ENABLE { .fxnTablePtr = &I2CCC26XX_fxnTable, .object = &i2cCC26xxObjects[CC1350DK_7XD_I2C0], .hwAttrs = &i2cCC26xxHWAttrs[CC1350DK_7XD_I2C0] }, +#endif }; const uint_least8_t I2C_count = CC1350DK_7XD_I2CCOUNT; +#endif /* TI_I2C_CONF_ENABLE */ + /* * =============================== NVS =============================== */ @@ -391,8 +408,9 @@ const uint_least8_t I2C_count = CC1350DK_7XD_I2CCOUNT; #define SECTORSIZE 0x1000 #define REGIONSIZE (SECTORSIZE * 4) -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_ENABLE +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE /* * Reserve flash sectors for NVS driver use by placing an uninitialized byte * array at the desired flash address. @@ -441,11 +459,11 @@ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { }, }; -#endif /* Board_EXCLUDE_NVS_INTERNAL_FLASH */ +#endif /* TI_NVS_CONF_NVS_INTERNAL_ENABLE */ /* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ const NVS_Config NVS_config[CC1350DK_7XD_NVSCOUNT] = { -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE { .fxnTablePtr = &NVSCC26XX_fxnTable, .object = &nvsCC26xxObjects[0], @@ -456,6 +474,8 @@ const NVS_Config NVS_config[CC1350DK_7XD_NVSCOUNT] = { const uint_least8_t NVS_count = CC1350DK_7XD_NVSCOUNT; +#endif /* TI_NVS_CONF_ENABLE */ + /* * =============================== PIN =============================== */ @@ -557,6 +577,12 @@ const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { #include #include +#if TI_SD_CONF_ENABLE + +#if !(TI_SPI_CONF_SPI0_ENABLE) +#error "SD driver requires SPI0 enabled" +#endif + SDSPI_Object sdspiObjects[CC1350DK_7XD_SDCOUNT]; const SDSPI_HWAttrs sdspiHWAttrs[CC1350DK_7XD_SDCOUNT] = { @@ -576,12 +602,16 @@ const SD_Config SD_config[CC1350DK_7XD_SDCOUNT] = { const uint_least8_t SD_count = CC1350DK_7XD_SDCOUNT; +#endif /* TI_SD_CONF_ENABLE */ + /* * =============================== SPI DMA =============================== */ #include #include +#if TI_SPI_CONF_ENABLE + SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1350DK_7XD_SPICOUNT]; /* @@ -590,6 +620,7 @@ SPICC26XXDMA_Object spiCC26XXDMAObjects[CC1350DK_7XD_SPICOUNT]; * to satisfy the SDSPI driver requirement. */ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1350DK_7XD_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .baseAddr = SSI0_BASE, .intNum = INT_SSI0_COMB, @@ -605,6 +636,8 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1350DK_7XD_SPICOUNT] = { .csnPin = CC1350DK_7XD_SPI0_CSN, .minDmaTransferSize = 10 }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .baseAddr = SSI1_BASE, .intNum = INT_SSI1_COMB, @@ -619,35 +652,45 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC1350DK_7XD_SPICOUNT] = { .clkPin = CC1350DK_7XD_SPI1_CLK, .csnPin = CC1350DK_7XD_SPI1_CSN, .minDmaTransferSize = 10 - } + }, +#endif }; const SPI_Config SPI_config[CC1350DK_7XD_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC1350DK_7XD_SPI0], .hwAttrs = &spiCC26XXDMAHWAttrs[CC1350DK_7XD_SPI0] }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC1350DK_7XD_SPI1], .hwAttrs = &spiCC26XXDMAHWAttrs[CC1350DK_7XD_SPI1] }, +#endif }; const uint_least8_t SPI_count = CC1350DK_7XD_SPICOUNT; +#endif /* TI_SPI_CONF_ENABLE */ + /* * =============================== UART =============================== */ #include #include +#if TI_UART_CONF_ENABLE + UARTCC26XX_Object uartCC26XXObjects[CC1350DK_7XD_UARTCOUNT]; uint8_t uartCC26XXRingBuffer[CC1350DK_7XD_UARTCOUNT][32]; const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1350DK_7XD_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .baseAddr = UART0_BASE, .powerMngrId = PowerCC26XX_PERIPH_UART0, @@ -663,19 +706,24 @@ const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC1350DK_7XD_UARTCOUNT] = { .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, .errorFxn = NULL - } + }, +#endif }; const UART_Config UART_config[CC1350DK_7XD_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .fxnTablePtr = &UARTCC26XX_fxnTable, .object = &uartCC26XXObjects[CC1350DK_7XD_UART0], .hwAttrs = &uartCC26XXHWAttrs[CC1350DK_7XD_UART0] }, +#endif }; const uint_least8_t UART_count = CC1350DK_7XD_UARTCOUNT; +#endif /* TI_UART_CONF_ENABLE */ + /* * =============================== UDMA =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h index b6fa91497..f90681dbf 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h @@ -49,6 +49,8 @@ extern "C" { #endif +#include "contiki-conf.h" + /* Includes */ #include #include @@ -275,7 +277,9 @@ typedef enum CC1350DK_7XD_GPTimers { * @brief Enum of I2C names */ typedef enum CC1350DK_7XD_I2CName { +#if TI_I2C_CONF_I2C0_ENABLE CC1350DK_7XD_I2C0 = 0, +#endif CC1350DK_7XD_I2CCOUNT } CC1350DK_7XD_I2CName; @@ -285,7 +289,7 @@ typedef enum CC1350DK_7XD_I2CName { * @brief Enum of NVS names */ typedef enum CC1350DK_7XD_NVSName { -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE CC1350DK_7XD_NVSCC26XX0 = 0, #endif @@ -324,8 +328,12 @@ typedef enum CC1350DK_7XD_SDName { * @brief Enum of SPI names */ typedef enum CC1350DK_7XD_SPIName { +#if TI_SPI_CONF_SPI0_ENABLE CC1350DK_7XD_SPI0 = 0, +#endif +#if TI_SPI_CONF_SPI1_ENABLE CC1350DK_7XD_SPI1, +#endif CC1350DK_7XD_SPICOUNT } CC1350DK_7XD_SPIName; @@ -335,7 +343,9 @@ typedef enum CC1350DK_7XD_SPIName { * @brief Enum of UARTs */ typedef enum CC1350DK_7XD_UARTName { +#if TI_UART_CONF_UART0_ENABLE CC1350DK_7XD_UART0 = 0, +#endif CC1350DK_7XD_UARTCOUNT } CC1350DK_7XD_UARTName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 index f79529781..a06b790a6 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 @@ -5,7 +5,7 @@ SUBFAMILY = cc13x0-cc26x0 DEVICE_FAMILY = CC13X0 DEVICE_LINE = CC13XX -BOARD_SOURCEFILES += CC1310DK_7XD.c CC1310DK_7XD_fxns.c +BOARD_SOURCEFILES += CC1350DK_7XD.c CC1350DK_7XD_fxns.c SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c index 51df6137c..52e27a7a7 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c @@ -175,19 +175,21 @@ const CryptoCC26XX_Config CryptoCC26XX_config[CC2650DK_7ID_CRYPTOCOUNT] = { #include #include +#if TI_DISPLAY_CONF_ENABLE + +#if TI_DISPLAY_CONF_UART_ENABLE + +#if !(TI_UART_CONF_UART0_ENABLE) +#error "Display UART driver requires UART0" +#endif + #ifndef BOARD_DISPLAY_UART_STRBUF_SIZE #define BOARD_DISPLAY_UART_STRBUF_SIZE 128 #endif -#ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 -#endif +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; DisplayUart_Object displayUartObject; -DisplaySharp_Object displaySharpObject; - -static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; -static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; const DisplayUart_HWAttrs displayUartHWAttrs = { .uartIdx = CC2650DK_7ID_UART0, @@ -197,6 +199,22 @@ const DisplayUart_HWAttrs displayUartHWAttrs = { .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, }; +#endif /* TI_DISPLAY_CONF_UART_ENABLE */ + +#if TI_DISPLAY_CONF_LCD_ENABLE + +#if !(TI_SPI_CONF_SPI0_ENABLE) +#error "Display LCD driver requires SPI0" +#endif + +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 +#endif + +static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; + +DisplaySharp_Object displaySharpObject; + const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .spiIndex = CC2650DK_7ID_SPI0, .csPin = CC2650DK_7ID_GPIO_LCD_CS, @@ -207,27 +225,18 @@ const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { .displayBuf = sharpDisplayBuf, }; -#ifndef BOARD_DISPLAY_USE_UART -#define BOARD_DISPLAY_USE_UART 1 -#endif -#ifndef BOARD_DISPLAY_USE_UART_ANSI -#define BOARD_DISPLAY_USE_UART_ANSI 0 -#endif -#ifndef BOARD_DISPLAY_USE_LCD -#define BOARD_DISPLAY_USE_LCD 0 -#endif +#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ /* * This #if/#else is needed to workaround a problem with the * IAR compiler. The IAR compiler doesn't like the empty array * initialization. (IAR Error[Pe1345]) */ -#if (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) const Display_Config Display_config[] = { -#if (BOARD_DISPLAY_USE_UART) +#if TI_DISPLAY_CONF_UART_ENABLE { -# if (BOARD_DISPLAY_USE_UART_ANSI) +# if TI_DISPLAY_CONF_USE_UART_ANSI .fxnTablePtr = &DisplayUartAnsi_fxnTable, # else /* Default to minimal UART with no cursor placement */ .fxnTablePtr = &DisplayUartMin_fxnTable, @@ -236,7 +245,7 @@ const Display_Config Display_config[] = { .hwAttrs = &displayUartHWAttrs, }, #endif -#if (BOARD_DISPLAY_USE_LCD) +#if TI_DISPLAY_CONF_LCD_ENABLE { .fxnTablePtr = &DisplaySharp_fxnTable, .object = &displaySharpObject, @@ -252,7 +261,7 @@ const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Conf const Display_Config *Display_config = NULL; const uint_least8_t Display_count = 0; -#endif /* (BOARD_DISPLAY_USE_UART || BOARD_DISPLAY_USE_LCD) */ +#endif /* TI_DISPLAY_CONF_ENABLE */ /* * =============================== GPIO =============================== @@ -356,9 +365,12 @@ const GPTimerCC26XX_Config GPTimerCC26XX_config[CC2650DK_7ID_GPTIMERPARTSCOUNT] #include #include +#if TI_I2C_CONF_ENABLE + I2CCC26XX_Object i2cCC26xxObjects[CC2650DK_7ID_I2CCOUNT]; const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC2650DK_7ID_I2CCOUNT] = { +#if TI_I2C_CONF_I2C0_ENABLE { .baseAddr = I2C0_BASE, .powerMngrId = PowerCC26XX_PERIPH_I2C0, @@ -367,19 +379,24 @@ const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC2650DK_7ID_I2CCOUNT] = { .swiPriority = 0, .sdaPin = CC2650DK_7ID_I2C0_SDA0, .sclPin = CC2650DK_7ID_I2C0_SCL0, - } + }, +#endif }; const I2C_Config I2C_config[CC2650DK_7ID_I2CCOUNT] = { +#if TI_I2C_CONF_I2C0_ENABLE { .fxnTablePtr = &I2CCC26XX_fxnTable, .object = &i2cCC26xxObjects[CC2650DK_7ID_I2C0], .hwAttrs = &i2cCC26xxHWAttrs[CC2650DK_7ID_I2C0] }, +#endif }; const uint_least8_t I2C_count = CC2650DK_7ID_I2CCOUNT; +#endif /* TI_I2C_CONF_ENABLE */ + /* * =============================== NVS =============================== */ @@ -391,7 +408,9 @@ const uint_least8_t I2C_count = CC2650DK_7ID_I2CCOUNT; #define SECTORSIZE 0x1000 #define REGIONSIZE (SECTORSIZE * 4) -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_ENABLE + +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE /* * Reserve flash sectors for NVS driver use by placing an uninitialized byte @@ -441,11 +460,11 @@ const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[1] = { }, }; -#endif /* Board_EXCLUDE_NVS_INTERNAL_FLASH */ +#endif /* TI_NVS_CONF_NVS_INTERNAL_ENABLE */ /* NVS Region index 0 and 1 refer to NVS and NVS SPI respectively */ const NVS_Config NVS_config[CC2650DK_7ID_NVSCOUNT] = { -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE { .fxnTablePtr = &NVSCC26XX_fxnTable, .object = &nvsCC26xxObjects[0], @@ -456,6 +475,8 @@ const NVS_Config NVS_config[CC2650DK_7ID_NVSCOUNT] = { const uint_least8_t NVS_count = CC2650DK_7ID_NVSCOUNT; +#endif /* TI_NVS_CONF_ENABLE */ + /* * =============================== PIN =============================== */ @@ -557,6 +578,12 @@ const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = { #include #include +#if TI_SD_CONF_ENABLE + +#if !(TI_SPI_CONF_SPI0_ENABLE) +#error "SD driver requires SPI0 enabled" +#endif + SDSPI_Object sdspiObjects[CC2650DK_7ID_SDCOUNT]; const SDSPI_HWAttrs sdspiHWAttrs[CC2650DK_7ID_SDCOUNT] = { @@ -576,12 +603,16 @@ const SD_Config SD_config[CC2650DK_7ID_SDCOUNT] = { const uint_least8_t SD_count = CC2650DK_7ID_SDCOUNT; +#endif /* TI_SD_CONF_ENABLE */ + /* * =============================== SPI DMA =============================== */ #include #include +#if TI_SPI_CONF_ENABLE + SPICC26XXDMA_Object spiCC26XXDMAObjects[CC2650DK_7ID_SPICOUNT]; /* @@ -590,6 +621,7 @@ SPICC26XXDMA_Object spiCC26XXDMAObjects[CC2650DK_7ID_SPICOUNT]; * to satisfy the SDSPI driver requirement. */ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC2650DK_7ID_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .baseAddr = SSI0_BASE, .intNum = INT_SSI0_COMB, @@ -605,6 +637,8 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC2650DK_7ID_SPICOUNT] = { .csnPin = CC2650DK_7ID_SPI0_CSN, .minDmaTransferSize = 10 }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .baseAddr = SSI1_BASE, .intNum = INT_SSI1_COMB, @@ -619,35 +653,45 @@ const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC2650DK_7ID_SPICOUNT] = { .clkPin = CC2650DK_7ID_SPI1_CLK, .csnPin = CC2650DK_7ID_SPI1_CSN, .minDmaTransferSize = 10 - } + }, +#endif }; const SPI_Config SPI_config[CC2650DK_7ID_SPICOUNT] = { +#if TI_SPI_CONF_SPI0_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC2650DK_7ID_SPI0], .hwAttrs = &spiCC26XXDMAHWAttrs[CC2650DK_7ID_SPI0] }, +#endif +#if TI_SPI_CONF_SPI1_ENABLE { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC2650DK_7ID_SPI1], .hwAttrs = &spiCC26XXDMAHWAttrs[CC2650DK_7ID_SPI1] }, +#endif }; const uint_least8_t SPI_count = CC2650DK_7ID_SPICOUNT; +#endif /* TI_SPI_CONF_ENABLE */ + /* * =============================== UART =============================== */ #include #include +#if TI_UART_CONF_ENABLE + UARTCC26XX_Object uartCC26XXObjects[CC2650DK_7ID_UARTCOUNT]; uint8_t uartCC26XXRingBuffer[CC2650DK_7ID_UARTCOUNT][32]; const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC2650DK_7ID_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .baseAddr = UART0_BASE, .powerMngrId = PowerCC26XX_PERIPH_UART0, @@ -663,19 +707,24 @@ const UARTCC26XX_HWAttrsV2 uartCC26XXHWAttrs[CC2650DK_7ID_UARTCOUNT] = { .txIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_1_8, .rxIntFifoThr = UARTCC26XX_FIFO_THRESHOLD_4_8, .errorFxn = NULL - } + }, +#endif }; const UART_Config UART_config[CC2650DK_7ID_UARTCOUNT] = { +#if TI_UART_CONF_UART0_ENABLE { .fxnTablePtr = &UARTCC26XX_fxnTable, .object = &uartCC26XXObjects[CC2650DK_7ID_UART0], .hwAttrs = &uartCC26XXHWAttrs[CC2650DK_7ID_UART0] }, +#endif }; const uint_least8_t UART_count = CC2650DK_7ID_UARTCOUNT; +#endif /* TI_UART_CONF_ENABLE */ + /* * =============================== UDMA =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h index 3b2017de9..bde1ff107 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h @@ -49,6 +49,8 @@ extern "C" { #endif +#include "contiki-conf.h" + /* Includes */ #include #include @@ -275,7 +277,9 @@ typedef enum CC2650DK_7ID_GPTimers { * @brief Enum of I2C names */ typedef enum CC2650DK_7ID_I2CName { +#if TI_I2C_CONF_I2C0_ENABLE CC2650DK_7ID_I2C0 = 0, +#endif CC2650DK_7ID_I2CCOUNT } CC2650DK_7ID_I2CName; @@ -285,7 +289,7 @@ typedef enum CC2650DK_7ID_I2CName { * @brief Enum of NVS names */ typedef enum CC2650DK_7ID_NVSName { -#ifndef Board_EXCLUDE_NVS_INTERNAL_FLASH +#if TI_NVS_CONF_NVS_INTERNAL_ENABLE CC2650DK_7ID_NVSCC26XX0 = 0, #endif @@ -324,8 +328,12 @@ typedef enum CC2650DK_7ID_SDName { * @brief Enum of SPI names */ typedef enum CC2650DK_7ID_SPIName { +#if TI_SPI_CONF_SPI0_ENABLE CC2650DK_7ID_SPI0 = 0, +#endif +#if TI_SPI_CONF_SPI1_ENABLE CC2650DK_7ID_SPI1, +#endif CC2650DK_7ID_SPICOUNT } CC2650DK_7ID_SPIName; @@ -335,7 +343,9 @@ typedef enum CC2650DK_7ID_SPIName { * @brief Enum of UARTs */ typedef enum CC2650DK_7ID_UARTName { +#if TI_UART_CONF_UART0_ENABLE CC2650DK_7ID_UART0 = 0, +#endif CC2650DK_7ID_UARTCOUNT } CC2650DK_7ID_UARTName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/leds-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/leds-arch.c index e5eae9d0f..23f1e1b53 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/leds-arch.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/leds-arch.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,27 +27,32 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup simplelink-platform + * \addtogroup srf06-peripherals * @{ * * \file - * Driver for LaunchPad LEDs + * LED HAL definitions for the SmartRF06 Evaluation Board's LEDs. + * Common across all CC13xx/CC26xx devices for the SmartRF06 EB. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ -/* Contiki API */ #include "contiki.h" #include "dev/leds.h" - +/*---------------------------------------------------------------------------*/ #include - +/*---------------------------------------------------------------------------*/ #include /*---------------------------------------------------------------------------*/ const leds_t leds_arch_leds[] = { + /* Red LED, AKA LED0 */ { .pin = Board_PIN_LED0, .negative_logic = false }, + /* Yellow LED, AKA LED1 */ { .pin = Board_PIN_LED1, .negative_logic = false }, + /* Green LED, AKA LED2 */ { .pin = Board_PIN_LED2, .negative_logic = false }, + /* Red-orange LED, AKA LED3 */ { .pin = Board_PIN_LED3, .negative_logic = false }, }; /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/srf06-sensors.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/srf06-sensors.c index 7e4468cbd..2bb2aee67 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/srf06-sensors.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/srf06-sensors.c @@ -27,13 +27,14 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup simplelink-peripherals + * \addtogroup srf06-peripherals * @{ * * \file - * Generic module controlling Simplelink sensors + * Generic module controlling sensors on SmartRF06 Evaluation Board. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #include "contiki.h" From 5f8727a6ba123c174f271513a481c89b880787ab Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Tue, 17 Jul 2018 07:59:37 +0200 Subject: [PATCH 270/485] Added missing include for sensortag board-conf --- arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h index 4a1822e82..eec9423ab 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h @@ -50,6 +50,8 @@ #ifndef BOARD_CONF_H_ #define BOARD_CONF_H_ /*---------------------------------------------------------------------------*/ +#include "leds-arch.h" +/*---------------------------------------------------------------------------*/ /** * \name Button configurations for the dev/button-hal.h API. * From 178bafad2eb9148a5d68f8e5f31274284b2f8179 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Tue, 17 Jul 2018 08:01:41 +0200 Subject: [PATCH 271/485] Fixed RX buf restart, and fixed RF prop settings include --- arch/cpu/cc13xx-cc26xx/dev/rf-core.c | 2 ++ arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-core.c b/arch/cpu/cc13xx-cc26xx/dev/rf-core.c index d9f6cf928..ebe34effa 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-core.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-core.c @@ -512,6 +512,8 @@ PROCESS_THREAD(rf_core_process, ev, data) if (rx_buf_full) { PRINTF("rf_core: RX buf full, restart RX\n"); rx_buf_full = false; + /* Restart RX */ + netstack_stop_rx(); netstack_sched_rx(); } diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c index 4758e01ce..490459292 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c @@ -60,7 +60,7 @@ #include "rf-core.h" #include "rf-data-queue.h" #include "netstack-settings.h" -#include RF_CORE_PROP_RF_SETTINGS +#include RF_PROP_SETTINGS /*---------------------------------------------------------------------------*/ #include #include From de0197d71fb3a7c8e232f263a30d50e30ef82104 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Tue, 17 Jul 2018 18:01:49 +0200 Subject: [PATCH 272/485] Normalized TX power settings --- .../rf-settings/cc13x0/ieee-settings.c | 18 +- .../rf-settings/cc13x0/ieee-settings.h | 11 +- .../rf-settings/cc13x0/prop-settings.c | 143 ++++++++- .../rf-settings/cc13x0/prop-settings.h | 11 +- .../rf-settings/cc13x2/ieee-settings.c | 161 ++++++++-- .../rf-settings/cc13x2/ieee-settings.h | 14 +- .../rf-settings/cc13x2/prop-settings.c | 284 ++++++++++++++---- .../rf-settings/cc13x2/prop-settings.h | 14 +- .../rf-settings/cc26x0/ieee-settings.c | 17 +- .../rf-settings/cc26x0/ieee-settings.h | 11 +- .../rf-settings/cc26x2/ieee-settings.c | 17 +- .../rf-settings/cc26x2/ieee-settings.h | 12 +- .../cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 1 + .../launchpad/cc1310/Makefile.cc1310 | 5 +- .../launchpad/cc1312r1/Makefile.cc1312r1 | 8 +- .../launchpad/cc1350-4/Makefile.cc1350-4 | 5 +- .../launchpad/cc1350/Makefile.cc1350 | 5 +- .../launchpad/cc1352p-2/Makefile.cc1352p-2 | 11 +- .../launchpad/cc1352p-4/Makefile.cc1352p-4 | 11 +- .../launchpad/cc1352p1/Makefile.cc1352p1 | 11 +- .../launchpad/cc1352r1/Makefile.cc1352r1 | 11 +- .../launchpad/cc2650/Makefile.cc2650 | 5 +- .../launchpad/cc26x2r1/Makefile.cc26x2r1 | 5 +- .../sensortag/cc1350/Makefile.cc1350 | 5 +- .../sensortag/cc2650/Makefile.cc2650 | 5 +- .../srf06/cc13x0/Makefile.cc13x0 | 5 +- .../srf06/cc26x0/Makefile.cc26x0 | 5 +- 27 files changed, 616 insertions(+), 195 deletions(-) diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c index d51fec78c..d903a4c4c 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c @@ -70,7 +70,7 @@ RF_Mode rf_ieee_mode = * See the Technical Reference Manual for further details about the "txPower" Command field. * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. */ -RF_TxPowerTable_Entry rf_ieee_tx_power_table[RF_IEEE_TX_POWER_TABLE_SIZE+1] = +RF_TxPowerTable_Entry rf_ieee_tx_power_table[] = { { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 6) }, { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 6) }, @@ -87,6 +87,20 @@ RF_TxPowerTable_Entry rf_ieee_tx_power_table[RF_IEEE_TX_POWER_TABLE_SIZE+1] = { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(48, 0, 1, 73) }, RF_TxPowerTable_TERMINATION_ENTRY }; + +/* + * TX power table size, with one less entry excluding the + * termination entry. + */ +const size_t rf_ieee_tx_power_table_size = + (sizeof(rf_ieee_tx_power_table) / sizeof(rf_ieee_tx_power_table[0])) - 1; + +/* + * CMD_RADIO_SETUP must be configured with default TX power value + * in the .txPower field. + */ +#define DEFAULT_TX_POWER 0x9330 /* 5 dBm */ + /*---------------------------------------------------------------------------*/ /* Overrides for CMD_RADIO_SETUP */ uint32_t rf_ieee_overrides[] CC_ALIGN(4) = @@ -133,7 +147,7 @@ rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup = .config.biasMode = 0x1, .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, - .txPower = 0x9330, /* 5 dBm default */ + .txPower = DEFAULT_TX_POWER, /* 5 dBm default */ .pRegOverride = rf_ieee_overrides, }; /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h index 5f66f8b5d..e25127c9c 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h @@ -31,6 +31,8 @@ #ifndef IEEE_SETTINGS_H_ #define IEEE_SETTINGS_H_ /*---------------------------------------------------------------------------*/ +#include "contiki-conf.h" +/*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) @@ -44,12 +46,11 @@ #include /*---------------------------------------------------------------------------*/ /* TI-RTOS RF Mode Object */ -extern RF_Mode rf_ieee_mode; +extern RF_Mode rf_ieee_mode; /*---------------------------------------------------------------------------*/ /* TX Power Table */ -#define RF_IEEE_TX_POWER_TABLE_SIZE 13 - -extern RF_TxPowerTable_Entry rf_ieee_tx_power_table[RF_IEEE_TX_POWER_TABLE_SIZE+1]; +extern RF_TxPowerTable_Entry rf_ieee_tx_power_table[]; +extern const size_t rf_ieee_tx_power_table_size; /*---------------------------------------------------------------------------*/ /* RF Core API commands */ extern rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup; @@ -59,7 +60,7 @@ extern rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx; extern rfc_CMD_IEEE_RX_ACK_t rf_cmd_ieee_rx_ack; /*---------------------------------------------------------------------------*/ /* RF Core API Overrides */ -extern uint32_t rf_ieee_overrides[]; +extern uint32_t rf_ieee_overrides[]; /*---------------------------------------------------------------------------*/ #endif /* IEEE_SETTINGS_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c index e32d93d31..3c6c1c261 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c @@ -51,6 +51,7 @@ * Whitening: Dynamically IEEE 802.15.4g compatible whitener and 16/32-bit CRC */ /*---------------------------------------------------------------------------*/ +#include "contiki-conf.h" #include "sys/cc.h" /*---------------------------------------------------------------------------*/ #include @@ -73,14 +74,15 @@ RF_Mode rf_prop_mode = .rfePatchFxn = &rf_patch_rfe_genfsk, }; /*---------------------------------------------------------------------------*/ +#if defined(DEVICE_CC1310) /* - * TX Power table + * TX Power table for CC1310 * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) * See the Technical Reference Manual for further details about the "txPower" Command field. * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. */ -RF_TxPowerTable_Entry rf_prop_tx_power_table[RF_PROP_TX_POWER_TABLE_SIZE+1] = +RF_TxPowerTable_Entry rf_prop_tx_power_table[] = { { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY( 0, 3, 0, 4) }, { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY( 1, 1, 0, 0) }, @@ -98,10 +100,136 @@ RF_TxPowerTable_Entry rf_prop_tx_power_table[RF_PROP_TX_POWER_TABLE_SIZE+1] = { 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 0, 0, 92) }, /* The original PA value (12.5 dBm) have been rounded to an integer value. */ { 13, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 0, 83) }, - /* This setting requires CCFG_FORCE_VDDR_HH = 1. */ +#if RF_CONF_TXPOWER_BOOST_MODE + /* This setting requires RF_CONF_TXPOWER_BOOST_MODE = 1. */ { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 83) }, +#endif RF_TxPowerTable_TERMINATION_ENTRY }; + +/* + * TX power table size, with one less entry excluding the + * termination entry. + */ +const size_t rf_prop_tx_power_table_size = + (sizeof(rf_prop_tx_power_table) / sizeof(rf_prop_tx_power_table[0])) - 1; + +/* + * CMD_PROP_RADIO_DIV_SETUP must be configured with default TX power value + * in the .txPower field. This depends on whether RF_CONF_TXPOWER_BOOST_MODE + * is configured or not. + */ +#if RF_CONF_TXPOWER_BOOST_MODE +#define DEFAULT_TX_POWER 0xA73F /* 14 dBm */ +#else +#define DEFAULT_TX_POWER 0xA63F /* 12.5 dBm (rounded up to 13 dBm) */ +#endif + +#endif /* defined(DEVICE_CC1310) */ +/*---------------------------------------------------------------------------*/ +#if defined(DEVICE_CC1350) +/* + * TX Power table for CC1350 + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +RF_TxPowerTable_Entry rf_prop_tx_power_table[] = +{ + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY( 0, 3, 0, 2) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY( 3, 3, 0, 9) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 3, 0, 11) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY( 5, 3, 0, 12) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY( 6, 3, 0, 14) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 1, 0, 12) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 3, 0, 16) }, + { 6, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 18) }, + { 7, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 21) }, + { 8, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 3, 0, 25) }, + { 9, RF_TxPowerTable_DEFAULT_PA_ENTRY(18, 3, 0, 32) }, + { 10, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 3, 0, 44) }, + { 11, RF_TxPowerTable_DEFAULT_PA_ENTRY(37, 3, 0, 72) }, + { 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(43, 0, 0, 94) }, +#if RF_CONF_TXPOWER_BOOST_MODE + /* This setting requires RF_CONF_TXPOWER_BOOST_MODE = 1. */ + { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 85) }, +#endif + RF_TxPowerTable_TERMINATION_ENTRY +}; + +/* + * TX power table size, with one less entry excluding the + * termination entry. + */ +const size_t rf_prop_tx_power_table_size = + (sizeof(rf_prop_tx_power_table) / sizeof(rf_prop_tx_power_table[0])) - 1; + +/* + * CMD_PROP_RADIO_DIV_SETUP must be configured with default TX power value + * in the .txPower field. This depends on whether RF_CONF_TXPOWER_BOOST_MODE + * is configured or not. + */ +#if RF_CONF_TXPOWER_BOOST_MODE +#define DEFAULT_TX_POWER 0xAB3F /* 14 dBm */ +#else +#define DEFAULT_TX_POWER 0xBC2B /* 12 dBm */ +#endif + +#endif /* defined(DEVICE_CC1350) */ + /*---------------------------------------------------------------------------*/ +#if defined(DEVICE_CC1350_4) +/* + * TX Power table for CC1350_433 + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +RF_TxPowerTable_Entry rf_prop_tx_power_table[] = +{ + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY( 0, 3, 0, 2) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY( 1, 3, 0, 7) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY( 1, 3, 0, 9) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY( 2, 3, 0, 11) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY( 2, 3, 0, 12) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY( 3, 3, 0, 16) }, + { 6, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 3, 0, 18) }, + { 7, RF_TxPowerTable_DEFAULT_PA_ENTRY( 5, 3, 0, 21) }, + { 8, RF_TxPowerTable_DEFAULT_PA_ENTRY( 6, 3, 0, 23) }, + { 9, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 3, 0, 28) }, + { 10, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 35) }, + { 11, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 1, 0, 39) }, + { 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 60) }, + { 13, RF_TxPowerTable_DEFAULT_PA_ENTRY(15, 0, 0, 108) }, + /* The original PA value (13.7 dBm) have been rounded to an integer value. */ + { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 0, 92) }, +#if RF_CONF_TXPOWER_BOOST_MODE + /* This setting requires RF_CONF_TXPOWER_BOOST_MODE = 1. */ + { 15, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 72) }, +#endif + RF_TxPowerTable_TERMINATION_ENTRY +}; + +/* + * TX power table size, with one less entry excluding the + * termination entry. + */ +const size_t rf_prop_tx_power_table_size = + (sizeof(rf_prop_tx_power_table) / sizeof(rf_prop_tx_power_table[0])) - 1; + +/* + * CMD_PROP_RADIO_DIV_SETUP must be configured with default TX power value + * in the .txPower field. This depends on whether RF_CONF_TXPOWER_BOOST_MODE + * is configured or not. + */ +#if RF_CONF_TXPOWER_BOOST_MODE +#define DEFAULT_TX_POWER 0x913F /* 15 dBm */ +#else +#define DEFAULT_TX_POWER 0xB83F /* 13.7 dBm (rounded up to 14 dBm) */ +#endif + +#endif /* defined(DEVICE_CC1350_4) */ /*---------------------------------------------------------------------------*/ /* Overrides for CMD_PROP_RADIO_DIV_SETUP */ uint32_t rf_prop_overrides[] CC_ALIGN(4) = @@ -138,10 +266,17 @@ uint32_t rf_prop_overrides[] CC_ALIGN(4) = (uint32_t)0x00000943, /* CRC-16 calculation (see TRM section 23.7.5.2.1) */ /* IEEE 802.15.4g: Fix incorrect initialization value for */ (uint32_t)0x00000963, /* CRC-16 calculation (see TRM section 23.7.5.2.1) */ +#if defined(DEVICE_CC1350_4) + /* override_phy_rx_rssi_offset_neg2db.xml */ + (uint32_t)0x000288A3, /* Rx: Set RSSI offset to adjust reported RSSI by -2 dB */ +#else /* override_phy_rx_rssi_offset_5db.xml */ (uint32_t)0x00FB88A3, /* Rx: Set RSSI offset to adjust reported RSSI by +5 dB */ +#endif /* TX power override */ +#if RF_CONF_TXPOWER_BOOST_MODE ADI_REG_OVERRIDE(0,12,0xF8), /* Tx: Set PA trim to max (in ADI0, set PACTL0=0xF8) */ +#endif (uint32_t)0xFFFFFFFF, }; /*---------------------------------------------------------------------------*/ @@ -175,7 +310,7 @@ rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup = .config.biasMode = 0x1, /* set by driver */ .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, - .txPower = 0xA73F, + .txPower = DEFAULT_TX_POWER, .pRegOverride = rf_prop_overrides, .centerFreq = 0x0364, /* set by driver */ .intFreq = 0x8000, /* set by driver */ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h index 1e5169459..f4f32ad57 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h @@ -31,6 +31,8 @@ #ifndef PROP_SETTINGS_H_ #define PROP_SETTINGS_H_ /*---------------------------------------------------------------------------*/ +#include "contiki-conf.h" +/*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) @@ -40,12 +42,11 @@ #include /*---------------------------------------------------------------------------*/ /* TI-RTOS RF Mode Object */ -extern RF_Mode rf_prop_mode; +extern RF_Mode rf_prop_mode; /*---------------------------------------------------------------------------*/ /* TX Power Table */ -#define RF_PROP_TX_POWER_TABLE_SIZE 16 - -extern RF_TxPowerTable_Entry rf_prop_tx_power_table[RF_PROP_TX_POWER_TABLE_SIZE+1]; +extern RF_TxPowerTable_Entry rf_prop_tx_power_table[]; +extern const size_t rf_prop_tx_power_table_size; /*---------------------------------------------------------------------------*/ /* RF Core API commands */ extern rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup; @@ -54,7 +55,7 @@ extern rfc_CMD_PROP_TX_ADV_t rf_cmd_prop_tx_adv; extern rfc_CMD_PROP_RX_ADV_t rf_cmd_prop_rx_adv; /*---------------------------------------------------------------------------*/ /* RF Core API Overrides */ -extern uint32_t rf_prop_overrides[]; +extern uint32_t rf_prop_overrides[]; /*---------------------------------------------------------------------------*/ #endif /* PROP_SETTINGS_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c index 4eabcf367..253c11dfc 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c @@ -67,6 +67,7 @@ RF_Mode rf_ieee_mode = .rfePatchFxn = 0, }; /*---------------------------------------------------------------------------*/ +#if defined(DEVICE_CC1352R) /* * TX Power table * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: @@ -74,7 +75,7 @@ RF_Mode rf_ieee_mode = * See the Technical Reference Manual for further details about the "txPower" Command field. * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. */ -RF_TxPowerTable_Entry rf_ieee_tx_power_table_default_pa[RF_IEEE_TX_POWER_TABLE_DEFAULT_PA_SIZE+1] = +RF_TxPowerTable_Entry rf_ieee_tx_power_table[] = { { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 3) }, { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 3) }, @@ -93,36 +94,22 @@ RF_TxPowerTable_Entry rf_ieee_tx_power_table_default_pa[RF_IEEE_TX_POWER_TABLE_D { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, RF_TxPowerTable_TERMINATION_ENTRY }; -/*---------------------------------------------------------------------------*/ + /* - * TX Power table - * The RF_TxPowerTable_HIGH_PA_ENTRY macro is defined in RF.h and requires the following arguments: - * RF_TxPowerTable_HIGH_PA_ENTRY(bias, ibboost, boost, coefficient, ldoTrim) - * See the Technical Reference Manual for further details about the "txPower" Command field. - * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + * TX power table size, with one less entry excluding the + * termination entry. */ -RF_TxPowerTable_Entry rf_ieee_tx_power_table_high_pa[RF_IEEE_TX_POWER_TABLE_HIGH_PA_SIZE+1] = -{ - { 0, RF_TxPowerTable_HIGH_PA_ENTRY(29, 0, 1, 17, 1) }, - { 3, RF_TxPowerTable_HIGH_PA_ENTRY(39, 0, 1, 20, 1) }, - { 6, RF_TxPowerTable_HIGH_PA_ENTRY(46, 0, 1, 26, 7) }, - { 9, RF_TxPowerTable_HIGH_PA_ENTRY(40, 0, 1, 39, 41) }, - { 10, RF_TxPowerTable_HIGH_PA_ENTRY(23, 2, 1, 65, 5) }, - { 11, RF_TxPowerTable_HIGH_PA_ENTRY(24, 2, 1, 29, 7) }, - { 12, RF_TxPowerTable_HIGH_PA_ENTRY(19, 2, 1, 16, 25) }, - { 13, RF_TxPowerTable_HIGH_PA_ENTRY(27, 2, 1, 19, 13) }, - { 14, RF_TxPowerTable_HIGH_PA_ENTRY(24, 2, 1, 19, 27) }, - { 15, RF_TxPowerTable_HIGH_PA_ENTRY(23, 2, 1, 20, 39) }, - { 16, RF_TxPowerTable_HIGH_PA_ENTRY(34, 2, 1, 26, 23) }, - { 17, RF_TxPowerTable_HIGH_PA_ENTRY(38, 2, 1, 33, 25) }, - { 18, RF_TxPowerTable_HIGH_PA_ENTRY(30, 2, 1, 37, 53) }, - { 19, RF_TxPowerTable_HIGH_PA_ENTRY(36, 2, 1, 57, 59) }, - { 20, RF_TxPowerTable_HIGH_PA_ENTRY(56, 2, 1, 45, 63) }, - RF_TxPowerTable_TERMINATION_ENTRY -}; +const size_t rf_ieee_tx_power_table_size = + (sizeof(rf_ieee_tx_power_table) / sizeof(rf_ieee_tx_power_table[0])) - 1; + +/* + * CMD_RADIO_SETUP must be configured with default TX power value + * in the .txPower field. + */ +#define DEFAULT_TX_POWER 0x941E /* 5 dBm */ /*---------------------------------------------------------------------------*/ -/* Overrides for CMD_RADIO_SETUP with default PA */ -uint32_t rf_ieee_overrides_default_pa[] CC_ALIGN(4) = +/* Overrides for CMD_RADIO_SETUP */ +uint32_t rf_ieee_overrides[] CC_ALIGN(4) = { /* override_ieee_802_15_4.xml */ MCE_RFE_OVERRIDE(1,0,0,0,1,0), /* PHY: Use MCE RAM patch, RFE ROM bank 1 */ @@ -142,9 +129,54 @@ uint32_t rf_ieee_overrides_default_pa[] CC_ALIGN(4) = (uint32_t)0x000F8883, /* Rx: Set LNA bias current offset to +15 to saturate trim to max (default: 0) */ (uint32_t)0xFFFFFFFF, }; + +#endif /* defined(DEVICE_CC1352R) */ +/*---------------------------------------------------------------------------*/ +#if defined(DEVICE_CC1352P) + +#if RF_CONF_TXPOWER_HIGH_PA +/* + * TX Power table + * The RF_TxPowerTable_HIGH_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_HIGH_PA_ENTRY(bias, ibboost, boost, coefficient, ldoTrim) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +RF_TxPowerTable_Entry rf_ieee_tx_power_table[] = +{ + { 0, RF_TxPowerTable_HIGH_PA_ENTRY(29, 0, 1, 17, 1) }, + { 3, RF_TxPowerTable_HIGH_PA_ENTRY(39, 0, 1, 20, 1) }, + { 6, RF_TxPowerTable_HIGH_PA_ENTRY(46, 0, 1, 26, 7) }, + { 9, RF_TxPowerTable_HIGH_PA_ENTRY(40, 0, 1, 39, 41) }, + { 10, RF_TxPowerTable_HIGH_PA_ENTRY(23, 2, 1, 65, 5) }, + { 11, RF_TxPowerTable_HIGH_PA_ENTRY(24, 2, 1, 29, 7) }, + { 12, RF_TxPowerTable_HIGH_PA_ENTRY(19, 2, 1, 16, 25) }, + { 13, RF_TxPowerTable_HIGH_PA_ENTRY(27, 2, 1, 19, 13) }, + { 14, RF_TxPowerTable_HIGH_PA_ENTRY(24, 2, 1, 19, 27) }, + { 15, RF_TxPowerTable_HIGH_PA_ENTRY(23, 2, 1, 20, 39) }, + { 16, RF_TxPowerTable_HIGH_PA_ENTRY(34, 2, 1, 26, 23) }, + { 17, RF_TxPowerTable_HIGH_PA_ENTRY(38, 2, 1, 33, 25) }, + { 18, RF_TxPowerTable_HIGH_PA_ENTRY(30, 2, 1, 37, 53) }, + { 19, RF_TxPowerTable_HIGH_PA_ENTRY(36, 2, 1, 57, 59) }, + { 20, RF_TxPowerTable_HIGH_PA_ENTRY(56, 2, 1, 45, 63) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; + +/* + * TX power table size, with one less entry excluding the + * termination entry. + */ +const size_t rf_ieee_tx_power_table_size = + (sizeof(rf_ieee_tx_power_table) / sizeof(rf_ieee_tx_power_table[0])) - 1; + +/* + * CMD_PROP_RADIO_DIV_SETUP must be configured with default TX power value + * in the .txPower field. For High PA, this must be 0xFFFF. + */ +#define DEFAULT_TX_POWER 0xFFFF /* High PA */ /*---------------------------------------------------------------------------*/ /* Overrides for CMD_RADIO_SETUP with high PA */ -uint32_t rf_ieee_overrides_high_pa[] CC_ALIGN(4) = +uint32_t rf_ieee_overrides[] CC_ALIGN(4) = { /* override_ieee_802_15_4.xml */ MCE_RFE_OVERRIDE(1,0,0,0,1,0), /* PHY: Use MCE RAM patch, RFE ROM bank 1 */ @@ -168,6 +200,73 @@ uint32_t rf_ieee_overrides_high_pa[] CC_ALIGN(4) = (uint32_t)0xFFFFFFFF, }; /*---------------------------------------------------------------------------*/ +#else +/* + * TX Power table + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +RF_TxPowerTable_Entry rf_ieee_tx_power_table[] = +{ + { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 3) }, + { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 3) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 2, 0, 6) }, + { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 2, 0, 8) }, + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 11) }, + { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 2, 0, 5) }, + { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 16) }, + { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 17) }, + { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 1, 0, 20) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(25, 1, 0, 26) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 1, 0, 28) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 0, 0, 34) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 0, 0, 42) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 0, 0, 54) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; + +/* + * TX power table size, with one less entry excluding the + * termination entry. + */ +const size_t rf_ieee_tx_power_table_size = + (sizeof(rf_ieee_tx_power_table) / sizeof(rf_ieee_tx_power_table[0])) - 1; + +/* + * CMD_RADIO_SETUP must be configured with default TX power value + * in the .txPower field. + */ +#define DEFAULT_TX_POWER 0x941E /* 5 dBm */ +/*---------------------------------------------------------------------------*/ +/* Overrides for CMD_RADIO_SETUP with default PA */ +uint32_t rf_ieee_overrides[] CC_ALIGN(4) = +{ + /* override_ieee_802_15_4.xml */ + MCE_RFE_OVERRIDE(1,0,0,0,1,0), /* PHY: Use MCE RAM patch, RFE ROM bank 1 */ + (uint32_t)0x02400403, /* Synth: Use 48 MHz crystal, enable extra PLL filtering */ + (uint32_t)0x001C8473, /* Synth: Configure extra PLL filtering */ + (uint32_t)0x00088433, /* Synth: Configure synth hardware */ + (uint32_t)0x00038793, /* Synth: Set minimum RTRIM to 3 */ + HW32_ARRAY_OVERRIDE(0x4004,1), /* Synth: Configure faster calibration */ + (uint32_t)0x1C0C0618, /* Synth: Configure faster calibration */ + (uint32_t)0xC00401A1, /* Synth: Configure faster calibration */ + (uint32_t)0x00010101, /* Synth: Configure faster calibration */ + (uint32_t)0xC0040141, /* Synth: Configure faster calibration */ + (uint32_t)0x00214AD3, /* Synth: Configure faster calibration */ + (uint32_t)0x02980243, /* Synth: Decrease synth programming time-out (0x0298 RAT ticks = 166 us) */ + /* DC/DC regulator: In Tx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). */ + (uint32_t)0xFCFC08C3, /* In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). */ + (uint32_t)0x000F8883, /* Rx: Set LNA bias current offset to +15 to saturate trim to max (default: 0) */ + (uint32_t)0xFFFFFFFF, +}; + +#endif /* RF_CONF_TXPOWER_HIGH_PA */ + +#endif /* defined(DEVICE_CC1352P) */ +/*---------------------------------------------------------------------------*/ /* CMD_RADIO_SETUP: Radio Setup Command for Pre-Defined Schemes */ rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup = { @@ -187,8 +286,8 @@ rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup = .config.biasMode = 0x1, .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, - .txPower = 0x941E, /* 5 dBm default */ - .pRegOverride = rf_ieee_overrides_default_pa, + .txPower = DEFAULT_TX_POWER, /* 5 dBm default */ + .pRegOverride = rf_ieee_overrides, }; /*---------------------------------------------------------------------------*/ /* CMD_FS: Frequency Synthesizer Programming Command */ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h index b187c833f..db2717f21 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h @@ -31,6 +31,8 @@ #ifndef IEEE_SETTINGS_H_ #define IEEE_SETTINGS_H_ /*---------------------------------------------------------------------------*/ +#include "contiki-conf.h" +/*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) @@ -40,14 +42,11 @@ #include /*---------------------------------------------------------------------------*/ /* TI-RTOS RF Mode Object */ -extern RF_Mode rf_ieee_mode; +extern RF_Mode rf_ieee_mode; /*---------------------------------------------------------------------------*/ /* TX Power Table */ -#define RF_IEEE_TX_POWER_TABLE_DEFAULT_PA_SIZE 15 -#define RF_IEEE_TX_POWER_TABLE_HIGH_PA_SIZE 15 - -extern RF_TxPowerTable_Entry rf_ieee_tx_power_table_default_pa[RF_IEEE_TX_POWER_TABLE_DEFAULT_PA_SIZE+1]; -extern RF_TxPowerTable_Entry rf_ieee_tx_power_table_high_pa[RF_IEEE_TX_POWER_TABLE_HIGH_PA_SIZE+1]; +extern RF_TxPowerTable_Entry rf_ieee_tx_power_table[]; +extern const size_t rf_ieee_tx_power_table_size; /*---------------------------------------------------------------------------*/ /* RF Core API commands */ extern rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup; @@ -57,8 +56,7 @@ extern rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx; extern rfc_CMD_IEEE_RX_ACK_t rf_cmd_ieee_rx_ack; /*---------------------------------------------------------------------------*/ /* RF Core API Overrides */ -extern uint32_t rf_ieee_overrides_default_pa[]; -extern uint32_t rf_ieee_overrides_high_pa[]; +extern uint32_t rf_ieee_overrides[]; /*---------------------------------------------------------------------------*/ #endif /* IEEE_SETTINGS_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c index ffea53182..44cd20960 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c @@ -80,6 +80,7 @@ RF_Mode rf_prop_mode = .rfePatchFxn = &rf_patch_rfe_genfsk, }; /*---------------------------------------------------------------------------*/ +#if defined(DEVICE_CC1312R) || defined(DEVICE_CC1352R) /* * TX Power table * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: @@ -87,7 +88,191 @@ RF_Mode rf_prop_mode = * See the Technical Reference Manual for further details about the "txPower" Command field. * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. */ -RF_TxPowerTable_Entry rf_prop_tx_power_table_default_pa[RF_PROP_TX_POWER_TABLE_DEFAULT_PA_SIZE+1] = +RF_TxPowerTable_Entry rf_prop_tx_power_table[] = +{ + { -20, RF_TxPowerTable_DEFAULT_PA_ENTRY(0, 3, 0, 2) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(1, 3, 0, 2) }, + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(2, 3, 0, 4) }, + { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(4, 3, 0, 5) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(8, 3, 0, 7) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(9, 3, 0, 7) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 3, 0, 9) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 9) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 3, 0, 11) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 3, 0, 12) }, + { 6, RF_TxPowerTable_DEFAULT_PA_ENTRY(16, 3, 0, 14) }, + { 7, RF_TxPowerTable_DEFAULT_PA_ENTRY(8, 2, 0, 16) }, + { 8, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 3, 0, 32) }, + { 9, RF_TxPowerTable_DEFAULT_PA_ENTRY(26, 3, 0, 28) }, + { 10, RF_TxPowerTable_DEFAULT_PA_ENTRY(33, 3, 0, 55) }, + { 11, RF_TxPowerTable_DEFAULT_PA_ENTRY(23, 2, 0, 42) }, + { 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 0, 0, 58) }, + /* The original PA value (12.5 dBm) have been rounded to an integer value. */ + { 13, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 0, 0, 102) }, +#if RF_CONF_TXPOWER_BOOST_MODE + /* This setting requires RF_CONF_TXPOWER_BOOST_MODE = 1. */ + { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 79) }, +#endif + RF_TxPowerTable_TERMINATION_ENTRY +}; + +/* + * TX power table size, with one less entry excluding the + * termination entry. + */ +const size_t rf_prop_tx_power_table_size = + (sizeof(rf_prop_tx_power_table) / sizeof(rf_prop_tx_power_table[0])) - 1; + +/* + * CMD_PROP_RADIO_DIV_SETUP must be configured with default TX power value + * in the .txPower field. This depends on whether RF_CONF_TXPOWER_BOOST_MODE + * is configured or not. + */ +#if RF_CONF_TXPOWER_BOOST_MODE +#define DEFAULT_TX_POWER 0x9F3F /* 14 dBm */ +#else +#define DEFAULT_TX_POWER 0xCC14 /* 12.5 dBm (rounded up to 13 dBm) */ +#endif + +/*---------------------------------------------------------------------------*/ +/* Overrides for CMD_PROP_RADIO_DIV_SETUP */ +uint32_t rf_prop_overrides[] CC_ALIGN(4) = +{ + /* override_use_patch_prop_genfsk.xml */ + MCE_RFE_OVERRIDE(1,0,0,1,0,0), /* PHY: Use MCE RAM patch, RFE RAM patch */ + /* override_synth_prop_863_930_div5.xml */ + (uint32_t)0x02400403, /* Synth: Use 48 MHz crystal as synth clock, enable extra PLL filtering */ + (uint32_t)0x00068793, /* Synth: Set minimum RTRIM to 6 */ + (uint32_t)0x001C8473, /* Synth: Configure extra PLL filtering */ + (uint32_t)0x00088433, /* Synth: Configure extra PLL filtering */ + (uint32_t)0x000684A3, /* Synth: Set Fref to 4 MHz */ + HW32_ARRAY_OVERRIDE(0x4004,1), /* Synth: Configure faster calibration */ + (uint32_t)0x180C0618, /* Synth: Configure faster calibration */ + (uint32_t)0xC00401A1, /* Synth: Configure faster calibration */ + (uint32_t)0x00010101, /* Synth: Configure faster calibration */ + (uint32_t)0xC0040141, /* Synth: Configure faster calibration */ + (uint32_t)0x00214AD3, /* Synth: Configure faster calibration */ + /* Synth: Decrease synth programming time-out by 90 us from default */ + (uint32_t)0x02980243, /* (0x0298 RAT ticks = 166 us) */ + (uint32_t)0x0A480583, /* Synth: Set loop bandwidth after lock to 20 kHz */ + (uint32_t)0x7AB80603, /* Synth: Set loop bandwidth after lock to 20 kHz */ + (uint32_t)0x00000623, /* Synth: Set loop bandwidth after lock to 20 kHz */ + /* override_phy_tx_pa_ramp_genfsk_hpa.xml */ + ADI_HALFREG_OVERRIDE(0,16,0x8,0x8), /* Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[3]=1) */ + ADI_HALFREG_OVERRIDE(0,17,0x1,0x1), /* Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[4]=1) */ + /* override_phy_rx_frontend_genfsk.xml */ + HW_REG_OVERRIDE(0x609C,0x001A), /* Rx: Set AGC reference level to 0x1A (default: 0x2E) */ + (uint32_t)0x00018883, /* Rx: Set LNA bias current offset to adjust +1 (default: 0) */ + (uint32_t)0x000288A3, /* Rx: Set RSSI offset to adjust reported RSSI by -2 dB (default: 0) */ + /* override_phy_rx_aaf_bw_0xd.xml */ + /* Rx: Set anti-aliasing filter bandwidth to 0xD */ + ADI_HALFREG_OVERRIDE(0,61,0xF,0xD), /* (in ADI0, set IFAMPCTL3[7:4]=0xD) */ +#if RF_CONF_TXPOWER_BOOST_MODE + /* TX power override */ + /* DC/DC regulator: In Tx with 14 dBm PA setting, */ + /* use DCDCCTL5[3:0]=0xF (DITHER_EN=1 and IPEAK=7). */ + (uint32_t)0xFFFC08C3, /* In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). */ + /* Tx: Set PA trim to max to maximize its output power */ + ADI_REG_OVERRIDE(0,12,0xF8), /* (in ADI0, set PACTL0=0xF8) */ +#else + /* TX power override */ + /* DC/DC regulator: */ + /* In Tx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). */ + (uint32_t)0xFCFC08C3, /* In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). */ +#endif + (uint32_t)0xFFFFFFFF, +}; + +#endif /* defined(DEVICE_CC1312R) || defined(DEVICE_CC1352R) */ +/*---------------------------------------------------------------------------*/ +#if defined(DEVICE_CC1352P) + +#if RF_CONF_TXPOWER_HIGH_PA +/* + * TX Power table + * The RF_TxPowerTable_HIGH_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_HIGH_PA_ENTRY(bias, ibboost, boost, coefficient, ldoTrim) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +RF_TxPowerTable_Entry rf_prop_tx_power_table[] = +{ + { 14, RF_TxPowerTable_HIGH_PA_ENTRY( 7, 0, 0, 23, 4) }, + { 15, RF_TxPowerTable_HIGH_PA_ENTRY(10, 0, 0, 26, 4) }, + { 16, RF_TxPowerTable_HIGH_PA_ENTRY(14, 0, 0, 33, 4) }, + { 17, RF_TxPowerTable_HIGH_PA_ENTRY(18, 0, 0, 40, 6) }, + { 18, RF_TxPowerTable_HIGH_PA_ENTRY(24, 0, 0, 51, 8) }, + { 19, RF_TxPowerTable_HIGH_PA_ENTRY(32, 0, 0, 73, 12) }, + { 20, RF_TxPowerTable_HIGH_PA_ENTRY(27, 0, 0, 85, 32) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; + +/* + * TX power table size, with one less entry excluding the + * termination entry. + */ +const size_t rf_prop_tx_power_table_size = + (sizeof(rf_prop_tx_power_table) / sizeof(rf_prop_tx_power_table[0])) - 1; + +/* + * CMD_PROP_RADIO_DIV_SETUP must be configured with default TX power value + * in the .txPower field. For High PA, this must be 0xFFFF. + */ +#define DEFAULT_TX_POWER 0xFFFF /* High PA */ + +/*---------------------------------------------------------------------------*/ +/* Overrides for CMD_PROP_RADIO_DIV_SETUP with high PA */ +uint32_t rf_prop_overrides[] CC_ALIGN(4) = +{ + /* override_use_patch_prop_genfsk.xml */ + MCE_RFE_OVERRIDE(1,0,0,1,0,0), /* PHY: Use MCE RAM patch, RFE RAM patch */ + /* override_synth_prop_863_930_div5.xml */ + (uint32_t)0x02400403, /* Synth: Use 48 MHz crystal as synth clock, enable extra PLL filtering */ + (uint32_t)0x00068793, /* Synth: Set minimum RTRIM to 6 */ + (uint32_t)0x001C8473, /* Synth: Configure extra PLL filtering */ + (uint32_t)0x00088433, /* Synth: Configure extra PLL filtering */ + (uint32_t)0x000684A3, /* Synth: Set Fref to 4 MHz */ + HW32_ARRAY_OVERRIDE(0x4004,1), /* Synth: Configure faster calibration */ + (uint32_t)0x180C0618, /* Synth: Configure faster calibration */ + (uint32_t)0xC00401A1, /* Synth: Configure faster calibration */ + (uint32_t)0x00010101, /* Synth: Configure faster calibration */ + (uint32_t)0xC0040141, /* Synth: Configure faster calibration */ + (uint32_t)0x00214AD3, /* Synth: Configure faster calibration */ + /* Synth: Decrease synth programming time-out by 90 us */ + (uint32_t)0x02980243, /* from default (0x0298 RAT ticks = 166 us) */ + (uint32_t)0x0A480583, /* Synth: Set loop bandwidth after lock to 20 kHz */ + (uint32_t)0x7AB80603, /* Synth: Set loop bandwidth after lock to 20 kHz */ + (uint32_t)0x00000623, /* Synth: Set loop bandwidth after lock to 20 kHz */ + /* override_phy_tx_pa_ramp_genfsk_hpa.xml */ + /* Tx: Configure PA ramping, set wait time before turning off */ + HW_REG_OVERRIDE(0x6028,0x002F), /* (0x2F ticks of 16/24 us = 31.3 us). */ + ADI_HALFREG_OVERRIDE(0,16,0x8,0x8), /* Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[3]=1) */ + ADI_HALFREG_OVERRIDE(0,17,0x1,0x1), /* Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[4]=1) */ + /* override_phy_rx_frontend_genfsk.xml */ + HW_REG_OVERRIDE(0x609C,0x001A), /* Rx: Set AGC reference level to 0x1A (default: 0x2E) */ + (uint32_t)0x00018883, /* Rx: Set LNA bias current offset to adjust +1 (default: 0) */ + (uint32_t)0x000288A3, /* Rx: Set RSSI offset to adjust reported RSSI by -2 dB (default: 0) */ + /* override_phy_rx_aaf_bw_0xd.xml */ + /* Rx: Set anti-aliasing filter bandwidth to 0xD */ + ADI_HALFREG_OVERRIDE(0,61,0xF,0xD), /* (in ADI0, set IFAMPCTL3[7:4]=0xD) */ + /* TX power override */ + /* DC/DC regulator: */ + /* In Tx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). */ + (uint32_t)0xFCFC08C3, /* In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). */ + (uint32_t)0x82A86C2B, /* txHighPA=0x20AA1B */ + (uint32_t)0xFFFFFFFF, +}; + +#else +/*---------------------------------------------------------------------------*/ +/* + * TX Power table + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +RF_TxPowerTable_Entry rf_prop_tx_power_table[] = { { -20, RF_TxPowerTable_DEFAULT_PA_ENTRY( 0, 3, 0, 2) }, { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY( 1, 3, 0, 3) }, @@ -106,33 +291,37 @@ RF_TxPowerTable_Entry rf_prop_tx_power_table_default_pa[RF_PROP_TX_POWER_TABLE_D { 10, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 40) }, { 11, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 0, 0, 71) }, { 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 0, 64) }, - /* The original PA value (13.5 dBm) have been rounded to an integer value. */ - /* This setting requires CCFG_FORCE_VDDR_HH = 1. */ +#if RF_CONF_TXPOWER_BOOST_MODE + /* + * This setting requires RF_CONF_TXPOWER_BOOST_MODE = 1. + * The original PA value (13.5 dBm) have been rounded to an integer value. + */ { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 0) }, +#endif RF_TxPowerTable_TERMINATION_ENTRY }; -/*---------------------------------------------------------------------------*/ + /* - * TX Power table - * The RF_TxPowerTable_HIGH_PA_ENTRY macro is defined in RF.h and requires the following arguments: - * RF_TxPowerTable_HIGH_PA_ENTRY(bias, ibboost, boost, coefficient, ldoTrim) - * See the Technical Reference Manual for further details about the "txPower" Command field. - * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + * TX power table size, with one less entry excluding the + * termination entry. */ -RF_TxPowerTable_Entry rf_prop_tx_power_table_high_pa[RF_PROP_TX_POWER_TABLE_HIGH_PA_SIZE+1] = -{ - { 14, RF_TxPowerTable_HIGH_PA_ENTRY( 7, 0, 0, 23, 4) }, - { 15, RF_TxPowerTable_HIGH_PA_ENTRY(10, 0, 0, 26, 4) }, - { 16, RF_TxPowerTable_HIGH_PA_ENTRY(14, 0, 0, 33, 4) }, - { 17, RF_TxPowerTable_HIGH_PA_ENTRY(18, 0, 0, 40, 6) }, - { 18, RF_TxPowerTable_HIGH_PA_ENTRY(24, 0, 0, 51, 8) }, - { 19, RF_TxPowerTable_HIGH_PA_ENTRY(32, 0, 0, 73, 12) }, - { 20, RF_TxPowerTable_HIGH_PA_ENTRY(27, 0, 0, 85, 32) }, - RF_TxPowerTable_TERMINATION_ENTRY -}; +const size_t rf_prop_tx_power_table_size = + (sizeof(rf_prop_tx_power_table) / sizeof(rf_prop_tx_power_table[0])) - 1; + +/* + * CMD_PROP_RADIO_DIV_SETUP must be configured with default TX power value + * in the .txPower field. This depends on whether RF_CONF_TXPOWER_BOOST_MODE + * is configured or not. + */ +#if RF_CONF_TXPOWER_BOOST_MODE +#define DEFAULT_TX_POWER 0x013F /* 13.5 dBm (rounded up to 14 dBm) */ +#else +#define DEFAULT_TX_POWER 0x803F /* 12 dBm */ +#endif + /*---------------------------------------------------------------------------*/ /* Overrides for CMD_PROP_RADIO_DIV_SETUP with defualt PA */ -uint32_t rf_prop_overrides_default_pa[] CC_ALIGN(4) = +uint32_t rf_prop_overrides[] CC_ALIGN(4) = { /* override_use_patch_prop_genfsk.xml */ MCE_RFE_OVERRIDE(1,0,0,1,0,0), /* PHY: Use MCE RAM patch, RFE RAM patch */ @@ -165,56 +354,25 @@ uint32_t rf_prop_overrides_default_pa[] CC_ALIGN(4) = /* override_phy_rx_aaf_bw_0xd.xml */ /* Rx: Set anti-aliasing filter bandwidth to 0xD */ ADI_HALFREG_OVERRIDE(0,61,0xF,0xD), /* (in ADI0, set IFAMPCTL3[7:4]=0xD) */ +#if RF_CONF_TXPOWER_BOOST_MODE /* TX power override */ /* DC/DC regulator: In Tx with 14 dBm PA setting, */ /* use DCDCCTL5[3:0]=0xF (DITHER_EN=1 and IPEAK=7). */ (uint32_t)0xFFFC08C3, /* In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). */ /* Tx: Set PA trim to max to maximize its output power */ ADI_REG_OVERRIDE(0,12,0xF8), /* (in ADI0, set PACTL0=0xF8) */ - (uint32_t)0xFFFFFFFF, -}; -/*---------------------------------------------------------------------------*/ -/* Overrides for CMD_PROP_RADIO_DIV_SETUP with high PA */ -uint32_t rf_prop_overrides_high_pa[] CC_ALIGN(4) = -{ - /* override_use_patch_prop_genfsk.xml */ - MCE_RFE_OVERRIDE(1,0,0,1,0,0), /* PHY: Use MCE RAM patch, RFE RAM patch */ - /* override_synth_prop_863_930_div5.xml */ - (uint32_t)0x02400403, /* Synth: Use 48 MHz crystal as synth clock, enable extra PLL filtering */ - (uint32_t)0x00068793, /* Synth: Set minimum RTRIM to 6 */ - (uint32_t)0x001C8473, /* Synth: Configure extra PLL filtering */ - (uint32_t)0x00088433, /* Synth: Configure extra PLL filtering */ - (uint32_t)0x000684A3, /* Synth: Set Fref to 4 MHz */ - HW32_ARRAY_OVERRIDE(0x4004,1), /* Synth: Configure faster calibration */ - (uint32_t)0x180C0618, /* Synth: Configure faster calibration */ - (uint32_t)0xC00401A1, /* Synth: Configure faster calibration */ - (uint32_t)0x00010101, /* Synth: Configure faster calibration */ - (uint32_t)0xC0040141, /* Synth: Configure faster calibration */ - (uint32_t)0x00214AD3, /* Synth: Configure faster calibration */ - /* Synth: Decrease synth programming time-out by 90 us from default */ - (uint32_t)0x02980243, /* (0x0298 RAT ticks = 166 us) */ - (uint32_t)0x0A480583, /* Synth: Set loop bandwidth after lock to 20 kHz */ - (uint32_t)0x7AB80603, /* Synth: Set loop bandwidth after lock to 20 kHz */ - (uint32_t)0x00000623, /* Synth: Set loop bandwidth after lock to 20 kHz */ - /* override_phy_tx_pa_ramp_genfsk_hpa.xml */ - /* Tx: Configure PA ramping, set wait time before turning off */ - HW_REG_OVERRIDE(0x6028,0x002F), /* (0x2F ticks of 16/24 us = 31.3 us). */ - ADI_HALFREG_OVERRIDE(0,16,0x8,0x8), /* Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[3]=1) */ - ADI_HALFREG_OVERRIDE(0,17,0x1,0x1), /* Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[4]=1) */ - /* override_phy_rx_frontend_genfsk.xml */ - HW_REG_OVERRIDE(0x609C,0x001A), /* Rx: Set AGC reference level to 0x1A (default: 0x2E) */ - (uint32_t)0x00018883, /* Rx: Set LNA bias current offset to adjust +1 (default: 0) */ - (uint32_t)0x000288A3, /* Rx: Set RSSI offset to adjust reported RSSI by -2 dB (default: 0) */ - /* override_phy_rx_aaf_bw_0xd.xml */ - /* Rx: Set anti-aliasing filter bandwidth to 0xD */ - ADI_HALFREG_OVERRIDE(0,61,0xF,0xD), /* (in ADI0, set IFAMPCTL3[7:4]=0xD) */ - /* TX power override */ +#else + /* TX power override */ /* DC/DC regulator: */ /* In Tx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). */ (uint32_t)0xFCFC08C3, /* In Rx, use DCDCCTL5[3:0]=0xC (DITHER_EN=1 and IPEAK=4). */ - (uint32_t)0x82A86C2B, /* txHighPA=0x20AA1B */ +#endif (uint32_t)0xFFFFFFFF, }; + +#endif /* RF_CONF_TXPOWER_HIGH_PA */ + +#endif /* defined(DEVICE_CC1352P) */ /*---------------------------------------------------------------------------*/ /* CMD_PROP_RADIO_DIV_SETUP: Proprietary Mode Radio Setup Command for All Frequency Bands */ rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup = @@ -244,11 +402,11 @@ rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup = .formatConf.fecMode = 0x0, .formatConf.whitenMode = 0x7, .config.frontEndMode = 0x0, /* set by driver */ - .config.biasMode = 0x0, /* set by driver */ + .config.biasMode = 0x1, /* set by driver */ .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, - .txPower = 0x013F, /* default 13.5 dBm */ - .pRegOverride = rf_prop_overrides_default_pa, + .txPower = DEFAULT_TX_POWER, + .pRegOverride = rf_prop_overrides, .centerFreq = 0x0393, /* set by driver */ .intFreq = 0x8000, /* set by driver */ .loDivider = 0x05, /* set by driver */ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h index b19e76a9f..9f4103530 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h @@ -31,6 +31,8 @@ #ifndef PROP_SETTINGS_H_ #define PROP_SETTINGS_H_ /*---------------------------------------------------------------------------*/ +#include "contiki-conf.h" +/*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) @@ -40,14 +42,11 @@ #include /*---------------------------------------------------------------------------*/ /* TI-RTOS RF Mode Object */ -extern RF_Mode rf_prop_mode; +extern RF_Mode rf_prop_mode; /*---------------------------------------------------------------------------*/ /* Tx Power Tables */ -#define RF_PROP_TX_POWER_TABLE_DEFAULT_PA_SIZE 18 -#define RF_PROP_TX_POWER_TABLE_HIGH_PA_SIZE 7 - -extern RF_TxPowerTable_Entry rf_prop_tx_power_table_default_pa[RF_PROP_TX_POWER_TABLE_DEFAULT_PA_SIZE+1]; -extern RF_TxPowerTable_Entry rf_prop_tx_power_table_high_pa[RF_PROP_TX_POWER_TABLE_HIGH_PA_SIZE+1]; +extern RF_TxPowerTable_Entry rf_prop_tx_power_table[]; +extern const size_t rf_prop_tx_power_table_size; /*---------------------------------------------------------------------------*/ /* RF Core API commands */ extern rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup; @@ -56,8 +55,7 @@ extern rfc_CMD_PROP_TX_ADV_t rf_cmd_prop_tx_adv; extern rfc_CMD_PROP_RX_ADV_t rf_cmd_prop_rx_adv; /*---------------------------------------------------------------------------*/ /* RF Core API Overrides */ -extern uint32_t rf_prop_overrides_default_pa[]; -extern uint32_t rf_prop_overrides_high_pa[]; +extern uint32_t rf_prop_overrides[]; /*---------------------------------------------------------------------------*/ #endif /* PROP_SETTINGS_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c index 96468c78b..2c87bb50e 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c @@ -66,7 +66,7 @@ RF_Mode rf_ieee_mode = * See the Technical Reference Manual for further details about the "txPower" Command field. * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. */ -RF_TxPowerTable_Entry rf_ieee_tx_power_table[RF_IEEE_TX_POWER_TABLE_SIZE+1] = +RF_TxPowerTable_Entry rf_ieee_tx_power_table[] = { { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 6) }, { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 6) }, @@ -83,6 +83,19 @@ RF_TxPowerTable_Entry rf_ieee_tx_power_table[RF_IEEE_TX_POWER_TABLE_SIZE+1] = { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(48, 0, 1, 73) }, RF_TxPowerTable_TERMINATION_ENTRY }; + +/* + * TX power table size, with one less entry excluding the + * termination entry. + */ +const size_t rf_ieee_tx_power_table_size = + (sizeof(rf_ieee_tx_power_table) / sizeof(rf_ieee_tx_power_table[0])) - 1; + +/* + * CMD_RADIO_SETUP must be configured with default TX power value + * in the .txPower field. + */ +#define DEFAULT_TX_POWER 0x9330 /* 5 dBm */ /*---------------------------------------------------------------------------*/ /* Overrides for CMD_RADIO_SETUP */ uint32_t rf_ieee_overrides[] CC_ALIGN(4) = @@ -130,7 +143,7 @@ rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup = .config.biasMode = 0x1, .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, - .txPower = 0x9330, /* 5 dBm default */ + .txPower = DEFAULT_TX_POWER, /* 5 dBm default */ .pRegOverride = rf_ieee_overrides, }; /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h index 3a4a7236d..db2717f21 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h @@ -31,6 +31,8 @@ #ifndef IEEE_SETTINGS_H_ #define IEEE_SETTINGS_H_ /*---------------------------------------------------------------------------*/ +#include "contiki-conf.h" +/*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) @@ -40,12 +42,11 @@ #include /*---------------------------------------------------------------------------*/ /* TI-RTOS RF Mode Object */ -extern RF_Mode rf_ieee_mode; +extern RF_Mode rf_ieee_mode; /*---------------------------------------------------------------------------*/ /* TX Power Table */ -#define RF_IEEE_TX_POWER_TABLE_SIZE 14 - -extern RF_TxPowerTable_Entry rf_ieee_tx_power_table[RF_IEEE_TX_POWER_TABLE_SIZE+1]; +extern RF_TxPowerTable_Entry rf_ieee_tx_power_table[]; +extern const size_t rf_ieee_tx_power_table_size; /*---------------------------------------------------------------------------*/ /* RF Core API commands */ extern rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup; @@ -55,7 +56,7 @@ extern rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx; extern rfc_CMD_IEEE_RX_ACK_t rf_cmd_ieee_rx_ack; /*---------------------------------------------------------------------------*/ /* RF Core API Overrides */ -extern uint32_t rf_ieee_overrides[]; +extern uint32_t rf_ieee_overrides[]; /*---------------------------------------------------------------------------*/ #endif /* IEEE_SETTINGS_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c index 3f6d4f7ed..76e6fdd14 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c @@ -67,7 +67,7 @@ RF_Mode rf_ieee_mode = * See the Technical Reference Manual for further details about the "txPower" Command field. * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. */ -RF_TxPowerTable_Entry rf_ieee_tx_power_table[RF_IEEE_TX_POWER_TABLE_SIZE+1] = +RF_TxPowerTable_Entry rf_ieee_tx_power_table[] = { { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY(7, 3, 0, 3) }, { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY(9, 3, 0, 3) }, @@ -86,6 +86,19 @@ RF_TxPowerTable_Entry rf_ieee_tx_power_table[RF_IEEE_TX_POWER_TABLE_SIZE+1] = { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, RF_TxPowerTable_TERMINATION_ENTRY }; + +/* + * TX power table size, with one less entry excluding the + * termination entry. + */ +const size_t rf_ieee_tx_power_table_size = + (sizeof(rf_ieee_tx_power_table) / sizeof(rf_ieee_tx_power_table[0])) - 1; + +/* + * CMD_RADIO_SETUP must be configured with default TX power value + * in the .txPower field. + */ +#define DEFAULT_TX_POWER 0x941E /* 5 dBm */ /*---------------------------------------------------------------------------*/ /* Overrides for CMD_RADIO_SETUP */ uint32_t rf_ieee_overrides[] CC_ALIGN(4) = @@ -129,7 +142,7 @@ rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup = .config.biasMode = 0x1, .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, - .txPower = 0x941E, /* 5 dBm default */ + .txPower = DEFAULT_TX_POWER, /* 5 dBm default */ .pRegOverride = rf_ieee_overrides, }; /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h index d2f65aee5..d03b24665 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h @@ -30,6 +30,9 @@ /*---------------------------------------------------------------------------*/ #ifndef IEEE_SETTINGS_H_ #define IEEE_SETTINGS_H_ +/*---------------------------------------------------------------------------*/ +#include "contiki-conf.h" + /*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) @@ -40,12 +43,11 @@ #include /*---------------------------------------------------------------------------*/ /* TI-RTOS RF Mode Object */ -extern RF_Mode rf_ieee_mode; +extern RF_Mode rf_ieee_mode; /*---------------------------------------------------------------------------*/ /* TX Power Table */ -#define RF_IEEE_TX_POWER_TABLE_SIZE 15 - -extern RF_TxPowerTable_Entry rf_ieee_tx_power_table[RF_IEEE_TX_POWER_TABLE_SIZE+1]; +extern RF_TxPowerTable_Entry rf_ieee_tx_power_table[]; +extern const size_t rf_ieee_tx_power_table_size; /*---------------------------------------------------------------------------*/ /* RF Core API commands */ extern rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup; @@ -55,7 +57,7 @@ extern rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx; extern rfc_CMD_IEEE_RX_ACK_t rf_cmd_ieee_rx_ack; /*---------------------------------------------------------------------------*/ /* RF Core API Overrides */ -extern uint32_t rf_ieee_overrides[]; +extern uint32_t rf_ieee_overrides[]; /*---------------------------------------------------------------------------*/ #endif /* IEEE_SETTINGS_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index f0a866f24..b9e315e80 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -33,6 +33,7 @@ CONTIKI_TARGET_DIRS += $(addprefix $(FAMILY)/, $(TARGET_FAMILY_DIRS)) DEFINES += DeviceFamily_$(DEVICE_FAMILY) DEFINES += DEVICE_LINE_$(DEVICE_LINE) +DEFINES += DEVICE_$(DEVICE) DEFINES += $(BOARD_TYPE) DEFINES += PLATFORM_HAS_BUTTON=$(PLATFORM_HAS_BUTTON) DEFINES += SUPPORTS_PROP_MODE=$(SUPPORTS_PROP_MODE) diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Makefile.cc1310 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Makefile.cc1310 index 257308196..d43113151 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Makefile.cc1310 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Makefile.cc1310 @@ -1,9 +1,10 @@ ################################################################################ # SimpleLink Device makefile -SUBFAMILY = cc13x0-cc26x0 +SUBFAMILY = cc13x0-cc26x0 DEVICE_FAMILY = CC13X0 -DEVICE_LINE = CC13XX +DEVICE_LINE = CC13XX +DEVICE = CC1310 BOARD_SOURCEFILES += CC1310_LAUNCHXL.c CC1310_LAUNCHXL_fxns.c diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 index 7b773d7be..b88997c9a 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Makefile.cc1312r1 @@ -1,15 +1,13 @@ ################################################################################ # SimpleLink Device makefile -SUBFAMILY = cc13x2-cc26x2 +SUBFAMILY = cc13x2-cc26x2 DEVICE_FAMILY = CC13X2 -DEVICE_LINE = CC13XX +DEVICE_LINE = CC13XX +DEVICE = CC1312R BOARD_SOURCEFILES += CC1312R1_LAUNCHXL.c CC1312R1_LAUNCHXL_fxns.c -DEFINES += PROP_MODE_CONF_TX_POWER_TABLE=rf_prop_tx_power_table_default_pa -DEFINES += PROP_MODE_CONF_TX_POWER_TABLE_SIZE=RF_PROP_TX_POWER_TABLE_DEFAULT_PA_SIZE - SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 0 SUPPORTS_BLE_BEACON = 0 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Makefile.cc1350-4 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Makefile.cc1350-4 index df701aa49..8ea92347b 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Makefile.cc1350-4 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Makefile.cc1350-4 @@ -1,9 +1,10 @@ ################################################################################ # SimpleLink Device makefile -SUBFAMILY = cc13x0-cc26x0 +SUBFAMILY = cc13x0-cc26x0 DEVICE_FAMILY = CC13X0 -DEVICE_LINE = CC13XX +DEVICE_LINE = CC13XX +DEVICE = CC1350_4 BOARD_SOURCEFILES += CC1350_LAUNCHXL_433.c CC1350_LAUNCHXL_433_fxns.c diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Makefile.cc1350 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Makefile.cc1350 index 45c9212e1..350a5a045 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Makefile.cc1350 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Makefile.cc1350 @@ -1,9 +1,10 @@ ################################################################################ # SimpleLink Device makefile -SUBFAMILY = cc13x0-cc26x0 +SUBFAMILY = cc13x0-cc26x0 DEVICE_FAMILY = CC13X0 -DEVICE_LINE = CC13XX +DEVICE_LINE = CC13XX +DEVICE = CC1350 BOARD_SOURCEFILES += CC1350_LAUNCHXL.c CC1350_LAUNCHXL_fxns.c diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/Makefile.cc1352p-2 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/Makefile.cc1352p-2 index 651336ad3..2a31100d4 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/Makefile.cc1352p-2 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/Makefile.cc1352p-2 @@ -1,18 +1,13 @@ ################################################################################ # SimpleLink Device makefile -SUBFAMILY = cc13x2-cc26x2 +SUBFAMILY = cc13x2-cc26x2 DEVICE_FAMILY = CC13X2 -DEVICE_LINE = CC13XX +DEVICE_LINE = CC13XX +DEVICE = CC1352P BOARD_SOURCEFILES += CC1352P_2_LAUNCHXL.c CC1352P_2_LAUNCHXL_fxns.c -DEFINES += PROP_MODE_CONF_TX_POWER_TABLE=rf_prop_tx_power_table_default_pa -DEFINES += PROP_MODE_CONF_TX_POWER_TABLE_SIZE=RF_PROP_TX_POWER_TABLE_DEFAULT_PA_SIZE - -DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE=rf_ieee_tx_power_table_default_pa -DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE_SIZE=RF_IEEE_TX_POWER_TABLE_DEFAULT_PA_SIZE - SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 1 SUPPORTS_BLE_BEACON = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/Makefile.cc1352p-4 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/Makefile.cc1352p-4 index b03e44903..076e186b4 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/Makefile.cc1352p-4 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/Makefile.cc1352p-4 @@ -1,18 +1,13 @@ ################################################################################ # SimpleLink Device makefile -SUBFAMILY = cc13x2-cc26x2 +SUBFAMILY = cc13x2-cc26x2 DEVICE_FAMILY = CC13X2 -DEVICE_LINE = CC13XX +DEVICE_LINE = CC13XX +DEVICE = CC1352P BOARD_SOURCEFILES += CC1352P_4_LAUNCHXL.c CC1352P_4_LAUNCHXL_fxns.c -DEFINES += PROP_MODE_CONF_TX_POWER_TABLE=rf_prop_tx_power_table_default_pa -DEFINES += PROP_MODE_CONF_TX_POWER_TABLE_SIZE=RF_PROP_TX_POWER_TABLE_DEFAULT_PA_SIZE - -DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE=rf_ieee_tx_power_table_default_pa -DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE_SIZE=RF_IEEE_TX_POWER_TABLE_DEFAULT_PA_SIZE - SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 1 SUPPORTS_BLE_BEACON = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 index b628d1aae..37afeef96 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Makefile.cc1352p1 @@ -1,18 +1,13 @@ ################################################################################ # SimpleLink Device makefile -SUBFAMILY = cc13x2-cc26x2 +SUBFAMILY = cc13x2-cc26x2 DEVICE_FAMILY = CC13X2 -DEVICE_LINE = CC13XX +DEVICE_LINE = CC13XX +DEVICE = CC1352P BOARD_SOURCEFILES += CC1352P1_LAUNCHXL.c CC1352P1_LAUNCHXL_fxns.c -DEFINES += PROP_MODE_CONF_TX_POWER_TABLE=rf_prop_tx_power_table_default_pa -DEFINES += PROP_MODE_CONF_TX_POWER_TABLE_SIZE=RF_PROP_TX_POWER_TABLE_DEFAULT_PA_SIZE - -DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE=rf_ieee_tx_power_table_default_pa -DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE_SIZE=RF_IEEE_TX_POWER_TABLE_DEFAULT_PA_SIZE - SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 1 SUPPORTS_BLE_BEACON = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 index fc9b5c1c5..acc892e33 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Makefile.cc1352r1 @@ -1,18 +1,13 @@ ################################################################################ # SimpleLink Device makefile -SUBFAMILY = cc13x2-cc26x2 +SUBFAMILY = cc13x2-cc26x2 DEVICE_FAMILY = CC13X2 -DEVICE_LINE = CC13XX +DEVICE_LINE = CC13XX +DEVICE = CC1352R BOARD_SOURCEFILES += CC1352R1_LAUNCHXL.c CC1352R1_LAUNCHXL_fxns.c -DEFINES += PROP_MODE_CONF_TX_POWER_TABLE=rf_prop_tx_power_table_default_pa -DEFINES += PROP_MODE_CONF_TX_POWER_TABLE_SIZE=RF_PROP_TX_POWER_TABLE_DEFAULT_PA_SIZE - -DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE=rf_ieee_tx_power_table_default_pa -DEFINES += IEEE_MODE_CONF_TX_POWER_TABLE_SIZE=RF_IEEE_TX_POWER_TABLE_DEFAULT_PA_SIZE - SUPPORTS_PROP_MODE = 1 SUPPORTS_IEEE_MODE = 1 SUPPORTS_BLE_BEACON = 1 diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Makefile.cc2650 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Makefile.cc2650 index 51e402012..d03a02397 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Makefile.cc2650 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Makefile.cc2650 @@ -1,9 +1,10 @@ ################################################################################ # SimpleLink Device makefile -SUBFAMILY = cc13x0-cc26x0 +SUBFAMILY = cc13x0-cc26x0 DEVICE_FAMILY = CC26X0 -DEVICE_LINE = CC26XX +DEVICE_LINE = CC26XX +DEVICE = CC2650 BOARD_SOURCEFILES += CC2650_LAUNCHXL.c CC2650_LAUNCHXL_fxns.c diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Makefile.cc26x2r1 b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Makefile.cc26x2r1 index 16891656a..803b592c0 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Makefile.cc26x2r1 +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Makefile.cc26x2r1 @@ -1,9 +1,10 @@ ################################################################################ # SimpleLink Device makefile -SUBFAMILY = cc13x2-cc26x2 +SUBFAMILY = cc13x2-cc26x2 DEVICE_FAMILY = CC26X2 -DEVICE_LINE = CC26XX +DEVICE_LINE = CC26XX +DEVICE = CC2652R BOARD_SOURCEFILES += CC26X2R1_LAUNCHXL.c CC26X2R1_LAUNCHXL_fxns.c diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Makefile.cc1350 b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Makefile.cc1350 index 475ada460..f9b395f95 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Makefile.cc1350 +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Makefile.cc1350 @@ -1,9 +1,10 @@ ################################################################################ # SimpleLink Device makefile -SUBFAMILY = cc13x0-cc26x0 +SUBFAMILY = cc13x0-cc26x0 DEVICE_FAMILY = CC13X0 -DEVICE_LINE = CC13XX +DEVICE_LINE = CC13XX +DEVICE = CC1350 BOARD_SOURCEFILES += CC1350STK.c CC1350STK_fxns.c BOARD_SOURCEFILES += leds-arch.c diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 index 02366870d..ccee91606 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 @@ -1,9 +1,10 @@ ################################################################################ # SimpleLink Device makefile -SUBFAMILY = cc13x0-cc26x0 +SUBFAMILY = cc13x0-cc26x0 DEVICE_FAMILY = CC26X0 -DEVICE_LINE = CC26XX +DEVICE_LINE = CC26XX +DEVICE = CC1350 BOARD_SOURCEFILES += CC2650STK.c CC2650STK_fxns.c BOARD_SOURCEFILES += leds-arch.c diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 index a06b790a6..8b034de05 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Makefile.cc13x0 @@ -1,9 +1,10 @@ ################################################################################ # SimpleLink Device makefile -SUBFAMILY = cc13x0-cc26x0 +SUBFAMILY = cc13x0-cc26x0 DEVICE_FAMILY = CC13X0 -DEVICE_LINE = CC13XX +DEVICE_LINE = CC13XX +DEVICE = CC1350 BOARD_SOURCEFILES += CC1350DK_7XD.c CC1350DK_7XD_fxns.c diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Makefile.cc26x0 b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Makefile.cc26x0 index 2b8693a2a..5f554cda4 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Makefile.cc26x0 +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Makefile.cc26x0 @@ -1,9 +1,10 @@ ################################################################################ # SimpleLink Device makefile -SUBFAMILY = cc13x0-cc26x0 +SUBFAMILY = cc13x0-cc26x0 DEVICE_FAMILY = CC26X0 -DEVICE_LINE = CC26XX +DEVICE_LINE = CC26XX +DEVICE = CC2650 BOARD_SOURCEFILES += CC2650DK_7ID.c CC2650DK_7ID_fxns.c From 10ff89ba01c29d3102574af3c24782e2da43795b Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Tue, 17 Jul 2018 18:02:38 +0200 Subject: [PATCH 273/485] Fixed issue with drift in synth --- arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h | 228 +++++++++++++------- arch/cpu/cc13xx-cc26xx/ccfg-conf.h | 48 ++--- arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h | 56 +++-- arch/cpu/cc13xx-cc26xx/dev/rf-core.c | 79 +++++-- arch/cpu/cc13xx-cc26xx/dev/rf-core.h | 2 +- arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c | 48 ++--- arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c | 29 ++- 7 files changed, 306 insertions(+), 184 deletions(-) diff --git a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h index 365b1e27a..12ca00313 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h +++ b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h @@ -1,11 +1,10 @@ /* - * Copyright (c) 2017, George Oikonomou - http://www.spd.gr + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * 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 @@ -28,16 +27,15 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup cc13xx-cc26xx + * \addtogroup cc13xx-cc26xx-cpu * @{ * * \file - * Header with configuration defines common to the CC13xx/CC26xx platform. - * + * Header with configuration defines common to the CC13xx/CC26xx + * platform. * \author - * Edvard Pettersen + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #ifndef SIMPLELINK_CONF_H_ @@ -47,12 +45,20 @@ #include "rf-core.h" /*---------------------------------------------------------------------------*/ -/* GPIO HAL configuration. */ +/** + * \name GPIO HAL configuration. + * + * @{ + */ #define GPIO_HAL_CONF_ARCH_SW_TOGGLE 0 #define GPIO_HAL_CONF_ARCH_HDR_PATH "dev/gpio-hal-arch.h" - +/** @} */ /*---------------------------------------------------------------------------*/ -/* RF configuration */ +/** + * \name RF configuration. + * + * @{ + */ /* * If set, the systems keeps the HF crystal oscillator on even when the @@ -65,96 +71,124 @@ # define RF_FAST_RADIO_STARTUP 0 #endif +/* + * Configure TX power to either default PA or High PA, defaults to + * default PA. + */ +#ifndef RF_CONF_TXPOWER_HIGH_PA +#define RF_CONF_TXPOWER_HIGH_PA 0 +#endif + +#if (RF_CONF_TXPOWER_HIGH_PA) && !(SUPPORTS_HIGH_PA) +# error "Device does not support High PA" +#endif + +/* + * CC13xx only: Configure TX power to use boot mode, allowing to gain + * up to 14 dBm with the default PA. This will, however, increase power + * consumption. + */ +#ifndef RF_CONF_TXPOWER_BOOST_MODE +#define RF_CONF_TXPOWER_BOOST_MODE 0 +#endif + /* * Configure RF mode. That is, whether to run on Sub-1 GHz (Prop-mode) or * 2.4 GHz (IEEE-mode). */ #ifdef RF_CONF_MODE -/* Sanity check a valid configuration is given */ +/* Sanity check a valid configuration is provided. */ # if !(RF_CONF_MODE & RF_MODE_BM) -# error "Invalid RF_CONF_MODE" +# error "Invalid RF_CONF_MODE provided" # endif -# define RF_MODE RF_CONF_MODE +# define RF_MODE RF_CONF_MODE #endif /* RF_CONF_MODE */ -/* Number of RX buffers */ +/* Number of RX buffers. */ #ifdef RF_CONF_RX_BUF_CNT -# define RF_RX_BUF_CNT RF_CONF_RX_BUF_CNT +# define RF_RX_BUF_CNT RF_CONF_RX_BUF_CNT #else -# define RF_RX_BUF_CNT 4 +# define RF_RX_BUF_CNT 4 #endif -/* Size of each RX buffer in bytes */ +/* Size of each RX buffer in bytes. */ #ifdef RF_CONF_RX_BUF_SIZE -# define RF_RX_BUF_SIZE RF_CONF_RX_BUF_SIZE +# define RF_RX_BUF_SIZE RF_CONF_RX_BUF_SIZE #else -# define RF_RX_BUF_SIZE 144 +# define RF_RX_BUF_SIZE 144 #endif -/* Enable/disable BLE beacon */ +/* Enable/disable BLE beacon. */ #ifdef RF_CONF_BLE_BEACON_ENABLE -# define RF_BLE_BEACON_ENABLE RF_CONF_BLE_BEACON_ENABLE +# define RF_BLE_BEACON_ENABLE RF_CONF_BLE_BEACON_ENABLE #else -# define RF_BLE_BEACON_ENABLE 0 +# define RF_BLE_BEACON_ENABLE 0 +#endif + +#if (RF_BLE_BEACON_ENABLE) && !(SUPPORTS_BLE_BEACON) +# error "Device does not support BLE for BLE beacon" #endif /*----- CC13xx Device Line --------------------------------------------------*/ -/* CC13xx supports both IEEE and Prop mode, depending on which device */ +/* CC13xx supports both IEEE and Prop mode, depending on which device. */ #if defined(DEVICE_LINE_CC13XX) -/* Default to Prop-mode for CC13xx devices if not configured */ +/* Default to Prop-mode for CC13xx devices if not configured. */ # ifndef RF_MODE -# define RF_MODE RF_MODE_SUB_1_GHZ +# define RF_MODE RF_MODE_SUB_1_GHZ # endif +/*----- CC13xx Prop-mode ----------------------------------------------------*/ # if (RF_MODE == RF_MODE_SUB_1_GHZ) && (SUPPORTS_PROP_MODE) -/*----- CC13xx Prop Mode ----------------------------------------------------*/ -/* Netstack configuration */ -# define NETSTACK_CONF_RADIO prop_mode_driver -/* CSMA configuration */ -# define CSMA_CONF_ACK_WAIT_TIME (RTIMER_SECOND / 300) -# define CSMA_CONF_AFTER_ACK_DETECTED_WAIT_TIME (RTIMER_SECOND / 1000) -# define CSMA_CONF_SEND_SOFT_ACK 1 +/* Netstack configuration. */ +# define NETSTACK_CONF_RADIO prop_mode_driver +/* CSMA configuration. */ +# define CSMA_CONF_ACK_WAIT_TIME (RTIMER_SECOND / 300) +# define CSMA_CONF_AFTER_ACK_DETECTED_WAIT_TIME (RTIMER_SECOND / 1000) +# define CSMA_CONF_SEND_SOFT_ACK 1 + +/*----- CC13xx IEEE-mode ----------------------------------------------------*/ # elif (RF_MODE == RF_MODE_2_4_GHZ) && (SUPPORTS_IEEE_MODE) -/*----- CC13xx IEEE Mode ----------------------------------------------------*/ -/* Netstack configuration */ -# define NETSTACK_CONF_RADIO ieee_mode_driver -/* CSMA configuration */ -# define CSMA_CONF_SEND_SOFT_ACK 0 +/* Netstack configuration. */ +# define NETSTACK_CONF_RADIO ieee_mode_driver + +/* CSMA configuration. */ +# define CSMA_CONF_SEND_SOFT_ACK 0 # else -/*----- CC13xx Non-supported Mode -------------------------------------------*/ -# error "Invalid radio mode configuration of CC13xx device" +/*----- CC13xx Unsupported Mode ---------------------------------------------*/ +# error "Invalid RF mode configuration of CC13xx device" # endif /* CC13xx RF Mode configuration */ /*----- CC26xx Device Line --------------------------------------------------*/ /* CC26xx only supports IEEE mode */ #elif defined(DEVICE_LINE_CC26XX) -/* Default to IEEE-mode for CC13xx devices if not configured */ +/* Default to IEEE-mode for CC26xx devices if not configured */ # ifndef RF_MODE -# define RF_MODE RF_MODE_2_4_GHZ +# define RF_MODE RF_MODE_2_4_GHZ # endif +/*----- CC26xx IEEE-mode ----------------------------------------------------*/ # if (RF_MODE == RF_MODE_2_4_GHZ) && (SUPPORTS_IEEE_MODE) -/*----- CC26xx IEEE Mode ----------------------------------------------------*/ + /* Netstack configuration */ -# define NETSTACK_CONF_RADIO ieee_mode_driver +# define NETSTACK_CONF_RADIO ieee_mode_driver /* CSMA configuration */ -# define CSMA_CONF_SEND_SOFT_ACK 0 +# define CSMA_CONF_SEND_SOFT_ACK 0 /* Frequncy band configuration */ -# undef DOT_15_4G_FREQ_BAND_ID -# define DOT_15_4G_CONF_FREQ_BAND_ID DOT_15_4G_FREQ_BAND_2450 +# undef DOT_15_4G_FREQ_BAND_ID +# define DOT_15_4G_CONF_FREQ_BAND_ID DOT_15_4G_FREQ_BAND_2450 # else -/*----- CC26xx Non-supported Mode -------------------------------------------*/ -# error "IEEE mode only supported by CC26xx devices" +/*----- CC26xx Unsupported Mode ---------------------------------------------*/ +# error "IEEE-mode only supported by CC26xx devices" # endif /* CC26xx RF Mode configuration */ /*----- Unsupported device line ---------------------------------------------*/ @@ -165,23 +199,23 @@ /** @} */ /*---------------------------------------------------------------------------*/ /** - * \name IEEE address configuration - * - * Used to generate our link-local & IPv6 address + * \name IEEE address configuration. Used to generate our link-local and + * global IPv6 addresses. * @{ */ + /** - * \brief Location of the IEEE address - * 0 => Read from InfoPage, - * 1 => Use a hardcoded address, configured by IEEE_ADDR_CONF_ADDRESS + * \brief Location of the IEEE address. + * 0 => Read from InfoPage. + * 1 => Use a hardcoded address, configured by IEEE_ADDR_CONF_ADDRESS. */ #ifndef IEEE_ADDR_CONF_HARDCODED #define IEEE_ADDR_CONF_HARDCODED 0 #endif /** - * \brief The hardcoded IEEE address to be used when IEEE_ADDR_CONF_HARDCODED - * is defined as 1 + * \brief The hardcoded IEEE address to be used when IEEE_ADDR_CONF_HARDCODED + * is defined as 1. Must be a byte array of size 8. */ #ifndef IEEE_ADDR_CONF_ADDRESS #define IEEE_ADDR_CONF_ADDRESS { 0x00, 0x12, 0x4B, 0x00, 0x89, 0xAB, 0xCD, 0xEF } @@ -189,107 +223,157 @@ /** @} */ /*---------------------------------------------------------------------------*/ /** - * \name RF configuration + * \name IEEE-mode configuration. * * @{ */ -/* RF Config */ +/** + * \brief Configure auto-ACK for IEEE-mode, which is ACK generated by the + * radio. + * 0 => ACK generated by software + * 1 => ACK generated by the radio. + */ #ifndef IEEE_MODE_CONF_AUTOACK #define IEEE_MODE_CONF_AUTOACK 1 /**< RF H/W generates ACKs */ #endif +/** + * \brief Configure promiscouos mode for IEEE-mode. + */ #ifndef IEEE_MODE_CONF_PROMISCOUS #define IEEE_MODE_CONF_PROMISCOUS 0 /**< 1 to enable promiscous mode */ #endif /** @} */ /*---------------------------------------------------------------------------*/ /** - * \name TI Drivers Configuration + * \name TI Drivers Configuration. * * @{ */ -/* UART */ +/** + * \brief Enable or disable UART driver. + */ #ifndef TI_UART_CONF_ENABLE #define TI_UART_CONF_ENABLE 1 #endif +/** + * \brief Enable or disable UART0 peripheral. + */ #ifndef TI_UART_CONF_UART0_ENABLE #define TI_UART_CONF_UART0_ENABLE TI_UART_CONF_ENABLE #endif +/** + * \brief Enable or disable UART1 peripheral. + */ #ifndef TI_UART_CONF_UART1_ENABLE #define TI_UART_CONF_UART1_ENABLE 0 #endif +/** + * \brief UART driver baud rate configuration. + */ #ifndef TI_UART_CONF_BAUD_RATE #define TI_UART_CONF_BAUD_RATE 115200 #endif -/* SPI */ +/** + * \brief Enable or disable SPI driver. + */ #ifndef TI_SPI_CONF_ENABLE -#define TI_SPI_CONF_ENABLE 1 +#define TI_SPI_CONF_ENABLE 0 #endif +/** + * \brief Enable or disable SPI0 peripheral. + */ #ifndef TI_SPI_CONF_SPI0_ENABLE #define TI_SPI_CONF_SPI0_ENABLE TI_SPI_CONF_ENABLE #endif +/** + * \brief Enable or disable SPI1 peripheral. + */ #ifndef TI_SPI_CONF_SPI1_ENABLE #define TI_SPI_CONF_SPI1_ENABLE 0 #endif -/* I2C */ +/** + * \brief Enable or disable I2C driver. + */ #ifndef TI_I2C_CONF_ENABLE -#define TI_I2C_CONF_ENABLE 1 +#define TI_I2C_CONF_ENABLE 0 #endif +/** + * \brief Enable or disable I2C0 peripheral. + */ #ifndef TI_I2C_CONF_I2C0_ENABLE #define TI_I2C_CONF_I2C0_ENABLE TI_I2C_CONF_ENABLE #endif -/* NVS */ +/** + * \brief Enable or disable Non-Volatile Storage (NVS) driver. + */ #ifndef TI_NVS_CONF_ENABLE -#define TI_NVS_CONF_ENABLE 1 +#define TI_NVS_CONF_ENABLE 0 #endif +/** + * \brief Enable or disable internal flash storage. + */ #ifndef TI_NVS_CONF_NVS_INTERNAL_ENABLE #define TI_NVS_CONF_NVS_INTERNAL_ENABLE TI_NVS_CONF_ENABLE #endif +/** + * \brief Enable or disable external flash storage. + */ #ifndef TI_NVS_CONF_NVS_EXTERNAL_ENABLE #define TI_NVS_CONF_NVS_EXTERNAL_ENABLE TI_NVS_CONF_ENABLE #endif -/* Display */ +/** + * \brief Enable or disable Display driver. + */ #ifndef TI_DISPLAY_CONF_ENABLE #define TI_DISPLAY_CONF_ENABLE 0 #endif -/* UART Display uses UART0 */ +/** + * \brief Enable or disable UART Display peripheral. + */ #ifndef TI_DISPLAY_CONF_UART_ENABLE #define TI_DISPLAY_CONF_UART_ENABLE TI_UART_CONF_UART0_ENABLE #endif +/** + * \brief Configure UART Display peripheral to use ANSI or not. + */ #ifndef TI_DISPLAY_CONF_USE_UART_ANSI #define TI_DISPLAY_CONF_USE_UART_ANSI 0 #endif -/* LCD Display uses SPI0 */ +/** + * \brief Enable or disable LCD Display peripheral. + */ #ifndef TI_DISPLAY_CONF_LCD_ENABLE #define TI_DISPLAY_CONF_LCD_ENABLE TI_SPI_CONF_SPI0_ENABLE #endif -/* SD card */ +/** + * \brief Enable or disable SD driver. + */ #ifndef TI_SD_CONF_ENABLE #define TI_SD_CONF_ENABLE 0 #endif - /** @} */ /*---------------------------------------------------------------------------*/ /** - * \name Misc. Configuration + * \name Slip configuration * * @{ */ diff --git a/arch/cpu/cc13xx-cc26xx/ccfg-conf.h b/arch/cpu/cc13xx-cc26xx/ccfg-conf.h index 9c1cf3263..ce7eff3d4 100644 --- a/arch/cpu/cc13xx-cc26xx/ccfg-conf.h +++ b/arch/cpu/cc13xx-cc26xx/ccfg-conf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Alex Stanoev + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,13 +27,14 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup cc13xx-cc26xx + * \addtogroup cc13xx-cc26xx-cpu * @{ * * \file - * Customer Configuration (CCFG) for the cc13xx-cc26xx CPU family + * Customer Configuration (CCFG) for the CC13xx/CC26xx CPU family. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #ifndef CCFG_CONF_H_ @@ -50,14 +51,14 @@ * @{ */ #if CCFG_CONF_JTAG_INTERFACE_DISABLE -# define SET_CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE 0x00 -# define SET_CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE 0x00 -# define SET_CCFG_CCFG_TAP_DAP_0_PRCM_TAP_ENABLE 0x00 -# define SET_CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE 0x00 -# define SET_CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE 0x00 -# define SET_CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE 0x00 -# define SET_CCFG_CCFG_TAP_DAP_1_WUC_TAP_ENABLE 0x00 -#endif /* CCFG_CONF_JTAG_INTERFACE_DISABLE */ +# define SET_CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE 0x00 +# define SET_CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE 0x00 +# define SET_CCFG_CCFG_TAP_DAP_0_PRCM_TAP_ENABLE 0x00 +# define SET_CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE 0x00 +# define SET_CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE 0x00 +# define SET_CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE 0x00 +# define SET_CCFG_CCFG_TAP_DAP_1_WUC_TAP_ENABLE 0x00 +#endif /** @} */ /*---------------------------------------------------------------------------*/ /** @@ -67,36 +68,35 @@ * output power with the default PA front-end configuration. * @{ */ -#if defined(DEVICE_LINE_CC13XX) && CC13XX_CONF_TXPOWER_BOOST_MODE -# define CCFG_FORCE_VDDR_HH 1 -#endif /* CCFG_CONF_TXPOWER_BOOST_MODE */ +#if defined(DEVICE_LINE_CC13XX) && (RF_CONF_TXPOWER_BOOST_MODE) +# define CCFG_FORCE_VDDR_HH 1 +#endif /** @} */ /*---------------------------------------------------------------------------*/ /** * \name ROM Bootloader configuration * * Enable/Disable the ROM bootloader in your image, if the board supports it. - * Look in board.h to choose the DIO and corresponding level that will cause + * Look in Board.h to choose the DIO and corresponding level that will cause * the chip to enter bootloader mode. * @{ */ #ifndef CCFG_CONF_ROM_BOOTLOADER_ENABLE -#define CCFG_CONF_ROM_BOOTLOADER_ENABLE 0 +#define CCFG_CONF_ROM_BOOTLOADER_ENABLE 0 #endif #if CCFG_CONF_ROM_BOOTLOADER_ENABLE -# define SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE 0xC5 -# define SET_CCFG_BL_CONFIG_BL_LEVEL 0x00 -# if defined(CCFG_CONF_BL_PIN_NUMBER) -# define SET_CCFG_BL_CONFIG_BL_PIN_NUMBER CCFG_CONF_BL_PIN_NUMBER -# endif -# define SET_CCFG_BL_CONFIG_BL_ENABLE 0xC5 +# define SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE 0xC5 +# define SET_CCFG_BL_CONFIG_BL_LEVEL 0x00 +# if defined(CCFG_CONF_BL_PIN_NUMBER) +# define SET_CCFG_BL_CONFIG_BL_PIN_NUMBER CCFG_CONF_BL_PIN_NUMBER +# endif +# define SET_CCFG_BL_CONFIG_BL_ENABLE 0xC5 #endif /** @} */ /*---------------------------------------------------------------------------*/ #endif /* CCFG_CONF_H_ */ /*---------------------------------------------------------------------------*/ /** - * @} * @} */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h b/arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h index e12fe2ffc..bb99d39c4 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h +++ b/arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h @@ -45,10 +45,13 @@ #define DOT_15_4G_H_ /*---------------------------------------------------------------------------*/ #include "contiki.h" - +/*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) /*---------------------------------------------------------------------------*/ +#include +#include +/*---------------------------------------------------------------------------*/ /* IEEE 802.15.4g frequency band identifiers (Table 68f) */ #define DOT_15_4G_FREQ_BAND_169 0 /* 169.400–169.475 (Europe) - 169 MHz band */ #define DOT_15_4G_FREQ_BAND_450 1 /* 450–470 (US FCC Part 22/90) - 450 MHz band */ @@ -79,76 +82,89 @@ * * DOT_15_4G_CHAN0_FREQ is specified here in KHz */ -#if DOT_15_4G_FREQ_BAND_ID==DOT_15_4G_FREQ_BAND_470 +#if (DOT_15_4G_FREQ_BAND_ID == DOT_15_4G_FREQ_BAND_470) # define DOT_15_4G_CHAN_MIN 0 # define DOT_15_4G_CHAN_MAX 198 # define DOT_15_4G_FREQ_SPACING 200 # define DOT_15_4G_CHAN0_FREQ 470200 +# define PROP_MODE_CONF_CENTER_FREQ 0x01EA # define PROP_MODE_CONF_LO_DIVIDER 0x0A -#elif DOT_15_4G_FREQ_BAND_ID==DOT_15_4G_FREQ_BAND_780 +#elif (DOT_15_4G_FREQ_BAND_ID == DOT_15_4G_FREQ_BAND_780) # define DOT_15_4G_CHAN_MIN 0 # define DOT_15_4G_CHAN_MAX 38 # define DOT_15_4G_FREQ_SPACING 200 # define DOT_15_4G_CHAN0_FREQ 779200 +# define PROP_MODE_CONF_CENTER_FREQ 0x030F # define PROP_MODE_CONF_LO_DIVIDER 0x06 -#elif DOT_15_4G_FREQ_BAND_ID==DOT_15_4G_FREQ_BAND_863 +#elif (DOT_15_4G_FREQ_BAND_ID == DOT_15_4G_FREQ_BAND_863) # define DOT_15_4G_CHAN_MIN 0 # define DOT_15_4G_CHAN_MAX 33 # define DOT_15_4G_FREQ_SPACING 200 # define DOT_15_4G_CHAN0_FREQ 863125 +# define PROP_MODE_CONF_CENTER_FREQ 0x0362 # define PROP_MODE_CONF_LO_DIVIDER 0x05 -#elif DOT_15_4G_FREQ_BAND_ID==DOT_15_4G_FREQ_BAND_915 +#elif (DOT_15_4G_FREQ_BAND_ID == DOT_15_4G_FREQ_BAND_915) # define DOT_15_4G_CHAN_MIN 0 # define DOT_15_4G_CHAN_MAX 128 # define DOT_15_4G_FREQ_SPACING 200 # define DOT_15_4G_CHAN0_FREQ 902200 +# define PROP_MODE_CONF_CENTER_FREQ 0x0393 # define PROP_MODE_CONF_LO_DIVIDER 0x05 -#elif DOT_15_4G_FREQ_BAND_ID==DOT_15_4G_FREQ_BAND_920 +#elif (DOT_15_4G_FREQ_BAND_ID == DOT_15_4G_FREQ_BAND_920) # define DOT_15_4G_CHAN_MIN 0 # define DOT_15_4G_CHAN_MAX 37 # define DOT_15_4G_FREQ_SPACING 200 # define DOT_15_4G_CHAN0_FREQ 920600 +# define PROP_MODE_CONF_CENTER_FREQ 0x039C # define PROP_MODE_CONF_LO_DIVIDER 0x05 -#elif DOT_15_4G_FREQ_BAND_ID==DOT_15_4G_FREQ_BAND_950 +#elif (DOT_15_4G_FREQ_BAND_ID == DOT_15_4G_FREQ_BAND_950) # define DOT_15_4G_CHAN_MIN 0 # define DOT_15_4G_CHAN_MAX 32 # define DOT_15_4G_FREQ_SPACING 200 # define DOT_15_4G_CHAN0_FREQ 951000 +# define PROP_MODE_CONF_CENTER_FREQ 0x03BA # define PROP_MODE_CONF_LO_DIVIDER 0x05 -#elif DOT_15_4G_FREQ_BAND_ID==DOT_15_4G_FREQ_BAND_2450 +#elif (DOT_15_4G_FREQ_BAND_ID == DOT_15_4G_FREQ_BAND_2450) # define DOT_15_4G_CHAN_MIN 11 # define DOT_15_4G_CHAN_MAX 26 # define DOT_15_4G_FREQ_SPACING 5000 # define DOT_15_4G_CHAN0_FREQ 2405000 #else -# error The selected IEEE 802.15.4g frequency band is not supported +# error "The selected IEEE 802.15.4g frequency band is not supported" #endif /*---------------------------------------------------------------------------*/ -#define DOT_15_4_G_FREQ(chan) \ - (DOT_15_4G_CHAN0_FREQ + DOT_15_4G_FREQ_SPACING * ((chan) - DOT_15_4G_CHAN_MIN)) - -#define DOT_15_4_G_CHAN_IN_RANGE(chan) \ - (((chan) >= DOT_15_4G_CHAN_MIN) && ((chan) <= DOT_15_4G_CHAN_MAX)) +static inline uint32_t +dot_15_4g_freq(const uint16_t chan) +{ + const uint32_t chan0 = DOT_15_4G_CHAN0_FREQ; + const uint32_t spacing = DOT_15_4G_FREQ_SPACING; + const uint32_t chan_min = DOT_15_4G_CHAN_MIN; + return (chan0 + spacing * ((uint32_t)chan - chan_min)); +} /*---------------------------------------------------------------------------*/ -#define DOT_15_4_G_DEFAULT_CHAN IEEE802154_DEFAULT_CHANNEL - -/* Sanity check default channel */ -#if !(DOT_15_4_G_CHAN_IN_RANGE(DOT_15_4_G_DEFAULT_CHAN)) -# error IEEE802154_DEFAULT_CHANNEL is not in valid channel range -#endif +static inline bool +dot_15_4g_chan_in_range(const uint16_t chan) +{ + const uint16_t chan_min = DOT_15_4G_CHAN_MIN; + const uint16_t chan_max = DOT_15_4G_CHAN_MAX; + return ((chan >= chan_min) && + (chan <= chan_max)); +} +/*---------------------------------------------------------------------------*/ +#define DOT_15_4G_DEFAULT_CHAN IEEE802154_DEFAULT_CHANNEL /*---------------------------------------------------------------------------*/ #endif /* DOT_15_4G_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-core.c b/arch/cpu/cc13xx-cc26xx/dev/rf-core.c index ebe34effa..027552631 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-core.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-core.c @@ -39,6 +39,7 @@ #include "contiki.h" #include "dev/watchdog.h" #include "sys/cc.h" +#include "sys/etimer.h" #include "sys/process.h" #include "sys/energest.h" #include "net/netstack.h" @@ -60,10 +61,10 @@ #include #include /*---------------------------------------------------------------------------*/ -#if 0 -# define PRINTF(...) -#else +#if 1 # define PRINTF(...) printf(__VA_ARGS__) +#else +# define PRINTF(...) #endif /*---------------------------------------------------------------------------*/ #define CMD_FS_RETRIES 3 @@ -78,11 +79,17 @@ #define EVENTS_CMD_DONE(events) (((events) & RF_EVENTS_CMD_DONE) != 0) /*---------------------------------------------------------------------------*/ +/* Synth re-calibration every 3 minutes */ +#define SYNTH_RECAL_INTERVAL (CLOCK_SECOND * 60 * 3) + +static struct etimer synth_recal_timer; +/*---------------------------------------------------------------------------*/ static RF_Object rf_netstack; static RF_Object rf_ble; static RF_CmdHandle cmd_rx_handle; +static bool rf_is_on; static volatile bool rx_buf_full; /*---------------------------------------------------------------------------*/ static void @@ -180,6 +187,9 @@ rf_yield(void) ENERGEST_OFF(ENERGEST_TYPE_LISTEN); + etimer_stop(&synth_recal_timer); + rf_is_on = false; + return RF_RESULT_OK; } /*---------------------------------------------------------------------------*/ @@ -285,7 +295,7 @@ netstack_sched_ieee_tx(bool recieve_ack) * chained TX command. */ if (rx_ack_required) { - res = netstack_sched_rx(); + res = netstack_sched_rx(false); if (res != RF_RESULT_OK) { return res; } @@ -393,7 +403,7 @@ netstack_sched_prop_tx(void) } /*---------------------------------------------------------------------------*/ rf_result_t -netstack_sched_rx(void) +netstack_sched_rx(bool start) { if (cmd_rx_is_active()) { PRINTF("netstack_sched_rx: already in RX\n"); @@ -424,6 +434,11 @@ netstack_sched_rx(void) ENERGEST_ON(ENERGEST_TYPE_LISTEN); + if (start) { + rf_is_on = true; + process_poll(&rf_core_process); + } + return RF_RESULT_OK; } /*---------------------------------------------------------------------------*/ @@ -502,27 +517,47 @@ PROCESS_THREAD(rf_core_process, ev, data) PROCESS_BEGIN(); while(1) { - PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL); + PROCESS_YIELD_UNTIL((ev == PROCESS_EVENT_POLL) || + etimer_expired(&synth_recal_timer)); - do { - //watchdog_periodic(); - packetbuf_clear(); - len = NETSTACK_RADIO.read(packetbuf_dataptr(), PACKETBUF_SIZE); + if (ev == PROCESS_EVENT_POLL) { + do { + watchdog_periodic(); + packetbuf_clear(); + len = NETSTACK_RADIO.read(packetbuf_dataptr(), PACKETBUF_SIZE); - if (rx_buf_full) { - PRINTF("rf_core: RX buf full, restart RX\n"); - rx_buf_full = false; - /* Restart RX */ - netstack_stop_rx(); - netstack_sched_rx(); - } + /* + * RX will stop if the RX buffers are full. In this case, restart + * RX after we've freed at least on packet. + */ + if (rx_buf_full) { + PRINTF("rf_core: RX buf full, restart RX\n"); + rx_buf_full = false; - if(len > 0) { - packetbuf_set_datalen(len); + /* Restart RX. */ + netstack_stop_rx(); + netstack_sched_rx(false); + } - NETSTACK_MAC.input(); - } - } while(len > 0); + if(len > 0) { + packetbuf_set_datalen(len); + + NETSTACK_MAC.input(); + } + } while(len > 0); + } + + /* start the synth re-calibration timer once. */ + if (rf_is_on) { + rf_is_on = false; + etimer_set(&synth_recal_timer, SYNTH_RECAL_INTERVAL); + } + /* Scheduling CMD_FS will re-calibrate the synth. */ + if (etimer_expired(&synth_recal_timer)) { + netstack_sched_fs(); + + etimer_reset(&synth_recal_timer); + } } PROCESS_END(); } diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-core.h b/arch/cpu/cc13xx-cc26xx/dev/rf-core.h index ad789c8e1..fa27ebf62 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-core.h +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-core.h @@ -78,7 +78,7 @@ RF_Handle netstack_open(RF_Params *params); rf_result_t netstack_sched_fs(void); rf_result_t netstack_sched_ieee_tx(bool recieve_ack); rf_result_t netstack_sched_prop_tx(void); -rf_result_t netstack_sched_rx(void); +rf_result_t netstack_sched_rx(bool start); rf_result_t netstack_stop_rx(void); /*---------------------------------------------------------------------------*/ /* BLE radio: BLE Beacon Daemon */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c index 177415290..60c806d24 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c @@ -78,7 +78,7 @@ #include #include /*---------------------------------------------------------------------------*/ -#if 0 +#if 1 # define PRINTF(...) #else # define PRINTF(...) printf(__VA_ARGS__) @@ -106,23 +106,13 @@ #else # define IEEE_MODE_RSSI_THRESHOLD 0xA6 #endif /* IEEE_MODE_CONF_RSSI_THRESHOLD */ - -/* Configuration for TX power table */ -#ifdef IEEE_MODE_CONF_TX_POWER_TABLE -# define TX_POWER_TABLE IEEE_MODE_CONF_TX_POWER_TABLE -#else -# define TX_POWER_TABLE rf_ieee_tx_power_table -#endif - -#ifdef IEEE_MODE_CONF_TX_POWER_TABLE_SIZE -# define TX_POWER_TABLE_SIZE IEEE_MODE_CONF_TX_POWER_TABLE_SIZE -#else -# define TX_POWER_TABLE_SIZE RF_IEEE_TX_POWER_TABLE_SIZE -#endif /*---------------------------------------------------------------------------*/ /* TX power table convenience macros */ -#define TX_POWER_MIN (TX_POWER_TABLE[0].power) -#define TX_POWER_MAX (TX_POWER_TABLE[TX_POWER_TABLE_SIZE - 1].power) +#define TX_POWER_TABLE rf_ieee_tx_power_table +#define TX_POWER_TABLE_SIZE rf_ieee_tx_power_table_size + +#define TX_POWER_MIN (TX_POWER_TABLE[0].power) +#define TX_POWER_MAX (TX_POWER_TABLE[TX_POWER_TABLE_SIZE - 1].power) #define TX_POWER_IN_RANGE(dbm) (((dbm) >= TX_POWER_MIN) && ((dbm) <= TX_POWER_MAX)) /*---------------------------------------------------------------------------*/ @@ -310,10 +300,10 @@ init_rf_params(void) static rf_result_t set_channel(uint8_t channel) { - if (!DOT_15_4_G_CHAN_IN_RANGE(channel)) { + if (!dot_15_4g_chan_in_range(channel)) { PRINTF("set_channel: illegal channel %d, defaults to %d\n", - (int)channel, DOT_15_4_G_DEFAULT_CHAN); - channel = DOT_15_4_G_DEFAULT_CHAN; + (int)channel, DOT_15_4G_DEFAULT_CHAN); + channel = DOT_15_4G_DEFAULT_CHAN; } /* @@ -328,7 +318,7 @@ set_channel(uint8_t channel) cmd_rx.channel = channel; - const uint32_t new_freq = (uint32_t)DOT_15_4_G_FREQ(channel); + const uint32_t new_freq = dot_15_4g_freq(channel); const uint16_t freq = (uint16_t)(new_freq / 1000); const uint16_t frac = (uint16_t)(((new_freq - (freq * 1000)) * 0x10000) / 1000); @@ -428,7 +418,7 @@ init(void) return RF_RESULT_ERROR; } - set_channel(DOT_15_4_G_DEFAULT_CHAN); + set_channel(DOT_15_4G_DEFAULT_CHAN); ENERGEST_ON(ENERGEST_TYPE_LISTEN); @@ -598,7 +588,7 @@ cca_request(cmd_cca_req_t *cmd_cca_req) const bool rx_is_idle = !rx_is_active(); if (rx_is_idle) { - res = netstack_sched_rx(); + res = netstack_sched_rx(false); if (res != RF_RESULT_OK) { return RF_RESULT_ERROR; } @@ -700,7 +690,7 @@ on(void) data_queue_reset(); - res = netstack_sched_rx(); + res = netstack_sched_rx(true); if (res != RF_RESULT_OK) { return RF_RESULT_ERROR; @@ -854,7 +844,7 @@ set_value(radio_param_t param, radio_value_t value) /* Channel */ case RADIO_PARAM_CHANNEL: - if (!DOT_15_4_G_CHAN_IN_RANGE(value)) { + if (!dot_15_4g_chan_in_range(value)) { return RADIO_RESULT_INVALID_VALUE; } set_channel((uint8_t)value); @@ -868,7 +858,7 @@ set_value(radio_param_t param, radio_value_t value) } netstack_stop_rx(); - res = netstack_sched_rx(); + res = netstack_sched_rx(false); return (res == RF_RESULT_OK) ? RADIO_RESULT_OK : RADIO_RESULT_ERROR; @@ -881,7 +871,7 @@ set_value(radio_param_t param, radio_value_t value) } netstack_stop_rx(); - res = netstack_sched_rx(); + res = netstack_sched_rx(false); return (res == RF_RESULT_OK) ? RADIO_RESULT_OK : RADIO_RESULT_ERROR; @@ -920,7 +910,7 @@ set_value(radio_param_t param, radio_value_t value) } netstack_stop_rx(); - res = netstack_sched_rx(); + res = netstack_sched_rx(false); return (res == RF_RESULT_OK) ? RADIO_RESULT_OK : RADIO_RESULT_ERROR; @@ -952,7 +942,7 @@ set_value(radio_param_t param, radio_value_t value) } netstack_stop_rx(); - res = netstack_sched_rx(); + res = netstack_sched_rx(false); return (res == RF_RESULT_OK) ? RADIO_RESULT_OK : RADIO_RESULT_ERROR; @@ -1028,7 +1018,7 @@ set_object(radio_param_t param, const void *src, size_t size) } netstack_stop_rx(); - res = netstack_sched_rx(); + res = netstack_sched_rx(false); return (res == RF_RESULT_OK) ? RADIO_RESULT_OK : RADIO_RESULT_ERROR; diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c index 490459292..2451bd0e7 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c @@ -136,15 +136,9 @@ /* How long to wait for the rx read entry to become ready */ #define TIMEOUT_DATA_ENTRY_BUSY (RTIMER_SECOND / 250) /*---------------------------------------------------------------------------*/ -/* Configuration for TX power table */ -#ifdef PROP_MODE_CONF_TX_POWER_TABLE -# define TX_POWER_TABLE PROP_MODE_CONF_TX_POWER_TABLE -#else -# define TX_POWER_TABLE rf_prop_tx_power_table -#endif -/*---------------------------------------------------------------------------*/ /* TX power table convenience macros */ -#define TX_POWER_TABLE_SIZE ((sizeof(TX_POWER_TABLE) / sizeof(TX_POWER_TABLE[0])) - 1) +#define TX_POWER_TABLE rf_prop_tx_power_table +#define TX_POWER_TABLE_SIZE rf_prop_tx_power_table_size #define TX_POWER_MIN (TX_POWER_TABLE[0].power) #define TX_POWER_MAX (TX_POWER_TABLE[TX_POWER_TABLE_SIZE - 1].power) @@ -208,11 +202,14 @@ static int off(void); static void init_rf_params(void) { + cmd_radio_setup.centerFreq = PROP_MODE_CONF_CENTER_FREQ; + cmd_radio_setup.loDivider = PROP_MODE_CONF_LO_DIVIDER; + data_queue_t *data_queue = data_queue_init(sizeof(lensz_t)); cmd_rx.maxPktLen = DOT_4G_MAX_FRAME_LEN - cmd_rx.lenOffset; - cmd_rx.pQueue = data_queue; - cmd_rx.pOutput = (uint8_t *)&prop_radio.rx_stats; + cmd_rx.pQueue = data_queue; + cmd_rx.pOutput = (uint8_t *)&prop_radio.rx_stats; } /*---------------------------------------------------------------------------*/ static int8_t @@ -223,7 +220,7 @@ get_rssi(void) const bool rx_is_idle = !rx_is_active(); if (rx_is_idle) { - res = netstack_sched_rx(); + res = netstack_sched_rx(false); if (res != RF_RESULT_OK) { return RF_GET_RSSI_ERROR_VAL; } @@ -266,10 +263,10 @@ set_channel(uint16_t channel) { rf_result_t res; - if (!DOT_15_4_G_CHAN_IN_RANGE(channel)) { + if (!dot_15_4g_chan_in_range(channel)) { PRINTF("set_channel: illegal channel %d, defaults to %d\n", - (int)channel, IEEE802154_DEFAULT_CHANNEL); - channel = IEEE802154_DEFAULT_CHANNEL; + (int)channel, DOT_15_4G_DEFAULT_CHAN); + channel = DOT_15_4G_DEFAULT_CHAN; } if (channel == prop_radio.channel) { @@ -277,7 +274,7 @@ set_channel(uint16_t channel) return RF_RESULT_OK; } - const uint32_t new_freq = DOT_15_4_G_FREQ(channel); + const uint32_t new_freq = dot_15_4g_freq(channel); const uint16_t freq = (uint16_t)(new_freq / 1000); const uint16_t frac = (uint16_t)(((new_freq - (freq * 1000)) * 0x10000) / 1000); @@ -513,7 +510,7 @@ on(void) data_queue_reset(); - res = netstack_sched_rx(); + res = netstack_sched_rx(true); if (res != RF_RESULT_OK) { return RF_RESULT_ERROR; From 8fb9b621400e3a4cf8f1c03da337ce9e35684d10 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Tue, 17 Jul 2018 18:02:55 +0200 Subject: [PATCH 274/485] Slight naming refactoring --- arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c | 34 ++++++++++++------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c b/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c index 7a00d55f2..7e2f70cfe 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c @@ -49,38 +49,38 @@ /*---------------------------------------------------------------------------*/ static UART_Handle gh_uart; -static volatile uart0_input_cb g_input_cb; -static unsigned char g_char_buf; +static volatile uart0_input_cb curr_input_cb; +static unsigned char char_buf; -static bool g_bIsInit = false; +static bool is_init; /*---------------------------------------------------------------------------*/ static void uart0_cb(UART_Handle handle, void *buf, size_t count) { - if (!g_input_cb) { return; } + if (!curr_input_cb) { return; } /* * Save the current callback function, as this might be overwritten after * the callback is called. */ - const uart0_input_cb currCb = g_input_cb; - /* Call the callback. Note this might reset g_input_cb */ - currCb(g_char_buf); + const uart0_input_cb currCb = curr_input_cb; + /* Call the callback. Note this might reset curr_input_cb */ + currCb(char_buf); /* - * If g_input_cb didn't change after the call, do another read. + * If curr_input_cb didn't change after the call, do another read. * Else, the uart0_set_callback was called with a different callback pointer * and triggered an another read. */ - if (currCb == g_input_cb) { - UART_read(gh_uart, &g_char_buf, 1); + if (currCb == curr_input_cb) { + UART_read(gh_uart, &char_buf, 1); } } /*---------------------------------------------------------------------------*/ void uart0_init(void) { - if (g_bIsInit) { return; } - g_bIsInit = true; + if (is_init) { return; } + is_init = true; UART_Params params; UART_Params_init(¶ms); @@ -98,7 +98,7 @@ uart0_init(void) int_fast32_t uart0_write(const void *buffer, size_t size) { - if (!g_bIsInit) { + if (!is_init) { return UART_STATUS_ERROR; } return UART_write(gh_uart, buffer, size); @@ -107,17 +107,17 @@ uart0_write(const void *buffer, size_t size) int_fast32_t uart0_set_callback(uart0_input_cb input_cb) { - if (!g_bIsInit) { + if (!is_init) { return UART_STATUS_ERROR; } - if (g_input_cb == input_cb) { + if (curr_input_cb == input_cb) { return UART_STATUS_SUCCESS; } - g_input_cb = input_cb; + curr_input_cb = input_cb; if (input_cb) { - return UART_read(gh_uart, &g_char_buf, 1); + return UART_read(gh_uart, &char_buf, 1); } else { UART_readCancel(gh_uart); return UART_STATUS_SUCCESS; From a18cac1e0c6493e081ca5f725d9c4ef2c5146d50 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Tue, 17 Jul 2018 19:09:38 +0200 Subject: [PATCH 275/485] Fixed GPIO HAL for srf06-cc26xx --- arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c | 83 ++++++++++--------- arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h | 8 -- .../srf06-cc26xx/launchpad/board-buttons.c | 4 +- 3 files changed, 44 insertions(+), 51 deletions(-) diff --git a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c index a7b025800..5f90529ed 100644 --- a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c +++ b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.c @@ -47,6 +47,18 @@ #define CONFIG_MASK (IOC_IOPULL_M | IOC_INT_M | IOC_IOMODE_OPEN_SRC_INV) /*---------------------------------------------------------------------------*/ void +gpio_hal_arch_interrupt_enable(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg) +{ + gpio_hal_pin_cfg_t config = gpio_hal_arch_pin_cfg_get(pin); + config &= ~GPIO_HAL_PIN_BM_INT; + config |= cfg; + gpio_hal_arch_pin_cfg_set(pin, cfg); + + ti_lib_gpio_clear_event_dio(pin); + ti_lib_rom_ioc_int_enable(pin); +} +/*---------------------------------------------------------------------------*/ +void gpio_hal_arch_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg) { uint32_t config; @@ -56,31 +68,24 @@ gpio_hal_arch_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg) config = ti_lib_rom_ioc_port_configure_get(pin); config &= ~CONFIG_MASK; - tmp = cfg & GPIO_HAL_PIN_CFG_EDGE_BOTH; - if(tmp == GPIO_HAL_PIN_CFG_EDGE_NONE) { - config |= IOC_NO_EDGE; - } else if(tmp == GPIO_HAL_PIN_CFG_EDGE_RISING) { - config |= IOC_RISING_EDGE; - } else if(tmp == GPIO_HAL_PIN_CFG_EDGE_FALLING) { - config |= IOC_FALLING_EDGE; - } else if(tmp == GPIO_HAL_PIN_CFG_EDGE_BOTH) { - config |= IOC_BOTH_EDGES; - } - - tmp = cfg & GPIO_HAL_PIN_CFG_PULL_MASK; - if(tmp == GPIO_HAL_PIN_CFG_PULL_NONE) { - config |= IOC_NO_IOPULL; - } else if(tmp == GPIO_HAL_PIN_CFG_PULL_DOWN) { - config |= IOC_IOPULL_DOWN; - } else if(tmp == GPIO_HAL_PIN_CFG_PULL_UP) { - config |= IOC_IOPULL_UP; - } - - tmp = cfg & GPIO_HAL_PIN_CFG_INT_MASK; + tmp = cfg & GPIO_HAL_PIN_BM_INT; if(tmp == GPIO_HAL_PIN_CFG_INT_DISABLE) { - config |= IOC_INT_DISABLE; - } else if(tmp == GPIO_HAL_PIN_CFG_INT_ENABLE) { - config |= IOC_INT_ENABLE; + config |= (IOC_NO_EDGE | IOC_INT_DISABLE); + } else if(tmp == GPIO_HAL_PIN_CFG_INT_RISING) { + config |= (IOC_RISING_EDGE | IOC_INT_ENABLE); + } else if(tmp == GPIO_HAL_PIN_CFG_INT_FALLING) { + config |= (IOC_FALLING_EDGE | IOC_INT_ENABLE); + } else if(tmp == GPIO_HAL_PIN_CFG_INT_BOTH) { + config |= (IOC_BOTH_EDGES | IOC_INT_ENABLE); + } + + tmp = cfg & GPIO_HAL_PIN_BM_INPUT; + if(tmp == GPIO_HAL_PIN_CFG_INPUT_NOPULL) { + config |= IOC_NO_IOPULL; + } else if(tmp == GPIO_HAL_PIN_CFG_INPUT_PULLDOWN) { + config |= IOC_IOPULL_DOWN; + } else if(tmp == GPIO_HAL_PIN_CFG_INPUT_PULLUP) { + config |= IOC_IOPULL_UP; } ti_lib_rom_ioc_port_configure_set(pin, IOC_PORT_GPIO, config); @@ -99,31 +104,27 @@ gpio_hal_arch_pin_cfg_get(gpio_hal_pin_t pin) /* Pull */ tmp = config & IOC_IOPULL_M; if(tmp == IOC_IOPULL_UP) { - cfg |= GPIO_HAL_PIN_CFG_PULL_UP; + cfg |= GPIO_HAL_PIN_CFG_INPUT_PULLUP; } else if(tmp == IOC_IOPULL_DOWN) { - cfg |= GPIO_HAL_PIN_CFG_PULL_DOWN; + cfg |= GPIO_HAL_PIN_CFG_INPUT_PULLDOWN; } else if(tmp == IOC_NO_IOPULL) { - cfg |= GPIO_HAL_PIN_CFG_PULL_NONE; + cfg |= GPIO_HAL_PIN_CFG_INPUT_NOPULL; } /* Interrupt enable/disable */ tmp = config & IOC_INT_ENABLE; if(tmp == IOC_INT_DISABLE) { cfg |= GPIO_HAL_PIN_CFG_INT_DISABLE; - } else if(tmp == IOC_INT_ENABLE) { - cfg |= GPIO_HAL_PIN_CFG_INT_ENABLE; - } - - /* Edge detection */ - tmp = config & IOC_BOTH_EDGES; - if(tmp == IOC_NO_EDGE) { - cfg |= GPIO_HAL_PIN_CFG_EDGE_NONE; - } else if(tmp == IOC_FALLING_EDGE) { - cfg |= GPIO_HAL_PIN_CFG_EDGE_FALLING; - } else if(tmp == IOC_RISING_EDGE) { - cfg |= GPIO_HAL_PIN_CFG_EDGE_RISING; - } else if(tmp == IOC_BOTH_EDGES) { - cfg |= GPIO_HAL_PIN_CFG_EDGE_BOTH; + } else { + /* Edge detection */ + tmp = config & IOC_BOTH_EDGES; + if(tmp == IOC_FALLING_EDGE) { + cfg |= GPIO_HAL_PIN_CFG_INT_FALLING; + } else if(tmp == IOC_RISING_EDGE) { + cfg |= GPIO_HAL_PIN_CFG_INT_RISING; + } else if(tmp == IOC_BOTH_EDGES) { + cfg |= GPIO_HAL_PIN_CFG_INT_BOTH; + } } return cfg; diff --git a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h index 2e83336d9..f24fa0828 100644 --- a/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h +++ b/arch/cpu/cc26xx-cc13xx/dev/gpio-hal-arch.h @@ -54,7 +54,6 @@ #include /*---------------------------------------------------------------------------*/ #define gpio_hal_arch_init() do { /* do nothing */ } while (0) -#define gpio_hal_arch_interrupt_enable(p) interrupt_enable(p) #define gpio_hal_arch_interrupt_disable(p) ti_lib_rom_ioc_int_disable(p) #define gpio_hal_arch_pin_set_input(p) ti_lib_rom_ioc_pin_type_gpio_input(p) @@ -70,13 +69,6 @@ #define gpio_hal_arch_toggle_pins(p) ti_lib_gpio_toggle_multi_dio(p) #define gpio_hal_arch_write_pins(p, v) ti_lib_gpio_write_multi_dio(p, v) /*---------------------------------------------------------------------------*/ -static inline void -interrupt_enable(gpio_hal_pin_t pin) -{ - ti_lib_gpio_clear_event_dio(pin); - ti_lib_rom_ioc_int_enable(pin); -} -/*---------------------------------------------------------------------------*/ #endif /* GPIO_HAL_ARCH_H_ */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/srf06-cc26xx/launchpad/board-buttons.c b/arch/platform/srf06-cc26xx/launchpad/board-buttons.c index f07fff09e..a0e9fa6f2 100644 --- a/arch/platform/srf06-cc26xx/launchpad/board-buttons.c +++ b/arch/platform/srf06-cc26xx/launchpad/board-buttons.c @@ -43,11 +43,11 @@ #include "ti-lib.h" /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTON(key_left, "Key Left", BOARD_IOID_KEY_LEFT, \ - GPIO_HAL_PIN_CFG_PULL_UP, BOARD_BUTTON_HAL_INDEX_KEY_LEFT, \ + GPIO_HAL_PIN_CFG_INPUT_PULLUP, BOARD_BUTTON_HAL_INDEX_KEY_LEFT, \ true); BUTTON_HAL_BUTTON(key_right, "Key Right", BOARD_IOID_KEY_RIGHT, \ - GPIO_HAL_PIN_CFG_PULL_UP, BOARD_BUTTON_HAL_INDEX_KEY_RIGHT, \ + GPIO_HAL_PIN_CFG_INPUT_PULLUP, BOARD_BUTTON_HAL_INDEX_KEY_RIGHT, \ true); /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTONS(&key_left, &key_right); From c333e9f7834d8d68176b96582729025cbce5a002 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Wed, 18 Jul 2018 17:41:04 +0200 Subject: [PATCH 276/485] Slight naming refactoring, and removed bloat .vramTable from linker --- arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 4 +- arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h | 6 +- .../dev/{dot-15-4g.h => rf-15-4g.h} | 0 .../dev/{ble-addr.c => rf-ble-addr.c} | 7 +- .../dev/{ble-addr.h => rf-ble-addr.h} | 0 arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.c | 7 +- arch/cpu/cc13xx-cc26xx/dev/rf-core.h | 56 ++++--------- .../dev/{ieee-addr.c => rf-ieee-addr.c} | 2 +- .../dev/{ieee-addr.h => rf-ieee-addr.h} | 0 arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c | 10 +-- arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c | 14 ++-- .../dev/{rf-core.c => rf-sched.c} | 32 ++++---- arch/cpu/cc13xx-cc26xx/dev/rf-sched.h | 82 +++++++++++++++++++ .../dev/startup_cc13xx_cc26xx_gcc.c | 12 --- .../{netstack-settings.h => rf-settings.h} | 32 ++------ .../simplelink/cc13xx-cc26xx/platform.c | 4 +- 16 files changed, 150 insertions(+), 118 deletions(-) rename arch/cpu/cc13xx-cc26xx/dev/{dot-15-4g.h => rf-15-4g.h} (100%) rename arch/cpu/cc13xx-cc26xx/dev/{ble-addr.c => rf-ble-addr.c} (97%) rename arch/cpu/cc13xx-cc26xx/dev/{ble-addr.h => rf-ble-addr.h} (100%) rename arch/cpu/cc13xx-cc26xx/dev/{ieee-addr.c => rf-ieee-addr.c} (99%) rename arch/cpu/cc13xx-cc26xx/dev/{ieee-addr.h => rf-ieee-addr.h} (100%) rename arch/cpu/cc13xx-cc26xx/dev/{rf-core.c => rf-sched.c} (96%) create mode 100644 arch/cpu/cc13xx-cc26xx/dev/rf-sched.h rename arch/cpu/cc13xx-cc26xx/rf-settings/{netstack-settings.h => rf-settings.h} (86%) diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index 083bf3f88..558ad4655 100644 --- a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -74,8 +74,8 @@ CONTIKI_CPU_SOURCEFILES += batmon-sensor.c gpio-hal-arch.c CONTIKI_CPU_SOURCEFILES += int-master-arch.c ### RF source files -CONTIKI_CPU_SOURCEFILES += rf-core.c rf-data-queue.c -CONTIKI_CPU_SOURCEFILES += ieee-addr.c ble-addr.c +CONTIKI_CPU_SOURCEFILES += rf-sched.c rf-data-queue.c +CONTIKI_CPU_SOURCEFILES += rf-ieee-addr.c rf-ble-addr.c CONTIKI_CPU_SOURCEFILES += rf-ble-beacond.c ifeq ($(SUPPORTS_PROP_MODE),1) diff --git a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h index 12ca00313..09c93bdf5 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h +++ b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h @@ -38,8 +38,8 @@ * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ -#ifndef SIMPLELINK_CONF_H_ -#define SIMPLELINK_CONF_H_ +#ifndef CC13XX_CC26XX_CONF_H_ +#define CC13XX_CC26XX_CONF_H_ /*---------------------------------------------------------------------------*/ #include "cc13xx-cc26xx-def.h" @@ -390,6 +390,6 @@ #endif /* SLIP_ARCH_CONF_ENABLED */ /** @} */ /*---------------------------------------------------------------------------*/ -#endif /* SIMPLELINK_CONF_H_ */ +#endif /* CC13XX_CC26XX_CONF_H_ */ /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h b/arch/cpu/cc13xx-cc26xx/dev/rf-15-4g.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/dev/dot-15-4g.h rename to arch/cpu/cc13xx-cc26xx/dev/rf-15-4g.h diff --git a/arch/cpu/cc13xx-cc26xx/dev/ble-addr.c b/arch/cpu/cc13xx-cc26xx/dev/rf-ble-addr.c similarity index 97% rename from arch/cpu/cc13xx-cc26xx/dev/ble-addr.c rename to arch/cpu/cc13xx-cc26xx/dev/rf-ble-addr.c index 11f4adf63..a76261c66 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/ble-addr.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-ble-addr.c @@ -37,19 +37,18 @@ */ /*---------------------------------------------------------------------------*/ #include "contiki.h" - #include "dev/ble-hal.h" #include "net/linkaddr.h" -#include "ble-addr.h" - -#include +#include "rf-ble-addr.h" /*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(inc/hw_memmap.h) #include DeviceFamily_constructPath(inc/hw_fcfg1.h) #include DeviceFamily_constructPath(inc/hw_ccfg.h) /*---------------------------------------------------------------------------*/ +#include +/*---------------------------------------------------------------------------*/ #define BLE_MAC_PRIMARY_ADDRESS (FCFG1_BASE + FCFG1_O_MAC_BLE_0) #define BLE_MAC_SECONDARY_ADDRESS (CCFG_BASE + CCFG_O_IEEE_BLE_0) /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/dev/ble-addr.h b/arch/cpu/cc13xx-cc26xx/dev/rf-ble-addr.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/dev/ble-addr.h rename to arch/cpu/cc13xx-cc26xx/dev/rf-ble-addr.h diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.c b/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.c index 442bd979a..7aa38198a 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.c @@ -44,8 +44,6 @@ #include "sys/etimer.h" #include "net/netstack.h" #include "net/linkaddr.h" - -#include "rf-ble-beacond.h" /*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/chipinfo.h) @@ -54,9 +52,10 @@ #include /*---------------------------------------------------------------------------*/ -#include "netstack-settings.h" +#include "rf-ble-addr.h" +#include "rf-ble-beacond.h" #include "rf-core.h" -#include "ble-addr.h" +#include "rf-settings.h" /*---------------------------------------------------------------------------*/ #include #include diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-core.h b/arch/cpu/cc13xx-cc26xx/dev/rf-core.h index fa27ebf62..6237779cd 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-core.h +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-core.h @@ -27,64 +27,40 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup simplelink + * \addtogroup cc13xx-cc26xx-cpu * @{ * - * \defgroup rf-common Common functionality fpr the CC13xx/CC26xx RF + * \defgroup rf-core Common functionality for the CC13xx/CC26xx RF * * @{ * * \file - * Header file of common CC13xx/CC26xx RF functionality + * Header file of common CC13xx/CC26xx RF functionality + * \author + * Edvard Pettersen + */ /*---------------------------------------------------------------------------*/ #ifndef RF_CORE_H_ #define RF_CORE_H_ /*---------------------------------------------------------------------------*/ -#include "contiki.h" -#include "sys/process.h" - -#include "rf-ble-beacond.h" -/*---------------------------------------------------------------------------*/ -#include -/*---------------------------------------------------------------------------*/ -#include -/*---------------------------------------------------------------------------*/ +/** + * \name Different modes the RF can operate on, denoted by which frequency + * band said mode operates on. Currently supports the following modes: + * - Sub-1 GHz, called prop-mode + * - 2.4 GHz, called ieee-mode + * + * @{ + */ #define RF_MODE_SUB_1_GHZ (1 << 0) #define RF_MODE_2_4_GHZ (1 << 1) +/* Bitmask of supported RF modes */ #define RF_MODE_BM ( RF_MODE_SUB_1_GHZ \ | RF_MODE_2_4_GHZ \ ) -/*---------------------------------------------------------------------------*/ -PROCESS_NAME(rf_core_process); -/*---------------------------------------------------------------------------*/ -typedef enum { - RF_RESULT_OK = 0, - RF_RESULT_ERROR, -} rf_result_t; -/*---------------------------------------------------------------------------*/ -/* Common */ -rf_result_t rf_yield(void); - -rf_result_t rf_set_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8_t dbm); -rf_result_t rf_get_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8_t *dbm); -/*---------------------------------------------------------------------------*/ -/* Netstack radio: IEEE-mode or prop-mode */ -RF_Handle netstack_open(RF_Params *params); - -rf_result_t netstack_sched_fs(void); -rf_result_t netstack_sched_ieee_tx(bool recieve_ack); -rf_result_t netstack_sched_prop_tx(void); -rf_result_t netstack_sched_rx(bool start); -rf_result_t netstack_stop_rx(void); -/*---------------------------------------------------------------------------*/ -/* BLE radio: BLE Beacon Daemon */ -RF_Handle ble_open(RF_Params *params); - -rf_result_t ble_sched_beacon(RF_Callback cb, RF_EventMask bm_event); +/** @} */ /*---------------------------------------------------------------------------*/ #endif /* RF_CORE_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/dev/ieee-addr.c b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-addr.c similarity index 99% rename from arch/cpu/cc13xx-cc26xx/dev/ieee-addr.c rename to arch/cpu/cc13xx-cc26xx/dev/rf-ieee-addr.c index 3d9b4c9f8..eddee8947 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/ieee-addr.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-addr.c @@ -40,7 +40,7 @@ #include "contiki.h" #include "net/linkaddr.h" -#include "ieee-addr.h" +#include "rf-ieee-addr.h" /*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(inc/hw_memmap.h) diff --git a/arch/cpu/cc13xx-cc26xx/dev/ieee-addr.h b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-addr.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/dev/ieee-addr.h rename to arch/cpu/cc13xx-cc26xx/dev/rf-ieee-addr.h diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c index 60c806d24..ce7d8b42c 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c @@ -68,9 +68,9 @@ /* SimpleLink Platform RF dev */ #include "rf-data-queue.h" #include "rf-core.h" -#include "dot-15-4g.h" -#include "netstack-settings.h" -#include RF_IEEE_SETTINGS +#include "rf-sched.h" +#include "rf-15-4g.h" +#include "ieee-settings.h" /*---------------------------------------------------------------------------*/ #include #include @@ -428,7 +428,7 @@ init(void) ctimer_set(&ieee_radio.rat.overflow_timer, two_quarters, rat_overflow_cb, NULL); /* Start RF process */ - process_start(&rf_core_process, NULL); + process_start(&rf_sched_process, NULL); return RF_RESULT_OK; } @@ -671,7 +671,7 @@ pending_packet(void) } while (curr_entry != read_entry); if ((num_pending > 0) && !ieee_radio.poll_mode) { - process_poll(&rf_core_process); + process_poll(&rf_sched_process); } /* If we didn't find an entry at status finished or busy, no frames are pending */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c index 2451bd0e7..02d48bc21 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c @@ -297,15 +297,19 @@ set_channel(uint16_t channel) static uint8_t calculate_lqi(int8_t rssi) { - /* Note : Currently the LQI value is simply the energy detect measurement. + /* + * Note : Currently the LQI value is simply the energy detect measurement. * A more accurate value could be derived by using the correlation - * value along with the RSSI value. */ + * value along with the RSSI value. + */ rssi = CLAMP(rssi, ED_RF_POWER_MIN_DBM, ED_RF_POWER_MAX_DBM); - /* Create energy detect measurement by normalizing and scaling RF power level. + /* + * Create energy detect measurement by normalizing and scaling RF power level. * Note : The division operation below is designed for maximum accuracy and - * best granularity. This is done by grouping the math operations to - * compute the entire numerator before doing any division. */ + * best granularity. This is done by grouping the math operations to + * compute the entire numerator before doing any division. + */ return (MAC_SPEC_ED_MAX * (rssi - ED_RF_POWER_MIN_DBM)) / (ED_RF_POWER_MAX_DBM - ED_RF_POWER_MIN_DBM); } /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-core.c b/arch/cpu/cc13xx-cc26xx/dev/rf-sched.c similarity index 96% rename from arch/cpu/cc13xx-cc26xx/dev/rf-core.c rename to arch/cpu/cc13xx-cc26xx/dev/rf-sched.c index 027552631..a258dc54b 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-core.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-sched.c @@ -27,9 +27,8 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup simplelink + * \addtogroup * @{ * * \file @@ -46,7 +45,6 @@ #include "net/packetbuf.h" #include "net/mac/mac.h" -#include "rf-core.h" /*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) @@ -54,8 +52,10 @@ #include /*---------------------------------------------------------------------------*/ +#include "rf-core.h" +#include "rf-sched.h" #include "rf-data-queue.h" -#include "netstack-settings.h" +#include "rf-settings.h" /*---------------------------------------------------------------------------*/ #include #include @@ -100,13 +100,13 @@ cmd_rx_cb(RF_Handle client, RF_CmdHandle command, RF_EventMask events) (void)command; if (events & RF_EventRxEntryDone) { - process_poll(&rf_core_process); + process_poll(&rf_sched_process); } if (events & RF_EventRxBufFull) { rx_buf_full = true; - process_poll(&rf_core_process); + process_poll(&rf_sched_process); } } /*---------------------------------------------------------------------------*/ @@ -275,7 +275,7 @@ netstack_sched_fs(void) } /*---------------------------------------------------------------------------*/ rf_result_t -netstack_sched_ieee_tx(bool recieve_ack) +netstack_sched_ieee_tx(bool ack_request) { rf_result_t res; @@ -286,15 +286,15 @@ netstack_sched_ieee_tx(bool recieve_ack) sched_params.endTime = 0; sched_params.allowDelay = RF_AllowDelayAny; - const bool is_active = cmd_rx_is_active(); - const bool rx_ack_required = (recieve_ack && !is_active); + const bool rx_is_active = cmd_rx_is_active(); + const bool rx_needed = (ack_request && !rx_is_active); /* * If we expect ACK after transmission, RX must be running to be able to * run the RX_ACK command. Therefore, turn on RX before starting the * chained TX command. */ - if (rx_ack_required) { + if (rx_needed) { res = netstack_sched_rx(false); if (res != RF_RESULT_OK) { return res; @@ -316,7 +316,7 @@ netstack_sched_ieee_tx(bool recieve_ack) return RF_RESULT_ERROR; } - if (is_active) { + if (rx_is_active) { ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT); } else { ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); @@ -326,11 +326,11 @@ netstack_sched_ieee_tx(bool recieve_ack) RF_EventMask tx_events = RF_pendCmd(&rf_netstack, tx_handle, 0); /* Stop RX if it was turned on only for ACK */ - if (rx_ack_required) { + if (rx_needed) { netstack_stop_rx(); } - if (is_active) { + if (rx_is_active) { ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN); } else { ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); @@ -436,7 +436,7 @@ netstack_sched_rx(bool start) if (start) { rf_is_on = true; - process_poll(&rf_core_process); + process_poll(&rf_sched_process); } return RF_RESULT_OK; @@ -508,9 +508,9 @@ ble_sched_beacon(RF_Callback cb, RF_EventMask bm_event) return RF_RESULT_OK; } /*---------------------------------------------------------------------------*/ -PROCESS(rf_core_process, "RF Core Process"); +PROCESS(rf_sched_process, "RF Core Process"); /*---------------------------------------------------------------------------*/ -PROCESS_THREAD(rf_core_process, ev, data) +PROCESS_THREAD(rf_sched_process, ev, data) { int len; diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-sched.h b/arch/cpu/cc13xx-cc26xx/dev/rf-sched.h new file mode 100644 index 000000000..32f6f0a6b --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-sched.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/** + * \addtogroup rf-core + * @{ + * + * \file + * Header file of the CC13xx/CC26xx RF scheduler. + */ +/*---------------------------------------------------------------------------*/ +#ifndef RF_SCHED_H_ +#define RF_SCHED_H_ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "sys/process.h" + +#include "rf-ble-beacond.h" +/*---------------------------------------------------------------------------*/ +#include +/*---------------------------------------------------------------------------*/ +#include +/*---------------------------------------------------------------------------*/ +PROCESS_NAME(rf_sched_process); +/*---------------------------------------------------------------------------*/ +typedef enum { + RF_RESULT_OK = 0, + RF_RESULT_ERROR, +} rf_result_t; +/*---------------------------------------------------------------------------*/ +/* Common */ +rf_result_t rf_yield(void); + +rf_result_t rf_set_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8_t dbm); +rf_result_t rf_get_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8_t *dbm); +/*---------------------------------------------------------------------------*/ +/* Netstack radio: IEEE-mode or prop-mode */ +RF_Handle netstack_open(RF_Params *params); + +rf_result_t netstack_sched_fs(void); +rf_result_t netstack_sched_ieee_tx(bool ack_request); +rf_result_t netstack_sched_prop_tx(void); +rf_result_t netstack_sched_rx(bool start); +rf_result_t netstack_stop_rx(void); +/*---------------------------------------------------------------------------*/ +/* BLE radio: BLE Beacon Daemon */ +RF_Handle ble_open(RF_Params *params); + +rf_result_t ble_sched_beacon(RF_Callback cb, RF_EventMask bm_event); +/*---------------------------------------------------------------------------*/ +#endif /* RF_SCHED_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c b/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c index 6efdf5569..869414920 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c +++ b/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c @@ -107,10 +107,6 @@ static void (* const resetVectors[16])(void) = defaultHandler, // The PendSV handler defaultHandler // The SysTick handler }; - -__attribute__ ((section(".ramVecs"))) -static unsigned long ramVectors[50]; - //***************************************************************************** // // The following are arrays of pointers to constructor functions that need to @@ -194,14 +190,6 @@ void localProgramStart(void) __init_array_start[i](); } - /* Copy from reset vector table into RAM vector table */ - memcpy(ramVectors, resetVectors, 16*4); - - /* fill remaining vectors with default handler */ - for (i=16; i < 50; i++) { - ramVectors[i] = (unsigned long)defaultHandler; - } - /* Call the application's entry point. */ main(); diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/netstack-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/rf-settings.h similarity index 86% rename from arch/cpu/cc13xx-cc26xx/rf-settings/netstack-settings.h rename to arch/cpu/cc13xx-cc26xx/rf-settings/rf-settings.h index 03bcfe2bb..198482b1f 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/netstack-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/rf-settings.h @@ -35,31 +35,10 @@ /*---------------------------------------------------------------------------*/ #include /*---------------------------------------------------------------------------*/ -/* Prop-mode RF settings configuration */ -#ifdef RF_CONF_PROP_SETTINGS -# define RF_PROP_SETTINGS RF_CONF_PROP_SETTINGS -#else -# define RF_PROP_SETTINGS "prop-settings.h" -#endif - -/* IEEE-mode RF settings configuration */ -#ifdef RF_CONF_IEEE_SETTINGS -# define RF_IEEE_SETTINGS RF_CONF_IEEE_SETTINGS -#else -# define RF_IEEE_SETTINGS "ieee-settings.h" -#endif - -/* BLE RF settings configuration */ -#ifdef RF_CONF_BLE_SETTINGS -# define RF_BLE_SETTINGS RF_CONF_BLE_SETTINGS -#else -# define RF_BLE_SETTINGS "ble-settings.h" -#endif -/*---------------------------------------------------------------------------*/ /* Prop-mode RF settings */ #if (RF_MODE == RF_MODE_SUB_1_GHZ) -#include RF_PROP_SETTINGS +#include "prop-settings.h" #define netstack_mode rf_prop_mode #define netstack_cmd_radio_setup rf_cmd_prop_radio_div_setup @@ -70,7 +49,7 @@ /* IEEE-mode RF settings */ #elif (RF_MODE == RF_MODE_2_4_GHZ) -#include RF_IEEE_SETTINGS +#include "ieee-settings.h" #define netstack_mode rf_ieee_mode #define netstack_cmd_radio_setup rf_cmd_ieee_radio_setup @@ -83,22 +62,27 @@ #endif /*---------------------------------------------------------------------------*/ /* BLE RF settings */ -#include RF_BLE_SETTINGS #if (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0) +#include "ble-settings.h" + #define ble_mode rf_ble_mode #define ble_cmd_radio_setup rf_ble_cmd_radio_setup #define ble_adv_par rf_ble_adv_par #define ble_cmd_beacon rf_ble_cmd_ble_adv_nc +/*---------------------------------------------------------------------------*/ #elif (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X2_CC26X2) +#include "ble-settings.h" + #define ble_mode rf_ble_mode #define ble_cmd_radio_setup rf_cmd_ble5_radio_setup #define ble_adv_par rf_ble5_adv_aux_par #define ble_cmd_beacon rf_cmd_ble5_adv_aux +/*---------------------------------------------------------------------------*/ #else # error "Unsupported DeviceFamily_PARENT for BLE settings" #endif diff --git a/arch/platform/simplelink/cc13xx-cc26xx/platform.c b/arch/platform/simplelink/cc13xx-cc26xx/platform.c index 86342a287..64317dc02 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/platform.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/platform.c @@ -72,13 +72,13 @@ #include /*---------------------------------------------------------------------------*/ /* Arch driver implementations */ +#include "button-sensor.h" #include "board-peripherals.h" #include "uart0-arch.h" /*---------------------------------------------------------------------------*/ -#include "ieee-addr.h" #include "rf-core.h" +#include "rf-ieee-addr.h" #include "rf-ble-beacond.h" -#include "button-sensor.h" /*---------------------------------------------------------------------------*/ #include #include From dfc6ee611ae854fbbfaaba70622801a9c9b09e5c Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Thu, 19 Jul 2018 16:44:39 +0200 Subject: [PATCH 277/485] Doxygen alignment, and fixed missing TRNG objects --- arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 20 +- .../cc13x0-cc26x0/cc13x0-cc26x0.icf | 86 +++ .../cc13x0-cc26x0/cc13xx-cc26xx-def.h | 105 ---- .../cc13x2-cc26x2/cc13x2-cc26x2.icf | 91 +++ arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h | 4 +- .../{cc13x2-cc26x2 => }/cc13xx-cc26xx-def.h | 43 +- arch/cpu/cc13xx-cc26xx/dev/clock-arch.c | 132 ++-- arch/cpu/cc13xx-cc26xx/dev/dbg-arch.c | 38 +- arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c | 39 +- arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.h | 22 +- arch/cpu/cc13xx-cc26xx/dev/int-master-arch.c | 22 +- .../dev/{random-arch.c => random.c} | 50 +- arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c | 5 +- .../dev/startup_cc13xx_cc26xx_gcc.c | 220 +++---- .../dev/startup_cc13xx_cc26xx_iar.c | 306 ++++++++++ arch/cpu/cc13xx-cc26xx/dev/ti-lib-rom.h | 194 ------ arch/cpu/cc13xx-cc26xx/dev/ti-lib.h | 578 ------------------ arch/cpu/cc13xx-cc26xx/dev/trng-arch.c | 94 +++ arch/cpu/cc13xx-cc26xx/dev/trng-arch.h | 75 +++ .../{dev/rf-ble-addr.c => rf/ble-addr.c} | 2 +- .../{dev/rf-ble-addr.h => rf/ble-addr.h} | 0 .../rf-ble-beacond.c => rf/ble-beacond.c} | 6 +- .../rf-ble-beacond.h => rf/ble-beacond.h} | 0 .../{dev/rf-data-queue.c => rf/data-queue.c} | 2 +- .../{dev/rf-data-queue.h => rf/data-queue.h} | 0 .../{dev/rf-15-4g.h => rf/dot-15-4g.h} | 0 .../{dev/rf-ieee-addr.c => rf/ieee-addr.c} | 2 +- .../{dev/rf-ieee-addr.h => rf/ieee-addr.h} | 0 .../{dev/rf-ieee-mode.c => rf/ieee-mode.c} | 8 +- .../{dev/rf-prop-mode.c => rf/prop-mode.c} | 0 .../cc13xx-cc26xx/{dev/rf-core.h => rf/rf.h} | 0 .../{dev/rf-sched.c => rf/sched.c} | 6 +- .../{dev/rf-sched.h => rf/sched.h} | 2 - .../cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 1 + .../simplelink/cc13xx-cc26xx}/batmon-sensor.c | 26 +- .../simplelink/cc13xx-cc26xx}/batmon-sensor.h | 0 .../launchpad/cc1310/CC1310_LAUNCHXL.c | 23 + .../launchpad/cc1310/CC1310_LAUNCHXL.h | 10 + .../launchpad/cc1312r1/CC1312R1_LAUNCHXL.c | 23 + .../launchpad/cc1312r1/CC1312R1_LAUNCHXL.h | 10 + .../launchpad/cc1350/CC1350_LAUNCHXL.c | 23 + .../launchpad/cc1350/CC1350_LAUNCHXL.h | 10 + .../launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.c | 23 + .../launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h | 10 + .../launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.c | 23 + .../launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.h | 10 + .../launchpad/cc1352p1/CC1352P1_LAUNCHXL.c | 23 + .../launchpad/cc1352p1/CC1352P1_LAUNCHXL.h | 10 + .../launchpad/cc1352r1/CC1352R1_LAUNCHXL.c | 23 + .../launchpad/cc1352r1/CC1352R1_LAUNCHXL.h | 10 + .../launchpad/cc2650/CC2650_LAUNCHXL.c | 23 + .../launchpad/cc2650/CC2650_LAUNCHXL.h | 10 + .../launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c | 23 + .../launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h | 10 + .../simplelink/cc13xx-cc26xx/platform.c | 21 +- .../sensortag/cc1350/CC1350STK.c | 23 + .../sensortag/cc1350/CC1350STK.h | 10 + .../sensortag/cc2650/CC2650STK.c | 23 + .../sensortag/cc2650/CC2650STK.h | 10 + .../cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c | 23 + .../cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h | 10 + .../cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c | 23 + .../cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h | 10 + 63 files changed, 1455 insertions(+), 1174 deletions(-) create mode 100644 arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.icf delete mode 100644 arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13xx-cc26xx-def.h create mode 100644 arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.icf rename arch/cpu/cc13xx-cc26xx/{cc13x2-cc26x2 => }/cc13xx-cc26xx-def.h (78%) rename arch/cpu/cc13xx-cc26xx/dev/{random-arch.c => random.c} (67%) create mode 100644 arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_iar.c delete mode 100644 arch/cpu/cc13xx-cc26xx/dev/ti-lib-rom.h delete mode 100644 arch/cpu/cc13xx-cc26xx/dev/ti-lib.h create mode 100644 arch/cpu/cc13xx-cc26xx/dev/trng-arch.c create mode 100644 arch/cpu/cc13xx-cc26xx/dev/trng-arch.h rename arch/cpu/cc13xx-cc26xx/{dev/rf-ble-addr.c => rf/ble-addr.c} (99%) rename arch/cpu/cc13xx-cc26xx/{dev/rf-ble-addr.h => rf/ble-addr.h} (100%) rename arch/cpu/cc13xx-cc26xx/{dev/rf-ble-beacond.c => rf/ble-beacond.c} (99%) rename arch/cpu/cc13xx-cc26xx/{dev/rf-ble-beacond.h => rf/ble-beacond.h} (100%) rename arch/cpu/cc13xx-cc26xx/{dev/rf-data-queue.c => rf/data-queue.c} (99%) rename arch/cpu/cc13xx-cc26xx/{dev/rf-data-queue.h => rf/data-queue.h} (100%) rename arch/cpu/cc13xx-cc26xx/{dev/rf-15-4g.h => rf/dot-15-4g.h} (100%) rename arch/cpu/cc13xx-cc26xx/{dev/rf-ieee-addr.c => rf/ieee-addr.c} (99%) rename arch/cpu/cc13xx-cc26xx/{dev/rf-ieee-addr.h => rf/ieee-addr.h} (100%) rename arch/cpu/cc13xx-cc26xx/{dev/rf-ieee-mode.c => rf/ieee-mode.c} (99%) rename arch/cpu/cc13xx-cc26xx/{dev/rf-prop-mode.c => rf/prop-mode.c} (100%) rename arch/cpu/cc13xx-cc26xx/{dev/rf-core.h => rf/rf.h} (100%) rename arch/cpu/cc13xx-cc26xx/{dev/rf-sched.c => rf/sched.c} (99%) rename arch/cpu/cc13xx-cc26xx/{dev/rf-sched.h => rf/sched.h} (99%) rename arch/{cpu/cc13xx-cc26xx/dev => platform/simplelink/cc13xx-cc26xx}/batmon-sensor.c (88%) rename arch/{cpu/cc13xx-cc26xx/dev => platform/simplelink/cc13xx-cc26xx}/batmon-sensor.h (100%) diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index 558ad4655..6605ea849 100644 --- a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -67,23 +67,23 @@ EXTERNALDIRS += $(SDK_DEVICE) EXTERNALDIRS += $(SDK_DEVICE)/startup_files ### CPU-dependent source files -CONTIKI_CPU_SOURCEFILES += rtimer-arch.c clock-arch.c +CONTIKI_CPU_SOURCEFILES += rtimer-arch.c clock-arch.c CONTIKI_CPU_SOURCEFILES += watchdog-arch.c dbg-arch.c -CONTIKI_CPU_SOURCEFILES += uart0-arch.c slip-arch.c -CONTIKI_CPU_SOURCEFILES += batmon-sensor.c gpio-hal-arch.c -CONTIKI_CPU_SOURCEFILES += int-master-arch.c +CONTIKI_CPU_SOURCEFILES += uart0-arch.c slip-arch.c +CONTIKI_CPU_SOURCEFILES += gpio-hal-arch.c int-master-arch.c +CONTIKI_CPU_SOURCEFILES += random.c trng-arch.c ### RF source files -CONTIKI_CPU_SOURCEFILES += rf-sched.c rf-data-queue.c -CONTIKI_CPU_SOURCEFILES += rf-ieee-addr.c rf-ble-addr.c -CONTIKI_CPU_SOURCEFILES += rf-ble-beacond.c +CONTIKI_CPU_SOURCEFILES += sched.c data-queue.c +CONTIKI_CPU_SOURCEFILES += ieee-addr.c ble-addr.c +CONTIKI_CPU_SOURCEFILES += ble-beacond.c ifeq ($(SUPPORTS_PROP_MODE),1) -CONTIKI_CPU_SOURCEFILES += rf-prop-mode.c prop-settings.c +CONTIKI_CPU_SOURCEFILES += prop-mode.c prop-settings.c endif ifeq ($(SUPPORTS_IEEE_MODE),1) -CONTIKI_CPU_SOURCEFILES += rf-ieee-mode.c ieee-settings.c +CONTIKI_CPU_SOURCEFILES += ieee-mode.c ieee-settings.c endif ifeq ($(SUPPORTS_BLE_BEACON),1) @@ -95,7 +95,7 @@ MODULES += os/lib/dbg-io ### CPU-dependent directories CONTIKI_CPU_DIRS += . dev $(SUBFAMILY) -CONTIKI_CPU_DIRS += rf-settings rf-settings/$(DEVICE_FAMILY_LC) +CONTIKI_CPU_DIRS += rf rf-settings rf-settings/$(DEVICE_FAMILY_LC) CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES) $(DEBUG_IO_SOURCEFILES) diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.icf b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.icf new file mode 100644 index 000000000..5dee82c93 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13x0-cc26x0.icf @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2017, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +define symbol STACK_SIZE = 0x800; /* 2048 bytes */ +define symbol HEAP_SIZE = 0x100; /* 256 bytes */ + +define symbol __intvec_start__ = 0x00000000; + +/*-Memory Regions-*/ +define symbol ROM_start__ = 0x00000000; +define symbol ROM_end__ = 0x0001FFFF; +define symbol RAM_start__ = 0x20000000; +define symbol RAM_end__ = 0x20004FFF; + +/* Define a memory region that covers the entire 4 GB addressable space */ +define memory mem with size = 4G; + +/* Define a region for the on-chip flash */ +define region FLASH_region = mem:[from ROM_start__ to ROM_end__]; + +/* Define a region for the on-chip SRAM */ +define region RAM_region = mem:[from RAM_start__ to RAM_end__]; + +/* Place the interrupt vectors at the start of flash */ +place at address mem:__intvec_start__ { readonly section .intvec }; +keep { section .intvec }; + +/* Place the CCA area at the end of flash */ +place at end of FLASH_region { readonly section .ccfg }; +keep { section .ccfg }; + +/* Place remaining 'read only' in Flash */ +place in FLASH_region { readonly }; + +/* Place all read/write items into RAM */ +place in RAM_region { readwrite }; +initialize by copy { readwrite }; + +/* + * Define CSTACK block to contain .stack section. This enables the IAR IDE + * to properly show the stack content during debug. Place stack at end of + * retention RAM, do not initialize (initializing the stack will destroy the + * return address from the initialization code, causing the processor to branch + * to zero and fault) + */ +define block CSTACK with alignment = 8, size = STACK_SIZE { section .stack }; +place at end of RAM_region { block CSTACK }; +do not initialize { section .stack, section .noinit }; + +/* Export stack top symbol. Used by startup file */ +define exported symbol STACK_TOP = RAM_end__ + 1; + +/* Primary Heap configuration */ +define block HEAP with alignment = 8, size = HEAP_SIZE { }; + +/* Place heap just before CSTACK */ +place in RAM_region { block HEAP }; diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13xx-cc26xx-def.h b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13xx-cc26xx-def.h deleted file mode 100644 index bca8365c7..000000000 --- a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/cc13xx-cc26xx-def.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2017, 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 CC13XX_CC26XX_DEF_H_ -#define CC13XX_CC26XX_DEF_H_ -/*---------------------------------------------------------------------------*/ -#include -/*---------------------------------------------------------------------------*/ -/* TSCH related defines */ - -/* Delay between GO signal and SFD */ -#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(81)) -/* Delay between GO signal and start listening. - * This value is so small because the radio is constantly on within each timeslot. */ -#define RADIO_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(15)) -/* Delay between the SFD finishes arriving and it is detected in software. */ -#define RADIO_DELAY_BEFORE_DETECT ((unsigned)US_TO_RTIMERTICKS(352)) - -/* Timer conversion; radio is running at 4 MHz */ -#define RAT_SECOND 4000000u -#define RAT_TO_RTIMER(X) ((uint32_t)(((uint64_t)(X) * (RTIMER_SECOND / 256)) / (RAT_SECOND / 256))) -#define USEC_TO_RAT(X) ((X) * 4) - -#if (RTIMER_SECOND % 256) || (RAT_SECOND % 256) -# error RAT_TO_RTIMER macro must be fixed! -#endif - -/* The PHY header (preamble + SFD, 4+1 bytes) duration is equivalent to 10 symbols */ -#define RADIO_IEEE_802154_PHY_HEADER_DURATION_USEC 160 - -/* Do not turn off TSCH within a timeslot: not enough time */ -#define TSCH_CONF_RADIO_ON_DURING_TIMESLOT 1 - -/* Disable TSCH frame filtering */ -#define TSCH_CONF_HW_FRAME_FILTERING 0 - -/* Use hardware timestamps */ -#ifndef TSCH_CONF_RESYNC_WITH_SFD_TIMESTAMPS -#define TSCH_CONF_RESYNC_WITH_SFD_TIMESTAMPS 1 -#define TSCH_CONF_TIMESYNC_REMOVE_JITTER 0 -#endif - -#ifndef TSCH_CONF_BASE_DRIFT_PPM -/* The drift compared to "true" 10ms slots. - * Enable adaptive sync to enable compensation for this. - * Slot length 10000 usec - * 328 ticks - * Tick duration 30.517578125 usec - * Real slot duration 10009.765625 usec - * Target - real duration = -9.765625 usec - * TSCH_CONF_BASE_DRIFT_PPM -977 - */ -#define TSCH_CONF_BASE_DRIFT_PPM -977 -#endif - -/* 10 times per second */ -#ifndef TSCH_CONF_CHANNEL_SCAN_DURATION -#define TSCH_CONF_CHANNEL_SCAN_DURATION (CLOCK_SECOND / 10) -#endif - -/* Slightly reduce the TSCH guard time (from 2200 usec to 1800 usec) to make sure - * the CC26xx radio has sufficient time to start up. */ -#ifndef TSCH_CONF_RX_WAIT -#define TSCH_CONF_RX_WAIT 1800 -#endif -/*---------------------------------------------------------------------------*/ -#define RTIMER_ARCH_SECOND 65536 -/*---------------------------------------------------------------------------*/ -/* Path to CMSIS header */ -#define CMSIS_CONF_HEADER_PATH "cc13x0-cc26x0-cm3.h" - -/* Path to headers with implementation of mutexes and memory barriers */ -#define MUTEX_CONF_ARCH_HEADER_PATH "mutex-cortex.h" -#define MEMORY_BARRIER_CONF_ARCH_HEADER_PATH "memory-barrier-cortex.h" -/*---------------------------------------------------------------------------*/ -#endif /* CC13XX_CC26XX_DEF_H_ */ -/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.icf b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.icf new file mode 100644 index 000000000..32316f445 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13x2-cc26x2.icf @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2017, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +define symbol STACK_SIZE = 0x800; /* 2048 bytes */ +define symbol HEAP_SIZE = 0x100; /* 256 bytes */ + +define symbol __intvec_start__ = 0x00000000; + +/*-Memory Regions-*/ +define symbol ROM_start__ = 0x00000000; +define symbol ROM_end__ = 0x00057FFF; +define symbol RAM_start__ = 0x20000000; +define symbol RAM_end__ = 0x20013FFF; +define symbol GPRAM_start__ = 0x11000000; +define symbol GPRAM_end__ = 0x11001FFF; + +/* Define a memory region that covers the entire 4 GB addressable space */ +define memory mem with size = 4G; + +/* Define a region for the on-chip flash */ +define region FLASH_region = mem:[from ROM_start__ to ROM_end__]; + +/* Define a region for the on-chip SRAM */ +define region RAM_region = mem:[from RAM_start__ to RAM_end__]; + +/* Define a region for the on-chip GPRAM */ +define region GPRAM_region = mem:[from GPRAM_start__ to GPRAM_end__]; + +/* Place the interrupt vectors at the start of flash */ +place at address mem:__intvec_start__ { readonly section .intvec }; +keep { section .intvec }; + +/* Place the CCA area at the end of flash */ +place at end of FLASH_region { readonly section .ccfg }; +keep { section .ccfg }; + +/* Place remaining 'read only' in Flash */ +place in FLASH_region { readonly }; + +/* Place all read/write items into RAM */ +place in RAM_region { readwrite }; +initialize by copy { readwrite }; + +/* + * Define CSTACK block to contain .stack section. This enables the IAR IDE + * to properly show the stack content during debug. Place stack at end of + * retention RAM, do not initialize (initializing the stack will destroy the + * return address from the initialization code, causing the processor to branch + * to zero and fault) + */ +define block CSTACK with alignment = 8, size = STACK_SIZE { section .stack }; +place at end of RAM_region { block CSTACK }; +do not initialize { section .stack, section .noinit }; + +/* Export stack top symbol. Used by startup file */ +define exported symbol STACK_TOP = RAM_end__ + 1; + +/* Primary Heap configuration */ +define block HEAP with alignment = 8, size = HEAP_SIZE { }; + +/* Place heap just before CSTACK */ +place in RAM_region { block HEAP }; diff --git a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h index 09c93bdf5..45b10e17d 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h +++ b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h @@ -43,7 +43,7 @@ /*---------------------------------------------------------------------------*/ #include "cc13xx-cc26xx-def.h" -#include "rf-core.h" +#include "rf/rf.h" /*---------------------------------------------------------------------------*/ /** * \name GPIO HAL configuration. @@ -68,7 +68,7 @@ #ifndef RF_CONF_FAST_RADIO_STARTUP # define RF_FAST_RADIO_STARTUP (MAC_CONF_WITH_TSCH) #else -# define RF_FAST_RADIO_STARTUP 0 +# define RF_FAST_RADIO_STARTUP RF_CONF_FAST_RADIO_STARTUP #endif /* diff --git a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13xx-cc26xx-def.h b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-def.h similarity index 78% rename from arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13xx-cc26xx-def.h rename to arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-def.h index 507db4470..0f941b058 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/cc13xx-cc26xx-def.h +++ b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-def.h @@ -1,11 +1,10 @@ /* - * Copyright (c) 2017, George Oikonomou - http://www.spd.gr + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * 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 @@ -28,11 +27,32 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + * \addtogroup cc13xx-cc26xx-cpu + * @{ + * + * \file + * Header with configuration defines for the Contiki system. + * \author + * Edvard Pettersen + */ /*---------------------------------------------------------------------------*/ #ifndef CC13XX_CC26XX_DEF_H_ #define CC13XX_CC26XX_DEF_H_ /*---------------------------------------------------------------------------*/ -#include +#include +/*---------------------------------------------------------------------------*/ +#if (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0) +# include +#elif (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X2_CC26X2) +# include +#endif +/*---------------------------------------------------------------------------*/ +#include +/*---------------------------------------------------------------------------*/ +#define RTIMER_ARCH_SECOND 65536 +/*---------------------------------------------------------------------------*/ +#define INT_MASTER_CONF_STATUS_DATATYPE uintptr_t /*---------------------------------------------------------------------------*/ /* TSCH related defines */ @@ -44,7 +64,6 @@ /* Delay between the SFD finishes arriving and it is detected in software. */ #define RADIO_DELAY_BEFORE_DETECT ((unsigned)US_TO_RTIMERTICKS(352)) -/* Timer conversion; radio is running at 4 MHz */ /* Timer conversion; radio is running at 4 MHz */ #define RAT_SECOND 4000000u #define RAT_TO_RTIMER(X) ((uint32_t)(((uint64_t)(X) * (RTIMER_SECOND / 256)) / (RAT_SECOND / 256))) @@ -54,8 +73,6 @@ # error RAT_TO_RTIMER macro must be fixed! #endif -#define USEC_TO_RADIO(X) ((X) * 4) - /* The PHY header (preamble + SFD, 4+1 bytes) duration is equivalent to 10 symbols */ #define RADIO_IEEE_802154_PHY_HEADER_DURATION_USEC 160 @@ -72,7 +89,8 @@ #endif #ifndef TSCH_CONF_BASE_DRIFT_PPM -/* The drift compared to "true" 10ms slots. +/* + * The drift compared to "true" 10ms slots. * Enable adaptive sync to enable compensation for this. * Slot length 10000 usec * 328 ticks @@ -95,14 +113,17 @@ #define TSCH_CONF_RX_WAIT 1800 #endif /*---------------------------------------------------------------------------*/ -#define RTIMER_ARCH_SECOND 65536 -/*---------------------------------------------------------------------------*/ /* Path to CMSIS header */ -#define CMSIS_CONF_HEADER_PATH "cc13x2-cc26x2-cm4.h" - +#if (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0) +# define CMSIS_CONF_HEADER_PATH "cc13x0-cc26x0-cm3.h" +#elif (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X2_CC26X2) +# define CMSIS_CONF_HEADER_PATH "cc13x2-cc26x2-cm4.h" +#endif +/*---------------------------------------------------------------------------*/ /* Path to headers with implementation of mutexes and memory barriers */ #define MUTEX_CONF_ARCH_HEADER_PATH "mutex-cortex.h" #define MEMORY_BARRIER_CONF_ARCH_HEADER_PATH "memory-barrier-cortex.h" /*---------------------------------------------------------------------------*/ #endif /* CC13XX_CC26XX_DEF_H_ */ /*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/clock-arch.c b/arch/cpu/cc13xx-cc26xx/dev/clock-arch.c index e39d54f4c..3396240e8 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/clock-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/clock-arch.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,114 +27,110 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup cc26xx-clocks + * \addtogroup cc13xx-cc26xx-cpu * @{ * - * \defgroup cc26xx-software-clock Software Clock + * \defgroup cc13xx-cc26xx-clock CC13xx/CC26xx clock library * - * Implementation of the clock module for the CC26xx and CC13xx. - * - * The software clock uses the facilities provided by the AON RTC driver * @{ - * * \file - * Software clock implementation for the TI CC13xx/CC26xx + * Implementation of the clock libary for CC13xx/CC26xx. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "sys/etimer.h" +/*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/aon_rtc.h) #include DeviceFamily_constructPath(driverlib/cpu.h) #include DeviceFamily_constructPath(driverlib/interrupt.h) #include DeviceFamily_constructPath(driverlib/prcm.h) #include DeviceFamily_constructPath(driverlib/timer.h) + #include +#include #include - -#include "contiki.h" - -#define DPL_CLOCK_TICK_PERIOD_US ClockP_getSystemTickPeriod() -#define CLOCK_TICKS_SECOND ((uint32_t)1000000 / (CLOCK_SECOND) / (DPL_CLOCK_TICK_PERIOD_US)) - /*---------------------------------------------------------------------------*/ -static volatile uint64_t count; -static ClockP_Struct etimerClock; -static void clock_update(void); -/*---------------------------------------------------------------------------*/ -void -clock_init(void) -{ - count = 0; - ClockP_Params params; - ClockP_Params_init(¶ms); - params.period = CLOCK_TICKS_SECOND; - params.startFlag = true; - ClockP_construct(&etimerClock, (ClockP_Fxn)&clock_update, CLOCK_TICKS_SECOND, ¶ms); -} -/*---------------------------------------------------------------------------*/ -clock_time_t -clock_time(void) -{ - uint64_t count_read; - { - const uintptr_t key = HwiP_disable(); - count_read = count; - HwiP_restore(key); - } - - return (clock_time_t)(count_read & 0xFFFFFFFF); -} +static volatile clock_time_t count; +static ClockP_Struct etimer_clock; /*---------------------------------------------------------------------------*/ static void -clock_update(void) +clock_update_cb(void) { - { - const uintptr_t key = HwiP_disable(); - count += 1; - HwiP_restore(key); - } + const uintptr_t key = HwiP_disable(); + count += 1; + HwiP_restore(key); + /* Notify the etimer system. */ if (etimer_pending()) { etimer_request_poll(); } } /*---------------------------------------------------------------------------*/ +static inline clock_time_t +get_count(void) +{ + clock_time_t count_read; + + const uintptr_t key = HwiP_disable(); + count_read = count; + HwiP_restore(key); + + return count_read; +} +/*---------------------------------------------------------------------------*/ +void +clock_init(void) +{ + /* ClockP_getSystemTickPeriod() returns ticks per us. */ + const uint32_t clockp_ticks_second = + (uint32_t)(1000 * 1000) / (CLOCK_SECOND) / ClockP_getSystemTickPeriod(); + + count = 0; + + ClockP_Params params; + ClockP_Params_init(¶ms); + + params.period = clockp_ticks_second; + params.startFlag = true; + + ClockP_construct(&etimer_clock, (ClockP_Fxn)&clock_update_cb, + clockp_ticks_second, ¶ms); +} +/*---------------------------------------------------------------------------*/ +clock_time_t +clock_time(void) +{ + return get_count(); +} +/*---------------------------------------------------------------------------*/ unsigned long clock_seconds(void) { - uint64_t count_read; - { - const uintptr_t key = HwiP_disable(); - count_read = count; - HwiP_restore(key); - } - - return (unsigned long)count_read / CLOCK_SECOND; + return (unsigned long)get_count() / CLOCK_SECOND; } /*---------------------------------------------------------------------------*/ void clock_wait(clock_time_t i) { - const clock_time_t start = clock_time(); - while(clock_time() - start < (clock_time_t)i); + clock_time_t start; + + start = clock_time(); + while(clock_time() - start < i); } /*---------------------------------------------------------------------------*/ void -clock_delay_usec(uint16_t len) +clock_delay_usec(uint16_t usec) { - // See driverlib/cpu.h - const uint32_t cpu_clock_mhz = 48; - // Code in flash, cache disabled: 7 cycles per loop - const uint32_t cycles_per_loop = 7; - // ui32Count = [delay in us] * [CPU clock in MHz] / [cycles per loop] - const uint32_t count = (uint32_t)len * cpu_clock_mhz / cycles_per_loop; - CPUdelay(count); + ClockP_usleep(usec); } /*---------------------------------------------------------------------------*/ /** - * \brief Obsolete delay function but we implement it here since some code - * still uses it + * \brief Obsolete delay function but we implement it here since some code + * still uses it. */ void clock_delay(unsigned int i) diff --git a/arch/cpu/cc13xx-cc26xx/dev/dbg-arch.c b/arch/cpu/cc13xx-cc26xx/dev/dbg-arch.c index a12a877ed..1c9ec68cc 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/dbg-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/dbg-arch.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,21 +27,35 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + * \addtogroup cc13xx-cc26xx-platform + * @{ + * + * \file + * Implementation of the dbg module for CC13xx/CC26xx, used by stdio. + * The dbg module is implemented by writing to UART0. + * \author + * Edvard Pettersen + */ /*---------------------------------------------------------------------------*/ +#include "contiki.h" #include "sys/cc.h" /*---------------------------------------------------------------------------*/ +#include "uart0-arch.h" +/*---------------------------------------------------------------------------*/ #include #include #include /*---------------------------------------------------------------------------*/ -#include "uart0-arch.h" -/*---------------------------------------------------------------------------*/ int dbg_putchar(int c) { - const unsigned char ch = (unsigned char)c; + unsigned char ch; + int num_bytes; - const int num_bytes = (int)uart0_write(&ch, 1); + ch = (unsigned char)c; + + num_bytes = (int)uart0_write(&ch, 1); return (num_bytes > 0) ? num_bytes : 0; @@ -50,17 +64,21 @@ dbg_putchar(int c) unsigned int dbg_send_bytes(const unsigned char *seq, unsigned int len) { - const size_t seq_len = strlen((const char *)seq); + size_t seq_len; + size_t max_len; + int num_bytes; - const size_t max_len = MIN(seq_len, (size_t)len); + seq_len = strlen((const char *)seq); + max_len = MIN(seq_len, (size_t)len); if (max_len == 0) { return 0; } - const int num_bytes = (int)uart0_write(seq, max_len); + num_bytes = (int)uart0_write(seq, max_len); return (num_bytes > 0) - ? num_bytes - : 0; + ? num_bytes + : 0; } /*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c b/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c index 38ebe4a0c..c88549149 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c @@ -1,11 +1,10 @@ /* - * Copyright (c) 2017, George Oikonomou - http://www.spd.gr + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * 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 @@ -28,31 +27,30 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup cc26xx-gpio-hal + * \addtogroup cc13xx-cc26xx-gpio-hal * @{ * * \file - * Implementation file for the CC13xx/CC26xx GPIO HAL functions + * Implementation of the GPIO HAL module for CC13xx/CC26xx. The GPIO + * HAL module is implemented by using the PINCC26XX module, except + * for multi-dio functions which use the GPIO driverlib module. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "dev/gpio-hal.h" - +/*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/gpio.h) #include #include - +/*---------------------------------------------------------------------------*/ #include /*---------------------------------------------------------------------------*/ -static PIN_Config pin_config[] = -{ - PIN_TERMINATE -}; - +static PIN_Config pin_config[] = { PIN_TERMINATE }; static PIN_State pin_state; static PIN_Handle pin_handle; /*---------------------------------------------------------------------------*/ @@ -65,10 +63,12 @@ from_hal_cfg(gpio_hal_pin_cfg_t cfg, PIN_Config *pin_cfg, PIN_Config *pin_mask) if (cfg & GPIO_HAL_PIN_BM_INPUT) { *pin_mask |= PIN_BM_INPUT_MODE; + /* Hysteresis config */ if ((cfg & GPIO_HAL_PIN_BM_INPUT_HYSTERESIS) == GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS) { *pin_cfg |= PIN_HYSTERESIS; } + /* Pulling config */ switch (cfg & GPIO_HAL_PIN_BM_INPUT_PULLING) { case GPIO_HAL_PIN_CFG_INPUT_NOPULL: *pin_cfg |= PIN_NOPULL; break; case GPIO_HAL_PIN_CFG_INPUT_PULLUP: *pin_cfg |= PIN_PULLUP; break; @@ -80,16 +80,19 @@ from_hal_cfg(gpio_hal_pin_cfg_t cfg, PIN_Config *pin_cfg, PIN_Config *pin_mask) if (cfg & GPIO_HAL_PIN_BM_OUTPUT) { *pin_mask |= PIN_BM_OUTPUT_MODE; + /* Output buffer type config */ switch (cfg & GPIO_HAL_PIN_BM_OUTPUT_BUF) { case GPIO_HAL_PIN_CFG_OUTPUT_PUSHPULL: *pin_cfg |= PIN_PUSHPULL; break; case GPIO_HAL_PIN_CFG_OUTPUT_OPENDRAIN: *pin_cfg |= PIN_OPENDRAIN; break; case GPIO_HAL_PIN_CFG_OUTPUT_OPENSOURCE: *pin_cfg |= PIN_OPENSOURCE; break; } + /* Slew control config */ if ((cfg & GPIO_HAL_PIN_BM_OUTPUT_SLEWCTRL) == GPIO_HAL_PIN_CFG_OUTPUT_SLEWCTRL) { *pin_cfg |= PIN_SLEWCTRL; } + /* Drive strength config */ switch (cfg & GPIO_HAL_PIN_BM_OUTPUT_DRVSTR) { case GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MIN: *pin_cfg |= PIN_DRVSTR_MIN; break; case GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MED: *pin_cfg |= PIN_DRVSTR_MED; break; @@ -101,7 +104,8 @@ from_hal_cfg(gpio_hal_pin_cfg_t cfg, PIN_Config *pin_cfg, PIN_Config *pin_mask) if (cfg & GPIO_HAL_PIN_BM_INT) { *pin_mask |= PIN_BM_IRQ; - switch (cfg & GPIO_HAL_PIN_BM_OUTPUT_BUF) { + /* Interrupt edge config */ + switch (cfg & GPIO_HAL_PIN_BM_INT) { case GPIO_HAL_PIN_CFG_INT_DISABLE: *pin_cfg |= PIN_IRQ_DIS; break; case GPIO_HAL_PIN_CFG_INT_FALLING: *pin_cfg |= PIN_IRQ_NEGEDGE; break; case GPIO_HAL_PIN_CFG_INT_RISING: *pin_cfg |= PIN_IRQ_POSEDGE; break; @@ -115,10 +119,12 @@ to_hal_cfg(PIN_Config pin_cfg, gpio_hal_pin_cfg_t *cfg) { /* Input config */ if (pin_cfg & PIN_BM_INPUT_MODE) { + /* Hysteresis config */ if ((pin_cfg & PIN_BM_HYSTERESIS) == PIN_HYSTERESIS) { *cfg |= GPIO_HAL_PIN_BM_INPUT_HYSTERESIS; } + /* Pulling config */ switch (pin_cfg & PIN_BM_PULLING) { case PIN_NOPULL: *cfg |= GPIO_HAL_PIN_CFG_INPUT_NOPULL; break; case PIN_PULLUP: *cfg |= GPIO_HAL_PIN_CFG_INPUT_PULLUP; break; @@ -128,16 +134,19 @@ to_hal_cfg(PIN_Config pin_cfg, gpio_hal_pin_cfg_t *cfg) /* Output config */ if (pin_cfg & PIN_BM_OUTPUT_MODE) { + /* Output buffer type config */ switch (pin_cfg & PIN_BM_OUTPUT_BUF) { case PIN_PUSHPULL: *cfg |= GPIO_HAL_PIN_CFG_OUTPUT_PUSHPULL; break; case PIN_OPENDRAIN: *cfg |= GPIO_HAL_PIN_CFG_OUTPUT_OPENDRAIN; break; case PIN_OPENSOURCE: *cfg |= GPIO_HAL_PIN_CFG_OUTPUT_OPENSOURCE; break; } + /* Slew control config */ if ((pin_cfg & PIN_BM_SLEWCTRL) == PIN_SLEWCTRL) { *cfg |= GPIO_HAL_PIN_CFG_OUTPUT_SLEWCTRL; } + /* Drive strength config */ switch (pin_cfg & PIN_BM_DRVSTR) { case PIN_DRVSTR_MIN: *cfg |= GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MIN; break; case PIN_DRVSTR_MED: *cfg |= GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MED; break; @@ -147,6 +156,7 @@ to_hal_cfg(PIN_Config pin_cfg, gpio_hal_pin_cfg_t *cfg) /* Interrupt config */ if (pin_cfg & PIN_BM_IRQ) { + /* Interrupt edge config */ switch (pin_cfg & PIN_BM_IRQ) { case PIN_IRQ_DIS: *cfg |= GPIO_HAL_PIN_CFG_INT_DISABLE; break; case PIN_IRQ_NEGEDGE: *cfg |= GPIO_HAL_PIN_CFG_INT_FALLING; break; @@ -162,6 +172,7 @@ gpio_int_cb(PIN_Handle handle, PIN_Id pin_id) /* Unused args */ (void)handle; + /* Notify the GPIO HAL driver */ gpio_hal_event_handler(gpio_hal_pin_to_mask(pin_id)); } @@ -204,7 +215,7 @@ gpio_hal_arch_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg) { PIN_add(pin_handle, PIN_getConfig(pin)); - /* Clear settings that we are about to change, keep everything else */ + /* Clear settings that we are about to change, keep everything else. */ PIN_Config pin_cfg = 0; PIN_Config pin_mask = 0; diff --git a/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.h b/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.h index d175ec301..3ca169a82 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.h +++ b/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.h @@ -1,11 +1,10 @@ /* - * Copyright (c) 2017, George Oikonomou - http://www.spd.gr + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * 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 @@ -28,36 +27,31 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup cc26xx + * \addtogroup cc13xx-cc26xx-cpu * @{ * - * \defgroup cc26xx-gpio-hal CC13xx/CC26xx GPIO HAL implementation + * \defgroup cc13xx-cc26xx-gpio-hal CC13xx/CC26xx GPIO HAL implementation * * @{ * * \file - * Header file for the CC13xx/CC26xx GPIO HAL functions - * + * Header file for the CC13xx/CC26xx GPIO HAL functions. + * \author + * Edvard Pettersen * \note - * Do not include this header directly + * Do not include this header directly. */ /*---------------------------------------------------------------------------*/ #ifndef GPIO_HAL_ARCH_H_ #define GPIO_HAL_ARCH_H_ /*---------------------------------------------------------------------------*/ #include "contiki.h" - +/*---------------------------------------------------------------------------*/ #include -#include DeviceFamily_constructPath(driverlib/ioc.h) #include DeviceFamily_constructPath(driverlib/gpio.h) -#include #include - -#include -#include /*---------------------------------------------------------------------------*/ #define gpio_hal_arch_pin_set_input(p) PINCC26XX_setOutputEnable(p, false) #define gpio_hal_arch_pin_set_output(p) PINCC26XX_setOutputEnable(p, true) diff --git a/arch/cpu/cc13xx-cc26xx/dev/int-master-arch.c b/arch/cpu/cc13xx-cc26xx/dev/int-master-arch.c index c06cc364f..2c72992e6 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/int-master-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/int-master-arch.c @@ -1,11 +1,10 @@ /* - * Copyright (c) 2017, George Oikonomou - http://www.spd.gr + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * 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 @@ -28,23 +27,23 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup cc26xx + * \addtogroup cc13xx-cc26xx-cpu * @{ * - * \defgroup cc26xx-interrupts CC13xx-CC26xx master interrupt manipulation + * \defgroup cc13xx-cc26xx-int-master CC13xx/CC26xx master interrupt manipulation * - * Master interrupt manipulation routines for the CC13xx and CC26xx CPUs + * Master interrupt manipulation routines for CC13xx/CC26xx. * * @{ * * \file - * Master interrupt manipulation implementation for the TI CC13xx/CC26xx + * Master interrupt manipulation implementation for CC13xx/CC26xx. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #include "contiki.h" - #include "sys/int-master.h" /*---------------------------------------------------------------------------*/ #include @@ -52,6 +51,9 @@ #include /*---------------------------------------------------------------------------*/ +#include +#include +/*---------------------------------------------------------------------------*/ void int_master_enable(void) { @@ -61,13 +63,13 @@ int_master_enable(void) int_master_status_t int_master_read_and_disable(void) { - return HwiP_disable(); + return (int_master_status_t)HwiP_disable(); } /*---------------------------------------------------------------------------*/ void int_master_status_set(int_master_status_t status) { - HwiP_restore(status); + HwiP_restore((uintptr_t)status); } /*---------------------------------------------------------------------------*/ bool diff --git a/arch/cpu/cc13xx-cc26xx/dev/random-arch.c b/arch/cpu/cc13xx-cc26xx/dev/random.c similarity index 67% rename from arch/cpu/cc13xx-cc26xx/dev/random-arch.c rename to arch/cpu/cc13xx-cc26xx/dev/random.c index 87962e501..3232a06d2 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/random-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/random.c @@ -28,38 +28,66 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup cc26xx-trng + * \addtogroup cc13xx-cc26xx-prng * @{ * - * \file + * Implementation based on Bob Jenkins' small noncryptographic PRNG. + * http://burtleburtle.net/bob/rand/smallprng.html * - * This file overrides os/lib/random.c and calls SoC-specific RNG functions + * \file + * This file overrides os/lib/random.c. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #include /*---------------------------------------------------------------------------*/ -#include +#include +/*---------------------------------------------------------------------------*/ +typedef struct { + uint32_t a; + uint32_t b; + uint32_t c; + uint32_t d; +} ranctx_t; + +static ranctx_t ranctx; +/*---------------------------------------------------------------------------*/ +#define rot32(x, k) (((x) << (k)) | ((x) >> (32 - (k)))) /*---------------------------------------------------------------------------*/ /** - * \brief Generates a new random number using the hardware TRNG. - * \return The random number. + * \brief Generates a new random number using the PRNG. + * \return The random number. */ unsigned short random_rand(void) { - return (unsigned short)soc_trng_rand_synchronous() & 0xFFFF; + uint32_t e; + + e = ranctx.a - rot32(ranctx.b, 27); + ranctx.a = ranctx.b ^ rot32(ranctx.c, 17); + ranctx.b = ranctx.c + ranctx.d; + ranctx.c = ranctx.d + e; + ranctx.d = e + ranctx.a; + + return (unsigned short)ranctx.d; } /*---------------------------------------------------------------------------*/ /** - * \brief Function required by the API - * \param seed Ignored. + * \brief Function required by the API + * \param seed Ignored. */ void random_init(unsigned short seed) { - soc_trng_init(); + uint32_t i; + + ranctx.a = 0xf1ea5eed; + ranctx.b = ranctx.c = ranctx.d = (uint32_t)seed; + for(i = 0; i < 20; ++i) { + (void)random_rand(); + } } /*---------------------------------------------------------------------------*/ /** diff --git a/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c b/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c index 05e8b51f3..345ea80bb 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,9 +27,8 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup cc26xx-rtimer + * \addtogroup cc13xx-cc26xx-rtimer * @{ * * \file diff --git a/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c b/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c index 869414920..1618f6d71 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c +++ b/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c @@ -89,23 +89,23 @@ extern unsigned long _stack_end; __attribute__ ((section(".resetVecs"))) __attribute__ ((used)) static void (* const resetVectors[16])(void) = { - (void (*)(void))((uint32_t)&_stack_end), - // The initial stack pointer - resetISR, // The reset handler - nmiISR, // The NMI handler - faultISR, // The hard fault handler - defaultHandler, // The MPU fault handler - busFaultHandler, // The bus fault handler - defaultHandler, // The usage fault handler - 0, // Reserved - 0, // Reserved - 0, // Reserved - 0, // Reserved - defaultHandler, // SVCall handler - defaultHandler, // Debug monitor handler - 0, // Reserved - defaultHandler, // The PendSV handler - defaultHandler // The SysTick handler + (void (*)(void))((uint32_t)&_stack_end), + // The initial stack pointer + resetISR, // The reset handler + nmiISR, // The NMI handler + faultISR, // The hard fault handler + defaultHandler, // The MPU fault handler + busFaultHandler, // The bus fault handler + defaultHandler, // The usage fault handler + 0, // Reserved + 0, // Reserved + 0, // Reserved + 0, // Reserved + defaultHandler, // SVCall handler + defaultHandler, // Debug monitor handler + 0, // Reserved + defaultHandler, // The PendSV handler + defaultHandler // The SysTick handler }; //***************************************************************************** // @@ -113,15 +113,15 @@ static void (* const resetVectors[16])(void) = // be called during startup to initialize global objects. // //***************************************************************************** -extern void (*__init_array_start []) (void); -extern void (*__init_array_end []) (void); +extern void (*__init_array_start[])(void); +extern void (*__init_array_end[])(void); //***************************************************************************** // // The following global variable is required for C++ support. // //***************************************************************************** -void * __dso_handle = (void *) &__dso_handle; +void *__dso_handle = (void *)&__dso_handle; //***************************************************************************** // @@ -130,8 +130,11 @@ void * __dso_handle = (void *) &__dso_handle; // for the "data" segment resides immediately following the "text" segment. // //***************************************************************************** -extern uint32_t __bss_start__, __bss_end__; -extern uint32_t __data_load__, __data_start__, __data_end__; +extern uint32_t __bss_start__; +extern uint32_t __bss_end__; +extern uint32_t __data_load__; +extern uint32_t __data_start__; +extern uint32_t __data_end__; // //***************************************************************************** @@ -144,51 +147,51 @@ extern uint32_t __data_load__, __data_start__, __data_end__; // void localProgramStart(void) { - uint32_t * bs; - uint32_t * be; - uint32_t * dl; - uint32_t * ds; - uint32_t * de; - uint32_t count; - uint32_t i; + uint32_t *bs; + uint32_t *be; + uint32_t *dl; + uint32_t *ds; + uint32_t *de; + uint32_t count; + uint32_t i; #if defined (__ARM_ARCH_7EM__) && defined(__VFP_FP__) && !defined(__SOFTFP__) - volatile uint32_t * pui32Cpacr = (uint32_t *) 0xE000ED88; + volatile uint32_t *pui32Cpacr = (uint32_t *)0xE000ED88; - /* Enable Coprocessor Access Control (CPAC) */ - *pui32Cpacr |= (0xF << 20); + /* Enable Coprocessor Access Control (CPAC) */ + *pui32Cpacr |= (0xF << 20); #endif - IntMasterDisable(); + IntMasterDisable(); - /* Final trim of device */ - SetupTrimDevice(); + /* Final trim of device */ + SetupTrimDevice(); - /* initiailize .bss to zero */ - bs = & __bss_start__; - be = & __bss_end__; - while (bs < be) { - *bs = 0; - bs++; + /* initiailize .bss to zero */ + bs = &__bss_start__; + be = &__bss_end__; + while(bs < be) { + *bs = 0; + bs++; + } + + /* relocate the .data section */ + dl = &__data_load__; + ds = &__data_start__; + de = &__data_end__; + if(dl != ds) { + while(ds < de) { + *ds = *dl; + dl++; + ds++; } + } - /* relocate the .data section */ - dl = & __data_load__; - ds = & __data_start__; - de = & __data_end__; - if (dl != ds) { - while (ds < de) { - *ds = *dl; - dl++; - ds++; - } - } - - /* Run any constructors */ - count = (uint32_t)(__init_array_end - __init_array_start); - for (i = 0; i < count; i++) { - __init_array_start[i](); - } + /* Run any constructors */ + count = (uint32_t)(__init_array_end - __init_array_start); + for(i = 0; i < count; i++) { + __init_array_start[i](); + } /* Call the application's entry point. */ main(); @@ -209,13 +212,14 @@ void localProgramStart(void) //***************************************************************************** void __attribute__((naked)) resetISR(void) { - __asm__ __volatile__ ( - " movw r0, #:lower16:resetVectors\n" - " movt r0, #:upper16:resetVectors\n" - " ldr r0, [r0]\n" - " mov sp, r0\n" - " bl localProgramStart" - ); + __asm__ __volatile__ + ( + "movw r0, #:lower16:resetVectors \n" + "movt r0, #:upper16:resetVectors \n" + "ldr r0, [r0] \n" + "mov sp, r0 \n" + "bl localProgramStart \n" + ); } //***************************************************************************** @@ -228,35 +232,10 @@ void __attribute__((naked)) resetISR(void) static void nmiISR(void) { - /* Enter an infinite loop. */ - while(1) - { - } -} - -volatile int x__; - -void debugHardfault(uint32_t *sp) -{ - volatile uint32_t r0; - volatile uint32_t r1; - volatile uint32_t r2; - volatile uint32_t r3; - volatile uint32_t r12; - volatile uint32_t lr; - volatile uint32_t pc; - volatile uint32_t psr; - - (void)(r0 = sp[0]); - (void)(r1 = sp[1]); - (void)(r2 = sp[2]); - (void)(r3 = sp[3]); - (void)(r12 = sp[4]); - (void)(lr = sp[5]); - (void)(pc = sp[6]); - (void)(psr = sp[7]); - - while(1); + /* Enter an infinite loop. */ + while(1) + { + } } //***************************************************************************** @@ -266,16 +245,40 @@ void debugHardfault(uint32_t *sp) // for examination by a debugger. // //***************************************************************************** +void +debugHardfault(uint32_t *sp) +{ + volatile uint32_t r0; + volatile uint32_t r1; + volatile uint32_t r2; + volatile uint32_t r3; + volatile uint32_t r12; + volatile uint32_t lr; + volatile uint32_t pc; + volatile uint32_t psr; + + (void)(r0 = sp[0]); + (void)(r1 = sp[1]); + (void)(r2 = sp[2]); + (void)(r3 = sp[3]); + (void)(r12 = sp[4]); + (void)(lr = sp[5]); + (void)(pc = sp[6]); + (void)(psr = sp[7]); + + while(1); +} + static void faultISR(void) { - __asm volatile + __asm__ __volatile__ ( - "tst lr, #4 \n" - "ite eq \n" - "mrseq r0, msp \n" - "mrsne r0, psp \n" - "b debugHardfault \n" + "tst lr, #4 \n" + "ite eq \n" + "mrseq r0, msp \n" + "mrsne r0, psp \n" + "b debugHardfault \n" ); } @@ -286,15 +289,16 @@ faultISR(void) // for examination by a debugger. // //***************************************************************************** +volatile int x__; static void busFaultHandler(void) { x__ = 0; - /* Enter an infinite loop. */ - while(1) - { - } + /* Enter an infinite loop. */ + while(1) + { + } } //***************************************************************************** @@ -307,10 +311,10 @@ busFaultHandler(void) static void defaultHandler(void) { - /* Enter an infinite loop. */ - while(1) - { - } + /* Enter an infinite loop. */ + while(1) + { + } } //***************************************************************************** diff --git a/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_iar.c b/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_iar.c new file mode 100644 index 000000000..9279ea523 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_iar.c @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2017, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Texas Instruments Incorporated 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 OWNER 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. + */ + +//***************************************************************************** +// +// Check if compiler is IAR +// +//***************************************************************************** +#if !(defined(__IAR_SYSTEMS_ICC__)) +#error "startup_cc13xx_cc26xx_iar.c: Unsupported compiler!" +#endif + + +// We need intrinsic functions for IAR (if used in source code) +#include +#include +#include DeviceFamily_constructPath(inc/hw_types.h) +#include DeviceFamily_constructPath(driverlib/setup.h) +#include DeviceFamily_constructPath(driverlib/interrupt.h) + + +//***************************************************************************** +// +//! Forward declaration of the reset ISR and the default fault handlers. +// +//***************************************************************************** +static void nmiISR( void ); +static void faultISR( void ); +static void intDefaultHandler( void ); +extern int main( void ); + +extern void MPUFaultIntHandler( void ); +extern void BusFaultIntHandler( void ); +extern void UsageFaultIntHandler( void ); +extern void SVCallIntHandler( void ); +extern void DebugMonIntHandler( void ); +extern void PendSVIntHandler( void ); +extern void SysTickIntHandler( void ); +extern void GPIOIntHandler( void ); +extern void I2CIntHandler( void ); +extern void RFCCPE1IntHandler( void ); +extern void AONRTCIntHandler( void ); +extern void UART0IntHandler( void ); +extern void AUXSWEvent0IntHandler( void ); +extern void SSI0IntHandler( void ); +extern void SSI1IntHandler( void ); +extern void RFCCPE0IntHandler( void ); +extern void RFCHardwareIntHandler( void ); +extern void RFCCmdAckIntHandler( void ); +extern void I2SIntHandler( void ); +extern void AUXSWEvent1IntHandler( void ); +extern void WatchdogIntHandler( void ); +extern void Timer0AIntHandler( void ); +extern void Timer0BIntHandler( void ); +extern void Timer1AIntHandler( void ); +extern void Timer1BIntHandler( void ); +extern void Timer2AIntHandler( void ); +extern void Timer2BIntHandler( void ); +extern void Timer3AIntHandler( void ); +extern void Timer3BIntHandler( void ); +extern void CryptoIntHandler( void ); +extern void uDMAIntHandler( void ); +extern void uDMAErrIntHandler( void ); +extern void FlashIntHandler( void ); +extern void SWEvent0IntHandler( void ); +extern void AUXCombEventIntHandler( void ); +extern void AONProgIntHandler( void ); +extern void DynProgIntHandler( void ); +extern void AUXCompAIntHandler( void ); +extern void AUXADCIntHandler( void ); +extern void TRNGIntHandler( void ); + +// Default interrupt handlers +#pragma weak MPUFaultIntHandler = intDefaultHandler +#pragma weak BusFaultIntHandler = intDefaultHandler +#pragma weak UsageFaultIntHandler = intDefaultHandler +#pragma weak SVCallIntHandler = intDefaultHandler +#pragma weak DebugMonIntHandler = intDefaultHandler +#pragma weak PendSVIntHandler = intDefaultHandler +#pragma weak SysTickIntHandler = intDefaultHandler +#pragma weak GPIOIntHandler = intDefaultHandler +#pragma weak I2CIntHandler = intDefaultHandler +#pragma weak RFCCPE1IntHandler = intDefaultHandler +#pragma weak AONRTCIntHandler = intDefaultHandler +#pragma weak UART0IntHandler = intDefaultHandler +#pragma weak AUXSWEvent0IntHandler = intDefaultHandler +#pragma weak SSI0IntHandler = intDefaultHandler +#pragma weak SSI1IntHandler = intDefaultHandler +#pragma weak RFCCPE0IntHandler = intDefaultHandler +#pragma weak RFCHardwareIntHandler = intDefaultHandler +#pragma weak RFCCmdAckIntHandler = intDefaultHandler +#pragma weak I2SIntHandler = intDefaultHandler +#pragma weak AUXSWEvent1IntHandler = intDefaultHandler +#pragma weak WatchdogIntHandler = intDefaultHandler +#pragma weak Timer0AIntHandler = intDefaultHandler +#pragma weak Timer0BIntHandler = intDefaultHandler +#pragma weak Timer1AIntHandler = intDefaultHandler +#pragma weak Timer1BIntHandler = intDefaultHandler +#pragma weak Timer2AIntHandler = intDefaultHandler +#pragma weak Timer2BIntHandler = intDefaultHandler +#pragma weak Timer3AIntHandler = intDefaultHandler +#pragma weak Timer3BIntHandler = intDefaultHandler +#pragma weak CryptoIntHandler = intDefaultHandler +#pragma weak uDMAIntHandler = intDefaultHandler +#pragma weak uDMAErrIntHandler = intDefaultHandler +#pragma weak FlashIntHandler = intDefaultHandler +#pragma weak SWEvent0IntHandler = intDefaultHandler +#pragma weak AUXCombEventIntHandler = intDefaultHandler +#pragma weak AONProgIntHandler = intDefaultHandler +#pragma weak DynProgIntHandler = intDefaultHandler +#pragma weak AUXCompAIntHandler = intDefaultHandler +#pragma weak AUXADCIntHandler = intDefaultHandler +#pragma weak TRNGIntHandler = intDefaultHandler + +//***************************************************************************** +// +//! The entry point for the application startup code. +// +//***************************************************************************** +extern void __iar_program_start(void); + +//***************************************************************************** +// +//! Get stack start (highest address) symbol from linker file. +// +//***************************************************************************** +extern const void* STACK_TOP; + +// It is required to place something in the CSTACK segment to get the stack +// check feature in IAR to work as expected +__root static void* dummy_stack @ ".stack"; + + +//***************************************************************************** +// +//! The vector table. Note that the proper constructs must be placed on this to +//! ensure that it ends up at physical address 0x0000.0000 or at the start of +//! the program if located at a start address other than 0. +// +//***************************************************************************** +__root void (* const __vector_table[])(void) @ ".intvec" = +{ + (void (*)(void))&STACK_TOP, // 0 The initial stack pointer + __iar_program_start, // 1 The reset handler + nmiISR, // 2 The NMI handler + faultISR, // 3 The hard fault handler + MPUFaultIntHandler, // 4 The MPU fault handler + BusFaultIntHandler, // 5 The bus fault handler + UsageFaultIntHandler, // 6 The usage fault handler + 0, // 7 Reserved + 0, // 8 Reserved + 0, // 9 Reserved + 0, // 10 Reserved + SVCallIntHandler, // 11 SVCall handler + DebugMonIntHandler, // 12 Debug monitor handler + 0, // 13 Reserved + PendSVIntHandler, // 14 The PendSV handler + SysTickIntHandler, // 15 The SysTick handler + //--- External interrupts --- + GPIOIntHandler, // 16 AON edge detect + I2CIntHandler, // 17 I2C + RFCCPE1IntHandler, // 18 RF Core Command & Packet Engine 1 + intDefaultHandler, // 19 Reserved + AONRTCIntHandler, // 20 AON RTC + UART0IntHandler, // 21 UART0 Rx and Tx + AUXSWEvent0IntHandler, // 22 AUX software event 0 + SSI0IntHandler, // 23 SSI0 Rx and Tx + SSI1IntHandler, // 24 SSI1 Rx and Tx + RFCCPE0IntHandler, // 25 RF Core Command & Packet Engine 0 + RFCHardwareIntHandler, // 26 RF Core Hardware + RFCCmdAckIntHandler, // 27 RF Core Command Acknowledge + I2SIntHandler, // 28 I2S + AUXSWEvent1IntHandler, // 29 AUX software event 1 + WatchdogIntHandler, // 30 Watchdog timer + Timer0AIntHandler, // 31 Timer 0 subtimer A + Timer0BIntHandler, // 32 Timer 0 subtimer B + Timer1AIntHandler, // 33 Timer 1 subtimer A + Timer1BIntHandler, // 34 Timer 1 subtimer B + Timer2AIntHandler, // 35 Timer 2 subtimer A + Timer2BIntHandler, // 36 Timer 2 subtimer B + Timer3AIntHandler, // 37 Timer 3 subtimer A + Timer3BIntHandler, // 38 Timer 3 subtimer B + CryptoIntHandler, // 39 Crypto Core Result available + uDMAIntHandler, // 40 uDMA Software + uDMAErrIntHandler, // 41 uDMA Error + FlashIntHandler, // 42 Flash controller + SWEvent0IntHandler, // 43 Software Event 0 + AUXCombEventIntHandler, // 44 AUX combined event + AONProgIntHandler, // 45 AON programmable 0 + DynProgIntHandler, // 46 Dynamic Programmable interrupt + // source (Default: PRCM) + AUXCompAIntHandler, // 47 AUX Comparator A + AUXADCIntHandler, // 48 AUX ADC new sample or ADC DMA + // done, ADC underflow, ADC overflow + TRNGIntHandler // 49 TRNG event +}; + + +//***************************************************************************** +// +// This function is called by __iar_program_start() early in the boot sequence. +// Copy the first 16 vectors from the read-only/reset table to the runtime +// RAM table. Fill the remaining vectors with a stub. This vector table will +// be updated at runtime. +// +//***************************************************************************** +int __low_level_init(void) +{ + IntMasterDisable(); + + // + // Final trim of device + // + SetupTrimDevice(); + + /*==================================*/ + /* Choose if segment initialization */ + /* should be done or not. */ + /* Return: 0 to omit seg_init */ + /* 1 to run seg_init */ + /*==================================*/ + return 1; +} + +//***************************************************************************** +// +//! This is the code that gets called when the processor receives a NMI. This +//! simply enters an infinite loop, preserving the system state for examination +//! by a debugger. +// +//***************************************************************************** +static void +nmiISR(void) +{ + // + // Enter an infinite loop. + // + while(1) + { + } +} + +//***************************************************************************** +// +//! This is the code that gets called when the processor receives a fault +//! interrupt. This simply enters an infinite loop, preserving the system state +//! for examination by a debugger. +// +//***************************************************************************** +static void +faultISR(void) +{ + // + // Enter an infinite loop. + // + while(1) + { + } +} + +//***************************************************************************** +// +//! This is the code that gets called when the processor receives an unexpected +//! interrupt. This simply enters an infinite loop, preserving the system state +//! for examination by a debugger. +// +//***************************************************************************** +static void +intDefaultHandler(void) +{ + // + // Go into an infinite loop. + // + while(1) + { + } +} diff --git a/arch/cpu/cc13xx-cc26xx/dev/ti-lib-rom.h b/arch/cpu/cc13xx-cc26xx/dev/ti-lib-rom.h deleted file mode 100644 index cd019ce01..000000000 --- a/arch/cpu/cc13xx-cc26xx/dev/ti-lib-rom.h +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (c) 2016, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/*---------------------------------------------------------------------------*/ -/** - * \addtogroup cc26xx-ti-lib - * @{ - * - * \file - * Header file with CC13xxware/CC26xxware ROM API. - */ -/*---------------------------------------------------------------------------*/ -#ifndef TI_LIB_ROM_H_ -#define TI_LIB_ROM_H_ -/*---------------------------------------------------------------------------*/ -/* rom.h */ -#include -#include DeviceFamily_constructPath(driverlib/rom.h) - -/* AON API */ -#define ti_lib_rom_aon_event_mcu_wake_up_set ROM_AONEventMcuWakeUpSet -#define ti_lib_rom_aon_event_mcu_wake_up_get ROM_AONEventMcuWakeUpGet -#define ti_lib_rom_aon_event_aux_wake_up_set ROM_AONEventAuxWakeUpSet -#define ti_lib_rom_aon_event_aux_wake_up_get ROM_AONEventAuxWakeUpGet -#define ti_lib_rom_aon_event_mcu_set ROM_AONEventMcuSet -#define ti_lib_rom_aon_event_mcu_get ROM_AONEventMcuGet - -/* AON_WUC API */ -#define ti_lib_rom_aon_wuc_aux_reset ROM_AONWUCAuxReset -#define ti_lib_rom_aon_wuc_recharge_ctrl_config_set ROM_AONWUCRechargeCtrlConfigSet -#define ti_lib_rom_aon_wuc_osc_config ROM_AONWUCOscConfig - -/* AUX_TDC API */ -#define ti_lib_rom_aux_tdc_config_set ROM_AUXTDCConfigSet -#define ti_lib_rom_aux_tdc_measurement_done ROM_AUXTDCMeasurementDone - -/* AUX_WUC API */ -#define ti_lib_rom_aux_wuc_clock_enable ROM_AUXWUCClockEnable -#define ti_lib_rom_aux_wuc_clock_disable ROM_AUXWUCClockDisable -#define ti_lib_rom_aux_wuc_clock_status ROM_AUXWUCClockStatus -#define ti_lib_rom_aux_wuc_power_ctrl ROM_AUXWUCPowerCtrl - -/* FLASH API */ -#define ti_lib_rom_flash_power_mode_get ROM_FlashPowerModeGet -#define ti_lib_rom_flash_protection_set ROM_FlashProtectionSet -#define ti_lib_rom_flash_protection_get ROM_FlashProtectionGet -#define ti_lib_rom_flash_protection_save ROM_FlashProtectionSave -#define ti_lib_rom_flash_efuse_read_row ROM_FlashEfuseReadRow -#define ti_lib_rom_flash_disable_sectors_for_write ROM_FlashDisableSectorsForWrite - -/* I2C API */ -#define ti_lib_rom_i2c_master_init_exp_clk ROM_I2CMasterInitExpClk -#define ti_lib_rom_i2c_master_err ROM_I2CMasterErr - -/* INTERRUPT API */ -#define ti_lib_rom_int_priority_grouping_set ROM_IntPriorityGroupingSet -#define ti_lib_rom_int_priority_grouping_get ROM_IntPriorityGroupingGet -#define ti_lib_rom_int_priority_set ROM_IntPrioritySet -#define ti_lib_rom_int_priority_get ROM_IntPriorityGet -#define ti_lib_rom_int_enable ROM_IntEnable -#define ti_lib_rom_int_disable ROM_IntDisable -#define ti_lib_rom_int_pend_set ROM_IntPendSet -#define ti_lib_rom_int_pend_get ROM_IntPendGet -#define ti_lib_rom_int_pend_clear ROM_IntPendClear - -/* IOC API */ -#define ti_lib_rom_ioc_port_configure_set ROM_IOCPortConfigureSet -#define ti_lib_rom_ioc_port_configure_get ROM_IOCPortConfigureGet -#define ti_lib_rom_ioc_io_shutdown_set ROM_IOCIOShutdownSet -#define ti_lib_rom_ioc_io_mode_set ROM_IOCIOModeSet -#define ti_lib_rom_ioc_io_int_set ROM_IOCIOIntSet -#define ti_lib_rom_ioc_io_port_pull_set ROM_IOCIOPortPullSet -#define ti_lib_rom_ioc_io_hyst_set ROM_IOCIOHystSet -#define ti_lib_rom_ioc_io_input_set ROM_IOCIOInputSet -#define ti_lib_rom_ioc_io_slew_ctrl_set ROM_IOCIOSlewCtrlSet -#define ti_lib_rom_ioc_io_drv_strength_set ROM_IOCIODrvStrengthSet -#define ti_lib_rom_ioc_io_port_id_set ROM_IOCIOPortIdSet -#define ti_lib_rom_ioc_int_enable ROM_IOCIntEnable -#define ti_lib_rom_ioc_int_disable ROM_IOCIntDisable -#define ti_lib_rom_ioc_pin_type_gpio_input ROM_IOCPinTypeGpioInput -#define ti_lib_rom_ioc_pin_type_gpio_output ROM_IOCPinTypeGpioOutput -#define ti_lib_rom_ioc_pin_type_uart ROM_IOCPinTypeUart -#define ti_lib_rom_ioc_pin_type_ssi_master ROM_IOCPinTypeSsiMaster -#define ti_lib_rom_ioc_pin_type_ssi_slave ROM_IOCPinTypeSsiSlave -#define ti_lib_rom_ioc_pin_type_i2c ROM_IOCPinTypeI2c -#define ti_lib_rom_ioc_pin_type_aux ROM_IOCPinTypeAux - -/* PRCM API */ -#define ti_lib_rom_prcm_inf_clock_configure_set ROM_PRCMInfClockConfigureSet -#define ti_lib_rom_prcm_inf_clock_configure_get ROM_PRCMInfClockConfigureGet -#define ti_lib_rom_prcm_audio_clock_config_set ROM_PRCMAudioClockConfigSet -#define ti_lib_rom_prcm_power_domain_on ROM_PRCMPowerDomainOn -#define ti_lib_rom_prcm_power_domain_off ROM_PRCMPowerDomainOff -#define ti_lib_rom_prcm_peripheral_run_enable ROM_PRCMPeripheralRunEnable -#define ti_lib_rom_prcm_peripheral_run_disable ROM_PRCMPeripheralRunDisable -#define ti_lib_rom_prcm_peripheral_sleep_enable ROM_PRCMPeripheralSleepEnable -#define ti_lib_rom_prcm_peripheral_sleep_disable ROM_PRCMPeripheralSleepDisable -#define ti_lib_rom_prcm_peripheral_deep_sleep_enable ROM_PRCMPeripheralDeepSleepEnable -#define ti_lib_rom_prcm_peripheral_deep_sleep_disable ROM_PRCMPeripheralDeepSleepDisable -#define ti_lib_rom_prcm_power_domain_status ROM_PRCMPowerDomainStatus -#define ti_lib_rom_prcm_deep_sleep ROM_PRCMDeepSleep - -/* SMPH API */ -#define ti_lib_rom_smph_acquire ROM_SMPHAcquire - -/* SSI API */ -#define ti_lib_rom_ssi_config_set_exp_clk ROM_SSIConfigSetExpClk -#define ti_lib_rom_ssi_data_put ROM_SSIDataPut -#define ti_lib_rom_ssi_data_put_non_blocking ROM_SSIDataPutNonBlocking -#define ti_lib_rom_ssi_data_get ROM_SSIDataGet -#define ti_lib_rom_ssi_data_get_non_blocking ROM_SSIDataGetNonBlocking - -/* TIMER API */ -#define ti_lib_rom_timer_configure ROM_TimerConfigure -#define ti_lib_rom_timer_level_control ROM_TimerLevelControl -#define ti_lib_rom_timer_stall_control ROM_TimerStallControl -#define ti_lib_rom_timer_wait_on_trigger_control ROM_TimerWaitOnTriggerControl - -/* TRNG API */ -#define ti_lib_rom_trng_number_get ROM_TRNGNumberGet - -/* UART API */ -#define ti_lib_rom_uart_fifo_level_get ROM_UARTFIFOLevelGet -#define ti_lib_rom_uart_config_set_exp_clk ROM_UARTConfigSetExpClk -#define ti_lib_rom_uart_config_get_exp_clk ROM_UARTConfigGetExpClk -#define ti_lib_rom_uart_disable ROM_UARTDisable -#define ti_lib_rom_uart_char_get_non_blocking ROM_UARTCharGetNonBlocking -#define ti_lib_rom_uart_char_get ROM_UARTCharGet -#define ti_lib_rom_uart_char_put_non_blocking ROM_UARTCharPutNonBlocking -#define ti_lib_rom_uart_char_put ROM_UARTCharPut - -/* UDMA API */ -#define ti_lib_rom_udma_channel_attribute_enable ROM_uDMAChannelAttributeEnable -#define ti_lib_rom_udma_channel_attribute_disable ROM_uDMAChannelAttributeDisable -#define ti_lib_rom_udma_channel_attribute_get ROM_uDMAChannelAttributeGet -#define ti_lib_rom_udma_channel_control_set ROM_uDMAChannelControlSet -#define ti_lib_rom_udma_channel_transfer_set ROM_uDMAChannelTransferSet -#define ti_lib_rom_udma_channel_scatter_gather_set ROM_uDMAChannelScatterGatherSet -#define ti_lib_rom_udma_channel_size_get ROM_uDMAChannelSizeGet -#define ti_lib_rom_udma_channel_mode_get ROM_uDMAChannelModeGet - -/* VIMS API */ -#define ti_lib_rom_vims_configure ROM_VIMSConfigure -#define ti_lib_rom_vims_mode_set ROM_VIMSModeSet - -/* HAPI */ -#define ti_lib_hapi_crc32(a, b, c) HapiCrc32(a, b, c) -#define ti_lib_hapi_get_flash_size() HapiGetFlashSize() -#define ti_lib_hapi_get_chip_id() HapiGetChipId() -#define ti_lib_hapi_sector_erase(a) HapiSectorErase(a) -#define ti_lib_hapi_program_flash(a, b, c) HapiProgramFlash(a, b, c) -#define ti_lib_hapi_reset_device() HapiResetDevice() -#define ti_lib_hapi_fletcher32(a, b, c) HapiFletcher32(a, b, c) -#define ti_lib_hapi_min_value(a, b) HapiMinValue(a,b) -#define ti_lib_hapi_max_value(a, b) HapiMaxValue(a,b) -#define ti_lib_hapi_mean_value(a, b) HapiMeanValue(a,b) -#define ti_lib_hapi_stand_deviation_value(a, b) HapiStandDeviationValue(a,b) -#define ti_lib_hapi_hf_source_safe_switch() HapiHFSourceSafeSwitch() -#define ti_lib_hapi_select_comp_a_input(a) HapiSelectCompAInput(a) -#define ti_lib_hapi_select_comp_a_ref(a) HapiSelectCompARef(a) -#define ti_lib_hapi_select_adc_comp_b_input(a) HapiSelectADCCompBInput(a) -#define ti_lib_hapi_select_comp_b_ref(a) HapiSelectCompBRef(a) -/*---------------------------------------------------------------------------*/ -#endif /* TI_LIB_ROM_H_ */ -/*---------------------------------------------------------------------------*/ -/** - * @} - */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/ti-lib.h b/arch/cpu/cc13xx-cc26xx/dev/ti-lib.h deleted file mode 100644 index 022a6543f..000000000 --- a/arch/cpu/cc13xx-cc26xx/dev/ti-lib.h +++ /dev/null @@ -1,578 +0,0 @@ -/* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ - * 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. - */ -/** - * \addtogroup cc26xx - * @{ - * - * \defgroup cc26xx-ti-lib TI CC26xxware/CC13xxware Glue - * - * Glue file which renames TI CC26xxware functions. Thus, for example, - * PowerCtrlIOFreezeDisable() becomes power_ctrl_io_freeze_disable() - * - * This is not strictly required and a call to the former will work perfectly - * correctly. However, in using those macros, we make the core of the Contiki - * port match the naming convention. - * - * Since all functions are prefixed with ti_lib, it also becomes clear to the - * reader that this is a call to TI driverlib's sources and not a call to a - * function inside Contiki - * - * @{ - * - * \file - * Header file with macros which rename TI CC26xxware functions. - */ -#ifndef TI_LIB_H_ -#define TI_LIB_H -/*---------------------------------------------------------------------------*/ -/* For DeviceFamily_constructPath() */ -#include -/*---------------------------------------------------------------------------*/ -/* Include ROM API */ -#include "ti-lib-rom.h" -/*---------------------------------------------------------------------------*/ -/* aon_batmon.h */ -#include DeviceFamily_constructPath(driverlib/aon_batmon.h) - -#define ti_lib_aon_batmon_enable(...) AONBatMonEnable(__VA_ARGS__) -#define ti_lib_aon_batmon_disable(...) AONBatMonDisable(__VA_ARGS__) -#define ti_lib_aon_batmon_temperature_get_deg_c(...) AONBatMonTemperatureGetDegC(__VA_ARGS__) -#define ti_lib_aon_batmon_battery_voltage_get(...) AONBatMonBatteryVoltageGet(__VA_ARGS__) -#define ti_lib_aon_batmon_new_battery_measure_ready(...) AONBatMonNewBatteryMeasureReady(__VA_ARGS__) -#define ti_lib_aon_batmon_new_temp_measure_ready(...) AONBatMonNewTempMeasureReady(__VA_ARGS__) -/*---------------------------------------------------------------------------*/ -/* aon_event.h */ -#include DeviceFamily_constructPath(driverlib/aon_event.h) - -#define ti_lib_aon_event_mcu_wake_up_set(...) AONEventMcuWakeUpSet(__VA_ARGS__) -#define ti_lib_aon_event_mcu_wake_up_get(...) AONEventMcuWakeUpGet(__VA_ARGS__) -#define ti_lib_aon_event_aux_wake_up_set(...) AONEventAuxWakeUpSet(__VA_ARGS__) -#define ti_lib_aon_event_aux_wake_up_get(...) AONEventAuxWakeUpGet(__VA_ARGS__) -#define ti_lib_aon_event_mcu_set(...) AONEventMcuSet(__VA_ARGS__) -#define ti_lib_aon_event_mcu_get(...) AONEventMcuGet(__VA_ARGS__) -#define ti_lib_aon_event_rtc_set(...) AONEventRtcSet(__VA_ARGS__) -#define ti_lib_aon_event_rtc_get(...) AONEventRtcGet(__VA_ARGS__) -/*---------------------------------------------------------------------------*/ -/* aon_ioc.h */ -#include DeviceFamily_constructPath(driverlib/aon_ioc.h) - -#define ti_lib_aon_ioc_drive_strength_set(...) AONIOCDriveStrengthSet(__VA_ARGS__) -#define ti_lib_aon_ioc_drive_strength_get(...) AONIOCDriveStrengthGet(__VA_ARGS__) -#define ti_lib_aon_ioc_freeze_enable(...) AONIOCFreezeEnable(__VA_ARGS__) -#define ti_lib_aon_ioc_freeze_disable(...) AONIOCFreezeDisable(__VA_ARGS__) -#define ti_lib_aon_ioc_32_khz_output_disable(...) AONIOC32kHzOutputDisable(__VA_ARGS__) -#define ti_lib_aon_ioc_32_khz_output_enable(...) AONIOC32kHzOutputEnable(__VA_ARGS__) -/*---------------------------------------------------------------------------*/ -/* aon_rtc.h */ -#include DeviceFamily_constructPath(driverlib/aon_rtc.h) - -#define ti_lib_aon_rtc_enable(...) AONRTCEnable(__VA_ARGS__) -#define ti_lib_aon_rtc_disable(...) AONRTCDisable(__VA_ARGS__) -#define ti_lib_aon_rtc_active(...) AONRTCActive(__VA_ARGS__) -#define ti_lib_aon_rtc_channel_active(...) AONRTCChannelActive(__VA_ARGS__) -#define ti_lib_aon_rtc_reset(...) AONRTCReset(__VA_ARGS__) -#define ti_lib_aon_rtc_delay_config(...) AONRTCDelayConfig(__VA_ARGS__) -#define ti_lib_aon_rtc_combined_event_config(...) AONRTCCombinedEventConfig(__VA_ARGS__) -#define ti_lib_aon_rtc_event_clear(...) AONRTCEventClear(__VA_ARGS__) -#define ti_lib_aon_rtc_event_get(...) AONRTCEventGet(__VA_ARGS__) -#define ti_lib_aon_rtc_sec_get(...) AONRTCSecGet(__VA_ARGS__) -#define ti_lib_aon_rtc_fraction_get(...) AONRTCFractionGet(__VA_ARGS__) -#define ti_lib_aon_rtc_sub_sec_incr_get(...) AONRTCSubSecIncrGet(__VA_ARGS__) -#define ti_lib_aon_rtc_mode_ch1_set(...) AONRTCModeCh1Set(__VA_ARGS__) -#define ti_lib_aon_rtc_mode_ch1_get(...) AONRTCModeCh1Get(__VA_ARGS__) -#define ti_lib_aon_rtc_mode_ch2_set(...) AONRTCModeCh2Set(__VA_ARGS__) -#define ti_lib_aon_rtc_mode_ch2_get(...) AONRTCModeCh2Get(__VA_ARGS__) -#define ti_lib_aon_rtc_channel_enable(...) AONRTCChannelEnable(__VA_ARGS__) -#define ti_lib_aon_rtc_channel_disable(...) AONRTCChannelDisable(__VA_ARGS__) -#define ti_lib_aon_rtc_compare_value_set(...) AONRTCCompareValueSet(__VA_ARGS__) -#define ti_lib_aon_rtc_compare_value_get(...) AONRTCCompareValueGet(__VA_ARGS__) -#define ti_lib_aon_rtc_current_compare_value_get(...) AONRTCCurrentCompareValueGet(__VA_ARGS__) -#define ti_lib_aon_rtc_current_64_bit_value_get(...) AONRTCCurrent64BitValueGet(__VA_ARGS__) -#define ti_lib_aon_rtc_inc_value_ch2_set(...) AONRTCIncValueCh2Set(__VA_ARGS__) -#define ti_lib_aon_rtc_inc_value_ch2_get(...) AONRTCIncValueCh2Get(__VA_ARGS__) -#define ti_lib_aon_rtc_capture_value_ch1_get(...) AONRTCCaptureValueCh1Get(__VA_ARGS__) -/*---------------------------------------------------------------------------*/ -#if DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0 -/* aon_wuc.h */ -#include DeviceFamily_constructPath(driverlib/aon_wuc.h) - -#define ti_lib_aon_wuc_mcu_wake_up_config(...) AONWUCMcuWakeUpConfig(__VA_ARGS__) -#define ti_lib_aon_wuc_mcu_power_down_config(...) AONWUCMcuPowerDownConfig(__VA_ARGS__) -#define ti_lib_aon_wuc_mcu_power_off_config(...) AONWUCMcuPowerOffConfig(__VA_ARGS__) -#define ti_lib_aon_wuc_mcu_sram_config(...) AONWUCMcuSRamConfig(__VA_ARGS__) -#define ti_lib_aon_wuc_aux_clock_config_get(...) AONWUCAuxClockConfigGet(__VA_ARGS__) -#define ti_lib_aon_wuc_aux_power_down_config(...) AONWUCAuxPowerDownConfig(__VA_ARGS__) -#define ti_lib_aon_wuc_aux_wake_up_config(...) AONWUCAuxWakeUpConfig(__VA_ARGS__) -#define ti_lib_aon_wuc_aux_sram_config(...) AONWUCAuxSRamConfig(__VA_ARGS__) -#define ti_lib_aon_wuc_aux_wakeup_event(...) AONWUCAuxWakeupEvent(__VA_ARGS__) -#define ti_lib_aon_wuc_aux_image_valid(...) AONWUCAuxImageValid(__VA_ARGS__) -#define ti_lib_aon_wuc_aux_image_invalid(...) AONWUCAuxImageInvalid(__VA_ARGS__) -#define ti_lib_aon_wuc_aux_reset(...) AONWUCAuxReset(__VA_ARGS__) -#define ti_lib_aon_wuc_power_status_get(...) AONWUCPowerStatusGet(__VA_ARGS__) -#define ti_lib_aon_wuc_shut_down_enable(...) AONWUCShutDownEnable(__VA_ARGS__) -#define ti_lib_aon_wuc_domain_power_down_enable(...) AONWUCDomainPowerDownEnable(__VA_ARGS__) -#define ti_lib_aon_wuc_domain_power_down_disable(...) AONWUCDomainPowerDownDisable(__VA_ARGS__) -#define ti_lib_aon_wuc_mcu_reset_status_get(...) AONWUCMcuResetStatusGet(__VA_ARGS__) -#define ti_lib_aon_wuc_mcu_reset_clear(...) AONWUCMcuResetClear(__VA_ARGS__) -#define ti_lib_aon_wuc_recharge_ctrl_config_set(...) AONWUCRechargeCtrlConfigSet(__VA_ARGS__) -#define ti_lib_aon_wuc_recharge_ctrl_config_get(...) AONWUCRechargeCtrlConfigGet(__VA_ARGS__) -#define ti_lib_aon_wuc_osc_config(...) AONWUCOscConfig(__VA_ARGS__) -#define ti_lib_aon_wuc_jtag_power_off(...) AONWUCJtagPowerOff(__VA_ARGS__) - -#endif /* DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0 */ -/*---------------------------------------------------------------------------*/ -/* aux_adc.h */ -#include DeviceFamily_constructPath(driverlib/aux_adc.h) - -#define ti_lib_aux_adc_disable(...) AUXADCDisable(__VA_ARGS__) -#define ti_lib_aux_adc_enable_async(...) AUXADCEnableAsync(__VA_ARGS__) -#define ti_lib_aux_adc_enable_sync(...) AUXADCEnableSync(__VA_ARGS__) -#define ti_lib_aux_adc_disable_input_scaling(...) AUXADCDisableInputScaling(__VA_ARGS__) -#define ti_lib_aux_adc_flush_fifo(...) AUXADCFlushFifo(__VA_ARGS__) -#define ti_lib_aux_adc_gen_manual_trigger(...) AUXADCGenManualTrigger(__VA_ARGS__) -#define ti_lib_aux_adc_get_fifo_status(...) AUXADCGetFifoStatus(__VA_ARGS__) -#define ti_lib_aux_adc_read_fifo(...) AUXADCReadFifo(__VA_ARGS__) -#define ti_lib_aux_adc_pop_fifo(...) AUXADCPopFifo(__VA_ARGS__) -#define ti_lib_aux_adc_select_input(...) AUXADCSelectInput(__VA_ARGS__) -#define ti_lib_aux_adc_get_adjustment_gain(...) AUXADCGetAdjustmentGain(__VA_ARGS__) -#define ti_lib_aux_adc_get_adjustment_offset(...) AUXADCGetAdjustmentOffset(__VA_ARGS__) -#define ti_lib_aux_adc_value_to_microvolts(...) AUXADCValueToMicrovolts(__VA_ARGS__) -#define ti_lib_aux_adc_microvolts_to_value(...) AUXADCMicrovoltsToValue(__VA_ARGS__) -#define ti_lib_aux_adc_adjust_value_for_gain_and_offset(...) AUXADCAdjustValueForGainAndOffset(__VA_ARGS__) -#define ti_lib_aux_adc_unadjust_value_for_gain_and_offset(...) AUXADCUnadjustValueForGainAndOffset(__VA_ARGS__) -/*---------------------------------------------------------------------------*/ -#if DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0 -/* aux_wuc.h */ -#include DeviceFamily_constructPath(driverlib/aux_wuc.h) - -#define ti_lib_aux_wuc_clock_enable(...) AUXWUCClockEnable(__VA_ARGS__) -#define ti_lib_aux_wuc_clock_disable(...) AUXWUCClockDisable(__VA_ARGS__) -#define ti_lib_aux_wuc_clock_status(...) AUXWUCClockStatus(__VA_ARGS__) -#define ti_lib_aux_wuc_clock_freq_req(...) AUXWUCClockFreqReq(__VA_ARGS__) -#define ti_lib_aux_wuc_power_ctrl(...) AUXWUCPowerCtrl(__VA_ARGS__) -#define ti_lib_aux_wuc_freeze_enable(...) AUXWUCFreezeEnable(__VA_ARGS__) -#define ti_lib_aux_wuc_freeze_disable(...) AUXWUCFreezeDisable(__VA_ARGS__) - -#endif /* DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0 */ -/*---------------------------------------------------------------------------*/ -/* cpu.h */ -#include DeviceFamily_constructPath(driverlib/cpu.h) - -#define ti_lib_cpu_cpsid(...) CPUcpsid(__VA_ARGS__) -#define ti_lib_cpu_cpsie(...) CPUcpsie(__VA_ARGS__) -#define ti_lib_cpu_primask(...) CPUprimask(__VA_ARGS__) -#define ti_lib_cpu_wfi(...) CPUwfi(__VA_ARGS__) -#define ti_lib_cpu_wfe(...) CPUwfe(__VA_ARGS__) -#define ti_lib_cpu_sev(...) CPUsev(__VA_ARGS__) -#define ti_lib_cpu_base_pri_get(...) CPUbasepriGet(__VA_ARGS__) -#define ti_lib_cpu_base_pri_set(...) CPUbasepriSet(__VA_ARGS__) -#define ti_lib_cpu_delay(...) CPUdelay(__VA_ARGS__) -/*---------------------------------------------------------------------------*/ -/* chipinfo.h */ -#include DeviceFamily_constructPath(driverlib/chipinfo.h) - -#define ti_lib_chipinfo_get_supported_protocol_bv(...) ChipInfo_GetSupportedProtocol_BV(__VA_ARGS__) -#define ti_lib_chipinfo_supports_ble(...) ChipInfo_SupportsBLE(__VA_ARGS__) -#define ti_lib_chipinfo_supports_ieee_802_15_4(...) ChipInfo_SupportsIEEE_802_15_4(__VA_ARGS__) -#define ti_lib_chipinfo_supports_proprietary(...) ChipInfo_SupportsPROPRIETARY(__VA_ARGS__) -#define ti_lib_chipinfo_get_package_type(...) ChipInfo_GetPackageType(__VA_ARGS__) -#define ti_lib_chipinfo_package_type_is_4x4(...) ChipInfo_PackageTypeIs4x4(__VA_ARGS__) -#define ti_lib_chipinfo_package_type_is_5x5(...) ChipInfo_PackageTypeIs5x5(__VA_ARGS__) -#define ti_lib_chipinfo_package_type_is_7x7(...) ChipInfo_PackageTypeIs7x7(__VA_ARGS__) -#define ti_lib_chipinfo_get_device_id_hw_rev_code(...) ChipInfo_GetDeviceIdHwRevCode(__VA_ARGS__) -#define ti_lib_chipinfo_get_chip_type(...) ChipInfo_GetChipType(__VA_ARGS__) -#define ti_lib_chipinfo_get_chip_family(...) ChipInfo_GetChipFamily(__VA_ARGS__) -#define ti_lib_chipinfo_chip_family_is_cc13x0(...) ChipInfo_ChipFamilyIs_CC13x0(__VA_ARGS__) -#define ti_lib_chipinfo_chip_family_is_cc26x0(...) ChipInfo_ChipFamilyIs_CC26x0(__VA_ARGS__) -#define ti_lib_chipinfo_chip_family_is_cc26x0r2(...) ChipInfo_ChipFamilyIs_CC26x0R2(__VA_ARGS__) -#define ti_lib_chipinfo_chip_family_is_cc26x1(...) ChipInfo_ChipFamilyIs_CC26x1(__VA_ARGS__) -#define ti_lib_chipinfo_chip_family_is_cc13x2_cc26x2(...) ChipInfo_ChipFamilyIs_CC13x2_CC26x2(__VA_ARGS__) -#define ti_lib_chipinfo_get_hw_revision(...) ChipInfo_GetHwRevision(__VA_ARGS__) -#define ti_lib_chipinfo_hw_revision_is_1_0(...) ChipInfo_HwRevisionIs_1_0(__VA_ARGS__) -#define ti_lib_chipinfo_hw_revision_is_gteq_2_0(...) ChipInfo_HwRevisionIs_GTEQ_2_0(__VA_ARGS__) -#define ti_lib_chipinfo_hw_revision_is_2_0(...) ChipInfo_HwRevisionIs_2_0(__VA_ARGS__) -#define ti_lib_chipinfo_hw_revision_is_2_1(...) ChipInfo_HwRevisionIs_2_1(__VA_ARGS__) -#define ti_lib_chipinfo_hw_revision_is_2_2(...) ChipInfo_HwRevisionIs_2_2(__VA_ARGS__) -#define ti_lib_chipinfo_hw_revision_is_gteq_2_2(...) ChipInfo_HwRevisionIs_GTEQ_2_2( __VA_ARGS__ ) -/*---------------------------------------------------------------------------*/ -/* ddi.h */ -#include DeviceFamily_constructPath(driverlib/ddi.h) - -#define ti_lib_aux_adi_ddi_safe_write(...) AuxAdiDdiSafeWrite(__VA_ARGS__) -#define ti_lib_aux_adi_ddi_safe_read(...) AuxAdiDdiSafeRead(__VA_ARGS__) -#define ti_lib_ddi_32_reg_write(...) DDI32RegWrite(__VA_ARGS__) -#define ti_lib_ddi_32_reg_read(...) DDI32RegRead(__VA_ARGS__) -#define ti_lib_ddi_32_bits_set(...) DDI32BitsSet(__VA_ARGS__) -#define ti_lib_ddi_32_bits_clear(...) DDI32BitsClear(__VA_ARGS__) -#define ti_lib_ddi_8_set_val_bit(...) DDI8SetValBit(__VA_ARGS__) -#define ti_lib_ddi_16_set_val_bit(...) DDI16SetValBit(__VA_ARGS__) -#define ti_lib_ddi_16_bit_write(...) DDI16BitWrite(__VA_ARGS__) -#define ti_lib_ddi_16_bit_field_write(...) DDI16BitfieldWrite(__VA_ARGS__) -#define ti_lib_ddi_16_bit_read(...) DDI16BitRead(__VA_ARGS__) -#define ti_lib_ddi_16_bitfield_read(...) DDI16BitfieldRead(__VA_ARGS__) -/*---------------------------------------------------------------------------*/ -/* gpio.h */ -#include DeviceFamily_constructPath(driverlib/gpio.h) - -#define ti_lib_gpio_read_dio(...) GPIO_readDio(__VA_ARGS__) -#define ti_lib_gpio_read_multi_dio(...) GPIO_readMultiDio(__VA_ARGS__) -#define ti_lib_gpio_write_dio(...) GPIO_writeDio(__VA_ARGS__) -#define ti_lib_gpio_write_multi_dio(...) GPIO_writeMultiDio(__VA_ARGS__) -#define ti_lib_gpio_set_dio(...) GPIO_setDio(__VA_ARGS__) -#define ti_lib_gpio_set_multi_dio(...) GPIO_setMultiDio(__VA_ARGS__) -#define ti_lib_gpio_clear_dio(...) GPIO_clearDio(__VA_ARGS__) -#define ti_lib_gpio_clear_multi_dio(...) GPIO_clearMultiDio(__VA_ARGS__) -#define ti_lib_gpio_toggle_dio(...) GPIO_toggleDio(__VA_ARGS__) -#define ti_lib_gpio_toggle_multi_dio(...) GPIO_toggleMultiDio(__VA_ARGS__) -#define ti_lib_gpio_get_output_enable_dio(...) GPIO_getOutputEnableDio(__VA_ARGS__) -#define ti_lib_gpio_get_output_enable_multi_dio(...) GPIO_getOutputEnableMultiDio(__VA_ARGS__) -#define ti_lib_gpio_set_output_enable_dio(...) GPIO_setOutputEnableDio(__VA_ARGS__) -#define ti_lib_gpio_set_output_enable_multi_dio(...) GPIO_setOutputEnableMultiDio(__VA_ARGS__) -#define ti_lib_gpio_get_event_dio(...) GPIO_getEventDio(__VA_ARGS__) -#define ti_lib_gpio_get_event_multi_dio(...) GPIO_getEventMultiDio(__VA_ARGS__) -#define ti_lib_gpio_clear_event_dio(...) GPIO_clearEventDio(__VA_ARGS__) -#define ti_lib_gpio_clear_event_multi_dio(...) GPIO_clearEventMultiDio(__VA_ARGS__) -/*---------------------------------------------------------------------------*/ -/* i2c.h */ -#include DeviceFamily_constructPath(driverlib/i2c.h) - -#define ti_lib_i2c_int_register(...) I2CIntRegister(__VA_ARGS__) -#define ti_lib_i2c_int_unregister(...) I2CIntUnregister(__VA_ARGS__) -#define ti_lib_i2c_master_bus_busy(...) I2CMasterBusBusy(__VA_ARGS__) -#define ti_lib_i2c_master_busy(...) I2CMasterBusy(__VA_ARGS__) -#define ti_lib_i2c_master_control(...) I2CMasterControl(__VA_ARGS__) -#define ti_lib_i2c_master_data_get(...) I2CMasterDataGet(__VA_ARGS__) -#define ti_lib_i2c_master_data_put(...) I2CMasterDataPut(__VA_ARGS__) -#define ti_lib_i2c_master_disable(...) I2CMasterDisable(__VA_ARGS__) -#define ti_lib_i2c_master_enable(...) I2CMasterEnable(__VA_ARGS__) -#define ti_lib_i2c_master_err(...) I2CMasterErr(__VA_ARGS__) -#define ti_lib_i2c_master_init_exp_clk(...) I2CMasterInitExpClk(__VA_ARGS__) -#define ti_lib_i2c_master_int_clear(...) I2CMasterIntClear(__VA_ARGS__) -#define ti_lib_i2c_master_int_disable(...) I2CMasterIntDisable(__VA_ARGS__) -#define ti_lib_i2c_master_int_enable(...) I2CMasterIntEnable(__VA_ARGS__) -#define ti_lib_i2c_master_int_status(...) I2CMasterIntStatus(__VA_ARGS__) -#define ti_lib_i2c_master_slave_addr_set(...) I2CMasterSlaveAddrSet(__VA_ARGS__) -#define ti_lib_i2c_slave_data_get(...) I2CSlaveDataGet(__VA_ARGS__) -#define ti_lib_i2c_slave_data_put(...) I2CSlaveDataPut(__VA_ARGS__) -#define ti_lib_i2c_slave_disable(...) I2CSlaveDisable(__VA_ARGS__) -#define ti_lib_i2c_slave_enable(...) I2CSlaveEnable(__VA_ARGS__) -#define ti_lib_i2c_slave_init(...) I2CSlaveInit(__VA_ARGS__) -#define ti_lib_i2c_slave_address_set(...) I2CSlaveAddressSet(__VA_ARGS__) -#define ti_lib_i2c_slave_int_clear(...) I2CSlaveIntClear(__VA_ARGS__) -#define ti_lib_i2c_slave_int_disable(...) I2CSlaveIntDisable(__VA_ARGS__) -#define ti_lib_i2c_slave_int_enable(...) I2CSlaveIntEnable(__VA_ARGS__) -#define ti_lib_i2c_slave_int_status(...) I2CSlaveIntStatus(__VA_ARGS__) -#define ti_lib_i2c_slave_status(...) I2CSlaveStatus(__VA_ARGS__) -/*---------------------------------------------------------------------------*/ -/* interrupt.h */ -#include DeviceFamily_constructPath(driverlib/interrupt.h) - -#define ti_lib_int_master_enable(...) IntMasterEnable(__VA_ARGS__) -#define ti_lib_int_master_disable(...) IntMasterDisable(__VA_ARGS__) -#define ti_lib_int_register(...) IntRegister(__VA_ARGS__); -#define ti_lib_int_unregsiter(...) IntUnregister(__VA_ARGS__) -#define ti_lib_int_priority_grouping_set(...) IntPriorityGroupingSet(__VA_ARGS__) -#define ti_lib_int_priority_grouping_get(...) IntPriorityGroupingGet(__VA_ARGS__) -#define ti_lib_int_priority_set(...) IntPrioritySet(__VA_ARGS__) -#define ti_lib_int_priority_get(...) IntPriorityGet(__VA_ARGS__) -#define ti_lib_int_enable(...) IntEnable(__VA_ARGS__) -#define ti_lib_int_disable(...) IntDisable(__VA_ARGS__) -#define ti_lib_int_pend_set(...) IntPendSet(__VA_ARGS__) -#define ti_lib_int_pend_get(...) IntPendGet(__VA_ARGS__) -#define ti_lib_int_pend_clear(...) IntPendClear(__VA_ARGS__) -#define ti_lib_int_mask_set(...) IntPriorityMaskSet(__VA_ARGS__) -#define ti_lib_int_mask_get(...) IntPriorityMaskGet(__VA_ARGS__) -/*---------------------------------------------------------------------------*/ -/* ioc.h */ -#include DeviceFamily_constructPath(driverlib/ioc.h) - -#define ti_lib_ioc_port_configure_set(...) IOCPortConfigureSet(__VA_ARGS__) -#define ti_lib_ioc_port_configure_get(...) IOCPortConfigureGet(__VA_ARGS__) -#define ti_lib_ioc_io_shutdown_set(...) IOCIOShutdownSet(__VA_ARGS__) -#define ti_lib_ioc_io_mode_set(...) IOCIOModeSet(__VA_ARGS__) -#define ti_lib_ioc_io_port_pull_set(...) IOCIOPortPullSet(__VA_ARGS__) -#define ti_lib_ioc_io_hyst_set(...) IOCIOHystSet(__VA_ARGS__) -#define ti_lib_ioc_io_input_set(...) IOCIOInputSet(__VA_ARGS__) -#define ti_lib_ioc_io_slew_ctrl_set(...) IOCIOSlewCtrlSet(__VA_ARGS__) -#define ti_lib_ioc_io_drv_strength_set(...) IOCIODrvStrengthSet(__VA_ARGS__) -#define ti_lib_ioc_io_port_id_set(...) IOCIOPortIdSet(__VA_ARGS__) -#define ti_lib_ioc_io_int_set(...) IOCIOIntSet(__VA_ARGS__) -#define ti_lib_ioc_int_register(...) IOCIntRegister(__VA_ARGS__); -#define ti_lib_ioc_int_unregister(...) IOCIntUnregister(__VA_ARGS__) -#define ti_lib_ioc_int_enable(...) IOCIntEnable(__VA_ARGS__) -#define ti_lib_ioc_int_disable(...) IOCIntDisable(__VA_ARGS__) -#define ti_lib_ioc_int_clear(...) IOCIntClear(__VA_ARGS__) -#define ti_lib_ioc_int_status(...) IOCIntStatus(__VA_ARGS__) -#define ti_lib_ioc_pin_type_gpio_input(...) IOCPinTypeGpioInput(__VA_ARGS__) -#define ti_lib_ioc_pin_type_gpio_output(...) IOCPinTypeGpioOutput(__VA_ARGS__) -#define ti_lib_ioc_pin_type_uart(...) IOCPinTypeUart(__VA_ARGS__) -#define ti_lib_ioc_pin_type_ssi_master(...) IOCPinTypeSsiMaster(__VA_ARGS__) -#define ti_lib_ioc_pin_type_ssi_slave(...) IOCPinTypeSsiSlave(__VA_ARGS__) -#define ti_lib_ioc_pin_type_i2c(...) IOCPinTypeI2c(__VA_ARGS__) -#define ti_lib_ioc_pin_type_aux(...) IOCPinTypeAux(__VA_ARGS__) -#define ti_lib_ioc_pin_type_spis(...) IOCPinTypeSpis(__VA_ARGS__) -/*---------------------------------------------------------------------------*/ -/* osc.h */ -#include DeviceFamily_constructPath(driverlib/osc.h) - -#define ti_lib_osc_xhf_power_mode_set(...) OSCXHfPowerModeSet(__VA_ARGS__) -#define ti_lib_osc_clock_loss_event_enable(...) OSCClockLossEventEnable(__VA_ARGS__) -#define ti_lib_osc_clock_loss_event_disable(...) OSCClockLossEventDisable(__VA_ARGS__) -#define ti_lib_osc_clock_source_set(...) OSCClockSourceSet(__VA_ARGS__) -#define ti_lib_osc_clock_source_get(...) OSCClockSourceGet(__VA_ARGS__) -#define ti_lib_osc_hf_source_ready(...) OSCHfSourceReady(__VA_ARGS__) -#define ti_lib_osc_hf_source_switch(...) OSCHfSourceSwitch(__VA_ARGS__) -#define ti_lib_osc_hf_get_startup_time(...) OSCHF_GetStartupTime(__VA_ARGS__) -#define ti_lib_osc_hf_turn_on_xosc(...) OSCHF_TurnOnXosc(__VA_ARGS__) -#define ti_lib_osc_hf_attempt_to_switch_to_xosc(...) OSCHF_AttemptToSwitchToXosc(__VA_ARGS__) -#define ti_lib_osc_hf_debug_get_crystal_amplitude(...) OSCHF_DebugGetCrystalAmplitude(__VA_ARGS__) -#define ti_lib_osc_hf_debug_get_expected_average_crystal_amplitude(...) \ - OSCHF_DebugGetExpectedAverageCrystalAmplitude(__VA_ARGS__) -#define ti_lib_osc_hposc_relative_frequency_offset_get(...) OSC_HPOSCRelativeFrequencyOffsetGet(__VA_ARGS__) -#define ti_lib_osc_hposc_relative_frequency_offset_to_rf_core_format_convert(...) \ - OSC_HPOSCRelativeFrequencyOffsetToRFCoreFormatConvert(__VA_ARGS__) -#define ti_lib_osc_hf_switch_to_rc_osc_turn_off_xosc(...) OSCHF_SwitchToRcOscTurnOffXosc(__VA_ARGS__) -/*---------------------------------------------------------------------------*/ -/* prcm.h */ -#include DeviceFamily_constructPath(driverlib/prcm.h) - -#define ti_lib_prcm_inf_clock_configure_set(...) PRCMInfClockConfigureSet(__VA_ARGS__) -#define ti_lib_prcm_inf_clock_configure_get(...) PRCMInfClockConfigureGet(__VA_ARGS__) -#define ti_lib_prcm_mcu_power_off(...) PRCMMcuPowerOff(__VA_ARGS__) -#define ti_lib_prcm_mcu_power_off_cancel(...) PRCMMcuPowerOffCancel(__VA_ARGS__) -#define ti_lib_prcm_mcu_uldo_configure(...) PRCMMcuUldoConfigure(__VA_ARGS__) -#define ti_lib_prcm_audio_clock_enable(...) PRCMAudioClockEnable(__VA_ARGS__) -#define ti_lib_prcm_audio_clock_disable(...) PRCMAudioClockDisable(__VA_ARGS__) -#define ti_lib_prcm_audio_clock_config_set(...) PRCMAudioClockConfigSet(__VA_ARGS__) -#define ti_lib_prcm_load_set(...) PRCMLoadSet(__VA_ARGS__) -#define ti_lib_prcm_load_get(...) PRCMLoadGet(__VA_ARGS__) -#define ti_lib_prcm_domain_enable(...) PRCMDomainEnable(__VA_ARGS__) -#define ti_lib_prcm_domain_disable(...) PRCMDomainDisable(__VA_ARGS__) -#define ti_lib_prcm_power_domain_on(...) PRCMPowerDomainOn(__VA_ARGS__) -#define ti_lib_prcm_power_domain_off(...) PRCMPowerDomainOff(__VA_ARGS__) -#define ti_lib_prcm_rf_power_down_when_idle(...) PRCMRfPowerDownWhenIdle(__VA_ARGS__) -#define ti_lib_prcm_peripheral_run_enable(...) PRCMPeripheralRunEnable(__VA_ARGS__) -#define ti_lib_prcm_peripheral_run_disable(...) PRCMPeripheralRunDisable(__VA_ARGS__) -#define ti_lib_prcm_peripheral_sleep_enable(...) PRCMPeripheralSleepEnable(__VA_ARGS__) -#define ti_lib_prcm_peripheral_sleep_disable(...) PRCMPeripheralSleepDisable(__VA_ARGS__) -#define ti_lib_prcm_peripheral_deep_sleep_enable(...) PRCMPeripheralDeepSleepEnable(__VA_ARGS__) -#define ti_lib_prcm_peripheral_deep_sleep_disable(...) PRCMPeripheralDeepSleepDisable(__VA_ARGS__) -#define ti_lib_prcm_power_domain_status(...) PRCMPowerDomainStatus(__VA_ARGS__) -#define ti_lib_prcm_rf_ready(...) PRCMRfReady(__VA_ARGS__) -#define ti_lib_prcm_sleep(...) PRCMSleep(__VA_ARGS__) -#define ti_lib_prcm_deep_sleep(...) PRCMDeepSleep(__VA_ARGS__) -#define ti_lib_prcm_cache_retention_enable(...) PRCMCacheRetentionEnable(__VA_ARGS__) -#define ti_lib_prcm_cache_retention_disable(...) PRCMCacheRetentionDisable(__VA_ARGS__) -/*---------------------------------------------------------------------------*/ -/* sys_ctrl.h */ -#include DeviceFamily_constructPath(driverlib/pwr_ctrl.h) - -#define ti_lib_pwr_ctrl_state_set(...) PowerCtrlStateSet(__VA_ARGS__) -#define ti_lib_pwr_ctrl_source_set(...) PowerCtrlSourceSet(__VA_ARGS__) -#define ti_lib_pwr_ctrl_source_get(...) PowerCtrlSourceGet(__VA_ARGS__) -#define ti_lib_pwr_ctrl_reset_source_get(...) PowerCtrlResetSourceGet(__VA_ARGS__) -#define ti_lib_pwr_ctrl_reset_source_clear(...) PowerCtrlResetSourceClear(__VA_ARGS__) -#define ti_lib_pwr_ctrl_io_freeze_enable(...) PowerCtrlIOFreezeEnable(__VA_ARGS__) -#define ti_lib_pwr_ctrl_io_freeze_disable(...) PowerCtrlIOFreezeDisable(__VA_ARGS__) -/*---------------------------------------------------------------------------*/ -/* rfc.h */ -#include DeviceFamily_constructPath(driverlib/rfc.h) - -#define ti_lib_rfc_rtrim(...) RFCRTrim(__VA_ARGS__) -#define ti_lib_rfc_adi3vco_ldo_voltage_mode(...) RFCAdi3VcoLdoVoltageMode(__VA_ARGS__) -/*---------------------------------------------------------------------------*/ -/* sys_ctrl.h */ -#include DeviceFamily_constructPath(driverlib/sys_ctrl.h) - -#define ti_lib_sys_ctrl_power_everything(...) SysCtrlPowerEverything(__VA_ARGS__) -#define ti_lib_sys_ctrl_powerdown(...) SysCtrlPowerdown(__VA_ARGS__) -#define ti_lib_sys_ctrl_standby(...) SysCtrlStandby(__VA_ARGS__) -#define ti_lib_sys_ctrl_shutdown(...) SysCtrlShutdown(__VA_ARGS__) -#define ti_lib_sys_ctrl_clock_get(...) SysCtrlClockGet(__VA_ARGS__) -#define ti_lib_sys_ctrl_aon_sync(...) SysCtrlAonSync(__VA_ARGS__) -#define ti_lib_sys_ctrl_aon_update(...) SysCtrlAonUpdate(__VA_ARGS__) -#define ti_lib_sys_ctrl_set_recharge_before_power_down(...) SysCtrlSetRechargeBeforePowerDown(__VA_ARGS__) -#define ti_lib_sys_ctrl_adjust_recharge_after_power_down(...) SysCtrlAdjustRechargeAfterPowerDown(__VA_ARGS__) -#define ti_lib_sys_ctrl_dcdc_voltage_conditional_control(...) SysCtrl_DCDC_VoltageConditionalControl(__VA_ARGS__) -#define ti_lib_sys_ctrl_reset_source_get(...) SysCtrlResetSourceGet(__VA_ARGS__) -#define ti_lib_sys_ctrl_system_reset(...) SysCtrlSystemReset(__VA_ARGS__) -/*---------------------------------------------------------------------------*/ -/* ssi.h */ -#include DeviceFamily_constructPath(driverlib/ssi.h) - -#define ti_lib_ssi_config_set_exp_clk(...) SSIConfigSetExpClk(__VA_ARGS__) -#define ti_lib_ssi_enable(...) SSIEnable(__VA_ARGS__) -#define ti_lib_ssi_disable(...) SSIDisable(__VA_ARGS__) -#define ti_lib_ssi_data_put(...) SSIDataPut(__VA_ARGS__) -#define ti_lib_ssi_data_put_non_blocking(...) SSIDataPutNonBlocking(__VA_ARGS__) -#define ti_lib_ssi_data_get(...) SSIDataGet(__VA_ARGS__) -#define ti_lib_ssi_data_get_non_blocking(...) SSIDataGetNonBlocking(__VA_ARGS__) -#define ti_lib_ssi_busy(...) SSIBusy(__VA_ARGS__) -#define ti_lib_ssi_status(...) SSIStatus(__VA_ARGS__) -#define ti_lib_ssi_int_register(...) SSIIntRegister(__VA_ARGS__) -#define ti_lib_ssi_int_unregister(...) SSIIntUnregister(__VA_ARGS__) -#define ti_lib_ssi_int_enable(...) SSIIntEnable(__VA_ARGS__) -#define ti_lib_ssi_int_disable(...) SSIIntDisable(__VA_ARGS__) -#define ti_lib_ssi_int_clear(...) SSIIntClear(__VA_ARGS__) -#define ti_lib_ssi_int_status(...) SSIIntStatus(__VA_ARGS__) -#define ti_lib_ssi_dma_enable(...) SSIDMAEnable(__VA_ARGS__) -#define ti_lib_ssi_dma_disable(...) SSIDMADisable(__VA_ARGS__) -/*---------------------------------------------------------------------------*/ -/* systick.h */ -#include DeviceFamily_constructPath(driverlib/systick.h) - -#define ti_lib_systick_enable(...) SysTickEnable(__VA_ARGS__) -#define ti_lib_systick_disable(...) SysTickDisable(__VA_ARGS__) -#define ti_lib_systick_int_register(...) SysTickIntRegister(__VA_ARGS__) -#define ti_lib_systick_int_unregister(...) SysTickIntUnregister(__VA_ARGS__) -#define ti_lib_systick_int_enable(...) SysTickIntEnable(__VA_ARGS__) -#define ti_lib_systick_int_disable(...) SysTickIntDisable(__VA_ARGS__) -#define ti_lib_systick_period_set(...) SysTickPeriodSet(__VA_ARGS__) -#define ti_lib_systick_period_get(...) SysTickPeriodGet(__VA_ARGS__) -#define ti_lib_systick_value_get(...) SysTickValueGet(__VA_ARGS__) -/*---------------------------------------------------------------------------*/ -/* timer.h */ -#include DeviceFamily_constructPath(driverlib/timer.h) - -#define ti_lib_timer_enable(...) TimerEnable(__VA_ARGS__) -#define ti_lib_timer_disable(...) TimerDisable(__VA_ARGS__) -#define ti_lib_timer_configure(...) TimerConfigure(__VA_ARGS__) -#define ti_lib_timer_level_control(...) TimerLevelControl(__VA_ARGS__) -#define ti_lib_timer_event_control(...) TimerEventControl(__VA_ARGS__) -#define ti_lib_timer_stall_control(...) TimerStallControl(__VA_ARGS__) -#define ti_lib_timer_wait_on_trigger_control(...) TimerWaitOnTriggerControl(__VA_ARGS__) -#define ti_lib_timer_rtc_enable(...) TimerRtcEnable(__VA_ARGS__) -#define ti_lib_timer_rtc_disable(...) TimerRtcDisable(__VA_ARGS__) -#define ti_lib_timer_prescale_set(...) TimerPrescaleSet(__VA_ARGS__) -#define ti_lib_timer_prescale_get(...) TimerPrescaleGet(__VA_ARGS__) -#define ti_lib_timer_prescale_match_set(...) TimerPrescaleMatchSet(__VA_ARGS__) -#define ti_lib_timer_prescale_match_get(...) TimerPrescaleMatchGet(__VA_ARGS__) -#define ti_lib_timer_load_set(...) TimerLoadSet(__VA_ARGS__) -#define ti_lib_timer_load_get(...) TimerLoadGet(__VA_ARGS__) -#define ti_lib_timer_value_get(...) TimerValueGet(__VA_ARGS__) -#define ti_lib_timer_match_set(...) TimerMatchSet(__VA_ARGS__) -#define ti_lib_timer_match_get(...) TimerMatchGet(__VA_ARGS__) -#define ti_lib_timer_int_register(...) TimerIntRegister(__VA_ARGS__) -#define ti_lib_timer_int_unregister(...) TimerIntUnregister(__VA_ARGS__) -#define ti_lib_timer_int_enable(...) TimerIntEnable(__VA_ARGS__) -#define ti_lib_timer_int_disable(...) TimerIntDisable(__VA_ARGS__) -#define ti_lib_timer_int_status(...) TimerIntStatus(__VA_ARGS__) -#define ti_lib_timer_int_clear(...) TimerIntClear(__VA_ARGS__) -#define ti_lib_timer_synchronize(...) TimerSynchronize(__VA_ARGS__) -#define ti_lib_timer_ccp_combine_enable(...) TimerCcpCombineEnable(__VA_ARGS__) -#define ti_lib_timer_ccp_combine_disable(...) TimerCcpCombineDisable(__VA_ARGS__) -#define ti_lib_timer_match_update_mode(...) TimerMatchUpdateMode(__VA_ARGS__) -#define ti_lib_timer_interval_load_mode(...) TimerIntervalLoadMode(__VA_ARGS__) -/*---------------------------------------------------------------------------*/ -/* trng.h */ -#include DeviceFamily_constructPath(driverlib/trng.h) - -#define ti_lib_trng_configure(...) TRNGConfigure(__VA_ARGS__) -#define ti_lib_trng_enable(...) TRNGEnable(__VA_ARGS__) -#define ti_lib_trng_disable(...) TRNGDisable(__VA_ARGS__) -#define ti_lib_trng_number_get(...) TRNGNumberGet(__VA_ARGS__) -#define ti_lib_trng_status_get(...) TRNGStatusGet(__VA_ARGS__) -#define ti_lib_trng_reset(...) TRNGReset(__VA_ARGS__) -#define ti_lib_trng_int_enable(...) TRNGIntEnable(__VA_ARGS__) -#define ti_lib_trng_int_disable(...) TRNGIntDisable(__VA_ARGS__) -#define ti_lib_trng_int_status(...) TRNGIntStatus(__VA_ARGS__) -#define ti_lib_trng_int_clear(...) TRNGIntClear(__VA_ARGS__) -#define ti_lib_trng_int_register(...) TRNGIntRegister(__VA_ARGS__) -#define ti_lib_trng_int_unregister(...) TRNGIntUnregister(__VA_ARGS__) -/*---------------------------------------------------------------------------*/ -/* uart.h */ -#include DeviceFamily_constructPath(driverlib/uart.h) - -#define ti_lib_uart_parity_mode_set(...) UARTParityModeSet(__VA_ARGS__) -#define ti_lib_uart_parity_mode_get(...) UARTParityModeGet(__VA_ARGS__) -#define ti_lib_uart_fifo_level_set(...) UARTFIFOLevelSet(__VA_ARGS__) -#define ti_lib_uart_fifo_level_get(...) UARTFIFOLevelGet(__VA_ARGS__) -#define ti_lib_uart_config_set_exp_clk(...) UARTConfigSetExpClk(__VA_ARGS__) -#define ti_lib_uart_config_get_exp_clk(...) UARTConfigGetExpClk(__VA_ARGS__) -#define ti_lib_uart_enable(...) UARTEnable(__VA_ARGS__) -#define ti_lib_uart_disable(...) UARTDisable(__VA_ARGS__) -#define ti_lib_uart_fifo_enable(...) UARTFIFOEnable(__VA_ARGS__) -#define ti_lib_uart_fifo_disable(...) UARTFIFODisable(__VA_ARGS__) -#define ti_lib_uart_chars_avail(...) UARTCharsAvail(__VA_ARGS__) -#define ti_lib_uart_space_avail(...) UARTSpaceAvail(__VA_ARGS__) -#define ti_lib_uart_char_get_non_blocking(...) UARTCharGetNonBlocking(__VA_ARGS__) -#define ti_lib_uart_char_get(...) UARTCharGet(__VA_ARGS__) -#define ti_lib_uart_char_put_non_blocking(...) UARTCharPutNonBlocking(__VA_ARGS__) -#define ti_lib_uart_char_put(...) UARTCharPut(__VA_ARGS__) -#define ti_lib_uart_break_ctl(...) UARTBreakCtl(__VA_ARGS__) -#define ti_lib_uart_busy(...) UARTBusy(__VA_ARGS__) -#define ti_lib_uart_int_register(...) UARTIntRegister(__VA_ARGS__) -#define ti_lib_uart_int_unregister(...) UARTIntUnregister(__VA_ARGS__) -#define ti_lib_uart_int_enable(...) UARTIntEnable(__VA_ARGS__) -#define ti_lib_uart_int_disable(...) UARTIntDisable(__VA_ARGS__) -#define ti_lib_uart_int_status(...) UARTIntStatus(__VA_ARGS__) -#define ti_lib_uart_int_clear(...) UARTIntClear(__VA_ARGS__) -#define ti_lib_uart_dma_enable(...) UARTDMAEnable(__VA_ARGS__) -#define ti_lib_uart_dma_disable(...) UARTDMADisable(__VA_ARGS__) -#define ti_lib_uart_rx_error_get(...) UARTRxErrorGet(__VA_ARGS__) -#define ti_lib_uart_rx_error_clear(...) UARTRxErrorClear(__VA_ARGS__) -#define ti_lib_uart_hw_flow_control_en(...) UARTHwFlowControlEnable(__VA_ARGS__) -#define ti_lib_uart_hw_flow_control_dis(...) UARTHwFlowControlDisable(__VA_ARGS__) -/*---------------------------------------------------------------------------*/ -/* vims.h */ -#include DeviceFamily_constructPath(driverlib/vims.h) - -#define ti_lib_vims_configure(...) VIMSConfigure(__VA_ARGS__) -#define ti_lib_vims_mode_set(...) VIMSModeSet(__VA_ARGS__) -#define ti_lib_vims_mode_get(...) VIMSModeGet(__VA_ARGS__) -/*---------------------------------------------------------------------------*/ -/* watchdog.h */ -#include DeviceFamily_constructPath(driverlib/watchdog.h) - -#define ti_lib_watchdog_running(...) WatchdogRunning(__VA_ARGS__) -#define ti_lib_watchdog_enable(...) WatchdogEnable(__VA_ARGS__) -#define ti_lib_watchdog_reset_enable(...) WatchdogResetEnable(__VA_ARGS__) -#define ti_lib_watchdog_reset_disable(...) WatchdogResetDisable(__VA_ARGS__) -#define ti_lib_watchdog_lock(...) WatchdogLock(__VA_ARGS__) -#define ti_lib_watchdog_unlock(...) WatchdogUnlock(__VA_ARGS__) -#define ti_lib_watchdog_lock_state(...) WatchdogLockState(__VA_ARGS__) -#define ti_lib_watchdog_reload_set(...) WatchdogReloadSet(__VA_ARGS__) -#define ti_lib_watchdog_reload_get(...) WatchdogReloadGet(__VA_ARGS__) -#define ti_lib_watchdog_value_get(...) WatchdogValueGet(__VA_ARGS__) -#define ti_lib_watchdog_int_register(...) WatchdogIntRegister(__VA_ARGS__) -#define ti_lib_watchdog_int_unregister(...) WatchdogIntUnregister(__VA_ARGS__) -#define ti_lib_watchdog_int_enable(...) WatchdogIntEnable(__VA_ARGS__) -#define ti_lib_watchdog_int_status(...) WatchdogIntStatus(__VA_ARGS__) -#define ti_lib_watchdog_int_clear(...) WatchdogIntClear(__VA_ARGS__) -#define ti_lib_watchdog_int_type_set(...) WatchdogIntTypeSet(__VA_ARGS__) -#define ti_lib_watchdog_stall_enable(...) WatchdogStallEnable(__VA_ARGS__) -#define ti_lib_watchdog_stall_disable(...) WatchdogStallDisable(__VA_ARGS__) -/*---------------------------------------------------------------------------*/ -#endif /* TI_LIB_H_ */ -/*---------------------------------------------------------------------------*/ -/** - * @} - * @} - */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/trng-arch.c b/arch/cpu/cc13xx-cc26xx/dev/trng-arch.c new file mode 100644 index 000000000..cb32232e0 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/dev/trng-arch.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/** + * \addtogroup cc13xx-cc26xx-trng + * @{ + * + * \file + * Implementation of True Random Number Generator for CC13xx/CC26xx. + * \author + * Edvard Pettersen + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" + +#include "trng-arch.h" +/*---------------------------------------------------------------------------*/ +#include +#include +/*---------------------------------------------------------------------------*/ +/* + * Very dirty workaround because of the pre-compiled TI drivers library for + * CC13xx/CC26x0 is missing the CryptoKey object file. + */ +#include +#if (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0) +# include +#endif +/*---------------------------------------------------------------------------*/ +#include +#include +/*---------------------------------------------------------------------------*/ +void +trng_init(void) +{ + TRNG_init(); +} +/*---------------------------------------------------------------------------*/ +bool +trng_rand(uint8_t *entropy_buf, size_t entropy_len, uint32_t timeout_us) +{ + TRNG_Params trng_params; + TRNG_Handle trng_handle; + CryptoKey entropy_key; + int_fast16_t result; + + TRNG_Params_init(&trng_params); + trng_params.returnBehavior = TRNG_RETURN_BEHAVIOR_BLOCKING; + if(timeout_us != TRNG_WAIT_FOREVER) { + trng_params.timeout = timeout_us; + } + + trng_handle = TRNG_open(0, &trng_params); + if (!trng_handle) { + return false; + } + + CryptoKeyPlaintext_initBlankKey(&entropy_key, entropy_buf, entropy_len); + + result = TRNG_generateEntropy(trng_handle, &entropy_key); + + TRNG_close(trng_handle); + + return (result == TRNG_STATUS_SUCCESS); +} +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/trng-arch.h b/arch/cpu/cc13xx-cc26xx/dev/trng-arch.h new file mode 100644 index 000000000..1b6c7f3a4 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/dev/trng-arch.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/** + * \addtogroup cc13xx-cc26xx-cpu + * @{ + * + * \defgroup cc13xx-cc26xx-trng True Random Number Generator for CC13xx/CC26xx. + * @{ + * + * \file + * Header file of True Random Number Generator for CC13xx/CC26xx. + * \author + * Edvard Pettersen + */ +/*---------------------------------------------------------------------------*/ +#ifndef TRNG_ARCH_H_ +#define TRNG_ARCH_H_ +/*---------------------------------------------------------------------------*/ +#include +/*---------------------------------------------------------------------------*/ +#include +#include +/*---------------------------------------------------------------------------*/ +#define TRNG_WAIT_FOREVER (~(uint32_t)0) +/*---------------------------------------------------------------------------*/ +/** + * \breif Initialize the TRNG module. + */ +void trng_init(void); + +/** + * \brief Generates a stream of true random numbers. This is + * a blocking function call with a specified timeout. + * \param entropy_buf Buffer to store a stream of entropy. + * \param entropy_len Length of the entropy buffer. + * \param timeout_us How long to wait until timing out the operation. A + * timeout of TRNG_WAIT_FOREVER blocks forever. + * \return true if successful; else, false. + */ +bool trng_rand(uint8_t *entropy_buf, size_t entropy_len, uint32_t timeout_us); +/*---------------------------------------------------------------------------*/ +#endif /* TRNG_ARCH_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ble-addr.c b/arch/cpu/cc13xx-cc26xx/rf/ble-addr.c similarity index 99% rename from arch/cpu/cc13xx-cc26xx/dev/rf-ble-addr.c rename to arch/cpu/cc13xx-cc26xx/rf/ble-addr.c index a76261c66..db01506ad 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-ble-addr.c +++ b/arch/cpu/cc13xx-cc26xx/rf/ble-addr.c @@ -40,7 +40,7 @@ #include "dev/ble-hal.h" #include "net/linkaddr.h" -#include "rf-ble-addr.h" +#include "rf/ble-addr.h" /*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(inc/hw_memmap.h) diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ble-addr.h b/arch/cpu/cc13xx-cc26xx/rf/ble-addr.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/dev/rf-ble-addr.h rename to arch/cpu/cc13xx-cc26xx/rf/ble-addr.h diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.c b/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c similarity index 99% rename from arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.c rename to arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c index 7aa38198a..ea56af9e5 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.c +++ b/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c @@ -52,9 +52,9 @@ #include /*---------------------------------------------------------------------------*/ -#include "rf-ble-addr.h" -#include "rf-ble-beacond.h" -#include "rf-core.h" +#include "rf/rf.h" +#include "rf/ble-addr.h" +#include "rf/ble-beacond.h" #include "rf-settings.h" /*---------------------------------------------------------------------------*/ #include diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.h b/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/dev/rf-ble-beacond.h rename to arch/cpu/cc13xx-cc26xx/rf/ble-beacond.h diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-data-queue.c b/arch/cpu/cc13xx-cc26xx/rf/data-queue.c similarity index 99% rename from arch/cpu/cc13xx-cc26xx/dev/rf-data-queue.c rename to arch/cpu/cc13xx-cc26xx/rf/data-queue.c index 32bab1242..96f1be9c1 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-data-queue.c +++ b/arch/cpu/cc13xx-cc26xx/rf/data-queue.c @@ -39,7 +39,7 @@ #include "contiki.h" #include "sys/cc.h" -#include "rf-data-queue.h" +#include "rf/data-queue.h" /*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-data-queue.h b/arch/cpu/cc13xx-cc26xx/rf/data-queue.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/dev/rf-data-queue.h rename to arch/cpu/cc13xx-cc26xx/rf/data-queue.h diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-15-4g.h b/arch/cpu/cc13xx-cc26xx/rf/dot-15-4g.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/dev/rf-15-4g.h rename to arch/cpu/cc13xx-cc26xx/rf/dot-15-4g.h diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-addr.c b/arch/cpu/cc13xx-cc26xx/rf/ieee-addr.c similarity index 99% rename from arch/cpu/cc13xx-cc26xx/dev/rf-ieee-addr.c rename to arch/cpu/cc13xx-cc26xx/rf/ieee-addr.c index eddee8947..25aacc63b 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-addr.c +++ b/arch/cpu/cc13xx-cc26xx/rf/ieee-addr.c @@ -40,7 +40,7 @@ #include "contiki.h" #include "net/linkaddr.h" -#include "rf-ieee-addr.h" +#include "rf/ieee-addr.h" /*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(inc/hw_memmap.h) diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-addr.h b/arch/cpu/cc13xx-cc26xx/rf/ieee-addr.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/dev/rf-ieee-addr.h rename to arch/cpu/cc13xx-cc26xx/rf/ieee-addr.h diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c b/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c similarity index 99% rename from arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c rename to arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c index ce7d8b42c..4ab38acb8 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c +++ b/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c @@ -66,10 +66,10 @@ #include /*---------------------------------------------------------------------------*/ /* SimpleLink Platform RF dev */ -#include "rf-data-queue.h" -#include "rf-core.h" -#include "rf-sched.h" -#include "rf-15-4g.h" +#include "rf/rf.h" +#include "rf/data-queue.h" +#include "rf/dot-15-4g.h" +#include "rf/sched.h" #include "ieee-settings.h" /*---------------------------------------------------------------------------*/ #include diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c b/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c similarity index 100% rename from arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c rename to arch/cpu/cc13xx-cc26xx/rf/prop-mode.c diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-core.h b/arch/cpu/cc13xx-cc26xx/rf/rf.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/dev/rf-core.h rename to arch/cpu/cc13xx-cc26xx/rf/rf.h diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-sched.c b/arch/cpu/cc13xx-cc26xx/rf/sched.c similarity index 99% rename from arch/cpu/cc13xx-cc26xx/dev/rf-sched.c rename to arch/cpu/cc13xx-cc26xx/rf/sched.c index a258dc54b..476c9d56c 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-sched.c +++ b/arch/cpu/cc13xx-cc26xx/rf/sched.c @@ -52,9 +52,9 @@ #include /*---------------------------------------------------------------------------*/ -#include "rf-core.h" -#include "rf-sched.h" -#include "rf-data-queue.h" +#include "rf/rf.h" +#include "rf/sched.h" +#include "rf/data-queue.h" #include "rf-settings.h" /*---------------------------------------------------------------------------*/ #include diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-sched.h b/arch/cpu/cc13xx-cc26xx/rf/sched.h similarity index 99% rename from arch/cpu/cc13xx-cc26xx/dev/rf-sched.h rename to arch/cpu/cc13xx-cc26xx/rf/sched.h index 32f6f0a6b..6ba452702 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-sched.h +++ b/arch/cpu/cc13xx-cc26xx/rf/sched.h @@ -40,8 +40,6 @@ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "sys/process.h" - -#include "rf-ble-beacond.h" /*---------------------------------------------------------------------------*/ #include /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index b9e315e80..e691b0768 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -46,6 +46,7 @@ ifdef NODEID endif CONTIKI_TARGET_SOURCEFILES += platform.c +CONTIKI_TARGET_SOURCEFILES += batmon-sensor.c CONTIKI_TARGET_SOURCEFILES += $(BOARD_SOURCEFILES) CONTIKI_SOURCEFILES += $(CONTIKI_TARGET_SOURCEFILES) diff --git a/arch/cpu/cc13xx-cc26xx/dev/batmon-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/batmon-sensor.c similarity index 88% rename from arch/cpu/cc13xx-cc26xx/dev/batmon-sensor.c rename to arch/platform/simplelink/cc13xx-cc26xx/batmon-sensor.c index 423a9fbcc..557c9d018 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/batmon-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/batmon-sensor.c @@ -38,10 +38,12 @@ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "lib/sensors.h" + #include "batmon-sensor.h" - -#include "ti-lib.h" - +/*---------------------------------------------------------------------------*/ +#include +#include DeviceFamily_constructPath(driverlib/aon_batmon.h) +/*---------------------------------------------------------------------------*/ #include #include /*---------------------------------------------------------------------------*/ @@ -71,15 +73,13 @@ value(int type) return 0; } - if(type == BATMON_SENSOR_TYPE_TEMP) { - return (int)ti_lib_aon_batmon_temperature_get_deg_c(); - } else if(type == BATMON_SENSOR_TYPE_VOLT) { - return (int)ti_lib_aon_batmon_battery_voltage_get(); - } else { + switch(type) { + case BATMON_SENSOR_TYPE_TEMP: return (int)AONBatMonTemperatureGetDegC(); + case BATMON_SENSOR_TYPE_VOLT: return (int)AONBatMonBatteryVoltageGet(); + default: PRINTF("Invalid type\n"); + return 0; } - - return 0; } /*---------------------------------------------------------------------------*/ /** @@ -97,15 +97,15 @@ configure(int type, int enable) { switch(type) { case SENSORS_HW_INIT: - ti_lib_aon_batmon_enable(); + AONBatMonEnable(); enabled = SENSOR_STATUS_ENABLED; break; case SENSORS_ACTIVE: if(enable) { - ti_lib_aon_batmon_enable(); + AONBatMonEnable(); enabled = SENSOR_STATUS_ENABLED; } else { - ti_lib_aon_batmon_disable(); + AONBatMonDisable(); enabled = SENSOR_STATUS_DISABLED; } break; diff --git a/arch/cpu/cc13xx-cc26xx/dev/batmon-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/batmon-sensor.h similarity index 100% rename from arch/cpu/cc13xx-cc26xx/dev/batmon-sensor.h rename to arch/platform/simplelink/cc13xx-cc26xx/batmon-sensor.h diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.c index df5454f5d..b9f3adfb1 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.c @@ -779,6 +779,29 @@ const uint_least8_t SPI_count = CC1310_LAUNCHXL_SPICOUNT; #endif /* TI_SPI_CONF_ENABLE */ + +/* + * =============================== TRNG =============================== + */ +#include +#include + +TRNGCC26X0_Object trngCC26X0Object[CC1310_LAUNCHXL_TRNGCOUNT]; + +const TRNGCC26X0_HWAttrs trngCC26X0HWAttrs[CC1310_LAUNCHXL_TRNGCOUNT] = { + { + .swiPriority = 0, + .intPriority = ~0, + } +}; + +const TRNG_Config TRNG_config[] = { + { &trngCC26X0Object[0], &trngCC26X0HWAttrs[0] }, +}; + +const uint8_t TRNG_count = CC1310_LAUNCHXL_TRNGCOUNT; + + /* * =============================== UART =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h index 51ff78942..12b3bb084 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h @@ -333,6 +333,16 @@ typedef enum CC1310_LAUNCHXL_SPIName { CC1310_LAUNCHXL_SPICOUNT } CC1310_LAUNCHXL_SPIName; +/*! + * @def CC1310_LAUNCHXL_TRNGName + * @brief Enum of TRNGs + */ +typedef enum CC1310_LAUNCHXL_TRNGName { + CC1310_LAUNCHXL_TRNG0 = 0, + + CC1310_LAUNCHXL_TRNGCOUNT +} CC1310_LAUNCHXL_TRNGName; + /*! * @def CC1310_LAUNCHXL_UARTName * @brief Enum of UARTs diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.c index 20372347e..24db2296f 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.c @@ -900,6 +900,29 @@ const uint_least8_t SPI_count = CC1312R1_LAUNCHXL_SPICOUNT; #endif /* TI_SPI_CONF_ENABLE */ + +/* + * =============================== TRNG =============================== + */ +#include +#include + +TRNGCC26X2_Object trngCC26X2Object[CC1312R1_LAUNCHXL_TRNGCOUNT]; + +const TRNGCC26X2_HWAttrs trngCC26X2HWAttrs[CC1312R1_LAUNCHXL_TRNGCOUNT] = { + { + .swiPriority = 0, + .intPriority = ~0, + } +}; + +const TRNG_Config TRNG_config[] = { + { &trngCC26X2Object[0], &trngCC26X2HWAttrs[0] }, +}; + +const uint8_t TRNG_count = CC1312R1_LAUNCHXL_TRNGCOUNT; + + /* * =============================== UART =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h index c70e28755..d54a18e89 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h @@ -392,6 +392,16 @@ typedef enum CC1312R1_LAUNCHXL_SPIName { CC1312R1_LAUNCHXL_SPICOUNT } CC1312R1_LAUNCHXL_SPIName; +/*! + * @def CC1312R1_LAUNCHXL_TRNGName + * @brief Enum of TRNGs + */ +typedef enum CC1312R1_LAUNCHXL_TRNGName { + CC1312R1_LAUNCHXL_TRNG0 = 0, + + CC1312R1_LAUNCHXL_TRNGCOUNT +} CC1312R1_LAUNCHXL_TRNGName; + /*! * @def CC1312R1_LAUNCHXL_UARTName * @brief Enum of UARTs diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c index 1fbff5e6d..61efd4e92 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c @@ -792,6 +792,29 @@ const uint_least8_t SPI_count = CC1350_LAUNCHXL_SPICOUNT; #endif /* TI_SPI_CONF_ENABLE */ + +/* + * =============================== TRNG =============================== + */ +#include +#include + +TRNGCC26X0_Object trngCC26X0Object[CC1350_LAUNCHXL_TRNGCOUNT]; + +const TRNGCC26X0_HWAttrs trngCC26X0HWAttrs[CC1350_LAUNCHXL_TRNGCOUNT] = { + { + .swiPriority = 0, + .intPriority = ~0, + } +}; + +const TRNG_Config TRNG_config[] = { + { &trngCC26X0Object[0], &trngCC26X0HWAttrs[0] }, +}; + +const uint8_t TRNG_count = CC1350_LAUNCHXL_TRNGCOUNT; + + /* * =============================== UART =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h index 88ffb333b..a54fa9365 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h @@ -336,6 +336,16 @@ typedef enum CC1350_LAUNCHXL_SPIName { CC1350_LAUNCHXL_SPICOUNT } CC1350_LAUNCHXL_SPIName; +/*! + * @def CC1350_LAUNCHXL_TRNGName + * @brief Enum of TRNGs + */ +typedef enum CC1350_LAUNCHXL_TRNGName { + CC1350_LAUNCHXL_TRNG0 = 0, + + CC1350_LAUNCHXL_TRNGCOUNT +} CC1350_LAUNCHXL_TRNGName; + /*! * @def CC1350_LAUNCHXL_UARTName * @brief Enum of UARTs diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.c index 973f712ac..ea178974b 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.c @@ -884,6 +884,29 @@ const uint_least8_t SPI_count = CC1352P_2_LAUNCHXL_SPICOUNT; #endif /* TI_SPI_CONF_ENABLE */ + +/* + * =============================== TRNG =============================== + */ +#include +#include + +TRNGCC26X2_Object trngCC26X2Object[CC1352P_2_LAUNCHXL_TRNGCOUNT]; + +const TRNGCC26X2_HWAttrs trngCC26X2HWAttrs[CC1352P_2_LAUNCHXL_TRNGCOUNT] = { + { + .swiPriority = 0, + .intPriority = ~0, + } +}; + +const TRNG_Config TRNG_config[] = { + { &trngCC26X2Object[0], &trngCC26X2HWAttrs[0] }, +}; + +const uint8_t TRNG_count = CC1352P_2_LAUNCHXL_TRNGCOUNT; + + /* * =============================== UART =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h index f71a15aa6..7c83f2935 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h @@ -400,6 +400,16 @@ typedef enum CC1352P_2_LAUNCHXL_SPIName { CC1352P_2_LAUNCHXL_SPICOUNT } CC1352P_2_LAUNCHXL_SPIName; +/*! + * @def CC1352p_2_LAUNCHXL_TRNGName + * @brief Enum of TRNGs + */ +typedef enum CC1352p_2_LAUNCHXL_TRNGName { + CC1352p_2_LAUNCHXL_TRNG0 = 0, + + CC1352p_2_LAUNCHXL_TRNGCOUNT +} CC1352p_2_LAUNCHXL_TRNGName; + /*! * @def CC1352P_2_LAUNCHXL_UARTName * @brief Enum of UARTs diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.c index 007bcfeab..9a2ae3505 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.c @@ -884,6 +884,29 @@ const uint_least8_t SPI_count = CC1352P_4_LAUNCHXL_SPICOUNT; #endif /* TI_SPI_CONF_ENABLE */ + +/* + * =============================== TRNG =============================== + */ +#include +#include + +TRNGCC26X2_Object trngCC26X2Object[CC1352P_4_LAUNCHXL_TRNGCOUNT]; + +const TRNGCC26X2_HWAttrs trngCC26X2HWAttrs[CC1352P_4_LAUNCHXL_TRNGCOUNT] = { + { + .swiPriority = 0, + .intPriority = ~0, + } +}; + +const TRNG_Config TRNG_config[] = { + { &trngCC26X2Object[0], &trngCC26X2HWAttrs[0] }, +}; + +const uint8_t TRNG_count = CC1352P_4_LAUNCHXL_TRNGCOUNT; + + /* * =============================== UART =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.h index bee9657ea..a125dcd6a 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.h @@ -400,6 +400,16 @@ typedef enum CC1352P_4_LAUNCHXL_SPIName { CC1352P_4_LAUNCHXL_SPICOUNT } CC1352P_4_LAUNCHXL_SPIName; +/*! + * @def CC1352P_4_LAUNCHXL_TRNGName + * @brief Enum of TRNGs + */ +typedef enum CC1352P_4_LAUNCHXL_TRNGName { + CC1352P_4_LAUNCHXL_TRNG0 = 0, + + CC1352P_4_LAUNCHXL_TRNGCOUNT +} CC1352P_4_LAUNCHXL_TRNGName; + /*! * @def CC1352P_4_LAUNCHXL_UARTName * @brief Enum of UARTs diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.c index 8ec044737..4a6e7b5e8 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.c @@ -884,6 +884,29 @@ const uint_least8_t SPI_count = CC1352P1_LAUNCHXL_SPICOUNT; #endif /* TI_SPI_CONF_ENABLE */ + +/* + * =============================== TRNG =============================== + */ +#include +#include + +TRNGCC26X2_Object trngCC26X2Object[CC1352P1_LAUNCHXL_TRNGCOUNT]; + +const TRNGCC26X2_HWAttrs trngCC26X2HWAttrs[CC1352P1_LAUNCHXL_TRNGCOUNT] = { + { + .swiPriority = 0, + .intPriority = ~0, + } +}; + +const TRNG_Config TRNG_config[] = { + { &trngCC26X2Object[0], &trngCC26X2HWAttrs[0] }, +}; + +const uint8_t TRNG_count = CC1352P1_LAUNCHXL_TRNGCOUNT; + + /* * =============================== UART =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h index af3478bac..dd91ea72d 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h @@ -404,6 +404,16 @@ typedef enum CC1352P1_LAUNCHXL_SPIName { CC1352P1_LAUNCHXL_SPICOUNT } CC1352P1_LAUNCHXL_SPIName; +/*! + * @def CC1352P1_LAUNCHXL_TRNGName + * @brief Enum of TRNGs + */ +typedef enum CC1352P1_LAUNCHXL_TRNGName { + CC1352P1_LAUNCHXL_TRNG0 = 0, + + CC1352P1_LAUNCHXL_TRNGCOUNT +} CC1352P1_LAUNCHXL_TRNGName; + /*! * @def CC1352P1_LAUNCHXL_UARTName * @brief Enum of UARTs diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c index 5ed8d3167..e84f74cbe 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c @@ -903,6 +903,29 @@ const uint_least8_t SPI_count = CC1352R1_LAUNCHXL_SPICOUNT; #endif /* TI_SPI_CONF_ENABLE */ + +/* + * =============================== TRNG =============================== + */ +#include +#include + +TRNGCC26X2_Object trngCC26X2Object[CC1352R1_LAUNCHXL_TRNGCOUNT]; + +const TRNGCC26X2_HWAttrs trngCC26X2HWAttrs[CC1352R1_LAUNCHXL_TRNGCOUNT] = { + { + .swiPriority = 0, + .intPriority = ~0, + } +}; + +const TRNG_Config TRNG_config[] = { + { &trngCC26X2Object[0], &trngCC26X2HWAttrs[0] }, +}; + +const uint8_t TRNG_count = CC1352R1_LAUNCHXL_TRNGCOUNT; + + /* * =============================== UART =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h index 3dcd63af5..3a4949f87 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h @@ -396,6 +396,16 @@ typedef enum CC1352R1_LAUNCHXL_SPIName { CC1352R1_LAUNCHXL_SPICOUNT } CC1352R1_LAUNCHXL_SPIName; +/*! + * @def CC1352R1_LAUNCHXL_TRNGName + * @brief Enum of TRNGs + */ +typedef enum CC1352R1_LAUNCHXL_TRNGName { + CC1352R1_LAUNCHXL_TRNG0 = 0, + + CC1352R1_LAUNCHXL_TRNGCOUNT +} CC1352R1_LAUNCHXL_TRNGName; + /*! * @def CC1352R1_LAUNCHXL_UARTName * @brief Enum of UARTs diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.c index b6c799ad2..1d63a60a3 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.c @@ -778,6 +778,29 @@ const uint_least8_t SPI_count = CC2650_LAUNCHXL_SPICOUNT; #endif /* TI_SPI_CONF_ENABLE */ + +/* + * =============================== TRNG =============================== + */ +#include +#include + +TRNGCC26X0_Object trngCC26X0Object[CC2650_LAUNCHXL_TRNGCOUNT]; + +const TRNGCC26X0_HWAttrs trngCC26X0HWAttrs[CC2650_LAUNCHXL_TRNGCOUNT] = { + { + .swiPriority = 0, + .intPriority = ~0, + } +}; + +const TRNG_Config TRNG_config[] = { + { &trngCC26X0Object[0], &trngCC26X0HWAttrs[0] }, +}; + +const uint8_t TRNG_count = CC2650_LAUNCHXL_TRNGCOUNT; + + /* * =============================== UART =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h index 89244b0f6..9f0fd81f9 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h @@ -333,6 +333,16 @@ typedef enum CC2650_LAUNCHXL_SPIName { CC2650_LAUNCHXL_SPICOUNT } CC2650_LAUNCHXL_SPIName; +/*! + * @def CC2650_LAUNCHXL_TRNGName + * @brief Enum of TRNGs + */ +typedef enum CC2650_LAUNCHXL_TRNGName { + CC2650_LAUNCHXL_TRNG0 = 0, + + CC2650_LAUNCHXL_TRNGCOUNT +} CC2650_LAUNCHXL_TRNGName; + /*! * @def CC2650_LAUNCHXL_UARTName * @brief Enum of UARTs diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c index b7879f5a8..47a6ef8da 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c @@ -901,6 +901,29 @@ const uint_least8_t SPI_count = CC26X2R1_LAUNCHXL_SPICOUNT; #endif /* TI_SPI_CONF_ENABLE */ + +/* + * =============================== TRNG =============================== + */ +#include +#include + +TRNGCC26X2_Object trngCC26X2Object[CC26X2R1_LAUNCHXL_TRNGCOUNT]; + +const TRNGCC26X2_HWAttrs trngCC26X2HWAttrs[CC26X2R1_LAUNCHXL_TRNGCOUNT] = { + { + .swiPriority = 0, + .intPriority = ~0, + } +}; + +const TRNG_Config TRNG_config[] = { + { &trngCC26X2Object[0], &trngCC26X2HWAttrs[0] }, +}; + +const uint8_t TRNG_count = CC26X2R1_LAUNCHXL_TRNGCOUNT; + + /* * =============================== UART =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h index 155fff3f9..998a8ffa6 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h @@ -398,6 +398,16 @@ typedef enum CC26X2R1_LAUNCHXL_SPIName { CC26X2R1_LAUNCHXL_SPICOUNT } CC26X2R1_LAUNCHXL_SPIName; +/*! + * @def CC26X2R1_LAUNCHXL_TRNGName + * @brief Enum of TRNGs + */ +typedef enum CC26X2R1_LAUNCHXL_TRNGName { + CC26X2R1_LAUNCHXL_TRNG0 = 0, + + CC26X2R1_LAUNCHXL_TRNGCOUNT +} CC26X2R1_LAUNCHXL_TRNGName; + /*! * @def CC26X2R1_LAUNCHXL_UARTName * @brief Enum of UARTs diff --git a/arch/platform/simplelink/cc13xx-cc26xx/platform.c b/arch/platform/simplelink/cc13xx-cc26xx/platform.c index 64317dc02..a591fefa0 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/platform.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/platform.c @@ -38,7 +38,6 @@ * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ -/* Contiki API */ #include "contiki.h" #include "contiki-net.h" #include "sys/clock.h" @@ -53,7 +52,6 @@ #include "lib/random.h" #include "lib/sensors.h" /*---------------------------------------------------------------------------*/ -/* Simplelink SDK includes */ #include #include @@ -71,14 +69,13 @@ #include #include /*---------------------------------------------------------------------------*/ -/* Arch driver implementations */ -#include "button-sensor.h" #include "board-peripherals.h" #include "uart0-arch.h" +#include "trng-arch.h" /*---------------------------------------------------------------------------*/ -#include "rf-core.h" -#include "rf-ieee-addr.h" -#include "rf-ble-beacond.h" +#include "rf/rf.h" +#include "rf/ble-beacond.h" +#include "rf/ieee-addr.h" /*---------------------------------------------------------------------------*/ #include #include @@ -200,7 +197,15 @@ platform_init_stage_two(void) uart0_set_callback(serial_line_input_byte); #endif - random_init(0x1234); + /* Use TRNG to seed PRNG. If TRNG fails, use a hard-coded seed. */ + unsigned short trn = 0; + trng_init(); + bool result = trng_rand((uint8_t*)&trn, sizeof(trn), TRNG_WAIT_FOREVER); + if (!result) { + /* Default to some hard-coded seed. */ + trn = 0x1234; + } + random_init(trn); /* Populate linkaddr_node_addr */ ieee_addr_cpy_to(linkaddr_node_addr.u8, LINKADDR_SIZE); diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.c index f1d8bf53d..c5a7558c7 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.c @@ -611,6 +611,29 @@ const uint_least8_t SPI_count = CC1350STK_SPICOUNT; #endif /* TI_SPI_CONF_ENABLE */ + +/* + * =============================== TRNG =============================== + */ +#include +#include + +TRNGCC26X0_Object trngCC26X0Object[CC1350STK_TRNGCOUNT]; + +const TRNGCC26X0_HWAttrs trngCC26X0HWAttrs[CC1350STK_TRNGCOUNT] = { + { + .swiPriority = 0, + .intPriority = ~0, + } +}; + +const TRNG_Config TRNG_config[] = { + { &trngCC26X0Object[0], &trngCC26X0HWAttrs[0] }, +}; + +const uint8_t TRNG_count = CC1350STK_TRNGCOUNT; + + /* * =============================== UART =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.h index ea857a185..2a6f4bde9 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.h @@ -299,6 +299,16 @@ typedef enum CC1350STK_SPIName { CC1350STK_SPICOUNT } CC1350STK_SPIName; +/*! + * @def CC1350STK_TRNGName + * @brief Enum of TRNGs + */ +typedef enum CC1350STK_TRNGName { + CC1350STK_TRNG0 = 0, + + CC1350STK_TRNGCOUNT +} CC1350STK_TRNGName; + /*! * @def CC1350STK_UARTName * @brief Enum of UARTs diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.c index d070170c9..b267075e5 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.c @@ -612,6 +612,29 @@ const uint_least8_t SPI_count = CC2650STK_SPICOUNT; #endif /* TI_SPI_CONF_ENABLE */ + +/* + * =============================== TRNG =============================== + */ +#include +#include + +TRNGCC26X0_Object trngCC26X0Object[CC2650STK_TRNGCOUNT]; + +const TRNGCC26X0_HWAttrs trngCC26X0HWAttrs[CC2650STK_TRNGCOUNT] = { + { + .swiPriority = 0, + .intPriority = ~0, + } +}; + +const TRNG_Config TRNG_config[] = { + { &trngCC26X0Object[0], &trngCC26X0HWAttrs[0] }, +}; + +const uint8_t TRNG_count = CC2650STK_TRNGCOUNT; + + /* * =============================== UART =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h index 0264ae110..8ec745f45 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h @@ -300,6 +300,16 @@ typedef enum CC2650STK_SPIName { CC2650STK_SPICOUNT } CC2650STK_SPIName; +/*! + * @def CC2650STK_TRNGName + * @brief Enum of TRNGs + */ +typedef enum CC2650STK_TRNGName { + CC2650STK_TRNG0 = 0, + + CC2650STK_TRNGCOUNT +} CC2650STK_TRNGName; + /*! * @def CC2650STK_UARTName * @brief Enum of UARTs diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c index 3214b385a..8e05f6574 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c @@ -677,6 +677,29 @@ const uint_least8_t SPI_count = CC1350DK_7XD_SPICOUNT; #endif /* TI_SPI_CONF_ENABLE */ + +/* + * =============================== TRNG =============================== + */ +#include +#include + +TRNGCC26X0_Object trngCC26X0Object[CC1350DK_7XD_TRNGCOUNT]; + +const TRNGCC26X0_HWAttrs trngCC26X0HWAttrs[CC1350DK_7XD_TRNGCOUNT] = { + { + .swiPriority = 0, + .intPriority = ~0, + } +}; + +const TRNG_Config TRNG_config[] = { + { &trngCC26X0Object[0], &trngCC26X0HWAttrs[0] }, +}; + +const uint8_t TRNG_count = CC1350DK_7XD_TRNGCOUNT; + + /* * =============================== UART =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h index f90681dbf..72b19a036 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h @@ -338,6 +338,16 @@ typedef enum CC1350DK_7XD_SPIName { CC1350DK_7XD_SPICOUNT } CC1350DK_7XD_SPIName; +/*! + * @def CC1350DK_7XD_TRNGName + * @brief Enum of TRNGs + */ +typedef enum CC1350DK_7XD_TRNGName { + CC1350DK_7XD_TRNG0 = 0, + + CC1350DK_7XD_TRNGCOUNT +} CC1350DK_7XD_TRNGName; + /*! * @def CC1350DK_7XD_UARTName * @brief Enum of UARTs diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c index 52e27a7a7..431b0005c 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c @@ -678,6 +678,29 @@ const uint_least8_t SPI_count = CC2650DK_7ID_SPICOUNT; #endif /* TI_SPI_CONF_ENABLE */ + +/* + * =============================== TRNG =============================== + */ +#include +#include + +TRNGCC26X0_Object trngCC26X0Object[CC2650DK_7ID_TRNGCOUNT]; + +const TRNGCC26X0_HWAttrs trngCC26X0HWAttrs[CC2650DK_7ID_TRNGCOUNT] = { + { + .swiPriority = 0, + .intPriority = ~0, + } +}; + +const TRNG_Config TRNG_config[] = { + { &trngCC26X0Object[0], &trngCC26X0HWAttrs[0] }, +}; + +const uint8_t TRNG_count = CC2650DK_7ID_TRNGCOUNT; + + /* * =============================== UART =============================== */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h index bde1ff107..7901fbed1 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h @@ -323,6 +323,16 @@ typedef enum CC2650DK_7ID_SDName { CC2650DK_7ID_SDCOUNT } CC2650DK_7ID_SDName; +/*! + * @def CC2650DK_7ID_TRNGName + * @brief Enum of TRNGs + */ +typedef enum CC2650DK_7ID_TRNGName { + CC2650DK_7ID_TRNG0 = 0, + + CC2650DK_7ID_TRNGCOUNT +} CC2650DK_7ID_TRNGName; + /*! * @def CC2650DK_7ID_SPIName * @brief Enum of SPI names From 824296cbc0b07e1a9dbb718b44225ae5f532309f Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Fri, 20 Jul 2018 17:20:25 +0200 Subject: [PATCH 278/485] Removed external bias as default from RF settings, and doxygen alignment --- arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h | 14 +++ arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-def.h | 5 +- arch/cpu/cc13xx-cc26xx/dev/random.c | 17 ++- arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c | 117 +++++++++++------- arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.h | 56 +++++---- arch/cpu/cc13xx-cc26xx/dev/slip-arch.c | 36 +++--- arch/cpu/cc13xx-cc26xx/dev/trng-arch.c | 18 +-- arch/cpu/cc13xx-cc26xx/dev/trng-arch.h | 10 +- arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c | 82 ++++++------ arch/cpu/cc13xx-cc26xx/dev/uart0-arch.h | 48 ++++--- arch/cpu/cc13xx-cc26xx/dev/watchdog-arch.c | 63 ++++++---- .../rf-settings/cc13x0/ble-settings.c | 2 +- .../rf-settings/cc13x0/ieee-settings.c | 4 +- .../rf-settings/cc13x0/prop-settings.c | 2 +- .../rf-settings/cc13x2/ieee-settings.c | 4 +- .../rf-settings/cc13x2/prop-settings.c | 2 +- .../rf-settings/cc26x0/ieee-settings.c | 4 +- .../rf-settings/cc26x2/ieee-settings.c | 6 +- arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c | 6 +- arch/cpu/cc13xx-cc26xx/rf/prop-mode.c | 13 +- arch/cpu/cc13xx-cc26xx/rf/sched.c | 41 ++++-- .../simplelink/cc13xx-cc26xx/platform.c | 15 +-- 22 files changed, 334 insertions(+), 231 deletions(-) diff --git a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h index 45b10e17d..f169a088e 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h +++ b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h @@ -54,6 +54,20 @@ #define GPIO_HAL_CONF_ARCH_HDR_PATH "dev/gpio-hal-arch.h" /** @} */ /*---------------------------------------------------------------------------*/ +/** + * \name Watchdog Configuration. + * + * @{ + */ +#ifndef WATCHDOG_CONF_DISABLE +#define WATCHDOG_CONF_DISABLE 0 +#endif + +#ifndef WATCHDOG_CONF_TIMER_TOP +#define WATCHDOG_CONF_TIMER_TOP 0xFFFFF +#endif + /** @} */ +/*---------------------------------------------------------------------------*/ /** * \name RF configuration. * diff --git a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-def.h b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-def.h index 0f941b058..fc133948c 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-def.h +++ b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-def.h @@ -49,6 +49,7 @@ #endif /*---------------------------------------------------------------------------*/ #include +#include /*---------------------------------------------------------------------------*/ #define RTIMER_ARCH_SECOND 65536 /*---------------------------------------------------------------------------*/ @@ -115,9 +116,9 @@ /*---------------------------------------------------------------------------*/ /* Path to CMSIS header */ #if (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0) -# define CMSIS_CONF_HEADER_PATH "cc13x0-cc26x0-cm3.h" +# define CMSIS_CONF_HEADER_PATH "cc13x0-cc26x0-cm3.h" #elif (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X2_CC26X2) -# define CMSIS_CONF_HEADER_PATH "cc13x2-cc26x2-cm4.h" +# define CMSIS_CONF_HEADER_PATH "cc13x2-cc26x2-cm4.h" #endif /*---------------------------------------------------------------------------*/ /* Path to headers with implementation of mutexes and memory barriers */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/random.c b/arch/cpu/cc13xx-cc26xx/dev/random.c index 3232a06d2..1a244742b 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/random.c +++ b/arch/cpu/cc13xx-cc26xx/dev/random.c @@ -29,14 +29,20 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /** - * \addtogroup cc13xx-cc26xx-prng + * \addtogroup cc13xx-cc26xx-cpu + * @{ + * + * \defgroup cc13xx-cc26xx-prng Pseudo Random Number Generator (PRNG) for CC13xx/CC26xx. * @{ * * Implementation based on Bob Jenkins' small noncryptographic PRNG. - * http://burtleburtle.net/bob/rand/smallprng.html + * - http://burtleburtle.net/bob/rand/smallprng.html + * + * This file overrides os/lib/random.c. Note that the file name must + * match the original file for the override to work. * * \file - * This file overrides os/lib/random.c. + * Implementation of Pseudo Random Number Generator for CC13xx/CC26xx. * \author * Edvard Pettersen */ @@ -75,8 +81,8 @@ random_rand(void) } /*---------------------------------------------------------------------------*/ /** - * \brief Function required by the API - * \param seed Ignored. + * \brief Initialize the PRNG. + * \param seed Seed for the PRNG. */ void random_init(unsigned short seed) @@ -91,5 +97,6 @@ random_init(unsigned short seed) } /*---------------------------------------------------------------------------*/ /** + * @} * @} */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c b/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c index 345ea80bb..143a23cc3 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c @@ -10,6 +10,7 @@ * 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. @@ -32,38 +33,42 @@ * @{ * * \file - * Implementation of the arch-specific rtimer functions for the CC13xx/CC26xx + * Implementation of the rtimer driver for CC13xx/CC26xx. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ +#include "contiki.h" +/*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/aon_event.h) #include DeviceFamily_constructPath(driverlib/aon_rtc.h) #include DeviceFamily_constructPath(driverlib/interrupt.h) #include +#include /*---------------------------------------------------------------------------*/ -#include "contiki.h" -/*---------------------------------------------------------------------------*/ +#include #include /*---------------------------------------------------------------------------*/ #define HWIP_RTC_CH AON_RTC_CH0 #define RTIMER_RTC_CH AON_RTC_CH1 /*---------------------------------------------------------------------------*/ -static ClockP_Struct gClk; -static ClockP_Handle hClk; -/*---------------------------------------------------------------------------*/ -typedef void (*IsrFxn)(void); -typedef void (*HwiDispatchFxn)(void); +typedef void (*isr_fxn_t)(void); +typedef void (*hwi_dispatch_fxn_t)(void); -static volatile HwiDispatchFxn hwiDispatch = NULL; +static hwi_dispatch_fxn_t hwi_dispatch_fxn; /*---------------------------------------------------------------------------*/ /** - * \brief TODO + * \brief Stub function used when creating the dummy clock object. */ -static void rtimer_clock_stub(uintptr_t arg) { /* do nothing */ } +static void rtimer_clock_stub(uintptr_t unused) { (void)unused; /* do nothing */ } /*---------------------------------------------------------------------------*/ /** - * \brief TODO + * \brief The Man-in-the-Middle ISR hook for the HWI dispatch ISR. This + * will be the ISR dispatched when INT_AON_RTC_COMB is triggered, + * and will either dispatch the interrupt to the rtimer driver or + * the HWI driver, depening on which event triggered the interrupt. */ static void rtimer_isr_hook(void) @@ -75,9 +80,13 @@ rtimer_isr_hook(void) rtimer_run_next(); } - if (hwiDispatch && AONRTCEventGet(HWIP_RTC_CH)) + /* + * HWI Dispatch clears the interrupt. If HWI wasn't triggered, clear + * the interrupt manually. + */ + if (AONRTCEventGet(HWIP_RTC_CH)) { - hwiDispatch(); + hwi_dispatch_fxn(); } else { @@ -91,50 +100,73 @@ rtimer_isr_hook(void) void rtimer_arch_init(void) { - const bool intkey = IntMasterDisable(); + uintptr_t key; + ClockP_Struct clk_object; + ClockP_Params clk_params; + volatile isr_fxn_t *ramvec_table; - // Create dummy clock to trigger init of the RAM vector table - ClockP_Params clkParams; - ClockP_Params_init(&clkParams); - hClk = ClockP_construct(&gClk, rtimer_clock_stub, 0, &clkParams); + key = HwiP_disable(); - // Try to access the RAM vector table - volatile IsrFxn * const pfnRAMVectors = (volatile IsrFxn *)(HWREG(NVIC_VTABLE)); - if (!pfnRAMVectors) + /* + * Create a dummy clock to guarantee the RAM vector table is initialized. + * + * Creating a dummy clock will trigger initialization of TimerP, which + * subsequently initializes the driverlib/interrupt.h module. It is the + * interrupt module that initializes the RAM vector table. + * + * It is safe to destruct the Clock object immediately afterwards. + */ + ClockP_Params_init(&clk_params); + ClockP_construct(&clk_object, rtimer_clock_stub, 0, &clk_params); + ClockP_destruct(&clk_object); + + /* Try to access the RAM vector table. */ + ramvec_table = (isr_fxn_t*)HWREG(NVIC_VTABLE); + if (!ramvec_table) { + /* + * Unable to find the RAM vector table is a serious fault. + * Spin-lock forever. + */ for (;;) { /* hang */ } } - // The HWI Dispatch ISR should be located at int num INT_AON_RTC_COMB. - // Fetch and store it. - hwiDispatch = (HwiDispatchFxn)pfnRAMVectors[INT_AON_RTC_COMB]; - if (!hwiDispatch) + /* + * The HWI Dispatch ISR is located at interrupt number INT_AON_RTC_COMB + * in the RAM vector table. Fetch and store it. + */ + hwi_dispatch_fxn = (hwi_dispatch_fxn_t)ramvec_table[INT_AON_RTC_COMB]; + if (!hwi_dispatch_fxn) { + /* + * Unable to find the HWI dispatch ISR in the RAM vector table is + * a serious fault. Spin-lock forever. + */ for (;;) { /* hang */ } } - // Override the INT_AON_RTC_COMB int num with own ISR hook + /* + * Override the INT_AON_RTC_COMB interrupt number with our own ISR hook, + * which will act as a man-in-the-middle ISR for the HWI dispatch. + */ IntRegister(INT_AON_RTC_COMB, rtimer_isr_hook); AONEventMcuWakeUpSet(AON_EVENT_MCU_WU1, AON_EVENT_RTC_CH1); AONRTCCombinedEventConfig(HWIP_RTC_CH | RTIMER_RTC_CH); - if (!intkey) - { - IntMasterEnable(); - } + HwiP_restore(key); } /*---------------------------------------------------------------------------*/ /** - * \brief Schedules an rtimer task to be triggered at time t - * \param t The time when the task will need executed. + * \brief Schedules an rtimer task to be triggered at time \p t. + * \param t The time when the task will need executed. * - * \e t is an absolute time, in other words the task will be executed AT - * time \e t, not IN \e t rtimer ticks. + * \p t is an absolute time, in other words the task will be + * executed AT time \p t, not IN \p t rtimer ticks. * - * This function schedules a one-shot event with the AON RTC. + * This function schedules a one-shot event with the AON RTC. * - * This functions converts \e to a value suitable for the AON RTC. + * This functions converts \p t to a value suitable for the AON RTC. */ void rtimer_arch_schedule(rtimer_clock_t t) @@ -145,17 +177,16 @@ rtimer_arch_schedule(rtimer_clock_t t) } /*---------------------------------------------------------------------------*/ /** - * \brief Returns the current real-time clock time - * \return The current rtimer time in ticks - * - * The value is read from the AON RTC counter and converted to a number of - * rtimer ticks + * \brief Returns the current real-time clock time. + * \return The current rtimer time in ticks. * + * The value is read from the AON RTC counter and converted to a + * number of rtimer ticks. */ rtimer_clock_t rtimer_arch_now() { - return ((rtimer_clock_t)AONRTCCurrentCompareValueGet()); + return (rtimer_clock_t)AONRTCCurrentCompareValueGet(); } /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.h b/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.h index 2b9394c1d..341f09393 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.h +++ b/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -10,6 +10,7 @@ * 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. @@ -27,19 +28,22 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup cc26xx-clocks + * \addtogroup cc13xx-cc26xx-cpu * @{ * - * \defgroup cc26xx-rtimer CC13xx/CC26xx rtimer + * \defgroup cc13xx-cc26xx-rtimer The CC13xx/CC26xx rtimer * - * Implementation of the rtimer module for the CC13xx/CC26xx + * Implementation of the rtimer module for CC13xx/CC26xx. This header + * is included by os/sys/rtimer.h. + * + * RTIMER_ARCH_SECOND is defined in cc13xx-cc26xx-def.h. * @{ - */ -/** + * * \file - * Header file for the CC13xx/CC26xx rtimer driver + * Header file of the rtimer driver for CC13xx/CC26xx. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #ifndef RTIMER_ARCH_H_ @@ -47,22 +51,32 @@ /*---------------------------------------------------------------------------*/ #include "contiki.h" /*---------------------------------------------------------------------------*/ -extern rtimer_clock_t rtimer_arch_now(void); - -/* HW oscillator frequency is 32 kHz, not 64 kHz and RTIMER_NOW() never returns - * an odd value; so US_TO_RTIMERTICKS always rounds to the nearest even number. +rtimer_clock_t rtimer_arch_now(void); +/*---------------------------------------------------------------------------*/ +/* + * HW oscillator frequency is 32 kHz, not 64 kHz. And, RTIMER_NOW() never + * returns an odd value; US_TO_RTIMERTICKS always rounds to the nearest + * even number. */ -#define US_TO_RTIMERTICKS(US) (2 * ((US) >= 0 ? \ - (((int32_t)(US) * (RTIMER_ARCH_SECOND / 2) + 500000) / 1000000L) : \ - ((int32_t)(US) * (RTIMER_ARCH_SECOND / 2) - 500000) / 1000000L)) +#define US_TO_RTIMERTICKS(us) (2 * ( \ + ((us) >= 0) \ + ? (((int32_t)(us) * (RTIMER_ARCH_SECOND / 2) + 500000) / 1000000L) \ + : (((int32_t)(us) * (RTIMER_ARCH_SECOND / 2) - 500000) / 1000000L) \ + )) -#define RTIMERTICKS_TO_US(T) ((T) >= 0 ? \ - (((int32_t)(T) * 1000000L + ((RTIMER_ARCH_SECOND) / 2)) / (RTIMER_ARCH_SECOND)) : \ - ((int32_t)(T) * 1000000L - ((RTIMER_ARCH_SECOND) / 2)) / (RTIMER_ARCH_SECOND)) +#define RTIMERTICKS_TO_US(rt) ( \ + ((rt) >= 0) \ + ? (((int32_t)(rt) * 1000000L + (RTIMER_ARCH_SECOND / 2)) / RTIMER_ARCH_SECOND) \ + : (((int32_t)(rt) * 1000000L - (RTIMER_ARCH_SECOND / 2)) / RTIMER_ARCH_SECOND) \ + ) -/* A 64-bit version because the 32-bit one cannot handle T >= 4295 ticks. - Intended only for positive values of T. */ -#define RTIMERTICKS_TO_US_64(T) ((uint32_t)(((uint64_t)(T) * 1000000 + ((RTIMER_ARCH_SECOND) / 2)) / (RTIMER_ARCH_SECOND))) +/* + * A 64-bit version because the 32-bit one cannot handle T >= 4295 ticks. + * Intended only for positive values of T. + */ +#define RTIMERTICKS_TO_US_64(rt) ((uint32_t)( \ + ((uint64_t)(rt) * 1000000 + (RTIMER_ARCH_SECOND / 2)) / RTIMER_ARCH_SECOND \ + )) /*---------------------------------------------------------------------------*/ #endif /* RTIMER_ARCH_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/dev/slip-arch.c b/arch/cpu/cc13xx-cc26xx/dev/slip-arch.c index c8d3cea2a..f1f877e98 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/slip-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/slip-arch.c @@ -28,23 +28,27 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup cc26xx-char-io + * \addtogroup cc13xx-cc26xx-cpu + * @{ + * + * \defgroup cc13xx-cc26xx-slip-arch SLIP for CC13xx/CC26xx. * @{ * * \file - * Arch-specific SLIP functions for the CC13xx/CC26xx + * Implementation of SLIP driver for CC13xx/CC26xx. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ -#include -#include +#include "contiki.h" +#include "dev/slip.h" /*---------------------------------------------------------------------------*/ -#include "dev/uart0-arch.h" +#include "uart0-arch.h" /*---------------------------------------------------------------------------*/ /** - * \brief Write a byte over SLIP - * \param c the byte + * \brief Write a single byte over SLIP. + * \param c The byte to write. */ void slip_arch_writeb(unsigned char c) @@ -53,16 +57,20 @@ slip_arch_writeb(unsigned char c) } /*---------------------------------------------------------------------------*/ /** - * \brief Initialise the arch-specific SLIP driver + * \brief Initialize the SLIP driver. */ void -slip_arch_init() +slip_arch_init(void) { - // Enable an input handler. In doing so, the driver will make sure that UART - // RX stays operational during deep sleep + /* + * Set an input handler. In doing so, the driver will make sure that UART + * RX stays operational during deep sleep. + */ uart0_init(); uart0_set_callback(slip_input_byte); } /*---------------------------------------------------------------------------*/ - -/** @} */ +/** + * @} + * @} + */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/trng-arch.c b/arch/cpu/cc13xx-cc26xx/dev/trng-arch.c index cb32232e0..cdba878af 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/trng-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/trng-arch.c @@ -46,8 +46,8 @@ #include /*---------------------------------------------------------------------------*/ /* - * Very dirty workaround because of the pre-compiled TI drivers library for - * CC13xx/CC26x0 is missing the CryptoKey object file. + * Very dirty workaround because the pre-compiled TI drivers library for + * CC13x0/CC26x0 is missing the CryptoKey object file. */ #include #if (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0) @@ -57,18 +57,12 @@ #include #include /*---------------------------------------------------------------------------*/ -void -trng_init(void) -{ - TRNG_init(); -} -/*---------------------------------------------------------------------------*/ bool trng_rand(uint8_t *entropy_buf, size_t entropy_len, uint32_t timeout_us) { - TRNG_Params trng_params; - TRNG_Handle trng_handle; - CryptoKey entropy_key; + TRNG_Params trng_params; + TRNG_Handle trng_handle; + CryptoKey entropy_key; int_fast16_t result; TRNG_Params_init(&trng_params); @@ -78,7 +72,7 @@ trng_rand(uint8_t *entropy_buf, size_t entropy_len, uint32_t timeout_us) } trng_handle = TRNG_open(0, &trng_params); - if (!trng_handle) { + if(!trng_handle) { return false; } diff --git a/arch/cpu/cc13xx-cc26xx/dev/trng-arch.h b/arch/cpu/cc13xx-cc26xx/dev/trng-arch.h index 1b6c7f3a4..ac220bd25 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/trng-arch.h +++ b/arch/cpu/cc13xx-cc26xx/dev/trng-arch.h @@ -52,13 +52,9 @@ #define TRNG_WAIT_FOREVER (~(uint32_t)0) /*---------------------------------------------------------------------------*/ /** - * \breif Initialize the TRNG module. - */ -void trng_init(void); - -/** - * \brief Generates a stream of true random numbers. This is - * a blocking function call with a specified timeout. + * \brief Generates a stream of entropy from which you can create + * a true random number from. This is a blocking function + * call with a specified timeout. * \param entropy_buf Buffer to store a stream of entropy. * \param entropy_len Length of the entropy buffer. * \param timeout_us How long to wait until timing out the operation. A diff --git a/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c b/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c index 7e2f70cfe..ec1f85265 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -10,6 +10,7 @@ * 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. @@ -27,99 +28,102 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup cc26xx-uart + * \addtogroup cc13xx-cc26xx-uart * @{ * * \file - * Implementation of the CC13xx/CC26xx UART driver. + * Implementation of UART driver for CC13xx/CC26xx. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ +#include "contiki.h" +/*---------------------------------------------------------------------------*/ +#include "uart0-arch.h" +/*---------------------------------------------------------------------------*/ #include #include /*---------------------------------------------------------------------------*/ -#include -/*---------------------------------------------------------------------------*/ #include #include /*---------------------------------------------------------------------------*/ -#include "uart0-arch.h" -/*---------------------------------------------------------------------------*/ -static UART_Handle gh_uart; +static UART_Handle uart_handle; -static volatile uart0_input_cb curr_input_cb; +static volatile uart0_input_fxn_t curr_input_cb; static unsigned char char_buf; -static bool is_init; +static bool initialized; /*---------------------------------------------------------------------------*/ static void uart0_cb(UART_Handle handle, void *buf, size_t count) { - if (!curr_input_cb) { return; } + /* Simply return if the current callback is NULL. */ + if(!curr_input_cb) { return; } /* - * Save the current callback function, as this might be overwritten after - * the callback is called. + * Save the current callback function locally, as it might be overwritten + * after calling the callback. */ - const uart0_input_cb currCb = curr_input_cb; - /* Call the callback. Note this might reset curr_input_cb */ - currCb(char_buf); + const uart0_input_fxn_t curr_cb = curr_input_cb; + curr_cb(char_buf); /* * If curr_input_cb didn't change after the call, do another read. * Else, the uart0_set_callback was called with a different callback pointer * and triggered an another read. */ - if (currCb == curr_input_cb) { - UART_read(gh_uart, &char_buf, 1); + if(curr_cb == curr_input_cb) { + UART_read(uart_handle, &char_buf, 1); } } /*---------------------------------------------------------------------------*/ void uart0_init(void) { - if (is_init) { return; } - is_init = true; + if(initialized) { return; } - UART_Params params; - UART_Params_init(¶ms); + UART_Params uart_params; + UART_Params_init(&uart_params); - params.baudRate = TI_UART_CONF_BAUD_RATE; - params.readMode = UART_MODE_CALLBACK; - params.writeMode = UART_MODE_BLOCKING; - params.readCallback = uart0_cb; - params.readDataMode = UART_DATA_TEXT; - params.readReturnMode = UART_RETURN_NEWLINE; + uart_params.baudRate = TI_UART_CONF_BAUD_RATE; + uart_params.readMode = UART_MODE_CALLBACK; + uart_params.writeMode = UART_MODE_BLOCKING; + uart_params.readCallback = uart0_cb; + uart_params.readDataMode = UART_DATA_TEXT; + uart_params.readReturnMode = UART_RETURN_NEWLINE; - gh_uart = UART_open(Board_UART0, ¶ms); + /* No error handling. */ + uart_handle = UART_open(Board_UART0, &uart_params); + + initialized = true; } /*---------------------------------------------------------------------------*/ int_fast32_t -uart0_write(const void *buffer, size_t size) +uart0_write(const void *buf, size_t buf_size) { - if (!is_init) { + if(!initialized) { return UART_STATUS_ERROR; } - return UART_write(gh_uart, buffer, size); + return UART_write(uart_handle, buf, buf_size); } /*---------------------------------------------------------------------------*/ int_fast32_t -uart0_set_callback(uart0_input_cb input_cb) +uart0_set_callback(uart0_input_fxn_t input_cb) { - if (!is_init) { + if(!initialized) { return UART_STATUS_ERROR; } - if (curr_input_cb == input_cb) { + if(curr_input_cb == input_cb) { return UART_STATUS_SUCCESS; } curr_input_cb = input_cb; - if (input_cb) { - return UART_read(gh_uart, &char_buf, 1); + if(input_cb) { + return UART_read(uart_handle, &char_buf, 1); } else { - UART_readCancel(gh_uart); + UART_readCancel(uart_handle); return UART_STATUS_SUCCESS; } } diff --git a/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.h b/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.h index 2fd5eae42..68b7a18c5 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.h +++ b/arch/cpu/cc13xx-cc26xx/dev/uart0-arch.h @@ -28,16 +28,20 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /** - * \addtogroup cc26xx + * \addtogroup cc13xx-cc26xx-cpu * @{ * - * \defgroup cc26xx-uart CC13xx/CC26xx UARTs + * \defgroup cc13xx-cc26xx-uart UART for CC13xx/CC26xx. * - * Driver for the CC13xx/CC26xx UART controller + * This particular driver utilizes the UART0 peripheral specifically. + * + * Driver for the CC13xx/CC26xx UART controller. * @{ * * \file - * Header file for the CC13xx/CC26xx UART driver + * Header file of UART driver for CC13xx/CC26xx. + * \author + * Edvard Pettersen */ #ifndef UART0_ARCH_H_ #define UART0_ARCH_H_ @@ -45,37 +49,31 @@ #include #include /*---------------------------------------------------------------------------*/ -typedef int (*uart0_input_cb)(unsigned char); +typedef int (*uart0_input_fxn_t)(unsigned char); /*---------------------------------------------------------------------------*/ -/** \name UART functions - * @{ - */ - /** - * \brief Initializes the UART driver + * \brief Initializes the UART driver. */ void uart0_init(void); /** - * \brief Writes data from a memory buffer to the UART interface. - * \param buffer A pointer to the data buffer. - * \param size Size of the data buffer. - * \return Number of bytes that has been written to the UART. If an - * error occurs, a negative value is returned. + * \brief Writes data from a memory buffer to the UART interface. + * \param buf A pointer to the data buffer. + * \param buf_size Size of the data buffer. + * \return Number of bytes that has been written to the UART. If an + * error occurs, a negative value is returned. */ -int_fast32_t uart0_write(const void *buffer, size_t size); +int_fast32_t uart0_write(const void *buf, size_t buf_size); /** - * \brief Sets the callback function for when bytes are received - * on UART0. - * \param input_cb Pointer to the callback function. A valid pointer subscribes - * for UART0 callbacks when bytes are received, while a NULL pointer - * unsubscribes. - * \return 0 for success, negative value for errors. + * \brief Set the callback function for when bytes are received + * on UART0. + * \param input_cb Pointer to the callback function. A valid pointer + * subscribes for UART0 callbacks when bytes are received, + * while a NULL pointer unsubscribes. + * \return 0 for success, negative value for errors. */ -int_fast32_t uart0_set_callback(uart0_input_cb input_cb); - -/** @} */ +int_fast32_t uart0_set_callback(uart0_input_fxn_t input_cb); /*---------------------------------------------------------------------------*/ #endif /* UART0_ARCH_H_ */ /** diff --git a/arch/cpu/cc13xx-cc26xx/dev/watchdog-arch.c b/arch/cpu/cc13xx-cc26xx/dev/watchdog-arch.c index f5eb3537d..825b835bf 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/watchdog-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/watchdog-arch.c @@ -28,10 +28,10 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /** - * \addtogroup cc26xx-clocks + * \addtogroup cc13xx-cc26xx-cpu * @{ * - * \defgroup cc26xx-wdt CC13xx/CC26xx watchdog timer driver + * \defgroup cc13xx-cc26xx-watchdog CC13xx/CC26xx watchdog timer driver * * Driver for the CC13xx/CC26xx Watchdog Timer * @@ -53,66 +53,85 @@ #include #include /*---------------------------------------------------------------------------*/ -#ifdef CONTIKI_WATCHDOG_CONF_TIMER_TOP -#define CONTIKI_WATCHDOG_TIMER_TOP CONTIKI_WATCHDOG_CONF_TIMER_TOP -#else -#define CONTIKI_WATCHDOG_TIMER_TOP 0xFFFFF -#endif +#define WATCHDOG_DISABLE WATCHDOG_CONF_DISABLE +#define WATCHDOG_TIMER_TOP WATCHDOG_CONF_TIMER_TOP /*---------------------------------------------------------------------------*/ -static Watchdog_Handle wd_handle; +static Watchdog_Handle wdt_handle; /*---------------------------------------------------------------------------*/ /** - * \brief Initialises the CC26xx WDT + * \brief Initialises the Watchdog module. * - * Simply sets the reload counter to a default value. The WDT is not started - * yet. To start it, watchdog_start() must be called. + * Simply sets the reload counter to a default value. The WDT is not + * started yet. To start it, watchdog_start() must be called. */ void watchdog_init(void) { + if(WATCHDOG_DISABLE) { + return; + } + Watchdog_init(); - Watchdog_Params params; - Watchdog_Params_init(¶ms); - params.resetMode = Watchdog_RESET_ON; - params.debugStallMode = Watchdog_DEBUG_STALL_ON; + Watchdog_Params wdt_params; + Watchdog_Params_init(&wdt_params); - wd_handle = Watchdog_open(Board_WATCHDOG0, ¶ms); + wdt_params.resetMode = Watchdog_RESET_ON; + wdt_params.debugStallMode = Watchdog_DEBUG_STALL_ON; + + wdt_handle = Watchdog_open(Board_WATCHDOG0, &wdt_params); } /*---------------------------------------------------------------------------*/ /** - * \brief Starts the CC26xx WDT + * \brief Start the Watchdog. */ void watchdog_start(void) { + if(WATCHDOG_DISABLE) { + return; + } + watchdog_periodic(); } /*---------------------------------------------------------------------------*/ /** - * \brief Refreshes the CC26xx WDT + * \brief Refresh (feed) the Watchdog. */ void watchdog_periodic(void) { - Watchdog_setReload(wd_handle, CONTIKI_WATCHDOG_TIMER_TOP); + if(WATCHDOG_DISABLE) { + return; + } + + Watchdog_setReload(wdt_handle, WATCHDOG_TIMER_TOP); } /*---------------------------------------------------------------------------*/ /** - * \brief Stops the WDT such that it won't timeout and cause MCU reset + * \brief Stop the Watchdog such that it won't timeout and cause a + * system reset. */ void watchdog_stop(void) { - Watchdog_clear(wd_handle); + if(WATCHDOG_DISABLE) { + return; + } + + Watchdog_clear(wdt_handle); } /*---------------------------------------------------------------------------*/ /** - * \brief Manually trigger a WDT reboot + * \brief Manually trigger a Watchdog timeout. */ void watchdog_reboot(void) { + if(WATCHDOG_DISABLE) { + return; + } + watchdog_start(); while(1); } diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.c index b7a9194ed..59054c175 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.c @@ -141,7 +141,7 @@ rfc_CMD_RADIO_SETUP_t rf_ble_cmd_radio_setup = .mode = 0x00, .loDivider = 0x00, .config.frontEndMode = 0x0, - .config.biasMode = 0x1, + .config.biasMode = 0x0, .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, .txPower = 0x3D3F, diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c index d903a4c4c..c2d7b5fdc 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c @@ -144,7 +144,7 @@ rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup = .condition.nSkip = 0x0, .mode = 0x01, .config.frontEndMode = 0x0, - .config.biasMode = 0x1, + .config.biasMode = 0x0, .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, .txPower = DEFAULT_TX_POWER, /* 5 dBm default */ @@ -210,7 +210,7 @@ rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx = .condition.nSkip = 0x0, .channel = 0x00, /* set by driver */ .rxConfig.bAutoFlushCrc = 0x1, - .rxConfig.bAutoFlushIgn = 0x0, + .rxConfig.bAutoFlushIgn = 0x1, .rxConfig.bIncludePhyHdr = 0x0, .rxConfig.bIncludeCrc = 0x1, .rxConfig.bAppendRssi = 0x1, diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c index 3c6c1c261..e47ebde1a 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c @@ -307,7 +307,7 @@ rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup = .formatConf.fecMode = 0x0, .formatConf.whitenMode = 0x7, .config.frontEndMode = 0x0, /* set by driver */ - .config.biasMode = 0x1, /* set by driver */ + .config.biasMode = 0x0, /* set by driver */ .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, .txPower = DEFAULT_TX_POWER, diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c index 253c11dfc..dd0df6343 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c @@ -283,7 +283,7 @@ rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup = .mode = 0x01, .loDivider = 0x00, .config.frontEndMode = 0x0, - .config.biasMode = 0x1, + .config.biasMode = 0x0, .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, .txPower = DEFAULT_TX_POWER, /* 5 dBm default */ @@ -349,7 +349,7 @@ rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx = .condition.nSkip = 0x0, .channel = 0x00, /* set by driver */ .rxConfig.bAutoFlushCrc = 0x1, - .rxConfig.bAutoFlushIgn = 0x0, + .rxConfig.bAutoFlushIgn = 0x1, .rxConfig.bIncludePhyHdr = 0x0, .rxConfig.bIncludeCrc = 0x1, .rxConfig.bAppendRssi = 0x1, diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c index 44cd20960..5b8a1d04d 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c @@ -402,7 +402,7 @@ rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup = .formatConf.fecMode = 0x0, .formatConf.whitenMode = 0x7, .config.frontEndMode = 0x0, /* set by driver */ - .config.biasMode = 0x1, /* set by driver */ + .config.biasMode = 0x0, /* set by driver */ .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, .txPower = DEFAULT_TX_POWER, diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c index 2c87bb50e..1afb9d593 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c @@ -140,7 +140,7 @@ rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup = .mode = 0x01, .__dummy0 = 0x00, .config.frontEndMode = 0x0, - .config.biasMode = 0x1, + .config.biasMode = 0x0, .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, .txPower = DEFAULT_TX_POWER, /* 5 dBm default */ @@ -206,7 +206,7 @@ rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx = .condition.nSkip = 0x0, .channel = 0x00, /* set by driver */ .rxConfig.bAutoFlushCrc = 0x1, - .rxConfig.bAutoFlushIgn = 0x0, + .rxConfig.bAutoFlushIgn = 0x1, .rxConfig.bIncludePhyHdr = 0x0, .rxConfig.bIncludeCrc = 0x1, .rxConfig.bAppendRssi = 0x1, diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c index 76e6fdd14..b0e6de78f 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c @@ -139,10 +139,10 @@ rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup = .mode = 0x01, .loDivider = 0x00, .config.frontEndMode = 0x0, - .config.biasMode = 0x1, + .config.biasMode = 0x0, .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, - .txPower = DEFAULT_TX_POWER, /* 5 dBm default */ + .txPower = DEFAULT_TX_POWER, .pRegOverride = rf_ieee_overrides, }; /*---------------------------------------------------------------------------*/ @@ -205,7 +205,7 @@ rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx = .condition.nSkip = 0x0, .channel = 0x00, /* set by driver */ .rxConfig.bAutoFlushCrc = 0x1, - .rxConfig.bAutoFlushIgn = 0x0, + .rxConfig.bAutoFlushIgn = 0x1, .rxConfig.bIncludePhyHdr = 0x0, .rxConfig.bIncludeCrc = 0x1, .rxConfig.bAppendRssi = 0x1, diff --git a/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c b/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c index 4ab38acb8..8f230de2c 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c +++ b/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c @@ -79,9 +79,9 @@ #include /*---------------------------------------------------------------------------*/ #if 1 -# define PRINTF(...) -#else # define PRINTF(...) printf(__VA_ARGS__) +#else +# define PRINTF(...) #endif /*---------------------------------------------------------------------------*/ /* Configuration parameters */ @@ -420,6 +420,8 @@ init(void) set_channel(DOT_15_4G_DEFAULT_CHAN); + rf_set_tx_power(ieee_radio.rf_handle, TX_POWER_TABLE, TX_POWER_MAX); + ENERGEST_ON(ENERGEST_TYPE_LISTEN); /* Start RAT overflow upkeep */ diff --git a/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c b/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c index 02d48bc21..a573914d3 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c +++ b/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c @@ -56,11 +56,10 @@ #include /*---------------------------------------------------------------------------*/ /* Platform RF dev */ -#include "dot-15-4g.h" -#include "rf-core.h" -#include "rf-data-queue.h" -#include "netstack-settings.h" -#include RF_PROP_SETTINGS +#include "rf/dot-15-4g.h" +#include "rf/sched.h" +#include "rf/data-queue.h" +#include "prop-settings.h" /*---------------------------------------------------------------------------*/ #include #include @@ -495,7 +494,7 @@ pending_packet(void) } while (curr_entry != read_entry); if (num_pending > 0) { - process_poll(&rf_core_process); + process_poll(&rf_sched_process); } /* If we didn't find an entry at status finished, no frames are pending */ @@ -691,7 +690,7 @@ init(void) ENERGEST_ON(ENERGEST_TYPE_LISTEN); /* Start RF process */ - process_start(&rf_core_process, NULL); + process_start(&rf_sched_process, NULL); return RF_RESULT_OK; } diff --git a/arch/cpu/cc13xx-cc26xx/rf/sched.c b/arch/cpu/cc13xx-cc26xx/rf/sched.c index 476c9d56c..fc12b3302 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/sched.c +++ b/arch/cpu/cc13xx-cc26xx/rf/sched.c @@ -44,7 +44,7 @@ #include "net/netstack.h" #include "net/packetbuf.h" #include "net/mac/mac.h" - +#include "lib/random.h" /*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) @@ -81,6 +81,8 @@ /*---------------------------------------------------------------------------*/ /* Synth re-calibration every 3 minutes */ #define SYNTH_RECAL_INTERVAL (CLOCK_SECOND * 60 * 3) +/* Set re-calibration interval with a jitter of 10 seconds */ +#define SYNTH_RECAL_JITTER (CLOCK_SECOND * 10) static struct etimer synth_recal_timer; /*---------------------------------------------------------------------------*/ @@ -105,11 +107,20 @@ cmd_rx_cb(RF_Handle client, RF_CmdHandle command, RF_EventMask events) if (events & RF_EventRxBufFull) { rx_buf_full = true; - process_poll(&rf_sched_process); } } /*---------------------------------------------------------------------------*/ +static inline clock_time_t +synth_recal_interval(void) +{ + /* + * Add jitter centered around SYNTH_RECAL_INTERVAL, + * giving a +- jitter halved. + */ + return SYNTH_RECAL_INTERVAL + (random_rand() % SYNTH_RECAL_JITTER) - (SYNTH_RECAL_JITTER / 2); +} +/*---------------------------------------------------------------------------*/ static inline bool cmd_rx_is_active(void) { @@ -241,12 +252,12 @@ netstack_sched_fs(void) * * For Prop-mode, the synth is always manually calibrated with CMD_FS. */ -#if (RF_CORE_CONF_MODE == RF_CORE_MODE_2_4_GHZ) +#if (RF_MODE == RF_CORE_MODE_2_4_GHZ) if (rx_key) { cmd_rx_restore(rx_key); return RF_RESULT_OK; } -#endif /* RF_CORE_CONF_MODE == RF_CORE_MODE_2_4_GHZ */ +#endif /* RF_MODE == RF_CORE_MODE_2_4_GHZ */ RF_EventMask events; bool synth_error = false; @@ -518,11 +529,18 @@ PROCESS_THREAD(rf_sched_process, ev, data) while(1) { PROCESS_YIELD_UNTIL((ev == PROCESS_EVENT_POLL) || - etimer_expired(&synth_recal_timer)); + (ev == PROCESS_EVENT_TIMER)); + + /* start the synth re-calibration timer once. */ + if (rf_is_on) { + rf_is_on = false; + etimer_set(&synth_recal_timer, synth_recal_interval()); + } if (ev == PROCESS_EVENT_POLL) { do { watchdog_periodic(); + packetbuf_clear(); len = NETSTACK_RADIO.read(packetbuf_dataptr(), PACKETBUF_SIZE); @@ -531,7 +549,7 @@ PROCESS_THREAD(rf_sched_process, ev, data) * RX after we've freed at least on packet. */ if (rx_buf_full) { - PRINTF("rf_core: RX buf full, restart RX\n"); + PRINTF("rf_core: RX buf full, restart RX status=0x%04x\n", CMD_STATUS(netstack_cmd_rx)); rx_buf_full = false; /* Restart RX. */ @@ -547,16 +565,13 @@ PROCESS_THREAD(rf_sched_process, ev, data) } while(len > 0); } - /* start the synth re-calibration timer once. */ - if (rf_is_on) { - rf_is_on = false; - etimer_set(&synth_recal_timer, SYNTH_RECAL_INTERVAL); - } /* Scheduling CMD_FS will re-calibrate the synth. */ - if (etimer_expired(&synth_recal_timer)) { + if ((ev == PROCESS_EVENT_TIMER) && + etimer_expired(&synth_recal_timer)) { + PRINTF("rf_core: Re-calibrate synth\n"); netstack_sched_fs(); - etimer_reset(&synth_recal_timer); + etimer_set(&synth_recal_timer, synth_recal_interval()); } } PROCESS_END(); diff --git a/arch/platform/simplelink/cc13xx-cc26xx/platform.c b/arch/platform/simplelink/cc13xx-cc26xx/platform.c index a591fefa0..abe00da49 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/platform.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/platform.c @@ -67,6 +67,7 @@ #include #include #include +#include #include /*---------------------------------------------------------------------------*/ #include "board-peripherals.h" @@ -152,7 +153,7 @@ platform_init_stage_one(void) * Something is seriously wrong if PIN initialization of the Board GPIO * table fails. */ - while (1); + for (;;); } /* Perform board-specific initialization */ @@ -178,6 +179,8 @@ platform_init_stage_one(void) NVS_init(); #endif + TRNG_init(); + fade(LEDS_GREEN); /* NoRTOS must be called last */ @@ -198,14 +201,12 @@ platform_init_stage_two(void) #endif /* Use TRNG to seed PRNG. If TRNG fails, use a hard-coded seed. */ - unsigned short trn = 0; - trng_init(); - bool result = trng_rand((uint8_t*)&trn, sizeof(trn), TRNG_WAIT_FOREVER); - if (!result) { + unsigned short seed = 0; + if (!trng_rand((uint8_t*)&seed, sizeof(seed), TRNG_WAIT_FOREVER)) { /* Default to some hard-coded seed. */ - trn = 0x1234; + seed = 0x1234; } - random_init(trn); + random_init(seed); /* Populate linkaddr_node_addr */ ieee_addr_cpy_to(linkaddr_node_addr.u8, LINKADDR_SIZE); From abe82f3d8ec1c0f03d390fd43a78292fff8904dc Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Mon, 23 Jul 2018 09:37:23 +0200 Subject: [PATCH 279/485] Fixed bug in the circular data queue --- arch/cpu/cc13xx-cc26xx/rf/data-queue.c | 4 ++-- arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c | 17 ++++++++++------- arch/cpu/cc13xx-cc26xx/rf/prop-mode.c | 17 ++++++++++------- arch/cpu/cc13xx-cc26xx/rf/sched.c | 9 +++++---- 4 files changed, 27 insertions(+), 20 deletions(-) diff --git a/arch/cpu/cc13xx-cc26xx/rf/data-queue.c b/arch/cpu/cc13xx-cc26xx/rf/data-queue.c index 96f1be9c1..8b34569f1 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/data-queue.c +++ b/arch/cpu/cc13xx-cc26xx/rf/data-queue.c @@ -84,9 +84,9 @@ rx_bufs_init(void) data_entry->config.lenSz = rx_data_queue.lensz; data_entry->length = RX_BUF_SIZE - sizeof(data_entry_t); /* TODO: is this sizeof sound? */ /* Point to fist entry if this is last entry, else point to next entry */ - data_entry->pNextEntry = (i == (RX_BUF_CNT - 1)) + data_entry->pNextEntry = ((i + 1) == RX_BUF_CNT) ? rx_data_queue.bufs[0].buf - : rx_data_queue.bufs[i].buf; + : rx_data_queue.bufs[i+1].buf; } } /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c b/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c index 8f230de2c..449eb3d6a 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c +++ b/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c @@ -518,21 +518,24 @@ read(void *buf, unsigned short buf_len) if (data_entry->status != DATA_ENTRY_FINISHED) { /* No available data */ - return 0; + return -1; } /* - * First byte in the data entry is the length. + * lensz bytes (1) in the data entry are the length of the received frame. * Data frame is on the following format: * Length (1) + Payload (N) + FCS (2) + RSSI (1) + Status (1) + Timestamp (4) * Data frame DOES NOT contain the following: * no PHY Header bytes * no Source Index bytes - * +--------+---------+---------+--------+--------+-----------+ - * | 1 byte | N bytes | 2 bytes | 1 byte | 1 byte | 4 bytes | - * +--------+---------+---------+--------+--------+-----------+ - * | Length | Payload | FCS | RSSI | Status | Timestamp | - * +--------+---------+---------+--------+--------+-----------+ + * Visual representation of frame format: + * + * +--------+---------+---------+--------+--------+-----------+ + * | 1 byte | N bytes | 2 bytes | 1 byte | 1 byte | 4 bytes | + * +--------+---------+---------+--------+--------+-----------+ + * | Length | Payload | FCS | RSSI | Status | Timestamp | + * +--------+---------+---------+--------+--------+-----------+ + * * Length bytes equal total length of entire frame excluding itself, * Length = N + FCS (2) + RSSI (1) + Status (1) + Timestamp (4) * Length = N + 8 diff --git a/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c b/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c index a573914d3..d7b25eda2 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c +++ b/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c @@ -376,22 +376,25 @@ read(void *buf, unsigned short buf_len) if (data_entry->status != DATA_ENTRY_FINISHED) { /* No available data */ - return 0; + return -1; } /* - * First 2 bytes in the data entry are the length. + * lensz bytes (2) in the data entry are the length of the received frame. * Data frame is on the following format: * Length (2) + Payload (N) + RSSI (1) + Status (1) * Data frame DOES NOT contain the following: * no Header/PHY bytes * no appended Received CRC bytes * no Timestamp bytes - * +---------+---------+--------+--------+ - * | 2 bytes | N bytes | 1 byte | 1 byte | - * +---------+---------+--------+--------+ - * | Length | Payload | RSSI | Status | - * +---------+---------+--------+--------+ + * Visual representation of frame format: + * + * +---------+---------+--------+--------+ + * | 2 bytes | N bytes | 1 byte | 1 byte | + * +---------+---------+--------+--------+ + * | Length | Payload | RSSI | Status | + * +---------+---------+--------+--------+ + * * Length bytes equal total length of entire frame excluding itself, * Length = N + RSSI (1) + Status (1) * = N + 2 diff --git a/arch/cpu/cc13xx-cc26xx/rf/sched.c b/arch/cpu/cc13xx-cc26xx/rf/sched.c index fc12b3302..840010d22 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/sched.c +++ b/arch/cpu/cc13xx-cc26xx/rf/sched.c @@ -115,8 +115,8 @@ static inline clock_time_t synth_recal_interval(void) { /* - * Add jitter centered around SYNTH_RECAL_INTERVAL, - * giving a +- jitter halved. + * Add jitter centered around SYNTH_RECAL_INTERVAL, giving a plus/minus + * jitter seconds halved. */ return SYNTH_RECAL_INTERVAL + (random_rand() % SYNTH_RECAL_JITTER) - (SYNTH_RECAL_JITTER / 2); } @@ -519,7 +519,7 @@ ble_sched_beacon(RF_Callback cb, RF_EventMask bm_event) return RF_RESULT_OK; } /*---------------------------------------------------------------------------*/ -PROCESS(rf_sched_process, "RF Core Process"); +PROCESS(rf_sched_process, "RF Scheduler Process"); /*---------------------------------------------------------------------------*/ PROCESS_THREAD(rf_sched_process, ev, data) { @@ -562,7 +562,8 @@ PROCESS_THREAD(rf_sched_process, ev, data) NETSTACK_MAC.input(); } - } while(len > 0); + /* Only break when we receive -1 => No available data */ + } while(len >= 0); } /* Scheduling CMD_FS will re-calibrate the synth. */ From 1d0f6227dc8413e090a9a268810bbf3d91d8a7dc Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Mon, 23 Jul 2018 14:35:37 +0200 Subject: [PATCH 280/485] Fixed doxygen --- arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h | 8 ++ arch/cpu/cc13xx-cc26xx/rf/ble-addr.c | 12 +- arch/cpu/cc13xx-cc26xx/rf/ble-addr.h | 21 +++- arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c | 39 +++--- arch/cpu/cc13xx-cc26xx/rf/ble-beacond.h | 21 ++-- arch/cpu/cc13xx-cc26xx/rf/data-queue.c | 16 ++- arch/cpu/cc13xx-cc26xx/rf/data-queue.h | 24 +++- arch/cpu/cc13xx-cc26xx/rf/dot-15-4g.h | 29 ++--- arch/cpu/cc13xx-cc26xx/rf/ieee-addr.c | 31 ++--- arch/cpu/cc13xx-cc26xx/rf/ieee-addr.h | 27 ++-- arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c | 115 +++++++++--------- arch/cpu/cc13xx-cc26xx/rf/prop-mode.c | 64 +++++----- arch/cpu/cc13xx-cc26xx/rf/rf.h | 5 +- arch/cpu/cc13xx-cc26xx/rf/sched.c | 67 +++++----- arch/cpu/cc13xx-cc26xx/rf/sched.h | 36 ++++-- .../simplelink/cc13xx-cc26xx/platform.c | 49 ++++---- 16 files changed, 317 insertions(+), 247 deletions(-) diff --git a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h index f169a088e..2a3b7cbde 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h +++ b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h @@ -45,6 +45,14 @@ #include "rf/rf.h" /*---------------------------------------------------------------------------*/ +#ifndef BOARD_CONF_HAS_SENSORS +#define BOARD_CONF_HAS_SENSORS 0 +#endif + +#ifndef BOARD_CONF_SENSORS_ENABLE +#define BOARD_CONF_SENSORS_ENABLE BOARD_CONF_HAS_SENSORS +#endif +/*---------------------------------------------------------------------------*/ /** * \name GPIO HAL configuration. * diff --git a/arch/cpu/cc13xx-cc26xx/rf/ble-addr.c b/arch/cpu/cc13xx-cc26xx/rf/ble-addr.c index db01506ad..ec1bec9eb 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/ble-addr.c +++ b/arch/cpu/cc13xx-cc26xx/rf/ble-addr.c @@ -26,14 +26,16 @@ * 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. - * */ /** - * \file - * Driver for the retrieval of an BLE address from flash + * \addtogroup cc13xx-cc26xx-rf-ble-addr + * @{ * + * \file + * Implementation of the CC13xx/CC26xx IEEE addresses driver. * \author - * Michael Spoerk + * Michael Spoerk + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #include "contiki.h" @@ -131,3 +133,5 @@ ble_addr_to_eui64_cpy(uint8_t *dst) return ble_addr_to_eui64(dst, ble_addr); } +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/cpu/cc13xx-cc26xx/rf/ble-addr.h b/arch/cpu/cc13xx-cc26xx/rf/ble-addr.h index 9a7901675..0b4028269 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/ble-addr.h +++ b/arch/cpu/cc13xx-cc26xx/rf/ble-addr.h @@ -26,15 +26,20 @@ * 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. - * */ -/*---------------------------------------------------------------------------*/ /** - * \file - * Driver for the retrieval of an BLE address from flash + * \addtogroup cc13xx-cc26xx-rf + * @{ * + * \defgroup cc13xx-cc26xx-rf-ble-addr Driver for CC13xx/CC26xx BLE addresses + * + * @{ + * + * \file + * Header file for the CC13xx/CC26xx BLE address driver. * \author - * Michael Spoerk + * Michael Spoerk + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #ifndef BLE_ADDR_H_ @@ -44,6 +49,12 @@ #include /*---------------------------------------------------------------------------*/ +/** + * \brief Retrieve the pointer to where the BLE address is stored. + * + * This function will return the primary address from info page, unless a + * valid address is found in the secondary address from CCFG. + */ uint8_t* ble_addr_ptr(void); /*---------------------------------------------------------------------------*/ /** diff --git a/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c b/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c index ea56af9e5..7924693a8 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c +++ b/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c @@ -1,6 +1,5 @@ /* - * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ - * Copyright (c) 2017, University of Bristol - http://www.bristol.ac.uk/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,22 +27,23 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup rf-core-ble + * \addtogroup cc13xx-cc26xx-rf-ble * @{ * * \file - * Implementation of the CC13xx/CC26xx RF BLE driver + * Implementation for the CC13xx/CC26xx BLE Beacon Daemon. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #include "contiki.h" -#include "sys/process.h" -#include "sys/clock.h" #include "sys/cc.h" +#include "sys/clock.h" #include "sys/etimer.h" -#include "net/netstack.h" +#include "sys/process.h" #include "net/linkaddr.h" +#include "net/netstack.h" /*---------------------------------------------------------------------------*/ #include #include DeviceFamily_constructPath(driverlib/chipinfo.h) @@ -155,7 +155,7 @@ rf_ble_beacond_init(void) ble_beacond.handle = ble_open(&rf_params); - if (ble_beacond.handle == NULL) { + if(ble_beacond.handle == NULL) { return RF_BLE_BEACOND_ERROR; } @@ -165,11 +165,11 @@ rf_ble_beacond_init(void) rf_ble_beacond_result_t rf_ble_beacond_start(clock_time_t interval, const char *name) { - if (interval == 0) { + if(interval == 0) { return RF_BLE_BEACOND_ERROR; } - if (name == NULL) { + if(name == NULL) { return RF_BLE_BEACOND_ERROR; } @@ -177,7 +177,7 @@ rf_ble_beacond_start(clock_time_t interval, const char *name) const size_t name_len = strlen(name); - if ((name_len == 0) || + if((name_len == 0) || (name_len >= BLE_ADV_NAME_BUF_LEN)) { return RF_BLE_BEACOND_ERROR; } @@ -213,7 +213,7 @@ rf_ble_set_tx_power(int8_t dBm) { rf_result_t res; - if (!TX_POWER_IN_RANGE(dBm)) { + if(!TX_POWER_IN_RANGE(dBm)) { return RADIO_RESULT_INVALID_VALUE; } @@ -232,7 +232,7 @@ rf_ble_get_tx_power(void) int8_t dbm; res = rf_get_tx_power(ble_beacond.rf_handle, TX_POWER_TABLE, &dbm) - if (res != RF_RESULT_OK) { + if(res != RF_RESULT_OK) { return ~(int8_t)0; } @@ -245,9 +245,9 @@ ble_beacon_burst(uint8_t channels_bm, uint8_t *data, uint8_t len) rf_result_t res; uint8_t channel; - for (channel = BLE_ADV_CHANNEL_MIN; channel <= BLE_ADV_CHANNEL_MAX; ++channel) { + for(channel = BLE_ADV_CHANNEL_MIN; channel <= BLE_ADV_CHANNEL_MAX; ++channel) { const uint8_t channel_bv = (1 << (channel - BLE_ADV_CHANNEL_MIN)); - if ((channel_bv & channels_bm) == 0) { + if((channel_bv & channels_bm) == 0) { continue; } @@ -258,7 +258,7 @@ ble_beacon_burst(uint8_t channels_bm, uint8_t *data, uint8_t len) res = ble_sched_beacon(NULL, 0); - if (res != RF_RESULT_OK) { + if(res != RF_RESULT_OK) { return RF_BLE_BEACOND_ERROR; } } @@ -332,7 +332,4 @@ rf_ble_get_tx_power(void) { return ~(int8_t)(0); } /*---------------------------------------------------------------------------*/ #endif /* RF_BLE_BEACON_ENABLE */ /*---------------------------------------------------------------------------*/ -/** - * @} - * @} - */ +/** @} */ diff --git a/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.h b/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.h index da672b800..f97927ff5 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.h +++ b/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.h @@ -1,6 +1,5 @@ /* - * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ - * Copyright (c) 2017, University of Bristol - http://www.bristol.ac.uk/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,24 +27,25 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup rf-core + * \addtogroup cc13xx-cc26xx-rf * @{ * - * \defgroup rf-core-ble CC13xx/CC26xx BLE driver + * \defgroup cc13xx-cc26xx-rf-ble CC13xx/CC26xx BLE Beacon Daemon * * @{ * * \file - * Header file for the CC13xx/CC26xx BLE driver + * Header file for the CC13xx/CC26xx BLE Beacon Daemon. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #ifndef RF_BLE_BEACOND_H_ #define RF_BLE_BEACOND_H_ /*---------------------------------------------------------------------------*/ #include "contiki.h" - +/*---------------------------------------------------------------------------*/ #include /*---------------------------------------------------------------------------*/ typedef enum { @@ -53,6 +53,7 @@ typedef enum { RF_BLE_BEACOND_ERROR, RF_BLE_BEACOND_DISABLED, } rf_ble_beacond_result_t; +/*---------------------------------------------------------------------------*/ /** * \brief Set the device name to use with the BLE advertisement/beacon daemon * \param interval The interval (ticks) between two consecutive beacon bursts @@ -65,7 +66,7 @@ typedef enum { rf_ble_beacond_result_t rf_ble_beacond_init(void); /** - * \brief Start the BLE advertisement/beacon daemon + * \brief Start the BLE advertisement/beacon daemon * \return RF_CORE_CMD_OK: Success, RF_CORE_CMD_ERROR: Failure * * Before calling this function, the name to advertise must first be set by @@ -99,8 +100,8 @@ int8_t rf_ble_is_active(void); rf_ble_beacond_result_t rf_ble_set_tx_power(int8_t dbm); /** - * \brief Get TX power for BLE advertisements - * \return The TX power for BLE advertisements + * \brief Get TX power for BLE advertisements + * \return The TX power for BLE advertisements */ int8_t rf_ble_get_tx_power(void); /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf/data-queue.c b/arch/cpu/cc13xx-cc26xx/rf/data-queue.c index 8b34569f1..06d57bd71 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/data-queue.c +++ b/arch/cpu/cc13xx-cc26xx/rf/data-queue.c @@ -27,13 +27,14 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup simplelink + * \addtogroup cc13xx-cc26xx-rf-data-queue * @{ * * \file - * Implementation of common CC13xx/CC26xx RF functionality + * Implementation of the CC13xx/CC26xx RF data queue. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #include "contiki.h" @@ -75,9 +76,11 @@ static rx_data_queue_t rx_data_queue; static void rx_bufs_init(void) { + data_entry_t *data_entry; size_t i; - for (i = 0; i < RX_BUF_CNT; ++i) { - data_entry_t *const data_entry = &(rx_data_queue.bufs[i].data_entry); + + for(i = 0; i < RX_BUF_CNT; ++i) { + data_entry = &(rx_data_queue.bufs[i].data_entry); data_entry->status = DATA_ENTRY_PENDING; data_entry->config.type = DATA_ENTRY_TYPE_GEN; @@ -94,7 +97,7 @@ static void rx_bufs_reset(void) { size_t i; - for (i = 0; i < RX_BUF_CNT; ++i) { + for(i = 0; i < RX_BUF_CNT; ++i) { data_entry_t *const data_entry = &(rx_data_queue.bufs[i].data_entry); /* Clear length bytes */ @@ -155,3 +158,4 @@ data_queue_release_entry(void) rx_data_queue.curr_entry = (data_entry_t*)(curr_entry->pNextEntry); } /*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/arch/cpu/cc13xx-cc26xx/rf/data-queue.h b/arch/cpu/cc13xx-cc26xx/rf/data-queue.h index 9a95f2f5d..c0b6913a8 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/data-queue.h +++ b/arch/cpu/cc13xx-cc26xx/rf/data-queue.h @@ -27,6 +27,19 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + * \addtogroup cc13xx-cc26xx-rf + * @{ + * + * \defgroup cc13xx-cc26xx-rf-data-queue RF data queue for CC13xx/CC26xx + * + * @{ + * + * \file + * Header file of the CC13xx/CC26xx RF data queue. + * \author + * Edvard Pettersen + */ /*---------------------------------------------------------------------------*/ #ifndef RF_DATA_QUEUE_H_ #define RF_DATA_QUEUE_H_ @@ -43,12 +56,13 @@ typedef dataQueue_t data_queue_t; typedef rfc_dataEntryGeneral_t data_entry_t; /*---------------------------------------------------------------------------*/ data_queue_t* data_queue_init(size_t lensz); -/*---------------------------------------------------------------------------*/ -void data_queue_reset(void); -/*---------------------------------------------------------------------------*/ +void data_queue_reset(void); data_entry_t* data_queue_current_entry(void); -/*---------------------------------------------------------------------------*/ -void data_queue_release_entry(void); +void data_queue_release_entry(void); /*---------------------------------------------------------------------------*/ #endif /* RF_DATA_QUEUE_H_ */ /*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/cpu/cc13xx-cc26xx/rf/dot-15-4g.h b/arch/cpu/cc13xx-cc26xx/rf/dot-15-4g.h index bb99d39c4..d0bf42722 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/dot-15-4g.h +++ b/arch/cpu/cc13xx-cc26xx/rf/dot-15-4g.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,18 +27,19 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup rf-core + * \addtogroup cc13xx-cc26xx-rf * @{ * - * \defgroup rf-core-15-4g-modes IEEE 802.15.4g Frequency Bands and Modes + * \defgroup cc13xx-cc26xx-rf-15-4g-modes IEEE 802.15.4g Frequency Bands and Modes * * @{ * * \file - * Header file with descriptors for the various modes of operation defined in - * IEEE 802.15.4g + * Header file with descriptors for the various modes of operation + * defined in IEEE 802.15.4g. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #ifndef DOT_15_4G_H_ @@ -149,19 +150,19 @@ static inline uint32_t dot_15_4g_freq(const uint16_t chan) { - const uint32_t chan0 = DOT_15_4G_CHAN0_FREQ; - const uint32_t spacing = DOT_15_4G_FREQ_SPACING; - const uint32_t chan_min = DOT_15_4G_CHAN_MIN; - return (chan0 + spacing * ((uint32_t)chan - chan_min)); + const uint32_t chan0 = DOT_15_4G_CHAN0_FREQ; + const uint32_t spacing = DOT_15_4G_FREQ_SPACING; + const uint32_t chan_min = DOT_15_4G_CHAN_MIN; + return (chan0 + spacing * ((uint32_t)chan - chan_min)); } /*---------------------------------------------------------------------------*/ static inline bool dot_15_4g_chan_in_range(const uint16_t chan) { - const uint16_t chan_min = DOT_15_4G_CHAN_MIN; - const uint16_t chan_max = DOT_15_4G_CHAN_MAX; - return ((chan >= chan_min) && - (chan <= chan_max)); + const uint16_t chan_min = DOT_15_4G_CHAN_MIN; + const uint16_t chan_max = DOT_15_4G_CHAN_MAX; + return ((chan >= chan_min) && + (chan <= chan_max)); } /*---------------------------------------------------------------------------*/ #define DOT_15_4G_DEFAULT_CHAN IEEE802154_DEFAULT_CHANNEL diff --git a/arch/cpu/cc13xx-cc26xx/rf/ieee-addr.c b/arch/cpu/cc13xx-cc26xx/rf/ieee-addr.c index 25aacc63b..bdea2782e 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/ieee-addr.c +++ b/arch/cpu/cc13xx-cc26xx/rf/ieee-addr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -10,7 +10,6 @@ * 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. @@ -28,13 +27,14 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup cc26xx-ieee-addr + * \addtogroup cc13xx-cc26xx-rf-ieee-addr * @{ * * \file - * Driver for the CC13xx/CC26xx IEEE addresses + * Implementation of the CC13xx/CC26xx IEEE addresses driver. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #include "contiki.h" @@ -50,22 +50,23 @@ #include #include /*---------------------------------------------------------------------------*/ +#define IEEE_ADDR_HARDCODED IEEE_ADDR_CONF_HARDCODED +#define IEEE_ADDR_ADDRESS IEEE_ADDR_CONF_ADDRESS +/*---------------------------------------------------------------------------*/ #define IEEE_MAC_PRIMARY_ADDRESS (FCFG1_BASE + FCFG1_O_MAC_15_4_0) #define IEEE_MAC_SECONDARY_ADDRESS (CCFG_BASE + CCFG_O_IEEE_MAC_0) /*---------------------------------------------------------------------------*/ -#define IEEE_ADDR_SIZE 8 -/*---------------------------------------------------------------------------*/ int ieee_addr_cpy_to(uint8_t *dst, uint8_t len) { - if (len > IEEE_ADDR_SIZE) { + if(len > LINKADDR_SIZE) { return -1; } - if(IEEE_ADDR_CONF_HARDCODED) { - const uint8_t ieee_addr_hc[IEEE_ADDR_SIZE] = IEEE_ADDR_CONF_ADDRESS; + if(IEEE_ADDR_HARDCODED) { + const uint8_t ieee_addr_hc[LINKADDR_SIZE] = IEEE_ADDR_ADDRESS; - memcpy(dst, &ieee_addr_hc[IEEE_ADDR_SIZE - len], len); + memcpy(dst, &ieee_addr_hc[LINKADDR_SIZE - len], len); } else { int i; @@ -76,13 +77,13 @@ ieee_addr_cpy_to(uint8_t *dst, uint8_t len) volatile const uint8_t *ieee_addr = primary; /* - * ...unless we can find a byte != 0xFF in secondary + * ...unless we can find a byte != 0xFF in secondary. * * Intentionally checking all 8 bytes here instead of len, because we - * are checking validity of the entire address irrespective of the + * are checking validity of the entire address respective of the * actual number of bytes the caller wants to copy over. */ - for(i = 0; i < IEEE_ADDR_SIZE; i++) { + for(i = 0; i < len; i++) { if(secondary[i] != 0xFF) { /* A byte in the secondary location is not 0xFF. Use the secondary */ ieee_addr = secondary; @@ -92,7 +93,7 @@ ieee_addr_cpy_to(uint8_t *dst, uint8_t len) /* * We have chosen what address to read the address from. Do so, - * inverting byte order + * in inverted byte order. */ for(i = 0; i < len; i++) { dst[i] = ieee_addr[len - 1 - i]; diff --git a/arch/cpu/cc13xx-cc26xx/rf/ieee-addr.h b/arch/cpu/cc13xx-cc26xx/rf/ieee-addr.h index 167b75623..dc649cdd1 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/ieee-addr.h +++ b/arch/cpu/cc13xx-cc26xx/rf/ieee-addr.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -10,7 +10,6 @@ * 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. @@ -28,14 +27,13 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup cc26xx + * \addtogroup cc13xx-cc26xx-cpu * @{ * - * \defgroup cc26xx-ieee-addr CC13xx/CC26xx IEEE Address Control + * \defgroup cc13xx-cc26xx-rf-ieee-addr CC13xx/CC26xx IEEE Address Control * - * Driver for the retrieval of an IEEE address from flash + * Driver for the retrieval of an IEEE address from flash. * * The user can specify a hardcoded IEEE address through the * IEEE_ADDR_CONF_HARDCODED configuration macro. @@ -57,8 +55,9 @@ * @{ * * \file - * Header file with register and macro declarations for the cc26xx IEEE address - * driver + * Header file for the CC13xx/CC26xx IEEE address driver. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #ifndef IEEE_ADDR_H_ @@ -67,15 +66,15 @@ #include "contiki.h" /*---------------------------------------------------------------------------*/ /** - * \brief Copy the node's IEEE address to a destination memory area - * \param dst A pointer to the destination area where the IEEE address is to be - * written - * \param len The number of bytes to write to destination area + * \brief Copy the device's IEEE address to a destination buffer. + * \param dst A pointer to the destination area where the IEEE address is to + * be written. + * \param len The number of bytes to write to destination area * \return 0 : Returned successfully * -1 : Returned with error * - * This function will copy \e len LS bytes and it will invert byte order in - * the process. The factory address on devices is normally little-endian, + * This function will copy \p len bytes in LSB and it will invert byte order + * in the process. The factory address on devices is normally little-endian, * therefore you should expect dst to store the address in a big-endian order. */ int ieee_addr_cpy_to(uint8_t *dst, uint8_t len); diff --git a/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c b/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c index 449eb3d6a..c39699c5f 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c +++ b/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c @@ -27,17 +27,18 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup rf-core + * \addtogroup cc13xx-cc26xx-rf * @{ * - * \defgroup rf-core-ieee CC13xx/CC26xx IEEE mode driver + * \defgroup cc13xx-cc26xx-rf-ieee IEEE-mode driver for CC13xx/CC26xx * * @{ * * \file - * Implementation of the CC13xx/CC26xx IEEE mode NETSTACK_RADIO driver + * Implementation of the CC13xx/CC26xx IEEE-mode NETSTACK_RADIO driver. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #include "contiki.h" @@ -300,7 +301,7 @@ init_rf_params(void) static rf_result_t set_channel(uint8_t channel) { - if (!dot_15_4g_chan_in_range(channel)) { + if(!dot_15_4g_chan_in_range(channel)) { PRINTF("set_channel: illegal channel %d, defaults to %d\n", (int)channel, DOT_15_4G_DEFAULT_CHAN); channel = DOT_15_4G_DEFAULT_CHAN; @@ -311,7 +312,7 @@ set_channel(uint8_t channel) * set_channel() to cause a synth calibration, since channel must be in * range 11-26. */ - if (channel == cmd_rx.channel) { + if(channel == cmd_rx.channel) { /* We are already calibrated to this channel */ return true; } @@ -342,7 +343,7 @@ check_rat_overflow(void) { const bool was_off = !rx_is_active(); - if (was_off) { + if(was_off) { RF_runDirectCmd(ieee_radio.rf_handle, CMD_NOP); } @@ -351,12 +352,12 @@ check_rat_overflow(void) static bool initial_iteration = true; static uint32_t last_value; - if (initial_iteration) { + if(initial_iteration) { /* First time checking overflow will only store the current value */ initial_iteration = false; } else { /* Overflow happens in the last quarter of the RAT range */ - if ((current_value + RAT_ONE_QUARTER) < last_value) { + if((current_value + RAT_ONE_QUARTER) < last_value) { /* Overflow detected */ ieee_radio.rat.last_overflow = RTIMER_NOW(); ieee_radio.rat.overflow_count += 1; @@ -365,7 +366,7 @@ check_rat_overflow(void) last_value = current_value; - if (was_off) { + if(was_off) { RF_yield(ieee_radio.rf_handle); } } @@ -379,9 +380,9 @@ rat_to_timestamp(const uint32_t rat_ticks) /* If the timestamp is in the 4th quarter and the last overflow was recently, * assume that the timestamp refers to the time before the overflow */ - if (rat_ticks > RAT_THREE_QUARTERS) { + if(rat_ticks > RAT_THREE_QUARTERS) { const rtimer_clock_t one_quarter = (RAT_ONE_QUARTER * RTIMER_SECOND) / RAT_SECOND; - if (RTIMER_CLOCK_LT(RTIMER_NOW(), ieee_radio.rat.last_overflow + one_quarter)) { + if(RTIMER_CLOCK_LT(RTIMER_NOW(), ieee_radio.rat.last_overflow + one_quarter)) { adjusted_overflow_count -= 1; } } @@ -396,7 +397,7 @@ rat_to_timestamp(const uint32_t rat_ticks) static int init(void) { - if (ieee_radio.rf_handle) { + if(ieee_radio.rf_handle) { PRINTF("init: Radio already initialized\n"); return RF_RESULT_OK; } @@ -413,7 +414,7 @@ init(void) ieee_radio.rf_handle = netstack_open(&rf_params); - if (ieee_radio.rf_handle == NULL) { + if(ieee_radio.rf_handle == NULL) { PRINTF("init: unable to open IEEE RF driver\n"); return RF_RESULT_ERROR; } @@ -450,7 +451,7 @@ transmit(unsigned short transmit_len) { rf_result_t res; - if (ieee_radio.send_on_cca && channel_clear() != 1) { + if(ieee_radio.send_on_cca && channel_clear() != 1) { PRINTF("transmit: channel wasn't clear\n"); return RADIO_TX_COLLISION; } @@ -460,7 +461,7 @@ transmit(unsigned short transmit_len) * Control Field byte, that is the first byte in the frame. */ const bool ack_request = (bool)(ieee_radio.tx_buf[FRAME_FCF_OFFSET] & FRAME_ACK_REQUEST); - if (ack_request) { + if(ack_request) { /* Yes, turn on chaining */ cmd_tx.condition.rule = COND_STOP_ON_FALSE; @@ -479,11 +480,11 @@ transmit(unsigned short transmit_len) res = netstack_sched_ieee_tx(ack_request); - if (res != RF_RESULT_OK) { + if(res != RF_RESULT_OK) { return RADIO_TX_ERR; } - if (ack_request) { + if(ack_request) { switch(cmd_rx_ack.status) { /* CMD_IEEE_RX_ACK timed out, i.e. never received ACK */ case IEEE_DONE_TIMEOUT: return RADIO_TX_NOACK; @@ -513,10 +514,10 @@ read(void *buf, unsigned short buf_len) const rtimer_clock_t t0 = RTIMER_NOW(); /* Only wait if the Radio timer is accessing the entry */ - while ((data_entry->status == DATA_ENTRY_BUSY) && + while((data_entry->status == DATA_ENTRY_BUSY) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + TIMEOUT_DATA_ENTRY_BUSY)); - if (data_entry->status != DATA_ENTRY_FINISHED) { + if(data_entry->status != DATA_ENTRY_FINISHED) { /* No available data */ return -1; } @@ -545,7 +546,7 @@ read(void *buf, unsigned short buf_len) const lensz_t frame_len = *(lensz_t*)frame_ptr; /* Sanity check that Frame is at least Frame Shave bytes long */ - if (frame_len < FRAME_SHAVE) { + if(frame_len < FRAME_SHAVE) { PRINTF("read: frame too short len=%d\n", frame_len); data_queue_release_entry(); @@ -556,7 +557,7 @@ read(void *buf, unsigned short buf_len) const unsigned short payload_len = (unsigned short)(frame_len - FRAME_SHAVE); /* Sanity check that Payload fits in Buffer */ - if (payload_len > buf_len) { + if(payload_len > buf_len) { PRINTF("read: payload too large for buffer len=%d buf_len=%d\n", payload_len, buf_len); data_queue_release_entry(); @@ -573,7 +574,7 @@ read(void *buf, unsigned short buf_len) const uint32_t rat_ticks = *(uint32_t*)(payload_ptr + payload_len + 4); ieee_radio.last.timestamp = rat_to_timestamp(rat_ticks); - if (!ieee_radio.poll_mode) { + if(!ieee_radio.poll_mode) { /* Not in poll mode: packetbuf should not be accessed in interrupt context. */ /* In poll mode, the last packet RSSI and link quality can be obtained through */ /* RADIO_PARAM_LAST_RSSI and RADIO_PARAM_LAST_LINK_QUALITY */ @@ -592,23 +593,23 @@ cca_request(cmd_cca_req_t *cmd_cca_req) const bool rx_is_idle = !rx_is_active(); - if (rx_is_idle) { + if(rx_is_idle) { res = netstack_sched_rx(false); - if (res != RF_RESULT_OK) { + if(res != RF_RESULT_OK) { return RF_RESULT_ERROR; } } const rtimer_clock_t t0 = RTIMER_NOW(); - while ((cmd_rx.status != ACTIVE) && + while((cmd_rx.status != ACTIVE) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + TIMEOUT_ENTER_RX_WAIT)); RF_Stat stat = RF_StatRadioInactiveError; - if (rx_is_active()) { + if(rx_is_active()) { stat = RF_runImmediateCmd(ieee_radio.rf_handle, (uint32_t*)&cmd_cca_req); } - if (rx_is_idle) { + if(rx_is_idle) { netstack_stop_rx(); } @@ -624,7 +625,7 @@ channel_clear(void) memset(&cmd_cca_req, 0x0, sizeof(cmd_cca_req_t)); cmd_cca_req.commandNo = CMD_IEEE_CCA_REQ; - if (cca_request(&cmd_cca_req) != RF_RESULT_OK) { + if(cca_request(&cmd_cca_req) != RF_RESULT_OK) { return 0; } @@ -639,12 +640,12 @@ receiving_packet(void) memset(&cmd_cca_req, 0x0, sizeof(cmd_cca_req_t)); cmd_cca_req.commandNo = CMD_IEEE_CCA_REQ; - if (cca_request(&cmd_cca_req) != RF_RESULT_OK) { + if(cca_request(&cmd_cca_req) != RF_RESULT_OK) { return 0; } /* If we are transmitting (can only be an ACK here), we are not receiving */ - if ((cmd_cca_req.ccaInfo.ccaEnergy == CCA_STATE_BUSY) && + if((cmd_cca_req.ccaInfo.ccaEnergy == CCA_STATE_BUSY) && (cmd_cca_req.ccaInfo.ccaCorr == CCA_STATE_BUSY) && (cmd_cca_req.ccaInfo.ccaSync == CCA_STATE_BUSY)) { PRINTF("receiving_packet: we were TXing ACK\n"); @@ -666,16 +667,16 @@ pending_packet(void) /* Go through RX Circular buffer and check each data entry status */ do { const uint8_t status = curr_entry->status; - if ((status == DATA_ENTRY_FINISHED) || + if((status == DATA_ENTRY_FINISHED) || (status == DATA_ENTRY_BUSY)) { num_pending += 1; } /* Stop when we have looped the circular buffer */ curr_entry = (data_entry_t *)curr_entry->pNextEntry; - } while (curr_entry != read_entry); + } while(curr_entry != read_entry); - if ((num_pending > 0) && !ieee_radio.poll_mode) { + if((num_pending > 0) && !ieee_radio.poll_mode) { process_poll(&rf_sched_process); } @@ -688,7 +689,7 @@ on(void) { rf_result_t res; - if (ieee_radio.rf_is_on) { + if(ieee_radio.rf_is_on) { PRINTF("on: Radio already on\n"); return RF_RESULT_OK; } @@ -697,7 +698,7 @@ on(void) res = netstack_sched_rx(true); - if (res != RF_RESULT_OK) { + if(res != RF_RESULT_OK) { return RF_RESULT_ERROR; } @@ -708,7 +709,7 @@ on(void) static int off(void) { - if (!ieee_radio.rf_is_on) { + if(!ieee_radio.rf_is_on) { PRINTF("off: Radio already off\n"); return RF_RESULT_OK; } @@ -724,7 +725,7 @@ get_value(radio_param_t param, radio_value_t *value) { rf_result_t res; - if (!value) { + if(!value) { return RADIO_RESULT_INVALID_VALUE; } @@ -755,13 +756,13 @@ get_value(radio_param_t param, radio_value_t *value) /* RX mode */ case RADIO_PARAM_RX_MODE: *value = 0; - if (cmd_rx.frameFiltOpt.frameFiltEn) { + if(cmd_rx.frameFiltOpt.frameFiltEn) { *value |= (radio_value_t)RADIO_RX_MODE_ADDRESS_FILTER; } - if (cmd_rx.frameFiltOpt.autoAckEn) { + if(cmd_rx.frameFiltOpt.autoAckEn) { *value |= (radio_value_t)RADIO_RX_MODE_AUTOACK; } - if (ieee_radio.poll_mode) { + if(ieee_radio.poll_mode) { *value |= (radio_value_t)RADIO_RX_MODE_POLL_MODE; } return RADIO_RESULT_OK; @@ -835,12 +836,12 @@ set_value(radio_param_t param, radio_value_t value) /* Power Mode */ case RADIO_PARAM_POWER_MODE: - if (value == RADIO_POWER_MODE_ON) { + if(value == RADIO_POWER_MODE_ON) { return (on() == RF_RESULT_OK) ? RADIO_RESULT_OK : RADIO_RESULT_ERROR; - } else if (value == RADIO_POWER_MODE_OFF) { + } else if(value == RADIO_POWER_MODE_OFF) { off(); return RADIO_RESULT_OK; } @@ -849,7 +850,7 @@ set_value(radio_param_t param, radio_value_t value) /* Channel */ case RADIO_PARAM_CHANNEL: - if (!dot_15_4g_chan_in_range(value)) { + if(!dot_15_4g_chan_in_range(value)) { return RADIO_RESULT_INVALID_VALUE; } set_channel((uint8_t)value); @@ -858,7 +859,7 @@ set_value(radio_param_t param, radio_value_t value) /* PAN ID */ case RADIO_PARAM_PAN_ID: cmd_rx.localPanID = (uint16_t)value; - if (!ieee_radio.rf_is_on) { + if(!ieee_radio.rf_is_on) { return RADIO_RESULT_OK; } @@ -871,7 +872,7 @@ set_value(radio_param_t param, radio_value_t value) /* 16bit address */ case RADIO_PARAM_16BIT_ADDR: cmd_rx.localShortAddr = (uint16_t)value; - if (!ieee_radio.rf_is_on) { + if(!ieee_radio.rf_is_on) { return RADIO_RESULT_OK; } @@ -883,7 +884,7 @@ set_value(radio_param_t param, radio_value_t value) /* RX Mode */ case RADIO_PARAM_RX_MODE: { - if (value & ~(RADIO_RX_MODE_ADDRESS_FILTER | + if(value & ~(RADIO_RX_MODE_ADDRESS_FILTER | RADIO_RX_MODE_AUTOACK | RADIO_RX_MODE_POLL_MODE)) { return RADIO_RESULT_INVALID_VALUE; } @@ -900,17 +901,17 @@ set_value(radio_param_t param, radio_value_t value) const bool old_poll_mode = ieee_radio.poll_mode; ieee_radio.poll_mode = (value & RADIO_RX_MODE_POLL_MODE) != 0; - if (old_poll_mode == ieee_radio.poll_mode) { + if(old_poll_mode == ieee_radio.poll_mode) { /* Do not turn the radio off and on, just send an update command */ memcpy(&cmd_mod_filt.newFrameFiltOpt, &(rf_cmd_ieee_rx.frameFiltOpt), sizeof(rf_cmd_ieee_rx.frameFiltOpt)); const RF_Stat stat = RF_runImmediateCmd(ieee_radio.rf_handle, (uint32_t*)&cmd_mod_filt); - if (stat != RF_StatCmdDoneSuccess) { + if(stat != RF_StatCmdDoneSuccess) { PRINTF("setting address filter failed: stat=0x%02X\n", stat); return RADIO_RESULT_ERROR; } return RADIO_RESULT_OK; } - if (!ieee_radio.rf_is_on) { + if(!ieee_radio.rf_is_on) { return RADIO_RESULT_OK; } @@ -931,7 +932,7 @@ set_value(radio_param_t param, radio_value_t value) /* TX Power */ case RADIO_PARAM_TXPOWER: - if (!TX_POWER_IN_RANGE((int8_t)value)) { + if(!TX_POWER_IN_RANGE((int8_t)value)) { return RADIO_RESULT_INVALID_VALUE; } res = rf_set_tx_power(ieee_radio.rf_handle, TX_POWER_TABLE, (int8_t)value); @@ -942,7 +943,7 @@ set_value(radio_param_t param, radio_value_t value) /* CCA Threshold */ case RADIO_PARAM_CCA_THRESHOLD: cmd_rx.ccaRssiThr = (int8_t)value; - if (!ieee_radio.rf_is_on) { + if(!ieee_radio.rf_is_on) { return RADIO_RESULT_OK; } @@ -960,7 +961,7 @@ set_value(radio_param_t param, radio_value_t value) static radio_result_t get_object(radio_param_t param, void *dest, size_t size) { - if (!dest) { + if(!dest) { return RADIO_RESULT_INVALID_VALUE; } @@ -1000,7 +1001,7 @@ set_object(radio_param_t param, const void *src, size_t size) { rf_result_t res; - if (!src) { + if(!src) { return RADIO_RESULT_INVALID_VALUE; } @@ -1008,17 +1009,17 @@ set_object(radio_param_t param, const void *src, size_t size) /* 64-bit address */ case RADIO_PARAM_64BIT_ADDR: { const size_t destSize = sizeof(cmd_rx.localExtAddr); - if (size != destSize) { + if(size != destSize) { return RADIO_RESULT_INVALID_VALUE; } const uint8_t *pSrc = (const uint8_t *)src; volatile uint8_t *pDest = (uint8_t *)&(cmd_rx.localExtAddr); - for (size_t i = 0; i < destSize; ++i) { + for(size_t i = 0; i < destSize; ++i) { pDest[i] = pSrc[destSize - 1 - i]; } - if (!rx_is_active()) { + if(!rx_is_active()) { return RADIO_RESULT_OK; } diff --git a/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c b/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c index d7b25eda2..9ac48aa8f 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c +++ b/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c @@ -27,13 +27,18 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup rf-core-prop + * \addtogroup cc13xx-cc26xx-rf + * @{ + * + * \defgroup cc13xx-cc26xx-rf-prop Prop-mode driver for CC13xx/CC26xx + * * @{ * * \file - * Implementation of the CC13xx prop mode NETSTACK_RADIO driver + * Implementation of the CC13xx/CC26xx prop-mode NETSTACK_RADIO driver. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #include "contiki.h" @@ -218,23 +223,23 @@ get_rssi(void) const bool rx_is_idle = !rx_is_active(); - if (rx_is_idle) { + if(rx_is_idle) { res = netstack_sched_rx(false); - if (res != RF_RESULT_OK) { + if(res != RF_RESULT_OK) { return RF_GET_RSSI_ERROR_VAL; } } const rtimer_clock_t t0 = RTIMER_NOW(); - while ((cmd_rx.status != ACTIVE) && + while((cmd_rx.status != ACTIVE) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + TIMEOUT_ENTER_RX_WAIT)); int8_t rssi = RF_GET_RSSI_ERROR_VAL; - if (rx_is_active()) { + if(rx_is_active()) { rssi = RF_getRssi(prop_radio.rf_handle); } - if (rx_is_idle) { + if(rx_is_idle) { netstack_stop_rx(); } @@ -262,13 +267,13 @@ set_channel(uint16_t channel) { rf_result_t res; - if (!dot_15_4g_chan_in_range(channel)) { + if(!dot_15_4g_chan_in_range(channel)) { PRINTF("set_channel: illegal channel %d, defaults to %d\n", (int)channel, DOT_15_4G_DEFAULT_CHAN); channel = DOT_15_4G_DEFAULT_CHAN; } - if (channel == prop_radio.channel) { + if(channel == prop_radio.channel) { /* We are already calibrated to this channel */ return RF_RESULT_OK; } @@ -285,7 +290,7 @@ set_channel(uint16_t channel) res = netstack_sched_fs(); - if (res != RF_RESULT_OK) { + if(res != RF_RESULT_OK) { return res; } @@ -327,7 +332,7 @@ transmit(unsigned short transmit_len) { rf_result_t res; - if (tx_is_active()) { + if(tx_is_active()) { PRINTF("transmit: not allowed while transmitting\n"); return RADIO_TX_ERR; } @@ -371,10 +376,10 @@ read(void *buf, unsigned short buf_len) const rtimer_clock_t t0 = RTIMER_NOW(); /* Only wait if the Radio is accessing the entry */ - while ((data_entry->status == DATA_ENTRY_BUSY) && + while((data_entry->status == DATA_ENTRY_BUSY) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + TIMEOUT_DATA_ENTRY_BUSY)); - if (data_entry->status != DATA_ENTRY_FINISHED) { + if(data_entry->status != DATA_ENTRY_FINISHED) { /* No available data */ return -1; } @@ -404,7 +409,7 @@ read(void *buf, unsigned short buf_len) const lensz_t frame_len = *(lensz_t*)frame_ptr; /* Sanity check that Frame is at least Frame Shave bytes long */ - if (frame_len < FRAME_SHAVE) { + if(frame_len < FRAME_SHAVE) { PRINTF("read: frame too short len=%d\n", frame_len); data_queue_release_entry(); @@ -415,7 +420,7 @@ read(void *buf, unsigned short buf_len) const unsigned short payload_len = (unsigned short)(frame_len - FRAME_SHAVE); /* Sanity check that Payload fits in Buffer */ - if (payload_len > buf_len) { + if(payload_len > buf_len) { PRINTF("read: payload too large for buffer len=%d buf_len=%d\n", payload_len, buf_len); data_queue_release_entry(); @@ -441,7 +446,7 @@ cca_request(void) { const int8_t rssi = get_rssi(); - if (rssi == RF_GET_RSSI_ERROR_VAL) { + if(rssi == RF_GET_RSSI_ERROR_VAL) { return CCA_STATE_INVALID; } @@ -453,7 +458,7 @@ cca_request(void) static int channel_clear(void) { - if (tx_is_active()) { + if(tx_is_active()) { PRINTF("channel_clear: called while in TX\n"); return 0; } @@ -467,7 +472,7 @@ channel_clear(void) static int receiving_packet(void) { - if (!rx_is_active()) { + if(!rx_is_active()) { return 0; } @@ -487,16 +492,16 @@ pending_packet(void) /* Go through RX Circular buffer and check their status */ do { const uint8_t status = curr_entry->status; - if ((status == DATA_ENTRY_FINISHED) || + if((status == DATA_ENTRY_FINISHED) || (status == DATA_ENTRY_BUSY)) { num_pending += 1; } /* Stop when we have looped the circular buffer */ curr_entry = (data_entry_t *)curr_entry->pNextEntry; - } while (curr_entry != read_entry); + } while(curr_entry != read_entry); - if (num_pending > 0) { + if(num_pending > 0) { process_poll(&rf_sched_process); } @@ -509,7 +514,7 @@ on(void) { rf_result_t res; - if (prop_radio.rf_is_on) { + if(prop_radio.rf_is_on) { PRINTF("on: Radio already on\n"); return RF_RESULT_OK; } @@ -518,7 +523,7 @@ on(void) res = netstack_sched_rx(true); - if (res != RF_RESULT_OK) { + if(res != RF_RESULT_OK) { return RF_RESULT_ERROR; } @@ -529,7 +534,7 @@ on(void) static int off(void) { - if (!prop_radio.rf_is_on) { + if(!prop_radio.rf_is_on) { PRINTF("off: Radio already off\n"); return RF_RESULT_OK; } @@ -545,7 +550,7 @@ get_value(radio_param_t param, radio_value_t *value) { rf_result_t res; - if (!value) { + if(!value) { return RADIO_RESULT_INVALID_VALUE; } @@ -627,7 +632,7 @@ set_value(radio_param_t param, radio_value_t value) : RADIO_RESULT_ERROR; case RADIO_PARAM_TXPOWER: - if (!TX_POWER_IN_RANGE((int8_t)value)) { + if(!TX_POWER_IN_RANGE((int8_t)value)) { return RADIO_RESULT_INVALID_VALUE; } res = rf_set_tx_power(prop_radio.rf_handle, TX_POWER_TABLE, (int8_t)value); @@ -662,7 +667,7 @@ set_object(radio_param_t param, const void *src, size_t size) static int init(void) { - if (prop_radio.rf_handle) { + if(prop_radio.rf_handle) { PRINTF("init: Radio already initialized\n"); return RF_RESULT_OK; } @@ -683,7 +688,7 @@ init(void) /* Open RF Driver */ prop_radio.rf_handle = netstack_open(&rf_params); - if (prop_radio.rf_handle == NULL) { + if(prop_radio.rf_handle == NULL) { PRINTF("init: unable to open RF driver\n"); return RF_RESULT_ERROR; } @@ -716,5 +721,6 @@ const struct radio_driver prop_mode_driver = { }; /*---------------------------------------------------------------------------*/ /** + * @} * @} */ diff --git a/arch/cpu/cc13xx-cc26xx/rf/rf.h b/arch/cpu/cc13xx-cc26xx/rf/rf.h index 6237779cd..a0c38513f 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/rf.h +++ b/arch/cpu/cc13xx-cc26xx/rf/rf.h @@ -31,15 +31,14 @@ * \addtogroup cc13xx-cc26xx-cpu * @{ * - * \defgroup rf-core Common functionality for the CC13xx/CC26xx RF + * \defgroup cc13xx-cc26xx-rf RF specific files for CC13xx/CC26xx * * @{ * * \file - * Header file of common CC13xx/CC26xx RF functionality + * Header file of common CC13xx/CC26xx RF functionality. * \author * Edvard Pettersen - */ /*---------------------------------------------------------------------------*/ #ifndef RF_CORE_H_ diff --git a/arch/cpu/cc13xx-cc26xx/rf/sched.c b/arch/cpu/cc13xx-cc26xx/rf/sched.c index 840010d22..784cfff3f 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/sched.c +++ b/arch/cpu/cc13xx-cc26xx/rf/sched.c @@ -28,11 +28,13 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /** - * \addtogroup + * \addtogroup cc13xx-cc26xx-rf-sched * @{ * * \file - * Implementation of common CC13xx/CC26xx RF functionality + * Implementation of the CC13xx/CC26xx RF scheduler. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #include "contiki.h" @@ -101,11 +103,11 @@ cmd_rx_cb(RF_Handle client, RF_CmdHandle command, RF_EventMask events) (void)client; (void)command; - if (events & RF_EventRxEntryDone) { + if(events & RF_EventRxEntryDone) { process_poll(&rf_sched_process); } - if (events & RF_EventRxBufFull) { + if(events & RF_EventRxBufFull) { rx_buf_full = true; process_poll(&rf_sched_process); } @@ -138,7 +140,7 @@ cmd_rx_disable(void) { const bool is_active = cmd_rx_is_active(); - if (is_active) { + if(is_active) { CMD_STATUS(netstack_cmd_rx) = DONE_STOPPED; RF_cancelCmd(&rf_netstack, cmd_rx_handle, RF_ABORT_GRACEFULLY); cmd_rx_handle = 0; @@ -152,7 +154,7 @@ cmd_rx_restore(uint_fast8_t rx_key) { const bool was_active = (rx_key != 0) ? true : false; - if (!was_active) { + if(!was_active) { return RF_RESULT_OK; } @@ -172,7 +174,7 @@ cmd_rx_restore(uint_fast8_t rx_key) RF_EventRxEntryDone | RF_EventRxBufFull ); - if (!CMD_HANDLE_OK(cmd_rx_handle)) { + if(!CMD_HANDLE_OK(cmd_rx_handle)) { PRINTF("cmd_rx_restore: unable to schedule RX command handle=%d status=0x%04x", cmd_rx_handle, CMD_STATUS(netstack_cmd_rx)); return RF_RESULT_ERROR; @@ -246,14 +248,13 @@ netstack_sched_fs(void) /* * For IEEE-mode, restarting CMD_IEEE_RX re-calibrates the synth by using the * channel field in the CMD_IEEE_RX command. It is assumed this field is - * already configured before this function is called. - * However, if CMD_IEEE_RX wasn't active, manually calibrate the synth - * with CMD_FS. + * already configured before this function is called. However, if + * CMD_IEEE_RX wasn't active, manually calibrate the synth with CMD_FS. * * For Prop-mode, the synth is always manually calibrated with CMD_FS. */ #if (RF_MODE == RF_CORE_MODE_2_4_GHZ) - if (rx_key) { + if(rx_key) { cmd_rx_restore(rx_key); return RF_RESULT_OK; } @@ -276,7 +277,7 @@ netstack_sched_fs(void) synth_error = (EVENTS_CMD_DONE(events)) && (CMD_STATUS(netstack_cmd_fs) == ERROR_SYNTH_PROG); - } while (synth_error && (num_tries++ < CMD_FS_RETRIES)); + } while(synth_error && (num_tries++ < CMD_FS_RETRIES)); cmd_rx_restore(rx_key); @@ -305,9 +306,9 @@ netstack_sched_ieee_tx(bool ack_request) * run the RX_ACK command. Therefore, turn on RX before starting the * chained TX command. */ - if (rx_needed) { + if(rx_needed) { res = netstack_sched_rx(false); - if (res != RF_RESULT_OK) { + if(res != RF_RESULT_OK) { return res; } } @@ -321,13 +322,13 @@ netstack_sched_ieee_tx(bool ack_request) 0 ); - if (!CMD_HANDLE_OK(tx_handle)) { + if(!CMD_HANDLE_OK(tx_handle)) { PRINTF("netstack_sched_tx: unable to schedule TX command handle=%d status=0x%04x\n", tx_handle, CMD_STATUS(netstack_cmd_tx)); return RF_RESULT_ERROR; } - if (rx_is_active) { + if(rx_is_active) { ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT); } else { ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); @@ -337,17 +338,17 @@ netstack_sched_ieee_tx(bool ack_request) RF_EventMask tx_events = RF_pendCmd(&rf_netstack, tx_handle, 0); /* Stop RX if it was turned on only for ACK */ - if (rx_needed) { + if(rx_needed) { netstack_stop_rx(); } - if (rx_is_active) { + if(rx_is_active) { ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN); } else { ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); } - if (!EVENTS_CMD_DONE(tx_events)) { + if(!EVENTS_CMD_DONE(tx_events)) { PRINTF("netstack_sched_tx: TX command pend error events=0x%08llx status=0x%04x\n", tx_events, CMD_STATUS(netstack_cmd_tx)); return RF_RESULT_ERROR; @@ -375,7 +376,7 @@ netstack_sched_prop_tx(void) 0 ); - if (!CMD_HANDLE_OK(tx_handle)) { + if(!CMD_HANDLE_OK(tx_handle)) { PRINTF("netstack_sched_tx: unable to schedule TX command handle=%d status=0x%04x\n", tx_handle, CMD_STATUS(netstack_cmd_tx)); return RF_RESULT_ERROR; @@ -387,7 +388,7 @@ netstack_sched_prop_tx(void) */ const bool rx_key = cmd_rx_disable(); - if (rx_key) { + if(rx_key) { ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT); } else { ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); @@ -398,13 +399,13 @@ netstack_sched_prop_tx(void) cmd_rx_restore(rx_key); - if (rx_key) { + if(rx_key) { ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN); } else { ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); } - if (!EVENTS_CMD_DONE(tx_events)) { + if(!EVENTS_CMD_DONE(tx_events)) { PRINTF("netstack_sched_tx: TX command pend error events=0x%08llx status=0x%04x\n", tx_events, CMD_STATUS(netstack_cmd_tx)); return RF_RESULT_ERROR; @@ -416,7 +417,7 @@ netstack_sched_prop_tx(void) rf_result_t netstack_sched_rx(bool start) { - if (cmd_rx_is_active()) { + if(cmd_rx_is_active()) { PRINTF("netstack_sched_rx: already in RX\n"); return RF_RESULT_OK; } @@ -437,7 +438,7 @@ netstack_sched_rx(bool start) RF_EventRxEntryDone | RF_EventRxBufFull ); - if (!CMD_HANDLE_OK(cmd_rx_handle)) { + if(!CMD_HANDLE_OK(cmd_rx_handle)) { PRINTF("netstack_sched_rx: unable to schedule RX command handle=%d status=0x%04x\n", cmd_rx_handle, CMD_STATUS(netstack_cmd_rx)); return RF_RESULT_ERROR; @@ -445,7 +446,7 @@ netstack_sched_rx(bool start) ENERGEST_ON(ENERGEST_TYPE_LISTEN); - if (start) { + if(start) { rf_is_on = true; process_poll(&rf_sched_process); } @@ -456,7 +457,7 @@ netstack_sched_rx(bool start) rf_result_t netstack_stop_rx(void) { - if (!cmd_rx_is_active()) { + if(!cmd_rx_is_active()) { PRINTF("netstack_stop_rx: RX not active\n"); return RF_RESULT_OK; } @@ -497,7 +498,7 @@ ble_sched_beacon(RF_Callback cb, RF_EventMask bm_event) bm_event ); - if (!CMD_HANDLE_OK(beacon_handle)) { + if(!CMD_HANDLE_OK(beacon_handle)) { PRINTF("ble_sched_beacon: unable to schedule BLE Beacon command handle=%d status=0x%04x\n", beacon_handle, CMD_STATUS(ble_cmd_beacon)); return RF_RESULT_ERROR; @@ -507,7 +508,7 @@ ble_sched_beacon(RF_Callback cb, RF_EventMask bm_event) /* Wait until Beacon operation finishes */ RF_EventMask beacon_events = RF_pendCmd(&rf_ble, beacon_handle, 0); - if (!EVENTS_CMD_DONE(beacon_events)) { + if(!EVENTS_CMD_DONE(beacon_events)) { PRINTF("ble_sched_beacon: Beacon command pend error events=0x%08llx status=0x%04x\n", beacon_events, CMD_STATUS(ble_cmd_beacon)); @@ -532,12 +533,12 @@ PROCESS_THREAD(rf_sched_process, ev, data) (ev == PROCESS_EVENT_TIMER)); /* start the synth re-calibration timer once. */ - if (rf_is_on) { + if(rf_is_on) { rf_is_on = false; etimer_set(&synth_recal_timer, synth_recal_interval()); } - if (ev == PROCESS_EVENT_POLL) { + if(ev == PROCESS_EVENT_POLL) { do { watchdog_periodic(); @@ -548,7 +549,7 @@ PROCESS_THREAD(rf_sched_process, ev, data) * RX will stop if the RX buffers are full. In this case, restart * RX after we've freed at least on packet. */ - if (rx_buf_full) { + if(rx_buf_full) { PRINTF("rf_core: RX buf full, restart RX status=0x%04x\n", CMD_STATUS(netstack_cmd_rx)); rx_buf_full = false; @@ -567,7 +568,7 @@ PROCESS_THREAD(rf_sched_process, ev, data) } /* Scheduling CMD_FS will re-calibrate the synth. */ - if ((ev == PROCESS_EVENT_TIMER) && + if((ev == PROCESS_EVENT_TIMER) && etimer_expired(&synth_recal_timer)) { PRINTF("rf_core: Re-calibrate synth\n"); netstack_sched_fs(); diff --git a/arch/cpu/cc13xx-cc26xx/rf/sched.h b/arch/cpu/cc13xx-cc26xx/rf/sched.h index 6ba452702..bd966f36b 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/sched.h +++ b/arch/cpu/cc13xx-cc26xx/rf/sched.h @@ -28,11 +28,17 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ /** - * \addtogroup rf-core + * \addtogroup cc13xx-cc26xx-rf + * @{ + * + * \defgroup cc13xx-cc26xx-rf-sched RF Scheduler for CC13xx/CC26xx + * * @{ * * \file * Header file of the CC13xx/CC26xx RF scheduler. + * \author + * Edvard Pettersen */ /*---------------------------------------------------------------------------*/ #ifndef RF_SCHED_H_ @@ -52,25 +58,41 @@ typedef enum { RF_RESULT_ERROR, } rf_result_t; /*---------------------------------------------------------------------------*/ -/* Common */ +/** + * \name Common RF scheduler functionality. + * + * @{ + */ rf_result_t rf_yield(void); - rf_result_t rf_set_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8_t dbm); rf_result_t rf_get_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8_t *dbm); +/** @} */ /*---------------------------------------------------------------------------*/ -/* Netstack radio: IEEE-mode or prop-mode */ +/** + * \name Nestack Radio scheduler functionality. + * + * Either for Prop-mode or IEEE-mode Radio driver. + * + * @{ + */ RF_Handle netstack_open(RF_Params *params); - rf_result_t netstack_sched_fs(void); rf_result_t netstack_sched_ieee_tx(bool ack_request); rf_result_t netstack_sched_prop_tx(void); rf_result_t netstack_sched_rx(bool start); rf_result_t netstack_stop_rx(void); +/** @} */ /*---------------------------------------------------------------------------*/ -/* BLE radio: BLE Beacon Daemon */ +/** + * \name BLE Radio scheduler functionality. + * + * Only for the BLE Beacon Daemon. + * + * @{ + */ RF_Handle ble_open(RF_Params *params); - rf_result_t ble_sched_beacon(RF_Callback cb, RF_EventMask bm_event); +/** @} */ /*---------------------------------------------------------------------------*/ #endif /* RF_SCHED_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/platform.c b/arch/platform/simplelink/cc13xx-cc26xx/platform.c index abe00da49..651e97424 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/platform.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/platform.c @@ -59,12 +59,12 @@ #include DeviceFamily_constructPath(driverlib/driverlib_release.h) #include DeviceFamily_constructPath(driverlib/chipinfo.h) #include DeviceFamily_constructPath(driverlib/vims.h) -#include DeviceFamily_constructPath(inc/hw_cpu_scs.h) #include #include #include #include +#include #include #include #include @@ -92,30 +92,31 @@ */ extern void Board_initHook(void); /*---------------------------------------------------------------------------*/ -#ifdef BOARD_CONF_HAS_SENSORS -#define BOARD_HAS_SENSORS BOARD_CONF_HAS_SENSORS -#else -#define BOARD_HAS_SENSORS 1 -#endif -/*---------------------------------------------------------------------------*/ -/* Fade a specified LED */ +/* + * \brief Fade a specified LED. + */ static void -fade(unsigned char l) +fade(PIN_Id pin) { - volatile int i; - int k; - int j; - for(k = 0; k < 800; ++k) { - j = (k > 400) ? 800 - k : k; + volatile uint32_t i; + uint32_t k; + uint32_t j; + uint32_t pivot = 800; + uint32_t pivot_half = pivot / 2; - leds_single_on(l); - for(i = 0; i < j; ++i) { __asm("nop"); } - leds_single_off(l); - for(i = 0; i < 400 - j; ++i) { __asm("nop"); } + for(k = 0; k < pivot; ++k) { + j = (k > pivot_half) ? pivot - k : k; + + PINCC26XX_setOutputValue(pin, 1); + for (i = 0; i < j; ++i) { __asm__ __volatile__ ("nop"); } + PINCC26XX_setOutputValue(pin, 0); + for (i = 0; i < pivot_half - j; ++i) { __asm__ __volatile__ ("nop"); } } } /*---------------------------------------------------------------------------*/ -/* Configure RF params for the radio driver */ +/* + * \brief Configure RF params for the radio driver. + */ static void set_rf_params(void) { @@ -163,7 +164,7 @@ platform_init_stage_one(void) gpio_hal_init(); leds_init(); - fade(LEDS_RED); + fade(Board_PIN_RLED); /* TI Drivers init */ #if TI_UART_CONF_ENABLE @@ -181,7 +182,7 @@ platform_init_stage_one(void) TRNG_init(); - fade(LEDS_GREEN); + fade(Board_PIN_GLED); /* NoRTOS must be called last */ NoRTOS_start(); @@ -213,7 +214,7 @@ platform_init_stage_two(void) button_hal_init(); - fade(LEDS_RED); + fade(Board_PIN_RLED); } /*---------------------------------------------------------------------------*/ void @@ -246,11 +247,11 @@ platform_init_stage_three(void) LOG_INFO("RF: Channel %d, PANID 0x%04X\n", chan, pan); LOG_INFO("Node ID: %d\n", node_id); -#if BOARD_HAS_SENSORS +#if BOARD_CONF_SENSORS_ENABLE process_start(&sensors_process, NULL); #endif - fade(LEDS_GREEN); + fade(Board_PIN_GLED); } /*---------------------------------------------------------------------------*/ void From 6deae207e5b090de1c949f00336e2229932a2cb1 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Mon, 23 Jul 2018 14:36:17 +0200 Subject: [PATCH 281/485] Remove 0b literal prefix --- os/dev/gpio-hal.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/os/dev/gpio-hal.h b/os/dev/gpio-hal.h index bbfa35dff..49b4e5344 100644 --- a/os/dev/gpio-hal.h +++ b/os/dev/gpio-hal.h @@ -127,8 +127,8 @@ typedef void (*gpio_hal_callback_t)(gpio_hal_pin_mask_t pin_mask); #define GPIO_HAL_PIN_CFG_INPUT_PULLUP (1 << 1) #define GPIO_HAL_PIN_CFG_INPUT_PULLDOWN (2 << 1) -#define GPIO_HAL_PIN_BM_INPUT_HYSTERESIS (0b00000001 << 0) -#define GPIO_HAL_PIN_BM_INPUT_PULLING (0b00000110 << 0) +#define GPIO_HAL_PIN_BM_INPUT_HYSTERESIS (0x01 << 0) /**< 0b00000001 */ +#define GPIO_HAL_PIN_BM_INPUT_PULLING (0x06 << 0) /**< 0b00000110 */ #define GPIO_HAL_PIN_BM_INPUT ( GPIO_HAL_PIN_BM_INPUT_HYSTERESIS \ | GPIO_HAL_PIN_BM_INPUT_PULLING) @@ -140,9 +140,9 @@ typedef void (*gpio_hal_callback_t)(gpio_hal_pin_mask_t pin_mask); #define GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MED (1 << 6) #define GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MAX (2 << 6) -#define GPIO_HAL_PIN_BM_OUTPUT_BUF (0b00011000 << 0) -#define GPIO_HAL_PIN_BM_OUTPUT_SLEWCTRL (0b00100000 << 0) -#define GPIO_HAL_PIN_BM_OUTPUT_DRVSTR (0b11000000 << 0) +#define GPIO_HAL_PIN_BM_OUTPUT_BUF (0x18 << 0) /**< 0b00011000 */ +#define GPIO_HAL_PIN_BM_OUTPUT_SLEWCTRL (0x20 << 0) /**< 0b00100000 */ +#define GPIO_HAL_PIN_BM_OUTPUT_DRVSTR (0xC0 << 0) /**< 0b11000000 */ #define GPIO_HAL_PIN_BM_OUTPUT ( GPIO_HAL_PIN_BM_OUTPUT_BUF \ | GPIO_HAL_PIN_BM_OUTPUT_SLEWCTRL \ | GPIO_HAL_PIN_BM_OUTPUT_DRVSTR) @@ -152,7 +152,7 @@ typedef void (*gpio_hal_callback_t)(gpio_hal_pin_mask_t pin_mask); #define GPIO_HAL_PIN_CFG_INT_RISING (2 << 8) #define GPIO_HAL_PIN_CFG_INT_BOTH (3 << 8) -#define GPIO_HAL_PIN_BM_INT (0b00000011 << 8) +#define GPIO_HAL_PIN_BM_INT (0x03 << 8) /**< 0b00000011 */ #define GPIO_HAL_PIN_BM_ALL ( GPIO_HAL_PIN_BM_INPUT \ | GPIO_HAL_PIN_BM_OUTPUT \ From 06cc883b3fca199d8b7003f4f3fa3475968a9b80 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Mon, 23 Jul 2018 17:37:19 +0200 Subject: [PATCH 282/485] Fixed DeviceFamily_constructPath() --- .../cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.c | 9 +++++---- .../cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h | 3 ++- .../launchpad/cc1310/CC1310_LAUNCHXL_fxns.c | 5 +++-- .../cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.c | 9 +++++---- .../cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h | 3 ++- .../launchpad/cc1312r1/CC1312R1_LAUNCHXL_fxns.c | 5 +++-- .../launchpad/cc1350-4/CC1350_LAUNCHXL_433.c | 9 +++++---- .../launchpad/cc1350-4/CC1350_LAUNCHXL_433.h | 3 ++- .../launchpad/cc1350-4/CC1350_LAUNCHXL_433_fxns.c | 5 +++-- .../cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c | 9 +++++---- .../cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h | 3 ++- .../launchpad/cc1350/CC1350_LAUNCHXL_fxns.c | 5 +++-- .../launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.c | 9 +++++---- .../launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h | 3 ++- .../launchpad/cc1352p-2/CC1352P_2_LAUNCHXL_fxns.c | 5 +++-- .../launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.c | 9 +++++---- .../launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.h | 3 ++- .../launchpad/cc1352p-4/CC1352P_4_LAUNCHXL_fxns.c | 5 +++-- .../cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.c | 9 +++++---- .../cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h | 3 ++- .../launchpad/cc1352p1/CC1352P1_LAUNCHXL_fxns.c | 5 +++-- .../cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c | 9 +++++---- .../cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h | 3 ++- .../launchpad/cc1352r1/CC1352R1_LAUNCHXL_fxns.c | 5 +++-- .../cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.c | 9 +++++---- .../cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h | 3 ++- .../launchpad/cc2650/CC2650_LAUNCHXL_fxns.c | 5 +++-- .../cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c | 9 +++++---- .../cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h | 3 ++- .../launchpad/cc26x2r1/CC26X2R1_LAUNCHXL_fxns.c | 5 +++-- .../cc13xx-cc26xx/sensortag/cc1350/CC1350STK.c | 9 +++++---- .../cc13xx-cc26xx/sensortag/cc1350/CC1350STK_fxns.c | 5 +++-- .../simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c | 9 +++++---- .../simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h | 3 ++- .../cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD_fxns.c | 5 +++-- .../simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c | 9 +++++---- .../simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h | 3 ++- .../cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID_fxns.c | 5 +++-- os/sys/cc.h | 2 ++ 39 files changed, 130 insertions(+), 90 deletions(-) diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.c index b9f3adfb1..638bfa0d0 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.c @@ -40,10 +40,11 @@ #include #include -#include -#include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/udma.h) +#include DeviceFamily_constructPath(inc/hw_ints.h) +#include DeviceFamily_constructPath(inc/hw_memmap.h) #include "CC1310_LAUNCHXL.h" diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h index 12b3bb084..4d11cd749 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h @@ -53,7 +53,8 @@ extern "C" { /* Includes */ #include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) /* Externs */ extern const PIN_Config BoardGpioInitTable[]; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL_fxns.c index 9656aa821..6918918bb 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL_fxns.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL_fxns.c @@ -39,8 +39,9 @@ #include #include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/cpu.h) #include diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.c index 24db2296f..e45317c9f 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.c @@ -40,10 +40,11 @@ #include #include -#include -#include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/udma.h) +#include DeviceFamily_constructPath(inc/hw_ints.h) +#include DeviceFamily_constructPath(inc/hw_memmap.h) #include "CC1312R1_LAUNCHXL.h" diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h index d54a18e89..3d796df9b 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h @@ -53,7 +53,8 @@ extern "C" { /* Includes */ #include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) /* Externs */ extern const PIN_Config BoardGpioInitTable[]; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL_fxns.c index 77a830b4d..0a28583d4 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL_fxns.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL_fxns.c @@ -39,8 +39,9 @@ #include #include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/cpu.h) #include #include "Board.h" diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.c index 55b30637d..deec29ce6 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.c @@ -40,10 +40,11 @@ #include #include -#include -#include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/udma.h) +#include DeviceFamily_constructPath(inc/hw_ints.h) +#include DeviceFamily_constructPath(inc/hw_memmap.h) #include "CC1350_LAUNCHXL_433.h" diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h index 9e9bee949..441bb04fa 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h @@ -53,7 +53,8 @@ extern "C" { /* Includes */ #include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) /* Externs */ extern const PIN_Config BoardGpioInitTable[]; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433_fxns.c index 2d2a27784..a8a6b16c0 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433_fxns.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433_fxns.c @@ -38,8 +38,9 @@ #include #include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/cpu.h) #include #include diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c index 61efd4e92..cddb5a9fa 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c @@ -40,10 +40,11 @@ #include #include -#include -#include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/udma.h) +#include DeviceFamily_constructPath(inc/hw_ints.h) +#include DeviceFamily_constructPath(inc/hw_memmap.h) #include "CC1350_LAUNCHXL.h" diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h index a54fa9365..746a25fa1 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h @@ -53,7 +53,8 @@ extern "C" { /* Includes */ #include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) /* Externs */ extern const PIN_Config BoardGpioInitTable[]; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL_fxns.c index a60df3e65..90f69a0c0 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL_fxns.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL_fxns.c @@ -40,8 +40,9 @@ #include #include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/cpu.h) #include #include diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.c index ea178974b..4f1d297a7 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.c @@ -40,10 +40,11 @@ #include #include -#include -#include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/udma.h) +#include DeviceFamily_constructPath(inc/hw_ints.h) +#include DeviceFamily_constructPath(inc/hw_memmap.h) #include "CC1352P_2_LAUNCHXL.h" diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h index 7c83f2935..e81d45aec 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h @@ -53,7 +53,8 @@ extern "C" { /* Includes */ #include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) /* Externs */ extern const PIN_Config BoardGpioInitTable[]; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL_fxns.c index b346056a3..f8b4930c8 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL_fxns.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL_fxns.c @@ -40,8 +40,9 @@ #include #include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/cpu.h) #include #include diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.c index 9a2ae3505..bb055fbb4 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.c @@ -40,10 +40,11 @@ #include #include -#include -#include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/udma.h) +#include DeviceFamily_constructPath(inc/hw_ints.h) +#include DeviceFamily_constructPath(inc/hw_memmap.h) #include "CC1352P_4_LAUNCHXL.h" diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.h index a125dcd6a..55baa0037 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.h @@ -53,7 +53,8 @@ extern "C" { /* Includes */ #include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) /* Externs */ extern const PIN_Config BoardGpioInitTable[]; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL_fxns.c index 8a703efe7..ef9c0531c 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL_fxns.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL_fxns.c @@ -40,8 +40,9 @@ #include #include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/cpu.h) #include #include diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.c index 4a6e7b5e8..6fdfc525e 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.c @@ -40,10 +40,11 @@ #include #include -#include -#include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/udma.h) +#include DeviceFamily_constructPath(inc/hw_ints.h) +#include DeviceFamily_constructPath(inc/hw_memmap.h) #include "CC1352P1_LAUNCHXL.h" diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h index dd91ea72d..a023cca75 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h @@ -53,7 +53,8 @@ extern "C" { /* Includes */ #include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) /* Externs */ extern const PIN_Config BoardGpioInitTable[]; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL_fxns.c index cdfa6342e..9f3000929 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL_fxns.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL_fxns.c @@ -40,8 +40,9 @@ #include #include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/cpu.h) #include #include diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c index e84f74cbe..e60b6d73e 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c @@ -42,10 +42,11 @@ #include #include -#include -#include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/udma.h) +#include DeviceFamily_constructPath(inc/hw_ints.h) +#include DeviceFamily_constructPath(inc/hw_memmap.h) #include "CC1352R1_LAUNCHXL.h" diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h index 3a4949f87..5a0717057 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h @@ -53,7 +53,8 @@ extern "C" { /* Includes */ #include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) /* Externs */ extern const PIN_Config BoardGpioInitTable[]; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL_fxns.c index 9ee574235..520b91297 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL_fxns.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL_fxns.c @@ -40,8 +40,9 @@ #include #include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/cpu.h) #include #include diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.c index 1d63a60a3..e201b8e89 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.c @@ -40,10 +40,11 @@ #include #include -#include -#include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/udma.h) +#include DeviceFamily_constructPath(inc/hw_ints.h) +#include DeviceFamily_constructPath(inc/hw_memmap.h) #include "CC2650_LAUNCHXL.h" diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h index 9f0fd81f9..f344e79bc 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h @@ -53,7 +53,8 @@ extern "C" { /* Includes */ #include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) /* Externs */ extern const PIN_Config BoardGpioInitTable[]; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL_fxns.c index 5562bd0a0..f471e33d6 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL_fxns.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL_fxns.c @@ -39,8 +39,9 @@ #include #include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/cpu.h) #include diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c index 47a6ef8da..6fb5e357f 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c @@ -41,10 +41,11 @@ #include #include -#include -#include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/udma.h) +#include DeviceFamily_constructPath(inc/hw_ints.h) +#include DeviceFamily_constructPath(inc/hw_memmap.h) #include "CC26X2R1_LAUNCHXL.h" diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h index 998a8ffa6..6af14329b 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h @@ -53,7 +53,8 @@ extern "C" { /* Includes */ #include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) /* Externs */ extern const PIN_Config BoardGpioInitTable[]; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL_fxns.c index 6c288ab0b..606339f2d 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL_fxns.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL_fxns.c @@ -39,8 +39,9 @@ #include #include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/cpu.h) #include diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.c index c5a7558c7..6f9f68e20 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.c @@ -43,10 +43,11 @@ #include #include -#include -#include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/udma.h) +#include DeviceFamily_constructPath(inc/hw_ints.h) +#include DeviceFamily_constructPath(inc/hw_memmap.h) #include "CC1350STK.h" diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK_fxns.c index 16cdde8bd..dd20cb301 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK_fxns.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK_fxns.c @@ -38,8 +38,9 @@ #include #include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/cpu.h) #include "Board.h" diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c index 8e05f6574..ab1a4db22 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c @@ -40,10 +40,11 @@ #include #include -#include -#include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/udma.h) +#include DeviceFamily_constructPath(inc/hw_ints.h) +#include DeviceFamily_constructPath(inc/hw_memmap.h) #include "CC1350DK_7XD.h" diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h index 72b19a036..d9d3fc63e 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h @@ -53,7 +53,8 @@ extern "C" { /* Includes */ #include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) /* Externs */ extern const PIN_Config BoardGpioInitTable[]; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD_fxns.c index e012731c6..b7983730a 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD_fxns.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD_fxns.c @@ -39,8 +39,9 @@ #include #include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/cpu.h) #include diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c index 431b0005c..7689793a2 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c @@ -40,10 +40,11 @@ #include #include -#include -#include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/udma.h) +#include DeviceFamily_constructPath(inc/hw_ints.h) +#include DeviceFamily_constructPath(inc/hw_memmap.h) #include "CC2650DK_7ID.h" diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h index 7901fbed1..356b50fc0 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h @@ -53,7 +53,8 @@ extern "C" { /* Includes */ #include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) /* Externs */ extern const PIN_Config BoardGpioInitTable[]; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID_fxns.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID_fxns.c index b742aad53..aa6a6c60e 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID_fxns.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID_fxns.c @@ -39,8 +39,9 @@ #include #include -#include -#include +#include +#include DeviceFamily_constructPath(driverlib/ioc.h) +#include DeviceFamily_constructPath(driverlib/cpu.h) #include diff --git a/os/sys/cc.h b/os/sys/cc.h index 2fa5439df..cb9fb109d 100644 --- a/os/sys/cc.h +++ b/os/sys/cc.h @@ -103,6 +103,8 @@ #ifdef CC_CONF_ALIGN #define CC_ALIGN(n) CC_CONF_ALIGN(n) +#else +#define CC_ALIGN(n) #endif /* CC_CONF_INLINE */ /** From 54e8adfdec537c66471b95c57943f8b3805b3c30 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Mon, 23 Jul 2018 17:37:42 +0200 Subject: [PATCH 283/485] Fixed elif --- arch/platform/simplelink/cc13xx-cc26xx/platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/platform/simplelink/cc13xx-cc26xx/platform.c b/arch/platform/simplelink/cc13xx-cc26xx/platform.c index 651e97424..58474a809 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/platform.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/platform.c @@ -241,7 +241,7 @@ platform_init_stage_three(void) #if (RF_MODE == RF_MODE_SUB_1_GHZ) LOG_INFO("Operating frequency on Sub-1 GHz\n"); -#else +#elif (RF_MODE == RF_MODE_2_4_GHZ) LOG_INFO("Operating frequency on 2.4 GHz\n"); #endif LOG_INFO("RF: Channel %d, PANID 0x%04X\n", chan, pan); From 640570cd38c6db9cbf2b67459332dad775b08699 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Mon, 23 Jul 2018 17:49:18 +0200 Subject: [PATCH 284/485] Removed space between keyword and parentheses --- arch/cpu/cc13xx-cc26xx/dev/clock-arch.c | 2 +- arch/cpu/cc13xx-cc26xx/dev/dbg-arch.c | 2 +- arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c | 38 ++++++++--------- arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c | 12 +++--- arch/cpu/cc13xx-cc26xx/rf/ble-addr.c | 6 +-- arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c | 8 ++-- arch/cpu/cc13xx-cc26xx/rf/prop-mode.c | 2 +- .../simplelink/cc13xx-cc26xx/batmon-sensor.c | 7 ++-- .../simplelink/cc13xx-cc26xx/batmon-sensor.h | 9 ++-- .../simplelink/cc13xx-cc26xx/platform.c | 14 +++---- .../cc13xx-cc26xx/sensortag/bmp-280-sensor.c | 20 ++++----- .../cc13xx-cc26xx/sensortag/buzzer.c | 16 +++---- .../cc13xx-cc26xx/sensortag/hdc-1000-sensor.c | 24 +++++------ .../cc13xx-cc26xx/sensortag/mpu-9250-sensor.c | 42 +++++++++---------- .../cc13xx-cc26xx/sensortag/opt-3001-sensor.c | 16 +++---- .../cc13xx-cc26xx/sensortag/tmp-007-sensor.c | 28 ++++++------- .../cc13xx-cc26xx/srf06/als-sensor.c | 4 +- 17 files changed, 124 insertions(+), 126 deletions(-) diff --git a/arch/cpu/cc13xx-cc26xx/dev/clock-arch.c b/arch/cpu/cc13xx-cc26xx/dev/clock-arch.c index 3396240e8..d65750dc8 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/clock-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/clock-arch.c @@ -65,7 +65,7 @@ clock_update_cb(void) HwiP_restore(key); /* Notify the etimer system. */ - if (etimer_pending()) { + if(etimer_pending()) { etimer_request_poll(); } } diff --git a/arch/cpu/cc13xx-cc26xx/dev/dbg-arch.c b/arch/cpu/cc13xx-cc26xx/dev/dbg-arch.c index 1c9ec68cc..f61d0e6af 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/dbg-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/dbg-arch.c @@ -71,7 +71,7 @@ dbg_send_bytes(const unsigned char *seq, unsigned int len) seq_len = strlen((const char *)seq); max_len = MIN(seq_len, (size_t)len); - if (max_len == 0) { + if(max_len == 0) { return 0; } diff --git a/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c b/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c index c88549149..03fdc870f 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c @@ -60,16 +60,16 @@ from_hal_cfg(gpio_hal_pin_cfg_t cfg, PIN_Config *pin_cfg, PIN_Config *pin_mask) cfg &= GPIO_HAL_PIN_BM_ALL; /* Input config */ - if (cfg & GPIO_HAL_PIN_BM_INPUT) { + if(cfg & GPIO_HAL_PIN_BM_INPUT) { *pin_mask |= PIN_BM_INPUT_MODE; /* Hysteresis config */ - if ((cfg & GPIO_HAL_PIN_BM_INPUT_HYSTERESIS) == GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS) { + if((cfg & GPIO_HAL_PIN_BM_INPUT_HYSTERESIS) == GPIO_HAL_PIN_CFG_INPUT_HYSTERESIS) { *pin_cfg |= PIN_HYSTERESIS; } /* Pulling config */ - switch (cfg & GPIO_HAL_PIN_BM_INPUT_PULLING) { + switch(cfg & GPIO_HAL_PIN_BM_INPUT_PULLING) { case GPIO_HAL_PIN_CFG_INPUT_NOPULL: *pin_cfg |= PIN_NOPULL; break; case GPIO_HAL_PIN_CFG_INPUT_PULLUP: *pin_cfg |= PIN_PULLUP; break; case GPIO_HAL_PIN_CFG_INPUT_PULLDOWN: *pin_cfg |= PIN_PULLDOWN; break; @@ -77,23 +77,23 @@ from_hal_cfg(gpio_hal_pin_cfg_t cfg, PIN_Config *pin_cfg, PIN_Config *pin_mask) } /* Output config */ - if (cfg & GPIO_HAL_PIN_BM_OUTPUT) { + if(cfg & GPIO_HAL_PIN_BM_OUTPUT) { *pin_mask |= PIN_BM_OUTPUT_MODE; /* Output buffer type config */ - switch (cfg & GPIO_HAL_PIN_BM_OUTPUT_BUF) { + switch(cfg & GPIO_HAL_PIN_BM_OUTPUT_BUF) { case GPIO_HAL_PIN_CFG_OUTPUT_PUSHPULL: *pin_cfg |= PIN_PUSHPULL; break; case GPIO_HAL_PIN_CFG_OUTPUT_OPENDRAIN: *pin_cfg |= PIN_OPENDRAIN; break; case GPIO_HAL_PIN_CFG_OUTPUT_OPENSOURCE: *pin_cfg |= PIN_OPENSOURCE; break; } /* Slew control config */ - if ((cfg & GPIO_HAL_PIN_BM_OUTPUT_SLEWCTRL) == GPIO_HAL_PIN_CFG_OUTPUT_SLEWCTRL) { + if((cfg & GPIO_HAL_PIN_BM_OUTPUT_SLEWCTRL) == GPIO_HAL_PIN_CFG_OUTPUT_SLEWCTRL) { *pin_cfg |= PIN_SLEWCTRL; } /* Drive strength config */ - switch (cfg & GPIO_HAL_PIN_BM_OUTPUT_DRVSTR) { + switch(cfg & GPIO_HAL_PIN_BM_OUTPUT_DRVSTR) { case GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MIN: *pin_cfg |= PIN_DRVSTR_MIN; break; case GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MED: *pin_cfg |= PIN_DRVSTR_MED; break; case GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MAX: *pin_cfg |= PIN_DRVSTR_MAX; break; @@ -101,11 +101,11 @@ from_hal_cfg(gpio_hal_pin_cfg_t cfg, PIN_Config *pin_cfg, PIN_Config *pin_mask) } /* Interrupt config */ - if (cfg & GPIO_HAL_PIN_BM_INT) { + if(cfg & GPIO_HAL_PIN_BM_INT) { *pin_mask |= PIN_BM_IRQ; /* Interrupt edge config */ - switch (cfg & GPIO_HAL_PIN_BM_INT) { + switch(cfg & GPIO_HAL_PIN_BM_INT) { case GPIO_HAL_PIN_CFG_INT_DISABLE: *pin_cfg |= PIN_IRQ_DIS; break; case GPIO_HAL_PIN_CFG_INT_FALLING: *pin_cfg |= PIN_IRQ_NEGEDGE; break; case GPIO_HAL_PIN_CFG_INT_RISING: *pin_cfg |= PIN_IRQ_POSEDGE; break; @@ -118,14 +118,14 @@ static void to_hal_cfg(PIN_Config pin_cfg, gpio_hal_pin_cfg_t *cfg) { /* Input config */ - if (pin_cfg & PIN_BM_INPUT_MODE) { + if(pin_cfg & PIN_BM_INPUT_MODE) { /* Hysteresis config */ - if ((pin_cfg & PIN_BM_HYSTERESIS) == PIN_HYSTERESIS) { + if((pin_cfg & PIN_BM_HYSTERESIS) == PIN_HYSTERESIS) { *cfg |= GPIO_HAL_PIN_BM_INPUT_HYSTERESIS; } /* Pulling config */ - switch (pin_cfg & PIN_BM_PULLING) { + switch(pin_cfg & PIN_BM_PULLING) { case PIN_NOPULL: *cfg |= GPIO_HAL_PIN_CFG_INPUT_NOPULL; break; case PIN_PULLUP: *cfg |= GPIO_HAL_PIN_CFG_INPUT_PULLUP; break; case PIN_PULLDOWN: *cfg |= GPIO_HAL_PIN_CFG_INPUT_PULLDOWN; break; @@ -133,21 +133,21 @@ to_hal_cfg(PIN_Config pin_cfg, gpio_hal_pin_cfg_t *cfg) } /* Output config */ - if (pin_cfg & PIN_BM_OUTPUT_MODE) { + if(pin_cfg & PIN_BM_OUTPUT_MODE) { /* Output buffer type config */ - switch (pin_cfg & PIN_BM_OUTPUT_BUF) { + switch(pin_cfg & PIN_BM_OUTPUT_BUF) { case PIN_PUSHPULL: *cfg |= GPIO_HAL_PIN_CFG_OUTPUT_PUSHPULL; break; case PIN_OPENDRAIN: *cfg |= GPIO_HAL_PIN_CFG_OUTPUT_OPENDRAIN; break; case PIN_OPENSOURCE: *cfg |= GPIO_HAL_PIN_CFG_OUTPUT_OPENSOURCE; break; } /* Slew control config */ - if ((pin_cfg & PIN_BM_SLEWCTRL) == PIN_SLEWCTRL) { + if((pin_cfg & PIN_BM_SLEWCTRL) == PIN_SLEWCTRL) { *cfg |= GPIO_HAL_PIN_CFG_OUTPUT_SLEWCTRL; } /* Drive strength config */ - switch (pin_cfg & PIN_BM_DRVSTR) { + switch(pin_cfg & PIN_BM_DRVSTR) { case PIN_DRVSTR_MIN: *cfg |= GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MIN; break; case PIN_DRVSTR_MED: *cfg |= GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MED; break; case PIN_DRVSTR_MAX: *cfg |= GPIO_HAL_PIN_CFG_OUTPUT_DRVSTR_MAX; break; @@ -155,9 +155,9 @@ to_hal_cfg(PIN_Config pin_cfg, gpio_hal_pin_cfg_t *cfg) } /* Interrupt config */ - if (pin_cfg & PIN_BM_IRQ) { + if(pin_cfg & PIN_BM_IRQ) { /* Interrupt edge config */ - switch (pin_cfg & PIN_BM_IRQ) { + switch(pin_cfg & PIN_BM_IRQ) { case PIN_IRQ_DIS: *cfg |= GPIO_HAL_PIN_CFG_INT_DISABLE; break; case PIN_IRQ_NEGEDGE: *cfg |= GPIO_HAL_PIN_CFG_INT_FALLING; break; case PIN_IRQ_POSEDGE: *cfg |= GPIO_HAL_PIN_CFG_INT_RISING; break; @@ -193,7 +193,7 @@ gpio_hal_arch_interrupt_enable(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg) cfg &= GPIO_HAL_PIN_BM_INT; PIN_Config int_cfg = PIN_IRQ_DIS; - switch (cfg) { + switch(cfg) { case GPIO_HAL_PIN_CFG_INT_FALLING: int_cfg |= PIN_IRQ_NEGEDGE; break; case GPIO_HAL_PIN_CFG_INT_RISING: int_cfg |= PIN_IRQ_POSEDGE; break; case GPIO_HAL_PIN_CFG_INT_BOTH: int_cfg |= PIN_IRQ_BOTHEDGES; break; diff --git a/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c b/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c index 143a23cc3..90fe9c6e5 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c @@ -73,7 +73,7 @@ static void rtimer_clock_stub(uintptr_t unused) { (void)unused; /* do nothing */ static void rtimer_isr_hook(void) { - if (AONRTCEventGet(RTIMER_RTC_CH)) + if(AONRTCEventGet(RTIMER_RTC_CH)) { AONRTCEventClear(RTIMER_RTC_CH); AONRTCChannelDisable(RTIMER_RTC_CH); @@ -84,7 +84,7 @@ rtimer_isr_hook(void) * HWI Dispatch clears the interrupt. If HWI wasn't triggered, clear * the interrupt manually. */ - if (AONRTCEventGet(HWIP_RTC_CH)) + if(AONRTCEventGet(HWIP_RTC_CH)) { hwi_dispatch_fxn(); } @@ -122,13 +122,13 @@ rtimer_arch_init(void) /* Try to access the RAM vector table. */ ramvec_table = (isr_fxn_t*)HWREG(NVIC_VTABLE); - if (!ramvec_table) + if(!ramvec_table) { /* * Unable to find the RAM vector table is a serious fault. * Spin-lock forever. */ - for (;;) { /* hang */ } + for(;;) { /* hang */ } } /* @@ -136,13 +136,13 @@ rtimer_arch_init(void) * in the RAM vector table. Fetch and store it. */ hwi_dispatch_fxn = (hwi_dispatch_fxn_t)ramvec_table[INT_AON_RTC_COMB]; - if (!hwi_dispatch_fxn) + if(!hwi_dispatch_fxn) { /* * Unable to find the HWI dispatch ISR in the RAM vector table is * a serious fault. Spin-lock forever. */ - for (;;) { /* hang */ } + for(;;) { /* hang */ } } /* diff --git a/arch/cpu/cc13xx-cc26xx/rf/ble-addr.c b/arch/cpu/cc13xx-cc26xx/rf/ble-addr.c index ec1bec9eb..d4753e1a5 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/ble-addr.c +++ b/arch/cpu/cc13xx-cc26xx/rf/ble-addr.c @@ -104,7 +104,7 @@ ble_addr_cpy(uint8_t *dst) int ble_addr_to_eui64(uint8_t *dst, uint8_t *src) { - if (!dst || !src) { + if(!dst || !src) { return -1; } @@ -119,7 +119,7 @@ ble_addr_to_eui64(uint8_t *dst, uint8_t *src) int ble_addr_to_eui64_cpy(uint8_t *dst) { - if (!dst) { + if(!dst) { return -1; } @@ -127,7 +127,7 @@ ble_addr_to_eui64_cpy(uint8_t *dst) uint8_t ble_addr[BLE_ADDR_SIZE]; res = ble_addr_cpy(ble_addr); - if (res) { + if(res) { return -1; } diff --git a/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c b/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c index c39699c5f..8eb4a442c 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c +++ b/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c @@ -729,7 +729,7 @@ get_value(radio_param_t param, radio_value_t *value) return RADIO_RESULT_INVALID_VALUE; } - switch (param) { + switch(param) { /* Power Mode */ case RADIO_PARAM_POWER_MODE: @@ -831,7 +831,7 @@ set_value(radio_param_t param, radio_value_t value) { rf_result_t res; - switch (param) { + switch(param) { /* Power Mode */ case RADIO_PARAM_POWER_MODE: @@ -965,7 +965,7 @@ get_object(radio_param_t param, void *dest, size_t size) return RADIO_RESULT_INVALID_VALUE; } - switch (param) { + switch(param) { /* 64bit address */ case RADIO_PARAM_64BIT_ADDR: { const size_t srcSize = sizeof(cmd_rx.localExtAddr); @@ -1005,7 +1005,7 @@ set_object(radio_param_t param, const void *src, size_t size) return RADIO_RESULT_INVALID_VALUE; } - switch (param) { + switch(param) { /* 64-bit address */ case RADIO_PARAM_64BIT_ADDR: { const size_t destSize = sizeof(cmd_rx.localExtAddr); diff --git a/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c b/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c index 9ac48aa8f..42447a082 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c +++ b/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c @@ -554,7 +554,7 @@ get_value(radio_param_t param, radio_value_t *value) return RADIO_RESULT_INVALID_VALUE; } - switch (param) { + switch(param) { case RADIO_PARAM_POWER_MODE: /* On / off */ *value = (prop_radio.rf_is_on) diff --git a/arch/platform/simplelink/cc13xx-cc26xx/batmon-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/batmon-sensor.c index 557c9d018..14c5ae5fe 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/batmon-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/batmon-sensor.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,13 +27,12 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup cc26xx-batmon + * \addtogroup cc13xx-cc26xx-batmon * @{ * * \file - * Driver for the CC13xx/CC26xx AON battery monitor + * Driver for the CC13xx/CC26xx AON battery monitor. */ /*---------------------------------------------------------------------------*/ #include "contiki.h" diff --git a/arch/platform/simplelink/cc13xx-cc26xx/batmon-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/batmon-sensor.h index 014e9a17d..2bfd82ae0 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/batmon-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/batmon-sensor.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,18 +27,17 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*---------------------------------------------------------------------------*/ /** - * \addtogroup cc26xx + * \addtogroup cc13xx-cc26xx-platform * @{ * - * \defgroup cc26xx-batmon CC13xx/CC26xx BatMon sensor driver + * \defgroup cc13xx-cc26xx-batmon CC13xx/CC26xx Battery Monitor sensor driver. * * Driver for the on-chip battery voltage and chip temperature sensor. * @{ * * \file - * Header file for the CC13xx/CC26xx battery monitor + * Header file for the CC13xx/CC26xx battery monitor. */ /*---------------------------------------------------------------------------*/ #ifndef BATMON_SENSOR_H_ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/platform.c b/arch/platform/simplelink/cc13xx-cc26xx/platform.c index 58474a809..ab40846a7 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/platform.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/platform.c @@ -108,9 +108,9 @@ fade(PIN_Id pin) j = (k > pivot_half) ? pivot - k : k; PINCC26XX_setOutputValue(pin, 1); - for (i = 0; i < j; ++i) { __asm__ __volatile__ ("nop"); } + for(i = 0; i < j; ++i) { __asm__ __volatile__ ("nop"); } PINCC26XX_setOutputValue(pin, 0); - for (i = 0; i < pivot_half - j; ++i) { __asm__ __volatile__ ("nop"); } + for(i = 0; i < pivot_half - j; ++i) { __asm__ __volatile__ ("nop"); } } } /*---------------------------------------------------------------------------*/ @@ -149,12 +149,12 @@ platform_init_stage_one(void) Power_init(); /* BoardGpioInitTable declared in Board.h */ - if (PIN_init(BoardGpioInitTable) != PIN_SUCCESS) { + if(PIN_init(BoardGpioInitTable) != PIN_SUCCESS) { /* * Something is seriously wrong if PIN initialization of the Board GPIO * table fails. */ - for (;;); + for(;;) { /* hang */ } } /* Perform board-specific initialization */ @@ -203,7 +203,7 @@ platform_init_stage_two(void) /* Use TRNG to seed PRNG. If TRNG fails, use a hard-coded seed. */ unsigned short seed = 0; - if (!trng_rand((uint8_t*)&seed, sizeof(seed), TRNG_WAIT_FOREVER)) { + if(!trng_rand((uint8_t*)&seed, sizeof(seed), TRNG_WAIT_FOREVER)) { /* Default to some hard-coded seed. */ seed = 0x1234; } @@ -239,9 +239,9 @@ platform_init_stage_three(void) ChipInfo_SupportsPROPRIETARY() ? "Yes" : "No", ChipInfo_SupportsBLE() ? "Yes" : "No"); -#if (RF_MODE == RF_MODE_SUB_1_GHZ) +#if(RF_MODE == RF_MODE_SUB_1_GHZ) LOG_INFO("Operating frequency on Sub-1 GHz\n"); -#elif (RF_MODE == RF_MODE_2_4_GHZ) +#elif(RF_MODE == RF_MODE_2_4_GHZ) LOG_INFO("Operating frequency on 2.4 GHz\n"); #endif LOG_INFO("RF: Channel %d, PANID 0x%04X\n", chan, pan); diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c index 372cfc81c..3795a77d5 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c @@ -181,7 +181,7 @@ i2c_write_read(void *writeBuf, size_t writeCount, void *readBuf, size_t readCoun static bool init(void) { - if (i2c_handle) { + if(i2c_handle) { return true; } @@ -192,7 +192,7 @@ init(void) i2cParams.bitRate = I2C_400kHz; i2c_handle = I2C_open(Board_I2C0, &i2cParams); - if (i2c_handle == NULL) { + if(i2c_handle == NULL) { return false; } @@ -310,7 +310,7 @@ convert(uint8_t *data, int32_t *temp, uint32_t *press) (32768 + v_x1_u32r) * (int32_t)p->dig_p1 ) >> 15; - if (v_x1_u32r == 0) { + if(v_x1_u32r == 0) { /* Avoid exception caused by division by zero */ *press = 0; return; @@ -322,7 +322,7 @@ convert(uint8_t *data, int32_t *temp, uint32_t *press) v_x2_u32r >> 12 ) ) * 3125; - if ((int32_t)pressure < 0) { + if((int32_t)pressure < 0) { pressure = (pressure << 1) / (uint32_t)v_x1_u32r; } else { pressure = (pressure / (uint32_t)v_x1_u32r) * 2; @@ -360,7 +360,7 @@ value(int type) int32_t temp = 0; uint32_t pres = 0; - if (sensor_status != SENSOR_STATUS_READY) { + if(sensor_status != SENSOR_STATUS_READY) { PRINTF("Sensor disabled or starting up (%d)\n", sensor_status); return BMP_280_READING_ERROR; } @@ -368,11 +368,11 @@ value(int type) /* A buffer for the raw reading from the sensor */ uint8_t sensor_value[MEAS_DATA_SIZE]; - switch (type) { + switch(type) { case BMP_280_SENSOR_TYPE_TEMP: case BMP_280_SENSOR_TYPE_PRESS: memset(sensor_value, 0, MEAS_DATA_SIZE); - if (!read_data(sensor_value, MEAS_DATA_SIZE)) { + if(!read_data(sensor_value, MEAS_DATA_SIZE)) { return BMP_280_READING_ERROR; } @@ -409,7 +409,7 @@ configure(int type, int enable) { switch(type) { case SENSORS_HW_INIT: - if (init()) { + if(init()) { enable_sensor(false); sensor_status = SENSOR_STATUS_INITIALISED; } else { @@ -419,10 +419,10 @@ configure(int type, int enable) case SENSORS_ACTIVE: /* Must be initialised first */ - if (sensor_status == SENSOR_STATUS_DISABLED) { + if(sensor_status == SENSOR_STATUS_DISABLED) { break; } - if (enable) { + if(enable) { enable_sensor(true); ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready, NULL); sensor_status = SENSOR_STATUS_NOT_READY; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.c index 2c2459225..84d760278 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/buzzer.c @@ -74,7 +74,7 @@ static volatile bool is_running; bool buzzer_init() { - if (has_init) { + if(has_init) { return true; } @@ -86,7 +86,7 @@ buzzer_init() gpt_params.debugStallMode = GPTimerCC26XX_DEBUG_STALL_OFF; gpt_handle = GPTimerCC26XX_open(Board_GPTIMER0A, &gpt_params); - if (!gpt_handle) { + if(!gpt_handle) { return false; } @@ -105,20 +105,20 @@ buzzer_running() bool buzzer_start(uint32_t freq) { - if (!has_init) { + if(!has_init) { return false; } - if (freq == 0) { + if(freq == 0) { return false; } - if (is_running) { + if(is_running) { return true; } pin_handle = PIN_open(&pin_state, pin_table); - if (!pin_handle) { + if(!pin_handle) { return false; } @@ -139,11 +139,11 @@ buzzer_start(uint32_t freq) void buzzer_stop() { - if (!gpt_handle) { + if(!gpt_handle) { return; } - if (!is_running) { + if(!is_running) { return; } diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.c index 64f1a01ce..47e724fa0 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.c @@ -170,7 +170,7 @@ i2c_read(void *rbuf, size_t rcount) static bool sensor_init(void) { - if (i2c_handle) { + if(i2c_handle) { return true; } @@ -181,7 +181,7 @@ sensor_init(void) i2c_params.bitRate = I2C_400kHz; i2c_handle = I2C_open(Board_I2C0, &i2c_params); - if (i2c_handle == NULL) { + if(i2c_handle == NULL) { return false; } @@ -230,7 +230,7 @@ notify_ready(void *unused) (void)unused; /* Latch readings */ - if (i2c_read(&sensor_data, sizeof(sensor_data))) { + if(i2c_read(&sensor_data, sizeof(sensor_data))) { sensor_status = HDC_1000_SENSOR_STATUS_READINGS_READY; } else { sensor_status = HDC_1000_SENSOR_STATUS_I2C_ERROR; @@ -250,20 +250,20 @@ value(int type) int32_t temp = 0; int32_t hum = 0; - if (sensor_status != HDC_1000_SENSOR_STATUS_READINGS_READY) { + if(sensor_status != HDC_1000_SENSOR_STATUS_READINGS_READY) { PRINTF("Sensor disabled or starting up (%d)\n", sensor_status); return HDC_1000_READING_ERROR; } - switch (type) { + switch(type) { case HDC_1000_SENSOR_TYPE_TEMP: case HDC_1000_SENSOR_TYPE_HUMID: convert(&temp, &hum); PRINTF("HDC: t=%d h=%d\n", (int)temp, (int)hum); - if (type == HDC_1000_SENSOR_TYPE_TEMP) { + if(type == HDC_1000_SENSOR_TYPE_TEMP) { return (int)temp; - } else if (type == HDC_1000_SENSOR_TYPE_HUMID) { + } else if(type == HDC_1000_SENSOR_TYPE_HUMID) { return (int)hum; } else { return HDC_1000_READING_ERROR; @@ -286,11 +286,11 @@ value(int type) static int configure(int type, int enable) { - switch (type) { + switch(type) { case SENSORS_HW_INIT: memset(&sensor_data, 0, sizeof(sensor_data)); - if (sensor_init()) { + if(sensor_init()) { sensor_status = HDC_1000_SENSOR_STATUS_INITIALISED; } else { sensor_status = HDC_1000_SENSOR_STATUS_I2C_ERROR; @@ -299,12 +299,12 @@ configure(int type, int enable) case SENSORS_ACTIVE: /* Must be initialised first */ - if (sensor_status == HDC_1000_SENSOR_STATUS_DISABLED) { + if(sensor_status == HDC_1000_SENSOR_STATUS_DISABLED) { break; } - if (enable) { - if (!start()) { + if(enable) { + if(!start()) { sensor_status = HDC_1000_SENSOR_STATUS_I2C_ERROR; break; } diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c index f6e9bcdca..a35a08367 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c @@ -283,7 +283,7 @@ static bool sensor_init(void) { pin_handle = PIN_open(&pin_state, mpu_9250_pin_table); - if (pin_handle == NULL) { + if(pin_handle == NULL) { return false; } @@ -293,7 +293,7 @@ sensor_init(void) i2cParams.bitRate = I2C_400kHz; i2c_handle = I2C_open(Board_I2C0, &i2cParams); - if (i2c_handle == NULL) { + if(i2c_handle == NULL) { PIN_close(&pin_state); return false; } @@ -399,14 +399,14 @@ sensor_data_ready(uint8_t* int_status) static bool acc_read(uint8_t int_status, uint16_t *data) { - if (!(int_status & BIT_RAW_RDY_EN)) { + if(!(int_status & BIT_RAW_RDY_EN)) { return false; } /* Burst read of all accelerometer values */ uint8_t accel_xout_h[] = { REG_ACCEL_XOUT_H }; bool spi_ok = i2c_write_read(accel_xout_h, sizeof(accel_xout_h), data, DATA_SIZE); - if (!spi_ok) { + if(!spi_ok) { return false; } @@ -422,14 +422,14 @@ acc_read(uint8_t int_status, uint16_t *data) static bool gyro_read(uint8_t int_status, uint16_t *data) { - if (!(int_status & BIT_RAW_RDY_EN)) { + if(!(int_status & BIT_RAW_RDY_EN)) { return false; } /* Burst read of all accelerometer values */ uint8_t gyro_xout_h[] = { REG_GYRO_XOUT_H }; bool spi_ok = i2c_write_read(gyro_xout_h, sizeof(gyro_xout_h), data, DATA_SIZE); - if (!spi_ok) { + if(!spi_ok) { return false; } @@ -446,7 +446,7 @@ gyro_read(uint8_t int_status, uint16_t *data) static int32_t acc_convert(int32_t raw_data) { - switch (mpu_9250.acc_range) { + switch(mpu_9250.acc_range) { case MPU_9250_SENSOR_ACC_RANGE_2G: return raw_data * 100 * 2 / 32768; case MPU_9250_SENSOR_ACC_RANGE_4G: return raw_data * 100 * 4 / 32768; case MPU_9250_SENSOR_ACC_RANGE_8G: return raw_data * 100 * 8 / 32768; @@ -481,7 +481,7 @@ initialise_cb(void *unused) { (void)unused; - if (mpu_9250.type == MPU_9250_SENSOR_TYPE_NONE) { + if(mpu_9250.type == MPU_9250_SENSOR_TYPE_NONE) { return; } @@ -489,7 +489,7 @@ initialise_cb(void *unused) sensor_wakeup(); /* Configure the accelerometer range */ - if ((mpu_9250.type & MPU_9250_SENSOR_TYPE_ACC) != 0) { + if((mpu_9250.type & MPU_9250_SENSOR_TYPE_ACC) != 0) { sensor_set_acc_range(mpu_9250.acc_range); } @@ -514,14 +514,14 @@ value(int type) return MPU_9250_READING_ERROR; } - if (mpu_9250.type == MPU_9250_SENSOR_TYPE_NONE) { + if(mpu_9250.type == MPU_9250_SENSOR_TYPE_NONE) { return MPU_9250_READING_ERROR; } uint8_t int_status = 0; const rtimer_clock_t t0 = RTIMER_NOW(); - while (!sensor_data_ready(&int_status)) { - if (!(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + READING_WAIT_TIMEOUT))) { + while(!sensor_data_ready(&int_status)) { + if(!(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + READING_WAIT_TIMEOUT))) { return MPU_9250_READING_ERROR; } } @@ -530,9 +530,9 @@ value(int type) memset(sensor_value, 0, sizeof(sensor_value)); /* Read accel data */ - if ((type & MPU_9250_SENSOR_TYPE_ACC) != 0) { + if((type & MPU_9250_SENSOR_TYPE_ACC) != 0) { - if (!acc_read(int_status, sensor_value)) { + if(!acc_read(int_status, sensor_value)) { return MPU_9250_READING_ERROR; } @@ -540,7 +540,7 @@ value(int type) sensor_value[0], sensor_value[1], sensor_value[2]); /* Convert */ - switch (type) { + switch(type) { case MPU_9250_SENSOR_TYPE_ACC_X: return acc_convert(sensor_value[0]); case MPU_9250_SENSOR_TYPE_ACC_Y: return acc_convert(sensor_value[1]); case MPU_9250_SENSOR_TYPE_ACC_Z: return acc_convert(sensor_value[2]); @@ -550,7 +550,7 @@ value(int type) /* Read gyro data */ } else if((type & MPU_9250_SENSOR_TYPE_GYRO) != 0) { - if (!gyro_read(int_status, sensor_value)) { + if(!gyro_read(int_status, sensor_value)) { return MPU_9250_READING_ERROR; } @@ -558,7 +558,7 @@ value(int type) sensor_value[0], sensor_value[1], sensor_value[2]); /* Convert */ - switch (type) { + switch(type) { case MPU_9250_SENSOR_TYPE_GYRO_X: return gyro_convert(sensor_value[0]); case MPU_9250_SENSOR_TYPE_GYRO_Y: return gyro_convert(sensor_value[1]); case MPU_9250_SENSOR_TYPE_GYRO_Z: return gyro_convert(sensor_value[2]); @@ -588,7 +588,7 @@ configure(int type, int enable) switch(type) { case SENSORS_HW_INIT: - if (sensor_init()) { + if(sensor_init()) { mpu_9250.status = MPU_9250_SENSOR_STATUS_ENABLED; } else { mpu_9250.status = MPU_9250_SENSOR_STATUS_DISABLED; @@ -596,7 +596,7 @@ configure(int type, int enable) break; case SENSORS_ACTIVE: - if (enable_type != MPU_9250_SENSOR_TYPE_NONE) { + if(enable_type != MPU_9250_SENSOR_TYPE_NONE) { PRINTF("MPU: Enabling\n"); mpu_9250.type = enable_type; @@ -610,7 +610,7 @@ configure(int type, int enable) ctimer_stop(&startup_timer); - if (PIN_getOutputValue(Board_MPU_POWER)) { + if(PIN_getOutputValue(Board_MPU_POWER)) { sensor_sleep(); I2C_cancel(i2c_handle); @@ -636,7 +636,7 @@ configure(int type, int enable) static int status(int type) { - switch (type) { + switch(type) { case SENSORS_ACTIVE: case SENSORS_READY: return mpu_9250.status; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.c index a7774414a..f846e42a1 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.c @@ -195,7 +195,7 @@ i2c_read(void *rbuf, size_t rcount) static bool sensor_init(void) { - if (i2c_handle) { + if(i2c_handle) { return true; } @@ -206,7 +206,7 @@ sensor_init(void) i2c_params.bitRate = I2C_400kHz; i2c_handle = I2C_open(Board_I2C0, &i2c_params); - if (i2c_handle == NULL) { + if(i2c_handle == NULL) { return false; } @@ -249,12 +249,12 @@ notify_ready_cb(void *unused) uint16_t cfg_value = 0; bool spi_ok = i2c_write_read(cfg_data, sizeof(cfg_data), &cfg_value, sizeof(cfg_value)); - if (!spi_ok) { + if(!spi_ok) { opt_3001.status = OPT_3001_STATUS_I2C_ERROR; return; } - if (cfg_value & CFG_CRF) { + if(cfg_value & CFG_CRF) { opt_3001.status = OPT_3001_STATUS_DATA_READY; sensors_changed(&opt_3001_sensor); } else { @@ -273,7 +273,7 @@ value(int type) /* Unused args */ (void)type; - if (opt_3001.status != OPT_3001_STATUS_DATA_READY) { + if(opt_3001.status != OPT_3001_STATUS_DATA_READY) { return OPT_3001_READING_ERROR; } @@ -281,7 +281,7 @@ value(int type) uint16_t cfg_value = 0; bool spi_ok = i2c_write_read(cfg_data, sizeof(cfg_data), &cfg_value, sizeof(cfg_value)); - if (!spi_ok) { + if(!spi_ok) { opt_3001.status = OPT_3001_STATUS_I2C_ERROR; return OPT_3001_READING_ERROR; } @@ -290,7 +290,7 @@ value(int type) uint16_t result_value = 0; spi_ok = i2c_write_read(result_data, sizeof(result_data), &result_value, sizeof(result_value)); - if (!spi_ok) { + if(!spi_ok) { opt_3001.status = OPT_3001_STATUS_I2C_ERROR; return OPT_3001_READING_ERROR; } @@ -322,7 +322,7 @@ configure(int type, int enable) int rv = 0; switch(type) { case SENSORS_HW_INIT: - if (sensor_init()) { + if(sensor_init()) { opt_3001.status = OPT_3001_STATUS_STANDBY; } else { opt_3001.status = OPT_3001_STATUS_DISABLED; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c index 48c5ed5b9..8c6b5e8d7 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c @@ -183,12 +183,12 @@ i2c_read(void *rbuf, size_t rcount) static bool sensor_init(void) { - if (pin_handle && i2c_handle) { + if(pin_handle && i2c_handle) { return true; } pin_handle = PIN_open(&pin_state, pin_table); - if (!pin_handle) { + if(!pin_handle) { return false; } @@ -199,7 +199,7 @@ sensor_init(void) i2c_params.bitRate = I2C_400kHz; i2c_handle = I2C_open(Board_I2C0, &i2c_params); - if (i2c_handle == NULL) { + if(i2c_handle == NULL) { PIN_close(pin_handle); return false; } @@ -252,12 +252,12 @@ read_data(uint16_t *local_tmp, uint16_t *obj_tmp) spi_ok = i2c_write_read(status_data, sizeof(status_data), &status_value, sizeof(status_value)); - if (!spi_ok) { + if(!spi_ok) { return false; } status_value = SWAP16(status_value); - if ((status_value & CONV_RDY_BIT) == 0) { + if((status_value & CONV_RDY_BIT) == 0) { return false; } @@ -266,7 +266,7 @@ read_data(uint16_t *local_tmp, uint16_t *obj_tmp) spi_ok = i2c_write_read(local_temp_data, sizeof(local_temp_data), &local_temp_value, sizeof(local_temp_value)); - if (!spi_ok) { + if(!spi_ok) { return false; } @@ -275,7 +275,7 @@ read_data(uint16_t *local_tmp, uint16_t *obj_tmp) spi_ok = i2c_write_read(obj_temp_data, sizeof(obj_temp_data), &obj_temp_value, sizeof(obj_temp_value)); - if (!spi_ok) { + if(!spi_ok) { return false; } @@ -316,17 +316,17 @@ value(int type) uint16_t raw_local_tmp = 0, local_tmp = 0; uint16_t raw_obj_tmp = 0, obj_tmp = 0; - if (tmp_007.status != TMP_007_STATUS_READY) { + if(tmp_007.status != TMP_007_STATUS_READY) { PRINTF("Sensor disabled or starting up (%d)\n", tmp_007.status); return TMP_007_READING_ERROR; } - switch (type) { + switch(type) { case TMP_007_TYPE_OBJECT: return tmp_007.obj_tmp_latched; case TMP_007_TYPE_AMBIENT: return tmp_007.local_tmp_latched; case TMP_007_TYPE_ALL: - if (!read_data(&raw_local_tmp, &raw_obj_tmp)) { + if(!read_data(&raw_local_tmp, &raw_obj_tmp)) { return TMP_007_READING_ERROR; } @@ -360,9 +360,9 @@ value(int type) static int configure(int type, int enable) { - switch (type) { + switch(type) { case SENSORS_HW_INIT: - if (!sensor_init()) { + if(!sensor_init()) { return TMP_007_STATUS_DISABLED; } @@ -373,10 +373,10 @@ configure(int type, int enable) case SENSORS_ACTIVE: /* Must be initialised first */ - if (tmp_007.status == TMP_007_STATUS_DISABLED) { + if(tmp_007.status == TMP_007_STATUS_DISABLED) { return TMP_007_STATUS_DISABLED; } - if (enable) { + if(enable) { enable_sensor(true); ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready_cb, NULL); tmp_007.status = TMP_007_STATUS_NOT_READY; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/als-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/als-sensor.c index d4a5bbb04..4f625943b 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/als-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/als-sensor.c @@ -59,7 +59,7 @@ init(void) ADC_Params_init(&adc_params); adc_handle = ADC_open(Board_ADCALS, &adc_params); - if (adc_handle == NULL) { + if(adc_handle == NULL) { return 0; } @@ -97,7 +97,7 @@ value(int type) uint16_t adc_value = 0; int_fast16_t res = ADC_convert(adc_handle, &adc_value); - if (res != ADC_STATUS_SUCCESS) { + if(res != ADC_STATUS_SUCCESS) { return -1; } From c2906383232c67be3012a67a1a8de45547e15b8b Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Mon, 23 Jul 2018 18:53:53 +0200 Subject: [PATCH 285/485] Nicer comment --- Makefile.include | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.include b/Makefile.include index 27b0ca110..7643455b5 100644 --- a/Makefile.include +++ b/Makefile.include @@ -41,8 +41,8 @@ endif # Prevent Make from remaking any makefiles. This was particularly an # issue when you had a Makefile with a suffix equal to that of $(TARGET), -# as it managed to match with the %.$(TARGET) rule, which in turn fucked up -# everything. Now this isn't the case. +# as it managed to match with the %.$(TARGET) rule, which in turn screwed +# everything up. Makefile.%: ; OBJECTDIR := obj_$(TARGET) From 3031be39a81fb6d5000a4eb83f55faff0dccc239 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Mon, 23 Jul 2018 19:23:13 +0200 Subject: [PATCH 286/485] Added BOARD_STRING --- arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Board.h | 1 + .../platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Board.h | 1 + .../platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Board.h | 1 + arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Board.h | 1 + .../simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/Board.h | 1 + .../simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/Board.h | 1 + .../platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Board.h | 1 + .../platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h | 1 + arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Board.h | 1 + .../platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Board.h | 1 + arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h | 1 + arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h | 1 + arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Board.h | 1 + arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Board.h | 1 + 14 files changed, 14 insertions(+) diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Board.h index 30aafeffe..67b79dc2a 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/Board.h @@ -34,6 +34,7 @@ #define __BOARD_H #define Board_CC1310_LAUNCHXL +#define BOARD_STRING "TI CC1310 LaunchPad" #ifdef __cplusplus extern "C" { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Board.h index 3a08792dd..92ddab790 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/Board.h @@ -34,6 +34,7 @@ #define __BOARD_H #define Board_CC1312R1_LAUNCHXL +#define BOARD_STRING "TI CC1312R1 LaunchPad" #ifdef __cplusplus extern "C" { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Board.h index 394f3a3cd..a10c225c8 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/Board.h @@ -34,6 +34,7 @@ #define __BOARD_H #define Board_CC1350_LAUNCHXL_433 +#define BOARD_STRING "TI CC1350-433 LaunchPad" #ifdef __cplusplus extern "C" { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Board.h index a695a57cc..e3aea2847 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/Board.h @@ -34,6 +34,7 @@ #define __BOARD_H #define Board_CC1350_LAUNCHXL +#define BOARD_STRING "TI CC1350 LaunchPad" #ifdef __cplusplus extern "C" { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/Board.h index 7fe300916..51b9fc4c2 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/Board.h @@ -34,6 +34,7 @@ #define __BOARD_H #define Board_CC1352P_2_LAUNCHXL +#define BOARD_STRING "TI CC1352P-2 LaunchPad" #ifdef __cplusplus extern "C" { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/Board.h index 752f8d88f..db91700f8 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/Board.h @@ -34,6 +34,7 @@ #define __BOARD_H #define Board_CC1352P_4_LAUNCHXL +#define BOARD_STRING "TI CC1352P-4 LaunchPad" #ifdef __cplusplus extern "C" { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Board.h index c078fe636..f0a8f0042 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/Board.h @@ -34,6 +34,7 @@ #define __BOARD_H #define Board_CC1352P1_LAUNCHXL +#define BOARD_STRING "TI CC1352P1 LaunchPad" #ifdef __cplusplus extern "C" { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h index 9cc52d689..a70dc6568 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/Board.h @@ -34,6 +34,7 @@ #define __BOARD_H #define Board_CC1352R1_LAUNCHXL +#define BOARD_STRING "TI CC1352R1 LaunchPad" #ifdef __cplusplus extern "C" { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Board.h index 5088d0ea6..38cc87207 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/Board.h @@ -34,6 +34,7 @@ #define __BOARD_H #define Board_CC2650_LAUNCHXL +#define BOARD_STRING "TI CC2650 LaunchPad" #ifdef __cplusplus extern "C" { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Board.h index 8940527b9..e44623aa0 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/Board.h @@ -34,6 +34,7 @@ #define __BOARD_H #define Board_CC26X2R1_LAUNCHXL +#define BOARD_STRING "TI CC26x2R1 LaunchPad" #ifdef __cplusplus extern "C" { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h index 58e661f78..283dfe9a5 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/Board.h @@ -34,6 +34,7 @@ #define __BOARD_H #define Board_CC1350STK +#define BOARD_STRING "TI CC1350 SensorTag" #ifdef __cplusplus extern "C" { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h index 830bbf63c..b1b84e0eb 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Board.h @@ -34,6 +34,7 @@ #define __BOARD_H #define Board_CC2650STK +#define BOARD_STRING "TI CC2650 SensorTag" #ifdef __cplusplus extern "C" { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Board.h index 3f2c0421d..6d352a9dc 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/Board.h @@ -34,6 +34,7 @@ #define __BOARD_H #define Board_CC1350DK_7XD +#define BOARD_STRING "TI SmartRF06EB + CC13x0 EM" #ifdef __cplusplus extern "C" { diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Board.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Board.h index b1a7b6a94..df2a32790 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Board.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/Board.h @@ -34,6 +34,7 @@ #define __BOARD_H #define Board_CC2650DK_7ID +#define BOARD_STRING "TI SmartRF06EB + CC26x0 EM" #ifdef __cplusplus extern "C" { From b605e9b43fd091957df34458d7030dbf7ef2c5a1 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Mon, 23 Jul 2018 19:23:51 +0200 Subject: [PATCH 287/485] Aligned Board Button HAL naming --- arch/platform/srf06-cc26xx/launchpad/board-buttons.c | 4 ++-- arch/platform/srf06-cc26xx/launchpad/cc1310/board.h | 4 ++-- arch/platform/srf06-cc26xx/launchpad/cc1350/board.h | 4 ++-- arch/platform/srf06-cc26xx/launchpad/cc2650/board.h | 4 ++-- arch/platform/srf06-cc26xx/sensortag/board-buttons.c | 6 +++--- arch/platform/srf06-cc26xx/sensortag/cc1350/board.h | 6 +++--- arch/platform/srf06-cc26xx/sensortag/cc2650/board.h | 6 +++--- arch/platform/srf06-cc26xx/srf06/board-buttons.c | 10 +++++----- arch/platform/srf06-cc26xx/srf06/cc13xx/board.h | 10 +++++----- arch/platform/srf06-cc26xx/srf06/cc26xx/board.h | 10 +++++----- examples/platform-specific/cc26xx/cc26xx-demo.c | 6 +++--- .../cc26xx/cc26xx-web-demo/cc26xx-web-demo.h | 8 ++++---- .../cc26xx/very-sleepy-demo/very-sleepy-demo.c | 2 +- 13 files changed, 40 insertions(+), 40 deletions(-) diff --git a/arch/platform/srf06-cc26xx/launchpad/board-buttons.c b/arch/platform/srf06-cc26xx/launchpad/board-buttons.c index a0e9fa6f2..1850684c3 100644 --- a/arch/platform/srf06-cc26xx/launchpad/board-buttons.c +++ b/arch/platform/srf06-cc26xx/launchpad/board-buttons.c @@ -43,11 +43,11 @@ #include "ti-lib.h" /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTON(key_left, "Key Left", BOARD_IOID_KEY_LEFT, \ - GPIO_HAL_PIN_CFG_INPUT_PULLUP, BOARD_BUTTON_HAL_INDEX_KEY_LEFT, \ + GPIO_HAL_PIN_CFG_INPUT_PULLUP, BUTTON_HAL_ID_KEY_LEFT, \ true); BUTTON_HAL_BUTTON(key_right, "Key Right", BOARD_IOID_KEY_RIGHT, \ - GPIO_HAL_PIN_CFG_INPUT_PULLUP, BOARD_BUTTON_HAL_INDEX_KEY_RIGHT, \ + GPIO_HAL_PIN_CFG_INPUT_PULLUP, BUTTON_HAL_ID_KEY_RIGHT, \ true); /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTONS(&key_left, &key_right); diff --git a/arch/platform/srf06-cc26xx/launchpad/cc1310/board.h b/arch/platform/srf06-cc26xx/launchpad/cc1310/board.h index 41e929571..2363ccf79 100644 --- a/arch/platform/srf06-cc26xx/launchpad/cc1310/board.h +++ b/arch/platform/srf06-cc26xx/launchpad/cc1310/board.h @@ -198,8 +198,8 @@ * Those values are not meant to be modified by the user * @{ */ -#define BOARD_BUTTON_HAL_INDEX_KEY_LEFT 0x00 -#define BOARD_BUTTON_HAL_INDEX_KEY_RIGHT 0x01 +#define BUTTON_HAL_ID_KEY_LEFT 0x00 +#define BUTTON_HAL_ID_KEY_RIGHT 0x01 /** @} */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/srf06-cc26xx/launchpad/cc1350/board.h b/arch/platform/srf06-cc26xx/launchpad/cc1350/board.h index 643d69e0b..cca7e0b1a 100644 --- a/arch/platform/srf06-cc26xx/launchpad/cc1350/board.h +++ b/arch/platform/srf06-cc26xx/launchpad/cc1350/board.h @@ -214,8 +214,8 @@ * Those values are not meant to be modified by the user * @{ */ -#define BOARD_BUTTON_HAL_INDEX_KEY_LEFT 0x00 -#define BOARD_BUTTON_HAL_INDEX_KEY_RIGHT 0x01 +#define BUTTON_HAL_ID_KEY_LEFT 0x00 +#define BUTTON_HAL_ID_KEY_RIGHT 0x01 /** @} */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/srf06-cc26xx/launchpad/cc2650/board.h b/arch/platform/srf06-cc26xx/launchpad/cc2650/board.h index 822e776b8..5ea73c692 100644 --- a/arch/platform/srf06-cc26xx/launchpad/cc2650/board.h +++ b/arch/platform/srf06-cc26xx/launchpad/cc2650/board.h @@ -199,8 +199,8 @@ * Those values are not meant to be modified by the user * @{ */ -#define BOARD_BUTTON_HAL_INDEX_KEY_LEFT 0x00 -#define BOARD_BUTTON_HAL_INDEX_KEY_RIGHT 0x01 +#define BUTTON_HAL_ID_KEY_LEFT 0x00 +#define BUTTON_HAL_ID_KEY_RIGHT 0x01 /** @} */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/srf06-cc26xx/sensortag/board-buttons.c b/arch/platform/srf06-cc26xx/sensortag/board-buttons.c index 4a1b02ed5..73fc178bd 100644 --- a/arch/platform/srf06-cc26xx/sensortag/board-buttons.c +++ b/arch/platform/srf06-cc26xx/sensortag/board-buttons.c @@ -47,14 +47,14 @@ /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTON(reed_relay, "Reed Relay", BOARD_IOID_REED_RELAY, \ GPIO_HAL_PIN_CFG_PULL_DOWN, \ - BOARD_BUTTON_HAL_INDEX_REED_RELAY, true); + BUTTON_HAL_ID_REED_RELAY, true); BUTTON_HAL_BUTTON(key_left, "Key Left", BOARD_IOID_KEY_LEFT, \ - GPIO_HAL_PIN_CFG_PULL_UP, BOARD_BUTTON_HAL_INDEX_KEY_LEFT, \ + GPIO_HAL_PIN_CFG_PULL_UP, BUTTON_HAL_ID_KEY_LEFT, \ true); BUTTON_HAL_BUTTON(key_right, "Key Right", BOARD_IOID_KEY_RIGHT, \ - GPIO_HAL_PIN_CFG_PULL_UP, BOARD_BUTTON_HAL_INDEX_KEY_RIGHT, \ + GPIO_HAL_PIN_CFG_PULL_UP, BUTTON_HAL_ID_KEY_RIGHT, \ true); /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTONS(&reed_relay, &key_left, &key_right); diff --git a/arch/platform/srf06-cc26xx/sensortag/cc1350/board.h b/arch/platform/srf06-cc26xx/sensortag/cc1350/board.h index 6fdab1295..140838605 100644 --- a/arch/platform/srf06-cc26xx/sensortag/cc1350/board.h +++ b/arch/platform/srf06-cc26xx/sensortag/cc1350/board.h @@ -248,9 +248,9 @@ * Those values are not meant to be modified by the user * @{ */ -#define BOARD_BUTTON_HAL_INDEX_KEY_LEFT 0x00 -#define BOARD_BUTTON_HAL_INDEX_KEY_RIGHT 0x01 -#define BOARD_BUTTON_HAL_INDEX_REED_RELAY 0xFF +#define BUTTON_HAL_ID_KEY_LEFT 0x00 +#define BUTTON_HAL_ID_KEY_RIGHT 0x01 +#define BUTTON_HAL_ID_REED_RELAY 0xFF /** @} */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/srf06-cc26xx/sensortag/cc2650/board.h b/arch/platform/srf06-cc26xx/sensortag/cc2650/board.h index dda3e46e5..d0109db42 100644 --- a/arch/platform/srf06-cc26xx/sensortag/cc2650/board.h +++ b/arch/platform/srf06-cc26xx/sensortag/cc2650/board.h @@ -229,9 +229,9 @@ * Those values are not meant to be modified by the user * @{ */ -#define BOARD_BUTTON_HAL_INDEX_KEY_LEFT 0x00 -#define BOARD_BUTTON_HAL_INDEX_KEY_RIGHT 0x01 -#define BOARD_BUTTON_HAL_INDEX_REED_RELAY 0xFF +#define BUTTON_HAL_ID_KEY_LEFT 0x00 +#define BUTTON_HAL_ID_KEY_RIGHT 0x01 +#define BUTTON_HAL_ID_REED_RELAY 0xFF /** @} */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/srf06-cc26xx/srf06/board-buttons.c b/arch/platform/srf06-cc26xx/srf06/board-buttons.c index c0db8daaa..db06cfcc0 100644 --- a/arch/platform/srf06-cc26xx/srf06/board-buttons.c +++ b/arch/platform/srf06-cc26xx/srf06/board-buttons.c @@ -43,20 +43,20 @@ #include "ti-lib.h" /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTON(key_left, "Key Left", BOARD_IOID_KEY_LEFT, \ - GPIO_HAL_PIN_CFG_PULL_UP, BOARD_BUTTON_HAL_INDEX_KEY_LEFT, \ + GPIO_HAL_PIN_CFG_PULL_UP, BUTTON_HAL_ID_KEY_LEFT, \ true); BUTTON_HAL_BUTTON(key_right, "Key Right", BOARD_IOID_KEY_RIGHT, \ - GPIO_HAL_PIN_CFG_PULL_UP, BOARD_BUTTON_HAL_INDEX_KEY_RIGHT, \ + GPIO_HAL_PIN_CFG_PULL_UP, BUTTON_HAL_ID_KEY_RIGHT, \ true); BUTTON_HAL_BUTTON(key_up, "Key Up", BOARD_IOID_KEY_UP, \ - GPIO_HAL_PIN_CFG_PULL_UP, BOARD_BUTTON_HAL_INDEX_KEY_UP, \ + GPIO_HAL_PIN_CFG_PULL_UP, BUTTON_HAL_ID_KEY_UP, \ true); BUTTON_HAL_BUTTON(key_down, "Key Down", BOARD_IOID_KEY_DOWN, \ - GPIO_HAL_PIN_CFG_PULL_UP, BOARD_BUTTON_HAL_INDEX_KEY_DOWN, \ + GPIO_HAL_PIN_CFG_PULL_UP, BUTTON_HAL_ID_KEY_DOWN, \ true); BUTTON_HAL_BUTTON(key_select, "Key Select", BOARD_IOID_KEY_SELECT, \ GPIO_HAL_PIN_CFG_PULL_UP, \ - BOARD_BUTTON_HAL_INDEX_KEY_SELECT, true); + BUTTON_HAL_ID_KEY_SELECT, true); /*---------------------------------------------------------------------------*/ BUTTON_HAL_BUTTONS(&key_left, &key_right, &key_up, &key_down, &key_select); /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/srf06-cc26xx/srf06/cc13xx/board.h b/arch/platform/srf06-cc26xx/srf06/cc13xx/board.h index 9fece9180..431aac628 100644 --- a/arch/platform/srf06-cc26xx/srf06/cc13xx/board.h +++ b/arch/platform/srf06-cc26xx/srf06/cc13xx/board.h @@ -238,11 +238,11 @@ * Those values are not meant to be modified by the user * @{ */ -#define BOARD_BUTTON_HAL_INDEX_KEY_LEFT 0x00 -#define BOARD_BUTTON_HAL_INDEX_KEY_RIGHT 0x01 -#define BOARD_BUTTON_HAL_INDEX_KEY_UP 0x02 -#define BOARD_BUTTON_HAL_INDEX_KEY_DOWN 0x03 -#define BOARD_BUTTON_HAL_INDEX_KEY_SELECT 0x04 +#define BUTTON_HAL_ID_KEY_LEFT 0x00 +#define BUTTON_HAL_ID_KEY_RIGHT 0x01 +#define BUTTON_HAL_ID_KEY_UP 0x02 +#define BUTTON_HAL_ID_KEY_DOWN 0x03 +#define BUTTON_HAL_ID_KEY_SELECT 0x04 /** @} */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/srf06-cc26xx/srf06/cc26xx/board.h b/arch/platform/srf06-cc26xx/srf06/cc26xx/board.h index b9171388a..39db0374f 100644 --- a/arch/platform/srf06-cc26xx/srf06/cc26xx/board.h +++ b/arch/platform/srf06-cc26xx/srf06/cc26xx/board.h @@ -238,11 +238,11 @@ * Those values are not meant to be modified by the user * @{ */ -#define BOARD_BUTTON_HAL_INDEX_KEY_LEFT 0x00 -#define BOARD_BUTTON_HAL_INDEX_KEY_RIGHT 0x01 -#define BOARD_BUTTON_HAL_INDEX_KEY_UP 0x02 -#define BOARD_BUTTON_HAL_INDEX_KEY_DOWN 0x03 -#define BOARD_BUTTON_HAL_INDEX_KEY_SELECT 0x04 +#define BUTTON_HAL_ID_KEY_LEFT 0x00 +#define BUTTON_HAL_ID_KEY_RIGHT 0x01 +#define BUTTON_HAL_ID_KEY_UP 0x02 +#define BUTTON_HAL_ID_KEY_DOWN 0x03 +#define BUTTON_HAL_ID_KEY_SELECT 0x04 /** @} */ /*---------------------------------------------------------------------------*/ /** diff --git a/examples/platform-specific/cc26xx/cc26xx-demo.c b/examples/platform-specific/cc26xx/cc26xx-demo.c index 8c90905af..acc3ca823 100644 --- a/examples/platform-specific/cc26xx/cc26xx-demo.c +++ b/examples/platform-specific/cc26xx/cc26xx-demo.c @@ -98,11 +98,11 @@ #define CC26XX_DEMO_LEDS_BUTTON LEDS_RED #define CC26XX_DEMO_LEDS_REBOOT LEDS_ALL /*---------------------------------------------------------------------------*/ -#define CC26XX_DEMO_TRIGGER_1 BOARD_BUTTON_HAL_INDEX_KEY_LEFT -#define CC26XX_DEMO_TRIGGER_2 BOARD_BUTTON_HAL_INDEX_KEY_RIGHT +#define CC26XX_DEMO_TRIGGER_1 BUTTON_HAL_ID_KEY_LEFT +#define CC26XX_DEMO_TRIGGER_2 BUTTON_HAL_ID_KEY_RIGHT #if BOARD_SENSORTAG -#define CC26XX_DEMO_TRIGGER_3 BOARD_BUTTON_HAL_INDEX_REED_RELAY +#define CC26XX_DEMO_TRIGGER_3 BUTTON_HAL_ID_REED_RELAY #endif /*---------------------------------------------------------------------------*/ static struct etimer et; diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/cc26xx-web-demo.h b/examples/platform-specific/cc26xx/cc26xx-web-demo/cc26xx-web-demo.h index 0761725c7..1840c31b1 100644 --- a/examples/platform-specific/cc26xx/cc26xx-web-demo/cc26xx-web-demo.h +++ b/examples/platform-specific/cc26xx/cc26xx-web-demo/cc26xx-web-demo.h @@ -98,18 +98,18 @@ /*---------------------------------------------------------------------------*/ /* User configuration */ /* Take a sensor reading on button press */ -#define CC26XX_WEB_DEMO_SENSOR_READING_TRIGGER BOARD_BUTTON_HAL_INDEX_KEY_LEFT +#define CC26XX_WEB_DEMO_SENSOR_READING_TRIGGER BUTTON_HAL_ID_KEY_LEFT /* Payload length of ICMPv6 echo requests used to measure RSSI with def rt */ #define CC26XX_WEB_DEMO_ECHO_REQ_PAYLOAD_LEN 20 #if BOARD_SENSORTAG /* Force an MQTT publish on sensor event */ -#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BOARD_BUTTON_HAL_INDEX_REED_RELAY +#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BUTTON_HAL_ID_REED_RELAY #elif BOARD_LAUNCHPAD -#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BOARD_BUTTON_HAL_INDEX_KEY_LEFT +#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BUTTON_HAL_ID_KEY_LEFT #else -#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BOARD_BUTTON_HAL_INDEX_KEY_DOWN +#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER BUTTON_HAL_ID_KEY_DOWN #endif #define CC26XX_WEB_DEMO_STATUS_LED LEDS_GREEN 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 ebd55712b..d707f3cd1 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 @@ -63,7 +63,7 @@ #define VERY_SLEEPY_MODE_OFF 0 #define VERY_SLEEPY_MODE_ON 1 /*---------------------------------------------------------------------------*/ -#define BUTTON_TRIGGER BOARD_BUTTON_HAL_INDEX_KEY_LEFT +#define BUTTON_TRIGGER BUTTON_HAL_ID_KEY_LEFT /*---------------------------------------------------------------------------*/ #define MAC_CAN_BE_TURNED_OFF 0 #define MAC_MUST_STAY_ON 1 From ca2e82a45968e54a468fd6d4d6a98363fd9dc50a Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Tue, 24 Jul 2018 12:16:53 +0200 Subject: [PATCH 288/485] Uncrustify code style --- arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h | 82 ++++++++-------- arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-def.h | 10 +- arch/cpu/cc13xx-cc26xx/ccfg-conf.h | 28 +++--- arch/cpu/cc13xx-cc26xx/dev/clock-arch.c | 2 +- arch/cpu/cc13xx-cc26xx/dev/dbg-arch.c | 8 +- arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c | 7 +- arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c | 18 ++-- .../dev/startup_cc13xx_cc26xx_gcc.c | 55 +++++------ .../dev/startup_cc13xx_cc26xx_iar.c | 85 ++++++++-------- arch/cpu/cc13xx-cc26xx/dev/trng-arch.c | 4 +- .../cc13xx-cc26xx/rf-settings/rf-settings.h | 4 +- arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c | 20 ++-- arch/cpu/cc13xx-cc26xx/rf/ble-beacond.h | 6 +- arch/cpu/cc13xx-cc26xx/rf/data-queue.c | 2 +- arch/cpu/cc13xx-cc26xx/rf/dot-15-4g.h | 96 +++++++++---------- arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c | 75 ++++++++------- arch/cpu/cc13xx-cc26xx/rf/prop-mode.c | 79 ++++++++------- arch/cpu/cc13xx-cc26xx/rf/sched.c | 33 ++++--- arch/cpu/cc13xx-cc26xx/rf/sched.h | 4 +- 19 files changed, 308 insertions(+), 310 deletions(-) diff --git a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h index 2a3b7cbde..08e5a4916 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h +++ b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h @@ -74,7 +74,7 @@ #ifndef WATCHDOG_CONF_TIMER_TOP #define WATCHDOG_CONF_TIMER_TOP 0xFFFFF #endif - /** @} */ +/** @} */ /*---------------------------------------------------------------------------*/ /** * \name RF configuration. @@ -88,9 +88,9 @@ * or larger guard time. */ #ifndef RF_CONF_FAST_RADIO_STARTUP -# define RF_FAST_RADIO_STARTUP (MAC_CONF_WITH_TSCH) +#define RF_FAST_RADIO_STARTUP (MAC_CONF_WITH_TSCH) #else -# define RF_FAST_RADIO_STARTUP RF_CONF_FAST_RADIO_STARTUP +#define RF_FAST_RADIO_STARTUP RF_CONF_FAST_RADIO_STARTUP #endif /* @@ -102,7 +102,7 @@ #endif #if (RF_CONF_TXPOWER_HIGH_PA) && !(SUPPORTS_HIGH_PA) -# error "Device does not support High PA" +#error "Device does not support High PA" #endif /* @@ -120,36 +120,36 @@ */ #ifdef RF_CONF_MODE /* Sanity check a valid configuration is provided. */ -# if !(RF_CONF_MODE & RF_MODE_BM) -# error "Invalid RF_CONF_MODE provided" -# endif +#if !(RF_CONF_MODE & RF_MODE_BM) +#error "Invalid RF_CONF_MODE provided" +#endif -# define RF_MODE RF_CONF_MODE +#define RF_MODE RF_CONF_MODE #endif /* RF_CONF_MODE */ /* Number of RX buffers. */ #ifdef RF_CONF_RX_BUF_CNT -# define RF_RX_BUF_CNT RF_CONF_RX_BUF_CNT +#define RF_RX_BUF_CNT RF_CONF_RX_BUF_CNT #else -# define RF_RX_BUF_CNT 4 +#define RF_RX_BUF_CNT 4 #endif /* Size of each RX buffer in bytes. */ #ifdef RF_CONF_RX_BUF_SIZE -# define RF_RX_BUF_SIZE RF_CONF_RX_BUF_SIZE +#define RF_RX_BUF_SIZE RF_CONF_RX_BUF_SIZE #else -# define RF_RX_BUF_SIZE 144 +#define RF_RX_BUF_SIZE 144 #endif /* Enable/disable BLE beacon. */ #ifdef RF_CONF_BLE_BEACON_ENABLE -# define RF_BLE_BEACON_ENABLE RF_CONF_BLE_BEACON_ENABLE +#define RF_BLE_BEACON_ENABLE RF_CONF_BLE_BEACON_ENABLE #else -# define RF_BLE_BEACON_ENABLE 0 +#define RF_BLE_BEACON_ENABLE 0 #endif #if (RF_BLE_BEACON_ENABLE) && !(SUPPORTS_BLE_BEACON) -# error "Device does not support BLE for BLE beacon" +#error "Device does not support BLE for BLE beacon" #endif /*----- CC13xx Device Line --------------------------------------------------*/ @@ -157,65 +157,65 @@ #if defined(DEVICE_LINE_CC13XX) /* Default to Prop-mode for CC13xx devices if not configured. */ -# ifndef RF_MODE -# define RF_MODE RF_MODE_SUB_1_GHZ -# endif +#ifndef RF_MODE +#define RF_MODE RF_MODE_SUB_1_GHZ +#endif /*----- CC13xx Prop-mode ----------------------------------------------------*/ -# if (RF_MODE == RF_MODE_SUB_1_GHZ) && (SUPPORTS_PROP_MODE) +#if (RF_MODE == RF_MODE_SUB_1_GHZ) && (SUPPORTS_PROP_MODE) /* Netstack configuration. */ -# define NETSTACK_CONF_RADIO prop_mode_driver +#define NETSTACK_CONF_RADIO prop_mode_driver /* CSMA configuration. */ -# define CSMA_CONF_ACK_WAIT_TIME (RTIMER_SECOND / 300) -# define CSMA_CONF_AFTER_ACK_DETECTED_WAIT_TIME (RTIMER_SECOND / 1000) -# define CSMA_CONF_SEND_SOFT_ACK 1 +#define CSMA_CONF_ACK_WAIT_TIME (RTIMER_SECOND / 300) +#define CSMA_CONF_AFTER_ACK_DETECTED_WAIT_TIME (RTIMER_SECOND / 1000) +#define CSMA_CONF_SEND_SOFT_ACK 1 /*----- CC13xx IEEE-mode ----------------------------------------------------*/ -# elif (RF_MODE == RF_MODE_2_4_GHZ) && (SUPPORTS_IEEE_MODE) +#elif (RF_MODE == RF_MODE_2_4_GHZ) && (SUPPORTS_IEEE_MODE) /* Netstack configuration. */ -# define NETSTACK_CONF_RADIO ieee_mode_driver +#define NETSTACK_CONF_RADIO ieee_mode_driver /* CSMA configuration. */ -# define CSMA_CONF_SEND_SOFT_ACK 0 +#define CSMA_CONF_SEND_SOFT_ACK 0 -# else +#else /*----- CC13xx Unsupported Mode ---------------------------------------------*/ -# error "Invalid RF mode configuration of CC13xx device" -# endif /* CC13xx RF Mode configuration */ +#error "Invalid RF mode configuration of CC13xx device" +#endif /* CC13xx RF Mode configuration */ /*----- CC26xx Device Line --------------------------------------------------*/ /* CC26xx only supports IEEE mode */ #elif defined(DEVICE_LINE_CC26XX) /* Default to IEEE-mode for CC26xx devices if not configured */ -# ifndef RF_MODE -# define RF_MODE RF_MODE_2_4_GHZ -# endif +#ifndef RF_MODE +#define RF_MODE RF_MODE_2_4_GHZ +#endif /*----- CC26xx IEEE-mode ----------------------------------------------------*/ -# if (RF_MODE == RF_MODE_2_4_GHZ) && (SUPPORTS_IEEE_MODE) +#if (RF_MODE == RF_MODE_2_4_GHZ) && (SUPPORTS_IEEE_MODE) /* Netstack configuration */ -# define NETSTACK_CONF_RADIO ieee_mode_driver +#define NETSTACK_CONF_RADIO ieee_mode_driver /* CSMA configuration */ -# define CSMA_CONF_SEND_SOFT_ACK 0 +#define CSMA_CONF_SEND_SOFT_ACK 0 /* Frequncy band configuration */ -# undef DOT_15_4G_FREQ_BAND_ID -# define DOT_15_4G_CONF_FREQ_BAND_ID DOT_15_4G_FREQ_BAND_2450 +#undef DOT_15_4G_FREQ_BAND_ID +#define DOT_15_4G_CONF_FREQ_BAND_ID DOT_15_4G_FREQ_BAND_2450 -# else +#else /*----- CC26xx Unsupported Mode ---------------------------------------------*/ -# error "IEEE-mode only supported by CC26xx devices" -# endif /* CC26xx RF Mode configuration */ +#error "IEEE-mode only supported by CC26xx devices" +#endif /* CC26xx RF Mode configuration */ /*----- Unsupported device line ---------------------------------------------*/ #else -# error "Unsupported Device Line defined" +#error "Unsupported Device Line defined" #endif /* Unsupported device line */ /** @} */ diff --git a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-def.h b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-def.h index fc133948c..f51ee3c2b 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-def.h +++ b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-def.h @@ -43,9 +43,9 @@ #include /*---------------------------------------------------------------------------*/ #if (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0) -# include +#include #elif (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X2_CC26X2) -# include +#include #endif /*---------------------------------------------------------------------------*/ #include @@ -71,7 +71,7 @@ #define USEC_TO_RAT(X) ((X) * 4) #if (RTIMER_SECOND % 256) || (RAT_SECOND % 256) -# error RAT_TO_RTIMER macro must be fixed! +#error RAT_TO_RTIMER macro must be fixed! #endif /* The PHY header (preamble + SFD, 4+1 bytes) duration is equivalent to 10 symbols */ @@ -116,9 +116,9 @@ /*---------------------------------------------------------------------------*/ /* Path to CMSIS header */ #if (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0) -# define CMSIS_CONF_HEADER_PATH "cc13x0-cc26x0-cm3.h" +#define CMSIS_CONF_HEADER_PATH "cc13x0-cc26x0-cm3.h" #elif (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X2_CC26X2) -# define CMSIS_CONF_HEADER_PATH "cc13x2-cc26x2-cm4.h" +#define CMSIS_CONF_HEADER_PATH "cc13x2-cc26x2-cm4.h" #endif /*---------------------------------------------------------------------------*/ /* Path to headers with implementation of mutexes and memory barriers */ diff --git a/arch/cpu/cc13xx-cc26xx/ccfg-conf.h b/arch/cpu/cc13xx-cc26xx/ccfg-conf.h index ce7eff3d4..23bc5dc9a 100644 --- a/arch/cpu/cc13xx-cc26xx/ccfg-conf.h +++ b/arch/cpu/cc13xx-cc26xx/ccfg-conf.h @@ -51,13 +51,13 @@ * @{ */ #if CCFG_CONF_JTAG_INTERFACE_DISABLE -# define SET_CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE 0x00 -# define SET_CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE 0x00 -# define SET_CCFG_CCFG_TAP_DAP_0_PRCM_TAP_ENABLE 0x00 -# define SET_CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE 0x00 -# define SET_CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE 0x00 -# define SET_CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE 0x00 -# define SET_CCFG_CCFG_TAP_DAP_1_WUC_TAP_ENABLE 0x00 +#define SET_CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE 0x00 +#define SET_CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE 0x00 +#define SET_CCFG_CCFG_TAP_DAP_0_PRCM_TAP_ENABLE 0x00 +#define SET_CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE 0x00 +#define SET_CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE 0x00 +#define SET_CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE 0x00 +#define SET_CCFG_CCFG_TAP_DAP_1_WUC_TAP_ENABLE 0x00 #endif /** @} */ /*---------------------------------------------------------------------------*/ @@ -69,7 +69,7 @@ * @{ */ #if defined(DEVICE_LINE_CC13XX) && (RF_CONF_TXPOWER_BOOST_MODE) -# define CCFG_FORCE_VDDR_HH 1 +#define CCFG_FORCE_VDDR_HH 1 #endif /** @} */ /*---------------------------------------------------------------------------*/ @@ -86,12 +86,12 @@ #endif #if CCFG_CONF_ROM_BOOTLOADER_ENABLE -# define SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE 0xC5 -# define SET_CCFG_BL_CONFIG_BL_LEVEL 0x00 -# if defined(CCFG_CONF_BL_PIN_NUMBER) -# define SET_CCFG_BL_CONFIG_BL_PIN_NUMBER CCFG_CONF_BL_PIN_NUMBER -# endif -# define SET_CCFG_BL_CONFIG_BL_ENABLE 0xC5 +#define SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE 0xC5 +#define SET_CCFG_BL_CONFIG_BL_LEVEL 0x00 +#if defined(CCFG_CONF_BL_PIN_NUMBER) +#define SET_CCFG_BL_CONFIG_BL_PIN_NUMBER CCFG_CONF_BL_PIN_NUMBER +#endif +#define SET_CCFG_BL_CONFIG_BL_ENABLE 0xC5 #endif /** @} */ /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/dev/clock-arch.c b/arch/cpu/cc13xx-cc26xx/dev/clock-arch.c index d65750dc8..516d51cdb 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/clock-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/clock-arch.c @@ -87,7 +87,7 @@ clock_init(void) { /* ClockP_getSystemTickPeriod() returns ticks per us. */ const uint32_t clockp_ticks_second = - (uint32_t)(1000 * 1000) / (CLOCK_SECOND) / ClockP_getSystemTickPeriod(); + (uint32_t)(1000 * 1000) / (CLOCK_SECOND) / ClockP_getSystemTickPeriod(); count = 0; diff --git a/arch/cpu/cc13xx-cc26xx/dev/dbg-arch.c b/arch/cpu/cc13xx-cc26xx/dev/dbg-arch.c index f61d0e6af..823239f21 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/dbg-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/dbg-arch.c @@ -57,8 +57,8 @@ dbg_putchar(int c) num_bytes = (int)uart0_write(&ch, 1); return (num_bytes > 0) - ? num_bytes - : 0; + ? num_bytes + : 0; } /*---------------------------------------------------------------------------*/ unsigned int @@ -77,8 +77,8 @@ dbg_send_bytes(const unsigned char *seq, unsigned int len) num_bytes = (int)uart0_write(seq, max_len); return (num_bytes > 0) - ? num_bytes - : 0; + ? num_bytes + : 0; } /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c b/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c index 03fdc870f..9da458899 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/gpio-hal-arch.c @@ -175,7 +175,6 @@ gpio_int_cb(PIN_Handle handle, PIN_Id pin_id) /* Notify the GPIO HAL driver */ gpio_hal_event_handler(gpio_hal_pin_to_mask(pin_id)); } - /*---------------------------------------------------------------------------*/ void gpio_hal_arch_init(void) @@ -244,15 +243,15 @@ gpio_hal_arch_read_pins(gpio_hal_pin_mask_t pins) pins &= ~oe_pins; return (HWREG(GPIO_BASE + GPIO_O_DOUT31_0) & oe_pins) | - GPIO_readMultiDio(pins); + GPIO_readMultiDio(pins); } /*---------------------------------------------------------------------------*/ uint8_t gpio_hal_arch_read_pin(gpio_hal_pin_t pin) { return (GPIO_getOutputEnableDio(pin)) - ? PINCC26XX_getOutputValue(pin) - : PINCC26XX_getInputValue(pin); + ? PINCC26XX_getOutputValue(pin) + : PINCC26XX_getInputValue(pin); } /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c b/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c index 90fe9c6e5..d63adc36c 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rtimer-arch.c @@ -73,8 +73,7 @@ static void rtimer_clock_stub(uintptr_t unused) { (void)unused; /* do nothing */ static void rtimer_isr_hook(void) { - if(AONRTCEventGet(RTIMER_RTC_CH)) - { + if(AONRTCEventGet(RTIMER_RTC_CH)) { AONRTCEventClear(RTIMER_RTC_CH); AONRTCChannelDisable(RTIMER_RTC_CH); @@ -84,12 +83,9 @@ rtimer_isr_hook(void) * HWI Dispatch clears the interrupt. If HWI wasn't triggered, clear * the interrupt manually. */ - if(AONRTCEventGet(HWIP_RTC_CH)) - { + if(AONRTCEventGet(HWIP_RTC_CH)) { hwi_dispatch_fxn(); - } - else - { + } else { IntPendClear(INT_AON_RTC_COMB); } } @@ -121,9 +117,8 @@ rtimer_arch_init(void) ClockP_destruct(&clk_object); /* Try to access the RAM vector table. */ - ramvec_table = (isr_fxn_t*)HWREG(NVIC_VTABLE); - if(!ramvec_table) - { + ramvec_table = (isr_fxn_t *)HWREG(NVIC_VTABLE); + if(!ramvec_table) { /* * Unable to find the RAM vector table is a serious fault. * Spin-lock forever. @@ -136,8 +131,7 @@ rtimer_arch_init(void) * in the RAM vector table. Fetch and store it. */ hwi_dispatch_fxn = (hwi_dispatch_fxn_t)ramvec_table[INT_AON_RTC_COMB]; - if(!hwi_dispatch_fxn) - { + if(!hwi_dispatch_fxn) { /* * Unable to find the HWI dispatch ISR in the RAM vector table is * a serious fault. Spin-lock forever. diff --git a/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c b/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c index 1618f6d71..dbcbe3048 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c +++ b/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c @@ -87,25 +87,25 @@ extern unsigned long _stack_end; // //***************************************************************************** __attribute__ ((section(".resetVecs"))) __attribute__ ((used)) -static void (* const resetVectors[16])(void) = +static void(*const resetVectors[16]) (void) = { (void (*)(void))((uint32_t)&_stack_end), - // The initial stack pointer - resetISR, // The reset handler - nmiISR, // The NMI handler - faultISR, // The hard fault handler - defaultHandler, // The MPU fault handler - busFaultHandler, // The bus fault handler - defaultHandler, // The usage fault handler - 0, // Reserved - 0, // Reserved - 0, // Reserved - 0, // Reserved - defaultHandler, // SVCall handler - defaultHandler, // Debug monitor handler - 0, // Reserved - defaultHandler, // The PendSV handler - defaultHandler // The SysTick handler + /* The initial stack pointer */ + resetISR, /* The reset handler */ + nmiISR, /* The NMI handler */ + faultISR, /* The hard fault handler */ + defaultHandler, /* The MPU fault handler */ + busFaultHandler, /* The bus fault handler */ + defaultHandler, /* The usage fault handler */ + 0, /* Reserved */ + 0, /* Reserved */ + 0, /* Reserved */ + 0, /* Reserved */ + defaultHandler, /* SVCall handler */ + defaultHandler, /* Debug monitor handler */ + 0, /* Reserved */ + defaultHandler, /* The PendSV handler */ + defaultHandler /* The SysTick handler */ }; //***************************************************************************** // @@ -155,7 +155,7 @@ void localProgramStart(void) uint32_t count; uint32_t i; -#if defined (__ARM_ARCH_7EM__) && defined(__VFP_FP__) && !defined(__SOFTFP__) +#if defined(__ARM_ARCH_7EM__) && defined(__VFP_FP__) && !defined(__SOFTFP__) volatile uint32_t *pui32Cpacr = (uint32_t *)0xE000ED88; /* Enable Coprocessor Access Control (CPAC) */ @@ -193,11 +193,11 @@ void localProgramStart(void) __init_array_start[i](); } - /* Call the application's entry point. */ - main(); + /* Call the application's entry point. */ + main(); - /* If we ever return signal Error */ - faultISR(); + /* If we ever return signal Error */ + faultISR(); } //***************************************************************************** @@ -233,8 +233,7 @@ static void nmiISR(void) { /* Enter an infinite loop. */ - while(1) - { + while(1) { } } @@ -296,8 +295,7 @@ busFaultHandler(void) { x__ = 0; /* Enter an infinite loop. */ - while(1) - { + while(1) { } } @@ -312,8 +310,7 @@ static void defaultHandler(void) { /* Enter an infinite loop. */ - while(1) - { + while(1) { } } @@ -326,5 +323,5 @@ defaultHandler(void) //***************************************************************************** void _fini(void) { - /* Function body left empty intentionally */ + /* Function body left empty intentionally */ } diff --git a/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_iar.c b/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_iar.c index 9279ea523..70981ef77 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_iar.c +++ b/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_iar.c @@ -39,8 +39,7 @@ #error "startup_cc13xx_cc26xx_iar.c: Unsupported compiler!" #endif - -// We need intrinsic functions for IAR (if used in source code) +/* We need intrinsic functions for IAR (if used in source code) */ #include #include #include DeviceFamily_constructPath(inc/hw_types.h) @@ -58,48 +57,48 @@ static void faultISR( void ); static void intDefaultHandler( void ); extern int main( void ); -extern void MPUFaultIntHandler( void ); -extern void BusFaultIntHandler( void ); -extern void UsageFaultIntHandler( void ); -extern void SVCallIntHandler( void ); -extern void DebugMonIntHandler( void ); -extern void PendSVIntHandler( void ); -extern void SysTickIntHandler( void ); -extern void GPIOIntHandler( void ); -extern void I2CIntHandler( void ); -extern void RFCCPE1IntHandler( void ); -extern void AONRTCIntHandler( void ); -extern void UART0IntHandler( void ); -extern void AUXSWEvent0IntHandler( void ); -extern void SSI0IntHandler( void ); -extern void SSI1IntHandler( void ); -extern void RFCCPE0IntHandler( void ); -extern void RFCHardwareIntHandler( void ); -extern void RFCCmdAckIntHandler( void ); -extern void I2SIntHandler( void ); -extern void AUXSWEvent1IntHandler( void ); -extern void WatchdogIntHandler( void ); -extern void Timer0AIntHandler( void ); -extern void Timer0BIntHandler( void ); -extern void Timer1AIntHandler( void ); -extern void Timer1BIntHandler( void ); -extern void Timer2AIntHandler( void ); -extern void Timer2BIntHandler( void ); -extern void Timer3AIntHandler( void ); -extern void Timer3BIntHandler( void ); -extern void CryptoIntHandler( void ); -extern void uDMAIntHandler( void ); -extern void uDMAErrIntHandler( void ); -extern void FlashIntHandler( void ); -extern void SWEvent0IntHandler( void ); -extern void AUXCombEventIntHandler( void ); -extern void AONProgIntHandler( void ); -extern void DynProgIntHandler( void ); -extern void AUXCompAIntHandler( void ); -extern void AUXADCIntHandler( void ); -extern void TRNGIntHandler( void ); +extern void MPUFaultIntHandler(void); +extern void BusFaultIntHandler(void); +extern void UsageFaultIntHandler(void); +extern void SVCallIntHandler(void); +extern void DebugMonIntHandler(void); +extern void PendSVIntHandler(void); +extern void SysTickIntHandler(void); +extern void GPIOIntHandler(void); +extern void I2CIntHandler(void); +extern void RFCCPE1IntHandler(void); +extern void AONRTCIntHandler(void); +extern void UART0IntHandler(void); +extern void AUXSWEvent0IntHandler(void); +extern void SSI0IntHandler(void); +extern void SSI1IntHandler(void); +extern void RFCCPE0IntHandler(void); +extern void RFCHardwareIntHandler(void); +extern void RFCCmdAckIntHandler(void); +extern void I2SIntHandler(void); +extern void AUXSWEvent1IntHandler(void); +extern void WatchdogIntHandler(void); +extern void Timer0AIntHandler(void); +extern void Timer0BIntHandler(void); +extern void Timer1AIntHandler(void); +extern void Timer1BIntHandler(void); +extern void Timer2AIntHandler(void); +extern void Timer2BIntHandler(void); +extern void Timer3AIntHandler(void); +extern void Timer3BIntHandler(void); +extern void CryptoIntHandler(void); +extern void uDMAIntHandler(void); +extern void uDMAErrIntHandler(void); +extern void FlashIntHandler(void); +extern void SWEvent0IntHandler(void); +extern void AUXCombEventIntHandler(void); +extern void AONProgIntHandler(void); +extern void DynProgIntHandler(void); +extern void AUXCompAIntHandler(void); +extern void AUXADCIntHandler(void); +extern void TRNGIntHandler(void); -// Default interrupt handlers +/* Default interrupt handlers */ #pragma weak MPUFaultIntHandler = intDefaultHandler #pragma weak BusFaultIntHandler = intDefaultHandler #pragma weak UsageFaultIntHandler = intDefaultHandler diff --git a/arch/cpu/cc13xx-cc26xx/dev/trng-arch.c b/arch/cpu/cc13xx-cc26xx/dev/trng-arch.c index cdba878af..8f7cb2627 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/trng-arch.c +++ b/arch/cpu/cc13xx-cc26xx/dev/trng-arch.c @@ -51,7 +51,7 @@ */ #include #if (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0) -# include +#include #endif /*---------------------------------------------------------------------------*/ #include @@ -82,7 +82,7 @@ trng_rand(uint8_t *entropy_buf, size_t entropy_len, uint32_t timeout_us) TRNG_close(trng_handle); - return (result == TRNG_STATUS_SUCCESS); + return result == TRNG_STATUS_SUCCESS; } /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/rf-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/rf-settings.h index 198482b1f..744a6948a 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/rf-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/rf-settings.h @@ -58,7 +58,7 @@ #define netstack_cmd_rx rf_cmd_ieee_rx /*---------------------------------------------------------------------------*/ #else -# error "Unsupported RF_MODE" +#error "Unsupported RF_MODE" #endif /*---------------------------------------------------------------------------*/ /* BLE RF settings */ @@ -84,7 +84,7 @@ /*---------------------------------------------------------------------------*/ #else -# error "Unsupported DeviceFamily_PARENT for BLE settings" +#error "Unsupported DeviceFamily_PARENT for BLE settings" #endif /*---------------------------------------------------------------------------*/ #endif /* NETSTACK_SETTINGS_H_ */ diff --git a/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c b/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c index 7924693a8..87fd7b43e 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c +++ b/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c @@ -112,26 +112,26 @@ typedef struct { bool is_active; /* Periodic timer for sending out BLE advertisements */ - clock_time_t ble_adv_interval; + clock_time_t ble_adv_interval; struct etimer ble_adv_et; /* RF driver */ - RF_Handle rf_handle; + RF_Handle rf_handle; } ble_beacond_t; static ble_beacond_t ble_beacond; /*---------------------------------------------------------------------------*/ /* Configuration for TX power table */ #ifdef BLE_MODE_CONF_TX_POWER_TABLE -# define TX_POWER_TABLE BLE_MODE_CONF_TX_POWER_TABLE +#define TX_POWER_TABLE BLE_MODE_CONF_TX_POWER_TABLE #else -# define TX_POWER_TABLE rf_ble_tx_power_table +#define TX_POWER_TABLE rf_ble_tx_power_table #endif #ifdef BLE_MODE_CONF_TX_POWER_TABLE_SIZE -# define TX_POWER_TABLE_SIZE BLE_MODE_CONF_TX_POWER_TABLE_SIZE +#define TX_POWER_TABLE_SIZE BLE_MODE_CONF_TX_POWER_TABLE_SIZE #else -# define TX_POWER_TABLE_SIZE RF_BLE_TX_POWER_TABLE_SIZE +#define TX_POWER_TABLE_SIZE RF_BLE_TX_POWER_TABLE_SIZE #endif /* TX power table convenience macros */ @@ -150,7 +150,7 @@ rf_ble_beacond_init(void) RF_Params rf_params; RF_Params_init(&rf_params); - /* Should immediately turn off radio if possible */ + /* Should immediately turn off radio if possible */ rf_params.nInactivityTimeout = 0; ble_beacond.handle = ble_open(&rf_params); @@ -178,7 +178,7 @@ rf_ble_beacond_start(clock_time_t interval, const char *name) const size_t name_len = strlen(name); if((name_len == 0) || - (name_len >= BLE_ADV_NAME_BUF_LEN)) { + (name_len >= BLE_ADV_NAME_BUF_LEN)) { return RF_BLE_BEACOND_ERROR; } @@ -220,8 +220,8 @@ rf_ble_set_tx_power(int8_t dBm) res = rf_set_tx_power(ble_beacond.rf_handle, TX_POWER_TABLE, dbm); return (res == RF_RESULT_OK) - ? RF_BLE_BEACOND_OK - : RF_BLE_BEACOND_ERROR; + ? RF_BLE_BEACOND_OK + : RF_BLE_BEACOND_ERROR; } /*---------------------------------------------------------------------------*/ int8_t diff --git a/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.h b/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.h index f97927ff5..87e2ccc74 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.h +++ b/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.h @@ -49,9 +49,9 @@ #include /*---------------------------------------------------------------------------*/ typedef enum { - RF_BLE_BEACOND_OK, - RF_BLE_BEACOND_ERROR, - RF_BLE_BEACOND_DISABLED, + RF_BLE_BEACOND_OK, + RF_BLE_BEACOND_ERROR, + RF_BLE_BEACOND_DISABLED, } rf_ble_beacond_result_t; /*---------------------------------------------------------------------------*/ /** diff --git a/arch/cpu/cc13xx-cc26xx/rf/data-queue.c b/arch/cpu/cc13xx-cc26xx/rf/data-queue.c index 06d57bd71..31da05302 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/data-queue.c +++ b/arch/cpu/cc13xx-cc26xx/rf/data-queue.c @@ -140,7 +140,7 @@ data_queue_reset(void) data_entry_t* data_queue_current_entry(void) { - return rx_data_queue.curr_entry; + return rx_data_queue.curr_entry; } /*---------------------------------------------------------------------------*/ void diff --git a/arch/cpu/cc13xx-cc26xx/rf/dot-15-4g.h b/arch/cpu/cc13xx-cc26xx/rf/dot-15-4g.h index d0bf42722..5366651e7 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/dot-15-4g.h +++ b/arch/cpu/cc13xx-cc26xx/rf/dot-15-4g.h @@ -71,9 +71,9 @@ /*---------------------------------------------------------------------------*/ /* Default band selection to band 4 - 863MHz */ #ifdef DOT_15_4G_CONF_FREQ_BAND_ID -# define DOT_15_4G_FREQ_BAND_ID DOT_15_4G_CONF_FREQ_BAND_ID +#define DOT_15_4G_FREQ_BAND_ID DOT_15_4G_CONF_FREQ_BAND_ID #else -# define DOT_15_4G_FREQ_BAND_ID DOT_15_4G_FREQ_BAND_863 +#define DOT_15_4G_FREQ_BAND_ID DOT_15_4G_FREQ_BAND_863 #endif /*---------------------------------------------------------------------------*/ /* @@ -84,76 +84,76 @@ * DOT_15_4G_CHAN0_FREQ is specified here in KHz */ #if (DOT_15_4G_FREQ_BAND_ID == DOT_15_4G_FREQ_BAND_470) -# define DOT_15_4G_CHAN_MIN 0 -# define DOT_15_4G_CHAN_MAX 198 -# define DOT_15_4G_FREQ_SPACING 200 -# define DOT_15_4G_CHAN0_FREQ 470200 +#define DOT_15_4G_CHAN_MIN 0 +#define DOT_15_4G_CHAN_MAX 198 +#define DOT_15_4G_FREQ_SPACING 200 +#define DOT_15_4G_CHAN0_FREQ 470200 -# define PROP_MODE_CONF_CENTER_FREQ 0x01EA -# define PROP_MODE_CONF_LO_DIVIDER 0x0A +#define PROP_MODE_CONF_CENTER_FREQ 0x01EA +#define PROP_MODE_CONF_LO_DIVIDER 0x0A #elif (DOT_15_4G_FREQ_BAND_ID == DOT_15_4G_FREQ_BAND_780) -# define DOT_15_4G_CHAN_MIN 0 -# define DOT_15_4G_CHAN_MAX 38 -# define DOT_15_4G_FREQ_SPACING 200 -# define DOT_15_4G_CHAN0_FREQ 779200 +#define DOT_15_4G_CHAN_MIN 0 +#define DOT_15_4G_CHAN_MAX 38 +#define DOT_15_4G_FREQ_SPACING 200 +#define DOT_15_4G_CHAN0_FREQ 779200 -# define PROP_MODE_CONF_CENTER_FREQ 0x030F -# define PROP_MODE_CONF_LO_DIVIDER 0x06 +#define PROP_MODE_CONF_CENTER_FREQ 0x030F +#define PROP_MODE_CONF_LO_DIVIDER 0x06 #elif (DOT_15_4G_FREQ_BAND_ID == DOT_15_4G_FREQ_BAND_863) -# define DOT_15_4G_CHAN_MIN 0 -# define DOT_15_4G_CHAN_MAX 33 -# define DOT_15_4G_FREQ_SPACING 200 -# define DOT_15_4G_CHAN0_FREQ 863125 +#define DOT_15_4G_CHAN_MIN 0 +#define DOT_15_4G_CHAN_MAX 33 +#define DOT_15_4G_FREQ_SPACING 200 +#define DOT_15_4G_CHAN0_FREQ 863125 -# define PROP_MODE_CONF_CENTER_FREQ 0x0362 -# define PROP_MODE_CONF_LO_DIVIDER 0x05 +#define PROP_MODE_CONF_CENTER_FREQ 0x0362 +#define PROP_MODE_CONF_LO_DIVIDER 0x05 #elif (DOT_15_4G_FREQ_BAND_ID == DOT_15_4G_FREQ_BAND_915) -# define DOT_15_4G_CHAN_MIN 0 -# define DOT_15_4G_CHAN_MAX 128 -# define DOT_15_4G_FREQ_SPACING 200 -# define DOT_15_4G_CHAN0_FREQ 902200 +#define DOT_15_4G_CHAN_MIN 0 +#define DOT_15_4G_CHAN_MAX 128 +#define DOT_15_4G_FREQ_SPACING 200 +#define DOT_15_4G_CHAN0_FREQ 902200 -# define PROP_MODE_CONF_CENTER_FREQ 0x0393 -# define PROP_MODE_CONF_LO_DIVIDER 0x05 +#define PROP_MODE_CONF_CENTER_FREQ 0x0393 +#define PROP_MODE_CONF_LO_DIVIDER 0x05 #elif (DOT_15_4G_FREQ_BAND_ID == DOT_15_4G_FREQ_BAND_920) -# define DOT_15_4G_CHAN_MIN 0 -# define DOT_15_4G_CHAN_MAX 37 -# define DOT_15_4G_FREQ_SPACING 200 -# define DOT_15_4G_CHAN0_FREQ 920600 +#define DOT_15_4G_CHAN_MIN 0 +#define DOT_15_4G_CHAN_MAX 37 +#define DOT_15_4G_FREQ_SPACING 200 +#define DOT_15_4G_CHAN0_FREQ 920600 -# define PROP_MODE_CONF_CENTER_FREQ 0x039C -# define PROP_MODE_CONF_LO_DIVIDER 0x05 +#define PROP_MODE_CONF_CENTER_FREQ 0x039C +#define PROP_MODE_CONF_LO_DIVIDER 0x05 #elif (DOT_15_4G_FREQ_BAND_ID == DOT_15_4G_FREQ_BAND_950) -# define DOT_15_4G_CHAN_MIN 0 -# define DOT_15_4G_CHAN_MAX 32 -# define DOT_15_4G_FREQ_SPACING 200 -# define DOT_15_4G_CHAN0_FREQ 951000 +#define DOT_15_4G_CHAN_MIN 0 +#define DOT_15_4G_CHAN_MAX 32 +#define DOT_15_4G_FREQ_SPACING 200 +#define DOT_15_4G_CHAN0_FREQ 951000 -# define PROP_MODE_CONF_CENTER_FREQ 0x03BA -# define PROP_MODE_CONF_LO_DIVIDER 0x05 +#define PROP_MODE_CONF_CENTER_FREQ 0x03BA +#define PROP_MODE_CONF_LO_DIVIDER 0x05 #elif (DOT_15_4G_FREQ_BAND_ID == DOT_15_4G_FREQ_BAND_2450) -# define DOT_15_4G_CHAN_MIN 11 -# define DOT_15_4G_CHAN_MAX 26 -# define DOT_15_4G_FREQ_SPACING 5000 -# define DOT_15_4G_CHAN0_FREQ 2405000 +#define DOT_15_4G_CHAN_MIN 11 +#define DOT_15_4G_CHAN_MAX 26 +#define DOT_15_4G_FREQ_SPACING 5000 +#define DOT_15_4G_CHAN0_FREQ 2405000 #else -# error "The selected IEEE 802.15.4g frequency band is not supported" +#error "The selected IEEE 802.15.4g frequency band is not supported" #endif /*---------------------------------------------------------------------------*/ static inline uint32_t dot_15_4g_freq(const uint16_t chan) { - const uint32_t chan0 = DOT_15_4G_CHAN0_FREQ; - const uint32_t spacing = DOT_15_4G_FREQ_SPACING; + const uint32_t chan0 = DOT_15_4G_CHAN0_FREQ; + const uint32_t spacing = DOT_15_4G_FREQ_SPACING; const uint32_t chan_min = DOT_15_4G_CHAN_MIN; - return (chan0 + spacing * ((uint32_t)chan - chan_min)); + return chan0 + spacing * ((uint32_t)chan - chan_min); } /*---------------------------------------------------------------------------*/ static inline bool @@ -161,8 +161,8 @@ dot_15_4g_chan_in_range(const uint16_t chan) { const uint16_t chan_min = DOT_15_4G_CHAN_MIN; const uint16_t chan_max = DOT_15_4G_CHAN_MAX; - return ((chan >= chan_min) && - (chan <= chan_max)); + return (chan >= chan_min) && + (chan <= chan_max); } /*---------------------------------------------------------------------------*/ #define DOT_15_4G_DEFAULT_CHAN IEEE802154_DEFAULT_CHANNEL diff --git a/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c b/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c index 8eb4a442c..9a36497fc 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c +++ b/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c @@ -80,7 +80,7 @@ #include /*---------------------------------------------------------------------------*/ #if 1 -# define PRINTF(...) printf(__VA_ARGS__) +#define PRINTF(...) printf(__VA_ARGS__) #else # define PRINTF(...) #endif @@ -89,23 +89,23 @@ /* Configuration to enable/disable auto ACKs in IEEE mode */ #ifdef IEEE_MODE_CONF_AUTOACK -# define IEEE_MODE_AUTOACK IEEE_MODE_CONF_AUTOACK +#define IEEE_MODE_AUTOACK IEEE_MODE_CONF_AUTOACK #else -# define IEEE_MODE_AUTOACK 1 +#define IEEE_MODE_AUTOACK 1 #endif /* IEEE_MODE_CONF_AUTOACK */ /* Configuration to enable/disable frame filtering in IEEE mode */ #ifdef IEEE_MODE_CONF_PROMISCOUS -# define IEEE_MODE_PROMISCOUS IEEE_MODE_CONF_PROMISCOUS +#define IEEE_MODE_PROMISCOUS IEEE_MODE_CONF_PROMISCOUS #else -# define IEEE_MODE_PROMISCOUS 0 +#define IEEE_MODE_PROMISCOUS 0 #endif /* IEEE_MODE_CONF_PROMISCOUS */ /* Configuration to set the RSSI threshold */ #ifdef IEEE_MODE_CONF_RSSI_THRESHOLD -# define IEEE_MODE_RSSI_THRESHOLD IEEE_MODE_CONF_RSSI_THRESHOLD +#define IEEE_MODE_RSSI_THRESHOLD IEEE_MODE_CONF_RSSI_THRESHOLD #else -# define IEEE_MODE_RSSI_THRESHOLD 0xA6 +#define IEEE_MODE_RSSI_THRESHOLD 0xA6 #endif /* IEEE_MODE_CONF_RSSI_THRESHOLD */ /*---------------------------------------------------------------------------*/ /* TX power table convenience macros */ @@ -206,7 +206,11 @@ static cmd_mod_filt_t cmd_mod_filt; #define cmd_rx (*(volatile rfc_CMD_IEEE_RX_t*) &rf_cmd_ieee_rx) #define cmd_rx_ack (*(volatile rfc_CMD_IEEE_RX_ACK_t*)&rf_cmd_ieee_rx_ack) /*---------------------------------------------------------------------------*/ -static inline bool rx_is_active(void) { return cmd_rx.status == ACTIVE; } +static inline bool +rx_is_active(void) +{ + return cmd_rx.status == ACTIVE; +} /*---------------------------------------------------------------------------*/ /* Forward declarations of local functions */ static void check_rat_overflow(void); @@ -515,7 +519,7 @@ read(void *buf, unsigned short buf_len) const rtimer_clock_t t0 = RTIMER_NOW(); /* Only wait if the Radio timer is accessing the entry */ while((data_entry->status == DATA_ENTRY_BUSY) && - RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + TIMEOUT_DATA_ENTRY_BUSY)); + RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + TIMEOUT_DATA_ENTRY_BUSY)) ; if(data_entry->status != DATA_ENTRY_FINISHED) { /* No available data */ @@ -602,7 +606,7 @@ cca_request(cmd_cca_req_t *cmd_cca_req) const rtimer_clock_t t0 = RTIMER_NOW(); while((cmd_rx.status != ACTIVE) && - RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + TIMEOUT_ENTER_RX_WAIT)); + RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + TIMEOUT_ENTER_RX_WAIT)) ; RF_Stat stat = RF_StatRadioInactiveError; if(rx_is_active()) { @@ -614,8 +618,8 @@ cca_request(cmd_cca_req_t *cmd_cca_req) } return (stat == RF_StatCmdDoneSuccess) - ? RF_RESULT_OK - : RF_RESULT_ERROR; + ? RF_RESULT_OK + : RF_RESULT_ERROR; } /*---------------------------------------------------------------------------*/ static int @@ -630,7 +634,7 @@ channel_clear(void) } /* Channel is clear if CCA state is IDLE */ - return (cmd_cca_req.ccaInfo.ccaState == CCA_STATE_IDLE); + return cmd_cca_req.ccaInfo.ccaState == CCA_STATE_IDLE; } /*---------------------------------------------------------------------------*/ static int @@ -646,14 +650,14 @@ receiving_packet(void) /* If we are transmitting (can only be an ACK here), we are not receiving */ if((cmd_cca_req.ccaInfo.ccaEnergy == CCA_STATE_BUSY) && - (cmd_cca_req.ccaInfo.ccaCorr == CCA_STATE_BUSY) && - (cmd_cca_req.ccaInfo.ccaSync == CCA_STATE_BUSY)) { + (cmd_cca_req.ccaInfo.ccaCorr == CCA_STATE_BUSY) && + (cmd_cca_req.ccaInfo.ccaSync == CCA_STATE_BUSY)) { PRINTF("receiving_packet: we were TXing ACK\n"); return 0; } /* We are receiving a packet if a CCA sync has been seen, i.e. ccaSync is busy (1) */ - return (cmd_cca_req.ccaInfo.ccaSync == CCA_STATE_BUSY); + return cmd_cca_req.ccaInfo.ccaSync == CCA_STATE_BUSY; } /*---------------------------------------------------------------------------*/ static int @@ -668,7 +672,7 @@ pending_packet(void) do { const uint8_t status = curr_entry->status; if((status == DATA_ENTRY_FINISHED) || - (status == DATA_ENTRY_BUSY)) { + (status == DATA_ENTRY_BUSY)) { num_pending += 1; } @@ -777,8 +781,8 @@ get_value(radio_param_t param, radio_value_t *value) res = rf_get_tx_power(ieee_radio.rf_handle, TX_POWER_TABLE, (int8_t*)&value); return ((res == RF_RESULT_OK) && (*value != RF_TxPowerTable_INVALID_DBM)) - ? RADIO_RESULT_OK - : RADIO_RESULT_ERROR; + ? RADIO_RESULT_OK + : RADIO_RESULT_ERROR; /* CCA threshold */ case RADIO_PARAM_CCA_THRESHOLD: @@ -789,8 +793,8 @@ get_value(radio_param_t param, radio_value_t *value) case RADIO_PARAM_RSSI: *value = RF_getRssi(ieee_radio.rf_handle); return (*value == RF_GET_RSSI_ERROR_VAL) - ? RADIO_RESULT_ERROR - : RADIO_RESULT_OK; + ? RADIO_RESULT_ERROR + : RADIO_RESULT_OK; /* Channel min */ case RADIO_CONST_CHANNEL_MIN: @@ -838,9 +842,8 @@ set_value(radio_param_t param, radio_value_t value) if(value == RADIO_POWER_MODE_ON) { return (on() == RF_RESULT_OK) - ? RADIO_RESULT_OK - : RADIO_RESULT_ERROR; - + ? RADIO_RESULT_OK + : RADIO_RESULT_ERROR; } else if(value == RADIO_POWER_MODE_OFF) { off(); return RADIO_RESULT_OK; @@ -866,8 +869,8 @@ set_value(radio_param_t param, radio_value_t value) netstack_stop_rx(); res = netstack_sched_rx(false); return (res == RF_RESULT_OK) - ? RADIO_RESULT_OK - : RADIO_RESULT_ERROR; + ? RADIO_RESULT_OK + : RADIO_RESULT_ERROR; /* 16bit address */ case RADIO_PARAM_16BIT_ADDR: @@ -879,8 +882,8 @@ set_value(radio_param_t param, radio_value_t value) netstack_stop_rx(); res = netstack_sched_rx(false); return (res == RF_RESULT_OK) - ? RADIO_RESULT_OK - : RADIO_RESULT_ERROR; + ? RADIO_RESULT_OK + : RADIO_RESULT_ERROR; /* RX Mode */ case RADIO_PARAM_RX_MODE: { @@ -918,8 +921,8 @@ set_value(radio_param_t param, radio_value_t value) netstack_stop_rx(); res = netstack_sched_rx(false); return (res == RF_RESULT_OK) - ? RADIO_RESULT_OK - : RADIO_RESULT_ERROR; + ? RADIO_RESULT_OK + : RADIO_RESULT_ERROR; } /* TX Mode */ @@ -937,8 +940,8 @@ set_value(radio_param_t param, radio_value_t value) } res = rf_set_tx_power(ieee_radio.rf_handle, TX_POWER_TABLE, (int8_t)value); return (res == RF_RESULT_OK) - ? RADIO_RESULT_OK - : RADIO_RESULT_ERROR; + ? RADIO_RESULT_OK + : RADIO_RESULT_ERROR; /* CCA Threshold */ case RADIO_PARAM_CCA_THRESHOLD: @@ -950,8 +953,8 @@ set_value(radio_param_t param, radio_value_t value) netstack_stop_rx(); res = netstack_sched_rx(false); return (res == RF_RESULT_OK) - ? RADIO_RESULT_OK - : RADIO_RESULT_ERROR; + ? RADIO_RESULT_OK + : RADIO_RESULT_ERROR; default: return RADIO_RESULT_NOT_SUPPORTED; @@ -1026,8 +1029,8 @@ set_object(radio_param_t param, const void *src, size_t size) netstack_stop_rx(); res = netstack_sched_rx(false); return (res == RF_RESULT_OK) - ? RADIO_RESULT_OK - : RADIO_RESULT_ERROR; + ? RADIO_RESULT_OK + : RADIO_RESULT_ERROR; } default: return RADIO_RESULT_NOT_SUPPORTED; diff --git a/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c b/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c index 42447a082..c3042fa6e 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c +++ b/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c @@ -85,15 +85,15 @@ /*---------------------------------------------------------------------------*/ /* Data whitener. 1: Whitener, 0: No whitener */ #ifdef PROP_MODE_CONF_DW -# define PROP_MODE_DW PROP_MODE_CONF_DW +#define PROP_MODE_DW PROP_MODE_CONF_DW #else -# define PROP_MODE_DW 0 +#define PROP_MODE_DW 0 #endif #ifdef PROP_MODE_CONF_USE_CRC16 -# define PROP_MODE_USE_CRC16 PROP_MODE_CONF_USE_CRC16 +#define PROP_MODE_USE_CRC16 PROP_MODE_CONF_USE_CRC16 #else -# define PROP_MODE_USE_CRC16 0 +#define PROP_MODE_USE_CRC16 0 #endif /*---------------------------------------------------------------------------*/ /* Used for checking result of CCA_REQ command */ @@ -105,9 +105,9 @@ #define RF_GET_CCA_INFO_ERROR 0xFF #ifdef PROP_MODE_CONF_RSSI_THRESHOLD -# define PROP_MODE_RSSI_THRESHOLD PROP_MODE_CONF_RSSI_THRESHOLD +#define PROP_MODE_RSSI_THRESHOLD PROP_MODE_CONF_RSSI_THRESHOLD #else -# define PROP_MODE_RSSI_THRESHOLD 0xA6 +#define PROP_MODE_RSSI_THRESHOLD 0xA6 #endif /*---------------------------------------------------------------------------*/ /* Defines and variables related to the .15.4g PHY HDR */ @@ -120,18 +120,18 @@ #if PROP_MODE_USE_CRC16 /* CRC16 */ -# define DOT_4G_PHR_CRC_BIT DOT_4G_PHR_CRC16 -# define CRC_LEN 2 +#define DOT_4G_PHR_CRC_BIT DOT_4G_PHR_CRC16 +#define CRC_LEN 2 #else /* CRC32 */ -# define DOT_4G_PHR_CRC_BIT 0 -# define CRC_LEN 4 +#define DOT_4G_PHR_CRC_BIT 0 +#define CRC_LEN 4 #endif /* PROP_MODE_USE_CRC16 */ #if PROP_MODE_DW -# define DOT_4G_PHR_DW_BIT DOT_4G_PHR_DW +#define DOT_4G_PHR_DW_BIT DOT_4G_PHR_DW #else - #define DOT_4G_PHR_DW_BIT 0 +#define DOT_4G_PHR_DW_BIT 0 #endif /*---------------------------------------------------------------------------*/ /* How long to wait for the RF to enter RX in rf_cmd_ieee_rx */ @@ -197,8 +197,16 @@ static prop_radio_t prop_radio; #define cmd_tx (*(volatile rfc_CMD_PROP_TX_ADV_t *) &rf_cmd_prop_tx_adv) #define cmd_rx (*(volatile rfc_CMD_PROP_RX_ADV_t *) &rf_cmd_prop_rx_adv) /*---------------------------------------------------------------------------*/ -static inline bool tx_is_active(void) { return cmd_tx.status == ACTIVE; } -static inline bool rx_is_active(void) { return cmd_rx.status == ACTIVE; } +static inline bool +tx_is_active(void) +{ + return cmd_tx.status == ACTIVE; +} +static inline bool +rx_is_active(void) +{ + return cmd_rx.status == ACTIVE; +} /*---------------------------------------------------------------------------*/ static int on(void); static int off(void); @@ -232,7 +240,7 @@ get_rssi(void) const rtimer_clock_t t0 = RTIMER_NOW(); while((cmd_rx.status != ACTIVE) && - RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + TIMEOUT_ENTER_RX_WAIT)); + RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + TIMEOUT_ENTER_RX_WAIT)) ; int8_t rssi = RF_GET_RSSI_ERROR_VAL; if(rx_is_active()) { @@ -358,8 +366,8 @@ transmit(unsigned short transmit_len) res = netstack_sched_prop_tx(); return (res == RF_RESULT_OK) - ? RADIO_TX_OK - : RADIO_TX_ERR; + ? RADIO_TX_OK + : RADIO_TX_ERR; } /*---------------------------------------------------------------------------*/ static int @@ -377,7 +385,7 @@ read(void *buf, unsigned short buf_len) const rtimer_clock_t t0 = RTIMER_NOW(); /* Only wait if the Radio is accessing the entry */ while((data_entry->status == DATA_ENTRY_BUSY) && - RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + TIMEOUT_DATA_ENTRY_BUSY)); + RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + TIMEOUT_DATA_ENTRY_BUSY)) ; if(data_entry->status != DATA_ENTRY_FINISHED) { /* No available data */ @@ -451,8 +459,8 @@ cca_request(void) } return (rssi < prop_radio.rssi_threshold) - ? CCA_STATE_IDLE - : CCA_STATE_BUSY; + ? CCA_STATE_IDLE + : CCA_STATE_BUSY; } /*---------------------------------------------------------------------------*/ static int @@ -466,7 +474,7 @@ channel_clear(void) const uint8_t cca_state = cca_request(); /* Channel is clear if CCA state is IDLE */ - return (cca_state == CCA_STATE_IDLE); + return cca_state == CCA_STATE_IDLE; } /*---------------------------------------------------------------------------*/ static int @@ -478,7 +486,7 @@ receiving_packet(void) const uint8_t cca_state = cca_request(); - return (cca_state == CCA_STATE_BUSY); + return cca_state == CCA_STATE_BUSY; } /*---------------------------------------------------------------------------*/ static int @@ -493,7 +501,7 @@ pending_packet(void) do { const uint8_t status = curr_entry->status; if((status == DATA_ENTRY_FINISHED) || - (status == DATA_ENTRY_BUSY)) { + (status == DATA_ENTRY_BUSY)) { num_pending += 1; } @@ -558,8 +566,8 @@ get_value(radio_param_t param, radio_value_t *value) case RADIO_PARAM_POWER_MODE: /* On / off */ *value = (prop_radio.rf_is_on) - ? RADIO_POWER_MODE_ON - : RADIO_POWER_MODE_OFF; + ? RADIO_POWER_MODE_ON + : RADIO_POWER_MODE_OFF; return RADIO_RESULT_OK; @@ -571,8 +579,8 @@ get_value(radio_param_t param, radio_value_t *value) res = rf_get_tx_power(prop_radio.rf_handle, TX_POWER_TABLE, (int8_t*)&value); return ((res == RF_RESULT_OK) && (*value != RF_TxPowerTable_INVALID_DBM)) - ? RADIO_RESULT_OK - : RADIO_RESULT_ERROR; + ? RADIO_RESULT_OK + : RADIO_RESULT_ERROR; case RADIO_PARAM_CCA_THRESHOLD: *value = prop_radio.rssi_threshold; @@ -581,8 +589,8 @@ get_value(radio_param_t param, radio_value_t *value) case RADIO_PARAM_RSSI: *value = get_rssi(); return (*value == RF_GET_RSSI_ERROR_VAL) - ? RADIO_RESULT_ERROR - : RADIO_RESULT_OK; + ? RADIO_RESULT_ERROR + : RADIO_RESULT_OK; case RADIO_CONST_CHANNEL_MIN: *value = DOT_15_4G_CHAN_MIN; @@ -615,9 +623,8 @@ set_value(radio_param_t param, radio_value_t value) if(value == RADIO_POWER_MODE_ON) { return (on() == RF_RESULT_OK) - ? RADIO_RESULT_OK - : RADIO_RESULT_ERROR; - + ? RADIO_RESULT_OK + : RADIO_RESULT_ERROR; } else if(value == RADIO_POWER_MODE_OFF) { off(); return RADIO_RESULT_OK; @@ -628,8 +635,8 @@ set_value(radio_param_t param, radio_value_t value) case RADIO_PARAM_CHANNEL: res = set_channel((uint16_t)value); return (res == RF_RESULT_OK) - ? RADIO_RESULT_OK - : RADIO_RESULT_ERROR; + ? RADIO_RESULT_OK + : RADIO_RESULT_ERROR; case RADIO_PARAM_TXPOWER: if(!TX_POWER_IN_RANGE((int8_t)value)) { @@ -637,8 +644,8 @@ set_value(radio_param_t param, radio_value_t value) } res = rf_set_tx_power(prop_radio.rf_handle, TX_POWER_TABLE, (int8_t)value); return (res == RF_RESULT_OK) - ? RADIO_RESULT_OK - : RADIO_RESULT_ERROR; + ? RADIO_RESULT_OK + : RADIO_RESULT_ERROR; case RADIO_PARAM_RX_MODE: return RADIO_RESULT_OK; diff --git a/arch/cpu/cc13xx-cc26xx/rf/sched.c b/arch/cpu/cc13xx-cc26xx/rf/sched.c index 784cfff3f..d1e8bbef5 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/sched.c +++ b/arch/cpu/cc13xx-cc26xx/rf/sched.c @@ -64,9 +64,9 @@ #include /*---------------------------------------------------------------------------*/ #if 1 -# define PRINTF(...) printf(__VA_ARGS__) +#define PRINTF(...) printf(__VA_ARGS__) #else -# define PRINTF(...) +#define PRINTF(...) #endif /*---------------------------------------------------------------------------*/ #define CMD_FS_RETRIES 3 @@ -88,12 +88,12 @@ static struct etimer synth_recal_timer; /*---------------------------------------------------------------------------*/ -static RF_Object rf_netstack; -static RF_Object rf_ble; +static RF_Object rf_netstack; +static RF_Object rf_ble; static RF_CmdHandle cmd_rx_handle; -static bool rf_is_on; +static bool rf_is_on; static volatile bool rx_buf_full; /*---------------------------------------------------------------------------*/ static void @@ -214,8 +214,8 @@ rf_set_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8_t dbm) ); return (stat == RF_StatSuccess) - ? RF_RESULT_OK - : RF_RESULT_ERROR; + ? RF_RESULT_OK + : RF_RESULT_ERROR; } /*---------------------------------------------------------------------------*/ rf_result_t @@ -226,8 +226,8 @@ rf_get_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8_t *dbm) ); return (*dbm != RF_TxPowerTable_INVALID_DBM) - ? RF_RESULT_OK - : RF_RESULT_ERROR; + ? RF_RESULT_OK + : RF_RESULT_ERROR; } /*---------------------------------------------------------------------------*/ RF_Handle @@ -275,15 +275,14 @@ netstack_sched_fs(void) ); synth_error = (EVENTS_CMD_DONE(events)) - && (CMD_STATUS(netstack_cmd_fs) == ERROR_SYNTH_PROG); - + && (CMD_STATUS(netstack_cmd_fs) == ERROR_SYNTH_PROG); } while(synth_error && (num_tries++ < CMD_FS_RETRIES)); cmd_rx_restore(rx_key); return (CMD_STATUS(netstack_cmd_fs) == DONE_OK) - ? RF_RESULT_OK - : RF_RESULT_ERROR; + ? RF_RESULT_OK + : RF_RESULT_ERROR; } /*---------------------------------------------------------------------------*/ rf_result_t @@ -469,8 +468,8 @@ netstack_stop_rx(void) ENERGEST_OFF(ENERGEST_TYPE_LISTEN); return (stat == RF_StatSuccess) - ? RF_RESULT_OK - : RF_RESULT_ERROR; + ? RF_RESULT_OK + : RF_RESULT_ERROR; } /*---------------------------------------------------------------------------*/ RF_Handle @@ -563,13 +562,13 @@ PROCESS_THREAD(rf_sched_process, ev, data) NETSTACK_MAC.input(); } - /* Only break when we receive -1 => No available data */ + /* Only break when we receive -1 => No available data */ } while(len >= 0); } /* Scheduling CMD_FS will re-calibrate the synth. */ if((ev == PROCESS_EVENT_TIMER) && - etimer_expired(&synth_recal_timer)) { + etimer_expired(&synth_recal_timer)) { PRINTF("rf_core: Re-calibrate synth\n"); netstack_sched_fs(); diff --git a/arch/cpu/cc13xx-cc26xx/rf/sched.h b/arch/cpu/cc13xx-cc26xx/rf/sched.h index bd966f36b..de32dbbd4 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/sched.h +++ b/arch/cpu/cc13xx-cc26xx/rf/sched.h @@ -54,8 +54,8 @@ PROCESS_NAME(rf_sched_process); /*---------------------------------------------------------------------------*/ typedef enum { - RF_RESULT_OK = 0, - RF_RESULT_ERROR, + RF_RESULT_OK = 0, + RF_RESULT_ERROR, } rf_result_t; /*---------------------------------------------------------------------------*/ /** From 66005c923259646894a37e42ec87fad21b337e84 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Tue, 24 Jul 2018 17:24:06 +0200 Subject: [PATCH 289/485] Extracted TX Power settings to its own file --- arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 6 +- arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h | 86 +++-- .../dev/startup_cc13xx_cc26xx_gcc.c | 302 +++++++-------- .../dev/startup_cc13xx_cc26xx_iar.c | 352 +++++++++--------- .../rf-settings/cc13x0/ble-settings.c | 31 -- .../rf-settings/cc13x0/ble-settings.h | 16 +- .../rf-settings/cc13x0/ble-tx-power.c | 98 +++++ .../rf-settings/cc13x0/ieee-settings.c | 33 -- .../rf-settings/cc13x0/ieee-settings.h | 4 - .../rf-settings/cc13x0/ieee-tx-power.c | 93 +++++ .../rf-settings/cc13x0/prop-settings.c | 115 ------ .../rf-settings/cc13x0/prop-tx-power.c | 168 +++++++++ .../rf-settings/cc13x2/ble-settings.c | 27 -- .../rf-settings/cc13x2/ble-settings.h | 22 +- .../rf-settings/cc13x2/ble-tx-power.c | 151 ++++++++ .../rf-settings/cc13x2/ieee-settings.c | 102 ----- .../rf-settings/cc13x2/ieee-settings.h | 4 - .../rf-settings/cc13x2/ieee-tx-power.c | 186 +++++++++ .../rf-settings/cc13x2/prop-settings.c | 111 ------ .../rf-settings/cc13x2/prop-settings.h | 4 - .../rf-settings/cc13x2/prop-tx-power.c | 203 ++++++++++ .../rf-settings/cc26x0/ble-settings.c | 25 -- .../rf-settings/cc26x0/ble-settings.h | 16 +- .../rf-settings/cc26x0/ble-tx-power.c | 88 +++++ .../rf-settings/cc26x0/ieee-settings.c | 32 -- .../rf-settings/cc26x0/ieee-settings.h | 4 - .../rf-settings/cc26x0/ieee-tx-power.c | 93 +++++ .../rf-settings/cc26x2/ble-settings.c | 27 -- .../rf-settings/cc26x2/ble-settings.h | 6 - .../rf-settings/cc26x2/ble-tx-power.c | 90 +++++ .../rf-settings/cc26x2/ieee-settings.c | 34 -- .../rf-settings/cc26x2/ieee-settings.h | 4 - .../rf-settings/cc26x2/ieee-tx-power.c | 95 +++++ arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c | 27 +- arch/cpu/cc13xx-cc26xx/rf/data-queue.c | 4 +- arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c | 137 +++---- arch/cpu/cc13xx-cc26xx/rf/prop-mode.c | 116 +++--- arch/cpu/cc13xx-cc26xx/rf/sched.c | 56 +-- .../rf-settings.h => rf/settings.h} | 59 ++- arch/cpu/cc13xx-cc26xx/rf/tx-power.h | 106 ++++++ .../cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 1 + .../simplelink/cc13xx-cc26xx/platform.c | 10 +- .../cc13xx-cc26xx/sensortag/bmp-280-sensor.c | 14 +- .../cc13xx-cc26xx/sensortag/bmp-280-sensor.h | 4 + .../cc13xx-cc26xx/sensortag/board-conf.h | 9 + .../sensortag/cc2650/Makefile.cc2650 | 2 +- .../cc13xx-cc26xx/sensortag/hdc-1000-sensor.c | 11 + .../cc13xx-cc26xx/sensortag/hdc-1000-sensor.h | 4 + .../cc13xx-cc26xx/sensortag/mpu-9250-sensor.c | 12 +- .../cc13xx-cc26xx/sensortag/mpu-9250-sensor.h | 4 + .../cc13xx-cc26xx/sensortag/opt-3001-sensor.c | 12 +- .../cc13xx-cc26xx/sensortag/opt-3001-sensor.h | 4 + .../sensortag/sensortag-sensors.c | 5 +- .../cc13xx-cc26xx/sensortag/tmp-007-sensor.c | 12 +- .../cc13xx-cc26xx/sensortag/tmp-007-sensor.h | 4 + .../cc13xx-cc26xx/srf06/board-conf.h | 9 + .../cc13xx-cc26xx/srf06/srf06-sensors.c | 5 +- 57 files changed, 2068 insertions(+), 1187 deletions(-) create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-tx-power.c create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-tx-power.c create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-tx-power.c create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-tx-power.c create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-tx-power.c create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-tx-power.c create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-tx-power.c create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-tx-power.c create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-tx-power.c create mode 100644 arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-tx-power.c rename arch/cpu/cc13xx-cc26xx/{rf-settings/rf-settings.h => rf/settings.h} (87%) create mode 100644 arch/cpu/cc13xx-cc26xx/rf/tx-power.h diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index 6605ea849..3c86a2a50 100644 --- a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -79,15 +79,15 @@ CONTIKI_CPU_SOURCEFILES += ieee-addr.c ble-addr.c CONTIKI_CPU_SOURCEFILES += ble-beacond.c ifeq ($(SUPPORTS_PROP_MODE),1) -CONTIKI_CPU_SOURCEFILES += prop-mode.c prop-settings.c +CONTIKI_CPU_SOURCEFILES += prop-mode.c prop-settings.c prop-tx-power.c endif ifeq ($(SUPPORTS_IEEE_MODE),1) -CONTIKI_CPU_SOURCEFILES += ieee-mode.c ieee-settings.c +CONTIKI_CPU_SOURCEFILES += ieee-mode.c ieee-settings.c ieee-tx-power.c endif ifeq ($(SUPPORTS_BLE_BEACON),1) -CONTIKI_CPU_SOURCEFILES += ble-settings.c +CONTIKI_CPU_SOURCEFILES += ble-settings.c ble-tx-power.c endif ### CPU-dependent debug source files diff --git a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h index 08e5a4916..e32819285 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h +++ b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h @@ -45,12 +45,20 @@ #include "rf/rf.h" /*---------------------------------------------------------------------------*/ +/** + * \name Board Configuration. + * + * @{ + */ + +/* Configure that a board has sensors for the dev/sensors.h API. */ #ifndef BOARD_CONF_HAS_SENSORS #define BOARD_CONF_HAS_SENSORS 0 #endif -#ifndef BOARD_CONF_SENSORS_ENABLE -#define BOARD_CONF_SENSORS_ENABLE BOARD_CONF_HAS_SENSORS +/* Enable/disable the dev/sensors.h API for the given board. */ +#ifndef BOARD_CONF_SENSORS_DISABLE +#define BOARD_CONF_SENSORS_DISABLE 0 #endif /*---------------------------------------------------------------------------*/ /** @@ -128,24 +136,18 @@ #endif /* RF_CONF_MODE */ /* Number of RX buffers. */ -#ifdef RF_CONF_RX_BUF_CNT -#define RF_RX_BUF_CNT RF_CONF_RX_BUF_CNT -#else -#define RF_RX_BUF_CNT 4 +#ifndef RF_CONF_RX_BUF_CNT +#define RF_CONF_RX_BUF_CNT 4 #endif /* Size of each RX buffer in bytes. */ -#ifdef RF_CONF_RX_BUF_SIZE -#define RF_RX_BUF_SIZE RF_CONF_RX_BUF_SIZE -#else -#define RF_RX_BUF_SIZE 144 +#ifndef RF_CONF_RX_BUF_SIZE +#define RF_CONF_RX_BUF_SIZE 144 #endif /* Enable/disable BLE beacon. */ -#ifdef RF_CONF_BLE_BEACON_ENABLE -#define RF_BLE_BEACON_ENABLE RF_CONF_BLE_BEACON_ENABLE -#else -#define RF_BLE_BEACON_ENABLE 0 +#ifndef RF_CONF_BLE_BEACON_ENABLE +#define RF_CONF_BLE_BEACON_ENABLE 0 #endif #if (RF_BLE_BEACON_ENABLE) && !(SUPPORTS_BLE_BEACON) @@ -245,31 +247,73 @@ /** @} */ /*---------------------------------------------------------------------------*/ /** - * \name IEEE-mode configuration. + * \name IEEE-mode configuration. * * @{ */ /** - * \brief Configure auto-ACK for IEEE-mode, which is ACK generated by the - * radio. + * \brief Configuration to enable/disable auto ACKs in IEEE-mode. * 0 => ACK generated by software * 1 => ACK generated by the radio. */ #ifndef IEEE_MODE_CONF_AUTOACK -#define IEEE_MODE_CONF_AUTOACK 1 /**< RF H/W generates ACKs */ +#define IEEE_MODE_CONF_AUTOACK 1 #endif /** - * \brief Configure promiscouos mode for IEEE-mode. + * \brief Configuration to enable/disable frame filtering in IEEE-mode. + * 0 => Disable promiscous mode. + * 1 => Enable promiscous mode. */ #ifndef IEEE_MODE_CONF_PROMISCOUS -#define IEEE_MODE_CONF_PROMISCOUS 0 /**< 1 to enable promiscous mode */ +#define IEEE_MODE_CONF_PROMISCOUS 0 +#endif + +/** + * \brief Configuration to set the RSSI threshold in dBm in IEEE-mode. + * Defaults to -90 dBm. + */ +#ifndef IEEE_MODE_CONF_CCA_RSSI_THRESHOLD +#define IEEE_MODE_CONF_CCA_RSSI_THRESHOLD 0xA6 #endif /** @} */ /*---------------------------------------------------------------------------*/ /** - * \name TI Drivers Configuration. + * \name Prop-mode configuration. + * + * @{ + */ + +/** + * \brief Configuration to set whitener in Prop-mode. + * 0 => No whitener + * 1 => Whitener. + */ +#ifndef PROP_MODE_CONF_DW +#define PROP_MODE_CONF_DW 0 +#endif + +/** + * \brief Use 16-bit or 32-bit CRC in Prop-mode. + * 0 => 32-bit CRC. + * 1 => 16-bit CRC. + */ +#ifndef PROP_MODE_CONF_USE_CRC16 +#define PROP_MODE_CONF_USE_CRC16 0 +#endif + +/** + * \brief Configuration to set the RSSI threshold in dBm in Prop-mode. + * Defaults to -90 dBm. + */ +#ifndef PROP_MODE_CONF_CCA_RSSI_THRESHOLD +#define PROP_MODE_CONF_CCA_RSSI_THRESHOLD 0xA6 +#endif +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \name TI Drivers Configuration. * * @{ */ diff --git a/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c b/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c index dbcbe3048..b5bb2c13c 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c +++ b/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_gcc.c @@ -1,93 +1,77 @@ /* - * Copyright (c) 2017, Texas Instruments Incorporated + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: - * - * * Redistributions of source code must retain the above copyright + * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright + * 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. - * - * * Neither the name of Texas Instruments Incorporated nor the names of - * its contributors may be used to endorse or promote products derived + * 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 OWNER 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 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. */ - - -//***************************************************************************** -// -// Check if compiler is GNU Compiler -// -//***************************************************************************** +/** + * \addtogroup cc13xx-cc26xx-cpu + * @{ + * + * \file + * Startup file for GCC for CC13xx/CC26xx. + */ +/*---------------------------------------------------------------------------*/ +/* Check if compiler is GNU Compiler. */ #if !(defined(__GNUC__)) #error "startup_cc13xx_cc26xx_gcc.c: Unsupported compiler!" #endif - +/*---------------------------------------------------------------------------*/ #include #include #include DeviceFamily_constructPath(inc/hw_types.h) #include DeviceFamily_constructPath(driverlib/interrupt.h) #include DeviceFamily_constructPath(driverlib/setup.h) - -//***************************************************************************** -// -// Forward declaration of the default fault handlers. -// -//***************************************************************************** +/*---------------------------------------------------------------------------*/ +/* Forward declaration of the default fault handlers. */ void resetISR(void); static void nmiISR(void); static void faultISR(void); static void defaultHandler(void); static void busFaultHandler(void); - -//***************************************************************************** -// -// External declaration for the reset handler that is to be called when the -// processor is started -// -//***************************************************************************** +/*---------------------------------------------------------------------------*/ +/* + * External declaration for the reset handler that is to be called when the + * processor is started. + */ extern void _c_int00(void); -//***************************************************************************** -// -// The entry point for the application. -// -//***************************************************************************** +/* The entry point for the application. */ extern int main(void); - -//***************************************************************************** -// -// linker variable that marks the top of stack. -// -//***************************************************************************** +/*---------------------------------------------------------------------------*/ +/* Linker variable that marks the top of stack. */ extern unsigned long _stack_end; -//***************************************************************************** -// -// The vector table. Note that the proper constructs must be placed on this to -// ensure that it ends up at physical address 0x0000.0000. -// -//***************************************************************************** -__attribute__ ((section(".resetVecs"))) __attribute__ ((used)) -static void(*const resetVectors[16]) (void) = +/* + * The vector table. Note that the proper constructs must be placed on this to + * ensure that it ends up at physical address 0x0000.0000. + */ +__attribute__((section(".resetVecs"))) __attribute__((used)) +static void(*const resetVectors[16])(void) = { (void (*)(void))((uint32_t)&_stack_end), /* The initial stack pointer */ @@ -107,45 +91,35 @@ static void(*const resetVectors[16]) (void) = defaultHandler, /* The PendSV handler */ defaultHandler /* The SysTick handler */ }; -//***************************************************************************** -// -// The following are arrays of pointers to constructor functions that need to -// be called during startup to initialize global objects. -// -//***************************************************************************** +/*---------------------------------------------------------------------------*/ +/* + * The following are arrays of pointers to constructor functions that need to + * be called during startup to initialize global objects. + */ extern void (*__init_array_start[])(void); extern void (*__init_array_end[])(void); -//***************************************************************************** -// -// The following global variable is required for C++ support. -// -//***************************************************************************** +/* The following global variable is required for C++ support. */ void *__dso_handle = (void *)&__dso_handle; - -//***************************************************************************** -// -// The following are constructs created by the linker, indicating where the -// the "data" and "bss" segments reside in memory. The initializers for the -// for the "data" segment resides immediately following the "text" segment. -// -//***************************************************************************** +/*---------------------------------------------------------------------------*/ +/* + * The following are constructs created by the linker, indicating where the + * the "data" and "bss" segments reside in memory. The initializers for the + * for the "data" segment resides immediately following the "text" segment. + */ extern uint32_t __bss_start__; extern uint32_t __bss_end__; extern uint32_t __data_load__; extern uint32_t __data_start__; extern uint32_t __data_end__; - -// -//***************************************************************************** -// -// Initialize the .data and .bss sections and copy the first 16 vectors from -// the read-only/reset table to the runtime RAM table. Fill the remaining -// vectors with a stub. This vector table will be updated at runtime. -// -//***************************************************************************** -// -void localProgramStart(void) +/*---------------------------------------------------------------------------*/ +/* + * \brief Entry point of the startup code. + * + * Initialize the .data and .bss sections, and call main. + */ +void +localProgramStart(void) { uint32_t *bs; uint32_t *be; @@ -199,18 +173,19 @@ void localProgramStart(void) /* If we ever return signal Error */ faultISR(); } - -//***************************************************************************** -// -// This is the code that gets called when the processor first starts execution -// following a reset event. Only the absolutely necessary set is performed, -// after which the application supplied entry() routine is called. Any fancy -// actions (such as making decisions based on the reset cause register, and -// resetting the bits in that register) are left solely in the hands of the -// application. -// -//***************************************************************************** -void __attribute__((naked)) resetISR(void) +/*---------------------------------------------------------------------------*/ +/* + * \brief Reset ISR. + * + * This is the code that gets called when the processor first starts execution + * following a reset event. Only the absolutely necessary set is performed, + * after which the application supplied entry() routine is called. Any fancy + * actions (such as making decisions based on the reset cause register, and + * resetting the bits in that register) are left solely in the hands of the + * application. + */ +void __attribute__((naked)) +resetISR(void) { __asm__ __volatile__ ( @@ -221,40 +196,38 @@ void __attribute__((naked)) resetISR(void) "bl localProgramStart \n" ); } - -//***************************************************************************** -// -// This is the code that gets called when the processor receives a NMI. This -// simply enters an infinite loop, preserving the system state for examination -// by a debugger. -// -//***************************************************************************** +/*---------------------------------------------------------------------------*/ +/* + * \brief Non-Maskable Interrupt (NMI) ISR. + * + * This is the code that gets called when the processor receives a NMI. This + * simply enters an infinite loop, preserving the system state for examination + * by a debugger. + */ static void nmiISR(void) { /* Enter an infinite loop. */ - while(1) { - } + for(;;) { /* hang */ } } - -//***************************************************************************** -// -// This is the code that gets called when the processor receives a fault -// interrupt. This simply enters an infinite loop, preserving the system state -// for examination by a debugger. -// -//***************************************************************************** +/*---------------------------------------------------------------------------*/ +/* + * \brief Debug stack pointer. + * \param sp Stack pointer. + * + * Provide a view into the CPU state from the provided stack pointer. + */ void debugHardfault(uint32_t *sp) { - volatile uint32_t r0; - volatile uint32_t r1; - volatile uint32_t r2; - volatile uint32_t r3; - volatile uint32_t r12; - volatile uint32_t lr; - volatile uint32_t pc; - volatile uint32_t psr; + volatile uint32_t r0; /**< R0 register */ + volatile uint32_t r1; /**< R1 register */ + volatile uint32_t r2; /**< R2 register */ + volatile uint32_t r3; /**< R3 register */ + volatile uint32_t r12; /**< R12 register */ + volatile uint32_t lr; /**< LR register */ + volatile uint32_t pc; /**< PC register */ + volatile uint32_t psr; /**< PSR register */ (void)(r0 = sp[0]); (void)(r1 = sp[1]); @@ -265,9 +238,18 @@ debugHardfault(uint32_t *sp) (void)(pc = sp[6]); (void)(psr = sp[7]); - while(1); + /* Enter an infinite loop. */ + for(;;) { /* hang */ } } - +/*---------------------------------------------------------------------------*/ +/* + * \brief CPU Fault ISR. + * + * This is the code that gets called when the processor receives a fault + * interrupt. Setup a call to debugStackPointer with the current stack pointer. + * The stack pointer in this case would be the CPU state which caused the CPU + * fault. + */ static void faultISR(void) { @@ -280,48 +262,50 @@ faultISR(void) "b debugHardfault \n" ); } - -//***************************************************************************** -// -// This is the code that gets called when the processor receives an unexpected -// interrupt. This simply enters an infinite loop, preserving the system state -// for examination by a debugger. -// -//***************************************************************************** +/*---------------------------------------------------------------------------*/ +/* Dummy variable */ volatile int x__; +/* + * \brief Bus Fault Handler. + * + * This is the code that gets called when the processor receives an unexpected + * interrupt. This simply enters an infinite loop, preserving the system state + * for examination by a debugger. + */ static void busFaultHandler(void) { x__ = 0; - /* Enter an infinite loop. */ - while(1) { - } -} -//***************************************************************************** -// -// This is the code that gets called when the processor receives an unexpected -// interrupt. This simply enters an infinite loop, preserving the system state -// for examination by a debugger. -// -//***************************************************************************** + /* Enter an infinite loop. */ + for(;;) { /* hang */ } +} +/*---------------------------------------------------------------------------*/ +/* + * \brief Default Handler. + * + * This is the code that gets called when the processor receives an unexpected + * interrupt. This simply enters an infinite loop, preserving the system state + * for examination by a debugger. + */ static void defaultHandler(void) { /* Enter an infinite loop. */ - while(1) { - } + for(;;) { /* hang */ } } - -//***************************************************************************** -// -// This function is called by __libc_fini_array which gets called when exit() -// is called. In order to support exit(), an empty _fini() stub function is -// required. -// -//***************************************************************************** -void _fini(void) +/*---------------------------------------------------------------------------*/ +/* + * \brief Finalize object function. + * + * This function is called by __libc_fini_array which gets called when exit() + * is called. In order to support exit(), an empty _fini() stub function is + * required. + */ +void +_fini(void) { /* Function body left empty intentionally */ } +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_iar.c b/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_iar.c index 70981ef77..3624c20ac 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_iar.c +++ b/arch/cpu/cc13xx-cc26xx/dev/startup_cc13xx_cc26xx_iar.c @@ -1,57 +1,54 @@ /* - * Copyright (c) 2017, Texas Instruments Incorporated + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: - * - * * Redistributions of source code must retain the above copyright + * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright + * 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. - * - * * Neither the name of Texas Instruments Incorporated nor the names of - * its contributors may be used to endorse or promote products derived + * 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 OWNER 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 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. */ - -//***************************************************************************** -// -// Check if compiler is IAR -// -//***************************************************************************** +/** + * \addtogroup cc13xx-cc26xx-cpu + * @{ + * + * \file + * Startup file for IAR for CC13xx/CC26xx. + */ +/*---------------------------------------------------------------------------*/ +/* Check if compiler is IAR. */ #if !(defined(__IAR_SYSTEMS_ICC__)) #error "startup_cc13xx_cc26xx_iar.c: Unsupported compiler!" #endif - -/* We need intrinsic functions for IAR (if used in source code) */ +/*---------------------------------------------------------------------------*/ +/* We need intrinsic functions for IAR (if used in source code). */ #include + #include #include DeviceFamily_constructPath(inc/hw_types.h) #include DeviceFamily_constructPath(driverlib/setup.h) #include DeviceFamily_constructPath(driverlib/interrupt.h) - - -//***************************************************************************** -// -//! Forward declaration of the reset ISR and the default fault handlers. -// -//***************************************************************************** +/*---------------------------------------------------------------------------*/ +/* Forward declaration of the reset ISR and the default fault handlers. */ static void nmiISR( void ); static void faultISR( void ); static void intDefaultHandler( void ); @@ -139,167 +136,182 @@ extern void TRNGIntHandler(void); #pragma weak AUXCompAIntHandler = intDefaultHandler #pragma weak AUXADCIntHandler = intDefaultHandler #pragma weak TRNGIntHandler = intDefaultHandler - -//***************************************************************************** -// -//! The entry point for the application startup code. -// -//***************************************************************************** +/*---------------------------------------------------------------------------*/ +/* The entry point for the application startup code. */ extern void __iar_program_start(void); -//***************************************************************************** -// -//! Get stack start (highest address) symbol from linker file. -// -//***************************************************************************** +/* Get stack start (highest address) symbol from linker file. */ extern const void* STACK_TOP; - -// It is required to place something in the CSTACK segment to get the stack -// check feature in IAR to work as expected +/*---------------------------------------------------------------------------*/ +/* + * It is required to place something in the CSTACK segment to get the stack + * check feature in IAR to work as expected + */ __root static void* dummy_stack @ ".stack"; - -//***************************************************************************** -// -//! The vector table. Note that the proper constructs must be placed on this to -//! ensure that it ends up at physical address 0x0000.0000 or at the start of -//! the program if located at a start address other than 0. -// -//***************************************************************************** +/* + * The vector table. Note that the proper constructs must be placed on this to + * ensure that it ends up at physical address 0x0000.0000 or at the start of + * the program if located at a start address other than 0. + */ __root void (* const __vector_table[])(void) @ ".intvec" = { - (void (*)(void))&STACK_TOP, // 0 The initial stack pointer - __iar_program_start, // 1 The reset handler - nmiISR, // 2 The NMI handler - faultISR, // 3 The hard fault handler - MPUFaultIntHandler, // 4 The MPU fault handler - BusFaultIntHandler, // 5 The bus fault handler - UsageFaultIntHandler, // 6 The usage fault handler - 0, // 7 Reserved - 0, // 8 Reserved - 0, // 9 Reserved - 0, // 10 Reserved - SVCallIntHandler, // 11 SVCall handler - DebugMonIntHandler, // 12 Debug monitor handler - 0, // 13 Reserved - PendSVIntHandler, // 14 The PendSV handler - SysTickIntHandler, // 15 The SysTick handler - //--- External interrupts --- - GPIOIntHandler, // 16 AON edge detect - I2CIntHandler, // 17 I2C - RFCCPE1IntHandler, // 18 RF Core Command & Packet Engine 1 - intDefaultHandler, // 19 Reserved - AONRTCIntHandler, // 20 AON RTC - UART0IntHandler, // 21 UART0 Rx and Tx - AUXSWEvent0IntHandler, // 22 AUX software event 0 - SSI0IntHandler, // 23 SSI0 Rx and Tx - SSI1IntHandler, // 24 SSI1 Rx and Tx - RFCCPE0IntHandler, // 25 RF Core Command & Packet Engine 0 - RFCHardwareIntHandler, // 26 RF Core Hardware - RFCCmdAckIntHandler, // 27 RF Core Command Acknowledge - I2SIntHandler, // 28 I2S - AUXSWEvent1IntHandler, // 29 AUX software event 1 - WatchdogIntHandler, // 30 Watchdog timer - Timer0AIntHandler, // 31 Timer 0 subtimer A - Timer0BIntHandler, // 32 Timer 0 subtimer B - Timer1AIntHandler, // 33 Timer 1 subtimer A - Timer1BIntHandler, // 34 Timer 1 subtimer B - Timer2AIntHandler, // 35 Timer 2 subtimer A - Timer2BIntHandler, // 36 Timer 2 subtimer B - Timer3AIntHandler, // 37 Timer 3 subtimer A - Timer3BIntHandler, // 38 Timer 3 subtimer B - CryptoIntHandler, // 39 Crypto Core Result available - uDMAIntHandler, // 40 uDMA Software - uDMAErrIntHandler, // 41 uDMA Error - FlashIntHandler, // 42 Flash controller - SWEvent0IntHandler, // 43 Software Event 0 - AUXCombEventIntHandler, // 44 AUX combined event - AONProgIntHandler, // 45 AON programmable 0 - DynProgIntHandler, // 46 Dynamic Programmable interrupt - // source (Default: PRCM) - AUXCompAIntHandler, // 47 AUX Comparator A - AUXADCIntHandler, // 48 AUX ADC new sample or ADC DMA - // done, ADC underflow, ADC overflow - TRNGIntHandler // 49 TRNG event + (void (*)(void))&STACK_TOP, /* 0 The initial stack pointer */ + __iar_program_start, /* 1 The reset handler */ + nmiISR, /* 2 The NMI handler */ + faultISR, /* 3 The hard fault handler */ + MPUFaultIntHandler, /* 4 The MPU fault handler */ + BusFaultIntHandler, /* 5 The bus fault handler */ + UsageFaultIntHandler, /* 6 The usage fault handler */ + 0, /* 7 Reserved */ + 0, /* 8 Reserved */ + 0, /* 9 Reserved */ + 0, /* 10 Reserved */ + SVCallIntHandler, /* 11 SVCall handler */ + DebugMonIntHandler, /* 12 Debug monitor handler */ + 0, /* 13 Reserved */ + PendSVIntHandler, /* 14 The PendSV handler */ + SysTickIntHandler, /* 15 The SysTick handler */ + /* --- External interrupts --- */ + GPIOIntHandler, /* 16 AON edge detect */ + I2CIntHandler, /* 17 I2C */ + RFCCPE1IntHandler, /* 18 RF Core Command & Packet Engine 1 */ + intDefaultHandler, /* 19 Reserved */ + AONRTCIntHandler, /* 20 AON RTC */ + UART0IntHandler, /* 21 UART0 Rx and Tx */ + AUXSWEvent0IntHandler, /* 22 AUX software event 0 */ + SSI0IntHandler, /* 23 SSI0 Rx and Tx */ + SSI1IntHandler, /* 24 SSI1 Rx and Tx */ + RFCCPE0IntHandler, /* 25 RF Core Command & Packet Engine 0 */ + RFCHardwareIntHandler, /* 26 RF Core Hardware */ + RFCCmdAckIntHandler, /* 27 RF Core Command Acknowledge */ + I2SIntHandler, /* 28 I2S */ + AUXSWEvent1IntHandler, /* 29 AUX software event 1 */ + WatchdogIntHandler, /* 30 Watchdog timer */ + Timer0AIntHandler, /* 31 Timer 0 subtimer A */ + Timer0BIntHandler, /* 32 Timer 0 subtimer B */ + Timer1AIntHandler, /* 33 Timer 1 subtimer A */ + Timer1BIntHandler, /* 34 Timer 1 subtimer B */ + Timer2AIntHandler, /* 35 Timer 2 subtimer A */ + Timer2BIntHandler, /* 36 Timer 2 subtimer B */ + Timer3AIntHandler, /* 37 Timer 3 subtimer A */ + Timer3BIntHandler, /* 38 Timer 3 subtimer B */ + CryptoIntHandler, /* 39 Crypto Core Result available */ + uDMAIntHandler, /* 40 uDMA Software */ + uDMAErrIntHandler, /* 41 uDMA Error */ + FlashIntHandler, /* 42 Flash controller */ + SWEvent0IntHandler, /* 43 Software Event 0 */ + AUXCombEventIntHandler, /* 44 AUX combined event */ + AONProgIntHandler, /* 45 AON programmable 0 */ + DynProgIntHandler, /* 46 Dynamic Programmable interrupt */ + /* source (Default: PRCM) */ + AUXCompAIntHandler, /* 47 AUX Comparator A */ + AUXADCIntHandler, /* 48 AUX ADC new sample or ADC DMA */ + /* done, ADC underflow, ADC overflow */ + TRNGIntHandler /* 49 TRNG event */ }; - - -//***************************************************************************** -// -// This function is called by __iar_program_start() early in the boot sequence. -// Copy the first 16 vectors from the read-only/reset table to the runtime -// RAM table. Fill the remaining vectors with a stub. This vector table will -// be updated at runtime. -// -//***************************************************************************** -int __low_level_init(void) +/*---------------------------------------------------------------------------*/ +/* + * \brief Setup trim device. + * \return Return value determines whether to omit seg_init or not. + * 0 => omit seg_init + * 1 => run seg_init + * + * This function is called by __iar_program_start() early in the boot sequence. + * Copy the first 16 vectors from the read-only/reset table to the runtime + * RAM table. Fill the remaining vectors with a stub. This vector table will + * be updated at runtime. + */ +int +__low_level_init(void) { IntMasterDisable(); - // - // Final trim of device - // + /* Final trim of device */ SetupTrimDevice(); - /*==================================*/ - /* Choose if segment initialization */ - /* should be done or not. */ - /* Return: 0 to omit seg_init */ - /* 1 to run seg_init */ - /*==================================*/ + /* Run seg_init */ return 1; } - -//***************************************************************************** -// -//! This is the code that gets called when the processor receives a NMI. This -//! simply enters an infinite loop, preserving the system state for examination -//! by a debugger. -// -//***************************************************************************** +/*---------------------------------------------------------------------------*/ +/* + * \brief Non-Maskable Interrupt (NMI) ISR. + * + * This is the code that gets called when the processor receives a NMI. This + * simply enters an infinite loop, preserving the system state for examination + * by a debugger. + */ static void nmiISR(void) { - // - // Enter an infinite loop. - // - while(1) - { - } + /* Enter an infinite loop. */ + for(;;) { /* hang */ } } +/*---------------------------------------------------------------------------*/ +/* + * \brief Debug stack pointer. + * \param sp Stack pointer. + * + * Provide a view into the CPU state from the provided stack pointer. + */ +void +debugStackPointer(uint32_t *sp) +{ + volatile uint32_t r0; /**< R0 register */ + volatile uint32_t r1; /**< R1 register */ + volatile uint32_t r2; /**< R2 register */ + volatile uint32_t r3; /**< R3 register */ + volatile uint32_t r12; /**< R12 register */ + volatile uint32_t lr; /**< LR register */ + volatile uint32_t pc; /**< PC register */ + volatile uint32_t psr; /**< PSR register */ -//***************************************************************************** -// -//! This is the code that gets called when the processor receives a fault -//! interrupt. This simply enters an infinite loop, preserving the system state -//! for examination by a debugger. -// -//***************************************************************************** + /* Cast to void to disable warnings of unused variables */ + (void)(r0 = sp[0]); + (void)(r1 = sp[1]); + (void)(r2 = sp[2]); + (void)(r3 = sp[3]); + (void)(r12 = sp[4]); + (void)(lr = sp[5]); + (void)(pc = sp[6]); + (void)(psr = sp[7]); + + /* Enter an infinite loop. */ + for(;;) { /* hang */ } +} +/*---------------------------------------------------------------------------*/ +/* + * \brief CPU Fault ISR. + * + * This is the code that gets called when the processor receives a fault + * interrupt. Setup a call to debugStackPointer with the current stack pointer. + * The stack pointer in this case would be the CPU state which caused the CPU + * fault. + */ static void faultISR(void) { - // - // Enter an infinite loop. - // - while(1) - { - } + __asm__ __volatile__ + ( + "tst lr, #4 \n" + "ite eq \n" + "mrseq r0, msp \n" + "mrsne r0, psp \n" + "b debugStackPointer \n" + ); } - -//***************************************************************************** -// -//! This is the code that gets called when the processor receives an unexpected -//! interrupt. This simply enters an infinite loop, preserving the system state -//! for examination by a debugger. -// -//***************************************************************************** +/*---------------------------------------------------------------------------*/ +/* + * \brief Interrupt Default Handler. + * + * This is the code that gets called when the processor receives an unexpected + * interrupt. This simply enters an infinite loop, preserving the system state + * for examination by a debugger. + */ static void intDefaultHandler(void) { - // - // Go into an infinite loop. - // - while(1) - { - } + /* Enter an infinite loop. */ + for(;;) { /* hang */ } } +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.c index 59054c175..7fc79ae2d 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.c @@ -62,37 +62,6 @@ RF_Mode rf_ble_mode = .rfePatchFxn = &rf_patch_rfe_ble, }; /*---------------------------------------------------------------------------*/ -/* TX Power table */ -/* The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: */ -/* RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) */ -/* See the Technical Reference Manual for further details about the "txPower" Command field. */ -/* The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. */ -RF_TxPowerTable_Entry rf_ble_tx_power_table[RF_BLE_TX_POWER_TABLE_SIZE+1] = -{ - { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 3, 1, 6) }, - { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 1, 6) }, - { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 3, 1, 10) }, - { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 3, 1, 12) }, - { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(26, 3, 1, 14) }, - { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(35, 3, 1, 18) }, - { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(47, 3, 1, 22) }, - { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(29, 0, 1, 45) }, - { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(33, 0, 1, 49) }, - { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(38, 0, 1, 55) }, - { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(44, 0, 1, 63) }, - { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(52, 0, 1, 59) }, - { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(60, 0, 1, 47) }, - /* This setting requires CCFG_FORCE_VDDR_HH = 1. */ - { 6, RF_TxPowerTable_DEFAULT_PA_ENTRY(38, 0, 1, 49) }, - /* This setting requires CCFG_FORCE_VDDR_HH = 1. */ - { 7, RF_TxPowerTable_DEFAULT_PA_ENTRY(46, 0, 1, 59) }, - /* This setting requires CCFG_FORCE_VDDR_HH = 1. */ - { 8, RF_TxPowerTable_DEFAULT_PA_ENTRY(55, 0, 1, 51) }, - /* This setting requires CCFG_FORCE_VDDR_HH = 1. */ - { 9, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 30) }, - RF_TxPowerTable_TERMINATION_ENTRY -}; -/*---------------------------------------------------------------------------*/ /* Overrides for CMD_RADIO_SETUP */ uint32_t rf_ble_overrides[] CC_ALIGN(4) = { diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.h index 83d2614aa..81fbf67ba 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-settings.h @@ -38,22 +38,16 @@ #include /*---------------------------------------------------------------------------*/ -/* TX Power table size definition */ -#define RF_BLE_TX_POWER_TABLE_SIZE 17 - -/* TX Power Table Object */ -extern RF_TxPowerTable_Entry rf_ble_tx_power_table[RF_BLE_TX_POWER_TABLE_SIZE+1]; -/*---------------------------------------------------------------------------*/ /* TI-RTOS RF Mode Object */ -extern RF_Mode rf_ble_mode; +extern RF_Mode rf_ble_mode; /*---------------------------------------------------------------------------*/ /* RF Core API commands */ -extern rfc_CMD_RADIO_SETUP_t rf_ble_cmd_radio_setup; -extern rfc_bleAdvPar_t rf_ble_adv_par; -extern rfc_CMD_BLE_ADV_NC_t rf_ble_cmd_ble_adv_nc; +extern rfc_CMD_RADIO_SETUP_t rf_ble_cmd_radio_setup; +extern rfc_bleAdvPar_t rf_ble_adv_par; +extern rfc_CMD_BLE_ADV_NC_t rf_ble_cmd_ble_adv_nc; /*---------------------------------------------------------------------------*/ /* RF Core API Overrides */ -extern uint32_t rf_ble_overrides[]; +extern uint32_t rf_ble_overrides[]; /*---------------------------------------------------------------------------*/ #endif /* BLE_SETTINGS_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-tx-power.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-tx-power.c new file mode 100644 index 000000000..16a5b37b7 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ble-tx-power.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/** + * \addtogroup cc13xx-cc26xx-rf-tx-power + * @{ + * + * \file + * Source file for BLE Beacon TX power tables for CC13x0. + * \author + * Edvard Pettersen + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +/*---------------------------------------------------------------------------*/ +#include "rf/tx-power.h" +/*---------------------------------------------------------------------------*/ +/* + * TX Power table for CC1350 + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +tx_power_table_t rf_ble_tx_power_table_cc1350[] = +{ + { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 3, 1, 6) }, + { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 1, 6) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 3, 1, 10) }, + { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 3, 1, 12) }, + { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(26, 3, 1, 14) }, + { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(35, 3, 1, 18) }, + { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(47, 3, 1, 22) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(29, 0, 1, 45) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(33, 0, 1, 49) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(38, 0, 1, 55) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(44, 0, 1, 63) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(52, 0, 1, 59) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(60, 0, 1, 47) }, +#if RF_TXPOWER_BOOST_MODE + /* This setting requires CCFG_FORCE_VDDR_HH = 1. */ + { 6, RF_TxPowerTable_DEFAULT_PA_ENTRY(38, 0, 1, 49) }, + /* This setting requires CCFG_FORCE_VDDR_HH = 1. */ + { 7, RF_TxPowerTable_DEFAULT_PA_ENTRY(46, 0, 1, 59) }, + /* This setting requires CCFG_FORCE_VDDR_HH = 1. */ + { 8, RF_TxPowerTable_DEFAULT_PA_ENTRY(55, 0, 1, 51) }, + /* This setting requires CCFG_FORCE_VDDR_HH = 1. */ + { 9, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 30) }, +#endif + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +tx_power_table_t rf_ble_tx_power_table_empty[] = +{ + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +/* TX power table, based on which board is used. */ +#elif defined(DEVICE_CC1350) || defined(DEVICE_CC1350_4) +#define TX_POWER_TABLE rf_ble_tx_power_table_cc1350 + +#else +#define TX_POWER_TABLE rf_ble_tx_power_table_empty +#endif + +/* + * Define symbols for both the TX power table and its size. The TX power + * table size is with one less entry by excluding the termination entry. + */ +tx_power_table_t *const ble_tx_power_table = TX_POWER_TABLE; +const size_t ble_tx_power_table_size = (sizeof(TX_POWER_TABLE) / sizeof(TX_POWER_TABLE[0])) - 1; +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c index c2d7b5fdc..2a383e6c6 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.c @@ -63,44 +63,11 @@ RF_Mode rf_ieee_mode = .rfePatchFxn = 0, }; /*---------------------------------------------------------------------------*/ -/* - * TX Power table - * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: - * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) - * See the Technical Reference Manual for further details about the "txPower" Command field. - * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. - */ -RF_TxPowerTable_Entry rf_ieee_tx_power_table[] = -{ - { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 6) }, - { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 6) }, - { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 6) }, - { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 1, 0, 10) }, - { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 1, 12) }, - { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(18, 1, 1, 14) }, - { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 1, 1, 18) }, - { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(33, 1, 1, 24) }, - { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 0, 0, 33) }, - { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 0, 0, 39) }, - { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 0, 0, 45) }, - { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(36, 0, 1, 73) }, - { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(48, 0, 1, 73) }, - RF_TxPowerTable_TERMINATION_ENTRY -}; - -/* - * TX power table size, with one less entry excluding the - * termination entry. - */ -const size_t rf_ieee_tx_power_table_size = - (sizeof(rf_ieee_tx_power_table) / sizeof(rf_ieee_tx_power_table[0])) - 1; - /* * CMD_RADIO_SETUP must be configured with default TX power value * in the .txPower field. */ #define DEFAULT_TX_POWER 0x9330 /* 5 dBm */ - /*---------------------------------------------------------------------------*/ /* Overrides for CMD_RADIO_SETUP */ uint32_t rf_ieee_overrides[] CC_ALIGN(4) = diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h index e25127c9c..bc60d70c3 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-settings.h @@ -48,10 +48,6 @@ /* TI-RTOS RF Mode Object */ extern RF_Mode rf_ieee_mode; /*---------------------------------------------------------------------------*/ -/* TX Power Table */ -extern RF_TxPowerTable_Entry rf_ieee_tx_power_table[]; -extern const size_t rf_ieee_tx_power_table_size; -/*---------------------------------------------------------------------------*/ /* RF Core API commands */ extern rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup; extern rfc_CMD_FS_t rf_cmd_ieee_fs; diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-tx-power.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-tx-power.c new file mode 100644 index 000000000..2d37ef641 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/ieee-tx-power.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/** + * \addtogroup cc13xx-cc26xx-rf-tx-power + * @{ + * + * \file + * Source file for IEEE-mode TX power tables for CC13x0. + * \author + * Edvard Pettersen + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +/*---------------------------------------------------------------------------*/ +#include "rf/tx-power.h" +/*---------------------------------------------------------------------------*/ +/* + * TX Power table for CC1350 + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +tx_power_table_t rf_ieee_tx_power_table_cc1350[] = +{ + { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 6) }, + { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 6) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 6) }, + { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 1, 0, 10) }, + { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 1, 12) }, + { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(18, 1, 1, 14) }, + { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 1, 1, 18) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(33, 1, 1, 24) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 0, 0, 33) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 0, 0, 39) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 0, 0, 45) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(36, 0, 1, 73) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(48, 0, 1, 73) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +tx_power_table_t rf_ieee_tx_power_table_empty[] = +{ + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +/* Only define the symbols if Prop-mode is selected */ +#if (RF_MODE == RF_MODE_2_4_GHZ) +/*---------------------------------------------------------------------------*/ +/* TX power table, based on which board is used. */ +#if defined(DEVICE_CC1350) || defined(DEVICE_CC1350_4) +#define TX_POWER_TABLE rf_ieee_tx_power_table_cc1350 + +#else +#define TX_POWER_TABLE rf_ieee_tx_power_table_empty +#endif + +/* + * Define symbols for both the TX power table and its size. The TX power + * table size is with one less entry by excluding the termination entry. + */ +tx_power_table_t *const rf_tx_power_table = TX_POWER_TABLE; +const size_t rf_tx_power_table_size = (sizeof(TX_POWER_TABLE) / sizeof(TX_POWER_TABLE[0])) - 1; +/*---------------------------------------------------------------------------*/ +#endif /* RF_MODE */ +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c index e47ebde1a..64dbe591f 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c @@ -75,45 +75,6 @@ RF_Mode rf_prop_mode = }; /*---------------------------------------------------------------------------*/ #if defined(DEVICE_CC1310) -/* - * TX Power table for CC1310 - * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: - * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) - * See the Technical Reference Manual for further details about the "txPower" Command field. - * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. - */ -RF_TxPowerTable_Entry rf_prop_tx_power_table[] = -{ - { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY( 0, 3, 0, 4) }, - { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY( 1, 1, 0, 0) }, - { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY( 3, 3, 0, 8) }, - { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY( 2, 1, 0, 8) }, - { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 3, 0, 10) }, - { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY( 5, 3, 0, 12) }, - { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY( 6, 3, 0, 12) }, - { 6, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 14) }, - { 7, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 16) }, - { 8, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 18) }, - { 9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 3, 0, 22) }, - { 10, RF_TxPowerTable_DEFAULT_PA_ENTRY(19, 3, 0, 28) }, - { 11, RF_TxPowerTable_DEFAULT_PA_ENTRY(26, 3, 0, 40) }, - { 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 0, 0, 92) }, - /* The original PA value (12.5 dBm) have been rounded to an integer value. */ - { 13, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 0, 83) }, -#if RF_CONF_TXPOWER_BOOST_MODE - /* This setting requires RF_CONF_TXPOWER_BOOST_MODE = 1. */ - { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 83) }, -#endif - RF_TxPowerTable_TERMINATION_ENTRY -}; - -/* - * TX power table size, with one less entry excluding the - * termination entry. - */ -const size_t rf_prop_tx_power_table_size = - (sizeof(rf_prop_tx_power_table) / sizeof(rf_prop_tx_power_table[0])) - 1; - /* * CMD_PROP_RADIO_DIV_SETUP must be configured with default TX power value * in the .txPower field. This depends on whether RF_CONF_TXPOWER_BOOST_MODE @@ -128,43 +89,6 @@ const size_t rf_prop_tx_power_table_size = #endif /* defined(DEVICE_CC1310) */ /*---------------------------------------------------------------------------*/ #if defined(DEVICE_CC1350) -/* - * TX Power table for CC1350 - * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: - * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) - * See the Technical Reference Manual for further details about the "txPower" Command field. - * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. - */ -RF_TxPowerTable_Entry rf_prop_tx_power_table[] = -{ - { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY( 0, 3, 0, 2) }, - { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY( 3, 3, 0, 9) }, - { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 3, 0, 11) }, - { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY( 5, 3, 0, 12) }, - { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY( 6, 3, 0, 14) }, - { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 1, 0, 12) }, - { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 3, 0, 16) }, - { 6, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 18) }, - { 7, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 21) }, - { 8, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 3, 0, 25) }, - { 9, RF_TxPowerTable_DEFAULT_PA_ENTRY(18, 3, 0, 32) }, - { 10, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 3, 0, 44) }, - { 11, RF_TxPowerTable_DEFAULT_PA_ENTRY(37, 3, 0, 72) }, - { 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(43, 0, 0, 94) }, -#if RF_CONF_TXPOWER_BOOST_MODE - /* This setting requires RF_CONF_TXPOWER_BOOST_MODE = 1. */ - { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 85) }, -#endif - RF_TxPowerTable_TERMINATION_ENTRY -}; - -/* - * TX power table size, with one less entry excluding the - * termination entry. - */ -const size_t rf_prop_tx_power_table_size = - (sizeof(rf_prop_tx_power_table) / sizeof(rf_prop_tx_power_table[0])) - 1; - /* * CMD_PROP_RADIO_DIV_SETUP must be configured with default TX power value * in the .txPower field. This depends on whether RF_CONF_TXPOWER_BOOST_MODE @@ -179,45 +103,6 @@ const size_t rf_prop_tx_power_table_size = #endif /* defined(DEVICE_CC1350) */ /*---------------------------------------------------------------------------*/ #if defined(DEVICE_CC1350_4) -/* - * TX Power table for CC1350_433 - * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: - * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) - * See the Technical Reference Manual for further details about the "txPower" Command field. - * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. - */ -RF_TxPowerTable_Entry rf_prop_tx_power_table[] = -{ - { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY( 0, 3, 0, 2) }, - { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY( 1, 3, 0, 7) }, - { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY( 1, 3, 0, 9) }, - { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY( 2, 3, 0, 11) }, - { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY( 2, 3, 0, 12) }, - { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY( 3, 3, 0, 16) }, - { 6, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 3, 0, 18) }, - { 7, RF_TxPowerTable_DEFAULT_PA_ENTRY( 5, 3, 0, 21) }, - { 8, RF_TxPowerTable_DEFAULT_PA_ENTRY( 6, 3, 0, 23) }, - { 9, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 3, 0, 28) }, - { 10, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 35) }, - { 11, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 1, 0, 39) }, - { 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 60) }, - { 13, RF_TxPowerTable_DEFAULT_PA_ENTRY(15, 0, 0, 108) }, - /* The original PA value (13.7 dBm) have been rounded to an integer value. */ - { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 0, 92) }, -#if RF_CONF_TXPOWER_BOOST_MODE - /* This setting requires RF_CONF_TXPOWER_BOOST_MODE = 1. */ - { 15, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 72) }, -#endif - RF_TxPowerTable_TERMINATION_ENTRY -}; - -/* - * TX power table size, with one less entry excluding the - * termination entry. - */ -const size_t rf_prop_tx_power_table_size = - (sizeof(rf_prop_tx_power_table) / sizeof(rf_prop_tx_power_table[0])) - 1; - /* * CMD_PROP_RADIO_DIV_SETUP must be configured with default TX power value * in the .txPower field. This depends on whether RF_CONF_TXPOWER_BOOST_MODE diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-tx-power.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-tx-power.c new file mode 100644 index 000000000..f2293767f --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-tx-power.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/** + * \addtogroup cc13xx-cc26xx-rf-tx-power + * @{ + * + * \file + * Source file for Prop-mode TX power tables for CC13x0. + * \author + * Edvard Pettersen + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +/*---------------------------------------------------------------------------*/ +#include "rf/tx-power.h" +/*---------------------------------------------------------------------------*/ +/* + * TX Power table for CC1310 + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +tx_power_table_t rf_prop_tx_power_table_cc1310[] = +{ + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY( 0, 3, 0, 4) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY( 1, 1, 0, 0) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY( 3, 3, 0, 8) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY( 2, 1, 0, 8) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 3, 0, 10) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY( 5, 3, 0, 12) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY( 6, 3, 0, 12) }, + { 6, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 14) }, + { 7, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 16) }, + { 8, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 18) }, + { 9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 3, 0, 22) }, + { 10, RF_TxPowerTable_DEFAULT_PA_ENTRY(19, 3, 0, 28) }, + { 11, RF_TxPowerTable_DEFAULT_PA_ENTRY(26, 3, 0, 40) }, + { 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 0, 0, 92) }, + /* The original PA value (12.5 dBm) have been rounded to an integer value. */ + { 13, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 0, 83) }, +#if RF_CONF_TXPOWER_BOOST_MODE + /* This setting requires RF_CONF_TXPOWER_BOOST_MODE = 1. */ + { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 83) }, +#endif + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +/* + * TX Power table for CC1350 + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +tx_power_table_t rf_prop_tx_power_table_cc1350[] = +{ + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY( 0, 3, 0, 2) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY( 3, 3, 0, 9) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 3, 0, 11) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY( 5, 3, 0, 12) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY( 6, 3, 0, 14) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 1, 0, 12) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 3, 0, 16) }, + { 6, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 18) }, + { 7, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 21) }, + { 8, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 3, 0, 25) }, + { 9, RF_TxPowerTable_DEFAULT_PA_ENTRY(18, 3, 0, 32) }, + { 10, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 3, 0, 44) }, + { 11, RF_TxPowerTable_DEFAULT_PA_ENTRY(37, 3, 0, 72) }, + { 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(43, 0, 0, 94) }, +#if RF_CONF_TXPOWER_BOOST_MODE + /* This setting requires RF_CONF_TXPOWER_BOOST_MODE = 1. */ + { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 85) }, +#endif + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +/* + * TX Power table for CC1350_433 + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +tx_power_table_t rf_prop_tx_power_table_cc1350_4[] = +{ + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY( 0, 3, 0, 2) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY( 1, 3, 0, 7) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY( 1, 3, 0, 9) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY( 2, 3, 0, 11) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY( 2, 3, 0, 12) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY( 3, 3, 0, 16) }, + { 6, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 3, 0, 18) }, + { 7, RF_TxPowerTable_DEFAULT_PA_ENTRY( 5, 3, 0, 21) }, + { 8, RF_TxPowerTable_DEFAULT_PA_ENTRY( 6, 3, 0, 23) }, + { 9, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 3, 0, 28) }, + { 10, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 35) }, + { 11, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 1, 0, 39) }, + { 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 60) }, + { 13, RF_TxPowerTable_DEFAULT_PA_ENTRY(15, 0, 0, 108) }, + /* The original PA value (13.7 dBm) have been rounded to an integer value. */ + { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 0, 92) }, +#if RF_CONF_TXPOWER_BOOST_MODE + /* This setting requires RF_CONF_TXPOWER_BOOST_MODE = 1. */ + { 15, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 72) }, +#endif + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +tx_power_table_t rf_prop_tx_power_table_empty[] = +{ + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +/* Only define the symbols if Prop-mode is selected */ +#if (RF_MODE == RF_MODE_SUB_1_GHZ) +/*---------------------------------------------------------------------------*/ +/* TX power table, based on which board is used. */ +#if defined(DEVICE_CC1310) +#define TX_POWER_TABLE rf_prop_tx_power_table_cc1310 + +#elif defined(DEVICE_CC1350) +#define TX_POWER_TABLE rf_prop_tx_power_table_cc1350 + +#elif defined(DEVICE_CC1350_4) +#define TX_POWER_TABLE rf_prop_tx_power_table_cc1350_4 + +#else +#define TX_POWER_TABLE rf_prop_tx_power_table_empty +#endif + +/* + * Define symbols for both the TX power table and its size. The TX power + * table size is with one less entry by excluding the termination entry. + */ +tx_power_table_t *const rf_tx_power_table = TX_POWER_TABLE; +const size_t rf_tx_power_table_size = (sizeof(TX_POWER_TABLE) / sizeof(TX_POWER_TABLE[0])) - 1; +/*---------------------------------------------------------------------------*/ +#endif /* RF_MODE */ +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.c index de3b03f8c..e6771de64 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.c @@ -64,33 +64,6 @@ RF_Mode rf_ble_mode = .rfePatchFxn = &rf_patch_rfe_bt5, }; /*---------------------------------------------------------------------------*/ -/* - * TX Power table - * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: - * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) - * See the Technical Reference Manual for further details about the "txPower" Command field. - * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. - */ -RF_TxPowerTable_Entry rf_ble_tx_power_table[RF_BLE_TX_POWER_TABLE_SIZE+1] = -{ - { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 3) }, - { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 3) }, - { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 2, 0, 6) }, - { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 2, 0, 8) }, - { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 11) }, - { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 2, 0, 5) }, - { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 16) }, - { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 17) }, - { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 1, 0, 20) }, - { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(25, 1, 0, 26) }, - { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 1, 0, 28) }, - { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 0, 0, 34) }, - { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 0, 0, 42) }, - { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 0, 0, 54) }, - { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, - RF_TxPowerTable_TERMINATION_ENTRY -}; -/*---------------------------------------------------------------------------*/ /* Overrides for CMD_BLE5_RADIO_SETUP */ uint32_t rf_ble_overrides_common[] CC_ALIGN(4) = { diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.h index 695d27e24..7793b89e6 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-settings.h @@ -38,25 +38,19 @@ #include /*---------------------------------------------------------------------------*/ -/* TX Power table size definition */ -#define RF_BLE_TX_POWER_TABLE_SIZE 15 - -/* TX Power Table Object */ -extern RF_TxPowerTable_Entry rf_ble_tx_power_table[RF_BLE_TX_POWER_TABLE_SIZE+1]; -/*---------------------------------------------------------------------------*/ /* TI-RTOS RF Mode Object */ -extern RF_Mode rf_ble_mode; +extern RF_Mode rf_ble_mode; /*---------------------------------------------------------------------------*/ /* RF Core API commands */ -extern rfc_CMD_BLE5_RADIO_SETUP_t rf_cmd_ble5_radio_setup; -extern rfc_ble5AdvAuxPar_t rf_ble5_adv_aux_par; -extern rfc_CMD_BLE5_ADV_AUX_t rf_cmd_ble5_adv_aux; +extern rfc_CMD_BLE5_RADIO_SETUP_t rf_cmd_ble5_radio_setup; +extern rfc_ble5AdvAuxPar_t rf_ble5_adv_aux_par; +extern rfc_CMD_BLE5_ADV_AUX_t rf_cmd_ble5_adv_aux; /*---------------------------------------------------------------------------*/ /* RF Core API Overrides */ -extern uint32_t rf_ble_overrides_common[]; -extern uint32_t rf_ble_overrides_1mbps[]; -extern uint32_t rf_ble_overrides_2mbps[]; -extern uint32_t rf_ble_overrides_coded[]; +extern uint32_t rf_ble_overrides_common[]; +extern uint32_t rf_ble_overrides_1mbps[]; +extern uint32_t rf_ble_overrides_2mbps[]; +extern uint32_t rf_ble_overrides_coded[]; /*---------------------------------------------------------------------------*/ #endif /* BLE_SETTINGS_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-tx-power.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-tx-power.c new file mode 100644 index 000000000..7a87ca567 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ble-tx-power.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/** + * \addtogroup cc13xx-cc26xx-rf-tx-power + * @{ + * + * \file + * Source file for ble-mode TX power tables for CC13x2. + * \author + * Edvard Pettersen + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +/*---------------------------------------------------------------------------*/ +#include "rf/tx-power.h" +/*---------------------------------------------------------------------------*/ +/* + * TX Power table for CC1352R + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +tx_power_table_t rf_ble_tx_power_table_cc1352r[] = +{ + { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 3) }, + { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 3) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 2, 0, 6) }, + { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 2, 0, 8) }, + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 11) }, + { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 2, 0, 5) }, + { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 16) }, + { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 17) }, + { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 1, 0, 20) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(25, 1, 0, 26) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 1, 0, 28) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 0, 0, 34) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 0, 0, 42) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 0, 0, 54) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +/* + * TX Power table for CC1352P with default PA + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +tx_power_table_t rf_ble_tx_power_table_cc1352p_dpa[] = +{ + { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 3) }, + { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 3) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 2, 0, 6) }, + { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 2, 0, 8) }, + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 11) }, + { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 2, 0, 5) }, + { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 16) }, + { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 17) }, + { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 1, 0, 20) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(25, 1, 0, 26) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 1, 0, 28) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 0, 0, 34) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 0, 0, 42) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 0, 0, 54) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +/* + * TX Power table for CC1352P with high PA + * The RF_TxPowerTable_HIGH_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_HIGH_PA_ENTRY(bias, ibboost, boost, coefficient, ldoTrim) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +tx_power_table_t rf_ble_tx_power_table_cc1352p_hpa[] = +{ + { 0, RF_TxPowerTable_HIGH_PA_ENTRY(29, 0, 1, 17, 1) }, + { 3, RF_TxPowerTable_HIGH_PA_ENTRY(39, 0, 1, 20, 1) }, + { 6, RF_TxPowerTable_HIGH_PA_ENTRY(46, 0, 1, 26, 7) }, + { 9, RF_TxPowerTable_HIGH_PA_ENTRY(40, 0, 1, 39, 41) }, + { 10, RF_TxPowerTable_HIGH_PA_ENTRY(23, 2, 1, 65, 5) }, + { 11, RF_TxPowerTable_HIGH_PA_ENTRY(24, 2, 1, 29, 7) }, + { 12, RF_TxPowerTable_HIGH_PA_ENTRY(19, 2, 1, 16, 25) }, + { 13, RF_TxPowerTable_HIGH_PA_ENTRY(27, 2, 1, 19, 13) }, + { 14, RF_TxPowerTable_HIGH_PA_ENTRY(24, 2, 1, 19, 27) }, + { 15, RF_TxPowerTable_HIGH_PA_ENTRY(23, 2, 1, 20, 39) }, + { 16, RF_TxPowerTable_HIGH_PA_ENTRY(34, 2, 1, 26, 23) }, + { 17, RF_TxPowerTable_HIGH_PA_ENTRY(38, 2, 1, 33, 25) }, + { 18, RF_TxPowerTable_HIGH_PA_ENTRY(30, 2, 1, 37, 53) }, + { 19, RF_TxPowerTable_HIGH_PA_ENTRY(36, 2, 1, 57, 59) }, + { 20, RF_TxPowerTable_HIGH_PA_ENTRY(56, 2, 1, 45, 63) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +tx_power_table_t rf_ble_tx_power_table_empty[] = +{ + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +/* TX power table, based on which board is used. */ +#if defined(DEVICE_CC1352R) +#define TX_POWER_TABLE rf_ble_tx_power_table_cc1352r + +#elif defined(DEVICE_CC1352P) +#if RF_TXPOWER_HIGH_PA +#define TX_POWER_TABLE rf_ble_tx_power_table_cc1352p_hpa +#else +#define TX_POWER_TABLE rf_ble_tx_power_table_cc1352p_dpa +#endif + +#else +#define TX_POWER_TABLE rf_ble_tx_power_table_empty +#endif + +/* + * Define symbols for both the TX power table and its size. The TX power + * table size is with one less entry by excluding the termination entry. + */ +tx_power_table_t *const ble_tx_power_table = TX_POWER_TABLE; +const size_t ble_tx_power_table_size = (sizeof(TX_POWER_TABLE) / sizeof(TX_POWER_TABLE[0])) - 1; +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c index dd0df6343..1f5e3d8d7 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.c @@ -68,40 +68,6 @@ RF_Mode rf_ieee_mode = }; /*---------------------------------------------------------------------------*/ #if defined(DEVICE_CC1352R) -/* - * TX Power table - * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: - * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) - * See the Technical Reference Manual for further details about the "txPower" Command field. - * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. - */ -RF_TxPowerTable_Entry rf_ieee_tx_power_table[] = -{ - { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 3) }, - { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 3) }, - { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 2, 0, 6) }, - { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 2, 0, 8) }, - { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 11) }, - { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 2, 0, 5) }, - { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 16) }, - { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 17) }, - { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 1, 0, 20) }, - { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(25, 1, 0, 26) }, - { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 1, 0, 28) }, - { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 0, 0, 34) }, - { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 0, 0, 42) }, - { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 0, 0, 54) }, - { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, - RF_TxPowerTable_TERMINATION_ENTRY -}; - -/* - * TX power table size, with one less entry excluding the - * termination entry. - */ -const size_t rf_ieee_tx_power_table_size = - (sizeof(rf_ieee_tx_power_table) / sizeof(rf_ieee_tx_power_table[0])) - 1; - /* * CMD_RADIO_SETUP must be configured with default TX power value * in the .txPower field. @@ -135,40 +101,6 @@ uint32_t rf_ieee_overrides[] CC_ALIGN(4) = #if defined(DEVICE_CC1352P) #if RF_CONF_TXPOWER_HIGH_PA -/* - * TX Power table - * The RF_TxPowerTable_HIGH_PA_ENTRY macro is defined in RF.h and requires the following arguments: - * RF_TxPowerTable_HIGH_PA_ENTRY(bias, ibboost, boost, coefficient, ldoTrim) - * See the Technical Reference Manual for further details about the "txPower" Command field. - * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. - */ -RF_TxPowerTable_Entry rf_ieee_tx_power_table[] = -{ - { 0, RF_TxPowerTable_HIGH_PA_ENTRY(29, 0, 1, 17, 1) }, - { 3, RF_TxPowerTable_HIGH_PA_ENTRY(39, 0, 1, 20, 1) }, - { 6, RF_TxPowerTable_HIGH_PA_ENTRY(46, 0, 1, 26, 7) }, - { 9, RF_TxPowerTable_HIGH_PA_ENTRY(40, 0, 1, 39, 41) }, - { 10, RF_TxPowerTable_HIGH_PA_ENTRY(23, 2, 1, 65, 5) }, - { 11, RF_TxPowerTable_HIGH_PA_ENTRY(24, 2, 1, 29, 7) }, - { 12, RF_TxPowerTable_HIGH_PA_ENTRY(19, 2, 1, 16, 25) }, - { 13, RF_TxPowerTable_HIGH_PA_ENTRY(27, 2, 1, 19, 13) }, - { 14, RF_TxPowerTable_HIGH_PA_ENTRY(24, 2, 1, 19, 27) }, - { 15, RF_TxPowerTable_HIGH_PA_ENTRY(23, 2, 1, 20, 39) }, - { 16, RF_TxPowerTable_HIGH_PA_ENTRY(34, 2, 1, 26, 23) }, - { 17, RF_TxPowerTable_HIGH_PA_ENTRY(38, 2, 1, 33, 25) }, - { 18, RF_TxPowerTable_HIGH_PA_ENTRY(30, 2, 1, 37, 53) }, - { 19, RF_TxPowerTable_HIGH_PA_ENTRY(36, 2, 1, 57, 59) }, - { 20, RF_TxPowerTable_HIGH_PA_ENTRY(56, 2, 1, 45, 63) }, - RF_TxPowerTable_TERMINATION_ENTRY -}; - -/* - * TX power table size, with one less entry excluding the - * termination entry. - */ -const size_t rf_ieee_tx_power_table_size = - (sizeof(rf_ieee_tx_power_table) / sizeof(rf_ieee_tx_power_table[0])) - 1; - /* * CMD_PROP_RADIO_DIV_SETUP must be configured with default TX power value * in the .txPower field. For High PA, this must be 0xFFFF. @@ -201,40 +133,6 @@ uint32_t rf_ieee_overrides[] CC_ALIGN(4) = }; /*---------------------------------------------------------------------------*/ #else -/* - * TX Power table - * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: - * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) - * See the Technical Reference Manual for further details about the "txPower" Command field. - * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. - */ -RF_TxPowerTable_Entry rf_ieee_tx_power_table[] = -{ - { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 3) }, - { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 3) }, - { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 2, 0, 6) }, - { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 2, 0, 8) }, - { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 11) }, - { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 2, 0, 5) }, - { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 16) }, - { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 17) }, - { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 1, 0, 20) }, - { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(25, 1, 0, 26) }, - { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 1, 0, 28) }, - { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 0, 0, 34) }, - { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 0, 0, 42) }, - { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 0, 0, 54) }, - { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, - RF_TxPowerTable_TERMINATION_ENTRY -}; - -/* - * TX power table size, with one less entry excluding the - * termination entry. - */ -const size_t rf_ieee_tx_power_table_size = - (sizeof(rf_ieee_tx_power_table) / sizeof(rf_ieee_tx_power_table[0])) - 1; - /* * CMD_RADIO_SETUP must be configured with default TX power value * in the .txPower field. diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h index db2717f21..7019598c8 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-settings.h @@ -44,10 +44,6 @@ /* TI-RTOS RF Mode Object */ extern RF_Mode rf_ieee_mode; /*---------------------------------------------------------------------------*/ -/* TX Power Table */ -extern RF_TxPowerTable_Entry rf_ieee_tx_power_table[]; -extern const size_t rf_ieee_tx_power_table_size; -/*---------------------------------------------------------------------------*/ /* RF Core API commands */ extern rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup; extern rfc_CMD_FS_t rf_cmd_ieee_fs; diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-tx-power.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-tx-power.c new file mode 100644 index 000000000..efd143e9d --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/ieee-tx-power.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/** + * \addtogroup cc13xx-cc26xx-rf-tx-power + * @{ + * + * \file + * Source file for IEEE-mode TX power tables for CC13x2. + * \author + * Edvard Pettersen + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +/*---------------------------------------------------------------------------*/ +#include "rf/tx-power.h" +/*---------------------------------------------------------------------------*/ +/* + * TX Power table for CC1312R + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +tx_power_table_t rf_ieee_tx_power_table_cc1312r[] = +{ + { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 3) }, + { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 3) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 2, 0, 6) }, + { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 2, 0, 8) }, + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 11) }, + { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 2, 0, 5) }, + { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 16) }, + { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 17) }, + { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 1, 0, 20) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(25, 1, 0, 26) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 1, 0, 28) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 0, 0, 34) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 0, 0, 42) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 0, 0, 54) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +/* + * TX Power table for CC1352R + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +tx_power_table_t rf_ieee_tx_power_table_cc1352r[] = +{ + { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 3) }, + { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 3) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 2, 0, 6) }, + { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 2, 0, 8) }, + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 11) }, + { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 2, 0, 5) }, + { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 16) }, + { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 17) }, + { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 1, 0, 20) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(25, 1, 0, 26) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 1, 0, 28) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 0, 0, 34) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 0, 0, 42) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 0, 0, 54) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +/* + * TX Power table for CC1352P with default PA + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +tx_power_table_t rf_ieee_tx_power_table_cc1352p_dpa[] = +{ + { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 3) }, + { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 3) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 2, 0, 6) }, + { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 2, 0, 8) }, + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 11) }, + { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 2, 0, 5) }, + { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 16) }, + { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 17) }, + { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 1, 0, 20) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(25, 1, 0, 26) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 1, 0, 28) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 0, 0, 34) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 0, 0, 42) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 0, 0, 54) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +/* + * TX Power table for CC1352P with high PA + * The RF_TxPowerTable_HIGH_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_HIGH_PA_ENTRY(bias, ibboost, boost, coefficient, ldoTrim) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +tx_power_table_t rf_ieee_tx_power_table_cc1352p_hpa[] = +{ + { 0, RF_TxPowerTable_HIGH_PA_ENTRY(29, 0, 1, 17, 1) }, + { 3, RF_TxPowerTable_HIGH_PA_ENTRY(39, 0, 1, 20, 1) }, + { 6, RF_TxPowerTable_HIGH_PA_ENTRY(46, 0, 1, 26, 7) }, + { 9, RF_TxPowerTable_HIGH_PA_ENTRY(40, 0, 1, 39, 41) }, + { 10, RF_TxPowerTable_HIGH_PA_ENTRY(23, 2, 1, 65, 5) }, + { 11, RF_TxPowerTable_HIGH_PA_ENTRY(24, 2, 1, 29, 7) }, + { 12, RF_TxPowerTable_HIGH_PA_ENTRY(19, 2, 1, 16, 25) }, + { 13, RF_TxPowerTable_HIGH_PA_ENTRY(27, 2, 1, 19, 13) }, + { 14, RF_TxPowerTable_HIGH_PA_ENTRY(24, 2, 1, 19, 27) }, + { 15, RF_TxPowerTable_HIGH_PA_ENTRY(23, 2, 1, 20, 39) }, + { 16, RF_TxPowerTable_HIGH_PA_ENTRY(34, 2, 1, 26, 23) }, + { 17, RF_TxPowerTable_HIGH_PA_ENTRY(38, 2, 1, 33, 25) }, + { 18, RF_TxPowerTable_HIGH_PA_ENTRY(30, 2, 1, 37, 53) }, + { 19, RF_TxPowerTable_HIGH_PA_ENTRY(36, 2, 1, 57, 59) }, + { 20, RF_TxPowerTable_HIGH_PA_ENTRY(56, 2, 1, 45, 63) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +tx_power_table_t rf_ieee_ztx_power_table_empty[] = +{ + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +/* Only define the symbols if Prop-mode is selected */ +#if (RF_MODE == RF_MODE_2_4_GHZ) +/*---------------------------------------------------------------------------*/ +/* TX power table, based on which board is used. */ +#if defined(DEVICE_CC1312R) +#define TX_POWER_TABLE rf_ieee_tx_power_table_cc1312r + +#elif defined(DEVICE_CC1352R) +#define TX_POWER_TABLE rf_ieee_tx_power_table_cc1352r + +#elif defined(DEVICE_CC1352P) +#if RF_TXPOWER_HIGH_PA +#define TX_POWER_TABLE rf_ieee_tx_power_table_cc1352p_hpa +#else +#define TX_POWER_TABLE rf_ieee_tx_power_table_cc1352p_dpa +#endif + +#else +#define TX_POWER_TABLE rf_ieee_tx_power_table_empty +#endif + +/* + * Define symbols for both the TX power table and its size. The TX power + * table size is with one less entry by excluding the termination entry. + */ +tx_power_table_t *const rf_tx_power_table = TX_POWER_TABLE; +const size_t rf_tx_power_table_size = (sizeof(TX_POWER_TABLE) / sizeof(TX_POWER_TABLE[0])) - 1; +/*---------------------------------------------------------------------------*/ +#endif /* RF_MODE */ +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c index 5b8a1d04d..c63e6bef7 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.c @@ -81,48 +81,6 @@ RF_Mode rf_prop_mode = }; /*---------------------------------------------------------------------------*/ #if defined(DEVICE_CC1312R) || defined(DEVICE_CC1352R) -/* - * TX Power table - * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: - * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) - * See the Technical Reference Manual for further details about the "txPower" Command field. - * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. - */ -RF_TxPowerTable_Entry rf_prop_tx_power_table[] = -{ - { -20, RF_TxPowerTable_DEFAULT_PA_ENTRY(0, 3, 0, 2) }, - { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(1, 3, 0, 2) }, - { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(2, 3, 0, 4) }, - { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(4, 3, 0, 5) }, - { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(8, 3, 0, 7) }, - { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(9, 3, 0, 7) }, - { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 3, 0, 9) }, - { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 9) }, - { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 3, 0, 11) }, - { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 3, 0, 12) }, - { 6, RF_TxPowerTable_DEFAULT_PA_ENTRY(16, 3, 0, 14) }, - { 7, RF_TxPowerTable_DEFAULT_PA_ENTRY(8, 2, 0, 16) }, - { 8, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 3, 0, 32) }, - { 9, RF_TxPowerTable_DEFAULT_PA_ENTRY(26, 3, 0, 28) }, - { 10, RF_TxPowerTable_DEFAULT_PA_ENTRY(33, 3, 0, 55) }, - { 11, RF_TxPowerTable_DEFAULT_PA_ENTRY(23, 2, 0, 42) }, - { 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 0, 0, 58) }, - /* The original PA value (12.5 dBm) have been rounded to an integer value. */ - { 13, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 0, 0, 102) }, -#if RF_CONF_TXPOWER_BOOST_MODE - /* This setting requires RF_CONF_TXPOWER_BOOST_MODE = 1. */ - { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 79) }, -#endif - RF_TxPowerTable_TERMINATION_ENTRY -}; - -/* - * TX power table size, with one less entry excluding the - * termination entry. - */ -const size_t rf_prop_tx_power_table_size = - (sizeof(rf_prop_tx_power_table) / sizeof(rf_prop_tx_power_table[0])) - 1; - /* * CMD_PROP_RADIO_DIV_SETUP must be configured with default TX power value * in the .txPower field. This depends on whether RF_CONF_TXPOWER_BOOST_MODE @@ -188,32 +146,6 @@ uint32_t rf_prop_overrides[] CC_ALIGN(4) = #if defined(DEVICE_CC1352P) #if RF_CONF_TXPOWER_HIGH_PA -/* - * TX Power table - * The RF_TxPowerTable_HIGH_PA_ENTRY macro is defined in RF.h and requires the following arguments: - * RF_TxPowerTable_HIGH_PA_ENTRY(bias, ibboost, boost, coefficient, ldoTrim) - * See the Technical Reference Manual for further details about the "txPower" Command field. - * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. - */ -RF_TxPowerTable_Entry rf_prop_tx_power_table[] = -{ - { 14, RF_TxPowerTable_HIGH_PA_ENTRY( 7, 0, 0, 23, 4) }, - { 15, RF_TxPowerTable_HIGH_PA_ENTRY(10, 0, 0, 26, 4) }, - { 16, RF_TxPowerTable_HIGH_PA_ENTRY(14, 0, 0, 33, 4) }, - { 17, RF_TxPowerTable_HIGH_PA_ENTRY(18, 0, 0, 40, 6) }, - { 18, RF_TxPowerTable_HIGH_PA_ENTRY(24, 0, 0, 51, 8) }, - { 19, RF_TxPowerTable_HIGH_PA_ENTRY(32, 0, 0, 73, 12) }, - { 20, RF_TxPowerTable_HIGH_PA_ENTRY(27, 0, 0, 85, 32) }, - RF_TxPowerTable_TERMINATION_ENTRY -}; - -/* - * TX power table size, with one less entry excluding the - * termination entry. - */ -const size_t rf_prop_tx_power_table_size = - (sizeof(rf_prop_tx_power_table) / sizeof(rf_prop_tx_power_table[0])) - 1; - /* * CMD_PROP_RADIO_DIV_SETUP must be configured with default TX power value * in the .txPower field. For High PA, this must be 0xFFFF. @@ -265,49 +197,6 @@ uint32_t rf_prop_overrides[] CC_ALIGN(4) = #else /*---------------------------------------------------------------------------*/ -/* - * TX Power table - * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: - * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) - * See the Technical Reference Manual for further details about the "txPower" Command field. - * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. - */ -RF_TxPowerTable_Entry rf_prop_tx_power_table[] = -{ - { -20, RF_TxPowerTable_DEFAULT_PA_ENTRY( 0, 3, 0, 2) }, - { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY( 1, 3, 0, 3) }, - { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY( 2, 3, 0, 3) }, - { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 3, 0, 6) }, - { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 8) }, - { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 3, 0, 9) }, - { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 9) }, - { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 11) }, - { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 3, 0, 12) }, - { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 3, 0, 14) }, - { 6, RF_TxPowerTable_DEFAULT_PA_ENTRY( 6, 2, 0, 14) }, - { 7, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 1, 0, 16) }, - { 8, RF_TxPowerTable_DEFAULT_PA_ENTRY( 6, 1, 0, 19) }, - { 9, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 1, 0, 25) }, - { 10, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 40) }, - { 11, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 0, 0, 71) }, - { 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 0, 64) }, -#if RF_CONF_TXPOWER_BOOST_MODE - /* - * This setting requires RF_CONF_TXPOWER_BOOST_MODE = 1. - * The original PA value (13.5 dBm) have been rounded to an integer value. - */ - { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 0) }, -#endif - RF_TxPowerTable_TERMINATION_ENTRY -}; - -/* - * TX power table size, with one less entry excluding the - * termination entry. - */ -const size_t rf_prop_tx_power_table_size = - (sizeof(rf_prop_tx_power_table) / sizeof(rf_prop_tx_power_table[0])) - 1; - /* * CMD_PROP_RADIO_DIV_SETUP must be configured with default TX power value * in the .txPower field. This depends on whether RF_CONF_TXPOWER_BOOST_MODE diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h index 9f4103530..ab13a754a 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-settings.h @@ -44,10 +44,6 @@ /* TI-RTOS RF Mode Object */ extern RF_Mode rf_prop_mode; /*---------------------------------------------------------------------------*/ -/* Tx Power Tables */ -extern RF_TxPowerTable_Entry rf_prop_tx_power_table[]; -extern const size_t rf_prop_tx_power_table_size; -/*---------------------------------------------------------------------------*/ /* RF Core API commands */ extern rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup; extern rfc_CMD_FS_t rf_cmd_prop_fs; diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-tx-power.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-tx-power.c new file mode 100644 index 000000000..8052ac4fb --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x2/prop-tx-power.c @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/** + * \addtogroup cc13xx-cc26xx-rf-tx-power + * @{ + * + * \file + * Source file for TX power tables for CC13x2. + * \author + * Edvard Pettersen + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +/*---------------------------------------------------------------------------*/ +#include "rf/tx-power.h" +/*---------------------------------------------------------------------------*/ +/* + * TX Power table for CC1312R + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +tx_power_table_t rf_prop_tx_power_table_cc1312r[] = +{ + { -20, RF_TxPowerTable_DEFAULT_PA_ENTRY(0, 3, 0, 2) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(1, 3, 0, 2) }, + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(2, 3, 0, 4) }, + { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(4, 3, 0, 5) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(8, 3, 0, 7) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(9, 3, 0, 7) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 3, 0, 9) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 9) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 3, 0, 11) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 3, 0, 12) }, + { 6, RF_TxPowerTable_DEFAULT_PA_ENTRY(16, 3, 0, 14) }, + { 7, RF_TxPowerTable_DEFAULT_PA_ENTRY(8, 2, 0, 16) }, + { 8, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 3, 0, 32) }, + { 9, RF_TxPowerTable_DEFAULT_PA_ENTRY(26, 3, 0, 28) }, + { 10, RF_TxPowerTable_DEFAULT_PA_ENTRY(33, 3, 0, 55) }, + { 11, RF_TxPowerTable_DEFAULT_PA_ENTRY(23, 2, 0, 42) }, + { 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 0, 0, 58) }, + /* The original PA value (12.5 dBm) have been rounded to an integer value. */ + { 13, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 0, 0, 102) }, +#if RF_TXPOWER_BOOST_MODE + /* This setting requires RF_TXPOWER_BOOST_MODE = 1. */ + { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 79) }, +#endif + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +/* + * TX Power table for CC1352R + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +tx_power_table_t rf_prop_tx_power_table_cc1352r[] = +{ + { -20, RF_TxPowerTable_DEFAULT_PA_ENTRY(0, 3, 0, 2) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(1, 3, 0, 2) }, + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(2, 3, 0, 4) }, + { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(4, 3, 0, 5) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(8, 3, 0, 7) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(9, 3, 0, 7) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 3, 0, 9) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 9) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 3, 0, 11) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 3, 0, 12) }, + { 6, RF_TxPowerTable_DEFAULT_PA_ENTRY(16, 3, 0, 14) }, + { 7, RF_TxPowerTable_DEFAULT_PA_ENTRY(8, 2, 0, 16) }, + { 8, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 3, 0, 32) }, + { 9, RF_TxPowerTable_DEFAULT_PA_ENTRY(26, 3, 0, 28) }, + { 10, RF_TxPowerTable_DEFAULT_PA_ENTRY(33, 3, 0, 55) }, + { 11, RF_TxPowerTable_DEFAULT_PA_ENTRY(23, 2, 0, 42) }, + { 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 0, 0, 58) }, + /* The original PA value (12.5 dBm) have been rounded to an integer value. */ + { 13, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 0, 0, 102) }, +#if RF_TXPOWER_BOOST_MODE + /* This setting requires RF_TXPOWER_BOOST_MODE = 1. */ + { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 79) }, +#endif + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +/* + * TX Power table for CC1352P with default PA + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +tx_power_table_t rf_prop_tx_power_table_cc1352p_dpa[] = +{ + { -20, RF_TxPowerTable_DEFAULT_PA_ENTRY( 0, 3, 0, 2) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY( 1, 3, 0, 3) }, + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY( 2, 3, 0, 3) }, + { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 3, 0, 6) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 8) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 3, 0, 9) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 9) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 11) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 3, 0, 12) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 3, 0, 14) }, + { 6, RF_TxPowerTable_DEFAULT_PA_ENTRY( 6, 2, 0, 14) }, + { 7, RF_TxPowerTable_DEFAULT_PA_ENTRY( 4, 1, 0, 16) }, + { 8, RF_TxPowerTable_DEFAULT_PA_ENTRY( 6, 1, 0, 19) }, + { 9, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 1, 0, 25) }, + { 10, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 40) }, + { 11, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 0, 0, 71) }, + { 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 0, 64) }, +#if RF_TXPOWER_BOOST_MODE + /* + * This setting requires RF_TXPOWER_BOOST_MODE = 1. + * The original PA value (13.5 dBm) have been rounded to an integer value. + */ + { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 0) }, +#endif + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +/* + * TX Power table for CC1352P with high PA + * The RF_TxPowerTable_HIGH_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_HIGH_PA_ENTRY(bias, ibboost, boost, coefficient, ldoTrim) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +tx_power_table_t rf_prop_tx_power_table_cc1352p_hpa[] = +{ + { 14, RF_TxPowerTable_HIGH_PA_ENTRY( 7, 0, 0, 23, 4) }, + { 15, RF_TxPowerTable_HIGH_PA_ENTRY(10, 0, 0, 26, 4) }, + { 16, RF_TxPowerTable_HIGH_PA_ENTRY(14, 0, 0, 33, 4) }, + { 17, RF_TxPowerTable_HIGH_PA_ENTRY(18, 0, 0, 40, 6) }, + { 18, RF_TxPowerTable_HIGH_PA_ENTRY(24, 0, 0, 51, 8) }, + { 19, RF_TxPowerTable_HIGH_PA_ENTRY(32, 0, 0, 73, 12) }, + { 20, RF_TxPowerTable_HIGH_PA_ENTRY(27, 0, 0, 85, 32) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +tx_power_table_t rf_prop_tx_power_table_empty[] = +{ + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +/* Only define the symbols if Prop-mode is selected */ +#if (RF_MODE == RF_MODE_SUB_1_GHZ) +/*---------------------------------------------------------------------------*/ +/* TX power table, based on which board is used. */ +#if defined(DEVICE_CC1312R) +#define TX_POWER_TABLE rf_prop_tx_power_table_cc1312r + +#elif defined(DEVICE_CC1352R) +#define TX_POWER_TABLE rf_prop_tx_power_table_cc1352r + +#elif defined(DEVICE_CC1352P) +#if RF_TXPOWER_HIGH_PA +#define TX_POWER_TABLE rf_prop_tx_power_table_cc1352p_hpa +#else +#define TX_POWER_TABLE rf_prop_tx_power_table_cc1352p_dpa +#endif + +#else +#define TX_POWER_TABLE rf_prop_tx_power_table_empty +#endif + +/* + * Define symbols for both the TX power table and its size. The TX power + * table size is with one less entry by excluding the termination entry. + */ +tx_power_table_t *const rf_tx_power_table = TX_POWER_TABLE; +const size_t rf_tx_power_table_size = (sizeof(TX_POWER_TABLE) / sizeof(TX_POWER_TABLE[0])) - 1; +/*---------------------------------------------------------------------------*/ +#endif /* RF_MODE */ +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.c index 048c9399d..7edc3e487 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.c @@ -61,31 +61,6 @@ RF_Mode rf_ble_mode = .rfePatchFxn = &rf_patch_rfe_ble, }; /*---------------------------------------------------------------------------*/ -/* - * TX Power table - * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: - * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) - * See the Technical Reference Manual for further details about the "txPower" Command field. - * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. - */ -RF_TxPowerTable_Entry rf_ble_tx_power_table[RF_BLE_TX_POWER_TABLE_SIZE+1] = -{ - { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 6) }, - { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 6) }, - { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 6) }, - { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 1, 0, 10) }, - { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 1, 12) }, - { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(18, 1, 1, 14) }, - { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 1, 1, 18) }, - { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(33, 1, 1, 24) }, - { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 0, 0, 33) }, - { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 0, 0, 39) }, - { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 0, 0, 45) }, - { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(36, 0, 1, 73) }, - { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(48, 0, 1, 73) }, - RF_TxPowerTable_TERMINATION_ENTRY -}; -/*---------------------------------------------------------------------------*/ /* Overrides for CMD_RADIO_SETUP */ uint32_t rf_ble_overrides[] CC_ALIGN(4) = { diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.h index 63afd846b..5776fc407 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-settings.h @@ -38,22 +38,16 @@ #include /*---------------------------------------------------------------------------*/ -/* TX Power table size definition */ -#define RF_BLE_TX_POWER_TABLE_SIZE 13 - -/* TX Power Table Object */ -extern RF_TxPowerTable_Entry rf_ble_tx_power_table[RF_BLE_TX_POWER_TABLE_SIZE+1]; -/*---------------------------------------------------------------------------*/ /* TI-RTOS RF Mode Object */ -extern RF_Mode rf_ble_mode; +extern RF_Mode rf_ble_mode; /*---------------------------------------------------------------------------*/ /* RF Core API commands */ -extern rfc_CMD_RADIO_SETUP_t rf_ble_cmd_radio_setup; -extern rfc_CMD_FS_t rf_ble_cmd_fs; -extern rfc_CMD_BLE_ADV_NC_t rf_ble_cmd_ble_adv_nc; +extern rfc_CMD_RADIO_SETUP_t rf_ble_cmd_radio_setup; +extern rfc_CMD_FS_t rf_ble_cmd_fs; +extern rfc_CMD_BLE_ADV_NC_t rf_ble_cmd_ble_adv_nc; /*---------------------------------------------------------------------------*/ /* RF Core API Overrides */ -extern uint32_t rf_ble_overrides[]; +extern uint32_t rf_ble_overrides[]; /*---------------------------------------------------------------------------*/ #endif /* BLE_SETTINGS_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-tx-power.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-tx-power.c new file mode 100644 index 000000000..7510df27a --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ble-tx-power.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/** + * \addtogroup cc13xx-cc26xx-rf-tx-power + * @{ + * + * \file + * Source file for BLE Beacon TX power tables for CC26x0. + * \author + * Edvard Pettersen + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +/*---------------------------------------------------------------------------*/ +#include "rf/tx-power.h" +/*---------------------------------------------------------------------------*/ +/* + * TX Power table for CC2650 + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +tx_power_table_t rf_ble_tx_power_table_cc2650[] = +{ + { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 6) }, + { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 6) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 6) }, + { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 1, 0, 10) }, + { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 1, 12) }, + { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(18, 1, 1, 14) }, + { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 1, 1, 18) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(33, 1, 1, 24) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 0, 0, 33) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 0, 0, 39) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 0, 0, 45) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(36, 0, 1, 73) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(48, 0, 1, 73) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +tx_power_table_t rf_ble_tx_power_table_empty[] = +{ + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +/* TX power table, based on which board is used. */ +#if defined(DEVICE_CC2650) +#define TX_POWER_TABLE rf_ble_tx_power_table_cc2650 + +#else +#define TX_POWER_TABLE rf_ble_tx_power_table_empty +#endif + +/* + * Define symbols for both the TX power table and its size. The TX power + * table size is with one less entry by excluding the termination entry. + */ +tx_power_table_t *const ble_tx_power_table = TX_POWER_TABLE; +const size_t ble_tx_power_table_size = (sizeof(TX_POWER_TABLE) / sizeof(TX_POWER_TABLE[0])) - 1; +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c index 1afb9d593..e93561962 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.c @@ -59,38 +59,6 @@ RF_Mode rf_ieee_mode = .rfePatchFxn = 0, }; /*---------------------------------------------------------------------------*/ -/* - * TX Power table - * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: - * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) - * See the Technical Reference Manual for further details about the "txPower" Command field. - * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. - */ -RF_TxPowerTable_Entry rf_ieee_tx_power_table[] = -{ - { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 6) }, - { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 6) }, - { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 6) }, - { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 1, 0, 10) }, - { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 1, 12) }, - { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(18, 1, 1, 14) }, - { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 1, 1, 18) }, - { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(33, 1, 1, 24) }, - { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 0, 0, 33) }, - { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 0, 0, 39) }, - { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 0, 0, 45) }, - { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(36, 0, 1, 73) }, - { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(48, 0, 1, 73) }, - RF_TxPowerTable_TERMINATION_ENTRY -}; - -/* - * TX power table size, with one less entry excluding the - * termination entry. - */ -const size_t rf_ieee_tx_power_table_size = - (sizeof(rf_ieee_tx_power_table) / sizeof(rf_ieee_tx_power_table[0])) - 1; - /* * CMD_RADIO_SETUP must be configured with default TX power value * in the .txPower field. diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h index db2717f21..7019598c8 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-settings.h @@ -44,10 +44,6 @@ /* TI-RTOS RF Mode Object */ extern RF_Mode rf_ieee_mode; /*---------------------------------------------------------------------------*/ -/* TX Power Table */ -extern RF_TxPowerTable_Entry rf_ieee_tx_power_table[]; -extern const size_t rf_ieee_tx_power_table_size; -/*---------------------------------------------------------------------------*/ /* RF Core API commands */ extern rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup; extern rfc_CMD_FS_t rf_cmd_ieee_fs; diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-tx-power.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-tx-power.c new file mode 100644 index 000000000..a3a34a860 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x0/ieee-tx-power.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/** + * \addtogroup cc13xx-cc26xx-rf-tx-power + * @{ + * + * \file + * Source file for IEEE-mode TX power tables for CC26x0. + * \author + * Edvard Pettersen + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +/*---------------------------------------------------------------------------*/ +#include "rf/tx-power.h" +/*---------------------------------------------------------------------------*/ +/* + * TX Power table for CC2650 + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +tx_power_table_t rf_ieee_tx_power_table_cc2650[] = +{ + { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 6) }, + { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 6) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 6) }, + { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 1, 0, 10) }, + { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 1, 12) }, + { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(18, 1, 1, 14) }, + { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 1, 1, 18) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(33, 1, 1, 24) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 0, 0, 33) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 0, 0, 39) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 0, 0, 45) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(36, 0, 1, 73) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(48, 0, 1, 73) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +tx_power_table_t rf_ieee_tx_power_table_empty[] = +{ + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +/* Only define the symbols if Prop-mode is selected */ +#if (RF_MODE == RF_MODE_2_4_GHZ) +/*---------------------------------------------------------------------------*/ +/* TX power table, based on which board is used. */ +#if defined(DEVICE_CC2650) +#define TX_POWER_TABLE rf_ieee_tx_power_table_cc2650 + +#else +#define TX_POWER_TABLE rf_ieee_tx_power_table_empty +#endif + +/* + * Define symbols for both the TX power table and its size. The TX power + * table size is with one less entry by excluding the termination entry. + */ +tx_power_table_t *const rf_tx_power_table = TX_POWER_TABLE; +const size_t rf_tx_power_table_size = (sizeof(TX_POWER_TABLE) / sizeof(TX_POWER_TABLE[0])) - 1; +/*---------------------------------------------------------------------------*/ +#endif /* RF_MODE */ +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.c index c39fc4207..ba322e99b 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.c @@ -63,33 +63,6 @@ RF_Mode rf_ble_mode = .rfePatchFxn = &rf_patch_rfe_bt5, }; /*---------------------------------------------------------------------------*/ -/* - * TX Power table - * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: - * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) - * See the Technical Reference Manual for further details about the "txPower" Command field. - * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. - */ -RF_TxPowerTable_Entry rf_ble_tx_power_table[RF_BLE_TX_POWER_TABLE_SIZE+1] = -{ - { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 3) }, - { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 3) }, - { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 2, 0, 6) }, - { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 2, 0, 8) }, - { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 11) }, - { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 2, 0, 5) }, - { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 16) }, - { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 17) }, - { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 1, 0, 20) }, - { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(25, 1, 0, 26) }, - { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 1, 0, 28) }, - { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 0, 0, 34) }, - { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 0, 0, 42) }, - { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 0, 0, 54) }, - { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, - RF_TxPowerTable_TERMINATION_ENTRY -}; -/*---------------------------------------------------------------------------*/ /* Overrides for CMD_BLE5_RADIO_SETUP */ uint32_t rf_ble_overrides_common[] CC_ALIGN(4) = { diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.h index 81b4a0fea..a41902956 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-settings.h @@ -38,12 +38,6 @@ #include /*---------------------------------------------------------------------------*/ -/* TX Power table size definition */ -#define RF_BLE_TX_POWER_TABLE_SIZE 15 - -/* TX Power Table Object */ -extern RF_TxPowerTable_Entry rf_ble_tx_power_table[RF_BLE_TX_POWER_TABLE_SIZE+1]; -/*---------------------------------------------------------------------------*/ /* TI-RTOS RF Mode Object */ extern RF_Mode rf_ble_mode; /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-tx-power.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-tx-power.c new file mode 100644 index 000000000..368c19637 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ble-tx-power.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/** + * \addtogroup cc13xx-cc26xx-rf-tx-power + * @{ + * + * \file + * Source file for BLE Beacon TX power tables for CC26x2. + * \author + * Edvard Pettersen + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +/*---------------------------------------------------------------------------*/ +#include "rf/tx-power.h" +/*---------------------------------------------------------------------------*/ +/* + * TX Power table for CC2652R + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +tx_power_table_t rf_ble_tx_power_table_cc2652r[] = +{ + { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY( 7, 3, 0, 3) }, + { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY( 9, 3, 0, 3) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY( 8, 2, 0, 6) }, + { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 2, 0, 8) }, + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 11) }, + { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 2, 0, 5) }, + { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 16) }, + { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 17) }, + { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 1, 0, 20) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(25, 1, 0, 26) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 1, 0, 28) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 0, 0, 34) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 0, 0, 42) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 0, 0, 54) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +tx_power_table_t rf_ble_tx_power_table_empty[] = +{ + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +/* TX power table, based on which board is used. */ +#if defined(DEVICE_CC2652R) +#define TX_POWER_TABLE rf_ble_tx_power_table_cc2652r + +#else +#define TX_POWER_TABLE rf_ble_tx_power_table_empty +#endif + +/* + * Define symbols for both the TX power table and its size. The TX power + * table size is with one less entry by excluding the termination entry. + */ +tx_power_table_t *const ble_tx_power_table = TX_POWER_TABLE; +const size_t ble_tx_power_table_size = (sizeof(TX_POWER_TABLE) / sizeof(TX_POWER_TABLE[0])) - 1; +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c index b0e6de78f..cc012da89 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c @@ -60,40 +60,6 @@ RF_Mode rf_ieee_mode = .rfePatchFxn = 0, }; /*---------------------------------------------------------------------------*/ -/* - * TX Power table - * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: - * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) - * See the Technical Reference Manual for further details about the "txPower" Command field. - * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. - */ -RF_TxPowerTable_Entry rf_ieee_tx_power_table[] = -{ - { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY(7, 3, 0, 3) }, - { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY(9, 3, 0, 3) }, - { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 100) }, - { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(40, 2, 0, 8) }, - { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 11) }, - { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 2, 0, 5) }, - { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 16) }, - { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 17) }, - { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 1, 0, 20) }, - { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(25, 1, 0, 26) }, - { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 1, 0, 28) }, - { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 0, 0, 34) }, - { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 0, 0, 42) }, - { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 0, 0, 54) }, - { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, - RF_TxPowerTable_TERMINATION_ENTRY -}; - -/* - * TX power table size, with one less entry excluding the - * termination entry. - */ -const size_t rf_ieee_tx_power_table_size = - (sizeof(rf_ieee_tx_power_table) / sizeof(rf_ieee_tx_power_table[0])) - 1; - /* * CMD_RADIO_SETUP must be configured with default TX power value * in the .txPower field. diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h index d03b24665..141a0e4b3 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h @@ -45,10 +45,6 @@ /* TI-RTOS RF Mode Object */ extern RF_Mode rf_ieee_mode; /*---------------------------------------------------------------------------*/ -/* TX Power Table */ -extern RF_TxPowerTable_Entry rf_ieee_tx_power_table[]; -extern const size_t rf_ieee_tx_power_table_size; -/*---------------------------------------------------------------------------*/ /* RF Core API commands */ extern rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup; extern rfc_CMD_FS_t rf_cmd_ieee_fs; diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-tx-power.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-tx-power.c new file mode 100644 index 000000000..fcf353209 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-tx-power.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/** + * \addtogroup cc13xx-cc26xx-rf-tx-power + * @{ + * + * \file + * Source file for IEEE-mode TX power tables for CC26x2. + * \author + * Edvard Pettersen + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +/*---------------------------------------------------------------------------*/ +#include "rf/tx-power.h" +/*---------------------------------------------------------------------------*/ +/* + * TX Power table for CC2652R + * The RF_TxPowerTable_DEFAULT_PA_ENTRY macro is defined in RF.h and requires the following arguments: + * RF_TxPowerTable_DEFAULT_PA_ENTRY(bias, gain, boost coefficient) + * See the Technical Reference Manual for further details about the "txPower" Command field. + * The PA settings require the CCFG_FORCE_VDDR_HH = 0 unless stated otherwise. + */ +tx_power_table_t rf_ieee_tx_power_table_cc2652r[] = +{ + { -21, RF_TxPowerTable_DEFAULT_PA_ENTRY(7, 3, 0, 3) }, + { -18, RF_TxPowerTable_DEFAULT_PA_ENTRY(9, 3, 0, 3) }, + { -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 100) }, + { -12, RF_TxPowerTable_DEFAULT_PA_ENTRY(40, 2, 0, 8) }, + { -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(12, 2, 0, 11) }, + { -9, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 2, 0, 5) }, + { -6, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 1, 0, 16) }, + { -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 1, 0, 17) }, + { -3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 1, 0, 20) }, + { 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(25, 1, 0, 26) }, + { 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 1, 0, 28) }, + { 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 0, 0, 34) }, + { 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 0, 0, 42) }, + { 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(22, 0, 0, 54) }, + { 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(30, 0, 0, 74) }, + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +tx_power_table_t rf_ieee_tx_power_table_empty[] = +{ + RF_TxPowerTable_TERMINATION_ENTRY +}; +/*---------------------------------------------------------------------------*/ +/* Only define the symbols if Prop-mode is selected */ +#if (RF_MODE == RF_MODE_2_4_GHZ) +/*---------------------------------------------------------------------------*/ +/* TX power table, based on which board is used. */ +#if defined(DEVICE_CC2652R) +#define TX_POWER_TABLE rf_ieee_tx_power_table_cc2652r + +#else +#define TX_POWER_TABLE rf_ieee_tx_power_table_empty +#endif + +/* + * Define symbols for both the TX power table and its size. The TX power + * table size is with one less entry by excluding the termination entry. + */ +tx_power_table_t *const rf_tx_power_table = TX_POWER_TABLE; +const size_t rf_tx_power_table_size = (sizeof(TX_POWER_TABLE) / sizeof(TX_POWER_TABLE[0])) - 1; +/*---------------------------------------------------------------------------*/ +#endif /* RF_MODE */ +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c b/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c index 87fd7b43e..f4b693aa8 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c +++ b/arch/cpu/cc13xx-cc26xx/rf/ble-beacond.c @@ -55,7 +55,7 @@ #include "rf/rf.h" #include "rf/ble-addr.h" #include "rf/ble-beacond.h" -#include "rf-settings.h" +#include "rf/settings.h" /*---------------------------------------------------------------------------*/ #include #include @@ -121,25 +121,6 @@ typedef struct { static ble_beacond_t ble_beacond; /*---------------------------------------------------------------------------*/ -/* Configuration for TX power table */ -#ifdef BLE_MODE_CONF_TX_POWER_TABLE -#define TX_POWER_TABLE BLE_MODE_CONF_TX_POWER_TABLE -#else -#define TX_POWER_TABLE rf_ble_tx_power_table -#endif - -#ifdef BLE_MODE_CONF_TX_POWER_TABLE_SIZE -#define TX_POWER_TABLE_SIZE BLE_MODE_CONF_TX_POWER_TABLE_SIZE -#else -#define TX_POWER_TABLE_SIZE RF_BLE_TX_POWER_TABLE_SIZE -#endif - -/* TX power table convenience macros */ -#define TX_POWER_MIN (TX_POWER_TABLE[0].power) -#define TX_POWER_MAX (TX_POWER_TABLE[TX_POWER_TABLE_SIZE - 1].power) - -#define TX_POWER_IN_RANGE(dbm) (((dbm) >= TX_POWER_MIN) && ((dbm) <= TX_POWER_MAX)) -/*---------------------------------------------------------------------------*/ PROCESS(ble_beacond_process, "RF BLE Beacon Daemon Process"); /*---------------------------------------------------------------------------*/ rf_ble_beacond_result_t @@ -209,11 +190,11 @@ rf_ble_is_active(void) } /*---------------------------------------------------------------------------*/ rf_ble_beacond_result_t -rf_ble_set_tx_power(int8_t dBm) +rf_ble_set_tx_power(int8_t dbm) { rf_result_t res; - if(!TX_POWER_IN_RANGE(dBm)) { + if(!tx_power_in_range(dbm, ble_tx_power_table, ble_tx_power_table_size)) { return RADIO_RESULT_INVALID_VALUE; } @@ -233,7 +214,7 @@ rf_ble_get_tx_power(void) res = rf_get_tx_power(ble_beacond.rf_handle, TX_POWER_TABLE, &dbm) if(res != RF_RESULT_OK) { - return ~(int8_t)0; + return RF_TxPowerTable_INVALID_DBM; } return dbm; diff --git a/arch/cpu/cc13xx-cc26xx/rf/data-queue.c b/arch/cpu/cc13xx-cc26xx/rf/data-queue.c index 31da05302..27e383557 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/data-queue.c +++ b/arch/cpu/cc13xx-cc26xx/rf/data-queue.c @@ -51,8 +51,8 @@ #include /*---------------------------------------------------------------------------*/ /* RX buf configuration */ -#define RX_BUF_CNT RF_RX_BUF_CNT -#define RX_BUF_SIZE RF_RX_BUF_SIZE +#define RX_BUF_CNT RF_CONF_RX_BUF_CNT +#define RX_BUF_SIZE RF_CONF_RX_BUF_SIZE /*---------------------------------------------------------------------------*/ /* Receive buffer entries with room for 1 IEEE 802.15.4 frame in each */ typedef union { diff --git a/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c b/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c index 9a36497fc..ef7408b21 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c +++ b/arch/cpu/cc13xx-cc26xx/rf/ieee-mode.c @@ -71,7 +71,8 @@ #include "rf/data-queue.h" #include "rf/dot-15-4g.h" #include "rf/sched.h" -#include "ieee-settings.h" +#include "rf/settings.h" +#include "rf/tx-power.h" /*---------------------------------------------------------------------------*/ #include #include @@ -79,43 +80,15 @@ #include #include /*---------------------------------------------------------------------------*/ -#if 1 -#define PRINTF(...) printf(__VA_ARGS__) -#else -# define PRINTF(...) -#endif +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Radio" +#define LOG_LEVEL LOG_LEVEL_NONE /*---------------------------------------------------------------------------*/ /* Configuration parameters */ - -/* Configuration to enable/disable auto ACKs in IEEE mode */ -#ifdef IEEE_MODE_CONF_AUTOACK -#define IEEE_MODE_AUTOACK IEEE_MODE_CONF_AUTOACK -#else -#define IEEE_MODE_AUTOACK 1 -#endif /* IEEE_MODE_CONF_AUTOACK */ - -/* Configuration to enable/disable frame filtering in IEEE mode */ -#ifdef IEEE_MODE_CONF_PROMISCOUS -#define IEEE_MODE_PROMISCOUS IEEE_MODE_CONF_PROMISCOUS -#else -#define IEEE_MODE_PROMISCOUS 0 -#endif /* IEEE_MODE_CONF_PROMISCOUS */ - -/* Configuration to set the RSSI threshold */ -#ifdef IEEE_MODE_CONF_RSSI_THRESHOLD -#define IEEE_MODE_RSSI_THRESHOLD IEEE_MODE_CONF_RSSI_THRESHOLD -#else -#define IEEE_MODE_RSSI_THRESHOLD 0xA6 -#endif /* IEEE_MODE_CONF_RSSI_THRESHOLD */ -/*---------------------------------------------------------------------------*/ -/* TX power table convenience macros */ -#define TX_POWER_TABLE rf_ieee_tx_power_table -#define TX_POWER_TABLE_SIZE rf_ieee_tx_power_table_size - -#define TX_POWER_MIN (TX_POWER_TABLE[0].power) -#define TX_POWER_MAX (TX_POWER_TABLE[TX_POWER_TABLE_SIZE - 1].power) - -#define TX_POWER_IN_RANGE(dbm) (((dbm) >= TX_POWER_MIN) && ((dbm) <= TX_POWER_MAX)) +#define IEEE_MODE_AUTOACK IEEE_MODE_CONF_AUTOACK +#define IEEE_MODE_PROMISCOUS IEEE_MODE_CONF_PROMISCOUS +#define IEEE_MODE_CCA_RSSI_THRESHOLD IEEE_MODE_CONF_CCA_RSSI_THRESHOLD /*---------------------------------------------------------------------------*/ /* Timeout constants */ @@ -232,24 +205,6 @@ static radio_result_t set_value(radio_param_t, radio_value_t); static radio_result_t get_object(radio_param_t, void*, size_t); static radio_result_t set_object(radio_param_t, const void*, size_t); /*---------------------------------------------------------------------------*/ -/* Radio driver object */ -const struct radio_driver ieee_mode_driver = { - init, - prepare, - transmit, - send, - read, - channel_clear, - receiving_packet, - pending_packet, - on, - off, - get_value, - set_value, - get_object, - set_object, -}; -/*---------------------------------------------------------------------------*/ static void rat_overflow_cb(void *arg) { @@ -279,7 +234,7 @@ init_rf_params(void) cmd_rx.frameFiltOpt.autoAckEn = 0; #endif - cmd_rx.ccaRssiThr = IEEE_MODE_RSSI_THRESHOLD; + cmd_rx.ccaRssiThr = IEEE_MODE_CCA_RSSI_THRESHOLD; cmd_tx.pNextOp = (RF_Op*)&cmd_rx_ack; cmd_tx.condition.rule = COND_NEVER; /* Initially ACK turned off */ @@ -306,8 +261,8 @@ static rf_result_t set_channel(uint8_t channel) { if(!dot_15_4g_chan_in_range(channel)) { - PRINTF("set_channel: illegal channel %d, defaults to %d\n", - (int)channel, DOT_15_4G_DEFAULT_CHAN); + LOG_WARN("Supplied hannel %d is illegal, defaults to %d\n", + (int)channel, DOT_15_4G_DEFAULT_CHAN); channel = DOT_15_4G_DEFAULT_CHAN; } @@ -327,7 +282,7 @@ set_channel(uint8_t channel) const uint16_t freq = (uint16_t)(new_freq / 1000); const uint16_t frac = (uint16_t)(((new_freq - (freq * 1000)) * 0x10000) / 1000); - PRINTF("set_channel: %d = 0x%04X.0x%04X (%lu)\n", + LOG_DBG("Set channel to %d, frequency 0x%04X.0x%04X (%lu)\n", (int)channel, freq, frac, new_freq); cmd_fs.frequency = freq; @@ -402,7 +357,7 @@ static int init(void) { if(ieee_radio.rf_handle) { - PRINTF("init: Radio already initialized\n"); + LOG_WARN("Radio already initialized\n"); return RF_RESULT_OK; } @@ -419,13 +374,14 @@ init(void) ieee_radio.rf_handle = netstack_open(&rf_params); if(ieee_radio.rf_handle == NULL) { - PRINTF("init: unable to open IEEE RF driver\n"); + LOG_ERR("Unable to open RF driver\n"); return RF_RESULT_ERROR; } set_channel(DOT_15_4G_DEFAULT_CHAN); - rf_set_tx_power(ieee_radio.rf_handle, TX_POWER_TABLE, TX_POWER_MAX); + int8_t max_tx_power = tx_power_max(rf_tx_power_table, rf_tx_power_table_size); + rf_set_tx_power(ieee_radio.rf_handle, rf_tx_power_table, max_tx_power); ENERGEST_ON(ENERGEST_TYPE_LISTEN); @@ -456,7 +412,7 @@ transmit(unsigned short transmit_len) rf_result_t res; if(ieee_radio.send_on_cca && channel_clear() != 1) { - PRINTF("transmit: channel wasn't clear\n"); + LOG_WARN("Channel is not clear for transmission\n"); return RADIO_TX_COLLISION; } @@ -551,7 +507,7 @@ read(void *buf, unsigned short buf_len) /* Sanity check that Frame is at least Frame Shave bytes long */ if(frame_len < FRAME_SHAVE) { - PRINTF("read: frame too short len=%d\n", frame_len); + LOG_ERR("Received frame too short, len=%d\n", frame_len); data_queue_release_entry(); return 0; @@ -560,9 +516,10 @@ read(void *buf, unsigned short buf_len) const uint8_t *payload_ptr = frame_ptr + sizeof(lensz_t); const unsigned short payload_len = (unsigned short)(frame_len - FRAME_SHAVE); - /* Sanity check that Payload fits in Buffer */ + /* Sanity check that Payload fits in buffer. */ if(payload_len > buf_len) { - PRINTF("read: payload too large for buffer len=%d buf_len=%d\n", payload_len, buf_len); + LOG_ERR("MAC payload too large for buffer, len=%d buf_len=%d\n", + payload_len, buf_len); data_queue_release_entry(); return 0; @@ -570,11 +527,11 @@ read(void *buf, unsigned short buf_len) memcpy(buf, payload_ptr, payload_len); - /* RSSI stored FCS (2) bytes after payload */ + /* RSSI stored FCS (2) bytes after payload. */ ieee_radio.last.rssi = (int8_t)payload_ptr[payload_len + 2]; - /* LQI retrieved from Status byte, FCS (2) + RSSI (1) bytes after payload */ + /* LQI retrieved from Status byte, FCS (2) + RSSI (1) bytes after payload. */ ieee_radio.last.corr_lqi = (uint8_t)(payload_ptr[payload_len + 3] & STATUS_CORRELATION); - /* Timestamp stored FCS (2) + RSSI (1) + Status (1) bytes after payload */ + /* Timestamp stored FCS (2) + RSSI (1) + Status (1) bytes after payload. */ const uint32_t rat_ticks = *(uint32_t*)(payload_ptr + payload_len + 4); ieee_radio.last.timestamp = rat_to_timestamp(rat_ticks); @@ -617,9 +574,12 @@ cca_request(cmd_cca_req_t *cmd_cca_req) netstack_stop_rx(); } - return (stat == RF_StatCmdDoneSuccess) - ? RF_RESULT_OK - : RF_RESULT_ERROR; + if(stat != RF_StatCmdDoneSuccess) { + LOG_ERR("CCA request failed, stat=0x%02X\n", stat); + return RF_RESULT_ERROR; + } + + return RF_RESULT_OK; } /*---------------------------------------------------------------------------*/ static int @@ -652,7 +612,7 @@ receiving_packet(void) if((cmd_cca_req.ccaInfo.ccaEnergy == CCA_STATE_BUSY) && (cmd_cca_req.ccaInfo.ccaCorr == CCA_STATE_BUSY) && (cmd_cca_req.ccaInfo.ccaSync == CCA_STATE_BUSY)) { - PRINTF("receiving_packet: we were TXing ACK\n"); + LOG_WARN("We are TXing ACK, therefore not receiving packets\n"); return 0; } @@ -694,7 +654,7 @@ on(void) rf_result_t res; if(ieee_radio.rf_is_on) { - PRINTF("on: Radio already on\n"); + LOG_WARN("Radio is already on\n"); return RF_RESULT_OK; } @@ -714,7 +674,7 @@ static int off(void) { if(!ieee_radio.rf_is_on) { - PRINTF("off: Radio already off\n"); + LOG_WARN("Radio is already off\n"); return RF_RESULT_OK; } @@ -778,7 +738,7 @@ get_value(radio_param_t param, radio_value_t *value) /* TX power */ case RADIO_PARAM_TXPOWER: - res = rf_get_tx_power(ieee_radio.rf_handle, TX_POWER_TABLE, (int8_t*)&value); + res = rf_get_tx_power(ieee_radio.rf_handle, rf_tx_power_table, (int8_t*)&value); return ((res == RF_RESULT_OK) && (*value != RF_TxPowerTable_INVALID_DBM)) ? RADIO_RESULT_OK @@ -807,12 +767,12 @@ get_value(radio_param_t param, radio_value_t *value) return RADIO_RESULT_OK; case RADIO_CONST_TXPOWER_MIN: - *value = (radio_value_t)TX_POWER_MIN; + *value = (radio_value_t)tx_power_min(rf_tx_power_table); return RADIO_RESULT_OK; /* TX power max */ case RADIO_CONST_TXPOWER_MAX: - *value = (radio_value_t)TX_POWER_MAX; + *value = (radio_value_t)tx_power_max(rf_tx_power_table, rf_tx_power_table_size); return RADIO_RESULT_OK; /* Last RSSI */ @@ -909,7 +869,7 @@ set_value(radio_param_t param, radio_value_t value) memcpy(&cmd_mod_filt.newFrameFiltOpt, &(rf_cmd_ieee_rx.frameFiltOpt), sizeof(rf_cmd_ieee_rx.frameFiltOpt)); const RF_Stat stat = RF_runImmediateCmd(ieee_radio.rf_handle, (uint32_t*)&cmd_mod_filt); if(stat != RF_StatCmdDoneSuccess) { - PRINTF("setting address filter failed: stat=0x%02X\n", stat); + LOG_ERR("Setting address filter failed, stat=0x%02X\n", stat); return RADIO_RESULT_ERROR; } return RADIO_RESULT_OK; @@ -935,10 +895,10 @@ set_value(radio_param_t param, radio_value_t value) /* TX Power */ case RADIO_PARAM_TXPOWER: - if(!TX_POWER_IN_RANGE((int8_t)value)) { + if(!tx_power_in_range((int8_t)value, rf_tx_power_table, rf_tx_power_table_size)) { return RADIO_RESULT_INVALID_VALUE; } - res = rf_set_tx_power(ieee_radio.rf_handle, TX_POWER_TABLE, (int8_t)value); + res = rf_set_tx_power(ieee_radio.rf_handle, rf_tx_power_table, (int8_t)value); return (res == RF_RESULT_OK) ? RADIO_RESULT_OK : RADIO_RESULT_ERROR; @@ -1037,6 +997,23 @@ set_object(radio_param_t param, const void *src, size_t size) } } /*---------------------------------------------------------------------------*/ +const struct radio_driver ieee_mode_driver = { + init, + prepare, + transmit, + send, + read, + channel_clear, + receiving_packet, + pending_packet, + on, + off, + get_value, + set_value, + get_object, + set_object, +}; +/*---------------------------------------------------------------------------*/ /** * @} * @} diff --git a/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c b/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c index c3042fa6e..a2ff18635 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c +++ b/arch/cpu/cc13xx-cc26xx/rf/prop-mode.c @@ -64,7 +64,8 @@ #include "rf/dot-15-4g.h" #include "rf/sched.h" #include "rf/data-queue.h" -#include "prop-settings.h" +#include "rf/tx-power.h" +#include "rf/settings.h" /*---------------------------------------------------------------------------*/ #include #include @@ -74,64 +75,43 @@ /*---------------------------------------------------------------------------*/ /* Log configuration */ #include "sys/log.h" -#define LOG_MODULE "RF Prop Mode" +#define LOG_MODULE "Radio" #define LOG_LEVEL LOG_LEVEL_NONE /*---------------------------------------------------------------------------*/ -#if 0 -# define PRINTF(...) -#else -# define PRINTF(...) printf(__VA_ARGS__) -#endif -/*---------------------------------------------------------------------------*/ -/* Data whitener. 1: Whitener, 0: No whitener */ -#ifdef PROP_MODE_CONF_DW -#define PROP_MODE_DW PROP_MODE_CONF_DW -#else -#define PROP_MODE_DW 0 -#endif - -#ifdef PROP_MODE_CONF_USE_CRC16 -#define PROP_MODE_USE_CRC16 PROP_MODE_CONF_USE_CRC16 -#else -#define PROP_MODE_USE_CRC16 0 -#endif +/* Configuration parameters */ +#define PROP_MODE_DW PROP_MODE_CONF_DW +#define PROP_MODE_USE_CRC16 PROP_MODE_CONF_USE_CRC16 +#define PROP_MODE_CCA_RSSI_THRESHOLD PROP_MODE_CONF_CCA_RSSI_THRESHOLD /*---------------------------------------------------------------------------*/ /* Used for checking result of CCA_REQ command */ -#define CCA_STATE_IDLE 0 -#define CCA_STATE_BUSY 1 -#define CCA_STATE_INVALID 2 - -/* Used as an error return value for get_cca_info */ -#define RF_GET_CCA_INFO_ERROR 0xFF - -#ifdef PROP_MODE_CONF_RSSI_THRESHOLD -#define PROP_MODE_RSSI_THRESHOLD PROP_MODE_CONF_RSSI_THRESHOLD -#else -#define PROP_MODE_RSSI_THRESHOLD 0xA6 -#endif +typedef enum { + CCA_STATE_IDLE = 0, + CCA_STATE_BUSY = 1, + CCA_STATE_INVALID = 2 +} cca_state_t; /*---------------------------------------------------------------------------*/ /* Defines and variables related to the .15.4g PHY HDR */ #define DOT_4G_MAX_FRAME_LEN 2047 -#define DOT_4G_PHR_LEN 2 +#define DOT_4G_PHR_LEN 2 /* PHY HDR bits */ -#define DOT_4G_PHR_CRC16 0x10 -#define DOT_4G_PHR_DW 0x08 +#define DOT_4G_PHR_CRC16 0x10 +#define DOT_4G_PHR_DW 0x08 #if PROP_MODE_USE_CRC16 /* CRC16 */ -#define DOT_4G_PHR_CRC_BIT DOT_4G_PHR_CRC16 -#define CRC_LEN 2 +#define DOT_4G_PHR_CRC_BIT DOT_4G_PHR_CRC16 +#define CRC_LEN 2 #else /* CRC32 */ -#define DOT_4G_PHR_CRC_BIT 0 -#define CRC_LEN 4 +#define DOT_4G_PHR_CRC_BIT 0 +#define CRC_LEN 4 #endif /* PROP_MODE_USE_CRC16 */ #if PROP_MODE_DW -#define DOT_4G_PHR_DW_BIT DOT_4G_PHR_DW +#define DOT_4G_PHR_DW_BIT DOT_4G_PHR_DW #else -#define DOT_4G_PHR_DW_BIT 0 +#define DOT_4G_PHR_DW_BIT 0 #endif /*---------------------------------------------------------------------------*/ /* How long to wait for the RF to enter RX in rf_cmd_ieee_rx */ @@ -140,15 +120,6 @@ /* How long to wait for the rx read entry to become ready */ #define TIMEOUT_DATA_ENTRY_BUSY (RTIMER_SECOND / 250) /*---------------------------------------------------------------------------*/ -/* TX power table convenience macros */ -#define TX_POWER_TABLE rf_prop_tx_power_table -#define TX_POWER_TABLE_SIZE rf_prop_tx_power_table_size - -#define TX_POWER_MIN (TX_POWER_TABLE[0].power) -#define TX_POWER_MAX (TX_POWER_TABLE[TX_POWER_TABLE_SIZE - 1].power) - -#define TX_POWER_IN_RANGE(dbm) ((TX_POWER_MIN <= (dbm)) && ((dbm) <= TX_POWER_MAX)) -/*---------------------------------------------------------------------------*/ /* TX buf configuration */ #define TX_BUF_HDR_LEN 2 #define TX_BUF_PAYLOAD_LEN 180 @@ -156,42 +127,44 @@ #define TX_BUF_SIZE (TX_BUF_HDR_LEN + TX_BUF_PAYLOAD_LEN) /*---------------------------------------------------------------------------*/ /* Size of the Length field in Data Entry, two bytes in this case */ -typedef uint16_t lensz_t; +typedef uint16_t lensz_t; -#define FRAME_OFFSET sizeof(lensz_t) -#define FRAME_SHAVE 2 /* RSSI (1) + Status (1) */ +#define FRAME_OFFSET sizeof(lensz_t) +#define FRAME_SHAVE 2 /**< RSSI (1) + Status (1) */ /*---------------------------------------------------------------------------*/ -#define MAC_RADIO_RECEIVER_SENSITIVITY_DBM -110 -#define MAC_RADIO_RECEIVER_SATURATION_DBM 10 -#define MAC_SPEC_ED_MIN_DBM_ABOVE_RECEIVER_SENSITIVITY 10 -#define MAC_SPEC_ED_MAX 0xFF +/* Constants used when calculating the LQI from the RSSI */ +#define RX_SENSITIVITY_DBM -110 +#define RX_SATURATION_DBM 10 +#define ED_MIN_DBM_ABOVE_RX_SENSITIVITY 10 +#define ED_MAX 0xFF -#define ED_RF_POWER_MIN_DBM (MAC_RADIO_RECEIVER_SENSITIVITY_DBM + MAC_SPEC_ED_MIN_DBM_ABOVE_RECEIVER_SENSITIVITY) -#define ED_RF_POWER_MAX_DBM MAC_RADIO_RECEIVER_SATURATION_DBM +#define ED_RF_POWER_MIN_DBM (RX_SENSITIVITY_DBM + ED_MIN_DBM_ABOVE_RX_SENSITIVITY) +#define ED_RF_POWER_MAX_DBM RX_SATURATION_DBM /*---------------------------------------------------------------------------*/ /* RF Core typedefs */ typedef rfc_propRxOutput_t rx_output_t; typedef struct { /* Outgoing frame buffer */ - uint8_t tx_buf[TX_BUF_SIZE] CC_ALIGN(4); + uint8_t tx_buf[TX_BUF_SIZE] CC_ALIGN(4); /* RX Statistics struct */ - rx_output_t rx_stats; + rx_output_t rx_stats; /* RSSI Threshold */ - int8_t rssi_threshold; - uint16_t channel; + int8_t rssi_threshold; + uint16_t channel; /* Indicates RF is supposed to be on or off */ - uint8_t rf_is_on; + uint8_t rf_is_on; /* RF driver */ - RF_Handle rf_handle; + RF_Handle rf_handle; } prop_radio_t; static prop_radio_t prop_radio; /*---------------------------------------------------------------------------*/ +/* Convenience macros for volatile access with the RF commands */ #define cmd_radio_setup (*(volatile rfc_CMD_PROP_RADIO_DIV_SETUP_t *)&rf_cmd_prop_radio_div_setup) #define cmd_fs (*(volatile rfc_CMD_FS_t *) &rf_cmd_prop_fs) #define cmd_tx (*(volatile rfc_CMD_PROP_TX_ADV_t *) &rf_cmd_prop_tx_adv) @@ -202,6 +175,7 @@ tx_is_active(void) { return cmd_tx.status == ACTIVE; } +/*---------------------------------------------------------------------------*/ static inline bool rx_is_active(void) { @@ -322,7 +296,7 @@ calculate_lqi(int8_t rssi) * best granularity. This is done by grouping the math operations to * compute the entire numerator before doing any division. */ - return (MAC_SPEC_ED_MAX * (rssi - ED_RF_POWER_MIN_DBM)) / (ED_RF_POWER_MAX_DBM - ED_RF_POWER_MIN_DBM); + return (ED_MAX * (rssi - ED_RF_POWER_MIN_DBM)) / (ED_RF_POWER_MAX_DBM - ED_RF_POWER_MIN_DBM); } /*---------------------------------------------------------------------------*/ static int @@ -576,7 +550,7 @@ get_value(radio_param_t param, radio_value_t *value) return RADIO_RESULT_OK; case RADIO_PARAM_TXPOWER: - res = rf_get_tx_power(prop_radio.rf_handle, TX_POWER_TABLE, (int8_t*)&value); + res = rf_get_tx_power(prop_radio.rf_handle, rf_tx_power_table, (int8_t*)&value); return ((res == RF_RESULT_OK) && (*value != RF_TxPowerTable_INVALID_DBM)) ? RADIO_RESULT_OK @@ -601,11 +575,11 @@ get_value(radio_param_t param, radio_value_t *value) return RADIO_RESULT_OK; case RADIO_CONST_TXPOWER_MIN: - *value = (radio_value_t)TX_POWER_MIN; + *value = (radio_value_t)tx_power_min(rf_tx_power_table); return RADIO_RESULT_OK; case RADIO_CONST_TXPOWER_MAX: - *value = (radio_value_t)TX_POWER_MAX; + *value = (radio_value_t)tx_power_max(rf_tx_power_table, rf_tx_power_table_size); return RADIO_RESULT_OK; default: @@ -639,10 +613,10 @@ set_value(radio_param_t param, radio_value_t value) : RADIO_RESULT_ERROR; case RADIO_PARAM_TXPOWER: - if(!TX_POWER_IN_RANGE((int8_t)value)) { + if(!tx_power_in_range((int8_t)value, rf_tx_power_table, rf_tx_power_table_size)) { return RADIO_RESULT_INVALID_VALUE; } - res = rf_set_tx_power(prop_radio.rf_handle, TX_POWER_TABLE, (int8_t)value); + res = rf_set_tx_power(prop_radio.rf_handle, rf_tx_power_table, (int8_t)value); return (res == RF_RESULT_OK) ? RADIO_RESULT_OK : RADIO_RESULT_ERROR; diff --git a/arch/cpu/cc13xx-cc26xx/rf/sched.c b/arch/cpu/cc13xx-cc26xx/rf/sched.c index d1e8bbef5..85e7f5e7e 100644 --- a/arch/cpu/cc13xx-cc26xx/rf/sched.c +++ b/arch/cpu/cc13xx-cc26xx/rf/sched.c @@ -57,17 +57,18 @@ #include "rf/rf.h" #include "rf/sched.h" #include "rf/data-queue.h" -#include "rf-settings.h" +#include "rf/settings.h" /*---------------------------------------------------------------------------*/ #include #include #include /*---------------------------------------------------------------------------*/ -#if 1 -#define PRINTF(...) printf(__VA_ARGS__) -#else -#define PRINTF(...) -#endif +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Radio" +#define LOG_LEVEL LOG_LEVEL_NONE +/*---------------------------------------------------------------------------*/ +/* Configuration parameters */ /*---------------------------------------------------------------------------*/ #define CMD_FS_RETRIES 3 @@ -175,7 +176,7 @@ cmd_rx_restore(uint_fast8_t rx_key) ); if(!CMD_HANDLE_OK(cmd_rx_handle)) { - PRINTF("cmd_rx_restore: unable to schedule RX command handle=%d status=0x%04x", + LOG_ERR("Unable to restore RX command, handle=%d status=0x%04x", cmd_rx_handle, CMD_STATUS(netstack_cmd_rx)); return RF_RESULT_ERROR; } @@ -322,7 +323,7 @@ netstack_sched_ieee_tx(bool ack_request) ); if(!CMD_HANDLE_OK(tx_handle)) { - PRINTF("netstack_sched_tx: unable to schedule TX command handle=%d status=0x%04x\n", + LOG_ERR("Unable to schedule TX command, handle=%d status=0x%04x\n", tx_handle, CMD_STATUS(netstack_cmd_tx)); return RF_RESULT_ERROR; } @@ -348,7 +349,7 @@ netstack_sched_ieee_tx(bool ack_request) } if(!EVENTS_CMD_DONE(tx_events)) { - PRINTF("netstack_sched_tx: TX command pend error events=0x%08llx status=0x%04x\n", + LOG_ERR("Pending on TX comand generated error, events=0x%08llx status=0x%04x\n", tx_events, CMD_STATUS(netstack_cmd_tx)); return RF_RESULT_ERROR; } @@ -376,8 +377,8 @@ netstack_sched_prop_tx(void) ); if(!CMD_HANDLE_OK(tx_handle)) { - PRINTF("netstack_sched_tx: unable to schedule TX command handle=%d status=0x%04x\n", - tx_handle, CMD_STATUS(netstack_cmd_tx)); + LOG_ERR("Unable to schedule TX command, handle=%d status=0x%04x\n", + tx_handle, CMD_STATUS(netstack_cmd_tx)); return RF_RESULT_ERROR; } @@ -405,8 +406,8 @@ netstack_sched_prop_tx(void) } if(!EVENTS_CMD_DONE(tx_events)) { - PRINTF("netstack_sched_tx: TX command pend error events=0x%08llx status=0x%04x\n", - tx_events, CMD_STATUS(netstack_cmd_tx)); + LOG_ERR("Pending on scheduled TX command generated error, events=0x%08llx status=0x%04x\n", + tx_events, CMD_STATUS(netstack_cmd_tx)); return RF_RESULT_ERROR; } @@ -417,7 +418,7 @@ rf_result_t netstack_sched_rx(bool start) { if(cmd_rx_is_active()) { - PRINTF("netstack_sched_rx: already in RX\n"); + LOG_WARN("Already in RX when scheduling RX\n"); return RF_RESULT_OK; } @@ -438,8 +439,8 @@ netstack_sched_rx(bool start) ); if(!CMD_HANDLE_OK(cmd_rx_handle)) { - PRINTF("netstack_sched_rx: unable to schedule RX command handle=%d status=0x%04x\n", - cmd_rx_handle, CMD_STATUS(netstack_cmd_rx)); + LOG_ERR("Unable to schedule RX command, handle=%d status=0x%04x\n", + cmd_rx_handle, CMD_STATUS(netstack_cmd_rx)); return RF_RESULT_ERROR; } @@ -457,7 +458,7 @@ rf_result_t netstack_stop_rx(void) { if(!cmd_rx_is_active()) { - PRINTF("netstack_stop_rx: RX not active\n"); + LOG_WARN("RX not active when stopping RX\n"); return RF_RESULT_OK; } @@ -498,8 +499,8 @@ ble_sched_beacon(RF_Callback cb, RF_EventMask bm_event) ); if(!CMD_HANDLE_OK(beacon_handle)) { - PRINTF("ble_sched_beacon: unable to schedule BLE Beacon command handle=%d status=0x%04x\n", - beacon_handle, CMD_STATUS(ble_cmd_beacon)); + LOG_ERR("Unable to schedule BLE Beacon command, handle=%d status=0x%04x\n", + beacon_handle, CMD_STATUS(ble_cmd_beacon)); return RF_RESULT_ERROR; } @@ -508,8 +509,8 @@ ble_sched_beacon(RF_Callback cb, RF_EventMask bm_event) /* Wait until Beacon operation finishes */ RF_EventMask beacon_events = RF_pendCmd(&rf_ble, beacon_handle, 0); if(!EVENTS_CMD_DONE(beacon_events)) { - PRINTF("ble_sched_beacon: Beacon command pend error events=0x%08llx status=0x%04x\n", - beacon_events, CMD_STATUS(ble_cmd_beacon)); + LOG_ERR("Pending on scheduled BLE Beacon command generated error, events=0x%08llx status=0x%04x\n", + beacon_events, CMD_STATUS(ble_cmd_beacon)); cmd_rx_restore(rx_key); return RF_RESULT_ERROR; @@ -534,7 +535,9 @@ PROCESS_THREAD(rf_sched_process, ev, data) /* start the synth re-calibration timer once. */ if(rf_is_on) { rf_is_on = false; - etimer_set(&synth_recal_timer, synth_recal_interval()); + clock_time_t interval = synth_recal_interval(); + LOG_INFO("Starting synth re-calibration timer, next timeout %lu\n", interval); + etimer_set(&synth_recal_timer, interval); } if(ev == PROCESS_EVENT_POLL) { @@ -549,7 +552,7 @@ PROCESS_THREAD(rf_sched_process, ev, data) * RX after we've freed at least on packet. */ if(rx_buf_full) { - PRINTF("rf_core: RX buf full, restart RX status=0x%04x\n", CMD_STATUS(netstack_cmd_rx)); + LOG_ERR("RX buffer full, restart RX status=0x%04x\n", CMD_STATUS(netstack_cmd_rx)); rx_buf_full = false; /* Restart RX. */ @@ -569,10 +572,11 @@ PROCESS_THREAD(rf_sched_process, ev, data) /* Scheduling CMD_FS will re-calibrate the synth. */ if((ev == PROCESS_EVENT_TIMER) && etimer_expired(&synth_recal_timer)) { - PRINTF("rf_core: Re-calibrate synth\n"); - netstack_sched_fs(); + clock_time_t interval = synth_recal_interval(); + LOG_DBG("Re-calibrate synth, next interval %lu\n", interval); - etimer_set(&synth_recal_timer, synth_recal_interval()); + netstack_sched_fs(); + etimer_set(&synth_recal_timer, interval); } } PROCESS_END(); diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/rf-settings.h b/arch/cpu/cc13xx-cc26xx/rf/settings.h similarity index 87% rename from arch/cpu/cc13xx-cc26xx/rf-settings/rf-settings.h rename to arch/cpu/cc13xx-cc26xx/rf/settings.h index 744a6948a..4f6eab1c2 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/rf-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf/settings.h @@ -27,6 +27,19 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ + /** + * \addtogroup cc13xx-cc26xx-cpu + * @{ + * + * \defgroup cc13xx-cc26xx-rf-settings RF settings for CC13xx/CC26xx + * + * @{ + * + * \file + * Header file of RF settings for CC13xx/CC26xx. + * \author + * Edvard Pettersen + */ /*---------------------------------------------------------------------------*/ #ifndef NETSTACK_SETTINGS_H_ #define NETSTACK_SETTINGS_H_ @@ -35,57 +48,63 @@ /*---------------------------------------------------------------------------*/ #include /*---------------------------------------------------------------------------*/ +#if SUPPORTS_PROP_MODE +#include "prop-settings.h" +#endif + +#if SUPPORTS_IEEE_MODE +#include "ieee-settings.h" +#endif + +#if SUPPORTS_BLE_BEACON +#include "ble-settings.h" +#endif +/*---------------------------------------------------------------------------*/ +/* Netstack RF command configuration */ + /* Prop-mode RF settings */ #if (RF_MODE == RF_MODE_SUB_1_GHZ) -#include "prop-settings.h" - #define netstack_mode rf_prop_mode #define netstack_cmd_radio_setup rf_cmd_prop_radio_div_setup #define netstack_cmd_fs rf_cmd_prop_fs #define netstack_cmd_tx rf_cmd_prop_tx_adv #define netstack_cmd_rx rf_cmd_prop_rx_adv -/*---------------------------------------------------------------------------*/ + /* IEEE-mode RF settings */ #elif (RF_MODE == RF_MODE_2_4_GHZ) -#include "ieee-settings.h" - #define netstack_mode rf_ieee_mode #define netstack_cmd_radio_setup rf_cmd_ieee_radio_setup #define netstack_cmd_fs rf_cmd_ieee_fs #define netstack_cmd_tx rf_cmd_ieee_tx #define netstack_cmd_rx rf_cmd_ieee_rx -/*---------------------------------------------------------------------------*/ -#else -#error "Unsupported RF_MODE" -#endif -/*---------------------------------------------------------------------------*/ -/* BLE RF settings */ +#endif /* RF_MODE */ +/*---------------------------------------------------------------------------*/ +/* BLE Beacon RF command configuration */ + +/* CC13x0/CC26x0 devices */ #if (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0) -#include "ble-settings.h" - #define ble_mode rf_ble_mode #define ble_cmd_radio_setup rf_ble_cmd_radio_setup #define ble_adv_par rf_ble_adv_par #define ble_cmd_beacon rf_ble_cmd_ble_adv_nc -/*---------------------------------------------------------------------------*/ +/* CC13x2/CC26x2 devices */ #elif (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X2_CC26X2) -#include "ble-settings.h" - #define ble_mode rf_ble_mode #define ble_cmd_radio_setup rf_cmd_ble5_radio_setup #define ble_adv_par rf_ble5_adv_aux_par #define ble_cmd_beacon rf_cmd_ble5_adv_aux -/*---------------------------------------------------------------------------*/ -#else -#error "Unsupported DeviceFamily_PARENT for BLE settings" -#endif +#endif /* DeviceFamily_PARENT */ /*---------------------------------------------------------------------------*/ #endif /* NETSTACK_SETTINGS_H_ */ /*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ \ No newline at end of file diff --git a/arch/cpu/cc13xx-cc26xx/rf/tx-power.h b/arch/cpu/cc13xx-cc26xx/rf/tx-power.h new file mode 100644 index 000000000..a6104275e --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/rf/tx-power.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ +/** + * \addtogroup cc13xx-cc26xx-cpu + * @{ + * + * \defgroup cc13xx-cc26xx-rf-tx-power TX power functioanlity for CC13xx/CC26xx + * + * @{ + * + * \file + * Header file of TX power functionality of CC13xx/CC26xx. + * \author + * Edvard Pettersen + */ +/*---------------------------------------------------------------------------*/ +#ifndef TX_POWER_H_ +#define TX_POWER_H_ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +/*---------------------------------------------------------------------------*/ +#include +/*---------------------------------------------------------------------------*/ +#include +#include +#include +/*---------------------------------------------------------------------------*/ +#define RF_TXPOWER_HIGH_PA RF_CONF_TXPOWER_HIGH_PA +#define RF_TXPOWER_BOOST_MODE RF_CONF_TXPOWER_BOOST_MODE +/*---------------------------------------------------------------------------*/ +typedef RF_TxPowerTable_Entry tx_power_table_t; +/*---------------------------------------------------------------------------*/ +/** + * \name Extern declarations of TX Power Table variables. + * + * @{ + */ + +/* Nestack RF TX power table */ +extern tx_power_table_t *const rf_tx_power_table; +extern const size_t rf_tx_power_table_size; + +/* BLE Beacon RF TX power table */ +extern tx_power_table_t *const ble_tx_power_table; +extern const size_t ble_tx_power_table_size; +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \name TX power table convenience functions. + * + * @{ + */ + +static inline int8_t +tx_power_min(tx_power_table_t *table) +{ + return table[0].power; +} + +static inline int8_t +tx_power_max(tx_power_table_t *table, size_t size) +{ + return table[size - 1].power; +} + +static inline bool +tx_power_in_range(int8_t dbm, tx_power_table_t *table, size_t size) +{ + return (dbm >= tx_power_min(table)) && + (dbm <= tx_power_max(table, size)); +} +/** @} */ +/*---------------------------------------------------------------------------*/ +#endif /* TX_POWER_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index e691b0768..5e9904fe7 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -38,6 +38,7 @@ DEFINES += $(BOARD_TYPE) DEFINES += PLATFORM_HAS_BUTTON=$(PLATFORM_HAS_BUTTON) DEFINES += SUPPORTS_PROP_MODE=$(SUPPORTS_PROP_MODE) DEFINES += SUPPORTS_IEEE_MODE=$(SUPPORTS_IEEE_MODE) +DEFINES += SUPPORTS_BLE_BEACON=$(SUPPORTS_BLE_BEACON) DEFINES += SUPPORTS_HIGH_PA=$(SUPPORTS_HIGH_PA) ### If the user-specified a Node ID, pass a define diff --git a/arch/platform/simplelink/cc13xx-cc26xx/platform.c b/arch/platform/simplelink/cc13xx-cc26xx/platform.c index ab40846a7..bf295e762 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/platform.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/platform.c @@ -84,7 +84,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "CC13xx/CC26xx" -#define LOG_LEVEL LOG_LEVEL_DBG +#define LOG_LEVEL LOG_LEVEL_MAIN /*---------------------------------------------------------------------------*/ /* * Board-specific initialization function. This function is defined in @@ -164,7 +164,7 @@ platform_init_stage_one(void) gpio_hal_init(); leds_init(); - fade(Board_PIN_RLED); + fade(Board_PIN_LED0); /* TI Drivers init */ #if TI_UART_CONF_ENABLE @@ -182,7 +182,7 @@ platform_init_stage_one(void) TRNG_init(); - fade(Board_PIN_GLED); + fade(Board_PIN_LED1); /* NoRTOS must be called last */ NoRTOS_start(); @@ -214,7 +214,7 @@ platform_init_stage_two(void) button_hal_init(); - fade(Board_PIN_RLED); + fade(Board_PIN_LED0); } /*---------------------------------------------------------------------------*/ void @@ -251,7 +251,7 @@ platform_init_stage_three(void) process_start(&sensors_process, NULL); #endif - fade(Board_PIN_GLED); + fade(Board_PIN_LED1); } /*---------------------------------------------------------------------------*/ void diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c index 3795a77d5..830506fac 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.c @@ -41,12 +41,13 @@ #include "lib/sensors.h" #include "sys/ctimer.h" /*---------------------------------------------------------------------------*/ +#include "board-conf.h" +#include "bmp-280-sensor.h" +/*---------------------------------------------------------------------------*/ #include #include /*---------------------------------------------------------------------------*/ -#include "bmp-280-sensor.h" -/*---------------------------------------------------------------------------*/ #include #include #include @@ -58,6 +59,13 @@ #define PRINTF(...) #endif /*---------------------------------------------------------------------------*/ +/* + * Disable the entire file if sensors are disabled, as it could potentially + * create compile errors with missing defines from either the Board file or + * configuration defines. + */ +#if BOARD_SENSORS_ENABLE +/*---------------------------------------------------------------------------*/ #ifndef Board_BMP280_ADDR # error "Board file doesn't define I2C address Board_BMP280_ADDR" #endif @@ -458,4 +466,6 @@ status(int type) /*---------------------------------------------------------------------------*/ SENSORS_SENSOR(bmp_280_sensor, "BMP280", value, configure, status); /*---------------------------------------------------------------------------*/ +#endif /* BOARD_SENSORS_ENABLE */ +/*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.h index 3f7f846b7..f2c160947 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/bmp-280-sensor.h @@ -59,10 +59,14 @@ #include "contiki.h" #include "lib/sensors.h" /*---------------------------------------------------------------------------*/ +#include "board-conf.h" +/*---------------------------------------------------------------------------*/ /* The BMP-280 driver uses the I2C0 peripheral to access the senssor */ +#if BOARD_SENSORS_ENABLE #if (TI_I2C_CONF_ENABLE == 0) || (TI_I2C_CONF_I2C0_ENABLE == 0) # error "The BMP280 requires the I2C driver (TI_I2C_CONF_ENABLE = 1)" #endif +#endif /*---------------------------------------------------------------------------*/ typedef enum { BMP_280_SENSOR_TYPE_TEMP, diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h index eec9423ab..fa3c4e406 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/board-conf.h @@ -72,6 +72,15 @@ #define BOARD_CONF_HAS_SENSORS 1 /** @} */ /*---------------------------------------------------------------------------*/ +/** + * \name Enable or disable the SensorTag sensors. + * + * Those values are not meant to be modified by the user + * @{ + */ +#define BOARD_SENSORS_ENABLE (!(BOARD_CONF_SENSORS_DISABLE)) +/** @} */ +/*---------------------------------------------------------------------------*/ #endif /* BOARD_CONF_H_ */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 index ccee91606..d5b3303ba 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/Makefile.cc2650 @@ -4,7 +4,7 @@ SUBFAMILY = cc13x0-cc26x0 DEVICE_FAMILY = CC26X0 DEVICE_LINE = CC26XX -DEVICE = CC1350 +DEVICE = CC2650 BOARD_SOURCEFILES += CC2650STK.c CC2650STK_fxns.c BOARD_SOURCEFILES += leds-arch.c diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.c index 47e724fa0..2f3e6fa6e 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.c @@ -40,6 +40,8 @@ #include "contiki.h" #include "sys/ctimer.h" #include "lib/sensors.h" +/*---------------------------------------------------------------------------*/ +#include "board-conf.h" #include "hdc-1000-sensor.h" /*---------------------------------------------------------------------------*/ #include @@ -58,6 +60,13 @@ #define PRINTF(...) #endif /*---------------------------------------------------------------------------*/ +/* + * Disable the entire file if sensors are disabled, as it could potentially + * create compile errors with missing defines from either the Board file or + * configuration defines. + */ +#if BOARD_SENSORS_ENABLE +/*---------------------------------------------------------------------------*/ #ifndef Board_HDC1000_ADDR # error "Board file doesn't define the I2C address Board_HDC1000_ADDR" #endif @@ -342,4 +351,6 @@ status(int type) /*---------------------------------------------------------------------------*/ SENSORS_SENSOR(hdc_1000_sensor, "HDC1000", value, configure, status); /*---------------------------------------------------------------------------*/ +#endif /* BOARD_SENSORS_ENABLE */ +/*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.h index c3d31e383..b6bd7ca4f 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/hdc-1000-sensor.h @@ -67,9 +67,13 @@ #include "contiki.h" #include "lib/sensors.h" /*---------------------------------------------------------------------------*/ +#include "board-conf.h" +/*---------------------------------------------------------------------------*/ +#if BOARD_SENSORS_ENABLE #if (TI_I2C_CONF_ENABLE == 0) || (TI_I2C_CONF_I2C0_ENABLE == 0) # error "The HDC-1000 requires the I2C driver (TI_I2C_CONF_ENABLE = 1)" #endif +#endif /*---------------------------------------------------------------------------*/ typedef enum { HDC_1000_SENSOR_TYPE_TEMP, diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c index a35a08367..f849c6735 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.c @@ -40,7 +40,8 @@ #include "contiki.h" #include "lib/sensors.h" #include "sys/rtimer.h" - +/*---------------------------------------------------------------------------*/ +#include "board-conf.h" #include "mpu-9250-sensor.h" /*---------------------------------------------------------------------------*/ #include @@ -63,6 +64,13 @@ #define PRINTF(...) #endif /*---------------------------------------------------------------------------*/ +/* + * Disable the entire file if sensors are disabled, as it could potentially + * create compile errors with missing defines from either the Board file or + * configuration defines. + */ +#if BOARD_SENSORS_ENABLE +/*---------------------------------------------------------------------------*/ #ifndef Board_MPU9250_ADDR # error "Board file doesn't define I2C address Board_MPU9250_ADDR" #endif @@ -648,4 +656,6 @@ status(int type) /*---------------------------------------------------------------------------*/ SENSORS_SENSOR(mpu_9250_sensor, "MPU9250", value, configure, status); /*---------------------------------------------------------------------------*/ +#endif /* BOARD_SENSORS_ENABLE */ +/*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.h index 632d6e5b9..846e6beb2 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/mpu-9250-sensor.h @@ -75,9 +75,13 @@ /*---------------------------------------------------------------------------*/ #include "contiki.h" /*---------------------------------------------------------------------------*/ +#include "board-conf.h" +/*---------------------------------------------------------------------------*/ +#if BOARD_SENSORS_ENABLE #if (TI_I2C_CONF_ENABLE == 0) || (TI_I2C_CONF_I2C0_ENABLE == 0) # error "The MPU-9250 requires the I2C driver (TI_I2C_CONF_ENABLE = 1)" #endif +#endif /*---------------------------------------------------------------------------*/ #define MPU_9250_READING_ERROR -1 /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.c index f846e42a1..086c61165 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.c @@ -40,7 +40,8 @@ #include "contiki.h" #include "lib/sensors.h" #include "sys/ctimer.h" - +/*---------------------------------------------------------------------------*/ +#include "board-conf.h" #include "opt-3001-sensor.h" /*---------------------------------------------------------------------------*/ #include @@ -59,6 +60,13 @@ #define PRINTF(...) #endif /*---------------------------------------------------------------------------*/ +/* + * Disable the entire file if sensors are disabled, as it could potentially + * create compile errors with missing defines from either the Board file or + * configuration defines. + */ +#if BOARD_SENSORS_ENABLE +/*---------------------------------------------------------------------------*/ #ifndef Board_OPT3001_ADDR # error "Board file doesn't define I2C address Board_OPT3001_ADDR" #endif @@ -365,4 +373,6 @@ status(int type) /*---------------------------------------------------------------------------*/ SENSORS_SENSOR(opt_3001_sensor, "OPT3001", value, configure, status); /*---------------------------------------------------------------------------*/ +#endif /* BOARD_SENSORS_ENABLE */ +/*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.h index 06f6cca8b..7f4e132c5 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/opt-3001-sensor.h @@ -63,9 +63,13 @@ /*---------------------------------------------------------------------------*/ #include "contiki.h" /*---------------------------------------------------------------------------*/ +#include "board-conf.h" +/*---------------------------------------------------------------------------*/ +#if BOARD_SENSORS_ENABLE #if (TI_I2C_CONF_ENABLE == 0) || (TI_I2C_CONF_I2C0_ENABLE == 0) # error "The OPT-3001 requires the I2C driver (TI_I2C_CONF_ENABLE = 1)" #endif +#endif /*---------------------------------------------------------------------------*/ #define OPT_3001_READING_ERROR -1 /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag-sensors.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag-sensors.c index 258f9f829..d2da9fa8f 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag-sensors.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/sensortag-sensors.c @@ -39,10 +39,13 @@ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "lib/sensors.h" - +/*---------------------------------------------------------------------------*/ +#include "board-conf.h" #include "board-peripherals.h" /*---------------------------------------------------------------------------*/ /* Exports a global symbol to be used by the sensor API */ +#if BOARD_SENSORS_ENABLE SENSORS(&bmp_280_sensor, &tmp_007_sensor, &opt_3001_sensor, &hdc_1000_sensor, &mpu_9250_sensor); +#endif /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c index 8c6b5e8d7..92033c5a8 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.c @@ -40,7 +40,8 @@ #include "contiki.h" #include "lib/sensors.h" #include "sys/ctimer.h" - +/*---------------------------------------------------------------------------*/ +#include "board-conf.h" #include "tmp-007-sensor.h" /*---------------------------------------------------------------------------*/ #include @@ -59,6 +60,13 @@ #define PRINTF(...) #endif /*---------------------------------------------------------------------------*/ +/* + * Disable the entire file if sensors are disabled, as it could potentially + * create compile errors with missing defines from either the Board file or + * configuration defines. + */ +#if BOARD_SENSORS_ENABLE +/*---------------------------------------------------------------------------*/ /* Slave address */ #ifndef Board_TMP_ADDR # error "Board file doesn't define I2C address Board_TMP_ADDR" @@ -409,4 +417,6 @@ status(int type) /*---------------------------------------------------------------------------*/ SENSORS_SENSOR(tmp_007_sensor, "TMP-007", value, configure, status); /*---------------------------------------------------------------------------*/ +#endif /* BOARD_SENSORS_ENABLE */ +/*---------------------------------------------------------------------------*/ /** @} */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.h index 0fff84556..cb810e703 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/tmp-007-sensor.h @@ -68,9 +68,13 @@ /*---------------------------------------------------------------------------*/ #include "contiki.h" /*---------------------------------------------------------------------------*/ +#include "board-conf.h" +/*---------------------------------------------------------------------------*/ +#if BOARD_SENSORS_ENABLE #if (TI_I2C_CONF_ENABLE == 0) || (TI_I2C_CONF_I2C0_ENABLE == 0) # error "The BMP280 requires the I2C driver to be enabled (TI_I2C_CONF_ENABLE = 1)" #endif +#endif /*---------------------------------------------------------------------------*/ typedef enum { TMP_007_TYPE_OBJECT = (1 << 0), diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/board-conf.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/board-conf.h index 8fdb0895f..a8a97ddf5 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/board-conf.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/board-conf.h @@ -80,6 +80,15 @@ #define BOARD_CONF_HAS_SENSORS 1 /** @} */ /*---------------------------------------------------------------------------*/ +/** + * \name Enable or disable the SmartRF06EB sensors. + * + * Those values are not meant to be modified by the user + * @{ + */ +#define BOARD_SENSORS_ENABLE (!(BOARD_CONF_SENSORS_DISABLE)) +/** @} */ +/*---------------------------------------------------------------------------*/ #endif /* BOARD_CONF_H_ */ /*---------------------------------------------------------------------------*/ /** diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/srf06-sensors.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/srf06-sensors.c index 2bb2aee67..1660cc0c8 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/srf06-sensors.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/srf06-sensors.c @@ -39,10 +39,13 @@ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "lib/sensors.h" - +/*---------------------------------------------------------------------------*/ +#include "board-conf.h" #include "board-peripherals.h" /*---------------------------------------------------------------------------*/ /* Exports a global symbol to be used by the sensor API */ +#if BOARD_SENSORS_ENABLE SENSORS(&als_sensor); +#endif /*---------------------------------------------------------------------------*/ /** @} */ From a19980929840b948e04fbc27a7bc4c115ff5316f Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Tue, 24 Jul 2018 17:46:42 +0200 Subject: [PATCH 290/485] Added the Core SDK submodule --- .gitmodules | 3 +++ arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 27 ++++++++++++++++--- .../cc13xx-cc26xx/lib/coresdk_cc13xx_cc26xx | 1 + arch/platform/simplelink/Makefile.simplelink | 16 +++-------- 4 files changed, 31 insertions(+), 16 deletions(-) create mode 160000 arch/cpu/cc13xx-cc26xx/lib/coresdk_cc13xx_cc26xx diff --git a/.gitmodules b/.gitmodules index 80dd37e17..9fbee3575 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,3 +22,6 @@ [submodule "tools/motelist"] path = tools/motelist url = https://github.com/contiki-ng/motelist +[submodule "arch/cpu/cc13xx-cc26xx/lib/coresdk_cc13xx_cc26xx"] + path = arch/cpu/cc13xx-cc26xx/lib/coresdk_cc13xx_cc26xx + url = https://github.com/contiki-ng/coresdk_cc13xx_cc26xx.git diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index 3c86a2a50..2b9331c2b 100644 --- a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -1,13 +1,34 @@ ################################################################################ # CC13x2/CC26x2 CPU makefile +# Core SDK is placed as a submodule under the arch/cpu/cc13xx-cc26xx/lib. +# Do a sanity check that Core SDK submodule has been initialized. +# Note that Core SDK can be overriden with a user-specified SimpleLink SDK. +# As long as the SimpleLink SDK matches the device in use and is of a reasonable +# newer version, then it should be no different than using Core SDK. +ifeq ($(CORE_SDK),) + CORE_SDK := $(CONTIKI_CPU)/lib/coresdk_cc13xx_cc26xx + CORE_SDK_INIT := $(shell [ -f $(CORE_SDK)/.git ]; echo $$?) + ifeq ($(CORE_SDK_INIT),1) + $(error The Core SDK submodule is not available. Please run 'git submodule update --init --recursive') + endif +else + # Core SDK was overriden. Do a sanity check the path exists. + CORE_SDK_VALID := $(shell [ -d $(CORE_SDK) ]; echo $$?) + ifeq ($(CORE_SDK_VALID),1) + $(error Supplied CORE_SDK is not a valid path.) + endif +endif +# Clean up the path. +CORE_SDK := ${realpath $(CORE_SDK)} + # ccfg.c comes from the device-specific startp_files folder, # and startup_cc13xx_cc26xx_gcc.c comes from NoRTOS startup folder CPU_START_SOURCEFILES += ccfg.c startup_cc13xx_cc26xx_gcc.c ################################################################################ # Device Family -DEVICE_FAMILY_H := $(SIMPLELINK_SDK)/source/ti/devices/DeviceFamily.h +DEVICE_FAMILY_H := $(CORE_SDK)/source/ti/devices/DeviceFamily.h # The define of the Device Family ID is on the format of either # #define DeviceFamily_ID_ @@ -54,8 +75,8 @@ SDK_DEVICE_DIR := $(shell echo "DeviceFamily_constructPath(dummy)" \ ################################################################################ # Simplelink SDK paths -SDK_KERNEL := $(SIMPLELINK_SDK)/kernel/nortos -SDK_SOURCE := $(SIMPLELINK_SDK)/source +SDK_KERNEL := $(CORE_SDK)/kernel/nortos +SDK_SOURCE := $(CORE_SDK)/source SDK_BOARDS := $(SDK_SOURCE)/ti/boards SDK_DRIVERS := $(SDK_SOURCE)/ti/drivers SDK_DEVICE := $(SDK_SOURCE)/$(SDK_DEVICE_DIR) diff --git a/arch/cpu/cc13xx-cc26xx/lib/coresdk_cc13xx_cc26xx b/arch/cpu/cc13xx-cc26xx/lib/coresdk_cc13xx_cc26xx new file mode 160000 index 000000000..b83faf3be --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/lib/coresdk_cc13xx_cc26xx @@ -0,0 +1 @@ +Subproject commit b83faf3be2cb7468dc836a6fbd9d804638263252 diff --git a/arch/platform/simplelink/Makefile.simplelink b/arch/platform/simplelink/Makefile.simplelink index 2435e6e3d..250d034a0 100644 --- a/arch/platform/simplelink/Makefile.simplelink +++ b/arch/platform/simplelink/Makefile.simplelink @@ -5,25 +5,15 @@ ### Sanity check of expected symbols ifndef CONTIKI - $(error 'CONTIKI' not defined! You must specify where CONTIKI resides!) + $(error 'CONTIKI' not defined! You must specify where CONTIKI resides!) endif ifndef FAMILY - $(error 'FAMILY' not defined! You must specify which Simplelink family you are using!) + $(error 'FAMILY' not defined! You must specify which Simplelink family you are using!) endif ifndef BOARD - $(error 'BOARD' not defined! You must specify which board you are using!) -endif - -ifndef SIMPLELINK_SDK - $(error 'SIMPLELINK_SDK' not defined! You must specify where the installed SimpleLink SDK resides!) -endif - -SIMPLELINK_SDK_EXISTS := $(shell [ -d "$(SIMPLELINK_SDK)" ]; echo $$?) - -ifneq ($(SIMPLELINK_SDK_EXISTS),0) - $(error Simplelink SDK path 'SIMPLELINK_SDK' does not exist) + $(error 'BOARD' not defined! You must specify which board you are using!) endif ################################################################################ From 8fb568a7a2090444cf168c4f1e85260e11a17141 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Tue, 24 Jul 2018 17:58:08 +0200 Subject: [PATCH 291/485] Removed Display from Board files --- arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h | 28 ----- .../launchpad/cc1310/CC1310_LAUNCHXL.c | 101 ----------------- .../launchpad/cc1310/CC1310_LAUNCHXL.h | 3 - .../launchpad/cc1312r1/CC1312R1_LAUNCHXL.c | 101 ----------------- .../launchpad/cc1312r1/CC1312R1_LAUNCHXL.h | 3 - .../launchpad/cc1350-4/CC1350_LAUNCHXL_433.c | 101 ----------------- .../launchpad/cc1350-4/CC1350_LAUNCHXL_433.h | 3 - .../launchpad/cc1350/CC1350_LAUNCHXL.c | 101 ----------------- .../launchpad/cc1350/CC1350_LAUNCHXL.h | 3 - .../launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.c | 106 +----------------- .../launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h | 4 +- .../launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.c | 106 +----------------- .../launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.h | 4 +- .../launchpad/cc1352p1/CC1352P1_LAUNCHXL.c | 106 +----------------- .../launchpad/cc1352p1/CC1352P1_LAUNCHXL.h | 4 +- .../launchpad/cc1352r1/CC1352R1_LAUNCHXL.c | 101 ----------------- .../launchpad/cc1352r1/CC1352R1_LAUNCHXL.h | 3 - .../launchpad/cc2650/CC2650_LAUNCHXL.c | 101 ----------------- .../launchpad/cc2650/CC2650_LAUNCHXL.h | 3 - .../launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c | 102 ----------------- .../launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h | 3 - .../sensortag/cc1350/CC1350STK.c | 100 ----------------- .../sensortag/cc1350/CC1350STK.h | 2 - .../sensortag/cc2650/CC2650STK.c | 100 ----------------- .../sensortag/cc2650/CC2650STK.h | 2 - .../cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c | 101 ----------------- .../cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h | 8 -- .../cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c | 101 ----------------- .../cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h | 8 -- 29 files changed, 6 insertions(+), 1503 deletions(-) diff --git a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h index e32819285..fad5bcf5e 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h +++ b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h @@ -402,34 +402,6 @@ #define TI_NVS_CONF_NVS_EXTERNAL_ENABLE TI_NVS_CONF_ENABLE #endif -/** - * \brief Enable or disable Display driver. - */ -#ifndef TI_DISPLAY_CONF_ENABLE -#define TI_DISPLAY_CONF_ENABLE 0 -#endif - -/** - * \brief Enable or disable UART Display peripheral. - */ -#ifndef TI_DISPLAY_CONF_UART_ENABLE -#define TI_DISPLAY_CONF_UART_ENABLE TI_UART_CONF_UART0_ENABLE -#endif - -/** - * \brief Configure UART Display peripheral to use ANSI or not. - */ -#ifndef TI_DISPLAY_CONF_USE_UART_ANSI -#define TI_DISPLAY_CONF_USE_UART_ANSI 0 -#endif - -/** - * \brief Enable or disable LCD Display peripheral. - */ -#ifndef TI_DISPLAY_CONF_LCD_ENABLE -#define TI_DISPLAY_CONF_LCD_ENABLE TI_SPI_CONF_SPI0_ENABLE -#endif - /** * \brief Enable or disable SD driver. */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.c index 638bfa0d0..b33dab9ad 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.c @@ -247,101 +247,6 @@ const CryptoCC26XX_Config CryptoCC26XX_config[CC1310_LAUNCHXL_CRYPTOCOUNT] = { } }; -/* - * =============================== Display =============================== - */ -#include -#include -#include - -#if TI_DISPLAY_CONF_ENABLE - -#if TI_DISPLAY_CONF_UART_ENABLE - -#if !(TI_UART_CONF_UART0_ENABLE) -#error "Display UART driver requires UART0" -#endif - -#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE -#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 -#endif - -static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; - -DisplayUart_Object displayUartObject; - -const DisplayUart_HWAttrs displayUartHWAttrs = { - .uartIdx = CC1310_LAUNCHXL_UART0, - .baudRate = 115200, - .mutexTimeout = (unsigned int)(-1), - .strBuf = uartStringBuf, - .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, -}; - -#endif /* TI_DISPLAY_CONF_UART_ENABLE */ - -#if TI_DISPLAY_CONF_LCD_ENABLE - -#if !(TI_SPI_CONF_SPI0_ENABLE) -#error "Display LCD driver requires SPI0" -#endif - -#ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 -#endif - -static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; - -DisplaySharp_Object displaySharpObject; - -const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { - .spiIndex = CC1310_LAUNCHXL_SPI0, - .csPin = CC1310_LAUNCHXL_GPIO_LCD_CS, - .powerPin = CC1310_LAUNCHXL_GPIO_LCD_POWER, - .enablePin = CC1310_LAUNCHXL_GPIO_LCD_ENABLE, - .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, - .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, - .displayBuf = sharpDisplayBuf, -}; - -#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ - -/* - * This #if/#else is needed to workaround a problem with the - * IAR compiler. The IAR compiler doesn't like the empty array - * initialization. (IAR Error[Pe1345]) - */ - -const Display_Config Display_config[] = { -#if TI_DISPLAY_CONF_UART_ENABLE - { -# if TI_DISPLAY_CONF_USE_UART_ANSI - .fxnTablePtr = &DisplayUartAnsi_fxnTable, -# else /* Default to minimal UART with no cursor placement */ - .fxnTablePtr = &DisplayUartMin_fxnTable, -# endif - .object = &displayUartObject, - .hwAttrs = &displayUartHWAttrs, - }, -#endif -#if TI_DISPLAY_CONF_LCD_ENABLE - { - .fxnTablePtr = &DisplaySharp_fxnTable, - .object = &displaySharpObject, - .hwAttrs = &displaySharpHWattrs - }, -#endif -}; - -const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); - -#else - -const Display_Config *Display_config = NULL; -const uint_least8_t Display_count = 0; - -#endif /* TI_DISPLAY_CONF_ENABLE */ - /* * =============================== GPIO =============================== */ @@ -373,12 +278,6 @@ GPIO_PinConfig gpioPinConfigs[] = { /* SD CS */ GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG, - - /* Sharp Display - GPIO configurations will be done in the Display files */ - GPIOCC26XX_DIO_24 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ - GPIOCC26XX_DIO_22 | GPIO_DO_NOT_CONFIG, /* LCD power control */ - GPIOCC26XX_DIO_23 | GPIO_DO_NOT_CONFIG, /*LCD enable */ - }; /* diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h index 4d11cd749..b1066711b 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1310/CC1310_LAUNCHXL.h @@ -229,9 +229,6 @@ typedef enum CC1310_LAUNCHXL_GPIOName { CC1310_LAUNCHXL_GPIO_LED_RED, CC1310_LAUNCHXL_GPIO_SPI_FLASH_CS, CC1310_LAUNCHXL_SDSPI_CS, - CC1310_LAUNCHXL_GPIO_LCD_CS, - CC1310_LAUNCHXL_GPIO_LCD_POWER, - CC1310_LAUNCHXL_GPIO_LCD_ENABLE, CC1310_LAUNCHXL_GPIOCOUNT } CC1310_LAUNCHXL_GPIOName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.c index e45317c9f..44fd41035 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.c @@ -368,101 +368,6 @@ const AESECB_Config AESECB_config[CC1312R1_LAUNCHXL_AESECBCOUNT] = { const uint_least8_t AESECB_count = CC1312R1_LAUNCHXL_AESECBCOUNT; -/* - * =============================== Display =============================== - */ -#include -#include -#include - -#if TI_DISPLAY_CONF_ENABLE - -#if TI_DISPLAY_CONF_UART_ENABLE - -#if !(TI_UART_CONF_UART0_ENABLE) -#error "Display UART driver requires UART0" -#endif - -#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE -#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 -#endif - -static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; - -DisplayUart_Object displayUartObject; - -const DisplayUart_HWAttrs displayUartHWAttrs = { - .uartIdx = CC1312R1_LAUNCHXL_UART0, - .baudRate = 115200, - .mutexTimeout = (unsigned int)(-1), - .strBuf = uartStringBuf, - .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, -}; - -#endif /* TI_DISPLAY_CONF_UART_ENABLE */ - -#if TI_DISPLAY_CONF_LCD_ENABLE - -#if !(TI_SPI_CONF_SPI0_ENABLE) -#error "Display LCD driver requires SPI0" -#endif - -#ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 -#endif - -DisplaySharp_Object displaySharpObject; - -static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; - -const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { - .spiIndex = CC1312R1_LAUNCHXL_SPI0, - .csPin = CC1312R1_LAUNCHXL_GPIO_LCD_CS, - .powerPin = CC1312R1_LAUNCHXL_GPIO_LCD_POWER, - .enablePin = CC1312R1_LAUNCHXL_GPIO_LCD_ENABLE, - .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, - .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, - .displayBuf = sharpDisplayBuf, -}; - -#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ - -/* - * This #if/#else is needed to workaround a problem with the - * IAR compiler. The IAR compiler doesn't like the empty array - * initialization. (IAR Error[Pe1345]) - */ - -const Display_Config Display_config[] = { -#if TI_DISPLAY_CONF_UART_ENABLE - { -# if TI_DISPLAY_CONF_USE_UART_ANSI - .fxnTablePtr = &DisplayUartAnsi_fxnTable, -# else /* Default to minimal UART with no cursor placement */ - .fxnTablePtr = &DisplayUartMin_fxnTable, -# endif - .object = &displayUartObject, - .hwAttrs = &displayUartHWAttrs, - }, -#endif -#if TI_DISPLAY_CONF_LCD_ENABLE - { - .fxnTablePtr = &DisplaySharp_fxnTable, - .object = &displaySharpObject, - .hwAttrs = &displaySharpHWattrs - }, -#endif -}; - -const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); - -#else - -const Display_Config *Display_config = NULL; -const uint_least8_t Display_count = 0; - -#endif /* TI_DISPLAY_CONF_ENABLE */ - /* * =============================== GPIO =============================== */ @@ -494,12 +399,6 @@ GPIO_PinConfig gpioPinConfigs[] = { /* SD CS */ GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG, - - /* Sharp Display - GPIO configurations will be done in the Display files */ - GPIOCC26XX_DIO_24 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ - GPIOCC26XX_DIO_22 | GPIO_DO_NOT_CONFIG, /* LCD power control */ - GPIOCC26XX_DIO_23 | GPIO_DO_NOT_CONFIG, /*LCD enable */ - }; /* diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h index 3d796df9b..a6e5e3bbf 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1312r1/CC1312R1_LAUNCHXL.h @@ -288,9 +288,6 @@ typedef enum CC1312R1_LAUNCHXL_GPIOName { CC1312R1_LAUNCHXL_GPIO_LED_RED, CC1312R1_LAUNCHXL_GPIO_SPI_FLASH_CS, CC1312R1_LAUNCHXL_SDSPI_CS, - CC1312R1_LAUNCHXL_GPIO_LCD_CS, - CC1312R1_LAUNCHXL_GPIO_LCD_POWER, - CC1312R1_LAUNCHXL_GPIO_LCD_ENABLE, CC1312R1_LAUNCHXL_GPIOCOUNT } CC1312R1_LAUNCHXL_GPIOName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.c index deec29ce6..fda5b5b9f 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.c @@ -246,101 +246,6 @@ const CryptoCC26XX_Config CryptoCC26XX_config[CC1350_LAUNCHXL_433_CRYPTOCOUNT] = }, }; -/* - * =============================== Display =============================== - */ -#include -#include -#include - -#if TI_DISPLAY_CONF_ENABLE - -#if TI_DISPLAY_CONF_UART_ENABLE - -#if !(TI_UART_CONF_UART0_ENABLE) -#error "Display UART driver requires UART0" -#endif - -#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE -#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 -#endif - -static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; - -DisplayUart_Object displayUartObject; - -const DisplayUart_HWAttrs displayUartHWAttrs = { - .uartIdx = CC1350_LAUNCHXL_433_UART0, - .baudRate = 115200, - .mutexTimeout = (unsigned int)(-1), - .strBuf = uartStringBuf, - .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, -}; - -#endif /* TI_DISPLAY_CONF_UART_ENABLE */ - -#if TI_DISPLAY_CONF_LCD_ENABLE - -#if !(TI_SPI_CONF_SPI0_ENABLE) -#error "Display LCD driver requires SPI0" -#endif - -#ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 -#endif - -static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; - -DisplaySharp_Object displaySharpObject; - -const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { - .spiIndex = CC1350_LAUNCHXL_433_SPI0, - .csPin = CC1350_LAUNCHXL_433_GPIO_LCD_CS, - .powerPin = CC1350_LAUNCHXL_433_GPIO_LCD_POWER, - .enablePin = CC1350_LAUNCHXL_433_GPIO_LCD_ENABLE, - .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, - .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, - .displayBuf = sharpDisplayBuf, -}; - -#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ - -/* - * This #if/#else is needed to workaround a problem with the - * IAR compiler. The IAR compiler doesn't like the empty array - * initialization. (IAR Error[Pe1345]) - */ - -const Display_Config Display_config[] = { -#if TI_DISPLAY_CONF_UART_ENABLE - { -# if TI_DISPLAY_CONF_USE_UART_ANSI - .fxnTablePtr = &DisplayUartAnsi_fxnTable, -# else /* Default to minimal UART with no cursor placement */ - .fxnTablePtr = &DisplayUartMin_fxnTable, -# endif - .object = &displayUartObject, - .hwAttrs = &displayUartHWAttrs, - }, -#endif -#if TI_DISPLAY_CONF_LCD_ENABLE - { - .fxnTablePtr = &DisplaySharp_fxnTable, - .object = &displaySharpObject, - .hwAttrs = &displaySharpHWattrs - }, -#endif -}; - -const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); - -#else - -const Display_Config *Display_config = NULL; -const uint_least8_t Display_count = 0; - -#endif /* TI_DISPLAY_CONF_ENABLE */ - /* * =============================== GPIO =============================== */ @@ -372,12 +277,6 @@ GPIO_PinConfig gpioPinConfigs[] = { /* SD CS */ GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG, - - /* Sharp Display - GPIO configurations will be done in the Display files */ - GPIOCC26XX_DIO_24 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ - GPIOCC26XX_DIO_22 | GPIO_DO_NOT_CONFIG, /* LCD power control */ - GPIOCC26XX_DIO_23 | GPIO_DO_NOT_CONFIG, /*LCD enable */ - }; /* diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h index 441bb04fa..80352e30e 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350-4/CC1350_LAUNCHXL_433.h @@ -232,9 +232,6 @@ typedef enum CC1350_LAUNCHXL_433_GPIOName { CC1350_LAUNCHXL_433_GPIO_LED_RED, CC1350_LAUNCHXL_433_GPIO_SPI_FLASH_CS, CC1350_LAUNCHXL_433_SDSPI_CS, - CC1350_LAUNCHXL_433_GPIO_LCD_CS, - CC1350_LAUNCHXL_433_GPIO_LCD_POWER, - CC1350_LAUNCHXL_433_GPIO_LCD_ENABLE, CC1350_LAUNCHXL_433_GPIOCOUNT } CC1350_LAUNCHXL_433_GPIOName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c index cddb5a9fa..1277fc66a 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.c @@ -247,101 +247,6 @@ const CryptoCC26XX_Config CryptoCC26XX_config[CC1350_LAUNCHXL_CRYPTOCOUNT] = { }, }; -/* - * =============================== Display =============================== - */ -#include -#include -#include - -#if TI_DISPLAY_CONF_ENABLE - -#if TI_DISPLAY_CONF_UART_ENABLE - -#if !(TI_UART_CONF_UART0_ENABLE) -#error "Display UART driver requires UART0" -#endif - -#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE -#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 -#endif - -static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; - -DisplayUart_Object displayUartObject; - -const DisplayUart_HWAttrs displayUartHWAttrs = { - .uartIdx = CC1350_LAUNCHXL_UART0, - .baudRate = 115200, - .mutexTimeout = (unsigned int)(-1), - .strBuf = uartStringBuf, - .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, -}; - -#endif /* TI_DISPLAY_CONF_UART_ENABLE */ - -#if TI_DISPLAY_CONF_LCD_ENABLE - -#if !(TI_SPI_CONF_SPI0_ENABLE) -#error "Display LCD driver requires SPI0" -#endif - -#ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 -#endif - -static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; - -DisplaySharp_Object displaySharpObject; - -const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { - .spiIndex = CC1350_LAUNCHXL_SPI0, - .csPin = CC1350_LAUNCHXL_GPIO_LCD_CS, - .powerPin = CC1350_LAUNCHXL_GPIO_LCD_POWER, - .enablePin = CC1350_LAUNCHXL_GPIO_LCD_ENABLE, - .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, - .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, - .displayBuf = sharpDisplayBuf, -}; - -#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ - -/* - * This #if/#else is needed to workaround a problem with the - * IAR compiler. The IAR compiler doesn't like the empty array - * initialization. (IAR Error[Pe1345]) - */ - -const Display_Config Display_config[] = { -#if TI_DISPLAY_CONF_UART_ENABLE - { -# if TI_DISPLAY_CONF_USE_UART_ANSI - .fxnTablePtr = &DisplayUartAnsi_fxnTable, -# else /* Default to minimal UART with no cursor placement */ - .fxnTablePtr = &DisplayUartMin_fxnTable, -# endif - .object = &displayUartObject, - .hwAttrs = &displayUartHWAttrs, - }, -#endif -#if TI_DISPLAY_CONF_LCD_ENABLE - { - .fxnTablePtr = &DisplaySharp_fxnTable, - .object = &displaySharpObject, - .hwAttrs = &displaySharpHWattrs - }, -#endif -}; - -const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); - -#else - -const Display_Config *Display_config = NULL; -const uint_least8_t Display_count = 0; - -#endif /* TI_DISPLAY_CONF_ENABLE */ - /* * =============================== GPIO =============================== */ @@ -373,12 +278,6 @@ GPIO_PinConfig gpioPinConfigs[] = { /* SD CS */ GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG, - - /* Sharp Display - GPIO configurations will be done in the Display files */ - GPIOCC26XX_DIO_24 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ - GPIOCC26XX_DIO_22 | GPIO_DO_NOT_CONFIG, /* LCD power control */ - GPIOCC26XX_DIO_23 | GPIO_DO_NOT_CONFIG, /*LCD enable */ - }; /* diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h index 746a25fa1..f711874c2 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1350/CC1350_LAUNCHXL.h @@ -232,9 +232,6 @@ typedef enum CC1350_LAUNCHXL_GPIOName { CC1350_LAUNCHXL_GPIO_LED_RED, CC1350_LAUNCHXL_GPIO_SPI_FLASH_CS, CC1350_LAUNCHXL_SDSPI_CS, - CC1350_LAUNCHXL_GPIO_LCD_CS, - CC1350_LAUNCHXL_GPIO_LCD_POWER, - CC1350_LAUNCHXL_GPIO_LCD_ENABLE, CC1350_LAUNCHXL_GPIOCOUNT } CC1350_LAUNCHXL_GPIOName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.c index 4f1d297a7..a1b74bce4 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.c @@ -334,101 +334,6 @@ const AESECB_Config AESECB_config[CC1352P_2_LAUNCHXL_AESECBCOUNT] = { const uint_least8_t AESECB_count = CC1352P_2_LAUNCHXL_AESECBCOUNT; -/* - * =============================== Display =============================== - */ -#include -#include -#include - -#if TI_DISPLAY_CONF_ENABLE - -#if TI_DISPLAY_CONF_UART_ENABLE - -#if !(TI_UART_CONF_UART0_ENABLE) -#error "Display UART driver requires UART0" -#endif - -#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE -#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 -#endif - -static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; - -DisplayUart_Object displayUartObject; - -const DisplayUart_HWAttrs displayUartHWAttrs = { - .uartIdx = CC1352P_2_LAUNCHXL_UART0, - .baudRate = 115200, - .mutexTimeout = (unsigned int)(-1), - .strBuf = uartStringBuf, - .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, -}; - -#endif /* TI_DISPLAY_CONF_UART_ENABLE */ - -#if TI_DISPLAY_CONF_LCD_ENABLE - -#if !(TI_SPI_CONF_SPI0_ENABLE) -#error "Display LCD driver requires SPI0" -#endif - -#ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 -#endif - -static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; - -DisplaySharp_Object displaySharpObject; - -const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { - .spiIndex = CC1352P_2_LAUNCHXL_SPI0, - .csPin = CC1352P_2_LAUNCHXL_GPIO_LCD_CS, - .powerPin = CC1352P_2_LAUNCHXL_GPIO_DIO_19, - .enablePin = CC1352P_2_LAUNCHXL_GPIO_LCD_ENABLE, - .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, - .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, - .displayBuf = sharpDisplayBuf, -}; - -#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ - -/* - * This #if/#else is needed to workaround a problem with the - * IAR compiler. The IAR compiler doesn't like the empty array - * initialization. (IAR Error[Pe1345]) - */ - -const Display_Config Display_config[] = { -#if TI_DISPLAY_CONF_UART_ENABLE - { -# if TI_DISPLAY_CONF_USE_UART_ANSI - .fxnTablePtr = &DisplayUartAnsi_fxnTable, -# else /* Default to minimal UART with no cursor placement */ - .fxnTablePtr = &DisplayUartMin_fxnTable, -# endif - .object = &displayUartObject, - .hwAttrs = &displayUartHWAttrs, - }, -#endif -#if TI_DISPLAY_CONF_LCD_ENABLE - { - .fxnTablePtr = &DisplaySharp_fxnTable, - .object = &displaySharpObject, - .hwAttrs = &displaySharpHWattrs - }, -#endif -}; - -const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); - -#else - -const Display_Config *Display_config = NULL; -const uint_least8_t Display_count = 0; - -#endif /* TI_DISPLAY_CONF_ENABLE */ - /* * =============================== GPIO =============================== */ @@ -458,17 +363,8 @@ GPIO_PinConfig gpioPinConfigs[] = { /* SPI Flash CSN */ GPIOCC26XX_DIO_20 | GPIO_DO_NOT_CONFIG, - /* - * DIO 19 is used for LCD power control and SD chip select. This is due to - * DIO21 & DIO22 moving on this LaunchPad. DIO 19 can also be used as a - * UART CTS pin. - */ + /* SD CS */ GPIOCC26XX_DIO_19 | GPIO_DO_NOT_CONFIG, - - /* Sharp Display - GPIO configurations will be done in the Display files */ - GPIOCC26XX_DIO_24 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ - GPIOCC26XX_DIO_23 | GPIO_DO_NOT_CONFIG, /*LCD enable */ - }; /* diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h index e81d45aec..40f01ef03 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-2/CC1352P_2_LAUNCHXL.h @@ -296,9 +296,7 @@ typedef enum CC1352P_2_LAUNCHXL_GPIOName { CC1352P_2_LAUNCHXL_GPIO_LED_GREEN, CC1352P_2_LAUNCHXL_GPIO_LED_RED, CC1352P_2_LAUNCHXL_GPIO_SPI_FLASH_CS, - CC1352P_2_LAUNCHXL_GPIO_DIO_19, - CC1352P_2_LAUNCHXL_GPIO_LCD_CS, - CC1352P_2_LAUNCHXL_GPIO_LCD_ENABLE, + CC1352P_2_LAUNCHXL_GPIO_SDSPI_CS, CC1352P_2_LAUNCHXL_GPIOCOUNT } CC1352P_2_LAUNCHXL_GPIOName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.c index bb055fbb4..63a41d64b 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.c @@ -334,101 +334,6 @@ const AESECB_Config AESECB_config[CC1352P_4_LAUNCHXL_AESECBCOUNT] = { const uint_least8_t AESECB_count = CC1352P_4_LAUNCHXL_AESECBCOUNT; -/* - * =============================== Display =============================== - */ -#include -#include -#include - -#if TI_DISPLAY_CONF_ENABLE - -#if TI_DISPLAY_CONF_UART_ENABLE - -#if !(TI_UART_CONF_UART0_ENABLE) -#error "Display UART driver requires UART0" -#endif - -#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE -#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 -#endif - -static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; - -DisplayUart_Object displayUartObject; - -const DisplayUart_HWAttrs displayUartHWAttrs = { - .uartIdx = CC1352P_4_LAUNCHXL_UART0, - .baudRate = 115200, - .mutexTimeout = (unsigned int)(-1), - .strBuf = uartStringBuf, - .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, -}; - -#endif /* TI_DISPLAY_CONF_UART_ENABLE */ - -#if TI_DISPLAY_CONF_LCD_ENABLE - -#if !(TI_SPI_CONF_SPI0_ENABLE) -#error "Display LCD driver requires SPI0" -#endif - -#ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 -#endif - -static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; - -DisplaySharp_Object displaySharpObject; - -const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { - .spiIndex = CC1352P_4_LAUNCHXL_SPI0, - .csPin = CC1352P_4_LAUNCHXL_GPIO_LCD_CS, - .powerPin = CC1352P_4_LAUNCHXL_GPIO_DIO_19, - .enablePin = CC1352P_4_LAUNCHXL_GPIO_LCD_ENABLE, - .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, - .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, - .displayBuf = sharpDisplayBuf, -}; - -#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ - -/* - * This #if/#else is needed to workaround a problem with the - * IAR compiler. The IAR compiler doesn't like the empty array - * initialization. (IAR Error[Pe1345]) - */ - -const Display_Config Display_config[] = { -#if TI_DISPLAY_CONF_UART_ENABLE - { -# if TI_DISPLAY_CONF_USE_UART_ANSI - .fxnTablePtr = &DisplayUartAnsi_fxnTable, -# else /* Default to minimal UART with no cursor placement */ - .fxnTablePtr = &DisplayUartMin_fxnTable, -# endif - .object = &displayUartObject, - .hwAttrs = &displayUartHWAttrs, - }, -#endif -#if TI_DISPLAY_CONF_LCD_ENABLE - { - .fxnTablePtr = &DisplaySharp_fxnTable, - .object = &displaySharpObject, - .hwAttrs = &displaySharpHWattrs - }, -#endif -}; - -const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); - -#else - -const Display_Config *Display_config = NULL; -const uint_least8_t Display_count = 0; - -#endif /* TI_DISPLAY_CONF_ENABLE */ - /* * =============================== GPIO =============================== */ @@ -458,17 +363,8 @@ GPIO_PinConfig gpioPinConfigs[] = { /* SPI Flash CSN */ GPIOCC26XX_DIO_20 | GPIO_DO_NOT_CONFIG, - /* - * DIO 19 is used for LCD power control and SD chip select. This is due to - * DIO21 & DIO22 moving on this LaunchPad. DIO 19 can also be used as a - * UART CTS pin. - */ + /* SD CS */ GPIOCC26XX_DIO_19 | GPIO_DO_NOT_CONFIG, - - /* Sharp Display - GPIO configurations will be done in the Display files */ - GPIOCC26XX_DIO_24 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ - GPIOCC26XX_DIO_23 | GPIO_DO_NOT_CONFIG, /*LCD enable */ - }; /* diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.h index 55baa0037..bce1bb54a 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p-4/CC1352P_4_LAUNCHXL.h @@ -296,9 +296,7 @@ typedef enum CC1352P_4_LAUNCHXL_GPIOName { CC1352P_4_LAUNCHXL_GPIO_LED_GREEN, CC1352P_4_LAUNCHXL_GPIO_LED_RED, CC1352P_4_LAUNCHXL_GPIO_SPI_FLASH_CS, - CC1352P_4_LAUNCHXL_GPIO_DIO_19, - CC1352P_4_LAUNCHXL_GPIO_LCD_CS, - CC1352P_4_LAUNCHXL_GPIO_LCD_ENABLE, + CC1352P_4_LAUNCHXL_GPIO_SDSPI_CS, CC1352P_4_LAUNCHXL_GPIOCOUNT } CC1352P_4_LAUNCHXL_GPIOName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.c index 6fdfc525e..d4f953fba 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.c @@ -334,101 +334,6 @@ const AESECB_Config AESECB_config[CC1352P1_LAUNCHXL_AESECBCOUNT] = { const uint_least8_t AESECB_count = CC1352P1_LAUNCHXL_AESECBCOUNT; -/* - * =============================== Display =============================== - */ -#include -#include -#include - -#if TI_DISPLAY_CONF_ENABLE - -#if TI_DISPLAY_CONF_UART_ENABLE - -#if !(TI_UART_CONF_UART0_ENABLE) -#error "Display UART driver requires UART0" -#endif - -#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE -#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 -#endif - -static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; - -DisplayUart_Object displayUartObject; - -const DisplayUart_HWAttrs displayUartHWAttrs = { - .uartIdx = CC1352P1_LAUNCHXL_UART0, - .baudRate = 115200, - .mutexTimeout = (unsigned int)(-1), - .strBuf = uartStringBuf, - .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, -}; - -#endif /* TI_DISPLAY_CONF_UART_ENABLE */ - -#if TI_DISPLAY_CONF_LCD_ENABLE - -#if !(TI_SPI_CONF_SPI0_ENABLE) -#error "Display LCD driver requires SPI0" -#endif - -#ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 -#endif - -static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; - -DisplaySharp_Object displaySharpObject; - -const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { - .spiIndex = CC1352P1_LAUNCHXL_SPI0, - .csPin = CC1352P1_LAUNCHXL_GPIO_LCD_CS, - .powerPin = CC1352P1_LAUNCHXL_GPIO_DIO_19, - .enablePin = CC1352P1_LAUNCHXL_GPIO_LCD_ENABLE, - .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, - .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, - .displayBuf = sharpDisplayBuf, -}; - -#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ - -/* - * This #if/#else is needed to workaround a problem with the - * IAR compiler. The IAR compiler doesn't like the empty array - * initialization. (IAR Error[Pe1345]) - */ - -const Display_Config Display_config[] = { -#if TI_DISPLAY_CONF_UART_ENABLE - { -# if TI_DISPLAY_CONF_USE_UART_ANSI - .fxnTablePtr = &DisplayUartAnsi_fxnTable, -# else /* Default to minimal UART with no cursor placement */ - .fxnTablePtr = &DisplayUartMin_fxnTable, -# endif - .object = &displayUartObject, - .hwAttrs = &displayUartHWAttrs, - }, -#endif -#if TI_DISPLAY_CONF_LCD_ENABLE - { - .fxnTablePtr = &DisplaySharp_fxnTable, - .object = &displaySharpObject, - .hwAttrs = &displaySharpHWattrs - }, -#endif -}; - -const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); - -#else - -const Display_Config *Display_config = NULL; -const uint_least8_t Display_count = 0; - -#endif /* TI_DISPLAY_CONF_ENABLE */ - /* * =============================== GPIO =============================== */ @@ -458,17 +363,8 @@ GPIO_PinConfig gpioPinConfigs[] = { /* SPI Flash CSN */ GPIOCC26XX_DIO_20 | GPIO_DO_NOT_CONFIG, - /* - * DIO 19 is used for LCD power control and SD chip select. This is due to - * DIO21 & DIO22 moving on this LaunchPad. DIO 19 can also be used as a - * UART CTS pin. - */ + /* SD CS */ GPIOCC26XX_DIO_19 | GPIO_DO_NOT_CONFIG, - - /* Sharp Display - GPIO configurations will be done in the Display files */ - GPIOCC26XX_DIO_24 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ - GPIOCC26XX_DIO_23 | GPIO_DO_NOT_CONFIG, /*LCD enable */ - }; /* diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h index a023cca75..f5fa59fe7 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352p1/CC1352P1_LAUNCHXL.h @@ -300,9 +300,7 @@ typedef enum CC1352P1_LAUNCHXL_GPIOName { CC1352P1_LAUNCHXL_GPIO_LED_GREEN, CC1352P1_LAUNCHXL_GPIO_LED_RED, CC1352P1_LAUNCHXL_GPIO_SPI_FLASH_CS, - CC1352P1_LAUNCHXL_GPIO_DIO_19, - CC1352P1_LAUNCHXL_GPIO_LCD_CS, - CC1352P1_LAUNCHXL_GPIO_LCD_ENABLE, + CC1352P1_LAUNCHXL_GPIO_SDSPI_CS, CC1352P1_LAUNCHXL_GPIOCOUNT } CC1352P1_LAUNCHXL_GPIOName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c index e60b6d73e..a9197a4f5 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.c @@ -358,101 +358,6 @@ const AESECB_Config AESECB_config[CC1352R1_LAUNCHXL_AESECBCOUNT] = { const uint_least8_t AESECB_count = CC1352R1_LAUNCHXL_AESECBCOUNT; -/* - * =============================== Display =============================== - */ -#include -#include -#include - -#if TI_DISPLAY_CONF_ENABLE - -#if TI_DISPLAY_CONF_UART_ENABLE - -#if !(TI_UART_CONF_UART0_ENABLE) -#error "Display UART driver requires UART0" -#endif - -#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE -#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 -#endif - -static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; - -DisplayUart_Object displayUartObject; - -const DisplayUart_HWAttrs displayUartHWAttrs = { - .uartIdx = CC1352R1_LAUNCHXL_UART0, - .baudRate = 115200, - .mutexTimeout = (unsigned int)(-1), - .strBuf = uartStringBuf, - .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, -}; - -#endif /* TI_DISPLAY_CONF_UART_ENABLE */ - -#if TI_DISPLAY_CONF_LCD_ENABLE - -#if !(TI_SPI_CONF_SPI0_ENABLE) -#error "Display LCD driver requires SPI0" -#endif - -#ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 -#endif - -static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; - -DisplaySharp_Object displaySharpObject; - -const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { - .spiIndex = CC1352R1_LAUNCHXL_SPI0, - .csPin = CC1352R1_LAUNCHXL_GPIO_LCD_CS, - .powerPin = CC1352R1_LAUNCHXL_GPIO_LCD_POWER, - .enablePin = CC1352R1_LAUNCHXL_GPIO_LCD_ENABLE, - .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, - .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, - .displayBuf = sharpDisplayBuf, -}; - -#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ - -/* - * This #if/#else is needed to workaround a problem with the - * IAR compiler. The IAR compiler doesn't like the empty array - * initialization. (IAR Error[Pe1345]) - */ - -const Display_Config Display_config[] = { -#if TI_DISPLAY_CONF_UART_ENABLE - { -# if TI_DISPLAY_CONF_USE_UART_ANSI - .fxnTablePtr = &DisplayUartAnsi_fxnTable, -# else /* Default to minimal UART with no cursor placement */ - .fxnTablePtr = &DisplayUartMin_fxnTable, -# endif - .object = &displayUartObject, - .hwAttrs = &displayUartHWAttrs, - }, -#endif -#if TI_DISPLAY_CONF_LCD_ENABLE - { - .fxnTablePtr = &DisplaySharp_fxnTable, - .object = &displaySharpObject, - .hwAttrs = &displaySharpHWattrs - }, -#endif -}; - -const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); - -#else - -const Display_Config *Display_config = NULL; -const uint_least8_t Display_count = 0; - -#endif /* TI_DISPLAY_CONF_ENABLE */ - /* * =============================== GPIO =============================== */ @@ -484,12 +389,6 @@ GPIO_PinConfig gpioPinConfigs[] = { /* SD CS */ GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG, - - /* Sharp Display - GPIO configurations will be done in the Display files */ - GPIOCC26XX_DIO_24 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ - GPIOCC26XX_DIO_22 | GPIO_DO_NOT_CONFIG, /* LCD power control */ - GPIOCC26XX_DIO_23 | GPIO_DO_NOT_CONFIG, /* LCD enable */ - }; /* diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h index 5a0717057..f0d94306b 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc1352r1/CC1352R1_LAUNCHXL.h @@ -292,9 +292,6 @@ typedef enum CC1352R1_LAUNCHXL_GPIOName { CC1352R1_LAUNCHXL_GPIO_LED_RED, CC1352R1_LAUNCHXL_GPIO_SPI_FLASH_CS, CC1352R1_LAUNCHXL_SDSPI_CS, - CC1352R1_LAUNCHXL_GPIO_LCD_CS, - CC1352R1_LAUNCHXL_GPIO_LCD_POWER, - CC1352R1_LAUNCHXL_GPIO_LCD_ENABLE, CC1352R1_LAUNCHXL_GPIOCOUNT } CC1352R1_LAUNCHXL_GPIOName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.c index e201b8e89..ed0a4796e 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.c @@ -246,101 +246,6 @@ const CryptoCC26XX_Config CryptoCC26XX_config[CC2650_LAUNCHXL_CRYPTOCOUNT] = { }, }; -/* - * =============================== Display =============================== - */ -#include -#include -#include - -#if TI_DISPLAY_CONF_ENABLE - -#if TI_DISPLAY_CONF_UART_ENABLE - -#if !(TI_UART_CONF_UART0_ENABLE) -#error "Display UART driver requires UART0" -#endif - -#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE -#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 -#endif - -static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; - -DisplayUart_Object displayUartObject; - -const DisplayUart_HWAttrs displayUartHWAttrs = { - .uartIdx = CC2650_LAUNCHXL_UART0, - .baudRate = 115200, - .mutexTimeout = (unsigned int)(-1), - .strBuf = uartStringBuf, - .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, -}; - -#endif /* TI_DISPLAY_CONF_UART_ENABLE */ - -#if TI_DISPLAY_CONF_LCD_ENABLE - -#if !(TI_SPI_CONF_SPI0_ENABLE) -#error "Display LCD driver requires SPI0" -#endif - -#ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 -#endif - -static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; - -DisplaySharp_Object displaySharpObject; - -const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { - .spiIndex = CC2650_LAUNCHXL_SPI0, - .csPin = CC2650_LAUNCHXL_GPIO_LCD_CS, - .powerPin = CC2650_LAUNCHXL_GPIO_LCD_POWER, - .enablePin = CC2650_LAUNCHXL_GPIO_LCD_ENABLE, - .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, - .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, - .displayBuf = sharpDisplayBuf, -}; - -#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ - -/* - * This #if/#else is needed to workaround a problem with the - * IAR compiler. The IAR compiler doesn't like the empty array - * initialization. (IAR Error[Pe1345]) - */ - -const Display_Config Display_config[] = { -#if TI_DISPLAY_CONF_UART_ENABLE - { -# if TI_DISPLAY_CONF_USE_UART_ANSI - .fxnTablePtr = &DisplayUartAnsi_fxnTable, -# else /* Default to minimal UART with no cursor placement */ - .fxnTablePtr = &DisplayUartMin_fxnTable, -# endif - .object = &displayUartObject, - .hwAttrs = &displayUartHWAttrs, - }, -#endif -#if TI_DISPLAY_CONF_LCD_ENABLE - { - .fxnTablePtr = &DisplaySharp_fxnTable, - .object = &displaySharpObject, - .hwAttrs = &displaySharpHWattrs - }, -#endif -}; - -const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); - -#else - -const Display_Config *Display_config = NULL; -const uint_least8_t Display_count = 0; - -#endif /* TI_DISPLAY_CONF_ENABLE */ - /* * =============================== GPIO =============================== */ @@ -372,12 +277,6 @@ GPIO_PinConfig gpioPinConfigs[] = { /* SD CS */ GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG, - - /* Sharp Display - GPIO configurations will be done in the Display files */ - GPIOCC26XX_DIO_24 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ - GPIOCC26XX_DIO_22 | GPIO_DO_NOT_CONFIG, /* LCD power control */ - GPIOCC26XX_DIO_23 | GPIO_DO_NOT_CONFIG, /*LCD enable */ - }; /* diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h index f344e79bc..90bf27d38 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc2650/CC2650_LAUNCHXL.h @@ -229,9 +229,6 @@ typedef enum CC2650_LAUNCHXL_GPIOName { CC2650_LAUNCHXL_GPIO_LED_RED, CC2650_LAUNCHXL_GPIO_SPI_FLASH_CS, CC2650_LAUNCHXL_SDSPI_CS, - CC2650_LAUNCHXL_GPIO_LCD_CS, - CC2650_LAUNCHXL_GPIO_LCD_POWER, - CC2650_LAUNCHXL_GPIO_LCD_ENABLE, CC2650_LAUNCHXL_GPIOCOUNT } CC2650_LAUNCHXL_GPIOName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c index 6fb5e357f..db47744de 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.c @@ -368,102 +368,6 @@ const AESECB_Config AESECB_config[CC26X2R1_LAUNCHXL_AESECBCOUNT] = { const uint_least8_t AESECB_count = CC26X2R1_LAUNCHXL_AESECBCOUNT; - -/* - * =============================== Display =============================== - */ -#include -#include -#include - -#if TI_DISPLAY_CONF_ENABLE - -#if TI_DISPLAY_CONF_UART_ENABLE - -#if !(TI_UART_CONF_UART0_ENABLE) -#error "Display UART driver requires UART0" -#endif - -#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE -#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 -#endif - -static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; - -DisplayUart_Object displayUartObject; - -const DisplayUart_HWAttrs displayUartHWAttrs = { - .uartIdx = CC26X2R1_LAUNCHXL_UART0, - .baudRate = 115200, - .mutexTimeout = (unsigned int)(-1), - .strBuf = uartStringBuf, - .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, -}; - -#endif /* TI_DISPLAY_CONF_UART_ENABLE */ - -#if TI_DISPLAY_CONF_LCD_ENABLE - -#if !(TI_SPI_CONF_SPI0_ENABLE) -#error "Display LCD driver requires SPI0" -#endif - -#ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 -#endif - -static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; - -DisplaySharp_Object displaySharpObject; - -const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { - .spiIndex = CC26X2R1_LAUNCHXL_SPI0, - .csPin = CC26X2R1_LAUNCHXL_GPIO_LCD_CS, - .powerPin = CC26X2R1_LAUNCHXL_GPIO_LCD_POWER, - .enablePin = CC26X2R1_LAUNCHXL_GPIO_LCD_ENABLE, - .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, - .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, - .displayBuf = sharpDisplayBuf, -}; - -#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ - -/* - * This #if/#else is needed to workaround a problem with the - * IAR compiler. The IAR compiler doesn't like the empty array - * initialization. (IAR Error[Pe1345]) - */ - -const Display_Config Display_config[] = { -#if TI_DISPLAY_CONF_UART_ENABLE - { -# if TI_DISPLAY_CONF_USE_UART_ANSI - .fxnTablePtr = &DisplayUartAnsi_fxnTable, -# else /* Default to minimal UART with no cursor placement */ - .fxnTablePtr = &DisplayUartMin_fxnTable, -# endif - .object = &displayUartObject, - .hwAttrs = &displayUartHWAttrs, - }, -#endif -#if TI_DISPLAY_CONF_LCD_ENABLE - { - .fxnTablePtr = &DisplaySharp_fxnTable, - .object = &displaySharpObject, - .hwAttrs = &displaySharpHWattrs - }, -#endif -}; - -const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); - -#else - -const Display_Config *Display_config = NULL; -const uint_least8_t Display_count = 0; - -#endif /* TI_DISPLAY_CONF_ENABLE */ - /* * =============================== GPIO =============================== */ @@ -495,12 +399,6 @@ GPIO_PinConfig gpioPinConfigs[] = { /* SD CS */ GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG, - - /* Sharp Display - GPIO configurations will be done in the Display files */ - GPIOCC26XX_DIO_24 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ - GPIOCC26XX_DIO_22 | GPIO_DO_NOT_CONFIG, /* LCD power control */ - GPIOCC26XX_DIO_23 | GPIO_DO_NOT_CONFIG, /*LCD enable */ - }; /* diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h index 6af14329b..040d9fb50 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/cc26x2r1/CC26X2R1_LAUNCHXL.h @@ -294,9 +294,6 @@ typedef enum CC26X2R1_LAUNCHXL_GPIOName { CC26X2R1_LAUNCHXL_GPIO_LED_RED, CC26X2R1_LAUNCHXL_GPIO_SPI_FLASH_CS, CC26X2R1_LAUNCHXL_SDSPI_CS, - CC26X2R1_LAUNCHXL_GPIO_LCD_CS, - CC26X2R1_LAUNCHXL_GPIO_LCD_POWER, - CC26X2R1_LAUNCHXL_GPIO_LCD_ENABLE, CC26X2R1_LAUNCHXL_GPIOCOUNT } CC26X2R1_LAUNCHXL_GPIOName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.c index 6f9f68e20..de15954f0 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.c @@ -74,102 +74,6 @@ const CryptoCC26XX_Config CryptoCC26XX_config[CC1350STK_CRYPTOCOUNT] = { } }; -/* - * =============================== Display =============================== - */ -#include -#include -#include - -#if TI_DISPLAY_CONF_ENABLE - -#if TI_DISPLAY_CONF_UART_ENABLE - -#if !(TI_UART_CONF_UART0_ENABLE) -#error "Display UART driver requires UART0" -#endif - -#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE -#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 -#endif - -static char uartStringBuf[CC1350STK_DISPLAY_UART_STRBUF_SIZE]; - -DisplayUart_Object displayUartObject; - -const DisplayUart_HWAttrs displayUartHWAttrs = { - .uartIdx = CC1350STK_UART0, - .baudRate = 115200, - .mutexTimeout = (unsigned int)(-1), - .strBuf = uartStringBuf, - .strBufLen = CC1350STK_DISPLAY_UART_STRBUF_SIZE, -}; - -#endif /* TI_DISPLAY_CONF_UART_ENABLE */ - -#if TI_DISPLAY_CONF_LCD_ENABLE - -#if !(TI_SPI_CONF_SPI0_ENABLE) -#error "Display LCD driver requires SPI0" -#endif - -#ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 -#endif - -static uint_least8_t sharpDisplayBuf[CC1350STK_DISPLAY_SHARP_SIZE * CC1350STK_DISPLAY_SHARP_SIZE / 8]; - -DisplaySharp_Object displaySharpObject; - -const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { - .spiIndex = CC1350STK_SPI0, - .csPin = CC1350STK_GPIO_LCD_CS, - .powerPin = (uint32_t)(-1), /* no need to apply power for this LCD */ - .enablePin = CC1350STK_GPIO_LCD_ENABLE, - .pixelWidth = CC1350STK_DISPLAY_SHARP_SIZE, - .pixelHeight = CC1350STK_DISPLAY_SHARP_SIZE, - .displayBuf = sharpDisplayBuf, -}; - -#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ - -/* - * This #if/#else is needed to workaround a problem with the - * IAR compiler. The IAR compiler doesn't like the empty array - * initialization. (IAR Error[Pe1345]) - */ - -const Display_Config Display_config[] = { -#if TI_DISPLAY_CONF_UART_ENABLE - { -# if TI_DISPLAY_CONF_USE_UART_ANSI - .fxnTablePtr = &DisplayUartAnsi_fxnTable, -# else /* Default to minimal UART with no cursor placement */ - .fxnTablePtr = &DisplayUartMin_fxnTable, -# endif - .fxnTablePtr = &DisplayUart_fxnTable, - .object = &displayUartObject, - .hwAttrs = &displayUartHWAttrs, - }, -#endif -#if TI_DISPLAY_CONF_LCD_ENABLE - { - .fxnTablePtr = &DisplaySharp_fxnTable, - .object = &displaySharpObject, - .hwAttrs = &displaySharpHWattrs - }, -#endif -}; - -const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); - -#else - -const Display_Config *Display_config = NULL; -const uint_least8_t Display_count = 0; - -#endif /* TI_DISPLAY_CONF_ENABLE */ - /* * =============================== GPIO =============================== */ @@ -194,10 +98,6 @@ GPIO_PinConfig gpioPinConfigs[] = { /* SPI Flash CSN */ GPIOCC26XX_DIO_14 | GPIO_DO_NOT_CONFIG, - - /* Sharp Display - GPIO configurations will be done in the Display files */ - GPIOCC26XX_DIO_20 | GPIO_DO_NOT_CONFIG, /* LCD CS */ - GPIOCC26XX_DIO_29 | GPIO_DO_NOT_CONFIG, /* LCD Enable */ }; /* diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.h index 2a6f4bde9..dae1c7739 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc1350/CC1350STK.h @@ -194,8 +194,6 @@ typedef enum CC1350STK_GPIOName { CC1350STK_GPIO_S2, CC1350STK_GPIO_LED0, CC1350STK_GPIO_SPI_FLASH_CS, - CC1350STK_GPIO_LCD_CS, - CC1350STK_GPIO_LCD_ENABLE, CC1350STK_GPIOCOUNT } CC1350STK_GPIOName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.c b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.c index b267075e5..7b16c58ee 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.c @@ -74,102 +74,6 @@ const CryptoCC26XX_Config CryptoCC26XX_config[CC2650STK_CRYPTOCOUNT] = { } }; -/* - * =============================== Display =============================== - */ -#include -#include -#include - -#if TI_DISPLAY_CONF_ENABLE - -#if TI_DISPLAY_CONF_UART_ENABLE - -#if !(TI_UART_CONF_UART0_ENABLE) -#error "Display UART driver requires UART0" -#endif - -#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE -#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 -#endif - -static char uartStringBuf[CC2650STK_DISPLAY_UART_STRBUF_SIZE]; - -DisplaySharp_Object displaySharpObject; - -const DisplayUart_HWAttrs displayUartHWAttrs = { - .uartIdx = CC2650STK_UART0, - .baudRate = 115200, - .mutexTimeout = (unsigned int)(-1), - .strBuf = uartStringBuf, - .strBufLen = CC2650STK_DISPLAY_UART_STRBUF_SIZE, -}; - -#endif /* TI_DISPLAY_CONF_UART_ENABLE */ - -#if TI_DISPLAY_CONF_LCD_ENABLE - -#if !(TI_SPI_CONF_SPI0_ENABLE) -#error "Display LCD driver requires SPI0" -#endif - -#ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 -#endif - -static uint_least8_t sharpDisplayBuf[CC2650STK_DISPLAY_SHARP_SIZE * CC2650STK_DISPLAY_SHARP_SIZE / 8]; - -DisplayUart_Object displayUartObject; - -const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { - .spiIndex = CC2650STK_SPI0, - .csPin = CC2650STK_GPIO_LCD_CS, - .powerPin = (uint32_t)(-1), /* no need to apply power for this LCD */ - .enablePin = CC2650STK_GPIO_LCD_ENABLE, - .pixelWidth = CC2650STK_DISPLAY_SHARP_SIZE, - .pixelHeight = CC2650STK_DISPLAY_SHARP_SIZE, - .displayBuf = sharpDisplayBuf, -}; - -#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ - -/* - * This #if/#else is needed to workaround a problem with the - * IAR compiler. The IAR compiler doesn't like the empty array - * initialization. (IAR Error[Pe1345]) - */ - -const Display_Config Display_config[] = { -#if TI_DISPLAY_CONF_UART_ENABLE - { -# if TI_DISPLAY_CONF_USE_UART_ANSI - .fxnTablePtr = &DisplayUartAnsi_fxnTable, -# else /* Default to minimal UART with no cursor placement */ - .fxnTablePtr = &DisplayUartMin_fxnTable, -# endif - .fxnTablePtr = &DisplayUart_fxnTable, - .object = &displayUartObject, - .hwAttrs = &displayUartHWAttrs, - }, -#endif -#if TI_DISPLAY_CONF_LCD_ENABLE - { - .fxnTablePtr = &DisplaySharp_fxnTable, - .object = &displaySharpObject, - .hwAttrs = &displaySharpHWattrs - }, -#endif -}; - -const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); - -#else - -const Display_Config *Display_config = NULL; -const uint_least8_t Display_count = 0; - -#endif /* TI_DISPLAY_CONF_ENABLE */ - /* * =============================== GPIO =============================== */ @@ -194,10 +98,6 @@ GPIO_PinConfig gpioPinConfigs[] = { /* SPI Flash CSN */ GPIOCC26XX_DIO_14 | GPIO_DO_NOT_CONFIG, - - /* Sharp Display - GPIO configurations will be done in the Display files */ - GPIOCC26XX_DIO_20 | GPIO_DO_NOT_CONFIG, /* LCD CS */ - GPIOCC26XX_DIO_29 | GPIO_DO_NOT_CONFIG, /* LCD Enable */ }; /* diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h index 8ec745f45..8dc1a9326 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/cc2650/CC2650STK.h @@ -195,8 +195,6 @@ typedef enum CC2650STK_GPIOName { CC2650STK_GPIO_S2, CC2650STK_GPIO_LED0, CC2650STK_GPIO_SPI_FLASH_CS, - CC2650STK_GPIO_LCD_CS, - CC2650STK_GPIO_LCD_ENABLE, CC2650STK_GPIOCOUNT } CC2650STK_GPIOName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c index ab1a4db22..f9e1f8fe5 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.c @@ -169,101 +169,6 @@ const CryptoCC26XX_Config CryptoCC26XX_config[CC1350DK_7XD_CRYPTOCOUNT] = { }, }; -/* - * =============================== Display =============================== - */ -#include -#include -#include - -#if TI_DISPLAY_CONF_ENABLE - -#if TI_DISPLAY_CONF_UART_ENABLE - -#if !(TI_UART_CONF_UART0_ENABLE) -#error "Display UART driver requires UART0" -#endif - -#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE -#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 -#endif - -static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; - -DisplayUart_Object displayUartObject; - -const DisplayUart_HWAttrs displayUartHWAttrs = { - .uartIdx = CC1350DK_7XD_UART0, - .baudRate = 115200, - .mutexTimeout = (unsigned int)(-1), - .strBuf = uartStringBuf, - .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, -}; - -#endif /* TI_DISPLAY_CONF_UART_ENABLE */ - -#if TI_DISPLAY_CONF_LCD_ENABLE - -#if !(TI_SPI_CONF_SPI0_ENABLE) -#error "Display LCD driver requires SPI0" -#endif - -#ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 -#endif - -static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; - -DisplaySharp_Object displaySharpObject; - -const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { - .spiIndex = CC1350DK_7XD_SPI0, - .csPin = CC1350DK_7XD_GPIO_LCD_CS, - .powerPin = CC1350DK_7XD_GPIO_LCD_POWER, - .enablePin = CC1350DK_7XD_GPIO_LCD_ENABLE, - .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, - .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, - .displayBuf = sharpDisplayBuf, -}; - -#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ - -/* - * This #if/#else is needed to workaround a problem with the - * IAR compiler. The IAR compiler doesn't like the empty array - * initialization. (IAR Error[Pe1345]) - */ - -const Display_Config Display_config[] = { -#if TI_DISPLAY_CONF_UART_ENABLE - { -# if TI_DISPLAY_CONF_USE_UART_ANSI - .fxnTablePtr = &DisplayUartAnsi_fxnTable, -# else /* Default to minimal UART with no cursor placement */ - .fxnTablePtr = &DisplayUartMin_fxnTable, -# endif - .object = &displayUartObject, - .hwAttrs = &displayUartHWAttrs, - }, -#endif -#if TI_DISPLAY_CONF_LCD_ENABLE - { - .fxnTablePtr = &DisplaySharp_fxnTable, - .object = &displaySharpObject, - .hwAttrs = &displaySharpHWattrs - }, -#endif -}; - -const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); - -#else - -const Display_Config *Display_config = NULL; -const uint_least8_t Display_count = 0; - -#endif /* TI_DISPLAY_CONF_ENABLE */ - /* * =============================== GPIO =============================== */ @@ -300,12 +205,6 @@ GPIO_PinConfig gpioPinConfigs[] = { /* Accelerometer */ GPIOCC26XX_DIO_24 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ - - /* Sharp Display - GPIO configurations will be done in the Display files */ - GPIOCC26XX_DIO_14 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ - GPIOCC26XX_DIO_05 | GPIO_DO_NOT_CONFIG, /* LCD power control */ - GPIOCC26XX_DIO_04 | GPIO_DO_NOT_CONFIG, /* LCD enable */ - }; /* diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h index d9d3fc63e..b531041cb 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc13x0/CC1350DK_7XD.h @@ -138,11 +138,6 @@ extern const PIN_Config BoardGpioInitTable[]; /* SD Card */ #define CC1350DK_7XD_SDCARD_CS IOID_30 -/* LCD Board */ -#define CC1350DK_7XD_LCD_MODE IOID_4 -#define CC1350DK_7XD_LCD_RST IOID_5 -#define CC1350DK_7XD_LCD_CS IOID_14 - /* Ambient Light Sensor */ #define CC1350DK_7XD_ALS_OUT IOID_23 #define CC1350DK_7XD_ALS_PWR IOID_26 @@ -236,9 +231,6 @@ typedef enum CC1350DK_7XD_GPIOName { CC1350DK_7XD_GPIO_LED4, CC1350DK_7XD_GPIO_SDCARD_CS, CC1350DK_7XD_GPIO_ACC_CS, - CC1350DK_7XD_GPIO_LCD_CS, - CC1350DK_7XD_GPIO_LCD_POWER, - CC1350DK_7XD_GPIO_LCD_ENABLE, CC1350DK_7XD_GPIOCOUNT } CC1350DK_7XD_GPIOName; diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c index 7689793a2..1f7ed1ab1 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.c @@ -169,101 +169,6 @@ const CryptoCC26XX_Config CryptoCC26XX_config[CC2650DK_7ID_CRYPTOCOUNT] = { }, }; -/* - * =============================== Display =============================== - */ -#include -#include -#include - -#if TI_DISPLAY_CONF_ENABLE - -#if TI_DISPLAY_CONF_UART_ENABLE - -#if !(TI_UART_CONF_UART0_ENABLE) -#error "Display UART driver requires UART0" -#endif - -#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE -#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 -#endif - -static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; - -DisplayUart_Object displayUartObject; - -const DisplayUart_HWAttrs displayUartHWAttrs = { - .uartIdx = CC2650DK_7ID_UART0, - .baudRate = 115200, - .mutexTimeout = (unsigned int)(-1), - .strBuf = uartStringBuf, - .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, -}; - -#endif /* TI_DISPLAY_CONF_UART_ENABLE */ - -#if TI_DISPLAY_CONF_LCD_ENABLE - -#if !(TI_SPI_CONF_SPI0_ENABLE) -#error "Display LCD driver requires SPI0" -#endif - -#ifndef BOARD_DISPLAY_SHARP_SIZE -#define BOARD_DISPLAY_SHARP_SIZE 96 -#endif - -static uint_least8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; - -DisplaySharp_Object displaySharpObject; - -const DisplaySharp_HWAttrsV1 displaySharpHWattrs = { - .spiIndex = CC2650DK_7ID_SPI0, - .csPin = CC2650DK_7ID_GPIO_LCD_CS, - .powerPin = CC2650DK_7ID_GPIO_LCD_POWER, - .enablePin = CC2650DK_7ID_GPIO_LCD_ENABLE, - .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, - .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, - .displayBuf = sharpDisplayBuf, -}; - -#endif /* TI_DISPLAY_CONF_LCD_ENABLE */ - -/* - * This #if/#else is needed to workaround a problem with the - * IAR compiler. The IAR compiler doesn't like the empty array - * initialization. (IAR Error[Pe1345]) - */ - -const Display_Config Display_config[] = { -#if TI_DISPLAY_CONF_UART_ENABLE - { -# if TI_DISPLAY_CONF_USE_UART_ANSI - .fxnTablePtr = &DisplayUartAnsi_fxnTable, -# else /* Default to minimal UART with no cursor placement */ - .fxnTablePtr = &DisplayUartMin_fxnTable, -# endif - .object = &displayUartObject, - .hwAttrs = &displayUartHWAttrs, - }, -#endif -#if TI_DISPLAY_CONF_LCD_ENABLE - { - .fxnTablePtr = &DisplaySharp_fxnTable, - .object = &displaySharpObject, - .hwAttrs = &displaySharpHWattrs - }, -#endif -}; - -const uint_least8_t Display_count = sizeof(Display_config) / sizeof(Display_Config); - -#else - -const Display_Config *Display_config = NULL; -const uint_least8_t Display_count = 0; - -#endif /* TI_DISPLAY_CONF_ENABLE */ - /* * =============================== GPIO =============================== */ @@ -300,12 +205,6 @@ GPIO_PinConfig gpioPinConfigs[] = { /* Accelerometer */ GPIOCC26XX_DIO_24 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ - - /* Sharp Display - GPIO configurations will be done in the Display files */ - GPIOCC26XX_DIO_14 | GPIO_DO_NOT_CONFIG, /* SPI chip select */ - GPIOCC26XX_DIO_05 | GPIO_DO_NOT_CONFIG, /* LCD power control */ - GPIOCC26XX_DIO_04 | GPIO_DO_NOT_CONFIG, /* LCD enable */ - }; /* diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h index 356b50fc0..a48531407 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/cc26x0/CC2650DK_7ID.h @@ -138,11 +138,6 @@ extern const PIN_Config BoardGpioInitTable[]; /* SD Card */ #define CC2650DK_7ID_SDCARD_CS IOID_30 -/* LCD Board */ -#define CC2650DK_7ID_LCD_MODE IOID_4 -#define CC2650DK_7ID_LCD_RST IOID_5 -#define CC2650DK_7ID_LCD_CS IOID_14 - /* Ambient Light Sensor */ #define CC2650DK_7ID_ALS_OUT IOID_23 #define CC2650DK_7ID_ALS_PWR IOID_26 @@ -236,9 +231,6 @@ typedef enum CC2650DK_7ID_GPIOName { CC2650DK_7ID_GPIO_LED4, CC2650DK_7ID_GPIO_SDCARD_CS, CC2650DK_7ID_GPIO_ACC_CS, - CC2650DK_7ID_GPIO_LCD_CS, - CC2650DK_7ID_GPIO_LCD_POWER, - CC2650DK_7ID_GPIO_LCD_ENABLE, CC2650DK_7ID_GPIOCOUNT } CC2650DK_7ID_GPIOName; From ee0a4df7bf62a9ab3e4958fc001147b805f977fb Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Tue, 24 Jul 2018 18:27:49 +0200 Subject: [PATCH 292/485] Cleanup in Makefiles --- arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 42 ++++++++++--------- arch/platform/simplelink/Makefile.simplelink | 18 ++++---- .../cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 9 +--- .../cc13xx-cc26xx/custom/Makefile.custom | 15 ++----- .../launchpad/Makefile.launchpad | 4 +- .../sensortag/Makefile.sensortag | 4 +- .../cc13xx-cc26xx/srf06/Makefile.srf06 | 4 +- 7 files changed, 38 insertions(+), 58 deletions(-) diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index 2b9331c2b..5a4d6aee3 100644 --- a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -1,6 +1,8 @@ ################################################################################ # CC13x2/CC26x2 CPU makefile +PRE_RTM = 1 + # Core SDK is placed as a submodule under the arch/cpu/cc13xx-cc26xx/lib. # Do a sanity check that Core SDK submodule has been initialized. # Note that Core SDK can be overriden with a user-specified SimpleLink SDK. @@ -37,8 +39,8 @@ DEVICE_FAMILY_H := $(CORE_SDK)/source/ti/devices/DeviceFamily.h # We are interested in the right-hand side of the define, i.e. the third word on the line, # as it either defines a number or an another Device Family ID. DEVICE_DEFINE := $(shell cat $(DEVICE_FAMILY_H) \ - | grep "\#define DeviceFamily_ID_$(DEVICE_FAMILY)\\b" \ - | awk '{print $$3}') + | grep "\#define DeviceFamily_ID_$(DEVICE_FAMILY)\\b" \ + | awk '{print $$3}') # If the define is a number, then the device family name is the resulting device name; # Else, it points to a sub-name of the device family, e.g. DeviceFamily_ID_CC13X2_V1. @@ -48,19 +50,19 @@ DEVICE_DEFINE := $(shell cat $(DEVICE_FAMILY_H) \ IS_NUMBER := $(shell [ "$(DEVICE_DEFINE)" -eq "$(DEVICE_DEFINE)" ] 2>/dev/null; echo $$?) ifeq ($(IS_NUMBER),0) - # The define points to a number, meaning the device family name is the same as the - # specified device name in lower case, e.g. - # cc13x2 - DEVICE_FAMILY_NAME := $(DEVICE_FAMILY_LC) + # The define points to a number, meaning the device family name is the same as the + # specified device name in lower case, e.g. + # cc13x2 + DEVICE_FAMILY_NAME := $(DEVICE_FAMILY_LC) else - # The define points to a sub-name of the device family. The resulting device family name - # is therefore the name after specified after ID in lower case, e.g. - # DeviceFamily_ID_CC13X2_V1 - # will result in - # cc13x2_v1 - DEVICE_FAMILY_NAME := $(shell echo "$(DEVICE_DEFINE)" \ - | sed -E "s/DeviceFamily_ID_(.+)/\1/" \ - | tr A-Z a-z) + # The define points to a sub-name of the device family. The resulting device family name + # is therefore the name after specified after ID in lower case, e.g. + # DeviceFamily_ID_CC13X2_V1 + # will result in + # cc13x2_v1 + DEVICE_FAMILY_NAME := $(shell echo "$(DEVICE_DEFINE)" \ + | sed -E "s/DeviceFamily_ID_(.+)/\1/" \ + | tr A-Z a-z) endif # The DeviceFamily_constructPath() macro in DeviceFamily.h will always construct the @@ -68,9 +70,9 @@ endif # root path. Note that the returned path is encased in angular brackets, <...>, # and is therefore extracted with sed. SDK_DEVICE_DIR := $(shell echo "DeviceFamily_constructPath(dummy)" \ - | arm-none-eabi-cpp -x c -E -DDeviceFamily_$(DEVICE_FAMILY) -include $(DEVICE_FAMILY_H) - \ - | tail -1 \ - | sed -E 's:<(.+)/dummy>:\1:') + | arm-none-eabi-cpp -x c -E -DDeviceFamily_$(DEVICE_FAMILY) -include $(DEVICE_FAMILY_H) - \ + | tail -1 \ + | sed -E 's:<(.+)/dummy>:\1:') ################################################################################ # Simplelink SDK paths @@ -100,15 +102,15 @@ CONTIKI_CPU_SOURCEFILES += ieee-addr.c ble-addr.c CONTIKI_CPU_SOURCEFILES += ble-beacond.c ifeq ($(SUPPORTS_PROP_MODE),1) -CONTIKI_CPU_SOURCEFILES += prop-mode.c prop-settings.c prop-tx-power.c + CONTIKI_CPU_SOURCEFILES += prop-mode.c prop-settings.c prop-tx-power.c endif ifeq ($(SUPPORTS_IEEE_MODE),1) -CONTIKI_CPU_SOURCEFILES += ieee-mode.c ieee-settings.c ieee-tx-power.c + CONTIKI_CPU_SOURCEFILES += ieee-mode.c ieee-settings.c ieee-tx-power.c endif ifeq ($(SUPPORTS_BLE_BEACON),1) -CONTIKI_CPU_SOURCEFILES += ble-settings.c ble-tx-power.c + CONTIKI_CPU_SOURCEFILES += ble-settings.c ble-tx-power.c endif ### CPU-dependent debug source files diff --git a/arch/platform/simplelink/Makefile.simplelink b/arch/platform/simplelink/Makefile.simplelink index 250d034a0..265bd2c01 100644 --- a/arch/platform/simplelink/Makefile.simplelink +++ b/arch/platform/simplelink/Makefile.simplelink @@ -8,10 +8,6 @@ ifndef CONTIKI $(error 'CONTIKI' not defined! You must specify where CONTIKI resides!) endif -ifndef FAMILY - $(error 'FAMILY' not defined! You must specify which Simplelink family you are using!) -endif - ifndef BOARD $(error 'BOARD' not defined! You must specify which board you are using!) endif @@ -19,12 +15,16 @@ endif ################################################################################ ### Defines -SIMPLELINK_SDK := $(realpath $(SIMPLELINK_SDK)) +SIMPLELINK_FAMILIES := cc13xx-cc26xx -SUPPORTED_FAMILIES := cc13xx-cc26xx +# Given a SimpleLink family as argument, check if it has the Board file and if so return itself. +verify_family = $(shell [ -d $(CONTIKI)/arch/platform/simplelink/$(1)/$(BOARD) ] && echo $(1)) -ifeq ($(filter $(FAMILY), $(SUPPORTED_FAMILIES)),) - $(error Simlpelink Family $(FAMILY) is not supported.) +# Test each supported SimpleLink family and see if it contains the specified Board. +# Throw an error if it isn't found. +FAMILY := $(firstword $(foreach FAMILY, $(SIMPLELINK_FAMILIES), $(call verify_family,$(FAMILY)))) +ifeq ($(FAMILY),) + $(error Board '$(BOARD)' does not corresponding to any SimpleLink family. Make sure your BOARD variable is correct.) endif FAMILY_PATH := $(realpath $(CONTIKI)/arch/platform/simplelink/$(FAMILY)) @@ -37,4 +37,4 @@ include $(FAMILY_PATH)/Makefile.$(FAMILY) ################################################################################ # Display all supported SimpleLink Families simplelink_families: - @echo "$(SUPPORTED_FAMILIES) (current: $(FAMILY))" + @echo "$(SIMPLELINK_FAMILIES) (current: $(FAMILY))" diff --git a/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index 5e9904fe7..9d696263f 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -7,13 +7,7 @@ BOARD_PLATFORMS = launchpad sensortag srf06 # Assigned lazily to avoid breaking environments which doesn't have cd and find BOARDS := $(foreach BOARD_TYPE, $(BOARD_PLATFORMS), \ - $(shell cd $(FAMILY_PATH); find $(BOARD_TYPE)/* -type d -print)) - -BOARD_EXISTS := $(shell [ -d "$(FAMILY_PATH)/$(BOARD)" ]; echo $$?) - -ifneq ($(BOARD_EXISTS),0) - $(error Simplelink Board '$(BOARD)' is not supported for Simplelink Family '$(FAMILY)') -endif + $(shell cd $(FAMILY_PATH); find $(BOARD_TYPE)/* -type d -print)) ################################################################################ # Directory and source configurations @@ -35,7 +29,6 @@ DEFINES += DeviceFamily_$(DEVICE_FAMILY) DEFINES += DEVICE_LINE_$(DEVICE_LINE) DEFINES += DEVICE_$(DEVICE) DEFINES += $(BOARD_TYPE) -DEFINES += PLATFORM_HAS_BUTTON=$(PLATFORM_HAS_BUTTON) DEFINES += SUPPORTS_PROP_MODE=$(SUPPORTS_PROP_MODE) DEFINES += SUPPORTS_IEEE_MODE=$(SUPPORTS_IEEE_MODE) DEFINES += SUPPORTS_BLE_BEACON=$(SUPPORTS_BLE_BEACON) diff --git a/arch/platform/simplelink/cc13xx-cc26xx/custom/Makefile.custom b/arch/platform/simplelink/cc13xx-cc26xx/custom/Makefile.custom index 31da88d0a..0b953bea8 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/custom/Makefile.custom +++ b/arch/platform/simplelink/cc13xx-cc26xx/custom/Makefile.custom @@ -1,15 +1,6 @@ ################################################################################ -# SimpleLink LaunchPad makefile +# SimpleLink Custom makefile -BOARD_TYPE = BOARD_SENSORTAG +BOARD_TYPE = BOARD_CUSTOM -PLATFORM_HAS_BUTTON = 1 - -# leds-arch.c/h etc. -BOARD_SOURCEFILES += sensortag-sensors.c -BOARD_SOURCEFILES += button-sensor-arch.c ext-flash.c -BOARD_SOURCEFILES += bmp-280-sensor.c hdc-1000-sensor.c -BOARD_SOURCEFILES += mpu-9250-sensor.c opt-3001-sensor.c -BOARD_SOURCEFILES += tmp-007-sensor.c buzzer.c - -TARGET_FAMILY_DIRS += sensortag \ No newline at end of file +TARGET_FAMILY_DIRS += custom diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/Makefile.launchpad b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/Makefile.launchpad index 6dabff9bf..66ac2df24 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/Makefile.launchpad +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/Makefile.launchpad @@ -3,9 +3,7 @@ BOARD_TYPE = BOARD_LAUNCHPAD -PLATFORM_HAS_BUTTON = 1 - -# leds-arch.c/h etc. +# leds-arch.c etc. BOARD_SOURCEFILES += button-sensor-arch.c leds-arch.c TARGET_FAMILY_DIRS += launchpad diff --git a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/Makefile.sensortag b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/Makefile.sensortag index fe6156ea7..cdb55c48f 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/sensortag/Makefile.sensortag +++ b/arch/platform/simplelink/cc13xx-cc26xx/sensortag/Makefile.sensortag @@ -3,9 +3,7 @@ BOARD_TYPE = BOARD_SENSORTAG -PLATFORM_HAS_BUTTON = 1 - -# leds-arch.c/h etc. +# leds-arch.c etc. BOARD_SOURCEFILES += sensortag-sensors.c BOARD_SOURCEFILES += button-sensor-arch.c BOARD_SOURCEFILES += bmp-280-sensor.c hdc-1000-sensor.c diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/Makefile.srf06 b/arch/platform/simplelink/cc13xx-cc26xx/srf06/Makefile.srf06 index b15d7db32..500b8414d 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/Makefile.srf06 +++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/Makefile.srf06 @@ -3,9 +3,7 @@ BOARD_TYPE = BOARD_SRF06 -PLATFORM_HAS_BUTTON = 1 - -# leds-arch.c/h etc. +# leds-arch.c etc. BOARD_SOURCEFILES += srf06-sensors.c BOARD_SOURCEFILES += button-sensor-arch.c leds-arch.c BOARD_SOURCEFILES += als-sensor.c From 0c17a1a7ee9aa75d3eac1eb66b4128aa2728df39 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Tue, 24 Jul 2018 18:42:00 +0200 Subject: [PATCH 293/485] Streamlined pre-RTM and RTM devices --- arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 56 +++++-------------- .../cc13x0-cc26x0/Makefile.cc13x0-cc26x0 | 6 +- .../cc13x2-cc26x2/Makefile.cc13x2-cc26x2 | 6 +- 3 files changed, 19 insertions(+), 49 deletions(-) diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index 5a4d6aee3..dab12cf7b 100644 --- a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -1,7 +1,7 @@ ################################################################################ -# CC13x2/CC26x2 CPU makefile +# CC13xx/CC26xx CPU makefile -PRE_RTM = 1 +CC13x2_CC26x2_PRE_RTM ?= 1 # Core SDK is placed as a submodule under the arch/cpu/cc13xx-cc26xx/lib. # Do a sanity check that Core SDK submodule has been initialized. @@ -30,50 +30,20 @@ CPU_START_SOURCEFILES += ccfg.c startup_cc13xx_cc26xx_gcc.c ################################################################################ # Device Family -DEVICE_FAMILY_H := $(CORE_SDK)/source/ti/devices/DeviceFamily.h -# The define of the Device Family ID is on the format of either -# #define DeviceFamily_ID_ -# or -# #define DeviceFamily_ID_ -# We are interested in the right-hand side of the define, i.e. the third word on the line, -# as it either defines a number or an another Device Family ID. -DEVICE_DEFINE := $(shell cat $(DEVICE_FAMILY_H) \ - | grep "\#define DeviceFamily_ID_$(DEVICE_FAMILY)\\b" \ - | awk '{print $$3}') - -# If the define is a number, then the device family name is the resulting device name; -# Else, it points to a sub-name of the device family, e.g. DeviceFamily_ID_CC13X2_V1. -# This line checks if the extracted define is a number or not, based on this SO post: -# https://stackoverflow.com/a/19116862/5099169 -# Return value 0 is no error, i.e. is a number. -IS_NUMBER := $(shell [ "$(DEVICE_DEFINE)" -eq "$(DEVICE_DEFINE)" ] 2>/dev/null; echo $$?) - -ifeq ($(IS_NUMBER),0) - # The define points to a number, meaning the device family name is the same as the - # specified device name in lower case, e.g. - # cc13x2 - DEVICE_FAMILY_NAME := $(DEVICE_FAMILY_LC) +ifeq ($(SUBFAMILY),cc13x2-cc26x2) + ifeq ($(CC13x2_CC26x2_PRE_RTM),1) + SDK_DEVICES_NAME := cc13x2_cc26x2_v1 + SDK_LIB_NAME := $(DEVICE_FAMILY_LC)_v1 + else + SDK_DEVICES_NAME := cc13x2_cc26x2_v2 + SDK_LIB_NAME := $(DEVICE_FAMILY_LC)_v2 + endif else - # The define points to a sub-name of the device family. The resulting device family name - # is therefore the name after specified after ID in lower case, e.g. - # DeviceFamily_ID_CC13X2_V1 - # will result in - # cc13x2_v1 - DEVICE_FAMILY_NAME := $(shell echo "$(DEVICE_DEFINE)" \ - | sed -E "s/DeviceFamily_ID_(.+)/\1/" \ - | tr A-Z a-z) + SDK_DEVICES_NAME := $(DEVICE_FAMILY_LC) + SDK_LIB_NAME := $(DEVICE_FAMILY_LC) endif -# The DeviceFamily_constructPath() macro in DeviceFamily.h will always construct the -# correct path for device specific files. In this case, constructing the device specific -# root path. Note that the returned path is encased in angular brackets, <...>, -# and is therefore extracted with sed. -SDK_DEVICE_DIR := $(shell echo "DeviceFamily_constructPath(dummy)" \ - | arm-none-eabi-cpp -x c -E -DDeviceFamily_$(DEVICE_FAMILY) -include $(DEVICE_FAMILY_H) - \ - | tail -1 \ - | sed -E 's:<(.+)/dummy>:\1:') - ################################################################################ # Simplelink SDK paths @@ -81,7 +51,7 @@ SDK_KERNEL := $(CORE_SDK)/kernel/nortos SDK_SOURCE := $(CORE_SDK)/source SDK_BOARDS := $(SDK_SOURCE)/ti/boards SDK_DRIVERS := $(SDK_SOURCE)/ti/drivers -SDK_DEVICE := $(SDK_SOURCE)/$(SDK_DEVICE_DIR) +SDK_DEVICE := $(SDK_SOURCE)/ti/devices/$(SDK_DEVICES_NAME) EXTERNALDIRS += $(SDK_SOURCE) EXTERNALDIRS += $(SDK_KERNEL) diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/Makefile.cc13x0-cc26x0 b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/Makefile.cc13x0-cc26x0 index 023ef556b..f008760c6 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/Makefile.cc13x0-cc26x0 +++ b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/Makefile.cc13x0-cc26x0 @@ -2,9 +2,9 @@ # CC13x0/CC26x0 CPU makefile ### Simplelink SDK pre-compiled libraries -TARGET_LIBFILES += $(SDK_KERNEL)/lib/nortos_$(DEVICE_FAMILY_NAME).am3g -TARGET_LIBFILES += $(SDK_DRIVERS)/rf/lib/rf_multiMode_$(DEVICE_FAMILY_NAME).am3g -TARGET_LIBFILES += $(SDK_DRIVERS)/lib/drivers_$(DEVICE_FAMILY_NAME).am3g +TARGET_LIBFILES += $(SDK_KERNEL)/lib/nortos_$(SDK_LIB_NAME).am3g +TARGET_LIBFILES += $(SDK_DRIVERS)/rf/lib/rf_multiMode_$(SDK_LIB_NAME).am3g +TARGET_LIBFILES += $(SDK_DRIVERS)/lib/drivers_$(SDK_LIB_NAME).am3g TARGET_LIBFILES += $(SDK_DEVICE)/driverlib/bin/gcc/driverlib.lib include $(CONTIKI)/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 diff --git a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/Makefile.cc13x2-cc26x2 b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/Makefile.cc13x2-cc26x2 index 64b083840..3e590400a 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/Makefile.cc13x2-cc26x2 +++ b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/Makefile.cc13x2-cc26x2 @@ -2,9 +2,9 @@ # CC13x2/CC26x2 CPU makefile ### Simplelink SDK pre-compiled libraries -TARGET_LIBFILES += $(SDK_KERNEL)/lib/nortos_$(DEVICE_FAMILY_NAME).am4fg -TARGET_LIBFILES += $(SDK_DRIVERS)/rf/lib/rf_multiMode_$(DEVICE_FAMILY_NAME).am4fg -TARGET_LIBFILES += $(SDK_DRIVERS)/lib/drivers_$(DEVICE_FAMILY_NAME).am4fg +TARGET_LIBFILES += $(SDK_KERNEL)/lib/nortos_$(SDK_LIB_NAME).am4fg +TARGET_LIBFILES += $(SDK_DRIVERS)/rf/lib/rf_multiMode_$(SDK_LIB_NAME).am4fg +TARGET_LIBFILES += $(SDK_DRIVERS)/lib/drivers_$(SDK_LIB_NAME).am4fg TARGET_LIBFILES += $(SDK_DEVICE)/driverlib/bin/gcc/driverlib.lib include $(CONTIKI)/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 From 7002309c23983d417b6b88e04c2a3e80ab1bd8f4 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Wed, 25 Jul 2018 10:21:54 +0200 Subject: [PATCH 294/485] Makefile rework --- arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 102 ++++++++++-------- .../cc13x0-cc26x0/Makefile.cc13x0-cc26x0 | 9 +- .../cc13x2-cc26x2/Makefile.cc13x2-cc26x2 | 9 +- arch/cpu/cc13xx-cc26xx/ccfg.c | 50 +++++++++ arch/platform/simplelink/Makefile.simplelink | 22 ++-- .../cc13xx-cc26xx/Makefile.cc13xx-cc26xx | 2 +- 6 files changed, 137 insertions(+), 57 deletions(-) create mode 100644 arch/cpu/cc13xx-cc26xx/ccfg.c diff --git a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index dab12cf7b..6322e9a1b 100644 --- a/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/cpu/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -1,36 +1,43 @@ ################################################################################ -# CC13xx/CC26xx CPU makefile +### CC13xx/CC26xx CPU makefile CC13x2_CC26x2_PRE_RTM ?= 1 -# Core SDK is placed as a submodule under the arch/cpu/cc13xx-cc26xx/lib. +# Core SDK is placed as a submodule under arch/cpu/cc13xx-cc26xx/lib. # Do a sanity check that Core SDK submodule has been initialized. +ifeq ($(CORE_SDK),) + CORE_SDK := $(CONTIKI_CPU)/lib/coresdk_cc13xx_cc26xx + CORE_SDK_INIT := $(shell [ -f $(CORE_SDK)/.git ] && echo 1) + ifeq ($(CORE_SDK_INIT),) + $(error The Core SDK submodule is not available. Please run 'git submodule update --init --recursive') + endif # Note that Core SDK can be overriden with a user-specified SimpleLink SDK. # As long as the SimpleLink SDK matches the device in use and is of a reasonable # newer version, then it should be no different than using Core SDK. -ifeq ($(CORE_SDK),) - CORE_SDK := $(CONTIKI_CPU)/lib/coresdk_cc13xx_cc26xx - CORE_SDK_INIT := $(shell [ -f $(CORE_SDK)/.git ]; echo $$?) - ifeq ($(CORE_SDK_INIT),1) - $(error The Core SDK submodule is not available. Please run 'git submodule update --init --recursive') - endif else - # Core SDK was overriden. Do a sanity check the path exists. - CORE_SDK_VALID := $(shell [ -d $(CORE_SDK) ]; echo $$?) - ifeq ($(CORE_SDK_VALID),1) + # Do a sanity check the path exists. + CORE_SDK_VALID := $(shell [ -d $(CORE_SDK) ] && echo 1) + ifeq ($(CORE_SDK_VALID),) $(error Supplied CORE_SDK is not a valid path.) endif endif -# Clean up the path. -CORE_SDK := ${realpath $(CORE_SDK)} -# ccfg.c comes from the device-specific startp_files folder, -# and startup_cc13xx_cc26xx_gcc.c comes from NoRTOS startup folder +# Clean up the path. +CORE_SDK := $(realpath $(CORE_SDK)) + +# Both ccfg.c and startup_cc13xx_cc26xx_gcc.c is located locally in +# the arch/cpu/cc13xx-cc26xx folder. CPU_START_SOURCEFILES += ccfg.c startup_cc13xx_cc26xx_gcc.c ################################################################################ -# Device Family +### Device Family +# CC13x2/CC26x2 has to differentiate both pre-RTM and RTM devices. As of now, +# pre-RTM is suffixed with _v1 while RTM is suffixed with _v2. This will be +# removed when CC13x2/CC26x2 RTMs. For now, provide a switch to choose +# either pre-RTM or RTM. +# Also note that the devices name is cc13x2_cc26x2 for all CC13x2/CC26x2 +# devices, while the library name is individual for each device family. ifeq ($(SUBFAMILY),cc13x2-cc26x2) ifeq ($(CC13x2_CC26x2_PRE_RTM),1) SDK_DEVICES_NAME := cc13x2_cc26x2_v1 @@ -39,36 +46,37 @@ ifeq ($(SUBFAMILY),cc13x2-cc26x2) SDK_DEVICES_NAME := cc13x2_cc26x2_v2 SDK_LIB_NAME := $(DEVICE_FAMILY_LC)_v2 endif +# CC13x0/CC26x0 does not have this, with both its devices name and library +# name he same as its own device family name. else SDK_DEVICES_NAME := $(DEVICE_FAMILY_LC) SDK_LIB_NAME := $(DEVICE_FAMILY_LC) endif ################################################################################ -# Simplelink SDK paths +### Core SDK paths -SDK_KERNEL := $(CORE_SDK)/kernel/nortos -SDK_SOURCE := $(CORE_SDK)/source -SDK_BOARDS := $(SDK_SOURCE)/ti/boards -SDK_DRIVERS := $(SDK_SOURCE)/ti/drivers -SDK_DEVICE := $(SDK_SOURCE)/ti/devices/$(SDK_DEVICES_NAME) +SDK_NORTOS := $(CORE_SDK)/kernel/nortos +SDK_SOURCE := $(CORE_SDK)/source +SDK_DRIVERS := $(CORE_SDK)/source/ti/drivers +SDK_DEVICES := $(CORE_SDK)/source/ti/devices/$(SDK_DEVICES_NAME) EXTERNALDIRS += $(SDK_SOURCE) -EXTERNALDIRS += $(SDK_KERNEL) -EXTERNALDIRS += $(SDK_KERNEL)/startup -EXTERNALDIRS += $(SDK_DEVICE) -EXTERNALDIRS += $(SDK_DEVICE)/startup_files +EXTERNALDIRS += $(SDK_NORTOS) -### CPU-dependent source files -CONTIKI_CPU_SOURCEFILES += rtimer-arch.c clock-arch.c -CONTIKI_CPU_SOURCEFILES += watchdog-arch.c dbg-arch.c -CONTIKI_CPU_SOURCEFILES += uart0-arch.c slip-arch.c -CONTIKI_CPU_SOURCEFILES += gpio-hal-arch.c int-master-arch.c -CONTIKI_CPU_SOURCEFILES += random.c trng-arch.c +################################################################################ +### CC13xx/CC26xx CPU files -### RF source files -CONTIKI_CPU_SOURCEFILES += sched.c data-queue.c -CONTIKI_CPU_SOURCEFILES += ieee-addr.c ble-addr.c +# CPU-dependent source files +CONTIKI_CPU_SOURCEFILES += rtimer-arch.c clock-arch.c +CONTIKI_CPU_SOURCEFILES += watchdog-arch.c dbg-arch.c +CONTIKI_CPU_SOURCEFILES += uart0-arch.c slip-arch.c +CONTIKI_CPU_SOURCEFILES += gpio-hal-arch.c int-master-arch.c +CONTIKI_CPU_SOURCEFILES += random.c trng-arch.c + +# RF source files +CONTIKI_CPU_SOURCEFILES += sched.c data-queue.c +CONTIKI_CPU_SOURCEFILES += ieee-addr.c ble-addr.c CONTIKI_CPU_SOURCEFILES += ble-beacond.c ifeq ($(SUPPORTS_PROP_MODE),1) @@ -83,33 +91,43 @@ ifeq ($(SUPPORTS_BLE_BEACON),1) CONTIKI_CPU_SOURCEFILES += ble-settings.c ble-tx-power.c endif -### CPU-dependent debug source files +################################################################################ +### Modules and paths + +# CPU-dependent debug source files MODULES += os/lib/dbg-io -### CPU-dependent directories +# CPU-dependent directories CONTIKI_CPU_DIRS += . dev $(SUBFAMILY) CONTIKI_CPU_DIRS += rf rf-settings rf-settings/$(DEVICE_FAMILY_LC) CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES) $(DEBUG_IO_SOURCEFILES) -### Linker flag +################################################################################ +### Linker configuration + +# Linker flag LDFLAGS += --entry resetISR LDFLAGS += -static LDFLAGS += --specs=nano.specs LDSCRIPT := $(CONTIKI_CPU)/$(SUBFAMILY)/$(SUBFAMILY).lds -### Always re-build ieee-addr.o in case the command line passes a new NODEID +################################################################################ +### Specialized build targets + +# Always re-build ieee-addr.o in case the command line passes a new NODEID FORCE: $(OBJECTDIR)/ieee-addr.o: ieee-addr.c FORCE | $(OBJECTDIR) $(TRACE_CC) $(Q)$(CC) $(CFLAGS) -c $< -o $@ -### Always re-build ccfg.c so changes to ccfg-conf.h will apply without having -### to make clean first +# Always re-build ccfg.c so changes to ccfg-conf.h will apply without having +# to make clean first $(OBJECTDIR)/ccfg.o: ccfg.c FORCE | $(OBJECTDIR) $(TRACE_CC) - $(Q)$(CC) $(CFLAGS) -include "ccfg-conf.h" -c $< -o $@ + $(Q)$(CC) $(CFLAGS) -c $< -o $@ +# Include the Sub-family specific Makefile include $(CONTIKI_CPU)/$(SUBFAMILY)/Makefile.$(SUBFAMILY) diff --git a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/Makefile.cc13x0-cc26x0 b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/Makefile.cc13x0-cc26x0 index f008760c6..9aa7c5be2 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/Makefile.cc13x0-cc26x0 +++ b/arch/cpu/cc13xx-cc26xx/cc13x0-cc26x0/Makefile.cc13x0-cc26x0 @@ -1,10 +1,11 @@ ################################################################################ -# CC13x0/CC26x0 CPU makefile +### CC13x0/CC26x0 CPU makefile -### Simplelink SDK pre-compiled libraries -TARGET_LIBFILES += $(SDK_KERNEL)/lib/nortos_$(SDK_LIB_NAME).am3g +# Simplelink SDK pre-compiled libraries +TARGET_LIBFILES += $(SDK_NORTOS)/lib/nortos_$(SDK_LIB_NAME).am3g TARGET_LIBFILES += $(SDK_DRIVERS)/rf/lib/rf_multiMode_$(SDK_LIB_NAME).am3g TARGET_LIBFILES += $(SDK_DRIVERS)/lib/drivers_$(SDK_LIB_NAME).am3g -TARGET_LIBFILES += $(SDK_DEVICE)/driverlib/bin/gcc/driverlib.lib +TARGET_LIBFILES += $(SDK_DEVICES)/driverlib/bin/gcc/driverlib.lib +# CC13x0/CC26x0 is a Cortex-M3 architecture include $(CONTIKI)/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 diff --git a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/Makefile.cc13x2-cc26x2 b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/Makefile.cc13x2-cc26x2 index 3e590400a..ede55d4bc 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/Makefile.cc13x2-cc26x2 +++ b/arch/cpu/cc13xx-cc26xx/cc13x2-cc26x2/Makefile.cc13x2-cc26x2 @@ -1,10 +1,11 @@ ################################################################################ -# CC13x2/CC26x2 CPU makefile +### CC13x2/CC26x2 CPU makefile -### Simplelink SDK pre-compiled libraries -TARGET_LIBFILES += $(SDK_KERNEL)/lib/nortos_$(SDK_LIB_NAME).am4fg +# Simplelink SDK pre-compiled libraries +TARGET_LIBFILES += $(SDK_NORTOS)/lib/nortos_$(SDK_LIB_NAME).am4fg TARGET_LIBFILES += $(SDK_DRIVERS)/rf/lib/rf_multiMode_$(SDK_LIB_NAME).am4fg TARGET_LIBFILES += $(SDK_DRIVERS)/lib/drivers_$(SDK_LIB_NAME).am4fg -TARGET_LIBFILES += $(SDK_DEVICE)/driverlib/bin/gcc/driverlib.lib +TARGET_LIBFILES += $(SDK_DEVICES)/driverlib/bin/gcc/driverlib.lib +# CC13x0/CC26x0 is a Cortex-M4 architecture include $(CONTIKI)/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 diff --git a/arch/cpu/cc13xx-cc26xx/ccfg.c b/arch/cpu/cc13xx-cc26xx/ccfg.c new file mode 100644 index 000000000..764b80196 --- /dev/null +++ b/arch/cpu/cc13xx-cc26xx/ccfg.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ + * 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. + */ + /** + * \addtogroup cc13xx-cc26xx-cpu + * @{ + * + * \file + * Customer Configuration (CCFG). + * \author + * Edvard Pettersen + */ +/*---------------------------------------------------------------------------*/ +/** + * Customer Configuration for CC13xx/CC26xx devices. This file is used to + * configure Boot ROM, start-up code, and SW radio behaviour. + * + * Configuration is done in ccfg-conf.h. + */ +#include "ccfg-conf.h" + +#include +#include DeviceFamily_constructPath(startup_files/ccfg.c) +/*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/Makefile.simplelink b/arch/platform/simplelink/Makefile.simplelink index 265bd2c01..1895c4d71 100644 --- a/arch/platform/simplelink/Makefile.simplelink +++ b/arch/platform/simplelink/Makefile.simplelink @@ -13,28 +13,38 @@ ifndef BOARD endif ################################################################################ -### Defines +### Resolve the SimpleLink Family SIMPLELINK_FAMILIES := cc13xx-cc26xx -# Given a SimpleLink family as argument, check if it has the Board file and if so return itself. +# Given a SimpleLink family as argument, check if it has the Board file. +# If so, return itself; else, return empty string. verify_family = $(shell [ -d $(CONTIKI)/arch/platform/simplelink/$(1)/$(BOARD) ] && echo $(1)) # Test each supported SimpleLink family and see if it contains the specified Board. # Throw an error if it isn't found. -FAMILY := $(firstword $(foreach FAMILY, $(SIMPLELINK_FAMILIES), $(call verify_family,$(FAMILY)))) +FAMILY := $(foreach FAMILY, $(SIMPLELINK_FAMILIES), $(call verify_family,$(FAMILY))) ifeq ($(FAMILY),) $(error Board '$(BOARD)' does not corresponding to any SimpleLink family. Make sure your BOARD variable is correct.) endif +# If multiple families are found, only the first one is chosen. If this every +# happens something is not correct. +ifneq ($(words $(FAMILY)),1) + FAMILY := $(firstword $(FAMILY)) + $(warning Multiple SimpleLink families found to support '$(BOARD)'. Resolve to '$(FAMILY)'.) +endif + +# Remove any excess whitespace. +FAMILY := $(strip $(FAMILY)) FAMILY_PATH := $(realpath $(CONTIKI)/arch/platform/simplelink/$(FAMILY)) - CLEAN += *.simplelink -### Include the Simplelink Family specific Makefile +# Include the Simplelink Family specific Makefile include $(FAMILY_PATH)/Makefile.$(FAMILY) ################################################################################ -# Display all supported SimpleLink Families +### SimpleLink targets + simplelink_families: @echo "$(SIMPLELINK_FAMILIES) (current: $(FAMILY))" diff --git a/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx b/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx index 9d696263f..dc681a5eb 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx +++ b/arch/platform/simplelink/cc13xx-cc26xx/Makefile.cc13xx-cc26xx @@ -5,7 +5,7 @@ # Board and BSP selection BOARD_PLATFORMS = launchpad sensortag srf06 -# Assigned lazily to avoid breaking environments which doesn't have cd and find +# All supported boards for this SimpleLink family BOARDS := $(foreach BOARD_TYPE, $(BOARD_PLATFORMS), \ $(shell cd $(FAMILY_PATH); find $(BOARD_TYPE)/* -type d -print)) From 6ed5d7399017676324300b96462985e0e9c3ef53 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Wed, 25 Jul 2018 15:01:08 +0200 Subject: [PATCH 295/485] Renamed cc26xx example folder to its actual platform name, srf06-cc26xx --- .../platform-specific/cc26xx/Makefile.target | 1 - .../cc26xx/cc26xx-web-demo/Makefile.target | 1 - .../cc26xx/cc26xx-web-demo/img/6lbr-web.png | Bin 81741 -> 0 bytes .../ibm-watson-iot-platform-tls-optional.png | Bin 86462 -> 0 bytes .../img/quickstart-sensortag.png | Bin 158808 -> 0 bytes .../img/sensor-readings-config.png | Bin 33000 -> 0 bytes .../cc26xx-web-demo/img/well-known-core.png | Bin 9102 -> 0 bytes .../cc26xx/very-sleepy-demo/Makefile.target | 1 - .../{cc26xx => srf06-cc26xx}/Makefile | 0 .../{cc26xx => srf06-cc26xx}/README.md | 0 .../{cc26xx => srf06-cc26xx}/ble-ipv6/Makefile | 0 .../ble-ipv6/README.md | 0 .../{cc26xx => srf06-cc26xx}/ble-ipv6/client.c | 0 .../ble-ipv6/project-conf.h | 0 .../{cc26xx => srf06-cc26xx}/cc26xx-demo.c | 0 .../cc26xx-web-demo/Makefile | 0 .../cc26xx-web-demo/README.md | 0 .../cc26xx-web-demo/cc26xx-web-demo.c | 0 .../cc26xx-web-demo/cc26xx-web-demo.h | 0 .../cc26xx-web-demo/cetic-6lbr-client.c | 0 .../cc26xx-web-demo/coap-server.c | 0 .../cc26xx-web-demo/coap-server.h | 0 .../cc26xx-web-demo/httpd-simple.c | 0 .../cc26xx-web-demo/httpd-simple.h | 0 .../cc26xx-web-demo/mqtt-client.c | 0 .../cc26xx-web-demo/mqtt-client.h | 0 .../cc26xx-web-demo/net-uart.c | 0 .../cc26xx-web-demo/net-uart.h | 0 .../cc26xx-web-demo/project-conf.h | 0 .../cc26xx-web-demo/resources/res-ble-advd.c | 0 .../cc26xx-web-demo/resources/res-device.c | 0 .../cc26xx-web-demo/resources/res-leds.c | 0 .../cc26xx-web-demo/resources/res-net.c | 0 .../cc26xx-web-demo/resources/res-sensors.c | 0 .../resources/res-toggle-leds.c | 0 .../{cc26xx => srf06-cc26xx}/project-conf.h | 0 .../very-sleepy-demo/Makefile | 0 .../very-sleepy-demo/README.md | 0 .../very-sleepy-demo/project-conf.h | 0 .../very-sleepy-demo/very-sleepy-demo.c | 0 40 files changed, 3 deletions(-) delete mode 100644 examples/platform-specific/cc26xx/Makefile.target delete mode 100644 examples/platform-specific/cc26xx/cc26xx-web-demo/Makefile.target delete mode 100644 examples/platform-specific/cc26xx/cc26xx-web-demo/img/6lbr-web.png delete mode 100644 examples/platform-specific/cc26xx/cc26xx-web-demo/img/ibm-watson-iot-platform-tls-optional.png delete mode 100644 examples/platform-specific/cc26xx/cc26xx-web-demo/img/quickstart-sensortag.png delete mode 100644 examples/platform-specific/cc26xx/cc26xx-web-demo/img/sensor-readings-config.png delete mode 100644 examples/platform-specific/cc26xx/cc26xx-web-demo/img/well-known-core.png delete mode 100644 examples/platform-specific/cc26xx/very-sleepy-demo/Makefile.target rename examples/platform-specific/{cc26xx => srf06-cc26xx}/Makefile (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/README.md (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/ble-ipv6/Makefile (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/ble-ipv6/README.md (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/ble-ipv6/client.c (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/ble-ipv6/project-conf.h (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/cc26xx-demo.c (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/cc26xx-web-demo/Makefile (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/cc26xx-web-demo/README.md (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/cc26xx-web-demo/cc26xx-web-demo.c (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/cc26xx-web-demo/cc26xx-web-demo.h (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/cc26xx-web-demo/cetic-6lbr-client.c (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/cc26xx-web-demo/coap-server.c (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/cc26xx-web-demo/coap-server.h (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/cc26xx-web-demo/httpd-simple.c (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/cc26xx-web-demo/httpd-simple.h (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/cc26xx-web-demo/mqtt-client.c (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/cc26xx-web-demo/mqtt-client.h (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/cc26xx-web-demo/net-uart.c (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/cc26xx-web-demo/net-uart.h (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/cc26xx-web-demo/project-conf.h (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/cc26xx-web-demo/resources/res-ble-advd.c (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/cc26xx-web-demo/resources/res-device.c (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/cc26xx-web-demo/resources/res-leds.c (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/cc26xx-web-demo/resources/res-net.c (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/cc26xx-web-demo/resources/res-sensors.c (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/cc26xx-web-demo/resources/res-toggle-leds.c (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/project-conf.h (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/very-sleepy-demo/Makefile (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/very-sleepy-demo/README.md (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/very-sleepy-demo/project-conf.h (100%) rename examples/platform-specific/{cc26xx => srf06-cc26xx}/very-sleepy-demo/very-sleepy-demo.c (100%) diff --git a/examples/platform-specific/cc26xx/Makefile.target b/examples/platform-specific/cc26xx/Makefile.target deleted file mode 100644 index 15890aa6a..000000000 --- a/examples/platform-specific/cc26xx/Makefile.target +++ /dev/null @@ -1 +0,0 @@ -TARGET = srf06-cc26xx diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/Makefile.target b/examples/platform-specific/cc26xx/cc26xx-web-demo/Makefile.target deleted file mode 100644 index 15890aa6a..000000000 --- a/examples/platform-specific/cc26xx/cc26xx-web-demo/Makefile.target +++ /dev/null @@ -1 +0,0 @@ -TARGET = srf06-cc26xx diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/img/6lbr-web.png b/examples/platform-specific/cc26xx/cc26xx-web-demo/img/6lbr-web.png deleted file mode 100644 index 5308c412bc183fe3f62930fec950a1029ebc036b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 81741 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 LdQl>7^!EP%AFu2O 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 deleted file mode 100644 index 93c98624fddeefc38f66885bb184589c6a6c31e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 86462 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
f>yQ%fU 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