MCP2515 CANBus message substitution

I'm struggling and I need help!

I've been working with the CoryJFowler MCP_Can libraries to build a pass through and filter 'box' to get some kit (nav screen) to function in a car it was never intended to go in.

In a nut shell I have an Arduino Pro Mini hooked up to two CAN transceivers (TJA1050) and I am running a vehicle log file into one transceiver (CAN0) using BUSMaster, and pushing the messages straight back on to CAN1 which is monitored in BUSMaster and connected to the screen.

The examples in the library are excellent, as is the mark up in the header files, a credit to Cory and the reason I've got this far.

As a simple bi directional pass through its working great (I get an occasional error frame, but I can live with that!)

So now I need to pluck out a single message, with a specific id (0x401) and specific content (01 yy xx xx xx xx xx xx), change the value in y and push it back out.

I've managed to mask out the ID but that doesn't really help.

I've tried 'IF' statements, but they seem to really screw with the CAN messages, typically filtering out way more than I intended.

More than likely my lack of programming skill is the issue, its something I pick up every now and again and forget pretty much everything in between.

My current code is below and features a few of the attempts i'm made to get what I want, currently commented out

// Demo: Dual CAN-BUS Shields, Data Pass-through
// Written by: Cory J. Fowler
// January 31st 2014
// This examples the ability of this library to support more than one MCP2515 based CAN interface.


#include <mcp_can_dfs.h>
#include <mcp_can.h>
#include <SPI.h>

unsigned long rxId;
unsigned long rxId_Filter;

byte len;
byte rxBuf[8];

//byte txBuf0[] = {AA,55,AA,55,AA,55,AA,55};
//byte txBuf1[] = {55,AA,55,AA,55,AA,55,AA};

MCP_CAN CAN0(9);                              // CAN0 interface usins CS on digital pin 10
MCP_CAN CAN1(8);                               // CAN1 interface using CS on digital pin 9

#define CAN0_INT 2                              // Set INT to pin 2
#define CAN1_INT 3                              // Set INT to pin 2

void setup()
{
  Serial.begin(115200);
  
  // init CAN0 bus, baudrate: 250k@16MHz
  if(CAN0.begin(MCP_ANY, CAN_125KBPS, MCP_8MHZ) == CAN_OK){ //MCP_EXT Vs MCP_ANY?
  Serial.print("CAN0: Init OK!\r\n");
  CAN0.setMode(MCP_NORMAL);
  } else Serial.print("CAN0: Init Fail!!!\r\n");
  
  // init CAN1 bus, baudrate: 250k@16MHz
  if(CAN1.begin(MCP_ANY, CAN_125KBPS, MCP_8MHZ) == CAN_OK){
  Serial.print("CAN1: Init OK!\r\n");
  CAN1.setMode(MCP_NORMAL);
  } else Serial.print("CAN1: Init Fail!!!\r\n");
  
  Serial.end();


  SPI.setClockDivider(SPI_CLOCK_DIV2);         // Set SPI to run at 8MHz (16MHz / 2 = 8 MHz)
  
  //CAN0.sendMsgBuf(0x1000000, 1, 8, txBuf0);
  //CAN1.sendMsgBuf(0x1000001, 1, 8, txBuf0);
  rxId_Filter = 401;

}

void loop(){  
	if (!digitalRead(CAN0_INT)) {                         // If pin 2 is low, read CAN0 receive buffer
		CAN0.readMsgBuf(&rxId, &len, rxBuf);       // Read data: len = data length, buf = data byte(s)
		//if (rxId == rxId_Filter) {

			CAN1.sendMsgBuf(rxId, 0, len, rxBuf);      // Immediately send message out CAN1 interface

		//}
	}
  if(!digitalRead(CAN1_INT)){                         // If pin 3 is low, read CAN1 receive buffer
    CAN1.readMsgBuf(&rxId, &len, rxBuf);       // Read data: len = data length, buf = data byte(s)
    CAN0.sendMsgBuf(rxId, 0, len, rxBuf);      // Immediately send message out CAN0 interface
  }
}

/*********************************************************************************************************
  END FILE
*********************************************************************************************************/

I guess I'm asking for some pointers for basic programming that might make identifying, modifying and sending a single message possible, without messing up the CAN message.

if you wish to select a single message ID you do not require if statements
set the mask to 0x1FFFFFFF (assuming 29bit ID) and the filter to the ID you require
the hardware will only pass messages with that ID to your program
do a web search on canbus mask and filter

Hi Horace,

I don't think I understand how a mask would work. I've had masks working to filter the message out, I think your suggesting filtering out all but the message I want from CAN0, then edit that and send it out on CAN1.

