/*---------------------------------------------------------------------------\
| Project:		Generic LV2 PIC18F458 CAN node firmware
|
| File:			main.c
|
| Description:		Mainline routines.
|
| Global Routines:	Main()
|
| Local Routines:	None
|
|    Date    | Notes
|------------|------------------------------------------------------------
| 06/01/2002 | Stolen from ADG code.
\---------------------------------------------------------------------------*/


//------------------------------------------------------------------------
//  #includes
//------------------------------------------------------------------------

#include <pic18.h>    	// Include for PICC-18
#include "pic18fxx8.h"	// Register definitions for the PIC18F458
#include "project.h"	// Includes for the project (Globals + misc)
#include "main.h"	// Includes for the mainline
#include "ints.h"	// Includes for interrupts
#include "excepts.h"	// Includes for exception handling
#include "ports.h"	// Includes for the port peripherals
#include "timer2.h"	// Includes for the Timer2 peripheral
#include "serial.h"	// Includes for the serial peripheral (UART )
#include "can.h"	// Includes for the CAN peripheral



//------------------------------------------------------------------------
//	Global Variables
//------------------------------------------------------------------------

	static	uint8_t			prevByte, currByte;
	static	bit			newGpsMsg;
	static	uint16_t		gpsMsgId, gpsMsgLength;
	/* gpsMsgLength represents the number of data bytes in the message,
	   *not* the number of data words! I can't recall why I ever thought
	   it need to be 16-bit (judging by the Zodiac docs, it appears unlikely
	   that any messages will contain more than 255 bytes) but I must have
	   had some reason. */



//------------------------------------------------------------------------
//  Function Prototypes
//------------------------------------------------------------------------

	bit		GpsHeaderWatch( void );
	void		BuildCanMsgs( void );



/*---------------------------------------------------------------------------\
| Function:		main
|
| Purpose:		Run all Mainline code
|
| Discussion:		Doesn't do much, huh?
|
| Expects:		Uh let's see... nothing.
|
|    Date    | Notes
|------------|------------------------------------------------------------
| 10 Feb 02  | Created if you can call it that.
| 11 Aug 02  | GPS work begun by PEM
| 19 Aug 02  | Still working on it...
| 25 Aug 02  | Ditto...
\---------------------------------------------------------------------------*/

void main (void)
{
	// Initialize everything and its brother
	Initialize();

	// Loop for ever...and......ev....er....and.......ev............er.
	while (TRUE)
	{
	    if ( gSerialRxDataAvailable )
	    {
		prevByte = currByte;
		currByte = GetSerialByte();

		newGpsMsg = GpsHeaderWatch();
		BuildCanMsgs();
	    }
	}

} // end main




/*---------------------------------------------------------------------------\
| Function:	GpsHeaderWatch
|
| Purpose:	Returns TRUE/FALSE to indicate wether or not it has determined
|		the beginning of a new GPS message. Sets a global byte with
|		the value of the new incoming GPS message ID and a global byte
|		with the number of data words in the incoming GPS message, so
|		that BuildCanMsg() knows what it's dealing with.
|
| Discussion:	Talk amongst yourselves!
|
| Expects:	ADG's core firmware to perform as promised! :-)
|
|    Date    | Notes
|------------|------------------------------------------------------------
|  11 Aug 02 | Outlined by PEM
|  19 Aug 02 | Mostly completed by PEM
|  25 Aug 02 | Hopefully finished by PEM
|  27 Aug 02 | Really finished by PEM
\---------------------------------------------------------------------------*/

bit GpsHeaderWatch( void )
{

    #define CHECKSUM_BYTE	10	/* Position in the header byte
					   stream occupied by msB of checksum value */
    #define GPS_MSG_ID_BYTE	4	// Position of msB of GPS message ID
    #define GPS_MSG_LENGTH_BYTE	6	// Position of msB of GPS message data length

    // These var's actually *need* to be static:
    static  uint8_t	    headerByteCounter;
    static  uint16_t	    headerByteSum;
 
    if ( currByte == 0x81  &&  prevByte == 0xFF )
    {
	// We may have the makings of a new header...
	headerByteSum = 0x81FF;
	headerByteCounter = 3;
	return FALSE;
    }

    if ( headerByteCounter > 0 )
    {
	// There's checksum work to be done...
	if ( headerByteCounter <= CHECKSUM_BYTE )
	{
	    // Start/continue adding bytes. Look for relevant header data...
	    if ( headerByteCounter % 2 == 1 )
	    {
		// It's the lsB..
		headerByteSum += currByte;
	    }
	    else
	    {
		// It's the msB...
		headerByteSum += ( currByte << 8 );
	    }

	    if ( headerByteCounter == GPS_MSG_ID_BYTE )
		gpsMsgId = ( currByte << 8 ) + prevByte;
	    if ( headerByteCounter == GPS_MSG_LENGTH_BYTE )
		gpsMsgLength = (( currByte << 8 ) + prevByte) * 2;

	    ++headerByteCounter;
	    return FALSE;
	}

	else
	{
	    // Now we test the checksum...
	    headerByteCounter = 0;

	    if ( headerByteSum == 0 )
	    {
		// We have a match -- it's a new header!
		return TRUE;
	    }

	    else
	    {
		// No match -- not a new header.
		return FALSE;
	    }
	}

    }

} // end GpsHeaderWatch




/*---------------------------------------------------------------------------\
| Function:	BuildCanMsgs
|
| Purpose:	Grab incoming GPS message bytes and use them to assemble
|		CAN messages.
|
| Discussion:	Talk amongst yourselves!
|
| Expects:	Relies on data provided by GpsHeaderWatch().
|
|    Date    | Notes
|------------|------------------------------------------------------------
|  11 Aug 02 | Handcrafted by PEM
|  29 Aug 02 | Desperately fleshed out by PEM
|  05 Sep 02 | More desperation...
|  15 Sep 02 | God save us!
\---------------------------------------------------------------------------*/

