Compare commits

2 Commits
main ... ladder

Author SHA1 Message Date
wikano
1532753042 david 2025-12-04 23:08:12 +01:00
wikano
869f498daf ex 4 2025-12-04 22:55:32 +01:00
22 changed files with 1095 additions and 4273 deletions

View File

@@ -1,18 +0,0 @@
Quelles difficultés avez-vous rencontré dans lutilisation de OpenPLC ?
les instructions d'installations pour linux n'étaient pas claires, il fallait soit lancer l'installateur classique soit compiler Open PLC depuis avec le code source.
-> en compilant depuis le code source, il faut utiliser python 2 qui n'est absolument plus disponible sur des distributions normales, j'ai réussi à l'installer sur debian mais je n'ai pas pu installer les paquets pip nécessaires avec
-> en utilsant l'installateur normal, ça fonctionne sauf qu'il faut installer python 3.11 qui est une version antérieure non disponible par défaut.
il faudrait inclure des instructions d'installation claires pour les distributions populaires étant donné que la quasi totalité des étudiant de l'ufr utilisent linux
Comment les avez-vous surmontées (ou pas) ?
le logiciel n'est pas particulièrement bien conçu, très peu d'indications sans devoir passer par la documentation, beaucoup de crashs et comportements étranges en utilisation normale, sans chercher à en produire.
Que pensez-vous sur le développement en langage Ladder (LD) ?
peu d'elements de syntaxe disponibles, par exemple, il n'y a pas d'instructions if else ce qui est assez embetant pour faire un programme de vérifications d'exigences comme les instructions demandées à l'exercice 4 je ne vois pas l'intérêt comparé à par exemple structured text
Inclure dans votre rapport des extraits de votre OpenPLC Editor sur les solutions demandées.

View File

@@ -1,29 +0,0 @@
/*******************************************/
/* FILE GENERATED BY iec2c */
/* Editing this file is not recommended... */
/*******************************************/
#include "iec_std_lib.h"
#include "accessor.h"
#include "POUS.h"
// CONFIGURATION CONFIG0
void RES0_init__(void);
void config_init__(void) {
BOOL retain;
retain = 0;
RES0_init__();
}
void RES0_run__(unsigned long tick);
void config_run__(unsigned long tick) {
RES0_run__(tick);
}
unsigned long long common_ticktime__ = 20000000ULL; /*ns*/
unsigned long greatest_tick_count__ = (unsigned long)0UL; /*tick*/

View File

@@ -1,2 +0,0 @@
#include "beremiz.h"

Binary file not shown.

View File

@@ -1,74 +0,0 @@
void LOGGER_init__(LOGGER *data__, BOOL retain) {
__INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain)
__INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain)
__INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain)
__INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain)
__INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain)
__INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain)
}
// Code part
void LOGGER_body__(LOGGER *data__) {
// Control execution
if (!__GET_VAR(data__->EN)) {
__SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE));
return;
}
else {
__SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE));
}
// Initialise TEMP variables
if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) {
#define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__)
#define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val)
LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len));
#undef GetFbVar
#undef SetFbVar
;
};
__SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,));
goto __end;
__end:
return;
} // LOGGER_body__()
void MOTOR_init__(MOTOR *data__, BOOL retain) {
__INIT_VAR(data__->START,__BOOL_LITERAL(FALSE),retain)
__INIT_VAR(data__->STOP,__BOOL_LITERAL(FALSE),retain)
__INIT_VAR(data__->DELAY,__time_to_timespec(1, 100, 0, 0, 0, 0),retain)
__INIT_VAR(data__->RUNNING,__BOOL_LITERAL(FALSE),retain)
RS_init__(&data__->RS0,retain);
TON_init__(&data__->TON0,retain);
}
// Code part
void MOTOR_body__(MOTOR *data__) {
// Initialise TEMP variables
__SET_VAR(data__->TON0.,IN,,__GET_VAR(data__->START,));
__SET_VAR(data__->TON0.,PT,,__GET_VAR(data__->DELAY,));
TON_body__(&data__->TON0);
__SET_VAR(data__->RS0.,S,,__GET_VAR(data__->TON0.Q,));
__SET_VAR(data__->RS0.,R1,,__GET_VAR(data__->STOP,));
RS_body__(&data__->RS0);
__SET_VAR(data__->,RUNNING,,__GET_VAR(data__->RS0.Q1,));
goto __end;
__end:
return;
} // MOTOR_body__()

View File

@@ -1,50 +0,0 @@
#include "beremiz.h"
#ifndef __POUS_H
#define __POUS_H
#include "accessor.h"
#include "iec_std_lib.h"
__DECLARE_ENUMERATED_TYPE(LOGLEVEL,
LOGLEVEL__CRITICAL,
LOGLEVEL__WARNING,
LOGLEVEL__INFO,
LOGLEVEL__DEBUG
)
// FUNCTION_BLOCK LOGGER
// Data part
typedef struct {
// FB Interface - IN, OUT, IN_OUT variables
__DECLARE_VAR(BOOL,EN)
__DECLARE_VAR(BOOL,ENO)
__DECLARE_VAR(BOOL,TRIG)
__DECLARE_VAR(STRING,MSG)
__DECLARE_VAR(LOGLEVEL,LEVEL)
// FB private variables - TEMP, private and located variables
__DECLARE_VAR(BOOL,TRIG0)
} LOGGER;
void LOGGER_init__(LOGGER *data__, BOOL retain);
// Code part
void LOGGER_body__(LOGGER *data__);
// PROGRAM MOTOR
// Data part
typedef struct {
// PROGRAM Interface - IN, OUT, IN_OUT variables
// PROGRAM private variables - TEMP, private and located variables
__DECLARE_VAR(BOOL,START)
__DECLARE_VAR(BOOL,STOP)
__DECLARE_VAR(TIME,DELAY)
__DECLARE_VAR(BOOL,RUNNING)
RS RS0;
TON TON0;
} MOTOR;
void MOTOR_init__(MOTOR *data__, BOOL retain);
// Code part
void MOTOR_body__(MOTOR *data__);
#endif //__POUS_H

View File

@@ -1,37 +0,0 @@
/*******************************************/
/* FILE GENERATED BY iec2c */
/* Editing this file is not recommended... */
/*******************************************/
#include "iec_std_lib.h"
// RESOURCE RES0
extern unsigned long long common_ticktime__;
#include "accessor.h"
#include "POUS.h"
#include "Config0.h"
#include "POUS.c"
BOOL TASK0;
MOTOR RES0__INSTANCE0;
#define INSTANCE0 RES0__INSTANCE0
void RES0_init__(void) {
BOOL retain;
retain = 0;
TASK0 = __BOOL_LITERAL(FALSE);
MOTOR_init__(&INSTANCE0,retain);
}
void RES0_run__(unsigned long tick) {
TASK0 = !(tick % 1);
if (TASK0) {
MOTOR_body__(&INSTANCE0);
}
}

Binary file not shown.

View File

