Ccall from 32-bit Julia to 64-bit OS


#1

Can I make a calls to libc from a 32-bit version of Julia that is running on a 64-bit version of Linux? I’m working on code dealing with termios in libc. I’m running 32-bit Julia on my 64-bit machine (I have a cluster with a couple 32-bit architecture machines - so, running lowest common denominator). Will the 32-bit Julia ccall call 32-bit versions of libc or is it trying to call the 64-bit version? I’m getting weird results and some segment faults.

Frank


#2

Basically no.


#3

That’s what I thought. Just no indicators to tell me otherwise.


#4

You can call libc of the correct word size. I think @yuyichao just meant that you can’t call shared libraries with a different word size.

Note that libc (of the appropriate word size) is already linked into Julia, so if you just ccall a libc function without specifying a library, it will call the right one:

julia> ccall(:isalpha, Cint, (Cint,), 'a')
1

julia> ccall(:isalpha, Cint, (Cint,), ' ')
0

Termios functions like ccall(:tcdrain, Cint, (Cint,), 0) should also work.


#5

OK. I’ll give it a try. Thanks.


#6

Thanks!! That seems to have it working.

So, is this version of ccall an implicit call to the libc in the Julia you’re running? And - ccall((:tcsetattr, “libc”), Int32, (Int32, Int32, Ref{termios}), fd, TCSANOW, toptions) makes an explicit call to the O.S.? Am I understanding this correctly?


#7

More accurately, it’s calling the symbol that’s in the process’s symbol table. No matter what provides it.

No. You are never calling the “OS”. This calls the symbol in a library libc. Ignoring symbols of the same name elsewhere/already loaded.
It will also always call the correct library. The two should do the same thing.


#8

Maybe not if he’s set LD_LIBRARY_PATH incorrectly or something?


#9

dlopen will fail so the loaded code should always be correct.


#10

OK. I re-installed my whole O.S. just to make sure I hadn’t installed something that might have been messing me up. So, obviously, now, it’s something I am doing wrong in the code. It’s something to do with the tcsetattrib call dealing with the termios. I know this because I have printed out the value of the flags after every call I make in both the C code and the Julia code and I am getting different results. It could also be that I have the wrong .h values. I’ll have you guys see if you spot anything in the code first. So, I post the C and Julia code and the results from both.

C code

int serialport_init(const char* serialport, int baud)
{
    struct termios toptions;
    int fd;
    
    //fd = open(serialport, O_RDWR | O_NOCTTY | O_NDELAY);
    fd = open(serialport, O_RDWR | O_NONBLOCK );
    
    if (fd == -1)  {
        perror("serialport_init: Unable to open port ");
        return -1;
    }
    
    //int iflags = TIOCM_DTR;
    //ioctl(fd, TIOCMBIS, &iflags);     // turn on DTR
    //ioctl(fd, TIOCMBIC, &iflags);    // turn off DTR

    dbg(1, toptions);

    if (tcgetattr(fd, &toptions) < 0) {
        perror("serialport_init: Couldn't get term attributes");
        return -1;
    }

    dbg(2, toptions);

    speed_t brate = baud; // let you override switch below if needed
    switch(baud) {
    case 4800:   brate=B4800;   break;
    case 9600:   brate=B9600;   break;
#ifdef B14400
    case 14400:  brate=B14400;  break;
#endif
    case 19200:  brate=B19200;  break;
#ifdef B28800
    case 28800:  brate=B28800;  break;
#endif
    case 38400:  brate=B38400;  break;
    case 57600:  brate=B57600;  break;
    case 115200: brate=B115200; break;
    }
    cfsetispeed(&toptions, brate);
    cfsetospeed(&toptions, brate);

    dbg(3, toptions);

    // 8N1
    toptions.c_cflag &= ~PARENB;
    toptions.c_cflag &= ~CSTOPB;
    toptions.c_cflag &= ~CSIZE;
    toptions.c_cflag |= CS8;
    // no flow control
    toptions.c_cflag &= ~CRTSCTS;

    //toptions.c_cflag &= ~HUPCL; // disable hang-up-on-close to avoid reset

    toptions.c_cflag |= CREAD | CLOCAL;  // turn on READ & ignore ctrl lines
    toptions.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl

    toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw
    toptions.c_oflag &= ~OPOST; // make raw

    // see: http://unixwiz.net/techtips/termios-vmin-vtime.html
    toptions.c_cc[VMIN]  = 0;
    toptions.c_cc[VTIME] = 0;
    //toptions.c_cc[VTIME] = 20;

    dbg(4, toptions);
    
    tcsetattr(fd, TCSANOW, &toptions);

    dbg(5, toptions);

    if( tcsetattr(fd, TCSAFLUSH, &toptions) < 0) {
        perror("init_serialport: Couldn't set term attributes");
        return -1;
    }

    dbg(6, toptions);

    return fd;
}

