cipepath.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  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. #include <assert.h>
  13. const unsigned int kPortSegmentExtendedPort = 15; /**< Reserved port segment port value, indicating the use of the extended port field */
  14. /*** Path Segment ***/
  15. SegmentType GetPathSegmentType(const CipOctet *const cip_path) {
  16. const unsigned int kSegmentTypeMask = 0xE0;
  17. const unsigned int segment_type = *cip_path & kSegmentTypeMask;
  18. SegmentType result = kSegmentTypeInvalid;
  19. switch(segment_type) {
  20. case SEGMENT_TYPE_PORT_SEGMENT:
  21. result = kSegmentTypePortSegment;
  22. break;
  23. case SEGMENT_TYPE_LOGICAL_SEGMENT:
  24. result = kSegmentTypeLogicalSegment;
  25. break;
  26. case SEGMENT_TYPE_NETWORK_SEGMENT:
  27. result = kSegmentTypeNetworkSegment;
  28. break;
  29. case SEGMENT_TYPE_SYMBOLIC_SEGMENT:
  30. result = kSegmentTypeSymbolicSegment;
  31. break;
  32. case SEGMENT_TYPE_DATA_SEGMENT:
  33. result = kSegmentTypeDataSegment;
  34. break;
  35. case SEGMENT_TYPE_DATA_TYPE_CONSTRUCTED:
  36. result = kSegmentTypeDataTypeConstructed;
  37. break;
  38. case SEGMENT_TYPE_DATA_TYPE_ELEMENTARTY:
  39. result = kSegmentTypeDataTypeElementary;
  40. break;
  41. case SEGMENT_TYPE_SEGMENT_RESERVED:
  42. result = kSegmentTypeReserved;
  43. break;
  44. default:
  45. OPENER_TRACE_ERR(
  46. "Invalid Segment type in the message! We should never come here!\n");
  47. break;
  48. }
  49. return result;
  50. }
  51. void SetPathSegmentType(SegmentType segment_type,
  52. unsigned char *const cip_path) {
  53. switch(segment_type) {
  54. case kSegmentTypePortSegment:
  55. *cip_path = SEGMENT_TYPE_PORT_SEGMENT;
  56. break;
  57. case kSegmentTypeLogicalSegment:
  58. *cip_path = SEGMENT_TYPE_LOGICAL_SEGMENT;
  59. break;
  60. case kSegmentTypeNetworkSegment:
  61. *cip_path = SEGMENT_TYPE_NETWORK_SEGMENT;
  62. break;
  63. case kSegmentTypeSymbolicSegment:
  64. *cip_path = SEGMENT_TYPE_SYMBOLIC_SEGMENT;
  65. break;
  66. case kSegmentTypeDataSegment:
  67. *cip_path = SEGMENT_TYPE_DATA_SEGMENT;
  68. break;
  69. case kSegmentTypeDataTypeConstructed:
  70. *cip_path = SEGMENT_TYPE_DATA_TYPE_CONSTRUCTED;
  71. break;
  72. case kSegmentTypeDataTypeElementary:
  73. *cip_path = SEGMENT_TYPE_DATA_TYPE_ELEMENTARTY;
  74. break;
  75. case kSegmentTypeReserved:
  76. *cip_path = SEGMENT_TYPE_SEGMENT_RESERVED;
  77. break;
  78. default:
  79. OPENER_TRACE_ERR(
  80. "Invalid Segment type chosen! We should never come here!\n");
  81. OPENER_ASSERT(false);
  82. break;
  83. }
  84. }
  85. /*** Port Segment ***/
  86. bool GetPathPortSegmentExtendedLinkAddressSizeBit(
  87. const unsigned char *const cip_path) {
  88. const unsigned int kExtendedLinkAddressSizeMask = 0x10;
  89. if(kExtendedLinkAddressSizeMask ==
  90. (*cip_path & kExtendedLinkAddressSizeMask) ) {
  91. return true;
  92. }
  93. return false;
  94. }
  95. unsigned int GetPathPortSegmentPortIdentifier(
  96. const unsigned char *const cip_path) {
  97. const unsigned int kPortIdentifierMask = 0x0F;
  98. unsigned int port_identifier = *cip_path & kPortIdentifierMask;
  99. OPENER_ASSERT(kSegmentTypePortSegment == GetPathSegmentType(cip_path) );
  100. /* Use of reserved port identifier 0 */
  101. OPENER_ASSERT(0 != port_identifier);
  102. return port_identifier;
  103. }
  104. void SetPathPortSegmentPortIdentifier(const unsigned int port_identifier,
  105. unsigned char *const cip_path) {
  106. /* OPENER_ASSERT(
  107. port_identifier < 16,
  108. "Port identifier too large for standard port identifier field\n"); */
  109. OPENER_ASSERT(port_identifier < 16);
  110. (*cip_path) |= port_identifier;
  111. }
  112. unsigned int GetPathPortSegmentLinkAddressSize(
  113. const unsigned char *const cip_path) {
  114. /* OPENER_ASSERT(false == GetPathPortSegmentExtendedLinkAddressSizeBit(cip_path),
  115. "Call to non existent extended link address size\n"); */
  116. OPENER_ASSERT(true ==
  117. GetPathPortSegmentExtendedLinkAddressSizeBit(cip_path) );
  118. return *(cip_path + 1);
  119. }
  120. unsigned int GetPathPortSegmentExtendedPortNumber(
  121. const unsigned char *const cip_path) {
  122. /* OPENER_ASSERT(kPortSegmentExtendedPort == GetPathPortSegmentPortIdentifier(cip_path),
  123. "There is no extended port available!\n");*/
  124. OPENER_ASSERT(kPortSegmentExtendedPort ==
  125. GetPathPortSegmentPortIdentifier(cip_path) );
  126. const unsigned int kExtendedPortSegmentPosition =
  127. GetPathPortSegmentExtendedLinkAddressSizeBit(cip_path) == true ? 2 : 1;
  128. return cip_path[kExtendedPortSegmentPosition] +
  129. (cip_path[kExtendedPortSegmentPosition + 1] << 8);
  130. }
  131. void SetPathPortSegmentExtendedPortIdentifier(
  132. const unsigned int extended_port_identifier,
  133. CipOctet *const cip_path) {
  134. SetPathPortSegmentPortIdentifier(kPortSegmentExtendedPort, cip_path);
  135. const unsigned int kExtendedPortSegmentPosition =
  136. GetPathPortSegmentExtendedLinkAddressSizeBit(cip_path) == true ? 2 : 1;
  137. cip_path[kExtendedPortSegmentPosition] =
  138. (char) (extended_port_identifier & 0x00FF);
  139. cip_path[kExtendedPortSegmentPosition +
  140. 1] = (char) ( (extended_port_identifier & 0xFF00) >> 8 );
  141. }
  142. /*** Port Segment ***/
  143. /*** Logical Segment ***/
  144. LogicalSegmentLogicalType GetPathLogicalSegmentLogicalType(
  145. const unsigned char *const cip_path) {
  146. OPENER_ASSERT(kSegmentTypeLogicalSegment == GetPathSegmentType(cip_path) );
  147. const unsigned int kLogicalTypeMask = 0x1C;
  148. const unsigned int logical_type = (*cip_path) & kLogicalTypeMask;
  149. LogicalSegmentLogicalType result = kLogicalSegmentLogicalTypeInvalid;
  150. switch(logical_type) {
  151. case LOGICAL_SEGMENT_TYPE_CLASS_ID:
  152. result = kLogicalSegmentLogicalTypeClassId;
  153. break;
  154. case LOGICAL_SEGMENT_TYPE_INSTANCE_ID:
  155. result = kLogicalSegmentLogicalTypeInstanceId;
  156. break;
  157. case LOGICAL_SEGMENT_TYPE_MEMBER_ID:
  158. result = kLogicalSegmentLogicalTypeMemberId;
  159. break;
  160. case LOGICAL_SEGMENT_TYPE_CONNECTION_POINT:
  161. result = kLogicalSegmentLogicalTypeConnectionPoint;
  162. break;
  163. case LOGICAL_SEGMENT_TYPE_ATTRIBUTE_ID:
  164. result = kLogicalSegmentLogicalTypeAttributeId;
  165. break;
  166. case LOGICAL_SEGMENT_TYPE_SPECIAL:
  167. result = kLogicalSegmentLogicalTypeSpecial;
  168. break;
  169. case LOGICAL_SEGMENT_TYPE_SERVICE_ID:
  170. result = kLogicalSegmentLogicalTypeServiceId;
  171. break;
  172. case LOGICAL_SEGMENT_TYPE_EXTENDED_LOGICAL:
  173. result = kLogicalSegmentLogicalTypeExtendedLogical;
  174. break;
  175. default:
  176. OPENER_TRACE_ERR(
  177. "Logical segment/logical type: Invalid input!\n");
  178. break;
  179. }
  180. return result;
  181. }
  182. void SetPathLogicalSegmentLogicalType(LogicalSegmentLogicalType logical_type,
  183. CipOctet *const cip_path) {
  184. OPENER_ASSERT(kSegmentTypeLogicalSegment == GetPathSegmentType(cip_path) );
  185. switch(logical_type) {
  186. case kLogicalSegmentLogicalTypeClassId:
  187. (*cip_path) |= LOGICAL_SEGMENT_TYPE_CLASS_ID;
  188. break;
  189. case kLogicalSegmentLogicalTypeInstanceId:
  190. (*cip_path) |= LOGICAL_SEGMENT_TYPE_INSTANCE_ID;
  191. break;
  192. case kLogicalSegmentLogicalTypeMemberId:
  193. (*cip_path) |= LOGICAL_SEGMENT_TYPE_MEMBER_ID;
  194. break;
  195. case kLogicalSegmentLogicalTypeConnectionPoint:
  196. (*cip_path) |= LOGICAL_SEGMENT_TYPE_CONNECTION_POINT;
  197. break;
  198. case kLogicalSegmentLogicalTypeAttributeId:
  199. (*cip_path) |= LOGICAL_SEGMENT_TYPE_ATTRIBUTE_ID;
  200. break;
  201. case kLogicalSegmentLogicalTypeSpecial:
  202. (*cip_path) |= LOGICAL_SEGMENT_TYPE_SPECIAL;
  203. break;
  204. case kLogicalSegmentLogicalTypeServiceId:
  205. (*cip_path) |= LOGICAL_SEGMENT_TYPE_SERVICE_ID;
  206. break;
  207. case kLogicalSegmentLogicalTypeExtendedLogical:
  208. (*cip_path) |= LOGICAL_SEGMENT_TYPE_EXTENDED_LOGICAL;
  209. break;
  210. default:
  211. OPENER_TRACE_ERR(
  212. "Logical segment/logical type: It is not possible to reach this point!\n");
  213. OPENER_ASSERT(false);
  214. break;
  215. }
  216. }
  217. LogicalSegmentLogicalFormat GetPathLogicalSegmentLogicalFormat(
  218. const unsigned char *const cip_path) {
  219. OPENER_ASSERT(kSegmentTypeLogicalSegment == GetPathSegmentType(cip_path) );
  220. const unsigned int kLogicalFormatMask = 0x03;
  221. const unsigned int logical_format = (*cip_path) & kLogicalFormatMask;
  222. LogicalSegmentLogicalFormat result = kLogicalSegmentLogicalFormatInvalid;
  223. switch(logical_format) {
  224. case LOGICAL_SEGMENT_FORMAT_EIGHT_BIT:
  225. result = kLogicalSegmentLogicalFormatEightBit;
  226. break;
  227. case LOGICAL_SEGMENT_FORMAT_SIXTEEN_BIT:
  228. result = kLogicalSegmentLogicalFormatSixteenBit;
  229. break;
  230. case LOGICAL_SEGMENT_FORMAT_THIRTY_TWO_BIT:
  231. result = kLogicalSegmentLogicalFormatThirtyTwoBit;
  232. break;
  233. default:
  234. OPENER_TRACE_ERR(
  235. "Logical segment/logical type: Invalid logical type detected!\n");
  236. break;
  237. }
  238. return result;
  239. }
  240. void SetPathLogicalSegmentLogicalFormat(LogicalSegmentLogicalFormat format,
  241. CipOctet *const cip_path) {
  242. OPENER_ASSERT(kSegmentTypeLogicalSegment ==
  243. GetPathSegmentType( (const CipOctet * )cip_path ) );
  244. switch(format) {
  245. case kLogicalSegmentLogicalFormatEightBit:
  246. (*cip_path) |= LOGICAL_SEGMENT_FORMAT_EIGHT_BIT;
  247. break;
  248. case kLogicalSegmentLogicalFormatSixteenBit:
  249. (*cip_path) |= LOGICAL_SEGMENT_FORMAT_SIXTEEN_BIT;
  250. break;
  251. case kLogicalSegmentLogicalFormatThirtyTwoBit:
  252. (*cip_path) |= LOGICAL_SEGMENT_FORMAT_THIRTY_TWO_BIT;
  253. break;
  254. default:
  255. OPENER_TRACE_ERR(
  256. "Logical segment/logical type: Invalid logical type detected!\n");
  257. OPENER_ASSERT(false);
  258. break;
  259. }
  260. }
  261. CipDword CipEpathGetLogicalValue(const EipUint8 **message) {
  262. LogicalSegmentLogicalFormat logical_format =
  263. GetPathLogicalSegmentLogicalFormat(*message);
  264. CipDword data = kLogicalSegmentLogicalFormatInvalid;
  265. (*message) += 1; /* Move to logical value */
  266. switch(logical_format) {
  267. case kLogicalSegmentLogicalFormatEightBit:
  268. data = GetByteFromMessage(message);
  269. break;
  270. case kLogicalSegmentLogicalFormatSixteenBit:
  271. (*message) += 1; /* Pad byte needs to be skipped */
  272. data = GetWordFromMessage(message);
  273. break;
  274. case kLogicalSegmentLogicalFormatThirtyTwoBit:
  275. (*message) += 1; /* Pad byte needs to be skipped */
  276. data = GetDwordFromMessage(message);
  277. break;
  278. default:
  279. OPENER_TRACE_ERR(
  280. "Logical segment/logical type: Invalid logical value detected!\n");
  281. break;
  282. }
  283. return data;
  284. }
  285. void CipEpathSetLogicalValue(const CipDword logical_value,
  286. const LogicalSegmentLogicalFormat logical_format,
  287. CipMessageRouterResponse *const message) {
  288. switch(logical_format) {
  289. case kLogicalSegmentLogicalFormatEightBit:
  290. OPENER_ASSERT( (logical_value <= UINT8_MAX) ); /* Sanity check before casting to a smaller integer. */
  291. AddSintToMessage( (EipUint8)logical_value, &message->message );
  292. break;
  293. case kLogicalSegmentLogicalFormatSixteenBit:
  294. MoveMessageNOctets(1, &message->message); /* Needed for padding */
  295. OPENER_ASSERT( (logical_value <= UINT16_MAX) ); /* Sanity check before casting to a smaller integer. */
  296. AddIntToMessage( (EipUint16)logical_value, &message->message );
  297. break;
  298. case kLogicalSegmentLogicalFormatThirtyTwoBit:
  299. MoveMessageNOctets(1, &message->message); /* Needed for padding */
  300. AddDintToMessage(logical_value, &message->message);
  301. break;
  302. default:
  303. OPENER_ASSERT(false); /* This should never happen! */
  304. break;
  305. }
  306. }
  307. LogicalSegmentExtendedLogicalType GetPathLogicalSegmentExtendedLogicalType(
  308. const unsigned char *const cip_path) {
  309. /* OPENER_ASSERT(LOGICAL_SEGMENT_TYPE_EXTENDED_kLogicalSegmentLogicalTypeExtendedLogicalMessageValue == GetPathLogicalSegmentLogicalType(cip_path),
  310. "Trying to extract non-existent extended logical type") */
  311. OPENER_ASSERT(kLogicalSegmentLogicalTypeExtendedLogical == GetPathLogicalSegmentLogicalType(
  312. cip_path) );
  313. const unsigned int extended_logical_type = *(cip_path + 1);
  314. LogicalSegmentExtendedLogicalType result =
  315. kLogicalSegmentExtendedLogicalTypeInvalid;
  316. switch(extended_logical_type) {
  317. case LOGICAL_SEGMENT_EXTENDED_TYPE_ARRAY_INDEX:
  318. result = kLogicalSegmentExtendedLogicalTypeArrayIndex;
  319. break;
  320. case LOGICAL_SEGMENT_EXTENDED_TYPE_INDIRECT_ARRAY_INDEX:
  321. result = kLogicalSegmentExtendedLogicalTypeIndirectArrayIndex;
  322. break;
  323. case LOGICAL_SEGMENT_EXTENDED_TYPE_BIT_INDEX:
  324. result = kLogicalSegmentExtendedLogicalTypeBitIndex;
  325. break;
  326. case LOGICAL_SEGMENT_EXTENDED_TYPE_INDIRECT_BIT_INDEX:
  327. result = kLogicalSegmentExtendedLogicalTypeIndirectBitIndex;
  328. break;
  329. case LOGICAL_SEGMENT_EXTENDED_TYPE_STRUCTURE_MEMBER_NUMBER:
  330. result = kLogicalSegmentExtendedLogicalTypeStructureMemberNumber;
  331. break;
  332. case LOGICAL_SEGMENT_EXTENDED_TYPE_STRUCTURE_MEMBER_HANDLE:
  333. result = kLogicalSegmentExtendedLogicalTypeStructureMemberHandle;
  334. break;
  335. case LOGICAL_SEGMENT_EXTENDED_TYPE_RESERVED:
  336. result = kLogicalSegmentExtendedLogicalTypeReserved;
  337. break;
  338. default:
  339. OPENER_TRACE_ERR(
  340. "Logical segment/logical type: Invalid extended type detected!\n");
  341. }
  342. return result;
  343. }
  344. LogicalSegmentSpecialTypeLogicalFormat
  345. GetPathLogicalSegmentSpecialTypeLogicalType(const unsigned char *const cip_path)
  346. {
  347. /* OPENER_ASSERT(kSegmentTypeLogicalSegment == GetPathSegmentType(cip_path), "Not a logical segment!\n") */
  348. OPENER_ASSERT(kSegmentTypeLogicalSegment == GetPathSegmentType(cip_path) );
  349. OPENER_ASSERT(kLogicalSegmentLogicalTypeSpecial == GetPathLogicalSegmentLogicalType(
  350. cip_path) );
  351. const unsigned int kLogicalFormatMask = 0x03;
  352. const unsigned int logical_format = (*cip_path) & kLogicalFormatMask;
  353. LogicalSegmentSpecialTypeLogicalFormat result =
  354. kLogicalSegmentSpecialTypeLogicalFormatReserved;
  355. switch(logical_format) {
  356. case LOGICAL_SEGMENT_SPECIAL_TYPE_FORMAT_ELECTRONIC_KEY:
  357. result = kLogicalSegmentSpecialTypeLogicalFormatElectronicKey;
  358. break;
  359. default:
  360. result = kLogicalSegmentSpecialTypeLogicalFormatReserved;
  361. break;
  362. }
  363. return result;
  364. }
  365. ElectronicKeySegmentFormat GetPathLogicalSegmentElectronicKeyFormat(
  366. const unsigned char *const cip_path) {
  367. /* OPENER_ASSERT(kLogicalSegmentSpecialTypeLogicalFormatElectronicKey ==
  368. GetPathLogicalSegmentSpecialTypeLogicalType(cip_path), "Not an electronic key!\n") */
  369. OPENER_ASSERT(kLogicalSegmentSpecialTypeLogicalFormatElectronicKey == GetPathLogicalSegmentSpecialTypeLogicalType(
  370. cip_path) );
  371. ElectronicKeySegmentFormat result = kElectronicKeySegmentFormatReserved;
  372. switch(*(cip_path + 1) ) {
  373. case ELECTRONIC_KEY_SEGMENT_KEY_FORMAT_4:
  374. result = kElectronicKeySegmentFormatKeyFormat4;
  375. break;
  376. default:
  377. result = kElectronicKeySegmentFormatReserved;
  378. break;
  379. }
  380. return result;
  381. }
  382. void GetElectronicKeyFormat4FromMessage(const CipOctet **const message,
  383. ElectronicKeyFormat4 *key) {
  384. OPENER_ASSERT(kElectronicKeySegmentFormatKeyFormat4 == GetPathLogicalSegmentElectronicKeyFormat(
  385. *message) );
  386. (*message) += 2;
  387. ElectronicKeyFormat4SetVendorId(key, GetUintFromMessage(message) );
  388. ElectronicKeyFormat4SetDeviceType(key, GetUintFromMessage(message) );
  389. ElectronicKeyFormat4SetProductCode(key, GetUintFromMessage(message) );
  390. ElectronicKeyFormat4SetMajorRevisionCompatibility(key,
  391. GetByteFromMessage(message) );
  392. ElectronicKeyFormat4SetMinorRevision(key, GetUsintFromMessage(message) );
  393. }
  394. /*** Logical Segment ***/
  395. /*** Network Segment ***/
  396. /** @brief Return the Network Segment subtype
  397. *
  398. * @param cip_path Pointer to the start of the EPath message
  399. * @return The Network Segment subtype of the EPath
  400. */
  401. NetworkSegmentSubtype GetPathNetworkSegmentSubtype(
  402. const unsigned char *const cip_path) {
  403. OPENER_ASSERT(kSegmentTypeNetworkSegment == GetPathSegmentType(cip_path) );
  404. const unsigned int kSubtypeMask = 0x1F;
  405. const unsigned int subtype = (*cip_path) & kSubtypeMask;
  406. NetworkSegmentSubtype result = kNetworkSegmentSubtypeReserved;
  407. switch(subtype) {
  408. case NETWORK_SEGMENT_SCHEDULE:
  409. result = kNetworkSegmentSubtypeScheduleSegment;
  410. break;
  411. case NETWORK_SEGMENT_FIXED_TAG:
  412. result = kNetworkSegmentSubtypeFixedTagSegment;
  413. break;
  414. case NETWORK_SEGMENT_PRODUCTION_INHIBIT_TIME_IN_MILLISECONDS:
  415. result = kNetworkSegmentSubtypeProductionInhibitTimeInMilliseconds;
  416. break;
  417. case NETWORK_SEGMENT_SAFETY:
  418. result = kNetworkSegmentSubtypeSafetySegment;
  419. break;
  420. case NETWORK_SEGMENT_PRODUCTION_INHIBIT_TIME_IN_MICROSECONDS:
  421. result = kNetworkSegmentSubtypeProductionInhibitTimeInMicroseconds;
  422. break;
  423. case NETWORK_SEGMENT_EXTENDED_NETWORK:
  424. result = kNetworkSegmentSubtypeExtendedNetworkSegment;
  425. break;
  426. default:
  427. result = kNetworkSegmentSubtypeReserved;
  428. break;
  429. }
  430. return result;
  431. }
  432. /**
  433. * @brief Return the Production Inhibit Time in milliseconds from an EPath
  434. *
  435. * @param cip_path Pointer to the start of the EPath message
  436. * @return the Production Inhibit Time in milliseconds ranging from 0 to 255
  437. */
  438. CipUsint GetPathNetworkSegmentProductionInhibitTimeInMilliseconds(
  439. const unsigned char *const cip_path) {
  440. /* OPENER_ASSERT(kSegmentTypeNetworkSegment == GetPathSegmentType(cip_path),"Not a network segment!\n")
  441. OPENER_ASSERT(kNetworkSegmentSubtypeProductionInhibitTimeInMilliseconds == GetPathNetworkSegmentSubtype(cip_path),
  442. "Not a Production Inhibit Time milliseconds segment!\n") */
  443. OPENER_ASSERT(kSegmentTypeNetworkSegment == GetPathSegmentType(cip_path) );
  444. OPENER_ASSERT(kNetworkSegmentSubtypeProductionInhibitTimeInMilliseconds == GetPathNetworkSegmentSubtype(
  445. cip_path) );
  446. return *(cip_path + 1);
  447. }
  448. /**
  449. * @brief Return the Production Inhibit Time in microseconds from an EPath
  450. *
  451. * @param cip_path Pointer to the start of the EPath message
  452. * @return the Production Inhibit Time in microseconds ranging from 0 to 4294967295
  453. */
  454. CipUdint GetPathNetworkSegmentProductionInhibitTimeInMicroseconds(
  455. const unsigned char *const cip_path) {
  456. /* OPENER_ASSERT(kSegmentTypeNetworkSegment == GetPathSegmentType(cip_path),"Not a network segment!\n")
  457. OPENER_ASSERT(kNetworkSegmentSubtypeProductionInhibitTimeInMicroseconds == GetPathNetworkSegmentSubtype(cip_path),
  458. "Not a Production Inhibit Time microseconds segment!\n")
  459. OPENER_ASSERT(2 == *(cip_path + 1), "Data Words length is incorrect! See CIP Spec Vol.1 C-1.4.3.3.2\n") */
  460. OPENER_ASSERT(kSegmentTypeNetworkSegment == GetPathSegmentType(cip_path) );
  461. OPENER_ASSERT(kNetworkSegmentSubtypeProductionInhibitTimeInMicroseconds == GetPathNetworkSegmentSubtype(
  462. cip_path) );
  463. OPENER_ASSERT(2 == *(cip_path + 1) );
  464. const unsigned char *message_runner = cip_path + 2;
  465. return GetUdintFromMessage(&message_runner);
  466. }
  467. /*** Network Segment ***/
  468. /*** Symbolic Segment ***/
  469. SymbolicSegmentFormat GetPathSymbolicSegmentFormat(
  470. const unsigned char *const cip_path) {
  471. const unsigned int kSymbolicSegmentFormatMask = 0x1F;
  472. if(SYMBOLIC_SEGMENT_FORMAT_EXTENDED_STRING ==
  473. (*cip_path & kSymbolicSegmentFormatMask) ) {
  474. return kSymbolicSegmentFormatExtendedString;
  475. }
  476. return kSymbolicSegmentFormatASCII;
  477. }
  478. unsigned int GetPathSymbolicSegmentASCIIFormatLength(
  479. const unsigned char *const cip_path) {
  480. const unsigned int kSymbolicSegmentASCIIFormatLength = 0x1F;
  481. const unsigned int length = *cip_path & kSymbolicSegmentASCIIFormatLength;
  482. OPENER_ASSERT(0 != length);
  483. return length;
  484. }
  485. SymbolicSegmentExtendedFormat GetPathSymbolicSegmentNumericType(
  486. const unsigned char *const cip_path) {
  487. const unsigned int kSymbolicSegmentExtendedFormatNumericTypeMask = 0x1F;
  488. const unsigned int numeric_subtype = *(cip_path + 1) &
  489. kSymbolicSegmentExtendedFormatNumericTypeMask;
  490. SymbolicSegmentExtendedFormat result = kSymbolicSegmentExtendedFormatReserved;
  491. switch(numeric_subtype) {
  492. case SYMBOLIC_SEGMENT_EXTENDED_FORMAT_NUMERIC_USINT_TYPE:
  493. result = kSymbolicSegmentExtendedFormatNumericSymbolUSINT;
  494. break;
  495. case SYMBOLIC_SEGMENT_EXTENDED_FORMAT_NUMERIC_UINT_TYPE:
  496. result = kSymbolicSegmentExtendedFormatNumericSymbolUINT;
  497. break;
  498. case SYMBOLIC_SEGMENT_EXTENDED_FORMAT_NUMERIC_UDINT_TYPE:
  499. result = kSymbolicSegmentExtendedFormatNumericSymbolUDINT;
  500. break;
  501. default:
  502. result = kSymbolicSegmentExtendedFormatReserved;
  503. break;
  504. }
  505. return result;
  506. }
  507. SymbolicSegmentExtendedFormat GetPathSymbolicSegmentExtendedFormat(
  508. const unsigned char *const cip_path) {
  509. OPENER_ASSERT(kSegmentTypeSymbolicSegment == GetPathSegmentType(cip_path) );
  510. OPENER_ASSERT(kSymbolicSegmentFormatExtendedString == GetPathSymbolicSegmentFormat(
  511. cip_path) );
  512. const unsigned int kSymbolicSegmentExtendedFormatMask = 0xE0;
  513. const unsigned int extended_type = *(cip_path + 1) &
  514. kSymbolicSegmentExtendedFormatMask;
  515. SymbolicSegmentExtendedFormat result = kSymbolicSegmentExtendedFormatReserved;
  516. switch(extended_type) {
  517. case SYMBOLIC_SEGMENT_EXTENDED_FORMAT_DOUBLE_CHAR:
  518. result = kSymbolicSegmentExtendedFormatDoubleByteChars;
  519. break;
  520. case SYMBOLIC_SEGMENT_EXTENDED_FORMAT_TRIPLE_CHAR:
  521. result = kSymbolicSegmentExtendedFormatTripleByteChars;
  522. break;
  523. case SYMBOLIC_SEGMENT_EXTENDED_FORMAT_NUMERIC:
  524. result = GetPathSymbolicSegmentNumericType(cip_path);
  525. break;
  526. default:
  527. result = kSymbolicSegmentExtendedFormatReserved;
  528. break;
  529. }
  530. return result;
  531. }
  532. /*** Symbolic Segment ***/
  533. /*** Data Segment ***/
  534. DataSegmentSubtype GetPathDataSegmentSubtype(const unsigned char *const cip_path)
  535. {
  536. const unsigned int kDataSegmentSubtypeMask = 0x1F;
  537. const unsigned int data_subtype = (*cip_path) & kDataSegmentSubtypeMask;
  538. DataSegmentSubtype result = kDataSegmentSubtypeReserved;
  539. switch(data_subtype) {
  540. case DATA_SEGMENT_SUBTYPE_SIMPLE_DATA:
  541. result = kDataSegmentSubtypeSimpleData;
  542. break;
  543. case DATA_SEGMENT_SUBTYPE_ANSI_EXTENDED_SYMBOL:
  544. result = kDataSegmentSubtypeANSIExtendedSymbol;
  545. break;
  546. default:
  547. result = kDataSegmentSubtypeReserved;
  548. break;
  549. }
  550. return result;
  551. }
  552. /** @brief Returns the amount of 16-bit data words in the Simple Data EPath
  553. *
  554. * @param cip_path Pointer to the start of the EPath message
  555. * @return The amount of 16-bit words of data in the EPath
  556. */
  557. CipUsint GetPathDataSegmentSimpleDataWordLength(
  558. const unsigned char *const cip_path) {
  559. /* OPENER_ASSERT(kSegmentTypeDataSegment == GetPathSegmentType(cip_path),"Not a data segment!\n");
  560. OPENER_ASSERT(kDataSegmentSubtypeSimpleData == GetPathDataSegmentSubtype(cip_path), "Not a simple data segment!\n") */
  561. OPENER_ASSERT(kSegmentTypeDataSegment == GetPathSegmentType(cip_path) );
  562. OPENER_ASSERT(kDataSegmentSubtypeSimpleData ==
  563. GetPathDataSegmentSubtype(cip_path) );
  564. const unsigned char *message_runner = cip_path + 1;
  565. return GetUsintFromMessage(&message_runner);
  566. }
  567. /*** End Data Segment ***/
  568. /* Special purpose functions */
  569. LogicalSegmentLogicalFormat CipEpathGetNeededLogicalFormatForValue(
  570. CipDword value) {
  571. LogicalSegmentLogicalFormat logical_format =
  572. kLogicalSegmentLogicalFormatEightBit;
  573. if(0xFF < value) {
  574. logical_format = kLogicalSegmentLogicalFormatSixteenBit;
  575. }
  576. if(0xFFFF < value) {
  577. logical_format = kLogicalSegmentLogicalFormatThirtyTwoBit;
  578. }
  579. return logical_format;
  580. }
  581. //TODO: Does not match the actual interface anymore, check how to fix
  582. size_t CipEpathEncodeConnectionEpath(
  583. const CipConnectionPathEpath *const connection_epath,
  584. CipOctet **encoded_path) {
  585. size_t encoded_path_length = 0;
  586. {
  587. SetPathSegmentType(kSegmentTypeLogicalSegment, *encoded_path);
  588. SetPathLogicalSegmentLogicalType(kLogicalSegmentLogicalTypeClassId,
  589. *encoded_path);
  590. LogicalSegmentLogicalFormat logical_value =
  591. CipEpathGetNeededLogicalFormatForValue(connection_epath->class_id);
  592. SetPathLogicalSegmentLogicalFormat(logical_value, *encoded_path);
  593. encoded_path_length += 1;
  594. MoveMessageNOctets(1, (ENIPMessage *const) encoded_path);
  595. CipEpathSetLogicalValue(connection_epath->class_id,
  596. logical_value,
  597. (CipMessageRouterResponse *const)encoded_path);
  598. }
  599. {
  600. SetPathSegmentType(kSegmentTypeLogicalSegment, *encoded_path);
  601. SetPathLogicalSegmentLogicalType(kLogicalSegmentLogicalTypeClassId,
  602. *encoded_path);
  603. LogicalSegmentLogicalFormat logical_value =
  604. CipEpathGetNeededLogicalFormatForValue(connection_epath->instance_id);
  605. SetPathLogicalSegmentLogicalFormat(logical_value, *encoded_path);
  606. encoded_path_length += 1;
  607. MoveMessageNOctets(1, (ENIPMessage *const) encoded_path);
  608. CipEpathSetLogicalValue(connection_epath->instance_id,
  609. logical_value,
  610. (CipMessageRouterResponse *const)encoded_path);
  611. }
  612. if(0 != connection_epath->attribute_id_or_connection_point) {
  613. SetPathSegmentType(kSegmentTypeLogicalSegment, *encoded_path);
  614. SetPathLogicalSegmentLogicalType(kLogicalSegmentLogicalTypeClassId,
  615. *encoded_path);
  616. LogicalSegmentLogicalFormat logical_value =
  617. CipEpathGetNeededLogicalFormatForValue(
  618. connection_epath->attribute_id_or_connection_point);
  619. SetPathLogicalSegmentLogicalFormat(logical_value, *encoded_path);
  620. encoded_path_length += 1;
  621. MoveMessageNOctets(1, (ENIPMessage *const) encoded_path);
  622. CipEpathSetLogicalValue(connection_epath->attribute_id_or_connection_point,
  623. logical_value,
  624. (CipMessageRouterResponse *const)encoded_path);
  625. }
  626. return encoded_path_length += 1;
  627. }
  628. bool CipEpathEqual(const CipOctet *const path1,
  629. const CipUint path1_length,
  630. const CipOctet *const path2,
  631. const CipUint path2_length) {
  632. if(path1_length != path2_length) {
  633. return false;
  634. }
  635. for(size_t i = 0; i < path1_length; ++i) {
  636. if(path1[i] != path2[i]) {
  637. return false;
  638. }
  639. }
  640. return true;
  641. }