/*
 * Copyright (C) 2018 dimercur
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * \file      robot.h
 * \author    L.Senaneuch
 * \version   1.0
 * \date      06/06/2017
 * \brief     Fonctions for communicating with robot.
 */

#include "robot.h"

int fd;

int getChar(char * c);
int readSerial(char * msg);
char checkSumGO(char * msg);
int receiveMsg(void);
int sendCmd(char cmd, const char * arg);

int open_communication_robot(const char * path)
{
#ifndef __STUB__
    struct termios options;
    fd = open(path, O_RDWR | O_NOCTTY | O_NDELAY);
    if(fd !=-1)
    {
        fcntl(fd, F_SETFL, 0);
        tcgetattr(fd, &options);
        options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
        cfsetospeed (&options, B9600);
        cfsetispeed (&options, B9600);
        options.c_cc[VMIN]=0;
        options.c_cc[VTIME]=0;
        tcsetattr(fd, TCSANOW, &options);
        return 0;
    }
    else
    {
        perror("can't openSerial");
        return -1;
    }
#else
    return 0;
#endif
}


int close_communication_robot(void)
{
#ifndef __STUB__
    return close(fd);
#else
    return 0;
#endif
}


int send_command_to_robot(char cmd, const char * arg)
{
#ifndef __STUB__
    sendCmd(cmd,arg);
    // TODO : check return from sendCmd
    return receiveMsg();
#else
    int reponse;
    switch(cmd)
    {
        case DMB_PING:
            reponse = 0;
            break;
        case DMB_IDLE:
            reponse = 0;
            break;
        case DMB_START_WITH_WD:
            reponse = 0;
            break;
        case DMB_RELOAD_WD:
            reponse = 0;
            break;
        case DMB_GET_VBAT:
            reponse = 2;
            break;
        case DMB_IS_BUSY:
            reponse = 1;
            break;
        case DMB_START_WITHOUT_WD:
            reponse = 0;
            break;
        case DMB_MOVE:
            reponse = 0;
            break;
        case DMB_TURN:
            reponse = 0;
            break;
        case DMB_GO_FORWARD:
            reponse = 0;
            break;
        case DMB_GO_BACK:
            reponse = 0;
            break;
        case DMB_GO_LEFT:
            reponse = 0;
            break;
        case DMB_GO_RIGHT:
            reponse = 0;
            break;
        case DMB_STOP_MOVE:
            reponse = 0;
            break;
        default:
            reponse = 0;
            break;
    }
    return reponse;
#endif
}

/****************************/
/* PRIVATE                  */
/****************************/

int sendCmd(char cmd, const char * arg)
{
    char cmdWithArg[20]={};
    cmdWithArg[0]=cmd;
    switch(cmd)
    {
        case DMB_GO_FORWARD: strcpy(cmdWithArg,"M=+64000");
            break;
        case DMB_GO_BACK:    strcpy(cmdWithArg,"M=-64000");
            break;
        case DMB_GO_LEFT:  strcpy(cmdWithArg,"T=+64000");
            break;
        case DMB_GO_RIGHT: strcpy(cmdWithArg,"T=-64000");
            break;
        case DMB_STOP_MOVE:  strcpy(cmdWithArg,"M=0");
            break;
        case DMB_MOVE:   strcat(cmdWithArg,"=");
            strcat(cmdWithArg,arg);
            break;
        case DMB_TURN:   strcat(cmdWithArg,"=");
            strcat(cmdWithArg,arg);
            break;
    }
    int sizeCmd = strlen(cmdWithArg);
    cmdWithArg[sizeCmd] = checkSumGO(cmdWithArg);
    cmdWithArg[sizeCmd+1] = '\r';
    cmdWithArg[sizeCmd+2] = '\0';
    return write(fd,cmdWithArg,strlen(cmdWithArg));
}

int receiveMsg(void)
{
    char msg[20];
    int b;
    if((b = readSerial(msg))!=ROBOT_TIMED_OUT)
    {
        int taille = strlen(msg);
        char checksum = msg[taille-2];
        msg[taille-1] = 0;
        msg[taille-2] = 0;
        if(checksum!=checkSumGO(msg))
        {
            return ROBOT_CHECKSUM;
        }
        else
        {
            switch(msg[0])
            {
                case 'O' : return 0;
                case 'E' : return ROBOT_ERROR;
                case 'C' : return ROBOT_UKNOWN_CMD;
                default :  return atoi(&msg[0]);
            }
        }
    }
    else
    {
        return ROBOT_TIMED_OUT;
    }
}

int getChar(char * c)
{
    int n =0;
    int delay =0;
    while((n=read(fd,c,1)) <=0)
    {
        usleep(5000);
        delay++;
        if(delay > 10)
        {
            return ROBOT_TIMED_OUT;
        }

    }
    return n;
}

int readSerial(char * msg)
{
    char car=0;
    int i=0;
    for(int j = 0 ; j < 20 ; j++)
        msg[j]=0;
    
    while(car !='\r' && car!='\n') {
        if(i>=20) 
            return -5;

        if(getChar(&car)==ROBOT_TIMED_OUT) {
            return ROBOT_TIMED_OUT;
        }
        
        msg[i] = car;
        i++;
    }
    return i;
}

char checkSumGO(char * msg)
{
    char resultat = 0;
    int i = 0;
    int taille = strlen(msg);
    for(i=0;i<taille;i++)
    {
        resultat^=msg[i];
    }
    return resultat;

}



