Template for LPC1768

Dependencies:   Gimbal MLX90620 Socket lwip-eth lwip-sys lwip mbed-rtos mbed

Fork of EkkoEye by EkkoSense

main.cpp

Committer:
gardnmc
Date:
2016-04-14
Revision:
54:aaf6b5ceedd8
Parent:
53:72f350a6d09c

File content as of revision 54:aaf6b5ceedd8:

#include "mbed.h"
#include "EthernetInterface.h"
#include "CMLX90620.h"
#include "base.h"
#include <string.h>
#include <time.h>
#define MAX_CHARS 1024
Serial pc(USBTX, USBRX);
Ticker Pulser;

/*
DigitalOut	xStep(LED1);
DigitalOut	xDir(LED2);
DigitalOut	yStep(LED3);
DigitalOut	yDir(LED4);
DigitalIn	xStop(p20);
DigitalOut	laser(p11);
*/

DigitalOut	xStep(p14);
DigitalOut	xDir(p26);
DigitalOut	yStep(p6);
DigitalOut	yDir(p5);
DigitalOut	enable(p22);
DigitalOut	newenable(p25);
DigitalOut	laser(p20);
DigitalIn	xHome(p15);
DigitalIn	yHome(p13);

//	DigitalIn	m0X(p19);		//	Must be set to float to achieve some micro-step values
DigitalOut	m1X(p18);
DigitalOut	m0X(p19);

//DigitalIn	m0Y(p8);			//	Must be set to float to achieve some micro-step values
DigitalOut	m1Y(p11);
DigitalOut	m0Y(p8);


char* EEbuf = new char[256];	//	buffer for contents of EEPROM
char* RamCmmd = new char[8];	//	holds / sends MLX90620 RAM commands
char* RamBuf = new char[128];	//	0x3f words, values are 'unsigned short'
float Ta = 0.0;					//	Ambient temperature from MLX
float TempPxl = 0.0;			//	Interim measure for use with centre pixel of 16x4 MLX array
int mgTick=0;					//	Used as a general reference by core Timer ISR
MLX90620 mlx(p9, p10, "mlx");	//	Constructor for mlx class
ROTATION	rotn;				//	Structure for x and y rotation values

CGimbal gimbal(&xStep, &xDir, &yStep, &yDir);	//	Constructor for gimbal
CGimbal * pGimbal=NULL;							//	Pointer to gimbal class for easing argument passing



int main() {

	char cmd;
	int timeout=1200;

    init();
	pc.printf("Initialising Network...\r\n");
    EthernetInterface eth;
    eth.init(); //Use DHCP
    eth.connect();
    
    pc.printf("IP Address is %s\r\n", eth.getIPAddress());

    while (1)
    {
    	cmd = handleSerial();		// Checks for any input from user and returns single char command token
    	switch(cmd)
    	{
			case	'G'	:			//	Hand over to server
			case	'g'	:
    			ServerLoop();
    			break;

			case	'h'	:			//	Go to Home position
			case	'H'	:
				enable.write(1);
    			pGimbal->Home();
    			enable.write(0);
    			break;

			case	'L'	:			//	Laser ON
				laser = ON;
				pc.printf("Laser ON\r\n");
				break;

			case	'l'	:			//	Laser OFF
				laser = OFF;
				pc.printf("Laser OFF\r\n");
				break;

			case	'm'	:			//	Perform a meander-scan and take readings
			case	'M'	:
				pGimbal->MeanderScan();
				break;

			case	'r'	:			//	Rotate to absolute (x,y) position, perform homing reference first
				Rotate(rotn);
				break;

			case	'R'	:			//	Rotate to absolute (x,y) position direct without homing first
				RotateNoHome(rotn);
				break;

			case	't'	:			//	Execute a tour using internal stored waypoints
			case	'T'	:
				Tour();
				timeout = 600;
				break;

			case	'v'	:			//	Measure the temperature at the current position
			case	'V'	:
				//	xStop();
				Measure();
				break;

			case	'z'	:			//	Set this position as the home reference
			case	'Z'	:
				//	xStop();
				Zero();
				break;

			default	:
    			break;
    	}
    	wait(0.1);
    }
    
    eth.disconnect();
}

/*
 *	Set all parameters to a known state
 */
