Kaynağa Gözat

Merge pull request #342 from micsat/master

Common service "Set_Attribute_List" added,  service added to Identity object
Martin Melik-Merkumians 4 yıl önce
ebeveyn
işleme
2ddd023bfd

+ 2 - 2
data/OpENerPC.stc

@@ -1,4 +1,4 @@
- StcRev Data |1.25|CT17-EN|opener_master|1621536250| DevData |255|0|500|500|500,500|X||ENet|
+ StcRev Data |1.25|CT17-EN|OpENerPC|1623922735| DevData |255|0|500|500|500,500|X||ENet|
 [<00>]-------|OpENer PC||
   General    |3.27|EtherNet/IP  Vol 2, Ed 1.25||2.3|Rockwell Automation/Allen-Bradley|1|65001|
   DevProfile |12|Communications Adapter|,04,05,06,07,08,09,10,11,15,16,29,30,32,33,43,55,243,244,245,246,35,67,71,72,77,84,85,86,87,69,81,68,70,82,78,79,80,83,92,256,257,258,259,260,261,262|
@@ -27,7 +27,7 @@
   IAG        |X|X|X|X|X|X|X| | | | | | | | | | | | | | | | | |
   IAS        | | | | | | | | | | | | | | | | | | | | | | | | |
   IAL        | =(1)| =(12)| =(65001)| =(2.3)| | | =(OpENer PC)| | | | | | | | | | | | | | | | | |
-  IS         |X|X|X| | | |X| | | | | |
+  IS         |X|X|X| | | |X|X| | | | |
   ISP        ||0,1|||||||||||
   VSA        | |
   OPT        | | |

+ 1 - 1
source/src/cip/CMakeLists.txt

@@ -12,7 +12,7 @@ opener_common_includes()
 #######################################
 opener_platform_support("INCLUDES")
 
-set( CIP_SRC appcontype.c cipassembly.c cipclass3connection.c cipcommon.c cipconnectionobject.c cipconnectionmanager.c cipdlr.c ciperror.h cipethernetlink.c cipidentity.c cipioconnection.c cipmessagerouter.c ciptcpipinterface.c ciptypes.h cipepath.c cipelectronickey.c cipstring.c cipqos.c )
+set( CIP_SRC appcontype.c cipassembly.c cipclass3connection.c cipcommon.c cipconnectionobject.c cipconnectionmanager.c cipdlr.c ciperror.h cipethernetlink.c cipidentity.c cipioconnection.c cipmessagerouter.c ciptcpipinterface.c ciptypes.h cipepath.c cipelectronickey.c cipstring.c cipqos.c ciptypes.c)
 
 add_library( CIP ${CIP_SRC} )
 

+ 80 - 4
source/src/cip/cipcommon.c

@@ -28,9 +28,9 @@
 #include "appcontype.h"
 #include "cipepath.h"
 #include "stdlib.h"
+#include "ciptypes.h"
 
 /* private functions*/
