AutoCalculation.g — automatically calculates formulas based on data points.
![]() | Please refer to Section 3.1, “How to Run a Script” for more information on using scripts. |
/*
* Automatically calculate formulas based on data points. Create data points where
* necessary to store the results back to the DataHub's data set.
*
* To use:
* - create a file, like c:/tmp/calculations.txt
* - in the file, create any number of calculations of the form
* $default:test = $DataPid:PID1.Mv * 10;
* $default:test2 = $DataPid:PID1.Mv / 10;
* - change the fileName member in the AutoCalculation class below to refer to your file
* - run the script
*
* Any symbol in the calculation of the form $domain:name is assumed to be a DataHub point,
* and will be created if necessary. The point on the left hand side of the equal sign will
* be automatically updated whenever any point on the right hand side of the equal sign
* changes.
*
* You can include complex Gamma expressions, like:
* $default:output = progn {
* local a = $DataPid:PID1.Mv;
* local b = $DataPid:PID1.Pv;
* if (b != 0)
* a / b;
* else
* a;
* };
*
* You can define functions within this file, though it is better to put functions into a
* separate script file:
*
* function average(a,b)
* {
* a + b / 2;
* }
*
* $default:output = average($DataPid:PID1.Mv, $DataPid:PID1.Pv);
*/
require ("Application");
class AutoCalculation Application
{
fileName = "C:/tmp/calculations.txt";
fp;
}
class Computation
{
app; // the Application instance defining this computation
output; // a symbol
inputs; // a list of symbols
code; // the code to execute
}
method Computation.constructor(app, expression)
{
.app = app;
.code = expression;
.output = .findOutput(expression);
.inputs = .findInputs(expression);
if (.output)
{
datahub_command(format("(create %s 1)", stringc(.output)), 1);
with input in .inputs do
{
datahub_command(format("(create %s 1)", stringc(input)), 1);
.app.OnChange(input, `(@self).compute());
}
}
.compute();
}
method Computation.compute()
{
try
{
eval(.code);
}
catch
{
princ ("Assignment to ", .output, " failed: ", _last_error_, "\n");
}
}
method Computation.findOutput (expr)
{
if (car(expr) == #setq)
cadr(expr);
else
nil;
}
method Computation.findInputsRecursive (expr)
{
local inputs, partial;
if (list_p(expr))
{
with part in expr do
{
partial = .findInputsRecursive(part);
inputs = nappend(inputs, partial);
}
}
else if (symbol_p(expr) && strchr(string(expr), ":") != -1)
{
inputs = cons(expr, inputs);
}
inputs;
}
method Computation.findInputs (expr)
{
.findInputsRecursive(cddr(expr));
}
method AutoCalculation.readFile()
{
if ((.fp = open(.fileName, "r", t)) != nil)
{
//create some local variables
local line;
//loop until we have read the entire file.
while((line = read(.fp)) != _eof_)
{
local comp = new Computation(self, line);
}
//once we have read the entire file we need to close it.
close(.fp);
}
else
{
princ ("AutoCalculation: Could not open file: ",
.fileName, ": ", strerror(errno()), "\n");
}
}
/* Write the 'main line' of the program here. */
method AutoCalculation.constructor ()
{
.readFile();
}
/* Any code to be run when the program gets shut down. */
method AutoCalculation.destructor ()
{
}
/* Start the program by instantiating the class. */
ApplicationSingleton (AutoCalculation);
Copyright © 1995-2010 by Cogent Real-Time Systems, Inc. All rights reserved.