Understanding Canbus.h library

Hi,

for my bachelorthesis I have to build a cruise control for a boat which has a CAN bus. There already is an arduino with a sparkfun CANbus shield to read the data and save it. This arduino was programmed by an ICT-guy and I’m not, so understanding his code is a disaster cause he uses efficient coding :slight_smile: . He said that he started with this code from a tutorial (https://www.instructables.com/id/CAN-Bus-Sniffing-and-Broadcasting-with-Arduino/). So I tried understanding the tutorial but I cant seem to understand everything:

  • tCAN message: what does this do? is this a type that is defined in the library? like:
typedef struct tCAN{
id
header
data
}tCAN;
  • mcp3626_get_message(&message)): if this returns 1 it continues but what does it check? why the &message?
/*
This is for use with Sparkfun's CAN Bus Shield: https://www.sparkfun.com/products/10039
*/

#include <Canbus.h>
#include <defaults.h>
#include <global.h>
#include <mcp2515.h>
#include <mcp2515_defs.h>

void setup() {
  Serial.begin(9600); // For debug use
  Serial.println("CAN Read - Testing receival of CAN Bus message");  
  delay(1000);
  
  if(Canbus.init(CANSPEED_500))  //Initialise MCP2515 CAN controller at the specified speed
    Serial.println("CAN Init ok");
  else
    Serial.println("Can't init CAN");
    
  delay(1000);
}

void loop(){

  tCAN message;
if (mcp2515_check_message()) 
	{
    if (mcp2515_get_message(&message)) 
	{
        //if(message.id == 0x620 and message.data[2] == 0xFF)  //uncomment when you want to filter
             //{
               
               Serial.print("ID: ");
               Serial.print(message.id,HEX);
               Serial.print(", ");
               Serial.print("Data: ");
               Serial.print(message.header.length,DEC);
               for(int i=0;i<message.header.length;i++) 
                {	
                  Serial.print(message.data[i],HEX);
                  Serial.print(" ");
                }
               Serial.println("");
             //}
           }}

}

Moshtaraq:

  • tCAN message: what does this do? is this a type that is defined in the library?

Yes. It is declared in one of the libraries as either a 'struct' or a 'class'.

Moshtaraq:

  • mcp3626_get_message(&message)): if this returns 1 it continues but what does it check? why the &message?

You'd have to check the library source to see exactly what it does. It appears to accept a message from the CAN bus and store it in the tCAN struct/object. It appears to return 'true' (a non-zero value) when the message passes some checks (like maybe a checksum). The "&message" ('address of' message) is passed to the function so the function can change the contents of the variable 'message'. If the variable is passed by value, the function just gets a copy of it and can't change the passed variable.

Thanks!
that & sign had me confused with the bitwise operator. Is there an overview of the commands from that library, or any library like the mcp2515? Can't seem to find any.

 rx_frame.FIR.B.FF = CAN_frame_std; // standard frame or extended frame
        rx_frame.MsgID = pxServo_Message.MsgID; // can be used to control which message is for what
        rx_frame.FIR.B.DLC = pxServo_Message.DLC; // if extended frame a lot of info can be stored here
        rx_frame.data.u8[0] = pxServo_Message.Instruction; // the 8 bytes of data in a can frame
        rx_frame.data.u8[1] = pxServo_Message.p1;
        rx_frame.data.u8[2] = pxServo_Message.p2;
        rx_frame.data.u8[3] = pxServo_Message.p3;
        rx_frame.data.u8[4] = pxServo_Message.p4; 
        rx_frame.data.u8[5] = pxServo_Message.p5;
        rx_frame.data.u8[6] = pxServo_Message.p6;
        rx_frame.data.u8[7] = pxServo_Message.p7;

I got a bit further in the other guy’s code and came to this function(?):

long convertBytesToDec(byte bytes[], int start, int ending)
{
  long value = 0;
  int shift = 24;
  for (int i = start; i < ending; i++)
  {
    value |= (uint32_t) bytes[i] << shift;
    shift -= 8;
  }
}

-Obviously its to convert Bytes in to decimal values but why is there no return? like ‘return value’ as I would write at the end.
-Can it only go through 4 bytes because of the shift=24?
-Why is the (uint32_t) there? is it because value is a long (32 bit) and otherwise the bitwise operation would’nt work?

Moshtaraq:
-Obviously its to convert Bytes in to decimal values but why is there no return? like ‘return value’ as I would write at the end.

It’s not clear why it does not return the value. My guess is “Programmer Error”.

Moshtaraq:
-Can it only go through 4 bytes because of the shift=24?

It can do fewer bytes but the value is left-justified in the long int so anything less than 4 bytes doesn’t make much sense. Anything more then 4 bytes gets you into negative shifts!

Moshtaraq:
-Why is the (uint32_t) there? is it because value is a long (32 bit) and otherwise the bitwise operation would’nt work?

It is because shifting a byte left more than 8 bits pushes all the bits off the top, leaving you with zero. Casting the byte to uint32_t allows it to be shifted left without losing the data off the top.

This version works for any number of bytes, including zero, but only works with unsigned values unless the value is 4 bytes:

uint32_t convert8bitTo32bit(byte bytes[], int start, int ending)
{
  uint32_t value = 0;
  for (int i = start; i < ending; i++)
  {
    vaue <<= 8;
    value |= bytes[i];
  }
  return value;
}

I also thought it was an error but they told me the program worked, this converter is used in a check of what message is sent on the CAN bus. Thanks for the info

Moshtaraq:
I also thought it was an error but they told me the program worked, this converter is used in a check of what message is sent on the CAN bus. Thanks for the info

The value returned when reaching the end of a non-void C++ function is 'undefined behavior' (except for a function named 'main' where the return value is zero). This function may 'work' today but could return nonsense if you change to another board or update anything in the Arduino install.
Because of optimization, this function may not generate any code. The compiler can tell that it never returns a value and that it makes no changes to global variables so it does no useful work.
I recommend fixing this function and any other places where the libraries generate warnings. One of the great features of open-source libraries is that you can fix mistakes made by the author.