tosnic_status.c from EmStar at Krugle
Show tosnic_status.c syntax highlighted
/*
*
* Copyright (c) 2005 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.
*
*/
#include "tosnic_i.h"
static tosnic_type_spec_t known_types[] = {
[TOSNIC_TYPE_UNKNOWN] = { "*UNKNOWN*", 0, 0 },
[TOSNIC_TYPE_INT8] = { "int8", 0, sizeof(int8_t) },
[TOSNIC_TYPE_INT16] = { "int16", 0, sizeof(int16_t) },
[TOSNIC_TYPE_INT32] = { "int32", 0, sizeof(int32_t) },
[TOSNIC_TYPE_UINT8] = { "uint8", 0, sizeof(int8_t) },
[TOSNIC_TYPE_UINT16] = { "uint16", 0, sizeof(int16_t) },
[TOSNIC_TYPE_UINT32] = { "uint32", 0, sizeof(int32_t) },
[TOSNIC_TYPE_XINT8] = { "xint8", 0, sizeof(int8_t) },
[TOSNIC_TYPE_XINT16] = { "xint16", 0, sizeof(int16_t) },
[TOSNIC_TYPE_XINT32] = { "xint32", 0, sizeof(int32_t) },
[TOSNIC_TYPE_FLOAT] = { "float", 0, sizeof(float) },
[TOSNIC_TYPE_STRING] = { "string", 0, 0 },
[TOSNIC_TYPE_RADIO_STATUS] = { "radio_stats_t", 0, sizeof(radio_stats_t) }
};
static int known_types_initialized = 0;
static
void tosnic_known_types_init()
{
if (!known_types_initialized) {
known_types_initialized = 1;
int i;
for (i=0; i<TOSNIC_TYPE_MAX_VALUE; i++) {
known_types[i].type_code = i;
}
}
}
void tosnic_known_type_to_buf(buf_t *buf, uint type_code, buf_t *value)
{
tosnic_known_types_init();
int wrong_length = 0;
/* check for null */
if (value == NULL) {
bufprintf(buf, "No data present");
return;
}
/* check length */
tosnic_type_spec_t *spec = tosnic_known_type_get_info(type_code);
if (spec->type_code && spec->size && spec->size != value->len) {
wrong_length = 1;
type_code = 0;
}
switch (type_code) {
case TOSNIC_TYPE_INT8:
bufprintf(buf, "%d", *((int8_t*)value->buf)); break;
case TOSNIC_TYPE_INT16:
bufprintf(buf, "%d", *((int16_t*)value->buf)); break;
case TOSNIC_TYPE_INT32:
bufprintf(buf, "%d", *((int32_t*)value->buf)); break;
case TOSNIC_TYPE_UINT8:
bufprintf(buf, "%u", *((int8_t*)value->buf)); break;
case TOSNIC_TYPE_UINT16:
bufprintf(buf, "%u", *((int16_t*)value->buf)); break;
case TOSNIC_TYPE_UINT32:
bufprintf(buf, "%u", *((int32_t*)value->buf)); break;
case TOSNIC_TYPE_XINT8:
bufprintf(buf, "0x%x", *((int8_t*)value->buf)); break;
case TOSNIC_TYPE_XINT16:
bufprintf(buf, "0x%x", *((int16_t*)value->buf)); break;
case TOSNIC_TYPE_XINT32:
bufprintf(buf, "0x%x", *((int32_t*)value->buf)); break;
case TOSNIC_TYPE_FLOAT:
bufprintf(buf, "%f", *((float*)value->buf)); break;
case TOSNIC_TYPE_RADIO_STATUS: {
radio_stats_t *stats = (radio_stats_t *)(value->buf);
stats->mote_rev[sizeof(stats->mote_rev)-1] = 0;
bufprintf(buf,
"\n"
" Mote Revision: %s\n"
" EmStarBase version: %d\n"
" Flags: %x\n"
" MTU: %d\n"
" Radio CRC Fails: %d\n"
" Serial CRC Fails: %d\n"
" Radio queue drops: %d",
stats->mote_rev, stats->tosbase_version,
stats->flags, stats->MTU,
stats->radio_crc_fail,
stats->serial_crc_fail,
stats->radio_queue_drops);
break;
}
default:
if (wrong_length)
bufprintf(buf, "***WRONG LENGTH*** ");
buf_print_raw(buf, value->buf, value->len);
}
}
int tosnic_known_type_lookup(char *name)
{
tosnic_known_types_init();
int i;
if (name)
for (i=0; i<TOSNIC_TYPE_MAX_VALUE; i++) {
if (known_types[i].type_name &&
strcasecmp(known_types[i].type_name, name) == 0) {
return i;
}
}
return -1;
}
tosnic_type_spec_t *tosnic_known_type_get_info(int index)
{
tosnic_known_types_init();
if (index > 0 && index < TOSNIC_TYPE_MAX_VALUE)
return &(known_types[index]);
return &(known_types[0]);
}
/*
* TOSnic status interface
*/
static
void tosnic_status_data_ready(tosnic_state_t *s, int index, int type, buf_t *pkt)
{
struct tosnic_status_response_hdr *hdr = (struct tosnic_status_response_hdr *)pkt->buf;
/* process the incoming data */
while (pkt->len > sizeof(struct tosnic_status_response_hdr)) {
int next_len = (hdr->length + sizeof(struct tosnic_status_response_hdr));
if (next_len > pkt->len) {
elog(LOG_WARNING, "illegal status response packet!");
goto free_it;
}
/* process directory entries */
if (hdr->type_index == TOSNIC_STATUS_TYPE_DIR) {
if (hdr->length >= sizeof(struct tosnic_status_dir_hdr)) {
struct tosnic_status_dir_hdr *dir = (struct tosnic_status_dir_hdr *)(hdr->data);
hdr->data[hdr->length-1] = 0;
status_entry_t *stat = &(s->status_entry[dir->type_index]);
stat->read_only = dir->read_only;
stat->index = dir->type_index;
stat->in_use = 1;
stat->stale = 0;
if (stat->description) free(stat->description); stat->description = NULL;
if (stat->type) free(stat->type); stat->type = NULL;
if (hdr->length > sizeof(struct tosnic_status_dir_hdr)) {
stat->description = strdup(dir->string);
if ((sizeof(struct tosnic_status_dir_hdr) + strlen(dir->string) + 1) < hdr->length) {
stat->type = strdup(dir->string + strlen(dir->string) + 1);
}
}
stat->parsed_type_code = tosnic_known_type_lookup(stat->type);
}
}
/* process other entries */
else {
status_entry_t *stat = &(s->status_entry[hdr->type_index]);
stat->in_use = 1;
stat->index = hdr->type_index;
if (stat->value) buf_free(stat->value);
stat->value = buf_new();
bufcpy(stat->value, hdr->data, hdr->length);
/* check length */
tosnic_type_spec_t *spec = tosnic_known_type_get_info(stat->parsed_type_code);
if (spec->size && spec->size != hdr->length) {
elog(LOG_WARNING, "Illegal length %s status reponse: %d !+ %d",
spec->type_name, hdr->length, spec->size);
if (hdr->length < spec->size)
buf_insert(stat->value, stat->value->len, NULL, spec->size - hdr->length);
}
else {
/* check for status we're looking for.. */
if (strcasecmp(stat->description, TOSBASE_RADIO_STATS) == 0) {
if (stat->parsed_type_code == TOSNIC_TYPE_RADIO_STATUS) {
tosnic_upper_process_status_stats(s, (radio_stats_t *)(stat->value));
s->status_pending = 0;
}
else goto wrong_type;
}
else if (strcasecmp(stat->description, TOSBASE_CHANNEL) == 0) {
if (stat->parsed_type_code == TOSNIC_TYPE_UINT8)
tosnic_upper_process_status_channel(s, *(uint8_t *)(stat->value));
else goto wrong_type;
}
else if (strcasecmp(stat->description, TOSBASE_POWER) == 0) {
if (stat->parsed_type_code == TOSNIC_TYPE_UINT8)
tosnic_upper_process_status_power(s, *(uint8_t *)(stat->value));
else goto wrong_type;
}
goto remove;
wrong_type:
elog(LOG_WARNING, "Wrong type data %s(%d) for value %s",
stat->type, stat->parsed_type_code, stat->description);
}
}
remove:
buf_remove(pkt, 0, next_len);
}
free_it:
buf_free(pkt);
}
static
void tosnic_status_send_done(tosnic_state_t *s, int index, int type, buf_t *pkt, int acked)
{
s->status_request_pending = 0;
}
static
int tosnic_status_send_request(tosnic_state_t *s, uint8_t *types, size_t type_count)
{
if (!s->status_request_pending) {
buf_t *buf = buf_new();
bufcpy(buf, types, type_count);
tosnic_framer_enqueue_from_upper(s, s->status_client_index, TOSNIC_STATUS_PACKET, buf);
s->status_request_pending = 1;
s->status_pending = 1;
return 0;
}
return -1;
}
static
int tosnic_status_timeout(void *data, int interval, g_event_t *ev)
{
tosnic_state_t *s = (tosnic_state_t *)data;
/* mark all as stale */
int i;
for (i=0; i<256; i++) {
s->status_entry[i].stale = 1;
}
uint8_t type_index = TOSNIC_STATUS_TYPE_ALL;
tosnic_status_send_request(s, &type_index, sizeof(type_index));
return
TIMER_RENEW_MS(s->status_pending ? TOSNIC_TX_WATCHDOG : TOSNIC_STATUS_PERIOD);
}
static
int tosnic_status_print(status_context_t *info, buf_t *buf)
{
tosnic_state_t *s = (tosnic_state_t *) sd_data(info);
bufprintf(buf,
"Mote application status (%s), node %s%s\n"
"=====================================\n"
, s->dev_name, print_if_id(my_node_id),
s->status_pending ? ", ***PENDING***" : "");
int i;
for (i=0; i<256; i++) {
if (s->status_entry[i].in_use) {
bufprintf(buf, "%d: %s[%s]%s%s= ",
i, s->status_entry[i].description, s->status_entry[i].type,
s->status_entry[i].read_only ? "*RO*" : "",
s->status_entry[i].stale ? "*STALE*" : ""
);
tosnic_known_type_to_buf(buf, s->status_entry[i].parsed_type_code, s->status_entry[i].value);
bufprintf(buf, "\n");
}
}
bufprintf(buf, "\n");
return STATUS_MSG_COMPLETE;
}
/*
* TOSNic config interface..
*/
static void tosnic_config_data_ready(tosnic_state_t *s, int index, int type, buf_t *pkt) {}
static void tosnic_config_send_done(tosnic_state_t *s, int index, int type, buf_t *pkt, int acked) {}
void tosnic_status_init(tosnic_state_t *s, int *argc, char **argv)
{
g_timer_add(TOSNIC_STATUS_PERIOD, tosnic_status_timeout, s, NULL, &(s->periodic_status_req));
/* mote application status */
status_dev_opts_t st_opts = {
device: {
devname: link_name_s(s->dev_name, "mote/status"),
device_info: s
},
printable: tosnic_status_print
};
if (g_status_dev(&st_opts, &(s->mote_app_status)) < 0) {
elog(LOG_CRIT, "Unable to create status device %s: %m",
st_opts.device.devname);
exit(1);
}
/* register for access to status proto */
tosnic_client_t spec_status = {
type: TOSNIC_STATUS_PACKET,
handler: tosnic_status_data_ready,
send_done: tosnic_status_send_done,
description: "Mote Status Protocol"
};
s->status_client_index = tosnic_framer_register(s, &spec_status);
/* register for access to config proto */
tosnic_client_t spec_config = {
type: TOSNIC_CONF_PACKET,
handler: tosnic_config_data_ready,
send_done: tosnic_config_send_done,
description: "Mote Config Protocol"
};
s->config_client_index = tosnic_framer_register(s, &spec_config);
}
See more files for this project here