Skip to content

Commit ebf2dfd

Browse files
committed
refactoring
add type hints
1 parent 8b0e54b commit ebf2dfd

File tree

5 files changed

+337
-226
lines changed

5 files changed

+337
-226
lines changed

example/example.py

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,35 @@
2121

2222
lan = client.get_lan_config()
2323
print(f"get_lan_config: {lan}")
24-
# result = client.set_lan_config(lan["mac"], lan["ip"], lan["sn"], lan["gw"], lan["dns"], lan["port"], lan["dhcp"])
24+
print(f" mac: {lan.MAC}")
25+
print(f" ip: {lan.IP}")
26+
print(f" sn: {lan.SN}")
27+
print(f" gw: {lan.GW}")
28+
print(f" dns: {lan.DNS}")
29+
print(f" port: {lan.PORT}")
30+
print(f" dhcp: {lan.DHCP}")
31+
# result = client.set_lan_config(lan.MAC, lan.IP, lan.SN, lan.GW, lan.DNS, lan.PORT, lan.DHCP)
2532
# print(f"set_lan_config: {result}")
2633

27-
print(f"get_error_statistics: {client.get_error_statistics()}")
34+
stats = client.get_error_statistics()
35+
print(f"get_error_statistics: {stats}")
36+
print(f" n_starts: {stats.N_STARTS}")
37+
print(f" error_xt: {stats.ERROR_XT}")
38+
print(f" error_time_out: {stats.ERROR_TIME_OUT}")
39+
print(f" error_init_powerstep01: {stats.ERROR_INIT_POWERSTEP01}")
40+
print(f" error_init_wiznet: {stats.ERROR_INIT_WIZNET}")
41+
print(f" error_init_fram: {stats.ERROR_INIT_FRAM}")
42+
print(f" error_socket: {stats.ERROR_SOCKET}")
43+
print(f" error_fram: {stats.ERROR_FRAM}")
44+
print(f" error_interrupt: {stats.ERROR_INTERRUPT}")
45+
print(f" error_extern_5v: {stats.ERROR_EXTERN_5V}")
46+
print(f" error_extern_vdd: {stats.ERROR_EXTERN_VDD}")
47+
print(f" error_thermal_powerstep01: {stats.ERROR_THERMAL_POWERSTEP01}")
48+
print(f" error_thermal_brake: {stats.ERROR_THERMAL_BRAKE}")
49+
print(f" error_command_powerstep01: {stats.ERROR_COMMAND_POWERSTEP01}")
50+
print(f" error_uvlo_powerstep01: {stats.ERROR_UVLO_POWERSTEP01}")
51+
print(f" error_stall_powerstep01: {stats.ERROR_STALL_POWERSTEP01}")
52+
print(f" error_work_program: {stats.ERROR_WORK_PROGRAM}")
2853

2954
print(f"get_speed: {client.get_speed()}")
3055

@@ -38,7 +63,14 @@
3863
print(f"set_dec: {client.set_dec(50)}")
3964

4065
print(f"set_mode: {client.set_mode(current_or_voltage=1, motor_type=30, microstepping=4, work_current=15, stop_current=0)}")
41-
print(f"get_mode: {client.get_mode()}")
66+
mode = client.get_mode()
67+
print(f"get_mode: {mode}")
68+
print(f" current_or_voltage: {mode.CURRENT_OR_VOLTAGE}")
69+
print(f" motor_type: {mode.MOTOR_TYPE}")
70+
print(f" microstepping: {mode.MICROSTEPPING}")
71+
print(f" work_current: {mode.WORK_CURRENT}")
72+
print(f" stop_current: {mode.STOP_CURRENT}")
73+
print(f" program_n: {mode.PROGRAM_N}")
4274

4375
# print(f"run_f: {client.run_f(500)}")
4476
# sleep(5)
@@ -90,7 +122,32 @@
90122
print(f"get_status_and_clr: {client.get_status_and_clr()}")
91123

