Added USE_8MHZ_CRYSTAL so that normal MSP 4.15MHZ mode can be switched
[tinyos:tinyos-1_x.git] / contrib / handhelds / apps / MOBIUS / SixAxisCmdCtrl / SixAxisCmdCtrlM.nc
1 /*
2  * Copyright (c) 2007, Intel Corporation
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 are met:
7  * 
8  * Redistributions of source code must retain the above copyright notice, 
9  * this list of conditions and the following disclaimer. 
10  *
11  * Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution. 
14  *
15  * Neither the name of the Intel Corporation nor the names of its contributors
16  * may be used to endorse or promote products derived from this software 
17  * without specific prior written permission. 
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  * Author: Adrian Burns
32  *         November, 2007
33  */
34
35  /***********************************************************************************
36
37    This app is an example that shows how the SerialCommandParser interface can 
38    be used to control and configure SHIMMER from a MOBIUS PC application.
39
40    Default Sample Frequency: 100 hz
41    
42    Packet Format:
43          BOF| Sensor ID | Data Type | Seq No. | TimeStamp | Len | Acc | Acc  | Acc  | Gyro  | Gyro | Gyro |  CRC | EOF
44    Byte:  1 |    2      |     3     |    4    |     5-6   |  7  | 8-9 | 10-11| 12-13| 14-15 | 16-17| 18-19| 20-21| 22
45
46  ***********************************************************************************/
47
48 includes crc;
49 includes SixAxisCmdCtrl;
50 includes DMA;
51 includes MMA7260_Accel;
52 includes Message;
53 includes RovingNetworks;
54
55
56 module SixAxisCmdCtrlM {
57   provides{
58     interface StdControl;
59     interface SensorControl;
60   }
61   uses {
62     interface DMA as DMA0;
63
64     interface StdControl as AccelStdControl;
65     interface StdControl as SerialCommandStdControl;
66     interface MMA7260_Accel as Accel;
67
68     interface StdControl as BTStdControl;
69     interface Bluetooth;
70
71     interface Leds;
72     interface Timer as ActivityTimer;
73     interface Timer as SampleTimer;
74     interface LocalTime;
75     interface SerialCommandParser;
76   }
77 }
78
79 implementation {
80  
81 /* comment out USE_8MHZ_CRYSTAL and load this code once so that the baudrate of the RovingNetworks 
82    Bluetooth module is setup(once only), then uncomment it and load for 8MHZ operation */
83 #define USE_8MHZ_CRYSTAL
84
85 #ifdef LOW_BATTERY_INDICATION
86   //#define DEBUG_LOW_BATTERY_INDICATION
87   /* during testing of the the (AVcc-AVss)/2 value from the ADC on various SHIMMERS, to get a reliable cut off point 
88      to recharge the battery it is important to find the baseline (AVcc-AVss)/2 value coming from the ADC as it varies 
89      from SHIMMER to SHIMMER, however the range of fluctuation is pretty constant and (AVcc-AVss)/2 provides an accurate 
90      battery low indication that prevents getting any voltage skewed data from the accelerometer or add-on board sensors */
91   #define TOTAL_BASELINE_BATT_VOLT_SAMPLES_TO_RECORD 1000
92   #define BATTERY_LOW_INDICATION_OFFSET 20 /* (AVcc - AVss)/2 = Approx 3V-0V/2 = 1.5V, 12 bit ADC with 2.5V REF,
93                                               4096/2500 = 1mV=1.6384 units */ 
94   bool need_baseline_voltage, linkDisconnecting, battPacketPending;
95   uint16_t num_baseline_voltage_samples, baseline_voltage;
96   uint32_t sum_batt_volt_samples;
97
98 #ifdef DEBUG_LOW_BATTERY_INDICATION
99   uint16_t debug_counter;
100 #endif /* DEBUG_LOW_BATTERY_INDICATION */
101
102 #endif /* LOW_BATTERY_INDICATION */
103
104
105   task void startSensing();
106   task void stopSensing();
107
108   #define FIXED_PACKET_SIZE 22
109   #define FIXED_PAYLOAD_SIZE 12
110   uint8_t tx_packet[(FIXED_PACKET_SIZE*2)+1]; /* (*2)twice size because of byte stuffing */
111                                               /* (+1)MSP430 CPU can only read/write 16-bit values at even addresses, 
112                                               /* so use an empty byte to even up the memory locations for 16-bit values */
113   #define MAX_CMD_PACKET_SIZE 50
114   uint8_t tx_cmd_packet[MAX_CMD_PACKET_SIZE*2]; /* (*2)twice size because of byte stuffing */
115
116   const uint8_t personality[17] = {
117     0,1,2,3,4,5,0xFF,0xFF,
118     SAMPLING_50HZ,SAMPLING_50HZ,SAMPLING_50HZ,SAMPLING_50HZ,
119     SAMPLING_50HZ,SAMPLING_50HZ,SAMPLING_0HZ_OFF,SAMPLING_0HZ_OFF,FRAMING_EOF
120   };
121
122   norace uint8_t current_buffer = 0, dma_blocks = 0, g_data;
123   uint16_t sbuf0[36], sbuf1[36], timestamp0, timestamp1, 
124            sample_freq = SAMPLING_100HZ, new_sample_freq = SAMPLING_0HZ_OFF;
125
126   bool enable_sending, command_mode_complete, activity_led_on, sensor_sampling=FALSE, cmdPacketPending;
127   
128   /* Internal function to calculate 16 bit CRC */
129   uint16_t calc_crc(uint8_t *ptr, uint8_t count) {
130     uint16_t crc;
131       crc = 0;
132     while (count-- > 0)
133       crc = crcByte(crc, *ptr++);
134
135     return crc;
136   }
137
138   void setupDMA() {
139     call DMA0.init();
140
141     call DMA0.setSourceAddress((uint16_t)ADC12MEM0_);
142
143     call DMA0.setDestinationAddress((uint16_t)&sbuf0[0]);
144
145     /*
146      *  we'll transfer from six sequential adcmem registers 
147      * to six sequential addresses in a buffer
148      */
149     call DMA0.setBlockSize(7);
150
151     // we want block transfer, single
152     DMA0CTL = DMADT_1 + DMADSTINCR_3 + DMASRCINCR_3;
153   }
154
155   void sampleADC() {
156     call DMA0.ADCinit();   // this doesn't really need to be parameterized
157
158     atomic{
159       CLR_FLAG(ADC12CTL1, ADC12SSEL_3);         // clr clk from smclk
160       SET_FLAG(ADC12CTL1, ADC12SSEL_3);         // clk from aclk
161
162       /* with a 125khz clock (_7) its 136usec per conversion, 136*6=816usec in total */
163       SET_FLAG(ADC12CTL1, ADC12DIV_7);
164       // sample and hold time four adc12clk cycles
165       SET_FLAG(ADC12CTL0, SHT0_0);   
166
167       // set reference voltage to 2.5v
168       SET_FLAG(ADC12CTL0, REF2_5V);   
169       
170       // conversion start address
171       SET_FLAG(ADC12CTL1, CSTARTADD_0);      // really a zero, for clarity
172     }
173
174     SET_FLAG(ADC12MCTL0, INCH_5);  // accel x 
175     SET_FLAG(ADC12MCTL1, INCH_4);  // accel y 
176     SET_FLAG(ADC12MCTL2, INCH_3);  // accel z 
177     SET_FLAG(ADC12MCTL3, INCH_1);  // x gyro
178     SET_FLAG(ADC12MCTL4, INCH_6);  // y gyro
179     SET_FLAG(ADC12MCTL5, INCH_2);  // z gyro
180     SET_FLAG(ADC12MCTL6, INCH_11); // (AVcc-AVss)/2 to monitor battery voltage
181     SET_FLAG(ADC12MCTL6, EOS);     //sez "this is the last reg" 
182
183     SET_FLAG(ADC12MCTL0, SREF_1);             // Vref = Vref+ and Vr-
184     SET_FLAG(ADC12MCTL1, SREF_1);             // Vref = Vref+ and Vr-
185     SET_FLAG(ADC12MCTL2, SREF_1);             // Vref = Vref+ and Vr-
186     SET_FLAG(ADC12MCTL3, SREF_1);             // Vref = Vref+ and Vr-
187     SET_FLAG(ADC12MCTL4, SREF_1);             // Vref = Vref+ and Vr-
188     SET_FLAG(ADC12MCTL5, SREF_1);             // Vref = Vref+ and Vr-
189     SET_FLAG(ADC12MCTL6, SREF_1);             // Vref = Vref+ and Vr-
190     
191     /* set up for three adc channels -> three adcmem regs -> three dma channels in round-robin */
192     /* clear init defaults first */
193     CLR_FLAG(ADC12CTL1, CONSEQ_2);     // clear default repeat single channel
194
195     SET_FLAG(ADC12CTL1, CONSEQ_1);      // single sequence of channels
196     
197     setupDMA();
198
199     call DMA0.beginTransfer();
200   }
201
202   /*****************************************
203    * StdControl interface
204    *****************************************/
205   
206   command result_t StdControl.init() {
207
208 #ifdef USE_8MHZ_CRYSTAL
209     /* 
210      * set up 8mhz clock to max out 
211      * msp430 throughput 
212      */
213     register uint8_t i;
214
215     atomic CLR_FLAG(BCSCTL1, XT2OFF); // basic clock system control reg, turn off XT2 osc
216
217     call Leds.init();
218
219     call Leds.redOn();
220     do{
221       CLR_FLAG(IFG1, OFIFG);
222       for(i = 0; i < 0xff; i++);
223     }
224     while(READ_FLAG(IFG1, OFIFG));
225
226     call Leds.redOff();
227
228     call Leds.yellowOn();
229     TOSH_uwait(50000UL);
230
231     atomic{ 
232       BCSCTL2 = 0; 
233       SET_FLAG(BCSCTL2, SELM_2); /* select master clock source, XT2CLK when XT2 oscillator present */
234     }                            /*on-chip. LFXT1CLK when XT2 oscillator not present on-chip. */
235
236     call Leds.yellowOff();
237
238     atomic{
239       SET_FLAG(BCSCTL2, SELS);  // smclk from xt2
240       SET_FLAG(BCSCTL2, DIVS_3);  // divide it by 8, 8MHZ/8=1MHZ
241     }
242     /* 
243      * end clock set up 
244      */
245 #endif /* USE_8MHZ_CRYSTAL */
246
247     call AccelStdControl.init();
248
249     // pins for gyro, gyro enable
250     TOSH_MAKE_ADC_1_INPUT();   // x
251     TOSH_MAKE_ADC_2_INPUT();   // z
252     TOSH_MAKE_ADC_6_INPUT();   // y
253
254     TOSH_SEL_ADC_1_MODFUNC();
255     TOSH_SEL_ADC_2_MODFUNC();
256     TOSH_SEL_ADC_6_MODFUNC();
257     
258     atomic {
259       memset(tx_packet, 0, (FIXED_PACKET_SIZE*2));
260       memset(tx_cmd_packet, 0, (MAX_CMD_PACKET_SIZE*2));
261       enable_sending = FALSE;
262       cmdPacketPending = FALSE;
263       command_mode_complete = FALSE;
264       activity_led_on = FALSE;
265     }
266
267     call BTStdControl.init();
268     call Bluetooth.disableRemoteConfig(TRUE);
269      /* if CPU=8Mhz then customise roving networks baudrate to suit 8Mhz/9 baud */
270     call Bluetooth.setBaudrate("452");
271
272     call SerialCommandStdControl.init();
273     dma_blocks = 0;
274     return SUCCESS;
275   }
276
277   command result_t StdControl.start() {
278     call BTStdControl.start();
279     call SerialCommandStdControl.start();
280     /* so that the clinicians know the sensor is on */
281     call Leds.redOn();
282 #ifdef LOW_BATTERY_INDICATION
283     /* initialise baseline voltage measurement stuff */ 
284     need_baseline_voltage = TRUE;
285     linkDisconnecting = FALSE;
286     battPacketPending = FALSE;
287     num_baseline_voltage_samples = baseline_voltage = sum_batt_volt_samples = 0;
288     call Leds.orangeOn();
289 #ifdef DEBUG_LOW_BATTERY_INDICATION
290     debug_counter = 0;
291 #endif /* DEBUG_LOW_BATTERY_INDICATION */
292 #endif /* LOW_BATTERY_INDICATION */
293
294     return SUCCESS;
295   }
296
297   command result_t StdControl.stop() {
298     call Leds.redOff();
299     call BTStdControl.stop();
300     call SerialCommandStdControl.stop();
301     return SUCCESS;
302   }
303   
304   task void setSampleFrequency() {
305     result_t result;
306
307     sample_freq = new_sample_freq;
308     if(sensor_sampling) {
309       call SampleTimer.stop();
310       call SampleTimer.start(TIMER_REPEAT, sample_freq);
311     }
312     signal SensorControl.sampleFrequencyChanged(SUCCESS);
313   }
314
315   /*****************************************
316    * SensorControl interface
317    *****************************************/
318
319   command result_t SensorControl.startStreaming(){
320     if(command_mode_complete) {
321       post startSensing();
322       return SUCCESS;
323     }
324     else {
325       return FAIL;
326     }
327   }
328
329   command result_t SensorControl.stopStreaming(){
330     post stopSensing();
331     return SUCCESS;
332   }
333
334   command result_t SensorControl.startLogging(){
335   }
336
337   command result_t SensorControl.stopLogging(){
338   }
339
340   command result_t SensorControl.getCardData(){
341   }
342
343   command uint8_t SensorControl.getActiveRadio(){
344     return 'B'; /* Bluetooth */
345   }
346   
347   command result_t SensorControl.changeSampleFrequency(uint16_t new_freq){
348
349     switch ( new_freq ) {
350       case 1000:
351         new_freq = SAMPLING_1000HZ;
352       break;
353       case 500:
354         new_freq = SAMPLING_500HZ;
355       break;
356       case 250:
357         new_freq = SAMPLING_250HZ;
358       break;
359       case 200:
360         new_freq = SAMPLING_200HZ;
361       break;
362       case 166:
363         new_freq = SAMPLING_166HZ;
364       break;
365       case 125:
366         new_freq = SAMPLING_125HZ;
367       break;
368       case 100:
369         new_freq = SAMPLING_100HZ;
370       break;
371       case 50:
372         new_freq = SAMPLING_50HZ;
373       break;
374       case 10:
375         new_freq = SAMPLING_10HZ;
376       break;
377     }
378
379     if(new_freq == sample_freq) {
380       signal SensorControl.sampleFrequencyChanged(SUCCESS);
381       return SUCCESS;
382     }
383     new_sample_freq = new_freq;
384     post setSampleFrequency();
385   }
386
387   command uint16_t SensorControl.getSampleFrequency(){
388     switch ( sample_freq ) {
389       case SAMPLING_1000HZ:
390         return 1000;
391       case SAMPLING_500HZ:
392         return 500;
393       case SAMPLING_250HZ:
394         return 250;
395       case SAMPLING_200HZ:
396         return 200;
397       case SAMPLING_166HZ:
398         return 166;
399       case SAMPLING_125HZ:
400         return 125;
401       case SAMPLING_100HZ:
402         return 100;
403       case SAMPLING_50HZ:
404         return 50;
405       case SAMPLING_10HZ:
406         return 10;
407       default:
408         return 0;
409     }
410   }
411
412   task void sendCmdPacket() {
413     atomic if(enable_sending) {
414       call Bluetooth.write(tx_cmd_packet, (tx_cmd_packet[6]+10));
415       atomic enable_sending = FALSE;
416       cmdPacketPending = FALSE;
417     } 
418     else
419       cmdPacketPending = TRUE;
420   }
421
422   event result_t SerialCommandParser.responseReady(const uint8_t *buf, uint16_t len) {
423     uint16_t crc;
424     tx_cmd_packet[0] = FRAMING_BOF;
425     tx_cmd_packet[1] = SHIMMER_REV1;
426     tx_cmd_packet[2] = COMMAND_DATA_TYPE;
427     tx_cmd_packet[3]++; /* increment sequence number */ 
428     tx_cmd_packet[4] = tx_cmd_packet[5] = 0; /* no use for time stamp */
429     tx_cmd_packet[6] = len;
430     memcpy(&tx_cmd_packet[7], buf, len);
431     crc = calc_crc(&tx_cmd_packet[1], ((10+len)-FRAMING_SIZE));
432     tx_cmd_packet[len+7] = crc & 0xff;
433     tx_cmd_packet[len+8] = (crc >> 8) & 0xff;
434     tx_cmd_packet[len+9] = FRAMING_EOF;
435     post sendCmdPacket();
436     return SUCCESS;
437   }
438
439 #ifdef LOW_BATTERY_INDICATION
440   
441   task void sendBattMessage() {
442     atomic if(enable_sending) {
443       call Bluetooth.write(&tx_packet[1], FIXED_PACKET_SIZE);
444       atomic enable_sending = FALSE;
445       battPacketPending = FALSE;
446     }
447     else
448       battPacketPending = TRUE;
449   }
450
451   task void sendBatteryLowIndication() {
452     uint16_t crc;
453     char batt_low_str[] = "BATTERY LOW!";
454
455     /* stop all sensing - battery is below the threshold */
456     call SampleTimer.stop();
457     call ActivityTimer.stop();
458     call DMA0.ADCstopConversion();
459     call AccelStdControl.stop();
460     call Leds.yellowOff();
461
462     /* send the battery low indication packet to MOBIUS */
463     tx_packet[1] = FRAMING_BOF;
464     tx_packet[2] = SHIMMER_REV1;
465     tx_packet[3] = STRING_DATA_TYPE;
466     tx_packet[4]++; /* increment sequence number */ 
467     tx_packet[5] = timestamp0 & 0xff;
468     tx_packet[6] = (timestamp0 >> 8) & 0xff;
469     tx_packet[7] = FIXED_PAYLOAD_SIZE;
470     memcpy(&tx_packet[8], &batt_low_str[0], 12);
471
472 #ifdef DEBUG_LOW_BATTERY_INDICATION
473     tx_packet[8] = (baseline_voltage) & 0xff;
474     tx_packet[9] = ((baseline_voltage) >> 8) & 0xff;
475 #endif /* DEBUG_LOW_BATTERY_INDICATION */
476     
477     crc = calc_crc(&tx_packet[2], (FIXED_PACKET_SIZE-FRAMING_SIZE));
478     tx_packet[FIXED_PACKET_SIZE - 2] = crc & 0xff;
479     tx_packet[FIXED_PACKET_SIZE - 1] = (crc >> 8) & 0xff;
480     tx_packet[FIXED_PACKET_SIZE] = FRAMING_EOF;
481
482     /* re-initialise baseline voltage measurement stuff */
483     need_baseline_voltage = TRUE;
484     num_baseline_voltage_samples = baseline_voltage = sum_batt_volt_samples = 0;
485     call Leds.orangeOn();
486
487     post sendBattMessage();
488   }
489
490   /* all samples are got so set the baseline voltage for this SHIMMER hardware */
491   void setBattVoltageBaseline() {
492     baseline_voltage = (sum_batt_volt_samples / TOTAL_BASELINE_BATT_VOLT_SAMPLES_TO_RECORD);
493   }
494
495   /* check voltage level and if it is low then stop sampling, send message and disconnect */
496   void checkBattVoltageLevel(uint16_t battery_voltage) {
497 #ifndef DEBUG_LOW_BATTERY_INDICATION
498     if(battery_voltage < (baseline_voltage-BATTERY_LOW_INDICATION_OFFSET)) {
499 #else
500     if(debug_counter++ == 2500) {
501 #endif /* DEBUG_LOW_BATTERY_INDICATION */
502       linkDisconnecting = TRUE;
503     }
504   }
505
506   /* keep checking the voltage level of the battery until it drops below the offset */
507   void monitorBattery() {
508     uint16_t battery_voltage;
509     if(current_buffer == 1) {
510       battery_voltage = sbuf0[6];
511     }
512     else {
513       battery_voltage = sbuf1[6];
514     }
515     if(need_baseline_voltage) {
516       num_baseline_voltage_samples++;      
517       if(num_baseline_voltage_samples <= TOTAL_BASELINE_BATT_VOLT_SAMPLES_TO_RECORD) {
518         /* add this sample to the total so that an average baseline can be obtained */
519         sum_batt_volt_samples += battery_voltage;
520       }
521       else {
522         setBattVoltageBaseline();
523         need_baseline_voltage = FALSE;
524         call Leds.orangeOff();
525       }
526     }
527     else {
528       checkBattVoltageLevel(battery_voltage);
529     }
530   }
531 #endif /* LOW_BATTERY_INDICATION */
532
533
534   /* The MSP430 CPU is byte addressed and little endian */
535   /* packets are sent little endian so the word 0xABCD will be sent as bytes 0xCD 0xAB */
536   void preparePacket() {
537     uint16_t *p_packet, *p_ADCsamples, crc;
538     
539     tx_packet[1] = FRAMING_BOF;
540     tx_packet[2] = SHIMMER_REV1;
541     tx_packet[3] = PROPRIETARY_DATA_TYPE;
542     tx_packet[4]++; /* increment sequence number */ 
543
544     tx_packet[7] = FIXED_PAYLOAD_SIZE;
545
546     p_packet = (uint16_t *)&tx_packet[8];
547       
548     if(current_buffer == 1) {
549       p_ADCsamples = &sbuf0[0];
550       tx_packet[5] = timestamp0 & 0xff;
551       tx_packet[6] = (timestamp0 >> 8) & 0xff;
552     }
553     else {
554       p_ADCsamples = &sbuf1[0];
555       tx_packet[5] = timestamp1 & 0xff;
556       tx_packet[6] = (timestamp1 >> 8) & 0xff;
557     }
558     /* copy all the data samples into the outgoing packet */
559     *p_packet++ = *p_ADCsamples++; //tx_packet[8]
560     *p_packet++ = *p_ADCsamples++; //tx_packet[10]
561     *p_packet++ = *p_ADCsamples++; //tx_packet[12]
562     *p_packet++ = *p_ADCsamples++; //tx_packet[14]
563     *p_packet++ = *p_ADCsamples++; //tx_packet[16]
564     *p_packet = *p_ADCsamples; //tx_packet[18]
565
566 /* debug stuff - capture battery voltage to monitor discharge */
567 #ifdef DEBUG_LOW_BATTERY_INDICATION
568     if(current_buffer == 1) {
569       tx_packet[18] = (sbuf0[6]) & 0xff;
570       tx_packet[19] = ((sbuf0[6]) >> 8) & 0xff;
571     }
572     else {
573       tx_packet[18] = (sbuf1[6]) & 0xff;
574       tx_packet[19] = ((sbuf1[6]) >> 8) & 0xff;
575     }
576 #endif /* LOW_BATTERY_INDICATION */
577
578     crc = calc_crc(&tx_packet[2], (FIXED_PACKET_SIZE-FRAMING_SIZE));
579     tx_packet[FIXED_PACKET_SIZE - 2] = crc & 0xff;
580     tx_packet[FIXED_PACKET_SIZE - 1] = (crc >> 8) & 0xff;
581     tx_packet[FIXED_PACKET_SIZE] = FRAMING_EOF;
582   }
583
584
585   task void sendSensorData() {
586 #ifdef LOW_BATTERY_INDICATION
587     monitorBattery();
588 #endif /* LOW_BATTERY_INDICATION */
589
590     atomic if(enable_sending) {
591       preparePacket();
592
593       /* send data over the air */
594       call Bluetooth.write(&tx_packet[1], FIXED_PACKET_SIZE);
595       atomic enable_sending = FALSE;
596     }
597   }
598
599   task void startSensing() {
600     register uint16_t i;
601     signal SensorControl.streamingStarted(SUCCESS);
602     for(i = 0; i < 400 ; i++) // give the receiver a chance to receive the command response
603       TOSH_uwait(5000);
604
605     call ActivityTimer.start(TIMER_REPEAT, 1000);
606     call AccelStdControl.start();
607     call Accel.setSensitivity(RANGE_4_0G);
608
609     call SampleTimer.start(TIMER_REPEAT, sample_freq);
610
611     TOSH_CLR_PROG_OUT_PIN();   // gyro enable low
612     sampleADC();
613     sensor_sampling = TRUE;
614   }
615
616   task void sendPersonality() {
617     atomic if(enable_sending) {
618       /* send data over the air */
619       call Bluetooth.write(&personality[0], 17);
620       atomic enable_sending = FALSE;
621     }
622   }
623
624   task void stopSensing() {
625     call SampleTimer.stop();
626     call ActivityTimer.stop();
627     call DMA0.ADCstopConversion();
628     call AccelStdControl.stop();
629     call Leds.yellowOff();
630     signal SensorControl.streamingStopped(SUCCESS);
631     sensor_sampling = FALSE;
632   }
633
634   async event void Bluetooth.connectionMade(uint8_t status) { 
635     atomic enable_sending = TRUE;
636     call Leds.greenOn();
637   }
638
639   async event void Bluetooth.commandModeEnded() { 
640     atomic command_mode_complete = TRUE;
641   }
642     
643   async event void Bluetooth.connectionClosed(uint8_t reason){
644     atomic enable_sending = FALSE;    
645     call Leds.greenOff();
646     //call Leds.redOn();
647     post stopSensing();
648   }
649
650   async event void Bluetooth.dataAvailable(uint8_t data){
651     call SerialCommandParser.handleByte(data);
652   }
653
654   event void Bluetooth.writeDone(){
655     atomic enable_sending = TRUE;
656
657 #ifdef LOW_BATTERY_INDICATION
658     if(linkDisconnecting) {
659       linkDisconnecting = FALSE;
660       /* signal battery low to master and let the master disconnect the link */
661       post sendBatteryLowIndication();
662       return;
663     }
664     atomic if(battPacketPending) {
665       post sendBattMessage();
666     }
667
668 #endif /* LOW_BATTERY_INDICATION */
669     atomic if(cmdPacketPending) {
670       post sendCmdPacket();
671     }
672   }
673
674   event result_t ActivityTimer.fired() {
675       atomic {
676         /* toggle activity led every second */
677         if(activity_led_on) {
678           call Leds.yellowOn();
679           activity_led_on = FALSE;
680         }
681         else {
682           call Leds.yellowOff();
683           activity_led_on = TRUE;
684         }
685       }
686     return SUCCESS;
687   }
688
689   event result_t SampleTimer.fired() {
690     call DMA0.beginTransfer();
691     call DMA0.ADCbeginConversion();
692     return SUCCESS;
693   }
694
695   async event void DMA0.transferComplete() {
696     dma_blocks++;
697     //atomic DMA0DA += 12;
698     if(dma_blocks == 1){ //this should be about 6 but for this test its 1
699       dma_blocks = 0;
700
701       if(current_buffer == 0){
702         atomic DMA0DA = (uint16_t)&sbuf1[0];
703         atomic timestamp1 = call LocalTime.read();
704         current_buffer = 1;
705       }
706       else { 
707         atomic DMA0DA = (uint16_t)&sbuf0[0];
708         atomic timestamp0 = call LocalTime.read();
709         current_buffer = 0;
710       }
711       post sendSensorData();      
712     }
713   }
714
715   async event void DMA0.ADCInterrupt(uint8_t regnum) {
716     // we should *not* see this, as the adc interrupts are eaten by the dma controller!
717     /* Turn on all LEDs */
718     call Leds.set(0x0F);
719   } 
720 }
721