poll static method

Future<String> poll(
  1. int timeout,
  2. bool probeMagic
)

Try to poll a WebUSB device according to our protocol.

Implementation

static Future<String> poll(int timeout, bool probeMagic) async {
  // request WebUSB device with custom classcode
  if (!_deviceAvailable()) {
    var devicePromise = _USB.requestDevice(
      _USBDeviceRequestOptions(
        filters: [
          _USBDeviceFilter(classCode: USB_CLASS_CODE_VENDOR_SPECIFIC),
        ].toJS,
      ),
    );
    var device = await devicePromise.toDart;
    try {
      var openPromise = device.callMethod('open'.toJS) as JSPromise;
      await openPromise.toDart
          .then(
            (_) =>
                (device.callMethod('claimInterface'.toJS, 1.toJS)
                        as JSPromise)
                    .toDart,
          )
          .timeout(Duration(milliseconds: timeout));
      _device = device;
      _USB.ondisconnect = () {
        _device = null;
        onDisconnect?.call();
      }.toJS;
      log.info("WebUSB device opened", _device);
    } on TimeoutException catch (_) {
      log.severe("Polling tag timeout");
      throw PlatformException(code: "408", message: "Polling tag timeout");
    } on Exception catch (e) {
      log.severe("Poll error", e);
      throw PlatformException(
        code: "500",
        message: "WebUSB API error",
        details: e,
      );
    }

    if (probeMagic) {
      try {
        // PROBE request
        var promise =
            device.callMethod(
                  'controlTransferIn'.toJS,
                  _USBControlTransferParameters(
                    requestType: 'vendor',
                    recipient: 'interface',
                    request: 0xff,
                    value: 0,
                    index: 1,
                  ),
                  1.toJS,
                )
                as JSPromise<JSObject>;
        var resp = await promise.toDart;
        if (resp.getProperty<JSString>('status'.toJS).toDart == 'stalled') {
          throw PlatformException(
            code: "500",
            message: "Device error: transfer stalled",
          );
        }
        var result = _getDataBufferFromResponse(resp);
        if (result.length < USB_PROBE_MAGIC.length ||
            result.sublist(0, USB_PROBE_MAGIC.length) !=
                Uint8List.fromList(USB_PROBE_MAGIC.codeUnits)) {
          throw PlatformException(
            code: "500",
            message:
                "Device error: invalid probe response: ${hex.encode(result)}, should begin with $USB_PROBE_MAGIC",
          );
        }
        customProbeData = hex.encode(result.sublist(USB_PROBE_MAGIC.length));
      } on Exception catch (e) {
        log.severe("Probe error", e);
        throw PlatformException(
          code: "500",
          message: "WebUSB API error",
          details: e,
        );
      }
    } else {
      customProbeData = "";
    }
  }
  assert(_device != null);
  // get VID & PID
  var vendorId = _device!.getProperty<JSNumber>('vendorId'.toJS).toDartInt;
  var productId = _device!.getProperty<JSNumber>('productId'.toJS).toDartInt;
  String id =
      '${vendorId.toRadixString(16).padLeft(4, '0')}:${productId.toRadixString(16).padLeft(4, '0')}';
  return json.encode({
    'type': 'webusb',
    'id': id,
    'standard': 'nfc-im-webusb-protocol',
    'customProbeData': customProbeData,
  });
}