Home » Eclipse Projects » Eclipse Titan » J1939 Synchronizing Parallel Test Components of different type(Parallel Test Component Synchronization)
J1939 Synchronizing Parallel Test Components of different type [message #1830322] |
Thu, 23 July 2020 10:50 |
Michael Josenhans Messages: 99 Registered: February 2016 |
Member |
|
|
I have parallel test components of diffent types. In the past there were only parallel test components of the same type, thus when iteraring over the parallel test components only a set of PTCs was used.
Now there are different PTCs , over which I want to iterate. Which these are depends on the test setup. Some test components may represent an Isobus ECU, some an Virtual Terminal and some are just timers, which when active e.g. cyclically send a keep alive message or test for reception of a keep alive message.
type record of PTC PTCSet
function f_addSyncSlaveSet (in PTC p_slave,
inout PTCSet p_set) {
p_set[sizeof(p_set)] := p_slave
return
}
function f_startPhase (in e_Phase p_phase) runs on MTC {
var integer v_i
var integer v_amount := sizeof(v_PTCSet)
var PhaseStartReq v_phaseStartReq := { phase := p_phase, phase_int := enum2int(p_phase)}
for (v_i := 0; v_i < v_amount; v_i := v_i +1){
log("MTC instance: ", self)
pt_sync.send(v_phaseStartReq) to v_PTCSet[v_i]
}
}
What I probally need is:
type record of PTCs PTCSet
type union PTCs{
PTC_type1 ptc_type1,
PTC_type2 ptc_type2,
PTC_type3 ptc_type3
}
Here the current test cases, with only the "PTC" type components synchronized:
testcase tc_can_j1939_IsobusVtEcuSimulation() runs on MTC {
// before running this test cases start the j1939 address claim deamons via commandline
/*
j1939acd -r 100,80-120 -c /tmp/1122334455667789.jacd 1122334455667789 vcan0
j1939acd -r 100,80-120 -c /tmp/1122334455667788.jacd 1122334455667788 vcan0
*/
var PTC v_ptc_J1939VTSocketIF := PTC.create("PTC1_ptc_j1939VTSocketIF") alive
var PTC v_ptc_J1939ECUSocketIF := PTC.create("PTC2_ptc_j1939ECUSocketIF") alive
f_addSyncSlaveSet(v_ptc_J1939VTSocketIF, v_PTCSet)
f_addSyncSlaveSet(v_ptc_J1939ECUSocketIF, v_PTCSet)
connect(mtc:pt_sync, v_ptc_J1939VTSocketIF:pt_sync)
connect(mtc:pt_sync, v_ptc_J1939ECUSocketIF:pt_sync)
var PTC_Isobus_VT_CT v_ptc_J1939VTApplication := PTC_Isobus_VT_CT.create("PTC1_ptc_j1939VTApplication") alive
var PTC_Isobus_VT_VTSTATUSCycle_CT v_ptc_J1939VT_VTStatusCycle := PTC_Isobus_VT_VTSTATUSCycle_CT.create("PTC_Isobis_VT_VTSTATUSCycle") alive
var PTC_Isobus_ECU_CT v_ptc_J1939ECUApplication := PTC_Isobus_ECU_CT.create("PTC2_ptc_j1939ECUApplication") alive
connect(v_ptc_J1939VTSocketIF:pt_j1939PDU, v_ptc_J1939VTApplication:pt_j1939PDU)
connect(v_ptc_J1939VT_VTStatusCycle:pt_VTStatusTick, v_ptc_J1939VTApplication:pt_VTStatusTick)
connect(v_ptc_J1939ECUSocketIF:pt_j1939PDU, v_ptc_J1939ECUApplication:pt_j1939PDU)
const integer c_send_prio := 2
const J1939_NAME c_name_VT := '1122334455667788'O
const J1939_NAME c_name_ECU := '1122334455667789'O
v_ptc_J1939VTSocketIF.start(f_ptc_J1939Agent(
e_testbody1,
c_send_prio,
c_name_VT)) /* name source */
v_ptc_J1939ECUSocketIF.start(f_ptc_J1939Agent(
e_testbody1,
c_send_prio,
c_name_ECU ))/* name source */
v_ptc_J1939VTApplication.start(f_ptc_J1939VTApplication());
v_ptc_J1939ECUApplication.start(f_ptc_J1939ECUApplication());
v_ptc_J1939VT_VTStatusCycle.start(f_ptc_J1939VTStatusCycle());
var e_Phase v_phase
for(v_phase := c_firstPhase; v_phase < e_testcase_complete;v_phase := f_incMTCPhase(v_phase)) {
f_startPhase(v_phase)
log("MTC: ", v_phase)
f_awaitEndPhase(v_phase)
}
all component.done;
log("MTC done")
disconnect(v_ptc_J1939VTSocketIF:pt_j1939PDU, v_ptc_J1939VTApplication:pt_j1939PDU)
disconnect(v_ptc_J1939ECUSocketIF:pt_j1939PDU, v_ptc_J1939ECUApplication:pt_j1939PDU)
all component.kill;
}
------ --------
|mtc |--------->| PTC |
| | --------
| | |
| | ----------
| |--------->| PTC VT |
| | ----------
| | |
| | --------------------
| |--------->| PTC VT keep alive|
| | --------------------
| | --------
| |--------->| PTC |
| | --------
| | |
| | ----------
| |--------->| PTC ECU |
| | ----------
| | |
| | -----------
| |--------->| PTC ... |
| | -----------
------
Or is it the case that usually only the first set of PTCs are synchronized by the MTC and the rest is created by the "PTC" components in order to encapsulate the test cases better.
|
|
|
Re: J1939 Synchronizing Parallel Test Components of different type [message #1830361 is a reply to message #1830322] |
Fri, 24 July 2020 07:23 |
|
Hi Michael,
I'll try to reformulate your question, just to make sure I understand it correctly.
So your question, as I understand it, is: "Is it a good practice to have the MTC create/start/synchronize all the other PTCs, or there are advantages of having some of the PTCs create/start /synchronize other PTCs?"
Although technically both scenarios are possible, I prefer the first one, namely having the MTC to play an orchestrator role among the components.
I see at least two advantages of this:
-simplicity ; I don't think I have to argument this extensively: both code and architecture is simpler
-legibility; It's simply easier to read what's going on as the test case executing on MTC offers a clear blueprint of execution ;
If PTCs create other PTCs etc. one has to check details of the functions started on each PTC to create a mental image of the architecture and figure out in which direction the system goes.
On the other hand I see no obvious advantage of the second scenario.
By the way, the mechanism you suggested is the right way of doing synchronization, namely using a simple start/stop protocol; I don't see the definition of f_awaitEndPhase() but I assume components are reporting
termination of execution via the internal synchronization port.
It may look sometimes tempting to use timers instead of synchronization by signals, but that is extremely risky, as it builds in assumptions regarding timing of the execution phases that may or may not be correct and sooner than later will prove wrong.
Best regards
Elemer
|
|
|
Re: J1939 Synchronizing Parallel Test Components of different type [message #1830365 is a reply to message #1830361] |
Fri, 24 July 2020 08:37 |
Michael Josenhans Messages: 99 Registered: February 2016 |
Member |
|
|
Hi Elemer,
thank you for reformulating this.
Before to decide on how to go forward, we have to agree on the way how to orchestrate the PTCs.
I agree with you, it is easier to take the first approach. Thus in the following it is assumed of having the MTC to play an orchestrator role among the parallel test components components.
My problem starts here. The orchestration code, which had been provided by you in the past, can only handle components of one component type. The component type is called "PTC". (see code above)
I need to efficiently handle components of the type "PTC" and of any other component types e.g. "PTC_Isobus_VT_CT", "PTC_Isobus_ECU_CT", etc.
However this is not possible with the current code. As the set of the components "v_PTCSet", which are orchestrated by the MTC is a set of components of the type "PTC"
type record of PTC PTCSet
and is unable to contain e.g. components of the type "PTC_Isobus_VT_CT".
This means:
- The following is possible:
var PTC v_ptc_J1939VTSocketIF := PTC.create("PTC1_ptc_j1939VTSocketIF") alive
f_addSyncSlaveSet(v_ptc_J1939VTSocketIF, v_PTCSet)
- however not this:
var PTC_Isobus_VT_CT v_ptc_J1939VTApplication := PTC_Isobus_VT_CT.create("PTC1_ptc_j1939VTApplication") alive
f_addSyncSlaveSet(v_ptc_J1939VTApplication , v_PTCSet)
What do I have to change in the MTC orchestration code, in order to orchestrate other components than components of the type "PTC" too?
Here should be now the whole MTC orchestration code:
const e_Phase c_firstPhase := e_open_socket
const e_Phase c_testcase_complete := e_testcase_complete
type record PhaseStartReq {
e_Phase phase,
integer phase_int
}
type record PhaseEndInd {
e_Phase phase,
integer phase_int
}
type port SyncMasterPort message {
out PhaseStartReq
in PhaseEndInd
} with { extension "internal" }
type port SyncSlavePort message {
in PhaseStartReq
out PhaseEndInd
} with { extension "internal" }
type port J1939PDU_PT message {
inout J1939PDU_with_NAME
} with { extension "internal" }
type boolean PoolUploadOngoing
type port PoolUploadOngoingIn message {
in PoolUploadOngoing
} with { extension "internal" }
type port PoolUploadOngoingOut message {
out PoolUploadOngoing
} with { extension "internal" }
type boolean VTStatusTick
type port VTStatusTickIn message {
in VTStatusTick
} with { extension "internal" }
type port VTStatusTickOut message {
out VTStatusTick
} with { extension "internal" }
type component PTC_Isobus_VT_VTSTATUSCycle_CT
{
port VTStatusTickOut pt_VTStatusTick
port PoolUploadOngoingIn pt_PoolUploadOngoing
//variables
//timers
}
type component PTC_Isobus_VT_CT
{
port J1939PDU_PT pt_j1939PDU
port VTStatusTickIn pt_VTStatusTick
//variables
//timers
}
type component PTC_Isobus_ECU_CT
{
port J1939PDU_PT pt_j1939PDU
//variables
//timers
}
type record of PTC PTCSet
type component PTC {
port SyncSlavePort pt_sync
port SocketCAN_PT pt_socketCAN
port J1939PDU_PT pt_j1939PDU
var e_Phase v_phase := c_firstPhase
}
//component declarations
type component MTC{
timer t_guard
port SyncMasterPort pt_sync
var PTCSet v_PTCSet := {}
}
altstep alt_awaitPhaseStartReq(in e_Phase p_phase) runs on PTC {
var PhaseStartReq v_PhaseStartReq;
[] pt_sync.receive (PhaseStartReq: {phase := p_phase, phase_int := ?}){
log("PTC name: ", self)
log("Waits for start of phase: ", p_phase)
}
// between v_phase and p_phase
[] pt_sync.receive (PhaseStartReq: {phase := ?, phase_int := (enum2int(c_firstPhase) .. enum2int(v_phase))}) -> value v_PhaseStartReq
{
//v_phase := f_incPhase(v_phase)
log("PTC name: ", self)
log("Waits for start of phase: ", p_phase)
log("Received completion of phase: ", p_phase)
f_sendPhaseEndInd()
repeat
}
[] pt_sync.receive (PhaseStartReq: {phase := ?, phase_int :=?}) -> value v_PhaseStartReq
{log("Received unexpected message:", v_PhaseStartReq);setverdict(inconc)}
}
function f_startPhase (in e_Phase p_phase) runs on MTC {
var integer v_i
var integer v_amount := sizeof(v_PTCSet)
var PhaseStartReq v_phaseStartReq := { phase := p_phase, phase_int := enum2int(p_phase)}
for (v_i := 0; v_i < v_amount; v_i := v_i +1){
log("MTC instance: ", self)
pt_sync.send(v_phaseStartReq) to v_PTCSet[v_i]
}
}
function f_incPTCPhase(in e_Phase p_currentPhase) runs on PTC return e_Phase {
var e_Phase v_nextPhase
log("PTC: ", self)
log("PTC instance: ", self)
log("Current PTC phase: ", p_currentPhase)
int2enum( enum2int(p_currentPhase)+1, v_nextPhase)
log("Next PTC phase:", v_nextPhase)
return v_nextPhase
}
function f_sendPhaseEndInd() runs on PTC{
// just to allow matching with integer ranges on the reception side, as it is not poosible to do so with enums
var PhaseEndInd v_PhaseEndInd := {phase := v_phase, phase_int := enum2int(v_phase)}
pt_sync.send(v_PhaseEndInd)
log("PTC: PhaseEndInd to MTC with content: ", v_PhaseEndInd, self)
v_phase := f_incPTCPhase(v_phase)
}
function f_addSyncSlaveSet (in PTC p_slave,
inout PTCSet p_set) {
p_set[sizeof(p_set)] := p_slave
return
}
function f_incMTCPhase(in e_Phase p_currentPhase) runs on MTC return e_Phase {
var e_Phase v_nextPhase
log("MTC: ", self)
log("Current phase: ", p_currentPhase)
int2enum( enum2int(p_currentPhase)+1, v_nextPhase)
log("Next phase:", v_nextPhase)
return v_nextPhase
}
function f_awaitEndPhase(in e_Phase p_phase) runs on MTC {
var integer v_amount:= sizeof(v_PTCSet);
var integer v_i
t_guard.start(c_guard)
var PhaseEndInd v_PhaseEndInd
for(v_i := 0; v_i < v_amount; v_i := v_i +1) {
alt {
[] pt_sync.receive (PhaseEndInd: {phase :=p_phase, phase_int := ?}){}
// value between p_phase +1 and e_testcase_complete:
[] pt_sync.receive (PhaseEndInd: {phase :=?, phase_int := (enum2int(p_phase) .. (enum2int(c_testcase_complete)))}){}
[] t_guard.timeout {
log("Timeout in MTC phase:", p_phase)
setverdict(inconc)
}
[] pt_sync.receive (?) -> value v_PhaseEndInd {
log("Unexpected phase recieved: ", v_PhaseEndInd)
log("Expected phase range: ", p_phase)
log(" to ", c_testcase_complete)
setverdict(inconc)
}
[] any port.receive{
log("Expected phase:", p_phase)
setverdict(inconc)
}
}
}
t_guard.stop
}
|
|
|
Re: J1939 Synchronizing Parallel Test Components of different type [message #1830411 is a reply to message #1830365] |
Sat, 25 July 2020 08:34 |
|
Hi Michael,
OK, I think I understand now; but what is the problem with what you have suggested yourself,
namely administering the PTCs in a structure as below:
type record of PTCs PTCSet
type union PTCs{
PTC ptc_type1,
PTC_Isobus_VT_VTSTATUSCycle_CT ptc_type2,
PTC_Isobus_VT_CT ptc_type3,
PTC_Isobus_ECU_CT ptc_type4
}
extending the definitions of the new and different PTCs with sync port and phase variable:
//component declarations
type component MTC{
timer t_guard
port SyncMasterPort pt_sync
var PTCSet v_PTCSet := {}
}
type component PTC {
port SyncSlavePort pt_sync
port SocketCAN_PT pt_socketCAN
port J1939PDU_PT pt_j1939PDU
var e_Phase v_phase := c_firstPhase
}
//add sync port, phase variable to each PTC component type
type component PTC_Isobus_VT_VTSTATUSCycle_CT
{
port SyncSlavePort pt_sync
port VTStatusTickOut pt_VTStatusTick
port PoolUploadOngoingIn pt_PoolUploadOngoing
//variables
var e_Phase v_phase := c_firstPhase
//timers
}
type component PTC_Isobus_VT_CT
{
port SyncSlavePort pt_sync
port J1939PDU_PT pt_j1939PDU
port VTStatusTickIn pt_VTStatusTick
//variables
var e_Phase v_phase := c_firstPhase
//timers
}
type component PTC_Isobus_ECU_CT
{
port SyncSlavePort pt_sync
port J1939PDU_PT pt_j1939PDU
//variables
var e_Phase v_phase := c_firstPhase
//timers
}
modifying f_addSyncSlaveSet() to refer to the new structure:
function f_addSyncSlaveSet (in PTCs p_slave,
inout PTCSet p_set) {
p_set[sizeof(p_set)] := p_slave
return
}
and then executing everything from the test case running on MTC:
var PTC v_ptc_J1939VTSocketIF := PTC.create("PTC1_ptc_j1939VTSocketIF") alive
var PTC v_ptc_J1939ECUSocketIF := PTC.create("PTC2_ptc_j1939ECUSocketIF") alive
var PTC_Isobus_VT_CT v_ptc_J1939VTApplication := PTC_Isobus_VT_CT.create("PTC1_ptc_j1939VTApplication") alive
var PTC_Isobus_VT_VTSTATUSCycle_CT v_ptc_J1939VT_VTStatusCycle := PTC_Isobus_VT_VTSTATUSCycle_CT.create("PTC_Isobis_VT_VTSTATUSCycle") alive
var PTC_Isobus_ECU_CT v_ptc_J1939ECUApplication := PTC_Isobus_ECU_CT.create("PTC2_ptc_j1939ECUApplication") alive
f_addSyncSlaveSet(v_ptc_J1939VTSocketIF, v_PTCSet)
f_addSyncSlaveSet(v_ptc_J1939ECUSocketIF, v_PTCSet)
f_addSyncSlaveSet(v_ptc_J1939VTApplication, v_PTCSet)
f_addSyncSlaveSet(v_ptc_J1939VT_VTStatusCycle, v_PTCSet)
f_addSyncSlaveSet(v_ptc_J1939ECUApplication, v_PTCSet)
connect(mtc:pt_sync, v_ptc_J1939VTSocketIF:pt_sync)
connect(mtc:pt_sync, v_ptc_J1939ECUSocketIF:pt_sync)
connect(mtc:pt_sync, v_ptc_J1939VTApplication:pt_sync)
connect(mtc:pt_sync, v_ptc_J1939VTApplication:pt_sync)
connect(mtc:pt_sync, v_ptc_J1939ECUApplication:pt_sync)
Of course each PTC will have to contain the code to manage receiving sync messages and answering them , but this code should be the same as in the old PTCs.
So you can extend the principle over to the new PTCs which are of various and different types.
Besides maybe an unaesthetic duplication of the code of the PTC functions for every possible PTC type, I see no problem with this.
You can save some code and add some structure by creating a base PTC type and define all the other PTC types by extending this base type, something like below:
type component basePTC {
port SyncSlavePort pt_sync
var e_Phase v_phase := c_firstPhase
}
type component PTC extends basePTC {
port SocketCAN_PT pt_socketCAN
port J1939PDU_PT pt_j1939PDU
//pt_sync, e_Phase will be inherited from basePTC
}
:
etc.
This architecture I sketched should work as well as the current one; do you see any problem with it I might have missed?
Best regards
Elemer
|
|
|
Re: J1939 Synchronizing Parallel Test Components of different type [message #1830424 is a reply to message #1830411] |
Sat, 25 July 2020 19:55 |
Michael Josenhans Messages: 99 Registered: February 2016 |
Member |
|
|
Hi Elemer,
that is what I am asking for. Especially I like the base PTC, which is extended to the other PTCs.
altstep alt_awaitPhaseStartReq(in e_Phase p_phase) runs on PTC {
var PhaseStartReq v_PhaseStartReq;
[] pt_sync.receive (PhaseStartReq: {phase := p_phase, phase_int := ?}){
log("PTC name: ", self)
log("Waits for start of phase: ", p_phase)
}
One thing I am aware of, is that the "runs on PTC" needs to be generalized to be able to be used with the other PTC types too. Or does it still work, if all PTCs are extensions of the base "PTC" type.
I am afraid of duplicating the code for each PTC type.
Thanks,
Michael
[Updated on: Sat, 25 July 2020 19:56] Report message to a moderator
|
|
|
Re: J1939 Synchronizing Parallel Test Components of different type [message #1830433 is a reply to message #1830424] |
Sun, 26 July 2020 06:36 |
|
Hi Michael,
at the current status of the standard components behave as primitive objects (as in object-oriented programming).
The standard defines runs on compatibility between components as below:
Runs on compatibility: a function or altstep referring to component type "A" in its runs on clause may be
called or started on a component instance of type 'B' if all the definitions of "A" have identical definitions in "B".
For example:
module Sem_060303_component_types_003 {
type port P message {
inout integer;
} with {extension "internal"}
type component GeneralComp {
port P p;
}
type component GeneralCompEx {
port P p;
port P p2;
}
function f_test() runs on GeneralComp {
setverdict(pass);
}
testcase TC_Sem_060303_component_types_003() runs on GeneralCompEx {
f_test(); // GeneralCompEx and GeneralComp are "runs on" compatible
setverdict(pass);
}
control{
execute(TC_Sem_060303_component_types_003());
}
}
This means that if you define a component type by extension that covers all your new component types as below:
type component basePTC {
port SyncSlavePort pt_sync
var e_Phase v_phase := c_firstPhase
}
type component PTC extends basePTC {
// port SyncSlavePort pt_sync : inherited from basePTC
port SocketCAN_PT pt_socketCAN
port J1939PDU_PT pt_j1939PDU
//variables
// var e_Phase v_phase := c_firstPhase : inherited from basePTC
//timers
}
type component PTC_Isobus_CT extends PTC
{
// port SyncSlavePort pt_sync : inherited from basePTC
// port SocketCAN_PT pt_socketCAN : inherited from PTC
// port J1939PDU_PT pt_j1939PDU : inherited from PTC
port VTStatusTickOut pt_VTStatusTickOut
port VTStatusTickIn pt_VTStatusTickIn
port PoolUploadOngoingIn pt_PoolUploadOngoing
//variables
// var e_Phase v_phase := c_firstPhase : inherited from basePTC
//timers
}
(please observer that PTC_Isobus_CT covers PTC_Isobus_VT_VTSTATUSCycle_CT, PTC_Isobus_VT_CT, PTC_Isobus_ECU_CT)
then a function, altstep etc. declared to run on PTC_Isobus_CT will also run on PTC:
altstep alt_awaitPhaseStartReq(in e_Phase p_phase) PTC_Isobus_CT {
var PhaseStartReq v_PhaseStartReq;
[] pt_sync.receive (PhaseStartReq: {phase := p_phase, phase_int := ?}){
log("PTC name: ", self)
log("Waits for start of phase: ", p_phase)
}
}
Of course when creating components , mapping ports etc. this will have to be taken into consideration:
:
var PTC v_ptc_J1939VTSocketIF := PTC.create("PTC1_ptc_j1939VTSocketIF") alive
var PTC v_ptc_J1939ECUSocketIF := PTC.create("PTC2_ptc_j1939ECUSocketIF") alive
var PTC_Isobus_VT_CT v_ptc_J1939VTApplication := PTC_Isobus_CT.create("PTC1_ptc_j1939VTApplication") alive
var PTC_Isobus_VT_VTSTATUSCycle_CT v_ptc_J1939VT_VTStatusCycle := PTC_Isobus_CT.create("PTC_Isobis_VT_VTSTATUSCycle") alive
var PTC_Isobus_ECU_CT v_ptc_J1939ECUApplication := PTC_Isobus_CT.create("PTC2_ptc_j1939ECUApplication") alive
:
but this way you can avoid duplicating unnecessarily code that is common to
multiple component types.
Best regards
Elemer
|
|
|
Re: J1939 Synchronizing Parallel Test Components of different type [message #1830447 is a reply to message #1830433] |
Sun, 26 July 2020 14:15 |
Michael Josenhans Messages: 99 Registered: February 2016 |
Member |
|
|
Hi Elemer,
I started chnaging the code:
//component declarations
type component SyncPTC {
port SyncSlavePort pt_sync
var e_Phase v_phase := c_firstPhase
}
type component PTC_Isobus_VT_VTSTATUSCycle_CT extends SyncPTC
{
port VTStatusTickOut pt_VTStatusTick
port PoolUploadOngoingIn pt_PoolUploadOngoing
//variables
//timers
}
type component PTC_Isobus_VT_CT extends SyncPTC
{
port J1939PDU_PT pt_j1939PDU
port VTStatusTickIn pt_VTStatusTick
//variables
//timers
}
type component PTC_Isobus_ECU_CT extends SyncPTC
{
port J1939PDU_PT pt_j1939PDU
//variables
//timers
}
type component PTC extends SyncPTC {
port SocketCAN_PT pt_socketCAN
port J1939PDU_PT pt_j1939PDU
}type record of PTCs PTCSet
type union PTCs{
PTC ptc_type1,
PTC_Isobus_VT_VTSTATUSCycle_CT ptc_type2,
PTC_Isobus_VT_CT ptc_type3,
PTC_Isobus_ECU_CT ptc_type4
}
I came up withe the following issues (see comments inside):
function f_startPhase (in e_Phase p_phase) runs on MTC {
var integer v_i
var integer v_amount := sizeof(v_PTCSet)
var PhaseStartReq v_phaseStartReq := { phase := p_phase, phase_int := enum2int(p_phase)}
for (v_i := 0; v_i < v_amount; v_i := v_i +1){
log("MTC instance: ", self)
pt_sync.send(v_phaseStartReq) to v_PTCSet[v_i]
// above I get the error:'v_PTCSet[v_i]' Type mismatch: The type of the operand should be a component type
//instead of `@Isobus_test.PTCs'
}
}
and
f_addSyncSlaveSet(v_ptc_J1939VTSocketIF, v_PTCSet)
// above I get the error: 'v_ptc_J1939VTSocketIF' Type mismatch: `@Isobus_test.PTCs' and `@Isobus_test.PTC' are not compatible
f_addSyncSlaveSet(v_ptc_J1939ECUSocketIF, v_PTCSet)
// above I get the error: 'v_ptc_J1939ECUSocketIF' Type mismatch: `@Isobus_test.PTCs' and `@Isobus_test.PTC' are not compatible
where:
function f_addSyncSlaveSet (in PTCs p_slave,
inout PTCSet p_set) {
p_set[sizeof(p_set)] := p_slave
return
}
[Updated on: Sun, 26 July 2020 14:17] Report message to a moderator
|
|
|
Re: J1939 Synchronizing Parallel Test Components of different type [message #1830449 is a reply to message #1830447] |
Sun, 26 July 2020 15:31 |
|
Hi Michael,
yes, but you have to follow the changes in the structure: now PTCSet is a record of unions (possible choices of component type values), not component variables as before.
So now, when you are initializing the component variables, you have to do something like:
testcase tc_can_j1939_IsobusVtEcuSimulation() runs on MTC {
:
var PTC v_ptc_J1939VTSocketIF := PTC.create("PTC1_ptc_j1939VTSocketIF") alive
var PTC v_ptc_J1939ECUSocketIF := PTC.create("PTC2_ptc_j1939ECUSocketIF") alive
var PTC_Isobus_VT_CT v_ptc_J1939VTApplication := PTC_Isobus_VT_CT.create("PTC1_ptc_j1939VTApplication") alive
var PTC_Isobus_VT_VTSTATUSCycle_CT v_ptc_J1939VT_VTStatusCycle := PTC_Isobus_VT_VTSTATUSCycle_CT.create("PTC_Isobis_VT_VTSTATUSCycle") alive
var PTC_Isobus_ECU_CT v_ptc_J1939ECUApplication := PTC_Isobus_ECU_CT.create("PTC2_ptc_j1939ECUApplication") alive
var PTCs v_PTCs := {ptc_type1:=v_ptc_J1939VTSocketIF}
f_addSyncSlaveSet(v_PTCs, v_PTCSet);
v_PTCs := {ptc_type1:=v_ptc_J1939ECUSocketIF}
f_addSyncSlaveSet(v_PTCs, v_PTCSet);
:
}
and when extracting the values of the component variables,
something like:
function f_startPhase (in e_Phase p_phase) runs on MTC {
var integer v_i
var integer v_amount := sizeof(v_PTCSet)
var PhaseStartReq v_phaseStartReq := { phase := p_phase, phase_int := enum2int(p_phase)}
for (v_i := 0; v_i < v_amount; v_i := v_i +1){
log("MTC instance: ", self)
if (ischosen(v_PTCSet[v_i].ptc_type1)) { pt_sync.send(v_phaseStartReq) to v_PTCSet[v_i].ptc_type1}
else if (ischosen(v_PTCSet[v_i].ptc_type2)) { pt_sync.send(v_phaseStartReq) to v_PTCSet[v_i].ptc_type2}
else if (ischosen(v_PTCSet[v_i].ptc_type3)) { pt_sync.send(v_phaseStartReq) to v_PTCSet[v_i].ptc_type3}
else if (ischosen(v_PTCSet[v_i].ptc_type4)) { pt_sync.send(v_phaseStartReq) to v_PTCSet[v_i].ptc_type4}
else {}//something wrong, this should not happen
}//endfor
}//endfunction
Alternatively, select union can be used:
function f_startPhase (in e_Phase p_phase) runs on MTC {
var integer v_i
var integer v_amount := sizeof(v_PTCSet)
var PhaseStartReq v_phaseStartReq := { phase := p_phase, phase_int := enum2int(p_phase)}
for (v_i := 0; v_i < v_amount; v_i := v_i +1){
log("MTC instance: ", self)
select union (v_PTCSet[v_i]) {
case (ptc_type1) { pt_sync.send(v_phaseStartReq) to v_PTCSet[v_i].ptc_type1}
case (ptc_type2) { pt_sync.send(v_phaseStartReq) to v_PTCSet[v_i].ptc_type2}
case (ptc_type3) { pt_sync.send(v_phaseStartReq) to v_PTCSet[v_i].ptc_type3}
case (ptc_type4) { pt_sync.send(v_phaseStartReq) to v_PTCSet[v_i].ptc_type4}
case else {}//something wrong, this should not happen
}
}//endfor
}//endfunction
I hope this makes sense
Best regards
Elemer
[Updated on: Sun, 26 July 2020 16:03] Report message to a moderator
|
|
|
Re: J1939 Synchronizing Parallel Test Components of different type [message #1830987 is a reply to message #1830449] |
Fri, 07 August 2020 21:58 |
Michael Josenhans Messages: 99 Registered: February 2016 |
Member |
|
|
Hi Elemer,
I have an MTC and multiple PTCs.
Some test components have only the purpose to exchange keep alive messages in the background as long as the test case is running.
When now the test purpose in the test component is completed (verdict set to pass) the background components have to be stopped. What is the proper way to do this?
You provided some time ago the following code for such background PTC:
function f_behaviour1_sync() runs on PTC1_CT
{
//periodic sending
while (condition1)
{
port1.send(message1);
T1.start
alt
{
[]pt_sync.receive("halt") { // changed here syncport to pt_sync
condition1:=false }
}
[]T1.timeout;
}
}//endwhile
}//endfunction
Is it the usual procedure, that the component sends a halt_request message to the MTC, which then sends the halt_indication message "halt" to all PTCs via pt_sync?
Where:
function f_awaitEndPhase(in e_Phase p_phase) runs on MTC {
var integer v_amount:= sizeof(v_PTCSet);
var integer v_i
t_guard.start(c_guard)
var PhaseEndInd v_PhaseEndInd
for(v_i := 0; v_i < v_amount; v_i := v_i +1) {
alt {
[] pt_sync.receive (PhaseEndInd: {phase :=p_phase, phase_int := ?}){}
// value between p_phase +1 and e_testcase_complete:
[] pt_sync.receive (PhaseEndInd: {phase :=?, phase_int := (enum2int(p_phase) .. (enum2int(c_testcase_complete)))}){}
[] t_guard.timeout {
log("Timeout in MTC phase:", p_phase)
setverdict(inconc)
}
[] pt_sync.receive (?) -> value v_PhaseEndInd {
log("Unexpected phase recieved: ", v_PhaseEndInd)
log("Expected phase range: ", p_phase)
log(" to ", c_testcase_complete)
setverdict(inconc)
}
[] any port.receive{
log("Expected phase:", p_phase)
setverdict(inconc)
}
}
}
t_guard.stop
}
and:
altstep alt_awaitPhaseStartReq(in e_Phase p_phase) runs on PTC {
var PhaseStartReq v_PhaseStartReq;
[] pt_sync.receive (PhaseStartReq: {phase := p_phase, phase_int := ?}){
log("PTC name: ", self)
log("Waits for start of phase: ", p_phase)
}
// between v_phase and p_phase
[] pt_sync.receive (PhaseStartReq: {phase := ?, phase_int := (enum2int(c_firstPhase) .. enum2int(v_phase))}) -> value v_PhaseStartReq
{
//v_phase := f_incPhase(v_phase)
log("PTC name: ", self)
log("Waits for start of phase: ", p_phase)
log("Received completion of phase: ", p_phase)
f_sendPhaseEndInd()
repeat
}
[] pt_sync.receive (PhaseStartReq: {phase := ?, phase_int :=?}) -> value v_PhaseStartReq
{log("Received unexpected message:", v_PhaseStartReq);setverdict(inconc)}
}
and:
const e_Phase c_firstPhase := e_open_socket
const e_Phase c_testcase_complete := e_testcase_complete
type record PhaseStartReq {
e_Phase phase,
integer phase_int
}
type record PhaseEndInd {
e_Phase phase,
integer phase_int
}
type port SyncMasterPort message {
out PhaseStartReq
in PhaseEndInd
} with { extension "internal" }
type port SyncSlavePort message {
in PhaseStartReq
out PhaseEndInd
} with { extension "internal" }
|
|
|
Re: J1939 Synchronizing Parallel Test Components of different type [message #1831003 is a reply to message #1830987] |
Sat, 08 August 2020 17:14 |
|
Hi Michael,
the test case is executed on the MTC , so at any moment MTC will know the status of execution of the PTCs, based on the PhasEndInd received from them.
So I don't see the need of a halt_req to be sent to MTC; MTC can take this decision on it's own and can send a halt_req to each PTC at the end of the test case.
At this moment each of the PTCs will have its verdict reached , so this halt request is to terminate gracefully and avoid dynamic test case errors that
can happen when e.g. a component which has connected ports is killed.
So all you need to do on PTCs is to wait for halt at the end of the meaningful part of the function executing on them:
function f_behaviour1() runs on PTC1_CT
{
//does something meaningful here; this is the main behaviour
:
alt
{
[]pt_sync.receive("halt") { //execution will hang here until halt is received }
}
//when halt is received, the function executing on the PTC terminates and the component ends
}
I hope this answers your question
Best regards
Elemer
|
|
|
Re: J1939 Synchronizing Parallel Test Components of different type [message #1831005 is a reply to message #1831003] |
Sat, 08 August 2020 19:48 |
Michael Josenhans Messages: 99 Registered: February 2016 |
Member |
|
|
Hi Elemer,
I am not completly sure. The test is handled in 3 step.
- Open socket (phase e_open_socket)
- Running the test case (
- Closing the socket (phase e_close_socket)
I must first send the HaltReg / HaltInd to all components before closing the socket. Thus I have to send the HaltReq and receive the HaltInd before reaching the phase e_close_socket.
Please see attached test case:
J1939_Isobus_test.tc_can_j1939_IsobusVtEcuSimulation2
Here some representative code (Search for HaltReq/HaltInd):
function f_ptc_J1939ECUApplication(in e_Phase p_phase) runs on PTC_Isobus_ECU_CT
{
var boolean condition := true
alt_awaitPhaseStartReq(p_phase)
while (condition)
{
var J1939PDU_with_NAME v_pgn_and_pdu_with_name
alt
{
[] pt_sync.receive (Command:"HaltInd"){
log("PTC name: ", self)
log("Got HaltInd command")
condition := false
}
[]pt_j1939PDU.receive(J1939PDU_with_NAME:{addr:= ?, name:=?,
pdu:=t_VTStatusInd(?, ?, ?, ?, ?)}) -> value v_pgn_and_pdu_with_name
{
v_peeraddr := v_pgn_and_pdu_with_name.addr
v_peername := v_pgn_and_pdu_with_name.name
// store peer name
//log incoming message
log("SocketCan:Expected message VTStatusReq received!", v_pgn_and_pdu_with_name)
pt_VTStatusTick.send( true );
}
[] pt_WorkingSetMaintenance.receive(t_WorkingSetMaintenanceTick(?)) {
pt_j1939PDU.send(t_J1939PDU_with_NAME(
J1939_NO_ADDR, /* set addr 0xFF, applies as name is set */
v_peername, /* set peername */
t_WorkingSetMaintenanceInd(true, compliantWithVTVersion4)
))
}
[]pt_WorkingSetMaintenance.receive(t_WorkingSetMaintenanceInitialize(true)) {
// the ECU has received the first VTStatus message
pt_j1939PDU.send(t_J1939PDU_with_NAME(
J1939_NO_ADDR, /* set addr 0xFF, applies as name is set */
v_peername, /* set peername */
t_GetHardwareReq
))
}
[]pt_j1939PDU.receive(J1939PDU_with_NAME:{addr:= ?, name:=v_peername,
pdu:=t_GetHardwareRes(?, ?, ?, ?, ?)}) -> value v_pgn_and_pdu_with_name
....
[]pt_j1939PDU.receive(J1939PDU_with_NAME:{addr:= ?, name:=v_peername,
pdu:=t_EndOfObjectPoolRes(?, ?, ?,
/* objectPoolErrorCodes */ {
methodOrAttributeNotSupportedByTheVT :=?,
unknownObjectReference :=true,
anyOtherError :=?,
objectPoolWasDeletedFromVolatileMemory :=?,
reserved4 :=false,
reserved5 :=false,
reserved6 :=false,
reserved7 :=false
})}) -> value v_pgn_and_pdu_with_name
{
log("Expected message EndOfObjectPoolRes received!", v_pgn_and_pdu_with_name)
pt_sync.send("HaltReq")
setverdict ( pass );
}
[] pt_j1939PDU.receive(J1939PDU_with_NAME:{addr:=?, name:=?,pdu:=?}) -> value v_pgn_and_pdu_with_name
{
log("Unexpected message received!", v_pgn_and_pdu_with_name)
}
[] pt_j1939PDU.receive
{log("Unexpected message received")} //this should catch any incoming message type not matched on the first alternatives
[] any port.receive
{
setverdict(fail)
log("Message received on a different port")} //this should catch any incoming message type not matched on the first alternatives on any other port
}//endalt
} // end while
f_sendPhaseEndInd()
alt_awaitPhaseStartReq(e_close_socket)
f_sendPhaseEndInd()
}
function f_ptc_J1939VTStatusCycleSend(in e_Phase p_phase) runs on PTC_Isobus_VT_VTSTATUSCycleSend_CT
{
//periodic sending
timer VTStatusClock := 1.0
var boolean condition := true
alt_awaitPhaseStartReq(p_phase)
while (condition)
{
pt_VTStatusTick.send(true);
VTStatusClock.start
alt
{
[] pt_sync.receive (Command:"HaltInd"){
log("PTC name: ", self)
log("Got HaltInd command")
condition := false
}
[]VTStatusClock.timeout;
}
}//endwhile
f_sendPhaseEndInd()
setverdict(pass)
alt_awaitPhaseStartReq(e_close_socket)
f_sendPhaseEndInd()
}//endfunction
and:
function f_ptc_J1939Agent(
in e_Phase p_phase,
in J1939_Priority p_send_prio,
in J1939_NAME p_j1939_name_source) runs on PTCAgent {
map(self:pt_socketCAN, system:pt_socketCAN)
var SocketCAN_socketid v_socket_id
var SocketCAN_ifr v_ifr
alt_awaitPhaseStartReq(e_open_socket)
var SocketCAN_open_j1939_result res
res := f_open_j1939()
v_socket_id := res.socket_id
v_ifr := res.ifr
var SocketCAN_bind_result v_bind_result
v_bind_result := f_bind(v_socket_id,
v_ifr.if_index,
p_j1939_name_source,
J1939_NO_PGN, /* p_j1939_pgn_source */
J1939_NO_ADDR /* p_j1939_addr_source */)
var SocketCAN_setsockopt_result v_setsockopt_result
v_setsockopt_result := f_setsockopt(v_socket_id, {j1939_prio:=p_send_prio})
const SocketCAN_setsockopt_commandu c_commandu_activate_broadcast := {j1939_broadcast := Enable}
// configure broadcast:
v_setsockopt_result := f_setsockopt(v_socket_id, c_commandu_activate_broadcast)
f_sendPhaseEndInd()
alt_awaitPhaseStartReq(p_phase)
var SocketCAN_receive_j1939_message v_result
var SocketCAN_j1939_send_data_to_result v_send_data_to_result
var J1939PDU_with_NAME v_pgn_and_pdu_with_name
var boolean condition := true
var boolean v_guard :=true
timer t_guard
while (condition)
{
alt
{
[] pt_sync.receive (Command:"HaltInd"){
log("PTC name: ", self)
log("Got HaltInd command")
condition := false
}
[v_guard] pt_j1939PDU.receive(J1939PDU_with_NAME:{addr:= ?, name:=?,pdu:=?})
-> value v_pgn_and_pdu_with_name
{
t_guard.start(c_guard)
var octetstring v_j1939_pdu, v_pgn_and_pdu
v_pgn_and_pdu := f_encode_J1939_message (v_pgn_and_pdu_with_name.pdu)
v_j1939_pdu := substr(v_pgn_and_pdu,3,lengthof(v_pgn_and_pdu)-3)// strip PGN
var J1939_hdr v_j1939_destination := {
name := v_pgn_and_pdu_with_name.name,
pgn := substr(v_pgn_and_pdu,0,3), // strip PDU, pgn_destination
addr:= v_pgn_and_pdu_with_name.addr
}
pt_socketCAN.send(SocketCAN_j1939_send_data_to:{
id := v_socket_id,
if_index := v_ifr.if_index,
j1939_destination := v_j1939_destination,
// strip PGN
pdu := v_j1939_pdu});
v_guard:=false; //stop receiving until send confirmation received
}
[not(v_guard)] pt_socketCAN.receive(a_SocketCAN_j1939_send_data_to_result(a_result(SocketCAN_SUCCESS))) -> value v_send_data_to_result
{
log("Sending j1939_send_data_to:", v_socket_id, ", ", v_ifr.if_index)
v_guard:=true
t_guard.stop
}
[not(v_guard)] pt_socketCAN.receive(a_SocketCAN_j1939_send_data_to_result(a_result(SocketCAN_ERROR)))
{
log("Sending j1939_send_data_to failed", v_socket_id);
v_guard:=true
t_guard.stop
setverdict(fail)
}
[] pt_socketCAN.receive(a_SocketCAN_receive_j1939_message(
v_socket_id,
v_ifr,
?, /* any pgn */
?, /* any peer_addr */
?, /* any peer_name */
? /* any j1939_pdu */)) -> value v_result
{
log("SocketCan:J1939 message from socket received", v_result)
pt_j1939PDU.send({addr:=v_result.destAddr, name:= v_result.name,
// concatenate received pgn and pdu
pdu:=f_decode_J1939_message(v_result.pgn & v_result.pdu) /* concatenate pgn & pdu */});
}
[] pt_sync.receive
{
log("Fail:Unexpected message from port pt_sync received");
setverdict(fail)
}
[v_guard] pt_socketCAN.receive
{
log("Fail:Unexpected message from port pt_socketCAN received")
//this should catch any incoming message type not matched on the first alternatives
setverdict(fail)
}
[v_guard] pt_j1939PDU.receive
{
log("Fail:Unexpected message from port pt_j1939PDU received")
//this should catch any incoming message type not matched on the first alternatives
setverdict(fail)
}
[v_guard] any port.receive
{
log("Fail:Message received on a different port")
//this should catch any incoming message type not matched on the first alternatives on any other port
setverdict(fail)
}
[not(v_guard)] t_guard.timeout {
log("guard timeout!")
setverdict(fail)
}
}//endalt
} // end while
f_sendPhaseEndInd()
alt_awaitPhaseStartReq(e_close_socket)
f_close_socket (v_socket_id)
unmap(self:pt_socketCAN, system:pt_socketCAN)
setverdict(pass)
f_sendPhaseEndInd()
}
Also I'd like to know, if the following commands in the above routines are at the right place:
f_sendPhaseEndInd()
....
alt_awaitPhaseStartReq(e_close_socket)
f_sendPhaseEndInd()
Furthermore I'd like to know, of the adapter function f_ptc_J1939Agent(), which opens the socket can be implemedted as a Dual-Faced port?
Br,
Michael
|
|
|
Re: J1939 Synchronizing Parallel Test Components of different type [message #1831039 is a reply to message #1831005] |
Mon, 10 August 2020 13:20 |
|
Hi Michael,
sorry, but I'm confused again:
I don't see why PTCs should receive HaltInd; based on what we discussed, PTCs should receive HaltReq from MTC , and optionally may answer this with HaltInd (I said optionally, but it is indeed recommended to send HaltInd)
so the testcase goes like this:
testcase tc_something runs on MTC_CT
{
:
:
//send NextPhaseReq for the last phase to all PTCs
//receive NextPhaseInd (all PTCs finished last phase)
//send HaltReq to all PTCs
//receive HaltInd from all PTCs
all component.done;
//unmap/disconnect test ports
}
So the MTC acts as the orchestrator of the component system.
Do you agree with this?
BR
Elemer
|
|
|
Re: J1939 Synchronizing Parallel Test Components of different type [message #1831045 is a reply to message #1831039] |
Mon, 10 August 2020 15:24 |
|
Hi Michael,
as for your question related to f_ptc_J1939Agent():
this is a component behaviour function with the component having several port types so I'm not sure how to fit the concept of dual ports here:
dual ports have an upper port in layer N+1 and a lower port in layer N-1 and translate between these two, converting from N+1 to N then to N-1 and vice versa.
So I'd say it's not possible.
Best regards
Elemer
|
|
| |
Re: J1939 Synchronizing Parallel Test Components of different type [message #1831074 is a reply to message #1831047] |
Tue, 11 August 2020 07:42 |
|
Hi Michael,
on second thought I think I need to correct myself.
It should be possible to implement the adaptor PTC with translation port; however I would not recommend it right now.
With a separate component for translation you have more freedom at the expense of an extra component. The translation port
has a strict and set architecture that might be more restrictive and difficult to handle, especially if used for the first time.
So I would start with the adaptor PTC and maybe later convert to translation port and compare the two solutions.
Best regards
Elemer
|
|
|
Goto Forum:
Current Time: Wed Oct 09 23:36:49 GMT 2024
Powered by FUDForum. Page generated in 0.05036 seconds
|