element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Industrial Automation
  • Technologies
  • More
Industrial Automation
Blog CAN programming in C on Linux: Filter and Mask
  • Blog
  • Forum
  • Documents
  • Quiz
  • Events
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Industrial Automation to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: Jan Cumps
  • Date Created: 22 Nov 2020 2:20 PM Date Created
  • Views 12665 views
  • Likes 6 likes
  • Comments 1 comment
  • raspberry
  • avnet
  • smartedge
  • can bus listener
  • smartedge iiot gateway
  • iiot gateway
  • linux
Related
Recommended

CAN programming in C on Linux: Filter and Mask

Jan Cumps
Jan Cumps
22 Nov 2020

Linux supports CAN networks. I'm using a CAN-enabled Raspberry Pi to test some examples.

image

 

 

Design and code are not my own. This exercise is to investigate the Linux way of doing CAN.

The code I'm using is Craig Peacock's CAN example. For the hardware, see the box below.

 

A common Raspberry Pi doesn't have a CAN bus. But it can be added as a hat (e.g: PiCAN2), or you can build your own.

I'm using a SmartEdge IIOT GatewaySmartEdge IIOT Gateway . It's a Raspberry Pi 3 Compute based industrial Linux box. It has a CAN physical layer - a real CAN bus driver. And all drivers pre-installed. See AVNET SmartEdge IIOT Gateway: Use the Isolated CAN.

The result of the 3 options above are exactly the same. The PiCAN2, the diy example and the SmartEdge solution are the same.

 

If you don't have CAN hardware, you can use Linux' virtual CAN driver vcan. That will turn your Linux device (Pi, BB, ....) into a self-contained virtual CAN network (like using 127.0.0.1 in a network context or Oracle's bequath database connection). You'll then receive the same data you send out.

 

Goal: Listen to  a CAN bus and only pick up messages I'm interested in

 

A CAN bus in a a car can (sic) be busy. A lot of information and commands are on there continuously.

And every node in the network receives all that data. It isn't routed.

You could try and parse the interesting messages out in your software. It works but is compute- and I/O-intensive.

Luckily, CAN hardware modules typically have a method to filter out desired message scope.

 

Let's pretend that our Linux module is a rear view camera.

When the car is put in reverse, the camera should switch on, and the video signal has to be overlaid on the dashboard display.

Putting the car in reverse generates a known message on the CAN bus.

So we can either listen to the CAN bus, and react if we recognise that the message is "car in reverse".

Or we can program our Linux module, so that we only get messages that are related to "car in reverse" events.

And that's the goal. Setting up that filter so that our Linux OS is freed of the burden of listening and filtering.

 

Filter and Mask

 

The solution that's used in CAN peripherals is to support sets of filters and masks.

A CAN message starts with an ID, then a count of the payload bytes, then the payload.

The filter and mask work on the ID.

  • the filter defines what messages to listen for.
  • the mask defines what bits in the filter have to match, and which ones can be ignored.

 

Let's pretend that all messages related to "car in reverse" are in the range 0x550 -> 0x55F.

We can set our filter as 0x550 and mask to 0xFF0.

In binary:

0b010101010000

0b111111110000

The CAN peripheral only watches for IDs where the relevant bits match the filter.

0b01010101****

Any message with ID between 0b010101010000 and 0b010101011111 will be passed to Linux.

That's what we wanted. Any message in the range 0x550 -> 0x55F.

 

The code looks like this:

 

  struct can_filter rfilter[1];

  rfilter[0].can_id   = 0x550;
  rfilter[0].can_mask = 0xFF0;
  setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));

  nbytes = read(s, &frame, sizeof(struct can_frame));

  if (nbytes < 0) {
    perror("Read");
    return 1;
  }

  printf("0x%03X [%d] ",frame.can_id, frame.can_dlc);

  for (i = 0; i < frame.can_dlc; i++)
    printf("%02X ",frame.data[i]);

 

The code will be sitting and waiting on line 07 until a message within range arrives.

image

A message passed through the filter. Click to enlarge.

 

Multiple Filters

 

There will be cases where you want to react on several ranges or IDs. The number of filters is dependent on the CAN IC and the Linux driver/

The MCP2515 that's used in the majority of Raspberry Pi and Arduino designs, can handle six filters and two masks.

I haven't checked what the Linux driver does with that. Let's leave that as an exercise for the reader.

As indicated by Craig (see a link to his blog at the end of this article), the current Linux driver doesn't use the IC's filtering capabilities and performs filtering in the driver code.

Here's Craig's same example, modified for two sets of filters:

 

struct can_filter rfilter[2];

rfilter[0].can_id   = 0x550;
rfilter[0].can_mask = 0xFF0;
rfilter[1].can_id   = 0x200;
rfilter[1].can_mask = 0x700;

 

The rest of the code is identical.

It will still listen to the 0x550 -> 0x55F range.

In addition, it will also send the payload to Linux when messages in this range appear on the bus:

Filter 0x200 and mask to 0x700.

In binary:

0b001000000000

0b011100000000

The CAN peripheral only watches for IDs where the relevant bits match the filter.

0b*010********

You'll receive any message that matches that filter.

0x200 matches. But also e.g. 0xAFF.

It may seem an odd combination, but in a typical context, CAN message IDs are chosen/grouped based on this kind of capability.

 

Read Craig's blog: https://www.beyondlogic.org/category/can-controller-area-network/.

 

Related Blog
Industrial I/O
Use the Industrial I/O
Control Industrial I/O directly from GPIO Pins
C Program for the Industrial I/O
Control Industrial I/O directly from Node-RED
Display Industrial I/O on Node-RED Dashboard
CAN Bus
Use the Isolated CAN
CAN programming in C on Linux: Filter and Mask
2020 Linux Image
The 2020 Linux Image and IoTConnect Scripts
Understand the Custom Scripts and Services (Pt. 1: intro and reset button service)
Understand the Custom Scripts and Services (Pt. 2: led service)
Understand the Custom Scripts and Services (Pt. 3: IoT Connect service)
  • Sign in to reply

Top Comments

  • DAB
    DAB over 4 years ago +1
    Good job Jan. DAB
  • DAB
    DAB over 4 years ago

    Good job Jan.

     

    DAB

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube