Skip to content

Instantly share code, notes, and snippets.

@underdoeg
Created June 11, 2016 14:35
Show Gist options
  • Save underdoeg/7bdfb23240c8ae21d30b9a848436b035 to your computer and use it in GitHub Desktop.
Save underdoeg/7bdfb23240c8ae21d30b9a848436b035 to your computer and use it in GitHub Desktop.
godot serial hints
# SCsub
Import('env')
env.Append(CPPPATH = ['libs/libserial/src/')]
env.add_source_files(env.modules_sources,"libs/libserial/src/*.cc")
env.add_source_files(env.modules_sources,"libs/libserial/src/*.cpp")
env.add_source_files(env.modules_sources,"*.cpp")
#include "Serial.h"
#include <stdio.h> // Standard input/output 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 <string.h> // String function definitions
#include <sys/ioctl.h>
using namespace std;
int serialport_init(const char* serialport, int baud) {
struct termios toptions;
int fd;
//fd = open(serialport, O_RDWR | O_NOCTTY | O_NDELAY);
fd = open(serialport, O_RDWR | O_NONBLOCK );
if (fd == -1) {
perror("serialport_init: Unable to open port ");
return -1;
}
//int iflags = TIOCM_DTR;
//ioctl(fd, TIOCMBIS, &iflags); // turn on DTR
//ioctl(fd, TIOCMBIC, &iflags); // turn off DTR
if (tcgetattr(fd, &toptions) < 0) {
perror("serialport_init: Couldn't get term attributes");
return -1;
}
speed_t brate = baud; // let you override switch below if needed
switch(baud) {
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);
// 8N1
toptions.c_cflag &= ~PARENB;
toptions.c_cflag &= ~CSTOPB;
toptions.c_cflag &= ~CSIZE;
toptions.c_cflag |= CS8;
// no flow control
toptions.c_cflag &= ~CRTSCTS;
//toptions.c_cflag &= ~HUPCL; // disable hang-up-on-close to avoid reset
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
// see: http://unixwiz.net/techtips/termios-vmin-vtime.html
toptions.c_cc[VMIN] = 0;
toptions.c_cc[VTIME] = 0;
//toptions.c_cc[VTIME] = 20;
tcsetattr(fd, TCSANOW, &toptions);
if( tcsetattr(fd, TCSAFLUSH, &toptions) < 0) {
perror("init_serialport: Couldn't set term attributes");
return -1;
}
return fd;
}
//
int serialport_close( int fd ) {
return close( fd );
}
//
int serialport_writebyte( int fd, uint8_t b) {
int n = write(fd,&b,1);
if( n!=1)
return -1;
return 0;
}
//
int serialport_write(int fd, const char* str) {
int len = strlen(str);
int n = write(fd, str, len);
if( n!=len ) {
perror("serialport_write: couldn't write whole string\n");
return -1;
}
return 0;
}
//
int serialport_read_until(int fd, char* buf, char until, int buf_max, int timeout) {
char b[1]; // read expects an array, so we give it a 1-byte array
int i=0;
do {
int n = read(fd, b, 1); // read a char at a time
if( n==-1) return -1; // couldn't read
if( n==0 ) {
usleep( 1 * 1000 ); // wait 1 msec try again
timeout--;
if( timeout==0 ) return -2;
continue;
}
#ifdef SERIALPORTDEBUG
printf("serialport_read_until: i=%d, n=%d b='%c'\n",i,n,b[0]); // debug
#endif
buf[i] = b[0];
i++;
} while( b[0] != until && i < buf_max && timeout>0 );
buf[i] = 0; // null terminate the string
return 0;
}
//
int serialport_flush(int fd) {
sleep(2); //required to make flush work, for some reason
return tcflush(fd, TCIOFLUSH);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Serial::Serial():hasArduino(false) {
hasArduino = false;
mutex = Mutex::create();
}
void Serial::setup() {
hasArduino = false;
vector<serial::PortInfo> devices_found = serial::list_ports();
vector<serial::PortInfo>::iterator iter = devices_found.begin();
std::string port = "";
while( iter != devices_found.end() ) {
serial::PortInfo device = *iter++;
/*
printf( "(%s, %s, %s)\n", device.port.c_str(), device.description.c_str(),
device.hardware_id.c_str() );
*/
string deviceName = device.description.c_str();
if(deviceName.find("Arduino") != string::npos) {
port = device.port;
}
}
if(port == "") {
print_line("NO ARDUINO FOUND");
return;
}
/////////// ARDUINO FOUND
std::string msg = "OPENING ARDUINO: "+port;
print_line(msg.c_str());
/*
ser = new serial::Serial(port, 9600, serial::Timeout::simpleTimeout(1000));
*/
//serial.Open(port);
//serial.SetBaudRate(LibSerial::SerialStreamBuf::BaudRateEnum::BAUD_9600);
serialPort = serialport_init(port.c_str(), 9600);
if(serialPort == -1) {
print_line("COULD NOT OPEN ARDUINO");
return;
}
hasArduino = true;
quit = false;
Thread* thread = Thread::create(&thread_func, this);
}
Serial::~Serial() {
quit = true;
}
void Serial::thread_func(void* caller) {
//ser->close();
print_line("STARTING SERIAL THREAD");
Serial* serial = (Serial*)caller;
const int buf_max = 256;
char buf[buf_max];
char eolchar = '\n';
int timeout = 5000;
while(!serial->quit) {
memset(buf,0,buf_max); //
serialport_read_until(serial->serialPort, buf, eolchar, buf_max, timeout);
std::string str(buf);
if(str.size()>0) {
serial->mutex->lock();
serial->msgQueue.push_back(str);
serial->mutex->unlock();
}
}
print_line("ENDED SERIAL THREAD");
}
void Serial::processQueue() {
if(!hasArduino)
return;
if(mutex == NULL)
return;
std::vector<std::string> commands;
mutex->lock();
commands = msgQueue;
msgQueue.clear();
mutex->unlock();
for(auto& res: commands) {
if(res.size()>0) {
print_line(res.c_str());
//do something here
}
}
}
#ifndef SERIAL_MOD_H
#define SERIAL_MOD_H
//code uses http://libserial.sourceforge.net/
#include "libs/serial/include/serial/serial.h"
#include <vector>
#include <thread>
#include "core/os/thread.h"
#include "core/os/mutex.h"
class Serial {
public:
Serial();
~Serial();
void processQueue();
bool hasArduino;
void setup();
private:
//Thread* thread;
Mutex* mutex;
int serialPort;
bool quit;
static void thread_func(void* caller);
std::vector<std::string> msgQueue;
};
#endif // SERIAL_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment