-
-
Save reinzor/6659f260c9e9a5db8fe5 to your computer and use it in GitHub Desktop.
Decode CAN signals
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdint.h> //uint typedefinitions, non-rtw! | |
#include <iostream> | |
#define MASK64(nbits) ((0xffffffffffffffff)>> (64-nbits)) | |
inline float toPhysicalValue(uint64_t target, float factor, float offset, bool is_signed) | |
{ | |
if (is_signed) | |
return ( (int64_t) target ) * factor + offset; | |
else | |
return target * factor + offset; | |
} | |
inline uint64_t fromPhysicalValue(float physical_value, float factor, float offset) | |
{ | |
return (physical_value - offset) / factor; | |
} | |
void storeSignal(uint8_t* frame, uint64_t value, const uint8_t startbit, const uint8_t length, bool is_big_endian, bool is_signed) | |
{ | |
uint8_t start_byte = startbit / 8; | |
uint8_t startbit_in_byte = startbit % 8; | |
uint8_t end_byte = 0; | |
int8_t count = 0; | |
uint8_t current_target_length = (8-startbit_in_byte); | |
//! TODO: Deal with sign | |
if (is_signed) | |
{ | |
// perform sign extension | |
// update value | |
} | |
value &= MASK64(length); | |
frame[start_byte] |= value >> startbit_in_byte; | |
if(is_big_endian) // Motorola (big endian) | |
{ | |
end_byte = (start_byte * 8 + 8 - startbit_in_byte - length) / 8; | |
for(count = start_byte-1; count >= end_byte; count --) | |
{ | |
frame[count] |= value << current_target_length; | |
current_target_length += 8; | |
} | |
} | |
else // Intel (little endian) | |
{ | |
end_byte = (startbit + length - 1) / 8; | |
for(count = start_byte+1; count <= end_byte; count ++) | |
{ | |
frame[count] |= value << current_target_length; | |
current_target_length += 8; | |
} | |
} | |
} | |
inline uint64_t extractSignal(const uint8_t* frame, const uint8_t startbit, const uint8_t length, bool is_big_endian, bool is_signed) | |
{ | |
uint8_t start_byte = startbit / 8; | |
uint8_t startbit_in_byte = startbit % 8; | |
uint8_t end_byte = 0; | |
int8_t count = 0; | |
uint64_t target = frame[start_byte] >> startbit_in_byte; | |
uint8_t current_target_length = (8-startbit_in_byte); | |
if(is_big_endian) // Motorola (big endian) | |
{ | |
end_byte = (start_byte * 8 + 8 - startbit_in_byte - length) / 8; | |
for(count = start_byte-1; count >= end_byte; count --) | |
{ | |
target |= frame[count] << current_target_length; | |
current_target_length += 8; | |
} | |
} | |
else // Intel (little endian) | |
{ | |
end_byte = (startbit + length) / 8; | |
for(count = start_byte+1; count <= end_byte; count ++) | |
{ | |
target |= frame[count] << current_target_length; | |
current_target_length += 8; | |
} | |
} | |
target &= MASK64(length); | |
if (is_signed) | |
{ | |
// perform sign extension | |
int64_t msb_sign_mask = 1 << (length - 1); | |
target = ( (int32_t) target ^ msb_sign_mask) - msb_sign_mask; | |
} | |
return target; | |
} | |
inline float decode(const uint8_t* frame, const uint16_t startbit, const uint16_t length, bool is_big_endian, bool is_signed, float factor, float offset) | |
{ | |
return toPhysicalValue(extractSignal(frame, startbit, length, is_big_endian, is_signed), factor, offset, is_signed); | |
} | |
void test(uint8_t* frame, uint8_t startbit, uint8_t length, bool is_big_endian, bool is_signed, float factor, float offset, uint32_t int_value, float value) | |
{ | |
std::cout << "\n---- (startbit=" << (int) startbit << ",length=" << (int) length << ",is_big_endian=" << is_big_endian << ",is_signed=" << is_signed << ",factor=" << factor << ",offset=" << offset << ")" << std::endl; | |
std::cout << "Unsigned int value: " << extractSignal(frame, startbit, length, is_big_endian, is_signed) << " should be " << int_value << std::endl; | |
std::cout << "Physical value: " << decode(frame, startbit, length, is_big_endian, is_signed, factor, offset) << " should be " << value << std::endl; | |
} | |
int main(void) | |
{ | |
{ | |
uint8_t src_array[8] = {48, 48, 48, 48, 225, 127, 202, 139}; | |
test(src_array, 34, 2, true, false, 1.000000, 0, 0, 0.000000); | |
test(src_array, 40, 8, false, false, 0.010000, 0, 127, 1.270000); | |
test(src_array, 32, 1, false, false, 1.000000, 0, 1, 1.000000); | |
test(src_array, 16, 16, false, false, 0.003906, 0, 12336, 48.187500); | |
test(src_array, 0, 16, false, false, 0.000977, -31, 12336, -19.952148); | |
} | |
{ | |
uint8_t src_array[8] = {13, 27, 78, 68, 254, 139, 13, 147}; | |
test(src_array, 0, 2, true, false, 1.000000, 0, 1, 1.000000); | |
test(src_array, 2, 6, true, false, 1.000000, 0, 3, 3.000000); | |
test(src_array, 21, 11, true, false, 0.100000, 0, 218, 21.800000); | |
test(src_array, 25, 12, true, false, 0.062500, -128, 1826, -13.875000); | |
test(src_array, 32, 9, true, false, 0.062500, -16, 254, -0.125000); | |
test(src_array, 48, 3, true, false, 1.000000, 0, 5, 5.000000); | |
test(src_array, 51, 3, true, false, 1.000000, 0, 1, 1.000000); | |
test(src_array, 54, 10, true, false, 0.100000, -52, 556, 3.600000); | |
test(src_array, 56, 3, true, false, 1.000000, 0, 3, 3.000000); | |
test(src_array, 59, 3, true, false, 1.000000, 0, 2, 2.000000); | |
test(src_array, 62, 2, true, false, 1.000000, 0, 2, 2.000000); | |
} | |
return 0; | |
} |
@ebroeker; we could also set up a new repo for this and refer from the canmatrix repo to this repo?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
encoding is done in my gist - maybe you could have a look on it