Compare commits

...

3 Commits

Author SHA1 Message Date
Jean Sirmai 74894b5253
rtfm/intro Manual Introduction - a first version.
The same text is presented in two formats: for an external text editor (.txt)
or with lines limited to 80 characters.

The links are prepared but not functionnal.
2024-11-10 19:55:24 +01:00
Jean Sirmai 4d97b5328e
src/fsm/control.c fsm_init() and fsm_close() can be now triggered from main().
These two functions (defined in control.c) initiate the log and print it just
before the end of the program.
It is now possible to send messages that reports the events occuring during a
session: the creation of the log, then of the application and their closure in
the reverse order.
As previously,there is no g signal connect (activate) and no window is created.
This triggers the same error message in the console.
What is new, in this commit, is that a first log is printed in the console.
2024-11-09 08:03:55 +01:00
Jean Sirmai 4ce6443e39
/src/fsm/log/* adds the three files:
- manager.c,
- oper.c and
- appendix.c

and the functions needed to init, edit and publish the log.

fsm_add_log() is in manager.c  There are the filters.

init(), add(), publish() are in oper.c
                   These are the executive functions.

and functions whose usefulness remains to be demonstrated
are in appendix.

In fsm.h remain the structures (fsm_log_struct, fsm_log_struct_unit)
and the two enums (severity and source)
2024-11-08 19:56:07 +01:00
11 changed files with 934 additions and 160 deletions

View File

@ -403,7 +403,7 @@ MARKDOWN_ID_STYLE = DOXYGEN
# globally by setting AUTOLINK_SUPPORT to NO. # globally by setting AUTOLINK_SUPPORT to NO.
# The default value is: YES. # The default value is: YES.
AUTOLINK_SUPPORT = YES AUTOLINK_SUPPORT = NO
# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
# to include (a tag file for) the STL sources as input, then you should set this # to include (a tag file for) the STL sources as input, then you should set this
@ -565,7 +565,7 @@ EXTRACT_PACKAGE = NO
# included in the documentation. # included in the documentation.
# The default value is: NO. # The default value is: NO.
EXTRACT_STATIC = NO EXTRACT_STATIC = YES
# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined # If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
# locally in source files will be included in the documentation. If set to NO, # locally in source files will be included in the documentation. If set to NO,
@ -573,7 +573,7 @@ EXTRACT_STATIC = NO
# for Java sources. # for Java sources.
# The default value is: YES. # The default value is: YES.
EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_CLASSES = NO
# This flag is only useful for Objective-C code. If set to YES, local methods, # This flag is only useful for Objective-C code. If set to YES, local methods,
# which are defined in the implementation section but not in the interface are # which are defined in the implementation section but not in the interface are
@ -614,7 +614,7 @@ HIDE_UNDOC_MEMBERS = NO
# if EXTRACT_ALL is enabled. # if EXTRACT_ALL is enabled.
# The default value is: NO. # The default value is: NO.
HIDE_UNDOC_CLASSES = NO HIDE_UNDOC_CLASSES = YES
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
# declarations. If set to NO, these declarations will be included in the # declarations. If set to NO, these declarations will be included in the

View File

@ -24,7 +24,8 @@
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
This dossier gives you information on how to make the best use of doc.
(a few tips for personalising it)
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

View File

@ -1,34 +0,0 @@
Welcome to Gem-graph !
Gem-graph lets you move or transform drawn objects and can be used in all cases where drawings, designs or patterns are useful. You can draw anything you like. You can make it move or transform as you like. It is your design and you decide how you want it to evolve! You can use it to make a game. You can use it to make an animated representation (a model) of a phenomenon that interests you. You can represent what you want simply or in more realistic detail. Simple parts and more detailed parts can coexist in the same design. You can watch what you have created evolve without interfering or guiding it towards what you want to achieve. You can observe it in detail, go back, start again, measure, compare and keep the results that interest you so that you can play them again.
However, a certain amount of effort may be required to achieve the desired results. A complicated model will require more work than a simpler one, but it is possible to start with something simple and develop it step by step. In any case, you must draw what you want to see and say how you want it to move. Gem-graph cannot do that for you. Gem-graph can only help you to draw up and develop your idea. However, it can give you powerful tools to do so. All this is possible because the drawings that gem-graph manipulates are made up of very simple elements, all similar, driven by simple rules that can therefore be processed automatically. The tools provided by gem-graph give you access to the power of the automaton it uses to draw and animate your drawings, and this manual is here to help you to learn how to master them.
One way of doing this is to reproduce a very simple example, such as when a word processing program asks you to write "Hello world". For gem-graph, the equivalent of "Hello world" will be to move a small line on your screen. Once you have done this simple example, you will know enough to quickly build and animate much more complex drawings that suit your desires. If you like learning this way, this example is explained (here). If you prefer to learn by reading what the commands you see on the screen are doing, they have been detailed (here). The table of contents goes from the simplest to the most complicated. How to set up a simple model, observe it and measure what it does, then transform it by changing what you see and how it reacts.
------------
Our "Hello world" is the simplest program that gem-graph can execute. It consists of a single short arrow, which moves in a straight line in a single direction. To do this, we first had to draw this little arrow and then make it move. The result is certainly not very exciting, but this example is enough to show how a drawing is made and how it is animated. One state and one rule are enough. The rule only says: if an arrow is drawn here, I erase it and redraw it on the next square. For the moment, you don't need to know in detail how the rule works (it's described here). All that gem-graph needs to know is written in the "Hello world" file (here). If you open this file, you'll find a description of the arrow (here) and its movement (here).
------------
To improve this model, it is possible to give the arrow the ability to move in two directions: forwards or backwards. To do this, we need to add a second rule. This second rule says: if an arrow is drawn here, I erase it and redraw it on the previous square. A random draw (described here) is also necessary to determine whether the first or second rule applies. With these two rules and the random draw, the arrow now sometimes goes forwards, sometimes backwards. We can call this second model a "random walk".
------------
The second model (the random walk) had one state (the arrow) and two rules (forward/backward). Now here's a model with two states and two rules: the pendulum. This time, the arrow can be drawn either tilted forwards or tilted backwards (these are the two possible states) and the two rules switch the drawn arrow from one state to the other or vice versa. In the file, the states are (here) and the rules (here). The pendulum does not change place, but alternates between left and right. Like the previous ones, the programme is slowed down so that you can see the movements.
------------
Once you know how to write a state and a rule, you can write thousands of them: they will always be combinations of the same elementary form. However, it is also possible to combine programs: for example, you can combine the reports and rules from the two previous models to create a new model that shows both phenomena simultaneously. Once again, in the file, the states are (here) and the rules (here).
------------
A final simple example shows how a single rule can be applied to a multitude of states. The rule is the same as for the first model: an arrow can only be moved one square forward, but this time you have to check that the square forward is free. If it isn't, the arrow won't move. And this time, the space contains a multitude of arrows that have been randomly placed all over the place (see details here).
When you open this model, you see a multitude of small lines, all similar, some vertical, some horizontal, placed on a grid. When you set the model in motion, you see these little lines moving from left to right if they are horizontal, and up and down if they are vertical (a second rule vas added to do that). Their number is constant. They don't change shape or direction. There seems to be no accident when they cross. Nothing else happens.
------------
These five examples give an initial idea of the diversity of possible models and the operations that can be performed on them.

143
docs/rtfm/intro 80 char Normal file
View File

@ -0,0 +1,143 @@
Welcome to Gem-graph !
Gem-graph lets you move and transform drawn objects using an automaton. It's an
ideal tool for describing the evolution of a situation through drawing. Would
you like to see your drawings evolve automatically to represent a phenomenon?
Gem-graph lets you transform your drawings as you wish. You can draw whatever
you want. It's your drawing and you decide how it evolves! You can use gem-graph
to make a game. You can use it to make a model of a phenomenon that interests you.
You can represent what you want simply or in more realistic detail.
Simple parts and more detailed parts can coexist in the same design. You can
watch what you have created evolve without interfering or guiding it towards what
you want to achieve. You can mix several drawings and animations. You can observe
them in detail, modify them, go back, start again, measure, compare and keep the
results that interest you so that you can play them again.
However, a certain amount of effort will be required to achieve this. A complicated
model will require more work than a simpler one, but it is possible to start with
something simple and develop it step by step. In any case, you must draw what you
want to see and say how you want it to be transformed. Gem-graph cannot do that
for you. Gem-graph can only help you to draw up and develop your idea. However,
it can give you powerful tools to do so. The strength of gem-graph - short for
'geometric graph' - lies in the fact that it deals only with very simple drawing
elements, all of which are similar, and that the rules it uses to manipulate these
elements are equally simple and similar. As a result, these rules can be combined
and processed automatically, no matter how many there are. The tools provided by
gem-graph give you access to the power of the automaton it uses to draw and animate
your drawings, and this manual is here to help you to learn how to master them.
One way of doing this is to reproduce a very simple example, such as when a word
processing program asks you to write "Hello world". For gem-graph, the equivalent
of "Hello world" will be to move a small line on your screen. Once you have done
this simple example, you will know enough to quickly build and animate much more
complex drawings that suit your desires. If you like learning this way, this
example is explained (here). If you prefer to learn by reading what the commands
you see on the screen are doing, they have been detailed (here). The table of
contents goes from the simplest to the most complicated. How to set up a simple
model, observe it and measure what it does, then transform it by changing what
you see and how it reacts.
------------
Our "Hello world" is the simplest program that gem-graph can execute. It consists
of a single short arrow, which moves in a straight line in a single direction.
To do this, we first had to draw this little arrow and then make it move. The
result is certainly not very exciting, but this example is enough to show how a
drawing is made and how it is animated. One state and one rule are enough. The
rule only says: if an arrow is drawn here, I erase it and redraw it on the next
square. For the moment, you don't need to know in detail how the rule works
(it's described here). All that gem-graph needs to know is written in the
"Hello world" file (here). If you open this file, you'll find a description of
the arrow (here) and its movement (there).
------------
To improve this model, it is possible to give the arrow the ability to move in
two directions: forwards or backwards. To do this, we need to add a second rule.
This second rule says: if an arrow is drawn here, I erase it and redraw it on the
previous square. A random draw (described here) is also necessary to determine
whether the first or second rule applies. With these two rules and the random
draw, the arrow now sometimes goes forwards, sometimes backwards. We can call
this second model a "random walk".
------------
The second model (the random walk) had one state (the arrow) and two rules
(forward/backward). Now here's a model with two states and two rules:
the pendulum. This time, the arrow can be drawn either tilted forwards or tilted
backwards (these are the two possible states) and the two rules switch the drawn
arrow from one state to the other or vice versa. In the file, the states are (here)
and the rules (here). The pendulum does not change place, but alternates between
left and right. Like the previous ones, you can slow down the programme so that
you can observe the movements.
------------
Once you know how to write a state and a rule, you can write thousands of them:
they will always be combinations of the same elementary form. However, it is also
possible to combine programs: for example, you can combine the reports and rules
from the two previous models to create a new model that shows both phenomena
simultaneously. Once again, in the file, the states are (here) and the rules
(here).
------------
The next example shows how the same rule can be applied to a multitude of states.
The rule is the same as that used in the first model: an arrow can only be moved
one square forward, but this time you have to check that the square forward is
free. If it isn't, the arrow won't move. Once the rule has been modified in this
way, it can be applied to a multitude of arrows distributed randomly in space
(see details here).
When you set the model in motion, you will see all these small lines moving from
left to right. A single rule is responsible for all these movements.
For a small fee, we can apply the two rules of the 'random walk' model to all the
arrows distributed in this space, and they will then all behave in the same way,
sometimes moving forwards, sometimes backwards.
------------
In the next example, we first build a model similar to the previous one: a
multitude of arrows are randomly distributed in space, but this time they are
vertical and the movements are up and down instead of right and left. Then, we
add this model to the previous state and set the final model in motion. We see
then little lines moving from left to right or reverse if they are horizontal,
and up and down or reverse if they are vertical. Their number is constant. They
don't change shape or direction. There seems to be no accident when they cross.
Nothing else happens.
------------
The last example in this series, because it shows a multitude of diverse and
simultaneous movements, perhaps gives the impression of a more complex system.
It would be easy to make it even more complex, but it's much more interesting
to show how gem-graph can be used to analyse and control that complexity (here). At
this point, it's time to compare gem-graph to other classes of automata that do
quite similar things, and to look at what it can actually do and what its
limitations are.
------------
The main difference between gem-graph models and agent-based models is that
gem-graph deals with situations, not agents. In a situation where several agents
are interacting and each agent could apply a different rule, gem-graph considers
and processes the situation. Not the agents. Whatever the state - the new
situation - that results from his action, his decision-making process will have
been simple and straightforward. It will therefore be easy to modify and control.
And the diversity of possible new situations will be far greater than that
offered by agent-based models.
------------
The comparison between gem-graphs and cellular automata first comes up against
a question of vocabulary. What is commonly called a 'rule' in one and the other
is not the same thing. Gem-graphs and cellular automata have the same power:
anything that can be done by one can be done by the other, but their writing is
not the same (details of this comparison here).
------------
How can gem-graph be used to analyse and control the complexity of what it
represents and sets in motion? This chapter introduces the gem-graph mechanism.

51
docs/rtfm/intro.txt Normal file
View File

@ -0,0 +1,51 @@
Welcome to Gem-graph !
Gem-graph lets you move and transform drawn objects using an automaton. It's an ideal tool for describing the evolution of a situation through drawing. Would you like to see your drawings evolve automatically to represent a phenomenon? Gem-graph lets you transform your drawings as you wish. You can draw whatever you want. It's your drawing and you decide how it evolves! You can use gem-graph to make a game. You can use it to make a model of a phenomenon that interests you. You can represent what you want simply or in more realistic detail. Simple parts and more detailed parts can coexist in the same design. You can watch what you have created evolve without interfering or guiding it towards what you want to achieve. You can mix several drawings and animations. You can observe them in detail, modify them, go back, start again, measure, compare and keep the results that interest you so that you can play them again.
However, a certain amount of effort will be required to achieve this. A complicated model will require more work than a simpler one, but it is possible to start with something simple and develop it step by step. In any case, you must draw what you want to see and say how you want it to be transformed. Gem-graph cannot do that for you. Gem-graph can only help you to draw up and develop your idea. However, it can give you powerful tools to do so. The strength of gem-graph - short for 'geometric graph' - lies in the fact that it deals only with very simple drawing elements, all of which are similar, and that the rules it uses to manipulate these elements are equally simple and similar. As a result, these rules can be combined and processed automatically, no matter how many there are. The tools provided by gem-graph give you access to the power of the automaton it uses to draw and animate your drawings, and this manual is here to help you to learn how to master them.
One way of doing this is to reproduce a very simple example, such as when a word processing program asks you to write "Hello world". For gem-graph, the equivalent of "Hello world" will be to move a small line on your screen. Once you have done this simple example, you will know enough to quickly build and animate much more complex drawings that suit your desires. If you like learning this way, this example is explained (here). If you prefer to learn by reading what the commands you see on the screen are doing, they have been detailed (here). The table of contents goes from the simplest to the most complicated. How to set up a simple model, observe it and measure what it does, then transform it by changing what you see and how it reacts.
------------
Our "Hello world" is the simplest program that gem-graph can execute. It consists of a single short arrow, which moves in a straight line in a single direction. To do this, we first had to draw this little arrow and then make it move. The result is certainly not very exciting, but this example is enough to show how a drawing is made and how it is animated. One state and one rule are enough. The rule only says: if an arrow is drawn here, I erase it and redraw it on the next square. For the moment, you don't need to know in detail how the rule works (it's described here). All that gem-graph needs to know is written in the "Hello world" file (here). If you open this file, you'll find a description of the arrow (here) and its movement (there).
------------
To improve this model, it is possible to give the arrow the ability to move in two directions: forwards or backwards. To do this, we need to add a second rule. This second rule says: if an arrow is drawn here, I erase it and redraw it on the previous square. A random draw (described here) is also necessary to determine whether the first or second rule applies. With these two rules and the random draw, the arrow now sometimes goes forwards, sometimes backwards. We can call this second model a "random walk".
------------
The second model (the random walk) had one state (the arrow) and two rules (forward/backward). Now here's a model with two states and two rules: the pendulum. This time, the arrow can be drawn either tilted forwards or tilted backwards (these are the two possible states) and the two rules switch the drawn arrow from one state to the other or vice versa. In the file, the states are (here) and the rules (here). The pendulum does not change place, but alternates between left and right. Like the previous ones, you can slow down the programme so that you can observe the movements.
------------
Once you know how to write a state and a rule, you can write thousands of them: they will always be combinations of the same elementary form. However, it is also possible to combine programs: for example, you can combine the reports and rules from the two previous models to create a new model that shows both phenomena simultaneously. Once again, in the file, the states are (here) and the rules (here).
------------
The next example shows how the same rule can be applied to a multitude of states. The rule is the same as that used in the first model: an arrow can only be moved one square forward, but this time you have to check that the square forward is free. If it isn't, the arrow won't move. Once the rule has been modified in this way, it can be applied to a multitude of arrows distributed randomly in space (see details here).
When you set the model in motion, you will see all these small lines moving from left to right. A single rule is responsible for all these movements.
For a small fee, we can apply the two rules of the 'random walk' model to all the arrows distributed in this space, and they will then all behave in the same way, sometimes moving forwards, sometimes backwards.
------------
In the next example, we first, we build a model similar to the previous one: a multitude of arrows are randomly distributed in space, but this time they are vertical and the movements are up and down instead of right and left. Then, we add this model to the previous state and set the final model in motion. We see then little lines moving from left to right or reverse if they are horizontal, and up and down or reverse if they are vertical. Their number is constant. They don't change shape or direction. There seems to be no accident when they cross. Nothing else happens.
------------
The last example in this series, because it shows a multitude of diverse and simultaneous movements, perhaps gives the impression of a more complex system. It would be easy to make it even more complex, but it's much more interesting to show how gem-graph can be used to analyse and control that complexity. At this point, it's time to compare gem-graph to other classes of automata that do quite similar things, and to look at what it can actually do and what its limitations are.
------------
The main difference between gem-graph models and agent-based models is that gem-graph deals with situations, not agents. In a situation where several agents are interacting and each agent could apply a different rule, gem-graph considers and processes the situation. Not the agents. Whatever the state - the new situation - that results from his action, his decision-making process will have been simple and straightforward. It will therefore be easy to modify and control. And the diversity of possible new situations will be far greater than that offered by agent-based models.
------------
The comparison between gem-graphs and cellular automata first comes up against a question of vocabulary. What is commonly called a 'rule' in one and the other is not the same thing. Gem-graphs and cellular automata have the same power: anything that can be done by one can be done by the other, but their writing is not the same (details of this comparison here).
------------
How can gem-graph be used to analyse and control the complexity of what it represents and sets in motion? This chapter introduces the gem-graph mechanism.

View File

@ -1,58 +1,43 @@
/** /**
* @file * @file
* FSM (Finite State Machine) header * Client fsm (finite state machine) header
* *
* This file is part of Gem-graph. * This file is part of Gem-graph.
* *
* @cond LICENSE
* Copyright © 2021 Libre en Communs <contact@a-lec.org>
* Copyright © 2021-2024 Adrien Bourmault <neox@a-lec.org>
* Copyright © 2021-2024 Jean Sirmai <jean@a-lec.org>
* *
* This program is free software: you can redistribute it and/or modify it under * This commit introduces:
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, eisrc/log/ther version 3 of the License, or (at your option) any
* later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * - the two functions that enable main() to init and close the log:
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * fsm_trigger_log_init() and fsm_trigger_log_close()
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
* *
* You should have received a copy of the GNU Affero General Public License * - the two functions that enable main() to init and close the fsm:
* along with this program. If not, see <http://www.gnu.org/licenses/>. * fsm_init() and fsm_close()
* @endcond *
* - the two functions that enable the fsm to init and close its structures:
* fsm_structures_init() and fsm_structures_close()
* *
* *
* The fsm header lists all the structures that the log will need. * @see readme.docs and this text below.
* *
* The two structures and the two enums listed below will stay in the fsm header. * ---
* *
* All functions but the last one will be in a dedicated file: src/log/oper.c * The two log structures and the two enums listed below stay in the fsm header.
* This file will contain the declaration of the log with the static attribute, *
* which will force all the functions that read or write it to be in it. * All log functions are now in dedicated files.
*
* The most important function: fsm_add_log() is in the file:
* /src/fsm/log/manager.c
*
* This file contains the declaration of the log with the static attribute,
* which forces all the functions that read or write it to be in it.
* Forcing all functions that read or write to the log to be grouped together * Forcing all functions that read or write to the log to be grouped together
* will prevent uncontrolled operations. * help to prevent uncontrolled operations.
* *
* The four most important functions are:
* - fsm_init_log()
* - fsm_publish_log()
* - fsm_clear_log()
* - fsm_add_log_event()
* .
*
* A typical list would also feature the last three functions:
* - fsm_get_log_length()
* - fsm_seek_log()
* - fsm_remove_log()
* .
* but in the case of a log, their usefulness remains to be demonstrated.
*
*
* A last function: fsm_add_log() will be in another file: src/log/manager.c.
* All events sent to the log must pass through this function, which allows them * All events sent to the log must pass through this function, which allows them
* to be filtered before being published in the log. * to be filtered before being published in the log.
* *
* ---
*
* Here's how the procedure works. * Here's how the procedure works.
* A message is send to the fsm_add_log() function for each documented event. * A message is send to the fsm_add_log() function for each documented event.
* If there are too many events, this is the only function that allows you to * If there are too many events, this is the only function that allows you to
@ -70,28 +55,49 @@
* *
* file_source, function_source and string_value are three strings. * file_source, function_source and string_value are three strings.
* *
* Here is the list of all the structures that the log will need. The functions * ---
* will be documented in future commits.
* *
* - fsm_log_struct() * The four mandatory executive functions that the log needs to init, add and
* - fsm_log_struct_unit() * publish are in the dedicated file: /src/fsm/log/oper.c:
* .
* *
* - fsm_enum_log_severity() * NB: fsm_clear_log() is designed to close what was initiated by fsm_init_log().
* - fsm_enum_log_source() * As, in this commit, fsm_publish_log() is the last instruction and no memory
* . * leaks are detected, the use of fsm_clear_log() is not required.
* *
* - fsm_init_log() * - fsm_init_log()
* - fsm_publish_log() * - fsm_publish_log()
* - fsm_clear_log() * - fsm_clear_log()
* - fsm_add_log_event() * - fsm_add_log_event()
* .
*
* A typical list would also feature the following three functions
* but in the case of a log, their usefulness remains to be demonstrated.
* These functions are therefore apart in the file /src/fsm/log/appendix.c
*
* - fsm_get_log_length() * - fsm_get_log_length()
* - fsm_seek_log() * - fsm_seek_log()
* - fsm_remove_log() * - fsm_remove_log()
* . * .
* *
* - fsm_add_log() *
* . * @cond LICENSE
* Copyright © 2021 Libre en Communs <contact@a-lec.org>
* Copyright © 2021-2024 Adrien Bourmault <neox@a-lec.org>
* Copyright © 2021-2024 Jean Sirmai <jean@a-lec.org>
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* @endcond
*/ */
@ -109,7 +115,7 @@
* https://en.wikipedia.org/wiki/Syslog * https://en.wikipedia.org/wiki/Syslog
* *
* All logs must contain at least one item from this enum and only one. * All logs must contain at least one item from this enum and only one.
* This item can not be set to NULL. * This item can NOT be set to NULL.
* *
* @see fsm_add_log() * @see fsm_add_log()
*/ */
@ -243,61 +249,16 @@ long fsm_remove_log (fsm_log_struct *jj,
const char *function_source, const char *function_source,
const char *string_value); const char *string_value);
void fsm_add_log (int severity,
int source,
const char *file_source,
const char *function_source,
const char *string_value);
void fsm_trigger_log_init();
void fsm_trigger_log_close();
void fsm_init (const char *initial_message_from_main);
void fsm_close (const char *final_message_from_main);
/**
* @brief (1) This comment is not a duplicate: it will be displaced in the file:
* src/log/manager.c in next commits.
*
* It will be mandatory for any event to call the function fsm_add_log()
* to be published in the journal and it is here and only here that filters will
* be found.
*
* --
*
* @details The fsm_struct_journal (gg_logs) will be a static instance in a
* dedicated file: src/log/manager.c
* Therefore, all the functions that read or write it will be in this file.
* This is to avoid uncontrolled operations on it.
*
* While the program is running, messages will be sent to the fsm_add_log()
* function for each documented event.
* If there are too many events, this is the only function that allows you to
* apply one or more filters before publication. This allows you to select the
* events of interest, which can vary depending on the type of session.
*
* These filters can operate on any of the following five parameters:
* severity, source, file_source, function_source, string_value .
* They can be combined using any logical operators and parentheses.
*
* --
*
* @since 2024-08
*
* @callgraph
* @see fsm_add_log_event() insertion into the log list
*
* @callergraph @see Almost all functions will have to report events and will
* therefore call fsm_add_log().
* @see main() will send the first and last messages.
*
*
* @param severity: one of the following pre-defined values
*
* FATAL - ERROR - WARN - INFO - DEBUG - TRACE
*
* @param source: a pre-defined value (a name of a structure) that can be
* associated to each event. It can be set to 'NULL'.
*
* @param *file_source the name of the file that emits the event
* @param *function_source the function that emits the event
* @param *string_value any value that better specifies the event
*
* @see fsm_enum_log_severity
* @see fsm_enum_log_source
*/
void fsm_add_log (int severity,
int source,
const char *file_source,
const char *function_source,
const char *string_value);

