init, read and write for linux serial device with C - c

I'm working on a new project where I want to make a connection with an FTDI which is connected to my debian machine. I am intending to write the code with C, not C++. Here lies my problem. All the examples I find are incomplete or are made for a c++ compiler in stead of the GCC compiler.
The goal is to talk to my microcontroller which is connected to the FTDI. For debugging i want to start building a linux application which is able to:
initialize a serial connection on startup with ttyUSB1
send a character string
display character strings when they are received by the pc
save the communication to a .txt file
Is there any example code or tutorial to make this?
If I succeed I will defenetly place the code here so that new viewers can use it to!
Edit:
Like I said I would post the code if I had it, and this is what worked for me:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#define MODEM "/dev/ttyUSB0"
#define BAUDRATE B115200
int main(int argc,char** argv)
{
struct termios tio;
struct termios stdio;
struct termios old_stdio;
int tty_fd, flags;
unsigned char c='D';
tcgetattr(STDOUT_FILENO,&old_stdio);
printf("Please start with %s /dev/ttyS1 (for example)\n",argv[0]);
memset(&stdio,0,sizeof(stdio));
stdio.c_iflag=0;
stdio.c_oflag=0;
stdio.c_cflag=0;
stdio.c_lflag=0;
stdio.c_cc[VMIN]=1;
stdio.c_cc[VTIME]=0;
tcsetattr(STDOUT_FILENO,TCSANOW,&stdio);
tcsetattr(STDOUT_FILENO,TCSAFLUSH,&stdio);
fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); // make the reads non-blocking
memset(&tio,0,sizeof(tio));
tio.c_iflag=0;
tio.c_oflag=0;
tio.c_cflag=CS8|CREAD|CLOCAL; // 8n1, see termios.h for more information
tio.c_lflag=0;
tio.c_cc[VMIN]=1;
tio.c_cc[VTIME]=5;
if((tty_fd = open(MODEM , O_RDWR | O_NONBLOCK)) == -1){
printf("Error while opening\n"); // Just if you want user interface error control
return -1;
}
cfsetospeed(&tio,BAUDRATE);
cfsetispeed(&tio,BAUDRATE); // baudrate is declarated above
tcsetattr(tty_fd,TCSANOW,&tio);
while (c!='q'){
if (read(tty_fd,&c,1)>0){
write(STDOUT_FILENO,&c,1); // if new data is available on the serial port, print it out
printf("\n");
}
if (read(STDIN_FILENO,&c,1)>0){
write(tty_fd,&c,1);//if new data is available on the console, send it to serial port
printf("\n");
}
}
close(tty_fd);
tcsetattr(STDOUT_FILENO,TCSANOW,&old_stdio);
return EXIT_SUCCESS;
}
Most of the code came from http://en.wikibooks.org/wiki/Serial_Programming/Serial_Linux but i also used a bit from the code posted below.

