00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069 #include <ros/ros.h>
00070 #include <dynamic_reconfigure/server.h>
00071 #include <uavc_v4lctl/v4lctlNodeDynConfig.h>
00072 #include <uavc_v4lctl/v4lctlSet.h>
00073 #include <uavc_v4lctl/v4lctlGet.h>
00074 #include <opencv2/opencv.hpp>
00075 #include <boost/algorithm/string/replace.hpp>
00076 #include <boost/regex.hpp>
00077 #include <sstream>
00078 #include <map>
00079
00080 #define YAML_OPT_TO_NAME(s) boost::replace_all_copy(boost::replace_all_copy(s,"\"","-")," ","_")
00081 #define YAML_NAME_TO_OPT(s) boost::replace_all_copy(boost::replace_all_copy(s,"-","\""),"_"," ")
00082
00083 namespace uavc_v4lctl {
00084
00085 class v4lctlNode
00086 {
00087 ros::NodeHandle nh_;
00088
00089 ros::ServiceServer srv_v4lctl_get_;
00090 ros::ServiceServer srv_v4lctl_set_;
00091
00092 v4lctlNodeDynConfig cfg_;
00093 dynamic_reconfigure::Server<v4lctlNodeDynConfig> cfg_server_;
00094
00095 std::map<std::string, std::string> fs_map_;
00096
00097 std::string device_;
00098 std::string yaml_;
00099
00100 public:
00101
00102 v4lctlNode()
00103 {
00104 ros::NodeHandle pnh("~");
00105
00106 pnh.param<std::string>("device", device_, "/dev/video0");
00107 pnh.param<std::string>("yaml", yaml_, "");
00108
00109 if (!yaml_.empty())
00110 restoreFromYaml();
00111
00112 cfg_server_.setCallback(boost::bind(&v4lctlNode::configCb, this, _1, _2));
00113
00114 srv_v4lctl_set_ = nh_.advertiseService("v4lctlSet", &v4lctlNode::v4lctlSetCb, this);
00115 srv_v4lctl_get_ = nh_.advertiseService("v4lctlGet", &v4lctlNode::v4lctlGetCb, this);
00116 }
00117
00118 ~v4lctlNode()
00119 {
00120 cv::FileStorage fs;
00121
00122 if (!yaml_.empty() && fs.open(yaml_, cv::FileStorage::WRITE))
00123 {
00124 std::map<std::string, std::string>::iterator it = fs_map_.begin();
00125
00126 while (it != fs_map_.end())
00127 {
00128 std::string key = (*it).first;
00129
00130 fs << key << fs_map_[key];
00131 it++;
00132 }
00133 }
00134 }
00135
00136 std::string v4lctlGet(std::string name)
00137 {
00138 FILE *pipe;
00139 char stdout[128];
00140 std::string result;
00141 std::stringstream ss;
00142
00143 ss << "v4lctl -c " << device_ << " show \"" << name << "\"";
00144
00145 if ((pipe=popen(ss.str().c_str(), "r")))
00146 {
00147 if (fgets(stdout, sizeof(stdout), pipe))
00148 result = boost::regex_replace(std::string(stdout), boost::regex("^" + name + ": ([a-zA-Z0-9\\-]+).*"), "$1");
00149
00150 ROS_INFO_STREAM("Call '" << ss.str() << "' Result: " << result);
00151
00152 pclose(pipe);
00153 }
00154 else
00155 ROS_ERROR_STREAM("Call failed '" << ss.str() << "'");
00156
00157 return result;
00158 }
00159
00160 bool v4lctlSet(std::string name, std::string value)
00161 {
00162 std::stringstream ss;
00163 bool result = false;
00164
00165 ss << "v4lctl -c " << device_ << " " << name << " " << value;
00166
00167 ROS_INFO_STREAM("Call '" << ss.str() << "'");
00168
00169 if ((result=std::system(ss.str().c_str()) > -1))
00170 fs_map_[YAML_OPT_TO_NAME(name)] = value;
00171
00172 return result;
00173 }
00174
00175 void restoreFromYaml()
00176 {
00177 cv::FileStorage fs;
00178
00179 if (fs.open(yaml_, cv::FileStorage::READ))
00180 {
00181 cv::FileNode fn = fs.root();
00182
00183 for (cv::FileNodeIterator fit = fn.begin(); fit != fn.end(); fit++)
00184 {
00185 cv::FileNode item = *fit;
00186
00187 v4lctlSet(YAML_NAME_TO_OPT(item.name()), (std::string)item);
00188 }
00189 }
00190 }
00191
00192 void initConfig(v4lctlNodeDynConfig &config, bool defaults = false)
00193 {
00194 std::string s;
00195
00196 #define V4LCTL_GET_PERCENT(name,default,max) (defaults || (s=v4lctlGet(name)).empty() ? default : (atoi(s.c_str()) * 100 / max))
00197 #define V4LCTL_GET_BOOL(name,default) (defaults || (s=v4lctlGet(name)).empty() ? default : boost::regex_match(s, boost::regex("^on\$")))
00198 #define V4LCTL_GET_INT(name,default) (defaults || (s=v4lctlGet(name)).empty() ? default : atoi(s.c_str()))
00199 #define V4LCTL_GET_STRING(name,default) (defaults || (s=v4lctlGet(name)).empty() ? default : s)
00200
00201 config.input = V4LCTL_GET_STRING ("input", "Composite0");
00202 config.norm = V4LCTL_GET_STRING ("norm", "PAL-I");
00203 config.bright = V4LCTL_GET_PERCENT("bright", 50, 65280);
00204 config.contrast = V4LCTL_GET_PERCENT("contrast", 40, 65280);
00205 config.color = V4LCTL_GET_PERCENT("color", 50, 65280);
00206 config.hue = V4LCTL_GET_PERCENT("hue", 50, 65280);
00207 config.UV_Ratio = V4LCTL_GET_INT ("UV Ratio", 50);
00208 config.Coring = V4LCTL_GET_INT ("Coring", 0);
00209 config.Whitecrush_Lower = V4LCTL_GET_PERCENT("Whitecrush Lower", 50, 255);
00210 config.Whitecrush_Upper = V4LCTL_GET_PERCENT("Whitecrush Upper", 80, 255);
00211 config.mute = V4LCTL_GET_BOOL ("mute", false);
00212 config.Chroma_AGC = V4LCTL_GET_BOOL ("Chroma AGC", false);
00213 config.Color_Killer = V4LCTL_GET_BOOL ("Color Killer", false);
00214 config.Comb_Filter = V4LCTL_GET_BOOL ("Comb Filter", false);
00215 config.Auto_Mute = V4LCTL_GET_BOOL ("Auto Mute", true);
00216 config.Luma_Decim = V4LCTL_GET_BOOL ("Luma Decimation Filter", false);
00217 config.AGC_Crush = V4LCTL_GET_BOOL ("AGC Crush", true);
00218 config.VCR_Hack = V4LCTL_GET_BOOL ("VCR Hack", false);
00219 config.Full_Luma = V4LCTL_GET_BOOL ("Full Luma Range", false);
00220 }
00221
00222 void configCb(v4lctlNodeDynConfig &config, int level)
00223 {
00224 if (level < 0)
00225 {
00226 initConfig(config);
00227 cfg_ = config;
00228
00229 ROS_INFO("Reconfigure server initialized");
00230
00231 return;
00232 }
00233
00234 if (config.Set_Defaults)
00235 {
00236 initConfig(config, true);
00237 config.Set_Defaults = false;
00238 }
00239
00240 if (config.input != cfg_.input)
00241 v4lctlSet("setattr input", config.input);
00242
00243 if (config.norm != cfg_.norm)
00244 v4lctlSet("setnorm", config.norm);
00245
00246 if (config.bright != cfg_.bright)
00247 v4lctlSet("bright", std::to_string(config.bright)+'%');
00248
00249 if (config.contrast != cfg_.contrast)
00250 v4lctlSet("contrast", std::to_string(config.contrast)+'%');
00251
00252 if (config.color != cfg_.color)
00253 v4lctlSet("color", std::to_string(config.color)+'%');
00254
00255 if (config.hue != cfg_.hue)
00256 v4lctlSet("hue", std::to_string(config.hue)+'%');
00257
00258 if (config.UV_Ratio != cfg_.UV_Ratio)
00259 v4lctlSet("setattr \"UV Ratio\"", std::to_string(config.UV_Ratio)+'%');
00260
00261 if (config.Coring != cfg_.Coring)
00262 v4lctlSet("setattr Coring", std::to_string(config.Coring));
00263
00264 if (config.Whitecrush_Lower != cfg_.Whitecrush_Lower)
00265 v4lctlSet("setattr \"Whitecrush Lower\"", std::to_string(config.Whitecrush_Lower)+'%');
00266
00267 if (config.Whitecrush_Upper != cfg_.Whitecrush_Upper)
00268 v4lctlSet("setattr \"Whitecrush Upper\"", std::to_string(config.Whitecrush_Upper)+'%');
00269
00270 if (config.mute != cfg_.mute)
00271 v4lctlSet("setattr mute", config.mute ? "on" : "off");
00272
00273 if (config.Chroma_AGC != cfg_.Chroma_AGC)
00274 v4lctlSet("setattr \"Chroma AGC\"", config.Chroma_AGC ? "on" : "off");
00275
00276 if (config.Color_Killer != cfg_.Color_Killer)
00277 v4lctlSet("setattr \"Color Killer\"", config.Color_Killer ? "on" : "off");
00278
00279 if (config.Comb_Filter != cfg_.Comb_Filter)
00280 v4lctlSet("setattr \"Comb Filter\"", config.Comb_Filter ? "on" : "off");
00281
00282 if (config.Auto_Mute != cfg_.Auto_Mute)
00283 v4lctlSet("setattr \"Auto Mute\"", config.Auto_Mute ? "on" : "off");
00284
00285 if (config.Luma_Decim != cfg_.Luma_Decim)
00286 v4lctlSet("setattr \"Luma Decimation Filter\"", config.Luma_Decim ? "on" : "off");
00287
00288 if (config.AGC_Crush != cfg_.AGC_Crush)
00289 v4lctlSet("setattr \"AGC Crush\"", config.AGC_Crush ? "on" : "off");
00290
00291 if (config.VCR_Hack != cfg_.VCR_Hack)
00292 v4lctlSet("setattr \"VCR Hack\"", config.VCR_Hack ? "on" : "off");
00293
00294 if (config.Full_Luma != cfg_.Full_Luma)
00295 v4lctlSet("setattr \"Full Luma Range\"", config.Full_Luma ? "on" : "off");
00296
00297 cfg_ = config;
00298 }
00299
00300 bool v4lctlGetCb(v4lctlGet::Request &req, v4lctlGet::Response &res)
00301 {
00302 res.result = v4lctlGet(req.name);
00303
00304 return true;
00305 }
00306
00307 bool v4lctlSetCb(v4lctlSet::Request &req, v4lctlSet::Response &res)
00308 {
00309 return v4lctlSet(req.name, req.value);
00310 }
00311 };
00312
00313 }
00314
00315 int main(int argc, char **argv)
00316 {
00317 ros::init(argc, argv, "v4lctl");
00318
00319 uavc_v4lctl::v4lctlNode n;
00320
00321 ros::spin();
00322
00323 return 0;
00324 }