/********************************************************************************/
/*                      Demo source for esd NTCAN-API                           */
/*                                                                              */
/*              Copyright by Shanghai ESD Electric Technology Co., Ltd.         */
/*------------------------------------------------------------------------------*/
/*          Filename:       canstatus.c                                         */
/*          Date:           2020-12-28                                          */
/*          Language:       ANSI C                                              */
/*          Targetsystem:   Windows 10, Linux                                   */
/*          Purpose:        Get the status information about the CAN hardware   */
/*                          and software environment.                           */
/*          Author:         Bob Tu                                              */
/*------------------------------------------------------------------------------*/ 
/* Revision history:                                                            */
/*------------------------------------------------------------------------------*/
/* v1.0     Birth of module                                                     */
/* v1.1     When printf NTCAN_INFO->timestamp_freq, use %#llx and %lld for      */
/*          _WIN32, use %#lx and %ld for __linux__                              */
/********************************************************************************/

#include <stdio.h>
#include "ntcan.h"
int main()
{
  int net=0; /* logical net number (here: 0) */
  uint32_t mode=0; /* mode used for canOpen() */
  int32_t txqueuesize=8; /* size of transmit queue */
  int32_t rxqueuesize=8; /* size of receive queue */
  int32_t txtimeout=100; /* timeout for transmit operations in ms */
  int32_t rxtimeout=1000; /* timeout for receive operations in ms */
  NTCAN_HANDLE handle; /* can handle returned by canOpen() */
  NTCAN_RESULT retvalue; /* return values of NTCAN API calls */
  uint32_t baud=0; /* 1000k bit/s, 2 for 500k bit/s, 4 for 250k bit/s */
  CAN_IF_STATUS cstatus;
  NTCAN_INFO ntcan_info;
/* ############################################################### */
  retvalue = canOpen(net,
                     mode,
                     txqueuesize,
                     rxqueuesize,
                     txtimeout,
                     rxtimeout,
                     &handle);

  if (retvalue != NTCAN_SUCCESS)
  {
    printf("canOpen() failed with error %d!\n", retvalue);
    return(-1);
  }
/* ############################################################### */
  retvalue = canSetBaudrate(handle, baud);
  if (retvalue != 0)
  {
    printf("canSetBaudrate() failed with error %d!\n", retvalue);
    canClose(handle);
    return(-1);
  }
/* ############################################################### */
retvalue = canStatus(handle, &cstatus);  
if (retvalue == NTCAN_SUCCESS){
	printf("CAN_IF_STATUS->hardware: %#x\n", cstatus.hardware);
	printf("\thardware version: %x.%x.%x\n",
				cstatus.hardware>>12 & 0xf,
				cstatus.hardware>>8 & 0x0f,
				cstatus.hardware & 0x00ff);
	printf("CAN_IF_STATUS->firmware: %#x\n", cstatus.firmware);
	if(cstatus.firmware)
		printf("\tfirmware version: %x.%x.%x\n",
					cstatus.firmware>>12 & 0xf,
					cstatus.firmware>>8 & 0x0f,
					cstatus.firmware & 0x00ff);
	else
		printf("\tpassive CAN interface, no firmware inside. \n");
	printf("CAN_IF_STATUS->driver: %#x\n", cstatus.driver);
	printf("\tdriver version: %x.%x.%x\n",
				cstatus.driver>>12 & 0xf,
				cstatus.driver>>8 & 0x0f,
				cstatus.driver & 0x00ff);
	printf("CAN_IF_STATUS->dll: %#x\n", cstatus.dll);
	printf("\tdll version: %x.%x.%x\n",
				cstatus.dll>>12 & 0xf,
				cstatus.dll>>8 & 0x0f,
				cstatus.dll & 0x00ff);
	printf("CAN_IF_STATUS->boardstatus: %#x\n", cstatus.boardstatus);
	printf("\tCAN controller type: ");
	switch (cstatus.boardstatus>>24)
	{
   		case NTCAN_CANCTL_SJA1000: 		
		   printf("NXP SJA1000 / Philips 82C200 \n");break;
		case NTCAN_CANCTL_I82527: 
		   printf("Intel I82527 \n");break;
   		case NTCAN_CANCTL_FUJI: 
		   printf("Fujitsu MBxxxxx MCU \n");break;
   		case NTCAN_CANCTL_LPC: 
		   printf("NXP LPC2xxx / LPC17xx MCU \n");break;
   		case NTCAN_CANCTL_MSCAN: 
		   printf("Freescale MCU (MSCAN) \n");break;
   		case NTCAN_CANCTL_ATSAM: 
		   printf("Atmel ARM CPU \n");break;
   		case NTCAN_CANCTL_ESDACC: 
		   printf("esd Advanced CAN Core \n");break; 
  		case NTCAN_CANCTL_STM32: 
		   printf("ST STM32Fxxx MCU (bxCAN) \n");break;
  		case NTCAN_CANCTL_CC770: 
		   printf("Bosch CC770 (Intel 82527 compatible) \n");break;
  		case NTCAN_CANCTL_SPEAR: 
		   printf("ST SPEAr320 (Bosch C_CAN compatible) \n");break;
   		case NTCAN_CANCTL_FLEXCAN: 
		   printf("Freescale I.MX SoC (FlexCAN) \n");break;
   		case NTCAN_CANCTL_SITARA: 
		   printf("TI AM335x (Sitara) SoC (Bosch D_CAN compatible) \n");break;
   		case NTCAN_CANCTL_MCP2515: 
		   printf("Microchip MCP2515 \n");break;
   		default: printf("\n");
	}	
	printf("\thardware status: ");
	switch (cstatus.boardstatus<<16)
	{
   		case NTCAN_BSTATUS_OK: 		
			printf("No error.\n");break;
		case NTCAN_BSTATUS_NEED_FW_UPDATE: 
			printf("Driver and FW are incompatible. Update the FW. \n");break;
		case NTCAN_BSTATUS_HW_ERROR: 
			printf("Hardware error (usually during initialization). \n");break;
   		default: printf("\n");
	}
	printf("CAN_IF_STATUS->boardid:");
	for (int i=0;i<14;i++){
		if(cstatus.boardid[i]=='\0')
			break;
		printf("%c", cstatus.boardid[i]);
	}
	printf("\n");
  	printf("CAN_IF_STATUS->features: %#x\n", cstatus.features);
	printf("\tfeatures supported: \n");
  	if(cstatus.features & NTCAN_FEATURE_FULL_CAN)
		printf("\tNTCAN_FEATURE_FULL_CAN");  	
  	if(cstatus.features & NTCAN_FEATURE_CAN_20B)
  		printf("\tNTCAN_FEATURE_CAN_20B \n");  	
  	if(cstatus.features & NTCAN_FEATURE_DEVICE_NET)
		printf("\tNTCAN_FEATURE_DEVICE_NET \n");
  	if(cstatus.features & NTCAN_FEATURE_CYCLIC_TX)
		printf("\tNTCAN_FEATURE_CYCLIC_TX \n");
  	if(cstatus.features & NTCAN_FEATURE_TIMESTAMPED_TX)
		printf("\tNTCAN_FEATURE_TIMESTAMPED_TX \n");
  	if(cstatus.features & NTCAN_FEATURE_RX_OBJECT_MODE)
		printf("\tNTCAN_FEATURE_RX_OBJECT_MODE \n");
  	if(cstatus.features & NTCAN_FEATURE_TIMESTAMP)
		printf("\tNTCAN_FEATURE_TIMESTAMP \n");
  	if(cstatus.features & NTCAN_FEATURE_LISTEN_ONLY_MODE)
		printf("\tNTCAN_FEATURE_LISTEN_ONLY_MODE \n");
  	if(cstatus.features & NTCAN_FEATURE_SMART_DISCONNECT)
		printf("\tNTCAN_FEATURE_SMART_DISCONNECT \n");  	
  	if(cstatus.features & NTCAN_FEATURE_LOCAL_ECHO)
		printf("\tNTCAN_FEATURE_LOCAL_ECHO \n");
  	if(cstatus.features & NTCAN_FEATURE_SMART_ID_FILTER)
		printf("\tNTCAN_FEATURE_SMART_ID_FILTER \n");
  	if(cstatus.features & NTCAN_FEATURE_SCHEDULING)
		printf("\tNTCAN_FEATURE_SCHEDULING \n");  	
  	if(cstatus.features & NTCAN_FEATURE_DIAGNOSTIC)
		printf("\tNTCAN_FEATURE_DIAGNOSTIC \n");
  	if(cstatus.features & NTCAN_FEATURE_ERROR_INJECTION)
		printf("\tNTCAN_FEATURE_ERROR_INJECTION \n");  	
  	if(cstatus.features & NTCAN_FEATURE_IRIGB)
		printf("\tNTCAN_FEATURE_IRIGB \n");
  	if(cstatus.features & NTCAN_FEATURE_PXI)
		printf("\tNTCAN_FEATURE_PXI \n");
  	if(cstatus.features & NTCAN_FEATURE_CAN_FD)
		printf("\tNTCAN_FEATURE_CAN_FD \n");  
  	if(cstatus.features & NTCAN_FEATURE_SELF_TEST)
		printf("\tNTCAN_FEATURE_SELF_TEST \n");
   	if(cstatus.features & NTCAN_FEATURE_TRIPLE_SAMPLING)
		printf("\tNTCAN_FEATURE_TRIPLE_SAMPLING \n");  	
	// NTCAN_FEATURE_LIN feature can't be checked here, but can be 
	// checked in NTCAN_INFO. because NTCAN_FEATURE_LIN is defined with 
	// value 27, which exceeds the CAN_IF_STATUS.features 16-bit definition.
	// if(features & NTCAN_FEATURE_LIN)	
	// 	printf("\tNTCAN_FEATURE_LIN \n");  	
  	printf("\n");
  }  
/* ############################################################### */
retvalue = canIoctl(handle, NTCAN_IOCTL_GET_INFO, &ntcan_info);
if (retvalue == NTCAN_SUCCESS){
	printf("NTCAN_INFO->hardware: %#x \n", ntcan_info.hardware);
	printf("\thardware version: %x.%x.%x\n",
				ntcan_info.hardware>>12 & 0xf,
				ntcan_info.hardware>>8 & 0x0f,
				ntcan_info.hardware & 0x00ff);
	printf("NTCAN_INFO->firmware: %#x \n", ntcan_info.firmware);
	if(ntcan_info.firmware)
		printf("\tfirmware version: %x.%x.%x\n",
					ntcan_info.firmware>>12 & 0xf,
					ntcan_info.firmware>>8 & 0x0f,
					ntcan_info.firmware & 0x00ff);
	else
		printf("\tpassive CAN interface, no firmware inside. \n");
	printf("NTCAN_INFO->driver: %#x \n", ntcan_info.driver);
	printf("\tdriver version: %x.%x.%x\n",
				ntcan_info.driver>>12 & 0xf,
				ntcan_info.driver>>8 & 0x0f,
				ntcan_info.driver & 0x00ff);
	printf("NTCAN_INFO->dll: %#x \n", ntcan_info.dll);
	printf("\tdll version: %x.%x.%x\n",
				ntcan_info.dll>>12 & 0xf,
				ntcan_info.dll>>8 & 0x0f,
				ntcan_info.dll & 0x00ff);
	printf("NTCAN_INFO->features: %#x \n", ntcan_info.features);
		printf("\tfeatures supported: \n");
		if(ntcan_info.features & NTCAN_FEATURE_FULL_CAN)
			printf("\tNTCAN_FEATURE_FULL_CAN");  	
		if(ntcan_info.features & NTCAN_FEATURE_CAN_20B)
			printf("\tNTCAN_FEATURE_CAN_20B \n");  	
		if(ntcan_info.features & NTCAN_FEATURE_DEVICE_NET)
			printf("\tNTCAN_FEATURE_DEVICE_NET \n");
		if(ntcan_info.features & NTCAN_FEATURE_CYCLIC_TX)
			printf("\tNTCAN_FEATURE_CYCLIC_TX \n");
		if(ntcan_info.features & NTCAN_FEATURE_TIMESTAMPED_TX)
			printf("\tNTCAN_FEATURE_TIMESTAMPED_TX \n");
		if(ntcan_info.features & NTCAN_FEATURE_RX_OBJECT_MODE)
			printf("\tNTCAN_FEATURE_RX_OBJECT_MODE \n");
		if(ntcan_info.features & NTCAN_FEATURE_TIMESTAMP)
			printf("\tNTCAN_FEATURE_TIMESTAMP \n");
		if(ntcan_info.features & NTCAN_FEATURE_LISTEN_ONLY_MODE)
			printf("\tNTCAN_FEATURE_LISTEN_ONLY_MODE \n");
		if(ntcan_info.features & NTCAN_FEATURE_SMART_DISCONNECT)
			printf("\tNTCAN_FEATURE_SMART_DISCONNECT \n");  	
		if(ntcan_info.features & NTCAN_FEATURE_LOCAL_ECHO)
			printf("\tNTCAN_FEATURE_LOCAL_ECHO \n");
		if(ntcan_info.features & NTCAN_FEATURE_SMART_ID_FILTER)
			printf("\tNTCAN_FEATURE_SMART_ID_FILTER \n");
		if(ntcan_info.features & NTCAN_FEATURE_SCHEDULING)
			printf("\tNTCAN_FEATURE_SCHEDULING \n");  	
		if(ntcan_info.features & NTCAN_FEATURE_DIAGNOSTIC)
			printf("\tNTCAN_FEATURE_DIAGNOSTIC \n");
		if(ntcan_info.features & NTCAN_FEATURE_ERROR_INJECTION)
			printf("\tNTCAN_FEATURE_ERROR_INJECTION \n");  	
		if(ntcan_info.features & NTCAN_FEATURE_IRIGB)
			printf("\tNTCAN_FEATURE_IRIGB \n");
		if(ntcan_info.features & NTCAN_FEATURE_PXI)
			printf("\tNTCAN_FEATURE_PXI \n");
		if(ntcan_info.features & NTCAN_FEATURE_CAN_FD)
			printf("\tNTCAN_FEATURE_CAN_FD \n");  
		if(ntcan_info.features & NTCAN_FEATURE_SELF_TEST)
			printf("\tNTCAN_FEATURE_SELF_TEST \n");
		if(ntcan_info.features & NTCAN_FEATURE_TRIPLE_SAMPLING)
			printf("\tNTCAN_FEATURE_TRIPLE_SAMPLING \n");  	
		if(ntcan_info.features & NTCAN_FEATURE_LIN)	
			printf("\tNTCAN_FEATURE_LIN \n");  
	printf("NTCAN_INFO->serial: %#x \n", ntcan_info.serial);
	printf("\tserial number: %c%c%06d \n", 
		(char)((ntcan_info.serial>>28) + 65),
		(char)((ntcan_info.serial>>24 & 0x0f) + 65),
		(ntcan_info.serial & 0xffffff));	

#if __linux__
	printf("NTCAN_INFO->timestamp_freq: %#lx \n", ntcan_info.timestamp_freq);
	printf("\tresolution of the timestamp counter in %ld Hz. \n", 
		ntcan_info.timestamp_freq);
#endif

#if _WIN32
	printf("NTCAN_INFO->timestamp_freq: %#llx \n", ntcan_info.timestamp_freq);
	printf("\tresolution of the timestamp counter in %lld Hz. \n", 
		ntcan_info.timestamp_freq);
#endif

	printf("NTCAN_INFO->ctrl_clock: %#x \n", ntcan_info.ctrl_clock);
	printf("\tclock frequency of the CAN controller in %d Hz.\n", 
		ntcan_info.ctrl_clock);
	printf("NTCAN_INFO->ctrl_type: %#x \n", ntcan_info.ctrl_type);
	printf("\tCAN controller type: ");
	switch (ntcan_info.ctrl_type)
	{
   		case NTCAN_CANCTL_SJA1000: 		
		   printf("NXP SJA1000 / Philips 82C200 \n");break;
		case NTCAN_CANCTL_I82527: 
		   printf("Intel I82527 \n");break;
   		case NTCAN_CANCTL_FUJI: 
		   printf("Fujitsu MBxxxxx MCU \n");break;
   		case NTCAN_CANCTL_LPC: 
		   printf("NXP LPC2xxx / LPC17xx MCU \n");break;
   		case NTCAN_CANCTL_MSCAN: 
		   printf("Freescale MCU (MSCAN) \n");break;
   		case NTCAN_CANCTL_ATSAM: 
		   printf("Atmel ARM CPU \n");break;
   		case NTCAN_CANCTL_ESDACC: 
		   printf("esd Advanced CAN Core \n");break; 
  		case NTCAN_CANCTL_STM32: 
		   printf("ST STM32Fxxx MCU (bxCAN) \n");break;
  		case NTCAN_CANCTL_CC770: 
		   printf("Bosch CC770 (Intel 82527 compatible) \n");break;
  		case NTCAN_CANCTL_SPEAR: 
		   printf("ST SPEAr320 (Bosch C_CAN compatible) \n");break;
   		case NTCAN_CANCTL_FLEXCAN: 
		   printf("Freescale I.MX SoC (FlexCAN) \n");break;
   		case NTCAN_CANCTL_SITARA: 
		   printf("TI AM335x (Sitara) SoC (Bosch D_CAN compatible) \n");break;
   		case NTCAN_CANCTL_MCP2515: 
		   printf("Microchip MCP2515 \n");break;
   		default: printf("\n");
	}
	printf("NTCAN_INFO->base_net: %d \n", ntcan_info.base_net);
	printf("NTCAN_INFO->ports: %d \n", ntcan_info.ports);
	printf("NTCAN_INFO->transceiver: %#x \n", ntcan_info.transceiver);
	printf("\tCAN transceiver: ");
	switch (ntcan_info.transceiver)
	{
		case NTCAN_TRX_PCA82C251:
			printf("NXP PCA82C251 \n");break;
		case NTCAN_TRX_SN65HVD251:
			printf("TI SN65HVD251 \n");break;
		case NTCAN_TRX_SN65HVD265:
			printf("TI SN65HVD255 \n");break;
		default:
			printf("\n");break;
	}
	printf("NTCAN_INFO->boardstatus: %#x \n", ntcan_info.boardstatus);
	printf("\thardware status: ");
	switch (ntcan_info.boardstatus)
	{
   		case NTCAN_BSTATUS_OK: 		
			printf("No error.\n");break;
		case NTCAN_BSTATUS_NEED_FW_UPDATE: 
			printf("Driver and FW are incompatible. Update the FW. \n");break;
		case NTCAN_BSTATUS_HW_ERROR: 
			printf("Hardware error (usually during initialization). \n");break;
   		default: printf("\n");
	}
	printf("NTCAN_INFO->firmware2: %#x \n", ntcan_info.firmware2);
	if(ntcan_info.firmware2)
		printf("\tfirmware version: %x.%x.%x\n",
					ntcan_info.firmware>>12 & 0xf,
					ntcan_info.firmware>>8 & 0x0f,
					ntcan_info.firmware & 0x00ff);
	else
		printf("\tthis CAN interface has no 2nd firmware inside. \n");
	printf("NTCAN_INFO->boardid: ");
	for (int i=0;i<14;i++){
		if(ntcan_info.boardid[i]=='\0')
			break;
		printf("%c", ntcan_info.boardid[i]);
	}
	printf("\n");
	printf("NTCAN_INFO->serial_string: ");
	for (int i = 0; i < 16; i++){
		if(ntcan_info.serial_string[i]=='\0')
			break;
		printf("%c", ntcan_info.serial_string[i]);
	}
	printf("\n");
	printf("NTCAN_INFO->drv_build_info: ");
	for (int i = 0; i < 64; i++){
		if(ntcan_info.drv_build_info[i]=='\0')
			break;
		printf("%c", ntcan_info.drv_build_info[i]);
	}
	printf("\n");
	printf("NTCAN_INFO->lib_build_info: ");
	for (int i = 0; i < 64; i++){
		if(ntcan_info.lib_build_info[i]=='\0')
			break;
		printf("%c", ntcan_info.lib_build_info[i]);
	}
	printf("\n");
	printf("NTCAN_INFO->open_handle: %d \n", ntcan_info.open_handle);
  }
/* ############################################################### */
  retvalue = canClose (handle);
  if (retvalue != NTCAN_SUCCESS)
    printf("canClose failed with error %d!\n", retvalue);
/* ############################################################### */
  return(0);
}