Skip to content

Commit

Permalink
Merge pull request #97 from norberttak/hid-init-modifications
Browse files Browse the repository at this point in the history
Handle multiple instance of the same VID/PID devices
  • Loading branch information
norberttak authored Apr 1, 2024
2 parents 551bcbd + a1de060 commit db0f7d4
Show file tree
Hide file tree
Showing 14 changed files with 234 additions and 65 deletions.
48 changes: 37 additions & 11 deletions src/core/UsbHidDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,19 +114,45 @@ int UsbHidDevice::write_device(unsigned char* buf, int length)

int UsbHidDevice::connect()
{
device_handle = hid_open(vid, pid, NULL);
if (!device_handle) {
Logger(TLogLevel::logERROR) << "error opening hid device vid=" << vid << " pid=" << pid << " reason=" << hidapi_error(NULL) << std::endl;
return EXIT_FAILURE;
}
ref_count++;
struct hid_device_info *dev_info = hid_enumerate(vid, pid);
if (!dev_info) {
Logger(TLogLevel::logERROR) << "error enumerating hid device with vid=" << vid << " pid=" << pid << " reason=" << hidapi_error(NULL) << std::endl;
hid_free_enumeration(dev_info);
return EXIT_FAILURE;
}

if (hid_set_nonblocking(device_handle, 1) == -1) {
Logger(TLogLevel::logERROR) << "error in hid_set_nonblocking vid=" << vid << " pid=" << pid << " reason=" << hidapi_error(device_handle) << std::endl;
return EXIT_FAILURE;
}
device_handle = hid_open_path(dev_info->path);
if (!device_handle) {
Logger(TLogLevel::logERROR) << "error opening hid device vid=" << vid << " pid=" << pid << " reason=" << hidapi_error(NULL) << std::endl;
hid_free_enumeration(dev_info);
return EXIT_FAILURE;
}

if (hid_set_nonblocking(device_handle, 1) == -1) {
Logger(TLogLevel::logERROR) << "error in hid_set_nonblocking vid=" << vid << " pid=" << pid << " reason=" << hidapi_error(device_handle) << std::endl;
hid_free_enumeration(dev_info);
return EXIT_FAILURE;
}

ref_count++;

if (dev_info->next) {
Logger(TLogLevel::logWARNING) << "found more than one device with vid=" << vid << " pid=" << pid << " Only the first device is used now" << std::endl;
}

Logger(TLogLevel::logDEBUG) << "device opened: vid=" << vid << " pid=" << pid << std::endl;

hid_free_enumeration(dev_info);

return EXIT_SUCCESS;
}

int UsbHidDevice::connect(hid_device* _device_handle)
{
ref_count++;
device_handle = _device_handle;
Logger(TLogLevel::logDEBUG) << "device connect: vid=" << vid << " pid=" << pid << std::endl;

Logger(TLogLevel::logDEBUG) << "UsbHidDevice connect successful. vid=" << vid << " pid=" << pid << std::endl;
return EXIT_SUCCESS;
}

Expand Down
1 change: 1 addition & 0 deletions src/core/UsbHidDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class UsbHidDevice : public Device
unsigned short vid = 0;
unsigned short pid = 0;
int connect();
int connect(hid_device* _device_handle);
virtual void start();
virtual void stop(int time_out);
void release();
Expand Down
103 changes: 53 additions & 50 deletions src/core/XPanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,29 +127,29 @@ PLUGIN_API int XPluginEnable(void)

