Package: gpsbabel
Version: 1.2.5+1.2.6-beta20050608-1
Severity: wishlist

The Alan Map 500 is a relatively cheap mapping GPS unit that uses CF
cards as storage extension. The manufacturers, Alan Electronics, are
very open towards open source software. They have made the documentation
for ther data structures freely available as downloadble PDFs
(<http://www.hobbyradio.de/GPS/Map500/Software/file-descriptions/>), and
someone has written a proof-of-concept program to transfer data via the
serial port and the RS-232 data cable (the code is put under the GPL and
is attached to this report).

Is it possible to add the Alan Map 500 and it's file formats to the list
of the supported units?

Greetings from Münster,

=ToJe=

-- System Information:
Debian Release: testing/unstable
  APT prefers unstable
  APT policy: (990, 'unstable'), (500, 'stable')
Architecture: i386 (i586)
Shell:  /bin/sh linked to /bin/bash
Kernel: Linux 2.4.29
Locale: [EMAIL PROTECTED], [EMAIL PROTECTED] (charmap=ISO-8859-15)

Versions of packages gpsbabel depends on:
ii  libc6                       2.3.5-6      GNU C Library: Shared libraries an
ii  libexpat1                   1.95.8-3     XML parsing C library - runtime li
ii  libusb-0.1-4                2:0.1.10a-21 userspace USB programming library

gpsbabel recommends no packages.

-- no debconf information
/*
   map500 - Interaction with Alan Map500 Device

   Copyright (C) 2004-2005 Christian Cyrus <[EMAIL PROTECTED]>

   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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

   Versionhistory:
   
   v0.1 - 20.02.2004
     - Initial Release
     - Allows Up- and Download of Font, Map, Tracklog and Waypoint & Route

   v0.2 - 01.05.2005
     - Download of Firmware implemented (-p) use with care 

   TODO:
     - Support for Bigendian
*/
   
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/select.h>

#include <sys/time.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
#include <string.h>
#include <getopt.h>

#define ERROR_NO(x) fprintf(stderr, "%s: %d: %s - %s\n", __FILE__, __LINE__, strerror(errno), (x))
#define ERROR(x) fprintf(stderr, "%s: %d: %s\n", __FILE__, __LINE__, (x))

#ifndef cfmakeraw
#define cfmakeraw(x) \
    (x)->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); \
    (x)->c_oflag &= ~OPOST; \
    (x)->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); \
    (x)->c_cflag &= ~(CSIZE|PARENB); \
    (x)->c_cflag |= CS8;
#endif

int readbuffer(int device, unsigned char *buffer, int buffersize)
{
    int count = 0;
    int retval;
    do {
	fd_set rdfs;
	struct timeval tv;
	FD_ZERO(&rdfs);
	FD_SET(device, &rdfs);
	tv.tv_sec = 20;
	tv.tv_usec = 0;

	retval = select(device + 1, &rdfs, NULL, NULL, &tv);
	if (retval < 0) {
	    ERROR_NO("readbuffer - select()");
	} else if (FD_ISSET(device, &rdfs)) {
	    int get = read(device, &(buffer[count]), buffersize - count);
	    count += get;
	} else {
	    retval = 0;
	}
    } while ((retval > 0) && (count < buffersize));

    return (retval > 0) ? count : retval;
}


int command(int device, const char *command, int length)
{
    unsigned char buffer[1];
    int retval;
    write(device, command, length);
    retval = readbuffer(device, buffer, 1);
    if (retval != 1) {
	ERROR("device is not responding");
	exit(1);
    } else {
	switch (buffer[0]) {
	case '!':
	    retval = 1;
	    break;
	case '?':
	    retval = 0;
	    break;
	default:
	    {
		char stringbuffer[1024];
		sprintf(stringbuffer,
			"unknown response (0x%x) on (%.4s)request",
			buffer[0], command);
		ERROR(stringbuffer);
		exit(1);
	    }
	}
    }

    return retval;
}

unsigned long checksum(const unsigned char *buffer, int length)
{
    int i;
    unsigned long retval = 0;
    for (i = 0; i < length; i++) {
	retval += buffer[i];
    }
    return retval & 0x7f;
}

void usage()
{
    fprintf(stderr, "usage: map500 -[u|d] -[f|m|p|t|w] <device> <file>\n\n");
    fprintf(stderr, "       -u\tretrieve data to <file>\n");
    fprintf(stderr, "       -d\tsend data to <device>\n");
    fprintf(stderr, "\n");
    fprintf(stderr, "       -f\tfont is to be processed (-d only)\n");
    fprintf(stderr, "       -m\tmap is to be processed (-d only)\n");
    fprintf(stderr, "       -p\tprogram is to be processed (-d only)\n");
    fprintf(stderr, "       -t\ttracklog is to be processed\n");
    fprintf(stderr, "       -w\twaypoint & route is to be processed\n");
    exit(1);
}

enum { NONE, UPLOAD, DOWNLOAD,
    FONT, MAP, PROGRAM, TRACK, ROUTE
};

