Failed to configure device ttyUSB0 (Arduino) on Ubuntu, C++ - c++

I can open serial port, but I can't correctly configure this port for write (/dev/ttyUSB0).
Piece of code C++:
int
Platform::initConnection( const char* devicePath, int baudRate )
{
int fd = 0;
int ret = 0;
struct termios terminalOptions; // POSIX structure for configurating terminal devices
fd = open( devicePath, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
//fd = open( devicePath, O_RDWR | O_NOCTTY );
if (fd == -1)
{
this->setFail();
this->setErrorStr( "Failed to open: " + (std::string)devicePath + ". " + (std::string)strerror(errno) );
return -1;
}
memset( &terminalOptions, 0, sizeof( struct termios ) ); // Cleaning up the structure
cfmakeraw(&terminalOptions); //
cfsetspeed(&terminalOptions, baudRate);
/*terminalOptions.c_cflag = CLOCAL; // If CLOCAL is set, the line behaves as if DCD is always asserted.
// It is used when your device is local
terminalOptions.c_cflag |= CS8; // Character size mask
terminalOptions.c_cc[VMIN] = 24; // 1 second timeout
terminalOptions.c_cc[VTIME] = 0; // */
terminalOptions.c_cflag &= ~CRTSCTS;
terminalOptions.c_cflag |= (CLOCAL | CREAD);
terminalOptions.c_iflag |= (IGNPAR | IGNCR);
terminalOptions.c_iflag &= ~(IXON | IXOFF | IXANY);
terminalOptions.c_oflag &= ~OPOST;
terminalOptions.c_cflag &= ~CSIZE;
terminalOptions.c_cflag |= CS8;
terminalOptions.c_cflag &= ~PARENB;
terminalOptions.c_iflag &= ~INPCK;
terminalOptions.c_iflag &= ~(ICRNL|IGNCR);
terminalOptions.c_cflag &= ~CSTOPB;
terminalOptions.c_iflag |= INPCK;
terminalOptions.c_cc[VTIME] = 0.001; // 1s=10 0.1s=1 *
terminalOptions.c_cc[VMIN] = 0;
ret = ioctl( fd, TIOCSETA, &terminalOptions ); // Configuring the device
if (ret == -1)
{
this->setFail();
this->setErrorStr( "Failed to configure device: " + (std::string)devicePath + ". " + (std::string)strerror(errno) );
return -1;
}
return fd;
}
Error:
Failed to configure device: /dev/ttyUSB0. Inappropriate ioctl for device
Arduino UNO uses chipset CH340.
I have no idea about the resolve this problem. I'm hope for your help. Thanks!
Update:
Log from dmesg
[11840.346071] usb 2-1.2: new full-speed USB device number 5 using ehci-pci
[11840.439832] usb 2-1.2: New USB device found, idVendor=1a86, idProduct=7523
[11840.439844] usb 2-1.2: New USB device strings: Mfr=0, Product=2, SerialNumber=0
[11840.439850] usb 2-1.2: Product: USB2.0-Serial
[11840.440472] ch341 2-1.2:1.0: ch341-uart converter detected
[11840.442452] usb 2-1.2: ch341-uart converter now attached to ttyUSB0

Thanks to all. I found the solution on their own:
As autoreset on serial connection is activated by default on most boards, you need to disable this feature if you want to communicate directly with your board with the last command instead of a terminal emulator (arduino IDE, screen, picocom...). If you have a Leonardo board, you are not concerned by this, because it does not autoreset. If you have a Uno board, connect a 10 µF capacitor between the RESET and GND pins. If you have another board, connect a 120 ohms resistor between the RESET and 5V pins. See http://playground.arduino.cc/Main/DisablingAutoResetOnSerialConnection for more details.
Сhanged code
memset( &terminalOptions, 0, sizeof( struct termios ) );
tcgetattr(fd, &terminalOptions); //change
cfmakeraw(&terminalOptions);
cfsetspeed(&terminalOptions, baudRate);
terminalOptions.c_cflag = CLOCAL;
terminalOptions.c_cflag |= CS8;
terminalOptions.c_cc[VMIN] = 0;
terminalOptions.c_cc[VTIME] = 10;
terminalOptions.c_cflag = CLOCAL;
terminalOptions.c_cflag &= ~HUPCL; //change (disable hang-up-on-close to avoid reset)
ret = tcsetattr(fd, TCSANOW, &terminalOptions); //change
if (ret == -1)
{
this->setFail();
this->setErrorStr( "Failed to configure device: " + (std::string)devicePath + ". " + (std::string)strerror(errno) );
return -1;
}
return fd;

I also have arduino UNO and when I plug it via usb port it connects to /dev/ttyACM0 not ttyUSB0 you should also check ttyACM0 when you plug and unplug your arduino UNO.
It is also the case If you haven't installed arduino port driver

Related

Why when I try set serial port, function return "Input/output error"?

I try set in c++ some serial port, but when I try function tcsetatrr, its return error -1. Port opens without problems.
char port_name[] = "/dev/ttyS1";
int port = open(port_name, O_RDWR | O_NOCTTY | O_NDELAY);
if(port < 0){
std::cout << "Cant open port" << std::endl;
return;
}
struct termios settings;
tcgetattr(port, &settings);
cfgetispeed(&settings);
//std::cout << settings.c_cflag;
//Baudrate
cfsetispeed(&settings, B115200);
cfsetospeed(&settings, B115200);
//Data bits
settings.c_cflag &= ~CSIZE;
settings.c_cflag |= CS8;
//Parity
settings.c_cflag |= ~PARENB;
//Stop bit
settings.c_cflag &= ~CSTOPB;
//Flow control
settings.c_cflag |= ~CRTSCTS;
settings.c_iflag &= ~(IXON | IXOFF | IXANY);
int er = tcsetattr(port, TCSANOW, &settings);
if (er<0) {
fprintf(stderr, "Error openinig: %s\n", strerror(errno));
}
close(port);
output:
Input/output error
How can I fix that? I was running code as root. The problem is not in the configuration of the settings structure because after commenting it out, I get the same error
The most likely answer is that you don't really have a serial device /dev/ttyS1. Try /dev/ttyS0 instead. I have the same deal on my PC.
I see a few additional problems here.
You don't check if tcgetattr() succeeds, so don't be so sure you even get to tcsetattr().
Calling settings.c_cflag |= ~PARENB; or settings.c_cflag |= ~CRTSCTS; is most likely not what you want to do (will raise all flags except the selected one).

No data sent over serial port in linux c++

TL;DR - I am attempting serial communication with Arduino with code that I found here and nothing gets sent over (Arduino programmed to respond, and I checked that it does with its serial monitor)
Hi there,
I was looking for a way to send information over to an Arduino Mega (2560) unit over linux serial port by C++.
I came across the following solution: Solution
I'm using this guy's code for write (I'm able to read data from the arduino) and use the same parameters (they work, as I'm able to receive data from the Ardunio).
I programmed my Arduino to send "Hi" over serial whenever it sees at least 1 bit of information, and checked it worked through the Arduino IDE Serial Monitor.
Yet when running the C++ code, the arduino doesn't respond. Do anyone might have idea why?
Full disclosure - I inserted #Lunatic999's code to a class so I can make an instance of it for my needs of the code.
fd = open(portNameC, O_RDWR | O_NOCTTY | O_SYNC); //open port ("opens file")
Serial Parameters:
struct termios tty;
struct termios tty_old;
memset (&tty, 0, sizeof tty);
/* Error Handling */
if ( tcgetattr ( fd, &tty ) != 0 ) {
std::cout << "Error " << errno << " from tcgetattr: " << strerror(errno) << std::endl;
}
/* Save old tty parameters */
tty_old = tty;
/* Set Baud Rate */
cfsetospeed (&tty, (speed_t)B19200);
cfsetispeed (&tty, (speed_t)B19200);
/* Setting other Port Stuff */
tty.c_cflag &= ~PARENB; // Make 8n1
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8;
tty.c_cflag &= ~CRTSCTS; // no flow control
tty.c_cc[VMIN] = 1; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines
/* Make raw */
cfmakeraw(&tty);
/* Flush Port, then applies attributes */
tcflush( fd, TCIFLUSH );
if ( tcsetattr ( fd, TCSANOW, &tty ) != 0) {
std::cout << "Error " << errno << " from tcsetattr" << std::endl;
}
Write (this code I put inside a function which I call)
unsigned char cmd[] = "INIT \r";
int n_written = 0,
spot = 0;
do {
n_written = write( fd, &cmd[spot], 1 );
spot += n_written;
} while (cmd[spot-1] != '\r' && n_written > 0);
Arduino code:
bool dataRecieved = false;
int ledpin = 13;
void setup() {
pinMode(ledpin, OUTPUT);
digitalWrite(ledpin, HIGH);
Serial.begin(19200);
}
void loop() {
while(!dataRecieved)
{
digitalWrite(ledpin,HIGH);
if (Serial.available() > 0)
{
dataRecieved = true;
}
}
digitalWrite(ledpin,LOW);
delay(1000);
digitalWrite(ledpin,HIGH);
delay(1000);
Serial.println("hi");
}
Turns out it was an arduino problem all along. I needed to apply some usleep to let arduino bootload

Connect to serial device

I'm trying to write bytes to an serialport, where I connect a relay.
Everything works fine, if I use C++ for this: (comments are german, sorry)
#include <fcntl.h>
#include <termios.h>
RelayProtocol::RelayProtocol()
{
// Create structure
struct termios options;
// Open Connection
_handle = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);
// clear all flags
fcntl(_handle, F_SETFL, 0);
// Get current options
tcgetattr(_handle, &options);
// Set Boundrate (19200)
cfsetispeed(&options, B19200); // Input
cfsetospeed(&options, B19200); // Output
// Set serial-flags
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
options.c_cflag |= (CLOCAL | CREAD);
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
options.c_oflag &= ~OPOST;
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 10;
// Flush settings
tcflush(_handle,TCIOFLUSH);
tcsetattr(_handle, TCSAFLUSH, &options);
fcntl(_handle, F_SETFL, FNDELAY);
fcntl(_handle, F_SETFL, 0);
// Initialize relay
SendCommand(1, 1, 0);
}
Now I tried the same using vala:
public static void main (string[] args) {
int handle = Posix.open ("/dev/ttyUSB0", Posix.O_RDWR | Posix.O_NOCTTY | O_NDELAY);
Posix.termios termios;
Posix.fcntl (handle, Posix.F_SETFL, 0);
Posix.tcgetattr (handle, out termios);
termios.c_ispeed = 19200;
termios.c_ospeed = 19200;
/* Configure serialport */
termios.c_cflag &= ~Posix.PARENB;
termios.c_cflag &= ~Posix.CSTOPB;
termios.c_cflag &= ~Posix.CSIZE;
termios.c_cflag |= Posix.CS8;
termios.c_cflag |= (Posix.CLOCAL | Posix.CREAD);
termios.c_lflag &= ~(Posix.ICANON | Posix.ECHO | Posix.ECHOE | Posix.ISIG);
termios.c_oflag &= ~Posix.OPOST;
termios.c_cc[Posix.VMIN] = 0;
termios.c_cc[Posix.VTIME] = 10;
Posix.tcflush (handle, Posix.TCIOFLUSH);
Posix.tcsetattr (handle, Posix.TCSAFLUSH, termios);
Posix.fcntl (handle, Posix.F_SETFL, FNDELAY);
Posix.fcntl (handle, Posix.F_SETFL, 0);
/* Everything works fine, if I open it using tail -f /dev/ttyUSB0*/
uint8[] data = new uint8[4];
data[0] = 1;
data[1] = 1;
data[2] = 0;
data[3] = data[0] ^ data[1] ^ data[2];
int l = (int)Posix.write (handle, data, data.length);
Thread.usleep (1000 * 1000);
data[0] = make_array (2, true)[0];
data[1] = make_array (2, true)[1];
data[2] = make_array (2, true)[2];
data[3] = data[0] ^ data[1] ^ data[2];
l = (int)Posix.write (handle, data, data.length);
}
I have created two variables on the top, which doesn't exist in the posix namespace. I simply print the value in C.
This code in vala doesn't work, the relay doesn't receive anything, although it uses the same flags and handles.
The strange thing is, that the vala code works fine, if I open a terminal and run "tail -f /dev/ttyUSB0".
It seems that the valacode isn't able to initialize the serial port, so relay will never receive them.
Anybody know a fix for this, or find my mistake in the vala code?
Normally the librarys should be the same in both programming languages.

