Skip to content

Commit

Permalink
VW MQB: Refactored CRC calculation (commaai#1236)
Browse files Browse the repository at this point in the history
* VW MQB: Refactor CRC constants

Big switch statement in volkswagen_mqb_checksum was refactored with map of arrays.
With this approach there's no need for specifying all 16 byte values if constant is the same for all of them.

* temporary, repeat packing step 1M times

* follow comma convention for include order

* comma indent convention, tighten message annotations

* whitespace

* cleanup

* more comma indent convention

* Revert "temporary, repeat packing step 1M times"

This reverts commit 06d8f46.

* comment touch-up

* beautify spacing

* codespell says you're gonna have to Google it

* fully initialize all data ID arrays

* clarify array name as part of VW support

* fix comment typo

---------

Co-authored-by: Jason Young <jyoung8607@gmail.com>
  • Loading branch information
JaCzekanski and jyoung8607 authored Sep 13, 2024
1 parent 2b85882 commit 0994697
Showing 1 changed file with 35 additions and 69 deletions.
104 changes: 35 additions & 69 deletions opendbc/can/common.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "opendbc/can/common.h"
#include <array>
#include <unordered_map>

#include "opendbc/can/common.h"

unsigned int honda_checksum(uint32_t address, const Signal &sig, const std::vector<uint8_t> &d) {
int s = 0;
Expand Down Expand Up @@ -112,85 +114,49 @@ struct CrcInitializer {

static CrcInitializer crcInitializer;

static const std::unordered_map<uint32_t, std::array<uint8_t, 16>> volkswagen_mqb_crc_constants {
{0x86, {0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86}}, // LWI_01
{0x9F, {0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5}}, // LH_EPS_03
{0xAD, {0x3F, 0x69, 0x39, 0xDC, 0x94, 0xF9, 0x14, 0x64, 0xD8, 0x6A, 0x34, 0xCE, 0xA2, 0x55, 0xB5, 0x2C}}, // Getriebe_11
{0xFD, {0xB4, 0xEF, 0xF8, 0x49, 0x1E, 0xE5, 0xC2, 0xC0, 0x97, 0x19, 0x3C, 0xC9, 0xF1, 0x98, 0xD6, 0x61}}, // ESP_21
{0x106, {0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07}}, // ESP_05
{0x117, {0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16}}, // ACC_10
{0x120, {0xC4, 0xE2, 0x4F, 0xE4, 0xF8, 0x2F, 0x56, 0x81, 0x9F, 0xE5, 0x83, 0x44, 0x05, 0x3F, 0x97, 0xDF}}, // TSK_06
{0x121, {0xE9, 0x65, 0xAE, 0x6B, 0x7B, 0x35, 0xE5, 0x5F, 0x4E, 0xC7, 0x86, 0xA2, 0xBB, 0xDD, 0xEB, 0xB4}}, // Motor_20
{0x122, {0x37, 0x7D, 0xF3, 0xA9, 0x18, 0x46, 0x6D, 0x4D, 0x3D, 0x71, 0x92, 0x9C, 0xE5, 0x32, 0x10, 0xB9}}, // ACC_06
{0x126, {0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA}}, // HCA_01
{0x12B, {0x6A, 0x38, 0xB4, 0x27, 0x22, 0xEF, 0xE1, 0xBB, 0xF8, 0x80, 0x84, 0x49, 0xC7, 0x9E, 0x1E, 0x2B}}, // GRA_ACC_01
{0x12E, {0xF8, 0xE5, 0x97, 0xC9, 0xD6, 0x07, 0x47, 0x21, 0x66, 0xDD, 0xCF, 0x6F, 0xA1, 0x94, 0x74, 0x63}}, // ACC_07
{0x187, {0x7F, 0xED, 0x17, 0xC2, 0x7C, 0xEB, 0x44, 0x21, 0x01, 0xFA, 0xDB, 0x15, 0x4A, 0x6B, 0x23, 0x05}}, // Motor_EV_01
{0x30C, {0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F}}, // ACC_02
{0x30F, {0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C}}, // SWA_01
{0x324, {0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27}}, // ACC_04
{0x3C0, {0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3}}, // Klemmen_Status_01
{0x65D, {0xAC, 0xB3, 0xAB, 0xEB, 0x7A, 0xE1, 0x3B, 0xF7, 0x73, 0xBA, 0x7C, 0x9E, 0x06, 0x5F, 0x02, 0xD9}}, // ESP_20
};

unsigned int volkswagen_mqb_checksum(uint32_t address, const Signal &sig, const std::vector<uint8_t> &d) {
// Volkswagen uses standard CRC8 8H2F/AUTOSAR, but they compute it with
// a magic variable padding byte tacked onto the end of the payload.
// https://www.autosar.org/fileadmin/user_upload/standards/classic/4-3/AUTOSAR_SWS_CRCLibrary.pdf
// This is AUTOSAR E2E Profile 2, CRC-8H2F with a "data ID" (varying by message/counter) appended to the payload

uint8_t crc = 0xFF; // Standard init value for CRC8 8H2F/AUTOSAR
uint8_t crc = 0xFF; // CRC-8H2F initial value

// CRC the payload first, skipping over the first byte where the CRC lives.
// CRC over payload first, skipping the first byte where the CRC lives
for (int i = 1; i < d.size(); i++) {
crc ^= d[i];
crc = crc8_lut_8h2f[crc];
}

// Look up and apply the magic final CRC padding byte, which permutes by CAN
// address, and additionally (for SOME addresses) by the message counter.
// Continue CRC over the "data ID"
uint8_t counter = d[1] & 0x0F;
switch (address) {
case 0x86: // LWI_01 Steering Angle
crc ^= (uint8_t[]){0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86}[counter];
break;
case 0x9F: // LH_EPS_03 Electric Power Steering
crc ^= (uint8_t[]){0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5}[counter];
break;
case 0xAD: // Getriebe_11 Automatic Gearbox
crc ^= (uint8_t[]){0x3F, 0x69, 0x39, 0xDC, 0x94, 0xF9, 0x14, 0x64, 0xD8, 0x6A, 0x34, 0xCE, 0xA2, 0x55, 0xB5, 0x2C}[counter];
break;
case 0xFD: // ESP_21 Electronic Stability Program
crc ^= (uint8_t[]){0xB4, 0xEF, 0xF8, 0x49, 0x1E, 0xE5, 0xC2, 0xC0, 0x97, 0x19, 0x3C, 0xC9, 0xF1, 0x98, 0xD6, 0x61}[counter];
break;
case 0x106: // ESP_05 Electronic Stability Program
crc ^= (uint8_t[]){0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07}[counter];
break;
case 0x117: // ACC_10 Automatic Cruise Control
crc ^= (uint8_t[]){0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16}[counter];
break;
case 0x120: // TSK_06 Drivetrain Coordinator
crc ^= (uint8_t[]){0xC4, 0xE2, 0x4F, 0xE4, 0xF8, 0x2F, 0x56, 0x81, 0x9F, 0xE5, 0x83, 0x44, 0x05, 0x3F, 0x97, 0xDF}[counter];
break;
case 0x121: // Motor_20 Driver Throttle Inputs
crc ^= (uint8_t[]){0xE9, 0x65, 0xAE, 0x6B, 0x7B, 0x35, 0xE5, 0x5F, 0x4E, 0xC7, 0x86, 0xA2, 0xBB, 0xDD, 0xEB, 0xB4}[counter];
break;
case 0x122: // ACC_06 Automatic Cruise Control
crc ^= (uint8_t[]){0x37, 0x7D, 0xF3, 0xA9, 0x18, 0x46, 0x6D, 0x4D, 0x3D, 0x71, 0x92, 0x9C, 0xE5, 0x32, 0x10, 0xB9}[counter];
break;
case 0x126: // HCA_01 Heading Control Assist
crc ^= (uint8_t[]){0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA}[counter];
break;
case 0x12B: // GRA_ACC_01 Steering wheel controls for ACC
crc ^= (uint8_t[]){0x6A, 0x38, 0xB4, 0x27, 0x22, 0xEF, 0xE1, 0xBB, 0xF8, 0x80, 0x84, 0x49, 0xC7, 0x9E, 0x1E, 0x2B}[counter];
break;
case 0x12E: // ACC_07 Automatic Cruise Control
crc ^= (uint8_t[]){0xF8, 0xE5, 0x97, 0xC9, 0xD6, 0x07, 0x47, 0x21, 0x66, 0xDD, 0xCF, 0x6F, 0xA1, 0x94, 0x74, 0x63}[counter];
break;
case 0x187: // Motor_EV_01 gearshift position for BEVs with no transmission
crc ^= (uint8_t[]){0x7F, 0xED, 0x17, 0xC2, 0x7C, 0xEB, 0x44, 0x21, 0x01, 0xFA, 0xDB, 0x15, 0x4A, 0x6B, 0x23, 0x05}[counter];
break;
case 0x30C: // ACC_02 Automatic Cruise Control
crc ^= (uint8_t[]){0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F}[counter];
break;
case 0x30F: // SWA_01 Lane Change Assist (SpurWechselAssistent)
crc ^= (uint8_t[]){0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C}[counter];
break;
case 0x324: // ACC_04 Automatic Cruise Control
crc ^= (uint8_t[]){0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27}[counter];
break;
case 0x3C0: // Klemmen_Status_01 ignition and starting status
crc ^= (uint8_t[]){0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3}[counter];
break;
case 0x65D: // ESP_20 Electronic Stability Program
crc ^= (uint8_t[]){0xAC, 0xB3, 0xAB, 0xEB, 0x7A, 0xE1, 0x3B, 0xF7, 0x73, 0xBA, 0x7C, 0x9E, 0x06, 0x5F, 0x02, 0xD9}[counter];
break;
default: // As-yet undefined CAN message, CRC check expected to fail
printf("Attempt to CRC check undefined Volkswagen message 0x%02X\n", address);
crc ^= (uint8_t[]){0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}[counter];
break;
auto crc_const = volkswagen_mqb_crc_constants.find(address);
if (crc_const != volkswagen_mqb_crc_constants.end()) {
crc ^= crc_const->second[counter];
crc = crc8_lut_8h2f[crc];
} else {
printf("Attempt to CRC check undefined Volkswagen message 0x%02X\n", address);
}
crc = crc8_lut_8h2f[crc];

return crc ^ 0xFF; // Return after standard final XOR for CRC8 8H2F/AUTOSAR
return crc ^ 0xFF; // CRC-8H2F final XOR
}

unsigned int xor_checksum(uint32_t address, const Signal &sig, const std::vector<uint8_t> &d) {
Expand Down

0 comments on commit 0994697

Please sign in to comment.