cipepath.c 26 KB

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