comtrade_format.h

1: /*
2:  * 分析解析COMTRADE(IEEE標準電力系統暫態數據交換通用格式)文件格式。
3:  *
4:  * (一)IEEE的COMTRADE數據格式
5:  *
6:  * COMTRADE是IEEE標準電力系統暫態數據交換通用格式。標準為電力系統或電力系統模型採集到的暫態波形和事故數據的文件定義了一種格式。
7:  * 該格式意欲提供一種易於説明的數據交換通用格式。IEEE於1991年提出,並於1999進行了修訂和完善。每個COMTRADE記錄都有一組最多4個與
8:  * 其相關的文件,4個文件中的每一個都具有一個不同的信息等級。4個文件如下:
9:  *
10:  * (1)、標題文件(xxxxxxxx.HDR)
11:  * 標題文件是由COMTRADE數據的原創者建立的一種可選的ASCII文本文件,標題文件的創建者可以以任何需要的順序創建任何信息。標題文件的
12:  * 格式為ASCII。
13:  *
14:  * (2)、 配置文件(xxxxxxxx.CFG)
15:  * 配置文件為一種ASCII文本文件,用於正確地説明數據(.DAT)文件的格式,因此必須以一種具體的格式保存。該文件詮釋了數據(.DAT)文
16:  * 件所包含信息,其中包括諸如採樣速率、通道數量、頻率、通道信息等項。配置文件第一行中的一個字段識別文件所依照的 COMTRADE標準版
17:  * 本的年份(例如1991、1999等)。如果該字段不存在或是空的,則假設文件則遵照標準的最初發行日期(1991)。配置文件還包含識別伴隨
18:  * 的數據文件是以ASCII格式還是以二進制格式存儲的字段。 配置文件有下列信息:
19:  * (a)站名,記錄裝置的特徵,COMTRADE 標準的修改年份
20:  * (b)通道的數量和類型
21:  * (c)通道名稱、單位和轉換系數
22:  * (d)線路頻率
23:  * (e)採樣速率和每一速率下的採樣數量
24:  * (f)第一數據點的日期和時間
25:  * (g)觸發點和日期和時間
26:  * (h)數據文件類型
27:  * (i)時間標記倍乘係數
28:  *
29:  * (3)、 數據文件(xxxxxxxx.DAT)
30:  * 數據文件包含記錄中每個採樣所有輸入通道的值。數據文件包含一個順序號和每次採樣的時間標誌。這些採樣值除記錄模擬輸入的數據之外,
31:  * 也記錄狀態,即表示開/關信號的輸入。
32:  *
33:  * (4)、 信息文件(xxxxxxxx.INF)
34:  * 信息文件是一種文件創建者希望使之對用户有用的信息之外的特別信息。信息文件是可選文件。
35:  *
36:  * COMTRADE定義的所有文件,都在IEEE 標準電力系統暫態數據交換通用格式Std C37.111-1991或IEEE Std C37.111-1999版本中進行了詮釋。
37:  *
38:  * (二) 電力系統故障動態記錄技術準則
39:  *
40:  * 電力行業標準《220kV~500kV電力系統故障動態記錄技術準則》(DL/T 553-94),是故障錄波裝置研製和開發中必須依據的標準。標準在3.6.5
41:  * 條中規定了,輸出的動態過程記錄數據應符合的標準格式與ANSI/IEEE Std C37.111-1991 COMTRADE兼容。同時,標準規定了電力系統發生故障
42:  * 的整個過程中,模擬量採集方式的數據記錄按時段順序進行。
43:  * A時段:系統在擾動開始前的狀態數據,直接輸出原始採集波形,記錄時間≥0.04S
44:  * B時段:系統大擾動初期的狀態數據,直接輸出原始採集波形,記錄時間≥0.1S
45:  * C時段:系統大擾動後的中期狀態數據,可輸出連續工頻有效值,記錄時間≥1.0S
46:  * D時段:系統動態過程數據,每0.1S輸出一個工頻有效值,記錄時間≥20S
47:  * E時段:系統長過程的動態數據,每0.1S輸出一個工頻有效值,記錄時間≥10min
48:  * 這裏,技術標準的數據記錄有兩個主要特點,一是分段記錄,二是記錄的數據不僅可以有按某一採樣率的採樣數據,而且可按一定間隔記錄有效
49:  * 值以代替採樣值。
50:  *
51:  *(三) 微機故障錄波裝置和COMTRADE文件
52:  *
53:  * 微機故障錄波裝置,基本配置分為一台採集站和一台分析站,採集站和分析站之間通過高速以太網連接。採集站負責採集、記錄故障數據;採集
54:  * 站採集的原始數據或記錄的原始故障數據,除了存入採集站的硬盤保存外,還將通過網絡把數據上傳到分析站。分析站程序採用VC 6.0編制,完
55:  * 成對數據處理、波形顯示、自動分析、與遠方通信功能。數據處理中,自動生成符合COMTRADE格式的文件。裝置接收故障採樣數據後,直接將數
56:  * 據處理成COMTRADE數據格式的文件。故障錄波裝置模擬量採樣頻率為5000次/秒,採樣時段根據電力系統故障動態記錄技術準則,做了相應調整,
57:  * 將C時段調整為直接輸出原始採集波形,記錄時間≥1.0S,這樣ABC時段採樣頻率為5000次/秒,存實時的模擬數據;而DE時段採樣頻率為10次/秒,
58:  * 用存最大值數據來代替有效值,這樣便於產生包絡線波形。我們省略了標題文件和信息文件,並且根據不同的批次和故障次數,定義文件名,生
59:  * 成的配置文件( DIR00.CFG )和數據文件( DIR00.DAT ),並同時存放於同一批次文件夾DIR00內。文件示例如下列所示。
60:  *
61:  * (1)、配置文件( DIR00.CFG )
62:  * 城東變電所,03                                                                                     【注:變電站名稱 錄波器編號】
63:  * 12, 8A, 4D                                                                           【注:12格通道,8個模擬通道,4個數字通道】
64:  * 1, 1 Ia, A, mx1, A, 8.46830338, 0.00000000, 0, -2048, 2047   【注:模擬量依次為:通道編號,通道名稱,通道相,XX,單位,fCoefA[變
65:  *              換因子A],fCoefB[變換因子B],fTime[時間偏移],fMin[此模擬量採樣記錄數據最小值], fMax[此模擬量採樣記錄數據最大值],
66:  *              其中:實際值y與採樣記錄數據X的關係:y = fCoefA * X + fCoefB, 所以實際的最值:
67:  *                      Min = fCoefA * fMin + fCoefB;    Max = fCoefA * fMax~ + fCoefB;                                         】
68:  * 2, 1 Ib, B, mx1, A, 8.46830338, 0.00000000, 0, -2048, 2047
69:  * 3, 1 Ic, C, mx1, A, 8.46830338, 0.00000000, 0, -2048, 2047
70:  * 4, 1 IN, N, mx1, A, 8.46830338, 0.00000000, 0, -2048, 2047
71:  * 5, mx1 Ua, A, , kV, 0.15540126, 0.00000000, 0, -2048, 2047
72:  * 6, mx1 Ub, B, , kV, 0.15540126, 0.00000000, 0, -2048, 2047
73:  * 7, mx1 Uc, C, , kV, 0.15540126, 0.00000000, 0, -2048, 2047
74:  * 8, mx1 UN, N, , kV, 0.15540126, 0.00000000, 0, -2048, 2047
75:  * 1,開關1,0                                                                      【注:通道編號/序號、通道名稱、數字量初始狀態】
76:  * 2,開關2,0
77:  * 3,開關3,0
78:  * 4,開關4,1
79:  * 50                                                                                            【注:系統電流電壓的頻率為50Hz】
80:  * 2                                                                                                       【注:有兩個採樣頻率】
81:  * 5000, 6300                                                              【注:第一個採樣頻率: 在採樣率為5000Hz下采了6300個點】
82:  * 10, 200                                                                    【注:第二個採樣頻率: 在採樣率為10Hz下采了200個點】
83:  * 03/07/03,14:46:48.850000                                                                                  【注:採樣開始時間】
84:  * 03/07/03,14:46:49.010000                                                                                  【注:採樣結束時間】
85:  * ASCII                                                           【注:dat文件記錄格式為ASCII, 還有一種是BINARY(二進制格式)】
86:  *
87:  *(2)、 數據文件( DIR00.DAT )
88:  * 1, 0, 46, -54, 10, 0, 1204, -734, -442, 60, 0, 1, 0, 1       【注:依次為:序號,採樣時間,模擬採樣記錄值[按cfg文件的順序],數
89:  *              字採樣記錄值[按cfg文件的順序],其中模擬量實際值算法:y = fCoefA * X + fCoefB, 同最值計算方法;如:
90:  *              對於46表示的實際值y為:y = fCoefA(即8.46830338) * X(即46) + fCoefB(即0.00000000)
91:  *              對於-54表示的實際值y為:y = fCoefA(即8.46830338) * X(即-54) + fCoefB(即0.00000000)
92:  *              對於10表示的實際值y為:y = fCoefA(即8.46830338) * X(即10) + fCoefB(即0.00000000)
93:  *              對於0表示的實際值y為:y = fCoefA(即0.15540126) * X(即0) + fCoefB(即0.00000000)
94:  *              對於1024表示的實際值y為:y = fCoefA(即0.15540126) * X(即1024) + fCoefB(即0.00000000)                     】
95:  * 2, 200, 48, -54, 6, 0, 1218, -682, -504, 60, 0, 1, 0, 1
96:  * 3, 400, 50, -52, 4, -2, 1206, -616, -554, 58, 0, 1, 0, 1
97:  * 4, 600, 52,-50, -2, 0, 1192, -542, -614, 56, 0, 1, 0, 1
98:  *
99:  * 注:以上説明文字部分來自網絡。
100:  *
101:  * 另外,對於Binary保存方式的數據文件(dat文件),數據保存格式為:序號[4字節]、採樣時間[4字節]、模擬量值[按cfg文件的順序,兩字節
102:  * 表示一個模擬量採樣值]、數字量組值[按cfg文件的順序,16個數字量一組,一組用2字節表示,不夠一組的空位(高位)補零構成一組,組內
103:  * 從低位bit依次到高位bit與cfg文件裏的數字量順序對應]。
104:  *
105:  * 經驗表明,目前大部分comtrade文件中的cfg文件中所表示的通道最值與dat中實際的最值都是不相符(出入很大),所以在讀dat的接口中引入
106:  * 了最值統計。
107:  *
108:  * 本代碼支持win32平台和linux平台。
109:  *
110:  * Copyright,lizhi<ibox>
111:  *
112:  * 2012-10-10 V1.0 lizhi<QQ:252240557,msn:ddgooo@hotmail.com> created
113:  *
114:  */
115:
116:
117: #ifndef __INCLUDE_COMTRADE_FORMAT_H
118: #define __INCLUDE_COMTRADE_FORMAT_H
119:
120:
121:
122: /*
123:  * 頭文件
124:  */
125: #include "base_type.h"
126:
127:
128: #if defined (__cplusplus)
129: extern "C" {
130: #endif /* defined (__cplusplus) */
131:
132:
133: /*
134:  * 宏開關 定義為文件讀寫
135:  */
136: #define CMTR_IOFILE
137:
138:
139:
140: /*
141:  * 宏定義文件的讀寫操作,可以根據需要改寫該接口,如重定義
142:  * 為網口的recv\send、串口r\w等。
143:  *
144:  * _my_read_cmtr_bufn/_my_read_cmtr_bufn - cmtr的讀寫操作
145:  * @pfd: 讀寫地址,可以為文件的fd、或者buffer地址等
146:  * @buf: 緩衝區地址
147:  * @count: 需要讀寫的字節數
148:  *
149:  */
150: #if defined(CMTR_IOFILE)
151: typedef int _my_cmtr_ioptr;
152: #define _my_read_cmtr_bufn(pfd, buf, count)             \
153:         do {                                            \
154:                 if (read((pfd), (buf), (count)) <= 0) { \
155:                         (pfd) = -1;                     \
156:                 }                                       \
157:         } while(0);
158: #define _my_write_cmtr_bufn(pfd, buf, count)            \
159:         do {                                            \
160:                 if (write((pfd), (buf), (count)) <= 0) {\
161:                         (pfd) = -1;                     \
162:                 }                                       \
163:         } while(0);
164: #define _my_check_cmtr_ptr(pfd)                            \
165:         (((pfd) != -1) && ((pfd) != 0))
166: #elif defined(CMTR_IOBUFFER)
167: typedef u8* _my_cmtr_ioptr;
168: #define _my_read_cmtr_bufn(pfd, buf, count)             \
169:         do {                                            \
170:                 memcpy((buf), (pfd), (count));          \
171:                 (pfd) += (count);                       \
172:         } while(0);
173: #define _my_write_cmtr_bufn(pfd, buf, count)            \
174:         do {                                            \
175:                 memcpy((pfd), (buf), (count));          \
176:                 (pfd) += (count);                       \
177:         } while(0);
178: #define _my_check_cmtr_ptr(pfd)                            \
179:         (((pfd) != -1) && ((pfd) != 0))
180: #endif
181:
182:
183:
184: /*
185:  * 關於comtrade文件配置文件的宏定義。
186:  * 在此採用預定義最大個數方法,避免動態內存管理的問題。
187:  *
188:  * 相關字符串最大字符個數,一般不會超過16個;
189:  * 模擬量端口最大個數,一般不會超過64個;
190:  * 數字量量端口最大個數,一般不會超過64個;
191:  * 採樣率最大個數,一般不會超過8個;
192:  *
193:  */
194: #define  CMTR_STRING_MAX_LENGTH         64
195: #define  CMTR_ANALOG_MAX_COUNT          255
196: #define  CMTR_DIGIT_MAX_COUNT           255
197: #define  CMTR_SMPRATE_MAX_COUNT         255
198:
199:
200:
201: /*
202:  * cmtr_cfg_analog - 配置文件模擬量信息
203:  * @index: 模擬量端口序號(只是編號,解析時不做序號用);
204:  * @name: 模擬量端口名稱;
205:  * @phase: 模擬量端口相標識,值如(A、B、C、N等);
206:  * @element:標識(還未知,待補充),一般為空;
207:  * @unit: 模擬量端口數值的單位,該單位常用來區分該端口是電流還是電流,值如:kV、V、A、mA等;
208:  * @factor_a: 係數a,一般為整數,可以是浮點數;
209:  * @factor_b: 係數b,一般為整數,可以是浮點數;
210:  * @offset_time: 時間偏移,指第一個點的時間偏移量,一般為0;
211:  * @smp_min: 通道的最小採用值,一般為整數,國內有些變態的儀器會生成浮點數(在次不支持);
212:  * @smp_max: 通道的最大采用值,一般為整數,國內有些變態的儀器會生成浮點數(在次不支持);
213:  *
214:  * 通道採樣的實際值計算方法:實際值 = factor_a * smp_value + factor_b;所以根據該公式,可以計算
215:  * 通道的最小值為:factor_a * smp_min + factor_b,最大值為:factor_a * smp_max + factor_b。
216:  *
217:  * 注:本來smp_min、smp_max為兩個字節的一個數據(即最大為65535),但不同廠家會生成很大的四字節數據,
218:  *    所以採用s32類型;factor_a、factor_b用double類型,用float可能會丟精度;為了提供解析程序的適
219:  *    應性,以適應國內各種變態的有標準不遵循的廠家的儀器生成的cmtr文件。
220:  *
221:  */
222: struct cmtr_cfg_analog {
223:         s32 index;
224:         u8 name[CMTR_STRING_MAX_LENGTH];
225:         u8 phase[CMTR_STRING_MAX_LENGTH];
226:         u8 element[CMTR_STRING_MAX_LENGTH];
227:         u8 unit[CMTR_STRING_MAX_LENGTH];
228:         f64 factor_a;
229:         f64 factor_b;
230:         s32 offset_time;
231:         s32 smp_min;
232:         s32 smp_max;
233: };
234:
235:
236: /*
237:  * cmtr_cfg_digit - 配置文件數字量信息
238:  * @index: 數字量端口序號(只是編號,解析時不做序號用);
239:  * @name: 數字量端口名稱;
240:  * @state: 數字量起始狀態值,一般為1或者0,很少情況下會為2;
241:  *
242:  */
243: struct cmtr_cfg_digit {
244:         s32 index;
245:         u8 name[CMTR_STRING_MAX_LENGTH];
246:         s8 state;
247: };
248:
249: /*
250:  * cmtr_cfg_smprate_info - 配置文件採樣點信息
251:  * @rate: 採樣率,一般為整數,也有小數表示的;
252:  * @point: 該採樣率下采樣的點數,為整數;
253:  *
254:  */
255: struct cmtr_cfg_smprate {
256:         f32 rate;
257:         s32 point;
258: };
259:
260: /*
261:  * cmtr_cfg_info - 配置文件信息。
262:  * @station_name: 廠站名稱;
263:  * @kymograph_id: 錄波器編號;
264:  * @analog_count: 模擬量個數;
265:  * @digit_count: 數字量個數;
266:  * @analogs: 模擬量信息;
267:  * @digits: 數字量信息;
268:  * @frequency: 基本頻率,一般為額定頻率,指的是電網頻率;
269:  * @smprate_count: 採樣率個數;
270:  * @smprates: 採樣率信息;
271:  * @begin_time: 錄波開始時間;
272:  * @end_time: 錄波結束時間;
273:  * @file_type: 數據文件類型,可以“ASCII”和“Binary”,ASCII類型為dat文件可以用記事本打開看詳
274:  *             細的採樣信息;binary格式的只能用特殊的工具查看,為二進制數據文件;
275:  *
276:  */
277: typedef struct cmtr_cfg_info {
278:         u8 station_name[CMTR_STRING_MAX_LENGTH];
279:         u8 kymograph_id[CMTR_STRING_MAX_LENGTH];
280:         s32 analog_count;
281:         s32 digit_count;
282:         struct cmtr_cfg_analog analogs[CMTR_ANALOG_MAX_COUNT];
283:         struct cmtr_cfg_digit digits[CMTR_DIGIT_MAX_COUNT];
284:         f32 frequency;
285:         s32 smprate_count;
286:         struct cmtr_cfg_smprate smprates[CMTR_SMPRATE_MAX_COUNT];
287:         u8 begin_time[CMTR_STRING_MAX_LENGTH];
288:         u8 end_time[CMTR_STRING_MAX_LENGTH];
289:         u8 file_type[CMTR_STRING_MAX_LENGTH];
290: };
291:
292:
293:
294: /*
295:  * cmtr_dat_smpdot - 數據文件中的採樣點數據信息.
296:  * @index: 端口序號(只是編號,解析時不做序號用);
297:  * @time: 採樣點採樣時間偏移量,單位微妙;
298:  * @analogs: 模擬量信息,一般為有符號整數,國內有些變態的儀器會生成浮點數(在此不支持);
299:  * @digits: 數字量信息,為有符號整數;
300:  *
301:  */
302: struct cmtr_dat_smpdot{
303:         s32 index;
304:         s32 time;
305:         s32 analogs[CMTR_ANALOG_MAX_COUNT];
306:         s8 digits[CMTR_DIGIT_MAX_COUNT];
307: };
308:
309:
310:
311:
312:
313: /*
314:  * write_cmtr_cfg_info - 寫cmtr配置文件.
315:  * @pfd:  輸入輸出參數,地址
316:  * @cfg:輸入參數,cmtr(cfg文件)結構體
317:  * @counter:  輸出參數,寫入的字節計數器;
318:  *
319:  * 返回當前pfd指針,寫失敗返回NULL
320:  *
321:  */
322: _my_cmtr_ioptr write_cmtr_cfg_info(_my_cmtr_ioptr pfd,
323:                                    struct cmtr_cfg_info *cfg,
324:                                    int *counter);
325:
326:
327: /*
328:  * write_cmtr_dat_smpdot_ascii - 寫cmtr採樣點數據信息(ascii格式).
329:  * @pfd:  輸入輸出參數,地址
330:  * @analog_count: 輸入參數,模擬量個數;
331:  * @digit_count: 輸入參數,數字量個數;
332:  * @dot:  輸入參數,採樣點信息;
333:  * @counter:  輸出參數,寫入的字節計數器;
334:  *
335:  * 返回當前pfd指針,寫失敗返回NULL
336:  *
337:  */
338: _my_cmtr_ioptr write_cmtr_dat_smpdot_ascii(_my_cmtr_ioptr pfd,
339:                                            int analog_count, int digit_count,
340:                                            struct cmtr_dat_smpdot *dot,
341:                                            int* counter);
342:
343: /*
344:  * write_cmtr_dat_smpdot_binary - 寫cmtr採樣點數據信息(binary格式).
345:  * @pfd:  輸入輸出參數,地址
346:  * @big_endian_tag: 輸入參數,標識文件中數據的字節順序,為FALSE按照小端寫(默認值),True按照大端寫;
347:  * @analog_count: 輸入參數,模擬量個數;
348:  * @digit_count: 輸入參數,數字量個數;
349:  * @dot:  輸入參數,採樣點信息;
350:  * @counter:  輸出參數,寫入的字節計數器;
351:  *
352:  * 返回當前pfd指針,寫失敗返回NULL
353:  *
354:  */
355: _my_cmtr_ioptr write_cmtr_dat_smpdot_binary(_my_cmtr_ioptr pfd,
356:                                             u8 big_endian_tag,
357:                                             int analog_count, int digit_count,
358:                                             struct cmtr_dat_smpdot *dot,
359:                                             int* counter);
360:
361:
362: /*
363:  * read_cmtr_cfg_info - 讀cmtr配置文件.
364:  * @pfd:  輸入輸出參數,地址
365:  * @cfg:輸出參數,cmtr(cfg文件)結構體
366:  * @counter:  輸出參數,讀取的字節計數器;
367:  *
368:  * 返回當前pfd指針,讀失敗返回NULL
369:  *
370:  */
371: _my_cmtr_ioptr read_cmtr_cfg_info(_my_cmtr_ioptr pfd,
372:                                   struct cmtr_cfg_info *cfg,
373:                                   int* counter);
374:
375:
376: /*
377:  * read_cmtr_dat_smpdot_ascii - 讀ascii格式cmtr採樣點數據信息.
378:  * @pfd:  輸入輸出參數,地址
379:  * @read_buf: 輸入參數,讀緩衝,在外部申請內存,避免在內部頻繁申請、釋放內存;
380:  * @buf_size: 輸入參數,讀緩衝區的大小;
381:  * @analog_count: 輸入參數,模擬量個數;
382:  * @digit_count: 輸入參數,數字量個數;
383:  * @dot:  輸出參數,採樣點信息;
384:  * @the_smp_mins: 輸出參數,統計最小值,為數組,個數至少為analog_count個,值為NULL時忽略統計;
385:  * @the_smp_maxs: 輸出參數,統計最大值,為數組,個數至少為analog_count個,值為NULL時忽略統計;
386:  * @counter:  輸出參數,讀取的字節計數器;
387:  *
388:  * 返回當前pfd指針,讀失敗返回NULL
389:  *
390:  */
391: _my_cmtr_ioptr read_cmtr_dat_smpdot_ascii(_my_cmtr_ioptr pfd,
392:                                           u8 *read_buf, int buf_size,
393:                                           int analog_count, int digit_count,
394:                                           struct cmtr_dat_smpdot *dot,
395:                                           u16* the_smp_mins, u16* the_smp_maxs,
396:                                           int* counter);
397:
398: /*
399:  * read_cmtr_dat_smpdot_binary - 讀bin格式cmtr採樣點數據信息.
400:  * @pfd:  輸入輸出參數,地址
401:  * @big_endian_tag: 輸入參數,標識文件中數據的字節順序,為FALSE按照小端讀(默認值),True按照大端讀;
402:  * @analog_count: 輸入參數,模擬量個數;
403:  * @digit_count: 輸入參數,數字量個數;
404:  * @dot:  輸出參數,採樣點信息;
405:  * @the_smp_mins: 輸出參數,統計最小值,為數組,個數至少為analog_count個,值為NULL時忽略統計;
406:  * @the_smp_maxs: 輸出參數,統計最大值,為數組,個數至少為analog_count個,值為NULL時忽略統計;
407:  * @counter:  輸出參數,讀取的字節計數器;
408:  *
409:  * 返回當前pfd指針,讀失敗返回NULL
410:  *
411:  */
412: _my_cmtr_ioptr read_cmtr_dat_smpdot_binary(_my_cmtr_ioptr pfd, u8 big_endian_tag,
413:                                            int analog_count, int digit_count,
414:                                            struct cmtr_dat_smpdot *dot,
415:                                            u32* the_smp_mins, u32* the_smp_maxs,
416:                                            int* counter);
417:
418: /*
419:  * print_cmtr_cfg_info - 打印cmtr文件配置數.
420:  * @cfg:  輸入參數,cmtr文件配置數據;
421:  *
422:  */
423: void print_cmtr_cfg_info(struct cmtr_cfg_info *cfg);
424:
425: /*
426:  * print_cmtr_dat_smpdot - 打印cmtr數據文件採樣點.
427:  * @cfg:  輸入參數,cmtr文件配置數據;
428:  * @analog_count: 輸入參數,模擬量個數;
429:  * @digit_count: 輸入參數,數字量個數;
430:  * @dot:  輸入參數,採樣點信息;
431:  *
432:  */
433: void print_cmtr_dat_smpdot(int analog_count, int digit_count,
434:                            struct cmtr_dat_smpdot *dot);
435:
436:
437:
438: #if defined (__cplusplus)
439: }
440: #endif /* defined (__cplusplus) */
441:
442:
443: #endif /* __INCLUDE_COMTRADE_FORMAT_H */

 

