Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to open62541 1.4.6 #29

Merged
merged 13 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,7 @@ jobs:
- Core
version:
- '1'
- 'pre'
include:
# run 1.6 only on Windows, Mac OS on current github runners doesn't work, see: https://github.com/julia-actions/setup-julia/issues/240
# and on ubuntu it runs for disproportionate times.
- platform: windows-latest
version: 1.6
- 'lts'
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v4
Expand Down
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Open62541"
uuid = "e9b70463-8ccb-4e30-a2e2-0d1ec8db6536"
authors = ["Martin Kosch <[email protected]> and contributors"]
version = "0.1.1"
version = "0.2.0"

[deps]
CEnum = "fa961155-64e5-5f13-b03f-caf6b980ea82"
Expand All @@ -18,12 +18,12 @@ Dates = "1.6"
Distributed = "1.6"
DocStringExtensions = "0.9"
OffsetArrays = "1"
open62541_jll = "~1.3.9"
Pkg = "1.6"
Random = "1.6"
SafeTestsets = "0.1.0"
Test = "1.6"
julia = "1.6"
open62541_jll = "~1.4.1"

[extras]
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ accidental breakage and evolutions of the API have to be expected.

Documentation is also a work in progress.

## How to contribute
There is many ways one can contribute to the development of Open62541.jl (in order of increasing complexity):
- Reporting bugs, issues and suggestions on the Github repository.
- Improving the clarity of the existing documentation.
- Adding new tutorials for more advanced functionality.
- Adding/Improving docstrings, especially in the main file of the library src/Open62541.jl. It would be best if these are added automatically in the right spot during the code generation using Clang.jl (see gen/generator.jl). But improvements are welcome also if they are directly done in the src/Open62541.jl (existing contributors can help keeping things aligned).
- Adding improvements to the high-level interface. It would be best to discuss ideas on this topic via the Github repository before embarking on larger changes.

## Installation

Open62541.jl is registered in Julia's General registry.
Expand Down
2 changes: 1 addition & 1 deletion docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ Open62541 = "e9b70463-8ccb-4e30-a2e2-0d1ec8db6536"

