cipepath.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. /*******************************************************************************
  2. * Copyright (c) 2009, Rockwell Automation, Inc.
  3. * All rights reserved.
  4. *
  5. ******************************************************************************/
  6. #include <stdbool.h>
  7. #include <stdlib.h>
  8. #include "cipepath.h"
  9. #include "endianconv.h"
  10. #include "cipelectronickey.h"
  11. #include "trace.h"
  12. const unsigned int kPortSegmentExtendedPort = 15; /**< Reserved port segment port value, indicating the use of the extended port field */
  13. /* Segments */
  14. #define SEGMENT_TYPE_PORT_SEGMENT_MESSAGE_VALUE 0x00 /**< Message value of the Port segment */
  15. #define SEGMENT_TYPE_LOGICAL_SEGMENT_MESSAGE_VALUE 0x20 /**< Message value of the Logical segment */
  16. #define SEGMENT_TYPE_NETWORK_SEGMENT_MESSAGE_VALUE 0x40 /**< Message value of the Network segment */
  17. #define SEGMENT_TYPE_SYMBOLIC_SEGMENT_MESSAGE_VALUE 0x60 /**< Message value of the Symbolic segment */
  18. #define SEGMENT_TYPE_DATA_SEGMENT_MESSAGE_VALUE 0x80 /**< Message value of the Data segment */
  19. #define SEGMENT_TYPE_DATA_TYPE_CONSTRUCTED_MESSAGE_VALUE 0xA0 /**< Message value of the Data type constructed */
  20. #define SEGMENT_TYPE_DATA_TYPE_ELEMENTARTY_MESSAGE_VALUE 0xC0 /**< Message value of the Data type elementary */
  21. #define SEGMENT_TYPE_SEGMENT_RESERVED_MESSAGE_VALUE 0xE0 /**< Reserved value */
  22. #define LOGICAL_SEGMENT_TYPE_CLASS_ID_MESSAGE_VALUE 0x00 /**< Message value of the logical segment/logical type Class ID */
  23. #define LOGICAL_SEGMENT_TYPE_INSTANCE_ID_MESSAGE_VALUE 0x04 /**< Message value of the logical segment/logical type Instance ID */
  24. #define LOGICAL_SEGMENT_TYPE_MEMBER_ID_MESSAGE_VALUE 0x08 /**< Message value of the logical segment/logical type Member ID */
  25. #define LOGICAL_SEGMENT_TYPE_CONNECTION_POINT_MESSAGE_VALUE 0x0C /**< Message value of the logical segment/logical type Connection Point */
  26. #define LOGICAL_SEGMENT_TYPE_ATTRIBUTE_ID_MESSAGE_VALUE 0x10 /**< Message value of the logical segment/logical type Attribute ID */
  27. #define LOGICAL_SEGMENT_TYPE_SPECIAL_MESSAGE_VALUE 0x14 /**< Message value of the logical segment/logical type Special */
  28. #define LOGICAL_SEGMENT_TYPE_SERVICE_ID_MESSAGE_VALUE 0x18 /**< Message value of the logical segment/logical type Service ID */
  29. #define LOGICAL_SEGMENT_TYPE_EXTENDED_LOGICAL_MESSAGE_VALUE 0x1C /**< Message value of the logical segment/logical type Extended Logical */
  30. #define LOGICAL_SEGMENT_FORMAT_EIGHT_BIT_MESSAGE_VALUE 0x00
  31. #define LOGICAL_SEGMENT_FORMAT_SIXTEEN_BIT_MESSAGE_VALUE 0x01
  32. #define LOGICAL_SEGMENT_FORMAT_THIRTY_TWO_BIT_MESSAGE_VALUE 0x02
  33. #define LOGICAL_SEGMENT_EXTENDED_TYPE_RESERVED_MESSAGE_VALUE 0x00
  34. #define LOGICAL_SEGMENT_EXTENDED_TYPE_ARRAY_INDEX_MESSAGE_VALUE 0x01
  35. #define LOGICAL_SEGMENT_EXTENDED_TYPE_INDIRECT_ARRAY_INDEX_MESSAGE_VALUE 0x02
  36. #define LOGICAL_SEGMENT_EXTENDED_TYPE_BIT_INDEX_MESSAGE_VALUE 0x03
  37. #define LOGICAL_SEGMENT_EXTENDED_TYPE_INDIRECT_BIT_INDEX_MESSAGE_VALUE 0x04
  38. #define LOGICAL_SEGMENT_EXTENDED_TYPE_STRUCTURE_MEMBER_NUMBER_MESSAGE_VALUE 0x05
  39. #define LOGICAL_SEGMENT_EXTENDED_TYPE_STRUCTURE_MEMBER_HANDLE_MESSAGE_VALUE 0x06
  40. #define LOGICAL_SEGMENT_SPECIAL_TYPE_FORMAT_ELECTRONIC_KEY_MESSAGE_VALUE 0x00
  41. #define NETWORK_SEGMENT_SUBTYPE_SCHEDULE_MESSAGE_VALUE 0x01
  42. #define NETWORK_SEGMENT_SUBTYPE_FIXED_TAG_MESSAGE_VALUE 0x02
  43. #define NETWORK_SEGMENT_SUBTYPE_PRODUCTION_INHIBIT_TIME_IN_MILLISECONDS_MESSAGE_VALUE 0x03
  44. #define NETWORK_SEGMENT_SUBTYPE_SAFETY_MESSAGE_VALUE 0x04
  45. #define NETWORK_SEGMENT_SUBTYPE_PRODUCTION_INHIBIT_TIME_IN_MICROSECONDS_MESSAGE_VALUE 0x10
  46. #define NETWORK_SEGMENT_SUBTYPE_EXTENDED_NETWORK_MESSAGE_VALUE 0x1F
  47. typedef enum {
  48. kElectronicKeySegmentFormatReserved,
  49. kElectronicKeySegmentFormatKeyFormat4
  50. } ElectronicKeySegmentFormat;
  51. #define ELECTRONIC_KEY_SEGMENT_KEY_FORMAT_4_MESSAGE_VALUE 0x04
  52. typedef enum {
  53. kDataSegmentSubtypeReserved,
  54. kDataSegmentSubtypeSimpleData,
  55. kDataSegmentSubtypeANSIExtendedSymbol
  56. } DataSegmentSubtype;
  57. #define DATA_SEGMENT_SUBTYPE_SIMPLE_DATA_MESSAGE_VALUE 0x00
  58. #define DATA_SEGMENT_SUBTYPE_ANSI_EXTENDED_SYMBOL_MESSAGE_VALUE 0x11
  59. /*** Path Segment ***/
  60. SegmentType GetPathSegmentType(const char *const cip_path) {
  61. const unsigned int kSegmentTypeMask = 0xE0;
  62. const unsigned int segment_type = *cip_path & kSegmentTypeMask;
  63. SegmentType result = kSegmentTypeReserved;
  64. switch (segment_type) {
  65. case SEGMENT_TYPE_PORT_SEGMENT_MESSAGE_VALUE:
  66. result = kSegmentTypePortSegment;
  67. break;
  68. case SEGMENT_TYPE_LOGICAL_SEGMENT_MESSAGE_VALUE:
  69. result = kSegmentTypeLogicalSegment;
  70. break;
  71. case SEGMENT_TYPE_NETWORK_SEGMENT_MESSAGE_VALUE:
  72. result = kSegmentTypeNetworkSegment;
  73. break;
  74. case SEGMENT_TYPE_SYMBOLIC_SEGMENT_MESSAGE_VALUE:
  75. result = kSegmentTypeSymbolicSegment;
  76. break;
  77. case SEGMENT_TYPE_DATA_SEGMENT_MESSAGE_VALUE:
  78. result = kSegmentTypeDataSegment;
  79. break;
  80. case SEGMENT_TYPE_DATA_TYPE_CONSTRUCTED_MESSAGE_VALUE:
  81. result = kSegmentTypeDataTypeConstructed;
  82. break;
  83. case SEGMENT_TYPE_DATA_TYPE_ELEMENTARTY_MESSAGE_VALUE:
  84. result = kSegmentTypeDataTypeElementary;
  85. break;
  86. case SEGMENT_TYPE_SEGMENT_RESERVED_MESSAGE_VALUE:
  87. result = kSegmentTypeReserved;
  88. break;
  89. default:
  90. OPENER_ASSERT(
  91. "Invalid Segment type in the message! We should never come here!\n");
  92. break;
  93. }
  94. return result;
  95. }
  96. void SetPathSegmentType(SegmentType segment_type, char *const cip_path) {
  97. switch (segment_type) {
  98. case kSegmentTypePortSegment:
  99. *cip_path |= SEGMENT_TYPE_PORT_SEGMENT_MESSAGE_VALUE;
  100. break;
  101. case kSegmentTypeLogicalSegment:
  102. *cip_path |= SEGMENT_TYPE_LOGICAL_SEGMENT_MESSAGE_VALUE;
  103. break;
  104. case kSegmentTypeNetworkSegment:
  105. *cip_path |= SEGMENT_TYPE_NETWORK_SEGMENT_MESSAGE_VALUE;
  106. break;
  107. case kSegmentTypeSymbolicSegment:
  108. *cip_path |= SEGMENT_TYPE_SYMBOLIC_SEGMENT_MESSAGE_VALUE;
  109. break;
  110. case kSegmentTypeDataSegment:
  111. *cip_path |= SEGMENT_TYPE_DATA_SEGMENT_MESSAGE_VALUE;
  112. break;
  113. case kSegmentTypeDataTypeConstructed:
  114. *cip_path |= SEGMENT_TYPE_DATA_TYPE_CONSTRUCTED_MESSAGE_VALUE;
  115. break;
  116. case kSegmentTypeDataTypeElementary:
  117. *cip_path |= SEGMENT_TYPE_DATA_TYPE_ELEMENTARTY_MESSAGE_VALUE;
  118. break;
  119. case kSegmentTypeReserved:
  120. *cip_path |= SEGMENT_TYPE_SEGMENT_RESERVED_MESSAGE_VALUE;
  121. break;
  122. default:
  123. OPENER_ASSERT(
  124. "Invalid Segment type chosen! We should never come here!\n");
  125. }
  126. }
  127. /*** Port Segment ***/
  128. bool GetPathPortSegmentExtendedLinkAddressSizeBit(const char *const cip_path) {
  129. const unsigned int kExtendedLinkAddressSizeMask = 0x10;
  130. if (kExtendedLinkAddressSizeMask == (*cip_path & kExtendedLinkAddressSizeMask) ) {
  131. return true;
  132. }
  133. return false;
  134. }
  135. unsigned int GetPathPortSegmentPortIdentifier(const char *const cip_path) {
  136. const unsigned int kPortIdentifierMask = 0x0F;
  137. unsigned int port_identifier = *cip_path & kPortIdentifierMask;
  138. // OPENER_ASSERT(0 != port_identifier, "Use of reserved port identifier 0\n");
  139. OPENER_ASSERT(kSegmentTypePortSegment == GetPathSegmentType(cip_path));
  140. OPENER_ASSERT(0 != port_identifier);
  141. return port_identifier;
  142. }
  143. void SetPathPortSegmentPortIdentifier(const unsigned int port_identifier,
  144. char *const cip_path) {
  145. // OPENER_ASSERT(
  146. // port_identifier < 16,
  147. // "Port identifier too large for standard port identifier field\n");
  148. OPENER_ASSERT(port_identifier < 16);
  149. (*cip_path) |= port_identifier;
  150. }
  151. unsigned int GetPathPortSegmentLinkAddressSize(const char *const cip_path) {
  152. // OPENER_ASSERT(false == GetPathPortSegmentExtendedLinkAddressSizeBit(cip_path),
  153. // "Call to non existent extended link address size\n");
  154. OPENER_ASSERT(true == GetPathPortSegmentExtendedLinkAddressSizeBit(cip_path));
  155. return *(cip_path + 1);
  156. }
  157. unsigned int GetPathPortSegmentExtendedPortNumber(const char *const cip_path) {
  158. // OPENER_ASSERT(kPortSegmentExtendedPort == GetPathPortSegmentPortIdentifier(cip_path),
  159. // "There is no extended port available!\n");
  160. OPENER_ASSERT(kPortSegmentExtendedPort == GetPathPortSegmentPortIdentifier(cip_path));
  161. const unsigned int kExtendedPortSegmentPosition =
  162. GetPathPortSegmentExtendedLinkAddressSizeBit(cip_path) == true ? 2 : 1;
  163. return cip_path[kExtendedPortSegmentPosition]
  164. + (cip_path[kExtendedPortSegmentPosition + 1] << 8);
  165. }
  166. void SetPathPortSegmentExtendedPortIdentifier(
  167. const unsigned int extended_port_identifier, char *const cip_path) {
  168. SetPathPortSegmentPortIdentifier(kPortSegmentExtendedPort, cip_path);
  169. const unsigned int kExtendedPortSegmentPosition =
  170. GetPathPortSegmentExtendedLinkAddressSizeBit(cip_path) == true ? 3 : 2;
  171. cip_path[kExtendedPortSegmentPosition] = (char) (extended_port_identifier
  172. & 0x00FF);
  173. cip_path[kExtendedPortSegmentPosition + 1] =
  174. (char) ((extended_port_identifier & 0xFF00) >> 8);
  175. }
  176. /*** Port Segment ***/
  177. /*** Logical Segment ***/
  178. LogicalSegmentLogicalType GetPathLogicalSegmentLogicalType(
  179. const char *const cip_path) {
  180. const unsigned int kLogicalTypeMask = 0x1C;
  181. const unsigned int logical_type = (*cip_path) & kLogicalTypeMask;
  182. LogicalSegmentLogicalType result = kLogicalSegmentLogicalTypeExtendedLogical;
  183. switch (logical_type) {
  184. case LOGICAL_SEGMENT_TYPE_CLASS_ID_MESSAGE_VALUE:
  185. result = kLogicalSegmentLogicalTypeClassId;
  186. break;
  187. case LOGICAL_SEGMENT_TYPE_INSTANCE_ID_MESSAGE_VALUE:
  188. result = kLogicalSegmentLogicalTypeInstanceId;
  189. break;
  190. case LOGICAL_SEGMENT_TYPE_MEMBER_ID_MESSAGE_VALUE:
  191. result = kLogicalSegmentLogicalTypeMemberId;
  192. break;
  193. case LOGICAL_SEGMENT_TYPE_CONNECTION_POINT_MESSAGE_VALUE:
  194. result = kLogicalSegmentLogicalTypeConnectionPoint;
  195. break;
  196. case LOGICAL_SEGMENT_TYPE_ATTRIBUTE_ID_MESSAGE_VALUE:
  197. result = kLogicalSegmentLogicalTypeAttributeId;
  198. break;
  199. case LOGICAL_SEGMENT_TYPE_SPECIAL_MESSAGE_VALUE:
  200. result = kLogicalSegmentLogicalTypeSpecial;
  201. break;
  202. case LOGICAL_SEGMENT_TYPE_SERVICE_ID_MESSAGE_VALUE:
  203. result = kLogicalSegmentLogicalTypeServiceId;
  204. break;
  205. case LOGICAL_SEGMENT_TYPE_EXTENDED_LOGICAL_MESSAGE_VALUE:
  206. result = kLogicalSegmentLogicalTypeExtendedLogical;
  207. break;
  208. default:
  209. OPENER_ASSERT(
  210. "Logical segment/logical type: It is not possible to reach this point!\n");
  211. break;
  212. }
  213. return result;
  214. }
  215. LogicalSegmentLogicalFormat GetPathLogicalSegmentLogicalFormat(
  216. const char *const cip_path) {
  217. const unsigned int kLogicalFormatMask = 0x03;
  218. const unsigned int logical_format = (*cip_path) & kLogicalFormatMask;
  219. LogicalSegmentLogicalFormat result = kLogicalSegmentLogicalFormatEightBit;
  220. switch (logical_format) {
  221. case LOGICAL_SEGMENT_FORMAT_EIGHT_BIT_MESSAGE_VALUE:
  222. result = kLogicalSegmentLogicalFormatEightBit;
  223. break;
  224. case LOGICAL_SEGMENT_FORMAT_SIXTEEN_BIT_MESSAGE_VALUE:
  225. result = kLogicalSegmentLogicalFormatSixteenBit;
  226. break;
  227. case LOGICAL_SEGMENT_FORMAT_THIRTY_TWO_BIT_MESSAGE_VALUE:
  228. result = kLogicalSegmentLogicalFormatThirtyTwoBit;
  229. break;
  230. default:
  231. OPENER_ASSERT(
  232. "Logical segment/logical type: Invalid logical type detected!\n");
  233. break;
  234. }
  235. return result;
  236. }
  237. LogicalSegmentExtendedLogicalType GetPathLogicalSegmentExtendedLogicalType(const char *const cip_path) {
  238. // OPENER_ASSERT(LOGICAL_SEGMENT_TYPE_EXTENDED_kLogicalSegmentLogicalTypeExtendedLogicalMessageValue == GetPathLogicalSegmentLogicalType(cip_path),
  239. // "Trying to extract non-existent extended logical type");
  240. OPENER_ASSERT(LOGICAL_SEGMENT_TYPE_EXTENDED_LOGICAL_MESSAGE_VALUE == GetPathLogicalSegmentLogicalType(cip_path));
  241. const unsigned int extended_logical_type = *(cip_path + 1);
  242. LogicalSegmentExtendedLogicalType result = kLogicalSegmentExtendedLogicalTypeReserved;
  243. switch(extended_logical_type) {
  244. case LOGICAL_SEGMENT_EXTENDED_TYPE_ARRAY_INDEX_MESSAGE_VALUE: result = kLogicalSegmentExtendedLogicalTypeArrayIndex; break;
  245. case LOGICAL_SEGMENT_EXTENDED_TYPE_INDIRECT_ARRAY_INDEX_MESSAGE_VALUE: result = kLogicalSegmentExtendedLogicalTypeIndirectArrayIndex; break;
  246. case LOGICAL_SEGMENT_EXTENDED_TYPE_BIT_INDEX_MESSAGE_VALUE: result = kLogicalSegmentExtendedLogicalTypeBitIndex; break;
  247. case LOGICAL_SEGMENT_EXTENDED_TYPE_INDIRECT_BIT_INDEX_MESSAGE_VALUE: result = kLogicalSegmentExtendedLogicalTypeIndirectBitIndex; break;
  248. case LOGICAL_SEGMENT_EXTENDED_TYPE_STRUCTURE_MEMBER_NUMBER_MESSAGE_VALUE: result = kLogicalSegmentExtendedLogicalTypeStructureMemberNumber; break;
  249. case LOGICAL_SEGMENT_EXTENDED_TYPE_STRUCTURE_MEMBER_HANDLE_MESSAGE_VALUE: result = kLogicalSegmentExtendedLogicalTypeStructureMemberHandle; break;
  250. default: result = kLogicalSegmentExtendedLogicalTypeReserved;
  251. }
  252. return result;
  253. }
  254. LogicalSegmentSpecialTypeLogicalFormat GetPathLogicalSegmentSpecialTypeLogicalType(const char *const cip_path) {
  255. // OPENER_ASSERT(kSegmentTypeLogicalSegment == GetPathSegmentType(cip_path), "Not a logical segment!\n");
  256. OPENER_ASSERT(kSegmentTypeLogicalSegment == GetPathSegmentType(cip_path));
  257. const unsigned int kLogicalFormatMask = 0x03;
  258. const unsigned int logical_format = (*cip_path) & kLogicalFormatMask;
  259. LogicalSegmentSpecialTypeLogicalFormat result = kLogicalSegmentSpecialTypeLogicalFormatReserved;
  260. switch(logical_format) {
  261. case LOGICAL_SEGMENT_SPECIAL_TYPE_FORMAT_ELECTRONIC_KEY_MESSAGE_VALUE:
  262. result = kLogicalSegmentSpecialTypeLogicalFormatElectronicKey; break;
  263. default: result = kLogicalSegmentSpecialTypeLogicalFormatReserved; break;
  264. }
  265. return result;
  266. }
  267. ElectronicKeySegmentFormat GetPathLogicalSegmentElectronicKeyFormat(const char *const cip_path) {
  268. // OPENER_ASSERT(kLogicalSegmentSpecialTypeLogicalFormatElectronicKey ==
  269. // GetPathLogicalSegmentSpecialTypeLogicalType(cip_path), "Not an electronic key!\n");
  270. OPENER_ASSERT(kLogicalSegmentSpecialTypeLogicalFormatElectronicKey ==
  271. GetPathLogicalSegmentSpecialTypeLogicalType(cip_path));
  272. ElectronicKeySegmentFormat result = kElectronicKeySegmentFormatReserved;
  273. switch(*(cip_path + 1)) {
  274. case ELECTRONIC_KEY_SEGMENT_KEY_FORMAT_4_MESSAGE_VALUE: result = kElectronicKeySegmentFormatKeyFormat4; break;
  275. default: result = kElectronicKeySegmentFormatReserved; break;
  276. }
  277. return result;
  278. }
  279. ElectronicKeyFormat4 *GetPathLogicalSegmentElectronicKeyFormat4(const char *const cip_path) {
  280. // OPENER_ASSERT(kElectronicKeySegmentFormatKeyFormat4 ==
  281. // GetPathLogicalSegmentElectronicKeyFormat(cip_path), "Not electronic key format 4!\n");
  282. OPENER_ASSERT(kElectronicKeySegmentFormatKeyFormat4 ==
  283. GetPathLogicalSegmentElectronicKeyFormat(cip_path));
  284. const char *message_runner = (const char *)cip_path;
  285. ElectronicKeyFormat4 *result = calloc(1, sizeof(ElectronicKeySegmentFormat));
  286. SetElectronicKeyFormat4VendorId(GetIntFromMessage(&message_runner), result);
  287. SetElectronicKeyFormat4DeviceType(GetIntFromMessage(&message_runner), result);
  288. SetElectronicKeyFormat4ProductCode(GetIntFromMessage(&message_runner), result);
  289. SetElectronicKeyFormat4MajorRevisionCompatibility(GetSintFromMessage(&message_runner), result);
  290. SetElectronicKeyFormat4MinorRevision(GetSintFromMessage(&message_runner), result);
  291. return result;
  292. }
  293. /*** Logical Segment ***/
  294. /*** Network Segment ***/
  295. /** @brief Return the Network Segment subtype
  296. *
  297. * @param cip_path Pointer to the start of the EPath message
  298. * @return The Network Segment subtype of the EPath
  299. */
  300. NetworkSegmentSubType GetPathNetworkSegmentSubtype(const char *const cip_path) {
  301. const unsigned int kSubtypeMask = 0x1F;
  302. const unsigned int subtype = (*cip_path) & kSubtypeMask;
  303. NetworkSegmentSubType result = kNetworkSegmentSubtypeReserved;
  304. switch(subtype) {
  305. case NETWORK_SEGMENT_SUBTYPE_SCHEDULE_MESSAGE_VALUE:
  306. result = kNetworkSegmentSubtypeScheduleSegment; break;
  307. case NETWORK_SEGMENT_SUBTYPE_FIXED_TAG_MESSAGE_VALUE:
  308. result = kNetworkSegmentSubtypeFixedTagSegment; break;
  309. case NETWORK_SEGMENT_SUBTYPE_PRODUCTION_INHIBIT_TIME_IN_MILLISECONDS_MESSAGE_VALUE:
  310. result = kNetworkSegmentSubtypeProductionInhibitTimeInMilliseconds; break;
  311. case NETWORK_SEGMENT_SUBTYPE_SAFETY_MESSAGE_VALUE:
  312. result = kNetworkSegmentSubtypeSafetySegment; break;
  313. case NETWORK_SEGMENT_SUBTYPE_PRODUCTION_INHIBIT_TIME_IN_MICROSECONDS_MESSAGE_VALUE:
  314. result = kNetworkSegmentSubtypeProductionInhibitTimeInMicroseconds; break;
  315. default: result = kNetworkSegmentSubtypeReserved; break;
  316. }
  317. return result;
  318. }
  319. /**
  320. * @brief Return the Production Inhibit Time in milliseconds from an EPath
  321. *
  322. * @param cip_path Pointer to the start of the EPath message
  323. * @return the Production Inhibit Time in milliseconds ranging from 0 to 255
  324. */
  325. CipUsint GetPathNetworkSegmentProductionInhibitTimeInMilliseconds(const char *const cip_path) {
  326. // OPENER_ASSERT(kSegmentTypeNetworkSegment == GetPathSegmentType(cip_path),"Not a network segment!\n");
  327. // OPENER_ASSERT(kNetworkSegmentSubtypeProductionInhibitTimeInMilliseconds == GetPathNetworkSegmentSubtype(cip_path),
  328. // "Not a Production Inhibit Time milliseconds segment!\n");
  329. OPENER_ASSERT(kSegmentTypeNetworkSegment == GetPathSegmentType(cip_path));
  330. OPENER_ASSERT(kNetworkSegmentSubtypeProductionInhibitTimeInMilliseconds == GetPathNetworkSegmentSubtype(cip_path));
  331. return *(cip_path + 1);
  332. }
  333. /**
  334. * @brief Return the Production Inhibit Time in microseconds from an EPath
  335. *
  336. * @param cip_path Pointer to the start of the EPath message
  337. * @return the Production Inhibit Time in microseconds ranging from 0 to 4294967295
  338. */
  339. CipUdint GetPathNetworkSegmentProductionInhibitTimeInMicroseconds(const char *const cip_path) {
  340. // OPENER_ASSERT(kSegmentTypeNetworkSegment == GetPathSegmentType(cip_path),"Not a network segment!\n");
  341. // OPENER_ASSERT(kNetworkSegmentSubtypeProductionInhibitTimeInMicroseconds == GetPathNetworkSegmentSubtype(cip_path),
  342. // "Not a Production Inhibit Time microseconds segment!\n");
  343. // OPENER_ASSERT(2 == *(cip_path + 1), "Data Words length is incorrect! See CIP Spec Vol.1 C-1.4.3.3.2\n");
  344. OPENER_ASSERT(kSegmentTypeNetworkSegment == GetPathSegmentType(cip_path));
  345. OPENER_ASSERT(kNetworkSegmentSubtypeProductionInhibitTimeInMicroseconds == GetPathNetworkSegmentSubtype(cip_path));
  346. OPENER_ASSERT(2 == *(cip_path + 1));
  347. const char *message_runner = cip_path;
  348. return GetDintFromMessage(&message_runner);
  349. }
  350. /*** Network Segment ***/
  351. /*** Symbolic Segment ***/
  352. /* Currently not supported */
  353. /*** Symbolic Segment ***/
  354. /*** Data Segment ***/
  355. DataSegmentSubtype GetPathDataSegmentSubtype(const char *const cip_path) {
  356. const unsigned int kDataSegmentSubtypeMask = 0x1F;
  357. const unsigned int data_subtype = (*cip_path) & kDataSegmentSubtypeMask;
  358. DataSegmentSubtype result = kDataSegmentSubtypeReserved;
  359. switch(data_subtype) {
  360. case DATA_SEGMENT_SUBTYPE_SIMPLE_DATA_MESSAGE_VALUE:
  361. result = kDataSegmentSubtypeSimpleData; break;
  362. case DATA_SEGMENT_SUBTYPE_ANSI_EXTENDED_SYMBOL_MESSAGE_VALUE:
  363. result = kDataSegmentSubtypeANSIExtendedSymbol; break;
  364. default: result = kDataSegmentSubtypeReserved; break;
  365. }
  366. return result;
  367. }
  368. /** @brief Returns the amount of 16-bit data words in the Simple Data EPath
  369. *
  370. * @param cip_path Pointer to the start of the EPath message
  371. * @return The amount of 16-bit words of data in the EPath
  372. */
  373. CipUsint GetPathDataSegmentSimpleDataWordLength(const char * const cip_path) {
  374. // OPENER_ASSERT(kSegmentTypeDataSegment == GetPathSegmentType(cip_path),"Not a data segment!\n");
  375. // OPENER_ASSERT(kDataSegmentSubtypeSimpleData == GetPathDataSegmentSubtype(cip_path), "Not a simple data segment!\n");
  376. OPENER_ASSERT(kSegmentTypeDataSegment == GetPathSegmentType(cip_path));
  377. OPENER_ASSERT(
  378. kDataSegmentSubtypeSimpleData == GetPathDataSegmentSubtype(cip_path));
  379. const char *message_runner = cip_path;
  380. return GetSintFromMessage(&message_runner);
  381. }
  382. /*** Data Segment ***/