USB host support (#527)
This commit is contained in:
@@ -273,6 +273,14 @@ bool device_exists_of_type(const struct DeviceType* type);
|
||||
*/
|
||||
struct Device* device_find_by_name(const char* name);
|
||||
|
||||
/**
|
||||
* Find the first started device of the given type.
|
||||
*
|
||||
* @param[in] type non-null device type pointer
|
||||
* @return the first started device of the given type, or NULL if none found
|
||||
*/
|
||||
struct Device* device_find_first_active_by_type(const struct DeviceType* type);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Device;
|
||||
struct DeviceType;
|
||||
|
||||
typedef void* UsbHidQueueHandle;
|
||||
|
||||
/** Key values — numerically identical to lv_key_t so no translation is needed. */
|
||||
typedef enum {
|
||||
USB_HID_KEY_UP = 17,
|
||||
USB_HID_KEY_DOWN = 18,
|
||||
USB_HID_KEY_RIGHT = 19,
|
||||
USB_HID_KEY_LEFT = 20,
|
||||
USB_HID_KEY_ESC = 27,
|
||||
USB_HID_KEY_DEL = 127,
|
||||
USB_HID_KEY_BACKSPACE = 8,
|
||||
USB_HID_KEY_ENTER = 10,
|
||||
USB_HID_KEY_NEXT = 9,
|
||||
USB_HID_KEY_PREV = 11,
|
||||
USB_HID_KEY_HOME = 2,
|
||||
USB_HID_KEY_END = 3,
|
||||
} UsbHidKey;
|
||||
|
||||
typedef enum {
|
||||
USB_HID_EVENT_KEY,
|
||||
USB_HID_EVENT_MOUSE_MOVE,
|
||||
USB_HID_EVENT_MOUSE_BTN,
|
||||
USB_HID_EVENT_SCROLL,
|
||||
USB_HID_EVENT_KEYBOARD_CONNECTED,
|
||||
USB_HID_EVENT_KEYBOARD_DISCONNECTED,
|
||||
USB_HID_EVENT_MOUSE_CONNECTED,
|
||||
USB_HID_EVENT_MOUSE_DISCONNECTED,
|
||||
} UsbHidEventType;
|
||||
|
||||
typedef struct {
|
||||
UsbHidEventType type;
|
||||
union {
|
||||
struct { uint32_t key_code; bool pressed; } key;
|
||||
struct { int32_t dx; int32_t dy; } mouse_move;
|
||||
struct { bool button1; bool button2; } mouse_btn;
|
||||
struct { int32_t delta; } scroll;
|
||||
};
|
||||
} UsbHidEvent;
|
||||
|
||||
struct UsbHidApi {
|
||||
bool (*is_connected)(struct Device* device);
|
||||
bool (*subscribe)(struct Device* device, UsbHidQueueHandle event_queue);
|
||||
void (*unsubscribe)(struct Device* device, UsbHidQueueHandle event_queue);
|
||||
};
|
||||
|
||||
extern const struct DeviceType USB_HOST_HID_TYPE;
|
||||
|
||||
/** Returns true if any HID device (keyboard or mouse) is currently connected. */
|
||||
bool usb_host_hid_is_connected(struct Device* device);
|
||||
|
||||
/** Subscribe a FreeRTOS queue to receive UsbHidEvent items from the HID driver. */
|
||||
bool usb_host_hid_subscribe(struct Device* device, UsbHidQueueHandle event_queue);
|
||||
|
||||
/** Unsubscribe a previously subscribed queue. */
|
||||
void usb_host_hid_unsubscribe(struct Device* device, UsbHidQueueHandle event_queue);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Device;
|
||||
struct DeviceType;
|
||||
|
||||
/**
|
||||
* Decoded USB MIDI message.
|
||||
*
|
||||
* `status` encodes both message type and channel:
|
||||
* type = status & 0xF0 (0x80=NoteOff, 0x90=NoteOn, 0xB0=CC, 0xC0=PC, 0xE0=PitchBend, ...)
|
||||
* channel = status & 0x0F (0–15)
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t cable; /**< USB cable number (0–15, almost always 0) */
|
||||
uint8_t status; /**< MIDI status byte */
|
||||
uint8_t data1; /**< First data byte */
|
||||
uint8_t data2; /**< Second data byte */
|
||||
} usb_midi_message_t;
|
||||
|
||||
typedef void (*usb_midi_message_cb_t)(const usb_midi_message_t* msg, void* user_data);
|
||||
|
||||
struct UsbMidiApi {
|
||||
void (*set_callback)(struct Device* device, usb_midi_message_cb_t callback, void* user_data);
|
||||
bool (*is_connected)(struct Device* device);
|
||||
};
|
||||
|
||||
extern const struct DeviceType USB_HOST_MIDI_TYPE;
|
||||
|
||||
/**
|
||||
* Register a callback for incoming MIDI messages.
|
||||
* Replaces any previously registered callback. Pass NULL to disable.
|
||||
* @param device non-null ready USB MIDI device.
|
||||
*/
|
||||
// TODO: Make an interface that takes/releases control
|
||||
void usb_midi_set_callback(struct Device* device, usb_midi_message_cb_t callback, void* user_data);
|
||||
|
||||
/**
|
||||
* Returns true if a MIDI device is currently connected and streaming.
|
||||
* @param device non-null ready USB MIDI device.
|
||||
*/
|
||||
bool usb_midi_is_connected(struct Device* device);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Device;
|
||||
struct DeviceType;
|
||||
|
||||
#define USB_MSC_MOUNT_PATH_PREFIX "/usb"
|
||||
|
||||
struct UsbMscApi {
|
||||
bool (*eject)(struct Device* device, const char* mount_path);
|
||||
};
|
||||
|
||||
extern const struct DeviceType USB_HOST_MSC_TYPE;
|
||||
|
||||
/**
|
||||
* Safely eject a mounted USB drive.
|
||||
* @param device non-null ready USB MSC device (from device_find_first_active_by_type).
|
||||
* @param mount_path Full mount path (e.g. "/usb0").
|
||||
* @return true if the drive was found and ejected.
|
||||
*/
|
||||
bool usb_msc_eject(struct Device* device, const char* mount_path);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -370,4 +370,16 @@ Device* device_find_by_name(const char* name) {
|
||||
return found;
|
||||
}
|
||||
|
||||
Device* device_find_first_active_by_type(const DeviceType* type) {
|
||||
Device* found = nullptr;
|
||||
device_for_each_of_type(type, &found, [](Device* dev, void* ctx) -> bool {
|
||||
if (device_is_ready(dev)) {
|
||||
*static_cast<Device**>(ctx) = dev;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return found;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
#include <tactility/drivers/usb_host_hid.h>
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/driver.h>
|
||||
|
||||
#define USB_HID_API(driver) ((struct UsbHidApi*)(driver)->api)
|
||||
|
||||
extern "C" {
|
||||
|
||||
const struct DeviceType USB_HOST_HID_TYPE = {
|
||||
.name = "usb-host-hid",
|
||||
};
|
||||
|
||||
bool usb_host_hid_is_connected(struct Device* device) {
|
||||
auto* api = USB_HID_API(device_get_driver(device));
|
||||
return api->is_connected(device);
|
||||
}
|
||||
|
||||
bool usb_host_hid_subscribe(struct Device* device, UsbHidQueueHandle event_queue) {
|
||||
auto* api = USB_HID_API(device_get_driver(device));
|
||||
return api->subscribe(device, event_queue);
|
||||
}
|
||||
|
||||
void usb_host_hid_unsubscribe(struct Device* device, UsbHidQueueHandle event_queue) {
|
||||
auto* api = USB_HID_API(device_get_driver(device));
|
||||
api->unsubscribe(device, event_queue);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,23 @@
|
||||
#include <tactility/drivers/usb_host_midi.h>
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/driver.h>
|
||||
|
||||
#define USB_MIDI_API(driver) ((struct UsbMidiApi*)(driver)->api)
|
||||
|
||||
extern "C" {
|
||||
|
||||
const struct DeviceType USB_HOST_MIDI_TYPE = {
|
||||
.name = "usb-host-midi",
|
||||
};
|
||||
|
||||
void usb_midi_set_callback(struct Device* device, usb_midi_message_cb_t callback, void* user_data) {
|
||||
auto* api = USB_MIDI_API(device_get_driver(device));
|
||||
api->set_callback(device, callback, user_data);
|
||||
}
|
||||
|
||||
bool usb_midi_is_connected(struct Device* device) {
|
||||
auto* api = USB_MIDI_API(device_get_driver(device));
|
||||
return api->is_connected(device);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,18 @@
|
||||
#include <tactility/drivers/usb_host_msc.h>
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/driver.h>
|
||||
|
||||
#define USB_MSC_API(driver) ((struct UsbMscApi*)(driver)->api)
|
||||
|
||||
extern "C" {
|
||||
|
||||
const struct DeviceType USB_HOST_MSC_TYPE = {
|
||||
.name = "usb-host-msc",
|
||||
};
|
||||
|
||||
bool usb_msc_eject(struct Device* device, const char* mount_path) {
|
||||
auto* api = USB_MSC_API(device_get_driver(device));
|
||||
return api->eject && api->eject(device, mount_path);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -8,6 +8,9 @@
|
||||
#include <tactility/drivers/bluetooth_serial.h>
|
||||
#include <tactility/drivers/bluetooth_midi.h>
|
||||
#include <tactility/drivers/bluetooth_hid_device.h>
|
||||
#include <tactility/drivers/usb_host_hid.h>
|
||||
#include <tactility/drivers/usb_host_midi.h>
|
||||
#include <tactility/drivers/usb_host_msc.h>
|
||||
#include <tactility/drivers/gpio_controller.h>
|
||||
#include <tactility/drivers/i2c_controller.h>
|
||||
#include <tactility/drivers/i2s_controller.h>
|
||||
@@ -55,6 +58,7 @@ const struct ModuleSymbol KERNEL_SYMBOLS[] = {
|
||||
DEFINE_MODULE_SYMBOL(device_for_each_of_type),
|
||||
DEFINE_MODULE_SYMBOL(device_exists_of_type),
|
||||
DEFINE_MODULE_SYMBOL(device_find_by_name),
|
||||
DEFINE_MODULE_SYMBOL(device_find_first_active_by_type),
|
||||
// driver
|
||||
DEFINE_MODULE_SYMBOL(driver_construct),
|
||||
DEFINE_MODULE_SYMBOL(driver_destruct),
|
||||
@@ -168,6 +172,16 @@ const struct ModuleSymbol KERNEL_SYMBOLS[] = {
|
||||
DEFINE_MODULE_SYMBOL(bluetooth_hid_device_send_gamepad),
|
||||
DEFINE_MODULE_SYMBOL(bluetooth_hid_device_is_connected),
|
||||
DEFINE_MODULE_SYMBOL(BLUETOOTH_HID_DEVICE_TYPE),
|
||||
// drivers/usb_host_hid
|
||||
DEFINE_MODULE_SYMBOL(usb_host_hid_is_connected),
|
||||
DEFINE_MODULE_SYMBOL(USB_HOST_HID_TYPE),
|
||||
// drivers/usb_host_midi
|
||||
DEFINE_MODULE_SYMBOL(usb_midi_set_callback),
|
||||
DEFINE_MODULE_SYMBOL(usb_midi_is_connected),
|
||||
DEFINE_MODULE_SYMBOL(USB_HOST_MIDI_TYPE),
|
||||
// drivers/usb_host_msc
|
||||
DEFINE_MODULE_SYMBOL(usb_msc_eject),
|
||||
DEFINE_MODULE_SYMBOL(USB_HOST_MSC_TYPE),
|
||||
// concurrent/dispatcher
|
||||
DEFINE_MODULE_SYMBOL(dispatcher_alloc),
|
||||
DEFINE_MODULE_SYMBOL(dispatcher_free),
|
||||
|
||||
Reference in New Issue
Block a user