/***********************************************************************
 *  avrp - Atmel AVR programming software to use with Atmel's
 *         serial-port programmers.
 *  Copyright (C) 1997-1998 Jon Anders Haugum
 *
 *  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 2 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; see the file COPYING.  If not, write to
 *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 *  Boston, MA 02111-1307, USA.
 *
 *
 *  Author of avrp can be reached at:
 *     email: jonah@colargol.tihlde.hist.no
 *     www: http://www.colargol.tihlde.hist.no/~jonah/el/avrp.html
 *     Postal address: Jon Anders Haugum
 *                     Øvre Møllenbergsgt 52
 *                     7014 Trondheim
 */

/*
 * Serial port routines using win32 API (Windows 95/NT)
 */

#include <stdio.h>
#include <windows.h>

#include "avrp.h"

/*
 * Structure private to serial port functions
 */

struct Ser
   {
   char *Name;           // Name of serial port
   HANDLE Comm;          // Filehandle for serial port
   int comm_open;        // Set to True when port is open
   COMMTIMEOUTS cto_old; // Storage for old timeout values
   };

/*
 * Open the serial port
 */

void *OpenSer(char *SerPort)
   {
   struct Ser *Ser = NULL;
   DCB dcb;
   COMMTIMEOUTS cto_new = {0};

   if(Ser = (struct Ser *)malloc(sizeof(struct Ser)))
      {
      Ser->Name = SerPort;
      Ser->comm_open = False;
      Ser->Comm = CreateFile(SerPort,  
                             GENERIC_READ | GENERIC_WRITE, 
                             0, 
                             0, 
                             OPEN_EXISTING,
                             0,
                             0);
      if(Ser->Comm != INVALID_HANDLE_VALUE)
         {
         Ser->comm_open = True;
         GetCommTimeouts(Ser->Comm, &Ser->cto_old);
         cto_new.ReadTotalTimeoutConstant = 300; // milliseconds
         SetCommTimeouts(Ser->Comm, &cto_new);
         FillMemory(&dcb, sizeof(dcb), 0);
         dcb.DCBlength = sizeof(dcb);
         if(BuildCommDCB("19200,n,8,1", &dcb))
            {
            if(SetCommState(Ser->Comm, &dcb))
               return(Ser);
            else
               printf("Error: SetCommState() failed\n");
            }
         else
            printf("Error: BuildCommDCB() failed\n");
         }
      else
         printf("Error: %s: No such port\n", SerPort);
      CloseSer(Ser);
      }
   else
      printf("Error: Unable to allocate memory\n");
   return(NULL);
   }

/*
 * Close the serial port
 */

void CloseSer(void *Ser)
   {
   if(((struct Ser *)Ser)->comm_open)
      {
      SetCommTimeouts(((struct Ser *)Ser)->Comm, &((struct Ser *)Ser)->cto_old);
      CloseHandle(((struct Ser *)Ser)->Comm);
      }
   free(Ser);
   }

/*
 * Write a byte to serial port
 */

void SerWriteByte(void *Ser, unsigned char Byte)
   {
   int ret;

   WriteFile(((struct Ser *)Ser)->Comm, &Byte, 1, &ret, NULL);
   }

/*
 * Read data from serial port
 *
 * INPUTS
 *   Ser   - Pointer to serial structure
 *   Buff  - Pointer to buffer
 *   Count - Number of bytes to read
 * 
 * RESULT
 *    Actual number of bytes read 
 */

int SerReadData(void *Ser, unsigned char *Buff, int Count)
   {
   int ret;

   ReadFile(((struct Ser *)Ser)->Comm, Buff, Count, &ret, NULL);
   return(ret);
   }

