Contiki 3.x
shell-sky.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008, Swedish Institute of Computer Science.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  *
31  */
32 
33 /**
34  * \file
35  * Tmote Sky-specific Contiki shell commands
36  * \author
37  * Adam Dunkels <adam@sics.se>
38  */
39 
40 #include "contiki.h"
41 #include "shell-sky.h"
42 
43 #include "dev/watchdog.h"
44 
45 #include "net/rime/rime.h"
46 #include "net/netstack.h"
47 #include "cc2420.h"
48 #include "dev/leds.h"
49 #include "dev/sht11/sht11.h"
50 #include "dev/light-sensor.h"
51 #include "dev/battery-sensor.h"
52 #include "dev/sht11/sht11-sensor.h"
53 #include "net/rime/timesynch.h"
54 
55 #include "sys/node-id.h"
56 
57 #include <stdio.h>
58 #include <string.h>
59 
60 /*---------------------------------------------------------------------------*/
61 PROCESS(shell_nodeid_process, "nodeid");
62 SHELL_COMMAND(nodeid_command,
63  "nodeid",
64  "nodeid: set node ID",
65  &shell_nodeid_process);
66 PROCESS(shell_sense_process, "sense");
67 SHELL_COMMAND(sense_command,
68  "sense",
69  "sense: print out sensor data",
70  &shell_sense_process);
71 PROCESS(shell_senseconv_process, "senseconv");
72 SHELL_COMMAND(senseconv_command,
73  "senseconv",
74  "senseconv: convert 'sense' data to human readable format",
75  &shell_senseconv_process);
76 PROCESS(shell_txpower_process, "txpower");
77 SHELL_COMMAND(txpower_command,
78  "txpower",
79  "txpower <power>: change CC2420 transmission power (0 - 31)",
80  &shell_txpower_process);
81 PROCESS(shell_rfchannel_process, "rfchannel");
82 SHELL_COMMAND(rfchannel_command,
83  "rfchannel",
84  "rfchannel <channel>: change CC2420 radio channel (11 - 26)",
85  &shell_rfchannel_process);
86 /*---------------------------------------------------------------------------*/
87 #define MAX(a, b) ((a) > (b)? (a): (b))
88 #define MIN(a, b) ((a) < (b)? (a): (b))
89 struct spectrum {
90  int channel[16];
91 };
92 #define NUM_SAMPLES 4
93 static struct spectrum rssi_samples[NUM_SAMPLES];
94 static int
95 do_rssi(void)
96 {
97  static int sample;
98  int channel;
99 
100  NETSTACK_MAC.off(0);
101 
102  cc2420_on();
103  for(channel = 11; channel <= 26; ++channel) {
104  cc2420_set_channel(channel);
105  rssi_samples[sample].channel[channel - 11] = cc2420_rssi() + 53;
106  }
107 
108  NETSTACK_MAC.on();
109 
110  sample = (sample + 1) % NUM_SAMPLES;
111 
112  {
113  int channel, tot;
114  tot = 0;
115  for(channel = 0; channel < 16; ++channel) {
116  int max = -256;
117  int i;
118  for(i = 0; i < NUM_SAMPLES; ++i) {
119  max = MAX(max, rssi_samples[i].channel[channel]);
120  }
121  tot += max / 20;
122  }
123  return tot;
124  }
125 }
126 /*---------------------------------------------------------------------------*/
127 struct sense_msg {
128  uint16_t len;
129  uint16_t clock;
130  uint16_t timesynch_time;
131  uint16_t light1;
132  uint16_t light2;
133  uint16_t temp;
134  uint16_t humidity;
135  uint16_t rssi;
136  uint16_t voltage;
137 };
138 /*---------------------------------------------------------------------------*/
139 PROCESS_THREAD(shell_sense_process, ev, data)
140 {
141  struct sense_msg msg;
142  PROCESS_BEGIN();
143 
144  SENSORS_ACTIVATE(light_sensor);
145  SENSORS_ACTIVATE(battery_sensor);
146  SENSORS_ACTIVATE(sht11_sensor);
147 
148  msg.len = 7;
149  msg.clock = clock_time();
150 #if TIMESYNCH_CONF_ENABLED
151  msg.timesynch_time = timesynch_time();
152 #else /* TIMESYNCH_CONF_ENABLED */
153  msg.timesynch_time = 0;
154 #endif /* TIMESYNCH_CONF_ENABLED */
155  msg.light1 = light_sensor.value(LIGHT_SENSOR_PHOTOSYNTHETIC);
156  msg.light2 = light_sensor.value(LIGHT_SENSOR_TOTAL_SOLAR);
157  msg.temp = sht11_sensor.value(SHT11_SENSOR_TEMP);
158  msg.humidity = sht11_sensor.value(SHT11_SENSOR_HUMIDITY);
159  msg.rssi = do_rssi();
160  msg.voltage = battery_sensor.value(0);
161 
162  msg.rssi = do_rssi();
163 
164  SENSORS_DEACTIVATE(light_sensor);
165  SENSORS_DEACTIVATE(battery_sensor);
166  SENSORS_DEACTIVATE(sht11_sensor);
167 
168  shell_output(&sense_command, &msg, sizeof(msg), "", 0);
169  PROCESS_END();
170 }
171 /*---------------------------------------------------------------------------*/
172 PROCESS_THREAD(shell_senseconv_process, ev, data)
173 {
174  struct shell_input *input;
175  struct sense_msg *msg;
176  PROCESS_BEGIN();
177  while(1) {
179  input = data;
180 
181  if(input->len1 + input->len2 == 0) {
182  PROCESS_EXIT();
183  }
184  msg = (struct sense_msg *)input->data1;
185 
186  if(msg != NULL) {
187  char buf[40];
188  snprintf(buf, sizeof(buf),
189  "%d", 10 * msg->light1 / 7);
190  shell_output_str(&senseconv_command, "Light 1 ", buf);
191  snprintf(buf, sizeof(buf),
192  "%d", 46 * msg->light2 / 10);
193  shell_output_str(&senseconv_command, "Light 2 ", buf);
194  snprintf(buf, sizeof(buf),
195  "%d.%d", (msg->temp / 10 - 396) / 10,
196  (msg->temp / 10 - 396) % 10);
197  shell_output_str(&senseconv_command, "Temperature ", buf);
198  snprintf(buf, sizeof(buf),
199  "%d", (int)(-4L + 405L * msg->humidity / 10000L));
200  shell_output_str(&senseconv_command, "Relative humidity ", buf);
201  snprintf(buf, sizeof(buf),
202  "%d", msg->rssi);
203  shell_output_str(&senseconv_command, "RSSI ", buf);
204  snprintf(buf, sizeof(buf), /* 819 = 4096 / 5 */
205  "%d.%d", (msg->voltage / 819), (10 * msg->voltage / 819) % 10);
206  shell_output_str(&senseconv_command, "Voltage ", buf);
207  }
208  }
209  PROCESS_END();
210 }
211 /*---------------------------------------------------------------------------*/
212 PROCESS_THREAD(shell_txpower_process, ev, data)
213 {
214  struct {
215  uint16_t len;
216  uint16_t txpower;
217  } msg;
218  const char *newptr;
219  PROCESS_BEGIN();
220 
221  msg.txpower = shell_strtolong(data, &newptr);
222 
223  /* If no transmission power was given on the command line, we print
224  out the current txpower. */
225 
226  if(newptr == data) {
227  msg.txpower = cc2420_get_txpower();
228  } else {
229  cc2420_set_txpower(msg.txpower);
230  }
231 
232  msg.len = 1;
233 
234  shell_output(&txpower_command, &msg, sizeof(msg), "", 0);
235 
236  PROCESS_END();
237 }
238 /*---------------------------------------------------------------------------*/
239 PROCESS_THREAD(shell_rfchannel_process, ev, data)
240 {
241  struct {
242  uint16_t len;
243  uint16_t channel;
244  } msg;
245  const char *newptr;
246  PROCESS_BEGIN();
247 
248  msg.channel = shell_strtolong(data, &newptr);
249 
250  /* If no channel was given on the command line, we print out the
251  current channel. */
252  if(newptr == data) {
253  msg.channel = cc2420_get_channel();
254  } else {
255  cc2420_set_channel(msg.channel);
256  }
257 
258  msg.len = 1;
259 
260  shell_output(&rfchannel_command, &msg, sizeof(msg), "", 0);
261 
262  PROCESS_END();
263 }
264 /*---------------------------------------------------------------------------*/
265 PROCESS_THREAD(shell_nodeid_process, ev, data)
266 {
267  uint16_t nodeid;
268  char buf[20];
269  const char *newptr;
270  PROCESS_BEGIN();
271 
272  nodeid = shell_strtolong(data, &newptr);
273 
274  /* If no node ID was given on the command line, we print out the
275  current channel. Else we burn the new node ID. */
276  if(newptr == data) {
277  nodeid = node_id;
278  } else {
279  nodeid = shell_strtolong(data, &newptr);
280  watchdog_stop();
281  leds_on(LEDS_RED);
282  node_id_burn(nodeid);
283  leds_on(LEDS_BLUE);
284  node_id_restore();
285  leds_off(LEDS_RED + LEDS_BLUE);
286  watchdog_start();
287  }
288 
289  snprintf(buf, sizeof(buf), "%d", nodeid);
290  shell_output_str(&nodeid_command, "Node ID: ", buf);
291 
292  PROCESS_END();
293 }
294 /*---------------------------------------------------------------------------*/
295 void
296 shell_sky_init(void)
297 {
298  shell_register_command(&txpower_command);
299  shell_register_command(&rfchannel_command);
300  shell_register_command(&sense_command);
301  shell_register_command(&senseconv_command);
302  shell_register_command(&nodeid_command);
303 
304 }
305 /*---------------------------------------------------------------------------*/
void shell_output_str(struct shell_command *c, char *text1, const char *text2)
Output strings from a shell command.
Definition: shell.c:383
#define LEDS_RED
LED1 (Red) -&gt; PC0.
Definition: board.h:89
#define PROCESS_EXIT()
Exit the currently running process.
Definition: process.h:200
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
void watchdog_start(void)
Starts the WDT in watchdog mode if enabled by user configuration, maximum interval.
Definition: watchdog.c:49
#define NULL
The null pointer.
Header file for Tmote Sky-specific Contiki shell commands
Header file for a simple time synchronization mechanism
Header file for the Rime stack
rtimer_clock_t timesynch_time(void)
Get the current time-synchronized time.
void shell_output(struct shell_command *c, void *data1, int len1, const void *data2, int len2)
Output data from a shell command.
Definition: shell.c:395
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition: process.h:273
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
CCIF clock_time_t clock_time(void)
Get the current clock time.
Definition: clock.c:41
unsigned long shell_strtolong(const char *str, const char **retstr)
Convert a string to a number.
Definition: shell.c:521
void watchdog_stop(void)
In watchdog mode, the WDT can not be stopped.
Definition: watchdog.c:58
Structure for shell input data.
Definition: shell.h:365
void shell_register_command(struct shell_command *c)
Register a command with the shell.
Definition: shell.c:413
#define PROCESS_WAIT_EVENT_UNTIL(c)
Wait for an event to be posted to the process, with an extra condition.
Definition: process.h:157
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
int shell_event_input
The event number for shell input data.
Definition: shell.c:70
#define SHELL_COMMAND(name, command, description, process)
Define a shell command.
Definition: shell.h:219
Include file for the Contiki low-layer network stack (NETSTACK)