Read Write serial port

Discussion in 'C Programming' started by collinm, Mar 21, 2005.

  1. collinm

    collinm Guest

    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?
    collinm, Mar 21, 2005
    #1
    1. Advertising

  2. 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
    Ulrich Eckhardt, Mar 21, 2005
    #2
    1. Advertising

  3. In article <>,
    collinm <> 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
    Walter Roberson, Mar 21, 2005
    #3
  4. collinm

    collinm Guest

    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?
    collinm, Mar 22, 2005
    #4
  5. collinm

    -berlin.de Guest

    collinm <> 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 ___ -berlin.de
    \__________________________ http://www.toerring.de
    -berlin.de, Mar 22, 2005
    #5
  6. In article <>,
    collinm <> 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.
    Walter Roberson, Mar 22, 2005
    #6
  7. In article <>,
    collinm <> 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\x04"};


    > 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\x04"};

    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
    Walter Roberson, Mar 23, 2005
    #7
  8. On 22 Mar 2005 18:22:48 GMT, -cnrc.gc.ca (Walter
    Roberson) wrote:

    > In article <>,
    > collinm <> 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
    Dave Thompson, Mar 28, 2005
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. collinm

    Read Write serial port

    collinm, Mar 21, 2005, in forum: C Programming
    Replies:
    0
    Views:
    636
    collinm
    Mar 21, 2005
  2. collinm

    Problem to read and write on a serial port

    collinm, Mar 29, 2005, in forum: C Programming
    Replies:
    3
    Views:
    446
    collinm
    Mar 30, 2005
  3. Shadowdancer

    Open/write and read serial port (COM1) on iPAQ 2210

    Shadowdancer, Sep 17, 2004, in forum: ASP .Net Mobile
    Replies:
    1
    Views:
    407
    JuanDG
    Sep 21, 2004
  4. PerlFAQ Server
    Replies:
    0
    Views:
    188
    PerlFAQ Server
    Jan 15, 2011
  5. PerlFAQ Server
    Replies:
    0
    Views:
    174
    PerlFAQ Server
    Mar 11, 2011
Loading...

Share This Page