X893

Car/Personal Tracker with STM32 and UBlox G200/NEO5

New car/personal tracker with STM32F103 microprocessor. Battery or only external 12V-20V power.
Accelerometer, EEPROM, microSD.
Plastic box 90x50x(16 or 24) mm

Use Maple (Arduino compatible) IDE for programming.

 

and in box

 Add SMS control as popular china device but only for compatible. Also Firmware over Air.

UBlox.pde example

#define DEBUG_LEVEL		DEBUG_NONE

#include "common.h"

#include "usb.h"
#include "usart.h"
#include "gsm.h"
#include "gps.h"

#include <string.h>
#include <math.h>
#include <eeprom.h>
#include <softi2c.h>
#include "MMA7455.h"

const char DEFAULT_UPWD[]		= "*XXXX*";
const char DEFAULT_GPWD[]		= "*XXXX*";
const char DEVICE_VERSION[]		= "1.00";

const char FW_GPRS_APN[]		= "internet.mts.ru";
const char FW_GPRS_USER[]		= "mts";
const char FW_GPRS_PASS[]		= "mts";

const char FW_HTTP_HOST[]		= "XXX.XXX.XXX.XXX";
const char FW_HTTP_PORT[]		= "80";
const char FW_HTTP_GET_BEGIN[]	= "GET ";
const char FW_HTTP_GET_END[]	= " HTTP/1.0\r\n\r\n";
const char FW_PARAM_URL[]		= "/GpsGate.aspx";
const char FW_PARAM_LONGITUDE[]	= "?longitude=";
const char FW_PARAM_LATITUDE[]	= "&latitude=";
const char FW_PARAM_SPEED[]		= "&Speed=";
const char FW_PARAM_HEADING[]	= "&heading=";
const char FW_PARAM_DATE[]		= "&date=";
const char FW_PARAM_TIME[]		= "&time=";
const char FW_PARAM_VALID[]		= "&valid=";
const char FW_PARAM_USER[]		= "";
const char FW_PARAM_PASS[]		= "";
const char FW_PARAM_IMEI[]		= "&imei=";
const char FW_PARAM_VERSION[]	= "&version=";
const char FW_PARAM_ACC[]		= "&acc=";

char EE_GSM_GPWD[7];
char EE_GSM_UPWD[7];

uint16 EE_SENDDATA_PERIOD;
uint16 EE_HEARDBEAT_PERIOD;

uint16 Globals, Options;

uint32 LedBlinkTimer;
uint32 HeartBeatTimer;
uint32 SendDataTimer;

volatile uint16 systick_downtimer;
volatile uint16 systick_key_timer;

char *HostCmdPtr;
char HostCommand[HOST_BUFFER_SIZE + 2];

volatile uint8 gsm_unregister;

int16 AX_Last, AY_Last, AZ_Last;
int16 A_Max, AX_Max, AY_Max, AZ_Max;

MMA7455Class MMA7455 = MMA7455Class(&SoftI2C);
G200Class G200 = G200Class(&Serial2);

void InitializeMMA7455(void);
char *PrepareData(void);

void SystemRestart(void)
{
	SerialUSB.end();
	usart_disable_all();
	usbWaitReset();
}

void user_SysTickHandler(void)
{
	if (systick_downtimer > 0)
		--systick_downtimer;
	if (!gpio_read_bit(KEY_PORT, KEY_PIN))
	{
		if (systick_key_timer == 0)
			systick_key_timer = KEY_DEBOUNCE_RESET;
		else if(--systick_key_timer == 0)
			SystemRestart();
	}
	else
		systick_key_timer = 0;
}

