Newton Communication
Volume Number: 10
Issue Number: 5
Column Tag: Newton
Newton Communication Programming
The basics
By Kent Sandvik
Note: Source code files accompanying article are located on MacTech CD-ROM or
source code disks.
About the author
Kent Sandvik is working at PIE Developer Technical Support, Apple, as a
Technical Lead. This means less programming and more meeting attendance. You can try
to reach him on Internet, CompuServe or AppleLink, but he may be in Nepal for a few
weeks on his sabbatical
Introduction
This article is an introduction to communication application development on the
Newton platform. Some of you maybe have read the Communication chapter in the
Newton Programmer’s Guide, and also looked at the various samples and the Q&A
material (posted on AppleLink and Internet). This article will complement the existing
material, and the intent is to be more practical and provide an introduction into
writing communication applications. The end result is (hopefully) that you could
implement communication aware applications on the Newton platform within a short
time frame and with no headache.
Newton provides a high level interface to the built-in communication facilities
(serial port, modem, Infrared and ADSP) by the way of routing. When the end user
selects a specific action from the action button, the system will place the contents into
a specific outbox, and later send and receive information from and to the inbox and
outbox. In this case we are talking about store-and-forward communication support.
In this article we will dive further down into the guts of Newton communication
programming. In other words we want to implement point-to-point connections with
other Newtons or external services, and write applications that talk with various
application level protocols. Examples of such cases could be various ADSP servers,
on-line services, mail systems, relational databases and other interesting entities on
the future information highway.
In this article we will mainly discuss the basics of the communication system,
what various buzzwords mean, how to implement basic communication applications
using the serial port and a serial cable and how to write protocol implementations.
Communications, Routing
Testing
In many cases we do testing of communication applications using a Newton, an
external service, modems, cables, if possible also using line analyzers for debugging
purposes (but these are fairly expensive). If you want to configure a fairly cheap
environment, I would suggest to purchase a Macintosh terminal program that is
Communication Toolbox aware. This means that you could test out various protocols and
services using existing CTB tools (modem, MNP5, ADSP, plain serial).
Oh yes, what about the cable? We are dealing with so called null modem cables. In
the case of a Macintosh connection, use M0197, part number 590-0552-A. [I simply
used the cable that came with a StyleWriter - Ed stb]
Endpoints
So, what are endpoints? The new X/OPEN standard by the name of XTI specifies a
new communication entity called an endpoint. The idea with the endpoint is that it
encapsulates the behavior and attributes associated with a particular connection. Think
about it as a black box, from the outside you have a specified interface that works for
any kind of endpoint. However the endpoint itself implements various protocols so two
ends could talk with each other, either an endpoint talks with another similar
endpoint, or a with a service that talks the same protocol lingo.
Endpoints
All this means that it’s fairly easy for an application developer to understand the
endpoint APIs - they all look the same with some minor variations.
In practice you create an endpoint, initiate it, specify the options needed for
various communication protocols (speed, transfer rates and so on), send a Connect
message to the endpoint, read and write data from and to the endpoint, and finally
disconnect and dispose the endpoint. The endpoints also have more functions that we
won’t talk about in this introduction article.
So, how is this done in the Newton programming world? Here’s an example of an
endpoint frame definition:
/* 1 */
protoSerialEndpoint := {
// basic endpoint proto
__proto: protoEndpoint,
// options (array stored inside the configOptions slot)
configOptions: [
// basic serial port
{ label: kCMSAsyncSerial,
type: 'service,
opCode: opSetRequired },
// basic serial port options
{ label: kCMOSerialIOParms,
type: 'option,
opCode: opSetNegotiate,
data: { bps: k9600bps, dataBits: k8DataBits,
stopBits: k1StopBits, parity: kNoParity } },
// flow control (XON/XOFF)
{ label: kCMOInputFlowControlParms,
type: 'option,
opCode: opSetNegotiate,
data: { xonChar: unicodeDC1,
xoffChar: unicodeDC3,
useSoftFlowControl: true,
useHardFlowControl: nil
}
},
],
});
First we specify that we want to inherit the basic protoEndpoint behavior by
stating in the proto slot that we want to proto from the protoEndpoint (this contains
the basic behavior for all endpoints).
After this we want to spice the endpoint by defining what options we want to make
this a serial endpoint. We want to specify the speed, parity bit settings, stop bits and
flow control.
All options are stored in an internal slot called configOptions. The option settings
are valid before we create the actual instance of the endpoint specified. This means
that the settings should be set before or during the Instantiate method call. After that
the endpoint will happily continue with the earlier defined settings, and we need to do
some magic to re-configure the endpoint.
Looking more closely at the complicated option setting frame, we notice that we
have label slots, type slots, opCode slots and dataSlots. The label slot is the universal
option identifier, so we know that for instance we are dealing with an async serial
option setting. The type slot will contain the type of option, are we dealing with
service settings, or option settings? Service settings identify the actual
communication service. In this case we want an asynchronous serial service, so we
specify the constant kCMSAsyncSerial. You could use this slot for specifying IR
services, or ADSP services, or any other comms services.
Opcode slots identify how the service should deal with the actual option request.
We could for instance honor the request (opSetRequired) but if the option is
unbelievable or not available (let’s say a speed of 3 billion bps) the option setting will
fail. If we specify opSetNegotiate the service might substitute the 3 billion bps to
14.2kbps as a more reasonable value.
The data slot is used for further specifications of the options, such as actual speed
rates, XON/XOFF characters and so on.
If we dissect the kCMOSerialIOParms option, we would see that:
/* 2 */
// basic serial port options
{ label: kCMOSerialIOParms,
type: 'option,
opCode: opSetNegotiate,
data: { bps: k9600bps,
dataBits: k8DataBits,
stopBits: k1StopBits,
parity: kNoParity
}
},
We are indeed dealing with a service option ('option), and that we want to have
9600bps, 8 data bits, 1 stop bit, and no parity (the data slot constant values). We also
want to negotiate and the service could substitute some of the values to something else
if it’s not available. If this happens we need to use the GetOptions method to later see
how the endpoint is really configured.
State Machines
Another important concept to understand when writing Newton
communication-aware applications is the notion of state machines. Reading my Dragon
Book, state machines or state transition diagrams are used for defining actions that
take place when a certain state has been triggered.
Here’s a simplified example showing a state diagram of when I’m logging into a
UNIX system, and I’m trying to see if I could finger a user named sandvik on the
apple.com system.
From a pure textual point of view, here’s the session:
4.3 BSD UNIX ( apple.com)
login: sandvik
Password:
Last login: Sat Mar 19 12:32:59 from 17.205.4.47
4.3 BSD UNIX #44: Mon Feb 28 15:36:01 PST 1994
>>> Apple.com will be down on Saturday, 3/26/94 from
>>> noon until 9pm for a full monthly backup.
Sat Mar 19 12:37:51 PST 1994