Dmitry преди 4 години
родител
ревизия
a16ae6c737
променени са 2 файла, в които са добавени 103 реда и са изтрити 32 реда
  1. 82 29
      tools/idf_monitor.py
  2. 21 3
      tools/idf_monitor_base/serial_reader.py

+ 82 - 29
tools/idf_monitor.py

@@ -140,6 +140,8 @@ class Monitor(object):
         self._decode_panic = decode_panic
         self._reading_panic = PANIC_IDLE
         self._panic_buffer = b''
+        self.gdb_exit = False
+        self.start_cmd_sent = False
 
     def invoke_processing_last_line(self):
         # type: () -> None
@@ -149,43 +151,70 @@ class Monitor(object):
         # type: () -> None
         self.console_reader.start()
         self.serial_reader.start()
+        self.gdb_exit = False
+        self.start_cmd_sent = False
         try:
             while self.console_reader.alive and self.serial_reader.alive:
                 try:
-                    item = self.cmd_queue.get_nowait()
-                except queue.Empty:
+                    if self.gdb_exit is True:
+                        self.gdb_exit = False
+
+                        time.sleep(0.3)
+                        try:
+                            # Continue the program after exit from the GDB
+                            self.serial.write(codecs.encode('+$c#63'))
+                            self.start_cmd_sent = True
+                        except serial.SerialException:
+                            pass  # this shouldn't happen, but sometimes port has closed in serial thread
+                        except UnicodeEncodeError:
+                            pass  # this can happen if a non-ascii character was passed, ignoring
+
                     try:
-                        item = self.event_queue.get(True, 0.03)
+                        item = self.cmd_queue.get_nowait()
                     except queue.Empty:
-                        continue
-
-                event_tag, data = item
-                if event_tag == TAG_CMD:
-                    self.handle_commands(data, self.target)
-                elif event_tag == TAG_KEY:
+                        try:
+                            item = self.event_queue.get(True, 0.03)
+                        except queue.Empty:
+                            continue
+
+                    (event_tag, data) = item
+
+                    if event_tag == TAG_CMD:
+                        self.handle_commands(data, self.target)
+                    elif event_tag == TAG_KEY:
+                        try:
+                            self.serial.write(codecs.encode(data))
+                        except serial.SerialException:
+                            pass  # this shouldn't happen, but sometimes port has closed in serial thread
+                        except UnicodeEncodeError:
+                            pass  # this can happen if a non-ascii character was passed, ignoring
+                    elif event_tag == TAG_SERIAL:
+                        self.handle_serial_input(data)
+                        if self._invoke_processing_last_line_timer is not None:
+                            self._invoke_processing_last_line_timer.cancel()
+                        self._invoke_processing_last_line_timer = threading.Timer(0.1, self.invoke_processing_last_line)
+                        self._invoke_processing_last_line_timer.start()
+                        # If no futher data is received in the next short period
+                        # of time then the _invoke_processing_last_line_timer
+                        # generates an event which will result in the finishing of
+                        # the last line. This is fix for handling lines sent
+                        # without EOL.
+                    elif event_tag == TAG_SERIAL_FLUSH:
+                        self.handle_serial_input(data, finalize_line=True)
+                    else:
+                        raise RuntimeError("Bad event data %r" % ((event_tag,data),))
+                except KeyboardInterrupt:
                     try:
-                        self.serial.write(codecs.encode(data))
+                        yellow_print("To exit from IDF monitor please use \"Ctrl+]\"")
+                        self.serial.write(codecs.encode('\x03'))
                     except serial.SerialException:
                         pass  # this shouldn't happen, but sometimes port has closed in serial thread
                     except UnicodeEncodeError:
                         pass  # this can happen if a non-ascii character was passed, ignoring
-                elif event_tag == TAG_SERIAL:
-                    self.handle_serial_input(data)
-                    if self._invoke_processing_last_line_timer is not None:
-                        self._invoke_processing_last_line_timer.cancel()
-                    self._invoke_processing_last_line_timer = threading.Timer(0.1, self.invoke_processing_last_line)
-                    self._invoke_processing_last_line_timer.start()
-                    # If no further data is received in the next short period
-                    # of time then the _invoke_processing_last_line_timer
-                    # generates an event which will result in the finishing of
-                    # the last line. This is fix for handling lines sent
-                    # without EOL.
-                elif event_tag == TAG_SERIAL_FLUSH:
-                    self.handle_serial_input(data, finalize_line=True)
-                else:
-                    raise RuntimeError('Bad event data %r' % ((event_tag, data),))
         except SerialStopException:
             normal_print('Stopping condition has been received\n')
