280 lines
8.7 KiB
C
280 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(¶meters, 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();
|
|
}
|