214
src/fsm/control.c Normal file
View File

@ -0,0 +1,214 @@
/**
* @file
* Client fsm (Finite State Machine) control file.
*
* ---
*
* The fsm control instance
* - **initialises** the log and the rest of the fsm when triggered by main()
* - **checks** all triggered operations and **allocates** them if they are valid
* - **closes** all the elements it opened before handing over to main()
* .
*
* About code organization, see src/readme.dox
*
* ---
*
* @cond LICENSE
* Copyright © 2021 Libre en Communs <contact@a-lec.org>
* Copyright © 2021-2024 Adrien Bourmault <neox@a-lec.org>
* Copyright © 2021-2024 Jean Sirmai <jean@a-lec.org>
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* @endcond
*
* @file
* @brief
*
* This file is part of Gem-graph.
*
* @details
* The Finite State Machine (fsm) describes all the possible states of the
* Gem-graph client and all the transitions between them.
* It manages several kinds of exclusive states:
* - Run the model or edit it.
* - Select a single view of the model from all those possible.
* The different views show either the space, or the rule tree,
* or a single rule of interest, or measurements or results.
* NB an overview is possible, but it does not provide details.
* - Apply a selected measurement to the currently running model
* - Select some results for study or/and presentation.
* - Choose the user's preferred values for a set of parameters
* used to modify the appearance or behaviour of gem-graph.
*
* Each state of the fsm is a combination of each of these states.
*
* The current state of the fsm must be
* - saved at the end of a work session and
* - reread (available to the user) at the start of a new session.
*
* No state of the fsm should be defined in another module.
*
* No fsm transition should be executed in another module.
*
* The journal is created, edited and published from here.
*
* @cond LICENSE
* Copyright © 2021 Libre en Communs <contact@a-lec.org>
* Copyright © 2021-2024 Adrien Bourmault <neox@a-lec.org>
* Copyright © 2021-2024 Jean Sirmai <jean@a-lec.org>
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* @endcond
*/
#include "../../include/fsm.h"
/**
* Initiates the four lists:
* 'measures', 'results', 'displayables results' and 'preferences'.
* The items selected in these lists contribute to define the current state of
* the fsm.
* The exact number and status of the structures of the fsm are still being
* assessed.
*
* @callergraph
* @see fsm_init()
*/
static void fsm_structures_init()
{
/**< will be introduced later on:
fsm_add_log (info, FSM, "fsm/dispatch", "measures list init()",
"measurement processes");
fsm_list_init_measures();
fsm_add_log (info, FSM, "fsm/dispatch", "results list init()",
"measurement results (gross)");
fsm_list_init_results();
fsm_add_log (info, FSM, "fsm/dispatch", "displayables list init()",
"displayable results");
fsm_list_init_displayables();
fsm_add_log (info, FSM, "fsm/dispatch", "preferences list init()",
"preferences");
fsm_list_init_preferences();
*/
}
/**
* Closes the four lists:
* 'measures', 'results', 'displayables results' and 'preferences'.
* The items selected in these lists contribute to define the current state of
* the fsm.
* The exact number and status of the structures of the fsm are still being
* assessed.
*
* @callergraph
* @see fsm_close()
*/
static void fsm_structures_close()
{
/**< ? */
}
/**
* @brief fsm_init() is the first function called by main.c
* It initiates the journal and calls fsm_structures_init() that
*
* @since 2024-08
*
* @callergraph
* @see main()
*
* @callgraph
* @see trigger_fsm_log_init()
* @see fsm_add_log()
* @see fsm_list_init_measures()
* @see fsm_list_init_results()
* @see fsm_list_init_displayables()
* @see fsm_list_init_preferences()
*
* @param *initial_info_from_main
*/
void fsm_init (const char *initial_info_from_main)
{
fsm_trigger_log_init(); /**< fsm_init_log(() can't be called from here
* because static fsm_log_struct gg_logs
* is in src/fsm/log/manager.c */
fsm_add_log (INFO, MAIN, "main", initial_info_from_main,
"👋️ (☕️) Hi everybody ! Here is Gem-Graph.");
fsm_add_log (INFO, FSM, "fsm/control", "fsm initialisation", "has began ✍️");
fsm_structures_init();
fsm_add_log (INFO, FSM, "fsm/control", "fsm initialisation", "has ended 😇️");
}
/**
* @brief fsm_close() is the last function called by main.c It closes all that
* was opened in reverse order before handing over to main().
*
* @details It ensures the fsm state is saved:
* - preferences
* - model
*
* Then it closes the four lists:
* - 'measures',
* - 'results',
* - 'displayables results' and
* - 'preferences'.
* and closes the journal
*
* @since 2024-08
*
* @callergraph
* @see main()
*
* @callgraph
* @see fsm_structures_close()
* @see fsm_trigger_log_close()
* @see fsm_add_log()
*
* @param *closing_info_from_main
*/
void fsm_close (const char *closing_info_from_main)
{
fsm_add_log (INFO, FSM, "fsm/control", "fsm closing", "has began");
fsm_structures_close();
fsm_add_log (INFO, FSM, "fsm/control", "fsm closing", "has ended");
fsm_add_log (INFO, MAIN, "main", closing_info_from_main,
"👋️😄️ That'all folks !");
fsm_trigger_log_close(); /**< fsm_clear_log(() can't be called from here
* because static fsm_log_struct gg_logs
* is in src/fsm/log/manager.c */
}

