Half Duplex RS485 linux Serial USB Programing in C - c

I'm trying to setup half duplex communication in Ubuntu 14.04 in my program. I have my RS485 transceiver using the RTS line to toggle back and forth between transmit and receive. I'm using a speak when spoken to system and this program is the master. The problem is that the RTS isn't toggling back off when I'm done sending the package so I can receive the data. Basically I want it to turn the RTS high, send the data, turn the RTS low, then read the data. Any help would be great.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/signal.h>
#include <sys/types.h>
#define BAUDRATE B38400
#define COMPORT "/dev/ttyUSB0"
#define _POSIX_SOURCE 1
#define FALSE 0
#define TRUE 1
#define STX_KEYPAD 0xE1
#define PAYLOAD_BUFF_SIZE 256
#define CRC_HI 0xD8
#define CRC_LOW 0xC3
volatile int STOP=FALSE;
int ser_port;
int bus_address = 1;
int message_length = 0;
struct termios oldtio,newtio;
unsigned char rxbuf[256];
unsigned char tx_flags = 0;
void openCommPort();
void sendSerial();
int setRTS(int level);
int main(void)
{
printf("Starting...\r\n");
openCommPort();
setRTS(1);
printf("Sending Serial Data\r\n");
sendSerial();
setRTS(0);
//close(ser_port);
printf("All Done\r\n");
return EXIT_SUCCESS;
}
void openCommPort()
{
ser_port = open(COMPORT, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (ser_port == -1)
{
perror(COMPORT);
perror("Unable to open port");
exit(-1);
}
if(tcgetattr(ser_port,&oldtio) <0)// save current port settings
{
perror(COMPORT);
perror("Couldn't get old terminal attributes");
exit (-1);
}
bzero(&newtio, sizeof(newtio));
newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD | CRTSCTS;
newtio.c_iflag = IGNPAR | ICANON;
newtio.c_oflag = 0;
// set input mode (non-C, no echo,...)
newtio.c_lflag = 0;
newtio.c_cc[VTIME] = 0; // inter-character timer unused
newtio.c_cc[VMIN] = 0; // blocking read until 5 chars received
tcflush(ser_port, TCIFLUSH);
tcsetattr(ser_port,TCSANOW,&newtio);
}
void sendSerial()
{
unsigned char tx_header[6];
tx_header[0] = STX_KEYPAD;
tx_header[1] = bus_address;
tx_header[2] = tx_flags;
tx_header[3] = message_length;
tx_header[4] = CRC_HI;
tx_header[5] = CRC_LOW;
if((write(ser_port, tx_header, 6)) != 6)
{
printf("Error sending data! Not all bytes sent\r\n");
}
}
int setRTS(int level)
{
int status;
if (ioctl(ser_port, TIOCMGET, &status) == -1)
{
perror("getRTS(): TIOCMSET");
return 0;
}
if(level)
{
status |= TIOCM_RTS;
}
else
{
status &= ~TIOCM_RTS;
}
if (ioctl(ser_port, TIOCMSET, &status) == -1)
{
perror("setRTS(): TIOCMSET");
return 0;
}
return 1;
}

Related

Send Commands to serial device and receiving response

Am trying to send a command to a serial device (arduino) and receive a response, the command goes through but I don't get a response from the target device.
I want the C program to control the serial device by sending & receiving data.
Arduino Code:
void setup() {
// initialize serial communication:
Serial.begin(9600);
}
void loop() {
if (Serial.available() > 0) {
int inByte = Serial.read();
switch (inByte) {
case 'H':
Serial.print("75864d63001bebaa");
break;
}
}
}
C Code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <sys/ioctl.h>
int main(int argc, char *argv[]) {
int fd, n, i;
char buf[64] = "temp text";
struct termios toptions;
/* open serial port */
fd = open("/dev/ttyACM0", O_RDWR | O_NOCTTY);
printf("fd opened as %i\n", fd);
/* wait for the Arduino to reboot */
usleep(3500000);
/* get current serial port settings */
tcgetattr(fd, &toptions);
/* set 9600 baud both ways */
cfsetispeed(&toptions, B9600);
cfsetospeed(&toptions, B9600);
/* 8 bits, no parity, no stop bits */
toptions.c_cflag &= ~PARENB;
toptions.c_cflag &= ~CSTOPB;
toptions.c_cflag &= ~CSIZE;
toptions.c_cflag |= CS8;
/* Canonical mode */
toptions.c_lflag |= ICANON;
/* commit the serial port settings */
tcsetattr(fd, TCSANOW, &toptions);
/* Send byte to trigger Arduino to send string back */
write(fd, "H", 1);
/* Receive string from Arduino */
n = read(fd, buf, 64);
/* insert terminating zero in the string */
buf[n] = 0;
printf("%i bytes read, buffer contains: %s\n", n, buf);
return 0;
}

Reading arduino serial in linux using C

I want to read serial from arduino. I use this code :
#include <stdio.h> /* Standard input/output definitions */
#include <string.h> /* String function definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
#include <sys/ioctl.h>
int main(){
char data[1024];
char dev[] = "/dev/ttyACM1";
int fd = open(dev, O_RDWR | O_NOCTTY | O_NDELAY);
fcntl(fd, F_SETFL, FNDELAY);
struct termios options;
tcgetattr(fd, &options);
cfsetispeed(&options, B9600);
cfsetospeed(&options, B9600);
options.c_cflag |= CS8;
options.c_cflag |= CS8;
options.c_cflag &= ~CRTSCTS;
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
tcsetattr(fd, TCSANOW, &options);
ioctl(fd, TCFLSH, 2);
while(1){
read(fd, data, sizeof(data));
printf(data);
}
//write(fd, data, sizeof(data));
}
My arduino runs very simple sketch :
int x;
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println("DO YOU HEAR ME ??");
delay(1000);
}
and output of this combinatin is that :
??OU HEAR ME ??
DO YOU HEAR ME ??
DO YOU HEAR ME ??
A¹­þ
??OU HEAR ME ??
DO YOU HEAR ME ??
DO YOU HEAR ME ??
A¹­þ
??OU HEAR ME ??
DO YOU HEAR ME ??
DO YOU HEAR ME ??
My question is how to make order out of chaos. I found that this issue occurs when buffer ends and new one begins(bigger buffer less junk data) but I can't have a infinite buffer. Also there is a lot of junk when it reads for the first time.. Is there a way to sync it or something ?
(Also I am not native English sorry for any mistakes.)
I found answer to my own problem. I used this time c++ to organize it in class (very poor one because it doesn't handle any errors and doesn't use c++ in the most..) Here is the code :
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <cstring>
#include <iostream>
//Here I define some vars
#define BAUDRATE B9600
#define MODEMDEVICE "/dev/ttyACM0"
#define _POSIX_SOURCE 1
class serial{
public:
serial(){
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
if (fd <0) {perror(MODEMDEVICE); exit(-1); }
// Improvement No. 1 I save old setting and clean the new one
tcgetattr(fd,&oldtio);
bzero(&newtio, sizeof(newtio));
// Here I set all the flags to vars at once
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR | ICRNL;
newtio.c_oflag = 0;
newtio.c_lflag = ICANON;
//here I set some new flags..
newtio.c_cc[VINTR] = 0; /* Ctrl-c */
newtio.c_cc[VQUIT] = 0; /* Ctrl-\ */
newtio.c_cc[VERASE] = 0; /* del */
newtio.c_cc[VKILL] = 0; /* # */
newtio.c_cc[VEOF] = 4; /* Ctrl-d */
newtio.c_cc[VTIME] = 0; /* inter-character timer unused */
newtio.c_cc[VMIN] = 1; /* blocking read until 1 character arrives */
newtio.c_cc[VSWTC] = 0; /* '\0' */
newtio.c_cc[VSTART] = 0; /* Ctrl-q */
newtio.c_cc[VSTOP] = 0; /* Ctrl-s */
newtio.c_cc[VSUSP] = 0; /* Ctrl-z */
newtio.c_cc[VEOL] = 0; /* '\0' */
newtio.c_cc[VREPRINT] = 0; /* Ctrl-r */
newtio.c_cc[VDISCARD] = 0; /* Ctrl-u */
newtio.c_cc[VWERASE] = 0; /* Ctrl-w */
newtio.c_cc[VLNEXT] = 0; /* Ctrl-v */
newtio.c_cc[VEOL2] = 0; /* '\0' */
// and I finally save the settings
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
}
~serial(){
close(fd);
}
std::string sread(){
res = read(fd,buf,255);
buf[res]=0;
return buf;
}
void swrite(const char* input){
write(fd,input,std::strlen(input));
}
private:
int fd,c,res;
struct termios oldtio,newtio;
char buf[255];
};
int main(){
serial s;
s.swrite("Light");
std::string buf = s.sread();
std::cout << buf;
}
This is more of a ripoff from "Serial programming HOW TO" : http://tldp.org/HOWTO/Serial-Programming-HOWTO/ (form the example code..)
And here is the new poor arduino code :
int x;
String buff;
int lpin = A0;
int tpin = A1;
int data;
void setup() {
Serial.begin(9600);
pinMode(lpin,INPUT);
pinMode(tpin,INPUT);
}
void loop() {
if(Serial.available() == 1)
{
buff = Serial.readString();
if(buff == "Light"){
data = analogRead(lpin);
Serial.print(data);
Serial.print("\n");
}else if(buff == "Temp"){
data = analogRead(tpin);
Serial.print(data);
Serial.print("\n");
}else{
Serial.print("Something went wrong !");
Serial.print("\n");
}
}
delay(1);
}

