Tài liệu này mô tả cách sử dụng API USB để giao tiếp với các thiết bị USB. Một số thiết bị không thể truy cập qua API USB (xem phần Lưu ý dưới đây để biết chi tiết). Ứng dụng Chrome cũng có thể kết nối với thiết bị nối tiếp và Bluetooth.
Để biết thông tin cơ bản về USB, hãy xem Thông số kỹ thuật chính thức của USB. USB trong NutShell là một khoá học nhanh hợp lý mà bạn có thể thấy hữu ích.
Yêu cầu về tệp kê khai
API USB yêu cầu "usb" quyền trong tệp kê khai:
"permissions": [
"usb"
]
Ngoài ra, để ngăn in vân tay, bạn phải khai báo tất cả các loại thiết bị mà mình muốn truy cập trong tệp kê khai. Mỗi loại thiết bị USB tương ứng với một mã nhà cung cấp/mã sản phẩm cặp (VID/PID). Bạn có thể sử dụng usb.getDevices để liệt kê các thiết bị theo cặp VID/PID của chúng.
Bạn phải khai báo cặp VID/PID cho từng loại thiết bị bạn muốn sử dụng trong usbDevices
quyền trong tệp kê khai của ứng dụng, như trong ví dụ dưới đây:
"permissions": [
{
"usbDevices": [
{
"vendorId": 123,
"productId": 456
}
]
}
]
Kể từ Chrome 57, bạn phải đáp ứng yêu cầu khai báo tất cả loại thiết bị trong tệp kê khai ứng dụng
thoải mái cho những ứng dụng chạy dưới dạng ứng dụng kiosk của ChromeOS. Đối với ứng dụng kiosk, bạn có thể sử dụng
Thuộc tính quyền của interfaceClass
để yêu cầu cấp quyền truy cập vào các thiết bị USB:
- triển khai giao diện USB của một lớp giao diện cụ thể
- có một lớp thiết bị USB cụ thể
Ví dụ: Quyền usbDevices
sau đây sẽ cấp cho một ứng dụng quyền truy cập vào mọi thiết bị USB
triển khai giao diện máy in (mã lớp giao diện 7) và tới các thiết bị bộ chia USB (mã lớp thiết bị)
9):
"permissions": [
{
"usbDevices": [
{"interfaceClass": 7},
{"interfaceClass": 9}
]
}
]
Để biết danh sách các giá trị interfaceClass
được chấp nhận, hãy xem phần Mã lớp USB.
Bạn có thể kết hợp thuộc tính interfaceClass
với thuộc tính vendorId
để chỉ truy cập được vào USB
thiết bị của một nhà cung cấp cụ thể, như được minh hoạ trong ví dụ sau:
"permissions": [
{
"usbDevices": [
{
"vendorId": 123,
"interfaceClass": 7
}
]
}
]
Tìm thiết bị
Để xác định xem một hoặc nhiều thiết bị cụ thể có được kết nối với hệ thống của người dùng hay không, hãy sử dụng usb.getDevices:
chrome.usb.getDevices(enumerateDevicesOptions, callback);
Thông số (loại) | Mô tả |
---|---|
EnumerateDevicesOptions (đối tượng) | Một đối tượng chỉ định cả vendorId (dài) và productId (dài) dùng để tìm đúng loại thiết bị trên xe buýt. Tệp kê khai phải khai báo phần quyền usbDevices liệt kê mọi cặp vendorId và deviceId mà ứng dụng của bạn muốn truy cập. |
lệnh gọi lại (hàm) | Được gọi khi quá trình liệt kê thiết bị hoàn tất. Lệnh gọi lại sẽ được thực thi bằng một tham số là một mảng gồm các đối tượng Device có 3 thuộc tính: device , vendorId , productId . Thuộc tính thiết bị là giá trị nhận dạng ổn định cho một thiết bị đã kết nối. Chế độ này sẽ không thay đổi cho đến khi bạn rút thiết bị ra khỏi nguồn điện. Thông tin chi tiết của giá trị nhận dạng này chưa rõ ràng và có thể thay đổi. Đừng dựa vào loại hiện tại của mảng.Nếu không tìm thấy thiết bị nào, mảng sẽ trống. |
Ví dụ:
function onDeviceFound(devices) {
this.devices=devices;
if (devices) {
if (devices.length > 0) {
console.log("Device(s) found: "+devices.length);
} else {
console.log("Device could not be found");
}
} else {
console.log("Permission denied.");
}
}
chrome.usb.getDevices({"vendorId": vendorId, "productId": productId}, onDeviceFound);
Mở thiết bị
Sau khi đối tượng Device
được trả về, bạn có thể mở một thiết bị bằng usb.openDevice để lấy
điểm điều khiển kết nối. Bạn chỉ có thể giao tiếp với thiết bị USB bằng tay cầm kết nối.
Thuộc tính | Mô tả |
---|---|
thiết bị | Đã nhận được đối tượng trong lệnh gọi lại usb.getDevices. |
dữ liệu (vùng đệm mảng) | Chứa dữ liệu do thiết bị gửi nếu dữ liệu chuyển là dữ liệu đến. |
Ví dụ:
var usbConnection = null;
var onOpenCallback = function(connection) {
if (connection) {
usbConnection = connection;
console.log("Device opened.");
} else {
console.log("Device failed to open.");
}
};
chrome.usb.openDevice(device, onOpenCallback);
Để đơn giản hoá quá trình mở, bạn có thể sử dụng phương thức usb.findDevices, trong đó liệt kê yêu cầu quyền truy cập và mở thiết bị trong một cuộc gọi:
chrome.usb.findDevices({"vendorId": vendorId, "productId": productId, "interfaceId": interfaceId}, callback);
tương đương với:
chrome.usb.getDevices({"vendorId": vendorId, "productId": productId}, function (devices) {
if (!devices) {
console.log("Error enumerating devices.");
callback();
return;
}
var connections = [], pendingAccessRequests = devices.length;
devices.forEach(function (device) {
chrome.usb.requestAccess(interfaceId, function () {
// No need to check for errors at this point.
// Nothing can be done if an error occurs anyway. You should always try
// to open the device.
chrome.usb.openDevices(device, function (connection) {
if (connection) connections.push(connection);
pendingAccessRequests--;
if (pendingAccessRequests == 0) {
callback(connections);
}
});
});
})
});
Truyền và nhận dữ liệu qua USB từ một thiết bị
Giao thức USB xác định 4 phương thức truyền: kiểm soát, hàng loạt, đồng bộ và gián đoạn. Những quá trình chuyển này được mô tả bên dưới.
Hoạt động chuyển dữ liệu có thể diễn ra theo cả hai hướng: từ thiết bị đến máy chủ (đến) và từ máy chủ đến thiết bị (ra ngoài). Hạn bản chất của giao thức USB, cả thư đến và thư đi đều phải do máy chủ khởi tạo (máy tính chạy ứng dụng Chrome). Đối với thư đến (từ thiết bị đến máy chủ), máy chủ (được thực hiện) bằng mã JavaScript của bạn) sẽ gửi thông báo được gắn cờ là "gửi đến" đối với thiết bị. Thông tin chi tiết về tin nhắn phụ thuộc vào thiết bị, nhưng thường sẽ có một số thông tin nhận dạng về nội dung bạn đang yêu cầu từ đó. Sau đó, thiết bị sẽ phản hồi bằng dữ liệu được yêu cầu. Phản hồi của thiết bị được xử lý bởi Chrome và phân phối không đồng bộ cho lệnh gọi lại mà bạn chỉ định trong phương thức chuyển. Sự kiện ra ngoài Thông báo (từ máy chủ đến thiết bị) cũng tương tự, nhưng phản hồi không chứa dữ liệu được thiết bị trả về.
Đối với mỗi thông báo từ thiết bị, lệnh gọi lại được chỉ định sẽ nhận một đối tượng sự kiện có thuộc tính các thuộc tính sau:
Thuộc tính | Mô tả |
---|---|
kết quả (số nguyên) | 0 là thành công; các giá trị khác cho biết không thành công. Chuỗi lỗi có thể được đọc từ chrome.extension.lastError khi hệ thốngchỉ báo lỗi. |
dữ liệu (vùng đệm mảng) | Chứa dữ liệu do thiết bị gửi nếu dữ liệu chuyển là dữ liệu đến. |
Ví dụ:
var onTransferCallback = function(event) {
if (event && event.resultCode === 0 && event.data) {
console.log("got " + event.data.byteLength + " bytes");
}
};
chrome.usb.bulkTransfer(connectionHandle, transferInfo, onTransferCallback);
CONTROL chuyển tuyến
Truyền quyền kiểm soát thường dùng để gửi hoặc nhận các tham số cấu hình hoặc lệnh tới USB thiết bị. Phương thức controlTransfer luôn gửi đến/đọc từ điểm cuối 0 và không có claimInterface là bắt buộc. Phương thức này rất đơn giản và nhận được 3 tham số:
chrome.usb.controlTransfer(connectionHandle, transferInfo, transferCallback)
Thông số (loại) | Mô tả |
---|---|
connectionHandle | Đã nhận được đối tượng trong lệnh gọi lại usb.openDevice. |
transferInfo | Đối tượng thông số với các giá trị từ bảng bên dưới. Hãy kiểm tra thông số kỹ thuật về giao thức của thiết bị USB để biết thông tin chi tiết. |
transferCallback() | Được gọi khi quá trình chuyển hoàn tất. |
Giá trị cho đối tượng transferInfo
:
Giá trị | Mô tả |
---|---|
requestType (chuỗi) | "nhà cung cấp", "tiêu chuẩn", "loại" hoặc "dành riêng". |
người nhận (chuỗi) | "thiết bị", "giao diện", "điểm cuối" hoặc "khác". |
hướng (chuỗi) | "in" hoặc "out". Chữ "in" Chỉ đường dùng để thông báo cho thiết bị rằng thiết bị sẽ gửi thông tin đến máy chủ. Mọi hoạt động giao tiếp trên cổng USB đều do máy chủ khởi tạo, vì vậy hãy sử dụng giá trị "in" chuyển dữ liệu để cho phép thiết bị gửi lại thông tin. |
yêu cầu (số nguyên) | Được xác định bởi giao thức của thiết bị. |
giá trị (số nguyên) | Được xác định bởi giao thức của thiết bị. |
chỉ mục (số nguyên) | Được xác định bởi giao thức của thiết bị. |
độ dài (số nguyên) | Chỉ được dùng khi hướng là "vào". Thông báo cho thiết bị rằng đây là lượng dữ liệu mà máy chủ lưu trữ đang mong đợi phản hồi. |
dữ liệu (vùng đệm mảng) | Được xác định bởi giao thức của thiết bị, bắt buộc khi hướng là "out". |
Ví dụ:
var transferInfo = {
"requestType": "vendor",
"recipient": "device",
"direction": "out",
"request": 0x31,
"value": 120,
"index": 0,
// Note that the ArrayBuffer, not the TypedArray itself is used.
"data": new Uint8Array([4, 8, 15, 16, 23, 42]).buffer
};
chrome.usb.controlTransfer(connectionHandle, transferInfo, optionalCallback);
Chuyển dữ liệu ISOCHRONOUS
Chuyển đồng thời là loại chuyển USB phức tạp nhất. Các thẻ này thường được dùng cho sự kiện phát trực tiếp như video và âm thanh. Để bắt đầu quá trình chuyển đồng bộ (trong hoặc đi), bạn phải sử dụng phương thức usb.isochronousTransfer:
chrome.usb.isochronousTransfer(connectionHandle, isochronousTransferInfo, transferCallback)
Thông số | Mô tả |
---|---|
connectionHandle | Đã nhận được đối tượng trong lệnh gọi lại usb.openDevice. |
isochronousTransferInfo | Đối tượng thông số với các giá trị trong bảng bên dưới. |
transferCallback() | Được gọi khi quá trình chuyển hoàn tất. |
Giá trị cho đối tượng isochronousTransferInfo
:
Giá trị | Mô tả |
---|---|
TransferInfo (đối tượng) | Một đối tượng có các thuộc tính sau: hướng (chuỗi): "in" hoặc "out". điểm cuối (số nguyên): do thiết bị của bạn xác định. Thường thì bạn có thể tìm thấy bằng công cụ so sánh kỹ thuật số của USB, chẳng hạn như lsusb -v length (số nguyên): chỉ dùng khi hướng là "in". Thông báo cho thiết bị rằng đây là lượng dữ liệu mà máy chủ đang mong đợi để phản hồi. Phải ÍT NHẤT packets × packetLength .dữ liệu (bộ đệm mảng): xác định bởi giao thức của thiết bị; chỉ được sử dụng khi hướng là "ra ngoài". |
gói (số nguyên) | Tổng số gói dự kiến trong quá trình chuyển này. |
PacketLength (số nguyên) | Độ dài dự kiến của mỗi gói trong quá trình chuyển này. |
Ví dụ:
var transferInfo = {
"direction": "in",
"endpoint": 1,
"length": 2560
};
var isoTransferInfo = {
"transferInfo": transferInfo,
"packets": 20,
"packetLength": 128
};
chrome.usb.isochronousTransfer(connectionHandle, isoTransferInfo, optionalCallback);
Chuyển hàng loạt
Chuyển hàng loạt thường được dùng để chuyển một lượng lớn dữ liệu không có giới hạn thời gian theo cách đáng tin cậy . usb.bulkTransfer có 3 tham số:
chrome.usb.bulkTransfer(connectionHandle, transferInfo, transferCallback);
Thông số | Mô tả |
---|---|
connectionHandle | Đã nhận được đối tượng trong lệnh gọi lại usb.openDevice. |
transferInfo | Đối tượng thông số với các giá trị trong bảng bên dưới. |
transferCallback | Được gọi khi quá trình chuyển hoàn tất. |
Giá trị cho đối tượng transferInfo
:
Giá trị | Mô tả |
---|---|
hướng (chuỗi) | "in" hoặc "out". |
điểm cuối (số nguyên) | Được xác định bởi giao thức của thiết bị. |
độ dài (số nguyên) | Chỉ được dùng khi hướng là "vào". Thông báo cho thiết bị rằng đây là lượng dữ liệu mà máy chủ lưu trữ đang mong đợi phản hồi. |
dữ liệu (ArrayBuffer) | Được xác định bằng giao thức của thiết bị; chỉ được sử dụng khi hướng là "ra ngoài". |
Ví dụ:
var transferInfo = {
"direction": "out",
"endpoint": 1,
"data": new Uint8Array([4, 8, 15, 16, 23, 42]).buffer
};
TẠM DỪNG chuyển giao
Phương thức chuyển dữ liệu bị gián đoạn được dùng cho một lượng nhỏ dữ liệu nhạy cảm về thời gian. Vì tất cả giao tiếp USB đều do máy chủ khởi tạo, mã máy chủ thường thăm dò thiết bị theo định kỳ, gửi gián đoạn vào những lượt chuyển giúp thiết bị gửi dữ liệu trở lại nếu có bất cứ điều gì trong hàng đợi gián đoạn (được thiết bị duy trì). usb.interruptTransfer có 3 thông số:
chrome.usb.interruptTransfer(connectionHandle, transferInfo, transferCallback);
Thông số | Mô tả |
---|---|
connectionHandle | Đã nhận được đối tượng trong lệnh gọi lại usb.openDevice. |
transferInfo | Đối tượng thông số với các giá trị trong bảng bên dưới. |
transferCallback | Được gọi khi quá trình chuyển hoàn tất. Lưu ý rằng lệnh gọi lại này không chứa phản hồi của thiết bị. Mục đích của lệnh gọi lại chỉ là để thông báo cho mã của bạn rằng các yêu cầu chuyển không đồng bộ đã được xử lý. |
Giá trị cho đối tượng transferInfo
:
Giá trị | Mô tả |
---|---|
hướng (chuỗi) | "in" hoặc "out". |
điểm cuối (số nguyên) | Được xác định bởi giao thức của thiết bị. |
độ dài (số nguyên) | Chỉ được dùng khi hướng là "vào". Thông báo cho thiết bị rằng đây là lượng dữ liệu mà máy chủ lưu trữ đang mong đợi phản hồi. |
dữ liệu (ArrayBuffer) | Được xác định bằng giao thức của thiết bị; chỉ được sử dụng khi hướng là "ra ngoài". |
Ví dụ:
var transferInfo = {
"direction": "in",
"endpoint": 1,
"length": 2
};
chrome.usb.interruptTransfer(connectionHandle, transferInfo, optionalCallback);
Chú ý
Không phải thiết bị nào cũng truy cập được qua USB API. Nói chung, bạn không thể truy cập vào thiết bị vì nhân của hệ điều hành hoặc trình điều khiển gốc giữ chúng khỏi mã không gian của người dùng. Hơi nhiều ví dụ như các thiết bị có hồ sơ HID trên hệ thống OSX và ổ đĩa bút USB.
Trên hầu hết các hệ thống Linux, theo mặc định, các thiết bị USB được liên kết với quyền chỉ có thể đọc. Để mở một
thiết bị thông qua API này, người dùng của bạn cũng sẽ cần có quyền ghi vào thiết bị đó. Một giải pháp đơn giản là
đặt một quy tắc udev. Tạo tệp /etc/udev/rules.d/50-yourdevicename.rules
bằng các thành phần sau
nội dung:
SUBSYSTEM=="usb", ATTR{idVendor}=="[yourdevicevendor]", MODE="0664", GROUP="plugdev"
Sau đó, chỉ cần khởi động lại trình nền udev: service udev restart
. Bạn có thể kiểm tra xem các quyền trên thiết bị có đang
đặt chính xác bằng cách làm theo các bước sau:
- Chạy
lsusb
để tìm số xe buýt và thiết bị. - Chạy
ls -al /dev/bus/usb/[bus]/[device]
. Tệp này phải thuộc sở hữu của nhóm "plugin" và có quyền ghi nhóm.
Ứng dụng của bạn không thể tự động thực hiện vì quy trình này yêu cầu quyền truy cập thư mục gốc. Bạn nên bạn cung cấp hướng dẫn cho người dùng cuối và liên kết đến mục Lưu ý trên trang này để nội dung giải thích.
Trên ChromeOS, bạn chỉ cần gọi usb.requestAccess. Nhà môi giới quyền sẽ thực hiện việc này cho bạn.