If I use the code below to receive a J1939 can message, is the data available in the same cycle where the Receive is set to true or in the following cycle?
fb_receive_patrol_f_shm(MpLink := ADR(gJ1939Receive_patrol_shm),
Enable := TRUE,
PGN := 3584,
Priority := 3,
Data := ADR(pgn_data_raw_shm),
DataLength := 8);
IF NOT fb_receive_patrol_f_shm.CommandDone AND
NOT fb_receive_patrol_f_shm.CommandBusy AND
fb_receive_patrol_f_shm.Active AND
NOT fb_receive_patrol_f_shm.Error THEN
fb_receive_patrol_f_shm.Receive := TRUE;
ELSE
fb_receive_patrol_f_shm.Receive := FALSE;
END_IF;
This code calls the function block once at the beginning. The inputs and outputs are processed when the function block is called, so there is no way for the data to update in the same cycle that Receive is set.
However, from the MpJ1939Receive documentation:
The requested information is indicated via the positive edge input parameter “Receive” = TRUE on parameter “Data”. Output “CommandDone” set to TRUE indicates that the command was successful. This means that every positive edge at “Receive” requests the information at the specified PGN
The function block works asynchronously and so you must wait for CommandDone to be true to know that the data has been processed.
I now use a cycle time that is shorter than the cycle time of the CAN messages that I want to receive. Then I use the CommandDone output and only process the data when this is set to true. There is one case where the CAN messages are send every 45 ms. I use this solution for that:
PROGRAM _CYCLIC
fb_receive_patrol_e_stop(MpLink := ADR(gJ1939Receive_patrol_e_stop),
Enable := TRUE,
PGN := 64982,
Priority := 3,
Data := ADR(pgn_data_raw_e_stop),
DataLength := 8);
IF g_cycle_counter_patrol_f < 5 THEN
fb_receive_patrol_e_stop.Receive := TRUE;
ELSE
fb_receive_patrol_e_stop.Receive := FALSE;
END_IF;
IF fb_receive_patrol_e_stop.CommandDone THEN
// process the data
END_IF;
g_cycle_counter_patrol_f := (g_cycle_counter_patrol_f + 1) MOD 8;
This program runs with a cycle time of 5ms, hence the counter with MOD 8 to get to 45 ms.
Not sure if this is the most elegant solution but the connection is stable
just a heads up: Making your task dependent on the task class it’s in is usually prone to errors since either a future you or a colleague will not know/remember that dependency and either change task class times or move tasks around - at which time the whole thing breaks.
I recommend setting the Receive input, waiting for the CommandDone and then act depending on the content of “ReceivedBytes” - either you received something, then you process the data, or you didn’t, then you reset “Receive” for one cycle and repeat
PROGRAM _CYCLIC
fb_receive_patrol_e_stop(MpLink := ADR(gJ1939Receive_patrol_e_stop),
Enable := TRUE,
PGN := 64982,
Priority := 3,
Data := ADR(pgn_data_raw_e_stop),
DataLength := 8);
fb_receive_patrol_e_stop.Receive := TRUE;
IF fb_receive_patrol_e_stop.CommandDone THEN
fb_receive_patrol_e_stop.Receive := FALSE;
IF fb_receive_patrol_e_stop.ReceivedBytes > 0 THEN
// process the data
END_IF
END_IF
That way you set the receive more often than “required” but even then, your code reacts as soon as data is available and you’re good to go. As long as you call this task faster than two different frames arrive (so faster than 45ms in this case), this code should work.
Obligatory disclaimer: I have not used this FUB myself before but I assume “no data” doesn’t trigger errors (and the documentation doesn’t say so)
This might be more resilient to changes and also works for other PGNs that arrive at different timings, etc…