float flight_loop_callback(float, float, int, void*)
{
for (const auto &it : config.device_configs)
for (const auto& it : config.device_configs)
{
// check and set LED states
for (const auto &triggers : it.light_triggers)
for (const auto& triggers : it.light_triggers)
{
for (auto &trigger : triggers.second)
for (auto& trigger : triggers.second)
{
trigger->evaluate_and_store_action();
}
}
// check and set 7 segment display states
for (const auto &display : it.multi_displays)
for (const auto& display : it.multi_displays)
{
display.second->evaluate_and_store_dataref_value();
}

for (const auto &display : it.generic_displays)
for (const auto& display : it.generic_displays)
{
display.second->evaluate_and_store_dataref_value();
}

// update the FIP devices
for (auto &screen : it.fip_screens)
for (auto& screen : it.fip_screens)
{
screen.second->evaluate_and_store_screen_action();
}
Expand Down Expand Up @@ -183,7 +183,7 @@ void stop_and_clear_xpanel_plugin()
XPLMUnregisterFlightLoopCallback(flight_loop_callback, NULL);
LuaHelper::get_instace()->close();

for (auto &dev : devices)
for (auto& dev : devices)
{
if (dev != NULL)
{
Expand Down Expand Up @@ -226,6 +226,39 @@ extern std::filesystem::path get_plugin_path()
return plugin_path;
}

template <class T>
int enumerate_and_add_hid_devices(DeviceConfiguration& it)
{
Device* device;
struct hid_device_info* dev_info;
struct hid_device_info* dev_info_first;

dev_info = hid_enumerate(it.vid, it.pid);
if (!dev_info) {
Logger(TLogLevel::logERROR) << "error enumerating hid device with vid=" << it.vid << " pid=" << it.pid << std::endl;
hid_free_enumeration(dev_info);
return EXIT_FAILURE;
}
dev_info_first = dev_info;
do
{
Logger(TLogLevel::logDEBUG) << "add new panel device. vid =" << it.vid << " pid = " << it.pid << std::endl;
device = new T(it);
devices.push_back(device);

hid_device* hid_dev = hid_open_path(dev_info->path);
hid_set_nonblocking(hid_dev, 1);
((T*)device)->connect(hid_dev);
device->start();
device->thread_handle = new std::thread(&T::thread_func, (T*)device);
LuaHelper::get_instace()->register_hid_device((UsbHidDevice*)device);
dev_info = dev_info->next;
} while (dev_info);
hid_free_enumeration(dev_info_first);

return EXIT_SUCCESS;
}

int init_and_start_xpanel_plugin(void)
{
char aircraft_file_name[256];
Expand Down Expand Up @@ -277,7 +310,7 @@ int init_and_start_xpanel_plugin(void)

Device* device;

for (auto &it : config.device_configs)
for (auto& it : config.device_configs)
{
switch (it.device_type) {
case DeviceType::SAITEK_MULTI:
Expand All @@ -287,54 +320,34 @@ int init_and_start_xpanel_plugin(void)
if (it.pid == 0)
it.pid = 0x0d06;
Logger(TLogLevel::logDEBUG) << "add new saitek multi panel device" << std::endl;
device = new SaitekMultiPanel(it);
devices.push_back(device);
device->connect();
device->start();
device->thread_handle = new std::thread(&SaitekMultiPanel::thread_func, (SaitekMultiPanel*)device);
LuaHelper::get_instace()->register_hid_device((UsbHidDevice*)device);
enumerate_and_add_hid_devices<SaitekMultiPanel>(it);
break;
case DeviceType::HOME_COCKPIT:
// set default vid & pid if it's not set in config file
if (it.vid == 0)
it.vid = 0x2341;
if (it.pid == 0)
it.pid = 0x8036;
Logger(TLogLevel::logDEBUG) << "add new homecockpit device" << std::endl;
device = new ArduinoHomeCockpit(it);
devices.push_back(device);
device->connect();
device->start();
device->thread_handle = new std::thread(&ArduinoHomeCockpit::thread_func, (ArduinoHomeCockpit*)device);
LuaHelper::get_instace()->register_hid_device((UsbHidDevice*)device);
Logger(TLogLevel::logDEBUG) << "add new homecockpit devices" << std::endl;
enumerate_and_add_hid_devices<ArduinoHomeCockpit>(it);
break;
case DeviceType::SAITEK_RADIO:
// set default vid & pid if it's not set in config file
if (it.vid == 0)
it.vid = 0x06a3;
if (it.pid == 0)
it.pid = 0x0d05;
Logger(TLogLevel::logDEBUG) << "add new saitek radio panel device" << std::endl;
device = new SaitekRadioPanel(it);
devices.push_back(device);
device->connect();
device->start();
device->thread_handle = new std::thread(&SaitekRadioPanel::thread_func, (SaitekRadioPanel*)device);
LuaHelper::get_instace()->register_hid_device((UsbHidDevice*)device);
Logger(TLogLevel::logDEBUG) << "add new saitek radio devices" << std::endl;
enumerate_and_add_hid_devices<SaitekRadioPanel>(it);
break;
case DeviceType::SAITEK_SWITCH:
// set default vid & pid if it's not set in config file
if (it.vid == 0)
it.vid = 0x06a3;
if (it.pid == 0)
it.pid = 0x0d67;
Logger(TLogLevel::logDEBUG) << "add new saitek switch panel device" << std::endl;
device = new SaitekSwitchPanel(it);
devices.push_back(device);
device->connect();
device->start();
device->thread_handle = new std::thread(&SaitekSwitchPanel::thread_func, (SaitekSwitchPanel*)device);
LuaHelper::get_instace()->register_hid_device((UsbHidDevice*)device);
Logger(TLogLevel::logDEBUG) << "add new saitek switch panel devices" << std::endl;
enumerate_and_add_hid_devices<SaitekSwitchPanel>(it);
break;
case DeviceType::LOGITECH_FIP:
Logger(TLogLevel::logDEBUG) << "add new FIP device" << std::endl;
Expand All @@ -345,22 +358,12 @@ int init_and_start_xpanel_plugin(void)
device->thread_handle = new std::thread(&FIPDevice::thread_func, (FIPDevice*)device);
break;
case DeviceType::TRC1000_PFD:
Logger(TLogLevel::logDEBUG) << "add new TRC1000 PFD device" << std::endl;
device = new TRC1000PFD(it);
devices.push_back(device);
device->connect();
device->start();
device->thread_handle = new std::thread(&TRC1000PFD::thread_func, (TRC1000PFD*)device);
LuaHelper::get_instace()->register_hid_device((UsbHidDevice*)device);
Logger(TLogLevel::logDEBUG) << "add new TRC1000 PFD devices" << std::endl;
enumerate_and_add_hid_devices<TRC1000PFD>(it);
break;
case DeviceType::TRC1000_AUDIO:
Logger(TLogLevel::logDEBUG) << "add new TRC1000 Audio device" << std::endl;
device = new TRC1000Audio(it);
devices.push_back(device);
device->connect();
device->start();
device->thread_handle = new std::thread(&TRC1000Audio::thread_func, (TRC1000Audio*)device);
LuaHelper::get_instace()->register_hid_device((UsbHidDevice*)device);
Logger(TLogLevel::logDEBUG) << "add new TRC1000 Audio devices" << std::endl;
enumerate_and_add_hid_devices<TRC1000Audio>(it);
break;
default:
Logger(TLogLevel::logERROR) << "unknown device type" << std::endl;
Expand All @@ -382,7 +385,7 @@ PLUGIN_API void XPluginReceiveMessage(XPLMPluginID inFrom, int inMsg, void*)
switch (inMsg) {
case XPLM_MSG_AIRPORT_LOADED:
Logger(TLogLevel::logTRACE) << "XPLM_MSG_AIRPORT_LOADED: message received" << std::endl;

if (plugin_already_initialized)
stop_and_clear_xpanel_plugin();

Expand Down
21 changes: 21 additions & 0 deletions src/devices/arduino-homecockpit/ArduinoHomeCockpit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,27 @@ int ArduinoHomeCockpit::read_board_configuration(std::string file_name, unsigned
return exit_status;
}

int ArduinoHomeCockpit::connect(hid_device* _device_handle)
{
if (_device_handle == NULL)
{
if (UsbHidDevice::connect() != EXIT_SUCCESS)
{
Logger(TLogLevel::logERROR) << "Arduin Home Cockpit connect. Error during connect" << std::endl;
return EXIT_FAILURE;
}
}
else
{
if (UsbHidDevice::connect(_device_handle) != EXIT_SUCCESS)
{
Logger(TLogLevel::logERROR) << "Arduin Home Cockpit connect. Error during connect" << std::endl;
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}

int ArduinoHomeCockpit::connect()
{
return UsbHidDevice::connect();
Expand Down
1 change: 1 addition & 0 deletions src/devices/arduino-homecockpit/ArduinoHomeCockpit.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class ArduinoHomeCockpit :public UsbHidDevice
const std::string TOKEN_DISPLAY = "display:id=\"([a-zA-Z0-9_-]+)\",width=([0-9]+)";
public:
ArduinoHomeCockpit(DeviceConfiguration& config);
int connect(hid_device* _device_handle);
int connect();
void start();
void stop(int timeout);
Expand Down
21 changes: 21 additions & 0 deletions src/devices/saitek-multi/SaitekMultiPanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,27 @@ SaitekMultiPanel::SaitekMultiPanel(DeviceConfiguration& config) :UsbHidDevice(co
}
}

int SaitekMultiPanel::connect(hid_device* _device_handle)
{
if (_device_handle == NULL)
{
if (UsbHidDevice::connect() != EXIT_SUCCESS)
{
Logger(TLogLevel::logERROR) << "SaitekMultiPanel connect. Error during connect" << std::endl;
return EXIT_FAILURE;
}
}
else
{
if (UsbHidDevice::connect(_device_handle) != EXIT_SUCCESS)
{
Logger(TLogLevel::logERROR) << "SaitekMultiPanel connect. Error during connect" << std::endl;
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}

int SaitekMultiPanel::connect()
{
unsigned char buff[WRITE_BUFFER_SIZE];
Expand Down
1 change: 1 addition & 0 deletions src/devices/saitek-multi/SaitekMultiPanel.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class SaitekMultiPanel : public UsbHidDevice
std::vector<PanelDisplay> multi_displays;
public:
SaitekMultiPanel(DeviceConfiguration &config);
int connect(hid_device* _device_handle);
int connect();
void start();
void stop(int timeout);
Expand Down
22 changes: 19 additions & 3 deletions src/devices/saitek-radio/SaitekRadioPanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,26 @@ SaitekRadioPanel::SaitekRadioPanel(DeviceConfiguration& config) :UsbHidDevice(co

int SaitekRadioPanel::connect()
{
if (UsbHidDevice::connect() != EXIT_SUCCESS)
return connect(NULL);
}

int SaitekRadioPanel::connect(hid_device* _device_handle)
{
if (_device_handle == NULL)
{
Logger(TLogLevel::logERROR) << "SaitekRadioPanel connect. Error during connect" << std::endl;
return EXIT_FAILURE;
if (UsbHidDevice::connect() != EXIT_SUCCESS)
{
Logger(TLogLevel::logERROR) << "SaitekRadioPanel connect. Error during connect" << std::endl;
return EXIT_FAILURE;
}
}
else
{
if (UsbHidDevice::connect(_device_handle) != EXIT_SUCCESS)
{
Logger(TLogLevel::logERROR) << "SaitekRadioPanel connect. Error during connect" << std::endl;
return EXIT_FAILURE;
}
}

read_device(read_buffer, read_buffer_size);
Expand Down
1 change: 1 addition & 0 deletions src/devices/saitek-radio/SaitekRadioPanel.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class SaitekRadioPanel : public UsbHidDevice
public:
SaitekRadioPanel(DeviceConfiguration& config);
int connect();
int connect(hid_device* _device_handle);
void start();
void stop(int timeout);
};
21 changes: 21 additions & 0 deletions src/devices/saitek-switch/SaitekSwitchPanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,27 @@ SaitekSwitchPanel::SaitekSwitchPanel(DeviceConfiguration& config) :UsbHidDevice(
register_lights(switch_lights);
}

int SaitekSwitchPanel::connect(hid_device* _device_handle)
{
if (_device_handle == NULL)
{
if (UsbHidDevice::connect() != EXIT_SUCCESS)
{
Logger(TLogLevel::logERROR) << "SaitekSwitchPanel connect. Error during connect" << std::endl;
return EXIT_FAILURE;
}
}
else
{
if (UsbHidDevice::connect(_device_handle) != EXIT_SUCCESS)
{
Logger(TLogLevel::logERROR) << "SaitekSwitchPanel connect. Error during connect" << std::endl;
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}

int SaitekSwitchPanel::connect()
{
unsigned char buff[WRITE_BUFFER_SIZE];
Expand Down
Loading

0 comments on commit db0f7d4

Please sign in to comment.