comtrade_format.c

1: /*
2:  * 分析解析COMTRADE(IEEE標準電力系統暫態數據交換通用格式)文件格式。
3:  *
4:  *
5:  * 本代碼支持win32平台和linux平台。
6:  *
7:  * Copyright,lizhi<ibox>
8:  *
9:  * 2012-10-10 V1.0 lizhi<QQ:252240557,msn:ddgooo@hotmail.com> created
10:  *
11:  */
12:
13: /*
14:  * 頭文件
15:  */
16: #include "base_type.h"
17: #include "base_include.h"
18: #include "base_debug.h"
19: #include "base_endian.h"
20: #include "base_function.h"
21: #include "comtrade_format.h"
22:
23:
24: /*
25:  * 測試宏開關
26:  */
27: ///*
28: #define CMTR_CONSOLE_DEMO
29: //*/
30:
31:
32: /*
33:  * _my_read_cmtr_data/_my_write_cmtr_data - 讀取/寫入並且轉換cmtr數據。
34:  * @src: 讀寫地址,為buffer地址;
35:  * @data:  讀取/寫入的數據;
36:  * @count: 需要讀取/寫入的字節個數;
37:  * @counter:  讀取/寫入的字節計數器;
38:  *
39:  */
40: #define _my_read_cmtr_data(src, data, count, counter)                   \
41:         do {                                                            \
42:                 if (_my_check_cmtr_ptr(src)) {                          \
43:                         _my_read_cmtr_bufn((src), (data), (count));     \
44:                         (counter) += (count);                           \
45:                 }                                                       \
46:         } while(0);
47: #define _my_write_cmtr_data(src, data, count, counter)                  \
48:         do {                                                            \
49:                 if (_my_check_cmtr_ptr(src)) {                          \
50:                         _my_write_cmtr_bufn((src), (data), (count));    \
51:                         (counter) +=(count);                            \
52:                 }                                                       \
53:         } while(0);
54:
55: /*
56:  * write_cmtr_cfg_info - 寫cmtr配置文件.
57:  * @pfd:  輸入輸出參數,地址
58:  * @cfg:輸入參數,cmtr(cfg文件)結構體
59:  * @counter:  輸出參數,寫入的字節計數器;
60:  *
61:  * 返回當前pfd指針,寫失敗返回NULL
62:  *
63:  */
64: _my_cmtr_ioptr write_cmtr_cfg_info(_my_cmtr_ioptr pfd, struct cmtr_cfg_info *cfg, int *counter)
65: {
66:         u32 strlenr = 0;
67:         u32 strmaxl = CMTR_STRING_MAX_LENGTH * 10;
68:         u8* strline = (u8 *)_my_buf_malloc((size_t)(strmaxl));
69:         u32 index = 0;
70:
71:         _my_cmtr_ioptr curr_pfd = pfd;
72:
73:         memset(strline, '\0', strmaxl);
74:         strlenr = sprintf(strline, "%s,%s\n", cfg->station_name, cfg->kymograph_id);
75:         _my_write_cmtr_data(curr_pfd, strline, strlenr, *counter);
76:
77:         memset(strline, '\0', strmaxl);
78:         strlenr = sprintf(strline, "%d,%dA,%dD\n", cfg->analog_count + cfg->digit_count, cfg->analog_count, cfg->digit_count);
79:         _my_write_cmtr_data(curr_pfd, strline, strlenr, *counter);
80:
81:         for (index = 0; index < cfg->analog_count; index++) {
82:                 memset(strline, '\0', strmaxl);
83:                 strlenr = sprintf(strline, "%d,%s,%s,%s,%s,%lf,%lf,%d,%d,%d\n",
84:                                   cfg->analogs[index].index,
85:                                   cfg->analogs[index].name,
86:                                   cfg->analogs[index].phase,
87:                                   cfg->analogs[index].element,
88:                                   cfg->analogs[index].unit,
89:                                   cfg->analogs[index].factor_a,
90:                                   cfg->analogs[index].factor_b,
91:                                   cfg->analogs[index].offset_time,
92:                                   cfg->analogs[index].smp_min,
93:                                   cfg->analogs[index].smp_max);
94:                 _my_write_cmtr_data(curr_pfd, strline, strlenr, *counter);
95:         }
96:
97:         for (index = 0; index < cfg->digit_count; index++) {
98:                 memset(strline, '\0', strmaxl);
99:                 strlenr = sprintf(strline, "%d,%s,%d\n",
100:                                   cfg->digits[index].index,
101:                                   cfg->digits[index].name,
102:                                   cfg->digits[index].state);
103:                 _my_write_cmtr_data(curr_pfd, strline, strlenr, *counter);
104:         }
105:
106:         memset(strline, '\0', strmaxl);
107:         strlenr = sprintf(strline, "%f\n", cfg->frequency);
108:         _my_write_cmtr_data(curr_pfd, strline, strlenr, *counter);
109:
110:         memset(strline, '\0', strmaxl);
111:         strlenr = sprintf(strline, "%d\n", cfg->smprate_count);
112:         _my_write_cmtr_data(curr_pfd, strline, strlenr, *counter);
113:         for (index = 0; index < cfg->smprate_count; index++) {
114:                 memset(strline, '\0', strmaxl);
115:                 strlenr = sprintf(strline, "%f,%d\n", cfg->smprates[index].rate, cfg->smprates[index].point);
116:                 _my_write_cmtr_data(curr_pfd, strline, strlenr, *counter);
117:         }
118:
119:         memset(strline, '\0', strmaxl);
120:         strlenr = sprintf(strline, "%s\n", cfg->begin_time);
121:         _my_write_cmtr_data(curr_pfd, strline, strlenr, *counter);
122:         memset(strline, '\0', strmaxl);
123:         strlenr = sprintf(strline, "%s\n", cfg->end_time);
124:         _my_write_cmtr_data(curr_pfd, strline, strlenr, *counter);
125:         strlenr = sprintf(strline, "%s\n", cfg->file_type);
126:         _my_write_cmtr_data(curr_pfd, strline, strlenr, *counter);
127:
128:         _my_buf_free(strline);
129:
130:         return curr_pfd;
131: }
132:
133:
134: /*
135:  * write_cmtr_dat_smpdot_ascii - 寫cmtr採樣點數據信息(ascii格式).
136:  * @pfd:  輸入輸出參數,地址
137:  * @analog_count: 輸入參數,模擬量個數;
138:  * @digit_count: 輸入參數,數字量個數;
139:  * @dot:  輸入參數,採樣點信息;
140:  * @counter:  輸出參數,寫入的字節計數器;
141:  *
142:  * 返回當前pfd指針,寫失敗返回NULL
143:  *
144:  */
145: _my_cmtr_ioptr write_cmtr_dat_smpdot_ascii(_my_cmtr_ioptr pfd, int analog_count, int digit_count, struct cmtr_dat_smpdot *dot, int* counter)
146: {
147:         u32 strlenr = 0;
148:         u32 strmaxl = CMTR_STRING_MAX_LENGTH;
149:         u8* strline = (u8 *)_my_buf_malloc((size_t)(strmaxl));
150:         int index = 0;
151:
152:         _my_cmtr_ioptr curr_pfd = pfd;
153:
154:         _my_assert(pfd && dot);
155:
156:         memset(strline, '\0', strmaxl);
157:         strlenr = sprintf(strline, "%d,%d", dot->index, dot->time);
158:         _my_write_cmtr_data(curr_pfd, strline, strlenr, *counter);
159:         for (index = 0; index < analog_count; index++) {
160:                 memset(strline, '\0', strmaxl);
161:                 strlenr = sprintf(strline, ",%d", dot->analogs[index]);
162:                 _my_write_cmtr_data(curr_pfd, strline, strlenr, *counter);
163:         }
164:         for (index = 0; index < digit_count; index++) {
165:                 memset(strline, '\0', strmaxl);
166:                 strlenr = sprintf(strline, ",%d", dot->digits[index]);
167:                 _my_write_cmtr_data(curr_pfd, strline, strlenr, *counter);
168:         }
169:         memset(strline, '\0', strmaxl);
170:         strlenr = sprintf(strline, "\n");
171:         _my_write_cmtr_data(curr_pfd, strline, strlenr, *counter);
172:
173:         _my_buf_free(strline);
174:
175:         return curr_pfd;
176: }
177:
178:
179: /*
180:  * write_cmtr_dat_smpdot_binary - 寫cmtr採樣點數據信息(binary格式).
181:  * @pfd:  輸入輸出參數,地址
182:  * @big_endian_tag: 輸入參數,標識文件中數據的字節順序,為FALSE按照小端寫(默認值),True按照大端寫;
183:  * @analog_count: 輸入參數,模擬量個數;
184:  * @digit_count: 輸入參數,數字量個數;
185:  * @dot:  輸入參數,採樣點信息;
186:  * @counter:  輸出參數,寫入的字節計數器;
187:  *
188:  * 返回當前pfd指針,寫失敗返回NULL
189:  *
190:  */
191: _my_cmtr_ioptr write_cmtr_dat_smpdot_binary(_my_cmtr_ioptr pfd, u8 big_endian_tag, int analog_count, int digit_count, struct cmtr_dat_smpdot *dot, int* counter)
192: {
193:         s16 data16 = 0x00;
194:         s32 data32 = 0x00;
195:         int oldnum = 0;
196:
197:         s16 datatp = 0x00;
198:
199:         int index = 0;
200:
201:         _my_cmtr_ioptr curr_pfd = pfd;
202:
203:         oldnum = (*counter);
204:         data32 = big_endian_tag ? _my_htob32(dot->index) : _my_htol32(dot->index);
205:         _my_write_cmtr_data(curr_pfd, &data32, 4, *counter);
206:         if ((*counter) <= oldnum) {
207:                 return NULL;
208:         }
209:         oldnum = (*counter);
210:         data32 = big_endian_tag ? _my_htob32(dot->time) : _my_htol32(dot->time);
211:         _my_write_cmtr_data(curr_pfd, &data32, 4, *counter);
212:         if ((*counter) <= oldnum) {
213:                 return NULL;
214:         }
215:         for (index = 0; index < analog_count; index++) {
216:                 oldnum = (*counter);
217:                 datatp = (s16)(dot->analogs[index]);
218:                 data16 = big_endian_tag ? _my_htob16(datatp) : _my_htol16(datatp);
219:                 _my_write_cmtr_data(curr_pfd, &data16, 2, *counter);
220:                 if ((*counter) <= oldnum) {
221:                         return NULL;
222:                 }
223:         }
224:
225:         data16 = 0x0000;
226:         for (index = 0; index < digit_count; index++) {
227:                 if (dot->digits[index]) {
228:                         data16 |= (0x0001 << (index % 16));
229:                 }
230:                 if (((index % 16) == 0) && (index != 0)) {
231:                         oldnum = (*counter);
232:                         data16 = big_endian_tag ? _my_htob16(data16) : _my_htol16(data16);
233:                         _my_write_cmtr_data(curr_pfd, &data16, 2, *counter);
234:                         if ((*counter) <= oldnum) {
235:                                 return NULL;
236:                         }
237:                 }
238:         }
239:         if (((index % 16) != 1) && (index != 0)) {
240:                 oldnum = (*counter);
241:                 data16 = big_endian_tag ? _my_htob16(data16) : _my_htol16(data16);
242:                 _my_write_cmtr_data(curr_pfd, &data16, 2, *counter);
243:                 if ((*counter) <= oldnum) {
244:                         return NULL;
245:                 }
246:         }
247:
248:         return curr_pfd;
249: }
250:
251:
252: /*
253:  * read_cmtr_cfg_line - 讀cmtr配置文件一行,跳過空行.
254:  * @pfd:  輸入輸出參數,地址;
255:  * @strline:輸出參數,內容緩衝區;
256:  * @size:輸入參數,緩衝區大小;
257:  * @strlend: 輸出參數,讀取的line的結束字符指針;
258:  * @counter:  輸出參數,讀取的字節計數器;
259:  *
260:  * 返回當前pfd指針,讀失敗返回NULL。
261:  *
262:  */
263: static _my_cmtr_ioptr read_cmtr_cfg_line(_my_cmtr_ioptr pfd, char *strline, int size, char **strlend,int *counter)
264: {
265:         int pos = 0;
266:         int oldnum = 0;
267:         u8 datard = 0;
268:         _my_cmtr_ioptr curr_pfd = pfd;
269:         (*strlend) = NULL;
270:         if (size <= 0) {
271:                 return NULL;
272:         }
273:         if ((!strline) || (!counter)) {
274:                 return NULL;
275:         }
276:
277:         memset(strline, '\0', size);
278:         while (_my_check_cmtr_ptr(curr_pfd)) {
279:                 oldnum = (*counter);
280:                 datard = '\0';
281:                 _my_read_cmtr_data(curr_pfd, &datard, 1, *counter);
282:                 if ((*counter) > oldnum) {
283:                         if (( datard != '\0') && ( datard != '\r') && ( datard != '\n')) {
284:                                 if ((*strlend) < (strline + size)) {
285:                                         (*(strline + pos)) = datard;
286:                                         (*strlend) = strline + pos;
287:                                 }
288:                                 pos += 1;
289:                                 continue;
290:                         } else {
291:                                 break;
292:                         }
293:                 }
294:         }
295:         if (pos == 0) {
296:                 if (_my_check_cmtr_ptr(curr_pfd)) {
297:                         return read_cmtr_cfg_line(curr_pfd, strline, size, strlend, counter);
298:                 } else {
299:                         return NULL;
300:                 }
301:         }
302:
303:         return curr_pfd;
304: }
305:
306: /*
307:  * read_cmtr_cfg_one_analog - 分析一行模擬量信息.
308:  * @analog:  輸出參數,模擬量信息;
309:  * @strline:輸入參數,內容緩衝區;
310:  * @size:輸入參數,緩衝區大小;
311:  * @strlend: 輸入參數,讀取的line結束指針;
312:  *
313:  * 返回TRUE成功,失敗返回FALSE。
314:  *
315:  */
316: static u8 read_cmtr_cfg_one_analog(struct cmtr_cfg_analog *analog, char *strline, int size, char *strlend)
317: {
318:         int dataint = 0;
319:         f64 dataflt = 0;
320:         char* ptrpos = 0;
321:         char* strlcur = strline;
322:
323:         ptrpos = strchr(strlcur, ',');
324:         if ((!ptrpos) || (ptrpos >= strlend)) {
325:                 return FALSE;
326:         }
327:         if (sscanf(strlcur, "%d%*s", &dataint) <= 0) {
328:                 return FALSE;
329:         }
330:         analog->index = dataint;
331:
332:         strlcur = ptrpos += 1;
333:         ptrpos = strchr(strlcur, ',');
334:         if ((!ptrpos) || (ptrpos >= strlend)) {
335:                 return FALSE;
336:         }
337:         memset(analog->name, '\0', CMTR_STRING_MAX_LENGTH);
338:         memcpy(analog->name, strlcur, ptrpos-strlcur);
339:
340:         strlcur = ptrpos += 1;
341:         ptrpos = strchr(strlcur, ',');
342:         if ((!ptrpos) || (ptrpos >= strlend)) {
343:                 return FALSE;
344:         }
345:         memset(analog->phase, '\0', CMTR_STRING_MAX_LENGTH);
346:         memcpy(analog->phase, strlcur, ptrpos-strlcur);
347:
348:         strlcur = ptrpos += 1;
349:         ptrpos = strchr(strlcur, ',');
350:         if ((!ptrpos) || (ptrpos >= strlend)) {
351:                 return FALSE;
352:         }
353:         memset(analog->element, '\0', CMTR_STRING_MAX_LENGTH);
354:         memcpy(analog->element, strlcur, ptrpos-strlcur);
355:
356:         strlcur = ptrpos += 1;
357:         ptrpos = strchr(strlcur, ',');
358:         if ((!ptrpos) || (ptrpos >= strlend)) {
359:                 return FALSE;
360:         }
361:         memset(analog->unit, '\0', CMTR_STRING_MAX_LENGTH);
362:         memcpy(analog->unit, strlcur, ptrpos-strlcur);
363:
364:         strlcur = ptrpos += 1;
365:         ptrpos = strchr(strlcur, ',');
366:         if ((!ptrpos) || (ptrpos >= strlend)) {
367:                 return FALSE;
368:         }
369:         if (sscanf(strlcur, "%lf%*s", &dataflt) <= 0) {
370:                 return FALSE;
371:         }
372:         analog->factor_a = dataflt;
373:
374:         strlcur = ptrpos += 1;
375:         ptrpos = strchr(strlcur, ',');
376:         if ((!ptrpos) || (ptrpos >= strlend)) {
377:                 return FALSE;
378:         }
379:         if (sscanf(strlcur, "%lf%*s", &dataflt) <= 0) {
380:                 return FALSE;
381:         }
382:         analog->factor_b = dataflt;
383:
384:         strlcur = ptrpos += 1;
385:         ptrpos = strchr(strlcur, ',');
386:         if ((!ptrpos) || (ptrpos >= strlend)) {
387:                 return FALSE;
388:         }
389:         if (sscanf(strlcur, "%d%*s", &dataint) <= 0) {
390:                 return FALSE;
391:         }
392:         analog->offset_time = dataint;
393:
394:         strlcur = ptrpos += 1;
395:         ptrpos = strchr(strlcur, ',');
396:         if ((!ptrpos) || (ptrpos >= strlend)) {
397:                 return FALSE;
398:         }
399:         if (sscanf(strlcur, "%d%*s", &dataint) <= 0) {
400:                 return FALSE;
401:         }
402:         analog->smp_min = dataint;
403:
404:         strlcur = ptrpos += 1;
405:         if (ptrpos > strlend) {
406:                 return FALSE;
407:         }
408:         if (sscanf(strlcur, "%d%*s", &dataint) <= 0) {
409:                 return FALSE;
410:         }
411:         analog->smp_max = dataint;
412:
413:         return TRUE;
414: }
415:
416: /*
417:  * read_cmtr_cfg_one_digit - 分析一行數字量信息.
418:  * @analog:  輸出參數,數字量信息;
419:  * @strline:輸入參數,內容緩衝區;
420:  * @size:輸入參數,緩衝區大小;
421:  * @strlend: 輸入參數,讀取的line結束指針;
422:  *
423:  * 返回TRUE成功,失敗返回FALSE。
424:  *
425:  */
426: static u8 read_cmtr_cfg_one_digit(struct cmtr_cfg_digit *digit, char *strline, int size, char *strlend)
427: {
428:         int dataint = 0;
429:         char* ptrpos = 0;
430:         char* strlcur = strline;
431:         ptrpos = strchr(strlcur, ',');
432:         if ((!ptrpos) || (ptrpos >= strlend)) {
433:                 return FALSE;
434:         }
435:         if (sscanf(strlcur, "%d%*s", &dataint) <= 0) {
436:                 return FALSE;
437:         }
438:         digit->index = dataint;
439:
440:         strlcur = ptrpos += 1;
441:         ptrpos = strchr(strlcur, ',');
442:         if ((!ptrpos) || (ptrpos >= strlend)) {
443:                 return FALSE;
444:         }
445:         memset(digit->name, '\0', CMTR_STRING_MAX_LENGTH);
446:         memcpy(digit->name, strlcur, ptrpos-strlcur);
447:
448:         strlcur = ptrpos += 1;
449:         if (ptrpos > strlend) {
450:                 return FALSE;
451:         }
452:         if (sscanf(strlcur, "%d", &dataint) <= 0) {
453:                 return FALSE;
454:         }
455:         digit->state = dataint;
456:
457:         return TRUE;
458: }
459:
460: /*
461:  * read_cmtr_cfg_info - 讀cmtr配置文件.
462:  * @pfd:  輸入輸出參數,地址
463:  * @cfg:輸出參數,cmtr(cfg文件)結構體
464:  * @counter:  輸出參數,讀取的字節計數器;
465:  *
466:  * 返回當前pfd指針,讀失敗返回NULL
467:  *
468:  */
469: _my_cmtr_ioptr read_cmtr_cfg_info(_my_cmtr_ioptr pfd, struct cmtr_cfg_info *cfg, int* counter)
470: {
471:         u8 returntag = FALSE;
472:
473:         int strsize = 1024;
474:         char* strline = NULL;
475:         char* strlcur = NULL;
476:         char* strlend = NULL;
477:         _my_cmtr_ioptr curr_pfd = pfd;
478:
479:         char* ptrpos = 0;
480:
481:         int port1num = 0;
482:         int port2num = 0;
483:         char port1chr = '\0';
484:         char port2chr = '\0';
485:
486:         int index = 0;
487:         int dataint = 0;
488:         f32 dataflt = 0;
489:
490:         _my_assert(pfd && cfg);
491:
492:         strline = _my_buf_malloc(strsize);
493:         memset(strline, '\0', strsize);
494:
495:         /* read station name and  kymograph id */
496:         curr_pfd = read_cmtr_cfg_line(curr_pfd, strline, strsize, &strlend, counter);
497:
498:         if (!curr_pfd) {
499:                 goto RETURN_FINISH;
500:         }
501:         strlcur = strline;
502:         ptrpos = strchr(strlcur, ',');
503:         memset(cfg->station_name, '\0', CMTR_STRING_MAX_LENGTH);
504:         memset(cfg->kymograph_id, '\0', CMTR_STRING_MAX_LENGTH);
505:         if (ptrpos) {
506:                 memcpy(cfg->station_name, strlcur, ptrpos - strlcur);
507:                 if (ptrpos < strlend) {
508:                         ptrpos += 1;
509:                         memcpy(cfg->kymograph_id, ptrpos, strlen(ptrpos));
510:                 }
511:         } else {
512:                 memcpy(cfg->station_name, strlcur, strlen(strlcur));
513:         }
514:
515:         /* read port count */
516:         curr_pfd = read_cmtr_cfg_line(curr_pfd, strline, strsize, &strlend, counter);
517:         if (!curr_pfd) {
518:                 goto RETURN_FINISH;
519:         }
520:         strlcur = strline;
521:         ptrpos = strchr(strlcur, ',');
522:         if ((!ptrpos) || (ptrpos >= strlend)) {
523:                 goto RETURN_FINISH;
524:         }
525:         ptrpos += 1;
526:         if (sscanf(ptrpos, "%d%c%*s", &port1num, &port1chr) <= 0) {
527:                 goto RETURN_FINISH;
528:         }
529:         ptrpos = strchr(ptrpos, ',');
530:         if ((!ptrpos) || (ptrpos >= strlend)) {
531:                 goto RETURN_FINISH;
532:         }
533:         ptrpos += 1;
534:         if (sscanf(ptrpos, "%d%c", &port2num, &port2chr) <= 0) {
535:                 goto RETURN_FINISH;
536:         }
537:         if ((port1chr == 'A') || (port1chr == 'a')) {
538:                 cfg->analog_count = port1num;
539:                 cfg->digit_count = port2num;
540:         } else if ((port1chr == 'D') || (port1chr == 'd')) {
541:                 cfg->analog_count = port2num;
542:                 cfg->digit_count = port1num;
543:         } else {
544:                 goto RETURN_FINISH;
545:         }
546:
547:         /* read analog port info */
548:         for (index = 0; index < cfg->analog_count; index++) {
549:                 curr_pfd = read_cmtr_cfg_line(curr_pfd, strline, strsize, &strlend, counter);
550:                 if (!curr_pfd) {
551:                         goto RETURN_FINISH;
552:                 }
553:                 if (!read_cmtr_cfg_one_analog((cfg->analogs)+index, strline, strsize, strlend)) {
554:                         goto RETURN_FINISH;
555:                 }
556:         }
557:         /* read digit port info */
558:         for (index = 0; index < cfg->digit_count; index++) {
559:                 curr_pfd = read_cmtr_cfg_line(curr_pfd, strline, strsize, &strlend, counter);
560:                 if (!curr_pfd) {
561:                         goto RETURN_FINISH;
562:                 }
563:                 if (!read_cmtr_cfg_one_digit((cfg->digits)+index, strline, strsize, strlend)) {
564:                         goto RETURN_FINISH;
565:                 }
566:         }
567:
568:         /* read Frequency info */
569:         curr_pfd = read_cmtr_cfg_line(curr_pfd, strline, strsize, &strlend, counter);
570:         if (!curr_pfd) {
571:                 goto RETURN_FINISH;
572:         }
573:         if (strline > strlend) {
574:                 goto RETURN_FINISH;
575:         }
576:         if (sscanf(strline, "%f", &dataflt) <= 0) {
577:                 goto RETURN_FINISH;
578:         }
579:         cfg->frequency = dataflt;
580:
581:         /* read smprate count info */
582:         curr_pfd = read_cmtr_cfg_line(curr_pfd, strline, strsize, &strlend, counter);
583:         if (!curr_pfd) {
584:                 goto RETURN_FINISH;
585:         }
586:         if (strline > strlend) {
587:                 goto RETURN_FINISH;
588:         }
589:         if (sscanf(strline, "%d", &dataint) <= 0) {
590:                 goto RETURN_FINISH;
591:         }
592:         cfg->smprate_count = dataint;
593:
594:         /* read smprate info */
595:         for (index = 0; index < cfg->smprate_count; index ++) {
596:                 curr_pfd = read_cmtr_cfg_line(curr_pfd, strline, strsize, &strlend, counter);
597:                 if (!curr_pfd) {
598:                         goto RETURN_FINISH;
599:                 }
600:                 strlcur = strline;
601:                 ptrpos = strchr(strlcur, ',');
602:                 if ((!ptrpos) || (ptrpos >= strlend)) {
603:                         goto RETURN_FINISH;
604:                 }
605:                 if (sscanf(strlcur, "%f%*s", &dataflt) <= 0) {
606:                         goto RETURN_FINISH;
607:                 }
608:                 cfg->smprates[index].rate = dataflt;
609:                 strlcur = ptrpos += 1;
610:                 if (ptrpos > strlend) {
611:                         goto RETURN_FINISH;
612:                 }
613:                 if (sscanf(strlcur, "%d", &dataint) <= 0) {
614:                         goto RETURN_FINISH;
615:                 }
616:                 cfg->smprates[index].point = dataint;
617:         }
618:
619:         /* read time info */
620:         curr_pfd = read_cmtr_cfg_line(curr_pfd, strline, strsize, &strlend, counter);
621:         if (!curr_pfd) {
622:                 goto RETURN_FINISH;
623:         }
624:         memset(cfg->begin_time, '\0', CMTR_STRING_MAX_LENGTH);
625:         if (strlend - strline >= 0) {
626:                 memcpy(cfg->begin_time, strline, strlend - strline + 1);
627:         }
628:         curr_pfd = read_cmtr_cfg_line(curr_pfd, strline, strsize, &strlend, counter);
629:         if (!curr_pfd) {
630:                 goto RETURN_FINISH;
631:         }
632:         memset(cfg->end_time, '\0', CMTR_STRING_MAX_LENGTH);
633:         if (strlend - strline >= 0) {
634:                 memcpy(cfg->end_time, strline, strlend - strline + 1);
635:         }
636:
637:         /* read dat type info */
638:         curr_pfd = read_cmtr_cfg_line(curr_pfd, strline, strsize, &strlend, counter);
639:         if (!curr_pfd) {
640:                 goto RETURN_FINISH;
641:         }
642:         strlcur =_my_strupr(strline);
643:         ptrpos = strstr(strlcur, "BIN");
644:         memset(cfg->file_type, '\0', CMTR_STRING_MAX_LENGTH);
645:         if (ptrpos > 0) {
646:                 strcpy(cfg->file_type, "BINARY");
647:         } else if (strstr(strlcur, "ASC") > 0) {
648:                 strcpy(cfg->file_type, "ASCII");
649:         }
650:         else {
651:                 goto RETURN_FINISH;
652:         }
653:
654:         returntag = TRUE;
655:
656: RETURN_FINISH:
657:         _my_buf_free(strline);
658:         return returntag ? curr_pfd : NULL;
659: }
660:
661: /*
662:  * read_cmtr_dat_smpdot_binary - 讀bin格式cmtr採樣點數據信息.
663:  * @pfd:  輸入輸出參數,地址
664:  * @big_endian_tag: 輸入參數,標識文件中數據的字節順序,為FALSE按照小端讀(默認值),True按照大端讀;
665:  * @analog_count: 輸入參數,模擬量個數;
666:  * @digit_count: 輸入參數,數字量個數;
667:  * @dot:  輸出參數,採樣點信息;
668:  * @the_smp_mins: 輸出參數,統計最小值,為數組,個數至少為analog_count個,值為NULL時忽略統計;
669:  * @the_smp_maxs: 輸出參數,統計最大值,為數組,個數至少為analog_count個,值為NULL時忽略統計;
670:  * @counter:  輸出參數,讀取的字節計數器;
671:  *
672:  * 返回當前pfd指針,讀失敗返回NULL
673:  *
674:  */
675: _my_cmtr_ioptr read_cmtr_dat_smpdot_binary(_my_cmtr_ioptr pfd, u8 big_endian_tag,
676:                                            int analog_count, int digit_count,
677:                                            struct cmtr_dat_smpdot *dot,
678:                                            u32* the_smp_mins, u32* the_smp_maxs,
679:                                            int* counter)
680: {
681:         u16 data16 = 0x00;
682:         u32 data32 = 0x00;
683:         int oldnum = 0;
684:
685:         int index = 0;
686:         int bitpos = 0;
687:
688:         _my_cmtr_ioptr curr_pfd = pfd;
689:
690:         oldnum = (*counter);
691:         data32 = 0x00;
692:         _my_read_cmtr_data(curr_pfd, &data32, 4, *counter);
693:         if ((*counter) <= oldnum) {
694:                 return NULL;
695:         }
696:         dot->index =  big_endian_tag ? _my_btoh32(data32) : _my_ltoh32(data32);
697:
698:         oldnum = (*counter);
699:         data32 = 0x00;
700:         _my_read_cmtr_data(curr_pfd, &data32, 4, *counter);
701:         if ((*counter) <= oldnum) {
702:                 return NULL;
703:         }
704:         dot->time =  big_endian_tag ? _my_btoh32(data32) : _my_ltoh32(data32);
705:
706:         /* read analog port info */
707:         for (index = 0; index < analog_count; index ++) {
708:                 oldnum = (*counter);
709:                 data16 = 0x00;
710:                 _my_read_cmtr_data(curr_pfd, &data16, 2, *counter);
711:                 if ((*counter) <= oldnum) {
712:                         return NULL;
713:                 }
714:                 dot->analogs[index] =  big_endian_tag ? _my_btoh16(data16) : _my_ltoh16(data16);
715:                 if (the_smp_mins) {
716:                         if (the_smp_mins + index) {
717:                                 the_smp_mins[index] = _my_min(the_smp_mins[index], dot->analogs[index]);
718:                         }
719:                 }
720:                 if (the_smp_maxs) {
721:                         if (the_smp_maxs + index) {
722:                                 the_smp_maxs[index] = _my_min(the_smp_maxs[index], dot->analogs[index]);
723:                         }
724:                 }
725:         }
726:         /* read digit port info */
727:         for (index = 0; index < digit_count; index ++) {
728:                 oldnum = (*counter);
729:                 data16 = 0x00;
730:                 _my_read_cmtr_data(curr_pfd, &data16, 2, *counter);
731:                 if ((*counter) <= oldnum) {
732:                         return NULL;
733:                 }
734:                 data16 =  big_endian_tag ? _my_btoh16(data16) : _my_ltoh16(data16);
735:                 for (bitpos = 0; bitpos < 16; bitpos++) {
736:                         if ((index * 16 + bitpos) < digit_count) {
737:                                 dot->digits[index * 16 + bitpos] = (data16 & (0x0001 << bitpos));
738:                         } else {
739:                                 break;
740:                         }
741:                 }
742:         }
743:
744:         return curr_pfd;
745: }
746:
747: /*
748:  * read_cmtr_dat_smpdot_ascii - 讀ascii格式cmtr採樣點數據信息.
749:  * @pfd:  輸入輸出參數,地址
750:  * @read_buf: 輸入參數,讀緩衝,在外部申請內存,避免在內部頻繁申請、釋放內存;
751:  * @buf_size: 輸入參數,讀緩衝區的大小;
752:  * @analog_count: 輸入參數,模擬量個數;
753:  * @digit_count: 輸入參數,數字量個數;
754:  * @dot:  輸出參數,採樣點信息;
755:  * @the_smp_mins: 輸出參數,統計最小值,為數組,個數至少為analog_count個,值為NULL時忽略統計;
756:  * @the_smp_maxs: 輸出參數,統計最大值,為數組,個數至少為analog_count個,值為NULL時忽略統計;
757:  * @counter:  輸出參數,讀取的字節計數器;
758:  *
759:  * 返回當前pfd指針,讀失敗返回NULL
760:  *
761:  */
762: _my_cmtr_ioptr read_cmtr_dat_smpdot_ascii(_my_cmtr_ioptr pfd,
763:                                           u8 *read_buf, int buf_size,
764:                                           int analog_count, int digit_count,
765:                                           struct cmtr_dat_smpdot *dot,
766:                                           u16* the_smp_mins,u16* the_smp_maxs,
767:                                           int* counter)
768: {
769:         char* ptrpos = 0;
770:         char* strlend = 0;
771:
772:         int index = 0;
773:
774:         int dataint = 0;
775:         float dataflt = 0;
776:
777:         _my_cmtr_ioptr curr_pfd = pfd;
778:
779:         memset(read_buf, '\0', buf_size);
780:         curr_pfd = read_cmtr_cfg_line(curr_pfd, read_buf, buf_size, &strlend, counter);
781:         if (!curr_pfd) {
782:                 return NULL;
783:         }
784:
785:         ptrpos = read_buf;
786:         if ((!ptrpos) || (ptrpos >= strlend)) {
787:                 return NULL;
788:         }
789:         if (sscanf(ptrpos, "%d%*s", &dataint) <= 0) {
790:                 return NULL;
791:         }
792:         dot->index = dataint;
793:         ptrpos = strchr(ptrpos, ',');
794:         if (!ptrpos) {
795:                 return NULL;
796:         }
797:         ptrpos += 1;
798:         if ((!ptrpos) || (ptrpos > strlend)) {
799:                 return NULL;
800:         }
801:         if (sscanf(ptrpos, "%d%*s", &dataint) <= 0) {
802:                 return NULL;
803:         }
804:         dot->time = dataint;
805:
806:         /* read analog port info */
807:         for (index = 0; index < analog_count; index ++) {
808:                 ptrpos = strchr(ptrpos, ',');
809:                 if (!ptrpos) {
810:                         return NULL;
811:                 }
812:                 ptrpos += 1;
813:                 if ((!ptrpos) || (ptrpos > strlend)) {
814:                         return NULL;
815:                 }
816:                 if (sscanf(ptrpos, "%f%*s", &dataflt) <= 0) {
817:                         return NULL;
818:                 }
819:                 dot->analogs[index] = dataflt;
820:                 if (the_smp_mins) {
821:                         if (the_smp_mins + index) {
822:                                 the_smp_mins[index] = _my_min(the_smp_mins[index], dataflt);
823:                         }
824:                 }
825:                 if (the_smp_maxs) {
826:                         if (the_smp_maxs + index) {
827:                                 the_smp_maxs[index] = _my_min(the_smp_maxs[index], dataflt);
828:                         }
829:                 }
830:         }
831:         /* read digit port info */
832:         for (index = 0; index < digit_count; index ++) {
833:                 ptrpos = strchr(ptrpos, ',');
834:                 if (!ptrpos) {
835:                         return NULL;
836:                 }
837:                 ptrpos += 1;
838:                 if ((!ptrpos) || (ptrpos > strlend)) {
839:                         return NULL;
840:                 }
841:                 if (sscanf(ptrpos, "%d%*s", &dataint) <= 0) {
842:                         return NULL;
843:                 }
844:                 dot->digits[index] = dataint;
845:         }
846:
847:         return curr_pfd;
848: }
849:
850: /*
851:  * print_cmtr_cfg_info - 打印cmtr文件配置數.
852:  * @cfg:  輸入參數,cmtr文件配置數據;
853:  *
854:  */
855: void print_cmtr_cfg_info(struct cmtr_cfg_info *cfg)
856: {
857:         u32 index = 0;
858:         if ( cfg ) {
859:                 _my_printf("=====================\n");
860:                 _my_printf("%s,%s\n", cfg->station_name, cfg->kymograph_id);
861:                 _my_printf("%d,%dA,%dD\n", cfg->analog_count + cfg->digit_count, cfg->analog_count, cfg->digit_count);
862:                 for (index = 0; index < cfg->analog_count; index++) {
863:                         _my_printf("%d,%s,%s,%s,%s,%.6lf,%.6lf,%d,%d,%d\n",
864:                                  cfg->analogs[index].index,
865:                                  cfg->analogs[index].name,
866:                                  cfg->analogs[index].phase,
867:                                  cfg->analogs[index].element,
868:                                  cfg->analogs[index].unit,
869:                                  cfg->analogs[index].factor_a,
870:                                  cfg->analogs[index].factor_b,
871:                                  cfg->analogs[index].offset_time,
872:                                  cfg->analogs[index].smp_min,
873:                                  cfg->analogs[index].smp_max);
874:                 }
875:                 for (index = 0; index < cfg->digit_count; index++) {
876:                         _my_printf("%d,%s,%d\n",
877:                                  cfg->digits[index].index,
878:                                  cfg->digits[index].name,
879:                                  cfg->digits[index].state);
880:                 }
881:                 _my_printf("%.6f\n", cfg->frequency);
882:                 for (index = 0; index < cfg->smprate_count; index++) {
883:                         _my_printf("%f,%d\n", cfg->smprates[index].rate, cfg->smprates[index].point);
884:                 }
885:                 _my_printf("%s\n", cfg->begin_time);
886:                 _my_printf("%s\n", cfg->end_time);
887:                 _my_printf("%s\n", cfg->file_type);
888:                 _my_printf("=====================\n");
889:         }
890: }
891:
892: /*
893:  * print_cmtr_dat_smpdot - 打印cmtr數據文件採樣點.
894:  * @cfg:  輸入參數,cmtr文件配置數據;
895:  * @analog_count: 輸入參數,模擬量個數;
896:  * @digit_count: 輸入參數,數字量個數;
897:  * @dot:  輸入參數,採樣點信息;
898:  *
899:  */
900: void print_cmtr_dat_smpdot(int analog_count, int digit_count, struct cmtr_dat_smpdot *dot)
901: {
902:         int index = 0;
903:         if ( dot ) {
904:                 _my_printf("%u,%d", dot->index, dot->time);
905:                 for (index = 0; index < analog_count; index++) {
906:                         _my_printf(",%d", dot->analogs[index]);
907:                 }
908:                 for (index = 0; index < digit_count; index++) {
909:                         _my_printf(",%d", dot->digits[index]);
910:                 }
911:                 _my_printf("\n");
912:         }
913: }
914:
915:
916: #ifdef CMTR_CONSOLE_DEMO
917:
918:
919: /*
920:  * _my_cmtr_openrb/_my_cmtr_openwb/_my_cmtr_openab/_my_cmtr_close
921:  *              - 可以根據需要改寫該接口,如重定義為網口的recv\send、串口r\w等
922:  * @pfd:  文件地址、緩衝區地址、或者socket地址等
923:  * @str:  文件路徑或者聯機ip或者串口地址或者共享內存名稱
924:  *
925:  */
926: #define _my_cmtr_openrb(str)    (open((str), O_RDONLY, S_IWRITE | S_IREAD))
927: #define _my_cmtr_openwb(str)    (open((str), O_CREAT | O_RDWR, S_IWRITE | S_IREAD))
928: #define _my_cmtr_openab(str)    (open((str), O_CREAT | O_APPEND | O_RDWR, S_IWRITE | S_IREAD))
929: #define _my_cmtr_close(pfd)     (close(pfd))
930:
931:
932: /*
933:  * cmtr_test_demo - 測試函數
934:  *
935:  */
936:
937: void cmtr_test_demo()
938: {
939:         int counter1 = 0;
940:         int counter2 = 0;
941:         struct cmtr_dat_smpdot dot0;
942:         struct cmtr_cfg_info cfg0;
943:         _my_cmtr_ioptr fdcfg1 = 0;
944:         _my_cmtr_ioptr fddat1 = 0;
945:         _my_cmtr_ioptr fdcfg2 = 0;
946:         _my_cmtr_ioptr fddat2 = 0;
947:         int buf_size = 1024;
948:         u8 *read_buf = _my_buf_malloc(buf_size);
949:         int analog_count = 0;
950:         int digit_count = 0;
951:         u16 *the_smp_mins = 0;
952:         u16 *the_smp_maxs = 0;
953:
954:         fdcfg1 = _my_cmtr_openrb("E:/iec-61850/test_r.cfg");
955:         fdcfg2 = _my_cmtr_openwb("E:/iec-61850/test_w.cfg");
956:         _my_assert(fdcfg1);
957:         _my_assert(fdcfg2);
958:         read_cmtr_cfg_info(fdcfg1, &cfg0, &counter1);
959:         print_cmtr_cfg_info(&cfg0);
960:         write_cmtr_cfg_info(fdcfg2, &cfg0, &counter2);
961:         _my_cmtr_close(fdcfg1);
962:         _my_cmtr_close(fdcfg2);
963:
964:
965:         fddat1 = _my_cmtr_openrb("E:/iec-61850/test_r.dat");
966:         fddat2 = _my_cmtr_openwb("E:/iec-61850/test_w.dat");
967:         while (_my_check_cmtr_ptr(fddat1)) {
968:                 analog_count = cfg0.analog_count;
969:                 digit_count = cfg0.digit_count;
970:                 if (analog_count > 0) the_smp_mins = _my_buf_malloc(2*analog_count);
971:                 if (analog_count > 0) the_smp_maxs = _my_buf_malloc(2*analog_count);
972:                 fddat1 = read_cmtr_dat_smpdot_ascii(fddat1,
973:                                            read_buf, buf_size,
974:                                            analog_count, digit_count,
975:                                            &dot0,
976:                                            the_smp_mins, the_smp_maxs,
977:                                            &counter1);
978:                 if (_my_check_cmtr_ptr(fddat1)) {
979:                         print_cmtr_dat_smpdot(analog_count, digit_count, &dot0);
980:                         fddat2 = write_cmtr_dat_smpdot_ascii(fddat2, analog_count, digit_count, &dot0, &counter2);
981:                 }
982:         }
983:         _my_cmtr_close(fddat1);
984:         _my_cmtr_close(fddat2);
985: }
986:
987:
988: /*
989:  * main - 測試main函數
990:  *
991:  */
992: int main(int argc, char* argv[])
993: {
994:         cmtr_test_demo();
995:         getchar();
996:         return 0;
997: }
998:
999:
1000: #endif /* CMTR_CONSOLE_DEMO */
1001:
1002: