/***************************************************************************
 *   Copyright (C) 2006 by EVER Sp. z o.o.                                 *
 *                                                                         *
 *   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; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "ftccomm.h"
#include "common.h"
#include <sys/ioctl.h>

#define _POSIX_SOURCE 1 /* POSIX compliant source */

FTCComm::FTCComm()
{
	device=NULL;
	fd=0;
	bIsSimpleSig = false;
	bIsLocked = false;
	bIsInitialized = false;
	fStatus = FT_OK;
}


FTCComm::~FTCComm()
{
	FT_Close(fd);
	if (device!=NULL)
		free(device);
}

int FTCComm::open()
{
	if (device==NULL || baudrate==0)
		return COMM_FAILURE;

	fStatus = FT_OpenEx(device, FT_OPEN_BY_SERIAL_NUMBER, &fd);
	lasterror = fStatus;
	if (fStatus!=FT_OK)
		return COMM_FAILURE;
	else
		bIsInitialized = true;
	
	fStatus = FT_SetBaudRate(fd, baudrate);
	lasterror = fStatus;
	if (fStatus!=FT_OK)
		return COMM_FAILURE;
	lasterror=fStatus;
	
	fStatus = FT_SetFlowControl(fd, FT_FLOW_NONE, 0, 0);
	lasterror = fStatus;
	if (fStatus!=FT_OK)
		return COMM_FAILURE;
	
	fStatus = FT_SetTimeouts(fd, 2500, 1500);
	lasterror = fStatus;
	if (fStatus!=FT_OK)
		return COMM_FAILURE;
	
	return COMM_SUCCESS;
}

/* open port for simple signalling type of communication */
int FTCComm::open_simplesignalling()
{
	if (device == NULL)
		return COMM_FAILURE;

	fStatus = FT_OpenEx(device, FT_OPEN_BY_SERIAL_NUMBER, &fd);
	lasterror = fStatus;
	if (fStatus != FT_OK)
		return COMM_FAILURE;
	else
		bIsInitialized = true;
	
	fStatus = FT_SetFlowControl(fd, FT_FLOW_NONE, 0, 0);
	lasterror = fStatus;
	if (fStatus != FT_OK)
		return COMM_FAILURE;
	
	return COMM_SUCCESS;
}

int FTCComm::close()
{
	if (!bIsInitialized)
		return COMM_FAILURE;
	
	flush(1, 1);
	/* close port */
	fStatus = FT_Close(fd);
	lasterror=errno;
	if (fStatus != FT_OK)
		return COMM_FAILURE;
	bIsInitialized = false;
	fd = 0;
	
	return COMM_SUCCESS;
}

unsigned long FTCComm::getStatus()
{
	if (!bIsInitialized)
		return COMM_FAILURE;
	
	unsigned long ulflags = 0;
	
	fStatus = FT_GetModemStatus(fd, &ulflags);
	lasterror = fStatus;
	if (fStatus != FT_OK)
		return COMM_FAILURE;
	else
		return ulflags;
}

int FTCComm::getStatus(unsigned long *pflags)
{
	if (!bIsInitialized || pflags==NULL)
		return COMM_FAILURE;
	
	fStatus = FT_GetModemStatus(fd, pflags);
	lasterror = fStatus;
	if (fStatus != FT_OK)
		return COMM_FAILURE;
	else
		return COMM_SUCCESS;
}

int FTCComm::setStatus(unsigned long flags)
{
	if (!bIsInitialized)
		return COMM_FAILURE;
	
	// RTS control line
	if (flags & FT_S_RTS)
		fStatus = FT_SetRts(fd);
	else
		fStatus = FT_ClrRts(fd);
	lasterror = fStatus;
	if (fStatus != FT_OK)
		return COMM_FAILURE;
	// DTR control line
	if (flags & FT_S_DTR)
		fStatus = FT_SetDtr(fd);
	else
		fStatus = FT_ClrDtr(fd);
	lasterror = fStatus;
	if (fStatus != FT_OK)
		return COMM_FAILURE;

	return COMM_SUCCESS;
}

int FTCComm::status_check(eftcomm_status eFlag)
{
	unsigned long curflags = 0;
	if (getStatus(&curflags)!=COMM_FAILURE) {
		if (curflags & eFlag)
			return 1;
	}
	return 0;
}

/* send one byte/character */
int FTCComm::send(unsigned char data)
{
	if (!bIsInitialized)
		return COMM_FAILURE;
	unsigned char data_out = data;
	unsigned long ulnbw = 0;

	fStatus = FT_Write(fd, &data_out, 1, &ulnbw);
	lasterror = fStatus;
	if (fStatus != FT_OK)
		return COMM_FAILURE;

	return COMM_SUCCESS;
}

int FTCComm::send(unsigned char *pdata, int len)
{
	if (!bIsInitialized)
		return COMM_FAILURE;
	unsigned long ulnbw = 0;

	fStatus = FT_Write(fd, pdata, len, &ulnbw);
	lasterror = fStatus;
	if (fStatus != FT_OK)
		return COMM_FAILURE;
		
	return COMM_SUCCESS;
}

/* send two byte/character */
int FTCComm::send2b(unsigned int *pdata)
{
	if (!bIsInitialized)
		return COMM_FAILURE;
	if((send(LOBYTE(*pdata))!=COMM_SUCCESS) ||
		(send(HIBYTE(*pdata))!=COMM_SUCCESS)) {
		lasterror=errno;
		return COMM_FAILURE;
	}
	lasterror=errno;
	return COMM_SUCCESS;
}