112
src/fsm/log/appendix.c Normal file
View File

@ -0,0 +1,112 @@
/**
* @file
*
* This file is part of Gem-graph. The log (or journal) stores chronologically
* the events during a session run (rules exec, mainly)
*
* This file groups some functions that a typical list should implement but whose
* utility remains to evaluate in the case of a log list.
*
* @cond LICENSE
* Copyright © 2021 Libre en Communs <contact@a-lec.org>
* Copyright © 2021-2024 Adrien Bourmault <neox@a-lec.org>
* Copyright © 2021-2024 Jean Sirmai <jean@a-lec.org>
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* @endcond
*/
#include <stdio.h>
#include <stdlib.h>
#include "../../../include/fsm.h"
/**
* remove an event;
* the removal is a pop back
*
* @since 2024-09
*
* @param *jj
* @param *file_source
* @param *function_source
* @param *string_value
*
* @returns the removed event date microseconds
*/
long fsm_remove_log (fsm_log_struct *jj,
const char *file_source,
const char *function_source,
const char *string_value)
{
long usec;
fsm_log_struct_unit *tmp = jj->last;
if (! tmp) return -1;
usec = tmp->usec;
jj->last = tmp->prev;
if (jj->last) jj->last->next = NULL;
else jj->first = NULL;
free (tmp);
return usec;
}
/**
* get log length
*
* @since 2024-09
*
* @param *jj
* @returns log length
*/
int fsm_get_log_length (fsm_log_struct jj)
{
fsm_log_struct_unit *a_unit = jj.first;
int nb = 0;
while (a_unit)
{
nb ++;
a_unit = a_unit->next;
}
return nb;
}
/**
* seek for an event
*
* @since 2024-09
*
* @param *jj
* @param usec
* @param *file_source
* @param *function_source
* @param *string_value
*/
void fsm_seek_log (fsm_log_struct jj,
long usec,
const char *file_source,
const char *function_source,
const char *string_value)
{
fsm_log_struct_unit *a_unit = jj.first;
int nb = 0;
while (a_unit)
{
if (usec == a_unit->usec) nb++;
a_unit = a_unit->next;
}
if (nb > 0) printf ("> date (usec) %ld found %d times in journal\n", usec, nb);
else printf ("> date (usec) %ld not found in journal\n", usec);
}

