contiki/examples/sensinode/cc2431-location-engine/blind-node.c

281 lines
8.7 KiB
C

/*
* Copyright (c) 2010, Loughborough University - Computer Science
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*/
/**
* \file
* Example demonstrating the cc2431 location engine.
*
* This file contains code for the blind node. The blind node must be
* equipped with a cc2431 SoC (as opposed to reference nodes which
* don't need to have a Loc. Eng.)
*
* The blind node receives co-ordinates of reference nodes over
* broadcast rime. Once it has enough data (3+ reference nodes), it
* will calculate its own position.
*
* We calculate with all potential values for parameter 'n' to
* demonstrate how 'n' influences the result of the calculation.
*
* Optionally, send the result of the calculation to a collection node
*
* More information on the cc2431 Location Engine can be found in:
* - cc2431 Datasheet
* - Texas Instruments Application Note 42
*
* \author
* George Oikonomou - <oikonomou@users.sourceforge.net>
*/
#include "contiki.h"
#include "net/rime/rime.h"
#include "cc2431_loc_eng.h"
#include "cc2430_sfr.h"
#include <string.h>
#include <stdio.h>
#define MAX_REF_NODES 16 /* Do not change */
#define SAMPLE_RSSI 100 /* Used for testing */
#define SAMPLE_ALPHA 101
static struct meas_params parameters;
static struct refcoords ref_coords[MAX_REF_NODES];
/* Store our current location here to be transmitted to a collector node */
static uint8_t coords[2];
/*---------------------------------------------------------------------------*/
PROCESS(blindnode_bcast_rec, "Blind Node");
AUTOSTART_PROCESSES(&blindnode_bcast_rec);
/*---------------------------------------------------------------------------*/
/*
* This handles the calculation cycle. Returns non-zero on error, 0 on success.
*
* When we move this outside the example, we will perhaps want to pass
* struct refcoords *, struct meas_params *
* instead of exposing our own data structures. If this happens, we will need
* to add checks to our code to detect non-sane values
*/
static uint8_t
calculate()
{
static int j, x;
uint8_t valid_rssi = 0;
/* Turn on the Engine */
LOCENG = LOCENG_EN;
while(!(LOCENG & LOCENG_EN));
/* Reference Coordinate Load Stage */
LOCENG |= LOCENG_REFLD;
while(!(LOCENG & LOCENG_REFLD));
for(j = 0; j < MAX_REF_NODES; j++) {
/* Write the Reference Node x,y into the engine */
REFCOORD = ref_coords[j].x;
REFCOORD = ref_coords[j].y;
}
/* Reference Coordinate Load Stage Done. Proceed with measured params */
LOCENG &= ~LOCENG_REFLD;
LOCENG |= LOCENG_PARLD;
/* Load Parameters */
MEASPARM = parameters.alpha;
MEASPARM = parameters.n;
MEASPARM = parameters.x_min;
MEASPARM = parameters.x_delta;
MEASPARM = parameters.y_min;
MEASPARM = parameters.y_delta;
/* Load Neighbor RSSIs */
for(j = 0; j < MAX_REF_NODES; j++) {
if(parameters.rssi[j] != 0) {
/* Range-check for the RSSI here, can only be in [-95 dBm , -40 dBm]
* so we only accept 80 <= rssi <= 190*/
if(parameters.rssi[j] >= 80 && parameters.rssi[j] <= 190) {
valid_rssi++;
}
}
/* Write the value, even if it's zero */
MEASPARM = parameters.rssi[j];
}
/* Done with measured parameters too */
LOCENG &= ~LOCENG_PARLD;
/* Only Calculate if we have 3+ reference nodes (non-zero RSSIs) */
if(valid_rssi >= 3) {
LOCENG |= LOCENG_RUN;
} else {
LOCENG = 0;
printf("some error\n");
return 1;
}
/* Block on the calculation, between 50us and 13ms */
while(!(LOCENG & LOCENG_DONE));
/*
* LOCX contains an offset. Remove it to obtain our actual X value.
* cc2431 datasheet, section 2.1.3
*/
x = (LOCX - parameters.x_min + 1) % (parameters.x_delta + 1)
+ parameters.x_min;
coords[0] = x;
coords[1] = LOCY; /* No offset here */
printf("n=%2u: X=%3u, Y=%3u\n", parameters.n, LOCX, LOCY);
/* Turn it off */
LOCENG = 0;
return 0;
}
/*---------------------------------------------------------------------------*/
/*
* We receive X, Y from reference nodes.
* We store this in location J of the ref_coords array, where J is the LSB
* of the reference node's rime address. So we can only accept data from nodes
* with rime address ending in [0 , 15]
*/
static void
broadcast_recv(struct broadcast_conn *c, const linkaddr_t *from)
{
packetbuf_attr_t rssi; /* Careful here, this is uint16_t */
if(from->u8[1] < MAX_REF_NODES) {
memset(&ref_coords[from->u8[1] - 1], 0, sizeof(struct refcoords));
/* Obtain incoming message's RSSI from contiki */
rssi = packetbuf_attr(PACKETBUF_ATTR_RSSI);
/* Convert RSSI to the loc. eng. format */
parameters.rssi[from->u8[1] - 1] = (-2 * rssi);
/* Raw dump the packetbuf into the ref_coords struct */
memcpy(&ref_coords[from->u8[1] - 1], packetbuf_dataptr(),
2 * sizeof(uint8_t));
}
return;
}
/*
* Imaginary nodes to test functionality
* All nodes at 1 meter distance, rssi = -40 (80)
* Since the rssi at 1 meter = -40 (A), the blind node should think it's at
* 5,5
*/
/*---------------------------------------------------------------------------*/
static void
set_imaginary_ref_nodes()
{
ref_coords[0].x = 1;
ref_coords[0].y = 5;
parameters.rssi[0] = SAMPLE_RSSI;
ref_coords[1].x = 5;
ref_coords[1].y = 1;
parameters.rssi[1] = SAMPLE_RSSI;
ref_coords[2].x = 5;
ref_coords[2].y = 9;
parameters.rssi[2] = SAMPLE_RSSI;
ref_coords[3].x = 9;
ref_coords[3].y = 5;
parameters.rssi[3] = SAMPLE_RSSI;
}
/*---------------------------------------------------------------------------*/
static const struct broadcast_callbacks broadcast_call = { broadcast_recv };
static struct broadcast_conn broadcast;
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(blindnode_bcast_rec, ev, data)
{
static struct etimer et;
static uint8_t n;
int i;
PROCESS_EXITHANDLER(broadcast_close(&broadcast));
PROCESS_BEGIN();
printf("Reading Chip ID: 0x%02x\n", CHIPID);
/* Read our chip ID. If we are not cc2431, bail out */
if(CHIPID != CC2431_CHIP_ID) {
printf("Hardware does not have a location engine. Exiting.\n");
PROCESS_EXIT();
}
/* OK, we are cc2431. Do stuff */
n = 0;
/* Initalise our structs and parameters */
memset(ref_coords, 0, sizeof(struct refcoords) * MAX_REF_NODES);
memset(&parameters, 0, sizeof(struct meas_params));
/*
* Just hard-coding measurement parameters here.
* Ideally, this should be part of a calibration mechanism
*/
parameters.alpha = SAMPLE_ALPHA;
parameters.x_min = 0;
parameters.x_delta = 255;
parameters.y_min = 0;
parameters.y_delta = 255;
set_imaginary_ref_nodes();
broadcast_open(&broadcast, 129, &broadcast_call);
while(1) {
etimer_set(&et, CLOCK_SECOND);
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
/*
* With the hard-coded parameters and locations, we will calculate
* for all possible values of n [0 , 31]
*/
parameters.n = n;
calculate();
n++;
if(n == 32) {
n = 0;
}
/* Send our calculated location to some monitoring node */
packetbuf_copyfrom(&coords, 2 * sizeof(uint8_t));
broadcast_send(&broadcast);
}
PROCESS_END();
}