Межплатформенная связь USB с использованием ASP.NET Core

Обзор

Я перенес веб-приложение в .NET Core и обнаружил, что оно может взаимодействовать с микроконтроллером через USB при работе в Windows, но не при работе в Linux. Я пытаюсь решить:

  • Почему это так (это ошибка в библиотеках, которые я использую, или я неправильно настроил среду Linux?)

  • Как я могу решить или обойти это (альтернативные библиотеки, изменения в среде и т. д.)

Если кому-то удалось создать приложение на основе .NET Core, которое может обмениваться данными через USB независимо от платформы, я был бы очень признателен за ваш вклад.

Окружающая обстановка

Для справки в оставшейся части этого сообщения, вот некоторые подробности о моей текущей среде:

  • 64-разрядная хост-машина Windows 7
  • Версия Dotnet 1.0.0-preview2-003131
  • Докер версии 1.12.0, сборка 8eab29e
  • Docker Toolbox (кажется, v1.12.3)
  • VirtualBox v5.0.30 r112061

Подробности

Раньше у меня была веб-служба на основе .NET Framework, которую я использовал для управления микроконтроллером. Будучи основанным на .NET Framework, он был ограничен работой в Windows. Чтобы добиться межплатформенной поддержки, я начал портировать приложение на .NET Core. Эта задача теперь более или менее завершена — например, теперь я могу создавать и запускать свое приложение как службу Docker, что, как я полагаю, принесет большую пользу.

Мое приложение разделено на несколько проектов, но для целей этого поста я рассмотрю только два:

  • Проект веб-службы на основе ASP.NET Core, который адаптирует основные функции приложения для управления через веб-связь. 1 Он связывает все остальное вместе, и это то, что я на самом деле выполняю с помощью dotnet <<application.dll>>.

  • Проект Службы связи USB, который управляет связью с моим USB-устройством. 2 В настоящее время используется Библиотека CoreCompat.LibUsbDotNet (v2.2.8-r101), которая действует как кросс-платформенный адаптер C# поверх библиотек WinUSB и libusb в Windows и Unix соответственно. Этот проект распространяется как пакет Nuget, который используется веб-службой, и именно в этом заключается проблема.

Приложение работает нормально, когда я запускаю его непосредственно под Windows. Однако, если я попытаюсь запустить его на виртуальной машине Linux или в качестве службы Docker, веб-служба не сможет инициализироваться с ошибкой, жалующейся на то, что не удалось найти libusb-1.0 library. 3

Основываясь на этом сообщении об ошибке, я попытался проверить среду как виртуальных машин Linux, так и контейнеров Docker, на которых я пытался запустить приложение. 4

После подключения моего USB-устройства к виртуальной машине Docker и запуска контейнера на основе моего образа веб-приложения в привилегированном режиме я могу убедиться, что он видит мое USB-устройство:

root@19e8929e1814:/app# lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 002: ID 2b87:0001
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

Я также подтверждаю, что libusb-1.0 установлен 5, и проверяю, доступен ли он из кэша ldconfig:

