Hi!

I've configured my Bela so UART4 is activated. I have the Tx pin of an arduino connected to P9-11 (UART4 Rx), through a level shifter so it comes out at 3.3v. The grounds are connected too.
I've set the baud rate to 38400.

I found some example code on the internet - and it successfully sends data out. I can also see my serial data being received by the Bela if I run this command in the terminal -

screen -S serial /dev/ttyS4 38400

However, when I run my program, I don't see anything displayed. Could anyone tell me why?

Here's the code:

#include <Bela.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <termios.h>

#define SERIAL_BUFFER_SIZE 255
int  serialPort;
char serialBuffer[SERIAL_BUFFER_SIZE];

int testCount = 0;




void serialTest(void* arg)
{
    while(!gShouldStop)
    {
        unsigned char cmd[] = {'H', 'i', ' ', 'C', 'a', 'r', 'l',  '\n',     '\0'};
		write( serialPort, cmd, sizeof(cmd) -1);

	/* *** READ *** */
	int bytesRead = read(serialPort, serialBuffer , SERIAL_BUFFER_SIZE);
	if (bytesRead > 0) rt_printf("%s\t[%i]\n", serialBuffer, bytesRead);
    usleep(10000);
}
}


void startSerial()
{
	speed_t baud = B38400;
    serialPort = open( "/dev/ttyS4", O_RDWR | O_NONBLOCK | O_NDELAY );
    if ( serialPort < 0 ) printf("UART4 not available\n");

/* set the other settings (in this case, 9600 8N1) */
struct termios settings;
tcgetattr(serialPort, &settings);
cfsetospeed(&settings, baud); /* baud rate */
settings.c_cflag &= ~PARENB; /* no parity */
settings.c_cflag &= ~CSTOPB; /* 1 stop bit */
settings.c_cflag &= ~CSIZE;
settings.c_cflag |= CS8 | CLOCAL; /* 8 bits */
settings.c_lflag  = ICANON; /* canonical mode */
settings.c_oflag &= ~OPOST; /* raw output */

tcsetattr(serialPort, TCSANOW, &settings); /* apply the settings */
tcflush(serialPort, TCOFLUSH);

memset (&serialBuffer, '\0', sizeof serialBuffer);	// allocate serial buffer memory
Bela_scheduleAuxiliaryTask(Bela_createAuxiliaryTask(serialTest, 50, "serialTest", NULL));
}


bool setup(BelaContext *context, void *userData)
{
	startSerial();
	return true;
}


void render(BelaContext *context, void *userData)
{	

}

void cleanup(BelaContext *context, void *userData)
{

}

Curiously, I tried running the program, and then running the terminal serial monitor with this..

screen -S serial /dev/ttyS4 38400

And the program starts receiving the serial data, even after I quit the monitor using <ctrl+a d>.
The monitor is also emptying the buffer as it reads it, so the program is only getting some of the data.

Can someone explain what is happening? How can I get my program to open the serial port automatically?

Check on serial timeouts. For example, what does this function do if there are not 255 bytes to read from the serial port?

int bytesRead = read(serialPort, serialBuffer , SERIAL_BUFFER_SIZE);

Does it return immediately and loop again, or does it block forever until it gets the number of requested bytes?

The behavior of read() depends on the flags you set up when you open the port, and I haven't taken time to review this in your code, but I thought I would at least give you a hint about something worth looking at more closely. That is, look into the behavior of the file descriptor when opened with these flags:

serialPort = open( "/dev/ttyS4", O_RDWR | O_NONBLOCK | O_NDELAY );

Another quick hint I can give is some working code from a utility I wrote to communicate with an LCD (serial read() function is for getting I/O pin states on the microcontroller driving the LCD):
https://github.com/transmogrifox/Bela_Misc/blob/master/audio_level_meter/usb_backpack.cpp

//Serial setup and opening file
.
.
.
    memset(&(d->tio),0,sizeof(struct termios));
    d->tio.c_iflag=0;
    d->tio.c_oflag=0;
    d->tio.c_cflag=CS8|CREAD|CLOCAL;           // 8n1, see termios.h for more information
    d->tio.c_lflag=0;
    d->tio.c_cc[VMIN]=1;
    d->tio.c_cc[VTIME]=2;

    int psz = strlen(port);
    for(int i = 0; i < psz; i++)
    {
        d->tty_port[i] = port[i];
    }

    d->tty_fd = open(d->tty_port, O_RDWR | O_NONBLOCK);
    cfsetospeed(&(d->tio),B115200);            // 115200 baud
    cfsetispeed(&(d->tio),B115200);            // 115200 baud

    tcsetattr(d->tty_fd,TCSANOW,&(d->tio));
.
.
.

Code reading the port

void lcd_read_from_device(display_20x4_lcd* d)
{
    unsigned char c = 0;
    int i = 0;
    unsigned char x = 0;
    while (read(d->tty_fd,&c,1) > 0)
    {
        printf("%c", c);
        if( ++i > 4 )
        {
            x = (c  - '0') & 0x0F;
            printf("\nState: %d\n", x);
            for(int j = 0; j < 4; j++)
            {
                printf("%d", ((x >> j) & 0x01) );
            }
            printf("\n");
            i = 0;
        }
    }
}

Hey thanks! Your source code provided the answer!

I was setting the baud rate for the Tx port, but I omitted the command to set the Rx baud rate..

This line here fixed it..

cfsetispeed(&(d->tio),B38400);            // 38400 baud

I used the port settings in my original code - they seem to work so I'll post them again here for reference.. Arduino is talking to Bela!

serialPort = open("/dev/ttyS4", O_RDWR | O_NONBLOCK | O_NDELAY );
	
struct termios settings;
tcgetattr(serialPort, &settings);

cfsetospeed(&settings,B38400);            // B115200
cfsetispeed(&settings,B38400);

settings.c_cflag &= ~PARENB;
settings.c_cflag &= ~CSTOPB;
settings.c_cflag &= ~CSIZE;
settings.c_cflag |= CS8 | CLOCAL; 
settings.c_lflag  = ICANON; 
settings.c_oflag &= ~OPOST; 

tcsetattr(serialPort, TCSANOW, &settings); 
tcflush(serialPort, TCOFLUSH);
12 days later