Browse Source

Allow fractions of milliseconds for timed callback intervalls

Julius Pfrommer 6 years ago
parent
commit
5d72fb8462

+ 14 - 2
include/ua_client.h

@@ -475,16 +475,28 @@ __UA_Client_AsyncServiceEx(UA_Client *client, const void *request,
 
 typedef void (*UA_ClientCallback)(UA_Client *client, void *data);
 
+/* Add a callback for cyclic repetition to the client.
+ *
+ * @param client The client object.
+ * @param callback The callback that shall be added.
+ * @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_Client_addRepeatedCallback(UA_Client *client,
                               UA_ClientCallback callback,
-                              void *data, UA_UInt32 interval,
+                              void *data, UA_Double interval_ms,
                               UA_UInt64 *callbackId);
 
 UA_StatusCode
 UA_Client_changeRepeatedCallbackInterval(UA_Client *client,
                                          UA_UInt64 callbackId,
-                                         UA_UInt32 interval);
+                                         UA_Double interval_ms);
 
 UA_StatusCode UA_Client_removeRepeatedCallback(UA_Client *client,
                                                UA_UInt64 callbackId);

+ 11 - 10
include/ua_server.h

@@ -85,20 +85,21 @@ typedef void (*UA_ServerCallback)(UA_Server *server, void *data);
  *
  * @param server The server object.
  * @param callback The callback that shall be added.
- * @param interval The callback shall be repeatedly executed with the given interval
- *        (in ms). The interval must be larger than 5ms. The first execution
+ * @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. */
+ * @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_UInt32 interval, UA_UInt64 *callbackId);
+                              void *data, UA_Double interval_ms, UA_UInt64 *callbackId);
 
 UA_StatusCode UA_EXPORT
 UA_Server_changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId,
-                                         UA_UInt32 interval);
+                                         UA_Double interval_ms);
 
 /* Remove a repeated callback.
  *
@@ -516,8 +517,8 @@ UA_Server_unregister_discovery(UA_Server *server, struct UA_Client *client);
 UA_StatusCode UA_EXPORT
 UA_Server_addPeriodicServerRegisterCallback(UA_Server *server, struct UA_Client *client,
                                             const char* discoveryServerUrl,
-                                            UA_UInt32 intervalMs,
-                                            UA_UInt32 delayFirstRegisterMs,
+                                            UA_Double intervalMs,
+                                            UA_Double delayFirstRegisterMs,
                                             UA_UInt64 *periodicCallbackId);
 
 /* Callback for RegisterServer. Data is passed from the register call */

+ 8 - 2
src/client/ua_client.c

@@ -632,13 +632,19 @@ UA_Client_sendAsyncRequest(UA_Client *client, const void *request,
 
 UA_StatusCode
 UA_Client_addRepeatedCallback(UA_Client *client, UA_ClientCallback callback,
-                              void *data, UA_UInt32 interval,
+                              void *data, UA_Double interval_ms,
                               UA_UInt64 *callbackId) {
     return UA_Timer_addRepeatedCallback(&client->timer,
                                         (UA_ApplicationCallback) callback, client, data,
-                                        interval, callbackId);
+                                        interval_ms, callbackId);
 }
 
