class ComPort(object): re_data = re.compile(r'(?:<)(?P<cmd>\d+)(?:>)(.*)(?:<\/)(?P=cmd)(?:>)', re.DOTALL) re_next_cmd = re.compile("(?:<)(\d+)(?:>\{\"cmd\":\")") redis_pub_channel = 'data' def __init__(self, port = '/dev/ttyUSB0', packet_timeout=1, baudrate=115200, bytesize=8, parity='N', stopbits=1, xonxoff=0, rtscts=0, writeTimeout=None, dsrdtr=None, host='127.0.0.1', run=True): self.buffer = '' self.last_read_line = '' self.serial = serial.Serial(port, baudrate, bytesize, parity, stopbits, packet_timeout, xonxoff, rtscts, writeTimeout, dsrdtr) self.signature = "{0:s}:{1:s}".format(get_host_ip(), self.serial.port) self.redis_send_key = self.signature+'-send' self.redis_read_key = self.signature+'-read' self.redis = redis.Redis(host=host) logger_name = 'sermon.py:{}'.format(self.signature) if sys.stdout.isatty(): self.log = Logger(logger_name) else: self.log = logger.RedisLogger(logger_name) self.log.addHandler(handlers.RedisHandler.to("log", host='localhost', port=6379)) self.log.level = 1 self.alive = False self._reader_alive = False # TODO add checking for redis presence and connection if self.redis.ping(): # Register the new instance with the redis exchange if not self.redis.sismember(EXCHANGE,self.signature): self.redis.sadd(EXCHANGE,self.signature) else: pass if run: self.run() def __del__(self): self.log.debug("About to delete the object") self.close() time.sleep(1) self.log.debug("Closing serial interface") self.serial.close() if self.serial.closed: self.log.error("The serial connection still appears to be open") else: self.log.debug("The serial connection is closed") self.log.debug("Object deleted") if self.redis.sismember('ComPort',self.signature): self.redis.srem('ComPort',self.signature) # Thread control def run(self): self.log.debug('run()') self._start_reader() self._start_listner() def _start_reader(self): """Start reader thread""" self.log.debug("Start serial port reader thread") self.alive = True self._reader_alive = True self.receiver_thread = threading.Thread(target=self.reader) self.receiver_thread.setDaemon(True) self.receiver_thread.start() def _stop_reader(self): """Stop reader thread only, wait for clean exit of thread""" self.log.debug("Stop reader thread only, wait for clean exit of thread") self._reader_alive = False self.receiver_thread.join() def _start_listner(self): self.log.debug("Start redis sub channel and listen for commands send via redis") self._redis_subscriber_alive = True self.redis_subscriber_thread = threading.Thread(target=self.cmd_via_redis_subscriber) self.redis_subscriber_thread.setDaemon(True) self.redis_subscriber_thread.start() def cmd_via_redis_subscriber(self): self.log.debug('cmd_via_redis_subscriber(channel={})'.format(self.signature)) self.pubsub = self.redis.pubsub() self.pubsub.subscribe(self.signature) while self._redis_subscriber_alive: try: for item in self.pubsub.listen(): if item['data'] == "unsubscribe": self.pubsub.unsubscribe() self.log.info("unsubscribed and finished") break else: cmd = item['data'] if isinstance(cmd,str): self.log.debug(cmd) self.send(item['data']) else: self.log.debug(cmd) except Exception as E: error_msg = 'error: {}'.format(E.message) self.log.error(error_msg) self.pubsub.unsubscribe() self.log.debug('end of cmd_via_redis_subscriber()') def stop(self): self.alive = False def join(self, transmit_only=False): self.transmitter_thread.join() if not transmit_only: self.receiver_thread.join() def start_thread(self): ''' Open the serial serial bus to be read. This starts the listening thread. ''' self.log.debug('start_thread()') self.serial.flushInput() self.running.set() self.start() def open(self): if not self.serial.isOpen(): self.serial.open() return self.serial.isOpen() def send(self, data, CR=True): '''Send command to the serial port ''' if len(data) == 0: return self.log.debug("send(cmd=%s)" % data) # Automatically append \n by default, but allow the user to send raw characters as well if CR: if (data[-1] == "\n"): pass else: data += "\n" if self.open(): try: self.serial.write(data) serial_error = 0 except: serial_error = 1 else: serial_error = 2 self.redis.set(self.redis_send_key,data) return serial_error def read(self, waitfor=''): ''' reads the data by waiting until new comport is found in the buffer and result can be read from the redis server ''' serial_data = '' done = False to = time.clock() while time.clock() - to < TIMEOUT and not done: if self.alive and self._reader_alive: serial_data = self.redis.get(self.redis_read_key) done = waitfor in self.buffer and isinstance(serial_data,str) else: self.read_serial_data() done = waitfor in self.buffer and isinstance(serial_data,str) if not done: self.log.debug("read() did not find waitfor {:s} in self.buffer".format(waitfor)) self.redis.delete(self.redis_read_key) return [done, serial_data] def query(self,cmd, **kwargs): """ sends cmd to the controller and waits until waitfor is found in the buffer. """ waitfor = kwargs.get('waitfor','') tag = kwargs.get('tag','') json = kwargs.get('json',1) delay = kwargs.get('delay',0.01) if len(waitfor) < 1: next_cmd_num = self.re_next_cmd.findall(self.buffer) if len(next_cmd_num) > 0: waitfor = '<{:d}>{:s}"cmd":"'.format(int(next_cmd_num[0])+1,"{") self.log.debug('query(cmd=%s, waitfor=%s, tag=%s,json=%d, delay=%d):' % \ (cmd, waitfor, tag, json, delay)) self.send(cmd) time.sleep(delay) query_data = self.read(waitfor=waitfor) if query_data[0]: try: query_data[1] = sjson.loads(query_data[1]) except: query_data[0] = False return query_data def close(self): ''' Close the listening thread. ''' self.log.debug('close() - closing the worker thread') self.alive = False self._reader_alive = False self._redis_subscriber_alive = False self.receiver_thread.join() def reader(self): ''' Run is the function that runs in the new thread and is called by ''' try: self.log.debug('Starting the listner thread') Msg = Message(self.signature) while self.alive and self._reader_alive: bytes_in_waiting = self.serial.inWaiting() if bytes_in_waiting: new_data = self.serial.read(bytes_in_waiting) self.buffer = self.buffer + new_data else: sleep(0.1) crlf_index = self.buffer.find('\r\n') if crlf_index > -1: line = self.buffer[0:crlf_index] temp = self.re_data.findall(line) self.log.debug('read line: ' + line) if len(temp): final_data = dict() timestamp = datetime.now().strftime('%Y-%m-%d-%H:%M:%S') final_data['timestamp'] = timestamp final_data['raw'] = line try: final_data.update({'cmd_number' : sjson.loads(temp[0][0])}) final_data.update(sjson.loads(temp[0][1])) self.log.debug('.....updated final_data') except Exception as E: final_data.update({'cmd_number' : -1}) error_msg = {'timestamp' : timestamp, 'from': self.signature, 'source' : 'ComPort', 'function' : 'def run() - inner', 'error' : E.message} Msg.msg = error_msg self.log.error(Msg.msg) Msg.msg = final_data self.log.debug("final_data={}".format(final_data)) self.redis.publish(self.redis_pub_channel, Msg.as_jsno()) #self.log.debug('.....publish to :' + self.redis_pub_channel) self.redis.set(self.redis_read_key,Msg.as_jsno()) self.buffer = self.buffer[crlf_index+2:] #self.log.debug('.....empty buffer') else: #self.buffer = '' #self.send('Z') #self.log.debug('.....reseting command number') pass except Exception as E: error_msg = {'source' : 'ComPort', 'function' : 'def run() - outter', 'error' : E.message} self.log.error("Exception occured, within the run function: %s" % E.message) self.log.debug('Exiting run() function') def read_serial_data(self): Msg = Message(self.signature) bytes_in_waiting = self.serial.inWaiting() if bytes_in_waiting: new_data = self.serial.read(bytes_in_waiting) self.buffer = self.buffer + new_data else: sleep(0.1) crlf_index = self.buffer.find('\r\n') if crlf_index > -1: self.last_read_line = self.buffer[0:crlf_index] temp = self.re_data.findall(self.last_read_line) self.log.debug('read self.last_read_line: ' + self.last_read_line) if len(temp): final_data = dict() timestamp = datetime.now().strftime('%Y-%m-%d-%H:%M:%S') final_data['timestamp'] = timestamp final_data['raw'] = self.last_read_line try: final_data.update({'cmd_number' : sjson.loads(temp[0][0])}) final_data.update(sjson.loads(temp[0][1])) self.log.debug('.....updated final_data') except Exception as E: final_data.update({'cmd_number' : -1}) error_msg = {'timestamp' : timestamp, 'from': self.signature, 'source' : 'ComPort', 'function' : 'def run() - inner', 'error' : E.message} Msg.msg = error_msg self.log.error(Msg.msg) Msg.msg = final_data self.log.debug("final_data={}".format(final_data)) self.redis.publish(self.redis_pub_channel, Msg.as_jsno()) #self.log.debug('.....publish to :' + self.redis_pub_channel) self.redis.set(self.redis_read_key,Msg.as_jsno()) #self.log.debug('.....empty buffer') self.buffer = self.buffer[crlf_index+2:] else: self.buffer = '' self.send('Z') self.log.debug('.....reseting command number') pass
def main(**kwargs): try: while True: sleep(0.1) pass except KeyboardInterrupt: pass if __name__ == '__main__': arguments = docopt(__doc__, version='Naval Fate 2.0') if sys.stdout.isatty(): mainlog = Logger('sermon.py:main') else: mainlog = logger.RedisLogger('sermon.py:main') mainlog.addHandler(handlers.RedisHandler.to("log", host='localhost', port=6379)) mainlog.info("========= __main__ ============") mainlog.info(arguments) dev = arguments['--dev'] mainlog.info(dev) test_json = arguments['test'] run_main = arguments['run'] one_wire = arguments['1wire'] redis_host = arguments.get('--redishost',get_host_ip()) run_local = arguments.get('--local',False) if run_local: