add support for generating functions to backup/restore the internal state of the PLC.
authorMario de Sousa <msousa@fe.up.pt>
Wed, 30 Aug 2017 21:57:18 +0100
changeset 1059 aef63aa7ef2e
parent 1058 5b54ecd4303b
child 1060 01c48180af05
add support for generating functions to backup/restore the internal state of the PLC.
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;
     }