[Tinyos-contrib-commits] CVS: tinyos-1.x/contrib/handhelds/apps/FTP_DataLogger FTP_DataLogger.nc, NONE, 1.1 FTP_DataLoggerM.nc, NONE, 1.1 Makefile, NONE, 1.1 README, NONE, 1.1 crc16.h, NONE, 1.1 shimmerDisk.c, NONE, 1.1 shimmerSerial.c, NONE, 1.1 shimmerSerial.h, NONE, 1.1

steve ayer ayer1 at users.sourceforge.net
Thu Mar 27 13:05:15 PDT 2008


Update of /cvsroot/tinyos/tinyos-1.x/contrib/handhelds/apps/FTP_DataLogger
In directory sc8-pr-cvs10.sourceforge.net:/tmp/cvs-serv4716/FTP_DataLogger

Added Files:
	FTP_DataLogger.nc FTP_DataLoggerM.nc Makefile README crc16.h 
	shimmerDisk.c shimmerSerial.c shimmerSerial.h 
Log Message:

first check-in of stephen linder's serial data collection utility,
which was developed to work sensibly on a windows platform but should
work on linux.

extensive notes in README.



--- NEW FILE: FTP_DataLogger.nc ---
/*
 * Copyright (c) 2007, Intel Corporation
 * 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. 
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution. 
 *
 * Neither the name of the Intel Corporation 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
 *
 *   Author:  Stephen Linder
 *            August, 2007
 * 
 * started from work by Jason Waterman during the summer of 2007
 */

configuration FTP_DataLogger {
}
implementation {
  components Main, 
    FTP_DataLoggerM, 
    PowerSupplyMonitorC,
    UserButtonC,
    TimerC,
    HPLUARTC, 
    HPLUSART0M,
    LedsC,
    DMA_M,
    MMA7260_AccelM,
    DS2411LiteM,			// module \tos\system\DS2411LiteM.nc
	SD_DMA_C;

 // if you want to have the init, start and stop functions of the StdControl
 // interface to be called automatically you must wire them here. 
 // Because the SD card interface was originally not wired I developed all the
 // code with out using this feature  SPL 2-25-08  Main.StdControl -> FTP_DataLoggerM;
  Main.StdControl -> FTP_DataLoggerM;
  Main.StdControl -> UserButtonC;
  Main.StdControl -> TimerC;

  FTP_DataLoggerM.PSMStdControl -> 		PowerSupplyMonitorC;
  FTP_DataLoggerM.PowerSupplyMonitor -> PowerSupplyMonitorC;

  FTP_DataLoggerM.Button -> 			UserButtonC.UserButton;

  FTP_DataLoggerM.sampleTimer -> 		TimerC.Timer[unique("Timer")];
  FTP_DataLoggerM.blinkRunAndPowerLEDTimer -> TimerC.Timer[unique("Timer")];
  FTP_DataLoggerM.blinkGreenTimer -> 	TimerC.Timer[unique("Timer")];
  FTP_DataLoggerM.IDChip            ->  DS2411LiteM.IDChip;
  									
  FTP_DataLoggerM.HPLUART -> 			HPLUARTC;
  FTP_DataLoggerM.USARTControl -> 		HPLUSART0M;

  FTP_DataLoggerM.Leds -> 				LedsC;
  FTP_DataLoggerM.LocalTime -> 			TimerC;
  FTP_DataLoggerM.SD -> 				SD_DMA_C;
  FTP_DataLoggerM.DMA0 -> 				DMA_M.DMA[0];
  FTP_DataLoggerM.AccelStdControl   -> 	MMA7260_AccelM;
  FTP_DataLoggerM.Accel             -> 	MMA7260_AccelM;
}

