Skip to content

Commit d44a8aa

Browse files
authored
Merge pull request #569 from avinxshKD/docs/julia-documenter
docs: add Julia Documenter site
2 parents a075366 + 84d6ee6 commit d44a8aa

8 files changed

Lines changed: 368 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,22 @@ jobs:
8383
run: julia --color=yes tests/julia/runtests.jl
8484
shell: bash
8585

86+
julia-docs:
87+
runs-on: ubuntu-latest
88+
89+
steps:
90+
- uses: actions/checkout@v4
91+
92+
- uses: julia-actions/setup-julia@v3
93+
with:
94+
version: '1.10'
95+
96+
- name: Install documentation dependencies
97+
run: julia --project=docs -e 'using Pkg; Pkg.instantiate()'
98+
99+
- name: Build Julia documentation
100+
run: julia --project=docs docs/make.jl
101+
86102
julia-matlab-verilog-test:
87103
runs-on: ubuntu-latest
88104

docs/Project.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[deps]
2+
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
3+
4+
[compat]
5+
Documenter = "1"
6+
julia = "1.10"

docs/make.jl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using Documenter
2+
3+
include(joinpath(@__DIR__, "..", "concore.jl"))
4+
using .Concore
5+
6+
makedocs(;
7+
modules=[Concore],
8+
sitename="Concore.jl",
9+
checkdocs=:exports,
10+
format=Documenter.HTML(; inventory_version="dev"),
11+
pages=[
12+
"Home" => "index.md",
13+
"Getting Started" => "getting-started.md",
14+
"API Reference" => "api.md",
15+
"Backends" => "backends.md",
16+
"Wire Format" => "wire-format.md",
17+
],
18+
)

docs/src/api.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# [API Reference](@id api-reference)
2+
3+
```@meta
4+
CurrentModule = Concore
5+
```
6+
7+
## Protocol
8+
9+
```@docs
10+
concore_read
11+
concore_write
12+
initval
13+
unchanged
14+
```
15+
16+
## Configuration
17+
18+
```@docs
19+
safe_parse_list
20+
tryparam
21+
default_maxtime!
22+
load_iport!
23+
load_oport!
24+
load_params!
25+
concore_init!
26+
```
27+
28+
The compatibility names `default_maxtime`, `load_iport`, `load_oport`,
29+
`load_params`, and `concore_init` are aliases for the corresponding functions
30+
above.
31+
32+
`FileTransport`, `MmapTransport`, and `ZmqTransport` are aliases for the
33+
corresponding backend types.
34+
35+
## Backends
36+
37+
```@docs
38+
AbstractBackend
39+
FileBackend
40+
MmapBackend
41+
mmap_cleanup
42+
ZmqBackend
43+
```
44+
45+
ZMQ ports are registered with
46+
`init_zmq_port(name, mode, address, socket_type)` and closed with
47+
`terminate_zmq()`. These functions require the optional ZMQ.jl package. See
48+
[ZMQ](@ref zmq) for a complete call sequence.

docs/src/backends.md

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# [Backends](@id backends)
2+
3+
The active backend controls how `concore_read` and `concore_write` move the
4+
same wire-format strings. File is the default backend.
5+
6+
## File
7+
8+
`FileBackend` uses ordinary files and has no external Julia dependencies.
9+
10+
```julia
11+
include("concore.jl")
12+
using .Concore
13+
14+
concore_init!(FileBackend())
15+
```
16+
17+
Local input and output path prefixes are `./in` and `./out`. The numeric port
18+
is appended to the prefix, so port 1 uses `./in1` and `./out1`.
19+
20+
## Mmap
21+
22+
`MmapBackend` keeps the file-based naming and wire format but accesses each
23+
file through a fixed-size memory-mapped segment. The default segment size is
24+
4096 bytes.
25+
26+
```julia
27+
concore_init!(MmapBackend())
28+
29+
try
30+
value = concore_read(1, "ym", "[0.0, 0.0]")
31+
concore_write(1, "u", value)
32+
finally
33+
mmap_cleanup()
34+
end
35+
```
36+
37+
Pass a different segment size when constructing the backend if the wire value
38+
does not fit in the default segment:
39+
40+
```julia
41+
concore_init!(MmapBackend(8192))
42+
```
43+
44+
## [ZMQ](@id zmq)
45+
46+
ZMQ support is optional. Install ZMQ.jl in the active Julia environment before
47+
including `concore.jl`:
48+
49+
```julia
50+
using Pkg
51+
Pkg.add("ZMQ")
52+
```
53+
54+
`Concore.HAS_ZMQ` reports whether the package was available when the runtime
55+
was loaded. ZMQ ports use string names instead of numeric file ports. This
56+
example shows the request side of a REQ/REP pair:
57+
58+
```julia
59+
include("concore.jl")
60+
using .Concore
61+
62+
concore_init!(ZmqBackend())
63+
init_zmq_port("req", "connect", "tcp://127.0.0.1:5555", "REQ")
64+
65+
try
66+
concore_write("req", "u", [1.0])
67+
ym = concore_read("req", "ym", "[0.0, 0.0]")
68+
finally
69+
terminate_zmq()
70+
end
71+
```
72+
73+
A REP peer must bind the same address and receive before replying.
74+
75+
## Docker
76+
77+
Docker is a runtime path variant, not a separate backend type.
78+
`concoredocker.jl` uses `/in` and `/out` as its path prefixes, producing paths
79+
such as `/in1/ym` and `/out1/u`.
80+
81+
For generated Docker studies, `mkconcore.py` copies `concoredocker.jl` into the
82+
node build directory as `concore.jl`. The node source therefore keeps the same
83+
include statement used locally:
84+
85+
```julia
86+
include("concore.jl")
87+
using .Concore
88+
```
89+
90+
Build the mixed Julia controller and Python plant example with the existing
91+
study generator:
92+
93+
```sh
94+
concore build demo/sampleJ.graphml --source demo --output docker-julia-demo --type docker --compose
95+
cd docker-julia-demo
96+
./build
97+
./maxtime 5
98+
docker compose up
99+
```
100+
101+
The generated Compose file mounts the connected input and output directories
102+
at the paths expected by each container.

docs/src/getting-started.md

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# [Getting Started](@id getting-started)
2+
3+
```@meta
4+
DocTestSetup = :(using Main.Concore)
5+
```
6+
7+
## Setup
8+
9+
Concore.jl requires Julia 1.10 or later. Clone the Concore repository and run
10+
Julia from the repository root:
11+
12+
```sh
13+
git clone https://github.com/ControlCore-Project/concore.git
14+
cd concore
15+
julia
16+
```
17+
18+
Load the standalone runtime from a Julia node:
19+
20+
```julia
21+
include("concore.jl")
22+
using .Concore
23+
```
24+
25+
There are no required Julia package dependencies for the default File backend.
26+
ZMQ.jl is only needed when using the ZMQ backend.
27+
28+
## Node loop
29+
30+
A Concore node reads until its input changes, performs its calculation, and
31+
writes its output. This controller reads `ym` from input port 1 and writes `u`
32+
to output port 1:
33+
34+
```julia
35+
include("concore.jl")
36+
using .Concore
37+
38+
Concore.default_maxtime!(100)
39+
Concore.delay = 0.02
40+
41+
ym = initval("[0.0, 0.0]")
42+
43+
while Concore.simtime < Concore.maxtime
44+
while unchanged()
45+
ym = concore_read(1, "ym", "[0.0, 0.0]")
46+
end
47+
48+
u = 1.01 .* ym
49+
concore_write(1, "u", u; delta=0)
50+
end
51+
```
52+
53+
With the default paths, port 1 reads from `./in1/ym` and writes to
54+
`./out1/u`. The study runner creates and connects those directories.
55+
56+
The repository also contains a mixed Python and Julia file-backend demo:
57+
58+
```sh
59+
julia demo/run_julia_mixed_demo.jl
60+
```
61+
62+
## Initial values and simulation time
63+
64+
`initval` parses a wire value and sets `Concore.simtime` from its first value:
65+
66+
```jldoctest
67+
julia> ym = initval("[0.0, 1.5]"); (Concore.simtime, ym)
68+
(0.0, [1.5])
69+
```
70+
71+
`ym` is `[1.5]` and `Concore.simtime` is `0.0`. A read returns only the data
72+
values and updates simulation time to the largest timestamp seen. A write uses
73+
`Concore.simtime + delta` as the outgoing timestamp.
74+
75+
## Configuration
76+
77+
The runtime loads the same files as the other Concore implementations:
78+
79+
- `concore.iport` maps named input ports to numbers.
80+
- `concore.oport` maps named output ports to numbers.
81+
- `concore.params` supplies values returned by `tryparam`.
82+
- `concore.maxtime` sets the simulation limit used by `default_maxtime!`.
83+
84+
Parameters can use Python dictionary syntax or semicolon-separated key/value
85+
pairs:
86+
87+
```text
88+
{'gain': 1.5, 'mode': 'auto'}
89+
```
90+
91+
```text
92+
gain=1.5;mode=auto
93+
```
94+
95+
Use a default when a parameter is absent:
96+
97+
```julia
98+
gain = tryparam("gain", 1.0)
99+
```

