大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是串列埠除錯工具Jays-PyCOM誕生之軟體優化。
前面痞子衡已經初步實現了Jays-PyCOM的串列埠功能,並且通過了最基本的測試,但目前的Jays-PyCOM相比市面上流行的串列埠除錯工具還差得很遠,有很大的優化空間。優化可以從兩方面進行:一、是功能上的優化,可以新增更多實用的功能;二、是介面效果上的優化,可以增加一些介面動畫效果或者重新配色美化介面。下面痞子衡從這兩方面分別為Jays-PyCOM做一些簡單的優化:
一、功能優化
1.1 增強魯棒性
最開始要做的功能優化應該是增強軟體魯棒性,即在任何異常使用者輸入的情況下,軟體都不能掛掉,痞子衡在實測中發現當使用者在"Com Port"裡輸入的是無效串列埠裝置號時,軟體會掛掉,因此做了以下改進,在開啟裝置時使用try except語句,如有異常,直接退出,不會繼續後面程式碼的執行。此類改進還有很多,不一一例舉。
class mainWin(win.com_win):
def openClosePort( self, event ):
if s_serialPort.isOpen():
s_serialPort.close()
self.m_button_openClose.SetLabel('Open')
else:
# ...
self.setParitybits()
# 新增程式碼開始
try:
s_serialPort.open()
except Exception, e:
# Show warning message
return
# 新增程式碼結束
self.m_button_openClose.SetLabel('Close')
# ...
1.2 自動檢測可用Port
最初版本實現Port口選擇是使用者按標準格式“COMx”手動輸入,但這樣有一個問題,即使用者輸入的格式有可能不合法,並且即使是一個合法的格式輸入,但也可能不是一個可用的有效Port。參照市面上流行的串列埠除錯助手,有的是下拉選單選擇所有COM口(比如AccessPort,這樣可以解決不合法格式輸入的問題),有的是下拉選單選擇可用的COM口(比如sscom,這樣可以解決Port是否有效的問題),痞子衡參照sscom的做法對Jays-PyCOM進行了如下優化:
class mainWin(win.com_win):
def __init__(self, parent):
self.refreshComPort(None)
self.m_choice_comPort.SetSelection( 0 )
def refreshComPort( self, event ):
comports = list(serial.tools.list_ports.comports())
ports = [None] * len(comports)
for i in range(len(comports)):
comport = list(comports[i])
# example comport = [u'COM3', u'Intel(R) Active Management Technology - SOL (COM3)', u'PCI\\VEN_8086&DEV_9D3D&SUBSYS_06DC1028&REV_21\\3&11583659&0&B3']
ports[i] = comport[0] + ' - ' + comport[1]
self.m_choice_comPort.Clear()
self.m_choice_comPort.SetItems(ports)
def setPort ( self ):
index = self.m_choice_comPort.GetSelection()
comPort = self.m_choice_comPort.GetString(index)
comPort = comPort.split(' - ')
s_serialPort.port = comPort[0]
1.3 實現格式切換功能
Char/Hex格式轉換屬於比較實用的功能,一般的串列埠除錯助手都會有這個功能,Jays-PyCOM之前預設總是按照Char格式來輸入和顯示,"Format"選項框的功能實際上並沒有實現,因此痞子衡在這裡加上了格式切換功能。
import formatter
s_formatter = formatter.formatter()
s_lastRecvFormat = None
s_lastSendFormat = None
class mainWin(win.com_win):
# 函式功能實現
def setSendFormat( self, event ):
lines = self.m_textCtrl_send.GetNumberOfLines()
if lines != 0:
m_sendFormat = self.m_choice_sendFormat.GetString(self.m_choice_sendFormat.GetSelection())
global s_lastSendFormat
if s_lastSendFormat == m_sendFormat:
return
else:
s_lastSendFormat = m_sendFormat
# Get existing data from textCtrl_send
data = ''
for i in range(0, lines):
data += str(self.m_textCtrl_send.GetLineText(i))
# Convert data format according to choice_sendFormat
if m_sendFormat == 'Char':
status, data = s_formatter.hexToChar(data)
if not status:
self.m_textCtrl_send.Clear()
self.m_textCtrl_send.write('Invalid format! Correct example: 12 34 56 ab cd ef')
return
elif m_sendFormat == 'Hex':
data = s_formatter.charToHex(data)
# Re-show converted data in textCtrl_send
self.m_textCtrl_send.Clear()
self.m_textCtrl_send.write(data)
def sendData( self, event ):
if s_serialPort.isOpen():
lines = self.m_textCtrl_send.GetNumberOfLines()
if lines != 0:
data = ''
for i in range(0, lines):
data += str(self.m_textCtrl_send.GetLineText(i))
# 新增程式碼開始
# Make sure data is always in 'Char' format
m_sendFormat = self.m_choice_sendFormat.GetString(self.m_choice_sendFormat.GetSelection())
if m_sendFormat == 'Hex':
status, data = s_formatter.hexToChar(data)
if not status:
self.m_textCtrl_send.Clear()
self.m_textCtrl_send.write('Invalid format! Correct example: 12 34 56 ab cd ef')
return
# 新增程式碼結束
s_serialPort.write(data)
# 函式功能實現
def setRecvFormat( self, event ):
lines = self.m_textCtrl_recv.GetNumberOfLines()
if lines != 0:
m_recvFormat = self.m_choice_recvFormat.GetString(self.m_choice_recvFormat.GetSelection())
global s_lastRecvFormat
if s_lastRecvFormat == m_recvFormat:
return
else:
s_lastRecvFormat = m_recvFormat
# Get existing data from textCtrl_recv
data = ''
for i in range(0, lines):
data += str(self.m_textCtrl_recv.GetLineText(i))
# Convert data format according to choice_recvFormat
if m_recvFormat == 'Char':
status, data = s_formatter.hexToChar(data)
elif m_recvFormat == 'Hex':
data = s_formatter.charToHex(data)
# Re-show converted data in textCtrl_recv
self.m_textCtrl_recv.Clear()
self.m_textCtrl_recv.write(data)
def recvData( self ):
if s_serialPort.isOpen():
num = s_serialPort.inWaiting()
if num != 0:
data = s_serialPort.read(num)
# 新增程式碼開始
# Note: Assume that data is always in 'Char' format
# Convert data format if dispaly format is 'Hex'
m_recvFormat = self.m_choice_recvFormat.GetString(self.m_choice_recvFormat.GetSelection())
if m_recvFormat == 'Hex':
data = s_formatter.charToHex(data)
# 新增程式碼結束
self.m_textCtrl_recv.write(data)
傳送輸入框格式切換功能實測如下,尤其是在Hex模式下,如果有異常輸入,Jays-PyCOM會直接清屏,並在輸入框裡提示正確的示例。接收顯示框格式切換功能雷同,但並不包含異常輸入提示,因為這是個結果顯示輸出框。
1.4 啟用選單欄
選單欄是一個功能齊全的軟體的標配,用於實現各種特性功能,此處痞子衡僅新增了一個“Help”選單,用於顯示Jays-PyCOM的主頁以及作者資訊。首先需要在wxFormBuilder新增menu控制元件,然後設定回撥函式名,下面是回撥函式的實現:
def showHomepageMessage( self, event ):
messageText = (('Code: \n https://github.com/JayHeng/Jays-PyCOM.git \n') +
('Doc: \n https://www.cnblogs.com/henjay724/p/9416096.html \n'))
wx.MessageBox(messageText, "Homepage", wx.OK | wx.ICON_INFORMATION)
def showAboutMessage( self, event ):
messageText = (('Author: Jay Heng \n') +
('Email: hengjie1989@foxmail.com \n'))
wx.MessageBox(messageText, "About", wx.OK | wx.ICON_INFORMATION)
1.5 啟用狀態列
狀態列也是一般串列埠除錯助手的標配,用於顯示傳送/接收資料統計資訊以及串列埠開關狀態,因此痞子衡為Jays-PyCOM也加上了狀態列功能,狀態列主要分為三欄:接收資料統計、傳送資料統計、串列埠狀態。
s_recvStatusFieldIndex = 0
s_sendStatusFieldIndex = 1
s_infoStatusFieldIndex = 2
s_recvStatusStr = 'Recv: '
s_recvTotalBytes = 0
s_sendStatusStr = 'Send: '
s_sendTotalBytes = 0
class mainWin(win.com_win):
def openClosePort( self, event ):
if s_serialPort.isOpen():
s_serialPort.close()
self.m_button_openClose.SetLabel('Open')
# 新增程式碼開始
self.statusBar.SetStatusText(s_serialPort.name + ' is closed', s_infoStatusFieldIndex)
# 新增程式碼結束
else:
# 新增程式碼開始
self.statusBar.SetFieldsCount(3)
self.statusBar.SetStatusWidths([150, 150, 400])
# 新增程式碼結束
self.setPort()
# ...
self.m_button_openClose.SetLabel('Close')
# 新增程式碼開始
self.statusBar.SetStatusText(s_recvStatusStr + str(s_recvTotalBytes), s_recvStatusFieldIndex)
self.statusBar.SetStatusText(s_sendStatusStr + str(s_sendTotalBytes), s_sendStatusFieldIndex)
self.statusBar.SetStatusText(s_serialPort.name + ' is open, ' +
str(s_serialPort.baudrate) + ', ' +
str(s_serialPort.bytesizes) + ', ' +
s_serialPort.parity + ', ' +
str(s_serialPort.stopbits), s_infoStatusFieldIndex)
# 新增程式碼結束
s_serialPort.reset_input_buffer()
# ...
def sendData( self, event ):
if s_serialPort.isOpen():
lines = self.m_textCtrl_send.GetNumberOfLines()
if lines != 0:
# ...
s_serialPort.write(data)
# 新增程式碼開始
global s_sendTotalBytes
s_sendTotalBytes += len(data)
self.statusBar.SetStatusText(s_sendStatusStr + str(s_sendTotalBytes), s_sendStatusFieldIndex)
# 新增程式碼結束
else:
self.statusBar.SetStatusText(s_serialPort.name + ' is not open !!!', s_infoStatusFieldIndex)
def recvData( self ):
if s_serialPort.isOpen():
num = s_serialPort.inWaiting()
if num != 0:
# ...
self.m_textCtrl_recv.write(data)
# 新增程式碼開始
global s_recvTotalBytes
s_recvTotalBytes += len(data)
self.statusBar.SetStatusText(s_recvStatusStr + str(s_recvTotalBytes), s_recvStatusFieldIndex)
# 新增程式碼結束
狀態列實測功能如下:
二、介面優化
2.1 新增串列埠開關亮燈效果
介面優化的地方有很多,痞子衡簡單做了一個與串列埠開關按鈕同步的小燈顯示效果,當串列埠開啟時,小燈顯示綠色;當串列埠關閉時,小燈顯示黑色;程式碼裡的實現其實就是兩張圖片之間的切換。
class mainWin(win.com_win):
def openClosePort( self, event ):
if s_serialPort.isOpen():
s_serialPort.close()
self.m_button_openClose.SetLabel('Open')
# 新增程式碼開始
self.m_bitmap_led.SetBitmap(wx.Bitmap( u"../img/led_black.png", wx.BITMAP_TYPE_ANY ))
# 新增程式碼結束
else:
# ...
self.m_button_openClose.SetLabel('Close')
# 新增程式碼開始
self.m_bitmap_led.SetBitmap(wx.Bitmap( u"../img/led_green.png", wx.BITMAP_TYPE_ANY ))
# 新增程式碼結束
# ...
至此,串列埠除錯工具Jays-PyCOM誕生之軟體優化痞子衡便介紹完畢了,掌聲在哪裡~~~