0

I am new to serail programing in Linux (Fedora 12) using C Language. I have a simple device, it is supposed to get 3 bytes command in hex (wirte) like {0x02,0x03,0x0D} and return 4 bytes response.

First I wrote a simple java program on windows, and I get the correct response.. as and when,I switch to linux, I can't read from serial com port neither using java nor C language.

I tried using libraries like rs232 .. but still the problem remains. I can open "/dev/ttyS0", and write on it .. (none of them returns any Error), but read is not possible ..

If I use canonical mode, the program blocks on reading until i kill the program.. If use non-canonical mode, with VMIN=0 and VTIME=5, read function returns whith -107725432 bytes for example .. (I have tried reading and writing byte by byte or all at the same time .. no difference ..)

rs232.c

#include "rs232.h"

int Cport[6],
    error;

struct termios new_port_settings,
       old_port_settings[6];

char comports[6][16]={"/dev/ttyS0","/dev/ttyS1","/dev/ttyS2","/dev/ttyS3","/dev/ttyS4","/dev/ttyS5"};

int RS232_OpenComport(int comport_number, int baudrate, const char *mode)
{
  int baudr,
      status;

  if((comport_number>5)||(comport_number<0))
  {
    printf("illegal comport number\n");
    return(1);
  }

  switch(baudrate)
  {
    case    2400 : baudr = B2400;
                   break;
    case    4800 : baudr = B4800;
                   break;
    case    9600 : baudr = B9600;
                   break;
    case   19200 : baudr = B19200;
                   break;

    default      : printf("invalid baudrate\n");
                   return(1);
                   break;
  }

  int cbits=CS8,
      cpar=0,
      ipar=IGNPAR,
      bstop=0;

  if(strlen(mode) != 3)
  {
    printf("invalid mode \"%s\"\n", mode);
    return(1);
  }

  switch(mode[0])
  {
    case '8': cbits = CS8;
              break;
    case '7': cbits = CS7;
              break;
    case '6': cbits = CS6;
              break;
    case '5': cbits = CS5;
              break;
    default : printf("invalid number of data-bits '%c'\n", mode[0]);
              return(1);
              break;
  }

  switch(mode[1])
  {
    case 'N':
    case 'n': cpar = 0;
              ipar = IGNPAR;
              break;
    case 'E':
    case 'e': cpar = PARENB;
              ipar = INPCK;
              break;
    case 'O':
    case 'o': cpar = (PARENB | PARODD);
              ipar = INPCK;
              break;
    default : printf("invalid parity '%c'\n", mode[1]);
              return(1);
              break;
  }

  switch(mode[2])
  {
    case '1': bstop = 0;
              break;
    case '2': bstop = CSTOPB;
              break;
    default : printf("invalid number of stop bits '%c'\n", mode[2]);
              return(1);
              break;
  }


  Cport[comport_number] = open(comports[comport_number], O_RDWR | O_NOCTTY);
  if(Cport[comport_number]==-1)
  {
    perror("unable to open comport ");
    return(1);
  }

  /* lock access so that another process can't also use the port */
  if(flock(Cport[comport_number], LOCK_EX | LOCK_NB) != 0)
  {
    close(Cport[comport_number]);
    perror("Another process has locked the comport.");
    return(1);
  }

  error = tcgetattr(Cport[comport_number], old_port_settings + comport_number);
  if(error==-1)
  {
    close(Cport[comport_number]);
    perror("unable to read portsettings ");
    return(1);
  }
  memset(&new_port_settings, 0, sizeof(new_port_settings));  /* clear the new struct */

  new_port_settings.c_cflag = cbits | cpar | bstop | CLOCAL | CREAD;
  new_port_settings.c_iflag = ipar;
  new_port_settings.c_oflag = 0;
  new_port_settings.c_lflag = 0;
  new_port_settings.c_cc[VMIN] = 0;      /* block untill n bytes are received */
  new_port_settings.c_cc[VTIME] = 5;     /* block untill a timer expires (n * 100 mSec.) */

  cfsetispeed(&new_port_settings, baudr);
  cfsetospeed(&new_port_settings, baudr);

  error = tcsetattr(Cport[comport_number], TCSANOW, &new_port_settings);
  if(error==-1)
  {
    close(Cport[comport_number]);
    perror("unable to adjust portsettings ");
    return(1);
  }

  if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)
  {
    perror("unable to get portstatus");
    return(1);
  }

  status |= TIOCM_DTR;    /* turn on DTR */
  status |= TIOCM_RTS;    /* turn on RTS */

  if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)
  {
    perror("unable to set portstatus");
    return(1);
  }

  return(0);
}


