C++ Blueprint Serial Port for Mac

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.

Also, why can’t I add conditions to the first function without generating an error?

well, I think I am pretty stupid for this. I don’t need to expose any of these variables. I am hard coding everything. I have the init, flush, and close functions working with blueprint calls. Once I clean up the read part, I guess I should post up if someone wants this functionality.