IDFDUT.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. # Copyright 2015-2017 Espressif Systems (Shanghai) PTE 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. """ DUT for IDF applications """
  15. import os
  16. import re
  17. import subprocess
  18. import functools
  19. import DUT
  20. class IDFToolError(OSError):
  21. pass
  22. def _tool_method(func):
  23. """ close port, execute tool method and then reopen port """
  24. @functools.wraps(func)
  25. def handler(self, *args, **kwargs):
  26. self.close()
  27. ret = func(self, *args, **kwargs)
  28. self.open()
  29. return ret
  30. return handler
  31. class IDFDUT(DUT.SerialDUT):
  32. """ IDF DUT, extends serial with ESPTool methods """
  33. CHIP_TYPE_PATTERN = re.compile(r"Detecting chip type[.:\s]+(.+)")
  34. def __init__(self, name, port, log_file, app, **kwargs):
  35. self.download_config, self.partition_table = app.process_app_info()
  36. super(IDFDUT, self).__init__(name, port, log_file, app, **kwargs)
  37. @classmethod
  38. def get_chip(cls, app, port):
  39. """
  40. get chip id via esptool
  41. :param app: application instance (to get tool)
  42. :param port: comport
  43. :return: chip ID or None
  44. """
  45. try:
  46. output = subprocess.check_output(["python", app.esptool, "--port", port, "chip_id"])
  47. except subprocess.CalledProcessError:
  48. output = bytes()
  49. if isinstance(output, bytes):
  50. output = output.decode()
  51. chip_type = cls.CHIP_TYPE_PATTERN.search(output)
  52. return chip_type.group(1) if chip_type else None
  53. @classmethod
  54. def confirm_dut(cls, port, app, **kwargs):
  55. return cls.get_chip(app, port) is not None
  56. @_tool_method
  57. def start_app(self):
  58. """
  59. download and start app.
  60. :return: None
  61. """
  62. retry_baud_rates = ["921600", "115200"]
  63. error = IDFToolError()
  64. for baud_rate in retry_baud_rates:
  65. try:
  66. subprocess.check_output(["python", self.app.esptool,
  67. "--port", self.port, "--baud", baud_rate]
  68. + self.download_config)
  69. break
  70. except subprocess.CalledProcessError as error:
  71. continue
  72. else:
  73. raise error
  74. @_tool_method
  75. def reset(self):
  76. """
  77. reset DUT with esptool
  78. :return: None
  79. """
  80. subprocess.check_output(["python", self.app.esptool, "--port", self.port, "run"])
  81. @_tool_method
  82. def dump_flush(self, output_file, **kwargs):
  83. """
  84. dump flush
  85. :param output_file: output file name, if relative path, will use sdk path as base path.
  86. :keyword partition: partition name, dump the partition.
  87. ``partition`` is preferred than using ``address`` and ``size``.
  88. :keyword address: dump from address (need to be used with size)
  89. :keyword size: dump size (need to be used with address)
  90. :return: None
  91. """
  92. if os.path.isabs(output_file) is False:
  93. output_file = os.path.relpath(output_file, self.app.get_log_folder())
  94. if "partition" in kwargs:
  95. partition = self.partition_table[kwargs["partition"]]
  96. _address = partition["offset"]
  97. _size = partition["size"]
  98. elif "address" in kwargs and "size" in kwargs:
  99. _address = kwargs["address"]
  100. _size = kwargs["size"]
  101. else:
  102. raise IDFToolError("You must specify 'partition' or ('address' and 'size') to dump flash")
  103. subprocess.check_output(
  104. ["python", self.app.esptool, "--port", self.port, "--baud", "921600",
  105. "--before", "default_reset", "--after", "hard_reset", "read_flash",
  106. _address, _size, output_file]
  107. )