opener_api.h 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182
  1. /*******************************************************************************
  2. * Copyright (c) 2009, Rockwell Automation, Inc.
  3. * All rights reserved.
  4. *
  5. ******************************************************************************/
  6. #ifndef OPENER_OPENER_API_H_
  7. #define OPENER_OPENER_API_H_
  8. #include <assert.h>
  9. #include <stdbool.h>
  10. #include "ciperror.h"
  11. #include "ciptypes.h"
  12. #include "core/typedefs.h"
  13. #if defined(STM32) /** STM32 target -> uses a struct for the network interface \
  14. */
  15. #define TcpIpInterface struct netif
  16. #else /** other targets -> string for the network interface */
  17. #define TcpIpInterface const char
  18. #endif /** other targets */
  19. /** @defgroup CIP_API OpENer User interface
  20. * @brief This is the public interface of the OpENer. It provides all function
  21. * needed to implement an EtherNet/IP enabled slave-device.
  22. */
  23. /** @ingroup CIP_API
  24. * @brief Read network configuration data from specified hardware interface
  25. *
  26. * @param iface address specifying the network interface
  27. * @param iface_cfg address of interface configuration structure
  28. * @return kEipStatusOk on success,
  29. * kEipStatusError on error with @p errno set
  30. *
  31. * This function reads all information needed to fill the iface_cfg structure
  32. * of type @ref CipTcpIpInterfaceConfiguration from the hardware interface
  33. * specified by the iface string.
  34. *
  35. */
  36. EipStatus IfaceGetConfiguration(TcpIpInterface* iface,
  37. CipTcpIpInterfaceConfiguration* iface_cfg);
  38. /** @ingroup CIP_API
  39. * @brief Read and return the MAC address of the Ethernet interface
  40. *
  41. * @param iface address specifying the network interface
  42. * @param physical_address hardware MAC address of the network interface
  43. * @return kEipStatusOk: all fine
  44. * kEipStatusError: failure, errno set
  45. */
  46. EipStatus IfaceGetMacAddress(TcpIpInterface* iface,
  47. uint8_t* const physical_address);
  48. /** @ingroup CIP_API
  49. * @brief Wait for the network interface having an IP address
  50. *
  51. * @param iface address specifying the network interface
  52. * @param timeout in seconds; max: INT_MAX/10, -1: wait for ever
  53. * @param abort_wait stop waiting if this parameter becomes zero
  54. * @return kEipStatusOk on success,
  55. * kEipStatusError on error with @p errno set
  56. *
  57. * This function waits for the network interface getting an IP address but
  58. * only @p timeout seconds (set to -1 to wait for ever).
  59. * The polling wait process can be aborted by setting @p abort_wait to
  60. * a non zero value from another thread.
  61. */
  62. EipStatus IfaceWaitForIp(TcpIpInterface* const iface,
  63. int timeout,
  64. volatile int* const abort_wait);
  65. #if defined(STM32) /** STM32 target, the hostname is linked to the network \
  66. interface */
  67. /** @ingroup CIP_API
  68. * @brief Get host name from platform
  69. *
  70. * @param iface address specifying the network interface
  71. * @param hostname address of CipString destination structure
  72. *
  73. * This function reads the host name from the platform and returns it
  74. * via the hostname parameter.
  75. */
  76. void GetHostName(TcpIpInterface* iface, CipString* hostname);
  77. #else /** other targets */
  78. /** @ingroup CIP_API
  79. * @brief Get host name from platform
  80. *
  81. * @param hostname address of CipString destination structure
  82. *
  83. * This function reads the host name from the platform and returns it
  84. * via the hostname parameter.
  85. */
  86. void GetHostName(CipString* hostname);
  87. #endif /** other targets */
  88. /** @ingroup CIP_API
  89. * @brief Set the CIP revision of the device's identity object.
  90. *
  91. * @param major unsigned 8 bit major revision
  92. * @param minor unsigned 8 bit minor revision
  93. */
  94. void SetDeviceRevision(EipUint8 major, EipUint8 minor);
  95. /** @ingroup CIP_API
  96. * @brief Set the serial number of the device's identity object.
  97. *
  98. * @param serial_number unique 32 bit number identifying the device
  99. */
  100. void SetDeviceSerialNumber(const EipUint32 serial_number);
  101. /** @ingroup CIP_API
  102. * @brief Set the DeviceType of the device's identity object.
  103. *
  104. * @param type 16 bit unsigned number representing the CIP device type
  105. */
  106. void SetDeviceType(const EipUint16 type);
  107. /** @ingroup CIP_API
  108. * @brief Set the ProductCode of the device's identity object.
  109. *
  110. * @param type 16 bit unsigned number representing the product code
  111. */
  112. void SetDeviceProductCode(const EipUint16 code);
  113. /** @ingroup CIP_API
  114. * @brief Set the device's Status word also updating the Extended Device Status
  115. *
  116. * @param status complete Identity Object's Status word content
  117. *
  118. * This function sets the status flags and the internal state of the Extended
  119. * Device Status field in Identity object's ext_status member.
  120. */
  121. void SetDeviceStatus(const CipWord status);
  122. /** @ingroup CIP_API
  123. * @breif Set device's CIP VendorId
  124. *
  125. * @param vendor_id vendor ID, can be zero
  126. *
  127. * When OpENer is used as a library, multiple CIP adapters may use it
  128. * and may want to set the VendorId. Note: some applications allow
  129. * the use of VendorId 0.
  130. */
  131. void SetDeviceVendorId(CipUint vendor_id);
  132. /** @ingroup CIP_API
  133. * @brief Get device's CIP VendorId
  134. *
  135. * @returns the currently used VendorId
  136. */
  137. CipUint GetDeviceVendorId(void);
  138. /** @ingroup CIP_API
  139. * @breif Set device's CIP ProductName
  140. *
  141. * @param product_name C-string to use as ProducName
  142. *
  143. * When OpENer is used as a library, multiple CIP adapters may use it
  144. * and will need to change the product name.
  145. */
  146. void SetDeviceProductName(const char* product_name);
  147. /** @ingroup CIP_API
  148. * @brief Get device's current CIP ProductName
  149. *
  150. * Hint, use GetCstrFromCipShortString() to get a printable/logable C
  151. * string, since CipShortString's aren't NUL terminated.
  152. *
  153. * @returns the CipShortString for the product name
  154. */
  155. CipShortString* GetDeviceProductName(void);
  156. /** @ingroup CIP_API
  157. * @brief Initialize and setup the CIP-stack
  158. *
  159. * @param unique_connection_id value passed to Connection_Manager_Init() to form
  160. * a "per boot" unique connection ID.
  161. */
  162. EipStatus CipStackInit(const EipUint16 unique_connection_id);
  163. /** @ingroup CIP_API
  164. * @brief Shutdown of the CIP stack
  165. *
  166. * This will
  167. * - close all open I/O connections,
  168. * - close all open explicit connections, and
  169. * - free all memory allocated by the stack.
  170. *
  171. * Memory allocated by the application will not be freed. This has to be done
  172. * by the application!
  173. */
  174. void ShutdownCipStack(void);
  175. /** @ingroup CIP_API
  176. * @brief Enable the Run/Idle header for consumed (O->T) cyclic data
  177. * @param onoff if set (default), OpENer expects 4 byte Run/Idle header from
  178. * scanner
  179. */
  180. void CipRunIdleHeaderSetO2T(bool onoff);
  181. /** @ingroup CIP_API
  182. * @brief Get current setting of the O->T Run/Idle header
  183. * @return current setting of the O->T Run/Idle header
  184. */
  185. bool CipRunIdleHeaderGetO2T(void);
  186. /** @ingroup CIP_API
  187. * @brief Enable the Run/Idle header for produced (T->O) cyclic data
  188. * @param onoff if set (not default), OpENer includes a 4 byte Run/Idle header
  189. * in responses to scanner
  190. */
  191. void CipRunIdleHeaderSetT2O(bool onoff);
  192. /** @ingroup CIP_API
  193. * @brief Get current setting of the T->O Run/Idle header
  194. * @return current setting of the T->O Run/Idle header
  195. */
  196. bool CipRunIdleHeaderGetT2O(void);
  197. /** @ingroup CIP_API
  198. * @brief Get a pointer to a CIP object with given class code
  199. *
  200. * @param class_code class code of the object to retrieve
  201. * @return pointer to CIP Object
  202. * 0 if object is not present in the stack
  203. */
  204. CipClass* GetCipClass(const CipUdint class_code);
  205. /** @ingroup CIP_API
  206. * @brief Get a pointer to an instance
  207. *
  208. * @param cip_object pointer to the object the instance belongs to
  209. * @param instance_number number of the instance to retrieve
  210. * @return pointer to CIP Instance
  211. * 0 if instance is not in the object
  212. */
  213. CipInstance* GetCipInstance(const CipClass* RESTRICT const cip_object,
  214. const CipInstanceNum instance_number);
  215. /** @ingroup CIP_API
  216. * @brief Get a pointer to an instance's attribute
  217. *
  218. * As instances and objects are selfsimilar this function can also be used
  219. * to retrieve the attribute of an object.
  220. * @param cip_instance pointer to the instance the attribute belongs to
  221. * @param attribute_number number of the attribute to retrieve
  222. * @return pointer to attribute
  223. * 0 if instance is not in the object
  224. */
  225. CipAttributeStruct* GetCipAttribute(const CipInstance* const cip_instance,
  226. const EipUint16 attribute_number);
  227. typedef void (*InitializeCipClass)(
  228. CipClass*); /**< Initializer function for CIP class initialization */
  229. /** @ingroup CIP_API
  230. * @brief Allocate memory for new CIP Class and attributes
  231. *
  232. * The new CIP class will be registered at the stack to be able
  233. * for receiving explicit messages.
  234. *
  235. * @param class_code class code of the new class
  236. * @param number_of_class_attributes number of class attributes
  237. * @param highest_class_attribute_number Highest attribute number from the set
  238. * of implemented class attributes
  239. * @param number_of_class_services number of class services
  240. * @param number_of_instance_attributes Number of implemented instance
  241. * attributes
  242. * @param highest_instance_attribute_number Highest attribute number from the
  243. * set of implemented instance attributes
  244. * @param number_of_instance_services number of instance services
  245. * @param number_of_instances number of initial instances to create
  246. * @param name class name (for debugging class structure)
  247. * @param revision class revision
  248. * @param initializer For non-standard implementation of
  249. * class attributes, function realizes specific implementation
  250. * @return pointer to new class object
  251. * 0 on error
  252. */
  253. CipClass* CreateCipClass(const CipUdint class_code,
  254. const int number_of_class_attributes,
  255. const EipUint32 highest_class_attribute_number,
  256. const int number_of_class_services,
  257. const int number_of_instance_attributes,
  258. const EipUint32 highest_instance_attribute_number,
  259. const int number_of_instance_services,
  260. const CipInstanceNum number_of_instances,
  261. const char* const name,
  262. const EipUint16 revision,
  263. InitializeCipClass initializer);
  264. /** @ingroup CIP_API
  265. * @brief Add a number of CIP instances to a given CIP class
  266. *
  267. * The required number of instances are attached to the class as a linked list.
  268. *
  269. * The instances are numbered sequentially -- i.e. the first node in the chain
  270. * is instance 1, the second is 2, and so on.
  271. * You can add new instances at any time (you do not have to create all the
  272. * instances of a class at the same time) deleting instances once they have
  273. * been created is not supported out-of-order instance numbers are not
  274. * supported running out of memory while creating new instances causes an
  275. * assert.
  276. *
  277. * @param cip_object_to_add_instances CIP object the instances should be added
  278. * @param number_of_instances number of instances to be generated.
  279. * @return pointer to the first of the new instances
  280. * 0 on error
  281. */
  282. CipInstance* AddCipInstances(
  283. CipClass* RESTRICT const cip_object_to_add_instances,
  284. const CipInstanceNum number_of_instances);
  285. /** @ingroup CIP_API
  286. * @brief Create one instance of a given class with a certain instance number
  287. *
  288. * This function can be used for creating out of order instance numbers
  289. * @param cip_class_to_add_instance the class the instance should be created for
  290. * @param instance_id the instance id of the created instance
  291. * @return pointer to the created instance, if an instance with the given id
  292. * already exists the existing is returned an no new instance is created
  293. *
  294. */
  295. CipInstance* AddCipInstance(CipClass* RESTRICT const cip_class_to_add_instance,
  296. const CipInstanceNum instance_id);
  297. /** @ingroup CIP_API
  298. * @brief Insert an attribute in an instance of a CIP class
  299. *
  300. * Note that attributes are stored in an array pointer in the instance
  301. * the attributes array is not expandable if you insert an attributes that has
  302. * already been defined, the previous attributes will be replaced
  303. *
  304. * @param cip_instance Pointer to CIP class instance (Instance 0)
  305. * @param attribute_number Number of attribute to be inserted.
  306. * @param cip_data_type Type of attribute to be inserted.
  307. * @param encode_function Function pointer to the encoding function
  308. * @param decode_function Function pointer to the decoding function
  309. * @param cip_data Pointer to data of attribute.
  310. * @param cip_flags Flags to indicate set-ability and get-ability of attribute.
  311. */
  312. void InsertAttribute(CipInstance* const instance,
  313. const EipUint16 attribute_number,
  314. const EipUint8 cip_type,
  315. CipAttributeEncodeInMessage encode_function,
  316. CipAttributeDecodeFromMessage decode_function,
  317. void* const data,
  318. const EipByte cip_flags);
  319. /** @ingroup CIP_API
  320. * @brief Allocates Attribute bitmasks
  321. *
  322. * @param target_class Class, in which the bitmasks will be inserted.
  323. *
  324. */
  325. void AllocateAttributeMasks(CipClass* target_class);
  326. /** @ingroup CIP_API
  327. * @brief Calculates Byte-Index of Attribute
  328. *
  329. * @param attribute_number Attribute number.
  330. *
  331. */
  332. size_t CalculateIndex(EipUint16 attribute_number);
  333. /** @ingroup CIP_API
  334. * @brief Insert a service in an instance of a CIP object
  335. *
  336. * Note that services are stored in an array pointer in the class object
  337. * the service array is not expandable if you insert a service that has
  338. * already been defined, the previous service will be replaced
  339. *
  340. * @param cip_class pointer to CIP object. (may be also
  341. * instance# 0)
  342. * @param service_code service code of service to be inserted.
  343. * @param service_function pointer to function which represents the service.
  344. * @param service_name name of the service
  345. */
  346. void InsertService(const CipClass* const cip_class,
  347. const EipUint8 service_code,
  348. const CipServiceFunction service_function,
  349. char* const service_name);
  350. /** @ingroup CIP_API
  351. * @brief Insert a Get or Set callback for a CIP class
  352. *
  353. * @param cip_class pointer to the target CIP object
  354. * @param callback_function the callback function to insert
  355. * @param callbacks_to_install flags to select the affected callbacks
  356. *
  357. * This function inserts the provided @p callback_function into selected
  358. * callback function entries of the CIP class @p cip_class.
  359. * The callback targets are selected by @p callbacks_to_install that may
  360. * be an ORed mask of kPreGetFunc, kPostGetFunc, kPreSetFunc, kPostSetFunc
  361. * and kNvDataFunc.
  362. * If either the kPostSetFunc or kNvDataFunc is set the same function
  363. * pointer CipClass::PostSetCallback will be called.
  364. */
  365. void InsertGetSetCallback(CipClass* const cip_class,
  366. CipGetSetCallback callback_function,
  367. CIPAttributeFlag callbacks_to_install);
  368. // TODO: Update documentation
  369. /** @ingroup CIP_API
  370. * @brief Produce the data according to CIP encoding onto the message buffer.
  371. *
  372. * This function may be used in own services for sending data back to the
  373. * requester (e.g., getAttributeSingle for special structs).
  374. * @param cip_data_type the cip type to encode
  375. * @param cip_data pointer to data value.
  376. * @param message_router_response The message router response construct
  377. */
  378. void EncodeCipBool(const void* const data, ENIPMessage* const outgoing_message);
  379. void EncodeCipByte(const void* const data, ENIPMessage* const outgoing_message);
  380. void EncodeCipWord(const void* const data, ENIPMessage* const outgoing_message);
  381. void EncodeCipDword(const void* const data,
  382. ENIPMessage* const outgoing_message);
  383. void EncodeCipLword(const void* const data,
  384. ENIPMessage* const outgoing_message);
  385. void EncodeCipUsint(const void* const data,
  386. ENIPMessage* const outgoing_message);
  387. void EncodeCipUint(const void* const data, ENIPMessage* const outgoing_message);
  388. void EncodeCipUdint(const void* const data,
  389. ENIPMessage* const outgoing_message);
  390. void EncodeCipUlint(const void* const data,
  391. ENIPMessage* const outgoing_message);
  392. void EncodeCipSint(const void* const data, ENIPMessage* const outgoing_message);
  393. void EncodeCipInt(const void* const data, ENIPMessage* const outgoing_message);
  394. void EncodeCipDint(const void* const data, ENIPMessage* const outgoing_message);
  395. void EncodeCipLint(const void* const data, ENIPMessage* const outgoing_message);
  396. void EncodeCipReal(const void* const data, ENIPMessage* const outgoing_message);
  397. void EncodeCipLreal(const void* const data,
  398. ENIPMessage* const outgoing_message);
  399. void EncodeCipShortString(const void* const data,
  400. ENIPMessage* const outgoing_message);
  401. void EncodeCipString(const void* const data,
  402. ENIPMessage* const outgoing_message);
  403. void EncodeCipString2(const void* const data,
  404. ENIPMessage* const outgoing_message);
  405. void EncodeCipStringN(const void* const data,
  406. ENIPMessage* const outgoing_message);
  407. void EncodeCipStringI(const void* const data,
  408. ENIPMessage* const outgoing_message);
  409. void EncodeCipByteArray(const void* const data,
  410. ENIPMessage* const outgoing_message);
  411. void EncodeCipEPath(const void* const data,
  412. ENIPMessage* const outgoing_message); // path_size UINT
  413. void EncodeEPath(const void* const data,
  414. ENIPMessage* const outgoing_message); // path_size not encoded
  415. void EncodeCipEthernetLinkPhyisicalAddress(const void* const data,
  416. ENIPMessage* const outgoing_message);
  417. /** @ingroup CIP_API
  418. * @brief Retrieve the given data according to CIP encoding from the message
  419. * buffer.
  420. *
  421. * This function may be used in own services for handling data from the
  422. * requester (e.g., setAttributeSingle).
  423. * @param data pointer to value to be written.
  424. * @param message_router_request pointer to the request where the data should
  425. * be taken from
  426. * @param message_router_response pointer to the response where status should
  427. * be set
  428. * @return length of taken bytes
  429. * -1 .. error
  430. */
  431. int DecodeCipBool(CipBool* const data,
  432. CipMessageRouterRequest* const message_router_request,
  433. CipMessageRouterResponse* const message_router_response);
  434. int DecodeCipByte(CipByte* const data,
  435. CipMessageRouterRequest* const message_router_request,
  436. CipMessageRouterResponse* const message_router_response);
  437. int DecodeCipByteArray(
  438. CipByteArray* const data,
  439. const CipMessageRouterRequest* const message_router_request,
  440. CipMessageRouterResponse* const message_router_response);
  441. int DecodeCipWord(CipWord* const data,
  442. CipMessageRouterRequest* const message_router_request,
  443. CipMessageRouterResponse* const message_router_response);
  444. int DecodeCipDword(CipDword* const data,
  445. CipMessageRouterRequest* const message_router_request,
  446. CipMessageRouterResponse* const message_router_response);
  447. int DecodeCipLword(CipLword* const data,
  448. CipMessageRouterRequest* const message_router_request,
  449. CipMessageRouterResponse* const message_router_response);
  450. int DecodeCipUsint(CipUsint* const data,
  451. CipMessageRouterRequest* const message_router_request,
  452. CipMessageRouterResponse* const message_router_response);
  453. int DecodeCipUint(CipUint* const data,
  454. CipMessageRouterRequest* const message_router_request,
  455. CipMessageRouterResponse* const message_router_response);
  456. int DecodeCipUdint(CipUdint* const data,
  457. CipMessageRouterRequest* const message_router_request,
  458. CipMessageRouterResponse* const message_router_response);
  459. int DecodeCipUlint(CipUlint* const data,
  460. CipMessageRouterRequest* const message_router_request,
  461. CipMessageRouterResponse* const message_router_response);
  462. int DecodeCipSint(CipSint* const data,
  463. CipMessageRouterRequest* const message_router_request,
  464. CipMessageRouterResponse* const message_router_response);
  465. int DecodeCipInt(CipInt* const data,
  466. CipMessageRouterRequest* const message_router_request,
  467. CipMessageRouterResponse* const message_router_response);
  468. int DecodeCipDint(CipDint* const data,
  469. CipMessageRouterRequest* const message_router_request,
  470. CipMessageRouterResponse* const message_router_response);
  471. int DecodeCipLint(CipLint* const data,
  472. CipMessageRouterRequest* const message_router_request,
  473. CipMessageRouterResponse* const message_router_response);
  474. int DecodeCipReal(CipReal* const data,
  475. CipMessageRouterRequest* const message_router_request,
  476. CipMessageRouterResponse* const message_router_response);
  477. int DecodeCipLreal(CipLreal* const data,
  478. CipMessageRouterRequest* const message_router_request,
  479. CipMessageRouterResponse* const message_router_response);
  480. int DecodeCipString(CipString* const data,
  481. CipMessageRouterRequest* const message_router_request,
  482. CipMessageRouterResponse* const message_router_response);
  483. int DecodeCipShortString(
  484. CipShortString* const data,
  485. CipMessageRouterRequest* const message_router_request,
  486. CipMessageRouterResponse* const message_router_response);
  487. /** @ingroup CIP_API
  488. * @brief Create an instance of an assembly object
  489. *
  490. * @param instance_number instance number of the assembly object to create
  491. * @param data pointer to the data the assembly object should contain
  492. * @param data_length length of the assembly object's data
  493. * @return pointer to the instance of the created assembly object. NULL on error
  494. *
  495. * Assembly Objects for Configuration Data:
  496. *
  497. * The CIP stack treats configuration assembly objects the same way as any other
  498. * assembly object.
  499. * In order to support a configuration assembly object it has to be created with
  500. * this function.
  501. * The notification on received configuration data is handled with the
  502. * AfterAssemblyDataReceived.
  503. */
  504. CipInstance* CreateAssemblyObject(const CipInstanceNum instance_number,
  505. EipByte* const data,
  506. const EipUint16 data_length);
  507. typedef struct cip_connection_object CipConnectionObject;
  508. /** @ingroup CIP_API
  509. * @brief Function prototype for handling the opening of connections
  510. *
  511. * @param connection_object The connection object which is opening the
  512. * connection
  513. * @param extended_error_code The returned error code of the connection object
  514. *
  515. * @return CIP error code
  516. */
  517. typedef CipError (*OpenConnectionFunction)(
  518. CipConnectionObject* RESTRICT const connection_object,
  519. EipUint16* const extended_error_code);
  520. /** @ingroup CIP_API
  521. * @brief Function prototype for handling the closing of connections
  522. *
  523. * @param connection_object The connection object which is closing the
  524. * connection
  525. */
  526. typedef void (*ConnectionCloseFunction)(
  527. CipConnectionObject* RESTRICT connection_object);
  528. /** @ingroup CIP_API
  529. * @brief Function prototype for handling the timeout of connections
  530. *
  531. * @param connection_object The connection object which connection timed out
  532. */
  533. typedef void (*ConnectionTimeoutFunction)(
  534. CipConnectionObject* connection_object);
  535. /** @ingroup CIP_API
  536. * @brief Function prototype for sending data via a connection
  537. *
  538. * @param connection_object The connection object which connection timed out
  539. *
  540. * @return EIP stack status
  541. */
  542. typedef EipStatus (*ConnectionSendDataFunction)(
  543. CipConnectionObject* connection_object);
  544. /** @ingroup CIP_API
  545. * @brief Function prototype for receiving data via a connection
  546. *
  547. * @param connection_object The connection object which connection timed out
  548. * @param data The payload of the CIP message
  549. * @param data_length Length of the payload
  550. *
  551. * @return Stack status
  552. */
  553. typedef EipStatus (*ConnectionReceiveDataFunction)(
  554. CipConnectionObject* connection_object,
  555. const EipUint8* data,
  556. const EipUint16 data_length);
  557. /** @ingroup CIP_API
  558. * @brief Function pointer for timeout checker functions
  559. *
  560. * @param elapsed_time elapsed time since last check
  561. */
  562. typedef void (*TimeoutCheckerFunction)(const MilliSeconds elapsed_time);
  563. /** @ingroup CIP_API
  564. * @brief register open functions for an specific object.
  565. *
  566. * With this function any object can be enabled to be a target for forward
  567. * open/close request.
  568. * @param class_code The class code
  569. * @param open_connection_function Pointer to the function handling the open
  570. * process
  571. * @return EIP_OK on success
  572. */
  573. EipStatus AddConnectableObject(const CipUdint class_code,
  574. OpenConnectionFunction open_connection_function);
  575. /** @ingroup CIP_API
  576. * @brief Configures the connection point for an exclusive owner connection.
  577. *
  578. * @param connection_number The number of the exclusive owner connection. The
  579. * enumeration starts with 0. Has to be smaller than
  580. * OPENER_CIP_NUM_EXLUSIVE_OWNER_CONNS.
  581. * @param output_assembly_id ID of the O-to-T point to be used for this
  582. * connection
  583. * @param input_assembly_id ID of the T-to-O point to be used for this
  584. * connection
  585. * @param configuration_assembly_id ID of the configuration point to be used for
  586. * this connection
  587. */
  588. void ConfigureExclusiveOwnerConnectionPoint(
  589. const unsigned int connection_number,
  590. const unsigned int output_assembly_id,
  591. const unsigned int input_assembly_id,
  592. const unsigned int configuration_assembly_id);
  593. /** @ingroup CIP_API
  594. * @brief Configures the connection point for an input only connection.
  595. *
  596. * @param connection_number The number of the input only connection. The
  597. * enumeration starts with 0. Has to be smaller than
  598. * OPENER_CIP_NUM_INPUT_ONLY_CONNS.
  599. * @param output_assembly_id ID of the O-to-T point to be used for this
  600. * connection
  601. * @param input_assembly_id ID of the T-to-O point to be used for this
  602. * connection
  603. * @param configuration_assembly_id ID of the configuration point to be used for
  604. * this connection
  605. */
  606. void ConfigureInputOnlyConnectionPoint(
  607. const unsigned int connection_number,
  608. const unsigned int output_assembly_id,
  609. const unsigned int input_assembly_id,
  610. const unsigned int configuration_assembly_id);
  611. /** \ingroup CIP_API
  612. * \brief Configures the connection point for a listen only connection.
  613. *
  614. * @param connection_number The number of the input only connection. The
  615. * enumeration starts with 0. Has to be smaller than
  616. * OPENER_CIP_NUM_LISTEN_ONLY_CONNS.
  617. * @param output_assembly_id ID of the O-to-T point to be used for this
  618. * connection
  619. * @param input_assembly_id ID of the T-to-O point to be used for this
  620. * connection
  621. * @param configuration_assembly_id ID of the configuration point to be used for
  622. * this connection
  623. */
  624. void ConfigureListenOnlyConnectionPoint(
  625. const unsigned int connection_number,
  626. const unsigned int output_assembly_id,
  627. const unsigned int input_assembly_id,
  628. const unsigned int configuration_assembly_id);
  629. /** @ingroup CIP_API
  630. * @brief Notify the encapsulation layer that an explicit message has been
  631. * received via TCP.
  632. *
  633. * @param socket_handle Socket handle from which data is received.
  634. * @param buffer Buffer that contains the received data. This buffer will also
  635. * contain the response if one is to be sent.
  636. * @param length Length of the data in buffer.
  637. * @param number_of_remaining_bytes Return how many bytes of the input are left
  638. * over after we're done here
  639. * @param originator_address Address struct of the message originator
  640. * @param outgoing_message The outgoing ENIP message
  641. * @return kEipStatusOkSend: a response needs to be sent, others: EIP stack
  642. * status
  643. */
  644. EipStatus HandleReceivedExplictTcpData(int socket_handle,
  645. EipUint8* buffer,
  646. size_t length,
  647. int* number_of_remaining_bytes,
  648. struct sockaddr* originator_address,
  649. ENIPMessage* const outgoing_message);
  650. /** @ingroup CIP_API
  651. * @brief Notify the encapsulation layer that an explicit message has been
  652. * received via UDP.
  653. *
  654. * @param socket_handle socket handle from which data is received.
  655. * @param from_address remote address from which the data is received.
  656. * @param buffer buffer that contains the received data. This buffer will also
  657. * contain the response if one is to be sent.
  658. * @param buffer_length length of the data in buffer.
  659. * @param number_of_remaining_bytes return how many bytes of the input are left
  660. * over after we're done here
  661. * @param unicast Was the data received as unicast message?
  662. * @param outgoing_message Outgoing ENIP message
  663. * @return kEipStatusOkSend: a response needs to be sent, others: EIP stack
  664. * status
  665. */
  666. EipStatus HandleReceivedExplictUdpData(const int socket_handle,
  667. const struct sockaddr_in* from_address,
  668. const EipUint8* buffer,
  669. const size_t buffer_length,
  670. int* number_of_remaining_bytes,
  671. bool unicast,
  672. ENIPMessage* const outgoing_message);
  673. /** @ingroup CIP_API
  674. * @brief Notify the connection manager that data for a connection has been
  675. * received.
  676. *
  677. * This function should be invoked by the network layer.
  678. * @param received_data pointer to the buffer of data that has been received
  679. * @param received_data_length number of bytes in the data buffer
  680. * @param from_address address from which the data has been received. Only
  681. * data from the connections originator may be accepted. Avoids
  682. * connection hijacking
  683. * @return EIP_OK on success
  684. */
  685. EipStatus HandleReceivedConnectedData(const EipUint8* const received_data,
  686. int received_data_length,
  687. struct sockaddr_in* from_address);
  688. /** @ingroup CIP_API
  689. * @brief Check if any of the connection timers (TransmissionTrigger or
  690. * WatchdogTimeout) have timed out.
  691. *
  692. * If the a timeout occurs the function performs the necessary action. This
  693. * function should be called periodically once every @ref
  694. * kOpenerTimerTickInMilliSeconds milliseconds. In order to simplify the
  695. * algorithm if more time was lapsed, the elapsed time since the last call of
  696. * the function is given as a parameter.
  697. *
  698. * @param elapsed_time Elapsed time in milliseconds since the last call of
  699. * ManageConnections
  700. *
  701. * @return EIP_OK on success
  702. */
  703. EipStatus ManageConnections(MilliSeconds elapsed_time);
  704. /** @ingroup CIP_API
  705. * @brief Trigger the production of an application triggered connection.
  706. *
  707. * This will issue the production of the specified connection at the next
  708. * possible occasion. Depending on the values for the RPI and the production
  709. * inhibit timer. The application is informed via the
  710. * EIP_BOOL8 BeforeAssemblyDataSend(S_CIP_Instance *pa_pstInstance)
  711. * callback function when the production will happen. This function should only
  712. * be invoked from void HandleApplication(void).
  713. *
  714. * The connection can only be triggered if the application is established and it
  715. * is of application application triggered type.
  716. *
  717. * @param output_assembly_id the output assembly connection point of the
  718. * connection
  719. * @param input_assembly_id the input assembly connection point of the
  720. * connection
  721. * @return EIP_OK on success
  722. */
  723. EipStatus TriggerConnections(unsigned int output_assembly_id,
  724. unsigned int input_assembly_id);
  725. /** @ingroup CIP_API
  726. * @brief Inform the encapsulation layer that the remote host has closed the
  727. * connection.
  728. *
  729. * According to the specifications that will clean up and close the session in
  730. * the encapsulation layer.
  731. * @param socket_handle the handler to the socket of the closed connection
  732. */
  733. void CloseSession(int socket_handle);
  734. /** @defgroup CIP_CALLBACK_API Callback Functions Demanded by OpENer
  735. * @ingroup CIP_API
  736. *
  737. * @brief These functions have to implemented in order to give the OpENer a
  738. * method to inform the application on certain state changes.
  739. */
  740. /** @ingroup CIP_CALLBACK_API
  741. * @brief Callback for the application initialization
  742. *
  743. * This function will be called by the CIP stack after it has finished its
  744. * initialization. In this function the user can setup all CIP objects she
  745. * likes to have.
  746. *
  747. * This function is provided for convenience reasons. After the void
  748. * CipStackInit(void)
  749. * function has finished it is okay to also generate your CIP objects.
  750. * return status EIP_ERROR .. error
  751. * EIP_OK ... successful finish
  752. */
  753. EipStatus ApplicationInitialization(void);
  754. /** @ingroup CIP_CALLBACK_API
  755. * @brief Allow the device specific application to perform its execution
  756. *
  757. * This function will be executed by the stack at the beginning of each
  758. * execution of EIP_STATUS ManageConnections(void). It allows to implement
  759. * device specific application functions. Execution within this function should
  760. * be short.
  761. */
  762. void HandleApplication(void);
  763. /** @ingroup CIP_CALLBACK_API
  764. * @brief Inform the application on changes occurred for a connection
  765. *
  766. * @param output_assembly_id the output assembly connection point of the
  767. * connection
  768. * @param input_assembly_id the input assembly connection point of the
  769. * connection
  770. * @param io_connection_event information on the change occurred
  771. */
  772. void CheckIoConnectionEvent(unsigned int output_assembly_id,
  773. unsigned int input_assembly_id,
  774. IoConnectionEvent io_connection_event);
  775. /** @ingroup CIP_CALLBACK_API
  776. * @brief Call back function to inform application on received data for an
  777. * assembly object.
  778. *
  779. * This function has to be implemented by the user of the CIP-stack.
  780. * @param instance pointer to the assembly object data was received for
  781. * @return Information if the data could be processed
  782. * - EIP_OK the received data was ok
  783. * - EIP_ERROR the received data was wrong (especially needed for
  784. * configuration data assembly objects)
  785. *
  786. * Assembly Objects for Configuration Data:
  787. * The CIP-stack uses this function to inform on received configuration data.
  788. * The length of the data is already checked within the stack. Therefore the
  789. * user only has to check if the data is valid.
  790. */
  791. EipStatus AfterAssemblyDataReceived(CipInstance* instance);
  792. /** @ingroup CIP_CALLBACK_API
  793. * @brief Inform the application that the data of an assembly
  794. * object will be sent.
  795. *
  796. * Within this function the user can update the data of the assembly object
  797. * before it gets sent. The application can inform the application if data has
  798. * changed.
  799. * @param instance instance of assembly object that should send data.
  800. * @return data has changed:
  801. * - true assembly data has changed
  802. * - false assembly data has not changed
  803. */
  804. EipBool8 BeforeAssemblyDataSend(CipInstance* instance);
  805. /** @ingroup CIP_CALLBACK_API
  806. * @brief Emulate as close a possible a power cycle of the device
  807. *
  808. * @return if the service is supported the function will not return.
  809. * EIP_ERROR if this service is not supported
  810. */
  811. EipStatus ResetDevice(void);
  812. /** @ingroup CIP_CALLBACK_API
  813. * @brief Reset the device to the initial configuration and emulate as close as
  814. * possible a power cycle of the device
  815. *
  816. * @return if the service is supported the function will not return.
  817. * EIP_ERROR if this service is not supported
  818. */
  819. EipStatus ResetDeviceToInitialConfiguration(void);
  820. /** @ingroup CIP_CALLBACK_API
  821. * @brief Allocate memory for the CIP stack
  822. *
  823. * emulate the common c-library function calloc
  824. * In OpENer allocation only happens on application startup and on
  825. * class/instance creation and configuration not on during operation
  826. * (processing messages).
  827. * @param number_of_elements number of elements to allocate
  828. * @param size_of_element size in bytes of one element
  829. * @return pointer to the allocated memory, 0 on error
  830. */
  831. void* CipCalloc(size_t number_of_elements, size_t size_of_element);
  832. /** @ingroup CIP_CALLBACK_API
  833. * @brief Free memory allocated by the OpENer
  834. *
  835. * emulate the common c-library function free
  836. * @param data pointer to the allocated memory
  837. */
  838. void CipFree(void* data);
  839. /** @ingroup CIP_CALLBACK_API
  840. * @brief Inform the application that the Run/Idle State has been changed
  841. * by the originator.
  842. *
  843. * @param run_idle_value the current value of the run/idle flag according to CIP
  844. * spec Vol 1 3-6.5
  845. */
  846. void RunIdleChanged(EipUint32 run_idle_value);
  847. /** @ingroup CIP_CALLBACK_API
  848. * @brief Create the UDP socket for the implicit IO messaging,
  849. * one socket handles all connections
  850. * @return the socket handle if successful, else kEipInvalidSocket
  851. */
  852. int CreateUdpSocket(void);
  853. /** @ingroup CIP_CALLBACK_API
  854. * @brief Sends the data for the implicit IO messaging via UDP socket
  855. * @param socket_data Address message to be sent
  856. * @param outgoing message The constructed outgoing message
  857. * @return kEipStatusOk on success
  858. */
  859. EipStatus SendUdpData(const struct sockaddr_in* const socket_data,
  860. const ENIPMessage* const outgoing_message);
  861. /** @ingroup CIP_CALLBACK_API
  862. * @brief Close the given socket and clean up the stack
  863. *
  864. * @param socket_handle socket descriptor to close
  865. */
  866. void CloseSocket(const int socket_handle);
  867. /** @ingroup CIP_CALLBACK_API
  868. * @brief Register function pointer in timeout_checker_array
  869. *
  870. * @param timeout_checker_function pointer to object specific timeout checker
  871. * function
  872. */
  873. void RegisterTimeoutChecker(TimeoutCheckerFunction timeout_checker_function);
  874. /** @mainpage OpENer - Open Source EtherNet/IP(TM) Communication Stack
  875. * Documentation
  876. *
  877. * EtherNet/IP stack for adapter devices (connection target); supports multiple
  878. * I/O and explicit connections; includes features and objects required by the
  879. * CIP specification to enable devices to comply with ODVA's conformance/
  880. * interoperability tests.
  881. *
  882. * @section intro_sec Introduction
  883. *
  884. * This is the introduction.
  885. *
  886. * @section install_sec Building
  887. * How to compile, install and run OpENer on a specific platform.
  888. *
  889. * @subsection build_req_sec Requirements
  890. * OpENer has been developed to be highly portable. The default version targets
  891. * PCs with a POSIX operating system and a BSD-socket network interface. To
  892. * test this version we recommend a Linux PC or Windows with Cygwin installed.
  893. * You will need to have the following installed:
  894. * - gcc, make, binutils, etc.
  895. *
  896. * for normal building. These should be installed on most Linux installations
  897. * and are part of the development packages of Cygwin.
  898. *
  899. * For the development itself we recommend the use of Eclipse with the CDT
  900. * plugin. For your convenience OpENer already comes with an Eclipse project
  901. * file. This allows to just import the OpENer source tree into Eclipse.
  902. *
  903. * @subsection compile_pcs_sec Compile for PCs
  904. * -# Directly in the shell
  905. * -# Go into the bin/pc directory
  906. * -# Invoke make
  907. * -# For invoking opener type:\n
  908. * ./opener ipaddress subnetmask gateway domainname hostaddress
  909. * macaddress\n
  910. * e.g., ./opener 192.168.0.2 255.255.255.0 192.168.0.1 test.com
  911. * testdevice 00 15 C5 BF D0 87
  912. * -# Within Eclipse
  913. * -# Import the project
  914. * -# Go to the bin/pc folder in the make targets view
  915. * -# Choose all from the make targets
  916. * -# The resulting executable will be in the directory
  917. * ./bin/pc
  918. * -# The command line parameters can be set in the run configuration
  919. * dialog of Eclipse
  920. *
  921. * @section further_reading_sec Further Topics
  922. * - @ref porting
  923. * - @ref extending
  924. * - @ref license
  925. *
  926. * @page porting Porting OpENer
  927. * @section gen_config_section General Stack Configuration
  928. * The general stack properties have to be defined prior to building your
  929. * production. This is done by providing a file called opener_user_conf.h. An
  930. * example file can be found in the src/ports/POSIX or src/ports/WIN32
  931. directory.
  932. * The documentation of the example file for the necessary configuration
  933. options:
  934. * opener_user_conf.h
  935. *
  936. * @copydoc ./ports/POSIX/sample_application/opener_user_conf.h
  937. *
  938. * @section startup_sec Startup Sequence
  939. * During startup of your EtherNet/IP(TM) device the following steps have to be
  940. * performed:
  941. * -# Configure the network properties:\n
  942. * With the following functions the network interface of OpENer is
  943. * configured:
  944. * - EIP_STATUS ConfigureNetworkInterface(const char *ip_address,
  945. * const char *subnet_mask, const char *gateway_address)
  946. * - void ConfigureMACAddress(const EIP_UINT8 *mac_address)
  947. * - void ConfigureDomainName(const char *domain_name)
  948. * - void ConfigureHostName(const char *host_name)
  949. * .
  950. * Depending on your platform these data can come from a configuration
  951. * file or from operating system functions. If these values should be
  952. * setable remotely via explicit messages the SetAttributeSingle functions
  953. * of the EtherNetLink and the TCPIPInterface object have to be adapted.
  954. * -# Set the device's serial number\n
  955. * According to the CIP specification a device vendor has to ensure that
  956. * each of its devices has a unique 32Bit device id. You can set it with
  957. * the function:
  958. * - void setDeviceSerialNumber(EIP_UINT32 serial_number)
  959. * -# Initialize OpENer: \n
  960. * With the function CipStackInit(EIP_UINT16 unique_connection_id) the
  961. * internal data structures of opener are correctly setup. After this
  962. * step own CIP objects and Assembly objects instances may be created. For
  963. * your convenience we provide the call-back function
  964. * ApplicationInitialization. This call back function is called when the
  965. * stack is ready to receive application specific CIP objects.
  966. * -# Create Application Specific CIP Objects:\n
  967. * Within the call-back function ApplicationInitialization(void) or
  968. * after CipStackInit(void) has finished you may create and configure any
  969. * CIP object or Assembly object instances. See the module @ref CIP_API
  970. * for available functions. Currently no functions are available to
  971. * remove any created objects or instances. This is planned
  972. * for future versions.
  973. * -# Setup the listening TCP and UDP port:\n
  974. * THE ETHERNET/IP SPECIFICATION demands from devices to listen to TCP
  975. * connections and UDP datagrams on the port AF12hex for explicit messages.
  976. * Therefore before going into normal operation you need to configure your
  977. * network library so that TCP and UDP messages on this port will be
  978. * received and can be hand over to the Ethernet encapsulation layer.
  979. *
  980. * @section normal_op_sec Normal Operation
  981. * During normal operation the following tasks have to be done by the platform
  982. * specific code:
  983. * - Establish connections requested on TCP port AF12hex
  984. * - Receive explicit message data on connected TCP sockets and the UPD socket
  985. * for port AF12hex. The received data has to be hand over to Ethernet
  986. * encapsulation layer with the functions: \n
  987. * int HandleReceivedExplictTCPData(int socket_handle, EIP_UINT8* buffer,
  988. int
  989. * buffer_length, int *number_of_remaining_bytes),\n
  990. * int HandleReceivedExplictUDPData(int socket_handle, struct sockaddr_in
  991. * *from_address, EIP_UINT8* buffer, unsigned int buffer_length, int
  992. * *number_of_remaining_bytes).\n
  993. * Depending if the data has been received from a TCP or from a UDP socket.
  994. * As a result of this function a response may have to be sent. The data to
  995. * be sent is in the given buffer pa_buf.
  996. * - Create UDP sending and receiving sockets for implicit connected
  997. * messages\n
  998. * OpENer will use to call-back function int CreateUdpSocket(
  999. * UdpCommuncationDirection connection_direction,
  1000. * struct sockaddr_in *pa_pstAddr)
  1001. * for informing the platform specific code that a new connection is
  1002. * established and new sockets are necessary
  1003. * - Receive implicit connected data on a receiving UDP socket\n
  1004. * The received data has to be hand over to the Connection Manager Object
  1005. * with the function EIP_STATUS HandleReceivedConnectedData(EIP_UINT8
  1006. * *data, int data_length)
  1007. * - Close UDP and TCP sockets:
  1008. * -# Requested by OpENer through the call back function: void
  1009. * CloseSocket(int socket_handle)
  1010. * -# For TCP connection when the peer closed the connection OpENer needs
  1011. * to be informed to clean up internal data structures. This is done
  1012. * with
  1013. * the function void CloseSession(int socket_handle).
  1014. * .
  1015. * - Cyclically update the connection status:\n
  1016. * In order that OpENer can determine when to produce new data on
  1017. * connections or that a connection timed out every @ref
  1018. kOpenerTimerTickInMilliSeconds
  1019. * milliseconds the
  1020. * function EIP_STATUS ManageConnections(void) has to be called.
  1021. *
  1022. * @section callback_funcs_sec Callback Functions
  1023. * In order to make OpENer more platform independent and in order to inform the
  1024. * application on certain state changes and actions within the stack a set of
  1025. * call-back functions is provided. These call-back functions are declared in
  1026. * the file opener_api.h and have to be implemented by the application specific
  1027. * code. An overview and explanation of OpENer's call-back API may be found in
  1028. * the module @ref CIP_CALLBACK_API.
  1029. *
  1030. * @page extending Extending OpENer
  1031. * OpENer provides an API for adding own CIP objects and instances with
  1032. * specific services and attributes. Therefore OpENer can be easily adapted to
  1033. * support different device profiles and specific CIP objects needed for your
  1034. * device. The functions to be used are:
  1035. * - CipClass *CreateCipClass( const CipUdint class_code,
  1036. const int number_of_class_attributes,
  1037. const EipUint32 highest_class_attribute_number,
  1038. const int number_of_class_services,
  1039. const int number_of_instance_attributes,
  1040. const EipUint32 highest_instance_attribute_number,
  1041. const int number_of_instance_services,
  1042. const int number_of_instances,
  1043. char *name,
  1044. const EipUint16 revision,
  1045. InitializeCipClass initializer );
  1046. * - CipInstance *AddCipInstances(CipClass *RESTRICT const cip_class,
  1047. const int number_of_instances)
  1048. * - CipInstance *AddCipInstance(CipClass *RESTRICT const class,
  1049. const EipUint32 instance_id)
  1050. * - void InsertAttribute(CipInstance *const cip_instance,
  1051. const EipUint16 attribute_number,
  1052. const EipUint8 cip_data_type,
  1053. void *const cip_data,
  1054. const EipByte cip_flags);
  1055. * - void InsertService(const CipClass *const cip_class_to_add_service,
  1056. const EipUint8 service_code,
  1057. const CipServiceFunction service_function,
  1058. char *const service_name);
  1059. *
  1060. * @page license OpENer Open Source License
  1061. * The OpENer Open Source License is an adapted BSD style license. The
  1062. * adaptations include the use of the term EtherNet/IP(TM) and the necessary
  1063. * guarding conditions for using OpENer in own products. For this please look
  1064. * in license text as shown below:
  1065. *
  1066. * @include "../license.txt"
  1067. *
  1068. */
  1069. #endif /*OPENER_OPENER_API_H_*/