/* 
 * gpsdump 0.1 for Motorola A780
 *
 * init code reverse engineered by mack
 * protocol re'd by floe <floe@butterbrot.org>
 *
 * (c) 2006 by mack and floe
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

#define LAPI_MSG_INIT  "Z\1\0\0d\0\4\0\1\0\0\0"
#define LAPI_MSG_OPEN  "Z\1\0\0f\0\4\0" /* + 4 bytes globalId */
#define LAPI_MSG_START "Z\1\0\0j\0 \0\0\0\0\0\2\0\0\0\226\0\0\0\226\0\0\0\210\23\0\0\1\0\0\0\1\0\0\0\1\0\0\0"
#define LAPI_MSG_STOP  "Z\1\0\0l\0\0\0"
#define LAPI_MSG_CLOSE "Z\1\0\0h\0\0\0"

typedef struct {
	unsigned char padding[6]; // necessary due to the fucking 8 byte double alignment of ARM architecture
	unsigned int pid;	
	unsigned short msgid;
	unsigned short msglen;
	unsigned char sessid;
	unsigned char transid;
	double longitude;
	double latitude;
	double accuracy;
	unsigned long long int timestamp; // milliseconds since the epoch (1 Jan 1970 00:00:00) (in UTC)
	double altitude;
	double speed;
	double heading;
	double bearing;                   // always -256.0
	double horizontal_accuracy;       // always equal to accuracy
	double vertical_accuracy;
	double course;                    // always equal to heading
	int locmethod;
	int cause;
	unsigned long long int ageoffix;  // also a millisecond counter
} lapi_gps_rec;


int run = 1;

void error(char *msg) { perror(msg); exit(1); }
void quitsignal() { run = 0; }


int main(int argc, char *argv[]) {

	int ctrlsock, datasock, servlen, n;
	struct sockaddr_un serv_addr;
	unsigned char buffer[256];
	lapi_gps_rec* record = (lapi_gps_rec*)&buffer;

	signal( SIGHUP,  quitsignal );
	signal( SIGINT,  quitsignal );
	signal( SIGQUIT, quitsignal );
	signal( SIGTERM, quitsignal );

	fprintf( stderr, "Motorola A780 GPS dump\n(c) 2006 by Floe <floe@butterbrot.org>\n" );

	bzero( (char*)&serv_addr, sizeof(serv_addr) );
	serv_addr.sun_family = AF_UNIX;
	strcpy( serv_addr.sun_path, "/tmp/lapisock" );
	servlen = strlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family);

	if ((ctrlsock = socket( AF_UNIX, SOCK_STREAM, 0 )) < 0) error("Creating control socket");
	if ((datasock = socket( AF_UNIX, SOCK_STREAM, 0 )) < 0) error("Creating data socket");
	
	if (connect( ctrlsock, (struct sockaddr*)&serv_addr, servlen ) < 0) error("Connecting control socket");
	if (connect( datasock, (struct sockaddr*)&serv_addr, servlen ) < 0) error("Connecting data socket");

	fprintf( stderr, "Opening LAPI.." ); fflush(0);

	write( ctrlsock, LAPI_MSG_INIT, sizeof(LAPI_MSG_INIT)-1 );
	read( ctrlsock, buffer, sizeof(buffer) );

	memcpy( buffer, LAPI_MSG_OPEN, sizeof(LAPI_MSG_OPEN)-1 );

	write( datasock, buffer, sizeof(LAPI_MSG_OPEN)-1+4 );
	read( datasock, buffer, sizeof(buffer) );

	write( ctrlsock, LAPI_MSG_START, sizeof(LAPI_MSG_START)-1 );

	fprintf( stderr, "done.\n" );

	while (run) {		

			// the 6 bytes offset is necessary to compensate the compiler's additional padding
		  n = read( datasock, buffer+6, sizeof(buffer)-6 );

			printf( "lat: %f\nlon: %f\n", record->latitude, record->longitude );
			printf( "accuracy: %f\n", record->accuracy );
			printf( "timestamp: %llu\n", record->timestamp );
			printf( "altitude: %f\n", record->altitude );
			printf( "speed: %f\n", record->speed );
			printf( "traveldir: %f\n", record->heading );
			printf( "pointing: %f\n", record->bearing );
			printf( "horacc: %f\n", record->horizontal_accuracy );
			printf( "veracc: %f\n", record->vertical_accuracy );
			printf( "course: %f\n", record->course );
			printf( "ageoffix: %llu\n", record->ageoffix );

	}

	fprintf( stderr, "Releasing LAPI.." ); fflush( 0 );

	write( ctrlsock, LAPI_MSG_STOP, sizeof(LAPI_MSG_STOP)-1 );
	//read( ctrlsock, buffer, sizeof(buffer) );

	write( ctrlsock, LAPI_MSG_CLOSE, sizeof(LAPI_MSG_CLOSE)-1 );
	read( ctrlsock, buffer, sizeof(buffer) );

	fprintf( stderr, "done.\n" );

	return 0;
}


