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