
#include "serial_function.h"
#include <stdio.h>
#include <windows.h> 
#include <winerror.h> 
#include <string.h>

#define MAX_HANDLES 10

HANDLE handles[MAX_HANDLES];	  // speicher fuer die Handles, die aber eigentlich void* sind


void uni_to_ascii( const short * unistring , char *asciistring)
{
	int i=0;
	while(unistring[i])
	{
		asciistring[i] = (char)unistring[i];
		i++;
	}
    asciistring[i] = 0;	
}

void ascii_to_uni( const char * asciistring , short *unistring)
{
	int i=0;
	while(asciistring[i])
	{
		unistring[i] = asciistring[i];
		i++;
	}
    unistring[i] = 0;	
}

/*----------------------------------------------------------------*/
/* INIT                                                           */
/*----------------------------------------------------------------*/
JNIEXPORT void JNICALL Java_serial_1function_Init
  (JNIEnv * env , jclass cl)
{
	int i;
			// alle handles feigeben
	for(i=0; i< MAX_HANDLES; i++)
	{
        handles[i] = 0;
	}
}

/*----------------------------------------------------------------*/
/* Setup                                                          */
/*----------------------------------------------------------------*/

JNIEXPORT jint JNICALL Java_serial_1function_SerialSetup
  (JNIEnv * env, jclass cl, jint jhandle, jint jbaud, jint jhandshake)
{
	HANDLE hand;
	DCB PortDCB;

    if(jhandle > 0 && jhandle < MAX_HANDLES)
	{

		hand = handles[jhandle-1];


		// Initialize the DCBlength member. 
		PortDCB.DCBlength = sizeof (DCB); 

		// Get the default port setting information.
		GetCommState (hand, &PortDCB);

		// Change the DCB structure settings.
		PortDCB.BaudRate = jbaud;              // Current baud 
		PortDCB.fBinary = TRUE;               // Binary mode; no EOF check 
		PortDCB.fParity = TRUE;               // Enable parity checking 
		PortDCB.fOutxCtsFlow = FALSE;         // No CTS output flow control 
		PortDCB.fOutxDsrFlow = FALSE;         // No DSR output flow control 
		PortDCB.fDtrControl = DTR_CONTROL_ENABLE; 
											  // DTR flow control type 
		PortDCB.fDsrSensitivity = FALSE;      // DSR sensitivity 
		PortDCB.fTXContinueOnXoff = TRUE;     // XOFF continues Tx 
		PortDCB.fOutX = FALSE;                // No XON/XOFF out flow control 
		PortDCB.fInX = FALSE;                 // No XON/XOFF in flow control 
		PortDCB.fErrorChar = FALSE;           // Disable error replacement 
		PortDCB.fNull = FALSE;                // Disable null stripping 

		if(jhandshake)
 		   PortDCB.fRtsControl = RTS_CONTROL_ENABLE; 
		else
 		   PortDCB.fRtsControl = RTS_CONTROL_DISABLE; 

											  // RTS flow control 
		PortDCB.fAbortOnError = FALSE;        // Do not abort reads/writes on 
											  // error
		PortDCB.ByteSize = 8;                 // Number of bits/byte, 4-8 
		PortDCB.Parity = NOPARITY;            // 0-4=no,odd,even,mark,space 
		PortDCB.StopBits = ONESTOPBIT;        // 0,1,2 = 1, 1.5, 2 

		// Configure the port according to the specifications of the DCB 
		// structure.
		if (!SetCommState (hand, &PortDCB))
		{
		  return 1;
		}
    }
	return 0;
}


/*----------------------------------------------------------------*/
/* Open                                                           */
/*----------------------------------------------------------------*/

