UC2-REST 0.2.0.20__tar.gz → 0.2.0.22__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.
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/PKG-INFO +13 -5
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/UC2_REST.egg-info/PKG-INFO +13 -5
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/UC2_REST.egg-info/SOURCES.txt +0 -1
- uc2_rest-0.2.0.22/UC2_REST.egg-info/requires.txt +3 -0
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/setup.py +1 -1
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/UC2Client.py +4 -10
- uc2_rest-0.2.0.22/uc2rest/__init__.py +2 -0
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/__version__.py +1 -1
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/galvo.py +7 -4
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/home.py +13 -3
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/laser.py +15 -0
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/ledmatrix.py +1 -2
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/motor.py +50 -6
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/mserial.py +62 -14
- uc2_rest-0.2.0.20/UC2_REST.egg-info/requires.txt +0 -6
- uc2_rest-0.2.0.20/uc2rest/__init__.py +0 -6
- uc2_rest-0.2.0.20/uc2rest/updater.py +0 -268
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/LICENSE +0 -0
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/README.md +0 -0
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/UC2_REST.egg-info/dependency_links.txt +0 -0
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/UC2_REST.egg-info/not-zip-safe +0 -0
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/UC2_REST.egg-info/top_level.txt +0 -0
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/setup.cfg +0 -0
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/MockSerial.py +0 -0
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/analog.py +0 -0
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/camera.py +0 -0
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/cmdrecorder.py +0 -0
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/config.py +0 -0
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/config_.py +0 -0
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/digitalout.py +0 -0
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/logger.py +0 -0
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/message.py +0 -0
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/modules.py +0 -0
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/pid.py +0 -0
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/rotator.py +0 -0
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/slm.py +0 -0
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/state.py +0 -0
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/temperature.py +0 -0
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/utils.py +0 -0
- {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/wifi.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: UC2-REST
|
|
3
|
-
Version: 0.2.0.
|
|
3
|
+
Version: 0.2.0.22
|
|
4
4
|
Summary: This pacage will help you to drive the ESP32-driven microscopy control modules from UC2
|
|
5
5
|
Home-page: https://github.com/openUC2/UC2-REST
|
|
6
6
|
Author: Benedict Diederich
|
|
@@ -16,9 +16,17 @@ License-File: LICENSE
|
|
|
16
16
|
Requires-Dist: numpy
|
|
17
17
|
Requires-Dist: requests
|
|
18
18
|
Requires-Dist: pyserial
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
Dynamic: author
|
|
20
|
+
Dynamic: author-email
|
|
21
|
+
Dynamic: classifier
|
|
22
|
+
Dynamic: description
|
|
23
|
+
Dynamic: description-content-type
|
|
24
|
+
Dynamic: home-page
|
|
25
|
+
Dynamic: keywords
|
|
26
|
+
Dynamic: license
|
|
27
|
+
Dynamic: requires-dist
|
|
28
|
+
Dynamic: requires-python
|
|
29
|
+
Dynamic: summary
|
|
22
30
|
|
|
23
31
|
|
|
24
32
|
<p align="left">
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: UC2-REST
|
|
3
|
-
Version: 0.2.0.
|
|
3
|
+
Version: 0.2.0.22
|
|
4
4
|
Summary: This pacage will help you to drive the ESP32-driven microscopy control modules from UC2
|
|
5
5
|
Home-page: https://github.com/openUC2/UC2-REST
|
|
6
6
|
Author: Benedict Diederich
|
|
@@ -16,9 +16,17 @@ License-File: LICENSE
|
|
|
16
16
|
Requires-Dist: numpy
|
|
17
17
|
Requires-Dist: requests
|
|
18
18
|
Requires-Dist: pyserial
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
Dynamic: author
|
|
20
|
+
Dynamic: author-email
|
|
21
|
+
Dynamic: classifier
|
|
22
|
+
Dynamic: description
|
|
23
|
+
Dynamic: description-content-type
|
|
24
|
+
Dynamic: home-page
|
|
25
|
+
Dynamic: keywords
|
|
26
|
+
Dynamic: license
|
|
27
|
+
Dynamic: requires-dist
|
|
28
|
+
Dynamic: requires-python
|
|
29
|
+
Dynamic: summary
|
|
22
30
|
|
|
23
31
|
|
|
24
32
|
<p align="left">
|
|
@@ -27,7 +27,7 @@ setup(
|
|
|
27
27
|
packages=['uc2rest'],
|
|
28
28
|
include_package_data=True,
|
|
29
29
|
python_requires='>=3.7',
|
|
30
|
-
install_requires=['numpy', 'requests', 'pyserial'
|
|
30
|
+
install_requires=['numpy', 'requests', 'pyserial'],
|
|
31
31
|
license=about['__license__'],
|
|
32
32
|
zip_safe=False,
|
|
33
33
|
entry_points={
|
|
@@ -84,9 +84,7 @@ class UC2Client(object):
|
|
|
84
84
|
else:
|
|
85
85
|
self.logger.error("No ESP32 device is connected - check IP or Serial port!")
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
if not self.isPyScript: from .updater import updater
|
|
89
|
-
|
|
87
|
+
|
|
90
88
|
# import libraries depending on API version
|
|
91
89
|
self.logger.debug("Using API version 2")
|
|
92
90
|
|
|
@@ -150,11 +148,7 @@ class UC2Client(object):
|
|
|
150
148
|
try: self.pinConfig = self.config.loadConfigDevice()
|
|
151
149
|
except: self.pinConfig = None
|
|
152
150
|
|
|
153
|
-
|
|
154
|
-
if not self.isPyScript:
|
|
155
|
-
try: self.updater = updater(parent=self)
|
|
156
|
-
except: self.updater = None
|
|
157
|
-
|
|
151
|
+
|
|
158
152
|
# initialize module controller
|
|
159
153
|
self.modules = Modules(parent=self)
|
|
160
154
|
|
|
@@ -192,7 +186,7 @@ class UC2Client(object):
|
|
|
192
186
|
if timeout <=0:
|
|
193
187
|
getReturn = False
|
|
194
188
|
return self.serial.post_json(path, payload=None, getReturn=getReturn, nResponses=1, timeout=timeout)
|
|
195
|
-
#return self.serial.read_json()
|
|
189
|
+
#return self.serial.read_json()<
|
|
196
190
|
else:
|
|
197
191
|
self.logger.error("No ESP32 device is connected - check IP or Serial port!")
|
|
198
192
|
return None
|
|
@@ -202,4 +196,4 @@ class UC2Client(object):
|
|
|
202
196
|
self.serial.DEBUG = debug
|
|
203
197
|
|
|
204
198
|
def close(self):
|
|
205
|
-
self.serial.
|
|
199
|
+
self.serial.close()
|
|
@@ -6,7 +6,7 @@ __version__.py
|
|
|
6
6
|
|
|
7
7
|
__title__ = 'UC2-REST'
|
|
8
8
|
__description__ = 'This pacage will help you to drive the ESP32-driven microscopy control modules from UC2'
|
|
9
|
-
__version__ = "v0.2.0.
|
|
9
|
+
__version__ = "v0.2.0.22"
|
|
10
10
|
__author__ = 'Benedict Diederich'
|
|
11
11
|
__author_email__ = 'benedictdied@gmail.com'
|
|
12
12
|
__license__ = 'GPL v3'
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import numpy as np
|
|
1
2
|
class Galvo(object):
|
|
2
3
|
def __init__(self, parent=None):
|
|
3
4
|
'''
|
|
@@ -15,16 +16,18 @@ class Galvo(object):
|
|
|
15
16
|
self._parent = parent
|
|
16
17
|
|
|
17
18
|
|
|
18
|
-
def set_dac(self, channel=1, frequency=1, offset=0, amplitude=1
|
|
19
|
-
|
|
19
|
+
def set_dac(self, channel=1, frequency=1, offset=0, amplitude=1, clk_div=0, phase=0, invert=1, timeout=1):
|
|
20
|
+
# {"task":"/dac_act", "dac_channel":1, "frequency":10, "offset":1, "amplitude":1, "divider":0, "phase":0, "invert":1, "qid":2}
|
|
20
21
|
path = "/dac_act"
|
|
21
22
|
payload = {
|
|
22
23
|
"task": path,
|
|
23
24
|
"dac_channel": channel, # 1 or 2
|
|
24
25
|
"frequency": frequency,
|
|
25
26
|
"offset": offset,
|
|
26
|
-
"
|
|
27
|
-
"
|
|
27
|
+
"divider": clk_div,
|
|
28
|
+
"amplitude":amplitude,
|
|
29
|
+
"phase":phase,
|
|
30
|
+
"invert":invert
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
self._parent.post_json(path, payload, timeout=timeout, getReturn=False)
|
|
@@ -44,6 +44,17 @@ class Home(object):
|
|
|
44
44
|
endstoppolarity=endstoppolarity,
|
|
45
45
|
isBlocking=isBlocking)
|
|
46
46
|
|
|
47
|
+
def home_a(self, speed = None, direction = None, endposrelease = None, endstoppolarity=None, timeout=None, isBlocking=False):
|
|
48
|
+
# axis = 0 corresponds to 'A'
|
|
49
|
+
axis = 0
|
|
50
|
+
self.home(axis=axis,
|
|
51
|
+
timeout=timeout,
|
|
52
|
+
speed = speed,
|
|
53
|
+
direction = direction,
|
|
54
|
+
endposrelease=endposrelease,
|
|
55
|
+
endstoppolarity=endstoppolarity,
|
|
56
|
+
isBlocking=isBlocking)
|
|
57
|
+
|
|
47
58
|
def home(self, axis=None, timeout=None, speed=None, direction=None, endposrelease=None, endstoppolarity=None, isBlocking=False):
|
|
48
59
|
'''
|
|
49
60
|
axis = 0,1,2,3 or 'A, 'X','Y','Z'
|
|
@@ -77,10 +88,9 @@ class Home(object):
|
|
|
77
88
|
"steppers": [
|
|
78
89
|
{
|
|
79
90
|
"stepperid": axis,
|
|
80
|
-
"timeout":timeout
|
|
81
|
-
"speed":
|
|
91
|
+
"timeout":timeout,
|
|
92
|
+
"speed":abs(speed),
|
|
82
93
|
"direction":direction,
|
|
83
|
-
"endposrelease":endposrelease,
|
|
84
94
|
"endstoppolarity":endstoppolarity
|
|
85
95
|
}]
|
|
86
96
|
}}
|
|
@@ -60,3 +60,18 @@ class Laser(object):
|
|
|
60
60
|
r = self._parent.post_json(path, payload)
|
|
61
61
|
return r
|
|
62
62
|
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def set_servo(self, channel=1, value=0, is_blocking=False):
|
|
66
|
+
#{"task":"/laser_act", "LASERid":1 ,"LASERval":99, "servo":1, "qid":1}
|
|
67
|
+
path = '/laser_act'
|
|
68
|
+
|
|
69
|
+
payload = {
|
|
70
|
+
"task": path,
|
|
71
|
+
"LASERid": channel,
|
|
72
|
+
"LASERval": value,
|
|
73
|
+
"servo": 1
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
r = self._parent.post_json(path, payload, getReturn=is_blocking)
|
|
77
|
+
return r
|
|
@@ -75,10 +75,11 @@ class Motor(object):
|
|
|
75
75
|
into the position array of the motors '''
|
|
76
76
|
try:
|
|
77
77
|
nSteppers = len(data["steppers"])
|
|
78
|
+
stepSizes = np.array((self.stepSizeA, self.stepSizeX, self.stepSizeY, self.stepSizeZ))
|
|
78
79
|
for iMotor in range(nSteppers):
|
|
79
80
|
stepperID = data["steppers"][iMotor]["stepperid"]
|
|
80
|
-
# smart to re-update this variable? Will be updated by motor-sender too
|
|
81
|
-
self._position[stepperID] = data["steppers"][iMotor]["position"]
|
|
81
|
+
# FIXME: smart to re-update this variable? Will be updated by motor-sender too
|
|
82
|
+
self._position[stepperID] = data["steppers"][iMotor]["position"] * stepSizes[stepperID]
|
|
82
83
|
if callable(self._callbackPerKey[0]):
|
|
83
84
|
self._callbackPerKey[0](self._position) # we call the function with the value
|
|
84
85
|
except Exception as e:
|
|
@@ -218,7 +219,10 @@ class Motor(object):
|
|
|
218
219
|
if type(speed)==int or len(speed)!= 2:
|
|
219
220
|
speed = (speed,speed)
|
|
220
221
|
|
|
221
|
-
if
|
|
222
|
+
if acceleration is None:
|
|
223
|
+
acceleration = 100000
|
|
224
|
+
|
|
225
|
+
if type(acceleration)==int or len(acceleration)!= 2:
|
|
222
226
|
acceleration = (acceleration,acceleration)
|
|
223
227
|
|
|
224
228
|
# motor axis is 1,2,3,0 => X,Y,Z,T # FIXME: Hardcoded
|
|
@@ -237,10 +241,14 @@ class Motor(object):
|
|
|
237
241
|
return r
|
|
238
242
|
|
|
239
243
|
def move_xyza(self, steps=(0,0,0,0), speed=(1000,1000,1000,1000), acceleration=None, is_blocking=False, is_absolute=False, is_enabled=True, timeout=gTIMEOUT):
|
|
244
|
+
# everywhere, where relative steps are zero, speed should be zero, too
|
|
240
245
|
if type(speed)==int:
|
|
241
|
-
speed =
|
|
242
|
-
if type(
|
|
243
|
-
|
|
246
|
+
speed = [speed,speed,speed,speed]
|
|
247
|
+
if type(speed)==tuple:
|
|
248
|
+
speed = list(speed)
|
|
249
|
+
for iMotor in range(len(steps)):
|
|
250
|
+
if steps[iMotor]==0 and not is_absolute:
|
|
251
|
+
speed[iMotor] = 0
|
|
244
252
|
|
|
245
253
|
r = self.move_stepper(steps=steps, speed=speed, acceleration=acceleration, is_blocking=is_blocking, is_absolute=is_absolute, is_enabled=is_enabled, timeout=timeout)
|
|
246
254
|
return r
|
|
@@ -543,6 +551,7 @@ class Motor(object):
|
|
|
543
551
|
|
|
544
552
|
# this may be an asynchronous call.. #FIXME!
|
|
545
553
|
r = self._parent.post_json(path, payload, getReturn = True, nResponses=1, timeout=timeout)
|
|
554
|
+
# returns {"motor": }
|
|
546
555
|
if "motor" in r:
|
|
547
556
|
for index, istepper in enumerate(r["motor"]["steppers"]):
|
|
548
557
|
_position[istepper["stepperid"]]=istepper["position"]*_physicalStepSizes[self.motorAxisOrder[index]]
|
|
@@ -592,3 +601,38 @@ class Motor(object):
|
|
|
592
601
|
|
|
593
602
|
def set_direction(self, axis=1, sign=1, timeout=1):
|
|
594
603
|
return False
|
|
604
|
+
|
|
605
|
+
def set_tmc_parameters(self, axis=0, msteps=None, rms_current=None, stall_value=None, sgthrs=None, semin=None, semax=None, blank_time=None, toff=None, timeout=1):
|
|
606
|
+
''' set the TMC parameters for a specific axis
|
|
607
|
+
msteps: microsteps
|
|
608
|
+
rms_current: current in mA
|
|
609
|
+
sgthrs: stallguard threshold
|
|
610
|
+
semin: minimum current
|
|
611
|
+
semax: maximum current
|
|
612
|
+
blank_time: blank time
|
|
613
|
+
toff: off time
|
|
614
|
+
# {"task":"/tmc_act", "msteps":32, "rms_current":600, "sgthrs":100, "semin":5, "semax":2, "blank_time":24, "toff":4, "axis":1}
|
|
615
|
+
'''
|
|
616
|
+
if type(axis)==str:
|
|
617
|
+
axis = self.xyztTo1230(axis)
|
|
618
|
+
path = "/tmc_act"
|
|
619
|
+
payload = {}
|
|
620
|
+
if axis is not None:
|
|
621
|
+
payload["axis"] = axis
|
|
622
|
+
if msteps is not None:
|
|
623
|
+
payload["msteps"] = msteps
|
|
624
|
+
if rms_current is not None:
|
|
625
|
+
payload["rms_current"] = rms_current
|
|
626
|
+
if sgthrs is not None:
|
|
627
|
+
payload["sgthrs"] = sgthrs
|
|
628
|
+
if semin is not None:
|
|
629
|
+
payload["semin"] = semin
|
|
630
|
+
if semax is not None:
|
|
631
|
+
payload["semax"] = semax
|
|
632
|
+
if blank_time is not None:
|
|
633
|
+
payload["blank_time"] = blank_time
|
|
634
|
+
if toff is not None:
|
|
635
|
+
payload["toff"] = toff
|
|
636
|
+
|
|
637
|
+
r = self._parent.post_json(path, payload, timeout=timeout)
|
|
638
|
+
return r
|
|
@@ -5,7 +5,7 @@ import queue
|
|
|
5
5
|
import threading
|
|
6
6
|
import time
|
|
7
7
|
|
|
8
|
-
T_SERIAL_WARMUP = 2.5
|
|
8
|
+
T_SERIAL_WARMUP = 1#2.5
|
|
9
9
|
class Serial:
|
|
10
10
|
def __init__(self, port, baudrate=115200, timeout=5,
|
|
11
11
|
identity="UC2_Feather", parent=None, DEBUG=False):
|
|
@@ -104,7 +104,7 @@ class Serial:
|
|
|
104
104
|
pass
|
|
105
105
|
self.running = True
|
|
106
106
|
self.identifier_counter = 0 # Counter for generating unique identifiers
|
|
107
|
-
self.thread = threading.Thread(target=self._process_commands)
|
|
107
|
+
self.thread = threading.Thread(target=self._process_commands, daemon=True)
|
|
108
108
|
self.thread.start()
|
|
109
109
|
|
|
110
110
|
# setup sender queue
|
|
@@ -142,7 +142,14 @@ class Serial:
|
|
|
142
142
|
def tryToConnect(self, port):
|
|
143
143
|
try:
|
|
144
144
|
self.serialdevice = serial.Serial(port=port, baudrate=self.baudrate, timeout=self.read_timeout, write_timeout=self.write_timeout)
|
|
145
|
-
|
|
145
|
+
# close the device - similar to hard reset
|
|
146
|
+
self.serialdevice.setDTR(False)
|
|
147
|
+
self.serialdevice.setRTS(True)
|
|
148
|
+
time.sleep(.1)
|
|
149
|
+
self.serialdevice.setDTR(False)
|
|
150
|
+
self.serialdevice.setRTS(False)
|
|
151
|
+
time.sleep(.5)
|
|
152
|
+
#time.sleep(T_SERIAL_WARMUP)
|
|
146
153
|
self._freeSerialBuffer(self.serialdevice, timeout=2, timeMinimum=1)
|
|
147
154
|
if self.checkFirmware(self.serialdevice):
|
|
148
155
|
self.is_connected = True
|
|
@@ -213,6 +220,8 @@ class Serial:
|
|
|
213
220
|
currentIdentifier = None
|
|
214
221
|
nLineCountTimeout = 50 # maximum number of lines read before timeout
|
|
215
222
|
lineCounter = 0
|
|
223
|
+
nFailedCommands = 0
|
|
224
|
+
nFailedCommandsMax = 5
|
|
216
225
|
while self.running:
|
|
217
226
|
if self.manufacturer == "UC2Mock":
|
|
218
227
|
self.running = False
|
|
@@ -226,17 +235,38 @@ class Serial:
|
|
|
226
235
|
self.is_connected = True
|
|
227
236
|
|
|
228
237
|
# if we just want to send but not even wait for a response
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
238
|
+
with self.serialLock:
|
|
239
|
+
try:
|
|
240
|
+
mReadline = self.serialdevice.readline()
|
|
241
|
+
line = mReadline.decode('utf-8').strip()
|
|
242
|
+
if self.DEBUG and line!="":
|
|
243
|
+
self._logger.debug("[ProcessLines]:"+str(line))
|
|
244
|
+
except Exception as e:
|
|
245
|
+
self._logger.error("Failed to read the line in serial: "+str(e))
|
|
246
|
+
nFailedCommands += 1
|
|
247
|
+
line = ""
|
|
248
|
+
|
|
249
|
+
# if we have a problem with the serial connection, we need to reconnect
|
|
250
|
+
for i in range(4):
|
|
251
|
+
if self.reconnect():
|
|
252
|
+
self._logger.debug("Reconnected to the serial device")
|
|
253
|
+
break
|
|
254
|
+
else:
|
|
255
|
+
self._logger.debug("Failed to reconnect to the serial device")
|
|
256
|
+
time.sleep(1)
|
|
257
|
+
|
|
237
258
|
if line == "++":
|
|
238
259
|
reading_json = True
|
|
239
260
|
continue
|
|
261
|
+
elif line.find("error") != -1:
|
|
262
|
+
# if we have an error, we need to reset the last command
|
|
263
|
+
self._logger.debug("Error - last command did not match the firmware: "+str(self.commands[currentIdentifier]))
|
|
264
|
+
self.resetLastCommand = True
|
|
265
|
+
buffer = ""
|
|
266
|
+
lineCounter = 0
|
|
267
|
+
reading_json = False
|
|
268
|
+
self.responses[currentIdentifier].append({"error": 1})
|
|
269
|
+
self.responses[currentIdentifier].append({"qid": currentIdentifier})
|
|
240
270
|
elif line == "--" or lineCounter>nLineCountTimeout:
|
|
241
271
|
lineCounter = 0
|
|
242
272
|
reading_json = False
|
|
@@ -246,6 +276,7 @@ class Serial:
|
|
|
246
276
|
for callback in self.callBackList:
|
|
247
277
|
# check if json has key
|
|
248
278
|
try:
|
|
279
|
+
self._logger.debug("[ProcessCommands]: "+str(json_response))
|
|
249
280
|
if callback["pattern"] in json_response:
|
|
250
281
|
callback["callbackfct"](json_response)
|
|
251
282
|
except Exception as e:
|
|
@@ -255,6 +286,7 @@ class Serial:
|
|
|
255
286
|
self._logger.error("Failed to load the json from serial %s" % buffer)
|
|
256
287
|
self._logger.error("Error: %s" % str(e))
|
|
257
288
|
json_response = {}
|
|
289
|
+
reading_json = True
|
|
258
290
|
|
|
259
291
|
try: currentIdentifier = json_response["qid"]
|
|
260
292
|
except: pass
|
|
@@ -341,7 +373,8 @@ class Serial:
|
|
|
341
373
|
json_command = json.dumps(command)+"\n"
|
|
342
374
|
#self.serialdevice.flush()
|
|
343
375
|
if self.DEBUG and json_command!="": self._logger.debug("[SendingCommands]:"+str(json_command))
|
|
344
|
-
self.
|
|
376
|
+
with self.serialLock:
|
|
377
|
+
self.serialdevice.write(json_command.encode('utf-8'))
|
|
345
378
|
#time.sleep(1)
|
|
346
379
|
# we have to queue the commands and give it some time to process
|
|
347
380
|
#self._enqueue_command(json_command)
|
|
@@ -355,6 +388,8 @@ class Serial:
|
|
|
355
388
|
return identifier
|
|
356
389
|
t0 = time.time()
|
|
357
390
|
timeReturnReceived = 0.3
|
|
391
|
+
maxRetry = 3
|
|
392
|
+
iRetry = 0
|
|
358
393
|
while self.running:
|
|
359
394
|
time.sleep(0.002)
|
|
360
395
|
if self.resetLastCommand or time.time()-t0>timeout or not self.is_connected:
|
|
@@ -368,9 +403,16 @@ class Serial:
|
|
|
368
403
|
self._logger.debug("You have sent the wrong command!")
|
|
369
404
|
return "Wrong Command"
|
|
370
405
|
if time.time()-t0>timeReturnReceived and not (identifier in self.responses and len(self.responses[identifier]) > 0):
|
|
371
|
-
|
|
406
|
+
if iRetry > maxRetry:
|
|
407
|
+
self.resetLastCommand = True
|
|
408
|
+
return "No response received"
|
|
409
|
+
self._logger.debug("It takes too long to get a response, we will resend the last command: "+str(self.commands[identifier]))
|
|
372
410
|
try:
|
|
411
|
+
ERROR="We have a queue, so after a while we need to resend the wrong command!"
|
|
412
|
+
iRetry += 1
|
|
413
|
+
raise Exception(ERROR)
|
|
373
414
|
self.serialdevice.write(json.dumps(self.commands[identifier]).encode('utf-8'))
|
|
415
|
+
t0 = time.time()
|
|
374
416
|
time.sleep(0.1)
|
|
375
417
|
except Exception as e:
|
|
376
418
|
self._logger.error("Failed to write the line in serial: "+str(e))
|
|
@@ -388,7 +430,11 @@ class Serial:
|
|
|
388
430
|
self.stop()
|
|
389
431
|
self.running = False
|
|
390
432
|
|
|
433
|
+
def close(self):
|
|
434
|
+
self.closeSerial()
|
|
435
|
+
|
|
391
436
|
def reconnect(self, baudrate=None):
|
|
437
|
+
self._logger.debug("Reconnecting to the serial device")
|
|
392
438
|
self.running = False
|
|
393
439
|
if baudrate is not None:
|
|
394
440
|
self.baudrate = baudrate
|
|
@@ -397,6 +443,8 @@ class Serial:
|
|
|
397
443
|
except:
|
|
398
444
|
pass
|
|
399
445
|
self.serialdevice = self.openDevice(port = self.serialport, baud_rate = self.baudrate)
|
|
446
|
+
if self.serialdevice: return True
|
|
447
|
+
return False
|
|
400
448
|
|
|
401
449
|
def toggleCommandOutput(self, cmdCallBackFct=None):
|
|
402
450
|
# if true, all commands will be output to a callback function and stored for later use
|
|
@@ -526,4 +574,4 @@ if __name__ == "__main__":
|
|
|
526
574
|
#response = monitor.waitForResponse(command_id)
|
|
527
575
|
|
|
528
576
|
if response:
|
|
529
|
-
print("Response:", response)
|
|
577
|
+
print("Response:", response)
|
|
@@ -1,268 +0,0 @@
|
|
|
1
|
-
import subprocess
|
|
2
|
-
import os
|
|
3
|
-
import esptool
|
|
4
|
-
import tempfile
|
|
5
|
-
import urllib
|
|
6
|
-
import threading
|
|
7
|
-
import zipfile
|
|
8
|
-
import progressbar
|
|
9
|
-
import platform
|
|
10
|
-
import glob
|
|
11
|
-
try:
|
|
12
|
-
import requests
|
|
13
|
-
is_requests = True
|
|
14
|
-
except:
|
|
15
|
-
is_requests = False
|
|
16
|
-
|
|
17
|
-
class updater(object):
|
|
18
|
-
|
|
19
|
-
def __init__(self, ESP32=None, port=None, parent=None):
|
|
20
|
-
if ESP32 is not None:
|
|
21
|
-
self.port = ESP32.serial.serialport
|
|
22
|
-
if port is not None:
|
|
23
|
-
self.port = port
|
|
24
|
-
# parent holds the entire esp object
|
|
25
|
-
if parent is not None:
|
|
26
|
-
self._parent = parent
|
|
27
|
-
self.port = self._parent.serial.serialport
|
|
28
|
-
|
|
29
|
-
# define a temporary firmware file name for the firmware download
|
|
30
|
-
self.firmwarePath = os.path.join(tempfile.gettempdir(), "uc2rest")
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def unzipFiles(self):
|
|
35
|
-
''' Unzip the UC2Rest.zip '''
|
|
36
|
-
print("Unzipping files")
|
|
37
|
-
with zipfile.ZipFile(os.path.join(self.firmwarePath, self.uc2restZip), 'r') as zip_ref:
|
|
38
|
-
zip_ref.extractall(self.firmwarePath)
|
|
39
|
-
# list the files in the directory
|
|
40
|
-
filenames = os.listdir(self.firmwarePath)
|
|
41
|
-
print("Done unzipping files:")
|
|
42
|
-
print(filenames)
|
|
43
|
-
return filenames
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
def flashFirmware(self, firmwarePath=None):
|
|
47
|
-
# sideload the firmware if already available online
|
|
48
|
-
|
|
49
|
-
self.filenames = self.unzipFiles()
|
|
50
|
-
if self._parent is not None:
|
|
51
|
-
# in case the serial is still open, perhaps it makes sense to close it
|
|
52
|
-
try:
|
|
53
|
-
self._parent.serial.closeSerial()
|
|
54
|
-
except:
|
|
55
|
-
pass
|
|
56
|
-
|
|
57
|
-
if platform.system()=="Windows":
|
|
58
|
-
try:
|
|
59
|
-
#esptool.py --chip esp32 --port /dev/cu.SLAB_USBtoUART --baud 921600
|
|
60
|
-
# --before default_reset --after hard_reset write_flash -z --flash_mode dio
|
|
61
|
-
# --flash_freq 80m --flash_size 4MB
|
|
62
|
-
# 0x1000 ./ESP32/build/main.ino.bootloader.bin
|
|
63
|
-
# 0x8000 ./ESP32/build/main.ino.partitions.bin
|
|
64
|
-
# 0xe000 ./ESP32/build/boot_app0.bin
|
|
65
|
-
# 0x10000 ./ESP32/build/main.ino.bin
|
|
66
|
-
try:
|
|
67
|
-
cmd = ["esptool.py",
|
|
68
|
-
"--chip", "esp32",
|
|
69
|
-
"--port", self.port,
|
|
70
|
-
"--baud", "921600",
|
|
71
|
-
"write_flash",
|
|
72
|
-
"--flash_freq", "80m",
|
|
73
|
-
"--flash_mode", "dio",
|
|
74
|
-
"--flash_size", "detect",
|
|
75
|
-
"0xe000", os.path.join(self.firmwarePath,"boot_app0.bin"),
|
|
76
|
-
"0x1000", os.path.join(self.firmwarePath,"main.ino.bootloader.bin"),
|
|
77
|
-
"0x8000", os.path.join(self.firmwarePath,"main.ino.partitions.bin"),
|
|
78
|
-
"0x10000", os.path.join(self.firmwarePath,"main.ino.bin")]
|
|
79
|
-
print('Using command %s' % ' '.join(cmd))
|
|
80
|
-
process = subprocess.Popen(cmd,shell=True,stderr=subprocess.PIPE, stdout=subprocess.PIPE)
|
|
81
|
-
process.wait()
|
|
82
|
-
stdout, stderr = process.communicate()
|
|
83
|
-
if str(stderr).find("not reco")>0 or not str(stdout).find("Leaving...")>0:
|
|
84
|
-
raise Exception
|
|
85
|
-
|
|
86
|
-
except Exception as e:
|
|
87
|
-
print(e)
|
|
88
|
-
print("We will try an alternative route:")
|
|
89
|
-
try:
|
|
90
|
-
cmd = ["python -m esptool",
|
|
91
|
-
"--chip", "esp32",
|
|
92
|
-
"--port", self.port,
|
|
93
|
-
"--baud", "921600",
|
|
94
|
-
"write_flash",
|
|
95
|
-
"--flash_freq", "80m",
|
|
96
|
-
"--flash_mode", "dio",
|
|
97
|
-
"--flash_size", "detect",
|
|
98
|
-
"0xe000", os.path.join(self.firmwarePath,"boot_app0.bin"),
|
|
99
|
-
"0x1000", os.path.join(self.firmwarePath,"main.ino.bootloader.bin"),
|
|
100
|
-
"0x8000", os.path.join(self.firmwarePath,"main.ino.partitions.bin"),
|
|
101
|
-
"0x10000", os.path.join(self.firmwarePath,"main.ino.bin")]
|
|
102
|
-
print('Using command %s' % ' '.join(cmd))
|
|
103
|
-
env = os.environ
|
|
104
|
-
process = subprocess.Popen(cmd,shell=True, env=env,stderr=subprocess.PIPE, stdout=subprocess.PIPE)
|
|
105
|
-
process.wait()
|
|
106
|
-
stdout, stderr = process.communicate()
|
|
107
|
-
if str(stderr).find("not reco")>0 or not str(stdout).find("Leaving...")>0:
|
|
108
|
-
raise Exception
|
|
109
|
-
except Exception as e:
|
|
110
|
-
print(e)
|
|
111
|
-
print("We will try an alternative route:")
|
|
112
|
-
try:
|
|
113
|
-
# special weindows case?
|
|
114
|
-
cmd = ["esptool",
|
|
115
|
-
"--chip", "esp32",
|
|
116
|
-
"--port", self.port,
|
|
117
|
-
"--baud", "921600",
|
|
118
|
-
"write_flash",
|
|
119
|
-
"--flash_freq", "80m",
|
|
120
|
-
"--flash_mode", "dio",
|
|
121
|
-
"--flash_size", "detect",
|
|
122
|
-
"0xe000", os.path.join(self.firmwarePath,"boot_app0.bin"),
|
|
123
|
-
"0x1000", os.path.join(self.firmwarePath,"main.ino.bootloader.bin"),
|
|
124
|
-
"0x8000", os.path.join(self.firmwarePath,"main.ino.partitions.bin"),
|
|
125
|
-
"0x10000", os.path.join(self.firmwarePath,"main.ino.bin")]
|
|
126
|
-
print('Using command %s' % ' '.join(cmd))
|
|
127
|
-
env = os.environ
|
|
128
|
-
process = subprocess.Popen(cmd,shell=True, env=env)
|
|
129
|
-
process.wait()
|
|
130
|
-
except Exception as e:
|
|
131
|
-
print(e)
|
|
132
|
-
print("Firmware not flashed.")
|
|
133
|
-
return False
|
|
134
|
-
print("Firmware flashed")
|
|
135
|
-
return True
|
|
136
|
-
except Exception as e:
|
|
137
|
-
print(e)
|
|
138
|
-
print("Firmware flash failed")
|
|
139
|
-
return False
|
|
140
|
-
|
|
141
|
-
else:
|
|
142
|
-
try:
|
|
143
|
-
try:
|
|
144
|
-
cmd = ["esptool.py",
|
|
145
|
-
"--chip", "esp32",
|
|
146
|
-
"--port", self.port,
|
|
147
|
-
"--baud", "921600",
|
|
148
|
-
"write_flash",
|
|
149
|
-
"--flash_freq", "80m",
|
|
150
|
-
"--flash_mode", "dio",
|
|
151
|
-
"--flash_size", "detect",
|
|
152
|
-
"0xe000", os.path.join(self.firmwarePath,"boot_app0.bin"),
|
|
153
|
-
"0x1000", os.path.join(self.firmwarePath,"main.ino.bootloader.bin"),
|
|
154
|
-
"0x8000", os.path.join(self.firmwarePath,"main.ino.partitions.bin"),
|
|
155
|
-
"0x10000", os.path.join(self.firmwarePath,"main.ino.bin")]
|
|
156
|
-
print('Using command %s' % ' '.join(cmd))
|
|
157
|
-
process = subprocess.Popen(cmd)
|
|
158
|
-
process.wait()
|
|
159
|
-
except Exception as e:
|
|
160
|
-
print(e)
|
|
161
|
-
print("We will try an alternative route:")
|
|
162
|
-
cmd = ["python -m esptool",
|
|
163
|
-
"--chip", "esp32",
|
|
164
|
-
"--port", self.port,
|
|
165
|
-
"--baud", "921600",
|
|
166
|
-
"write_flash",
|
|
167
|
-
"--flash_freq", "80m",
|
|
168
|
-
"--flash_mode", "dio",
|
|
169
|
-
"--flash_size", "detect",
|
|
170
|
-
"0xe000", os.path.join(self.firmwarePath,"boot_app0.bin"),
|
|
171
|
-
"0x1000", os.path.join(self.firmwarePath,"main.ino.bootloader.bin"),
|
|
172
|
-
"0x8000", os.path.join(self.firmwarePath,"main.ino.partitions.bin"),
|
|
173
|
-
"0x10000", os.path.join(self.firmwarePath,"main.ino.bin")]
|
|
174
|
-
print('Using command %s' % ' '.join(cmd))
|
|
175
|
-
process = subprocess.Popen(cmd)
|
|
176
|
-
process.wait()
|
|
177
|
-
print("Firmware flashed")
|
|
178
|
-
return True
|
|
179
|
-
except Exception as e:
|
|
180
|
-
print(e)
|
|
181
|
-
print("Firmware flash failed")
|
|
182
|
-
return False
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
def downloadFirmware(self):
|
|
186
|
-
|
|
187
|
-
print("We are checking for pre-built binaries on Github")
|
|
188
|
-
self.firmwareDownloadPath = 'https://api.github.com/repos/youseetoo/uc2-esp32/releases/latest'
|
|
189
|
-
releaseResponse = requests.get(
|
|
190
|
-
self.firmwareDownloadPath
|
|
191
|
-
)
|
|
192
|
-
latestVersion = releaseResponse.json()['tag_name']
|
|
193
|
-
print("Latest version is: "+latestVersion)
|
|
194
|
-
|
|
195
|
-
## attempting to downloda the current ImSwitch version
|
|
196
|
-
self.downloadURL = releaseResponse.json()['assets'][0]['browser_download_url']
|
|
197
|
-
self.uc2restZip = "UC2Rest.zip"
|
|
198
|
-
print("We are downloading the software from: "+self.uc2restZip)
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
print("Downloading Firmware from "+self.firmwareDownloadPath)
|
|
202
|
-
# download the firmware from github
|
|
203
|
-
## inplace replacement won't work I guess? => seems to work
|
|
204
|
-
def dlImSwitch(downloadURL, fileName):
|
|
205
|
-
resultDL = urllib.request.urlretrieve(downloadURL, fileName, MyProgressBar())
|
|
206
|
-
print("Done Downloading")
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
try:
|
|
210
|
-
if not os.path.exists(self.firmwarePath):
|
|
211
|
-
os.makedirs(self.firmwarePath)
|
|
212
|
-
# remove file if exists
|
|
213
|
-
if os.path.exists(self.firmwarePath+self.uc2restZip):
|
|
214
|
-
os.remove(os.path.join(self.firmwarePath,self.uc2restZip))
|
|
215
|
-
|
|
216
|
-
# download the new version in a separate thread
|
|
217
|
-
mThread = threading.Thread(target=dlImSwitch, args=(self.downloadURL, os.path.join(self.firmwarePath,self.uc2restZip)))
|
|
218
|
-
mThread.start()
|
|
219
|
-
mThread.join()
|
|
220
|
-
|
|
221
|
-
print("Succesfully downloaded file: "+os.path.join(self.firmwarePath, self.uc2restZip))
|
|
222
|
-
return True
|
|
223
|
-
except Exception as e:
|
|
224
|
-
print(e)
|
|
225
|
-
print("Firmware download failed"+self.uc2restZip)
|
|
226
|
-
|
|
227
|
-
return False
|
|
228
|
-
|
|
229
|
-
def removeFirmware(self):
|
|
230
|
-
try:
|
|
231
|
-
print("Removing Firmware:"+self.uc2restZip)
|
|
232
|
-
for ifile in glob.glob(self.firmwarePath+"/*"):
|
|
233
|
-
try:os.remove(ifile)
|
|
234
|
-
except:pass
|
|
235
|
-
return True
|
|
236
|
-
except Exception as e:
|
|
237
|
-
print(e)
|
|
238
|
-
return False
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
class MyProgressBar():
|
|
243
|
-
def __init__(self):
|
|
244
|
-
self.pbar = None
|
|
245
|
-
|
|
246
|
-
def __call__(self, block_num, block_size, total_size):
|
|
247
|
-
if not self.pbar:
|
|
248
|
-
self.pbar=progressbar.ProgressBar(maxval=total_size)
|
|
249
|
-
self.pbar.start()
|
|
250
|
-
|
|
251
|
-
downloaded = block_num * block_size
|
|
252
|
-
if downloaded < total_size:
|
|
253
|
-
self.pbar.update(downloaded)
|
|
254
|
-
else:
|
|
255
|
-
self.pbar.finish()
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
if __name__ == "__main__":
|
|
259
|
-
updater = updater(port="/dev/cu.SLAB_USBtoUART", firmwarePath=None)
|
|
260
|
-
updater.downloadFirmware()
|
|
261
|
-
updater.flashFirmware()
|
|
262
|
-
|
|
263
|
-
# remove firmware.bin after flashing
|
|
264
|
-
updater.removeFirmware()
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|