[compat]
Documenter = "1"
Open62541 = "0.1"
Open62541 = "0.1, 0.2"
4 changes: 3 additions & 1 deletion docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ makedocs(;
"Tutorials" => [
"tutorials/server_first_steps.md",
"tutorials/client_first_steps.md",
"tutorials/combined_variables.md"
"tutorials/combined_variables.md",
"tutorials/combined_username_password_login.md",
"tutorials/further_resources.md"
],
"Manual" => [
"manual/numbertypes.md",
Expand Down
8 changes: 8 additions & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,11 @@ The documentation has the following structure:

The docstring situation is better on the handwritten functions contained in
the other source files.

## How to contribute
There is many ways one can contribute to the development of Open62541.jl (in order of increasing complexity):
- Reporting bugs, issues and suggestions on the Github repository.
- Improving the clarity of the existing documentation.
- Adding new tutorials for more advanced functionality.
- Adding/Improving docstrings, especially in the main file of the library src/Open62541.jl. It would be best if these are added automatically in the right spot during the code generation using Clang.jl (see gen/generator.jl). But improvements are welcome also if they are directly done in the src/Open62541.jl (existing contributors can help keeping things aligned).
- Adding improvements to the high-level interface. It would be best to discuss ideas on this topic via the Github repository before embarking on larger changes.
33 changes: 24 additions & 9 deletions docs/src/manual/numbertypes.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,29 @@
# Supported number types
It is noteworthy that the open62541 library does not support all number types
included within Julia natively. Open62541.jl supports the same number types as its
C counterpart. Julia types that are not supported will throw an exception, rather
than silently performing an automated conversion for you.

It is noteworthy that the open62541 library supports the following Julia
number types natively. Open62541.jl provides support for the same number types.
Adding other types is possible, but must rely on a custom datatype. See the [open62541 documentation](https://github.com/open62541/open62541/tree/master/examples/custom_datatype).
If you want to store a Julia type that is not on the list below (for example:
`Float32`, `Complex{Int64}` or `Rational{Bool}`) in an OPC UA server, you should
consciously convert it to a supported number type beforehand.

**Real:**
- Boolean: Bool
- Integers: Int8, Int16, Int32, Int64, UInt8, UInt16, UInt32, UInt64.
- Float: Float32 and Float64.
Furthermore `JUA_Client_readValueAttribute(client, nodeid)` will return numbers
in one of the supported formats below. You can specify the conversion to be used
via its typed equivalent if you know a `Float16` value should be returned, you
can call `JUA_Client_readValueAttribute(client, nodeid, Float16)`. This conversion
obviously only works if implemented in Julia.

Adding other number types is possible, but relies on introducing a custom
datatype. See the [open62541 documentation](https://github.com/open62541/open62541/tree/master/examples/custom_datatype)
for details about this.

**Complex:**
## Real numbers:
- Boolean: Bool
- Integers: Int8, Int16, Int32, Int64, UInt8, UInt16, UInt32, UInt64
- Float: Float32, Float64
- Rational: Rational{Int32}, Rational{UInt32}

- Complex{Float32}, Complex{Float64}
## Complex numbers:
- Complex{Float32}
- Complex{Float64}
58 changes: 58 additions & 0 deletions docs/src/tutorials/combined_username_password_login.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Username/password authentication using basic access control

In this tutorial, we will showcase how authentication using a username and password
(rather than an anonymous user) can be accomplished using Open62541.jl.

## Configuring the server
Here we configure the server to accept a The
code block is commented line by line.

```julia
using Open62541

#configure the open62541 server; we choose a default config on port 4840.
server = JUA_Server()
config = JUA_ServerConfig(server)
JUA_ServerConfig_setDefault(config)
login = JUA_UsernamePasswordLogin("BruceWayne", "IamBatman") #specifies the user BruceWayne and his secret password.
allowAnonymous = false #disallow anonymous login
retval = JUA_AccessControl_default(config, allowAnonymous, login) #set the access control inside the server config.

JUA_Server_runUntilInterrupt(server) #start the server, shut it down by pressing CTRL+C repeatedly once you are finished with it.
```

## Using the client
Start a new Julia session and run the program shown below. Once you are finished,
you may want to return to the first Julia session and stop the server (press
CTRL + C repeatedly).

```julia
using Open62541

#initiate client, configure it and connect to server
client = JUA_Client()
config = JUA_ClientConfig(client)
JUA_ClientConfig_setDefault(config)

retval = JUA_Client_connectUsername(client,
"opc.tcp://localhost:4840",
"BruceWayne",
"IamBatman") #connect using the username and password

JUA_Client_disconnect(client) #disconnect

retval2 = JUA_Client_connectUsername(client,
"opc.tcp://localhost:4840",
"PeterParker",
"IamSpiderman") #try connecting using a wrong username/password

JUA_Client_disconnect(client) #disconnect

```
`retval` should be `UA_STATUSCODE_GOOD` (= 0) indicating that authentication was sucessful,
whereas `retval2` should be `UA_STATUSCODE_BADUSERACCESSDENIED` (= 2149515264) indicating
that the second login attempt was rejected.

Note that in this basic configuration the login credentials are transmitted unencrypted,
which is obviously not recommended when network traffic is potentially exposed to
unwanted listeners.
2 changes: 1 addition & 1 deletion docs/src/tutorials/combined_variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ retval3 = JUA_Client_writeValueAttribute(client, id3, new3)

Inspecting the return values (`retval1,2,3`) and the log and error messages in the
terminal (both server and client), you will see that writing `new2` to `id2`
failed with the statuscode "BadTypeMismatch" (`retval2a`).
failed with the statuscode "BadTypeMismatch" (`retval2`).

This is because in open62541 arrays are statically sized, both in terms of the
number of dimensions, as well as the number of elements along each dimension.
Expand Down
18 changes: 18 additions & 0 deletions docs/src/tutorials/further_resources.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Further resources
The tutorials and documentation currently included with Open62541.jl is very slim
(pull request welcome!). This will be gradually improved over time. Meanwhile, it
is important to realize that other resources exist that can be helpful in answering
questions.

## Tutorials in the open62541 documentation
The [tutorials of the open62541 C-library](https://www.open62541.org/doc/master/tutorials.html),
as well as its documentation, are a good starting point. While the code in these
tutorials is of course written in C, many of the function names and approaches
directly transfer over to Open62541.jl and are thus very useful to know.

## Examples in the open62541 source repository on Github
The [examples](https://github.com/open62541/open62541/tree/master/examples) provided in Github repository of the open62541 C-library can also be instructive. Many of the tests of the Julia library have been adapted from examples found in this folder, so it is useful to compare the two codes against each other.

## Tests in Open62541.jl
Code changes implemented in Open62541.jl are continuously tested against a growing
[set of tests](https://github.com/martinkosch/Open62541.jl/tree/main/test). In the absence of more step-by-step guidance, the code for these test sets can be instructive.
2 changes: 1 addition & 1 deletion gen/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ open62541_jll = "de311183-6042-582f-9ed9-05a52085bec4"
Clang = "0.18"
JuliaFormatter = "1.0.42"
OffsetArrays = "1.12.10"
open62541_jll = "=1.3.10"
open62541_jll = "~1.4.1"
2 changes: 1 addition & 1 deletion gen/epilogue.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const UA_GUID_NULL = UA_Guid(0, 0, 0, Tuple(zeros(UA_Byte, 8)))
const UA_NODEID_NULL = UA_NodeId(Tuple(zeros(UA_Byte, 24)))
const UA_EXPANDEDNODEID_NULL = UA_ExpandedNodeId(UA_NODEID_NULL, UA_STRING_NULL, 0)

#Julia number types that are rare built directly into open62541
#Julia number types that are built directly into open62541
#Does NOT include ComplexF32/64 - these have to be treated differently.
const UA_NUMBER_TYPES = Union{Bool, Int8, Int16, Int32, Int64, UInt8, UInt16,
UInt32, UInt64, Float32, Float64}
Expand Down
58 changes: 53 additions & 5 deletions gen/generator.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ headers = filter(x -> endswith(x, ".h"), headers) #just in case there are non .h

#comment out two lines in util.h;
#these caused errors since open62541_jll is compiled without amalgamation (reason not clear to me)
fn = joinpath(@__DIR__, "./headers/open62541/util.h")
fn = joinpath(@__DIR__, "./headers/open62541/common.h")
f = open(fn, "r")
util_content = read(f, String)
close(f)
Expand All @@ -62,6 +62,7 @@ function write_generated_defs(generated_defs_dir::String,
type_names,
julia_types)
julia_types = replace("$julia_types", Regex("Main\\.Open62541\\.") => "")
types_ambiguous_ignorelist = type_names[1:end .∉ [unique_julia_types_ind]]
type_string = """
# Vector of all UA types
const type_names = $type_names
Expand All @@ -73,23 +74,28 @@ function write_generated_defs(generated_defs_dir::String,
const unique_julia_types_ind = unique(i -> julia_types[i], eachindex(julia_types))

# Vector of types that are ambiguously defined via typedef and are not to be used as default type
types_ambiguous_ignorelist = [:UA_Duration, :UA_ByteString, :UA_XmlElement, :UA_LocaleId, :UA_DateTime, :UA_UtcTime, :UA_StatusCode]
types_ambiguous_ignorelist = type_names[1:end .∉ [unique_julia_types_ind]]

"""

inlined_funcs = """
# Vector of all inlined function names listed in the open62541 header files
const inlined_funcs = $(extract_inlined_funcs(headers))
"""


client_write = extract_header_data(r"UA_INLINE[\s\S]{0,50}\s(UA_Client_write(\w*)Attribute)\((?:[\s\S]*?,\s*){2}const\s(\S*)", headers)
push!(client_write, ["UA_Client_writeUserAccessLevelAttribute", "UserAccessLevel", "UA_Byte"])
push!(client_write, ["UA_Client_writeValueAttribute_scalar", "Value", "UA_DataType"])
push!(client_write, ["UA_Client_writeValueAttributeEx", "Value", "UA_DataValue"])
data_UA_Client = """
# UA_Client_ functions data
const attributes_UA_Client_Service = $(extract_header_data(r"UA_INLINE[\s\S]{0,50}\s(UA_Client_Service_(\w*))\((?:[\s\S]*?)\)(?:[\s\S]*?)UA_\S*", headers))
const attributes_UA_Client_read = $(extract_header_data(r"UA_INLINE[\s\S]{0,50}\s(UA_Client_read(\w*)Attribute)\((?:[\s\S]*?,\s*){2}(\S*)", headers))
const attributes_UA_Client_write = $(extract_header_data(r"UA_INLINE[\s\S]{0,50}\s(UA_Client_write(\w*)Attribute)\((?:[\s\S]*?,\s*){2}const\s(\S*)", headers))
const attributes_UA_Client_write = $(client_write)
const attributes_UA_Client_read_async = $(extract_header_data(r"UA_INLINE[\s\S]{0,50}\s(UA_Client_read(\w*)Attribute_async)\([\s\S]+?\)[\s\S]+?{[\s\S]+?__UA_Client_readAttribute_async\s*\([\s\S]+?&UA_TYPES\[([\S]+?)\]", headers))
const attributes_UA_Client_write_async = $(extract_header_data(r"UA_INLINE[\s\S]{0,50}\s(UA_Client_write(\w*)Attribute_async)\s*\(UA_Client\s*\*client,\s*const\s*UA_NodeId\s*nodeId,\s*const\s*(\S*)", headers))
const attributes_UA_Client_write_async = $(extract_header_data(r"UA_INLINE[\s\S]{0,50}\s(UA_Client_write(\w*)Attribute_async)\s*\(\s*UA_Client\s*\*client,\s*const\s*UA_NodeId\s*nodeId,\s*const\s*(\S*)", headers))
"""

#Get rid of unnecessary type unions
data_UA_Client = replace(data_UA_Client,
"Vector{Union{Nothing, SubString{String}}}" => "Vector{String}")
Expand All @@ -113,12 +119,15 @@ end

function extract_inlined_funcs(headers)
regex_inlined = r"UA_INLINE[\s]+(?:[\w\*]+[\s]*[\s\S]){0,3}((?:__)?UA_[\w]+)\("
regex_inlined2 = r"UA_INLINABLE\(\s*\S*\s*(\S*)\("
inlined_funcs = String[]
for i in eachindex(headers)
open(headers[i], "r") do f
data = read(f, String)
append!(inlined_funcs,
vcat(getfield.(collect(eachmatch(regex_inlined, data)), :captures)...)) # Extract inlined functions from header file
append!(inlined_funcs,
vcat(getfield.(collect(eachmatch(regex_inlined2, data)), :captures)...)) # Extract inlined functions from header file
end
end
return inlined_funcs
Expand Down Expand Up @@ -185,6 +194,44 @@ return guid_dst
end"
data = replace(data, orig=>new)

#need to remove some buggy lines
replacestring = "const UA_INT32_MIN = int32_t - Clonglong(2147483648)

const UA_INT32_MAX = Clong(2147483647)

const UA_UINT32_MIN = 0

const UA_UINT32_MAX = Culong(4294967295)

const UA_FLOAT_MIN = \$(Expr(:toplevel, :FLT_MIN))

const UA_FLOAT_MAX = \$(Expr(:toplevel, :FLT_MAX))

const UA_DOUBLE_MIN = \$(Expr(:toplevel, :DBL_MIN))

const UA_DOUBLE_MAX = \$(Expr(:toplevel, :DBL_MAX))"

data = replace(data, replacestring=>"")

#need to remove some buggy lines
replacestring = "const UA_INT32_MIN = int32_t - Clonglong(2147483648)

const UA_INT32_MAX = Clong(2147483647)

const UA_UINT32_MIN = 0

const UA_UINT32_MAX = Culong(4294967295)

const UA_FLOAT_MIN = \$(Expr(:toplevel, :FLT_MIN))

const UA_FLOAT_MAX = \$(Expr(:toplevel, :FLT_MAX))

const UA_DOUBLE_MIN = \$(Expr(:toplevel, :DBL_MIN))

const UA_DOUBLE_MAX = \$(Expr(:toplevel, :DBL_MAX))"

data = replace(data, replacestring=>"")

#replace version number code (make the constants express the version of the _jll
#rather than hard coded numbers)
version_regex = r"const UA_OPEN62541_VER_MAJOR = \d+\n
Expand All @@ -201,6 +248,7 @@ f = open(fn, "w")
write(f, data)
close(f)


@warn "If errors occur at this stage, check start section of Open62541.jl for system-dependent symbols; may have to resolve manually."
@show "loading module"
include("../src/Open62541.jl")
Expand Down
1 change: 1 addition & 0 deletions gen/generator.toml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ output_ignorelist = [
"RTL_CRITICAL_SECTION",
"_RTL_CRITICAL_SECTION_DEBUG",
"_LIST_ENTRY",
"LIST_ENTRY",
"HANDLE",
"DWORD",
"WORD",
Expand Down
9 changes: 8 additions & 1 deletion gen/prologue.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,14 @@ const UA_UINT64_MAX = typemax(UInt64)
const UA_UINT64_MIN = typemin(UInt64)
const UA_FALSE = false
const UA_TRUE = true

const UA_INT32_MIN = typemin(Int32)
const UA_INT32_MAX = typemax(Int32)
const UA_UINT32_MIN = 0
const UA_UINT32_MAX = typemax(UInt32)
const UA_FLOAT_MIN = typemin(Float32)
const UA_FLOAT_MAX = typemax(Float32)
const UA_DOUBLE_MIN = typemin(Float64)
const UA_DOUBLE_MAX = typemax(Float64)
const UA_EMPTY_ARRAY_SENTINEL = convert(Ptr{Nothing}, Int(0x01))

@static if VERSION < v"1.7"
Expand Down
Loading