How to check serial port in linux work properly

I am going to use serial port in my C++ program linux ubuntu 10.4 ,this is my open port function :
int Recorder::OpenPort()
{
int intFd ;
struct termios options;
intFd=open("/dev/ttyS0", O_RDWR | O_NOCTTY| O_NDELAY);
if (intFd==-1){
perror("open_port: Unable to open /dev/ttyS0 - ");
}
fcntl(intFd, F_SETFL, FNDELAY); /*configuration the port*/
tcgetattr(intFd, &options);
//set baud rates at 115200
cfsetispeed(&options, B115200 );
cfsetospeed(&options, B115200);
//mask the character size to 8 bit data & no parity.CHARACTER SIZE SETTING
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
//setting hardware flow control
options.c_cflag |= CRTSCTS;
//Enable the receiver and set local mode .should always be enabled (enable receiver and dont change owner of port)
options.c_cflag |= (CLOCAL | CREAD);
//flush output buffer
options.c_lflag |= FLUSHO;
//choosing raw data disable echoing
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
//not setting software flow control
options.c_iflag &= ~(IXON | IXOFF | IXANY);
options.c_oflag &= ~OPOST;
// //output changes :for mapping NL to CR-NL.
// options.c_oflag |= (OPOST | ONLCR );
//
// options.c_oflag |= (NL1 | CR1 | FFDLY);
tcsetattr(intFd, TCSANOW, &options);
return intFd;
}
and this is the sample where I check my serial number:
int serial=0;
ioctl(intFd, TIOCMGET, &serial);
//for ubuntu 7.04 and 10.04
if(serial==16390 || serial==16422 || serial==16454 || serial==16486){//no connection with serial port
i checked my program many times and serial is 16486 every times and it means I have no connection with serial port , I checked my serial cable and it was ok? so how can I Solve my problem?

What have i missed when writing this serial test program

I am having serious trouble with rs232 communications in linux so i wrote this test program to make sure it was not other parts of my program interfering with the serial communications.
The program however does not work so as i feared it is the serial port code that is the problem.
I have a laptop with centos running the program and that is connected to a computer with windows xp running hyperterminal. the code executes ok according to the error checking but nothing is showing up in huperterminal.
The serial pore setup I am trying to achive is 115200 baud rate, 8 databits, 1 stopbit and mark parity.
This is the program:
#include <termios.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <ncurses.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
int port, serial, i;
unsigned long nobw;
char buf[10];
struct termios options;
port = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
if (port == -1)
perror("open_port: Unable to open /dev/ttyS0 - ");
else
printf("port open \n");
tcgetattr(port, &options); // get current settings
cfsetispeed(&options, 115200); // set baud rate
cfsetospeed(&options, 115200); // set baud rate
options.c_cflag &= ~CSIZE; // Mask the character size bits
options.c_cflag |= CS8; // 8 bit data
options.c_cflag &= ~PARENB; // set parity to no
options.c_cflag &= ~PARODD; // set parity to no
options.c_cflag |= CSTOPB;//set mark parity by using 2 stop bits
options.c_cflag |= (CLOCAL | CREAD);
options.c_oflag &= ~OPOST;
options.c_lflag &= 0;
options.c_iflag &= 0; //disable software flow controll
options.c_oflag &= 0;
tcsetattr(port, TCSANOW, &options);// save the settings
ioctl(port, TIOCMGET, &serial);
serial |= TIOCM_DTR; // set DTR to high
ioctl(port, TIOCMSET, &serial);
for(i = 0; i < 10; i++)
{
buf[i] = i;
}
for(i = 0; i < 10; i++)
{
errno = 0;
nobw = write(port, buf, 1);
if(nobw == -1)
perror("WriteComm:");
else
printf("sent character %d \n", i);
}
return 0;
}
This is all done from tutorials on the interned i have little idea what im doing, can you see where i have gone wrong ?
also if anyone knows how to do space parity that would also be appreciated.
Maybe worth checking if the setup works without your code? :)
If you connect using minicom on the linux side and hyperterminal on the windows side, can you pass data back and forth?