int init()
{

 	int i;

	laser.write(0);					//	Ensure the laser is off
 	enable.write(0);				//	Disable the x and y motor drivers
	pc.baud(115200);				//	Set the USB virtual comm port baud rate to 115200
	pGimbal = &gimbal;				//	Determine the pointer to the gimbal class
	Pulser.attach_us(Pulse, 10);	//	Start the ISR ticker event every 10us
	xHome.mode(PullUp);				//	Enable weak pull-up
	yHome.mode(PullUp);				//	Enable weak pull-up

	wait(1);
	//	m0X.mode(PullNone);				//	Disable pull-up to force it to float
	m0X.write(1);					//	Set X micro-step to 1/16
	m1X.write(1);					//	Set X micro-step to 1/16

	//	m0Y.mode(PullNone);				//	Disable pull-up to force it to float
	m0Y.write(1);					//	Set Y micro-step to 1/16
	m1Y.write(1);					//	Set Y micro-step to 1/16

	mlx.LoadEEPROM();         		//	if returns non 0, MLX90620 may not be connected to i2c bus
    mlx.SetOscTrimReg();      		//	if returns non 0, MLX90620 is having RAM access problems with i2c bus
    mlx.SetConfigReg();       		//	if returns non 0, shouldn't be any i2c problems at this point
    mlx.StartMeasurement();

    newenable.write(1);				//	newenable is a temporary over-ride for the motor enable signal

	//	Insert some random way-points into the tour for testing only (will get over-written by remote server anyway)
    srand (time(NULL));
	for (i=0; i<MAX_TOUR; i++)
	{
		gimbal.m_TourPoints[X_AXIS][i] = (0x3fffffff - rand()) / 13421760;
		gimbal.m_TourPoints[Y_AXIS][i] = (0x3fffffff - rand()) / 13421760;
	}
	return(0);

/*
 * Manual entries instead...
 *
 *
    gimbal.m_TourPoints[X_AXIS][0] = 50;
	gimbal.m_TourPoints[X_AXIS][1] = -50;
	gimbal.m_TourPoints[X_AXIS][2] = 100;
	gimbal.m_TourPoints[X_AXIS][3] = -100;
	gimbal.m_TourPoints[X_AXIS][4] = 100;
	gimbal.m_TourPoints[X_AXIS][5] = -100;
	gimbal.m_TourPoints[X_AXIS][6] = 50;
	gimbal.m_TourPoints[X_AXIS][7] = -50;
  *
  *
  *
*/
}


/*
 *	Parse the response from the remote server and determine the number of way-points and respective x,y coordinates
 */
int parseServerResponse(char * buffer, CGimbal * pgimbal)
{
	char * startstr=NULL;
	char * endstr=NULL;
	int PointIdx=0;

	//	Typical Server Response...
	//	{"status":"1 readings imported","readingVals":[{"xAngle":5,"yAngle":0},{"xAngle":13,"yAngle":4}]}

	startstr = strstr(buffer, "status\":\"");
 	while (startstr)
 	{
		startstr = strstr(startstr, "xAngle");
		endstr = strstr(startstr, ",");

		if (startstr)
		{
			pgimbal->m_TourPoints[X_AXIS][PointIdx] = strtol(startstr+8, &endstr, 10);
			startstr = strstr(startstr, "yAngle");
			endstr = strstr(startstr, "}");

			if (startstr)
			{
				pgimbal->m_TourPoints[Y_AXIS][PointIdx] = strtol(startstr+8, &endstr, 10);
				PointIdx++;
			}
		}
	}

	return(PointIdx);
}

/*
 *	Retrieves the MLX data, currently only prints it to stdout (USB virt comm port)
 */
float ReadMLX(void)
{
	int chk = 0x200;	//  Running flag in config register
	int i, j;			//	Used only for future meander-scan operation
	float	tPix=0.0;	//	Stores temperature of centre pixel

	mlx.CalcTa_To();						//	Get ambient temperature
	Ta = mlx.GetDieTemp();
    //	pc.printf("\nTa = %3.1f\r\n", Ta);

    mlx.StartMeasurement();					//	Starts a conversion
    wait (.5);								//	Allow time for gimbal to settle
	laser.write(1);							//	Switch on laser
    wait (.5);								//	Allow time to settle
    while(chk > 0)							//	1 second should have been ample time to complete a conversion, but check the completion flag anyway
	{
		chk = mlx.GetConfigReg() & 0x200;	//	Completion flag is b9 of config register
		if(chk == 0)
			mlx.LoadMLXRam();				//	Retrieve the values from the MLX Ram contents
		else
		   wait_ms(200);
	}
    /*
	for(i = 0; i < 16; i++)					//	The MLX pixel format is 16 columms of 4 rows rather than 4 rows of 16 columns
	{										//	So values have to be read out x0y0, x0y1, x0y2, x0y3 rather than x0y0, x1y0, x2y0 ...
		for (j=0; j<4; j++)
		{
			TempPxl = mlx.CalcPixel(j + i*4);
			pc.printf("%3.1f ", TempPxl);
		}
		printf("\r\n");
	}
	printf("\r\n");
	*/

	tPix = mlx.CalcPixel(31);				//	Centre pixel
	laser.write(0);							//	Switch off laser

	return(tPix);

}
/*
 *	Performs an HTTP transaction with the remote server and stores the response in the char * data buffer
 */
