Solved

Serial Linux C App Issues

Posted on 2006-07-18
9
324 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
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

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

Have you thought about creating an iPhone application (app), but didn't even know where to get started? Here's how: ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Important pre-programming comments: I’ve never tri…
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…
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use nested-loops in the C programming language.
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use while-loops in the C programming language.

696 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