Skip to content

Commit 56df49c

Browse files
committed
implement a multiFilter function for the MCP2515 which allows to filter for multiple can ids (standard only for now)
1 parent bcdd7ac commit 56df49c

File tree

4 files changed

+136
-0
lines changed

4 files changed

+136
-0
lines changed

src/CANController.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,11 @@ int CANControllerClass::filterExtended(long /*id*/, long /*mask*/)
195195
return 0;
196196
}
197197

198+
int CANControllerClass::multiFilter(int * /*ids*/, unsigned /*mask*/)
199+
{
200+
return 0;
201+
}
202+
198203
int CANControllerClass::observe()
199204
{
200205
return 0;

src/CANController.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ class CANControllerClass : public Stream {
3939
virtual int filterExtended(long id) { return filterExtended(id, 0x1fffffff); }
4040
virtual int filterExtended(long id, long mask);
4141

42+
virtual int multiFilter(int *ids, unsigned count);
43+
4244
virtual int observe();
4345
virtual int loopback();
4446
virtual int sleep();

src/MCP2515.cpp

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,133 @@ int MCP2515Class::filter(int id, int mask)
313313
return 1;
314314
}
315315

316+
unsigned char hammingDistance(int x, int y)
317+
{
318+
unsigned char distance = 0;
319+
int xorXY = x ^ y;
320+
321+
for(int i = 0; i < 8 * sizeof(int); i++) {
322+
if(xorXY & (1 << i))
323+
distance++;
324+
}
325+
326+
return distance;
327+
}
328+
329+
int MCP2515Class::multiFilter(int *ids, unsigned count)
330+
{
331+
long filterMasks[2];
332+
long filterIds[6];
333+
334+
if(count <= 6) {
335+
// the MCP2515 has enough registers to filter all ids
336+
for (int n = 0; n < 2; n++)
337+
filterMasks[n] = 0x7ff;
338+
339+
for (int n = 0; n < 6; n++) {
340+
if (n < count)
341+
filterIds[n] = ids[n];
342+
else
343+
filterIds[n] = 0;
344+
}
345+
}
346+
else {
347+
// we have more ids than filters, we find the two most distant ids and use
348+
// them as base for anding together all other ids
349+
unsigned char maxDistance = 0;
350+
351+
for(int i = 0; i < count; i++) {
352+
for(int j = i; j < count; j++) {
353+
unsigned char distance = hammingDistance(ids[i], ids[j]);
354+
355+
if(distance > maxDistance) {
356+
filterIds[0] = ids[i];
357+
filterIds[2] = ids[j];
358+
maxDistance = distance;
359+
}
360+
}
361+
}
362+
363+
filterMasks[0] = 0x7ff;
364+
filterMasks[1] = 0x7ff;
365+
filterIds[1] = 0;
366+
filterIds[3] = 0;
367+
filterIds[4] = 0;
368+
filterIds[5] = 0;
369+
370+
for(int i = 0; i < count; i++) {
371+
unsigned char distance0 = hammingDistance(ids[i], filterMasks[0]);
372+
unsigned char distance1 = hammingDistance(ids[i], filterMasks[1]);
373+
374+
#if 0
375+
Serial.print("id ");
376+
Serial.print(ids[i]);
377+
Serial.print(" distance0: ");
378+
Serial.print(distance0);
379+
Serial.print(" distance1: ");
380+
Serial.print(distance1);
381+
Serial.println();
382+
#endif
383+
384+
if(distance0 < distance1) {
385+
filterMasks[0] = filterMasks[0] & ~(filterIds[0] ^ ids[i]);
386+
filterIds[0] &= ids[i];
387+
}
388+
else {
389+
filterMasks[1] = filterMasks[1] & ~(filterIds[2] ^ ids[i]);
390+
filterIds[2] &= ids[i];
391+
}
392+
}
393+
394+
#if 0
395+
Serial.print("filterMasks[0] = ");
396+
Serial.print(filterMasks[0], 16);
397+
Serial.print(" filterIds[0] = ");
398+
Serial.println(filterIds[0], 16);
399+
400+
Serial.print("filterMasks[1] = ");
401+
Serial.print(filterMasks[1], 16);
402+
Serial.print(" filterIds[2] = ");
403+
Serial.println(filterIds[2], 16);
404+
#endif
405+
}
406+
407+
408+
409+
// config mode
410+
writeRegister(REG_CANCTRL, 0x80);
411+
if (readRegister(REG_CANCTRL) != 0x80) {
412+
return 0;
413+
}
414+
415+
for (int n = 0; n < 2; n++) {
416+
// for now standard only (TODO: extended)
417+
writeRegister(REG_RXBnCTRL(n), FLAG_RXM0);
418+
writeRegister(REG_RXBnCTRL(n), FLAG_RXM0);
419+
420+
writeRegister(REG_RXMnSIDH(n), filterMasks[n] >> 3);
421+
writeRegister(REG_RXMnSIDL(n), filterMasks[n] << 5);
422+
writeRegister(REG_RXMnEID8(n), 0);
423+
writeRegister(REG_RXMnEID0(n), 0);
424+
}
425+
426+
for (int n = 0; n < 6; n++) {
427+
writeRegister(REG_RXFnSIDH(n), filterIds[n] >> 3);
428+
writeRegister(REG_RXFnSIDL(n), filterIds[n] << 5);
429+
430+
writeRegister(REG_RXFnEID8(n), 0);
431+
writeRegister(REG_RXFnEID0(n), 0);
432+
}
433+
434+
// normal mode
435+
writeRegister(REG_CANCTRL, 0x00);
436+
if (readRegister(REG_CANCTRL) != 0x00) {
437+
return 0;
438+
}
439+
440+
return 1;
441+
}
442+
316443
int MCP2515Class::filterExtended(long id, long mask)
317444
{
318445
id &= 0x1FFFFFFF;

src/MCP2515.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ class MCP2515Class : public CANControllerClass {
4040
virtual int filter(int id, int mask);
4141
using CANControllerClass::filterExtended;
4242
virtual int filterExtended(long id, long mask);
43+
using CANControllerClass::multiFilter;
44+
virtual int multiFilter(int *ids, unsigned count);
4345

4446
virtual int observe();
4547
virtual int loopback();

0 commit comments

Comments
 (0)