|
6 | 6 | import sys
|
7 | 7 | import os
|
8 | 8 | import os.path
|
| 9 | +import re |
9 | 10 | import time
|
10 | 11 | import traceback
|
11 | 12 | import shutil
|
@@ -500,11 +501,125 @@ class USBLauterbachDebuggerExport(USBGenericExport):
|
500 | 501 |
|
501 | 502 | def __attrs_post_init__(self):
|
502 | 503 | super().__attrs_post_init__()
|
| 504 | + self.stat = None |
| 505 | + self.port = None |
| 506 | + self.socket = None |
| 507 | + self.child = None |
| 508 | + self.machine = get_uname_machine() |
| 509 | + |
| 510 | + import random |
| 511 | + for port in random.sample(range(8455,8555),100): |
| 512 | + s = self._block_port(port) |
| 513 | + if s is not None: |
| 514 | + self.port = port |
| 515 | + self.socket = s |
| 516 | + break |
| 517 | + |
| 518 | + def _block_port(self, port): |
| 519 | + from socket import socket, AF_INET, SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR |
| 520 | + s = None |
| 521 | + try: |
| 522 | + s = socket(AF_INET, SOCK_STREAM) |
| 523 | + except OSError: |
| 524 | + s = None |
| 525 | + if s is not None: |
| 526 | + try: |
| 527 | + s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) |
| 528 | + s.bind(('', port)) |
| 529 | + s.listen() |
| 530 | + except: |
| 531 | + s.close() |
| 532 | + s = None |
| 533 | + self.logger.debug("block port %d", port) |
| 534 | + return s |
| 535 | + |
| 536 | + def _get_t32tcpusb_version(self, path): |
| 537 | + """Get version of `t32tcpusb`""" |
| 538 | + version = 0x0 |
| 539 | + # convert 'Sw.Version: N.<year>.<month>.<revision>' to 0x<year><month> |
| 540 | + output = subprocess.check_output([path, '-h']).decode('utf-8') |
| 541 | + versionmatch = re.search(r"Version:\s[NSRP]\.(\d{4})\.(\d{2})\.\d+", str(output)) |
| 542 | + |
| 543 | + if versionmatch is not None: |
| 544 | + version = int(f'0x{versionmatch[1]}{versionmatch[2]}', 16) |
| 545 | + |
| 546 | + return version |
| 547 | + |
| 548 | + def _get_start_params(self): |
| 549 | + assert not self.broken |
| 550 | + self.stat = None |
| 551 | + symlink = f"/var/cache/labgrid/t32tcpusb-{self.local.path}" |
| 552 | + try: |
| 553 | + if os.path.exists(symlink): |
| 554 | + stat = os.stat(symlink) |
| 555 | + self.stat = (stat.st_ino, stat.st_size, stat.st_mtime) |
| 556 | + except Exception as e: |
| 557 | + self.logger.debug(e) |
| 558 | + self.broken = f"cannot access {symlink}" |
| 559 | + self.stat = None |
| 560 | + if self.stat is None: |
| 561 | + return None |
| 562 | + return { |
| 563 | + 'stat': self.stat, |
| 564 | + 'symlink': symlink, |
| 565 | + 'busnum': self.local.busnum, |
| 566 | + 'devnum': self.local.devnum |
| 567 | + } |
| 568 | + |
| 569 | + def _start(self, start_params): |
| 570 | + """Start ``t32tcpusb`` subprocess""" |
| 571 | + assert self.local.avail |
| 572 | + assert self.child is None |
| 573 | + |
| 574 | + # t32tcpusb available yet? |
| 575 | + if start_params is None: |
| 576 | + #self.logger.info("skip start of t32tcpusb (Reason: link %s-<path> not found)", self.t32tcpusb_basename) |
| 577 | + return |
| 578 | + |
| 579 | + tcpusbVersion = self._get_t32tcpusb_version(start_params['symlink']) |
| 580 | + |
| 581 | + cmd = [start_params['symlink'],] |
| 582 | + if tcpusbVersion >= 0x202212: |
| 583 | + cmd += [ |
| 584 | + '--device', |
| 585 | + f'{start_params["busnum"]:03}:{start_params["devnum"]:03}' |
| 586 | + ] |
| 587 | + cmd += [f'{self.port}'] |
| 588 | + self.logger.info("starting t32tcpusb with: %s", " ".join(cmd)) |
| 589 | + self.socket.close() |
| 590 | + self.child = subprocess.Popen(cmd) |
| 591 | + try: |
| 592 | + self.child.wait(timeout=0.5) |
| 593 | + raise ExporterError("t32tcpusb exited immediately") |
| 594 | + except subprocess.TimeoutExpired: |
| 595 | + # good, t32tcpusb didn't exit immediately |
| 596 | + pass |
| 597 | + self.logger.info("started t32tcpusb for bus %03d device %03d on port %d", start_params['busnum'], start_params['devnum'], self.port) |
| 598 | + |
| 599 | + def _stop(self, start_params): |
| 600 | + """Stop ``t32tcpusb`` subprocess""" |
| 601 | + if start_params is None: |
| 602 | + return |
| 603 | + |
| 604 | + assert self.child |
| 605 | + child = self.child |
| 606 | + self.child = None |
| 607 | + child.terminate() |
| 608 | + try: |
| 609 | + child.wait(2.0) # t32tcpusb takes about a second to react |
| 610 | + except subprocess.TimeoutExpired: |
| 611 | + self.logger.warning("t32tcpusb still running after SIGTERM") |
| 612 | + log_subprocess_kernel_stack(self.logger, child) |
| 613 | + child.kill() |
| 614 | + child.wait(1.0) |
| 615 | + self.logger.info("stopped t32tcpusb for bus %03d device %03d on port %d", start_params['busnum'], start_params['devnum'], self.port) |
| 616 | + self._block_port(self.port) |
503 | 617 |
|
504 | 618 | def _get_params(self):
|
505 | 619 | """Helper function to return parameters"""
|
506 | 620 | p = super()._get_params()
|
507 | 621 | p['architecture'] = get_uname_machine()
|
| 622 | + p['port'] = self.port |
508 | 623 | return p
|
509 | 624 |
|
510 | 625 | @attr.s(eq=False)
|
|
0 commit comments