This repository was archived by the owner on Mar 16, 2023. It is now read-only.
forked from gijzelaerr/python-snap7
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathcommon.py
More file actions
152 lines (122 loc) · 4.39 KB
/
common.py
File metadata and controls
152 lines (122 loc) · 4.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import os
import sys
import logging
import pathlib
import platform
from ctypes import c_char
from typing import Optional
from ctypes.util import find_library
if platform.system() == 'Windows':
from ctypes import windll as cdll # type: ignore
else:
from ctypes import cdll
logger = logging.getLogger(__name__)
# regexp for checking if an ipv4 address is valid.
ipv4 = r"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"
class ADict(dict):
"""
Accessing dict keys like an attribute.
"""
__getattr__ = dict.__getitem__
__setattr__ = dict.__setitem__ # type: ignore
class Snap7Library:
"""Snap7 loader and encapsulator. We make this a singleton to make
sure the library is loaded only once.
Attributes:
lib_location: full path to the `snap7.dll` file. Optional.
"""
_instance = None
lib_location: Optional[str]
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = object.__new__(cls)
cls._instance.lib_location = None
cls._instance.cdll = None
return cls._instance
def __init__(self, lib_location: Optional[str] = None):
""" Loads the snap7 library using ctypes cdll.
Args:
lib_location: full path to the `snap7.dll` file. Optional.
Raises:
RuntimeError: if `lib_location` is not found.
"""
if self.cdll: # type: ignore
return
self.lib_location = (lib_location
or self.lib_location
or find_in_package()
or find_library('snap7')
or find_locally('snap7'))
if not self.lib_location:
raise RuntimeError("can't find snap7 library. If installed, try running ldconfig")
self.cdll = cdll.LoadLibrary(self.lib_location)
def load_library(lib_location: Optional[str] = None):
"""Loads the `snap7.dll` library.
Returns:
cdll: a ctypes cdll object with the snap7 shared library loaded.
"""
return Snap7Library(lib_location).cdll
def check_error(code: int, context: str = "client") -> None:
"""Check if the error code is set. If so, a Python log message is generated
and an error is raised.
Args:
code: error code number.
context: context in which is called.
Raises:
RuntimeError: if the code exists and is different from 1.
"""
if code and code != 1:
error = error_text(code, context)
logger.error(error)
raise RuntimeError(error)
def error_text(error, context: str = "client") -> bytes:
"""Returns a textual explanation of a given error number
Args:
error: an error integer
context: context in which is called from, server, client or partner
Returns:
The error.
Raises:
TypeError: if the context is not in `["client", "server", "partner"]`
"""
if context not in ("client", "server", "partner"):
raise TypeError(f"Unkown context {context} used, should be either client, server or partner")
logger.debug(f"error text for {hex(error)}")
len_ = 1024
text_type = c_char * len_
text = text_type()
library = load_library()
if context == "client":
library.Cli_ErrorText(error, text, len_)
elif context == "server":
library.Srv_ErrorText(error, text, len_)
elif context == "partner":
library.Par_ErrorText(error, text, len_)
return text.value
def find_locally(fname: str = "snap7") -> Optional[str]:
"""Finds the `snap7.dll` file in the local project directory.
Args:
fname: file name to search for. Optional.
Returns:
Full path to the `snap7.dll` file.
"""
file = pathlib.Path.cwd() / f"{fname}.dll"
if file.exists():
return str(file)
return None
def find_in_package() -> Optional[str]:
"""Find the `snap7.dll` file according to the os used.
Returns:
Full path to the `snap7.dll` file.
"""
basedir = pathlib.Path(__file__).parent.absolute()
if sys.platform == "darwin":
lib = 'libsnap7.dylib'
elif sys.platform == "win32":
lib = 'snap7.dll'
else:
lib = 'libsnap7.so'
full_path = basedir.joinpath('lib', lib)
if os.path.exists(full_path) and os.path.isfile(full_path):
return str(full_path)
return None