Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Read Write serial port

Reply
Thread Tools

Read Write serial port

 
 
collinm
Guest
Posts: n/a
 
      03-21-2005
hi

we use linux and c language


under bash i do
echo -e \\000\\000\\000\\000\000\\001Z00\\002AA LINUX \\004 >/dev/ttyS2

that send command to a led display (alpha sign communication)

i need to do convert this code to a c programm under linux

i tried this code:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <stdio.h>

/* File descriptors for the ports */
int fd1, fd2;
char *buff,*buffer,*bufptr;

/* Opening port one for read and write */
int open_port1(void)
{
fd1 = open("/dev/ttyS2", O_RDWR | O_NOCTTY | O_NDELAY);
if (fd1 == -1)
{
perror("open_port: Unable to open /dev/ttyS0 - ");
}
else
{
fcntl(fd1, F_SETFL, 0);
printf(" Port 1 has been sucessfully opened and %d is the file
descriptor\n",fd1);
}
return (fd1);
}

int open_port2(void)
{
fd2 = open("/dev/ttyS2", O_RDWR | O_NOCTTY | O_NDELAY);
if (fd2 == -1)
{
perror("open_port: Unable to open /dev/ttyS0 - ");
}
else
{
fcntl(fd2, F_SETFL,FNDELAY);
printf(" Port 2 has been sucessfully opened and %d is the file
descriptor\n",fd2);
}
return (fd2);
}

int main()
{
int wr,rd;
open_port1();
open_port2();

char msg[]="\\000\\000\\000\\000\\000\\001Z00\\002AA LINUX \\004";

wr=write(fd1,msg,100);

printf(" Bytes sent are %d \n",wr);
if (wr < 0)
fputs("write() of 4 bytes failed!\n", stderr);
else
printf(" Stuff has been written into port 1\n");
sleep(1);

fcntl(fd2, F_SETFL,FNDELAY);
rd=read(fd2,buff,100);
printf(" Bytes recieved are %d \n",rd);
printf("%s",buff);

close(fd1);
close(fd2);
return 1;
}



but nothing happen on the led display

any idea?

 
Reply With Quote
 
 
 
 
Ulrich Eckhardt
Guest
Posts: n/a
 
      03-21-2005
collinm wrote:
> we use linux and c language


<irony> but you don't use shift keys</irony>

> echo -e \\000\\000\\000\\000\000\\001Z00\\002AA LINUX \\004 >/dev/ttyS2
>
> that send command to a led display (alpha sign communication)
>
> i need to do convert this code to a c programm under linux


> int fd1, fd2;
> int open_port1(void)
> {
> fd1 = open("/dev/ttyS2", O_RDWR | O_NOCTTY | O_NDELAY);
> if (fd1 == -1)
> {
> perror("open_port: Unable to open /dev/ttyS0 - ");
> }
> else
> {
> fcntl(fd1, F_SETFL, 0);
> printf(" Port 1 has been sucessfully opened and %d is the file
> descriptor\n",fd1);
> }
> return (fd1);
> }


Bad idea: returning a value and storing it in a global at the same time.
Later on ignoring the returnvalue and using the global. Time for
refactoring.

> char msg[]="\\000\\000\\000\\000\\000\\001Z00\\002AA LINUX \\004";
>
> wr=write(fd1,msg,100);


Your mistake is that you don't know what gets sent through the serial port.
Seriously, the 'echo -e ..' is something you type at a sh prompt (I assume
you use sh or some similar shell). This line is subject to having certain
characters (in particular the backslash) interpreted specially before
invoking 'echo'. 'echo' in turn interprets another set of characters
specially before sending anything to its stdout. Now, the same scheme
applies to C sourcecode, which interprets the content of string literals
to generate binary strings.

IOW, you have to read manuals to first find out what gets sent to the
serial port and can then start redoing the same under C.

Uli

 
Reply With Quote
 
 
 
 
Walter Roberson
Guest
Posts: n/a
 
      03-21-2005
In article <(E-Mail Removed) .com>,
collinm <(E-Mail Removed)> wrote:
:we use linux and c language

;under bash i do
;echo -e \\000\\000\\000\\000\000\\001Z00\\002AA LINUX \\004 >/dev/ttyS2

:that send command to a led display (alpha sign communication)

:i need to do convert this code to a c programm under linux

:i tried this code:

:/* Opening port one for read and write */
:int open_port1(void)

Your code for open_port1() is the same as your code for
open_port2() except for the message about which port was opened.
In particular, it is bug-for-bug identical in claiming to open S0 but
really opening S2.

: fd1 = open("/dev/ttyS2", O_RDWR | O_NOCTTY | O_NDELAY);

Why are you setting a global variable with the fd number, and
then ignorning the fd value returned by the routine? Don't mix
metaphors.

: char msg[]="\\000\\000\\000\\000\\000\\001Z00\\002AA LINUX \\004";

That doesn't correspond to what you are doing in bash. The correspondance
would be

char msg[] = {'\0', '\0', '\0', '\0', '0', '0', '\1', '0', '0',
'\2', 'A', 'A', ' ', 'L', 'I', 'N', 'U', 'X', '\4' };

a) in your bash version you have a \000 in one place instead of a \\000
b) in your bash version the characters after the Z are literal, not
numeric;
c) using char[] with an initialized string is going to result in a trailing
'\0' being put on that is not present in your original. As you are already
dealing with null characters, this could be significant.

