* Simple JSON parser and generator.

* Simple HTTP webservice with support for both receiving and sending HTTP requests.
* json-ws example that optionally push sensor data to COSM over IPv6.
This commit is contained in:
Joakim Eriksson 2012-06-02 18:24:29 +02:00 committed by Niclas Finne
parent f177284a73
commit 51b73127e9
19 changed files with 3028 additions and 0 deletions

View File

@ -0,0 +1 @@
httpd-ws_src = httpd-ws.c

478
apps/httpd-ws/httpd-ws.c Normal file
View File

@ -0,0 +1,478 @@
/*
* Copyright (c) 2010-2012, 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 simple webserver for web services
* \author
* Adam Dunkels <adam@sics.se>
* Niclas Finne <nfi@sics.se>
* Joakim Eriksson <joakime@sics.se>
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "contiki-net.h"
#include "httpd-ws.h"
#define DEBUG 0
#if DEBUG
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...)
#endif
#ifndef WEBSERVER_CONF_CFS_CONNS
#define CONNS UIP_CONNS
#else /* WEBSERVER_CONF_CFS_CONNS */
#define CONNS WEBSERVER_CONF_CFS_CONNS
#endif /* WEBSERVER_CONF_CFS_CONNS */
#ifndef WEBSERVER_CONF_CFS_URLCONV
#define URLCONV 0
#else /* WEBSERVER_CONF_CFS_URLCONV */
#define URLCONV WEBSERVER_CONF_CFS_URLCONV
#endif /* WEBSERVER_CONF_CFS_URLCONV */
#if URLCONV
#include "urlconv.h"
#endif /* URLCONV */
static struct httpd_ws_state conns[CONNS];
PROCESS(httpd_ws_process, "Web server (WS)");
#define ISO_nl 0x0a
#define ISO_space 0x20
#define ISO_period 0x2e
#define ISO_slash 0x2f
uint16_t http_connections = 0;
static const char http_10[] = " HTTP/1.0\r\n";
static const char http_content_type[] = "Content-Type:";
static const char http_content_type_html[] = "text/html";
static const char http_content_len[] = "Content-Length:";
static const char http_header_404[] =
"HTTP/1.0 404 Not found\r\nServer: Contiki\r\nConnection: close\r\n";
static const char http_header_200[] =
"HTTP/1.0 200 OK\r\nServer: Contiki\r\nConnection: close\r\n";
static const char html_not_found[] =
"<html><body><h1>Page not found</h1></body></html>";
/*---------------------------------------------------------------------------*/
/* just set all states to unused */
static void
httpd_state_init(void)
{
int i;
for(i = 0; i < CONNS; i++) {
conns[i].state = HTTPD_WS_STATE_UNUSED;
}
}
/*---------------------------------------------------------------------------*/
static struct httpd_ws_state *
httpd_state_alloc(void)
{
int i;
for(i = 0; i < CONNS; i++) {
if(conns[i].state == HTTPD_WS_STATE_UNUSED) {
conns[i].state = HTTPD_WS_STATE_INPUT;
return &conns[i];
}
}
return NULL;
}
/*---------------------------------------------------------------------------*/
#define httpd_state_free(s) (s->state = HTTPD_WS_STATE_UNUSED)
/*---------------------------------------------------------------------------*/
static
PT_THREAD(send_string(struct httpd_ws_state *s, const char *str, uint16_t len))
{
PSOCK_BEGIN(&s->sout);
SEND_STRING(&s->sout, str, len);
PSOCK_END(&s->sout);
}
/*---------------------------------------------------------------------------*/
static
PT_THREAD(send_headers(struct httpd_ws_state *s, const char *statushdr))
{
PSOCK_BEGIN(&s->sout);
SEND_STRING(&s->sout, statushdr, strlen(statushdr));
s->outbuf_pos = snprintf(s->outbuf, sizeof(s->outbuf),
"%s %s\r\n\r\n", http_content_type,
s->content_type == NULL
? http_content_type_html : s->content_type);
SEND_STRING(&s->sout, s->outbuf, s->outbuf_pos);
s->outbuf_pos = 0;
PSOCK_END(&s->sout);
}
/*---------------------------------------------------------------------------*/
static
PT_THREAD(handle_output(struct httpd_ws_state *s))
{
PT_BEGIN(&s->outputpt);
s->content_type = http_content_type_html;
s->script = httpd_ws_get_script(s);
if(s->script == NULL) {
PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_404));
PT_WAIT_THREAD(&s->outputpt,
send_string(s, html_not_found, strlen(html_not_found)));
uip_close();
/* webserver_log_file(&uip_conn->ripaddr, "404 - not found"); */
PT_EXIT(&s->outputpt);
} else {
if(s->request_type == HTTPD_WS_POST) {
/* A post has a body that needs to be read */
s->state = HTTPD_WS_STATE_INPUT;
PT_WAIT_UNTIL(&s->outputpt, s->state == HTTPD_WS_STATE_OUTPUT);
}
PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_200));
PT_WAIT_THREAD(&s->outputpt, s->script(s));
}
s->script = NULL;
PSOCK_CLOSE(&s->sout);
PT_END(&s->outputpt);
}
/*---------------------------------------------------------------------------*/
static
PT_THREAD(handle_request(struct httpd_ws_state *s))
{
PT_BEGIN(&s->outputpt);
/* send the request line */
PT_WAIT_THREAD(&s->outputpt,
send_string(s, s->filename, strlen(s->filename)));
/* send host */
if(s->outbuf_pos > 0) {
PT_WAIT_THREAD(&s->outputpt, send_string(s, s->outbuf, s->outbuf_pos));
}
if(s->content_type != NULL) {
s->outbuf_pos = snprintf(s->outbuf, sizeof(s->outbuf), "%s %s\r\n",
http_content_type, s->content_type);
PT_WAIT_THREAD(&s->outputpt, send_string(s, s->outbuf, s->outbuf_pos));
}
/* send the extra header(s) */
if(s->output_extra_headers != NULL) {
s->response_index = 0;
while((s->outbuf_pos =
s->output_extra_headers(s,
s->outbuf, sizeof(s->outbuf),
s->response_index)) > 0) {
PT_WAIT_THREAD(&s->outputpt, send_string(s, s->outbuf, s->outbuf_pos));
s->response_index++;
}
}
/* send content length */
if(s->content_len > 0) {
s->outbuf_pos = snprintf(s->outbuf, sizeof(s->outbuf), "%s %u\r\n",
http_content_len, s->content_len);
}
/* send header separator */
if(s->outbuf_pos + 2 < sizeof(s->outbuf)) {
s->outbuf[s->outbuf_pos++] = '\r';
s->outbuf[s->outbuf_pos++] = '\n';
}
PT_WAIT_THREAD(&s->outputpt, send_string(s, s->outbuf, s->outbuf_pos));
s->outbuf_pos = 0;
if(s->script != NULL) {
PT_WAIT_THREAD(&s->outputpt, s->script(s));
}
s->state = HTTPD_WS_STATE_REQUEST_INPUT;
PSOCK_CLOSE(&s->sout);
PT_END(&s->outputpt);
}
/*---------------------------------------------------------------------------*/
static
PT_THREAD(handle_input(struct httpd_ws_state *s))
{
PSOCK_BEGIN(&s->sin);
PSOCK_READTO(&s->sin, ISO_space);
if(strncmp(s->inputbuf, "GET ", 4) == 0) {
s->request_type = HTTPD_WS_GET;
} else if(strncmp(s->inputbuf, "POST ", 5) == 0) {
s->request_type = HTTPD_WS_POST;
s->content_len = 0;
} else if(strncmp(s->inputbuf, "HTTP ", 5) == 0) {
s->request_type = HTTPD_WS_RESPONSE;
} else {
PSOCK_CLOSE_EXIT(&s->sin);
}
PSOCK_READTO(&s->sin, ISO_space);
/* TODO handle HTTP response */
if(s->inputbuf[0] != ISO_slash) {
PSOCK_CLOSE_EXIT(&s->sin);
}
#if URLCONV
s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0;
urlconv_tofilename(s->filename, s->inputbuf, sizeof(s->filename));
#else /* URLCONV */
s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0;
snprintf(s->filename, sizeof(s->filename), "%s", s->inputbuf);
#endif /* URLCONV */
/* webserver_log_file(&uip_conn->ripaddr, s->filename); */
s->state = HTTPD_WS_STATE_OUTPUT;
while(1) {
PSOCK_READTO(&s->sin, ISO_nl);
if(s->request_type == HTTPD_WS_POST &&
strncmp(s->inputbuf, http_content_len, 15) == 0) {
s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0;
s->content_len = atoi(&s->inputbuf[16]);
}
/* should have a header callback here check_header(s) */
if(PSOCK_DATALEN(&s->sin) > 2) {
s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0;
} else if(s->request_type == HTTPD_WS_POST) {
PSOCK_READBUF_LEN(&s->sin, s->content_len);
s->inputbuf[PSOCK_DATALEN(&s->sin)] = 0;
/* printf("Content: '%s'\nSize:%d\n", s->inputbuf, PSOCK_DATALEN(&s->sin)); */
s->state = HTTPD_WS_STATE_OUTPUT;
}
}
PSOCK_END(&s->sin);
}
/*---------------------------------------------------------------------------*/
static void
handle_connection(struct httpd_ws_state *s)
{
if(s->state == HTTPD_WS_STATE_REQUEST_OUTPUT) {
handle_request(s);
}
handle_input(s);
if(s->state == HTTPD_WS_STATE_OUTPUT) {
handle_output(s);
}
}
/*---------------------------------------------------------------------------*/
void
httpd_ws_appcall(void *state)
{
struct httpd_ws_state *s = (struct httpd_ws_state *)state;
if(uip_closed() || uip_aborted() || uip_timedout()) {
if(s != NULL) {
PRINTF("HTTPD-WS: closed/aborted (%d)\n", http_connections);
http_connections--;
httpd_state_free(s);
} else {
PRINTF("HTTPD-WS: closed/aborted ** NO HTTPD_WS_STATE!!! ** (%d)\n",
http_connections);
}
} else if(uip_connected()) {
if(s == NULL) {
s = httpd_state_alloc();
if(s == NULL) {
uip_abort();
PRINTF("HTTPD-WS: aborting - no resource (%d)\n", http_connections);
/* webserver_log_file(&uip_conn->ripaddr, "reset (no memory block)"); */
return;
}
http_connections++;
tcp_markconn(uip_conn, s);
s->state = HTTPD_WS_STATE_INPUT;
} else {
/* this is a request that is to be sent! */
s->state = HTTPD_WS_STATE_REQUEST_OUTPUT;
}
PSOCK_INIT(&s->sin, (uint8_t *)s->inputbuf, sizeof(s->inputbuf) - 1);
PSOCK_INIT(&s->sout, (uint8_t *)s->inputbuf, sizeof(s->inputbuf) - 1);
PT_INIT(&s->outputpt);
timer_set(&s->timer, CLOCK_SECOND * 30);
handle_connection(s);
} else if(s != NULL) {
if(uip_poll()) {
if(timer_expired(&s->timer)) {
uip_abort();
PRINTF("HTTPD-WS: aborting - http timeout (%d)\n", http_connections);
http_connections--;
httpd_state_free(s);
/* webserver_log_file(&uip_conn->ripaddr, "reset (timeout)"); */
} else {
PRINTF("HTTPD-WS: uip-poll (%d)\n", http_connections);
}
} else {
/* PRINTF("HTTPD-WS: restart timer %s (%d)\n", s->filename, */
/* http_connections); */
timer_restart(&s->timer);
}
handle_connection(s);
} else {
PRINTF("HTTPD-WS: aborting - no state (%d)\n", http_connections);
uip_abort();
}
}
/*---------------------------------------------------------------------------*/
void
httpd_ws_init(void)
{
tcp_listen(UIP_HTONS(80));
httpd_state_init();
#if URLCONV
urlconv_init();
#endif /* URLCONV */
}
/*---------------------------------------------------------------------------*/
struct httpd_ws_state *
httpd_ws_request(char request_type, const char *host_ip, const char *host_hdr,
uint16_t port, const char *file,
const char *content_type, uint16_t content_len,
httpd_ws_script_t generator)
{
struct httpd_ws_state *s;
struct uip_conn *conn;
uip_ipaddr_t *ipaddr;
uip_ipaddr_t addr;
char *request_str;
/* First check if the host is an IP address. */
ipaddr = &addr;
if(uiplib_ipaddrconv(host_ip, &addr) == 0) {
#if 0 && UIP_UDP
ipaddr = resolv_lookup(host_ip);
if(ipaddr == NULL) {
return NULL;
}
#else /* UIP_UDP */
return NULL;
#endif /* UIP_UDP */
}
s = httpd_state_alloc();
if(s == NULL) {
/* no memory left... do no request... */
return NULL;
}
http_connections++;
switch(request_type) {
case HTTPD_WS_POST:
request_str = "POST ";
break;
case HTTPD_WS_PUT:
request_str = "PUT ";
break;
default:
request_str = "GET ";
break;
}
s->request_type = request_type;
s->content_len = content_len;
s->content_type = content_type;
s->script = generator;
s->state = HTTPD_WS_STATE_REQUEST_OUTPUT;
/* create a request line for a POST - should check size of it!!! */
/* Assume post for now */
snprintf(s->filename, sizeof(s->filename), "%s%s%s",
request_str, file, http_10);
s->outbuf_pos = snprintf(s->outbuf, sizeof(s->outbuf), "Host:%s\r\n",
host_hdr != NULL ? host_hdr : host_ip);
PROCESS_CONTEXT_BEGIN(&httpd_ws_process);
conn = tcp_connect(ipaddr, uip_htons(port), s);
PROCESS_CONTEXT_END(&httpd_ws_process);
if(conn == NULL) {
PRINTF("HTTPD-WS: aborting... could not allocate tcp connection (%d)\n",
http_connections);
httpd_state_free(s);
http_connections--;
return NULL;
}
PRINTF("HTTPD-WS: created http connection (%d)\n", http_connections);
return s;
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(httpd_ws_process, ev, data)
{
static struct etimer et;
int i;
PROCESS_BEGIN();
httpd_ws_init();
PRINTF("Buffer size, input %d, output\n",
HTTPD_INBUF_SIZE, HTTPD_OUTBUF_SIZE);
/* Delay 2-4 seconds */
etimer_set(&et, CLOCK_SECOND * 10);
/* GC any http session that is too long lived - either because other
end never closed or if any other state cause too long lived http
sessions */
while(1) {
PROCESS_WAIT_EVENT_UNTIL(ev == tcpip_event || etimer_expired(&et));
if(ev == tcpip_event) {
httpd_ws_appcall(data);
} else if(etimer_expired(&et)) {
PRINTF("HTTPD States: ");
for(i = 0; i < CONNS; i++) {
PRINTF("%d ", conns[i].state);
if(conns[i].state != HTTPD_WS_STATE_UNUSED &&
timer_expired(&conns[i].timer)) {
conns[i].state = HTTPD_WS_STATE_UNUSED;
PRINTF("\n*** RELEASED HTTPD Session\n");
http_connections--;
}
}
PRINTF("\n");
etimer_reset(&et);
}
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/

125
apps/httpd-ws/httpd-ws.h Normal file
View File

@ -0,0 +1,125 @@
/*
* Copyright (c) 2010-2012, 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 simple webserver for web services
* \author
* Adam Dunkels <adam@sics.se>
* Niclas Finne <nfi@sics.se>
* Joakim Eriksson <joakime@sics.se>
*/
#ifndef __HTTPD_WS_H__
#define __HTTPD_WS_H__
#include "contiki-net.h"
#ifndef WEBSERVER_CONF_CFS_PATHLEN
#define HTTPD_PATHLEN 80
#else /* WEBSERVER_CONF_CFS_CONNS */
#define HTTPD_PATHLEN WEBSERVER_CONF_CFS_PATHLEN
#endif /* WEBSERVER_CONF_CFS_CONNS */
#ifndef WEBSERVER_CONF_INBUF_SIZE
#define HTTPD_INBUF_SIZE (HTTPD_PATHLEN + 90)
#else /* WEBSERVER_CONF_INBUF_SIZE */
#define HTTPD_INBUF_SIZE WEBSERVER_CONF_INBUF_SIZE
#endif /* WEBSERVER_CONF_INBUF_SIZE */
#if HTTPD_INBUF_SIZE < UIP_TCP_MSS || HTTPD_INBUF_SIZE < UIP_RECEIVE_WINDOW
#error HTTPD_INBUF_SIZE is too small. Must be at least a TCP window in size.
#endif
#ifndef WEBSERVER_CONF_OUTBUF_SIZE
#define HTTPD_OUTBUF_SIZE (UIP_TCP_MSS + 20)
#else /* WEBSERVER_CONF_OUTBUF_SIZE */
#define HTTPD_OUTBUF_SIZE WEBSERVER_CONF_OUTBUF_SIZE
#endif /* WEBSERVER_CONF_OUTBUF_SIZE */
struct httpd_ws_state;
typedef char (* httpd_ws_script_t)(struct httpd_ws_state *s);
typedef int (* httpd_ws_output_headers_t)(struct httpd_ws_state *s,
char *buffer, int buf_size,
int index);
#define HTTPD_WS_GET 1
#define HTTPD_WS_POST 2
#define HTTPD_WS_PUT 3
#define HTTPD_WS_RESPONSE 4
#define HTTPD_WS_STATE_UNUSED 0
#define HTTPD_WS_STATE_INPUT 1
#define HTTPD_WS_STATE_OUTPUT 2
#define HTTPD_WS_STATE_REQUEST_OUTPUT 3
#define HTTPD_WS_STATE_REQUEST_INPUT 4
struct httpd_ws_state {
struct timer timer;
struct psock sin, sout;
struct pt outputpt;
char inputbuf[HTTPD_INBUF_SIZE];
char filename[HTTPD_PATHLEN];
const char *content_type;
uint16_t content_len;
char outbuf[HTTPD_OUTBUF_SIZE];
uint16_t outbuf_pos;
char state;
char request_type;
int response_index;
httpd_ws_output_headers_t output_extra_headers;
httpd_ws_script_t script;
#ifdef HTTPD_WS_CONF_USER_STATE
HTTPD_WS_CONF_USER_STATE;
#endif
};
void httpd_ws_init(void);
void httpd_ws_appcall(void *state);
struct httpd_ws_state *httpd_ws_request(char request_type,
const char *host_ip,
const char *host_hdr,
uint16_t port,
const char *file,
const char *content_type,
uint16_t content_len,
httpd_ws_script_t generator);
#define SEND_STRING(s, str, len) PSOCK_SEND((s), (uint8_t *)(str), (len))
httpd_ws_script_t httpd_ws_get_script(struct httpd_ws_state *s);
PROCESS_NAME(httpd_ws_process);
#endif /* __HTTPD_WS_H__ */

1
apps/json/Makefile.json Normal file
View File

@ -0,0 +1 @@
json_src = jsonparse.c jsontree.c

70
apps/json/json.h Normal file
View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2011-2012, 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 few JSON defines used for parsing and generating JSON.
* \author
* Niclas Finne <nfi@sics.se>
* Joakim Eriksson <joakime@sics.se>
*/
#ifndef __JSON_H__
#define __JSON_H__
#define JSON_TYPE_ARRAY '['
#define JSON_TYPE_OBJECT '{'
#define JSON_TYPE_PAIR ':'
#define JSON_TYPE_PAIR_NAME 'N' /* for N:V pairs */
#define JSON_TYPE_STRING '"'
#define JSON_TYPE_INT 'I'
#define JSON_TYPE_NUMBER '0'
#define JSON_TYPE_ERROR 0
/* how should we handle null vs false - both can be 0? */
#define JSON_TYPE_NULL 'n'
#define JSON_TYPE_TRUE 't'
#define JSON_TYPE_FALSE 'f'
#define JSON_TYPE_CALLBACK 'C'
enum {
JSON_ERROR_OK,
JSON_ERROR_SYNTAX,
JSON_ERROR_UNEXPECTED_ARRAY,
JSON_ERROR_UNEXPECTED_END_OF_ARRAY,
JSON_ERROR_UNEXPECTED_OBJECT,
JSON_ERROR_UNEXPECTED_STRING
};
#define JSON_CONTENT_TYPE "application/json"
#endif /* __JSON_H__ */

257
apps/json/jsonparse.c Normal file
View File

@ -0,0 +1,257 @@
/*
* Copyright (c) 2011-2012, 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.
*/
#include "jsonparse.h"
#include <stdlib.h>
#include <string.h>
/*--------------------------------------------------------------------*/
static int
push(struct jsonparse_state *state, char c)
{
state->stack[state->depth] = c;
state->depth++;
state->vtype = 0;
return state->depth < JSONPARSE_MAX_DEPTH;
}
/*--------------------------------------------------------------------*/
static char
pop(struct jsonparse_state *state)
{
if(state->depth == 0) {
return JSON_TYPE_ERROR;
}
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
atomic(struct jsonparse_state *state, char type)
{
char c;
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 */
}
}
state->vlen = state->pos - state->vstart - 1;
} else if(type == JSON_TYPE_NUMBER) {
do {
c = state->json[state->pos];
if((c < '0' || c > '9') && c != '.') {
c = 0;
} else {
state->pos++;
}
} while(c);
/* need to back one step since first char is already gone */
state->vstart--;
state->vlen = state->pos - state->vstart;
}
/* no other types for now... */
}
/*--------------------------------------------------------------------*/
static void
skip_ws(struct jsonparse_state *state)
{
char c;
while(state->pos < state->len &&
((c = state->json[state->pos]) == ' ' || c == '\n')) {
state->pos++;
}
}
/*--------------------------------------------------------------------*/
void
jsonparse_setup(struct jsonparse_state *state, const char *json, int len)
{
state->json = json;
state->len = len;
state->pos = 0;
state->depth = 0;
state->error = 0;
state->stack[0] = 0;
}
/*--------------------------------------------------------------------*/
int
jsonparse_next(struct jsonparse_state *state)
{
char c;
char s;
skip_ws(state);
c = state->json[state->pos];
s = jsonparse_get_type(state);
state->pos++;
switch(c) {
case '{':
push(state, c);
return c;
case '}':
if(s == ':' && state->vtype != 0) {
/* printf("Popping vtype: '%c'\n", state->vtype); */
pop(state);
s = jsonparse_get_type(state);
}
if(s == '{') {
pop(state);
} else {
state->error = JSON_ERROR_SYNTAX;
return JSON_TYPE_ERROR;
}
return c;
case ']':
if(s == '[') {
pop(state);
} else {
state->error = JSON_ERROR_UNEXPECTED_END_OF_ARRAY;
return JSON_TYPE_ERROR;
}
return c;
case ':':
push(state, c);
return c;
case ',':
/* if x:y ... , */
if(s == ':' && state->vtype != 0) {
pop(state);
} else if(s == '[') {
/* ok! */
} 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));
} else {
state->error = JSON_ERROR_UNEXPECTED_STRING;
return JSON_TYPE_ERROR;
}
return c;
case '[':
if(s == '{' || s == '[' || s == ':') {
push(state, c);
} else {
state->error = JSON_ERROR_UNEXPECTED_ARRAY;
return JSON_TYPE_ERROR;
}
return c;
default:
if(s == ':' || s == '[') {
if(c <= '9' && c >= '0') {
atomic(state, JSON_TYPE_NUMBER);
return JSON_TYPE_NUMBER;
}
}
}
return 0;
}
/*--------------------------------------------------------------------*/
/* get the json value of the current position
* works only on "atomic" values such as string, number, null, false, true
*/
/*--------------------------------------------------------------------*/
int
jsonparse_copy_value(struct jsonparse_state *state, char *str, int size)
{
int i;
if(state->vtype == 0) {
return 0;
}
size = size <= state->vlen ? (size - 1) : state->vlen;
for(i = 0; i < size; i++) {
str[i] = state->json[state->vstart + i];
}
str[i] = 0;
return state->vtype;
}
/*--------------------------------------------------------------------*/
int
jsonparse_get_value_as_int(struct jsonparse_state *state)
{
if(state->vtype != JSON_TYPE_NUMBER) {
return 0;
}
return atoi(&state->json[state->vstart]);
}
/*--------------------------------------------------------------------*/
long
jsonparse_get_value_as_long(struct jsonparse_state *state)
{
if(state->vtype != JSON_TYPE_NUMBER) {
return 0;
}
return atol(&state->json[state->vstart]);
}
/*--------------------------------------------------------------------*/
/* strcmp - assume no strange chars that needs to be stuffed in string... */
/*--------------------------------------------------------------------*/
int
jsonparse_strcmp_value(struct jsonparse_state *state, const char *str)
{
if(state->vtype == 0) {
return -1;
}
return strncmp(str, &state->json[state->vstart], state->vlen);
}
/*--------------------------------------------------------------------*/
int
jsonparse_get_len(struct jsonparse_state *state)
{
return state->vlen;
}
/*--------------------------------------------------------------------*/
int
jsonparse_get_type(struct jsonparse_state *state)
{
if(state->depth == 0) {
return 0;
}
return state->stack[state->depth - 1];
}
/*--------------------------------------------------------------------*/
int
jsonparse_has_next(struct jsonparse_state *state)
{
return state->pos < state->len;
}
/*--------------------------------------------------------------------*/