That would let me modify the message I need to, but I don't understand how I would get the rest of the messages from CAN0 to CAN1.

What did I miss?

the MCP2515 has two masks and six filters
Mask RXM0 and associated filters RXF0 and RXF1 and mask RXM1 and associated filters RXF2 thru RXF5
you can mask and filter out ranges of IDs and then use if statements to select particular IDs

give us some examples of what you are looking at in terms of IDs ?

here is a simple example of setting masks and filters to receive a range if IDs and using an if() statement to check if ID is 5

// demo: CAN-BUS Shield, receive data  and set mask and filter
#include <SPI.h>
#include "mcp_can.h"

// the cs pin of the version after v1.1 is default to D9
// v0.9b and v1.0 is default D10
const int SPI_CS_PIN = 10;

MCP_CAN CAN(SPI_CS_PIN);                                    // Set CS pin

unsigned char flagRecv = 0;
unsigned char len = 0;
unsigned char buf[8];
char str[20];

void setup()
{
    Serial.begin(115200);
    while (CAN_OK != CAN.begin(CAN_500KBPS))              // init can bus : baudrate = 500k
    {
        Serial.println("CAN BUS Shield init fail");
        Serial.println(" Init CAN BUS Shield again");
        delay(100);
    }
    Serial.println("CAN BUS Shield init ok!");
    // set mask, set both the mask to 0x3ff
    CAN.init_Mask(0, 0, 0x3ff);                         // there are 2 mask in mcp2515, you need to set both of them
    CAN.init_Mask(1, 0, 0x3ff);
    // set filter, we can receive id from 0x04 ~ 0x09
    CAN.init_Filt(0, 0, 0x04);                          // there are 6 filter in mcp2515
    CAN.init_Filt(1, 0, 0x05);                          // there are 6 filter in mcp2515
    CAN.init_Filt(2, 0, 0x06);                          // there are 6 filter in mcp2515
    CAN.init_Filt(3, 0, 0x07);                          // there are 6 filter in mcp2515
    CAN.init_Filt(4, 0, 0x08);                          // there are 6 filter in mcp2515
    CAN.init_Filt(5, 0, 0x09);                          // there are 6 filter in mcp2515

}

void loop()
{
     if(CAN_MSGAVAIL == CAN.checkReceive())            // check if data coming
   {
        flagRecv = 0;                // clear flag
        CAN.readMsgBuf(&len, buf);    // read data,  len: data length, buf: data buf
        Serial.println("\r\n------------------------------------------------------------------");
        long int id;
        Serial.print("Get Data From id: ");
        Serial.println(id=CAN.getCanId());
        for(int i = 0; i<len; i++)    // print the data
        {
            Serial.print("0x");
            Serial.print(buf[i], HEX);
            Serial.print("\t");
        }
        if(id == 0x5) Serial.println("\nID 5 received");  // << check ID == 5
        Serial.println();

    }
}

a run gives

CAN BUS Shield init ok!
------------------------------------------------------------------
Get Data From id: 7
0x55	0x55	0x55	0x55	0x55	0x50	0x0	0x0	
------------------------------------------------------------------
Get Data From id: 5
0x55	0x55	0x55	0x55	0x55	0x50	0x0	0x0	
ID 5 received
------------------------------------------------------------------
Get Data From id: 8
0x55	0x55	0x55	0x55	0x55	0x50	0x0	0x0

Hi Horace,

Thank you for your help, I appreciate it.

I tried your code, I don't think it used the same MCP_CAN header (version?), but I got the filters working.

I've got my code working, although not with the filters. The code you supplied was enough for me to realise what I needed to do.

The working code is below, for future reference. It's not finished, needs notation and tidying. I'll also have to prove it on vehicle!

The vehicle uses standard message lengths, with IDs between 0x010 and 0x54D

// Dual CAN-BUS Shields, Man In The Middle
// Based on the work of Cory J. Fowler, January 31st 2014
// 

// define functions to use, remove comments to enable functions
//// #define SerMon
//// #define msgfilter

#include <mcp_can_dfs.h>
#include <mcp_can.h>
#include <SPI.h>

unsigned long rxId;
unsigned long rxId_Filter;

/////////////
unsigned char flagRecv = 0;
//unsigned char len = 0;
unsigned char buf[8];
char str[20];

byte len;
byte rxBuf[8];

//byte txBuf0[] = {AA,55,AA,55,AA,55,AA,55};
//byte txBuf1[] = {55,AA,55,AA,55,AA,55,AA};

MCP_CAN CAN0(9);                              // CAN0 interface usins CS on digital pin 10
MCP_CAN CAN1(8);                               // CAN1 interface using CS on digital pin 9

