/*************************************************************************** * Copyright (C) 2020 by Kyle Hayes * * Author Kyle Hayes kyle.hayes@gmail.com * * * * This software is available under either the Mozilla Public License * * version 2.0 or the GNU LGPL version 2 (or later) license, whichever * * you choose. * * * * MPL 2.0: * * * * This Source Code Form is subject to the terms of the Mozilla Public * * License, v. 2.0. If a copy of the MPL was not distributed with this * * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * * * * * LGPL 2: * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #pragma once #include #ifdef __cplusplus extern "C" { #endif #if defined(_WIN32) || defined(WIN32) || defined(WIN64) || defined(_WIN64) #ifdef __cplusplus #define C_FUNC extern "C" #else #define C_FUNC #endif #ifdef LIBPLCTAGDLL_EXPORTS #define LIB_EXPORT __declspec(dllexport) #else #define LIB_EXPORT __declspec(dllimport) #endif #else #ifdef LIBPLCTAGDLL_EXPORTS #define LIB_EXPORT __attribute__ ((visibility ("default"))) #else #define LIB_EXPORT extern #endif #endif /* library internal status. */ #define PLCTAG_STATUS_PENDING (1) #define PLCTAG_STATUS_OK (0) #define PLCTAG_ERR_ABORT (-1) #define PLCTAG_ERR_BAD_CONFIG (-2) #define PLCTAG_ERR_BAD_CONNECTION (-3) #define PLCTAG_ERR_BAD_DATA (-4) #define PLCTAG_ERR_BAD_DEVICE (-5) #define PLCTAG_ERR_BAD_GATEWAY (-6) #define PLCTAG_ERR_BAD_PARAM (-7) #define PLCTAG_ERR_BAD_REPLY (-8) #define PLCTAG_ERR_BAD_STATUS (-9) #define PLCTAG_ERR_CLOSE (-10) #define PLCTAG_ERR_CREATE (-11) #define PLCTAG_ERR_DUPLICATE (-12) #define PLCTAG_ERR_ENCODE (-13) #define PLCTAG_ERR_MUTEX_DESTROY (-14) #define PLCTAG_ERR_MUTEX_INIT (-15) #define PLCTAG_ERR_MUTEX_LOCK (-16) #define PLCTAG_ERR_MUTEX_UNLOCK (-17) #define PLCTAG_ERR_NOT_ALLOWED (-18) #define PLCTAG_ERR_NOT_FOUND (-19) #define PLCTAG_ERR_NOT_IMPLEMENTED (-20) #define PLCTAG_ERR_NO_DATA (-21) #define PLCTAG_ERR_NO_MATCH (-22) #define PLCTAG_ERR_NO_MEM (-23) #define PLCTAG_ERR_NO_RESOURCES (-24) #define PLCTAG_ERR_NULL_PTR (-25) #define PLCTAG_ERR_OPEN (-26) #define PLCTAG_ERR_OUT_OF_BOUNDS (-27) #define PLCTAG_ERR_READ (-28) #define PLCTAG_ERR_REMOTE_ERR (-29) #define PLCTAG_ERR_THREAD_CREATE (-30) #define PLCTAG_ERR_THREAD_JOIN (-31) #define PLCTAG_ERR_TIMEOUT (-32) #define PLCTAG_ERR_TOO_LARGE (-33) #define PLCTAG_ERR_TOO_SMALL (-34) #define PLCTAG_ERR_UNSUPPORTED (-35) #define PLCTAG_ERR_WINSOCK (-36) #define PLCTAG_ERR_WRITE (-37) #define PLCTAG_ERR_PARTIAL (-38) #define PLCTAG_ERR_BUSY (-39) /* * helper function for errors. * * This takes one of the above errors and turns it into a const char * suitable * for printing. */ LIB_EXPORT const char *plc_tag_decode_error(int err); /* * Set the debug level. * * This function takes values from the defined debug levels below. It sets * the debug level to the passed value. Higher numbers output increasing amounts * of information. Input values not defined below will be ignored. */ #define PLCTAG_DEBUG_NONE (0) #define PLCTAG_DEBUG_ERROR (1) #define PLCTAG_DEBUG_WARN (2) #define PLCTAG_DEBUG_INFO (3) #define PLCTAG_DEBUG_DETAIL (4) #define PLCTAG_DEBUG_SPEW (5) LIB_EXPORT void plc_tag_set_debug_level(int debug_level); /* * Check that the library supports the required API version. * * The version is passed as integers. The three arguments are: * * ver_major - the major version of the library. This must be an exact match. * ver_minor - the minor version of the library. The library must have a minor * version greater than or equal to the requested version. * ver_patch - the patch version of the library. The library must have a patch * version greater than or equal to the requested version if the minor * version is the same as that requested. If the library minor version * is greater than that requested, any patch version will be accepted. * * PLCTAG_STATUS_OK is returned if the version is compatible. If it does not, * PLCTAG_ERR_UNSUPPORTED is returned. * * Examples: * * To match version 2.1.4, call plc_tag_check_lib_version(2, 1, 4). * */ LIB_EXPORT int plc_tag_check_lib_version(int req_major, int req_minor, int req_patch); /* * tag functions * * The following is the public API for tag operations. * * These are implemented in a protocol-specific manner. */ /* * plc_tag_create * * Create a new tag based on the passed attributed string. The attributes * are protocol-specific. The only required part of the string is the key- * value pair "protocol=XXX" where XXX is one of the supported protocol * types. * * Wait for timeout milliseconds for the tag to finish the creation process. * If this is zero, return immediately. The application program will need to * poll the tag status with plc_tag_status() while the status is PLCTAG_STATUS_PENDING * until the status changes to PLCTAG_STATUS_OK if the creation was successful or * another PLCTAG_ERR_xyz if it was not. * * An opaque handle is returned. If the value is greater than zero, then * the operation was a success. If the value is less than zero then the * tag was not created and the failure error is one of the PLCTAG_ERR_xyz * errors. */ LIB_EXPORT int32_t plc_tag_create(const char *attrib_str, int timeout); /* * plc_tag_create_ex * * As for plc_tag_create with the addition of a callback and user-supplied data pointer. * * The callback will be set as early as possible in the callback process. This allows sending * of early creation time events to user code. */ LIB_EXPORT int32_t plc_tag_create_ex(const char *attrib_str, void (*tag_callback_func)(int32_t tag_id, int event, int status, void *userdata), void *userdata, int timeout); /* * plc_tag_shutdown * * Some systems may not call the atexit() handlers. In those cases, wrappers should * call this function before unloading the library or terminating. Most OSes will cleanly * recover all system resources when a process is terminated and this will not be necessary. * * THIS IS NOT THREAD SAFE! Do not call this if you have multiple threads running against * the library. You have been warned. Close all tags first with plc_tag_destroy() and make * sure that nothing can call any library functions until this function returns. * * Normally you do not need to call this function. This is only for certain wrappers or * operating environments that use libraries in ways that prevent the normal exit handlers * from working. */ LIB_EXPORT void plc_tag_shutdown(void); /* * plc_tag_register_callback * * This function registers the passed callback function with the tag. Only one callback function * may be registered on a tag at a time! * * Once registered, any of the following operations on or in the tag will result in the callback * being called: * * * starting a tag read operation. * * a tag read operation ending. * * a tag read being aborted. * * starting a tag write operation. * * a tag write operation ending. * * a tag write being aborted. * * a tag being destroyed * * The callback is called outside of the internal tag mutex so it can call any tag functions safely. However, * the callback is called in the context of the internal tag helper thread and not the client library thread(s). * This means that YOU are responsible for making sure that all client application data structures the callback * function touches are safe to access by the callback! * * Do not do any operations in the callback that block for any significant time. This will cause library * performance to be poor or even to start failing! * * When the callback is called with the PLCTAG_EVENT_DESTROY_STARTED, do not call any tag functions. It is * not guaranteed that they will work and they will possibly hang or fail. * * Return values: * * If there is already a callback registered, the function will return PLCTAG_ERR_DUPLICATE. Only one callback * function may be registered at a time on each tag. * * If all is successful, the function will return PLCTAG_STATUS_OK. */ #define PLCTAG_EVENT_READ_STARTED (1) #define PLCTAG_EVENT_READ_COMPLETED (2) #define PLCTAG_EVENT_WRITE_STARTED (3) #define PLCTAG_EVENT_WRITE_COMPLETED (4) #define PLCTAG_EVENT_ABORTED (5) #define PLCTAG_EVENT_DESTROYED (6) #define PLCTAG_EVENT_CREATED (7) #define PLCTAG_EVENT_MAX (PLCTAG_EVENT_CREATED + 1) LIB_EXPORT int plc_tag_register_callback(int32_t tag_id, void (*tag_callback_func)(int32_t tag_id, int event, int status)); LIB_EXPORT int plc_tag_register_callback_ex(int32_t tag_id, void (*tag_callback_func)(int32_t tag_id, int event, int status, void *userdata), void *userdata); /* * plc_tag_unregister_callback * * This function removes the callback already registered on the tag. * * Return values: * * The function returns PLCTAG_STATUS_OK if there was a registered callback and removing it went well. * An error of PLCTAG_ERR_NOT_FOUND is returned if there was no registered callback. */ LIB_EXPORT int plc_tag_unregister_callback(int32_t tag_id); /* * plc_tag_register_logger * * This function registers the passed callback function with the library. Only one callback function * may be registered with the library at a time! * * Once registered, the function will be called with any logging message that is normally printed due * to the current log level setting. * * WARNING: the callback will usually be called when the internal tag API mutex is held. You cannot * call any tag functions within the callback! * * Return values: * * If there is already a callback registered, the function will return PLCTAG_ERR_DUPLICATE. Only one callback * function may be registered at a time on each tag. * * If all is successful, the function will return PLCTAG_STATUS_OK. */ LIB_EXPORT int plc_tag_register_logger(void (*log_callback_func)(int32_t tag_id, int debug_level, const char *message)); /* * plc_tag_unregister_logger * * This function removes the logger callback already registered for the library. * * Return values: * * The function returns PLCTAG_STATUS_OK if there was a registered callback and removing it went well. * An error of PLCTAG_ERR_NOT_FOUND is returned if there was no registered callback. */ LIB_EXPORT int plc_tag_unregister_logger(void); /* * plc_tag_lock * * Lock the tag against use by other threads. Because operations on a tag are * very much asynchronous, actions like getting and extracting the data from * a tag take more than one API call. If more than one thread is using the same tag, * then the internal state of the tag will get broken and you will probably experience * a crash. * * This should be used to initially lock a tag when starting operations with it * followed by a call to plc_tag_unlock when you have everything you need from the tag. */ LIB_EXPORT int plc_tag_lock(int32_t tag); /* * plc_tag_unlock * * The opposite action of plc_tag_unlock. This allows other threads to access the * tag. */ LIB_EXPORT int plc_tag_unlock(int32_t tag); /* * plc_tag_abort * * Abort any outstanding IO to the PLC. If there is something in flight, then * it is marked invalid. Note that this does not abort anything that might * be still processing in the report PLC. * * The status will be PLCTAG_STATUS_OK unless there is an error such as * a null pointer. * * This is a function provided by the underlying protocol implementation. */ LIB_EXPORT int plc_tag_abort(int32_t tag); /* * plc_tag_destroy * * This frees all resources associated with the tag. Internally, it may result in closed * connections etc. This calls through to a protocol-specific function. * * This is a function provided by the underlying protocol implementation. */ LIB_EXPORT int plc_tag_destroy(int32_t tag); /* * plc_tag_read * * Start a read. If the timeout value is zero, then wait until the read * returns or the timeout occurs, whichever is first. Return the status. * If the timeout value is zero, then plc_tag_read will normally return * PLCTAG_STATUS_PENDING. * * This is a function provided by the underlying protocol implementation. */ LIB_EXPORT int plc_tag_read(int32_t tag, int timeout); /* * plc_tag_status * * Return the current status of the tag. This will be PLCTAG_STATUS_PENDING if there is * an uncompleted IO operation. It will be PLCTAG_STATUS_OK if everything is fine. Other * errors will be returned as appropriate. * * This is a function provided by the underlying protocol implementation. */ LIB_EXPORT int plc_tag_status(int32_t tag); /* * plc_tag_write * * Start a write. If the timeout value is zero, then wait until the write * returns or the timeout occurs, whichever is first. Return the status. * If the timeout value is zero, then plc_tag_write will usually return * PLCTAG_STATUS_PENDING. The write is considered done * when it has been written to the socket. * * This is a function provided by the underlying protocol implementation. */ LIB_EXPORT int plc_tag_write(int32_t tag, int timeout); /* * Tag data accessors. */ LIB_EXPORT int plc_tag_get_int_attribute(int32_t tag, const char *attrib_name, int default_value); LIB_EXPORT int plc_tag_set_int_attribute(int32_t tag, const char *attrib_name, int new_value); LIB_EXPORT int plc_tag_get_size(int32_t tag); /* return the old size or negative for errors. */ LIB_EXPORT int plc_tag_set_size(int32_t tag, int new_size); LIB_EXPORT int plc_tag_get_bit(int32_t tag, int offset_bit); LIB_EXPORT int plc_tag_set_bit(int32_t tag, int offset_bit, int val); LIB_EXPORT uint64_t plc_tag_get_uint64(int32_t tag, int offset); LIB_EXPORT int plc_tag_set_uint64(int32_t tag, int offset, uint64_t val); LIB_EXPORT int64_t plc_tag_get_int64(int32_t tag, int offset); LIB_EXPORT int plc_tag_set_int64(int32_t, int offset, int64_t val); LIB_EXPORT uint32_t plc_tag_get_uint32(int32_t tag, int offset); LIB_EXPORT int plc_tag_set_uint32(int32_t tag, int offset, uint32_t val); LIB_EXPORT int32_t plc_tag_get_int32(int32_t tag, int offset); LIB_EXPORT int plc_tag_set_int32(int32_t, int offset, int32_t val); LIB_EXPORT uint16_t plc_tag_get_uint16(int32_t tag, int offset); LIB_EXPORT int plc_tag_set_uint16(int32_t tag, int offset, uint16_t val); LIB_EXPORT int16_t plc_tag_get_int16(int32_t tag, int offset); LIB_EXPORT int plc_tag_set_int16(int32_t, int offset, int16_t val); LIB_EXPORT uint8_t plc_tag_get_uint8(int32_t tag, int offset); LIB_EXPORT int plc_tag_set_uint8(int32_t tag, int offset, uint8_t val); LIB_EXPORT int8_t plc_tag_get_int8(int32_t tag, int offset); LIB_EXPORT int plc_tag_set_int8(int32_t, int offset, int8_t val); LIB_EXPORT double plc_tag_get_float64(int32_t tag, int offset); LIB_EXPORT int plc_tag_set_float64(int32_t tag, int offset, double val); LIB_EXPORT float plc_tag_get_float32(int32_t tag, int offset); LIB_EXPORT int plc_tag_set_float32(int32_t tag, int offset, float val); /* raw byte bulk access */ LIB_EXPORT int plc_tag_set_raw_bytes(int32_t id, int offset, uint8_t *buffer, int buffer_length); LIB_EXPORT int plc_tag_get_raw_bytes(int32_t id, int offset, uint8_t *buffer, int buffer_length); /* string accessors */ LIB_EXPORT int plc_tag_get_string(int32_t tag_id, int string_start_offset, char *buffer, int buffer_length); LIB_EXPORT int plc_tag_set_string(int32_t tag_id, int string_start_offset, const char *string_val); LIB_EXPORT int plc_tag_get_string_length(int32_t tag_id, int string_start_offset); LIB_EXPORT int plc_tag_get_string_capacity(int32_t tag_id, int string_start_offset); LIB_EXPORT int plc_tag_get_string_total_length(int32_t tag_id, int string_start_offset); #ifdef __cplusplus } #endif