class SerialKISSDevice(BaseKISSDevice): def __init__(self, device, baudrate, *args, **kwargs): super(SerialKISSDevice, self).__init__(*args, **kwargs) self._serial = None self._device = device self._baudrate = baudrate def _open(self): self._serial = Serial(port=self._device, baudrate=self._baudrate, bytesize=EIGHTBITS, parity=PARITY_NONE, stopbits=STOPBITS_ONE, timeout=None, xonxoff=False, rtscts=False, write_timeout=None, dsrdtr=False, inter_byte_timeout=None) self._loop.add_reader(self._serial.fileno(), self._on_recv_ready) self._loop.call_soon(self._init_kiss) def _close(self): # Remove handlers self._loop.remove_reader(self._serial.fileno()) # Wait for all data to be sent. self._serial.flush() # Close the port self._serial.close() self._serial = None self._state = KISSDeviceState.CLOSED def _on_recv_ready(self): try: self._receive(self._serial.read(self._serial.in_waiting)) except: self._log.exception('Failed to read from serial device') def _send_raw_data(self, data): self._serial.write(data)
class XBeeDaemon(dbus.service.Object): """ Main class which connects dbus API and serial communication name: Unique DBUS object name for this instance All other arguments are passed off to the underlying pySerial implementation """ def __init__(self, name, port, escaping=True, baudrate=9600): if escaping: self.serial = EscapingSerial(port=port, baudrate=baudrate, timeout=0) else: self.serial = Serial(port=port, baudrate=baudrate, timeout=0) self.object_path = XBEED_DAEMON_OBJECT % name self.partial = PartialFrame() dbus.service.Object.__init__(self, BUS_NAME, self.object_path) gobject.io_add_watch(self.serial.fileno(), gobject.IO_IN, self.serial_read) def serial_read(self, fd, condition, *args): """ Called when there is data available from the serial port """ buffer = self.serial.read(256) print 'xbeed: read %d bytes' % len(buffer) try: if(self.partial.add(buffer)): packet = XBeeModuleFrame.parse(*self.partial.get_data()) self.handle_packet(packet) except ChecksumFail, e: print 'xbeed: ', e except UnknownFrameType, e: print 'xbeed: ', e
def get_serial_port(): """ Return serial.Serial instance, ready to use for RS485.""" port = Serial(port='/dev/ttyS1', baudrate=9600, parity=PARITY_NONE, stopbits=1, bytesize=8, timeout=1) fh = port.fileno() # A struct with configuration for serial port. serial_rs485 = struct.pack('hhhhhhhh', 1, 0, 0, 0, 0, 0, 0, 0) fcntl.ioctl(fh, 0x542F, serial_rs485) return port
class DummyPty(object): def __init__(self, sequence): # type: (List[bytes]) -> None self._replies = [] # type: List[bytes] self._sequence = sequence self._read = threading.Event() master, slave = pty.openpty() self.fd = os.fdopen(master, 'wb', 0) self._serial = Serial(os.ttyname(slave)) self._serial.timeout = None def master_reply(self, data): # type: (bytes) -> None self._replies.append(data) def master_wait(self, timeout=2): # type: (Optional[float]) -> None self._read.clear() self._read.wait(timeout) def read(self, size=None): # type: (Optional[int]) -> bytes data = self._serial.read(size) if data: self._read.set() return data def write(self, data): # type: (bytes) -> int if data != self._sequence[0]: assert printable(self._sequence[0]) == printable(data) self._sequence.pop(0) if self._replies: self.fd.write(self._replies[0]) self._replies.pop(0) return len(data) def fileno(self): # type: () -> int return self._serial.fileno() @property def in_waiting(self): # type: () -> int return self._serial.in_waiting def inWaiting(self): # pylint: disable=C0103 # type: () -> int return self._serial.inWaiting()
def watch(port): try: serial = Serial(port, 115200, timeout=None) fileno = serial.fileno() if fileno is not None: flags_rs485 = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND serial_rs485 = struct.pack('hhhhhhhh', flags_rs485, 0, 0, 0, 0, 0, 0, 0) fcntl.ioctl(fileno, TIOCSRS485, serial_rs485) buffer = '' while True: buffer += serial.read(1) _print(buffer) if buffer == 'ping\r': _print(buffer) serial.write('pong\r\n') buffer = '' except KeyboardInterrupt: print('Exit')
#data is good, lets output #creat a timestamp for the current message and prepend to the message stamp = datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S') message = stamp + ' $' + serialData.decode('UTF-8').rstrip('\r\n') + '#' #debug: print(message) print(message) #save message to the buffer data_log_buffer.append(message) #send the message to the producer p.send("weather-test",message.encode('UTF-8')) #attempt to rotate the log if needed rotate_log() #create an async loop object that drives the entire app loop = asyncio.get_event_loop() #add the serial function to the event handler loop.add_reader(s.fileno(), SerialReader) #call the function to write the process id to file writePidFile() #begin the main loop try: loop.run_forever() #on ctrl+c key press grab the exception except KeyboardInterrupt: #close the serial line s.close() #save the current buffer to local file buffer_to_file(data_log_buffer, current_log, True) #delete the pid file deletePidFile() #end the main loop loop.close()
class SerialConsole(ConsoleBase): def __init__(self, port, baud, encoding=None, linesep=None, raw_logfile=None, system: SystemContext = None): self.port = port self.baud = baud self._timeout = 0.001 self._ser = None super().__init__(encoding=encoding, linesep=linesep, raw_logfile=raw_logfile, system=system) def __repr__(self): return "SerialConsole[{}]".format(self.port) @property def is_open(self): return super().is_open and self._ser and self._ser.isOpen() def open(self): self.log(f'Trying to open serial port {self.port}', level=LogLevel.DEBUG) self._ser = Serial(port=self.port, baudrate=self.baud, timeout=self._timeout) self.engine.open(console_fd=self._ser.fileno()) if not self.is_open: raise RuntimeError(f'Failed to open serial port {self.port}') self.log(f'Init serial {self.port} success', level=LogLevel.DEBUG) return def close(self): if not self.is_open: return self._ser.flush() # Closes the serial too super().close() self._ser = None self.log("Closed serial", level=LogLevel.DEBUG) def interact(self, exit_char=None): ''' Take interactive control of a SerialConsole. The intention is that this be used from the command line. To exit the terminal press the exit character. You can set the exit character with @exit_char, default is "¬". ''' if not self.is_open: self.open() exit_char = exit_char or '¬' self.log('Starting interactive console') print(f'Press {exit_char} to exit') com = self._logging_Nanocom(self.engine.raw_logfile, self._ser, exit_character=exit_char) com.start() try: com.join() except KeyboardInterrupt: pass finally: self.log('Exiting interactive console...') com.close() class _logging_Nanocom(Nanocom): ''' This class just slightly modifies Nanocom to get it to log received data to a file. This is done so that the text from the interactive session is written to the raw logfile, along with everything else. The reader() method is copy-pasted from Nanocom and modified. ''' def __init__(self, logfile, *args, **kwargs): self.logfile = logfile Nanocom.__init__(self, *args, **kwargs) def reader(self): try: while self.alive: data = self.serial.read(self.serial.in_waiting or 1) if data: self.console.write_bytes(data) with open(self.logfile, 'ab') as f: f.write(data) except Exception: self.alive = False self.console.cancel() raise
class XBeeInterface(object): """ Interfaces between an XBee connected through a serial port and messages passed through stdin/stdout. Uses a simple JSON protocol to encode message parameters. """ def __init__(self, port, baud, escaped): self.serial_port = Serial(port, baud) self.xbee = ZigBee(self.serial_port, escaped=escaped) # Reopen stdin/stdout in line-buffered mode self.stdin = os.fdopen(sys.stdin.fileno(), 'r', 1) self.stdout = os.fdopen(sys.stdout.fileno(), 'w', 1) # Associate each file descriptor with handler methods self.handlers = { self.serial_port.fileno(): (self.read_frame, self.on_frame), self.stdin.fileno(): (self.read_message, self.on_message) } # Turn on non-blocking IO for fd in self.handlers.keys(): fcntl.fcntl(fd, fcntl.F_SETFL, os.O_NONBLOCK) def run(self): # Send an AT command to trigger a response from the module self.xbee.at(command='NI') response = self.xbee.wait_read_frame() log.info('Network identifier is "%s"', response['parameter']) while True: # do non-blocking reading from stdin and serial port r, w, x = select.select(self.handlers.keys(), [], []) for fd in r: read_handler, data_handler = self.handlers[fd] data = read_handler() # read handlers return None if message is gimped if data is not None: data_handler(data) def read_frame(self): """ Read an entire frame from the serial connection and return it """ try: return self.xbee.wait_read_frame() except ValueError as e: log.warning('error in packet data: %s', e) return None except SerialException as e: log.error('error reading serial frame: %s', e) raise IOError("Error reading from serial port") def read_message(self): """ Read a line from stdin and parse it as JSON """ try: line = self.stdin.readline() return json.loads(line) except ValueError as e: log.error('error decoding message: %s', e) return None def json_message(self, data): """ Write a JSON string to stdout, using latin1 encoding to keep binary data intact """ json_str = json.dumps(data, encoding='latin1') self.stdout.write(json_str + '\n') def on_message(self, message): log.info('Message received from stdin: %s', message) try: # delegate to another method specified by action action = '_'.join(('do', message['action'])) if not hasattr(self, action): return log.error('Unknown action "%s"', message['action']) getattr(self, action)(message) except KeyError as e: return log.error('Message is missing "%s"', e.message) def do_send(self, message): """ Sends a transmit request to the module """ # encode as latin1 to get back byte string address, data, frame_id = ( message['address'].encode('latin1'), message['data'].encode('latin1'), message.get('frame_id', u'\x01').encode('latin1')) try: self.xbee.tx(data=data, frame_id=frame_id, dest_addr_long=address, dest_addr='\xFF\xFE') except Exception as e: return log.error('Failed to send transmit request: %s', e) def do_discover(self, message): frame_id = message.get('frame_id', u'\x01').encode('latin1') self.xbee.at(command='ND', frame_id=frame_id) def on_frame(self, frame): log.debug('Frame received from device: %s', frame) try: event = '_'.join(('on_frame', frame['id'])) getattr(self, event)(frame) except (AttributeError, KeyError): log.warning('unhandled frame: %s', frame) def on_frame_rx(self, frame): log.info('Received message from %s/%s', hexify(frame['source_addr_long']), hexify(frame['source_addr'])) self.json_message(frame) def on_frame_tx_status(self, frame): log.info('Transmit status for frame %s: %s', frame['frame_id'], 'success' if frame['deliver_status'] == '\x00' else 'failure') self.json_message(frame) def on_frame_at_response(self, frame): log.info('AT response for frame %s: "%s"', frame['frame_id'], frame['parameter']) self.json_message(frame)
#p = KafkaProducer(bootstrap_servers=[systemconfig.kafka_connection]) s = Serial(current_port,'9600',bytesize=8,parity='N',xonxoff=0,rtscts=0,timeout=1) #to add a serial write function, you can use a buffer or rewrite the callback #buffer = "" def SerialReader(): # global p if s.readable(): serialData = s.readline() #s.write(buffer) ts = time.time() if len(serialData) > 2: #data is good, lets output stamp = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S') message = stamp + ' $' + serialData.decode('UTF-8').rstrip('\r\n') + '#' print(message) # p.send("weather-test",message.encode('UTF-8')) loop = asyncio.get_event_loop() loop.add_reader(s.fileno(), SerialReader) try: loop.run_forever() except KeyboardInterrupt: s.close() loop.close() finally: loop.close()