-
Notifications
You must be signed in to change notification settings - Fork 0
/
iec60870_common.h
708 lines (572 loc) · 17 KB
/
iec60870_common.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
/*
* Copyright 2016, 2017 MZ Automation GmbH
*
* This file is part of lib60870-C
*
* lib60870-C is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* lib60870-C is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with lib60870-C. If not, see <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/
#ifndef SRC_INC_IEC60870_COMMON_H_
#define SRC_INC_IEC60870_COMMON_H_
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* \file iec60870_common.h
* \brief Common definitions for IEC 60870-5-101/104
* These types are used by CS101/CS104 master and slaves
*/
/**
* @addtogroup COMMON Common API functions
*
* @{
*/
#define IEC_60870_5_104_DEFAULT_PORT 2404
#define IEC_60870_5_104_DEFAULT_TLS_PORT 19998
#define LIB60870_VERSION_MAJOR 2
#define LIB60870_VERSION_MINOR 1
#define LIB60870_VERSION_PATCH 0
/**
* \brief lib60870 version information
*/
typedef struct {
int major;
int minor;
int patch;
} Lib60870VersionInfo;
/**
* \brief link layer mode for serial link layers
*/
typedef enum {
IEC60870_LINK_LAYER_BALANCED = 0,
IEC60870_LINK_LAYER_UNBALANCED = 1
} IEC60870_LinkLayerMode;
/** \brief State of the link layer */
typedef enum {
/** The link layer is idle, there is no communication */
LL_STATE_IDLE,
/** An error has occurred at the link layer, the link may not be usable */
LL_STATE_ERROR,
/** The link layer is busy and therefore no usable */
LL_STATE_BUSY,
/** The link is available for user data transmission and reception */
LL_STATE_AVAILABLE
} LinkLayerState;
/**
* \brief Callback handler for link layer state changes
*
* \param parameter user provided parameter that is passed to the handler
* \param address slave address used by the link layer state machine (only relevant for unbalanced master)
* \param newState the new link layer state
*/
typedef void (*IEC60870_LinkLayerStateChangedHandler) (void* parameter, int address, LinkLayerState newState);
/**
* \brief Callback handler for sent and received messages
*
* This callback handler provides access to the raw message buffer of received or sent
* messages. It can be used for debugging purposes. Usually it is not used nor required
* for applications.
*
* \param parameter user provided parameter
* \param msg the message buffer
* \param msgSize size of the message
* \param sent indicates if the message was sent or received
*/
typedef void (*IEC60870_RawMessageHandler) (void* parameter, uint8_t* msg, int msgSize, bool sent);
/**
* \brief Parameters for the CS101/CS104 application layer
*/
typedef struct sCS101_AppLayerParameters* CS101_AppLayerParameters;
struct sCS101_AppLayerParameters {
int sizeOfTypeId; /* size of the type id (default = 1 - don't change) */
int sizeOfVSQ; /* don't change */
int sizeOfCOT; /* size of COT (1/2 - default = 2 -> COT includes OA) */
int originatorAddress; /* originator address (OA) to use (0-255) */
int sizeOfCA; /* size of common address (CA) of ASDU (1/2 - default = 2) */
int sizeOfIOA; /* size of information object address (IOA) (1/2/3 - default = 3) */
int maxSizeOfASDU; /* maximum size of the ASDU that is generated - the maximum maximum value is 249 for IEC 104 and 254 for IEC 101 */
};
/**
* \brief Application Service Data Unit (ASDU) for the CS101/CS104 application layer
*/
typedef struct sCS101_ASDU* CS101_ASDU;
typedef struct {
CS101_AppLayerParameters parameters;
uint8_t* asdu;
int asduHeaderLength;
uint8_t* payload;
int payloadSize;
uint8_t encodedData[256];
} sCS101_StaticASDU;
typedef sCS101_StaticASDU* CS101_StaticASDU;
typedef struct sCP16Time2a* CP16Time2a;
struct sCP16Time2a {
uint8_t encodedValue[2];
};
typedef struct sCP24Time2a* CP24Time2a;
struct sCP24Time2a {
uint8_t encodedValue[3];
};
typedef struct sCP32Time2a* CP32Time2a;
/**
* \brief 4 byte binary time
*/
struct sCP32Time2a {
uint8_t encodedValue[4];
};
/**
* \brief 7 byte binary time
*/
typedef struct sCP56Time2a* CP56Time2a;
struct sCP56Time2a {
uint8_t encodedValue[7];
};
/**
* \brief Base type for counter readings
*/
typedef struct sBinaryCounterReading* BinaryCounterReading;
struct sBinaryCounterReading {
uint8_t encodedValue[5];
};
/**
* \brief Parameters for CS104 connections - APCI (application protocol control information)
*/
typedef struct sCS104_APCIParameters* CS104_APCIParameters;
struct sCS104_APCIParameters {
int k;
int w;
int t0;
int t1;
int t2;
int t3;
};
#include "cs101_information_objects.h"
typedef enum {
CS101_COT_PERIODIC = 1,
CS101_COT_BACKGROUND_SCAN = 2,
CS101_COT_SPONTANEOUS = 3,
CS101_COT_INITIALIZED = 4,
CS101_COT_REQUEST = 5,
CS101_COT_ACTIVATION = 6,
CS101_COT_ACTIVATION_CON = 7,
CS101_COT_DEACTIVATION = 8,
CS101_COT_DEACTIVATION_CON = 9,
CS101_COT_ACTIVATION_TERMINATION = 10,
CS101_COT_RETURN_INFO_REMOTE = 11,
CS101_COT_RETURN_INFO_LOCAL = 12,
CS101_COT_FILE_TRANSFER = 13,
CS101_COT_AUTHENTICATION = 14,
CS101_COT_MAINTENANCE_OF_AUTH_SESSION_KEY = 15,
CS101_COT_MAINTENANCE_OF_USER_ROLE_AND_UPDATE_KEY = 16,
CS101_COT_INTERROGATED_BY_STATION = 20,
CS101_COT_INTERROGATED_BY_GROUP_1 = 21,
CS101_COT_INTERROGATED_BY_GROUP_2 = 22,
CS101_COT_INTERROGATED_BY_GROUP_3 = 23,
CS101_COT_INTERROGATED_BY_GROUP_4 = 24,
CS101_COT_INTERROGATED_BY_GROUP_5 = 25,
CS101_COT_INTERROGATED_BY_GROUP_6 = 26,
CS101_COT_INTERROGATED_BY_GROUP_7 = 27,
CS101_COT_INTERROGATED_BY_GROUP_8 = 28,
CS101_COT_INTERROGATED_BY_GROUP_9 = 29,
CS101_COT_INTERROGATED_BY_GROUP_10 = 30,
CS101_COT_INTERROGATED_BY_GROUP_11 = 31,
CS101_COT_INTERROGATED_BY_GROUP_12 = 32,
CS101_COT_INTERROGATED_BY_GROUP_13 = 33,
CS101_COT_INTERROGATED_BY_GROUP_14 = 34,
CS101_COT_INTERROGATED_BY_GROUP_15 = 35,
CS101_COT_INTERROGATED_BY_GROUP_16 = 36,
CS101_COT_REQUESTED_BY_GENERAL_COUNTER = 37,
CS101_COT_REQUESTED_BY_GROUP_1_COUNTER = 38,
CS101_COT_REQUESTED_BY_GROUP_2_COUNTER = 39,
CS101_COT_REQUESTED_BY_GROUP_3_COUNTER = 40,
CS101_COT_REQUESTED_BY_GROUP_4_COUNTER = 41,
CS101_COT_UNKNOWN_TYPE_ID = 44,
CS101_COT_UNKNOWN_COT = 45,
CS101_COT_UNKNOWN_CA = 46,
CS101_COT_UNKNOWN_IOA = 47
} CS101_CauseOfTransmission;
const char*
CS101_CauseOfTransmission_toString(CS101_CauseOfTransmission self);
void
Lib60870_enableDebugOutput(bool value);
Lib60870VersionInfo
Lib60870_getLibraryVersionInfo(void);
/**
* \brief Check if the test flag of the ASDU is set
*/
bool
CS101_ASDU_isTest(CS101_ASDU self);
/**
* \brief Set the test flag of the ASDU
*/
void
CS101_ASDU_setTest(CS101_ASDU self, bool value);
/**
* \brief Check if the negative flag of the ASDU is set
*/
bool
CS101_ASDU_isNegative(CS101_ASDU self);
/**
* \brief Set the negative flag of the ASDU
*/
void
CS101_ASDU_setNegative(CS101_ASDU self, bool value);
/**
* \brief get the OA (originator address) of the ASDU.
*/
int
CS101_ASDU_getOA(CS101_ASDU self);
/**
* \brief Get the cause of transmission (COT) of the ASDU
*/
CS101_CauseOfTransmission
CS101_ASDU_getCOT(CS101_ASDU self);
/**
* \brief Set the cause of transmission (COT) of the ASDU
*/
void
CS101_ASDU_setCOT(CS101_ASDU self, CS101_CauseOfTransmission value);
/**
* \brief Get the common address (CA) of the ASDU
*/
int
CS101_ASDU_getCA(CS101_ASDU self);
/**
* \brief Set the common address (CA) of the ASDU
*
* \param ca the ca in unstructured form
*/
void
CS101_ASDU_setCA(CS101_ASDU self, int ca);
/**
* \brief Get the type ID of the ASDU
*/
IEC60870_5_TypeID
CS101_ASDU_getTypeID(CS101_ASDU self);
/**
* \brief Check if the ASDU contains a sequence of consecutive information objects
*
* NOTE: in a sequence of consecutive information objects only the first information object address
* is encoded. The following information objects ahve consecutive information object addresses.
*/
bool
CS101_ASDU_isSequence(CS101_ASDU self);
/**
* \brief Get the number of information objects (elements) in the ASDU
*/
int
CS101_ASDU_getNumberOfElements(CS101_ASDU self);
/**
* \brief Get the information object with the given index
*
* \param index the index of the information object (starting with 0)
*
* \return the information object, or NULL if there is no information object with the given index
*/
InformationObject
CS101_ASDU_getElement(CS101_ASDU self, int index);
/**
* \brief Get the information object with the given index and store it in the provided information object instance
*
* \param io if not NULL use the provided information object instance to store the information, has to be of correct type.
* \param index the index of the information object (starting with 0)
*
* \return the information object, or NULL if there is no information object with the given index
*/
InformationObject
CS101_ASDU_getElementEx(CS101_ASDU self, InformationObject io, int index);
/**
* \brief Create a new ASDU. The type ID will be derived from the first InformationObject that will be added
*
* \param parameters the application layer parameters used to encode the ASDU
* \param isSequence if the information objects will be encoded as a compact sequence of information objects with subsequent IOA values
* \param cot cause of transmission (COT)
* \param oa originator address (OA) to be used
* \param ca the common address (CA) of the ASDU
* \param isTest if the test flag will be set or not
* \param isNegative if the negative falg will be set or not
*
* \return the new CS101_ASDU instance
*/
CS101_ASDU
CS101_ASDU_create(CS101_AppLayerParameters parameters, bool isSequence, CS101_CauseOfTransmission cot, int oa, int ca,
bool isTest, bool isNegative);
/**
* \brief Create a new ASDU and store it in the provided static ASDU structure.
*
* NOTE: The type ID will be derived from the first InformationObject that will be added.
*
* \param self pointer to the statically allocated data structure
* \param parameters the application layer parameters used to encode the ASDU
* \param isSequence if the information objects will be encoded as a compact sequence of information objects with subsequent IOA values
* \param cot cause of transmission (COT)
* \param oa originator address (OA) to be used
* \param ca the common address (CA) of the ASDU
* \param isTest if the test flag will be set or not
* \param isNegative if the negative falg will be set or not
*
* \return the new CS101_ASDU instance
*/
CS101_ASDU
CS101_ASDU_initializeStatic(CS101_StaticASDU self, CS101_AppLayerParameters parameters, bool isSequence, CS101_CauseOfTransmission cot, int oa, int ca,
bool isTest, bool isNegative);
/**
* \brief Destroy the ASDU object (release all resources)
*/
void
CS101_ASDU_destroy(CS101_ASDU self);
/**
* \brief add an information object to the ASDU
*
* \param self ASDU object instance
* \param io information object to be added
*
* \return true when added, false when there not enough space left in the ASDU or IO cannot be added to the sequence because of wrong IOA.
*/
bool
CS101_ASDU_addInformationObject(CS101_ASDU self, InformationObject io);
/**
* \brief remove all information elements from the ASDU object
*
* \param self ASDU object instance
*/
void
CS101_ASDU_removeAllElements(CS101_ASDU self);
/**
* \brief Get the elapsed time in ms
*/
int
CP16Time2a_getEplapsedTimeInMs(CP16Time2a self);
/**
* \brief set the elapsed time in ms
*/
void
CP16Time2a_setEplapsedTimeInMs(CP16Time2a self, int value);
/**
* \brief Get the millisecond part of the time value
*/
int
CP24Time2a_getMillisecond(CP24Time2a self);
/**
* \brief Set the millisecond part of the time value
*/
void
CP24Time2a_setMillisecond(CP24Time2a self, int value);
/**
* \brief Get the second part of the time value
*/
int
CP24Time2a_getSecond(CP24Time2a self);
/**
* \brief Set the second part of the time value
*/
void
CP24Time2a_setSecond(CP24Time2a self, int value);
/**
* \brief Get the minute part of the time value
*/
int
CP24Time2a_getMinute(CP24Time2a self);
/**
* \brief Set the minute part of the time value
*/
void
CP24Time2a_setMinute(CP24Time2a self, int value);
/**
* \brief Check if the invalid flag of the time value is set
*/
bool
CP24Time2a_isInvalid(CP24Time2a self);
/**
* \brief Set the invalid flag of the time value
*/
void
CP24Time2a_setInvalid(CP24Time2a self, bool value);
/**
* \brief Check if the substituted flag of the time value is set
*/
bool
CP24Time2a_isSubstituted(CP24Time2a self);
/**
* \brief Set the substituted flag of the time value
*/
void
CP24Time2a_setSubstituted(CP24Time2a self, bool value);
/**
* \brief Create a 7 byte time from a UTC ms timestamp
*/
CP56Time2a
CP56Time2a_createFromMsTimestamp(CP56Time2a self, uint64_t timestamp);
CP32Time2a
CP32Time2a_create(CP32Time2a self);
void
CP32Time2a_setFromMsTimestamp(CP32Time2a self, uint64_t timestamp);
int
CP32Time2a_getMillisecond(CP32Time2a self);
void
CP32Time2a_setMillisecond(CP32Time2a self, int value);
int
CP32Time2a_getSecond(CP32Time2a self);
void
CP32Time2a_setSecond(CP32Time2a self, int value);
int
CP32Time2a_getMinute(CP32Time2a self);
void
CP32Time2a_setMinute(CP32Time2a self, int value);
bool
CP32Time2a_isInvalid(CP32Time2a self);
void
CP32Time2a_setInvalid(CP32Time2a self, bool value);
bool
CP32Time2a_isSubstituted(CP32Time2a self);
void
CP32Time2a_setSubstituted(CP32Time2a self, bool value);
int
CP32Time2a_getHour(CP32Time2a self);
void
CP32Time2a_setHour(CP32Time2a self, int value);
bool
CP32Time2a_isSummerTime(CP32Time2a self);
void
CP32Time2a_setSummerTime(CP32Time2a self, bool value);
/**
* \brief Set the time value of a 7 byte time from a UTC ms timestamp
*/
void
CP56Time2a_setFromMsTimestamp(CP56Time2a self, uint64_t timestamp);
/**
* \brief Convert a 7 byte time to a ms timestamp
*/
uint64_t
CP56Time2a_toMsTimestamp(CP56Time2a self);
/**
* \brief Get the ms part of a time value
*/
int
CP56Time2a_getMillisecond(CP56Time2a self);
/**
* \brief Set the ms part of a time value
*/
void
CP56Time2a_setMillisecond(CP56Time2a self, int value);
int
CP56Time2a_getSecond(CP56Time2a self);
void
CP56Time2a_setSecond(CP56Time2a self, int value);
int
CP56Time2a_getMinute(CP56Time2a self);
void
CP56Time2a_setMinute(CP56Time2a self, int value);
int
CP56Time2a_getHour(CP56Time2a self);
void
CP56Time2a_setHour(CP56Time2a self, int value);
int
CP56Time2a_getDayOfWeek(CP56Time2a self);
void
CP56Time2a_setDayOfWeek(CP56Time2a self, int value);
int
CP56Time2a_getDayOfMonth(CP56Time2a self);
void
CP56Time2a_setDayOfMonth(CP56Time2a self, int value);
/**
* \brief Get the month field of the time
*
* \return value the month (1..12)
*/
int
CP56Time2a_getMonth(CP56Time2a self);
/**
* \brief Set the month field of the time
*
* \param value the month (1..12)
*/
void
CP56Time2a_setMonth(CP56Time2a self, int value);
/**
* \brief Get the year (range 0..99)
*
* \param value the year (0.99)
*/
int
CP56Time2a_getYear(CP56Time2a self);
/**
* \brief Set the year
*
* \param value the year
*/
void
CP56Time2a_setYear(CP56Time2a self, int value);
bool
CP56Time2a_isSummerTime(CP56Time2a self);
void
CP56Time2a_setSummerTime(CP56Time2a self, bool value);
bool
CP56Time2a_isInvalid(CP56Time2a self);
void
CP56Time2a_setInvalid(CP56Time2a self, bool value);
bool
CP56Time2a_isSubstituted(CP56Time2a self);
void
CP56Time2a_setSubstituted(CP56Time2a self, bool value);
BinaryCounterReading
BinaryCounterReading_create(BinaryCounterReading self, int32_t value, int seqNumber,
bool hasCarry, bool isAdjusted, bool isInvalid);
void
BinaryCounterReading_destroy(BinaryCounterReading self);
int32_t
BinaryCounterReading_getValue(BinaryCounterReading self);
void
BinaryCounterReading_setValue(BinaryCounterReading self, int32_t value);
int
BinaryCounterReading_getSequenceNumber(BinaryCounterReading self);
bool
BinaryCounterReading_hasCarry(BinaryCounterReading self);
bool
BinaryCounterReading_isAdjusted(BinaryCounterReading self);
bool
BinaryCounterReading_isInvalid(BinaryCounterReading self);
void
BinaryCounterReading_setSequenceNumber(BinaryCounterReading self, int value);
void
BinaryCounterReading_setCarry(BinaryCounterReading self, bool value);
void
BinaryCounterReading_setAdjusted(BinaryCounterReading self, bool value);
void
BinaryCounterReading_setInvalid(BinaryCounterReading self, bool value);
/**
* @}
*/
typedef struct sFrame* Frame;
void
Frame_destroy(Frame self);
void
Frame_resetFrame(Frame self);
void
Frame_setNextByte(Frame self, uint8_t byte);
void
Frame_appendBytes(Frame self, uint8_t* bytes, int numberOfBytes);
int
Frame_getMsgSize(Frame self);
uint8_t*
Frame_getBuffer(Frame self);
int
Frame_getSpaceLeft(Frame self);
#ifdef __cplusplus
}
#endif
#endif /* SRC_INC_IEC60870_COMMON_H_ */