串口的圖形界面化工具在Windows下很多, 但是在Linux下可選擇的就很少, CuteCom 是相對比較好用的一款了. Ubuntu20.04默認安裝的是0.30.3, 這是一個比較早的版本, 最新的版本是0.51.0, 如果需要自定義RTS電平高低, 例如連接W801這樣RESET連接了RTS的開發板, 就需要升級到最新版.
安裝和更新到最新版本
默認安裝
在Ubuntu下使用apt可以直接安裝
sudo apt install cutecom
這樣安裝的是0.30.3版本
CuteCom的項目地址
如果需要使用最新版本, 需要自行編譯
- 最初在Sourceforge: http://cutecom.sourceforge.net/ 版本最高到0.22.0
- 后來遷移到了Github: https://github.com/neundorf/CuteCom
- 2018-08-22, 遷移到了Gitlab: https://gitlab.com/cutecom/cutecom/
現在最新的代碼在Gitlab, 當前版本為0.51.0
環境准備
CuteCom並未提供預編譯的安裝包, 所以需要自己本地編譯, 本地編譯需要安裝Qt的開發環境
apt install apt-transport-https git dh-make build-essential autoconf autotools-dev qt5-default libssl-dev qt5keychain-dev devscripts
因為CuteCom用到了Qtserial, 所以還需要安裝
apt install libqt5serialport5-dev
Ubuntu22.04
sudo apt install qtbase5-dev qt5-qmake cmake dh-make build-essential autoconf autotools-dev libqt5serialport5-dev
下載和編譯
git clone https://gitlab.com/cutecom/cutecom.git
cd cuteCom
cmake .
make
編譯完成后在同一目錄下, 可以看到cutecom的可執行文件
替換本機安裝的CuteCom
# 確認cutecom的位置
whereis cutecom
# 本例是在/usr/bin
cd /usr/bin
mv cutecom cutecom.0.30.3
mv ~/cutecom/cutecom .
對於使用Qt Creator的用戶, 在cmake之前, Qt Creator不能直接編譯Cutecom項目, 在cmake之后, Qt Creator就可以在IDE里直接編譯了.
新版本中的RTS控制功能
在設置中, 如果選擇了Flow Control為NONE, 在面板上會增加兩個勾選框選項: RTS和DTR. 使用中, 勾選RTS會拉低電平, 不勾選則會使RTS保持低電平, 在連接W801開發板時, 需要取消勾選. 如果在W801開發板上已經給RESET和GND之間加焊了電容, 可以在開發板運行中打開和關閉串口而不會導致開發板重啟.
在連接狀態中, 可以通過勾選/取消勾選實時控制RTS的電平狀態.
Cutecom的代碼解讀
CuteCom的是比較標准的Qt項目
項目文件 CuteCom.pro
項目文件中定義了項目包含的.cpp, .h文件, .ui后綴的界面文件, 資源文件resources.qrc
DISTFILES設置的是qt.astylerc, 這個似乎是代碼格式插件Artistic Style的配置
啟動入口 main.cpp
這里設置程序名稱, 可以看到已經使用了QCoreApplication::translate(
, 可以支持多國化, 但是現在還沒有其它語言的資源
然后就是初始化MainWindow
, show()
啟動
主窗口 mainwindow.cpp 和 mainwindow.h
- 主界面在mainwidnow.ui中定義, 最外層使用的是
QMainWindow
控件 - 主界面上需要包含的元素, 其它的界面元素類, 在mainwindow.h中聲明, 在mainwindow.cpp中創建並加入到對應的QWidget中
- mainwindow.cpp 通過 mainwindows.h 關聯ui ui_mainwindow.h
- ui_mainwindow.h 是由ui文件生成的, 其中不僅聲明了界面元素, 還定義了 setupUi() 方法, 里面有具體的界面展示實現, 以及 retranslateUi() 方法, 用於對界面元素的多國化展示
- setupUi() 在 mainwindow.cpp 的構建方法中調用.
MainWindow::MainWindow(QWidget *parent, const QString &session)
: QMainWindow(parent)
, m_device(new QSerialPort(this))
, m_deviceState(DEVICE_CLOSED)
, m_progress(nullptr)
, m_sz(nullptr)
, m_previousChar('\0')
, m_command_history_model(nullptr)
, m_ctrlCharactersPopup(nullptr)
, m_keyRepeatTimer(this)
, m_keyCode('\0')
, m_cmdBufIndex(0)
, m_reconnectTimer(this)
{
QCoreApplication::setOrganizationName(QStringLiteral("CuteCom"));
// setting it to CuteCom5 will prevent the original CuteCom's settings file
// to be overwritten
QCoreApplication::setApplicationName(QStringLiteral("CuteCom5"));
QCoreApplication::setApplicationVersion(QStringLiteral("%1").arg(CuteCom_VERSION));
// qRegisterMetaType<Settings::LineTerminator>();
setupUi(this);
m_bt_sendfile->setEnabled(false);
m_command_history->setEnabled(false);
m_command_history->setSelectionMode(QAbstractItemView::SelectionMode::ExtendedSelection);
m_lb_logfile->setStyleSheet(" QLabel:hover{color: blue;} ");
...
- retranslateUi() 方法未被調用
- 在 qmainwindow.h 中, 使用
QT_CONFIG()
宏定義根據編譯環境的Qt是否包含某個特性而加入對應的聲明, 不需要開發者關心
/*
The QT_CONFIG macro implements a safe compile time check for features of Qt.
Features can be in three states:
0 or undefined: This will lead to a compile error when testing for it
-1: The feature is not available
1: The feature is available
*/
#define QT_CONFIG(feature) (1/QT_FEATURE_##feature == 1)
- 加入ControlPanel
controlPanel = new ControlPanel(this->centralWidget(), m_settings);
- 加入狀態欄的方式和ControlPanel的方式不一樣
// setup status bar with initial infromation
m_device_statusbar = new StatusBar(this);
m_device_statusbar->sessionChanged(m_settings->getCurrentSession());
this->statusBar()->addWidget(m_device_statusbar);
mainwindow 中的用戶動作, 一部分是通過 connect() 實現關聯, 另一部分是通過 eventFilter(), 通過控件的 installEventFilter() 方法, 將 eventFilter() 中定義的邏輯關聯到當前控件上.
mainwindow 中, 使用 signal 關聯 controlpanl 傳遞來的連接/關閉串口的操作, 調用當前類下的連接/關閉方法
connect(controlPanel, &ControlPanel::openDeviceClicked, this, &MainWindow::openDevice);
connect(controlPanel, &ControlPanel::closeDeviceClicked, this, &MainWindow::closeDevice);
對RTS和DTR的控制
- 處理方法為
void MainWindow::setRTSLineState(int checked)
, 這個方法里面的m_device就是一個QSerialPort設備, 對應的setRequestToSend(true)
方法會將RTS電平拉低(有些硬件的電平是相反的)
void MainWindow::setRTSLineState(int checked)
{
if ((nullptr != m_device) && (true == m_device->isOpen())) {
if (Qt::CheckState::Checked == static_cast<Qt::CheckState>(checked)) {
m_device->setRequestToSend(true);
} else {
m_device->setRequestToSend(false);
}
}
}
- 消息綁定在mainwindow.cpp里,
connect(controlPanel->m_rts_line, &QCheckBox::stateChanged, this, &MainWindow::setRTSLineState);
Settings控制面板的收起和打開
- 信號關聯
connect(m_panel_settings, &QTabWidget::tabBarClicked, this, &ControlPanel::tabClicked);
- 對應的
tabClicked
是在controlpanel.h中定義的
// slots
void tabClicked(int i)
{
Q_UNUSED(i);
toggleMenu();
}
- 在
toogleMenu()
方法里實現了控制面板的收起和打開
void ControlPanel::toggleMenu()
{
// Create animation
QPropertyAnimation *animation = new QPropertyAnimation(this, "pos");
QPoint endPos = m_menuVisible ? QPoint(m_x, m_y) : QPoint(m_x, -13);
// qDebug() << m_menuVisible << endPos;
animation->setStartValue(pos());
animation->setEndValue(endPos);
animation->start();
if (m_menuVisible) {
m_panel_settings->setTabIcon(0, showIcon);
m_menuVisible = false;
} else {
m_panel_settings->setTabIcon(0, hideIcon);
m_menuVisible = true;
m_combo_Baud->setFocus();
}
}
問題
如果使用Ubuntu20.04自帶的qt庫(5.12.x版本)編譯, 控制面板界面的那些輸入和下拉控件高度在HDPI屏幕下會特別小, 如果使用Qt Creator的qt庫(5.14.x版本)編譯, 這個高度就是正常的.