JNIEXPORT jint JNICALL Java_serial_1function_CreateFile
  (JNIEnv * env, jclass cl, jstring jfilename, jint jmode)
{
	HANDLE hand;
    const char *filename;
	short unifilename[100];
    int erg;
	DWORD mode=0;

	filename = (*env)->GetStringUTFChars(env,jfilename,0);

	// die windows flags haben astronmische nummern, gehtueber den singned range hinaus
	// daher mappe auf eigene symbole
    if(jmode & serial_0005ffunction_MODE_READ)
		mode |= GENERIC_READ;
    if(jmode & serial_0005ffunction_MODE_WRITE)
		mode |= GENERIC_WRITE;


    ascii_to_uni(filename, unifilename);

	hand = CreateFile(unifilename, GENERIC_READ | GENERIC_WRITE , FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING , 0, NULL ); 
    if(hand == INVALID_HANDLE_VALUE)
    {
		erg = 0;
	}
	else
	{
		int merk;   // primitive suche nach einem freien Handle
        for(merk=0; merk < MAX_HANDLES; merk ++)
		{
			if(handles[merk] == 0)
				break;
		}

        if(merk < MAX_HANDLES)  // wir haben einen freien Platz bekommen
		{
	 		handles[merk] = hand;
			erg = merk+1;     // handles beginnen bei mir mit 1
		}
		else
		{
			erg = 0;	  // null ist fehler
		}
    }

	(*env)->ReleaseStringUTFChars(env, jfilename, filename );

    return (jint)erg;
}

/*----------------------------------------------------------------*/
/* Write                                                          */
/*----------------------------------------------------------------*/

JNIEXPORT jint JNICALL Java_serial_1function_WriteFile
  (JNIEnv * env, jclass cl,jint jhandle, jbyteArray jbuffer, jint size)
{
	HANDLE hand;
	unsigned long ergebnis=0;
	unsigned long erg;
    char *buffer;

    if(jhandle > 0 && jhandle < MAX_HANDLES)
	{

		buffer = (*env)->GetByteArrayElements(env,jbuffer,0);  // letzter parameter eigentlich pointer auf boolean ob copy

		hand = handles[jhandle-1];


		erg = WriteFile( hand, buffer, size, &ergebnis, NULL); 


		(*env)->ReleaseByteArrayElements(env, jbuffer, buffer,0 );

		if(erg != 0)
		  return (int)ergebnis;
		else 
		  return 0;
	}
	return 0;
}


/*----------------------------------------------------------------*/
/* Read                                                           */
/*----------------------------------------------------------------*/

JNIEXPORT jint JNICALL Java_serial_1function_ReadFile
  (JNIEnv * env, jclass cl, jint jhandle, jbyteArray jbuffer, jint size)
{
	HANDLE hand;
	unsigned long ergebnis=0;
	unsigned long erg;
    char *buffer;

	if(jhandle > 0 && jhandle < MAX_HANDLES)
	{
		buffer = (*env)->GetByteArrayElements(env,jbuffer,0);  // letzter parameter eigentlich pointer auf boolean ob copy

		hand = handles[jhandle-1];
		
		
		erg = ReadFile( hand, buffer, size, &ergebnis, NULL); 

		if(erg != 0)
		{		
			(*env)->SetByteArrayRegion(env, jbuffer, 0, ergebnis, (jbyte *) buffer );
			return (int)ergebnis;
		}
		else 
		{
			return 0;
		}
	}
	return 0;  // wrong handle

}

/*----------------------------------------------------------------*/
/* Close                                                          */
/*----------------------------------------------------------------*/

JNIEXPORT void JNICALL Java_serial_1function_CloseFile
  (JNIEnv * env, jclass cl, jint jhandle)
{
	HANDLE hand;

	if(jhandle > 0 && jhandle < MAX_HANDLES)
	{
		hand = handles[jhandle-1];
		CloseHandle(hand);

		handles[jhandle-1] = 0;
	}
}

JNIEXPORT jint JNICALL Java_serial_1function_GetLastError
  (JNIEnv * env, jclass cl)
{
	return GetLastError();
}


JNIEXPORT void JNICALL Java_serial_1function_SetLastError
  (JNIEnv * env, jclass cl, jint jerror)
{
	SetLastError((DWORD)jerror);
}

