/*
 * sonardyneCommand.h
 *
 *  Created on: Jan 20, 2015
 *      Author: emartin
 */

#ifndef SONARDYNECOMMAND_H_
#define SONARDYNECOMMAND_H_

#include <stdio.h>
#include <string.h>
/*
 * CLASS
 * sonardyneCommand
 *
 * DESCRIPTION
 * Sonardyne command string class for General SMS (sonardyne messaging service)
 * message construction and message translation to/from SMAC messages (seafloor
 * mapping acoustic communications), neededfor development of the sonardyne
 * avtrak drivers. These response and interrogation structures do not
 * support multi-element messages (CS:ME1)
 *
 * Based on Sonardyne command language Version 1.04.05, see document
 * CommandLaguage_V1_04_05a.doc for further details.
 *
 */
#define SCL_STRINGMAX 256
#define SCL_SMSMAX    128

typedef struct t_SCL_NMEA_HEADER_RECORD {
	unsigned int talkerID; //SF,M1,M2
	unsigned int msgType; // SAN, STA, or CMD
	unsigned int version; //protocol version
	unsigned long int ts_sec; //seconds from epoch
	unsigned long int ts_msec;//millsecond fraction
	unsigned int frontLen; // length in characters of the header portion of the record.
}SCL_NMEA_HEADER_RECORD;

typedef struct t_SCL_SAN_RECORD {
	float wfTime; //timestamp
	float wfLat;  //latitude
	float wfLong; //longitude
	float wfSlant;//slantrange
}SCL_SAN_RECORD;

typedef struct t_SCL_STATUS_RECORD {
	// Data from AUV
	  float auvLat;
	  float auvLong;
	  float auvHeading;
	  float auvDepth;
	  float auvAlt;
	  float auvVolt;
	  float auvHumid;
	  unsigned int auvBehavior;
	  unsigned int auvAbort;
}SCL_STATUS_RECORD;

typedef struct t_SCL_CMD_RECORD {
	unsigned int cmd; // see MsgCmdType enum for values.
}SCL_CMD_RECORD;



typedef struct t_SCL_RECORD_HEADER {
	unsigned int cmdtype; //command type will set two letter command field
	unsigned int address; //address to interrogate;
}SCL_RECORD_HEADER;

typedef struct t_SCL_FIRMWARE_RESPONSE {
	char firmwareVersionString[SCL_STRINGMAX];
	int firmwareVersionStringLength;
	char protocolVersionString[SCL_STRINGMAX];
	int protocolVersionStringLength;
}SCL_FIRMWARE_RESPONSE;

typedef struct t_SCL_BOOTLOADER_RESPONSE {
	char bootloaderVersionString[SCL_STRINGMAX];
	int bootloaderVersionStringLength;
}SCL_BOOTLOADER_RESPONSE;

typedef struct t_SCL_MEASURERANGE_RESPONSE {
	unsigned long int rangeTime; // time of flight in microseconds including TAT
}SCL_MEASURERANGE_RESPONSE;

typedef struct t_SCL_MEASURESLANTRANGE_INT {
	char interrogationSignalString[SCL_STRINGMAX];
	int  interrogationSignalStringLength;
	int  wakeupTone;
	char channel1Descriptor[SCL_STRINGMAX];
	int  channel1DescriptorLength;
	char channel2Descriptor[SCL_STRINGMAX];
	int  channel2DescriptorLength;
	char channel3Descriptor[SCL_STRINGMAX];
	int  channel3DescriptorLength;
	char channel4Descriptor[SCL_STRINGMAX];
	int  channel4DescriptorLength;

}SCL_MEASURESLANTRANGE_INT;

typedef struct t_SCL_MEASURESLANTRANGE_RESPONSE {
	char channel1Descriptor[SCL_STRINGMAX];
	int  channel1DescriptorLength;
	unsigned long int Channel1RangeTime;
	char channel2Descriptor[SCL_STRINGMAX];
	int  channel2DescriptorLength;
	unsigned long int Channel2RangeTime;
	char channel3Descriptor[SCL_STRINGMAX];
	int  channel3DescriptorLength;
	unsigned long int Channel3RangeTime;
	char channel4Descriptor[SCL_STRINGMAX];
	int  channel4DescriptorLength;
	unsigned long int Channel4RangeTime;
} SCL_MEASURESLANTRANGE_RESPONSE;

typedef struct t_SCL_SMS_INT {
	int wakeupTone; //specifies whether to proceed with a wakeuptone 0 is no tone
	int portNumber; // sets the port number (0-7) default is 0
	int commandNumber; // sets the command number
	int subCode; // 0=SMS_STD EXCHANGE, 1=SMS_ACK_ONLY, 3=NO_RESPONSE
	int rangeData; // 0=no range data on reply, 1=range data in reply
	int bufferMsg; // 0= send immediately, 1=buffer until wd timeout
	char sms[128]; // actual sms message to send
	int smsLength; // length of sms message;
} SCL_SMS_INT;

typedef struct t_SCL_SMS_RESPONSE {
	unsigned long int rangeTime; //range time in microseconds with TAT included.
	int smsReplyCode; //reply or failure code.
	long int smsRangeuS; //range in uSeconds/
	char sms[128]; //optional reply message;
	int smslen; //length of sms string
}SCL_SMS_RESPONSE;


