C program to write to the com port

Giorgos Keramidas keramida at ceid.upatras.gr
Sun Jul 31 15:06:43 GMT 2005


On 2005-07-31 22:50, Paul Hamilton <paulh at bdug.org.au> wrote:
> Hi,
>
> I am trying to write a C program that will send 3 bytes to the cuaa0 com
> port at 9600 baud, 8n1.  I am trying to control a Northlight 8 Channel Servo
> motor controller:
> http://home.att.net/~northlightsystems/DMX512toRCservo.htm
>
> Most of the code came from this page:
> http://www.easysw.com/~mike/serial/serial.html
>
> Here is what I have so far:-
> -----------------------------------------------------------------------
>
>     #include <sys/time.h>
>     #include <sys/ioctl.h>
>     #include <errno.h>
>     #include <fcntl.h>
>     #include <termios.h> /*Originally it was termio.h*/
>     #include <stdio.h>
>     #include <unistd.h>
>     static char *opt_comport="/dev/cuaa0";
>
> int main(int argc, char **argv)
> {
>     int n;
>     int dcf_dev;
>     int sdata =  0xFF0090;  // sync byte, address, servo value to be sent to
> the Servo Controller
>     struct termios options;
>
>     // ok, lets try opening the com port
>     printf("Opening Com port: %s\n\n", opt_comport);
>     if((dcf_dev = open(opt_comport, O_RDWR | O_NOCTTY | O_NDELAY)) < 0)
>       {
>          printf("Problems opening %s\n", opt_comport);
>          return (-1);
>       }
>     // set the required com port parrameters
>     options.c_cflag &= ~CSIZE;  /* Mask the character size bits */
>     options.c_cflag |= CS8;     /* Select 8 data bits */
>     options.c_cflag &= ~PARENB; // set no parity
>     options.c_cflag &= ~CSTOPB; // set 1 stop bit
>     options.c_oflag &= ~OPOST;  // Raw output
>
>     tcgetattr(dcf_dev, &options);
>
>     /*
>      * Set the baud rates to 9600...
>      */
>     cfsetispeed(&options, B9600);
>     cfsetospeed(&options, B9600);
>
>     /*
>      * Enable the receiver and set local mode...
>      */
>     options.c_cflag |= (CLOCAL | CREAD);
>
>     /*
>      * Set the new options for the port...
>      */
>     tcsetattr(dcf_dev, TCSANOW, &options);
>
>     // ok, lets transmit our 3 bytes to com port 1
>     n = write(dcf_dev, &sdata, 3);
>     if (n < 0)
>     fputs("write() of 3 bytes failed!\n", stderr);
>     printf("Output status: %d bytes written out\n", n);
>     exit(1);
> };
>
> -----------------------------------------------------------------------
>
> Now I am just a beginner at C code, so I feel pretty good getting this far
> (hey, it compiles :-)  However, a miss is as good as a mile, and so it
> doesn't work :-(   Having said that, I have a serial port LED breakout
> device watching, and I can see a blip on the TX line when I run the compiled
> program.  This is just meant to be test code, i.e.. Get it working before
> cleaning it up etc :-)
>
> I have tried connecting the computers serial port to another one, running:
> 'cu -s 9600 -l cuaa0' but I don't see anything.  Having said that, I don't
> see anything if I run the same on the other PC (yes, the TX-RX lines are
> swapped over), so maybe that is a problem with my serial cable between the
> two computers.
>
> The Servo Controller only needs two wires:  signal ground and TX  so not
> much to go wrong there, and as I said above, I do see a blip on the TX LED
> when I run the program.
>
> Questions:
>
> 1. Am I really sending the data correctly at 9600baud, 8n1?
>
> 2. Am I really sending the hex bytes:  FF 00 90  out (or am I sending an
> pointer address)?

No.  You are using:

	int sdata = 0xFF0090;

There's no guarantee that an ``int'' can hold a value greater than
0x7FFF.  This is the minimum required by the C standard (pp. 22 of
ISO/IEC 9899:1999(E)).  You should use types like uint32_t if you have
specific size requirements.

You are then passing this as a `buffer' to write(), but this is buggy
because you don't know (and shouldn't really care) what the endianess of
the machine you're using is.  This means that the value 0xFF0090, if we
do assume that sizeof(int) is 4 bytes, may be stored either as:

	Low memory addresses    ---->    High memory addresses
	00 FF 00 90		(big endian order)
	90 00 FF 00		(little endian order)

None of these is correct, as far as your real intention is concerned.

Try using a more explicit buffer-like structure for your data bytes,
like for instance:

	int fd;
	unsigned char buf[] = { 0xFF, 0x00, 0x90 };
	size_t buflen = sizeof(buf) / sizeof(buf[0]);

	if (write(fd, buf, buflen) != buflen)
		err(1, "write");



More information about the freebsd-questions mailing list