/*  Copyright (C) MOXA Inc. All rights reserved.

    This software is distributed under the terms of the
    MOXA License.  See the file COPYING-MOXA for details.
*/
/*
    mxcanbus_win.c

    Routines to operate canbus ports 

    2009-07-25	CF Lin
		new release
	2010-12-03	Epson
		mxcan_open modified

	2011-01-05	Epson
		mxcan_get_parameters modified
		mxcan_set_parameters modified
*/
#include "stdafx.h"
#include <winioctl.h>
#include "mxcanbus.h"
//#include "os-support.h"

//#define mxcan_get_parameters(comH,param,rlen) 	DeviceIoControl( comH, IOCTL_GET_PARAMETERS, NULL,0, param, sizeof(CANPRM), rlen,NULL)
//#define mxcan_set_parameters(comH,param,rlen) 	DeviceIoControl( comH, IOCTL_SET_PARAMETERS, param, sizeof(CANPRM), NULL,0, rlen,NULL)


/* get the parameters of an open port
	Inputs:
		<fd>	the open port
		<param> CANBUS Parameter
		<rlen>  length of param
	Returns:
		return 0 on success, otherwise returns a negative value
*/
int	
mxcan_get_parameters ( unsigned int fd, CANPRM *param)
{
	DWORD	rlen;
	HANDLE  comH=(HANDLE)fd;
	
	if(!DeviceIoControl( comH, IOCTL_GET_PARAMETERS, NULL,0, param, sizeof(CANPRM), &rlen,NULL)){
		return (-1);
	}

	return 0;	
}

/* set the parameters of an open port
	Inputs:
		<fd>	the open port
		<param> CANBUS Parameter
		<rlen>  length of param
	Returns:
		return 0 on success, otherwise returns a negative value
*/
int	
mxcan_set_parameters ( unsigned int fd, CANPRM *param)
{
	DWORD	rlen;
	HANDLE  comH=(HANDLE)fd;
	
	if(!DeviceIoControl( comH, IOCTL_SET_PARAMETERS, param, sizeof(CANPRM), NULL,0, &rlen,NULL)){
		return (-1);		
	}
	return 0;
}

/* set the bus timing of an open port
	Inputs:
		<fd> the open port
		<speed> bus timing in Hz
	Returns:
		return 0 on success, otherwise returns a negative value
*/
int	
mxcan_set_bus_timing ( unsigned int fd, unsigned int speed)
{
	CANPRM param;

	if (mxcan_get_parameters(fd, &param)==(-1))
		return -1;
	param.bus_timing = speed;
	if (mxcan_set_parameters(fd, &param)==(-1))
		return -2;
	else
		return 0;
}

/* get the bus timing of an open port
	Inputs:
		<fd> the open port
	Returns:
		return 0 on failure, otherwise the bus speed in KHz
*/
unsigned int	
mxcan_get_bus_timing(unsigned int fd)
{
	CANPRM param;
	
	if (mxcan_get_parameters(fd, &param)==(-1))
		return 0;
	else
		return param.bus_timing;
}

/*	purge the buffers of an open port
	Inputs:
		<fd> the open port
		<purge> 1: receive data buffer, 2: transmit data buffer, otherwise: both
	Returns:
		0 on success, otherwise failure
*/
int 
mxcan_purge_buffer( unsigned int fd, unsigned int purge)
{
	HANDLE comH = (HANDLE) fd;
	DWORD rlen;

	if (purge==1)
		return (DeviceIoControl( comH, IOCTL_PURGE_RX_BUFFER, NULL, 0, NULL,0,&rlen,NULL) == 0)? -1:0;
	else if (purge==2)
		return (DeviceIoControl( comH, IOCTL_PURGE_TX_BUFFER, NULL, 0, NULL,0,&rlen,NULL) == 0)? -2:0;
	else if (DeviceIoControl( comH, IOCTL_PURGE_RX_BUFFER, NULL, 0, NULL,0,&rlen,NULL) == 0)
		return -3;
	else
		return (DeviceIoControl( comH, IOCTL_PURGE_TX_BUFFER, NULL, 0, NULL,0,&rlen,NULL) == 0)? -4:0;
}

/*	set data reading timeout of an open port
	Inputs:
		<fd> the open port
		<to> timeout in milliseconds
	Returns:
		0 on success, otherwise failure
*/
int
mxcan_set_read_timeout(unsigned int fd, unsigned int to)
{
	HANDLE comH = (HANDLE) fd;
	DWORD timeout = (DWORD) to; 
	DWORD rlen;

	return (DeviceIoControl( comH, IOCTL_SET_READ_TIMEOUT, &timeout, sizeof(DWORD), NULL, 0, &rlen,NULL) == 0)? -1:0;
}

