Solved

Serial Linux C App Issues

Posted on 2006-07-18
9
301 Views
Last Modified: 2010-05-18
I have a SmartRelay device that I need to create a "driver" for. I'm just trying to get this working at a very simple level first and then continue from there.

I can drive the SmartRelay device from HyperTerminal in windows with 9600 8n1 settings and everything works successfully.

I have been able to capture the output from my comtest.c driver in HyperTerminal and it displays as expected.

Here is the c code:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>

/* baudrate settings are defined in <asm/termbits.h>, which is
included by <termios.h> */
#define BAUDRATE B9600
/* change this definition for the correct port */
#define DEVICE "/dev/ttyS0"

#define FALSE 0
#define TRUE 1

int open_port(void)
{
      int fd;
      
      fd = open(DEVICE, O_RDWR | O_NOCTTY | O_NDELAY);
      if (fd == -1)
      {
            perror("open_port: Unable to open port - ");
      }
      else
      {
            fcntl(fd, F_SETFL, 0);
      }
      
      return (fd);
}

int main()
{
      int fd,c, res;
      struct termios oldtio,newtio;
      char buf[255];
      char mystring[255];
      /*
      Open modem device for reading and writing and not as controlling tty
      because we don't want to get killed if linenoise sends CTRL-C.
      */
printf("open port\n");
      fd = open_port();
      if (fd < 0) {
            perror(DEVICE);
            exit(-1);
      }
printf("port opened\n");      
      tcgetattr(fd,&oldtio); /* save current serial port settings */
printf("got attribs\n");      
      bzero(&newtio, sizeof(newtio)); /* clear struct for new port settings */
printf("zeroed attribs\n");      
      /*
            BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed.
            CRTSCTS : output hardware flow control (only used if the cable has
                              all necessary lines. See sect. 7 of Serial-HOWTO)
            CS8     : 8n1 (8bit,no parity,1 stopbit)
            CLOCAL  : local connection, no modem contol
            CREAD   : enable receiving characters
      */
      newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD;
      
      /*
            IGNPAR  : ignore bytes with parity errors
            ICRNL   : map CR to NL (otherwise a CR input on the other computer
                              will not terminate input)
                              otherwise make device raw (no other input processing)
      */
      newtio.c_iflag = IGNPAR | ICRNL;
      
      /*
      Raw output.
      */
      newtio.c_oflag = 0;
      
      /*
            now clean the line and activate the settings for the port
      */
printf("tcflush\n");      
      tcflush(fd, TCIFLUSH);
printf("tcsetattr\n");      
      tcsetattr(fd,TCSANOW,&newtio);
      
      /*
            terminal settings done, now handle input
            In this example, inputting a 'z' at the beginning of a line will
            exit the program.
      */

      printf("writing to port\n");
      if (-1 == write(fd, "1R1\r", 4))
      {
            perror("Error writing 1R1\n");
            exit(1);
      }
      sleep(1);
      if (-1 == write(fd, "1R0\r", 4))
      {
            perror("Error writing 1R0\n");
            exit(1);
      }
      sleep(1);
      if (-1 == write(fd, "2R1\r", 4))
      {
            perror("Error writing 2R1\n");
            exit(1);
      }
      sleep(1);
      if (-1 == write(fd, "2R0\r", 4))
      {
            perror("Error writing 2R0\n");
            exit(1);
      }
      sleep(1);
      if (-1 == write(fd, "3R1\r", 4))
      {
            perror("Error writing 3R1\n");
            exit(1);
      }
      sleep(1);
      if (-1 == write(fd, "3R0\r", 4))
      {
            perror("Error writing 3R0\n");
            exit(1);
      }
      sleep(1);
      
      /* restore the old port settings */
printf("restore attribs\n");      
      tcsetattr(fd,TCSANOW,&oldtio);
}

Here is the stty from the comport after breaking within the application:
[root@ScanVue bin]# stty < /dev/ttyS0
speed 9600 baud; line = 0;
intr = <undef>; quit = <undef>; erase = <undef>; kill = <undef>; eof = <undef>;
start = <undef>; stop = <undef>; susp = <undef>; rprnt = <undef>;
werase = <undef>; lnext = <undef>; flush = <undef>; min = 0; time = 0;
-brkint -imaxbel
-opost -onlcr
-isig -icanon -iexten -echo -echoe -echok -echoctl -echoke
0
Comment
Question by:r_i_x
  • 5
  • 3
9 Comments
 
LVL 8

Expert Comment

by:manish_regmi
Comment Utility
hi r_i_x,
    You are not using any of the old attributes but using your new. In the new structure, you have only used few attributes. the rest is set to zero.

but you should copy the old attributes to new attributes and change only the attributes you need.


struct termios oldtio,newtio;

 tcgetattr(fd,&oldtio); /* save current serial port settings */
memcpy(&newio, &oldio, sizeof(struct termios));
 newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD;
...... whatever you want to change
tcsetattr(fd,TCSANOW,&newtio);


regards
Manish Regmi
0
 
LVL 8

Expert Comment

by:manish_regmi
Comment Utility
the problem with your code was that after you set the terminal attributes, a lot of attributes was set to 0,

like
c_cc array.
so all the characters will be set to 0, like
VEOF, VEOL, VERASE, VKILL

so, the terminal driver will take EOF, EOL etc as 0.

regards
Manish Regmi
0
 
LVL 1

Author Comment

by:r_i_x
Comment Utility
Thanks for the help. I've added that code but I don't think it has made a difference (although likely it is cleaner). Here is the stty output now:

[root@ScanVue bin]# stty < /dev/ttyS0
speed 9600 baud; line = 0;
min = 1; time = 0;
-brkint -icrnl -imaxbel
-opost -onlcr
-icanon -echo -echoe -echok -echoctl -echoke

The data I'm sending is simply "1R1\r". The first 3 chars are a command and then a carriage return.

Supposed to be setup with 9600bps, 8 data bits, parity = none, 1 stop bit, and no flow control. Does the stty show this correctly?
0
 
LVL 8

Expert Comment

by:manish_regmi
Comment Utility
it has corrected your our output

previously, it was
ntr = <undef>; quit = <undef>; erase = <undef>; kill = <undef>; eof = <undef>;
start = <undef>; stop = <undef>; susp = <undef>; rprnt = <undef>;

it meant that all those characters were undefined. means you could not use any of those control characters like kill, erase start etc.

-icanon -echo -echoe -echok -echoctl -echoke
means canonical mode and echo is on

see this howto
http://www.erlenstar.demon.co.uk/unix/faq_4.html

regards
Manish Regmi

0
Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

 
LVL 8

Expert Comment

by:manish_regmi
Comment Utility
also see what posix has to say on terminal i/o

http://www.opengroup.org/pubs/online/7908799/xbd/termios.html

regards
Manish Regmi
0
 
LVL 1

Author Comment

by:r_i_x
Comment Utility
Can you tell by what I've posted if I have everything setup properly for 8n1 and no harware flow control?
0
 
LVL 8

Accepted Solution

by:
manish_regmi earned 500 total points
Comment Utility
ooh,
 newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD;

should be

newtio.c_cflag &= ~CSIZE; // turn of other bits if already set
newtio.c_cflag |= CS8;    // set cs8 bit only

 newtio.c_cflag |= BAUDRATE | CLOCAL | CREAD;

regards
Manish Regmi



0
 

Expert Comment

by:KubaOber
Comment Utility
Long time ago I've posted a relatively generic way of setting an arbitrary baudrate for most Linux serial devices. Here's the link:
http://hrabia.ibib.waw.pl/~winnie/baudrate.html

This is mildly related to your question; it will come handy if you ever have to deal with non-standard baud rates.
0
 
LVL 1

Author Comment

by:r_i_x
Comment Utility
Thanks for the assistance. Turns out the pinouts on the device required a NULL modem cable.

The settings worked well.
0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

Preface I don't like visual development tools that are supposed to write a program for me. Even if it is Xcode and I can use Interface Builder. Yes, it is a perfect tool and has helped me a lot, mainly, in the beginning, when my programs were small…
This is a short and sweet, but (hopefully) to the point article. There seems to be some fundamental misunderstanding about the function prototype for the "main" function in C and C++, more specifically what type this function should return. I see so…
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use for-loops in the C programming language.
The goal of this video is to provide viewers with basic examples to understand and use conditional statements in the C programming language.

771 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now