/* Ralf Ackermann, rac@iptel-now.de, 2001 */
/* Felix Tang, tangf@eyetap.org 2002 */

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <string.h>
#include <termios.h>

#define RETOUR_OK       0
#define RETOUR_ERROR    -1

#define BAUD9600 0
#define BAUD115200 1

int init_ser(char *ser_device);
int set_ser_param(int fd);
void flush_ser(void);
int shutdown_ser(void);
char get_1_char(void);

/* (fd == -1) shows that fd is not valid */
int fd=-1;

int init_ser(char *ser_device)
{
    /* fd is static to this module but not to be seen outside */
    fprintf(stderr, "Opening serial device: %s\n", ser_device);
    fd=open(ser_device, O_RDWR | O_NOCTTY | O_NONBLOCK, 0);
    if (fd == -1)
    {
        fprintf(stderr, "Error opening serial device !\n");
        return (RETOUR_ERROR);
    }
    else {
        fprintf(stderr, "open returned: %d\n", fd);
        if (set_ser_param(fd) == RETOUR_ERROR) {
            fprintf(stderr, "Couldn't set serial parameters !\n");
            close(fd);
            fd=-1;
            return (RETOUR_ERROR);
        }
        else {
            /* printf("Sucessfully opened serial device !\n"); */
            return (RETOUR_OK);
        }
    }
}

int set_ser_param(int fd)
{
    /* see: man termios(3) */
    int line;
    struct termios options;

    tcgetattr(fd, &options);

#if 0
    cfsetispeed(&options, B9600);
    cfsetospeed(&options, B9600);
#endif

    cfsetispeed(&options, B9600);
    cfsetospeed(&options, B9600);

    options.c_cflag &= ~PARENB;
    options.c_cflag |= CSTOPB;
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;

    /* disable hardware flow control - would be */
    options.c_cflag &= ~CRTSCTS;

    options.c_cflag |= CREAD;

    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    options.c_iflag=(IMAXBEL | IGNBRK);
    options.c_oflag=0;

    options.c_cc[VTIME]='\0';
    options.c_cc[VMIN]='\0';

    tcsetattr(fd, TCSANOW, &options);

    flush_ser();
}

void flush_ser(void)
{
    ioctl(fd, TCFLSH, 0);
}

int shutdown_ser(void)
{
    if (close(fd) == -1) {
        fd=-1;
        return (RETOUR_ERROR);
    }
    else {
        fd=-1;
        return (RETOUR_OK);
    }
}

char get_1_char(void)
{
    char recv_char;
    int r_code;

    do {
        /* wait for a char to arrive */
        r_code=read(fd, &recv_char, 1);
    }
    while (r_code != 1);

    return (recv_char);
}


//change baud rate
int change_baud(int baud)
{
    unsigned char command;
    struct termios options;
    int flags;

    //print out flags
    ioctl(fd, TIOCMGET, &flags);
    fprintf(stderr, "Flags are %x\n", flags);
    //set DTR and RTS to reset MCP2120
    flags |= TIOCM_RTS |TIOCM_DTR;
    ioctl(fd, TIOCMSET, &flags);
    //print out flags
    ioctl(fd, TIOCMGET, &flags);
    fprintf(stderr, "set DTR and RTS %x\n", flags);
    //need 2000 ns pulse = 2 us
    usleep(5);
    //clear RTS
    flags &= ~(TIOCM_RTS);
    ioctl(fd, TIOCMSET, &flags);
    //print out flags
    ioctl(fd, TIOCMGET, &flags);
    fprintf(stderr, "cleared RTS Flags are %x\n", flags);
    //need max 30 ms to come back from a reset
    usleep(100*1000);

    
    command=0xDE;
    write(fd, &command, 1);
    command=0xAD;
    write(fd, &command, 1);
    command=0xBE;
    write(fd, &command, 1);
    command=0xEF;
    write(fd, &command, 1);
        
//printf("pause");
//getchar();
 
    //change baud rate
    if (baud == BAUD9600) {
        command = 0x87;
    } else {
        printf("115200 command\n");
        command = 0x81;
    }
    write(fd, &command, 1);
    //command = get_1_char();
    //printf("<%02x>", (unsigned char)command);
    

    //commit 
    command = 0x11;
    write(fd, &command, 1);
    //command = get_1_char();
    //printf("<%02x>", (unsigned char)command);

//printf("pause");
//getchar();
    usleep(500*1000);

    //clear DTR and RTS
    flags &= ~(TIOCM_DTR | TIOCM_RTS);
    ioctl(fd, TIOCMSET, &flags);

    tcgetattr(fd, &options);
    if (baud == BAUD9600) {
        cfsetispeed(&options, B9600);
        cfsetospeed(&options, B9600);
    } else {
        printf("115200 terminal\n");
        cfsetispeed(&options, B115200);
        cfsetospeed(&options, B115200);
    }
    tcsetattr(fd, TCSANOW, &options);
    

}

int main(int argc, char **argv)
{
    unsigned char buffer;
    unsigned char command;
    int flags;
    int rc;

    if (argc != 2)
    {
        fprintf(stderr, "usage: </dev/ttyS?> !\n");
        exit(0);
    }

    init_ser(argv[1]);
    flush_ser();
/*
    //print out flags
    ioctl(fd, TIOCMGET, &flags);
    fprintf(stderr, "Flags are %x\n", flags);

    //clear DTR and RTS
    flags &= ~(TIOCM_DTR | TIOCM_RTS);
    ioctl(fd, TIOCMSET, &flags);

    //print out flags
    ioctl(fd, TIOCMGET, &flags);
    fprintf(stderr, "Flags are %x\n", flags);
*/
    //starting up
    printf("changing baud rate\n");
    change_baud(BAUD9600);
    //change_baud(BAUD115200);

    while (1)
    {
        write(fd, &buffer, 1);
        buffer=getchar();
        rc=write(fd, &buffer, 1);
        printf("<%02x>", (unsigned char)buffer);
        fflush(stdout); 
   }
}