: wr=write(fd1,msg,100);

Why are you writing 100 characters out of a string that is only 19
characters long? You should write(fd1, msg, sizeof(msg))

: printf(" Bytes sent are %d \n",wr);
: if (wr < 0)
: fputs("write() of 4 bytes failed!\n", stderr);

But it isn't 4 bytes you would have written!

: fcntl(fd2, F_SETFL,FNDELAY);
: rd=read(fd2,buff,100);
: printf(" Bytes recieved are %d \n",rd);

If you are reading from the same file as you are writting to, and
both fd's are RW, why not just use the same descriptor? Just make
sure you switch properly into reading mode by doing the appropriate
lseek().

: printf("%s",buff);

You are sending binary characters to the device, so why should we
expect that we will get null-terminated printable text back?
My expectation would be that there might be a null in the input,
and that would cause the %s format to stop printing.

Also, you said that the C program was to be the equivilent of the
bash, but in the bash you never read from the device.

One has to wonder whether the device is properly initialized to the
correct speed, parity, and so on, since there is no 'stty' shown,
nor tcsetattr() nor termio call.
--
"Who Leads?" / "The men who must... driven men, compelled men."
"Freak men."
"You're all freaks, sir. But you always have been freaks.
Life is a freak. That's its hope and glory." -- Alfred Bester, TSMD
 
Reply With Quote
 
collinm
Guest
Posts: n/a
 
      03-22-2005

Walter Roberson wrote:

>
> : char msg[]="\\000\\000\\000\\000\\000\\001Z00\\002AA LINUX

\\004";
>
> That doesn't correspond to what you are doing in bash. The

correspondance
> would be
>
> char msg[] = {'\0', '\0', '\0', '\0', '0', '0', '\1', '0', '0',
> '\2', 'A', 'A', ' ', 'L', 'I', 'N', 'U', 'X', '\4'

};
>
> a) in your bash version you have a \000 in one place instead of a

\\000

why some characters have \ in front of them and some not?

where is the Z?

they surely miss a '\0', because in the msg array, there a 5 null


> b) in your bash version the characters after the Z are literal, not
> numeric;

ya i know, in bash i can mix octal characters with literal...

i need to do the same thing with the C program


> c) using char[] with an initialized string is going to result in a

trailing
> '\0' being put on that is not present in your original. As you are

already
> dealing with null characters, this could be significant.


what i need to do to resolve that?

char *msg?

 
Reply With Quote
 
Jens.Toerring@physik.fu-berlin.de
Guest
Posts: n/a
 
      03-22-2005
collinm <(E-Mail Removed)> wrote:

> Walter Roberson wrote:
>>
>> : char msg[]="\\000\\000\\000\\000\\000\\001Z00\\002AA LINUX

> \\004";
>>
>> That doesn't correspond to what you are doing in bash. The

> correspondance
>> would be
>>
>> char msg[] = {'\0', '\0', '\0', '\0', '0', '0', '\1', '0', '0',
>> '\2', 'A', 'A', ' ', 'L', 'I', 'N', 'U', 'X', '\4'

> };
>>
>> a) in your bash version you have a \000 in one place instead of a

> \\000


> why some characters have \ in front of them and some not?


Because '\0' and '0' are two different characters. The first one ('\0')
is the character with the numerical value 0, while the second is the
character that will be printed as the character 0 but will have the
numerical value 48 if your machines uses the ASCII character encoding.
Same for the difference between '\1' and '1' etc. Or do you mean the
difference in bash? That's a question for comp.unix.shell or maybe
comp.unix.programmer since it's nothing related to C.

> where is the Z?


Walter forgot it, just put it in where it's missing (i.e. after the
'\1' character).

> they surely miss a '\0', because in the msg array, there a 5 null


Then put it in. The corrected version would be

char msg[ ] = { '\0', '\0', '\0', '\0', '\0', '\1', 'Z', '0', '0',
'\2', 'A', 'A', ' ', 'L', 'I', 'N', 'U', 'X', '\4' };

>> b) in your bash version the characters after the Z are literal, not
>> numeric;

>
> ya i know, in bash i can mix octal characters with literal...
> i need to do the same thing with the C program


What is "the same thing"? Octal, decimal, hexadecimal or whatever
way a value is represented in the program is irrelevant.

>> c) using char[] with an initialized string is going to result in a

> trailing
>> '\0' being put on that is not present in your original. As you are

> already
>> dealing with null characters, this could be significant.


> what i need to do to resolve that?


Take care that you don't use functions that expect strings (i.e. char
arrays that are terminated by a '\0' character) with that array and
to pass the correct length of the array to functions that operate on
simple arrays. You can determine the length by using e.g. 'sizeof msg'.

Regards, Jens
--
\ Jens Thoms Toerring ___ http://www.velocityreviews.com/forums/(E-Mail Removed)-berlin.de
\__________________________ http://www.toerring.de
 
Reply With Quote
 
Walter Roberson
Guest
Posts: n/a
 
      03-22-2005
In article <(E-Mail Removed) .com>,
collinm <(E-Mail Removed)> wrote:

:Walter Roberson wrote:
:> char msg[] = {'\0', '\0', '\0', '\0', '0', '0', '\1', '0', '0',
:> '\2', 'A', 'A', ' ', 'L', 'I', 'N', 'U', 'X', '\4'
:};

:> a) in your bash version you have a \000 in one place instead of a
:\\000

:where is the Z?

As Jens indicated in his follow-up, I forgot that one when I was
typing it.


:they surely miss a '\0', because in the msg array, there a 5 null

Yes, in the msg array, but that original bash we were given as the
original value had \\000\\000\\000\\000\000 at the beginning. The
\\ introduces an octal character in that bash context, but notice that
before the fifth group there is only a single \ instead of a double \\ .
The single \ and the following 0 will be consumed by the shell at a
level before octal conversion is attempted, so in the bash version
there were four nulls followed by a silently-eaten \0 pair followed
by two literal characters 0 as strings.

:ya i know, in bash i can mix octal characters with literal...

:i need to do the same thing with the C program

You can generally do so in a double-quoted initializer, but there
are a couple of restrictions.

a) The double-quoted initializer wants
to tack a null on the end of the string, and it is not clear from
what you wrote before that that is acceptable; if not, then you cannot
use a double-quoted string (not unless you use it as a convenient
initializer but take a copy of it and strip off the trailing null
before actual use.)

b) A sequence starting with \ extends as far as possible, so
the sequence \00000 wants to consume the five 0's, whereas the
bash you presented wants to consume 3 0's and then have two
literal 0's. There are two ways around this:

1) Keep using \ escapes as far as necessary to reach something
that is not part of any possible escape sequence. For example,

"\0\x30\x30Z"

ends the first null byte because it sees the second one start;
then the \0x30 is one of the representations of the character 0
(as opposed to the -number- 0). You need another escape
after that to end the \x30 because the next character, 0, would
otherwise be eaten as part of the first \x30 too. But then
after that, the Z cannot possibly be part of any octal or
hex or decimal escape sequence, so it is "self-delimiting",
not needing anything to indicate that the previous escape
sequence has ended.

2) Sometimes it's easiest to break the double-quoted string
into two parts, and rely upon the fact that standard C will merge
adjacent double-quoted strings. For example,

"\0\0\0\0" "00Z"

The first four escapes are processed, but the first closing quote
ends the scope of the active escape sequence, so when the second
opening quote starts one is not in escape mode anymore and it is
the literal characters 0 0 Z that would be there.

:> c) using char[] with an initialized string is going to result in a
:trailing
:> '\0' being put on that is not present in your original. As you are
:already
:> dealing with null characters, this could be significant.

:what i need to do to resolve that?

If you need to work with "strings" with embedded nulls, you end up
needing to pass the size all over the place, one way or another
(because otherwise the code won't know where to leave off.) You can
initialize a char [] with a "" string and then pass around the length
-excluding- the trailing null you know to be there. Or you can do as I
demonstrated earlier, in which you use an aggregate initializer of byte
by byte. Or you can bother to create a new string that has the null
stripped out, except you don't gain much by doing so since you
still need to pass the sizes around.
--
Ceci, ce n'est pas une idée.
 
Reply With Quote
 
Walter Roberson
Guest
Posts: n/a
 
      03-23-2005
In article <(E-Mail Removed) om>,
collinm <(E-Mail Removed)> wrote:
> about hex code i have with bash


> CMD_INIT="\x00\x00\x00\x00\x00\x01Z00\x02"
> CMD_END="\x04"
> echo -e "${CMD_INIT}E$AAU0030FFFF${CMD_END}" >/dev/ttyS2


> in C, i wrote


> char msg1[]={"\x00\x00\x00\x00\x00\x01Z00\x02E$AAU0030FFFF\x0 4"};


> that don't seem to be ok


> with your information that could maybe transform to


> char msg1[]={"\x00\x00\x00\x00\x00\x01\Z00\x02\E$AAU0030FFFF\ x04"};


Close; you recognized correctly that the problem was the run-on
of the x02 towards the E, but \E is not the way to correct it.

The simplest correction would likely be:

char msg1[]={"\x00\x00\x00\x00\x00\x01\Z00\02E$AAU0030FFFF\x0 4"};

Notice the lack of the 'x' before the 02. Without the x it's
an octal escape instead of a hex escape. E is not a valid octal
character so the parser would end the escape at the 2 and treat the
E as a plain text character.
--
"This was a Golden Age, a time of high adventure, rich living and
hard dying... but nobody thought so." -- Alfred Bester, TSMD
 
Reply With Quote
 
Dave Thompson
Guest
Posts: n/a
 
      03-28-2005
On 22 Mar 2005 18:22:48 GMT, http://www.velocityreviews.com/forums/(E-Mail Removed)-cnrc.gc.ca (Walter
Roberson) wrote:

> In article <(E-Mail Removed) .com>,
> collinm <(E-Mail Removed)> wrote:

<snip>
> :i need to do the same [string value] with the C program
>
> You can generally do so in a double-quoted initializer, but there
> are a couple of restrictions.
>
> a) The double-quoted initializer wants
> to tack a null on the end of the string, and it is not clear from
> what you wrote before that that is acceptable; if not, then you cannot
> use a double-quoted string (not unless you use it as a convenient
> initializer but take a copy of it and strip off the trailing null
> before actual use.)
>

Unless you declare a char array with an explicit bound which just fits
the contents of a string-literal initializer with no added null; in
this specific case no null is added, but this is error-prone
especially if you need (later) to change the string and its length.

Or, as you say later, initialize char[] with "string" which adds the
null, and then adjust the size, but you don't need to copy to do this.
Just e.g. write (fd1, msg, sizeof msg -1).

> b) A sequence starting with \ extends as far as possible, so
> the sequence \00000 wants to consume the five 0's, whereas the


No, \octal only takes up to three digits. And of course \b \r etc. do
exactly one letter. _Only_ \xhex takes as much as possible.

- David.Thompson1 at worldnet.att.net
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
FAQ 8.10 How do I read and write the serial port? PerlFAQ Server Perl Misc 0 03-11-2011 11:00 PM
FAQ 8.10 How do I read and write the serial port? PerlFAQ Server Perl Misc 0 01-15-2011 05:00 AM
Problem to read and write on a serial port collinm C Programming 3 03-30-2005 04:50 PM
Read Write serial port collinm C Programming 0 03-21-2005 08:46 PM
Open/write and read serial port (COM1) on iPAQ 2210 Shadowdancer ASP .Net Mobile 1 09-21-2004 08:12 PM



Advertisments