C programming communicate with realport on ubuntu linux

Here is my code, but I am unable to get the device to respond correctly. Anyone notice any problems with this code? I’m trying to write a command consisting of 3 numbers to a serial port on a circuit board to control a relay. The board is using a Digi ethernet interface.

   fd = open( portAddress, O_RDWR | O_NOCTTY | O_NDELAY );

    //check if serial port opened properly
    if (fd == -1 ) {
            syslog(LOG_INFO, "open_port: Unable to open %s", portAddress );
            printf("open_port: Unable to open %s", portAddress);
            return 0;
    } else {
            //set the port read function to return 0 if no data is available to read
          fcntl(fd, F_SETFL, FNDELAY);

            //get the current serial port settings, so we can restore them later
            tcgetattr(fd, &oldtio);
            tcgetattr(fd, &newtio);

            //set the speed of the serial port
            cfsetispeed(&newtio, B115200);  //input speed
            cfsetospeed(&newtio, B115200);  //also output speed

            newtio.c_cflag &= ~PARENB;  //no parity
            newtio.c_cflag &= ~CSTOPB;  //1 stop bit
            newtio.c_cflag &= ~CSIZE;  //clear data size bits
            newtio.c_cflag |= CS8;  //set data size to 8 bits
            newtio.c_cflag |= (CLOCAL);
            newtio.c_cflag &= ~CRTSCTS;  //no flow control
            newtio.c_cflag &= ~(IXON | IXOFF);
            newtio.c_lflag &= ~(ICANON | ECHO | ECHOE |ISIG);  //raw input, disable canonical input, no echo, no signals
            newtio.c_lflag &= ~(INPCK | ISTRIP);  //no parity check or strip parity bit

            newtio.c_oflag = 0;

            tcsetattr(fd, TCSAFLUSH, &newtio);  //make changes now with in/out flush

char command[ 3 ] = { char(254), char(116), char(1) };
int wr = write(fd, &command, 3);

One thing you’ll want to make sure of is that your Realport driver is properly installed/working. Are you able to “ditty-rp -a /dev/ttyxxx” with an actual Realport tty device and get a bunch of stty-like output?

If so, the device is valid and useable, in which case if your application fails you know its really the application, and non an improper driver install or something. If you can’t get a good output from ditty-rp, resolve that issue first.

I get this response from the ditty command. This is working I suppose?

onstr \033[5i offstr \033[4i term ansi
maxcps 100 maxchar 50 bufsize 100 edelay 100
-forcedcd -altpin -fastbaud (115200) -printer -rtstoggle
-rtspace -dtrpace -ctspace -dsrpace -dcdpace
DTR+ RTS+ CTS- CD- DSR- RI-
startc = 0x0 stopc = 0x0
-aixon astartc = 0x0 astopc = 0x0
speed 115200 baud; rows 0; columns 0; line = 0;
intr = ; quit = ; erase = ; kill = ; eof = ; eol = ; eol2 = ; swtch = ; start = ; stop = ;
susp = ; rprnt = ; werase = ; lnext = ; flush = ; min = 0; time = 0;
-parenb -parodd cs5 -hupcl -cstopb -cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany -imaxbel -iutf8
-opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
-isig -icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt -echoctl -echoke

What is the exact behavior seen when running the C code?

Based on the ditty results, it appears the port opened and the settings have been applied successfully (i.e. 115200 baud, -ixon -ixoff, etc…).

The program connects properly and updates settings on the serial port. I can verify this by reading the settings back from the port. The problem is that I don’t actually see the commands in the serial log on the device I’m communicating with. This is odd because I can accomplish this using the same port and a php script. When I try with this c code, I cannot succeed. When I run the program I see network traffic appear on the serial device that I’m trying to control. So I think a command of some sort is being sent to the device. Maybe I need to snoop the network packets and see what differs between the php script and c program.

Your open() and tcsetattr() look fine.

However, I believe your write() is incorrect, or at least, not doing what you are expecting it to do…

You are doing:
int wr = write(fd, &command, 3);

And instead, you should be doing:

int wr = write(fd, command, 3);

Also, BTW, the line:
char command[ 3 ] = { char(254), char(116), char(1) };
Is kind of weird.

Typically it would be written something more like:

char command[] = { 0xFE, 0x74, 0x1 };

Finally, one of the fun/cute ways to see what you are actually sending out your fd, is to “strace” the command.
(man strace)
With strace, it will show you the exact sequence of bytes you are writing/reading as well as a whole slew of other interesting tidbits of information about your program’s interaction with the system.

#include
#include
#include
#include
#include
#include
#include
#include
#include

int main()
{
int fd;
struct termios newtio, oldtio;

char command[3] = { char(254), char(108), char(1) };

    fd = open( "/dev/ttyS00", O_RDWR | O_NONBLOCK );

    //check if serial port opened properly
    if (fd == -1 ) {
            printf("open_port: Unable to open port");
            return 0;
    } else {
            //set the port read function to return 0 if no data is available to read

// fcntl(fd, F_SETFL, FNDELAY);

            //get the current serial port settings, so we can restore them later

            tcgetattr(fd, &newtio);

            newtio.c_cflag &= ~CSIZE;  //clear data size bits
                            
            //set the speed of the serial port
            cfsetispeed(&newtio, B115200);  //input speed
            cfsetospeed(&newtio, B115200);  //also output speed

            newtio.c_cflag &= ~PARENB;  //no parity
            newtio.c_cflag &= ~CSTOPB;  //1 stop bit
            newtio.c_cflag |= CS8;  //set data size to 8 bits
            newtio.c_cflag |= (CLOCAL);
            newtio.c_cflag &= ~CRTSCTS;  //no flow control

// newtio.c_cflag &= ~(IXON | IXOFF);
newtio.c_lflag &= ~(ICANON); //disable canonical input
newtio.c_lflag |= ISIG;
newtio.c_lflag &= ~( ECHO | ECHOE ); //raw input, no echo, no signals
newtio.c_lflag &= ~(INPCK | ISTRIP); //no parity check or strip parity bit

            newtio.c_oflag = 0;
	newtio.c_iflag = 0;

            tcsetattr(fd, TCSANOW, &newtio);  //make changes now with in/out flush

	write(fd, command, 3);

	tcflush(fd, TCIOFLUSH);

}
close(fd);

}

strace results for this program are as follows (partial, only from port open to close)

open(“/dev/ttyS00”, O_RDWR|O_NONBLOCK) = 3
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B115200 -opost isig -icanon -echo …}) = 0
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B115200 -opost isig -icanon -echo …}) = 0
ioctl(3, SNDCTL_TMR_START or TCSETS, {B115200 -opost isig -icanon -echo …}) = 0
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B115200 -opost isig -icanon -echo …}) = 0
write(3, “\376l\1”, 3) = 3
ioctl(3, TCFLSH, 0x2) = 0
close(3) = 0

