// Text of project LlamaTalk written on 11/22/95 at 8:07 PM
// Beginning of text file Project Data
/*
**      Newton Developer Technical Support Sample Code
**
**      LlamaTalk, The safest way to use ADSP on the 1.x Newton OS
**      Now for use with Newton OS 2.x
**
**      by Jim Schram, Newton Developer Technical Support
**
**      Copyright © 1994-1995 by Apple Computer, Inc.  All rights reserved.
**
**      You may incorporate this sample code into your applications without
**      restriction.  This sample code has been provided "AS IS" and the
**      responsibility for its operation is 100% yours.  You are not
**      permitted to modify and redistribute the source as "DTS Sample Code."
**      If you are going to re-distribute the source, we require that you
**      make it clear in the source that the code was descended from
**      Apple-provided sample code, but that you've made changes.
*/

constant kMaxAppWidth := 240;		// original MP width
constant kMaxAppHeight := 336;		// original MP height
// End of text file Project Data
// Beginning of file protoLlamaTalk

// Before Script for "LlamaTalk"
/*
	protoLlamaTalk
	
	This layout file is copyright © 1994-1995 Apple Computer, Inc. All rights reserved.
	
	Modification Status
	YY/MM/DD	Name				Comments
	95/09/12	Jim Schram		Released as 2.0a1 - Now uses protoBasicEndpoint in Newton OS 2.0
	95/05/09	Jim Schram		Released as 1.0a8 - Modifications to support NTK 1.5
	94/09/22	Jim Schram		Released as 1.0a7 - removed power-off patch code (install "MP110 Power Off Update.pkg" instead)
	94/07/07	Jim Schram		Released as 1.0a6 - modified to use kViewIsOpenFunc & kLlamaTalkStuffCStringFunc
	94/06/21	Jim Schram		Released as 1.0a5 - added improved CloseAppleTalk support
	94/06/10	Jim Schram		Released as 1.0a4 - added dynamic GotoSleep patch code
	94/05/13	Jim Schram		Released as 1.0a3 - added support for typed transaction data
	94/05/04	Jim Schram		Released as 1.0a1
	94/03/17	Jim Schram		Initial Development
	---------------------------------------------------------------------
	The LlamaTalk packet format is as follows:
	1 byte packet type
	3 bytes packet length (MSB -> LSB order)
	N bytes packet data
	
	Currently only packet type cLTPacketType_Simple (zero) is implemented.
	Future packet types will include features such as compression and encryption.
	All other packet types are reserved.
*/