@@ -1,30 +0,0 @@
// Programs
0;CONFIG0.RES0.INSTANCE0;MOTOR;
// Variables
0;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MOTOR;
1;VAR;CONFIG0.RES0.INSTANCE0.START;CONFIG0.RES0.INSTANCE0.START;BOOL;
2;VAR;CONFIG0.RES0.INSTANCE0.STOP;CONFIG0.RES0.INSTANCE0.STOP;BOOL;
3;VAR;CONFIG0.RES0.INSTANCE0.DELAY;CONFIG0.RES0.INSTANCE0.DELAY;TIME;
4;VAR;CONFIG0.RES0.INSTANCE0.RUNNING;CONFIG0.RES0.INSTANCE0.RUNNING;BOOL;
5;FB;CONFIG0.RES0.INSTANCE0.RS0;CONFIG0.RES0.INSTANCE0.RS0;RS;
6;VAR;CONFIG0.RES0.INSTANCE0.RS0.EN;CONFIG0.RES0.INSTANCE0.RS0.EN;BOOL;
7;VAR;CONFIG0.RES0.INSTANCE0.RS0.ENO;CONFIG0.RES0.INSTANCE0.RS0.ENO;BOOL;
8;VAR;CONFIG0.RES0.INSTANCE0.RS0.S;CONFIG0.RES0.INSTANCE0.RS0.S;BOOL;
9;VAR;CONFIG0.RES0.INSTANCE0.RS0.R1;CONFIG0.RES0.INSTANCE0.RS0.R1;BOOL;
10;VAR;CONFIG0.RES0.INSTANCE0.RS0.Q1;CONFIG0.RES0.INSTANCE0.RS0.Q1;BOOL;
11;FB;CONFIG0.RES0.INSTANCE0.TON0;CONFIG0.RES0.INSTANCE0.TON0;TON;
12;VAR;CONFIG0.RES0.INSTANCE0.TON0.EN;CONFIG0.RES0.INSTANCE0.TON0.EN;BOOL;
13;VAR;CONFIG0.RES0.INSTANCE0.TON0.ENO;CONFIG0.RES0.INSTANCE0.TON0.ENO;BOOL;
14;VAR;CONFIG0.RES0.INSTANCE0.TON0.IN;CONFIG0.RES0.INSTANCE0.TON0.IN;BOOL;
15;VAR;CONFIG0.RES0.INSTANCE0.TON0.PT;CONFIG0.RES0.INSTANCE0.TON0.PT;TIME;
16;VAR;CONFIG0.RES0.INSTANCE0.TON0.Q;CONFIG0.RES0.INSTANCE0.TON0.Q;BOOL;
17;VAR;CONFIG0.RES0.INSTANCE0.TON0.ET;CONFIG0.RES0.INSTANCE0.TON0.ET;TIME;
18;VAR;CONFIG0.RES0.INSTANCE0.TON0.STATE;CONFIG0.RES0.INSTANCE0.TON0.STATE;SINT;
19;VAR;CONFIG0.RES0.INSTANCE0.TON0.PREV_IN;CONFIG0.RES0.INSTANCE0.TON0.PREV_IN;BOOL;
20;VAR;CONFIG0.RES0.INSTANCE0.TON0.CURRENT_TIME;CONFIG0.RES0.INSTANCE0.TON0.CURRENT_TIME;TIME;
21;VAR;CONFIG0.RES0.INSTANCE0.TON0.START_TIME;CONFIG0.RES0.INSTANCE0.TON0.START_TIME;TIME;
// Ticktime
20000000
1 // Programs
2 0;CONFIG0.RES0.INSTANCE0;MOTOR;
3 // Variables
4 0;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MOTOR;
5 1;VAR;CONFIG0.RES0.INSTANCE0.START;CONFIG0.RES0.INSTANCE0.START;BOOL;
6 2;VAR;CONFIG0.RES0.INSTANCE0.STOP;CONFIG0.RES0.INSTANCE0.STOP;BOOL;
7 3;VAR;CONFIG0.RES0.INSTANCE0.DELAY;CONFIG0.RES0.INSTANCE0.DELAY;TIME;
8 4;VAR;CONFIG0.RES0.INSTANCE0.RUNNING;CONFIG0.RES0.INSTANCE0.RUNNING;BOOL;
9 5;FB;CONFIG0.RES0.INSTANCE0.RS0;CONFIG0.RES0.INSTANCE0.RS0;RS;
10 6;VAR;CONFIG0.RES0.INSTANCE0.RS0.EN;CONFIG0.RES0.INSTANCE0.RS0.EN;BOOL;
11 7;VAR;CONFIG0.RES0.INSTANCE0.RS0.ENO;CONFIG0.RES0.INSTANCE0.RS0.ENO;BOOL;
12 8;VAR;CONFIG0.RES0.INSTANCE0.RS0.S;CONFIG0.RES0.INSTANCE0.RS0.S;BOOL;
13 9;VAR;CONFIG0.RES0.INSTANCE0.RS0.R1;CONFIG0.RES0.INSTANCE0.RS0.R1;BOOL;
14 10;VAR;CONFIG0.RES0.INSTANCE0.RS0.Q1;CONFIG0.RES0.INSTANCE0.RS0.Q1;BOOL;
15 11;FB;CONFIG0.RES0.INSTANCE0.TON0;CONFIG0.RES0.INSTANCE0.TON0;TON;
16 12;VAR;CONFIG0.RES0.INSTANCE0.TON0.EN;CONFIG0.RES0.INSTANCE0.TON0.EN;BOOL;
17 13;VAR;CONFIG0.RES0.INSTANCE0.TON0.ENO;CONFIG0.RES0.INSTANCE0.TON0.ENO;BOOL;
18 14;VAR;CONFIG0.RES0.INSTANCE0.TON0.IN;CONFIG0.RES0.INSTANCE0.TON0.IN;BOOL;
19 15;VAR;CONFIG0.RES0.INSTANCE0.TON0.PT;CONFIG0.RES0.INSTANCE0.TON0.PT;TIME;
20 16;VAR;CONFIG0.RES0.INSTANCE0.TON0.Q;CONFIG0.RES0.INSTANCE0.TON0.Q;BOOL;
21 17;VAR;CONFIG0.RES0.INSTANCE0.TON0.ET;CONFIG0.RES0.INSTANCE0.TON0.ET;TIME;
22 18;VAR;CONFIG0.RES0.INSTANCE0.TON0.STATE;CONFIG0.RES0.INSTANCE0.TON0.STATE;SINT;
23 19;VAR;CONFIG0.RES0.INSTANCE0.TON0.PREV_IN;CONFIG0.RES0.INSTANCE0.TON0.PREV_IN;BOOL;
24 20;VAR;CONFIG0.RES0.INSTANCE0.TON0.CURRENT_TIME;CONFIG0.RES0.INSTANCE0.TON0.CURRENT_TIME;TIME;
25 21;VAR;CONFIG0.RES0.INSTANCE0.TON0.START_TIME;CONFIG0.RES0.INSTANCE0.TON0.START_TIME;TIME;
26 // Ticktime
27 20000000

View File

@@ -1,44 +0,0 @@
#ifndef _BEREMIZ_H_
#define _BEREMIZ_H_
/* Beremiz' header file for use by extensions */
#include "iec_types.h"
#define LOG_LEVELS 4
#define LOG_CRITICAL 0
#define LOG_WARNING 1
#define LOG_INFO 2
#define LOG_DEBUG 3
extern unsigned long long common_ticktime__;
#ifdef TARGET_LOGGING_DISABLE
static inline int LogMessage(uint8_t level, char* buf, uint32_t size)
{
(void)level;
(void)buf;
(void)size;
return 0;
}
#else
int LogMessage(uint8_t level, char* buf, uint32_t size);
#endif
long AtomicCompareExchange(long* atomicvar,long compared, long exchange);
void *create_RT_to_nRT_signal(char* name);
void delete_RT_to_nRT_signal(void* handle);
int wait_RT_to_nRT_signal(void* handle);
int unblock_RT_to_nRT_signal(void* handle);
void nRT_reschedule(void);
#ifdef REALTIME_LINUX
#ifndef PLC_THREAD_PRIORITY
#define PLC_THREAD_PRIORITY 80
#endif
#endif
#endif

View File

@@ -13,6 +13,114 @@ PROGRAM motor
RUNNING := RS0.Q1;
END_PROGRAM
PROGRAM traffic_light
VAR
RED : BOOL;
RED0 : BOOL;
ORANGE : BOOL;
GREEN : BOOL;
DELAY : TIME := T#30s;
TON0 : TON;
TON1 : TON;
TON2 : TON;
WAIT : BOOL := 1;
TON3 : TON;
DELAY2 : TIME := T#1s;
DELAY3 : TIME := T#10s;
END_VAR
INITIAL_STEP Step0:
GREEN(N);
COMPUTE_FUNCTION_BLOCKS(S);
END_STEP
ACTION COMPUTE_FUNCTION_BLOCKS:
TON0(IN := WAIT, PT := DELAY);
TON4(IN := WAIT, PT := DELAY3);
TON3(IN := WAIT, PT := DELAY2);
END_ACTION
TRANSITION FROM Step0 TO Step1
:= TON0.Q;
END_TRANSITION
STEP Step1:
ORANGE(N);
END_STEP
TRANSITION FROM Step1 TO Step2
:= TON3.Q;
END_TRANSITION
STEP Step2:
RED(N);
END_STEP
TRANSITION FROM Step2 TO Step0
:= TON4.Q;
END_TRANSITION
END_PROGRAM
PROGRAM automate_controle_commande_ld
VAR
P1_enc : BOOL;
WAIT2 : TIME;
P1_run : BOOL;
P2_enc : BOOL;
P2_run : BOOL;
P3_enc : BOOL;
P3_run : BOOL;
Pump_def : BOOL;
WAIT7 : TIME;
secours : BOOL;
only_one_run : BOOL;
TON0 : TON;
WAIT13 : TIME;
TON1 : TON;
secours_c_ok : BOOL;
CTU0 : CTU;
TON2 : TON;
CTU1 : CTU;
CTU2 : CTU;
req_enc_ok : BOOL;
WAIT15 : TIME;
TON3 : TON;
R_TRIG1 : R_TRIG;
_TMP_GT42_ENO : BOOL;
_TMP_GT42_OUT : BOOL;
R_TRIG2 : R_TRIG;
_TMP_EQ54_OUT : BOOL;
_TMP_EQ53_OUT : BOOL;
_TMP_AND45_ENO : BOOL;
_TMP_AND45_OUT : BOOL;
END_VAR
Pump_def := NOT(P1_run) AND P1_enc OR NOT(P2_run) AND P2_enc OR NOT(P3_run) AND P3_enc;
Pump_def := TRUE;
TON0(IN := TRUE, PT := WAIT7);
secours := TON0.Q;
only_one_run := NOT(P3_run) AND NOT(P2_run) AND P1_run OR NOT(P3_run) AND P2_run AND NOT(P1_run) OR P3_run AND NOT(P2_enc) AND NOT(P1_run);
Pump_def := TRUE;
TON2(IN := TRUE, PT := WAIT13);
R_TRIG1(CLK := );
CTU1(CU := R_TRIG1.Q, R := true);
_TMP_GT42_OUT := GT(EN := TON2.Q, IN1 := CTU1.CV, IN2 := 1, ENO => _TMP_GT42_ENO);
secours_c_ok := _TMP_GT42_OUT;
secours := TRUE;
TON1(IN := TRUE, PT := WAIT2);
R_TRIG2(CLK := P1_enc OR P2_enc OR P3_enc);
CTU0(CU := R_TRIG2.Q, R := true);
_TMP_EQ54_OUT := EQ(CTU0.CV, 1);
CTU2(R := NOT(P1_enc) OR NOT(P2_enc) OR NOT(P3_enc), PV := 1);
_TMP_EQ53_OUT := EQ(CTU2.CV, 1);
_TMP_AND45_OUT := AND(EN := TON1.Q, IN1 := _TMP_EQ54_OUT, IN2 := _TMP_EQ53_OUT, ENO => _TMP_AND45_ENO);
req_enc_ok := _TMP_AND45_OUT;
only_one_run := TRUE;
TON3(IN := TRUE, PT := WAIT15);
only_one_run := NOT(TON3.Q);
END_PROGRAM
CONFIGURATION Config0

View File

@@ -1 +0,0 @@
533fc3297d0bbb235fea6b21736971d0

Binary file not shown.

View File

