openrvdas.logger.utils.simulate_serial
No module-level documentation available.
1#!/usr/bin/env python3 2 3import logging 4import os.path 5import subprocess 6import threading 7import time 8 9from logger.readers.logfile_reader import LogfileReader # noqa: E402 10from logger.transforms.slice_transform import SliceTransform # noqa: E402 11from logger.writers.text_file_writer import TextFileWriter # noqa: E402 12 13from logger.utils.read_config import read_config # noqa: E402 14from logger.utils.timestamp import TIME_FORMAT # noqa: E402 15 16 17class SimSerial: 18 """Create a virtual serial port and feed stored logfile data to it.""" 19 ############################ 20 21 def __init__(self, port, source_file, time_format=TIME_FORMAT, 22 use_timestamps=True, 23 baudrate=9600, bytesize=8, parity='N', stopbits=1, 24 timeout=None, xonxoff=False, rtscts=False, write_timeout=None, 25 dsrdtr=False, inter_byte_timeout=None, exclusive=None): 26 """Takes source file, whether to deliver data at rate indicated by 27 timestamps, and the standard parameters that a serial port takes.""" 28 29 # flake8: noqa: E501 30 logging.warning('simulate_serial.SimSerial is deprecated in favor of simulate_data.SimSerial') 31 32 self.source_file = source_file 33 self.use_timestamps = use_timestamps 34 self.time_format = time_format 35 36 # We'll create two virtual ports: 'port' and 'port_in'; we will write 37 # to port_in and read the values back out from port 38 self.read_port = port 39 self.write_port = port + '_in' 40 41 self.serial_params = {'baudrate': baudrate, 42 'byteside': bytesize, 43 'parity': parity, 44 'stopbits': stopbits, 45 'timeout': timeout, 46 'xonxoff': xonxoff, 47 'rtscts': rtscts, 48 'write_timeout': write_timeout, 49 'dsrdtr': dsrdtr, 50 'inter_byte_timeout': inter_byte_timeout, 51 'exclusive': exclusive} 52 self.quit = False 53 54 # Finally, find path to socat executable 55 self.socat_path = None 56 for socat_path in ['/usr/bin/socat', '/usr/local/bin/socat']: 57 if os.path.exists(socat_path) and os.path.isfile(socat_path): 58 self.socat_path = socat_path 59 if not self.socat_path: 60 raise NameError('Executable "socat" not found on path. Please refer ' 61 'to installation guide to install socat.') 62 63 ############################ 64 def _run_socat(self): 65 """Internal: run the actual command.""" 66 verbose = '-d' 67 write_port_params = 'pty,link=%s,raw,echo=0' % self.write_port 68 read_port_params = 'pty,link=%s,raw,echo=0' % self.read_port 69 70 cmd = [self.socat_path, 71 verbose, 72 # verbose, # repeating makes it more verbose 73 read_port_params, 74 write_port_params, 75 ] 76 try: 77 # Run socat process using Popen, checking every second or so whether 78 # it's died (poll() != None) or we've gotten a quit signal. 79 logging.info('Calling: %s', ' '.join(cmd)) 80 socat_process = subprocess.Popen(cmd) 81 while not self.quit and not socat_process.poll(): 82 try: 83 socat_process.wait(1) 84 except subprocess.TimeoutExpired: 85 pass 86 87 except Exception as e: 88 logging.error('ERROR: socat command: %s', e) 89 90 # If here, process has terminated, or we've seen self.quit. We 91 # want both to be true: if we've terminated, set self.quit so that 92 # 'run' loop can exit. If self.quit, terminate process. 93 if self.quit: 94 socat_process.kill() 95 else: 96 self.quit = True 97 logging.info('Finished: %s', ' '.join(cmd)) 98 99 ############################ 100 def run(self, loop=False): 101 """Create the virtual port with socat and start feeding it records from 102 the designated logfile. If loop==True, loop when reaching end of input.""" 103 self.socat_thread = threading.Thread(target=self._run_socat, daemon=True) 104 self.socat_thread.start() 105 time.sleep(0.2) 106 107 self.reader = LogfileReader(filebase=self.source_file, 108 use_timestamps=self.use_timestamps, 109 time_format=self.time_format) 110 111 self.strip = SliceTransform('1:') # strip off the first field) 112 self.writer = TextFileWriter(self.write_port, truncate=True) 113 114 while not self.quit: 115 try: 116 record = self.reader.read() # get the next record 117 logging.debug('SimSerial got: %s', record) 118 119 # End of input? If loop==True, re-open the logfile from the start 120 if record is None: 121 if not loop: 122 break 123 self.reader = LogfileReader(filebase=self.source_file, 124 use_timestamps=self.use_timestamps) 125 126 record = self.strip.transform(record) # strip the timestamp 127 if record: 128 logging.debug('SimSerial writing: %s', record) 129 self.writer.write(record) # and write it to the virtual port 130 except (OSError, KeyboardInterrupt): 131 break 132 133 # If we're here, we got None from our input, and are done. Signal 134 # for run_socat to exit 135 self.quit = True 136 137 138################################################################################ 139if __name__ == '__main__': 140 import argparse 141 parser = argparse.ArgumentParser() 142 143 parser.add_argument('--config', dest='config', default=None, 144 help='Config file of JSON specs for port-file mappings.') 145 146 parser.add_argument('--logfile', dest='logfile', 147 help='Log file to read from.') 148 149 parser.add_argument('--time_format', dest='time_format', default=TIME_FORMAT, 150 help='Format string for parsing timestamp') 151 152 parser.add_argument('--loop', dest='loop', action='store_true', 153 help='If True, loop when reaching end of sample data') 154 155 parser.add_argument('--port', dest='port', 156 help='Virtual serial port to open') 157 parser.add_argument('--baud', dest='baud', type=int, 158 help='Baud rate for port.') 159 160 parser.add_argument('-v', '--verbosity', dest='verbosity', 161 default=0, action='count', 162 help='Increase output verbosity') 163 args = parser.parse_args() 164 165 LOGGING_FORMAT = '%(asctime)-15s %(message)s' 166 logging.basicConfig(format=LOGGING_FORMAT) 167 168 LOG_LEVELS = {0: logging.WARNING, 1: logging.INFO, 2: logging.DEBUG} 169 args.verbosity = min(args.verbosity, max(LOG_LEVELS)) 170 logging.getLogger().setLevel(LOG_LEVELS[args.verbosity]) 171 172 # Okay - get to work here 173 174 if args.config: 175 configs = read_config(args.config) 176 logging.info('Read configs: %s', configs) 177 thread_list = [] 178 for inst in configs: 179 config = configs[inst] 180 sim = SimSerial(port=config['port'], source_file=config['logfile'], 181 time_format=config.get('time_format', args.time_format)) 182 sim_thread = threading.Thread(target=sim.run, kwargs={'loop': args.loop}, 183 daemon=True) 184 sim_thread.start() 185 thread_list.append(sim_thread) 186 187 logging.warning('Running simulated ports for %s', ', '.join(configs.keys())) 188 for thread in thread_list: 189 thread.join() 190 191 # If no config file, just a simple, single serial port 192 elif args.logfile and args.port: 193 sim_serial = SimSerial(port=args.port, baudrate=args.baud, 194 source_file=args.logfile) 195 sim_serial.run(args.loop) 196 197 # Otherwise, we don't have enough information to run 198 else: 199 parser.error('Either --config or both --logfile and --port must ' 200 'be specified')
class
SimSerial:
18class SimSerial: 19 """Create a virtual serial port and feed stored logfile data to it.""" 20 ############################ 21 22 def __init__(self, port, source_file, time_format=TIME_FORMAT, 23 use_timestamps=True, 24 baudrate=9600, bytesize=8, parity='N', stopbits=1, 25 timeout=None, xonxoff=False, rtscts=False, write_timeout=None, 26 dsrdtr=False, inter_byte_timeout=None, exclusive=None): 27 """Takes source file, whether to deliver data at rate indicated by 28 timestamps, and the standard parameters that a serial port takes.""" 29 30 # flake8: noqa: E501 31 logging.warning('simulate_serial.SimSerial is deprecated in favor of simulate_data.SimSerial') 32 33 self.source_file = source_file 34 self.use_timestamps = use_timestamps 35 self.time_format = time_format 36 37 # We'll create two virtual ports: 'port' and 'port_in'; we will write 38 # to port_in and read the values back out from port 39 self.read_port = port 40 self.write_port = port + '_in' 41 42 self.serial_params = {'baudrate': baudrate, 43 'byteside': bytesize, 44 'parity': parity, 45 'stopbits': stopbits, 46 'timeout': timeout, 47 'xonxoff': xonxoff, 48 'rtscts': rtscts, 49 'write_timeout': write_timeout, 50 'dsrdtr': dsrdtr, 51 'inter_byte_timeout': inter_byte_timeout, 52 'exclusive': exclusive} 53 self.quit = False 54 55 # Finally, find path to socat executable 56 self.socat_path = None 57 for socat_path in ['/usr/bin/socat', '/usr/local/bin/socat']: 58 if os.path.exists(socat_path) and os.path.isfile(socat_path): 59 self.socat_path = socat_path 60 if not self.socat_path: 61 raise NameError('Executable "socat" not found on path. Please refer ' 62 'to installation guide to install socat.') 63 64 ############################ 65 def _run_socat(self): 66 """Internal: run the actual command.""" 67 verbose = '-d' 68 write_port_params = 'pty,link=%s,raw,echo=0' % self.write_port 69 read_port_params = 'pty,link=%s,raw,echo=0' % self.read_port 70 71 cmd = [self.socat_path, 72 verbose, 73 # verbose, # repeating makes it more verbose 74 read_port_params, 75 write_port_params, 76 ] 77 try: 78 # Run socat process using Popen, checking every second or so whether 79 # it's died (poll() != None) or we've gotten a quit signal. 80 logging.info('Calling: %s', ' '.join(cmd)) 81 socat_process = subprocess.Popen(cmd) 82 while not self.quit and not socat_process.poll(): 83 try: 84 socat_process.wait(1) 85 except subprocess.TimeoutExpired: 86 pass 87 88 except Exception as e: 89 logging.error('ERROR: socat command: %s', e) 90 91 # If here, process has terminated, or we've seen self.quit. We 92 # want both to be true: if we've terminated, set self.quit so that 93 # 'run' loop can exit. If self.quit, terminate process. 94 if self.quit: 95 socat_process.kill() 96 else: 97 self.quit = True 98 logging.info('Finished: %s', ' '.join(cmd)) 99 100 ############################ 101 def run(self, loop=False): 102 """Create the virtual port with socat and start feeding it records from 103 the designated logfile. If loop==True, loop when reaching end of input.""" 104 self.socat_thread = threading.Thread(target=self._run_socat, daemon=True) 105 self.socat_thread.start() 106 time.sleep(0.2) 107 108 self.reader = LogfileReader(filebase=self.source_file, 109 use_timestamps=self.use_timestamps, 110 time_format=self.time_format) 111 112 self.strip = SliceTransform('1:') # strip off the first field) 113 self.writer = TextFileWriter(self.write_port, truncate=True) 114 115 while not self.quit: 116 try: 117 record = self.reader.read() # get the next record 118 logging.debug('SimSerial got: %s', record) 119 120 # End of input? If loop==True, re-open the logfile from the start 121 if record is None: 122 if not loop: 123 break 124 self.reader = LogfileReader(filebase=self.source_file, 125 use_timestamps=self.use_timestamps) 126 127 record = self.strip.transform(record) # strip the timestamp 128 if record: 129 logging.debug('SimSerial writing: %s', record) 130 self.writer.write(record) # and write it to the virtual port 131 except (OSError, KeyboardInterrupt): 132 break 133 134 # If we're here, we got None from our input, and are done. Signal 135 # for run_socat to exit 136 self.quit = True
Create a virtual serial port and feed stored logfile data to it.
SimSerial( port, source_file, time_format='%Y-%m-%dT%H:%M:%S.%fZ', use_timestamps=True, baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, write_timeout=None, dsrdtr=False, inter_byte_timeout=None, exclusive=None)
22 def __init__(self, port, source_file, time_format=TIME_FORMAT, 23 use_timestamps=True, 24 baudrate=9600, bytesize=8, parity='N', stopbits=1, 25 timeout=None, xonxoff=False, rtscts=False, write_timeout=None, 26 dsrdtr=False, inter_byte_timeout=None, exclusive=None): 27 """Takes source file, whether to deliver data at rate indicated by 28 timestamps, and the standard parameters that a serial port takes.""" 29 30 # flake8: noqa: E501 31 logging.warning('simulate_serial.SimSerial is deprecated in favor of simulate_data.SimSerial') 32 33 self.source_file = source_file 34 self.use_timestamps = use_timestamps 35 self.time_format = time_format 36 37 # We'll create two virtual ports: 'port' and 'port_in'; we will write 38 # to port_in and read the values back out from port 39 self.read_port = port 40 self.write_port = port + '_in' 41 42 self.serial_params = {'baudrate': baudrate, 43 'byteside': bytesize, 44 'parity': parity, 45 'stopbits': stopbits, 46 'timeout': timeout, 47 'xonxoff': xonxoff, 48 'rtscts': rtscts, 49 'write_timeout': write_timeout, 50 'dsrdtr': dsrdtr, 51 'inter_byte_timeout': inter_byte_timeout, 52 'exclusive': exclusive} 53 self.quit = False 54 55 # Finally, find path to socat executable 56 self.socat_path = None 57 for socat_path in ['/usr/bin/socat', '/usr/local/bin/socat']: 58 if os.path.exists(socat_path) and os.path.isfile(socat_path): 59 self.socat_path = socat_path 60 if not self.socat_path: 61 raise NameError('Executable "socat" not found on path. Please refer ' 62 'to installation guide to install socat.')
Takes source file, whether to deliver data at rate indicated by timestamps, and the standard parameters that a serial port takes.
def
run(self, loop=False):
101 def run(self, loop=False): 102 """Create the virtual port with socat and start feeding it records from 103 the designated logfile. If loop==True, loop when reaching end of input.""" 104 self.socat_thread = threading.Thread(target=self._run_socat, daemon=True) 105 self.socat_thread.start() 106 time.sleep(0.2) 107 108 self.reader = LogfileReader(filebase=self.source_file, 109 use_timestamps=self.use_timestamps, 110 time_format=self.time_format) 111 112 self.strip = SliceTransform('1:') # strip off the first field) 113 self.writer = TextFileWriter(self.write_port, truncate=True) 114 115 while not self.quit: 116 try: 117 record = self.reader.read() # get the next record 118 logging.debug('SimSerial got: %s', record) 119 120 # End of input? If loop==True, re-open the logfile from the start 121 if record is None: 122 if not loop: 123 break 124 self.reader = LogfileReader(filebase=self.source_file, 125 use_timestamps=self.use_timestamps) 126 127 record = self.strip.transform(record) # strip the timestamp 128 if record: 129 logging.debug('SimSerial writing: %s', record) 130 self.writer.write(record) # and write it to the virtual port 131 except (OSError, KeyboardInterrupt): 132 break 133 134 # If we're here, we got None from our input, and are done. Signal 135 # for run_socat to exit 136 self.quit = True
Create the virtual port with socat and start feeding it records from the designated logfile. If loop==True, loop when reaching end of input.