DefConst('kDebugLlamaTalk,								nil);		// true = print comms debugging statements on bunwarmers, nil = supress them
DeclareGlobalFn('LT_PRINT, 1);										// if kDebugLlamaTalk is true, then a global function LT_PRINT will be installed at run time
DefConst('kLT_PRINT,	func(data)
									begin
										Print(data);
										// Sleep(30);
									end	);

DefConst('kLlamaTalkState_Disconnected,			nil);		// ready-to-go (default state)
DefConst('kLlamaTalkState_Connect,					1);		// preparation for (asynchronous) connect
DefConst('kLlamaTalkState_Connecting,				2);		// in-process of (asynchronous) connect
DefConst('kLlamaTalkState_Connected,				3);		// connected (requires disconnect)
DefConst('kLlamaTalkState_Disconnecting,		4);		// in-process of (asynchronous) disconnect
DefConst('kLlamaTalkState_Listen,					5);		// preparation for (asynchronous) listen
DefConst('kLlamaTalkState_Listening,				6);		// in-process of (asynchronous) listen

DefConst('kLlamaTalkAction_Connect,		'connect);		// specifies active connection
DefConst('kLlamaTalkAction_Listen,			'listen);		// specifies passive connection

DefConst('kLlamaTalkType_nil,				0);		// transaction data item types, as used in :MWriteObject() -- DO NOT RENUMBER!
DefConst('kLlamaTalkType_true,			1);	
DefConst('kLlamaTalkType_char,			2);
DefConst('kLlamaTalkType_integer,		3);
DefConst('kLlamaTalkType_real,			4);
DefConst('kLlamaTalkType_string,		5);
DefConst('kLlamaTalkType_binary,		6);

DefConst('kLlamaTalkError_IllegalOperation,		-666);
DefConst('kLlamaTalkError_EndpointInUse,		-667);
DefConst('kLlamaTalkMessage_EndpointInUse,	"Another application seems to be using the communications port.");
DefConst('kLlamaTalkMessage_BindFailed,			"Could not bind the communications tool.");
DefConst('kLlamaTalkMessage_Unknown,			"An unexpected error has occured.");

DefConst('kLlamaTalkQueueTemplate,				// create a new queue like this:  kLlamaTalkQueueTemplate:MInstantiate('FIFO);
{
	MInstantiate:		func(queueType)				// currently 'FIFO (first-in-first-out) and 'FILO (first-in-last-out) queues are supported
								begin
									if queueType = 'FIFO or queueType = 'FILO then
										return	{	_proto:		self,
														fType:		queueType,		// 'FIFO or 'FILO
														fNbElem:	0,						// 0 - N
														fData:		[],	}				// array [] of fNbElem enqueued items
									else
										return nil;
								end,
	
	MDispose:				func()
								begin
									fType := nil;
									fNbElem := nil;
									fData := nil;
									return nil;
								end,
	
	MReset:				func()								// empties the queue, allowing potential garbage collection to occur
								begin
									if fType then begin
											fNbElem := 0;
											SetLength(fData,0);
										end;
									return nil;
								end,
	
	MEnQueue:			func(data)							// adds a non-nil data item to a queue according to queue type
								begin
									if data then
										if fType = 'FIFO or fType = 'FILO then begin
												fNbElem := fNbElem + 1;
												SetLength(fData, fNbElem);
												fData[fNbElem - 1] := data;
												return nil;
											end;
									
									return data;
								end,
	
	MDeQueue:			func()								// removes a data item from a queue according to queue type
								begin
									if not fType or fNbElem <= 0 then
										return nil;
									
									if fType = 'FIFO then begin
											fNbElem := fNbElem - 1;
											local data := fData[0];
											ArrayMunger(fData, 0, 1, nil, 0, 1);
										end
									else if fType = 'FILO then begin
											fNbElem := fNbElem - 1;
											local data := fData[fNbElem];
											ArrayMunger(fData, fNbElem, 1, nil, fNbElem, 1);
										end
									else
										local data := nil;
									
									return data;
								end,
	
	MGetQueueSize:	func()								// return the number of data items in the queue
								begin
									if fType = 'FIFO or fType = 'FILO then
										return fNbElem
									else
										return 0;
								end,
	
	MGetDataSize:		func()								// return the sum of the binary Length() of each data item in the queue
								begin
									local len := 0;
									
									if fType = 'FIFO or fType = 'FILO then
										foreach item in fData do
											len := len + Length(item);
									
									return len;
								end,
});


DefConst('kLlamaTalkStreamTemplate,				// create a new stream like this:  kLlamaTalkStreamTemplate:MInstantiate();
{
	MInstantiate:	func()
							{	_proto:		self,
								fObj:			GetDefaultStore():NewVBO('binary, 0),
								fPos:		0,
							},
	
	MDispose:			func()
							begin
								fObj := nil;
								fPos := -1;
							end,
	
	MOpen:				func()
							nil,

	MClose:			func()
							SetLength(fObj, fPos),

	MRequest:			func(size)
							if Length(fObj) < fPos + size then
								SetLength(fObj, Length(fObj) + Max(size, 256)),
	
	MForward:		func(size)
							begin
								if fPos + size >= Length(fObj) then
									:MRequest(size);
								fPos := fPos + size;
							end,
});

LlamaTalk :=
    {
     MWriteObject:
       func(data)		// WARNING:  This func contains work-arounds and currently undocumented functions.  Use at your own risk!
       begin
       	if fLlamaTalkState <> kLlamaTalkState_Connected then
       		return;
       	
       	IF kDebugLlamaTalk THEN LT_PRINT("Enqueueing data...");
       	
       	local stream := fWriteStream;																// cache the stream object locally for efficiency
       	
       	if not data then begin																				// Note:	if-then-else tree is structured for common-case efficiency
       			stream:MRequest(1);
       			StuffByte(stream.fObj, stream.fPos, kLlamaTalkType_nil);			// object type = nil
       			stream:MForward(1);
       		end
       	
       	else if IsInstance(data, 'string) then begin
       			local len := StrLen(data);
       			stream:MRequest(len + 4);
       			StuffByte(stream.fObj, stream.fPos, kLlamaTalkType_string);		// object type = string
       			StuffWord(stream.fObj, stream.fPos + 1, len);								// MSB -> LSB of 2-byte length
       //			StuffByte(stream.fObj, stream.fPos + 1, len >> 8);						// MSB of length
       //			StuffByte(stream.fObj, stream.fPos + 2, len);								// LSB of length
       			StuffCString(stream.fObj, stream.fPos + 3, data);						// N single byte chars (Mac encoding for chars 128-255)
       			stream:MForward(len + 3);															// get rid of that zero terminator byte from StuffCString
       		end
       	
       	else if IsInstance(data, 'int) then begin
       			stream:MRequest(5);
       			StuffByte(stream.fObj, stream.fPos, kLlamaTalkType_integer);	// object type = integer
       			StuffLong(stream.fObj, stream.fPos + 1, data);								// MSB -> LSB of 4 byte sign-extended value
       			stream:MForward(5);
       		end
       	
       	else if IsInstance(data, 'char) then begin
       			stream:MRequest(2);
       			StuffByte(stream.fObj, stream.fPos, kLlamaTalkType_char);		// object type = char
       			StuffChar(stream.fObj, stream.fPos + 1, data);							// 1 single byte char (Mac encoding for chars 128-255)
       			stream:MForward(2);
       		end
       	
       	else if IsInstance(data, 'boolean) then begin
       			stream:MRequest(1);
       			StuffByte(stream.fObj, stream.fPos,	if data then
       																			kLlamaTalkType_true	// object type = true
       																		else
       																			kLlamaTalkType_nil);	// object type = nil (= false)
       			stream:MForward(1);
       		end
       	
       	else if IsInstance(data, 'real) then begin
       			local s := NumberStr(data);
       			local len := StrLen(s);
       			stream:MRequest(len + 2);
       			StuffByte(stream.fObj, stream.fPos, kLlamaTalkType_real);			// object type = real (as an N-char string)
       			StuffPString(stream.fObj, stream.fPos + 1, s);								// pascal string representation (length byte followed by chars)
       			stream:MForward(len + 2);
       		end
       	
       	else if IsInstance(data, 'binary) then begin
       			local len := Length(data);
       			stream:MRequest(len + 5);
       			StuffByte(stream.fObj, stream.fPos, kLlamaTalkType_binary);		// object type = binary (bytes)
       			StuffLong(stream.fObj, stream.fPos + 1, len);								// MSB -> LSB of 4 byte sign-extended length of object
       			BinaryMunger(stream.fObj, stream.fPos + 5, len, data, 0, len);	// data bytes
       			stream:MForward(len + 5);
       		end
       	
       	else begin
       			IF kDebugLlamaTalk THEN LT_PRINT("Unsupported data class!!!  Cannot enqueue...");
       			:?MLlamaTalk_StdError("Unsupported data class (" & SPrintObject(ClassOf(data)) & ").  Cannot enqueue.", -48215);
       			return nil;
       		end;
       	
       	stream;
       end,
     MIsVisible:
       func()
       begin
       	if fBusyShapes then
       					true
       				else
       					nil;
       end,
     MRead:
       func()
       begin
       	if fInputQueue then
       		fInputQueue:MDeQueue()
       	else
       		nil;
       end,
     MIsOpen:
       func()		// this function will only work when 'self' is the protoLlamaTalk view!
       begin			// In other words,  we're called using:  if view:MIsOpen() then...
       	return call kViewIsOpenFunc with (self);
       end,
     viewFormat: nil,
     MBeginTransaction:
       func()
       begin
       	if fLlamaTalkState <> kLlamaTalkState_Connected then
       		return;
       		
       	IF kDebugLlamaTalk THEN LT_PRINT("Beginning write transaction...");
       	
       	fWriteStream := :MNewStream();
       	fWriteStream:MOpen();
       	
       	return true;
       end,
     viewQuitScript:
       func()
       begin
       	:MDisconnect();
       	
       	fInputQueue := fInputQueue:MDispose();
       	fOutputQueue := fOutputQueue:MDispose();
       	
       	fEndPoint := nil;
       	fEndPointAddress := nil;
       	fEndPointConfig := nil;
       	
       	fOutputData := nil;
       	
       	fIsQuietDisconnect := nil;
       	fBusyShapes := nil;
       	
       //	if kDebugLlamaTalk then
       //		RemoveSlot(functions, 'LT_PRINT);
       end,
     MGetAddress:
       func()
       begin
       	if HasSlot(fEndPointAddress, 'data) and HasSlot(fEndPointAddress.data, 'addressData) then
       		return fEndPointAddress.data.addressData
       	else
       		return fEndPointAddress;
       end,
     MNewBinary:
       func(size)
       begin
       	// SetLength(SetClass(Clone(""), 'binary), size);
       
       	GetDefaultStore():NewVBO('binary, size);
       end,
     viewDrawScript:
       func()
       begin
       	if fLlamaTalkState = kLlamaTalkState_Connected then
       		:MDrawBusyIcon('IDLE)
       	else
       		:MDrawBusyIcon('DISCONNECTED);
       end,
     FInputHeaderComponent:
       {
       	form:				'bytes,
       	termination:		{	byteCount:		4,	},
       	inputScript:		func(ep, data, terminator, options)
       							begin
       								local size := (data[1] << 16) + (data[2] << 8) + data[3];
       								
       								IF kDebugLlamaTalk THEN LT_PRINT("FInputHeaderComponent called, byte count =" && NumberStr(size));
       								
       								if data[0] = 0 then
       									begin
       										ep.FInputDataComponent.fDataBuffer := ep:MNewBinary(size);
       										ep.FInputDataComponent.fDataOffset := 0;
       										ep.FInputDataComponent.fDataBytesToGo := size;
       										ep.FInputDataComponent.termination.byteCount := if size < 512 then size else 512;
       										ep:SetInputSpec(ep.FInputDataComponent);
       									end;
       								else
       									begin
       										ep.FInputDataComponent.fDataBytesToGo := size;
       										ep.FInputDataComponent.termination.byteCount := if size < 512 then size else 512;
       										ep:SetInputSpec(ep.FInputDataSkipper);
       									end;
       							end,
       },
     MConnect:
       func()
       begin
       	IF kDebugLlamaTalk THEN LT_PRINT("LlamaTalk.MConnect");
       
       	if not :MIsOpen() then		// return an error if this view has not yet been opened!
       		return kLlamaTalkError_IllegalOperation;
       		
       	if fLlamaTalkState <> kLlamaTalkState_Disconnected then
       		return kLlamaTalkError_IllegalOperation;
       		
       	:MSetLlamaTalkState(kLlamaTalkState_Connect);
       	
       	fEndPoint:MConnectAction(nil, nil);
       end,
     fBusyShapes:
       nil		// holds an array of shapes to be drawn during I/O when this view is visible, nil otherwise
       ,
     MDisconnectCompProc:
       func(options, result)		// SELF is the endpoint frame
       begin
       	IF kDebugLlamaTalk THEN LT_PRINT("LlamaTalk.MDisconnectCompProc");
       
       	try
       		:UnBind(nil)
       	onexception |evt.ex.comm| do
       		nil;
       	
       	try
       		:Dispose()
       	onexception |evt.ex.comm| do
       		nil;
       	
       	if fDisconnectSlip then begin
       			fDisconnectSlip:Close();
       			fDisconnectSlip := nil;
       		end;
       	
       	:MSetLlamaTalkState(kLlamaTalkState_Disconnected);
       	
       	if fPowerOffState then
       		begin
       			fPowerOffState := nil;
       			PowerOffResume(kAppSymbol);
       		end;
       	UnRegPowerOff(kAppSymbol);
       end,
     viewFlags: 32,
     fEndPointConfigADSP:
       [
       	{	label:		kCMSAppleTalkID,
       		type:		'service,
       		opCode:		opSetRequired,	},
       	
       	{ 	label:		kCMSAppleTalkID,
       		type:		'option,
       		opCode:		opSetRequired,
       		data:		{
       			arglist:		[ 
       				"adsp",	],
       			typelist:	['struct,
       				['array, 'char, 4],	],	},	},
       	
       	{	label:		kCMOEndpointName,
       		type:		'option,
       		opCode:		opSetRequired,
       		data:		{
       			arglist:		[
       				kADSPEndpoint,		],
       			typeList:	['struct, 
       				[11, 13, 0],	],	},	},
       	
       	{	label:		kCMOAppleTalkBuffer,
       		type:		'option,
       		opCode:		opSetRequired,
       		data:		{
       			arglist:		[
       				kSndBuffer,
       				511,		],
       			typeList:	['struct,
       				'ulong,
       				'ulong,	],	},	},
       	
       	{	label:		kCMOAppleTalkBuffer,
       		type:		'option,
       		opCode:		opSetRequired,
       		data:		{
       			arglist:		[
       				kRcvBuffer,
       				511,		],
       			typeList:	['struct,
       				'ulong,
       				'ulong,	],	},	},
       	
       	{	label:		kCMOAppleTalkBuffer,
       		type:		'option,
       		opCode:		opSetRequired,
       		data:		{
       			arglist:	[
       				kAtnBuffer,
       				0,		],
       			typeList:	['struct,
       				'ulong,
       				'ulong,	],	},	},
       ],
     MDisconnectAction:
       func(fromState)		// SELF is the endpoint frame
       begin
       	IF kDebugLlamaTalk THEN LT_PRINT("LlamaTalk.MDisconnectAction");
       
       	try
       		:Cancel(nil)
       	onexception |evt.ex.comm| do
       		nil;
       	
       	if fromState = kLlamaTalkState_Connected then
       		try
       			:Disconnect(nil, {	async:					true,
       										// reqTimeout:		3600,
       										completionScript:	func(ep, options, result)
       																	ep:MDisconnectCompProc(options, result),	})
       		onexception |evt.ex.comm| do
       			:MDisconnectCompProc(nil, CurrentException().error);
       	else
       		:MDisconnectCompProc(nil, nil);
       end,
     MIsConnected:
       func()
       begin
       	return fLlamaTalkState = kLlamaTalkState_Connected;
       end,
     MConnectAsync:
       func()
       begin
       	if not :MIsOpen() then		// return an error if this view has not yet been opened!
       		return kLlamaTalkError_IllegalOperation;
       		
       	if fLlamaTalkState <> kLlamaTalkState_Disconnected then
       		return kLlamaTalkError_IllegalOperation;
       		
       	:MSetLlamaTalkState(kLlamaTalkState_Connect);
       	
       	fEndPoint:MConnectAction(nil, true);
       end,
     viewIdleScript:
       func()
       try
       begin
       	if fLlamaTalkState <> kLlamaTalkState_Connected then begin			// if not connected, turn off idle handler
       			:Dirty();
       			return nil;
       		end;
       	
       	if :MGetState() < 3 then begin			// if connection has dropped, disconnect and turn off idle handler
       			:MDisconnect();
       			if not fIsQuietDisconnect then	// avoid calling the error method if we're supposed to keep quiet about it
       				:?MLlamaTalk_StdError("The connection has closed unexpectedly.", -1);
       			return nil;
       		end;
       	
       	if fInputQueue:MGetQueueSize() > 0 then begin		// if there is any input data available, call input script if defined
       			:DoDrawing('MDrawBusyIcon, ['INPUT]);
       			:?MLlamaTalk_InputScript(:MRead());
       		end;
       	
       	if fOutputQueue:MGetQueueSize() > 0 then begin
       			:DoDrawing('MDrawBusyIcon, ['OUTPUT]);
       			
       			fOutputData := fOutputQueue:MDeQueue();							// fOutputData = the transaction to be output (a stream object)
       			
       			local len := Length(fOutputData.fObj);								// len = total bytes of this transaction
       			IF kDebugLlamaTalk THEN LT_PRINT("Total length to be written = " & NumberStr(len));
       			
       			fEndPoint:Output([0, len >> 16, len >> 8, len], nil, nil);		// output the transaction length
       			fEndPoint:Output(fOutputData.fObj, nil, nil);						// output the transaction data
       		end;
       		
       	if fInputQueue:MGetQueueSize() = 0
       	and fOutputQueue:MGetQueueSize() = 0 then begin	// if no more data to process then slow down the idle handler
       			:DoDrawing('MDrawBusyIcon, ['IDLE]);
       			return 15000												// check for dropped connections every 15 seconds
       		end
       	else
       		return 0;															// number of milliseconds to delay until next idle
       end
       onexception |evt.ex| do
       	0;,
     MIsQuietDisconnect:
       func()
       begin
       	return fIsQuietDisconnect;
       end,
     MProtoClone:
       func(obj)
       begin
       	if not IsFrame(obj) or IsFunction(obj) then
       		Throw('|evt.ex.msg|, "ProtoClone only works with frames.");
       	
       	local new := {_proto: obj};
       	foreach slot, value in obj do
       		if IsFrame(value) and not IsFunction(value) then
       			new.(slot) := :MProtoClone(value);
       	new;
       end,
     MSetProtocol:
       func(protocol)		// returns the endpoint configuration frame, or nil if protocol symbol is unsupported or view is not open
       begin
       	if not :MIsOpen() then
       		return nil;
       	
       	if IsFrame(protocol) then
       		fEndPointConfig := EnsureInternal(protocol.configOptions)
       	else if IsArray(protocol) then
       		fEndPointConfig := EnsureInternal(protocol)
       	else if protocol = 'MNP then
       		fEndPointConfig := fEndPointConfigMNP
       	else if protocol = 'ADSP then
       		fEndPointConfig := fEndPointConfigADSP
       	else
       		return nil;
       		
       	fEndPointConfig;
       end,
     fEndPointConfig:
       nil		// contains the "live" endpoint config frame used during endpoint instantiation
       ,
     viewBounds: {left: 100, top: 100, right: 116, bottom: 116},
     MCountPendingOutputTransactions:
       func()
       begin
       	return	if fOutputQueue then
       					fOutputQueue:MGetQueueSize()
       				else
       					0;
       end,
     MEndTransaction:
       func()
       begin
       	if fLlamaTalkState <> kLlamaTalkState_Connected then
       		return;
       		
       	IF kDebugLlamaTalk THEN LT_PRINT("Transferring transaction to output queue.  Enabling idle handler.");
       	
       	fWriteStream:MClose();
       	fOutputQueue:MEnQueue(fWriteStream);
       	fWriteStream := nil;
       	
       	:SetUpIdle(100);
       	return nil;
       end,
     MDrawBusyIcon:
       func(state)
       begin
       	if fBusyShapes then begin
       			:DrawShape(fBusyShapes[0].fShape, fBusyShapes[0].fStyle);		// erase the background, then draw the appropriate icon
       			
       			if state = 'DISCONNECTED then
       				:DrawShape(fBusyShapes[1].fShape, fBusyShapes[1].fStyle)
       			else if state = 'IDLE then
       				:DrawShape(fBusyShapes[2].fShape, fBusyShapes[2].fStyle)
       			else if state = 'INPUT then
       				:DrawShape(fBusyShapes[3].fShape, fBusyShapes[3].fStyle)
       			else if state = 'OUTPUT then
       				:DrawShape(fBusyShapes[4].fShape, fBusyShapes[4].fStyle)
       			else
       				:DrawShape(fBusyShapes[1].fShape, fBusyShapes[1].fStyle)
       		end;
       end,
     MCountPendingInputTransactions:
       func()
       begin
       	return	if fInputQueue then
       					fInputQueue:MGetQueueSize()
       				else
       					0;
       end,
     fDisconnectSlipTemplate:
       {
       	_proto:							protoFloater,
       	viewBounds:					{	left:			0,
       											top:			0,
       											right: 		108,
       											bottom:		44,	},
       	viewJustify:					vjParentCenterH + vjParentCenterV,				// 80
       	
       	stepChildren:				[
       											{	_proto:				protoStaticText,
       												viewBounds:		{	left:			8,
       																			top:			8,
       																			right: 		104,
       																			bottom:		40,	},
       												viewJustify:		vjCenterH,						// 2
       												text:					"Disconnecting...\nPlease Wait...",	},
       										],
       },
     MResetQueues:
       func()
       begin
       	fInputQueue:MReset();
       	fOutputQueue:MReset();
       end,
     MNewStream:
       func()
       begin
       	kLlamaTalkStreamTemplate:MInstantiate();
       end,
     fEndPointConfigMNP:
       [
       	{	label:		kCMSMNPID,
       		type:		'service,
       		result:		nil,
       		opCode:		opSetRequired	},
       	
       	{	label:		kCMOMNPDataRate,
       		type:		'option,
       		result:		nil,
       		opCode:		opSetRequired,
       		form:		'template,
       		data:	{
       			arglist:	[
       				k38400bps,	],
       			typelist:	['struct,
       				'ulong,	],	},	},
       	
       	{	label:		kCMOSerialIOParms,
       		type:		'option,
       		result:		nil,
       		opCode:		opSetRequired,
       		form:		'template,
       		data:	{
       			arglist:	[
       				k1StopBits,
       				kNoParity,
       				k8DataBits,
       				k38400bps,	],
       			typelist:	['struct,
       				'long,
       				'long,
       				'long,
       				'long,	],	},	},
       	
       	{	label:		kCMOMNPCompression,
       		type:		'option,
       		result:		nil,
       		opCode:		opSetNegotiate,
       		form:		'template,
       		data:	{
       			arglist:	[
       				kMNPCompressionNone,	],					// also works with kMNPCompressionV42bis (but that uses lots more memory)
       			typelist:	['struct,
       				'ulong,	],	},	},
       	
       	/*
       	{	label:		kCMOSerialHWChipLoc,
       		type:		'option,
       		opCode:		opSetNegotiate,	
       		result:		nil,
       		form: 		'template,
       		data:	{
       			arglist:[
       				kHWLocPCMCIASlot1,
       				0,	],
       			typelist:['struct,
       				'ulong,
       				'ulong,	],	},	},
       	*/
       ],
     MSetAddress:
       func(address)		// returns the address, or nil if view is not open
       begin
       	if :MIsOpen() then
       		if address then
       			if IsFrame(address) then
       				fEndPointAddress := EnsureInternal(address);
       			else
       				fEndPointAddress := MakeAppleTalkOption(address);
       		else
       			fEndPointAddress := nil;
       	else
       		nil;
       end,
     MNewQueue:
       func(queueType)
       begin
       	kLlamaTalkQueueTemplate:MInstantiate(queueType);
       end,
     MDisconnect:
       func()		// NOTE: this method may also be called from :MEndPointExceptionHandler in which case SELF is the endpoint frame
       begin
       	IF kDebugLlamaTalk THEN LT_PRINT("LlamaTalk.MDisconnect");
       
       	if fLlamaTalkState <> kLlamaTalkState_Connected
       	and fLlamaTalkState <> kLlamaTalkState_Connecting
       	and fLlamaTalkState <> kLlamaTalkState_Listening then
       		return;
       	
       	:MSetQuietDisconnect(true);		// supress user alerts and other interactions while disconnecting
       	
       	IF kDebugLlamaTalk THEN LT_PRINT("LlamaTalk.MDisconnect -- Disconnecting endpoint");
       	
       	local fromState := fLlamaTalkState;
       	:MSetLlamaTalkState(kLlamaTalkState_Disconnecting);
       	
       	fEndPoint.fDisconnectSlip := BuildContext(fDisconnectSlipTemplate);
       	fEndPoint.fDisconnectSlip:Open();
       	
       	:MResetQueues();						// blow away all queued data
       	
       	fEndPoint:MDisconnectAction(fromState);
       	
       	:Dirty();
       	
       	return nil;
       end,
     fEndPoint:
       nil		// contains the "live" endpoint while we're connected, nil otherwise
       ,
     MSetLlamaTalkState:
       func(newState)
       begin
       	local appBaseView := GetRoot().(kAppSymbol);
       	appBaseView.fLlamaTalkState := newState;
       	if call kViewIsOpenFunc with (appBaseView) then begin
       			fLlamaTalk:?MLlamaTalk_StateChanged();
       			if call kViewIsOpenFunc with (fLlamaTalk) then
       				fLlamaTalk:Dirty();
       			RefreshViews();
       		end;
       end,
     fWriteStream:
       nil		// current outgoing transaction object (a big binary object)
       ,
     MAbortPendingTransactions:
       func()
       begin
       	fInputQueue:MReset();
       	fOutputQueue:MReset();
       	return nil;
       end,
     MToggle:
       func()
       begin
       	if :MIsOpen() then
       		if :MIsVisible() then
       			:Hide()
       		else
       			:Show();
       	return nil;
       end,
     fOutputData:
       nil		// queue of outgoing transaction data items (transaction is sent in chunks)
       ,
     declareSelf: 'fLlamaTalk,
     viewSetupFormScript:
       func()
       begin
       	if kDebugLlamaTalk then DefGlobalFn('LT_PRINT, EnsureInternal(kLT_PRINT));
       	
       	self.fEndPointAddress := TotalClone(fEndPointAddress);				// ADSP address frame must be in RAM so we can modify it
       	self.fEndPointConfig := fEndPointConfigADSP;								// ADSP is the default configuration for this endpoint proto
       	self.fEndPoint :=																			// the endpoint frame must be in RAM so we can modify it
       		{				
       			_proto:								protoBasicEndpoint,
       			_parent:							self,
       			ExceptionHandler:				MEndPointExceptionHandler,
       			FInputHeaderComponent:	:MProtoClone(FInputHeaderComponent),
       			FInputDataComponent:		:MProtoClone(FInputDataComponent),
       			FInputDataSkipper:			:MProtoClone(FInputDataSkipper),
       			fConnectAction:				nil,
       			fDisconnectSlip:				nil,
       		};
       	
       	self.fInputQueue := :MNewQueue('FIFO);
       	self.fOutputQueue := :MNewQueue('FIFO);
       end,
     FInputDataSkipper:
       {
       	form:					'bytes,
       	termination:			{	byteCount:		0,	},
       	fDataBytesToGo:	0,
       	inputScript:			func(ep, data, terminator, options)
       								begin
       									IF kDebugLlamaTalk THEN LT_PRINT("FInputDataSkipper called...");
       									
       									fDataBytesToGo := fDataBytesToGo - termination.byteCount;
       									
       									if fDataBytesToGo > 0 then begin
       											termination.byteCount := if fDataBytesToGo < 512 then fDataBytesToGo else 512;
       											ep:SetInputSpec(ep.FInputDataSkipper);
       										end
       									else
       										ep:SetInputSpec(ep.FInputHeaderComponent);
       								end,
       },
     MListen:
       func()
       begin
       	IF kDebugLlamaTalk THEN LT_PRINT("LlamaTalk.MListen");
       
       	if not :MIsOpen() then		// return an error if this view has not yet been opened!
       		return kLlamaTalkError_IllegalOperation;
       		
       	if fLlamaTalkState <> kLlamaTalkState_Disconnected then
       		return kLlamaTalkError_IllegalOperation;
       		
       	:MSetLlamaTalkState(kLlamaTalkState_Listen);
       	
       	fEndPoint:MConnectAction(true, nil);
       end,
     MEndPointExceptionHandler:
       func(exception)
       begin
       	IF kDebugLlamaTalk THEN LT_PRINT("MEndPointExceptionHandler called!");
       	
       	if exception.data exists
       	and exception.data <> -16005					// exception generated by ep:Abort() while connected -- really not an error
       	and exception.data <> -16013					// exception generated by ep:Abort() during connect -- really not an error
       	and fLlamaTalkState <> kLlamaTalkState_Disconnecting then
       		begin
       			if exception.data = -20003				// the other end has torn down its connection
       			or exception.data = -16009 then		// wouldn't it be nice if all endpoints used the same error codes?
       				if fIsQuietDisconnect then				// avoid calling the error method if we're supposed to keep quiet about it
       					nil
       				else
       					fLlamaTalk:?MLlamaTalk_StdError("The connection has closed unexpectedly.", exception.data)
       			else
       				fLlamaTalk:?MLlamaTalk_StdError("A communications error has occured.", exception.data);
       			
       			AddDeferredSend(fLlamaTalk, 'MDisconnect, []);
       		end;
       	
       	true;
       end,
     MSetQuietDisconnect:
       func(quiet)	// returns true or nil
       begin
       	fIsQuietDisconnect := if quiet then true else nil;
       end,
     fEndPointAddress:
       nil		// contains the connection address frame, or nil if not required 
       ,
     MIsConnecting:
       func()
       begin
       	return (fLlamaTalkState = kLlamaTalkState_Connecting) or (fLlamaTalkState = kLlamaTalkState_Listening);
       end,
     MConnectCompProc:
       // this routine is called from MConnectAction
       // SELF is the endpoint frame
       
       func(options, result)	
       begin
       	IF kDebugLlamaTalk THEN LT_PRINT("LlamaTalk.MConnectCompProc");
       	
       	if result then
       		begin
       			IF kDebugLlamaTalk THEN LT_PRINT("ERROR in MConnectAction/CompProc, error code =" && NumberStr(result));
       			if not fIsQuietDisconnect then
       				fLlamaTalk:?MLlamaTalk_StdError("Could not connect.", result);
       			:MDisconnect();
       			return result;
       		end;
       	
       	if fConnectAction = kLlamaTalkAction_Listen then
       		try
       			:Accept(nil, nil)
       		onexception |evt.ex.comm| do
       			begin
       				fLlamaTalk:?MLlamaTalk_StdError("Could not connect.", CurrentException().error);
       				:MDisconnect();
       				return;
       			end;
       	
       	:MSetLlamaTalkState(kLlamaTalkState_Connected);
       	:SetInputSpec(FInputHeaderComponent);						// kick-off the receive
       end,
     FInputDataComponent:
       {
       	form:					'bytes,
       	termination:			{	byteCount:		0,	},
       	fDataBuffer:			nil,
       	fDataOffset:			0,
       	fDataBytesToGo:	0,
       	inputScript:			func(ep, data, terminator, options)
       								begin
       									IF kDebugLlamaTalk THEN LT_PRINT("FInputDataComponent called...");
       									
       									local size := ep.FInputDataComponent.termination.byteCount;
       									
       									for i := 0 to size - 1 do
       										StuffByte(ep.FInputDataComponent.fDataBuffer, ep.FInputDataComponent.fDataOffset + i, data[i]);
       									ep.FInputDataComponent.fDataOffset := ep.FInputDataComponent.fDataOffset + size;
       									ep.FInputDataComponent.fDataBytesToGo := ep.FInputDataComponent.fDataBytesToGo - size;
       									
       									if ep.FInputDataComponent.fDataBytesToGo > 0 then begin
       											ep.FInputDataComponent.termination.byteCount := if ep.FInputDataComponent.fDataBytesToGo < 512 then ep.FInputDataComponent.fDataBytesToGo else 512;
       											ep:SetInputSpec(ep.FInputDataComponent);
       										end
       									else begin
       											ep._parent.fInputQueue:MEnQueue(ep.FInputDataComponent.fDataBuffer);
       											ep.FInputDataComponent.fDataBuffer := nil;
       											ep:SetInputSpec(ep.FInputHeaderComponent);
       											ep._parent:SetUpIdle(100);
       										end;
       								end,
       },
     viewHideScript:
       func()
       begin
       	fBusyShapes := nil;
       end,
     viewClass: 74,
     MListenAsync:
       func()
       begin
       	IF kDebugLlamaTalk THEN LT_PRINT("LlamaTalk.MListen");
       
       	if not :MIsOpen() then		// return an error if this view has not yet been opened!
       		return kLlamaTalkError_IllegalOperation;
       		
       	if fLlamaTalkState <> kLlamaTalkState_Disconnected then
       		return kLlamaTalkError_IllegalOperation;
       		
       	:MSetLlamaTalkState(kLlamaTalkState_Listen);
       	
       	fEndPoint:MConnectAction(true, true);
       end,
     fOutputQueue:
       nil		// each entry holds an outgoing transaction (a queue) until it can be processed
       ,
     MConnectAction:
       func(isPassive, isAsync)		// SELF is the endpoint frame
       begin	
       	IF kDebugLlamaTalk THEN LT_PRINT("LlamaTalk.MConnectAction");
       
       	RegPowerOff(	kAppSymbol,
       							func(what, why)			// we create the closure here so as to set up SELF as the endpoint frame in the closure
       							begin
       								if what = 'okToPowerOff then
       									begin
       										if why <> 'idle																		// keep the unit awake whenever we're connected
       										or fLlamaTalkState = kLlamaTalkState_Disconnected then		// unless the user or an application explicitly
       											return true;																		// wants it to sleep
       									end;
       								
       								else if what = 'powerOff then
       									begin
       										if why <> 'idle																		// if we simply must go to sleep but we're still
       										or fLlamaTalkState <> kLlamaTalkState_Disconnected then		// connected then begin the disconnect process
       											begin
       												fPowerOffState := 'holdYourHorses;								// set a flag to indicate we're powering down
       												:MDisconnect();
       												return 'holdYourHorses;
       											end;
       									end;
       								
       								nil;	// ALWAYS return nil here!
       							end	);
       	
       	if isPassive then
       		fConnectAction := kLlamaTalkAction_Listen;
       	else
       		fConnectAction := kLlamaTalkAction_Connect;
       	
       	:MSetQuietDisconnect(nil);
       	
       	local error;
       	local options := Clone(fEndPointConfig);
       
       	try
       		options := :Instantiate(self, options)
       	onexception |evt.ex.comm| do
       		begin
       			error := CurrentException().error;
       			IF kDebugLlamaTalk THEN LT_PRINT("ERROR in MConnectAction Instantiate, error code =" && NumberStr(error));
       			:?MLlamaTalk_StdError(kLlamaTalkMessage_EndpointInUse, error);
       			:MSetLlamaTalkState(kLlamaTalkState_Disconnected);
       			UnRegPowerOff(kAppSymbol);
       			return error;
       		end;
       	
       	try
       		options := :Bind(nil, nil)
       	onexception |evt.ex.comm| do
       		begin
       			error := CurrentException().error;
       			:?MLlamaTalk_StdError(kLlamaTalkMessage_BindFailed, error);
       			:MSetLlamaTalkState(kLlamaTalkState_Disconnected);
       			:Dispose();
       			UnRegPowerOff(kAppSymbol);
       			return error;
       		end;
       		
       	try
       		begin
       			if fConnectAction = kLlamaTalkAction_Listen then
       				begin
       					:MSetLlamaTalkState(kLlamaTalkState_Listening);
       					options := :Listen( [fEndPointAddress],
       												{	async:						isAsync,
       													reqTimeout:				90000,		// 90 seconds -- for DEMO purposes only
       													completionScript:		func(ep, options, result)
       																					ep:MConnectCompProc(options, result)	});
       				end;
       			else if fConnectAction = kLlamaTalkAction_Connect then
       				begin
       					:MSetLlamaTalkState(kLlamaTalkState_Connecting);
       					options := :Connect(	[fEndPointAddress],
       													{	async:					isAsync,
       														reqTimeout:			30000,		// 30 seconds -- for DEMO purposes only
       														completionScript:	func(ep, options, result)
       																					ep:MConnectCompProc(options, result),	});
       				end;
       			else
       				Throw('|evt.ex.msg|,"Illegal fConnectAction value (neither kLlamaTalkAction_Connect or kLlamaTalkAction_Listen).");
       		end
       	onexception |evt.ex.comm| do
       		begin
       			error := CurrentException().error;
       			:MConnectCompProc(options, error);
       			return error;
       		end;
       	
       	if not isAsync then
       		:MConnectCompProc(options, nil);
       	
       	nil;	// return "no error" to caller
       end,
     MAbortTransaction:
       func()
       begin
       	IF kDebugLlamaTalk THEN LT_PRINT("Aborting current transaction...");
       	return :MBeginTransaction();
       end,
     fInputQueue:
       nil		// holds incoming data until it can be processed
       ,
     fPowerOffState: nil,
     viewShowScript:
       func()
       begin
       	local r := :LocalBox();
       	local s := MakeOval(0, 0, r.right - 1, r.bottom - 1);
       	fBusyShapes :=
       		[
       			{	fShape:		[	MakeShape(r)											],				// used to erase the view
       				fStyle:		{	transferMode:	modeCopy,
       									penPattern:		vfNone,
       									fillPattern:		vfFillWhite,	} },
       				
       			{	fShape:		[	s,																				// 'DISCONNECTED phase
       									MakeLine(0, 0, r.right - 1, r.bottom - 1),
       									MakeLine(0, r.bottom - 1, r.right - 1, 0)	],	
       				fStyle:		{	transferMode:	modeCopy,
       									penSize:			1,
       									penPattern:		vfBlack,
       									fillPattern:		vfFillWhite,	} },
       
       			{	fShape:		[	s																],				// 'IDLE phase
       				fStyle:		{	transferMode:	modeCopy,
       									penSize:			1,
       									penPattern:		vfBlack,
       									fillPattern:		vfFillWhite,	} },
       				
       			{	fShape:		[	s																],				// 'INPUT phase
       				fStyle:		{	transferMode:	modeCopy,
       									penSize:			1,
       									penPattern:		vfBlack,
       									fillPattern:		vfFillGray,	} },
       			
       			{	fShape:		[	s																],				// 'OUTPUT phase
       				fStyle:		{	transferMode:	modeCopy,
       									penSize:			1,
       									penPattern:		vfNone,
       									fillPattern:		vfFillBlack,	} },
       		];
       end,
     MGetState:
       func()
       begin
       	local state := -1;
       	
       	if fLlamaTalkState = kLlamaTalkState_Connected then
       		try
       			state := fEndPoint:State();
       		onexception |evt.ex| do
       			state := kLlamaTalkError_IllegalOperation;
       				
       	return state;
       end,
     fIsQuietDisconnect: nil
    };


constant |layout_protoLlamaTalk| := LlamaTalk;
// End of file protoLlamaTalk
// Beginning of file LlamaTalkMain.t

// Before Script for "vDali"
// This file and project is Copyright © 1994-1995 Apple Computer, Inc. All rights reserved.


vDali :=
    {viewFormat: 83951953,
     viewBounds: {left: 2, top: 2, right: 242, bottom: 338},
     viewSetupFormScript:
       func()
       begin
       	// make view no bigger than the original MP
       	local b := GetAppParams()	;
       	viewBounds := RelBounds( b.appAreaLeft, b.appAreaTop,
       									MIN( b.appAreaWidth, kMaxAppWidth ),
       									MIN( b.appAreaHeight, kMaxAppHeight ));
       end,
     viewSetupDoneScript:
       func()
       begin
       	:DoUpdateButtons();
       end,
     DoConnect:
       func()
       begin
       	if not vLlamaTalk:MIsOpen() then
       		vLlamaTalk:Open();
       	
       	if vProtocol.clusterValue = 1 then begin
       			vLlamaTalk:MSetProtocol('ADSP);
       			vLlamaTalk:MSetAddress("Echo Server:EchoLlama@*");
       		end
       	else begin
       			vLlamaTalk:MSetProtocol('MNP);
       			vLlamaTalk:MSetAddress(nil);
       		end;
       	
       	vLlamaTalk:MSetQuietDisconnect(true);
       	
       	local err := nil;
       	if vAsync.viewValue then
       		if vPassive.viewValue then
       			err := vLlamaTalk:MListenAsync();
       		else
       			err := vLlamaTalk:MConnectAsync();
       	else
       		begin
       			if vPassive.viewValue then
       				err := vLlamaTalk:MListen();
       			else
       				err := vLlamaTalk:MConnect();
       		end;
       	
       	if err then
       		vLlamaTalk:Close();
       	
       	:DoUpdateButtons();
       end,
     DoDisconnect:
       func()
       begin
       	vLlamaTalk:MDisconnect();
       	vLlamaTalk:Close();
       	:DoUpdateButtons();
       	:DoMessage("Ready for connect...");
       end,
     DoMessage:
       func(message)
       begin	
       	SetValue(vMessage, 'text, Clone(message));
       	RefreshViews();
       end,
     DoUpdateButtons:
       func()
       begin
       		if vLlamaTalk:MIsConnected() then
       			SetValue(vConnect, 'text, "Disconnect");
       		
       		else if vPassive.viewValue then
       			begin
       				if vLlamaTalk:MIsConnecting() then
       					SetValue(vConnect, 'text, "Stop Listening");
       				else
       					if vAsync.viewValue then
       						SetValue(vConnect, 'text, "Listen Async");
       					else
       						SetValue(vConnect, 'text, "Listen");
       			end;
       		else
       			begin
       				if vLlamaTalk:MIsConnecting() then
       					SetValue(vConnect, 'text, "Stop Connecting");
       				else
       					if vAsync.viewValue then
       						SetValue(vConnect, 'text, "Connect Async");
       					else
       						SetValue(vConnect, 'text, "Connect");
       			end;
       		
       		if vLlamaTalk:MIsOpen() then
       			begin
       				SetValue(vOpenClose, 'text, "Close");
       				vShowHide:Show();
       				if vLlamaTalk:MIsVisible() then
       					SetValue(vShowHide, 'text, "Hide");
       				else
       					SetValue(vShowHide, 'text, "Show");
       			end;
       		else
       			begin
       				SetValue(vOpenClose, 'text, "Open");
       				vShowHide:Hide();
       			end;
       end,
     MLlamaTalk_InputScript:
       func(data)
       begin
       	if Length(data) = 0 then
       		return :DoMessage("Empty data packet.");
       
       	local s, fieldType := ExtractByte(data, 0);
       	
       	if fieldType = kLlamaTalkType_nil then
       		s := "Nil";
       	else if fieldType = kLlamaTalkType_true then
       		s := "True";
       	else if fieldType = kLlamaTalkType_char then
       		s := "Char " & $\22 & ExtractChar(data, 1) & $\22;
       	else if fieldType = kLlamaTalkType_integer then
       		s := "Integer " & $\22 & NumberStr(ExtractLong(data, 1)) & $\22;
       	else if fieldType = kLlamaTalkType_real then
       		s := "Real " & $\22 & ExtractPString(data, 1) & $\22;
       	else if fieldType = kLlamaTalkType_string then
       		begin
       			local len := ExtractWord(data, 1);
       			local obj := SetLength(ExtractBytes(data, 3, len, 'binary), len + 1);
       			StuffByte(obj, len, 0);
       			s := "String of length " & NumberStr(len) & " " & $\22 & ExtractCString(obj, 0) & $\22;
       		end;
       	else if fieldType = kLlamaTalkType_binary then
       		begin
       			local len := ExtractLong(data, 1);
       			s := "Binary of length " & NumberStr(len);
       		end;
       	else
       		s := ExtractCString(data, 0);	// must be an unformatted packet from LlamaTalkEchoApp
       
       	:DoMessage("First field in data packet = " & unicodeCR & s);
       end,
     MLlamaTalk_StdError:
       func(messageText, errorNum)
       begin
       	:DoUpdateButtons();
       	if errorNum = 0 then
       		local text := messageText
       	else
       		local text := messageText & "\n" & NumberStr(errorNum);
       	:DoMessage(text);
       	GetRoot():Notify(kNotifyAlert, kAppName, text);
       end,
     fLlamaTalkState:
       // this is a REQUIRED slot for use with protoLlamaTalk
       // it MUST have the initial value of NIL when compiled
       // it orchestrates the connect and disconnect process
       
       nil,
     MLlamaTalk_StateChanged:
       func()
       begin
       	if vLlamaTalk:MIsConnecting() then
       		:DoMessage("Connecting...");
       	else if vLlamaTalk:MIsConnected() then
       		:DoMessage("Connected");
       	else
       		:DoMessage("Ready for connect...");
       	
       	:DoUpdateButtons();
       end,
     title: kAppName,
     _proto: @157
    };

vLlamaTalk :=
    {viewBounds: {left: 8, top: 141, right: 24, bottom: 157}, _proto: LlamaTalk}
    ;
AddStepForm(vDali, vLlamaTalk);
StepDeclare(vDali, vLlamaTalk, 'vLlamaTalk);



vMessage :=
    {text: "Ready for connect...",
     viewBounds: {left: 9, top: 25, right: 229, bottom: 125},
     viewJustify: 0,
     viewFormat: 524624,
     viewFlags: 515,
     viewClickScript:
       func(unit)
       begin
       	SetValue(self, 'text, "");
       	true;
       end,
     _proto: @218
    };
AddStepForm(vDali, vMessage);
StepDeclare(vDali, vMessage, 'vMessage);



vStatus :=
    {text: "",
     viewBounds: {left: 32, top: 136, right: 224, bottom: 168},
     viewIdleScript:
       func()
       begin
       	SetValue (vStatus, 'text,	"In =" && NumberStr(vLlamaTalk:MCountPendingInputTransactions())			& "     " &
       											"Out =" && NumberStr(vLlamaTalk:MCountPendingOutputTransactions())		& "\n" &
       											"State =" && NumberStr(vLlamaTalk:MGetState())										& "   " &
       											(if fLlamaTalkState then NumberStr(fLlamaTalkState) else "nil")					& "      " &
       											"Ticks =" && NumberStr(Ticks())
       											);
       	1000;			// 'idle one second':  return the number of milliseconds to wait before calling IdelScript again
       end,
     viewSetupDoneScript:
       func()
       begin
       	:SetUpIdle(100);
       end,
     viewJustify: 0,
     _proto: @218
    };
AddStepForm(vDali, vStatus);
StepDeclare(vDali, vStatus, 'vStatus);



vConnect :=
    {text: "",
     buttonClickScript:
       func()
       begin
       	if vLlamaTalk:MIsConnected() then
       		:DoDisconnect()
       	else
       		:DoConnect();
       	:DoUpdateButtons();
       end,
     viewBounds: {left: 122, top: 230, right: 222, bottom: 246},
     _proto: @226
    };
AddStepForm(vDali, vConnect);
StepDeclare(vDali, vConnect, 'vConnect);



vOpenClose :=
    {text: "",
     buttonClickScript:
       func()
       begin
       	vLlamaTalk:Toggle();
       	:DoUpdateButtons();
       end,
     viewBounds: {left: 122, top: 254, right: 166, bottom: 270},
     _proto: @226
    };
AddStepForm(vDali, vOpenClose);
StepDeclare(vDali, vOpenClose, 'vOpenClose);



vShowHide :=
    {text: "",
     buttonClickScript:
       func()
       begin
       	vLlamaTalk:MToggle();
       	:DoUpdateButtons();
       end;,
     viewBounds: {left: 178, top: 254, right: 222, bottom: 270},
     viewFlags: 515,
     _proto: @226
    };
AddStepForm(vDali, vShowHide);
StepDeclare(vDali, vShowHide, 'vShowHide);



vSendPings :=
    {text: "Start Ping Test",
     buttonClickScript:
       func()
       begin
       	if fIsActiveIdle then begin
       			fIsActiveIdle := nil;
       			SetValue(self, 'text, "Start Ping Test");
       			:SetUpIdle(0);
       		end
       	else begin
       			fIsActiveIdle := true;
       			SetValue(self, 'text, "Stop Ping Test");
       			:SetUpIdle(100);
       		end;
       end,
     viewBounds: {left: 122, top: 278, right: 222, bottom: 294},
     viewIdleScript:
       func()
       begin
       	try
       		begin
       			if vLlamaTalk:MCountPendingOutputTransactions() < 1 then		// let's try to not explode our Newton, okay?
       				if vLlamaTalk:MBeginTransaction() then begin
       						vLlamaTalk:MWriteObject("How very like the future this place might be.  It is a tiny world just big enough to support the chemicals of one knowledge worker.  I feel a wave of loneliness as I head back down.  Am I going too fast?");
       						vLlamaTalk:MWriteObject("I plunge right on in through the office door and into the bottomless sea below.  Suddenly I can't remember how to stop.  Turn around.  Look.  Point behind myself.  Do I have to turn around and point?  I flip into a burning fit.");
       						vLlamaTalk:MEndTransaction();
       					end
       				else
       					Throw('|evt.ex.msg.ignore.me|, "A ping error occured!");
       		end
       	onexception |evt.ex.msg.ignore.me| do
       		begin
       			fIsActiveIdle := nil;
       			SetValue(self, 'text, "Start Ping Test");
       			return nil;
       		end;
       	
       	return 1000;		// idle rate at which to send, in miliseconds, or nil to turn off idle handler
       end,
     fIsActiveIdle: nil,
     _proto: @226
    };
AddStepForm(vDali, vSendPings);
StepDeclare(vDali, vSendPings, 'vSendPings);



vProtocolLabel :=
    {text: "Transport Protocol:",
     viewBounds: {left: 8, top: 176, right: 112, bottom: 192},
     viewJustify: 8388609,
     _proto: @218
    };
AddStepForm(vDali, vProtocolLabel);
StepDeclare(vDali, vProtocolLabel, 'vProtocolLabel);



vProtocol :=
    {viewBounds: {left: 120, top: 178, right: 216, bottom: 192},
     clusterValue: 1,
     _proto: @203
    };
AddStepForm(vDali, vProtocol);
StepDeclare(vDali, vProtocol, 'vProtocol);

vADSP :=
    {buttonValue: 1,
     viewBounds: {left: 0, top: -5, right: 48, bottom: 11},
     text: "ADSP",
     _proto: @202
    };
AddStepForm(vProtocol, vADSP);
StepDeclare(vDali, vADSP, 'vADSP);



vMNP :=
    {buttonValue: 2,
     viewBounds: {left: 48, top: -5, right: 96, bottom: 11},
     text: "MNP",
     _proto: @202
    };
AddStepForm(vProtocol, vMNP);
StepDeclare(vDali, vMNP, 'vMNP);





vS :=
    {text: "Str",
     buttonClickScript:
       func()
       begin
       	vLlamaTalk:MBeginTransaction();
       	vLlamaTalk:MWriteObject("Hello");
       	vLlamaTalk:MEndTransaction();
       end,
     viewBounds: {left: 66, top: 234, right: 94, bottom: 246},
     _proto: @226
    };
AddStepForm(vDali, vS);
StepDeclare(vDali, vS, 'vS);



vC :=
    {text: "Char",
     buttonClickScript:
       func()
       begin
       	vLlamaTalk:MBeginTransaction();
       	vLlamaTalk:MWriteObject($A);
       	vLlamaTalk:MEndTransaction();
       end,
     viewBounds: {left: 26, top: 234, right: 54, bottom: 246},
     _proto: @226
    };
AddStepForm(vDali, vC);
StepDeclare(vDali, vC, 'vC);



vT :=
    {text: "True",
     buttonClickScript:
       func()
       begin
       	vLlamaTalk:MBeginTransaction();
       	vLlamaTalk:MWriteObject(true);
       	vLlamaTalk:MEndTransaction();
       end,
     viewBounds: {left: 66, top: 210, right: 94, bottom: 222},
     _proto: @226
    };
AddStepForm(vDali, vT);
StepDeclare(vDali, vT, 'vT);



vI :=
    {text: "Int",
     buttonClickScript:
       func()
       begin
       	vLlamaTalk:MBeginTransaction();
       	vLlamaTalk:MWriteObject(1234567);
       	vLlamaTalk:MEndTransaction();
       end,
     viewBounds: {left: 26, top: 258, right: 54, bottom: 270},
     _proto: @226
    };
AddStepForm(vDali, vI);
StepDeclare(vDali, vI, 'vI);



vR :=
    {text: "Real",
     buttonClickScript:
       func()
       begin
       	vLlamaTalk:MBeginTransaction();
       	vLlamaTalk:MWriteObject(1234567.89);
       	vLlamaTalk:MEndTransaction();
       end,
     viewBounds: {left: 66, top: 258, right: 94, bottom: 270},
     _proto: @226
    };
AddStepForm(vDali, vR);
StepDeclare(vDali, vR, 'vR);



vN :=
    {text: "Nil",
     buttonClickScript:
       func()
       begin
       	vLlamaTalk:MBeginTransaction();
       	vLlamaTalk:MWriteObject(nil);
       	vLlamaTalk:MEndTransaction();
       end,
     viewBounds: {left: 26, top: 210, right: 54, bottom: 222},
     _proto: @226
    };
AddStepForm(vDali, vN);
StepDeclare(vDali, vN, 'vN);



vB :=
    {text: "Binary",
     buttonClickScript:
       func()
       begin
       	vLlamaTalk:MBeginTransaction();
       	local b := SetLength(SetClass(Clone(""), 'binary), 4);
       	StuffLong(b, 0, 1234567);
       	vLlamaTalk:MWriteObject(b);
       	vLlamaTalk:MEndTransaction();
       end,
     viewBounds: {left: 34, top: 282, right: 86, bottom: 294},
     _proto: @226
    };
AddStepForm(vDali, vB);
StepDeclare(vDali, vB, 'vB);



vAsync :=
    {indent: 4,
     text: "Connect Asynchronously",
     viewBounds: {left: 112, top: 208, right: 234, bottom: 224},
     viewSetupFormScript:
       func()
       begin
       	self.indent := self.indent + StrWidth(self.text);
       	inherited:?viewSetupFormScript();
       end,
     viewValue: nil,
     valueChanged:
       func()
       begin
       	:DoUpdateButtons();
       end,
     _proto: @204
    };
AddStepForm(vDali, vAsync);
StepDeclare(vDali, vAsync, 'vAsync);



vPassive :=
    {indent: 4,
     text: "Wait For Connection",
     viewBounds: {left: 112, top: 192, right: 234, bottom: 208},
     viewSetupFormScript:
       func()
       begin
       	self.indent := self.indent + StrWidth(self.text);
       	inherited:?viewSetupFormScript();
       end,
     viewValue: nil,
     valueChanged:
       func()
       begin
       	:DoUpdateButtons();
       end,
     _proto: @204
    };
AddStepForm(vDali, vPassive);
StepDeclare(vDali, vPassive, 'vPassive);




constant |layout_LlamaTalkMain.t| := vDali;
// End of file LlamaTalkMain.t



