//----------------------------------------------------------------------------------
// <copyright file="SeabirdGPCTD.c" company="LiquidRobotics">
//	Copyright (c) Liquid Robotics Corporation.  All rights reserved.
// </copyright>
//
// <summary>
// 	This is the source for managing Seabird GPCTD
// </summary>
//----------------------------------------------------------------------------------

#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 "SeabirdGPCTD.h"

#include "SerialDebug.h"


//Serial Number stored at offset 0x0010 from PM base -- 16 bytes
#define SEABIRD_GPCTD_SERNUM_OFFSET					0x0010
//Sample Rate stored at offset 0x0040 from PM base -- 2 bytes
#define SEABIRD_GPCTD_SAMPLE_INTERVAL_OFFSET		0x0040
//Packet Size stored at offset 0x0042 from PM base -- 2 bytes
#define SEABIRD_GPCTD_PACKET_SIZE_OFFSET			0x0042
//Data Destination stored at offset 0x0044 from PM base -- 2 bytes
#define SEABIRD_GPCTD_PACKET_DESTINATION_OFFSET		0x0044
//Flag indicating O2 Sensor stored at offset 0x0046 from PM base -- 1 byte
#define SEABIRD_GPCTD_PACKET_O2_OFFSET				0x0046
//Idle time between sample blocks when duty cycling the CTD	-- 2 bytes
#define SEABIRD_GPCTD_PACKET_CYCLE_OFFSET			0x0047
//Autorun State stored at offset 0x0049 from PM base -- 1 byte
#define SEABIRD_GPCTD_AUTORUN_OFFSET				0x0049
//Time to run the pump in order to fluch the plumbing before sampling when duty cycling the CTD	-- 2 bytes
#define SEABIRD_GPCTD_PUMP_FLUSH_OFFSET				0x0050

#define MAX_GPCTD_SAMPLES	10
#define MAX_GPCTD_SAMPLE_INTERVAL		3600
#define DEFAULT_GPCTD_SAMPLE_INTERVAL	60

#define MAX_OFF_TIME		43200
#define MAX_FLUSH_TIME		110

#define NO_O2	0
#define USE_O2	1

typedef struct _GPCTD_DATA_REPORT_BLOCK_
{
	TYPE_90_91_DATA_HEADER	headerData;
	uint32_t				pressure;
	uint32_t				temperature;
	uint32_t				conductivity;	
}GPCTD_DATA_REPORT_BLOCK, *PGPCTD_DATA_REPORT_BLOCK;

typedef struct _GPCTD_DATA_REPORT_BLOCK_2_
{
	TYPE_90_91_DATA_HEADER	headerData;
	uint32_t				pressure;
	uint32_t				temperature;
	uint32_t				conductivity;	
	uint32_t				oxygen;	
}GPCTD_DATA_REPORT_BLOCK_2, *PGPCTD_DATA_REPORT_BLOCK_2;

typedef struct _GPCTD_DATA_REPORT_
{
	TYPE_91_REPORT_HEADER	headerReport;
	GPCTD_DATA_REPORT_BLOCK	dataBlock[MAX_GPCTD_SAMPLES];
}GPCTD_DATA_REPORT, *PGPCTD_DATA_REPORT;

typedef struct _GPCTD_DATA_REPORT_2_
{
	TYPE_91_REPORT_HEADER		headerReport;
	GPCTD_DATA_REPORT_BLOCK_2	dataBlock2[MAX_GPCTD_SAMPLES];
}GPCTD_DATA_REPORT_2, *PGPCTD_DATA_REPORT_2;

typedef struct _GPCTD_ASCII_REPORT_
{
	TYPE_91_REPORT_HEADER	headerReport;
	TYPE_90_91_DATA_HEADER	headerData;
	char					data[165];
}GPCTD_ASCII_REPORT, *PGPCTD_ASCII_REPORT;

typedef struct _SEABIRD_GPCTD_DATA_REPORT_XMIT_
{
	PIB_IRIDIUM_DATA_XMIT	comm;
	GPCTD_DATA_REPORT		reportData;
}SEABIRD_GPCTD_DATA_REPORT_XMIT, *PSEABIRD_GPCTD_DATA_REPORT_XMIT;

typedef struct _SEABIRD_GPCTD_DATA_REPORT_XMIT_2_
{
	PIB_IRIDIUM_DATA_XMIT	comm;
	GPCTD_DATA_REPORT_2		reportData;
}SEABIRD_GPCTD_DATA_REPORT_XMIT_2, *PSEABIRD_GPCTD_DATA_REPORT_XMIT_2;

typedef struct _SEABIRD_GPCTD_ASCII_REPORT_XMIT_
{
	PIB_IRIDIUM_DATA_XMIT	comm;
	GPCTD_ASCII_REPORT		reportASCII;
}SEABIRD_GPCTD_ASCII_REPORT_XMIT, *PSEABIRD_GPCTD_ASCII_REPORT_XMIT;


typedef struct _SEABIRD_GPCTD_BUFFER_
{
	char 					bufferTx[256];
	char 					bufferRx[1024];
	uint8_t					initState;
	uint16_t 				sampleRate;
	uint16_t 				samplePacketSize;
	uint16_t 				destination;
	char 					serialNumber[16];
	char					ctdInfo[64];
	BOOL					sampleCTD;
	BOOL					powerCTD;
	uint8_t					useO2;
	BOOL					findDataFrame;
	GPCTD_DATA_REPORT		reportData;
	GPCTD_DATA_REPORT_2		reportData2;
	CONSOLE_RESPONSE_INFO	responseInfo;
	char					tokenSeparatorList[MAX_TOKEN_SEPARATORS];
	char					statusConstructor[128];
	char					consoleResponse[256];
	uint32_t				fileID;
	DEBUG_OUTPUT_INFO		dbgInfo;
	uint16_t				offTime;
	uint32_t				turnBackOnTime;
	BOOL					sleeping;
	uint16_t				flushTime;
	BOOL					pumpRun;
}SEABIRD_GPCTD_BUFFER, *PSEABIRD_GPCTD_BUFFER;


typedef struct _SEABIRD_GPCTD_TASK_
{
	uint8_t		taskID;
	uint8_t 	portNum;
	uint16_t	eepromAddress;
	PSEABIRD_GPCTD_BUFFER 	pBuf;
}SEABIRD_GPCTD_TASK, *PSEABIRD_GPCTD_TASK;



uint8_t Seabird_GPCTD_Init(PSEABIRD_GPCTD_TASK taskInfo);
uint8_t SBGPCTD_CTD_Tx(PSEABIRD_GPCTD_TASK pTaskInfo);
uint8_t SBGPCTD_CTD_Rx(PSEABIRD_GPCTD_TASK pTaskInfo, prog_char* pEOL, uint16_t* pLen);
void 	SBGPCTD_GetCTDSampleNoO2(PSEABIRD_GPCTD_TASK pTtaskInfo);
void 	SBGPCTD_GetCTDSampleWithO2(PSEABIRD_GPCTD_TASK pTtaskInfo);
void 	SBGPCTD_GetCTDSampleFrame(PSEABIRD_GPCTD_TASK pTaskInfo);
uint8_t SBGPCTD_ReportCTDTelemetry(PSEABIRD_GPCTD_TASK pTaskInfo);
uint8_t SBGPCTD_AlphatoMonth(char* pChar);
uint8_t SBGPCTD_CTDReportXmitNoO2(PSEABIRD_GPCTD_TASK pTaskInfo);
uint8_t SBGPCTD_CTDReportXmitWithO2(PSEABIRD_GPCTD_TASK pTaskInfo);
uint8_t SBGPCTD_GetSerNum(PSEABIRD_GPCTD_TASK pTaskInfo);
//uint8_t SBGPCTD_ParseFile(PSEABIRD_GPCTD_TASK pTaskInfo);
uint8_t SBGPCTD_QueueFile(PSEABIRD_GPCTD_TASK pTaskInfo);


