cipidentity.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. /*******************************************************************************
  2. * Copyright (c) 2009, Rockwell Automation, Inc.
  3. * All rights reserved.
  4. *
  5. ******************************************************************************/
  6. /**
  7. * @file cipidentity.c
  8. *
  9. * CIP Identity Object
  10. * ===================
  11. *
  12. * Implemented Attributes
  13. * ----------------------
  14. * - Attribute 1: VendorID
  15. * - Attribute 2: Device Type
  16. * - Attribute 3: Product Code
  17. * - Attribute 4: Revision
  18. * - Attribute 5: Status
  19. * - Attribute 6: Serial Number
  20. * - Attribute 7: Product Name
  21. * - Attribute 8: State
  22. *
  23. * Implemented Services
  24. * --------------------
  25. */
  26. #include "cipidentity.h"
  27. #include <string.h>
  28. #include "opener_user_conf.h"
  29. #include "cipcommon.h"
  30. #include "cipstring.h"
  31. #include "cipmessagerouter.h"
  32. #include "ciperror.h"
  33. #include "endianconv.h"
  34. #include "opener_api.h"
  35. #include "trace.h"
  36. /** @brief The device's configuration data for the Identity Object */
  37. #include "devicedata.h"
  38. /** @brief Definition of the global Identity Object */
  39. CipIdentityObject g_identity = { .vendor_id = OPENER_DEVICE_VENDOR_ID, /* Attribute 1: Vendor ID */
  40. .device_type = OPENER_DEVICE_TYPE, /* Attribute 2: Device Type */
  41. .product_code = OPENER_DEVICE_PRODUCT_CODE, /* Attribute 3: Product Code */
  42. .revision = { /* Attribute 4: Revision / CipUsint Major, CipUsint Minor */
  43. OPENER_DEVICE_MAJOR_REVISION,
  44. OPENER_DEVICE_MINOR_REVISION
  45. }, .status = 0, /* Attribute 5: Status */
  46. .ext_status = kSelftestingUnknown, /* Attribute 5: Extended Device Status field */
  47. .serial_number = 0, /* Attribute 6: Serial Number */
  48. /* Attribute 7: Product Name, set by CipIdentityInit() */
  49. };
  50. /* The Doxygen comment is with the function's prototype in opener_api.h. */
  51. void SetDeviceRevision(EipUint8 major, EipUint8 minor) {
  52. g_identity.revision.major_revision = major;
  53. g_identity.revision.minor_revision = minor;
  54. }
  55. /* The Doxygen comment is with the function's prototype in opener_api.h. */
  56. void SetDeviceSerialNumber(const EipUint32 serial_number) {
  57. g_identity.serial_number = serial_number;
  58. }
  59. /* The Doxygen comment is with the function's prototype in opener_api.h. */
  60. void SetDeviceType(const EipUint16 type) {
  61. g_identity.device_type = type;
  62. }
  63. /* The Doxygen comment is with the function's prototype in opener_api.h. */
  64. void SetDeviceProductCode(const EipUint16 code) {
  65. g_identity.product_code = code;
  66. }
  67. /* The Doxygen comment is with the function's prototype in opener_api.h. */
  68. void SetDeviceStatus(const CipWord status) {
  69. g_identity.status = status;
  70. g_identity.ext_status = status & kExtStatusMask;
  71. }
  72. /* The Doxygen comment is with the function's prototype in opener_api.h. */
  73. void SetDeviceVendorId(CipUint vendor_id) {
  74. g_identity.vendor_id = vendor_id;
  75. }
  76. /* The Doxygen comment is with the function's prototype in opener_api.h. */
  77. CipUint GetDeviceVendorId(void) {
  78. return g_identity.vendor_id;
  79. }
  80. /* The Doxygen comment is with the function's prototype in opener_api.h. */
  81. void SetDeviceProductName(const char *product_name) {
  82. if (!product_name)
  83. return;
  84. SetCipShortStringByCstr(&g_identity.product_name, product_name);
  85. }
  86. /* The Doxygen comment is with the function's prototype in opener_api.h. */
  87. CipShortString *GetDeviceProductName(void) {
  88. return &g_identity.product_name;
  89. }
  90. static inline void MergeStatusAndExtStatus(void) {
  91. CipWord status_flags = g_identity.status & (~kExtStatusMask);
  92. CipWord ext_status = g_identity.ext_status & kExtStatusMask;
  93. /* Any major fault will override the current extended status with kMajorFault.
  94. See comment on Major Fault at Vol. 1, Table 5A-2.4. */
  95. if(0 !=
  96. (status_flags & (kMajorRecoverableFault | kMajorUnrecoverableFault) ) ) {
  97. ext_status = kMajorFault;
  98. }
  99. g_identity.status = status_flags | ext_status;
  100. }
  101. /** @brief Set status flags of the device's Status word
  102. *
  103. * @param status_flags flags to set in the Status word
  104. *
  105. * This function sets status flags of the device's Status word and combines
  106. * the flag values with the internal ext_status member into a new Status
  107. * value.
  108. */
  109. void CipIdentitySetStatusFlags(const CipWord status_flags) {
  110. g_identity.status |= status_flags & (~kExtStatusMask);
  111. MergeStatusAndExtStatus();
  112. }
  113. /** @brief Clear status flags of the device's Status word
  114. *
  115. * @param status_flags flags to clear in the Status word
  116. *
  117. * This function clears status flags of the device's Status word and combines
  118. * the flag values with the internal ext_status member into a new Status
  119. * value.
  120. */
  121. void CipIdentityClearStatusFlags(const CipWord status_flags) {
  122. g_identity.status &= ~(status_flags & (~kExtStatusMask) );
  123. MergeStatusAndExtStatus();
  124. }
  125. /** @brief Set the device's Extended Device Status field in the Status word
  126. *
  127. * @param extended_status Extended Device Status field
  128. *
  129. * This function sets the internal ext_status member of the Identity object
  130. * and combines its value depending on the other Status flags into a new
  131. * Status value.
  132. */
  133. void CipIdentitySetExtendedDeviceStatus(
  134. CipIdentityExtendedStatus extended_status) {
  135. OPENER_TRACE_INFO("Setting extended status: %x\n", extended_status);
  136. g_identity.ext_status = extended_status & kExtStatusMask;
  137. MergeStatusAndExtStatus();
  138. }
  139. /** @brief Identity Object PreResetCallback
  140. *
  141. * Used for common Reset service
  142. *
  143. * @returns Currently always kEipOkSend is returned
  144. */
  145. EipStatus IdentityObjectPreResetCallback(
  146. CipInstance *RESTRICT const instance,
  147. const CipMessageRouterRequest *const message_router_request,
  148. CipMessageRouterResponse *const message_router_response
  149. ) {
  150. (void) instance;
  151. EipStatus eip_status = kEipStatusOkSend;
  152. if(message_router_request->request_data_size > 1) {
  153. message_router_response->general_status = kCipErrorTooMuchData;
  154. } else {
  155. CipOctet reset_type = 0; /* The default type if type parameter was omitted. */
  156. if(message_router_request->request_data_size == 1) {
  157. reset_type = message_router_request->data[0];
  158. }
  159. switch(reset_type) {
  160. case 0: /* Reset type 0 -> Emulate power cycle */
  161. if(kEipStatusError == ResetDevice() ) {
  162. message_router_response->general_status = kCipErrorInvalidParameter;
  163. }
  164. break;
  165. case 1: /* Reset type 1 -> Return to factory defaults & power cycle*/
  166. if(kEipStatusError == ResetDeviceToInitialConfiguration() ) {
  167. message_router_response->general_status = kCipErrorInvalidParameter;
  168. }
  169. break;
  170. /* case 2: Not supported Reset type 2 ->
  171. Return to factory defaults except communications parameters & power cycle*/
  172. default:
  173. message_router_response->general_status = kCipErrorInvalidParameter;
  174. break;
  175. }
  176. }
  177. return eip_status;
  178. }
  179. void InitializeCipIdentity(CipClass *class) {
  180. CipClass *meta_class = class->class_instance.cip_class;
  181. InsertAttribute( (CipInstance *) class, 1, kCipUint, EncodeCipUint, NULL,
  182. (void *) &class->revision, kGetableSingleAndAll ); /* revision */
  183. InsertAttribute( (CipInstance *) class, 2, kCipUint, EncodeCipUint, NULL,
  184. (void *) &class->number_of_instances, kGetableSingleAndAll ); /* largest instance number */
  185. InsertAttribute( (CipInstance *) class, 3, kCipUint, EncodeCipUint, NULL,
  186. (void *) &class->number_of_instances, kGetableSingle ); /* number of instances currently existing*/
  187. InsertAttribute( (CipInstance *) class, 4, kCipUint, EncodeCipUint, NULL,
  188. (void *) &kCipUintZero, kNotSetOrGetable ); /* optional attribute list - default = 0 */
  189. InsertAttribute( (CipInstance *) class, 5, kCipUint, EncodeCipUint, NULL,
  190. (void *) &kCipUintZero, kNotSetOrGetable ); /* optional service list - default = 0 */
  191. InsertAttribute( (CipInstance *) class, 6, kCipUint, EncodeCipUint, NULL,
  192. (void *) &meta_class->highest_attribute_number,
  193. kGetableSingleAndAll ); /* max class attribute number*/
  194. InsertAttribute( (CipInstance *) class, 7, kCipUint, EncodeCipUint, NULL,
  195. (void *) &class->highest_attribute_number,
  196. kGetableSingleAndAll ); /* max instance attribute number*/
  197. InsertService(meta_class,
  198. kGetAttributeAll,
  199. &GetAttributeAll,
  200. "GetAttributeAll"); /* bind instance services to the metaclass*/
  201. InsertService(meta_class,
  202. kGetAttributeSingle,
  203. &GetAttributeSingle,
  204. "GetAttributeSingle");
  205. // add Callback function pointers
  206. class->PreResetCallback = &IdentityObjectPreResetCallback;
  207. }
  208. void EncodeRevision(const void *const data,
  209. ENIPMessage *const outgoing_message) {
  210. CipRevision *revision = (CipRevision *) data;
  211. AddSintToMessage(revision->major_revision, outgoing_message);
  212. AddSintToMessage(revision->minor_revision, outgoing_message);
  213. }
  214. EipStatus CipIdentityInit() {
  215. CipClass *class = CreateCipClass(kCipIdentityClassCode, 0, /* # of non-default class attributes */
  216. 7, /* # highest class attribute number*/
  217. 2, /* # of class services*/
  218. 7, /* # of instance attributes*/
  219. 7, /* # highest instance attribute number*/
  220. 5, /* # of instance services*/
  221. 1, /* # of instances*/
  222. "identity", /* # class name (for debug)*/
  223. 1, /* # class revision*/ //TODO: change revision to 2 - check
  224. &InitializeCipIdentity); /* # function pointer for initialization*/
  225. if(class == 0) {
  226. return kEipStatusError;
  227. }
  228. if (g_identity.product_name.length == 0)
  229. SetDeviceProductName(OPENER_DEVICE_NAME);
  230. CipInstance *instance = GetCipInstance(class, 1);
  231. InsertAttribute(instance, 1, kCipUint, EncodeCipUint,
  232. NULL, &g_identity.vendor_id, kGetableSingleAndAll);
  233. InsertAttribute(instance, 2, kCipUint, EncodeCipUint,
  234. NULL, &g_identity.device_type, kGetableSingleAndAll);
  235. InsertAttribute(instance, 3, kCipUint, EncodeCipUint,
  236. NULL, &g_identity.product_code, kGetableSingleAndAll);
  237. InsertAttribute(instance, 4, kCipUsintUsint, EncodeRevision,
  238. NULL, &g_identity.revision, kGetableSingleAndAll);
  239. InsertAttribute(instance, 5, kCipWord, EncodeCipWord,
  240. NULL, &g_identity.status, kGetableSingleAndAll);
  241. InsertAttribute(instance, 6, kCipUdint, EncodeCipUdint,
  242. NULL, &g_identity.serial_number, kGetableSingleAndAll);
  243. InsertAttribute(instance, 7, kCipShortString, EncodeCipShortString,
  244. NULL, &g_identity.product_name, kGetableSingleAndAll);
  245. InsertService(class,
  246. kGetAttributeSingle,
  247. &GetAttributeSingle,
  248. "GetAttributeSingle");
  249. InsertService(class, kGetAttributeAll, &GetAttributeAll, "GetAttributeAll");
  250. InsertService(class, kReset, &CipResetService, "Reset");
  251. InsertService(class, kGetAttributeList, &GetAttributeList,
  252. "GetAttributeList");
  253. InsertService(class, kSetAttributeList, &SetAttributeList,
  254. "SetAttributeList");
  255. return kEipStatusOk;
  256. }