Process that can sleep waiting for a tty driver protocol RX

My aim is to have a user space linux process that sleep while a tty uart based driver is receiving a message.
The protocol is a very simple (bad) stream of data that starts with a break signal followed by 513 bytes.
So far I modified the freescale's tty uart driver interrupt to receive the message.
static int DMX_RX(struct imx_port *sport)
{
struct tty_port *port = &sport->port.state->port;
tty_flip_buffer_push(port);
struct uart_state *state = sport->port.state;
if (sport->port.flags & UPF_SAK)
do_SAK(state->port.tty);
return 0;
}
static irqreturn_t imx_rxint(int irq, void *dev_id)
{
struct imx_port *sport = dev_id;
unsigned int rx, flg, ignored = 0;
struct tty_port *port = &sport->port.state->port;
unsigned long flags, temp;
spin_lock_irqsave(&sport->port.lock, flags);
while (readl(sport->port.membase + USR2) & USR2_RDR)
{
flg = TTY_NORMAL;
sport->port.icount.rx++;
rx = readl(sport->port.membase + URXD0);
temp = readl(sport->port.membase + USR2);
if (temp & USR2_BRCD)
{
writel(USR2_BRCD, sport->port.membase + USR2);
// Break received then push the message to userspace
DMX_RX(sport);
}
else
{
// Byte received then put it in the flip buffer
tty_insert_flip_char(port, rx, flg);
}
.....
// other stuff
.....
out:
spin_unlock_irqrestore(&sport->port.lock, flags);
return IRQ_HANDLED;
}
Then I implemented a simple process on linux user space as below:
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <linux/termios.h>
#include <sched.h>
int ioctl(int d, int request, ...);
#define MAX_DATA_LOG 1000
int main(int argc, char *argv[])
{
struct termios2 t;
int fd,baud;
char buf[513];
fd = open("/dev/ttyDMXc4", O_RDONLY | O_NOCTTY | O_NDELAY);
baud = 250000;
if (ioctl(fd, TCGETS2, &t))
{
perror("TCGETS2");
return 3;
}
t.c_cflag &= ~CBAUD;
t.c_cflag |= BOTHER;
t.c_cflag |= CSTOPB;
t.c_ospeed = baud;
t.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO);
/* Noncanonical mode, disable signals, extended
input processing, and echoing */
t.c_iflag &= ~(BRKINT | ICRNL | IGNBRK | IGNCR | INLCR |
INPCK | ISTRIP | IXON | PARMRK);
/* Disable special handling of CR, NL, and BREAK.
No 8th-bit stripping or parity error handling.
Disable START/STOP output flow control. */
t.c_oflag &= ~OPOST; /* Disable all output processing */
if (ioctl(fd, TCSETS2, &t))
{
perror("TCSETS2");
return 4;
}
if (ioctl(fd, TCGETS2, &t))
{
perror("TCGETS2");
return 5;
}
printf("actual speed reported %d\n", t.c_ospeed);
typedef struct {
unsigned long time;
unsigned int res;
}stuct_appo;
int ret = 1;
int res;
int i;
fd_set read_fds;
struct timeval tv;
int data_log_idx=1;
stuct_appo data_log[MAX_DATA_LOG];
struct timespec now;
while (1)
{
tv.tv_sec = 1;
tv.tv_usec = 0;
FD_ZERO(&read_fds);
FD_SET(fd, &read_fds);
ret = select (fd+1, &read_fds, NULL, NULL, &tv);
if (ret > 0)
{
res = read (fd, buf, 513);
if (res > 0)
{
clock_gettime(0, &now);
data_log[data_log_idx].time = now.tv_nsec;
data_log[data_log_idx].res = res;
data_log_idx = (data_log_idx % MAX_DATA_LOG) + 1;
}
}
else
{
int i;
printf("TIMEOUT %d!!!\n", ret);
for (i=1; i<data_log_idx; i++)
printf("%lu\n", data_log[i].time);
for (i=1; i<data_log_idx; i++)
printf("%d\n", data_log[i].res);
}
}
return 0;
}
As you can see the select has a 1 sec of timeout.
I start my process and after receiving some messages I stop the sender and the process printout timings and received char.
What I can see is that sometimes (very often) select return and the read: eg 69 bytes.
At the end all 513 bytes are read, but shared on 2 or 3 read, eg: 154 and 359 bytes.
I'm sure that driver push data of split buffer each 513 bytes, so my doubt is:
Is select awaking at the wrong time when the flip buffer is not pushed?
Is the read function that can read less that the whole buffer even if I specified 513 in the third parameter?

