From ec4e338f29c27f5aef4d61da9394cf284216dc4a Mon Sep 17 00:00:00 2001 From: Roberto-R Date: Thu, 30 Sep 2021 16:06:40 +0200 Subject: [PATCH] Added read/write by list feature for symbols (this branch was rebased on top of the refactor) --- pyads/connection.py | 138 ++++++++++++++++++++++++++++++++++++++++++++ pyads/pyads_ex.py | 4 +- pyads/symbol.py | 5 +- 3 files changed, 143 insertions(+), 4 deletions(-) diff --git a/pyads/connection.py b/pyads/connection.py index 16b19dd5..fbe7e9a9 100644 --- a/pyads/connection.py +++ b/pyads/connection.py @@ -68,13 +68,17 @@ adsGetNetIdForPLC, adsGetSymbolInfo, adsSumRead, + adsSumReadBytes, adsSumWrite, + adsSumWriteBytes, adsReleaseHandle, adsSyncReadByNameEx, adsSyncWriteByNameEx, adsSyncAddDeviceNotificationReqEx, adsSyncDelDeviceNotificationReqEx, adsSyncSetTimeoutEx, + get_value_from_ctype_data, + type_is_string, ) from .structs import ( AmsAddr, @@ -92,6 +96,7 @@ bytes_from_dict, size_of_structure, ) +from .errorcodes import ERROR_CODES from .symbol import AdsSymbol from .utils import decode_ads @@ -800,6 +805,139 @@ def write_structure_by_name( data_name, byte_values, c_ubyte * structure_size, handle=handle ) + def read_list_of_symbols( + self, + symbols: List[AdsSymbol], + ads_sub_commands: int = MAX_ADS_SUB_COMMANDS, + ): + """Read new values for a list of AdsSymbols using a single ADS call. + + The outputs will be returned as a dictionary, but the cache of each symbol will + be updated too. + + Comparable to :meth:`Connection.read_list_by_name`. + See also :class:`pyads.AdsSymbol`. + + :param symbols: List if symbol instances + :param ads_sub_commands: Max. number of symbols per call (see + `read_list_by_name`) + """ + + # Relying on `adsSumRead()` is tricky, because we do not have the `dataType` + # (integer) for each symbol, we only have the ctypes-type. + # Instead a very similar low-level read is done. + + # Allocate return dict + result = {symbol.name: None for symbol in symbols} + + symbol_infos = [(sym.index_group, sym.index_offset, sizeof(sym.plc_type)) + for sym in symbols] + + sum_response = adsSumReadBytes(self._port, self._adr, symbol_infos) + + data_start = 4 * len(symbols) + offset = data_start + + for i, symbol in enumerate(symbols): + + if symbol.is_structure: + raise ValueError("Method not available for structured variables") + + # Check if read was successful for this variable + error = struct.unpack_from("