uint8_t SBGPCTD_TurnOn(PSEABIRD_GPCTD_TASK pTaskInfo);
uint8_t SBGPCTD_TurnOff(PSEABIRD_GPCTD_TASK pTaskInfo);
uint8_t SBGPCTD_StartSample(PSEABIRD_GPCTD_TASK pTaskInfo);
uint8_t SBGPCTD_StopSample(PSEABIRD_GPCTD_TASK pTaskInfo);
uint8_t SBGPCTD_PumpFast(PSEABIRD_GPCTD_TASK pTaskInfo);
uint8_t SBGPCTD_SetPeriod(PSEABIRD_GPCTD_TASK pTaskInfo, uint16_t newInterval);
uint8_t SBGPCTD_SetPacketSize(PSEABIRD_GPCTD_TASK pTaskInfo, uint8_t newPacketSize);
uint8_t SBGPCTD_SetPacketDest(PSEABIRD_GPCTD_TASK pTaskInfo, uint16_t newDest);
uint8_t SBGPCTD_SetDutyCycleOffTime(PSEABIRD_GPCTD_TASK pTaskInfo, uint16_t newOffTime);
uint8_t SBGPCTD_Status(PSEABIRD_GPCTD_TASK pTaskInfo);
uint8_t SBGPCTD_Id(PSEABIRD_GPCTD_TASK pTaskInfo);
uint8_t SBGPCTD_Cmd(PSEABIRD_GPCTD_TASK pTaskInfo, char* cmd);
uint8_t SBGPCTD_SetTime(PSEABIRD_GPCTD_TASK pTaskInfo);
uint8_t SBGPCTD_CreateStatusResponse(PSEABIRD_GPCTD_TASK pTaskInfo, uint8_t status);

void SBGPCTD_SimpleStop(PSEABIRD_GPCTD_TASK pTaskInfo);
void SBGPCTD_CheckO2Sensor(PSEABIRD_GPCTD_TASK pTaskInfo);


//void SBGPCTD_ParseConsole(PSEABIRD_GPCTD_TASK pTaskInfo);
void SBGPCTD_ParseInput(PSEABIRD_GPCTD_TASK pTaskInfo, uint8_t source);
uint8_t SBGPCTD_ParseCommand(PSEABIRD_GPCTD_TASK pTaskInfo, char command, char* cmdParams);
void SBGPCTD_QueueConsoleResponse(PSEABIRD_GPCTD_TASK pTaskInfo);



void SerialPortPassThroughGPCTD(uint8_t port);

//GPCTD Command Strings
prog_char cmdGPCTD_Enter[] = "\r\n";
prog_char cmdGPCTD_DS[] = "ds";
prog_char cmdGPCTD_DC[] = "dc";
prog_char cmdGPCTD_GetHD[] = "gethd";
prog_char cmdGPCTD_GetCD[] = "getcd";
prog_char cmdGPCTD_ResetLogging[] = "resetlogging";
prog_char cmdGPCTD_DateTime[] = "datetime=%02d%02d%04d%02d%02d%02d";
prog_char cmdGPCTD_BaudRate[] = "baudrate=%ld";
prog_char cmdGPCTD_OutputExecuted[] = "outputexecuted=%c";
prog_char cmdGPCTD_AutoRun[] = "autorun=%c";
prog_char cmdGPCTD_OutputFormat[] = "outputformat=%d";
prog_char cmdGPCTD_MinCondFreq[] = "mincondfreq=%d";
prog_char cmdGPCTD_Interval[] = "interval=%d";
prog_char cmdGPCTD_CustomPump[] = "custompumpmode=%c";
prog_char cmdGPCTD_TxRealTime[] = "txrealtime=%c";
prog_char cmdGPCTD_RS232ForceOn[] = "rs232forceon=%c";
prog_char cmdGPCTD_Start[] = "start";
prog_char cmdGPCTD_Stop[] = "stop";
prog_char cmdGPCTD_PumpFast[] = "pumpfast";


//prog_char cmdGPCTD_EOL[] = "\r\nS>";
prog_char cmdGPCTD_EOL[] = "S>";
prog_char cmdGPCTD_Sample_EOL[] = "\r\n";

prog_char parseGPCTD_SerNum[] = "  ";

prog_char tokensGPCTD1[] = " \t=,:\r\n";

prog_char checkO2[] = "<SBE43>yes</SBE43>";
prog_char check2forO2[] = "\r\nacquire SBE 43";

prog_char statusGPCTD_On[] 		= "On";
prog_char statusGPCTD_Off[] 	= "Off";
prog_char statusGPCTD_OK[] 		= "SUCCESS:";
prog_char statusGPCTD_Fail[] 	= "FAILED:";
prog_char statusGPCTD_Msg2[] 	= " Pwr=";
prog_char statusGPCTD_Msg3[] 	= "  Smpl=";
prog_char statusGPCTD_Msg4[] 	= "  Intrvl=%04d sec Size=%02d smpl/pkt Off-Tm=%d Flush-Tm=%d Slp=%s Dest=0x%04X";
prog_char statusGPCTD_Msg5[] 	= "  Intrvl=%04d sec Size=%02d smpl/pkt Off-Tm=%d Flush-Tm=%d Slp=%s Dest=SHORE";
prog_char statusGPCTD_Msg6[] 	= "  Oxygen=";
prog_char statusGPCTD_Msg7[] 	= "  Autorun=";
prog_char statusGPCTD_Yes[] 	= "Yes";
prog_char statusGPCTD_No[] 		= "No";




#define GPCTD_RESET_LOGGING_CMD_LEN	82
#define GPCTD_O2_SENSOR_CMD_LEN		91
#define GPCTD_SAMPLE_NO_O2_LEN		17
#define GPCTD_SAMPLE_WITH_O2_LEN	22


#define NUM_COMMANDS 13

extern const prog_char tokenListConsole[];
prog_char gpctdCommands[NUM_COMMANDS][8] = {"on", "off", "autorun", "run", "stop", "period", "size", "dest", "stat", "id", "cmd", "cycle", "flush"};
prog_char gpctdParserID[] = "CTD";
prog_char ctdCmdList[] = "ofarxpzdsicylOFARXPZDSICYL";


#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;
extern int32_t longitude;
extern char	fixValid;