--- NEW FILE: FTP_DataLoggerM.nc ---
/*
 * Copyright (c) 2007, Intel Corporation
 * 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. 
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution. 
 *
 * Neither the name of the Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
[...968 lines suppressed...]
	result_t sendNextSerialByte() {
		bool busy;

	    atomic {
	       busy = (bytePending == TRUE);
	    }
	    if (busy) {
	       return FAIL;
	    }
	    if (head == tail) {
	       return SUCCESS; // buffer is empty
	    }
	    atomic bytePending = TRUE;
	    call HPLUART.put(serialBuffer[tail]);
	    return SUCCESS;
  	} 

	async event void SD.available() {}
	async event void SD.unavailable() {}
}

--- NEW FILE: Makefile ---
# $Id: Makefile,v 1.1 2008/03/27 20:05:13 ayer1 Exp $
#
# Copyright (c) 2007, Intel Corporation
# 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.
#
# Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# Neither the name of the Intel Corporation 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
#
#   Author:  Jason Waterman
#            July, 2007

COMPONENT=FTP_DataLogger
PFLAGS=-DDEFAULT_BAUDRATE=115200
# PFLAGS += -g
include ../Makerules

--- NEW FILE: README ---

Data Logging to SD Card

Stephen Paul Linder

December 2007

spl at alum.mit.edu

 

The FTP_DataLogger TinyOS application for SHIMMER I  logs data from the
three axis accelerometer to the SD card.  Data is saved into 512-byte
blocks. Each block has 84-data sets, a time stamp, experimental ID
number and 16-bit CRC.

 

Data that has been saved on the SD card can be downloaded from the
SHIMMER over the USB connection to the docking station. Significantly
faster download speeds can be  obtained by removing the SD card and
using a card reader for the data download. Every attempt has been made
to recover gracefully from intermittent faults writing to the SD card
because of mechanical vibration, etc.

 

SHIMMER2 should also support this application but you may want to use
the FAT_DataLogger application instead. It stores the data in a FAT
readable file.

 


    Starting up

The SHIMMER is controlled using the /ss.exe / program compiled from the
/shimmerSerial.c/. It shares a /shimmerSerial.h/ header file with the
SHIMMER-side software.  The /shimmerSerial.c/ was written under Cygwin
and should compile and run under Linux. Compile by using /gcc/

 

       gcc shimmerSerial.c -o ss.exe

 

Place the SHIMMER in the dock station. Reset the SHIMMER and confirm
that the yellow LED is blinking. Confirm that the serial link to the
SHIMMER (thru the USB interface) is working by toggling the red LED on
the SHIMMER

 

       ./ss.exe –d

 

The response to this command is

 

$ ./ss  -d

Shimmer Serial version 1.00

 

Attempting port /dev/ttyS3

Port /dev/ttyS3 open to Shimmer.

Toggling red LED ...

Closing port

 

The SHIMMER docking station uses a FTDI chip to interface the SHIMMER’s
serial port to the USB port. FTDI provides a device driver that maps the
USB port to a virtual serial port. / ss.exe/ will search through the
first ten serial ports to find the SHIMMER. Sometimes you may need to
specify the serial port. You can do this using /–p/ option.

 

./ss.exe -p /dev/ttyS3 –d

 

The /–p/ option must be the first option.

 


    Initiating Data Collection

Start  data collection by placing the SHIMMER in the dock station. Reset
the SHIMMER and confirm that the yellow LED is blinking.

 

Run /ss.exe/ under Cygwin with the following option to commence data logging

 

       ./ss.exe -A "Shimmer ID String"   // Linux

 

To run /ss.exe/ on a Windows PC without Cygqin, have the cyqwin1.dll in
the same subdirectory as ss.exe.

 

       ss -A "Shimmer ID String"                      

 

When data is being collected the green LED blinks every time a data
block is saved to the SD card. Each block is save with a single time
stamp and an experimental ID.  


    Terminating Data Collection

Data collection can be terminated normally by inserting the SHIMMER in
the docking station and depressing the user button (the button furthest
from the USB connector). The LEDs then stop blinking and the green LED
remains on.

 

When data collection is done this way you will have a status

 

/Data collection completed normally/

 

Data collection will also terminate when the battery monitor detects a
low battery conditions. When this occurs the status becomes

 

/Shimmer powered down because of low battery voltage /

 

Unexpected termination either because of a hardware fault causing an
abnormal program termination or possible software error will result in

 

/Data collection terminated without setting status/

 

When this occurs SHIMMER is unable to save the number of blocks of data
collected on the header block of the SHIMMER. Therefore, /ss.exe/ must
use the experimental ID to search sequentially for all the data that was
logged during the current experiment. The experimental ID is saved with
every data block and consists of the lower sixteen bits of the starting
time of the experiment in seconds from the start of the UNIX epoch.


    Downloading Data to PC

Data is downloaded using the /–F/ option

 

$ ./ss -F >t.txt

 

A successful download produces the following output

 

$ ./ss -F >t.txt

Shimmer Serial version 1.00

Attempting port /dev/ttyS3

Port /dev/ttyS3 open to Shimmer.

Shimmer Serial version 1.00

Shimmer Type: 3-axis accel

Release Date: 14-Nov-07

Shimmer ID: a third turntable test

Shimmer Status: Data collection completed normally

Starting time of data collection: Tue Dec 18 20:06:46 2007

SHIMMER collected 0 minutes of data in 2 blocks.

/../

Closing port

/ /

During the download the green and orange on the SHIMMER blink with every
block downloaded. On the PC-side a “.” is printed for each block downloaded.

 

If data logging was terminated unexpectedly you will get the following
type of output

 

$ ./ss -F >t.txt

Shimmer Serial version 1.00

Attempting port /dev/ttyS3

Port /dev/ttyS3 open to Shimmer.

Shimmer Type: 3-axis accel

Release Date: 14-Nov-07

Shimmer ID: a third turntable test

Shimmer Status: Data collection terminated without setting status.

Starting time of data collection: Tue Dec 18 20:09:38 2007

SHIMMER collected 117440511 minutes of data in -1 blocks.

 

Header block indicates that the data collection was interrupted.

 Retrieving data blocks that have a experimental ID of 28498 .

..

Block ID does not match, trying next block.

.

Block ID does not match, trying next block.

.

Block ID does not match, Stopping data dump.

 

Closing port

/ /

Finally you should ensure that the version of /.///ss/ is the same as
the software running on the SHIMMER. You will see an error message if
they are not the same. Running with different version might result in
the data saved on the SD card not being saved correctly. You will
receive the following error message

 

WARNING SOFTWARE VERSIONS DO NOT MATCH.

Shimmer firmware: 1.00, PC software: 1.10

  Data fields are possibly misaligned. Check if data looks reasonable.

 

Data is not erased after download and can be downloaded multiple times.

 

The output file is space delimited and can be read by Matlab. Look at
plotData.m for an

example.

 

Column 1         time      e.g. 1193179481.099

Column  2-4     raw data e.g. 2883 2276 2473

 


    Increasing download speeds

The download speed obtained is quiet variable with the fastest speeds
obtained using Linux. Michael Healy was able to achieve the following
results downloading 10 minutes of data

 

* *

	

*10 minutes (366 blocks)*

 

	

*Linux*

	

*Cygwin*

*No USB Hub*

	

16s

	

571s

*IOGEAR GUH275 USB Hub(USB 2.0)*

	

16s

	

65s

 

When using Cygwin the data transfer is always faster when the docking
station is connected to a USB hub.  This has been isolated to a problem
with Cygwin not Windows.

 


      Downloading Data using a SD Card Reader

If your applications allows you to remove your SD card the data can be
downloaded significantly faster by removing the SD card and placing it
in a card reader. The program sd.exe can then be used to read the data. 
Compile sd.exe be

 

$ gcc shimmerDisk.c -o sd

 

Usage is

 

 ./sd <devname>

Give the name of the device  that has the SD card with the SHIMMER data

Example device names would be /dev/sdb for the second hard drive

                              /dev/sdc for the third hard drive

 

The SD card is accessed as an attached disk. The device letter for the
disk is usually less than the drive letter given to the reader by MS
Windows. If you inadvertently try to download your  hard drive you will
get the following error message

 

$ ./sd /dev/sda >t.txt

Shimmer Disk version 1.00

 

Attempting to access /dev/sda

ERROR: bad header block. Try again.

 

While every effort has been made to keep the ss.exe and sd.exe
synchronized they may respond differently to error conditions on the SD
card.


    Miscellaneous Details


      Testing

We use a phonograph turntable to test the SHIMMERs. You should see a
continuous sine wave from at least two of the three channels if the
turntable is tilted.


      Power Management

After a successful reset the yellow LED blink. When the Shimmer senses a
lower power condition the red LED begins a double blink pattern: two
short blinks, a long pause and then repeat. During this condition the
accelerometer output sags as seen in the figure below.

 

 

 

In this example the sag is less than 10%.  As a precaution the header
block is updated to the SD card with the number of data blocks save up
to this point.

 

When the power level reaches a critical level the Shimmer attempts to
update the SD card again, and then enters a low power state with no LEDs
lit and no data is saved. The Shimmers battery should be recharged as
quickly as possible.

 

If the SHIMMER’s lithium ion battery is over discharged the factory
warranty is void and the battery may be either hard to charge or it’s
performance greatly degraded.

 

SHIMMERs running FTP_DataLogger  should be able to collect data for over
one week. Time will vary depending on

    * temperature: warmer temperatures should increase battery life
    * Age and condition of battery: newer battery that has not been over
      discharge should do better.
    * Battery charger: charger may not fully charge battery
    * Bluetooth module: removal of module will increase battery life

 

*WARNING*

Sometimes the low voltage detection comes on just when the SHIMMER has
been configured to collected data. If this is the case try again. It
appears to happen after the SHIMMER is charged and the battery is full.

 


      Notes

 

As of December  18^th , 2007:

 

Click on the file ignoreFTDISerialNumber.reg to update the Microsoft
Windows registry to have all of your docking station appear the same to
Windows.

 

* *

 

 

 


--- NEW FILE: crc16.h ---
#ifndef CRC16_H_
#define CRC16_H_

// CCITT CRC16 lookup table
uint16_t CRC_table[] = {
    0x0000,  0x1021,  0x2042,  0x3063,  0x4084,  0x50a5,  0x60c6,  0x70e7,
    0x8108,  0x9129,  0xa14a,  0xb16b,  0xc18c,  0xd1ad,  0xe1ce,  0xf1ef,
    0x1231,  0x0210,  0x3273,  0x2252,  0x52b5,  0x4294,  0x72f7,  0x62d6,
    0x9339,  0x8318,  0xb37b,  0xa35a,  0xd3bd,  0xc39c,  0xf3ff,  0xe3de,
    0x2462,  0x3443,  0x0420,  0x1401,  0x64e6,  0x74c7,  0x44a4,  0x5485,
    0xa56a,  0xb54b,  0x8528,  0x9509,  0xe5ee,  0xf5cf,  0xc5ac,  0xd58d,
    0x3653,  0x2672,  0x1611,  0x0630,  0x76d7,  0x66f6,  0x5695,  0x46b4,
    0xb75b,  0xa77a,  0x9719,  0x8738,  0xf7df,  0xe7fe,  0xd79d,  0xc7bc,
    0x48c4,  0x58e5,  0x6886,  0x78a7,  0x0840,  0x1861,  0x2802,  0x3823,
    0xc9cc,  0xd9ed,  0xe98e,  0xf9af,  0x8948,  0x9969,  0xa90a,  0xb92b,
    0x5af5,  0x4ad4,  0x7ab7,  0x6a96,  0x1a71,  0x0a50,  0x3a33,  0x2a12,
    0xdbfd,  0xcbdc,  0xfbbf,  0xeb9e,  0x9b79,  0x8b58,  0xbb3b,  0xab1a,
    0x6ca6,  0x7c87,  0x4ce4,  0x5cc5,  0x2c22,  0x3c03,  0x0c60,  0x1c41,
    0xedae,  0xfd8f,  0xcdec,  0xddcd,  0xad2a,  0xbd0b,  0x8d68,  0x9d49,
    0x7e97,  0x6eb6,  0x5ed5,  0x4ef4,  0x3e13,  0x2e32,  0x1e51,  0x0e70,
    0xff9f,  0xefbe,  0xdfdd,  0xcffc,  0xbf1b,  0xaf3a,  0x9f59,  0x8f78,
    0x9188,  0x81a9,  0xb1ca,  0xa1eb,  0xd10c,  0xc12d,  0xf14e,  0xe16f,
    0x1080,  0x00a1,  0x30c2,  0x20e3,  0x5004,  0x4025,  0x7046,  0x6067,
    0x83b9,  0x9398,  0xa3fb,  0xb3da,  0xc33d,  0xd31c,  0xe37f,  0xf35e,
    0x02b1,  0x1290,  0x22f3,  0x32d2,  0x4235,  0x5214,  0x6277,  0x7256,
    0xb5ea,  0xa5cb,  0x95a8,  0x8589,  0xf56e,  0xe54f,  0xd52c,  0xc50d,
    0x34e2,  0x24c3,  0x14a0,  0x0481,  0x7466,  0x6447,  0x5424,  0x4405,
    0xa7db,  0xb7fa,  0x8799,  0x97b8,  0xe75f,  0xf77e,  0xc71d,  0xd73c,
    0x26d3,  0x36f2,  0x0691,  0x16b0,  0x6657,  0x7676,  0x4615,  0x5634,
    0xd94c,  0xc96d,  0xf90e,  0xe92f,  0x99c8,  0x89e9,  0xb98a,  0xa9ab,
    0x5844,  0x4865,  0x7806,  0x6827,  0x18c0,  0x08e1,  0x3882,  0x28a3,
    0xcb7d,  0xdb5c,  0xeb3f,  0xfb1e,  0x8bf9,  0x9bd8,  0xabbb,  0xbb9a,
    0x4a75,  0x5a54,  0x6a37,  0x7a16,  0x0af1,  0x1ad0,  0x2ab3,  0x3a92,
    0xfd2e,  0xed0f,  0xdd6c,  0xcd4d,  0xbdaa,  0xad8b,  0x9de8,  0x8dc9,
    0x7c26,  0x6c07,  0x5c64,  0x4c45,  0x3ca2,  0x2c83,  0x1ce0,  0x0cc1,
    0xef1f,  0xff3e,  0xcf5d,  0xdf7c,  0xaf9b,  0xbfba,  0x8fd9,  0x9ff8,
    0x6e17,  0x7e36,  0x4e55,  0x5e74,  0x2e93,  0x3eb2,  0x0ed1,  0x1ef0,
};
 
uint16_t updcrc(uint16_t p_crc, char* cp, int size)
{
	uint16_t	crc = p_crc;

	while (size-- > 0) {
		uint16_t partOne = (crc  << 8) & 0xFF00;
		uint16_t aByte = *cp++ & 0xFF;
		crc = partOne ^ CRC_table[(crc>>8) ^ aByte];
	}
	return (crc);
}
//  Calculate CCITT CRC16.
uint16_t  CRC16(char* buffer, int byteSize)
{
	return updcrc(0x0000, buffer, byteSize);
}



#endif /*CRC16_H_*/

