Skip to content

Commit

Permalink
Update Ultrastik code with requested changes.
Browse files Browse the repository at this point in the history
  • Loading branch information
robabram committed Feb 13, 2024
1 parent ea7802e commit de15e72
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 27 deletions.
8 changes: 1 addition & 7 deletions ultimarc/devices/_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,6 @@ class USBRequestCode(IntEnum):
SET_INTERFACE = 0x0B # Select an alternate interface for the specified interface
SYNCH_FRAME = 0x0C # Set then report an endpoint's synchronization frame
REQUEST_SET_SEL = 0x30 # Sets both the U1 and U2 Exit Latency
SET_ISOCH_DELAY = 0x31 # Delay from the time a host transmits a packet to the time it is received by the device.

# Pre-2015 UltraStik controller ID change Codes
ULTRASTIK_E9 = 0xE9
ULTRASTIK_EA = 0xEA
ULTRASTIK_EB = 0xEB


class USBRequestDirection(IntEnum):
Expand Down Expand Up @@ -215,7 +209,7 @@ def _make_control_transfer(self, request_type, b_request, w_value, w_index, data
"""
if self.interface is None:
raise USBDeviceInterfaceNotClaimedError(self.dev_key)
if not isinstance(b_request, USBRequestCode):
if not isinstance(b_request, (USBRequestCode, IntEnum)):
raise ValueError('b_request argument must be USBRequestCode enum value.')

ret = usb.control_transfer(
Expand Down
48 changes: 29 additions & 19 deletions ultimarc/devices/ultrastik.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#
import ctypes as ct
import logging
from enum import IntEnum

from python_easy_json import JSONObject

Expand All @@ -15,8 +16,7 @@

USTIK_RESOURCE_TYPES = ['ultrastik-controller-id', 'ultrastik-config']

USTIK_DATA_SIZE = 96
USTIK_CONFIG_BASE = 0x51
USTIK_ID_CONFIG_BASE = 0x51

# UltraStik pre 2015 defines
USTIK_PRE_INTERFACE = 0
Expand All @@ -27,6 +27,18 @@
USTIK_PRE_REQUEST_3 = 0xEA
USTIK_PRE_MESG_LENGTH = 32


class USBRequestCodePre2015(IntEnum):
""" Support pre-2015 Ultrastik USB devices """
# Pre-2015 UltraStik controller ID change Codes
SET_ISOCH_DELAY = 0x31 # Delay from the time a host transmits a packet to the time it is received by the device.
ULTRASTIK_E9 = 0xE9
ULTRASTIK_EA = 0xEA
ULTRASTIK_EB = 0xEB

USTIK_DATA_SIZE = 96


# UltraStik 2015 and newer defines
USTIK_INTERFACE = 2
USTIK_MESG_LENGTH = 4
Expand Down Expand Up @@ -62,22 +74,22 @@ def set_controller_id(self, new_controller_id: int) -> bool:
:return: True if successful, otherwise false.
"""
# Calculate new device ID.
new_id = USTIK_CONFIG_BASE + (new_controller_id - 1)
new_id = USTIK_ID_CONFIG_BASE + (new_controller_id - 1)
# Setup an array with zero for all byte values.
data = (ct.c_ubyte * USTIK_PRE_MESG_LENGTH)(0)
data[0] = new_id

resp_1 = self.write_raw(USBRequestCode.ULTRASTIK_E9, 0x1, USTIK_PRE_INTERFACE, ct.c_void_p(), 0x0,
resp_1 = self.write_raw(USBRequestCodePre2015.ULTRASTIK_E9, 0x1, USTIK_PRE_INTERFACE, ct.c_void_p(), 0x0,
request_type=USBRequestType.REQUEST_TYPE_VENDOR,
recipient=USBRequestRecipient.RECIPIENT_OTHER)
# We need to write 32 bytes here.
resp_2 = self.write(USBRequestCode.ULTRASTIK_EB, 0x0, USTIK_PRE_INTERFACE, data, USTIK_PRE_MESG_LENGTH,
resp_2 = self.write(USBRequestCodePre2015.ULTRASTIK_EB, 0x0, USTIK_PRE_INTERFACE, data, USTIK_PRE_MESG_LENGTH,
request_type=USBRequestType.REQUEST_TYPE_VENDOR,
recipient=USBRequestRecipient.RECIPIENT_OTHER)
resp_3 = self.read(USBRequestCode.ULTRASTIK_EA, 0x0, USTIK_PRE_INTERFACE, ct.c_void_p(), 0x0,
resp_3 = self.read(USBRequestCodePre2015.ULTRASTIK_EA, 0x0, USTIK_PRE_INTERFACE, ct.c_void_p(), 0x0,
request_type=USBRequestType.REQUEST_TYPE_VENDOR,
recipient=USBRequestRecipient.RECIPIENT_OTHER)
resp_4 = self.write(USBRequestCode.ULTRASTIK_E9, 0x0, USTIK_PRE_INTERFACE, ct.c_void_p(), 0x0,
resp_4 = self.write(USBRequestCodePre2015.ULTRASTIK_E9, 0x0, USTIK_PRE_INTERFACE, ct.c_void_p(), 0x0,
request_type=USBRequestType.REQUEST_TYPE_VENDOR,
recipient=USBRequestRecipient.RECIPIENT_OTHER)

Expand All @@ -89,8 +101,8 @@ def set_config(self, config_file: str) -> bool:
config = JSONObject(self.validate_config_base(config_file, USTIK_RESOURCE_TYPES))

data = UltraStikStruct()
data.keepAnalog = 0x11 if config.keepAnalog else 0x11
data.mapSize = config.mapSize
data.keepAnalog = 0x11 if config.keepAnalog else 0x50 # Keep Analog: true on(0x11) else false off(0x50)
data.mapSize = 9
data.restrictor = 0x09 if config.restrictor else 0x10
data.borders = (ct.c_uint8 * 8)(*config.borders)
data.map = (ct.c_uint8 * 81)(*[DIRECTION_MAP[v] for v in config.map])
Expand All @@ -100,26 +112,26 @@ def set_config(self, config_file: str) -> bool:
resp_2 = resp_3 = resp_4 = False
payload = (ct.c_uint8 * USTIK_PRE_MESG_LENGTH)(0)

resp_1 = self.write_raw(USBRequestCode.ULTRASTIK_E9, 0x1, USTIK_PRE_INTERFACE, ct.c_void_p(), 0x0,
resp_1 = self.write_raw(USBRequestCodePre2015.ULTRASTIK_E9, 0x1, USTIK_PRE_INTERFACE, ct.c_void_p(), 0x0,
request_type=USBRequestType.REQUEST_TYPE_VENDOR,
recipient=USBRequestRecipient.RECIPIENT_OTHER)
# We need to write 32 bytes here.
for x in range(3):
ct.memmove(ct.addressof(payload), ct.byref(data, USTIK_PRE_MESG_LENGTH * x), USTIK_PRE_MESG_LENGTH)
_logger.debug(f" config data block {x+1}: {' '.join('%02X' % b for b in payload)}")

resp_2 = self.write(USBRequestCode.ULTRASTIK_EB, 0x0, USTIK_PRE_INTERFACE,
resp_2 = self.write(USBRequestCodePre2015.ULTRASTIK_EB, 0x0, USTIK_PRE_INTERFACE,
payload, USTIK_PRE_MESG_LENGTH,
request_type=USBRequestType.REQUEST_TYPE_VENDOR,
recipient=USBRequestRecipient.RECIPIENT_OTHER)
resp_3 = self.read(USBRequestCode.ULTRASTIK_EA, 0x0, USTIK_PRE_INTERFACE, ct.c_void_p(), 0x0,
resp_3 = self.read(USBRequestCodePre2015.ULTRASTIK_EA, 0x0, USTIK_PRE_INTERFACE, ct.c_void_p(), 0x0,
request_type=USBRequestType.REQUEST_TYPE_VENDOR,
recipient=USBRequestRecipient.RECIPIENT_OTHER)
if not resp_2 or not resp_3:
break

if resp_2 and resp_3:
resp_4 = self.write(USBRequestCode.ULTRASTIK_E9, 0x0, USTIK_PRE_INTERFACE, ct.c_void_p(), 0x0,
resp_4 = self.write(USBRequestCodePre2015.ULTRASTIK_E9, 0x0, USTIK_PRE_INTERFACE, ct.c_void_p(), 0x0,
request_type=USBRequestType.REQUEST_TYPE_VENDOR,
recipient=USBRequestRecipient.RECIPIENT_OTHER)

Expand All @@ -141,7 +153,7 @@ def set_controller_id(self, new_controller_id: int) -> bool:
:return: True if successful, otherwise false.
"""
# Calculate new device ID.
new_id = USTIK_CONFIG_BASE + (new_controller_id - 1)
new_id = USTIK_ID_CONFIG_BASE + (new_controller_id - 1)
# Setup an array with zero for all byte values.
data = (ct.c_ubyte * USTIK_MESG_LENGTH)(0)
data[0] = new_id
Expand All @@ -158,8 +170,8 @@ def set_config(self, config_file: str) -> bool:
config = JSONObject(self.validate_config_base(config_file, USTIK_RESOURCE_TYPES))

data = UltraStikStruct()
data.keepAnalog = 0x11 if config.keepAnalog else 0x11
data.mapSize = config.mapSize
data.keepAnalog = 0x11 if config.keepAnalog else 0x50 # Keep Analog: true on(0x11) else false off(0x50)
data.mapSize = 9
data.restrictor = 0x09 if config.restrictor else 0x10
data.borders = (ct.c_uint8 * 8)(*config.borders)
data.map = (ct.c_uint8 * 81)(*[DIRECTION_MAP[v] for v in config.map])
Expand All @@ -170,8 +182,6 @@ def set_config(self, config_file: str) -> bool:
ct.memmove(ct.addressof(payload), ct.byref(data, USTIK_MESG_LENGTH), USTIK_MESG_LENGTH)
_logger.debug(f" config data : {' '.join('%02X' % b for b in payload)}")

resp = self.write_raw(USBRequestCode.SET_CONFIGURATION, 0x1, USTIK_INTERFACE, payload, USTIK_MESG_LENGTH,
request_type=USBRequestType.REQUEST_TYPE_CLASS,
recipient=USBRequestRecipient.RECIPIENT_INTERFACE)
resp = self.write_alt(USBRequestCode.SET_CONFIGURATION, 0x0, USTIK_INTERFACE, payload, USTIK_MESG_LENGTH)

return resp
2 changes: 1 addition & 1 deletion ultimarc/tools/ultrastik.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def run(self):
"schemaVersion" : 2.0,
"resourceType" : "ultrastik-controller-id",
"deviceClass" : "ultrastik",
"newControllerId" : 1
"newControllerId" : self.args.set_device_id
}
else:
# Load and validate config file is one of the valid resource types
Expand Down

0 comments on commit de15e72

Please sign in to comment.