//----------------------------------------------------------------------------------
// <copyright file="Seabird37SI.c" company="LiquidRobotics">
//	Copyright (c) Liquid Robotics Corporation.  All rights reserved.
// </copyright>
//
// <summary>
// 	This is the source for managing Seabird 37SI CTD
// </summary>
//
// <owner>Jim Kirklin</owner>
//----------------------------------------------------------------------------------

#include "includes.h"
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <string.h>
#include <avr/wdt.h>
#include <avr/power.h>
#include "uart.h"
#include "pib.h"
#include "timer.h"
#include "lrstat.h"
#include "spidebug.h"
#include "wdtrig.h"
#include "pib_apps.h"
#include "User_app_init.h"
#include "fltPyldComms.h"
#include "UserData.h"
#include "Seabird37SI.h"

#include "SerialDebug.h"


//Serial Number stored at offset 0x0010 from PM base -- 16 bytes
#define SEABIRD_37SI_SERNUM_OFFSET					0x0010
//Sample Rate stored at offset 0x0040 from PM base -- 2 bytes
#define SEABIRD_37SI_SAMPLE_INTERVAL_OFFSET		0x0040
//Packet Size stored at offset 0x0042 from PM base -- 2 bytes
#define SEABIRD_37SI_PACKET_SIZE_OFFSET			0x0042
//Data Destination stored at offset 0x0044 from PM base -- 2 bytes
#define SEABIRD_37SI_PACKET_DESTINATION_OFFSET		0x0044

#define MAX_37SI_SAMPLES	10
#define MAX_37SI_SAMPLE_INTERVAL		3600
#define DEFAULT_37SI_SAMPLE_INTERVAL	60

//No pressure sensor installed
#define SB37SI_SAMPLE_LEN		9

typedef struct _SBSB37SI_DATA_REPORT_BLOCK_
{
	TYPE_90_91_DATA_HEADER	headerData;
	int32_t				pressure;
	int32_t				temperature;
	int32_t				conductivity;	
}SBSB37SI_DATA_REPORT_BLOCK, *PSBSB37SI_DATA_REPORT_BLOCK;

typedef struct _SB37SI_DATA_REPORT_
{
	TYPE_91_REPORT_HEADER	headerReport;
	SBSB37SI_DATA_REPORT_BLOCK	dataBlock[MAX_37SI_SAMPLES];
}SB37SI_DATA_REPORT, *PSB37SI_DATA_REPORT;

typedef struct _SB37SI_ASCII_REPORT_
{
	TYPE_91_REPORT_HEADER	headerReport;
	TYPE_90_91_DATA_HEADER	headerData;
	char					data[165];
}SB37SI_ASCII_REPORT, *PSB37SI_ASCII_REPORT;

typedef struct _SEABIRD_SB37SI_DATA_REPORT_XMIT_
{
	PIB_IRIDIUM_DATA_XMIT	comm;
	SB37SI_DATA_REPORT		reportData;
}SEABIRD_SB37SI_DATA_REPORT_XMIT, *PSEABIRD_SB37SI_DATA_REPORT_XMIT;

typedef struct _SEABIRD_SB37SI_ASCII_REPORT_XMIT_
{
	PIB_IRIDIUM_DATA_XMIT	comm;
	SB37SI_ASCII_REPORT		reportASCII;
}SEABIRD_SB37SI_ASCII_REPORT_XMIT, *PSEABIRD_SB37SI_ASCII_REPORT_XMIT;


typedef struct _SEABIRD_37SI_BUFFER_
{
	char 					bufferTx[256];
	char 					bufferRx[1024];
	uint16_t 				sampleRate;
	uint16_t 				samplePacketSize;
	uint16_t 				destination;
	char 					serialNumber[16];
	char					ctdInfo[64];
	BOOL					sampleCTD;
	BOOL					powerCTD;
	BOOL					findDataFrame;
	BOOL					pressureInstalled;
	uint8_t					pressureBytes;
	BOOL					gotConfig;
	SB37SI_DATA_REPORT		reportData;
	CONSOLE_RESPONSE_INFO	responseInfo;
	char					tokenSeparatorList[MAX_TOKEN_SEPARATORS];
	char					statusConstructor[100];
	char					consoleResponse[256];
	DEBUG_OUTPUT_INFO		dbgInfo;
	uint8_t					frameBuf[2*SB37SI_SAMPLE_LEN + 8];		//Plus 8 is to make sure we ahve enough space if the pressure sensor is installed
	uint16_t				offTime;
	uint32_t				turnBackOnTime;
	BOOL					sleeping;
}SEABIRD_37SI_BUFFER, *PSEABIRD_37SI_BUFFER;


typedef struct _SEABIRD_37SI_TASK_
{
	uint8_t		taskID;
	uint8_t 	portNum;
	uint16_t	eepromAddress;
	PSEABIRD_37SI_BUFFER 	pBuf;
}SEABIRD_37SI_TASK, *PSEABIRD_37SI_TASK;



uint8_t Seabird_37SI_Init(PSEABIRD_37SI_TASK taskInfo);
uint8_t SB37SI_CTD_Tx2(PSEABIRD_37SI_TASK pTaskInfo);
uint8_t SB37SI_CTD_Rx2(PSEABIRD_37SI_TASK pTaskInfo, prog_char* pEOL, uint16_t* pLen);
void 	SB37SI_GetCTDSample2(PSEABIRD_37SI_TASK pTtaskInfo);
void 	SB37SI_GetCTDSampleFrame(PSEABIRD_37SI_TASK pTaskInfo);
uint8_t SB37SI_ReportCTDTelemetry(PSEABIRD_37SI_TASK pTaskInfo);
uint8_t SB37SI_AlphatoMonth(char* pChar);
uint8_t SB37SI_CTDReportXmit2(PSEABIRD_37SI_TASK pTaskInfo);
uint8_t SB37SI_GetSerNum2(PSEABIRD_37SI_TASK pTaskInfo);
uint8_t SB37SI_ParseFile(PSEABIRD_37SI_TASK pTaskInfo, uint32_t fileID);
uint8_t SB37SI_QueueFile(PSEABIRD_37SI_TASK pTaskInfo, uint32_t fileID);


uint8_t SB37SI_TurnOn(PSEABIRD_37SI_TASK pTaskInfo);
uint8_t SB37SI_TurnOff(PSEABIRD_37SI_TASK pTaskInfo);
uint8_t SB37SI_StartSample(PSEABIRD_37SI_TASK pTaskInfo);
uint8_t SB37SI_StopSample(PSEABIRD_37SI_TASK pTaskInfo);
uint8_t SB37SI_SetPeriod(PSEABIRD_37SI_TASK pTaskInfo, uint16_t newInterval);
uint8_t SB37SI_SetPacketSize(PSEABIRD_37SI_TASK pTaskInfo, uint8_t newPacketSize);
uint8_t SB37SI_SetPacketDest(PSEABIRD_37SI_TASK pTaskInfo, uint16_t newDest);
uint8_t SB37SI_Status(PSEABIRD_37SI_TASK pTaskInfo);
uint8_t SB37SI_Id(PSEABIRD_37SI_TASK pTaskInfo);
uint8_t SB37SI_Cmd(PSEABIRD_37SI_TASK pTaskInfo, char* cmd);
uint8_t SB37SI_SetTime(PSEABIRD_37SI_TASK pTaskInfo);
uint8_t SB37SI_CreateStatusResponse(PSEABIRD_37SI_TASK pTaskInfo, uint8_t status);



void SB37SI_ParseConsole2(PSEABIRD_37SI_TASK pTaskInfo);
uint8_t SB37SI_ParseCommand2(PSEABIRD_37SI_TASK pTaskInfo, char command, char* cmdParams);
void SB37SI_QueueConsoleResponse2(PSEABIRD_37SI_TASK pTaskInfo);

void SerialPortPassThrough37SI2(uint8_t port);

