OpENer - Open Source EtherNet/IP(TM) I/O Target Stack  2.1
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cipassembly.c
Go to the documentation of this file.
1 /*******************************************************************************
2  * Copyright (c) 2009, Rockwell Automation, Inc.
3  * All rights reserved.
4  *
5  ******************************************************************************/
6 
7 #include <string.h>
8 #include <stdbool.h>
9 
10 #include "cipassembly.h"
11 
12 #include "cipcommon.h"
13 #include "opener_api.h"
14 #include "trace.h"
15 #include "cipconnectionmanager.h"
16 
22  CipMessageRouterRequest *const message_router_request,
23  CipMessageRouterResponse *const message_router_response,
24  struct sockaddr *originator_address,
25  const int encapsulation_session);
26 
33  /* create the CIP Assembly object with zero instances */
34  CipClass *assembly_class = CreateCipClass(kCipAssemblyClassCode, 0, /* # class attributes*/
35  7, /* # highest class attribute number*/
36  1, /* # class services*/
37  2, /* # instance attributes*/
38  4, /* # highest instance attribute number*/
39  2, /* # instance services*/
40  0, /* # instances*/
41  "assembly", /* name */
42  2, /* Revision, according to the CIP spec currently this has to be 2 */
43  NULL); /* # function pointer for initialization*/
44  if(NULL != assembly_class) {
45  InsertService(assembly_class,
48  "GetAttributeSingle");
49  InsertService(assembly_class,
52  "SetAssemblyAttributeSingle");
53  }
54 
55  return assembly_class;
56 }
57 
62  return ( NULL != CreateAssemblyClass() ) ? kEipStatusOk : kEipStatusError;
63 }
64 
65 void ShutdownAssemblies(void) {
66  CipClass *assembly_class = GetCipClass(kCipAssemblyClassCode);
67 
68  if(NULL != assembly_class) {
69  CipInstance *instance = assembly_class->instances;
70  while(NULL != instance) {
71  CipAttributeStruct *attribute = GetCipAttribute(instance, 3);
72  if(NULL != attribute) {
73  CipFree(attribute->data);
74  }
75  instance = instance->next;
76  }
77  }
78 }
79 
81  EipByte *const data,
82  const EipUint16 data_length) {
83  CipClass *assembly_class = GetCipClass(kCipAssemblyClassCode);
84  if(NULL == assembly_class) {
85  assembly_class = CreateAssemblyClass();
86  }
87 
88  if(NULL == assembly_class) {
89  return NULL;
90  }
91 
92  CipInstance *const instance = AddCIPInstance(assembly_class, instance_id); /* add instances (always succeeds (or asserts))*/
93 
94  CipByteArray *const assembly_byte_array = (CipByteArray *) CipCalloc(1,
95  sizeof(
96  CipByteArray) );
97  if(assembly_byte_array == NULL) {
98  return NULL; /*TODO remove assembly instance in case of error*/
99  }
100 
101  assembly_byte_array->length = data_length;
102  assembly_byte_array->data = data;
103  InsertAttribute(instance,
104  3,
106  assembly_byte_array,
108  /* Attribute 4 Number of bytes in Attribute 3 */
109  InsertAttribute(instance,
110  4,
111  kCipUint,
112  &(assembly_byte_array->length),
114 
115  return instance;
116 }
117 
119  const EipUint8 *const data,
120  const EipUint16 data_length) {
121  /* empty path (path size = 0) need to be checked and taken care of in future */
122  /* copy received data to Attribute 3 */
123  CipByteArray *assembly_byte_array =
124  (CipByteArray *) instance->attributes->data;
125  if(assembly_byte_array->length != data_length) {
126  OPENER_TRACE_ERR("wrong amount of data arrived for assembly object\n");
127  return kEipStatusError; /*TODO question should we notify the application that wrong data has been received???*/
128  }
129  else{
130  memcpy(assembly_byte_array->data, data, data_length);
131  /* call the application that new data arrived */
132  }
133 
134  return AfterAssemblyDataReceived(instance);
135 }
136 
138  CipMessageRouterRequest *const message_router_request,
139  CipMessageRouterResponse *const message_router_response,
140  struct sockaddr *originator_address,
141  const int encapsulation_session) {
142  OPENER_TRACE_INFO(" setAttribute %d\n",
143  message_router_request->request_path.attribute_number);
144 
145  const EipUint8 *const router_request_data = message_router_request->data;
146 
147  message_router_response->data_length = 0;
148  message_router_response->reply_service =
149  (0x80 | message_router_request->service);
150  message_router_response->general_status = kCipErrorAttributeNotSupported;
151  message_router_response->size_of_additional_status = 0;
152 
153  CipAttributeStruct *attribute = GetCipAttribute(instance,
154  message_router_request->request_path.attribute_number);
155 
156  if( (attribute != NULL) &&
157  (3 == message_router_request->request_path.attribute_number) ) {
158  if(attribute->data != NULL) {
159  CipByteArray *data = (CipByteArray *) attribute->data;
160 
161  /* TODO: check for ATTRIBUTE_SET/GETABLE MASK */
162  if( true == IsConnectedOutputAssembly(instance->instance_number) ) {
164  "Assembly AssemblyAttributeSingle: received data for connected output assembly\n\r");
165  message_router_response->general_status = kCipErrorAttributeNotSetable;
166  }
167  else{
168  if(message_router_request->request_path_size < data->length) {
170  "Assembly setAssemblyAttributeSingle: not enough data received.\r\n");
171  message_router_response->general_status = kCipErrorNotEnoughData;
172  }
173  else{
174  if(message_router_request->request_path_size > data->length) {
176  "Assembly setAssemblyAttributeSingle: too much data received.\r\n");
177  message_router_response->general_status = kCipErrorTooMuchData;
178  }
179  else{
180  memcpy(data->data, router_request_data, data->length);
181 
182  if(AfterAssemblyDataReceived(instance) != kEipStatusOk) {
183  /* punt early without updating the status... though I don't know
184  * how much this helps us here, as the attribute's data has already
185  * been overwritten.
186  *
187  * however this is the task of the application side which will
188  * take the data. In addition we have to inform the sender that the
189  * data was not ok.
190  */
191  message_router_response->general_status =
193  }
194  else{
195  message_router_response->general_status = kCipErrorSuccess;
196  }
197  }
198  }
199  }
200  }
201  else{
202  /* the attribute was zero we are a heartbeat assembly */
203  message_router_response->general_status = kCipErrorTooMuchData;
204  }
205  }
206 
207  if( (attribute != NULL) &&
208  (4 == message_router_request->request_path.attribute_number) ) {
209  message_router_response->general_status = kCipErrorAttributeNotSetable;
210  }
211 
212  return kEipStatusOkSend;
213 }
void InsertAttribute(CipInstance *const instance, const EipUint16 attribute_number, const EipUint8 cip_type, void *const data, const EipByte cip_flags)
Insert an attribute in an instance of a CIP class.
Definition: cipcommon.c:304
EipStatus SetAssemblyAttributeSingle(CipInstance *const instance, CipMessageRouterRequest *const message_router_request, CipMessageRouterResponse *const message_router_response, struct sockaddr *originator_address, const int encapsulation_session)
Implementation of the SetAttributeSingle CIP service for Assembly Objects. Currently only supports At...
Definition: cipassembly.c:137
const CipOctet * data
Definition: ciptypes.h:191
Tracing infrastructure for OpENer.
CipInstance * CreateAssemblyObject(const EipUint32 instance_id, EipByte *const data, const EipUint16 data_length)
Create an instance of an assembly object.
Definition: cipassembly.c:80
CipAttributeStruct * attributes
Definition: ciptypes.h:229
CIP Message Router Request.
Definition: ciptypes.h:187
Class is a subclass of Instance.
Definition: ciptypes.h:237
CIP Byte Array.
Definition: ciptypes.h:122
CipInstance * instances
Definition: ciptypes.h:255
EipUint16 length
Definition: ciptypes.h:123
#define OPENER_TRACE_ERR(...)
Definition: trace.h:86
CipInstance * AddCIPInstance(CipClass *RESTRICT const class, const EipUint32 instance_id)
Create one instance of a given class with a certain instance number.
Definition: cipcommon.c:178
EipStatus NotifyAssemblyConnectedDataReceived(CipInstance *const instance, const EipUint8 *const data, const EipUint16 data_length)
notify an Assembly object that data has been received for it.
Definition: cipassembly.c:118
EipStatus CipAssemblyInitialize(void)
create the CIP Assembly object with zero instances
Definition: cipassembly.c:61
void * CipCalloc(size_t number_of_elements, size_t size_of_element)
Allocate memory for the CIP stack.
CipClass * CreateCipClass(const EipUint32 class_id, const int number_of_class_attributes, const EipUint32 highest_class_attribute_number, const int number_of_class_services, const int number_of_instance_attributes, const EipUint32 highest_instance_attribute_number, const int number_of_instance_services, const int number_of_instances, char *name, const EipUint16 revision, void(*InitializeCipClass)(CipClass *))
Definition: cipcommon.c:189
EipStatus
EIP stack status enum.
Definition: typedefs.h:93
uint8_t EipUint8
Definition: typedefs.h:32
void InsertService(const CipClass *const class, const EipUint8 service_number, const CipServiceFunction service_function, char *const service_name)
Insert a service in an instance of a CIP object.
Definition: cipcommon.c:346
uint32_t EipUint32
Definition: typedefs.h:34
struct cip_instance * next
Definition: ciptypes.h:232
EipStatus AfterAssemblyDataReceived(CipInstance *instance)
Call back function to inform application on received data for an assembly object. ...
void ShutdownAssemblies(void)
clean up the data allocated in the assembly object instances
Definition: cipassembly.c:65
#define OPENER_TRACE_INFO(...)
Definition: trace.h:89
void CipFree(void *data)
Free memory allocated by the OpENer.
EipStatus GetAttributeSingle(CipInstance *RESTRICT const instance, CipMessageRouterRequest *const message_router_request, CipMessageRouterResponse *const message_router_response, struct sockaddr *originator_address, const int encapsulation_session)
Generic implementation of the GetAttributeSingle CIP service.
Definition: cipcommon.c:391
CipClass * GetCipClass(const EipUint32 class_id)
Get a pointer to a CIP object with given class code.
CipAttributeStruct * GetCipAttribute(const CipInstance *const instance, const EipUint16 attribute_number)
Get a pointer to an instance's attribute.
Definition: cipcommon.c:373
EipUint16 attribute_number
Definition: ciptypes.h:156
uint8_t EipByte
EIP Data type definitions.
Definition: typedefs.h:28
#define OPENER_TRACE_WARN(...)
Definition: trace.h:87
CipClass * CreateAssemblyClass(void)
Constructor for the assembly object class.
Definition: cipassembly.c:32
CIP Message Router Response.
Definition: ciptypes.h:199
EipUint32 instance_number
Definition: ciptypes.h:228
uint16_t EipUint16
Definition: typedefs.h:33
EipBool8 IsConnectedOutputAssembly(const EipUint32 instance_number)
EipByte * data
Definition: ciptypes.h:124
EipInt16 request_path_size
Definition: ciptypes.h:190
CipUsint size_of_additional_status
Definition: ciptypes.h:205