void BuildCanMsgs()
{

	#define GPS_CAN_ID	0x06		// GPS CAN message ID

	// These var's actually *need* to be static:
	static	uint8_t		dataByteCounter;
	static	uint16_t	dataByteSum;
	static	CanMessage_t	canMsgs[6];	// Six is all we need for now.
	static	uint8_t		qtyCanMsgs;	// Number of CAN messages derived from the current GPS message.
	static	uint8_t		foo, bar;

	// A new GPS message is incoming -- start over...
	if ( newGpsMsg )
	{
		dataByteSum = 0;

		/* Initialize the CAN messages' data arrays. Probably unnecessary,
		   but I like to show off my incredible coding prowess. */
		for ( foo=0; foo<6; ++foo )
		    for ( bar=0; bar<8; ++bar )
			canMsgs[foo].data[bar] = 0;

		/* It's a "header-only" message. Nothing to see here, folks,
		   move along... (And yes, it's an ugly hack. So sue me.
		   The rocket will still fly. Then again, the rocket will
		   fly without any GPS code at all. I don't belong here!!!) */
	    if ( gpsMsgLength == 0 )
			dataByteCounter = 255;
		else
	  	  dataByteCounter = 0;
	}

	/* We must already be working with an incoming GPS message.
	   It's "gpsMsgLength + 2" because the two-byte data checksum
	   at the end of the GPS message is not included in gpsMsgLength. */
	else if ( dataByteCounter <= gpsMsgLength + 2 )
	{
		++dataByteCounter;

		// Collect bytes for checksum purposes
		if ( dataByteCounter % 2 == 1 )
		    dataByteSum += currByte;
		else
		    dataByteSum += ( currByte << 8 );


		/* Parse those GPS message data bytes and start building CAN
		   messages...

		Six CAN messages derive from GPS message 1000.
		The structure of each CAN message data array is as follows:
		
		CAN Msg ID	    Data Array Index	GPS Msg Byte #	    Description
		--------------------------------------------------------------------------
		00001		    0			23		    # of measurements
				    1			19		    sol'n validity
				    2			21		    sol'n type
		
		00010		    0			n/a (byte 41)	    years since 2k
				    1			39		    UTC month
				    2			37		    UTC day
				    3			43		    UTC hours
				    4			45		    UTC minutes
				    5			47		    UTC seconds
							    
		00011		    0			56		    latitude (high byte)
				    1			55		    latitude
				    2			54		    latitude
				    3			53		    latitude (low byte)
				    4			60		    longitude (high byte)
				    5			59		    longitude
				    6			58		    longitude
				    7			57		    longitude (low byte)
		
		00100		    0			64		    height (high byte)
				    1			63		    height
				    2			62		    height
				    3			61		    height (low byte)
		
		00101		    0			80		    EHPE (high byte)
				    1			79		    EHPE (low byte)
				    2			84		    EVPE (high byte)
				    3			83		    EVPE (low byte)
				    4			88		    ETE (high byte)
				    5			87		    ETE (low byte)
		
		00110		    0			94		    clock bias (high byte)
				    1			93		    clock bias (low byte)
				    2			98		    clock bias std dev (high byte)
				    3			97		    clock bias std dev (low byte)
				    4			102		    clock drift (high byte)
				    5			101		    clock drift (low byte)
			    
					
		Two CAN messages derive from GPS message 1003
		The structure of each CAN message data array is as follows:
		
		CAN Msg ID	    Data Array Index	GPS Msg Byte #	    Description
		--------------------------------------------------------------------------
		00111		    0			20		    best PDOP (high byte)
				    1			19		    best PDOP (low byte)
				    2			22		    best HDOP (high byte)
				    3			21		    best HDOP (low byte)
				    4			24		    best VDOP (high byte)
				    5			23		    best VDOP (low byte)
		
		01000		    0			18		    best GDOP (high byte)
				    1			17		    best GDOP (low byte)
				    2			26		    best TDOP (high byte)
				    3			25		    best TDOP (low byte)
		
		
		Three CAN messages derive from GPS message 1009
		The structure of each CAN message data array is as follows:
		
		CAN Msg ID	    Data Array Index	GPS Msg Byte #	    Description
		--------------------------------------------------------------------------
		01001		    0			22		    ECEF X (high byte)
				    1			21		    ECEF X
				    2			20		    ECEF X
				    3			19		    ECEF X (low byte)
				    4			26		    ECEF Y (high byte)
				    5			25		    ECEF Y
				    6			24		    ECEF Y
				    7			23		    ECEF Y (low byte)
		
		01010		    0			30		    ECEF Z (high byte)
				    1			29		    ECEF Z
				    2			28		    ECEF Z
				    3			27		    ECEF Z (low byte)
				    4			34		    ECEF dX (high byte)
				    5			33		    ECEF dX
				    6			32		    ECEF dX
				    7			31		    ECEF dX (low byte)
		
		01011		    0			38		    ECEF dY (high byte)
				    1			37		    ECEF dY
				    2			36		    ECEF dY
				    3			35		    ECEF dY (low byte)
				    4			42		    ECEF dZ (high byte)
				    5			41		    ECEF dZ
				    6			40		    ECEF dZ
				    7			39		    ECEF dZ (low byte)
		*/


		if ( dataByteCounter <= gpsMsgLength )
		{
		    if ( gpsMsgId == 1000 )
		    {
			qtyCanMsgs = 6;

			// Build CAN message headers...
			for ( foo=0; foo<qtyCanMsgs; ++foo )
			    canMsgs[foo].header.bits.idlow = GPS_CAN_ID;

			// I have no idea what the request bit is for, so I'm blindly clearing it.
			for ( foo=0; foo<qtyCanMsgs; ++foo )
			    canMsgs[foo].header.bits.request = 0;
			
			canMsgs[0].header.bits.idhigh = 1;	// CAN message # 0b00001
			canMsgs[0].header.bits.length = 3;
			
			canMsgs[1].header.bits.idhigh = 2;	// CAN message # 0b00010
			canMsgs[1].header.bits.length = 6;
			
			canMsgs[2].header.bits.idhigh = 3;	// CAN message # 0b00011
			canMsgs[2].header.bits.length = 8;
			
			canMsgs[3].header.bits.idhigh = 4;	// CAN message # 0b00100
			canMsgs[3].header.bits.length = 4;

			canMsgs[4].header.bits.idhigh = 5;	// CAN message # 0b00101
			canMsgs[4].header.bits.length = 6;

			canMsgs[5].header.bits.idhigh = 6;	// CAN message # 0b00110
			canMsgs[5].header.bits.length = 6;


			switch ( dataByteCounter )
			{
			    /* Strictly speaking, since I am retaining the previous byte I suppose I
			       could cut the number of case evaluations by ~ half. Oh well... */
			    case 19:	canMsgs[0].data[1] = currByte;
					break;
			    case 21:	canMsgs[0].data[2] = currByte;
					break;
			    case 23:	canMsgs[0].data[0] = currByte;
					break;

			    case 37:	canMsgs[1].data[2] = currByte;
					break;
			    case 39:	canMsgs[1].data[1] = currByte;
					break;
			    /* Subtracting 0d208 from the low byte of the UTC year provides us with the
			       # of years since Y2K. */
			    case 41:	canMsgs[1].data[0] = currByte - 208;	
					break;
			    case 43:	canMsgs[1].data[3] = currByte;
					break;
			    case 45:	canMsgs[1].data[4] = currByte;
					break;
			    case 47:	canMsgs[1].data[5] = currByte;
					break;

			    case 53:	canMsgs[2].data[3] = currByte;
					break;
			    case 54:	canMsgs[2].data[2] = currByte;
					break;
			    case 55:	canMsgs[2].data[1] = currByte;
					break;
			    case 56:	canMsgs[2].data[0] = currByte;
					break;
			    case 57:	canMsgs[2].data[7] = currByte;
					break;
			    case 58:	canMsgs[2].data[6] = currByte;
					break;	
			    case 59:	canMsgs[2].data[5] = currByte;
					break;
			    case 60:	canMsgs[2].data[4] = currByte;
					break;

			    case 61:	canMsgs[3].data[3] = currByte;
					break;
			    case 62:	canMsgs[3].data[2] = currByte;
					break;
			    case 63:	canMsgs[3].data[1] = currByte;
					break;
			    case 64:	canMsgs[3].data[0] = currByte;
					break;

			    case 79:	canMsgs[4].data[1] = currByte;
					break;
			    case 80:	canMsgs[4].data[0] = currByte;
					break;
			    case 83:	canMsgs[4].data[3] = currByte;
					break;
			    case 84:	canMsgs[4].data[2] = currByte;
					break;
			    case 87:	canMsgs[4].data[5] = currByte;
					break;
			    case 88:	canMsgs[4].data[4] = currByte;
					break;

			    case 93:	canMsgs[5].data[1] = currByte;
					break;
			    case 94:	canMsgs[5].data[0] = currByte;
					break;
			    case 97:	canMsgs[5].data[3] = currByte;
					break;
			    case 98:	canMsgs[5].data[2] = currByte;
					break;
			    case 101:	canMsgs[5].data[5] = currByte;
					break;
			    case 102:	canMsgs[5].data[4] = currByte;
					break;
			}	
		    }

		    else if ( gpsMsgId == 1003 )
		    {
			qtyCanMsgs = 2;

			// Build CAN message headers...
			for ( foo=0; foo<qtyCanMsgs; ++foo )
			    canMsgs[foo].header.bits.idlow = GPS_CAN_ID;

			// I have no idea what the request bit is for, so I'm blindly clearing it.
			for ( foo=0; foo<qtyCanMsgs; ++foo )
			    canMsgs[foo].header.bits.request = 0;
			
			canMsgs[0].header.bits.idhigh = 7;	// CAN message 0b00111
			canMsgs[0].header.bits.length = 6;
			
			canMsgs[1].header.bits.idhigh = 8;	// CAN message 0b01000
			canMsgs[1].header.bits.length = 4;
			

			switch ( dataByteCounter )
			{
			    case 17:	canMsgs[1].data[1] = currByte;
					break;
			    case 18:	canMsgs[1].data[0] = currByte;
					break;

			    case 19:	canMsgs[0].data[1] = currByte;
					break;
			    case 20:	canMsgs[0].data[0] = currByte;
					break;
			    case 21:	canMsgs[0].data[3] = currByte;
					break;
			    case 22:	canMsgs[0].data[2] = currByte;
					break;
			    case 23:	canMsgs[0].data[5] = currByte;
					break;
			    case 24:	canMsgs[0].data[4] = currByte;
					break;

			    case 25:	canMsgs[1].data[3] = currByte;
					break;
			    case 26:	canMsgs[1].data[2] = currByte;
					break;
			}
		    }

		    else if ( gpsMsgId == 1009 )
		    {
			qtyCanMsgs = 3;

			// Build CAN message headers...
			for ( foo=0; foo<qtyCanMsgs; ++foo )
			    canMsgs[foo].header.bits.idlow = GPS_CAN_ID;

			// I have no idea what the request bit is for, so I'm blindly clearing it.
			for ( foo=0; foo<qtyCanMsgs; ++foo )
			    canMsgs[foo].header.bits.request = 0;
			
			canMsgs[0].header.bits.idhigh = 9;	// CAN message # 0b01001
			canMsgs[0].header.bits.length = 8;
			
			canMsgs[1].header.bits.idhigh = 10;	// CAN message # 0b01010
			canMsgs[1].header.bits.length = 8;
			
			canMsgs[2].header.bits.idhigh = 11;	// CAN message # 0b01011
			canMsgs[2].header.bits.length = 8;
			

			switch ( dataByteCounter )
			{
			    case 19:	canMsgs[0].data[3] = currByte;
					break;
			    case 20:	canMsgs[0].data[2] = currByte;
					break;
			    case 21:	canMsgs[0].data[1] = currByte;
					break;
			    case 22:	canMsgs[0].data[0] = currByte;
					break;
			    case 23:	canMsgs[0].data[7] = currByte;
					break;
			    case 24:	canMsgs[0].data[6] = currByte;
					break;
			    case 25:	canMsgs[0].data[5] = currByte;
					break;
			    case 26:	canMsgs[0].data[4] = currByte;
					break;

			    case 27:	canMsgs[1].data[3] = currByte;
					break;
			    case 28:	canMsgs[1].data[2] = currByte;
					break;
			    case 29:	canMsgs[1].data[1] = currByte;
					break;
			    case 30:	canMsgs[1].data[0] = currByte;
					break;
			    case 31:	canMsgs[1].data[7] = currByte;
					break;
			    case 32:	canMsgs[1].data[6] = currByte;
					break;
			    case 33:	canMsgs[1].data[5] = currByte;
					break;
			    case 34:	canMsgs[1].data[4] = currByte;
					break;

			    case 35:	canMsgs[2].data[3] = currByte;
					break;
			    case 36:	canMsgs[2].data[2] = currByte;
					break;
			    case 37:	canMsgs[2].data[1] = currByte;
					break;
			    case 38:	canMsgs[2].data[0] = currByte;
					break;
			    case 39:	canMsgs[2].data[7] = currByte;
					break;
			    case 40:	canMsgs[2].data[6] = currByte;
					break;
			    case 41:	canMsgs[2].data[5] = currByte;
					break;
			    case 42:	canMsgs[2].data[4] = currByte;
					break;
			}
		    }
		}

		// Deal with the checksum, and maybe even send a CAN message!
		else if ( dataByteCounter == gpsMsgLength + 2 )
		{
		    if ( dataByteSum ==0 )
		    {
			// Checksum looks good! Let's send a few CAN messages...
			for ( foo=0; foo<qtyCanMsgs; ++foo )
			    SendCanMsg( &canMsgs[foo] );
		    }
		}

	}

}	// end BuildCanMsgs




