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.
Files changed (40) hide show
  1. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/PKG-INFO +13 -5
  2. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/UC2_REST.egg-info/PKG-INFO +13 -5
  3. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/UC2_REST.egg-info/SOURCES.txt +0 -1
  4. uc2_rest-0.2.0.22/UC2_REST.egg-info/requires.txt +3 -0
  5. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/setup.py +1 -1
  6. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/UC2Client.py +4 -10
  7. uc2_rest-0.2.0.22/uc2rest/__init__.py +2 -0
  8. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/__version__.py +1 -1
  9. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/galvo.py +7 -4
  10. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/home.py +13 -3
  11. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/laser.py +15 -0
  12. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/ledmatrix.py +1 -2
  13. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/motor.py +50 -6
  14. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/mserial.py +62 -14
  15. uc2_rest-0.2.0.20/UC2_REST.egg-info/requires.txt +0 -6
  16. uc2_rest-0.2.0.20/uc2rest/__init__.py +0 -6
  17. uc2_rest-0.2.0.20/uc2rest/updater.py +0 -268
  18. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/LICENSE +0 -0
  19. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/README.md +0 -0
  20. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/UC2_REST.egg-info/dependency_links.txt +0 -0
  21. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/UC2_REST.egg-info/not-zip-safe +0 -0
  22. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/UC2_REST.egg-info/top_level.txt +0 -0
  23. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/setup.cfg +0 -0
  24. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/MockSerial.py +0 -0
  25. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/analog.py +0 -0
  26. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/camera.py +0 -0
  27. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/cmdrecorder.py +0 -0
  28. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/config.py +0 -0
  29. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/config_.py +0 -0
  30. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/digitalout.py +0 -0
  31. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/logger.py +0 -0
  32. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/message.py +0 -0
  33. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/modules.py +0 -0
  34. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/pid.py +0 -0
  35. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/rotator.py +0 -0
  36. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/slm.py +0 -0
  37. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/state.py +0 -0
  38. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/temperature.py +0 -0
  39. {uc2_rest-0.2.0.20 → uc2_rest-0.2.0.22}/uc2rest/utils.py +0 -0
  40. {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
1
+ Metadata-Version: 2.2
2
2
  Name: UC2-REST
3
- Version: 0.2.0.20
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
- Requires-Dist: esptool
20
- Requires-Dist: progressbar2
21
- Requires-Dist: pillow
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
1
+ Metadata-Version: 2.2
2
2
  Name: UC2-REST
3
- Version: 0.2.0.20
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
- Requires-Dist: esptool
20
- Requires-Dist: progressbar2
21
- Requires-Dist: pillow
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">
@@ -31,6 +31,5 @@ uc2rest/rotator.py
31
31
  uc2rest/slm.py
32
32
  uc2rest/state.py
33
33
  uc2rest/temperature.py
34
- uc2rest/updater.py
35
34
  uc2rest/utils.py
36
35
  uc2rest/wifi.py
@@ -0,0 +1,3 @@
1
+ numpy
2
+ requests
3
+ pyserial
@@ -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', "esptool", "progressbar2", "pillow"],
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
- # initialize updater
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.closeSerial()
199
+ self.serial.close()
@@ -0,0 +1,2 @@
1
+ from .config import *
2
+ from .UC2Client import *
@@ -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.20"
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/2, clk_div=0, timeout=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
- "amplitude":amplitude,
27
- "clk_div": clk_div
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*1000,
81
- "speed":direction*abs(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
@@ -1,6 +1,5 @@
1
1
  import numpy as np
2
- import json
3
- import time
2
+
4
3
  gTimeout = 2
5
4
  class LedMatrix(object):
6
5
  def __init__(self, parent, NLeds=64):
@@ -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 len(acceleration)!= 2:
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 = (speed,speed,speed,speed)
242
- if type(steps)==int:
243
- steps = (steps,steps,steps,steps)
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
- time.sleep(T_SERIAL_WARMUP)
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
- try:
230
- with self.serialLock:
231
- mReadline = self.serialdevice.readline()
232
- line = mReadline.decode('utf-8').strip()
233
- if self.DEBUG and line!="": self._logger.debug("[ProcessLines]:"+str(line))
234
- except Exception as e:
235
- self._logger.error("Failed to read the line in serial: "+str(e))
236
- line = ""
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.serialdevice.write(json_command.encode('utf-8'))
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
- self._logger.debug("It takes too long to get a response, we will resend the last command")
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,6 +0,0 @@
1
- numpy
2
- requests
3
- pyserial
4
- esptool
5
- progressbar2
6
- pillow
@@ -1,6 +0,0 @@
1
- from .config import *
2
- from .UC2Client import *
3
- try:
4
- from .updater import *
5
- except:
6
- print("Updater not available")
@@ -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