--- NEW FILE: shimmerDisk.c ---
#include <stdlib.h>  /* Standard library */
#include <stdio.h>   /* Standard input/output definitions */
#include <string.h>  /* String function definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <fcntl.h>   /* File control definitions */
#include <errno.h>   /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
#include <time.h>
#include <math.h>
#include <stdint.h>
#include "shimmerSerial.h"
#include "crc16.h"

void getAndPrintAllDataBlocks ();
void printADCdata(	FILE*		fd,
					char* 		buffer,
					time_t* 	LinuxStartTimeSec,
					uint32_t 	firstBlockShimmerTime,
					time_t* 	LinuxBlockTimeSec,
					BOOL*    	blockOutOfSequenceFlag);

char* getDataDiskBlock( FILE* filePointer, uint blockNumber, char buffer[]);

void getHeaderBlock (FILE* filePointer,
					 dataCollectionStatus_t* status,
					 uint32_t* blocksToRead,
					 time_t* LinuxstartTimeSec);

//#define _DEBUG_SERIAL
//////////////////////////////////////////////////////////////////////////
int main( int argc, char ** argv ) {

	fprintf (stderr,
		"Shimmer Disk version %s \n\n", SHIMMER_VERSION);

	///////////////////////////////////////////////////////////////////
	// error checking
	HEADER_BLOCK_STRUCTURE headerBlock;
	if (sizeof(headerBlock) != BLOCK_LENGTH) {
		fprintf (stderr,
		    "\nERROR: header block structure length: %i, is not equal to block length: %i\n\n",
			sizeof(headerBlock), BLOCK_LENGTH);
	}
	DATA_BLOCK_STRUCTURE dataBlock;
	if (sizeof(dataBlock) != BLOCK_LENGTH) {
		fprintf (stderr,
		    "\nERROR: data block structure length: %i, is not equal to block length: %i\n\n",
			sizeof(dataBlock), BLOCK_LENGTH);
	}
	///////////////////////////////////////////////////////////////////
	  char deviceName[128];

	  /* get device name */
	  if (argc == 2) {
		  strcpy( deviceName, argv[1] );
		  fprintf (stderr, "Attempting to access %s \n", deviceName);
	  } else {
			fprintf (stderr, "SHIMMER Disk Data Parser\n");
		    fprintf (stderr, "Usage %s <devname>\n", argv[0] );
			fprintf (stderr, "Give the name of the device  that has the SD card with the SHIMMER data\n");
		    fprintf (stderr, "Example device names would be /dev/sdb for the second hard drive\n");
		    fprintf (stderr, "                              /dev/sdc for the third hard drive\n");
		    exit (0);
	  }

	  FILE* filePointer = fopen(deviceName, "rb");
	if (filePointer == NULL)  {
	    perror ("Unable to open port to disk containing SHIMMER data");
		exit(0);
	}
	getAndPrintAllDataBlocks (filePointer);
 	fprintf (stderr, "Closing file");
	fclose (filePointer);
	exit(0);
}

// get all the data blocks from Shimmer
////////////////////////////////////////////////////
void getAndPrintAllDataBlocks (FILE* filePointer) {
	DATA_BLOCK_STRUCTURE 	block;
	uint32_t 				i;
	dataCollectionStatus_t 	status;
	uint32_t  				blocksToRead;
	time_t  				LinuxStartTimeSec;
	uint32_t  				firstBlockShimmerTime;
	time_t  				LinuxBlockTimeSec;
	uint32_t				experimentID;
	BOOL					ignoreBlocksToReadFlag;
	BOOL					timeStampOutOfSequence = FALSE;
	#define BLOCK_MESSAGE_FREQUENCY 50

	memset(&block, 1, sizeof(block));
	getHeaderBlock(filePointer, &status, &blocksToRead, &LinuxStartTimeSec);

	// need to subtract the timeStamp from the first block
	// from all subsequent blocks
	getDataDiskBlock(filePointer, FIRST_DATA_BLOCK_OFFSET, (char*) &block);
	firstBlockShimmerTime = block.ShimmerTime;
	LinuxBlockTimeSec = LinuxStartTimeSec ;
	experimentID = LinuxStartTimeSec & 0xFFFF;


	if ( (status == nullStatus) ||
		 (blocksToRead == 0)    ) {
		ignoreBlocksToReadFlag = TRUE;
		fprintf (stderr,
			"\n\nHeader block indicates that the data collection was interrupted. \n" );
		fprintf (stderr,
			" Retriving data blocks that have a experminent ID of %d . \n\n",
			(unsigned int)experimentID );

	} else {
		ignoreBlocksToReadFlag = FALSE;
	}

	i = FIRST_DATA_BLOCK_OFFSET;

	while (	i < FIRST_DATA_BLOCK_OFFSET + blocksToRead ||
			(ignoreBlocksToReadFlag	&& experimentID == block.experimentID )	 ) {

		if( (i % BLOCK_MESSAGE_FREQUENCY ) == 0  )  {
			fprintf (stderr, "\nRequesting data collected at %s .",
				ctime(&LinuxBlockTimeSec));

		} else {
			fprintf (stderr, ".");
		}
		if (getDataDiskBlock(filePointer, i, (char*) &block) ) {
			if (experimentID == block.experimentID) {
				// side effect is to change timeOffset when there
				// is a shimmer clock overflow and
				// to set timeStampOutOf Sequence flag
				printADCdata(stdout, (char*) &block,
							&LinuxStartTimeSec, firstBlockShimmerTime,
							&LinuxBlockTimeSec,
							&timeStampOutOfSequence);
			} else if (block.experimentID != 0) {
			  fprintf (stderr,
					"\nBlock ID does not match, Stopping data dump. \n\n");
			} else {
				fprintf (stderr,
					"\nBlock ID of block %i is zero. Continuing data dump. \n\n",
					(unsigned int)i);
			}
			if(timeStampOutOfSequence) {
				fprintf (stderr,
					"\nTime stamp of block %i is out of sequence. Continuing data dump. \n\n",
					(unsigned int)i);
			}
			i++;
		}
	}
	fprintf (stderr, "\n");
}
// write the ADC data to the file descriptor
// Format of each line
// 			time x  y  z
// the separator between fields is given by SEPARATOR
//
// main task is keeping track of time.
//		 zero the shimmer time - the shimmer time of the first block is really zero
// 		 overflows - shimmer time overflows.
////////////////////////////////////////////////////
void printADCdata(	FILE*		fd,
					char* 		buffer,
					time_t* 	LinuxStartTimeSec,
					uint32_t 	firstBlockShimmerTime,
					time_t* 	LinuxBlockTimeSec,
					BOOL*    	blockOutOfSequenceFlag) {

	char 					SEPARATOR[] = " ";
	int 					i;
	SAMPLE_STRUCTURE* 		samples;
	static double 			deltaTime = (double)ADC_TIMER_PERIOD_MSEC / TINYOS_TIMER_TICS_SEC;
	static double 			clockInverted = 1.0 / ((double) TINYOS_CLOCK_TICS_SEC);
	// number of seconds that can be counted before the TinyOS clock overflows
	// 2^32 / 2^15 = 2^17 = 131072
 	static double 			shimmerClockOverflowPeriodSec = 131072;
	double 					shimmerTimeSec;
	static double 			oldShimmerTimeSec = 0;

#ifdef _DEBUG_SERIAL
	FILE *fdi = fopen("foofoo.exe", "w");
	if(fdi > 0) {
		fwrite (buffer, 1, BLOCK_LENGTH, fdi);
	}
	fclose(fdi);
#endif
	DATA_BLOCK_STRUCTURE* block = (DATA_BLOCK_STRUCTURE*) buffer;

	shimmerTimeSec = (double) ((*block).ShimmerTime - firstBlockShimmerTime) * clockInverted;

	// check for overflow
	// if overflow we need to add time to clock offset
	// this is hard to test because it only happens after 36.4 hours
	double shimmerTimeDifferenceBetweenBlocks = shimmerTimeSec - oldShimmerTimeSec;
	if (shimmerTimeDifferenceBetweenBlocks < 0) {
		*LinuxStartTimeSec += shimmerClockOverflowPeriodSec;
 	}
	 oldShimmerTimeSec = shimmerTimeSec;
	double blockStartTime = *LinuxStartTimeSec + shimmerTimeSec;
	*LinuxBlockTimeSec = (time_t)blockStartTime;

	// keep track of start times of blocks to insure that blocks are insequence
	// initialze to time of first block
	static double			lastBlockStartTime = -1.0;
	if (lastBlockStartTime == -1.0) {
		lastBlockStartTime = blockStartTime;
	}
	double difference = (blockStartTime - lastBlockStartTime);
	if ( difference > 2.0* DURATION_OF_BLOCK_SEC ) {
		*blockOutOfSequenceFlag = TRUE;
		lastBlockStartTime = blockStartTime;
		return;
	} else {
		lastBlockStartTime = blockStartTime;
		*blockOutOfSequenceFlag = FALSE;
	}
	samples = &((*block).data[0]);
	for (i = 0; i < NUMBER_OF_SAMPLES_PER_STRUCTURE; i++) {
		fprintf(fd, "%10.4f", blockStartTime + (double)i * deltaTime);
		fprintf(fd, SEPARATOR);

		fprintf(fd, "%5i", samples[i].x);
		fprintf(fd, SEPARATOR);
		fprintf(fd, "%5i", samples[i].y);
		fprintf(fd, SEPARATOR);
		fprintf(fd, "%5i", samples[i].z);
		fprintf(fd, "\n");
	}
}
// get header block  from Shimmer
////////////////////////////////////////////////////
void getHeaderBlock (FILE* filePointer,
					 dataCollectionStatus_t* status,
					 uint32_t* blocksToRead,
					 time_t* LinuxStartTimeSec) {

	HEADER_BLOCK_STRUCTURE header;
	memset(&header, 1, sizeof(header));

	long byteAddress = (SD_START_BLOCK) * BLOCK_LENGTH;
	// to speed things up this should probably
	// be only done for first block in sequence
	rewind(filePointer);
	size_t len;

	  if(fseek(filePointer, byteAddress, SEEK_SET)) {
	    perror ("Unable to seek to data block");
		exit(0);
	  } else {
		  len = fread((char*) &header, 1, BLOCK_LENGTH, filePointer);
	  }

	// check if block is real SHIMMER data
	uint16_t blockCRC = CRC16( (char*) &header, BLOCK_LENGTH-2);
	if ( (header.CRC) != blockCRC ) {
		fprintf (stderr, "ERROR: SD block has bad CRC. Block read failed. \n");
		fprintf (stderr, "Possible bad SD card or SD card is missing. \n");
		exit(0);
	}


	// blocks written includes the header block
	*status = header.dataCollectionStatus;
	*blocksToRead = header.numberOfBlocksWritten - 1;
	*LinuxStartTimeSec = header.LinuxStartTimeSec;

	if (*LinuxStartTimeSec == 0) {
		fprintf (stderr, "ERROR: bad header block. Try again.\n");
		exit(0);
	}

	if(strcmp(header.ShimmerVer, SHIMMER_VERSION) ) {
		fprintf (stderr, "\n WARNING SOFTWARE VERSIONS DO NOT MATCH.\n");
		fprintf (stderr, "\nShimmer firmware: %s, PC software: %s \n",
						header.ShimmerVer, SHIMMER_VERSION );
		fprintf (stderr, "  Data fields are possibly misaligned. Check if data looks reasonable.\n\n");
	}

	fprintf (stderr, "Shimmer Type: %s \n",
					header.ShimmerType);
	fprintf (stderr, "Release Date: %s \n",
					header.ShimmerDate);
	fprintf (stderr, "Shimmer ID: %s \n",
					header.ShimmerID );
	fprintf (stderr, "Shimmer Status: %s \n",
					STATUS_MESSAGES[*status]);
	fprintf (stderr, "Starting time of data collection: %s",
					ctime(LinuxStartTimeSec));
	fprintf (stderr,
					"SHIMMER collected %d minutes of data in %d blocks. \n",
					(unsigned int)(*blocksToRead * DURATION_OF_BLOCK_SEC / 60),
					(unsigned int)*blocksToRead);
}

