From: Stuart Cheshire <cheshire@cs.stanford.edu>
Subject: Re: Looking for some sample appletalk ATP code...
X-Xxmessage-Id: <A6CA4EBFCC020010@bolo.stanford.edu>
X-Xxdate: Wed, 2 Sep 92 18:58:07 GMT
Organization: Stanford University
X-Useragent: Nuntius v1.1.1d7
Date: Wed, 2 Sep 92 17:58:33 GMT

In article <1992Sep1.033635.28604@sunb10.cs.uiuc.edu> Alex Bratton,
bratton@sparc3.cs.uiuc.edu writes:
>If you have some sample code (ATP) that opens, registers, and dumps some
>data, I'd really appreciate seeing it.  This has been bugging me for a
while
>and I think I need to look at some working code to see what I'm missing.

Here is some sample code which includes ATP calls. It is the code I use
to obtain the list of AppleTalk zones to display in my game Bolo, and
judging by the time it took to get all the wrinkles worked out, and make
it run with both Phase 1 and Phase 2, it probably should be in some
sample code library somewhere for other people's use.

The ATP calls are in the Phase 1 part, which has to communicate directly
with the bridge via ATP.

The code gets the list of zones, sorts them into alphabetical order using
heap sort, and then appends them in order to the list identified by the
parameter "zonelist", which should be initialized before calling
getzonelist.

The code is written for Think C 5.

#include <AppleTalk.h>

#define local static
#define export
#define import extern

typedef struct
	{
	BYTE sysLAPAddr;
	BYTE destnode;
	BYTE srcnode;
	BYTE ALAPproto;
	WORD length;
	union
		{
		struct
			{
			BYTE destsocket;
			BYTE srcsocket;
			BYTE DPPproto;
			BYTE userdata[15];
			} shortheader;
		struct
			{
			WORD checksum;
			WORD destnet;
			WORD srcnet;
			BYTE destnode;
			BYTE srcnode;
			BYTE destsocket;
			BYTE srcsocket;
			BYTE DPPproto;
			BYTE userdata[7];
			} longheader;
		} u;
	BYTE unused;
	BYTE sysABridge;
	WORD sysNetNum;
	WORD vSCCEnable;
	} MPPglobals;

extern MPPglobals *ABusVars : 0x2D8;

#define		atpMaxData				578			// size of buffer for zone names
#define		kZIPSocket				6			// the Zone Information Protocol socket
#define		kATPTimeOutVal			3			// re-try ATP SendRequest every 3 seconds
#define		kATPRetryCount			5			// for five times
#define		kGZLCall				0x08000000	// GetZoneList indicator
#define		kGMZCall				0x07000000	// GetMyZone indicator
#define		kZoneCount				0x0000FFFF 	// mask to count zones in buffer
#define		kNoMoreZones			0xFF000000 	// mask to see if more zones to come

#define xCall               246
#define zipGetLocalZones    5
#define zipGetZoneList      6
#define zipGetMyZone        7

typedef struct
    {
    QElemPtr         qLink;
    short            qType;
    short            ioTrap;
    Ptr              ioCmdAddr;
    ProcPtr          ioCompletion;
    OSErr            ioResult;
    StringPtr        ioNamePtr;
    short            ioVRefNum;
    short            ioRefNum;
    short            csCode;
    short            xppSubCode;
    unsigned char    xppTimeOut;
    unsigned char    xppRetry;
    short            filler;
    Ptr              zipBuffPtr;
    short            zipNumZones;
    short            zipLastFlag;
    short            zipInfoField[35];
	} xCallParam;

#define MAX_ZONES 1000
typedef struct { unsigned char c[34]; } ZONE_NAME;
ZONE_NAME *zone_array, **zone_heap;
local int num_zones;

local void addtoheap(int place, ZONE_NAME *new)
	{
	int parent = (place-1)>>1;
	zone_heap[place]=new;
	while (place>0 && IUCompString(zone_heap[parent]->c,
zone_heap[place]->c)>0)
		{
		ZONE_NAME *temp   = zone_heap[place ];
		zone_heap[place ] = zone_heap[parent];
		zone_heap[parent] = temp;
		place=parent;
		parent=(place-1)>>1;
		}
	}

local ZONE_NAME *removefromheap(int last)	// last is index of last item
on heap
	{
	ZONE_NAME *top = zone_heap[0];			// extract top element
	int gap   = 0;							// top is now empty
	int left  = 1;
	int right = 2;
	while(left<=last)						// move gap to bottom
		{
		if(right>last || IUCompString(zone_heap[right]->c,
zone_heap[left]->c)>0)
			{ zone_heap[gap]=zone_heap[left ]; gap=left;  }
		else{ zone_heap[gap]=zone_heap[right]; gap=right; }
		left  = (gap<<1)+1;
		right = left + 1;
		}
	if(last != gap) addtoheap(gap, zone_heap[last]);	// fill gap
	return(top);	// and heap is now one element smaller
	}

