Wykrywanie zmian sprzetu na róznych platformach, jedna biblioteka

0

Kolejny krok w migracji Pascal -> C++
Do wykrywania podłączenia urządzenia USB ( nie jest to pamięć USB ) na Linux używałem udev, na windows WM_devicechange
Chciałbym ten mechanizm ogarnąć jako multi platformowa bibliotekę gotowa do wykorzystania na razie Windows i Linux, może w przyszłości Android jabłkowe systemy

Pytania:

  • Czy może już jest jakaś gotowa biblioteka do wykorzystania ? Bo mi się nie udało znaleźć
  • Jeżeli nie ma gotowego rozwiania to jak tworzyć takie multi-platformowe rozwiania ? Może jakieś przykłady na github kodu który jest multi platformowy, niezbyt skomplikowany i jest godny naśladowania ?
2

Ostatnim razem jak się orientowałem to FTDI robiło drajwery dla windowsa i linuksa, tak więc mógłbyś użyć ftd2xx. Aczkolwiek sam używałem tylko pod windowsem.

EDIT

to jak tworzyć takie multi-platformowe rozwiania ?

Piszesz natywnie pod wspólnym interfejsem i potem przełączasz to makrami w trakcie kompilacji. Np. jakbyś implementował swoje utility do obsługi systemu plików.

my_filesystem.h

#include <string>

#ifdef __unix__

#include <unistd.h>

inline bool removeFile(const std::string &filePath)
{
 return unlink(filePath.c_str()) == 0; 
}

#endif

#ifdef _WIN32

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

inline bool removeFile(const std::string &filePath)
{
  return DeleteFileA(filePath.c_str()) != 0;
}

#endif

Przy większej ilości kodu to jednak słabo wygląda i można zrobić nagłówek, który będzie niezależny od platformy a potem osobne implementacje stylu my_windows_filesystem.cpp i przełączać się między tymi plikami z poziomu systemu budowania.

3

Możesz zobaczyć libusb, to jest C co prawda ale zawrapować w C++ będzie łatwo.

Z doświadczenia natomiast: korzystniej było zrobić wspólną fasadę i potem stosownie podmieniać kod implementacji w zależności od platformy niż korzystać z jednej libki do wsparcia USB (chociażby z racji tego że libusb trzeba na Win doinstalowywać).

0

Koncept na razie taki

#ifndef _deviceconnectdisconnect_H
#define _deviceconnectdisconnect_H

// rodzaj zdarzenia 
enum device_event
{
  device_event_disconnect,
  device_event_connect
};

// Filtr urzadzenia 
// Linux: udev
//      str1 = "usb"            klasa 
//      str2 = "usb_interface"  rodzaj
//      str3 = "403/601f/0"     identyfikator sprzetu 
// Windows: RegisterDeviceNotification + WM_DEVICECHANGE
//      str1 = GUID np. {d1e8fe6a-ab75-4d9e-97d2-06fa22c7736c}
// TCP/IP
//      str1 = url
struct device_filter
{
    const char *str1;
    const char *str2;
    const char *str3;
};

typedef int (*CallbackAfterDeviceChange)(device_event, const char *); // ,

class DeviceConnectDisconnect
{
  private:
    device_filter m_filter{0};
    CallbackAfterDeviceChange _callback{0};
  public:
    static void assign_callback(CallbackAfterDeviceChange p_callback);
    static void assign_filter(device_filter filter);
    static void start();
    static void stop();
};


#endif

w implementacji juz pojawiaja sie #ifdef

#include "deviceconnectdisconnect.h"

#if defined(_WIN32)
#include "deviceconnectdisconnect_win.h"
#else
#include "deviceconnectdisconnect_udev.h"
#endif


void DeviceConnectDisconnect::assign_callback(CallbackAfterDeviceChange p_callback)
{
#if defined(_WIN32)
    DeviceConnectDisconnect_win::assign_callback(p_callback);
#else
    DeviceConnectDisconnect_udev::assign_callback(p_callback);
#endif
    return;
}

