#include "serial_t.h"

/* open serial ---------------------------------------------------------------*/
extern serial_t *openserial(const char *path, int mode, char *msg)
{
    const int br[]={
        300,600,1200,2400,4800,9600,19200,38400,57600,115200,230400,460800
    };
    serial_t *serial;
    int i,brate=9600,bsize=8,stopb=1;
    const char *p=NULL;
    char  /**p,*/parity='N',dev[128],port[128],fctr[64]="";
    const speed_t bs[]={
        B300,B600,B1200,B2400,B4800,B9600,B19200,B38400,B57600,B115200,B230400,B460800
    };
    struct termios ios={0};
    int rw=0;
    
    if (!(serial=(serial_t *)malloc(sizeof(serial_t)))) return NULL;
      
    if ((p=strchr(path,':'))) {
        strncpy(port,path,p-path); port[p-path]='\0';
        sscanf(p,":%d:%d:%c:%d:%s",&brate,&bsize,&parity,&stopb,fctr);
    }
    else strcpy(port,path);
    
    for (i=0;i<11;i++) if (br[i]==brate) break;
    if (i>=12) {
        sprintf(msg,"bitrate error (%d)",brate);
        //tracet(1,"openserial: %s path=%s\n",msg,path);
        free(serial);
        return NULL;
    }
    parity=(char)toupper((int)parity);

    //sprintf(dev,"/dev/%s",port);
    sprintf(dev,"%s",port);
    
    if ((mode&SERIAL_MODE_R)&&(mode&SERIAL_MODE_W)) rw=O_RDWR;
    else if (mode&SERIAL_MODE_R) rw=O_RDONLY;
    else if (mode&SERIAL_MODE_W) rw=O_WRONLY;
    
    if ((serial->dev=open(dev,rw|O_NOCTTY|O_NONBLOCK))<0) {
        sprintf(msg,"device open error (%d)",errno);
        //tracet(1,"openserial: %s dev=%s\n",msg,dev);
        free(serial);
        return NULL;
    }
    tcgetattr(serial->dev,&ios);
    ios.c_iflag=0;
    ios.c_oflag=0;
    ios.c_lflag=0;     /* non-canonical */
    ios.c_cc[VMIN ]=0; /* non-block-mode */
    ios.c_cc[VTIME]=0;
    cfsetospeed(&ios,bs[i]);
    cfsetispeed(&ios,bs[i]);
    ios.c_cflag|=bsize==7?CS7:CS8;
    ios.c_cflag|=parity=='O'?(PARENB|PARODD):(parity=='E'?PARENB:0);
    ios.c_cflag|=stopb==2?CSTOPB:0;
    ios.c_cflag|=!strcmp(fctr,"rts")?CRTSCTS:0;
    tcsetattr(serial->dev,TCSANOW,&ios);
    tcflush(serial->dev,TCIOFLUSH);
    
    return serial;
}
/* close serial --------------------------------------------------------------*/
extern void closeserial(serial_t *serial)
{   
    if (!serial)
        return;
    
    close(serial->dev);
    free(serial);

    return;
}
/* read serial ---------------------------------------------------------------*/
extern int readserial(serial_t *serial, unsigned char *buff, int n, char *msg)
{
    int nr;
    
    if (!serial)
        return 0;
    
    if ((nr=read(serial->dev,buff,n))<0)
        return 0;
    
    return nr;
}
/* write serial --------------------------------------------------------------*/
extern int writeserial(serial_t *serial, unsigned char *buff, int n, char *msg)
{
    int ns;
    
    if (!serial)
        return 0;
    
    if ((ns=write(serial->dev,buff,n))<0)
        return 0;
    
    return ns;
}
/* get state serial ----------------------------------------------------------*/
extern int stateserial(serial_t *serial)
{
    return !serial?0:(serial->error?-1:2);
}
