24. NS BASIC Tech Note: Using Endpoints with NSBASIC 6 JUNE 1996.
------------------------------------------------------------
Contributed by Jonathan Kipling Knight (KKnight-COS3© Kaman.com), Colorado
Springs, CO.
[Note: NS BASIC provides a standard, easy to use interface to
communications, based on the INPUT and PRINT statements. WIth Rev 3.5, we
also provided a more direct interface to the underlying communications in
the Newton. While this is more complex to use, it is also much more
powerful. Here'a a tech note showing how to roll your own communications -
Ed.]
If you have a special purpose for a program that involves talking to the
outside world, you might be glad to see the large document "Newton
Programmers Guide: Communications" at
http://dev.info.apple.com/newton/techinfo/techinfo.html. This document
was designed to be used with Newton 2.0 in conjunction with the Newton
ToolKit. If you planned to use endpoints with NSBASIC then you'll run
into a snag. Apple doesn't provide the values of the necessary constants
to start communicating. The following is a list of constants that are
missing from that document.
Constants missing from NPG:Communications
Protos:
oldProtoEndpoint © 174 // provided for compatibility with NOS 1.x
protoBasicEndpoint © 383 // the normal proto for endpoints
protoStreamingEndpoint © 466 // use to "stream" large objects onto stores
Services:
kCMSMNPID "mnps" // Asynchronous Serial with MNP Compression
kCMSSlowIR "slir" // Infrared
kCMSModemID "mods" // Modem
kCMSAsynchSerial "aser" // Asynchronous Serial
kCMSAppleTalkID "atlk" // AppleTalk
The following listing is the special purpose that drove me to find these
missing constants. It is a program that calls up the NIST Atomic Clock
computer (located in Boulder, Colorado) and sets the Newton's time to the
received time strings. This is a working program but could use some more
error checking and state checking to make it dependable. It's offered
here to provide an example of how to set up and use endpoints with
NSBASIC. The functions are extended for clarity and should be typed in
without carriage returns.
0010 LET kCMSModemID="mods"
0020 LET protoBasicEndpoint:=© 383
0030 LET opSetRequired=512
0040 LET unicodeLF=chr(10)
0050 LET unicodeCR=chr(13)
0060 LET EOL:=Stringer([unicodeCR,unicodeLF]) // End of Line characters
0070 LET OTM:="*" // Character received on the seconds mark
0080 LET
connectService={label:kCMSModemID,type:'service,opCode:opSetRequired}
0090 LET dialOps:=MakeModemOption() // Gets Extras\Prefs\Modem options
0100 LET initConfig=[connectService,dialOps]
0110 LET NISTAddress=MakePhoneOption("1(303)494-4774")
0120 LET ep={_proto:protoBasicEndpoint}
0130 FUNCTION InitFunc(ep,data,term,ops)
begin
SetValue(u.inWindow,'text,data);
if StrPosExact(data,"",0) then
ep:SetInputSpec(u.rxTimeSpec);
end
0140 FUNCTION RxTimeFunc(ep,data,term,ops)
begin
local dt;
SetValue(u.inWindow,'text,data);
dt:=u:DecodeNISTTime(data);
if Abs(dt-TimeInSeconds())<60*60 then
begin
SetTimeInSeconds(dt);
u:FinishConnect(ep);
end;
end
0150 FUNCTION DecodeNISTTime(data)
begin
local dst,ds,secs,hrPos:=StrPos(data,":",0)-2;
ds:=StringToNumber(SubStr(data,hrPos+9,2));
dst:=if ds<51 and ds<>0 then 3600 else 0;
secs:=(StringToNumber(SubStr(data,hrPos-15,5))-48988)*86400;
secs:=secs+(StringToTime(SubStr(data,hrPos,5))-StringToTime("00:00"))*60;
secs:=secs+StringToNumber(SubStr(data,hrPos+6,2));
secs:=secs+dst+GetUserConfig('location).gmt;
RintToL(secs) end
0160 FUNCTION FinishConnect(ep)
begin
ep:SetInputSpec(nil);
ep:FlushInput();
ep:Disconnect(True,nil);
ep:UnBind(nil);
end
0170 LET initSpec={termination:{endSequence:EOL},form:'string,
inputScript:InitFunc}
0180 LET rxTimeSpec={termination:{endSequence:OTM},form:'string,
inputScript:RxTimeFunc}
0190 LET inWindow:={text:"",viewBounds:RelBounds(5,5,230,50)}
0200 WINDOW inW,inWindow
0210 SHOW inW
0220 u.ep:Instantiate(ep,initConfig)
0230 u.ep:Bind(nil,nil) // bind endpoint to service
0240 u.ep:Connect(NISTAddress,{reqTimeout:30000}) // Stop calling after
30 secs
0250 u.ep:SetInputSpec(initSpec) // Start receiving
0260 WAIT 30000 // Wait 30 secs for connection to finish
0270 u.ep:Dispose() // Dispose endpoint
0280 HIDE
0290 END
All of the other services can be used in a similar manner if you use the
above constants and follow NPG:Communications. BASIC 3.5 now provides for
more communication services but for highly specialized communications, it
is possible to use endpoints directly. By the way, the above program
makes a 2-5 second phone call so it shouldn't increase your phone bill by
much. I've seen it at 15 cents a call.