Initial commit
This commit is contained in:
29
.devcontainer/Dockerfile
Normal file
29
.devcontainer/Dockerfile
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
FROM debian:stable-slim
|
||||||
|
|
||||||
|
RUN RUN set -eux; \
|
||||||
|
apt-get update; \
|
||||||
|
apt-get install -y \
|
||||||
|
git \
|
||||||
|
build-essential \
|
||||||
|
cmake \
|
||||||
|
gdb;
|
||||||
|
|
||||||
|
RUN set -eux; \
|
||||||
|
apt-get update; \
|
||||||
|
apt-get install -y \
|
||||||
|
libncurses-dev \
|
||||||
|
libmicrohttpd-dev;\
|
||||||
|
apt-get clean
|
||||||
|
|
||||||
|
RUN set -eux; \
|
||||||
|
git clone https://github.com/jelmd/libprom.git; \
|
||||||
|
cd libprom; \
|
||||||
|
make build; \
|
||||||
|
cd prom/build; \
|
||||||
|
make install; \
|
||||||
|
cd ../../promhttp/build; \
|
||||||
|
make install;
|
||||||
|
|
||||||
|
WORKDIR /root
|
||||||
|
|
||||||
|
CMD ["sleep infinity"]
|
||||||
21
.devcontainer/devcontainer.json
Normal file
21
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "Developpement C",
|
||||||
|
"build": {
|
||||||
|
"dockerfile": "Dockerfile"
|
||||||
|
},
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
|
"settings": {
|
||||||
|
"remote.downloadExtensionsLocally": true,
|
||||||
|
"telemetry.enableTelemetry": false,
|
||||||
|
"extensions.ignoreRecommendations": true,
|
||||||
|
"workbench.remoteIndicator.showExtensionRecommendations": false
|
||||||
|
},
|
||||||
|
"extensions": [
|
||||||
|
"ms-vscode.cpptools",
|
||||||
|
"ms-vscode.makefile-tools",
|
||||||
|
"danielpinto8zz6.c-cpp-compile-run"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/output/
|
||||||
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"files.insertFinalNewline": true,
|
||||||
|
"files.trimTrailingWhitespace": true,
|
||||||
|
"files.trimFinalNewlines": true
|
||||||
|
}
|
||||||
33
.vscode/tasks.json
vendored
Normal file
33
.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"type": "cppbuild",
|
||||||
|
"label": "C/C++: gcc build active file",
|
||||||
|
"command": "/usr/bin/gcc",
|
||||||
|
"args": [
|
||||||
|
"-fdiagnostics-color=always",
|
||||||
|
"-g",
|
||||||
|
"${workspaceFolder}${pathSeparator}main.cpp",
|
||||||
|
"-lm",
|
||||||
|
"-lncursesw",
|
||||||
|
"-lprom",
|
||||||
|
"-lpromhttp",
|
||||||
|
"-lmicrohttpd",
|
||||||
|
"-o",
|
||||||
|
"${fileDirname}/${fileBasenameNoExtension}"
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"cwd": "${fileDirname}"
|
||||||
|
},
|
||||||
|
"problemMatcher": [
|
||||||
|
"$gcc"
|
||||||
|
],
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
},
|
||||||
|
"detail": "Task generated by Debugger."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": "2.0.0"
|
||||||
|
}
|
||||||
424
AutomForArduino.cpp
Normal file
424
AutomForArduino.cpp
Normal file
@@ -0,0 +1,424 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
/* From Arduino.h */
|
||||||
|
|
||||||
|
#define HIGH 0x1
|
||||||
|
#define LOW 0x00
|
||||||
|
|
||||||
|
#define IO_INPUT 0x02
|
||||||
|
#define IO_OUTPUT 0x04
|
||||||
|
|
||||||
|
#define DIGITAL 0x08
|
||||||
|
#define ANALOG 0x10
|
||||||
|
|
||||||
|
#define PI 3.1415926535897932384626433832795
|
||||||
|
#define HALF_PI 1.5707963267948966192313216916398
|
||||||
|
|
||||||
|
#define true 1
|
||||||
|
#define false 0
|
||||||
|
|
||||||
|
// Temps
|
||||||
|
|
||||||
|
// Timestamp unix en millisecondes
|
||||||
|
// t_start : timestamp de départ
|
||||||
|
// t_backup : timestamp de la précédente itération
|
||||||
|
// t_elapsed : temps écoulé en secondes depuis le départ
|
||||||
|
// dt (delta t) : temps écoulé en secondes depuis la dernière itération
|
||||||
|
unsigned long t_start, t_backup;
|
||||||
|
double t_elapsed, dt;
|
||||||
|
|
||||||
|
unsigned long millis()
|
||||||
|
{
|
||||||
|
struct timespec now;
|
||||||
|
clock_gettime(CLOCK_REALTIME, &now);
|
||||||
|
return ((unsigned long)now.tv_sec) * 1000 + ((unsigned long)now.tv_nsec) / 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define OP_DIGITAL_READ 0
|
||||||
|
#define OP_DIGITAL_WRITE 1
|
||||||
|
#define OP_ANALOG_READ 2
|
||||||
|
#define OP_ANALOG_WRITE 3
|
||||||
|
#define OP_PIN_MODE 4
|
||||||
|
|
||||||
|
typedef struct PinIO
|
||||||
|
{
|
||||||
|
unsigned char mode;
|
||||||
|
int ivalue;
|
||||||
|
double dvalue;
|
||||||
|
int error; // % = 1 /error ex 1 / 20 = 5 %
|
||||||
|
double efficacite; // 0 - 100%
|
||||||
|
unsigned long start;
|
||||||
|
unsigned long time;
|
||||||
|
double duration;
|
||||||
|
unsigned int nb; // compteur d'activation
|
||||||
|
int memory;
|
||||||
|
unsigned char raising;
|
||||||
|
unsigned char falling;
|
||||||
|
} PinIO;
|
||||||
|
|
||||||
|
PinIO _digital[256];
|
||||||
|
|
||||||
|
void pinMode(unsigned char p, unsigned char mode)
|
||||||
|
{
|
||||||
|
_digital[p].mode = 0x01 | mode;
|
||||||
|
|
||||||
|
_digital[p].ivalue = 0;
|
||||||
|
_digital[p].dvalue = 0.0;
|
||||||
|
|
||||||
|
_digital[p].nb = 0;
|
||||||
|
_digital[p].time = 0.0;
|
||||||
|
_digital[p].duration = 0.0;
|
||||||
|
_digital[p].start = 0;
|
||||||
|
_digital[p].raising = 0;
|
||||||
|
_digital[p].memory = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* KEYBOARD */
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char input;
|
||||||
|
int vKey;
|
||||||
|
} KeyboardIO;
|
||||||
|
|
||||||
|
#define NB_KEYBOARD 10
|
||||||
|
KeyboardIO _keyboard[NB_KEYBOARD];
|
||||||
|
|
||||||
|
void LireClavier(int ch)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < NB_KEYBOARD; i++)
|
||||||
|
{
|
||||||
|
_digital[_keyboard[i].input].ivalue = (ch == _keyboard[i].vKey);
|
||||||
|
_digital[_keyboard[i].input].raising = _digital[_keyboard[i].input].ivalue > _digital[_keyboard[i].input].memory;
|
||||||
|
_digital[_keyboard[i].input].falling = _digital[_keyboard[i].input].ivalue < _digital[_keyboard[i].input].memory;
|
||||||
|
_digital[_keyboard[i].input].memory = _digital[_keyboard[i].input].ivalue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ********************************************************
|
||||||
|
* TEMPORISATION RETARD A LA MONTEE *
|
||||||
|
* La sortie passe à 1 au bout de la tempo *
|
||||||
|
******************************************************** */
|
||||||
|
|
||||||
|
class TemporisationRetardMontee
|
||||||
|
{
|
||||||
|
// methodes
|
||||||
|
public :
|
||||||
|
// Contructeur qui prend la duree souhaitee de la temporisation
|
||||||
|
TemporisationRetardMontee(unsigned long duree)
|
||||||
|
{
|
||||||
|
this->duree = duree;
|
||||||
|
sortie = false;
|
||||||
|
captureTemps = false;
|
||||||
|
}
|
||||||
|
// Activation de la temporisation. Doit etre fait tout le temps de la duree de la tempo
|
||||||
|
void activation()
|
||||||
|
{
|
||||||
|
// Capture du temps de reference
|
||||||
|
if(!captureTemps)
|
||||||
|
{
|
||||||
|
debut = millis();
|
||||||
|
captureTemps = true;
|
||||||
|
}
|
||||||
|
// Calcul du temps ecoule depuis le temps de reference
|
||||||
|
tempsEcoule = millis() - debut;
|
||||||
|
// Mise a 1 de la fin de tempo
|
||||||
|
if (tempsEcoule >= duree)
|
||||||
|
{
|
||||||
|
sortie = true;
|
||||||
|
captureTemps = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sortie = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Precharge de la temporisation
|
||||||
|
void setDuree(unsigned long majduree)
|
||||||
|
{
|
||||||
|
duree = majduree;
|
||||||
|
sortie = false;
|
||||||
|
captureTemps = false;
|
||||||
|
}
|
||||||
|
// Interrogation du bit de fin de tempo
|
||||||
|
bool getSortie()
|
||||||
|
{
|
||||||
|
return(sortie);
|
||||||
|
}
|
||||||
|
// Recuperation du temps ecoule depuis le debut si necessaire
|
||||||
|
unsigned long getTempsEcoule()
|
||||||
|
{
|
||||||
|
return(tempsEcoule);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attributs
|
||||||
|
private:
|
||||||
|
unsigned long duree;
|
||||||
|
unsigned long debut;
|
||||||
|
unsigned long tempsEcoule;
|
||||||
|
bool captureTemps;
|
||||||
|
bool sortie;
|
||||||
|
};
|
||||||
|
|
||||||
|
/********************************************************
|
||||||
|
* TEMPORISATION RETARD A LA DESCENTE *
|
||||||
|
* La sortie passe à 0 au bout de la tempo *
|
||||||
|
*********************************************************/
|
||||||
|
class TemporisationRetardDescente
|
||||||
|
{
|
||||||
|
public :
|
||||||
|
// Contructeur qui prend la duree souhaitee de la temporisation
|
||||||
|
TemporisationRetardDescente(unsigned long duree)
|
||||||
|
{
|
||||||
|
this->duree = duree;
|
||||||
|
sortie = false;
|
||||||
|
captureTemps = false;
|
||||||
|
}
|
||||||
|
// Activation de la temporisation. Doit etre fait tout le temps de la duree de la tempo
|
||||||
|
void activation()
|
||||||
|
{
|
||||||
|
// Capture du temps de reference
|
||||||
|
if(!captureTemps)
|
||||||
|
{
|
||||||
|
debut = millis();
|
||||||
|
captureTemps = true;
|
||||||
|
sortie = true;
|
||||||
|
}
|
||||||
|
// Calcul du temps ecoule depuis le temps de reference
|
||||||
|
tempsEcoule = millis() - debut;
|
||||||
|
// Mise a 0 de la fin de tempo
|
||||||
|
if (tempsEcoule >= duree)
|
||||||
|
{
|
||||||
|
sortie = false;
|
||||||
|
captureTemps = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Precharge de la temporisation
|
||||||
|
void setDuree(unsigned long majduree)
|
||||||
|
{
|
||||||
|
duree = majduree;
|
||||||
|
sortie = false;
|
||||||
|
captureTemps = false;
|
||||||
|
}
|
||||||
|
// Interrogration du bit de fin de tempo
|
||||||
|
bool getSortie()
|
||||||
|
{
|
||||||
|
return(sortie);
|
||||||
|
}
|
||||||
|
// Recuperation du temps ecoule depuis le debut si necessaire
|
||||||
|
unsigned long getTempsEcoule()
|
||||||
|
{
|
||||||
|
return(tempsEcoule);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned long duree;
|
||||||
|
unsigned long debut;
|
||||||
|
unsigned long tempsEcoule;
|
||||||
|
bool captureTemps;
|
||||||
|
bool sortie;
|
||||||
|
};
|
||||||
|
|
||||||
|
/********************************************************
|
||||||
|
**** CLIGNOTEUR *************************************
|
||||||
|
*********************************************************/
|
||||||
|
class Clignoteur
|
||||||
|
{
|
||||||
|
// methodes
|
||||||
|
public :
|
||||||
|
// Construteur qui prend en parametre le temps haut ou bas souhaitee
|
||||||
|
Clignoteur(int baseDeTemps)
|
||||||
|
{
|
||||||
|
this->baseDeTemps = baseDeTemps;
|
||||||
|
}
|
||||||
|
// Fonction qui renvoie true si le clignoteur est ├á l'├®tat haut et false s'il est ├á l'├®tat bas
|
||||||
|
bool statut()
|
||||||
|
{
|
||||||
|
return ((millis() / baseDeTemps) % 2 == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attributs
|
||||||
|
private:
|
||||||
|
int baseDeTemps;
|
||||||
|
};
|
||||||
|
|
||||||
|
/********************************************************
|
||||||
|
**** COMPTEUR *************************************
|
||||||
|
**** ATTENTION : Il faut gerer le front montant dans le programme
|
||||||
|
*********************************************************/
|
||||||
|
class Compteur
|
||||||
|
{
|
||||||
|
// methodes
|
||||||
|
public :
|
||||||
|
// Constructeur qui prend en parametre la valeur de preselection
|
||||||
|
Compteur(int valeurPreselection)
|
||||||
|
{
|
||||||
|
this->valeurPreselection = valeurPreselection;
|
||||||
|
valeur = 0;
|
||||||
|
}
|
||||||
|
// Incrementation du compteur
|
||||||
|
void incrementer()
|
||||||
|
{
|
||||||
|
valeur++;
|
||||||
|
}
|
||||||
|
// Decrementation du compteur
|
||||||
|
void decrementer()
|
||||||
|
{
|
||||||
|
valeur--;
|
||||||
|
}
|
||||||
|
// remise a zero du compteur
|
||||||
|
void remettreAZero()
|
||||||
|
{
|
||||||
|
valeur = 0;
|
||||||
|
}
|
||||||
|
// recuperation de la valeur courante
|
||||||
|
int getValeurCourante()
|
||||||
|
{
|
||||||
|
return(valeur);
|
||||||
|
}
|
||||||
|
// est-ce que la preselection est atteinte (sortie Q compteur Siemens ou Schnieder)
|
||||||
|
bool getSortie()
|
||||||
|
{
|
||||||
|
return(valeur == valeurPreselection);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attributs
|
||||||
|
private:
|
||||||
|
int valeur;
|
||||||
|
int valeurPreselection;
|
||||||
|
};
|
||||||
|
|
||||||
|
/********************************************************
|
||||||
|
**** MISE A L'ECHELLE DE VALEUR ************************
|
||||||
|
*********************************************************/
|
||||||
|
class MiseAEchelle
|
||||||
|
{
|
||||||
|
public :
|
||||||
|
// Constructeur qui ne prend en parametre la plage d'entree et la plage de sortie
|
||||||
|
MiseAEchelle(float minEntree,float maxEntree,float minSortie,float maxSortie)
|
||||||
|
{
|
||||||
|
this->minEntree = minEntree;
|
||||||
|
this->maxEntree = maxEntree;
|
||||||
|
this->minSortie = minSortie;
|
||||||
|
this->maxSortie = maxSortie;
|
||||||
|
}
|
||||||
|
// fonction de conversion qui prend la valeur a convertir et renvoie la valeur convertie
|
||||||
|
float convertir(float valeurAConvertir)
|
||||||
|
{
|
||||||
|
if(valeurAConvertir >= minEntree && valeurAConvertir <= maxEntree)
|
||||||
|
{
|
||||||
|
float norm = (1 / (maxEntree - minEntree)) * (valeurAConvertir - minEntree);
|
||||||
|
float scale = (maxSortie - minSortie) * norm + minSortie;
|
||||||
|
return(scale);
|
||||||
|
}
|
||||||
|
return(-1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attributs
|
||||||
|
private:
|
||||||
|
float minEntree;
|
||||||
|
float minSortie;
|
||||||
|
float maxEntree;
|
||||||
|
float maxSortie;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* READ */
|
||||||
|
|
||||||
|
int digitalRead(int p)
|
||||||
|
{
|
||||||
|
return ((_digital[p].mode & IO_INPUT) && (_digital[p].mode & DIGITAL) && (_digital[p].mode & 0x01)) ? _digital[p].ivalue : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double analogRead(int p)
|
||||||
|
{
|
||||||
|
return ((_digital[p].mode & IO_INPUT) && (_digital[p].mode & ANALOG) && (_digital[p].mode & 0x01)) ? _digital[p].dvalue : 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* WRITE */
|
||||||
|
|
||||||
|
void digitalWrite(unsigned int p, int value)
|
||||||
|
{
|
||||||
|
if (p < 0 || p > 255)
|
||||||
|
{
|
||||||
|
printf("Pin %d is out of Range.", p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// En panne !
|
||||||
|
if (!(_digital[p].mode & 0x01))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(_digital[p].mode & IO_OUTPUT && _digital[p].mode & DIGITAL))
|
||||||
|
{
|
||||||
|
printf("Pin %d is not a digital input.", p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long m = millis();
|
||||||
|
|
||||||
|
if (value != _digital[p].ivalue)
|
||||||
|
{
|
||||||
|
_digital[p].time = _digital[p].time > 5000 ? 0 : 5000 - _digital[p].time;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_digital[p].time += m - _digital[p].start;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value && !_digital[p].ivalue)
|
||||||
|
{
|
||||||
|
_digital[p].start = m;
|
||||||
|
_digital[p].nb += 1;
|
||||||
|
}
|
||||||
|
else if (value)
|
||||||
|
{
|
||||||
|
_digital[p].duration += dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
_digital[p].ivalue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void analogWrite(unsigned int p, double value)
|
||||||
|
{
|
||||||
|
if (p < 0 || p > 31)
|
||||||
|
{
|
||||||
|
printf("Pin %d is out of Range.", p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// En panne
|
||||||
|
if (!(_digital[p].mode & 0x01))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(_digital[p].mode & IO_OUTPUT) || !(_digital[p].mode & ANALOG))
|
||||||
|
{
|
||||||
|
printf("Pin %d is not a analog input.", p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_digital[p].dvalue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ********************************************************
|
||||||
|
* Console *
|
||||||
|
* *
|
||||||
|
******************************************************** */
|
||||||
|
void ConsoleInit()
|
||||||
|
{
|
||||||
|
setlocale(LC_ALL, ""); // Activer le support des caractères Unicode
|
||||||
|
setlocale(LC_NUMERIC, "C");
|
||||||
|
initscr(); // Initialise ncurses
|
||||||
|
raw(); // Mode brut, sans besoin de validation par Entrée
|
||||||
|
keypad(stdscr, TRUE); // Active les touches spéciales comme ESC
|
||||||
|
nodelay(stdscr, TRUE); // Mode non-bloquant pour getch()
|
||||||
|
noecho(); // Ne pas afficher les touches appuyées
|
||||||
|
curs_set(0); // Masquer le curseur
|
||||||
|
}
|
||||||
819
main.cpp
Normal file
819
main.cpp
Normal file
@@ -0,0 +1,819 @@
|
|||||||
|
#include <unistd.h>
|
||||||
|
#include <ncurses.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <locale.h>
|
||||||
|
#include <array>
|
||||||
|
#include "main.h"
|
||||||
|
#include "AutomForArduino.cpp"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "libprom/prom.h"
|
||||||
|
#include "libprom/promhttp.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constantes de fonctionnement
|
||||||
|
#define LEVEL_MIN 2
|
||||||
|
#define FLOW_PER_PUMP 150
|
||||||
|
|
||||||
|
WINDOW *window;
|
||||||
|
|
||||||
|
int etape = 10; // Étape du grafcet : début Automatique
|
||||||
|
int bp_mode, bp_mode_fm;
|
||||||
|
unsigned short pompe1, pompe2, pompe3, pompe4; // bouton des pompes 0 (arrêt) / 1 (marche)
|
||||||
|
unsigned short pompe1_old, pompe2_old, pompe3_old, pompe4_old;
|
||||||
|
unsigned short sensor_max, sensor_high, sensor_low, sensor_min;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
float TankInitalValue = 7;
|
||||||
|
|
||||||
|
TemporisationRetardMontee tempo1(500);
|
||||||
|
TemporisationRetardMontee tempo2(1000);
|
||||||
|
TemporisationRetardMontee tempo3(1500);
|
||||||
|
TemporisationRetardMontee tempo4(2000);
|
||||||
|
|
||||||
|
// Prometheus
|
||||||
|
// ************************************************************
|
||||||
|
struct MHD_Daemon *server;
|
||||||
|
|
||||||
|
prom_counter_t *pm_pompe;
|
||||||
|
prom_gauge_t *pm_debit;
|
||||||
|
// ************************************************************
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
/* Initialisation */
|
||||||
|
ConsoleInit();
|
||||||
|
AffichageWindow();
|
||||||
|
|
||||||
|
InitPrometheus();
|
||||||
|
ProcessInitKeyboard();
|
||||||
|
ProcessInitIO();
|
||||||
|
ProcessInitValues();
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
int ch = getch(); // Lit l'entrée du clavier sans bloquer
|
||||||
|
|
||||||
|
// **** Break loop if escape key (27) is pressed
|
||||||
|
if (ch == 27 || _digital[OUT_END].ivalue) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// **** Beep
|
||||||
|
if (_digital[OUT_BEEP].ivalue)
|
||||||
|
{
|
||||||
|
beep();
|
||||||
|
_digital[OUT_BEEP].ivalue = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Process();
|
||||||
|
|
||||||
|
LireClavier(ch);
|
||||||
|
LireEntree();
|
||||||
|
EvolutionGrafcet();
|
||||||
|
Actions();
|
||||||
|
|
||||||
|
ProcessPrometheus();
|
||||||
|
|
||||||
|
ProcessException();
|
||||||
|
|
||||||
|
usleep(100000);
|
||||||
|
}
|
||||||
|
|
||||||
|
endwin(); // Termine ncurses et rétablit le terminal
|
||||||
|
puts("Fin du programme");
|
||||||
|
pcr_destroy(PROM_COLLECTOR_REGISTRY);
|
||||||
|
promhttp_stop_daemon(server);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Programme
|
||||||
|
*/
|
||||||
|
void LireEntree()
|
||||||
|
{
|
||||||
|
int input;
|
||||||
|
input = digitalRead(IN_KEYBOARD_A);
|
||||||
|
bp_mode_fm = (input > bp_mode);
|
||||||
|
bp_mode = input;
|
||||||
|
|
||||||
|
sensor_min = digitalRead(IN_SENSOR_MIN);
|
||||||
|
sensor_low = digitalRead(IN_SENSOR_LOW);
|
||||||
|
sensor_high = digitalRead(IN_SENSOR_HIGH);
|
||||||
|
sensor_max = digitalRead(IN_SENSOR_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EvolutionGrafcet()
|
||||||
|
{
|
||||||
|
int etape_futur = etape;
|
||||||
|
|
||||||
|
if (etape < 10 && bp_mode_fm)
|
||||||
|
{
|
||||||
|
etape_futur = 10;
|
||||||
|
pompe1 = pompe2 = pompe3 = pompe4 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etape <= 2 && _digital[IN_KEYBOARD_1].raising)
|
||||||
|
{
|
||||||
|
pompe1 = !pompe1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etape <= 2 && _digital[IN_KEYBOARD_2].raising)
|
||||||
|
{
|
||||||
|
pompe2 = !pompe2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etape <= 2 && _digital[IN_KEYBOARD_3].raising)
|
||||||
|
{
|
||||||
|
pompe3 = !pompe3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etape <= 2 && _digital[IN_KEYBOARD_4].raising)
|
||||||
|
{
|
||||||
|
pompe4 = !pompe4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etape == 0 && !sensor_min)
|
||||||
|
{
|
||||||
|
etape_futur = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etape == 1)
|
||||||
|
{
|
||||||
|
etape_futur = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etape == 2 && sensor_min)
|
||||||
|
{
|
||||||
|
etape_futur = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etape >= 10 && bp_mode_fm)
|
||||||
|
{
|
||||||
|
etape_futur = 0;
|
||||||
|
pompe1 = pompe2 = pompe3 = pompe4 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sensor_max)
|
||||||
|
{
|
||||||
|
pompe1 = pompe2 = pompe3 = pompe4 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Automatique */
|
||||||
|
if (etape == 10 && !sensor_low && !sensor_high)
|
||||||
|
{
|
||||||
|
etape_futur = 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etape == 11 && sensor_high)
|
||||||
|
{
|
||||||
|
etape_futur = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etape == 11 && tempo1.getSortie())
|
||||||
|
{
|
||||||
|
etape_futur = 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etape == 12 && sensor_high)
|
||||||
|
{
|
||||||
|
etape_futur = 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etape == 12 && tempo2.getSortie())
|
||||||
|
{
|
||||||
|
etape_futur = 14; // Allumer le moteur 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etape == 13 && tempo1.getSortie())
|
||||||
|
{
|
||||||
|
etape_futur = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etape == 13 && !sensor_low && !sensor_high)
|
||||||
|
{
|
||||||
|
etape_futur = 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etape == 14 && sensor_high)
|
||||||
|
{
|
||||||
|
etape_futur = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etape == 14 && tempo3.getSortie())
|
||||||
|
{
|
||||||
|
etape_futur = 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etape == 15 && tempo1.getSortie())
|
||||||
|
{
|
||||||
|
etape_futur = 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etape == 15 && !sensor_low && !sensor_high)
|
||||||
|
{
|
||||||
|
etape_futur = 14;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etape == 16 && sensor_high)
|
||||||
|
{
|
||||||
|
etape_futur = 17;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etape == 16 && tempo4.getSortie())
|
||||||
|
{
|
||||||
|
etape_futur = 18;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etape == 17 && tempo1.getSortie())
|
||||||
|
{
|
||||||
|
etape_futur = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etape == 17 && !sensor_low && !sensor_high)
|
||||||
|
{
|
||||||
|
etape_futur = 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etape == 18 && sensor_high)
|
||||||
|
{
|
||||||
|
etape_futur = 19;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etape == 19 && tempo1.getSortie())
|
||||||
|
{
|
||||||
|
etape_futur = 17;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etape == 19 && !sensor_low && !sensor_high)
|
||||||
|
{
|
||||||
|
etape_futur = 18;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fin de mode automatique */
|
||||||
|
|
||||||
|
if (etape != etape_futur)
|
||||||
|
{
|
||||||
|
etape = etape_futur;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Actions()
|
||||||
|
{
|
||||||
|
digitalWrite(OUT_DISPLAY_GRAFCET, etape);
|
||||||
|
digitalWrite(OUT_DISPLAY_MODE, etape >= 10);
|
||||||
|
digitalWrite(OUT_PUMP_1, !sensor_max && (pompe1 == 1 || etape >= 12));
|
||||||
|
digitalWrite(OUT_PUMP_2, !sensor_max && (pompe2 == 1 || etape >= 14));
|
||||||
|
digitalWrite(OUT_PUMP_3, !sensor_max && (pompe3 == 1 || etape >= 16));
|
||||||
|
digitalWrite(OUT_PUMP_4, !sensor_max && (pompe4 == 1 || etape >= 18));
|
||||||
|
// digitalWrite(OUT_BEEP, etape == 1);
|
||||||
|
|
||||||
|
if (etape >= 11)
|
||||||
|
{
|
||||||
|
tempo1.activation();
|
||||||
|
tempo2.activation();
|
||||||
|
tempo3.activation();
|
||||||
|
tempo4.activation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process
|
||||||
|
*/
|
||||||
|
void ProcessInitKeyboard()
|
||||||
|
{
|
||||||
|
_keyboard[0].vKey = '1';
|
||||||
|
_keyboard[0].input = IN_KEYBOARD_1;
|
||||||
|
|
||||||
|
_keyboard[1].vKey = '2';
|
||||||
|
_keyboard[1].input = IN_KEYBOARD_2;
|
||||||
|
|
||||||
|
_keyboard[2].vKey = '3';
|
||||||
|
_keyboard[2].input = IN_KEYBOARD_3;
|
||||||
|
|
||||||
|
_keyboard[3].vKey = '4';
|
||||||
|
_keyboard[3].input = IN_KEYBOARD_4;
|
||||||
|
|
||||||
|
_keyboard[4].vKey = 'a';
|
||||||
|
_keyboard[4].input = IN_KEYBOARD_A;
|
||||||
|
|
||||||
|
_keyboard[5].vKey = 'x';
|
||||||
|
_keyboard[5].input = IN_KEYBOARD_X;
|
||||||
|
|
||||||
|
_keyboard[6].vKey = '6';
|
||||||
|
_keyboard[6].input = IN_KEYBOARD_7;
|
||||||
|
|
||||||
|
_keyboard[7].vKey = '7';
|
||||||
|
_keyboard[7].input = IN_KEYBOARD_8;
|
||||||
|
|
||||||
|
_keyboard[8].vKey = '8';
|
||||||
|
_keyboard[8].input = IN_KEYBOARD_9;
|
||||||
|
|
||||||
|
_keyboard[9].vKey = '9';
|
||||||
|
_keyboard[9].input = IN_KEYBOARD_0;
|
||||||
|
|
||||||
|
for (int i = 0; i < NB_KEYBOARD; i++)
|
||||||
|
{
|
||||||
|
_digital[_keyboard[i].input].mode = OP_DIGITAL_READ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessInitIO()
|
||||||
|
{
|
||||||
|
pinMode(IN_KEYBOARD_1, IO_INPUT | DIGITAL);
|
||||||
|
pinMode(IN_KEYBOARD_2, IO_INPUT | DIGITAL);
|
||||||
|
pinMode(IN_KEYBOARD_3, IO_INPUT | DIGITAL);
|
||||||
|
pinMode(IN_KEYBOARD_4, IO_INPUT | DIGITAL);
|
||||||
|
pinMode(IN_KEYBOARD_A, IO_INPUT | DIGITAL);
|
||||||
|
|
||||||
|
pinMode(IN_KEYBOARD_7, IO_INPUT | DIGITAL);
|
||||||
|
pinMode(IN_KEYBOARD_8, IO_INPUT | DIGITAL);
|
||||||
|
pinMode(IN_KEYBOARD_9, IO_INPUT | DIGITAL);
|
||||||
|
pinMode(IN_KEYBOARD_0, IO_INPUT | DIGITAL);
|
||||||
|
pinMode(IN_KEYBOARD_X, IO_INPUT | DIGITAL);
|
||||||
|
|
||||||
|
pinMode(IN_SENSOR_MIN, IO_INPUT | DIGITAL);
|
||||||
|
pinMode(IN_SENSOR_LOW, IO_INPUT | DIGITAL);
|
||||||
|
pinMode(IN_SENSOR_HIGH, IO_INPUT | DIGITAL);
|
||||||
|
pinMode(IN_SENSOR_MAX, IO_INPUT | DIGITAL);
|
||||||
|
|
||||||
|
pinMode(IN_TANK_LEVEL, IO_INPUT | ANALOG);
|
||||||
|
pinMode(IN_FLOW_OUT, IO_INPUT | ANALOG);
|
||||||
|
pinMode(IN_FLOW_IN, IO_INPUT | ANALOG);
|
||||||
|
pinMode(IN_FLOW_DIF, IO_INPUT | ANALOG);
|
||||||
|
pinMode(IN_TANK_MIN, IO_INPUT | ANALOG);
|
||||||
|
pinMode(IN_TANK_MAX, IO_INPUT | ANALOG);
|
||||||
|
pinMode(IN_FLOW_CAP, IO_INPUT | ANALOG);
|
||||||
|
pinMode(IN_FLOW_1, IO_INPUT | ANALOG);
|
||||||
|
pinMode(IN_FLOW_2, IO_INPUT | ANALOG);
|
||||||
|
pinMode(IN_FLOW_3, IO_INPUT | ANALOG);
|
||||||
|
pinMode(IN_FLOW_4, IO_INPUT | ANALOG);
|
||||||
|
|
||||||
|
pinMode(OUT_PUMP_1, IO_OUTPUT | DIGITAL);
|
||||||
|
pinMode(OUT_PUMP_2, IO_OUTPUT | DIGITAL);
|
||||||
|
pinMode(OUT_PUMP_3, IO_OUTPUT | DIGITAL);
|
||||||
|
pinMode(OUT_PUMP_4, IO_OUTPUT | DIGITAL);
|
||||||
|
|
||||||
|
pinMode(OUT_DISPLAY_MODE, IO_OUTPUT | DIGITAL);
|
||||||
|
pinMode(OUT_DISPLAY_GRAFCET, IO_OUTPUT | DIGITAL);
|
||||||
|
|
||||||
|
pinMode(OUT_LEVEL_MIN, IO_OUTPUT | ANALOG);
|
||||||
|
pinMode(OUT_LEVEL_LOW, IO_OUTPUT | ANALOG);
|
||||||
|
pinMode(OUT_LEVEL_HIGH, IO_OUTPUT | ANALOG);
|
||||||
|
pinMode(OUT_LEVEL_MAX, IO_OUTPUT | ANALOG);
|
||||||
|
pinMode(OUT_FLOW_PER_PUMP, IO_OUTPUT | ANALOG);
|
||||||
|
pinMode(OUT_FLOW_OUT_AMPLITUDE, IO_OUTPUT | ANALOG);
|
||||||
|
|
||||||
|
pinMode(OUT_BEEP, IO_OUTPUT | DIGITAL);
|
||||||
|
|
||||||
|
_digital[OUT_PUMP_1].error = 30;
|
||||||
|
_digital[OUT_PUMP_1].efficacite = 1.0;
|
||||||
|
//_digital[OUT_PUMP_1].time = 4294967295; //UINT_MAX
|
||||||
|
|
||||||
|
_digital[OUT_PUMP_2].error = 30;
|
||||||
|
_digital[OUT_PUMP_2].efficacite = 0.72;
|
||||||
|
//_digital[OUT_PUMP_2].time = 4294967295;
|
||||||
|
|
||||||
|
_digital[OUT_PUMP_3].error = 10;
|
||||||
|
_digital[OUT_PUMP_3].efficacite = 1.0;
|
||||||
|
//_digital[OUT_PUMP_3].time = 4294967295;
|
||||||
|
|
||||||
|
_digital[OUT_PUMP_4].error = 30;
|
||||||
|
_digital[OUT_PUMP_4].efficacite = 1.0;
|
||||||
|
//_digital[OUT_PUMP_4].time = 4294967295;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessInitValues()
|
||||||
|
{
|
||||||
|
t_start = t_backup = millis();
|
||||||
|
|
||||||
|
srand(time(NULL));
|
||||||
|
|
||||||
|
_digital[IN_TANK_LEVEL].dvalue = _digital[IN_TANK_MAX].dvalue = _digital[IN_TANK_MIN].dvalue = TankInitalValue;
|
||||||
|
|
||||||
|
_digital[OUT_FLOW_PER_PUMP].dvalue = FLOW_PER_PUMP;
|
||||||
|
_digital[OUT_FLOW_OUT_AMPLITUDE].dvalue = 100.0;
|
||||||
|
|
||||||
|
_digital[OUT_LEVEL_MIN].dvalue = LEVEL_MIN;
|
||||||
|
_digital[OUT_LEVEL_LOW].dvalue = 6;
|
||||||
|
_digital[OUT_LEVEL_HIGH].dvalue = 7;
|
||||||
|
_digital[OUT_LEVEL_MAX].dvalue = 9.5;
|
||||||
|
|
||||||
|
_digital[IN_FLOW_OUT].dvalue = 100.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fonctionnement des moteurs
|
||||||
|
*/
|
||||||
|
double ProcessMoteur(int i)
|
||||||
|
{
|
||||||
|
double vitesse = 1.0;
|
||||||
|
double t = _digital[i].time / 5000.0;
|
||||||
|
|
||||||
|
if (_digital[i].ivalue)
|
||||||
|
{
|
||||||
|
if (_digital[i].time < 2500)
|
||||||
|
{
|
||||||
|
vitesse = 4 * pow(t, 3.0);
|
||||||
|
}
|
||||||
|
else if (_digital[i].time < 5000)
|
||||||
|
{
|
||||||
|
vitesse = 1.0 - pow(2 - 2 * t, 3) / 2.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vitesse = 1.0 + 1.0 / (_digital[i].error * 2.0) - rand() / (double)RAND_MAX / _digital[i].error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_digital[i].time < 2500)
|
||||||
|
{
|
||||||
|
vitesse = 1 - 4 * pow(t, 3.0);
|
||||||
|
}
|
||||||
|
else if (_digital[i].time < 5000)
|
||||||
|
{
|
||||||
|
vitesse = pow(2 - 2 * t, 3) / 2.0;
|
||||||
|
// vitesse = 1 - pow(t, 4.0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vitesse = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _digital[OUT_FLOW_PER_PUMP].dvalue * _digital[i].efficacite * vitesse;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessException()
|
||||||
|
{
|
||||||
|
if (t_elapsed > 30) {
|
||||||
|
_digital[OUT_PUMP_1].mode = 0;
|
||||||
|
} else if (t_elapsed > 15) {
|
||||||
|
_digital[IN_SENSOR_LOW].mode = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process()
|
||||||
|
{
|
||||||
|
// *****
|
||||||
|
unsigned long t = millis();
|
||||||
|
t_elapsed = (t - t_start) / 1000.0;
|
||||||
|
dt = (t - t_backup) / 1000.0;
|
||||||
|
|
||||||
|
// ***** FLOW OUT
|
||||||
|
if (_digital[IN_TANK_LEVEL].dvalue > 1.0)
|
||||||
|
{
|
||||||
|
//_digital[IN_FLOW_OUT].dvalue = SimulConsoSinusoidale(t);
|
||||||
|
_digital[IN_FLOW_OUT].dvalue = SimulConsoBrown(_digital[IN_FLOW_OUT].dvalue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_digital[IN_FLOW_CAP].dvalue == 0.0) {
|
||||||
|
_digital[IN_FLOW_CAP].dvalue = _digital[IN_FLOW_OUT].dvalue;
|
||||||
|
}
|
||||||
|
_digital[IN_FLOW_OUT].dvalue = _digital[IN_FLOW_CAP].dvalue * _digital[IN_TANK_LEVEL].dvalue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ***** FLOW IN
|
||||||
|
_digital[IN_FLOW_IN].dvalue = 0;
|
||||||
|
for (int i = OUT_PUMP_1; i <= OUT_PUMP_4; i++)
|
||||||
|
{
|
||||||
|
_digital[i - 4].dvalue = ProcessMoteur(i);
|
||||||
|
_digital[IN_FLOW_IN].dvalue += _digital[i - 4].dvalue;
|
||||||
|
}
|
||||||
|
|
||||||
|
_digital[IN_FLOW_DIF].dvalue = _digital[IN_FLOW_IN].dvalue - _digital[IN_FLOW_OUT].dvalue;
|
||||||
|
|
||||||
|
// ***** TANK LEVEL
|
||||||
|
_digital[IN_TANK_LEVEL].dvalue += (_digital[IN_FLOW_IN].dvalue - _digital[IN_FLOW_OUT].dvalue) / 1000.0 * dt;
|
||||||
|
if (_digital[IN_TANK_LEVEL].dvalue > 10.0) {
|
||||||
|
_digital[IN_TANK_LEVEL].dvalue = 10.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_digital[IN_TANK_LEVEL].dvalue > _digital[IN_TANK_MAX].dvalue) {
|
||||||
|
_digital[IN_TANK_MAX].dvalue = _digital[IN_TANK_LEVEL].dvalue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_digital[IN_TANK_LEVEL].dvalue < _digital[IN_TANK_MIN].dvalue) {
|
||||||
|
_digital[IN_TANK_MIN].dvalue = _digital[IN_TANK_LEVEL].dvalue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// **** KEYBOARD
|
||||||
|
if (_digital[IN_KEYBOARD_X].raising)
|
||||||
|
{
|
||||||
|
_digital[IN_SENSOR_LOW].mode = _digital[IN_SENSOR_LOW].mode ^ 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = IN_KEYBOARD_7; i <= IN_KEYBOARD_0; i++)
|
||||||
|
{
|
||||||
|
if (_digital[i].raising)
|
||||||
|
{
|
||||||
|
unsigned char p = i + (OUT_PUMP_1 - IN_KEYBOARD_7);
|
||||||
|
_digital[p].mode ^= 0x01;
|
||||||
|
if (!(_digital[p].mode & 0x01)) {
|
||||||
|
_digital[p].ivalue = 0;
|
||||||
|
_digital[p].dvalue = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// **** SENSOR
|
||||||
|
int test;
|
||||||
|
|
||||||
|
test = (_digital[IN_TANK_LEVEL].dvalue > _digital[OUT_LEVEL_MIN].dvalue);
|
||||||
|
if (_digital[IN_SENSOR_MIN].ivalue != test)
|
||||||
|
{
|
||||||
|
if (test == 0)
|
||||||
|
{
|
||||||
|
_digital[IN_SENSOR_MIN].nb += 1;
|
||||||
|
}
|
||||||
|
_digital[IN_SENSOR_MIN].ivalue = test;
|
||||||
|
}
|
||||||
|
|
||||||
|
test = _digital[IN_TANK_LEVEL].dvalue > _digital[OUT_LEVEL_LOW].dvalue && _digital[IN_SENSOR_LOW].mode & 0x01;
|
||||||
|
if (_digital[IN_SENSOR_LOW].ivalue != test)
|
||||||
|
{
|
||||||
|
if (test == 0)
|
||||||
|
{
|
||||||
|
_digital[IN_SENSOR_LOW].nb += 1;
|
||||||
|
}
|
||||||
|
_digital[IN_SENSOR_LOW].ivalue = test;
|
||||||
|
}
|
||||||
|
|
||||||
|
test = _digital[IN_TANK_LEVEL].dvalue > _digital[OUT_LEVEL_MAX].dvalue;
|
||||||
|
if (_digital[IN_SENSOR_MAX].ivalue != test)
|
||||||
|
{
|
||||||
|
if (test == 1)
|
||||||
|
{
|
||||||
|
_digital[IN_SENSOR_MAX].nb += 1;
|
||||||
|
}
|
||||||
|
_digital[IN_SENSOR_MAX].ivalue = test;
|
||||||
|
}
|
||||||
|
|
||||||
|
test = _digital[IN_TANK_LEVEL].dvalue > _digital[OUT_LEVEL_HIGH].dvalue;
|
||||||
|
if (_digital[IN_SENSOR_HIGH].ivalue != test)
|
||||||
|
{
|
||||||
|
if (test == 1)
|
||||||
|
{
|
||||||
|
_digital[IN_SENSOR_HIGH].nb += 1;
|
||||||
|
}
|
||||||
|
_digital[IN_SENSOR_HIGH].ivalue = test;
|
||||||
|
}
|
||||||
|
|
||||||
|
Affichage(t);
|
||||||
|
|
||||||
|
t_backup = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
double SimulConsoSinusoidale(long t)
|
||||||
|
{
|
||||||
|
double alea = ((long)(t / 100.0) % 600) * 3 / 1800.0 * PI;
|
||||||
|
//mvprintw(18, 0, "%ld %f", (long)(t / 100.0), alea);
|
||||||
|
return 100 + cos(alea) * cos(alea) * _digital[OUT_FLOW_OUT_AMPLITUDE].dvalue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dt : Intervalle de temps
|
||||||
|
double SimulConsoBrown(double valeur_precedente)
|
||||||
|
{
|
||||||
|
float mu = 0.01 * -((((int)t_elapsed / 30) % 2) * 2 - 1); // Taux de croissance (1%)
|
||||||
|
float sigma = 0.05; // Volatilité (5%)
|
||||||
|
|
||||||
|
mvprintw(8, 40, "(µ %.1f %% ; σ %.1f %%) ", mu * 100, sigma * 100);
|
||||||
|
|
||||||
|
// Nombre aléatoire compris dans [-1 +1]
|
||||||
|
float rand_std_normal = ((double)rand() / RAND_MAX) * 2.0 - 1.0;
|
||||||
|
|
||||||
|
// Calcule la variation logarithmique pour cette étape
|
||||||
|
float drift = (mu - 0.5f * sigma * sigma) * dt;
|
||||||
|
float diffusion = sigma * sqrt(dt) * rand_std_normal;
|
||||||
|
|
||||||
|
return valeur_precedente * exp(drift + diffusion);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Affichage dans la console
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialisation, affichage des parties statiques
|
||||||
|
*/
|
||||||
|
void AffichageWindow()
|
||||||
|
{
|
||||||
|
window = subwin(stdscr, 19, 62, 0, 0);
|
||||||
|
|
||||||
|
box(window, 0, 0);
|
||||||
|
|
||||||
|
// Titre
|
||||||
|
mvwprintw(window, 1, 2, "Château d'eau (11/2024)");
|
||||||
|
|
||||||
|
// I/O
|
||||||
|
// Ligne du haut
|
||||||
|
mvwaddch(window, 2, 0, ACS_LTEE);
|
||||||
|
mvwhline(window, 2, 1, 0, 60);
|
||||||
|
mvwaddch(window, 2, 61, ACS_RTEE);
|
||||||
|
|
||||||
|
// Ligne du bas
|
||||||
|
mvwaddch(window, 7, 0, ACS_LTEE);
|
||||||
|
mvwhline(window, 7, 1, 0, 60);
|
||||||
|
mvwaddch(window, 7, 61, ACS_RTEE);
|
||||||
|
|
||||||
|
// Séparation verticale
|
||||||
|
mvwaddch(window, 2, 18, ACS_TTEE);
|
||||||
|
mvwvline(window, 3, 18, 0, 4);
|
||||||
|
mvwaddch(window, 7, 18, ACS_BTEE);
|
||||||
|
|
||||||
|
// Input : Boutons poussoirs
|
||||||
|
mvwprintw(window, 3, 2, "BP 1");
|
||||||
|
mvwprintw(window, 4, 2, "BP 2");
|
||||||
|
mvwprintw(window, 5, 2, "BP 3");
|
||||||
|
mvwprintw(window, 6, 2, "BP 4");
|
||||||
|
|
||||||
|
// Output : Moteurs pompes
|
||||||
|
mvwprintw(window, 3, 20, "Pompe 1");
|
||||||
|
mvwprintw(window, 4, 20, "Pompe 2");
|
||||||
|
mvwprintw(window, 5, 20, "Pompe 3");
|
||||||
|
mvwprintw(window, 6, 20, "Pompe 4");
|
||||||
|
|
||||||
|
// Mesures
|
||||||
|
mvwprintw(window, 8, 2, "Debit en sortie");
|
||||||
|
mvwprintw(window, 9, 2, "Debit en entrée");
|
||||||
|
mvwprintw(window, 10, 2, "Volume dans le réservoir");
|
||||||
|
|
||||||
|
// Graphe
|
||||||
|
|
||||||
|
// Ligne du haut
|
||||||
|
mvwaddch(window, 11, 0, ACS_LTEE);
|
||||||
|
mvwhline(window, 11, 1, 0, 60);
|
||||||
|
mvwaddch(window, 11, 61, ACS_RTEE);
|
||||||
|
|
||||||
|
// Ligne du bas
|
||||||
|
mvwaddch(window, 13, 0, ACS_LTEE);
|
||||||
|
mvwhline(window, 13, 1, 0, 60);
|
||||||
|
mvwaddch(window, 13, 61, ACS_RTEE);
|
||||||
|
|
||||||
|
// Graduations
|
||||||
|
for (int i = 1 ; i < 11; i++) {
|
||||||
|
mvwaddch(window, 11, 6 * i, ACS_TTEE);
|
||||||
|
mvwaddch(window, 13, 6 * i, ACS_BTEE);
|
||||||
|
}
|
||||||
|
|
||||||
|
mvwaddch(window, 13, 2 * 6, ACS_PLUS);
|
||||||
|
mvwaddch(window, 13, 6 * 6, ACS_PLUS);
|
||||||
|
mvwaddch(window, 13, 7 * 6, ACS_PLUS);
|
||||||
|
mvwaddch(window, 13, 57, ACS_TTEE); //9.5 x 6
|
||||||
|
|
||||||
|
mvwvline(window, 12, 6 * 10, 0, 1);
|
||||||
|
|
||||||
|
// Légende
|
||||||
|
mvwaddch(window, 16, 0, ACS_LTEE);
|
||||||
|
mvwhline(window, 16, 1, 0, 60);
|
||||||
|
mvwaddch(window, 16, 61, ACS_RTEE);
|
||||||
|
|
||||||
|
mvwprintw(window, 14, 2 * 6 - 1, "min");
|
||||||
|
mvwprintw(window, 14, 6 * 6 - 2, "low");
|
||||||
|
mvwprintw(window, 14, 7 * 6, "high");
|
||||||
|
mvwprintw(window, 14, 56, "max");
|
||||||
|
|
||||||
|
// Informations
|
||||||
|
mvwprintw(window, 17, 2, "Mode");
|
||||||
|
|
||||||
|
mvwaddch(window, 16, 18, ACS_TTEE);
|
||||||
|
mvwaddch(window, 18, 18, ACS_BTEE);
|
||||||
|
mvwvline(window, 17, 18, 0, 1);
|
||||||
|
mvwprintw(window, 17, 20, "Grafcet");
|
||||||
|
|
||||||
|
mvwaddch(window, 16, 31, ACS_TTEE);
|
||||||
|
mvwaddch(window, 18, 31, ACS_BTEE);
|
||||||
|
mvwvline(window, 17, 31, 0, 1);
|
||||||
|
mvwprintw(window, 17, 33, "min");
|
||||||
|
|
||||||
|
mvwprintw(window, 17, 46, "max");
|
||||||
|
|
||||||
|
wrefresh(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Affichage(unsigned long t)
|
||||||
|
{
|
||||||
|
mvwprintw(window, 1, 50, "%5.1f s", t_elapsed);
|
||||||
|
|
||||||
|
for (int i = OUT_PUMP_1; i <= OUT_PUMP_4; i++)
|
||||||
|
{
|
||||||
|
mvwprintw(window, (short)(i - OUT_PUMP_1 + 3), 30, " %c %5.1f s %dx", _digital[i].mode & 0x01 ? _digital[i].ivalue ? 'M' : '.' : 'X', _digital[i].duration, _digital[i].nb);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = IN_KEYBOARD_1; i <= IN_KEYBOARD_4; i++)
|
||||||
|
{
|
||||||
|
mvwprintw(window, (short)(i + 3), 10, _digital[_keyboard[i].input].ivalue ? "1" : "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
mvwprintw(window, 8, 28, "%3d l/s", (int)_digital[IN_FLOW_OUT].dvalue);
|
||||||
|
mvwprintw(window, 9, 28, "%3d l/s", (int)_digital[IN_FLOW_IN].dvalue);
|
||||||
|
mvwprintw(window, 10, 29, "%5.2lf m3 (%+d l/s)", _digital[IN_TANK_LEVEL].dvalue, (int)_digital[IN_FLOW_DIF].dvalue);
|
||||||
|
|
||||||
|
AffichageGraphe(12, 1, _digital[IN_TANK_LEVEL].dvalue * 6);
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (_digital[IN_SENSOR_LOW].mode & 0x01)
|
||||||
|
{
|
||||||
|
mvwprintw(window, 15, 1, " (%dx) (%dx) (%dx) (%dx)", _digital[IN_SENSOR_MIN].nb, _digital[IN_SENSOR_LOW].nb, _digital[IN_SENSOR_HIGH].nb, _digital[IN_SENSOR_MAX].nb);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mvwprintw(window, 15, 1, " (%dx) X (%dx) (%dx) (%dx)", _digital[IN_SENSOR_MIN].nb, _digital[IN_SENSOR_LOW].nb, _digital[IN_SENSOR_HIGH].nb, _digital[IN_SENSOR_MAX].nb);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
mvwprintw(window, 14, 15, "%d", _digital[IN_SENSOR_MIN].ivalue);
|
||||||
|
mvwprintw(window, 14, 38, "%d", _digital[IN_SENSOR_LOW].ivalue);
|
||||||
|
mvwprintw(window, 14, 47, "%d", _digital[IN_SENSOR_HIGH].ivalue);
|
||||||
|
mvwprintw(window, 14, 60, "%d", _digital[IN_SENSOR_MAX].ivalue);
|
||||||
|
|
||||||
|
mvwprintw(window, 15, 11, "(%dx) %s", _digital[IN_SENSOR_MIN].nb, _digital[IN_SENSOR_MIN].mode & 0x01 ? " " : "D");
|
||||||
|
mvwprintw(window, 15, 34, "(%dx) %s", _digital[IN_SENSOR_LOW].nb, _digital[IN_SENSOR_LOW].mode & 0x01 ? " " : "D");
|
||||||
|
mvwprintw(window, 15, 42, "(%dx) %s", _digital[IN_SENSOR_HIGH].nb, _digital[IN_SENSOR_HIGH].mode & 0x01 ? " " : "D");
|
||||||
|
mvwprintw(window, 15, 56, "(%dx)", _digital[IN_SENSOR_MAX].nb);
|
||||||
|
|
||||||
|
// Informations complémentaires
|
||||||
|
mvwprintw(window, 17, 2, _digital[OUT_DISPLAY_MODE].ivalue ? "Automatique" : "Manuel ");
|
||||||
|
mvwprintw(window, 17, 28, "%d", _digital[OUT_DISPLAY_GRAFCET].ivalue);
|
||||||
|
mvwprintw(window, 17, 38, "%4.2lf m3", _digital[IN_TANK_MIN].dvalue);
|
||||||
|
mvwprintw(window, 17, 51, "%4.2lf m3", _digital[IN_TANK_MAX].dvalue);
|
||||||
|
|
||||||
|
wrefresh(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AffichageGraphe(int y, int x, double value)
|
||||||
|
{
|
||||||
|
int entier = (int)(value);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < entier; i++)
|
||||||
|
{
|
||||||
|
mvwaddwstr(window, y, x + i, L"█"); // U+2588
|
||||||
|
}
|
||||||
|
|
||||||
|
int frac = (int)((value - entier) * 4);
|
||||||
|
if (frac > 3) // 0.75 -> 0.99
|
||||||
|
{
|
||||||
|
mvwaddwstr(window, y, x + i, L"▊"); // U+258A
|
||||||
|
entier += 1;
|
||||||
|
}
|
||||||
|
if (frac > 2) // 0.5 -> 0.99
|
||||||
|
{
|
||||||
|
mvwaddwstr(window, y, x + i, L"▌"); // U+258C
|
||||||
|
entier += 1;
|
||||||
|
}
|
||||||
|
else if (frac > 1) // 0.25 -> 0.49
|
||||||
|
{
|
||||||
|
mvwaddwstr(window, y, x + i, L"▎"); //U+258E
|
||||||
|
entier += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = entier; i < 59; i++)
|
||||||
|
{
|
||||||
|
mvwprintw(window, y, x + i, " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prometheus
|
||||||
|
*/
|
||||||
|
void InitPrometheus()
|
||||||
|
{
|
||||||
|
int result = pcr_init(0,"geii_");
|
||||||
|
|
||||||
|
std::array<const char*, 1> labels = { "numero" };
|
||||||
|
pm_pompe = prom_counter_new("pompe_on", "Mise en marche de la pompe"
|
||||||
|
, labels.size(), labels.data());
|
||||||
|
pcr_register_metric(pm_pompe);
|
||||||
|
|
||||||
|
pm_debit = prom_gauge_new("debit", "Débit en l/s"
|
||||||
|
, labels.size(), labels.data());
|
||||||
|
pcr_register_metric(pm_debit);
|
||||||
|
|
||||||
|
promhttp_set_active_collector_registry(NULL);
|
||||||
|
|
||||||
|
// Serveur web
|
||||||
|
server = promhttp_start_daemon(MHD_USE_SELECT_INTERNALLY
|
||||||
|
, 8099, NULL, NULL);
|
||||||
|
if (server == NULL)
|
||||||
|
{
|
||||||
|
printf("Impossible de démarrer le serveur HTTP\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessPrometheus()
|
||||||
|
{
|
||||||
|
// raising = 1 => front montant sur la sortie
|
||||||
|
if (_digital[OUT_PUMP_1].raising) {
|
||||||
|
std::array<const char*, 1> labels1 = { "1" };
|
||||||
|
prom_counter_inc(pm_pompe, labels1.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<const char*, 1> labels1 = { "sortie" };
|
||||||
|
std::array<const char*, 1> labels2 = { "entree" };
|
||||||
|
prom_gauge_set(pm_debit, _digital[IN_FLOW_OUT].dvalue, labels1.data());
|
||||||
|
prom_gauge_set(pm_debit, _digital[IN_FLOW_IN].dvalue, labels2.data());
|
||||||
|
}
|
||||||
82
main.h
Normal file
82
main.h
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
void ConsoleInit();
|
||||||
|
|
||||||
|
void LireClavier(int ch);
|
||||||
|
void LireEntree();
|
||||||
|
void EvolutionGrafcet();
|
||||||
|
void Actions();
|
||||||
|
void RemiseZeroInput();
|
||||||
|
|
||||||
|
void ProcessInitKeyboard();
|
||||||
|
void ProcessInitIO();
|
||||||
|
void ProcessInitValues();
|
||||||
|
double ProcessMoteur(int i);
|
||||||
|
void ProcessException();
|
||||||
|
void Process();
|
||||||
|
|
||||||
|
void InitPrometheus();
|
||||||
|
void ProcessPrometheus();
|
||||||
|
|
||||||
|
double SimulConsoSinusoidale(long t);
|
||||||
|
double SimulConsoBrown(double valeur_precedente);
|
||||||
|
|
||||||
|
void AffichageWindow();
|
||||||
|
void Affichage(unsigned long t);
|
||||||
|
void AffichageGraphe(int y, int x, double value);
|
||||||
|
|
||||||
|
// KEYBOARD INPUT
|
||||||
|
|
||||||
|
#define IN_KEYBOARD_1 0
|
||||||
|
#define IN_KEYBOARD_2 1
|
||||||
|
#define IN_KEYBOARD_3 2
|
||||||
|
#define IN_KEYBOARD_4 3
|
||||||
|
#define IN_KEYBOARD_A 4
|
||||||
|
|
||||||
|
#define IN_KEYBOARD_X 5
|
||||||
|
#define IN_KEYBOARD_7 6
|
||||||
|
#define IN_KEYBOARD_8 7
|
||||||
|
#define IN_KEYBOARD_9 8
|
||||||
|
#define IN_KEYBOARD_0 9
|
||||||
|
|
||||||
|
// DIGITAL INPUT
|
||||||
|
|
||||||
|
#define IN_SENSOR_MIN 10
|
||||||
|
#define IN_SENSOR_LOW 11
|
||||||
|
#define IN_SENSOR_HIGH 12
|
||||||
|
#define IN_SENSOR_MAX 13
|
||||||
|
|
||||||
|
// ANALOG INPUT
|
||||||
|
|
||||||
|
#define IN_TANK_LEVEL 14
|
||||||
|
#define IN_FLOW_OUT 15
|
||||||
|
#define IN_FLOW_IN 16
|
||||||
|
#define IN_FLOW_DIF 17
|
||||||
|
#define IN_TANK_MIN 18
|
||||||
|
#define IN_TANK_MAX 19
|
||||||
|
#define IN_FLOW_CAP 20
|
||||||
|
|
||||||
|
#define IN_FLOW_1 21
|
||||||
|
#define IN_FLOW_2 22
|
||||||
|
#define IN_FLOW_3 23
|
||||||
|
#define IN_FLOW_4 24
|
||||||
|
|
||||||
|
// DIGITAL OUTPUT
|
||||||
|
|
||||||
|
#define OUT_PUMP_1 25
|
||||||
|
#define OUT_PUMP_2 26
|
||||||
|
#define OUT_PUMP_3 27
|
||||||
|
#define OUT_PUMP_4 28
|
||||||
|
|
||||||
|
#define OUT_DISPLAY_MODE 29
|
||||||
|
#define OUT_DISPLAY_GRAFCET 30
|
||||||
|
|
||||||
|
// ANALOG OUTPUT
|
||||||
|
|
||||||
|
#define OUT_LEVEL_MIN 31
|
||||||
|
#define OUT_LEVEL_LOW 32
|
||||||
|
#define OUT_LEVEL_HIGH 33
|
||||||
|
#define OUT_LEVEL_MAX 34
|
||||||
|
#define OUT_FLOW_PER_PUMP 35
|
||||||
|
#define OUT_FLOW_OUT_AMPLITUDE 36
|
||||||
|
|
||||||
|
#define OUT_BEEP 254
|
||||||
|
#define OUT_END 255
|
||||||
Reference in New Issue
Block a user