void setup()
{
	G200.PIN[0] = 0;
	EE_GSM_GPWD[0] = 0;
	EE_GSM_UPWD[0] = 0;
	EE_SENDDATA_PERIOD	= 120;
	EE_HEARDBEAT_PERIOD	= 30;

	Options = 0;
	Globals = 0;

	systick_key_timer = 0;
	systick_downtimer = 0;
	systick_set_callback(user_SysTickHandler);

    digitalWrite(CPU_PWR, HIGH);
    pinMode(CPU_PWR, OUTPUT);
    digitalWrite(CPU_PWR, HIGH);
    
    pinMode(GSM_ON, OUTPUT);
    digitalWrite(GSM_ON, LOW);
    
    pinMode(GSM_RST, OUTPUT);
    digitalWrite(GSM_RST, LOW);

	G200.off();

    digitalWrite(GPS_PWR, LOW);
    pinMode(GPS_PWR, OUTPUT);
	GPS_Off();

    pinMode(LED, OUTPUT_OPEN_DRAIN);
    digitalWrite(LED, HIGH);
    
	pinMode(ACC_INT1,  INPUT_PULLUP);	// INT1 & INT2 from accelerometer
	pinMode(ACC_INT2, INPUT_PULLUP);

    pinMode(USB_P, INPUT);
    pinMode(KEY, INPUT_PULLUP);

    SerialUSB.begin();
	if (digitalRead(USB_P))
	{
		LED_ON();
		while(!SerialUSB.getDTR());
		Globals |= (HOST_CONNECTED | DEBUG_ON);
		LED_OFF();
	}
/*
	while(1)
	{
		while (SerialUSB.available())
		{
			SerialUSB.read();
			SerialUSB.println("Power pulse");
			digitalWrite(GSM_ON, HIGH);
			delay(500);
			digitalWrite(GSM_ON, LOW);
		}
	}
*/
	LedBlinkTimer = millis();
	HeartBeatTimer = millis();
	SendDataTimer = millis();

	EEPROM.PageBase0 = EEPROM_PAGE_0;
	EEPROM.PageBase1 = EEPROM_PAGE_1;
	EEPROM.PageSize  = EEPROM_SIZE;
	if (EEPROM.init() != EEPROM_OK)
	{
		DebugMsg("EEPROM init failure");
		ErrorBlink(GENERAL_ERROR, EEPROM_ERROR);
	}
	else
	{
		uint16 data;
		if (LoadXPWD(G200.PIN, EEPROM_PIN, false) != EEPROM_OK)
			G200.PIN[0] = '\0';

		if (LoadXPWD(EE_GSM_UPWD, EEPROM_UPWD, true) != EEPROM_OK)
			StringCopyEnd(EE_GSM_UPWD, DEFAULT_UPWD);

		if (LoadXPWD(EE_GSM_GPWD, EEPROM_GPWD, true) != EEPROM_OK)
			StringCopyEnd(EE_GSM_GPWD, DEFAULT_GPWD);

		if (EEPROM.read(EEPROM_SEND_PERIOD, &data) == EEPROM_OK)
			EE_SENDDATA_PERIOD = data;

		if (EEPROM.read(EEPROM_HEARDBEAT_PERIOD, &data) == EEPROM_OK)
			EE_HEARDBEAT_PERIOD = data;

		if (EEPROM.read(EEPROM_OPTIONS, &Options) != EEPROM_OK)
		{
			Options = OPTIONS_DEFAULT;
			EEPROM.write(EEPROM_OPTIONS, Options);
		}
	}

	Globals |= MUX_SELECT_GSM;

	if (GPS_On() != RESPONSE_OK)
		ErrorBlink(GPS_ERROR, GPS_ERROR_INIT);

	gsm_unregister = 0;
	switch(G200.on())
	{
	case RESPONSE_OK:
		break;
	case RESPONSE_GSM_OFF:
		DebugMsgln("GSM power off");
		ErrorBlink(GSM_ERROR, GSM_ERROR_OFF);
		break;
	case RESPONSE_GSM_NO_IMEI:
		DebugMsgln("IMEI read error");
		ErrorBlink(GSM_ERROR, GSM_ERROR_IMEI);
		break;
	default:
		DebugMsgln("GSM unknown error");
		ErrorBlink(GSM_ERROR, GSM_ERROR_UNKNOWN);
		break;
	}

	SoftI2C.begin(ACC_SDA, ACC_SCL);	// Initialize I2C bus (EEPROM and MMA7455)
	InitializeMMA7455();
}


