コード例 #1
0
//-- AsyncBluetoothPairDeviceRequest State Machine -----
static bool
AsyncBluetoothPairDeviceRequest__findBluetoothRadio(BluetoothPairDeviceState *state)
{
    assert(state->isMainThread());
    bool bSuccess= true;

    if (find_first_bluetooth_radio(&state->hRadio) && state->hRadio != INVALID_HANDLE_VALUE) 
    {
        SERVER_LOG_INFO("AsyncBluetoothPairDeviceRequest") << "Found a bluetooth radio";
    }
    else
    {
        SERVER_LOG_ERROR("AsyncBluetoothPairDeviceRequest") << "Failed to find a bluetooth radio";
        bSuccess= false;
    }

    if (bSuccess) 
    {
        DWORD result= BluetoothGetRadioInfo(state->hRadio, &state->radioInfo);
        if (result == ERROR_SUCCESS)
        {
            SERVER_LOG_INFO("AsyncBluetoothPairDeviceRequest") << "Retrieved radio info";
            state->host_address_string= bluetooth_address_to_string(&state->radioInfo.address);
        }
        else
        {
            SERVER_LOG_ERROR("AsyncBluetoothPairDeviceRequest") 
                << "Failed to retrieve radio info (Error Code: "
                << std::hex << std::setfill('0') << std::setw(8) << result;
            bSuccess= false;
        }
    }

    return bSuccess;
}
コード例 #2
0
void MorpheusHMD::close()
{
    if (USBContext->sensor_device_handle != nullptr || USBContext->usb_device_handle != nullptr)
    {
		if (USBContext->sensor_device_handle != nullptr)
		{
			SERVER_LOG_INFO("MorpheusHMD::close") << "Closing MorpheusHMD sensor interface(" << USBContext->sensor_device_path << ")";
			hid_close(USBContext->sensor_device_handle);
		}

		if (USBContext->usb_device_handle != nullptr)
		{
			SERVER_LOG_INFO("MorpheusHMD::close") << "Closing MorpheusHMD command interface";
			morpheus_set_headset_power(USBContext, false);
			morpheus_close_usb_device(USBContext);
		}

        USBContext->Reset();
        InData->Reset();
    }
    else
    {
        SERVER_LOG_INFO("MorpheusHMD::close") << "MorpheusHMD already closed. Ignoring request.";
    }
}
コード例 #3
0
ファイル: context.cpp プロジェクト: chenchu0910/mooon
bool CContext::create_thread_pool(net::CListenManager<CListener>* listen_manager)
{
    SERVER_LOG_INFO("Started to create waiter thread pool.\n");
    if (_config->get_thread_number() < 1)
    {
        SERVER_LOG_ERROR("Server thread number is not specified.\n");
        return false;
    }

    // 创建线程池
    _thread_pool.create(_config->get_thread_number(), this);

    uint16_t thread_count = _thread_pool.get_thread_count();
    CWorkThread** thread_array = _thread_pool.get_thread_array();

    // 设置线程运行时参数
    for (uint16_t i=0; i<thread_count; ++i)
    {
        uint16_t listen_count = listen_manager->get_listener_count();
        CListener* listener_array = listen_manager->get_listener_array();

        thread_array[i]->add_listener_array(listener_array, listen_count);
    }

    _thread_pool.activate();
    SERVER_LOG_INFO("Created waiter thread pool success.\n");
    return true;
}
コード例 #4
0
bool ServerDeviceView::poll()
{
    bool bSuccessfullyUpdated= true;
    
    IDeviceInterface* device = getDevice();

    // Only poll data from open, bluetooth controllers
    if (device != nullptr && device->getIsReadyToPoll())
    {
        switch (device->poll())
        {
        case IDeviceInterface::_PollResultSuccessNoData:
            {
                long max_failure= device->getMaxPollFailureCount();
                
                ++m_pollNoDataCount;

                if (m_pollNoDataCount > max_failure)
                {
                    SERVER_LOG_INFO("ServerDeviceView::poll") <<
                    "Device id " << getDeviceID() << " closing due to no data (" << max_failure << " failed poll attempts)";
                    device->close();
                    
                    bSuccessfullyUpdated= false;
                }
            }
            break;
                
        case IDeviceInterface::_PollResultSuccessNewData:
            {
                m_pollNoDataCount= 0;
                m_lastNewDataTimestamp= std::chrono::high_resolution_clock::now();

                // If we got new sensor data, then we have new state to publish
                markStateAsUnpublished();

                bSuccessfullyUpdated= true;
            }
            break;
                
        case IDeviceInterface::_PollResultFailure:
            {
                SERVER_LOG_INFO("ServerDeviceView::poll") <<
                "Device id " << getDeviceID() << " closing due to failed read";
                device->close();
                
                bSuccessfullyUpdated= false;
            }
            break;
        }
    }
    
    return bSuccessfullyUpdated;
}
コード例 #5
0
static bool
AsyncBluetoothPairDeviceRequest__registerHostAddress(
    ServerControllerViewPtr &controllerView, 
    BluetoothPairDeviceState *state)
{
    assert(state->isMainThread());
    const int controller_id= controllerView->getDeviceID();
    bool bSuccess= true;

    if (controllerView->setHostBluetoothAddress(state->host_address_string))
    {
        SERVER_LOG_INFO("AsyncBluetoothPairDeviceRequest") 
            << "Assigned host address " << state->host_address_string
            << " to controller id " << controller_id;
    }
    else
    {
        SERVER_LOG_ERROR("AsyncBluetoothPairDeviceRequest") 
            << "Failed to set host address " << state->host_address_string
            << " on controller id " << controller_id;
        bSuccess= false;
    }

    return bSuccess;
}
コード例 #6
0
void PSDualShock4Controller::close()
{
    if (getIsOpen())
    {
        SERVER_LOG_INFO("PSDualShock4Controller::close") << "Closing PSDualShock4Controller(" << HIDDetails.Device_path << ")";

        if (HIDDetails.Handle != nullptr)
        {
            if (IsBluetooth)
            {
                clearAndWriteDataOut();
            }

            hid_close(HIDDetails.Handle);
            HIDDetails.Handle = nullptr;
        }
    }
    else
    {
        SERVER_LOG_INFO("PSDualShock4Controller::close") << "PSDualShock4Controller(" << HIDDetails.Device_path << ") already closed. Ignoring request.";
    }
}
コード例 #7
0
//-- Queries -----
bool bluetooth_get_host_address(std::string &out_address)
{
    bool bSuccess = true;
    HANDLE hRadio;

    if (find_first_bluetooth_radio(&hRadio) && hRadio != INVALID_HANDLE_VALUE)
    {
        SERVER_LOG_INFO("bluetooth_get_host_address") << "Found a bluetooth radio";
    }
    else
    {
        SERVER_LOG_ERROR("bluetooth_get_host_address") << "Failed to find a bluetooth radio";
        bSuccess = false;
    }

    if (bSuccess)
    {
        BLUETOOTH_RADIO_INFO radioInfo;
        memset(&radioInfo, 0, sizeof(BLUETOOTH_RADIO_INFO));
        radioInfo.dwSize = sizeof(BLUETOOTH_RADIO_INFO);

        DWORD result = BluetoothGetRadioInfo(hRadio, &radioInfo);

        if (result == ERROR_SUCCESS)
        {
            SERVER_LOG_INFO("bluetooth_get_host_address") << "Retrieved radio info";
            out_address = bluetooth_address_to_string(&radioInfo.address);
        }
        else
        {
            SERVER_LOG_ERROR("bluetooth_get_host_address")
                << "Failed to retrieve radio info (Error Code: "
                << std::hex << std::setfill('0') << std::setw(8) << result;
            bSuccess = false;
        }
    }

    return bSuccess;
}
コード例 #8
0
void PSNaviController::close()
{
    if (getIsOpen())
    {
        SERVER_LOG_INFO("PSNaviController::close") << "Closing PSNaviController(" << HIDDetails.Device_path << ")";

        if (HIDDetails.Handle != nullptr)
        {
            hid_close(HIDDetails.Handle);
            HIDDetails.Handle= nullptr;
        }

        if (HIDDetails.Handle_addr != nullptr)
        {
            hid_close(HIDDetails.Handle_addr);
            HIDDetails.Handle_addr= nullptr;
        }
    }
    else
    {
        SERVER_LOG_INFO("PSNaviController::close") << "PSNaviController(" << HIDDetails.Device_path << ") already closed. Ignoring request.";
    }
}
コード例 #9
0
ファイル: Room.cpp プロジェクト: mjssw/myproj
void CRoom::_GameStart()
{
	SERVER_LOG_INFO( "GameStart," << Id() );

	ChangeState( E_RoomState_InGame );

	SG_ASSERT( m_PlayerCount == CHall::Instance().RoomPlayerCount() );
	for( s32 i=0; i<m_PlayerCount; ++i )
	{
		CPlayer *player = (CPlayer*)m_Players[i];
		SG_ASSERT( player && player->IsReady() );
		player->GameStart();
	}
}
コード例 #10
0
ファイル: context.cpp プロジェクト: chenchu0910/mooon
bool CContext::IgnorePipeSignal()
{
    // 忽略PIPE信号
    if (SIG_ERR == signal(SIGPIPE, SIG_IGN))
    {
        SERVER_LOG_FATAL("Can not ignore PIPE signal for %s.\n", strerror(errno));
        return false;
    }
    else
    {
        SERVER_LOG_INFO("Ignore PIPE signal success.\n");
        return true;
    }
}
コード例 #11
0
ファイル: context.cpp プロジェクト: chenchu0910/mooon
bool CContext::create_listen_manager()
{
    SERVER_LOG_INFO("Started to create listen manager.\n");
    const net::ip_port_pair_array_t& listen_parameter = _config->get_listen_parameter();

    if (0 == listen_parameter.size())
    {
        SERVER_LOG_ERROR("Listen parameters are not specified.\n");
        return false;
    }

    for (net::ip_port_pair_array_t::size_type i=0; i<listen_parameter.size(); ++i)
    {
        _listen_manager.add(listen_parameter[i].first, listen_parameter[i].second);
        SERVER_LOG_INFO("Added listener %s:%d.\n"
                        , listen_parameter[i].first.to_string().c_str()
                        , listen_parameter[i].second);
    }

    _listen_manager.create(true);
    SERVER_LOG_INFO("Created listen manager success.\n");

    return true;
}
コード例 #12
0
bool PS3EyeTracker::open(const DeviceEnumerator *enumerator)
{
    const TrackerDeviceEnumerator *tracker_enumerator = static_cast<const TrackerDeviceEnumerator *>(enumerator);
    const char *cur_dev_path = tracker_enumerator->get_path();

    bool bSuccess = false;
    
    if (getIsOpen())
    {
        SERVER_LOG_WARNING("PS3EyeTracker::open") << "PS3EyeTracker(" << cur_dev_path << ") already open. Ignoring request.";
        bSuccess = true;
    }
    else
    {
        const int camera_index = tracker_enumerator->get_camera_index();

        SERVER_LOG_INFO("PS3EyeTracker::open") << "Opening PS3EyeTracker(" << cur_dev_path << ", camera_index=" << camera_index << ")";

        VideoCapture = new PSEyeVideoCapture(camera_index);

        if (VideoCapture->isOpened())
        {
            CaptureData = new PSEyeCaptureData;
            USBDevicePath = enumerator->get_path();
            bSuccess = true;
        }
        else
        {
            SERVER_LOG_ERROR("PS3EyeTracker::open") << "Failed to open PS3EyeTracker(" << cur_dev_path << ", camera_index=" << camera_index << ")";

            close();
        }
    }
    
    if (bSuccess)
    {
        std::string identifier = VideoCapture->getUniqueIndentifier();
        std::string config_name = "PS3EyeTrackerConfig_";
        config_name.append(identifier);

        cfg = PS3EyeTrackerConfig(config_name);
        cfg.load();
        setExposure(cfg.exposure);
        setGain(cfg.gain);
    }

    return bSuccess;
}
コード例 #13
0
ファイル: Room.cpp プロジェクト: mjssw/myproj
void CRoom::_GameEnd(CPlayer *loser)
{
	SG_ASSERT( loser != NULL );

	SERVER_LOG_INFO( "GameEnd," << Id() << "," << loser->UserId().c_str() );

	ChangeState( E_RoomState_Wait );

	SG_ASSERT( m_PlayerCount == CHall::Instance().RoomPlayerCount() );
	for( s32 i=0; i<m_PlayerCount; ++i )
	{
		CPlayer *player = (CPlayer*)m_Players[i];
		SG_ASSERT( player );
		player->GameEnd();
	}
}
コード例 #14
0
bool MorpheusHMD::open(
    const DeviceEnumerator *enumerator)
{
    const HMDDeviceEnumerator *pEnum = static_cast<const HMDDeviceEnumerator *>(enumerator);

    const char *cur_dev_path = pEnum->get_path();
    bool success = false;

    if (getIsOpen())
    {
        SERVER_LOG_WARNING("MorpheusHMD::open") << "MorpheusHMD(" << cur_dev_path << ") already open. Ignoring request.";
        success = true;
    }
    else
    {
		SERVER_LOG_INFO("MorpheusHMD::open") << "Opening MorpheusHMD(" << cur_dev_path << ").";

		USBContext->device_identifier = cur_dev_path;

		// Open the sensor interface using HIDAPI
		USBContext->sensor_device_path = pEnum->get_hid_hmd_enumerator()->get_interface_path(MORPHEUS_SENSOR_INTERFACE);
		USBContext->sensor_device_handle = hid_open_path(USBContext->sensor_device_path.c_str());
		if (USBContext->sensor_device_handle != nullptr)
		{
			hid_set_nonblocking(USBContext->sensor_device_handle, 1);
		}

		// Open the command interface using libusb.
		// NOTE: Ideally we would use one usb library for both interfaces, but there are some complications.
		// A) The command interface uses the bulk transfer endpoint and HIDApi doesn't support that endpoint.
		// B) In Windows, libusb doesn't handle a high frequency of requests coming from two different threads well.
		// In this case, PS3EyeDriver is constantly sending bulk transfer requests in its own thread to get video frames.
		// If we started sending control transfer requests for the sensor data in the main thread at the same time
		// it can lead to a crash. It shouldn't, but this was a problem previously setting video feed properties
		// from the color config tool while a video feed was running.
		if (!cfg.disable_command_interface)
		{
			morpheus_open_usb_device(USBContext);
		}
		else
		{
			SERVER_LOG_WARNING("MorpheusHMD::open") << "Morpheus command interface is flagged as DISABLED.";
		}

        if (getIsOpen())  // Controller was opened and has an index
        {
			if (USBContext->usb_device_handle != nullptr)
			{
				if (morpheus_set_headset_power(USBContext, true))
				{
					if (morpheus_enable_tracking(USBContext))
					{
						morpheus_set_led_brightness(USBContext, _MorpheusLED_ALL, 0);
					}
				}
			}

			// Always save the config back out in case some defaults changed
			cfg.save();

            // Reset the polling sequence counter
            NextPollSequenceNumber = 0;

			success = true;
        }
        else
        {
            SERVER_LOG_ERROR("MorpheusHMD::open") << "Failed to open MorpheusHMD(" << cur_dev_path << ")";
			close();
        }
    }

    return success;
}
コード例 #15
0
bool
DeviceTypeManager::update_connected_devices()
{
    bool success = false;

    // Don't do any connection opening/closing until all pending bluetooth operations are finished
    if (can_update_connected_devices())
    {
        const int maxDeviceCount = getMaxDevices();
        ServerDeviceViewPtr *temp_device_list = new ServerDeviceViewPtr[maxDeviceCount];
        bool bSendControllerUpdatedNotification = false;

        // Step 1
        // See if any devices shuffled order OR if any new controllers were attached.
        // Migrate open devices to a new temp list in the order
        // that they appear in the device enumerator.
        {
            DeviceEnumerator *enumerator = allocate_device_enumerator();

            while (enumerator->is_valid())
            {
                // Find device index for the device with the matching device path
                int device_id = find_open_device_device_id(enumerator);

                // Existing device case (Most common)
                if (device_id != -1)
                {
                    // Fetch the device from it's existing device slot
                    ServerDeviceViewPtr existingDevice = getDeviceViewPtr(device_id);

                    // Move it to the same slot in the temp list
                    temp_device_list[device_id] = existingDevice;

                    // Remove it from the previous list
                    m_deviceViews[device_id] = ServerDeviceViewPtr();
                }
                // New controller connected case
                else
                {
                    int device_id = find_first_closed_device_device_id();

                    if (device_id != -1)
                    {
                        // Fetch the controller from it's existing controller slot
                        ServerDeviceViewPtr existingDevice = getDeviceViewPtr(device_id);

                        // Move it to the available slot
                        existingDevice->setDeviceID(static_cast<int>(device_id));
                        temp_device_list[device_id] = existingDevice;

                        // Remove it from the previous list
                        m_deviceViews[device_id] = ServerDeviceViewPtr();

                        // Attempt to open the device
                        if (existingDevice->open(enumerator))
                        {
                            const char *device_type_name =
                                CommonDeviceState::getDeviceTypeString(existingDevice->getDevice()->getDeviceType());

                            SERVER_LOG_INFO("DeviceTypeManager::update_connected_devices") <<
                                "Device device_id " << device_id << " (" << device_type_name << ") connected";
                            bSendControllerUpdatedNotification = true;
                        }
                    }
                    else
                    {
                        SERVER_LOG_ERROR("DeviceTypeManager::update_connected_devices") << "Can't connect any more new devices. Too many open device.";
                        break;
                    }
                }

                enumerator->next();
            }

            free_device_enumerator(enumerator);
        }

        // Step 2
        // Close any remaining open controllers not listed in the device enumerator.
        // Copy over any closed controllers to the temp.
        for (int existing_device_id = 0; existing_device_id < maxDeviceCount; ++existing_device_id)
        {
            ServerDeviceViewPtr existingDevice = getDeviceViewPtr(existing_device_id);

            if (existingDevice)
            {
                // Any "open" controllers remaining in the old list need to be closed
                // since they no longer appear in the connected device list.
                // This probably shouldn't happen very often (at all?) as polling should catch
                // disconnected controllers first.
                if (existingDevice->getIsOpen())
                {
                    const char *device_type_name =
                        CommonDeviceState::getDeviceTypeString(existingDevice->getDevice()->getDeviceType());

                    SERVER_LOG_WARNING("DeviceTypeManager::update_connected_devices") << "Closing device "
                        << existing_device_id << " (" << device_type_name << ") since it's no longer in the device list.";
                    existingDevice->close();
                    bSendControllerUpdatedNotification = true;
                }

                // Move it to the temp slot
                temp_device_list[existing_device_id] = existingDevice;

                // Remove it from the previous list
                m_deviceViews[existing_device_id] = ServerDeviceViewPtr();
            }
        }

        // Step 3
        // Copy the temp controller list back over top the original list
        for (int device_id = 0; device_id < maxDeviceCount; ++device_id)
        {
            m_deviceViews[device_id] = temp_device_list[device_id];
        }

        if (bSendControllerUpdatedNotification)
        {
            send_device_list_changed_notification();
        }

        delete[] temp_device_list;

        success = true;
    }

    return success;
}
コード例 #16
0
bool PSNaviController::open(
    const DeviceEnumerator *enumerator)
{
    const ControllerDeviceEnumerator *pEnum = static_cast<const ControllerDeviceEnumerator *>(enumerator);

    const char *cur_dev_path= pEnum->get_path();
    bool success= false;

    if (getIsOpen())
    {
        SERVER_LOG_WARNING("PSNaviController::open") << "PSNavoController(" << cur_dev_path << ") already open. Ignoring request.";
        success= true;
    }
    else
    {
        char cur_dev_serial_number[256];

        SERVER_LOG_INFO("PSNaviController::open") << "Opening PSNaviController(" << cur_dev_path << ")";

        if (pEnum->get_serial_number(cur_dev_serial_number, sizeof(cur_dev_serial_number)))
        {
            SERVER_LOG_INFO("PSNaviController::open") << "  with serial_number: " << cur_dev_serial_number;
        }
        else
        {
            cur_dev_serial_number[0]= '\0';
            SERVER_LOG_INFO("PSNaviController::open") << "  with EMPTY serial_number";
        }

        HIDDetails.Device_path = cur_dev_path;
#ifdef _WIN32
        HIDDetails.Device_path_addr = HIDDetails.Device_path;
        HIDDetails.Device_path_addr.replace(HIDDetails.Device_path_addr.find("&col01#"), 7, "&col02#");
        HIDDetails.Device_path_addr.replace(HIDDetails.Device_path_addr.find("&0000#"), 6, "&0001#");
        HIDDetails.Handle_addr = hid_open_path(HIDDetails.Device_path_addr.c_str());
        hid_set_nonblocking(HIDDetails.Handle_addr, 1);
#endif
        HIDDetails.Handle = hid_open_path(HIDDetails.Device_path.c_str());
        hid_set_nonblocking(HIDDetails.Handle, 1);

        IsBluetooth = (strlen(cur_dev_serial_number) > 0);

        if (getIsOpen())  // Controller was opened and has an index
        {
            // Get the bluetooth address
#ifndef _WIN32
            // On my Mac, getting the bt feature report when connected via
            // bt crashes the controller. So we simply copy the serial number.
            // It gets modified in getBTAddress.
            // TODO: Copy this over anyway even in Windows. Check getBTAddress
            // comments for handling windows serial_number.
            // Once done, we can remove the ifndef above.
            std::string mbs(cur_dev_serial_number);
            HIDDetails.Bt_addr = mbs;
#endif
            if (getBTAddress(HIDDetails.Host_bt_addr, HIDDetails.Bt_addr))
            {
                // Load the config file
                std::string btaddr = HIDDetails.Bt_addr;
                std::replace(btaddr.begin(), btaddr.end(), ':', '_');
                cfg = PSNaviControllerConfig(btaddr);
                cfg.load();

                // TODO: Other startup.

                success= true;
            }
            else
            {
                // If serial is still bad, maybe we have a disconnected
                // controller still showing up in hidapi
                SERVER_LOG_ERROR("PSNaviController::open") << "Failed to get bluetooth address of PSNaviController(" << cur_dev_path << ")";
                success= false;
            }

            // Reset the polling sequence counter
            NextPollSequenceNumber= 0;
        }
        else
        {
            SERVER_LOG_ERROR("PSNaviController::open") << "Failed to open PSNaviController(" << cur_dev_path << ")";
            success= false;
        }
    }

    return success;
}
コード例 #17
0
bool 
AsyncBluetoothPairDeviceRequest::start()
{
    bool success= true;
    const int controller_id= m_controllerView->getDeviceID();

    // Reset the pairing device state
    BluetoothPairDeviceState *state= reinterpret_cast<BluetoothPairDeviceState *>(m_internal_state);
    state->initialize(controller_id);
    state->controller_serial_string= m_controllerView->getSerial();
    state->controller_device_type= m_controllerView->getControllerDeviceType();

    // Make sure the controller we're working with is a USB connection
    if (success && m_controllerView->getIsOpen() && m_controllerView->getIsBluetooth())
    {
        SERVER_LOG_ERROR("AsyncBluetoothPairDeviceRequest") 
            << "Controller " << controller_id 
            << " isn't an open USB device";
        success= false;
    }

    // Find the bluetooth address of the host adapter
    if (success)
    {
        success= AsyncBluetoothPairDeviceRequest__findBluetoothRadio(state);
    }

    // Make sure the controller isn't already paired with this host adapter
    if (m_controllerView->getAssignedHostBluetoothAddress() != state->host_address_string)
    {
        // Assign this host address on the controller.
        // NOTE: This needs to be done on the main thread since the controller view isn't thread safe.
        if (success)
        {
            success= AsyncBluetoothPairDeviceRequest__registerHostAddress(m_controllerView, state);
        }

        // Kick off the worker thread to do the rest of the work
        if (success)
        {
            state->worker_thread_handle=
                CreateThread( 
                    NULL,                        // default security attributes
                    0,                           // use default stack size  
                    AsyncBluetoothPairDeviceThreadFunction,       // thread function pointer
                    m_internal_state,            // argument to thread function 
                    0,                           // use default creation flags 
                    NULL);                       // returns the thread identifier

            if (state->worker_thread_handle == NULL)
            {
                SERVER_LOG_ERROR("AsyncBluetoothPairDeviceRequest") << "Failed to start worker thread!";
                success= false;
            }
        }

        if (success)
        {
            m_status = AsyncBluetoothRequest::running;
        }
    }
    else
    {
        SERVER_LOG_INFO("AsyncBluetoothPairDeviceRequest") << "Controller already paired";
        m_status= AsyncBluetoothRequest::succeeded;
    }

    if (!success)
    {
        m_status = AsyncBluetoothRequest::failed;
    }

    return success;
}
コード例 #18
0
bool PSDualShock4Controller::open(
    const DeviceEnumerator *enumerator)
{
    const ControllerDeviceEnumerator *pEnum = static_cast<const ControllerDeviceEnumerator *>(enumerator);

    const char *cur_dev_path = pEnum->get_path();
    bool success = false;

    if (getIsOpen())
    {
        SERVER_LOG_WARNING("PSDualShock4Controller::open") << "PSDualShock4Controller(" << cur_dev_path << ") already open. Ignoring request.";
        success = true;
    }
    else
    {
        char cur_dev_serial_number[256];

        SERVER_LOG_INFO("PSDualShock4Controller::open") << "Opening PSDualShock4Controller(" << cur_dev_path << ")";

        if (pEnum->get_serial_number(cur_dev_serial_number, sizeof(cur_dev_serial_number)))
        {
            SERVER_LOG_INFO("PSDualShock4Controller::open") << "  with serial_number: " << cur_dev_serial_number;
        }
        else
        {
            cur_dev_serial_number[0] = '\0';
            SERVER_LOG_INFO("PSDualShock4Controller::open") << "  with EMPTY serial_number";
        }

        // Attempt to open the controller 
		HIDDetails.vendor_id = pEnum->get_vendor_id();
		HIDDetails.product_id = pEnum->get_product_id();
        HIDDetails.Device_path = cur_dev_path;
        HIDDetails.Handle = hid_open_path(HIDDetails.Device_path.c_str());

        if (HIDDetails.Handle != nullptr)  // Controller was opened and has an index
        {             
            // Don't block on hid report requests
            hid_set_nonblocking(HIDDetails.Handle, 1);

            /* -USB or Bluetooth Device-

                On my Mac, using bluetooth,
                cur_dev->path = Bluetooth_054c_03d5_779732e8
                cur_dev->serial_number = 00-06-f7-97-32-e8
                On my Mac, using USB,
                cur_dev->path = USB_054c_03d5_14100000
                cur_dev->serial_number = "" (not null, just empty)

                On my Windows 10 box (different controller), using bluetooth
                cur_dev->path = \\?\hid#{00001124-0000-1000-8000-00805f9b34fb}_vid&0002054c_pid&05c4#8&217a4584&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
                cur_dev->serial_number = 1c666d2c8deb
                Using USB
                cur_dev->path = \\?\hid#vid_054c&pid_03d5&col01#6&7773e57&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
                cur_dev->serial_number = (null)
            */

            // Bluetooth connected
            if (strlen(cur_dev_serial_number) > 0)
            {
                IsBluetooth = true;

                // Convert the serial number into a normalized bluetooth address of the form: "xx:xx:xx:xx:xx:xx"
                char szNormalizedControllerAddress[18];
                ServerUtility::bluetooth_cstr_address_normalize(
                    cur_dev_serial_number, true, ':',
                    szNormalizedControllerAddress, sizeof(szNormalizedControllerAddress));

                // Save the controller address as a std::string
                HIDDetails.Bt_addr = std::string(szNormalizedControllerAddress);

				// Get the (possibly cached) bluetooth address of the first bluetooth adapter
				if (!bluetooth_get_host_address(HIDDetails.Host_bt_addr))
				{
					HIDDetails.Host_bt_addr= "00:00:00:00:00:00";
				}

                success = true;
            }
            // USB Connected
            else
            {
                IsBluetooth = false;
                
                // Fetch the bluetooth host and controller addresses via USB HID report request
                success = getBTAddressesViaUSB(HIDDetails.Host_bt_addr, HIDDetails.Bt_addr);

                if (!success)
                {
                    // If serial is still bad, maybe we have a disconnected
                    // controller still showing up in hidapi
                    SERVER_LOG_ERROR("PSDualShock4Controller::open") << "Failed to get bluetooth address of PSDualShock4Controller(" << cur_dev_path << ")";
                }
            }

            if (success)
            {
                // Build a unique name for the config file using bluetooth address of the controller
                char szConfigSuffix[18];
                ServerUtility::bluetooth_cstr_address_normalize(
                    HIDDetails.Bt_addr.c_str(), true, '_',
                    szConfigSuffix, sizeof(szConfigSuffix));

                std::string config_name("dualshock4_");
                config_name += szConfigSuffix;

                // Load the config file
                cfg = PSDualShock4ControllerConfig(config_name);
                cfg.load();

				// Save it back out again in case any defaults changed
				cfg.save();
            }

            // Reset the polling sequence counter
            NextPollSequenceNumber = 0;

            // Write out the initial controller state
            if (success && IsBluetooth)
            {
                bWriteStateDirty= true;
                writeDataOut();
            }
        }
        else
        {
            SERVER_LOG_ERROR("PSDualShock4Controller::open") << "Failed to open PSDualShock4Controller(" << cur_dev_path << ")";
            success = false;
        }
    }

    return success;
}