uint8_t Seabird_GPCTD_Init(PSEABIRD_GPCTD_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_GPCTD_SAMPLE_INTERVAL;
	pTaskInfo->pBuf->samplePacketSize = MAX_GPCTD_SAMPLES;
	pTaskInfo->pBuf->destination = FLOAT_TO_SHORE_VIA_DEFAULT;
	pTaskInfo->pBuf->useO2 = NO_O2;
	pTaskInfo->pBuf->findDataFrame = FALSE;
	pTaskInfo->pBuf->pumpRun = FALSE;

	if(pTaskInfo->eepromAddress != 0)
	{
		uint16_t temp;

		//Get default sample rate
		temp = 0xFFFF;
		EepromReadWord((void*)(pTaskInfo->eepromAddress + SEABIRD_GPCTD_SAMPLE_INTERVAL_OFFSET), (void*)&temp);
		if((temp == 0xFFFF) || (temp == 0x0000) || (temp > MAX_GPCTD_SAMPLE_INTERVAL))
		{
			temp = DEFAULT_GPCTD_SAMPLE_INTERVAL;	//Default to 1 sample per minute if not defined
			EepromWriteWordUnSigned((void*)(pTaskInfo->eepromAddress + SEABIRD_GPCTD_SAMPLE_INTERVAL_OFFSET), temp);
		}
		pTaskInfo->pBuf->sampleRate = temp;

		//Get default packet size for data (# samples per packet)
		temp = 0xFFFF;
		EepromReadWord((void*)(pTaskInfo->eepromAddress + SEABIRD_GPCTD_PACKET_SIZE_OFFSET), (void*)&temp);
		if((temp == 0xFFFF) || (temp == 0x0000))
		{
			temp = MAX_GPCTD_SAMPLES;	//Default to 10 samples per packet if not defined
			EepromWriteWordUnSigned((void*)(pTaskInfo->eepromAddress + SEABIRD_GPCTD_PACKET_SIZE_OFFSET), temp);
		}
		pTaskInfo->pBuf->samplePacketSize = temp;

		//Get default destination for data
		temp = 0xFFFF;
		EepromReadWord((void*)(pTaskInfo->eepromAddress + SEABIRD_GPCTD_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_GPCTD_PACKET_DESTINATION_OFFSET), temp);
		}
		pTaskInfo->pBuf->destination = temp;

		temp = 0xFFFF;
		EepromReadWord((void*)(pTaskInfo->eepromAddress + SEABIRD_GPCTD_PACKET_CYCLE_OFFSET), (void*)&temp);
		if(temp > MAX_OFF_TIME)		//12 hours = 43200 seconds
		{
			temp = 0;	//Default to 0 seconds off between sample blocks
			EepromWriteWordUnSigned((void*)(pTaskInfo->eepromAddress + SEABIRD_GPCTD_PACKET_CYCLE_OFFSET), temp);
		}
		pTaskInfo->pBuf->offTime = temp;

		
		pTaskInfo->pBuf->initState = 0xFF;
		EepromReadByte((void*)(pTaskInfo->eepromAddress + SEABIRD_GPCTD_AUTORUN_OFFSET), (void*)&pTaskInfo->pBuf->initState);
		if((pTaskInfo->pBuf->initState != AUTORUN_ON) && (pTaskInfo->pBuf->initState != AUTORUN_OFF))
		{
			pTaskInfo->pBuf->initState = AUTORUN_OFF;	//Default to Auto-Run Off
			EepromWriteByteUnSigned((void*)(pTaskInfo->eepromAddress + SEABIRD_GPCTD_AUTORUN_OFFSET), pTaskInfo->pBuf->initState);
		}


		temp = 0xFFFF;
		EepromReadWord((void*)(pTaskInfo->eepromAddress + SEABIRD_GPCTD_PUMP_FLUSH_OFFSET), (void*)&temp);
		if(temp > MAX_FLUSH_TIME)		//12 hours = 43200 seconds
		{
			temp = 0;	//Default to 0 seconds of pre-pump time to flush plumbing
			EepromWriteWordUnSigned((void*)(pTaskInfo->eepromAddress + SEABIRD_GPCTD_PUMP_FLUSH_OFFSET), temp);
		}
		pTaskInfo->pBuf->flushTime = temp;

		if(pTaskInfo->pBuf->initState == AUTORUN_ON)
		{
			char tempBuf[2] = " ";
			SBGPCTD_ParseCommand(pTaskInfo, 'r', tempBuf);
		}


	}

	return SUCCESS;
}

void SbrdGPCTD(void* pParam)
{
	SEABIRD_GPCTD_TASK taskInfo;
	PSEABIRD_GPCTD_TASK pTaskInit = (PSEABIRD_GPCTD_TASK)pParam;
	uint8_t count = 0;
	uint32_t currentSecond = 0;

	memset((char*)&taskInfo, 0, sizeof(SEABIRD_GPCTD_TASK));

	taskInfo.taskID = pTaskInit->taskID;
	taskInfo.portNum = pTaskInit->portNum;
	taskInfo.pBuf = pTaskInit->pBuf;

	count = Seabird_GPCTD_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("GPCTD 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);

				SerialPortPassThroughGPCTD(taskInfo.portNum);
			}

			
			currentSecond = getsecondtick();

			//Check to see if we need to turn the pump on
			if((taskInfo.pBuf->offTime > 0) && (taskInfo.pBuf->flushTime > 0) && (taskInfo.pBuf->pumpRun == FALSE))
			{
				if((taskInfo.pBuf->sleeping == TRUE) && (taskInfo.pBuf->turnBackOnTime - currentSecond <= taskInfo.pBuf->flushTime))
				{
					SBGPCTD_PumpFast(&taskInfo);
				}
			}



			// Check to see if we should come out of the sleep state
			if((taskInfo.pBuf->sleeping == TRUE) && (taskInfo.pBuf->turnBackOnTime <= currentSecond) && (taskInfo.pBuf->turnBackOnTime != 0))
			{
				//SBGPCTD_TurnOn(&taskInfo);
				SBGPCTD_StartSample(&taskInfo);
				//taskInfo.pBuf->turnBackOnTime = 0;
				//if(taskInfo.pBuf->turnBackOnTime == 0)
				//taskInfo.pBuf->turnBackOnTime = (taskInfo.pBuf->samplePacketSize * taskInfo.pBuf->sampleRate) + taskInfo.pBuf->offTime + currentSecond;
				//else
				taskInfo.pBuf->turnBackOnTime += (taskInfo.pBuf->samplePacketSize * taskInfo.pBuf->sampleRate) + taskInfo.pBuf->offTime;
				taskInfo.pBuf->sleeping = FALSE;
			}

			if(taskInfo.pBuf->sampleCTD == TRUE)
			{
				OSuartGetRxFifoCount(taskInfo.portNum, &count);
				

				if((taskInfo.pBuf->useO2 != USE_O2) && (count >= GPCTD_SAMPLE_NO_O2_LEN))
				{
					SBGPCTD_GetCTDSampleNoO2(&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 = 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;

						SBGPCTD_CTDReportXmitNoO2(&taskInfo);

						memset(&taskInfo.pBuf->reportData, 0, sizeof(GPCTD_DATA_REPORT));

						if(taskInfo.pBuf->offTime != 0)
						{
							SBGPCTD_StopSample(&taskInfo);
							//SBGPCTD_TurnOff(&taskInfo);
							//taskInfo.pBuf->turnBackOnTime = getsecondtick() + taskInfo.pBuf->offTime;
							taskInfo.pBuf->sleeping = TRUE;
						}
					}

					count = 0;
				}
				else if((taskInfo.pBuf->useO2 == USE_O2) && (count >= GPCTD_SAMPLE_NO_O2_LEN))
//				else if((taskInfo.pBuf->useO2 == USE_O2) && (count >= GPCTD_SAMPLE_WITH_O2_LEN))
				{
					SBGPCTD_GetCTDSampleWithO2(&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, O=%05lX\r\n\r\n"),
							 mainBoardID, taskInfo.taskID,
							 taskInfo.pBuf->reportData2.dataBlock[taskInfo.pBuf->reportData.headerReport.repeatCount - 1].pressure,
							 taskInfo.pBuf->reportData2.dataBlock[taskInfo.pBuf->reportData.headerReport.repeatCount - 1].temperature,
							 taskInfo.pBuf->reportData2.dataBlock[taskInfo.pBuf->reportData.headerReport.repeatCount - 1].conductivity);
							 taskInfo.pBuf->reportData2.dataBlock[taskInfo.pBuf->reportData.headerReport.repeatCount - 1].oxygen);

					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->reportData2.headerReport.repeatCount >= taskInfo.pBuf->samplePacketSize)
					{
						taskInfo.pBuf->reportData2.headerReport.payloadType = 0x00000070;
						taskInfo.pBuf->reportData2.headerReport.boardID = mainBoardID;
						taskInfo.pBuf->reportData2.headerReport.taskID = taskInfo.taskID;
						taskInfo.pBuf->reportData2.headerReport.dataFormat = 9;
						taskInfo.pBuf->reportData2.headerReport.parser = 0;
						taskInfo.pBuf->reportData2.headerReport.priority = 2;

						SBGPCTD_CTDReportXmitWithO2(&taskInfo);

						memset(&taskInfo.pBuf->reportData2, 0, sizeof(GPCTD_DATA_REPORT_2));

						if(taskInfo.pBuf->offTime != 0)
						{
							SBGPCTD_StopSample(&taskInfo);
							//SBGPCTD_TurnOff(&taskInfo);
							//taskInfo.pBuf->turnBackOnTime = currentSecond + taskInfo.pBuf->offTime;
							taskInfo.pBuf->sleeping = TRUE;
						}
					}

					count = 0;
				}

				if((taskInfo.pBuf->findDataFrame == TRUE) && (count != 0))
				{
					SBGPCTD_GetCTDSampleFrame(&taskInfo);
				}
			}


			if(fileAvailable[pTaskInit->portNum] == TRUE)
			{
				//SBGPCTD_ParseFile(&taskInfo, fileAvailableID[pTaskInit->portNum]);
				taskInfo.pBuf->fileID = fileAvailableID[pTaskInit->portNum];
				SBGPCTD_ParseInput(&taskInfo, FILE_INPUT);
				fileAvailableID[pTaskInit->portNum] = 0;
				fileAvailable[pTaskInit->portNum] = FALSE;
			}

			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;