example C code for reading from a serial port using Cygwin

I am trying to create a simple serial communications program on code blocks with a Cygwin environment under Windows 7.
The program is just meant to read bytes from the serial port which is connected to a gps using three pins on the com port (TX, RX, GND)
I have a program that works (taken from an example i found) but polls till there is data from serial.
{
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#define BAUDRATE B115200
#define MODEMDEVICE "/dev/ttyS0"
#define FALSE 0
#define TRUE 1
main()
{
int fd,c, res, x;
struct termios oldtio,newtio;
uint8_t buf[255];
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
if (fd <0) {perror(MODEMDEVICE); exit(-1); }
tcgetattr(fd,&oldtio); /* save current port settings */
bzero(&newtio, sizeof(newtio));
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR;
newtio.c_oflag = 0;
fcntl(fd, F_SETOWN, getpid());
/* set input mode (non-canonical, no echo,...) */
newtio.c_lflag = 0;
newtio.c_cc[VTIME] = 1; /* inter-character timer unused */
newtio.c_cc[VMIN] = 1; /* blocking read until 10 chars received */
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
while (1) { /* loop for input */
res = read(fd,buf,255); /* returns after 5 chars have been input */
for (x=0;x<res;x++)
{
printf("%x ", buf[x]);
}
printf(":%d\n",res);
}
tcsetattr(fd,TCSANOW,&oldtio);
}
}
I would like to rather have an interrupt that allows me to run things in the background till something comes to the serial port.
I found an example that uses signal.h but it doesn't work? Can some help me.
{
#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/signal.h>
#include <sys/types.h>
#define BAUDRATE B115200
#define MODEMDEVICE "/dev/ttyS0"
#define _POSIX_SOURCE 1 /* POSIX compliant source */
#define FALSE 0
#define TRUE 1
volatile int STOP=FALSE;
void signal_handler_IO (int status); /* definition of signal handler */
int wait_flag=TRUE; /* TRUE while no signal received */
main()
{
int fd,c, res;
struct termios oldtio,newtio;
struct sigaction saio; /* definition of signal action */
char buf[255];
/* open the device to be non-blocking (read will return immediatly) */
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd <0) {perror(MODEMDEVICE); exit(-1); }
/* install the signal handler before making the device asynchronous */
saio.sa_handler = signal_handler_IO;
saio.sa_mask = 0;
saio.sa_flags = 0;
// saio.sa_restorer = NULL;
sigaction(SIGIO,&saio,NULL);
/* allow the process to receive SIGIO */
fcntl(fd, F_SETOWN, getpid());
/* Make the file descriptor asynchronous (the manual page says only
O_APPEND and O_NONBLOCK, will work with F_SETFL...) */
fcntl(fd, F_SETFL, FASYNC);
tcgetattr(fd,&oldtio); /* save current port settings */
/* set new port settings for canonical input processing */
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR | ICRNL;
newtio.c_oflag = 0;
newtio.c_lflag = 0;
newtio.c_cc[VMIN]=1;
newtio.c_cc[VTIME]=0;
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
/* loop while waiting for input. normally we would do something
useful here */
while (STOP==FALSE) {
printf(".\n");usleep(100000);
/* after receiving SIGIO, wait_flag = FALSE, input is available
and can be read */
if (wait_flag==FALSE) {
res = read(fd,buf,255);
buf[res]=0;
printf(":%s:%d\n", buf, res);
if (res==1) STOP=TRUE; /* stop loop if only a CR was input */
wait_flag = TRUE; /* wait for new input */
}
}
/* restore old port settings */
tcsetattr(fd,TCSANOW,&oldtio);
}
/***************************************************************************
* signal handler. sets wait_flag to FALSE, to indicate above loop that *
* characters have been received. *
***************************************************************************/
void signal_handler_IO (int status)
{
printf("received SIGIO signal.\n");
wait_flag = FALSE;
}
}

