File: hid.pyx

package info (click to toggle)
python-hidapi 0.7.99.post21-1
  • links: PTS
  • area: main
  • in suites: buster
  • size: 304 kB
  • sloc: ansic: 3,069; python: 156; makefile: 7
file content (196 lines) | stat: -rw-r--r-- 6,230 bytes parent folder | download | duplicates (2)
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
import sys
from chid cimport *
from libc.stddef cimport wchar_t, size_t
from cpython.unicode cimport PyUnicode_FromUnicode

cdef extern from "ctype.h":
  int wcslen(wchar_t*)

cdef extern from "stdlib.h":
  void free(void* ptr)
  void* malloc(size_t size)

cdef extern from *:
  object PyUnicode_FromWideChar(const wchar_t *w, Py_ssize_t size)
  Py_ssize_t PyUnicode_AsWideChar(object unicode, wchar_t *w, Py_ssize_t size)

cdef object U(wchar_t *wcs):
  if wcs == NULL:
    return ''
  cdef int n = wcslen(wcs)
  return PyUnicode_FromWideChar(wcs, n)

def enumerate(int vendor_id=0, int product_id=0):
  cdef hid_device_info* info = hid_enumerate(vendor_id, product_id)
  cdef hid_device_info* c = info
  res = []
  while c:
    res.append({
      'path': c.path,
      'vendor_id': c.vendor_id,
      'product_id': c.product_id,
      'serial_number': U(c.serial_number),
      'release_number': c.release_number,
      'manufacturer_string': U(c.manufacturer_string),
      'product_string': U(c.product_string),
      'usage_page': c.usage_page,
      'usage': c.usage,
      'interface_number': c.interface_number,
    })
    c = c.next
  hid_free_enumeration(info)
  return res

cdef class device:
  cdef hid_device *_c_hid

  def open(self, int vendor_id=0, int product_id=0, unicode serial_number=None):
      cdef wchar_t * cserial_number = NULL
      cdef int serial_len
      cdef Py_ssize_t result
      try:
        if serial_number is not None:
          serial_len = len(serial_number)
          cserial_number = <wchar_t*>malloc(sizeof(wchar_t) * (serial_len+1))
          if cserial_number == NULL:
              raise MemoryError()
          result = PyUnicode_AsWideChar(serial_number, cserial_number, serial_len)
          if result == -1:
              raise ValueError("invalid serial number string")
          cserial_number[serial_len] = 0  # Must explicitly null-terminate
        self._c_hid = hid_open(vendor_id, product_id, cserial_number)
      finally:
          if cserial_number != NULL:
            free(cserial_number)
      if self._c_hid == NULL:
          raise IOError('open failed')

  def open_path(self, bytes path):
      cdef char* cbuff = path
      self._c_hid = hid_open_path(cbuff)
      if self._c_hid == NULL:
          raise IOError('open failed')

  def close(self):
      if self._c_hid != NULL:
          hid_close(self._c_hid)
          self._c_hid = NULL

  def write(self, buff):
      '''Accept a list of integers (0-255) and send them to the device'''
      if self._c_hid == NULL:
          raise ValueError('not open')
      # convert to bytes
      if sys.version_info < (3, 0):
          buff = ''.join(map(chr, buff))
      else:
          buff = bytes(buff)
      cdef hid_device * c_hid = self._c_hid
      cdef unsigned char* cbuff = buff # covert to c string
      cdef size_t c_buff_len = len(buff)
      cdef int result
      with nogil:
        result = hid_write(c_hid, cbuff, c_buff_len)
      return result

  def set_nonblocking(self, int v):
      '''Set the nonblocking flag'''
      if self._c_hid == NULL:
          raise ValueError('not open')
      return hid_set_nonblocking(self._c_hid, v)

  def read(self, int max_length, int timeout_ms=0):
      '''Return a list of integers (0-255) from the device up to max_length bytes.'''
      if self._c_hid == NULL:
          raise ValueError('not open')
      cdef unsigned char lbuff[16]
      cdef unsigned char* cbuff
      cdef size_t c_max_length = max_length
      cdef int c_timeout_ms = timeout_ms
      cdef hid_device * c_hid = self._c_hid
      if max_length <= 16:
          cbuff = lbuff
      else:
          cbuff = <unsigned char *>malloc(max_length)
      if timeout_ms > 0:
        with nogil:
            n = hid_read_timeout(c_hid, cbuff, c_max_length, c_timeout_ms)
      else:
        with nogil:
            n = hid_read(c_hid, cbuff, c_max_length)
      if n is -1:
          raise IOError('read error')
      res = []
      for i in range(n):
          res.append(cbuff[i])
      if max_length > 16:
          free(cbuff)
      return res

  def get_manufacturer_string(self):
      if self._c_hid == NULL:
          raise ValueError('not open')
      cdef wchar_t buff[255]
      cdef int r = hid_get_manufacturer_string(self._c_hid, buff, 255)
      if not r:
          return U(buff)

  def get_product_string(self):
      if self._c_hid == NULL:
          raise ValueError('not open')
      cdef wchar_t buff[255]
      cdef int r = hid_get_product_string(self._c_hid, buff, 255)
      if not r:
          return U(buff)

  def get_serial_number_string(self):
      if self._c_hid == NULL:
          raise ValueError('not open')
      cdef wchar_t buff[255]
      cdef int r = hid_get_serial_number_string(self._c_hid, buff, 255)
      if not r:
          return U(buff)

  def send_feature_report(self, buff):
      if self._c_hid == NULL:
          raise ValueError('not open')
      '''Accept a list of integers (0-255) and send them to the device'''
      # convert to bytes
      if sys.version_info < (3, 0):
          buff = ''.join(map(chr, buff))
      else:
          buff = bytes(buff)
      cdef hid_device * c_hid = self._c_hid
      cdef unsigned char* cbuff = buff # covert to c string
      cdef size_t c_buff_len = len(buff)
      cdef int result
      with nogil:
        result = hid_send_feature_report(c_hid, cbuff, c_buff_len)
      return result

  def get_feature_report(self, int report_num, int max_length):
      if self._c_hid == NULL:
          raise ValueError('not open')
      cdef hid_device * c_hid = self._c_hid
      cdef unsigned char lbuff[16]
      cdef unsigned char* cbuff
      cdef size_t c_max_length = max_length
      cdef int n
      if max_length <= 16:
          cbuff = lbuff
      else:
          cbuff = <unsigned char *>malloc(max_length)
      cbuff[0] = report_num
      with nogil:
        n = hid_get_feature_report(c_hid, cbuff, c_max_length)
      res = []
      for i in range(n):
          res.append(cbuff[i])
      if max_length > 16:
          free(cbuff)
      return res

  def error(self):
      if self._c_hid == NULL:
          raise ValueError('not open')
      return U(<wchar_t*>hid_error(self._c_hid))