# HG changeset patch # User Mario de Sousa # Date 1504126638 -3600 # Node ID aef63aa7ef2ebc91a8453b7180df78f022ff2c28 # Parent 5b54ecd4303b504e5381ec43c278f5bbd6b66d01 add support for generating functions to backup/restore the internal state of the PLC. diff -r 5b54ecd4303b -r aef63aa7ef2e stage4/generate_c/generate_c.cc --- a/stage4/generate_c/generate_c.cc Tue Aug 29 12:02:09 2017 +0100 +++ b/stage4/generate_c/generate_c.cc Wed Aug 30 21:57:18 2017 +0100 @@ -178,6 +178,7 @@ static int generate_line_directives__ = 0; static int generate_pou_filepairs__ = 0; +static int generate_plc_state_backup_fuctions__ = 1; #ifdef __unix__ /* Parse command line options passed from main.c !! */ @@ -1572,6 +1573,7 @@ }; + /***********************************************************************/ /***********************************************************************/ /***********************************************************************/ @@ -2108,6 +2110,261 @@ /***********************************************************************/ /***********************************************************************/ +/*******************************************************/ +/* Classes to generate the backup/restore functions... */ +/*******************************************************/ + +#define RESTORE_ "_restore__" +#define BACKUP_ "_backup__" + +/* class to generate the forward declaration of the XXXX_backup() and XXXX_restore() + * functions that will later (in the generated C source code) be defined + * to backup/restore the global state of each RESOURCE in the source code being compiled. + * The XXXX is actually the resource name! + */ +class generate_c_backup_resource_decl_c: public generate_c_base_and_typeid_c { + public: + generate_c_backup_resource_decl_c(stage4out_c *s4o_ptr) + : generate_c_base_and_typeid_c(s4o_ptr) {}; + + void *visit(resource_declaration_c *symbol) { + s4o.print(s4o.indent_spaces); + s4o.print("void "); + symbol->resource_name->accept(*this); + s4o.print("_backup__" "(void **buffer, int *maxsize);\n"); + s4o.print(s4o.indent_spaces); + s4o.print("void "); + symbol->resource_name->accept(*this); + s4o.print("_restore__" "(void **buffer, int *maxsize);\n"); + return NULL; + } +}; + + +/* print out the begining of the generic backup/restore function */ +void print_backup_restore_function_beg(stage4out_c &s4o, const char *func_name, const char *operation) { + /* operation will be either "_backup__" or "_restore__" */ + s4o.print("\n"); + s4o.print("void "); + s4o.print(func_name); + s4o.print(operation); + s4o.print("(void **buffer, int *maxsize) {\n"); + s4o.indent_right(); + // Don't save/restore the __CURRENT_TIME variable, as 'plc controller' has easy access to it + // and can therefore do the save/restore by itself. +//s4o.print(s4o.indent_spaces); +//s4o.print(operation); +//s4o.print("(&__CURRENT_TIME, sizeof(__CURRENT_TIME), buffer, maxsize);\n"); + s4o.print(s4o.indent_spaces); + s4o.print("#define " DECLARE_GLOBAL "(vartype, domain, varname) \\\n "); + s4o.print(operation); + s4o.print("(&domain##__##varname, sizeof(domain##__##varname), buffer, maxsize);\n"); + s4o.print(s4o.indent_spaces); + s4o.print("#define " DECLARE_GLOBAL_FB "(vartype, domain, varname) \\\n "); + s4o.print(operation); + s4o.print("(&domain##__##varname, sizeof(domain##__##varname), buffer, maxsize);\n"); + s4o.print(s4o.indent_spaces); + s4o.print("#define " DECLARE_GLOBAL_LOCATION "(vartype, location) \\\n "); + s4o.print(operation); + s4o.print("(location, sizeof(*location), buffer, maxsize);\n"); + s4o.print(s4o.indent_spaces); + s4o.print("#define " DECLARE_GLOBAL_LOCATED "(vartype, domain, varname) \\\n "); + s4o.print(operation); + s4o.print("(&domain##__##varname, sizeof(domain##__##varname), buffer, maxsize);\n"); +} + +/* print out the ending of the generic backup/restore function */ +void print_backup_restore_function_end(stage4out_c &s4o) { + s4o.print(s4o.indent_spaces); s4o.print("#undef " DECLARE_GLOBAL "\n"); + s4o.print(s4o.indent_spaces); s4o.print("#undef " DECLARE_GLOBAL_FB "\n"); + s4o.print(s4o.indent_spaces); s4o.print("#undef " DECLARE_GLOBAL_LOCATION "\n"); + s4o.print(s4o.indent_spaces); s4o.print("#undef " DECLARE_GLOBAL_LOCATED "\n"); + s4o.indent_left(); + s4o.print("}\n"); +} + + +/* generate the backup/restore function for a CONFIGURATION */ +/* the generated function will backup/restore the global variables declared in the + * configuration, and call the backup/restore functions of each embedded resource to do + * the same for the global variables declared inside each resource. + */ +class generate_c_backup_config_c: public generate_c_base_and_typeid_c { + private: + const char *func_to_call = NULL; // will later be set to either "_backup__" or "_restore__" + + public: + generate_c_backup_config_c(stage4out_c *s4o_ptr) + : generate_c_base_and_typeid_c(s4o_ptr) { + }; + + virtual ~generate_c_backup_config_c(void) {} + + + public: + /********************/ + /* 2.1.6 - Pragmas */ + /********************/ + void *visit(enable_code_generation_pragma_c * symbol) {s4o.enable_output(); return NULL;} + void *visit(disable_code_generation_pragma_c * symbol) {s4o.disable_output();return NULL;} + + + /********************************/ + /* B 1.7 Configuration elements */ + /********************************/ + /* + SYM_REF6(configuration_declaration_c, configuration_name, global_var_declarations, resource_declarations, access_declarations, instance_specific_initializations, unused) + */ + void *visit(configuration_declaration_c *symbol) { + + s4o.print("\n\n\n"); + + s4o.print("void "); + s4o.print("_backup__"); + s4o.print("(void *varptr, int varsize, void **buffer, int *maxsize) {\n"); + s4o.print(" if (varsize <= *maxsize) {memmove(*buffer, varptr, varsize); *buffer += varsize;}\n"); + s4o.print(" *maxsize -= varsize;\n"); + s4o.print("}\n"); + + s4o.print("void "); + s4o.print("_restore__"); + s4o.print("(void *varptr, int varsize, void **buffer, int *maxsize) {\n"); + s4o.print(" if (varsize <= *maxsize) {memmove(varptr, *buffer, varsize); *buffer += varsize;}\n"); + s4o.print(" *maxsize -= varsize;\n"); + s4o.print("}\n"); + + + generate_c_vardecl_c vardecl = generate_c_vardecl_c(&s4o, + generate_c_vardecl_c::local_vf, + generate_c_vardecl_c::global_vt, + symbol->configuration_name); + + s4o.print("\n\n\n"); + s4o.print("#undef " DECLARE_GLOBAL "\n"); + s4o.print("#undef " DECLARE_GLOBAL_FB "\n"); + s4o.print("#undef " DECLARE_GLOBAL_LOCATION "\n"); + s4o.print("#undef " DECLARE_GLOBAL_LOCATED "\n"); + + generate_c_backup_resource_decl_c declare_functions = generate_c_backup_resource_decl_c(&s4o); + symbol->resource_declarations->accept(declare_functions); + + print_backup_restore_function_beg(s4o, "config", "_backup__"); + vardecl.print(symbol); + s4o.print("\n"); + func_to_call = "_backup__"; + symbol->resource_declarations->accept(*this); + func_to_call = NULL; + print_backup_restore_function_end(s4o); + + print_backup_restore_function_beg(s4o, "config", "_restore__"); + vardecl.print(symbol); + s4o.print("\n"); + func_to_call = "_restore__"; + symbol->resource_declarations->accept(*this); + func_to_call = NULL; + print_backup_restore_function_end(s4o); + + return NULL; + } + + void *visit(resource_declaration_c *symbol) { + if (symbol->global_var_declarations == NULL) + return NULL; + s4o.print(s4o.indent_spaces); + symbol->resource_name->accept(*this); + s4o.print(func_to_call); + s4o.print("(buffer, maxsize);\n"); + return NULL; + } + + void *visit(single_resource_declaration_c *symbol) { + /* A single resource never has global variables declared, so nothing to do! */ + return NULL; + } + +}; + + + +/* generate the backup/restore function for a RESOURCE */ +/* the backup/restore function generated here will be called by the backup/restore + * function generated for the configuration in which the resource is embedded + */ +class generate_c_backup_resource_c: public generate_c_base_and_typeid_c { + public: + generate_c_backup_resource_c(stage4out_c *s4o_ptr) + : generate_c_base_and_typeid_c(s4o_ptr) { + }; + + virtual ~generate_c_backup_resource_c(void) {} + + + public: + /********************/ + /* 2.1.6 - Pragmas */ + /********************/ + void *visit(enable_code_generation_pragma_c * symbol) {s4o.enable_output(); return NULL;} + void *visit(disable_code_generation_pragma_c * symbol) {s4o.disable_output();return NULL;} + + + /********************************/ + /* B 1.7 Configuration elements */ + /********************************/ + void *visit(resource_declaration_c *symbol) { + if (symbol->global_var_declarations == NULL) + return NULL; + + char *resource_name = strdup(symbol->resource_name->token->value); + /* convert to upper case */ + for (char *c = resource_name; *c != '\0'; *c = toupper(*c), c++); + + generate_c_vardecl_c vardecl = generate_c_vardecl_c(&s4o, + generate_c_vardecl_c::local_vf, + generate_c_vardecl_c::global_vt, + symbol->resource_name); + s4o.print("\n\n\n"); + + s4o.print("void "); + s4o.print("_backup__"); + s4o.print("(void *varptr, int varsize, void **buffer, int *maxsize);\n"); + s4o.print("void "); + s4o.print("_restore__"); + s4o.print("(void *varptr, int varsize, void **buffer, int *maxsize);\n"); + + s4o.print("\n\n\n"); + s4o.print("#undef " DECLARE_GLOBAL "\n"); + s4o.print("#undef " DECLARE_GLOBAL_FB "\n"); + s4o.print("#undef " DECLARE_GLOBAL_LOCATION "\n"); + s4o.print("#undef " DECLARE_GLOBAL_LOCATED "\n"); + + print_backup_restore_function_beg(s4o, resource_name, "_backup__"); + vardecl.print(symbol->global_var_declarations); + print_backup_restore_function_end(s4o); + + print_backup_restore_function_beg(s4o, resource_name, "_restore__"); + vardecl.print(symbol->global_var_declarations); + print_backup_restore_function_end(s4o); + + return NULL; + } + + void *visit(single_resource_declaration_c *symbol) { + /* A single resource never has global variables declared, so nothing to do! */ + return NULL; + } + +}; + + +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ + class generate_c_c: public iterator_visitor_c { protected: stage4out_c &s4o; @@ -2329,6 +2586,11 @@ config_s4o.print("unsigned long greatest_tick_count__ = (unsigned long)"); config_s4o.print_long_integer(calculate_common_ticktime.get_greatest_tick_count()); config_s4o.print("; /*tick*/\n"); + + if (generate_plc_state_backup_fuctions__ > 0) { + generate_c_backup_config_c generate_backup = generate_c_backup_config_c(&config_s4o); + symbol->accept(generate_backup); + } } symbol->resource_declarations->accept(*this); @@ -2344,6 +2606,10 @@ stage4out_c resources_s4o(current_builddir, current_name, "c"); generate_c_resources_c generate_c_resources(&resources_s4o, current_configuration, symbol, common_ticktime); symbol->accept(generate_c_resources); + if (generate_plc_state_backup_fuctions__ > 0) { + generate_c_backup_resource_c generate_backup = generate_c_backup_resource_c(&resources_s4o); + symbol->accept(generate_backup); + } return NULL; }