[comp.sys.mac.programmer] Gettint the current Map location -- here's how

minow@thundr.dec.com (Martin Minow THUNDR::MINOW ML3-5/U26 223-9922) (08/30/88)

Several months ago, I asked the collected wisdom of the net (also several
other people) for information on extracting the Map latitude and longitude
for use in an astronomy program I was messing around with.  (Map is a Cdev
in the 6.0 system release.)  With the significant assistance of Mike Carleton,
here is a simple program that extracts and formats the information.
(If you need the city name, you'll have to poke around in the Map database
yourself -- I can't help you there.)

The program should be reasonably easy to follow.  It is, of course, not
guaranteed to work in future systems, is not blessed by Apple, and does
not express the position of my employer.  It is in the public domain.

Martin Minow
minow%thundr.dec@decwrl.dec.com
...!decwrldec-rhea!dec-thundr!minow

-----
#include	<stdio.h>
#include	<math.h>
#include	<pascal.h>

#define _ReadXPRam 0xA051
#define _WriteXPRam 0xA052

/*
 * This structure defines the location currently set by the Map Cdev.
 *
 *	Latitude and longitude are signed long integers giving the
 *	fraction of the circle.  I.e.,
 *		1 degree East == 0x000308B9
 *		1 degree West == 0xFFFCF747
 *	All values are possible for longitude, while latitude is constrained
 *	to +/- 90 degrees.
 *
 *	Only the low-order three bytes of timezone are used.  The value is
 *	the number of seconds East of UTC.
 */

typedef struct {
    long	latitude;	/* fractional latitude	(North +)	*/
    long	longitude;	/* fractional longitude	(East  +)	*/
    long	timezone;	/* high byte zero, seconds in low 3	*/
} MapDatum;
	
typedef	struct {
	Byte		valid;
	Byte		aTalkA;
	Byte		aTalkB;
	Byte		config;
	int		portA;
	int		portB;
	long		alarm;
	int		font;
	int		kbdPrint;
	int		volClik;
	int		misc;
	Byte		fill[76];		/* 0x14 */
	char		name[20];		/* 0x60 */
	Byte		fill2[112];		/* 0x74 */
	MapDatum	map;			/* 0xE4 */
	Byte		XPram[16];		/* 0xF0	*/
} XParmType;
	
XParmType		Rbuff;	

int	WpRam(struct pRAM *, int, int);
	
int
WpRam(add, st, cnt)
struct pRAM	*add;		/* Address of buffer			*/
int		st;		/* Starting address in PRam		*/
int		cnt;		/* Count of bytes to write		*/
{
	asm {
		move.w	cnt,D0		/* Put count of bytes in DO.	*/
		swap	D0		/* Move it to the high word.	*/ 
		move.w 	st,D0		/* Start at this Pram address.	*/
		movea.l	add,A0		/* Pointer to the data buffer.	*/
		dc.w	_WriteXPRam	/* Trap to ROM			*/
		return			/* OK = 0, error = -87		*/
	}
}

int	RpRam(struct pRAM *, int, int);

int
RpRam(add, st, cnt)
struct pRAM	*add;		/* Address of buffer			*/
int		st;		/* Starting address in PRam		*/
int		cnt;		/* Count of bytes to write		*/
{
	asm {
		move.w	cnt,D0		/* Put count of bytes in DO.	*/
		swap	D0		/* Move it to the high word.	*/ 
		move.w 	st,D0		/* Start at this Pram address.	*/
		movea.l	add,A0		/* Pointer to the data buffer.	*/
		dc.w	_ReadXPRam	/* Trap to ROM			*/
		return			/* OK = 0, error = -87		*/
	}
}

void		main(void);
void		printf(char *, ...);
void		fputc(int, FILE *);
int		fgetc(FILE *);

void		print_map(MapDatum *);

void
main()
{
	int					status;
	XParmType			*sys;
					
	/*
	 * Rbuff.valid is never valid on my system! -- it's only
	 * valid in the GetSysPPtr buffer, but I can't find the
	 * map info in that buffer.
	 */
	do {
		status = RpRam((struct pRAM *) &Rbuff, 0, sizeof(XParmType));
		sys = (XParmType *) GetSysPPtr();
		print_map(&Rbuff.map);
	} while (getchar() != 'q');
}

void		dms(long, char *, char *);
void		hms(long, char *);

void
print_map(map)
register MapDatum		*map;
{
	dms(map->longitude, "Longitude", "EW");
	dms(map->latitude,	"Latitude",  "NS");
	hms(map->timezone,	"Zone");
}

void
dms(raw_value, what, zone)
long		raw_value;
char		*what;
char		*zone;
{
	register long	value;
	register long	degree, minute, second;
	int		west;
		
	static long	one_degree = (0x80000000 / 180L);
	static long	one_minute = (0x80000000 / (180L * 60L));
	static long	one_second = (0x80000000 / (180L * 60L * 60L));

	value = raw_value;
	degree = value / one_degree;
	value -= (degree * one_degree);
	minute = value / one_minute;
	value -= (minute * one_minute);
	second = value / one_second;
	if ((west = (raw_value < 0))) {
		degree = (-degree);
		minute = (-minute);
		second = (-second);
	}	
	printf("(%08lx): %3ld.%02ld.%02ld %c %s\n",
		raw_value, degree, minute, second, zone[west], what);
}


void
hms(timezone, what)
long			timezone;
char			*what;
{
	register long	value;
	register long	hour, minute, second;
	int		west;
		
	static long	one_hour	= (60L * 60L);
	static long	one_minute	= (60L);

	if (timezone & 0xFF000000) {
		printf("High byte set in timezone: %02x\n",
			(timezone >> 12) & 0xFF);
		timezone &= 0x00FFFFFF;
	}
	if ((timezone & 0x00800000) != 0)
		timezone |= 0xFF000000;		/* Sign-extend zone	*/
	value	 = timezone;
	hour	 = value / one_hour;
	value 	-= (hour * one_hour);
	minute	 = value / one_minute;
	value	-= (minute * one_minute);
	second	 = value;
	if ((west = (timezone < 0))) {
		hour = (-hour);
		minute = (-minute);
		second = (-second);
	} 	
	printf("(%08lx): %3ld.%02ld.%02ld %c %s\n",
		timezone, hour, minute, seconds, "EW"[west], what);
}

---- end ----