hostmote_conf.c from EmStar at Krugle
Show hostmote_conf.c syntax highlighted
/* ex: set tabstop=8 expandtab shiftwidth=2 softtabstop=2: */
/*
*
* Copyright (c) 2003 The Regents of the University of California. All
* rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Neither the name of the University 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 REGENTS 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 REGENTS 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.
*
*/
/*
* basic configuration messages for host-mote protocol: reset, etc.
*
* $Id: hostmote_conf.c,v 1.40 2005/04/15 21:15:19 thanos Exp $
*/
char *hostmote_conf_id = "$Id: hostmote_conf.c,v 1.40 2005/04/15 21:15:19 thanos Exp $";
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "hostmote_i.h"
#define MOTE_STATUS_TIMEOUT 5000
/****************************************************************/
static void convert_mac_int_to_string(uint8_t type, char *name);
static void convert_status_to_report(mote_conf_hdr_t *status,
mote_report *report);
/* Callback when the timeout expires from when we send a stat request
* and when we expect to receive a response. */
static int stat_timeout_handler(void *data, int interval, g_event_t *ev)
{
mote_state_t *m = (mote_state_t *) data;
if (++m->not_responding > m->next_complaint) {
elog(LOG_WARNING, "%s: Mote not responding, still trying...", MOTE(m));
m->next_complaint += 1 + i_min(m->next_complaint, 100);
}
mote_configure(m, 1);
return TIMER_DONE;
}
/*
* Send a message to the mote asking it to send us status
*/
void mote_request_status(mote_state_t *m)
{
hostmote_header hdr={0};
elog(LOG_DEBUG(0), "%s: ***** Requesting mote status", MOTE(m));
m->last_status_request = time(0);
HOSTMOTE_SET_OP(HOSTMOTE_CONF, CONF_STAT, &hdr);
if (mote_serial_send(m, &hdr, 0) < 0) {
elog(LOG_WARNING, "%s: couldn't send status request to mote: %m", MOTE(m));
}
/* set timeout in case we don't hear back */
g_event_destroy(m->stat_timeout);
g_timer_add(MOTE_STATUS_TIMEOUT, stat_timeout_handler, m, NULL, &m->stat_timeout);
}
/*
* Send a message to the mote asking it to send us status
*/
#define COPY_AND_CHECK(field, flag) \
do { if (m->request_set_##field) { \
if (request.field != m->requested_conf.field) { \
request.field = m->requested_conf.field; \
request.set_flags |= flag; \
} } } while(0)
void mote_configure(mote_state_t *m, int from_user)
{
hostmote_header hdr={0};
/* construct the status request */
// mote_conf_hdr_t request = m->status;
mote_conf_request_t request;
request.set_flags = 0;
request.saddr = m->report.saddr;
request.pot = m->report.pot;
request.lpl_tx = m->report.lpl_tx;
request.lpl_rx = m->report.lpl_rx;
/* copy over */
COPY_AND_CHECK(saddr, CONF_SET_SADDR);
COPY_AND_CHECK(pot, CONF_SET_POT);
// this can be used with smac as well. smac will return the value
// without doing anything
COPY_AND_CHECK(lpl_tx, CONF_SET_LPL_TX_MODE);
COPY_AND_CHECK(lpl_rx, CONF_SET_LPL_RX_MODE);
if (request.set_flags || from_user) {
buf_t *buf = buf_new();
if (!from_user) {
elog(LOG_WARNING, "Mote [%d] reported inconsistent info..."
" reconfiguring!", m->index);
}
elog(LOG_DEBUG(0), "%s: ***** Sending mote configuration", MOTE(m));
HOSTMOTE_SET_OP(HOSTMOTE_CONF, CONF_CONF, &hdr);
/* construct the mote message: first the header, then conf struct */
bufcpy(buf, &hdr, sizeof(hdr));
bufcpy(buf, &request, sizeof(request));
if (mote_serial_send(m, (hostmote_header *) buf->buf,
sizeof(request)) < 0) {
elog(LOG_WARNING, "%s: couldn't send new configuration to mote: %m",
MOTE(m));
}
buf_free(buf);
/* set timeout in case we don't hear back */
g_event_destroy(m->stat_timeout);
g_timer_add(MOTE_STATUS_TIMEOUT, stat_timeout_handler, m, NULL, &m->stat_timeout);
}
else {
elog(LOG_DEBUG(0), "%s: ***** Skipping mote configuration", MOTE(m));
}
}
/*
* Send a reset message to the mote
*/
void mote_reset(mote_state_t *m, uint8_t type)
{
hostmote_header hdr={0};
/* be sure we are awake */
//sync_start(1);
if (type!=SOFT_RESET && type!=HARD_RESET) {
elog(LOG_ERR, "Unknown RESET type %d", type);
return;
}
elog(LOG_DEBUG(0), "%s: ***** RESETTING MOTE (type=%d)", MOTE(m), type);
HOSTMOTE_SET_OP(HOSTMOTE_RST, 0, &hdr);
hdr.subop=type;
if (mote_serial_send(m, &hdr, 0) < 0) {
elog(LOG_ERR, "%s: can't reset mote: %m", MOTE(m));
}
m->report.pcCrcErrors=0;
/* request status information from the mote */
mote_request_status(m);
}
/*
* Send a sleep message to the mote
*/
void mote_sleep(mote_state_t *m)
{
m->asleep = 1;
elog(LOG_WARNING, "%s: not *really* sleeping the mote", MOTE(m));
#if 0
hostmote_header hdr;
elog(LOG_DEBUG(0), "%s: ***** SLEEPING MOTE", MOTE(m));
HOSTMOTE_SET_OP(HOSTMOTE_SLEEP, 0, &hdr);
if (mote_serial_send(m, &hdr, 0) < 0) {
elog(LOG_WARNING, "%s: couldn't sleep mote: %m", MOTE(m));
} else {
m->asleep = 1;
}
#endif
}
/*
* This function is called when a CONF message arrives from the mote.
*/
void mote_conf_input_handler(mote_state_t *m, hostmote_header *hdr, int datalen)
{
mote_conf_hdr_t *mc = (mote_conf_hdr_t *)(hdr->data);
if (m->status==NULL) {
elog(LOG_ERR, "NULL status pointer!");
// perhaps we should exit here
return;
}
if (hdr->opnum != HOSTMOTE_CONF) {
elog(LOG_ERR, "Got a non-CONF message (%d) but conf handler got to run?!",
hdr->opnum);
return;
}
if (HOSTMOTE_DATALEN(hdr)==0) {
elog(LOG_ERR, "Got a 0-length conf packet!");
return;
}
// first let's make sure our pointer has the type set
if (m->status->type == 0) {
// type hasn't been initialized yet. we set it now
m->status->type = mc->type;
switch (mc->type) {
case BMAC_CONF:
elog(LOG_NOTICE, "Mote [%d] says it's using BMAC", m->index);
break;
case SMAC_CONF:
elog(LOG_NOTICE, "Mote [%d] says it's using SMAC", m->index);
break;
default:
elog(LOG_ERR, "Mote [%d] sent invalid conf type %d", m->index,
mc->type);
return;
break;
}
}
// now let's make sure the type hasn't changed since the time we set it
// this could happen if someone swapped motes...
if (m->status->type != mc->type) {
elog(LOG_WARNING, "Warning: mote conf type has changed!"
" (got %d, had %d)", mc->type, m->status->type);
// not sure what else we're supposed to do here
m->status->type = mc->type;
}
if (datalen > m->alloc_conf_length) {
elog(LOG_WARNING, "Warning: datalen is greater than conf"
" allocated length (%d > %d)", datalen, m->alloc_conf_length);
m->alloc_conf_length+=datalen; //increase by datalen
// realloc
m->status = realloc(m->status, m->alloc_conf_length);
}
switch (HOSTMOTE_SUBOP(hdr)) {
case CONF_SYNC:
elog(LOG_WARNING, "%s: got unsupported CONF_SYNC message", MOTE(m));
// mote_handle_sync_message(m, conf);
/* fall through */
// why fall through? it should break!
break;
case CONF_STAT:
elog(LOG_DEBUG(0), "%s: **** Got STAT message", MOTE(m));
memcpy(m->status, mc, datalen);
// convert status to report here
// we're using the values of report for other things so this is critical
convert_status_to_report(m->status, &m->report);
mote_configure(m, 0);
g_status_dev_notify(m->status_ev);
g_event_destroy(m->stat_timeout);
if (m->not_responding) {
m->not_responding = 0;
m->next_complaint = 0;
elog(LOG_WARNING, "%s: Mote OK", MOTE(m));
}
break;
}
}
/*
* when someone tries to open the status device, initiate a mote
* status request. Return 0, meaning don't allow the read to complete
* until the status comes back.
*/
static int mote_status_open(status_context_t *info)
{
mote_state_t *m = (mote_state_t *) sd_data(info);
mote_request_status(m);
return 0;
}
/*
* Generate human-readable mote status when someone tries to cat
* /dev/mote/status
*/
static int mote_status_printable(status_context_t *info, buf_t *buf)
{
char name[128]={0};
mote_state_t *m = (mote_state_t *) sd_data(info);
convert_status_to_report(m->status, &m->report);
convert_mac_int_to_string(m->status->type, name);
switch (m->status->type) {
case BMAC_CONF:
bufprintf(buf,
"Current Mote Status:\n"
" MAC type= %s\n"
" Version number= [mote:%03d, pc:%03d]\n"
" if id= %04x [%6d] (%d.%d)\n"
" MTU= %03d\n"
" pot= %u\n"
" LPL TX mode= %u\n"
" LPL RX mode= %u\n"
" Bytes sent= %u\n"
" Packets sent= %u\n"
" Bytes rcvd= %u\n"
" Packets rcvd= %u\n"
" Packet CRC errors= %u\n"
" Packet Drops= %u\n"
" Packet TX errors= %u\n"
" Packets queued= %d\n"
" Max queue size= %d\n"
" PC->Mote CRC errors= %u\n"
" Mote->PC CRC errors= %u\n",
name,
m->report.version,
HOSTMOTE_CURRENT_VERSION,
m->report.saddr,
m->report.saddr,
(m->report.saddr & 0xff00) >> 8,
(m->report.saddr & 0xff),
m->report.mtu,
m->report.pot,
m->report.lpl_tx,
m->report.lpl_rx,
m->report.txBytes,
m->report.txPkts,
m->report.rxBytes,
m->report.rxPkts,
m->report.pktCrcErrors,
m->report.rxDrops,
m->report.txErrors,
m->report.pkts_queued,
m->report.max_queue_size,
m->report.serialCrcErrors,
m->report.pcCrcErrors);
break;
case SMAC_CONF:
bufprintf(buf,
"Current Mote Status:\n"
" MAC type= %s\n"
" Version number = [mote:%03d, pc:%03d]\n"
" if id= %04x [%6d] (%d.%d)\n"
" MTU= %03d\n"
" fault count= %02x\n"
" pot= %u\n"
" TX packets= %ud\n"
" TX errors= %ud\n"
" RX packets= %ud\n" /* arg 15 */
" RX drops= %ud\n"
" MAC TX errors= %ud\n"
" Sleep RX errors= %ud\n"
" Length errors= %ud\n"
" Pkt CRC errors= %ud\n" /* arg 20 */
" Pkts queued= %d\n"
" Max queue size= %d\n"
" PC->Mote CRC errors= %ud\n"
" Mote->PC CRC errors= %ud\n"
" reTX packets= %ud\n" /* arg 25 */
" Ctrl packets= %ud\n"
" Neighbors= %d\n"
" Schedules= %d\n"
" MAC state= %d\n"
" Radio state= %d\n", /* arg 30 */
name,
m->report.version,
HOSTMOTE_CURRENT_VERSION,
m->report.saddr,
m->report.saddr,
(m->report.saddr & 0xff00) >> 8,
(m->report.saddr & 0xff),
m->report.mtu,
m->report.reset_count,
m->report.pot,
m->report.txPkts,
m->report.txErrors,
m->report.rxPkts,
m->report.rxDrops,
m->report.macTxErrors,
m->report.sleepErrors,
m->report.lenErrors,
m->report.pktCrcErrors,
m->report.pkts_queued,
m->report.max_queue_size,
m->report.serialCrcErrors,
m->report.pcCrcErrors,
m->report.retx,
m->report.ctrlPkts,
m->report.numNeighb,
m->report.numSched,
m->report.macState,
m->report.radioState);
break;
default:
elog(LOG_ERR, "Unknown conf type %d", m->status->type);
break;
}
if (m->asleep)
bufprintf(buf, " Currently asleep\n");
return STATUS_MSG_COMPLETE;
}
/*
* Return the most recent mote status struct when someone tries to do
* a binary read of it
*/
static int mote_status_binary(status_context_t *info, buf_t *buf)
{
mote_state_t *m = (mote_state_t *) sd_data(info);
convert_status_to_report(m->status, &m->report);
bufcpy(buf, &m->report, sizeof(m->report));
return STATUS_MSG_COMPLETE;
}
/******* Command Interface ********/
/*
* command interface
*/
char *mote_command_usage(void *data)
{
return
"Mote command interface:\n"
" address=0xXXXX: Set address to specified hex value\n"
" address=DDDDD: Set address to specified decimal value\n"
" pot=DDD: Set mote power\n"
" pwr=0xXX: Set radio power for chipcon radio (mica2+)\n"
" lpl_tx=D: Set LPL TX mode\n"
" lpl_rx=D: Set LPL RX mode\n"
" lpl=D: Set LPL TX and RX mode\n"
" soft_reset: Resets mote state but doesn't reboot mote\n"
" hard_reset: Reboots mote\n"
"\n";
}
/*
* argument processing macros
*/
#define CASE(str) \
if ((strncmp(command, (str), strlen(str)) == 0) && \
(args = command + strlen(str)))
#define NUMERIC_ARG(field, str, flag) \
do { \
uint tmp; \
if (strncmp(args, "0x", 2) == 0) { \
if (1 != sscanf(args+2, "%x", &tmp)) { \
fprintf(stderr, "Invalid %s %s\n", str, args); \
break; \
} \
} \
else { \
if (1 != sscanf(args, "%u", &tmp)) { \
fprintf(stderr, "Invalid %s %s\n", str, args); \
break; \
} \
} \
m->requested_conf.field = tmp; \
m->request_set_##field = 1; \
} while (0)
static int mote_command_handler(char *command, size_t size, void *data)
{
mote_state_t *m = (mote_state_t *) data;
char *args = NULL;
int reset = -1;
int sleep = 0;
int wake = 0;
// parse command
while (command && *command) {
args = NULL;
CASE("address=") {
NUMERIC_ARG(saddr, "address", CONF_SET_SADDR);
}
CASE("pot=") {
NUMERIC_ARG(pot, "pot", CONF_SET_POT);
}
CASE("pwr=") {
NUMERIC_ARG(pot, "pwr", CONF_SET_PWR);
}
CASE("lpl_tx=") {
NUMERIC_ARG(lpl_tx, "lpl_tx", CONF_SET_LPL_TX_MODE);
}
CASE("lpl_rx=") {
NUMERIC_ARG(lpl_rx, "lpl_rx", CONF_SET_LPL_RX_MODE);
}
CASE("lpl=") {
NUMERIC_ARG(lpl_tx, "lpl", CONF_SET_LPL_TX_MODE);
NUMERIC_ARG(lpl_rx, "lpl", CONF_SET_LPL_RX_MODE);
}
CASE("soft_reset") {
reset=SOFT_RESET;
}
CASE("hard_reset") {
reset=HARD_RESET;
}
command = strpbrk(command, ":");
if (command) command++;
}
if (wake) {
//sync_start(1);
}
if (reset>-1) {
mote_reset(m, reset);
} else {
mote_configure(m, 1);
}
if (sleep) {
mote_sleep(m);
}
return EVENT_RENEW;
}
/*
* Initialize the configuration-related pieces of hostmoted
*/
void mote_conf_init(mote_state_t *m)
{
/* Options for the mote status device */
status_dev_opts_t s_opts = {
device: {
device_info: m,
devname: mote_name(m->index, MOTE_STATUS_DEV)
},
open: mote_status_open,
printable: mote_status_printable,
binary: mote_status_binary,
no_read_on_open: 1
};
/* Options for the mote command device */
cmd_dev_opts_t c_opts = {
device: {
device_info: m,
devname: mote_name(m->index, MOTE_COMMAND_DEV)
},
command: mote_command_handler,
usage: mote_command_usage
};
/* Create the status device */
if (g_status_dev(&s_opts, &m->status_ev) < 0) {
elog(LOG_CRIT, "can't create status dev %s: %m", s_opts.device.devname);
exit(1);
}
/* Create the command device */
if (g_command_dev(&c_opts, &m->command_ev) < 0) {
elog(LOG_CRIT, "can't create command dev %s: %m", c_opts.device.devname);
exit(1);
}
}
static void convert_status_to_report(mote_conf_hdr_t *status,
mote_report *report)
{
// declare both pointers, we have stack space
mote_bmac_conf_t *bmac_conf;
mote_smac_conf_t *smac_conf;
if (status==NULL || report==NULL) {
elog(LOG_ERR, "NULL pointer!\n");
return;
}
switch (status->type) {
case BMAC_CONF:
bmac_conf = (mote_bmac_conf_t *)status->data;
report->conf_type = status->type;
report->mtu=bmac_conf->mtu;
report->version=bmac_conf->version;
report->saddr=bmac_conf->saddr;
report->pot=bmac_conf->pot;
report->lpl_tx=bmac_conf->lpl_tx;
report->lpl_rx=bmac_conf->lpl_rx;
report->serialCrcErrors=bmac_conf->serialCrcErrors;
report->txPkts=bmac_conf->txPkts;
report->rxPkts=bmac_conf->rxPkts;
report->txErrors=bmac_conf->txErrors;
report->pktCrcErrors=bmac_conf->pktCrcErrors;
report->txBytes=bmac_conf->txBytes;
report->rxBytes=bmac_conf->rxBytes;
report->rxDrops=bmac_conf->rxDrops;
report->pkts_queued=bmac_conf->pkts_queued;
report->max_queue_size=bmac_conf->max_queue_size;
break;
case SMAC_CONF:
smac_conf = (mote_smac_conf_t *)status->data;
report->conf_type = status->type;
report->mtu=smac_conf->mtu;
report->version=smac_conf->version;
report->saddr=smac_conf->saddr;
report->pot=smac_conf->pot;
report->lpl_tx=smac_conf->lpl_tx;
report->lpl_rx=smac_conf->lpl_rx;
report->serialCrcErrors=smac_conf->serialCrcErrors;
report->txPkts=smac_conf->txPkts;
report->rxPkts=smac_conf->rxPkts;
report->txErrors=smac_conf->txErrors;
report->reset_count=smac_conf->fault;
report->rxDrops=smac_conf->rxDrops;
report->lenErrors=smac_conf->lenErrors;
report->pktCrcErrors=smac_conf->crcErrors;
report->retx=smac_conf->retx;
report->ctrlPkts=smac_conf->ctrlPkts;
report->numNeighb=smac_conf->numNeighb;
report->numSched=smac_conf->numSched;
report->macState=smac_conf->macState;
report->radioState=smac_conf->radioState;
report->sleepErrors=smac_conf->sleepErrors;
report->macTxErrors=smac_conf->macTxErrors;
report->pkts_queued=smac_conf->pkts_queued;
report->max_queue_size=smac_conf->max_queue_size;
break;
default:
elog(LOG_ERR, "Unkwown conf type %d", status->type);
break;
}
}
static void convert_mac_int_to_string(uint8_t type, char *name)
{
if (name==NULL) {
elog(LOG_ERR, "NULL name pointer");
return;
}
switch (type) {
case BMAC_CONF:
sprintf(name, "B-MAC");
break;
case SMAC_CONF:
sprintf(name, "S-MAC");
break;
default:
elog(LOG_ERR, "Invalid type %d", type);
sprintf(name, "INVALID");
break;
}
}
See more files for this project here