local void BuildZoneListPhase1(unsigned char *myzone)
	{
	ATPParamBlock	pb;
	BDSElement		dBDS;
	unsigned char	datapacket[atpMaxData];
	short			zIndex=1, zCount=0, i;

	dBDS.buffSize    = atpMaxData;
	dBDS.buffPtr     = (Ptr)datapacket;

	pb.ATPatpFlags   = 0;
	pb.ATPreqLength  = 0;
	pb.ATPreqPointer = NULL;
	pb.ATPbdsPointer = (Ptr) &dBDS;
	pb.ATPnumOfBuffs = 1;
	pb.ATPtimeOutVal = kATPTimeOutVal;
	pb.ATPretryCount = kATPRetryCount;

	pb.ATPaddrBlock.aNet    = ABusVars->sysNetNum;
	pb.ATPaddrBlock.aNode   = GetBridgeAddress();
	pb.ATPaddrBlock.aSocket = kZIPSocket;

	if (!pb.ATPaddrBlock.aNode) return;		// no bridge -- no zones

	do	{
		unsigned char *ptr = datapacket;
		pb.ATPuserData = kGZLCall + zIndex;
		PSendRequest(&pb, false);
		zCount += dBDS.userBytes & kZoneCount;
		while(zIndex++ <= zCount)
			{
			int count = 1 + *ptr;
			unsigned char *dest = zone_array[num_zones].c;
			while (count-- > 0) *dest++ = *ptr++;
			addtoheap(num_zones, &zone_array[num_zones]);
			num_zones++;
			}
		} until(dBDS.userBytes & kNoMoreZones);
	
	pb.ATPuserData = kGMZCall;
	datapacket[0] = 0;
	if (PSendRequest(&pb, false) == noErr && datapacket[0] &&
datapacket[0]<32)
		for (i=0; i<=datapacket[0]; i++) myzone[i] = datapacket[i];
	}

local void BuildZoneListPhase2(unsigned char *myzone)
	{
	short XPPRefNum;
	xCallParam		xpb;
	unsigned char	datapacket[atpMaxData];
	short			zIndex=1, zCount=0;
	
	if (OpenDriver("\p.XPP", &XPPRefNum)) return;

	xpb.zipInfoField[0] = 0;
	xpb.zipLastFlag = FALSE;
	xpb.ioRefNum    = XPPRefNum;
	xpb.csCode      = xCall;
	xpb.xppSubCode  = zipGetZoneList;
	xpb.xppTimeOut  = kATPTimeOutVal;
	xpb.xppRetry    = kATPRetryCount;
	xpb.zipBuffPtr  = (Ptr)datapacket;

	while (!xpb.zipLastFlag && !PBControl((ParmBlkPtr)&xpb, FALSE))
		{
		unsigned char *ptr = datapacket;
		zCount += xpb.zipNumZones;
		while(zIndex++ <= zCount)
			{
			int count = 1 + *ptr;
			unsigned char *dest = zone_array[num_zones].c;
			while (count-- > 0) *dest++ = *ptr++;
			addtoheap(num_zones, &zone_array[num_zones]);
			num_zones++;
			}
		}

	xpb.zipInfoField[0] = 0;
	xpb.xppSubCode  = zipGetMyZone;
	xpb.zipBuffPtr  = (Ptr)myzone;
	PBControl((ParmBlkPtr)&xpb, FALSE);
	// Mustn't close XPP driver (see IM V 532)
	}

local short addrow(ListHandle list, unsigned char *newdata)
	{
	Point pt = { 0, 0 };
	pt.v = (*list)->dataBounds.bottom;
	LAddRow(1, pt.v, list);
	LSetCell(newdata+1, newdata[0], pt, list);
	return(pt.v);
	}

export int getzonelist(ListHandle zonelist)
	{
	unsigned char myzone[33];
	Point pt = { 0, 0 };
	SysEnvRec sysenvirons;
	SysEnvirons(1, &sysenvirons);
	zone_array = (ZONE_NAME  *) NewPtr(MAX_ZONES * sizeof(ZONE_NAME  ));
	zone_heap  = (ZONE_NAME **) NewPtr(MAX_ZONES * sizeof(ZONE_NAME *));
	myzone[0] = num_zones = 0;
	if (sysenvirons.atDrvrVersNum < 53) BuildZoneListPhase1(myzone);
	else                                BuildZoneListPhase2(myzone);
	
	while (num_zones-->0) addrow(zonelist, removefromheap(num_zones)->c);
	DisposPtr((Ptr)zone_array);
	DisposPtr((Ptr)zone_heap);

	LSearch(myzone+1, *myzone, NULL, &pt, zonelist);
	LSetSelect(TRUE, pt, zonelist);
	LAutoScroll(zonelist);
	return(pt.v);
	}


Stuart Cheshire <cheshire@cs.stanford.edu>
 * Liliore Green Rains Houses Resident Computer Coordinator
 * Stanford Distributed Systems Group Research Assistant
 * Macintosh Programmer
Newsgroups: comp.sys.mac.programmer