-void EncodeEPath(CipEpath *epath, ENIPMessage *message);
 
 EipStatus CipStackInit(const EipUint16 unique_connection_id) {
   /* The message router is the first CIP object be initialized!!! */
@@ -560,6 +560,7 @@ void EncodeCipByteArray(const CipByteArray *const data, ENIPMessage *const outgo
 }
 
 void EncodeCipEPath(const CipEpath *const data, ENIPMessage *const outgoing_message) {
+  AddIntToMessage(data->path_size, outgoing_message);
   EncodeEPath((CipEpath*) data, outgoing_message);
 }
 
@@ -905,10 +906,85 @@ EipStatus GetAttributeList(CipInstance *instance,
 	return kEipStatusOkSend;
 }
 
-void EncodeEPath(CipEpath *epath, ENIPMessage *message) {
+EipStatus SetAttributeList(CipInstance *instance,
+		CipMessageRouterRequest *message_router_request,
+		CipMessageRouterResponse *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;
+
+	CipUint attribute_count_request = GetUintFromMessage(
+			&message_router_request->data);
+
+	if (0 != attribute_count_request) {
+
+		EipUint16 attribute_number = 0;
+		CipAttributeStruct *attribute = NULL;
+
+		AddIntToMessage(attribute_count_request,
+				&message_router_response->message); // number of attributes in the response
+
+		for (size_t j = 0; j < attribute_count_request; j++) {
+
+			attribute_number = GetUintFromMessage(
+					&message_router_request->data);
+			attribute = GetCipAttribute(instance, attribute_number);
+
+			AddIntToMessage(attribute_number,
+					&message_router_response->message); // Attribute-ID
+
+			if (NULL != attribute) {
+
+				uint8_t set_bit_mask =
+						(instance->cip_class->set_bit_mask[CalculateIndex(
+								attribute_number)]);
+				if (0 != (set_bit_mask & (1 << (attribute_number % 8)))) { //check if attribute is settable
+					AddSintToMessage(kCipErrorSuccess,
+							&message_router_response->message); // Attribute status
+					AddSintToMessage(0, &message_router_response->message); // Reserved, shall be 0
+					attribute->decode(attribute->data, message_router_request,
+							message_router_response); // write data to attribute
+				} else {
+					AddSintToMessage(kCipErrorAttributeNotSetable,
+							&message_router_response->message); // Attribute status
+					AddSintToMessage(0, &message_router_response->message); // Reserved, shall be 0
+
+					//move request message pointer
+					int attribute_data_length = GetCipDataTypeLength(
+							attribute->type, message_router_request->data);
+					if (0 != attribute_data_length) {
+						message_router_request->data += attribute_data_length;
+						message_router_response->general_status =
+								kCipErrorAttributeListError;
+					} else {
+						message_router_response->general_status =
+								kCipErrorPartialTransfer;
+						return kEipStatusOkSend;
+					}
+				}
+			} else {
+				AddSintToMessage(kCipErrorAttributeNotSupported,
+						&message_router_response->message); // status
+				AddSintToMessage(0, &message_router_response->message); // Reserved, shall be 0
+				message_router_response->general_status =
+						kCipErrorAttributeListError;
+			}
+		}
+	} else {
+		message_router_response->general_status = kCipErrorAttributeListError;
+	}
+
+	return kEipStatusOkSend;
+}
+
+void EncodeEPath(const CipEpath *const epath, ENIPMessage *const message) {
   unsigned int length = epath->path_size;
   size_t start_length = message->used_message_length;
-  AddIntToMessage(epath->path_size, message);
 
   if(epath->class_id < 256) {
     AddSintToMessage(0x20, message); /* 8 Bit Class Id */
@@ -947,7 +1023,7 @@ void EncodeEPath(CipEpath *epath, ENIPMessage *message) {
     }
   }
 
-  OPENER_ASSERT(2 + epath->path_size * 2 == message->used_message_length - start_length); /* path size is in 16 bit chunks according to the specification */
+  OPENER_ASSERT(epath->path_size * 2 == message->used_message_length - start_length); /* path size is in 16 bit chunks according to the specification */
 }
 
 int DecodePaddedEPath(CipEpath *epath, const EipUint8 **message) {

+ 19 - 1
source/src/cip/cipcommon.h

@@ -65,7 +65,7 @@ void GenerateSetAttributeSingleHeader(
 /** @brief Generic implementation of the SetAttributeSingle CIP service
  *
  *  Modifies an attribute value if the requested object has
- *  the appropriate attribute implemented and if the attribute is setable.
+ *  the appropriate attribute implemented and if the attribute is settable.
  *
  * @param instance pointer to instance.
  * @param message_router_request pointer to request.
@@ -119,6 +119,24 @@ EipStatus GetAttributeList(CipInstance *instance,
                           const struct sockaddr *originator_address,
                           const int encapsulation_session);
 
+/** @brief Generic implementation of the SetAttributeList CIP service
+ *
+ * Sets the values of selected attributes of the specified object class
+ * or instance.
+ * @param instance pointer to object instance with data.
+ * @param message_router_request pointer to MR request.
+ * @param message_router_response pointer to MR response.
+ * @param originator_address address struct of the originator as received
+ * @param encapsulation_session associated encapsulation session of the explicit message
+ * @return length of data stream >0 .. success
+ *              0 .. no reply to send
+ */
+EipStatus SetAttributeList(CipInstance *instance,
+                          CipMessageRouterRequest *message_router_request,
+                          CipMessageRouterResponse *message_router_response,
+                          const struct sockaddr *originator_address,
+                          const int encapsulation_session);
+
 /** @brief Decodes padded EPath
  *  @param epath EPath object to the receiving element
  *  @param message pointer to the message to decode

+ 4 - 2
source/src/cip/cipidentity.c

@@ -233,10 +233,10 @@ EipStatus CipIdentityInit() {
                                    2, /* # of class services*/
                                    7, /* # of instance attributes*/
                                    7, /* # highest instance attribute number*/
-                                   4, /* # of instance services*/
+                                   5, /* # of instance services*/
                                    1, /* # of instances*/
                                    "identity", /* # class name (for debug)*/
-                                   1, /* # class revision*/
+                                   1, /* # class revision*/ //TODO: change revision to 2 - check
                                    &InitializeCipIdentity); /* # function pointer for initialization*/
 
   if (class == 0) {
@@ -300,6 +300,8 @@ EipStatus CipIdentityInit() {
   InsertService(class, kReset, &Reset, "Reset");
   InsertService(class, kGetAttributeList, &GetAttributeList,
                 "GetAttributeList");
+  InsertService(class, kSetAttributeList, &SetAttributeList,
+                  "SetAttributeList");
 
   return kEipStatusOk;
 }

+ 95 - 0
source/src/cip/ciptypes.c

@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2009, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+#include <ciptypes.h>
+#include <endianconv.h>
+#include <trace.h>
+
+/* functions*/
+size_t GetCipDataTypeLength(EipUint8 type, const EipUint8 *data) {
+
+	size_t length = 0;
+
+	switch (type) {
+		case kCipBool:
+		case kCipSint:
+		case kCipUsint:
+		case kCipByte:
+			length = 1;
+			break;
+
+		case kCipInt:
+		case kCipUint:
+		case kCipWord:
+		case kCipUsintUsint:
+		case kCipItime:
+		case kCipDate:
+		case kCipEngUnit:
+			length = 2;
+			break;
+
+		case kCipDint:
+		case kCipUdint:
+		case kCipDword:
+		case kCipStime:
+		case kCipFtime:
+		case kCipTime:
+		case kCipReal:
+		case kCipTimeOfDay:
+			length = 4;
+			break;
+
+		case kCipLint:
+		case kCipUlint:
+		case kCipLreal:
+		case kCipLword:
+		case kCipLtime:
+			length = 8;
+			break;
+
+		case kCip6Usint:
+			length = 6;
+			break;
+
+		case kCipString:
+		case kCipString2:
+		case kCipStringN:
+			if(NULL != data){
+				length = GetIntFromMessage(&data) + 2; // string length + 2 bytes length indicator
+			}
+			break;
+
+		case kCipShortString:
+			if(NULL != data){
+				length = GetSintFromMessage(&data) + 1; // string length + 1 byte length indicator
+			}
+			break;
+
+		case kCipEpath:
+			if(NULL != data){
+				length = GetIntFromMessage(&data) + 2; // path size + 2 bytes path size indicator
+			}
+			break;
+
+		case kCipByteArray:
+			if (NULL != data) {
+				CipByteArray *byte_array = (CipByteArray*) data;
+				length = byte_array->length;
+			}
+			break;
+
+		default:
+			OPENER_TRACE_ERR("GetCipDataTypeLength ERROR\n");
+			return 0;
+
+		/* TODO: missing data types:
+		 * kCipAny
+		 * kCipDateAndTime
+		 * kCipStringI
+		 * kCipMemberList
+		 */
+	}
+	return length;
+}

+ 8 - 1
source/src/cip/ciptypes.h

@@ -45,7 +45,7 @@ typedef enum cip_data_types {
                              length indicator */
   kCipTime = 0xDB, /**< Duration in milli-seconds; range of DINT */
   kCipEpath = 0xDC, /**< CIP path segments*/
-  kCipEngUnit = 0xDD, /**< Engineering Units*/
+  kCipEngUnit = 0xDD, /**< Engineering Units, range of UINT*/
   /* definition of some CIP structs */
   /* need to be validated in IEC 61131-3 subclause 2.3.3 */
   /* TODO: Check these codes */
@@ -60,6 +60,13 @@ typedef enum cip_data_types {
   kCipStringI
 } CipDataType;
 
+/** @brief returns the size of CIP data types in bytes
+ * @param type CIP data type
+ * @param data use data pointer if data length is variable, else set NULL
+ * @return size of CIP data type in bytes
+ * */
+size_t GetCipDataTypeLength(EipUint8 type, const EipUint8 *data);
+
 /** @brief Definition of CIP service codes
  *
  * An Enum with all CIP service codes. Common services codes range from 0x01 to

+ 4 - 1
source/src/opener_api.h

@@ -364,7 +364,10 @@ void EncodeCipByteArray(const CipByteArray *const data,
                         ENIPMessage *const outgoing_message);
 
 void EncodeCipEPath(const CipEpath *const data,
-                    ENIPMessage *const outgoing_message);
+                    ENIPMessage *const outgoing_message); //path_size UINT
+
+void EncodeEPath(const CipEpath *const data,
+                 ENIPMessage *const outgoing_message); //path_size not encoded
 
 void EncodeCipEthernetLinkPhyisicalAddress(const void *const data,
                                            ENIPMessage *const outgoing_message);