Merge branch 'master' of https://github.com/contiki-os/contiki into fixes

This commit is contained in:
Marco Casaroli 2016-06-03 11:49:04 -03:00
commit cade3c7699
143 changed files with 9721 additions and 706 deletions

4
.gitignore vendored
View file

@ -125,3 +125,7 @@ platform/galileo/bsp/grub/bin/
*.galileo.dll
*.galileo.efi
LOG_OPENOCD
# nRF52 build artifacts
*.jlink
*.nrf52dk

View file

@ -74,7 +74,6 @@ before_script:
git clone https://github.com/cc65/cc65 /tmp/cc65 &&
make -C /tmp/cc65 bin apple2enh atarixl c64 c128 &&
sudo make -C /tmp/cc65 avail &&
export CC65_HOME=/tmp/cc65/ &&
cc65 --version ;
fi
@ -93,6 +92,18 @@ before_script:
rm -rf /tmp/ba-elf-gcc* /tmp/jn516x-sdk* &&
ba-elf-gcc --version ;
fi
## Install mainline ARM toolchain and download nRF52 SDK
- if [ ${BUILD_ARCH:-0} = nrf52dk ] ; then
sudo add-apt-repository -y ppa:team-gcc-arm-embedded/ppa &&
sudo apt-get -qq update &&
sudo apt-get -qq install gcc-arm-embedded srecord &&
arm-none-eabi-gcc --version &&
$WGET https://developer.nordicsemi.com/nRF5_IoT_SDK/nRF5_IoT_SDK_v0.9.x/nrf5_iot_sdk_3288530.zip &&
mkdir /tmp/nrf52-sdk &&
unzip nrf5_iot_sdk_3288530.zip -d /tmp/nrf52-sdk &&
export NRF52_SDK_ROOT=/tmp/nrf52-sdk ;
fi
## Compile cooja.jar only when it's going to be needed
- if [ ${BUILD_CATEGORY:-sim} = sim ] ; then
@ -142,6 +153,7 @@ env:
- BUILD_TYPE='compile-6502-ports' BUILD_CATEGORY='compile' BUILD_ARCH='6502'
- BUILD_TYPE='compile-arm-ports' BUILD_CATEGORY='compile' BUILD_ARCH='arm-aapcs'
- BUILD_TYPE='compile-nxp-ports' BUILD_CATEGORY='compile' BUILD_ARCH='jn516x'
- BUILD_TYPE='compile-nrf52-ports' BUILD_CATEGORY='compile' BUILD_ARCH='nrf52dk'
- BUILD_TYPE='slip-radio' MAKE_TARGETS='cooja'
- BUILD_TYPE='llsec' MAKE_TARGETS='cooja'
- BUILD_TYPE='compile-avr' BUILD_CATEGORY='compile' BUILD_ARCH='avr-rss2'

View file

@ -182,7 +182,7 @@ CONTIKI_CPU_DIRS_CONCAT = ${addprefix $(CONTIKI_CPU)/, \
$(CONTIKI_CPU_DIRS)}
SOURCEDIRS = . $(PROJECTDIRS) $(CONTIKI_TARGET_DIRS_CONCAT) \
$(CONTIKI_CPU_DIRS_CONCAT) $(CONTIKIDIRS) $(APPDS) ${dir $(target_makefile)}
$(CONTIKI_CPU_DIRS_CONCAT) $(CONTIKIDIRS) $(APPDS) $(EXTERNALDIRS) ${dir $(target_makefile)}
vpath %.c $(SOURCEDIRS)
vpath %.S $(SOURCEDIRS)

View file

@ -1,5 +1,13 @@
oma-lwm2m_src = lwm2m-object.c lwm2m-engine.c \
lwm2m-device.c lwm2m-server.c lwm2m-security.c \
oma-tlv.c oma-tlv-reader.c oma-tlv-writer.c \
lwm2m-plain-text.c
oma-lwm2m_src = \
lwm2m-object.c \
lwm2m-engine.c \
lwm2m-device.c \
lwm2m-server.c \
lwm2m-security.c \
oma-tlv.c \
oma-tlv-reader.c \
oma-tlv-writer.c \
lwm2m-plain-text.c \
lwm2m-json.c \
#
CFLAGS += -DHAVE_OMA_LWM2M=1

View file

@ -46,6 +46,7 @@
#include "lwm2m-object.h"
#include "lwm2m-device.h"
#include "lwm2m-plain-text.h"
#include "lwm2m-json.h"
#include "rest-engine.h"
#include "er-coap-constants.h"
#include "er-coap-engine.h"
@ -727,6 +728,10 @@ lwm2m_engine_select_writer(lwm2m_context_t *context, unsigned int accept)
case TEXT_PLAIN:
context->writer = &lwm2m_plain_text_writer;
break;
case LWM2M_JSON:
case APPLICATION_JSON:
context->writer = &lwm2m_json_writer;
break;
default:
PRINTF("Unknown Accept type %u, using LWM2M plain text\n", accept);
context->writer = &lwm2m_plain_text_writer;

162
apps/oma-lwm2m/lwm2m-json.c Normal file
View file

@ -0,0 +1,162 @@
/*
* Copyright (c) 2016, Eistec 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
* Implementation of the Contiki OMA LWM2M JSON writer
* \author
* Joakim Nohlgård <joakim.nohlgard@eistec.se>
*/
#include "lwm2m-object.h"
#include "lwm2m-json.h"
#include "lwm2m-plain-text.h"
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
#include <inttypes.h>
#define DEBUG 0
#if DEBUG
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...)
#endif
/*---------------------------------------------------------------------------*/
static size_t
write_boolean(const lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen,
int value)
{
int len = snprintf((char *)outbuf, outlen, "{\"e\":[{\"n\":\"%u\",\"bv\":%s}]}\n", ctx->resource_id, value ? "true" : "false");
if((len < 0) || (len >= outlen)) {
return 0;
}
return len;
}
/*---------------------------------------------------------------------------*/
static size_t
write_int(const lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen,
int32_t value)
{
int len = snprintf((char *)outbuf, outlen, "{\"e\":[{\"n\":\"%u\",\"v\":%" PRId32 "}]}\n", ctx->resource_id, value);
if((len < 0) || (len >= outlen)) {
return 0;
}
return len;
}
/*---------------------------------------------------------------------------*/
static size_t
write_float32fix(const lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen,
int32_t value, int bits)
{
size_t len = 0;
int res;
res = snprintf((char *)outbuf, outlen, "{\"e\":[{\"n\":\"%u\",\"v\":", ctx->resource_id);
if(res <= 0 || res >= outlen) {
return 0;
}
len += res;
outlen -= res;
res = lwm2m_plain_text_write_float32fix(&outbuf[len], outlen, value, bits);
if((res <= 0) || (res >= outlen)) {
return 0;
}
len += res;
outlen -= res;
res = snprintf((char *)&outbuf[len], outlen, "}]}\n");
if((res <= 0) || (res >= outlen)) {
return 0;
}
len += res;
return len;
}
/*---------------------------------------------------------------------------*/
static size_t
write_string(const lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen,
const char *value, size_t stringlen)
{
size_t i;
size_t len = 0;
int res;
PRINTF("{\"e\":[{\"n\":\"%u\",\"sv\":\"", ctx->resource_id);
res = snprintf((char *)outbuf, outlen, "{\"e\":[{\"n\":\"%u\",\"sv\":\"", ctx->resource_id);
if(res < 0 || res >= outlen) {
return 0;
}
len += res;
for (i = 0; i < stringlen && len < outlen; ++i) {
/* Escape special characters */
/* TODO: Handle UTF-8 strings */
if(value[i] < '\x20') {
PRINTF("\\x%x", value[i]);
res = snprintf((char *)&outbuf[len], outlen - len, "\\x%x", value[i]);
if((res < 0) || (res >= (outlen - len))) {
return 0;
}
len += res;
continue;
} else if(value[i] == '"' || value[i] == '\\') {
PRINTF("\\");
outbuf[len] = '\\';
++len;
if(len >= outlen) {
return 0;
}
}
PRINTF("%c", value[i]);
outbuf[len] = value[i];
++len;
if(len >= outlen) {
return 0;
}
}
PRINTF("\"}]}\n");
res = snprintf((char *)&outbuf[len], outlen - len, "\"}]}\n");
if((res < 0) || (res >= (outlen - len))) {
return 0;
}
len += res;
return len;
}
/*---------------------------------------------------------------------------*/
const lwm2m_writer_t lwm2m_json_writer = {
write_int,
write_string,
write_float32fix,
write_boolean
};
/*---------------------------------------------------------------------------*/
/** @} */

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2016, Eistec 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 JSON writer
* \author
* Joakim Nohlgård <joakim.nohlgard@eistec.se>
*/
#ifndef LWM2M_JSON_H_
#define LWM2M_JSON_H_
#include "lwm2m-object.h"
extern const lwm2m_writer_t lwm2m_json_writer;
#endif /* LWM2M_JSON_H_ */
/** @} */

View file

@ -196,7 +196,7 @@ struct file_header {
/* This is needed because of a buggy compiler. */
struct log_param {
cfs_offset_t offset;
const char *buf;
char *buf;
uint16_t size;
};
@ -1198,7 +1198,7 @@ cfs_write(int fd, const void *buf, unsigned size)
need_dummy_write = 0;
for(bytes_left = size; bytes_left > 0;) {
lp.offset = fdp->offset;
lp.buf = buf;
lp.buf = (void *)buf;
lp.size = bytes_left;
i = write_log_page(file, &lp);
if(i < 0) {

View file

@ -30,7 +30,7 @@
/**
* \file
* A set of debugging tools
* A set of debugging tools for the IP stack
* \author
* Nicolas Tsiftes <nvt@sics.se>
* Niclas Finne <nfi@sics.se>
@ -92,19 +92,3 @@ uip_debug_ipaddr_print(const uip_ipaddr_t *addr)
#endif /* NETSTACK_CONF_WITH_IPV6 */
}
/*---------------------------------------------------------------------------*/
void
uip_debug_lladdr_print(const uip_lladdr_t *addr)
{
unsigned int i;
if(addr == NULL) {
PRINTA("(NULL LL addr)");
return;
}
for(i = 0; i < sizeof(uip_lladdr_t); i++) {
if(i > 0) {
PRINTA(":");
}
PRINTA("%02x", addr->addr[i]);
}
}
/*---------------------------------------------------------------------------*/

View file

@ -31,57 +31,27 @@
*/
/**
* \file
* A set of debugging macros.
* A set of debugging macros for the IP stack
*
* \author Nicolas Tsiftes <nvt@sics.se>
* Niclas Finne <nfi@sics.se>
* Joakim Eriksson <joakime@sics.se>
* Simon Duquennoy <simon.duquennoy@inria.fr>
*/
#ifndef UIP_DEBUG_H
#define UIP_DEBUG_H
#include "net/net-debug.h"
#include "net/ip/uip.h"
#include <stdio.h>
void uip_debug_ipaddr_print(const uip_ipaddr_t *addr);
void uip_debug_lladdr_print(const uip_lladdr_t *addr);
#define DEBUG_NONE 0
#define DEBUG_PRINT 1
#define DEBUG_ANNOTATE 2
#define DEBUG_FULL DEBUG_ANNOTATE | DEBUG_PRINT
/* PRINTA will always print if the debug routines are called directly */
#ifdef __AVR__
#include <avr/pgmspace.h>
#define PRINTA(FORMAT,args...) printf_P(PSTR(FORMAT),##args)
#else
#define PRINTA(...) printf(__VA_ARGS__)
#endif
#if (DEBUG) & DEBUG_ANNOTATE
#ifdef __AVR__
#define ANNOTATE(FORMAT,args...) printf_P(PSTR(FORMAT),##args)
#else
#define ANNOTATE(...) printf(__VA_ARGS__)
#endif
#else
#define ANNOTATE(...)
#endif /* (DEBUG) & DEBUG_ANNOTATE */
#if (DEBUG) & DEBUG_PRINT
#ifdef __AVR__
#define PRINTF(FORMAT,args...) printf_P(PSTR(FORMAT),##args)
#else
#define PRINTF(...) printf(__VA_ARGS__)
#endif
#define PRINT6ADDR(addr) uip_debug_ipaddr_print(addr)
#define PRINTLLADDR(lladdr) uip_debug_lladdr_print(lladdr)
#else
#define PRINTF(...)
#define PRINT6ADDR(addr)
#define PRINTLLADDR(lladdr)
#endif /* (DEBUG) & DEBUG_PRINT */
#endif
#endif /* UIP_DEBUG_H */

View file

@ -163,6 +163,14 @@ void uip_log(char *msg);
#define COMPRESSION_THRESHOLD 0
#endif
/** \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.
*/
#ifndef SICSLOWPAN_FIXED_HDRLEN
#define SICSLOWPAN_FIXED_HDRLEN 21
#endif
/** \name General variables
* @{
*/
@ -1271,11 +1279,6 @@ output(const uip_lladdr_t *localdest)
/* The MAC address of the destination of the packet */
linkaddr_t dest;
#if SICSLOWPAN_CONF_FRAG
/* Number of bytes processed. */
uint16_t processed_ip_out_len;
#endif /* SICSLOWPAN_CONF_FRAG */
/* init */
uncomp_hdr_len = 0;
packetbuf_hdr_len = 0;
@ -1336,21 +1339,23 @@ output(const uip_lladdr_t *localdest)
/* Calculate NETSTACK_FRAMER's header length, that will be added in the NETSTACK_RDC.
* We calculate it here only to make a better decision of whether the outgoing packet
* needs to be fragmented or not. */
#define USE_FRAMER_HDRLEN 1
#if USE_FRAMER_HDRLEN
#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 = 21;
framer_hdrlen = SICSLOWPAN_FIXED_HDRLEN;
}
#else /* USE_FRAMER_HDRLEN */
framer_hdrlen = 21;
framer_hdrlen = SICSLOWPAN_FIXED_HDRLEN;
#endif /* USE_FRAMER_HDRLEN */
max_payload = MAC_MAX_PAYLOAD - framer_hdrlen;
if((int)uip_len - (int)uncomp_hdr_len > max_payload - (int)packetbuf_hdr_len) {
#if SICSLOWPAN_CONF_FRAG
/* Number of bytes processed. */
uint16_t processed_ip_out_len;
struct queuebuf *q;
uint16_t frag_tag;

View file

@ -135,11 +135,13 @@ static uip_ds6_prefix_t *prefix; /** Pointer to a prefix list entry */
#if UIP_ND6_SEND_NA || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER
/*------------------------------------------------------------------*/
/* Copy link-layer address from LLAO option to a word-aligned uip_lladdr_t */
static void
extract_lladdr_aligned(uip_lladdr_t *dest) {
static int
extract_lladdr_from_llao_aligned(uip_lladdr_t *dest) {
if(dest != NULL && nd6_opt_llao != NULL) {
memcpy(dest, &nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], UIP_LLADDR_LEN);
return 1;
}
return 0;
}
#endif /* UIP_ND6_SEND_NA || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER */
/*------------------------------------------------------------------*/
@ -199,17 +201,23 @@ ns_input(void)
goto discard;
} else {
#endif /*UIP_CONF_IPV6_CHECKS */
uip_lladdr_t lladdr_aligned;
extract_lladdr_from_llao_aligned(&lladdr_aligned);
nbr = uip_ds6_nbr_lookup(&UIP_IP_BUF->srcipaddr);
if(nbr == NULL) {
uip_lladdr_t lladdr_aligned;
extract_lladdr_aligned(&lladdr_aligned);
uip_ds6_nbr_add(&UIP_IP_BUF->srcipaddr, &lladdr_aligned,
0, NBR_STALE, NBR_TABLE_REASON_IPV6_ND, NULL);
} else {
uip_lladdr_t *lladdr = (uip_lladdr_t *)uip_ds6_nbr_get_ll(nbr);
const uip_lladdr_t *lladdr = uip_ds6_nbr_get_ll(nbr);
if(lladdr == NULL) {
goto discard;
}
if(memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET],
lladdr, UIP_LLADDR_LEN) != 0) {
memcpy(lladdr, &nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], UIP_LLADDR_LEN);
if(nbr_table_update_lladdr((const linkaddr_t *)lladdr, (const linkaddr_t *)&lladdr_aligned, 1) == 0) {
/* failed to update the lladdr */
goto discard;
}
nbr->state = NBR_STALE;
} else {
if(nbr->state == NBR_INCOMPLETE) {
@ -428,6 +436,7 @@ na_input(void)
uint8_t is_router;
uint8_t is_solicited;
uint8_t is_override;
uip_lladdr_t lladdr_aligned;
PRINTF("Received NA from ");
PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
@ -490,23 +499,29 @@ na_input(void)
PRINTF("NA received is bad\n");
goto discard;
} else {
uip_lladdr_t *lladdr;
const uip_lladdr_t *lladdr;
nbr = uip_ds6_nbr_lookup(&UIP_ND6_NA_BUF->tgtipaddr);
lladdr = (uip_lladdr_t *)uip_ds6_nbr_get_ll(nbr);
if(nbr == NULL) {
goto discard;
}
if(nd6_opt_llao != 0) {
lladdr = uip_ds6_nbr_get_ll(nbr);
if(lladdr == NULL) {
goto discard;
}
if(nd6_opt_llao != NULL) {
is_llchange =
memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], (void *)lladdr,
memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], lladdr,
UIP_LLADDR_LEN);
}
if(nbr->state == NBR_INCOMPLETE) {
if(nd6_opt_llao == NULL) {
if(nd6_opt_llao == NULL || !extract_lladdr_from_llao_aligned(&lladdr_aligned)) {
goto discard;
}
memcpy(lladdr, &nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET],
UIP_LLADDR_LEN);
if(nbr_table_update_lladdr((const linkaddr_t *)lladdr, (const linkaddr_t *)&lladdr_aligned, 1) == 0) {
/* failed to update the lladdr */
goto discard;
}
if(is_solicited) {
nbr->state = NBR_REACHABLE;
nbr->nscount = 0;
@ -518,27 +533,29 @@ na_input(void)
nbr->state = NBR_STALE;
}
nbr->isrouter = is_router;
} else {
} else { /* NBR is not INCOMPLETE */
if(!is_override && is_llchange) {
if(nbr->state == NBR_REACHABLE) {
nbr->state = NBR_STALE;
}
goto discard;
} else {
if(is_override || (!is_override && nd6_opt_llao != 0 && !is_llchange)
|| nd6_opt_llao == 0) {
if(nd6_opt_llao != 0) {
memcpy(lladdr, &nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET],
UIP_LLADDR_LEN);
/**
* If this is an cache override, or same lladdr, or no llao -
* do updates of nbr states.
*/
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) {
/* failed to update the lladdr */
goto discard;
}
}
if(is_solicited) {
nbr->state = NBR_REACHABLE;
/* reachable time is stored in ms */
stimer_set(&(nbr->reachable), uip_ds6_if.reachable_time / 1000);
} else {
if(nd6_opt_llao != 0 && is_llchange) {
nbr->state = NBR_STALE;
}
}
}
}
@ -632,15 +649,19 @@ rs_input(void)
} else {
#endif /*UIP_CONF_IPV6_CHECKS */
uip_lladdr_t lladdr_aligned;
extract_lladdr_aligned(&lladdr_aligned);
extract_lladdr_from_llao_aligned(&lladdr_aligned);
if((nbr = uip_ds6_nbr_lookup(&UIP_IP_BUF->srcipaddr)) == NULL) {
/* we need to add the neighbor */
uip_ds6_nbr_add(&UIP_IP_BUF->srcipaddr, &lladdr_aligned,
0, NBR_STALE, NBR_TABLE_REASON_IPV6_ND, NULL);
} else {
/* If LL address changed, set neighbor state to stale */
const uip_lladdr_t *lladdr = uip_ds6_nbr_get_ll(nbr);
if(lladdr == NULL) {
goto discard;
}
if(memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET],
uip_ds6_nbr_get_ll(nbr), UIP_LLADDR_LEN) != 0) {
lladdr, UIP_LLADDR_LEN) != 0) {
uip_ds6_nbr_t nbr_data = *nbr;
uip_ds6_nbr_rm(nbr);
nbr = uip_ds6_nbr_add(&UIP_IP_BUF->srcipaddr, &lladdr_aligned,
@ -826,6 +847,8 @@ uip_nd6_rs_output(void)
void
ra_input(void)
{
uip_lladdr_t lladdr_aligned;
PRINTF("Received RA from ");
PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
PRINTF(" to ");
@ -870,20 +893,28 @@ ra_input(void)
PRINTF("Processing SLLAO option in RA\n");
nd6_opt_llao = (uint8_t *) UIP_ND6_OPT_HDR_BUF;
nbr = uip_ds6_nbr_lookup(&UIP_IP_BUF->srcipaddr);
if(!extract_lladdr_from_llao_aligned(&lladdr_aligned)) {
/* failed to extract llao - discard packet */
goto discard;
}
if(nbr == NULL) {
uip_lladdr_t lladdr_aligned;
extract_lladdr_aligned(&lladdr_aligned);
nbr = uip_ds6_nbr_add(&UIP_IP_BUF->srcipaddr, &lladdr_aligned,
1, NBR_STALE, NBR_TABLE_REASON_IPV6_ND, NULL);
} else {
uip_lladdr_t *lladdr = (uip_lladdr_t *)uip_ds6_nbr_get_ll(nbr);
const uip_lladdr_t *lladdr = uip_ds6_nbr_get_ll(nbr);
if(lladdr == NULL) {
goto discard;
}
if(nbr->state == NBR_INCOMPLETE) {
nbr->state = NBR_STALE;
}
if(memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET],
lladdr, UIP_LLADDR_LEN) != 0) {
memcpy(lladdr, &nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET],
UIP_LLADDR_LEN);
/* change of link layer address */
if(nbr_table_update_lladdr((const linkaddr_t *)lladdr, (const linkaddr_t *)&lladdr_aligned, 1) == 0) {
/* failed to update the lladdr */
goto discard;
}
nbr->state = NBR_STALE;
}
nbr->isrouter = 1;

View file

@ -41,7 +41,7 @@
#include "net/mac/frame802154e-ie.h"
#define DEBUG DEBUG_NONE
#include "net/ip/uip-debug.h"
#include "net/net-debug.h"
/* c.f. IEEE 802.15.4e Table 4b */
enum ieee802154e_header_ie_id {

View file

@ -36,6 +36,7 @@ It has been tested on the following platforms:
* NXP JN516x (`jn516x`, tested on hardware)
* Tmote Sky (`sky`, tested on hardware and in cooja)
* Zolertia Z1 (`z1`, tested in cooja only)
* CC2538DK (`cc2538dk`, tested on hardware)
This implementation was present at the ETSI Plugtest
event in Prague in July 2015, and did successfully inter-operate with all
@ -76,7 +77,7 @@ Orchestra is implemented in:
A simple TSCH+RPL example is included under `examples/ipv6/rpl-tsch`.
To use TSCH, first make sure your platform supports it.
Currently, `jn516x`, `sky` and `z1` are the supported platforms.
Currently, `jn516x`, `sky`, `z1` and `cc2538dk` are the supported platforms.
To add your own, we refer the reader to the next section.
To add TSCH to your application, first include the TSCH module from your makefile with:
@ -162,7 +163,7 @@ Finally, one can also implement his own scheduler, centralized or distributed, b
## Porting TSCH to a new platform
Porting TSCH to a new platform requires a few new features in the radio driver, a number of timing-related configuration paramters.
The easiest is probably to start from one of the existing port: `jn516x`, `sky`, `z1`.
The easiest is probably to start from one of the existing port: `jn516x`, `sky`, `z1`, `cc2538dk`.
### Radio features required for TSCH

View file

@ -175,4 +175,11 @@
#define TSCH_ADAPTIVE_TIMESYNC 0
#endif
/* HW frame filtering enabled */
#ifdef TSCH_CONF_HW_FRAME_FILTERING
#define TSCH_HW_FRAME_FILTERING TSCH_CONF_HW_FRAME_FILTERING
#else /* TSCH_CONF_HW_FRAME_FILTERING */
#define TSCH_HW_FRAME_FILTERING 1
#endif /* TSCH_CONF_HW_FRAME_FILTERING */
#endif /* __TSCH_CONF_H__ */

View file

@ -56,7 +56,7 @@
#else /* TSCH_LOG_LEVEL */
#define DEBUG DEBUG_NONE
#endif /* TSCH_LOG_LEVEL */
#include "net/ip/uip-debug.h"
#include "net/net-debug.h"
#if TSCH_LOG_LEVEL >= 2 /* Skip this file for log levels 0 or 1 */

View file

@ -60,7 +60,7 @@
#else /* TSCH_LOG_LEVEL */
#define DEBUG DEBUG_NONE
#endif /* TSCH_LOG_LEVEL */
#include "net/ip/uip-debug.h"
#include "net/net-debug.h"
/*---------------------------------------------------------------------------*/
/* Construct enhanced ACK packet and return ACK length */

View file

@ -61,7 +61,7 @@
#else /* TSCH_LOG_LEVEL */
#define DEBUG DEBUG_NONE
#endif /* TSCH_LOG_LEVEL */
#include "net/ip/uip-debug.h"
#include "net/net-debug.h"
/* Check if TSCH_QUEUE_NUM_PER_NEIGHBOR is power of two */
#if (TSCH_QUEUE_NUM_PER_NEIGHBOR & (TSCH_QUEUE_NUM_PER_NEIGHBOR - 1)) != 0

View file

@ -51,7 +51,7 @@
#else /* TSCH_LOG_LEVEL */
#define DEBUG DEBUG_NONE
#endif /* TSCH_LOG_LEVEL */
#include "net/ip/uip-debug.h"
#include "net/net-debug.h"
/*---------------------------------------------------------------------------*/
/* To use, set #define TSCH_CALLBACK_JOINING_NETWORK tsch_rpl_callback_joining_network */

View file

@ -60,7 +60,7 @@
#else /* TSCH_LOG_LEVEL */
#define DEBUG DEBUG_NONE
#endif /* TSCH_LOG_LEVEL */
#include "net/ip/uip-debug.h"
#include "net/net-debug.h"
/* Pre-allocated space for links */
MEMB(link_memb, struct tsch_link, TSCH_SCHEDULE_MAX_LINKS);

View file

@ -58,7 +58,7 @@
#else /* TSCH_LOG_LEVEL */
#define DEBUG DEBUG_NONE
#endif /* TSCH_LOG_LEVEL */
#include "net/ip/uip-debug.h"
#include "net/net-debug.h"
/* The two keys K1 and K2 from 6TiSCH minimal configuration
* K1: well-known, used for EBs

View file

@ -59,7 +59,7 @@
#else /* TSCH_LOG_LEVEL */
#define DEBUG DEBUG_NONE
#endif /* TSCH_LOG_LEVEL */
#include "net/ip/uip-debug.h"
#include "net/net-debug.h"
/* TSCH debug macros, i.e. to set LEDs or GPIOs on various TSCH
* timeslot events */
@ -493,9 +493,11 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t))
uint8_t ack_hdrlen;
frame802154_t frame;
#if TSCH_HW_FRAME_FILTERING
/* Entering promiscuous mode so that the radio accepts the enhanced ACK */
NETSTACK_RADIO.get_value(RADIO_PARAM_RX_MODE, &radio_rx_mode);
NETSTACK_RADIO.set_value(RADIO_PARAM_RX_MODE, radio_rx_mode & (~RADIO_RX_MODE_ADDRESS_FILTER));
#endif /* TSCH_HW_FRAME_FILTERING */
/* Unicast: wait for ack after tx: sleep until ack time */
TSCH_SCHEDULE_AND_YIELD(pt, t, current_slot_start,
tsch_timing[tsch_ts_tx_offset] + tx_duration + tsch_timing[tsch_ts_rx_ack_delay] - RADIO_DELAY_BEFORE_RX, "TxBeforeAck");
@ -514,9 +516,11 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t))
TSCH_DEBUG_TX_EVENT();
NETSTACK_RADIO.off();
#if TSCH_HW_FRAME_FILTERING
/* Leaving promiscuous mode */
NETSTACK_RADIO.get_value(RADIO_PARAM_RX_MODE, &radio_rx_mode);
NETSTACK_RADIO.set_value(RADIO_PARAM_RX_MODE, radio_rx_mode | RADIO_RX_MODE_ADDRESS_FILTER);
#endif /* TSCH_HW_FRAME_FILTERING */
/* Read ack frame */
ack_len = NETSTACK_RADIO.read((void *)ackbuf, sizeof(ackbuf));
@ -737,7 +741,7 @@ PT_THREAD(tsch_rx_slot(struct pt *pt, struct rtimer *t))
if(linkaddr_cmp(&destination_address, &linkaddr_node_addr)
|| linkaddr_cmp(&destination_address, &linkaddr_null)) {
int do_nack = 0;
estimated_drift = ((int32_t)expected_rx_time - (int32_t)rx_start_time);
estimated_drift = RTIMER_CLOCK_DIFF(expected_rx_time, rx_start_time);
#if TSCH_TIMESYNC_REMOVE_JITTER
/* remove jitter due to measurement errors */

View file

@ -64,7 +64,7 @@
#else /* TSCH_LOG_LEVEL */
#define DEBUG DEBUG_NONE
#endif /* TSCH_LOG_LEVEL */
#include "net/ip/uip-debug.h"
#include "net/net-debug.h"
/* Use to collect link statistics even on Keep-Alive, even though they were
* not sent from an upper layer and don't have a valid packet_sent callback */

View file

@ -178,6 +178,25 @@ nbr_set_bit(uint8_t *bitmap, nbr_table_t *table, nbr_table_item_t *item, int val
return 0;
}
/*---------------------------------------------------------------------------*/
static void
remove_key(nbr_table_key_t *least_used_key)
{
int i;
for(i = 0; i < MAX_NUM_TABLES; i++) {
if(all_tables[i] != NULL && all_tables[i]->callback != NULL) {
/* Call table callback for each table that uses this item */
nbr_table_item_t *removed_item = item_from_key(all_tables[i], least_used_key);
if(nbr_get_bit(used_map, all_tables[i], removed_item) == 1) {
all_tables[i]->callback(removed_item);
}
}
}
/* Empty used map */
used_map[index_from_key(least_used_key)] = 0;
/* Remove neighbor from list */
list_remove(nbr_table_keys, least_used_key);
}
/*---------------------------------------------------------------------------*/
static nbr_table_key_t *
nbr_table_allocate(nbr_table_reason_t reason, void *data)
{
@ -253,21 +272,7 @@ nbr_table_allocate(nbr_table_reason_t reason, void *data)
return NULL;
} else {
/* Reuse least used item */
int i;
for(i = 0; i<MAX_NUM_TABLES; i++) {
if(all_tables[i] != NULL && all_tables[i]->callback != NULL) {
/* Call table callback for each table that uses this item */
nbr_table_item_t *removed_item = item_from_key(all_tables[i], least_used_key);
if(nbr_get_bit(used_map, all_tables[i], removed_item) == 1) {
all_tables[i]->callback(removed_item);
}
}
}
/* Empty used map */
used_map[index_from_key(least_used_key)] = 0;
/* Remove neighbor from list */
list_remove(nbr_table_keys, least_used_key);
/* Return associated key */
remove_key(least_used_key);
return least_used_key;
}
}
@ -416,6 +421,39 @@ 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()

