xarm-python-sdk 1.15.2__py3-none-any.whl

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.
Files changed (63) hide show
  1. xarm/__init__.py +2 -0
  2. xarm/build_backend.py +17 -0
  3. xarm/core/__init__.py +2 -0
  4. xarm/core/comm/__init__.py +5 -0
  5. xarm/core/comm/base.py +303 -0
  6. xarm/core/comm/serial_port.py +44 -0
  7. xarm/core/comm/socket_port.py +150 -0
  8. xarm/core/comm/uxbus_cmd_protocol.py +100 -0
  9. xarm/core/config/__init__.py +0 -0
  10. xarm/core/config/x_code.py +1427 -0
  11. xarm/core/config/x_config.py +553 -0
  12. xarm/core/utils/__init__.py +3 -0
  13. xarm/core/utils/convert.py +124 -0
  14. xarm/core/utils/crc16.py +76 -0
  15. xarm/core/utils/debug_print.py +21 -0
  16. xarm/core/utils/log.py +98 -0
  17. xarm/core/version.py +1 -0
  18. xarm/core/wrapper/__init__.py +11 -0
  19. xarm/core/wrapper/uxbus_cmd.py +1457 -0
  20. xarm/core/wrapper/uxbus_cmd_ser.py +94 -0
  21. xarm/core/wrapper/uxbus_cmd_tcp.py +305 -0
  22. xarm/tools/__init__.py +0 -0
  23. xarm/tools/blockly/__init__.py +1 -0
  24. xarm/tools/blockly/_blockly_base.py +416 -0
  25. xarm/tools/blockly/_blockly_handler.py +1338 -0
  26. xarm/tools/blockly/_blockly_highlight.py +94 -0
  27. xarm/tools/blockly/_blockly_node.py +61 -0
  28. xarm/tools/blockly/_blockly_tool.py +480 -0
  29. xarm/tools/blockly_tool.py +1864 -0
  30. xarm/tools/gcode.py +90 -0
  31. xarm/tools/list_ports.py +39 -0
  32. xarm/tools/modbus_tcp.py +205 -0
  33. xarm/tools/threads.py +30 -0
  34. xarm/tools/utils.py +36 -0
  35. xarm/version.py +1 -0
  36. xarm/wrapper/__init__.py +1 -0
  37. xarm/wrapper/studio_api.py +34 -0
  38. xarm/wrapper/xarm_api.py +4416 -0
  39. xarm/x3/__init__.py +2 -0
  40. xarm/x3/base.py +2638 -0
  41. xarm/x3/base_board.py +198 -0
  42. xarm/x3/code.py +62 -0
  43. xarm/x3/decorator.py +104 -0
  44. xarm/x3/events.py +166 -0
  45. xarm/x3/ft_sensor.py +264 -0
  46. xarm/x3/gpio.py +457 -0
  47. xarm/x3/grammar_async.py +21 -0
  48. xarm/x3/grammar_coroutine.py +24 -0
  49. xarm/x3/gripper.py +830 -0
  50. xarm/x3/modbus_tcp.py +84 -0
  51. xarm/x3/parse.py +110 -0
  52. xarm/x3/record.py +216 -0
  53. xarm/x3/report.py +204 -0
  54. xarm/x3/robotiq.py +220 -0
  55. xarm/x3/servo.py +485 -0
  56. xarm/x3/studio.py +138 -0
  57. xarm/x3/track.py +424 -0
  58. xarm/x3/utils.py +43 -0
  59. xarm/x3/xarm.py +1928 -0
  60. xarm_python_sdk-1.15.2.dist-info/METADATA +103 -0
  61. xarm_python_sdk-1.15.2.dist-info/RECORD +63 -0
  62. xarm_python_sdk-1.15.2.dist-info/WHEEL +4 -0
  63. xarm_python_sdk-1.15.2.dist-info/licenses/LICENSE +27 -0
