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])
trueConnected 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])
falseData 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) @0x00007fe0d500b5b0
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.0Note 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 Ports 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 — TypeCausal.Inport — TypeInport{T}(numpins=1)Constructs an Inport with numpins Inpin.
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 — TypeOutport{T}(numpins=1)Constructs an Outport with numpins Outpin.
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::AbstractPort, idx::Vararg{Int, N}) where NReturns 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::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}:
NaNBase.setindex! — Methodsetindex!(port::AbstractPort, item, idx::Vararg{Int, N}) where NSets 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::AbstractPort)Retruns size of port.
Base.take! — Methodtake!(inport::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.0Causal.datatype — Methoddatatype(port::AbstractPort)Returns the data type of port.
Causal.similar — Methodsimilar(port, numpins::Int=length(outport)) where {P<:Outpin{T}} where {T}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.