View file

@ -109,6 +109,7 @@ 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_ */

65
core/net/net-debug.c Normal file
View file

@ -0,0 +1,65 @@
/*
* Copyright (c) 2010, 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.
*
*/
/**
* \file
* A set of debugging tools for the IP stack
* \author
* Nicolas Tsiftes <nvt@sics.se>
* Niclas Finne <nfi@sics.se>
* Joakim Eriksson <joakime@sics.se>
* Simon Duquennoy <simon.duquennoy@inria.fr>
*/
#include "net/net-debug.h"
/*---------------------------------------------------------------------------*/
void
net_debug_lladdr_print(const uip_lladdr_t *addr)
{
if(addr == NULL) {
PRINTA("(NULL LL addr)");
return;
} else {
#if NETSTACK_CONF_WITH_RIME
/* Rime uses traditionally a %u.%u format */
PRINTA("%u.%u", addr->addr[0], addr->addr[1]);
#else /* NETSTACK_CONF_WITH_RIME */
unsigned int i;
for(i = 0; i < LINKADDR_SIZE; i++) {
if(i > 0) {
PRINTA(":");
}
PRINTA("%02x", addr->addr[i]);
}
#endif /* NETSTACK_CONF_WITH_RIME */
}
}
/*---------------------------------------------------------------------------*/

86
core/net/net-debug.h Normal file
View file

@ -0,0 +1,86 @@
/*
* Copyright (c) 2010, 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 set of debugging macros for the netstack
*
* \author Nicolas Tsiftes <nvt@sics.se>
* Niclas Finne <nfi@sics.se>
* Joakim Eriksson <joakime@sics.se>
* Simon Duquennoy <simon.duquennoy@inria.fr>
*/
#ifndef NET_DEBUG_H
#define NET_DEBUG_H
#include "net/ip/uip.h"
#include "net/linkaddr.h"
#include <stdio.h>
void net_debug_lladdr_print(const uip_lladdr_t *addr);
#define DEBUG_NONE 0
#define DEBUG_PRINT 1
#define DEBUG_ANNOTATE 2
#define DEBUG_FULL DEBUG_ANNOTATE | DEBUG_PRINT
/* PRINTA will always print if the debug routines are called directly */
#ifdef __AVR__
#include <avr/pgmspace.h>
#define PRINTA(FORMAT,args...) printf_P(PSTR(FORMAT),##args)
#else
#define PRINTA(...) printf(__VA_ARGS__)
#endif
#if (DEBUG) & DEBUG_ANNOTATE
#ifdef __AVR__
#define ANNOTATE(FORMAT,args...) printf_P(PSTR(FORMAT),##args)
#else
#define ANNOTATE(...) printf(__VA_ARGS__)
#endif
#else
#define ANNOTATE(...)
#endif /* (DEBUG) & DEBUG_ANNOTATE */
#if (DEBUG) & DEBUG_PRINT
#ifdef __AVR__
#define PRINTF(FORMAT,args...) printf_P(PSTR(FORMAT),##args)
#else
#define PRINTF(...) printf(__VA_ARGS__)
#endif
#define PRINTLLADDR(lladdr) net_debug_lladdr_print(lladdr)
#else
#define PRINTF(...)
#define PRINTLLADDR(lladdr)
#endif /* (DEBUG) & DEBUG_PRINT */
#endif /* NET_DEBUG_H */

5
core/net/rime/chameleon-raw.c Normal file → Executable file
View file

@ -205,10 +205,7 @@ hdrsize(const struct packetbuf_attrlist *a)
continue;
}
#endif /* CHAMELEON_WITH_MAC_LINK_ADDRESSES */
len = a->len;
if(len < 8) {
len = 8;
}
len = (a->len & 0xf8) + ((a->len & 7) ? 8: 0);
size += len;
}
return size / 8;

View file

@ -245,10 +245,10 @@ do_poll(void)
static void
do_event(void)
{
static process_event_t ev;
static process_data_t data;
static struct process *receiver;
static struct process *p;
process_event_t ev;
process_data_t data;
struct process *receiver;
struct process *p;
/*
* If there are any events in the queue, take the first one and walk
@ -321,7 +321,7 @@ process_nevents(void)
int
process_post(struct process *p, process_event_t ev, process_data_t data)
{
static process_num_events_t snum;
process_num_events_t snum;
if(PROCESS_CURRENT() == NULL) {
PRINTF("process_post: NULL process posts event %d to process '%s', nevents %d\n",

View file

@ -55,10 +55,12 @@
#include "contiki-conf.h"
#ifndef RTIMER_CLOCK_LT
#ifndef RTIMER_CLOCK_DIFF
typedef unsigned short rtimer_clock_t;
#define RTIMER_CLOCK_LT(a,b) ((signed short)((a)-(b)) < 0)
#endif /* RTIMER_CLOCK_LT */
#define RTIMER_CLOCK_DIFF(a,b) ((signed short)((a)-(b)))
#endif /* RTIMER_CLOCK_DIFF */
#define RTIMER_CLOCK_LT(a, b) (RTIMER_CLOCK_DIFF((a),(b)) < 0)
#include "rtimer-arch.h"

View file

@ -31,10 +31,6 @@
# Author: Oliver Schmidt <ol.sc@web.de>
#
ifndef CC65_HOME
${error CC65_HOME not defined! You must specify where cc65 resides}
endif
.SUFFIXES:
CONTIKI_TARGET_DIRS = . lib sys
@ -70,3 +66,5 @@ ASFLAGS = -t $(TARGET)
CFLAGS += -t $(TARGET) -Or -W -unused-param
LDFLAGS = -t $(TARGET) -m contiki-$(TARGET).map -D __STACKSIZE__=0x200
AROPTS = a
CC65_TARGET_DIR := $(shell $(CC) --print-target-path)/$(TARGET)

View file

@ -46,7 +46,7 @@ typedef uint32_t clock_time_t;
typedef uint16_t uip_stats_t;
typedef uint32_t rtimer_clock_t;
#define RTIMER_CLOCK_LT(a, b) ((int32_t)((a) - (b)) < 0)
#define RTIMER_CLOCK_DIFF(a, b) ((int32_t)((a) - (b)))
rtimer_clock_t rtimer_arch_now(void);
#endif

View file

@ -115,8 +115,7 @@ CUSTOM_RULE_LINK=1
cp $< $@
### This rule is used to generate the correct linker script
LDGENFLAGS += $(addprefix -D,$(subst $(COMMA), ,$(DEFINES)))
LDGENFLAGS += $(addprefix -I,$(SOURCEDIRS))
LDGENFLAGS += $(CFLAGS)
LDGENFLAGS += -imacros "contiki-conf.h" -imacros "dev/cc2538-dev.h"
LDGENFLAGS += -imacros "dev/flash.h" -imacros "cfs-coffee-arch.h"
LDGENFLAGS += -x c -P -E

View file

@ -102,6 +102,8 @@
/** Maximal amount of log table entries read in one batch */
#ifdef COFFEE_CONF_LOG_TABLE_LIMIT
#define COFFEE_LOG_TABLE_LIMIT COFFEE_CONF_LOG_TABLE_LIMIT
#else
#define COFFEE_LOG_TABLE_LIMIT 16
#endif
/** Default reserved file size */
#ifdef COFFEE_CONF_DYN_SIZE
@ -112,6 +114,8 @@
/** Default micro-log size */
#ifdef COFFEE_CONF_LOG_SIZE
#define COFFEE_LOG_SIZE COFFEE_CONF_LOG_SIZE
#else
#define COFFEE_LOG_SIZE (4 * COFFEE_PAGE_SIZE)
#endif
/** Whether Coffee will use micro logs */
#ifdef COFFEE_CONF_MICRO_LOGS

View file

@ -119,6 +119,25 @@ static const uint8_t magic[] = { 0x53, 0x6E, 0x69, 0x66 }; /** Snif */
#else
#define CC2538_RF_AUTOACK 1
#endif
/*---------------------------------------------------------------------------
* MAC timer
*---------------------------------------------------------------------------*/
/* Timer conversion */
#define RADIO_TO_RTIMER(X) ((uint32_t)((uint64_t)(X) * RTIMER_ARCH_SECOND / SYS_CTRL_32MHZ))
#define CLOCK_STABLE() do { \
while ( !(REG(SYS_CTRL_CLOCK_STA) & (SYS_CTRL_CLOCK_STA_XOSC_STB))); \
} while(0)
/*---------------------------------------------------------------------------*/
/* Are we currently in poll mode? Disabled by default */
static uint8_t volatile poll_mode = 0;
/* Do we perform a CCA before sending? Enabled by default. */
static uint8_t send_on_cca = 1;
static int8_t rssi;
static uint8_t crc_corr;
void mac_timer_init(void);
uint32_t get_sfd_timestamp(void);
/*---------------------------------------------------------------------------*/
static uint8_t rf_flags;
static uint8_t rf_channel = CC2538_RF_CHANNEL;
@ -329,6 +348,28 @@ set_frame_filtering(uint8_t enable)
}
/*---------------------------------------------------------------------------*/
static void
set_poll_mode(uint8_t enable)
{
poll_mode = enable;
if(enable) {
mac_timer_init();
REG(RFCORE_XREG_RFIRQM0) &= ~RFCORE_XREG_RFIRQM0_FIFOP; // mask out FIFOP interrupt source
REG(RFCORE_SFR_RFIRQF0) &= ~RFCORE_SFR_RFIRQF0_FIFOP; // clear pending FIFOP interrupt
nvic_interrupt_disable(NVIC_INT_RF_RXTX); // disable RF interrupts
} else {
REG(RFCORE_XREG_RFIRQM0) |= RFCORE_XREG_RFIRQM0_FIFOP; // enable FIFOP interrupt source
nvic_interrupt_enable(NVIC_INT_RF_RXTX); // enable RF interrupts
}
}
/*---------------------------------------------------------------------------*/
static void
set_send_on_cca(uint8_t enable)
{
send_on_cca = enable;
}
/*---------------------------------------------------------------------------*/
static void
set_auto_ack(uint8_t enable)
{
if(enable) {
@ -395,7 +436,9 @@ off(void)
/* Wait for ongoing TX to complete (e.g. this could be an outgoing ACK) */
while(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE);
CC2538_RF_CSP_ISFLUSHRX();
if(!(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFOP)) {
CC2538_RF_CSP_ISFLUSHRX();
}
/* Don't turn off if we are off as this will trigger a Strobe Error */
if(REG(RFCORE_XREG_RXENABLE) != 0) {
@ -459,10 +502,6 @@ init(void)
set_channel(rf_channel);
/* Acknowledge RF interrupts, FIFOP only */
REG(RFCORE_XREG_RFIRQM0) |= RFCORE_XREG_RFIRQM0_FIFOP;
nvic_interrupt_enable(NVIC_INT_RF_RXTX);
/* Acknowledge all RF Error interrupts */
REG(RFCORE_XREG_RFERRM) = RFCORE_XREG_RFERRM_RFERRM;
nvic_interrupt_enable(NVIC_INT_RF_ERR);
@ -488,6 +527,8 @@ init(void)
*/
udma_set_channel_src(CC2538_RF_CONF_RX_DMA_CHAN, RFCORE_SFR_RFDATA);
}
set_poll_mode(poll_mode);
process_start(&cc2538_rf_process, NULL);
@ -571,9 +612,11 @@ transmit(unsigned short transmit_len)
while(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + ONOFF_TIME));
}
if(channel_clear() == CC2538_RF_CCA_BUSY) {
RIMESTATS_ADD(contentiondrop);
return RADIO_TX_COLLISION;
if(send_on_cca) {
if(channel_clear() == CC2538_RF_CCA_BUSY) {
RIMESTATS_ADD(contentiondrop);
return RADIO_TX_COLLISION;
}
}
/*
@ -630,8 +673,6 @@ read(void *buf, unsigned short bufsize)
{
uint8_t i;
uint8_t len;
uint8_t crc_corr;
int8_t rssi;
PRINTF("RF: Read\n");
@ -731,14 +772,18 @@ read(void *buf, unsigned short bufsize)
flush();
#endif
/* If FIFOP==1 and FIFO==0 then we had a FIFO overflow at some point. */
if(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFOP) {
if(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFO) {
process_poll(&cc2538_rf_process);
} else {
CC2538_RF_CSP_ISFLUSHRX();
if(!poll_mode) {
/* If FIFOP==1 and FIFO==0 then we had a FIFO overflow at some point. */
if(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFOP) {
if(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFO) {
process_poll(&cc2538_rf_process);
} else {
CC2538_RF_CSP_ISFLUSHRX();
}
}
}
CC2538_RF_CSP_ISFLUSHRX();
return (len);
}
@ -796,6 +841,15 @@ get_value(radio_param_t param, radio_value_t *value)
if(REG(RFCORE_XREG_FRMCTRL0) & RFCORE_XREG_FRMCTRL0_AUTOACK) {
*value |= RADIO_RX_MODE_AUTOACK;
}
if(poll_mode) {
*value |= RADIO_RX_MODE_POLL_MODE;
}
return RADIO_RESULT_OK;
case RADIO_PARAM_TX_MODE:
*value = 0;
if(send_on_cca) {
*value |= RADIO_TX_MODE_SEND_ON_CCA;
}
return RADIO_RESULT_OK;
case RADIO_PARAM_TXPOWER:
*value = get_tx_power();
@ -806,6 +860,12 @@ get_value(radio_param_t param, radio_value_t *value)
case RADIO_PARAM_RSSI:
*value = get_rssi();
return RADIO_RESULT_OK;
case RADIO_PARAM_LAST_RSSI:
*value = rssi;
return RADIO_RESULT_OK;
case RADIO_PARAM_LAST_LINK_QUALITY:
*value = crc_corr & LQI_BIT_MASK;
return RADIO_RESULT_OK;
case RADIO_CONST_CHANNEL_MIN:
*value = CC2538_RF_CHANNEL_MIN;
return RADIO_RESULT_OK;
@ -854,13 +914,21 @@ set_value(radio_param_t param, radio_value_t value)
return RADIO_RESULT_OK;
case RADIO_PARAM_RX_MODE:
if(value & ~(RADIO_RX_MODE_ADDRESS_FILTER |
RADIO_RX_MODE_AUTOACK)) {
RADIO_RX_MODE_AUTOACK |
RADIO_RX_MODE_POLL_MODE)) {
return RADIO_RESULT_INVALID_VALUE;
}
set_frame_filtering((value & RADIO_RX_MODE_ADDRESS_FILTER) != 0);
set_auto_ack((value & RADIO_RX_MODE_AUTOACK) != 0);
set_poll_mode((value & RADIO_RX_MODE_POLL_MODE) != 0);
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 < OUTPUT_POWER_MIN || value > OUTPUT_POWER_MAX) {
@ -895,6 +963,15 @@ get_object(radio_param_t param, void *dest, size_t size)
return RADIO_RESULT_OK;
}
if(param == RADIO_PARAM_LAST_PACKET_TIMESTAMP) {
if(size != sizeof(rtimer_clock_t) || !dest) {
return RADIO_RESULT_INVALID_VALUE;
}
*(rtimer_clock_t*)dest = get_sfd_timestamp();
return RADIO_RESULT_OK;
}
return RADIO_RESULT_NOT_SUPPORTED;
}
/*---------------------------------------------------------------------------*/
@ -950,15 +1027,18 @@ PROCESS_THREAD(cc2538_rf_process, ev, data)
PROCESS_BEGIN();
while(1) {
PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
/* Only if we are not in poll mode oder we are in poll mode and transceiver has to be reset */
PROCESS_YIELD_UNTIL((!poll_mode || (poll_mode && (rf_flags & RF_MUST_RESET))) && (ev == PROCESS_EVENT_POLL));
packetbuf_clear();
len = read(packetbuf_dataptr(), PACKETBUF_SIZE);
if(!poll_mode) {
packetbuf_clear();
len = read(packetbuf_dataptr(), PACKETBUF_SIZE);
if(len > 0) {
packetbuf_set_datalen(len);
if(len > 0) {
packetbuf_set_datalen(len);
NETSTACK_RDC.input();
NETSTACK_RDC.input();
}
}
/* If we were polled due to an RF error, reset the transceiver */
@ -995,8 +1075,10 @@ void
cc2538_rf_rx_tx_isr(void)
{
ENERGEST_ON(ENERGEST_TYPE_IRQ);
process_poll(&cc2538_rf_process);
if(!poll_mode) {
process_poll(&cc2538_rf_process);
}
/* We only acknowledge FIFOP so we can safely wipe out the entire SFR */
REG(RFCORE_SFR_RFIRQF0) = 0;
@ -1045,4 +1127,44 @@ cc2538_rf_set_promiscous_mode(char p)
set_frame_filtering(p);
}
/*---------------------------------------------------------------------------*/
uint32_t get_sfd_timestamp(void)
{
uint64_t sfd, timer_val, buffer;
REG(RFCORE_SFR_MTMSEL) = (REG(RFCORE_SFR_MTMSEL) & ~RFCORE_SFR_MTMSEL_MTMSEL) | 0x00000000;
REG(RFCORE_SFR_MTCTRL) |= RFCORE_SFR_MTCTRL_LATCH_MODE;
timer_val = REG(RFCORE_SFR_MTM0) & RFCORE_SFR_MTM0_MTM0;
timer_val |= ((REG(RFCORE_SFR_MTM1) & RFCORE_SFR_MTM1_MTM1) << 8);
REG(RFCORE_SFR_MTMSEL) = (REG(RFCORE_SFR_MTMSEL) & ~RFCORE_SFR_MTMSEL_MTMOVFSEL) | 0x00000000;
timer_val |= ((REG(RFCORE_SFR_MTMOVF0) & RFCORE_SFR_MTMOVF0_MTMOVF0) << 16);
timer_val |= ((REG(RFCORE_SFR_MTMOVF1) & RFCORE_SFR_MTMOVF1_MTMOVF1) << 24);
buffer = REG(RFCORE_SFR_MTMOVF2) & RFCORE_SFR_MTMOVF2_MTMOVF2;
timer_val |= (buffer << 32);
REG(RFCORE_SFR_MTMSEL) = (REG(RFCORE_SFR_MTMSEL) & ~RFCORE_SFR_MTMSEL_MTMSEL) | 0x00000001;
REG(RFCORE_SFR_MTCTRL) |= RFCORE_SFR_MTCTRL_LATCH_MODE;
sfd = REG(RFCORE_SFR_MTM0) & RFCORE_SFR_MTM0_MTM0;
sfd |= ((REG(RFCORE_SFR_MTM1) & RFCORE_SFR_MTM1_MTM1) << 8);
REG(RFCORE_SFR_MTMSEL) = (REG(RFCORE_SFR_MTMSEL) & ~RFCORE_SFR_MTMSEL_MTMOVFSEL) | 0x00000010;
sfd |= ((REG(RFCORE_SFR_MTMOVF0) & RFCORE_SFR_MTMOVF0_MTMOVF0) << 16);
sfd |= ((REG(RFCORE_SFR_MTMOVF1) & RFCORE_SFR_MTMOVF1_MTMOVF1) << 24);
buffer = REG(RFCORE_SFR_MTMOVF2) & RFCORE_SFR_MTMOVF2_MTMOVF2;
sfd |= (buffer << 32);
return (RTIMER_NOW() - RADIO_TO_RTIMER(timer_val - sfd));
}
/*---------------------------------------------------------------------------*/
void mac_timer_init(void)
{
CLOCK_STABLE();
REG(RFCORE_SFR_MTCTRL) |= RFCORE_SFR_MTCTRL_SYNC;
REG(RFCORE_SFR_MTCTRL) |= RFCORE_SFR_MTCTRL_RUN;
while(!(REG(RFCORE_SFR_MTCTRL) & RFCORE_SFR_MTCTRL_STATE));
REG(RFCORE_SFR_MTCTRL) &= ~RFCORE_SFR_MTCTRL_RUN;
while(REG(RFCORE_SFR_MTCTRL) & RFCORE_SFR_MTCTRL_STATE);
REG(RFCORE_SFR_MTCTRL) |= RFCORE_SFR_MTCTRL_SYNC;
REG(RFCORE_SFR_MTCTRL) |= (RFCORE_SFR_MTCTRL_RUN);
while(!(REG(RFCORE_SFR_MTCTRL) & RFCORE_SFR_MTCTRL_STATE));
}
/*---------------------------------------------------------------------------*/
/** @} */

View file

@ -65,6 +65,20 @@
#define RTIMER_ARCH_SECOND 32768
/* Do the math in 32bits to save precision.
* Round to nearest integer rather than truncate. */
#define US_TO_RTIMERTICKS(US) ((US) >= 0 ? \
(((int32_t)(US) * (RTIMER_ARCH_SECOND) + 500000) / 1000000L) : \
((int32_t)(US) * (RTIMER_ARCH_SECOND) - 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)))
/** \sa RTIMER_NOW() */
rtimer_clock_t rtimer_arch_now(void);