Any ideas what I could possibly try to do. I am using realport compiled on ubuntu linux 9.10

You definitely do NOT want to do the tcflush() after doing a write!!!

That will just end up flushing away the bytes you were trying to write.

You should be using tcdrain() instead.

Also, your copy/paste from the strace look mistaken as well, at least this line:

write(3, “\376l\1”, 3) = 3

That “l” is there is odd, and I have to believe it was just a copy/paste issue here on the Forum.

You should be seeing the following from strace:
write(3, “\376\154\1”, 3) = 3

If you see that, then the open/write/close itself looks fine.

Next, we need to attack your tcsetattr().

I see you commented out turning off the IXON/IXOFF setting, which is fine.

If you turn it back on, be aware that you are setting the wrong set of flags.
You have it set to turn bits off of c_cflag. This is wrong, IXON/IXOFF are bits in the c_iflag value.

Now, I see you are setting CS8, but one of your above ditty -a outputs shows CS5.
I am guessing this is because you had the IXON/IXOFF line in there.
But you should verify now that you show CS8 in the ditty -a output.

YAY!!!
I just turned on a relay on my board using the following code. I think the tcdrain() is what I needed to write out the data. I had tried to use tcflush to accomplish this , but that was a mistake. Thank you so much for the help. I think I can proceed now.

#include
#include
#include
#include
#include
#include
#include

int main()
{
int fd;
struct termios newtio, oldtio;

    char command[3] = { char(254), char(108), char(1) };

    fd = open( "/dev/ttyS00", O_RDWR | O_NONBLOCK );

    //check if serial port opened properly
    if (fd == -1 ) {
            printf("open_port: Unable to open port");
            return 0;
    } else {
            //set the port read function to return 0 if no data is available to read

// fcntl(fd, F_SETFL, FNDELAY);

            //get the current serial port settings, so we can restore them later

            tcgetattr(fd, &newtio);

            newtio.c_cflag &= ~CSIZE;  //clear data size bits

            //set the speed of the serial port
            cfsetispeed(&newtio, B115200);  //input speed
            cfsetospeed(&newtio, B115200);  //also output speed

            newtio.c_cflag &= ~PARENB;  //no parity
            newtio.c_cflag &= ~CSTOPB;  //1 stop bit
            newtio.c_cflag |= CS8;  //set data size to 8 bits
            newtio.c_cflag |= (CLOCAL);
            newtio.c_cflag &= ~CRTSCTS;  //no flow control
            newtio.c_lflag &= ~(ICANON);  //disable canonical input
            newtio.c_lflag |= ISIG;
            newtio.c_lflag &= ~( ECHO | ECHOE );  //raw input,  no echo, no signals
            newtio.c_lflag &= ~(INPCK | ISTRIP);  //no parity check or strip parity bit

            newtio.c_oflag = 0;
            newtio.c_iflag = 0;

            tcsetattr(fd, TCSANOW, &newtio);  //make changes now with in/out flush

            write(fd, command, 3);

            tcdrain(fd);

    }
    close(fd);

}