// get block of data from Shimmer
////////////////////////////////////////////////////
char* getDataDiskBlock( FILE* filePointer, uint blockNumber, char buffer[]) {

	long byteAddress = (blockNumber + SD_START_BLOCK)
						* BLOCK_LENGTH;
	// to speed things up this should probably
	// be only done for first block in sequence
	rewind(filePointer);
	size_t len;

	  if(fseek(filePointer, byteAddress, SEEK_SET)) {
	    perror ("Unable to seek to data block");
		exit(0);
	  } else {
		  len = fread(buffer, 1, BLOCK_LENGTH, filePointer);
	  }

		// verify that the block has not been corrupted.
		// This is mostly a check of whether there has been a problem with the SD card.
		// Some SD cards do seem to work well with SHIMMER. If the SHIMMER was unable
		// to get a block from the SD card it will light the red LED and send a block of
		// junk data
		DATA_BLOCK_STRUCTURE* block = (DATA_BLOCK_STRUCTURE*)buffer;
		uint16_t blockCRC = CRC16( buffer, BLOCK_LENGTH-2);
		if ( (block -> CRC) != blockCRC ) {
			fprintf (stderr, "ERROR: SD block has bad CRC. Block read failed. \n");
			fprintf (stderr, "Possible bad SD card, SD card is missing or reading past end of data. \n");
			exit(0);
		}
	return buffer;
 }











--- NEW FILE: shimmerSerial.c ---
#include <stdlib.h>  /* Standard library */
#include <stdio.h>   /* Standard input/output definitions */
#include <string.h>  /* String function definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <fcntl.h>   /* File control definitions */
#include <errno.h>   /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
#include <time.h>
#include <math.h>
#include <stdint.h>

//typedef	unsigned char uint8_t;
//typedef	unsigned short int uint16_t;
//typedef	unsigned int uint32_t;

#define BLOCK_MESSAGE_FREQUENCY 50


#include "crc16.h"
#include "shimmerSerial.h"

// FUNCTION PROTOTYPES
int  openSerialPort (char defaultPort[]);
void setPortConfiguration (int fd);
BOOL isShimmer (int fd);

void printHelp ();
void parseCommandLineInputs (int argc, char ** argv);
void initTimeStructure (char* arg, uint32_t* timeSec );

void 		startRecording ();
void 		toggleRedLed ();
uint32_t 	getShimmerTime ();
uint32_t 	getShimmerTimeStartOfDataCollection ();
void 		setShimmerTimeStartOfDataCollection (const uint32_t time);
uint32_t 	calculateShimmerTimeOffset ();
void 		sendHeaderBlock (char* ShimmerID);
void 		getHeaderBlock (dataCollectionStatus_t* status,
					 uint32_t* blocksToRead,
					 uint32_t* LinuxstartTimeSec);

void getAndPrintAllDataBlocks ();
void getAndPrintData (const uint32_t requestTimeSec,
					  const uint32_t* requestedDurationSec);
void getAndPrintDataBlocks (const uint32_t startBlock,
							const uint32_t endBlock,
							const uint32_t LinuxTimeFirstBlockSec);
char* getDataBlock (const uint blockNumber, char buffer[]);

void printADCdata(FILE *fd, char* buffer,
					uint32_t* LinuxstartTimeSec,
					uint32_t firstBlockShimmerTime,
					uint32_t* blockTime,
					BOOL*    blockOutOfSequenceFlag);
void sendUint (int fd, uint blockNumber);

int	 			getSerialBlock (int fd, unsigned char buffer[], int length);
int 			getSerialChar (int fd, char* aChar);

// GLOBALS
int PORT_DESCRIPTOR = -1; // port to Shimmer

//#define _DEBUG_SERIAL
//////////////////////////////////////////////////////////////////////////
int main( int argc, char ** argv ) {

	fprintf (stderr,
		"Shimmer Serial version %s \n\n", SHIMMER_VERSION);

	///////////////////////////////////////////////////////////////////
	// error checking
	HEADER_BLOCK_STRUCTURE headerBlock;
	if (sizeof(headerBlock) != BLOCK_LENGTH) {
		fprintf (stderr,
		    "\nERROR: header block structure length: %i, is not equal to block length: %i\n\n",
			sizeof(headerBlock), BLOCK_LENGTH);
	}
	DATA_BLOCK_STRUCTURE block;
	if (sizeof(block) != BLOCK_LENGTH) {
		fprintf (stderr,
		    "\nERROR: data block structure length: %i, is not equal to block length: %i\n\n",
			sizeof(block), BLOCK_LENGTH);
	}
	///////////////////////////////////////////////////////////////////

	// parse command line input	to determine what to do
	//---------------------------------------------------
	parseCommandLineInputs (argc, argv);

	fprintf (stderr, "Closing port");
	close (PORT_DESCRIPTOR);
	exit(0);
}

////////////////////////////////////////////////////////
// search for Shimmer on serial ports
// and then open link. This works on Cygwin
////////////////////////////////////////////////////////
int openSerialPort( char defaultPort[] ){

	// if port is open already return
	if (PORT_DESCRIPTOR != -1) {
		return PORT_DESCRIPTOR;
	}

	#define PORT_LENGTH 30
	static char basePortString[] = "/dev/ttyS%d";
	char portString[PORT_LENGTH];

	static int FIRST_PORT = 3;
	static int NUMBER_OF_PORTS = 10;
	int fd;
	// search for the serial port connected to the Shimmmer is not as easy
	// as it first seems. Problems:
	// The Windows device manager does not always report the correct addresses
	// of the USB serial ports assigned to the docking station. Windows might
	// report port 9 and 10 when in reality it is mapped to port 8 and 9
	//
	// if the docking station has an even-odd mapping, and the even port is the
	// programming port, writing to the programming port will reset the shimmer
	// (the LEDs flicker and the green and yellow LEDs stay lit. )

	if (defaultPort == NULL) {
		int i = -1;
		do {
			i++;
			// look for shimmer on the listed ports
			sprintf (portString,  basePortString, i + FIRST_PORT);
			fprintf (stderr, "Attempting port %s \n", portString);
			fd = open (portString, O_RDWR | O_NOCTTY | O_NDELAY |  O_NONBLOCK );
			if ( (fd != -1) && (isShimmer (fd) == FALSE) ) {
				fd = -1;
			}
	   } while( (fd < 0) && (i < NUMBER_OF_PORTS) );
	}
	else {
		strncpy (portString, defaultPort, PORT_LENGTH);
		fprintf (stderr, "Attempting specified port %s \n", portString);
		fd = open (portString, O_RDWR | O_NOCTTY | O_NDELAY |  O_NONBLOCK );
		fprintf (stderr, "fd is %d \n", fd);
		if ( (fd != -1) && (isShimmer (fd) == FALSE) ) {
			fd = -1;
		}
	}

	// I get segmentation fault if I disconnect Shimmer
	// I never seem to get here.
	//	fprintf (stderr, "fd %i  \n", fd);

    if (fd < 0)  {
        perror ("Unable to open port to Shimmer");
		exit(0);
    }

	fprintf (stderr, "Port %s open to Shimmer.\n", portString);

    return  fd;

}