//				SBGPCTD_ParseConsole(&taskInfo);
				SBGPCTD_ParseInput(&taskInfo, CONSOLE_INPUT);
				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 SBGPCTD_CTD_Tx(PSEABIRD_GPCTD_TASK pTaskInfo)
{
	uint8_t retval = FAIL;
	uint8_t firstCharTries = 5;
	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 SBGPCTD_CTD_Rx(PSEABIRD_GPCTD_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 SBGPCTD_GetCTDSampleFrame(PSEABIRD_GPCTD_TASK pTaskInfo)
{
	uint8_t err = OS_ERR_NONE;
	char c = 0;

	while((c != 0x0A) && (err == OS_ERR_NONE))
		c = OSuartGetCharWait(pTaskInfo->portNum, 12, &err);

	return;
}

void SBGPCTD_GetCTDSampleNoO2(PSEABIRD_GPCTD_TASK pTaskInfo)
{
#define X_GPCTD1	pTaskInfo->pBuf->reportData.dataBlock
#define X_GPCTD2	pTaskInfo->pBuf->reportData.headerReport.repeatCount

	uint8_t count = 0;
	uint8_t err = OS_ERR_NONE;
	char tempString[6] = {0};
	
	memset(pTaskInfo->pBuf->bufferRx, 0, 256);

	while((count < GPCTD_SAMPLE_NO_O2_LEN) && (err == OS_ERR_NONE))
	{
		pTaskInfo->pBuf->bufferRx[count] = OSuartGetCharWait(pTaskInfo->portNum, 12, &err);
		count++;
	}

	if((count == GPCTD_SAMPLE_NO_O2_LEN) && (pTaskInfo->pBuf->bufferRx[count - 1] == 0x0A))
	{

		X_GPCTD1[X_GPCTD2].headerData.latitude = latitude;
		X_GPCTD1[X_GPCTD2].headerData.longitude = longitude;
		X_GPCTD1[X_GPCTD2].headerData.timestamp = gettime();

		
		memset(tempString, 0, 6);
		memcpy(tempString, &(pTaskInfo->pBuf->bufferRx[0]), 5);
		X_GPCTD1[X_GPCTD2].pressure = strtol(tempString, NULL, 16);

		memset(tempString, 0, 6);
		memcpy(tempString, &(pTaskInfo->pBuf->bufferRx[5]), 5);
		X_GPCTD1[X_GPCTD2].temperature = strtol(tempString, NULL, 16);

		memset(tempString, 0, 6);
		memcpy(tempString, &(pTaskInfo->pBuf->bufferRx[10]), 5);
		X_GPCTD1[X_GPCTD2].conductivity = strtol(tempString, NULL, 16);

		pTaskInfo->pBuf->reportData.headerReport.repeatCount++;
	}
	else
	{
		pTaskInfo->pBuf->findDataFrame = TRUE;
	}

#undef X_GPCTD1
#undef X_GPCTD2

	return;
}

void SBGPCTD_GetCTDSampleWithO2(PSEABIRD_GPCTD_TASK pTaskInfo)
{
#define X_GPCTD3	pTaskInfo->pBuf->reportData2.dataBlock2
#define X_GPCTD4	pTaskInfo->pBuf->reportData2.headerReport.repeatCount

	uint8_t count = 0;
	uint8_t err = OS_ERR_NONE;
	char tempString[6] = {0};
	
	memset(pTaskInfo->pBuf->bufferRx, 0, GPCTD_SAMPLE_WITH_O2_LEN);

	pTaskInfo->pBuf->bufferRx[0] = 0;

	while((count < GPCTD_SAMPLE_WITH_O2_LEN) && (err == OS_ERR_NONE))
	{
		pTaskInfo->pBuf->bufferRx[count] = OSuartGetCharWait(pTaskInfo->portNum, 12, &err);
		count++;
		if(pTaskInfo->pBuf->bufferRx[count-1] == 0x0A)
			break;
	}

	if(((count == GPCTD_SAMPLE_WITH_O2_LEN) || (count == GPCTD_SAMPLE_NO_O2_LEN)) && (pTaskInfo->pBuf->bufferRx[count - 1] == 0x0A))
	{

		X_GPCTD3[X_GPCTD4].headerData.latitude = latitude;
		X_GPCTD3[X_GPCTD4].headerData.longitude = longitude;
		X_GPCTD3[X_GPCTD4].headerData.timestamp = gettime();

		
		memset(tempString, 0, 6);
		memcpy(tempString, &(pTaskInfo->pBuf->bufferRx[0]), 5);
		X_GPCTD3[X_GPCTD4].pressure = strtol(tempString, NULL, 16);

		memset(tempString, 0, 6);
		memcpy(tempString, &(pTaskInfo->pBuf->bufferRx[5]), 5);
		X_GPCTD3[X_GPCTD4].temperature = strtol(tempString, NULL, 16);

		memset(tempString, 0, 6);
		memcpy(tempString, &(pTaskInfo->pBuf->bufferRx[10]), 5);
		X_GPCTD3[X_GPCTD4].conductivity = strtol(tempString, NULL, 16);

		if(count == GPCTD_SAMPLE_WITH_O2_LEN)
		{
			memset(tempString, 0, 6);
			memcpy(tempString, &(pTaskInfo->pBuf->bufferRx[15]), 5);
			X_GPCTD3[X_GPCTD4].oxygen = strtol(tempString, NULL, 16);
		}
		else
		{
			X_GPCTD3[X_GPCTD4].oxygen = 0xFFFFFFFF;
		}
		pTaskInfo->pBuf->reportData2.headerReport.repeatCount++;
	}
	else
	{
		pTaskInfo->pBuf->findDataFrame = TRUE;
	}

#undef X_GPCTD3
#undef X_GPCTD4

	return;
}

uint8_t SBGPCTD_GetSerNum(PSEABIRD_GPCTD_TASK pTaskInfo)
{
	uint8_t retval = FAIL;
	uint16_t lenData;
	char* pO2 = NULL;

	memset(pTaskInfo->pBuf->tokenSeparatorList, 0, MAX_TOKEN_SEPARATORS);
	strcat_P(pTaskInfo->pBuf->tokenSeparatorList, tokensGPCTD1);

	memset(pTaskInfo->pBuf->bufferTx, 0, 256);
	memset(pTaskInfo->pBuf->bufferRx, 0, 1024);
	strcat_P(pTaskInfo->pBuf->bufferTx, cmdGPCTD_DS);

	retval = SBGPCTD_CTD_Tx(pTaskInfo);

	if(retval == SUCCESS)
	{
		retval = SBGPCTD_CTD_Rx(pTaskInfo, cmdGPCTD_EOL, &lenData);

		if((retval == SUCCESS) && (lenData != 0))
		{
			char* pChar = NULL;

			pO2 = strstr_P(pTaskInfo->pBuf->bufferRx, check2forO2);
			if((pO2 != NULL) && (pO2 != pTaskInfo->pBuf->bufferRx))
				pTaskInfo->pBuf->useO2 = USE_O2;

			pChar = strstr_P(pTaskInfo->pBuf->bufferRx, parseGPCTD_SerNum);
			if(pChar != NULL)
			{
				pChar++;
				pChar = strstr_P(pChar, parseGPCTD_SerNum);
			}


			if((pChar != NULL) && ((uint16_t)(pChar - pTaskInfo->pBuf->bufferRx) < 64))
			{
				memcpy(pTaskInfo->pBuf->ctdInfo, pTaskInfo->pBuf->bufferRx, (uint16_t)(pChar - pTaskInfo->pBuf->bufferRx));
				strrev(pTaskInfo->pBuf->ctdInfo);
				pChar = NULL;
				pChar = strstr_P(pTaskInfo->pBuf->ctdInfo, PSTR(" "));
				if((pChar != NULL) && ((uint16_t)(pChar - pTaskInfo->pBuf->ctdInfo) < 16))
				{
					memcpy(pTaskInfo->pBuf->serialNumber, pTaskInfo->pBuf->ctdInfo, (uint16_t)(pChar - pTaskInfo->pBuf->ctdInfo));
					strrev(pTaskInfo->pBuf->serialNumber);
					retval = SUCCESS;
				}
				strrev(pTaskInfo->pBuf->ctdInfo);
			}
		}
	}

	return retval;
}

void SBGPCTD_CheckO2Sensor(PSEABIRD_GPCTD_TASK pTaskInfo)
{
	uint16_t lenData;
	char* pOut;
	uint8_t retval = FAIL;

	memset(pTaskInfo->pBuf->bufferTx, 0, 256);
	memset(pTaskInfo->pBuf->bufferRx, 0, 1024);
	strcat_P(pTaskInfo->pBuf->bufferTx, cmdGPCTD_GetCD);

	retval = SBGPCTD_CTD_Tx(pTaskInfo);

	if(retval == SUCCESS)
	{
		retval = SBGPCTD_CTD_Rx(pTaskInfo, cmdGPCTD_EOL, &lenData);

		if((retval == SUCCESS) && (lenData != 0))
		{
			pOut = strstr_P(pTaskInfo->pBuf->bufferRx, checkO2);

			if((pOut != NULL) && (pOut != pTaskInfo->pBuf->bufferRx))
				pTaskInfo->pBuf->useO2 = USE_O2;
		}
	}
}

uint8_t SBGPCTD_CTDReportXmitNoO2(PSEABIRD_GPCTD_TASK pTaskInfo)
{
	uint8_t retval = 0;
	uint8_t err = 0;
//	PPIB_DATA_FORWARD_MESSAGE pReport = NULL;
	PSEABIRD_GPCTD_DATA_REPORT_XMIT pReport = NULL;


	OSMutexPend(pMutexFloatQueue, INFINITE, &err);


	pReport = (PSEABIRD_GPCTD_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(GPCTD_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(GPCTD_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;
//
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
}




uint8_t SBGPCTD_CTDReportXmitWithO2(PSEABIRD_GPCTD_TASK pTaskInfo)
{
	uint8_t retval = 0;
	uint8_t err = 0;
//	PPIB_DATA_FORWARD_MESSAGE pReport = NULL;
	PSEABIRD_GPCTD_DATA_REPORT_XMIT_2 pReport= NULL;

	OSMutexPend(pMutexFloatQueue, INFINITE, &err);


	pReport = (PSEABIRD_GPCTD_DATA_REPORT_XMIT_2)&(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->reportData2.headerReport.repeatCount * sizeof(GPCTD_DATA_REPORT_BLOCK_2);	
	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->reportData2, 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 = 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->reportData2.headerReport.repeatCount * sizeof(GPCTD_DATA_REPORT_BLOCK_2);
//	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->reportData2, 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 SBGPCTD_ParseConsole(PSEABIRD_GPCTD_TASK pTaskInfo)
void SBGPCTD_ParseInput(PSEABIRD_GPCTD_TASK pTaskInfo, uint8_t source)
{

	char* myCommand = NULL;			//consoleIn[pTaskInfo->taskID].cmd; 
	char* result = NULL;
	char command = 0;
	BOOL goodCommand = FALSE;
	uint8_t resultCode = 0;

	switch(source)
	{
		case CONSOLE_INPUT:
			myCommand = consoleIn[pTaskInfo->taskID].cmd;
			break;
		case FILE_INPUT:
			myCommand = fileIn[pTaskInfo->taskID];
			break;
		default:
			return;
	}

	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, gpctdParserID, strlen_P(gpctdParserID)) == 0)
		{
			resultCode = 3;		//Unknown command
			command = getCommand(&myCommand, gpctdCommands[0], 8, NUM_COMMANDS, ctdCmdList, pTaskInfo->pBuf->tokenSeparatorList);

			if(command != 0)
				goodCommand = TRUE;
		}
	}

	if(goodCommand == TRUE)
		resultCode = SBGPCTD_ParseCommand(pTaskInfo, command, myCommand);

	if(resultCode != SUCCESS)
	{
		switch(resultCode)
		{
			case 1:
			{
				if(source == CONSOLE_INPUT)
					pTaskInfo->pBuf->responseInfo.status = CONSOLE_RESPONSE_EMPTY_CMD;
				else
				{
					memset(&fileOut[pTaskInfo->portNum][0], 0, 256);
					sprintf_P(&fileOut[pTaskInfo->portNum][0], PSTR("Received an Empty Command"));
					fileOutSize[pTaskInfo->portNum] = strlen(&fileOut[pTaskInfo->portNum][0]);
				}
				break;
			}
			case 2:
			{
				if(source == CONSOLE_INPUT)
					pTaskInfo->pBuf->responseInfo.status = CONSOLE_RESPONSE_WRONG_DEVICE;
				else
				{
					memset(&fileOut[pTaskInfo->portNum][0], 0, 256);
					sprintf_P(&fileOut[pTaskInfo->portNum][0], PSTR("Command received was not for the GPCTD"));
					fileOutSize[pTaskInfo->portNum] = strlen(&fileOut[pTaskInfo->portNum][0]);
				}
				break;
			}
			case 3:
			{
				if(source == CONSOLE_INPUT)
					pTaskInfo->pBuf->responseInfo.status = CONSOLE_RESPONSE_UNKNOWN_CMD;
				else
				{
					memset(&fileOut[pTaskInfo->portNum][0], 0, 256);
					sprintf_P(&fileOut[pTaskInfo->portNum][0], PSTR("Unrecognized Command"));
					fileOutSize[pTaskInfo->portNum] = strlen(&fileOut[pTaskInfo->portNum][0]);
				}
				break;
			}
			default:
			{
				if(source == CONSOLE_INPUT)
					pTaskInfo->pBuf->responseInfo.status = CONSOLE_RESPONSE_CMD_FAILED;
				else
				{
					memset(&fileOut[pTaskInfo->portNum][0], 0, 256);
					sprintf_P(&fileOut[pTaskInfo->portNum][0], PSTR("Command Failed"));
					fileOutSize[pTaskInfo->portNum] = strlen(&fileOut[pTaskInfo->portNum][0]);
				}
				break;
			}
		}
	}

	switch(source)
	{
		case CONSOLE_INPUT:
			SBGPCTD_QueueConsoleResponse(pTaskInfo);
			break;
		case FILE_INPUT:
			memcpy(&fileOut[pTaskInfo->portNum][0], pTaskInfo->pBuf->consoleResponse, pTaskInfo->pBuf->responseInfo.length);
			fileOutSize[pTaskInfo->portNum] = pTaskInfo->pBuf->responseInfo.length;
			SBGPCTD_QueueFile(pTaskInfo);
			break;
		default:
			return;
	}

//	SBGPCTD_QueueConsoleResponse(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 SBGPCTD_QueueConsoleResponse(PSEABIRD_GPCTD_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 SBGPCTD_TurnOn(PSEABIRD_GPCTD_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 = SBGPCTD_CTD_Rx(pTaskInfo, cmdGPCTD_EOL, &len);
		if(retval == SUCCESS)
			retries = 0;
	}

//	if(retval == SUCCESS)
//		SBGPCTD_StopSample(pTaskInfo);

	if(retval == SUCCESS)
	{
		SBGPCTD_GetSerNum(pTaskInfo);
		OSTimeDlyHMSM(0,0,0,100);
		pTaskInfo->pBuf->powerCTD = TRUE;
	}

	return retval;
}

uint8_t SBGPCTD_TurnOff(PSEABIRD_GPCTD_TASK pTaskInfo)
{
	uint8_t retval = FAIL;

	pTaskInfo->pBuf->sampleCTD = FALSE;
	pTaskInfo->pBuf->powerCTD = FALSE;

	EnablePIBModule(pTaskInfo->portNum, FALSE, FALSE);



	if(pTaskInfo->pBuf->reportData.headerReport.repeatCount != 0)
	{
		pTaskInfo->pBuf->reportData.headerReport.payloadType = 0x00000070;
		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;
		SBGPCTD_CTDReportXmitNoO2(pTaskInfo);
	}

	if(pTaskInfo->pBuf->reportData2.headerReport.repeatCount != 0)
	{
		pTaskInfo->pBuf->reportData2.headerReport.payloadType = 0x00000070;
		pTaskInfo->pBuf->reportData2.headerReport.boardID = mainBoardID;
		pTaskInfo->pBuf->reportData2.headerReport.taskID = pTaskInfo->taskID;
		pTaskInfo->pBuf->reportData2.headerReport.dataFormat = 9;
		pTaskInfo->pBuf->reportData2.headerReport.parser = 0;
		pTaskInfo->pBuf->reportData2.headerReport.priority = 2;
		SBGPCTD_CTDReportXmitWithO2(pTaskInfo);
	}

	pTaskInfo->pBuf->reportData.headerReport.repeatCount = 0;

	return retval;
}

uint8_t SBGPCTD_StartSample(PSEABIRD_GPCTD_TASK pTaskInfo)
{
	uint8_t retval = FAIL;
	uint16_t lenData = 0;

	SBGPCTD_SimpleStop(pTaskInfo);
	SBGPCTD_CheckO2Sensor(pTaskInfo);

	retval = SBGPCTD_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, cmdGPCTD_Start);

	retval = SBGPCTD_CTD_Tx(pTaskInfo);

	if(retval == SUCCESS)
		retval = SBGPCTD_CTD_Rx(pTaskInfo, cmdGPCTD_EOL, &lenData);

	pTaskInfo->pBuf->pumpRun = FALSE;

	return retval;
}

uint8_t SBGPCTD_StopSample(PSEABIRD_GPCTD_TASK pTaskInfo)
{
	uint8_t retval = FAIL;
	uint16_t lenData = 0;
	char* pBuffer = pTaskInfo->pBuf->bufferTx;
	uint8_t err = OS_ERR_NONE;


	if(pTaskInfo->pBuf->reportData.headerReport.repeatCount != 0)
	{
		pTaskInfo->pBuf->reportData.headerReport.payloadType = 0x00000070;
		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;
		SBGPCTD_CTDReportXmitNoO2(pTaskInfo);
	}

	if(pTaskInfo->pBuf->reportData2.headerReport.repeatCount != 0)
	{
		pTaskInfo->pBuf->reportData2.headerReport.payloadType = 0x00000070;
		pTaskInfo->pBuf->reportData2.headerReport.boardID = mainBoardID;
		pTaskInfo->pBuf->reportData2.headerReport.taskID = pTaskInfo->taskID;
		pTaskInfo->pBuf->reportData2.headerReport.dataFormat = 9;
		pTaskInfo->pBuf->reportData2.headerReport.parser = 0;
		pTaskInfo->pBuf->reportData2.headerReport.priority = 2;
		SBGPCTD_CTDReportXmitWithO2(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, cmdGPCTD_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 = SBGPCTD_CTD_Rx(pTaskInfo, cmdGPCTD_EOL, &lenData);

	pTaskInfo->pBuf->pumpRun = FALSE;
	
	return retval;
}

uint8_t SBGPCTD_PumpFast(PSEABIRD_GPCTD_TASK pTaskInfo)
{
	uint8_t retval = FAIL;
	uint16_t lenData = 0;

	memset(pTaskInfo->pBuf->bufferTx, 0, 256);
	memset(pTaskInfo->pBuf->bufferRx, 0, 1024);

	strcat_P(pTaskInfo->pBuf->bufferTx, cmdGPCTD_PumpFast);

	retval = SBGPCTD_CTD_Tx(pTaskInfo);

	if(retval == SUCCESS)
		retval = SBGPCTD_CTD_Rx(pTaskInfo, cmdGPCTD_EOL, &lenData);

	pTaskInfo->pBuf->pumpRun = TRUE;

	return retval;
}



void SBGPCTD_SimpleStop(PSEABIRD_GPCTD_TASK pTaskInfo)
{
	uint16_t lenData = 0;
	char* pBuffer = pTaskInfo->pBuf->bufferTx;
	uint8_t err = OS_ERR_NONE;

	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, cmdGPCTD_Stop);

	lenData = strlen(pBuffer);

	while(lenData > 0)
	{
		err = OSuartPutCharWait(pTaskInfo->portNum, *pBuffer, 10);
		if(err == OS_ERR_NONE)
		{
			lenData--;
			pBuffer++;
		}
		else
		{	
			break;
		}
	}

	err = OSuartPutCharWait(pTaskInfo->portNum, 0x0D, 10);
	SBGPCTD_CTD_Rx(pTaskInfo, cmdGPCTD_EOL, &lenData);

	pTaskInfo->pBuf->pumpRun = TRUE;

	return;
}


uint8_t SBGPCTD_SetPeriod(PSEABIRD_GPCTD_TASK pTaskInfo, uint16_t newInterval)
{
	uint8_t retval = FAIL;
	uint16_t lenData = 0;

	if((newInterval > 0) && (newInterval <= MAX_GPCTD_SAMPLE_INTERVAL))
	{
		memset(pTaskInfo->pBuf->bufferTx, 0, 256);
		memset(pTaskInfo->pBuf->bufferRx, 0, 1024);
		sprintf_P(pTaskInfo->pBuf->bufferTx, cmdGPCTD_Interval, newInterval);

		retval = SBGPCTD_CTD_Tx(pTaskInfo);

		if(retval == SUCCESS)
			retval = SBGPCTD_CTD_Rx(pTaskInfo, cmdGPCTD_EOL, &lenData);

		if(retval == SUCCESS)
		{
			EepromWriteWordUnSigned((void*)(pTaskInfo->eepromAddress + SEABIRD_GPCTD_SAMPLE_INTERVAL_OFFSET), newInterval);
			pTaskInfo->pBuf->sampleRate = newInterval;
		}
	}
	return retval;
}

uint8_t SBGPCTD_SetPacketSize(PSEABIRD_GPCTD_TASK pTaskInfo, uint8_t newPacketSize)
{
	uint8_t retval = FAIL;

	if((newPacketSize > 0) && (newPacketSize <= MAX_GPCTD_SAMPLES))
	{
		retval = SUCCESS;

		EepromWriteWordUnSigned((void*)(pTaskInfo->eepromAddress + SEABIRD_GPCTD_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 SBGPCTD_SetPacketDest(PSEABIRD_GPCTD_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_GPCTD_PACKET_DESTINATION_OFFSET), newDest);
		pTaskInfo->pBuf->samplePacketSize = newDest;
	}

	return retval;
}


uint8_t SBGPCTD_SetDutyCycleOffTime(PSEABIRD_GPCTD_TASK pTaskInfo, uint16_t newOffTime)
{
	uint8_t retval = FAIL;

	if((newOffTime >= 0) && (newOffTime <= MAX_OFF_TIME))
	{
		retval = SUCCESS;

		EepromWriteWordUnSigned((void*)(pTaskInfo->eepromAddress + SEABIRD_GPCTD_PACKET_CYCLE_OFFSET), newOffTime);
		pTaskInfo->pBuf->offTime = newOffTime;
	}

	return retval;
}

uint8_t SBGPCTD_SetPumpFlushTime(PSEABIRD_GPCTD_TASK pTaskInfo, uint16_t newFlushTime)
{
	uint8_t retval = FAIL;

	if((newFlushTime >= 0) && (newFlushTime <= MAX_FLUSH_TIME))
	{
		retval = SUCCESS;

		EepromWriteWordUnSigned((void*)(pTaskInfo->eepromAddress + SEABIRD_GPCTD_PUMP_FLUSH_OFFSET), newFlushTime);
		pTaskInfo->pBuf->flushTime = newFlushTime;
	}

	return retval;
}

uint8_t SBGPCTD_Id(PSEABIRD_GPCTD_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 SBGPCTD_Cmd(PSEABIRD_GPCTD_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 = SBGPCTD_CTD_Tx(pTaskInfo);

			if(retval == SUCCESS)
			{
				retval = SBGPCTD_CTD_Rx(pTaskInfo, cmdGPCTD_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 SBGPCTD_SetTime(PSEABIRD_GPCTD_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, cmdGPCTD_DateTime, dt->tm_mon+1, dt->tm_mday, dt->tm_year+1900,
	                                                        dt->tm_hour, dt->tm_min, dt->tm_sec); 

	retval = SBGPCTD_CTD_Tx(pTaskInfo);

	if(retval == SUCCESS)
		retval = SBGPCTD_CTD_Rx(pTaskInfo, cmdGPCTD_EOL, &lenData);

	return retval;
}


uint8_t SBGPCTD_ParseCommand(PSEABIRD_GPCTD_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 = SBGPCTD_TurnOn(pTaskInfo);
		break;
	case 'f':
	case 'F':
		//Power Off
		retval = SBGPCTD_TurnOff(pTaskInfo);
		pTaskInfo->pBuf->sleeping = FALSE;
		break;
	case 'r':
	case 'R':
		//Start Sampling
		if(pTaskInfo->pBuf->powerCTD == FALSE)
			retval = SBGPCTD_TurnOn(pTaskInfo);

		if(pTaskInfo->pBuf->sampleCTD == TRUE)
		{
			retval = SBGPCTD_StopSample(pTaskInfo);
			OSTimeDlyHMSM(0,0,1,0);
		}

		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:
				SBGPCTD_SetPeriod(pTaskInfo, newVal);
				break;
			case PARAM_SIZE:
				SBGPCTD_SetPacketSize(pTaskInfo, newVal);
				break;
			case PARAM_DEST:
				SBGPCTD_SetPacketDest(pTaskInfo, newVal);
				break;
			}
			paramCount++;
			result = strtok_r(NULL, pTaskInfo->pBuf->tokenSeparatorList, &cmdParams);
		}
		retval = SBGPCTD_SetTime(pTaskInfo);

		if(pTaskInfo->pBuf->offTime != 0)
			pTaskInfo->pBuf->turnBackOnTime = (pTaskInfo->pBuf->samplePacketSize * pTaskInfo->pBuf->sampleRate) + pTaskInfo->pBuf->offTime + getsecondtick();

		retval = SBGPCTD_StartSample(pTaskInfo);

		break;
	case 'x':
	case 'X':
		//Stop Sampling
		retval = SBGPCTD_StopSample(pTaskInfo);
		pTaskInfo->pBuf->sleeping = FALSE;
		break;
	case 'p':
	case 'P':
		//Set default sample interval
		if(pTaskInfo->pBuf->powerCTD == FALSE)
			retval = SBGPCTD_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 = SBGPCTD_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 = SBGPCTD_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 = SBGPCTD_SetPacketDest(pTaskInfo, newVal);
		}
		break;
	case 'i':
	case 'I':
		if(pTaskInfo->pBuf->powerCTD == FALSE)
			retval = SBGPCTD_TurnOn(pTaskInfo);

		//Return Serial Number and Version information
		retval = SBGPCTD_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':
		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, NULL, 0));
			//pTaskInfo->pBuf->offTime = (uint16_t)(strtol(result, &result, 0));
			SBGPCTD_SetDutyCycleOffTime(pTaskInfo, newVal);
		}
		//pTaskInfo->pBuf->turnBackOnTime = 0;
		break; 
	case 'l':
	case 'L':
		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, NULL, 0));
			//pTaskInfo->pBuf->offTime = (uint16_t)(strtol(result, &result, 0));
			SBGPCTD_SetPumpFlushTime(pTaskInfo, newVal);
		}
		//pTaskInfo->pBuf->turnBackOnTime = 0;
		break; 
	case 'c':
	case 'C':
		//CTD Pass Thru Command
		if(pTaskInfo->pBuf->powerCTD == FALSE)
		{
			retval = SBGPCTD_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 = SBGPCTD_Cmd(pTaskInfo, result);
			else
				pTaskInfo->pBuf->responseInfo.status = CONSOLE_RESPONSE_EMPTY_CMD;
		}
		else
		{
			pTaskInfo->pBuf->responseInfo.status = CONSOLE_RESPONSE_DEVICE_BUSY;
		}

		statusResponse = FALSE;
		break;
	case 'a':
	case 'A':
		{
			char* result = NULL;

			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)
			{
				char* pTest = result;
				if((*pTest == 'o') || (*pTest == 'O'))
				{
					pTest++;
				
					if((*pTest == 'f') || (*pTest == 'F'))
						*result = *pTest;
				}

				switch(*result)
				{
					case 'y':
					case 'Y':
					case 'o':
					case 'O':
					case '1':
						pTaskInfo->pBuf->initState = AUTORUN_ON;
						retval = SUCCESS;
						break;
					case 'n':
					case 'N':
					case 'f':
					case 'F':
					case '0':
						pTaskInfo->pBuf->initState = AUTORUN_OFF;
						retval = SUCCESS;
						break;
					default:
						retval = FAIL;
				}

				if(retval == SUCCESS)
					EepromWriteByteUnSigned((void*)(pTaskInfo->eepromAddress + SEABIRD_GPCTD_AUTORUN_OFFSET), pTaskInfo->pBuf->initState);
			}
			else
			{
				retval = FAIL;
			}
			break;
		}
	default:
		retval = FAIL;
	}

	if(statusResponse == TRUE)
	{
		retval = SUCCESS;
		SBGPCTD_CreateStatusResponse(pTaskInfo, retval);
	}

	return retval;
}


