Programming Interface¶
Overview¶
The USBHub3c consists of 6 USB Type-C ports connected to a USB 3.2 Gen 2x1 Hub, USB Power Delivery, and Qualcom QuickCharge hardware. The software control of this device manipulates various capabilities of each of these ports. The USBHub3c is one of a family of Acroname devices, and shares some of its feature set and interface with other Acroname devices.
Acroname provides software APIs for working with the USBHub3c in a number of different languages. We strive to keep much of the syntax and structure of the API similar across these languages. The core of this common protocol, API software structure, and nomenclature we call BrainStem (for more information see BrainStem).
Whether C++ or Python or another language interface is the target, all of our APIs start with the concept of a connection to the USBHub3c device. This is usually represented by a class, an instance of which represents a connection to a specific USBHub3c. We call these classes “Modules” or “Module classes.” Each class then contains a set of subclass instances which represent interface functionality for a specific piece of hardware functionality. We call these sub objects “Entities.” The following code block represents the “Module” class definition for the USBHub3c.
Module class¶
class aUSBHub3c : public Acroname::BrainStem::Module
{
public:
aUSBHub3c(const uint8_t module = aUSBHUB3P_MODULE,
bool bAutoNetworking = true,
const uint8_t model = aMODULE_TYPE_USBHub3c) :
Acroname::BrainStem::Module(module, bAutoNetworking, model)
{
for(int x = 0; x < aUSBHUB3C_NUM_APPS; x++) {
app[x].init(this, x);
}
for(int x = 0; x < aUSBHUB3C_NUM_PD_PORTS; x++) {
pd[x].init(this, x);
}
for(int x = 0; x < aUSBHUB3C_NUM_POINTERS; x++) {
pointer[x].init(this, x);
}
store[aUSBHUB3C_STORE_INTERNAL_INDEX].init(this, storeInternalStore);
store[aUSBHUB3C_STORE_RAM_INDEX].init(this, storeRAMStore);
store[aUSBHUB3C_STORE_EEPROM_INDEX].init(this, storeEEPROMStore);
system.init(this, 0);
for(int x = 0; x < aUSBHUB3C_NUM_TEMPERATURES; x++) {
temperature[x].init(this, x);
}
for(int x = 0; x < aUSBHUB3C_NUM_TIMERS; x++) {
timer[x].init(this, x);
}
hub.init(this, 0);
for(int x = 0; x < aUSBHUB3C_NUM_RAILS; x++) {
rail[x].init(this, x);
}
}
HubClass hub; /**< Hub Class */
Acroname::BrainStem::AppClass app[aUSBHUB3C_NUM_APPS]; /**< App Class */
Acroname::BrainStem::PointerClass pointer[aUSBHUB3C_NUM_POINTERS]; /**< Pointer Class */
Acroname::BrainStem::PowerDeliveryClass pd[aUSBHUB3C_NUM_USB_PORTS]; /**< Power Delivery Class */
Acroname::BrainStem::RailClass rail[aUSBHUB3C_NUM_RAILS]; /**< Rail Class */
Acroname::BrainStem::StoreClass store[aUSBHUB3C_NUM_STORES]; /**< Store Class */
Acroname::BrainStem::SystemClass system; /**< System Class */
Acroname::BrainStem::TemperatureClass temperature[aUSBHUB3C_NUM_TEMPERATURES]; /**< Temperature Class */
Acroname::BrainStem::TimerClass timer[aUSBHUB3C_NUM_TIMERS]; /**< Timer Class */
/** Port ID */
typedef enum PORT_ID : uint8_t {
kPORT_ID_0 = 0,
kPORT_ID_1,
kPORT_ID_2,
kPORT_ID_3,
kPORT_ID_4,
kPORT_ID_5,
kPORT_ID_CONTROL,
kPORT_ID_POWER_C
} PORT_ID_t;
};
class USBHub3c(Module):
BASE_ADDRESS = 6
NUMBER_OF_STORES = 3
NUMBER_OF_INTERNAL_SLOTS = 12
NUMBER_OF_RAM_SLOTS = 1
NUMBER_OF_TEMPERATURES = 3
NUMBER_OF_TIMERS = 8
NUMBER_OF_APPS = 4
NUMBER_OF_POINTERS = 4
NUMBER_OF_USB_PORTS = 8
NUMBER_OF_RAILS = 7
NUMBER_OF_POWER_DELIVERY_PORTS = 8
STORE_INTERNAL_INDEX = 0
STORE_RAM_INDEX = 1
STORE_EEPROM_INDEX = 2
def __init__(self, address=BASE_ADDRESS, enable_auto_networking=True, model=defs.MODEL_USBHUB_3C):
super(USBHub3c, self).__init__(address, enable_auto_networking, model)
self.system = System(self, 0)
self.app = [App(self, i) for i in range(0, USBHub3c.NUMBER_OF_APPS)]
self.pointer = [Pointer(self, i) for i in range(0, USBHub3c.NUMBER_OF_POINTERS)]
self.store = [Store(self, Store.INTERNAL_STORE),
Store(self, Store.RAM_STORE),
Store(self, Store.EEPROM_STORE)]
self.temperature = [Temperature(self, i) for i in range(0, USBHub3c.NUMBER_OF_TEMPERATURES)]
self.timer = [Timer(self, i) for i in range(0, USBHub3c.NUMBER_OF_TIMERS)]
self.hub = USBHub3c.Hub(self, 0)
self.rail = [Rail(self, i) for i in range(0, USBHub3c.NUMBER_OF_RAILS)]
self.pd = [PowerDelivery(self, i) for i in range(0, USBHub3c.NUMBER_OF_POWER_DELIVERY_PORTS)]
def connect(self, serial_number, **kwargs):
return super(USBHub3c, self).connect(Spec.USB, serial_number)
class Hub(USBSystem):
def __init__(self, module, index):
super(USBHub3c.Hub, self).__init__(module, index)
self.port = [Port(module, i) for i in range(0, USBHub3c.NUMBER_OF_USB_PORTS)]
In the code example above notice that the member variables app, pointer, pd, rail, store, system, temperature, and timer are all instances of “entity” classes. Once the USBHub3c is instantiated and the device connected the hardware functionality can be controlled via the entity interface.
aUSBHub3c device;
device.discoverAndConnect(USB);
device.hub.port[0].setEnabled(1);
device = aUSBHub3c();
device.discoverAndConnect(brainstem.link.Spec.USB);
device.hub.port[0].setEnabled(True);
Supported Entites¶
See the Module Entities section of the this document for a complete list of the entities supported by the USBHub3c.
Ports¶
Each of the 6 regular Type-C ports of the USBHub3c implement separate and independently switched USB2/3 data lines, CC, Vconn and current-limited Vbus lines. USB power, data and SS data can be independently disconnected for advanced USB testing applications. Control of various aspects of USB for each of the port is effected through two entities combined into a Hub member and Power Delivery control is effected through the Power Delivery entity.
USBHub3c Hub¶
There is a single “hub” instance within the module that controls the functionality primarily of the USBHub portion of the USBHub3c. It is made up of two separate entities. The USB System controls USB hub functionality as a whole, such as switching the upstream port setting enumeration delays and and controlling and monitoring multiple ports at a time. The Port entity provides fine grained control and monitoring of each port within the hub.
USBHub3c Power Delivery¶
There is a Power Delivery entity for each port on the USBHub3c. The Power Delivery entity controls much of the Power Delivery functionality of each of the Type-C ports.
USBHub3c System and Supporting entities¶
System: Device level functionality.
Rail: External rail controls supporting Loading on the Type-C ports.
Temperature: External rail controls supporting Loading on the Type-C ports.
Store: Access to non-volatile storage on the device.
Connections¶
Each USBHub3c is uniquely addressable and controllable from a host PC via the selected upstream port (0 by default) or through a dedicated Control Port. Acroname’s BrainStem™ link is then established over the USB input and allows a connection to the on-board controller in the USBHub3c. USBHub3c can be controlled via a host running BrainStem APIs
The USBHub3c is capable of many features. These features are organized into groups called entities. Through these entities we can access the vast features of the USBHub3c.
A complete list of all entities and functions can be found at the bottom of the page
Establishing Software Control¶
Software control of the features of the USBHub3c is done with the BrainStem API via a BrainStem link. BrainStem links are done over USB and can be established via the currently selected upstream port (0-6) or the Control Port. After one or more of these ports is connected to a host machine, a user can connect to it via software API:
device.link.discoverAndConnect(USB)
When multiple Acroname devices are connected to a host, connecting to a specific hub can be done by providing the hub serial number. Further, all connected devices can be found using;
brainstem.discover.findAllModules(USB)`` (Python)
Acroname::BrainStem::Link::sDiscover()`` (C++)
BrainStem Control Port¶
The USBHub3c also has a dedicated control channel on the Type C connector labeled “Control”. This is a full-speed USB 2.0 connection for BrainStem interface only. No USB hub traffic can flow on this connection. When a cable is connected to the Type C connector, the BrainStem link can only be established through the Control Port, independent of the selected upstream port. Ports 0-6 are then used only for USB hub traffic to connect upstream and downstream USB devices. When the Control Port is not used, the BrainStem link will share the active upstream USB connection. Using the Control Port provides the ability to completely disconnect USB upstream host connections while maintaining software control of the hub.
Using Multiple Hosts with USBHub3c¶
The USBHub3c supports Acroname’s AnyPort™ technology. Any of the ports 0 - 6 can be selected as the hub’s upstream facing port. This functionality is accessed via the USBSystem entity. In order to seamlessly switch upstream ports, it is recommended that you use the device’s dedicated control port to connect to and control the USBHub3c.
Device Drivers¶
The USBHub3c leverages common operating system drivers that do not require custom installations on modern operating systems.
Some older operating systems may require the installation of a BrainStem USB driver information files to enable software control. Installation details on installing USB drivers can be found within the BrainStem Development Kit under the “drivers” folder. For example, Windows 7 requires the supplied INF to communicate with BrainStem USB devices.