int RS232_PollComport(int comport_number, unsigned char *buf, int size)
{
  int n;

  n = read(Cport[comport_number], buf, size);

  return(n);
}

int RS232_SendBuf(int comport_number, unsigned char *buf, int size)
{
  return(write(Cport[comport_number], buf, size));
}


void RS232_CloseComport(int comport_number)
{
  int status;

  if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)
  {
    perror("unable to get portstatus");
  }

  status &= ~TIOCM_DTR;    /* turn off DTR */
  status &= ~TIOCM_RTS;    /* turn off RTS */

  if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)
  {
    perror("unable to set portstatus");
  }

  tcsetattr(Cport[comport_number], TCSANOW, old_port_settings + comport_number);
  close(Cport[comport_number]);

  flock(Cport[comport_number], LOCK_UN); /* free the port so that others can use it. */
}


 void RS232_flushRXTX(int comport_number)
{
  tcflush(Cport[comport_number], TCIOFLUSH);
}

and

main.c

    #include <stdlib.h>
    #include <stdio.h>  
    #include <unistd.h>          
    #include "rs232.h"
    
    int main()
    {
        int  cport_nr=0,   bdrate=9600;     /* 9600 baud */
        
        char mode[]={'8','N','1',0},
        str[512];
             
        unsigned char buf[6000];
        memset(buf, '\0' , 6000);
        int buf_SIZE=sizeof(buf);

        if(RS232_OpenComport(cport_nr, bdrate, mode))
        {
           printf("Can not open comport\n");
         
           return(0);
        }
        unsigned char wr_buff[5];
        memset(wr_buff, '\0', 5);
        wr_buff[0] = 0x02;
        wr_buff[1] = 0x01;
        wr_buff[2] = 0x0D;

        int cnt = RS232_SendBuf(cport_nr, wr_buff, 3);
     
        printf("Number of bytes that has been written: %d\n",cnt);
        
        if (cnt <= 0 )
            return(-1);
        cnt =0 ;
        
        usleep(100000);
        printf("Start Reading ... \n");
        
        
        int i = 0;
        do {
        cnt = RS232_PollComport(cport_nr,(buf+i), 1);
        i++;}
        while(cnt>0);
                
        printf ("%d bytes have been read\n");
                        
        RS232_CloseComport(cport_nr);

return (1);
}

I am really confused .. I tried almost every samples on the Internet .. An

y Idea Please?! I have traced the program, using strace ..

...

write(3,"\2\3\r",3) = 3

fstat64(1 , {st_mode=S_IFREG| 0755, st_size =0,..}) = 0

mmap2(NULL,4096,PROT_READ|PROT_WRITE, MAP_PRIVATE| MAP_ANONYMOUS,-1,0) = 0Xb78b4000

nanosleep({0, 100000000}, NULL) = 0

read(3,"",1) = 0

.....

Can the problem be related to fedora12?

P.S. : if I haven't got response in windows, I was sure that its a problem with the device.

5
  • Please show your code. We can't find problems in something we can't see. Commented May 8, 2016 at 11:25
  • Using memset() to initialize the termios structure is often done but still wrong; use tcgetattr() instead. You have done a poor job of providing the shortest code necessary to reproduce the problem. Commented May 9, 2016 at 2:00
  • @sawdust I can't understand what you mean by the shortest code?!! I have copied all the code with its details .., also how can I initialize termios with tcgetattr()??!! Commented May 9, 2016 at 4:33
  • You have the full lib of Linux and Windows source code. We should not have to play preprocessor to read the code. E.G. get rid of #ifdef ...#endif dead code. See Setting Terminal Modes Properly Commented May 9, 2016 at 6:37
  • @sawdust I am sorry, I am new to asking questions like this .. I have reduced the details .. I should use 9600 baudrate, databits_8 , no parity, no flow control and 1 stopbits .. input and output data should be in HEX .. this sample works for others when I search on the Internet .. but it doesn't work in my case !! and I Have no idea ... plz give me ideas to check what other things?! Commented May 9, 2016 at 7:20

1 Answer 1

1

Solved ...

it was a mistake of me ... In fact, every thing was ok, the problem was in the way I print number of bytes have been read.. I had forgotten to put "cnt" in respect of %d ...

printf ("%d bytes have been read\n"); --> printf ("%d bytes have been read\n",cnt);

also i should have read only 4 bytes based on the protocol of communication with my device ..

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.