Reputation: 81
I'm trying to read the linFrame sent from a slave LIN node, to identify when a particular bit has changed from from zero to one.
I'm sending a LIN message to a slave servo that commands it to move beyond a physical end-stop.
Once it physically hits the end-stop, its status message will set a single bit from zero to one. That bit identifies when the servo motor has stalled. My goal is to have the CAPL script detect that the motor has stalled.
My command message is sent by my CAPL script using the "output()" function. I'm unsure which function can read the response, but I think I have to send a header for the response message and then read the response frame.
variables
{
linFrame 0x03 ACT_CTRL_MT3 = {msgChannel=1}; // actuator control command
linFrame 0x21 ACT_STA_MT3 = {msgChannel=1}; // actuator status response
mstimer timer1;
}
on key 'c'
{
// command large angular position from servo at node 3
ACT_CTRL_MT3.RTR = 0;
ACT_CTRL_MT3.byte(0)=0x12; // section 4.5.9 of manual
ACT_CTRL_MT3.byte(1)=0xE4;
ACT_CTRL_MT3.byte(2)=0x14;
ACT_CTRL_MT3.byte(3)=0xFE; // max angle
ACT_CTRL_MT3.byte(4)=0xFF; // max angle
ACT_CTRL_MT3.byte(5)=0x00;
ACT_CTRL_MT3.byte(6)=0x00;
ACT_CTRL_MT3.byte(7)=0x40;
output(ACT_CTRL_MT3); // update command payload
// Send the frame header
ACT_CTRL_MT3.RTR = 1;
output(ACT_CTRL_MT3);
settimer(timer1,5000); // wait 5 seconds for motor to move
}
on timer timer1{
//send header of status message
ACT_STA_MT3.RTR = 1;
output(ACT_STA_MT3);
write("Reading message...");
//output message context
writelineex(1,1,"FrameId=%d Length=%d, 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X;", ACT_STA_MT3.ID, ACT_STA_MT3.DLC,
ACT_STA_MT3.byte(0), ACT_STA_MT3.byte(1), ACT_STA_MT3.byte(2), ACT_STA_MT3.byte(3), ACT_STA_MT3.byte(4), ACT_STA_MT3.byte(5), ACT_STA_MT3.byte(6), ACT_STA_MT3.byte(7));
}
The data that is written by the "writelinee" function is very different from the values seen in my LIN trace window in CANalyzer.
I find it especially strange that the ID field written out is different from the ID set in the variables section at the start of the code. In the code I define the frame ID of that status message as 0x21, but the write command gives a different value (0x35 I believe, although I'm away from my setup at the moment.
Upvotes: 2
Views: 6142
Reputation: 171
About @Maciek answer, it actually works. Interessting to see that if you have your .ldf file in the "ldf explorer" by Vector with the correct signals assigned, then you could replace on linframe <frame>
by on signal <any signal>
.
The main difference is that linframe receives all the bytes, so you must use masks as @Maciek did here if (this.byte(0) & 0x01)
which basically checks the first bit of the first byte. On the other hand, if you had a signal called e.g MyAlarmSignal which was defined in the .ldf file as the first bit of the frame, then you could simply read the signal using on signal MyAlarmSignal
and inside the handler use $MyAlarmSignal
or simply this
to get the value.
Upvotes: 1
Reputation: 590
Unfortunately I do not have CANoe licence so I cannot check my code is functional. I have done similar thinkgs many times, so we should be good.
As I notices from your description you need to do there 3 things:
Send control LIN frame (ID 0x03) with some data to start the motor.
Send status LIN headers (ID 0x21) - remember that LIN Slave cannot initiate transmission on LIN bus so you need to provice LIN headers so LIN Slave can respond with some data.
Get response data from LIN header (data added by LIN slave to LIN header 0x21) - informs about motor stalling.
This is small modification to the code that you provided before. I also marked which things can be done in a different ways (you know CANoe have many features):
variables
{
linFrame 0x03 ACT_CTRL_MT3 = {msgChannel=1}; // actuator control command
linFrame 0x21 ACT_STA_MT3 = {msgChannel=1}; // actuator status response
mstimer timer1;
}
// starts the fun
on key 'c'
{
ACT_CTRL_MT3.RTR = 1; // RTR=1 means that you want to send entire message (header + data)
ACT_CTRL_MT3.byte(0)=0x12;
ACT_CTRL_MT3.byte(1)=0xE4;
ACT_CTRL_MT3.byte(2)=0x14;
ACT_CTRL_MT3.byte(3)=0xFE;
ACT_CTRL_MT3.byte(4)=0xFF;
ACT_CTRL_MT3.byte(5)=0x00;
ACT_CTRL_MT3.byte(6)=0x00;
ACT_CTRL_MT3.byte(7)=0x40;
output(ACT_CTRL_MT3); // this sends the message to the bus
settimer(timer1, 20); // set timer to trigger actions in 20 ms
}
// sending LIN headers (ID 0x21) cyclically
on timer timer1
{
// sends a single LIN header - you can also try to do it this way:
// ACT_STA_MT3.RTR=0;
// output(ACT_STA_MT3);
linTransmitHeader(ACT_STA_MT3); // or linTransmitHeader(0x21);
//set timer again to let LIN Slave respond if stalled later on
settimer(timer1, 20); // reset to execute every 20 ms
}
// event on receiving entire frame (header + response data) from LIN Slave
on linFrame ACT_STA_MT3
{
// not sure where is located your bit that is informing about stalling of the motor, but in this example I assumed it is on first position of byte 0
if (this.byte(0) & 0x01)
{
// you can put some other instructions here
write("Motor has stalled!");
}
// you can also log entire frame (I think your code was fine so I copied it):
writelineex(1,1,"FrameId=%d Length=%d, 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X;", this.ID, this.DLC, this.byte(0), this.byte(1), this.byte(2), this.byte(3), this.byte(4), this.byte(5), this.byte(6), this.byte(7));
}
PS. Try this and let me know if it compiles and works as expected as I literally wrote it in notepad. I will help you to fix potential errors.
Upvotes: 1