// check if shimmer by setting time and reading it back
////////////////////////////////////////////////////////
BOOL isShimmer (int fd){
	setPortConfiguration (fd);
	PORT_DESCRIPTOR = fd;
	uint32_t timeOffset = 875634;
 	setShimmerTimeStartOfDataCollection (timeOffset);
 	uint32_t testOffset = getShimmerTimeStartOfDataCollection ();
  	if (testOffset == timeOffset) {
		return TRUE;
 	} else {
 		close (fd);
 		return FALSE;
 	}
}

////////////////////////////////////////////////////////
//      BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed.
// *************************** WARNING *****************************
//  	This did not work on cywin  10-27-7 had to use cfsetispeed
//		see http://www.easysw.com/~mike/serial/serial.html
// *************************** WARNING *****************************
//      CRTSCTS : output hardware flow control (only used if the cable has
//                all necessary lines. See sect. 7 of Serial-HOWTO)
//      CS8     : 8n1 (8bit,no parity,1 stopbit)
//      CLOCAL  : local connection, no modem contol
//      CREAD   : enable receiving characters
////////////////////////////////////////////////////////
void setPortConfiguration (int fd) {
	struct termios newtio;

	bzero(&newtio, sizeof(newtio));
	newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD;
	newtio.c_iflag = 0;
	newtio.c_oflag = 0;

	// set input mode (non-canonical, no echo,...)
	newtio.c_lflag = 0;

	cfsetispeed(&newtio, BAUDRATE);
	cfsetospeed(&newtio, BAUDRATE);

	// does not seem to work in CYQWIN
	newtio.c_cc[VTIME]    = 2;   // inter-character timer in intervals of 0.1 sec ?
	newtio.c_cc[VMIN]     = 0;   // blocking read until x chars received

	tcsetattr(fd, TCSANOW, &newtio);
	fcntl(fd, F_SETFL, 0);
}

////////////////////////////////////////////////////////
void printHelp () {
	fprintf (stderr, "SHIMMER data collection interface\n");
	fprintf (stderr, "ss [-p portString] [-AFHfds}\n");
	fprintf (stderr, "\n");
	fprintf (stderr, "Options for shimmerSerial: \n");
	fprintf (stderr, "    -p str   set serial port\n");
	fprintf (stderr, "    -A str   start data collection on Shimmer\n");
	fprintf (stderr, "               sets Shimmer ID to str (maximum length %i characters)\n", HEADER_ID_LENGTH);
	fprintf (stderr, "               initialize clock offset on Shimmer to current UTC \n");
	fprintf (stderr, "    -F       reads all data blocks written to SD card and writes them to stdout\n");
	fprintf (stderr, "    	       Example usage: ./ss  -F >data.txt  \n");
	fprintf (stderr, "    	       Press the user button (furthest from USB \n");
	fprintf (stderr, "    	       connector) before using this command\n");
	fprintf (stderr, "    -T MMDDYYYYHHMM EE \n");
	fprintf (stderr, "             Dump data beginning with time stamp of  month: MM, day: DD,\n");
	fprintf (stderr, "             year: YYYY, hour: HH, minute: MM for EE minutes  \n");
	fprintf (stderr, "    -H       display data from header block\n");
	fprintf (stderr, "    -f x     read data block x and write to stdout\n");
	fprintf (stderr, "    -d       toggling red LED (good for testing USB connection)\n");
	fprintf (stderr, "    -s       get Shimmer time \n");
	fprintf (stderr, "\n");
	fprintf (stderr, "Place SHIMMER in dock station before running ss\n");
}

////////////////////////////////////////////////////////
void parseCommandLineInputs(int argc, char ** argv) {
	int i;
	uint blockNumber;
	char buffer[BLOCK_LENGTH];

	if (argc == 1) {
		printHelp ();
		return;
	}
	for (i = 1; i < argc; i++ ) {
	    if (argv[i][0] == '-') {
	       	if (argv[1][1] == 'p' && i == 1)	{		// only allow as first option
				i++;
				PORT_DESCRIPTOR = openSerialPort(argv[i]);
			}
	       	else if (argv[i][1] == 'A')	{
			// next argument should be a number
				///////////////////////////////////
				char* ID_string;
				i++;
				if ( i < argc) {
	        		ID_string =  argv[i];
				}
				else {
					ID_string = "No ID";
				}

				// start connection to shimmer
				PORT_DESCRIPTOR = openSerialPort (NULL);
				if(PORT_DESCRIPTOR == -1) {
					exit(1);
				}

 	        	sendHeaderBlock (ID_string);
				fprintf (stderr, "Shimmer ID %s \n Starting data collection \n", ID_string);
	        	startRecording ();
				fprintf (stderr, "  Check if green and orange LEDs are blinking \n");
				return;
			}
			////////////////////////////////////////////////////////////
	      	else if (argv[i][1] == 'F')	{
				// start connection to shimmer
				PORT_DESCRIPTOR = openSerialPort (NULL);
				if(PORT_DESCRIPTOR == -1) {
					exit(1);
				}
				getAndPrintAllDataBlocks ();
			    return;
			}
			////////////////////////////////////////////////////////////
		      	else if (argv[i][1] == 'T')	{
		      		uint32_t requestTimeSec;
		      		uint32_t requestedDurationSec;
		      		i++;
	      			if ( i < argc) {
	      				initTimeStructure (argv[i], &requestTimeSec);
			      	}
	      			else {
	      				requestTimeSec = 0;
	      			}
					i++;
					if ( i < argc) {
							requestedDurationSec = (uint)atoi(argv[i]) * 60;
						}
						else {
							requestedDurationSec = 10 * 60;
						}
					if (requestTimeSec == 0 || requestedDurationSec == 0) {
		      			fprintf (stderr,
		      				"Switch -T requires start date and time, MMDDYYYYHHMM, (you have %s)and \n", argv[i-1]);
		      			fprintf (stderr,
		      				"a the number of minutes(you have %s) of data to download. \n", argv[i]);
						return;
					}

					// start connection to shimmer
					PORT_DESCRIPTOR = openSerialPort (NULL);
					if(PORT_DESCRIPTOR == -1) {
						exit(1);
					}
					getAndPrintData(requestTimeSec, &requestedDurationSec);
					return;
				}
			////////////////////////////////////////////////////////////
	      	else if (argv[i][1] == 'H')	{

				dataCollectionStatus_t 	status;
				uint32_t  				blocksToRead;
				uint32_t  				timeOffset;

				// start connection to shimmer
				PORT_DESCRIPTOR = openSerialPort (NULL);
				if(PORT_DESCRIPTOR == -1) {
					exit(1);
				}
				getHeaderBlock(&status, &blocksToRead, &timeOffset);
			    return;
			}

			////////////////////////////////////////////////////////////
	      	else if (argv[i][1] == 's')	{
				// start connection to shimmer
				PORT_DESCRIPTOR = openSerialPort (NULL);
				if(PORT_DESCRIPTOR == -1) {
					exit(1);
				}
				uint32_t shimmerTime = getShimmerTime();
      			fprintf (stderr, "Shimmer time (sec): %f\n",
	      					(float) shimmerTime /(float)SHIMMER_TICS_PER_SECOND);
      			fprintf (stderr,
	      				"PC time (sec): %d\n", (unsigned int)time(NULL)	);
			    return;
			}
			////////////////////////////////////////////////////////////
	      	else if (argv[i][1] == 'f')	{
				// next argument should be a number
				///////////////////////////////////
				i++;
				if ( i < argc) {
	        		blockNumber = (uint)atoi(argv[i]);
				}
				else {
					blockNumber = -1;
				}
				if (blockNumber < 0) {
	      			fprintf (stderr,
	      				"Switch -f requires a positive block number not %s\n", argv[i]);
					return;
				}
				// start connection to shimmer
				PORT_DESCRIPTOR = openSerialPort (NULL);
				if(PORT_DESCRIPTOR == -1) {
					exit(1);
				}
	        	if (getDataBlock(blockNumber, buffer) ) {
 					printADCdata(stdout, buffer, 0, 0, 0, 0);
				}
				return;
			}
			////////////////////////////////////////////////////////////
	      	else if (argv[i][1] == 'd')	{
				// start connection to shimmer
				PORT_DESCRIPTOR = openSerialPort (NULL);
				if(PORT_DESCRIPTOR == -1) {
					exit(1);
				}
				toggleRedLed ();
				return;
			}
			////////////////////////////////////////////////////////////
	      	else {
	      		fprintf (stderr, "Unknown switch %s\n", argv[i]);
				printHelp ();
				exit (1);
			}
		}
		 else {
			printHelp ();
			exit (1);
		}
  	}
 	return;
}
// initialize time structure from ASCII string with the format MMDDYYYYHHMM
// where
//			MM is month,
//			DD is day of the month
//			YYYY is the year
//			HH is the hour of the day
//			MM is the minute of the hour
// and then get time in seconds from the epoch
////////////////////////////////////////////////////
void initTimeStructure (char* arg, uint32_t* timeSec ) {
	struct tm timeStructure;

	char tempStr[5];

	if(strlen(arg) != 12) {
		*timeSec = 0;
	}
	memset(&timeStructure, 0, sizeof(timeStructure));

	memset(tempStr, 0, sizeof(tempStr));
	strncpy(tempStr, &arg[0], 2);
	timeStructure.tm_mon = atoi(tempStr) - 1;

	memset(tempStr, 0, sizeof(tempStr));
	strncpy(tempStr, &arg[2], 2);
	timeStructure.tm_mday = atoi(tempStr);

	memset(tempStr, 0, sizeof(tempStr));
	strncpy(tempStr, &arg[4], 4);
	timeStructure.tm_year = atoi(tempStr) - 1900;

	memset(tempStr, 0, sizeof(tempStr));
	strncpy(tempStr, &arg[8], 2);
	timeStructure.tm_hour = atoi(tempStr);

	memset(tempStr, 0, sizeof(tempStr));
	strncpy(tempStr, &arg[10], 2);
	timeStructure.tm_min = atoi(tempStr);

	*timeSec = mktime(&timeStructure);
}

