sv_subscriber.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. /*
  2. * sv_subscriber.h
  3. *
  4. * Copyright 2015-2022 Michael Zillgith
  5. *
  6. * This file is part of libIEC61850.
  7. *
  8. * libIEC61850 is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * libIEC61850 is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with libIEC61850. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. * See COPYING file for the complete license text.
  22. */
  23. #ifndef SAMPLED_VALUES_SV_SUBSCRIBER_H_
  24. #define SAMPLED_VALUES_SV_SUBSCRIBER_H_
  25. #include "libiec61850_common_api.h"
  26. #include "iec61850_common.h"
  27. #include "r_session.h"
  28. #include "hal_ethernet.h"
  29. #ifdef __cplusplus
  30. extern "C" {
  31. #endif
  32. /**
  33. * \defgroup sv_subscriber_api_group IEC 61850 Sampled Values (SV) subscriber API
  34. *
  35. * The sampled values (SV) subscriber API consists of three different objects.
  36. * The \ref SVReceiver object is responsible for handling all SV Ethernet messages
  37. * for a specific Ethernet interface. If you want to receive SV messages on multiple
  38. * Ethernet interfaces you have to use several \ref SVReceiver instances.
  39. * An \ref SVSubscriber object is associated to a SV data stream that is identified by its appID
  40. * and destination Ethernet address. The \reg SVSubscriber object is used to install a callback
  41. * handler \ref SVUpdateListener that is invoked for each ASDU (application service data unit) received for the
  42. * associated stream. An \ref SVSubscriber_ASDU is an object that represents a single ASDU. Each ASDU contains
  43. * some meta information that can be obtained by specific access functions like e.g.
  44. * \ref SVSubscriber_ASDU_getSmpCnt to access the "SmpCnt" (sample count) attribute of the ASDU. The actual
  45. * measurement data contained in the ASDU does not consist of structured ASN.1 data but stored as raw binary
  46. * data. Without a priori knowledge of the dataset associated with the ASDU data stream it is not
  47. * possible to interpret the received data correctly. Therefore you have to provide the data access functions
  48. * with an index value to indicate the data type and the start of the data in the data block of the ASDU.
  49. * E.g. reading a data set consisting of two FLOAT32 values you can use two subsequent calls of
  50. * \ref SVSubscriber_ASDU_getFLOAT32 one with index = 0 and the second one with index = 4.
  51. *
  52. * | IEC 61850 type | required bytes |
  53. * | -------------- | -------------- |
  54. * | BOOLEAN | 1 byte |
  55. * | INT8 | 1 byte |
  56. * | INT16 | 2 byte |
  57. * | INT32 | 4 byte |
  58. * | INT64 | 8 byte |
  59. * | INT8U | 1 byte |
  60. * | INT16U | 2 byte |
  61. * | INT24U | 3 byte |
  62. * | INT32U | 4 byte |
  63. * | INT64U | 8 byte |
  64. * | FLOAT32 | 4 byte |
  65. * | FLOAT64 | 8 byte |
  66. * | ENUMERATED | 4 byte |
  67. * | CODED ENUM | 4 byte |
  68. * | OCTET STRING | 20 byte |
  69. * | VISIBLE STRING | 35 byte |
  70. * | TimeStamp | 8 byte |
  71. * | EntryTime | 6 byte |
  72. * | BITSTRING | 4 byte |
  73. * | Quality | 4 byte |
  74. *
  75. * The SV subscriber API can be used independent of the IEC 61850 client API. In order to access the SVCB via MMS you
  76. * have to use the IEC 61850 client API. Please see \ref ClientSVControlBlock object in section \ref IEC61850_CLIENT_SV.
  77. *
  78. */
  79. /**@{*/
  80. /**
  81. * \brief opaque handle to a SV ASDU (Application service data unit) instance.
  82. *
  83. * Sampled Values (SV) ASDUs (application service data units) are the basic units for
  84. * sampled value data. Each ASDU represents a single sample consisting of multiple measurement
  85. * values with a single dedicated timestamp.
  86. *
  87. * NOTE: SVSubscriber_ASDU are statically allocated and are only valid inside of the SVUpdateListener
  88. * function when called by the library. If you need the data contained in the ASDU elsewhere
  89. * you have to copy and store the data by yourself!
  90. */
  91. typedef struct sSVSubscriber_ASDU* SVSubscriber_ASDU;
  92. /**
  93. * \brief opaque handle to a SV subscriber instance
  94. *
  95. * A subscriber is an instance associated with a single stream of measurement data. It is identified
  96. * by the Ethernet destination address, the appID value (both are on SV message level) and the svID value
  97. * that is part of each ASDU (SVSubscriber_ASDU object).
  98. */
  99. typedef struct sSVSubscriber* SVSubscriber;
  100. /**
  101. * \brief Callback function for received SV messages
  102. *
  103. * Will be called for each ASDU contained in a SV message!
  104. *
  105. * \param subscriber the subscriber that was associated with the received SV message
  106. * \param parameter a user provided parameter that is simply passed to the callback
  107. * \param asdu SV ASDU data structure. This structure is only valid inside of the callback function
  108. */
  109. typedef void (*SVUpdateListener)(SVSubscriber subscriber, void* parameter, SVSubscriber_ASDU asdu);
  110. /**
  111. * \brief opaque handle to a SV receiver instance
  112. */
  113. typedef struct sSVReceiver* SVReceiver;
  114. /**
  115. * \brief Create a new SV receiver instance.
  116. *
  117. * A receiver is responsible for processing all SV message for a single Ethernet interface.
  118. * In order to process messages from multiple Ethernet interfaces you have to create multiple
  119. * instances.
  120. *
  121. * \return the newly created receiver instance
  122. */
  123. LIB61850_API SVReceiver
  124. SVReceiver_create(void);
  125. /**
  126. * \brief Create a new R-SV receiver instance.
  127. *
  128. * \param session the remote session protocol instance
  129. *
  130. * \return the newly created receiver instance
  131. */
  132. LIB61850_API SVReceiver
  133. SVReceiver_createRemote(RSession session);
  134. /**
  135. * \brief Disable check for destination address of the received SV messages
  136. *
  137. * \param self the receiver instance reference
  138. */
  139. LIB61850_API void
  140. SVReceiver_disableDestAddrCheck(SVReceiver self);
  141. /**
  142. * \brief Enable check for destination address of the received SV messages
  143. *
  144. * Per default only the appID is checked to identify relevant SV messages and the
  145. * destination address is ignored for performance reasons. This only works when the
  146. * appIDs are unique in the local system. Otherwise the destination address check
  147. * has to be enabled.
  148. *
  149. * \param self the receiver instance reference
  150. */
  151. LIB61850_API void
  152. SVReceiver_enableDestAddrCheck(SVReceiver self);
  153. /**
  154. * \brief Set the Ethernet interface ID for the receiver instance
  155. *
  156. * Use this function if you want to use a different interface than
  157. * the default interface set by CONFIG_ETHERNET_INTERFACE_ID (stack_config.h)
  158. * NOTE: This function has to be called before calling SVReceiver_start.
  159. *
  160. * \param self the receiver instance reference
  161. * \param interfaceId the Ethernet interface id (platform specific e.g. eth0 for linux).
  162. */
  163. LIB61850_API void
  164. SVReceiver_setInterfaceId(SVReceiver self, const char* interfaceId);
  165. /**
  166. * \brief Add a subscriber instance to the receiver
  167. *
  168. * The given subscriber will be connected to the receiver instance.
  169. *
  170. * \param self the receiver instance reference
  171. * \param subscriber the subscriber instance to connect
  172. */
  173. LIB61850_API void
  174. SVReceiver_addSubscriber(SVReceiver self, SVSubscriber subscriber);
  175. /**
  176. * \brief Disconnect subscriber and receiver
  177. *
  178. * \param self the receiver instance reference
  179. * \param subscriber the subscriber instance to disconnect
  180. */
  181. LIB61850_API void
  182. SVReceiver_removeSubscriber(SVReceiver self, SVSubscriber subscriber);
  183. /**
  184. * \brief Receiver starts listening for SV messages.
  185. *
  186. * NOTE: This call will start a new background thread.
  187. *
  188. * \param self the receiver instance reference
  189. */
  190. LIB61850_API void
  191. SVReceiver_start(SVReceiver self);
  192. /**
  193. * \brief Receiver stops listening for SV messages
  194. *
  195. * \param self the receiver instance reference
  196. */
  197. LIB61850_API void
  198. SVReceiver_stop(SVReceiver self);
  199. /**
  200. * \brief Check if SV receiver is running
  201. *
  202. * Can be used to check if \ref SVReceiver_start has been successful.
  203. *
  204. * \param self the receiver instance reference
  205. *
  206. * \return true if SV receiver is running, false otherwise
  207. */
  208. LIB61850_API bool
  209. SVReceiver_isRunning(SVReceiver self);
  210. /**
  211. * \brief Destroy receiver instance (cleanup resources)
  212. *
  213. * \param self the receiver instance reference
  214. */
  215. LIB61850_API void
  216. SVReceiver_destroy(SVReceiver self);
  217. /***************************************
  218. * Functions for non-threaded operation
  219. ***************************************/
  220. LIB61850_API bool
  221. SVReceiver_startThreadless(SVReceiver self);
  222. LIB61850_API void
  223. SVReceiver_stopThreadless(SVReceiver self);
  224. /**
  225. * \brief Parse SV messages if they are available.
  226. *
  227. * Call after reception of ethernet frame and periodically to to house keeping tasks
  228. *
  229. * \param self the receiver object
  230. *
  231. * \return true if a message was available and has been parsed, false otherwise
  232. */
  233. LIB61850_API bool
  234. SVReceiver_tick(SVReceiver self);
  235. /*
  236. * \brief Create a new SV subscriber instance
  237. *
  238. * \param ethAddr optional destination address (NULL to not specify the destination address)
  239. * \param appID the APP-ID to identify matching SV messages
  240. *
  241. * \return the new subscriber instance
  242. */
  243. LIB61850_API SVSubscriber
  244. SVSubscriber_create(const uint8_t* ethAddr, uint16_t appID);
  245. /**
  246. * \brief Set a callback handler to process received SV messages
  247. *
  248. * If the received SV message contains multiple ASDUs (application service data units) the callback
  249. * function will be called for each ASDU separately. If a callback function has already been installed
  250. * for this SVSubscriber object the old callback will be replaced.
  251. *
  252. * \param self The subscriber object
  253. * \param listener the callback function to install
  254. * \param a user provided parameter that is provided to the callback function
  255. */
  256. LIB61850_API void
  257. SVSubscriber_setListener(SVSubscriber self, SVUpdateListener listener, void* parameter);
  258. LIB61850_API void
  259. SVSubscriber_destroy(SVSubscriber self);
  260. /*************************************************************************
  261. * SVSubscriber_ASDU object methods
  262. **************************************************************************/
  263. /**
  264. * \addtogroup sv_subscriber_asdu_group Values Application Service Data Unit (ASDU)
  265. * @{
  266. */
  267. /**
  268. * \brief return the SmpCnt value included in the SV ASDU
  269. *
  270. * The SmpCnt (sample counter) is increased for each ASDU to
  271. * identify the sample.
  272. *
  273. * \param self ASDU object instance
  274. */
  275. LIB61850_API uint16_t
  276. SVSubscriber_ASDU_getSmpCnt(SVSubscriber_ASDU self);
  277. /**
  278. * \brief return the SvID value included in the SV ASDU
  279. *
  280. * \param self ASDU object instance
  281. */
  282. LIB61850_API const char*
  283. SVSubscriber_ASDU_getSvId(SVSubscriber_ASDU self);
  284. /**
  285. * \brief return the DatSet value included in the SV ASDU
  286. *
  287. * \param self ASDU object instance
  288. */
  289. LIB61850_API const char*
  290. SVSubscriber_ASDU_getDatSet(SVSubscriber_ASDU self);
  291. /**
  292. * \brief return the ConfRev value included in the SV ASDU
  293. *
  294. * \param self ASDU object instance
  295. */
  296. LIB61850_API uint32_t
  297. SVSubscriber_ASDU_getConfRev(SVSubscriber_ASDU self);
  298. /**
  299. * \brief return the SmpMod value included in the SV ASDU
  300. *
  301. * \param self ASDU object instance
  302. */
  303. LIB61850_API uint8_t
  304. SVSubscriber_ASDU_getSmpMod(SVSubscriber_ASDU self);
  305. /**
  306. * \brief return the SmpRate value included in the SV ASDU
  307. *
  308. * \param self ASDU object instance
  309. */
  310. LIB61850_API uint16_t
  311. SVSubscriber_ASDU_getSmpRate(SVSubscriber_ASDU self);
  312. /**
  313. * \brief Check if DatSet value is included in the SV ASDU
  314. *
  315. * \param self ASDU object instance
  316. *
  317. * \return true if DatSet value is present, false otherwise
  318. */
  319. LIB61850_API bool
  320. SVSubscriber_ASDU_hasDatSet(SVSubscriber_ASDU self);
  321. /**
  322. * \brief Check if RefrTm value is included in the SV ASDU
  323. *
  324. * \param self ASDU object instance
  325. *
  326. * \return true if RefrTm value is present, false otherwise
  327. */
  328. LIB61850_API bool
  329. SVSubscriber_ASDU_hasRefrTm(SVSubscriber_ASDU self);
  330. /**
  331. * \brief Check if SmpMod value is included in the SV ASDU
  332. *
  333. * \param self ASDU object instance
  334. *
  335. * \return true if SmpMod value is present, false otherwise
  336. */
  337. LIB61850_API bool
  338. SVSubscriber_ASDU_hasSmpMod(SVSubscriber_ASDU self);
  339. /**
  340. * \brief Check if SmpRate value is included in the SV ASDU
  341. *
  342. * \param self ASDU object instance
  343. *
  344. * \return true if SmpRate value is present, false otherwise
  345. */
  346. LIB61850_API bool
  347. SVSubscriber_ASDU_hasSmpRate(SVSubscriber_ASDU self);
  348. /**
  349. * \brief Get the RefrTim value included in SV ASDU as milliseconds timestamp
  350. *
  351. * \param self ASDU object instance
  352. *
  353. * \return the time value as ms timestamp or 0 if RefrTm is not present in the SV ASDU
  354. */
  355. LIB61850_API uint64_t
  356. SVSubscriber_ASDU_getRefrTmAsMs(SVSubscriber_ASDU self);
  357. /**
  358. * \brief Get the RefrTim value included in SV ASDU as nanoseconds timestamp
  359. *
  360. * \param self ASDU object instance
  361. *
  362. * \return the time value as nanoseconds timestamp or 0 if RefrTm is not present in the SV ASDU
  363. */
  364. LIB61850_API nsSinceEpoch
  365. SVSubscriber_ASDU_getRefrTmAsNs(SVSubscriber_ASDU self);
  366. /**
  367. * \brief Get an INT8 data value in the data part of the ASDU
  368. *
  369. * \param self ASDU object instance
  370. * \param index the index (byte position of the start) of the data in the data part
  371. *
  372. * \return SV data
  373. */
  374. LIB61850_API int8_t
  375. SVSubscriber_ASDU_getINT8(SVSubscriber_ASDU self, int index);
  376. /**
  377. * \brief Get an INT16 data value in the data part of the ASDU
  378. *
  379. * \param self ASDU object instance
  380. * \param index the index (byte position of the start) of the data in the data part
  381. *
  382. * \return SV data
  383. */
  384. LIB61850_API int16_t
  385. SVSubscriber_ASDU_getINT16(SVSubscriber_ASDU self, int index);
  386. /**
  387. * \brief Get an INT32 data value in the data part of the ASDU
  388. *
  389. * \param self ASDU object instance
  390. * \param index the index (byte position of the start) of the data in the data part
  391. *
  392. * \return SV data
  393. */
  394. LIB61850_API int32_t
  395. SVSubscriber_ASDU_getINT32(SVSubscriber_ASDU self, int index);
  396. /**
  397. * \brief Get an INT64 data value in the data part of the ASDU
  398. *
  399. * \param self ASDU object instance
  400. * \param index the index (byte position of the start) of the data in the data part
  401. *
  402. * \return SV data
  403. */
  404. LIB61850_API int64_t
  405. SVSubscriber_ASDU_getINT64(SVSubscriber_ASDU self, int index);
  406. /**
  407. * \brief Get an INT8U data value in the data part of the ASDU
  408. *
  409. * \param self ASDU object instance
  410. * \param index the index (byte position of the start) of the data in the data part
  411. *
  412. * \return SV data
  413. */
  414. LIB61850_API uint8_t
  415. SVSubscriber_ASDU_getINT8U(SVSubscriber_ASDU self, int index);
  416. /**
  417. * \brief Get an INT16U data value in the data part of the ASDU
  418. *
  419. * \param self ASDU object instance
  420. * \param index the index (byte position of the start) of the data in the data part
  421. *
  422. * \return SV data
  423. */
  424. LIB61850_API uint16_t
  425. SVSubscriber_ASDU_getINT16U(SVSubscriber_ASDU self, int index);
  426. /**
  427. * \brief Get an INT32U data value in the data part of the ASDU
  428. *
  429. * \param self ASDU object instance
  430. * \param index the index (byte position of the start) of the data in the data part
  431. *
  432. * \return SV data
  433. */
  434. LIB61850_API uint32_t
  435. SVSubscriber_ASDU_getINT32U(SVSubscriber_ASDU self, int index);
  436. /**
  437. * \brief Get an INT64U data value in the data part of the ASDU
  438. *
  439. * \param self ASDU object instance
  440. * \param index the index (byte position of the start) of the data in the data part
  441. *
  442. * \return SV data
  443. */
  444. LIB61850_API uint64_t
  445. SVSubscriber_ASDU_getINT64U(SVSubscriber_ASDU self, int index);
  446. /**
  447. * \brief Get an FLOAT32 data value in the data part of the ASDU
  448. *
  449. * \param self ASDU object instance
  450. * \param index the index (byte position of the start) of the data in the data part
  451. *
  452. * \return SV data
  453. */
  454. LIB61850_API float
  455. SVSubscriber_ASDU_getFLOAT32(SVSubscriber_ASDU self, int index);
  456. /**
  457. * \brief Get an FLOAT64 data value in the data part of the ASDU
  458. *
  459. * \param self ASDU object instance
  460. * \param index the index (byte position of the start) of the data in the data part
  461. *
  462. * \return SV data
  463. */
  464. LIB61850_API double
  465. SVSubscriber_ASDU_getFLOAT64(SVSubscriber_ASDU self, int index);
  466. /**
  467. * \brief Get a timestamp data value in the data part of the ASDU
  468. *
  469. * \param self ASDU object instance
  470. * \param index the index (byte position of the start) of the data in the data part
  471. *
  472. * \return SV data
  473. */
  474. LIB61850_API Timestamp
  475. SVSubscriber_ASDU_getTimestamp(SVSubscriber_ASDU self, int index);
  476. /**
  477. * \brief Get a quality value in the data part of the ASDU
  478. *
  479. * NOTE: Quality is encoded as BITSTRING (4 byte)
  480. *
  481. * \param self ASDU object instance
  482. * \param index the index (byte position of the start) of the data in the data part
  483. *
  484. * \return SV data
  485. */
  486. LIB61850_API Quality
  487. SVSubscriber_ASDU_getQuality(SVSubscriber_ASDU self, int index);
  488. /**
  489. * \brief Returns the size of the data part of the ASDU
  490. *
  491. * \param self ASDU object instance
  492. *
  493. * \return size of the ASDU data part in bytes.
  494. */
  495. LIB61850_API int
  496. SVSubscriber_ASDU_getDataSize(SVSubscriber_ASDU self);
  497. /**
  498. * \brief return the SmpSynch value included in the SV ASDU
  499. *
  500. * The SmpSynch gives information about the clock synchronization.
  501. *
  502. * \param self ASDU object instance
  503. */
  504. uint8_t
  505. SVSubscriber_ASDU_getSmpSynch(SVSubscriber_ASDU self);
  506. /** @}*/
  507. #ifdef __cplusplus
  508. }
  509. #endif
  510. #endif /* SAMPLED_VALUES_SV_SUBSCRIBER_ */