root@19e8929e1814:/app# ldconfig -p | grep libusb
libusb-1.0.so.0 (libc6,x86-64) => /lib/x86_64-linux-gnu/libusb-1.0.so.0
libusb-1.0.so (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libusb-1.0.so
libusb-0.1.so.4 (libc6,x86-64) => /lib/x86_64-linux-gnu/libusb-0.1.so.4
libusb-0.1.so.4 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libusb-0.1.so.4

Исходя из этого, я не уверен, почему CoreCompat.LibUsbDotNet выдает исключение о невозможности найти libusb-1.0, и могу только предположить, что это ошибка в библиотеке.

Кому-нибудь удалось успешно использовать эту библиотеку для связи в среде Unix? В качестве альтернативы, нашел ли кто-нибудь другой способ связи с USB-устройствами, не зависящий от платформы, для приложения на основе .NET Core?

использованная литература

[1] project.json для проекта веб-сервиса

{
  "dependencies": {
    "<<Company>>.Communications.<<Product>>Usb": "0.4.9",
    "<<Company>>.<<Product>>Web.Core": {
      "target": "project"
    },
    "<<Company>>.<<Product>>WebComponentPackage": "0.4.9-beta0002",
    "Autofac": "4.2.1",
    "Common.Logging": "3.4.0-Beta2",
    "Microsoft.AspNetCore.Diagnostics": "1.1.0-preview1-final",
    "Microsoft.AspNetCore.Server.IISIntegration": "1.1.0-preview1-final",
    "Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
    "Microsoft.AspNetCore.StaticFiles": "1.1.0",
    "Microsoft.AspNetCore.WebSockets.Server": "0.1.0",
    "Microsoft.Extensions.DependencyModel": "1.1.0-preview1-001100",
    "Microsoft.Extensions.Logging.Console": "1.1.0",
    "Microsoft.NETCore.App": {
      "version": "1.1.0",
      "type": "platform"
    },
    "Serilog.Enrichers.Thread": "3.0.0",
    "Serilog.Sinks.Literate": "2.1.0-dev-00034",
    "Serilog.Sinks.RollingFile": "3.3.0",
    "System.Runtime.Loader": "4.3.0",
    "Thrower": "3.0.4"
  },

  "tools": {
  },

  "frameworks": {
    "netcoreapp1.1": {
      "imports": [
        "dotnet5.6",
        "portable-net45+win8"
      ]
    }
  },

  "buildOptions": {
    "emitEntryPoint": true,
    "preserveCompilationContext": true
  },

  "runtimeOptions": {
    "configProperties": {
      "System.GC.Server": true
    }
  },

  "publishOptions": {
    "include": [
      "wwwroot",
      "web.config"
    ]
  },

  "scripts": {
    "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
  }
}

[2] project.json для проекта связи через USB

{
  "version": "0.4.9-*",
  "description": "Provides a type of communication service that facilitates communication between .NET applications and <<Product>> over USB.",
  "authors": ["<<Author>>"],

  "dependencies": {
    "Microsoft.Composition": "1.0.30",
    "Microsoft.NETCore.Portable.Compatibility": "1.0.1",
    "Thrower": "3.0.4",
    "CoreCompat.LibUsbDotNet": "2.2.8-r101",
    "Common.Logging": "3.4.0-Beta2",
    "<<Company>>.Message": "0.4.3",
    "NETStandard.Library": "1.6.1",
    "<<Company>>.Communications.Core": "0.4.5",
    "Serilog": "2.3.0"
  },
  "packOptions": {
    "owners": ["<<Company>>"],
    "repository": {
      "type": "git",
      "url": "https://bitbucket.org/<<Company>>-dev/<<Product>>usb"
    }
  },
  "frameworks": {
    "netstandard1.4": {
      "imports": [ "dnxcore50", "portable-net45+win8" ]
    }
  },
  "buildOptions": {
    "xmlDoc": true
  }
}

[3] Исключение при сбое связи через USB

Unhandled Exception: System.DllNotFoundException: libusb-1.0 library not found.  This is often an indication that libusb-1.0 was installed to '/usr/local/lib' and
 mono.net is not looking for it there. To resolve this, add the path '/usr/local/lib' to '/etc/ld.so.conf' and run 'ldconfig' as root. (http://www.mono-project.co
m/DllNotFoundException) ---> System.DllNotFoundException: Unable to load DLL 'libusb-1.0.dll': The specified module could not be found.
 (Exception from HRESULT: 0x8007007E)
   at MonoLibUsb.MonoUsbApi.Init(IntPtr& pContext)
   at MonoLibUsb.MonoUsbSessionHandle..ctor()
   --- End of inner exception stack trace ---
   at MonoLibUsb.MonoUsbSessionHandle..ctor()
   at MonoLibUsb.MonoUsbEventHandler.Init(UnixNativeTimeval unixNativeTimeval)
   at MonoLibUsb.MonoUsbEventHandler.Init()
   at MonoLibUsb.MonoUsbApi.InitAndStart()
   at LibUsbDotNet.LudnMonoLibUsb.MonoUsbDevice.get_MonoUsbDeviceList()
   at LibUsbDotNet.Main.LegacyUsbRegistry.get_DeviceList()
   at LibUsbDotNet.UsbDevice.get_AllLibUsbDevices()
   at LibUsbDotNet.UsbDevice.get_AllDevices()
   at LibUsbDotNet.UsbDevice.OpenUsbDevice(Predicate`1 findDevicePredicate)
   at LibUsbDotNet.UsbDevice.OpenUsbDevice(UsbDeviceFinder usbDeviceFinder)
   at <<Company>>.Communications.<<Product>>Usb.UsbCommunicationService.Start()
   at <<Company>>.<<Product>>Web.Core.DeviceController.Initialize()
   at <<Company>>.<<Product>>Web.ServiceAdapters.WebSockets.Startup.ConfigureServices(IServiceCollection services)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.AspNetCore.Hosting.ConventionBasedStartup.ConfigureServices(IServiceCollection services)
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.EnsureApplicationServices()
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.Build()
   at <<Company>>.<<Product>>Web.ServiceAdapters.WebSockets.Program.Main(String[] args)

[4] Dockerfile веб-службы

FROM microsoft/aspnetcore:1.1.0
ENTRYPOINT ["dotnet", "bin/Debug/netcoreapp1.1/publish/<<Company>>.<<Product>>Web.ServiceAdapters.WebSockets.dll"]
ARG source=.
WORKDIR /app
EXPOSE 80
COPY $source .
RUN apt-get update
RUN apt-get install -y libusb-1.0-0-dev usbutils

[5] Вывод find / -name libusb* в контейнере Docker

root@19e8929e1814:/app# find / -name libusb*
/lib/x86_64-linux-gnu/libusb-1.0.so.0
/lib/x86_64-linux-gnu/libusb-1.0.so.0.1.0
/lib/x86_64-linux-gnu/libusb-0.1.so.4.4.4
/lib/x86_64-linux-gnu/libusb-0.1.so.4
/usr/lib/x86_64-linux-gnu/libusb-1.0.a
/usr/lib/x86_64-linux-gnu/pkgconfig/libusb-1.0.pc
/usr/lib/x86_64-linux-gnu/libusb-1.0.so
/usr/lib/x86_64-linux-gnu/libusb-0.1.so.4
/usr/include/libusb-1.0
/usr/include/libusb-1.0/libusb.h
/usr/share/doc/libusb-1.0-0
/usr/share/doc/libusb-1.0-doc
/usr/share/doc/libusb-1.0-doc/html/libusb_8h_source.html
/usr/share/doc/libusb-1.0-0-dev
/usr/share/doc/libusb-0.1-4
/usr/share/doc-base/libusb-1.0-doc
/var/lib/dpkg/info/libusb-1.0-0-dev:amd64.md5sums
/var/lib/dpkg/info/libusb-1.0-doc.list
/var/lib/dpkg/info/libusb-1.0-0:amd64.md5sums
/var/lib/dpkg/info/libusb-1.0-0:amd64.symbols
/var/lib/dpkg/info/libusb-1.0-0:amd64.shlibs
/var/lib/dpkg/info/libusb-1.0-0:amd64.list
/var/lib/dpkg/info/libusb-1.0-0:amd64.postrm
/var/lib/dpkg/info/libusb-1.0-0:amd64.postinst
/var/lib/dpkg/info/libusb-1.0-doc.md5sums
/var/lib/dpkg/info/libusb-1.0-0-dev:amd64.list
/var/lib/dpkg/info/libusb-0.1-4:amd64.postrm
/var/lib/dpkg/info/libusb-0.1-4:amd64.shlibs
/var/lib/dpkg/info/libusb-0.1-4:amd64.symbols
/var/lib/dpkg/info/libusb-0.1-4:amd64.postinst
/var/lib/dpkg/info/libusb-0.1-4:amd64.list
/var/lib/dpkg/info/libusb-0.1-4:amd64.md5sums

person Tagc    schedule 12.01.2017    source источник
comment
(1) Есть ли в библиотеке USB образцы? Вы можете запустить эти образцы, чтобы убедиться, что библиотека .NET работает в вашей среде Linux/Docker (или нет). И (2) - у вас есть netcoreapp1.0 в frameworks, но Microsoft.NETCore.App 1.1.0 в зависимостях.... Попробуйте привести их в соответствие с одной и той же версией.   -  person Dmitry    schedule 12.01.2017
comment
(1) Библиотека CoreCompat.LibUsbDotNet? Нет образцов, о которых я знаю. На самом деле все, что мне удалось найти для этой библиотеки, — это страница Nuget. Существуют образцы для зрелой версии LibUsbDotNet на базе .NET Framework, но в данном случае они мне не помогут. (2) Спасибо за указание на это, я исправил это.   -  person Tagc    schedule 12.01.2017


Ответы (1)


Свяжите фактическую общую библиотеку с расположением общих библиотек имеющейся у вас версии .Net Core. Мне удалось загрузить библиотеку, используя:

ln -s /lib/x86_64-linux-gnu/libusb-1.0.so.0 /opt/dotnet/shared/Microsoft.NETCore.App/1.1.0/libusb-1.0.dll

Я еще не получил список устройств, хотя.

См. эту проблему на Github.

person Fred    schedule 20.01.2017
comment
Серьезно, чувак, ты решил с помощью однострочной команды проблему, которая ставила меня в тупик несколько месяцев. Мне нужно было лишь внести небольшое изменение: /usr/share/dotnet/shared/Microsoft.NETCore.App/1.1.0/libusb-1.0.dll. Прежде чем я приму это и присужу вознаграждение, не могли бы вы кратко объяснить, почему создание этой символической ссылки работает на мою пользу и на пользу будущих читателей? - person Tagc; 20.01.2017
comment
Ладно, похоже, ты не вернешься, так что я просто приму это. - person Tagc; 23.01.2017