I am trying to read serial data from an Arduino Uno. I am using the Termios struct and followed this tutorial. I am not receiving the Arduino serial data in return, can anyone help me? First time using c++ to read serial. Following is the c++ code (i'm using ROS), and the arduino code.
c++ code
#include <ros.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <termios.h>
#include <csignal>
#include <sstream>
#include <algorithm>
#include <iterator>
const char *arduino_path = "/dev/ttyACM0";
int serial_port;
struct termios tty;
void init_serial(){
//do cereal things https://blog.mbedded.ninja/programming/operating-systems/linux/linux-serial-ports-using-c-cpp/
serial_port = open(arduino_path, O_RDWR | O_NOCTTY | O_NDELAY);
if (serial_port < 0) {
ROS_ERROR("Error %i from open: %s", errno, strerror(errno));
}
memset(&tty, 0, sizeof tty);
if(tcgetattr(serial_port, &tty) != 0) {
printf("Error %i from tcgetattr: %s\n", errno, strerror(errno));
}
//set flags
tty.c_cflag &= ~PARENB;
tty.c_cflag |= CS8; // 8 bits per byte (most common)
tty.c_cflag &= ~CRTSCTS;
tty.c_cflag |= CREAD | CLOCAL;
tty.c_lflag &= ~ICANON;
tty.c_lflag &= ~ECHO; // Disable echo
tty.c_lflag &= ~ECHOE; // Disable erasure
tty.c_lflag &= ~ECHONL; // Disable new-line echo
tty.c_lflag &= ~ISIG;
tty.c_iflag &= ~(IXON | IXOFF | IXANY);
tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL);
tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars)
tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed
tty.c_cc[VTIME] = 10; // Wait for up to 1s (10 deciseconds), returning as soon as any data is received.
tty.c_cc[VMIN] = 0;
cfsetispeed(&tty, B9600);
cfsetospeed(&tty, B9600);
if (tcsetattr(serial_port, TCSANOW, &tty) != 0) {
printf("Error %i from tcsetattr: %s\n", errno, strerror(errno));
}
}
std::string read_port(){
// Allocate memory for read buffer, set size according to your needs
char read_buf [256];
memset(&read_buf, '\0', sizeof(read_buf));
int n = read(serial_port, &read_buf, sizeof(read_buf));
std::string ret(read_buf);
return ret;
}
int main(int argc, char **argv){
ros::init(argc, argv, "sensor_handler");
ros::NodeHandle n;
init_serial();
while(ros::ok()){
cout << read_port() << std::endl;
}
}
Arduino code:
bool startup;
//Soil pins
const int soil_sensor_A0_AI = 0;
const int soil_sensor_A0_P = 0;
const int soil_sensor_A1_AI = 1;
const int soil_sensor_A1_P = 1;
const int soil_sensor_B0_AI = 2;
const int soil_sensor_B0_P = 2;
const int soil_sensor_B1_AI = 3;
const int soil_sensor_B1_P = 3;
int no_soil_sensors = 4;
//timer for the water
double water_timer;
int hours_delay = 4;
//water level vars
int water_level_sensor_pin = 5; //must be a PWM pin
int water_level; //in mm^3
double min_water = 20;
void setup() {
Serial.begin(9600);
//Setup soil moisture power pins as outputs
pinMode(soil_sensor_A0_P, OUTPUT);
pinMode(soil_sensor_A1_P, OUTPUT);
pinMode(soil_sensor_B0_P, OUTPUT);
pinMode(soil_sensor_B1_P, OUTPUT);
pinMode(water_level_sensor_pin, INPUT);
//init timer
water_timer = micros();
startup = true;
}
void loop() {
//check if starting up
if(startup){
check_water();
check_soil();
startup = false;
water_timer = micros();
}
/*
* if last check+delay in micros is less than or equal to current time then it means it is time to run a soil check.
*/
if(water_timer + (3600000000*hours_delay) <= micros() ){
check_water();
check_soil();
water_timer = micros();
}
//keep checking water, good way to monitor for leaks
check_water();
}
void check_soil() {
Serial.print("$SOIL:");
if(water_level < min_water){
Serial.println("E, Water level is too low to water the plants");
return;
}
for(int i = 0; i<no_soil_sensors; i++){
switch(i){
case soil_sensor_A0_AI:
digitalWrite(soil_sensor_A0_P, HIGH);
Serial.print("A0,");
Serial.print(analogRead(soil_sensor_A0_AI));
Serial.print(";");
digitalWrite(soil_sensor_A0_P, LOW);
break;
case soil_sensor_A1_AI:
digitalWrite(soil_sensor_A1_P, HIGH);
Serial.print("A1,");
Serial.print(analogRead(soil_sensor_A1_AI));
Serial.print(";");
digitalWrite(soil_sensor_A1_P, LOW);
break;
case soil_sensor_B0_AI:
digitalWrite(soil_sensor_B0_P, HIGH);
Serial.print("B0,");
Serial.print(analogRead(soil_sensor_B0_AI));
Serial.print(";");
digitalWrite(soil_sensor_B0_P, LOW);
break;
case soil_sensor_B1_AI:
digitalWrite(soil_sensor_B1_P, HIGH);
Serial.print("B1,");
Serial.print(analogRead(soil_sensor_B1_AI));
Serial.print(";");
digitalWrite(soil_sensor_B1_P, LOW);
break;
default:
Serial.println("E, SOIL_SENSORS");
break;
}
}
Serial.println("");
}
void check_water(){
//I don't know the math behind this yet but it will be in here
Serial.print("$WATER:");
double water_voltage = digitalRead(water_level_sensor_pin);
//math
double water_level = 0;
Serial.print(water_level);
if(water_level <= min_water){
Serial.print(";E, Water Level Low");
}
Serial.println("");
}
Related
I have written some code to find any modems on a unix system using the regex /dev/tty* basically and then for any matches see if can open the port and if so send an AT command and check if the response message contains the characters 'OK'.
The code does find a modem but unfortunately it messes up the terminal display. See below. I notice that it also prints the AT command - see output below. Why is my terminal display altered and how can I fix that?
After running the program, if you enter a command and enter, eg ls, the command is not shown but when you press enter you do see the output.
Here is the code:
#include <iostream>
#include <string>
#include <unordered_map>
#include <iomanip>
#include <memory>
#include <sstream>
#include <thread>
#include <iostream>
#include <filesystem>
#include <regex>
#include <unistd.h> // close
#include <fcntl.h> // open, O_RDWR, etc
#include <termios.h>
#include <string.h>
#include <sys/select.h> // timeouts for read
#include <sys/timeb.h> // measure time taken
int set_interface_attribs(int fd, int speed)
{
struct termios tty;
if (tcgetattr(fd, &tty) < 0) {
// Error from tcgetattr - can use strerror(errno)
return -1;
}
cfsetospeed(&tty, (speed_t)speed);
cfsetispeed(&tty, (speed_t)speed);
tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8; /* 8-bit characters */
tty.c_cflag &= ~PARENB; /* no parity bit */
tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */
/* setup for non-canonical mode */
tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
tty.c_oflag &= ~OPOST;
/* fetch bytes as they become available */
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 1;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
// Error from tcsetattr- use strerror(errno)
return -1;
}
return 0;
}
long enumerate_ports(std::unordered_map <std::string, std::string>& ports) {
// ls /dev | grep ^tty.*
const std::regex my_filter( "^tty.*" );
std::string path = "/dev/";
for (const auto & entry : std::filesystem::directory_iterator(path)) {
std::smatch sm;
std::string tmp = entry.path().filename().string();
// if we have a regex match attempt to open port and send AT command
if (std::regex_match(tmp, sm, my_filter)) {
std::string portname = entry.path().string();
int fd = ::open(portname.c_str(), O_RDWR | O_NOCTTY);
if (fd < 0) {
// Error opening port
continue;
} else {
// port was opened successfully
// try to write AT command and do we get an OK response
// baudrate 9600, 8 bits, no parity, 1 stop bit
if(set_interface_attribs(fd, B9600) != 0) {
::close(fd);
continue;
}
int wlen = ::write(fd, "AT\r\n", 4);
if (wlen != 4) {
// Error from write
::close(fd);
continue;
}
// tcdrain() waits until all output written to the object referred
// to by fd has been transmitted.
tcdrain(fd);
fd_set set;
struct timeval timeout;
FD_ZERO(&set); /* clear the set */
FD_SET(fd, &set); /* add our file descriptor to the set */
timeout.tv_sec = 0;
timeout.tv_usec = 100000; // 100 milliseconds
// wait for data to be read or timeout
int rv = select(fd + 1, &set, NULL, NULL, &timeout);
if(rv > 0) { // no timeout or error
unsigned char buf[80];
const int bytes_read = ::read(fd, buf, sizeof(buf) - 1);
if (bytes_read > 0) {
buf[bytes_read] = 0;
unsigned char* p = buf;
// scan for "OK"
for (int i = 0; i < bytes_read; ++i) {
if (*p == 'O' && i < bytes_read - 1 && *(p+1) == 'K') {
// we have a positive response from device so add to ports
ports[portname] = "";
break;
}
p++;
}
}
}
::close(fd);
}
}
}
return ports.size();
}
int main() {
struct timeb start, end;
int diff;
ftime(&start);
// get list of ports available on system
std::unordered_map <std::string, std::string> ports;
long result = enumerate_ports(ports);
std::cout << "No. found modems: " << result << std::endl;
for (const auto& item : ports) {
std::cout << item.first << "->" << item.second << std::endl;
}
ftime(&end);
diff = (int) (1000.0 * (end.time - start.time)
+ (end.millitm - start.millitm));
printf("Operation took %u milliseconds\n", diff);
}
And the output:
acomber#mail:~/Documents/projects/modem/serial/gdbplay$ ls
main.cpp main.o Makefile serial
acomber#mail:~/Documents/projects/modem/serial/gdbplay$ make serial
g++ -Wall -Werror -ggdb3 -std=c++17 -pedantic -c main.cpp
g++ -o serial -Wall -Werror -ggdb3 -std=c++17 -pedantic main.o -L/usr/lib -lstdc++fs
acomber#mail:~/Documents/projects/modem/serial/gdbplay$ sudo ./serial
[sudo] password for acomber:
AT
No. found modems: 1
/dev/ttyACM0->
Operation took 8643 milliseconds
acomber#mail:~/Documents/projects/modem/serial/gdbplay$
Why does this serial/modem code mess up my terminal display?
A precise answer requires you to post the terminal's settings prior to executing your code, i.e. stty -a.
The code does find a modem but unfortunately it messes up the terminal display.
The simplest (i.e. straightforward) workaround/solution is to adhere to the old (but rarely followed) advice of saving and then restoring the terminal's termios settings, as in this example.
The simple changes needed in your code would be something like (please overlook mixing of C and C++; I only know C) the following patch.
struct termios savetty;
int set_interface_attribs(int fd, int speed)
{
+ struct termios tty;
if (tcgetattr(fd, &tty) < 0) {
// Error from tcgetattr - can use strerror(errno)
return -1;
}
+ savetty = tty; /* preserve original settings for restoration */
cfsetospeed(&tty, (speed_t)speed);
cfsetispeed(&tty, (speed_t)speed);
Then in enumerate_ports(), the last two instances of ::close(fd); need to be replaced with the sequence that will perform the restoration:
+ if (tcsetattr(fd, &savetty) < 0) {
+ // report cannot restore attributes
+ }
::close(fd);
After running the program, if you enter a command and enter, eg ls, the command is not shown ...
That is obviously the result of leaving the ECHO attribute cleared.
The "missing" carriage returns are probably due to a cleared OPOST.
Other salient attributes that were cleared by your program but probably are expected to be set by the shell are ICANON, ICRNL, and IEXTEN.
But rather than try to determine what exactly needs to be undone, the proper and guaranteed fix is to simply restore the termios settings back to its original state.
An alternative (lazy) approach would to use the stty sane command after you execute your program.
I'm trying to sendo datas from Arduino Uno to RaspberryPi 3B. I need to send 14 int (max value: 6000) from Arduino as soon as Raspberry ask for them. Each one of this 14 number came from ad ADC (SPI communication).
ARDUINO SIDE
#include "SPI.h"
byte incomingByte = 0; // for incoming serial data
const int N_SENSORI=14;
const int DATAOUT = 11;
const int DATAIN = 12;
const int SPICLOCK = 13;
const int SLAVESELECT = 10;
//===============SPI COMMUNICATION================
short write_read_spi16(short what) {
digitalWrite(SS, LOW);
short res = SPI.transfer16(what);
digitalWrite(SS, HIGH);
return res;
}
//===============CONVERT INT IN BYTE AND SEND IT================
void longInt2Byte( int x){
unsigned char buf[sizeof( int)];
memcpy(buf,&x,sizeof(int));
Serial.write(buf,sizeof(buf));
}
//=======================================
void setup() {
Serial.begin(115200);
SPI.begin();
pinMode(DATAOUT, OUTPUT);
pinMode(DATAIN, INPUT);
pinMode(SPICLOCK,OUTPUT);
pinMode(SLAVESELECT,OUTPUT);
}
void loop() {
if (Serial.available() > 0) {
incomingByte= Serial.read();
if (incomingByte=='E') {
write_read_spi16(0b1000001101110000); //THIS IS FOR THE ADC COMMUNICATION
for (int i = 1; i<N_SENSORI+1; i++) { //DONE 14 TIMES.
short s = write_read_spi16(0b1000001101110000 | (i<<10));
int Data = s&0xFFF;
longInt2Byte(Data);
}
}
}}
// C++ SIDE
void stimulationController::SetupDario(){
cout<<"Dentro al setupDario"<<endl<<flush;
buffer=new char [1000];
const char* _portNameSensorsDario="/dev/ttyACM1";
//SERIAL PORT FOR HAND SENSORS
struct termios options;
SerialHandleSensors=open(_portNameSensorsDario, O_RDWR | O_NOCTTY | O_NDELAY); //SerialHandleSensors=open(_portNameSensors, O_RDWR | O_NOCTTY | O_NDELAY); non blocking
if (SerialHandleSensors == -1 )
{
cout<<endl<<"......ERROR: Unable to open: "<<_portNameSensorsDario<<endl;
return;
}
else
{
fcntl(SerialHandleSensors, F_SETFL,0);
cout<<"......OPENED PORT: Succesfully opened: "<<_portNameSensorsDario<<endl;
}
//GET THE OPTIONS, MODIFY AND SET
tcgetattr(SerialHandleSensors,&options);
cfsetispeed(&options,B115200); //BAUD RATE IN
cfsetospeed(&options,B115200); //BAUD RATE OUT
// options.c_lflag |= (ICANON | ECHO | ECHOE);
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~PARENB;
options.c_cflag |= CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
tcsetattr(SerialHandleSensors,TCSANOW,&options);
usleep(3000000);
cout<<"Fine Setup"<<endl<<flush;
}
int stimulationController::Dario( )
{
{
cout<<" NUOVA FUNZIONE"<<endl;
unsigned char bytes[4];
bytes[0]=0x45; // 'E'
int tempWrite=write(SerialHandleSensors,bytes,1);
if(tempWrite==-1)
{
cout<<"......ERROR: PROBLEM WRITING TO ROBOTIC HAND"<<endl;
failure=true;
return 0;
}
int value=0;
int tempRead=read(SerialHandleSensors,buffer,28);
if(tempRead==-1)
{
cout<<"......ERROR: PROBLEM READING FROM ROBOTIC HAND"<<endl;
failure=true;
return 0;
}
int j=0;
for( int i=0; i<28; i=i+2){
value= buffer[i] | ((int)buffer[i+1]<<8);
//ensorDataFoot.push_back(value); //Aggiunge un elemento
j=j+1;
cout<<"Dato "<<j <<"vale: "<<value<<endl<<flush;
}
return value;
}
}
The problem is that or the raspberry side some time it prints the right values, some time (the most of the times, actually) it doesn't. Data seems to be repeated or (2500 insted of 2000 for example).
I can't figure it out the problem.Could it be a matter of timing between the request of sending data and the reading? if so, there is a way to get rid of it?
I've added a do-while cycle in order to be sure that all the 28 bytes are read
int TotByte=28;
int ByteRead=0;
int TempRead=0;
do{ TempRead= read(SerialHandleSensors, buffer, (TotByte-ReadByte));
ReadByte= ReadByte+TempRead;
cout<<"ReadByte is: "<<ReadByte<<endl<<flush;
}while(ByteRead<TotByte);
Output:
ReadByte is: 5
ReadByte is: 15
ReadByte is: 25
and then it stay like that without doing anything
(Posted answer on behalf of the OP):
I figured it out; the problem were the settings of the serial port. For future reference, here is the working version.
bufferTemp=new char [1000];
bufferDEF = new char[1000];
const char* _portNameSensorsBT="/dev/rfcomm0";
struct termios options;
SerialHandleSensorsFoot=open(_portNameSensorsBT, O_RDWR ); //SerialHandleSensors=open(_portNameSensors, O_RDWR | O_NOCTTY | O_NDELAY); non blocking
if (SerialHandleSensorsFoot == -1 )
{
cout<<endl<<"......ERROR: Unable to open: "<<_portNameSensorsBT<<endl;
return 0;
}
else
{
fcntl(SerialHandleSensorsFoot, F_SETFL,0);
cout<<"......OPENED PORT: Succesfully opened: "<<_portNameSensorsBT<<endl;
}
//GET THE OPTIONS, MODIFY AND SET
tcgetattr(SerialHandleSensorsFoot,&options);
cfsetispeed(&options,B115200); //BAUD RATE IN
cfsetospeed(&options,B115200); //BAUD RATE OUT
// options.c_lflag |= (ICANON | ECHO | ECHOE);
options.c_iflag = IGNBRK | IGNPAR;
options.c_oflag = 0;
options.c_lflag = 0;
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~PARENB;
options.c_cflag |= CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
tcsetattr(SerialHandleSensorsFoot,TCSAFLUSH,&options);
usleep(5000000);
with these setting I'm able to communicate with bluetooth even though there might be some velocity problem.
I wrote a code to connect, throught a serial port, mi computer to arduino.
This is arduino's code:
#include <Servo.h>
Servo servo;
const int pinServo = 2;
unsigned int angle;
void setup()
{
Serial.begin(9600);
servo.attach(pinServo);
servo.write(0);
}
void loop()
{
if(Serial.available()>0)
{
angle = Serial.read();
if(angle <= 179)
{
servo.write(angle);
}
}
}
And this is c++'s:
#include <iostream>
#include <unistd.h>
#include <fstream>
#include <termios.h>
using namespace std;
int main()
{
unsigned int angle;
ofstream arduino;
struct termios ttable;
cout<<"\n\ntest1\n\n";
arduino.open("/dev/tty.usbmodem3a21");
cout<<"\n\ntest2\n\n";
if(!arduino)
{
cout<<"\n\nERR: could not open port\n\n";
}
else
{
if(tcgetattr(arduino,&ttable)<0)
{
cout<<"\n\nERR: could not get terminal options\n\n";
}
else
{
ttable.c_cflag &= ~PARENB;
ttable.c_cflag &= ~CSTOPB;
ttable.c_cflag &= ~CSIZE;
ttable.c_cflag |= CS8;
ttable.c_cflag &= ~CRTSCTS;
ttable.c_cflag |= CREAD | CLOCAL;
ttable.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
ttable.c_oflag &= ~OPOST;
ttable.c_cc[VMIN] = 0;
ttable.c_cc[VTIME] = 0;
cfsetospeed(&ttable,9600);
if(tcsetattr(arduino,TCSANOW,&ttable)<0)
{
cout<<"\n\nERR: could not set new terminal options\n\n";
}
else
{
do
{
cout<<"\n\ninsert a number between 0 and 179";
cin>>angle;
arduino<<angle;
}while(angle<=179);
arduino.close();
}
}
}
}
It should connect to arduino , then ask me a number between 0 an 179 and the send that number to arduino which aplly that number as an angle to a servo motor;
But it stops at arduino.open("/dev/tty.usbmodem3a21") .What can i do ?
I think your problems appear in these lines of code
if(tcgetattr(arduino,&ttable)<0) {
// ...
}
else {
// ...
if(tcsetattr(arduino,TCSANOW,&ttable)<0) {
// ...
}
}
The arduino variable is of type ofstream, where tcgetattr() and tcsetattr() expect a file descriptor obtained with open() at this point.
ofstream provides an automatic conversion to bool and thus int implicitely. Supposed the
arduino.open("/dev/tty.usbmodem3a21");
went OK, you are effectively passing 1 to tcgetattr() and tcsetattr(), which is the standard input file descriptor.
Solution is not to use a ofstream for arduino, but an ordinary file descriptor
int arduino = open("/dev/tty.usbmodem3a21",O_WRONLY);
I want to control the RTS line on the serial port to wake up a device. Here is some rough test code to open the serial port. I need to set the RTS line low for 500ms. I'm having trouble googleing/understanding how to control the lines. Any Hints?
EDIT: OR controlling the CTS/DTR, any other line besides the Tx/Rx lines to connect to a pin of the robot.
#include <iostream>
#include <string.h>
#include <cstdio>
#include <fstream>
#include <sys/types.h>
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <stdint.h> /* Standard types */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
#include <sys/ioctl.h>
#include <getopt.h>
using namespace std;
int fd_global;
FILE* fp_global;
int serialport_init(const char* serialport, int baud);
int serialport_read_until(int fd);
int fpeek(FILE* stream);
bool fexists(const char *filename);
void* screen_thread(void* arg) {
while(1) {
}
}
int main(void) {
pthread_t screen_thread_id;
int flags;
int baudrate = B9600; // default
fd_global = serialport_init((char*)"/dev/ttyUSB0", baudrate);
if(fd_global==-1) {
cout << "Open port: error\n";
return -1;
}
fp_global = fdopen(fd_global, "r");
if (-1 == (flags = fcntl(fd_global, F_GETFL, 0))) flags = 0;
fcntl(fd_global, F_SETFL, flags | O_NONBLOCK);
//pthread_create(&screen_thread_id, NULL, screen_thread, (void*)NULL);
serialport_read_until(fd_global);
return 0;
}
int serialport_read_until(int fd)
{
char b[1];
while(1) {
int n = read(fd, b, 1); //Read byte at a time
if(n==-1) {
printf("N");fflush(stdout);
perror("READ: ");
}
else if( n==0 ) {
printf("Z");fflush(stdout);
} else if(n>0) {
printf(":%d:",n);fflush(stdout);
}
usleep(100*1000);
if (fexists("/dev/ttyUSB0"))
printf("CONNECTED\n");
else
printf("NOT CONNECTED\n");
}
return 0;
}
bool fexists(const char *filename)
{
ifstream ifile(filename);
return ifile;
}
int serialport_init(const char* serialport, int baud)
{
struct termios toptions;
int fd;
// Open port
fd = open(serialport, O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1) {
perror("init_serialport: Unable to open port ");
return -1;
}
// Read current termios settings
if (tcgetattr(fd, &toptions) < 0) {
perror("init_serialport: Couldn't get term attributes");
return -1;
}
// Set baud rate variable
speed_t brate = baud;
switch(baud) {
case 2400: brate=B2400; break;
case 4800: brate=B4800; break;
case 9600: brate=B9600; break;
#ifdef B14400
case 14400: brate=B14400; break;
#endif
case 19200: brate=B19200; break;
#ifdef B28800
case 28800: brate=B28800; break;
#endif
case 38400: brate=B38400; break;
case 57600: brate=B57600; break;
case 115200: brate=B115200; break;
}
cfsetispeed(&toptions, brate);
cfsetospeed(&toptions, brate);
// Setup termios for 8N1
toptions.c_cflag &= ~PARENB;
toptions.c_cflag &= ~CSTOPB;
toptions.c_cflag &= ~CSIZE;
toptions.c_cflag |= CS8;
// Reccomended settings
toptions.c_cflag &= ~CRTSCTS; // no flow control
toptions.c_cflag |= CREAD | CLOCAL; // turn on read & ignore ctrl lines
toptions.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl
toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw
toptions.c_oflag &= ~OPOST; // make raw
// Setting when read() releases
// see: http://unixwiz.net/techtips/termios-vmin-vtime.html (Still a little confusing)
toptions.c_cc[VMIN] = 0;
toptions.c_cc[VTIME] = 20;
// Apply settings
if( tcsetattr(fd, TCSANOW, &toptions) < 0) {
perror("init_serialport: Couldn't set term attributes");
return -1;
}
return fd;
}
Would this work? I'll test it tomorrow.
int status;
status |= TIOCM_RTS;
ioctl(fd, TIOCMSET, &status);
usleep(500*1000);
status &= ~TIOCM_RTS;
ioctl(fd, TIOCMSET, &status);
I want a infinit loop to break when I press "q" key on my keyboard.
Problems I did'nt realize: standard getchar waits for the user to make an
input and press enter, which halt the execution of the loop there.
I got around the "enter" problem, but the loop still halts and waits for the input.
here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <termios.h>
int getch(void); // Declare of new function
int main (void) { char x;
do
{
if (x = getch())
printf ("Got It! \n!);
else
{
delay(2000);
printf ("Not yet\n!);
}
}while x != 'q');
return 0;
}
int getch(void)
{
int ch;
struct termios oldt;
struct termios newt;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
return ch;
}
You could read them from the device:
#define INPUT_QUEUE "/dev/input/event0"
#define EVENT_LEN 16
void readEventLine(FILE * in, char * data) { //read input key stream
int i;
for(i = 0; i <= 15; i++) { //each key press will trigger 16 characters of data, describing the event
data[i] = (char) fgetc(in);
}
}
int readKeyPress() {
FILE * input;
char data[EVENT_LEN];
input = fopen(INPUT_QUEUE, "r+");
readEventLine(input, data);
}
Just call something like this instead of your getch.
Adapted from http://www.cplusplus.com/forum/unices/8206/
I had to do following to make it work correctly, thanks for input!!
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
int getch(void); // Declare of new function
int main (void)
{
char x;
do
{
x = getch();
if (x != EOF)
{
printf ("\r%s\n", "Got something:");
printf ("it's %c!",x); // %c - for character %d - for ascii number
}else
{
delay(2000);
printf ("Not yet\n!);
}
}while x != 'q');
return 0;
}
int getch(void)
{
int ch;
struct termios oldt;
struct termios newt;
long oldf;
long newf;
tcgetattr(STDIN_FILENO, &oldt); /* Store old settings */
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO); /* Make one change to old settings in new settings */
tcsetattr(STDIN_FILENO, TCSANOW, &newt); /* Apply the changes immediatly */
oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
newf = oldf | O_NONBLOCK;
fcntl(STDIN_FILENO, F_SETFL, newf);
ch = getchar();
fcntl(STDIN_FILENO, F_SETFL, oldf);
tcsetattr(STDIN_FILENO, TCSANOW, &oldt); /* Reapply the old settings */
return ch;
}