อุปกรณ์ USB

เอกสารนี้จะอธิบายวิธีใช้ USB API เพื่อสื่อสารกับอุปกรณ์ USB อุปกรณ์บางรุ่น ไม่สามารถเข้าถึงได้ผ่าน USB API (ดูรายละเอียดในส่วนคำเตือนด้านล่าง) แอป Chrome ยังเชื่อมต่อกับอุปกรณ์ซีเรียลและบลูทูธได้ด้วย

สำหรับข้อมูลพื้นฐานเกี่ยวกับ USB โปรดดูข้อมูลจำเพาะของ USB อย่างเป็นทางการ USB ใน NutShell เป็นหลักสูตรเร่งรัดที่สมเหตุสมผลซึ่งอาจเป็นประโยชน์กับคุณ

ข้อกำหนดของไฟล์ Manifest

USB API ต้องใช้ "usb" สิทธิ์ในไฟล์ Manifest

"permissions": [
  "usb"
]

นอกจากนี้ เพื่อป้องกันลายนิ้วมือ คุณจะต้องประกาศประเภทอุปกรณ์ทั้งหมด ที่ต้องการเข้าถึงในไฟล์ Manifest อุปกรณ์ USB แต่ละประเภทจะสอดคล้องกับรหัสของผู้ให้บริการ/รหัสผลิตภัณฑ์ (VID/PID) คุณใช้ usb.getDevices เพื่อแจกแจงอุปกรณ์ตามคู่ VID/PID ได้

คุณต้องประกาศคู่ VID/PID สำหรับอุปกรณ์แต่ละประเภทที่ต้องการใช้ภายใต้ usbDevices สิทธิ์ในไฟล์ Manifest ของแอปตามที่แสดงในตัวอย่างด้านล่าง

"permissions": [
  {
    "usbDevices": [
      {
        "vendorId": 123,
        "productId": 456
      }
    ]
  }
]

ตั้งแต่ Chrome 57 เป็นต้นไป ข้อกำหนดสำหรับการประกาศอุปกรณ์ทุกประเภทในไฟล์ Manifest ของแอปคือ ผ่อนคลายสำหรับแอปที่ทำงานเป็นแอปคีออสก์ของ 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);
พารามิเตอร์ (ประเภท)คำอธิบาย
EnumIZEDeviceOptions (ออบเจ็กต์)วัตถุที่ระบุทั้ง vendorId (ยาว) และ productId (ยาว) ที่ใช้ค้นหาประเภทอุปกรณ์ที่ถูกต้องบนรถประจำทาง ไฟล์ Manifest ต้องประกาศส่วนสิทธิ์ usbDevices ที่แสดงคู่ vendorId และ deviceId ทั้งหมดที่แอปของคุณต้องการเข้าถึง
Callback (ฟังก์ชัน)มีการโทรเมื่อแจกแจงอุปกรณ์เสร็จแล้ว ระบบจะเรียกใช้ Callback ด้วยพารามิเตอร์ 1 รายการ ซึ่งเป็นอาร์เรย์ของออบเจ็กต์ Device ที่มีพร็อพเพอร์ตี้ 3 รายการ ได้แก่ device, vendorId, productId พร็อพเพอร์ตี้ของอุปกรณ์คือตัวระบุแบบคงที่สำหรับอุปกรณ์ที่เชื่อมต่อ โดยจะไม่เปลี่ยนแปลงจนกว่าจะถอดปลั๊กอุปกรณ์ รายละเอียดของตัวระบุจะไม่ชัดเจนและอาจมีการเปลี่ยนแปลง โปรดอย่าอิงตามประเภทปัจจุบัน
หากไม่พบอุปกรณ์ อาร์เรย์จะว่างเปล่า

ตัวอย่าง

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 ได้โดยใช้แฮนเดิลการเชื่อมต่อเท่านั้น

พร็อพเพอร์ตี้คำอธิบาย
อุปกรณ์ได้รับออบเจ็กต์ใน Callback usb.getDevices
ข้อมูล (arraybuffer)มีข้อมูลที่อุปกรณ์ส่งหากเป็นการโอนขาเข้า

ตัวอย่าง

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 กำหนดการโอน 4 ประเภท ได้แก่ การควบคุม แบบกลุ่ม แบบแบ่งย่อย และ ขัดจังหวะ เราได้อธิบายการโอนเหล่านี้ไว้ที่ด้านล่าง

การโอนอาจเกิดขึ้นในทั้ง 2 ทิศทาง ได้แก่ ระหว่างอุปกรณ์กับโฮสต์ (ขาเข้า) และโฮสต์ไปยังอุปกรณ์ (ขาออก) ครบกำหนด ตามลักษณะของโปรโตคอล USB ทั้งข้อความขาเข้าและขาออกจะต้องเริ่มต้นโดยโฮสต์ (คอมพิวเตอร์ที่เรียกใช้แอป Chrome) สำหรับข้อความขาเข้า (ระหว่างอุปกรณ์กับโฮสต์) โฮสต์ (เริ่มต้นแล้ว) ด้วยโค้ด JavaScript ของคุณ) ส่งข้อความที่มีการแจ้งว่าเป็น "ขาเข้า" กับอุปกรณ์ รายละเอียดของ ขึ้นอยู่กับอุปกรณ์ แต่โดยทั่วไปจะมี ข้อมูลบางอย่างที่จะระบุเกี่ยวกับสิ่งที่คุณจะขอ จากนั้น จากนั้นอุปกรณ์จะตอบสนองด้วยข้อมูลที่ขอ การตอบสนองของอุปกรณ์ได้รับการจัดการโดย Chrome และแสดงแบบไม่พร้อมกันไปยัง Callback ที่คุณระบุในวิธีการโอน สายโทรออก ข้อความ (host-to-device) คล้ายกัน แต่การตอบกลับไม่มีข้อมูลที่ส่งกลับมาจากอุปกรณ์

สำหรับแต่ละข้อความจากอุปกรณ์ การเรียกกลับที่ระบุจะได้รับออบเจ็กต์เหตุการณ์ที่มีฟังก์ชัน พร็อพเพอร์ตี้ต่อไปนี้

พร็อพเพอร์ตี้คำอธิบาย
resultsCode (จำนวนเต็ม)0 หมายถึงสำเร็จ ส่วนค่าอื่นๆ เป็นสัญญาณว่าไม่สำเร็จ ระบบ
อ่านสตริงข้อผิดพลาดจาก chrome.extension.lastError ได้เมื่อระบุ
ความล้มเหลว
ข้อมูล (arraybuffer)มีข้อมูลที่อุปกรณ์ส่งหากเป็นการโอนขาเข้า

ตัวอย่าง

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 เสมอ และไม่มี claimInterface ต้องระบุ วิธีการนี้ทำได้ง่ายและได้รับพารามิเตอร์สามรายการดังนี้

chrome.usb.controlTransfer(connectionHandle, transferInfo, transferCallback)
พารามิเตอร์ (ประเภท)คำอธิบาย
connectionHandleได้รับออบเจ็กต์ใน Callback usb.openDevice
transferInfoออบเจ็กต์พารามิเตอร์ที่มีค่าจากตารางด้านล่าง โปรดดูรายละเอียดในข้อมูลจำเพาะของโปรโตคอลอุปกรณ์ USB
transferCallback()เรียกใช้เมื่อการโอนเสร็จสมบูรณ์

ค่าสำหรับออบเจ็กต์ transferInfo:

ค่าคำอธิบาย
requestType (สตริง)"เวนเดอร์" "มาตรฐาน" "คลาส" หรือ "จองไว้"
ผู้รับ (สตริง)"อุปกรณ์" "อินเทอร์เฟซ" "ปลายทาง" หรือ "อื่นๆ"
ทิศทาง (สตริง)"ใน" หรือ "out" "ใน" จะใช้เพื่อแจ้งอุปกรณ์ว่า
ควรส่งข้อมูลไปยังโฮสต์ การสื่อสารทั้งหมดในบัส USB
เริ่มต้นโดยโฮสต์ ดังนั้นโปรดใช้ "in" การโอนเพื่อให้อุปกรณ์
ส่งข้อมูลกลับ
คำขอ (จำนวนเต็ม)กำหนดโดยโปรโตคอลของอุปกรณ์
ค่า (จำนวนเต็ม)กำหนดโดยโปรโตคอลของอุปกรณ์
ดัชนี (จำนวนเต็ม)กำหนดโดยโปรโตคอลของอุปกรณ์
ความยาว (จำนวนเต็ม)ใช้เมื่อทิศทางคือ "เข้า" เท่านั้น แจ้งอุปกรณ์ว่านี่คือปริมาณข้อมูลที่โฮสต์คาดว่าจะตอบสนอง
ข้อมูล (arraybuffer)โปรโตคอลของอุปกรณ์ต้องระบุเมื่อทิศทางคือ "ออก"

ตัวอย่าง

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

การโอนแบบ Ischronous เป็นการโอนทาง USB ประเภทที่ซับซ้อนที่สุด มักใช้กับสตรีม เช่น วิดีโอและเสียง ในการเริ่มต้นการโอนแบบอิสระ (ทั้งขาเข้าหรือขาออก) คุณต้อง ต้องใช้เมธอด usb.isochronousTransfer

chrome.usb.isochronousTransfer(connectionHandle, isochronousTransferInfo, transferCallback)
พารามิเตอร์คำอธิบาย
connectionHandleได้รับออบเจ็กต์ใน Callback usb.openDevice
isochronousTransferInfoออบเจ็กต์พารามิเตอร์ที่มีค่าในตารางด้านล่าง
transferCallback()เรียกใช้เมื่อการโอนเสร็จสมบูรณ์

ค่าสำหรับออบเจ็กต์ isochronousTransferInfo:

ค่าคำอธิบาย
TransferInfo (ออบเจ็กต์)วัตถุที่มีแอตทริบิวต์ต่อไปนี้:
คำสั่ง (สตริง): "in" หรือ "out".
ปลายทาง (จำนวนเต็ม): กำหนดโดยอุปกรณ์ โดยทั่วไปมักพบเครื่องมือนี้ได้จากเครื่องมือสำรวจ USB เช่น lsusb -v
ความยาว (จำนวนเต็ม): ใช้เมื่อทิศทางคือ "เข้า" เท่านั้น แจ้งอุปกรณ์ว่านี่คือปริมาณข้อมูลที่โฮสต์คาดว่าจะตอบสนอง
ไม่ควรเกิน packets × packetLength
ข้อมูล (arraybuffer): กำหนดโดยโปรโตคอลของอุปกรณ์ ใช้เมื่อทิศทางเป็น "ออก" เท่านั้น
แพ็กเก็ต (จำนวนเต็ม)จำนวนแพ็กเก็ตทั้งหมดที่คาดไว้ในการโอนนี้
แพ็กเก็ต Length (จำนวนเต็ม)ความยาวที่คาดไว้ของแต่ละแพ็กเก็ตในการโอนนี้

ตัวอย่าง

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 มีพารามิเตอร์ 3 ตัวดังนี้

chrome.usb.bulkTransfer(connectionHandle, transferInfo, transferCallback);
พารามิเตอร์คำอธิบาย
connectionHandleได้รับออบเจ็กต์ใน Callback usb.openDevice
transferInfoออบเจ็กต์พารามิเตอร์ที่มีค่าในตารางด้านล่าง
transferCallbackเรียกใช้เมื่อการโอนเสร็จสมบูรณ์

ค่าสำหรับออบเจ็กต์ transferInfo:

ค่าคำอธิบาย
ทิศทาง (สตริง)"ใน" หรือ "out"
ปลายทาง (จำนวนเต็ม)กำหนดโดยโปรโตคอลของอุปกรณ์
ความยาว (จำนวนเต็ม)ใช้เมื่อทิศทางคือ "เข้า" เท่านั้น แจ้งอุปกรณ์ว่านี่คือปริมาณข้อมูลที่โฮสต์คาดว่าจะตอบสนอง
ข้อมูล (ArrayBuffer)กำหนดโดยโปรโตคอลของอุปกรณ์ ใช้เมื่อทิศทางเป็น "ออก" เท่านั้น

ตัวอย่าง

var transferInfo = {
  "direction": "out",
  "endpoint": 1,
  "data": new Uint8Array([4, 8, 15, 16, 23, 42]).buffer
};

การโอน INTERRUPT

การโอนแบบขัดจังหวะจะใช้กับข้อมูลที่ละเอียดอ่อนซึ่งมีเวลาเพียงน้อยนิด เนื่องจากการสื่อสารผ่าน USB ทั้งหมด ที่โฮสต์เป็นผู้เริ่มต้น โค้ดโฮสต์มักจะสำรวจข้อมูลอุปกรณ์เป็นระยะๆ โดยส่งการรบกวน IN การโอนซึ่งจะทำให้อุปกรณ์ส่งข้อมูลกลับหากมีสิ่งใดอยู่ในคิวขัดจังหวะ (ดูแลรักษาโดยอุปกรณ์) usb.interruptTransfer มีพารามิเตอร์ 3 ตัว ได้แก่

