diff --git a/cutelog/serial.py b/cutelog/serial.py index 4f2d46c28e5105593ea88df851623e57d448419f..4a228de5ac7d9f5a577508a7e14163fb95167be2 100644 --- a/cutelog/serial.py +++ b/cutelog/serial.py @@ -2,7 +2,8 @@ import serial import pickle import struct import re -import sys +import logging +import time from datetime import datetime from qtpy.QtCore import QThread, Signal @@ -10,93 +11,146 @@ from qtpy.QtNetwork import QHostAddress, QTcpSocket from .config import CONFIG + class SerialConnection(QThread): disconnected = False - re_line = re.compile(r"(?P<tsmin>\d{2,}):(?P<tssec>\d{2}.\d{3}) (?P<file>[\dA-Za-z/_\-.]+):(?P<line>\d+) (?P<func>[\dA-Za-z/_\-\.]+) (?P<level>[A-Za-z\d]+) \[(?P<name>[\dA-Za-z/_\-.]+)\] (?P<msg>.*)") + crit_words = ["fault"] + warn_words = ["miosix v"] + ser = None + + logger = logging.getLogger("SerialConn") + # logging.Formatter("{message}", style='{') + + re_line = re.compile( + r"(?P<tsmin>\d{2,}):(?P<tssec>\d{2}.\d{3}) (?P<file>[\dA-Za-z/_\-.]+):" + r"(?P<line>\d+) (?P<func>[\dA-Za-z/_\-\.]+) (?P<level>[A-Za-z\d]+) " + r"\[(?P<name>[\dA-Za-z/_\-.]+)\] (?P<msg>.*)" + ) def __init__(self, parent, port, baud): super().__init__(parent) - print("Opening serial port {}:{}".format(port, baud)) + self.logger.info("Opening serial port {}:{}".format(port, baud)) + + self.port = port + self.baud = baud - self.ser = serial.Serial(port, baud, timeout=1) _, self.tcp_port = CONFIG.listen_address self.tcp_host = QHostAddress("127.0.0.1") - + self.start() - print("thread started") + self.logger.debug("thread started") def onDisconnect(self): - disconnect = True - print("on disconnect") + self.disconnected = True + self.logger.debug("on disconnect") + + def readSerial(self): + try: + logline = self.ser.readline().decode("ascii").strip("\n\r") + if len(logline) > 2: + return logline + else: + self.logger.debug("Ignored line as it is too short: '{}'".format(logline)) + return "" + except serial.SerialException as err: + self.logger.error(err.strerror) + return None + except Exception as err: + self.logger.error(err.strerror) + return "" + + def forwardLog(self, sock, logline: str): + match = self.re_line.fullmatch(logline) + + if match is None: + level = logging.DEBUG + for s in self.warn_words: + if logline.lower().find(s) > -1: + level = logging.WARNING + break + for s in self.crit_words: + if logline.lower().find(s) > -1: + level = logging.CRITICAL + break + + d = { + "args": None, + "created": datetime.now().timestamp(), + "exc_info": None, + "filename": "", + "funcName": "", + "levelname": logging.getLevelName(level), + "levelno": level, + "lineno": 0, + "module": "", + "msecs": 0, + "msg": logline, + "name": "raw_serial", + "pathname": "", + "process": 0, + "processName": "", + "relativeCreated": 0, + "stack_info": None, + "thread": 0, + "threadName": "", + "extra_column": "", + } + else: + d = { + "args": None, + "created": int(match.group("tsmin")) * 60 * 1000 + float(match.group("tssec")) * 1000, + "exc_info": None, + "filename": match.group("file"), + "funcName": match.group("func"), + "levelname": match.group("level"), + "levelno": 10, + "lineno": match.group("line"), + "module": "serial", + "msecs": 0, + "msg": match.group("msg"), + "name": match.group("name"), + "pathname": match.group("file"), + "process": 0, + "processName": "", + "relativeCreated": 0, + "stack_info": None, + "thread": 0, + "threadName": "", + "extra_column": "", + } + + s = pickle.dumps(d) + + sock.write(struct.pack(">L", len(s))) + sock.write(s) + sock.flush() def run(self): sock = QTcpSocket(None) sock.connectToHost(self.tcp_host, self.tcp_port) sock.disconnected.connect(self.onDisconnect) + if not sock.waitForConnected(): - print("Socket error!") - print(sock.errorString()) + self.logger.error("Socket error! {}".format(sock.errorString())) return - - if self.ser is None: - print("Error opening serial port") - return - - while True: - logline = self.ser.readline().decode("utf-8").strip("\n\r") - - match = self.re_line.fullmatch(logline) - - if match is None: - d = {'args': None, - 'created': datetime.now().timestamp(), - 'exc_info': None, - 'filename': '', - 'funcName': '', - 'levelname': 'DEBUG', - 'levelno': 0, - 'lineno': 0, - 'module': '', - 'msecs': 0, - 'msg': logline, - 'name': 'raw_serial', - 'pathname': '', - 'process': 0, - 'processName': '', - 'relativeCreated': 0, - 'stack_info': None, - 'thread': 0, - 'threadName': '', - 'extra_column': ''} - else: - d = {'args': None, - 'created': int(match.group('tsmin'))*60*1000 + float(match.group('tssec'))*1000, - 'exc_info': None, - 'filename': match.group('file'), - 'funcName': match.group('func'), - 'levelname': match.group('level'), - 'levelno': 10, - 'lineno': match.group('line'), - 'module': 'serial', - 'msecs': 0, - 'msg': match.group('msg'), - 'name': match.group('name'), - 'pathname': match.group('file'), - 'process': 0, - 'processName': '', - 'relativeCreated': 0, - 'stack_info': None, - 'thread': 0, - 'threadName': '', - 'extra_column': ''} - - s = pickle.dumps(d) - - sock.write(struct.pack(">L", len(s))) - sock.write(s) - sock.flush() + while True: + if self.ser is not None: + logline = self.readSerial() + if logline is None: + self.logger.error("Serial port error") + self.ser.close() + self.ser = None + elif len(logline) > 0: + self.forwardLog(sock, logline) + else: + try: + self.ser = serial.Serial(self.port, self.baud, timeout=1) + except serial.SerialException as err: + time.sleep(1) + self.logger.error(str(err)) + if sock.state() != QTcpSocket.SocketState.ConnectedState: - print("thread stop") + self.logger.debug("thread stop") self.ser.close() - break \ No newline at end of file + break