Serial communication between linux and 8051 microcontroller board using rs-232 in c

I have problem in sending data serially using RS-232 from linux OS to uc 8051.
8051 setting:
baudrate = 9600;
comport = port1.
parity = none
stop bit = one
// my code for receiving data on 8051 uc
#include <reg51.h>
unsigned char value;
int i,j;
void ini()
{
TMOD=0x20; //Timer1, mode 2, baud rate 9600 bps
TH1=0XFD;
SCON=0x50;
TR1=1;
}
void delay()
{
for(i=0;i<=1000;i++)
for (j=0;j<=300;j++);
}
void recieve()
{
unsigned char value;
while(RI==0);
value=SBUF;
P1=value;
RI=0;
}
void main()
{
while(1)
{
ini();
recieve();
}
}
// and code which run on linux is as following
#include <stdio.h> // standard input / output functions
#include <string.h> // string function definitions
#include <unistd.h> // UNIX standard function definitions
#include <fcntl.h> // File control definitions
#include <errno.h> // Error number definitions
#include <termios.h> // POSIX terminal control definitionss
#include <time.h> // time calls
int open_port(void)
{
int fd; // file description for the serial port
fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1) // if open is unsucessful
{
//perror("open_port: Unable to open /dev/ttyS0 - ");
printf("open_port: Unable to open /dev/ttyS0. \n");
}
else
{
fcntl(fd, F_SETFL, 0);
printf("port is open.\n");
}
return(fd);
} //open_port
int configure_port(int fd) // configure the port
{
struct termios port_settings; // structure to store the port settings in
cfsetispeed(&port_settings, B9600); // set baud rates
cfsetospeed(&port_settings, B9600);
port_settings.c_cflag &= ~PARENB; // set no parity, stop bits, data bits
port_settings.c_cflag &= ~CSTOPB;
port_settings.c_cflag &= ~CSIZE;
port_settings.c_cflag |= CS8;
tcsetattr(fd, TCSANOW, &port_settings); // apply the settings to the port
return(fd);
} //configure_port
int query_modem(int fd) // query modem with an AT command
{
char n;
fd_set rdfs;
struct timeval timeout;
// initialise the timeout structure
timeout.tv_sec = 10; // ten second timeout
timeout.tv_usec = 0;
// Create byte array
unsigned char send_bytes[] = { 0x00, 0xff};
write(fd, send_bytes, 2); //Send data
printf("Wrote the bytes. \n");
// do the select
n = select(fd + 1, &rdfs, NULL, NULL, &timeout);
// check if an error has occured
if(n < 0)
{
perror("select failed\n");
}
else if (n == 0)
{
puts("Timeout!");
}
else
{
printf("\nBytes detected on the port!\n");
}
return 0;
} //query_modem
int main(void)
{
int fd = open_port();
configure_port(fd);
query_modem(fd);
return(0);
} // main
But I have problem .. so plz help me out and tell me in which format linux sends data through rs-232. Also receiving format of 8051 micro-controller.
Need sample code in C.
I recomment basic fault finding
make sure you use correct cables (2 & 3 crossed out, no handshake lines to start with)
seperate the devices, i.e. connect your Linux machine to a PC running a terminal
program and try to establish 2-way communication - work on the Linux / C code until you achieve
connect your 8051 to a PC running a terminal program ....
connect Linux and 8051 only if they both work against a known and proven device
If your 8051 code sample represents all code .... how would the 8051 respond to the AT .... it can only receive.
good luck

Resources