Commit c64ea816 authored by Arnaud Blanchard's avatar Arnaud Blanchard
Browse files

Separated blc_command in a new blc_loop. Make systemticaly athread to listen...

Separated blc_command in a new blc_loop. Make systemticaly athread to listen to the input ( avoid to block the program)
parent 6c2c99b8
......@@ -16,7 +16,7 @@ project(${PROJECT_NAME})
find_package(blc_core REQUIRED)
#source files
set(sources src/blc_program.cpp src/blc_command.cpp)
set(sources src/blc_loop.cpp src/blc_program.cpp src/blc_command.cpp)
add_definitions(${BL_DEFINITIONS})
include_directories(include ${BL_INCLUDE_DIRS})
......@@ -29,15 +29,6 @@ target_link_libraries(${PROJECT_NAME} ${BL_LIBRARIES})
add_library(static_${PROJECT_NAME} STATIC ${sources})
#Both librairies have the same name only the extension will change.
set_target_properties(static_${PROJECT_NAME} PROPERTIES OUTPUT_NAME ${PROJECT_NAME})
#Add a target to generate documentation
find_package(Doxygen)
if(DOXYGEN_FOUND)
configure_file(${PROJECT_SOURCE_DIR}/doxyfile.in doxyfile.doxy) #Replace the CMAKE variables in the Doxyfile
add_custom_target(doc_${PROJECT_NAME} ${DOXYGEN_EXECUTABLE} doxyfile.doxy COMMENT "Generating API documentation for ${PROJECT_NAME}" VERBATIM)
else()
message("You need to install doxygen to generate the doc.")
endif()
#Describe what will be to install or in the package by default the prefix (CMAKE_INSTALL_PREFIX) is '/usr/’
install(DIRECTORY include/ DESTINATION include/${PROJECT_NAME})
......
PROJECT_NAME = ${PROJECT_NAME}
OUTPUT_DIRECTORY = ${PROJECT_SOURCE_DIR}
OPTIMIZE_OUTPUT_FOR_C = YES
EXTRACT_LOCAL_CLASSES = NO
HIDE_UNDOC_MEMBERS = YES
HIDE_UNDOC_CLASSES = YES
HIDE_FRIEND_COMPOUNDS = YES
HIDE_IN_BODY_DOCS = YES
CASE_SENSE_NAMES = NO
SORT_MEMBER_DOCS = NO
QUIET = YES
INPUT = ${PROJECT_SOURCE_DIR}
RECURSIVE = YES
USE_MDFILE_AS_MAINPAGE = ${PROJECT_SOURCE_DIR}/README.md
ALPHABETICAL_INDEX = NO
HTML_OUTPUT = doc/api
GENERATE_LATEX = NO
MACRO_EXPANSION = YES
PREDEFINED = __cplusplus = 1
REPEAT_BRIEF = YES
SKIP_FUNCTION_MACROS = NO
CLASS_DIAGRAMS = NO
SHOW_FILES = NO
......@@ -28,10 +28,6 @@ Few functions helping for pseudo realtime applications.
#include "blc_tools.h"
typedef enum {BLC_QUIT=0, BLC_RUN, BLC_PAUSE} type_blc_status;
extern int blc_input_terminal, blc_output_terminal;
extern type_blc_status blc_status;
#define BLC_COMMAND_LOOP_THREAD() for(blc_command_loop_init(-2); blc_command_loop_start();blc_command_loop_end())
......@@ -40,11 +36,25 @@ extern type_blc_status blc_status;
Warning the period can be till 10ms longer than, asked. Problem of usleep/nano sleep */
#define BLC_COMMAND_LOOP(period) for(blc_command_loop_init(period); blc_command_loop_start();blc_command_loop_end())
typedef void (*type_blc_command_cb)(char const *arguement, void *user_data);
typedef enum {BLC_QUIT=0, BLC_RUN, BLC_PAUSE} type_blc_status;
typedef void (*type_blc_command_cb)(char const *arguement, void *user_data);
extern int blc_input_terminal, blc_output_terminal;
extern type_blc_status blc_status;
extern int blc_loop_iteration;
extern long blc_command_loop_period;
START_EXTERN_C
//void * to not need to include "semaphore.h"
void blc_loop_sem_to_unlock_on_stop(void *sem);
void blc_command_ask_quit();
void pause_cb();
///Add a command in the list of possible command lines from the user.
void blc_command_add(const char *command_name, type_blc_command_cb callback, const char *prompt, const char *help, void *user_data);
......
......@@ -49,18 +49,51 @@ typedef struct
void *user_data;
}blc_command;
// Static means it is only existing in this file
static blc_command *blc_commands = NULL;
static int blc_commands_nb = 0;
static struct timeval timer;
static int iterations_nb=0;
static uint blc_period=0;
static uint blc_duration=0;
static long blc_current_duration;
long blc_command_loop_period;
static sem_t *sems_to_unlock=NULL;
static int sems_to_unlock_nb=0;
void pause_cb()
{
if (blc_status==BLC_RUN){
blc_status=BLC_PAUSE;
fprintf(stderr, "=== %s: pause ===\n", blc_program_name);
blc_command_interpret();
}else {
fprintf(stderr, "=== %s: running ===\n", blc_program_name);
blc_status=BLC_RUN;
}
}
void blc_loop_sem_to_unlock_on_stop(void *sem){
APPEND_ITEM(&sems_to_unlock, &sems_to_unlock_nb, &sem);
}
void blc_command_ask_quit(){
sem_t *sem;
blc_status=BLC_QUIT;
FOR_EACH(sem, sems_to_unlock, sems_to_unlock_nb ){
while (sem_trywait(sem)!=0){
if (errno==EAGAIN) sem_post(sem);
else EXIT_ON_SYSTEM_ERROR("unlocking semaphore");
}
sem_post(sem);
}
if (blc_command_loop_period==-2){ //thread
sleep(10);
fprintf(stderr, "=== %s: error program not quitting ! We force it. ===\n", blc_program_name);
exit(EXIT_FAILURE);
}
}
type_blc_status blc_status=BLC_RUN;
START_EXTERN_C
......@@ -84,40 +117,6 @@ void blc_command_display_help()
}
}
void blc_fprint_stats(FILE *file)
{
fprintf(file, "%d iterations, average duration: %.3fms, average frequency: %.3fHz period: %.3fms\n", iterations_nb, blc_duration/(1000.*iterations_nb), 1000000.*iterations_nb/(double)blc_period, blc_period/(1000.*iterations_nb));
iterations_nb=0;
blc_period=0;
blc_duration=0;
us_time_diff(&timer);
}
static void pause_cb()
{
if (blc_status==BLC_RUN){
blc_status=BLC_PAUSE;
fprintf(stderr, "=== %s: pause ===\n", blc_program_name);
blc_command_interpret();
}else {
fprintf(stderr, "=== %s: running ===\n", blc_program_name);
blc_status=BLC_RUN;
}
}
static void blc_command_ask_quit(){
blc_status=BLC_QUIT;
if (blc_command_loop_period==-2){ //thread
sleep(3);
fprintf(stderr, "=== %s: error program not quitting ! We force it. ===\n", blc_program_name);
exit(EXIT_FAILURE);
}
}
static void display_stats()
{
blc_fprint_stats(stderr);
}
void blc_command_add(const char *command_name, type_blc_command_cb callback, const char *prompt, const char *help, void *user_data){
blc_command tmp_command;
......@@ -181,17 +180,18 @@ static void blc_command_interpret_block(){
size_t line_capability=0;
ssize_t line_size;
//We do not consider error if it was an interruption. @TODO check wether the content of lin is correct.
do{
line_size = getline(&line, &line_capability, stdin);
}while ((line_size==-1) && (errno==EINTR));
if (line_size==-1)
{
if ((errno==0) || (errno==ETIMEDOUT)) {
free(line);
if ((errno==0) || (errno==ETIMEDOUT) || (errno==EINVAL)) {
if (line) FREE(line);
blc_command_ask_quit(); //stdin closed
}
else EXIT_ON_SYSTEM_ERROR("Command interpret: getline");
else EXIT_ON_SYSTEM_ERROR("getline(&line, &line_capability, stdin)");
}
else{
line_size=line_size-1;
......@@ -199,6 +199,7 @@ static void blc_command_interpret_block(){
blc_command_interpret_string(line, line_size);
}
FREE(line);
}
void blc_command_interpret(){
......@@ -246,56 +247,11 @@ void blc_command_interpret_thread(char const *option, void (*ask_quit_funcion)()
if (ask_quit_funcion==NULL) ask_quit_funcion=blc_command_ask_quit;
blc_command_loop_period=-2;
if (strchr(option, 'h')) blc_command_add("h", (type_blc_command_cb)blc_command_display_help, NULL, "display this help", NULL);
if (strchr(option, 'q')) blc_command_add("q", (type_blc_command_cb)ask_quit_funcion, NULL, "quit the application", NULL);
// if (strchr(option, 'h')) blc_command_add("h", (type_blc_command_cb)blc_command_display_help, NULL, "display this help", NULL);
// if (strchr(option, 'q')) blc_command_add("q", (type_blc_command_cb)ask_quit_funcion, NULL, "quit the application", NULL);
SYSTEM_ERROR_CHECK(pthread_create(&thread, NULL, command_thread_interpret_loop, NULL), -1, NULL);
}
void blc_command_loop_init(long loop_period)
{
iterations_nb=0;
blc_command_loop_period=loop_period;
if (blc_input_terminal && (blc_command_loop_period!=-1) && (blc_command_loop_period!=-2)) blc_command_add("", (type_blc_command_cb)pause_cb, NULL, "set on/off pause", NULL);
if (blc_command_loop_period!=-2){
blc_command_add("h", (type_blc_command_cb)blc_command_display_help, NULL, "display this help", NULL);
blc_command_add("q", (type_blc_command_cb)blc_command_ask_quit, NULL, "quit the application", NULL);
}
if (blc_command_loop_period!=-1) blc_command_add("s", (type_blc_command_cb)display_stats, NULL, "display time stats", NULL);
if (blc_input_terminal) blc_command_display_help();
if (blc_command_loop_period!=-1) fprintf(stderr, "=== %s: running ===\n", blc_program_name);
if (blc_command_loop_period==-2) blc_command_interpret_thread("hq", NULL);
}
int blc_command_loop_start(){
if (iterations_nb==0) us_time_diff(&timer);
else blc_period+=blc_current_duration+us_time_diff(&timer);
switch (blc_command_loop_period){
case -1: blc_command_interpret();break;
case -2:break;
default:blc_command_try_to_interpret();
}
return blc_status;
}
void blc_command_loop_end(){
struct timespec time_left={0,0};
blc_current_duration=us_time_diff(&timer);
blc_duration+=blc_current_duration;
if (blc_command_loop_period > 0){
time_left.tv_nsec = (blc_command_loop_period - blc_current_duration)*1000;
if (time_left.tv_nsec < 0) color_fprintf(BLC_YELLOW, stderr, "\rMissing %.3fms in the BLC_COMMAND_LOOP", -time_left.tv_nsec/1000000.f);
else SYSTEM_SUCCESS_CHECK(nanosleep(&time_left, NULL), 0, "Program loop interrupted. Time left %ldµs", time_left.tv_nsec/1000.f);
/* Warning the nanosleep can be overtimed of 10ms !!! it is the same for usleep !! */
}
iterations_nb++;
}
void blc_command_update_int_cb(char const *argument, void *int_pt){
char *endptr;
int value;
......
#include "blc_command.h"
#include "blc_realtime.h"
#include <unistd.h> //sleep
#include <errno.h> //errno
#include <time.h> //nanosleep
#include <sys/time.h> //gettimeofday
static struct timeval timer;
static uint blc_period=0;
static uint blc_duration=0;
static uint blc_duration_min=UINT_MAX, blc_duration_max=0;
static long blc_current_duration;
static int intermediate_iteration;
long blc_command_loop_period;
int blc_loop_iteration;
#include "blc_program.h"
type_blc_status blc_status=BLC_RUN;
void blc_fprint_stats(FILE *file)
{
fprintf(file, "%d iterations, average duration: %.3fms [%.3f, %.3f], average frequency: %.3fHz period: %.3fms\n", intermediate_iteration, blc_duration/(1000.f*intermediate_iteration), blc_duration_min/1000., blc_duration_max/1000., 1e6*intermediate_iteration/(double)blc_period, blc_period/(1000.*intermediate_iteration));
intermediate_iteration=0;
blc_period=0;
blc_duration=0;
blc_duration_min=UINT_MAX;
blc_duration_max=0;
gettimeofday(&timer, NULL);
}
static void display_stats(){
blc_fprint_stats(stderr);
}
void blc_command_loop_init(long loop_period)
{
blc_loop_iteration=0;
intermediate_iteration=0;
blc_command_loop_period=loop_period;
if (blc_input_terminal && (blc_command_loop_period!=-1) && (blc_command_loop_period!=-2)) blc_command_add("", (type_blc_command_cb)pause_cb, NULL, "set on/off pause", NULL);
if (blc_command_loop_period!=-2){
blc_command_add("h", (type_blc_command_cb)blc_command_display_help, NULL, "display this help", NULL);
blc_command_add("q", (type_blc_command_cb)blc_command_ask_quit, NULL, "quit the application", NULL);
}
if (blc_command_loop_period!=-1) blc_command_add("s", (type_blc_command_cb)display_stats, NULL, "display time stats", NULL);
if (blc_input_terminal) blc_command_display_help();
/* if (blc_command_loop_period!=-1)
if (blc_command_loop_period==-2);*/
fprintf(stderr, "=== %s: running ===\n", blc_program_name);
blc_command_interpret_thread("hq", NULL);
}
int blc_command_loop_start(){
if (intermediate_iteration==0) blc_us_time_diff(&timer);
else blc_period+=blc_current_duration+blc_us_time_diff(&timer);
switch (blc_command_loop_period){
case -1: blc_command_interpret();break;
case -2: break;
default:;//blc_command_try_to_interpret();
}
return blc_status;
}
void blc_command_loop_end(){
div_t ratio;
struct timespec time_left;
int diff;
blc_current_duration=blc_us_time_diff(&timer);
blc_duration+=blc_current_duration;
if (blc_duration<blc_duration_min) blc_duration_min=blc_duration;
else if (blc_duration > blc_duration_max) blc_duration_max=blc_duration;
if (blc_command_loop_period > 0){
diff=blc_command_loop_period - blc_current_duration;
ratio=div(diff, 1e6);
time_left.tv_sec = ratio.quot;
time_left.tv_nsec = ratio.rem*1e9;
if (diff < 0) color_fprintf(BLC_YELLOW, stderr, "\rMissing %.3fms in the BLC_COMMAND_LOOP", diff/1000.f);
else SYSTEM_ERROR_RETRY_ON_SPECIFIC_ERRNO(nanosleep(&time_left, &time_left), 0, EINTR, "Time left %.3fms", time_left.tv_nsec/1e6f + time_left.tv_sec*1000);
/* Warning the nanosleep can be overtimed of 10ms !!! it is the same for usleep !! */
}
intermediate_iteration++;
blc_loop_iteration++;
}
......@@ -85,7 +85,6 @@ static int blc_program_options_nb=0;
static struct program_parameter *blc_program_parameters=NULL;
static int blc_program_parameters_nb;
int blc_input_terminal, blc_output_terminal;
......@@ -306,7 +305,7 @@ void blc_program_option_interpret(int *argc, char **argv[])
if ((i+optind)>=(*argc)){//There is no more argument to interpret
if (blc_program_parameters[i].required_nb){
if (isatty(STDIN_FILENO)) fprintf(stderr, "%s: %s? ", blc_program_parameters[i].help, blc_program_parameters[i].name);
SYSTEM_ERROR_CHECK(parameter_read=getline(&tmp_parameter, &linecap, stdin), -1, "Reading input for parameter"); //getline(blc_program_parameters[i].string_pt, sizeof(blc_program_parameters[i].string_pt), stdin), NULL, "Wrong channel input name");
SYSTEM_ERROR_CHECK(parameter_read=getline(&tmp_parameter, &linecap, stdin), -1, "Reading input for parameter");
tmp_parameter[parameter_read-1]=0;//Remove the last return;
(*blc_program_parameters[i].string_pt)=tmp_parameter;
linecap=0;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment