Python parsing and packaging serial data

Overview

We did a project some time ago. Our system uses the serial port to interact with the MCU. The system side code has written the code for parsing and sending data according to the data packet protocol agreed by both parties, but the MCU side has not completed the code, we can’t wait for them After the completion of the code debugging, this will delay the progress of the project, after consulting the relevant information online. Finally, I decided to use a python script to complete the analysis and packaging of the data for simulation testing. I also checked a lot of information on the Internet, and finally realized the simulation data to complete the code debugging. This script mainly uses the two modules of python serial (serial port operation) And struct (packed into c language byte string). Some brief instructions:

serial module

The main user serial port operation, there are a lot of information on the network, here is the code directly for comments

class ComThread:
 def __init__(self, Port='COM56'): #打开COM56
  self.l_serial = None 
  self.alive = False
  self.waitEnd = None
  self.port = Port
  self.ID = None
  self.data = None

 def waiting(self):
  if not self.waitEnd is None:
   self.waitEnd.wait()

 def SetStopEvent(self):
  if not self.waitEnd is None:
   self.waitEnd.set()
  self.alive = False
  self.stop()

 def start(self):
  self.l_serial = serial.Serial()
  self.l_serial.port = self.port
  self.l_serial.baudrate = 115200 #串口波特率
  self.l_serial.timeout = 2 #超时时间
  self.l_serial.open()
  if self.l_serial.isOpen():
   self.waitEnd = threading.Event()
   self.alive = True
   self.thread_read = None
   self.thread_read = threading.Thread(target=self.FirstReader)
   self.thread_read.setDaemon(1)
   self.thread_read.start()
   return True
  else:
   return False

 def SendDate(self,i_msg,send):
  #lmsg = ''
  isOK = False
  #发送数据到相应的处理组件
  print(i_msg)
  send_buf = nwy_create_send_msg(i_msg, send)
  self.l_serial.write(send_buf)
  print("send success")
  return True
 def FirstReader(self):
  while self.alive:
   time.sleep(0.1)
   data = ''
   data = data.encode('utf-8')
   n = self.l_serial.inWaiting()
   if n:
    data = data + self.l_serial.read(n)
    print(len(data))#打印收到的数据
    print(data.hex()) #按照十六进制打印

 def stop(self):
  self.alive = False
  self.thread_read.join()
  if self.l_serial.isOpen():
   self.l_serial.close()
   
def quit(signum, frame):
 print("Bye Bye!")
 sys.exit(0)

#调用串口,测试串口
def main():
 rt = ComThread()
 rt.sendport = '**1*80*'
 try:
  if  rt.start():
   signal.signal(signal.SIGINT, quit)
   print(rt.l_serial.name)
   #rt.waiting()
   #print("The data is:%s,The Id is:%s"%(rt.data,rt.ID))
   #t.stop()
  else:
   pass
 except Exception as se:
  print(str(se))
  print ('End OK .')
 return rt

if __name__ == '__main__':
 mSerial = main()
 while True:
  time.sleep(1)

struct module

Serial data analysis, here does not use unpack for analysis, here is the analysis according to the current definition

def parse_read_data(data, len):
 print(data)
 print(len)
 #check head
 if 0x0F != data[0]:#判断数据头
  print ("head is not 0x0F data head is " + hex(data[0]))
  return False
 #get msg id 
 msg_id = data[1] << 8 | data[2] #获取消息ID
 msg_len = data[3] << 8 | data[4] #获取数据长度
 data_crc = data[7+msg_len] #获取数据的校验和
 Cal_crc = Calculation_crc(data[1:len-2]) #计算数据的校验和
 if data_crc != Cal_crc: #判断数据的校验和
  print ("crc error ")
  return False
 print ("data is good")
  #do something 
 #处理数据 
 return True

Pack the data to be sent into a fixed format byte string. The specific packing should be packed according to the actual protocol. The detailed explanation of strcut is too much, so I won’t repeat it here.

def create_send_msg(i_msg, send):
 msg_len = len(send)
 msg_len_2 = ~msg_len
 #下面就类似于c预言的printf 不过可以查查struct中对应的类型
 # !表示大端
 # H unsigned short
 # h singned short 这里用h主要是长度的反码如果有无符号会提示存不下,所以用有符号
 # %ds 这个比较特殊,s为字节串,长度为%d 
 # B byte
 psh = struct.pack('!HHh%ds'%len(send), i_msg, msg_len, msg_len_2,send)
 # 计算crc
 crc = Calculation_crc(psh)
  # c语言的结构体定义如下
 # struct{
 #  unsigned char  header
 #  unsigned short msgid
 #  unsigned short msglen
 #  signed short   unmsglen
 #  char *data
 #  unsigned char   crc
 #  unsigned char   end
 # }
 pshhh = struct.pack('!BHHh%dsBB' %len(send), MSG_HEADER, i_msg, msg_len, msg_len_2,send, crc, MSG_END)
 return pshhh

