00001
00002
00003 """
00004 Copyright 2013 Southwest Research Institute
00005
00006 Licensed under the Apache License, Version 2.0 (the "License");
00007 you may not use this file except in compliance with the License.
00008 You may obtain a copy of the License at
00009
00010 http://www.apache.org/licenses/LICENSE-2.0
00011
00012 Unless required by applicable law or agreed to in writing, software
00013 distributed under the License is distributed on an "AS IS" BASIS,
00014 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015 See the License for the specific language governing permissions and
00016 limitations under the License.
00017 """
00018
00019
00020 import sys
00021 import os
00022 import optparse
00023 import yaml
00024 import operator
00025 import thread
00026 import re
00027 import time
00028 import urllib2
00029 from Queue import Queue
00030 from threading import Thread, Timer
00031 from importlib import import_module
00032 from httplib import HTTPConnection
00033 from xml.etree import ElementTree
00034
00035
00036 import bridge_library
00037
00038
00039 path, file = os.path.split(__file__)
00040 sys.path.append(os.path.realpath(path) + '/src')
00041 from long_pull import LongPull
00042
00043
00044 import roslib
00045 import rospy
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068 class BridgePublisher():
00069
00070 def __init__(self):
00071
00072 rospy.init_node('bridge_publisher')
00073
00074
00075 self.config = bridge_library.obtain_dataMap()
00076 self.msg_parameters = ['url', 'url_port', 'machine_tool', 'xml_namespace']
00077 self.url = self.config[self.msg_parameters[0]]
00078 self.url_port = self.config[self.msg_parameters[1]]
00079 self.mtool = self.config[self.msg_parameters[2]]
00080 self.ns = dict(m = self.config[self.msg_parameters[3]])
00081
00082
00083 bridge_library.check_connectivity((1,self.url,self.url_port))
00084
00085
00086 self.topic_name_list = []
00087 self.topic_type_list = []
00088 self.lib_manifests = []
00089 self.data_items = []
00090 self.pub = []
00091 self.msg = []
00092 self.data_hold = None
00093
00094
00095 self.setup_topic_data()
00096
00097
00098 self.di_current = self.init_di_dict()
00099
00100
00101 self.di_changed = None
00102
00103
00104 while True:
00105 try:
00106 self.conn = HTTPConnection(self.url, self.url_port)
00107 response = bridge_library.xml_get_response((self.url, self.url_port, None, self.conn, self.mtool + "/current"))
00108 body = response.read()
00109 break
00110 except socket.error as e:
00111 rospy.loginfo('HTTP connection error %s' % e)
00112 time.sleep(10)
00113
00114
00115 seq, elements = bridge_library.xml_components(body, self.ns, self.di_current)
00116
00117
00118 for di in self.di_current.keys():
00119 name = bridge_library.split_event(di)
00120 for e in elements:
00121 rospy.loginfo('Element %s --> %s' % (e.tag, e.text))
00122 if name == e.attrib['name']:
00123 self.di_current[di] = e.text
00124
00125
00126 for di_set in self.data_items:
00127 if not set(di_set).issubset(set(self.di_current.keys())):
00128 rospy.logerr('ERROR: INCORRECT EVENTS IN TOPIC CONFIG OR XML AGENT FILE')
00129 sys.exit()
00130
00131
00132 response = bridge_library.xml_get_response((self.url, self.url_port, None, self.conn, self.mtool + "/sample?interval=1000&count=1000&from=" + seq))
00133
00134
00135 self.XML_queue = Queue()
00136
00137
00138 self.ros_publisher()
00139
00140
00141 lp = LongPull(response)
00142 lp.long_pull(self.xml_callback)
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157 def setup_topic_data(self):
00158 for topic_name, type_name in self.config.items():
00159 if topic_name not in self.msg_parameters:
00160
00161
00162 tn = type_name.keys()[0]
00163 tokens = tn.split('/')
00164 package = tokens[0]
00165 topic_type_name = tokens[1]
00166
00167
00168 if package not in self.lib_manifests:
00169 roslib.load_manifest(package)
00170 self.lib_manifests.append(package)
00171
00172
00173
00174 rospy.loginfo('Class Instance --> ' + package + '.msg.' + topic_type_name)
00175 type_handle = getattr(import_module(package + '.msg'), topic_type_name)
00176
00177
00178 self.data_items.append(self.config[topic_name][type_name.keys()[0]].keys())
00179
00180
00181 self.pub.append(rospy.Publisher(topic_name, type_handle))
00182
00183
00184 self.msg.append(type_handle())
00185
00186
00187 self.topic_name_list.append(topic_name)
00188 self.topic_type_list.append(type_name.keys()[0])
00189
00190 rospy.loginfo('TOPIC NAME LIST --> %s' % self.topic_name_list)
00191
00192 return
00193
00194
00195
00196
00197
00198 def init_di_dict(self):
00199 return {di:None for di_list in self.data_items for di in di_list}
00200
00201
00202
00203
00204
00205
00206
00207 def process_xml(self, xml):
00208 nextSeq, elements = bridge_library.xml_components(xml, self.ns, self.di_current)
00209
00210
00211 local_di = self.init_di_dict()
00212
00213
00214 di_list = [di_val for di_list in self.data_items for di_val in di_list]
00215
00216 if elements:
00217 rospy.logdebug('***********XML -->*************\n%s' % xml)
00218 for e in elements:
00219 for d_item in di_list:
00220 if e.attrib['name'] == bridge_library.split_event(d_item):
00221 local_di[d_item] = e.text
00222 self.di_current[d_item] = e.text
00223 break
00224 return nextSeq, local_di
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235 def topic_publisher(self, cb_data):
00236
00237 topic_name, topic_type, pub, msg, data_items = cb_data
00238
00239 msg.header.stamp = rospy.Time.now()
00240
00241 for di_name, value in self.di_changed.items():
00242
00243 if di_name in data_items:
00244 if value is not None:
00245
00246 conv_keys = self.config[topic_name][topic_type][di_name].keys()
00247 if value not in conv_keys:
00248 rospy.logerr("CONVERSION ERROR IN TOPIC CONFIG FILE: XML is '%s' --> CONFIG is %s" % (value, conv_keys))
00249 os._exit(0)
00250
00251
00252 ros_tag = self.config[topic_name][topic_type][di_name][self.di_changed[di_name]]
00253 else:
00254
00255 ros_tag = self.config[topic_name][topic_type][di_name][self.di_current[di_name]]
00256
00257
00258 name = bridge_library.split_event(di_name)
00259 state_object = operator.attrgetter(name + '.' + ros_tag)
00260 state_value = state_object(msg)
00261
00262
00263 attrib = getattr(msg, name)
00264
00265
00266 setattr(attrib, attrib.__slots__[0], state_value)
00267
00268 pub.publish(msg)
00269 return
00270
00271
00272
00273
00274
00275
00276 def xml_callback(self, chunk):
00277
00278 try:
00279 _, self.di_changed = self.process_xml(chunk)
00280 if self.di_changed is not None:
00281 self.XML_queue.put(self.di_changed)
00282 rospy.logdebug('PUTTING XML INTO QUEUE %s\tNUMBER OF QUEUED OBJECTS %s' % (self.XML_queue, self.XML_queue.qsize()))
00283 if self.XML_queue.qsize() > 1:
00284 rospy.loginfo('STORED XML INTO QUEUE, WAITING ON ROS PUBLISHER, QUEUE SIZE --> %s' % self.XML_queue.qsize())
00285 except Exception as e:
00286 rospy.logerr("Bridge Publisher: Process XML callback failed: %s, releasing lock" % e)
00287 finally:
00288 pass
00289
00290 return
00291
00292
00293
00294
00295 def ros_publisher(self):
00296
00297
00298
00299 ROSpub = Timer(0.1, self.ros_publisher)
00300 ROSpub.daemon = True
00301 ROSpub.start()
00302
00303
00304 if self.XML_queue.empty() and self.data_hold is not None:
00305 data = self.data_hold
00306 elif not self.XML_queue.empty():
00307 data = self.XML_queue.get()
00308 else:
00309
00310 data = None
00311
00312 try:
00313 if data != None:
00314
00315 publishers = []
00316 for topic_name, topic_type, pub, message, di in zip(self.topic_name_list, self.topic_type_list,
00317 self.pub, self.msg, self.data_items):
00318
00319 rospy.init_node('bridge_publisher')
00320 publishers.append(self.topic_publisher((topic_name, topic_type, pub, message, di)))
00321
00322
00323 self.di_changed = self.init_di_dict()
00324 except Exception as e:
00325 rospy.logerr("Bridge Publisher: ROS-Publisher callback failed: %s, releasing lock" % e)
00326 finally:
00327 if data != self.data_hold:
00328
00329 self.data_hold = data
00330 self.XML_queue.task_done()
00331 else:
00332 pass
00333
00334
00335 return
00336
00337 if __name__ == '__main__':
00338 try:
00339 rospy.loginfo('Launching Bridge Publisher -- Publishing Machine Tool Messages')
00340 mtc_parse = BridgePublisher()
00341 except rospy.ROSInterruptException:
00342 sys.exit(0)