+UA_StatusCode
+UA_Client_changeRepeatedCallbackInterval(UA_Client *client, UA_UInt64 callbackId,
+                                         UA_Double interval_ms) {
+    return UA_Timer_changeRepeatedCallbackInterval(&client->timer, callbackId,
+                                                   interval_ms);
+}
 
 UA_StatusCode
 UA_Client_removeRepeatedCallback(UA_Client *client, UA_UInt64 callbackId) {

+ 1 - 1
src/client/ua_client_connect_async.c

@@ -608,7 +608,7 @@ UA_Client_connect_async(UA_Client *client, const char *endpointUrl,
         UA_LOG_TRACE(client->config.logger, UA_LOGCATEGORY_CLIENT,
                      "Adding async connection callback");
         retval = UA_Client_addRepeatedCallback(
-                     client, client->config.pollConnectionFunc, &client->connection, 100,
+                     client, client->config.pollConnectionFunc, &client->connection, 100.0,
                      &client->connection.connectCallbackID);
         if(retval != UA_STATUSCODE_GOOD)
             goto cleanup;

+ 1 - 1
src/pubsub/ua_pubsub.c

@@ -1154,7 +1154,7 @@ UA_StatusCode
 UA_WriterGroup_addPublishCallback(UA_Server *server, UA_WriterGroup *writerGroup) {
     UA_StatusCode retval =
             UA_PubSubManager_addRepeatedCallback(server, (UA_ServerCallback) UA_WriterGroup_publishCallback,
-                                                 writerGroup, (UA_UInt32) writerGroup->config.publishingInterval,
+                                                 writerGroup, writerGroup->config.publishingInterval,
                                                  &writerGroup->publishCallbackId);
     if(retval == UA_STATUSCODE_GOOD)
         writerGroup->publishCallbackIsRegistered = true;

+ 4 - 4
src/pubsub/ua_pubsub_manager.c

@@ -310,15 +310,15 @@ UA_PubSubManager_delete(UA_Server *server, UA_PubSubManager *pubSubManager) {
 /***********************************/
 UA_StatusCode
 UA_PubSubManager_addRepeatedCallback(UA_Server *server, UA_ServerCallback callback,
-                                     void *data, UA_UInt32 interval, UA_UInt64 *callbackId) {
+                                     void *data, UA_Double interval_ms, UA_UInt64 *callbackId) {
     return UA_Timer_addRepeatedCallback(&server->timer, (UA_ApplicationCallback)callback,
-                                        server, data, interval, callbackId);
+                                        server, data, interval_ms, callbackId);
 }
 
 UA_StatusCode
 UA_PubSubManager_changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId,
-                                                UA_UInt32 interval) {
-    return UA_Timer_changeRepeatedCallbackInterval(&server->timer, callbackId, interval);
+                                                UA_Double interval_ms) {
+    return UA_Timer_changeRepeatedCallbackInterval(&server->timer, callbackId, interval_ms);
 }
 
 UA_StatusCode

+ 2 - 2
src/pubsub/ua_pubsub_manager.h

@@ -37,10 +37,10 @@ UA_PubSubConfigurationVersionTimeDifference(void);
 /***********************************/
 UA_StatusCode
 UA_PubSubManager_addRepeatedCallback(UA_Server *server, UA_ServerCallback callback,
-                                     void *data, UA_UInt32 interval, UA_UInt64 *callbackId);
+                                     void *data, UA_Double interval_ms, UA_UInt64 *callbackId);
 UA_StatusCode
 UA_PubSubManager_changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId,
-                                                UA_UInt32 interval);
+                                                UA_Double interval_ms);
 UA_StatusCode
 UA_PubSubManager_removeRepeatedPubSubCallback(UA_Server *server, UA_UInt64 callbackId);
 

+ 7 - 6
src/server/ua_server.c

@@ -231,9 +231,9 @@ UA_Server_new(const UA_ServerConfig *config) {
     UA_SecureChannelManager_init(&server->secureChannelManager, server);
     UA_SessionManager_init(&server->sessionManager, server);
 
-    /* Add a regular callback for cleanup and maintenance */
+    /* Add a regular callback for cleanup and maintenance. With a 10s interval. */
     UA_Server_addRepeatedCallback(server, (UA_ServerCallback)UA_Server_cleanup, NULL,
-                                  10000, NULL);
+                                  10000.0, NULL);
 
     /* Initialized discovery */
 #ifdef UA_ENABLE_DISCOVERY
@@ -265,17 +265,18 @@ UA_Server_new(const UA_ServerConfig *config) {
 
 UA_StatusCode
 UA_Server_addRepeatedCallback(UA_Server *server, UA_ServerCallback callback,
-                              void *data, UA_UInt32 interval,
+                              void *data, UA_Double interval_ms,
                               UA_UInt64 *callbackId) {
     return UA_Timer_addRepeatedCallback(&server->timer,
                                         (UA_ApplicationCallback)callback,
-                                        server, data, interval, callbackId);
+                                        server, data, interval_ms, callbackId);
 }
 
 UA_StatusCode
 UA_Server_changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId,
-                                         UA_UInt32 interval) {
-    return UA_Timer_changeRepeatedCallbackInterval(&server->timer, callbackId, interval);
+                                         UA_Double interval_ms) {
+    return UA_Timer_changeRepeatedCallbackInterval(&server->timer, callbackId,
+                                                   interval_ms);
 }
 
 UA_StatusCode

+ 6 - 6
src/server/ua_services_discovery.c

@@ -550,8 +550,8 @@ void UA_Discovery_cleanupTimedOut(UA_Server *server, UA_DateTime nowMonotonic) {
 
 struct PeriodicServerRegisterCallback {
     UA_UInt64 id;
-    UA_UInt32 this_interval;
-    UA_UInt32 default_interval;
+    UA_Double this_interval;
+    UA_Double default_interval;
     UA_Boolean registered;
     UA_Client* client;
     const char* discovery_server_url;
@@ -608,7 +608,7 @@ periodicServerRegister(UA_Server *server, void *data) {
 
         /* If the server was previously registered, retry in one second,
          * else, double the previous interval */
-        UA_UInt32 nextInterval = 1000;
+        UA_Double nextInterval = 1000.0;
         if(!cb->registered)
             nextInterval = cb->this_interval * 2;
 
@@ -638,8 +638,8 @@ UA_StatusCode
 UA_Server_addPeriodicServerRegisterCallback(UA_Server *server,
                                             struct UA_Client *client,
                                             const char* discoveryServerUrl,
-                                            UA_UInt32 intervalMs,
-                                            UA_UInt32 delayFirstRegisterMs,
+                                            UA_Double intervalMs,
+                                            UA_Double delayFirstRegisterMs,
                                             UA_UInt64 *periodicCallbackId) {
 
     /* No valid server URL */
@@ -680,7 +680,7 @@ UA_Server_addPeriodicServerRegisterCallback(UA_Server *server,
     /* Start repeating a failed register after 1s, then increase the delay. Set
      * to 500ms, as the delay is doubled before changing the callback
      * interval.*/
-    cb->this_interval = 500;
+    cb->this_interval = 500.0;
     cb->default_interval = intervalMs;
     cb->registered = false;
     cb->client = client;

+ 1 - 1
src/server/ua_subscription_monitoreditem.c

@@ -367,7 +367,7 @@ UA_MonitoredItem_registerSampleCallback(UA_Server *server, UA_MonitoredItem *mon
 
     UA_StatusCode retval =
         UA_Server_addRepeatedCallback(server, (UA_ServerCallback)UA_MonitoredItem_sampleCallback,
-                                      mon, (UA_UInt32)mon->samplingInterval, &mon->sampleCallbackId);
+                                      mon, mon->samplingInterval, &mon->sampleCallbackId);
     if(retval == UA_STATUSCODE_GOOD)
         mon->sampleCallbackIsRegistered = true;
     return retval;

+ 8 - 8
src/ua_timer.c

@@ -90,14 +90,14 @@ dequeueChange(UA_Timer *t) {
  * correct place. So that the next execution takes place ät "nextTime". */
 UA_StatusCode
 UA_Timer_addRepeatedCallback(UA_Timer *t, UA_ApplicationCallback callback,
-                             void *application, void *data, UA_UInt32 interval,
+                             void *application, void *data, UA_Double interval_ms,
                              UA_UInt64 *callbackId) {
     /* A callback method needs to be present */
     if(!callback)
         return UA_STATUSCODE_BADINTERNALERROR;
 
-    /* The interval needs to be at least 5ms */
-    if(interval < 5)
+    /* The interval needs to be positive */
+    if(interval_ms <= 0.0)
         return UA_STATUSCODE_BADINTERNALERROR;
 
     /* Allocate the repeated callback structure */
@@ -107,7 +107,7 @@ UA_Timer_addRepeatedCallback(UA_Timer *t, UA_ApplicationCallback callback,
         return UA_STATUSCODE_BADOUTOFMEMORY;
 
     /* Set the repeated callback */
-    tc->interval = (UA_UInt64)interval * UA_DATETIME_MSEC;
+    tc->interval = (UA_UInt64)(interval_ms * UA_DATETIME_MSEC); /* in 100ns resolution */
     tc->id = ++t->idCounter;
     tc->callback = callback;
     tc->application = application;
@@ -160,9 +160,9 @@ addTimerCallbackEntry(UA_Timer *t, UA_TimerCallbackEntry * UA_RESTRICT tc) {
 
 UA_StatusCode
 UA_Timer_changeRepeatedCallbackInterval(UA_Timer *t, UA_UInt64 callbackId,
-                                        UA_UInt32 interval) {
-    /* The interval needs to be at least 5ms */
-    if(interval < 5)
+                                        UA_Double interval_ms) {
+    /* The interval needs to be positive */
+    if(interval_ms <= 0.0)
         return UA_STATUSCODE_BADINTERNALERROR;
 
     /* Allocate the repeated callback structure */
@@ -172,7 +172,7 @@ UA_Timer_changeRepeatedCallbackInterval(UA_Timer *t, UA_UInt64 callbackId,
         return UA_STATUSCODE_BADOUTOFMEMORY;
 
     /* Set the repeated callback */
-    tc->interval = (UA_UInt64)interval * UA_DATETIME_MSEC;
+    tc->interval = (UA_UInt64)(interval_ms * UA_DATETIME_MSEC); /* in 100ns resolution */
     tc->id = callbackId;
     tc->nextTime = UA_DateTime_nowMonotonic() + (UA_DateTime)tc->interval;
     tc->callback = (UA_ApplicationCallback)CHANGE_SENTINEL;

+ 2 - 2
src/ua_timer.h

@@ -52,13 +52,13 @@ void UA_Timer_init(UA_Timer *t);
  * with UA_Timer_process. */
 UA_StatusCode
 UA_Timer_addRepeatedCallback(UA_Timer *t, UA_ApplicationCallback callback, void *application,
-                             void *data, UA_UInt32 interval, UA_UInt64 *callbackId);
+                             void *data, UA_Double interval_ms, UA_UInt64 *callbackId);
 
 /* Change the callback interval. If this is called from within the callback. The
  * adjustment is made during the next _process call. */
 UA_StatusCode
 UA_Timer_changeRepeatedCallbackInterval(UA_Timer *t, UA_UInt64 callbackId,
-                                        UA_UInt32 interval);
+                                        UA_Double interval_ms);
 
 /* Remove a repated callback. Thread-safe, can be used in parallel and in
  * parallel with UA_Timer_process. */

+ 8 - 5
tests/server/check_services_subscriptions.c

@@ -739,11 +739,12 @@ START_TEST(Server_invalidPublishingInterval) {
 
     UA_CreateSubscriptionRequest_init(&request);
     request.publishingEnabled = true;
-    request.requestedPublishingInterval = 1; // Must be < 5
-printf("BOFFF1 %f\n", server->config.publishingIntervalLimits.min);
+    request.requestedPublishingInterval = -5.0; // Must be positive
     UA_CreateSubscriptionResponse_init(&response);
     Service_CreateSubscription(server, session, &request, &response);
-    ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_BADINTERNALERROR);
+    ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
+    ck_assert(response.revisedPublishingInterval ==
+              server->config.publishingIntervalLimits.min);
     UA_CreateSubscriptionResponse_deleteMembers(&response);
 
     server->config.publishingIntervalLimits.min = savedPublishingIntervalLimitsMin;
@@ -771,7 +772,7 @@ START_TEST(Server_invalidSamplingInterval) {
     item.monitoringMode = UA_MONITORINGMODE_REPORTING;
     UA_MonitoringParameters params;
     UA_MonitoringParameters_init(&params);
-    params.samplingInterval = 1; // Must be < 5
+    params.samplingInterval = -5.0; // Must be positive
     item.requestedParameters = params;
     request.itemsToCreateSize = 1;
     request.itemsToCreate = &item;
@@ -781,7 +782,9 @@ START_TEST(Server_invalidSamplingInterval) {
     Service_CreateMonitoredItems(server, session, &request, &response);
     ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
     ck_assert_uint_eq(response.resultsSize, 1);
-    ck_assert_uint_eq(response.results[0].statusCode, UA_STATUSCODE_BADINTERNALERROR);
+    ck_assert_uint_eq(response.results[0].statusCode, UA_STATUSCODE_GOOD);
+    ck_assert(response.results[0].revisedSamplingInterval ==
+              server->config.samplingIntervalLimits.min);
 
     UA_MonitoredItemCreateRequest_deleteMembers(&item);
     UA_CreateMonitoredItemsResponse_deleteMembers(&response);