The complete sample code is as follows

import struct
import binascii
import sys
import signal
import threading
import time
import serial
import random
MSG_HEADER=0x0F
MSG_END=0xF0
MCU_MSG_ID=0x0001

def create_send_msg(i_msg, send):
 msg_len = len(send)
 msg_len_2 = ~msg_len
 #下面就类似于c预言的printf 不过可以查查struct中对应的类型
 # !表示大端
 # H unsigned short
 # h singned short 这里用h主要是长度的反码如果有无符号会提示存不下,所以用有符号
 # %ds 这个比较特殊,s为字节串,长度为%d 
 # B byte
 psh = struct.pack('!HHh%ds'%len(send), i_msg, msg_len, msg_len_2,send)
 # 计算crc
 crc = Calculation_crc(psh)
  # c语言的结构体定义如下
 # struct{
 #  unsigned char  header
 #  unsigned short msgid
 #  unsigned short msglen
 #  signed short   unmsglen
 #  char *data
 #  unsigned char   crc
 #  unsigned char   end
 # }
 pshhh = struct.pack('!BHHh%dsBB' %len(send), MSG_HEADER, i_msg, msg_len, msg_len_2,send, crc, MSG_END)
 return pshhh

def send_mcu_data(data):
 msg = "FF000000FFECFFD7FC03000000000000"; #模拟的一包数据
 by = binascii.a2b_hex(msg)
 mSerial.SendDate(MCU_MSG_ID, by)
 return

#计算校验和  
def Calculation_crc(data): 
 crc = 0
 for i in range(len(data)): 
  crc ^= data[i]
 return crc

def parse_read_data(data, len):
 print(data)
 print(len)
 #check head
 if 0x0F != data[0]:#判断数据头
  print ("head is not 0x0F data head is " + hex(data[0]))
  return False
 #get msg id 
 msg_id = data[1] << 8 | data[2] #获取消息ID
 msg_len = data[3] << 8 | data[4] #获取数据长度
 data_crc = data[7+msg_len] #获取数据的校验和
 Cal_crc = Calculation_crc(data[1:len-2]) #计算数据的校验和
 if data_crc != Cal_crc: #判断数据的校验和
  print ("crc error ")
  return False
 print ("data is good")
  #do something 
 #处理数据 
 return True
class ComThread:
 def __init__(self, Port='COM56'):
  self.l_serial = None
  self.alive = False
  self.waitEnd = None
  self.port = Port
  self.ID = None
  self.data = None
 def waiting(self):
  if not self.waitEnd is None:
   self.waitEnd.wait()
 def SetStopEvent(self):
  if not self.waitEnd is None:
   self.waitEnd.set()
  self.alive = False
  self.stop()

 def start(self):
  self.l_serial = serial.Serial()
  self.l_serial.port = self.port
  self.l_serial.baudrate = 230400
  self.l_serial.timeout = 2
  self.l_serial.open()
  if self.l_serial.isOpen():
   self.waitEnd = threading.Event()
   self.alive = True
   self.thread_read = None
   self.thread_read = threading.Thread(target=self.FirstReader)
   self.thread_read.setDaemon(1)
   self.thread_read.start()
   return True
  else:
   return False
 def SendDate(self,i_msg,send):
  send_buf = create_send_msg(i_msg, send)
  self.l_serial.write(send_buf)
  print("send success")
  return True

 def FirstReader(self):
  while self.alive:
   time.sleep(0.1)
   data = ''
   data = data.encode('utf-8')
   n = self.l_serial.inWaiting()
   if n:
    data = data + self.l_serial.read(n)
    #print(len(data))
    #print(data.hex())
    parse_read_data(data, len(data))
 def stop(self):
  self.alive = False
  self.thread_read.join()
  if self.l_serial.isOpen():
   self.l_serial.close()
  def quit(signum, frame):
 print("Bye Bye!")
 sys.exit(0)
#调用串口,测试串口
def main():
 rt = ComThread()
 rt.sendport = '**1*80*'
 try:
  if  rt.start():
   signal.signal(signal.SIGINT, quit)
   print(rt.l_serial.name)
  else:
   pass
 except Exception as se:
  print(str(se))
  print ('End OK .')
 return rt
if __name__ == '__main__':
 mSerial = main()
 while True:
  time.sleep(1)
  #发送给系统数据
  send_mcu_data(mSerial)

The above is my sharing, if you need to explore, you can add qq 991410485

Guess you like

Origin blog.csdn.net/weixin_35933684/article/details/108288943