summaryrefslogtreecommitdiff
path: root/extra/tigertool/ecusb/stm32usb.py
blob: f9c700466acd769de4c239ad654f417e0b5f7a3c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# Copyright 2017 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Allows creation of an interface via stm32 usb."""

import usb  # pylint:disable=import-error


class SusbError(Exception):
    """Class for exceptions of Susb."""

    def __init__(self, msg, value=0):
        """SusbError constructor.

        Args:
          msg: string, message describing error in detail
          value: integer, value of error when non-zero status returned.  Default=0
        """
        super(SusbError, self).__init__(msg, value)
        self.msg = msg
        self.value = value


class Susb(object):
    """Provide stm32 USB functionality.

    Instance Variables:
      _read_ep: pyUSB read endpoint for this interface
      _write_ep: pyUSB write endpoint for this interface
    """

    READ_ENDPOINT = 0x81
    WRITE_ENDPOINT = 0x1
    TIMEOUT_MS = 100

    def __init__(
        self,
        vendor=0x18D1,
        product=0x5027,
        interface=1,
        serialname=None,
        logger=None,
    ):
        """Susb constructor.

        Discovers and connects to stm32 USB endpoints.

        Args:
          vendor: usb vendor id of stm32 device.
          product: usb product id of stm32 device.
          interface: interface number ( 1 - 4 ) of stm32 device to use.
          serialname: string of device serialname.
          logger: none

        Raises:
          SusbError: An error accessing Susb object
        """
        self._vendor = vendor
        self._product = product
        self._interface = interface
        self._serialname = serialname
        self._find_device()

    def _find_device(self):
        """Set up the usb endpoint"""
        # Find the stm32.
        dev_g = usb.core.find(
            idVendor=self._vendor, idProduct=self._product, find_all=True
        )
        dev_list = list(dev_g)

        if not dev_list:
            raise SusbError("USB device not found")

        # Check if we have multiple stm32s and we've specified the serial.
        dev = None
        if self._serialname:
            for d in dev_list:
                dev_serial = usb.util.get_string(d, d.iSerialNumber)
                if dev_serial == self._serialname:
                    dev = d
                    break
            if dev is None:
                raise SusbError("USB device(%s) not found" % self._serialname)
        else:
            try:
                dev = dev_list[0]
            except StopIteration:
                raise SusbError(
                    "USB device %04x:%04x not found"
                    % (self._vendor, self._product)
                )

        # If we can't set configuration, it's already been set.
        try:
            dev.set_configuration()
        except usb.core.USBError:
            pass

        self._dev = dev

        # Get an endpoint instance.
        cfg = dev.get_active_configuration()
        intf = usb.util.find_descriptor(cfg, bInterfaceNumber=self._interface)
        self._intf = intf
        if not intf:
            raise SusbError(
                "Interface %04x:%04x - 0x%x not found"
                % (self._vendor, self._product, self._interface)
            )

        # Detach raiden.ko if it is loaded. CCD endpoints support either a kernel
        # module driver that produces a ttyUSB, or direct endpoint access, but
        # can't do both at the same time.
        if dev.is_kernel_driver_active(intf.bInterfaceNumber) is True:
            dev.detach_kernel_driver(intf.bInterfaceNumber)

        read_ep_number = intf.bInterfaceNumber + self.READ_ENDPOINT
        read_ep = usb.util.find_descriptor(
            intf, bEndpointAddress=read_ep_number
        )
        self._read_ep = read_ep

        write_ep_number = intf.bInterfaceNumber + self.WRITE_ENDPOINT
        write_ep = usb.util.find_descriptor(
            intf, bEndpointAddress=write_ep_number
        )
        self._write_ep = write_ep

    def close(self):
        usb.util.dispose_resources(self._dev)