Solved

Serial Linux C App Issues

Posted on 2006-07-18
9
312 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
ID: 17131462
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
ID: 17131507
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
ID: 17133669
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
Connect further...control easier

With the ATEN CE624, you can now enjoy a high-quality visual experience powered by HDBaseT technology and the convenience of a single Cat6 cable to transmit uncompressed video with zero latency and multi-streaming for dual-view applications where remote access is required.

 
LVL 8

Expert Comment

by:manish_regmi
ID: 17135318
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
 
LVL 8

Expert Comment

by:manish_regmi
ID: 17135324
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
ID: 17135445
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
ID: 17135672
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
ID: 17278801
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
ID: 17278937
Thanks for the assistance. Turns out the pinouts on the device required a NULL modem cable.

The settings worked well.
0

Featured Post

Best Practices: Disaster Recovery Testing

Besides backup, any IT division should have a disaster recovery plan. You will find a few tips below relating to the development of such a plan and to what issues one should pay special attention in the course of backup planning.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Summary: This tutorial covers some basics of pointer, pointer arithmetic and function pointer. What is a pointer: A pointer is a variable which holds an address. This address might be address of another variable/address of devices/address of fu…
Windows programmers of the C/C++ variety, how many of you realise that since Window 9x Microsoft has been lying to you about what constitutes Unicode (http://en.wikipedia.org/wiki/Unicode)? They will have you believe that Unicode requires you to use…
The goal of this video is to provide viewers with basic examples to understand recursion in the C programming language.
The goal of this video is to provide viewers with basic examples to understand and use switch statements in the C programming language.

840 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