//37SI Command Strings
prog_char cmd37SI_Enter[] = "\r\n";
prog_char cmd37SI_DS[] = "ds";
prog_char cmd37SI_DC[] = "dc";
prog_char cmd37SI_GetHD[] = "gethd";
prog_char cmd37SI_ResetLogging[] = "resetlogging";
prog_char cmd37SI_DateTime[] = "datetime=%02d%02d%04d%02d%02d%02d";
prog_char cmd37SI_BaudRate[] = "baudrate=%ld";
prog_char cmd37SI_OutputExecuted[] = "outputexecuted=%c";
prog_char cmd37SI_AutoRun[] = "autorun=%c";
prog_char cmd37SI_OutputFormat[] = "outputformat=%d";
prog_char cmd37SI_MinCondFreq[] = "mincondfreq=%d";
prog_char cmd37SI_Interval[] = "sampleinterval=%d";
prog_char cmd37SI_CustomPump[] = "custompumpmode=%c";
prog_char cmd37SI_TxRealTime[] = "txrealtime=%c";
prog_char cmd37SI_RS232ForceOn[] = "rs232forceon=%c";
prog_char cmd37SI_Start[] = "start";
prog_char cmd37SI_Stop[] = "stop";

//prog_char cmd37SI_EOL[] = "\r\nS>";
prog_char cmd37SI_EOL[] = "S>";
prog_char cmd37SI_Sample_EOL[] = "\r\n";

prog_char parse37SI_SerNum[] = "  ";

prog_char tokens37SI1[] = " \t=,:\r\n";


prog_char status37SI_On[] = "On";
prog_char status37SI_Off[] = "Off";
prog_char status37SI_OK[] = "SUCCESS:";
prog_char status37SI_Fail[] = "FAILED:";
prog_char status37SI_Msg2[] = " Pwr=";
prog_char status37SI_Msg3[] = "  Smpl=";
prog_char status37SI_Msg4[] = "  Intrvl=%04d sec Size=%02d smpl/pkt Off-T=%d Slp=%s Dest.=0x%04X";
prog_char status37SI_Msg5[] = "  Intrvl=%04d sec Size=%02d smpl/pkt Off-T=%d Slp=%s Dest.=SHORE";


#define NUM_COMMANDS 11

extern const prog_char tokenListConsole[];
prog_char SB37SICommands[NUM_COMMANDS][8] = {"on", "off", "run", "stop", "period", "size", "dest", "stat", "id", "cmd", "cycle"};
prog_char SB37SIParserID[] = "37SI";
prog_char ctd37SICmdList2[] = "ofrxpzdsicyOFRXPZDSICY";


#define PARAM_PERIOD	0
#define PARAM_SIZE		1
#define PARAM_DEST		2



extern char fileIn[NUM_TASK_FILES][MAX_FILE_SIZE_IN] __attribute__((section(".xdata")));
extern char fileOut[NUM_TASK_FILES][MAX_FILE_SIZE_OUT] __attribute__((section(".xdata")));
extern uint16_t fileOutSize[NUM_TASK_FILES];
extern uint16_t fileInSize[NUM_TASK_FILES];
extern BOOL fileAvailable[NUM_TASK_FILES];
extern uint32_t fileAvailableID[NUM_TASK_FILES];
extern BOOL transmitPending[NUM_TASK_FILES];

extern CONSOLE_CMD_FORMAT consoleIn[NUM_TASK_FILES] __attribute__((section(".xdata")));
extern BOOL consoleAvailable[NUM_TASK_FILES];

extern BOOL kill[NUM_TASK_FILES];
extern BOOL powerDown[NUM_TASK_FILES];

extern BOOL serialPortPassThrough[NUM_TASK_FILES];
extern BOOL serialPortPassThroughOK;
extern BOOL readyForSerialPassThru;

extern OS_EVENT* pMutexFloatQueue;
extern FLOAT_TX_BUFFER txFloatData[MAX_FLOAT_BUFFERS] __attribute__((section(".xdata")));
extern uint8_t	headFloatTx;
extern uint8_t tailFloatTx;

extern FLOAT_TX_BUFFER txFloatAck[MAX_ACK_BUFFERS] __attribute__((section(".xdata")));
extern uint8_t	headFloatAckTx;
extern uint8_t tailFloatAckTx;

extern uint8_t	DotToPad(char* pad, char* dot);
extern uint16_t mainTaskAddress;

extern int32_t latitude;		//JGK Added 06-11-10
extern int32_t longitude;		//JGK Added 06-11-10
extern char	fixValid;			//JGK Added 06-11-10

uint8_t Seabird_37SI_Init(PSEABIRD_37SI_TASK pTaskInfo)
{
	if(pTaskInfo->portNum == USER_PORT_1)
		pTaskInfo->eepromAddress = EEPROM_PM1_START;
	else if(pTaskInfo->portNum == USER_PORT_2)
		pTaskInfo->eepromAddress = EEPROM_PM2_START;
	else if(pTaskInfo->portNum == USER_PORT_3)
		pTaskInfo->eepromAddress = EEPROM_PM3_START;

	if(pTaskInfo->pBuf != NULL)
		memset(pTaskInfo->pBuf, 0, TASK_BUF_SIZE);

	OSuartInitPort(pTaskInfo->portNum, 9600, UART_MODE_EIGHT_DATA_BITS, UART_MODE_ONE_STOP_BIT, UART_MODE_NO_PARITY);

	pTaskInfo->pBuf->sampleRate = DEFAULT_37SI_SAMPLE_INTERVAL;
	pTaskInfo->pBuf->samplePacketSize = MAX_37SI_SAMPLES;
	pTaskInfo->pBuf->destination = FLOAT_TO_SHORE_VIA_DEFAULT;
	pTaskInfo->pBuf->findDataFrame = FALSE;

	if(pTaskInfo->eepromAddress != 0)
	{
		uint16_t temp;

		//Get default sample rate
		temp = 0xFFFF;
		EepromReadWord((void*)(pTaskInfo->eepromAddress + SEABIRD_37SI_SAMPLE_INTERVAL_OFFSET), (void*)&temp);
		if((temp == 0xFFFF) || (temp == 0x0000) || (temp > MAX_37SI_SAMPLE_INTERVAL))
		{
			temp = DEFAULT_37SI_SAMPLE_INTERVAL;	//Default to 1 sample per minute if not defined
			EepromWriteWordUnSigned((void*)(pTaskInfo->eepromAddress + SEABIRD_37SI_SAMPLE_INTERVAL_OFFSET), temp);
		}
		pTaskInfo->pBuf->sampleRate = temp;

		//Get default packet size for data (# samples per packet)
		temp = 0xFFFF;
		EepromReadWord((void*)(pTaskInfo->eepromAddress + SEABIRD_37SI_PACKET_SIZE_OFFSET), (void*)&temp);
		if((temp == 0xFFFF) || (temp == 0x0000))
		{
			temp = MAX_37SI_SAMPLES;	//Default to 10 samples per packet if not defined
			EepromWriteWordUnSigned((void*)(pTaskInfo->eepromAddress + SEABIRD_37SI_PACKET_SIZE_OFFSET), temp);
		}
		pTaskInfo->pBuf->samplePacketSize = temp;

		//Get default destination for data
		temp = 0xFFFF;
		EepromReadWord((void*)(pTaskInfo->eepromAddress + SEABIRD_37SI_PACKET_DESTINATION_OFFSET), (void*)&temp);
		if((temp == 0xFFFF) || (temp == 0x0000))
		{
			temp = FLOAT_TO_SHORE_VIA_DEFAULT;	//Default to data to shore via default path
			EepromWriteWordUnSigned((void*)(pTaskInfo->eepromAddress + SEABIRD_37SI_PACKET_DESTINATION_OFFSET), temp);
		}
		pTaskInfo->pBuf->destination = temp;
	}

	pTaskInfo->pBuf->gotConfig = FALSE;
	pTaskInfo->pBuf->pressureInstalled = FALSE;
	pTaskInfo->pBuf->pressureBytes = 0;

	return SUCCESS;
}

