本文說明如何使用 USB API 與 USB 裝置通訊。部分裝置 無法透過 USB API 存取 (詳情請參閱下方注意事項一節)。Chrome 應用程式 也可以連線至序列和藍牙裝置。
如需 USB 的背景資訊,請參閱官方 USB 規格。 NutShell 中的 USB 連接埠是合理的速成課程中,或許對您有所幫助。
資訊清單規定
USB API 需要「usb」權限:
"permissions": [
"usb"
]
此外,為避免指紋列印,您必須宣告 您要在資訊清單檔案中存取哪些項目每個類型的 USB 裝置都會對應到一個供應商 ID/產品 ID (VID/PID) 配對。您可以使用 usb.getDevices 按照 VID/PID 組合列舉裝置。
您必須為要使用的每種裝置類型宣告 VID/PID 組合,才能在 usbDevices
底下使用
權限,如以下範例所示:
"permissions": [
{
"usbDevices": [
{
"vendorId": 123,
"productId": 456
}
]
}
]
自 Chrome 57 起,在應用程式資訊清單中宣告所有裝置類型的條件如下:
輕鬆管理以 ChromeOS 資訊站應用程式執行的應用程式。如果是資訊站應用程式,您可以使用
interfaceClass
權限屬性,才能要求存取符合以下條件的 USB 裝置:
- 實作特定介面類別的 USB 介面
- 都有特定的 USB 裝置類別
舉例來說,下列 usbDevices
權限會將應用程式存取權授予所有符合以下條件的 USB 裝置:
實作印表機介面 (介面類別代碼 7),以及 USB 中樞裝置 (裝置類別代碼)
9):
"permissions": [
{
"usbDevices": [
{"interfaceClass": 7},
{"interfaceClass": 9}
]
}
]
如需可接受的 interfaceClass
值清單,請參閱 USB 類別代碼。
interfaceClass
屬性可與 vendorId
屬性結合,只取得 USB 存取權
特定供應商的裝置,如以下範例所示:
"permissions": [
{
"usbDevices": [
{
"vendorId": 123,
"interfaceClass": 7
}
]
}
]
尋找裝置
如要判斷一或多部特定裝置是否已連線至使用者的系統,請使用 usb.getDevices 方法:
chrome.usb.getDevices(enumerateDevicesOptions, callback);
參數 (類型) | 說明 |
---|---|
EnumerateDevicesOptions (物件) | 此物件同時指定 vendorId (長) 和 productId (長),用於在公車上尋找正確裝置類型。資訊清單必須宣告 usbDevices 權限部分,其中列出應用程式要存取的所有 vendorId 和 deviceId 組合。 |
回呼 (函式) | 裝置列舉完成時呼叫。系統會使用一個參數執行回呼,這是一種 Device 物件陣列,其中包含三個屬性:device 、vendorId 、productId 。裝置屬性是已連結裝置的穩定 ID。除非裝置接上電源,否則這個數值不會改變。ID 的詳細資料不透明,隨時可能變更。請勿依賴當前類型。如果找不到裝置,陣列會是空白的。 |
範例:
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);
開啟裝置
傳回 Device
物件後,您可以使用 usb.openDevice 開啟裝置來取得
連線控制代碼。您只能透過連線控點與 USB 裝置通訊。
屬性 | 說明 |
---|---|
裝置 | 在 usb.getDevices 回呼中接收的物件。 |
資料 (陣列緩衝區) | 包含裝置傳入的傳輸資料。 |
範例:
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);
如要簡化開啟程序,可以使用 usb.findDevices 方法,列舉如下: 要求存取權,並在通話中開啟裝置:
chrome.usb.findDevices({"vendorId": vendorId, "productId": productId, "interfaceId": interfaceId}, callback);
相當於:
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);
}
});
});
})
});
USB 傳輸及接收裝置的資料
USB 通訊協定定義了四種傳輸類型:控制、大量、同質和 幹擾。轉移程序如下。
裝置對主機 (傳入) 和主機對裝置 (傳出) 皆可進行轉移。應付款項 基於 USB 通訊協定的特性,內送和外寄郵件皆必須由主機發起 (執行 Chrome 應用程式的電腦)。如果是內送 (裝置對主機) 郵件,主機 (已啟動) ) 會傳送標記為「inbound」的訊息。詳細資料 訊息取決於裝置,但通常都能識別您提出要求的內容 從資料中學習接著,裝置會傳回要求的資料。裝置回應會由 Chrome 並以非同步的方式傳送至您在轉移方法中指定的回呼。出站 (主機對裝置) 訊息相似,但回應不包含裝置傳回的資料。
針對裝置的每則訊息,指定的回呼都會收到含有 屬性:
屬性 | 說明 |
---|---|
resultCode (整數) | 0 表示成功;其他值則代表失敗。發生失敗情形時, 可讀取 chrome.extension.lastError 錯誤字串。 |
資料 (陣列緩衝區) | 包含裝置傳入的傳輸資料。 |
範例:
var onTransferCallback = function(event) {
if (event && event.resultCode === 0 && event.data) {
console.log("got " + event.data.byteLength + " bytes");
}
};
chrome.usb.bulkTransfer(connectionHandle, transferInfo, onTransferCallback);
控制轉乘
控制傳輸通常用於傳送或接收設定或指令參數至 USB 裝置。ControlTransfer 方法一律會從端點 0 傳送至/讀取,且沒有宣告介面 這通常代表交易 不會十分要求關聯語意方法簡單,會收到三個參數:
chrome.usb.controlTransfer(connectionHandle, transferInfo, transferCallback)
參數 (類型) | 說明 |
---|---|
connectionHandle | usb.openDevice 回呼中接收到的物件。 |
transferInfo | 包含下表值的參數物件。詳情請參閱 USB 裝置通訊協定規格。 |
transferCallback() | 轉移作業完成後叫用。 |
transferInfo
物件的值:
值 | 說明 |
---|---|
requestType (字串) | 「vendor」、「standard」、「class」或「reserve」等值 |
收件者 (字串) | 「裝置」、「介面」、「端點」或「其他」 |
方向 (字串) | 「位於」或是「輸出」「進」方向是用來通知裝置, 應傳送資訊給主機。USB 匯流排上的所有通訊都是由主機發起,因此請使用「in」資料轉移,讓裝置 能夠傳回資訊。 |
要求 (整數) | 由裝置通訊協定定義。 |
值 (整數) | 由裝置通訊協定定義。 |
索引 (整數) | 由裝置通訊協定定義。 |
長度 (整數) | 僅適用於方向為「in」時。通知裝置,瞭解主機預期回應的資料量。 |
資料 (陣列緩衝區) | 由裝置通訊協定定義;方向為「離開」時必須要求。 |
範例:
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);
ISOCHRONOUS 傳輸
非同步傳輸是最複雜的 USB 傳輸類型。常用於串流 例如影片和聲音如要啟動異地傳輸 (無論是進出或傳出),您 必須使用 usb.isochronousTransfer 方法:
chrome.usb.isochronousTransfer(connectionHandle, isochronousTransferInfo, transferCallback)
參數 | 說明 |
---|---|
connectionHandle | usb.openDevice 回呼中接收到的物件。 |
isochronousTransferInfo | 包含下表值的參數物件。 |
transferCallback() | 轉移作業完成後叫用。 |
isochronousTransferInfo
物件的值:
值 | 說明 |
---|---|
TransferInfo (物件) | 包含下列屬性的物件: direction (string): "in"或「out」。 端點 (整數): 由裝置定義。通常可透過 USB 掃描工具取得,例如 lsusb -v 長度 (整數): 只有在方向「以」表示時才能使用。通知裝置此伺服器預期回應的資料量。 應至少為 packets × packetLength 。資料 (陣列緩衝區): 由裝置的通訊協定定義。只有在方向為「out」時才能使用。 |
封包數 (整數) | 這項傳輸作業中預期的封包總數。 |
封包長度 (整數) | 這項傳輸作業中每個封包的預期長度。 |
範例:
var transferInfo = {
"direction": "in",
"endpoint": 1,
"length": 2560
};
var isoTransferInfo = {
"transferInfo": transferInfo,
"packets": 20,
"packetLength": 128
};
chrome.usb.isochronousTransfer(connectionHandle, isoTransferInfo, optionalCallback);
轉移 BULK
大量轉移通常用於在可靠服務中轉移大量且不具時效性的資料 。usb.bulkTransfer 有三個參數:
chrome.usb.bulkTransfer(connectionHandle, transferInfo, transferCallback);
參數 | 說明 |
---|---|
connectionHandle | usb.openDevice 回呼中接收到的物件。 |
transferInfo | 包含下表值的參數物件。 |
transferCallback | 轉移作業完成後叫用。 |
transferInfo
物件的值:
值 | 說明 |
---|---|
方向 (字串) | 「位於」或是「輸出」 |
端點 (整數) | 由裝置通訊協定定義。 |
長度 (整數) | 僅適用於方向為「in」時。通知裝置,瞭解主機預期回應的資料量。 |
資料 (ArrayBuffer) | 由裝置的通訊協定定義;只有在方向為「out」時才能使用。 |
範例:
var transferInfo = {
"direction": "out",
"endpoint": 1,
"data": new Uint8Array([4, 8, 15, 16, 23, 42]).buffer
};
INTERRUPT 轉乘
中斷轉移作業則用於少量具時效性的資料。由於所有 USB 通訊 由主機啟動,主機代碼通常會定期輪詢裝置,傳送中斷 IN 是一種傳輸方法,如果中斷佇列中有任何內容,裝置就會傳回資料 (由裝置維護)。usb.interruptTransfer 有三個參數:
chrome.usb.interruptTransfer(connectionHandle, transferInfo, transferCallback);
參數 | 說明 |
---|---|
connectionHandle | usb.openDevice 回呼中接收到的物件。 |
transferInfo | 包含下表值的參數物件。 |
transferCallback | 轉移作業完成後叫用。請注意,這個回呼並不包含裝置的回應。回呼的目的只是告知您的程式碼已處理非同步轉移要求。 |
transferInfo
物件的值:
值 | 說明 |
---|---|
方向 (字串) | 「位於」或是「輸出」 |
端點 (整數) | 由裝置通訊協定定義。 |
長度 (整數) | 僅適用於方向為「in」時。通知裝置,瞭解主機預期回應的資料量。 |
資料 (ArrayBuffer) | 由裝置的通訊協定定義;只有在方向為「out」時才能使用。 |
範例:
var transferInfo = {
"direction": "in",
"endpoint": 1,
"length": 2
};
chrome.usb.interruptTransfer(connectionHandle, transferInfo, optionalCallback);
注意事項
並非所有裝置都可透過 USB API 存取。一般來說,無法存取裝置,因為 作業系統的 核心或原生驅動程式,不會顯示使用者的空間程式碼。只有部分通知 包括在 OSX 系統上擁有 HID 設定檔的裝置,以及 USB 隨身碟。
在大部分的 Linux 系統中,USB 裝置預設會對應唯讀權限。若要開啟
,您的使用者也必須具有此 API 的寫入權限。簡單的解決方法是
設定 udev 規則建立含有以下內容的檔案 /etc/udev/rules.d/50-yourdevicename.rules
內容:
SUBSYSTEM=="usb", ATTR{idVendor}=="[yourdevicevendor]", MODE="0664", GROUP="plugdev"
接著重新啟動 udev Daemon:service udev restart
。你可以查看裝置權限是否
請按照下列步驟正確設定:
- 執行
lsusb
找出公車和裝置號碼。 - 執行
ls -al /dev/bus/usb/[bus]/[device]
。 這個檔案應由「plugdev」群組擁有並擁有 群組寫入權限。
這個程序需要 Root 存取權,因此您的應用程式無法自動執行此操作。建議做法 為使用者提供操作說明,並參閱本頁的注意事項部分, 解釋。
在 ChromeOS 中,直接呼叫 usb.requestAccess 即可。權限代理程式會為您執行這項作業。