USB Host
TinyCLR's USB Host API lets a SITCore device act as the USB host — driving the bus and accepting USB devices that you'd normally plug into a PC. Supported device classes:
- HID — keyboards, mice, joysticks
- Mass Storage (MSC) — USB sticks, external drives (FAT16/FAT32, see File System)
- Raw devices — anything else, accessed via the underlying USB descriptors and pipes
NuGet packages: GHIElectronics.TinyCLR.Devices.UsbHost, plus GHIElectronics.TinyCLR.Devices.Storage and GHIElectronics.TinyCLR.IO if you need mass-storage support.
USB hubs aren't supported. Devices with multiple interfaces (composite devices) or built-in hubs (some USB sticks) won't enumerate correctly.
Detecting connections
The UsbHostController raises a single OnConnectionChangedEvent for every connect, disconnect, and bad-device condition. Inspect e.Type to find out what was plugged in and instantiate the matching driver class.
using System.Diagnostics;
using System.IO;
using System.Threading;
using GHIElectronics.TinyCLR.Devices.Storage;
using GHIElectronics.TinyCLR.Devices.UsbHost;
using GHIElectronics.TinyCLR.Devices.UsbHost.Descriptors;
using GHIElectronics.TinyCLR.Pins;
using GHIElectronics.TinyCLR.IO;
var usbHostController = UsbHostController.GetDefault();
usbHostController.OnConnectionChangedEvent += OnConnectionChanged;
usbHostController.Enable();
Thread.Sleep(Timeout.Infinite);
void OnConnectionChanged(UsbHostController sender, DeviceConnectionEventArgs e){
Debug.WriteLine("Id=" + e.Id + " interface=" + e.InterfaceIndex + " port=" + e.PortNumber
+ " type=" + e.Type + " vid=" + e.VendorId + " pid=" + e.ProductId);
switch (e.DeviceStatus){
case DeviceConnectionStatus.Connected:
HandleConnect(e);
break;
case DeviceConnectionStatus.Disconnected:
Debug.WriteLine("Device disconnected");
// Unmount file system here if previously mounted.
break;
case DeviceConnectionStatus.Bad:
Debug.WriteLine("Bad device");
break;
}
}
void HandleConnect(DeviceConnectionEventArgs e){
switch (e.Type){
case BaseDevice.DeviceType.Keyboard:
var keyboard = new Keyboard(e.Id, e.InterfaceIndex);
keyboard.KeyDown += (s, a) => Debug.WriteLine("Key down: " + a.Which + " (ASCII " + a.ASCII + ")");
keyboard.KeyUp += (s, a) => Debug.WriteLine("Key up: " + a.Which + " (ASCII " + a.ASCII + ")");
break;
case BaseDevice.DeviceType.Mouse:
var mouse = new Mouse(e.Id, e.InterfaceIndex);
mouse.CursorMoved += (s, a) => Debug.WriteLine("Mouse: " + a.NewPosition.X + "," + a.NewPosition.Y);
mouse.ButtonChanged += (s, a) => Debug.WriteLine("Mouse button: " + a.Which);
break;
case BaseDevice.DeviceType.Joystick:
var joystick = new Joystick(e.Id, e.InterfaceIndex);
joystick.CursorMoved += (s, a) => Debug.WriteLine("Joystick: " + a.NewPosition.X + "," + a.NewPosition.Y);
joystick.HatSwitchPressed += (s, a) => Debug.WriteLine("Joystick hat: " + a.Direction);
joystick.ButtonChanged += (s, a) => Debug.WriteLine("Joystick button: " + a.Which);
break;
case BaseDevice.DeviceType.MassStorage:
MountMassStorage();
break;
default:
ReadRawDevice(e);
break;
}
}
Mass Storage
When a USB stick or external drive is detected, mount it through StorageController and use it like any other file system:
void MountMassStorage()
{
var storage = StorageController.FromName(SC20260.StorageController.UsbHostMassStorage);
var drive = FileSystem.Mount(storage.Hdc);
var info = new DriveInfo(drive.Name);
Debug.WriteLine("Volume: " + info.VolumeLabel);
Debug.WriteLine("Format: " + info.DriveFormat);
Debug.WriteLine("Total size: " + info.TotalSize);
Debug.WriteLine("Free space: " + info.TotalFreeSpace);
Debug.WriteLine("Root: " + info.RootDirectory);
}
The mount lives until FileSystem.Unmount(...) (typically called on the Disconnected event).
Raw devices
If a device's class doesn't match Keyboard, Mouse, Joystick, or MassStorage, you can talk to it as a raw USB device — reading descriptors, opening pipes, and exchanging bytes directly. Useful for proprietary HID devices, custom hardware, or testing unusual USB peripherals.
void ReadRawDevice(DeviceConnectionEventArgs e)
{
var raw = new RawDevice(e.Id, e.InterfaceIndex, e.Type);
var deviceDescriptor = raw.GetDeviceDescriptor();
var configDescriptor = raw.GetConfigurationDescriptor(0);
// SET_CONFIGURATION(1) — standard setup packet to activate config 1.
raw.SendSetupPacket(0, 9, 1, 0);
// Build an Endpoint descriptor for an interrupt-in endpoint (address 0x81, 8-byte max packet, 10 ms poll).
var endpointData = new byte[7] {
7, // Descriptor length.
5, // Endpoint descriptor type.
0x81, // Input endpoint, address 1.
3, // Interrupt transfer type.
8, 0, // Max packet size = 8 (LSB, MSB).
10, // Polling interval (ms).
};
var endpoint = new Endpoint(endpointData, 0);
var pipe = raw.OpenPipe(endpoint);
pipe.TransferTimeout = 10;
var data = new byte[8];
var read = pipe.Transfer(data);
if (read > 0)
{
Debug.WriteLine("Raw device read " + read + " bytes: "
+ data[0] + "," + data[1] + "," + data[2] + "," + data[3]);
}
else
{
Debug.WriteLine("No data available");
}
Thread.Sleep(500);
}
The endpoint descriptor (7 bytes) is the standard USB endpoint descriptor format from the USB spec — fill in the values that match your device's interface, available in its USB documentation or via tools like lsusb -v on Linux.
API reference
| Namespace | Description |
|---|---|
| GHIElectronics.TinyCLR.Devices.UsbHost | USB host controller and device enumeration |