/*---------------------------------------------------------------------------\
| Function:		Initialize
|
| Purpose:		Initialize everything. Really.
|
| Discussion:	Did I mention initialization?
|
| Expects:		to be called after a RESET - eg, registers reset to known
|				values and and interrupts off.
|
|    Date    | Notes
|------------|------------------------------------------------------------
| 02/10/2002 | Created if you can call it that.
\---------------------------------------------------------------------------*/

void Initialize (void)
{

	/*
		EVENTUALLY: Check for a reset: If there hasn't been a reset,
		then something has gone horribly wrong. Do a SOFTWARE RESET
		here to put everything in a known state.
	*/

	// Setting up the CAN bus peripheral: We're passing constants
	// to the initialization routine so that we can just set the
	// initialize initialization :) here.

	const CanHeader_t canMaskB0 = (0x000 << 4);
	const CanHeader_t canMaskB1 = (0x000 << 4);
	const CanHeader_t CanFilterB0F0 = (0x000 << 4);
	const CanHeader_t CanFilterB0F1 = (0x000 << 4);
	const CanHeader_t CanFilterB1F2 = (0x000 << 4);
	const CanHeader_t CanFilterB1F3 = (0x000 << 4);
	const CanHeader_t CanFilterB1F4 = (0x000 << 4);
	const CanHeader_t CanFilterB1F5 = (0x000 << 4);

	// Get the outputs stabilized FIRST.

	InitializePorts();

	// Turn on serial transmitter and receiver. Turn on receiver interrupts
	// but leave the transmitter interrupts off (we'll turn them on when
	// there's actual data to send over the port). Make both interrupts
	// low priority, and se the bit rate to 9600bps.

	InitializeSerial (	SERIAL_TRANSMIT_ENABLE
						| SERIAL_TRANSMIT_DISABLE_INTS
						| SERIAL_RECEIVE_ENABLE
						| SERIAL_RECEIVE_ENABLE_INTS
						| SERIAL_BITRATE_9600 );

	// Turn on timer2, HP interrupts @ 1KHz

	InitializeTimer2 (	TIMER2_ENABLE
						| TIMER2_ENABLE_INTS
						| TIMER2_1KHZ );

	// Turn on CAN: See const variable declarations above
	// for the values. Note that as soon as we initialize the
	// the bus, we can start to receive messages, so be sure
	// that interrupts are enabled VERY SOON after this call
	// (No more than about a  message length, which at top
	// speed is about 1/22KHz = 45us which at 20MHz is only
	// 250 instructions.

	InitializeCan (	CAN_BITRATE_1MBPS,
					canMaskB0,		// Mask RXB0
					canMaskB1,		// Mask RXB1
					CanFilterB0F0,		// Filter RXB0 F0
					CanFilterB0F1,		// Filter RXB0 F1
					CanFilterB1F2,		// Filter RXB1 F2
					CanFilterB1F3,		// Filter RXB1 F3
					CanFilterB1F4,		// Filter RXB1 F4
					CanFilterB1F5);		// Filter RXB1 F5

	// Initialize variables before start up

	InitializeVariables();

	// Initialize interrupts

	InitializeInterrupts();

	// DO NO FURTHER INITIALIZATION AFTER INTERRUPTS SINCE WE'RE OFF AND
	// RUNNING ONCE THEY'RE ENABLED.
}





/*---------------------------------------------------------------------------\
| Function:		InitializeVariables
|
| Purpose:		Initialize all mainline variables
|
| Discussion:	Sure.
|
| Expects:		To be called before interrupts enabled, although it's not
|				a requirement.
|
|    Date    | Notes
|------------|------------------------------------------------------------
| 06/01/2002 | Created.
\---------------------------------------------------------------------------*/


void	InitializeVariables (void)
{
	/* Do nothing */;
}