View file

@ -81,6 +81,15 @@ CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES) $(DEBUG_IO_SOURCEFILES)
TARGET_START_SOURCEFILES += fault-handlers.c $(TI_XXWARE_STARTUP_SRCS)
TARGET_STARTFILES = $(addprefix $(OBJECTDIR)/,$(call oname, $(TARGET_START_SOURCEFILES)))
PYTHON = python
BSL_FLAGS += -e -w -v
ifdef PORT
BSL_FLAGS += -p $(PORT)
endif
BSL = $(CONTIKI)/tools/cc2538-bsl/cc2538-bsl.py
### Don't treat the .elf as intermediate
.PRECIOUS: %.elf %.hex %.bin
@ -125,3 +134,31 @@ 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;}'
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)

View file

@ -55,8 +55,8 @@ typedef unsigned short uip_stats_t;
typedef uint32_t clock_time_t;
/* Core rtimer.h defaults to 16 bit timer unless RTIMER_CLOCK_LT is defined */
/* Core rtimer.h defaults to 16 bit timer unless RTIMER_CLOCK_DIFF is defined */
typedef unsigned long rtimer_clock_t;
#define RTIMER_CLOCK_LT(a,b) ((signed long)((a)-(b)) < 0)
#define RTIMER_CLOCK_DIFF(a,b) ((signed long)((a)-(b)))
#endif

View file

@ -0,0 +1,262 @@
ifndef NRF52_SDK_ROOT
$(error NRF52_SDK_ROOT not defined! You must specify where nRF52 SDK resides!)
endif
ifneq ($(filter %.flash erase,$(MAKECMDGOALS)),)
ifeq ($(NRF52_JLINK_PATH),)
NRF52_JLINK_PATH=$(shell location=$$(which JLinkExe) && dirname $$location)
endif
ifeq ($(NRF52_JLINK_PATH),)
$(error JLink not found in PATH and NRF52_JLINK_PATH path is not defined)
endif
endif
ifeq ($(CONTIKI_WITH_RIME),1)
$(error Rime stack is not supported!)
endif
ifneq ($(CONTIKI_WITH_IPV6),1)
$(error Only IPv6 stack is supported!)
endif
$(info SDK: $(NRF52_SDK_ROOT))
ifeq ($(NRF52_DK_REVISION),)
NRF52_DK_REVISION=pca10040
endif
ifneq ($(NRF52_WITHOUT_SOFTDEVICE),1)
ifeq ($(NRF52_SOFTDEVICE),)
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
else
LINKER_SCRIPT := $(CONTIKI_CPU)/ld/nrf52.ld
endif
OUTPUT_FILENAME := $(CONTIKI_PROJECT)
MAKEFILE_NAME := $(MAKEFILE_LIST)
MAKEFILE_DIR := $(dir $(MAKEFILE_NAME) )
TEMPLATE_PATH = $(NRF52_SDK_ROOT)/components/toolchain/gcc
OBJECT_DIRECTORY = $(OBJECTDIR)
LISTING_DIRECTORY := $(OBJECTDIR)
OUTPUT_BINARY_DIRECTORY := bin_$(TARGET)
MK := mkdir
RM := rm -rf
# Toolchain commands
CC := arm-none-eabi-gcc
AS := arm-none-eabi-as
AR := arm-none-eabi-ar
LD := arm-none-eabi-ld
NM := arm-none-eabi-nm
OBJDUMP := arm-none-eabi-objdump
OBJCOPY := arm-none-eabi-objcopy
SIZE := arm-none-eabi-size
# JLink
JLINK := $(NRF52_JLINK_PATH)/JLinkExe
JLINK_OPTS = -Device NRF52 -if swd -speed 1000
ifneq ($(NRF52_JLINK_SN),)
JLINK_OPTS += -SelectEmuBySN $(NRF52_JLINK_SN)
endif
#function for removing duplicates in a list
remduplicates = $(strip $(if $1,$(firstword $1) $(call remduplicates,$(filter-out $(firstword $1),$1))))
### CPU-dependent directories
CONTIKI_CPU_DIRS += . dev ble #compat
### CPU-dependent source files
CONTIKI_CPU_SOURCEFILES += clock.c rtimer-arch.c uart0.c putchar.c watchdog.c
ifneq ($(NRF52_WITHOUT_SOFTDEVICE),1)
CONTIKI_CPU_SOURCEFILES += ble-core.c ble-mac.c
endif
CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES)
#source common to all targets
C_SOURCE_FILES += $(NRF52_SDK_ROOT)/components/drivers_nrf/common/nrf_drv_common.c \
$(NRF52_SDK_ROOT)/components/drivers_nrf/gpiote/nrf_drv_gpiote.c \
$(NRF52_SDK_ROOT)/components/drivers_nrf/rtc/nrf_drv_rtc.c \
$(NRF52_SDK_ROOT)/components/drivers_nrf/clock/nrf_drv_clock.c \
$(NRF52_SDK_ROOT)/components/drivers_nrf/timer/nrf_drv_timer.c \
$(NRF52_SDK_ROOT)/components/drivers_nrf/wdt/nrf_drv_wdt.c \
$(NRF52_SDK_ROOT)/components/drivers_nrf/rng/nrf_drv_rng.c \
$(NRF52_SDK_ROOT)/components/drivers_nrf/delay/nrf_delay.c \
$(NRF52_SDK_ROOT)/components/drivers_nrf/uart/nrf_drv_uart.c \
$(NRF52_SDK_ROOT)/components/libraries/util/app_error.c \
$(NRF52_SDK_ROOT)/components/toolchain/system_nrf52.c
ifneq ($(NRF52_WITHOUT_SOFTDEVICE),1)
C_SOURCE_FILES += $(NRF52_SDK_ROOT)/components/softdevice/common/softdevice_handler/softdevice_handler.c \
$(NRF52_SDK_ROOT)/components/ble/common/ble_advdata.c
else
C_SOURCE_FILES += $(NRF52_SDK_ROOT)/components/libraries/fifo/app_fifo.c \
$(NRF52_SDK_ROOT)/components/libraries/util/app_util_platform.c
endif
#assembly files common to all targets
ASM_SOURCE_FILES = $(NRF52_SDK_ROOT)/components/toolchain/gcc/gcc_startup_nrf52.s
#includes common to all targets
INC_PATHS += components/drivers_nrf/gpiote
INC_PATHS += components/drivers_nrf/hal
INC_PATHS += components/drivers_nrf/config
INC_PATHS += components/drivers_nrf/delay
INC_PATHS += components/drivers_nrf/uart
INC_PATHS += components/drivers_nrf/common
INC_PATHS += components/drivers_nrf/rtc
INC_PATHS += components/drivers_nrf/wdt
INC_PATHS += components/drivers_nrf/rng
INC_PATHS += components/drivers_nrf/clock
INC_PATHS += components/drivers_nrf/timer
INC_PATHS += components/libraries/util
INC_PATHS += components/libraries/timer
INC_PATHS += components/device
INC_PATHS += components/toolchain/gcc
INC_PATHS += components/toolchain
INC_PATHS += examples/bsp
ifneq ($(NRF52_WITHOUT_SOFTDEVICE),1)
INC_PATHS += components/softdevice/s1xx_iot/headers
INC_PATHS += components/softdevice/s1xx_iot/headers/nrf52
INC_PATHS += components/softdevice/common/softdevice_handler
INC_PATHS += components/ble/common
INC_PATHS += components/iot/common
INC_PATHS += components/iot/ble_ipsp
else
INC_PATHS += components/drivers_nrf/nrf_soc_nosd
INC_PATHS += components/libraries/fifo
endif
EXTERNALDIRS += $(addprefix $(NRF52_SDK_ROOT)/, $(INC_PATHS))
# Sorting removes duplicates
BUILD_DIRECTORIES := $(sort $(OUTPUT_BINARY_DIRECTORY) $(LISTING_DIRECTORY))
# Clean files and directories
CLEAN += bin_$(TARGET) lst_$(TARGET) nrf52832.a *.elf *.hex
#flags common to all targets
ifneq ($(NRF52_WITHOUT_SOFTDEVICE),1)
CFLAGS += -DSOFTDEVICE_PRESENT
CFLAGS += -DS132
endif
ifeq ($(SMALL),1)
CFLAGS += -Os
else
CFLAGS += -O2
endif
CFLAGS += -DNRF52
CFLAGS += -DBOARD_$(shell echo $(NRF52_DK_REVISION) | tr a-z A-Z)
CFLAGS += -D__HEAP_SIZE=512
CFLAGS += -DSWI_DISABLE0
CFLAGS += -DCONFIG_GPIO_AS_PINRESET
CFLAGS += -DBLE_STACK_SUPPORT_REQD
CFLAGS += -mcpu=cortex-m4
CFLAGS += -mthumb -mabi=aapcs --std=gnu99
CFLAGS += -Wall -Werror
CFLAGS += -ggdb
CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
# keep every function in separate section. This will allow linker to dump unused functions
CFLAGS += -ffunction-sections -fdata-sections -fno-strict-aliasing
CFLAGS += -fno-builtin --short-enums
# keep every function in separate section. This will allow linker to dump unused functions
LDFLAGS += -Xlinker -Map=$(LISTING_DIRECTORY)/$(OUTPUT_FILENAME).map
LDFLAGS += -mthumb -mabi=aapcs -L $(TEMPLATE_PATH) -T$(LINKER_SCRIPT)
LDFLAGS += -mcpu=cortex-m4
LDFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
# let linker to dump unused sections
LDFLAGS += -Wl,--gc-sections
# use newlib in nano version
LDFLAGS += --specs=nano.specs -lc -lnosys
# Assembler flags
ifneq ($(NRF52_WITHOUT_SOFTDEVICE),1)
ASMFLAGS += -DSOFTDEVICE_PRESENT
ASMFLAGS += -DS132
endif
ASMFLAGS += -x assembler-with-cpp
ASMFLAGS += -DSWI_DISABLE0
ASMFLAGS += -DNRF52
ASMFLAGS += -DBOARD_$(shell echo $(NRF52_DK_REVISION) | tr a-z A-Z)
ASMFLAGS += -DCONFIG_GPIO_AS_PINRESET
ASMFLAGS += -DBLE_STACK_SUPPORT_REQD
C_SOURCE_FILE_NAMES = $(notdir $(C_SOURCE_FILES))
C_PATHS = $(call remduplicates, $(dir $(C_SOURCE_FILES) ) )
C_OBJECTS = $(addprefix $(OBJECT_DIRECTORY)/, $(C_SOURCE_FILE_NAMES:.c=.o) )
ASM_SOURCE_FILE_NAMES = $(notdir $(ASM_SOURCE_FILES))
ASM_PATHS = $(call remduplicates, $(dir $(ASM_SOURCE_FILES) ))
ASM_OBJECTS = $(addprefix $(OBJECT_DIRECTORY)/, $(ASM_SOURCE_FILE_NAMES:.s=.o) )
vpath %.c $(C_PATHS)
vpath %.s $(ASM_PATHS)
OBJECTS = $(C_OBJECTS) $(ASM_OBJECTS)
TARGET_LIBS= nrf52832.a $(NRF52_SDK_ROOT)/components/iot/ble_6lowpan/lib/ble_6lowpan.a
### Don't treat the .elf as intermediate
.PRECIOUS: %.hex %.bin
nrf52832.a: $(OBJECTS)
$(TRACE_AR)
$(Q)$(AR) $(AROPTS) $@ $^
### Compilation rules
CUSTOM_RULE_LINK=1
%.elf: $(TARGET_STARTFILES) %.co $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) contiki-$(TARGET).a $(TARGET_LIBS)
$(TRACE_LD)
$(Q)$(CC) $(LDFLAGS) ${filter %o %.co %.a,$^} -o $@
# Assemble files
$(OBJECT_DIRECTORY)/%.o: %.s
@echo Compiling file: $(notdir $<)
$(Q)$(CC) $(ASMFLAGS) $(addprefix -I$(NRF52_SDK_ROOT)/, $(INC_PATHS)) -c -o $@ $<
# Create binary file from the .out file
%.bin: %.elf
@echo Preparing: $@
$(Q)$(OBJCOPY) -O binary $^ $@
# Create binary .hex file from the .out file
%.hex: %.elf
@echo Preparing: $@
$(Q)$(OBJCOPY) -O ihex $^ $@
### 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 $*.elf $@
$(Q)$(SIZE) $@
%.jlink:
sed -e 's/#OUTPUT_FILENAME#/$*.hex/' $(CONTIKI_CPU)/flash.jlink > $@
%.flash: %.hex %.jlink
@echo Flashing: $^
$(JLINK) $(JLINK_OPTS) -CommanderScript $*.jlink
softdevice.jlink:
sed -e 's,#OUTPUT_FILENAME#,$(NRF52_SOFTDEVICE),' $(CONTIKI_CPU)/flash.jlink > $@
softdevice.flash: softdevice.jlink
@echo Flashing: $(notdir $(NRF52_SOFTDEVICE))
$(JLINK) $(JLINK_OPTS) -CommanderScript $^
erase:
$(JLINK) $(JLINK_OPTS) -CommanderScript $(CONTIKI_CPU)/erase.jlink
.PHONY: softdevice.jlink

238
cpu/nrf52832/ble/ble-core.c Normal file
View file

