Ports
A Port
is actually is a bunch of pins (See Pins for mor information on pins.). As such, the connection, disconnection and data transfer are very similar to those of pins. Basically, there are two type of port: Outport
and Inport
. The data flows from outside of a component to its inside through an Inport
while data flows from inside of the component to its outside through an Outport
.
Construction of Ports
A port (both Inport
and Outport
) is constructed by specifying its element type T
, the number of pins npins
and the buffer length of its pins.
julia> Outport{Bool}(5)
5-element Outport{Outpin{Bool}}:
Outpin(eltype:Bool, isbound:false)
Outpin(eltype:Bool, isbound:false)
Outpin(eltype:Bool, isbound:false)
Outpin(eltype:Bool, isbound:false)
Outpin(eltype:Bool, isbound:false)
julia> Outport{Int}(2)
2-element Outport{Outpin{Int64}}:
Outpin(eltype:Int64, isbound:false)
Outpin(eltype:Int64, isbound:false)
julia> Outport(3)
3-element Outport{Outpin{Float64}}:
Outpin(eltype:Float64, isbound:false)
Outpin(eltype:Float64, isbound:false)
Outpin(eltype:Float64, isbound:false)
julia> Outport()
1-element Outport{Outpin{Float64}}:
Outpin(eltype:Float64, isbound:false)
julia> Inport{Bool}(5)
5-element Inport{Inpin{Bool}}:
Inpin(eltype:Bool, isbound:false)
Inpin(eltype:Bool, isbound:false)
Inpin(eltype:Bool, isbound:false)
Inpin(eltype:Bool, isbound:false)
Inpin(eltype:Bool, isbound:false)
julia> Inport{Int}(2)
2-element Inport{Inpin{Int64}}:
Inpin(eltype:Int64, isbound:false)
Inpin(eltype:Int64, isbound:false)
julia> Inport(3)
3-element Inport{Inpin{Float64}}:
Inpin(eltype:Float64, isbound:false)
Inpin(eltype:Float64, isbound:false)
Inpin(eltype:Float64, isbound:false)
julia> Inport()
1-element Inport{Inpin{Float64}}:
Inpin(eltype:Float64, isbound:false)
Connection and Disconnection of Ports
The ports can be connected to and disconnected from each other. See the following example.
Let us construct and Outport
and an Inport
and connect them together.
julia> op1 = Outport(2)
2-element Outport{Outpin{Float64}}:
Outpin(eltype:Float64, isbound:false)
Outpin(eltype:Float64, isbound:false)
julia> ip1 = Inport(2)
2-element Inport{Inpin{Float64}}:
Inpin(eltype:Float64, isbound:false)
Inpin(eltype:Float64, isbound:false)
julia> ls = connect!(op1, ip1)
2-element Array{Link{Float64},1}:
Link(state:open, eltype:Float64, isreadable:false, iswritable:false)
Link(state:open, eltype:Float64, isreadable:false, iswritable:false)
Note that we connected all pins of op
to ip
. We cannot connect the ports partially.
julia> op2, ip21, ip22 = Outport(5), Inport(2), Inport(3)
(Outport(numpins:5, eltype:Outpin{Float64}), Inport(numpins:2, eltype:Inpin{Float64}), Inport(numpins:3, eltype:Inpin{Float64}))
julia> ls1 = connect!(op2[1:2], ip21)
2-element Array{Link{Float64},1}:
Link(state:open, eltype:Float64, isreadable:false, iswritable:false)
Link(state:open, eltype:Float64, isreadable:false, iswritable:false)
julia> ls2 = connect!(op2[3:5], ip22)
3-element Array{Link{Float64},1}:
Link(state:open, eltype:Float64, isreadable:false, iswritable:false)
Link(state:open, eltype:Float64, isreadable:false, iswritable:false)
Link(state:open, eltype:Float64, isreadable:false, iswritable:false)
The connectedness of ports can be checked.
julia> isconnected(op2[1], ip21[1])
true
julia> isconnected(op2[1], ip21[2])
false
julia> isconnected(op2[1:2], ip21)
true
julia> isconnected(op2[3:5], ip22)
true
julia> isconnected(op2[5], ip22[3])
true
Connected ports can be disconnected.
julia> disconnect!(op2[1], ip21[1])
missing
julia> disconnect!(op2[2], ip21[2])
missing
julia> disconnect!(op2[3:5], ip22)
Now check again the connectedness,
julia> isconnected(op2[1], ip21[1])
false
julia> isconnected(op2[1], ip21[2])
false
julia> isconnected(op2[1:2], ip21)
false
julia> isconnected(op2[3:5], ip22)
false
julia> isconnected(op2[5], ip22[3])
false
Data Flow Through Ports
Data flow through the ports is very similar to the case in pins(see Data Flow Through Pins for information about data flow through pins). Running tasks must be bound to the links of pins of the ports for data flow through the ports.
Let us construct an Outport
and an Inport
, connect them together with links and perform data transfer from the Outport
to the Inport
through the links.
julia> op3, ip3 = Outport(2), Inport(2)
(Outport(numpins:2, eltype:Outpin{Float64}), Inport(numpins:2, eltype:Inpin{Float64}))
julia> ls = connect!(op3, ip3)
2-element Array{Link{Float64},1}:
Link(state:open, eltype:Float64, isreadable:false, iswritable:false)
Link(state:open, eltype:Float64, isreadable:false, iswritable:false)
julia> t = @async while true
val = take!(ip3)
all(val .=== NaN) && break
println("Took " * string(val))
end
Task (runnable) @0x00007f1fd477b340
julia> put!(op3, 1.);
Took [1.0, 1.0]
julia> ip3[1].link.buffer
64-element Buffer{Cyclic,Float64,1}:
1.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
⋮
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
Note that the data flowing through the links are also written into the buffers of links.
Indexing and Iteration of Ports
Ports can be indexed similarly to the arrays in Julia. When indexed, the corresponding pin of the port is returned.
julia> op4 = Outport(3)
3-element Outport{Outpin{Float64}}:
Outpin(eltype:Float64, isbound:false)
Outpin(eltype:Float64, isbound:false)
Outpin(eltype:Float64, isbound:false)
julia> op4[1]
Outpin(eltype:Float64, isbound:false)
julia> op4[end]
Outpin(eltype:Float64, isbound:false)
julia> op4[:]
3-element Array{Outpin{Float64},1}:
Outpin(eltype:Float64, isbound:false)
Outpin(eltype:Float64, isbound:false)
Outpin(eltype:Float64, isbound:false)
julia> op4[1] = Outpin()
Outpin(eltype:Float64, isbound:false)
julia> op4[1:2] = [Outpin(), Outpin()]
2-element Array{Outpin{Float64},1}:
Outpin(eltype:Float64, isbound:false)
Outpin(eltype:Float64, isbound:false)
The iteration of Port
s in a loop is also possible. When iterated, the pins of the Port
is returned.
julia> ip5 = Inport(3)
3-element Inport{Inpin{Float64}}:
Inpin(eltype:Float64, isbound:false)
Inpin(eltype:Float64, isbound:false)
Inpin(eltype:Float64, isbound:false)
julia> for pin in ip5
@show pin
end
pin = Inpin(eltype:Float64, isbound:false)
pin = Inpin(eltype:Float64, isbound:false)
pin = Inpin(eltype:Float64, isbound:false)
Full API
Causal.AbstractPort
— Typeabstract type AbstractPort{P} <: AbstractArray{P,1}
Abstract type of Outport
and Inport
. See also: Outport
, Inport
.
Causal.Inport
— Typestruct Inport{P} <: AbstractPort{P}
Constructs an Inport
with numpins
Inpin
.
Fields
pins::Array{P,1} where P
Pins of the port
!!! warning Element type of an Inport
must be Inpin
. See also Inpin
Example
julia> Inport{Int}(2)
2-element Inport{Inpin{Int64}}:
Inpin(eltype:Int64, isbound:false)
Inpin(eltype:Int64, isbound:false)
julia> Inport()
1-element Inport{Inpin{Float64}}:
Inpin(eltype:Float64, isbound:false)
Causal.Outport
— Typestruct Outport{P} <: AbstractPort{P}
Constructs an Outport
with numpins
Outpin
.
Fields
pins::Array{P,1} where P
Pins of the output port
id::Base.UUID
Unique identifier
!!! warning Element type of an Outport
must be Outpin
. See also Outpin
Example
julia> Outport{Int}(2)
2-element Outport{Outpin{Int64}}:
Outpin(eltype:Int64, isbound:false)
Outpin(eltype:Int64, isbound:false)
julia> Outport()
1-element Outport{Outpin{Float64}}:
Outpin(eltype:Float64, isbound:false)
Base.getindex
— Methodgetindex(port, idx)
Returns elements from port
at index idx
. Same as port[idx]
.
Example
julia> op = Outport(3)
3-element Outport{Outpin{Float64}}:
Outpin(eltype:Float64, isbound:false)
Outpin(eltype:Float64, isbound:false)
Outpin(eltype:Float64, isbound:false)
julia> op[1]
Outpin(eltype:Float64, isbound:false)
julia> op[end]
Outpin(eltype:Float64, isbound:false)
julia> op[:]
3-element Array{Outpin{Float64},1}:
Outpin(eltype:Float64, isbound:false)
Outpin(eltype:Float64, isbound:false)
Outpin(eltype:Float64, isbound:false)
Base.put!
— Methodput!(outport, vals)
Puts vals
to outport
. Each item in vals
is putted to the links
of the outport
.
The outport
must be writable to be read. That is, there must be a runnable tasks bound to links of the outport
that reads data from outport
.
Example
julia> op, ip = Outport(), Inport()
(Outport(numpins:1, eltype:Outpin{Float64}), Inport(numpins:1, eltype:Inpin{Float64}))
julia> ls = connect!(op, ip)
1-element Array{Link{Float64},1}:
Link(state:open, eltype:Float64, isreadable:false, iswritable:false)
julia> t = @async while true
val = take!(ip)
all(val .=== NaN) && break
println("Took " * string(val))
end;
julia> put!(op, [1.])
Took [1.0]
1-element Array{Float64,1}:
1.0
julia> put!(op, [NaN])
1-element Array{Float64,1}:
NaN
Base.setindex!
— Methodsetindex!(port, item, idx)
Sets item
to port
at index idx
. Same as port[idx] = item
.
Example
julia> op = Outport(3)
3-element Outport{Outpin{Float64}}:
Outpin(eltype:Float64, isbound:false)
Outpin(eltype:Float64, isbound:false)
Outpin(eltype:Float64, isbound:false)
julia> op[1] = Outpin()
Outpin(eltype:Float64, isbound:false)
julia> op[end] = Outpin()
Outpin(eltype:Float64, isbound:false)
julia> op[1:2] = [Outpin(), Outpin()]
2-element Array{Outpin{Float64},1}:
Outpin(eltype:Float64, isbound:false)
Outpin(eltype:Float64, isbound:false)
Base.size
— Methodsize(port)
Retruns size of port
.
Base.take!
— Methodtake!(inport)
Takes an element from inport
. Each link of the inport
is a read and a vector containing the results is returned.
The inport
must be readable to be read. That is, there must be a runnable tasks bound to links of the inport
that writes data to inport
.
Example
julia> op, ip = Outport(), Inport()
(Outport(numpins:1, eltype:Outpin{Float64}), Inport(numpins:1, eltype:Inpin{Float64}))
julia> ls = connect!(op, ip)
1-element Array{Link{Float64},1}:
Link(state:open, eltype:Float64, isreadable:false, iswritable:false)
julia> t = @async for val in 1 : 5
put!(op, [val])
end;
julia> take!(ip)
1-element Array{Float64,1}:
1.0
julia> take!(ip)
1-element Array{Float64,1}:
2.0
Causal.datatype
— MethodReturns the data type of port
.
Causal.similar
— Methodsimilar(outport)
similar(outport, numpins)
Returns a new port that is similar to port
with the same element type. The number of links in the new port is nlinks
and data buffer length is ln
.