cipassembly.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. /*******************************************************************************
  2. * Copyright (c) 2009, Rockwell Automation, Inc.
  3. * All rights reserved.
  4. *
  5. ******************************************************************************/
  6. #include <string.h>
  7. #include <stdbool.h>
  8. #include "cipassembly.h"
  9. #include "cipcommon.h"
  10. #include "opener_api.h"
  11. #include "trace.h"
  12. #include "cipconnectionmanager.h"
  13. /** @brief Retrieve the given data according to CIP encoding from the
  14. * message buffer.
  15. *
  16. * Implementation of the decode function for the SetAttributeSingle CIP service for Assembly
  17. * Objects.
  18. * Currently only supports Attribute 3 (CIP_BYTE_ARRAY) of an Assembly
  19. * @param data pointer to value to be written.
  20. * @param message_router_request pointer to the request where the data should be taken from
  21. * @param message_router_response pointer to the response where status should be set
  22. * @return length of taken bytes
  23. * -1 .. error
  24. */
  25. int DecodeCipAssemblyAttribute3(void *const data,
  26. CipMessageRouterRequest *const message_router_request,
  27. CipMessageRouterResponse *const message_router_response);
  28. static EipStatus AssemblyPreGetCallback(CipInstance *const instance,
  29. CipAttributeStruct *const attribute,
  30. CipByte service);
  31. static EipStatus AssemblyPostSetCallback(CipInstance *const instance,
  32. CipAttributeStruct *const attribute,
  33. CipByte service);
  34. /** @brief Constructor for the assembly object class
  35. *
  36. * Creates an initializes Assembly class or object instances
  37. * @return Pointer to the created Assembly object
  38. */
  39. CipClass *CreateAssemblyClass(void) {
  40. /* create the CIP Assembly object with zero instances */
  41. CipClass *assembly_class = CreateCipClass(kCipAssemblyClassCode, 0, /* # class attributes*/
  42. 7, /* # highest class attribute number*/
  43. 1, /* # class services*/
  44. 2, /* # instance attributes*/
  45. 4, /* # highest instance attribute number*/
  46. 2, /* # instance services*/
  47. 0, /* # instances*/
  48. "assembly", /* name */
  49. 2, /* Revision, according to the CIP spec currently this has to be 2 */
  50. NULL); /* # function pointer for initialization*/
  51. if(NULL != assembly_class) {
  52. InsertService(assembly_class,
  53. kGetAttributeSingle,
  54. &GetAttributeSingle,
  55. "GetAttributeSingle");
  56. InsertService(assembly_class,
  57. kSetAttributeSingle,
  58. &SetAttributeSingle,
  59. "SetAttributeSingle");
  60. InsertGetSetCallback(assembly_class, AssemblyPreGetCallback, kPreGetFunc);
  61. InsertGetSetCallback(assembly_class, AssemblyPostSetCallback, kPostSetFunc);
  62. }
  63. return assembly_class;
  64. }
  65. /** @brief create the CIP Assembly object with zero instances
  66. *
  67. */
  68. EipStatus CipAssemblyInitialize(void) {
  69. return ( NULL != CreateAssemblyClass() ) ? kEipStatusOk : kEipStatusError;
  70. }
  71. void ShutdownAssemblies(void) {
  72. const CipClass *const assembly_class = GetCipClass(kCipAssemblyClassCode);
  73. if(NULL != assembly_class) {
  74. const CipInstance *instance = assembly_class->instances;
  75. while(NULL != instance) {
  76. const CipAttributeStruct *const attribute = GetCipAttribute(instance, 3);
  77. if(NULL != attribute) {
  78. CipFree(attribute->data);
  79. }
  80. instance = instance->next;
  81. }
  82. }
  83. }
  84. CipInstance *CreateAssemblyObject(const CipInstanceNum instance_id,
  85. EipByte *const data,
  86. const EipUint16 data_length) {
  87. CipClass *assembly_class = GetCipClass(kCipAssemblyClassCode);
  88. if(NULL == assembly_class) {
  89. assembly_class = CreateAssemblyClass();
  90. }
  91. if(NULL == assembly_class) {
  92. return NULL;
  93. }
  94. CipInstance *const instance = AddCipInstance(assembly_class, instance_id); /* add instances (always succeeds (or asserts))*/
  95. CipByteArray *const assembly_byte_array = (CipByteArray *) CipCalloc(1,
  96. sizeof(
  97. CipByteArray) );
  98. if(assembly_byte_array == NULL) {
  99. return NULL; /*TODO remove assembly instance in case of error*/
  100. }
  101. assembly_byte_array->length = data_length;
  102. assembly_byte_array->data = data;
  103. InsertAttribute(instance,
  104. 3,
  105. kCipByteArray,
  106. EncodeCipByteArray,
  107. DecodeCipAssemblyAttribute3,
  108. assembly_byte_array,
  109. kSetAndGetAble | kPreGetFunc | kPostSetFunc);
  110. /* Attribute 4 Number of bytes in Attribute 3 */
  111. InsertAttribute(instance, 4, kCipUint, EncodeCipUint,
  112. NULL, &(assembly_byte_array->length), kGetableSingle);
  113. return instance;
  114. }
  115. EipStatus NotifyAssemblyConnectedDataReceived(CipInstance *const instance,
  116. const EipUint8 *const data,
  117. const size_t data_length) {
  118. /* empty path (path size = 0) need to be checked and taken care of in future */
  119. /* copy received data to Attribute 3 */
  120. const CipByteArray *const assembly_byte_array =
  121. (CipByteArray *) instance->attributes->data;
  122. if(assembly_byte_array->length != data_length) {
  123. OPENER_TRACE_ERR("wrong amount of data arrived for assembly object\n");
  124. return kEipStatusError; /*TODO question should we notify the application that wrong data has been received???*/
  125. } else {
  126. memcpy(assembly_byte_array->data, data, data_length);
  127. /* call the application that new data arrived */
  128. }
  129. return AfterAssemblyDataReceived(instance);
  130. }
  131. int DecodeCipAssemblyAttribute3(void *const data,
  132. CipMessageRouterRequest *const message_router_request,
  133. CipMessageRouterResponse *const message_router_response)
  134. {
  135. CipInstance *const instance =
  136. GetCipInstance(GetCipClass(
  137. message_router_request->request_path.class_id),
  138. message_router_request->request_path.instance_number);
  139. int number_of_decoded_bytes = -1;
  140. OPENER_TRACE_INFO(" -> set Assembly attribute byte array\r\n");
  141. CipByteArray *cip_byte_array = (CipByteArray *)data;
  142. if(message_router_request->request_data_size < cip_byte_array->length) {
  143. OPENER_TRACE_INFO(
  144. "DecodeCipByteArray: not enough data received.\n");
  145. message_router_response->general_status = kCipErrorNotEnoughData;
  146. return number_of_decoded_bytes;
  147. }
  148. if(message_router_request->request_data_size > cip_byte_array->length) {
  149. OPENER_TRACE_INFO(
  150. "DecodeCipByteArray: too much data received.\n");
  151. message_router_response->general_status = kCipErrorTooMuchData;
  152. return number_of_decoded_bytes;
  153. }
  154. // data-length is correct
  155. memcpy(cip_byte_array->data,
  156. message_router_request->data,
  157. cip_byte_array->length);
  158. if(AfterAssemblyDataReceived(instance) != kEipStatusOk) {
  159. /* punt early without updating the status... though I don't know
  160. * how much this helps us here, as the attribute's data has already
  161. * been overwritten.
  162. *
  163. * however this is the task of the application side which will
  164. * take the data. In addition we have to inform the sender that the
  165. * data was not ok.
  166. */
  167. message_router_response->general_status = kCipErrorInvalidAttributeValue;
  168. } else {
  169. message_router_response->general_status = kCipErrorSuccess;
  170. }
  171. number_of_decoded_bytes = cip_byte_array->length;
  172. return number_of_decoded_bytes;
  173. }
  174. static EipStatus AssemblyPreGetCallback(CipInstance *const instance,
  175. CipAttributeStruct *const attribute,
  176. CipByte service) {
  177. int rc;
  178. (void) attribute;
  179. (void) service; /* no unused parameter warnings */
  180. rc = BeforeAssemblyDataSend(instance);
  181. return rc;
  182. }
  183. static EipStatus AssemblyPostSetCallback(CipInstance *const instance,
  184. CipAttributeStruct *const attribute,
  185. CipByte service) {
  186. int rc;
  187. (void) attribute;
  188. (void) service; /* no unused parameter warnings */
  189. rc = AfterAssemblyDataReceived(instance);
  190. return rc;
  191. }