Issues of dynamic port and connect
Problems occurs when the dynamic port and connect are applied in the Autopilot model.
-
Dynamic ports free problem
After every execution of Autopilot model, dynamic input and output ports should be free by thefree_#port_name#
method in Autopilot.h, which is called in AutopilotAdapter.cpp.
For simple component like:dynamic component Autopilot { port dynamic in Q input[0:32], dynamic out Q output[0:32]; @input::connect{ connect input[?] -> output[?]; } }
Free of dynamic inputs and outputs works, when we use the
free_input
method of autopilot.h in AutopilotAdapter.cpp, like follows:bool free_input(int input_indexref) { if( (input_indexref < 0) || (32 <= input_indexref) || (!__input_connected[input_indexref]) ){ return false;} __input_free_request.push(input_indexref); dynamicfree(); return true; }
It‘s because in the
dynamicfree()
method,__output_free_request
will be pushed and then free, when it connects to in the dynamic input port.void __event_body_free_EventHandler_1_(){ while(input_has_free_request()){ int _input_dynPortID = input_free_request_front(); for(long i = __event_connects_EventHandler_1_.size()-1; i >= 0; --i){ int* _connected_idxs = __event_connects_EventHandler_1_.at(i); if( (_input_dynPortID == _connected_idxs[0]) ){ int _output_dynPortID = _connected_idxs[1]; __output_free_request.push(_output_dynPortID); if(__parent != NULL){__parent_dynamic(__parent, false, true);} if(__output_free_request.front() == _output_dynPortID){ __output_free_request.pop(); } dynamicconnect_remove(&__dynamic_double_connect, NULL, &(input[_input_dynPortID]), &(output[_output_dynPortID])); __event_connects_EventHandler_1_.erase(__event_connects_EventHandler_1_.begin()+i); __output_connected[_output_dynPortID] = false; free(_connected_idxs); } } } }
But when component is defined as follows:
dynamic component Autopilot { port dynamic in Q input[0:32], dynamic out Q output[0:32]; instance Autopilot1 ap1; @ input::connect{ connect input[?] -> ap1.input[?]; } @ ap1.output1::connect{ connect ap1.output1[?] -> output[?]; } }
dynamic component Autopilot1{ port dynamic in Q input[0:32], dynamic out Q output1[0:32], dynamic out Q output2[0:32]; @ input::connect{} implementation Math{ for i = 1:32 if is_connected(input,i) if ports_connect(output1, i, input(i)) output1(i) = input(i); end if ports_connect(output2, i, input(i)) output2(i) = input(i); end end end } }
Free of dynamic output ports depends on the free event:
void __event_body_free_EventHandler_3_(){ while(ap1.output1_has_free_request()){ int _ap1_output1_dynPortID = ap1.output1_free_request_front(); for(long i = __event_connects_EventHandler_3_.size()-1; i >= 0; --i){ int* _connected_idxs = __event_connects_EventHandler_3_.at(i); if( (_ap1_output1_dynPortID == _connected_idxs[0]) ){ int _output_dynPortID = _connected_idxs[1]; __output_free_request.push(_output_dynPortID); if(__parent != NULL){__parent_dynamic(__parent, false, true);} if(__output_free_request.front() == _output_dynPortID){ __output_free_request.pop(); } dynamicconnect_remove(&__dynamic_double_connect, NULL, &(ap1.output1[_ap1_output1_dynPortID]), &(output[_output_dynPortID])); __event_connects_EventHandler_3_.erase(__event_connects_EventHandler_3_.begin()+i); __output_connected[_output_dynPortID] = false; free(_connected_idxs); } } } }
But, the
ap1.output1_has_free_request()
is never pushed in instance ap1, because there is no connect between the dynamic input ports and output1 ports in instance ap1, so dynamic output ports of Autopilot can not be free correctly.
When we use the ports_free method in Autopilot1 component:dynamic component Autopilot1{ port dynamic in Q input[0:32], dynamic out Q output1[0:32], dynamic out Q output2[0:32]; @ input::connect{} implementation Math{ for i = 1:32 if is_connected(input,i) if ports_connect(output1, i, input(i)) output1(i) = input(i); end Z r = ports_free(output1,i); if ports_connect(output2, i, input(i)) output2(i) = input(i); end Z r = ports_free(output2,i); end end } }
The free request can be pushed into
ap1.output1_has_free_request()
with__ports_free_1
method:bool __ports_free_1(int idx0){ if((idx0 < 0) || (32 <= idx0) || (!__output1_connected[idx0])){return false;}__output1_free_request.push(idx0); if(__parent != NULL){__parent_dynamic(__parent, false, true);} __output1_connected[idx0] = false; return true; }
Problem is that
__output1_connected[idx0]
can not be set to false in this method, it means this port is free now and next connect will occupy this port, which leads to error that no matter how many inputs request there is just one output connect request.
Also, when component like follows, there are two Autopilot1 instances:dynamic component Autopilot { port dynamic in Q input[0:32], dynamic out Q output[0:32]; instance Autopilot1 ap1,ap2; @ input::connect{ connect input[?] -> ap1.input[?]; } @ ap1.output1::connect{ connect ap1.output1[?] -> ap2.input[?]; } @ ap2.output1::connect{ connect ap2.output1[?] -> output[?]; } }
dynamic component Autopilot1{ port dynamic in Q input[0:32], dynamic out Q output1[0:32], dynamic out Q output2[0:32]; @ input::connect{} implementation Math{ for i = 1:32 if is_connected(input,i) if ports_connect(output1, i, input(i)) output1(i) = input(i); end Z r = ports_free(output1,i); if ports_connect(output2, i, input(i)) output2(i) = input(i); end Z r = ports_free(output2,i); end end } }
Free of dynamic output ports depends on the free event:
void __event_body_free_EventHandler_4_(){ while(ap2.output1_has_free_request()){ int _ap2_output1_dynPortID = ap2.output1_free_request_front(); for(long i = __event_connects_EventHandler_4_.size()-1; i >= 0; --i){ int* _connected_idxs = __event_connects_EventHandler_4_.at(i); if( (_ap2_output1_dynPortID == _connected_idxs[0]) ){ int _output_dynPortID = _connected_idxs[1]; __output_free_request.push(_output_dynPortID); if(__parent != NULL){__parent_dynamic(__parent, false, true);} if(__output_free_request.front() == _output_dynPortID){ __output_free_request.pop(); } dynamicconnect_remove(&__dynamic_double_connect, NULL, &(ap2.output1[_ap2_output1_dynPortID]), &(output[_output_dynPortID])); __event_connects_EventHandler_4_.erase(__event_connects_EventHandler_4_.begin()+i); __output_connected[_output_dynPortID] = false; free(_connected_idxs); } } } }
Free of dynamic output port in Autopilot depends on
ap2.output1_has_free_request()
, although ports_free method is defined in Autopilot1, there is no__ports_free#number#
method in generated autopilot_ap2.h file. It means that ports_free method can just be converted in the outer layer of the whole component.
The structure like this problem occurs component is very important in the autopilot. Because there are several subcomponents, which all need the content of dynamic input. But once dynamic input port connects to the dynamic port in sub-component, connect request of dynamic input will be pop, so we need the component like Autopilot1, which aims to copy the connect request of dynamic input port.
When the dynamic port in Autopilot can not be free, after several frames of simulation, all ports will be occupied and over flow. JVM is broken down and shows RUNTIME error. -
Problems in instance ports
When the structure of Autopilot Model like follows:
dynamic component Autopilot {
port
dynamic in Q input[0:32],
dynamic out Q output[0:32];
instance Autopilot1 ap1[0:32];
instance Autopilot2 ap2[0:32];
instance Autopilot3 ap3;
@ input::connect{
connect input[?] -> ap1[?].input;
connect ap1[?].output1 -> ap3.input1[?];
connect ap1[?].output2 -> ap3.input2[?];
connect input[?] -> ap2[?].input;
connect ap2[?].output3 -> ap3.input3[?];
connect ap2[?].output4 -> ap3.input4[?];
}
@ ap3.output1::connect{
connect ap3.output1[?] -> output[?];
}
@ ap3.output2::connect{
connect ap3.output2[?] -> output[?];
}
}
component Autopilot1{
port
in Q input,
out Q output1,
out Q output2;
implementation Math{
output1 = input;
output2 = input;
}
}
component Autopilot2{
port
in Q input,
out Q output3,
out Q output4;
implementation Math{
output3 = input;
output4 = input;
}
}
dynamic component Autopilot4{
port
dynamic in Q input1[0:32],
dynamic in Q input2[0:32],
dynamic out Q output[0:32];
@input1::connect{}
@input2::connect{}
implementation Math{
for i = 1:32
if is_connected(input1,i)&&is_connected(input2,i)
if ports_connect(output,i,42.123)
output(i) = input1(i) + input2(i);
end
end
end
}
}
dynamic component Autopilot3{
port
dynamic in Q input1[0:32],
dynamic in Q input2[0:32],
dynamic in Q input3[0:32],
dynamic in Q input4[0:32],
dynamic out Q output1[0:32],
dynamic out Q output2[0:32];
instance Autopilot4 ap4,ap5;
@ input1::connect{
connect input1[?] -> ap4.input1[?];
}
@ input2::connect{
connect input2[?] -> ap4.input2[?];
}
@ ap4.output::connect{
connect ap4.output[?] -> output1[?];
}
@ input3::connect{
connect input3[?] -> ap5.input1[?];
}
@ input4::connect{
connect input4[?] -> ap5.input2[?];
}
@ ap5.output::connect{
connect ap5.output[?] -> output2[?];
}
}
The structure can be shown in a Figure:
In the generated c++ file of autopilot, there is a undefined connect method ap3.connect_input1_input2_input3_input4
, which is called in autopilot.h. This leads to the error when c++ files are compiled to dll file.
void __event_body_EventHandler_9_()
{
while(__event_condition_EventHandler_9_()){
int* _connected_idxs = (int *)calloc(7, sizeof(int));
int _input_dynPortID = __input_connect_request.front(); __input_connect_request.pop(); _connected_idxs[0] = _input_dynPortID;
int _ap2_dynINSTID = dynamicconnect(32, __ap2_connected); if( _ap2_dynINSTID < 0 ){ free(_connected_idxs); return; } _connected_idxs[1] = _ap2_dynINSTID;
int _ap1_dynINSTID = dynamicconnect(32, __ap1_connected); if( _ap1_dynINSTID < 0 ){ free(_connected_idxs); return; } _connected_idxs[2] = _ap1_dynINSTID;
int _ap3_input1_dynPortID = -1;
int _ap3_input2_dynPortID = -1;
int _ap3_input3_dynPortID = -1;
int _ap3_input4_dynPortID = -1;
if(!ap3.connect_input1_input2_input3_input4(&_ap3_input1_dynPortID, ap1[_ap1_dynINSTID].output1, &_ap3_input2_dynPortID, ap1[_ap1_dynINSTID].output2, &_ap3_input3_dynPortID, ap2[_ap2_dynINSTID].output3, &_ap3_input4_dynPortID, ap2[_ap2_dynINSTID].output4)){ free(_connected_idxs); return ;}
_connected_idxs[3] = _ap3_input1_dynPortID;_connected_idxs[4] = _ap3_input2_dynPortID;_connected_idxs[5] = _ap3_input3_dynPortID;_connected_idxs[6] = _ap3_input4_dynPortID;
__dynamic_double_connect.push_back({&ap1[_ap1_dynINSTID], &(input[_input_dynPortID]), &(ap1[_ap1_dynINSTID].input)});
__dynamic_double_connect.push_back({&ap3, &(ap1[_ap1_dynINSTID].output1), &(ap3.input1[_ap3_input1_dynPortID])});
__dynamic_double_connect.push_back({&ap3, &(ap1[_ap1_dynINSTID].output2), &(ap3.input2[_ap3_input2_dynPortID])});
__dynamic_double_connect.push_back({&ap2[_ap2_dynINSTID], &(input[_input_dynPortID]), &(ap2[_ap2_dynINSTID].input)});
__dynamic_double_connect.push_back({&ap3, &(ap2[_ap2_dynINSTID].output3), &(ap3.input3[_ap3_input3_dynPortID])});
__dynamic_double_connect.push_back({&ap3, &(ap2[_ap2_dynINSTID].output4), &(ap3.input4[_ap3_input4_dynPortID])});
__event_connects_EventHandler_9_.push_back(_connected_idxs);
}
}
- Port free in Streamtest
Dynamic ports can not be free in current Streamtest project, when dynamic component is tested with TestWrapper and Stream File. Because free_methods of dynamic component are not called. So, the length of Stream data can just be one. Otherwise, it leads to error when tests second group of stream data, the reason is that last used ports are not free.