Function Objects
Function objects allow you to create scripted views of values in the ECU. Function Objects cane be created using the
command.At present, this only applies to tables and maps. In the future Options or Channels may also be created.
For example, it is possible to create an editable map that displays the end injection angle by running scripts against the Injection Advance/Angle map and the Fuel Map. See the example script at the end of this topic. This script (or similar) is used as an initial starting point for new Function Objects.
The script for a function object is executed once when compiled to set up the context for the object. This is a good opportunity to find the objects (maps, tables etc) that your script is based upon.
Subsequently the object is accessed via a number of functions that you can define in the script:
getAxes()
getRaw(axes)
[required]setRaw(raw, axes)
getMinRaw(axes)
getMaxRaw(axes)
realFromRaw(raw, axes)
rawFromReal(real, axes)
getAxes
function getAxes()
This must return the axes of the object. This is an array that specifies the dimensions your object.
In general it is easiest to use the axes of another object (e.g. the Fuel Map):
var fuel = ecu.map("fuel");
function getAxes() {
if (fuel) return fuel.axes;
return {};
}
If this function is not defined then the object is one dimensional (like an option/channel).
getRaw
function getRaw(axes)
[required]
This should return the value of your object at the site specified by ‘axes’. The ‘axes’ parameter is an array that specifies the x and, optionally, the y coordinate of the object.
Note
The value returned will be interpreted as an integer.
function getRaw(axes)
{
if (fuel && injadv) {
// fuelAngle is a user defined function that gets the angle range
// over which fuel is injected at a given site.
return raw_per_real * (fuelAngle(axes) + injadv.getReal(axes));
}
return 0;
}
setRaw
function setRaw(raw, axes)
If specified, then the function object will be editable. This function should set the integer value ‘raw’ at the site specified by ‘axes’ in an appropriate manner.
function setRaw(raw, axes)
{
if (fuel && injadv) {
var real = raw;
real /= raw_per_real;
real -= fuelAngle(axes);
injadv.setReal(real, axes);
}
}
getMinRaw
function getMinRaw(axes)
Get the minimum raw value for the function object. If defined, this will affect how the limits are calculated for views of the function object.
getMaxRaw
function getMaxRaw(axes)
Get the maximum raw value for the function object. If defined, this will affect how the limits are calculated for views of the function object.
realFromRaw
function realFromRaw(axes)
Define how raw integer values are represented as real (floating point) numbers.
Raw numbers are always integers and a single +/- increment on a map/table/option etc generally corresponds to a single raw unit unless any overrides have been specified.
If you specify this function then you should also define its inverse, ‘rawFromReal’.
rawFromReal
function rawFromReal(axes)
Define how real (floating point) values are represented as raw (integer) numbers. The inverse of ‘realFromRaw’.
Example: End of Injection Angle Script
// ---------------------------------------------------------
// This script generates a map for the end injection angle.
// This will not take into account fuel modifiers /
// compensations that occur after the Fuel map has been
// processed by the ECU.
// ---------------------------------------------------------
//
// ---------------------------------------------------------
// Initialization.
// ---------------------------------------------------------
// First off, get hold of the base maps and options that are
// needed in our calculations.
// This code is run once after the script is compiled.
let fuel = ecu.map("fuel");
let injadv = ecu.map("inj advance");
if (injadv == null) {
injadv = ecu.map("inj angle");
}
if (injadv == null) {
injadv = ecu.map("injection angle");
}
// Some (but not all) ECUs have some additional scaling across the map
// This enables higher map resolution on 8-bit fuel maps by offsetting
// values against a general trend plane defined by ld0mpc and mspb.
let opt_ld0mpc = ecu.option("ld0mpc");
let opt_mspb = ecu.option("mspb");
if (opt_mspb == null) {
opt_mspb = ecu.option("microsec/bit");
}
if (opt_mspb == null) {
opt_mspb = ecu.option("inj microsec/bit");
}
// Raw numbers are always integers.
// To increase the resolution of our map, we can supply a
// real/raw scaling so that a single raw unit is a fraction
// of a single real number (floating point).
//
// see realFromRaw and rawFromReal below.
//
// Since edits to this map adjusts the injection angle map,
// we'll use the same precision as that map.
//
let raw_per_real = 1.0; // number of raw units per real.
if (injadv) {
raw_per_real = injadv.realFromRaw(1) -
injadv.realFromRaw(0);
raw_per_real = Math.abs(raw_per_real);
if (raw_per_real > 0) {
raw_per_real = 1 / raw_per_real;
}
else {
raw_per_real = 1;
}
}
// ---------------------------------------------------------
// Helper functions.
// ---------------------------------------------------------
// ---------------------------------------------------------
// Apply load scaling.
function ld0mpcFromRaw(d, site) {
let ld0 = opt_ld0mpc.raw;
if ((ld0 == 255) || (ld0 == 0)) {
return d;
}
// Maximum load site index:
let maxld = fuel.axes[1].siteCount - 1;
// Calculate the compressed value:
return d * (
(site / maxld) +
((maxld - site) / maxld) *
(ld0 / 256.0));
}
// ---------------------------------------------------------
function fuelUnitsAreMillisec()
{
let units = fuel.units;
switch (units) {
case "ms":
case "mS":
case "MS":
case "Ms":
// Fuel is already displayed in milliseconds,
// so no calculations are required.
return true;
default:
return false;
}
}
// ---------------------------------------------------------
// Get the fuel injector pulsewidth, in milliseconds.
function fuelMillisec(axes) {
if (fuelUnitsAreMillisec()) {
// Fuel is already displayed in milliseconds,
// so no calculations are required.
return fuel.getReal(axes);
}
// Calculate pulsewidth in milliseconds.
// On many ECU's this is scaled via mspb and ld0mpc from
// the raw fuel value.
let raw = fuel.getRaw(axes);
// For ECU's that do not use MSPB or Microsec/bit,
// the default mspb value may require tweaking so that
// the view is correct when the Fuel Map is viewed in
// pulsewidth mode.
let mspb = 1;
if (opt_mspb) {
mspb = opt_mspb.real;
}
if (opt_ld0mpc) {
let load_site = axes[1];
raw = ld0mpcFromRaw(raw, load_site);
}
return raw * mspb / 1000.0;
}
// ---------------------------------------------------------
// Calculate the angle range that fuel is injected over
// from a given fuel pulsewidth and engine RPM.
function fuelAngleFromMS(ms, rpm) {
// Seconds that the injector is open for.
let s = ms / 1000.0;
// degrees per second
let dps = 360.0 * rpm / 60.0;
return dps * s;
}
// ---------------------------------------------------------
// Calculate the angle range that fuel is injected over
// at a given Fuel Map site.
function fuelAngle(axes) {
// Get the RPM from the Fuel Map axis table
let ms = fuelMillisec(axes);
let rpm = fuel.axes[0].getReal([axes[0]]);
return fuelAngleFromMS(ms, rpm);
}
// ---------------------------------------------------------
// Map data access functions.
// This code is called as needed by the application.
// ---------------------------------------------------------
// ---------------------------------------------------------
// Get the axes of our calculated map.
// In this case we use the same axes as the Fuel Map.
function getAxes() {
if (fuel) return fuel.axes;
return [];
}
// ---------------------------------------------------------
// Get the raw integer calculated value at the given site.
function getRaw(axes) {
if (fuel && injadv) {
return raw_per_real *
(fuelAngle(axes) + injadv.getReal(axes));
}
return 0;
}
// ---------------------------------------------------------
// Set the raw integer calculated value at the given site.
// This adjusts the injection start angle such that the end
// injection angle is set to the provided value.
function setRaw(raw, axes) {
if (fuel && injadv) {
let real = raw;
real /= raw_per_real;
real -= fuelAngle(axes);
injadv.setReal(real, axes);
}
}
// ---------------------------------------------------------
// Get minimum raw integer value for this calculated map.
function getMinRaw(axes) {
return raw_per_real * injadv.minReal;
}
// ---------------------------------------------------------
// Get maximum raw integer value for this calculated map.
function getMaxRaw(axes) {
return raw_per_real *
(injadv.maxReal + fuelAngleFromMS(60, 10000));
}
// ---------------------------------------------------------
// Get the scaled floating point value from a raw value.
function realFromRaw(raw, axes) {
return raw / raw_per_real;
}
// ---------------------------------------------------------
// Get the raw value from a scaled floating point value.
function rawFromReal(real, axes) {
return real * raw_per_real;
}