/*	set data writing timeout of an open port
	Inputs:
		<fd> the open port
		<to> timeout in milliseconds
	Returns:
		0 on success, otherwise failure
*/
int
mxcan_set_write_timeout(unsigned int fd, unsigned int to)
{
	HANDLE comH = (HANDLE) fd;
	DWORD timeout = (DWORD) to; 
	DWORD rlen;

	return (DeviceIoControl( comH, IOCTL_SET_WRITE_TIMEOUT, &timeout, sizeof(DWORD), NULL, 0, &rlen,NULL) == 0)? -1:0;
}

/*	set the open fd to be non-blocking
	Inputs:
		<fd> the open port
	Returns:
		0 on success, otherwise failure
*/
int
mxcan_set_nonblocking(unsigned int fd)
{
	if (mxcan_set_read_timeout( fd, 0))
		return -1;
	if (mxcan_set_write_timeout( fd, 0))
		return -2;
	return 0;
}

/*	get the number of received bytes that are queuded 
	in the driver of an open port
	Inputs:
		<fd> the open port
	Returns:
		< 0 on failure, the number of bytes
*/
int	
mxcan_inqueue(unsigned int fd)
{
	HANDLE comH = (HANDLE) fd;
	unsigned int bytes = 0;
	DWORD rlen;

	if (DeviceIoControl( comH, IOCTL_GET_RX_BYTES, NULL,0, &bytes, sizeof(bytes), &rlen,NULL) == 0)
		return -1;
	return (int) bytes;
}

/*	get the number of bytes waiting for being transmitted to a can port
	Inputs:
		<fd> the open port
	Returns:
		< 0 on failure, the number of bytes
*/
int
mxcan_outqueue( unsigned int fd )
{
	HANDLE comH = (HANDLE) fd;
	int bytes = 0;
	DWORD rlen;

	if (DeviceIoControl( comH, IOCTL_GET_TX_BYTES, NULL,0, &bytes, sizeof(bytes), &rlen,NULL) == 0)
		return -1;
	return bytes;
}

/*	read data onto a buffer from an open port
	Inputs:
		<fd> the open port
		<buffer> point to the buffer
		<size> maximum size to be read
		<hndl> reserved
	Returns:
		< 0, on failure
		0, no data ready
		otherwise the number of bytes read
*/
int
mxcan_read( unsigned int fd, char *buffer, int size, void *hndl)
{
	HANDLE	comH = (HANDLE) fd;
	int len = 0;

	if (ReadFile(comH, buffer, size, (LPDWORD)&len, 0)==0)
		return -1;
	return len;
}

/* write data to the open port
	Inputs:
		<fd> the open port
		<data> point to the data
		<size> size of the data
		<hndl> reserved
	Returns:
		< 0 on failure, otherwise the number of bytes written
*/
int
mxcan_write( unsigned int fd, char *buffer, int size, void *hndl)
{
	HANDLE comH = (HANDLE) fd;
	int	len = 0;

	(void) hndl;

	if (WriteFile( comH, buffer, size, (LPDWORD)&len, NULL)) 
		return len;
	else
		return -1;
}

/*	close an open port 
	Inputs:
		<fd> the open port
	Returns:
		None
*/
int
mxcan_close( unsigned int fd )
{
	HANDLE comH = (HANDLE) fd;

	CloseHandle(comH);
	return 0;
}

/*	get the statatics of an open port 
	Inputs:
		<fd> the open port
		<stat> point to a contianer of statatics
	Returns:
		0 on success
*/
int	
mxcan_get_stat(unsigned int fd, CANBST *stat)
{
	DWORD rlen;
	if (DeviceIoControl( (HANDLE) fd, IOCTL_GET_DEVICE_STATISTIC, NULL,0, stat, sizeof(CANBST), &rlen,NULL) == 0)
		return -1;
	return 0;
}

/*	get the register values of an open port 
	Inputs:
		<fd> the open port
		<buffer> point to a buffer for these values
		<num> number of register values
	Returns:
		0 on success
*/
int	
mxcan_get_registers ( unsigned int fd, unsigned char *buffer, int num)
{
	DWORD rlen;
	if (DeviceIoControl( (HANDLE) fd, IOCTL_GET_DEVICE_REGISTERS, NULL,0, buffer,num, &rlen,NULL) == 0)
		return -1;
	return 0;
}

/*	open a can port by the port number 
	Inputs:
		<port> port number starting from 1
	Returns:
		0 on failure, otherwise the handle of an open port
*/
unsigned int
mxcan_open(int port)
{
	HANDLE comH;
	WCHAR szPort[20];
	unsigned int fd;

#ifdef _WIN32_WCE
	wsprintf(szPort, L"$device\\CAN%d\0", port);
	comH = CreateFile( szPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
#else
 	wsprintf( szPort, L"\\\\.\\CAN%d", port );
	comH = CreateFile(szPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
#endif
	if ( comH == INVALID_HANDLE_VALUE)
		return 0;
	fd = (unsigned int) comH;
	return fd;
}