open62541提供定时执行任务功能,这个功能很实用,在前面的文章中,有时我们想定时的去修改一些变量节点的值,都是开一个线程去做的,相对来说有点小麻烦。使用open62541自带的定时器就会简单很多。
下面来看下如何使用open62541提供定时功能。
首先要知道一些关于定时任务的简单知识,
也可以看下linux系统提供的api,促进理解,点击这里。
api分为Server端和Client端,如下,
/**
* Timed Callbacks
* --------------- */
typedef void (*UA_ServerCallback)(UA_Server *server, void *data);
/* Add a callback for execution at a specified time. If the indicated time lies
* in the past, then the callback is executed at the next iteration of the
* server's main loop.
*
* @param server The server object.
* @param callback The callback that shall be added.
* @param data Data that is forwarded to the callback.
* @param date The timestamp for the execution time.
* @param callbackId Set to the identifier of the repeated callback . This can
* be used to cancel the callback later on. If the pointer is null, the
* identifier is not set.
* @return Upon success, UA_STATUSCODE_GOOD is returned. An error code
* otherwise. */
UA_StatusCode UA_EXPORT
UA_Server_addTimedCallback(UA_Server *server, UA_ServerCallback callback,
void *data, UA_DateTime date, UA_UInt64 *callbackId);
/* Add a callback for cyclic repetition to the server.
*
* @param server The server object.
* @param callback The callback that shall be added.
* @param data Data that is forwarded to the callback.
* @param interval_ms The callback shall be repeatedly executed with the given
* interval (in ms). The interval must be positive. The first execution
* occurs at now() + interval at the latest.
* @param callbackId Set to the identifier of the repeated callback . This can
* be used to cancel the callback later on. If the pointer is null, the
* identifier is not set.
* @return Upon success, UA_STATUSCODE_GOOD is returned. An error code
* otherwise. */
UA_StatusCode UA_EXPORT
UA_Server_addRepeatedCallback(UA_Server *server, UA_ServerCallback callback,
void *data, UA_Double interval_ms, UA_UInt64 *callbackId);
UA_StatusCode UA_EXPORT
UA_Server_changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId,
UA_Double interval_ms);
/* Remove a repeated callback. Does nothing if the callback is not found.
*
1. @param server The server object.
2. @param callbackId The id of the callback */
void UA_EXPORT
UA_Server_removeCallback(UA_Server *server, UA_UInt64 callbackId);
简述:
/**
* Timed Callbacks
* ---------------
* Repeated callbacks can be attached to a client and will be executed in the
* defined interval. */
typedef void (*UA_ClientCallback)(UA_Client *client, void *data);
/* Add a callback for execution at a specified time. If the indicated time lies
* in the past, then the callback is executed at the next iteration of the
* server's main loop.
*
* @param client The client object.
* @param callback The callback that shall be added.
* @param data Data that is forwarded to the callback.
* @param date The timestamp for the execution time.
* @param callbackId Set to the identifier of the repeated callback . This can
* be used to cancel the callback later on. If the pointer is null, the
* identifier is not set.
* @return Upon success, UA_STATUSCODE_GOOD is returned. An error code
* otherwise. */
UA_StatusCode UA_EXPORT
UA_Client_addTimedCallback(UA_Client *client, UA_ClientCallback callback,
void *data, UA_DateTime date, UA_UInt64 *callbackId);
/* Add a callback for cyclic repetition to the client.
*
* @param client The client object.
* @param callback The callback that shall be added.
* @param data Data that is forwarded to the callback.
* @param interval_ms The callback shall be repeatedly executed with the given
* interval (in ms). The interval must be positive. The first execution
* occurs at now() + interval at the latest.
* @param callbackId Set to the identifier of the repeated callback . This can
* be used to cancel the callback later on. If the pointer is null, the
* identifier is not set.
* @return Upon success, UA_STATUSCODE_GOOD is returned. An error code
* otherwise. */
UA_StatusCode UA_EXPORT
UA_Client_addRepeatedCallback(UA_Client *client, UA_ClientCallback callback,
void *data, UA_Double interval_ms,
UA_UInt64 *callbackId);
UA_StatusCode UA_EXPORT
UA_Client_changeRepeatedCallbackInterval(UA_Client *client,
UA_UInt64 callbackId,
UA_Double interval_ms);
void UA_EXPORT
UA_Client_removeCallback(UA_Client *client, UA_UInt64 callbackId);
简述:
有了上节的知识,就可以开始写代码了。这里只以Server端为例,Client端的使用是一样的,不再赘述。
#include
#include
#include "open62541.h"
UA_Boolean running = true;
static void stopHandler(int sign)
{
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c");
running = false;
}
static void ctrlCallback(UA_Server *server, void *data)
{
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "ctrl callback");
UA_UInt64 callbackId = *(UA_UInt64*)data;
UA_Server_changeRepeatedCallbackInterval(server, callbackId, 5000); // change to every 5s
}
static void oneshotCallback(UA_Server *server, void *data)
{
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "oneshot callback");
}
static void cycleCallback(UA_Server *server, void *data)
{
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "cycle callback");
}
// expectedTime, 其单位是ms
static UA_DateTime convertToDateTime(UA_UInt64 expectedTime)
{
UA_UInt64 interval = (UA_UInt64)(expectedTime * UA_DATETIME_MSEC);
UA_DateTime nextTime = UA_DateTime_nowMonotonic() + (UA_DateTime)interval;
return nextTime;
}
int main(void)
{
signal(SIGINT, stopHandler);
signal(SIGTERM, stopHandler);
UA_StatusCode retval;
UA_Server *server = UA_Server_new();
UA_ServerConfig *config = UA_Server_getConfig(server);
UA_ServerConfig_setDefault(config);
UA_UInt64 callbackId = 0;
UA_Server_addRepeatedCallback(server, cycleCallback, NULL, 2000, &callbackId); // call every 2s
UA_DateTime nextTime = convertToDateTime(10000); // after 10s
UA_Server_addTimedCallback(server, ctrlCallback, &callbackId, nextTime, NULL);
nextTime = convertToDateTime(3000); // after 3s
UA_Server_addTimedCallback(server, oneshotCallback, NULL, nextTime, NULL);
retval = UA_Server_run(server, &running);
cleanup:
UA_Server_delete(server);
return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}
代码解释:
打印如下,
第一行是程序执行后打印的,可以看做是系统运行的起始时间点,以此为起点,后面的打印就是我们添加的定时任务,可以通过时间差观察其定时周期,还是比较准确的。
本文讲述如何使用open62541提供的定时功能去执行定时任务,还是比较容易理解的。需要注意的是UA_Server_addRepeatedCallback()和UA_Server_addTimedCallback()里的时间参数类型不一样,前者用的相对时间,后者用的是绝对时间。
如果有写的不对的地方,希望能留言指正,谢谢阅读。