92124
print(f"set_mask_event: {client.set_mask_event(0)}")
93-
print(f"get_status_in_event: {client.get_status_in_event()}")
125+
status = client.get_status_in_event()
126+
print(f"get_status_in_event: {status}")
127+
print(f" Int_0: {status.INT_0}")
128+
print(f" Int_1: {status.INT_1}")
129+
print(f" Int_2: {status.INT_2}")
130+
print(f" Int_3: {status.INT_3}")
131+
print(f" Int_4: {status.INT_4}")
132+
print(f" Int_5: {status.INT_5}")
133+
print(f" Int_6: {status.INT_6}")
134+
print(f" Int_7: {status.INT_7}")
135+
print(f" Mask_0: {status.MASK_0}")
136+
print(f" Mask_1: {status.MASK_1}")
137+
print(f" Mask_2: {status.MASK_2}")
138+
print(f" Mask_3: {status.MASK_3}")
139+
print(f" Mask_4: {status.MASK_4}")
140+
print(f" Mask_5: {status.MASK_5}")
141+
print(f" Mask_6: {status.MASK_6}")
142+
print(f" Mask_7: {status.MASK_7}")
143+
print(f" Wait_0: {status.WAIT_0}")
144+
print(f" Wait_1: {status.WAIT_1}")
145+
print(f" Wait_2: {status.WAIT_2}")
146+
print(f" Wait_3: {status.WAIT_3}")
147+
print(f" Wait_4: {status.WAIT_4}")
148+
print(f" Wait_5: {status.WAIT_5}")
149+
print(f" Wait_6: {status.WAIT_6}")
150+
print(f" Wait_7: {status.WAIT_7}")
94151

95152
print(f"soft_stop: {client.soft_stop()}")
96153
print(f"hard_stop: {client.hard_stop()}")

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from setuptools import setup
44

