diff --git a/libuvc_camera/include/libuvc_camera/camera_driver.h b/libuvc_camera/include/libuvc_camera/camera_driver.h index a4280795e14ec8a634eb8861c3e3910437f7ff4a..0a7c624ed622c7ebfb70148e5367234834d92909 100644 --- a/libuvc_camera/include/libuvc_camera/camera_driver.h +++ b/libuvc_camera/include/libuvc_camera/camera_driver.h @@ -33,8 +33,17 @@ private: // Accept a reconfigure request from a client void ReconfigureCallback(UVCCameraConfig &config, uint32_t level); // Accept changes in values of automatically updated controls - void AutoControlsCallback(); - static void AutoControlsCallbackAdapter(void *ptr); + void AutoControlsCallback(enum uvc_status_class status_class, + int event, + int selector, + enum uvc_status_attribute status_attribute, + void *data, size_t data_len); + static void AutoControlsCallbackAdapter(enum uvc_status_class status_class, + int event, + int selector, + enum uvc_status_attribute status_attribute, + void *data, size_t data_len, + void *ptr); // Accept a new image frame from the camera void ImageCallback(uvc_frame_t *frame); static void ImageCallbackAdapter(uvc_frame_t *frame, void *ptr); @@ -42,7 +51,7 @@ private: ros::NodeHandle nh_, priv_nh_; State state_; - boost::mutex mutex_; + boost::recursive_mutex mutex_; uvc_context_t *ctx_; uvc_device_t *dev_; @@ -54,6 +63,7 @@ private: dynamic_reconfigure::Server<UVCCameraConfig> config_server_; UVCCameraConfig config_; + bool config_changed_; }; }; diff --git a/libuvc_camera/src/camera_driver.cpp b/libuvc_camera/src/camera_driver.cpp index a6a415911ae810652d77e87464d990dcbedd91a9..37610bc442c42afe5115d8a9c25ee5054d9772d8 100644 --- a/libuvc_camera/src/camera_driver.cpp +++ b/libuvc_camera/src/camera_driver.cpp @@ -14,7 +14,8 @@ CameraDriver::CameraDriver(ros::NodeHandle nh, ros::NodeHandle priv_nh) state_(kInitial), ctx_(NULL), dev_(NULL), devh_(NULL), rgb_frame_(NULL), it_(nh_), - config_server_(priv_nh_) { + config_server_(mutex_, priv_nh_), + config_changed_(false) { cam_pub_ = it_.advertiseCamera("image_raw", 1, false); } @@ -46,7 +47,7 @@ bool CameraDriver::Start() { } void CameraDriver::Stop() { - boost::mutex::scoped_lock(mutex_); + boost::recursive_mutex::scoped_lock(mutex_); if (state_ == kRunning) { CloseCamera(); @@ -55,7 +56,7 @@ void CameraDriver::Stop() { } void CameraDriver::ReconfigureCallback(UVCCameraConfig &new_config, uint32_t level) { - boost::mutex::scoped_lock(mutex_); + boost::recursive_mutex::scoped_lock(mutex_); if (level & dynamic_reconfigure::SensorLevels::RECONFIGURE_CLOSE) { if (state_ == kRunning) @@ -69,6 +70,10 @@ void CameraDriver::ReconfigureCallback(UVCCameraConfig &new_config, uint32_t lev if (state_ == kRunning) { // TODO: scanning_mode // TODO: auto_exposure + if (new_config.auto_exposure != config_.auto_exposure) { + if (uvc_set_ae_mode(devh_, 1 << new_config.auto_exposure)) + ROS_WARN("Unable to set auto_exposure to %d", new_config.auto_exposure); + } // TODO: auto_exposure_priority // TODO: exposure_absolute // TODO: iris_absolute @@ -97,7 +102,7 @@ void CameraDriver::ReconfigureCallback(UVCCameraConfig &new_config, uint32_t lev } void CameraDriver::ImageCallback(uvc_frame_t *frame) { - boost::mutex::scoped_lock(mutex_); + boost::recursive_mutex::scoped_lock(mutex_); assert(state_ == kRunning); assert(rgb_frame_); @@ -118,6 +123,11 @@ void CameraDriver::ImageCallback(uvc_frame_t *frame) { memcpy(&(image.data[0]), rgb_frame_->data, rgb_frame_->data_bytes); cam_pub_.publish(image, sensor_msgs::CameraInfo()); + + if (config_changed_) { + config_server_.updateConfig(config_); + config_changed_ = false; + } } /* static */ void CameraDriver::ImageCallbackAdapter(uvc_frame_t *frame, void *ptr) { @@ -126,15 +136,59 @@ void CameraDriver::ImageCallback(uvc_frame_t *frame) { driver->ImageCallback(frame); } -void CameraDriver::AutoControlsCallback() { - boost::mutex::scoped_lock(mutex_); - +void CameraDriver::AutoControlsCallback( + enum uvc_status_class status_class, + int event, + int selector, + enum uvc_status_attribute status_attribute, + void *data, size_t data_len) { + boost::recursive_mutex::scoped_lock(mutex_); + + printf("Controls callback. class: %d, event: %d, selector: %d, attr: %d, data_len: %u\n", + status_class, event, selector, status_attribute, data_len); + + if (status_attribute == UVC_STATUS_ATTRIBUTE_VALUE_CHANGE) { + switch (status_class) { + case UVC_STATUS_CLASS_CONTROL_CAMERA: { + switch (selector) { + case UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL: + uint8_t *data_char = (uint8_t*) data; + uint32_t exposure_int = ((data_char[0]) | (data_char[1] << 8) | + (data_char[2] << 16) | (data_char[3] << 24)); + config_.exposure_absolute = exposure_int * 0.0001; + config_changed_ = true; + break; + } + break; + } + case UVC_STATUS_CLASS_CONTROL_PROCESSING: { + switch (selector) { + case UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL: + uint8_t *data_char = (uint8_t*) data; + config_.white_balance_temperature = + data_char[0] | (data_char[1] << 8); + config_changed_ = true; + break; + } + break; + } + } + + // config_server_.updateConfig(config_); + } } -/* static */ void CameraDriver::AutoControlsCallbackAdapter(void *ptr) { +/* static */ void CameraDriver::AutoControlsCallbackAdapter( + enum uvc_status_class status_class, + int event, + int selector, + enum uvc_status_attribute status_attribute, + void *data, size_t data_len, + void *ptr) { CameraDriver *driver = static_cast<CameraDriver*>(ptr); - driver->AutoControlsCallback(); + driver->AutoControlsCallback(status_class, event, selector, + status_attribute, data, data_len); } void CameraDriver::OpenCamera(UVCCameraConfig &new_config) { @@ -166,6 +220,8 @@ void CameraDriver::OpenCamera(UVCCameraConfig &new_config) { return; } + uvc_set_status_callback(devh_, &CameraDriver::AutoControlsCallbackAdapter, this); + uvc_stream_ctrl_t ctrl; uvc_error_t mode_err = uvc_get_stream_ctrl_format_size( devh_, &ctrl,