cleanup confilicrts
This commit is contained in:
commit
3c8e91d74e
701 changed files with 56477 additions and 7743 deletions
1
apps/at-master/Makefile.at-master
Normal file
1
apps/at-master/Makefile.at-master
Normal file
|
@ -0,0 +1 @@
|
|||
at-master_src = at-master.c
|
148
apps/at-master/at-master.c
Normal file
148
apps/at-master/at-master.c
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Zolertia - http://www.zolertia.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
#include "contiki.h"
|
||||
#include "contiki-lib.h"
|
||||
#include "at-master.h"
|
||||
#include "cpu.h"
|
||||
#include "dev/uart.h"
|
||||
#include "dev/serial-line.h"
|
||||
#include "dev/sys-ctrl.h"
|
||||
#include "lib/list.h"
|
||||
#include "sys/cc.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define DEBUG 0
|
||||
#if DEBUG
|
||||
#define PRINTF(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define PRINTF(...)
|
||||
#endif
|
||||
/*---------------------------------------------------------------------------*/
|
||||
LIST(at_cmd_list);
|
||||
process_event_t at_cmd_received_event;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static uint8_t at_uart = 0;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS(at_process, "AT process");
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS_THREAD(at_process, ev, data)
|
||||
{
|
||||
uint8_t plen;
|
||||
char *pch, *buf;
|
||||
struct at_cmd *a;
|
||||
PROCESS_BEGIN();
|
||||
|
||||
while(1) {
|
||||
PROCESS_WAIT_EVENT_UNTIL(ev == serial_line_event_message && data != NULL);
|
||||
buf = (char *)data;
|
||||
plen = strlen(buf);
|
||||
for(a = list_head(at_cmd_list); a != NULL; a = list_item_next(a)) {
|
||||
pch = strstr(buf, a->cmd_header);
|
||||
if((plen <= a->cmd_max_len) && (pch != NULL)) {
|
||||
if(strncmp(a->cmd_header, pch, a->cmd_hdr_len) == 0) {
|
||||
if((a->cmd_hdr_len == plen) || (a->cmd_max_len > a->cmd_hdr_len)) {
|
||||
a->event_callback(a, plen, (char *)pch);
|
||||
process_post(a->app_process, at_cmd_received_event, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PROCESS_END();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
struct at_cmd *
|
||||
at_list(void)
|
||||
{
|
||||
return list_head(at_cmd_list);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uint8_t
|
||||
at_send(char *s, uint8_t len)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
while(s && *s != 0) {
|
||||
if(i >= len) {
|
||||
break;
|
||||
}
|
||||
uart_write_byte(at_uart, *s++);
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
at_init(uint8_t uart_sel)
|
||||
{
|
||||
static uint8_t inited = 0;
|
||||
if(!inited) {
|
||||
list_init(at_cmd_list);
|
||||
at_cmd_received_event = process_alloc_event();
|
||||
inited = 1;
|
||||
|
||||
at_uart = uart_sel;
|
||||
uart_init(at_uart);
|
||||
uart_set_input(at_uart, serial_line_input_byte);
|
||||
serial_line_init();
|
||||
|
||||
process_start(&at_process, NULL);
|
||||
PRINTF("AT: Started (%u)\n", at_uart);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
at_status_t
|
||||
at_register(struct at_cmd *cmd, struct process *app_process,
|
||||
const char *cmd_hdr, const uint8_t hdr_len,
|
||||
const uint8_t cmd_max_len, at_event_callback_t event_callback)
|
||||
{
|
||||
if((hdr_len < 1) || (cmd_max_len < 1) || (!strncmp(cmd_hdr, "AT", 2) == 0) ||
|
||||
(event_callback == NULL)) {
|
||||
PRINTF("AT: Invalid argument\n");
|
||||
return AT_STATUS_INVALID_ARGS_ERROR;
|
||||
}
|
||||
|
||||
memset(cmd, 0, sizeof(struct at_cmd));
|
||||
cmd->event_callback = event_callback;
|
||||
cmd->cmd_header = cmd_hdr;
|
||||
cmd->cmd_hdr_len = hdr_len;
|
||||
cmd->cmd_max_len = cmd_max_len;
|
||||
cmd->app_process = app_process;
|
||||
list_add(at_cmd_list, cmd);
|
||||
PRINTF("AT: registered HDR %s LEN %u MAX %u\n", cmd->cmd_header,
|
||||
cmd->cmd_hdr_len,
|
||||
cmd->cmd_max_len);
|
||||
return AT_STATUS_OK;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
123
apps/at-master/at-master.h
Normal file
123
apps/at-master/at-master.h
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Zolertia - http://www.zolertia.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
#ifndef AT_MASTER_H_
|
||||
#define AT_MASTER_H_
|
||||
#include "contiki.h"
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define AT_DEFAULT_RESPONSE_OK "\r\nOK\r\n"
|
||||
#define AT_DEFAULT_RESPONSE_ERROR "\r\nERROR\r\n"
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define AT_RESPONSE(x) at_send((x), (strlen(x)))
|
||||
/*---------------------------------------------------------------------------*/
|
||||
extern process_event_t at_cmd_received_event;
|
||||
struct at_cmd;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
typedef enum {
|
||||
AT_STATUS_OK,
|
||||
AT_STATUS_ERROR,
|
||||
AT_STATUS_INVALID_ARGS_ERROR,
|
||||
} at_status_t;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief AT initialization
|
||||
* \param uart selects which UART to use
|
||||
*
|
||||
* The AT driver invokes this function upon registering a command, this will
|
||||
* wait for the serial_line_event_message event
|
||||
*/
|
||||
void at_init(uint8_t uart);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief AT initialization
|
||||
* \param uart selects which UART to use
|
||||
*
|
||||
* The AT driver invokes this function upon registering a command, this will
|
||||
* wait for the serial_line_event_message event
|
||||
*/
|
||||
uint8_t at_send(char *s, uint8_t len);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief AT event callback
|
||||
* \param cmd A pointer to the AT command placeholder
|
||||
* \param len Lenght of the received data (including the AT command header)
|
||||
* \param data A user-defined pointer
|
||||
*
|
||||
* The AT event callback function gets called whenever there is an
|
||||
* event on an incoming AT command
|
||||
*/
|
||||
typedef void (*at_event_callback_t)(struct at_cmd *cmd,
|
||||
uint8_t len,
|
||||
char *data);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
struct at_cmd {
|
||||
struct at_cmd *next;
|
||||
const char *cmd_header;
|
||||
uint8_t cmd_hdr_len;
|
||||
uint8_t cmd_max_len;
|
||||
at_event_callback_t event_callback;
|
||||
struct process *app_process;
|
||||
};
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Registers the callback to return an AT command
|
||||
* \param cmd A pointer to the CMD placeholder
|
||||
* \param cmd_hdr String to compare when an AT command is received
|
||||
* \param cmd_len Lenght of cmd_hdr
|
||||
* \param event_callback Callback function to handle the AT command
|
||||
* \return AT_STATUS_OK or AT_STATUS_INVALID_ARGS_ERROR
|
||||
*
|
||||
* Register the commands to search for when a valid AT frame has been received
|
||||
*/
|
||||
at_status_t at_register(struct at_cmd *cmd,
|
||||
struct process *app_process,
|
||||
const char *cmd_hdr,
|
||||
const uint8_t cmd_hdr_len,
|
||||
const uint8_t cmd_max_len,
|
||||
at_event_callback_t event_callback);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
struct at_cmd *at_list(void);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Registers the callback to return an AT command
|
||||
* \param cmd A pointer to the CMD placeholder
|
||||
* \param cmd_hdr String to compare when an AT command is received
|
||||
* \param cmd_len Lenght of cmd_hdr
|
||||
* \param event_callback Callback function to handle the AT command
|
||||
* \return AT_STATUS_OK or AT_STATUS_INVALID_ARGS_ERROR
|
||||
*
|
||||
* Register the commands to search for when a valid AT frame has been received
|
||||
*/
|
||||
at_status_t at_register(struct at_cmd *cmd,
|
||||
struct process *app_process,
|
||||
const char *cmd_hdr,
|
||||
const uint8_t cmd_hdr_len,
|
||||
const uint8_t cmd_max_len,
|
||||
at_event_callback_t event_callback);
|
||||
#endif /* AT_MASTER_H_ */
|
|
@ -1 +0,0 @@
|
|||
deluge_src = deluge.c
|
|
@ -1,698 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, 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
|
||||
* An implementation of the Deluge protocol.
|
||||
* (Hui and Culler: The dynamic behavior of a data
|
||||
* dissemination protocol for network programming at scale,
|
||||
* ACM SenSys 2004)
|
||||
* \author
|
||||
* Nicolas Tsiftes <nvt@sics.se>
|
||||
*/
|
||||
|
||||
#include "contiki.h"
|
||||
#include "net/rime/rime.h"
|
||||
#include "cfs/cfs.h"
|
||||
#include "loader/elfloader.h"
|
||||
#include "lib/crc16.h"
|
||||
#include "lib/random.h"
|
||||
#include "sys/node-id.h"
|
||||
#include "deluge.h"
|
||||
|
||||
#if NETSIM
|
||||
#include "ether.h"
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "dev/leds.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define DEBUG 0
|
||||
#if DEBUG
|
||||
#include <stdio.h>
|
||||
#define PRINTF(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define PRINTF(...)
|
||||
#endif
|
||||
|
||||
/* Implementation-specific variables. */
|
||||
static struct broadcast_conn deluge_broadcast;
|
||||
static struct unicast_conn deluge_uc;
|
||||
static struct deluge_object current_object;
|
||||
static process_event_t deluge_event;
|
||||
|
||||
/* Deluge variables. */
|
||||
static int deluge_state;
|
||||
static int old_summary;
|
||||
static int neighbor_inconsistency;
|
||||
static unsigned r_interval;
|
||||
static unsigned recv_adv;
|
||||
static int broadcast_profile;
|
||||
|
||||
/* Deluge timers. */
|
||||
static struct ctimer rx_timer;
|
||||
static struct ctimer tx_timer;
|
||||
static struct ctimer summary_timer;
|
||||
static struct ctimer profile_timer;
|
||||
|
||||
/* Deluge objects will get an ID that defaults to the current value of
|
||||
the next_object_id parameter. */
|
||||
static deluge_object_id_t next_object_id;
|
||||
|
||||
/* Rime callbacks. */
|
||||
static void broadcast_recv(struct broadcast_conn *, const linkaddr_t *);
|
||||
static void unicast_recv(struct unicast_conn *, const linkaddr_t *);
|
||||
|
||||
static const struct broadcast_callbacks broadcast_call = {broadcast_recv, NULL};
|
||||
static const struct unicast_callbacks unicast_call = {unicast_recv, NULL};
|
||||
|
||||
/* The Deluge process manages the main Deluge timer. */
|
||||
PROCESS(deluge_process, "Deluge");
|
||||
|
||||
static void
|
||||
transition(int state)
|
||||
{
|
||||
if(state != deluge_state) {
|
||||
switch(deluge_state) {
|
||||
case DELUGE_STATE_MAINTAIN:
|
||||
ctimer_stop(&summary_timer);
|
||||
ctimer_stop(&profile_timer);
|
||||
break;
|
||||
case DELUGE_STATE_RX:
|
||||
ctimer_stop(&rx_timer);
|
||||
break;
|
||||
case DELUGE_STATE_TX:
|
||||
ctimer_stop(&tx_timer);
|
||||
break;
|
||||
}
|
||||
deluge_state = state;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
write_page(struct deluge_object *obj, unsigned pagenum, unsigned char *data)
|
||||
{
|
||||
cfs_offset_t offset;
|
||||
|
||||
offset = pagenum * S_PAGE;
|
||||
|
||||
if(cfs_seek(obj->cfs_fd, offset, CFS_SEEK_SET) != offset) {
|
||||
return -1;
|
||||
}
|
||||
return cfs_write(obj->cfs_fd, (char *)data, S_PAGE);
|
||||
}
|
||||
|
||||
static int
|
||||
read_page(struct deluge_object *obj, unsigned pagenum, unsigned char *buf)
|
||||
{
|
||||
cfs_offset_t offset;
|
||||
|
||||
offset = pagenum * S_PAGE;
|
||||
|
||||
if(cfs_seek(obj->cfs_fd, offset, CFS_SEEK_SET) != offset) {
|
||||
return -1;
|
||||
}
|
||||
return cfs_read(obj->cfs_fd, (char *)buf, S_PAGE);
|
||||
}
|
||||
|
||||
static void
|
||||
init_page(struct deluge_object *obj, int pagenum, int have)
|
||||
{
|
||||
struct deluge_page *page;
|
||||
unsigned char buf[S_PAGE];
|
||||
|
||||
page = &obj->pages[pagenum];
|
||||
|
||||
page->flags = 0;
|
||||
page->last_request = 0;
|
||||
page->last_data = 0;
|
||||
|
||||
if(have) {
|
||||
page->version = obj->version;
|
||||
page->packet_set = ALL_PACKETS;
|
||||
page->flags |= PAGE_COMPLETE;
|
||||
read_page(obj, pagenum, buf);
|
||||
page->crc = crc16_data(buf, S_PAGE, 0);
|
||||
} else {
|
||||
page->version = 0;
|
||||
page->packet_set = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static cfs_offset_t
|
||||
file_size(const char *file)
|
||||
{
|
||||
int fd;
|
||||
cfs_offset_t size;
|
||||
|
||||
fd = cfs_open(file, CFS_READ);
|
||||
if(fd < 0) {
|
||||
return (cfs_offset_t)-1;
|
||||
}
|
||||
|
||||
size = cfs_seek(fd, 0, CFS_SEEK_END);
|
||||
cfs_close(fd);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static int
|
||||
init_object(struct deluge_object *obj, char *filename, unsigned version)
|
||||
{
|
||||
static struct deluge_page *page;
|
||||
int i;
|
||||
|
||||
obj->cfs_fd = cfs_open(filename, CFS_READ | CFS_WRITE);
|
||||
if(obj->cfs_fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
obj->filename = filename;
|
||||
obj->object_id = next_object_id++;
|
||||
obj->size = file_size(filename);
|
||||
obj->version = obj->update_version = version;
|
||||
obj->current_rx_page = 0;
|
||||
obj->nrequests = 0;
|
||||
obj->tx_set = 0;
|
||||
|
||||
obj->pages = malloc(OBJECT_PAGE_COUNT(*obj) * sizeof(*obj->pages));
|
||||
if(obj->pages == NULL) {
|
||||
cfs_close(obj->cfs_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(i = 0; i < OBJECT_PAGE_COUNT(current_object); i++) {
|
||||
page = ¤t_object.pages[i];
|
||||
init_page(¤t_object, i, 1);
|
||||
}
|
||||
|
||||
memset(obj->current_page, 0, sizeof(obj->current_page));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
highest_available_page(struct deluge_object *obj)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < OBJECT_PAGE_COUNT(*obj); i++) {
|
||||
if(!(obj->pages[i].flags & PAGE_COMPLETE)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static void
|
||||
send_request(void *arg)
|
||||
{
|
||||
struct deluge_object *obj;
|
||||
struct deluge_msg_request request;
|
||||
|
||||
obj = (struct deluge_object *)arg;
|
||||
|
||||
request.cmd = DELUGE_CMD_REQUEST;
|
||||
request.pagenum = obj->current_rx_page;
|
||||
request.version = obj->pages[request.pagenum].version;
|
||||
request.request_set = ~obj->pages[obj->current_rx_page].packet_set;
|
||||
request.object_id = obj->object_id;
|
||||
|
||||
PRINTF("Sending request for page %d, version %u, request_set %u\n",
|
||||
request.pagenum, request.version, request.request_set);
|
||||
packetbuf_copyfrom(&request, sizeof(request));
|
||||
unicast_send(&deluge_uc, &obj->summary_from);
|
||||
|
||||
/* Deluge R.2 */
|
||||
if(++obj->nrequests == CONST_LAMBDA) {
|
||||
/* XXX check rate here too. */
|
||||
obj->nrequests = 0;
|
||||
transition(DELUGE_STATE_MAINTAIN);
|
||||
} else {
|
||||
ctimer_reset(&rx_timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
advertise_summary(struct deluge_object *obj)
|
||||
{
|
||||
struct deluge_msg_summary summary;
|
||||
|
||||
if(recv_adv >= CONST_K) {
|
||||
ctimer_stop(&summary_timer);
|
||||
return;
|
||||
}
|
||||
|
||||
summary.cmd = DELUGE_CMD_SUMMARY;
|
||||
summary.version = obj->update_version;
|
||||
summary.highest_available = highest_available_page(obj);
|
||||
summary.object_id = obj->object_id;
|
||||
|
||||
PRINTF("Advertising summary for object id %u: version=%u, available=%u\n",
|
||||
(unsigned)obj->object_id, summary.version, summary.highest_available);
|
||||
|
||||
packetbuf_copyfrom(&summary, sizeof(summary));
|
||||
broadcast_send(&deluge_broadcast);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_summary(struct deluge_msg_summary *msg, const linkaddr_t *sender)
|
||||
{
|
||||
int highest_available, i;
|
||||
clock_time_t oldest_request, oldest_data, now;
|
||||
struct deluge_page *page;
|
||||
|
||||
highest_available = highest_available_page(¤t_object);
|
||||
|
||||
if(msg->version != current_object.version ||
|
||||
msg->highest_available != highest_available) {
|
||||
neighbor_inconsistency = 1;
|
||||
} else {
|
||||
recv_adv++;
|
||||
}
|
||||
|
||||
if(msg->version < current_object.version) {
|
||||
old_summary = 1;
|
||||
broadcast_profile = 1;
|
||||
}
|
||||
|
||||
/* Deluge M.5 */
|
||||
if(msg->version == current_object.update_version &&
|
||||
msg->highest_available > highest_available) {
|
||||
if(msg->highest_available > OBJECT_PAGE_COUNT(current_object)) {
|
||||
PRINTF("Error: highest available is above object page count!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
oldest_request = oldest_data = now = clock_time();
|
||||
for(i = 0; i < msg->highest_available; i++) {
|
||||
page = ¤t_object.pages[i];
|
||||
if(page->last_request < oldest_request) {
|
||||
oldest_request = page->last_request;
|
||||
}
|
||||
if(page->last_request < oldest_data) {
|
||||
oldest_data = page->last_data;
|
||||
}
|
||||
}
|
||||
|
||||
if(((now - oldest_request) / CLOCK_SECOND) <= 2 * r_interval ||
|
||||
((now - oldest_data) / CLOCK_SECOND) <= r_interval) {
|
||||
return;
|
||||
}
|
||||
|
||||
linkaddr_copy(¤t_object.summary_from, sender);
|
||||
transition(DELUGE_STATE_RX);
|
||||
|
||||
if(ctimer_expired(&rx_timer)) {
|
||||
ctimer_set(&rx_timer,
|
||||
CONST_OMEGA * ESTIMATED_TX_TIME + ((unsigned)random_rand() % T_R),
|
||||
send_request, ¤t_object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
send_page(struct deluge_object *obj, unsigned pagenum)
|
||||
{
|
||||
unsigned char buf[S_PAGE];
|
||||
struct deluge_msg_packet pkt;
|
||||
unsigned char *cp;
|
||||
|
||||
pkt.cmd = DELUGE_CMD_PACKET;
|
||||
pkt.pagenum = pagenum;
|
||||
pkt.version = obj->pages[pagenum].version;
|
||||
pkt.packetnum = 0;
|
||||
pkt.object_id = obj->object_id;
|
||||
pkt.crc = 0;
|
||||
|
||||
read_page(obj, pagenum, buf);
|
||||
|
||||
/* Divide the page into packets and send them one at a time. */
|
||||
for(cp = buf; cp + S_PKT <= (unsigned char *)&buf[S_PAGE]; cp += S_PKT) {
|
||||
if(obj->tx_set & (1 << pkt.packetnum)) {
|
||||
pkt.crc = crc16_data(cp, S_PKT, 0);
|
||||
memcpy(pkt.payload, cp, S_PKT);
|
||||
packetbuf_copyfrom(&pkt, sizeof(pkt));
|
||||
broadcast_send(&deluge_broadcast);
|
||||
}
|
||||
pkt.packetnum++;
|
||||
}
|
||||
obj->tx_set = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
tx_callback(void *arg)
|
||||
{
|
||||
struct deluge_object *obj;
|
||||
|
||||
obj = (struct deluge_object *)arg;
|
||||
if(obj->current_tx_page >= 0 && obj->tx_set) {
|
||||
send_page(obj, obj->current_tx_page);
|
||||
/* Deluge T.2. */
|
||||
if(obj->tx_set) {
|
||||
packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE,
|
||||
PACKETBUF_ATTR_PACKET_TYPE_STREAM);
|
||||
ctimer_reset(&tx_timer);
|
||||
} else {
|
||||
packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE,
|
||||
PACKETBUF_ATTR_PACKET_TYPE_STREAM_END);
|
||||
obj->current_tx_page = -1;
|
||||
transition(DELUGE_STATE_MAINTAIN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
handle_request(struct deluge_msg_request *msg)
|
||||
{
|
||||
int highest_available;
|
||||
|
||||
if(msg->pagenum >= OBJECT_PAGE_COUNT(current_object)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(msg->version != current_object.version) {
|
||||
neighbor_inconsistency = 1;
|
||||
}
|
||||
|
||||
highest_available = highest_available_page(¤t_object);
|
||||
|
||||
/* Deluge M.6 */
|
||||
if(msg->version == current_object.version &&
|
||||
msg->pagenum <= highest_available) {
|
||||
current_object.pages[msg->pagenum].last_request = clock_time();
|
||||
|
||||
/* Deluge T.1 */
|
||||
if(msg->pagenum == current_object.current_tx_page) {
|
||||
current_object.tx_set |= msg->request_set;
|
||||
} else {
|
||||
current_object.current_tx_page = msg->pagenum;
|
||||
current_object.tx_set = msg->request_set;
|
||||
}
|
||||
|
||||
transition(DELUGE_STATE_TX);
|
||||
ctimer_set(&tx_timer, CLOCK_SECOND, tx_callback, ¤t_object);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
handle_packet(struct deluge_msg_packet *msg)
|
||||
{
|
||||
struct deluge_page *page;
|
||||
uint16_t crc;
|
||||
struct deluge_msg_packet packet;
|
||||
|
||||
memcpy(&packet, msg, sizeof(packet));
|
||||
|
||||
PRINTF("Incoming packet for object id %u, version %u, page %u, packet num %u!\n",
|
||||
(unsigned)packet.object_id, (unsigned)packet.version,
|
||||
(unsigned)packet.pagenum, (unsigned)packet.packetnum);
|
||||
|
||||
if(packet.pagenum != current_object.current_rx_page) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(packet.version != current_object.version) {
|
||||
neighbor_inconsistency = 1;
|
||||
}
|
||||
|
||||
page = ¤t_object.pages[packet.pagenum];
|
||||
if(packet.version == page->version && !(page->flags & PAGE_COMPLETE)) {
|
||||
memcpy(¤t_object.current_page[S_PKT * packet.packetnum],
|
||||
packet.payload, S_PKT);
|
||||
|
||||
crc = crc16_data(packet.payload, S_PKT, 0);
|
||||
if(packet.crc != crc) {
|
||||
PRINTF("packet crc: %hu, calculated crc: %hu\n", packet.crc, crc);
|
||||
return;
|
||||
}
|
||||
|
||||
page->last_data = clock_time();
|
||||
page->packet_set |= (1 << packet.packetnum);
|
||||
|
||||
if(page->packet_set == ALL_PACKETS) {
|
||||
/* This is the last packet of the requested page; stop streaming. */
|
||||
packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE,
|
||||
PACKETBUF_ATTR_PACKET_TYPE_STREAM_END);
|
||||
|
||||
write_page(¤t_object, packet.pagenum, current_object.current_page);
|
||||
page->version = packet.version;
|
||||
page->flags = PAGE_COMPLETE;
|
||||
PRINTF("Page %u completed\n", packet.pagenum);
|
||||
|
||||
current_object.current_rx_page++;
|
||||
|
||||
if(packet.pagenum == OBJECT_PAGE_COUNT(current_object) - 1) {
|
||||
current_object.version = current_object.update_version;
|
||||
leds_on(LEDS_RED);
|
||||
PRINTF("Update completed for object %u, version %u\n",
|
||||
(unsigned)current_object.object_id, packet.version);
|
||||
} else if(current_object.current_rx_page < OBJECT_PAGE_COUNT(current_object)) {
|
||||
if(ctimer_expired(&rx_timer)) {
|
||||
ctimer_set(&rx_timer,
|
||||
CONST_OMEGA * ESTIMATED_TX_TIME + (random_rand() % T_R),
|
||||
send_request, ¤t_object);
|
||||
}
|
||||
}
|
||||
/* Deluge R.3 */
|
||||
transition(DELUGE_STATE_MAINTAIN);
|
||||
} else {
|
||||
/* More packets to come. Put lower layers in streaming mode. */
|
||||
packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE,
|
||||
PACKETBUF_ATTR_PACKET_TYPE_STREAM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
send_profile(struct deluge_object *obj)
|
||||
{
|
||||
struct deluge_msg_profile *msg;
|
||||
unsigned char buf[sizeof(*msg) + OBJECT_PAGE_COUNT(*obj)];
|
||||
int i;
|
||||
|
||||
if(broadcast_profile && recv_adv < CONST_K) {
|
||||
broadcast_profile = 0;
|
||||
|
||||
msg = (struct deluge_msg_profile *)buf;
|
||||
msg->cmd = DELUGE_CMD_PROFILE;
|
||||
msg->version = obj->version;
|
||||
msg->npages = OBJECT_PAGE_COUNT(*obj);
|
||||
msg->object_id = obj->object_id;
|
||||
for(i = 0; i < msg->npages; i++) {
|
||||
msg->version_vector[i] = obj->pages[i].version;
|
||||
}
|
||||
|
||||
packetbuf_copyfrom(buf, sizeof(buf));
|
||||
broadcast_send(&deluge_broadcast);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
handle_profile(struct deluge_msg_profile *msg)
|
||||
{
|
||||
int i;
|
||||
int npages;
|
||||
struct deluge_object *obj;
|
||||
char *p;
|
||||
|
||||
obj = ¤t_object;
|
||||
if(msg->version <= current_object.update_version) {
|
||||
return;
|
||||
}
|
||||
|
||||
PRINTF("Received profile of version %u with a vector of %u pages.\n",
|
||||
msg->version, msg->npages);
|
||||
|
||||
leds_off(LEDS_RED);
|
||||
current_object.tx_set = 0;
|
||||
|
||||
npages = OBJECT_PAGE_COUNT(*obj);
|
||||
obj->size = msg->npages * S_PAGE;
|
||||
|
||||
p = malloc(OBJECT_PAGE_COUNT(*obj) * sizeof(*obj->pages));
|
||||
if(p == NULL) {
|
||||
PRINTF("Failed to reallocate memory for pages!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(p, obj->pages, npages * sizeof(*obj->pages));
|
||||
free(obj->pages);
|
||||
obj->pages = (struct deluge_page *)p;
|
||||
|
||||
if(msg->npages < npages) {
|
||||
npages = msg->npages;
|
||||
}
|
||||
|
||||
for(i = 0; i < npages; i++) {
|
||||
if(msg->version_vector[i] > obj->pages[i].version) {
|
||||
obj->pages[i].packet_set = 0;
|
||||
obj->pages[i].flags &= ~PAGE_COMPLETE;
|
||||
obj->pages[i].version = msg->version_vector[i];
|
||||
}
|
||||
}
|
||||
|
||||
for(; i < msg->npages; i++) {
|
||||
init_page(obj, i, 0);
|
||||
}
|
||||
|
||||
obj->current_rx_page = highest_available_page(obj);
|
||||
obj->update_version = msg->version;
|
||||
|
||||
transition(DELUGE_STATE_RX);
|
||||
|
||||
ctimer_set(&rx_timer,
|
||||
CONST_OMEGA * ESTIMATED_TX_TIME + ((unsigned)random_rand() % T_R),
|
||||
send_request, obj);
|
||||
}
|
||||
|
||||
static void
|
||||
command_dispatcher(const linkaddr_t *sender)
|
||||
{
|
||||
char *msg;
|
||||
int len;
|
||||
struct deluge_msg_profile *profile;
|
||||
|
||||
msg = packetbuf_dataptr();
|
||||
len = packetbuf_datalen();
|
||||
if(len < 1)
|
||||
return;
|
||||
|
||||
switch(msg[0]) {
|
||||
case DELUGE_CMD_SUMMARY:
|
||||
if(len >= sizeof(struct deluge_msg_summary))
|
||||
handle_summary((struct deluge_msg_summary *)msg, sender);
|
||||
break;
|
||||
case DELUGE_CMD_REQUEST:
|
||||
if(len >= sizeof(struct deluge_msg_request))
|
||||
handle_request((struct deluge_msg_request *)msg);
|
||||
break;
|
||||
case DELUGE_CMD_PACKET:
|
||||
if(len >= sizeof(struct deluge_msg_packet))
|
||||
handle_packet((struct deluge_msg_packet *)msg);
|
||||
break;
|
||||
case DELUGE_CMD_PROFILE:
|
||||
profile = (struct deluge_msg_profile *)msg;
|
||||
if(len >= sizeof(*profile) &&
|
||||
len >= sizeof(*profile) + profile->npages * profile->version_vector[0])
|
||||
handle_profile((struct deluge_msg_profile *)msg);
|
||||
break;
|
||||
default:
|
||||
PRINTF("Incoming packet with unknown command: %d\n", msg[0]);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
unicast_recv(struct unicast_conn *c, const linkaddr_t *sender)
|
||||
{
|
||||
command_dispatcher(sender);
|
||||
}
|
||||
|
||||
static void
|
||||
broadcast_recv(struct broadcast_conn *c, const linkaddr_t *sender)
|
||||
{
|
||||
command_dispatcher(sender);
|
||||
}
|
||||
|
||||
int
|
||||
deluge_disseminate(char *file, unsigned version)
|
||||
{
|
||||
/* This implementation disseminates at most one object. */
|
||||
if(next_object_id > 0 || init_object(¤t_object, file, version) < 0) {
|
||||
return -1;
|
||||
}
|
||||
process_start(&deluge_process, (void *)file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
PROCESS_THREAD(deluge_process, ev, data)
|
||||
{
|
||||
static struct etimer et;
|
||||
static unsigned time_counter;
|
||||
static unsigned r_rand;
|
||||
|
||||
PROCESS_EXITHANDLER(goto exit);
|
||||
|
||||
PROCESS_BEGIN();
|
||||
|
||||
deluge_event = process_alloc_event();
|
||||
|
||||
broadcast_open(&deluge_broadcast, DELUGE_BROADCAST_CHANNEL, &broadcast_call);
|
||||
unicast_open(&deluge_uc, DELUGE_UNICAST_CHANNEL, &unicast_call);
|
||||
r_interval = T_LOW;
|
||||
|
||||
PRINTF("Maintaining state for object %s of %d pages\n",
|
||||
current_object.filename, OBJECT_PAGE_COUNT(current_object));
|
||||
|
||||
deluge_state = DELUGE_STATE_MAINTAIN;
|
||||
|
||||
for(r_interval = T_LOW;;) {
|
||||
if(neighbor_inconsistency) {
|
||||
/* Deluge M.2 */
|
||||
r_interval = T_LOW;
|
||||
neighbor_inconsistency = 0;
|
||||
} else {
|
||||
/* Deluge M.3 */
|
||||
r_interval = (2 * r_interval >= T_HIGH) ? T_HIGH : 2 * r_interval;
|
||||
}
|
||||
|
||||
r_rand = r_interval / 2 + ((unsigned)random_rand() % (r_interval / 2));
|
||||
recv_adv = 0;
|
||||
old_summary = 0;
|
||||
|
||||
/* Deluge M.1 */
|
||||
ctimer_set(&summary_timer, r_rand * CLOCK_SECOND,
|
||||
(void *)(void *)advertise_summary, ¤t_object);
|
||||
|
||||
/* Deluge M.4 */
|
||||
ctimer_set(&profile_timer, r_rand * CLOCK_SECOND,
|
||||
(void *)(void *)send_profile, ¤t_object);
|
||||
|
||||
LONG_TIMER(et, time_counter, r_interval);
|
||||
}
|
||||
|
||||
exit:
|
||||
unicast_close(&deluge_uc);
|
||||
broadcast_close(&deluge_broadcast);
|
||||
if(current_object.cfs_fd >= 0) {
|
||||
cfs_close(current_object.cfs_fd);
|
||||
}
|
||||
if(current_object.pages != NULL) {
|
||||
free(current_object.pages);
|
||||
}
|
||||
|
||||
PROCESS_END();
|
||||
}
|
|
@ -1,159 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, 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
|
||||
* Header for Deluge.
|
||||
* \author
|
||||
* Nicolas Tsiftes <nvt@sics.se>
|
||||
*/
|
||||
|
||||
#ifndef DELUGE_H
|
||||
#define DELUGE_H
|
||||
|
||||
#include "net/rime/rime.h"
|
||||
|
||||
PROCESS_NAME(deluge_process);
|
||||
|
||||
#define LONG_TIMER(et, counter, time) \
|
||||
do { \
|
||||
for (counter = 0; counter < time; counter++) { \
|
||||
etimer_set(&et, CLOCK_SECOND); \
|
||||
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define DELUGE_UNICAST_CHANNEL 55
|
||||
#define DELUGE_BROADCAST_CHANNEL 56
|
||||
|
||||
/* All the packets in a page have been received. */
|
||||
#define PAGE_COMPLETE 1
|
||||
/* All pages up to, and including, this page are complete. */
|
||||
#define PAGE_AVAILABLE 1
|
||||
|
||||
#define S_PKT 64 /* Deluge packet size. */
|
||||
#define N_PKT 4 /* Packets per page. */
|
||||
#define S_PAGE (S_PKT * N_PKT) /* Fixed page size. */
|
||||
|
||||
/* Bounds for the round time in seconds. */
|
||||
#define T_LOW 2
|
||||
#define T_HIGH 64
|
||||
|
||||
/* Random interval for request transmissions in jiffies. */
|
||||
#define T_R (CLOCK_SECOND * 2)
|
||||
|
||||
/* Bound for the number of advertisements. */
|
||||
#define CONST_K 1
|
||||
|
||||
/* The number of pages in this object. */
|
||||
#define OBJECT_PAGE_COUNT(obj) (((obj).size + (S_PAGE - 1)) / S_PAGE)
|
||||
|
||||
#define ALL_PACKETS ((1 << N_PKT) - 1)
|
||||
|
||||
#define DELUGE_CMD_SUMMARY 1
|
||||
#define DELUGE_CMD_REQUEST 2
|
||||
#define DELUGE_CMD_PACKET 3
|
||||
#define DELUGE_CMD_PROFILE 4
|
||||
|
||||
#define DELUGE_STATE_MAINTAIN 1
|
||||
#define DELUGE_STATE_RX 2
|
||||
#define DELUGE_STATE_TX 3
|
||||
|
||||
#define CONST_LAMBDA 2
|
||||
#define CONST_ALPHA 0.5
|
||||
|
||||
#define CONST_OMEGA 8
|
||||
#define ESTIMATED_TX_TIME (CLOCK_SECOND)
|
||||
|
||||
typedef uint8_t deluge_object_id_t;
|
||||
|
||||
struct deluge_msg_summary {
|
||||
uint8_t cmd;
|
||||
uint8_t version;
|
||||
uint8_t highest_available;
|
||||
deluge_object_id_t object_id;
|
||||
};
|
||||
|
||||
struct deluge_msg_request {
|
||||
uint8_t cmd;
|
||||
uint8_t version;
|
||||
uint8_t pagenum;
|
||||
uint8_t request_set;
|
||||
deluge_object_id_t object_id;
|
||||
};
|
||||
|
||||
struct deluge_msg_packet {
|
||||
uint8_t cmd;
|
||||
uint8_t version;
|
||||
uint8_t pagenum;
|
||||
uint8_t packetnum;
|
||||
uint16_t crc;
|
||||
deluge_object_id_t object_id;
|
||||
unsigned char payload[S_PKT];
|
||||
};
|
||||
|
||||
struct deluge_msg_profile {
|
||||
uint8_t cmd;
|
||||
uint8_t version;
|
||||
uint8_t npages;
|
||||
deluge_object_id_t object_id;
|
||||
uint8_t version_vector[];
|
||||
};
|
||||
|
||||
struct deluge_object {
|
||||
char *filename;
|
||||
uint16_t object_id;
|
||||
uint16_t size;
|
||||
uint8_t version;
|
||||
uint8_t update_version;
|
||||
struct deluge_page *pages;
|
||||
uint8_t current_rx_page;
|
||||
int8_t current_tx_page;
|
||||
uint8_t nrequests;
|
||||
uint8_t current_page[S_PAGE];
|
||||
uint8_t tx_set;
|
||||
int cfs_fd;
|
||||
linkaddr_t summary_from;
|
||||
};
|
||||
|
||||
struct deluge_page {
|
||||
uint32_t packet_set;
|
||||
uint16_t crc;
|
||||
clock_time_t last_request;
|
||||
clock_time_t last_data;
|
||||
uint8_t flags;
|
||||
uint8_t version;
|
||||
};
|
||||
|
||||
int deluge_disseminate(char *file, unsigned version);
|
||||
|
||||
#endif
|
|
@ -61,7 +61,7 @@ typedef struct coap_separate {
|
|||
|
||||
int coap_separate_handler(resource_t *resource, void *request,
|
||||
void *response);
|
||||
void coap_separate_reject();
|
||||
void coap_separate_reject(void);
|
||||
void coap_separate_accept(void *request, coap_separate_t *separate_store);
|
||||
void coap_separate_resume(void *response, coap_separate_t *separate_store,
|
||||
uint8_t code);
|
||||
|
|
|
@ -67,7 +67,7 @@ typedef struct coap_transaction {
|
|||
* Use snprintf(buf, len+1, "", ...) to completely fill payload */
|
||||
} coap_transaction_t;
|
||||
|
||||
void coap_register_as_transaction_handler();
|
||||
void coap_register_as_transaction_handler(void);
|
||||
|
||||
coap_transaction_t *coap_new_transaction(uint16_t mid, uip_ipaddr_t *addr,
|
||||
uint16_t port);
|
||||
|
@ -75,6 +75,6 @@ void coap_send_transaction(coap_transaction_t *t);
|
|||
void coap_clear_transaction(coap_transaction_t *t);
|
||||
coap_transaction_t *coap_get_transaction_by_mid(uint16_t mid);
|
||||
|
||||
void coap_check_transactions();
|
||||
void coap_check_transactions(void);
|
||||
|
||||
#endif /* COAP_TRANSACTIONS_H_ */
|
||||
|
|
|
@ -79,7 +79,7 @@ LWM2M_RESOURCES(temperature_resources,
|
|||
/* Temperature (Current) */
|
||||
LWM2M_RESOURCE_CALLBACK(5700, { temp, NULL, NULL }),
|
||||
/* Units */
|
||||
LWM2M_RESOURCE_STRING(5701, "Celcius"),
|
||||
LWM2M_RESOURCE_STRING(5701, "Cel"),
|
||||
/* Min Range Value */
|
||||
LWM2M_RESOURCE_FLOATFIX(5603, IPSO_TEMPERATURE_MIN),
|
||||
/* Max Range Value */
|
||||
|
|
|
@ -71,6 +71,7 @@ enum {
|
|||
JSON_ERROR_UNEXPECTED_ARRAY,
|
||||
JSON_ERROR_UNEXPECTED_END_OF_ARRAY,
|
||||
JSON_ERROR_UNEXPECTED_OBJECT,
|
||||
JSON_ERROR_UNEXPECTED_END_OF_OBJECT,
|
||||
JSON_ERROR_UNEXPECTED_STRING
|
||||
};
|
||||
|
||||
|
|
|
@ -43,6 +43,14 @@ push(struct jsonparse_state *state, char c)
|
|||
return state->depth < JSONPARSE_MAX_DEPTH;
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
static void
|
||||
modify(struct jsonparse_state *state, char c)
|
||||
{
|
||||
if(state->depth > 0) {
|
||||
state->stack[state->depth - 1] = c;
|
||||
}
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
static char
|
||||
pop(struct jsonparse_state *state)
|
||||
{
|
||||
|
@ -50,25 +58,31 @@ pop(struct jsonparse_state *state)
|
|||
return JSON_TYPE_ERROR;
|
||||
}
|
||||
state->depth--;
|
||||
state->vtype = state->stack[state->depth];
|
||||
return state->stack[state->depth];
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
/* will pass by the value and store the start and length of the value for
|
||||
atomic types */
|
||||
/*--------------------------------------------------------------------*/
|
||||
static void
|
||||
static char
|
||||
atomic(struct jsonparse_state *state, char type)
|
||||
{
|
||||
char c;
|
||||
const char *str;
|
||||
int len;
|
||||
|
||||
state->vstart = state->pos;
|
||||
state->vtype = type;
|
||||
if(type == JSON_TYPE_STRING || type == JSON_TYPE_PAIR_NAME) {
|
||||
while((c = state->json[state->pos++]) && c != '"') {
|
||||
if(c == '\\') {
|
||||
state->pos++; /* skip current char */
|
||||
}
|
||||
}
|
||||
if (c != '"') {
|
||||
state->error = JSON_ERROR_SYNTAX;
|
||||
return JSON_TYPE_ERROR;
|
||||
}
|
||||
state->vlen = state->pos - state->vstart - 1;
|
||||
} else if(type == JSON_TYPE_NUMBER) {
|
||||
do {
|
||||
|
@ -82,8 +96,31 @@ atomic(struct jsonparse_state *state, char type)
|
|||
/* need to back one step since first char is already gone */
|
||||
state->vstart--;
|
||||
state->vlen = state->pos - state->vstart;
|
||||
} else if(type == JSON_TYPE_NULL || type == JSON_TYPE_TRUE || type == JSON_TYPE_FALSE) {
|
||||
state->vstart--;
|
||||
switch (type) {
|
||||
case JSON_TYPE_NULL: str = "null"; break;
|
||||
case JSON_TYPE_TRUE: str = "true"; break;
|
||||
case JSON_TYPE_FALSE: str = "false"; break;
|
||||
default: str = ""; break;
|
||||
}
|
||||
|
||||
while ((c = state->json[state->pos]) && c != ' ' && c != ',' && c != ']' && c != '}') {
|
||||
state->pos++;
|
||||
}
|
||||
|
||||
state->vlen = state->pos - state->vstart;
|
||||
len = strlen(str);
|
||||
len = state->vlen > len ? state->vlen : len;
|
||||
|
||||
if (strncmp(str, &state->json[state->vstart], len) != 0) {
|
||||
state->error = JSON_ERROR_SYNTAX;
|
||||
return JSON_TYPE_ERROR;
|
||||
}
|
||||
}
|
||||
/* no other types for now... */
|
||||
|
||||
state->vtype = type;
|
||||
return state->vtype;
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
static void
|
||||
|
@ -97,6 +134,17 @@ skip_ws(struct jsonparse_state *state)
|
|||
}
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
static int
|
||||
is_atomic(struct jsonparse_state *state)
|
||||
{
|
||||
char v = state->vtype;
|
||||
if(v == 'N' || v == '"' || v == '0' || v == 'n' || v == 't' || v == 'f') {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
void
|
||||
jsonparse_setup(struct jsonparse_state *state, const char *json, int len)
|
||||
{
|
||||
|
@ -105,6 +153,7 @@ jsonparse_setup(struct jsonparse_state *state, const char *json, int len)
|
|||
state->pos = 0;
|
||||
state->depth = 0;
|
||||
state->error = 0;
|
||||
state->vtype = 0;
|
||||
state->stack[0] = 0;
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
@ -113,31 +162,33 @@ jsonparse_next(struct jsonparse_state *state)
|
|||
{
|
||||
char c;
|
||||
char s;
|
||||
char v;
|
||||
|
||||
skip_ws(state);
|
||||
c = state->json[state->pos];
|
||||
s = jsonparse_get_type(state);
|
||||
v = state->vtype;
|
||||
state->pos++;
|
||||
|
||||
switch(c) {
|
||||
case '{':
|
||||
push(state, c);
|
||||
if((s == 0 && v == 0) || s == '[' || s == ':') {
|
||||
push(state, c);
|
||||
} else {
|
||||
state->error = JSON_ERROR_UNEXPECTED_OBJECT;
|
||||
return JSON_TYPE_ERROR;
|
||||
}
|
||||
return c;
|
||||
case '}':
|
||||
if(s == ':' && state->vtype != 0) {
|
||||
/* printf("Popping vtype: '%c'\n", state->vtype); */
|
||||
pop(state);
|
||||
s = jsonparse_get_type(state);
|
||||
}
|
||||
if(s == '{') {
|
||||
if((s == ':' && v != ',' && v != 0 ) || (s == '{' && v == 0)) {
|
||||
pop(state);
|
||||
} else {
|
||||
state->error = JSON_ERROR_SYNTAX;
|
||||
state->error = JSON_ERROR_UNEXPECTED_END_OF_OBJECT;
|
||||
return JSON_TYPE_ERROR;
|
||||
}
|
||||
return c;
|
||||
case ']':
|
||||
if(s == '[') {
|
||||
if(s == '[' && v != ',') {
|
||||
pop(state);
|
||||
} else {
|
||||
state->error = JSON_ERROR_UNEXPECTED_END_OF_ARRAY;
|
||||
|
@ -145,41 +196,67 @@ jsonparse_next(struct jsonparse_state *state)
|
|||
}
|
||||
return c;
|
||||
case ':':
|
||||
push(state, c);
|
||||
return c;
|
||||
if(s == '{' && v == 'N') {
|
||||
modify(state, ':');
|
||||
state->vtype = 0;
|
||||
} else {
|
||||
state->error = JSON_ERROR_SYNTAX;
|
||||
return JSON_TYPE_ERROR;
|
||||
}
|
||||
return jsonparse_next(state);
|
||||
case ',':
|
||||
/* if x:y ... , */
|
||||
if(s == ':' && state->vtype != 0) {
|
||||
pop(state);
|
||||
if(s == ':' && v != 0) {
|
||||
modify(state, '{');
|
||||
state->vtype = c;
|
||||
} else if(s == '[') {
|
||||
/* ok! */
|
||||
state->vtype = c;
|
||||
} else {
|
||||
state->error = JSON_ERROR_SYNTAX;
|
||||
return JSON_TYPE_ERROR;
|
||||
}
|
||||
return c;
|
||||
case '"':
|
||||
if(s == '{' || s == '[' || s == ':') {
|
||||
atomic(state, c = (s == '{' ? JSON_TYPE_PAIR_NAME : c));
|
||||
if((s == 0 && v == 0) || s == '{' || s == '[' || s == ':') {
|
||||
return atomic(state, c = (s == '{' ? JSON_TYPE_PAIR_NAME : c));
|
||||
} else {
|
||||
state->error = JSON_ERROR_UNEXPECTED_STRING;
|
||||
return JSON_TYPE_ERROR;
|
||||
}
|
||||
return c;
|
||||
case '[':
|
||||
if(s == '{' || s == '[' || s == ':') {
|
||||
if((s == 0 && v == 0) || s == '[' || s == ':') {
|
||||
push(state, c);
|
||||
} else {
|
||||
state->error = JSON_ERROR_UNEXPECTED_ARRAY;
|
||||
return JSON_TYPE_ERROR;
|
||||
}
|
||||
return c;
|
||||
case 0:
|
||||
if(v == 0 || state->depth > 0) {
|
||||
state->error = JSON_ERROR_SYNTAX;
|
||||
}
|
||||
return JSON_TYPE_ERROR;
|
||||
default:
|
||||
if(s == ':' || s == '[') {
|
||||
if(c <= '9' && c >= '0') {
|
||||
atomic(state, JSON_TYPE_NUMBER);
|
||||
return JSON_TYPE_NUMBER;
|
||||
if(s == 0 || s == ':' || s == '[') {
|
||||
if (v != 0 && v != ',') {
|
||||
state->error = JSON_ERROR_SYNTAX;
|
||||
return JSON_TYPE_ERROR;
|
||||
}
|
||||
if(c == '-' || (c <= '9' && c >= '0')) {
|
||||
return atomic(state, JSON_TYPE_NUMBER);
|
||||
} else if(c == 'n') {
|
||||
return atomic(state, JSON_TYPE_NULL);
|
||||
} else if(c == 't') {
|
||||
return atomic(state, JSON_TYPE_TRUE);
|
||||
} else if(c == 'f') {
|
||||
return atomic(state, JSON_TYPE_FALSE);
|
||||
} else {
|
||||
state->error = JSON_ERROR_SYNTAX;
|
||||
return JSON_TYPE_ERROR;
|
||||
}
|
||||
} else if(s == '{') {
|
||||
state->error = JSON_ERROR_SYNTAX;
|
||||
return JSON_TYPE_ERROR;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -192,16 +269,31 @@ jsonparse_next(struct jsonparse_state *state)
|
|||
int
|
||||
jsonparse_copy_value(struct jsonparse_state *state, char *str, int size)
|
||||
{
|
||||
int i;
|
||||
int i, o;
|
||||
char c;
|
||||
|
||||
if(state->vtype == 0) {
|
||||
if(!is_atomic(state)) {
|
||||
return 0;
|
||||
}
|
||||
size = size <= state->vlen ? (size - 1) : state->vlen;
|
||||
for(i = 0; i < size; i++) {
|
||||
str[i] = state->json[state->vstart + i];
|
||||
for(i = 0, o = 0; i < state->vlen && o < size - 1; i++) {
|
||||
c = state->json[state->vstart + i];
|
||||
if(c == '\\') {
|
||||
i++;
|
||||
switch(state->json[state->vstart + i]) {
|
||||
case '"': str[o++] = '"'; break;
|
||||
case '\\': str[o++] = '\\'; break;
|
||||
case '/': str[o++] = '/'; break;
|
||||
case 'b': str[o++] = '\b'; break;
|
||||
case 'f': str[o++] = '\f'; break;
|
||||
case 'n': str[o++] = '\n'; break;
|
||||
case 'r': str[o++] = '\r'; break;
|
||||
case 't': str[o++] = '\t'; break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
str[o++] = c;
|
||||
}
|
||||
str[i] = 0;
|
||||
str[o] = 0;
|
||||
return state->vtype;
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
@ -228,7 +320,7 @@ jsonparse_get_value_as_long(struct jsonparse_state *state)
|
|||
int
|
||||
jsonparse_strcmp_value(struct jsonparse_state *state, const char *str)
|
||||
{
|
||||
if(state->vtype == 0) {
|
||||
if(!is_atomic(state)) {
|
||||
return -1;
|
||||
}
|
||||
return strncmp(str, &state->json[state->vstart], state->vlen);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -46,10 +46,12 @@
|
|||
#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"
|
||||
#include "oma-tlv.h"
|
||||
#include "oma-tlv-reader.h"
|
||||
#include "oma-tlv-writer.h"
|
||||
#include "net/ipv6/uip-ds6.h"
|
||||
#include <stdio.h>
|
||||
|
@ -639,10 +641,10 @@ write_rd_json_data(const lwm2m_context_t *context,
|
|||
value = lwm2m_object_get_resource_string(resource, context);
|
||||
slen = lwm2m_object_get_resource_strlen(resource, context);
|
||||
if(value != NULL) {
|
||||
PRINTF("%s{\"n\":\"%u\",\"vs\":\"%.*s\"}", s,
|
||||
PRINTF("%s{\"n\":\"%u\",\"sv\":\"%.*s\"}", s,
|
||||
resource->id, slen, value);
|
||||
len = snprintf(&buffer[rdlen], size - rdlen,
|
||||
"%s{\"n\":\"%u\",\"vs\":\"%.*s\"}", s,
|
||||
"%s{\"n\":\"%u\",\"sv\":\"%.*s\"}", s,
|
||||
resource->id, slen, value);
|
||||
}
|
||||
} else if(lwm2m_object_is_resource_int(resource)) {
|
||||
|
@ -682,10 +684,10 @@ write_rd_json_data(const lwm2m_context_t *context,
|
|||
} else if(lwm2m_object_is_resource_boolean(resource)) {
|
||||
int value;
|
||||
if(lwm2m_object_get_resource_boolean(resource, context, &value)) {
|
||||
PRINTF("%s{\"n\":\"%u\",\"v\":%s}", s, resource->id,
|
||||
PRINTF("%s{\"n\":\"%u\",\"bv\":%s}", s, resource->id,
|
||||
value ? "true" : "false");
|
||||
len = snprintf(&buffer[rdlen], size - rdlen,
|
||||
"%s{\"n\":\"%u\",\"v\":%s}", s, resource->id,
|
||||
"%s{\"n\":\"%u\",\"bv\":%s}", s, resource->id,
|
||||
value ? "true" : "false");
|
||||
}
|
||||
}
|
||||
|
@ -707,6 +709,63 @@ write_rd_json_data(const lwm2m_context_t *context,
|
|||
return rdlen;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Set the writer pointer to the proper writer based on the Accept: header
|
||||
*
|
||||
* @param[in] context LWM2M context to operate on
|
||||
* @param[in] accept Accept type number from CoAP headers
|
||||
*
|
||||
* @return The content type of the response if the selected writer is used
|
||||
*/
|
||||
static unsigned int
|
||||
lwm2m_engine_select_writer(lwm2m_context_t *context, unsigned int accept)
|
||||
{
|
||||
switch(accept) {
|
||||
case LWM2M_TLV:
|
||||
context->writer = &oma_tlv_writer;
|
||||
break;
|
||||
case LWM2M_TEXT_PLAIN:
|
||||
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;
|
||||
/* Set the response type to plain text */
|
||||
accept = LWM2M_TEXT_PLAIN;
|
||||
break;
|
||||
}
|
||||
return accept;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Set the reader pointer to the proper reader based on the Content-format: header
|
||||
*
|
||||
* @param[in] context LWM2M context to operate on
|
||||
* @param[in] content_format Content-type type number from CoAP headers
|
||||
*/
|
||||
static void
|
||||
lwm2m_engine_select_reader(lwm2m_context_t *context, unsigned int content_format)
|
||||
{
|
||||
switch(content_format) {
|
||||
case LWM2M_TLV:
|
||||
context->reader = &oma_tlv_reader;
|
||||
break;
|
||||
case LWM2M_TEXT_PLAIN:
|
||||
case TEXT_PLAIN:
|
||||
context->reader = &lwm2m_plain_text_reader;
|
||||
break;
|
||||
default:
|
||||
PRINTF("Unknown content type %u, using LWM2M plain text\n", accept);
|
||||
context->reader = &lwm2m_plain_text_reader;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
lwm2m_engine_handler(const lwm2m_object_t *object,
|
||||
void *request, void *response,
|
||||
|
@ -716,6 +775,8 @@ lwm2m_engine_handler(const lwm2m_object_t *object,
|
|||
int len;
|
||||
const char *url;
|
||||
unsigned int format;
|
||||
unsigned int accept;
|
||||
unsigned int content_type;
|
||||
int depth;
|
||||
lwm2m_context_t context;
|
||||
rest_resource_flags_t method;
|
||||
|
@ -734,11 +795,19 @@ lwm2m_engine_handler(const lwm2m_object_t *object,
|
|||
/* CoAP content format text plain - assume LWM2M text plain */
|
||||
format = LWM2M_TEXT_PLAIN;
|
||||
}
|
||||
if(!REST.get_header_accept(request, &accept)) {
|
||||
PRINTF("No Accept header, using same as Content-format...\n");
|
||||
accept = format;
|
||||
}
|
||||
|
||||
depth = lwm2m_engine_parse_context(object, url, len, &context);
|
||||
PRINTF("Context: %u/%u/%u found: %d\n", context.object_id,
|
||||
context.object_instance_id, context.resource_id, depth);
|
||||
|
||||
/* Select reader and writer based on provided Content type and Accept headers */
|
||||
lwm2m_engine_select_reader(&context, format);
|
||||
content_type = lwm2m_engine_select_writer(&context, accept);
|
||||
|
||||
#if (DEBUG) & DEBUG_PRINT
|
||||
/* for debugging */
|
||||
if(method == METHOD_GET) {
|
||||
|
@ -861,7 +930,7 @@ lwm2m_engine_handler(const lwm2m_object_t *object,
|
|||
|
||||
if(depth == 3) {
|
||||
const lwm2m_resource_t *resource = get_resource(instance, &context);
|
||||
size_t tlvlen = 0;
|
||||
size_t content_len = 0;
|
||||
if(resource == NULL) {
|
||||
PRINTF("Error - do not have resource %d\n", context.resource_id);
|
||||
REST.set_response_status(response, NOT_FOUND_4_04);
|
||||
|
@ -879,9 +948,9 @@ lwm2m_engine_handler(const lwm2m_object_t *object,
|
|||
context.reader = &lwm2m_plain_text_reader;
|
||||
PRINTF("PUT Callback with data: '%.*s'\n", plen, data);
|
||||
/* no specific reader for plain text */
|
||||
tlvlen = resource->value.callback.write(&context, data, plen,
|
||||
content_len = resource->value.callback.write(&context, data, plen,
|
||||
buffer, preferred_size);
|
||||
PRINTF("tlvlen:%u\n", (unsigned int)tlvlen);
|
||||
PRINTF("content_len:%u\n", (unsigned int)content_len);
|
||||
REST.set_response_status(response, CHANGED_2_04);
|
||||
} else {
|
||||
PRINTF("PUT callback with format %d\n", format);
|
||||
|
@ -899,48 +968,39 @@ lwm2m_engine_handler(const lwm2m_object_t *object,
|
|||
} else if(method == METHOD_GET) {
|
||||
if(lwm2m_object_is_resource_string(resource)) {
|
||||
const uint8_t *value;
|
||||
uint16_t len;
|
||||
value = lwm2m_object_get_resource_string(resource, &context);
|
||||
len = lwm2m_object_get_resource_strlen(resource, &context);
|
||||
if(value != NULL) {
|
||||
uint16_t len = lwm2m_object_get_resource_strlen(resource, &context);
|
||||
PRINTF("Get string value: %.*s\n", (int)len, (char *)value);
|
||||
/* TODO check format */
|
||||
REST.set_response_payload(response, value, len);
|
||||
REST.set_header_content_type(response, LWM2M_TEXT_PLAIN);
|
||||
/* Done */
|
||||
return;
|
||||
content_len = context.writer->write_string(&context, buffer,
|
||||
preferred_size, (const char *)value, len);
|
||||
}
|
||||
} else if(lwm2m_object_is_resource_int(resource)) {
|
||||
int32_t value;
|
||||
if(lwm2m_object_get_resource_int(resource, &context, &value)) {
|
||||
/* export INT as TLV */
|
||||
tlvlen = oma_tlv_write_int32(resource->id, value, buffer, preferred_size);
|
||||
PRINTF("Exporting int as TLV: %" PRId32 ", len: %u\n",
|
||||
value, (unsigned int)tlvlen);
|
||||
content_len = context.writer->write_int(&context, buffer, preferred_size, value);
|
||||
}
|
||||
} else if(lwm2m_object_is_resource_floatfix(resource)) {
|
||||
int32_t value;
|
||||
if(lwm2m_object_get_resource_floatfix(resource, &context, &value)) {
|
||||
/* export FLOATFIX as TLV */
|
||||
/* export FLOATFIX */
|
||||
PRINTF("Exporting %d-bit fix as float: %" PRId32 "\n",
|
||||
LWM2M_FLOAT32_BITS, value);
|
||||
tlvlen = oma_tlv_write_float32(resource->id,
|
||||
value, LWM2M_FLOAT32_BITS,
|
||||
buffer, preferred_size);
|
||||
PRINTF("Exporting as TLV: len:%u\n", (unsigned int)tlvlen);
|
||||
content_len = context.writer->write_float32fix(&context, buffer,
|
||||
preferred_size, value, LWM2M_FLOAT32_BITS);
|
||||
}
|
||||
} else if(lwm2m_object_is_resource_callback(resource)) {
|
||||
if(resource->value.callback.read != NULL) {
|
||||
tlvlen = resource->value.callback.read(&context,
|
||||
content_len = resource->value.callback.read(&context,
|
||||
buffer, preferred_size);
|
||||
} else {
|
||||
REST.set_response_status(response, METHOD_NOT_ALLOWED_4_05);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(tlvlen > 0) {
|
||||
REST.set_response_payload(response, buffer, tlvlen);
|
||||
REST.set_header_content_type(response, LWM2M_TLV);
|
||||
if(content_len > 0) {
|
||||
REST.set_response_payload(response, buffer, content_len);
|
||||
REST.set_header_content_type(response, content_type);
|
||||
} else {
|
||||
/* failed to produce output - it is an internal error */
|
||||
REST.set_response_status(response, INTERNAL_SERVER_ERROR_5_00);
|
||||
|
@ -952,7 +1012,7 @@ lwm2m_engine_handler(const lwm2m_object_t *object,
|
|||
const uint8_t *data;
|
||||
int plen = REST.get_request_payload(request, &data);
|
||||
PRINTF("Execute Callback with data: '%.*s'\n", plen, data);
|
||||
tlvlen = resource->value.callback.exec(&context,
|
||||
content_len = resource->value.callback.exec(&context,
|
||||
data, plen,
|
||||
buffer, preferred_size);
|
||||
REST.set_response_status(response, CHANGED_2_04);
|
||||
|
@ -973,7 +1033,7 @@ lwm2m_engine_handler(const lwm2m_object_t *object,
|
|||
REST.set_response_status(response, NOT_FOUND_4_04);
|
||||
} else {
|
||||
int rdlen;
|
||||
if(format == APPLICATION_LINK_FORMAT) {
|
||||
if(accept == APPLICATION_LINK_FORMAT) {
|
||||
rdlen = write_rd_link_data(object, instance,
|
||||
(char *)buffer, preferred_size);
|
||||
} else {
|
||||
|
@ -986,10 +1046,10 @@ lwm2m_engine_handler(const lwm2m_object_t *object,
|
|||
return;
|
||||
}
|
||||
REST.set_response_payload(response, buffer, rdlen);
|
||||
if(format == APPLICATION_LINK_FORMAT) {
|
||||
if(accept == APPLICATION_LINK_FORMAT) {
|
||||
REST.set_header_content_type(response, REST.type.APPLICATION_LINK_FORMAT);
|
||||
} else {
|
||||
REST.set_header_content_type(response, REST.type.APPLICATION_JSON);
|
||||
REST.set_header_content_type(response, LWM2M_JSON);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
162
apps/oma-lwm2m/lwm2m-json.c
Normal file
162
apps/oma-lwm2m/lwm2m-json.c
Normal 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
|
||||
};
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @} */
|
51
apps/oma-lwm2m/lwm2m-json.h
Normal file
51
apps/oma-lwm2m/lwm2m-json.h
Normal 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_ */
|
||||
/** @} */
|
|
@ -100,6 +100,11 @@ lwm2m_plain_text_read_float32fix(const uint8_t *inbuf, size_t len,
|
|||
break;
|
||||
}
|
||||
}
|
||||
if(dot == 0) {
|
||||
integerpart = counter;
|
||||
counter = 0;
|
||||
frac = 1;
|
||||
}
|
||||
*value = integerpart << bits;
|
||||
if(frac > 1) {
|
||||
*value += ((counter << bits) / frac);
|
||||
|
|
|
@ -1 +1 @@
|
|||
orchestra_src = orchestra.c orchestra-rule-default-common.c orchestra-rule-eb-per-time-source.c orchestra-rule-unicast-per-neighbor.c
|
||||
orchestra_src = orchestra.c orchestra-rule-default-common.c orchestra-rule-eb-per-time-source.c orchestra-rule-unicast-per-neighbor-rpl-storing.c orchestra-rule-unicast-per-neighbor-rpl-ns.c
|
||||
|
|
|
@ -46,10 +46,10 @@
|
|||
* - a sender-based or receiver-based slotframe for unicast to RPL parents and children
|
||||
* - a common shared slotframe for any other traffic (mostly broadcast)
|
||||
* */
|
||||
#define ORCHESTRA_RULES { &eb_per_time_source, \
|
||||
&unicast_per_neighbor, \
|
||||
&default_common, \
|
||||
}
|
||||
#define ORCHESTRA_RULES { &eb_per_time_source, &unicast_per_neighbor_rpl_storing, &default_common }
|
||||
/* Example configuration for RPL non-storing mode: */
|
||||
/* #define ORCHESTRA_RULES { &eb_per_time_source, &unicast_per_neighbor_rpl_ns, &default_common } */
|
||||
|
||||
#endif /* ORCHESTRA_CONF_RULES */
|
||||
|
||||
/* Length of the various slotframes. Tune to balance network capacity,
|
||||
|
|
|
@ -74,8 +74,8 @@ select_packet(uint16_t *slotframe, uint16_t *timeslot)
|
|||
static void
|
||||
new_time_source(const struct tsch_neighbor *old, const struct tsch_neighbor *new)
|
||||
{
|
||||
uint16_t old_ts = get_node_timeslot(&old->addr);
|
||||
uint16_t new_ts = get_node_timeslot(&new->addr);
|
||||
uint16_t old_ts = old != NULL ? get_node_timeslot(&old->addr) : 0xffff;
|
||||
uint16_t new_ts = new != NULL ? get_node_timeslot(&new->addr) : 0xffff;
|
||||
|
||||
if(new_ts == old_ts) {
|
||||
return;
|
||||
|
@ -83,14 +83,24 @@ new_time_source(const struct tsch_neighbor *old, const struct tsch_neighbor *new
|
|||
|
||||
if(old_ts != 0xffff) {
|
||||
/* Stop listening to the old time source's EBs */
|
||||
tsch_schedule_remove_link_by_timeslot(sf_eb, old_ts);
|
||||
if(old_ts == get_node_timeslot(&linkaddr_node_addr)) {
|
||||
/* This was the same timeslot as slot. Reset original link options */
|
||||
tsch_schedule_add_link(sf_eb, LINK_OPTION_TX, LINK_TYPE_ADVERTISING_ONLY,
|
||||
&tsch_broadcast_address, old_ts, 0);
|
||||
} else {
|
||||
/* Remove slot */
|
||||
tsch_schedule_remove_link_by_timeslot(sf_eb, old_ts);
|
||||
}
|
||||
}
|
||||
if(new_ts != 0xffff) {
|
||||
uint8_t link_options = LINK_OPTION_RX;
|
||||
if(new_ts == get_node_timeslot(&linkaddr_node_addr)) {
|
||||
/* This is also our timeslot, add necessary flags */
|
||||
link_options |= LINK_OPTION_TX;
|
||||
}
|
||||
/* Listen to the time source's EBs */
|
||||
tsch_schedule_add_link(sf_eb,
|
||||
LINK_OPTION_RX,
|
||||
LINK_TYPE_ADVERTISING_ONLY, NULL,
|
||||
new_ts, 0);
|
||||
tsch_schedule_add_link(sf_eb, link_options, LINK_TYPE_ADVERTISING_ONLY,
|
||||
&tsch_broadcast_address, new_ts, 0);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
|
119
apps/orchestra/orchestra-rule-unicast-per-neighbor-rpl-ns.c
Normal file
119
apps/orchestra/orchestra-rule-unicast-per-neighbor-rpl-ns.c
Normal file
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Inria.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this 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
|
||||
* Orchestra: a slotframe dedicated to unicast data transmission. Designed primarily
|
||||
* for RPL non-storing mode but would work with any mode-of-operation. Does not require
|
||||
* any knowledge of the children. Works only as received-base, and as follows:
|
||||
* Nodes listen at a timeslot defined as hash(MAC) % ORCHESTRA_SB_UNICAST_PERIOD
|
||||
* Nodes transmit at: for any neighbor, hash(nbr.MAC) % ORCHESTRA_SB_UNICAST_PERIOD
|
||||
*
|
||||
* \author Simon Duquennoy <simon.duquennoy@inria.fr>
|
||||
*/
|
||||
|
||||
#include "contiki.h"
|
||||
#include "orchestra.h"
|
||||
#include "net/ipv6/uip-ds6-route.h"
|
||||
#include "net/packetbuf.h"
|
||||
|
||||
static uint16_t slotframe_handle = 0;
|
||||
static uint16_t channel_offset = 0;
|
||||
static struct tsch_slotframe *sf_unicast;
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static uint16_t
|
||||
get_node_timeslot(const linkaddr_t *addr)
|
||||
{
|
||||
if(addr != NULL && ORCHESTRA_UNICAST_PERIOD > 0) {
|
||||
return ORCHESTRA_LINKADDR_HASH(addr) % ORCHESTRA_UNICAST_PERIOD;
|
||||
} else {
|
||||
return 0xffff;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
child_added(const linkaddr_t *linkaddr)
|
||||
{
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
child_removed(const linkaddr_t *linkaddr)
|
||||
{
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int
|
||||
select_packet(uint16_t *slotframe, uint16_t *timeslot)
|
||||
{
|
||||
/* Select data packets we have a unicast link to */
|
||||
const linkaddr_t *dest = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
|
||||
if(packetbuf_attr(PACKETBUF_ATTR_FRAME_TYPE) == FRAME802154_DATAFRAME
|
||||
&& !linkaddr_cmp(dest, &linkaddr_null)) {
|
||||
if(slotframe != NULL) {
|
||||
*slotframe = slotframe_handle;
|
||||
}
|
||||
if(timeslot != NULL) {
|
||||
*timeslot = get_node_timeslot(dest);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
new_time_source(const struct tsch_neighbor *old, const struct tsch_neighbor *new)
|
||||
{
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
init(uint16_t sf_handle)
|
||||
{
|
||||
int i;
|
||||
uint16_t rx_timeslot;
|
||||
slotframe_handle = sf_handle;
|
||||
channel_offset = sf_handle;
|
||||
/* Slotframe for unicast transmissions */
|
||||
sf_unicast = tsch_schedule_add_slotframe(slotframe_handle, ORCHESTRA_UNICAST_PERIOD);
|
||||
rx_timeslot = get_node_timeslot(&linkaddr_node_addr);
|
||||
/* Add a Tx link at each available timeslot. Make the link Rx at our own timeslot. */
|
||||
for(i = 0; i < ORCHESTRA_UNICAST_PERIOD; i++) {
|
||||
tsch_schedule_add_link(sf_unicast,
|
||||
LINK_OPTION_SHARED | LINK_OPTION_TX | ( i == rx_timeslot ? LINK_OPTION_RX : 0 ),
|
||||
LINK_TYPE_NORMAL, &tsch_broadcast_address,
|
||||
i, channel_offset);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
struct orchestra_rule unicast_per_neighbor_rpl_ns = {
|
||||
init,
|
||||
new_time_source,
|
||||
select_packet,
|
||||
child_added,
|
||||
child_removed,
|
||||
};
|
|
@ -29,12 +29,13 @@
|
|||
*/
|
||||
/**
|
||||
* \file
|
||||
* Orchestra: a slotframe dedicated to unicast data transmission.
|
||||
* If sender-based:
|
||||
* Orchestra: a slotframe dedicated to unicast data transmission. Designed for
|
||||
* RPL storing mode only, as this is based on the knowledge of the children (and parent).
|
||||
* If receiver-based:
|
||||
* Nodes listen at a timeslot defined as hash(MAC) % ORCHESTRA_SB_UNICAST_PERIOD
|
||||
* Nodes transmit at: for each nbr in RPL children and RPL preferred parent,
|
||||
* hash(nbr.MAC) % ORCHESTRA_SB_UNICAST_PERIOD
|
||||
* If receiver-based: the opposite
|
||||
* If sender-based: the opposite
|
||||
*
|
||||
* \author Simon Duquennoy <simonduq@sics.se>
|
||||
*/
|
||||
|
@ -43,6 +44,7 @@
|
|||
#include "orchestra.h"
|
||||
#include "net/ipv6/uip-ds6-route.h"
|
||||
#include "net/packetbuf.h"
|
||||
#include "net/rpl/rpl-conf.h"
|
||||
|
||||
#if ORCHESTRA_UNICAST_SENDER_BASED && ORCHESTRA_COLLISION_FREE_HASH
|
||||
#define UNICAST_SLOT_SHARED_FLAG ((ORCHESTRA_UNICAST_PERIOD < (ORCHESTRA_MAX_HASH + 1)) ? LINK_OPTION_SHARED : 0)
|
||||
|
@ -85,10 +87,16 @@ add_uc_link(const linkaddr_t *linkaddr)
|
|||
{
|
||||
if(linkaddr != NULL) {
|
||||
uint16_t timeslot = get_node_timeslot(linkaddr);
|
||||
tsch_schedule_add_link(sf_unicast,
|
||||
ORCHESTRA_UNICAST_SENDER_BASED ? LINK_OPTION_RX : LINK_OPTION_TX | UNICAST_SLOT_SHARED_FLAG,
|
||||
LINK_TYPE_NORMAL, &tsch_broadcast_address,
|
||||
timeslot, channel_offset);
|
||||
uint8_t link_options = ORCHESTRA_UNICAST_SENDER_BASED ? LINK_OPTION_RX : LINK_OPTION_TX | UNICAST_SLOT_SHARED_FLAG;
|
||||
|
||||
if(timeslot == get_node_timeslot(&linkaddr_node_addr)) {
|
||||
/* This is also our timeslot, add necessary flags */
|
||||
link_options |= ORCHESTRA_UNICAST_SENDER_BASED ? LINK_OPTION_TX | UNICAST_SLOT_SHARED_FLAG: LINK_OPTION_RX;
|
||||
}
|
||||
|
||||
/* Add/update link */
|
||||
tsch_schedule_add_link(sf_unicast, link_options, LINK_TYPE_NORMAL, &tsch_broadcast_address,
|
||||
timeslot, channel_offset);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
@ -123,7 +131,17 @@ remove_uc_link(const linkaddr_t *linkaddr)
|
|||
}
|
||||
item = nbr_table_next(nbr_routes, item);
|
||||
}
|
||||
tsch_schedule_remove_link(sf_unicast, l);
|
||||
|
||||
/* Do we need this timeslot? */
|
||||
if(timeslot == get_node_timeslot(&linkaddr_node_addr)) {
|
||||
/* This is our link, keep it but update the link options */
|
||||
uint8_t link_options = ORCHESTRA_UNICAST_SENDER_BASED ? LINK_OPTION_TX | UNICAST_SLOT_SHARED_FLAG: LINK_OPTION_RX;
|
||||
tsch_schedule_add_link(sf_unicast, link_options, LINK_TYPE_NORMAL, &tsch_broadcast_address,
|
||||
timeslot, channel_offset);
|
||||
} else {
|
||||
/* Remove link */
|
||||
tsch_schedule_remove_link(sf_unicast, l);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
|
@ -160,13 +178,14 @@ static void
|
|||
new_time_source(const struct tsch_neighbor *old, const struct tsch_neighbor *new)
|
||||
{
|
||||
if(new != old) {
|
||||
const linkaddr_t *old_addr = old != NULL ? &old->addr : NULL;
|
||||
const linkaddr_t *new_addr = new != NULL ? &new->addr : NULL;
|
||||
if(new_addr != NULL) {
|
||||
linkaddr_copy(&orchestra_parent_linkaddr, new_addr);
|
||||
} else {
|
||||
linkaddr_copy(&orchestra_parent_linkaddr, &linkaddr_null);
|
||||
}
|
||||
remove_uc_link(new_addr);
|
||||
remove_uc_link(old_addr);
|
||||
add_uc_link(new_addr);
|
||||
}
|
||||
}
|
||||
|
@ -185,7 +204,7 @@ init(uint16_t sf_handle)
|
|||
timeslot, channel_offset);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
struct orchestra_rule unicast_per_neighbor = {
|
||||
struct orchestra_rule unicast_per_neighbor_rpl_storing = {
|
||||
init,
|
||||
new_time_source,
|
||||
select_packet,
|
|
@ -53,7 +53,8 @@ struct orchestra_rule {
|
|||
};
|
||||
|
||||
struct orchestra_rule eb_per_time_source;
|
||||
struct orchestra_rule unicast_per_neighbor;
|
||||
struct orchestra_rule unicast_per_neighbor_rpl_storing;
|
||||
struct orchestra_rule unicast_per_neighbor_rpl_ns;
|
||||
struct orchestra_rule default_common;
|
||||
|
||||
extern linkaddr_t orchestra_parent_linkaddr;
|
||||
|
|
|
@ -116,11 +116,13 @@ PROCESS_THREAD(shell_exec_process, ev, data)
|
|||
shell_output_str(&exec_command, print, symbol);
|
||||
|
||||
if(ret == ELFLOADER_OK) {
|
||||
#if !PROCESS_CONF_NO_PROCESS_NAMES
|
||||
int i;
|
||||
for(i = 0; elfloader_autostart_processes[i] != NULL; ++i) {
|
||||
shell_output_str(&exec_command, "exec: starting process ",
|
||||
elfloader_autostart_processes[i]->name);
|
||||
}
|
||||
#endif
|
||||
autostart_start(elfloader_autostart_processes);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue