Hello,
I am using the Debain 283 and I am trying to test the RTS/CTS hardware flow control on both uart0 (/dev/ttyMSM1
) and uart1 (/dev/ttyMSM0
).
In order to enable the RTS/CTS pins for the uart1 I changed the uart1 pins in
arch/arm64/boot/dts/msm8916-pins.dtsi
as follows:
blsp1_uart2_default: blsp1_uart2_default {
pinmux {
function = "blsp_uart2";
pins = "gpio4", "gpio5", "gpio6", "gpio7";
};
pinconf {
pins = "gpio4", "gpio5", "gpio6", "gpio7";
drive-strength = <16>;
bias-disable;
};
};
So I am testing two codes.
The first code I am testing is this one:
#define _XOPEN_SOURCE_EXTENDED
#ifndef _POSIX_SOURCE
#define _POSIX_SOURCE
#endif
#ifndef _DEFAULT_SOURCE
#define _DEFAULT_SOURCE
#endif
#define _BSD_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdint.h>
int opentty(const char *ttyName)
{
printf("In function %s\n", __FUNCTION__);
/* open file & return file descriptor */
return open(ttyName, O_RDWR | O_NOCTTY | O_NDELAY);
}
int ttyinit(int *ttyfd, struct termios *t_old, uint32_t baud)
{
/* struct termios needed to handle the new serial port configuration */
struct termios t_new;
int8_t ret;
printf("In function %s\n", __FUNCTION__);
/* get the serial port attributes */
ret = tcgetattr(*ttyfd, t_old);
/* if fails, exit */
if(ret == -1)
{
printf("tcgetattr failed\n");
close(*ttyfd);
*ttyfd = -1;
return -1;
}
/* copy the new one from the old one */
t_new = *t_old;
switch(baud)
{
case 38400:
/* printf("38400...\n"); */
t_new.c_cflag = B38400;
break;
case 9600:
/* printf("9600...\n"); */
t_new.c_cflag = B9600;
break;
case 19200:
/* printf("19200...\n"); */
t_new.c_cflag = B19200;
break;
case 115200:
/* printf("115200...\n"); */
t_new.c_cflag = B115200;
break;
case 57600:
/* printf("57600...\n"); */
t_new.c_cflag = B57600;
break;
}
t_new.c_cflag |= PARODD | CS8 | CREAD | CLOCAL;
t_new.c_oflag = t_new.c_iflag = t_new.c_lflag = 0;
t_new.c_cflag |= CRTSCTS;
/* apply the given changes to the serial port */
ret = tcsetattr(*ttyfd, TCSANOW, &t_new);
/* if fails, exit */
if(ret == -1)
{
printf("tcsetattr failed\n");
/* restore old attributes and clos fd */
tcsetattr(*ttyfd, TCSANOW, t_old);
close(*ttyfd);
*ttyfd = -1;
}
return (ret == 0)? 1 : -1;
}
int main(int argc, char *argv[])
{
struct termios t_old = {0};
int fd = -1;
int32_t res = -1;
char c = 0;
fd_set rfd;
fd_set wfd;
struct timeval tm;
tm.tv_sec = 1;
tm.tv_usec = 0;
fd = opentty(argv[1]);
if(fd != -1)
{
if(ttyinit(&fd, &t_old, atoi(argv[2])) == 1)
{
while (1)
{
c = 'a';
write(fd, &c, 1);
}
close(fd);
}
}
return 0;
}
Whit this code the RTS/CTS pins are not used since the RTS is never set. I am able to communicate from putty with and without hardware flow control set, but I don’t see (from the oscilloscpe) the RTS and CTS pins toggled when hardware flow control is enabled.
However, I am able to toggle manually the RTS pin using ioctl with the following code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
static struct termios oldterminfo;
void closeserial(int fd)
{
tcsetattr(fd, TCSANOW, &oldterminfo);
if (close(fd) < 0)
perror("closeserial()");
}
int openserial(char *devicename)
{
int fd;
struct termios attr;
if ((fd = open(devicename, O_RDWR)) == -1) {
perror("openserial(): open()");
return 0;
}
if (tcgetattr(fd, &oldterminfo) == -1) {
perror("openserial(): tcgetattr()");
return 0;
}
attr = oldterminfo;
attr.c_cflag |= CRTSCTS | CLOCAL;
attr.c_oflag = 0;
if (tcflush(fd, TCIOFLUSH) == -1) {
perror("openserial(): tcflush()");
return 0;
}
if (tcsetattr(fd, TCSANOW, &attr) == -1) {
perror("initserial(): tcsetattr()");
return 0;
}
return fd;
}
int setRTS(int fd, int level)
{
int rts;
if (ioctl(fd, TIOCMGET, &rts) == -1) {
perror("setRTS(): TIOCMGET");
return 0;
}
if (level)
rts |= TIOCM_RTS;
else
rts &= ~TIOCM_RTS;
if (ioctl(fd, TIOCMSET, &rts) == -1) {
perror("setRTS(): TIOCMSET");
return 0;
}
return 1;
}
int main(int argc, const char *argv[])
{
int fd;
char serialdev[20] = {'\0'};
strcpy(serialdev, argv[1]);
fd = openserial(serialdev);
if (!fd) {
fprintf(stderr, "Error while initializing %s.\n", serialdev);
return 1;
}
while(1)
{
setRTS(fd, 0);
sleep(1); /* pause 1 second */
setRTS(fd, 1);
sleep(1);
};
closeserial(fd);
return 0;
}
This implies to manually set the RTS flow control before writing as manually checking the CTS state before reading. Sounds bad…
I was expecting that the setting and checking of the RTS and CTS pins is performed by hardware and kernel-space, not by the user-space program.
What is the proper way to set the hardware control flow handled by the Dragonboard hardware and kernel ?
Thank you in advance.
Regards,
Simon