Handling with serial ports ( for linux OS ) :
- To open communication, you will need a descriptor which will be the handle for your serial port.
- Set the flags to control how the comunication will be.
- Write the command to this Handle ( make sure you're formatting the input correctly ).
- Get the answer. (make sure you're to read the amount of information you want )
- Close the handle.
It will seem like this:
int fd; // file descriptor
int flags; // communication flags
int rsl_len; // result size
char message[128]; // message to send, you can even dinamically alocate.
char result[128]; // result to read, same from above, thanks to #Lu
flags = O_RDWR | O_NOCTTY; // Read and write, and make the job control for portability
if ((fd = open("/dev/ttyUSB1", flags)) == -1 ) {
printf("Error while opening\n"); // Just if you want user interface error control
return -1;
}
// In this point your communication is already estabilished, lets send out something
strcpy(message, "Hello");
if (rsl_len = write(fd, message, strlen(message)) < 0 ) {
printf("Error while sending message\n"); // Again just in case
return -2;
}
if (rsl_len = read(fd, &result, sizeof(result)) < 0 ) {
printf("Error while reading return\n");
return -3;
}
close(fd);
Note that you have to care about what to write and what to read.
Some more flags can be used in case of parity control, stop bits, baud rate and more.

Since gcc is a C/C++ compiler, you don't need to limit yourself to pure C.
Sticking to pure C is OK if you enjoy writing lots of boilerplate code, and if you really know what you're doing. Many people use Unix APIs incorrectly, and a lot of example code out there is much too simplistic. Writing correct Unix C code is somewhat annoying, to say the least.
Personally, I'd suggest using not only C++, but also a higher-level application development framework like Qt. Qt 5 comes bundled with a QtSerialPort module that makes it easy to enumerate the serial ports, configure them, and get data into and out of them. Qt does not force you to use the gui modules, it can be a command line application, or a non-interactive server/daemon.
QtSerialPort is also usable from Qt 4, but it doesn't come bundled with Qt 4, you have to add it to your project. I suggest starting out with Qt 5, it's nicer to use with its C++11 support.
The code using Qt can be pretty simple, not much longer than your plain-English description. The below is a Qt console application using Qt 5 and C++11. It uses the core and serialport modules. It also handles the SIGINT signal so that the output file gets flushed before the process would terminate due to a ^C. I'm using QLocalSocket in place of raw Unix API to communicate from the Unix signal handler, the functionality is the same.
Only the code within main is strictly required, the rest is just to make it properly wrap things up when you hit ^C.
#include <QCoreApplication>
#include <QSerialPort>
#include <QFile>
#include <QTextStream>
#include <QLocalServer>
#include <QLocalSocket>
#include <cstdio>
#include <csignal>
QLocalSocket * xmit;
static void signalHandler(int)
{
xmit->write(" ");
xmit->flush();
}
static bool setupSignalHandler()
{
QLocalServer srv;
srv.listen("foobarbaz");
xmit = new QLocalSocket(qApp);
xmit->connectToServer(srv.serverName(), QIODevice::WriteOnly);
srv.waitForNewConnection();
QLocalSocket * receive = srv.nextPendingConnection();
receive->setParent(qApp);
qApp->connect(receive, &QLocalSocket::readyRead, &QCoreApplication::quit);
struct sigaction sig;
sig.sa_handler = signalHandler;
sigemptyset(&sig.sa_mask);
sig.sa_flags = SA_RESTART;
return ! sigaction(SIGINT, &sig, NULL);
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
setupSignalHandler();
QSerialPort port("ttyUSB1");
QFile file("file.txt");
QTextStream err(stderr, QIODevice::WriteOnly);
QTextStream out(stdout, QIODevice::WriteOnly);
if (!file.open(QIODevice::WriteOnly)) {
err << "Couldn't open the output file" << endl;
return 1;
}
if (!port.open(QIODevice::ReadWrite)) {
err << "Couldn't open the port" << endl;
return 2;
}
port.setBaudRate(9600);
QObject::connect(&port, &QSerialPort::readyRead, [&](){
QByteArray data = port.readAll();
out << data;
file.write(data);
});
out << "Use ^C to quit" << endl;
return a.exec();
}

Related

How to make C program communicate with Python program using Linux's virtual serial ports?

I would like to send data from a C program into a Python program that will visualize this data. Development environment is a Linux (Ubuntu 18.04LTS) computer. To be clearer, both of the programs are running on the same computer.
I am using termios for opening the serial port in C program, and pySerial in the Python side. As for the serial port, I am using "ttyS0". The problem is that, when I send "Hello" from C program to the Python program and print it on the terminal what I see is space character, basically I am gettin this " ".
My question is, can I use the "ttyS0" serial port (I guess that is a virtual port) for this purpose?
Here is the C code:
#include <stdint.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <termios.h>
#include <time.h>
// Termios init functions are not posted because the configuration
// is correct and proved that they are working.
int main()
{
char *portname = "/dev/ttyS0";
int fd;
int wlen;
unsigned char writeBuffer[] = "Hello!";
fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0) {
printf("Error opening %s: %s\n", portname, strerror(errno));
return -1;
}
/*baudrate 115200, 8 bits, no parity, 1 stop bit */
set_interface_attribs(fd, B115200);
do{
wlen = write(fd, writeBuffer, sizeof(writeBuffer));
printf("Sent data is: \"%s\"\n", writeBuffer);
delay(500);
} while(1);
}
The Python code:
import serial
from time import sleep
port = "/dev/ttyS0"
ser = serial.Serial(port, 115200, timeout=0.5)
while True:
data = ser.readline()
print(str(data.decode('utf-8')))
ser.close()
ttyS0 is your computer's serial port -- there's nothing "virtual" about it. Writing to this device will attempt to transmit data out of the computer using that port, and reading from the device will attempt to receive data from an external device connected to the port. There is no way for two programs on the same computer to usefully communicate using a serial port.
What I think you're looking for here is either a pipe, a socket pair, or a pty. Which one is most appropriate will depend on your specific requirements.

USB to Serial: LoopBack Read-Write Programs

I am using BAFO bf-810 USB to Serial adapter with pl2303 drivers on Mac OS X. I am a beginner in the field and so have got the high level APIs from here which is a cross-platform API.
I have two programs, one to write and one to read. This API does not have a inbuilt samples in the code. So I had to look at other's APIs to get a picture of what had to be done (like, comOpen, comWrite etc.). With the limited knowledge, I wrote the following little programs using the linked APIs.
sendSerial.c
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include "rs232.h"
extern int errno;
int main(){
comEnumerate();
if(!comOpen(1, 9600)) printf("Cannot open the port\n");
while (1){
char data[1024] = "Hello World";
int ret = comWrite(1, data, 512);
printf("%d\n", ret);
if(ret>0){
printf("Bytes transferred!\n");
} else{
printf("%s\n", strerror(errno));
}
sleep(1);
}
return 0;
}
.
recSerial.c
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include "rs232.h"
extern int errno;
int main(){
comEnumerate();
if(!comOpen(1, 9600)) printf("Cannot open the port\n");
char read[1024] = "EMPTY";
printf("\nNow reading data at %s...\n",comGetPortName(1));
while (1){
printf(".\n");
if(comRead(1, read, 4)){
printf("Data: %s\n**\n", read);
}
sleep(1);
}
return 0;
}
The source has a single C program and might help on what I might be missing.
Question
When sending data, the write returns the Resource temporarily unavailable error after the third iteration. Why is this happening consistently? When I restart the sender program when the receiver is running, the error starts off with the first iteration itself.
In any case, I am not able to read any data on the read side of the program. I understand that the RS232 is an async protocol, but I've read somewhere that the system has a buffer of around 4 Mb before the data gets overwritten. So the second question is, do I have to manually handle the clock synchronisation?
P.S.: For the loopback test, I have connected, Send-Recieve, RTS-CTS and DTR-DSR on the DB9 connector.

Write and then read to serial port in C

I have a USB to serial adapter attached to /dev/ttyUSB0 which connects to a rotation stage. I can communicate to that rotation stage by simply sending ASCII commands over the serial port. i.e. to request the current position of that rotation stage just:
in window 1: echo -e "1tp\r" > /dev/ttyUSB
in window 2: cat /dev/ttyUSB which returns the current position: "1TP-0.00000"
Now I want to be able to do exactly this at a certain trigger inside a C program.
I've browsed this amazing archive and found a few examples of how it can be done. For example
how to open, read, and write from serial port in C
Linux C Serial Port Reading/Writing
Serial port loopback/duplex test, in Bash or C? (process substitution)
So based on those, I wrote this very ugly code to simply try writing "1tp\r" to the serial port and then reading the returned value ( the rotation stage position) back. Here is the code below.
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
int main(int argc, char *argv[])
{
char line[1024];
int chkin;
int chkout;
char input[1024];
char msg[1024];
char serport[24];
// argv[1] - serial port
sprintf(serport, "%s", argv[1]);
int file= open(serport, O_RDWR | O_NOCTTY | O_NDELAY);
printf("file descriptor: %d\n",file);
if (file == 0)
{
sprintf(msg, "open_port: Unable to open %s.\n", serport);
perror(msg);
}
else
fcntl(file, F_SETFL, FNDELAY); //fcntl(file, F_SETFL, 0);
while (1)
{
usleep (1000000);
// printf("enter input data:\n");
//scanf("%s",&input[0]);
// printf("You entered %s\n",&input);
//input= "1tp\r";
chkin = write(file,"1tp\r",5);
printf("chkin: %d\n",chkin);
if (chkin<0)
{
printf("cannot write to port\n");
}
fcntl(file, F_SETFL, FNDELAY);
//chkin=read(file,line,sizeof line);
usleep (100000);
//while ((chkin=read(file,line,sizeof line))>=0)
//printf("chkin: %d\n",chkin);
chkout = read(file, line ,sizeof line);
//{
if (chkout<0)
{
printf("cannot read from port\n");
}
else
{
printf("bytes: %d, line=%s\n",chkout, line);
}
//}
/*CODE TO EXIT THE LOOP GOES HERE*/
if (input[0] == 'q') break;
}
close(file);
return 0;
}
Well, it doesn't work. When I run it as: ./sertest /dev/ttyUSB0, I just get the error "cannot read from port". In reality, the problem seems to be that the "1tp\r" string does not seem to get written to the serial port. In addition, once I am done with this, the serial port settings seem to be all messed up because I can't communicate at all with the stage via simple terminal commands and need to reset the serial port using minicom.
I should also note that I know I can successfully read something from the serial port with the second part of that code because I have managed to send the "1tp\r" string with a terminal command and just read the output of the stage with the relevant snippet of code in the example below.
So, I would appreciate some input on how to successfully write this simple string "1tp\r" ( or a similar one) to the serial port and alternate to reading the serial port.
I am not a programmer so I apologize in advance for the poor style of the piece of code here.

C RbPi UART Remote Control Sockets

I want to remote control sockets in my room manual without an extra library on my raspberry pi. I want to use the UART interface in C. The socket has 433 Mhz receiver and I use a 433 Mhz transmitter. In other librarys you type something like this: send 11111 1 1. (socket code, socket number, condition). But how to format this command in C with the write() function? The 10 is for number of characters. I use this code below. I tested the output via minicom, that works fine. But how the receiver now knows that it was adressed?
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
int main(int argc, char ** argv) {
int fd;
// Open the Port. We want read/write, no "controlling tty" status, and open i$
fd = open("/dev/ttyAMA0", O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1) {
perror("open_port: Unable to open /dev/ttyAMA0 - ");
return(-1);
}
// Turn off blocking for reads, use (fd, F_SETFL, FNDELAY) if you want that
fcntl(fd, F_SETFL, 0);
// Write to the port
int n = write(fd,"11111 1 1",10);
if (n < 0) {
perror("Write failed - ");
return -1;
}
// Don't forget to clean up
close(fd);
return 0;
}
Do I get it right: you send a command via UART to transmit a message via radio trasmitter. Sniffing the UART output proves your code OK in the sense that TX line sends what you want it to send in the software, and the actual question is "how the rx module gets that message/how to make the rx module get it?"
If so, the main question is what kind of radio TX/RX or TRXs do you actually use (I mean chip/module codes, like CC1120, NRF2401 etc.)? There are plenty of 433MHz radiomodules available, I suppose consulting their datasheet first or at least posting the part number here is the right way to go.

Serial communication buffer data out of order

I'm trying to implement a simple SLAM project with Arduino and C on Linux Mint 15.
The Arduino project is sending data to notebook via bluetooth (serial). The data is read by a C program. In Arduino serial, the data is shown correctly, but in the notebook, the received data is wrong. (In image, white is Arduino data. The terminal shows the 'received' data.)
I'm sending d080x096y099z035 (for example) and receiving 99z0356y0999z035 (out of order?).
So, I have some questions:
What can I do to make the read()command in C, read the data in the correct order and length? (order: d000x000y000z000, length = 16)
In the Arduino sending function, are there length differences using Serial.print(char buffer[]) and Serial.println(char buffer[])? (Like adding a '\n' or something else at the end of buffer?)
Should I use the delay() function in the Arduino code or in the C code?
In Arduino:
...
int buffer_size = 17;
char buffer[17];
//void setup()
void loop(){
//create the string resp = "d000x111y222z333"
...
resp.toCharArray(buffer, buffersize);
bluetooth.print(buffer);
delay(200);
}
In C program:
...
int fd = open("/dev/rfcomm4", O_RDONLY | O_NOCTTY | O_NDELAY);
printf("fd code %d\n", fd);
if (fd == -1)
{
gchar *msg = "open_port: Unable to open /dev/rfcomm4";
gtk_label_set_text(GTK_LABEL(label), msg);
perror("error: ");
}
char buffer[17];
int n;
printf("entering in loop...\n");
while (1)
{
n = read(fd, buffer, sizeof(buffer));
printf("%s\n", buffer);
}
Sorry I'm not an expert but just a few ideas you might check concering your questions:
to 1) I guess it might be a problem with encoding, as Python AFAIK expects files to be unicode. So try open (.... ,encoding='ascii') or whatever encoding you use
Please also pay attention that you might block the GTK mainthread, that causes heavy delays in your UI. So I recommend creating a own thread for reading the serial port and filling an internal buffer, that get's rendered by the GTK mainthread, if you send an update request:
http://www.pardon-sleeuwaegen.be/antoon/python/page0.html

Resources