Tuesday, October 6, 2015

用 Qt 改 GRBL Controller 筆記 (一) compile 同 debug GRBL Controller

無野好玩, 走去學人寫 Qt....就係為左想改個 GRBL Controller....係咪痴痴地呢?

基本資料:

Qt class hierarchy


睇完個圖就識用?  我話 "係", 你吹得我漲咩?
其實如果你有寫開 C++, 基本上都睇得明, 反而都係用一堆 library 做野, 有問題都係即搵.
至於個 project 既架構, 點樣用 Qt gen 個 executable 出黎, 點埋睇下就知了.
之後改野, 如果唔係大改動既, 搵下 D code, 改少少野, 識 C++ 都夠用既.

要 Compile 到 GRBL Controller, 需要有少少改動, 而且未必個個 version 一樣, 以下係一個例子:
(只限於 Windows 下使用以下版本, 其他版本唔敢包.  因為未必人人有裝 VS, 所以無用 VS 版本.)
1) Qt version: Qt 5.5.0 for Windows 32-bit (MinGW 4.9.2, 959 MB)   下載版面 ,   直接下載
2) GRBL Controller 3.6.1 下載版面  ,  直接下載

下載完先安裝好 Qt 5.5.0, 唔理咁多, 乜都裝哂佢.

之後爆開 GRBL Controller 既 source, 再用 Qt 5.5.0 去開.
假設 GRBL Controller 放左去: E:\my.Source\GrblHoming\GrblHoming-3.6.1
最好改下 build 既 path, 左手邊 Projects 入面, 改左 General 下面既 path, 記得改哂 Debug 同 Release.

之後直接 Run 既話, 會出 error (人地都放埋 exe 比人下載, 無理由咁, 唔知係咪其他版本會無事.)
需要改動好系, 只係加番句 #include <QtCore/QObject>  去下面兩個 header file 就得了:

  • Headers\timer.h
  • log4qt\Headers\helpers\factory.h

之後應該行到無事, 但仲有可能 debug 唔到.  原因出在 qextserialport 度.
參考資料: Issue 158: On Windows7, QextSerialEnumerator::getPorts() occur debug break
好似有地方唔記得 check INVALID_HANDLE_VALUE, 直接行 RegCloseKey 就會出事.

解決方法 (修改 Sources 入面 qextserialenumerator_win.cpp:
1)  在 getRegKeyValue 中, 如果提供的是 invlalid handle 就即走

static QString getRegKeyValue(HKEY key, LPCTSTR property)
{
    /* By Super169
     *   Return empty string for invalid handle
     */
    if (key == INVALID_HANDLE_VALUE) return "";
    :
    :
}

2)  在 getDeviceDetailsWin 中, check 下 get 番黎既 key 係咪 invalid

static bool getDeviceDetailsWin(QextPortInfo *portInfo, HDEVINFO devInfo, PSP_DEVINFO_DATA devData
                                 , WPARAM wParam = DBT_DEVICEARRIVAL)
{
    :
    :
    HKEY devKey = ::SetupDiOpenDevRegKey(devInfo, devData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
    /* By Super169
     *   Return false for invalid handle
     */
    if (devKey == INVALID_HANDLE_VALUE)
        return false;

3)  在 enumerateDevicesWin 中, check 下 無問題 而且有名既 port 至加落去個 list 度

static void enumerateDevicesWin(const GUID &guid, QList *infoList)
{
    HDEVINFO devInfo;
    if ((devInfo = ::SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT)) != INVALID_HANDLE_VALUE) {
        SP_DEVINFO_DATA devInfoData;
        devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
        for(int i = 0; ::SetupDiEnumDeviceInfo(devInfo, i, &devInfoData); i++) {
            QextPortInfo info;
            info.productID = info.vendorID = 0;
            /* By Super169
             *   Skip for invalid devices, or empty name
             */
            if ( getDeviceDetailsWin(&info, devInfo, &devInfoData) &&
                 info.portName.compare("") &&
                 !info.portName.startsWith(QLatin1String("LPT"), Qt::CaseInsensitive) )
                infoList->append(info);
        }
        ::SetupDiDestroyDeviceInfoList(devInfo);
    }
}

做左以上幾樣 (第 1 個係 optional, 只係想安全 D), 應該可以 debug 到, 而且唔會出埋 D 無用既 list 了.
之後可以開始進行改動了.

so far 我只係改左個 combo box 既 behaviors, 唔要 auto-complete, 同埋加左兩個 button 改左 step 既設定, 都唔算大工程, 識少少 C++ 都夠了.