void SB37SI(void* pParam)
{
	SEABIRD_37SI_TASK taskInfo;
	PSEABIRD_37SI_TASK pTaskInit = (PSEABIRD_37SI_TASK)pParam;
	uint8_t count = 0;

	memset((char*)&taskInfo, 0, sizeof(SEABIRD_37SI_TASK));

	taskInfo.taskID = pTaskInit->taskID;
	taskInfo.portNum = pTaskInit->portNum;
	taskInfo.pBuf = pTaskInit->pBuf;

	count = Seabird_37SI_Init(&taskInfo);

	if(count == SUCCESS)
	{
		count = 0;

		OSTimeDlyHMSM(0,0,2,0);

		memset(taskInfo.pBuf->bufferTx, 0, 256);
		memset(taskInfo.pBuf->bufferRx, 0, 256);

		while(1)
		{
			OSTimeDlyHMSM(0,0,0,500);

			sprintf_P(dbgMsg, PSTR("37SI for PM%d"), taskInfo.portNum);
			SEND_MSG;

			if (powerDown[taskInfo.portNum] == TRUE)
			{
				sprintf_P(dbgMsg, PSTR("Power down...")); SEND_MSG;
			}
	
			if(serialPortPassThrough[taskInfo.portNum] == TRUE)
			{
				//Set Flag so the float COMM task will proceed
				serialPortPassThroughOK = TRUE;
				
				EnablePIBModule(taskInfo.portNum, TRUE, FALSE);
				OSTimeDlyHMSM(0,0,0,500);

				SerialPortPassThrough37SI2(taskInfo.portNum);
			}

			// Check to see if we should come out of the sleep state
			if(taskInfo.pBuf->sleeping && taskInfo.pBuf->turnBackOnTime < getsecondtick())
			{
				//SB37SI_TurnOn(&taskInfo);
				SB37SI_StartSample(&taskInfo);
				taskInfo.pBuf->turnBackOnTime = 0;
				taskInfo.pBuf->sleeping = FALSE;
			}

			if(taskInfo.pBuf->sampleCTD == TRUE)
			{
				OSuartGetRxFifoCount(taskInfo.portNum, &count);
				

				if((count >= SB37SI_SAMPLE_LEN + taskInfo.pBuf->pressureBytes) && (taskInfo.pBuf->findDataFrame == FALSE))
				{
					SB37SI_GetCTDSample2(&taskInfo);

#ifdef DEBUG_MESSAGES
					memset(taskInfo.pBuf->bufferTx, 0, 256);
					
					sprintf_P(taskInfo.pBuf->bufferTx, PSTR("\r\nBoard ID=%02d, Task ID=%02d, New Sample. P=%05lX, T=%05lX, C=%05lX\r\n\r\n"),
							 mainBoardID, taskInfo.taskID,
							 taskInfo.pBuf->reportData.dataBlock[taskInfo.pBuf->reportData.headerReport.repeatCount - 1].pressure,
							 taskInfo.pBuf->reportData.dataBlock[taskInfo.pBuf->reportData.headerReport.repeatCount - 1].temperature,
							 taskInfo.pBuf->reportData.dataBlock[taskInfo.pBuf->reportData.headerReport.repeatCount - 1].conductivity);

					taskInfo.pBuf->dbgInfo.pBuffer = taskInfo.pBuf->bufferTx;
					taskInfo.pBuf->dbgInfo.lenBuffer = strlen(taskInfo.pBuf->bufferTx);
					taskInfo.pBuf->dbgInfo.fmtBuffer = DEBUG_ASCII;
					taskInfo.pBuf->dbgInfo.dbgLevel = 5;

					SendDebugMsg(&(taskInfo.pBuf->dbgInfo));
#endif		//DEBUG_MESSAGES

					if (taskInfo.pBuf->reportData.headerReport.repeatCount >= taskInfo.pBuf->samplePacketSize)
					{
						taskInfo.pBuf->reportData.headerReport.payloadType = 0x00000021;		//0x00000070;
						taskInfo.pBuf->reportData.headerReport.boardID = mainBoardID;
						taskInfo.pBuf->reportData.headerReport.taskID = taskInfo.taskID;
						taskInfo.pBuf->reportData.headerReport.dataFormat = 8;
						taskInfo.pBuf->reportData.headerReport.parser = 0;
						taskInfo.pBuf->reportData.headerReport.priority = 2;
						
						SB37SI_CTDReportXmit2(&taskInfo);

						memset(&taskInfo.pBuf->reportData, 0, sizeof(SB37SI_DATA_REPORT));

						if(taskInfo.pBuf->offTime != 0)
						{
							SB37SI_StopSample(&taskInfo);
							//SB37SI_TurnOff(&taskInfo);
							taskInfo.pBuf->turnBackOnTime = getsecondtick() + taskInfo.pBuf->offTime;
							taskInfo.pBuf->sleeping = TRUE;
						}
					}

					count = 0;
				}

				if((taskInfo.pBuf->findDataFrame == TRUE) && (count >= (2 * (SB37SI_SAMPLE_LEN + taskInfo.pBuf->pressureBytes))))
				{
					SB37SI_GetCTDSampleFrame(&taskInfo);
				}
			}

			if(consoleAvailable[taskInfo.portNum] == TRUE)
			{
				taskInfo.pBuf->responseInfo.source = consoleIn[taskInfo.taskID].cmdSrcAddress;
				taskInfo.pBuf->responseInfo.status = 0;
				taskInfo.pBuf->responseInfo.length = consoleIn[taskInfo.taskID].cmdSize;
				taskInfo.pBuf->responseInfo.id = consoleIn[taskInfo.taskID].id;

				SB37SI_ParseConsole2(&taskInfo);
				consoleAvailable[taskInfo.portNum] = FALSE;
			}
			
			// Check to see if we need to end this task and release resources
			if (kill[taskInfo.portNum] == TRUE) 
			{
				//sprintf_P(dbgMsg, PSTR("Ending task...."));
				//SEND_MSG;

				uint8_t val = 0xFF;
				uint16_t startAddr = 0;

				if(taskInfo.portNum == USER_PORT_1)
					startAddr = EEPROM_PM1_START;
				if(taskInfo.portNum == USER_PORT_2)
					startAddr = EEPROM_PM2_START;
				if(taskInfo.portNum == USER_PORT_3)
					startAddr = EEPROM_PM3_START;

				if (startAddr == 0)
				{
					//sprintf_P(dbgMsg, PSTR("No start address for EEPROM"));
					//SEND_MSG;
					kill[taskInfo.portNum] = FALSE;
				}
				else
				{
					// Write all F's to EEPROM
					for (uint16_t addr = startAddr; addr < startAddr + EEPROM_PM_SIZE; addr++)
						EepromWriteBlock((void*)addr, (void*)&val, 1);

					// Turn off PIB
					EnablePIBModule(taskInfo.portNum, FALSE, FALSE);

					memset(taskInfo.pBuf, 0, TASK_BUF_SIZE);

					// Now end task (ie, just sleep for a really long time)
					while (1) OSTimeDlyHMSM(1,0,0,0);
				}
            }							
		}
	}
	return;
}


