$search
00001 /********************************************************************* 00002 * 00003 * Software License Agreement (BSD License) 00004 * 00005 * Copyright (c) 2011, Robert Bosch LLC. 00006 * All rights reserved. 00007 * 00008 * Redistribution and use in source and binary forms, with or without 00009 * modification, are permitted provided that the following conditions 00010 * are met: 00011 * 00012 * * Redistributions of source code must retain the above copyright 00013 * notice, this list of conditions and the following disclaimer. 00014 * * Redistributions in binary form must reproduce the above 00015 * copyright notice, this list of conditions and the following 00016 * disclaimer in the documentation and/or other materials provided 00017 * with the distribution. 00018 * * Neither the name of the Robert Bosch nor the names of its 00019 * contributors may be used to endorse or promote products derived 00020 * from this software without specific prior written permission. 00021 * 00022 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00023 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00024 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00025 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00026 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00027 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00028 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00029 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00030 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00031 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00032 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00033 * POSSIBILITY OF SUCH DAMAGE. 00034 * 00035 *********************************************************************/ 00036 00037 //\Author Philip Roan, Bosch LLC 00038 00039 #include <sys/socket.h> 00040 #include <netinet/in.h> 00041 #include <arpa/inet.h> 00042 #include <netdb.h> 00043 #include <ros/ros.h> 00044 #include "remote_power_manager.h" 00045 00046 00047 const char WILL = 251; 00048 const char WONT = 252; 00049 const char DO = 253; 00050 const char DONT = 254; 00051 const char IAC = 255; // control sequence 00052 const char ECHO = 1; // Echo commands 00053 const char SGA = 3; // Suppress Go-Ahead 00054 00055 const int SOCKET_BUFFER = 100; 00056 00057 RemotePowerManager::RemotePowerManager(const ros::NodeHandle& nh) : 00058 host_name_("butterbur"), 00059 host_port_(23), 00060 number_of_power_ports_(2), 00061 socket_(0) 00062 { 00063 // Getting parameters from .launch file 00064 nh.getParam("/remote_power_manager_node/host_name", host_name_); 00065 nh.getParam("/remote_power_manager_node/host_port", host_port_); 00066 nh.getParam("/remote_power_manager_node/number_of_power_ports", number_of_power_ports_); 00067 00068 //ROS_INFO("Retrieved parameters: %s %d %d", host_name_.c_str(), host_port_, number_of_power_ports_); 00069 00070 // Set defaults if unavailable? 00071 } 00072 00073 int RemotePowerManager::parseCommands(char* raw_message, int length, char* text_message) 00074 { 00075 int i = 0; 00076 int j = 0; 00077 char response[3]; 00078 00079 //ROS_INFO("Entering parse_commands"); 00080 for( i = 0; i < length; i++ ) 00081 { 00082 //ROS_INFO("i %d byte %u", i, raw_message[i] & 0xFF); 00083 if( raw_message[i] == IAC ) 00084 { 00085 switch( raw_message[++i] ) 00086 { 00087 case IAC: 00088 // escaped sequence, so put 255 into message 00089 text_message[j++] = 255; 00090 break; 00091 case DO: 00092 case DONT: 00093 case WILL: 00094 case WONT: 00095 //ROS_INFO("-i %d byte %u", i, raw_message[i] & 0xFF); 00096 // reply to all commands with "WONT" except SGA request 00097 response[0] = IAC; 00098 switch( raw_message[++i] ) 00099 { 00100 //case (char)1: //ECHO option 00101 case SGA: 00102 if( raw_message[i-1] == DO ) 00103 { 00104 response[1] = WILL; 00105 } 00106 else 00107 { 00108 response[1] = DO; 00109 } 00110 break; 00111 default: 00112 if( raw_message[i-1] == DO ) 00113 { 00114 response[1] = WONT; 00115 } 00116 else 00117 { 00118 response[1] = DONT; 00119 } 00120 break; 00121 } 00122 response[2] = raw_message[i]; 00123 //ROS_DEBUG("received: %u %u %u, responding: %u %u %u", 00124 // raw_message[i-2] & 0xFF, 00125 // raw_message[i-1] & 0xFF, 00126 // raw_message[i] & 0xFF, 00127 // response[0] & 0xFF, 00128 // response[1] & 0xFF, 00129 // response[2] & 0xFF); 00130 send( socket_, response, 3, 0); 00131 break; 00132 default: 00133 // unsupported command, ignore option 00134 ROS_WARN("Unsupported telnet command received: %u", raw_message[i] & 0xFF); 00135 i++; 00136 break; 00137 } 00138 } 00139 else 00140 { 00141 text_message[j++] = raw_message[i]; 00142 } 00143 } 00144 00145 return j; 00146 } 00147 00148 00149 bool RemotePowerManager::openConnection(void) 00150 { 00151 struct hostent *host; 00152 struct sockaddr_in server_addr; 00153 char recv_data[SOCKET_BUFFER]; 00154 char send_data[SOCKET_BUFFER]; 00155 char message[SOCKET_BUFFER]; 00156 int bytes_received; 00157 00158 host = gethostbyname( host_name_.c_str() ); 00159 00160 // Open socket 00161 if( (socket_ = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) 00162 { 00163 ROS_ERROR("Unable to open socket."); 00164 return false; 00165 } 00166 00167 server_addr.sin_family = AF_INET; 00168 server_addr.sin_port = htons( host_port_ ); 00169 server_addr.sin_addr = *((struct in_addr *)host->h_addr); 00170 bzero(&(server_addr.sin_zero),8); 00171 00172 // Connect to server 00173 if( connect(socket_, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1 ) 00174 { 00175 ROS_ERROR("Unable to connect to server."); 00176 return false; 00177 } 00178 00179 // Read intial response and parse for command signal IAC 00180 bytes_received = recv( socket_, recv_data, SOCKET_BUFFER, 0 ); 00181 if( bytes_received < SOCKET_BUFFER ) 00182 { 00183 recv_data[bytes_received] = '\0'; 00184 parseCommands(recv_data, bytes_received+1, message); 00185 } 00186 else 00187 { 00188 recv_data[bytes_received-1] = '\0'; 00189 parseCommands(recv_data, bytes_received, message); 00190 } 00191 ROS_DEBUG("Remote Power System login message:%s", message); 00192 00193 //Echo - the magic seems to be in sending two packets 00194 memset(send_data, '\n', 28); 00195 send( socket_, send_data, 28, 0 ); 00196 //for(int k = 0; k < strlen(send_data); k++) 00197 //{ 00198 // ROS_DEBUG("magic echo[%d]: %02x", k, send_data[k]); 00199 //} 00200 00201 return true; 00202 } 00203 00204 bool RemotePowerManager::closeConnection(void) 00205 { 00206 char send_data[SOCKET_BUFFER]; 00207 char recv_data[SOCKET_BUFFER]; 00208 int bytes_received; 00209 00210 // Client is closing connection 00211 00212 sprintf( send_data, "$A2\r"); 00213 00214 send( socket_, send_data, strlen(send_data), 0); 00215 bytes_received = recv( socket_, recv_data, SOCKET_BUFFER, 0 ); 00216 if( bytes_received < SOCKET_BUFFER ) 00217 { 00218 recv_data[bytes_received] = '\0'; 00219 } 00220 else 00221 { 00222 recv_data[bytes_received-1] = '\0'; 00223 } 00224 ROS_DEBUG("Closing connection to Remote Power Manager: %s", recv_data); 00225 00226 close(socket_); 00227 00228 return true; 00229 } 00230 00231 bool RemotePowerManager::sendCommand(const char command[], char reply[]) 00232 { 00233 int bytes_received; 00234 00235 // Send command 00236 send(socket_, command, strlen(command), 0); 00237 00238 // Copy received data from the socket 00239 bytes_received = recv( socket_, reply, SOCKET_BUFFER, 0 ); 00240 if( bytes_received < SOCKET_BUFFER ) 00241 { 00242 reply[bytes_received] = '\0'; 00243 } 00244 else 00245 { 00246 reply[bytes_received-1] = '\0'; 00247 } 00248 00249 ROS_DEBUG("Received %d bytes from Remote Power Manager: %s", bytes_received, reply); 00250 if( strstr( reply, "$A0" ) != NULL ) 00251 { 00252 return true; 00253 } 00254 else if( strstr( reply, "$AF" ) != NULL ) 00255 { 00256 return false; 00257 } 00258 else 00259 { 00260 ROS_WARN("Unknown response from remote power manager."); 00261 return false; 00262 } 00263 } 00264 00265 00266 bool RemotePowerManager::getPortStatus( remote_power_manager::GetPortStatus::Request &req, 00267 remote_power_manager::GetPortStatus::Response &res ) 00268 { 00269 char reply[SOCKET_BUFFER]; 00270 char* p_status; 00271 00272 if( openConnection() == false ) 00273 { 00274 return false; 00275 } 00276 00277 if( sendCommand("\r$A5\r", reply) ) 00278 { 00279 res.value.port_status.clear(); 00280 // parse first comma 00281 p_status = strchr( reply, ',' ); 00282 if( p_status != NULL ) 00283 { 00284 for( int i = 0; i < number_of_power_ports_; i++ ) 00285 { 00286 p_status++; 00287 if( *p_status == '1' ) 00288 { 00289 res.value.port_status.insert(res.value.port_status.begin(), true); 00290 } 00291 else 00292 { 00293 res.value.port_status.insert(res.value.port_status.begin(), false); 00294 } 00295 } 00296 closeConnection(); 00297 return true; 00298 } 00299 else 00300 { 00301 ROS_WARN("Failed to get port status from remote power manager."); 00302 closeConnection(); 00303 return false; 00304 } 00305 } 00306 else 00307 { 00308 ROS_WARN("Failed to get port status from remote power manager."); 00309 closeConnection(); 00310 return false; 00311 } 00312 } 00313 00314 bool RemotePowerManager::setAllRelay( remote_power_manager::SetAllRelay::Request &req, 00315 remote_power_manager::SetAllRelay::Response &res ) 00316 { 00317 char command[SOCKET_BUFFER]; 00318 char reply[SOCKET_BUFFER]; 00319 00320 if( openConnection() == false ) 00321 { 00322 return false; 00323 } 00324 00325 sprintf( command, "\r$A7 %d\r", (int)req.value ); 00326 00327 if( sendCommand(command, reply) ) 00328 { 00329 closeConnection(); 00330 res.return_code = true; 00331 return true; 00332 } 00333 else 00334 { 00335 ROS_WARN("Failed to set all relays to \"%d\" on remote power manager.", (int)req.value); 00336 closeConnection(); 00337 res.return_code = true; 00338 return false; 00339 } 00340 } 00341 00342 00343 bool RemotePowerManager::setPortRelay( remote_power_manager::SetPortRelay::Request &req, 00344 remote_power_manager::SetPortRelay::Response &res ) 00345 { 00346 char command[SOCKET_BUFFER]; 00347 char reply[SOCKET_BUFFER]; 00348 00349 if( openConnection() == false ) 00350 { 00351 return false; 00352 } 00353 00354 sprintf( command, "\r$A3 %ld %d\r", req.power_port, (int)req.value ); 00355 00356 if( sendCommand(command, reply) ) 00357 { 00358 closeConnection(); 00359 res.return_code = true; 00360 return true; 00361 } 00362 else 00363 { 00364 ROS_WARN("Failed to set relay %ld to \"%d\" on remote power manager.", req.power_port, (int)req.value); 00365 closeConnection(); 00366 res.return_code = true; 00367 return false; 00368 } 00369 } 00370 00371 00372 00373 bool RemotePowerManager::rebootPort( remote_power_manager::RebootPort::Request &req, 00374 remote_power_manager::RebootPort::Response &res ) 00375 { 00376 char command[SOCKET_BUFFER]; 00377 char reply[SOCKET_BUFFER]; 00378 00379 if( openConnection() == false ) 00380 { 00381 return false; 00382 } 00383 sprintf( command, "\r$A4 %ld\r", req.power_port ); 00384 00385 if( sendCommand(command, reply) ) 00386 { 00387 closeConnection(); 00388 res.return_code = true; 00389 return true; 00390 } 00391 else 00392 { 00393 ROS_WARN("Failed to reboot relay %ld on remote power manager.", req.power_port); 00394 closeConnection(); 00395 res.return_code = true; 00396 return false; 00397 } 00398 } 00399 00400 00405 int main(int argc, char **argv) 00406 { 00407 ros::init(argc, argv, "remote_power_manager_node"); 00408 00409 ros::NodeHandle nh; 00410 RemotePowerManager rmp = RemotePowerManager(nh); 00411 00412 00413 ros::ServiceServer service_handle_1 = nh.advertiseService("remote_power_manager/get_port_status", 00414 &RemotePowerManager::getPortStatus, &rmp); 00415 ros::ServiceServer service_handle_2 = nh.advertiseService("remote_power_manager/set_all_relay", 00416 &RemotePowerManager::setAllRelay, &rmp); 00417 ros::ServiceServer service_handle_3 = nh.advertiseService("remote_power_manager/set_port_relay", 00418 &RemotePowerManager::setPortRelay, &rmp); 00419 ros::ServiceServer service_handle_4 = nh.advertiseService("remote_power_manager/reboot_port", 00420 &RemotePowerManager::rebootPort, &rmp); 00421 00422 ros::spin(); 00423 00424 return 0; 00425 }