@@ -36,6 +36,114 @@ PROGRAM motor
RUNNING := RS0.Q1;
END_PROGRAM
PROGRAM traffic_light
VAR
RED : BOOL;
RED0 : BOOL;
ORANGE : BOOL;
GREEN : BOOL;
DELAY : TIME := T#30s;
TON0 : TON;
TON1 : TON;
TON2 : TON;
WAIT : BOOL := 1;
TON3 : TON;
DELAY2 : TIME := T#1s;
DELAY3 : TIME := T#10s;
END_VAR
INITIAL_STEP Step0:
GREEN(N);
COMPUTE_FUNCTION_BLOCKS(S);
END_STEP
ACTION COMPUTE_FUNCTION_BLOCKS:
TON0(IN := WAIT, PT := DELAY);
TON4(IN := WAIT, PT := DELAY3);
TON3(IN := WAIT, PT := DELAY2);
END_ACTION
TRANSITION FROM Step0 TO Step1
:= TON0.Q;
END_TRANSITION
STEP Step1:
ORANGE(N);
END_STEP
TRANSITION FROM Step1 TO Step2
:= TON3.Q;
END_TRANSITION
STEP Step2:
RED(N);
END_STEP
TRANSITION FROM Step2 TO Step0
:= TON4.Q;
END_TRANSITION
END_PROGRAM
PROGRAM automate_controle_commande_ld
VAR
P1_enc : BOOL;
WAIT2 : TIME;
P1_run : BOOL;
P2_enc : BOOL;
P2_run : BOOL;
P3_enc : BOOL;
P3_run : BOOL;
Pump_def : BOOL;
WAIT7 : TIME;
secours : BOOL;
only_one_run : BOOL;
TON0 : TON;
WAIT13 : TIME;
TON1 : TON;
secours_c_ok : BOOL;
CTU0 : CTU;
TON2 : TON;
CTU1 : CTU;
CTU2 : CTU;
req_enc_ok : BOOL;
WAIT15 : TIME;
TON3 : TON;
R_TRIG1 : R_TRIG;
_TMP_GT42_ENO : BOOL;
_TMP_GT42_OUT : BOOL;
R_TRIG2 : R_TRIG;
_TMP_EQ54_OUT : BOOL;
_TMP_EQ53_OUT : BOOL;
_TMP_AND45_ENO : BOOL;
_TMP_AND45_OUT : BOOL;
END_VAR
Pump_def := NOT(P1_run) AND P1_enc OR NOT(P2_run) AND P2_enc OR NOT(P3_run) AND P3_enc;
Pump_def := TRUE;
TON0(IN := TRUE, PT := WAIT7);
secours := TON0.Q;
only_one_run := NOT(P3_run) AND NOT(P2_run) AND P1_run OR NOT(P3_run) AND P2_run AND NOT(P1_run) OR P3_run AND NOT(P2_enc) AND NOT(P1_run);
Pump_def := TRUE;
TON2(IN := TRUE, PT := WAIT13);
R_TRIG1(CLK := );
CTU1(CU := R_TRIG1.Q, R := true);
_TMP_GT42_OUT := GT(EN := TON2.Q, IN1 := CTU1.CV, IN2 := 1, ENO => _TMP_GT42_ENO);
secours_c_ok := _TMP_GT42_OUT;
secours := TRUE;
TON1(IN := TRUE, PT := WAIT2);
R_TRIG2(CLK := P1_enc OR P2_enc OR P3_enc);
CTU0(CU := R_TRIG2.Q, R := true);
_TMP_EQ54_OUT := EQ(CTU0.CV, 1);
CTU2(R := NOT(P1_enc) OR NOT(P2_enc) OR NOT(P3_enc), PV := 1);
_TMP_EQ53_OUT := EQ(CTU2.CV, 1);
_TMP_AND45_OUT := AND(EN := TON1.Q, IN1 := _TMP_EQ54_OUT, IN2 := _TMP_EQ53_OUT, ENO => _TMP_AND45_ENO);
req_enc_ok := _TMP_AND45_OUT;
only_one_run := TRUE;
TON3(IN := TRUE, PT := WAIT15);
only_one_run := NOT(TON3.Q);
END_PROGRAM
CONFIGURATION Config0

View File