uint8_t SB37SI_CTD_Tx2(PSEABIRD_37SI_TASK pTaskInfo)
{
	uint8_t retval = FAIL;
	uint8_t firstCharTries = 3;
	char c = 0;
	uint8_t err = 0;
	char* pBuffer = pTaskInfo->pBuf->bufferTx;
	uint16_t len;

	len = strlen(pBuffer);

	if((len > 0) && (len <= 255))
	{
		while(len > 0)
		{
			c = 0;
			err = OSuartPutCharWait(pTaskInfo->portNum, *pBuffer, 10);
			if(err != OS_ERR_NONE)
				return retval;

			c = (char) OSuartGetCharWait(pTaskInfo->portNum, 128, &err);
		
			if(err != OS_ERR_NONE)
			{
				if(firstCharTries > 0)
				{
					firstCharTries--;
					OSTimeDlyHMSM(0,0,0,100);
				}
				else
					return retval;
			}
			if(c == *pBuffer)
			{
				pBuffer++;
				firstCharTries = 0;
				len--;
			}
			else
			{
				if(firstCharTries == 0)
					return retval;
			}
		}

		c = 0;
		err = OSuartPutCharWait(pTaskInfo->portNum, 0x0D, 10);		//Terminate command with carriage return		
		if(err != OS_ERR_NONE)
			return retval;

		c = (char) OSuartGetCharWait(pTaskInfo->portNum, 10, &err);	//Echos is Carriage Return
		c = (char) OSuartGetCharWait(pTaskInfo->portNum, 10, &err);	//And Line Feed
		if(c == 0x0A)
			retval = SUCCESS;
	}


	return retval;
}

uint8_t SB37SI_CTD_Rx2(PSEABIRD_37SI_TASK pTaskInfo, prog_char* pEOL, uint16_t* pLen)
{
	uint8_t retval = FAIL;
	char* pChar = pTaskInfo->pBuf->bufferRx;
	uint8_t err = 0;
	uint8_t lenEOL = strlen_P(pEOL);

	*pLen = 0;

	*pChar = (char)(OSuartGetCharWait(pTaskInfo->portNum, 640, &err));	//Wait 5 seconds for first character
			
	if(err != OS_ERR_NONE)
	{
		*pLen = 0;
		return retval;
	}

	pChar++;
	(*pLen)++;

	while((retval == FAIL) && (*pLen<1024))
	{
		*pChar = (char) OSuartGetCharWait(pTaskInfo->portNum, 64, &err);	//Wait 0.5 seconds for each additional character
			
		if(err != OS_ERR_NONE)
		{
			*pLen = 0;
			return retval;
		}

		pChar++;
		(*pLen)++;

		if(*pLen >= lenEOL)
		{
			err = strncmp_P((char *)(pChar - lenEOL), pEOL, lenEOL);
			if(err == 0)
				retval = SUCCESS;
		}
	}

	return retval;
}


void SB37SI_GetCTDSampleFrame(PSEABIRD_37SI_TASK pTaskInfo)
{
	uint8_t err = OS_ERR_NONE;
	uint8_t sum;

	for(int i=0; i<2*(SB37SI_SAMPLE_LEN + pTaskInfo->pBuf->pressureBytes); i++)
	{
		pTaskInfo->pBuf->frameBuf[i] = (uint8_t)(OSuartGetCharWait(pTaskInfo->portNum, 12, &err));
		if(i >= 12)
		{
			sum = 0;
			for(int j=i-12; j<=i; j++)
				sum += pTaskInfo->pBuf->frameBuf[j];
			
			if(sum == 0)
			{
				pTaskInfo->pBuf->findDataFrame = FALSE;
				break;
			}
		}
	}

	return;
}

void SB37SI_GetCTDSample2(PSEABIRD_37SI_TASK pTaskInfo)
{
#define X_37SI1	pTaskInfo->pBuf->reportData.dataBlock
#define X_37SI2	pTaskInfo->pBuf->reportData.headerReport.repeatCount

	uint8_t count = 0;
	uint8_t err = OS_ERR_NONE;
	int32_t* pTemp;
	uint8_t checksum = 0xFF;
		
	memset(pTaskInfo->pBuf->bufferRx, 0, 256);

	while((count < (SB37SI_SAMPLE_LEN + pTaskInfo->pBuf->pressureBytes)) && (err == OS_ERR_NONE))
	{
		pTaskInfo->pBuf->bufferRx[count] = OSuartGetCharWait(pTaskInfo->portNum, 12, &err);
		count++;
	}

	if(count == (SB37SI_SAMPLE_LEN + pTaskInfo->pBuf->pressureBytes))
	{
		checksum = 0;
		for(int i=0; i<(SB37SI_SAMPLE_LEN + pTaskInfo->pBuf->pressureBytes); i++)
			checksum += (uint8_t)(pTaskInfo->pBuf->bufferRx[i]);
	}
	
	if(checksum == 0)
	{
		X_37SI1[X_37SI2].headerData.latitude = latitude;
		X_37SI1[X_37SI2].headerData.longitude = longitude;
		X_37SI1[X_37SI2].headerData.timestamp = gettime();

		pTemp = (int32_t*)pTaskInfo->pBuf->bufferRx;

		X_37SI1[X_37SI2].temperature = *pTemp;
		pTemp++;

		X_37SI1[X_37SI2].conductivity = *pTemp;
		pTemp++;

		if(pTaskInfo->pBuf->pressureInstalled == TRUE)
			X_37SI1[X_37SI2].pressure = *pTemp;
		else
			X_37SI1[X_37SI2].pressure = 0;

		pTaskInfo->pBuf->reportData.headerReport.repeatCount++;
	}
	else
	{
		pTaskInfo->pBuf->findDataFrame = TRUE;
	}

#undef X_37SI1
#undef X_37SI2

	return;
}


uint8_t SB37SI_GetSerNum2(PSEABIRD_37SI_TASK pTaskInfo)
{
	uint8_t retval = FAIL;
	uint16_t lenData;

	memset(pTaskInfo->pBuf->tokenSeparatorList, 0, MAX_TOKEN_SEPARATORS);
	strcat_P(pTaskInfo->pBuf->tokenSeparatorList, tokens37SI1);

	memset(pTaskInfo->pBuf->bufferTx, 0, 256);
	memset(pTaskInfo->pBuf->bufferRx, 0, 1024);
	strcat_P(pTaskInfo->pBuf->bufferTx, cmd37SI_DS);

	retval = SB37SI_CTD_Tx2(pTaskInfo);

	if(retval == SUCCESS)
	{
		retval = SB37SI_CTD_Rx2(pTaskInfo, cmd37SI_EOL, &lenData);

		if((retval == SUCCESS) && (lenData != 0))
		{
			char* pResult = NULL;
			char* pNext = NULL;
			char myTokens[] = " \r\n\0";
			int i = 0;

			memset(pTaskInfo->pBuf->ctdInfo, 0, 64);

			pTaskInfo->pBuf->gotConfig = TRUE;

			pResult = strstr_P(pTaskInfo->pBuf->bufferRx, PSTR("pump installed = yes"));
			if(pResult != NULL)
			{
				pTaskInfo->pBuf->pressureInstalled = TRUE;
				pTaskInfo->pBuf->pressureBytes = 4;
			}
			else
			{
				pTaskInfo->pBuf->pressureInstalled = FALSE;
				pTaskInfo->pBuf->pressureBytes = 0;
			}

			pResult = strstr_P(pTaskInfo->pBuf->bufferRx, parse37SI_SerNum);
			if(pResult != NULL)
			{
				pResult++;
				pResult = strstr_P(pResult, parse37SI_SerNum);
			}

			if((pResult != NULL) && ((uint16_t)(pResult - pTaskInfo->pBuf->bufferRx) < 64))
			{
				pResult = NULL;
				pResult = strtok_r(pTaskInfo->pBuf->bufferRx, myTokens, &pNext);
				for(i=0; i<4; i++)
				{
					if(pResult != NULL)
					{
						strcat(pTaskInfo->pBuf->ctdInfo, pResult);
						strcat(pTaskInfo->pBuf->ctdInfo, " ");
					}
					else
						break;
		
					pResult = strtok_r(NULL, myTokens, &pNext);
				}

				memset(pTaskInfo->pBuf->serialNumber, 0, 16);
				if((i == 4) && (pResult != NULL))
				{
					strcat(pTaskInfo->pBuf->ctdInfo, pResult);
					strcat(pTaskInfo->pBuf->serialNumber, pResult);
				}
				else
					memset(pTaskInfo->pBuf->ctdInfo, 0, 64);
			}
		}
	}

	return retval;
}



