Sample code for Arduino CAN

Dependencies:   mbed

Revision:
0:6ed8574c6258
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arduinoCAN.cpp	Mon Feb 29 19:33:12 2016 +0000
@@ -0,0 +1,897 @@
+/*
+ *  Copyright (C) 2009 Libelium Comunicaciones Distribuidas S.L.
+ *  http://www.libelium.com
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU Lesser General Public License as published by
+ *  the Free Software Foundation, either version 2.1 of the License, or
+ *  (at your option) any later version.
+   
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Lesser General Public License for more details.
+  
+ *  You should have received a copy of the GNU Lesser General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Version:	0.3
+ *  Design:		David Gascon
+ *  Implementation:		Luis Antonio Martin & Ahmad Saad
+ */
+ 
+#include "Arduino.h"
+#include "arduinoCAN.h"
+#include "../SPI/SPI.h"
+#include "../arduino-api/arduinoMultiprotocol.h"
+#include "../arduino-api/arduinoUtils.h"
+
+
+
+#define DEBUGMODE 0
+/***********************************************************************
+ * Constructors
+ ***********************************************************************/
+
+CAN::CAN(void){}
+
+
+/***********************************************************************
+ * PUBLIC METHODS
+ ***********************************************************************/
+
+//!*************************************************************
+//!	Name:	ON()													
+//!	Description: 	Initialization MCP2515
+//!	Param : void														
+//!	Returns: "1" if no error, "0" if error							
+//!*************************************************************
+bool CAN::begin(uint16_t speed)
+{
+
+	#if (DEBUGMODE ==1 )
+		Serial.println("-- Constructor Can(uint16_t speed) --");
+	#endif
+	
+	// Initialize in Socket1
+    Utils.setONSocket0();
+    Utils.setMUXSocket0();
+    Utils.unsetCSSocket0();
+	
+	//Initialization SPI
+	SPI.begin();
+	SPI.detachInterrupt();	
+	SPI.setBitOrder(MSBFIRST);
+	// both mode 0 & 3 should work
+	SPI.setDataMode(SPI_MODE0); 
+	
+	//Set the SPI frequency
+	SPI.setClockDivider(SPI_CLOCK_DIV128);
+	
+	#if (DEBUGMODE==1)
+		Serial.println("SPI configured");
+	#endif
+	
+	
+	//Software resets MCP2515
+	reset();
+	delay(10);
+	
+	//After the reset enters configuration mode	
+	
+	//Choose the rate of CAN-bus
+	switch(speed){
+	  
+    	case 1000:
+		#if (DEBUGMODE==1)
+			Serial.println("Speed=1Mbps");
+		#endif
+            Utils.setCSSocket0();
+			SPI.transfer(SPI_WRITE);
+			SPI.transfer(CNF3);
+			SPI.transfer((1<<PHSEG21));	
+			SPI.transfer((1<<BTLMODE)|(1<<PHSEG11));	
+            Utils.unsetCSSocket0();
+      	break;
+
+    	case 500:
+		#if (DEBUGMODE==1)
+			Serial.println("Speed=500kps");
+		#endif
+            Utils.setCSSocket0();
+      		SPI.transfer(SPI_WRITE);
+			SPI.transfer(CNF3);
+			SPI.transfer((1<<PHSEG21));	
+			SPI.transfer((1<<BTLMODE)|(1<<PHSEG11));
+			SPI.transfer((1<<BRP0));		
+            Utils.unsetCSSocket0();
+		break;
+
+    	case 250:
+		#if (DEBUGMODE==1)
+			Serial.println("Speed=250kps");
+		#endif
+            Utils.setCSSocket0();
+			SPI.transfer(SPI_WRITE);
+			SPI.transfer(CNF3);
+			SPI.transfer((1<<PHSEG20)|(1<<PHSEG22));	
+			SPI.transfer((1<<BTLMODE)|(1<<PHSEG12)|(1<<PHSEG11)|(1<<PHSEG10));
+			SPI.transfer((1<<BRP0));		
+            Utils.unsetCSSocket0();
+		break;
+
+		default:
+		#if (DEBUGMODE==1)
+			Serial.println("The rate requested is unavailable, is set to 125 Kbit/s by default");
+		#endif
+            Utils.setCSSocket0();
+			SPI.transfer(SPI_WRITE);
+			SPI.transfer(CNF3);
+			SPI.transfer((1<<PHSEG21));	
+			SPI.transfer((1<<BTLMODE)|(1<<PHSEG11));
+			SPI.transfer((1<<BRP2)|(1<<BRP1)|(1<<BRP0));		
+            Utils.unsetCSSocket0();
+		break;
+
+  	}
+	
+	//Enable interrupts the Rx Buffer 
+	writeRegister(CANINTE,(1<<RX1IE)|(1<<RX0IE));
+		
+	//Filters and masks
+  	//Bufer 0: All the messages and Rollover
+  	writeRegister(RXB0CTRL,(1<<RXM1)|(1<<RXM0)|(1<<BUKT)); 
+	
+  	//Bufer 1: All the messages
+	writeRegister(RXB1CTRL,(1<<RXM1)|(1<<RXM0)); 
+	
+	//All bits of the mask reception delete
+ 	writeRegister( RXM0SIDH, 0 );
+ 	writeRegister( RXM0SIDL, 0 );
+ 	writeRegister( RXM0EID8, 0 );
+  	writeRegister( RXM0EID0, 0 );
+ 	writeRegister( RXM1SIDH, 0 );
+    writeRegister( RXM1SIDL, 0 );
+  	writeRegister( RXM1EID8, 0 );
+  	writeRegister( RXM1EID0, 0 );
+	
+	//Disable pins RXnBF pins (high impedance state) 
+	writeRegister( BFPCTRL, 0 );
+	
+	//Set normal mode
+	setMode(NORMAL_MODE);
+	
+	//Test its correct mode
+	/*
+	if (read_register(CANSTAT) != 0) {
+		Serial.println("Failed to initialize the MCP2515, normal mode not activated");
+		return false;
+	}*/
+	
+	#if (DEBUGMODE==1)
+		Serial.println("-- End Constructor Can(uint16_t speed) --");
+		Serial.println("");
+	#endif
+
+	return 1;
+}
+
+//!*************************************************************
+//!	Name:	getMessage()												
+//!	Description: 	Take the CAN message								
+//!	Param : messageCAN *rec_msje: pointer to reception buffer	
+//!	Returns: "1" if no error, "0" if error							
+//!*************************************************************
+char CAN::getMessage(messageCAN *rec_msje)
+{
+	//Bought that buffer is the message
+	char status = readStatus(SPI_RX_STATUS);
+	char addr;
+	static uint8_t previoSerialuffer;
+
+	/*	
+		if (bit_is_set(status,6)) {	    
+			//If the message is in the Buffer 1
+			addr = SPI_READ_RX;
+		} 
+		else if (bit_is_set(status,7)) 
+		{	    
+			//If the message is in the Buffer 2
+			addr = SPI_READ_RX | 0x04;
+		} 
+		else {	    
+			// Error, the message is not available
+			return 0;
+	  }*/
+
+	if ( (((status & 0b11000000)>>6)&0b00000011) >2 )
+	{
+		addr=SPI_READ_RX | (previoSerialuffer++ & 0x01)<<2;
+		#if (DEBUGMODE==1)
+			Serial.println("Data in buffer available");
+		#endif
+	}
+	else if (bit_is_set(status,6)) 
+	{		
+		addr = SPI_READ_RX;
+		#if (DEBUGMODE==1)
+			Serial.println("Data in buffer 0");
+		#endif
+	}
+	else if (bit_is_set(status,7)) 
+	{
+		addr = SPI_READ_RX | 0x04;
+		#if (DEBUGMODE==1)
+			Serial.println("Data in buffer 1");
+		#endif
+	}
+	else {
+		// Error: no message available
+		#if (DEBUGMODE==1)
+			Serial.println("No messages");
+		#endif
+
+		return 0;
+	}
+	
+    Utils.setCSSocket0();
+	SPI.transfer(addr);
+	
+	//Read id 
+	rec_msje->id  = (unsigned int) SPI.transfer(0xff) << 3;   //Read the top
+	rec_msje->id |=                  SPI.transfer(0xff) >> 5;   //Read the lower
+	
+	//Return the Extended ID
+	SPI.transfer(0xff);
+	SPI.transfer(0xff);
+	
+	//Read DLC
+	char length = SPI.transfer(0xff) & 0x0f;   
+	
+	rec_msje->header.length = length;
+	rec_msje->header.rtr = (bit_is_set(status, 3)) ? 1 : 0;
+	
+	//Read data
+	    for (char i=0;i<length;i++) {
+			rec_msje->data[i] = SPI.transfer(0xFF);
+	    }
+	    
+    Utils.unsetCSSocket0();
+	
+	//Delete the interruptions flags
+	    if (bit_is_set(status, 6)) {
+			bitModify(CANINTF, (1<<RX0IF), 0);
+		}
+		else {
+			bitModify(CANINTF, (1<<RX1IF), 0);
+		}
+	
+	return status;
+}
+
+
+
+//!*************************************************************
+//!	Name:	sendMessage()												
+//!	Description: 	Send the CAN message
+//!	Param: messageCAN *send_msje: pointer to transmission buffer
+//!	Returns: "1" if no error, "0" if error							
+//!*************************************************************
+char CAN::sendMessage(messageCAN *send_msje)
+{
+	char status = readStatus(SPI_READ_STATUS);
+	
+	/* Status char:
+	 * 
+	 * Bit	Funcion
+	 *  2	TXB0CNTRL.TXREQ
+	 *  4	TXB1CNTRL.TXREQ
+	 *  6	TXB2CNTRL.TXREQ
+	 */
+	
+	char address;
+	
+	if (bit_is_clear(status, 2)) {
+		address = 0x00;
+	} else if (bit_is_clear(status, 4)) {
+		address = 0x02;
+	} else if (bit_is_clear(status, 6)) {
+		address = 0x04;
+	} else {
+		//All buffers are used can not send messages (returns 0)
+		return 0;
+	}
+	
+    Utils.setCSSocket0();
+	SPI.transfer(SPI_WRITE_TX | address);
+	//First, send the top ID10....ID3
+	SPI.transfer(send_msje->id >> 3);
+	//After sending the lower ID2....ID0
+	SPI.transfer(send_msje->id << 5);
+
+	//As we will not use the Extended ID you set it to 0
+	SPI.transfer(0);
+	SPI.transfer(0);
+	
+	char length = send_msje->header.length & 0x0F;
+	
+		if (send_msje->header.rtr) {
+			SPI.transfer((1<<RTR) | length);
+		} else {
+		//Send the message length
+			SPI.transfer(length);		
+		//Send data
+			for (char i=0;i<length;i++) {
+				SPI.transfer(send_msje->data[i]);
+			}
+		}
+	
+    Utils.unsetCSSocket0();
+	
+	//Send message
+    Utils.setCSSocket0();
+	address = (address == 0) ? 1 : address;
+	SPI.transfer(SPI_RTS | address);
+    Utils.unsetCSSocket0();
+	
+	return address;
+}
+
+
+//!*************************************************************
+//!	Name:	printMessage()											
+//!	Description: 	CAN message print out the serial port			
+//!	Param : messageCAN *msje: pointer to the message				
+//!	Returns: "1" if no error, "0" if error							
+//!*************************************************************
+void CAN::printMessage(messageCAN *msje)
+{
+	Serial.print("  id: ");
+	Serial.print(messageRx.id,HEX); 
+	Serial.print("  rtr: ");
+	Serial.print(messageRx.header.rtr,HEX); 
+	Serial.print(" => ");
+    
+	if (!msje->header.rtr) {
+		//Data
+		Serial.print(" data:  ");
+		Serial.print(messageRx.data[0],HEX); Serial.print(",");
+		Serial.print(messageRx.data[1],HEX); Serial.print(","); 
+		Serial.print(messageRx.data[2],HEX); Serial.print(",");
+		Serial.print(messageRx.data[3],HEX); Serial.print(",");
+		Serial.print(messageRx.data[4],HEX); Serial.print(",");
+		Serial.print(messageRx.data[5],HEX); Serial.print(",");
+		Serial.print(messageRx.data[6],HEX); Serial.print(",");
+		Serial.println(messageRx.data[7],HEX);
+	}
+}
+
+
+//!*************************************************************
+//!	Name:	setMode()													
+//!	Description: 	Configure the MCP2515							
+//!	Param : uint8_t mode: The work mode							
+//!	Returns: void														
+//!*************************************************************
+void CAN::setMode(uint8_t mode)
+{
+	uint8_t mode_register = 0;
+	
+	if (mode == LISTEN_ONLY_MODE) {
+		mode_register = (0<<REQOP2)|(1<<REQOP1)|(1<<REQOP0);
+	}
+	else if (mode == LOOPBACK_MODE) {
+		mode_register = (0<<REQOP2)|(1<<REQOP1)|(0<<REQOP0);
+	}
+	else if (mode == SLEEP_MODE) {
+		mode_register = (0<<REQOP2)|(0<<REQOP1)|(1<<REQOP0);
+	}
+	else if (mode == NORMAL_MODE) {
+		mode_register = (0<<REQOP2)|(0<<REQOP1)|(0<<REQOP0);
+	}
+		
+	//Set the new mode
+	bitModify(CANCTRL, (1<<REQOP2)|(1<<REQOP1)|(1<<REQOP0), mode_register);
+	
+	//Wait until the mode has been changed
+	while ((readRegister(CANSTAT) & 0xe0) != mode_register) {	}
+}
+
+
+//!*************************************************************
+//!	Name:	messageAvailable()										
+//!	Description: 	Check if there is any message					
+//!	Param : void							
+//!	Returns: 1 if available, 0 if not. 														
+//!*************************************************************
+uint8_t CAN::messageAvailable(void)
+{
+	char status = readStatus(SPI_RX_STATUS);
+
+	if ( (((status & 0b11000000)>>6)&0b00000011) >2 )
+	{		
+		return 1;	
+	} else if (bit_is_set(status,6))  {
+		return 1;
+	} else if (bit_is_set(status,7)) {
+		return 1;
+	} else  {
+		return 0;
+	
+		#if (DEBUGMODE==1)
+			Serial.println("No data available");
+		#endif		
+	}
+}
+
+//**********************************************************************
+// Standars PIDs
+//**********************************************************************
+
+
+//!*************************************************************
+//!	Name:	getEngineLoad()										
+//!	Description: 	Calculated engine load value				
+//!	Param : void							
+//!	Returns: unsigned int: engine load value (0-100)				
+//!*************************************************************
+unsigned int CAN::getEngineLoad()
+{
+	unsigned int data;
+
+	CiARequest(CALC_ENGINE_LOAD);
+	
+	if (messageRx.id==ID_RESPONSE) {
+		data =  uint16_t(messageRx.data[3] * 100)  / 255; 
+
+		#if (DEBUGMODE==1)
+			printMessage(&messageRx);
+		#endif
+	}
+	
+	return data;
+}
+
+
+//!*************************************************************
+//!	Name:	getEngineCoolantTemp()								
+//!	Description: 	Engine coolant temperature					
+//!	Param : void							
+//!	Returns: Engine coolant temperature(-40 - 215)
+//!*************************************************************
+unsigned int CAN::getEngineCoolantTemp()
+{
+	unsigned int data;
+
+	CiARequest(ENGINE_COOLANT_TEMP);
+	
+	if (messageRx.id==ID_RESPONSE) {
+		data =  uint16_t(messageRx.data[3] - 40); 
+
+		#if (DEBUGMODE==1)
+			printMessage(&messageRx);
+		#endif
+	}
+	
+	return data;
+}
+
+
+//!*************************************************************
+//!	Name:	getFuelPressure()										
+//!	Description: 	Fuel pressure					
+//!	Param : void							
+//!	Returns: unsigned int: Fuel pressure (0 - 765 Kpa)				
+//!*************************************************************
+unsigned int CAN::getFuelPressure()
+{
+	unsigned int data;
+
+	CiARequest(FUEL_PRESSURE);
+	
+	if (messageRx.id==ID_RESPONSE) {
+		data =  uint16_t(messageRx.data[3] * 3) ; 
+
+		#if (DEBUGMODE==1)
+			printMessage(&messageRx);
+		#endif
+	}
+	
+	return data;
+}
+
+
+//!*************************************************************
+//!	Name:	getIntakeMAPressure()									
+//!	Description: 	Intake manifold absolute pressure 				
+//!	Param : void							
+//!	Returns: unsigned int: absolute pressure 	(0 - 255 Kpa)		
+//!*************************************************************
+unsigned int CAN::getIntakeMAPressure()
+{
+	unsigned int data;
+
+	CiARequest(INTAKE_M_A_PRESSURE);
+	
+	if (messageRx.id==ID_RESPONSE) {
+		data =  messageRx.data[3]; 
+
+		#if (DEBUGMODE==1)
+			printMessage(&messageRx);
+		#endif
+	}
+	
+	return data;
+	
+	
+}
+
+
+//!*************************************************************
+//!	Name:	getEngineRPM()										
+//!	Description: 	Engine RPM					
+//!	Param : void							
+//!	Returns: unsigned int: Engine RPM (0 - 16,383 RPM) 						
+//!*************************************************************
+unsigned int CAN::getEngineRPM()
+{	
+	
+	unsigned int data;
+
+	CiARequest(ENGINE_RPM);
+	
+	if (messageRx.id==ID_RESPONSE) {
+		data =  (uint16_t(messageRx.data[3]*256) + messageRx.data[4])/4; 
+
+		#if (DEBUGMODE==1)
+			printMessage(&messageRx);
+		#endif
+	}
+	
+	return data;
+}
+
+
+//!*************************************************************
+//!	Name:	getVehicleSpeed()										
+//!	Description: 	Vehicle speed					
+//!	Param : void							
+//!	Returns: unsigned int: Vehicle speed (0 - 255)				
+//!*************************************************************
+unsigned int CAN::getVehicleSpeed()
+{
+	unsigned int data;
+
+	CiARequest(VEHICLE_SPEED);
+	
+	if (messageRx.id==ID_RESPONSE) {
+		data =  uint16_t(messageRx.data[3]); 
+
+		#if (DEBUGMODE==1)
+			printMessage(&messageRx);
+		#endif
+	}
+	
+	return data;
+	
+}
+
+
+//!*************************************************************
+//!	Name:	getTimingAdvance()										
+//!	Description: 	Timing advance					
+//!	Param : void							
+//!	Returns: unsigned int: Time (-64 - 63.5)		 							
+//!*************************************************************
+unsigned int CAN::getTimingAdvance()
+{
+	unsigned int data;
+
+	CiARequest(TIMING_ADVANCE);
+	
+	if (messageRx.id==ID_RESPONSE) {
+		data =  uint16_t(messageRx.data[3] / 2- 64); 
+
+		#if (DEBUGMODE==1)
+			printMessage(&messageRx);
+		#endif
+	}
+	
+	return data;
+}
+	
+//!*************************************************************
+//!	Name:	getIntankeAirTemp()										
+//!	Description: 	Intake air temperature					
+//!	Param : void							
+//!	Returns: unsigned int: Intake air temperature(-40 - 215) 
+//!*************************************************************
+unsigned int CAN::getIntankeAirTemp()
+{
+	unsigned int data;
+
+	CiARequest(INTAKE_AIR_TEMP);
+	
+	if (messageRx.id==ID_RESPONSE) {
+		data =  uint16_t(messageRx.data[3] - 40); 
+
+		#if (DEBUGMODE==1)
+			printMessage(&messageRx);
+		#endif
+	}
+	
+	return data;
+}
+
+
+//!*************************************************************
+//!	Name:	getMAFairFlowRate()										
+//!	Description: 	MAF air flow rate					
+//!	Param : void							
+//!	Returns: unsigned int: air flow rate	(0 - 655.35 g/s) 						
+//!*************************************************************
+unsigned int CAN::getMAFairFlowRate()
+{
+	unsigned int data;
+
+	CiARequest(MAF_AIR_FLOW_RATE);
+	
+	if (messageRx.id==ID_RESPONSE) {
+		data =  ( uint16_t(messageRx.data[3] * 256) + messageRx.data[4]) / 100; 
+
+		#if (DEBUGMODE==1)
+			printMessage(&messageRx);
+		#endif
+	}
+	
+	return data;
+	
+}
+
+
+//!*************************************************************
+//!	Name:	getThrottlePosition()									
+//!	Description: 	Throttle position					
+//!	Param : void							
+//!	Returns: unsigned int: Throttle position	(0 - 100%) 		
+//!*************************************************************
+unsigned int CAN::getThrottlePosition()
+{
+	unsigned int data;
+
+	CiARequest(THROTTLE_POSITION);
+	
+	if (messageRx.id==ID_RESPONSE) {
+		data =  uint16_t(messageRx.data[3] * 100) / 255; 
+
+		#if (DEBUGMODE==1)
+			printMessage(&messageRx);
+		#endif
+	}
+	
+	return data;
+	
+	
+}
+
+
+//!*************************************************************
+//!	Name:	getFuelLevel()										
+//!	Description: 	Fuel Level Input				
+//!	Param : void							
+//!	Returns: unsigned int: Fuel Level Input (0 - 100%) 							
+//!*************************************************************
+unsigned int CAN::getFuelLevel()
+{
+	unsigned int data;
+
+	CiARequest(FUEL_LEVEL);
+	
+	if (messageRx.id==ID_RESPONSE) {
+		data =  uint16_t(messageRx.data[3] * 100)  / 255; 
+
+		#if (DEBUGMODE==1)
+			printMessage(&messageRx);
+		#endif
+	}
+	
+	return data;
+	
+}
+
+
+//!*************************************************************
+//!	Name:	getBarometricPressure()									
+//!	Description: 	Barometric pressure					
+//!	Param : void							
+//!	Returns: unsigned int: Barometric pressure (0 - 255 Kpa)		
+//!*************************************************************
+unsigned int CAN::getBarometricPressure()
+{
+	unsigned int data;
+
+	CiARequest(BAROMETRIC_PRESSURE);
+	
+	if (messageRx.id==ID_RESPONSE) {
+		data =  uint16_t(messageRx.data[3]); 
+
+		#if (DEBUGMODE == 1)
+			printMessage(&messageRx);
+		#endif
+	}
+	
+	return data;
+}
+
+
+//!*************************************************************
+//!	Name:	getEngineFuelRate()										
+//!	Description: 	Engine fuel rate					
+//!	Param : void							
+//!	Returns: unsigned int: Engine fuel rate	 (0 - 3212 L/h)	
+//!*************************************************************
+unsigned int CAN::getEngineFuelRate()
+{
+	unsigned int data;
+
+	CiARequest(ENGINE_FUEL_RATE);
+	
+	if (messageRx.id==ID_RESPONSE) {
+		data = uint16_t((messageRx.data[3] * 256) + messageRx.data[4]) * 0.05; 
+
+		#if (DEBUGMODE==1)
+			printMessage(&messageRx);
+		#endif
+	}
+	
+	return data;
+	
+}
+
+
+/***********************************************************************
+                          CAN in Automation (CiA)
+ ***********************************************************************/
+
+//Request information through OBD
+void CAN::CiARequest(uint8_t PID)
+{   
+	messageTx.id = ID_QUERY;
+	messageTx.header.rtr = 0;
+	messageTx.header.length = 8;
+	messageTx.data[0]= 0x02;
+	messageTx.data[1]= 0x01;
+	messageTx.data[2]= PID;  
+   
+	
+	sendMessage(&messageTx);
+	delay(5);
+
+	if (messageAvailable()) {
+		//Read the message buffers
+		getMessage(&messageRx);
+	}
+
+}
+
+
+/***********************************************************************
+ * PRIVATE METHODS
+ ***********************************************************************/
+
+//Write a MCP2515 register
+void CAN::writeRegister( char direction, char data )
+{
+	//CS low to select the MCP2515 
+    Utils.setCSSocket0();
+
+	SPI.transfer(SPI_WRITE);
+	SPI.transfer(direction);
+	SPI.transfer(data);
+	
+	//CS line again to release 
+    Utils.unsetCSSocket0();
+}
+
+
+//**********************************************************************
+
+//Read a MCP2515 register
+char CAN::readRegister(char direction)
+{
+	char data;
+	
+	//CS low to select the MCP2515 
+    Utils.setCSSocket0();
+	
+	SPI.transfer(SPI_READ);
+	SPI.transfer(direction);	
+	//Read data SPI
+	data = SPI.transfer(0xff);	
+	
+	//CS line again to release 
+    Utils.unsetCSSocket0();
+	
+	return data;
+}
+
+
+//***********************************************************************
+
+//Modify a bit of the MCP2515 registers
+void CAN::bitModify(char direction, char mask, char data)
+{
+	//CS low to select the MCP2515 
+    Utils.setCSSocket0();
+	
+	SPI.transfer(SPI_BIT_MODIFY);
+	SPI.transfer(direction);
+	SPI.transfer(mask);
+	SPI.transfer(data);
+	
+	//CS line again to release 
+    Utils.unsetCSSocket0();
+}
+
+
+//***********************************************************************
+
+//Check the status of the MCP2515 registers (SPI_RX_STATUS / SPI_READ_STATUS)
+char CAN::readStatus(char type)
+{
+	char data;
+	
+	//CS low to select the MCP2515 
+    Utils.setCSSocket0();
+		
+	SPI.transfer(type);	
+	//Read data SPI 
+	data = SPI.transfer(0xFF); 
+	 	
+	//CS line again to release 
+    Utils.unsetCSSocket0();
+	
+	return data;
+}
+
+
+//***********************************************************************
+
+//Check if the buffers are empty
+bool CAN::checkFreeBuffer(void)
+{
+	char status = readStatus(SPI_READ_STATUS);
+	
+	
+	if ((status & 0x54) == 0x54) 
+	{	  
+		//All buffers used
+		return false;
+	}
+	
+	return true;
+}
+
+
+//***********************************************************************
+
+//Reset MCP2515
+void CAN::reset(void)
+{
+	//CS low to select the MCP2515 
+    Utils.setCSSocket0();
+
+	SPI.transfer(SPI_RESET);	
+	//CS line again to release 
+    Utils.unsetCSSocket0();
+
+
+	//Wait a bit to be stabilized after the reset MCP2515
+	delay(10);
+	
+	#if (DEBUGMODE==1)
+		Serial.println("The MCP2515 has been successfully reset, configuration mode activated");
+	#endif
+}
+
+