void DeviceConnectDisconnect::assign_filter(device_filter filter)
{
#if defined(_WIN32)
    DeviceConnectDisconnect_win::assign_filter(filter);
#else
    DeviceConnectDisconnect_udev::assign_filter(filter);
#endif
    return;
}

void DeviceConnectDisconnect::start()
{
#if defined(_WIN32)
    DeviceConnectDisconnect_win::start();
#else
    DeviceConnectDisconnect_udev::start();
#endif
    return;
}

void DeviceConnectDisconnect::stop()
{
#if defined(_WIN32)
    DeviceConnectDisconnect_win::stop();
#else
    DeviceConnectDisconnect_udev::stop();
#endif
    return;
}

Wersja linux-owa działa

utykam na Windows bo mam problemy z utworzeniem niewidocznego okna do którego trafia komunikaty WM_DEVICECHANGE w Delphi jest prosta funkcja AllocateHWnd

2

Osobiście polecam osobne pliki deviceconnectdisconnect_win.cpp i deviceconnectdisconnect_posix.cpp albo coś podobnego, i dołączanie zależne do projektu. Inaczej będzie bardzo nieczytelnie przez ifdefozę - już jest.

0

https://github.com/mariuszmaximus/deviceconnectdisconnect
Wersja na Windows ma delikatny feler:
watek nie che się zakończyć , wisi na funkcji "messageReceiver" , bo tam jest nieskończona pętla która nie wiem jak przerwać

W Delphi to samo było zrobione w nieblokujący sposób w jakiś magiczny sposób funkcją MakeObjectInstance

Allocates a block of memory to be used by an instance of a class.

Call MakeObjectInstance to obtain memory to associate with an instance of a class.

This can be particularly useful when using classes that do not have a Windows handle but need to receive Windows Messages. MakeObjectInstance registers a message handling function into the Windows Message Processing Chain, effectively trapping the Windows Messages. This way the messages sent to the parent window are redirected and processed by the correct function.

Chciałem to zaimplementować w C++ ale utknąłem na funkcjach napisanych w asemblerze ;(

Wersja Windows inspirowana przykładami z google najbardziej projektem https://github.com/proxytype/usbnotifier.git

Z dziwnych rzeczy:
aby w cmake użyć konstrukcji "aux_source_directory" (dodaj wszystkie źródła z folderu) pliki które działają tylko na niektórych platformach maja dodatkowe IFDEF ELSE ENDIF , kompilator widzi pusty plik jak nie zgadza się platforma

NA windows nie działa re-enumeracja USB , jak podłącze elektronikę do zasilania to mam CONECT/DISCONNECT/CONNECT , tutaj trzeba jakiś timer

0

w ramach treningu cmake dodałem jeszcze opcje integracji biblioteki jako zewnetrzny moduł ładowany do większej całości
czyli w cmake wystarczy

add_subdirectory(".../deviceconnectdisconnect")
target_link_libraries( ... deviceconnectdisconnect)

i nic więcej nie trzeba ustawac w projekcie (żadnych bibliotek, includów ostawiać itp )
w kodzie tylko

#include "deviceconnectdisconnect.h"
DeviceConnectDisconnect::start()

Piękna sprawa

1

Tak dumam nad tym wątkiem.

Nie tylko sama detekcja (protokół niskopoziomowy) jest zuuupełnie inny, ale mam obawy, czy istnieje wspólna nad wszystkimi odnogami kodu abstrakcja.
Tu rzecz przebiega w czterech fazach/poziomach/enumach tam w dwóch, tu możliwe jest cofanie, tam nie (przykładowo), tu jest plikiem, tam, nie jest ...

Oczywiście, przy pewnym wysiłku zawsze wymyśli jakąś abstrakcję "wspólny mianownik", ale obawiam się czy nie przez wykastrowanie ważnych ficzerów

0

Linux vs Windows rzeczywiście maja zupełnie inne podejście do wykrywania zmian urządzeń
ale wspólne jest to że musisz podać jakieś kryteria po jakich szukasz to może być VID/PID albo jakiś GUID.
Link do biblioteki w komentarzu pierwszego postu

1 użytkowników online, w tym zalogowanych: 0, gości: 1