uint8_t SB37SI_CTDReportXmit2(PSEABIRD_37SI_TASK pTaskInfo)
{
	uint8_t retval = 0;
	uint8_t err = 0;
//	PPIB_DATA_FORWARD_MESSAGE pReport = NULL;
	PSEABIRD_SB37SI_DATA_REPORT_XMIT pReport = NULL;


	OSMutexPend(pMutexFloatQueue, INFINITE, &err);


	pReport = (PSEABIRD_SB37SI_DATA_REPORT_XMIT)&(txFloatData[headFloatTx]);
	memset(pReport, 0, sizeof(FLOAT_TX_BUFFER));


	pReport->comm.headers.length  = sizeof(PIB_IRIDIUM_DATA_XMIT) + CRC16_SIZE;
	pReport->comm.headers.length  += pTaskInfo->pBuf->reportData.headerReport.repeatCount * sizeof(SBSB37SI_DATA_REPORT_BLOCK);	
	pReport->comm.headers.length  += sizeof(TYPE_91_REPORT_HEADER);	
	
	pReport->comm.headers.destination = FLOAT_IRIDIUM_INTERFACE;

	pReport->comm.iridiumInfo.structureType = 0x91;
	pReport->comm.iridiumInfo.size = pReport->comm.headers.length - sizeof(PIB_IRIDIUM_DATA_XMIT) - CRC16_SIZE;


	memcpy((char*)&(pReport->reportData), &pTaskInfo->pBuf->reportData, pReport->comm.iridiumInfo.size);

	(headFloatTx < MAX_FLOAT_BUFFERS - 1) ? (headFloatTx++) : (headFloatTx = 0);

	if(headFloatTx == tailFloatTx)
		(tailFloatTx < MAX_FLOAT_BUFFERS - 1) ? (tailFloatTx++) : (tailFloatTx = 0);

	OSMutexPost(pMutexFloatQueue);

	return retval;

////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
//
//	Block below was removed to get PIB to use old data transport protocols
//
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
//
//	pReport = (PPIB_DATA_FORWARD_MESSAGE)&(txFloatData[headFloatTx]);
//
//	pReport->headers.destination = FLOAT_TASK_FORWARD_MESSAGE;		//pTaskInfo->pBuf->destination;
//	pReport->headers.source = ((uint16_t)mainBoardID<<8) | pTaskInfo->taskID;
//
//	pReport->fwdInfo.msgFormat = MSG_FORMAT_SHIP_TO_SHORE;
//	pReport->fwdInfo.destination = pTaskInfo->pBuf->destination;
//	pReport->fwdInfo.source = pReport->headers.source;
//
//	pReport->iridiumInfo.headerICD.type = 0x91;
//	pReport->iridiumInfo.headerICD.packetID = 0;
//	pReport->iridiumInfo.headerICD.size = pTaskInfo->pBuf->reportData.headerReport.repeatCount * sizeof(SBSB37SI_DATA_REPORT_BLOCK);
//	pReport->iridiumInfo.headerICD.size += sizeof(TYPE_91_REPORT_HEADER);
//
//	pReport->headers.length = sizeof(PIB_DATA_FORWARD_MESSAGE) + pReport->iridiumInfo.headerICD.size + CRC16_SIZE;
//
//	memcpy((char*)&(pReport[1]), &pTaskInfo->pBuf->reportData, pReport->iridiumInfo.headerICD.size);
//
//	(headFloatTx < MAX_FLOAT_BUFFERS - 1) ? (headFloatTx++) : (headFloatTx = 0);
//
//	if(headFloatTx == tailFloatTx)
//		(tailFloatTx < MAX_FLOAT_BUFFERS - 1) ? (tailFloatTx++) : (tailFloatTx = 0);
//
//	OSMutexPost(pMutexFloatQueue);
//
//	return retval;
//
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
}


void SB37SI_ParseConsole2(PSEABIRD_37SI_TASK pTaskInfo)
{

	char* myCommand = consoleIn[pTaskInfo->taskID].cmd; 
	char* result = NULL;
	char command = 0;
	BOOL goodCommand = FALSE;
	uint8_t resultCode = 0;

	myCommand[MAX_FILE_SIZE_IN - 1] = 0;			//Make sure command string is NULL terminated

	memset(pTaskInfo->pBuf->tokenSeparatorList, 0, MAX_TOKEN_SEPARATORS);
	strcat_P(pTaskInfo->pBuf->tokenSeparatorList, tokenListConsole);

	result = strtok_r(myCommand, pTaskInfo->pBuf->tokenSeparatorList, &myCommand);
	resultCode = 1;				//No Command Received

	if(result != NULL)
	{
		resultCode = 2;			//Unknown Parser Code
		if(strncasecmp_P(result, SB37SIParserID, strlen_P(SB37SIParserID)) == 0)
		{
			resultCode = 3;		//Unknown command
			command = getCommand(&myCommand, SB37SICommands[0], 8, NUM_COMMANDS, ctd37SICmdList2, pTaskInfo->pBuf->tokenSeparatorList);

			if(command != 0)
				goodCommand = TRUE;
		}
	}

	if(goodCommand == TRUE)
		resultCode = SB37SI_ParseCommand2(pTaskInfo, command, myCommand);

	if(resultCode != SUCCESS)
	{
		switch(resultCode)
		{
			case 1:
				pTaskInfo->pBuf->responseInfo.status = CONSOLE_RESPONSE_EMPTY_CMD;
				break;
			case 2:
				pTaskInfo->pBuf->responseInfo.status = CONSOLE_RESPONSE_WRONG_DEVICE;
				break;
			case 3:
				pTaskInfo->pBuf->responseInfo.status = CONSOLE_RESPONSE_UNKNOWN_CMD;
				break;
			default:
				pTaskInfo->pBuf->responseInfo.status = CONSOLE_RESPONSE_CMD_FAILED;
				break;
		}
	}

	SB37SI_QueueConsoleResponse2(pTaskInfo);

	memset(consoleIn[pTaskInfo->taskID].cmd, 0, MAX_FILE_SIZE_IN);
	consoleIn[pTaskInfo->taskID].cmdSrcAddress = 0;
	consoleIn[pTaskInfo->taskID].functionCode = 0;
	consoleIn[pTaskInfo->taskID].cmdSize = 0;
	consoleIn[pTaskInfo->taskID].id = 0;

	return;
}