#define CAN0_INT 2                              // Set INT to pin 2
#define CAN1_INT 3                              // Set INT to pin 2

void setup()
{
#ifdef SerMon
  Serial.begin(115200);
#endif  
  // init CAN0 bus, baudrate: 250k@16MHz
  if(CAN0.begin(MCP_ANY, CAN_125KBPS, MCP_8MHZ) == CAN_OK){ //MCP_EXT Vs MCP_ANY?
#ifdef SerMon 
	  Serial.print("CAN0: Init OK!\r\n");
#endif
  CAN0.setMode(MCP_NORMAL);
  }
  else {
#ifdef SerMon
	  Serial.print("CAN0: Init Fail!!!\r\n");
#endif
  }
  // init CAN1 bus, baudrate: 250k@16MHz
  if(CAN1.begin(MCP_ANY, CAN_125KBPS, MCP_8MHZ) == CAN_OK){
#ifdef SerMon
  Serial.print("CAN1: Init OK!\r\n");
#endif
  CAN1.setMode(MCP_NORMAL);
  }
  else {
#ifdef SerMon
	  Serial.print("CAN1: Init Fail!!!\r\n");
#endif
  }
#ifdef SerMon
 // Serial.end();
#endif

  SPI.setClockDivider(SPI_CLOCK_DIV2);         // Set SPI to run at 8MHz (16MHz / 2 = 8 MHz)
  
  //CAN0.sendMsgBuf(0x1000000, 1, 8, txBuf0);
  //CAN1.sendMsgBuf(0x1000001, 1, 8, txBuf0);
  rxId_Filter = 0x400;

 #ifdef msgfilter

  // set mask, set both the mask to 0x3ff
  CAN0.init_Mask(0, 0, 0x3ff);                         // there are 2 mask in mcp2515, you need to set both of them
  CAN0.init_Mask(1, 0, 0x3ff);
  // set filter, we can receive id from 0x04 ~ 0x09
  CAN0.init_Filt(0, 0, 0x04);                          // there are 6 filter in mcp2515
  CAN0.init_Filt(1, 0, 0x05);                          // there are 6 filter in mcp2515
  CAN0.init_Filt(2, 0, 0x06);                          // there are 6 filter in mcp2515
  CAN0.init_Filt(3, 0, 0x07);                          // there are 6 filter in mcp2515
  CAN0.init_Filt(4, 0, 0x08);                          // there are 6 filter in mcp2515
  CAN0.init_Filt(5, 0, 0x09);                          // there are 6 filter in mcp2515


#endif


}

void loop(){  
	if (!digitalRead(CAN0_INT)) {                         // If pin 2 is low, read CAN0 receive buffer
		CAN0.readMsgBuf(&rxId, &len, rxBuf);       // Read data: len = data length, buf = data byte(s)
		if (rxId != rxId_Filter) {

			CAN1.sendMsgBuf(rxId, 0, len, rxBuf);      // Immediately send message out CAN1 interface

		}
		else
		{
			//Serial.print("Hash 400 \t");
			//		for (int i = 0; i<8; i++)    // print the data
			//		{
			//			Serial.print("0x");
			//			Serial.print(rxBuf[i], HEX);
			//			Serial.print("\t");
			//		}
			//Serial.print("\r\n");

			if (rxBuf[0] == 0x1)
			{
			#ifdef SerMon
				Serial.print(rxId);
				Serial.print("\t ID 400 Buf 1 \t");
			#endif
				for (int i = 0; i<8; i++)    // print the data
				{
			#ifdef SerMon
					Serial.print("0x");
					Serial.print(rxBuf[i], HEX);
					Serial.print("\t");
				}
				Serial.print("\r\n");
			#endif
				//CAN1.sendMsgBuf(rxId, 0, len, rxBuf);

				byte data[8] = { rxBuf[0], 0xB, rxBuf[2], rxBuf[3], rxBuf[4], rxBuf[5], rxBuf[6], rxBuf[7] };
				CAN1.sendMsgBuf(rxId, 0, len, data );
			}
			else
			{
				CAN1.sendMsgBuf(rxId, 0, len, rxBuf);
			}

		}
	}
  if(!digitalRead(CAN1_INT)){                         // If pin 3 is low, read CAN1 receive buffer
    CAN1.readMsgBuf(&rxId, &len, rxBuf);       // Read data: len = data length, buf = data byte(s)
    CAN0.sendMsgBuf(rxId, 0, len, rxBuf);      // Immediately send message out CAN0 interface
  }
}

I uploaded a C# Arduino_Canbus_Monitor which I find useful for monitor Canbus information flow