
#include <stdio.h>
#include "ntcan.h"
#include <pthread.h>
#include <string.h>
#include <unistd.h>


/* background thread receive all CAN messages with 11-bit ID */
void* background_thread(void* arg) {
	int i,j; /* Loop counter */
	int32_t count=8;
	CMSG rxcmsg[8];
	NTCAN_HANDLE rxhandle = * (NTCAN_HANDLE*) arg; /* can txhandle returned by canOpen() */
	NTCAN_RESULT retvalue; /* return values of NTCAN API calls */
	while (1) {
		count=(int32_t)(sizeof(rxcmsg) / sizeof(rxcmsg[0]));
		retvalue = canRead(rxhandle, &rxcmsg[0], &count, NULL);
		if (retvalue == NTCAN_RX_TIMEOUT)
		{
			printf("canRead() returned timeout\n");
			continue;
		}
		else if (retvalue != NTCAN_SUCCESS)
		{
			printf("canRead() failed with error %d!\n", retvalue);
		}
		else
		{
			printf("canRead() received %d message(s) !\n", count);
			for (j = 0; j < (int)count; j++) {
				if(NTCAN_IS_INTERACTION(rxcmsg[j].len))
					printf("message sent from the same port! \n");
				int len = NTCAN_LEN_TO_DATASIZE(rxcmsg[j].len);
				printf("CAN-ID of received message %d : %03x\n",j, NTCAN_ID(rxcmsg[j].id));
				if (NTCAN_IS_RTR(rxcmsg[j].len)) {
					printf("Received a RTR message (%d)", len);
				} else {
					printf("Received a data message with %d bytes : ", len);
					for (i = 0; i < len; i++)
						printf("%02x ", rxcmsg[j].data[i]);
				}
				printf("\n\n");

			}
		}
		continue;
	}
    return(0);
}

int main()
{
	int net=0; /* logical net number */
	uint32_t mode1=0; /* mode used for the txhandle*/
	uint32_t mode2=NTCAN_MODE_MARK_INTERACTION; /* mode used for the rxhandle*/
	int32_t txqueuesize1=8; /* size of transmit queue for the txhandle*/
    int32_t txqueuesize2=NTCAN_NO_QUEUE; /* size of transmit queue for the rxhandle*/
	int32_t rxqueuesize1=NTCAN_NO_QUEUE; /* size of receive queue for the txhandle*/
	int32_t rxqueuesize2=8; /* size of receive queue for the rxhandle*/
	int32_t txtimeout1=2000; /* timeout for transmit operations in ms for the txhandle*/
    int32_t txtimeout2=0; /* timeout for transmit operations in ms for the rxhandle*/
	int32_t rxtimeout1=0; /* timeout for receive operations in ms for the txhandle*/
	int32_t rxtimeout2=2000; /* timeout for receive operations in ms for the rxhandle*/
	NTCAN_HANDLE txhandle; /* can txhandle returned by canOpen() */
	NTCAN_HANDLE rxhandle; /* can txhandle returned by canOpen() */
	NTCAN_RESULT retvalue; /* return values of NTCAN API calls */
	uint32_t baud=NTCAN_BAUD_1000; /* 1000k bit/s, 2 for 500k bit/s, 4 for 250k bit/s */
	uint64_t timestampFreq; /*timestamp frequency*/
	uint32_t time_interval_ms=500;
    int32_t idCount = 0x800;
	CMSG schedtxcmsg;
	CSCHED schedule;
	CAN_IF_STATUS cstatus;
    pthread_t tid;
/* ############################################################### */
	retvalue = canOpen(net,
                        mode1,
						txqueuesize1,
						rxqueuesize1,
						txtimeout1,
						rxtimeout1,
						&txhandle);
	if (retvalue != NTCAN_SUCCESS)
	{
		printf("canOpen() txhandle failed with error %d!\n", retvalue);
		return(-1);
	}

    retvalue = canOpen(net,
                        mode2,
                        txqueuesize2,
                        rxqueuesize2,
                        txtimeout2,
                        rxtimeout2,
                        &rxhandle);
    if (retvalue != NTCAN_SUCCESS)
    {
        printf("canOpen() rxhandle failed with error %d!\n", retvalue);
        return(-1);
    }
/* ############################################################### */
	retvalue = canSetBaudrate(txhandle, baud); 
    /* bit rate affects all CAN handles which refer to this physical port. */
	if (retvalue != 0)
	{
		printf("canSetBaudrate() failed with error %d!\n", retvalue);
		canClose(txhandle);
		return(-1);
	}
/* ############################################################### */
    retvalue = canIdRegionAdd(rxhandle, 0, &idCount); /* Enable CAN-IDs 0-0x7ff */
    if (retvalue != NTCAN_SUCCESS)
    {
        printf("canIdRegionAdd() failed with error %d!\n", retvalue);
        canClose(rxhandle);
        return(-1);
    }
/* ############################################################### */
    // create thread
    if (pthread_create(&tid, NULL, background_thread, &rxhandle) != 0) {
        perror("pthread_create");
        return (-1);
    }
    // detach the created thread
    if (pthread_detach(tid) != 0) {
        perror("pthread_detach");
        return (-1);
    }
/* ############################################################### */
	retvalue = canStatus(txhandle, &cstatus);
	if (retvalue != 0)
	{
		printf("canStatus() failed with error %d!\n", retvalue);
		canClose(txhandle);
		return(-1);
	}
	if (cstatus.features & NTCAN_FEATURE_SCHEDULING)
		printf("NTCAN_FEATURE_SCHEDULING is supported!\n");
	else{
		printf("NTCAN_FEATURE_SCHEDULING is NOT supported!\n");
		canClose(txhandle);
		return(-1);
	}
/* ############################################################### */
	/* Request timestamp/tick frequency of interface */
	retvalue = canIoctl(txhandle, NTCAN_IOCTL_GET_TIMESTAMP_FREQ, &timestampFreq);
	if (retvalue != NTCAN_SUCCESS) {
		printf("Gathering timestamp frequency failed with %d\n", retvalue);
		canClose(txhandle);
		return(-1);
	}

	memset(&schedtxcmsg, 0, sizeof(CMSG));
	schedtxcmsg.id = (uint32_t) 1;
	schedtxcmsg.len = 8;
	strncpy((char *)schedtxcmsg.data, "American", 8);

	memset(&schedule, 0, sizeof(CSCHED));
	schedule.id = (uint32_t) 1;
	schedule.flags = NTCAN_SCHED_FLAG_EN|
					 NTCAN_SCHED_FLAG_INC8|
					 NTCAN_SCHED_FLAG_OFS6;
	schedule.time_start = 0;
	schedule.time_interval = ((timestampFreq * time_interval_ms) / 1000ULL);
	schedule.count_start = 0xA0;
	schedule.count_stop = 0x20;

	/* Configure the scheduling for the Tx object */
	retvalue = canIoctl(txhandle, NTCAN_IOCTL_TX_OBJ_CREATE, &schedtxcmsg);
	if (retvalue != NTCAN_SUCCESS) {
		printf("Configuration of scheduling (NTCAN_IOCTL_TX_OBJ_CREATE) failed with error %x\n", retvalue);
		canClose(txhandle);
		return(-1);
	}

	/* Configure the scheduling for the Tx object */
	retvalue = canIoctl(txhandle, NTCAN_IOCTL_TX_OBJ_SCHEDULE, &schedule);
	if (retvalue != NTCAN_SUCCESS) {
		printf("Configuration of scheduling (NTCAN_IOCTL_TX_OBJ_SCHEDULE) failed with error %d\n", retvalue);
		canClose(txhandle);
		return(-1);
	}
	
	/* Start the scheduling set */
	retvalue = canIoctl(txhandle, NTCAN_IOCTL_TX_OBJ_SCHEDULE_START, NULL);
	if (retvalue != NTCAN_SUCCESS) {
		printf("Start of scheduling failed with error %d\n", retvalue);
		canClose(txhandle);
		return(-1);
	}

    sleep(100); /* Linux OS specific delay for 5 seconds !!! */


	/* Update the Tx message */
	strncpy((char *)schedtxcmsg.data, "Canadian",8);
	retvalue = canIoctl(txhandle, NTCAN_IOCTL_TX_OBJ_UPDATE, &schedtxcmsg);
	if (retvalue != NTCAN_SUCCESS) {
		printf("Update of scheduling failed with error %d\n", retvalue);
	}

	sleep(100); /* OS specific delay for 5 seconds !!! */

	/* Stop the scheduling */
	retvalue = canIoctl(txhandle, NTCAN_IOCTL_TX_OBJ_SCHEDULE_STOP, NULL);
	if (retvalue != NTCAN_SUCCESS) {
		printf("Stop of scheduling failed with error %d\n", retvalue);
		canClose(txhandle);
		return(-1);
	}

	sleep(100); /* OS specific delay for 10 seconds !!! */
/* ############################################################### */
	retvalue = canClose (txhandle);
	if (retvalue != NTCAN_SUCCESS)
		printf("canClose failed with error %d!\n", retvalue);
/* ############################################################### */
	return(0);
}