//typedef struct t_SCL_FIXEDSTATUS_RESPONSE {
//	unsigned int uid,
//	unsigned int functionalityLevel,
//	char[SCL_STRINGMAX] firmwareVersionString,
//	char[SCL_STRINGMAX] protocolVersionString,
//	char[SCL_STRINGMAX] transducerInfoString,
//	char[SCL_STRINGMAX] sensorsInfoString,
//	MORE FIELDS TODO LATER
//}SCL_FIXEDSTATUS_PARAMS;


class sonardyneCommand {

public:
	enum CmdType {
		CMD_VERSION = 0, // Firmware and protocol version
		CMD_BOOTLOADER, // Bootloader Version
		CMD_FIXEDSTATUS, // fixed status request
		CMD_VOLATILESTATUS, // volatile status request
		CMD_CONFIGSTATUS, // configuration status request
		CMD_MEASURERANGE, // measure range to target
		CMD_MEASURESLANTRANGE, // measure slant range to target
		CMD_SMS, // sonardyne messaging service message
		CMD_UNKNOWN
	};

	enum smsReplyCode {
		SMS_UNKNOWN = 0,
		SMS_ACK,
		SMS_NO_REPLY,
		SMS_FAILED,
		SMS_OK,
		SMS_SMS,
	};

	enum MsgType {
		MSG_UNKNOWN = 0, //unknown message type
		MSG_SAN,//surface aided navigation
		MSG_STA,	//status message
		MSG_CMD, 	//command message

	};

	enum TalkerID{
		TID_UNKNOWN = 0, //unknown source no more than 14 allowed (single char limit)
		TID_SURFACE,     //source surface
		TID_MAPPER1,	 //mapper1 source
		TID_MAPPER2	     //mapper2 source
	};

	enum MsgCmdType {
		REQ_STAT = 0,      // Surface request for status from vehicle
		REQ_SAN_ON,    // Vehicle requests surface to begin sending SAN messages
		REQ_SAN_OFF,   // Vehicle requests surface to stop sending SAN messages
		ABORT_MISSION, // Surface commanding vehicle to abort mission
		START_SURVEY,   // Surface commanding vehicle to start survey
        INVALID_CMD
	};

	enum BhavrType {
		ABORT_BHAVR = 0,
		DIVE_BHAVR,
		SURVEY_BHAVR,
		ASCEND_BHAVR,
		INVALID_BHAVR // Should always be the last one
	};

	sonardyneCommand();

	//void encodePacket(char * msg, short numBytes); //decoder constructor
	static void encodePacket(char * packet, int * packetsize, int cmdType); //encoder constructor for commands without input
	static int encodePacket(char * packet, int * packetsize,
			SCL_RECORD_HEADER * hdr); // encoder class constructor for commands with address input only
	static void encodePacket(char * packet, int * packetsize,
			SCL_RECORD_HEADER *hdr, SCL_SMS_INT * sms); // encoder constructor for an sms message.
	static void encodePacket(char * packet, int * packetsize,
			SCL_RECORD_HEADER *hdr, SCL_MEASURESLANTRANGE_INT * msr); // encoder constructor for measure of slant range.

	// encode the message string for sms inclusion
	static void encodeNMEAMsg(char * msg, int * msgsize, SCL_NMEA_HEADER_RECORD * hdr, SCL_SAN_RECORD * san);
	static void encodeNMEAMsg(char * msg, int * msgsize, SCL_NMEA_HEADER_RECORD * hdr, SCL_STATUS_RECORD * status);
	static void encodeNMEAMsg(char * msg, int * msgsize, SCL_NMEA_HEADER_RECORD * hdr, SCL_CMD_RECORD * cmd);

    static void decodeHeader(char *packet, int *packetsize, SCL_RECORD_HEADER * header);

    static void decodeSMS(char *packet, int * packetsize, SCL_SMS_RESPONSE * smsResponse);
    static void decodeMeasureRange(char *packet, int * packetsize, SCL_MEASURERANGE_RESPONSE * mrResponse);
    static void decodeMeasureSlantRange(char *packet, int * packetsize, SCL_MEASURESLANTRANGE_RESPONSE * msrResponse);

    //decoder for sms nmea messages
    // encode the message string for sms inclusion
    static void decodeNMEAMsgHeader(char * msg, int * msgsize, SCL_NMEA_HEADER_RECORD * hdr);
    static void decodeNMEAMsgContent(char * msg, int * msgsize, SCL_SAN_RECORD * san);
	static void decodeNMEAMsgContent(char * msg, int * msgsize, SCL_STATUS_RECORD * status);
	static void decodeNMEAMsgContent(char * msg, int * msgsize, SCL_CMD_RECORD * cmd);
	static void validateNMEAchecksum(char * msg, int * msgsize, unsigned int * valid); //1 valid 0 invalid

	virtual ~sonardyneCommand();
private:
	static void encodeHeader(char * packet, int *packetsize, SCL_RECORD_HEADER * hdr);
	static void encodeNMEAMsgHeader(char *msg , int *msgsize, SCL_NMEA_HEADER_RECORD *hdr);
	static void generateChecksum(char *msg, int *msgsize, unsigned int *checksum);

};

#endif /* SONARDYNECOMMAND_H_ */
