Skip to content
This repository has been archived by the owner on May 3, 2021. It is now read-only.

PSMoveService Update Walkthrough

Guido Sanchez edited this page Apr 29, 2017 · 1 revision

PSMoveService Update Walkthrough

PSMoveServiceImpl::update() in application loop:

* `m_request_handler.update()`
* `m_device_manager.update()`
* `m_network_manager.update()`

m_request_handler.update()

Update any async requests still waiting to complete. Iterate through m_connection_state_map. If the connection state has a pending bluetooth request then update that. TODO: As pending bluetooth requests are unique to the controller, we may need to add functionality here for tracker and HMD.

m_device_manager.update()

DeviceManager::update() calls each specific manager's .poll(), .updateStateAndPredict(), and .publish() in a specific order. These methods are described in more detail in the sections below about the Device<Type>Managers.

m_network_manager.update()

Process incoming/outgoing networking requests. ServerNetworkManagerImpl::poll() calls start_udp_queued_data_frame_write() (see below) and m_io_service.poll() to handle the callbacks. This continues as long as has_queued_controller_data_frames_ready_to_start(). TODO: Keep polling as long as there are ANY data frames ready to start, not just controller.

start_udp_queued_data_frame_write() iterates through m_connections, calling start_udp_write_queued_controller_data_frame() on each one. TODO: start ALL device data frames.

ServerNetworkManagerImpl::start_udp_write_queued_controller_data_frame() checks m_pending_dataframes (currently device-specific) and if not empty, pulls out a ControllerDataFramePtr, packs it, and sends it to async udp write with callback &ClientConnection::handle_udp_write_controller_data_frame_complete. This just pops the frame from the queue if completed.

The ControllerDataFramePtr gets added to the queue below (see add_controller_data_frame_to_write_queue(...)). ControllerDataFramePtr is a std::shared_ptr of PSMoveProtocol::ControllerDataFrame, which is created by protobuf. See the wiki page about PSMoveProtocol.

DeviceTypeManagers

During the application loop we call m_device_manager.update(). We glossed over this above but we will go into more detail here. This function has the following contents.

    m_controller_manager.poll(); // Update controller counts and poll button/IMU state
    m_tracker_manager.poll(); // Update tracker count and poll video frames
    m_hmd_manager.poll(); // Update HMD count and poll position/orientation state

    m_tracker_manager.updateStateAndPredict(); // Get controller colors and update tracking blob positions/predictions
    m_controller_manager.updateStateAndPredict(); // Compute pose/prediction of tracking blob+IMU state
    m_hmd_manager.updateStateAndPredict(); // Get the pose + prediction for HMD

    m_controller_manager.publish(); // publish controller state to any listening clients  (common case)
    m_tracker_manager.publish(); // publish tracker state to any listening clients (probably only used by ConfigTool)
    m_hmd_manager.publish(); // publish hmd state to any listening clients (probably only used by ConfigTool)

Each m__manager is an instance of the respective DeviceManager, which is a child of DeviceTypeManager.

DeviceTypeManager::poll()

Each m__manager.poll() is handled by the parent class method.

This calls poll_devices() and update_connected_devices() if sufficient time has elapsed (poll_interval and reconnect_interval). poll_devices() simply iterates through each device in m_devices and calls its poll(). Each m_device is a pointer to a ServerDeviceView (see below). update_connected_devices() adds/removes devices to the m_devices list; this is device-type-specific.

DeviceTypeManager::updateStateAndPredict()

This will derive a state from the data and update a model that allows prediction. This is just a wrapper around the (ServerDeviceViewPtr) device->updateStateAndPredict() which is purely virtual and implemented by the device-specific views.

update_connected_devices()
  1. Allocate a DeviceEnumerator (specific enumerator allocated by derived DeviceTypeManager)
  2. Process device shuffling or attachments
    • See if any devices shuffled order OR if any new devices were attached.
    • Migrate open devices to a new temp list in the order that they appear in the device enumerator.
  3. Process device removal
    • Close any remaining open controllers not listed in the device enumerator.
    • Copy over any closed controllers to the temp.
  4. Copy the temp controller list back over top the original list.
    • send_device_list_changed_notification() is device_type-agnostic.
  5. Free the device enumerator
  6. Send notification to connected clients if the device list changed

DeviceTypeManager::publish()

This simply iterates through each device in m_devices and calls its publish().