55
setup(name="python-smsd-lan",
6-
version="0.0.2",
6+
version="0.0.3",
77
description="SMSD LAN-series controller library",
88
url="https://github.com/RAA80/python-smsd-lan",
99
author="Alexey Ryadno",

smsd/client.py

Lines changed: 27 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import logging
66
from socket import AF_INET, SOCK_STREAM, socket
7+
from typing import Callable
78

89
from serial import Serial
910

@@ -13,58 +14,35 @@
1314
_logger.addHandler(logging.NullHandler())
1415

1516

16-
def log(func):
17+
def log(func: Callable) -> Callable:
1718
"""Вывод отладочной информации."""
1819

19-
def wrapper(self, packet):
20+
def wrapper(self: Callable[[bytes], bytes], packet: bytes) -> bytes:
2021
_logger.debug("Send frame: %r", list(packet))
2122
answer = func(self, packet)
2223
_logger.debug("Recv frame: %r", list(answer))
23-
return answer
24+
return bytes(answer)
25+
2426
return wrapper
2527

2628

27-
class BaseClient(Smsd):
28-
"""Базовый класс клиента."""
29+
class SmsdUsbClient(Smsd):
30+
"""Класс клиента для управления SMSD-LAN через USB."""
2931

30-
def __init__(self, address, **kwargs):
31-
"""Инициализация класса клиента с указанным адресом."""
32+
def __init__(self, address: str, timeout: float = 1.0) -> None:
33+
"""Инициализация класса клиента с указанными параметрами."""
3234

35+
self.socket = Serial(port=address, baudrate=115200, timeout=timeout)
3336
super().__init__()
3437

35-
self.socket = None
36-
self.address = address
37-
38-
self.port = kwargs.get("port", 5000)
39-
self.timeout = kwargs.get("timeout", 1.0)
40-
41-
self.connect()
42-
self.get_version()
43-
44-
def __del__(self):
38+
def __del__(self) -> None:
4539
"""Закрытие соединения с устройством при удалении объекта."""
4640

4741
if self.socket:
4842
self.socket.close()
49-
self.socket = None
50-
51-
def connect(self):
52-
"""Подключение к устройству."""
53-
54-
raise NotImplementedError
55-
56-
57-
class SmsdUsbClient(BaseClient):
58-
"""Класс клиента для управления SMSD-LAN через USB."""
59-
60-
def connect(self):
61-
"""Подключение к устройству."""
62-
63-
self.socket = Serial(port=self.address, baudrate=115200,
64-
timeout=self.timeout)
6543

6644
@log
67-
def _bus_exchange(self, packet):
45+
def _bus_exchange(self, packet: bytes) -> bytes:
6846
"""Обмен по интерфейсу."""
6947

7048
self.socket.reset_input_buffer()
@@ -82,7 +60,7 @@ def _bus_exchange(self, packet):
8260
return self._unescape(answer)
8361

8462
@staticmethod
85-
def _escape(packet):
63+
def _escape(packet: bytes) -> bytes:
8664
"""Замена специальных символов внутри пакета парой байтов."""
8765

8866
packet = packet.replace(b"\xFA", b"\xFE\x7A").\
@@ -91,7 +69,7 @@ def _escape(packet):
9169
return b"\xFA" + packet + b"\xFB"
9270

9371
@staticmethod
94-
def _unescape(packet):
72+
def _unescape(packet: bytes) -> bytes:
9573
"""Обратная замена пары байтов внутри пакета на символы."""
9674

9775
packet = packet[1:-1]
@@ -100,19 +78,25 @@ def _unescape(packet):
10078
replace(b"\xFE\x7E", b"\xFE")
10179

10280

103-
class SmsdTcpClient(BaseClient):
81+
class SmsdTcpClient(Smsd):
10482
"""Класс клиента для управления SMSD-LAN по протоколу TCP."""
10583

106-
def connect(self):
107-
"""Подключение к устройству."""
84+
def __init__(self, address: str, port: int = 5000, timeout: float = 1.0) -> None:
85+
"""Инициализация класса клиента с указанными параметрами."""
10886

109-
self.server = (self.address, self.port)
11087
self.socket = socket(AF_INET, SOCK_STREAM)
111-
self.socket.settimeout(self.timeout)
112-
self.socket.connect(self.server)
88+
self.socket.settimeout(timeout)
89+
self.socket.connect((address, port))
90+
super().__init__()
91+
92+
def __del__(self) -> None:
93+
"""Закрытие соединения с устройством при удалении объекта."""
94+
95+
if self.socket:
96+
self.socket.close()
11397

11498
@log
115-
def _bus_exchange(self, packet):
99+
def _bus_exchange(self, packet: bytes) -> bytes:
116100
"""Обмен по интерфейсу."""
117101

118102
self.socket.sendall(packet)

smsd/protocol.py

Lines changed: 74 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
"""Протокол обмена данными с SMSD-LAN."""
44

5-
from ctypes import LittleEndianStructure, Structure, c_ubyte, c_uint, c_ushort
6-
from enum import Enum
5+
from ctypes import LittleEndianStructure, Structure, Union, c_ubyte, c_uint, c_ushort
6+
from enum import IntEnum
77

88

9-
class CMD_TYPE(Enum):
9+
class CMD_TYPE(IntEnum):
1010
"""Команда, передаваемая по сети."""
1111

1212
CODE_CMD_REQUEST = 0x00 # команда авторизации (поле DATA пакета содержит информацию для авторизации)
@@ -26,7 +26,7 @@ class CMD_TYPE(Enum):
2626
CODE_CMD_ERROR_GET = 0x0E # команда чтения количества включений рабочего режима Контроллера и статистики по ошибкам
2727

2828

29-
class ERROR_OR_COMMAND(Enum):
29+
class ERROR_OR_COMMAND(IntEnum):
3030
"""Список возможных вариантов значений поля ERROR_OR_COMMAND."""
3131

3232
OK = 0x00 # без ошибок
@@ -55,7 +55,7 @@ class ERROR_OR_COMMAND(Enum):
5555
STATUS_RELE_CLR = 0x17 # реле выключено
5656

5757

58-
class COMMAND(Enum):
58+
class COMMAND(IntEnum):
5959
"""Список кодов исполнительных команд."""
6060

6161
CMD_POWERSTEP01_END = 0x00 # обозначение конца программы
@@ -213,3 +213,72 @@ class SMSD_LAN_CONFIG_TYPE(Structure):
213213
("PORT", c_ushort), # номер порта
214214
("DHCP", c_ubyte), # включен DHCP или нет
215215
]
216+
217+
218+
#####################################################
219+
220+
221+
class STATUS_IN_EVENT_BITS(Structure):
222+
"""Битовая карта состояний входных сигналов."""
223+
224+
_fields_ = [
225+
("INT_0", c_uint, 1), # Событие на входном сигнале 0
226+
("INT_1", c_uint, 1), # Событие на входном сигнале 1
227+
("INT_2", c_uint, 1), # Событие на входном сигнале 2
228+
("INT_3", c_uint, 1), # Событие на входном сигнале 3
229+
("INT_4", c_uint, 1), # Событие на входном сигнале 4
230+
("INT_5", c_uint, 1), # Событие на входном сигнале 5
231+
("INT_6", c_uint, 1), # Событие на входном сигнале 6
232+
("INT_7", c_uint, 1), # Событие на входном сигнале 7
233+
234+
("MASK_0", c_uint, 1), # Маскирование входного сигнала 0
235+
("MASK_1", c_uint, 1), # Маскирование входного сигнала 1
236+
("MASK_2", c_uint, 1), # Маскирование входного сигнала 2
237+
("MASK_3", c_uint, 1), # Маскирование входного сигнала 3
238+
("MASK_4", c_uint, 1), # Маскирование входного сигнала 4
239+
("MASK_5", c_uint, 1), # Маскирование входного сигнала 5
240+
("MASK_6", c_uint, 1), # Маскирование входного сигнала 6
241+
("MASK_7", c_uint, 1), # Маскирование входного сигнала 7
242+
243+
("WAIT_0", c_uint, 1), # Ожидание входного сигнала 0
244+
("WAIT_1", c_uint, 1), # Ожидание входного сигнала 1
245+
("WAIT_2", c_uint, 1), # Ожидание входного сигнала 2
246+
("WAIT_3", c_uint, 1), # Ожидание входного сигнала 3
247+
("WAIT_4", c_uint, 1), # Ожидание входного сигнала 4
248+
("WAIT_5", c_uint, 1), # Ожидание входного сигнала 5
249+
("WAIT_6", c_uint, 1), # Ожидание входного сигнала 6
250+
("WAIT_7", c_uint, 1), # Ожидание входного сигнала 7
251+
]
252+
253+
254+
class STATUS_IN_EVENT(Union):
255+
"""Состояния входных сигналов."""
256+
257+
_pack_ = 1
258+
_anonymous_ = ("bits",)
259+
_fields_ = [("bits", STATUS_IN_EVENT_BITS),
260+
("as_byte", c_uint),
261+
]
262+
263+
264+
class MODE_BITS(LittleEndianStructure):
265+
"""Битовая карта настроек управления двигателем."""
266+
267+
_fields_ = [
268+
("CURRENT_OR_VOLTAGE", c_uint, 1), # тип управления двигателем (0 – вольтовый режим, 1 – токовый режим)
269+
("MOTOR_TYPE", c_uint, 6), # модель двигателя для вольтового режима управления
270+
("MICROSTEPPING", c_uint, 3), # дробление шага
271+
("WORK_CURRENT", c_uint, 7), # рабочий ток
272+
("STOP_CURRENT", c_uint, 2), # ток удержания
273+
("PROGRAM_N", c_uint, 2), # номер программы для старта внешними сигналами
274+
]
275+
276+
277+
class MODE(Union):
278+
"""Настройки управления двигателем."""
279+
280+
_pack_ = 1
281+
_anonymous_ = ("bits",)
282+
_fields_ = [("bits", MODE_BITS),
283+
("as_byte", c_uint),
284+
]

0 commit comments

Comments
 (0)