A question about programming RS-232

Сергей Собко bug2bug at bug2bug.tk
Sat Sep 16 03:38:28 PDT 2006


Andrew Falanga wrote:
> I am by no means the worlds best serial programmer, but recently I have
> done some work on this subject and I noticed one thing in the code sample
> above that should be avoided.  However, I'll give you what I saw in-line:
>
>
> #include <stdio.h>
>
> > #include <termios.h>
> > #include <unistd.h>
> > #include <fcntl.h>
> >
> > int main(void) {
> > int t = 0, num = 10, fd, iOut; char *ch;
> > struct termios my_termios;
> > ch = (char *)malloc(6);
> > memset(ch, 250, 6);
> > fd = open("/dev/cuad0", O_RDWR | O_NONBLOCK);
>
> Ok, great, we've opened our serial device.  Unless you need this to be a
> controlling terminal, you should open with open( "/dev/cuad0", O_RDWR |
> O_NONBLOCK | O_NOCTTY );  Check with the open man page to make sure I've
> given you the correct constant for opening as a non-controlling terminal.
>
>
> printf("Opened com port\n");
>
> > if(fd < 0) return 0;
> > // tcflush(fd, TCIFLUSH);
> > my_termios.c_cflag = CS8 | CLOCAL;
> > if(cfsetspeed(&my_termios, B9600) < 0) return 0;
> > if(tcsetattr(fd, TCSANOW, &my_termios) < 0) return 0;
>
> You've set the attributes you want to use in the structure you defined,
> my_termios.  However, you should call tcgetattr() before changing what you
> want to change (and make sure you always turn things on as you have done
> above with bitwise or).  So, your code should look something like,
>
> // assume an open file descriptor named fd
> struct termios my_termios;
>
> if( tcgetattr( fd, &my_termios ) < 0 ) {
>    fprintf( stderr, "error in getting termios properties\n" );
>    return AN_ERROR;
> }
>
> // turn on what you want
> my_termios.c_cflag = CS8 | CLOCAL;
>
> if( tcsetattr( fd, &my_termios ) < 0 } {
>    fprintf( stderr, "error in setting new properties to serial port\n" );
>    return AN_ERROR;
> }
>
>
> I don't know if this will solve your problems but I do know I read that you
> should always get the current settings because the serial driver may use
> certain bits and you don't want to turn them off.  Also, if you're going to
> return the port settings to the state before you took hold of it, make two
> termios structures and stuff the original settings away to be restored upon
> exit or close of the port.
>
> Lastly, here is a link to a serial programming guide that I found quite
> helpful.  The info is probably dated to some degree, but it is non the less
> useful.
>
> http://www.easysw.com/~mike/serial/serial.html
>
> Andy

I have corrected, what you say, but it doesn't work at all!
The code I tryed:

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

int main(void) {
 int t = 0, num = 10, fd, i, iOut; char *ch;
 struct termios my_termios;
 ch = (char *)malloc(6);
 memset(ch, 50, 6);
 fd = open("/dev/cuad0", O_RDWR | O_NOCTTY | O_NDELAY);
 fcntl(fd, F_SETFL, 0);
 printf("Opened com port\n");
 if(fd < 0) return 0;
 if(tcgetattr(fd, &my_termios) < 0) return 0;
 printf("Got my_termios struct\n");
 if(cfsetspeed(&my_termios, B9600) < 0) return 0;
 printf("Set speed B9600\n");
 my_termios.c_cflag &= ~PARENB;
 my_termios.c_cflag &= ~CSTOPB;
 my_termios.c_cflag &= ~CSIZE;
 my_termios.c_cflag |= CS8;
 my_termios.c_cflag |= CLOCAL;
 my_termios.c_cflag |= CREAD;
 my_termios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
 my_termios.c_oflag &= ~OPOST;
 if(tcsetattr(fd, TCSANOW, &my_termios) < 0) return 0;
 printf("Setting my_termios attr\n");
 iOut = write(fd, ch, 6);
 if(iOut < 0) return 0;
 printf("Number of bytes = %d\n", iOut);
 printf("Writed %s!\n", ch);
 close(fd);
 printf("Closed!\n");
 return 0;
}

After executing it writes:

Opened com port
Got my_termios struct
Set speed B9600
Setting my_termios attr
Number of bytes = 6
Writed 222222!
Closed!

But! No effect ;(
I'm in shock! How can it work under Windows if it doesn't work in UNIX? May be 
I'm a lamer or I'm doing stupid things? But such code in Delphi using 
component TComPort works perfectly:



library cportio;

{ Important note about DLL memory management: ShareMem must be the
  first unit in your library's USES clause AND your project's (select
  Project-View Source) USES clause if your DLL exports any procedures or
  functions that pass strings as parameters or function results. This
  applies to all strings passed to and from your DLL--even those that
  are nested in records and classes. ShareMem is the interface unit to
  the BORLNDMM.DLL shared memory manager, which must be deployed along
  with your DLL. To avoid using BORLNDMM.DLL, pass string information
  using PChar or ShortString parameters. }

uses
  SysUtils,
  Classes,
  CPort,
  Forms,
  Windows,
  IniFiles;

var Com: TComPort;
const crlf: String = #10 + #13;
const Name: String = 'Com';
const xPort: String = 'COM1';
const xDataBits: TDataBits = dbEight;
const xStopBits: TStopBits = sbOneStopBit;
const xParityBits: TParityBits = prNone;
const xFlowControl: TFlowControl = fcNone;
const xBaudRate: TBaudRate = br9600;

{$R *.res}

function WriteComPort(xData: Integer): Integer; stdcall;
begin
Com := TComPort.Create(Application);
Com.Port := xPort;
Com.DataBits := xDataBits;
Com.StopBits := xStopBits;
Com.Parity.Bits := xParityBits;
Com.FlowControl.FlowControl := xFlowControl;
Com.BaudRate := xBaudRate;
Com.Open;
Com.WriteStr(chr(xData));
Com.Close;
Com.Free;
WriteComPort := 1;
end;

exports WriteComPort;
begin
end.


More information about the freebsd-questions mailing list