公司之前有委外開發一套收產線資料的程式, 是用VB寫的, 有留下原始碼.
最近有其他同事需要這些功能:
1. 收不同產線資料: 還是連線同一套系統, 只是不同點位的資料.
2. 撈取的頻率不同: 原本是以每分鐘一次, 新的頻率有每秒一次與每一小時一次.
3. 存檔格式不同: 原本以日為單位要增加以月為單位.
所以就原始碼先分析, 發現這程式其實已經是第二版.
第一版: 設定一個"間隔"(Interval), 可以用按鍵調上調下, 另外有一欄"上次完成後幾秒", 並用 Timer 每秒加 1 , 當"上次完成後幾秒"大於或等於"間隔"時, 就啟動撈取的動作.
第二版: 設定四個"間隔時間"按鈕, 有每分鐘, 每10分鐘, 每半小時, 每小時; 按下"間隔時間"的按鈕時, 有一欄"預定撈取時間"也跟著異動, 同樣透過 Timer 查詢目前時間, 如果"目前時間"等於"預定撈取時間", 則啟動撈取的動作.
而且第二版只是把第一版的幾個物件隱藏, 程式碼本身並沒有改成註解(Remark), 所以剛看完只覺得為什麼有2/5的程式沒有用到, 再對照Form隱藏的圖示, 歸納起來才發現這是有兩個版本了.
然後分析程式的寫法, 大概有這些特性:
1. 第一版有可能操作者不小心按到調整間隔的按鈕, 第二版也可能不小心按到不同間隔時間的按鈕, 造成撈取資料並不是預期的時間.
2. 撈取的點位表, 是用CSV格式存放於特定目錄, 每次要撈取資料時, 會將系統指定的檔名, 先讀取一次點位表, 再依點位表撈產線資料, 而重複開啟檔案會讓磁碟I/O增加.
3. 由於不同產線的點位不同, 原本的程式是寫死每條產線250點, 最多9條產線, 陣列名稱: DATA1(251)~DATA9(251) , 還多預留 1 個點但迴圈只抓 250 個 XD .
4. 第二版的預定撈取時間, 是以全手動把時間的字串, 拆成 時 分 秒, 每次 Timer 會把 秒 加 1 , 如果等於 60 , 再把 分 加 1 , 然後 秒 除以 60 取餘數.... @_@ .
5. 可能為了避免資料檔 lock 住, 所以撈資料後先存到 TEMP 目錄, 再 copy 到使用者讀取的目錄, 而 TEMP 目錄並不刪除, 造成檔案容量要 2 倍.
所以要配合新需求改版, 就改了架構:
1. 採用"間隔"時間法, 但是每個系統可以有各自的"間隔", 而且以每天 00:00:00 開始, 換算成當天的秒數, 如果 秒數 除以 間隔 等於 0 , 就執行撈資料.
2. 為了避免 Timer 意外, 也保留上次撈取後已經過了幾秒, 如果大於"間隔", 也會撈取資料.
以上兩點讓至少"間隔"時間內會撈取一次.
3. 因為產線有好幾條, 之前 9 個, 這次加 2 個共 11 個, 而且有條產線只有 1 個點位, 有條產線超過 50 個點位, 原本程式固定用 250 個點位, 造成輸出的 CSV 資料檔後面全部是空字串.
所以這次改用 2 個陣列: 第 1 個是產線清單, 並設定間隔時間, 存檔類型(每日/每月), 前次資料檔名, 點位數, 點位起始值; 第 2 個陣列則是撈取的點位清單. 陣列就大概長這樣:
A.
產線1, 每1秒, 每日1檔, 20190426MM, 2, 0
產線2, 每3600秒, 每月1檔, 201904CHL, 12, 2
產線3, 每60秒, 每日1檔, 20190426ETC, 44, 14
B.
(0) motor1, A(電流), (註解), (值)
(1) motor2, A(電流), (註解), (值)
(2) temp1, C(溫度), (註解), (值)
(3) temp2, C(溫度), (註解), (值)
這樣剛啟動程式時, 自動撈取指定的產線設定檔清單, 再依清單 redim 陣列大小, 並讀取清單檔寫入陣列, 之後程式就不會再讀取設定檔, 減少磁碟 I/O .
4. Timer 本身還是留著, 每 0.25 秒執行 1 次, 比對上次執行的當日秒數(0~86399), 若與目前秒數不同, 表示已經過了 1 秒, 再執行以下動作:
A. 把產線陣列的 離上次撈取秒數 加 1 .
B. 如果 離上次撈取秒數 大於等於 間隔時間 , 或 當日秒數 除以 間隔時間 的 餘數 等於 0 , 就執行 撈取資料 並把 離上次撈取秒數 設定為 0 .
5. 實際撈取資料時, 則是依 產線 陣列, 找到要撈取的點位序號, 再從 點位 陣列, 找到系統內點位代號, 呼叫 OPC 連線讀取值. 這邊還有些額外的網路連線判斷, 如果斷線的話就存特殊字串, 而不呼叫 OPC 避免時間拉太長.
6. 資料存檔還是使用 TEMP 目錄, 存檔後再 copy 到資料目錄; 不過多了一個動作, 就是紀錄前次存檔的檔名, 如果前次存檔檔名與這次不同, 表示可能換日或換月, 這時候就把 TEMP 目錄的前次檔案 copy 到資料目錄; 確定 資料目錄的前次檔案 存在後, 再把 TEMP 目錄的前次檔案刪除. 這樣確保 TEMP 目錄只有目前在使用的檔案.
基本上這樣就改造完了, 不過實際上線時, 因為大部分產線都是每分鐘抓一次, 而當次要撈的點位太多, 造成全部抓完大約 8~9 秒, 另外一條產線的每秒抓一次, 就跳過了 8~9 秒沒有資料.
看了一下 VB 本身沒有真正的多執行緒, 要靠快速切換的寫法, 於是....把程式拆成兩個, 一個執行每分鐘的撈取, 一個執行不是每分鐘的撈取, 然後 Windows 同時執行兩個不同檔名的撈取程式, 裡面指定的目錄也不同.... XD