Repetitive code eliminator


#1

here’s a little piece of code that can be used to eliminate the good old cut/paste/find/replace . i use it to do totalizing on digital input points (fan/pump runtimes) but it could be customized for any application. its pretty compact and easy to add to, just add another case statement and adjust pointers to suit and away you go. i know this could be done using a subroutine, but some people do not like using subs, and i think its a cool little piece of code that shows the power of optoscript by combining a loop, switch and if statement as well as playing with pointers!


temp_int = 1;  //init a counter
repeat
  //ok select a totalizer and variable to hold the total on time
  switch (temp_int)
    case 1:
      //point to the ontime totalizer
      on_totalizer_ptr=&ex_fan1_run;
      //point to the accumulated time variable
      float_ptr=&pnb_exf1_runtime;
      break
    case 2:
      //point to the ontime totalizer
      on_totalizer_ptr=&ex_fan3_run;
      //reuse the float pointer for this e
      float_ptr=&pnb_exf3_runtime;
      break
    case 3:
      //point to the ontime totalizer
      on_totalizer_ptr=&ex_fan4_run;
      //point to the accumulated time variable
      float_ptr=&pnb_exf4_runtime;
      break
    case 4:
      //point the pointer to the ontime totalizer
      on_totalizer_ptr=&ex_fan2_run;
      //point to the accumulated time variable
      float_ptr=&pnb_exf2_runtime;
      break
    case 5:
      //point to the ontime totalizer
      on_totalizer_ptr=&chiller_chwp1_run;
      //point to the accumulated time variable
      float_ptr=&pnb_chiller_chwp1_runtime;
      break
    case 6:
      //point to the ontime totalizer
      on_totalizer_ptr=&chiller_chwp2_run;
      //point to the accumulated time variable
      float_ptr=&pnb_chiller_chwp2_runtime;
      break
    default:
      //if we get here then we have run out of things to check so move NULL to the pointers
      on_totalizer_ptr=null;
      float_ptr=null;
      break
  endswitch
    //if the pointer is null then skip this bit
  if (not(on_totalizer_ptr==null)) then
    //get the totalizer
    fan_runtime=0;
    fan_runtime=GetRestartOnTimeTotalizer(*on_totalizer_ptr);
    //ok now convert the seconds to msecs
    fan_runtime = fan_runtime*1000; //to the millisecond will do us
    //now convert to hours and add to the total
    fan_runtime=fan_runtime/(1000*60*60);
    *float_ptr=*float_ptr+fan_runtime;
    //increment the counter so we can move to the next unit.
    IncrementVariable(temp_int);
  endif
until (on_totalizer_ptr==null);    //bail when the pointer is null

i hope this is useful for someone out there.

Nick


#2

Good stuff, thanks Nick.


#3

Hi Nick,

I like the way you’re thinking! In fact, we’ve been working on some training materials related to the overall topic of “Building Maintainable Code.” Stay tuned for more, and thanks for mentioning the topic.

In the meantime, I’d even go a step further with this idea of leveraging pointers and loops, to eliminate your whole case statement – you just need a couple of tables instead. Then when you go to expand this in the future, you’ll just need to add an element to each of these tables initialized at the top (this is the same method our very important: I/O Enabler uses).

I also renamed your “temp” variable, and cut out a couple of extra lines you had in calculating your fan_runtime so your original 60 lines in now 25.

// We're assuming the ptTotalizers & ptTimesTables were initialized to null
// Now set up the lists to loop through
ptTotalizers[0] = &ex_fan1_run;
ptTotalizers[1] = &ex_fan3_run;
ptTotalizers[2] = &ex_fan4_run;
ptTotalizers[3] = &ex_fan2_run;
ptTotalizers[4] = &chiller_chwp1_run;
ptTotalizers[5] = &chiller_chwp2_run;

ptTimesTable[0] = &pnb_exf1_runtime;
ptTimesTable[1] = &pnb_exf3_runtime;
ptTimesTable[2] = &pnb_exf4_runtime;
ptTimesTable[3] = &pnb_exf2_runtime;
ptTimesTable[4] = &pnb_chiller_chwp1_runtime;
ptTimesTable[5] = &pnb_chiller_chwp2_runtime;

// Initialize our looping pointers, loop through the totalizers, Get & Restart, then 
// update the "grand total" (in hours) for each
on_totalizer_ptr1 = ptTotalizers[0];
float_ptr = ptTimesTable[0];
totalizer_index = 0;
while ( not (on_totalizer_ptr1 == null) )

  fan_runtime = GetRestartOnTimeTotalizer(*on_totalizer_ptr1);

  // Convert seconds to hours (60 seconds x 60 minutes) and add to the total
  fan_runtime = fan_runtime/(60*60); // in hours
  *float_ptr = *float_ptr + fan_runtime;

  // Increment the counter & what we're pointing to 
  IncrementVariable(totalizer_index);
  on_totalizer_ptr = ptTotalizers[totalizer_index];
  float_ptr = ptTimesTable[totalizer_index];

wend

Better? Make sense?
Thanks for sharing and do share more!
-OptoMary


#4

awesome thanks mary. i will update the code i have. this is a much better way to do things. i do have other code which i use a pointer table and look for null to terminate, its a good way of having expandable programs by only updating a couple of lines.
i hope the Building Maintainable Code training program spawns a nice little sample pack of coding examples to download. i’ll be keeping and eye out for that one.

Nick


#5

Hi Nick,

Here’s that promised video, I hope you like it!

video:

//youtu.be/D5KAn9W-ePg

-OptoMary