docs/src/index.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Concore.jl
2+
3+
Concore.jl is the native Julia implementation of the Concore protocol. It uses
4+
the same wire format and synchronization pattern as the existing Concore
5+
runtimes, without calling through Python.
6+
7+
The runtime is the standalone file `concore.jl`. Julia nodes keep it next to
8+
their source and include it directly:
9+
10+
```julia
11+
include("concore.jl")
12+
using .Concore
13+
```
14+
15+
File transport is the default. Memory-mapped files and ZeroMQ are available as
16+
optional backend selections, and `concoredocker.jl` provides the path defaults
17+
used by generated Docker studies.
18+
19+
## Contents
20+
21+
- [Getting Started](@ref getting-started) covers setup, the standard node loop, and configuration.
22+
- [API Reference](@ref api-reference) lists the public Julia interface.
23+
- [Backends](@ref backends) describes File, Mmap, ZMQ, and Docker usage.
24+
- [Wire Format](@ref wire-format) documents message encoding and simulation time.

docs/src/wire-format.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# [Wire Format](@id wire-format)
2+
3+
```@meta
4+
DocTestSetup = :(using Main.Concore)
5+
```
6+
7+
Concore messages are text lists containing a simulation timestamp followed by
8+
zero or more data values:
9+
10+
```text
11+
[simtime, value1, value2, ...]
12+
```
13+
14+
For example:
15+
16+
```text
17+
[5.0, 1.5, -2.0]
18+
```
19+
20+
The first value is the timestamp. `concore_read` updates `Concore.simtime` and
21+
returns only `[1.5, -2.0]` to the node.
22+
23+
## Writing
24+
25+
For vector writes, the outgoing timestamp is `Concore.simtime + delta`:
26+
27+
```julia
28+
Concore.simtime = 5.0
29+
concore_write(1, "u", [1.5, -2.0]; delta=1)
30+
```
31+
32+
This writes:
33+
34+
```text
35+
[6.0, 1.5, -2.0]
36+
```
37+
38+
Integer-valued finite floats are written with a `.0` suffix. Other values are
39+
rounded to 15 significant digits to keep output consistent with the existing
40+
Concore wire format.
41+
42+
## Reading
43+
44+
`safe_parse_list` parses wire values without calling `eval` or `Meta.parse`.
45+
For compatibility with Python and NumPy output, it also accepts wrapped values
46+
and Python literals:
47+
48+
```jldoctest
49+
julia> safe_parse_list("[0.0, np.float64(1.5), True, None]") == [0.0, 1.5, 1.0, 0.0]
50+
true
51+
```
52+
53+
Malformed input raises `ArgumentError`. The protocol, wire compatibility, and
54+
interop tests cover Julia exchanges with the existing Python, C++, MATLAB, and
55+
Verilog implementations.

0 commit comments

Comments
 (0)