Created
June 11, 2016 14:35
-
-
Save underdoeg/7bdfb23240c8ae21d30b9a848436b035 to your computer and use it in GitHub Desktop.
godot serial hints
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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