int main(int argc, char **argv)
{
    int method = NONE;
    int type = NONE;
    char *methodcmd, *typecmd;
    struct termios tio;
    int device;
    int ch;

    while ((ch = getopt(argc, argv, "udfmptw")) != -1) {
	switch (ch) {
	case 'u':
	    if (method != NONE)
		usage();
	    method = UPLOAD;
	    methodcmd = "$STA";
	    break;
	case 'd':
	    if (method != NONE)
		usage();
	    method = DOWNLOAD;
	    methodcmd = "$BEG";
	    break;
	case 'f':
	    if (method != DOWNLOAD)
		usage();
	    if (type != NONE)
		usage();
	    type = FONT;
	    typecmd = "$FNT";
	    break;
	case 'm':
	    if (method != DOWNLOAD)
		usage();
	    if (type != NONE)
		usage();
	    type = MAP;
	    typecmd = "$MAP";
	    break;
	case 'p':
	    if (method != DOWNLOAD)
		usage();
	    if (type != NONE)
		usage();
	    type = PROGRAM;
	    typecmd = "$MAP";
	    break;
	case 't':
	    if ((method != DOWNLOAD) && (method != UPLOAD))
		usage();
	    if (type != NONE)
		usage();
	    type = TRACK;
	    typecmd = "$TLG";
	    break;
	case 'w':
	    if ((method != DOWNLOAD) && (method != UPLOAD))
		usage();
	    if (type != NONE)
		usage();
	    type = ROUTE;
	    typecmd = "$WRT";
	    break;
	default:
	    usage();
	}
    }
    argc -= optind;
    argv += optind;

    if (argc != 2)
	usage();

    device = open(argv[0], O_RDWR | O_SYNC);
    if (device < 0) {
	ERROR_NO("open");
	exit(1);
    }

    if (tcgetattr(device, &tio) < 0) {
	ERROR_NO("tcgetattr");
	exit(1);
    }

    cfmakeraw(&tio);
    tio.c_cc[VMIN] = 1;
    cfsetispeed(&tio, B38400);
    cfsetospeed(&tio, B38400);

    if (tcsetattr(device, TCSANOW, &tio) < 0) {
	ERROR_NO("tcsetattr");
	exit(1);
    }


    if (command(device, methodcmd, 4)) {
	if (method == UPLOAD) {
	    FILE *file = fopen(argv[1], "w");
	    if (!file) {
		ERROR_NO("fopen()");
	    } else {
		if (command(device, typecmd, 4)) {
		    unsigned char buffer[516];
		    unsigned long count;
		    readbuffer(device, buffer, 4);
		    count = *(uint32_t *) buffer;
		    
		    while (count) {
			printf("%lu chunks left \r", count);
			fflush(stdout);
			readbuffer(device, buffer, 516);
			if (checksum(buffer, 512) == buffer[514]) {
			    fwrite(buffer, 1, 512, file);
			    count--;
			    command(device, "!", 1);
			} else {
			    printf
				("checksum failure (%#lx) != (%#x), retrying\n",
				 checksum(buffer, 512), buffer[514]);
			    command(device, "?", 1);
			}
		    }
		    printf("Upload %s successfull                 \n",
			   (type ==
			    TRACK) ? "Tracklog" : "Waypoint & Route");

		} else {
		    printf("%s could not be found\n",
			   (type ==
			    TRACK) ? "Tracklog" : "Waypoint & Route");
		}
		fclose(file);
	    }
	} else {		/* Download */
	    FILE *file = fopen(argv[1], "r");
	    if (!file) {
		ERROR_NO("fopen()");
	    } else {
		struct stat fs;
		if (stat(argv[1], &fs) < 0) {
		    ERROR_NO("fstat()");
		} else {
		    unsigned long count = (fs.st_size + 511) / 512;
		    unsigned char buffer[516];
		    sprintf((char *) buffer, "%s", typecmd);
		    *(uint32_t *) &(buffer[4]) = count;

		    if (command(device, (char *) buffer, 8)) {
			while (count) {
			    printf("%lu chunks left \r", count);
			    fflush(stdout);
			    memset(buffer, 0xff, 512);
			    memset(buffer + 512, 0, 4);
			    fread(buffer, 1, 512, file);
			    buffer[515] = checksum(buffer, 512);
			    write(device, buffer, 516);
			    if (type == PROGRAM) {
			        readbuffer(device, buffer, 1);
			    } else {
			        readbuffer(device, buffer, 2);
			    }
			    if (buffer[0] == '!') {
				count--;
			    } else {
				printf("checksum failure, retrying\n");
				fseek(file, -512, SEEK_CUR);
				if (type != PROGRAM) {
				    if (buffer[1] != '!') {
				        ERROR
				           ("aborting upload something bad happend");
				        exit(1);
				    }
				}
			    }
			}
			sleep(1);
			printf
			    ("Download %s successfull                 \n",
			     (type == FONT) ? "Font" :
			     ((type == MAP) ? "Map" :
			      ((type == PROGRAM) ? "Program" :
			       ((type == TRACK) ? "Tracklog" :
			        "Waypoint & Route"))));

		    } else {
			printf("%s could not be found\n",
			       (type == FONT) ? "Font" :
			       ((type == MAP) ? "Map" :
				((type == TRACK) ? "Tracklog" :
				 ((type == PROGRAM) ? "Program" :
				  "Waypoint & Route"))));
		    }
		}
		fclose(file);
	    }

	}
    } else {
	printf("%s could not be initialized\n",
	       (method == UPLOAD) ? "Upload" : "Download");
    }

    command(device, "$END", 4);

    close(device);

    return 0;
}

Reply via email to