Ccall from 32-bit Julia to 64-bit OS

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

Basically no.

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

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.

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

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?

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.

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

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

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!

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.

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.

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!!

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

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