wasatch 2.3.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wasatch/AbstractUSBDevice.py +29 -0
- wasatch/AndorDevice.py +910 -0
- wasatch/AreaScanImage.py +19 -0
- wasatch/AutoRaman.py +457 -0
- wasatch/AutoRamanRequest.py +96 -0
- wasatch/BLEDevice.py +1032 -0
- wasatch/BalanceAcquisition.py +136 -0
- wasatch/CSVLoader.py +188 -0
- wasatch/CommandSettings.py +95 -0
- wasatch/ControlObject.py +17 -0
- wasatch/DetectorROI.py +36 -0
- wasatch/DetectorRegions.py +158 -0
- wasatch/DeviceFinderBLE.py +107 -0
- wasatch/DeviceFinderTCP.py +20 -0
- wasatch/DeviceFinderUSB.py +236 -0
- wasatch/DeviceID.py +344 -0
- wasatch/EEPROM.py +1450 -0
- wasatch/EEPROM_multical.sav +48 -0
- wasatch/FPGAOptions.py +125 -0
- wasatch/FeatureIdentificationDevice.py +3961 -0
- wasatch/FirmwareRequirements.py +76 -0
- wasatch/HardwareInfo.py +36 -0
- wasatch/IDSCamera.py +916 -0
- wasatch/IDSDevice.py +329 -0
- wasatch/IMX385.py +179 -0
- wasatch/InterfaceDevice.py +40 -0
- wasatch/MockUSBDevice.py +353 -0
- wasatch/OceanDevice.py +215 -0
- wasatch/PollStatus.py +15 -0
- wasatch/ProcessedReading.py +352 -0
- wasatch/ROI.py +33 -0
- wasatch/Reading.py +80 -0
- wasatch/RealUSBDevice.py +64 -0
- wasatch/SPIDevice.py +628 -0
- wasatch/SpectrometerRequest.py +15 -0
- wasatch/SpectrometerResponse.py +38 -0
- wasatch/SpectrometerSettings.py +446 -0
- wasatch/SpectrometerState.py +255 -0
- wasatch/StatusMessage.py +14 -0
- wasatch/TCPDevice.py +409 -0
- wasatch/TakeOneRequest.py +43 -0
- wasatch/WasatchBus.py +87 -0
- wasatch/WasatchDevice.py +1060 -0
- wasatch/WasatchDeviceWrapper.py +452 -0
- wasatch/WrapperWorker.py +304 -0
- wasatch/__init__.py +4 -0
- wasatch/applog.py +177 -0
- wasatch/simulation_protocol.py +227 -0
- wasatch/utils.py +731 -0
- wasatch-2.3.2.dist-info/LICENSE +21 -0
- wasatch-2.3.2.dist-info/METADATA +347 -0
- wasatch-2.3.2.dist-info/RECORD +53 -0
- wasatch-2.3.2.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import asyncio
|
|
3
|
+
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from bleak import BleakScanner
|
|
6
|
+
|
|
7
|
+
from wasatch.BLEDevice import BLEDevice
|
|
8
|
+
from wasatch.DeviceID import DeviceID
|
|
9
|
+
|
|
10
|
+
log = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
class DiscoveredBLEDevice:
|
|
13
|
+
def __init__(self, device_id, rssi):
|
|
14
|
+
self.device_id = device_id
|
|
15
|
+
self.rssi = rssi
|
|
16
|
+
|
|
17
|
+
class DeviceFinderBLE:
|
|
18
|
+
""" @see consolidated BLE docs in wasatch.BLEDevice """
|
|
19
|
+
|
|
20
|
+
def __init__(self, discovery_queue=None, discovery_callback=None, search_timeout_sec=30):
|
|
21
|
+
|
|
22
|
+
self.discovery_queue = discovery_queue
|
|
23
|
+
self.discovery_callback = discovery_callback
|
|
24
|
+
self.search_timeout_sec = search_timeout_sec
|
|
25
|
+
|
|
26
|
+
self.keep_scanning = True
|
|
27
|
+
self.stop_scanning_event = asyncio.Event()
|
|
28
|
+
|
|
29
|
+
async def search_for_devices(self):
|
|
30
|
+
log.debug("search_for_devices: start")
|
|
31
|
+
self.start_time = datetime.now()
|
|
32
|
+
|
|
33
|
+
# for some reason asyncio.timeout() isn't in my Python 3.10.15, so kludging
|
|
34
|
+
async def cancel_task(sec):
|
|
35
|
+
await asyncio.sleep(sec)
|
|
36
|
+
self.stop_scanning()
|
|
37
|
+
|
|
38
|
+
try:
|
|
39
|
+
log.debug(f"search_for_devices: scheduling cancel_task in {self.search_timeout_sec}sec")
|
|
40
|
+
task = asyncio.create_task(cancel_task(self.search_timeout_sec))
|
|
41
|
+
|
|
42
|
+
cb = self.detection_callback
|
|
43
|
+
uuid = BLEDevice.WASATCH_SERVICE
|
|
44
|
+
log.debug(f"search_for_devices: instantiating BleakScanner with callback {cb}, uuid {uuid}")
|
|
45
|
+
async with BleakScanner(detection_callback=self.detection_callback, service_uuids=[BLEDevice.WASATCH_SERVICE]) as scanner:
|
|
46
|
+
log.debug(f"search_for_devices: awaiting stop_scanning_event")
|
|
47
|
+
await self.stop_scanning_event.wait()
|
|
48
|
+
except:
|
|
49
|
+
log.error("exception while scanning for devices", exc_info=1)
|
|
50
|
+
|
|
51
|
+
# scanner stops when block exits
|
|
52
|
+
log.debug("search_for_devices: done")
|
|
53
|
+
|
|
54
|
+
def detection_callback(self, bleak_ble_device, advertisement_data):
|
|
55
|
+
log.debug("detection_callback: start")
|
|
56
|
+
if not self.keep_scanning:
|
|
57
|
+
log.debug("detection_callback: no longer scanning...done")
|
|
58
|
+
return
|
|
59
|
+
|
|
60
|
+
elapsed_sec = (datetime.now() - self.start_time).total_seconds()
|
|
61
|
+
if elapsed_sec >= self.search_timeout_sec:
|
|
62
|
+
log.debug(f"detection_callback: timeout expired ({elapsed_sec}sec > {self.search_timeout_sec})...done")
|
|
63
|
+
self.stop_scanning()
|
|
64
|
+
return
|
|
65
|
+
|
|
66
|
+
log.debug(f"detection_callback: discovered device {bleak_ble_device}, advertisement_data {advertisement_data}")
|
|
67
|
+
if not self.is_xs(bleak_ble_device):
|
|
68
|
+
log.debug(f"detection_callback: not XS...ignoring")
|
|
69
|
+
return
|
|
70
|
+
|
|
71
|
+
serial_number = advertisement_data.local_name
|
|
72
|
+
rssi = advertisement_data.rssi
|
|
73
|
+
device_id = DeviceID(label=f"BLE:{serial_number}", bleak_ble_device=bleak_ble_device)
|
|
74
|
+
|
|
75
|
+
discovered_device = DiscoveredBLEDevice(
|
|
76
|
+
device_id = device_id,
|
|
77
|
+
rssi = rssi)
|
|
78
|
+
log.debug(f"detection_callback: instantiated {discovered_device}")
|
|
79
|
+
|
|
80
|
+
if self.discovery_queue:
|
|
81
|
+
log.debug(f"detection_callback: returning DiscoveredBLEDevice via queue")
|
|
82
|
+
self.discovery_queue.put_nowait(discovered_device)
|
|
83
|
+
|
|
84
|
+
if self.discovery_callback:
|
|
85
|
+
log.debug(f"detection_callback: returning DiscoveredBLEDevice via callback")
|
|
86
|
+
self.discovery_callback(discovered_device)
|
|
87
|
+
|
|
88
|
+
if not (self.discovery_queue or self.discovery_callback):
|
|
89
|
+
log.error("have neither queue nor callback to return DeviceID...?")
|
|
90
|
+
|
|
91
|
+
log.debug("detection_callback: done")
|
|
92
|
+
|
|
93
|
+
def stop_scanning(self):
|
|
94
|
+
log.debug("stop_scanning")
|
|
95
|
+
self.keep_scanning = False
|
|
96
|
+
self.stop_scanning_event.set()
|
|
97
|
+
|
|
98
|
+
# send a "poison-pill" upstream to notify caller that we're no longer scanning
|
|
99
|
+
self.discovery_queue.put_nowait(None)
|
|
100
|
+
|
|
101
|
+
def is_xs(self, device, advertisement_data=None):
|
|
102
|
+
if device is None:
|
|
103
|
+
return
|
|
104
|
+
elif advertisement_data:
|
|
105
|
+
return BLEDevice.WASATCH_SERVICE.lower() in advertisement_data.service_uuids.lower()
|
|
106
|
+
else:
|
|
107
|
+
return "WP-" in device.name.upper()
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
log = logging.getLogger(__name__)
|
|
4
|
+
|
|
5
|
+
class DeviceFinderTCP:
|
|
6
|
+
"""
|
|
7
|
+
I started this class, but I'm not sure it's actually needed yet. Using
|
|
8
|
+
enlighten.Controller.other_device_ids for the moment.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
def find_tcp_devices(self):
|
|
15
|
+
device_ids = []
|
|
16
|
+
|
|
17
|
+
# for addr in self.addresses:
|
|
18
|
+
# ...
|
|
19
|
+
|
|
20
|
+
return device_ids
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import usb
|
|
3
|
+
import logging
|
|
4
|
+
import platform
|
|
5
|
+
from functools import partial
|
|
6
|
+
|
|
7
|
+
if platform.system() == "Darwin":
|
|
8
|
+
import usb.backend.libusb1 as backend
|
|
9
|
+
else:
|
|
10
|
+
import usb.backend.libusb0 as backend
|
|
11
|
+
|
|
12
|
+
log = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
from .DeviceID import DeviceID
|
|
15
|
+
|
|
16
|
+
class DeviceFinderUSB:
|
|
17
|
+
"""
|
|
18
|
+
Generates a list of DeviceID objects for all connected USB Wasatch Photonics
|
|
19
|
+
spectrometers.
|
|
20
|
+
|
|
21
|
+
Probably only works with libusb (which rules-out IDS cameras).
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
# VIDs
|
|
25
|
+
WASATCH_VID = 0x24aa
|
|
26
|
+
OCEAN_VID = 0x2457
|
|
27
|
+
ANDOR_VID = 0x136e
|
|
28
|
+
FT232_SPI_VID = 0x0403
|
|
29
|
+
|
|
30
|
+
VALID_VID_LIST = [ WASATCH_VID, OCEAN_VID, ANDOR_VID, FT232_SPI_VID ]
|
|
31
|
+
STR_VALID_VIDS = [ f"{vid:04x}" for vid in VALID_VID_LIST ]
|
|
32
|
+
|
|
33
|
+
# PIDs
|
|
34
|
+
WP_HAMA_SILICON_PID = 0x1000
|
|
35
|
+
WP_HAMA_INGAAS_PID = 0x2000
|
|
36
|
+
WP_ARM_PID = 0x4000
|
|
37
|
+
|
|
38
|
+
USE_MONITORING = True
|
|
39
|
+
MIN_POLLING_SCANS = 10
|
|
40
|
+
|
|
41
|
+
def __init__(self):
|
|
42
|
+
self.startup_scan = 0
|
|
43
|
+
if platform.system() == "Windows":
|
|
44
|
+
log.debug("configuring for Windows")
|
|
45
|
+
import win32com.client
|
|
46
|
+
|
|
47
|
+
# see https://docs.microsoft.com/en-us/windows/win32/wmisdk/creating-a-wmi-script
|
|
48
|
+
obj_WMI_service = win32com.client.GetObject("winmgmts:")
|
|
49
|
+
|
|
50
|
+
# see https://docs.microsoft.com/en-us/windows/win32/wmisdk/querying-with-wql
|
|
51
|
+
raw_wql = "SELECT * FROM __InstanceCreationEvent WITHIN 1 WHERE TargetInstance ISA \'Win32_PnPEntity\'"
|
|
52
|
+
|
|
53
|
+
# see https://docs.microsoft.com/en-us/windows/win32/wmisdk/monitoring-events
|
|
54
|
+
# while it removes polling the usb bus
|
|
55
|
+
# the polling now shifts to WMI events as the query is a polling operation
|
|
56
|
+
self.obj_events = obj_WMI_service.ExecNotificationQuery(raw_wql)
|
|
57
|
+
elif platform.system() == "Linux":
|
|
58
|
+
log.debug("configuring for Linux")
|
|
59
|
+
import pyudev
|
|
60
|
+
self.context = pyudev.Context()
|
|
61
|
+
self.monitor = pyudev.Monitor.from_netlink(self.context)
|
|
62
|
+
elif platform.system() == "Darwin":
|
|
63
|
+
log.debug("configuring for MacOS")
|
|
64
|
+
else:
|
|
65
|
+
pass
|
|
66
|
+
|
|
67
|
+
##
|
|
68
|
+
# Iterates over each supported PID, searching for any Wasatch devices
|
|
69
|
+
# with a known VID/PID and generating a list of DeviceIDs.
|
|
70
|
+
#
|
|
71
|
+
# Note that DeviceID internally pulls more attributes from the Device object.
|
|
72
|
+
# def find_usb_devices_alternate_unused(self):
|
|
73
|
+
# vid = 0x24aa
|
|
74
|
+
# device_ids = []
|
|
75
|
+
# count = 0
|
|
76
|
+
# for pid in [0x1000, 0x2000, 0x4000]:
|
|
77
|
+
# # we could also remove iProduct and do one find on vid
|
|
78
|
+
# devices = usb.core.find(find_all=True, idVendor=vid, idProduct=pid)
|
|
79
|
+
# for device in devices:
|
|
80
|
+
# count += 1
|
|
81
|
+
# log.debug("DeviceFinderUSB: discovered vid 0x%04x, pid 0x%04x (count %d)", vid, pid, count)
|
|
82
|
+
#
|
|
83
|
+
# device_id = DeviceID(device=device)
|
|
84
|
+
# device_ids.append(device_id)
|
|
85
|
+
# return device_ids
|
|
86
|
+
|
|
87
|
+
##
|
|
88
|
+
# Iterates over each USB bus, and each device on the bus, retaining any
|
|
89
|
+
# with a Wasatch Photonics VID and supported PID and instantiating a
|
|
90
|
+
# DeviceID for each.
|
|
91
|
+
#
|
|
92
|
+
# Note that DeviceID internally pulls more attributes from the Device object.
|
|
93
|
+
def bus_polling(self): # -> list[DeviceID]
|
|
94
|
+
device_ids = []
|
|
95
|
+
count = 0
|
|
96
|
+
devices = usb.core.find(find_all=True, backend=backend.get_backend())
|
|
97
|
+
for device in devices:
|
|
98
|
+
count += 1
|
|
99
|
+
vid = int(device.idVendor)
|
|
100
|
+
pid = int(device.idProduct)
|
|
101
|
+
log.debug("DeviceFinderUSB: discovered vid 0x%04x, pid 0x%04x (count %d), address %s", vid, pid, count, device.address)
|
|
102
|
+
|
|
103
|
+
if vid not in self.VALID_VID_LIST:
|
|
104
|
+
continue
|
|
105
|
+
|
|
106
|
+
if vid == self.WASATCH_VID and pid not in [ self.WP_HAMA_SILICON_PID, self.WP_HAMA_INGAAS_PID, self.WP_ARM_PID ]:
|
|
107
|
+
continue
|
|
108
|
+
|
|
109
|
+
device_id = DeviceID(device=device)
|
|
110
|
+
device_ids.append(device_id)
|
|
111
|
+
return device_ids
|
|
112
|
+
|
|
113
|
+
def linux_monitoring(self): # -> list[DeviceID]
|
|
114
|
+
device_ids = []
|
|
115
|
+
for device in iter(partial(self.monitor.poll, 0.001), None):
|
|
116
|
+
# sometimes I see events with None for the vendor id, those should be skipped
|
|
117
|
+
if device is not None and device.action == "add" and device.get('ID_VENDOR_ID') is not None:
|
|
118
|
+
device_ids.append(device)
|
|
119
|
+
log.debug(f"got a udev device add event")
|
|
120
|
+
valid_devices = [dev for dev in device_ids if dev.get('ID_VENDOR_ID').lower() in self.STR_VALID_VIDS]
|
|
121
|
+
pyusb_devices = [usb.core.find(idVendor=int(dev.get('ID_VENDOR_ID'), 16), idProduct=int(dev.get('ID_MODEL_ID'), 16)) for dev in valid_devices]
|
|
122
|
+
# if there is an error/can't find pyusb returns none
|
|
123
|
+
# filter those out
|
|
124
|
+
if None in pyusb_devices:
|
|
125
|
+
log.error(f"pyudev notified of a matching device, but error when doing pyusb query")
|
|
126
|
+
pyusb_devices = [dev for dev in pyusb_devices if dev is not None]
|
|
127
|
+
if pyusb_devices != []:
|
|
128
|
+
log.debug(f"pyudev returned devices of {pyusb_devices}")
|
|
129
|
+
return [DeviceID(device) for device in pyusb_devices]
|
|
130
|
+
|
|
131
|
+
# map across the STR_VALID_VIDS checking if it is in current id string, resulting in a bool array
|
|
132
|
+
# if any true in that bool array then any() is true and thus it will be in the list
|
|
133
|
+
def id_in_valid_vids(self, dev_id):
|
|
134
|
+
valid_vid_present = map(lambda valid: valid in dev_id, self.STR_VALID_VIDS)
|
|
135
|
+
return any(valid_vid_present)
|
|
136
|
+
|
|
137
|
+
def windows_monitoring(self): # -> list[DeviceID]
|
|
138
|
+
device_ids = []
|
|
139
|
+
try:
|
|
140
|
+
# the next event raises an error on timeout
|
|
141
|
+
# so if a connection has occured then add it to device ids
|
|
142
|
+
# when we stop seeing devices then pass on to the processing
|
|
143
|
+
while True:
|
|
144
|
+
obj_received = self.obj_events.NextEvent(0.001)
|
|
145
|
+
device_id = obj_received.Properties_("TargetInstance").Value.DeviceID
|
|
146
|
+
device_ids.append(device_id.lower())
|
|
147
|
+
except:
|
|
148
|
+
pass
|
|
149
|
+
if device_ids != []:
|
|
150
|
+
log.debug(f"found a WMI event of {device_ids}")
|
|
151
|
+
valid_vids = [dev_id for dev_id in device_ids if self.id_in_valid_vids(dev_id)]
|
|
152
|
+
pids = [re.findall(r'pid_(....)', dev) for dev in valid_vids]
|
|
153
|
+
pids = [id_num[0] for id_num in pids if id_num is not []]
|
|
154
|
+
vids = [re.findall(r'vid_(....)', dev) for dev in valid_vids]
|
|
155
|
+
vids = [id_num[0] for id_num in vids if id_num is not []]
|
|
156
|
+
# end by querying just the desired Wasatch Devices via pyusb
|
|
157
|
+
# this provides an easy meshing with our current setup using pyusb devices
|
|
158
|
+
pyusb_devices = [usb.core.find(idVendor=int(vid, 16), idProduct=int(pid, 16), backend=backend.get_backend()) for vid, pid in zip(vids, pids)]
|
|
159
|
+
# if there is an error/can't find pyusb returns none
|
|
160
|
+
# filter those out
|
|
161
|
+
if None in pyusb_devices:
|
|
162
|
+
log.error(f"WMI notified of a matching device, but error when doing pyusb query")
|
|
163
|
+
pyusb_devices = [dev for dev in pyusb_devices if dev is not None]
|
|
164
|
+
if pyusb_devices != []:
|
|
165
|
+
log.debug(f"WMI returned devices of {pyusb_devices}")
|
|
166
|
+
return [DeviceID(device) for device in pyusb_devices]
|
|
167
|
+
|
|
168
|
+
def find_usb_devices(self, poll = False):
|
|
169
|
+
# log.debug("DeviceFinderUSB.find_usb_devices: starting")
|
|
170
|
+
device_ids = []
|
|
171
|
+
|
|
172
|
+
# MZ/ED: If USE_MONITORING is True, I had to disable the call to remove_all in enlighten.Controller
|
|
173
|
+
if self.startup_scan < self.MIN_POLLING_SCANS or not self.USE_MONITORING or poll:
|
|
174
|
+
# our first few scans should always be a bus poll
|
|
175
|
+
# this is because no events will be registered
|
|
176
|
+
# log.debug(f"DeviceFinderUSB.find_usb_devices: just doing a bus poll for startup_scan {self.startup_scan}")
|
|
177
|
+
device_ids = self.bus_polling()
|
|
178
|
+
self.startup_scan += 1
|
|
179
|
+
elif platform.system() == "Windows":
|
|
180
|
+
device_ids = self.windows_monitoring()
|
|
181
|
+
elif platform.system() == "Linux":
|
|
182
|
+
device_ids = self.linux_monitoring()
|
|
183
|
+
else:
|
|
184
|
+
device_ids = self.bus_polling()
|
|
185
|
+
# log.debug(f"DeviceFinderUSB.find_usb_devices: returning {len(device_ids)} devices")
|
|
186
|
+
return device_ids
|
|
187
|
+
|
|
188
|
+
def mac_monitoring(self):
|
|
189
|
+
"""
|
|
190
|
+
The challenge of implementing Mac usb events was decided not to be worth it
|
|
191
|
+
since it is such a small porition of users. I've included my code below the not implemented error
|
|
192
|
+
for reference in case we decide to implement later. This is incomplete and shouldn't be called.
|
|
193
|
+
"""
|
|
194
|
+
raise NotImplementedError
|
|
195
|
+
|
|
196
|
+
from ctypes import cdll, util
|
|
197
|
+
|
|
198
|
+
#iokit = cdll.LoadLibrary(util.find_library('IOKit'))
|
|
199
|
+
|
|
200
|
+
# See ctypes for what these calls are doing
|
|
201
|
+
# For where iokit info is coming from
|
|
202
|
+
# Apple docs, which imo are bad with clear examples, if any,
|
|
203
|
+
# so I'm structuring this
|
|
204
|
+
# in a how to actually create and do way
|
|
205
|
+
# IO notifications in python using ctypes
|
|
206
|
+
# https://developer.apple.com/library/archive/documentation/DeviceDrivers/Conceptual/IOKitFundamentals/Introduction/Introduction.html
|
|
207
|
+
# AddMatchingNotification is our goal since that provides the iterator of devices
|
|
208
|
+
# https://developer.apple.com/documentation/iokit/1514362-ioserviceaddmatchingnotification?language=objc
|
|
209
|
+
# So our requirements are to create the following args
|
|
210
|
+
# IONotificationPortRef, io_name_t, CFDictionaryRef, IOServiceMatchingCallback, io_iterator_t
|
|
211
|
+
|
|
212
|
+
# For the IONotificationPortRef we call IONotificationPortCreate, which requires a mach_port_t
|
|
213
|
+
# the primary port comes from a constant used in the dylib
|
|
214
|
+
# https://developer.apple.com/documentation/iokit/1514480-ionotificationportcreate?language=objc
|
|
215
|
+
kIOMasterPortDefault = c_void_p.in_dll(iokit, 'kIOMasterPortDefault')
|
|
216
|
+
_ = iokit.IONotificationPortCreate(kIOMasterPortDefault)
|
|
217
|
+
|
|
218
|
+
# For the io_name_t that comes from a constant in the dll
|
|
219
|
+
# See the parameter description in the AddMatchinServiceNotification link at the top
|
|
220
|
+
# We want publish because it means whenever a connection occurs
|
|
221
|
+
_ = c_int.in_dll(iokit, 'kIOPublishNotification') # this throws an error that it doesn't have this symbol, idk why. It should export that
|
|
222
|
+
|
|
223
|
+
# CFDictionary creation call info, along with args to pass, can be found here
|
|
224
|
+
# https://developer.apple.com/documentation/corefoundation/1516791-cfdictionarycreatemutable?language=objc
|
|
225
|
+
# the pyobjc docs weren't helpful and just say this call exists but not how to call it
|
|
226
|
+
# we choose mutable when it could just be CFDictionaryCreate because it's easier to work with
|
|
227
|
+
# after creation this can be interacted with like a python dict
|
|
228
|
+
# the nonmutable requires passing c arrays for keys, values, which why bother when we can use python syntax
|
|
229
|
+
# expected keys example can be seen in xml doc in
|
|
230
|
+
# Figure 4-2 I found more helpful since it is for USB
|
|
231
|
+
# https://developer.apple.com/library/archive/documentation/DeviceDrivers/Conceptual/IOKitFundamentals/Matching/Matching.html
|
|
232
|
+
# XML docs say every dict requires IOProviderClass
|
|
233
|
+
# The value for the key can be found in the appendix of the driver docs
|
|
234
|
+
matching_dict = CFDictionaryCreateMutable(None, 0, kCFTypeDictionaryKeyCallBacks, kCFTypeDictionaryValueCallBacks)
|
|
235
|
+
matching_dict["IOProviderClass"] = "IOUSBDevice"
|
|
236
|
+
matching_dict["idVendor"] = 0x24aa # we can have the driver pre filter for wasatch, so I'm utilizing that
|