Flutter USB通信插件libusb_new的使用

Flutter USB通信插件libusb_new的使用

环境

  • Windows(10)
  • macOS
  • Linux(Ubuntu 18.04 LTS)

使用

查看示例

特性和错误

请在问题跟踪器上提交功能请求和错误报告。

构建

准备 llvm(9+)

  • Windows: winget install -e --id LLVM.LLVM
  • macOS: brew install llvm
  • Linux: sudo apt install libclang-10-dev

构建 libusb_xxx.dart

Windows/Linux:

pub run ffigen
mv lib/libusb_new.dart lib/libusb64.dart

修改 timevaltimeval64

macOS:

pub run ffigen
mv lib/libusb_new.dart lib/libusb32.dart

修改 timevaltimeval32

贡献

准备 libusb.h

https://github.com/libusb/libusb/releases 下载 xxx 版本并解压 libusb.h

准备 libusb-1.0 动态库

Windows:

https://github.com/libusb/libusb/releases 下载 xxx 版本并解压

copy libusb-1.0.23\MS64\dll\libusb-1.0.dll libusb-1.0\

macOS:

https://homebrew.bintray.com/bottles/libusb-1.0.23.catalina.bottle.tar.gz 下载 xxx 版本并解压

cp libusb/1.0.23/lib/libusb-1.0.dylib libusb-1.0/

Linux:

http://old.kali.org/kali/pool/main/libu/libusb-1.0/ 下载 xxx 版本并安装

cp /lib/x86_64-linux-gnu/libusb-1.0.so.0.xxx libusb-1.0/libusb-1.0.so

示例代码

main.dart

import 'dart:ffi';
import 'dart:io';
import 'package:ffi/ffi.dart' show calloc;
import 'package:libusb_new/libusb_new.dart';

// 加载动态库
final DynamicLibrary Function() loadLibrary = () {
  if (Platform.isWindows) {
    return DynamicLibrary.open(
        '${Directory.current.path}/libusb-1.0/libusb-1.0.dll');
  }
  if (Platform.isMacOS) {
    return DynamicLibrary.open(
        '${Directory.current.path}/libusb-1.0/libusb-1.0.dylib');
  } else if (Platform.isLinux) {
    return DynamicLibrary.open(
        '${Directory.current.path}/libusb-1.0/libusb-1.0.so');
  }
  throw 'libusb dynamic library not found';
};

// 初始化 libusb
final libusb = Libusb(loadLibrary());

void main(List<String> arguments) {
  // 初始化 libusb
  var initResult = libusb.libusb_init(nullptr);
  if (initResult < 0) {
    return;
  }

  // 获取设备列表指针
  var deviceListPtr = calloc<Pointer<Pointer<libusb_device>>>();
  listdevs(deviceListPtr);
  calloc.free(deviceListPtr);

  // 清理
  libusb.libusb_exit(nullptr);
}

// 列出设备
void listdevs(Pointer<Pointer<Pointer<libusb_device>>> deviceListPtr) {
  // 获取设备数量
  var count = libusb.libusb_get_device_list(nullptr, deviceListPtr);
  if (count < 0) {
    return;
  }

  // 获取设备列表
  var deviceList = deviceListPtr.value;
  printDevs(deviceList);
  libusb.libusb_free_device_list(deviceList, 1);
}

// 打印设备信息
void printDevs(Pointer<Pointer<libusb_device>> deviceList) {
  // 分配内存用于存储设备描述符
  var descPtr = calloc<libusb_device_descriptor>();
  var path = calloc<Uint8>(8);

  // 遍历设备列表
  for (var i = 0; deviceList[i] != nullptr; i++) {
    var dev = deviceList[i];
    // 获取设备描述符
    var result = libusb.libusb_get_device_descriptor(dev, descPtr);
    if (result < 0) continue;

    // 解析描述符
    var desc = descPtr.ref;
    var idVendor = desc.idVendor.toRadixString(16).padLeft(4, '0');
    var idProduct = desc.idProduct.toRadixString(16).padLeft(4, '0');
    var bus = libusb.libusb_get_bus_number(dev).toRadixString(16);
    var addr = libusb.libusb_get_device_address(dev).toRadixString(16);
    print('$idVendor:$idProduct (bus $bus, device $addr)');

    // 获取端口信息
    var portCount = libusb.libusb_get_port_numbers(dev, path, 8);
    if (portCount > 0) {
      var hexList = path
          .asTypedList(portCount)
          .map((e) => e.toRadixString(16).padLeft(2, '0'))
          .join(':');
      print(' path: $hexList');
    }
  }

  // 释放内存
  calloc.free(descPtr);
  calloc.free(path);
}