138
src/fsm/log/manager.c Normal file
View File

@ -0,0 +1,138 @@
/**
* @file
* @brief fsm (Finite State Machine) log manager
*
* This file is part of Gem-graph.
*
* @details
* The log (journal) is created, edited and published from here.
* This file contains only (1) the static fsm_log_struct gg_logs
* and (2) the function fsm_add_log() that all calls must pass through to send a
* message to the log.
*
* @cond LICENSE
* Copyright © 2021 Libre en Communs <contact@a-lec.org>
* Copyright © 2021-2024 Adrien Bourmault <neox@a-lec.org>
* Copyright © 2021-2024 Jean Sirmai <jean@a-lec.org>
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* @endcond
*/
#include "../../../include/fsm.h"
/*******************************************************************************
* L O G / J O U R N A L *
*******************************************************************************/
/**
* The fsm_struct_journal (gg_logs) is a static instance in the file
* /src/fsm/log/manager.c
* Therefore, all the functions that read or write it are in this file.
* This helps to avoid uncontrolled operations.
*/
static fsm_log_struct gg_logs;
/**
* @brief It is mandatory for any event to call this function to be published in
* the journal.
*
* @details The fsm_struct_journal (gg_logs) is a static instance in the file
* /src/fsm/log/manager.c
* Therefore, all the functions that read or write it will be in this file.
* This is to avoid uncontrolled operations on it.
*
* A message is send to the log for each documented event.
*
* One or several filters can be applied here (and only here) before publication,
* to select only some events of interest (during debugging, for example).
*
* These filters can operate on any the following five parameters:
* severity, source, file_source (text), function_source (text),
* string_value (text).
*
* They can be combined using any logical operators and parentheses.
*
* @since 2024-08
*
* @callgraph
* @see fsm_add_log_event()
*
* @callergraph
* see fsm_init()
*
* @param severity: one of the following pre-defined values
*
* FATAL - ERROR - WARN - INFO - DEBUG - TRACE
*
* @param source: a pre-defined value (a name of a structure) that can be
* associated to each event. It can be set to 'NULL'.
*
* @param *file_source the name of the file that emits the event
* @param *function_source the function that emits the event
* @param *string_value any value that better specifies the event
*
* @see fsm_enum_log_severity
* @see fsm_enum_log_source
*/
void fsm_add_log (int severity,
int source,
const char *file_source,
const char *function_source,
const char *string_value)
{
if
(
severity < TRACE
// && source == RULE_CONDITION
)
fsm_add_log_event (&gg_logs, file_source, function_source, string_value);
}
/**
* this function is a relay: fsm_init_log() can't be called directly from
* fsm_init() in control because static fsm_log_struct gg_logs is in
* src/fsm/log/manager.c
*
*
* @since 2024-08
*
* @callergraph
* @see main()
*
*/
void fsm_trigger_log_init()
{
fsm_init_log (&gg_logs);
}
/**
* this function is a relay: fsm_publish_log() and fsm_clear_log() can't be
* called directly from fsm_close() in control because static fsm_log_struct
* gg_logs is in src/fsm/log/manager.c
*
* @since 2024-08
*
* @callergraph
* @see main()
*
*/
void fsm_trigger_log_close()
{
fsm_publish_log (gg_logs);
fsm_clear_log (&gg_logs);
}

