home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
World of A1200
/
World_Of_A1200.iso
/
datafiles
/
text
/
c_manual
/
devices
/
serialdevice
/
serialdevice.doc
< prev
next >
Wrap
Text File
|
1995-02-27
|
64KB
|
1,839 lines
7 SERIAL DEVICE
7.1 INTRODUCTION
All Amiga models have a serial port to which you can connect
external devices like a modem, scanner or a printer with a
serial interface. Data can be sent in both directions, in
several different formats, like seven or eight bits, with
or without error checking etc.
On the Amiga the serial port consists of a 25 pin connector,
and can communicate with baud rate up to 32250. It is the
custom chip called "Paula" which contains a Universal
Asynchronous Receiver/Transmitter (UART) that takes care of
all serial data transmissions. The chip itself can manage
up to one million bits per second, but at that speed the data
buffer would be filled before the system had time to react,
and normal cables can not manage to transmit more than
100,000 - 200,000 bits per second.
Baud rates between 1200 and 9600 are in most cases more than
sufficient, and at that speed the computer will still be able
to multitask properly.
7.2 THE SERIAL PORT
The serial port sends and receives data in streams of bits.
In theory only one physical wire would therefore be required,
but there have been several extra cables added to send and
receive special information as well as to supply external
devices with power (+12V) and so on.
Since all data is sent bit by bit, and not as with the parallel
port which sends one byte (8 bits) each time, it is rather
slow. (Well at least not as fast as the parallel port, which
is fully documented in the next chapter.) However, since
some applications only works with one line, for example
the modems which are connected to the telephone system,
serial communication is easier to handle. Serial cables are
also much cheaper.
Although only one line is required there is a whole 25-pin
connector on the Amiga. Normal applications like a modem, or
a scanner only needs some of the lines, but since there are
so many possible lines to use, a lot of special equipment can
be connected to the serial port. (See illustration "RS-232".)
7.2.1 BYTE TO BITS AND VICE VERSA
Since the serial device only sends a stream of bits, a special
chip has to convert the data (bytes) to bits (8). The character
"A" would for example be transformed to 01000001 and "B" to
01000010 and so on. Of course the chip must also be able to
do the opposite, to convert an incoming stream of bits to
bytes.
--------
A (64) <- | | <- 01000001 (Receiving data)
| UART |
D (68) -> | | -> 01000100 (Transmitting data)
--------
The special chip that takes care of this is the "Universal
Asynchronous Receiver/Transmitter" usually referred to as
"UART". (See illustration "UART") Luckily we do not need to
bother too much about this. However, it is good to know what
is actually happening.
7.2.2 PIN ASSIGNMENT
The Amiga's serial port is a 25-pin D-female-type connector.
Below is an almost complete list of the pin assignment,
together with a short description. (See illustration "RS-232".)
Pin Amiga RS232 HAYES Direction Type Description
-------------------------------------------------------------------
1 SHIELD GND GND - Standard Ground
2 TXD TXD TXD Out Standard Transmit data
3 RXD RXD RXD In Standard Receive data
4 RTS RTS x - Out Standard Request to send
5 CTS CTS x CTS In Standard Clear to send
6 DSR DSR x DSR In Standard Data set ready
7 GND GND GND - Standard Signal ground
8 DCD DCD DCD In Standard Carrier detect
9 +12V - - - Amiga +12 Volt
10 -12V - - - Amiga -12 Volt
11 AUDO - - Out Amiga Audio output
12 - S.DS SI + - Speed indicate
13 S.CTS - + - RS232 code
14 - S.TXD - + - RS232 code
15 - TXC - + - RS232 code
16 - S.RXD - + - RS232 code
17 - RXC - + - RS232 code
18 AUDI - - In Amiga Audio in (not used)
19 - S.RTS - + - RS
20 DTR DTR x DTR Out Standard Data terminal ready
21 - SQD - - * (A1000 +5V)
22 RI RI RI In Standard Ring indicator
23 - SS - - * (A1000 +12V)
24 - TXC1 - - - 3.58 MHz clock
25 - - - - Amiga Reset (A1000)
(x) Used only if you have set the "seven-wire flag". Se below
for more information.
WARNING! Pin 21 and 23 are connected to the power supply on
the old Amiga 1000s (+5V and +12V). On all other models the
power is sent through pin 9 and 10. Be careful with this if
you intend to make serial cables! We do not want to burn the
user's external devices, do we?
7.2.3 THE DATA STREAM
Since all data is sent and received in a stream of bits, the
UART chip needs to know when each new byte (set of 8 bits) is
coming in. To make this possible, following rules have been
stated: (See illustration "Serial Bits".)
1. When no data is sent, a mark bit (1) is sent over and over.
2. Just before a byte is sent, a start bit (0) is transmitted.
The receiver will now know that seven or eight bits (depends
on what type of device it is) of data will be received.
3. An optional "parity" bit will come directly after the
data bits. The parity bit is used for error checking. The
receiver may use "even", "odd" or no parity at all. If
the receiver is using even parity, the sender should set
the parity bit to 1 if the remainder of all data bits
divided by two is 0, else the parity bit should be set to
0. If the receiver is using odd parity, the sender should
set the parity bit to 0 if the remainder of all data bits
divided by two is 0, else the parity bit should be set to
1. If the receiver does not use parity checking, either
set the parity bit to 0 or do not send any parity bit at
all.
4. Finally we need to send one (or two) stop bit(s) to tell
the receiver that the last data bit has been sent.
...1 0 0 0 1 0 0 0 1 0 1 0 0 0 1... -> -> ->
..._ _ _ _ _...
\_____/ \_____/ \_/ \_____/
^ ^
| ^ ^ ^ 8 7 6 5 4 3 2 1 0 ^ |
| | | | <-- Data bits --> | Mark bit(s)
| | | | (7 or 8 bits) |
| | | | Start bit
| | | |
| \ / Parity bit (We use even parity, hence 0)
| |
| One or two stop bits
|
Mark bit(s)
Even parity: The sum of the data bits is divided by two, and
if the remainder is 0, the parity bit should be
set to 1. If the remainder is 1, the parity bit
should be set to 0.
10100110 = 4 bits are set. 4/2 remainder = 0 -> parity = 1
01110110 = 5 bits are set. 5/2 remainder = 1 -> parity = 0
Odd parity: The sum of the data bits is divided by two, and
if the remainder is 0, the parity bit should be
set to 0. If the remainder is 1, the parity bit
should be set to 1.
10100110 = 4 bits are set. 4/2 remainder = 0 -> parity = 0
01110110 = 5 bits are set. 5/2 remainder = 1 -> parity = 1
The nice thing about the serial device is that we do not need
to bother about this. (So why did I write it?) You only have
to tell the device if you want to use parity, and if so if it
should use even (default) or odd parity. You should also tell
the serial device if you want to send seven or eight data bits,
and one or two stop bits. Once you have told the device what
you want, you do not need to think about it any more.
7.3 THE SERIAL DEVICE
The Serial Port is a limited resource it that sense that there
exist (normally) only one port. There may however be several
programs running at the same time which all want to use the
serial port. To make this possible they all have to coordinate
their work with the port. That is the serial device's main
task.
You can tell the device that you want a shared access, which
means that other programs may also use the serial port, or if
you want exclusive access, no other programs may use the
device. It is then up to the device if it will accept your
demands or else deny you the right to use the serial port.
(Another task may have exclusive access.)
Once you have been allowed to use the serial port, you should
send all your demands to the serial device, and it will take
care of everything. You only have to give it some information
like how it should work (eight or seven bits data, parity?
one or two stop bits, baud rate etc...) and where data should
be fetched/stored.
7.3.1 PREPARE THE SERIAL DEVICE
Before you should open the serial device you need to decide if
you want exclusive or shared access, and if you want to use the
special RTS/CTR, DTR/DSR ("seven-wire-mode").
1. If you want shared access, other programs may also use the
serial port, set the flag SERF_SHARED. (Se below.) If you
want exclusive access you do not need to set any flags,
since it is the default mode.
2. If you want to use the RTS/CTR, DTR/DSR handshaking
protocol ("seven-wire-mode") set the flag SERF_7WIRE.
7.3.2 OPEN THE SERIAL DEVICE
As with all devices you have to open a message port through
which the serial device can talk to you, and allocate a
request block (a IOExtSer structure), before you may open
the device itself.
1. Open a message port: (Since it is only our task and the
device that will use the message port, we do not need
to make it "public", hence no name. Priority should as
usual be set to 0, normal priority.)
struct MsgPort *replymp;
replymp = (struct MsgPort *)
CreatePort( NULL, 0 );
if( !replymp )
clean_up( "Could not create the reply port!" );
2. Allocate a request block of type IOExtSer structure.
(The IOExtSer structure is an extended version of the
normal request block, and should therefore be allocated
with help of the CreateExtIO() function with the size
set to sizeof( struct IOExtSer ).
struct IOExtSer *serial_req;
serial_req = (struct IOExtSer *)
CreateExtIO( replymp, sizeof( struct IOExtSer ) );
if( !serial_req )
clean_up( "Not enough memory!" );
Once the message port and the request block have successfully
been created, you should set the desired flags which were
explained above, and then open the serial device.
3. Set desired flags (only SERF_SHARED and SERF_7WIRE are
accepted), and open the device.
UBYTE error;
serial_req->io_SerFlags = SERF_SHARED|SERF_7WIRE;
error = OpenDevice( SERIALNAME, 0, serial_req, 0 );
if( error )
clean_up( "Could not open the Serial Device!" );
7.3.3 SET SERIAL PARAMETERS
Once the serial device has successfully been opened you should
set desired parameters like baud rate, seven or eight data bits
and so on. To set these parameters you initialize the request
block as described below, set the flag SDCMD_SETPARMS and
tells EXEC to execute your request with a DoIO() command.
Here is a list of parameters that should be initialized: (We
assume you have already opened the device as described above,
and have also created an IOExtSer structure with a pointer
named "ioreq" to it.
1. The serial device collects data and stores it in a
temporary buffer. Because of this it can read a lot of
data without any interruption, and once there is a break
the data in this temporary buffer is moved to the real
data buffer. The temporary buffer should be at least
512 bytes, but more is recommended, especially if you
want to collect a lot of data at high speed.
This temporary buffer is automatically created by the
serial device, and also automatically deallocated when
you close the device. If you have set one buffer size,
and later on changes the size, the old buffer will be
removed and a new buffer allocated. All data will then
be lost, so do not change the size of the buffer while
you are still collecting data.
The size is set in the io_RBufLen field of the request
structure. The size must be at least 512, but other
recommended sizes are 1024, 2048, 4096, 8192 or 16384.
To set the internal input buffer size to 8192 bytes do
like this:
ioreq->io_RBufLen = 8192;
2. You must tell the serial device at what speed it should
communicate (how many bits per second). It is important
that both the sender and receiver are using the same
speed.
You set the desired speed by initializing the io_Baud
field to one of the following baud rates (you may use
other speeds, but most applications expect you to use
on of the recommended speeds, and if it is to fast data
can be lost or corrupted): 110, 300, 1200, 2400, 4800,
9600, 19200 or 31250. To set the baud rate to 9600 do
like this:
ioreq->io_Baud = 9600;
3. Your program or the external device you are communicating
with can send a "break message", which will pause the
transmission for a specified time. This is useful if you
have received to many messages and you can not answer all
of them before more are arriving. A small break would in
this case be appreciated. A break signal simply stops the
communication for a specified number of microseconds.
You can set the number of microseconds the communication
should be down after a break signal by initializing the
io_BrkTime field. To set the break time to half a second
do like this:
ioreq->io_BrkTime = 500000;
4. If you want to read normal ASCII characters you only need
the first seven bits, and should therefore only try to
collect seven data bits instead of eight. However,
sometimes you want to receive whole bytes, and should then
collect all eight data bits.
To set the number of bits you want to read each time you
initialize the io_ReadLen field accordingly. To read eight
data bits do like this:
ioreq->io_ReadLen = 8;
5. Since you sometimes only want to send 7 data bits, but
other times want send all 8 data bits, you should
initialize the io_WriteLen field accordingly. To write
eight bits do like this:
ioreq->io_WriteLen = 8;
6. After each character you need to send one or two stop
bit(s), depending on what the other device expect.
Normally you only use one stop bit, but if you are using
seven data bits it happens that you should use two stop
bits. To tell the serial device to use one stop bit to
like this:
ioreq->io_StopBits = 1;
7. There exist some special modes that are selected by
setting some serial flags. Here is a complete list of
possible flags together with a short description:
SERF_XDISABLED Set this flag if you want to turn off
the XON-XOFF feature. Default is on.
SERF_EOFMODE Set this flag if you want the Serial
Device to send/collect data until it
finds one of the eight specified
"end-of-file" characters. (See below
for more information.)
SERF_SHARED Set this flag if you want to share the
serial port with other programs. Note
that this flag should only be used
BEFORE you have opened the device, and
should NOT be changed later on. If you
want to change status you should close
the serial device, alter the status and
then try to open it again.
SERF_RAD_BOOGIE Set this flag if you want to use the
serial port at high speed. When this
flag is set no parity is used, xON/xOFF
handling is turned off, no break signals
are allowed, and finally only eight-bit
characters are used. When you need fast
communication set this flag, but
remember that the data will then not be
error checked, and break signals are
ignored.
SERF_QUEUEDBRK Set this flag if you want break commands
to be queued along with all other
signals. The default is that a break
command interrupts the process
immediately.
SERF_7WIRE If the flag is set, the seven-wire
"handshaking" mode will be used.
(Default is three-wire.) With this flag
set you can use the RS232 RTS/CTS,
DTR/DSR commands. This flag should only
be used BEFORE when you have opened the
serial device, and should NOT be changed
after that. To change this mode, you
must close the device, set the desired
mode and then try to open it again.
SERF_PARTY_ODD Set this flag if you want to use odd
parity. (The default setting is even
parity.)
SERF_PARTY_ON Parity checking/writing is turned on.
(The sum of all data bits are divided by
two, and the remainder is the parity
bit. If even parity is used the bit will
be set to 1 if the remainder is even. If
odd parity is used the parity bit will
be set to 0 if the remainder is even.
You set desired flags in the io_SerFlags filed of the
request structure. If you want to set several flags, put
a "|" ("binary-OR") between. To set the parity on, and
use the end of character mode, do like this:
ioreq->io_SerFlags = SERF_PARTY_ON | SERF_EOFMODE;
Note! If you do not want to set any flags, remember to set
the field to 0. If you do not make sure it is empty, some
flags might accidentally be set.
8. There exist a special field where more serial flags can
be used in the future. For the moment there exist only two
flags for this field.
SEXTF_MSPON Set this flag if you want to use mark-space
parity rather than odd-even parity.
SEXTF_MARK If this and the SEXTF_MSPON flag is set, it
will Mark.
If you want to use the mark-space method, with mark, do
like this:
ioreq->io_ExtFlags = SEXTF_MSPON | SEXTF_MARK;
Note! If you do not want to set any of these flags, remember
to set the field to 0!
9. If you have set the flag "SERF_EOFMODE", the serial device
will send/collect data until it finds one of eight
specified "end-of-file" characters. These eight characters
are stored in a IOTArray structure which look like this:
struct IOTArray
{
ULONG TermArray0;
ULONG TermArray1;
};
Each ULONG data consists of four bytes, and in total you
can store eight bytes (end-of-file characters) in the
array. To make the checking routine efficient you must
store the characters in descending order! To copy the
desired characters into the array do like this:
/* Here is an array with all EOF characters: */
/* NOTE! They MUST be in descending order! */
UBYTE eof_char[8]={ 0x54, 0x32, 0x16, 0x15,
0x12, 0x03, 0x00, 0x00 };
/* Declare a unsigned byte pointer: */
UBYTE *ptr;
/* Simple loop variable: */
int loop;
...
/* Get the address of the IOTArray: */
ptr = (UBYTE *) &(ioreq->io_TermArray);
/* Set all eight end of file characters: */
for( loop=0; loop < 8; loop++ )
{
/* Copy character after character: */
*ptr = eof_chars[ loop ];
/* Step one byte foreward: */
ptr++;
}
Once you have set all desired parameters in the request block
(IOExtSer structure) you set the IO command to SDCMD_SETPARAMS
and tell the serial device to do your request by calling the
DoIO() function. If something went wrong DoIO() will return
with an error number, else 0 is returned which means that your
request have successfully been executed. (See below for a
complete list of error messages.)
ioreq->IOSer.io_Command = SDCMD_SETPARAMS;
error = DoIO( ioreq );
7.3.4 READ DATA
When you want to read data from the serial port, you have to do
four things. First you have to give the serial device a pointer
to a buffer where all data which you read will be stored.
(This memory buffer is not the same as the serial device's own
temporary input buffer that was explained above.)
Secondly you have to tell the device how many bytes/characters
you want to read. You do it by either telling the device
exactly how many characters you want to read, or set the
length to -1 which means you want to read continuously and stop
first when an end-of-file characters have been found. (Remember
to set the flag "SERF_EOFMODE", or the serial device will not
check for termination characters.)
Thirdly you have to set the command flag "CMD_READ", which
tells the serial device that you want to read data from the
serial port.
Finally you tell the serial device to do your request. You can
either put your program to sleep while the serial device is
reading data with a DoIO() call, or you use the SendIO()
function and continue to do something while all data is
collected. There exist even a special "quick" mode which
should be used if very fast communication is needed.
Here is an example on how to read data: (Your program will be
put to sleep while the data is collected.)
error: (UBYTE) is a simple unsigned byte variable.
ioreq: (struct IOExtSer *) is a pointer to an IOExtSer
structure.
data: (BYTE) is a pointer to a block of memory where all
data which is collected will be stored. Note that the
serial device will not check if it sends more data
than actually can be stored in the buffer. Innocent
memory can be corrupted if you do not make the buffer
big enough!
/* We want to read some data: */
ioreq->IOSer.io_Command = CMD_READ;
/* Give the start address of our data buffer: */
ioreq->IOSer.io_Data = data;
/* We want to read 400 bytes/characters: (The buffer must */
/* then be at least 400 bytes.) */
ioreq->IOSer.io_Length = 400;
/* Do our request: */
error = DoIO( ioreq );
/* Everything OK? */
if( error )
printf( "Problems while reading!\n" );
The program above will go to sleep while the data is collected
from the serial port. However, sometimes you may want to do
something while the data is fetched and not go to sleep.
Instead of using the function DoIO() you should then use the
asynchronous SendIO(). As explained in chapter 17 DEVICES, the
SendIO() will not wait for the request to be completed.
To check if the request have been completed or not you can
either use the function CheckIO(), or wait for a message to
arrive at the request block's reply port.
Once the request have been completed you can look at the
io_Error field of the request block to check if everything
was OK. If the field is zero everything was executed without
any problems, but if it is non zero the request failed.
Here is an example:
/* Declare a pointer and set it to NULL: */
struct IOExtSer *ptr = NULL;
...
/* We want to read some data: */
ioreq->IOSer.io_Command = CMD_READ;
/* Give the start address of our data buffer: */
ioreq->IOSer.io_Data = data;
/* We want to read 400 bytes/characters: (The buffer must */
/* then be at least 400 bytes.) */
ioreq->IOSer.io_Length = 400;
/* Do our request and return immediately: */
SendIO( ioreq );
/* As long as the pointer is not pointing to */
/* the request we should stay in the loop: */
while( ptr == NULL )
{
... do something ...
/* Check if the request has been completed: (If the */
/* request has been completed CheckIO() will return */
/* a pointer to the request, else NULL is returned.) */
ptr = CheckIO( ioreq );
}
/* Remove the request block's message. (The ptr and ioreq */
/* are in this example identical, so it does not matter */
/* whichever you will use. The parenthesis around the */
/* expression is actually unnecessary, but this looks */
/* better.) */
Remove( &(ptr->IOSer.io_Message.mn_Node) );
/* Everything OK? Check the io_Error filed: */
if( ioreq->IOSer.io_Error )
printf( "Problems while reading!\n" );
Finally their exist a special "quick" mode. It can only
sometimes be used and only for reading. This special mode
can be used when a lot of data at a very (!) high speed
should be collected. The "quick" mode is not the same as the
"SERF_RAD_BOOGIE" mode explained above. The quick mode can
only be used for reading, and there are some special
restrictions, while the high speed rad boogie mode can be
used both for reading and writing.
To use the quick mode you set the IOF_QUICK flag, before
you send the request. You should then not use the normal DoIO()
or SendIO() functions, but instead the low level BeginIO()
function. The BiginIO() is synchronous (like DoIO()) if we
were allowed to use quick mode, else the request is
asynchronous (like SendIO()).
Although you want to use the quick mode, it is not sure you
are allowed to do it. For some requests it is OK, others
will automatically remove the IOF_QUICK flag. You must
therefore check the request after you have posted it to
see if the IOF_QUICK flag is still on or not. If the flag was
removed, the quick mode was turned off and the request should
now be treated as those started with a SendIO() call (remember
to remove the message). However, it the flag is still there
the quick mode was used and we do not need (nor should) remove
any message at the reply port.
/* Initialize the request block as normal. */
/* ... */
/* Try to use the "quick" mode: */
ioreq->IOSer.io_Flags = IOF_QUICK;
/* Do the request: */
BeginIO( ioreq );
if( (ioreq->IOSer.io_Flags & IOFQUICK) )
{
/* OK! The request was using quick mode, which means */
/* that our task was put to sleep while the data was */
/* fetched, and the request have now been completed. */
/* Since we are using quick mode there are no message */
/* that should be removed. */
}
else
{
/* Too bad, we were not allowed to use the quick mode. */
/* The request should now be treated as if it was */
/* started with a SendIO() function call. This request */
/* is asynchronous - request returns immediately. */
/* We can either use the routine above with CheckIO() */
/* or put our task to sleep while we are waiting, by */
/* calling the WaitIO() function. The WaitIO() */
/* function will automatically remove the message, so */
/* we do not need to do anything more. However, if we */
/* used the function Wait(), we have to remove the */
/* messages ourself. */
WaitIO( ioreq );
}
The "quick" mode can only sometimes be used:
1. You may only read data. The "quick" mode is not allowed for
writing.
2. There is enough data in the internal input buffer so the
request will immediately be satisfied.
3. No other requests is using/waiting for the serial port.
7.3.5 WRITE DATA
When you want to write data to the serial port it is almost the
same procedure as when reading. The only difference is that you
set the command flag "CMD_WRITE".
Here is an example on how to write data to the serial port:
(Your program will be put to sleep while the data is moved to
the serial port.)
error: (UBYTE) is a simple unsigned byte variable.
ioreq: (struct IOExtSer *) is a pointer to an IOExtSer
structure.
data: (BYTE) is a pointer to a block of memory where all
data you want to send is stored.
/* We want to send (write) some data: */
ioreq->IOSer.io_Command = CMD_WRITE;
/* Give the start address of our data buffer: */
ioreq->IOSer.io_Data = data;
/* We want to send 150 bytes/characters: */
ioreq->IOSer.io_Length = 150;
/* Do our request: */
error = DoIO( ioreq );
/* Everything OK? */
if( error )
printf( "Problems while writing!\n" );
The program above will go to sleep while the data is copied to
the serial port. If you do not want the program to wait for the
request to be completed you should use SendIO(). The procedure
is very similar with reading.
To check if the request have been completed or not you can
either use the function CheckIO(), or wait for a message to
arrive at the request block's reply port.
Once the request have been completed you can look at the
io_Error field of the request block to check if everything
was OK. If the field is zero everything was executed without
any problems, but if it is non zero the request failed.
Here is an example:
/* Declare a pointer and set it to NULL: */
struct IOExtSer *ptr = NULL;
...
/* We want to send (write) some data: */
ioreq->IOSer.io_Command = CMD_WRITE;
/* Give the start address of our data buffer: */
ioreq->IOSer.io_Data = data;
/* We want to send 280 bytes/characters: */
ioreq->IOSer.io_Length = 280;
/* Do our request and return immediately: */
SendIO( ioreq );
/* As long as the pointer is not pointing to */
/* the request we should stay in the loop: */
while( ptr == NULL )
{
... do something ...
/* Check if the request has been completed: (If the */
/* request has been completed CheckIO() will return */
/* a pointer to the request, else NULL is returned.) */
ptr = CheckIO( ioreq );
}
/* Remove the requst block's message. (The ptr and ioreq */
/* are in this example identical, so it does not matter */
/* whichever you will use. The parenthesis around the */
/* expression is actually unnecessary, but this looks */
/* better.) */
Remove( &(ptr->IOSer.io_Message.mn_Node) );
/* Everything OK? Check the io_Error filed: */
if( ioreq->IOSer.io_Error )
printf( "Problems while writing!\n" );
You can not use the quick mode while you are sending data. If
you need fast communication you should set the serial flag
"SERB_RAD_BOOGIE". Note the restrictions mentioned above. (Only
eight-bit characters, and no parity checking etc...)
Since you usually will want to read and write data at the same
time, you have to use two separate request blocks. If you are
using shared access mode you simply create two request blocks
and open the serial device twice. (Do not forget to close both
requests later on.) Here is an example:
struct MsgPort *replymp;
struct IOExtSer *serial_req_read;
struct IOExtSer *serial_req_write;
UBYTE error;
/* We use only one reply message port: */
replymp = (struct MsgPort *)
CreatePort( NULL, 0 );
if( !replymp )
clean_up( "Could not create the reply port!" );
/* Create the request block "read": */
serial_req_read = (struct IOExtSer *)
CreateExtIO( replymp, sizeof( struct IOExtSer ) );
if( !serial_req_read )
clean_up( "Not enough memory!" );
serial_req_read->io_SerFlags = SERF_SHARED|SERF_7WIRE;
/* Create the request block "write": */
serial_req_write = (struct IOExtSer *)
CreateExtIO( replymp, sizeof( struct IOExtSer ) );
if( !serial_req_write )
clean_up( "Not enough memory!" );
serial_req_write->io_SerFlags = SERF_SHARED|SERF_7WIRE;
/* Open the serial device for the read request: */
error = OpenDevice( SERIALNAME, 0, serial_req_read, 0 );
if( error )
clean_up( "Could not open the serial device (Read)!" );
/* Open the serial device for the write request: */
error = OpenDevice( SERIALNAME, 0, serial_req_write, 0 );
if( error )
clean_up( "Could not open the serial device (Write)!" );
If you are using exclusive access mode you can of course not
open the serial device twice. Instead we have to copy the
first request block to the other request block, byte for byte.
Here is an example:
struct MsgPort *replymp;
struct IOExtSer *serial_req_read;
struct IOExtSer *serial_req_write;
BYTE *r_ptr;
BYTE *w_ptr;
UBYTE error;
int loop;
/* We use only one reply message port: */
replymp = (struct MsgPort *)
CreatePort( NULL, 0 );
if( !replymp )
clean_up( "Could not create the reply port!" );
/* Create the request block "read": */
serial_req_read = (struct IOExtSer *)
CreateExtIO( replymp, sizeof( struct IOExtSer ) );
if( !serial_req_read )
clean_up( "Not enough memory!" );
serial_req_read->io_SerFlags = SERF_SHARED|SERF_7WIRE;
/* Create the requestblock "write": */
serial_req_write = (struct IOExtSer *)
CreateExtIO( replymp, sizeof( struct IOExtSer ) );
if( !serial_req_write )
clean_up( "Not enough memory!" );
serial_req_write->io_SerFlags = SERF_SHARED|SERF_7WIRE;
/* Open the serial device for the read request: */
error = OpenDevice( SERIALNAME, 0, serial_req_read, 0 );
if( error )
clean_up( "Could not open the Serial Device (Read)!" );
/* Since we can not open the serial device once again */
/* for the write request, we have to copy the whole */
/* read request block into the write request block. */
/* Get the start address of both request blocks: */
r_ptr = (BYTE *) serial_req_read;
w_ptr = (BYTE *) serial_req_write;
/* Copy the request block, byte by byte: */
for( loop=0; loop < sizeof( struct IOExtSer ); loop++ )
{
/* Copy one byte: */
*w_ptr = *r_ptr;
/* Step one byte forward: */
w_ptr++;
r_ptr++;
}
Now we have two request blocks, and can therefore use both
read and write requests at the same time. If you also want to
use the special extra functions described further down, you
may want to create even one more request block (or maybe
even more...). The procedure is the same as described above.
7.3.6 ERRORS
While you are using the serial device several errors may
occur. The most common problem is that some other program is
already using the serial port, but it can happen that data has
been corrupted while reading/writing (the parity checking is
a simple way to find these errors).
There exit for the moment nine different types of serial port
errors, all defined in the header file "devices/serial.h".
You will receive the error message from the function you
just called, or you can check a request block to see if there
were any problems. (The io_Error filed of the request block
either contains 0, which means everything is OK, or an error
number.)
Here is a complete list of the serial error messages:
SerErr_DevBusy Some other task/request is already
using the serial device.
SerErr_BufErr: The serial device could not allocate
enough memory for the internal input
buffer.
SerErr_InvParam: The request block's parameters were not
properly initialized.
SerErr_LineErr: The serial cable is faulty or the other
device is not properly initialized or
not connected. Tell the user to check the
cables!
SerErr_ParityErr: The data you just sent/received contained
at least one byte which was corrupted.
Note that the serial flag "SERF_PARITY_ON"
must be set, else the device will not
check for errors.
SerErr_TimerErr: There was some problem with the timer.
SerErr_BufOverflow: The serial input buffer has been filled.
You should empty it as fast as possible
so you do not lose valuable information.
SerErr_NoDSR: No DSR.
SerErr_DetectedBreak: A break was detected.
While you are using the serial device it may happen that you
receive other error messages than described above. It is
then usually the Exec which sent them: (defined in the header
file "exec/errors.h")
IOERR_OPENFAIL The device (unit) could not be opened. (If you
are denied access to the serial device you
should receive the SerErr_DevBusy flag instead
of this exec message, but internally this flag
is used.)
IOERR_ABORTED When you abort a previously started request by
calling the AbortIO() function, the io_Error
filed of that request is set to IOERR_ABORTED.
If you find a request block with this flag set,
you know that it has been aborted.
IOERR_NOCMD You tried to use a command that is not
supported by the serial device.
IOERR_BADLENGTH The length of the request was not valid.
7.3.7 CLEAN UP
As usual on the Amiga you must remember to close and return
everything you have opened or allocated. If you do not close
the serial device after you, other programs will then not
be able to use the serial port. PLEASE be very careful about
this!
Here is a list of what you have to do:
1. All requests you have started with SendIO() or BeginIO()
(asynchronous commands) must either have been completed
or aborted before you may close the device. It is a very
common error to forget this, and it can be hard to find
this bug. Usually the program will work fine (the command
was completed in time), but now and then your program will
crash (the command was completed after the device have
been closed).
A simple way is to abort all commands that have not
reported that they have been completed, but this is not
always good way to do it. (The last commands may be
important and should therefore not be aborted.)
If you do not want to abort the command, you should
instead wait for it to be completed. The WaitIO()
function is simple to use, and will put your program
to sleep while waiting, so no computer time is wasted.
If the request has already been completed, the function
will return immediately. WaitIO() will also remove the
message from the reply port. It is a very useful and
simple function to use, but do NOT try to wait for
a request that has not been started! (It will then be
a very long wait, probably some million years before
the user realizes that he/she has to hit the reset keys.)
Here is an example on how to wait for a request to be
completed: (If the request already has been completed
it does not matter, WaitIO() will then simply return
immediately. Note that we do not have to remove any
messages from the reply port if we use WaitIO().)
/* Store possible error numbers here: */
UBYTE error;
/* ... */
/* Wait for the request to be completed: */
error = WaitIO( ioreq );
/* Everything OK? */
if( error )
printf( "Something went wrong!" );
/* Well, successful or not, we may now */
/* close the device! */
To abort a request, simply use the AbortIO() function:
/* Try to abort a previously started request: */
/* (Do not try to abort a request that has not */
/* been started.) */
AbortIO( ioreq );
2. When all requests have been completed or aborted you may
close the serial device. (Requests that have been executed
by calling the DoIO() function have already been completed
before your program wakes up, and thus you do not need to
wait for these.)
The serial device is closed as all other devices, by
calling the CloseDevice() function. Here is an example:
/* Close the Serial Device: */
if( !serial_dever )
CloseDevice( ioreq );
3. You should now return all request blocks you have
allocated. If you allocated a standard sized request block
by calling the CreateStdIO() function, you should free
it by calling the DeleteStdIO() function. However, if
you have allocated an extended request block (like the
serial device's request blocks) by calling the
CreateExtIO() function, you MUST call the DeleteExtIO(),
and of course remove the same amount of data as you
allocated.
How to delete a standard request block: (Since it is of
the standard size, you do not need to specify any size.)
/* Deallocate a standard sized request block: */
DeleteStdIO( ioreq );
With extended request block you have to specify the size
as you did when you allocated it:
/* Deallocate an extended request block: */
/* (The size may vary depending on what */
/* device it was used for.) */
DeleteExtIO( ioreq, sizeof( struct IOExtSer ) );
Note that ALL request blocks that have been allocated,
must be removed!
4. Finally you should close all message ports you have
previously opened. Simply use the DeletePort() function
as this example demonstrates:
/* Remove the replyport: */
DeletePort( replymp);
It can not be said to often. Please be careful with how your
program terminates! Your program should not only run fine,
but it should also allow other programs to run after and
simultaneously. Remember that your program must also be able
to quit nice and neatly even if it had to terminate too
early because of some fatale error. The cleaning up should
only be done where it is needed, and if you have not allocated
the memory or opened the device before your program quits, you
should of course NOT try to free these resources! If you do the
Amiga will most certainly crash! Too many programs contain this
very annoying error.
The best way to manage this cleaning up routine is to write a
separate function which checks each thing before it frees it.
The idea is that you may call this routine at any time, and it
will still manage to clear everything properly. Here is an
example: (Note how we check each thing to see if it should be
removed!)
/* Close and return everything that has been */
/* opened and allocated before we quit: */
void clean_up()
{
/* 1. Close the Serial Device: */
if( !serial_dever )
CloseDevice( serial_req );
/* 2. Deallocate the serial request block: */
if( serial_req )
DeleteExtIO( serial_req, sizeof( struct IOExtSer ) );
/* 3. Remove the replyport: */
if( replymp )
DeletePort( replymp);
/* 4. Quit: */
exit( 0 );
}
Comments: 1. The serial_dever is a variable that we have
declared ourself, and is used only to determine
if the device has been opened or not. (The
variable is set to TRUE before the program
starts, and is only changed to FALSE after
a successful opening of the device. See the
included examples for more information.) We
should of course only close the device if
the serial_dever is FALSE. ("serial_dever"
stands for "serial device error".)
2. The serial_req is a pointer which is either
pointing to a request block, or NULL if no
request block has been allocated. We should
of course only free the request block if there
exist one.
3. The replymp is a pointer which is either
pointing to a message port, or NULL if no message
port has been opened. And of course, we should
only close the message port if it has been
opened.
4. Finally our program may terminate. The exit()
function is placed here so we are sure the
program will quit. (If we did not have this
exit(), our function would then return the
control to our program again, and then we would
have serial (sorry, serious) problems.
7.4 A COMPLETE EXAMPLE
Here is a complete example that opens the serial device, sets
all necessary parameters, sends some data, collects some data
and finally cleans up and quits. Since we send the read and
write requests after each other (the first is completed before
the other is started) we only need to use one request block.
#include <exec/types.h>
#include <devices/serial.h>
/* Declare a pointer to our reply port: */
struct MsgPort *replymp = NULL;
/* Declare a pointer to our serial request block: */
struct IOExtSer *serial_req = NULL;
/* Store the serial device error here: */
UWORD serial_dever = TRUE;
/* Declare our own data buffer: (Big enough to hold 300 bytes.) */
BYTE buffer[ 300 ];
/* Declare our functions: */
void main();
void clean_up( STRPTR text );
void main()
{
int loop;
UBYTE *ptr;
UBYTE error;
/* The eight end-of-file characters: */
UBYTE eof_char[8]={ 0x06, 0x05, 0x04, 0x03,
0x02, 0x01, 0x00, 0x00 };
/* OPEN THE SERIAL DEVICE: */
/* Get a reply port: (No name, priority 0) */
replymp = (struct MsgPort *)
CreatePort( NULL, 0 );
if( !replymp )
clean_up( "Could not create the reply port!" );
/* Create a serial request block: */
serial_req = (struct IOExtSer *)
CreateExtIO( replymp, sizeof( struct IOExtSer ) );
if( !serial_req )
clean_up( "Not enough memory for the serial request block!" );
/* Open the Serial Device: */
serial_dever = OpenDevice( SERIALNAME, 0, serial_req, 0 );
if( serial_dever )
clean_up( "Could not open the Serial Device!" );
/* SET THE SERIAL PARAMETERS: */
/* Set the Serial Device's own input buffer to 512 bytes: */
serial_req->io_RBufLen = 512;
/* Set baud rate to 9600 baud: */
serial_req->io_Baud = 9600;
/* Set break time to half a second: */
serial_req->io_BrkTime = 500000;
/* Read 8 bits per character: */
serial_req->io_ReadLen = 8;
/* Write 8 bits per character: */
serial_req->io_WriteLen = 8;
/* Use 1 stop bit: */
serial_req->io_StopBits = 1;
/* Use parity and end-of-file characters: */
serial_req->io_SerFlags = SERF_PARTY_ON | SERF_EOFMODE;
/* No additional flags: */
serial_req->io_ExtFlags = NULL;
/* Set all eight end of file characters: */
ptr = (UBYTE *) &(serial_req->io_TermArray);
for( loop=0; loop < 8; loop++ )
{
/* Copy character after character: */
*ptr = eof_char[ loop ];
/* Step one byte forward: */
ptr++;
}
/* All values have now been set, lets do a SDCMD_SETPARAMS request: */
serial_req->IOSer.io_Command = SDCMD_SETPARAMS;
/* Do our request: */
error = DoIO( serial_req );
if( error )
clean_up( "Could not set the serial parameters!" );
/* SEND DATA TO THE SERIAL PORT: */
/* Put the data we want to send to the serial port into */
/* our own data buffer: (Well in this example we only */
/* send two bytes.) */
buffer[ 0 ] = 0x4C;
buffer[ 1 ] = 0x31;
/* We want to send (write) some data: */
serial_req->IOSer.io_Command = CMD_WRITE;
/* Give the start address of our data: */
serial_req->IOSer.io_Data = (APTR) buffer;
/* We want to send two bytes: */
serial_req->IOSer.io_Length = 2;
/* Do our request: */
error = DoIO( serial_req );
if( error )
clean_up( "Could not send data to the serial port!" );
/* READ DATA FROM THE SERIAL DEVICE: */
/* We want to read some data: */
serial_req->IOSer.io_Command = CMD_READ;
/* Give the start address of our buffer: */
serial_req->IOSer.io_Data = (APTR) buffer;
/* We want to read 0 bytes: */
/* (If you do not have anything connected to your serial */
/* port, we better not wait for any signals, thus read */
/* only 0 bytes.) */
serial_req->IOSer.io_Length = 0;
/* Do our request: */
error = DoIO( serial_req );
if( error )
clean_up( "Could not read data from the serial port!" );
/* THE END: */
clean_up( "The End" );
}
/* Close and return everything that has been */
/* opened and allocated before we quit: */
void clean_up( STRPTR text )
{
/* Close the Parallel Device: */
if( !serial_dever )
CloseDevice( serial_req );
/* Deallocate the serial request block: */
if( serial_req )
DeleteExtIO( serial_req, sizeof( struct IOExtSer ) );
/* Remove the replyport: */
if( replymp )
DeletePort( replymp);
/* Print the message: */
printf( "\n%s\n", text );
/* Quit: */
exit( 0 );
}
7.5 OTHER USEFUL COMMANDS
You can not only read and write from/to the serial port. There
exist several other functions that can sometimes be needed.
Here is a complete list:
1. Break, stop the serial device for a short time.
2. Clear, clear the input buffer.
3. Flush, removes all queued requests.
4. Query, get some information from the serial device.
5. Reset, reinitializes the serial device.
6. Start, restarts the serial communication.
7. Stop, temporary stops the serial communication.
7.5.1 BREAK
While you are sending or reading data you sometimes have to
take a small pause. Your program may for example need to empty
the data buffer, or coordinate its action with some other task.
To pause the serial device you simply send a break request,
and all communications is halted for a specified time.
You send a break signal by setting the io_Command field to
"SDCMD_BREAK". The default is that all serial requests are
immediately halted, but if the serial flag "SERF_QUEUEDBRK"
is set, the break command will be queued as all other requests
and the device will first take a break when all previous
requests have been completed.
The serial device will normally take a 250000 microseconds
(1/4 seconds) long break, but you may change this break time
by altering the serial device's "io_BrkTime" parameter.
Here is an example on how you can send a break command:
/* We want to take a pause: */
ioreq->IOSer.io_Command = SDCMD_BREAK;
/* Do our request: */
error = DoIO( ioreq );
/* OK? */
if( error )
printf( "Problems with the break!\n" );
7.5.2 CLEAR
While you are reading data from the serial device, it is
actually first stored in the internal input buffer, and then
moved to your own buffer when requested. If you want to clear
the buffer before you start to read you should set the
io_Command field to "CMD_CLEAR". Here is an example:
/* We want to clear the input buffer: */
ioreq->IOSer.io_Command = CMD_CLEAR;
/* Do our request: */
error = DoIO( ioreq );
/* OK? */
if( error )
printf( "Could not clear the input buffer!\n" );
7.5.3 FLUSH
If several requests are sent to the device they are all queued
on a FIFO (First In First Out) basis. The command "CMD_FLUSH"
can then be used to remove all these queued commands. Here
is an example:
/* We want to remove all queued requests: */
ioreq->IOSer.io_Command = CMD_FLUSH;
/* Do our request: */
error = DoIO( ioreq );
/* OK? */
if( error )
printf( "Could not remove the queued requests!\n" );
7.5.4 QUERY
The command "SDCMD_QUERY" can be used to get some information
from the serial device. It is useful if you want to see the
serial status and/or how many bytes there are already in the
internal input buffer. The "io_Status" field of the request
structure will be set as following table shows:
Bit Hex Active Description
---------------------------------------------------------------
0 0x0001 - Reserved
1 0x0002 - Reserved
2 0x0004 High Connected to par. "select" and ser. "ring"
3 0x0008 Low DSR - Data Set Ready
4 0x0010 Low CTS - Clear To Send
5 0x0020 Low DCD - Carrier Detect
6 0x0040 Low RTS - Ready To Send
7 0x0080 Low DTR - Data Terminal Ready
8 0x0100 High Read overrun
9 0x0200 High Break sent
10 0x0400 High Break received
11 0x0800 High Transmit X-OFF
12 0x1000 High Receive X-OFF
13 0x2000 - Reserved
14 0x4000 - Reserved
15 0x8000 - Reserved
---------------------------------------------------------------
The field "io_Actual" of the request structure contains the
number of bytes still left in the internal input buffer. Here
is an example:
/* Check the serial device: */
ioreq->IOSer.io_Command = SDCMD_QUERY;
/* Do our request: */
error = DoIO( ioreq );
/* OK? */
if( error )
printf( "Could not get any information from the device!\n" );
else
{
/* Check the "io_Status" field: */
if( ioreq->io_Status & 0x0200 )
printf( "A break request have just been sent!\n" );
/* Check number of characters left in the input buffer: */
printf( "Characters left: %ld\n", ioreq->IOSer.io_Actual );
}
7.5.5 RESET
Send the command "CMD_RESET" to reset the serial device. All
commands that are queued to the device will be removed, commands
that are currently executed will be aborted, the internal input
buffer will be cleared and reallocated to the default size and
finally all serial flags are resetted. Here is an example:
/* We want to reset the serial device: */
ioreq->IOSer.io_Command = CMD_RESET;
/* Do our request: */
error = DoIO( ioreq );
/* OK? */
if( error )
printf( "Could not reset the serial device!\n" );
7.5.6 START
After you have stopped the serial communication by sending an
X-OFF message to the other device, you may want to start the
communication again. It is done by sending an X-ON message,
and the external device will then know that it may start to
send/receive data. X-ON messages are sent to the other device
(as well to our self) by issuing a "CMD_START" command. Here
is an example:
/* We want to start serial communication again: */
ioreq->IOSer.io_Command = CMD_START;
/* Do our request: */
error = DoIO( ioreq );
/* OK? */
if( error )
printf( "Could not start the serial communication!\n" );
7.5.7 STOP
To temporary stop all serial communication you send a
"CMD_STOP" command. If you try to stop the communication an
X-OFF message will be sent to the external device (as well as
to all other programs currently using the serial device). When
a X-OFF message has been received, communication will first
start again when an X-ON message is sent. (See CMD_START.) Here
is an example:
/* We want to temporary stop all serial communication: */
ioreq->IOSer.io_Command = CMD_STOP;
/* Do our request: */
error = DoIO( ioreq );
/* OK? */
if( error )
printf( "Could not stop the serial communication!\n" );
7.6 FUNCTIONS
DoIO()
DoIO() is used to send requests to a device, and waits for it
to be completed. While the program is waiting it is put to
sleep so it will not waste any computer time. DoIO() will
return first when the request have been completed or failed,
and no message is therefore sent to the reply port.
Synopsis: error = DoIO( req );
error: (long) DoIO() will return first when the request has
been completed or something has failed. If the
request was successfully completed zero is returned,
else an error number is returned. What error number
depends on which device was used.
req: (struct IORequest *) Pointer to the request you
want to have executed.
SendIO()
SendIO() is used to send requests to a device, but will
return immediately without any delay. To check if the request
have been completed use the CheckIO() function, or look
at the request's reply port for any messages. Once the
request has been completed you must remove the message at
the reply port. (CheckIO() will not do it.) To remove a
message use the function Remove(). Note that you may NOT
close the serial device before all requests have been
completed or aborted!
Synopsis: SendIO( req )
req: (struct IORequest *) Pointer to the request you
want to have executed.
CheckIO()
CheckIO() is used to check if a previously started request
has been completed. Note that this function will not remove
the message at the reply port. This must be done with the
Remove() function.
Synopsis: ptr = CheckIO( req );
ptr: (long) CheckIO() will either return NULL if the
request have not been completed or it will return a
pointer to the request block.
req: (struct IORequest *) Pointer to the request you
want to check.
WaitIO()
WaitIO() will wait for the request to be completed, and while
the program is waiting it is put to sleep so no computer time
is wasted.
Synopsis: error = WaitIO( req );
error: (long) WaitIO() will return first when the request,
that has previously been sent, has been completed or
something has failed. If the request was successfully
completed zero is returned, else an error number is
returned. What error number depends on which device
was used.
req: (struct IORequest *) Pointer to the request you
want to wait for to be completed. Note that the
request must have already been sent to the device
by either a SendIO() or BeginIO() function call.
BeginIO()
BeginIO() is a low level form of the SendIO() function. The
advantage with BeginIO() is that no fields of the request
block will be altered as which is the case with SendIO(). If
you are for example using the "quick mode" you should not
use SendIO() since it will alter some of the data blocks.
BeginIO() is synchronous command if you use the quick mode,
but if you are not, the command will be asynchronous. Note
that you may NOT close the serial device before all requests
have been completed or aborted, so be careful with
asynchronous commands.
Synopsis: BeginIO( req )
req: (struct IORequest *) Pointer to the request you
want to have executed. BeginIO() will not alter any
values in this request structure as which is the case
with SendIO() and DoIO(). Normally this is not any
problem, and thus the SendIO() and DoIO() functions
should be used. However, with the Audio Device for
example some of these fields which are altered should
not be changed, and you should therefore use this
low level function BeginIO().
AbortIO()
AbortIO() will try to abort a previously started request. This
function should be used sparsely since it does not look so
good if you start a request and the try to stop it. (Better
not start it at all.) However, it is easy, and can sometimes
be very useful.
A request that is aborted will have its io_Error field set
to IOERR_ABORTED (defined in header file "exec/errors.h").
Synopsis: AbortIO( req )
req: (struct IORequest *) Pointer to the request you
want to abort.
CloseDevice()
CloseDevice() will (surprise!) close a device. If you close
the serial device the internal input buffer will
automatically be deallocated. Note that you should NOT close
the device before all started asynchronous requests have been
either completed or aborted.
Synopsis: CloseDevice( ioreq );
ioreg: (struct IORequest *) Pointer to the device's
request block.
OpenDevice()
OpenDevice() will try to open the specified device.
Synopsis: error = OpenDevice( name, unit, req, flags );
error: (long) If OpenDevice() managed to open the device
it returns 0, else an error number is returned.
If you try to open the serial device, and there is
already a program that is using it, the error
message "SerErr_DevBusy" is returned.
name: (char *) Name of the device you want to open.
The name of the serial device is defined as
SERIALNAME in header file "devices/serial.h".
unit: (long) Which unit you want to open. Since there
exist only one serial port, this field is ignored.
req: (struct IORequest *) Pointer to a request block.
For the serial device it must be a pointer to an
extender serial request block (struct IOExtSer).
flags: (long) Any special mode is set here. Ignored by
the serial device.
7.7 COMMANDS
Here is a complete list of commands you may send to the serial
device. For full documentation se examples above.
The special serial device commands: (Defined in header file
"devices/serial.h")
SDCMD_BREAK Sends a break signal.
SDCMD_QUERY Check the status of the serial device.
SDCMD_SETPARAMS Set the parameters of the serial device.
The rest of the commands you may use are normal exec commands,
and are defined in header file "exec/io.h".
CMD_RESET Resets all parameters of the serial device.
CMD_READ Read data from the serial port.
CMD_WRITE Write data to the serial port.
CMD_CLEAR Clears the internal input buffer.
CMD_STOP Temporary stops all serial communication. (X-OFF)
CMD_START Restarts serial communication. (X-ON)
CMD_FLUSH Removes all queued requests.
7.8 EXAMPLES
The included examples demonstrates how you can use the Serial
Device. It demonstrates most of the features described in this
chapter. Since I do not know what you have connected to your
serial port the examples will not do very much. However, the
examples are easy modify, so it should not be hard for you to
change them as desired.
Example 1
If you have a Sharp JX-100 scanner you can run this program
since it will try to turn the lamp on and then off again.
Very useful! (hmmm...) The program does not check if there
is any contact with the scanner, nor if the lamp really was
turned on or not. It simply demonstrates how to send data.
Example 2
This example is rather similar to Example 1, but this time
we do not wait for the serial port to complete our request.
Instead we do somethings (well not very much) and now and
then checks if the request has been completed. Using a busy
wait.
Example 3
This example is also rather similar to Example 1, but this
time we try to read and write at the same time. To be able
to do several requests simultaneously we need one request
block for each command. In this example we use three
separate request blocks. Using asynchronous commands but
puts the task to sleep just before we clear and return
everything.
Example 4
This example does not do anything, but it consists of
several useful functions that you can use yourself after
small modifications. The functions demonstrates all
commands there exist for the serial device, so if you
had problems in understanding how a command was used you
can look here.