aioads 0.1.0.dev5__tar.gz → 0.1.0.dev6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/PKG-INFO +1 -1
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/functions/ads_sum_read.py +21 -16
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/functions/ads_sum_read_write.py +15 -13
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/functions/ads_symbol_datatype_by_name.py +8 -3
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/functions/ads_symbol_datatype_upload.py +4 -1
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/functions/ads_symbol_info_by_name_ex.py +30 -12
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/functions/ads_symbol_table_version.py +6 -5
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/functions/ads_symbol_upload.py +10 -4
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/functions/ads_symbol_upload_info.py +10 -8
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/pyproject.toml +1 -1
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/.github/dependabot.yml +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/.github/workflows/ci.yml +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/.github/workflows/publish.yml +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/.gitignore +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/.vscode/settings.json +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/LICENSE +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/README.md +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/ads_client.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/ads_error_codes.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/ads_notifications.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/ads_symbol_cache.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/ads_symbol_parser.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/ams_address.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/ams_header.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/ams_service_port.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/ams_tcp_header.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/commands/ads_add_notification.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/commands/ads_command.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/commands/ads_delete_notification.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/commands/ads_read.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/commands/ads_read_device_info.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/commands/ads_read_state.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/commands/ads_read_write.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/commands/ads_write.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/commands/ads_write_state.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/commands/errors.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/errors.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/functions/ads_enable_route.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/functions/ads_function.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/py.typed +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/stream.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/transport.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/aioads/utils/local_ip.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/docs/transmission_mode.md +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/docs/unittest_style_guide.html +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/examples/read_cmd_reuse_mqtt.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/examples/read_cycles.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/examples/read_cycles_mqtt.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/examples/read_multiple.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/examples/read_multiple_mqtt.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/examples/read_single.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/pdm.lock +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/__init__.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/builders.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/integration/README.md +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/integration/__init__.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/integration/base.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/integration/config.example.toml +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/integration/config.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/integration/test_connection.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/integration/test_performance.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/integration/test_read_symbols.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/__init__.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/commands/__init__.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/commands/test_ads_add_notification.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/commands/test_ads_command.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/commands/test_ads_delete_notification.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/commands/test_ads_read.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/commands/test_ads_read_device_info.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/commands/test_ads_read_state.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/commands/test_ads_read_write.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/commands/test_ads_write.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/commands/test_ads_write_state.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/commands/test_errors.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/functions/__init__.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/functions/test_ads_enable_route.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/functions/test_ads_function.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/functions/test_ads_sum_read.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/functions/test_ads_sum_read_write.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/functions/test_ads_symbol_datatype_by_name.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/functions/test_ads_symbol_datatype_upload.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/functions/test_ads_symbol_info_by_name_ex.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/functions/test_ads_symbol_table_version.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/functions/test_ads_symbol_upload.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/functions/test_ads_symbol_upload_info.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/test_ads_client.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/test_ads_error_codes.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/test_ads_notifications.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/test_ads_symbol_cache.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/test_ads_symbol_parser.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/test_ams_address.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/test_ams_header.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/test_ams_tcp_header.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/test_errors.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/test_stream.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/test_transport.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/utils/__init__.py +0 -0
- {aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/utils/test_local_ip.py +0 -0
|
@@ -5,13 +5,13 @@ sending multiple `AdsReadCommand` in a single command
|
|
|
5
5
|
https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_adsdll2/124830987.html&id=
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
|
|
9
8
|
from struct import Struct
|
|
10
9
|
from typing import Final
|
|
11
10
|
from aioads.ads_error_codes import AdsErrorCode
|
|
12
11
|
from aioads.ams_address import AmsAddress
|
|
13
12
|
from aioads.commands.ads_read import AdsReadCommand, AdsReadResponse
|
|
14
13
|
from aioads.commands.ads_read_write import AdsReadWriteCommand
|
|
14
|
+
from aioads.commands.errors import AdsCommandError
|
|
15
15
|
from aioads.functions.ads_function import AdsFunctionSymbolGroup, IAdsFunction
|
|
16
16
|
from aioads.stream import AdsStream
|
|
17
17
|
from aioads.transport import ITransport
|
|
@@ -19,7 +19,7 @@ from aioads.transport import ITransport
|
|
|
19
19
|
|
|
20
20
|
class AdsSumRead(IAdsFunction[list[tuple[AdsReadResponse, AdsStream]]]):
|
|
21
21
|
"""
|
|
22
|
-
Ads sum read command that allows batching up to 500 `AdsReadCommand` in a single call
|
|
22
|
+
Ads sum read command that allows batching up to 500 `AdsReadCommand` in a single call
|
|
23
23
|
"""
|
|
24
24
|
|
|
25
25
|
ERROR_CODE_STRUCT_DEF: Final[Struct] = Struct("<I")
|
|
@@ -36,17 +36,15 @@ class AdsSumRead(IAdsFunction[list[tuple[AdsReadResponse, AdsStream]]]):
|
|
|
36
36
|
|
|
37
37
|
def serialize(self) -> bytes:
|
|
38
38
|
"""
|
|
39
|
-
serialize all commands to bytes
|
|
39
|
+
serialize all commands to bytes
|
|
40
40
|
"""
|
|
41
41
|
return b"".join(command.serialize() for command in self.commands)
|
|
42
42
|
|
|
43
43
|
async def execute(self) -> list[tuple[AdsReadResponse, AdsStream]]:
|
|
44
44
|
if len(self.commands) == 0:
|
|
45
|
-
raise ValueError(
|
|
46
|
-
"At least one command is required for ADS Sum Read")
|
|
45
|
+
raise ValueError("At least one command is required for ADS Sum Read")
|
|
47
46
|
if len(self.commands) > 500:
|
|
48
|
-
raise ValueError(
|
|
49
|
-
"Too many commands for ADS Sum Read, maximum is 500")
|
|
47
|
+
raise ValueError("Too many commands for ADS Sum Read, maximum is 500")
|
|
50
48
|
|
|
51
49
|
payload = self.serialize()
|
|
52
50
|
command = AdsReadWriteCommand(
|
|
@@ -60,20 +58,27 @@ class AdsSumRead(IAdsFunction[list[tuple[AdsReadResponse, AdsStream]]]):
|
|
|
60
58
|
write_length=len(payload),
|
|
61
59
|
write_data=payload,
|
|
62
60
|
)
|
|
63
|
-
|
|
61
|
+
header, read_payload = await command.request()
|
|
62
|
+
if not header.error_code.ok:
|
|
63
|
+
raise AdsCommandError(header.error_code, "Failed to execute ADS Sum Read")
|
|
64
64
|
error_stream = read_payload.sub_stream(
|
|
65
65
|
# 4 bytes per error code
|
|
66
|
-
len(self.commands)
|
|
66
|
+
len(self.commands)
|
|
67
|
+
* self.ERROR_CODE_STRUCT_DEF.size
|
|
68
|
+
)
|
|
67
69
|
|
|
68
70
|
response: list[tuple[AdsReadResponse, AdsStream]] = []
|
|
69
71
|
for cmd in self.commands:
|
|
70
72
|
error_code = AdsErrorCode(
|
|
71
|
-
error_stream.read_struct(self.ERROR_CODE_STRUCT_DEF)[0]
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
73
|
+
error_stream.read_struct(self.ERROR_CODE_STRUCT_DEF)[0]
|
|
74
|
+
)
|
|
75
|
+
response.append(
|
|
76
|
+
(
|
|
77
|
+
AdsReadResponse(
|
|
78
|
+
error_code=error_code,
|
|
79
|
+
length=cmd.length,
|
|
80
|
+
),
|
|
81
|
+
read_payload.sub_stream(cmd.length),
|
|
82
|
+
)
|
|
78
83
|
)
|
|
79
84
|
return response
|
|
@@ -49,17 +49,17 @@ packet
|
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
"""
|
|
52
|
+
|
|
52
53
|
from aioads.ams_address import AmsAddress
|
|
53
54
|
from aioads.commands.ads_read import AdsReadResponse
|
|
54
55
|
from aioads.commands.ads_read_write import AdsReadWriteCommand
|
|
56
|
+
from aioads.commands.errors import AdsCommandError
|
|
55
57
|
from aioads.functions.ads_function import AdsFunctionSymbolGroup, IAdsFunction
|
|
56
58
|
from aioads.stream import AdsStream
|
|
57
59
|
from aioads.transport import ITransport
|
|
58
60
|
|
|
59
61
|
|
|
60
|
-
class AdsSumReadWrite(
|
|
61
|
-
IAdsFunction[list[tuple[AdsReadResponse, AdsStream]]]
|
|
62
|
-
):
|
|
62
|
+
class AdsSumReadWrite(IAdsFunction[list[tuple[AdsReadResponse, AdsStream]]]):
|
|
63
63
|
"""
|
|
64
64
|
ADS Sum Read/Write function to send a READ/WRITE Command in batch.
|
|
65
65
|
This function allows multiple read/write commands to be sent in a single request,
|
|
@@ -92,11 +92,9 @@ class AdsSumReadWrite(
|
|
|
92
92
|
:return: An async generator yielding tuples of (AdsReadResponse, AdsStream) for each command.
|
|
93
93
|
"""
|
|
94
94
|
if len(self.commands) == 0:
|
|
95
|
-
raise ValueError(
|
|
96
|
-
"At least one command is required for ADS Sum Read/Write")
|
|
95
|
+
raise ValueError("At least one command is required for ADS Sum Read/Write")
|
|
97
96
|
if len(self.commands) > 500:
|
|
98
|
-
raise ValueError(
|
|
99
|
-
"Too many commands for ADS Sum Read/Write, maximum is 500")
|
|
97
|
+
raise ValueError("Too many commands for ADS Sum Read/Write, maximum is 500")
|
|
100
98
|
|
|
101
99
|
payload = self.serialize()
|
|
102
100
|
total_read_length = sum(
|
|
@@ -117,15 +115,19 @@ class AdsSumReadWrite(
|
|
|
117
115
|
write_length=total_write_length,
|
|
118
116
|
write_data=payload,
|
|
119
117
|
)
|
|
120
|
-
|
|
118
|
+
header, read_payload = await command.request()
|
|
119
|
+
if not header.error_code.ok:
|
|
120
|
+
raise AdsCommandError(
|
|
121
|
+
header.error_code, "Failed to execute ADS Sum Read/Write"
|
|
122
|
+
)
|
|
121
123
|
read_response_stream = read_payload.sub_stream(
|
|
122
|
-
len(self.commands) * AdsReadResponse.STRUCT_DEF.size
|
|
124
|
+
len(self.commands) * AdsReadResponse.STRUCT_DEF.size
|
|
125
|
+
)
|
|
123
126
|
|
|
124
127
|
response: list[tuple[AdsReadResponse, AdsStream]] = []
|
|
125
128
|
for _ in self.commands:
|
|
126
129
|
read_response = AdsReadResponse.deserialize(read_response_stream)
|
|
127
|
-
response.append(
|
|
128
|
-
read_response,
|
|
129
|
-
|
|
130
|
-
))
|
|
130
|
+
response.append(
|
|
131
|
+
(read_response, read_payload.sub_stream(read_response.length))
|
|
132
|
+
)
|
|
131
133
|
return response
|
|
@@ -36,11 +36,13 @@ packet
|
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
"""
|
|
39
|
+
|
|
39
40
|
from dataclasses import dataclass
|
|
40
41
|
from struct import Struct
|
|
41
42
|
from typing import ClassVar
|
|
42
43
|
from aioads.ams_address import AmsAddress
|
|
43
44
|
from aioads.commands.ads_read_write import AdsReadWriteCommand
|
|
45
|
+
from aioads.commands.errors import AdsCommandError
|
|
44
46
|
from aioads.functions.ads_function import AdsFunctionSymbolGroup, IAdsFunction
|
|
45
47
|
from aioads.functions.ads_symbol_info_by_name_ex import (
|
|
46
48
|
AdsSymbolDataType,
|
|
@@ -75,8 +77,7 @@ class AdsDatatypeArrayInfo:
|
|
|
75
77
|
"""
|
|
76
78
|
Create `AdsDatatypeArrayInfo` from the `AdsStream`
|
|
77
79
|
"""
|
|
78
|
-
l_bound, e_elements = data.read_struct(
|
|
79
|
-
AdsDatatypeArrayInfo.STRUCT_DEF)
|
|
80
|
+
l_bound, e_elements = data.read_struct(AdsDatatypeArrayInfo.STRUCT_DEF)
|
|
80
81
|
return AdsDatatypeArrayInfo(
|
|
81
82
|
l_bound=l_bound,
|
|
82
83
|
e_elements=e_elements,
|
|
@@ -227,6 +228,10 @@ class AdsSymbolDataTypeByName(IAdsFunction[SymbolDataTypeResponse]):
|
|
|
227
228
|
write_length=len(payload),
|
|
228
229
|
read_length=0xFFFF, # Max read length
|
|
229
230
|
)
|
|
230
|
-
|
|
231
|
+
header, read_payload = await command.request()
|
|
232
|
+
if not header.error_code.ok:
|
|
233
|
+
raise AdsCommandError(
|
|
234
|
+
header.error_code, "Failed to read symbol datatype by name"
|
|
235
|
+
)
|
|
231
236
|
symbol_datatype = SymbolDataTypeResponse.deserialize(read_payload)
|
|
232
237
|
return symbol_datatype
|
|
@@ -6,6 +6,7 @@ https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_adsdll2/124
|
|
|
6
6
|
|
|
7
7
|
from aioads.ams_address import AmsAddress
|
|
8
8
|
from aioads.commands.ads_read import AdsReadCommand
|
|
9
|
+
from aioads.commands.errors import AdsCommandError
|
|
9
10
|
from aioads.functions.ads_function import AdsFunctionSymbolGroup, IAdsFunction
|
|
10
11
|
from aioads.functions.ads_symbol_datatype_by_name import SymbolDataTypeResponse
|
|
11
12
|
from aioads.transport import ITransport
|
|
@@ -38,7 +39,9 @@ class AdsSymbolDataTypeUpload(IAdsFunction[list[SymbolDataTypeResponse]]):
|
|
|
38
39
|
idx_offset=0,
|
|
39
40
|
length=self.dt_size,
|
|
40
41
|
)
|
|
41
|
-
|
|
42
|
+
header, read_payload = await command.request()
|
|
43
|
+
if not header.error_code.ok:
|
|
44
|
+
raise AdsCommandError(header.error_code, "Failed to read datatype info")
|
|
42
45
|
|
|
43
46
|
symbol_datatypes = list[SymbolDataTypeResponse]()
|
|
44
47
|
start = read_payload.tell()
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""
|
|
2
|
-
This module provides models and ads function to get the symbol info (symbol metadata) by the variable / symbol name.
|
|
2
|
+
This module provides models and ads function to get the symbol info (symbol metadata) by the variable / symbol name.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
from dataclasses import dataclass
|
|
@@ -9,6 +9,7 @@ from typing import ClassVar
|
|
|
9
9
|
from aioads.ads_error_codes import AdsErrorCode
|
|
10
10
|
from aioads.ams_address import AmsAddress
|
|
11
11
|
from aioads.commands.ads_read_write import AdsReadWriteCommand
|
|
12
|
+
from aioads.commands.errors import AdsCommandError
|
|
12
13
|
from aioads.functions.ads_function import AdsFunctionSymbolGroup, IAdsFunction
|
|
13
14
|
from aioads.functions.ads_sum_read_write import AdsSumReadWrite
|
|
14
15
|
from aioads.stream import AdsStream
|
|
@@ -113,10 +114,8 @@ class SymbolInfo:
|
|
|
113
114
|
type_name_length,
|
|
114
115
|
comment_length,
|
|
115
116
|
) = data.read_struct(SymbolInfo.FIXED_STRUCT)
|
|
116
|
-
symbol_name = data.read(symbol_name_length + 1).rstrip(
|
|
117
|
-
|
|
118
|
-
type_name = data.read(type_name_length + 1).rstrip(
|
|
119
|
-
b"\x00").decode("cp1252")
|
|
117
|
+
symbol_name = data.read(symbol_name_length + 1).rstrip(b"\x00").decode("cp1252")
|
|
118
|
+
type_name = data.read(type_name_length + 1).rstrip(b"\x00").decode("cp1252")
|
|
120
119
|
comment = data.read(comment_length + 1).rstrip(b"\x00").decode("cp1252")
|
|
121
120
|
|
|
122
121
|
# Move the stream position to the end of the entry
|
|
@@ -133,6 +132,20 @@ class SymbolInfo:
|
|
|
133
132
|
comment=comment,
|
|
134
133
|
)
|
|
135
134
|
|
|
135
|
+
@classmethod
|
|
136
|
+
def void(cls) -> "SymbolInfo":
|
|
137
|
+
"""A void symbol info that can be used as a placeholder"""
|
|
138
|
+
return cls(
|
|
139
|
+
idx_group=0,
|
|
140
|
+
idx_offset=0,
|
|
141
|
+
idx_length=0,
|
|
142
|
+
data_type=AdsSymbolDataType.VOID,
|
|
143
|
+
symbol_flags=AdsSymbolFlags(0),
|
|
144
|
+
symbol_name="",
|
|
145
|
+
type_name="",
|
|
146
|
+
comment="",
|
|
147
|
+
)
|
|
148
|
+
|
|
136
149
|
|
|
137
150
|
class SymbolInfoByNameEx(IAdsFunction[SymbolInfo]):
|
|
138
151
|
"""
|
|
@@ -165,14 +178,14 @@ class SymbolInfoByNameEx(IAdsFunction[SymbolInfo]):
|
|
|
165
178
|
read_length=0xFFFF, # Max read length
|
|
166
179
|
write_data=payload,
|
|
167
180
|
)
|
|
168
|
-
|
|
181
|
+
header, read_payload = await command.request()
|
|
182
|
+
if not header.error_code.ok:
|
|
183
|
+
raise AdsCommandError(header.error_code, "Failed to read symbol info")
|
|
169
184
|
symbol_info = SymbolInfo.deserialize(read_payload)
|
|
170
185
|
return symbol_info
|
|
171
186
|
|
|
172
187
|
|
|
173
|
-
class SymbolInfoByNameExSumRead(
|
|
174
|
-
IAdsFunction[list[tuple[AdsErrorCode, SymbolInfo]]]
|
|
175
|
-
):
|
|
188
|
+
class SymbolInfoByNameExSumRead(IAdsFunction[list[tuple[AdsErrorCode, SymbolInfo]]]):
|
|
176
189
|
"""
|
|
177
190
|
This function utilizes the `AdsSumReadWrite` function to
|
|
178
191
|
send multiple `SymbolInfoByNameEx` function calls in a batch.
|
|
@@ -219,9 +232,14 @@ class SymbolInfoByNameExSumRead(
|
|
|
219
232
|
command = AdsSumReadWrite(
|
|
220
233
|
transport=self.transport,
|
|
221
234
|
ams_address=self.ams_address,
|
|
222
|
-
commands=commands[batch_start:batch_start + self.BATCH_SIZE],
|
|
235
|
+
commands=commands[batch_start : batch_start + self.BATCH_SIZE],
|
|
223
236
|
)
|
|
224
|
-
for
|
|
237
|
+
for header, read_payload in await command.execute():
|
|
238
|
+
# If we have an error and no payload we return a void symbol info
|
|
239
|
+
# we raise no exception to let the client handle the error for each symbol individually
|
|
240
|
+
if not header.error_code.ok and read_payload.length == 0:
|
|
241
|
+
response.append((header.error_code, SymbolInfo.void()))
|
|
242
|
+
continue
|
|
225
243
|
symbol_info = SymbolInfo.deserialize(read_payload)
|
|
226
|
-
response.append((
|
|
244
|
+
response.append((header.error_code, symbol_info))
|
|
227
245
|
return response
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
This module contains the ads function call for requesting the `SymbolTableVersion`.
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
This can be used to monitoring, on change the index offsets in symbol metadata can change
|
|
5
|
+
This can be used to monitoring, on change the index offsets in symbol metadata can change
|
|
6
6
|
and we need to re resolve the new address where we can read this symbol, if we don't do this
|
|
7
7
|
we read a random memory array we most likely can't parse.
|
|
8
8
|
https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_adsdll2/124830987.html&id=
|
|
@@ -42,8 +42,9 @@ class SymbolTableVersion(IAdsFunction[int]):
|
|
|
42
42
|
idx_offset=0,
|
|
43
43
|
length=1,
|
|
44
44
|
)
|
|
45
|
-
|
|
46
|
-
if not
|
|
47
|
-
raise AdsCommandError(
|
|
48
|
-
|
|
45
|
+
header, read_stream = await command.request()
|
|
46
|
+
if not header.error_code.ok:
|
|
47
|
+
raise AdsCommandError(
|
|
48
|
+
header.error_code, "Failed to read symbol table version"
|
|
49
|
+
)
|
|
49
50
|
return read_stream.read_struct(self.VERSION_STRUCT_DEF)[0]
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"""
|
|
2
|
-
This module contains a ads function to acquire the symbol infos (metadata) of the global / root symbols.
|
|
2
|
+
This module contains a ads function to acquire the symbol infos (metadata) of the global / root symbols.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
from aioads.ams_address import AmsAddress
|
|
6
6
|
from aioads.commands.ads_read import AdsReadCommand
|
|
7
|
+
from aioads.commands.errors import AdsCommandError
|
|
7
8
|
from aioads.functions.ads_function import AdsFunctionSymbolGroup, IAdsFunction
|
|
8
9
|
from aioads.functions.ads_symbol_info_by_name_ex import SymbolInfo
|
|
9
10
|
from aioads.transport import ITransport
|
|
@@ -11,8 +12,8 @@ from aioads.transport import ITransport
|
|
|
11
12
|
|
|
12
13
|
class AdsSymbolUpload(IAdsFunction[list[SymbolInfo]]):
|
|
13
14
|
"""
|
|
14
|
-
Ads Function to read all global symbols.
|
|
15
|
-
Hint:
|
|
15
|
+
Ads Function to read all global symbols.
|
|
16
|
+
Hint:
|
|
16
17
|
Only the top most symbol information are returned, to get the full ads tree
|
|
17
18
|
you need to resolve it from this over the datatypes that can be requested with `AdsSymbolDataTypeUpload`
|
|
18
19
|
"""
|
|
@@ -36,7 +37,12 @@ class AdsSymbolUpload(IAdsFunction[list[SymbolInfo]]):
|
|
|
36
37
|
idx_offset=0,
|
|
37
38
|
length=self.tree_size,
|
|
38
39
|
)
|
|
39
|
-
|
|
40
|
+
header, read_payload = await command.request()
|
|
41
|
+
if not header.error_code.ok:
|
|
42
|
+
raise AdsCommandError(
|
|
43
|
+
header.error_code, "Failed to request symbol upload info"
|
|
44
|
+
)
|
|
45
|
+
|
|
40
46
|
symbol_infos = list[SymbolInfo]()
|
|
41
47
|
|
|
42
48
|
start = read_payload.tell()
|
|
@@ -10,6 +10,7 @@ from typing import ClassVar
|
|
|
10
10
|
|
|
11
11
|
from aioads.ams_address import AmsAddress
|
|
12
12
|
from aioads.commands.ads_read import AdsReadCommand
|
|
13
|
+
from aioads.commands.errors import AdsCommandError
|
|
13
14
|
from aioads.functions.ads_function import AdsFunctionSymbolGroup, IAdsFunction
|
|
14
15
|
|
|
15
16
|
from aioads.stream import AdsStream
|
|
@@ -46,11 +47,9 @@ class SymbolUploadInfo2Response:
|
|
|
46
47
|
@classmethod
|
|
47
48
|
def deserialize(cls, data: AdsStream) -> "SymbolUploadInfo2Response":
|
|
48
49
|
"""
|
|
49
|
-
Create `SymbolUploadInfo2Response` from the `AdsStream`
|
|
50
|
+
Create `SymbolUploadInfo2Response` from the `AdsStream`
|
|
50
51
|
"""
|
|
51
|
-
parsed: tuple[
|
|
52
|
-
int, int, int, int, int, int
|
|
53
|
-
] = data.read_struct(cls.STRUCT_DEF)
|
|
52
|
+
parsed: tuple[int, int, int, int, int, int] = data.read_struct(cls.STRUCT_DEF)
|
|
54
53
|
return cls(
|
|
55
54
|
symbol_cnt=parsed[0],
|
|
56
55
|
symbol_size=parsed[1],
|
|
@@ -63,7 +62,7 @@ class SymbolUploadInfo2Response:
|
|
|
63
62
|
|
|
64
63
|
class AdsSymbolUploadInfo2(IAdsFunction[SymbolUploadInfo2Response]):
|
|
65
64
|
"""
|
|
66
|
-
Function to acquire basic symbol information
|
|
65
|
+
Function to acquire basic symbol information
|
|
67
66
|
"""
|
|
68
67
|
|
|
69
68
|
def __init__(self, transport: ITransport, ams_address: AmsAddress) -> None:
|
|
@@ -83,7 +82,10 @@ class AdsSymbolUploadInfo2(IAdsFunction[SymbolUploadInfo2Response]):
|
|
|
83
82
|
# 6 x 4 bytes (We expect a struct with 6x UINT32)
|
|
84
83
|
length=SymbolUploadInfo2Response.STRUCT_DEF.size,
|
|
85
84
|
)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
header, read_payload = await command.request()
|
|
86
|
+
if not header.error_code.ok:
|
|
87
|
+
raise AdsCommandError(
|
|
88
|
+
header.error_code, "Failed to request symbol upload info"
|
|
89
|
+
)
|
|
90
|
+
symbol_upload_info = SymbolUploadInfo2Response.deserialize(read_payload)
|
|
89
91
|
return symbol_upload_info
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/functions/test_ads_symbol_datatype_by_name.py
RENAMED
|
File without changes
|
{aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/functions/test_ads_symbol_datatype_upload.py
RENAMED
|
File without changes
|
{aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/functions/test_ads_symbol_info_by_name_ex.py
RENAMED
|
File without changes
|
{aioads-0.1.0.dev5 → aioads-0.1.0.dev6}/tests/unit/functions/test_ads_symbol_table_version.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|