xarm/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ from .wrapper import XArmAPI
2
+ from .version import __version__
xarm/build_backend.py ADDED
@@ -0,0 +1,17 @@
1
+ import os
2
+ import sys
3
+
4
+ if sys.version_info.major > 3 or (sys.version_info.major == 3 and sys.version_info.minor >= 8):
5
+ # os.environ['_PYPROJECT_HOOKS_BUILD_BACKEND'] = 'hatchling.build'
6
+ # requires = [
7
+ # "hatchling",
8
+ # ]
9
+ # build-backend = "hatchling.build"
10
+ from hatchling.build import *
11
+ else:
12
+ # os.environ['_PYPROJECT_HOOKS_BUILD_BACKEND'] = 'setuptools.build_meta'
13
+ # requires = [
14
+ # "setuptools >= 40.8.0",
15
+ # ]
16
+ # build-backend = "setuptools.build_meta"
17
+ from setuptools.build_meta import *
xarm/core/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ from .config.x_code import ControllerWarn, ControllerError, ServoError
2
+ from .config.x_config import XCONF
@@ -0,0 +1,5 @@
1
+ try:
2
+ from .serial_port import SerialPort
3
+ except:
4
+ SerialPort = None
5
+ from .socket_port import SocketPort
xarm/core/comm/base.py ADDED
@@ -0,0 +1,303 @@
1
+ #!/usr/bin/env python3
2
+ # Software License Agreement (MIT License)
3
+ #
4
+ # Copyright (c) 2018, UFACTORY, Inc.
5
+ # All rights reserved.
6
+ #
7
+ # Author: Vinman <vinman.wen@ufactory.cc>
8
+
9
+ import time
10
+ import queue
11
+ import socket
12
+ import select
13
+ import threading
14
+ from ..utils.log import logger
15
+ from ..utils import convert
16
+
17
+
18
+ class RxParse(object):
19
+ def __init__(self, rx_que, fb_que=None):
20
+ self.rx_que = rx_que
21
+ self.fb_que = fb_que
22
+
23
+ def flush(self, fromid=-1, toid=-1):
24
+ pass
25
+
26
+ def put(self, data, is_report=False):
27
+ if not is_report and data[6] == 0xFF:
28
+ if not self.fb_que:
29
+ return
30
+ self.fb_que.put(data)
31
+ else:
32
+ self.rx_que.put(data)
33
+
34
+
35
+ class Port(threading.Thread):
36
+ def __init__(self, rxque_max, fb_que=None):
37
+ super(Port, self).__init__()
38
+ self.daemon = True
39
+ self.rx_que = queue.Queue(rxque_max)
40
+ self.fb_que = fb_que
41
+ self.write_lock = threading.Lock()
42
+ self._connected = False
43
+ self.com = None
44
+ self.rx_parse = RxParse(self.rx_que, self.fb_que)
45
+ self.com_read = None
46
+ self.com_write = None
47
+ self.port_type = ''
48
+ self.buffer_size = 1
49
+ self.heartbeat_thread = None
50
+ self.alive = True
51
+
52
+ @property
53
+ def connected(self):
54
+ return self._connected
55
+
56
+ def run(self):
57
+ if self.port_type == 'report-socket':
58
+ self.recv_report_proc()
59
+ else:
60
+ self.recv_proc()
61
+ # self.recv_loop()
62
+
63
+ def close(self):
64
+ self.alive = False
65
+ if 'socket' in self.port_type:
66
+ try:
67
+ self.com.shutdown(socket.SHUT_RDWR)
68
+ except:
69
+ pass
70
+ try:
71
+ self.com.close()
72
+ except:
73
+ pass
74
+
75
+ def flush(self, fromid=-1, toid=-1):
76
+ if not self.connected:
77
+ return -1
78
+ while not(self.rx_que.empty()):
79
+ self.rx_que.queue.clear()
80
+ self.rx_parse.flush(fromid, toid)
81
+ return 0
82
+
83
+ def write(self, data):
84
+ if not self.connected:
85
+ return -1
86
+ try:
87
+ with self.write_lock:
88
+ logger.verbose('[{}] send: {}'.format(self.port_type, data))
89
+ self.com_write(data)
90
+ return 0
91
+ except Exception as e:
92
+ self._connected = False
93
+ logger.error("[{}] send error: {}".format(self.port_type, e))
94
+ return -1
95
+
96
+ def read(self, timeout=None):
97
+ if not self.connected:
98
+ return -1
99
+ try:
100
+ buf = self.rx_que.get(timeout=timeout)
101
+ logger.verbose('[{}] recv: {}'.format(self.port_type, buf))
102
+ return buf
103
+ except:
104
+ return -1
105
+ # if not self.connected:
106
+ # return -1
107
+ # if not self.rx_que.empty():
108
+ # buf = self.rx_que.get(timeout=timeout)
109
+ # logger.verbose('[{}] recv: {}'.format(self.port_type, buf))
110
+ # return buf
111
+ # else:
112
+ # return -1
113
+
114
+ # def recv_loop(self):
115
+ # self.alive = True
116
+ # logger.debug('[{}] recv thread start'.format(self.port_type))
117
+ # try:
118
+ # while self.connected and self.alive:
119
+ # if 'socket' in self.port_type:
120
+ # ready_input, ready_output, ready_exception = select.select([self.com], [], [])
121
+ # for indata in ready_input:
122
+ # if indata == self.com:
123
+ # rx_data = self.com_read(self.buffer_size)
124
+ # break
125
+ # else:
126
+ # continue
127
+ # else:
128
+ # rx_data = self.com_read(self.com.in_waiting or self.buffer_size)
129
+ # self.rx_parse.put(rx_data)
130
+ # except Exception as e:
131
+ # if self.alive:
132
+ # logger.error('[{}] recv error: {}'.format(self.port_type, e))
133
+ # finally:
134
+ # self.close()
135
+ # logger.debug('[{}] recv thread had stopped'.format(self.port_type))
136
+ # self._connected = False
137
+
138
+ def recv_report_proc(self):
139
+ self.alive = True
140
+ logger.debug('[{}] recv thread start'.format(self.port_type))
141
+ failed_read_count = 0
142
+ timeout_count = 0
143
+ size = 0
144
+ data_num = 0
145
+ buffer = b''
146
+ size_is_not_confirm = False
147
+
148
+ data_prev_us = 0
149
+ data_curr_us = 0
150
+ data_max_interval_us = 0
151
+ data_over_us = 205 * 1000 # over 205ms, cnts++
152
+ data_over_cnts = 0
153
+
154
+ recv_prev_us = 0
155
+ recv_curr_us = 0
156
+ recv_max_interval_us = 0
157
+ recv_over_us = 300 * 1000 # over 300ms, cnts++
158
+ recv_over_cnts = 0
159
+
160
+ try:
161
+ while self.connected and self.alive:
162
+ try:
163
+ data = self.com_read(4 - data_num if size == 0 else (size - data_num))
164
+ except socket.timeout:
165
+ timeout_count += 1
166
+ if timeout_count > 3:
167
+ self._connected = False
168
+ logger.error('[{}] socket read timeout'.format(self.port_type))
169
+ break
170
+ continue
171
+ else:
172
+ if len(data) == 0:
173
+ failed_read_count += 1
174
+ if failed_read_count > 5:
175
+ self._connected = False
176
+ logger.error('[{}] socket read failed, len=0'.format(self.port_type))
177
+ break
178
+ time.sleep(0.1)
179
+ continue
180
+ data_num += len(data)
181
+ buffer += data
182
+ if size == 0:
183
+ if data_num != 4:
184
+ continue
185
+ size = convert.bytes_to_u32(buffer[0:4])
186
+ if size == 233:
187
+ size_is_not_confirm = True
188
+ size = 245
189
+ logger.info('report_data_size: {}, size_is_not_confirm={}'.format(size, size_is_not_confirm))
190
+ else:
191
+ if data_num < size:
192
+ continue
193
+ if size_is_not_confirm:
194
+ size_is_not_confirm = True
195
+ if convert.bytes_to_u32(buffer[233:237]) == 233:
196
+ size = 233
197
+ buffer = buffer[233:]
198
+ continue
199
+
200
+ if convert.bytes_to_u32(buffer[0:4]) != size and not (size_is_not_confirm and size == 245 and convert.bytes_to_u32(buffer[0:4]) == 233):
201
+ logger.error('report data error, close, length={}, size={}'.format(convert.bytes_to_u32(buffer[0:4]), size))
202
+ break
203
+
204
+ # # buffer[494:502]
205
+ # data_curr_us = convert.bytes_to_u64(buffer[-8:])
206
+ # recv_curr_us = time.monotonic() * 1000000
207
+ #
208
+ # if data_prev_us != 0 and recv_prev_us != 0:
209
+ # data_interval_us = data_curr_us - data_prev_us
210
+ # data_over_cnts += 1 if data_interval_us > data_over_us else 0
211
+ #
212
+ # recv_interval_us = recv_curr_us - recv_prev_us
213
+ # recv_over_cnts += 1 if recv_interval_us > recv_over_us else 0
214
+ #
215
+ # print_flag = False
216
+ #
217
+ # if data_interval_us > data_max_interval_us:
218
+ # data_max_interval_us = data_interval_us
219
+ # print_flag = True
220
+ # elif data_interval_us > data_over_us:
221
+ # print_flag = True
222
+ #
223
+ # if recv_interval_us > recv_max_interval_us:
224
+ # recv_max_interval_us = recv_interval_us
225
+ # print_flag = True
226
+ # elif recv_interval_us > recv_over_us:
227
+ # print_flag = True
228
+ #
229
+ # if print_flag:
230
+ # print('[RECV] Di={}, Dmax={}, Dcnts={}, Ri={}, Rmax={}, Rcnts={}'.format(
231
+ # data_interval_us / 1000, data_max_interval_us / 1000, data_over_cnts,
232
+ # recv_interval_us / 1000, recv_max_interval_us / 1000, recv_over_cnts
233
+ # ))
234
+ # data_prev_us = data_curr_us
235
+ # recv_prev_us = recv_curr_us
236
+
237
+ if self.rx_que.qsize() > 1:
238
+ self.rx_que.get()
239
+ self.rx_parse.put(buffer, True)
240
+ buffer = b''
241
+ data_num = 0
242
+
243
+ timeout_count = 0
244
+ failed_read_count = 0
245
+ except Exception as e:
246
+ if self.alive:
247
+ logger.error('[{}] recv error: {}'.format(self.port_type, e))
248
+ finally:
249
+ self.close()
250
+ logger.debug('[{}] recv thread had stopped'.format(self.port_type))
251
+ self._connected = False
252
+
253
+ def recv_proc(self):
254
+ self.alive = True
255
+ logger.debug('[{}] recv thread start'.format(self.port_type))
256
+ is_main_tcp = self.port_type == 'main-socket'
257
+ is_main_serial = self.port_type == 'main-serial'
258
+ try:
259
+ failed_read_count = 0
260
+ buffer = b''
261
+ while self.connected and self.alive:
262
+ if is_main_tcp:
263
+ try:
264
+ rx_data = self.com_read(self.buffer_size)
265
+ except socket.timeout:
266
+ continue
267
+ if len(rx_data) == 0:
268
+ failed_read_count += 1
269
+ if failed_read_count > 5:
270
+ self._connected = False
271
+ logger.error('[{}] socket read failed, len=0'.format(self.port_type))
272
+ break
273
+ time.sleep(0.1)
274
+ continue
275
+ buffer += rx_data
276
+ while True:
277
+ if len(buffer) < 6:
278
+ break
279
+ length = convert.bytes_to_u16(buffer[4:6]) + 6
280
+ if len(buffer) < length:
281
+ break
282
+ rx_data = buffer[:length]
283
+ buffer = buffer[length:]
284
+ self.rx_parse.put(rx_data)
285
+ elif is_main_serial:
286
+ rx_data = self.com_read(self.com.in_waiting or self.buffer_size)
287
+ self.rx_parse.put(rx_data)
288
+ else:
289
+ break
290
+ failed_read_count = 0
291
+ except Exception as e:
292
+ if self.alive:
293
+ logger.error('[{}] recv error: {}'.format(self.port_type, e))
294
+ finally:
295
+ self.close()
296
+ logger.debug('[{}] recv thread had stopped'.format(self.port_type))
297
+ self._connected = False
298
+ # if self.heartbeat_thread:
299
+ # try:
300
+ # self.heartbeat_thread.join()
301
+ # except:
302
+ # pass
303
+
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env python3
2
+ # Software License Agreement (BSD License)
3
+ #
4
+ # Copyright (c) 2018, UFACTORY, Inc.
5
+ # All rights reserved.
6
+ #
7
+ # Author: Jimy Zhang <jimy.zhang@ufactory.cc> <jimy92@163.com>
8
+ # Author: Vinman <vinman.wen@ufactory.cc> <vinman.cub@gmail.com>
9
+
10
+
11
+ import serial
12
+ from ..utils.log import logger
13
+ from .base import Port
14
+ from .uxbus_cmd_protocol import Ux2HexProtocol
15
+ from ..config.x_config import XCONF
16
+
17
+
18
+ class SerialPort(Port):
19
+ def __init__(self, port, baud=XCONF.SerialConf.SERIAL_BAUD,
20
+ rxque_max=XCONF.SerialConf.UXBUS_RXQUE_MAX, protocol=XCONF.SerialConf.UX2_HEX_PROTOCOL):
21
+ super(SerialPort, self).__init__(rxque_max)
22
+ self.port_type = 'main-serial'
23
+ try:
24
+ self.com = serial.Serial(port=port, baudrate=baud)
25
+ if not self.com.isOpen():
26
+ self._connected = False
27
+ raise Exception('serial is not open')
28
+ logger.info('{} connect {}:{} success'.format(self.port_type, port, baud))
29
+
30
+ self._connected = True
31
+
32
+ self.buffer_size = 1
33
+
34
+ if protocol == XCONF.SerialConf.UX2_HEX_PROTOCOL:
35
+ self.rx_parse = Ux2HexProtocol(self.rx_que,
36
+ XCONF.SerialConf.UXBUS_DEF_FROMID,
37
+ XCONF.SerialConf.UXBUS_DEF_TOID)
38
+ self.com_read = self.com.read
39
+ self.com_write = self.com.write
40
+ self.start()
41
+ except Exception as e:
42
+ logger.info('{} connect {}:{} failed, {}'.format(self.port_type, port, baud, e))
43
+ self._connected = False
44
+
@@ -0,0 +1,150 @@
1
+ #!/usr/bin/env python3
2
+ # Software License Agreement (BSD License)
3
+ #
4
+ # Copyright (c) 2018, UFACTORY, Inc.
5
+ # All rights reserved.
6
+ #
7
+ # Author: Jimy Zhang <jimy.zhang@ufactory.cc> <jimy92@163.com>
8
+ # Author: Vinman <vinman.wen@ufactory.cc> <vinman.cub@gmail.com>
9
+
10
+
11
+ import queue
12
+ import os
13
+ import socket
14
+ import struct
15
+ import platform
16
+ import threading
17
+ import time
18
+ from ..utils.log import logger
19
+ from .base import Port
20
+ from ..config.x_config import XCONF
21
+
22
+ # try:
23
+ # if platform.system() == 'Linux':
24
+ # import fcntl
25
+ # else:
26
+ # fcntl = None
27
+ # except:
28
+ # fcntl = None
29
+ #
30
+ #
31
+ # def is_xarm_local_ip(ip):
32
+ # try:
33
+ # if platform.system() == 'Linux' and fcntl:
34
+ # def _get_ip(s, ifname):
35
+ # try:
36
+ # return socket.inet_ntoa(fcntl.ioctl(s.fileno(), 0x8915, struct.pack('256s', ifname[:15]))[20:24])
37
+ # except:
38
+ # pass
39
+ # return ''
40
+ # sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
41
+ # # gentoo system netcard name
42
+ # if ip == _get_ip(sock, b'enp1s0'):
43
+ # return True
44
+ # # rasp system netcard name
45
+ # if ip == _get_ip(sock, b'eth0'):
46
+ # return True
47
+ # except:
48
+ # pass
49
+ # return False
50
+
51
+
52
+ def get_all_ips():
53
+ addrs = ['localhost', '127.0.0.1']
54
+ addrs = set(addrs)
55
+ try:
56
+ for ip in socket.gethostbyname_ex(socket.gethostname())[2]:
57
+ try:
58
+ if not ip.startswith('127.'):
59
+ addrs.add(ip)
60
+ except:
61
+ pass
62
+ except:
63
+ pass
64
+ try:
65
+ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
66
+ sock.settimeout(3)
67
+ sock.connect(('8.8.8.8', 53))
68
+ addrs.add(sock.getsockname()[0])
69
+ except:
70
+ pass
71
+ return addrs
72
+
73
+
74
+ class HeartBeatThread(threading.Thread):
75
+ def __init__(self, sock_class):
76
+ threading.Thread.__init__(self)
77
+ self.sock_class = sock_class
78
+ self.daemon = True
79
+
80
+ def run(self):
81
+ logger.debug('{} heartbeat thread start'.format(self.sock_class.port_type))
82
+ heat_data = bytes([0, 0, 0, 1, 0, 2, 0, 0])
83
+
84
+ while self.sock_class.connected:
85
+ if self.sock_class.write(heat_data) == -1:
86
+ break
87
+ time.sleep(1)
88
+ logger.debug('{} heartbeat thread had stopped'.format(self.sock_class.port_type))
89
+
90
+
91
+ class SocketPort(Port):
92
+ def __init__(self, server_ip, server_port, rxque_max=XCONF.SocketConf.TCP_RX_QUE_MAX, heartbeat=False,
93
+ buffer_size=XCONF.SocketConf.TCP_CONTROL_BUF_SIZE, forbid_uds=False, fb_que=None):
94
+ is_main_tcp = server_port == XCONF.SocketConf.TCP_CONTROL_PORT or server_port == XCONF.SocketConf.TCP_CONTROL_PORT + 1
95
+ super(SocketPort, self).__init__(rxque_max, fb_que)
96
+ if is_main_tcp:
97
+ self.port_type = 'main-socket'
98
+ # self.com.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, 5)
99
+ else:
100
+ self.port_type = 'report-socket'
101
+ try:
102
+ socket.setdefaulttimeout(1)
103
+ use_uds = False
104
+ # if not forbid_uds and platform.system() == 'Linux' and is_xarm_local_ip(server_ip):
105
+ # if not forbid_uds and platform.system() == 'Linux' and server_ip in get_all_ips():
106
+ if not forbid_uds and platform.system() == 'Linux':
107
+ uds_path = os.path.join('/tmp/xarmcontroller_uds_{}'.format(server_port))
108
+ if os.path.exists(uds_path):
109
+ try:
110
+ self.com = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
111
+ self.com.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
112
+ self.com.setblocking(True)
113
+ self.com.settimeout(1)
114
+ self.com.connect(uds_path)
115
+ logger.info('{} connect {} success, uds_{}'.format(self.port_type, server_ip, server_port))
116
+ use_uds = True
117
+ except Exception as e:
118
+ pass
119
+ # logger.error('use uds error, {}'.format(e))
120
+ else:
121
+ pass
122
+ if not use_uds:
123
+ self.com = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
124
+ self.com.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
125
+ # self.com.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
126
+ # self.com.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE, 30)
127
+ # self.com.setsockopt(socket.SOL_TCP, socket.TCP_KEEPINTVL, 10)
128
+ # self.com.setsockopt(socket.SOL_TCP, socket.TCP_KEEPCNT, 3)
129
+ self.com.setblocking(True)
130
+ self.com.settimeout(1)
131
+ self.com.connect((server_ip, server_port))
132
+ logger.info('{} connect {} success'.format(self.port_type, server_ip))
133
+ # logger.info('{} connect {}:{} success'.format(self.port_type, server_ip, server_port))
134
+
135
+ self._connected = True
136
+ self.buffer_size = buffer_size
137
+ # time.sleep(1)
138
+
139
+ self.com_read = self.com.recv
140
+ self.com_write = self.com.send
141
+ self.write_lock = threading.Lock()
142
+ self.start()
143
+ if heartbeat:
144
+ self.heartbeat_thread = HeartBeatThread(self)
145
+ self.heartbeat_thread.start()
146
+ except Exception as e:
147
+ logger.info('{} connect {} failed, {}'.format(self.port_type, server_ip, e))
148
+ # logger.error('{} connect {}:{} failed, {}'.format(self.port_type, server_ip, server_port, e))
149
+ self._connected = False
150
+
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env python3
2
+ # Software License Agreement (BSD License)
3
+ #
4
+ # Copyright (c) 2018, UFACTORY, Inc.
5
+ # All rights reserved.
6
+ #
7
+ # Author: Jimy Zhang <jimy.zhang@ufactory.cc> <jimy92@163.com>
8
+ # Author: Vinman <vinman.wen@ufactory.cc> <vinman.cub@gmail.com>
9
+
10
+
11
+ from ..utils import crc16
12
+ from ..utils.log import logger
13
+
14
+ # ux2_hex_protocol define
15
+ UX2HEX_RXSTART_FROMID = 0
16
+ UX2HEX_RXSTART_TOID = 1
17
+ UX2HEX_RXSTATE_LEN = 2
18
+ UX2HEX_RXSTATE_DATA = 3
19
+ UX2HEX_RXSTATE_CRC1 = 4
20
+ UX2HEX_RXSTATE_CRC2 = 5
21
+ UX2HEX_RXLEN_MAX = 50
22
+
23
+
24
+ class Ux2HexProtocol(object):
25
+ """
26
+ fromid and toid: broadcast address is 0xFF
27
+ """
28
+ def __init__(self, rx_que, fromid, toid):
29
+ self.rx_que = rx_que
30
+ self.rxstate = UX2HEX_RXSTART_FROMID
31
+ self.data_idx = 0
32
+ self.len = 0
33
+ self.fromid = fromid
34
+ self.toid = toid
35
+ self.rxbuf = None
36
+
37
+ # wipe cache , set from_id and to_id
38
+ def flush(self, fromid=-1, toid=-1):
39
+ self.rxstate = UX2HEX_RXSTART_FROMID
40
+ self.data_idx = 0
41
+ self.len = 0
42
+ if fromid != -1:
43
+ self.fromid = fromid
44
+ if toid != -1:
45
+ self.toid = toid
46
+
47
+ def put(self, rxstr, length=0):
48
+ if length == 0:
49
+ length = len(rxstr)
50
+ if len(rxstr) < length:
51
+ logger.error('len(rxstr) < length')
52
+
53
+ for i in range(length):
54
+ rxch = bytes([rxstr[i]])
55
+ # print_hex(self.DB_FLG, rxch, 1)
56
+ # print('state:%d' % (self.rxstate))
57
+ if UX2HEX_RXSTART_FROMID == self.rxstate:
58
+ if self.toid == rxch[0] or 255 == self.toid:
59
+ self.rxbuf = rxch
60
+ self.rxstate = UX2HEX_RXSTART_TOID
61
+
62
+ elif UX2HEX_RXSTART_TOID == self.rxstate:
63
+ if self.fromid == rxch[0] or self.fromid == 0xFF:
64
+ self.rxbuf += rxch
65
+ self.rxstate = UX2HEX_RXSTATE_LEN
66
+ else:
67
+ self.rxstate = UX2HEX_RXSTART_FROMID
68
+
69
+ elif UX2HEX_RXSTATE_LEN == self.rxstate:
70
+ if rxch[0] < UX2HEX_RXLEN_MAX:
71
+ self.rxbuf += rxch
72
+ self.len = rxch[0]
73
+ self.data_idx = 0
74
+ self.rxstate = UX2HEX_RXSTATE_DATA
75
+ else:
76
+ self.rxstate = UX2HEX_RXSTART_FROMID
77
+
78
+ elif UX2HEX_RXSTATE_DATA == self.rxstate:
79
+ if self.data_idx < self.len:
80
+ self.rxbuf += rxch
81
+ self.data_idx += 1
82
+ if self.data_idx == self.len:
83
+ self.rxstate = UX2HEX_RXSTATE_CRC1
84
+ else:
85
+ self.rxstate = UX2HEX_RXSTART_FROMID
86
+
87
+ elif UX2HEX_RXSTATE_CRC1 == self.rxstate:
88
+ self.rxbuf += rxch
89
+ self.rxstate = UX2HEX_RXSTATE_CRC2
90
+
91
+ elif UX2HEX_RXSTATE_CRC2 == self.rxstate:
92
+ self.rxbuf += rxch
93
+ self.rxstate = UX2HEX_RXSTART_FROMID
94
+ crc = crc16.crc_modbus(self.rxbuf[:self.len + 3])
95
+ if crc[0] == self.rxbuf[self.len + 3] and crc[1] == self.rxbuf[self.len + 4]:
96
+ if self.rx_que.full():
97
+ self.rx_que.get()
98
+ self.rx_que.put(self.rxbuf)
99
+ # print(self.rxbuf)
100
+
File without changes