소스 검색

Merge pull request #355 from micsat/master

Common Services added, CMake config update
Martin Melik-Merkumians 3 년 전
부모
커밋
a066b345e9
6개의 변경된 파일309개의 추가작업 그리고 23개의 파일을 삭제
  1. 10 0
      source/CMakeLists.txt
  2. 165 1
      source/src/cip/cipcommon.c
  3. 64 0
      source/src/cip/cipcommon.h
  4. 15 22
      source/src/cip/cipidentity.c
  5. 32 0
      source/src/cip/ciptypes.h
  6. 23 0
      source/src/ports/POSIX/sample_application/opener_user_conf.h

+ 10 - 0
source/CMakeLists.txt

@@ -146,6 +146,16 @@ set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall" )
 ####################################################
 # Internal cache holding the available CIP objects #
 ####################################################
+
+# Add definitions for additional CIP Objects
+string(COMPARE NOTEQUAL "${OpENer_ADD_CIP_OBJECTS}" "" OpENer_HAS_ADDITIONAL_OBJECT)
+if (OpENer_HAS_ADDITIONAL_OBJECT)
+    string(REPLACE " " ";" OpENer_ADD_CIP_OBJECTS_LIST ${OpENer_ADD_CIP_OBJECTS})
+    foreach (CIP_OBJECT IN LISTS OpENer_ADD_CIP_OBJECTS_LIST)
+        add_definitions(-D${CIP_OBJECT})
+    endforeach ()
+endif ()
+
 set( OpENer_ADD_CIP_OBJECTS "" CACHE INTERNAL STRING )
 set( OpENer_ADD_CIP_OBJECTS_INCLUDES "" CACHE INTERNAL STRING )
 

+ 165 - 1
source/src/cip/cipcommon.c

@@ -30,6 +30,15 @@
 #include "stdlib.h"
 #include "ciptypes.h"
 
