Repository: apache/tvm

Issue:
[microTVM][zephyr] Add support for nRF5340 DK v2
There are two versions of the nRF5340 development kit, 1.0.0 and 2.0.0. The 1.0.0 DK exposes three COM ports, where COM2 is used to communicate with the device while running tests. The 2.0.0 DK only has two COM ports as can be seen here:
```
$ nrfjprog --com
1050063518    /dev/ttyACM0    VCOM0
1050063518    /dev/ttyACM1    VCOM1
```
[microtvm_api_server.py always uses VCOM2](https://github.com/apache/tvm/blob/3b2780a4141b5654439c43dfc7c1409f9cb1858c/apps/microtvm/zephyr/template_project/microtvm_api_server.py#L628) which doesn't exist on the 2.0.0 DK.

To accommodate this, the USB product ID (PID) can be used to differentiate between the 1.0.0 and 2.0.0 DKs. The PID for 1.0.0 is 1055, while the PID for the 2.0.0 DK is reported as 1051 via lsusb:
```
$ lsusb
Bus 005 Device 006: ID 1366:1051 SEGGER J-Link
```

Here are more details from Nordic Semiconductor's site:

[nRF5340 DK v2.0.0 COM ports](https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/ug_nrf5340.html#nrf5340-dk-v2-0-0-com-ports)
When connected to a computer, the nRF5340 DK v2.0.0 emulates two virtual COM ports. In the default configuration, they are set up as follows:
- The first COM port outputs the log from the network core (if available).
- The second COM port outputs the log from the application core.

[nRF5340 DK v1.0.0 COM ports](https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/ug_nrf5340.html#nrf5340-dk-v1-0-0-com-ports)
When connected to a computer, the nRF5340 DK v1.0.0 emulates three virtual COM ports. In the default configuration, they are set up as follows:
- The first COM port outputs the log from the network core (if available).
- The second (middle) COM port is routed to the P24 connector of the nRF5340 DK.
- The third (last) COM port outputs the log from the application core.

### Expected behavior
Tests pass while successfully connection to device via VCOM2

### Actual behavior
Tests fail due to inability to connect to device as VCOM2 does not exits.

### Environment
Linux Ubuntu 20.04 with nRF5340 v2.0.0 development kit

### Steps to reproduce
`pytest test_zephyr.py --zephyr-board=nrf5340dk_nrf5340_cpuapp`

cc: @areusch @mehrdadh 


Discussion:

Resolving patch:
diff --git a/apps/microtvm/zephyr/template_project/microtvm_api_server.py b/apps/microtvm/zephyr/template_project/microtvm_api_server.py
--- a/apps/microtvm/zephyr/template_project/microtvm_api_server.py
+++ b/apps/microtvm/zephyr/template_project/microtvm_api_server.py
@@ -20,6 +20,7 @@
 import collections.abc
 import enum
 import fcntl
+import json
 import logging
 import os
 import os.path
@@ -35,7 +36,7 @@
 import tempfile
 import threading
 import time
-import json
+import usb
 
 import serial
 import serial.tools.list_ports
@@ -179,8 +180,6 @@ def openocd_serial(options):
     if "openocd_serial" in options:
         return options["openocd_serial"]
 
-    import usb  # pylint: disable=import-outside-toplevel
-
     find_kw = BOARD_USB_FIND_KW[CMAKE_CACHE["BOARD"]]
     boards = usb.core.find(find_all=True, **find_kw)
     serials = []
@@ -588,6 +587,13 @@ def _set_nonblock(fd):
 
 
 class ZephyrSerialTransport:
+
+    NRF5340_VENDOR_ID = 0x1366
+
+    # NRF5340_DK v1.0.0 uses VCOM2
+    # NRF5340_DK v2.0.0 uses VCOM1
+    NRF5340_DK_BOARD_VCOM_BY_PRODUCT_ID = {0x1055: "VCOM2", 0x1051: "VCOM1"}
+
     @classmethod
     def _lookup_baud_rate(cls, options):
         # TODO(mehrdadh): remove this hack once dtlib.py is a standalone project
@@ -625,7 +631,17 @@ def _find_nrf_serial_port(cls, options):
             parts = line.split()
             ports_by_vcom[parts[2]] = parts[1]
 
-        return ports_by_vcom["VCOM2"]
+        nrf_board = usb.core.find(idVendor=cls.NRF5340_VENDOR_ID)
+
+        if nrf_board == None:
+            raise Exception("_find_nrf_serial_port: unable to find NRF5340DK")
+
+        if nrf_board.idProduct in cls.NRF5340_DK_BOARD_VCOM_BY_PRODUCT_ID:
+            vcom_port = cls.NRF5340_DK_BOARD_VCOM_BY_PRODUCT_ID[nrf_board.idProduct]
+        else:
+            raise Exception("_find_nrf_serial_port: unable to find known NRF5340DK product ID")
+
+        return ports_by_vcom[vcom_port]
 
     @classmethod
     def _find_openocd_serial_port(cls, options):


Test patch: