1 /*
2 *
3 * Copyright (c) 2005 The Regents of the University of California. All
4 * rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * - Neither the name of the University nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 */
30
31 #include <ar.h>
32
33 /*
34 * ar_send
35 *
36 * send an acoustic pulse
37 */
38
39
40 static
41 int ar_start_computation(void *data, int interval, g_event_t *ev)
42 {
43 ar_state_t *ar = (ar_state_t *)data;
44 g_event_destroy(ev);
45
46 /* trigger the compute thread */
47 pthread_cond_broadcast(&(ar->chirp_list_cond));
48
49 return TIMER_DONE;
50 }
51
52
53 static
54 int ar_amp_off(void *data, int interval, g_event_t *ev)
55 {
56 #ifndef SIM_ONLY
57 ar_state_t *ar = (ar_state_t *)data;
58 ar_amplifier_enable(ar, 0);
59 #endif
60 return TIMER_DONE;
61 }
62
63
64 static
65 int ar_amp_on(void *data, int interval, g_event_t *ev)
66 {
67 #ifndef SIM_ONLY
68 ar_state_t *ar = (ar_state_t *)data;
69 ar_amplifier_enable(ar, 1);
70 #endif
71 return TIMER_DONE;
72 }
73
74
75 static
76 int ar_send_go(void *data, int interval, g_event_t *ev)
77 {
78 ar_state_t *ar = (ar_state_t *)data;
79 int nocomp = ar->next_nocomp;
80 char *notation = ar->next_note;
81 ar->next_note = NULL;
82 int seed = ar->next_seed;
83 int modulation = ar->next_mod;
84
85 /* emit */
86 ar_emit_current_chirp(ar, 0);
87
88 /* turn off amplifier */
89 g_timer_add(1000, ar_amp_off, ar, NULL, NULL);
90
91 /* notify */
92 range_notify_pkt_t notify = {
93 chirp_time: {
94 timebase: {
95 node: my_node_id,
96 comp: CPU
97 },
98 stamp: ar->last_chirp_time
99 },
100 chirp_time_end: {
101 timebase: {
102 node: my_node_id,
103 comp: CPU
104 },
105 stamp: ar->last_chirp_time
106 },
107 seqno: ar->chirp_seqno,
108 modulation: modulation,
109 skip_computation: nocomp,
110 seed: seed,
111 chirp_index: ar->send_index
112 };
113 ar->send_index++;
114 if (notation) {
115 strcpy(notify.notation, notation);
116 free(notation);
117 }
118 ar_record_chirp(ar, my_node_id, ¬ify, 0);
119
120 return TIMER_DONE;
121 }
122
123
124 void ar_reset_chirp(ar_state_t *ar)
125 {
126 int chirp_len = CHIRP_CHIPS*MOD_FACTOR;
127 if (ar->next_chirp) free(ar->next_chirp);
128 ar->next_chirp = g_new0(int16_t,chirp_len);
129 ar_pn_generate_chirp(ar->next_chirp, chirp_len, ar->next_seed, ar->next_mod, 1.0);
130 }
131
132
133 int ar_send_schedule_chirp(ar_state_t *ar, struct timeval *tv, int seed, int delay, int count)
134 {
135 if (ar->chirp_refractory) {
136 /* these things would need to be more sophisticated if we were having more
137 * than one "master"... multiple scheduled chirps, etc. */
138 elog(LOG_CRIT, "Not doing triggered chirp because refractory was set!");
139 goto fail;
140 }
141
142 /* make sure that the codec is running at 48KHz */
143 printf_to_file(DEV_VXP_STATUS, "rate=48000");
144
145 /* configure the chirp */
146 ar->next_seed = seed;
147 ar->next_mod = 0;
148 ar->next_nocomp = 0;
149 if (ar->next_note) free(ar->next_note);
150 char buf[20];
151 sprintf(buf, "%d", my_node_id);
152 ar->next_note = strdup(buf);
153 ar_reset_chirp(ar);
154
155 struct timeval now;
156 gettimeofday(&now, NULL);
157 int msec = misc_tv_offset_neg_msec(tv, &now);
158 int holdoff = msec + 6000 + count * 1500;
159
160 msec += 3000 + delay * 1500;
161 if (msec < 0) {
162 elog(LOG_CRIT, "Not doing triggered chirp because msg arrived late");
163 goto fail;
164 }
165
166 g_event_destroy(ar->amp_at_time);
167 g_event_destroy(ar->chirp_delay);
168 g_timer_add(msec, ar_amp_on, ar, NULL, &(ar->amp_at_time));
169 g_timer_add(msec+1000, ar_send_go, ar, NULL, &(ar->chirp_delay));
170 g_timer_add(msec+6000, NULL, NULL, NULL, &(ar->chirp_refractory));
171 g_timer_add(holdoff, ar_start_computation, ar, NULL, &(ar->computation_holdoff));
172 return 0;
173
174 fail:
175 return -1;
176 }
177
178
179
180 int ar_send_trigger(ar_state_t *ar, int seed, int modulation, char *notation, int nocomp)
181 {
182 if (ar->chirp_refractory) {
183 elog(LOG_WARNING, "Chirp requested too soon after last chirp");
184 return -1;
185 }
186
187 #ifndef SIM_ONLY
188 /* turn on amplifier via GPIO */
189 ar_amplifier_enable(ar, 1);
190 #endif
191
192 /* set timer to start chirping */
193 g_timer_add(1000, ar_send_go, ar, NULL, &ar->chirp_delay);
194
195 /* set refractory for five seconds */
196 g_timer_add(5000, NULL, NULL, NULL, &ar->chirp_refractory);
197
198 /* save args */
199 ar->next_seed = seed;
200 ar->next_mod = modulation;
201 ar->next_nocomp = nocomp;
202 ar->next_note = notation ? strdup(notation) : NULL;
203 ar_reset_chirp(ar);
204
205 return 0;
206 }
207
208
209 /*
210 * outputs current orientation seqno
211 */
212
213 static
214 int ar_seqno_printable(status_context_t *ctx, buf_t *buf)
215 {
216 ar_state_t *ar = (ar_state_t *)sd_data(ctx);
217 bufprintf(buf, "%d\n", ar->chirp_seqno);
218 return STATUS_MSG_COMPLETE;
219 }
220
221 static
222 int ar_index_printable(status_context_t *ctx, buf_t *buf)
223 {
224 ar_state_t *ar = (ar_state_t *)sd_data(ctx);
225 bufprintf(buf, "%04d\n", ar->send_index%10000);
226 return STATUS_MSG_COMPLETE;
227 }
228
229 /*
230 * chirp request interface
231 */
232
233 static
234 int ar_send_usage(status_context_t *ctx, buf_t *buf)
235 {
236 ar_state_t *ar = (ar_state_t *)sd_data(ctx);
237
238 bufprintf(buf,
239 "chirp trigger device\n"
240 "Usage: \n"
241 " chirp[=notation]: cause a chirp now\n"
242 " mod=<modulation-number>: using this modulation\n"
243 " nocomp: withhold computation (when only collecting data)\n"
244 " inval: invalidate all range info after moving node\n"
245 " temp=<degrees-C>: set the current air temperature\n"
246 " The current temperature is %f degrees C\n"
247 " rh=<0-100>: set the current relative humdity\n"
248 " The current RH is %f\n"
249 " dump=<dump-format-str>: start saving debugging info to this file.\n"
250 " The format string must have %%s for datafile-type and %%d for index\n"
251 " Currently the format string is set to '%s'\n"
252 " nodump: disable saving debug info\n"
253 " array=<8cm,orig>: re-set the array type\n"
254 "\n"
255 "Examples: \n"
256 " echo chirp > %s\n"
257 " echo mod=2:chirp=20m-test > %s\n"
258 " echo inval > %s\n"
259 " echo dump=format-string > %s\n"
260 " echo temp=<temperature in C> > %s\n"
261 " echo rh=<RH (0-100)> > %s\n"
262 "\n"
263 "If a notation is supplied, the receiver will attempt to save\n"
264 "the raw data under that name. \n"
265 "\n"
266 "Set via command-line options:\n"
267 " Control string for raw files: %s\n"
268 " Control string for details log: %s\n"
269 "\n"
270
271 ,
272 ar->curr_temperature,
273 ar->curr_RH,
274 ar->dump_files_ctrl_string,
275 AR_CHIRP_DEVICE,
276 AR_CHIRP_DEVICE,
277 AR_CHIRP_DEVICE,
278 AR_CHIRP_DEVICE,
279 AR_CHIRP_DEVICE,
280 AR_CHIRP_DEVICE,
281 ar->ar_log_raw,
282 ar->ar_log_file
283 );
284 return STATUS_MSG_COMPLETE;
285 }
286
287
288 void ar_send_invalidate(ar_state_t *ar)
289 {
290 ar->chirp_seqno++;
291 g_status_dev_notify(ar->seqno_status);
292 chirp_result_t *result = g_new0(chirp_result_t, 1);
293 result->entry.source = my_node_id;
294 result->entry.seqno = ar->chirp_seqno;
295 ar_update_published(ar, result);
296 }
297
298
299 static
300 int ar_send_cmd(status_context_t *ctx, char *command, size_t buf_size)
301 {
302 ar_state_t *ar = (ar_state_t *)sd_data(ctx);
303 int modulation = 0;
304 char *notation = NULL;
305 int nocomp = 0;
306 int chirp = 0;
307 int retval = buf_size;
308 int seed = (random() % 999) + 1;
309
310 parser_state_t *ps = misc_parse_init(command, MISC_PARSE_COLON_SCHEME);
311 while (misc_parse_next_kvp(ps) >= 0) {
312
313 if (strcmp(ps->key, "inval") == 0) {
314 ar_send_invalidate(ar);
315 }
316
317 else if (strcmp(ps->key, "array") == 0) {
318 ar_update_array_spec(ar, ps->value);
319 }
320
321 else if (strcmp(ps->key, "mod") == 0) {
322 if (ps->value && isdigit(ps->value[0]))
323 modulation = atoi(ps->value);
324 else
325 retval = EVENT_ERROR(EINVAL);
326 }
327
328 else if (strcmp(ps->key, "nocomp") == 0) {
329 nocomp=1;
330 }
331
332 else if (strcmp(ps->key, "chirp") == 0) {
333 if (ps->value) notation = strdup(ps->value);
334 chirp = 1;
335 }
336
337 else if (strcmp(ps->key, "seed") == 0) {
338 if (ps->value && isdigit(ps->value[0]))
339 seed = atoi(ps->value);
340 }
341
342 else if (strcmp(ps->key, "dump") == 0) {
343 ar->dump_files_ctrl_string = strdup(ps->value);
344 if (strlen(ar->dump_files_ctrl_string) < 1) {
345 ar->dump_files_ctrl_string = NULL;
346 retval = EVENT_ERROR(EINVAL);
347 }
348 ar->dump_files_ctrl_string[strlen(ar->dump_files_ctrl_string)-1] = 0;
349 }
350
351 else if (strcmp(ps->key, "nodump") == 0) {
352 if (ar->dump_files_ctrl_string)
353 free(ar->dump_files_ctrl_string);
354 ar->dump_files_ctrl_string = NULL;
355 }
356
357 else if (strcmp(ps->key, "temp") == 0) {
358 if (ps->value && isdigit(ps->value[0])) {
359 if (1 != sscanf(ps->value, "%f", &(ar->curr_temperature)))
360 retval = EVENT_ERROR(EINVAL);
361 }
362 else
363 retval = EVENT_ERROR(EINVAL);
364 }
365
366 else if (strcmp(ps->key, "rh") == 0) {
367 if (ps->value && isdigit(ps->value[0])) {
368 if (1 != sscanf(ps->value, "%f", &(ar->curr_RH)))
369 retval = EVENT_ERROR(EINVAL);
370 }
371 else
372 retval = EVENT_ERROR(EINVAL);
373 }
374
375 else
376 retval = EVENT_ERROR(ENOSYS);
377 }
378
379 if (chirp) {
380 int status = ar_send_trigger(ar, seed, modulation, notation, nocomp);
381 if (status < 0)
382 retval = EVENT_ERROR(EALREADY);
383 }
384
385 //done:
386 misc_parse_cleanup(ps);
387 if (notation) free(notation);
388 return retval;
389 }
390
391
392 int ar_send_init(ar_state_t *ar)
393 {
394 #ifndef SIM_ONLY
395 /* disable amplifier */
396 ar_amplifier_enable(ar, 0);
397 #endif /*SIM_ONLY*/
398
399 status_dev_opts_t opts = {
400 device: {
401 devname: AR_CHIRP_DEVICE,
402 device_info: ar
403 },
404 printable: ar_send_usage,
405 write: ar_send_cmd
406 };
407
408 if (g_status_dev(&opts, &(ar->chirp_cmd)) < 0) {
409 elog(LOG_CRIT, "Failed to create trigger device: %m");
410 exit(1);
411 }
412
413 status_dev_opts_t opts2 = {
414 device: {
415 devname: AR_SEQNO_DEVICE,
416 device_info: ar
417 },
418 printable: ar_seqno_printable
419 };
420
421 if (g_status_dev(&opts2, &(ar->seqno_status)) < 0) {
422 elog(LOG_CRIT, "Failed to create seqno device: %m");
423 }
424
425 status_dev_opts_t opts3 = {
426 device: {
427 devname: AR_INDEX_DEVICE,
428 device_info: ar
429 },
430 printable: ar_index_printable
431 };
432
433 if (g_status_dev(&opts3, &(ar->index_status)) < 0) {
434 elog(LOG_CRIT, "Failed to create index device: %m");
435 }
436
437 ar->chirp_seqno = random();
438 ar_send_cmd(ar->chirp_cmd, "inval", 5);
439
440 return 0;
441 }
442
443
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.