This page will demonstrate how to send and receive data from the ADR112 or any other ADR interface, using Linux gcc programmes. It shows the commands used to configure the serial port, send data out through the serial port, and receive data through the serial port.
Additional help is available from the Linux HowTo documents found at a variety of locations around the web (hint: use a search engine). The man pages of your Linux system are invaluable as well. I make no effort to explain all of the parameters used in the various API calls. Read The Famous Manual.
This page is divided into several sections. The first section presents the source code with brief usage details. The second section shows pictorial examples and screen shots. Some troubleshooting hints are given in the second section. The third section describes some details (skip it if the first two sections provide what you need.)
I tested this program using Redhat 7.3, however I believe this code will operate correctly under all recent Linux kernels (your mileage may vary). The code was compiled with version 2.96-110 of the gcc compiler. Any recent vintage of the gcc compiler should be fine.
There are four files needed to compile the Linux example.
// adrport.h
// Copyright MMI, MMII by Sisusypro Incorporated
int OpenAdrPort (char* sPortNumber);
int WriteAdrPort(char* psOutput);
int ReadAdrPort(char* psResponse, int iMax);
void CloseAdrPort();
// adrport.c - Serial Port Handler
// Copyright MMI, MMII by Sisusypro Incorporated
// Permission is hereby granted to freely copy,
// modify, utilize and distribute this example in
// whatever manner you desire without restriction.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <string.h>
#include <errno.h>
#include "adrport.h"
static int fd = 0;
// opens the serial port
// return code:
// > 0 = fd for the port
// -1 = open failed
int OpenAdrPort(char* sPortNumber)
{
char sPortName[64];
printf("in OpenAdrPort port#=%s\n", sPortNumber);
sprintf(sPortName, "/dev/ttyS%s", sPortNumber);
printf("sPortName=%s\n", sPortName);
// make sure port is closed
CloseAdrPort(fd);
fd = open(sPortName, O_RDWR | O_NOCTTY | O_NDELAY);
if (fd < 0)
{
printf("open error %d %s\n", errno, strerror(errno));
}
else
{
struct termios my_termios;
printf("fd is %d\n", fd);
tcgetattr(fd, &my_termios);
// NOTE: you may want to save the port attributes
// here so that you can restore them later
printf("old cflag=%08x\n", my_termios.c_cflag);
printf("old oflag=%08x\n", my_termios.c_oflag);
printf("old iflag=%08x\n", my_termios.c_iflag);
printf("old lflag=%08x\n", my_termios.c_lflag);
printf("old line=%02x\n", my_termios.c_line);
tcflush(fd, TCIFLUSH);
my_termios.c_cflag = B9600 | CS8 |CREAD | CLOCAL | HUPCL;
cfsetospeed(&my_termios, B9600);
tcsetattr(fd, TCSANOW, &my_termios);
printf("new cflag=%08x\n", my_termios.c_cflag);
printf("new oflag=%08x\n", my_termios.c_oflag);
printf("new iflag=%08x\n", my_termios.c_iflag);
printf("new lflag=%08x\n", my_termios.c_lflag);
printf("new line=%02x\n", my_termios.c_line);
} // end if
return fd;
} // end OpenAdrPort
// writes zero terminated string to the serial port
// return code:
// >= 0 = number of characters written
// -1 = write failed
int WriteAdrPort(char* psOutput)
{
int iOut;
if (fd < 1)
{
printf(" port is not open\n");
return -1;
} // end if
iOut = write(fd, psOutput, strlen(psOutput));
if (iOut < 0)
{
printf("write error %d %s\n", errno, strerror(errno));
}
else
{
printf("wrote %d chars: %s\n", iOut, psOutput);
} // end if
return iOut;
} // end WriteAdrPort
// read string from the serial port
// return code:
// >= 0 = number of characters read
// -1 = read failed
int ReadAdrPort(char* psResponse, int iMax)
{
int iIn;
printf("in ReadAdrPort iMax=%d\n", iMax);
if (fd < 1)
{
printf(" port is not open\n");
return -1;
} // end if
strncpy (psResponse, "N/A", iMax<4?iMax:4);
iIn = read(fd, psResponse, iMax-1);
if (iIn < 0)
{
if (errno == EAGAIN)
{
return 0; // assume that command generated no response
}
else
{
printf("read error %d %s\n", errno, strerror(errno));
} // end if
}
else
{
psResponse[iIn<iMax?iIn:iMax] = '\0';
printf("read %d chars: %s\n", iIn, psResponse);
} // end if
return iIn;
} // end ReadAdrPort
// closes the serial port
void CloseAdrPort()
{
// you may want to restore the saved port attributes
if (fd > 0)
{
close(fd);
} // end if
} // end CloseAdrPort
// adrserial.c - Serial Port Test Example
// Copyright MMII by Sisusypro Incorporated
// WARNING: Example only. Lacks error checking!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "adrport.h"
// this is the mainline thingee
int main(int argc, char *argv[])
{
char sCmd[254];
char sResult[254];
if (argc < 2 || argc > 2)
{
printf("adrserial needs 1 parameter for the serial port\n");
printf(" ie. use 'adrserial 0' to connect to /dev/ttyS0\n");
return 0;
} // end if
printf("Type q to quit.\n\n");
if (OpenAdrPort(argv[1]) < 0) return 0;
while (1)
{
int iSpot;
printf("?:");
gets(sCmd);
if (sCmd[0] == 'q' || sCmd[0] == 'Q') return 0;
iSpot = strlen(sCmd);
sCmd[iSpot] = 0x0d; // stick a <CR> after the command
sCmd[iSpot+1] = 0x00; // terminate the string properly
if (WriteAdrPort(sCmd) < 0) return 0;
sleep(1); // give the ADR card some time to respond
if (ReadAdrPort(sResult,254) > 0)
{
printf("****Response is %s\n", sResult);
} // end if
} // end while
CloseAdrPort();
} // end main
CFLAGS=-g -Wall
adrserial: adrserial.c adrport.c
gcc -g -c -Wall adrserial.c -o adrserial.o
gcc -g -c -Wall adrport.c -o adrport.o
gcc adrport.o adrserial.o -o adrserial
Ontrak will send you a tarred and gzipped version of the above files (see bottom of this page), but it includes nothing beyond what is listed above.
First off, you have to grant permission to access the serial port. On my system I
logged in with root authority and used chmod to grant all users read/write access to the
serial port.
chmod o+rw /dev/ttyS0
The adrserial programme has a single parameter: the numeric value for the selected serial port. On my system the ADR card is connected to the first serial port which is known as /dev/ttyS0 in Linux. (please adjust the following instructions to match your system.)
Here is the ADR112 card that I used to test this programme.

