from Dxr_log.log import *
import threading
import time
import serial


class serial_class:
	# 初始化
	def __init__(self):
		self.obj_name = ""  # 对象名称
		self.port_name = ""  # 端口，GNU / Linux上的/ dev / ttyUSB0 等 或 Windows上的 COM3 等
		self.bps = 115200  # 波特率，标准值之一：50,75,110,134,150,200,300,600,1200,1800,2400,4800,9600,19200,38400,57600,115200
		self.time_out = 5  # 超时设置,None：永远等待操作，0为立即返回请求结果，其他值为等待超时时间(单位为秒）
		self.parity = ""  # N E O
		self.stop_bits = 1
		self.serial = {}  # 串口对象
		self.is_open = False  # 连接状态
		self.auto_connect_flag = True  # 内部重连标志
		self.callback_func = None  # 默认的回调函数
		self._auto_connect_thread = threading.Thread()  # 内部自动重连连接线程
		self._receive_thread = threading.Thread()  # 内部接收线程
		self.debug_flag = False  # debug模式
		self.read_wait_gap = 0.05  # 接收无数据时更待间隔

	# 串口连接 连接成功之后接收线程自动开启
	def connect(self):
		try:
			# 检查串口是否开启
			if self.is_open:
				self.close()
			self.is_open = False
			# 串口实例生成
			if not self.debug_flag:
				if self.stop_bits == 1.5:
					self.stop_bits = serial.STOPBITS_ONE_POINT_FIVE
				elif self.stop_bits == 2:
					self.stop_bits = serial.STOPBITS_TWO
				else:
					self.stop_bits = serial.STOPBITS_ONE
				self.serial = serial.Serial(self.port_name, self.bps, timeout=self.time_out, parity=self.parity,
				                            stopbits=self.stop_bits)
			self.is_open = True
			# 检查是否绑定接受回调
			if self.callback_func is None:
				print_error(self.obj_name + " " + "without dispose_func")
			print_info(self.obj_name + " " + "connect to " + self.port_name)
			# 内部接收线程开启
			self._receive_thread = threading.Thread(target=self._receive_thread_poc)
			self._receive_thread.daemon = True
			self._receive_thread.start()
			return True
		except Exception as e:
			print_error(self.obj_name + " " + "connect error:" + e.__str__())
			return False

	# 串口断开连接
	def close(self):
		try:
			# 关闭
			self.is_open = False
			time.sleep(0.5)
			if not self.debug_flag:
				self.serial.close()
			print_info(self.obj_name + " " + "close")
		except Exception as e:
			print_error(self.obj_name + " " + "close error:" + e.__str__())

	# 串口接收
	def read_msg(self):
		# 接收串口发送过来的数据
		if self.is_open:
			try:
				if not self.debug_flag:
					if self.serial.in_waiting > 0:
						data = self.serial.read(self.serial.in_waiting)
						if self.callback_func is not None:
							self.callback_func(data)
						else:
							print("receive:", data)
					else:
						time.sleep(self.read_wait_gap)
				else:
					time.sleep(self.read_wait_gap)
			except Exception as e:
				raise e

	# 串口发送
	def send_msg(self, msg):
		try:
			if msg:
				# 检查串口状态
				if self.is_open:
					if not self.debug_flag:
						self.serial.write(msg)
					else:
						try:
							print('serial debug send: ' + ''.join(['%02X ' % b for b in msg]))
						except Exception as e:
							print(e)
				else:
					raise Exception("is not open")
		except Exception as e:
			# 非主动停止进行重启
			if self.is_open:
				print_debug(self.obj_name + " " + "send_msg Error:" + e.__str__())
				self._auto_connect()
			# 主动停止退出
			else:
				print_debug(self.obj_name + " " + "send fail and exit")

	# 自动重连线程
	def _auto_connect_thread_poc(self):
		print_info(self.obj_name + " " + "start auto_connect_thread_poc")
		while 1:
			try:
				# 检查初值
				if self.port_name != "" and self.bps != 0:
					# 连接
					if self.connect():
						break
					else:
						# 连接失败则重复进行
						time.sleep(5)
			except Exception as e:
				# 连接异常则重复进行
				print_error(self.obj_name + " " + "failed to connect to server: " + e.__str__())
				time.sleep(5)

	# 自动重连
	def _auto_connect(self):
		# 需要自动重连则开启自动重连线程
		if self.auto_connect_flag:
			# 检查是否重复开启
			if not self._auto_connect_thread.is_alive():
				self._auto_connect_thread = threading.Thread(target=self._auto_connect_thread_poc)
				self._auto_connect_thread.daemon = True
				self._auto_connect_thread.start()
			else:
				print_error(self.obj_name + " " + "auto_connect_thread has been started")
		# 不需要自动重连则断开连接
		else:
			self.close()

	# 接收线程
	def _receive_thread_poc(self):
		try:
			print_info(self.obj_name + " " + "start receive_thread")
			while self.is_open:
				self.read_msg()
			print_info("receive_thread normal exit")
		except Exception as e:
			# 中止属于程序主动执行，跳过重启
			if e.__str__().find("中止") > 0:
				pass
			else:
				# 非主动停止
				if self.is_open:
					print_error(self.obj_name + " " + "receive_thread error:" + e.__str__())
					self._auto_connect()


if __name__ == '__main__':
	# 接收回调方法
	def com_callback(data):
		print(data)


	# 生成串口实例
	com = serial_class()
	# 串口实例属性配置
	com.obj_name = "rs485_1"
	com.port_name = "COM4"
	com.bps = 9600
	com.time_out = 10
	com.parity = "N"
	com.auto_connect_flag = True
	com.callback_func = com_callback
	com.debug_flag = False
	# 串口连接
	com.connect()
	send_data = [0x01, 0x02, 0x03, 0x04]
	for x in range(10):
		# 串口发送
		com.send_msg(send_data)
		time.sleep(0.5)
	# 串口关闭
	com.close()