void loop(void) __attribute__ ((naked, noreturn, weak));
void loop(void)
{
	while (1)
	{
		if (digitalRead(USB_P) && SerialUSB.isConnected() && SerialUSB.getDTR())
		{
			if (!(Globals & HOST_CONNECTED))
				Globals |= (HOST_CONNECTED | DEBUG_ON);		// Host connected (first)
		}
		else if (Globals & HOST_CONNECTED)
			Globals &= ~(HOST_CONNECTED | DEBUG_ON);			// Host disconnect (first)

		if (MMA7455.Mode == MMA7455_OK && MMA7455.readXYZ() == SI2C_SUCCESS)
		{
			int16 a_delta = abs(MMA7455.X - AX_Last) + abs(MMA7455.Y - AY_Last) + abs(MMA7455.Z - AZ_Last);
			if (A_Max < a_delta)
			{
				A_Max = a_delta;
				AX_Max = MMA7455.X;
				AY_Max = MMA7455.Y;
				AZ_Max = MMA7455.Z;
			}
			AX_Last = MMA7455.X;
			AY_Last = MMA7455.Y;
			AZ_Last = MMA7455.Z;
		}

		if (Globals & HOST_CMD_ACTIVE)
		{
			SendDataTimer = millis();						// No send during accept HOST command
			HeartBeatTimer = millis();
		}

		if (((millis() - HeartBeatTimer) / 1000) > EE_HEARDBEAT_PERIOD)
		{
			InitializeMMA7455();

			if (!(Globals & GPS_TURN_ON))
				if (GPS_On() != RESPONSE_OK)
					ErrorBlink(GPS_ERROR, GPS_ERROR_INIT);

			if (G200.checkStatus() == RESPONSE_OK)
			{
				gsm_unregister = 0;
				G200.checkSMS();
			}
			else
				switch(G200.Error)
				{
				case RESPONSE_GSM_NOREG:
					if (gsm_unregister++ >= 3)
					{
						G200.off();
						G200.on();
						gsm_unregister = 0;
					}
					break;
				case RESPONSE_TIMEOUT:
					if (G200.reset() != RESPONSE_OK)
					{
						G200.off();
						G200.on();
					}
					break;
				case RESPONSE_GSM_DENIED:
					DebugMsgln("GSM registration denied");
					ErrorBlink(GSM_ERROR, GSM_ERROR_DENIED);
					break;
				case RESPONSE_GSM_OFF:
					DebugMsgln("GSM power off");
					ErrorBlink(GSM_ERROR, GSM_ERROR_OFF);
					break;
				case RESPONSE_GSM_NO_SIM:
					DebugMsgln("SIM not inserted");
					ErrorBlink(GSM_ERROR, GSM_ERROR_NO_SIM);
					break;
				case RESPONSE_GSM_BAD_PIN:
					DebugMsgln("SIM pin invalid");
					ErrorBlink(GSM_ERROR, GSM_ERROR_PIN_BAD);
					break;
				case RESPONSE_GSM_NO_PIN:
					DebugMsgln("SIM pin required");
					ErrorBlink(GSM_ERROR, GSM_ERROR_SIM_PIN);
					break;
				case RESPONSE_GSM_NO_IMEI:
					DebugMsgln("IMEI read error");
					ErrorBlink(GSM_ERROR, GSM_ERROR_IMEI);
					break;
				default:
					DebugMsgln("GSM unknown error");
					ErrorBlink(GSM_ERROR, GSM_ERROR_UNKNOWN);
					break;
				}
			HeartBeatTimer = millis();
		}

		if (((millis() - SendDataTimer) / 1000) > EE_SENDDATA_PERIOD)
		{
			if (GPS_Fixup() == RESPONSE_OK)
			{
				if (!(Globals & GPS_FIXUP))
					ErrorBlink(GPS_ERROR, GPS_ERROR_NOFIX);

				if ((Globals & GPS_FIXUP) || (Globals & SEND_GSM_NO_FIX))
				{
					PrepareData();
					DebugMsgln("\r\n----------------\r\nSend to server:");

					uint8 retries = 2;
					while(retries-- > 0)
					{
						int8 retryConnect = 10;
						while (retryConnect-- > 0 && G200.connect() != RESPONSE_OK)
							delay(1000);

						if (G200.Error == RESPONSE_OK)
						{
							if	(	G200.activateGPRS(FW_GPRS_APN, FW_GPRS_USER, FW_GPRS_PASS) == RESPONSE_OK
								&&	G200.sendTCP(FW_HTTP_HOST, FW_HTTP_PORT, G200.Command) == RESPONSE_OK
								)
								break;			// First attempt
							else
							{
								G200.send("AT+UPSDA=0,4", 15000);		// Deactivate PSD
								if	(	G200.activateGPRS(FW_GPRS_APN, FW_GPRS_USER, FW_GPRS_PASS) == RESPONSE_OK
									&&	G200.sendTCP(FW_HTTP_HOST, FW_HTTP_PORT, G200.Command) == RESPONSE_OK
									)
									break;		// Second attempt
								else
								{
									delay(5000);
									continue;
								}
							}
						}
						else
						{
							ErrorBlink(GSM_ERROR, GSM_ERROR_GPRS);
							break;
						}
						if (retries == 0)
							ErrorBlink(GSM_ERROR, GSM_ERROR_CONNECT);
					}
				}
			}
			else
				ErrorBlink(GPS_ERROR, GPS_ERROR_PARSE);
			SendDataTimer = millis();
		}

		if (IsHostConnect())
		{
			while (SerialUSB.available())
			{
				char data = (char)SerialUSB.read();

				if (data == '\r' || data == '\n')
				{
					Globals |= HOST_CMD;
				}
				else if (Globals & HOST_CMD)
				{
					if (data == '%')
						Globals |= HOST_CMD_ACTIVE;
					Globals &= ~(HOST_CMD | HOST_CMD_TOO_LONG);
					HostCmdPtr = HostCommand;
				}

				if (Globals & HOST_CMD_ACTIVE)
				{
					SerialUSB.write(data);
					if (data == '\r')
					{
						Globals &= ~HOST_CMD_ACTIVE;
						SerialUSB.write('\n');
						if (Globals & HOST_CMD_TOO_LONG)
						{
							SerialUSB.println("Command too long\r\nERROR");
						}
						else
						{
							*HostCmdPtr = 0;
							HostCmdPtr = (char*)ProcessCommand(E_CMD_HOST, HostCommand + 1);	// skip first %
							if (HostCmdPtr != NULL)
								SerialUSB.println(HostCmdPtr);
						}
					}
					else
					{
						if (HostCmdPtr < (HostCommand + HOST_BUFFER_SIZE))
							*HostCmdPtr++ = data;
						else
							Globals |= HOST_CMD_TOO_LONG;
					}
				}
				else
				{
					if (Globals & MUX_SELECT_GSM)
					{
						if (G200.Status & GSM_TURN_ON)
							G200.Port->write(data);
					}
					else if (Globals & MUX_SELECT_GPS)
					{
						if (Globals & GPS_TURN_ON)
							Serial1.write(data);
					}
				}
			}

			if (G200.Status & GSM_TURN_ON)
				while (G200.Port->available())
					SerialUSB.write(G200.Port->read());

//			if (Globals & GPS_TURN_ON)
//				while (Serial1.available())
//					SerialUSB.write(Serial1.read());

			LedBlinkTimer = millis();
		}
		else
		{
			if(millis() - LedBlinkTimer >= 5000)
			{
				digitalWrite(LED, HIGH);
				LedBlinkTimer = millis();
			}
			else if(millis() - LedBlinkTimer >= 4950)
				digitalWrite(LED, LOW);
		}
	}
}

char *PrepareData(void)
{
	GPS_PrepareTrackPoint();

	char *ptr = StringCopyEnd(G200.Command, FW_HTTP_GET_BEGIN);
	ptr = StringCopyEnd(ptr, FW_PARAM_URL);
	ptr = StringCopyEnd(ptr, FW_PARAM_LONGITUDE);
	ptr = StringCopyEnd(ptr, GPS_TrackPoint.Longitude.Text);
	ptr = StringCopyEnd(ptr, FW_PARAM_LATITUDE);
	ptr = StringCopyEnd(ptr, GPS_TrackPoint.Latitude.Text);
	ptr = StringCopyEnd(ptr, FW_PARAM_TIME);
	ptr = StringCopyEnd(ptr, GPS_TrackPoint.Time);
	ptr = StringCopyEnd(ptr, FW_PARAM_DATE);
	ptr = StringCopyEnd(ptr, GPS_TrackPoint.Date);
	ptr = StringCopyEnd(ptr, FW_PARAM_SPEED);
	ptr = StringCopyEnd(ptr, GPS_TrackPoint.Speed);
	ptr = StringCopyEnd(ptr, FW_PARAM_HEADING);
	ptr = StringCopyEnd(ptr, GPS_TrackPoint.Course);
	ptr = StringCopyEnd(ptr, FW_PARAM_VALID);
	ptr = StringCopyEnd(ptr, GPS_TrackPoint.Valid);
	ptr = StringCopyEnd(ptr, FW_PARAM_IMEI);
	ptr = StringCopyEnd(ptr, G200.IMEI);
	ptr = StringCopyEnd(ptr, FW_PARAM_ACC);
	ptr = PrintNumberEnd(ptr, A_Max);
	ptr = StringCopyEnd(ptr, ",");
	ptr = PrintNumberEnd(ptr, AX_Max);
	ptr = StringCopyEnd(ptr, ",");
	ptr = PrintNumberEnd(ptr, AY_Max);
	ptr = StringCopyEnd(ptr, ",");
	ptr = PrintNumberEnd(ptr, AZ_Max);
	ptr = StringCopyEnd(ptr, FW_PARAM_VERSION);
	ptr = StringCopyEnd(ptr, DEVICE_VERSION);
	ptr = StringCopyEnd(ptr, FW_HTTP_GET_END);

	A_Max = AX_Max = AY_Max = AZ_Max = 0;

	return G200.Command;
}