chrome.usb.interruptTransfer(connectionHandle, transferInfo, transferCallback);
พารามิเตอร์คำอธิบาย
connectionHandleได้รับออบเจ็กต์ใน Callback usb.openDevice
transferInfoออบเจ็กต์พารามิเตอร์ที่มีค่าในตารางด้านล่าง
transferCallbackเรียกใช้เมื่อการโอนเสร็จสมบูรณ์ โปรดสังเกตว่า Callback นี้ไม่มีการตอบกลับของอุปกรณ์ วัตถุประสงค์ของ Callback คือเพื่อแจ้งโค้ดของคุณว่าคำขอโอนแบบอะซิงโครนัสได้รับการประมวลผลแล้ว

ค่าสำหรับออบเจ็กต์ transferInfo:

ค่าคำอธิบาย
ทิศทาง (สตริง)"ใน" หรือ "out"
ปลายทาง (จำนวนเต็ม)กำหนดโดยโปรโตคอลของอุปกรณ์
ความยาว (จำนวนเต็ม)ใช้เมื่อทิศทางคือ "เข้า" เท่านั้น แจ้งอุปกรณ์ว่านี่คือปริมาณข้อมูลที่โฮสต์คาดว่าจะตอบสนอง
ข้อมูล (ArrayBuffer)กำหนดโดยโปรโตคอลของอุปกรณ์ ใช้เมื่อทิศทางเป็น "ออก" เท่านั้น

ตัวอย่าง

var transferInfo = {
  "direction": "in",
  "endpoint": 1,
  "length": 2
};
chrome.usb.interruptTransfer(connectionHandle, transferInfo, optionalCallback);

คำเตือน

อุปกรณ์บางเครื่องอาจเข้าถึงผ่าน USB API ไม่ได้ โดยทั่วไป อุปกรณ์ไม่สามารถเข้าถึงได้เนื่องจาก เคอร์เนลของระบบปฏิบัติการหรือไดรเวอร์ในเครื่องจะตัดเคอร์เนลออกจากรหัสพื้นที่ของผู้ใช้ ใช้บ้าง เช่น อุปกรณ์ที่มีโปรไฟล์ HID ในระบบ OSX และไดรฟ์ปากกา USB

ในระบบ Linux ส่วนใหญ่ อุปกรณ์ USB จะแมปกับสิทธิ์แบบอ่านอย่างเดียวโดยค่าเริ่มต้น วิธีเปิด ผ่าน API นี้ ผู้ใช้ของคุณจะต้องมีสิทธิ์เขียนใน API นี้ด้วย วิธีแก้ไขง่ายๆ คือ ตั้งกฎ udev สร้างไฟล์ /etc/udev/rules.d/50-yourdevicename.rules ที่มีข้อมูลต่อไปนี้ เนื้อหา:

SUBSYSTEM=="usb", ATTR{idVendor}=="[yourdevicevendor]", MODE="0664", GROUP="plugdev"

จากนั้น ให้รีสตาร์ท Daemon ของ udev: service udev restart คุณตรวจสอบได้ว่าสิทธิ์ของอุปกรณ์ อย่างถูกต้องด้วยการทำตามขั้นตอนต่อไปนี้

  • เรียกใช้ lsusb เพื่อค้นหาหมายเลขรถประจำทางและอุปกรณ์
  • เรียกใช้ ls -al /dev/bus/usb/[bus]/[device] ไฟล์นี้ควรเป็นของกลุ่ม "Plugdev" และมี สิทธิ์การเขียนของกลุ่ม

แอปของคุณไม่สามารถดำเนินการนี้โดยอัตโนมัติได้เนื่องจากขั้นตอนนี้ต้องใช้การเข้าถึงระดับรูท คำแนะนำจากเรา คุณได้แจ้งวิธีการแก่ผู้ใช้ปลายทางและลิงก์ไปยังส่วนคำเตือนในหน้านี้ คำอธิบาย

ใน ChromeOS เพียงเรียก usb.requestAccess ตัวแทนที่ได้รับอนุญาตจะดำเนินการดังกล่าวให้คุณ