void SB37SI_QueueConsoleResponse2(PSEABIRD_37SI_TASK pTaskInfo)
{
	PCONSOLE_ACK_XMIT_2 pReport;
	uint8_t err = 0;
	char* pData;

	OSMutexPend(pMutexFloatQueue, INFINITE, &err);

	pReport = (PCONSOLE_ACK_XMIT_2)&(txFloatAck[headFloatAckTx]);
	pData = (char*)pReport;

	pReport->comm.headers.destination = FLOAT_TASK_FORWARD_MESSAGE;		//pTaskInfo->pBuf->responseInfo.source;

	pReport->comm.fwdInfo.msgFormat = MSG_FORMAT_SHIP_TO_SHORE;
	pReport->comm.fwdInfo.destination = pTaskInfo->pBuf->responseInfo.source;
	pReport->comm.fwdInfo.source = mainTaskAddress | pTaskInfo->taskID;

	if(pTaskInfo->pBuf->responseInfo.status < CONSOLE_RESPONSE_UNKNOWN_CMD)
	{
		pReport->comm.headers.length = sizeof(PIB_DATA_FORWARD_MESSAGE) + sizeof(CONSOLE_ACK) + pTaskInfo->pBuf->responseInfo.length + CRC16_SIZE;

		pReport->comm.iridiumInfo.headerICD.type = ACK_CONSOLE_DATA;

		pReport->consoleAck.len = pTaskInfo->pBuf->responseInfo.length;
		pReport->consoleAck.disposition = pTaskInfo->pBuf->responseInfo.status;
		pReport->consoleAck.format = pTaskInfo->pBuf->responseInfo.format;
		pData = pData + sizeof(PIB_DATA_FORWARD_MESSAGE) + sizeof(CONSOLE_ACK);
		memcpy(pData, pTaskInfo->pBuf->consoleResponse, pTaskInfo->pBuf->responseInfo.length);
	}
	else
	{
		pReport->comm.headers.length = sizeof(PIB_DATA_FORWARD_MESSAGE) + sizeof(CONSOLE_NACK) + CRC16_SIZE;
		pReport->comm.iridiumInfo.headerICD.type = NACK_CONSOLE_DATA;
		pReport->consoleNack.numDispositions = 1;
		pReport->consoleNack.disposition[0] = pTaskInfo->pBuf->responseInfo.status;
	}

	pReport->comm.iridiumInfo.headerICD.packetID = pTaskInfo->pBuf->responseInfo.id;
	pReport->comm.iridiumInfo.headerICD.size = pReport->comm.headers.length - sizeof(PIB_DATA_FORWARD_MESSAGE) - CRC16_SIZE;


	(headFloatAckTx < MAX_ACK_BUFFERS - 1) ? (headFloatAckTx++) : (headFloatAckTx = 0);

	if(headFloatAckTx == tailFloatAckTx)
	{
		(tailFloatAckTx < MAX_ACK_BUFFERS - 1) ? (tailFloatAckTx++) : (tailFloatAckTx = 0);
	}

	OSMutexPost(pMutexFloatQueue);

	return;
}


uint8_t SB37SI_TurnOn(PSEABIRD_37SI_TASK pTaskInfo)
{
	uint8_t retval = FAIL;
	uint8_t retries = 3;
	uint16_t len = 0;

	pTaskInfo->pBuf->sampleCTD = FALSE;
	pTaskInfo->pBuf->powerCTD = FALSE;

	pTaskInfo->pBuf->reportData.headerReport.repeatCount = 0;

	EnablePIBModule(pTaskInfo->portNum, TRUE, FALSE);

	while(retries > 0)
	{
		retries--;
		OSTimeDlyHMSM(0,0,1,0);
		OSuartPutCharWait(pTaskInfo->portNum, 0x0D, 10);
		retval = SB37SI_CTD_Rx2(pTaskInfo, cmd37SI_EOL, &len);
		if(retval == SUCCESS)
			retries = 0;
	}

	if(retval == SUCCESS)
		SB37SI_StopSample(pTaskInfo);

	if(retval == SUCCESS)
	{
		OSTimeDlyHMSM(0,0,0,100);
		SB37SI_GetSerNum2(pTaskInfo);
		OSTimeDlyHMSM(0,0,0,100);
		pTaskInfo->pBuf->powerCTD = TRUE;
	}

	return retval;
}

uint8_t SB37SI_TurnOff(PSEABIRD_37SI_TASK pTaskInfo)
{
	uint8_t retval = FAIL;

	pTaskInfo->pBuf->sampleCTD = FALSE;
	pTaskInfo->pBuf->powerCTD = FALSE;

	EnablePIBModule(pTaskInfo->portNum, FALSE, FALSE);


	pTaskInfo->pBuf->reportData.headerReport.payloadType = 0x00000021;
	pTaskInfo->pBuf->reportData.headerReport.boardID = mainBoardID;
	pTaskInfo->pBuf->reportData.headerReport.taskID = pTaskInfo->taskID;
	pTaskInfo->pBuf->reportData.headerReport.dataFormat = 8;
	pTaskInfo->pBuf->reportData.headerReport.parser = 0;
	pTaskInfo->pBuf->reportData.headerReport.priority = 2;

	if(pTaskInfo->pBuf->reportData.headerReport.repeatCount != 0)
		SB37SI_CTDReportXmit2(pTaskInfo);

	pTaskInfo->pBuf->reportData.headerReport.repeatCount = 0;

	return retval;
}

uint8_t SB37SI_StartSample(PSEABIRD_37SI_TASK pTaskInfo)
{
	uint8_t retval = FAIL;
	uint16_t lenData = 0;

	retval = SB37SI_SetPeriod(pTaskInfo, pTaskInfo->pBuf->sampleRate);

	pTaskInfo->pBuf->reportData.headerReport.repeatCount = 0;
	pTaskInfo->pBuf->sampleCTD = TRUE;

	memset(pTaskInfo->pBuf->bufferTx, 0, 256);
	memset(pTaskInfo->pBuf->bufferRx, 0, 1024);

	strcat_P(pTaskInfo->pBuf->bufferTx, cmd37SI_Start);

	retval = SB37SI_CTD_Tx2(pTaskInfo);

	if(retval == SUCCESS)
		retval = SB37SI_CTD_Rx2(pTaskInfo, cmd37SI_EOL, &lenData);

	return retval;
}

uint8_t SB37SI_StopSample(PSEABIRD_37SI_TASK pTaskInfo)
{
	uint8_t retval = FAIL;
	uint16_t lenData = 0;
	char* pBuffer = pTaskInfo->pBuf->bufferTx;
	uint8_t err = OS_ERR_NONE;

	pTaskInfo->pBuf->reportData.headerReport.payloadType = 0x00000021;
	pTaskInfo->pBuf->reportData.headerReport.boardID = mainBoardID;
	pTaskInfo->pBuf->reportData.headerReport.taskID = pTaskInfo->taskID;
	pTaskInfo->pBuf->reportData.headerReport.dataFormat = 8;
	pTaskInfo->pBuf->reportData.headerReport.parser = 0;
	pTaskInfo->pBuf->reportData.headerReport.priority = 2;

	if(pTaskInfo->pBuf->reportData.headerReport.repeatCount != 0)
		SB37SI_CTDReportXmit2(pTaskInfo);

	pTaskInfo->pBuf->reportData.headerReport.repeatCount = 0;
	pTaskInfo->pBuf->sampleCTD = FALSE;

	memset(pTaskInfo->pBuf->bufferTx, 0, 256);
	memset(pTaskInfo->pBuf->bufferRx, 0, 1024);
	strcat_P(pTaskInfo->pBuf->bufferTx, cmd37SI_Stop);

	lenData = strlen(pBuffer);

	while(lenData > 0)
	{
		err = OSuartPutCharWait(pTaskInfo->portNum, *pBuffer, 10);
		if(err == OS_ERR_NONE)
		{
			lenData--;
			pBuffer++;
			retval = SUCCESS;
		}
		else
		{	
			retval = FAIL;
			break;
		}
	}

	if(retval == SUCCESS)
	{
		err = OSuartPutCharWait(pTaskInfo->portNum, 0x0D, 10);
		if(err != OS_ERR_NONE)
			retval = FAIL;
	}
			
	if(retval == SUCCESS)
		retval = SB37SI_CTD_Rx2(pTaskInfo, cmd37SI_EOL, &lenData);

	return retval;
}



uint8_t SB37SI_SetPeriod(PSEABIRD_37SI_TASK pTaskInfo, uint16_t newInterval)
{
	uint8_t retval = FAIL;
	uint16_t lenData = 0;

	if((newInterval > 0) && (newInterval <= MAX_37SI_SAMPLE_INTERVAL))
	{
		memset(pTaskInfo->pBuf->bufferTx, 0, 256);
		memset(pTaskInfo->pBuf->bufferRx, 0, 1024);
		sprintf_P(pTaskInfo->pBuf->bufferTx, cmd37SI_Interval, newInterval);

		retval = SB37SI_CTD_Tx2(pTaskInfo);

		if(retval == SUCCESS)
			retval = SB37SI_CTD_Rx2(pTaskInfo, cmd37SI_EOL, &lenData);

		if(retval == SUCCESS)
		{
			EepromWriteWordUnSigned((void*)(pTaskInfo->eepromAddress + SEABIRD_37SI_SAMPLE_INTERVAL_OFFSET), newInterval);
			pTaskInfo->pBuf->sampleRate = newInterval;
		}
	}
	return retval;
}