void ErrorBlink(uint8 major, uint8 minor)
{
    if(IsHostConnect())
    {
        SerialUSB.print("Error:");
        SerialUSB.print(major, DEC);
        SerialUSB.print(":");        
        SerialUSB.println(minor, DEC);
    }
    delay(2000);
    BlinkLED(major);
    BlinkLED(minor);
    delay(1000);
}

void BlinkLED(uint8 blinks)
{
    while (blinks > 0)
    {
        --blinks;
		LED_ON();
        delay(500);
        LED_OFF();
        delay(500);
    }
    delay(1000);
}

void PrintErrorName(const char *msg, E_RESPONSE error)
{
	SerialUSB.write(msg);
	switch(error)
	{
	case RESPONSE_OK:
		SerialUSB.write("OK");
		break;
	case RESPONSE_ERROR:
		SerialUSB.write("ERROR");
		break;
	case RESPONSE_CME_ERROR:
		SerialUSB.write("ERR CME");
		break;
	case RESPONSE_CMS_ERROR:
		SerialUSB.write("ERR CMS");
		break;
	case RESPONSE_TOO_LONG:
		SerialUSB.write("TOO LONG");
		break;
	case RESPONSE_TIMEOUT:
		SerialUSB.write("TIMEOUT");
		break;
	case RESPONSE_GSM_OFF:
		SerialUSB.write("GSM OFF");
		break;
	case RESPONSE_GSM_NOREG:
		SerialUSB.write("NO REG");
		break;
	case RESPONSE_GSM_DENIED:
		SerialUSB.write("DENIED");
		break;
	case RESPONSE_GSM_NO_IMEI:
		SerialUSB.write("NO IMEI");
		break;
	case RESPONSE_GSM_NO_SIM:
		SerialUSB.write("NO SIM");
		break;
	case RESPONSE_GSM_NO_PIN:
		SerialUSB.write("NO PIN");
		break;
	case RESPONSE_GSM_BAD_PIN:
		SerialUSB.write("BAD PIN");
		break;
	case RESPONSE_GPS_OFF:
		SerialUSB.write("GPS OFF");
		break;
	case RESPONSE_WAITFOR:
		SerialUSB.write("WAIT FOR");
		break;
	case RESPONSE_SMS_REJECT:
		SerialUSB.write("SMS REJECT");
		break;
	case E_RESPONSE_BAD_FORMAT:
		SerialUSB.write("BAD FORMAT");
		break;
	case E_RESPONSE_EMPTY_POSITION:
		SerialUSB.write("EMPTY POS");
		break;
	default:
		SerialUSB.print((uint8)error, HEX);
		break;
	}
	SerialUSB.println();
}

void InitializeMMA7455(void)
{
	if (MMA7455.Mode == MMA7455_INITIAL)
	{
		switch(MMA7455.begin())
		{
		case MMA7455_NOT_FOUND:
			DebugMsgln("Accelerometer not found");
			ErrorBlink(GENERAL_ERROR, ACC_NOT_FOUND);
			break;
		case MMA7455_INIT_ERROR:
			DebugMsgln("Accelerometer initialize error");
			ErrorBlink(GENERAL_ERROR, ACC_INIT_ERROR);
			MMA7455.Mode = MMA7455_INITIAL;			// Try initialize later
			break;
		case MMA7455_OK:
			for(uint8 retry = 10; retry > 0; --retry)
				if (MMA7455.readXYZ() == SI2C_SUCCESS)
				{
					DebugMsgln("Accelerometer initialized");
					AX_Last = MMA7455.X;
					AX_Last = MMA7455.Y;
					AX_Last = MMA7455.Z;
					A_Max = AX_Max = AY_Max = AZ_Max = 0;
					break;
				}
				delay(10);
			break;
		default:
			DebugMsg("Accelerometer unknown mode : ");
			DebugHex(MMA7455.Mode);
			DebugMsgln("");
			ErrorBlink(GENERAL_ERROR, ACC_UNKNOWN_ERROR);
			MMA7455.Mode = MMA7455_INITIAL;			// Try initialize later
			break;
		}
	}
}


void MemManageException(void)
{
	ErrorBlink(GENERAL_ERROR, GENERAL_FAILURE);
	SystemRestart();

}
void HardFaultException(void)
{
	ErrorBlink(GENERAL_ERROR, GENERAL_FAILURE);
	SystemRestart();
}
void BusFaultException(void)
{
	ErrorBlink(GENERAL_ERROR, GENERAL_FAILURE);
	SystemRestart();
}
void UsageFaultException(void)
{
}

1 comment(s) so far

  1. Device can work on GPRS

Post your comment

Thanks for your comments

  • Comment

Github
Bitbucket
Codeplex
SF.net
Resume

Subscribe to x893 blog Subscribe to x893 blog