153
src/fsm/log/oper.c Normal file
View File

@ -0,0 +1,153 @@
/**
* @file
*
* This file is part of Gem-graph.
*
* The log (journal) stores chronologically the events during a session.
*
* This file contains the executive functions needed to init the log, add an
* event and publish the log.
*
* The log presentation is:
* [date - rank - source file - source function - value]
*
* Today, the log is simply printed in the console using glib/g_message();
* It will be printed in chronological order in a file.
*
* @cond LICENSE
* Copyright © 2021 Libre en Communs <contact@a-lec.org>
* Copyright © 2021-2024 Adrien Bourmault <neox@a-lec.org>
* Copyright © 2021-2024 Jean Sirmai <jean@a-lec.org>
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* @endcond
*/
#include <time.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <glib.h>
#include "../../../include/fsm.h"
/**
* init the log: a double chained list
*
* first and last records are set to NULL
*
* @since 2024-09
*
* @param *jj
*/
void fsm_init_log (fsm_log_struct *jj)
{
jj->first = NULL;
jj->last = NULL;
}
/**
* removes all the log content and free each unit
*
* @since 2024-09
*
* @param *jj
*/
void fsm_clear_log (fsm_log_struct *jj)
{
fsm_log_struct_unit *tmp;
fsm_log_struct_unit *a_unit = jj->first;
while(a_unit)
{
tmp = a_unit;
a_unit = a_unit->next;
free (tmp);
}
jj->first = NULL;
jj->last = NULL;
}
/**
* add an event
*
* *new_unit = malloc (sizeof(fsm_log_struct_unit));
*
* warn: is never free (as new log units are never removed)
*
* @since 2024-09
*
* @param *jj
* @param *file_source
* @param *function_source
* @param *string_value
*/
void fsm_add_log_event (fsm_log_struct *jj,
const char *file_source,
const char *function_source,
const char *string_value)
{
struct timeval tv;
gettimeofday (&tv, NULL);
fsm_log_struct_unit *new_unit = malloc (sizeof(fsm_log_struct_unit));
if (! new_unit) exit (EXIT_FAILURE);
new_unit->yy_dd_mm = tv.tv_sec;
new_unit->usec = tv.tv_usec;
new_unit->file_source = file_source;
new_unit->function_source = function_source;
new_unit->string_value = string_value;
new_unit->next = jj->first;
new_unit->prev = NULL;
if (jj->first) jj->first->prev = new_unit;
else jj->last = new_unit;
jj->first = new_unit;
}
#define LOG_MAX_LENGTH 255 /**< arbitrary */
/**
* publish all the logs chronologically (using the g_lib function: g_message)
*
* today, simply printed in the console; TODO: print in a file
*
* @since 2024-09
*
* @param *jj
*/
void fsm_publish_log (fsm_log_struct jj)
{
fsm_log_struct_unit *a_unit = jj.last;
char buf [LOG_MAX_LENGTH];
int nb = 0;
while (a_unit)
{
strftime(buf, sizeof(buf), "%D %T", localtime(&a_unit->yy_dd_mm));
g_message ("%s + %-6ld %6d %-32s %-38s %-50s",
buf,
a_unit->usec,
nb,
a_unit->file_source,
a_unit->function_source,
a_unit->string_value);
a_unit = a_unit->prev;
nb ++;
}
}