// start recording data
////////////////////////////////////////////////////
void startRecording () {
	write (PORT_DESCRIPTOR, START_RECORDING_CMD, 1);
}

// toggle red led
////////////////////////////////////////////////////
void toggleRedLed () {
	fprintf (stderr, "Toggling red LED ... \n");
	write (PORT_DESCRIPTOR, TOGGLE_RED_LED_CMD, 1);
}

// get time from Shimmer 's clock.
////////////////////////////////////////////////////
uint32_t getShimmerTime () {
	uint32_t time;
	write (PORT_DESCRIPTOR, GET_SHIMMER_TIME_CMD, 1);
	getSerialBlock(PORT_DESCRIPTOR, (unsigned char*)&time, sizeof(time));
 	return time;
}

// set and get clock offset from Shimmer.
// The clock offset sent to Shimmer using setShimmerTimeStartOfDataCollection is not used to populate
// the header block, it is only used by the getShimmerTimeStartOfDataCollection command
// the pair of functions are used to test the data connection
////////////////////////////////////////////////////
void setShimmerTimeStartOfDataCollection (const uint32_t time) {
	write (PORT_DESCRIPTOR, SET_SHIMMER_CLOCK_OFFSET_CMD, 1);
	sendUint(PORT_DESCRIPTOR, time);
}

// returns time offset set by setShimmerTimeStartOfDataCollection
uint32_t getShimmerTimeStartOfDataCollection () {
	uint32_t time;
	write (PORT_DESCRIPTOR, GET_SHIMMER_CLOCK_OFFSET_CMD, 1);
	getSerialBlock(PORT_DESCRIPTOR, (unsigned char*)&time, sizeof(time));
 	return time;
}

// this use to be complicated but now we are just saving the
// the time on the SHIMMMER as the number of seconds from the LINUX Epoch
// side effect is to test if Shimmer is alive
////////////////////////////////////////////////////////////////////
uint32_t calculateShimmerTimeOffset () {
	uint32_t timeAtStart = time(NULL);
	setShimmerTimeStartOfDataCollection( (uint32_t) timeAtStart );
	uint32_t testTimeAtStart =  getShimmerTimeStartOfDataCollection ();
//	fprintf (stderr, "Shimmmer clock offset: %d\n", testOffset);

	if ( (uint32_t) timeAtStart !=  testTimeAtStart) {

		fprintf (stderr,
			"\n ERROR: Unable to set time on Shimmer for the start of data collection.\n");
		fprintf (stderr,
			"Local offset: %u Shimmer's offset: %u.\n", (unsigned int)timeAtStart,
														(unsigned int)testTimeAtStart);
	   	exit(0);
	}
  	return timeAtStart;
}

// send header block with all the fields set
////////////////////////////////////////////////////
void sendHeaderBlock (char* ShimmerID) {
	HEADER_BLOCK_STRUCTURE header;

	memset(&header, ':', sizeof(header) );

	// side effect of clearing the Shimmer clock
	// that is used to time stamp each data block
	// Must save offset in header file.
	header.LinuxStartTimeSec= calculateShimmerTimeOffset ();
	fprintf (stderr, "Time at start of data collection saved on SD card: %s\n",
			ctime((time_t*)&(header.LinuxStartTimeSec)) );
	header.numberOfBlocksWritten = 0;
	// must do a string copy

	strncpy(header.ShimmerID, ShimmerID, HEADER_ID_LENGTH);
	header.dataCollectionStatus = nullStatus;
	sprintf((char *)&header.unused,"help me I am in the Shimmer.");

 	write (PORT_DESCRIPTOR, WRITE_HEADER_BLOCK_CMD, 1);
	write (PORT_DESCRIPTOR, &header, BLOCK_LENGTH);
}

// use the start and duration time (seconds from the epoch)
// to determine which blocks to get and print
////////////////////////////////////////////////////
void getAndPrintData  (const uint32_t requestTimeSec, const uint32_t* durationSec) {
	dataCollectionStatus_t 	status;
	uint32_t  				blocksToRead;
	uint32_t  				dataStartTimeSec;
	uint32_t  				dataDurationSec;
	uint32_t  				requestedDurationSec = *durationSec;

	getHeaderBlock(&status, &blocksToRead, &dataStartTimeSec);
	dataDurationSec = (unsigned int)
		(blocksToRead * DURATION_OF_BLOCK_SEC);

	fprintf (stderr,
		"\nData from SHIMMER will be requested starting at %s",
		ctime((time_t*) &requestTimeSec));
	fprintf (stderr,
		"for %d minutes.\n", (unsigned int) requestedDurationSec / 60);

	// validate that the request time is in the range
	// of available data
	if ( requestTimeSec < dataStartTimeSec ||
			requestTimeSec > dataStartTimeSec + dataDurationSec) {
		fprintf (stderr,
			"ERROR: requested start time is out of range." );
		return;
	}
	if ( requestTimeSec + requestedDurationSec  >
				(dataStartTimeSec + dataDurationSec) ) {

		requestedDurationSec = (dataStartTimeSec + dataDurationSec) - requestTimeSec;
		fprintf (stderr,
			"WARNING: requested duration goes past the end of data. Reset to %d minutes.\n",
			(unsigned int) requestedDurationSec / 60);
	}

	// calculate the blocks we would like to download
	uint32_t secondsFromStart = requestTimeSec - dataStartTimeSec;
	uint32_t startBlock = secondsFromStart / DURATION_OF_BLOCK_SEC;
	uint32_t endBlock = startBlock + (requestedDurationSec / DURATION_OF_BLOCK_SEC);
	fprintf (stderr,
			"Requesting block %d to %d \n",
			(unsigned int)startBlock, (unsigned int)endBlock);
	getAndPrintDataBlocks (startBlock, endBlock,
							dataStartTimeSec + startBlock * DURATION_OF_BLOCK_SEC);
}

// the time stamp associated with each measurement is only as accurate at
// the time stamp given given for the measurement
/////////////////////////////////////////////////////////////
void getAndPrintDataBlocks (const uint32_t startBlock,
							const uint32_t endBlock,
							const uint32_t LinuxTimeFirstBlockSec) {
	DATA_BLOCK_STRUCTURE 	block;
	uint32_t 				i;
	uint32_t  				firstBlockShimmerTime;
	uint32_t				LinuxStartTimeSec;
	uint32_t  				LinuxBlockTimeSec;
	BOOL					blockTimeSequenceBad = FALSE;

	// need to subtract the timeStamp from the first block
	// from all subsequent blocks
	getDataBlock(FIRST_DATA_BLOCK_OFFSET + startBlock, (char*) &block);
	firstBlockShimmerTime = block.ShimmerTime;
	LinuxBlockTimeSec = LinuxTimeFirstBlockSec;
	LinuxStartTimeSec = LinuxTimeFirstBlockSec;
//	blocksToRead = 0;			//////////////////////////// DEBUGGING

	i = FIRST_DATA_BLOCK_OFFSET + startBlock;
	while (	i < FIRST_DATA_BLOCK_OFFSET + endBlock ) {

		if(( i  % BLOCK_MESSAGE_FREQUENCY) == 0.0 )  {
			fprintf (stderr, "\nRequesting data collected at %s",
				ctime( (time_t*)&LinuxBlockTimeSec));

		} else {
			fprintf (stderr, ".");
		}

		if (getDataBlock(i, (char*) &block) ) {
//			fprintf (stderr,
//					"block number: %i time: %i\n",
//					(unsigned int)i, (unsigned int)block.ShimmerTime);

			// side effect is to change timeOffset when there
			// is a shimmer clock overflow and
			// to set timeStampOutOf Sequence flag
			printADCdata(stdout, (char*) &block,
							&LinuxStartTimeSec, firstBlockShimmerTime,
							&LinuxBlockTimeSec,
							&blockTimeSequenceBad);
			if(blockTimeSequenceBad) {
				fprintf (stderr,
					"\n Difference of time stamp (%s)", ctime((time_t*)&LinuxBlockTimeSec) );
				fprintf (stderr,
					"between block %i and the previous block is too large. Stopping data dump. \n\n",
					(unsigned int)i);
				}
		}
		i++;
	}
	fprintf (stderr, "\n");
}

// get all the data blocks from Shimmer
////////////////////////////////////////////////////
void getAndPrintAllDataBlocks () {
	DATA_BLOCK_STRUCTURE 	block;
	uint32_t 				i;
	static uint32_t 		nonMatchingBlockID_Count;
	#define MAX_COUNT_NONMATCHING_BLOCK_ID 5
	dataCollectionStatus_t 	status;
	uint32_t  				blocksToRead;
	uint32_t  				LinuxstartTimeSec;
	uint32_t  				firstBlockShimmerTime;
	uint32_t  				LinuxBlockTimeSec;
	uint32_t				experimentID;
	BOOL					ignoreBlocksToReadFlag;
	BOOL					timeStampOutOfSequence = FALSE;

	memset(&block, 1, sizeof(block));

	getHeaderBlock(&status, &blocksToRead, &LinuxstartTimeSec);
	experimentID = LinuxstartTimeSec & 0xFFFF;

	// need to subtract the timeStamp from the first block
	// from all subsequent blocks
	getDataBlock(FIRST_DATA_BLOCK_OFFSET, (char*) &block);
	firstBlockShimmerTime = block.ShimmerTime;
	LinuxBlockTimeSec = LinuxstartTimeSec ;

	if ( (status == nullStatus) ||
		 (blocksToRead == 0)    ) {
		ignoreBlocksToReadFlag = TRUE;
		fprintf (stderr,
			"\n\nHeader block indicates that the data collection was interrupted. \n" );
		fprintf (stderr,
			" Retrieving  data blocks that have a experimental ID of %d . \n\n",
			(unsigned int)experimentID );

	} else {
		ignoreBlocksToReadFlag = FALSE;
	}

	i = FIRST_DATA_BLOCK_OFFSET;

	while (	i < FIRST_DATA_BLOCK_OFFSET + blocksToRead ||
			(ignoreBlocksToReadFlag	&& experimentID == block.experimentID )	 ) {

		if( (i % BLOCK_MESSAGE_FREQUENCY) == 0  )  {
			fprintf (stderr, "\nRequesting data collect at %s .",
				ctime((time_t*)&LinuxBlockTimeSec));

		} else {
			fprintf (stderr, ".");
		}

		if (getDataBlock(i, (char*) &block) ) {
			if (experimentID == block.experimentID) {
				// side effect is to change timeOffset when there
				// is a shimmer clock overflow and
				// to set timeStampOutOf Sequence flag
				printADCdata(stdout, (char*) &block,
							&LinuxstartTimeSec, firstBlockShimmerTime,
							&LinuxBlockTimeSec,
							&timeStampOutOfSequence);
				nonMatchingBlockID_Count = 0;
			} else {
				nonMatchingBlockID_Count++;

				if(nonMatchingBlockID_Count == MAX_COUNT_NONMATCHING_BLOCK_ID) {
					fprintf (stderr,
						"\nBlock ID does not match, Stopping data dump. \n\n");
					return;
				}
				fprintf (stderr,
					"\nBlock ID does not match, trying next block. \n");
				block.experimentID = experimentID;
			}
			if(timeStampOutOfSequence) {
				fprintf (stderr,
					"\nTime stamp of block %i is out of sequence. Continuing data dump. \n\n",
					(unsigned int)i);

			}
		}
		i++;
	}
	fprintf (stderr, "\n");
}
// write the ADC data to the file descriptor
// Format of each line
// 			time x  y  z
// the separator between fields is given by SEPARATOR
//
// main task is keeping track of time.
//		 zero the shimmer time - the shimmer time of the first block is really zero
// 		 overflows - shimmer time overflows.
////////////////////////////////////////////////////
void printADCdata(	FILE*		fd,
					char* 		buffer,
					uint32_t* 	LinuxStartTimeSec,
					uint32_t 	firstBlockShimmerTime,
					uint32_t* 	LinuxBlockTimeSec,
					BOOL*    	blockOutOfSequenceFlag) {

	char 					SEPARATOR[] = " ";
	int 					i;
	SAMPLE_STRUCTURE* 		samples;
	static double 			deltaTime = (double)ADC_TIMER_PERIOD_MSEC / TINYOS_TIMER_TICS_SEC;
	static double 			clockInverted = 1.0 / ((double) TINYOS_CLOCK_TICS_SEC);
	// number of seconds that can be counted before the TinyOS clock overflows
	// 2^32 / 2^15 = 2^17 = 131072
 	static double 			shimmerClockOverflowPeriodSec = 131072;
	double 					shimmerTimeSec;
	static double 			oldShimmerTimeSec = 0;

#ifdef _DEBUG_SERIAL
	FILE *fdi = fopen("foofoo.exe", "w");
	if(fdi > 0) {
		fwrite (buffer, 1, BLOCK_LENGTH, fdi);
	}
	fclose(fdi);
#endif
	DATA_BLOCK_STRUCTURE* block = (DATA_BLOCK_STRUCTURE*) buffer;

	shimmerTimeSec = (double) ((*block).ShimmerTime - firstBlockShimmerTime) * clockInverted;

	// check for overflow
	// if overflow we need to add time to clock offset
	// this is hard to test because it only happens after 36.4 hours
	double shimmerTimeDifferenceBetweenBlocks = shimmerTimeSec - oldShimmerTimeSec;
	if (shimmerTimeDifferenceBetweenBlocks < 0) {
		*LinuxStartTimeSec += shimmerClockOverflowPeriodSec;
 	}
	 oldShimmerTimeSec = shimmerTimeSec;
	double blockStartTime = *LinuxStartTimeSec + shimmerTimeSec;
	*LinuxBlockTimeSec = (uint32_t)blockStartTime;

	// keep track of start times of blocks to insure that blocks are insequence
	// initialze to time of first block
	static double			lastBlockStartTime = -1.0;
	if (lastBlockStartTime == -1.0) {
		lastBlockStartTime = blockStartTime;
	}
	double difference = (blockStartTime - lastBlockStartTime);
	if ( difference > 2.0* DURATION_OF_BLOCK_SEC ) {
		*blockOutOfSequenceFlag = TRUE;
		lastBlockStartTime = blockStartTime;
		return;
	} else {
		lastBlockStartTime = blockStartTime;
		*blockOutOfSequenceFlag = FALSE;
	}

	samples = &((*block).data[0]);
	for (i = 0; i < NUMBER_OF_SAMPLES_PER_STRUCTURE; i++) {
		fprintf(fd, "%10.4f", blockStartTime + (double)i * deltaTime);
		fprintf(fd, SEPARATOR);

		fprintf(fd, "%5i", samples[i].x);
		fprintf(fd, SEPARATOR);
		fprintf(fd, "%5i", samples[i].y);
		fprintf(fd, SEPARATOR);
		fprintf(fd, "%5i", samples[i].z);
		fprintf(fd, "\n");
	}
}
// get header block  from Shimmer
////////////////////////////////////////////////////
void getHeaderBlock (dataCollectionStatus_t* status,
					 uint32_t* blocksToRead,
					 uint32_t* LinuxstartTimeSec) {
	HEADER_BLOCK_STRUCTURE header;
	memset(&header, 1, sizeof(header));
	getDataBlock (HEADER_BLOCK_OFFSET, (char*) &header);

	// blocks written includes the header block
	*status = header.dataCollectionStatus;
	*blocksToRead = header.numberOfBlocksWritten - 1;
	*LinuxstartTimeSec = header.LinuxStartTimeSec;
	if (LinuxstartTimeSec == 0) {
		fprintf (stderr, "ERROR: bad header block. Try again.\n");
		exit(0);
	}


	if(strcmp(header.ShimmerVer, SHIMMER_VERSION) ) {
		fprintf (stderr, "\n WARNING SOFTWARE VERSIONS DO NOT MATCH.\n");
		fprintf (stderr, "\nShimmer firmware: %s, PC software: %s \n",
						header.ShimmerVer, SHIMMER_VERSION );
		fprintf (stderr, "  Data fields are possibly misaligned. Check if data looks reasonable.\n\n");
	}


	fprintf (stderr, "Shimmer Type: %s \n",
					header.ShimmerType);
	fprintf (stderr, "Release Date: %s \n",
					header.ShimmerDate);
		fprintf (stderr, "Shimmer ID: %s \n",
					header.ShimmerID );
	fprintf (stderr, "Shimmer Status: %s \n",
					STATUS_MESSAGES[*status]);
	fprintf (stderr, "Starting time of data collection: %s",
					ctime((time_t*)LinuxstartTimeSec));
	fprintf (stderr,
					"SHIMMER collected %d minutes of data in %d blocks. \n",
					(unsigned int)(*blocksToRead * DURATION_OF_BLOCK_SEC / 60),
					(unsigned int)*blocksToRead);
}

