scietex.hal.adc 0.0.1__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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Anton Bondarenko
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,56 @@
1
+ Metadata-Version: 2.4
2
+ Name: scietex.hal.adc
3
+ Version: 0.0.1
4
+ Summary: Scietex ADC HAL package
5
+ Author-email: Anton Bondarenko <bond.anton@gmail.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2025 Anton Bondarenko
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+ Project-URL: Homepage, https://github.com/bond-anton/scietex.hal.adc
28
+ Project-URL: Bug Tracker, https://github.com/bond-anton/scietex.hal.adc/issues
29
+ Classifier: Programming Language :: Python :: 3
30
+ Classifier: License :: OSI Approved :: MIT License
31
+ Classifier: Operating System :: OS Independent
32
+ Requires-Python: >=3.10
33
+ Description-Content-Type: text/markdown
34
+ License-File: LICENSE
35
+ Requires-Dist: msgspec[yaml]>=0.20.0
36
+ Requires-Dist: scietex.hal.serial<2.0.0,>=1.3.0
37
+ Provides-Extra: dev
38
+ Requires-Dist: tox>=4.45.0; extra == "dev"
39
+ Provides-Extra: test
40
+ Requires-Dist: pytest; extra == "test"
41
+ Requires-Dist: pytest-asyncio; extra == "test"
42
+ Provides-Extra: lint
43
+ Requires-Dist: ruff; extra == "lint"
44
+ Dynamic: license-file
45
+
46
+ # scietex.hal.adc
47
+
48
+ The `scietex.hal.adc` package is a Python library for interfacing with ADC.
49
+ It provides an abstract class `ADC`, and a base class for ADCs with RS485 communication
50
+ interface, which in its turn inherits `scietex.hal.serial.RS485Client`.
51
+ The concrete implementation for the ADC manufactured by Scietex is provided.
52
+
53
+
54
+ ## License
55
+
56
+ This project is licensed under the **MIT License** - see the LICENSE file for details.
@@ -0,0 +1,11 @@
1
+ # scietex.hal.adc
2
+
3
+ The `scietex.hal.adc` package is a Python library for interfacing with ADC.
4
+ It provides an abstract class `ADC`, and a base class for ADCs with RS485 communication
5
+ interface, which in its turn inherits `scietex.hal.serial.RS485Client`.
6
+ The concrete implementation for the ADC manufactured by Scietex is provided.
7
+
8
+
9
+ ## License
10
+
11
+ This project is licensed under the **MIT License** - see the LICENSE file for details.
@@ -0,0 +1,39 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "scietex.hal.adc"
7
+ dynamic = ["version"]
8
+ description = "Scietex ADC HAL package"
9
+ authors = [{ name = "Anton Bondarenko", email = "bond.anton@gmail.com" }]
10
+ license = { file = "LICENSE" }
11
+ readme = "README.md"
12
+ classifiers = [
13
+ "Programming Language :: Python :: 3",
14
+ "License :: OSI Approved :: MIT License",
15
+ "Operating System :: OS Independent",
16
+ ]
17
+ requires-python = ">=3.10"
18
+ dependencies = [
19
+ "msgspec[yaml] >= 0.20.0",
20
+ "scietex.hal.serial >= 1.3.0, < 2.0.0",
21
+ ]
22
+
23
+ [project.urls]
24
+ "Homepage" = "https://github.com/bond-anton/scietex.hal.adc"
25
+ "Bug Tracker" = "https://github.com/bond-anton/scietex.hal.adc/issues"
26
+
27
+ [project.optional-dependencies]
28
+ dev = ["tox>=4.45.0"]
29
+ test = ["pytest", "pytest-asyncio"]
30
+ lint = ["ruff"]
31
+
32
+ [tool.setuptools.dynamic]
33
+ version = { attr = "scietex.hal.adc.version.__version__" }
34
+
35
+ [tool.setuptools.package-data]
36
+ "scietex.hal.adc" = ["py.typed"]
37
+
38
+ [tool.setuptools.packages.find]
39
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,6 @@
1
+ """ADC HAL module"""
2
+
3
+ from .base import ADC
4
+ from .version import __version__
5
+
6
+ __all__ = ["__version__", "ADC"]
@@ -0,0 +1,5 @@
1
+ """Base ADC classes to be inherited in particular device implementation."""
2
+
3
+ from .adc import ADC
4
+
5
+ __all__ = ["ADC"]
@@ -0,0 +1,88 @@
1
+ """ADC abstract interface."""
2
+
3
+ from abc import ABC, abstractmethod
4
+
5
+ from .data import ADCError, ADCParameters, VoltageTuple
6
+
7
+
8
+ class ADC(ABC):
9
+ """ADC interface class."""
10
+
11
+ channels_number: int = 1
12
+
13
+ error_codes: dict[int, ADCError] = {0: ADCError(code=0, message="No error")}
14
+ error_codes_com: dict[int, ADCError] = {0: ADCError(code=0, message="No error")}
15
+
16
+ # Error processing methods
17
+ @abstractmethod
18
+ async def get_error_code(self, comm: bool = False) -> int:
19
+ """Read error code from the device"""
20
+
21
+ def parse_error_code(self, code: int, comm: bool = False) -> ADCError:
22
+ """Parse error code from the device"""
23
+ if comm:
24
+ if code in self.error_codes_com:
25
+ return self.error_codes_com[code]
26
+ else:
27
+ if code in self.error_codes:
28
+ return self.error_codes[code]
29
+ return ADCError(code=code, message="Unknown error")
30
+
31
+ @abstractmethod
32
+ async def clear_error(self, comm: bool = False) -> int:
33
+ """Clear error from the device."""
34
+
35
+ # Device information methods
36
+ @abstractmethod
37
+ async def get_vendor(self) -> str:
38
+ """Get device vendor name."""
39
+
40
+ @abstractmethod
41
+ async def get_product_name(self) -> str:
42
+ """Get device product name."""
43
+
44
+ @abstractmethod
45
+ async def get_serial_number(self) -> str:
46
+ """Get device serial number."""
47
+
48
+ @abstractmethod
49
+ async def get_version(self) -> str:
50
+ """get device firmware version."""
51
+
52
+ # ADC measurement setup
53
+
54
+ # @abstractmethod
55
+ # async def get_mcu_frequency(self) -> int:
56
+ # """GET MCU frequency."""
57
+
58
+ # @abstractmethod
59
+ # async def get_gate_time(self) -> float:
60
+ # """Get gate time in ms"""
61
+
62
+ # @abstractmethod
63
+ # async def set_gate_time(self, gate_time_ms: float) -> float:
64
+ # """Set gate time in ms"""
65
+
66
+ # @abstractmethod
67
+ # async def get_averaging(self) -> int:
68
+ # """Get averaging window"""
69
+
70
+ # @abstractmethod
71
+ # async def set_averaging(self, averaging_window: int) -> int:
72
+ # """Set averaging window."""
73
+
74
+ # Voltage measurement methods
75
+
76
+ @abstractmethod
77
+ async def get_voltage(self) -> VoltageTuple:
78
+ """Get all channels voltages."""
79
+
80
+ @abstractmethod
81
+ async def get_channel_voltage(self, channel: int) -> float | None:
82
+ """Get voltage value for a specific channel."""
83
+
84
+ # Read ADC parameters in single call
85
+
86
+ @abstractmethod
87
+ async def read_parameters(self) -> ADCParameters:
88
+ """Read ADC Parameters"""
@@ -0,0 +1,69 @@
1
+ """Data models for the ADC."""
2
+
3
+ # from enum import Enum
4
+
5
+ import msgspec
6
+
7
+ # class OutCTRLMode(Enum):
8
+ # """Modes of the control output."""
9
+
10
+ # HIGH = 1
11
+ # LOW = 2
12
+ # MANUAL = 3
13
+ # DISABLED = 4
14
+
15
+
16
+ # class PwmCTRLMode(Enum):
17
+ # """Modes of the PWM output."""
18
+
19
+ # ABSOLUTE = 1
20
+ # RELATIVE = 2
21
+ # MANUAL = 3
22
+ # DISABLED = 4
23
+
24
+
25
+ class ADCError(msgspec.Struct, frozen=True):
26
+ """Model of an ADC error with code and message."""
27
+
28
+ code: int
29
+ message: str = "Unknown error"
30
+
31
+ def __str__(self) -> str:
32
+ return f"ADCError(code={self.code}, message='{self.message}')"
33
+
34
+
35
+ VoltageTuple = tuple[float | None, ...]
36
+
37
+
38
+ class ADCParameters(msgspec.Struct, frozen=True):
39
+ """ADC parameters schema."""
40
+
41
+ connected: bool = False # ADC connection status
42
+ channels_number: int | None = None # Number of ADC channels
43
+ voltage: VoltageTuple | None = None # Channel voltages
44
+
45
+ def __str__(self) -> str:
46
+ """Human-readable representation."""
47
+ if self.voltage is None:
48
+ voltage_str = "None"
49
+ elif not self.voltage:
50
+ voltage_str = "[]"
51
+ else:
52
+ voltage_strs = [f"{v:.2f} V" if v is not None else "N/A" for v in self.voltage]
53
+ voltage_str = f"[{', '.join(voltage_strs)}]"
54
+
55
+ return (
56
+ f"ADCParameters("
57
+ f"channels_number={self.channels_number}, "
58
+ f"voltage={voltage_str}, "
59
+ f"connected={self.connected})"
60
+ )
61
+
62
+ def __repr__(self) -> str:
63
+ """Official string representation (used in debugging)."""
64
+ return (
65
+ f"ADCParameters("
66
+ f"connected={self.connected!r}, "
67
+ f"channels_number={self.channels_number!r}, "
68
+ f"voltage={self.voltage!r})"
69
+ )
@@ -0,0 +1,5 @@
1
+ """RS485 devices."""
2
+
3
+ from .adc import RS485ADC
4
+
5
+ __all__ = ["RS485ADC"]
@@ -0,0 +1,152 @@
1
+ """Lock-in amplifier with RS485 communication interface."""
2
+
3
+ from logging import Logger
4
+ from typing import Any
5
+
6
+ from pymodbus.framer import FramerBase
7
+ from pymodbus.pdu import DecodePDU, ModbusPDU
8
+ from scietex.hal.serial import (
9
+ ModbusSerialConnectionConfig,
10
+ RS485Client,
11
+ SerialConnectionConfig,
12
+ )
13
+
14
+ from ...version import __version__
15
+ from .. import ADC
16
+ from ..data import ADCParameters, VoltageTuple
17
+
18
+
19
+ class RS485ADC(ADC, RS485Client):
20
+ """ADC with RS485 communication interface."""
21
+
22
+ def __init__(
23
+ self,
24
+ channels_number: int,
25
+ con_params: SerialConnectionConfig | ModbusSerialConnectionConfig,
26
+ address: int = 1,
27
+ label: str = "RS485 ADC",
28
+ custom_framer: type[FramerBase] | None = None,
29
+ custom_decoder: type[DecodePDU] | None = None,
30
+ custom_response: list[type[ModbusPDU]] | None = None,
31
+ chunk_size: int | None = None,
32
+ write_chunk_size: int | None = None,
33
+ logger: Logger | None = None,
34
+ **kwargs,
35
+ ):
36
+ RS485Client.__init__(
37
+ self,
38
+ con_params=con_params,
39
+ address=address,
40
+ custom_framer=custom_framer,
41
+ custom_decoder=custom_decoder,
42
+ custom_response=custom_response,
43
+ chunk_size=chunk_size,
44
+ write_chunk_size=write_chunk_size,
45
+ logger=logger,
46
+ )
47
+ self.channels_number = channels_number
48
+
49
+ # Error processing methods
50
+
51
+ async def get_error_code(self, comm: bool = False) -> int:
52
+ """Read error code from the ADC."""
53
+ code = 0
54
+ if comm:
55
+ self.logger.debug("%s: Communication error code %d.", self.label, code)
56
+ else:
57
+ self.logger.debug("%s: Error code %d.", self.label, code)
58
+ return code
59
+
60
+ async def clear_error(self, comm: bool = False) -> int:
61
+ """Clear error from the ADC."""
62
+ if comm:
63
+ self.logger.debug("%s: Clear communication error.", self.label)
64
+ else:
65
+ self.logger.debug("%s: Clear error.", self.label)
66
+ return await self.get_error_code()
67
+
68
+ # Device information methods
69
+
70
+ async def get_vendor(self) -> str:
71
+ """Get ADC vendor name."""
72
+ vendor: str = "n/d"
73
+ self.logger.debug("%s vendor: %s", self.label, vendor)
74
+ return vendor
75
+
76
+ async def get_product_name(self) -> str:
77
+ """Get ADC product name."""
78
+ self.logger.debug("%s prod. name: %s", self.label, self.label)
79
+ return self.label
80
+
81
+ async def get_serial_number(self) -> str:
82
+ """Get ADC serial number."""
83
+ sn = "n/d"
84
+ self.logger.debug("%s SN: %s", self.label, sn)
85
+ return sn
86
+
87
+ async def get_version(self) -> str:
88
+ """Get ADC firmware version."""
89
+ self.logger.debug("%s version: %s.", self.label, __version__)
90
+ return __version__
91
+
92
+ # Voltage measurement methods
93
+
94
+ async def get_voltage(self) -> VoltageTuple:
95
+ """Get all channels voltages."""
96
+ self.logger.debug("%s: get_voltage call", self.label)
97
+ voltage: VoltageTuple = (None,) * self.channels_number
98
+ return voltage
99
+
100
+ async def get_channel_voltage(self, channel: int) -> float | None:
101
+ """Get X channel voltage value."""
102
+ self.logger.debug("%s: get_channel_voltage[%d] call", self.label, channel)
103
+ return None
104
+
105
+ # RS485 address and baudrate
106
+
107
+ async def get_address(self) -> int:
108
+ """Get RS-485 address."""
109
+ self.logger.debug("%s: get_address call", self.label)
110
+ return 1
111
+
112
+ async def set_address(self, address: int) -> int:
113
+ """Set RS-485 address."""
114
+ self.logger.debug("%s: set_address(%d) call", self.label, address)
115
+ return await self.get_address()
116
+
117
+ async def get_baudrate(self) -> int:
118
+ """Get RS-485 baudrate value."""
119
+ self.logger.debug("%s: get_baudrate call", self.label)
120
+ return 9600
121
+
122
+ async def set_baudrate(self, baudrate: int) -> int:
123
+ """Set RS-485 baudrate."""
124
+ self.logger.debug("%s: set_baudrate(%d) call", self.label, baudrate)
125
+ return await self.get_baudrate()
126
+
127
+ async def check_connection(self) -> bool:
128
+ """Set RS-485 baudrate."""
129
+ self.logger.debug("%s: check_connection call", self.label)
130
+ return False
131
+
132
+ # Read Lock-in state in a single request
133
+
134
+ async def read_parameters(self) -> ADCParameters:
135
+ """Read ADC Parameters."""
136
+ self.logger.debug("%s: read_parameters call", self.label)
137
+ voltage: VoltageTuple = await self.get_voltage()
138
+ connected: bool = await self.check_connection()
139
+ parameters = ADCParameters(
140
+ channels_number=self.channels_number,
141
+ voltage=voltage,
142
+ connected=connected,
143
+ )
144
+ return parameters
145
+
146
+ async def read_data(self) -> dict[str, int | float | list[int | float]]:
147
+ """Read Lockin data in a single request."""
148
+ parameters = await self.read_parameters()
149
+ return {f: getattr(parameters, f) for f in parameters.__struct_fields__}
150
+
151
+ async def process_message(self, message: dict[str, Any]) -> None:
152
+ await super().process_message(message)
File without changes
@@ -0,0 +1,5 @@
1
+ """Scietex drivers."""
2
+
3
+ from .vdp_adc import VdpADC
4
+
5
+ __all__ = ["VdpADC"]
@@ -0,0 +1,21 @@
1
+ """Scietex-related utilities."""
2
+
3
+
4
+ def baudrate_check(baudrate: int) -> int:
5
+ """Adjust baudrate to the supported values."""
6
+ if baudrate <= 9600:
7
+ return 9600
8
+ if baudrate <= 14400:
9
+ return 14400
10
+ if baudrate <= 19200:
11
+ return 19200
12
+ if baudrate <= 38400:
13
+ return 38400
14
+ if baudrate <= 57600:
15
+ return 57600
16
+ return 115200
17
+
18
+
19
+ def address_check(address: int) -> int:
20
+ """Adjust address to the supported values."""
21
+ return max(1, min(address, 247))
@@ -0,0 +1,149 @@
1
+ """Scietex VdpADC."""
2
+
3
+ from logging import Logger
4
+
5
+ from scietex.hal.serial import ModbusSerialConnectionConfig
6
+ from scietex.hal.serial.utilities.numeric import ByteOrder, combine_32bit, float_from_int
7
+
8
+ from ..base.data import ADCParameters, VoltageTuple
9
+ from ..base.rs485 import RS485ADC
10
+
11
+ VOLTAGE_SCALE = 100
12
+
13
+
14
+ class VdpADC(RS485ADC):
15
+ """Scietex Van der Pauw ADC RS485 driver."""
16
+
17
+ def __init__(
18
+ self,
19
+ con_params: ModbusSerialConnectionConfig,
20
+ address: int = 1,
21
+ label: str = "Scietex Van der Pauw ADC",
22
+ logger: Logger | None = None,
23
+ chunk_size: int | None = 8,
24
+ write_chunk_size: int | None = 8,
25
+ **kwargs,
26
+ ):
27
+
28
+ con_params.framer = "RTU"
29
+ super().__init__(
30
+ channels_number=4,
31
+ con_params=con_params,
32
+ address=address,
33
+ label=label,
34
+ logger=logger,
35
+ chunk_size=chunk_size,
36
+ write_chunk_size=write_chunk_size,
37
+ **kwargs,
38
+ )
39
+
40
+ async def get_vendor(self) -> str:
41
+ response = await self.read_registers(0, 10, holding=False)
42
+ if response is not None:
43
+ return bytes(response).decode()
44
+ return ""
45
+
46
+ async def get_product_name(self) -> str:
47
+ response = await self.read_registers(10, 10, holding=False)
48
+ if response is not None:
49
+ return bytes(response).decode()
50
+ return ""
51
+
52
+ async def get_version(self) -> str:
53
+ response = await self.read_registers(20, 3, holding=False)
54
+ if response is not None:
55
+ return f"{response[0]:d}.{response[1]:d}.{response[2]:d}"
56
+ return ""
57
+
58
+ async def get_serial_number(self) -> str:
59
+ response = await self.read_two_registers_int(
60
+ 10, holding=True, byteorder=ByteOrder.BIG_ENDIAN
61
+ )
62
+ if response is not None:
63
+ return f"{response:d}"
64
+ return ""
65
+
66
+ async def get_channel_voltage(self, channel: int) -> float | None:
67
+ ch_idx = max(0, min(channel, self.channels_number - 1))
68
+ start_register = 36 + ch_idx * 2
69
+ response = await self.read_two_registers_float(
70
+ start_register, holding=False, factor=VOLTAGE_SCALE, byteorder=ByteOrder.BIG_ENDIAN
71
+ )
72
+ if response is not None:
73
+ return float(response)
74
+ return None
75
+
76
+ async def get_voltage(self) -> VoltageTuple:
77
+ response = await self.read_registers(36, self.channels_number * 2, holding=False)
78
+ if response is not None and len(response) == self.channels_number * 2:
79
+ voltage = tuple(
80
+ float_from_int(combine_32bit(a, b, byteorder=ByteOrder.BIG_ENDIAN), VOLTAGE_SCALE)
81
+ if a is not None and b is not None
82
+ else None
83
+ for a, b in zip(response[::2], response[1::2])
84
+ )
85
+ return voltage
86
+ return (None,) * self.channels_number
87
+
88
+ async def get_address(self) -> int:
89
+ response = await self.read_register(0, holding=True)
90
+ if response is not None:
91
+ return response
92
+ return 0
93
+
94
+ async def set_address(self, address: int) -> int:
95
+ new_address = max(1, min(address, 247))
96
+ await self.write_register(0, new_address)
97
+ self.address = new_address
98
+ response = await self.get_address()
99
+ if response is not None and response > 0:
100
+ self.address = response
101
+ return response
102
+ return 0
103
+
104
+ async def get_baudrate(self) -> int:
105
+ response = await self.read_register(1, holding=True)
106
+ if response is not None:
107
+ if response == 0:
108
+ return 9600
109
+ elif response == 1:
110
+ return 19200
111
+ elif response == 2:
112
+ return 115200
113
+ return 0
114
+
115
+ async def set_baudrate(self, baudrate: int) -> int:
116
+ if baudrate <= 9600:
117
+ new_baudrate = 9600
118
+ baudrate_code = 0
119
+ elif baudrate <= 19200:
120
+ new_baudrate = 19200
121
+ baudrate_code = 1
122
+ else:
123
+ new_baudrate = 115200
124
+ baudrate_code = 5
125
+ response = await self.write_register(1, baudrate_code)
126
+ new_con_params = self.con_params
127
+ new_con_params.baudrate = new_baudrate
128
+ self.con_params = new_con_params
129
+ if response is not None:
130
+ return response
131
+ response = await self.read_register(1, holding=True)
132
+ if response is not None:
133
+ return response
134
+ return 0
135
+
136
+ async def check_connection(self):
137
+ vendor = await self.get_vendor()
138
+ if vendor:
139
+ return True
140
+ return False
141
+
142
+ async def read_parameters(self) -> ADCParameters:
143
+ voltage = await self.get_voltage()
144
+ parameters = ADCParameters(
145
+ connected=True,
146
+ channels_number=self.channels_number,
147
+ voltage=voltage,
148
+ )
149
+ return parameters
@@ -0,0 +1,8 @@
1
+ """
2
+ Module containing the package version information.
3
+
4
+ Attributes:
5
+ __version__ (str): The current version of the package.
6
+ """
7
+
8
+ __version__ = "0.0.1"
@@ -0,0 +1,56 @@
1
+ Metadata-Version: 2.4
2
+ Name: scietex.hal.adc
3
+ Version: 0.0.1
4
+ Summary: Scietex ADC HAL package
5
+ Author-email: Anton Bondarenko <bond.anton@gmail.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2025 Anton Bondarenko
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+ Project-URL: Homepage, https://github.com/bond-anton/scietex.hal.adc
28
+ Project-URL: Bug Tracker, https://github.com/bond-anton/scietex.hal.adc/issues
29
+ Classifier: Programming Language :: Python :: 3
30
+ Classifier: License :: OSI Approved :: MIT License
31
+ Classifier: Operating System :: OS Independent
32
+ Requires-Python: >=3.10
33
+ Description-Content-Type: text/markdown
34
+ License-File: LICENSE
35
+ Requires-Dist: msgspec[yaml]>=0.20.0
36
+ Requires-Dist: scietex.hal.serial<2.0.0,>=1.3.0
37
+ Provides-Extra: dev
38
+ Requires-Dist: tox>=4.45.0; extra == "dev"
39
+ Provides-Extra: test
40
+ Requires-Dist: pytest; extra == "test"
41
+ Requires-Dist: pytest-asyncio; extra == "test"
42
+ Provides-Extra: lint
43
+ Requires-Dist: ruff; extra == "lint"
44
+ Dynamic: license-file
45
+
46
+ # scietex.hal.adc
47
+
48
+ The `scietex.hal.adc` package is a Python library for interfacing with ADC.
49
+ It provides an abstract class `ADC`, and a base class for ADCs with RS485 communication
50
+ interface, which in its turn inherits `scietex.hal.serial.RS485Client`.
51
+ The concrete implementation for the ADC manufactured by Scietex is provided.
52
+
53
+
54
+ ## License
55
+
56
+ This project is licensed under the **MIT License** - see the LICENSE file for details.
@@ -0,0 +1,20 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/scietex.hal.adc.egg-info/PKG-INFO
5
+ src/scietex.hal.adc.egg-info/SOURCES.txt
6
+ src/scietex.hal.adc.egg-info/dependency_links.txt
7
+ src/scietex.hal.adc.egg-info/requires.txt
8
+ src/scietex.hal.adc.egg-info/top_level.txt
9
+ src/scietex/hal/adc/__init__.py
10
+ src/scietex/hal/adc/py.typed
11
+ src/scietex/hal/adc/version.py
12
+ src/scietex/hal/adc/base/__init__.py
13
+ src/scietex/hal/adc/base/adc.py
14
+ src/scietex/hal/adc/base/data.py
15
+ src/scietex/hal/adc/base/rs485/__init__.py
16
+ src/scietex/hal/adc/base/rs485/adc.py
17
+ src/scietex/hal/adc/scietex/__init__.py
18
+ src/scietex/hal/adc/scietex/utils.py
19
+ src/scietex/hal/adc/scietex/vdp_adc.py
20
+ tests/test_version.py
@@ -0,0 +1,12 @@
1
+ msgspec[yaml]>=0.20.0
2
+ scietex.hal.serial<2.0.0,>=1.3.0
3
+
4
+ [dev]
5
+ tox>=4.45.0
6
+
7
+ [lint]
8
+ ruff
9
+
10
+ [test]
11
+ pytest
12
+ pytest-asyncio
@@ -0,0 +1,47 @@
1
+ """Test package version is correctly set"""
2
+
3
+ import pytest
4
+
5
+ try:
6
+ from src.scietex.hal.adc import __version__ as version
7
+ except ModuleNotFoundError:
8
+ from scietex.hal.adc import __version__ as version
9
+
10
+
11
+ def test_check_version_numbering():
12
+ """
13
+ Version must be a string with the three integers separated by a dot.
14
+ Example: `0.1.4` or `2.0.0`.
15
+ All three digits must not negative and must not be equal to zero at the same time.
16
+ """
17
+ # Assert version is a string.
18
+ assert isinstance(version, str)
19
+
20
+ # Assert no extra space present. Example: " 0.1.1 " is not correct, "0.1.1" is correct.
21
+ assert len(version) == len(version.strip())
22
+
23
+ # Assert all three parts are present
24
+ v_l = version.split(".")
25
+ assert len(v_l) == 3
26
+
27
+ # Assert no extra space present in each part.
28
+ # Example: "0. 1 .1" is not correct, "0.1.1" is correct
29
+ for i in range(3):
30
+ assert len(v_l[i]) == len(v_l[i].strip())
31
+
32
+ # Convert all parts of the version to int values
33
+ v_maj = int(v_l[0])
34
+ v_min = int(v_l[1])
35
+ v_patch = int(v_l[2])
36
+
37
+ # Assert all version numbers are not negative
38
+ assert v_maj >= 0
39
+ assert v_min >= 0
40
+ assert v_patch >= 0
41
+
42
+ # Assert all version numbers are not equal to zero at the same time
43
+ assert v_maj + v_min + v_patch > 0
44
+
45
+
46
+ if __name__ == "__main__":
47
+ pytest.main()