+#if defined(CIP_FILE_OBJECT) && 0 != CIP_FILE_OBJECT
+  #include "OpENerFileObject/cipfile.h"
+#endif
+
+#if defined(CIP_SECURITY_OBJECTS) && 0 != CIP_SECURITY_OBJECTS
+  #include "SecurityObjects/CipSecurityObject/cipsecurity.h"
+  #include "SecurityObjects/EtherNetIPSecurityObject/ethernetipsecurity.h"
+  #include "SecurityObjects/CertificateManagementObject/certificatemanagement.h"
+#endif
 /* private functions*/
 
 EipStatus CipStackInit(const EipUint16 unique_connection_id) {
@@ -52,6 +61,21 @@ EipStatus CipStackInit(const EipUint16 unique_connection_id) {
 #endif
   eip_status = CipQoSInit();
   OPENER_ASSERT(kEipStatusOk == eip_status);
+
+#if defined(CIP_FILE_OBJECT) && 0 != CIP_FILE_OBJECT
+  eip_status = CipFileInit();
+  OPENER_ASSERT(kEipStatusOk == eip_status);
+#endif
+
+#if defined(CIP_SECURITY_OBJECTS) && 0 != CIP_SECURITY_OBJECTS
+  eip_status = CipSecurityInit();
+  OPENER_ASSERT(kEipStatusOk == eip_status);
+  eip_status = EIPSecurityInit();
+  OPENER_ASSERT(kEipStatusOk == eip_status);
+  eip_status = CertificateManagementObjectInit();
+  OPENER_ASSERT(kEipStatusOk == eip_status);
+#endif
+
   /* the application has to be initialized at last */
   eip_status = ApplicationInitialization();
   OPENER_ASSERT(kEipStatusOk == eip_status);
@@ -230,6 +254,7 @@ CipClass *CreateCipClass(const CipUdint class_code,
   /* initialize the class-specific fields of the Class struct*/
   cip_class->class_code = class_code; /* the class remembers the class ID */
   cip_class->revision = revision; /* the class remembers the class ID */
+  cip_class->max_instance = 0; /* the largest instance number of a created object in this class */
   cip_class->number_of_instances = 0; /* the number of instances initially zero (more created below) */
   cip_class->instances = 0;
   cip_class->number_of_attributes = number_of_instance_attributes; /* the class remembers the number of instances of that class */
@@ -288,7 +313,7 @@ CipClass *CreateCipClass(const CipUdint class_code,
                      NULL, (void *) &cip_class->revision,
                      kGetableSingleAndAll );                   /* revision */
     InsertAttribute( (CipInstance *) cip_class, 2, kCipUint, EncodeCipUint,
-                     NULL, (void *) &cip_class->number_of_instances,
+                     NULL, (void *) &cip_class->max_instance,
                      kGetableSingleAndAll );                              /* #2 Max instance no. */
     InsertAttribute( (CipInstance *) cip_class, 3, kCipUint, EncodeCipUint,
                      NULL, (void *) &cip_class->number_of_instances,
@@ -1264,6 +1289,145 @@ int DecodePaddedEPath(CipEpath *epath,
   return number_of_decoded_elements * 2 + 1; /* number_of_decoded_elements times 2 as every encoding uses 2 bytes */
 }
 
+EipStatus CipCreateService(CipInstance *RESTRICT const instance,
+                             CipMessageRouterRequest *const message_router_request,
+                             CipMessageRouterResponse *const message_router_response,
+                             const struct sockaddr *originator_address,
+                             const int encapsulation_session) {
+
+  InitializeENIPMessage(&message_router_response->message);
+  message_router_response->reply_service = (0x80 | message_router_request->service);
+  message_router_response->general_status = kCipErrorSuccess;
+  message_router_response->size_of_additional_status = 0;
+
+  CipClass *class = GetCipClass(message_router_request->request_path.class_id);
+
+  EipStatus internal_state = kEipStatusOk;
+
+  /* Call the PreCreateCallback if the class provides one. */
+  if( NULL != class->PreCreateCallback) {
+    internal_state = class->PreCreateCallback(instance, message_router_request, message_router_response);
+  }
+
+  if (kEipStatusOk == internal_state) {
+    CipInstance *new_instance = AddCipInstances(class, 1); /* add 1 instance to class*/
+    OPENER_ASSERT(NULL != new_instance); /* fail if run out of memory */
+
+    /* Call the PostCreateCallback if the class provides one. */
+    if (NULL != class->PostCreateCallback) {
+      class->PostCreateCallback(new_instance, message_router_request, message_router_response);
+    }
+    OPENER_TRACE_INFO("Instance number %d created\n", new_instance->instance_number);
+  }
+  return kEipStatusOkSend;
+}
+
+EipStatus CipDeleteService(CipInstance *RESTRICT const instance,
+                 CipMessageRouterRequest *const message_router_request,
+                 CipMessageRouterResponse *const message_router_response,
+                 const struct sockaddr *originator_address,
+                 const int encapsulation_session) {
+
+  message_router_response->general_status = kCipErrorInstanceNotDeletable;
+  message_router_response->size_of_additional_status = 0;
+  InitializeENIPMessage(&message_router_response->message);
+  message_router_response->reply_service = (0x80 | message_router_request->service);
+
+  EipStatus internal_state = kEipStatusOk;
+
+  CipClass *const class = instance->cip_class;
+
+  /* Call the PreDeleteCallback if the class provides one. */
+  if (NULL != class->PreDeleteCallback) {
+    internal_state = class->PreDeleteCallback(instance, message_router_request,
+                                              message_router_response);
+  }
+
+  if (kEipStatusOk == internal_state) {
+    CipInstance *instances = class->instances;
+
+    // update pointers in instance list
+    instances = class->instances; /* pointer to first instance */
+    if (instances->instance_number ==
+        instance->instance_number) {  // if instance to delete is head
+      class->instances = instances->next;
+    } else {
+      while (NULL != instances->next)  // as long as pointer in not NULL
+      {
+        CipInstance *next_instance = instances->next;
+        if (next_instance->instance_number == instance->instance_number) {
+          instances->next = next_instance->next;
+          break;
+        }
+        instances = instances->next;
+      }
+    }
+    // free all allocated attributes of instance
+    CipAttributeStruct *attribute =
+        instance->attributes; /* init pointer to array of attributes*/
+    for (EipUint16 i = 0; i < instance->cip_class->number_of_attributes; i++) {
+      CipFree(attribute->data);
+      ++attribute;
+    }
+    CipFree(instance->attributes);
+
+    /* Call the PostDeleteCallback if the class provides one. */
+    if (NULL != class->PostDeleteCallback) {
+      class->PostDeleteCallback(instance, message_router_request,
+                                message_router_response);
+    }
+
+    OPENER_TRACE_INFO("Instance number %d deleted\n",
+                      instance->instance_number);
+    CipFree(instance);  // delete instance
+
+    class->number_of_instances--; /* update the total number of instances
+                                            recorded by the class - Attr. 3 */
+
+    // update largest instance number (class Attribute 2)
+    instances = class->instances;
+    while (NULL !=
+           instances->next) {  // get last element - should be largest number
+      instances = instances->next;
+    }
+    class->max_instance = instances->instance_number;
+
+    message_router_response->general_status = kCipErrorSuccess;
+  }
+  return kEipStatusOk;
+}
+
+EipStatus CipResetService(CipInstance *RESTRICT const instance,
+                CipMessageRouterRequest *const message_router_request,
+                CipMessageRouterResponse *const message_router_response,
+                const struct sockaddr *originator_address,
+                const int encapsulation_session) {
+  message_router_response->general_status = kCipErrorSuccess;
+  message_router_response->size_of_additional_status = 0;
+  InitializeENIPMessage(&message_router_response->message);
+  message_router_response->reply_service =
+      (0x80 | message_router_request->service);
+
+  EipStatus internal_state = kEipStatusOk;
+
+  CipClass *const class = instance->cip_class;
+
+  /* Call the PreResetCallback if the class provides one. */
+  if (NULL != class->PreResetCallback) {
+    internal_state = class->PreResetCallback(instance, message_router_request,
+                                             message_router_response);
+  }
+
+  if (kEipStatusError != internal_state) {
+    /* Call the PostResetCallback if the class provides one. */
+    if (NULL != class->PostResetCallback) {
+      class->PostResetCallback(instance, message_router_request,
+                               message_router_response);
+    }
+  }
+  return internal_state;
+}
+
 void AllocateAttributeMasks(CipClass *target_class) {
   unsigned size = 1 + CalculateIndex(target_class->highest_attribute_number);
   OPENER_TRACE_INFO(

+ 64 - 0
source/src/cip/cipcommon.h

@@ -145,4 +145,68 @@ EipStatus SetAttributeList(CipInstance *instance,
 int DecodePaddedEPath(CipEpath *epath,
                       const EipUint8 **message);
 
+/** @brief Generic implementation of the CIP Create service
+ *
+ *  Creates dynamically allocated object instance within the specified class.
+ *
+ * @param instance pointer to instance.
+ * @param message_router_request pointer to request.
+ * @param message_router_response pointer to response.
+ * @param originator_address address struct of the originator as received
+ * @param encapsulation_session associated encapsulation session of the explicit message
+ * @return status  >0 .. success
+ *          -1 .. requested instance not created
+ */
+EipStatus CipCreateService(
+    CipInstance *RESTRICT const instance,
+    CipMessageRouterRequest *const
+        message_router_request,
+    CipMessageRouterResponse *const
+        message_router_response,
+    const struct sockaddr *originator_address,
+    const int encapsulation_session);
+
+/** @brief Generic implementation of the CIP Delete service
+ *
+ *  Deletes dynamically allocated object instance within the specified class
+ *  and updates referred class attributes
+ *
+ * @param instance pointer to instance.
+ * @param message_router_request pointer to request.
+ * @param message_router_response pointer to response.
+ * @param originator_address address struct of the originator as received
+ * @param encapsulation_session associated encapsulation session of the explicit message
+ * @return status  >0 .. success
+ *          -1 .. requested instance not deleted
+ */
+EipStatus CipDeleteService(CipInstance *RESTRICT const instance,
+    CipMessageRouterRequest *const
+        message_router_request,
+    CipMessageRouterResponse *const
+        message_router_response,
+    const struct sockaddr *originator_address,
+    const int encapsulation_session);
+
+/** @brief Generic implementation of the CIP Reset service
+ *
+ *  Causes a transition to a default state or mode of
+ *  the object instance within the specified class
+ *
+ *
+ * @param instance pointer to instance.
+ * @param message_router_request pointer to request.
+ * @param message_router_response pointer to response.
+ * @param originator_address address struct of the originator as received
+ * @param encapsulation_session associated encapsulation session of the explicit message
+ * @return status  >0 .. success
+ *          -1 .. requested instance not reseted
+ */
+EipStatus CipResetService(CipInstance *RESTRICT const instance,
+    CipMessageRouterRequest *const
+        message_router_request,
+    CipMessageRouterResponse *const
+        message_router_response,
+    const struct sockaddr *originator_address,
+    const int encapsulation_session);
+
 #endif /* OPENER_CIPCOMMON_H_ */

+ 15 - 22
source/src/cip/cipidentity.c

@@ -120,29 +120,21 @@ void CipIdentitySetExtendedDeviceStatus(
   MergeStatusAndExtStatus();
 }
 
-/** @brief Reset service
+/** @brief Identity Object PreResetCallback
+ *
+ *  Used for common Reset service
  *
- * @param instance
- * @param message_router_request
- * @param message_router_response
  * @returns Currently always kEipOkSend is returned
  */
-static EipStatus Reset(CipInstance *instance,
-/* pointer to instance*/
-                       CipMessageRouterRequest *message_router_request,
-/* pointer to message router request*/
-                       CipMessageRouterResponse *message_router_response, /* pointer to message router response*/
-                       const struct sockaddr *originator_address,
-                       const int encapsulation_session) {
+EipStatus IdentityObjectPreResetCallback(
+    CipInstance *RESTRICT const instance,
+    CipMessageRouterRequest *const message_router_request,
+    CipMessageRouterResponse *const message_router_response
+) {
   (void) instance;
 
   EipStatus eip_status = kEipStatusOkSend;
 
-  message_router_response->reply_service =
-    (0x80 | message_router_request->service);
-  message_router_response->size_of_additional_status = 0;
-  message_router_response->general_status = kCipErrorSuccess;
-
   if(message_router_request->request_data_size > 1) {
     message_router_response->general_status = kCipErrorTooMuchData;
   } else {
@@ -163,18 +155,16 @@ static EipStatus Reset(CipInstance *instance,
         }
         break;
 
-      /* case 2: Not supported Reset type 2 ->
-         Return to factory defaults except communications parameters & power cycle*/
+        /* case 2: Not supported Reset type 2 ->
+           Return to factory defaults except communications parameters & power cycle*/
 
       default:
         message_router_response->general_status = kCipErrorInvalidParameter;
         break;
     }
   }
-
-  InitializeENIPMessage(&message_router_response->message);
   return eip_status;
-}
+  }
 
 void InitializeCipIdentity(CipClass *class) {
 
@@ -206,6 +196,9 @@ void InitializeCipIdentity(CipClass *class) {
                 &GetAttributeSingle,
                 "GetAttributeSingle");
 
+  // add Callback function pointers
+  class->PreResetCallback = &IdentityObjectPreResetCallback;
+
 }
 
 void EncodeRevision(const void *const data,
@@ -253,7 +246,7 @@ EipStatus CipIdentityInit() {
                 &GetAttributeSingle,
                 "GetAttributeSingle");
   InsertService(class, kGetAttributeAll, &GetAttributeAll, "GetAttributeAll");
-  InsertService(class, kReset, &Reset, "Reset");
+  InsertService(class, kReset, &CipResetService, "Reset");
   InsertService(class, kGetAttributeList, &GetAttributeList,
                 "GetAttributeList");
   InsertService(class, kSetAttributeList, &SetAttributeList,

+ 32 - 0
source/src/cip/ciptypes.h

@@ -333,6 +333,23 @@ typedef EipStatus (*CipGetSetCallback)(CipInstance *const instance,
                                        CipAttributeStruct *const attribute,
                                        CipByte service);
 
+/** @ingroup CIP_API
+ *  @typedef EipStatus (*CipCallback)(
+ *    CipInstance *const instance,
+ *    CipMessageRouterRequest *message_router_request,
+ *    CipMessageRouterResponse *message_router_response
+ *  )
+ *  @brief Signature definition of callback functions for CIP services
+ *
+ *  @param  instance  CIP instance involved in common services
+ *  @param  message_router_request pointer to request.
+ *  @param  message_router_response pointer to response.
+ *  @return           status of kEipStatusOk or kEipStatusError on failure
+ */
+typedef EipStatus (*CipCallback)(CipInstance *const instance,
+                const CipMessageRouterRequest *const message_router_request,
+		CipMessageRouterResponse *const message_router_response);
+
 /** @brief Type definition of CipClass that is a subclass of CipInstance */
 typedef struct cip_class {
   CipInstance class_instance;   /**< This is the instance that contains the
@@ -340,6 +357,7 @@ typedef struct cip_class {
   /* the rest of these are specific to the Class class only. */
   CipUdint class_code;   /**< class code */
   EipUint16 revision;   /**< class revision*/
+  EipUint16 max_instance;   /**< largest instance number existing in the class */
   EipUint16 number_of_instances;   /**< number of instances in the class (not
                                       including instance 0) */
   EipUint16 number_of_attributes;   /**< number of attributes of each instance */
@@ -365,6 +383,20 @@ typedef struct cip_class {
   /** Is called in SetAttributeSingle* after the received data was set
    * in the object's attributes. */
   CipGetSetCallback PostSetCallback;
+
+  /** Is called in Create before the instance is created. */
+  CipCallback PreCreateCallback;
+  /** Is called in Create after the instance has been created. */
+  CipCallback PostCreateCallback;
+  /** Is called in Delete before the instance is deleted. */
+  CipCallback PreDeleteCallback;
+  /** Is called in Delete after the instance has been deleted. */
+  CipCallback PostDeleteCallback;
+  /** Is called in Reset service */
+  CipCallback PreResetCallback;
+  /** Is called in Reset service. */
+  CipCallback PostResetCallback;
+
 } CipClass;
 
 /** @ingroup CIP_API

+ 23 - 0
source/src/ports/POSIX/sample_application/opener_user_conf.h

@@ -29,6 +29,29 @@
 
 #include "typedefs.h"
 
+/** @brief Set this define if you have a CIP File capable device
+ *
+ *  This define changes the OpENer device configuration in a way that
+ *  the File object is initialized.
+ *
+ *  This define should be set from the CMake command line using
+ *  "-DCIP_FILE_OBJECT:BOOL=ON"
+ */
+#ifndef CIP_FILE_OBJECT
+  #define CIP_FILE_OBJECT 0
+#endif
+
+/** @brief Set this define if you have a CIP Security capable device
+ *
+ *  This define changes the OpENer device configuration in a way that
+ *  the Security related objects are initialized.
+ *
+ *  This define should be set from the CMake command line using
+ *  "-DCIP_SECURITY_OBJECTS:BOOL=ON"
+ */
+#ifndef CIP_SECURITY_OBJECTS
+  #define CIP_SECURITY_OBJECTS 0
+#endif
 
 /** @brief Set this define if you have a DLR capable device
  *