// get block of data from Shimmer
////////////////////////////////////////////////////
char* getDataBlock(uint blockNumber, char buffer[]) {
	int markerCount = 0;
	unsigned char aChar;
	const unsigned char  headerChar = 0xAA;
	// print out occasional message

	write (PORT_DESCRIPTOR, READ_BLOCK_CMD , 1);

	// Shimmer expects a binary four byte integer for the block number.
	// little endian - low byte first
	//-----------------------------------------------------
	sendUint (PORT_DESCRIPTOR, blockNumber);

	// block is preceded with four bytes of 0xAA
	int maxRetryCount = 30;
	while (markerCount < 4 &&  maxRetryCount > 0) {
		if (getSerialChar(PORT_DESCRIPTOR, &aChar)) {
			if (aChar  == headerChar) {
				markerCount++;
				if (markerCount == 4) {
					break;
				}
			} else {
				markerCount = 0;
			}
			maxRetryCount--;
		} else {
			maxRetryCount--;
		}
	}
	if (markerCount != 4) {
		fprintf (stderr,
			"\n BAD MESSAGE HEADER. Block %i read failed. \n",
				blockNumber - FIRST_DATA_BLOCK_OFFSET);
		exit (0);
	}
	getSerialBlock(PORT_DESCRIPTOR, buffer, BLOCK_LENGTH);

	// verify that the block has not been corrupted.
	// This is mostly a check of whether there has been a problem with the SD card.
	// Some SD cards do seem to work well with SHIMMER. If the SHIMMER was unable
	// to get a block from the SD card it will light the red LED and send a block of
	// junk data
	//
	// a SHIMMER without an SD card can send back a block of zeros which
	// is not good because the CRC matches
	int i, sum = 0;
	for (i = 0; i < BLOCK_LENGTH; i++) {
		sum += buffer [i];
	}
	if ( sum == 0 ) {
		fprintf (stderr,
			"ERROR: SD block %i was all zeros. Block read failed. \n",
			blockNumber - FIRST_DATA_BLOCK_OFFSET);
		fprintf (stderr, "Possible bad SD card or SD card is missing. \n");
		exit(0);
	}

	DATA_BLOCK_STRUCTURE* block = (DATA_BLOCK_STRUCTURE*)buffer;
	uint16_t blockCRC = CRC16( buffer, BLOCK_LENGTH-2);
	if ( (block -> CRC) != blockCRC ) {
		fprintf (stderr,
			"\nERROR: SD block %i has bad CRC. Block read failed. \n",
			blockNumber - FIRST_DATA_BLOCK_OFFSET);

#ifdef _DEBUG_SERIAL
 	// debugging code to dump block
 	fprintf (stderr, " \n Dumping block received...\n");
 	int i;
 	for (i = 0; i < BLOCK_LENGTH; i++) {
		fprintf (stderr, "%2x  ", (unsigned char)(buffer [i]));
		if( ((i + 1) % 16) == 0)  {
			fprintf (stderr, " \n");
		}
	}
	fprintf (stderr, " \n");
#endif

	}
#ifdef _DEBUG_SERIAL
 	// debugging code to dump block
 	fprintf (stderr, " \n Dumping block received...\n");
 	int i;
 	for (i = 0; i < BLOCK_LENGTH; i++) {
		fprintf (stderr, "%2x  ", (unsigned char)(buffer [i]));
		if(((double)(i + 1) % 16.0) == 0.0)  {
			fprintf (stderr, " \n");
		}
	}
	fprintf (stderr, " \n");
#endif

	return buffer;
 }

// write a four byte integer to the serial port one byte at a time
////////////////////////////////////////////////////////////////////
void sendUint (int fd, uint blockNumber) {
	int i;
	char  c;

	for (i = 0; i < 4; i++) {
		c =  (char)   (blockNumber >> (i *8 ) );
 		c =  (char)   (blockNumber >> (i *8 ) ) & 0xFF;
		write (fd, &c, 1);
//		fprintf (stderr, "%u \n", (unsigned char)c);
	}
}

// wait until character is received from port
////////////////////////////////////////////////////
int getSerialChar (int fd, char* aChar){
	int numberOfCharacters = -1;
	// 	fprintf (stderr, "getting char from shimmer  ");
	#define MAX_RETRY_COUNT_READ 10
	int i = MAX_RETRY_COUNT_READ;
	while( (i > 0) && (numberOfCharacters <= 0) ) {
		numberOfCharacters = read(fd, aChar, 1);
		i--;
	}
	  if (numberOfCharacters == 0){
		  fprintf (stderr, "ERROR: Read from serial port timed out. \n" );
//		  exit(-1);
	  }
	return numberOfCharacters;
}

// wait until length characters are received from port
////////////////////////////////////////////////////
int	 getSerialBlock (int fd, unsigned char buffer[], int length){
	int charCount = 0;

	while( charCount < length ) {
	 if (getSerialChar(fd, &(buffer [charCount]) ) == 0 )
		 return 0;

 	  charCount++;
	}

#ifdef _DEBUG_SERIAL
 	// debugging code to dump block
 	fprintf (stderr, " \n Dumping block received...\n");
 	int i;
 	for (i = 0; i < length; i++) {
		fprintf (stderr, "%2x  ", (unsigned char)(buffer [i]));
		if(((double)(i + 1) % 16.0) == 0.0)  {
			fprintf (stderr, " \n");
		}
	}
	fprintf (stderr, " \n");
#endif
	return charCount;
}





--- NEW FILE: shimmerSerial.h ---
#ifndef __shimmerSerial_h
#define __shimmerSerial_h


#define SHIMMER_VERSION "1.20"
#define SHIMMER_DATE "25-Feb-08"

typedef enum {
  Accel_Shimmer = 0,
  BT_Shimmer
} Shimmer_t;

char*  SHIMMER_TYPE_STRINGS[] = {
	"3-axis accel",
	"BT data aggregator"	};

#define SHIMER_TYPE  SHIMMER_TYPE_STRINGS[Accel_Shimmer]

char*  SHIMMER_ACCEL_GAIN_STRINGS[] = {
	"1.5g",
	"2.0g",
	"4.0g",
	"6.0g"	};

// not saved on SD card yet
#define SHIMER_ACCELEROMETER_GAIN  RANGE_6_0G

// the settings to generate the correct baud rate are found in
// contrib\handhelds\tos\platform\msp430_crl_base\clock_settings
// if TARGET_DCO_KHZ is not set than it is defined there.
//
// this value is used to calculate SMCLK_KHZ which is used in
// contrib\handhelds\tos\platform\msp430_crl_base\msp430baudrates.h
// to calculate the baudrate enumeration for UBR_SMCLK_115200, UMCTL_SMCLK_115200
// which is used in initSPI
//#define TARGET_DCO_KHZ 4096 * 2
#define SHIMMER_TICS_PER_SECOND 0x8000

// B256000 does not seem to be supported. It set the baudrate to B115200
//#define BAUDRATE B115200
#define BAUDRATE B230400

#define BLOCK_LENGTH 512
#define HEADER_BLOCK_OFFSET 	0
#define FIRST_DATA_BLOCK_OFFSET 1
#define SD_START_BLOCK 2000

#define START_RECORDING_CMD "a"
#define READ_BLOCK_CMD "f"
#define WRITE_HEADER_BLOCK_CMD "m"
#define TOGGLE_RED_LED_CMD "d"
#define GET_SHIMMER_TIME_CMD "s"
#define GET_SHIMMER_CLOCK_OFFSET_CMD "o"
#define SET_SHIMMER_CLOCK_OFFSET_CMD "r"

// Shimmer/TinyOS has two clock/timers that are used.
// The time that is used to schedule the DC conversion
// 	call sampleTimer.start(TIMER_REPEAT, ADC_TIMER_PERIOD_MSEC);
// has one tic rate TINYOS_TIMER_TICS_SEC
//
// The time stamp that comes with each block is gotten by
// atomic dmaBufferTimeStamp = call LocalTime.read()
// uses a time base with another number of clock ticks per second
//
// if shimmer has a clock with 0x8000 (32k) ticks per second
// and time is saved in 32 bits then it will rollover every
// 36.4 hours
#define ADC_TIMER_PERIOD_MSEC 20
#define TINYOS_TIMER_TICS_SEC 0x0400
#define TINYOS_CLOCK_TICS_SEC 0x8000
#define BACKUP_HEADER_COUNT 40.0
#define LED_BLINK_ON_MSEC 5

typedef char BOOL;
enum {
	FALSE = 0,
	TRUE = 1 };

typedef enum {
  nullStatus = 0,					// starting status
  completedNormal,
  lowPowerWarning,
  poweredDown,
  periodicSave,
  errorWritingBlock					// not used yet
} dataCollectionStatus_t;

char*  STATUS_MESSAGES[] = {
	"Data collection terminated without setting status.",
	"Data collection completed normally",
	"Low battery warning received.",
	"Shimmer powered down because of low battery voltage",
	"Shimmer terminated abnormally, loss of some data, \nusing periodically backed up header info",
	"Error writing to SD card, possible end of card reached."	};


#define UNUSED_BYTES_IN_HEADER 60

#define HEADER_ID_LENGTH 400
#define HEADER_VERSION_LENGTH 10
#define HEADER_TYPE_LENGTH 20
#define HEADER_DATE_LENGTH 10

typedef struct{
 uint32_t LinuxStartTimeSec;
 uint32_t numberOfBlocksWritten;				//  includes the first status block
 char ShimmerVer 	[HEADER_VERSION_LENGTH];
 char ShimmerType 	[HEADER_TYPE_LENGTH];
 char ShimmerDate 	[HEADER_DATE_LENGTH];
 uint8_t  dataCollectionStatus;
 uint8_t  errorCount;							// not used yet
 char ShimmerID 	[HEADER_ID_LENGTH];
 uint8_t  unused[UNUSED_BYTES_IN_HEADER];		// needed to make block 512 bytes long
 uint16_t CRC;
} __attribute__((packed)) HEADER_BLOCK_STRUCTURE;

typedef struct  {
	uint16_t x;
	uint16_t y;
	uint16_t z;
} __attribute__ ((packed)) SAMPLE_STRUCTURE;

#define NUMBER_OF_SAMPLES_PER_STRUCTURE 84
typedef struct  {
	uint32_t 			ShimmerTime;
	SAMPLE_STRUCTURE 	data[NUMBER_OF_SAMPLES_PER_STRUCTURE];
	uint16_t 			experimentID;
	uint16_t			CRC;
} __attribute__ ((packed)) DATA_BLOCK_STRUCTURE;


// used by the data conversion and DMA transfer to RAM
//************* needs to be cleaned up *******************
//******  can get out of synch DATA_BLOCK_STRUCTURE   ************
//*****************************************************************

#define 	NUMBER_OF_ADC_CHANNELS 3		// Number of ADC channels used


#define DURATION_OF_BLOCK_SEC ((double) (NUMBER_OF_SAMPLES_PER_STRUCTURE * ADC_TIMER_PERIOD_MSEC) / \
							  (double)TINYOS_TIMER_TICS_SEC )
#endif



More information about the Tinyos-contrib-commits mailing list