I have been struggling with this for a week or so now, so I figured I should try the Unreal Community. I have been messing with a serial port implementation, but I think I am probably treading in the deep end to the point of drowning. I am trying to declare some conditions in my function but it is giving me the “Too few arguments to call function error”
#pragma once
#include <stdint.h> // Standard types
/**
*
*/
#include "StretchSerialPort.generated.h"
UCLASS(BlueprintType,Blueprintable)
class BLACKBIRDTEST_API UStretchSerialPort : public UBlueprintFunctionLibrary
{
GENERATED_UCLASS_BODY()
public:
UFUNCTION(BlueprintCallable, Category = "Stretch Tech")
static uint32 InitializeSerialPort(FString _serialportstring,int32 _baudInt);
UFUNCTION(BlueprintCallable, Category = "Stretch Tech")
static int32 CloseSerialPort();
UFUNCTION(BlueprintCallable, Category = "Stretch Tech")
static int32 ReadSerialPort();
UFUNCTION(BlueprintCallable, Category = "Stretch Tech")
static int32 FlushSerialPort();
private:
static char _serialport[];
static char _buf[];
static char _until;
static int32 _baud;
static int32 _fd;
static int32 _buf_max;
static int32 serialport_init(char* serialport,int32 baud);
static int32 serialport_close(int32 fd);
static int32 serialport_read_until(int32 fd, char* buf, char until, int32 buf_max);
static int32 serialport_flush(int32 fd);
};
Here is the cpp file:
// Fill out your copyright notice in the Description page of Project Settings.
#include "BlackbirdTest.h"
#include "StretchSerialPort.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"
//We are hardcoding values here for the serial port because we aren't sure what's going on yet
char UStretchSerialPort::_until = '\n';
int32 UStretchSerialPort::_baud = 9600;
int32 UStretchSerialPort::_fd = -1;
int32 UStretchSerialPort::_buf_max = 256;
// takes the string name of the serial port (e.g. "/dev/tty.usbserial","COM1")
// and a baud rate (bps) and connects to that port at that speed and 8N1.
// opens the port in fully raw mode so you can send binary data.
// returns valid fd, or -1 on error
UStretchSerialPort::UStretchSerialPort(const FObjectInitializer&ObjectInitializer): Super(ObjectInitializer) {}
//PUBLIC FUNCTIONS
uint32 UStretchSerialPort::InitializeSerialPort(FString _serialportstring,int32 _baudInt){
_serialport=_serialportstring;
_baud=_baudInt;
int32 res = serialport_init(_serialport, _baud);
return res;
}
int32 UStretchSerialPort::CloseSerialPort(){
if(_fd != -1){
return serialport_close(_fd);
}else{
return -1;
}
}
int32 UStretchSerialPort::ReadSerialPort(){
if(_fd != -1){
// NOTE: Not sure how to expose the data that is put into _buf, this only returns a status
return serialport_read_until(_fd, _buf, _until, _buf_max);
}else{
return -1;
}
}
int32 UStretchSerialPort::FlushSerialPort(){
if(_fd != -1){
return serialport_flush(_fd);
}else{
return -1;
}
}
//PRIVATE FUNCTIONS
int32 UStretchSerialPort::serialport_init(char* serialport,int32 baud)
{
struct termios toptions;
int32 fd;
//fd = open(serialport, O_RDWR | O_NOCTTY | O_NDELAY);
fd = open(serialport, O_RDWR | O_NONBLOCK );
if (fd == -1)
{
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)
{
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;
case 14400: brate=B14400; break;
case 19200: brate=B19200; break;
case 28800: brate=B28800; break;
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)
{
return -1;
}
return fd;
}
int32 UStretchSerialPort::serialport_close(int32 fd)
{
return close(fd);
}
int32 UStretchSerialPort::serialport_read_until(int32 fd, char* buf, char until, int32 buf_max)
{
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--;
// continue;
return -1;
}
buf[i] = b[0];
i++;
} while( b[0] != until && i < buf_max);// && timeout>0 );
buf[i] = 0; // null terminate the string
return 0;
}
int32 UStretchSerialPort::serialport_flush(int32 fd)
{
//NOTE: this could mess unreal up
sleep(2); //required to make flush work, for some reason
return tcflush(fd, TCIOFLUSH);
}
Again, please note I am not the C++ titan. I know the functions in the cpp file are probably broken, and dealing with a heavily char dependent coding process has been even more confusing in UE4. Any and all help will hopefully lead me to a better place. Note, I am developing on a Mac. Otherwise, I could easily use the plethora of Windows serial port plugins out there.