I'm trying to manipulate a CAN signal using C (with a PCAN Router interface).
What the program does is waits for a CAN specific frame like 0x1F0 and then modify some bits. The bits I want to modify is based on a DBC file. So im trying to make it more dynamically by using cantools to generate a source code a .h & .c file based on a DBC file here it's an example motohawk.h and motohawk.c.
Link to the motor DBC file.
What I wish is to be able to manipulate a signal somehow like this.
So the question is how do I use the source to manipulate a signal signal? for example the Temperature signal? Maybe I'm seeing it wrong and it's not possible to do what I wish to.
Frame from DBC:
BO_ 496 ExampleMessage: 8 PCM1
SG_ Temperature : 0|12@0- (0.01,250) [229.52|270.47] "degK" PCM1,FOO
SG_ AverageRadius : 6|6@0+ (0.1,0) [0|5] "m" Vector__XXX
SG_ Enable : 7|1@0+ (1,0) [0|0] "-" Vector__XXX
What I want to do is to have a struct similar to this:
struct motohawk_example_message_t {
/**
* Range: -
* Scale: 1
* Offset: 0
*/
uint8_t enable;
/**
* Range: 0..50 (0..5 m)
* Scale: 0.1
* Offset: 0
*/
uint8_t average_radius;
/**
* Range: -2048..2047 (229.52..270.47 degK)
* Scale: 0.01
* Offset: 250
*/
int16_t temperature;
};
but I would like to have a possibility to use something like:
frame_1F0 = motohawk_example_message_t();
frame_1F0.temperature.value = 255.01;
the frame_1F0.temperature.value will populate the correct bit/bytes in the frame (in the PCAN is something like TxMsg.Data16[index] = some hex value). Has somebody done it? or do you know if it's possible to use the source generated by the cantools package to do it?
Here is the PCAN code
frame_1F0 = motohawk_example_message_t();
while (1)
{
CANMsg_t RxMsg, TxMsg;
// process messages from CAN1
if ( CAN_UserRead ( CAN_BUS1, &RxMsg) != 0)
{
// message received from CAN1
// catch ID 1F0h from CAN1 to modify data
if ( RxMsg.Id == 0x1F0)
{
RxMsg.Id = 0x1E4;
RxMsg.Type = CAN_MSG_STANDARD;
}
// copy message
TxMsg.Id = RxMsg.Id;
TxMsg.Type = RxMsg.Type;
TxMsg.Len = RxMsg.Len;
frame_1F0.temperature.value = 255.01; // this should be TxMsg.Data[xxx] = 255.01. THIS is the hard part :/
// send
CAN_UserWrite ( CAN_BUS2, &TxMsg);
...
The code generated with cantools can be used to convert the binary data to structs where you can access the signals and vice versa.
In your case something like this should work
...
CANMsg_t RxMsg, TxMsg;
struct motohawk_example_message_t frame_1F0;
motohawk_example_message_unpack(&frame_1F0, RxMsg.Data.Data8, RxMsg.Len);
int16_t encoded_temperature = motohawk_example_message_temperature_encode(255.01);
frame_1F0.temperature.value = encoded_temperature;
motohawk_example_message_pack(TxMsg.Data.Data8, &frame_1F0, TxMsg.Len);
...
Typing this of the top of my head. The code may not compile out-of-the-box but I hope it helps to get the idea.
In the generated source code, the _pack
and _unpack
functions can be used to convert from _message
struct to binary data and back.
The _encode
and _decode
functions are used to convert the signals from their physical representation to their raw representation and back.