91
apps/json/jsonparse.h Normal file
View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2011-2012, 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.
*/
#ifndef __JSONPARSE_H__
#define __JSONPARSE_H__
#include "contiki-conf.h"
#include "json.h"
#ifdef JSONPARSE_CONF_MAX_DEPTH
#define JSONPARSE_MAX_DEPTH JSONPARSE_CONF_MAX_DEPTH
#else
#define JSONPARSE_MAX_DEPTH 10
#endif
struct jsonparse_state {
const char *json;
int pos;
int len;
int depth;
/* for handling atomic values */
int vstart;
int vlen;
char vtype;
char error;
char stack[JSONPARSE_MAX_DEPTH];
};
/**
* \brief Initialize a JSON parser state.
* \param state A pointer to a JSON parser state
* \param json The string to parse as JSON
* \param len The length of the string to parse
*
* This function initializes a JSON parser state for
* parsing a string as JSON.
*/
void jsonparse_setup(struct jsonparse_state *state, const char *json,
int len);
/* move to next JSON element */
int jsonparse_next(struct jsonparse_state *state);
/* copy the current JSON value into the specified buffer */
int jsonparse_copy_value(struct jsonparse_state *state, char *buf,
int buf_size);
/* get the current JSON value parsed as an int */
int jsonparse_get_value_as_int(struct jsonparse_state *state);
/* get the current JSON value parsed as a long */
long jsonparse_get_value_as_long(struct jsonparse_state *state);
/* get the length of the current JSON value */
int jsonparse_get_len(struct jsonparse_state *state);
/* get the type of the current JSON value */
int jsonparse_get_type(struct jsonparse_state *state);
/* compare the JSON value with the specified string */
int jsonparse_strcmp_value(struct jsonparse_state *state, const char *str);
#endif /* __JSONPARSE_H__ */

275
apps/json/jsontree.c Normal file
View File

@ -0,0 +1,275 @@
/*
* Copyright (c) 2011-2012, 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
* JSON output generation
* \author
* Niclas Finne <nfi@sics.se>
* Joakim Eriksson <joakime@sics.se>
*/
#include "contiki.h"
#include "jsontree.h"
#include "jsonparse.h"
#include <string.h>
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...)
#endif
/*---------------------------------------------------------------------------*/
void
jsontree_write_atom(const struct jsontree_context *js_ctx, const char *text)
{
if(text == NULL) {
js_ctx->putchar('0');
} else {
while(*text != '\0') {
js_ctx->putchar(*text++);
}
}
}
/*---------------------------------------------------------------------------*/
void
jsontree_write_string(const struct jsontree_context *js_ctx, const char *text)
{
js_ctx->putchar('"');
if(text != NULL) {
while(*text != '\0') {
if(*text == '"') {
js_ctx->putchar('\\');
}
js_ctx->putchar(*text++);
}
}
js_ctx->putchar('"');
}
/*---------------------------------------------------------------------------*/
void
jsontree_write_int(const struct jsontree_context *js_ctx, int value)
{
char buf[10];
int l;
if(value < 0) {
js_ctx->putchar('-');
value = -value;
}
l = sizeof(buf) - 1;
do {
buf[l--] = '0' + (value % 10);
value /= 10;
} while(value > 0 && l >= 0);
while(++l < sizeof(buf)) {
js_ctx->putchar(buf[l]);
}
}
/*---------------------------------------------------------------------------*/
void
jsontree_setup(struct jsontree_context *js_ctx, struct jsontree_value *root,
int (* putchar)(int))
{
js_ctx->values[0] = root;
js_ctx->putchar = putchar;
js_ctx->path = 0;
jsontree_reset(js_ctx);
}
/*---------------------------------------------------------------------------*/
void
jsontree_reset(struct jsontree_context *js_ctx)
{
js_ctx->depth = 0;
js_ctx->index[0] = 0;
}
/*---------------------------------------------------------------------------*/
const char *
jsontree_path_name(const struct jsontree_context *js_ctx, int depth)
{
if(depth < js_ctx->depth && js_ctx->values[depth]->type == JSON_TYPE_OBJECT) {
return ((struct jsontree_object *)js_ctx->values[depth])->
pairs[js_ctx->index[depth]].name;
}
return "";
}
/*---------------------------------------------------------------------------*/
int
jsontree_print_next(struct jsontree_context *js_ctx)
{
struct jsontree_value *v;
int index;
v = js_ctx->values[js_ctx->depth];
/* Default operation after switch is to back up one level */
switch(v->type) {
case JSON_TYPE_OBJECT:
case JSON_TYPE_ARRAY: {
struct jsontree_array *o = (struct jsontree_array *)v;
struct jsontree_value *ov;
index = js_ctx->index[js_ctx->depth];
if(index == 0) {
js_ctx->putchar(v->type);
js_ctx->putchar('\n');
}
if(index >= o->count) {
js_ctx->putchar('\n');
js_ctx->putchar(v->type + 2);
/* Default operation: back up one level! */
break;
}
if(index > 0) {
js_ctx->putchar(',');
js_ctx->putchar('\n');
}
if(v->type == JSON_TYPE_OBJECT) {
jsontree_write_string(js_ctx,
((struct jsontree_object *)o)->pairs[index].name);
js_ctx->putchar(':');
ov = ((struct jsontree_object *)o)->pairs[index].value;
} else {
ov = o->values[index];
}
/* TODO check max depth */
js_ctx->depth++; /* step down to value... */
js_ctx->index[js_ctx->depth] = 0; /* and init index */
js_ctx->values[js_ctx->depth] = ov;
/* Continue on this new level */
return 1;
}
case JSON_TYPE_STRING:
jsontree_write_string(js_ctx, ((struct jsontree_string *)v)->value);
/* Default operation: back up one level! */
break;
case JSON_TYPE_INT:
jsontree_write_int(js_ctx, ((struct jsontree_int *)v)->value);
/* Default operation: back up one level! */
break;
case JSON_TYPE_CALLBACK: { /* pre-formatted json string currently */
struct jsontree_callback *callback;
callback = (struct jsontree_callback *)v;
if(js_ctx->index[js_ctx->depth] == 0) {
/* First call: reset the callback status */
js_ctx->callback_state = 0;
}
if(callback->output == NULL) {
jsontree_write_string(js_ctx, "");
} else if(callback->output(js_ctx)) {
/* The callback wants to output more */
js_ctx->index[js_ctx->depth]++;
return 1;
}
/* Default operation: back up one level! */
break;
}
default:
PRINTF("\nError: Illegal json type:'%c'\n", v->type);
return 0;
}
/* Done => back up one level! */
if(js_ctx->depth > 0) {
js_ctx->depth--;
js_ctx->index[js_ctx->depth]++;
return 1;
}
return 0;
}
/*---------------------------------------------------------------------------*/
static struct jsontree_value *
find_next(struct jsontree_context *js_ctx)
{
struct jsontree_value *v;
int index;
do {
v = js_ctx->values[js_ctx->depth];
/* Default operation after switch is to back up one level */
switch(v->type) {
case JSON_TYPE_OBJECT:
case JSON_TYPE_ARRAY: {
struct jsontree_array *o = (struct jsontree_array *)v;
struct jsontree_value *ov;
index = js_ctx->index[js_ctx->depth];
if(index >= o->count) {
/* Default operation: back up one level! */
break;
}
if(v->type == JSON_TYPE_OBJECT) {
ov = ((struct jsontree_object *)o)->pairs[index].value;
} else {
ov = o->values[index];
}
/* TODO check max depth */
js_ctx->depth++; /* step down to value... */
js_ctx->index[js_ctx->depth] = 0; /* and init index */
js_ctx->values[js_ctx->depth] = ov;
/* Continue on this new level */
return ov;
}
default:
/* Default operation: back up one level! */
break;
}
/* Done => back up one level! */
if(js_ctx->depth > 0) {
js_ctx->depth--;
js_ctx->index[js_ctx->depth]++;
} else {
return NULL;
}
} while(1);
}
/*---------------------------------------------------------------------------*/
struct jsontree_value *
jsontree_find_next(struct jsontree_context *js_ctx, int type)
{
struct jsontree_value *v;
while((v = find_next(js_ctx)) != NULL && v->type != type &&
js_ctx->path < js_ctx->depth) {
/* search */
}
js_ctx->callback_state = 0;
return js_ctx->path < js_ctx->depth ? v : NULL;
}
/*---------------------------------------------------------------------------*/

