Serial port /dev/cuau0 setup problems

oOiOo​

Thanks for the correction. Added a debug function to print out the contents of the termio struct after various operations within the open function. One after the initial getattrib and set speed functions, to set a baseline, another after setting various flags, another after the setattrib call, and a final getattrib again, and printing the results. It's clear that the setattrib id doing something, as there are changes on the final getattrib, but nothng works now, and seems like that the serial port has been left in an unrecoverable state. Haven't analysed the printed out values, but there are changes, which means that setattrib is doing something..

Have done a for amount of network related and other programming on FreeBSD, but this is the first effort with serial lines. My code inspired by the Stevens Advanced programming in the unix environment, an excellent resource, as are the rest of his works.

Here's the debug function:

/* Debug: Print termios Struct Values */

void debug (struct termios *termio) {
printf ("\n%d", termio -> c_iflag); /* input modes */
printf ("\n%d", termio -> c_oflag); /* output modes */
printf ("\n%d", termio -> c_cflag); /* control modes */
printf ("\n%d", termio -> c_lflag); /* local modes */
printf ("\n%d", termio -> c_ispeed); /* input speed */
printf ("\n%x\n", termio -> c_ospeed); /* output speed */

return;
}
 
It is difficult to help you further with only a partial view of the code. Below is an example that opens the serial port in read-only mode and displays the incoming data:

C:
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>

char buf[256];
ssize_t n;

int main(int argc, char *argv[])
{
    const char *dev = (argc > 1) ? argv[1] : "/dev/cuau0";

    int fd = open(dev, O_RDONLY | O_NOCTTY);
    if (fd < 0) {
        perror("open");
        return 1;
    }

    struct termios termio;
    if (tcgetattr(fd, &termio) < 0) {
        perror("tcgetattr");
        close(fd);
        return 1;
    }

    /* 4800, 8N1 */
    cfsetispeed(&termio, B4800);
    cfsetospeed(&termio, B4800);
    termio.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS);
    termio.c_cflag |= CS8 | CREAD | CLOCAL;

    /* Canonical mode */
    termio.c_lflag |= ICANON;
    termio.c_lflag &= ~(ECHO | ISIG);

    /* No flow control, non ASCII mode */
    termio.c_iflag &= ~(IXON | IXOFF | ISTRIP);

    if (tcsetattr(fd, TCSANOW, &termio) < 0) {
        perror("tcsetattr");
        close(fd);
        return 1;
    }

    while ((n = read(fd, buf, sizeof(buf) - 1)) > 0) {
        buf[n] = '\0';
        printf("%s", buf);
        fflush(stdout);
    }

    close(fd);
    return 0;
}

If your radio receiver requires hardware flow control, replace

C:
termio.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS);
termio.c_cflag |= CS8 | CREAD | CLOCAL;

with
C:
ttermio.c_cflag &= ~(PARENB | CSTOPB | CSIZE);
termio.c_cflag |= CS8 | CREAD | CLOCAL | CRTSCTS;

I also have the Stevens book, which is an excellent reference. However, I recommend the serial programming tutorial by Michael R. Sweet - the author of CUPS - : https://www.msweet.org/serial/serial.html . In my opinion, it contains more concrete examples for getting started.
I hope this helps.
 
Thanks for the reply. Already posted the open function code, which does open in r/w mode. Changed slightly to set a couple of flags to zero, but apart from that, just the correction for or'ing of the flags. Here's the code again, inclding the write function.

/* Open tty Line */
/* ------------- */
STATUS eTtyOpen (TTY_INFO *psTtyInfo) { /* Open in raw mode, not cannonical */

STATUS eStatus = FAIL;
psTtyInfo -> TtyStatus = TTY_OK;

struct termios sTerm;

if ((psTtyInfo -> s16DevHandle = open ((char *) psTtyInfo -> pu8TtyId, O_RDWR | O_NONBLOCK | O_FSYNC)) < 0) { /* Open for r/w */
psTtyInfo -> TtyStatus = TTY_OPNFAL; /* Fail */
}
else if (tcgetattr (psTtyInfo -> s16DevHandle, &sTerm) < 0) { /* Get current attributes */
psTtyInfo -> TtyStatus = TTY_GETATT; /* Fail */
}
else if (cfsetispeed (&sTerm, psTtyInfo -> stBaudRate) < 0) { /* Set tx baud rate, eg: B9600 */
psTtyInfo -> TtyStatus = TTY_SETTXB;
}
else if (cfsetospeed (&sTerm, psTtyInfo -> stBaudRate) < 0) { /* and rx baud rate */
psTtyInfo -> TtyStatus = TTY_SETRXB;
}
else { /* Ok so far */

debug (&sTerm); (&sTerm);

sTerm.c_lflag = 0; /* Everything off in local mode ( Stevens, P609) */
sTerm.c_oflag = 0; /* All output processing off ditto */

sTerm.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); /* Break, cr2nl, parity, strip bit 8, all off */

sTerm.c_cflag &= ~(CSIZE | PARENB);
sTerm.c_cflag |= (CREAD | HUPCL | CLOCAL | CS8); /* Enable rx, lower on close, local line, 8 bit char */

sTerm.c_cc[VMIN] = 0;
sTerm.c_cc[VTIME] = 0; /* Poll exit on no data ready, no timeout */

debug (&sTerm);

if (tcsetattr (psTtyInfo -> s16DevHandle, TCSANOW, &sTerm) < 0) { /* Set attributes */
psTtyInfo -> TtyStatus = TTY_SETATT; /* Fail */
}
}

if (psTtyInfo -> TtyStatus == TTY_OK) { /* If no errors */
eStatus = OK;
}

tcgetattr (psTtyInfo -> s16DevHandle, &sTerm);

debug (&sTerm);


return eStatus;
}

/* Tty Write Data */
/* -------------- */
STATUS eTtyWrite (TTY_INFO *psTtyInfo) {

S8 *ps8TxData = (S8 *) psTtyInfo -> pu8TxBuffer;
S16 s16Count = (S16) psTtyInfo -> u16TxLength;
S16 s16Sent = 0;

STATUS eStatus = OK;

while (s16Count > 0) {
if (((s16Sent = write (psTtyInfo -> s16DevHandle, ps8TxData, s16Count)) ) <= 0) { /* Write to port */
eStatus = TXTIME_ERR; /* Transmit error */
break;
}
else { /* Still data to send ? */
s16Count -= s16Sent; /* Bump pointer and loop */
ps8TxData += s16Sent;
}
}

return eStatus;
}

Write worked earlier, as did the following read call, to show what was sent. That cups reference looks excellent. Will work though that.
 
Thinking about this, the baud rates are elements of the termio structure, so if we have a temporary termio struct, set that up, then call setattrib, perhaps any intermediate use of the set speed functions, before finally calling setattrib, may be overwritten ?. Will try settng up the speeds in the termio struct directly, before the final settattrib call.
 
Back
Top