@@ -1,548 +0,0 @@
/*
* DEBUGGER code
*
* On "publish", when buffer is free, debugger stores arbitrary variables
* content into, and mark this buffer as filled
*
*
* Buffer content is read asynchronously, (from non real time part),
* and then buffer marked free again.
*
*
* */
#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE
void __init_debug (void){}
void __cleanup_debug (void){}
void __retrieve_debug(void){}
void __publish_debug (void){}
#else
#include "iec_types_all.h"
#include "POUS.h"
/*for memcpy*/
#include <string.h>
#include <stdio.h>
typedef unsigned int dbgvardsc_index_t;
typedef unsigned short trace_buf_offset_t;
#define BUFFER_EMPTY 0
#define BUFFER_FULL 1
#ifndef TARGET_ONLINE_DEBUG_DISABLE
#define TRACE_BUFFER_SIZE 4096
#define TRACE_LIST_SIZE 1024
/* Atomically accessed variable for buffer state */
static long trace_buffer_state = BUFFER_EMPTY;
typedef struct trace_item_s {
dbgvardsc_index_t dbgvardsc_index;
} trace_item_t;
trace_item_t trace_list[TRACE_LIST_SIZE];
char trace_buffer[TRACE_BUFFER_SIZE];
/* Trace's cursor*/
static trace_item_t *trace_list_collect_cursor = trace_list;
static trace_item_t *trace_list_addvar_cursor = trace_list;
static const trace_item_t *trace_list_end =
&trace_list[TRACE_LIST_SIZE-1];
static char *trace_buffer_cursor = trace_buffer;
static const char *trace_buffer_end = trace_buffer + TRACE_BUFFER_SIZE;
#define FORCE_BUFFER_SIZE 1024
#define FORCE_LIST_SIZE 256
typedef struct force_item_s {
dbgvardsc_index_t dbgvardsc_index;
void *value_pointer_backup;
} force_item_t;
force_item_t force_list[FORCE_LIST_SIZE];
char force_buffer[FORCE_BUFFER_SIZE];
/* Force's cursor*/
static force_item_t *force_list_apply_cursor = force_list;
static force_item_t *force_list_addvar_cursor = force_list;
static const force_item_t *force_list_end =
&force_list[FORCE_LIST_SIZE-1];
static char *force_buffer_cursor = force_buffer;
static const char *force_buffer_end = force_buffer + FORCE_BUFFER_SIZE;
#endif
/***
* Declare programs
**/
extern MOTOR RES0__INSTANCE0;
/***
* Declare global variables from resources and conf
**/
extern MOTOR RES0__INSTANCE0;
typedef const struct {
void *ptr;
__IEC_types_enum type;
} dbgvardsc_t;
static const dbgvardsc_t dbgvardsc[] = {
{&(RES0__INSTANCE0.START), BOOL_ENUM},
{&(RES0__INSTANCE0.STOP), BOOL_ENUM},
{&(RES0__INSTANCE0.DELAY), TIME_ENUM},
{&(RES0__INSTANCE0.RUNNING), BOOL_ENUM},
{&(RES0__INSTANCE0.RS0.EN), BOOL_ENUM},
{&(RES0__INSTANCE0.RS0.ENO), BOOL_ENUM},
{&(RES0__INSTANCE0.RS0.S), BOOL_ENUM},
{&(RES0__INSTANCE0.RS0.R1), BOOL_ENUM},
{&(RES0__INSTANCE0.RS0.Q1), BOOL_ENUM},
{&(RES0__INSTANCE0.TON0.EN), BOOL_ENUM},
{&(RES0__INSTANCE0.TON0.ENO), BOOL_ENUM},
{&(RES0__INSTANCE0.TON0.IN), BOOL_ENUM},
{&(RES0__INSTANCE0.TON0.PT), TIME_ENUM},
{&(RES0__INSTANCE0.TON0.Q), BOOL_ENUM},
{&(RES0__INSTANCE0.TON0.ET), TIME_ENUM},
{&(RES0__INSTANCE0.TON0.STATE), SINT_ENUM},
{&(RES0__INSTANCE0.TON0.PREV_IN), BOOL_ENUM},
{&(RES0__INSTANCE0.TON0.CURRENT_TIME), TIME_ENUM},
{&(RES0__INSTANCE0.TON0.START_TIME), TIME_ENUM}
};
static const dbgvardsc_index_t retain_list[] = {
};
static unsigned int retain_list_collect_cursor = 0;
static const unsigned int retain_list_size = sizeof(retain_list)/sizeof(dbgvardsc_index_t);
typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*);
void __for_each_variable_do(__for_each_variable_do_fp fp)
{
unsigned int i;
for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){
dbgvardsc_t *dsc = &dbgvardsc[i];
if(dsc->type != UNKNOWN_ENUM)
(*fp)(dsc);
}
}
#define __Unpack_desc_type dbgvardsc_t
#define __Unpack_case_t(TYPENAME) \
case TYPENAME##_ENUM : \
if(flags) *flags = ((__IEC_##TYPENAME##_t *)varp)->flags; \
if(value_p) *value_p = &((__IEC_##TYPENAME##_t *)varp)->value; \
if(size) *size = sizeof(TYPENAME); \
break;
#define __Unpack_case_p(TYPENAME) \
case TYPENAME##_O_ENUM : \
case TYPENAME##_P_ENUM : \
if(flags) *flags = ((__IEC_##TYPENAME##_p *)varp)->flags; \
if(value_p) *value_p = ((__IEC_##TYPENAME##_p *)varp)->value; \
if(size) *size = sizeof(TYPENAME); \
break;
#define __Is_a_string(dsc) (dsc->type == STRING_ENUM) ||\
(dsc->type == STRING_P_ENUM) ||\
(dsc->type == STRING_O_ENUM)
static int UnpackVar(__Unpack_desc_type *dsc, void **value_p, char *flags, size_t *size)
{
void *varp = dsc->ptr;
/* find data to copy*/
switch(dsc->type){
__ANY(__Unpack_case_t)
__ANY(__Unpack_case_p)
default:
return 0; /* should never happen */
}
return 1;
}
void Remind(unsigned int offset, unsigned int count, void * p);
extern int CheckRetainBuffer(void);
extern void InitRetain(void);
void __init_debug(void)
{
/* init local static vars */
#ifndef TARGET_ONLINE_DEBUG_DISABLE
trace_buffer_cursor = trace_buffer;
trace_list_addvar_cursor = trace_list;
trace_list_collect_cursor = trace_list;
trace_buffer_state = BUFFER_EMPTY;
force_buffer_cursor = force_buffer;
force_list_addvar_cursor = force_list;
force_list_apply_cursor = force_list;
#endif
InitRetain();
/* Iterate over all variables to fill debug buffer */
if(CheckRetainBuffer()){
unsigned int retain_offset = 0;
retain_list_collect_cursor = 0;
/* iterate over retain list */
while(retain_list_collect_cursor < retain_list_size){
void *value_p = NULL;
size_t size;
char* next_cursor;
dbgvardsc_t *dsc = &dbgvardsc[
retain_list[retain_list_collect_cursor]];
UnpackVar(dsc, &value_p, NULL, &size);
/* if buffer not full */
Remind(retain_offset, size, value_p);
/* increment cursor according size*/
retain_offset += size;
retain_list_collect_cursor++;
}
}else{
char mstr[] = "RETAIN memory invalid - defaults used";
LogMessage(LOG_WARNING, mstr, sizeof(mstr));
}
}
extern void InitiateDebugTransfer(void);
extern void CleanupRetain(void);
extern unsigned long __tick;
void __cleanup_debug(void)
{
#ifndef TARGET_ONLINE_DEBUG_DISABLE
trace_buffer_cursor = trace_buffer;
InitiateDebugTransfer();
#endif
CleanupRetain();
}
void __retrieve_debug(void)
{
}
void Retain(unsigned int offset, unsigned int count, void * p);
/* Return size of all retain variables */
unsigned int GetRetainSize(void)
{
unsigned int retain_size = 0;
retain_list_collect_cursor = 0;
/* iterate over retain list */
while(retain_list_collect_cursor < retain_list_size){
void *value_p = NULL;
size_t size;
char* next_cursor;
dbgvardsc_t *dsc = &dbgvardsc[
retain_list[retain_list_collect_cursor]];
UnpackVar(dsc, &value_p, NULL, &size);
retain_size += size;
retain_list_collect_cursor++;
}
return retain_size;
}
extern void PLC_GetTime(IEC_TIME*);
extern int TryEnterDebugSection(void);
extern long AtomicCompareExchange(long*, long, long);
extern long long AtomicCompareExchange64(long long* , long long , long long);
extern void LeaveDebugSection(void);
extern void ValidateRetainBuffer(void);
extern void InValidateRetainBuffer(void);
#define __ReForceOutput_case_p(TYPENAME) \
case TYPENAME##_P_ENUM : \
case TYPENAME##_O_ENUM : \
{ \
char *next_cursor = force_buffer_cursor + sizeof(TYPENAME); \
if(next_cursor <= force_buffer_end ){ \
/* outputs real value must be systematically forced */ \
if(vartype == TYPENAME##_O_ENUM) \
/* overwrite value pointed by backup */ \
*((TYPENAME *)force_list_apply_cursor->value_pointer_backup) = \
*((TYPENAME *)force_buffer_cursor); \
/* inc force_buffer cursor */ \
force_buffer_cursor = next_cursor; \
}else{ \
stop = 1; \
} \
} \
break;
void __publish_debug(void)
{
InValidateRetainBuffer();
#ifndef TARGET_ONLINE_DEBUG_DISABLE
/* Check there is no running debugger re-configuration */
if(TryEnterDebugSection()){
/* Lock buffer */
long latest_state = AtomicCompareExchange(
&trace_buffer_state,
BUFFER_EMPTY,
BUFFER_FULL);
/* If buffer was free */
if(latest_state == BUFFER_EMPTY)
{
int stop = 0;
/* Reset force list cursor */
force_list_apply_cursor = force_list;
/* iterate over force list */
while(!stop && force_list_apply_cursor < force_list_addvar_cursor){
dbgvardsc_t *dsc = &dbgvardsc[
force_list_apply_cursor->dbgvardsc_index];
void *varp = dsc->ptr;
__IEC_types_enum vartype = dsc->type;
switch(vartype){
__ANY(__ReForceOutput_case_p)
default:
break;
}
force_list_apply_cursor++;
}
/* Reset buffer cursor */
trace_buffer_cursor = trace_buffer;
/* Reset trace list cursor */
trace_list_collect_cursor = trace_list;
/* iterate over trace list */
while(trace_list_collect_cursor < trace_list_addvar_cursor){
void *value_p = NULL;
size_t size;
char* next_cursor;
dbgvardsc_t *dsc = &dbgvardsc[
trace_list_collect_cursor->dbgvardsc_index];
UnpackVar(dsc, &value_p, NULL, &size);
/* copy visible variable to buffer */;
if(__Is_a_string(dsc)){
/* optimization for strings */
/* assume NULL terminated strings */
size = ((STRING*)value_p)->len + 1;
}
/* compute next cursor positon.*/
next_cursor = trace_buffer_cursor + size;
/* check for buffer overflow */
if(next_cursor < trace_buffer_end)
/* copy data to the buffer */
memcpy(trace_buffer_cursor, value_p, size);
else
/* stop looping in case of overflow */
break;
/* increment cursor according size*/
trace_buffer_cursor = next_cursor;
trace_list_collect_cursor++;
}
/* Leave debug section,
* Trigger asynchronous transmission
* (returns immediately) */
InitiateDebugTransfer(); /* size */
}
LeaveDebugSection();
}
#endif
unsigned int retain_offset = 0;
/* when not debugging, do only retain */
retain_list_collect_cursor = 0;
/* iterate over retain list */
while(retain_list_collect_cursor < retain_list_size){
void *value_p = NULL;
size_t size;
char* next_cursor;
dbgvardsc_t *dsc = &dbgvardsc[
retain_list[retain_list_collect_cursor]];
UnpackVar(dsc, &value_p, NULL, &size);
/* if buffer not full */
Retain(retain_offset, size, value_p);
/* increment cursor according size*/
retain_offset += size;
retain_list_collect_cursor++;
}
ValidateRetainBuffer();
}
#ifndef TARGET_ONLINE_DEBUG_DISABLE
#define TRACE_LIST_OVERFLOW 1
#define FORCE_LIST_OVERFLOW 2
#define FORCE_BUFFER_OVERFLOW 3
#define __ForceVariable_case_t(TYPENAME) \
case TYPENAME##_ENUM : \
/* add to force_list*/ \
force_list_addvar_cursor->dbgvardsc_index = idx; \
((__IEC_##TYPENAME##_t *)varp)->flags |= __IEC_FORCE_FLAG; \
((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force); \
break;
#define __ForceVariable_case_p(TYPENAME) \
case TYPENAME##_P_ENUM : \
case TYPENAME##_O_ENUM : \
{ \
char *next_cursor = force_buffer_cursor + sizeof(TYPENAME); \
if(next_cursor <= force_buffer_end ){ \
/* add to force_list*/ \
force_list_addvar_cursor->dbgvardsc_index = idx; \
/* save pointer to backup */ \
force_list_addvar_cursor->value_pointer_backup = \
((__IEC_##TYPENAME##_p *)varp)->value; \
/* store forced value in force_buffer */ \
*((TYPENAME *)force_buffer_cursor) = *((TYPENAME *)force); \
/* replace pointer with pointer to force_buffer */ \
((__IEC_##TYPENAME##_p *)varp)->value = \
(TYPENAME *)force_buffer_cursor; \
(((__IEC_##TYPENAME##_p *)varp)->fvalue) = *((TYPENAME *)force); \
/* mark variable as forced */ \
((__IEC_##TYPENAME##_p *)varp)->flags |= __IEC_FORCE_FLAG; \
/* inc force_buffer cursor */ \
force_buffer_cursor = next_cursor; \
/* outputs real value must be systematically forced */ \
if(vartype == TYPENAME##_O_ENUM) \
*(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\
} else { \
error_code = FORCE_BUFFER_OVERFLOW; \
goto error_cleanup; \
} \
} \
break;
void ResetDebugVariables(void);
int RegisterDebugVariable(dbgvardsc_index_t idx, void* force)
{
int error_code = 0;
if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){
/* add to trace_list, inc trace_list_addvar_cursor*/
if(trace_list_addvar_cursor <= trace_list_end){
trace_list_addvar_cursor->dbgvardsc_index = idx;
trace_list_addvar_cursor++;
} else {
error_code = TRACE_LIST_OVERFLOW;
goto error_cleanup;
}
if(force){
if(force_list_addvar_cursor <= force_list_end){
dbgvardsc_t *dsc = &dbgvardsc[idx];
void *varp = dsc->ptr;
__IEC_types_enum vartype = dsc->type;
switch(vartype){
__ANY(__ForceVariable_case_t)
__ANY(__ForceVariable_case_p)
default:
break;
}
/* inc force_list cursor */
force_list_addvar_cursor++;
} else {
error_code = FORCE_LIST_OVERFLOW;
goto error_cleanup;
}
}
}
return 0;
error_cleanup:
ResetDebugVariables();
trace_buffer_state = BUFFER_EMPTY;
return error_code;
}
#define ResetForcedVariable_case_t(TYPENAME) \
case TYPENAME##_ENUM : \
((__IEC_##TYPENAME##_t *)varp)->flags &= ~__IEC_FORCE_FLAG; \
/* for local variable we don't restore original value */ \
/* that can be added if needed, but it was like that since ever */ \
break;
#define ResetForcedVariable_case_p(TYPENAME) \
case TYPENAME##_P_ENUM : \
case TYPENAME##_O_ENUM : \
((__IEC_##TYPENAME##_p *)varp)->flags &= ~__IEC_FORCE_FLAG; \
/* restore backup to pointer */ \
((__IEC_##TYPENAME##_p *)varp)->value = \
force_list_apply_cursor->value_pointer_backup; \
break;
void ResetDebugVariables(void)
{
/* Reset trace list */
trace_list_addvar_cursor = trace_list;
force_list_apply_cursor = force_list;
/* Restore forced variables */
while(force_list_apply_cursor < force_list_addvar_cursor){
dbgvardsc_t *dsc = &dbgvardsc[
force_list_apply_cursor->dbgvardsc_index];
void *varp = dsc->ptr;
switch(dsc->type){
__ANY(ResetForcedVariable_case_t)
__ANY(ResetForcedVariable_case_p)
default:
break;
}
/* inc force_list cursor */
force_list_apply_cursor++;
} /* else TODO: warn user about failure to force */
/* Reset force list */
force_list_addvar_cursor = force_list;
/* Reset force buffer */
force_buffer_cursor = force_buffer;
}
void FreeDebugData(void)
{
/* atomically mark buffer as free */
AtomicCompareExchange(
&trace_buffer_state,
BUFFER_FULL,
BUFFER_EMPTY);
}
int WaitDebugData(unsigned long *tick);
/* Wait until debug data ready and return pointer to it */
int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){
int wait_error = WaitDebugData(tick);
if(!wait_error){
*size = trace_buffer_cursor - trace_buffer;
*buffer = trace_buffer;
}
return wait_error;
}
#endif
#endif

Binary file not shown.

View File

@@ -1,980 +0,0 @@
/**
* Head of code common to all C targets
**/
#include "beremiz.h"
#include <string.h>
/*
* Prototypes of functions provided by generated C softPLC
**/
void config_run__(unsigned long tick);
void config_init__(void);
/*
* Prototypes of functions provided by generated target C code
* */
long long AtomicCompareExchange64(long long*, long long, long long);
void __init_debug(void);
void __cleanup_debug(void);
/*void __retrieve_debug(void);*/
void __publish_debug(void);
/*
* Variables used by generated C softPLC and plugins
**/
IEC_TIME __CURRENT_TIME;
IEC_BOOL __DEBUG = 0;
unsigned long __tick = 0;
char *PLC_ID = NULL;
/*
* Variable generated by C softPLC and plugins
**/
extern unsigned long greatest_tick_count__;
/* Help to quit cleanly when init fail at a certain level */
static int init_level = 0;
/*
* Prototypes of functions exported by plugins
**/
/*
* Retrieve input variables, run PLC and publish output variables
**/
void __run(void)
{
__tick++;
if (greatest_tick_count__)
__tick %= greatest_tick_count__;
/*__retrieve_debug();*/
config_run__(__tick);
__publish_debug();
}
/*
* Initialize variables according to PLC's default values,
* and then init plugins with that values
**/
int __init(int argc,char **argv)
{
int res = 0;
init_level = 0;
/* Effective tick time with 1ms default value */
if(!common_ticktime__)
common_ticktime__ = 1000000;
config_init__();
__init_debug();
return res;
}
/*
* Calls plugin cleanup proc.
**/
void __cleanup(void)
{
__cleanup_debug();
}
void PLC_GetTime(IEC_TIME *CURRENT_TIME);
void PLC_SetTimer(unsigned long long next, unsigned long long period);
/**
* Win32 specific code
**/
#include <stdio.h>
#include <sys/timeb.h>
#include <time.h>
#include <windows.h>
#include <locale.h>
long AtomicCompareExchange(long* atomicvar, long compared, long exchange)
{
return InterlockedCompareExchange(atomicvar, exchange, compared);
}
CRITICAL_SECTION Atomic64CS;
long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange)
{
long long res;
EnterCriticalSection(&Atomic64CS);
res=*atomicvar;
if(*atomicvar == compared){
*atomicvar = exchange;
}
LeaveCriticalSection(&Atomic64CS);
return res;
}
struct timeb timetmp;
void PLC_GetTime(IEC_TIME *CURRENT_TIME)
{
ftime(&timetmp);
(*CURRENT_TIME).tv_sec = timetmp.time;
(*CURRENT_TIME).tv_nsec = timetmp.millitm * 1000000;
}
HANDLE PLC_timer = NULL;
void PLC_SetTimer(unsigned long long next, unsigned long long period)
{
LARGE_INTEGER liDueTime;
/* arg 2 of SetWaitableTimer take 100 ns interval*/
liDueTime.QuadPart = next / (-100);
if (!SetWaitableTimer(PLC_timer, &liDueTime, period<1000000?1:period/1000000, NULL, NULL, 0))
{
printf("SetWaitableTimer failed (%d)\n", GetLastError());
}
}
int PLC_shutdown;
int ForceSaveRetainReq(void) {
return PLC_shutdown;
}
/* Variable used to stop plcloop thread */
void PlcLoop()
{
PLC_shutdown = 0;
while(!PLC_shutdown) {
if (WaitForSingleObject(PLC_timer, INFINITE) != WAIT_OBJECT_0){
PLC_shutdown = 1;
break;
}
PLC_GetTime(&__CURRENT_TIME);
__run();
}
}
HANDLE PLC_thread;
HANDLE debug_sem;
HANDLE debug_wait_sem;
HANDLE python_sem;
HANDLE python_wait_sem;
#define maxval(a,b) ((a>b)?a:b)
int startPLC(int argc,char **argv)
{
unsigned long thread_id = 0;
BOOL tmp;
debug_sem = CreateSemaphore(
NULL, // default security attributes
1, // initial count
1, // maximum count
NULL); // unnamed semaphore
if (debug_sem == NULL)
{
printf("startPLC CreateSemaphore debug_sem error: %d\n", GetLastError());
return 1;
}
debug_wait_sem = CreateSemaphore(
NULL, // default security attributes
0, // initial count
1, // maximum count
NULL); // unnamed semaphore
if (debug_wait_sem == NULL)
{
printf("startPLC CreateSemaphore debug_wait_sem error: %d\n", GetLastError());
return 1;
}
python_sem = CreateSemaphore(
NULL, // default security attributes
1, // initial count
1, // maximum count
NULL); // unnamed semaphore
if (python_sem == NULL)
{
printf("startPLC CreateSemaphore python_sem error: %d\n", GetLastError());
return 1;
}
python_wait_sem = CreateSemaphore(
NULL, // default security attributes
0, // initial count
1, // maximum count
NULL); // unnamed semaphore
if (python_wait_sem == NULL)
{
printf("startPLC CreateSemaphore python_wait_sem error: %d\n", GetLastError());
return 1;
}
/* Create a waitable timer */
timeBeginPeriod(1);
PLC_timer = CreateWaitableTimer(NULL, FALSE, "WaitableTimer");
if(NULL == PLC_timer)
{
printf("CreateWaitableTimer failed (%d)\n", GetLastError());
return 1;
}
if( __init(argc,argv) == 0 )
{
PLC_SetTimer(common_ticktime__,common_ticktime__);
PLC_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PlcLoop, NULL, 0, &thread_id);
}
else{
return 1;
}
return 0;
}
static unsigned long __debug_tick;
int TryEnterDebugSection(void)
{
//printf("TryEnterDebugSection\n");
if(WaitForSingleObject(debug_sem, 0) == WAIT_OBJECT_0){
/* Only enter if debug active */
if(__DEBUG){
return 1;
}
ReleaseSemaphore(debug_sem, 1, NULL);
}
return 0;
}
void LeaveDebugSection(void)
{
ReleaseSemaphore(debug_sem, 1, NULL);
//printf("LeaveDebugSection\n");
}
int stopPLC()
{
PLC_shutdown = 1;
// force last wakeup of PLC thread
SetWaitableTimer(PLC_timer, 0, 0, NULL, NULL, 0);
// wait end of PLC thread
WaitForSingleObject(PLC_thread, INFINITE);
__cleanup();
CloseHandle(PLC_timer);
CloseHandle(debug_wait_sem);
CloseHandle(debug_sem);
CloseHandle(python_wait_sem);
CloseHandle(python_sem);
CloseHandle(PLC_thread);
}
/* from plc_debugger.c */
int WaitDebugData(unsigned long *tick)
{
DWORD res;
res = WaitForSingleObject(debug_wait_sem, INFINITE);
*tick = __debug_tick;
/* Wait signal from PLC thread */
return res != WAIT_OBJECT_0;
}
/* Called by PLC thread when debug_publish finished
* This is supposed to unlock debugger thread in WaitDebugData*/
void InitiateDebugTransfer()
{
/* remember tick */
__debug_tick = __tick;
/* signal debugger thread it can read data */
ReleaseSemaphore(debug_wait_sem, 1, NULL);
}
int suspendDebug(int disable)
{
/* Prevent PLC to enter debug code */
WaitForSingleObject(debug_sem, INFINITE);
__DEBUG = !disable;
if(disable)
ReleaseSemaphore(debug_sem, 1, NULL);
return 0;
}
void resumeDebug()
{
__DEBUG = 1;
/* Let PLC enter debug code */
ReleaseSemaphore(debug_sem, 1, NULL);
}
/* from plc_python.c */
int WaitPythonCommands(void)
{
/* Wait signal from PLC thread */
return WaitForSingleObject(python_wait_sem, INFINITE);
}
/* Called by PLC thread on each new python command*/
void UnBlockPythonCommands(void)
{
/* signal debugger thread it can read data */
ReleaseSemaphore(python_wait_sem, 1, NULL);
}
int TryLockPython(void)
{
return WaitForSingleObject(python_sem, 0) == WAIT_OBJECT_0;
}
void UnLockPython(void)
{
ReleaseSemaphore(python_sem, 1, NULL);
}
void LockPython(void)
{
WaitForSingleObject(python_sem, INFINITE);
}
static void __attribute__((constructor))
beremiz_dll_init(void)
{
InitializeCriticalSection(&Atomic64CS);
}
static void __attribute__((destructor))
beremiz_dll_destroy(void)
{
DeleteCriticalSection(&Atomic64CS);
}
struct RT_to_nRT_signal_s {
HANDLE sem;
};
typedef struct RT_to_nRT_signal_s RT_to_nRT_signal_t;
#define _LogAndReturnNull(text) \
{\
char mstr[256] = text " for ";\
strncat(mstr, name, 255);\
LogMessage(LOG_CRITICAL, mstr, strlen(mstr));\
return NULL;\
}
void *create_RT_to_nRT_signal(char* name){
RT_to_nRT_signal_t *sig = (RT_to_nRT_signal_t*)malloc(sizeof(RT_to_nRT_signal_t));
if(!sig)
_LogAndReturnNull("Failed allocating memory for RT_to_nRT signal");
sig->sem = CreateSemaphore(
NULL, // default security attributes
1, // initial count
1, // maximum count
NULL); // unnamed semaphore
if(sig->sem == NULL)
{
char mstr[256];
snprintf(mstr, 255, "startPLC CreateSemaphore %s error: %d\n", name, GetLastError());
LogMessage(LOG_CRITICAL, mstr, strlen(mstr));
return NULL;
}
return (void*)sig;
}
void delete_RT_to_nRT_signal(void* handle){
RT_to_nRT_signal_t *sig = (RT_to_nRT_signal_t*)handle;
CloseHandle(python_sem);
free(sig);
}
int wait_RT_to_nRT_signal(void* handle){
int ret;
RT_to_nRT_signal_t *sig = (RT_to_nRT_signal_t*)handle;
return WaitForSingleObject(sig->sem, INFINITE);
}
int unblock_RT_to_nRT_signal(void* handle){
RT_to_nRT_signal_t *sig = (RT_to_nRT_signal_t*)handle;
return ReleaseSemaphore(sig->sem, 1, NULL);
}
void nRT_reschedule(void){
SwitchToThread();
}
/*
This file is part of Beremiz, a Integrated Development Environment for
programming IEC 61131-3 automates supporting plcopen standard and CanFestival.
See COPYING.runtime
Copyright (C) 2018: Sergey Surkov <surkov.sv@summatechnology.ru>
Copyright (C) 2018: Andrey Skvortsov <andrej.skvortzov@gmail.com>
*/
#ifndef HAVE_RETAIN
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include "iec_types.h"
int GetRetainSize(void);
/* Retain buffer. */
FILE *retain_buffer;
const char rb_file[] = "retain_buffer_file";
const char rb_file_bckp[] = "retain_buffer_file.bak";
/* Retain header struct. */
struct retain_info_t {
uint32_t retain_size;
uint32_t hash_size;
uint8_t* hash;
uint32_t header_offset;
uint32_t header_crc;
};
/* Init retain info structure. */
struct retain_info_t retain_info;
/* CRC lookup table and initial state. */
static const uint32_t crc32_table[256] = {
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
};
uint32_t retain_crc;
/* Calculate CRC32 for len bytes from pointer buf with init starting value. */
uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init)
{
uint32_t crc = ~init;
unsigned char* current = (unsigned char*) buf;
while (len--)
crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8);
return ~crc;
}
/* Calc CRC32 for retain file byte by byte. */
int CheckFileCRC(FILE* file_buffer)
{
/* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */
const uint32_t magic_number = 0x2144df1c;
/* CRC initial state. */
uint32_t calc_crc32 = 0;
char data_block = 0;
while(!feof(file_buffer)){
if (fread(&data_block, sizeof(data_block), 1, file_buffer))
calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(data_block), calc_crc32);
}
/* Compare crc result with a magic number. */
return (calc_crc32 == magic_number) ? 1 : 0;
}
/* Compare current hash with hash from file byte by byte. */
int CheckFilehash(void)
{
unsigned int k;
int offset = sizeof(retain_info.retain_size);
rewind(retain_buffer);
fseek(retain_buffer, offset , SEEK_SET);
uint32_t size;
fread(&size, sizeof(size), 1, retain_buffer);
if (size != retain_info.hash_size)
return 0;
for(k = 0; k < retain_info.hash_size; k++){
uint8_t file_digit;
fread(&file_digit, sizeof(file_digit), 1, retain_buffer);
if (file_digit != *(retain_info.hash+k))
return 0;
}
return 1;
}
void InitRetain(void)
{
unsigned int i;
/* Get retain size in bytes */
retain_info.retain_size = GetRetainSize();
/* Hash stored in retain file as array of char in hex digits
(that's why we divide strlen in two). */
retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0;
//retain_info.hash_size = 0;
retain_info.hash = malloc(retain_info.hash_size);
/* Transform hash string into byte sequence. */
for (i = 0; i < retain_info.hash_size; i++) {
int byte = 0;
sscanf((PLC_ID + i*2), "%02X", &byte);
retain_info.hash[i] = byte;
}
/* Calc header offset. */
retain_info.header_offset = sizeof(retain_info.retain_size) + \
sizeof(retain_info.hash_size) + \
retain_info.hash_size;
/* Set header CRC initial state. */
retain_info.header_crc = 0;
/* Calc crc for header. */
retain_info.header_crc = GenerateCRC32Sum(
&retain_info.retain_size,
sizeof(retain_info.retain_size),
retain_info.header_crc);
retain_info.header_crc = GenerateCRC32Sum(
&retain_info.hash_size,
sizeof(retain_info.hash_size),
retain_info.header_crc);
retain_info.header_crc = GenerateCRC32Sum(
retain_info.hash,
retain_info.hash_size,
retain_info.header_crc);
}
void CleanupRetain(void)
{
/* Free hash memory. */
free(retain_info.hash);
}
int CheckRetainFile(const char * file)
{
retain_buffer = fopen(file, "rb");
if (retain_buffer) {
/* Check CRC32 and hash. */
if (CheckFileCRC(retain_buffer))
if (CheckFilehash())
return 1;
fclose(retain_buffer);
retain_buffer = NULL;
}
return 0;
}
int CheckRetainBuffer(void)
{
retain_buffer = NULL;
if (!retain_info.retain_size)
return 1;
/* Check latest retain file. */
if (CheckRetainFile(rb_file))
return 1;
/* Check if we have backup. */
if (CheckRetainFile(rb_file_bckp))
return 1;
/* We don't have any valid retain buffer - nothing to remind. */
return 0;
}
#ifndef FILE_RETAIN_SAVE_PERIOD_S
#define FILE_RETAIN_SAVE_PERIOD_S 1.0
#endif
static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2)
{
IEC_TIME dt ={
t1->tv_sec - t2->tv_sec,
t1->tv_nsec - t2->tv_nsec
};
if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){
dt.tv_sec--;
dt.tv_nsec += 1000000000;
}
if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){
dt.tv_sec++;
dt.tv_nsec -= 1000000000;
}
return dt.tv_sec + 1e-9*dt.tv_nsec;
}
int RetainSaveNeeded(void)
{
int ret = 0;
static IEC_TIME last_save;
IEC_TIME now;
double diff_s;
/* no retain */
if (!retain_info.retain_size)
return 0;
/* periodic retain flush to avoid high I/O load */
PLC_GetTime(&now);
diff_s = CalcDiffSeconds(&now, &last_save);
if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) {
ret = 1;
last_save = now;
}
return ret;
}
void ValidateRetainBuffer(void)
{
if (!retain_buffer)
return;
/* Add retain data CRC to the end of buffer file. */
fseek(retain_buffer, 0, SEEK_END);
fwrite(&retain_crc, sizeof(retain_crc), 1, retain_buffer);
/* Sync file buffer and close file. */
#ifdef __WIN32
fflush(retain_buffer);
#else
fsync(fileno(retain_buffer));
#endif
fclose(retain_buffer);
retain_buffer = NULL;
}
void InValidateRetainBuffer(void)
{
if (!RetainSaveNeeded())
return;
/* Rename old retain file into *.bak if it exists. */
rename(rb_file, rb_file_bckp);
/* Set file CRC initial value. */
retain_crc = retain_info.header_crc;
/* Create new retain file. */
retain_buffer = fopen(rb_file, "wb+");
if (!retain_buffer) {
fprintf(stderr, "Failed to create retain file : %s\n", rb_file);
return;
}
/* Write header to the new file. */
fwrite(&retain_info.retain_size,
sizeof(retain_info.retain_size), 1, retain_buffer);
fwrite(&retain_info.hash_size,
sizeof(retain_info.hash_size), 1, retain_buffer);
fwrite(retain_info.hash ,
sizeof(char), retain_info.hash_size, retain_buffer);
}
void Retain(unsigned int offset, unsigned int count, void *p)
{
if (!retain_buffer)
return;
/* Generate CRC 32 for each data block. */
retain_crc = GenerateCRC32Sum(p, count, retain_crc);
/* Save current var in file. */
fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET);
fwrite(p, count, 1, retain_buffer);
}
void Remind(unsigned int offset, unsigned int count, void *p)
{
/* Remind variable from file. */
fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET);
fread((void *)p, count, 1, retain_buffer);
}
#endif // !HAVE_RETAIN
/**
* Tail of code common to all C targets
**/
/**
* LOGGING
**/
#ifndef TARGET_LOGGING_DISABLE
#ifndef LOG_BUFFER_SIZE
#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/
#endif
#ifndef LOG_BUFFER_ATTRS
#define LOG_BUFFER_ATTRS
#endif
#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1)
static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS;
static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){
if(buffpos + size < LOG_BUFFER_SIZE){
memcpy(&LogBuff[level][buffpos], buf, size);
}else{
uint32_t remaining = LOG_BUFFER_SIZE - buffpos;
memcpy(&LogBuff[level][buffpos], buf, remaining);
memcpy(LogBuff[level], (char*)buf + remaining, size - remaining);
}
}
static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){
if(buffpos + size < LOG_BUFFER_SIZE){
memcpy(buf, &LogBuff[level][buffpos], size);
}else{
uint32_t remaining = LOG_BUFFER_SIZE - buffpos;
memcpy(buf, &LogBuff[level][buffpos], remaining);
memcpy((char*)buf + remaining, LogBuff[level], size - remaining);
}
}
/* Log buffer structure
|<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|...
| Message1 Body | Tail1 | Message2 Body | Tail2 |
*/
typedef struct {
uint32_t msgidx;
uint32_t msgsize;
unsigned long tick;
IEC_TIME time;
} mTail;
/* Log cursor : 64b
|63 ... 32|31 ... 0|
| Message | Buffer |
| counter | Index | */
static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0};
void ResetLogCount(void) {
uint8_t level;
for(level=0;level<LOG_LEVELS;level++){
LogCursor[level] = 0;
}
}
/* Store one log message of give size */
int LogMessage(uint8_t level, char* buf, uint32_t size){
if(size < LOG_BUFFER_SIZE - sizeof(mTail)){
uint32_t buffpos;
uint64_t new_cursor, old_cursor;
mTail tail;
tail.msgsize = size;
tail.tick = __tick;
PLC_GetTime(&tail.time);
/* We cannot increment both msg index and string pointer
in a single atomic operation but we can detect having been interrupted.
So we can try with atomic compare and swap in a loop until operation
succeeds non interrupted */
do{
old_cursor = LogCursor[level];
buffpos = (uint32_t)old_cursor;
tail.msgidx = (old_cursor >> 32);
new_cursor = ((uint64_t)(tail.msgidx + 1)<<32)
| (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK);
}while(AtomicCompareExchange64(
(long long*)&LogCursor[level],
(long long)old_cursor,
(long long)new_cursor)!=(long long)old_cursor);
copy_to_log(level, buffpos, buf, size);
copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail));
return 1; /* Success */
}else{
char mstr[] = "Logging error : message too big";
LogMessage(LOG_CRITICAL, mstr, sizeof(mstr));
}
return 0;
}
uint32_t GetLogCount(uint8_t level){
return (uint64_t)LogCursor[level] >> 32;
}
/* Return message size and content */
uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){
uint64_t cursor = LogCursor[level];
if(cursor){
/* seach cursor */
uint32_t stailpos = (uint32_t)cursor;
uint32_t smsgidx;
mTail tail;
tail.msgidx = cursor >> 32;
tail.msgsize = 0;
/* Message search loop */
do {
smsgidx = tail.msgidx;
stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK;
copy_from_log(level, stailpos, &tail, sizeof(mTail));
}while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx));
if(tail.msgidx == msgidx){
uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK;
uint32_t totalsize = tail.msgsize;
*tick = tail.tick;
*tv_sec = tail.time.tv_sec;
*tv_nsec = tail.time.tv_nsec;
copy_from_log(level, sbuffpos, buf,
totalsize > max_size ? max_size : totalsize);
return totalsize;
}
}
return 0;
}
#endif
#ifndef TARGET_EXT_SYNC_DISABLE
#define CALIBRATED -2
#define NOT_CALIBRATED -1
static int calibration_count = NOT_CALIBRATED;
static IEC_TIME cal_begin;
static long long Tsync = 0;
static long long FreqCorr = 0;
static int Nticks = 0;
static unsigned long last_tick = 0;
/*
* Called on each external periodic sync event
* make PLC tick synchronous with external sync
* ratio defines when PLC tick occurs between two external sync
* @param sync_align_ratio
* 0->100 : align ratio
* < 0 : no align, calibrate period
**/
void align_tick(int sync_align_ratio)
{
/*
printf("align_tick(%d)\n", calibrate);
*/
if(sync_align_ratio < 0){ /* Calibration */
if(calibration_count == CALIBRATED)
/* Re-calibration*/
calibration_count = NOT_CALIBRATED;
if(calibration_count == NOT_CALIBRATED)
/* Calibration start, get time*/
PLC_GetTime(&cal_begin);
calibration_count++;
}else{ /* do alignment (if possible) */
if(calibration_count >= 0){
/* End of calibration */
/* Get final time */
IEC_TIME cal_end;
PLC_GetTime(&cal_end);
/*adjust calibration_count*/
calibration_count++;
/* compute mean of Tsync, over calibration period */
Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 +
(cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count;
if( (Nticks = (Tsync / common_ticktime__)) > 0){
FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */
}else{
FreqCorr = Tsync - (common_ticktime__ % Tsync);
}
/*
printf("Tsync = %ld\n", Tsync);
printf("calibration_count = %d\n", calibration_count);
printf("Nticks = %d\n", Nticks);
*/
calibration_count = CALIBRATED;
}
if(calibration_count == CALIBRATED){
/* Get Elapsed time since last PLC tick (__CURRENT_TIME) */
IEC_TIME now;
long long elapsed;
long long Tcorr;
long long PhaseCorr;
long long PeriodicTcorr;
PLC_GetTime(&now);
elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec;
if(Nticks > 0){
PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */
Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks;
if(Nticks < 2){
/* When Sync source period is near Tick time */
/* PhaseCorr may not be applied to Periodic time given to timer */
PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks;
}else{
PeriodicTcorr = Tcorr;
}
}else if(__tick > last_tick){
last_tick = __tick;
PhaseCorr = elapsed - (Tsync*sync_align_ratio/100);
PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr;
}else{
/*PLC did not run meanwhile. Nothing to do*/
return;
}
/* DO ALIGNEMENT */
PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr);
}
}
}
#endif

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<BeremizRoot xmlns:xsd="http://www.w3.org/2001/XMLSchema" URI_location="LOCAL://">
<TargetType/>
</BeremizRoot>

View File

@@ -1,645 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<project xmlns="http://www.plcopen.org/xml/tc6_0201" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:ns1="http://www.plcopen.org/xml/tc6_0201">
<fileHeader companyName="Unknown" productName="Unnamed" productVersion="1" creationDateTime="2025-11-28T11:40:28"/>
<contentHeader name="tp2" modificationDateTime="2025-12-04T13:05:24">
<coordinateInfo>
<fbd>
<scaling x="10" y="10"/>
</fbd>
<ld>
<scaling x="10" y="10"/>
</ld>
<sfc>
<scaling x="10" y="10"/>
</sfc>
</coordinateInfo>
</contentHeader>
<types>
<dataTypes/>
<pous>
<pou name="motor" pouType="program">
<interface>
<localVars>
<variable name="START">
<type>
<BOOL/>
</type>
</variable>
<variable name="STOP">
<type>
<BOOL/>
</type>
</variable>
<variable name="DELAY">
<type>
<TIME/>
</type>
<initialValue>
<simpleValue value="T#100ms"/>
</initialValue>
</variable>
<variable name="RUNNING">
<type>
<BOOL/>
</type>
</variable>
<variable name="RS0">
<type>
<derived name="RS"/>
</type>
</variable>
<variable name="TON0">
<type>
<derived name="TON"/>
</type>
</variable>
</localVars>
</interface>
<body>
<LD>
<leftPowerRail localId="1" width="10" height="140">
<position x="180" y="100"/>
<connectionPointOut formalParameter="">
<relPosition x="10" y="20"/>
</connectionPointOut>
<connectionPointOut formalParameter="">
<relPosition x="10" y="120"/>
</connectionPointOut>
</leftPowerRail>
<contact localId="2" negated="false" width="21" height="20">
<position x="250" y="110"/>
<connectionPointIn>
<relPosition x="0" y="10"/>
<connection refLocalId="1">
<position x="250" y="120"/>
<position x="190" y="120"/>
</connection>
</connectionPointIn>
<connectionPointOut>
<relPosition x="21" y="10"/>
</connectionPointOut>
<variable>START</variable>
</contact>
<block localId="4" typeName="RS" instanceName="RS0" width="50" height="60">
<position x="390" y="90"/>
<inputVariables>
<variable formalParameter="S">
<connectionPointIn>
<relPosition x="0" y="30"/>
<connection refLocalId="8" formalParameter="Q">
<position x="390" y="120"/>
<position x="350" y="120"/>
</connection>
</connectionPointIn>
</variable>
<variable formalParameter="R1">
<connectionPointIn>
<relPosition x="0" y="50"/>
<connection refLocalId="5">
<position x="390" y="140"/>
<position x="370" y="140"/>
<position x="370" y="210"/>
<position x="271" y="210"/>
</connection>
</connectionPointIn>
</variable>
</inputVariables>
<inOutVariables/>
<outputVariables>
<variable formalParameter="Q1">
<connectionPointOut>
<relPosition x="50" y="30"/>
</connectionPointOut>
</variable>
</outputVariables>
</block>
<contact localId="5" negated="false" width="21" height="20">
<position x="250" y="200"/>
<connectionPointIn>
<relPosition x="0" y="10"/>
<connection refLocalId="1">
<position x="250" y="210"/>
<position x="220" y="210"/>
<position x="220" y="220"/>
<position x="190" y="220"/>
</connection>
</connectionPointIn>
<connectionPointOut>
<relPosition x="21" y="10"/>
</connectionPointOut>
<variable>STOP</variable>
</contact>
<coil localId="6" negated="false" width="21" height="20">
<position x="470" y="110"/>
<connectionPointIn>
<relPosition x="0" y="10"/>
<connection refLocalId="4" formalParameter="Q1">
<position x="470" y="120"/>
<position x="440" y="120"/>
</connection>
</connectionPointIn>
<connectionPointOut>
<relPosition x="21" y="10"/>
</connectionPointOut>
<variable>RUNNING</variable>
</coil>
<rightPowerRail localId="7" width="10" height="80">
<position x="540" y="100"/>
<connectionPointIn>
<relPosition x="0" y="20"/>
<connection refLocalId="6">
<position x="540" y="120"/>
<position x="490" y="120"/>
</connection>
</connectionPointIn>
<connectionPointIn>
<relPosition x="0" y="60"/>
</connectionPointIn>
</rightPowerRail>
<block localId="8" typeName="TON" instanceName="TON0" width="50" height="70">
<position x="300" y="90"/>
<inputVariables>
<variable formalParameter="IN">
<connectionPointIn>
<relPosition x="0" y="30"/>
<connection refLocalId="2">
<position x="300" y="120"/>
<position x="271" y="120"/>
</connection>
</connectionPointIn>
</variable>
<variable formalParameter="PT">
<connectionPointIn>
<relPosition x="0" y="60"/>
<connection refLocalId="9">
<position x="300" y="150"/>
<position x="280" y="150"/>
<position x="280" y="160"/>
<position x="260" y="160"/>
</connection>
</connectionPointIn>
</variable>
</inputVariables>
<inOutVariables/>
<outputVariables>
<variable formalParameter="Q">
<connectionPointOut>
<relPosition x="50" y="30"/>
</connectionPointOut>
</variable>
<variable formalParameter="ET">
<connectionPointOut>
<relPosition x="50" y="60"/>
</connectionPointOut>
</variable>
</outputVariables>
</block>
<inVariable localId="9" width="60" height="30" negated="false">
<position x="200" y="140"/>
<connectionPointOut>
<relPosition x="60" y="20"/>
</connectionPointOut>
<expression>DELAY</expression>
</inVariable>
</LD>
</body>
</pou>
<pou name="fan" pouType="program">
<interface>
<localVars>
<variable name="START">
<type>
<BOOL/>
</type>
</variable>
<variable name="STOP">
<type>
<BOOL/>
</type>
</variable>
<variable name="MOTOR1">
<type>
<BOOL/>
</type>
</variable>
<variable name="TEMPO">
<type>
<BOOL/>
</type>
</variable>
</localVars>
</interface>
<body>
<SFC>
<step localId="1" name="Step0" initialStep="true" width="60" height="30">
<position x="550" y="100"/>
<connectionPointOut formalParameter="">
<relPosition x="30" y="30"/>
</connectionPointOut>
</step>
<leftPowerRail localId="2" width="10" height="80">
<position x="370" y="130"/>
<connectionPointOut formalParameter="">
<relPosition x="10" y="20"/>
</connectionPointOut>
<connectionPointOut formalParameter="">
<relPosition x="10" y="60"/>
</connectionPointOut>
</leftPowerRail>
<contact localId="3" negated="false" edge="rising" width="21" height="20">
<position x="420" y="140"/>
<connectionPointIn>
<relPosition x="0" y="10"/>
<connection refLocalId="2">
<position x="420" y="150"/>
<position x="380" y="150"/>
</connection>
</connectionPointIn>
<connectionPointOut>
<relPosition x="21" y="10"/>
</connectionPointOut>
<variable>START</variable>
</contact>
<contact localId="4" negated="false" width="21" height="20" edge="rising">
<position x="420" y="180"/>
<connectionPointIn>
<relPosition x="0" y="10"/>
<connection refLocalId="2">
<position x="420" y="190"/>
<position x="380" y="190"/>
</connection>
</connectionPointIn>
<connectionPointOut>
<relPosition x="21" y="10"/>
</connectionPointOut>
<variable>STOP</variable>
</contact>
<step localId="5" name="Step1" initialStep="false" width="50" height="30">
<position x="560" y="180"/>
<connectionPointIn>
<relPosition x="20" y="0"/>
<connection refLocalId="6">
<position x="580" y="180"/>
<position x="580" y="160"/>
</connection>
</connectionPointIn>
<connectionPointOut formalParameter="">
<relPosition x="20" y="30"/>
</connectionPointOut>
<connectionPointOutAction formalParameter="">
<relPosition x="50" y="20"/>
</connectionPointOutAction>
</step>
<transition localId="6" width="20" height="10">
<position x="570" y="150"/>
<connectionPointIn>
<relPosition x="10" y="0"/>
<connection refLocalId="1">
<position x="580" y="150"/>
<position x="580" y="130"/>
</connection>
</connectionPointIn>
<connectionPointOut>
<relPosition x="10" y="10"/>
</connectionPointOut>
<condition>
<connectionPointIn>
<connection refLocalId="3">
<position x="570" y="150"/>
<position x="441" y="150"/>
</connection>
</connectionPointIn>
</condition>
</transition>
<actionBlock localId="8" width="100" height="30">
<position x="670" y="170"/>
<connectionPointIn>
<relPosition x="0" y="20"/>
<connection refLocalId="5">
<position x="670" y="190"/>
<position x="640" y="190"/>
<position x="640" y="200"/>
<position x="610" y="200"/>
</connection>
</connectionPointIn>
<action localId="0" qualifier="D" duration="t#2s">
<relPosition x="0" y="0"/>
<reference name="TEMPO"/>
</action>
</actionBlock>
<step localId="10" name="Step2" initialStep="false" width="50" height="30">
<position x="560" y="260"/>
<connectionPointIn>
<relPosition x="20" y="0"/>
<connection refLocalId="11">
<position x="580" y="260"/>
<position x="580" y="240"/>
</connection>
</connectionPointIn>
<connectionPointOut formalParameter="">
<relPosition x="20" y="30"/>
</connectionPointOut>
<connectionPointOutAction formalParameter="">
<relPosition x="50" y="20"/>
</connectionPointOutAction>
</step>
<transition localId="11" width="20" height="10">
<position x="570" y="230"/>
<connectionPointIn>
<relPosition x="10" y="0"/>
<connection refLocalId="5">
<position x="580" y="230"/>
<position x="580" y="210"/>
</connection>
</connectionPointIn>
<connectionPointOut>
<relPosition x="10" y="10"/>
</connectionPointOut>
<condition>
<inline name="">
<ST>
<xhtml:p><![CDATA[TEMPO]]></xhtml:p>
</ST>
</inline>
</condition>
</transition>
<jumpStep localId="12" targetName="Step0" width="20" height="20">
<position x="570" y="340"/>
<connectionPointIn>
<relPosition x="10" y="0"/>
<connection refLocalId="13">
<position x="580" y="340"/>
<position x="580" y="320"/>
</connection>
</connectionPointIn>
</jumpStep>
<transition localId="13" width="20" height="10">
<position x="570" y="310"/>
<connectionPointIn>
<relPosition x="10" y="0"/>
<connection refLocalId="10">
<position x="580" y="310"/>
<position x="580" y="290"/>
</connection>
</connectionPointIn>
<connectionPointOut>
<relPosition x="10" y="10"/>
</connectionPointOut>
<condition>
<connectionPointIn>
<connection refLocalId="4">
<position x="570" y="310"/>
<position x="546" y="310"/>
<position x="546" y="190"/>
<position x="441" y="190"/>
</connection>
</connectionPointIn>
</condition>
</transition>
<actionBlock localId="14" width="100" height="30">
<position x="668" y="260"/>
<connectionPointIn>
<relPosition x="0" y="20"/>
<connection refLocalId="10">
<position x="668" y="280"/>
<position x="610" y="280"/>
</connection>
</connectionPointIn>
<action localId="0">
<relPosition x="0" y="0"/>
<reference name="MOTOR1"/>
</action>
</actionBlock>
</SFC>
</body>
</pou>
<pou name="street_light" pouType="program">
<interface>
<localVars>
<variable name="RED">
<type>
<BOOL/>
</type>
</variable>
<variable name="YELLOW">
<type>
<BOOL/>
</type>
</variable>
<variable name="GREEN">
<type>
<BOOL/>
</type>
</variable>
<variable name="WAIT">
<type>
<BOOL/>
</type>
</variable>
</localVars>
</interface>
<body>
<SFC>
<step localId="1" name="show_green" initialStep="true" width="100" height="30">
<position x="500" y="80"/>
<connectionPointOut formalParameter="">
<relPosition x="50" y="30"/>
</connectionPointOut>
<connectionPointOutAction formalParameter="">
<relPosition x="100" y="10"/>
</connectionPointOutAction>
</step>
<actionBlock localId="2" width="110" height="60">
<position x="630" y="70"/>
<connectionPointIn>
<relPosition x="0" y="10"/>
<connection refLocalId="1">
<position x="630" y="80"/>
<position x="615" y="80"/>
<position x="615" y="100"/>
<position x="600" y="100"/>
</connection>
</connectionPointIn>
<action localId="0" qualifier="SL" duration="t#30s">
<relPosition x="0" y="0"/>
<reference name="GREEN"/>
</action>
<action localId="0" qualifier="SD" duration="t#28s">
<relPosition x="0" y="0"/>
<reference name="YELLOW"/>
</action>
</actionBlock>
<step localId="4" name="show_yellow" initialStep="false" width="100" height="30">
<position x="500" y="250"/>
<connectionPointIn>
<relPosition x="50" y="0"/>
<connection refLocalId="5">
<position x="550" y="250"/>
<position x="550" y="210"/>
</connection>
</connectionPointIn>
<connectionPointOut formalParameter="">
<relPosition x="50" y="30"/>
</connectionPointOut>
<connectionPointOutAction formalParameter="">
<relPosition x="100" y="10"/>
</connectionPointOutAction>
</step>
<transition localId="5" width="20" height="10">
<position x="540" y="200"/>
<connectionPointIn>
<relPosition x="10" y="0"/>
<connection refLocalId="1">
<position x="550" y="200"/>
<position x="550" y="110"/>
</connection>
</connectionPointIn>
<connectionPointOut>
<relPosition x="10" y="10"/>
</connectionPointOut>
<condition>
<inline name="">
<ST>
<xhtml:p><![CDATA[GREEN = false]]></xhtml:p>
</ST>
</inline>
</condition>
</transition>
<jumpStep localId="7" targetName="show_green" width="20" height="20">
<position x="540" y="440"/>
<connectionPointIn>
<relPosition x="10" y="0"/>
<connection refLocalId="10">
<position x="550" y="440"/>
<position x="550" y="410"/>
</connection>
</connectionPointIn>
</jumpStep>
<transition localId="8" width="20" height="10">
<position x="540" y="310"/>
<connectionPointIn>
<relPosition x="10" y="0"/>
<connection refLocalId="4">
<position x="550" y="310"/>
<position x="550" y="280"/>
</connection>
</connectionPointIn>
<connectionPointOut>
<relPosition x="10" y="10"/>
</connectionPointOut>
<condition>
<inline name="">
<ST>
<xhtml:p><![CDATA[YELLOW = false]]></xhtml:p>
</ST>
</inline>
</condition>
</transition>
<step localId="9" name="show_red" initialStep="false" width="80" height="30">
<position x="510" y="350"/>
<connectionPointIn>
<relPosition x="40" y="0"/>
<connection refLocalId="8">
<position x="550" y="350"/>
<position x="550" y="320"/>
</connection>
</connectionPointIn>
<connectionPointOut formalParameter="">
<relPosition x="40" y="30"/>
</connectionPointOut>
<connectionPointOutAction formalParameter="">
<relPosition x="80" y="10"/>
</connectionPointOutAction>
</step>
<transition localId="10" width="20" height="10">
<position x="540" y="400"/>
<connectionPointIn>
<relPosition x="10" y="0"/>
<connection refLocalId="9">
<position x="550" y="400"/>
<position x="550" y="380"/>
</connection>
</connectionPointIn>
<connectionPointOut>
<relPosition x="10" y="10"/>
</connectionPointOut>
<condition>
<inline name="">
<ST>
<xhtml:p><![CDATA[RED = false]]></xhtml:p>
</ST>
</inline>
</condition>
</transition>
<comment localId="3" height="100" width="310">
<position x="760" y="60"/>
<content>
<xhtml:p><![CDATA[REQ2 : Green lit for at least 30s
REQ3 : Lighting up Yellow 2s before Green turns off to ensure it ligths up within 0.2s.]]></xhtml:p>
</content>
</comment>
<actionBlock localId="13" width="90" height="30">
<position x="620" y="340"/>
<connectionPointIn>
<relPosition x="0" y="20"/>
<connection refLocalId="9">
<position x="620" y="360"/>
<position x="590" y="360"/>
</connection>
</connectionPointIn>
<action localId="0" qualifier="SL" duration="t#10s">
<relPosition x="0" y="0"/>
<reference name="RED"/>
</action>
</actionBlock>
<actionBlock localId="14" width="100" height="30">
<position x="640" y="240"/>
<connectionPointIn>
<relPosition x="0" y="20"/>
<connection refLocalId="4">
<position x="640" y="260"/>
<position x="600" y="260"/>
</connection>
</connectionPointIn>
<action localId="0" qualifier="P">
<relPosition x="0" y="0"/>
<reference name="YELLOW"/>
</action>
</actionBlock>
<comment localId="15" height="40" width="350">
<position x="680" y="180"/>
<content>
<xhtml:p><![CDATA[REQ1 : After Green, next step is yellow.]]></xhtml:p>
</content>
</comment>
<comment localId="16" height="40" width="350">
<position x="730" y="340"/>
<content>
<xhtml:p><![CDATA[REQ5 : Red stays active for at least 10s.]]></xhtml:p>
</content>
</comment>
<comment localId="17" height="40" width="220">
<position x="690" y="290"/>
<content>
<xhtml:p><![CDATA[REQ4 : Next step is Red.]]></xhtml:p>
</content>
</comment>
</SFC>
</body>
</pou>
</pous>
</types>
<instances>
<configurations>
<configuration name="Config0">
<resource name="Res0">
<task name="task0" priority="0" interval="T#20ms">
<pouInstance name="instance0" typeName="motor"/>
<pouInstance name="instance2" typeName="street_light"/>
<pouInstance name="instance1" typeName="fan"/>
</task>
</resource>
</configuration>
</configurations>
</instances>
</project>