uint8_t SBGPCTD_CreateStatusResponse(PSEABIRD_GPCTD_TASK pTaskInfo, uint8_t status)
{
	memset(pTaskInfo->pBuf->statusConstructor, 0, 192);
	memset(pTaskInfo->pBuf->consoleResponse, 0, 256);

	if(status == SUCCESS)
		strcat_P(pTaskInfo->pBuf->statusConstructor, statusGPCTD_OK);
	else
		strcat_P(pTaskInfo->pBuf->statusConstructor, statusGPCTD_Fail);

	strcat_P(pTaskInfo->pBuf->statusConstructor, statusGPCTD_Msg2);
	if(pTaskInfo->pBuf->powerCTD == TRUE)
		strcat_P(pTaskInfo->pBuf->statusConstructor, statusGPCTD_On);
	else
		strcat_P(pTaskInfo->pBuf->statusConstructor, statusGPCTD_Off);

	strcat_P(pTaskInfo->pBuf->statusConstructor, statusGPCTD_Msg3);
	if(pTaskInfo->pBuf->sampleCTD == TRUE)
		strcat_P(pTaskInfo->pBuf->statusConstructor, statusGPCTD_On);
	else
		strcat_P(pTaskInfo->pBuf->statusConstructor, statusGPCTD_Off);



	if(pTaskInfo->pBuf->destination >= 0x100)
		strcat_P(pTaskInfo->pBuf->statusConstructor, statusGPCTD_Msg4);
	else
		strcat_P(pTaskInfo->pBuf->statusConstructor, statusGPCTD_Msg5);

	strcat_P(pTaskInfo->pBuf->statusConstructor, statusGPCTD_Msg6);
	if(pTaskInfo->pBuf->useO2 != USE_O2)
		strcat_P(pTaskInfo->pBuf->statusConstructor, statusGPCTD_No);
	else
		strcat_P(pTaskInfo->pBuf->statusConstructor, statusGPCTD_Yes);

	strcat_P(pTaskInfo->pBuf->statusConstructor, statusGPCTD_Msg7);
	if(pTaskInfo->pBuf->initState == AUTORUN_ON)
		strcat_P(pTaskInfo->pBuf->statusConstructor, statusGPCTD_On);
	else
		strcat_P(pTaskInfo->pBuf->statusConstructor, statusGPCTD_Off);




	sprintf((char*)pTaskInfo->pBuf->consoleResponse, pTaskInfo->pBuf->statusConstructor, 
			pTaskInfo->pBuf->sampleRate, pTaskInfo->pBuf->samplePacketSize, 
			pTaskInfo->pBuf->offTime, pTaskInfo->pBuf->flushTime, 
			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;
}


uint8_t SBGPCTD_QueueFile(PSEABIRD_GPCTD_TASK pTaskInfo)
{
	uint8_t retval = FAIL;
	PFS_REPORT pReport;
	uint8_t err = 0;
	tm* dateTime;
	time_t time;

	OSMutexPend(pMutexFloatQueue, INFINITE, &err);

	pReport = (PFS_REPORT)&(txFloatData[headFloatTx]);

	memset(pReport, 0, sizeof(FS_REPORT));

	pReport->headers.length  = sizeof(FS_REPORT) + CRC16_SIZE;
	pReport->headers.destination = FLOAT_FS_INTERFACE;
	pReport->type = NEW_FILE_AVAILABLE;

	time=gettime();

	//Need to fill in these values appropriately
	pReport->newFile.fileSize = fileOutSize[pTaskInfo->portNum];
	dateTime = gmtime(&time);
	pReport->newFile.creationDate.day = dateTime->tm_mday;
	pReport->newFile.creationDate.hour = dateTime->tm_hour;
	pReport->newFile.creationDate.minute = dateTime->tm_min;
	pReport->newFile.creationDate.month = dateTime->tm_mon + 1;
	pReport->newFile.creationDate.second = dateTime->tm_sec;
	pReport->newFile.creationDate.year = (uint8_t)(dateTime->tm_year - 100);
	dateTime = gmtime(&time);
	pReport->newFile.modifiedDate.day = dateTime->tm_mday;
	pReport->newFile.modifiedDate.hour = dateTime->tm_hour;
	pReport->newFile.modifiedDate.minute = dateTime->tm_min;
	pReport->newFile.modifiedDate.month = dateTime->tm_mon + 1;
	pReport->newFile.modifiedDate.second = dateTime->tm_sec;
	pReport->newFile.modifiedDate.year = (uint8_t)(dateTime->tm_year - 100);

	pReport->newFile.fileAttributes = 0;
	memset(&pReport->newFile.calculatedMD5, 0, sizeof(MD5));
	memset(&pReport->newFile.providedMD5, 0, sizeof(MD5));
	pReport->newFile.calculatedCRC = 0;
	pReport->newFile.providedCRC = 0;
	pReport->newFile.storageControllerAddress = mainTaskAddress | pTaskInfo->portNum;

	char fileName[13];
	sprintf(fileName, "%.8lX.txt", pTaskInfo->pBuf->fileID);

	DotToPad(pReport->newFile.fileName, fileName);

	(headFloatTx < (MAX_FLOAT_BUFFERS - 1)) ? (headFloatTx++) : (headFloatTx = 0);
	
	if(headFloatTx == tailFloatTx)
	{
		(tailFloatTx < (MAX_FLOAT_BUFFERS - 1)) ? (tailFloatTx++) : (tailFloatTx = 0);
	}

	OSMutexPost(pMutexFloatQueue);

	return retval;
}


void SerialPortPassThroughGPCTD(uint8_t port)
{
	readyForSerialPassThru = TRUE;

	while(1)
	{
		OSTimeDlyHMSM(1,0,0,0);
	}
}
