#include <gtk/gtk.h>
#include "serial.h"

/*=============================================================================
  Variables globales.
=============================================================================*/

/* Nom du port série */
const char *PORT[10]={"COM1\0\0","COM2\0\0","COM3\0\0","COM4\0\0","COM5\0\0","COM6\0\0","COM7\0\0","COM8\0\0","COM9\0\0","COM10\0"};

/* Définition des vitesses de communication */
const long SPEED[7]={1200,2400,4800,9600,19200,38400,57600};

/* Handle du port COM ouvert */
HANDLE HDL_Com=NULL;

/* Délais d'attente sur le port COM */
COMMTIMEOUTS g_cto = {
    MAX_WAIT_READ,  /* ReadIntervalTimeOut          */
    0,              /* ReadTotalTimeOutMultiplier   */
    MAX_WAIT_READ,  /* ReadTotalTimeOutConstant     */
    0,              /* WriteTotalTimeOutMultiplier  */
    0               /* WriteTotalTimeOutConstant    */
};

/* Configuration du port COM */
DCB g_dcb = {
    sizeof(DCB),        /* DCBlength            */
    9600,               /* BaudRate             */
    TRUE,               /* fBinary              */
    FALSE,              /* fParity              */
    FALSE,              /* fOutxCtsFlow         */
    FALSE,              /* fOutxDsrFlow         */
    DTR_CONTROL_DISABLE, /* fDtrControl          */
    FALSE,              /* fDsrSensitivity      */
    FALSE,              /* fTXContinueOnXoff    */
    FALSE,              /* fOutX                */
    FALSE,              /* fInX                 */
    FALSE,              /* fErrorChar           */
    FALSE,              /* fNull                */
    RTS_CONTROL_DISABLE, /* fRtsControl          */
    FALSE,              /* fAbortOnError        */
    0,                  /* fDummy2              */
    0,                  /* wReserved            */
    0x100,              /* XonLim               */
    0x100,              /* XoffLim              */
    8,                  /* ByteSize             */
    NOPARITY,           /* Parity               */
    ONESTOPBIT,         /* StopBits             */
    0x11,               /* XonChar              */
    0x13,               /* XoffChar             */
    '?',                /* ErrorChar            */
    0x1A,               /* EofChar              */
    0x10                /* EvtChar              */
};

/******************************************************************************
  OpenCOM : ouverture et configuration du port COM.
  entrée : nId : Id du port COM à ouvrir.
  retour : vrai si l'opération a réussi, faux sinon.
******************************************************************************/
BOOL OpenCOM(char *nport,long speed) {
    char sztmp[64];
    GtkWidget *p_dialog = NULL;

    g_dcb.BaudRate=speed;

    HDL_Com=CreateFile(nport,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_SYSTEM,NULL);
    if(HDL_Com==INVALID_HANDLE_VALUE) {
        sprintf(sztmp,"Can't open %s port",nport);
        p_dialog=gtk_message_dialog_new(NULL,GTK_DIALOG_MODAL,GTK_MESSAGE_ERROR,GTK_BUTTONS_OK,sztmp);
        gtk_window_set_position(GTK_WINDOW(p_dialog),GTK_WIN_POS_CENTER);
        gtk_dialog_run(GTK_DIALOG(p_dialog));
        gtk_widget_destroy (p_dialog);
        return FALSE;
    }

    /* affectation taille des tampons d'émission et de réception */
    SetupComm(HDL_Com, RX_SIZE, TX_SIZE);

    /* configuration du port COM */
    if(!SetCommTimeouts(HDL_Com,&g_cto) || !SetCommState(HDL_Com,&g_dcb)) {
        sprintf(sztmp,"Can't configure %s port",nport);
        p_dialog=gtk_message_dialog_new(NULL,GTK_DIALOG_MODAL,GTK_MESSAGE_ERROR,GTK_BUTTONS_OK,sztmp);
        gtk_window_set_position(GTK_WINDOW(p_dialog),GTK_WIN_POS_CENTER);
        gtk_dialog_run(GTK_DIALOG(p_dialog));
        gtk_widget_destroy (p_dialog);
        CloseHandle(HDL_Com);
        return FALSE;
    }

    /* on vide les tampons d'émission et de réception, mise à 1 DTR */
    PurgeComm(HDL_Com,PURGE_TXCLEAR|PURGE_RXCLEAR|PURGE_TXABORT|PURGE_RXABORT);
    EscapeCommFunction(HDL_Com,SETDTR);
    return TRUE;
}

/******************************************************************************
  CloseCOM : fermeture du port COM.
  retour : vrai si l'opération a réussi, faux sinon.
******************************************************************************/
BOOL CloseCOM(void) {
    /* fermeture du port COM */
    CloseHandle(HDL_Com);
    return TRUE;
}

/******************************************************************************
  ReadCOM : lecture de données sur le port COM.
  entrée : buffer       : buffer où mettre les données lues.
           nBytesToRead : nombre max d'octets à lire.
           pBytesRead   : variable qui va recevoir le nombre d'octets lus.
  retour : vrai si l'opération a réussi, faux sinon.
-------------------------------------------------------------------------------
  Remarques : - la constante MAX_WAIT_READ utilisée dans la structure
                COMMTIMEOUTS permet de limiter le temps d'attente si aucun
                caractères n'est présent dans le tampon d'entrée.
              - la fonction peut donc retourner vrai sans avoir lu de données.
******************************************************************************/
BOOL ReadCOM(void* buffer, int nBytesToRead, int* pBytesRead) {
    return ReadFile(HDL_Com, buffer, nBytesToRead, (DWORD*)pBytesRead, NULL);
}

/******************************************************************************
  WriteCOM : envoi de données sur le port COM.
  entrée : buffer        : buffer avec les données à envoyer.
           nBytesToWrite : nombre d'octets à envoyer.
           pBytesWritten : variable qui va recevoir le nombre d'octets
                           envoyés.
  retour : vrai si l'opération a réussi, faux sinon.
******************************************************************************/
BOOL WriteCOM(void* buffer, int nBytesToWrite, int* pBytesWritten) {
    /* écriture sur le port */
    return WriteFile(HDL_Com, buffer, nBytesToWrite, (DWORD*)pBytesWritten, NULL);
}