There are several things to notice in the picture.
Here is a screen-shot of the adrserial programme starting up.

It commences with the command
./adrserial 0
followed by a number of lines of debug information. The ?: is a prompt to enter a command for the ADR112.
Here is a screen-shot of 2 ADR commands.

The first command, cpa00000000, sets PortA into output mode.
The second command, ma2, turns on the PA1 I/O line of the ADR card.
After these two commands the LED connected to PA1 is lit up.

The rpa command instructs the ADR card to report the status of all 8 lines on PortA.

The above screen-shot shows that PA1 is high (on) and all other PortA lines are low (off).
Prior to the next command I used the red wire to feed +5 volts to PA7. This caused the
LED on PA7 to light up.

Notice how both the LEDs on PA7 and PA1 are lit up. PA1 was turned on by the earlier ma2
command and PA7 is lit up by the current flowing in the red jumper wire.
An rpa command was sent to the ADR card eliciting the following response. 
This shows the ADR card reporting that line PA1 and line PA7 are high (on). All other
lines on PortA are low (off).
The remainder of this page contains some additional details that you may skip at your discretion. Some of this is directed at Linux newbies.
Do not call Ontrak and for help about this example. It is provided as a courtesy to show the operation of an ADR card in the Linux environment. It is not supported.
All the screen-shots show an xterm session running on a Gnome desktop. The caption bar shows the userid, jhomppi, and the machine name, guardian. (This machine normally operates as an Internet firewall.... hence guardian is its name).
The shell prompt is the userid followed by the directory in which the example resides:
[jhomppi:~/LinuxEg]$
The current directory (ie dot) is not in the path. Thus it must be specified in the command to start the programme:
./adrserial 0
The programme can be run from a normal tty console session (ie. command line). You do not need to start an xterm. You do not need to start the x-window environment.
When you have a numeric error code you will find that all of the man pages refer to #defined constants (eg EAGAIN). The /usr/include header files help you translate an error number into its constant.
On our development system (Redhat Linux 7.3) the file /usr/include/asm/errno.h contains a long list of defined error constants. Looking up the EAGAIN constant shows a value of 11.
Searching For Error Codes. You can use the "find" and "grep" commands to locate all the headers referring to a given defined constant. For example, the header files that refer to the EAGAIN constant can be listed with the following command:
find /usr/include -exec grep -l 'EAGAIN' {} \;
This example is based on information gleaned from many Internet Web sites. Special
accolades go to the following.
Thanks to all of the Linux and gcc developers, documenters and testers.
Thanks to Michael R. Sweet for his "Serial Port Programming Guide".
Thanks to Luis F. Guzman for explaining the "find" command on the Central
Indiana Linux Users Group page.
Thanks to Redhat for providing free ftp distribution of Linux.
This programme is free. Free of cost. Free of restrictions. You can use it, copy it,
modify it, distribute it and include it in your own application programme.
This programme is also free of any warranty, express or implied, for fitness or
merchantability. Use at your own risk.
I hope this assists your programming efforts.
John Homppi
To retrieve the Linux files used in this example (200K ) in ZIP format, click "LINUX EXAMPLE"
After you receive the LinuxEg.tar.gz file you must decompress it with:
gunzip LinuxEg.tar.gz
and then untar it with:
tar -xvf LinuxEg.tar