View File

@ -1,7 +1,6 @@
/** /**
* @file * @file
* * Gem-graph-client main file.
* Gem-graph main file
* *
* This file is part of Gem-graph. It contains only the main() function. * This file is part of Gem-graph. It contains only the main() function.
* *
@ -26,16 +25,22 @@
* *
* --- * ---
* *
* The main() function will **initialise** the log, the finite state machine (fsm), * The main() function
* the application and the windows and **close** all the elements it opened * - **initialise**
* before the end of program execution. * -# the log,
* -# the finite state machine (fsm),
* -# the application,
* -# the windows and
*
* - **close** all the elements it opened in reverse order
* before ending the program execution
* .
*
* In this commit, it does not implement g_application_activate() and has no * In this commit, it does not implement g_application_activate() and has no
* handlers connected to the 'activate' signal (which triggers an error message). * handlers connected to the 'activate' signal (which triggers an error message).
* *
* The default values of the fsm initial state will be specified in: * The default values of the fsm initial state will be specified in:
* src/fsm/dispatch(). They are user preference and, in accordance, the overview * src/fsm/control(). They are user preferences.
* page of the current model will be displayed as they specify it in:
* src/widget/main_window/designer/widget_design_main_window().
* *
* About code organization, see src/readme.dox * About code organization, see src/readme.dox
* *
@ -43,19 +48,49 @@
*/ */
#include <gtk-4.0/gtk/gtk.h> #include <gtk-4.0/gtk/gtk.h>
#include "../include/fsm.h" // finite state machine (fsm)
/**
* @since 2024-04
*
* @callgraph
* @see fsm_trigger_log_init()
* @see fsm_init()
* @see fsm_close()
* @see fsm_trigger_log_close()
* @see fsm_add_log()
*
* @param argc
* @param **argv
* @return status, the program errorlevel
*/
int main (int argc, char **argv) int main (int argc, char **argv)
{ {
GtkApplication *app; GtkApplication *app;
int status; int status;
app = gtk_application_new ("org.gem-graph", G_APPLICATION_DEFAULT_FLAGS); fsm_init ("first instruction / first log");
//g_signal_connect (app, "activate", G_CALLBACK (on_main_window_activation), NULL); fsm_add_log (INFO, MAIN, "main", "*app = gtk_application_new()",
//g_signal_connect (app, "activate", G_CALLBACK (on_dialog_window_activation), NULL); "| 👉️ trigger app initialization");
app = gtk_application_new ("org.gem-graph", G_APPLICATION_DEFAULT_FLAGS);
status = g_application_run (G_APPLICATION (app), argc, argv); fsm_add_log (INFO, MAIN, "main",
g_object_unref (app); "g signal connect (activate)",
"| 👉️ windows creation requested");
return status; // g_signal_connect (app, "startup", G_CALLBACK (on_windows_startup), NULL);
// g_signal_connect (app, "activate", G_CALLBACK (on_windows_activation), NULL);
fsm_add_log (INFO, MAIN, "main",
"no g signal connect (activate)",
"| 🖐️ windows creation denied");
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
fsm_add_log (INFO, MAIN, "main", "g_object unref (app)", "| 👌️ bye bye app !");
fsm_close("last instruction / last log");
return status;
} }