Julia code

function serialport_init(serialport::String, baud::Int)
    toptions = termios(0,0,0,0,(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),0,0) 

    
    #fd = open(serialport, O_RDWR | O_NONBLOCK );
    fd = ccall(:open, Int, (Cstring, Int), serialport, O_RDWR | O_NONBLOCK)
    
    if (fd == -1)  
        println("serialport_init: Unable to open port ")
        return -1
    end
    
    #int iflags = TIOCM_DTR;
    #ioctl(fd, TIOCMBIS, &iflags);     // turn on DTR
    #ioctl(fd, TIOCMBIC, &iflags);    // turn off DTR

    dbg(1, toptions)

    ret = ccall(:tcgetattr, Int, (Int, Ref{termios}), fd, toptions)
    if (ret < 0)
        println("serialport_init: Couldn't get term attributes")
        return -1
    end

    dbg(2, toptions)    

    brate = baud; # let you override switch below if needed
    if (baud == 4800)
        brate=B4800
    elseif (baud == 9600)
        brate=B9600
    elseif (baud == 14400)
        brate=B14400
    elseif (baud == 19200)
        brate=B19200
    elseif (baud == 28800)
        brate=B28800
    elseif (baud == 38400)
        brate=B38400
    elseif (baud == 57600)
        brate=B57600
    elseif (baud == 115200)
            brate=B115200
    end

    #cfsetispeed(&toptions, brate);
    #cfsetospeed(&toptions, brate);
    ccall(:cfsetospeed, Void, (Ref{termios}, Int), toptions, brate)
    ccall(:cfsetispeed, Void, (Ref{termios}, Int), toptions, brate)

    dbg(3, toptions)

    # 8N1
    toptions.c_cflag &= ~PARENB
    toptions.c_cflag &= ~CSTOPB
    toptions.c_cflag &= ~CSIZE
    toptions.c_cflag |= CS8
    # no flow control
    toptions.c_cflag &= ~CRTSCTS

    #toptions.c_cflag &= ~HUPCL; // disable hang-up-on-close to avoid reset

    toptions.c_cflag |= CREAD | CLOCAL  # turn on READ & ignore ctrl lines
    toptions.c_iflag &= ~(IXON | IXOFF | IXANY) # turn off s/w flow ctrl

    toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG) # make raw
    toptions.c_oflag &= ~OPOST # make raw

    # see: http://unixwiz.net/techtips/termios-vmin-vtime.html
    #toptions.c_cc[VMIN]  = 0;
    #toptions.c_cc[VTIME] = 0;
    #toptions.c_cc[VTIME] = 20;

    temp = string(VMIN) * "," * "0"
    temp = temp * "," * string(VTIME) * "," * "0"
    toptions.c_cc = initialize_NTuple(temp, NCCS)

    dbg(4, toptions)

   
    #tcsetattr(fd, TCSANOW, &toptions);
    ret = ccall(:tcsetattr, Int, (Int, Int, Ref{termios}), fd, TCSANOW, toptions)

    dbg(5, toptions)    
    ret = ccall(:tcsetattr, Int, (Int, Int, Ref{termios}), fd, TCSAFLUSH, toptions)

    dbg(6, toptions)
    if(ret < 0) 
        println("init_serialport: Couldn't set term attributes")
        return -1
    end

    return fd
end

C test results

=== 1
tty.c_iflag: -1216921190
tty.c_oflag: -1217127072
tty.c_cflag: 0
tty.c_lflag: -1216835584
tty.c_cc[0]: 164
tty.c_cc[1]: 15
tty.c_cc[2]: 128
tty.c_cc[3]: 16
tty.c_cc[4]: 107
tty.c_cc[5]: 222
tty.c_cc[6]: 191
tty.c_cc[7]: 188
tty.c_cc[8]: 142
tty.c_cc[9]: 101
tty.c_cc[10]: 183
tty.c_cc[11]: 4
tty.c_cc[12]: 0
tty.c_cc[13]: 0
tty.c_cc[14]: 0
tty.c_cc[15]: 168
tty.c_cc[16]: 5
tty.c_cc[17]: 89
tty.c_cc[18]: 183
tty.c_cc[19]: 235
tty.c_cc[20]: 185
tty.c_cc[21]: 15
tty.c_cc[22]: 128
tty.c_cc[23]: 160
tty.c_cc[24]: 224
tty.c_cc[25]: 15
tty.c_cc[26]: 128
tty.c_cc[27]: 27
tty.c_cc[28]: 64
tty.c_cc[29]: 119
tty.c_cc[30]: 183
tty.c_cc[31]: 0
tty.c_ispeed: -1075942640
tty.c_ospeed: -1217134592
=== 2
tty.c_iflag: 0
tty.c_oflag: 4
tty.c_cflag: 3261
tty.c_lflag: 0
tty.c_cc[0]: 0
tty.c_cc[1]: 0
tty.c_cc[2]: 0
tty.c_cc[3]: 0
tty.c_cc[4]: 0
tty.c_cc[5]: 0
tty.c_cc[6]: 0
tty.c_cc[7]: 0
tty.c_cc[8]: 0
tty.c_cc[9]: 0
tty.c_cc[10]: 0
tty.c_cc[11]: 0
tty.c_cc[12]: 0
tty.c_cc[13]: 0
tty.c_cc[14]: 0
tty.c_cc[15]: 0
tty.c_cc[16]: 0
tty.c_cc[17]: 0
tty.c_cc[18]: 0
tty.c_cc[19]: 0
tty.c_cc[20]: 0
tty.c_cc[21]: 0
tty.c_cc[22]: 0
tty.c_cc[23]: 0
tty.c_cc[24]: 0
tty.c_cc[25]: 0
tty.c_cc[26]: 0
tty.c_cc[27]: 0
tty.c_cc[28]: 0
tty.c_cc[29]: 0
tty.c_cc[30]: 0
tty.c_cc[31]: 0
tty.c_ispeed: 13
tty.c_ospeed: 13
=== 3
tty.c_iflag: 0
tty.c_oflag: 4
tty.c_cflag: 3261
tty.c_lflag: 0
tty.c_cc[0]: 0
tty.c_cc[1]: 0
tty.c_cc[2]: 0
tty.c_cc[3]: 0
tty.c_cc[4]: 0
tty.c_cc[5]: 0
tty.c_cc[6]: 0
tty.c_cc[7]: 0
tty.c_cc[8]: 0
tty.c_cc[9]: 0
tty.c_cc[10]: 0
tty.c_cc[11]: 0
tty.c_cc[12]: 0
tty.c_cc[13]: 0
tty.c_cc[14]: 0
tty.c_cc[15]: 0
tty.c_cc[16]: 0
tty.c_cc[17]: 0
tty.c_cc[18]: 0
tty.c_cc[19]: 0
tty.c_cc[20]: 0
tty.c_cc[21]: 0
tty.c_cc[22]: 0
tty.c_cc[23]: 0
tty.c_cc[24]: 0
tty.c_cc[25]: 0
tty.c_cc[26]: 0
tty.c_cc[27]: 0
tty.c_cc[28]: 0
tty.c_cc[29]: 0
tty.c_cc[30]: 0
tty.c_cc[31]: 0
tty.c_ispeed: 13
tty.c_ospeed: 13
=== 4
tty.c_iflag: 0
tty.c_oflag: 4
tty.c_cflag: 3261
tty.c_lflag: 0
tty.c_cc[0]: 0
tty.c_cc[1]: 0
tty.c_cc[2]: 0
tty.c_cc[3]: 0
tty.c_cc[4]: 0
tty.c_cc[5]: 0
tty.c_cc[6]: 0
tty.c_cc[7]: 0
tty.c_cc[8]: 0
tty.c_cc[9]: 0
tty.c_cc[10]: 0
tty.c_cc[11]: 0
tty.c_cc[12]: 0
tty.c_cc[13]: 0
tty.c_cc[14]: 0
tty.c_cc[15]: 0
tty.c_cc[16]: 0
tty.c_cc[17]: 0
tty.c_cc[18]: 0
tty.c_cc[19]: 0
tty.c_cc[20]: 0
tty.c_cc[21]: 0
tty.c_cc[22]: 0
tty.c_cc[23]: 0
tty.c_cc[24]: 0
tty.c_cc[25]: 0
tty.c_cc[26]: 0
tty.c_cc[27]: 0
tty.c_cc[28]: 0
tty.c_cc[29]: 0
tty.c_cc[30]: 0
tty.c_cc[31]: 0
tty.c_ispeed: 13
tty.c_ospeed: 13
=== 5
tty.c_iflag: 0
tty.c_oflag: 4
tty.c_cflag: 3261
tty.c_lflag: 0
tty.c_cc[0]: 0
tty.c_cc[1]: 0
tty.c_cc[2]: 0
tty.c_cc[3]: 0
tty.c_cc[4]: 0
tty.c_cc[5]: 0
tty.c_cc[6]: 0
tty.c_cc[7]: 0
tty.c_cc[8]: 0
tty.c_cc[9]: 0
tty.c_cc[10]: 0
tty.c_cc[11]: 0
tty.c_cc[12]: 0
tty.c_cc[13]: 0
tty.c_cc[14]: 0
tty.c_cc[15]: 0
tty.c_cc[16]: 0
tty.c_cc[17]: 0
tty.c_cc[18]: 0
tty.c_cc[19]: 0
tty.c_cc[20]: 0
tty.c_cc[21]: 0
tty.c_cc[22]: 0
tty.c_cc[23]: 0
tty.c_cc[24]: 0
tty.c_cc[25]: 0
tty.c_cc[26]: 0
tty.c_cc[27]: 0
tty.c_cc[28]: 0
tty.c_cc[29]: 0
tty.c_cc[30]: 0
tty.c_cc[31]: 0
tty.c_ispeed: 13
tty.c_ospeed: 13
=== 6
tty.c_iflag: 0
tty.c_oflag: 4
tty.c_cflag: 3261
tty.c_lflag: 0
tty.c_cc[0]: 0
tty.c_cc[1]: 0
tty.c_cc[2]: 0
tty.c_cc[3]: 0
tty.c_cc[4]: 0
tty.c_cc[5]: 0
tty.c_cc[6]: 0
tty.c_cc[7]: 0
tty.c_cc[8]: 0
tty.c_cc[9]: 0
tty.c_cc[10]: 0
tty.c_cc[11]: 0
tty.c_cc[12]: 0
tty.c_cc[13]: 0
tty.c_cc[14]: 0
tty.c_cc[15]: 0
tty.c_cc[16]: 0
tty.c_cc[17]: 0
tty.c_cc[18]: 0
tty.c_cc[19]: 0
tty.c_cc[20]: 0
tty.c_cc[21]: 0
tty.c_cc[22]: 0
tty.c_cc[23]: 0
tty.c_cc[24]: 0
tty.c_cc[25]: 0
tty.c_cc[26]: 0
tty.c_cc[27]: 0
tty.c_cc[28]: 0
tty.c_cc[29]: 0
tty.c_cc[30]: 0
tty.c_cc[31]: 0
tty.c_ispeed: 13
tty.c_ospeed: 13

Julia test results

=== 1
tty.c_iflag: 0
tty.c_oflag: 0
tty.c_cflag: 0
tty.c_lflag: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_ispeed: 0
tty.c_ospeed: 0
=== 2
tty.c_iflag: 0
tty.c_oflag: 4
tty.c_cflag: 3261
tty.c_lflag: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_ispeed: 0
tty.c_ospeed: 0
=== 3
tty.c_iflag: 0
tty.c_oflag: 4
tty.c_cflag: 3263
tty.c_lflag: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_ispeed: 0
tty.c_ospeed: 0
=== 4
tty.c_iflag: 0
tty.c_oflag: 4
tty.c_cflag: 4095
tty.c_lflag: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_ispeed: 0
tty.c_ospeed: 0
=== 5
tty.c_iflag: 0
tty.c_oflag: 4
tty.c_cflag: 4095
tty.c_lflag: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_ispeed: 0
tty.c_ospeed: 0
=== 6
tty.c_iflag: 0
tty.c_oflag: 4
tty.c_cflag: 4095
tty.c_lflag: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_ispeed: 0
tty.c_ospeed: 0

As you can see it doesn’t look like the speed is getting set by looking at the c_ispeed and c_ospeed flags. And, the other values are not getting set correctly.

Any ideas by just looking at the code to see if I’m not doing something right translating from C to Julia (before I post the .h values)?

Thanks again for all the help so far!


#11

Cint, same below.

If this is all what you need, it’s quite weird to have to go through strings/parsing.

Also, according to what I have locally, both speed_t and tcflag_t should be unsigned not unsigned long and you were also missing a c_line field.


#12

OK. Here’s what the code looks like, now.

function serialport_init(serialport::String, baud::Int)
    toptions = termios(0,0,0,0,(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),0,0) 

    
    #fd = open(serialport, O_RDWR | O_NONBLOCK );
    fd = ccall(:open, Cint, (Cstring, Cint), serialport, O_RDWR | O_NONBLOCK)
    
    if (fd == -1)  
        println("serialport_init: Unable to open port ")
        return -1
    end
    
    #int iflags = TIOCM_DTR;
    #ioctl(fd, TIOCMBIS, &iflags);     // turn on DTR
    #ioctl(fd, TIOCMBIC, &iflags);    // turn off DTR

    dbg(1, toptions)

    ret = ccall(:tcgetattr, Cint, (Cint, Ref{termios}), fd, toptions)
    if (ret < 0)
        println("serialport_init: Couldn't get term attributes")
        return -1
    end

    dbg(2, toptions)    

    brate = baud; # let you override switch below if needed
    if (baud == 4800)
        brate=B4800
    elseif (baud == 9600)
        brate=B9600
    elseif (baud == 14400)
        brate=B14400
    elseif (baud == 19200)
        brate=B19200
    elseif (baud == 28800)
        brate=B28800
    elseif (baud == 38400)
        brate=B38400
    elseif (baud == 57600)
        brate=B57600
    elseif (baud == 115200)
            brate=B115200
    end

    #cfsetispeed(&toptions, brate);
    #cfsetospeed(&toptions, brate);
    ccall(:cfsetospeed, Void, (Ref{termios}, Cint), toptions, brate)
    ccall(:cfsetispeed, Void, (Ref{termios}, Cint), toptions, brate)

    dbg(3, toptions)

    # 8N1
    toptions.c_cflag &= ~PARENB
    toptions.c_cflag &= ~CSTOPB
    toptions.c_cflag &= ~CSIZE
    toptions.c_cflag |= CS8
    # no flow control
    toptions.c_cflag &= ~CRTSCTS

    #toptions.c_cflag &= ~HUPCL; // disable hang-up-on-close to avoid reset

    toptions.c_cflag |= CREAD | CLOCAL  # turn on READ & ignore ctrl lines
    toptions.c_iflag &= ~(IXON | IXOFF | IXANY) # turn off s/w flow ctrl

    toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG) # make raw
    toptions.c_oflag &= ~OPOST # make raw

    # see: http://unixwiz.net/techtips/termios-vmin-vtime.html
    #toptions.c_cc[VMIN]  = 0;
    #toptions.c_cc[VTIME] = 0;
    #toptions.c_cc[VTIME] = 20;

    temp = string(VMIN) * "," * "0"
    temp = temp * "," * string(VTIME) * "," * "0"
    toptions.c_cc = initialize_NTuple(temp, NCCS)

    dbg(4, toptions)

   
    #tcsetattr(fd, TCSANOW, &toptions);
    ret = ccall(:tcsetattr, Cint, (Cint, Cint, Ref{termios}), fd, TCSANOW, toptions)

    dbg(5, toptions)    
    ret = ccall(:tcsetattr, Cint, (Cint, Cint, Ref{termios}), fd, TCSAFLUSH, toptions)

    dbg(6, toptions)
    if(ret < 0) 
        println("init_serialport: Couldn't set term attributes")
        return -1
    end

    return fd
end

Here’s the .h file

const   NCCS        =   20

macro ctypedef(fake_t,real_t)
  quote
    const $(esc(fake_t)) = $(esc(real_t))
  end
end


# c_cc characters 
const VINTR             =   0
const VQUIT             =   1
const VERASE            =   2
const VKILL             =   3
const VEOF              =   4
const VTIME             =   5
const VMIN              =   6
const VSWTC             =   7
const VSTART            =   8
const VSTOP             =   9
const VSUSP             =   10
const VEOL              =   11
const VREPRINT          =   12
const VDISCARD          =   13
const VWERASE           =   14
const VLNEXT            =   15
const VEOL2             =   16

# c_iflag bits 
const IGNBRK            =   0000001
const BRKINT            =   0000002
const IGNPAR            =   0000004
const PARMRK            =   0000010
const INPCK                =   0000020
const ISTRIP            =   0000040
const INLCR                =   0000100
const IGNCR                =   0000200
const ICRNL                =   0000400
const IUCLC                =   0001000
const IXON                =   0002000
const IXANY                =   0004000
const IXOFF                =   0010000
const IMAXBEL            =   0020000
const IUTF8                =   0040000

# c_oflag bits 
const OPOST                =   0000001
const OLCUC                =   0000002
const ONLCR                =   0000004
const OCRNL                =   0000010
const ONOCR                =   0000020
const ONLRET            =   0000040
const OFILL                =   0000100
const OFDEL                =   0000200
const NLDLY                =   0000400
const   NL0                =   0000000
const   NL1                =   0000400
const CRDLY                =   0003000
const   CR0                =   0000000
const   CR1                =   0001000
const   CR2                =   0002000
const   CR3                =   0003000
const TABDLY            =   0014000
const   TAB0            =   0000000
const   TAB1            =   0004000
const   TAB2            =   0010000
const   TAB3            =   0014000
const   XTABS            =   0014000
const BSDLY                =   0020000
const   BS0                =   0000000
const   BS1                =   0020000
const VTDLY                =   0040000
const   VT0                =   0000000
const   VT1                =   0040000
const FFDLY                =   0100000
const   FF0                =   0000000
const   FF1                =   0100000

# c_cflag bit meaning 
const CBAUD                =   0010017
const  B0                =   0000000        # hang up 
const  B50                =   0000001
const  B75                =   0000002
const  B110                =   0000003
const  B134                =   0000004
const  B150                =   0000005
const  B200                =   0000006
const  B300                =   0000007
const  B600                =   0000010
const  B1200            =   0000011
const  B1800            =   0000012
const  B2400            =   0000013
const  B4800            =   0000014
const  B9600            =   0000015
const  B19200            =   0000016
const  B38400            =   0000017
const EXTA              =   B19200
const EXTB              =   B38400
const CSIZE                =   0000060
const   CS5                =   0000000
const   CS6                =   0000020
const   CS7                =   0000040
const   CS8                =   0000060
const CSTOPB            =   0000100
const CREAD                =   0000200
const PARENB            =   0000400
const PARODD            =   0001000
const HUPCL                =   0002000
const CLOCAL            =   0004000
const CBAUDEX           =   0010000
const    BOTHER         =   0010000
const    B57600         =   0010001
const   B115200         =   0010002
const   B230400         =   0010003
const   B460800         =   0010004
const   B500000         =   0010005
const   B576000         =   0010006
const   B921600         =   0010007
const  B1000000         =   0010010
const  B1152000         =   0010011
const  B1500000         =   0010012
const  B2000000         =   0010013
const  B2500000         =   0010014
const  B3000000         =   0010015
const  B3500000         =   0010016
const  B4000000         =   0010017
const CIBAUD            =   002003600000    # input baud rate 
const CMSPAR            =   010000000000    # mark or space (stick) parity 
const CRTSCTS            =   020000000000    # flow control 

const IBSHIFT            =   16        # Shift from CBAUD to CIBAUD 

# c_lflag bits 
const ISIG                =   0000001
const ICANON            =   0000002
const XCASE                =   0000004
const ECHO                =   0000010
const ECHOE                =   0000020
const ECHOK                =   0000040
const ECHONL            =   0000100
const NOFLSH            =   0000200
const TOSTOP            =   0000400
const ECHOCTL            =   0001000
const ECHOPRT            =   0002000
const ECHOKE            =   0004000
const FLUSHO            =   0010000
const PENDIN            =   0040000
const IEXTEN            =   0100000
const EXTPROC            =   0200000

# tcflow() and TCXONC use these 
const    TCOOFF            =   0
const    TCOON            =   1
const    TCIOFF            =   2
const    TCION            =   3

# tcflush() and TCFLSH use these 
const    TCIFLUSH        =   0
const    TCOFLUSH        =   1
const    TCIOFLUSH        =   2

# tcsetattr uses these 
const    TCSANOW            =   0
const    TCSADRAIN        =   1
const    TCSAFLUSH        =   2

@ctypedef tcflag_t Cuint
@ctypedef cc_t Cuchar
@ctypedef speed_t Cuint

mutable struct termios
    c_iflag::tcflag_t    #input flags
    c_oflag::tcflag_t    #output flags
    c_cflag::tcflag_t    #control flags
    c_lflag::tcflag_t    #local flags
    c_cc::NTuple{NCCS,cc_t}     #control chars
    c_ispeed::speed_t    #input speed
    c_ospeed::speed_t    #output speed 
end

I’m getting a segmentation fault on this line.

julia> # 8N1
toptions.c_cflag &= ~PARENB

signal (11): Segmentation fault

So, now, it seems to have occurred after I changed tcflag_t to Cuint.


#13

OK. I got rid of the error by changing the struct to:

@ctypedef tcflag_t Cint
@ctypedef cc_t Cuchar
@ctypedef speed_t Cuint

mutable struct termios
    c_iflag::tcflag_t    #input flags
    c_oflag::tcflag_t    #output flags
    c_cflag::tcflag_t    #control flags
    c_lflag::tcflag_t    #local flags
    c_line::cc_t        #line discipline     
    c_cc::NTuple{NCCS,cc_t}     #control chars
    c_ispeed::speed_t               #input speed 
    c_ospeed::speed_t                 #output speed
end

But, I still don’t seem to be getting any values for the input/output speeds.

julia> serialport = "/dev/ttyACM0"
"/dev/ttyACM0"

julia> baud = 9600
9600

julia> toptions = termios(0,0,0,0, 0, (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), 0, 0)
termios(0, 0, 0, 0, 0x00, (0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 0x00000000, 0x00000000)

julia> #fd = open(serialport, O_RDWR | O_NONBLOCK );
       fd = ccall(:open, Cint, (Cstring, Cint), serialport, O_RDWR | O_NONBLOCK)

18

julia> if (fd == -1)  
           println("serialport_init: Unable to open port ")
           return -1
       end

julia> #int iflags = TIOCM_DTR;
       #ioctl(fd, TIOCMBIS, &iflags);     // turn on DTR
       #ioctl(fd, TIOCMBIC, &iflags);    // turn off DTR

       dbg(1, toptions)
=== 1
tty.c_iflag: 0
tty.c_oflag: 0
tty.c_cflag: 0
tty.c_lflag: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_ispeed: 0
tty.c_ospeed: 0

julia> ret = ccall(:tcgetattr, Cint, (Cint, Ref{termios}), fd, toptions)
0

julia> if (ret < 0)
           println("serialport_init: Couldn't get term attributes")
           return -1
       end

julia> dbg(2, toptions)
=== 2
tty.c_iflag: 0
tty.c_oflag: 0
tty.c_cflag: 4095
tty.c_lflag: 128
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_ispeed: 0
tty.c_ospeed: 0

julia> brate = baud; # let you override switch below if needed

julia> if (baud == 4800)
            brate=B4800
        elseif (baud == 9600)
            brate=B9600
        elseif (baud == 14400)
            brate=B14400
        elseif (baud == 19200)
            brate=B19200
        elseif (baud == 28800)
            brate=B28800
        elseif (baud == 38400)
            brate=B38400
        elseif (baud == 57600)
            brate=B57600
        elseif (baud == 115200)
                brate=B115200
        end
15

julia> #cfsetispeed(&toptions, brate);
        #cfsetospeed(&toptions, brate);
        ccall(:cfsetospeed, Void, (Ref{termios}, Cint), toptions, brate)

julia> ccall(:cfsetispeed, Void, (Ref{termios}, Cint), toptions, brate)

julia> dbg(3, toptions)
=== 3
tty.c_iflag: 0
tty.c_oflag: 0
tty.c_cflag: 4095
tty.c_lflag: 128
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_ispeed: 0
tty.c_ospeed: 0

julia> # 8N1
       toptions.c_cflag &= ~PARENB
3695

julia> toptions.c_cflag &= ~CSTOPB
3595

julia> toptions.c_cflag &= ~CSIZE
3587

julia> toptions.c_cflag |= CS8
3647

julia> # no flow control
       toptions.c_cflag &= ~CRTSCTS
1599

julia> #toptions.c_cflag &= ~HUPCL; // disable hang-up-on-close to avoid reset

       toptions.c_cflag |= CREAD | CLOCAL  # turn on READ & ignore ctrl lines
4095

julia> toptions.c_iflag &= ~(IXON | IXOFF | IXANY) # turn off s/w flow ctrl
0

julia> toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG) # make raw
128