更多关于Flutter USB通信插件libusb_new的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter USB通信插件libusb_new的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter应用中使用libusb_new插件进行USB通信的代码案例。这个插件允许Flutter应用与连接的USB设备进行通信。需要注意的是,libusb_new是一个较为底层的库,使用它需要对USB通信有一定的了解。

首先,你需要在pubspec.yaml文件中添加libusb_new依赖:

dependencies:
  flutter:
    sdk: flutter
  libusb_new: ^0.x.x  # 请替换为最新版本号

然后运行flutter pub get来安装依赖。

接下来是一个简单的Flutter应用示例,展示如何使用libusb_new插件来列出连接的USB设备并尝试打开一个设备进行通信。

import 'package:flutter/material.dart';
import 'package:libusb_new/libusb_new.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  List<UsbDevice> _devices = [];
  UsbDevice? _selectedDevice;

  @override
  void initState() {
    super.initState();
    _listDevices();
  }

  Future<void> _listDevices() async {
    final libusbContext = await Libusb.init();
    try {
      final devices = await libusbContext.listDevices();
      setState(() {
        _devices = devices;
      });
    } finally {
      await libusbContext.exit();
    }
  }

  Future<void> _openDevice(UsbDevice device) async {
    final libusbContext = await Libusb.init();
    try {
      final handle = await libusbContext.openDeviceWithVidPid(device.vendorId, device.productId);
      // 在这里你可以进行进一步的通信操作,例如读取/写入数据
      // 例如: await handle.claimInterface(0); // 假设接口号为0
      //      await handle.bulkTransfer(...); // 执行数据传输
      
      // 示例: 打印设备描述信息
      print('Opened device: ${device.description}');
      setState(() {
        _selectedDevice = device;
      });
    } catch (e) {
      print('Failed to open device: $e');
    } finally {
      await libusbContext.exit();
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter USB Communication'),
        ),
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            children: [
              Text('Connected USB Devices:'),
              SizedBox(height: 16.0),
              Expanded(
                child: ListView.builder(
                  itemCount: _devices.length,
                  itemBuilder: (context, index) {
                    final device = _devices[index];
                    return ListTile(
                      title: Text(device.description ?? 'Unknown Device'),
                      trailing: Icon(Icons.arrow_forward),
                      onTap: () => _openDevice(device),
                    );
                  },
                ),
              ),
              if (_selectedDevice != null)
                Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    SizedBox(height: 16.0),
                    Text('Selected Device: ${_selectedDevice?.description ?? 'None'}'),
                    // 这里可以添加更多与已打开设备交互的UI元素
                  ],
                ),
            ],
          ),
        ),
      ),
    );
  }
}

注意事项:

  1. 权限:在Android上,你可能需要在AndroidManifest.xml中添加USB权限,并处理运行时权限请求。
  2. 平台特定代码libusb_new是一个跨平台库,但某些功能(如处理权限)可能需要平台特定的代码。
  3. 错误处理:示例代码中的错误处理较为简单,实际应用中可能需要更复杂的错误处理和恢复机制。
  4. 设备兼容性:确保你的设备支持libusb,并且驱动已经正确安装。

这个示例仅展示了如何列出设备和打开设备。实际的通信操作(如读取/写入数据)需要根据你的具体设备和通信协议来实现。

回到顶部