void ContactServer(char * data)
{
    TCPSocketConnection sock;
	int ret;

	sock.connect("ekko.legendary-services.com", 80);
	char http_cmd[] = "GET /api/ekkocam?data=";
	char http_data[256];
	char readingvals[256];
	char http_footer[] = "Host: ekko.legendary-services.com\r\nAccept: application/json\r\n\r\n\r\n";


	sprintf(readingvals, "\"readingVals\":[{");
	for (ret=0; ret < pGimbal->m_NumWaypoints -1; ret++)
	{
		sprintf(http_data, "\"xAngle\":%3.1f,\"yAngle\":%3.1f,\"temperature\":%3.1f", pGimbal->m_TourPoints[X_AXIS][ret], pGimbal->m_TourPoints[Y_AXIS][ret], pGimbal->m_PointTemperature[ret]);	// temporary use of http_data array to conserve RAM
		strcat(http_data, ",");
		strcat(readingvals, http_data);
	}
	//	No comma on the last entry...
	sprintf(http_data, "\"xAngle\":%3.1f,\"yAngle\":%3.1f,\"temperature\":%3.1f", pGimbal->m_TourPoints[X_AXIS][ret], pGimbal->m_TourPoints[Y_AXIS][ret], pGimbal->m_PointTemperature[ret]);	// temporary use of http_data array to conserve RAM
	strcat(readingvals, http_data);

	//  Dummy time value is 1458085736
	sprintf(http_data, "{\"systemID\":\"hello\",\"sensorID\":\"Ekko0001\",\"eventID\":\"132\",\"utcStamp\":\"%ld\",%s}]} HTTP/1.0\r\n", time(NULL), readingvals);
	sprintf(data, "%s%s%s", (char *)http_cmd, (char *)http_data, (char *)http_footer);
	printf("\f%s", (char *)data);

	sock.send_all(data, strlen(data));

	while (true) {
		ret = sock.receive_all(data, MAX_CHARS -1);
		if (ret <= 0)
			break;
		data[ret] = '\0';
		pc.printf("Received %d bytes:\r\n%s\r\n", ret, data);
	}

	sock.close();

}

/*
 *	Communicate with server, interpret the response and instruct the gimbal accordingly
 */
int ServerLoop(void)
{
	char buffer[MAX_CHARS];
	int	i;

    while(1)
    {

    	ContactServer(buffer);
		pGimbal->m_NumWaypoints = parseServerResponse(buffer, pGimbal);

		pc.printf ("ISR Count: %08d, numwaypoints: %d\r\n", mgTick, pGimbal->m_NumWaypoints);

		enable.write(1);
		for (i=0; i< pGimbal->m_NumWaypoints; i++)
		{
			//	Issue command to move to waypoint [i]
			pGimbal->RotateAbs(pGimbal->m_TourPoints[X_AXIS][i], pGimbal->m_TourPoints[Y_AXIS][i]);
			pGimbal->m_PointTemperature[i] = ReadMLX();
			printf("Temperature at (%3.1f,%3.1f)=%3.1f\r\n", pGimbal->m_TourPoints[X_AXIS][i], pGimbal->m_TourPoints[Y_AXIS][i], pGimbal->m_PointTemperature[i]);
		}
		pGimbal->Home();

		printf("Temperature at (0,0)=%3.1f\r\n", pGimbal->m_PointTemperature[i]);
		printf("Socket Closed\r\n");
		enable.write(0);
		wait(8);
    }

}
/*
 * 	Execute a tour by stepping through 'i' way-points
 */
void	Tour(void)
{
	int i;

	enable.write(1);
	pc.printf("Performing manual tour...\r\n");
	for (i=0; i<MAX_TOUR; i++)
	{
		pGimbal->TourPoint(i);
		pGimbal->m_PointTemperature[i] = ReadMLX();
		printf("Temperature at (%3.1f,%3.1f)=%3.1f\r\n", pGimbal->m_TourPoints[X_AXIS][i], pGimbal->m_TourPoints[Y_AXIS][i], pGimbal->m_PointTemperature[i]);
	}
	enable.write(0);

}

void	xStop(void)
{
	pc.printf("Stop state: %02x\r\n", xHome.read());
}

/*
 * Set the current x,y position as the Zero point for all x and y coordinates
 */
void	Zero(void)
{
	pGimbal->m_AbsoluteXAngle = 0.0;
	pGimbal->m_AbsoluteXPos = 0;
	pGimbal->m_AbsoluteYAngle = 0.0;
	pGimbal->m_AbsoluteYPos = 0;
}

/*
 * Rotate to absolute position x,y stored in the rotn structure, reference to home before moving
 */
void	Rotate(ROTATION rotn)
{
	float temperature;
	enable.write(1);
	pGimbal->Home();
	pGimbal->RotateAbs(rotn.xAngle, rotn.yAngle);
	temperature = ReadMLX();
	printf("%3.1f\r\nOK\r\n", temperature);
	enable.write(0);
}

/*
 * Rotate to absolute position x,y stored in the rotn structure without reference to home before moving
 */
void	RotateNoHome(ROTATION rotn)
{
	float temperature;
	enable.write(1);
	pGimbal->RotateAbs(rotn.xAngle, rotn.yAngle);
	temperature = ReadMLX();
	printf("%3.1f\r\nOK\r\n", temperature);
	enable.write(0);
}

/*
 * Display the current MLX temperature value
 */
void	Measure(void)
{
	float temperature;

	temperature = ReadMLX();
	printf("%3.1f\r\nOK\r\n", temperature);

}