serial_reader.py 4.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. # Copyright 2015-2021 Espressif Systems (Shanghai) CO LTD
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. import queue
  15. import sys
  16. import time
  17. import serial
  18. from .constants import CHECK_ALIVE_FLAG_TIMEOUT, MINIMAL_EN_LOW_DELAY, RECONNECT_DELAY, TAG_SERIAL
  19. from .output_helpers import red_print, yellow_print
  20. from .stoppable_thread import StoppableThread
  21. class SerialReader(StoppableThread):
  22. """ Read serial data from the serial port and push to the
  23. event queue, until stopped.
  24. """
  25. def __init__(self, serial_instance, event_queue):
  26. # type: (serial.Serial, queue.Queue) -> None
  27. super(SerialReader, self).__init__()
  28. self.baud = serial_instance.baudrate
  29. self.serial = serial_instance
  30. self.event_queue = event_queue
  31. self.gdb_exit = False
  32. if not hasattr(self.serial, 'cancel_read'):
  33. # enable timeout for checking alive flag,
  34. # if cancel_read not available
  35. self.serial.timeout = CHECK_ALIVE_FLAG_TIMEOUT
  36. def run(self):
  37. # type: () -> None
  38. if not self.serial.is_open:
  39. self.serial.baudrate = self.baud
  40. # We can come to this thread at startup or from external application line GDB.
  41. # If we come from GDB we would like to continue to run without reset.
  42. high = False
  43. low = True
  44. self.serial.dtr = low # Non reset state
  45. self.serial.rts = high # IO0=HIGH
  46. self.serial.dtr = self.serial.dtr # usbser.sys workaround
  47. # Current state not reset the target!
  48. self.serial.open()
  49. if not self.gdb_exit:
  50. self.serial.dtr = high # Set dtr to reset state (affected by rts)
  51. self.serial.rts = low # Set rts/dtr to the reset state
  52. self.serial.dtr = self.serial.dtr # usbser.sys workaround
  53. # Add a delay to meet the requirements of minimal EN low time (2ms for ESP32-C3)
  54. time.sleep(MINIMAL_EN_LOW_DELAY)
  55. self.gdb_exit = False
  56. self.serial.rts = high # Set rts/dtr to the working state
  57. self.serial.dtr = self.serial.dtr # usbser.sys workaround
  58. try:
  59. while self.alive:
  60. try:
  61. data = self.serial.read(self.serial.in_waiting or 1)
  62. except (serial.serialutil.SerialException, IOError) as e:
  63. data = b''
  64. # self.serial.open() was successful before, therefore, this is an issue related to
  65. # the disappearance of the device
  66. red_print(e)
  67. yellow_print('Waiting for the device to reconnect', newline='')
  68. self.serial.close()
  69. while self.alive: # so that exiting monitor works while waiting
  70. try:
  71. time.sleep(RECONNECT_DELAY)
  72. self.serial.open()
  73. break # device connected
  74. except serial.serialutil.SerialException:
  75. yellow_print('.', newline='')
  76. sys.stderr.flush()
  77. yellow_print('') # go to new line
  78. if data:
  79. self.event_queue.put((TAG_SERIAL, data), False)
  80. finally:
  81. self.serial.close()
  82. def _cancel(self):
  83. # type: () -> None
  84. if hasattr(self.serial, 'cancel_read'):
  85. try:
  86. self.serial.cancel_read()
  87. except Exception: # noqa
  88. pass