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.
- xarm/__init__.py +2 -0
- xarm/build_backend.py +17 -0
- xarm/core/__init__.py +2 -0
- xarm/core/comm/__init__.py +5 -0
- xarm/core/comm/base.py +303 -0
- xarm/core/comm/serial_port.py +44 -0
- xarm/core/comm/socket_port.py +150 -0
- xarm/core/comm/uxbus_cmd_protocol.py +100 -0
- xarm/core/config/__init__.py +0 -0
- xarm/core/config/x_code.py +1427 -0
- xarm/core/config/x_config.py +553 -0
- xarm/core/utils/__init__.py +3 -0
- xarm/core/utils/convert.py +124 -0
- xarm/core/utils/crc16.py +76 -0
- xarm/core/utils/debug_print.py +21 -0
- xarm/core/utils/log.py +98 -0
- xarm/core/version.py +1 -0
- xarm/core/wrapper/__init__.py +11 -0
- xarm/core/wrapper/uxbus_cmd.py +1457 -0
- xarm/core/wrapper/uxbus_cmd_ser.py +94 -0
- xarm/core/wrapper/uxbus_cmd_tcp.py +305 -0
- xarm/tools/__init__.py +0 -0
- xarm/tools/blockly/__init__.py +1 -0
- xarm/tools/blockly/_blockly_base.py +416 -0
- xarm/tools/blockly/_blockly_handler.py +1338 -0
- xarm/tools/blockly/_blockly_highlight.py +94 -0
- xarm/tools/blockly/_blockly_node.py +61 -0
- xarm/tools/blockly/_blockly_tool.py +480 -0
- xarm/tools/blockly_tool.py +1864 -0
- xarm/tools/gcode.py +90 -0
- xarm/tools/list_ports.py +39 -0
- xarm/tools/modbus_tcp.py +205 -0
- xarm/tools/threads.py +30 -0
- xarm/tools/utils.py +36 -0
- xarm/version.py +1 -0
- xarm/wrapper/__init__.py +1 -0
- xarm/wrapper/studio_api.py +34 -0
- xarm/wrapper/xarm_api.py +4416 -0
- xarm/x3/__init__.py +2 -0
- xarm/x3/base.py +2638 -0
- xarm/x3/base_board.py +198 -0
- xarm/x3/code.py +62 -0
- xarm/x3/decorator.py +104 -0
- xarm/x3/events.py +166 -0
- xarm/x3/ft_sensor.py +264 -0
- xarm/x3/gpio.py +457 -0
- xarm/x3/grammar_async.py +21 -0
- xarm/x3/grammar_coroutine.py +24 -0
- xarm/x3/gripper.py +830 -0
- xarm/x3/modbus_tcp.py +84 -0
- xarm/x3/parse.py +110 -0
- xarm/x3/record.py +216 -0
- xarm/x3/report.py +204 -0
- xarm/x3/robotiq.py +220 -0
- xarm/x3/servo.py +485 -0
- xarm/x3/studio.py +138 -0
- xarm/x3/track.py +424 -0
- xarm/x3/utils.py +43 -0
- xarm/x3/xarm.py +1928 -0
- xarm_python_sdk-1.15.2.dist-info/METADATA +103 -0
- xarm_python_sdk-1.15.2.dist-info/RECORD +63 -0
- xarm_python_sdk-1.15.2.dist-info/WHEEL +4 -0
- xarm_python_sdk-1.15.2.dist-info/licenses/LICENSE +27 -0
xarm/__init__.py
ADDED
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
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
|