uint8_t SB37SI_SetPacketSize(PSEABIRD_37SI_TASK pTaskInfo, uint8_t newPacketSize)
{
	uint8_t retval = FAIL;

	if((newPacketSize > 0) && (newPacketSize <= MAX_37SI_SAMPLES))
	{
		retval = SUCCESS;

		EepromWriteWordUnSigned((void*)(pTaskInfo->eepromAddress + SEABIRD_37SI_PACKET_SIZE_OFFSET), newPacketSize);
		pTaskInfo->pBuf->samplePacketSize = newPacketSize;

		if(pTaskInfo->pBuf->reportData.headerReport.repeatCount >= pTaskInfo->pBuf->samplePacketSize)
		{
			//Send current data to shore
		}
	}

	return retval;
}

uint8_t SB37SI_SetPacketDest(PSEABIRD_37SI_TASK pTaskInfo, uint16_t newDest)
{
	uint8_t retval = FAIL;

	if(newDest == 0)
		newDest = FLOAT_TO_SHORE_VIA_DEFAULT;

	if((newDest > 0) && (newDest < 0xFF00))
	{
		retval = SUCCESS;

		EepromWriteWordUnSigned((void*)(pTaskInfo->eepromAddress + SEABIRD_37SI_PACKET_DESTINATION_OFFSET), newDest);
		pTaskInfo->pBuf->samplePacketSize = newDest;
	}

	return retval;
}

uint8_t SB37SI_Id(PSEABIRD_37SI_TASK pTaskInfo)
{
	uint8_t retval = SUCCESS;

	memset((char*)pTaskInfo->pBuf->consoleResponse, 0, 256);
	if(strlen(pTaskInfo->pBuf->ctdInfo) > 0)
		strcat(pTaskInfo->pBuf->consoleResponse, pTaskInfo->pBuf->ctdInfo);
	else
		strcat_P(pTaskInfo->pBuf->consoleResponse, PSTR("CTD Version and Serial Number is not available."));

	pTaskInfo->pBuf->responseInfo.length = strlen(pTaskInfo->pBuf->consoleResponse);

	return retval;
}

uint8_t SB37SI_Cmd(PSEABIRD_37SI_TASK pTaskInfo, char* cmd)
{
	uint8_t retval = SUCCESS;

	if(retval == SUCCESS)
	{
		strlwr(cmd);

		if(strstr_P(cmd, PSTR("baud")) != NULL)
		{
			retval = FAIL;
			pTaskInfo->pBuf->responseInfo.status = CONSOLE_RESPONSE_DEVICE_CMD_NOT_SUPPORTED;
		}
		if(strstr_P(cmd, PSTR("outputexecutedtag")) != NULL)
		{
			retval = FAIL;
			pTaskInfo->pBuf->responseInfo.status = CONSOLE_RESPONSE_DEVICE_CMD_NOT_SUPPORTED;
		}
		if(strstr_P(cmd, PSTR("start")) != NULL)
		{
			retval = FAIL;
			pTaskInfo->pBuf->responseInfo.status = CONSOLE_RESPONSE_DEVICE_CMD_NOT_SUPPORTED;
		}
		if(strstr_P(cmd, PSTR("autorun")) != NULL)
		{
			retval = FAIL;
			pTaskInfo->pBuf->responseInfo.status = CONSOLE_RESPONSE_DEVICE_CMD_NOT_SUPPORTED;
		}
		if(strstr_P(cmd, PSTR("get")) != NULL)
		{
			retval = FAIL;
			pTaskInfo->pBuf->responseInfo.status = CONSOLE_RESPONSE_DEVICE_CMD_NOT_SUPPORTED;
		}
		if(strstr_P(cmd, PSTR("resetlogging")) != NULL)
		{
			retval = FAIL;
			pTaskInfo->pBuf->responseInfo.status = CONSOLE_RESPONSE_DEVICE_CMD_NOT_SUPPORTED;
		}
		if(strstr_P(cmd, PSTR("resetec")) != NULL)
		{
			retval = FAIL;
			pTaskInfo->pBuf->responseInfo.status = CONSOLE_RESPONSE_DEVICE_CMD_NOT_SUPPORTED;
		}

		if(retval != FAIL)
		{
			uint16_t lenData;

			memset(pTaskInfo->pBuf->bufferTx, 0, 256);
			memset(pTaskInfo->pBuf->bufferRx, 0, 1024);
			strcat(pTaskInfo->pBuf->bufferTx, cmd);

			retval = SB37SI_CTD_Tx2(pTaskInfo);

			if(retval == SUCCESS)
			{
				retval = SB37SI_CTD_Rx2(pTaskInfo, cmd37SI_EOL, &lenData);

				if((retval == SUCCESS) && (lenData != 0))
				{
					memset((char*)pTaskInfo->pBuf->consoleResponse, 0, 256);
					if(lenData <= 256)
					{
						pTaskInfo->pBuf->responseInfo.status = CONSOLE_RESPONSE_OK;
						memcpy((char*)pTaskInfo->pBuf->consoleResponse, pTaskInfo->pBuf->bufferRx, lenData);
					}
					else
					{
						pTaskInfo->pBuf->responseInfo.status = CONSOLE_RESPONSE_OK_TRUNCATED;
						memcpy((char*)pTaskInfo->pBuf->consoleResponse, pTaskInfo->pBuf->bufferRx, 255);
						pTaskInfo->pBuf->consoleResponse[255] = 0;
					}
					pTaskInfo->pBuf->responseInfo.length = strlen(pTaskInfo->pBuf->consoleResponse);
				}
			}
		}
	}
	else
	{
		pTaskInfo->pBuf->responseInfo.status = CONSOLE_RESPONSE_DEVICE_NOT_RESPONDING;
	}	

	return retval;
}


uint8_t SB37SI_SetTime(PSEABIRD_37SI_TASK pTaskInfo)
{
	uint8_t retval = FAIL;
	tm* dt;
	time_t time;
	uint16_t lenData;

	time=gettime();
	dt = gmtime(&time);

	memset(pTaskInfo->pBuf->bufferTx, 0, 256);
	memset(pTaskInfo->pBuf->bufferRx, 0, 1024);

	sprintf_P(pTaskInfo->pBuf->bufferTx, cmd37SI_DateTime, dt->tm_mon+1, dt->tm_mday, dt->tm_year+1900,
	                                                        dt->tm_hour, dt->tm_min, dt->tm_sec); 

	retval = SB37SI_CTD_Tx2(pTaskInfo);

	if(retval == SUCCESS)
		retval = SB37SI_CTD_Rx2(pTaskInfo, cmd37SI_EOL, &lenData);

	return retval;
}


