دستگاه های USB

این سند نحوه استفاده از USB API برای برقراری ارتباط با دستگاه های USB را توضیح می دهد. برخی از دستگاه‌ها از طریق USB API قابل دسترسی نیستند (برای جزئیات به بخش هشدارها در زیر مراجعه کنید). Chrome Apps همچنین می‌تواند به دستگاه‌های سریال و بلوتوث متصل شود.

برای اطلاعات پس زمینه در مورد USB، به مشخصات رسمی USB مراجعه کنید. USB in a NutShell یک دوره آموزشی خرابی معقول است که ممکن است برای شما مفید باشد.

نیاز آشکار

USB API به مجوز "usb" در فایل مانیفست نیاز دارد:

"permissions": [
  "usb"
]

علاوه بر این، برای جلوگیری از انگشت نگاری ، باید تمام انواع دستگاه هایی که می خواهید به آنها دسترسی داشته باشید را در فایل مانیفست اعلام کنید. هر نوع دستگاه USB مربوط به یک جفت شناسه فروشنده/شناسه محصول (VID/PID) است. می توانید از usb.getDevices برای شمارش دستگاه ها بر اساس جفت VID/PID آنها استفاده کنید.

همانطور که در مثال زیر نشان داده شده است، باید جفت‌های VID/PID را برای هر نوع دستگاهی که می‌خواهید تحت مجوز usbDevices در فایل مانیفست برنامه خود استفاده کنید، اعلام کنید:

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

از Chrome 57 ، برای برنامه‌هایی که به‌عنوان برنامه‌های کیوسک ChromeOS اجرا می‌شوند، الزام برای اعلام همه انواع دستگاه در مانیفست برنامه کاهش یافته است. برای برنامه‌های کیوسک، می‌توانید از ویژگی مجوز interfaceClass برای درخواست اجازه دسترسی به دستگاه‌های USB استفاده کنید که:

  • یک رابط USB از یک کلاس رابط خاص را پیاده سازی کنید
  • یک کلاس دستگاه USB خاص داشته باشید

برای مثال، مجوز usbDevices زیر به یک برنامه اجازه دسترسی به همه دستگاه‌های USB را می‌دهد که رابط چاپگر را اجرا می‌کنند (کد کلاس رابط ۷)، و به دستگاه‌های هاب USB (کد کلاس دستگاه ۹):

"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 . ویژگی دستگاه یک شناسه پایدار برای یک دستگاه متصل است. تا زمانی که دستگاه از برق جدا نشود تغییر نمی کند. جزئیات شناسه مبهم است و ممکن است تغییر کند. به نوع فعلی آن تکیه نکنید.
اگر دستگاهی پیدا نشد، آرایه خالی خواهد بود.

مثال:

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» پرچم‌گذاری شده است به دستگاه ارسال می‌کند. جزئیات پیام به دستگاه بستگی دارد، اما معمولاً مشخصه ای از آنچه شما از آن درخواست می کنید دارد. سپس دستگاه با داده های درخواستی پاسخ می دهد. پاسخ دستگاه توسط کروم مدیریت می شود و به صورت ناهمزمان به پاسخی که در روش انتقال مشخص کرده اید تحویل داده می شود. پیام خروجی (میزبان به دستگاه) مشابه است، اما پاسخ حاوی داده‌های برگردانده شده از دستگاه نیست.

برای هر پیام از دستگاه، پاسخ تماس مشخص شده یک شی رویداد با ویژگی های زیر دریافت می کند:

اموال توضیحات
نتیجه کد (عدد صحیح) 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 به/خوانده می شود و هیچ نیازی به applicationInterface نیست. این روش ساده است و سه پارامتر را دریافت می کند:

chrome.usb.controlTransfer(connectionHandle, transferInfo, transferCallback)
پارامتر (انواع) توضیحات
اتصال هندل شی در پاسخ به تماس usb.openDevice دریافت شد.
انتقال اطلاعات شی پارامتر با مقادیر جدول زیر. مشخصات پروتکل دستگاه USB خود را برای جزئیات بررسی کنید.
transferCallback() پس از اتمام انتقال فراخوانی می شود.

مقادیر برای شی transferInfo :

ارزش توضیحات
نوع درخواست (رشته) «فروشنده»، «استاندارد»، «کلاس» یا «رزرو شده».
گیرنده (رشته) «دستگاه»، «رابط»، «نقطه پایانی» یا «سایر».
جهت (رشته) "در" یا "خارج". جهت "در" برای اطلاع دادن به دستگاه استفاده می شود که
باید اطلاعات را برای میزبان ارسال کند. تمام ارتباطات روی 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);

نقل و انتقالات ایزوکرون

انتقال هم زمان پیچیده ترین نوع انتقال USB است. آنها معمولا برای جریان داده ها، مانند ویدئو و صدا استفاده می شوند. برای شروع یک انتقال هم زمان (اعم از ورودی یا خروجی)، باید از روش usb.isochronousTransfer استفاده کنید:

chrome.usb.isochronousTransfer(connectionHandle, isochronousTransferInfo, transferCallback)
پارامتر توضیحات
اتصال هندل شی در پاسخ به تماس usb.openDevice دریافت شد.
اطلاعات انتقال هم زمان شی پارامتر با مقادیر جدول زیر.
transferCallback() پس از اتمام انتقال فراخوانی می شود.

