modbus/mb_runtime.c
changeset 2479 7f08b03a5d92
parent 1909 bb883e063175
child 2480 8efa26af791d
child 2507 0f6dae98ddc5
equal deleted inserted replaced
1911:c1298e7ffe3a 2479:7f08b03a5d92
   289 	mb_slave_run(server_node->mb_nd /* nd */, callbacks, server_node->slave_id);
   289 	mb_slave_run(server_node->mb_nd /* nd */, callbacks, server_node->slave_id);
   290 	fprintf(stderr, "Modbus plugin: Modbus server for node %%s died unexpectedly!\n", server_node->location); /* should never occur */
   290 	fprintf(stderr, "Modbus plugin: Modbus server for node %%s died unexpectedly!\n", server_node->location); /* should never occur */
   291 	return NULL;
   291 	return NULL;
   292 }
   292 }
   293 
   293 
       
   294 
       
   295 #define timespec_add(ts, sec, nsec) {		\
       
   296 	ts.tv_sec  +=  sec;			\
       
   297 	ts.tv_nsec += nsec;			\
       
   298 	if (ts.tv_nsec >= 1000000000) {		\
       
   299 		ts.tv_sec  ++;			\
       
   300 		ts.tv_nsec -= 1000000000;	\
       
   301 	}					\
       
   302 }
   294 
   303 
   295 
   304 
   296 static void *__mb_client_thread(void *_index)  {
   305 static void *__mb_client_thread(void *_index)  {
   297 	int client_node_id = (char *)_index - (char *)NULL; // Use pointer arithmetic (more portable than cast)
   306 	int client_node_id = (char *)_index - (char *)NULL; // Use pointer arithmetic (more portable than cast)
   298 	struct timespec next_cycle;
   307 	struct timespec next_cycle;
   360 				break;
   369 				break;
   361 			  }
   370 			  }
   362 			}
   371 			}
   363 		}
   372 		}
   364 		// Determine absolute time instant for starting the next cycle
   373 		// Determine absolute time instant for starting the next cycle
   365 		// struct timespec prev_cycle;
   374 		struct timespec prev_cycle, now;
   366 		// prev_cycle = next_cycle;
   375 		prev_cycle = next_cycle;
   367 		next_cycle.tv_sec  += period_sec;
   376 		timespec_add(next_cycle, period_sec, period_nsec);
   368 		next_cycle.tv_nsec += period_nsec;
   377 		/* NOTE A:
   369 		if (next_cycle.tv_nsec >= 1000000000) {
   378 		 * When we have difficulty communicating with remote client and/or server, then the communications get delayed and we will
   370 			next_cycle.tv_sec  ++;
   379 		 * fall behind in the period. This means that when communication is re-established we may end up running this loop continuously
   371 			next_cycle.tv_nsec -= 1000000000;
   380 		 * for some time until we catch up.
   372 		}
   381 		 * This is undesirable, so we detect it by making sure the next_cycle will start in the future.
   373 		/* It probably does not make sense to check for overflow of timer.
   382 		 * When this happens we will switch from a purely periodic task _activation_ sequence, to a fixed task suspension interval.
       
   383 		 * 
       
   384 		 * NOTE B:
       
   385 		 * It probably does not make sense to check for overflow of timer.
   374 		 * Even in 32 bit systems this will take at least 68 years since the computer booted
   386 		 * Even in 32 bit systems this will take at least 68 years since the computer booted
   375 		 * (remember, we are using CLOCK_MONOTONIC, which should start counting from 0
   387 		 * (remember, we are using CLOCK_MONOTONIC, which should start counting from 0
   376 		 * every time the system boots). On 64 bit systems, it will take over 
   388 		 * every time the system boots). On 64 bit systems, it will take over 
   377 		 * 10^11 years to overflow.
   389 		 * 10^11 years to overflow.
   378 		 */
   390 		 */
   379 		/*
   391 		clock_gettime(CLOCK_MONOTONIC, &now);
   380 		if (next_cycle.tv_sec) < prev_cycle.tv_sec) {
   392 		if (  ((now.tv_sec > next_cycle.tv_sec) || ((now.tv_sec == next_cycle.tv_sec) && (now.tv_nsec > next_cycle.tv_nsec)))
   381 			// we will lose some precision by reading the time again, 
   393 		   /* We are falling behind. See NOTE A above */
   382 			// but it is better than the alternative...
   394 		   || (next_cycle.tv_sec < prev_cycle.tv_sec)
   383 			clock_gettime(CLOCK_MONOTONIC, &next_cycle);
   395 		   /* Timer overflow. See NOTE B above */
   384 			next_cycle.tv_sec  += period_sec;
   396 		   ) {
   385 			next_cycle.tv_nsec += period_nsec;
   397 			next_cycle = now;
   386 			if (next_cycle.tv_nsec >= 1000000000) {
   398 			timespec_add(next_cycle, period_sec, period_nsec);
   387 				next_cycle.tv_sec  ++;
   399 		}
   388 				next_cycle.tv_nsec -= 1000000000;
       
   389 			}
       
   390 		}
       
   391 		*/
       
   392 		clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next_cycle, NULL);
   400 		clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next_cycle, NULL);
   393 	}
   401 	}
   394 
   402 
   395 	// humour the compiler.
   403 	// humour the compiler.
   396 	return NULL;
   404 	return NULL;