uint8_t SB37SI_ParseCommand2(PSEABIRD_37SI_TASK pTaskInfo, char command, char* cmdParams)
{
	uint8_t paramCount = 0;
	char* result = NULL;
	uint8_t retval = FAIL;		//Missing or Invalid Parameter
	uint16_t newVal = 0;
	BOOL statusResponse = TRUE;

	memset(pTaskInfo->pBuf->tokenSeparatorList, 0, MAX_TOKEN_SEPARATORS);
	strcat_P(pTaskInfo->pBuf->tokenSeparatorList, tokenListConsole);

	switch(command)
	{
	case 'o':
	case 'O':
		//Power On
		retval = SB37SI_TurnOn(pTaskInfo);
		break;
	case 'f':
	case 'F':
		//Power Off
		retval = SB37SI_TurnOff(pTaskInfo);
		pTaskInfo->pBuf->sleeping = FALSE;
		break;
	case 'r':
	case 'R':
		//Start Sampling
		if(pTaskInfo->pBuf->powerCTD == FALSE)
			retval = SB37SI_TurnOn(pTaskInfo);

		if(pTaskInfo->pBuf->sampleCTD == TRUE)
		{
			retval = SB37SI_StopSample(pTaskInfo);
			OSTimeDlyHMSM(0,0,1,0);
		}
		
		if(pTaskInfo->pBuf->gotConfig == FALSE)
			SB37SI_GetSerNum2(pTaskInfo);

		memset(pTaskInfo->pBuf->tokenSeparatorList, 0, MAX_TOKEN_SEPARATORS);
		strcat_P(pTaskInfo->pBuf->tokenSeparatorList, tokenListConsole);

		result = strtok_r(cmdParams, pTaskInfo->pBuf->tokenSeparatorList, &cmdParams);
		while((result != NULL) && (paramCount < 3))
		{
			newVal = (uint16_t)(strtol(result, &result, 0));
			switch(paramCount)
			{
			case PARAM_PERIOD:
				SB37SI_SetPeriod(pTaskInfo, newVal);
				break;
			case PARAM_SIZE:
				SB37SI_SetPacketSize(pTaskInfo, newVal);
				break;
			case PARAM_DEST:
				SB37SI_SetPacketDest(pTaskInfo, newVal);
				break;
			}
			paramCount++;
			result = strtok_r(NULL, pTaskInfo->pBuf->tokenSeparatorList, &cmdParams);
		}
		retval = SB37SI_SetTime(pTaskInfo);
		retval = SB37SI_StartSample(pTaskInfo);
		break;
	case 'x':
	case 'X':
		//Stop Sampling
		retval = SB37SI_StopSample(pTaskInfo);
		pTaskInfo->pBuf->sleeping = FALSE;
		break;
	case 'p':
	case 'P':
		//Set default sample interval
		if(pTaskInfo->pBuf->powerCTD == FALSE)
			retval = SB37SI_TurnOn(pTaskInfo);

		memset(pTaskInfo->pBuf->tokenSeparatorList, 0, MAX_TOKEN_SEPARATORS);
		strcat_P(pTaskInfo->pBuf->tokenSeparatorList, tokenListConsole);

		result = strtok_r(result, pTaskInfo->pBuf->tokenSeparatorList, &cmdParams);
		if(result != NULL)
		{
			newVal = (uint16_t)(strtol(result, &result, 0));
			retval = SB37SI_SetPeriod(pTaskInfo, newVal);
		}
		break;
	case 'z':
	case 'Z':
		//set default sample block size
		memset(pTaskInfo->pBuf->tokenSeparatorList, 0, MAX_TOKEN_SEPARATORS);
		strcat_P(pTaskInfo->pBuf->tokenSeparatorList, tokenListConsole);

		result = strtok_r(result, pTaskInfo->pBuf->tokenSeparatorList, &cmdParams);
		if(result != NULL)
		{
			newVal = (uint16_t)(strtol(result, &result, 0));
			retval = SB37SI_SetPacketSize(pTaskInfo, newVal);
		}
		break;
	case 'd':
	case 'D':
		//set default destination
		memset(pTaskInfo->pBuf->tokenSeparatorList, 0, MAX_TOKEN_SEPARATORS);
		strcat_P(pTaskInfo->pBuf->tokenSeparatorList, tokenListConsole);

		result = strtok_r(result, pTaskInfo->pBuf->tokenSeparatorList, &cmdParams);
		if(result != NULL)
		{
			newVal = (uint16_t)(strtol(result, &result, 0));
			retval = SB37SI_SetPacketDest(pTaskInfo, newVal);
		}
		break;
	case 'i':
	case 'I':
		if(pTaskInfo->pBuf->powerCTD == FALSE)
			retval = SB37SI_TurnOn(pTaskInfo);

		//Return Serial Number and Version information
		retval = SB37SI_Id(pTaskInfo);
		statusResponse = FALSE;
		pTaskInfo->pBuf->responseInfo.status = CONSOLE_RESPONSE_OK;
		break;
	case 's':
	case 'S':
		//Return CTD operating Status -- don't need to do anything here
		break;
	case 'y':
	case 'Y':
		result = strtok_r(result, pTaskInfo->pBuf->tokenSeparatorList, &cmdParams);
		pTaskInfo->pBuf->offTime = (uint16_t)(strtol(result, &result, 0));
		//pTaskInfo->pBuf->turnBackOnTime = 0;
		break;
	case 'c':
	case 'C':
		//CTD Pass Thru Command
		if(pTaskInfo->pBuf->powerCTD == FALSE)
		{
			retval = SB37SI_TurnOn(pTaskInfo);
			OSTimeDlyHMSM(0,0,2,0);
		}

		if(pTaskInfo->pBuf->sampleCTD == FALSE)
		{
			memset(pTaskInfo->pBuf->tokenSeparatorList, 0, MAX_TOKEN_SEPARATORS);
			strcat_P(pTaskInfo->pBuf->tokenSeparatorList, tokenListConsole);

			result = strtok_r(cmdParams, pTaskInfo->pBuf->tokenSeparatorList, &cmdParams);
			if(result != NULL)
				retval = SB37SI_Cmd(pTaskInfo, result);
			else
				pTaskInfo->pBuf->responseInfo.status = CONSOLE_RESPONSE_EMPTY_CMD;
		}
		else
		{
			pTaskInfo->pBuf->responseInfo.status = CONSOLE_RESPONSE_DEVICE_BUSY;
		}

		statusResponse = FALSE;
		break;
	default:
		retval = FAIL;
	}

	if(statusResponse == TRUE)
	{
		retval = SUCCESS;
		SB37SI_CreateStatusResponse(pTaskInfo, retval);
	}

	return retval;
}


uint8_t SB37SI_CreateStatusResponse(PSEABIRD_37SI_TASK pTaskInfo, uint8_t status)
{
	memset(pTaskInfo->pBuf->statusConstructor, 0, 100);
	memset(pTaskInfo->pBuf->consoleResponse, 0, 256);

	if(status == SUCCESS)
		strcat_P(pTaskInfo->pBuf->statusConstructor, status37SI_OK);
	else
		strcat_P(pTaskInfo->pBuf->statusConstructor, status37SI_Fail);

	strcat_P(pTaskInfo->pBuf->statusConstructor, status37SI_Msg2);
	if(pTaskInfo->pBuf->powerCTD == TRUE)
		strcat_P(pTaskInfo->pBuf->statusConstructor, status37SI_On);
	else
		strcat_P(pTaskInfo->pBuf->statusConstructor, status37SI_Off);

	strcat_P(pTaskInfo->pBuf->statusConstructor, status37SI_Msg3);
	if(pTaskInfo->pBuf->sampleCTD == TRUE)
		strcat_P(pTaskInfo->pBuf->statusConstructor, status37SI_On);
	else
		strcat_P(pTaskInfo->pBuf->statusConstructor, status37SI_Off);

	if(pTaskInfo->pBuf->destination >= 0x100)
		strcat_P(pTaskInfo->pBuf->statusConstructor, status37SI_Msg4);
	else
		strcat_P(pTaskInfo->pBuf->statusConstructor, status37SI_Msg5);

	sprintf((char*)pTaskInfo->pBuf->consoleResponse, pTaskInfo->pBuf->statusConstructor, pTaskInfo->pBuf->sampleRate, pTaskInfo->pBuf->samplePacketSize, pTaskInfo->pBuf->offTime, pTaskInfo->pBuf->sleeping ? "ON":"OFF", pTaskInfo->pBuf->destination);

	pTaskInfo->pBuf->responseInfo.status = CONSOLE_RESPONSE_OK;
	pTaskInfo->pBuf->responseInfo.length = strlen(pTaskInfo->pBuf->consoleResponse);

	return SUCCESS;
}

void SerialPortPassThrough37SI2(uint8_t port)
{
	readyForSerialPassThru = TRUE;

	while(1)
	{
		OSTimeDlyHMSM(1,0,0,0);
	}
}