int FTCComm::send2b(unsigned int *pdata, int len2b)
{
	if (!bIsInitialized)
		return COMM_FAILURE;

	for (int ib=0; ib<len2b; ib++) {
		if (send2b((unsigned int *)(pdata+ib))!=COMM_SUCCESS) {
			lasterror=errno;
			return COMM_FAILURE;
		}
	}
	lasterror=errno;
	return COMM_SUCCESS;
}

// receive only one character and place it in the buffer
int FTCComm::receive(unsigned char *pdata)
{
	if (pdata==NULL || !bIsInitialized)
		return COMM_FAILURE;
	unsigned long ulnbr = 0;

	fStatus = FT_Read(fd, pdata, 1, &ulnbr);
	lasterror = fStatus;
	if (fStatus != FT_OK)
		return COMM_FAILURE;
		
	return COMM_SUCCESS;
}

int FTCComm::receive(unsigned char *pdata, int len)
{
	if (pdata==NULL || !bIsInitialized)
		return COMM_FAILURE;

	unsigned long ulnbr = 0;

	fStatus = FT_Read(fd, pdata, len, &ulnbr);
	lasterror = fStatus;
	if (fStatus != FT_OK)
		return COMM_FAILURE;
	
	return COMM_SUCCESS;
}

int FTCComm::receive2b(unsigned int *pdata, int len2b)
{
	if (pdata==NULL || !bIsInitialized)
		return COMM_FAILURE;
		
	unsigned char ucTmpBuf[2]="";
	int ib=0;
	for (ib=0; ib<len2b; ib++) {
		if (receive(ucTmpBuf, 2)==COMM_FAILURE)
			return COMM_FAILURE;
		pdata[ib]=(unsigned int)MAKEWORD(ucTmpBuf[0], ucTmpBuf[1]);
	}
	return COMM_SUCCESS;
}

int FTCComm::receive2brev(unsigned int *pdata, int len2b)
{
	if (pdata==NULL || !bIsInitialized)
		return COMM_FAILURE;
		
	unsigned char ucTmpBuf[2]="";
	int ib=0;
	for (ib=0; ib<len2b; ib++) {
		if (receive(ucTmpBuf, 2)==COMM_FAILURE)
			return COMM_FAILURE;
		pdata[ib]=(unsigned int)MAKEWORD(ucTmpBuf[1], ucTmpBuf[0]);
	}
	return COMM_SUCCESS;
}

int FTCComm::receive2b(unsigned int *pdata, int len2b, unsigned long *pcrc)
{
	if (pdata==NULL || !bIsInitialized || pcrc==NULL)
		return COMM_FAILURE;
		
	unsigned char ucTmpBuf[2]="";
	int ib=0;
	for (ib=0; ib<len2b; ib++) {
		if (receive(ucTmpBuf, 2)==COMM_FAILURE)
			return COMM_FAILURE;
		pdata[ib]=(unsigned int)MAKEWORD(ucTmpBuf[0], ucTmpBuf[1]);
		*pcrc+=ucTmpBuf[0]+ucTmpBuf[1];
	}
	return COMM_SUCCESS;
}

int FTCComm::receive2brev(unsigned int *pdata, int len2b, unsigned long *pcrc)
{
	if (pdata==NULL || !bIsInitialized || pcrc==NULL)
		return COMM_FAILURE;

	unsigned char ucTmpBuf[2]="";
	int ib=0;
	for (ib=0; ib<len2b; ib++) {
		if (receive(ucTmpBuf, 2)==COMM_FAILURE)
			return COMM_FAILURE;
		pdata[ib]=(unsigned int)MAKEWORD(ucTmpBuf[1], ucTmpBuf[0]);
		*pcrc+=ucTmpBuf[0]+ucTmpBuf[1];
	}
	return COMM_SUCCESS;
}

int FTCComm::lock_port()
{
	if (!bIsInitialized)
		return COMM_FAILURE;

#if defined(HAVE_FLOCK)
/*
	if (flock(fd, LOCK_EX | LOCK_NB) != 0)
		return COMM_FAILURE;
*/
#elif defined(HAVE_LOCKF)
/*	
	lseek(fd, 0L, SEEK_SET);
	if (lockf(fd, F_TLOCK, 0L))
		return COMM_FAILURE;
*/
#endif
	return COMM_SUCCESS;
}

int FTCComm::unlock_port()
{
	if (!bIsInitialized || !bIsLocked)
		return COMM_FAILURE;

#if defined(HAVE_FLOCK)
/*
	if (flock(fd, LOCK_UN) != 0)
		return COMM_FAILURE;
*/
#elif defined(HAVE_LOCKF)
/*	
	lseek(fd, 0L, SEEK_SET);
	if (lockf(fd, F_ULOCK, 0L))
		return COMM_FAILURE;
*/
#endif
	return COMM_SUCCESS;
}

int FTCComm::set_line(eftcomm_lines eline)
{
	if (eline == FT_S_RTS) {
		fStatus = FT_SetRts(fd);
		lasterror = fStatus;
		if (fStatus != FT_OK)
			return COMM_FAILURE;
	}
	if (eline == FT_S_DTR) {
		fStatus = FT_SetDtr(fd);
		lasterror = fStatus;
		if (fStatus != FT_OK)
			return COMM_FAILURE;
	}
	return getStatus();
}

int FTCComm::clr_line(eftcomm_lines eline)
{
	if (eline == FT_S_RTS) {
		fStatus = FT_ClrRts(fd);
		lasterror = fStatus;
		if (fStatus != FT_OK)
			return COMM_FAILURE;
	}
	if (eline == FT_S_DTR) {
		fStatus = FT_ClrDtr(fd);
		lasterror = fStatus;
		if (fStatus != FT_OK)
			return COMM_FAILURE;
	}
	return getStatus();
}