@ -0,0 +1,238 @@
/*
* Copyright (c) 2015, Nordic Semiconductor
* 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 cpu
* @{
*
* \addtogroup nrf52832
* @{
*
* \addtogroup nrf52832-ble Bluetooth Low Energy drivers
* @{
*
* \file
* Basic BLE functions.
* \author
* Wojciech Bober <wojciech.bober@nordicsemi.no>
*
*/
#include <stdbool.h>
#include <stdint.h>
#include "boards.h"
#include "nordic_common.h"
#include "nrf_delay.h"
#include "nrf_sdm.h"
#include "ble_advdata.h"
#include "ble_srv_common.h"
#include "ble_ipsp.h"
#include "softdevice_handler.h"
#include "app_error.h"
#include "iot_defines.h"
#include "ble-core.h"
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...)
#endif
#define IS_SRVC_CHANGED_CHARACT_PRESENT 1
#define APP_ADV_TIMEOUT 0 /**< Time for which the device must be advertising in non-connectable mode (in seconds). 0 disables timeout. */
#define APP_ADV_ADV_INTERVAL MSEC_TO_UNITS(333, UNIT_0_625_MS) /**< The advertising interval. This value can vary between 100ms to 10.24s). */
static ble_gap_adv_params_t m_adv_params; /**< Parameters to be passed to the stack when starting advertising. */
static void
ble_evt_dispatch(ble_evt_t * p_ble_evt);
/*---------------------------------------------------------------------------*/
/**
* \brief Initialize and enable the BLE stack.
*/
void
ble_stack_init(void)
{
uint32_t err_code;
// Enable BLE stack.
ble_enable_params_t ble_enable_params;
memset(&ble_enable_params, 0, sizeof(ble_enable_params));
ble_enable_params.gatts_enable_params.attr_tab_size =
BLE_GATTS_ATTR_TAB_SIZE_DEFAULT;
ble_enable_params.gatts_enable_params.service_changed =
IS_SRVC_CHANGED_CHARACT_PRESENT;
err_code = sd_ble_enable(&ble_enable_params);
APP_ERROR_CHECK(err_code);
// Register with the SoftDevice handler module for BLE events.
err_code = softdevice_ble_evt_handler_set(ble_evt_dispatch);
APP_ERROR_CHECK(err_code);
// Setup address
ble_gap_addr_t ble_addr;
err_code = sd_ble_gap_address_get(&ble_addr);
APP_ERROR_CHECK(err_code);
ble_addr.addr[5] = 0x00;
ble_addr.addr_type = BLE_GAP_ADDR_TYPE_PUBLIC;
err_code = sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_NONE, &ble_addr);
APP_ERROR_CHECK(err_code);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Return device EUI64 MAC address
* \param addr pointer to a buffer to store the address
*/
void
ble_get_mac(uint8_t addr[8])
{
uint32_t err_code;
ble_gap_addr_t ble_addr;
err_code = sd_ble_gap_address_get(&ble_addr);
APP_ERROR_CHECK(err_code);
IPV6_EUI64_CREATE_FROM_EUI48(addr, ble_addr.addr, ble_addr.addr_type);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Initialize BLE advertising data.
* \param name Human readable device name that will be advertised
*/
void
ble_advertising_init(const char *name)
{
uint32_t err_code;
ble_advdata_t advdata;
uint8_t flags = BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED;
ble_gap_conn_sec_mode_t sec_mode;
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
err_code = sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *)name,
strlen(name));
APP_ERROR_CHECK(err_code);
ble_uuid_t adv_uuids[] = {{BLE_UUID_IPSP_SERVICE, BLE_UUID_TYPE_BLE}};
// Build and set advertising data.
memset(&advdata, 0, sizeof(advdata));
advdata.name_type = BLE_ADVDATA_FULL_NAME;
advdata.flags = flags;
advdata.uuids_complete.uuid_cnt = sizeof(adv_uuids) / sizeof(adv_uuids[0]);
advdata.uuids_complete.p_uuids = adv_uuids;
err_code = ble_advdata_set(&advdata, NULL);
APP_ERROR_CHECK(err_code);
// Initialize advertising parameters (used when starting advertising).
memset(&m_adv_params, 0, sizeof(m_adv_params));
m_adv_params.type = BLE_GAP_ADV_TYPE_ADV_IND;
m_adv_params.p_peer_addr = NULL; // Undirected advertisement.
m_adv_params.fp = BLE_GAP_ADV_FP_ANY;
m_adv_params.interval = APP_ADV_ADV_INTERVAL;
m_adv_params.timeout = APP_ADV_TIMEOUT;
}
/*---------------------------------------------------------------------------*/
/**
* \brief Start BLE advertising.
*/
void
ble_advertising_start(void)
{
uint32_t err_code;
err_code = sd_ble_gap_adv_start(&m_adv_params);
APP_ERROR_CHECK(err_code);
PRINTF("ble-core: advertising started\n");
}
/*---------------------------------------------------------------------------*/
/**
* \brief Print GAP address.
* \param addr a pointer to address
*/
void
ble_gap_addr_print(const ble_gap_addr_t *addr)
{
unsigned int i;
for(i = 0; i < sizeof(addr->addr); i++) {
if(i > 0) {
PRINTF(":");
}PRINTF("%02x", addr->addr[i]);
}PRINTF(" (%d)", addr->addr_type);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Function for handling the Application's BLE Stack events.
* \param[in] p_ble_evt Bluetooth stack event.
*/
static void
on_ble_evt(ble_evt_t *p_ble_evt)
{
switch(p_ble_evt->header.evt_id) {
case BLE_GAP_EVT_CONNECTED:
PRINTF("ble-core: connected [handle:%d, peer: ", p_ble_evt->evt.gap_evt.conn_handle);
ble_gap_addr_print(&(p_ble_evt->evt.gap_evt.params.connected.peer_addr));
PRINTF("]\n");
sd_ble_gap_rssi_start(p_ble_evt->evt.gap_evt.conn_handle,
BLE_GAP_RSSI_THRESHOLD_INVALID,
0);
break;
case BLE_GAP_EVT_DISCONNECTED:
PRINTF("ble-core: disconnected [handle:%d]\n", p_ble_evt->evt.gap_evt.conn_handle);
ble_advertising_start();
break;
default:
break;
}
}
/*---------------------------------------------------------------------------*/
/**
* \brief SoftDevice BLE event callback.
* \param[in] p_ble_evt Bluetooth stack event.
*/
static void
ble_evt_dispatch(ble_evt_t *p_ble_evt)
{
ble_ipsp_evt_handler(p_ble_evt);
on_ble_evt(p_ble_evt);
}
/*---------------------------------------------------------------------------*/
/**
* @}
* @}
* @}
*/

View file

@ -0,0 +1,61 @@
/*
* Copyright (c) 2015, Nordic Semiconductor
* 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 cpu
* @{
*
* \addtogroup nrf52832
* @{
*
* \addtogroup nrf52832-ble Bluetooth Low Energy drivers
* @{
*
* \file
* Basic BLE functions.
* \author
* Wojciech Bober <wojciech.bober@nordicsemi.no>
*/
#ifndef DEV_BLE_H_
#define DEV_BLE_H_
#include <stdint.h>
void ble_stack_init(void);
void ble_advertising_init(const char *name);
void ble_advertising_start(void);
void ble_get_mac(uint8_t addr[8]);
#endif /* DEV_BLE_H_ */
/**
* @}
* @}
* @}
*/

386
cpu/nrf52832/ble/ble-mac.c Normal file
View file

@ -0,0 +1,386 @@
/*
* Copyright (c) 2015, Nordic Semiconductor
* 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 nrf52832-ble
* @{
*
* \file
* A MAC protocol implementation that uses nRF52 IPSP implementation
* as a link layer.
* \author
* Wojciech Bober <wojciech.bober@nordicsemi.no>
*/
#include <stdint.h>
#include <ble-core.h>
#include "app_error.h"
#include "ble_ipsp.h"
#include "nrf_soc.h"
#include "iot_defines.h"
#include "net/mac/nullmac.h"
#include "net/netstack.h"
#include "net/ip/uip.h"
#include "net/ip/tcpip.h"
#include "net/packetbuf.h"
#include "net/netstack.h"
#include "net/linkaddr.h"
#include "dev/watchdog.h"
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...)
#endif
#ifndef BLE_MAC_MAX_INTERFACE_NUM
#define BLE_MAC_MAX_INTERFACE_NUM 1 /**< Maximum number of interfaces, i.e., connection to master devices */
#endif
/*---------------------------------------------------------------------------*/
process_event_t ble_event_interface_added; /**< This event is broadcast when BLE connection is established */
process_event_t ble_event_interface_deleted; /**< This event is broadcast when BLE connection is destroyed */
/*---------------------------------------------------------------------------*/
PROCESS(ble_ipsp_process, "BLE IPSP process");
/*---------------------------------------------------------------------------*/
/**
* \brief A structure that binds IPSP connection with a peer address.
*/
typedef struct {
eui64_t peer_addr;
ble_ipsp_handle_t handle;
} ble_mac_interface_t;
static ble_mac_interface_t interfaces[BLE_MAC_MAX_INTERFACE_NUM];
static volatile int busy_tx; /**< Flag is set to 1 when the driver is busy transmitting a packet. */
static volatile int busy_rx; /**< Flag is set to 1 when there is a received packet pending. */
struct {
eui64_t src;
uint8_t payload[PACKETBUF_SIZE];
uint16_t len;
int8_t rssi;
} input_packet;
static mac_callback_t mac_sent_cb;
static void *mac_sent_ptr;
/*---------------------------------------------------------------------------*/
/**
* \brief Lookup interface by IPSP connection.
*
* \param handle a pointer to IPSP handle.
* \retval a pointer to interface structure
* \retval NULL if no interface has been found for a given handle
*/
static ble_mac_interface_t *
ble_mac_interface_lookup(ble_ipsp_handle_t *handle)
{
int i;
for(i = 0; i < BLE_MAC_MAX_INTERFACE_NUM; i++) {
if(interfaces[i].handle.conn_handle == handle->conn_handle &&
interfaces[i].handle.cid == handle->cid) {
return &interfaces[i];
}
}
return NULL;
}
/*---------------------------------------------------------------------------*/
/**
* \brief Add IPSP connection to the interface table.
*
* This function binds IPSP connection with peer address.
*
* \param peer a pointer to eui64 address
* \param handle a pointer to IPSP handle
*
* \retval a pointer to an interface structure on success
* \retval NULL if interface table is full
*/
static ble_mac_interface_t *
ble_mac_interface_add(eui64_t *peer, ble_ipsp_handle_t *handle)
{
int i;
for(i = 0; i < BLE_MAC_MAX_INTERFACE_NUM; i++) {
if(interfaces[i].handle.conn_handle == 0 && interfaces[i].handle.cid == 0) {
memcpy(&interfaces[i].handle, handle, sizeof(ble_ipsp_handle_t));
memcpy(&interfaces[i].peer_addr, peer, sizeof(eui64_t));
process_post(PROCESS_BROADCAST, ble_event_interface_added, NULL);
return &interfaces[i];
}
}
return NULL;
}
/*---------------------------------------------------------------------------*/
/**
* \brief Remove interface from the interface table.
* \param interface a pointer to interface
*/
static void
ble_mac_interface_delete(ble_mac_interface_t *interface)
{
memset(interface, 0, sizeof(ble_mac_interface_t));
process_post(PROCESS_BROADCAST, ble_event_interface_deleted, NULL);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Callback registered with IPSP to receive asynchronous events from the module.
* \note This function is called from SoftDevice interrupt context.
*
* \param[in] p_handle Pointer to IPSP handle.
* \param[in] p_evt Pointer to specific event, generated by IPSP module.
*
* \return NRF_SUCCESS on success, otherwise NRF_ERROR_NO_MEM error.
*/
static uint32_t
ble_mac_ipsp_evt_handler_irq(ble_ipsp_handle_t *p_handle, ble_ipsp_evt_t *p_evt)
{
uint32_t retval = NRF_SUCCESS;
ble_mac_interface_t *p_instance = NULL;
p_instance = ble_mac_interface_lookup(p_handle);
if(p_handle) {
PRINTF("ble-mac: IPSP event [handle:%d CID 0x%04X]\n", p_handle->conn_handle, p_handle->cid);
}
switch(p_evt->evt_id) {
case BLE_IPSP_EVT_CHANNEL_CONNECTED: {
eui64_t peer_addr;
PRINTF("ble-mac: channel connected\n");
IPV6_EUI64_CREATE_FROM_EUI48(
peer_addr.identifier,
p_evt->evt_param->params.ch_conn_request.peer_addr.addr,
p_evt->evt_param->params.ch_conn_request.peer_addr.addr_type);
p_instance = ble_mac_interface_add(&peer_addr, p_handle);
if(p_instance != NULL) {
PRINTF("ble-mac: added new IPSP interface\n");
} else {
PRINTF("ble-mac: cannot add new interface. Table is full\n");
ble_ipsp_disconnect(p_handle);
}
break;
}
case BLE_IPSP_EVT_CHANNEL_DISCONNECTED: {
PRINTF("ble-mac: channel disconnected\n");
if(p_instance != NULL) {
PRINTF("ble-mac: removed IPSP interface\n");
ble_mac_interface_delete(p_instance);
}
break;
}
case BLE_IPSP_EVT_CHANNEL_DATA_RX: {
PRINTF("ble-mac: data received\n");
if(p_instance != NULL) {
if(busy_rx) {
PRINTF("ble-mac: packet dropped as input buffer is busy\n");
break;
}
if(p_evt->evt_param->params.ch_rx.len > PACKETBUF_SIZE) {
PRINTF("ble-mac: packet buffer is too small!\n");
break;
}
busy_rx = 1;
input_packet.len = p_evt->evt_param->params.ch_rx.len;
memcpy(input_packet.payload, p_evt->evt_param->params.ch_rx.p_data, input_packet.len);
memcpy(input_packet.src.identifier, p_instance->peer_addr.identifier, sizeof(eui64_t));
sd_ble_gap_rssi_get(p_handle->conn_handle, &input_packet.rssi);
process_poll(&ble_ipsp_process);
} else {
PRINTF("ble-mac: got data to unknown interface!\n");
}
break;
}
case BLE_IPSP_EVT_CHANNEL_DATA_TX_COMPLETE: {
PRINTF("ble-mac: data transmitted\n");
busy_tx = 0;
break;
}
}
return retval;
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(ble_ipsp_process, ev, data)
{
PROCESS_BEGIN();
while(1) {
PROCESS_WAIT_EVENT();
if(ev == PROCESS_EVENT_POLL) {
packetbuf_copyfrom(input_packet.payload, input_packet.len);
packetbuf_set_attr(PACKETBUF_ATTR_RSSI, input_packet.rssi);
packetbuf_set_addr(PACKETBUF_ADDR_SENDER, (const linkaddr_t *)input_packet.src.identifier);
packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &linkaddr_node_addr);
busy_rx = 0;
NETSTACK_LLSEC.input();
}
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
/**
* \brief Lookup IPSP handle by peer address.
*
* \param addr a pointer to eui64 address.
* \retval a pointer to IPSP handle on success
* \retval NULL if an IPSP handle for given address haven't been found
*/
static ble_ipsp_handle_t *
find_handle(const linkaddr_t *addr)
{
int i;
for(i = 0; i < BLE_MAC_MAX_INTERFACE_NUM; i++) {
if(linkaddr_cmp((const linkaddr_t *)&interfaces[i].peer_addr, addr)) {
return &interfaces[i].handle;
}
}
return NULL;
}
/*---------------------------------------------------------------------------*/
/**
* \brief Send packet on a given IPSP handle.
*
* \param handle a pointer to IPSP handle.
* \return 1 on success, 0 otherwise
*/
static int
send_to_peer(ble_ipsp_handle_t *handle)
{
PRINTF("ble-mac: sending packet[GAP handle:%d CID:0x%04X]\n", handle->conn_handle, handle->cid);
return (ble_ipsp_send(handle, packetbuf_dataptr(), packetbuf_datalen()) == NRF_SUCCESS);
}
/*---------------------------------------------------------------------------*/
static void
send_packet(mac_callback_t sent, void *ptr)
{
int i;
const linkaddr_t *dest;
ble_ipsp_handle_t *handle;
int ret = 0;
mac_sent_cb = sent;
mac_sent_ptr = ptr;
dest = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
if(linkaddr_cmp(dest, &linkaddr_null)) {
for(i = 0; i < BLE_MAC_MAX_INTERFACE_NUM; i++) {
if(interfaces[i].handle.cid != 0 && interfaces[i].handle.conn_handle != 0) {
ret = send_to_peer(&interfaces[i].handle);
watchdog_periodic();
}
}
} else if((handle = find_handle(dest)) != NULL) {
ret = send_to_peer(handle);
} else {
PRINTF("ble-mac: no connection found for peer");
}
if(ret) {
busy_tx = 1;
while(busy_tx) {
watchdog_periodic();
sd_app_evt_wait();
}
mac_call_sent_callback(sent, ptr, MAC_TX_OK, 1);
} else {
mac_call_sent_callback(sent, ptr, MAC_TX_ERR, 1);
}
}
/*---------------------------------------------------------------------------*/
static int
on(void)
{
return 1;
}
/*---------------------------------------------------------------------------*/
static int
off(int keep_radio_on)
{
return 1;
}
/*---------------------------------------------------------------------------*/
static unsigned short
channel_check_interval(void)
{
return 0;
}
/*---------------------------------------------------------------------------*/
static void
init(void)
{
// Initialize IPSP service
uint32_t err_code;
ble_ipsp_init_t ipsp_init_params;
memset(&ipsp_init_params, 0, sizeof(ipsp_init_params));
ipsp_init_params.evt_handler = ble_mac_ipsp_evt_handler_irq;
err_code = ble_ipsp_init(&ipsp_init_params);
APP_ERROR_CHECK(err_code);
ble_event_interface_added = process_alloc_event();
ble_event_interface_deleted = process_alloc_event();
process_start(&ble_ipsp_process, NULL);
}
/*---------------------------------------------------------------------------*/
const struct mac_driver ble_ipsp_mac_driver = {
"nRF52 IPSP driver",
init,
send_packet,
NULL,
on,
off,
channel_check_interval,
};
/*---------------------------------------------------------------------------*/
/**
* @}
*/

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2015, Nordic Semiconductor
* 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 nrf52832-ble
* @{
*
* \file
* A MAC protocol implementation that uses nRF52 IPSP implementation
* as a link layer.
* \author
* Wojciech Bober <wojciech.bober@nordicsemi.no>
*/
#ifndef BLE_MAC_H_
#define BLE_MAC_H_
#include "sys/process.h"
#include "net/mac/mac.h"
extern const struct mac_driver ble_ipsp_mac_driver; /**< BLE over IPSP MAC driver structure */
extern process_event_t ble_event_interface_added; /**< This event is broadcast when a new IPSP connection is established */
extern process_event_t ble_event_interface_deleted; /**< This event is broadcast when a IPSP connection is deleted */
#endif /* BLE_MAC_H_ */
/**
* @}
*/

171
cpu/nrf52832/dev/clock.c Normal file
View file

@ -0,0 +1,171 @@
/*
* Copyright (c) 2015 Nordic Semiconductor. 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 nrf52832
* @{
*
* \addtogroup nrf52832-dev Device drivers
* @{
*
* \addtogroup nrf52832-clock Clock driver
* @{
*
* \file
* Software clock implementation for the nRF52.
* \author
* Wojciech Bober <wojciech.bober@nordicsemi.no>
*
*/
/*---------------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include "nrf.h"
#include "nrf_drv_config.h"
#include "nrf_drv_rtc.h"
#include "nrf_drv_clock.h"
#include "nrf_delay.h"
#include "app_error.h"
#include "contiki.h"
#include "platform-conf.h"
/*---------------------------------------------------------------------------*/
const nrf_drv_rtc_t rtc = NRF_DRV_RTC_INSTANCE(PLATFORM_RTC_INSTANCE_ID); /**< RTC instance used for platform clock */
/*---------------------------------------------------------------------------*/
static volatile uint32_t ticks;
void clock_update(void);
#define TICKS (RTC1_CONFIG_FREQUENCY/CLOCK_CONF_SECOND)
/**
* \brief Function for handling the RTC0 interrupts
* \param int_type Type of interrupt to be handled
*/
static void
rtc_handler(nrf_drv_rtc_int_type_t int_type)
{
if (int_type == NRF_DRV_RTC_INT_TICK) {
clock_update();
}
}
#ifndef SOFTDEVICE_PRESENT
/** \brief Function starting the internal LFCLK XTAL oscillator.
*/
static void
lfclk_config(void)
{
ret_code_t err_code = nrf_drv_clock_init(NULL);
APP_ERROR_CHECK(err_code);
nrf_drv_clock_lfclk_request();
}
#endif
/**
* \brief Function initialization and configuration of RTC driver instance.
*/
static void
rtc_config(void)
{
uint32_t err_code;
//Initialize RTC instance
err_code = nrf_drv_rtc_init(&rtc, NULL, rtc_handler);
APP_ERROR_CHECK(err_code);
//Enable tick event & interrupt
nrf_drv_rtc_tick_enable(&rtc, true);
//Power on RTC instance
nrf_drv_rtc_enable(&rtc);
}
/*---------------------------------------------------------------------------*/
void
clock_init(void)
{
ticks = 0;
#ifndef SOFTDEVICE_PRESENT
lfclk_config();
#endif
rtc_config();
}
/*---------------------------------------------------------------------------*/
CCIF clock_time_t
clock_time(void)
{
return (clock_time_t)(ticks & 0xFFFFFFFF);
}
/*---------------------------------------------------------------------------*/
void
clock_update(void)
{
ticks++;
if (etimer_pending()) {
etimer_request_poll();
}
}
/*---------------------------------------------------------------------------*/
CCIF unsigned long
clock_seconds(void)
{
return (unsigned long)ticks/CLOCK_CONF_SECOND;
}
/*---------------------------------------------------------------------------*/
void
clock_wait(clock_time_t i)
{
clock_time_t start;
start = clock_time();
while (clock_time() - start < (clock_time_t)i) {
__WFE();
}
}
/*---------------------------------------------------------------------------*/
void
clock_delay_usec(uint16_t dt)
{
nrf_delay_us(dt);
}
/*---------------------------------------------------------------------------*/
/**
* \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);
}
/*---------------------------------------------------------------------------*/
/**
* @}
* @}
* @}
*/

67
cpu/nrf52832/dev/lpm.h Normal file
View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2015, Nordic Semiconductor
* 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 nrf52832-dev Device drivers
* @{
*
* \addtogroup nrf52832-lpm Low power mode functions
* @{
*
* \file
* A header file for low power mode functions.
* \author
* Wojciech Bober <wojciech.bober@nordicsemi.no>
*/
#ifndef LPM_H
#define LPM_H
#ifdef SOFTDEVICE_PRESENT
#include "nrf_soc.h"
#endif
/**
* \brief Stop and wait for an event
*
*/
static inline void
lpm_drop(void)
{
#ifdef SOFTDEVICE_PRESENT
sd_app_evt_wait();
#else
__WFI();
#endif
}
#endif /* DEV_LPM_H_ */
/**
* @}
* @}
*/

90
cpu/nrf52832/dev/random.c Normal file
View file

@ -0,0 +1,90 @@
/*
* Copyright (c) 2015, Nordic Semiconductor
* 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 nrf52832
* @{
*
* \addtogroup nrf52832-dev Device drivers
* @{
*
* \addtogroup nrf52832-rng Hardware random number generator
* @{
*
* \file
* Random number generator routines exploiting the nRF52 hardware
* capabilities.
*
* This file overrides core/lib/random.c.
*
* \author
* Wojciech Bober <wojciech.bober@nordicsemi.no>
*/
#include <stddef.h>
#include <nrf_drv_rng.h>
#include "app_error.h"
/*---------------------------------------------------------------------------*/
/**
* \brief Generates a new random number using the nRF52 RNG.
* \return a random number.
*/
unsigned short
random_rand(void)
{
unsigned short value = 42;
uint8_t available;
ret_code_t err_code;
do {
nrf_drv_rng_bytes_available(&available);
} while (available < sizeof(value));
err_code = nrf_drv_rng_rand((uint8_t *)&value, sizeof(value));
APP_ERROR_CHECK(err_code);
return value;
}
/*---------------------------------------------------------------------------*/
/**
* \brief Initialize the nRF52 random number generator.
* \param seed Ignored. It's here because the function prototype is in core.
*
*/
void
random_init(unsigned short seed)
{
(void)seed;
ret_code_t err_code = nrf_drv_rng_init(NULL);
APP_ERROR_CHECK(err_code);
}
/**
* @}
* @}
* @}
*/

118
cpu/nrf52832/dev/uart0.c Normal file
View file

@ -0,0 +1,118 @@
/*
* Copyright (c) 2015, Nordic Semiconductor
* 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 nrf52832-dev Device drivers
* @{
*
* \addtogroup nrf52832-uart UART driver
* @{
*
* \file
* Contiki compatible UART driver.
* \author
* Wojciech Bober <wojciech.bober@nordicsemi.no>
*/
#include <stdlib.h>
#include "nrf.h"
#include "nrf_drv_config.h"
#include "nrf_drv_uart.h"
#include "app_util_platform.h"
#include "app_error.h"
#include "contiki.h"
#include "dev/uart0.h"
#include "dev/watchdog.h"
#include "lib/ringbuf.h"
#define TXBUFSIZE 128
static uint8_t rx_buffer[1];
static int (*uart0_input_handler)(unsigned char c);
static struct ringbuf txbuf;
static uint8_t txbuf_data[TXBUFSIZE];
/*---------------------------------------------------------------------------*/
static void
uart_event_handler(nrf_drv_uart_event_t * p_event, void * p_context)
{
ENERGEST_ON(ENERGEST_TYPE_IRQ);
if (p_event->type == NRF_DRV_UART_EVT_RX_DONE) {
if (uart0_input_handler != NULL) {
uart0_input_handler(p_event->data.rxtx.p_data[0]);
}
(void)nrf_drv_uart_rx(rx_buffer, 1);
} else if (p_event->type == NRF_DRV_UART_EVT_TX_DONE) {
if (ringbuf_elements(&txbuf) > 0) {
uint8_t c = ringbuf_get(&txbuf);
nrf_drv_uart_tx(&c, 1);
}
}
ENERGEST_OFF(ENERGEST_TYPE_IRQ);
}
/*---------------------------------------------------------------------------*/
void
uart0_set_input(int (*input)(unsigned char c))
{
uart0_input_handler = input;
}
/*---------------------------------------------------------------------------*/
void
uart0_writeb(unsigned char c)
{
if (nrf_drv_uart_tx(&c, 1) == NRF_ERROR_BUSY) {
while (ringbuf_put(&txbuf, c) == 0) {
__WFE();
}
}
}
/*---------------------------------------------------------------------------*/
/**
* Initialize the RS232 port.
*
*/
void
uart0_init(unsigned long ubr)
{
nrf_drv_uart_config_t config = NRF_DRV_UART_DEFAULT_CONFIG;
ret_code_t retcode = nrf_drv_uart_init(&config, uart_event_handler);
APP_ERROR_CHECK(retcode);
ringbuf_init(&txbuf, txbuf_data, sizeof(txbuf_data));
nrf_drv_uart_rx_enable();
nrf_drv_uart_rx(rx_buffer, 1);
}
/**
* @}
* @}
*/

57
cpu/nrf52832/dev/uart0.h Normal file
View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 2015, Nordic Semiconductor
* 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 nrf52832-dev Device drivers
* @{
*
* \addtogroup nrf52832-uart UART driver
* @{
*
* \file
* A header file for Contiki compatible UART driver.
* \author
* Wojciech Bober <wojciech.bober@nordicsemi.no>
*/
#ifndef UART_0_H
#define UART_0_H
#include <stdint.h>
#include "contiki-conf.h"
void uart0_init();
void uart0_writeb(uint8_t byte);
void uart0_set_input(int (* input)(unsigned char c));
#endif /* UART_0_H */
/**
* @}
* @}
*/

View file

@ -0,0 +1,93 @@
/*
* Copyright (c) 2015, Nordic Semiconductor
* 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 nrf52832-dev Device drivers
* @{
*
* \addtogroup nrf52832-watchdog Watchdog driver
* @{
*
* \file
* Contiki compatible watchdog driver implementation.
* \author
* Wojciech Bober <wojciech.bober@nordicsemi.no>
*/
#include <nrf_drv_wdt.h>
#include "app_error.h"
#include "contiki-conf.h"
static nrf_drv_wdt_channel_id wdt_channel_id;
static uint8_t wdt_initialized = 0;
/**
* \brief WDT events handler.
*/
static void wdt_event_handler(void)
{
LEDS_OFF(LEDS_MASK);
}
/*---------------------------------------------------------------------------*/
void
watchdog_init(void)
{
ret_code_t err_code;
err_code = nrf_drv_wdt_init(NULL, &wdt_event_handler);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_wdt_channel_alloc(&wdt_channel_id);
APP_ERROR_CHECK(err_code);
wdt_initialized = 1;
}
/*---------------------------------------------------------------------------*/
void
watchdog_start(void)
{
if(wdt_initialized) {
nrf_drv_wdt_enable();
}
}
/*---------------------------------------------------------------------------*/
void
watchdog_periodic(void)
{
if(wdt_initialized) {
nrf_drv_wdt_channel_feed(wdt_channel_id);
}
}
/*---------------------------------------------------------------------------*/
void
watchdog_reboot(void)
{
NVIC_SystemReset();
}
/**
* @}
* @}
*/

2
cpu/nrf52832/erase.jlink Normal file
View file

@ -0,0 +1,2 @@
erase
q

4
cpu/nrf52832/flash.jlink Normal file
View file

@ -0,0 +1,4 @@
loadfile #OUTPUT_FILENAME#
r
g
q

View file

@ -0,0 +1,12 @@
/* Linker script to configure memory regions. */
SEARCH_DIR(.)
GROUP(-lgcc -lc -lnosys)
MEMORY
{
FLASH (rx) : ORIGIN = 0x1f000, LENGTH = 0x61000
RAM (rwx) : ORIGIN = 0x08000000, LENGTH = 0x8000
}
INCLUDE "nrf5x_common.ld"

View file

@ -0,0 +1,12 @@
/* Linker script to configure memory regions. */
SEARCH_DIR(.)
GROUP(-lgcc -lc -lnosys)
MEMORY
{
FLASH (rx) : ORIGIN = 0x1f000, LENGTH = 0x61000
RAM (rwx) : ORIGIN = 0x20002800, LENGTH = 0xD800
}
INCLUDE "nrf5x_common.ld"

12
cpu/nrf52832/ld/nrf52.ld Normal file
View file

@ -0,0 +1,12 @@
/* Linker script to configure memory regions. */
SEARCH_DIR(.)
GROUP(-lgcc -lc -lnosys)
MEMORY
{
FLASH (rx) : ORIGIN = 0x0, LENGTH = 0x80000
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x8000
}
INCLUDE "nrf5x_common.ld"

48
cpu/nrf52832/mtarch.h Normal file
View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2010, Loughborough University - 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. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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
* Stub header file for multi-threading. It doesn't do anything, it
* just exists so that mt.c can compile cleanly.
*
* This is based on the original mtarch.h for z80 by Takahide Matsutsuka
*
* \author
* George Oikonomou - <oikonomou@users.sourceforge.net>
*/
#ifndef __MTARCH_H__
#define __MTARCH_H__
struct mtarch_thread {
unsigned char *sp;
};
#endif /* __MTARCH_H__ */

70
cpu/nrf52832/putchar.c Normal file
View file

@ -0,0 +1,70 @@
/*
* Copyright (c) 2015, Nordic Semiconductor
* 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 nrf52832
* @{
*
* \file
* Hardware specific implementation of putchar() and puts() functions.
* \author
* Wojciech Bober <wojciech.bober@nordicsemi.no>
*
*/
/*---------------------------------------------------------------------------*/
#include <string.h>
#include "dev/uart0.h"
/*---------------------------------------------------------------------------*/
int
putchar(int c)
{
uart0_writeb(c);
return c;
}
/*---------------------------------------------------------------------------*/
int
puts(const char *str)
{
int i;
if (str == NULL) {
return 0;
}
for (i = 0; i < strlen(str); i++) {
uart0_writeb(str[i]);
}
uart0_writeb('\n');
return i;
}
/*---------------------------------------------------------------------------*/
/**
* @}
*/

110
cpu/nrf52832/rtimer-arch.c Normal file
View file

@ -0,0 +1,110 @@
/*
* Copyright (c) 2015 Nordic Semiconductor. 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 nrf52832
* @{
*
* \file
* Implementation of the architecture dependent rtimer functions for the nRF52
*
* \author
* Wojciech Bober <wojciech.bober@nordicsemi.no>
*/
/*---------------------------------------------------------------------------*/
#include <stdint.h>
#include <stddef.h>
#include "nrf.h"
#include "nrf_drv_timer.h"
#include "app_error.h"
#include "contiki.h"
#include "platform-conf.h"
static const nrf_drv_timer_t timer = NRF_DRV_TIMER_INSTANCE(PLATFORM_TIMER_INSTANCE_ID); /**< Timer instance used for rtimer */
/**
* \brief Handler for timer events.
*
* \param event_type type of an event that should be handled
* \param p_context opaque data pointer passed from nrf_drv_timer_init()
*/
static void
timer_event_handler(nrf_timer_event_t event_type, void* p_context)
{
switch (event_type) {
case NRF_TIMER_EVENT_COMPARE1:
rtimer_run_next();
break;
default:
//Do nothing.
break;
}
}
/*---------------------------------------------------------------------------*/
/**
* \brief Initialize platform rtimer
*/
void
rtimer_arch_init(void)
{
ret_code_t err_code = nrf_drv_timer_init(&timer, NULL, timer_event_handler);
APP_ERROR_CHECK(err_code);
nrf_drv_timer_enable(&timer);
}
/*---------------------------------------------------------------------------*/
/**
* \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 nRF RTC.
*/
void
rtimer_arch_schedule(rtimer_clock_t t)
{
nrf_drv_timer_compare(&timer, NRF_TIMER_CC_CHANNEL1, t, true);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Returns the current real-time clock time
* \return The current rtimer time in ticks
*
*/
rtimer_clock_t
rtimer_arch_now()
{
return nrf_drv_timer_capture(&timer, NRF_TIMER_CC_CHANNEL0);
}
/*---------------------------------------------------------------------------*/
/**
* @}
*/

View file

@ -0,0 +1,52 @@
/*
* Copyright (c) 2015, Nordic Semiconductor
* 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 nrf52832 nRF52832
* @{
*
* \file
* Architecture dependent rtimer implementation header file.
* \author
* Wojciech Bober <wojciech.bober@nordicsemi.no>
*
*/
/*---------------------------------------------------------------------------*/
#ifndef RTIMER_ARCH_H_
#define RTIMER_ARCH_H_
/*---------------------------------------------------------------------------*/
#include "contiki.h"
/*---------------------------------------------------------------------------*/
rtimer_clock_t rtimer_arch_now(void);
/*---------------------------------------------------------------------------*/
#endif /* RTIMER_ARCH_H_ */
/*---------------------------------------------------------------------------*/
/**
* @}
*/

View file

@ -0,0 +1,12 @@
DEFINES+=PROJECT_CONF_H=\"project-conf.h\"
CONTIKI = ../..
all: test-cfs test-coffee example-coffee
CONTIKI_WITH_RIME = 1
ifeq ($(TARGET),avr-raven)
COFFEE_FILES = 4
endif
include $(CONTIKI)/Makefile.include

View file

@ -0,0 +1,29 @@
Contiki File System (CFS) and Coffee Examples
=============================================
Coffee is a very simple, relatively small and easy to use file system that you
are most likely going to be very familiar with if you have done any C file
access in the past. The notion is the same as on a normal PC: you open a file,
read and write to it and close it. Contiki will take care of the underlying
flash memory, giving you more time to focus on the real issues.
Coffee is a full implementation of the CFS API.
An extended explanation on CFS and Coffee internals and how they work can be
found at the [CFS](https://github.com/contiki-os/contiki/wiki/File-systems) and
[Coffee](https://github.com/contiki-os/contiki/wiki/Coffee-filesystem-example)
wiki pages.
Supported Hardware (tested or known to work)
--------------------------------------------
* sky
* z1
* wismote
* avr-raven
* cc2538dk
* openmote-cc2538
* zoul
The examples are known to build for the 'avr-raven' platform. However,
some of them currently fail at runtime due to file system overflow.
Tweaking the file sizes in the examples is necessary.

View file

@ -28,31 +28,31 @@
*
* This file is part of the Contiki operating system.
*/
/*---------------------------------------------------------------------------*/
/**
* \file
* Example on how to use CFS/Coffee.
* \author
* Nicolas Tsiftes <nvt@sics.se>
*/
/*---------------------------------------------------------------------------*/
#include <stdio.h>
#include <string.h>
#include "contiki.h"
#include "cfs/cfs.h"
#include "cfs/cfs-coffee.h"
/*---------------------------------------------------------------------------*/
PROCESS(example_coffee_process, "Coffee example");
AUTOSTART_PROCESSES(&example_coffee_process);
/*---------------------------------------------------------------------------*/
#define FILENAME "test"
/* Formatting is needed if the storage device is in an unknown state;
/* Formatting is needed if the storage device is in an unknown state;
e.g., when using Coffee on the storage device for the first time. */
#ifndef NEED_FORMATTING
#define NEED_FORMATTING 0
#endif
/*---------------------------------------------------------------------------*/
static int
file_test(const char *filename, char *msg)
{
@ -65,12 +65,12 @@ file_test(const char *filename, char *msg)
} record;
/*
* Coffee determines the file length by finding the last non-zero byte
* of the file. This I/O semantic requires that each record should end
* with a non-zero, if we are writing multiple records and closing the
* Coffee determines the file length by finding the last non-zero byte
* of the file. This I/O semantic requires that each record should end
* with a non-zero, if we are writing multiple records and closing the
* file descriptor in between.
*
* In this example, in which the file_test function can be called
* In this example, in which the file_test function can be called
* multiple times, we ensure that the sequence counter starts at 1.
*/
@ -84,7 +84,7 @@ file_test(const char *filename, char *msg)
record.message[sizeof(record.message) - 1] = '\0';
record.sequence = sequence;
/* Obtain a file descriptor for the file, capable of handling both
/* Obtain a file descriptor for the file, capable of handling both
reads and writes. */
fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);
if(fd < 0) {
@ -103,7 +103,7 @@ file_test(const char *filename, char *msg)
printf("Wrote message \"%s\", sequence %u\n",
record.message, record.sequence);
/* To read back the message, we need to move the file pointer to the
/* To read back the message, we need to move the file pointer to the
beginning of the file. */
if(cfs_seek(fd, 0, CFS_SEEK_SET) != 0) {
printf("seek failed\n");
@ -133,7 +133,7 @@ file_test(const char *filename, char *msg)
return 1;
}
/*---------------------------------------------------------------------------*/
static int
dir_test(void)
{
@ -156,7 +156,7 @@ dir_test(void)
return 1;
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(example_coffee_process, ev, data)
{
PROCESS_BEGIN();

View file

@ -0,0 +1,40 @@
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this 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_
/*---------------------------------------------------------------------------*/
#if CONTIKI_TARGET_CC2538DK || CONTIKI_TARGET_OPENMOTE_CC2538 || \
CONTIKI_TARGET_ZOUL
#define COFFEE_CONF_SIZE (CC2538_DEV_FLASH_SIZE / 2)
#define COFFEE_CONF_MICRO_LOGS 1
#define COFFEE_CONF_APPEND_ONLY 0
#endif /* CONTIKI_TARGET_CC2538DK || CONTIKI_TARGET_ZOUL */
#endif /* PROJECT_CONF_H_ */
/*---------------------------------------------------------------------------*/

View file

@ -29,19 +29,18 @@
* This file is part of the Contiki operating system.
*
*/
/*---------------------------------------------------------------------------*/
/**
* \file
* A quick program for testing the CFS xmem driver
* \author
* Adam Dunkels <adam@sics.se>
*/
/*---------------------------------------------------------------------------*/
#include "contiki.h"
#include "cfs/cfs.h"
#include <stdio.h>
/*---------------------------------------------------------------------------*/
PROCESS(cfs_process, "Test CFS process");
AUTOSTART_PROCESSES(&cfs_process);
/*---------------------------------------------------------------------------*/
@ -55,6 +54,7 @@ PROCESS_THREAD(cfs_process, ev, data)
uint16_t filesize = 65000;
#define CHUNKSIZE 128
cfs_remove("hej");
fd = cfs_open("hej", CFS_WRITE);
if(fd < 0) {
printf("could not open file for writing, aborting\n");

View file

@ -29,14 +29,14 @@
* This file is part of the Contiki operating system.
*
*/
/*---------------------------------------------------------------------------*/
/**
* \file
* Basic test for CFS/Coffee.
* \author
* Nicolas Tsiftes <nvt@sics.se>
*/
/*---------------------------------------------------------------------------*/
#include "contiki.h"
#include "cfs/cfs.h"
#include "cfs/cfs-coffee.h"
@ -45,14 +45,12 @@
#include <stdio.h>
#include <string.h>
/*---------------------------------------------------------------------------*/
PROCESS(testcoffee_process, "Test CFS/Coffee process");
AUTOSTART_PROCESSES(&testcoffee_process);
#define FAIL(x) error = (x); goto end;
/*---------------------------------------------------------------------------*/
#define TEST_FAIL(x) error = (x); goto end;
#define FILE_SIZE 4096
/*---------------------------------------------------------------------------*/
static int
coffee_test_basic(void)
@ -62,8 +60,6 @@ coffee_test_basic(void)
unsigned char buf[256];
int r;
cfs_remove("T1");
wfd = rfd = afd = -1;
for(r = 0; r < sizeof(buf); r++) {
@ -73,64 +69,64 @@ coffee_test_basic(void)
/* Test 1: Open for writing. */
wfd = cfs_open("T1", CFS_WRITE);
if(wfd < 0) {
FAIL(1);
TEST_FAIL(1);
}
/* Test 2 and 3: Write buffer. */
r = cfs_write(wfd, buf, sizeof(buf));
if(r < 0) {
FAIL(2);
TEST_FAIL(2);
} else if(r < sizeof(buf)) {
FAIL(3);
TEST_FAIL(3);
}
/* Test 4: Deny reading. */
r = cfs_read(wfd, buf, sizeof(buf));
if(r >= 0) {
FAIL(4);
TEST_FAIL(4);
}
/* Test 5: Open for reading. */
rfd = cfs_open("T1", CFS_READ);
if(rfd < 0) {
FAIL(5);
TEST_FAIL(5);
}
/* Test 6: Write to read-only file. */
r = cfs_write(rfd, buf, sizeof(buf));
if(r >= 0) {
FAIL(6);
TEST_FAIL(6);
}
/* Test 7 and 8: Read the buffer written in Test 2. */
memset(buf, 0, sizeof(buf));
r = cfs_read(rfd, buf, sizeof(buf));
if(r < 0) {
FAIL(7);
TEST_FAIL(7);
} else if(r < sizeof(buf)) {
printf("r=%d\n", r);
FAIL(8);
TEST_FAIL(8);
}
/* Test 9: Verify that the buffer is correct. */
for(r = 0; r < sizeof(buf); r++) {
if(buf[r] != r) {
printf("r=%d. buf[r]=%d\n", r, buf[r]);
FAIL(9);
TEST_FAIL(9);
}
}
/* Test 10: Seek to beginning. */
if(cfs_seek(wfd, 0, CFS_SEEK_SET) != 0) {
FAIL(10);
TEST_FAIL(10);
}
/* Test 11 and 12: Write to the log. */
r = cfs_write(wfd, buf, sizeof(buf));
if(r < 0) {
FAIL(11);
TEST_FAIL(11);
} else if(r < sizeof(buf)) {
FAIL(12);
TEST_FAIL(12);
}
/* Test 13 and 14: Read the data from the log. */
@ -138,15 +134,15 @@ coffee_test_basic(void)
memset(buf, 0, sizeof(buf));
r = cfs_read(rfd, buf, sizeof(buf));
if(r < 0) {
FAIL(14);
TEST_FAIL(13);
} else if(r < sizeof(buf)) {
FAIL(15);
TEST_FAIL(14);
}
/* Test 16: Verify that the data is correct. */
for(r = 0; r < sizeof(buf); r++) {
if(buf[r] != r) {
FAIL(16);
TEST_FAIL(15);
}
}
@ -155,16 +151,16 @@ coffee_test_basic(void)
buf[r] = sizeof(buf) - r - 1;
}
if(cfs_seek(wfd, 0, CFS_SEEK_SET) != 0) {
FAIL(17);
TEST_FAIL(16);
}
r = cfs_write(wfd, buf, sizeof(buf));
if(r < 0) {
FAIL(18);
TEST_FAIL(17);
} else if(r < sizeof(buf)) {
FAIL(19);
TEST_FAIL(18);
}
if(cfs_seek(rfd, 0, CFS_SEEK_SET) != 0) {
FAIL(20);
TEST_FAIL(19);
}
/* Test 21 and 22: Read the reversed buffer. */
@ -172,16 +168,16 @@ coffee_test_basic(void)
memset(buf, 0, sizeof(buf));
r = cfs_read(rfd, buf, sizeof(buf));
if(r < 0) {
FAIL(21);
TEST_FAIL(20);
} else if(r < sizeof(buf)) {
printf("r = %d\n", r);
FAIL(22);
TEST_FAIL(21);
}
/* Test 23: Verify that the data is correct. */
for(r = 0; r < sizeof(buf); r++) {
if(buf[r] != sizeof(buf) - r - 1) {
FAIL(23);
TEST_FAIL(22);
}
}
@ -189,6 +185,7 @@ coffee_test_basic(void)
end:
cfs_close(wfd);
cfs_close(rfd);
cfs_remove("T1");
return error;
}
/*---------------------------------------------------------------------------*/
@ -202,50 +199,49 @@ coffee_test_append(void)
#define APPEND_BYTES 1000
#define BULK_SIZE 10
cfs_remove("T2");
/* Test 1 and 2: Append data to the same file many times. */
for(i = 0; i < APPEND_BYTES; i += BULK_SIZE) {
afd = cfs_open("T3", CFS_WRITE | CFS_APPEND);
afd = cfs_open("T2", CFS_WRITE | CFS_APPEND);
if(afd < 0) {
FAIL(1);
TEST_FAIL(1);
}
for(j = 0; j < BULK_SIZE; j++) {
buf[j] = 1 + ((i + j) & 0x7f);
}
if((r = cfs_write(afd, buf, BULK_SIZE)) != BULK_SIZE) {
printf("r=%d\n", r);
FAIL(2);
TEST_FAIL(2);
}
cfs_close(afd);
}
/* Test 3-6: Read back the data written previously and verify that it
/* Test 3-6: Read back the data written previously and verify that it
is correct. */
afd = cfs_open("T3", CFS_READ);
afd = cfs_open("T2", CFS_READ);
if(afd < 0) {
FAIL(3);
TEST_FAIL(3);
}
total_read = 0;
while((r = cfs_read(afd, buf2, sizeof(buf2))) > 0) {
for(j = 0; j < r; j++) {
if(buf2[j] != 1 + ((total_read + j) & 0x7f)) {
FAIL(4);
TEST_FAIL(4);
}
}
total_read += r;
}
if(r < 0) {
FAIL(5);
TEST_FAIL(5);
}
if(total_read != APPEND_BYTES) {
FAIL(6);
TEST_FAIL(6);
}
cfs_close(afd);
error = 0;
end:
cfs_close(afd);
cfs_remove("T2");
return error;
}
/*---------------------------------------------------------------------------*/
@ -258,58 +254,60 @@ coffee_test_modify(void)
int r, i;
unsigned offset;
cfs_remove("T3");
wfd = -1;
if(cfs_coffee_reserve("T3", FILE_SIZE) < 0) {
FAIL(1);
TEST_FAIL(1);
}
if(cfs_coffee_configure_log("T3", FILE_SIZE / 2, 11) < 0) {
FAIL(2);
TEST_FAIL(2);
}
/* Test 16: Test multiple writes at random offset. */
for(r = 0; r < 100; r++) {
wfd = cfs_open("T2", CFS_WRITE | CFS_READ);
wfd = cfs_open("T3", CFS_WRITE | CFS_READ);
if(wfd < 0) {
FAIL(3);
TEST_FAIL(3);
}
offset = random_rand() % FILE_SIZE;
for(r = 0; r < sizeof(buf); r++) {
buf[r] = r;
for(i = 0; i < sizeof(buf); i++) {
buf[i] = i;
}
if(cfs_seek(wfd, offset, CFS_SEEK_SET) != offset) {
FAIL(4);
TEST_FAIL(4);
}
if(cfs_write(wfd, buf, sizeof(buf)) != sizeof(buf)) {
FAIL(5);
TEST_FAIL(5);
}
if(cfs_seek(wfd, offset, CFS_SEEK_SET) != offset) {
FAIL(6);
TEST_FAIL(6);
}
memset(buf, 0, sizeof(buf));
if(cfs_read(wfd, buf, sizeof(buf)) != sizeof(buf)) {
FAIL(7);
TEST_FAIL(7);
}
for(i = 0; i < sizeof(buf); i++) {
if(buf[i] != i) {
printf("buf[%d] != %d\n", i, buf[i]);
FAIL(8);
TEST_FAIL(8);
}
}
cfs_close(wfd);
}
error = 0;
end:
cfs_close(wfd);
cfs_remove("T3");
return error;
}
/*---------------------------------------------------------------------------*/
@ -318,21 +316,17 @@ coffee_test_gc(void)
{
int i;
cfs_remove("alpha");
cfs_remove("beta");
for (i = 0; i < 100; i++) {
if (i & 1) {
if(cfs_coffee_reserve("alpha", random_rand() & 0xffff) < 0) {
return i;
}
cfs_remove("beta");
} else {
if(cfs_coffee_reserve("beta", 93171) < 0) {
if(cfs_coffee_reserve("beta", random_rand() & 0xffff) < 0) {
return i;
}
cfs_remove("alpha");
} else {
if(cfs_coffee_reserve("alpha", 93171) < 0) {
return i;
}
cfs_remove("beta");
}
}
@ -376,7 +370,7 @@ PROCESS_THREAD(testcoffee_process, ev, data)
result = coffee_test_gc();
print_result("Garbage collection", result);
printf("Coffee test finished. Duration: %d seconds\n",
printf("Coffee test finished. Duration: %d seconds\n",
(int)(clock_seconds() - start));
PROCESS_END();

View file

@ -67,13 +67,19 @@
#define TSCH_CALLBACK_JOINING_NETWORK tsch_rpl_callback_joining_network
#define TSCH_CALLBACK_LEAVING_NETWORK tsch_rpl_callback_leaving_network
/* Needed for CC2538 platforms only */
/* For TSCH we have to use the more accurate crystal oscillator
* by default the RC oscillator is activated */
#undef SYS_CTRL_CONF_OSC32K_USE_XTAL
#define SYS_CTRL_CONF_OSC32K_USE_XTAL 1
/* Needed for cc2420 platforms only */
/* Disable DCO calibration (uses timerB) */
#undef DCOSYNCH_CONF_ENABLED
#define DCOSYNCH_CONF_ENABLED 0
#define DCOSYNCH_CONF_ENABLED 0
/* Enable SFD timestamps (uses timerB) */
#undef CC2420_CONF_SFD_TIMESTAMPS
#define CC2420_CONF_SFD_TIMESTAMPS 1
#define CC2420_CONF_SFD_TIMESTAMPS 1
/*******************************************************/
/******************* Configure TSCH ********************/

View file

@ -0,0 +1,9 @@
CONTIKI_PROJECT = blink-hello
CONTIKI_WITH_RPL=0
NRF52_WITHOUT_SOFTDEVICE=1
all: $(CONTIKI_PROJECT)
CONTIKI = ../../..
include $(CONTIKI)/Makefile.include

View file

@ -0,0 +1,14 @@
Blink Hello example
===================
This example shows basic usage of DK's buttons and LEDs. It also shows basic
usage of Contiki's processes. The application autostarts 5 processes: 4 processes
for button and LED control and 1 to display current temperature to the console.
A process reacts to a press of a respective button (process 1 reacts to button 1, etc.)
and doubles the current blinking frequency. The cycle restarts for beginning when blinking
frequency is greater than 8Hz.
The example requires one DK and it doesn't use SoftDevice. To compile and flash the
example run:
make TARGET=nrf52dk blink-hello.flash

View file

@ -0,0 +1,182 @@
/* This is a very simple hello_world program.
* It aims to demonstrate the co-existence of two processes:
* One of them prints a hello world message and the other blinks the LEDs
*
* It is largely based on hello_world in $(CONTIKI)/examples/sensinode
*
* Author: George Oikonomou - <oikonomou@users.sourceforge.net>
*/
/**
* \addtogroup nrf52dk nRF52 Development Kit
* @{
*
* \addtogroup nrf52dk-examples Demo projects for nRF52 DK
* @{
*
* \defgroup nrf52dk-blink-hello Basic sensors and LEDs demo
* @{
*
* This demo demonstrates use of Contiki processes, sensors, and LEDs
* on nRF52 DK. Pressing a button will start a timer that blinks a
* respective LED (e.g., button 1 controls LED 1). Each time the button
* is pressed blinking frequency is doubled. On 4th press the LED is
* switched off and the sequence can be started from the beginning.
*
* \file Main file for Basic sensors and LEDs demo.
*/
#include <stdio.h> /* For printf() */
#include <inttypes.h>
#include "contiki.h"
#include "dev/leds.h"
#include "dev/temperature-sensor.h"
#include "lib/sensors.h"
#include "button-sensor.h"
/*---------------------------------------------------------------------------*/
PROCESS(blink_process_1, "LED1 blink process");
PROCESS(blink_process_2, "LED2 blink process");
PROCESS(blink_process_3, "LED3 blink process");
PROCESS(blink_process_4, "LED4 blink process");
PROCESS(temp, "Temperautre");
AUTOSTART_PROCESSES(
&blink_process_1,
&blink_process_2,
&blink_process_3,
&blink_process_4,
&temp
);
struct blink_process_ctx {
struct etimer et_blink;
unsigned char c;
const struct sensors_sensor *button;
unsigned char led;
};
static void handle_event(process_event_t ev, process_data_t data, struct blink_process_ctx *ctx)
{
if (ev == PROCESS_EVENT_TIMER && etimer_expired(&ctx->et_blink)) {
leds_toggle(ctx->led);
etimer_set(&ctx->et_blink, CLOCK_SECOND / ctx->c);
printf("Blink %d\n", ctx->led);
} else if (ev == sensors_event && data == ctx->button) {
if (ctx->button->value(BUTTON_SENSOR_VALUE_STATE) == 0) {
if (ctx->c == 0) {
ctx->c = 1;
} else if (ctx->c < 8){
ctx->c <<= 1;
} else {
ctx->c = 0;
leds_off(ctx->led);
}
if (ctx->c) {
etimer_set(&ctx->et_blink, CLOCK_SECOND / ctx->c);
} else {
etimer_stop(&ctx->et_blink);
}
}
}
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(blink_process_1, ev, data)
{
static struct blink_process_ctx ctx;
PROCESS_BEGIN();
ctx.button = &button_1;
ctx.c = 0;
ctx.led = LEDS_1;
ctx.button->configure(SENSORS_ACTIVE, 1);
while (1) {
PROCESS_WAIT_EVENT();
handle_event(ev, data, &ctx);
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(blink_process_2, ev, data)
{
static struct blink_process_ctx ctx;
PROCESS_BEGIN();
ctx.button = &button_2;
ctx.c = 0;
ctx.led = LEDS_2;
ctx.button->configure(SENSORS_ACTIVE, 1);
while (1) {
PROCESS_WAIT_EVENT();
handle_event(ev, data, &ctx);
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(blink_process_3, ev, data)
{
static struct blink_process_ctx ctx;
PROCESS_BEGIN();
ctx.button = &button_3;
ctx.c = 0;
ctx.led = LEDS_3;
ctx.button->configure(SENSORS_ACTIVE, 1);
while (1) {
PROCESS_WAIT_EVENT();
handle_event(ev, data, &ctx);
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(blink_process_4, ev, data)
{
static struct blink_process_ctx ctx;
PROCESS_BEGIN();
ctx.button = &button_4;
ctx.c = 0;
ctx.led = LEDS_4;
ctx.button->configure(SENSORS_ACTIVE, 1);
while (1) {
PROCESS_WAIT_EVENT();
handle_event(ev, data, &ctx);
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(temp, ev, data)
{
static struct etimer tick;
PROCESS_BEGIN();
etimer_set(&tick, CLOCK_SECOND);
while (1) {
PROCESS_WAIT_EVENT();
if (ev == PROCESS_EVENT_TIMER && etimer_expired(&tick)) {
int32_t temp = temperature_sensor.value(0);
printf("temp: %"PRId32".%02"PRId32"\n", temp >> 2, (temp & 0x03)*25);
etimer_reset(&tick);
}
}
PROCESS_END();
}
/**
* @}
* @}
* @}
*/

View file

@ -0,0 +1,35 @@
CONTIKI=../../..
CFLAGS += -DPROJECT_CONF_H=\"project-conf.h\"
ifeq ($(MAKECMDGOALS),)
$(error Please specify whether coap-client or coap-server should be built)
endif
ifneq ($(filter coap-client coap-client.flash, $(MAKECMDGOALS)),)
ifeq ($(SERVER_IPV6_ADDR),)
$(error Please define SERVER_IPV6_ADDR=<full ipv6 addr>)
else
CFLAGS += -DSERVER_IPV6_ADDR=\"$(SERVER_IPV6_ADDR)\"
CFLAGS += -DDEVICE_NAME=\"nRF52_DK_CoAP_Client\"
endif
else
CFLAGS += -DDEVICE_NAME=\"nRF52-DK-CoAP-Server\"
endif
# automatically build RESTful resources
REST_RESOURCES_DIR = ./resources
REST_RESOURCES_FILES = $(notdir $(shell find $(REST_RESOURCES_DIR) -name '*.c' ! -name 'res-plugtest*'))
PROJECTDIRS += $(REST_RESOURCES_DIR)
PROJECT_SOURCEFILES += $(REST_RESOURCES_FILES)
# linker optimizations
SMALL=1
# REST Engine shall use Erbium CoAP implementation
APPS += er-coap
APPS += rest-engine
CONTIKI_WITH_RPL = 0
include $(CONTIKI)/Makefile.include

View file

@ -0,0 +1,63 @@
A CoAP demo for nRF52 DK
========================
This demo contains two applications: coap-server and coap-client which are similar to
[Coap Observable Server] and [Coap Observer Client] examples provided by the nRF5 IoT SDK.
Note that before any CoAP requests can be made you'll need to configure an IPv6 connection
to the device and assign a routable IPv6 address.
For details how to do this please refer to sections 'Establishing an IPv6 connection'
and 'Distributing routable IPv6 prefix' in `platform/nrf52dk/README-BLE-6LoWPAN.md`.
CoAP Server
===========
The server exposes the following resources:
host
|-- .well-known
| `-- core
`-- lights
`-- led3
The state of LED 3 can be set and queried via CoAP through the observable resource `lights/led3`. Current
state of LED 3 is returned as a text string in the payload. The value 0 means that LED 3 is off, 1 otherwise.
Button 1 can be used to toggle state of the LED 3. This will cause a notification to be sent to
any subscriber observing `lights/led3`. The state of the resource can also be changed by using POST/PUT to
the resource with desired state encoded as a text in the payload. Send 1 to switch on and 0 to switch off.
In order to compile and flash the CoAP server to a DK execute:
make TARGET=nrf52dk coap-server.flash
Note, if you haven't previously used a given device with Contiki it is recommended
to erase the device and flash SoftDevice before flashing CoAP application, i.e.,
make TARGET=nrf52dk erase
make TARGET=nrf52dk softdevice.flash
Please refer to the *Testing* and *Python Example* sections of [Coap Observable Server] tutorial for detailed description how to query the Coap Server using a PC.
CoAP Client
===========
CoAP client compliments the CoAP server application. When Button 1 on the DK is pressed the the
client subscribes to `lights/led3` resource. If successful the LED 4 will blink briefly. From this moment
any change of the `lights/led3` resource will be automatically reflected by the client's LED 3.
Note that the client must know the server's IPv6 address. The address is specified as a make variable
during compliation.
In order to compile and flash the CoAP client to DK execute:
make TARGET=nrf52dk SERVER_IPV6_ADDR=<full-ip6-address> coap-client.flash
Note, that you can use `NRF52_JLINK_SN=<SN>` to select a particular devkit in a case when
you have more than one boards connected to PC. Please refer to `platform/README.md` for
details.
Please refer to the *Testing* and *Python Server Example* sections of [Coap Observer Client] tutorial for detailed description how to use CoAP client demo with a PC.
Resources
=========
[Coap Observable Server] http://developer.nordicsemi.com/nRF5_IoT_SDK/doc/0.9.0/html/a00054.html
[Coap Observer Client] http://developer.nordicsemi.com/nRF5_IoT_SDK/doc/0.9.0/html/a00051.html

View file

@ -0,0 +1,185 @@
/*
* Copyright (c) 2014, Daniele Alessandrelli.
* Copyright (c) 2015, Nordic Semiconductor
* 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 nrf52dk-examples Demo projects for nRF52 DK
* @{
*
* \defgroup nrf52dk-coap-demo CoAP demo for nRF52 DK
* @{
*
* \file
* Erbium (Er) CoAP observe client example.
* \author
* Daniele Alessandrelli <daniele.alessandrelli@gmail.com>
* \author
* Wojciech Bober <wojciech.bober@nordicsemi.no>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "contiki.h"
#include "contiki-net.h"
#include "er-coap-engine.h"
#include "dev/button-sensor.h"
#include "dev/leds.h"
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...)
#endif
/*----------------------------------------------------------------------------*/
#define REMOTE_PORT UIP_HTONS(COAP_DEFAULT_PORT)
#define OBS_RESOURCE_URI "lights/led3"
#define SUBS_LED LEDS_4
#define OBS_LED LEDS_3
/*----------------------------------------------------------------------------*/
static uip_ipaddr_t server_ipaddr[1]; /* holds the server ip address */
static coap_observee_t *obs;
static struct ctimer ct;
/*----------------------------------------------------------------------------*/
PROCESS(er_example_observe_client, "nRF52 DK Coap Observer Client");
AUTOSTART_PROCESSES(&er_example_observe_client);
/*----------------------------------------------------------------------------*/
static void
observe_led_off(void *d)
{
leds_off(SUBS_LED);
}
/*----------------------------------------------------------------------------*/
/*
* Handle the response to the observe request and the following notifications
*/
static void
notification_callback(coap_observee_t *obs, void *notification,
coap_notification_flag_t flag)
{
int len = 0;
const uint8_t *payload = NULL;
PRINTF("Notification handler\n");
PRINTF("Observee URI: %s\n", obs->url);
if (notification) {
len = coap_get_payload(notification, &payload);
}
(void)len;
switch (flag) {
case NOTIFICATION_OK:
PRINTF("NOTIFICATION OK: %*s\n", len, (char *)payload);
if (*payload == '1') {
leds_on(OBS_LED);
} else {
leds_off(OBS_LED);
}
break;
case OBSERVE_OK: /* server accepeted observation request */
PRINTF("OBSERVE_OK: %*s\n", len, (char *)payload);
if (*payload == '1') {
leds_on(OBS_LED);
} else {
leds_off(OBS_LED);
}
leds_on(SUBS_LED);
ctimer_set(&ct, CLOCK_SECOND, observe_led_off, NULL);
break;
case OBSERVE_NOT_SUPPORTED:
PRINTF("OBSERVE_NOT_SUPPORTED: %*s\n", len, (char *)payload);
obs = NULL;
break;
case ERROR_RESPONSE_CODE:
PRINTF("ERROR_RESPONSE_CODE: %*s\n", len, (char *)payload);
obs = NULL;
break;
case NO_REPLY_FROM_SERVER:
PRINTF("NO_REPLY_FROM_SERVER: "
"removing observe registration with token %x%x\n",
obs->token[0], obs->token[1]);
obs = NULL;
break;
}
}
/*----------------------------------------------------------------------------*/
/*
* The main (proto-)thread. It starts/stops the observation of the remote
* resource every time the timer elapses or the button (if available) is
* pressed
*/
PROCESS_THREAD(er_example_observe_client, ev, data)
{
PROCESS_BEGIN();
uiplib_ipaddrconv(SERVER_IPV6_ADDR, server_ipaddr);
/* receives all CoAP messages */
coap_init_engine();
#if PLATFORM_HAS_BUTTON
SENSORS_ACTIVATE(button_1);
SENSORS_ACTIVATE(button_2);
#endif
/* toggle observation every time the timer elapses or the button is pressed */
while (1) {
PROCESS_YIELD();
#if PLATFORM_HAS_BUTTON
if (ev == sensors_event) {
if (data == &button_1 && button_1.value(BUTTON_SENSOR_VALUE_STATE) == 0) {
PRINTF("Starting observation\n");
obs = coap_obs_request_registration(server_ipaddr, REMOTE_PORT,
OBS_RESOURCE_URI, notification_callback,
NULL);
}
if (data == &button_2 && button_2.value(BUTTON_SENSOR_VALUE_STATE) == 0) {
PRINTF("Stopping observation\n");
coap_obs_remove_observee(obs);
obs = NULL;
}
}
#endif
}
PROCESS_END();
}
/**
* @}
* @}
*/

View file

@ -0,0 +1,130 @@
/*
* Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich
* Copyright (c) 2015, Nordic Semiconductor
*
* 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 nrf52dk-examples Demo projects for nRF52 DK
* @{
*
* \defgroup nrf52dk-coap-demo CoAP demo for nRF52dk
* @{
*
* \file
* Erbium (Er) REST Engine example.
* \author
* Matthias Kovatsch <kovatsch@inf.ethz.ch>
* \author
* Wojciech Bober <wojciech.bober@nordicsemi.no>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "contiki.h"
#include "contiki-net.h"
#include "rest-engine.h"
#include "uip.h"
#include "dev/button-sensor.h"
#include "dev/leds.h"
#define DEBUG DEBUG_PRINT
#include "net/ip/uip-debug.h"
/*
* Resources to be activated need to be imported through the extern keyword.
* The build system automatically compiles the resources in the corresponding sub-directory.
*/
extern resource_t res_led3;
static void
print_local_addresses(void)
{
int i;
uint8_t state;
PRINTF("Server 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)) {
PRINTF(" ");
PRINT6ADDR(&uip_ds6_if.addr_list[i].ipaddr);
PRINTF("\n");
if(state == ADDR_TENTATIVE) {
uip_ds6_if.addr_list[i].state = ADDR_PREFERRED;
}
}
}
}
PROCESS(er_example_server, "nRF52 DK Coap Server");
AUTOSTART_PROCESSES(&er_example_server);
PROCESS_THREAD(er_example_server, ev, data)
{
PROCESS_BEGIN();
PROCESS_PAUSE();
PRINTF("Starting Erbium Example Server\n");
PRINTF("uIP buffer: %u\n", UIP_BUFSIZE);
PRINTF("LL header: %u\n", UIP_LLH_LEN);
PRINTF("IP+UDP header: %u\n", UIP_IPUDPH_LEN);
PRINTF("REST max chunk: %u\n", REST_MAX_CHUNK_SIZE);
print_local_addresses();
/* Initialize the REST engine. */
rest_init_engine();
rest_activate_resource(&res_led3, "lights/led3");
SENSORS_ACTIVATE(button_1);
/* Define application-specific events here. */
while (1) {
PROCESS_WAIT_EVENT();
if (ev == sensors_event) {
if (data == &button_1 && button_1.value(BUTTON_SENSOR_VALUE_STATE) == 0) {
leds_toggle(LEDS_3);
res_led3.trigger();
}
}
}
PROCESS_END();
}
/**
* @}
* @}
*/

View file

@ -0,0 +1,85 @@
/*
* Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*/
/**
* \addtogroup nrf52dk-examples Demo projects for nRF52 DK
* @{
*
* \defgroup nrf52dk-coap-demo CoAP demo for nRF52dk
* @{
*
* \file
* Erbium (Er) example project configuration.
* \author
* Matthias Kovatsch <kovatsch@inf.ethz.ch>
*/
#ifndef __PROJECT_ERBIUM_CONF_H__
#define __PROJECT_ERBIUM_CONF_H__
/* Disabling TCP on CoAP nodes. */
#undef UIP_CONF_TCP
#define UIP_CONF_TCP 0
/* Increase rpl-border-router IP-buffer when using more than 64. */
#undef REST_MAX_CHUNK_SIZE
#define REST_MAX_CHUNK_SIZE 48
/* Estimate your header size, especially when using Proxy-Uri. */
/*
#undef COAP_MAX_HEADER_SIZE
#define COAP_MAX_HEADER_SIZE 70
*/
/* Multiplies with chunk size, be aware of memory constraints. */
#undef COAP_MAX_OPEN_TRANSACTIONS
#define COAP_MAX_OPEN_TRANSACTIONS 4
/* Must be <= open transactions, default is COAP_MAX_OPEN_TRANSACTIONS-1. */
/*
#undef COAP_MAX_OBSERVERS
#define COAP_MAX_OBSERVERS 2
*/
/* Filtering .well-known/core per query can be disabled to save space. */
#undef COAP_LINK_FORMAT_FILTERING
#define COAP_LINK_FORMAT_FILTERING 0
#undef COAP_PROXY_OPTION_PROCESSING
#define COAP_PROXY_OPTION_PROCESSING 0
/* Enable client-side support for COAP observe */
#define COAP_OBSERVE_CLIENT 1
#endif /* __PROJECT_ERBIUM_CONF_H__ */
/**
* @}
* @}
*/

View file

@ -0,0 +1,106 @@
/*
* Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*/
/**
* \file
* Example resource
* \author
* Matthias Kovatsch <kovatsch@inf.ethz.ch>
* \author
* Wojciech Bober <wojciech.bober@nordicsemi.no>
*/
#include <string.h>
#include "contiki.h"
#include "rest-engine.h"
#include "dev/leds.h"
#define DEBUG DEBUG_NONE
#include "net/ip/uip-debug.h"
static void
res_post_put_handler(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset);
static void
res_get_handler(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset);
static void
res_event_handler();
/*A simple actuator example, depending on the color query parameter and post variable mode, corresponding led is activated or deactivated*/
EVENT_RESOURCE(res_led3,
"title=\"LED3\"; obs",
res_get_handler,
res_post_put_handler,
res_post_put_handler,
NULL,
res_event_handler
);
static void
res_post_put_handler(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset)
{
const uint8_t *payload;
REST.get_request_payload(request, &payload);
if (*payload == '0' || *payload == '1') {
if (*payload == '1') {
leds_on(LEDS_3);
} else {
leds_off(LEDS_3);
}
REST.notify_subscribers(&res_led3);
REST.set_response_status(response, REST.status.CHANGED);
} else {
REST.set_response_status(response, REST.status.BAD_REQUEST);
}
}
static void
res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset)
{
REST.set_header_content_type(response, REST.type.TEXT_PLAIN);
REST.set_response_payload(response, buffer, snprintf((char *)buffer, preferred_size, "%d", (leds_get() & LEDS_3) ? 1 : 0));
}
/*
* Additionally, res_event_handler must be implemented for each EVENT_RESOURCE.
* It is called through <res_name>.trigger(), usually from the server process.
*/
static void
res_event_handler()
{
/* Notify the registered observers which will trigger the res_get_handler to create the response. */
REST.notify_subscribers(&res_led3);
}

View file

@ -0,0 +1,11 @@
DEFINES+=PROJECT_CONF_H=\"project-conf.h\"
all: mqtt-demo
CONTIKI_WITH_IPV6 = 1
CONTIKI_WITH_RPL = 0
APPS += mqtt
CONTIKI=../../..
include $(CONTIKI)/Makefile.include

View file

@ -0,0 +1,74 @@
MQTT Demo
=========
The MQTT client can be used to:
* Publish sensor readings to an MQTT broker.
* Subscribe to a topic and receive commands from an MQTT broker
The demo will give some visual feedback with the green LED:
* Very fast blinking: Searching for a network
* Fast blinking: Connecting to broker
* Slow, long blinking: Sending a publish message
Note that before any MQTT messages can be sent or received you'll
need to configure an IPv6 connection to the device and assign a routable
IPv6 address.
For details how to do this please refer to sections 'Establishing an IPv6 connection'
and 'Distributing routable IPv6 prefix' in `platform/nrf52dk/README-BLE-6LoWPAN.md`.
Broker setup
------------
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
`project-conf.h`. This functionality was tested successfully with
[mosquitto](http://mosquitto.org/).
On Ubuntu you can install and run mosquitto broker using the following
commands:
apt-get install mosquitto mosquitto_clients
killall mosquitto
mosquitto -p 1883 -v
Publishing
----------
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:quickstart:cc2538:<device-id>`, where `<device-id>` gets
constructed from the device's IEEE address.
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:
`iot-2/cmd/+/fmt/json`
You can then use this to toggle LEDs. To do this, you can for example
use mosquitto client to publish to `iot-2/cmd/leds/fmt/json`. So, to change
the state of an LED, you would do this:
`mosquitto_pub -h <broker IP> -m "1" -t iot-2/cmd/leds/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 LED back off.
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. This comment only applies to parsing incoming
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`.
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.

View file

@ -0,0 +1,721 @@
/*
* Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/
* Copyright (c) 2015, Nordic Semiconductor
* 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 nrf52dk-examples Demo projects for nRF52 DK
* @{
*
* \defgroup nrf52dk-mqtt-demo nRF52 DK MQTT Demo Project
*
* Demonstrates MQTT functionality. Works with mosquitto.
* @{
*
* \file
* An MQTT example for the nrf52dk platform
*/
/*---------------------------------------------------------------------------*/
#include "contiki-conf.h"
#include "mqtt.h"
#include "net/ip/uip.h"
#include "net/ipv6/uip-icmp6.h"
#include "net/ipv6/sicslowpan.h"
#include "sys/etimer.h"
#include "sys/ctimer.h"
#include "lib/sensors.h"
#include "dev/button-sensor.h"
#include "dev/temperature-sensor.h"
#include "dev/leds.h"
#include <string.h>
/*---------------------------------------------------------------------------*/
/*
* IBM server: quickstart.messaging.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_DEMO_BROKER_IP_ADDR
static const char *broker_ip = MQTT_DEMO_BROKER_IP_ADDR;
#define DEFAULT_ORG_ID "mqtt-demo"
#else
static const char *broker_ip = "0064:ff9b:0000:0000:0000:0000:b8ac:7cbd";
#define DEFAULT_ORG_ID "quickstart"
#endif
/*---------------------------------------------------------------------------*/
/*
* 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 >> 2)
/* 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 RETRY_FOREVER
#define CONNECTION_STABLE_TIME (CLOCK_SECOND * 5)
static struct timer connection_life;
static uint8_t connect_attempt;
/*---------------------------------------------------------------------------*/
/* Various states */
static uint8_t state;
#define STATE_INIT 0
#define STATE_REGISTERED 1
#define STATE_CONNECTING 2
#define STATE_CONNECTED 3
#define STATE_PUBLISHING 4
#define STATE_DISCONNECTED 5
#define STATE_NEWCONFIG 6
#define STATE_CONFIG_ERROR 0xFE
#define STATE_ERROR 0xFF
/*---------------------------------------------------------------------------*/
#define CONFIG_ORG_ID_LEN 32
#define CONFIG_TYPE_ID_LEN 32
#define CONFIG_AUTH_TOKEN_LEN 32
#define CONFIG_EVENT_TYPE_ID_LEN 32
#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
#define NO_NET_LED_DURATION (NET_CONNECT_PERIODIC >> 1)
/*---------------------------------------------------------------------------*/
/* Default configuration values */
#define DEFAULT_TYPE_ID "nrf52dk"
#define DEFAULT_AUTH_TOKEN "AUTHZ"
#define DEFAULT_EVENT_TYPE_ID "status"
#define DEFAULT_SUBSCRIBE_CMD_TYPE "+"
#define DEFAULT_BROKER_PORT 1883
#define DEFAULT_PUBLISH_INTERVAL (30 * CLOCK_SECOND)
#define DEFAULT_KEEP_ALIVE_TIMER 60
#define DEFAULT_RSSI_MEAS_INTERVAL (CLOCK_SECOND * 30)
/*---------------------------------------------------------------------------*/
/* Take a sensor reading on button press */
#define PUBLISH_TRIGGER (&button_sensor)
/* Payload length of ICMPv6 echo requests used to measure RSSI with def rt */
#define ECHO_REQ_PAYLOAD_LEN 20
/*---------------------------------------------------------------------------*/
PROCESS_NAME(mqtt_demo_process);
AUTOSTART_PROCESSES(&mqtt_demo_process);
/*---------------------------------------------------------------------------*/
/**
* \brief Data structure declaration for the MQTT client configuration
*/
typedef struct mqtt_client_config {
char org_id[CONFIG_ORG_ID_LEN];
char type_id[CONFIG_TYPE_ID_LEN];
char auth_token[CONFIG_AUTH_TOKEN_LEN];
char event_type_id[CONFIG_EVENT_TYPE_ID_LEN];
char broker_ip[CONFIG_IP_ADDR_STR_LEN];
char cmd_type[CONFIG_CMD_TYPE_LEN];
clock_time_t pub_interval;
int def_rt_ping_interval;
uint16_t broker_port;
} mqtt_client_config_t;
/*---------------------------------------------------------------------------*/
/* Maximum TCP segment size for outgoing segments of our socket */
#define MAX_TCP_SEGMENT_SIZE 32
/*---------------------------------------------------------------------------*/
#define STATUS_LED LEDS_GREEN
/*---------------------------------------------------------------------------*/
/*
* 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 128
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;
/*---------------------------------------------------------------------------*/
/* Parent RSSI functionality */
static struct uip_icmp6_echo_reply_notification echo_reply_notification;
static struct etimer echo_request_timer;
static int def_rt_rssi = 0;
/*---------------------------------------------------------------------------*/
static mqtt_client_config_t conf;
/*---------------------------------------------------------------------------*/
PROCESS(mqtt_demo_process, "MQTT Demo");
/*---------------------------------------------------------------------------*/
int
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;
}
/*---------------------------------------------------------------------------*/
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
publish_led_off(void *d)
{
leds_off(STATUS_LED);
}
/*---------------------------------------------------------------------------*/
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;
}
}
/*---------------------------------------------------------------------------*/
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 = STATE_CONNECTED;
break;
}
case MQTT_EVENT_DISCONNECTED: {
DBG("APP - MQTT Disconnect. Reason %u\n", *((mqtt_event_t *)data));
state = STATE_DISCONNECTED;
process_poll(&mqtt_demo_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 = STATE_CONFIG_ERROR;
return;
}
if(construct_sub_topic() == 0) {
/* Fatal error. Topic larger than the buffer */
state = STATE_CONFIG_ERROR;
return;
}
if(construct_pub_topic() == 0) {
/* Fatal error. Topic larger than the buffer */
state = STATE_CONFIG_ERROR;
return;
}
/* Reset the counter */
seq_nr_value = 0;
state = 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, DEFAULT_ORG_ID, strlen(DEFAULT_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.event_type_id, DEFAULT_EVENT_TYPE_ID,
strlen(DEFAULT_EVENT_TYPE_ID));
memcpy(conf.broker_ip, broker_ip, strlen(broker_ip));
memcpy(conf.cmd_type, DEFAULT_SUBSCRIBE_CMD_TYPE, 1);
conf.broker_port = DEFAULT_BROKER_PORT;
conf.pub_interval = DEFAULT_PUBLISH_INTERVAL;
conf.def_rt_ping_interval = DEFAULT_RSSI_MEAS_INTERVAL;
return 1;
}
/*---------------------------------------------------------------------------*/
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;
seq_nr_value++;
buf_ptr = app_buffer;
len = snprintf(buf_ptr, remaining,
"{"
"\"d\":{"
"\"Seq #\":%d,"
"\"Uptime (sec)\":%lu", 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 */
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());
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;
len = snprintf(buf_ptr, remaining, ",\"On-Chip Temp (deg.C)\":%d",
temperature_sensor.value(0));
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_connect(&conn, conf.broker_ip, conf.broker_port,
conf.pub_interval * 3);
state = STATE_CONNECTING;
}
/*---------------------------------------------------------------------------*/
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,
ECHO_REQ_PAYLOAD_LEN);
}
/*---------------------------------------------------------------------------*/
static void
state_machine(void)
{
switch(state) {
case STATE_INIT:
/* If we have just been configured register MQTT connection */
mqtt_register(&conn, &mqtt_demo_process, client_id, mqtt_event,
MAX_TCP_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 = 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;
state = STATE_REGISTERED;
DBG("Init\n");
/* Continue */
case 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);
ping_parent();
connect_to_broker();
} else {
leds_on(STATUS_LED);
ctimer_set(&ct, NO_NET_LED_DURATION, publish_led_off, NULL);
}
etimer_set(&publish_periodic_timer, NET_CONNECT_PERIODIC);
return;
break;
case STATE_CONNECTING:
leds_on(STATUS_LED);
ctimer_set(&ct, CONNECTING_LED_DURATION, publish_led_off, NULL);
/* Not connected yet. Wait */
DBG("Connecting (%u)\n", connect_attempt);
break;
case 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 = STATE_PUBLISHING;
}
/* Continue */
case 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 == STATE_CONNECTED) {
subscribe();
state = STATE_PUBLISHING;
} else {
leds_on(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 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 = STATE_REGISTERED;
return;
} else {
/* Max reconnect attempts reached. Enter error state */
state = STATE_ERROR;
DBG("Aborting connection after %u attempts\n", connect_attempt - 1);
}
break;
case STATE_CONFIG_ERROR:
/* Idle away. The only way out is a new config */
printf("Bad configuration\n");
return;
case STATE_ERROR:
default:
leds_on(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_demo_process, ev, data)
{
PROCESS_BEGIN();
printf("MQTT Demo Process\n");
if(init_config() != 1) {
PROCESS_EXIT();
}
update_config();
def_rt_rssi = 0x8000000;
uip_icmp6_echo_reply_callback_add(&echo_reply_notification,
echo_reply_handler);
etimer_set(&echo_request_timer, conf.def_rt_ping_interval);
PUBLISH_TRIGGER->configure(SENSORS_ACTIVE, 1);
/* Main loop */
while(1) {
PROCESS_YIELD();
if(ev == sensors_event && data == PUBLISH_TRIGGER) {
if(state == STATE_ERROR) {
connect_attempt = 1;
state = STATE_REGISTERED;
}
}
if((ev == PROCESS_EVENT_TIMER && data == &publish_periodic_timer) ||
ev == PROCESS_EVENT_POLL ||
(ev == sensors_event && data == PUBLISH_TRIGGER && PUBLISH_TRIGGER->value(BUTTON_SENSOR_VALUE_STATE) == 0)) {
state_machine();
}
if(ev == PROCESS_EVENT_TIMER && data == &echo_request_timer) {
ping_parent();
etimer_set(&echo_request_timer, conf.def_rt_ping_interval);
}
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
/**
* @}
* @}
*/

View file

@ -0,0 +1,51 @@
/*
* 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 cc2538-mqtt-demo
* @{
*
* \file
* Project specific configuration defines for the MQTT demo
*/
/*---------------------------------------------------------------------------*/
#ifndef PROJECT_CONF_H_
#define PROJECT_CONF_H_
/*---------------------------------------------------------------------------*/
/* User configuration */
#define MQTT_DEMO_STATUS_LED LEDS_GREEN
/* If undefined, the demo will attempt to connect to IBM's quickstart */
#define MQTT_DEMO_BROKER_IP_ADDR "fd00::215:83ff:fed2:dbd7"
/*---------------------------------------------------------------------------*/
#endif /* PROJECT_CONF_H_ */
/*---------------------------------------------------------------------------*/
/** @} */

View file

@ -0,0 +1,9 @@
CONTIKI_PROJECT = timer-test
CONTIKI_WITH_RPL=0
NRF52_WITHOUT_SOFTDEVICE=1
all: $(CONTIKI_PROJECT)
CONTIKI = ../../..
include $(CONTIKI)/Makefile.include

View file

@ -0,0 +1,20 @@
Timers test
===========
Timers test is an application allows for testing clocks implementation for nRF52 DK.
The results of different tests are output to the console.
There are 4 tests performed:
1) TEST clock_delay_usec() - measures duration of a NOP delay using rtimer. It's expected
that difference is close to 0.
2) TEST rtimer - schedules an rtimer callback after 1 second. Prints actual time difference
in rtimer and clock ticks. It's expected that both values are close to 0.
3) TEST etimer - schedules an event timer and measures time difference. It is expected that
the value is close to 0.
The example requires one DK and it doesn't use SoftDevice. To compile and flash the
example run:
make TARGET=nrf52dk timer-test.flash

View file

@ -0,0 +1,131 @@
/**
* \file
* Tests related to clocks and timers
* This is based on clock_test.c from the original sensinode port
*
* \author
* Zach Shelby <zach@sensinode.com> (Original)
* George Oikonomou - <oikonomou@users.sourceforge.net> (rtimer code)
* Wojciech Bober <wojciech.bober@nordicsemi.no> (nRF52 DK adaptation)
*
*/
/**
* \addtogroup nrf52dk-examples Demo projects for nRF52 DK
* @{
*/
#include "contiki.h"
#include "sys/clock.h"
#include "sys/rtimer.h"
#include "dev/leds.h"
#include "nrf_delay.h"
#include <stdio.h>
/*---------------------------------------------------------------------------*/
#define TEST_CLOCK_DELAY_USEC 1
#define TEST_RTIMER 1
#define TEST_ETIMER 1
/*---------------------------------------------------------------------------*/
static struct etimer et;
#if TEST_CLOCK_DELAY_USEC
static rtimer_clock_t start_count, end_count, diff;
#endif
#if TEST_ETIMER
static clock_time_t count;
#endif
#if TEST_RTIMER
static struct rtimer rt;
static clock_time_t ct_now;
rtimer_clock_t rt_now, rt_until;
static volatile rtimer_clock_t rt_now_cb;
static volatile clock_time_t ct_cb;
#endif
static uint8_t i;
/*---------------------------------------------------------------------------*/
PROCESS(clock_test_process, "Clock test process");
AUTOSTART_PROCESSES(&clock_test_process);
/*---------------------------------------------------------------------------*/
#if TEST_RTIMER
void
rt_callback(struct rtimer *t, void *ptr)
{
rt_now_cb = RTIMER_NOW();
ct_cb = clock_time();
}
#endif
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(clock_test_process, ev, data)
{
PROCESS_BEGIN();
etimer_set(&et, 2 * CLOCK_SECOND);
PROCESS_YIELD();
printf("RTIMER_SECOND=%d CLOCK_SECOND=%d\n", RTIMER_SECOND, CLOCK_SECOND);
#if TEST_CLOCK_DELAY_USEC
printf("=======================\n");
printf("TEST clock_delay_usec()\n");
printf("=======================\n");
i = 1;
while(i < 7) {
start_count = RTIMER_NOW();
clock_delay_usec(10000 * i);
end_count = RTIMER_NOW();
diff = end_count - start_count;
printf("difference [usec]: %ld\n", 10000 * i - (diff*(1000000/RTIMER_SECOND)));
i++;
}
#endif
#if TEST_RTIMER
printf("=======================\n");
printf("TEST rtimer\n");
printf("=======================\n");
i = 0;
while(i < 5) {
etimer_set(&et, 2 * CLOCK_SECOND);
rt_now = RTIMER_NOW();
ct_now = clock_time();
rt_until = rt_now + RTIMER_SECOND;
printf("now [ticks]: %lu until[ticks]: %lu\n", rt_now, rt_until);
if (rtimer_set(&rt, rt_until, 1, rt_callback, NULL) != RTIMER_OK) {
printf("Error setting\n");
}
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
printf("rtimer difference [ticks]: %ld\n", RTIMER_SECOND - (rt_now_cb - rt_now));
printf("clock difference [ticks]: %ld\n", CLOCK_SECOND - (ct_cb - ct_now));
i++;
}
#endif
#if TEST_ETIMER
printf("=======================\n");
printf("TEST etimer\n");
printf("=======================\n");
i = 0;
while(i < 5) {
etimer_set(&et, i*CLOCK_SECOND);
count = clock_time();
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
etimer_reset(&et);
printf("difference [ticks]: %lu\n", i*CLOCK_SECOND - (clock_time() - count));
leds_toggle(LEDS_RED);
i++;
}
#endif
printf("Done!\n");
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
/**
* @}
*/

View file

@ -83,31 +83,33 @@ static struct broadcast_conn bc;
PROCESS_THREAD(openmote_demo_process, ev, data)
{
static struct etimer et;
static unsigned int raw, counter;
static uint8_t adxl346_present, max44009_present, sht21_present;
static float light, temperature, humidity;
static int16_t counter;
static uint16_t adxl346_present, sht21_present, max44009_present;
static int16_t accel, light, temperature, humidity;
PROCESS_EXITHANDLER(broadcast_close(&bc))
PROCESS_BEGIN();
adxl346_init();
adxl346_present = adxl346_is_present();
if(!adxl346_present) {
/* Initialize and calibrate the ADXL346 sensor */
adxl346_present = SENSORS_ACTIVATE(adxl346);
if(adxl346_present == ADXL346_ERROR) {
printf("ADXL346 sensor is NOT present!\n");
leds_on(LEDS_YELLOW);
} else {
adxl346.configure(ADXL346_CALIB_OFFSET, 0);
}
max44009_init();
max44009_present = max44009_is_present();
if(!max44009_present) {
/* Initialize the MAX44009 sensor */
max44009_present = SENSORS_ACTIVATE(max44009);
if(max44009_present == MAX44009_ERROR) {
printf("MAX44009 sensor is NOT present!\n");
leds_on(LEDS_ORANGE);
}
sht21_init();
sht21_present = sht21_is_present();
if(!sht21_present) {
/* Initialize the SHT21 sensor */
sht21_present = SENSORS_ACTIVATE(sht21);
if(sht21_present == SHT21_ERROR) {
printf("SHT21 sensor is NOT present!\n");
leds_on(LEDS_RED);
}
@ -123,33 +125,30 @@ PROCESS_THREAD(openmote_demo_process, ev, data)
PROCESS_YIELD();
if(ev == PROCESS_EVENT_TIMER) {
if(adxl346_present) {
if(adxl346_present != ADXL346_ERROR) {
leds_on(LEDS_YELLOW);
raw = adxl346_read_x();
printf("X Acceleration: %u\n", raw);
raw = adxl346_read_y();
printf("Y Acceleration: %u\n", raw);
raw = adxl346_read_z();
printf("Z Acceleration: %u\n", raw);
accel = adxl346.value(ADXL346_READ_X_mG);
printf("X Acceleration: %d.%u G\n", accel / 1000, accel % 1000);
accel = adxl346.value(ADXL346_READ_Y_mG);
printf("Y Acceleration: %d.%u G\n", accel / 1000, accel % 1000);
accel = adxl346.value(ADXL346_READ_Z_mG);
printf("Z Acceleration: %d.%u G\n", accel / 1000, accel % 1000);
leds_off(LEDS_YELLOW);
}
if(max44009_present) {
if(max44009_present != MAX44009_ERROR) {
leds_on(LEDS_ORANGE);
raw = max44009_read_light();
light = max44009_convert_light(raw);
printf("Light: %u.%ulux\n", (unsigned int)light, (unsigned int)(light * 100) % 100);
light = max44009.value(MAX44009_READ_LIGHT);
printf("Light: %u.%ulux\n", light / 100, light % 100);
leds_off(LEDS_ORANGE);
}
if(sht21_present) {
if(sht21_present != SHT21_ERROR) {
leds_on(LEDS_RED);
raw = sht21_read_temperature();
temperature = sht21_convert_temperature(raw);
printf("Temperature: %u.%uC\n", (unsigned int)temperature, (unsigned int)(temperature * 100) % 100);
raw = sht21_read_humidity();
humidity = sht21_convert_humidity(raw);
printf("Rel. humidity: %u.%u%%\n", (unsigned int)humidity, (unsigned int)(humidity * 100) % 100);
temperature = sht21.value(SHT21_READ_TEMP);
printf("Temperature: %u.%uC\n", temperature / 100, temperature % 100);
humidity = sht21.value(SHT21_READ_RHUM);
printf("Rel. humidity: %u.%u%%\n", humidity / 100, humidity % 100);
leds_off(LEDS_RED);
}

View file

@ -39,11 +39,6 @@
#include "contiki.h"
#include "net/rime/rime.h"
#include "dev/button-sensor.h"
#include "dev/leds.h"
#include <stdio.h>
/*---------------------------------------------------------------------------*/
@ -56,7 +51,19 @@ recv_uc(struct unicast_conn *c, const linkaddr_t *from)
printf("unicast message received from %d.%d\n",
from->u8[0], from->u8[1]);
}
static const struct unicast_callbacks unicast_callbacks = {recv_uc};
/*---------------------------------------------------------------------------*/
static void
sent_uc(struct unicast_conn *c, int status, int num_tx)
{
const linkaddr_t *dest = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
if(linkaddr_cmp(dest, &linkaddr_null)) {
return;
}
printf("unicast message sent to %d.%d: status %d num_tx %d\n",
dest->u8[0], dest->u8[1], status, num_tx);
}
/*---------------------------------------------------------------------------*/
static const struct unicast_callbacks unicast_callbacks = {recv_uc, sent_uc};
static struct unicast_conn uc;
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(example_unicast_process, ev, data)

View file

@ -77,7 +77,7 @@ do_rssi(void)
printf("RSSI:");
for(channel = 0; channel <= 85; ++channel) {
set_frq(channel);
printf("%d ", cc2420_rssi() + 55);
printf("%d ", cc2420_rssi() + 100);
}
printf("\n");
}

View file

@ -3,7 +3,7 @@ ifndef TARGET
TARGET=sky
endif
all: blink sky-collect #rt-leds test-button test-cfs tcprudolph0
all: blink sky-collect #rt-leds test-button tcprudolph0
%.tgz: %.ihex
mkdir $(basename $<) ; \

View file

@ -55,14 +55,14 @@ endif
disk: all
cp $(CONTIKI)/tools/$(TARGET)/prodos.dsk contiki.dsk
java -jar $(AC) -p contiki.dsk contiki.system sys < $(CC65_HOME)/targetutil/loader.system
java -jar $(AC) -p contiki.dsk contiki.system sys < $(CC65_TARGET_DIR)/util/loader.system
java -jar $(AC) -cc65 contiki.dsk contiki bin < $(CONTIKI_PROJECT).$(TARGET)
java -jar $(AC) -p contiki.dsk contiki.cfg bin 0 < $(CONTIKI)/tools/$(TARGET)/sample.cfg
java -jar $(AC) -p contiki.dsk cs8900a.eth rel 0 < cs8900a.eth
java -jar $(AC) -p contiki.dsk lan91c96.eth rel 0 < lan91c96.eth
java -jar $(AC) -p contiki.dsk w5100.eth rel 0 < w5100.eth
ifeq ($(findstring WITH_MOUSE,$(DEFINES)),WITH_MOUSE)
java -jar $(AC) -p contiki.dsk contiki.mou rel 0 < $(CC65_HOME)/mou/a2e.stdmou.mou
java -jar $(AC) -p contiki.dsk contiki.mou rel 0 < $(CC65_TARGET_DIR)/drv/mou/a2e.stdmou.mou
endif
ifeq ($(HTTPD-CFS),1)
java -jar $(AC) -p contiki.dsk index.htm bin 0 < httpd-cfs/index.htm

View file

@ -55,7 +55,7 @@ disk: all
cp $(CONTIKI)/tools/$(TARGET)/sample.cfg atr/contiki.cfg
cp cs8900a.eth atr/cs8900a.eth
ifeq ($(findstring WITH_MOUSE,$(DEFINES)),WITH_MOUSE)
cp $(CC65_HOME)/mou/atrxst.mou atr/contiki.mou
cp $(CC65_TARGET_DIR)/drv/mou/atrxst.mou atr/contiki.mou
endif
ifeq ($(HTTPD-CFS),1)
cp httpd-cfs/index.htm atr/index.htm

View file

@ -46,16 +46,16 @@ endif
disk: all
$(C1541) -format contiki,00 d71 contiki.d71
$(C1541) -attach contiki.d71 -write $(CONTIKI_PROJECT).$(TARGET) contiki,p
$(C1541) -attach contiki.d71 -write $(CONTIKI)/tools/$(TARGET)/sample.cfg contiki.cfg,s
$(C1541) -attach contiki.d71 -write cs8900a.eth cs8900a.eth,s
$(C1541) -attach contiki.d71 -write lan91c96.eth lan91c96.eth,s
$(C1541) -attach contiki.d71 -write $(CONTIKI_PROJECT).$(TARGET) contiki,p
$(C1541) -attach contiki.d71 -write $(CONTIKI)/tools/$(TARGET)/sample.cfg contiki.cfg,s
$(C1541) -attach contiki.d71 -write cs8900a.eth cs8900a.eth,s
$(C1541) -attach contiki.d71 -write lan91c96.eth lan91c96.eth,s
ifeq ($(findstring WITH_MOUSE,$(DEFINES)),WITH_MOUSE)
$(C1541) -attach contiki.d71 -write $(CC65_HOME)/mou/c128-1351.mou contiki.mou,s
$(C1541) -attach contiki.d71 -write $(CC65_TARGET_DIR)/drv/mou/c128-1351.mou contiki.mou,s
endif
ifeq ($(HTTPD-CFS),1)
$(C1541) -attach contiki.d71 -write httpd-cfs/index.htm index.htm,s
$(C1541) -attach contiki.d71 -write httpd-cfs/backgrnd.gif backgrnd.gif,s
$(C1541) -attach contiki.d71 -write httpd-cfs/contiki.gif contiki.gif,s
$(C1541) -attach contiki.d71 -write httpd-cfs/notfound.htm notfound.htm,s
$(C1541) -attach contiki.d71 -write httpd-cfs/index.htm index.htm,s
$(C1541) -attach contiki.d71 -write httpd-cfs/backgrnd.gif backgrnd.gif,s
$(C1541) -attach contiki.d71 -write httpd-cfs/contiki.gif contiki.gif,s
$(C1541) -attach contiki.d71 -write httpd-cfs/notfound.htm notfound.htm,s
endif

View file

@ -50,16 +50,16 @@ endif
disk: all
$(C1541) -format contiki,00 d64 contiki.d64
$(C1541) -attach contiki.d64 -write $(CONTIKI_PROJECT).$(TARGET) contiki,p
$(C1541) -attach contiki.d64 -write $(CONTIKI)/tools/$(TARGET)/sample.cfg contiki.cfg,s
$(C1541) -attach contiki.d64 -write cs8900a.eth cs8900a.eth,s
$(C1541) -attach contiki.d64 -write lan91c96.eth lan91c96.eth,s
$(C1541) -attach contiki.d64 -write $(CONTIKI_PROJECT).$(TARGET) contiki,p
$(C1541) -attach contiki.d64 -write $(CONTIKI)/tools/$(TARGET)/sample.cfg contiki.cfg,s
$(C1541) -attach contiki.d64 -write cs8900a.eth cs8900a.eth,s
$(C1541) -attach contiki.d64 -write lan91c96.eth lan91c96.eth,s
ifeq ($(findstring WITH_MOUSE,$(DEFINES)),WITH_MOUSE)
$(C1541) -attach contiki.d64 -write $(CC65_HOME)/mou/c64-1351.mou contiki.mou,s
$(C1541) -attach contiki.d64 -write $(CC65_TARGET_DIR)/drv/mou/c64-1351.mou contiki.mou,s
endif
ifeq ($(HTTPD-CFS),1)
$(C1541) -attach contiki.d64 -write httpd-cfs/index.htm index.htm,s
$(C1541) -attach contiki.d64 -write httpd-cfs/backgrnd.gif backgrnd.gif,s
$(C1541) -attach contiki.d64 -write httpd-cfs/contiki.gif contiki.gif,s
$(C1541) -attach contiki.d64 -write httpd-cfs/notfound.htm notfound.htm,s
$(C1541) -attach contiki.d64 -write httpd-cfs/index.htm index.htm,s
$(C1541) -attach contiki.d64 -write httpd-cfs/backgrnd.gif backgrnd.gif,s
$(C1541) -attach contiki.d64 -write httpd-cfs/contiki.gif contiki.gif,s
$(C1541) -attach contiki.d64 -write httpd-cfs/notfound.htm notfound.htm,s
endif

View file

@ -68,15 +68,3 @@ uip_debug_ipaddr_print(const uip_ipaddr_t *addr)
#endif /* NETSTACK_CONF_WITH_IPV6 */
}
/*---------------------------------------------------------------------------*/
void
uip_debug_lladdr_print(const uip_lladdr_t *addr)
{
unsigned int i;
for(i = 0; i < sizeof(uip_lladdr_t); i++) {
if(i > 0) {
putstring(":");
}
puthex(addr->addr[i]);
}
}
/*---------------------------------------------------------------------------*/

View file

@ -34,12 +34,20 @@ typedef uint32_t uip_stats_t;
/*
* rtimer.h typedefs rtimer_clock_t as unsigned short. We need to define
* RTIMER_CLOCK_LT to override this
* RTIMER_CLOCK_DIFF to override this
*/
typedef uint32_t rtimer_clock_t;
#define RTIMER_CLOCK_LT(a,b) ((int32_t)((a)-(b)) < 0)
#define RTIMER_CLOCK_DIFF(a,b) ((int32_t)((a)-(b)))
/** @} */
/*---------------------------------------------------------------------------*/
#define TSCH_CONF_HW_FRAME_FILTERING 0
/* 352us from calling transmit() until the SFD byte has been sent */
#define RADIO_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
/*---------------------------------------------------------------------------*/
/**
* \name Serial Boot Loader Backdoor configuration
*

View file

@ -198,7 +198,7 @@ typedef unsigned short uip_stats_t;
#define CLOCK_CONF_SECOND 1000L
typedef unsigned long clock_time_t;
typedef unsigned long rtimer_clock_t;
#define RTIMER_CLOCK_LT(a,b) ((signed long)((a)-(b)) < 0)
#define RTIMER_CLOCK_DIFF(a,b) ((signed long)((a)-(b)))
#define AODV_COMPLIANCE
#define AODV_NUM_RT_ENTRIES 32

View file

@ -46,7 +46,7 @@ typedef unsigned long clock_time_t;
typedef uint64_t rtimer_clock_t;
#define RTIMER_ARCH_SECOND 1024
#define RTIMER_CLOCK_LT(a, b) ((int64_t)((a) - (b)) < 0)
#define RTIMER_CLOCK_DIFF(a, b) ((int64_t)((a) - (b)))
/* We define the following macros and types otherwise Contiki does not
* compile.

View file

@ -80,9 +80,9 @@
#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_LT is defined */
/* Core rtimer.h defaults to 16 bit timer unless RTIMER_CLOCK_DIFF is defined */
typedef uint32_t rtimer_clock_t;
#define RTIMER_CLOCK_LT(a, b) ((int32_t)((a) - (b)) < 0)
#define RTIMER_CLOCK_DIFF(a, b) ((int32_t)((a) - (b)))
/* 8ms timer tick */
#define CLOCK_CONF_SECOND 125

View file

@ -179,7 +179,7 @@ main(void)
NETSTACK_RDC.channel_check_interval()));
printf("802.15.4 PAN ID 0x%x, EUI-%d:",
IEEE802154_CONF_PANID, UIP_CONF_LL_802154?64:16);
uip_debug_lladdr_print((const uip_lladdr_t *)&linkaddr_node_addr);
net_debug_lladdr_print((const uip_lladdr_t *)&linkaddr_node_addr);
printf(", radio channel %u\n", RF_CHANNEL);
procinit_init();

View file

@ -87,7 +87,7 @@ typedef unsigned long clock_time_t;
typedef unsigned long rtimer_clock_t;
#define RTIMER_CLOCK_LT(a,b) ((signed long)((a)-(b)) < 0)
#define RTIMER_CLOCK_DIFF(a,b) ((signed long)((a)-(b)))
#define LEDS_CONF_RED_PIN boardDescription->io->leds[1].gpioPin
#define LEDS_CONF_GREEN_PIN boardDescription->io->leds[0].gpioPin

View file

@ -0,0 +1,34 @@
ifndef CONTIKI
$(error CONTIKI not defined! You must specify where CONTIKI resides!)
endif
### Include the board-specific makefile
PLATFORM_ROOT_DIR = $(CONTIKI)/platform/$(TARGET)
CONTIKI_TARGET_DIRS += . dev config
CONTIKI_SOURCEFILES += contiki-main.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 cpu/arm/common
CONTIKI_TARGET_DIRS += rtt
CONTIKI_SOURCEFILES += rtt-printf.c segger-rtt.c segger-rtt-printf.c
else
CONTIKI_TARGET_DIRS += dbg-io
CONTIKI_SOURCEFILES += dbg.c
CONTIKI_CPU_DIRS += ../arm/common/dbg-io
CONTIKI_CPU_SOURCEFILES += dbg-printf.c dbg-putchar.c dbg-snprintf.c dbg-sprintf.c strformat.c
endif
CLEAN += *.nrf52dk
### Unless the example dictates otherwise, build with code size optimisations switched
### off
ifndef SMALL
SMALL = 0
endif
### Define the CPU directory and pull in the correct CPU makefile.
CONTIKI_CPU=$(CONTIKI)/cpu/nrf52832
include $(CONTIKI_CPU)/Makefile.nrf52832
MODULES += core/net core/net/mac core/net/llsec

View file

@ -0,0 +1,100 @@
This README contains information how to establish an IPv6 connecton between
Linux BLE router and an IPSP enabled BLE device.
Prerequisites
=============
In general, any device capable of running Linux operating system, can be used
as a BLE router provided the following conditions are met:
* Linux Kernel >3.18 is used
* bluez, libcap-ng0, radvd tools are present.
If a built-in Bluetooth device is not available then Bluetooth 4.0 compatible
USB dongle can be used.
The following procedures have been tested on Ubuntu 15.10.
Establishing an IPv6 connection
===============================
Use the following procedure to establish a connection between an nRF52 device
and Linux router:
First enable 6LoWPAN module. This is neccessary only once per session:
# Log in as a root user.
sudo su
# Mount debugfs file system.
mount -t debugfs none /sys/kernel/debug
# Load 6LoWPAN module.
modprobe bluetooth_6lowpan
# Enable the bluetooth 6lowpan module.
echo 1 > /sys/kernel/debug/bluetooth/6lowpan_enable
# Look for available HCI devices.
hciconfig
# Reset HCI device - for example hci0 device.
hciconfig hci0 reset
# Read 00:AA:BB:XX:YY:ZZ address of the nRF5x device.
hcitool lescan
If you see device name and address in lescan output then you can connect to the
device:
echo "connect 00:AA:BB:XX:YY:ZZ 1" > /sys/kernel/debug/bluetooth/6lowpan_control
If above is successful then LED1 will stop blinking and LED2 will switch on.
You can then check the connection using the following commands:
# Check if bt0 interface is present and up
ifconfig
# Try to ping the device using its link-local address, for example, on bt0 interface.
ping6 -I bt0 fe80::2aa:bbff:fexx:yyzz
If you'd like to learn more about the procedure please refer to
[Connecting devices to the router].
Distributing routable IPv6 prefix
=================================
In Linux, Router Advertisement Daemon (RADVD) can be used to distribute prefixes
in the network, hance configure routable IPv6 address.
To configure RADVD create `/etc/radvd.conf` file and paste the following contents:
interface bt0
{
AdvSendAdvert on;
prefix 2001:db8::/64
{
AdvOnLink off;
AdvAutonomous on;
AdvRouterAddr on;
};
};
Next, start RADVD daemon:
# Set IPv6 forwarding (must be present).
sudo echo 1 > /proc/sys/net/ipv6/conf/all/forwarding
# Run radvd daemon.
sudo service radvd restart
If successfull then all devices connected to the host will receive
a routable `2001:db8` prefix.
This can be verified by sending echo request to the full address:
ping6 -I bt0 2001:db8::2aa:bbff:fexx:yyzz
where `aa:bbff:fexx:yyzz` is device Bluetooth address.
If you'd like to learn more about the procedure please refer to
[Distributing a global IPv6 prefix].
* [Connecting devices to the router]: http://developer.nordicsemi.com/nRF5_IoT_SDK/doc/0.9.0/html/a00089.html
* [Distributing a global IPv6 prefix]: http://developer.nordicsemi.com/nRF5_IoT_SDK/doc/0.9.0/html/a00090.html

254
platform/nrf52dk/README.md Normal file
View file

@ -0,0 +1,254 @@
Contiki for nRF52 Development Kit
=================================
This guide's aim is to help you with using Contiki for
Nordic Semiconductor's nRF52 DK.
The port depends on Nordic Semiconductor IoT SDK for nRF52.
The IoT SDK contains source code and libraries which are
required for successfull port compilation. It also contains
SoftDevice binary driver which is required for BLE operation.
See prerequisites section for details on how to set up the SDK.
For more information about SoftDevice please refer to the SDK
docummentation [nRF52 Datasheet and SDK documentation].
This port supports DK versions PCA10040 and PCA10036.
Port Features
=============
The following features have been implemented:
* Support for IPv6 over BLE using Contiki 6LoWPAN implementation
* Contiki system clock and rtimers (using 32kHz and 1MHz timers)
* UART driver
* Watchdog driver
* Hardware RNG
* Temperature sensor driver
* DK LED driver
* DK Buttons driver
* Real Time Transfer (RTT) I/O support
Note that this port supports only IPv6 network stack.
The port is organized as follows:
* nRF52832 CPU and BLE drivers are located in `cpu/nrf52832` folder
* nRF52 Development Kit drivers are located in `platform/nrf52dk` folder
* Platform examples are located in `examples/nrf52dk` folder
Prerequisites and Setup
=======================
In order to compile for the nRF52 DK platform you'll need:
* nRF5 IOT SDK
https://developer.nordicsemi.com
Download nRF5 IOT SDK, extract it to a folder of your choice,
and point `NRF52_SDK_ROOT` environmental variable to it, e.g.,:
```
wget https://developer.nordicsemi.com/nRF5_IoT_SDK/nRF5_IoT_SDK_v0.9.x/nrf5_iot_sdk_3288530.zip
unzip nrf5_iot_sdk_3288530.zip -d /path/to/sdk
export NRF52_SDK_ROOT=/path/to/sdk
```
* An ARM compatible toolchain
The port has been tested with GNU Tools for ARM Embedded Processors
version 5.2.1.
For Ubuntu you can use package version provided by your distribution:
```
sudo apt-get install gcc-arm-none-eabi
```
Alternatively, install the toolchain from PPA to get the latest version
of the compiler: https://launchpad.net/~team-gcc-arm-embedded/+archive/ubuntu/ppa
For other systems please download and install toolchain available at
https://launchpad.net/gcc-arm-embedded
* GNU make
* Segger JLink Software for Linux
https://www.segger.com/jlink-software.html
This package contains tools necessary for programming and debugging nRF52 DK.
For Ubuntu you can download and install a .deb package. Alternatively download
tar.gz archive and extract it to a folder of your choice. In this case you
need to set `NRF52_JLINK_PATH` environmental variable to point to the
JLink tools location:
```
export NRF52_JLINK_PATH=/path/to/jlink/tools
```
To keep this variable set between sessions please add the above line to your
`rc.local` file.
In order to access the DK as a regular Linux user create a `99-jlink.rules`
file in your udev rules folder (e.g., `/etc/udev/rules.d/`) and add the
following line to it:
```
ATTRS{idProduct}=="1015", ATTRS{idVendor}=="1366", MODE="0666"
```
When installing from a deb package, the `99-jlink.rules` file is added
automatically to /etc/udev/rules.d folder. However, the syntax of the file
doesn't work on newer udev versions. To fix this problem edit this file and
replace ATTR keyword with ATTRS.
To fully use the platform a BLE enabled router device is needed. Please refer
to `Preqrequisites` section in `README-BLE-6LoWPAN.md` for details.
Getting Started
===============
Once all tools are installed it is recommended to start by compiling
and flashing `examples/hello-word` application. This allows to verify
that toolchain setup is correct.
To compile the example, go to `examples/hello-world` and execute:
make TARGET=nrf52dk
If you haven't used the device with Contiki before we advise to
erase the device and flash new SoftDevice:
make TARGET=nrf52dk erase
make TARGET=nrf52dk softdevice.flash
If the compilation is completed without errors flash the board:
make TARGET=nrf52dk hello-world.flash
The device will start BLE advertising as soon as initialized. By
default the device name is set to 'Contiki nRF52 DK'. To verify
that the device is advertising properly run:
sudo hcitool lescan
And observe if the device name appears in the output. Also, observe
if LED1 is blinking what indicates that device is waiting for a connection
from BLE master.
If device is functioning as expected you can test IPv6 connection
to the device. Please refer to `README-BLE-6LoWPAN.md` on details how to do
this.
Examples
========
Examples specific for nRF52 DK can be found in `examples/nrf52dk` folder. Please
refer to README.md in respective examples for detailed description.
The DK has also been tested with the `examples/hello-world` and `examples/webserver-ipv6`
generic examples.
Compilation Options
===================
The Contiki TARGET name for this port is `nrf52dk`, so in order to compile
an application you need to invoke GNU make as follows:
make TARGET=nrf52dk
In addition to this port supports the following variables which can be
set on the compilation command line:
* `NRF52_SDK_ROOT=<SDK PATH>`
This variable allows to specify a path to the nRF52 SDK which should
be used for the build.
* `NRF52_WITHOUT_SOFTDEVICE={0|1}`
Disables SoftDevice support if set to 1. By default, SoftDevice support
is used. Note that SoftDevice must be present (flashed) in the device
before you run an application that requires it's presence.
* `NRF52_USE_RTT={0|1}`
Enables RealTime Terminal I/O. See VCOM and RTT for details. By default,
RTT is disabled and IO is done using Virtual COM port.
* `NRF52_JLINK_SN=<serial number>`
Allows to choose a particular DK by its serial number (printed on the
label). This is useful if you have more than one DK connected to your
PC and whish to flash a particular device.
* `NRF52_DK_REVISION={pca10040|pca10036}`
Allows to specify DK revision. By default, pca10040 is used.
Compilation Targets
===================
Invoking make solely with the `TARGET` variable set will build all
applications in a given folder. A particular application can be built
by invoking make with its name as a compilation target:
make TARGET=nrf52dk hello-world
In order to flash the application binary to the device use `<application>.flash`
as make target, e.g.:
make TARGET=nrf52dk hello-world.flash
In addition, the SoftDevice binary can be flashed to the DK by invoking:
make TARGET=nrf52dk softdevice.flash
To remove all build results invoke:
make TARGET=nrf52dk clean
The device memory can be erased using:
make TARGET=nrf52dk erase
Note, that once the device is erased, the SoftDevice must be programmed again.
Virtual COM and Real Time Transfer
==================================
By default, the nRF52 DK uses a Virtual COM port to output logs. Once
the DK is plugged in a `/tty/ACM<n>` or `/ttyUSB<n>` device should appear in
your filesystem. A terminal emulator, such as picocom or minicom, can be
used to connect to the device. Default serial port speed is 38400 bps.
To connect to serial port using picocom invoke:
picocom -fh -b 38400 --imap lfcrlf /dev/ttyACM0
Note, that if you have not fixed file permissions for `/dev/ttyACM0`
according to section `Segger JLink Software for Linux` you'll need to use
root or sudo to open the port with `picocom`.
In addition to Virtual COM the port supports SEGGER's Real Time Transfer
for low overhead I/O support. This allows for outputting debugging information
at much higher rate with significantly lower overhead than regular I/O.
To compile an application with RTT rather that VCOM set `NRF52_USE_RTT` to 1 on
the compilation command line:
make TARGET=nrf52dk NRF52_USE_RTT=1 hello-world
You can then connect to the device terminal using `JLinkRTTClient`. Note that
a JLlink gdb or commander must be connected to the target for the RTT to work.
More details regarding RTT can be found at https://www.segger.com/jlink-rtt.html
Docummentation
==============
This port provides doxygen source code docummentation. To build the
docummentation please run:
sudo apt-get install doxygen
cd <CONTIKI_ROOT>\doc
make
Support
=======
This port is officially supported by Nordic Semiconductor. Please send bug
reports or/and suggestions to <wojciech.bober@nordicsemi.no>.
License
=======
All files in the port are under BSD license. nRF52 SDK and SoftDevice are
licensed on a separate terms.
Resources
=========
* nRF52 Datasheet and SDK documentation (http://infocenter.nordicsemi.com)
* nRF52 SDK Downloads (https://developer.nordicsemi.com/)
* JLink Tools (https://www.segger.com/)

View file

@ -0,0 +1,329 @@
/*
* Copyright (c) 2015, Nordic Semiconductor
* 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 nrf52dk
* @{
*
* \defgroup nrf52dk-config nRF52 SDK configuration
* @{
*/
#ifndef NRF_DRV_CONFIG_H
#define NRF_DRV_CONFIG_H
/* CLOCK */
#define CLOCK_CONFIG_XTAL_FREQ NRF_CLOCK_XTALFREQ_Default
#define CLOCK_CONFIG_LF_SRC NRF_CLOCK_LF_SRC_Xtal
#define CLOCK_CONFIG_LF_RC_CAL_INTERVAL RC_2000MS_CALIBRATION_INTERVAL
#define CLOCK_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOW
/* GPIOTE */
#define GPIOTE_ENABLED 1
#if (GPIOTE_ENABLED == 1)
#define GPIOTE_CONFIG_USE_SWI_EGU false
#define GPIOTE_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_HIGH
#define GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS 4
#endif
/* TIMER */
#define TIMER0_ENABLED 0
#if (TIMER0_ENABLED == 1)
#define TIMER0_CONFIG_FREQUENCY NRF_TIMER_FREQ_16MHz
#define TIMER0_CONFIG_MODE TIMER_MODE_MODE_Timer
#define TIMER0_CONFIG_BIT_WIDTH TIMER_BITMODE_BITMODE_32Bit
#define TIMER0_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOW
#define TIMER0_INSTANCE_INDEX 0
#endif
#define TIMER1_ENABLED 1
#if (TIMER1_ENABLED == 1)
#define TIMER1_CONFIG_FREQUENCY NRF_TIMER_FREQ_62500Hz
#define TIMER1_CONFIG_MODE TIMER_MODE_MODE_Timer
#define TIMER1_CONFIG_BIT_WIDTH TIMER_BITMODE_BITMODE_32Bit
#define TIMER1_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOW
#define TIMER1_INSTANCE_INDEX (TIMER0_ENABLED)
#endif
#define TIMER2_ENABLED 0
#if (TIMER2_ENABLED == 1)
#define TIMER2_CONFIG_FREQUENCY NRF_TIMER_FREQ_16MHz
#define TIMER2_CONFIG_MODE TIMER_MODE_MODE_Timer
#define TIMER2_CONFIG_BIT_WIDTH TIMER_BITMODE_BITMODE_16Bit
#define TIMER2_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOW
#define TIMER2_INSTANCE_INDEX (TIMER1_ENABLED+TIMER0_ENABLED)
#endif
#define TIMER3_ENABLED 0
#if (TIMER3_ENABLED == 1)
#define TIMER3_CONFIG_FREQUENCY NRF_TIMER_FREQ_16MHz
#define TIMER3_CONFIG_MODE TIMER_MODE_MODE_Timer
#define TIMER3_CONFIG_BIT_WIDTH TIMER_BITMODE_BITMODE_16Bit
#define TIMER3_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOW
#define TIMER3_INSTANCE_INDEX (TIMER2_ENABLED+TIMER2_INSTANCE_INDEX)
#endif
#define TIMER4_ENABLED 0
#if (TIMER4_ENABLED == 1)
#define TIMER4_CONFIG_FREQUENCY NRF_TIMER_FREQ_16MHz
#define TIMER4_CONFIG_MODE TIMER_MODE_MODE_Timer
#define TIMER4_CONFIG_BIT_WIDTH TIMER_BITMODE_BITMODE_16Bit
#define TIMER4_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOW
#define TIMER4_INSTANCE_INDEX (TIMER3_ENABLED+TIMER3_INSTANCE_INDEX)
#endif
#define TIMER_COUNT (TIMER0_ENABLED + TIMER1_ENABLED + TIMER2_ENABLED + TIMER3_ENABLED + TIMER4_ENABLED)
/* RTC */
#define RTC0_ENABLED 0
#if (RTC0_ENABLED == 1)
#define RTC0_CONFIG_FREQUENCY 32678
#define RTC0_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOW
#define RTC0_CONFIG_RELIABLE false
#define RTC0_INSTANCE_INDEX 0
#endif
#define RTC1_ENABLED 1
#if (RTC1_ENABLED == 1)
#define RTC1_CONFIG_FREQUENCY 128
#define RTC1_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOW
#define RTC1_CONFIG_RELIABLE false
#define RTC1_INSTANCE_INDEX (RTC0_ENABLED)
#endif
#define RTC_COUNT (RTC0_ENABLED+RTC1_ENABLED)
#define NRF_MAXIMUM_LATENCY_US 2000
/* RNG */
#define RNG_ENABLED 1
#if (RNG_ENABLED == 1)
#define RNG_CONFIG_ERROR_CORRECTION true
#define RNG_CONFIG_POOL_SIZE 8
#define RNG_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOW
#endif
/* SPI */
#define SPI0_ENABLED 0
#if (SPI0_ENABLED == 1)
#define SPI0_USE_EASY_DMA 0
#define SPI0_CONFIG_SCK_PIN 2
#define SPI0_CONFIG_MOSI_PIN 3
#define SPI0_CONFIG_MISO_PIN 4
#define SPI0_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOW
#define SPI0_INSTANCE_INDEX 0
#endif
#define SPI1_ENABLED 0
#if (SPI1_ENABLED == 1)
#define SPI1_USE_EASY_DMA 0
#define SPI1_CONFIG_SCK_PIN 2
#define SPI1_CONFIG_MOSI_PIN 3
#define SPI1_CONFIG_MISO_PIN 4
#define SPI1_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOW
#define SPI1_INSTANCE_INDEX (SPI0_ENABLED)
#endif
#define SPI2_ENABLED 0
#if (SPI2_ENABLED == 1)
#define SPI2_USE_EASY_DMA 0
#define SPI2_CONFIG_SCK_PIN 2
#define SPI2_CONFIG_MOSI_PIN 3
#define SPI2_CONFIG_MISO_PIN 4
#define SPI2_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOW
#define SPI2_INSTANCE_INDEX (SPI0_ENABLED + SPI1_ENABLED)
#endif
#define SPI_COUNT (SPI0_ENABLED + SPI1_ENABLED + SPI2_ENABLED)
/* UART */
#define UART0_ENABLED 1
#if (UART0_ENABLED == 1)
#define UART0_CONFIG_HWFC NRF_UART_HWFC_DISABLED
#define UART0_CONFIG_PARITY NRF_UART_PARITY_EXCLUDED
#define UART0_CONFIG_BAUDRATE NRF_UART_BAUDRATE_38400
#define UART0_CONFIG_PSEL_TXD 6
#define UART0_CONFIG_PSEL_RXD 8
#define UART0_CONFIG_PSEL_CTS 7
#define UART0_CONFIG_PSEL_RTS 5
#define UART0_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOW
#ifdef NRF52
#define UART0_CONFIG_USE_EASY_DMA false
//Compile time flag
#define UART_EASY_DMA_SUPPORT 1
#define UART_LEGACY_SUPPORT 1
#endif //NRF52
#endif
#define TWI0_ENABLED 0
#if (TWI0_ENABLED == 1)
#define TWI0_CONFIG_FREQUENCY NRF_TWI_FREQ_100K
#define TWI0_CONFIG_SCL 0
#define TWI0_CONFIG_SDA 1
#define TWI0_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_HIGH
#define TWI0_INSTANCE_INDEX 0
#endif
#define TWI1_ENABLED 0
#if (TWI1_ENABLED == 1)
#define TWI1_CONFIG_FREQUENCY NRF_TWI_FREQ_100K
#define TWI1_CONFIG_SCL 0
#define TWI1_CONFIG_SDA 1
#define TWI1_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_HIGH
#define TWI1_INSTANCE_INDEX (TWI0_ENABLED)
#endif
#define TWI_COUNT (TWI0_ENABLED+TWI1_ENABLED)
/* TWIS */
#define TWIS0_ENABLED 0
#if (TWIS0_ENABLED == 1)
#define TWIS0_CONFIG_ADDR0 0
#define TWIS0_CONFIG_ADDR1 0 /* 0: Disabled */
#define TWIS0_CONFIG_SCL 0
#define TWIS0_CONFIG_SDA 1
#define TWIS0_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_HIGH
#define TWIS0_INSTANCE_INDEX 0
#endif
#define TWIS1_ENABLED 0
#if (TWIS1_ENABLED == 1)
#define TWIS1_CONFIG_ADDR0 0
#define TWIS1_CONFIG_ADDR1 0 /* 0: Disabled */
#define TWIS1_CONFIG_SCL 0
#define TWIS1_CONFIG_SDA 1
#define TWIS1_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_HIGH
#define TWIS1_INSTANCE_INDEX (TWIS0_ENABLED)
#endif
#define TWIS_COUNT (TWIS0_ENABLED + TWIS1_ENABLED)
/* For more documentation see nrf_drv_twis.h file */
#define TWIS_ASSUME_INIT_AFTER_RESET_ONLY 0
/* For more documentation see nrf_drv_twis.h file */
#define TWIS_NO_SYNC_MODE 0
/**
* \brief Definition for patching PAN problems
*
* Set this definition to nonzero value to patch anomalies
* from MPW3 - first lunch microcontroller.
*
* Concerns:
* - PAN-29: TWIS: incorrect bits in ERRORSRC
* - PAN-30: TWIS: STOP task does not work as expected
*/
#define NRF_TWIS_PATCH_FOR_MPW3 1
/* QDEC */
#define QDEC_ENABLED 0
#if (QDEC_ENABLED == 1)
#define QDEC_CONFIG_REPORTPER NRF_QDEC_REPORTPER_10
#define QDEC_CONFIG_SAMPLEPER NRF_QDEC_SAMPLEPER_16384us
#define QDEC_CONFIG_PIO_A 1
#define QDEC_CONFIG_PIO_B 2
#define QDEC_CONFIG_PIO_LED 3
#define QDEC_CONFIG_LEDPRE 511
#define QDEC_CONFIG_LEDPOL NRF_QDEC_LEPOL_ACTIVE_HIGH
#define QDEC_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOW
#define QDEC_CONFIG_DBFEN false
#define QDEC_CONFIG_SAMPLE_INTEN false
#endif
/* SAADC */
#define SAADC_ENABLED 0
#if (SAADC_ENABLED == 1)
#define SAADC_CONFIG_RESOLUTION NRF_SAADC_RESOLUTION_10BIT
#define SAADC_CONFIG_OVERSAMPLE NRF_SAADC_OVERSAMPLE_DISABLED
#define SAADC_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOW
#endif
/* LPCOMP */
#define LPCOMP_ENABLED 0
#if (LPCOMP_ENABLED == 1)
#define LPCOMP_CONFIG_REFERENCE NRF_LPCOMP_REF_SUPPLY_4_8
#define LPCOMP_CONFIG_DETECTION NRF_LPCOMP_DETECT_DOWN
#define LPCOMP_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOW
#define LPCOMP_CONFIG_INPUT NRF_LPCOMP_INPUT_0
#endif
/* WDT */
#define WDT_ENABLED 1
#if (WDT_ENABLED == 1)
#define WDT_CONFIG_BEHAVIOUR NRF_WDT_BEHAVIOUR_RUN_SLEEP
#define WDT_CONFIG_RELOAD_VALUE 2000
#define WDT_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_HIGH
#endif
#include "nrf_drv_config_validation.h"
#endif // NRF_DRV_CONFIG_H
/**
* @}
* @}
*/

Some files were not shown because too many files have changed in this diff Show more