#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include <errno.h>
#include <jni.h>


#include <android/log.h>
static const char *TAG="SpiDevice";
#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO,  TAG, fmt, ##args)
#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)
#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)

int iFileHandle=0;
int iBaudRate=0;
jobject mFileDescriptor=NULL;

struct spi_ioc_transfer spiIocTransfer = {
            .delay_usecs = 0,
            .speed_hz = 12*1000*1000,
            .bits_per_word = 8,
        };


JNIEXPORT jobject JNICALL Java_com_xixun_communicate_SpiDevice_Open  (JNIEnv * env, jobject obj, jstring deviceName, jint iBaudRate0,jint mode)
{   int iWorkResault=-1;
    int ret ;

    iBaudRate=iBaudRate0;
    spiIocTransfer.speed_hz=iBaudRate;

	{
		jboolean isCopy;
		const char * pDeviceName= (*env)->GetStringUTFChars(env, deviceName, &isCopy);
		LOGD("SpiDevice.c Open %s. Baud Rate=%d", pDeviceName,iBaudRate0);
		iFileHandle = open(pDeviceName, O_RDWR);//"/dev/spidev0.0",O_RDWR);//
        // modified byfw 2019-4-19  ------------start
		(*env)->ReleaseStringUTFChars(env, deviceName, pDeviceName);
        // modified byfw 2019-4-19  ------------end
		if (iFileHandle<0)
		{
			/* Throw an exception */
			LOGE("SpiDevice.c Can't open device:%s,Error:%s!",deviceName,strerror(errno));//);
			/* TODO: throw an exception */
			return -1;
		}
	//	(*env)->ReleaseStringUTFChars(env, deviceName, pDeviceName);
	}
	if (iBaudRate0>0)
    {    LOGD("SpiDevice.c Set spi max speed %d.",iBaudRate);
        iWorkResault = ioctl(iFileHandle, SPI_IOC_WR_MAX_SPEED_HZ, &iBaudRate);
        if (iWorkResault<0)
        {	LOGE("SpiDevice.c Can't set max send speed:%d bps",iBaudRate);
            return NULL;
        }

        iWorkResault = ioctl(iFileHandle, SPI_IOC_RD_MAX_SPEED_HZ, &iBaudRate);
        if (iWorkResault<0)
        {	LOGE("SpiDevice.c Can't set max receive speed:%d bps",iBaudRate);
            return NULL;
        }
    }
    /*spi mode*/
    ret = ioctl(iFileHandle, SPI_IOC_WR_MODE32, &mode);
    	if (ret == -1)
    		LOGE("can't set spi WR mode");
    ret = ioctl(iFileHandle, SPI_IOC_RD_MODE32, &mode);
        if (ret == -1)
            LOGE("can't get spi RD mode");
	{
		jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor");
		jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "<init>", "()V");
		jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I");
		mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor);
		(*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint)iFileHandle);

		(*env)->DeleteLocalRef(env,cFileDescriptor);
	}

	return mFileDescriptor;
}

JNIEXPORT jint JNICALL Java_com_xixun_communicate_SpiDevice_Operator(JNIEnv * env, jobject obj, jbyteArray Databuffer, jint iLength)
{

  int iWorkResault=-1;
    if (iLength<=0) return iWorkResault;
    if (iFileHandle<=0) return iWorkResault;
    if (Databuffer==NULL) return iWorkResault;


    jbyte* array= (*env)->GetByteArrayElements(env,Databuffer,0);

    spiIocTransfer.tx_buf=spiIocTransfer.rx_buf=(unsigned long)array;
    spiIocTransfer.len=iLength;
    iWorkResault=ioctl(iFileHandle, SPI_IOC_MESSAGE(1), &spiIocTransfer);

    (*env)->ReleaseByteArrayElements(env,Databuffer,array,0);

    return iWorkResault;

}


JNIEXPORT jint JNICALL Java_com_xixun_communicate_SpiDevice_Trans(JNIEnv * env, jobject obj, jbyteArray sendBuf, jbyteArray recvBuf, jint iLength){
    int i = 0;
    int iWorkResault = -1;
    jbyte* sendArray= (*env)->GetByteArrayElements(env,sendBuf,0);
    jbyte* recvArray= (*env)->GetByteArrayElements(env,recvBuf,0);

    spiIocTransfer.tx_buf=(unsigned long)sendArray;
    spiIocTransfer.rx_buf=(unsigned long)recvArray;
    spiIocTransfer.len=iLength;



    iWorkResault=ioctl(iFileHandle, SPI_IOC_MESSAGE(1), &spiIocTransfer);
    for(; i<iWorkResault; i++){
        LOGI("recv %d", recvArray[i]);
    }

    (*env)->ReleaseByteArrayElements(env,sendBuf,sendArray,0);
    (*env)->ReleaseByteArrayElements(env,recvBuf,recvArray,0);
    return iWorkResault;
}


JNIEXPORT jint JNICALL Java_com_xixun_communicate_SpiDevice_Close(JNIEnv * env, jobject obj)
{
    close(iFileHandle);
    //(*env)->DeleteLocalRef(env,mFileDescriptor);
    return 0;
}




/*

static void transfer()
{
	jint i=0,iCounter=0,ret=0;
	uint8_t tx[32] = {
		0xAA,
		0x70,0x00,0x00,

		0x00,0x20,
		0x00,0x00
		//0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
		//0x40, 0x00, 0x00, 0x00, 0x00, 0x95,
		//0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
		//0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
		//0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
		//0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD,
		//0xF0, 0x0D,
	};
	uint8_t rx[40] = {0, };

	struct spi_ioc_transfer tr = {
		.tx_buf = (unsigned long)tx,
		.rx_buf = (unsigned long)rx,
		.len = sizeof(tx),
		.delay_usecs = 0,
		.speed_hz = iBaudRate,
		.bits_per_word = 8,
	};

printf("Send:");
	for (i = 0; i < sizeof(tx); i++) {
		if (!(i % 16))
			puts("");
		LOGD("%.2X ", tx[i]);
	}
	puts("");

	for (i=0;i<sizeof(rx);i++) rx[i]=0x3C;

	ret = ioctl(iFileHandle, SPI_IOC_MESSAGE(1), &tr);
	if (ret < 1)
		LOGE("Can't send spi message.");

LOGD("Rece:%d",ret);
	for (i = 0; i < ret; i++) {
		if (!(i % 16))
			puts("");
		LOGD("%.2X ", rx[i]);
	}
	puts("");
}

*/