مقادیر برای شی isochronousTransferInfo :

ارزش توضیحات
انتقال اطلاعات (شیء) یک شی با ویژگی های زیر:
جهت (رشته): "در" یا "خارج".
نقطه پایانی (عدد صحیح): توسط دستگاه شما تعریف شده است. معمولاً می توان با نگاه کردن به یک ابزار instrospection USB مانند lsusb -v پیدا کرد
طول (عدد صحیح): فقط زمانی استفاده می شود که جهت "در" باشد. به دستگاه اطلاع می دهد که این مقدار داده ای است که میزبان در پاسخ انتظار دارد.
باید حداقل packets × packetLength باشد.
داده (آرایه بافر): توسط پروتکل دستگاه شما تعریف شده است. فقط زمانی استفاده می شود که جهت "خارج" باشد.
بسته ها (عدد صحیح) تعداد کل بسته های مورد انتظار در این انتقال.
طول بسته (عدد صحیح) طول مورد انتظار هر بسته در این انتقال.

مثال:

var transferInfo = {
  "direction": "in",
  "endpoint": 1,
  "length": 2560
};

var isoTransferInfo = {
  "transferInfo": transferInfo,
  "packets": 20,
  "packetLength": 128
};

chrome.usb.isochronousTransfer(connectionHandle, isoTransferInfo, optionalCallback);

نقل و انتقالات انبوه

انتقال انبوه معمولاً برای انتقال حجم زیادی از داده های غیر حساس به زمان به روشی قابل اعتماد استفاده می شود. usb.bulkTransfer دارای سه پارامتر است:

chrome.usb.bulkTransfer(connectionHandle, transferInfo, transferCallback);
پارامتر توضیحات
اتصال هندل شی در پاسخ به تماس usb.openDevice دریافت شد.
انتقال اطلاعات شی پارامتر با مقادیر جدول زیر.
انتقال تماس برگشتی پس از اتمام انتقال فراخوانی می شود.

مقادیر برای شی transferInfo :

ارزش توضیحات
جهت (رشته) "در" یا "خارج".
نقطه پایانی (عدد صحیح) توسط پروتکل دستگاه شما تعریف شده است.
طول (عدد صحیح) فقط زمانی استفاده می شود که جهت "in" باشد. به دستگاه اطلاع می دهد که این مقدار داده ای است که میزبان در پاسخ انتظار دارد.
داده (ArrayBuffer) توسط پروتکل دستگاه شما تعریف شده است. فقط زمانی استفاده می شود که جهت "خارج" باشد.

مثال:

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

نقل و انتقالات را قطع کنید

انتقال وقفه به مقدار کمی از داده های حساس به زمان استفاده می شود. از آنجایی که تمام ارتباطات USB توسط میزبان آغاز می‌شود، کد میزبان معمولاً دستگاه را به صورت دوره‌ای نظرسنجی می‌کند و انتقالات IN وقفه‌ای را ارسال می‌کند که باعث می‌شود دستگاه در صورت وجود چیزی در صف وقفه (که توسط دستگاه نگهداری می‌شود) داده‌ها را پس بگیرد. usb.interruptTransfer دارای سه پارامتر است:

chrome.usb.interruptTransfer(connectionHandle, transferInfo, transferCallback);
پارامتر توضیحات
اتصال هندل شی در پاسخ به تماس usb.openDevice دریافت شد.
انتقال اطلاعات شی پارامتر با مقادیر جدول زیر.
انتقال تماس برگشتی پس از اتمام انتقال فراخوانی می شود. توجه داشته باشید که این پاسخ تماس شامل پاسخ دستگاه نیست. هدف از پاسخ به تماس این است که به کد شما اطلاع دهد که درخواست‌های انتقال ناهمزمان پردازش شده است.

مقادیر برای شی transferInfo :

ارزش توضیحات
جهت (رشته) "در" یا "خارج".
نقطه پایانی (عدد صحیح) توسط پروتکل دستگاه شما تعریف شده است.
طول (عدد صحیح) فقط زمانی استفاده می شود که جهت "در" باشد. به دستگاه اطلاع می دهد که این مقدار داده ای است که میزبان در پاسخ انتظار دارد.
داده (ArrayBuffer) توسط پروتکل دستگاه شما تعریف شده است. فقط زمانی استفاده می شود که جهت "خارج" باشد.

مثال:

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

هشدارها

همه دستگاه ها از طریق USB API قابل دسترسی نیستند. به طور کلی، دستگاه ها قابل دسترسی نیستند زیرا هسته سیستم عامل یا یک درایور بومی آنها را از کد فضای کاربر دور نگه می دارد. برخی از نمونه ها دستگاه هایی با نمایه های HID در سیستم های OSX و درایوهای قلم USB هستند.

در اکثر سیستم های لینوکس، دستگاه های 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" باشد و دارای مجوزهای نوشتن گروهی باشد.

برنامه شما نمی تواند این کار را به صورت خودکار انجام دهد زیرا این روش به دسترسی روت نیاز دارد. توصیه می کنیم دستورالعمل هایی را به کاربران نهایی ارائه دهید و برای توضیح به بخش هشدارها در این صفحه پیوند دهید.

در ChromeOS، فقط با usb.requestAccess تماس بگیرید. کارگزار مجوز این کار را برای شما انجام می دهد.