julia> toptions.c_oflag &= ~OPOST # make raw
0

julia> # see: http://unixwiz.net/techtips/termios-vmin-vtime.html
       #toptions.c_cc[VMIN]  = 0;
       #toptions.c_cc[VTIME] = 0;
       #toptions.c_cc[VTIME] = 20;

       temp = string(VMIN) * "," * "0"
"6,0"

julia> temp = temp * "," * string(VTIME) * "," * "0"
"6,0,5,0"

julia> toptions.c_cc = initialize_NTuple(temp, NCCS)
(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)

julia> dbg(4, toptions)
=== 4
tty.c_iflag: 0
tty.c_oflag: 0
tty.c_cflag: 4095
tty.c_lflag: 128
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_ispeed: 0
tty.c_ospeed: 0

julia> #tcsetattr(fd, TCSANOW, &toptions);
        ret = ccall(:tcsetattr, Cint, (Cint, Cint, Ref{termios}), fd, TCSANOW, toptions)
0

julia> dbg(5, toptions)
=== 5
tty.c_iflag: 0
tty.c_oflag: 0
tty.c_cflag: 4095
tty.c_lflag: 128
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_ispeed: 0
tty.c_ospeed: 0

julia> ret = ccall(:tcsetattr, Cint, (Cint, Cint, Ref{termios}), fd, TCSAFLUSH, toptions)
0

julia> dbg(6, toptions)
=== 6
tty.c_iflag: 0
tty.c_oflag: 0
tty.c_cflag: 4095
tty.c_lflag: 128
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_cc[n]: 0
tty.c_ispeed: 0
tty.c_ospeed: 0

julia> if(ret < 0) 
           println("init_serialport: Couldn't set term attributes")
           return -1
       end

And, the values don’t match the C code values (still):

tty.c_iflag: 0
tty.c_oflag: 4
tty.c_cflag: 3261
tty.c_lflag: 0
tty.c_cc[0]: 0
tty.c_cc[1]: 0
tty.c_cc[2]: 0
tty.c_cc[3]: 0
tty.c_cc[4]: 0
tty.c_cc[5]: 0
tty.c_cc[6]: 0
tty.c_cc[7]: 0
tty.c_cc[8]: 0
tty.c_cc[9]: 0
tty.c_cc[10]: 0
tty.c_cc[11]: 0
tty.c_cc[12]: 0
tty.c_cc[13]: 0
tty.c_cc[14]: 0
tty.c_cc[15]: 0
tty.c_cc[16]: 0
tty.c_cc[17]: 0
tty.c_cc[18]: 0
tty.c_cc[19]: 0
tty.c_cc[20]: 0
tty.c_cc[21]: 0
tty.c_cc[22]: 0
tty.c_cc[23]: 0
tty.c_cc[24]: 0
tty.c_cc[25]: 0
tty.c_cc[26]: 0
tty.c_cc[27]: 0
tty.c_cc[28]: 0
tty.c_cc[29]: 0
tty.c_cc[30]: 0
tty.c_cc[31]: 0
tty.c_ispeed: 13
tty.c_ospeed: 13

Very frustrating!!


#14

OK. I’ll ask one last question before I just wrap my C program in a Julia call.

Where in the Julia source is the termios code or header (or where it’s calling these routines)? I haven’t found it anywhere.

Frank


#15

It’s from your system, julia don’t have them.