+        except KeyboardInterrupt:
+            pass
         finally:
             try:
                 self.console_reader.stop()
@@ -200,6 +229,13 @@ class Monitor(object):
 
     def handle_serial_input(self, data, finalize_line=False):
         # type: (bytes, bool) -> None
+        # Remove "+" after Continue command
+        if self.start_cmd_sent is True:
+            self.start_cmd_sent = False
+            pos = data.find(b"+")
+            if pos != -1:
+                data = data[1:]
+
         sp = data.split(b'\n')
         if self._last_line_part != b'':
             # add unprocessed part from previous "data" to the first line
@@ -260,6 +296,7 @@ class Monitor(object):
     def __exit__(self, *args, **kwargs):  # type: ignore
         """ Use 'with self' to temporarily disable monitoring behaviour """
         self.console_reader.start()
+        self.serial_reader.gdb_exit = self.gdb_exit     # write gdb_exit flag
         self.serial_reader.start()
 
     def prompt_next_action(self, reason):  # type: (str) -> None
@@ -480,10 +517,25 @@ class Monitor(object):
                 cmd = ['%sgdb' % self.toolchain_prefix,
                        '-ex', 'set serial baud %d' % self.serial.baudrate,
                        '-ex', 'target remote %s' % self.serial.port,
-                       '-ex', 'interrupt',  # monitor has already parsed the first 'reason' command, need a second
                        self.elf_file]
-                process = subprocess.Popen(cmd, cwd='.')
-                process.wait()
+
+                # Here we handling GDB as a process
+                if True:
+                    # Open GDB process
+                    try:
+                        process = subprocess.Popen(cmd, cwd=".")
+                    except KeyboardInterrupt:
+                        pass
+
+                    # We ignore Ctrl+C interrupt form external process abd wait responce util GDB will be finished.
+                    while True:
+                        try:
+                            process.wait()
+                            break
+                        except KeyboardInterrupt:
+                            pass    # We ignore the Ctrl+C
+                    self.gdb_exit = True
+
             except OSError as e:
                 red_print('%s: %s' % (' '.join(cmd), e))
             except KeyboardInterrupt:
@@ -499,7 +551,6 @@ class Monitor(object):
                     subprocess.call(['stty', 'sane'])
                 except Exception:
                     pass  # don't care if there's no stty, we tried...
-            self.prompt_next_action('gdb exited')
 
     def output_enable(self, enable):  # type: (bool) -> None
         self._output_enabled = enable
@@ -733,6 +784,8 @@ def main():  # type: () -> None
             yellow_print('--- Print filter: {} ---'.format(args.print_filter))
 
         monitor.main_loop()
+    except KeyboardInterrupt:
+        pass
     finally:
         if ws:
             ws.close()

+ 21 - 3
tools/idf_monitor_base/serial_reader.py

@@ -38,6 +38,7 @@ class SerialReader(StoppableThread):
         self.baud = serial_instance.baudrate
         self.serial = serial_instance
         self.event_queue = event_queue
+        self.gdb_exit = False
         if not hasattr(self.serial, 'cancel_read'):
             # enable timeout for checking alive flag,
             # if cancel_read not available
@@ -47,10 +48,27 @@ class SerialReader(StoppableThread):
         #  type: () -> None
         if not self.serial.is_open:
             self.serial.baudrate = self.baud
-            self.serial.rts = True  # Force an RTS reset on open
+            # We can come to this thread at startup or from external application line GDB.
+            # If we come from GDB we would like to continue to run without reset.
+            if self.gdb_exit is False:
+                # This sequence of DTR/RTS and open/close set the serial port to
+                # condition when GDB not make reset of the target by switching DTR/RTS.
+                self.serial.rts = True  # IO0=LOW
+                self.serial.dtr = self.serial.dtr   # usbser.sys workaround
+                self.serial.open()
+                self.serial.close()
+                self.serial.rts = False     # IO0=HIGH
+                self.serial.dtr = False
+            else:                           # if we exit from GDB, we don't need to reset the target
+                self.serial.rts = False
+                self.serial.dtr = True
+
+            # Current state not reset the target!
+            self.gdb_exit = False
             self.serial.open()
-            self.serial.rts = False
-            self.serial.dtr = self.serial.dtr  # usbser.sys workaround
+            time.sleep(0.005)  # Add a delay to meet the requirements of minimal EN low time (2ms for ESP32-C3)
+            self.serial.rts = False             # Set rts/dtr to the working state
+            self.serial.dtr = self.serial.dtr   # usbser.sys workaround
         try:
             while self.alive:
                 try: