opener_api.h 47 KB

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