Let's look at each derived DeviceTypeManager.

ControllerManager

Derived DeviceTypeManager that manages all connected controller types. Creates a ControllerDeviceEnumerator when scanning for connected controllers. Specific controller views can be accessed from this manager. Currently the only supported controller type is the PSMoveController.

TrackerManager

Derived DeviceTypeManager that manages all connected camera types. Creates a TrackerDeviceEnumerator when scanning for connected camera. Specific tracker views can be accessed from this manager. Controller connections can't be updated while a controller pairing request is running. Currently the only supported tracker type is the PS3EyeTracker.

HMDManager

Derived DeviceTypeManager that manages all connected HMD types. Creates a HMDDeviceEnumerator when scanning for connected HMDs. Specific tracker views can be accessed from this manager. Currently the only supported tracker type is the DK2.

ServerDeviceView

Next we will look at the device poll() and publish() methods of of the devices which are called during DeviceTypeManager::poll_devices() and DeviceTypeManager::publish(), respectively. These are called on the upcast form of the device so we call the generic ServerDeviceView parent class methods.

ServerDeviceView::poll()

This gets the (upcast) *IDeviceInterface with getDevice() then calls its ->poll() method. If polling was successful, then we mark the device as having an unpublished state. IDeviceInterface::poll() is virtual and must be implemented by each specific Interface (see below for details of the devices).

ServerDeviceView::publish()

A wrapper around ServerDeviceView::publish_device_data_frame(). This is device specific and is implemented by the child class. It will tell the instance of the ServerRequestHandler to publish_<type>_data_frame with a type-specific callback (e.g., &ServerControllerView::generate_controller_data_frame_for_stream) that is called for each listening connection.

Let's look at the device-specific implementations, including updateStateAndPredict() called during DeviceTypeManager::updateStateAndPredict().

Devices

Controller

ServerControllerView::updateStateAndPredict()

Currently does nothing. TODO: Update state space model.

ServerControllerView::publish_device_data_frame()

ServerRequestHandler::get_instance()->publish_controller_data_frame(...). For each connection id,state , get a new ControllerDataFramePtr and send it with the ServerControllerView through the callback to build the frame, then ServerNetworkManager::get_instance()->send_controller_data_frame(connection_id, data_frame) to send it across the network.

Callback: ServerControllerView::generate_controller_data_frame_for_stream calls generate_psmove_data_frame_for_stream (or alternative for navi). This does all the work of actually filling out the data_frame to be transmitted with the current state information pulled from the hardware. This makes heavy use of PSMoveProtocol.

ServerNetworkManagerImpl::send_controller_data_frame(connection_id, data_frame) finds the right connection, then connection->add_controller_data_frame_to_write_queue(data_frame) which simply calls m_pending_dataframes.push_back(data_frame), and finally start_udp_queued_data_frame_write() which we mentioned above.

PSMoveController::poll()

This does all the work in communicating with the hardware and copying information to a state.

Tracker

ServerTrackerView::updateStateAndPredict()

Currently does nothing.

ServerTrackerView::publish_device_data_frame()

TODO: Implement ServerRequestHandler::get_instance()->publish_tracker_data_frame(...). This will call ServerNetworkManager::get_instance()->send_tracker_data_frame(connection_id, data_frame); TODO: TrackerDataFramePtr.

TODO: Implement ServerNetworkManager::send_tracker_data_frame. Adds the frame to the write queue and starts the UDP write. Does this have to be device-type-specific? What about just overloading using the data_frame argument type?

TODO: Implement ServerTrackerView::generate_tracker_data_frame_for_stream

PSMoveTracker::poll()

TODO: Implement PSMoveTracker in PSMoveTracker.cpp, including poll().

HMD

ServerHMDView::updateStateAndPredict()

Currently does nothing.

ServerHMDView::publish_device_data_frame()

TODO: Implement ServerRequestHandler::get_instance()->publish_tracker_data_frame(...). This will call ServerNetworkManager::get_instance()->send_hmd_data_frame(connection_id, data_frame);

TODO: Implement ServerNetworkManager::send_hmd_data_frame.

TODO: Implement ServerTrackerView::generate_hmd_data_frame_for_stream

PSMoveHMD::poll()

TODO: Implement PSMoveHMD in PSMoveHMD.cpp, including poll().

Clone this wiki locally