135
apps/json/jsontree.h Normal file
View File

@ -0,0 +1,135 @@
/*
* Copyright (c) 2011-2012, 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
* JSON output generation
* \author
* Niclas Finne <nfi@sics.se>
* Joakim Eriksson <joakime@sics.se>
*/
#ifndef __JSONTREE_H__
#define __JSONTREE_H__
#include "contiki-conf.h"
#include "json.h"
#ifdef JSONTREE_CONF_MAX_DEPTH
#define JSONTREE_MAX_DEPTH JSONTREE_CONF_MAX_DEPTH
#else
#define JSONTREE_MAX_DEPTH 10
#endif /* JSONTREE_CONF_MAX_DEPTH */
struct jsontree_context {
struct jsontree_value *values[JSONTREE_MAX_DEPTH];
uint16_t index[JSONTREE_MAX_DEPTH];
int (* putchar)(int);
uint8_t depth;
uint8_t path;
int callback_state;
};
struct jsontree_value {
uint8_t type;
/* followed by a value */
};
struct jsontree_string {
uint8_t type;
const char *value;
};
struct jsontree_int {
uint8_t type;
int value;
};
/* NOTE: the jsontree_callback set will receive a jsonparse state */
struct jsonparse_state;
struct jsontree_callback {
uint8_t type;
int (* output)(struct jsontree_context *js_ctx);
int (* set)(struct jsontree_context *js_ctx, struct jsonparse_state *parser);
};
struct jsontree_pair {
const char *name;
struct jsontree_value *value;
};
struct jsontree_object {
uint8_t type;
uint8_t count;
struct jsontree_pair *pairs;
};
struct jsontree_array {
uint8_t type;
uint8_t count;
struct jsontree_value **values;
};
#define JSONTREE_STRING(text) {JSON_TYPE_STRING, (text)}
#define JSONTREE_PAIR(name, value) {(name), (struct jsontree_value *)(value)}
#define JSONTREE_CALLBACK(output, set) {JSON_TYPE_CALLBACK, (output), (set)}
#define JSONTREE_OBJECT(name, ...) \
static struct jsontree_pair jsontree_pair_##name[] = {__VA_ARGS__}; \
static struct jsontree_object name = { \
JSON_TYPE_OBJECT, \
sizeof(jsontree_pair_##name)/sizeof(struct jsontree_pair), \
jsontree_pair_##name }
#define JSONTREE_OBJECT_EXT(name, ...) \
static struct jsontree_pair jsontree_pair_##name[] = {__VA_ARGS__}; \
struct jsontree_object name = { \
JSON_TYPE_OBJECT, \
sizeof(jsontree_pair_##name)/sizeof(struct jsontree_pair), \
jsontree_pair_##name }
void jsontree_setup(struct jsontree_context *js_ctx,
struct jsontree_value *root, int (* putchar)(int));
void jsontree_reset(struct jsontree_context *js_ctx);
const char *jsontree_path_name(const struct jsontree_context *js_ctx,
int depth);
void jsontree_write_int(const struct jsontree_context *js_ctx, int value);
void jsontree_write_atom(const struct jsontree_context *js_ctx,
const char *text);
void jsontree_write_string(const struct jsontree_context *js_ctx,
const char *text);
int jsontree_print_next(struct jsontree_context *js_ctx);
struct jsontree_value *jsontree_find_next(struct jsontree_context *js_ctx,
int type);
#endif /* __JSONTREE_H__ */

View File

@ -0,0 +1,30 @@
CONTIKI=../../..
WITH_UIP6=1
UIP_CONF_IPV6=1
SMALL=1
PROJECT_SOURCEFILES += json-ws.c
ifdef WITH_COSM
CFLAGS += -DWITH_COSM=1
endif
ifdef WITH_UDP
CFLAGS += -DWITH_UDP=1
PROJECT_SOURCEFILES += json-ws-udp.c
endif
APPS += httpd-ws json
CFLAGS += -DPROJECT_CONF_H=\"project-conf.h\"
ifeq ($(TARGET),)
-include Makefile.target
endif
ifneq ($(TARGET),)
all: websense-$(TARGET)
endif
include $(CONTIKI)/Makefile.include

View File

@ -0,0 +1,106 @@
Short description on how to set-up a sensor network for global IPv6 addresses.
NOTE: this assumes that you do not have a native IPv6 connection.
You will need:
* PC with Ubuntu (Linux) - 11 or 12 versions
* A node for the RPL-Border-Router (examples/ipv6/rpl-border-router)
* A node for the json webservice (examples/ipv6/json-ws)
Set-up IPv6 tunnel and Border Router
------------------------------------
1. Ensure that you have gogo6c installed.
> sudo apt-get install gogoc
2. Register an account at gogo6 and Freenet6 (http://www.gogo6.com).
The account at Freenet6 is needed by the gogo6c client.
3. Edit the gogoc.conf and set your own Freenet6 user and password by
changing the lines with "userid" and "passwd".
4. Start gogoc at command line
> cd contiki/examples/ipv6/json-ws
> sudo gogoc -f gogoc.conf -n
This will print your prefix - TSP_PREFIX.
In my case TSP_PREFIX=2001:05c0:1517:e400 (prefixlen is 56).
5. Connect one of the nodes to the PC (via USB or serial) and program
it with the RPL-border-router (assumes Z1 node).
> cd contiki/examples/ipv6/rpl-border-router
> make DEFINES=DEFINES=NETSTACK_RDC=nullrdc_driver,NULLRDC_CONF_802154_AUTOACK=1 TARGET=z1 border-router.upload
6. Run tunslip6 which will forward IP from the RPL network to
the IPv6 tunnel (and to the Internet).
> cd contiki/examples/ipv6/rpl-border-router
> make connect-router PREFIX=<TSP_PREFIX>::1/64
When you start this you should get a printout from the border-router
which give you the IPv6 address of it.
Server IPv6 addresses:
2001:05c0:1517:e400:c30c::10a
fe80::c30c:0:0:10a
7. Browse using Mozilla Firefox (or any other browser) to the IPv6 address
given by the border router. This will show you the list of other nodes
connected to the RPL network.
http://[2001:05c0:1517:e400:c30c::10a]/
NOTE: this is a global IPv6 address so it should also be reachable from
any machine on the Internet.
Configuration of COSM submission
--------------------------------
1. Register a COSM account at https://cosm.com/
Set-up a feed and create an API key for the feed.
2. Program the sensor node with (assumes Z1)
> cd contiki/examples/ipv6/json-ws
> make websense-z1.upload WITH_COSM=1 TARGET=z1
3. Check the IPv6 address of the node via the RPL-border router or
by looking at printouts when booting (make login TARGET=z1)
4. You need to configure the node to push data to the COSM feed and
this can be done in several ways. For convenience a Python script
is included that pushes the configuration to the nodes.
Edit the file 'setcosm.py' and replace "<your-key>" and
"<your-feed>" with your COSM API key and COSM feed id. You can then
use this Python script to configure your nodes.
This is an example that configures the node with IP address
2001:05c0:1517:e400:c30c::10b to push data to the COSM feed with
stream 1:
> cd contiki/examples/ipv6/json-ws
> ./setcosm.py [2001:05c0:1517:e400:c30c::10b] 1
Another way to configure the nodes is to use a REST add-on for the
web browser to post a COSM configuration to the node. "REST Client"
for Mozilla Firefox is an example of such add-on.
POST a JSON expression to your node with the following data:
This assumes that you have the feed with id 55180 and want to post
to stream 1 in that feed. The field 'appdata' should be set to the
API key you created at the COSM web site for the feed.
{
"host":"[2001:470:1f10:333::2]",
"port":80,
"path":"/v2/feeds/55180/datastreams/1",
"appdata":"<insert your COSM API key>",
"interval":120,
"proto":"cosm"
}
This will configure the node to periodically push temperature data
every other minute. You can use GET to retrieve the data to se that
the node has been successfully configured (the COSM API key will be
visualized as a number of stars).

View File

@ -0,0 +1,351 @@
#-----------------------------------------------------------------------------
# $Id: gogoc.conf.in,v 1.1 2009/11/20 16:53:12 jasminko Exp $
#-----------------------------------------------------------------------------
########################## READ ME! ################################
#
# Welcome to the gogoCLIENT configuration file.
# In order to use the client, you need to modify the 'userid', 'passwd' and
# 'server' parameters below depending on which of these situations applies:
#
# 1. If you created a Freenet6 account, enter your userid and password below.
# Change the server name to "broker.freenet6.net" and auth_method to 'any'.
# 2. If you would like to use Freenet6 without creating an account,
# do not make any modifications and close this file.
# 3. If this software was provided by your ISP, enter the userid, password and
# server name provided by your ISP below.
#
########################## BASIC CONFIGURATION ################################
#
# User Identification and Password:
# Specify your user name and password as provided by your ISP or Freenet6.
# If you plan to connect anonymously, leave these values empty.
# NOTE: Change auth_method option if you are using a username/password.
#
# userid=<your_userid>
# passwd=<your_password>
#
userid=<change to your userid>
passwd=<change to your password>
#
# gogoSERVER:
# Specify a gogoSERVER name or IP address (provided by your ISP or
# Freenet6). An optional port number can be added; the default port number
# is 3653.
#
# Examples:
# server=hostname # FQDN
# server=A.B.C.D # IPv4 address
# server=[X:X::X:X] # IPv6 address
# server=hostname:port_number
# server=A.B.C.D:port_number
# server=[X:X::X:X]:port_number
#
# Freenet6 account holders should enter authenticated.freenet6.net,
# otherwise use anonymous.freenet6.net.
# Your ISP may provide you with a different server name.
#
#server=anonymous.freenet6.net
#server=authenticated.freenet6.net
server=amsterdam.freenet6.net
#
# Authentication Method:
#
# auth_method=<{anonymous}|{any|passdss-3des-1|digest-md5|plain}>
#
# anonymous: Sends no username or password
#
# any: The most secure method will be used.
# passdss-3des-1: The password is sent encrypted.
# digest-md5: The password is sent encrypted.
# plain: Both username and password are sent as plain text.
#
# Recommended values:
# - any: If you are authenticating a username / password.
# - anonymous: If you are connecting anonymously.
#
#auth_method=anonymous
auth_method=any
########################## ROUTING CONFIGURATION ##############################
# Use these parameters when you wish the client to act as a router and provide
# IPv6 connectivity to IPv6-capable devices on your network.
#
# Local Host Type:
# Change this value to 'router' to enable IPv6 advertisements.
#
# host_type=<host|router>
#
host_type=router
#host
#
# Prefix Length:
# Length of the requested prefix. Valid values range between 0 and 64 when
# using V6*V4 tunnel modes, and between 0 and 32 when using V4V6 tunnel mode.
#
# prefixlen=<integer>
#
prefixlen=64
#
# Advertisement Interface Prefix:
# Name of the interface that will be configured to send router advertisements.
# This is an interface index on Windows (ex: 4) and a name on Linux
# and BSD (ex: eth1 or fxp1).
#
# if_prefix=<interface name>
#
if_prefix=tun0
#
# DNS Server:
# A DNS server list to which the reverse prefix will be delegated. Servers
# are separated by the colon(:) delimiter.
#
# Example: dns_server=ns1.domain:ns2.domain:ns3.domain
#
dns_server=
######################### ADVANCED CONFIGURATION ##############################
#
# gogoCLIENT Installation Directory:
# Directory where the gogoCLIENT will be installed. This value has been
# set during installation.
#
gogoc_dir=
#
# Auto-Retry Connect, Retry Delay and Max Retry Delay:
# When auto_retry_connect=yes, the gogoCLIENT will attempt to reconnect
# after a disconnection occurred. The time to wait is 'retry_delay' and that
# delay is doubled at every 3 failed consecutive reconnection attempt.
# However, the wait delay will never exceed retry_delay_max.
#
#
# auto_retry_connect=<yes|no>
# retry_delay=<integer: 0..3600>
# retry_delay_max=<integer: 0..3600>
#
# Recommended values: "yes", 30, 300
#
auto_retry_connect=yes
retry_delay=30
retry_delay_max=300
#
# Keepalive Feature and Message Interval:
# Indicates if and how often the client will send data to keep the tunnel
# active.
#
# keepalive=<yes|no>
# keepalive_interval=<integer>
#
# Recommended values: "yes" and 30
#
keepalive=yes
keepalive_interval=30
#
# Tunnel Encapsulation Mode:
# v6v4: IPv6-in-IPv4 tunnel.
# v6udpv4: IPv6-in-UDP-in-IPv4 tunnel (for clients behind a NAT).
# v6anyv4: Lets the broker choose the best mode for IPv6 tunnel.
# v4v6: IPv4-in-IPv6 tunnel.
#
# Recommended value: v6anyv4
#
tunnel_mode=v6anyv4
#
# Tunnel Interface Name:
# The interface name assigned to the tunnel. This value is O/S dependent.
#
# if_tunnel_v6v4 is the tunnel interface name for v6v4 encapsulation mode
# if_tunnel_v6udpv4 is the tunnel interface name for v6udpv4 encapsulate mode
# if_tunnel_v4v6 is the tunnel interface name for v4v6 encapsulation mode
#
# Default values are set during installation.
#
if_tunnel_v6v4=sit1
if_tunnel_v6udpv4=sit
if_tunnel_v4v6=sit0
#
# Local IP Address of the Client:
# Allows you to set a specific address as the local tunnel endpoint.
#
# client_v4=<auto|A.B.C.D (valid ipv4 address)>
# client_v6=<auto|X:X::X:X (valid ipv6 address)>
# auto: The gogoCLIENT will find the local IP address endpoint.
#
# Recommended value: auto
#
client_v4=auto
client_v6=auto
#
# Script Name:
# File name of the script to run to install the tunnel interface. The
# scripts are located in the template directory under the client
# installation directory.
#
# template=<checktunnel|freebsd|netbsd|openbsd|linux|windows|darwin|cisco|solaris>
#
# Default value is set during installation.
#
template=linux
#
# Proxy client:
# Indicates that this client will request a tunnel for another endpoint,
# such as a Cisco router.
#
# proxy_client=<yes|no>
#
# NOTE: NAT traversal is not possible in proxy mode.
#
proxy_client=no
############################ BROKER REDIRECTION ###############################
#
# Broker List File Name:
# The 'broker_list' directive specifies the filename where the broker
# list received during broker redirection will be saved.
#
# broker_list=<file_name>
#
broker_list=/var/lib/gogoc/tsp-broker-list.txt
#
# Last Server Used File Name:
# The 'last_server' directive specifies the filename where the address of
# the last broker to which a connection was successfully established will
# be saved.
#
# last_server=<file_name>
#
last_server=/var/lib/gogoc/tsp-last-server.txt
#
# Always Use Last Known Working Server:
# The value of the 'always_use_same_server' directive determines whether the
# client should always try to connect to the broker found in the
# 'last_server' directive filename.
#
# always_use_same_server=<yes|no>
#
always_use_same_server=no
#################################### LOGGING ##################################
#
# Log Verbosity Configuration:
# The format is 'log_<destination>=level', where possible values for
# 'destination' are:
#
# - console (logging to the console [AKA stdout])
# - stderr (logging to standard error)
# - file (logging to a file)
# - syslog (logging to syslog [Unix only])
#
# and 'level' is a digit between 0 and 3. A 'level' value of 0 disables
# logging to the destination, while values 1 to 3 request increasing levels
# of log verbosity and detail. If 'level' is not specified, a value of 1 is
# assumed.
#
# Example:
# log_file=3 (Maximal logging to a file)
# log_stderr=0 (Logging to standard error disabled)
# log_console= (Minimal logging to the console)
#
# - Default configuration on Windows platforms:
#
# log_console=0
# log_stderr=0
# log_file=1
#
# - Default configuration on Unix platforms:
#
# log_console=0
# log_stderr=1
# log_file=0
# log_syslog=0
#
log_console=3
log_stderr=0
#log_file=
#log_syslog=
#
# Log File Name:
# When logging to file is requested using the 'log_file' directive, the name
# and path of the file to use may be specified using this directive.
#
# log_filename=<file_name>
#
log_filename=/var/log/gogoc/gogoc.log
#
# Log File Rotation:
# When logging to file is requested using the 'log_file' directive, log file
# rotation may be enabled. When enabled, the contents of the log file will
# be moved to a backup file just before it reaches the maximum log file size
# specified via this directive.
#
# The name of the backup file is the name of the original log file with
# '.<timestamp>' inserted before the file extension. If the file does not
# have an extension, '.<timestamp>' is appended to the name of the original
# log file. The timestamp specifies when the rotation occurred.
#
# After the contents of the log file have been moved to the backup file, the
# original file is cleared, and logging resumes at the beginning of the file.
#
# log_rotation=<yes|no>
#
log_rotation=yes
#
# Log File Rotation Size:
# The 'log_rotation_size' directive specifies the maximum size a log file may
# reach before rotation occurs, if enabled. The value is expressed in
# kilobytes.
#
# log_rotation_size=<16|32|128|1024>
#
log_rotation_size=32
#
# Deletion of rotated log files:
# The 'log_rotation_delete' directive specifies that no log backup will be
# kept. When rotation occurs, the file is immediately wiped out and a new
# log file is started.
#
# log_rotation_delete=<yes|no>
#
log_rotation_delete=no
#
# Syslog Logging Facility [Unix Only]:
# When logging to syslog is requested using the 'log_syslog' directive, the
# facility to use may be specified using this directive.
#
# syslog_facility=<USER|LOCAL[0-7]>
#
syslog_facility=USER
# end of gogoc.conf
#------------------------------------------------------------------------------

View File

@ -0,0 +1,154 @@
/*
* Copyright (c) 2011-2012, 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.
*
* $Id: dmacro.dm,v 1.11 2006/03/18 19:43:52 nfi Exp $
*/
/**
* \file
* Code for sending the JSON data as a UDP packet
* Specify proto = "udp", port = <server-udp-port>
* host = <ipv6-server-address>
*
* \author
* Niclas Finne <nfi@sics.se>
* Joakim Eriksson <joakime@sics.se>
*/
#include "contiki.h"
#include "httpd-ws.h"
#include "jsontree.h"
#include "jsonparse.h"
#include "json-ws.h"
#include <stdio.h>
#include <string.h>
#define DEBUG DEBUG_FULL
#include "net/uip-debug.h"
static struct uip_udp_conn *client_conn;
static uip_ipaddr_t server_ipaddr;
static uint16_t server_port;
#define SENDER_PORT 8181
/*---------------------------------------------------------------------------*/
int
json_ws_udp_setup(const char *host, uint16_t port)
{
server_port = port;
if(client_conn != NULL) {
/* this should be a macro uip_udp_conn_free() or something */
uip_udp_remove(client_conn);
client_conn = NULL;
}
uip_ipaddr_t *ipaddr;
/* First check if the host is an IP address. */
ipaddr = &server_ipaddr;
if(uiplib_ipaddrconv(host, &server_ipaddr) == 0) {
#if 0 && UIP_UDP
ipaddr = resolv_lookup(host);
if(ipaddr == NULL) {
return 0;
}
#else /* UIP_UDP */
return 0;
#endif /* UIP_UDP */
}
/* new connection with remote host */
client_conn = udp_new(&server_ipaddr, UIP_HTONS(server_port), NULL);
udp_bind(client_conn, UIP_HTONS(SENDER_PORT));
PRINTF("Created a connection with the server ");
PRINT6ADDR(&client_conn->ripaddr);
PRINTF(" local/remote port %u/%u\n",
UIP_HTONS(client_conn->lport), UIP_HTONS(client_conn->rport));
return 1;
}
/*---------------------------------------------------------------------------*/
static char *udp_buf;
static int pos;
static int size;
static int
putchar_udp(int c)
{
if(udp_buf != NULL && pos <= size) {
udp_buf[pos++] = c;
return c;
}
return 0;
}
/*---------------------------------------------------------------------------*/
void
json_ws_udp_send(struct jsontree_value *tree, const char *path)
{
struct jsontree_context json;
/* maxsize = 70 bytes */
char buf[70];
udp_buf = buf;
/* reset state and set max-size */
/* NOTE: packet will be truncated at 70 bytes */
pos = 0;
size = sizeof(buf);
json.values[0] = (struct json_value *)tree;
jsontree_reset(&json);
find_json_path(&json, path);
json.path = json.depth;
json.putchar = putchar_udp;
while(jsontree_print_next(&json) && json.path <= json.depth);
printf("Real UDP size: %d\n", pos);
buf[pos] = 0;
uip_udp_packet_sendto(client_conn, &buf, pos,
&server_ipaddr, UIP_HTONS(server_port));
}
/*---------------------------------------------------------------------------*/
void
json_ws_udp_debug(char *string)
{
int len;
len = strlen(string);
uip_udp_packet_sendto(client_conn, string, len,
&server_ipaddr, UIP_HTONS(server_port));
}
/*---------------------------------------------------------------------------*/

View File

@ -0,0 +1,521 @@
/*
* Copyright (c) 2011-2012, 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
* JSON webservice util
* \author
* Niclas Finne <nfi@sics.se>
* Joakim Eriksson <joakime@sics.se>
* Joel Hoglund <joel@sics.se>
*/
#include "contiki.h"
#if PLATFORM_HAS_LEDS
#include "dev/leds.h"
#endif
#include "httpd-ws.h"
#include "jsontree.h"
#include "jsonparse.h"
#include "json-ws.h"
#include <stdio.h>
#include <string.h>
#define DEBUG 0
#if DEBUG
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...)
#endif
#ifdef JSON_WS_CONF_CALLBACK_PROTO
#define CALLBACK_PROTO JSON_WS_CONF_CALLBACK_PROTO
#else
#define CALLBACK_PROTO "http"
#endif /* JSON_WS_CONF_CALLBACK_PROTO */
#ifdef JSON_WS_CONF_CALLBACK_PORT
#define CALLBACK_PORT JSON_WS_CONF_CALLBACK_PORT
#else
#define CALLBACK_PORT 8080;
#endif /* JSON_WS_CONF_CALLBACK_PORT */
/* Predefined startup-send interval */
#ifdef JSON_WS_CONF_CALLBACK_INTERVAL
#define SEND_INTERVAL JSON_WS_CONF_CALLBACK_INTERVAL
#else
#define SEND_INTERVAL 120
#endif
static const char http_content_type_json[] = "application/json";
/* Maximum 40 chars in host name?: 5 x 8 */
static char callback_host[40] = "[aaaa::1]";
static uint16_t callback_port = CALLBACK_PORT;
static uint16_t callback_interval = SEND_INTERVAL;
static char callback_path[80] = "/debug/";
static char callback_appdata[80] = "";
static char callback_proto[8] = CALLBACK_PROTO;
static const char *callback_json_path = NULL;
static struct jsontree_object *tree;
static struct ctimer periodic_timer;
long json_time_offset = 0;
/* support for submitting to cosm */
#if WITH_COSM
extern struct jsontree_callback cosm_value_callback;
JSONTREE_OBJECT_EXT(cosm_tree,
JSONTREE_PAIR("current_value", &cosm_value_callback));
#endif /* WITH_COSM */
static void periodic(void *ptr);
/*---------------------------------------------------------------------------*/
static void
json_copy_string(struct jsonparse_state *parser, char *string, int len)
{
jsonparse_next(parser);
jsonparse_next(parser);
jsonparse_copy_value(parser, string, len);
}
/*---------------------------------------------------------------------------*/
static int
cfg_get(struct jsontree_context *js_ctx)
{
const char *path = jsontree_path_name(js_ctx, js_ctx->depth - 1);
if(strncmp(path, "host", 4) == 0) {
jsontree_write_string(js_ctx, callback_host);
} else if(strncmp(path, "port", 4) == 0) {
jsontree_write_int(js_ctx, callback_port);
} else if(strncmp(path, "interval", 8) == 0) {
jsontree_write_int(js_ctx, callback_interval);
} else if(strncmp(path, "path", 4) == 0) {
jsontree_write_string(js_ctx, callback_path);
} else if(strncmp(path, "appdata", 7) == 0) {
jsontree_write_string(js_ctx, callback_appdata[0] == '\0' ? "" : "***");
} else if(strncmp(path, "proto", 5) == 0) {
jsontree_write_string(js_ctx, callback_proto);
}
return 0;
}
static int
cfg_set(struct jsontree_context *js_ctx, struct jsonparse_state *parser)
{
int type;
int update = 0;
while((type = jsonparse_next(parser)) != 0) {
if(type == JSON_TYPE_PAIR_NAME) {
if(jsonparse_strcmp_value(parser, "host") == 0) {
json_copy_string(parser, callback_host, sizeof(callback_host));
update++;
} else if(jsonparse_strcmp_value(parser, "path") == 0) {
json_copy_string(parser, callback_path, sizeof(callback_path));
update++;
} else if(jsonparse_strcmp_value(parser, "appdata") == 0) {
json_copy_string(parser, callback_appdata, sizeof(callback_appdata));
update++;
} else if(jsonparse_strcmp_value(parser, "proto") == 0) {
json_copy_string(parser, callback_proto, sizeof(callback_proto));
update++;
} else if(jsonparse_strcmp_value(parser, "port") == 0) {
jsonparse_next(parser);
jsonparse_next(parser);
callback_port = jsonparse_get_value_as_int(parser);
if(callback_port == 0) {
callback_port = CALLBACK_PORT;
}
update++;
} else if(jsonparse_strcmp_value(parser, "interval") == 0) {
jsonparse_next(parser);
jsonparse_next(parser);
callback_interval = jsonparse_get_value_as_int(parser);
if(callback_interval == 0) {
callback_interval = SEND_INTERVAL;
}
update++;
}
}
}
if(update && callback_json_path != NULL) {
#if WITH_UDP
if(strncmp(callback_proto, "udp", 3) == 0) {
json_ws_udp_setup(callback_host, callback_port);
}
#endif
ctimer_set(&periodic_timer, CLOCK_SECOND * callback_interval,
periodic, NULL);
}
return 0;
}
static struct jsontree_callback cfg_callback =
JSONTREE_CALLBACK(cfg_get, cfg_set);
JSONTREE_OBJECT_EXT(json_subscribe_callback,
JSONTREE_PAIR("host", &cfg_callback),
JSONTREE_PAIR("port", &cfg_callback),
JSONTREE_PAIR("path", &cfg_callback),
JSONTREE_PAIR("appdata", &cfg_callback),
JSONTREE_PAIR("proto", &cfg_callback),
JSONTREE_PAIR("interval", &cfg_callback));
/*---------------------------------------------------------------------------*/
static int
time_get(struct jsontree_context *js_ctx)
{
/* unix time */
char buf[20];
unsigned long time = json_time_offset + clock_seconds();
snprintf(buf, 20, "%lu", time);
jsontree_write_atom(js_ctx, buf);
return 0;
}
static int
time_set(struct jsontree_context *js_ctx, struct jsonparse_state *parser)
{
int type;
unsigned long time;
while((type = jsonparse_next(parser)) != 0) {
if(type == JSON_TYPE_PAIR_NAME) {
if(jsonparse_strcmp_value(parser, "time") == 0) {
jsonparse_next(parser);
jsonparse_next(parser);
time = jsonparse_get_value_as_long(parser);
json_time_offset = time - clock_seconds();
}
}
}
return 0;
}
struct jsontree_callback json_time_callback =
JSONTREE_CALLBACK(time_get, time_set);
/*---------------------------------------------------------------------------*/
#if PLATFORM_HAS_LEDS
#include "dev/leds.h"
static int
ws_leds_get(struct jsontree_context *js_ctx)
{
char buf[4];
unsigned char leds = leds_get();
snprintf(buf, 4, "%u", leds);
jsontree_write_atom(js_ctx, buf);
return 0;
}
static int
ws_leds_set(struct jsontree_context *js_ctx, struct jsonparse_state *parser)
{
int type, old_leds, new_leds;
while((type = jsonparse_next(parser)) != 0) {
if(type == JSON_TYPE_PAIR_NAME) {
if(jsonparse_strcmp_value(parser, "leds") == 0) {
jsonparse_next(parser);
jsonparse_next(parser);
new_leds = jsonparse_get_value_as_int(parser);
old_leds = leds_get();
leds_on(~old_leds & new_leds);
leds_off(old_leds & ~new_leds);
}
}
}
return 0;
}
struct jsontree_callback json_leds_callback =
JSONTREE_CALLBACK(ws_leds_get, ws_leds_set);
#endif /* PLATFORM_HAS_LEDS */
/*---------------------------------------------------------------------------*/
static struct httpd_ws_state *json_putchar_context;
static int
json_putchar(int c)
{
if(json_putchar_context != NULL &&
json_putchar_context->outbuf_pos < HTTPD_OUTBUF_SIZE) {
json_putchar_context->outbuf[json_putchar_context->outbuf_pos++] = c;
return c;
}
return 0;
}
static int putchar_size = 0;
static int
json_putchar_count(int c)
{
putchar_size++;
return c;
}
/*---------------------------------------------------------------------------*/
static
PT_THREAD(send_values(struct httpd_ws_state *s))
{
json_putchar_context = s;
PSOCK_BEGIN(&s->sout);
s->json.putchar = json_putchar;
s->outbuf_pos = 0;
if(s->json.values[0] == NULL) {
/* Nothing to do */
} else if(s->request_type == HTTPD_WS_POST &&
s->state == HTTPD_WS_STATE_OUTPUT) {
/* Set value */
struct jsontree_value *v;
struct jsontree_callback *c;
while((v = jsontree_find_next(&s->json, JSON_TYPE_CALLBACK)) != NULL) {
c = (struct jsontree_callback *)v;
if(c->set != NULL) {
struct jsonparse_state js;
jsonparse_setup(&js, s->inputbuf, s->content_len);
c->set(&s->json, &js);
}
}
memcpy(s->outbuf, "{\"Status\":\"OK\"}", 15);
s->outbuf_pos = 15;
} else {
/* Get value */
while(jsontree_print_next(&s->json) && s->json.path <= s->json.depth) {
if(s->outbuf_pos >= UIP_TCP_MSS) {
SEND_STRING(&s->sout, s->outbuf, UIP_TCP_MSS);
s->outbuf_pos -= UIP_TCP_MSS;
if(s->outbuf_pos > 0) {
memcpy(s->outbuf, &s->outbuf[UIP_TCP_MSS], s->outbuf_pos);
}
}
}
}
if(s->outbuf_pos > 0) {
SEND_STRING(&s->sout, s->outbuf, s->outbuf_pos);
s->outbuf_pos = 0;
}
PSOCK_END(&s->sout);
}
/*---------------------------------------------------------------------------*/
struct jsontree_value *
find_json_path(struct jsontree_context *json, const char *path)
{
struct jsontree_value *v;
const char *start;
const char *end;
int len;
v = json->values[0];
start = path;
do {
end = strchr(start, '/');
if(end == start) {
break;
}
if(end != NULL) {
len = end - start;
end++;
} else {
len = strlen(start);
}
if(v->type != JSON_TYPE_OBJECT) {
v = NULL;
} else {
struct jsontree_object *o;
int i;
o = (struct jsontree_object *)v;
v = NULL;
for(i = 0; i < o->count; i++) {
if(strncmp(start, o->pairs[i].name, len) == 0) {
v = o->pairs[i].value;
json->index[json->depth] = i;
json->depth++;
json->values[json->depth] = v;
json->index[json->depth] = 0;
break;
}
}
}
start = end;
} while(end != NULL && *end != '\0' && v != NULL);
json->callback_state = 0;
return v;
}
/*---------------------------------------------------------------------------*/
static int
calculate_json_size(const char *path, struct jsontree_value *v)
{
/* check size of JSON expression */
struct jsontree_context json;
json.values[0] = (v == NULL) ? (struct jsontree_value *)tree : v;
jsontree_reset(&json);
if(path != NULL) {
find_json_path(&json, path);
}
json.path = json.depth;
json.putchar = json_putchar_count;
putchar_size = 0;
while(jsontree_print_next(&json) && json.path <= json.depth);
return putchar_size;
}
/*---------------------------------------------------------------------------*/
httpd_ws_script_t
httpd_ws_get_script(struct httpd_ws_state *s)
{
struct jsontree_value *v;
s->json.values[0] = v = (struct jsontree_value *)tree;
jsontree_reset(&s->json);
if(s->filename[1] == '\0') {
/* Default page: show full JSON tree. */
} else {
v = find_json_path(&s->json, &s->filename[1]);
}
if(v != NULL) {
s->json.path = s->json.depth;
s->content_type = http_content_type_json;
return send_values;
}
return NULL;
}
/*---------------------------------------------------------------------------*/
#if JSON_POST_EXTRA_HEADER || WITH_COSM
static int
output_headers(struct httpd_ws_state *s, char *buffer, int buffer_size,
int index)
{
if(index == 0) {
#ifdef JSON_POST_EXTRA_HEADER
return snprintf(buffer, buffer_size, "%s\r\n", JSON_POST_EXTRA_HEADER);
} else if(index == 1) {
#endif
#if WITH_COSM
if(strncmp(callback_proto, "cosm", 4) == 0 && callback_appdata[0] != '\0') {
return snprintf(buffer, buffer_size, "X-PachubeApiKey:%s\r\n",
callback_appdata);
}
#endif
}
return 0;
}
#endif /* JSON_POST_EXTRA_HEADER || WITH_COSM */
/*---------------------------------------------------------------------------*/
static void
periodic(void *ptr)
{
struct httpd_ws_state *s;
int callback_size;
if(callback_json_path != NULL && strlen(callback_host) > 2) {
ctimer_restart(&periodic_timer);
if(strncmp(callback_proto, "http", 4) == 0) {
callback_size = calculate_json_size(callback_json_path, NULL);
s = httpd_ws_request(HTTPD_WS_POST, callback_host, NULL, callback_port,
callback_path, http_content_type_json,
callback_size, send_values);
if(s != NULL) {
PRINTF("PERIODIC POST %s\n", callback_json_path);
#if JSON_POST_EXTRA_HEADER
s->output_extra_headers = output_headers;
#endif
s->json.values[0] = (struct jsontree_value *)tree;
jsontree_reset(&s->json);
find_json_path(&s->json, callback_json_path);
s->json.path = s->json.depth;
} else {
PRINTF("PERIODIC CALLBACK FAILED\n");
}
#if WITH_COSM
} else if(strncmp(callback_proto, "cosm", 4) == 0) {
callback_size = calculate_json_size(NULL, (struct jsontree_value *)
&cosm_tree);
/* printf("JSON Size:%d\n", callback_size); */
s = httpd_ws_request(HTTPD_WS_PUT, callback_host, "api.pachube.com",
callback_port, callback_path,
http_content_type_json, callback_size, send_values);
/* host = cosm host */
/* path => path to datastream / data point */
s->output_extra_headers = output_headers;
s->json.values[0] = (struct jsontree_value *)&cosm_tree;
jsontree_reset(&s->json);
s->json.path = 0;
PRINTF("PERIODIC cosm callback: %d\n", callback_size);
#endif /* WITH_COSM */
}
#if WITH_UDP
else {
callback_size = calculate_json_size(callback_json_path, NULL);
PRINTF("PERIODIC UDP size: %d\n", callback_size);
json_ws_udp_send(tree, callback_json_path);
}
#endif /* WITH_UDP */
} else {
printf("PERIODIC CALLBACK - nothing todo\n");
}
}
/*---------------------------------------------------------------------------*/
void
json_ws_init(struct jsontree_object *json)
{
PRINTF("JSON INIT (callback %s every %u seconds)\n",
CALLBACK_PROTO, SEND_INTERVAL);
tree = json;
ctimer_set(&periodic_timer, CLOCK_SECOND * SEND_INTERVAL, periodic, NULL);
process_start(&httpd_ws_process, NULL);
#if WITH_UDP
if(strncmp(callback_proto, "udp", 3) == 0) {
json_ws_udp_setup(callback_host, callback_port);
}
#endif /* WITH_UDP */
}
/*---------------------------------------------------------------------------*/
void
json_ws_set_callback(const char *path)
{
callback_json_path = path;
ctimer_restart(&periodic_timer);
}
/*---------------------------------------------------------------------------*/

View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2011-2012, 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
* JSON webservice util
* \author
* Niclas Finne <nfi@sics.se>
* Joakim Eriksson <joakime@sics.se>
* Joel Hoglund <joel@sics.se>
*/
#ifndef __JSON_WS_H__
#define __JSON_WS_H__
#include "jsontree.h"
void json_ws_init(struct jsontree_object *json);
void json_ws_set_callback(const char *json_path);
int json_ws_udp_setup(const char *host, uint16_t port);
extern struct jsontree_object json_subscribe_callback;
extern struct jsontree_callback json_time_callback;
#if PLATFORM_HAS_LEDS
extern struct jsontree_callback json_leds_callback;
#endif
extern struct jsontree_object cosm_tree;
#endif /* __JSON_WS_H__ */

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2012, 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.
*/
#ifndef __PROJECT_CONF_H__
#define __PROJECT_CONF_H__
#include "jsontree.h"
#define HTTPD_WS_CONF_USER_STATE struct jsontree_context json
/* #define JSON_WS_CONF_CALLBACK_PROTO "http" | "udp" | "cosm" */
#define JSON_WS_CONF_CALLBACK_PROTO "http"
#define JSON_WS_CONF_CALLBACK_PORT 80
#define JSON_WS_CONF_CALLBACK_INTERVAL 120
#undef NETSTACK_CONF_RDC
#define NETSTACK_CONF_RDC nullrdc_driver
/* #define NETSTACK_CONF_RDC contikimac_driver */
#define CONTIKIMAC_CONF_MAX_PHASE_NEIGHBORS 7
#undef NULLRDC_CONF_802154_AUTOACK
#define NULLRDC_CONF_802154_AUTOACK 1
/* Reduce code size */
#undef ENERGEST_CONF_ON
#define ENERGEST_CONF_ON 0
/* needs to be ~4 for fragmentation to work */
#undef QUEUEBUF_CONF_NUM
#define QUEUEBUF_CONF_NUM 4
#undef UIP_CONF_DS6_NBR_NBU
#define UIP_CONF_DS6_NBR_NBU 7
#undef UIP_CONF_DS6_ROUTE_NBU
#define UIP_CONF_DS6_ROUTE_NBU 7
#undef UIP_CONF_BUFFER_SIZE
#define UIP_CONF_BUFFER_SIZE 140
/* #undef UIP_CONF_RECEIVE_WINDOW */
/* #define UIP_CONF_RECEIVE_WINDOW 35 */
#undef WEBSERVER_CONF_INBUF_SIZE
#define WEBSERVER_CONF_INBUF_SIZE 200
#undef WEBSERVER_CONF_OUTBUF_SIZE
#define WEBSERVER_CONF_OUTBUF_SIZE (UIP_TCP_MSS + 20 + 80)
#undef WEBSERVER_CONF_CFS_CONNS
#define WEBSERVER_CONF_CFS_CONNS 3
#endif /* __PROJECT_CONF_H__ */

View File

@ -0,0 +1,30 @@
#!/usr/bin/python
# python set time code
import httplib,sys
# edit the key and feed parameters to match your COSM account and feed
key = "<your-key>"
feed = "<your-feed>"
cosmaddr = "[2001:470:1f10:333::2]"
print "JSON-WS COSM configuration utility\n Currently set to COSM feed: %s Key: '%s'" % (feed, key)
if len(sys.argv) > 2:
host = sys.argv[1]
stream = sys.argv[2]
else:
print "Usage: ", sys.argv[0], "<host> <feed-id>"
sys.exit()
print "Setting cosm config at:", host, " feed:", feed, " stream:",stream
conn = httplib.HTTPConnection(host)
# NAT64 address =
#conn.request("POST","", '{"host":"[2001:778:0:ffff:64:0:d834:e97a]","port":80,"path":"/v2/feeds/55180/datastreams/1","interval":120}')
requestData = '{"host":"%s","port":80,"path":"/v2/feeds/%s/datastreams/%s","appdata":"%s","interval":120,"proto":"cosm"}' % (cosmaddr, feed, stream, key)
print "Posting to node: ", requestData
conn.request("POST","", requestData)
res = conn.getresponse()
print res.status, res.reason

View File

@ -0,0 +1,130 @@
/*
* Copyright (c) 2011-2012, 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
* Websense for Sky mote
* \author
* Niclas Finne <nfi@sics.se>
* Joakim Eriksson <joakime@sics.se>
* Joel Hoglund <joel@sics.se>
*/
#include "contiki.h"
#include "dev/leds.h"
#include "dev/sht11-sensor.h"
#include "jsontree.h"
#include "json-ws.h"
#include <stdio.h>
#define DEBUG 0
#if DEBUG
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...)
#endif
PROCESS(websense_process, "Websense (sky)");
AUTOSTART_PROCESSES(&websense_process);
/*---------------------------------------------------------------------------*/
static CC_INLINE int
get_temp(void)
{
return ((sht11_sensor.value(SHT11_SENSOR_TEMP) / 10) - 396) / 10;
}
/*---------------------------------------------------------------------------*/
static int
output_temp(struct jsontree_context *path)
{
char buf[5];
snprintf(buf, sizeof(buf), "%3d", get_temp());
jsontree_write_atom(path, buf);
return 0;
}
static struct jsontree_callback temp_sensor_callback =
JSONTREE_CALLBACK(output_temp, NULL);
/*---------------------------------------------------------------------------*/
static struct jsontree_string desc = JSONTREE_STRING("Tmote Sky");
static struct jsontree_string temp_unit = JSONTREE_STRING("Celcius");
JSONTREE_OBJECT(node_tree,
JSONTREE_PAIR("node-type", &desc),
JSONTREE_PAIR("time", &json_time_callback));
JSONTREE_OBJECT(temp_sensor_tree,
JSONTREE_PAIR("unit", &temp_unit),
JSONTREE_PAIR("value", &temp_sensor_callback));
JSONTREE_OBJECT(rsc_tree,
JSONTREE_PAIR("temperature", &temp_sensor_tree),
JSONTREE_PAIR("leds", &json_leds_callback));
/* complete node tree */
JSONTREE_OBJECT(tree,
JSONTREE_PAIR("node", &node_tree),
JSONTREE_PAIR("rsc", &rsc_tree),
JSONTREE_PAIR("cfg", &json_subscribe_callback));
/*---------------------------------------------------------------------------*/
/* for cosm plugin */
#if WITH_COSM
/* set COSM value callback to be the temp sensor */
struct jsontree_callback cosm_value_callback =
JSONTREE_CALLBACK(output_temp, NULL);
#endif
PROCESS_THREAD(websense_process, ev, data)
{
static struct etimer timer;
PROCESS_BEGIN();
json_ws_init(&tree);
SENSORS_ACTIVATE(sht11_sensor);
json_ws_set_callback("rsc");
while(1) {
/* Alive indication with the LED */
etimer_set(&timer, CLOCK_SECOND * 5);
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&timer));
leds_on(LEDS_RED);
etimer_set(&timer, CLOCK_SECOND / 8);
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&timer));
leds_off(LEDS_RED);
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/

View File

@ -0,0 +1,136 @@
/*
* Copyright (c) 2011-2012, 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
* Websense for Z1 mote
* \author
* Niclas Finne <nfi@sics.se>
* Joakim Eriksson <joakime@sics.se>
* Joel Hoglund <joel@sics.se>
*/
#include "contiki.h"
#include "dev/leds.h"
#include "dev/tmp102.h"
#include "dev/z1-phidgets.h"
#include "lib/sensors.h"
#include "jsontree.h"
#include "json-ws.h"
/* It seems like there normally is an offset of some degrees for the tmp102 */
#define TMP102_OFFSET -150
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...)
#endif
PROCESS(websense_process, "Websense (z1)");
AUTOSTART_PROCESSES(&websense_process);
static int
output_sensor(struct jsontree_context *path)
{
char buf[10];
int tmp;
int tmp2;
tmp = tmp102_read_temp_x100();
tmp2 = tmp - TMP102_OFFSET;
tmp = tmp2 / 100;
snprintf(buf, sizeof(buf), "%2d.%02d", tmp, tmp2 - (100 * tmp));
jsontree_write_atom(path, buf);
return 0;
}
static struct jsontree_callback sensor_callback =
JSONTREE_CALLBACK(output_sensor, NULL);
/*---------------------------------------------------------------------------*/
static struct jsontree_string desc = JSONTREE_STRING("Zolertia Z1");
static struct jsontree_string unit = JSONTREE_STRING("Celcius");
JSONTREE_OBJECT(node_tree,
JSONTREE_PAIR("node-type", &desc),
JSONTREE_PAIR("time", &json_time_callback));
JSONTREE_OBJECT(sensor_tree,
JSONTREE_PAIR("unit", &unit),
JSONTREE_PAIR("value", &sensor_callback));
JSONTREE_OBJECT(rsc_tree,
JSONTREE_PAIR("temperature", &sensor_tree),
JSONTREE_PAIR("leds", &json_leds_callback));
/* complete node tree */
JSONTREE_OBJECT(tree,
JSONTREE_PAIR("node", &node_tree),
JSONTREE_PAIR("rsc", &rsc_tree),
JSONTREE_PAIR("cfg", &json_subscribe_callback));
/*---------------------------------------------------------------------------*/
/* for cosm plugin */
#if WITH_COSM
/* set COSM value callback to be the temp sensor */
struct jsontree_callback cosm_value_callback =
JSONTREE_CALLBACK(output_sensor, NULL);
#endif
PROCESS_THREAD(websense_process, ev, data)
{
static struct etimer timer;
PROCESS_BEGIN();
json_ws_init(&tree);
tmp102_init();
json_ws_set_callback("rsc");
while(1) {
/* Alive indication with the LED */
etimer_set(&timer, CLOCK_SECOND * 5);
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&timer));
leds_on(LEDS_RED);
etimer_set(&timer, CLOCK_SECOND / 8);
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&timer));
leds_off(LEDS_RED);
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/