analogue value
logical value a/m, s/n,v/n
Logical values represent logical results of measurements or calculations, or status flags.
block reference
text string
One to seven character string used to identify groups of blocks
which are associated
Number from 0 to 15. Specifies execution frequency for executable
blocks.
Floating point number. This is the analogue result of the block.
Logical flag which may be a (auto/true/1) or m (manual/false/0).
This flag enables or disables the block for normal scanned execution.
Logical result of block, may be v (violated/true/1) or n
(nonviolated/false/0).
This flag may be s (set/true/1) or r (reset/false/0).
If it is s and the block is executed the block's am flag
will subsequently be reset (to m) thus ensuring that the block executes
only once.
This string parameter may be used to identify the block, and is
printed in parenthese () after the block number when printed in engineers
mode. The text string is converted to upper case, and may not include spaces.
It must also be unique, attempts to enter an existing nn into a
block will be regected by eng. A maximum of 29 characters are accomodated.
Within eng blocks may be located using th '_' command imedeately followed
by a string. All matches will be listed, and connection will be made to
the last match. To clear an nn paramter enter nn-
example:
b6301 _FIR
Block 6301 (FIRST-AO) type analogue out
Block 14001 (FIRST-DI) type analogue out
b14001
example: (must be unique)
b14011 nnFIRST-DI
b.name
(name in use - block 14001)
This string parameter is used by various parts of the system to
identify the block. For example the PI-Bus driver inserts card and point
identification here for user information.
example:
b5301 b14037;p
Block 14037 () type dig input
Block 14037 () type dig input
nn.b.name
de.descr
nm.name DI card 03 point 05
tg.tag
0 sn.scan 0(0.0 sec) ra.rslta
0.000
am.au/mn m vn.vltn
n ss.sshot r
en.A Entpr 0
dd.D Entpr 0
b14037
The Indata (plc) driver uses the information here to identify 'nin'
and 'nout' numbers.
This string parameter is used as a textual description of the block.
It is useful in adding short comments which are displayed on the drawing
produced by the engdraw program. Text is converted to uppercase.
b14011 deThis is a bit of text to explain that this block is a digital
input block
descr
=THIS IS A BIT OF TEXT TO EXPLAIN THAT THIS BLOCK IS A DIGITAL INPUT BLOCK
One analogue output block is connected to each PI-Bus analogue output
point.
The Digital input block reflects the status of a discrete signal from
the process.
The Digital output block asserts the status of its am flag in
the form of a discrete digital output.
The Pulse duration Output block is used for plant control via two discrete
digital output, producing a timed raise or lower signal, to effect the
required control action.
One K48 analogue input/output block is connected to each analogue input
point and corresponding analogue output point on a SIOX K48 module. The
calibrated output is presented on the block ra parameter.
This block is used to connect one SIOX N45 I/O module to various other ABACUS I/O blocks.

One analogue input block is connected to each PI-Bus analogue input point. The calibrated output is presented on the block ra parameter. The block has the following parameters in addition to the common parameters tg sn ra am vn and ss.
integer_value
integer_value
This parameter sets the gain of the amplifier as follows
|
|
gain | range |
|
|
1 | 0 - 10 volt |
|
|
2 | 0 - 5 volt |
|
|
4 | 0 - 2.5 volt |
|
|
8 | 0 - 1.25 volt |
|
|
16 | 0 - 625 m volt |
|
|
32 | 0 - 312.5 m volt |
|
|
64 | 0 - 156.25 m volt |
|
|
128 | 0 - 78.125 m volt |
|
|
256 | 0 - 39.0625 m volt |
|
|
512 | 0 - 19.53125 m volt |
|
|
1024 | 0 - 9.765625 m volt |
block_number or indirect
floating_point_value
This is the result of the analogue to digital conversion represented as 0.0 to 100.0 (unipolar) or -100.0 to 100.0 (bipolar).
floating_point_constant
floating_point_constant
The block result is calculated using the following equation
One analogue output block is connected to each PI-Bus analogue output point. The block has the following parameters in addition to the common parameters tg sn ra am vn and ss.
sp set point floating_point_value
hl high limit floating_point_value
ll low limit floating_point_value
sp set point
The full output range of the analogue output is represented by a setpoint of 0-100. On the first scan after the am is set the sp set point is made equal to the current output.
hl high limit
ll low limit
The sp is constrained between the values of hl and ll , before being further processed.
The Digital input block reflects the status of a discrete signal from the process. The vn flag will be v when the discrete signal is active, and n otherwise. Although the block has all the common parameters including sn and am it is scanned independently of the normal block scanning process.
The Digital output block asserts the status of its am flag in the form of a discrete digital output. Depending on the process I/O used the vn flag may indicate the actual status of the digital output. Although the block has all the common parameters including sn, it is scanned independently of the normal block scanning process.
The Pulse duration Output block is used for plant control via two discrete digital output, producing a timed raise or lower signal, to effect the required control action. In addition to the common parameters the following exist
sp set point floating_point_value
hl high limit positive floating_point_value
ll low limit positive floating_point_value
sp set point
The required number, and duration of pulses required are cascaded into the sp of this block. Cascading +1.00 produces a raise pulse of one unit duration, -1.00 a lower pulse of one duration.
On the first scan after being set auto the sp is set to zero.
hl high limit
The maximum duration of pulse permitted in either direction is determined by the hl high limit value. If the absolute value of sp is greater than hl then hl pulses will be sent
ll low limit
The minimum duration of pulse permitted in either direction is determined by the ll low limit value. If the sp is less than ll then no pulse will be sent.
ra result a
The value of ra represents the actual pulse length to be sent. If an sp value greater than a predetermined maximum is sent then only that maximum is sent and the value of sp is reduced by that amount. Thus pulses are carried forward from one scan to the next.
The actual execution of the pulse duration depends on hardware. If a SIOX N45 module is to be used, the PDO block must be referenced in the N45 module block, see N45 section.
The Indata communications protocol is based on markers. Each of the units on an Indata network has an address in the range 1-31. Markers have a number in the range 1-511 (coresponding to blocks 18001 to 18511). Only one unit on the network should write a marker, but any or all of the units may read that marker. Markers may be either analog or digital.
In the Indata programming language a marker is set using a NOUT entity, and is read using a NIN entity.
If ABACUS reads a marker (set by another unit) it will detect the type (analog or digital), the source address and the value. The value will be put into the ra of the block for analog markers, or the vn for digital markers.Text is inserted in the nm parameter describing the address and type or marker. For example if a digital marker (1) from unit with addres 1 is received
nin d adr 1 mark 1
will be written.
If ABACUS is to output a marker then the nm must have text of the following format.
nout d
or
nout a
The digital value of the am flag or analog value of the ra will be transmitted onto the network.
To avoid scanning the entire address range when only some addresses are present the first and last uPLD addresses are defined in the ra parameters of block 23 and 23 respectively.
The cycle time is defined by setting a value in the ra of block 24. This value is the polling frequency of the driver in milliseconds.
To reduce trafic, the Indata protocol allows polling of changes of signals in addition to taking all values. The C/I ratio is the ratio of the number of Change messages to Init (i.e. all signals) messages.
sudo $ABACUS_HOME/indata /dev/cua1 9600 21 18001 &
sudo $ABACUS_HOME/indata /dev/cua2 9600 31 19001 &
sudo $ABACUS_HOME/indata /dev/cua3 9600 41 20001 &
One method is to use a RS232 - RS422 (4-wire) converter with the RS422 TX and RX pairs connected together.
TX+ ----+-----------------+--------------+-----------+ | | | | TX- ----|--+--------------|--+-----------|--+--------|--+ | | | | | | | | RX+ ----+ | | | | | | | | RX- -------+

One K48 analogue input/output block is connected to each analogue input point and corresponding analogue output point on a SIOX K48 module. The calibrated output is presented on the block ra parameter. The block has the following parameters in addition to the common parameters tg sn ra am vn and ss.
ao analogue output block number
ds data source integer constant
mx max value floating_point_constant
ze zero floating_point_constant
The block result is scaled to the range ze to mx corresponding to 0 to 100 % input. This may be 0 - 20mA, 4 - 20mA, or 0 - 10 V depending on the hardware configuration of the K48 module.
The K48 module should be configured to have 4 addresses, (4A/I and 4A/O). The value of ds defines both the SIOX port used and the point address. ds should be 10000 + 100*port number + SIOX point address. i.e. for port number 2, SIOX point address 5 ds should be 10205.
The ao parameter should be connected to an analogue output block, whose result will be sent to the corresponding point address.
The block has the following parameters in addition to the common parameters
tg
sn ra am vn and ss.
| ds | data source | integer constant |
| oa | output a terminal 1 | block_number |
| ob | output b terminal 2 | block_number |
| oc | output c terminal 3 | block_number |
| od | output d terminal 4 | block_number |
| oe | output e terminal 5 | block_number |
| ia | input a terminal 10 | block_number |
| ib | input b terminal 11 | block_number |
| ic | input c terminal 12 | block_number |
| id | input d terminal 13 | block_number |
| ie | input e terminal 14 | block_number |
| if | input f terminal 15 | block_number |
| ig | input g terminal 16 | block_number |
| ih | input h terminal 17 | block_number |
| ii | input i terminal 18 | block_number |
| ij | input j terminal 19 | block_number |
| ik | input k terminal 20 | block_number |
| il | input l terminal 21 | block_number |
| im | input m terminal 22 | block_number |
| in | input n terminal 23 | block_number |
The value of ds defines both the SIOX port used and the point address. ds should be 10000 + 100*port number + SIOX point address. i.e. for port number 2, SIOX point address 5 ds should be 10205.
The SIOX N45 I/O module is a general purpose digital I/O module with 7 sourcing output and 14 inputs, all 10V - 35V DC. The outputs can supply 0.5A each and have short circuit protection. Through the built-in CPU and a simple PLC programming language, curtain options are available.
If the PLC programme has been correctly loaded and configured, a number of the outputs may serve as pulse duration outputs. The corresponding output parameter (oa - og ) should be connected to a pdo block. Enter the pdo block as a positive number to connect the raise side, and as a negative number for the lower side. Thus it is possible to connect raise and lower in any combination. The pdo function, if programmed into to N45 module excludes ordinary digital output operation for those specified output points. It is possible to configure any combination of digital outputs and pdo outputs.
| This block type functions as an AND or OR gate for up to five logical inputs, any or all of which may be inverted. | |
| The switch block derives a single logical result (vn), and can switch auto or manual two blocks, depending on the status of a single logical input. Two list processing algorithms allow ranges of blocks to be switched. | |
| The pattern block is used to switch up to five blocks auto or manual. |

The checklist block derives a single logical result (vn), and
can switch auto or manual one block, depending on the status of five logical
inputs. The block has the following parameters in addition to the common
parameters tg sn ra am vn and ss.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The logical result of the five blocks specified by each of the logical inputs in turn (ia,ib ,ic,id,ie) is processed by its coresponding algorithm ( aa,ab,ac, ad,ae) to generate five intermediate logical results in accordance with table ck1. (Note that only aa can have a value greater than one.)
Unconnected inputs are ignored.
af = 0 AND operation
The logical result of the block will be v (true) only if all of the five intermediate logical results are true (1).
af = 1 OR operation
The logical result of the block will be v (true) if any of the five intermediate logical results is true (1).
Table ck1
|
|
|
|
|
|
|---|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
||
The block addressed by the sv parameter will be affected in accordance with table ck2.
Table ck2
| intermediate result | switch type s | switch type r | switch type + | switch type - |
| target block becomes | ||||
| 1 | a | m | a | m |
| 0 | - | - | m | a |
The switch block derives a single logical result (vn), and can
switch auto or manual two blocks, depending on the status of a single logical
input. The block has the following parameters in addition to the common
parameters tg sn ra am vn and ss.
| ia | logical input | block_number or indirect_block_number |
| aa | algorithm a | 0 - 7 |
| sa | switch a | block_number s/r/+/- or indirect_block_number s/r/+/- |
The status of the logical input specified by the input a ia parameter is processed by algorithm a aa and the target block's am auto/manual flag is changed in accordance with table sw1 .
The logical result of the block is set to the intermediate logical result
derived by aa algorithm a.
| ab | algorithm b | 0 - 7 |
| sb | switch b | block_number s/r/+/- or indirect_block_number s/r/+/- |
The status of the logical input specified by the input a ia parameter is processed by algorithm b ab and the target block's am auto/manual flag is changed in accordance with table sw1 .
List processing
These algorithms permit the execution of the block's algorithm over a contiguous list of blocks instead of individual blocks. The target list is specified by sa and sb . The first output block is specified by sa, the last by sb . The input list is of exactly the same length as the output list, thus it is only necessary to specify the first input block with ia. Indirection is allowed on ia, sa and sb. The direction of processing is always from the first to the last, and cannot be reversed; thus the block specified as the first output block must have a lower or equal block number as that specified as the last. If ia is zero then an imaginary input list of blocks all having a 0 (nonviolated,reset, false) logical result is used.
The only restriction to the size of the lists is that they must both be accommodated within the constraint of the system.
aa = ab = 6 List processing (inverting)
The switch type of both sa and sb must be the same. For each block an intermediate result is calculated and the corresponding target block is modified as if the algorithm were 0 (inverting).
aa = ab = 7 List processing (noninverting)
This algorithm functions in the same list processing way as above, except that for each block an intermediate result is calculated and the corresponding target block is modified as if the algorithm were 1 (noninverting).
Table sw1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
||
|
|
list processing (inverting) see text | |||||||
|
|
list processing (noninverting) see text | |||||||

The pattern block is used to switch up to five blocks auto or manual.
The block has the following parameters in addition to the common parameters
tg
sn ra am vn and ss.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Each time the block is executed the blocks specified by switches sa to se are switched auto or manual depending on the specified switch type s or r respectively.
Note unless continual and repeated operation is desired it is usual to the set the single shot flag ss to s.
The p.i.d. block is designed to perform P, PI, or PID control functions, with standard control constants, executing a variety of alternative control algorithms, and calculating control performance data at the same time.
The motor block is designed to allow comprehensive control of the starting/stopping
of electric motors, pumps, and opening/closing of valves. The connections
are made through digital inputs and outputs. Facilities are included to
initiate alarm signals if the motor/pump fails to respond to control signals
in allowed time periods. The accumulation of run time is also included.

The p.i.d. block is designed to perform P, PI, or PID control functions,
with standard control constants, executing a variety of alternative control
algorithms, and calculating control performance data at the same time.
In addition to the common parameters the p.i.d. block has the following
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The am flag of a pid block may be considered as an îauto-requestî flag. When the am flag is auto the loop may be regarded as requested auto. The vn flag may be regarded as that flag which indicates that the loop is in fact operating in automatic.
When conditions are right for the controller to start operating in automatic the vn falg is set, and previous stored values of er are set to zero, and previous values of mv are set to the current mv value. If the se flag is set ( e equalise) then the setpoint value is made equal to the measured variable. This is done to ensure bumpless transfer.
ir input run
If the vn violation status of any block connected here is v then the normal processing of the block may proceed. The vn of this pid block is made the same as that of the pointed to block if this pid block is auto. If this pid block is inactivated because of this connection it will be initialised when reactivated. This allows interlocking of control loops.
ip input process
If the vn violation status of any block connected here is v then the normal processing of the block may proceed. No re-initialisation is performed nor is the vn status changed as a consequence of this connection. This parameter is intended for use with the ai=1 dead time controller option.
ia input a
The measured variable (mv) in the following is derived from the analogue result ra of the block specified here.
mh input hl, ml input ll
These limits are used to constrain the value of the measured variable (mv).
is input setpoint, sp setpoint
If the is value is that of a valid block number, then the sp value is obtained from the analogue result ra of that block. The sp value is the same as the ra of this block.
sh setpoint hl, sl setpoint ll
These limits are used to constrain the value of sp. Upon execution of this block the ra of the block pointed to by is will also be constrained, That is to say the constrained sp is fed back to the block pointed to by is on each scan.
op output block, an answer
an answer is the result of the control equation below which is then added to the op output block. If the op output block is an analogue output, pulse duration output or a control block the value of an is added to the sp of that block, other wise it is added to its ra.
Note that because of the fact that an incremental value is added to the op output block it is possible to alter manually, or with other blocks, that value.
er = sp - mv
er_1 = er from previous scan
er_2 = er from two scans previous
mv_1 = mv from previous scan
mv_2 = mv from two scans previous.
an = kp * ( prop_value + int_value + deriv_value )
where prop_value, int_value and deriv_value are internal temporary variables depending on the algorithms and constants as follows
td derivative time, ad derivative algorithm, deriv_value
if ad = 0 then
deriv_value =(mv - 2*mv_1 + mv_2) * td / scan_time_in_minutes
if ad = 1 then
deriv_value =(er - 2*er_1 + er_2) * td / scan_time_in_minutes
if ad = 3 then
er = error squared, (note if error is -ve, er is also made -ve)
deriv_value =(er - 2*er_1 + er_2) * td / scan_time_in_minutes
Derivative time (in minutes) can be set to zero to disable derivative action. The derivative action may be configured to operate on the measured variable (ad=0) or the error ( ad=1). Even error squared control is available with (ad=3).
kp proportional constant, ap proportional algorithm, prop_value
if ap = 0 then prop_value = er - er_1
if ap = 1 then prop_value = mv - mv_1
The proportional action may be configured to operate on the error ( ap=0) or the measured variable ( ap=1)
ti integral time, ai integral algorithm, int_value
if ti is not equal to 0 then int_value = er * scan_time_in_minutes / ti
To disable integral action simply set ti to 0, otherwise ti represents integral time in minutes. ( ai integral algorithm is reserved for future use.)
These parameters are reserved for future use.
if ag = 0 gf = gf + abs( er ) absolute error
if ag = 1 gf = gf + er * er error squared
if ag = 2 gf = gf + abs( er ) * db absolute error * time
if ag = 3 gf = gf + er * er * db error squared * time
After a step change in demand, one can look at the rising value of gf
and compare with other tuning constants.
Motor Block

The motor block is designed to allow comprehensive control of the starting/stopping of electric motors, pumps, and opening/closing of valves. The connections are made through digital inputs and outputs. Facilities are included to initiate alarm signals if the motor/pump fails to respond to control signals in allowed time periods. The accumulation of run time is also included.
Each of the logical inputs and outputs has associated with it an algorithm for inverting the significance of that input or output. In each case this algorithm follows the normal ABACUS convention where 1=noninverting, and 0=inverting.
In addition to the common parameters the motor block has the following
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Check if sn = current scan & am = a No - exit
Yes
Read in all logical inputs to internal flags
IRVAL = logical result of ir if ar=1 else not logical result of ir
IUVAL = logical result of iu if au=1 else not logical result of iu
ITVAL = logical result of it if at=1 else not logical result of it
IPVAL = logical result of ip if ap=1 else not logical result of ip
ICVAL = logical result of ic if ac=1 else not logical result of ic
C1VAL = logical result of c1 if a1=1 else not logical result of c1
C2VAL = logical result of c2 if ar=1 else not logical result of c2
SAVAL = logical result of sa if na=1 else not logical result of sa
SRVAL = logical result of sr if nr=1 else not logical result of sr
SPVAL = logical result of sp if np=1 else not logical result of sp
Read in time values from scratchpads if specified
t1 = if (d1 is a block) d1's ra
t2 = if (d2 is a block) d2's ra
t3 = if (d3 is a block) d3's ra
t4 = if (d4 is a block) d4's ra
if t1 > t2 then set saval (alarm) (time-out)
if IPVAL (stop input) then reset SAVAL (alarm)
if ITVAL (start i/p) is set then set SRVAL (start o/p)
if SRVAL (start o/p) is set then
if IRVAL (run i/p) ir reset
or t2 > t1 or IPVAL (stop i/p) or ICVAL (auto) is set
then reset SRVAL (start switch)
if ICVAL (auto) is set then
if IRVAL (ready i/p) is reset
or t2 > t1 or IPVAL (stop i/p) or ITVAL (start) is set
then reset ICVAL (auto flag)
if ICVAL is set (auto)
then
if af = 0 do îANDî control action i.e.
if C1VAL AND C2VAL then set SRVAL (start)
else reset SRVAL (start)
else
if af = 1 do îORî control action i.e.
if C1VAL OR C2VAL then set SRVAL (start)
else reset SRVAL (start)
Calculate timer values
if SRVAL is set (start requested) and IUVAL (running i/p) is reset
then increment t2
if IUVAL is set (runnning) then increment t3
if t3 > 3600
then increment t4, and subtract 3600 from t3
(t4 becomes hours if t3 is seconds)
set SPVAL to the complement of SRVAL
(i.e. stop o/p opposite of start o/p)
reset is and ip blocks (start and stop scratchpads)
is = if (as = 1) then 0 else 1
ip = if (ap = 1) then 0 else 1
set / reset logical block in accordance with internal flags
ic block = if ( (ICVAL = 1) & (ac = 1) )
or ( (ICVAL = 0) & ( ac = 0) ) then 1 else 0
sr block = if ( (SRVAL = 1) & (nr = 1) )
or ( (SRVAL = 0) & ( nr = 0) ) then 1 else 0
sp block = if ( (SPVAL = 1) & (np = 1) )
or ( (SPVAL = 0) & ( np = 0) ) then 1 else 0
sa block = if ( (SAVAL = 1) & (na = 1) )
or ( (SAVAL = 0) & ( na = 0) ) then 1 else 0
FINISH
| Index Block | This block type is used for counting, timing and integer arithmetic. |
| Input code conversion block | The input conde conversion block is used to reference a continuous range of logical block results and produce an analogue result depending upon their status. |
| Output code conversion block | The output conde conversion block is used to convert an analogue result into a bit pattern and switch a continuous range of blocks. |
| Control Block | The control block is a multifunction block capable of many different types of calculation, control functions, accumulation functions, and list processing. |
| Sequence Block | This block causes the execution of curtain other blocks independently of their scan parameters in a sequence determined by an input list to the sequence block. Alternatively a serial programme can be executed. |
| Scratchpad Block | All blocks which have no other block type are classified as scratchpad blocks. Scratchpad blocks are nonexecutable, and only have the common parameters. They are used for analogue and data storage only. |
The index block is used for counting, timing and integer arithmetic. The block has the following parameters in addition to the common parameters tg sn ra am vn and ss.
| ia | logical input | block_number or indirect_block_number |
|---|---|---|
| aa | algorithm a | 0 - 7 |
| ib | analogue input | block_number or indirect_block_number |
| ab | algorithm b | 0 - 7 |
| hl | high limit | floating_point_constant |
| ll | low limit | floating_point_constant |
| k1 | constant | floating_point_constant |
ia input a, aa algorithm a
The status of the logical input specified by the ia parameter is processed by aa in accordance with table IX1. If the intermediate logical result is 1 then further processing is carried out as described below, otherwise processing is discontinued, except for the initialisation described for ab of 1.
ib input b
The analogue result of the block specified by this parameter is used as the measured variable in further processing of this block.
hl high limit, ll low limit, k1 constant
The value of these parameters are used in the various calculations performed in accordance with ab.
| algoritm | logical | logical | intermediate | |
|---|---|---|---|---|
| description | previous | current | result | |
| 0 | off (inverting) | - | 0 | 1 |
| - | 1 | 0 | ||
| 1 | on (noninverting) | - | 1 | 1 |
| - | 0 | 0 | ||
| 2 | on-going | 0 | 1 | 1 |
| 1 | 1 | 0 | ||
| 1 | 0 | 0 | ||
| 0 | 0 | 0 | ||
| 3 | off-going | 1 | 0 | 1 |
| 0 | 0 | 0 | ||
| 0 | 1 | 0 | ||
| 1 | 1 | 0 | ||
| 4 | any-change | 0 | 1 | 1 |
| 1 | 0 | 1 | ||
| 0 | 0 | 0 | ||
| 1 | 1 | 0 | ||
| 5 | no-change | 0 | 0 | 1 |
| 1 | 1 | 1 | ||
| 0 | 1 | 0 | ||
| 1 | 0 | 0 |
ra = measured variable + k1
If ib is nonzero ra = measured variableFurther processing of this algorithm only occurs if the logical input ia and its algorithm aa produce an intermediate result of 1. Each time this algorithm is processed, the value of ra and vn are updated according to the following conditions.If k1 = 0 thenIf ib is zero and k1 = 0 ra = ll
If ib is zero and k1 < 0 ra = hl
if ra+k1 hl thenra = ll, and vn = v
else
ra = ra + k1 , and vn = n
If k1 < 0 then
if ra+k1 < ll then
ra = hl, and vn = v
else
ra = ra + k1 , and vn = n
In this way the value of ra steps from one limit to the other
with steps of k1. When arriving at the limit the violation flag
is set for one scan.
ra = k1 - measured variableIf ( ra < ll ) or ( ra hl ) vn = v
else vn = n
ra = k1 * measured variableIf ( ra < ll ) or ( ra hl ) vn = v
else vn = n
ra = measured variable / k1If ( ra < ll ) or ( ra hl ) vn = v
else vn = n
ra = k1 / measured variableIf ( ra < ll ) or ( ra hl ) vn = v
else vn = n

The input code conversion block is used to reference a continuous range of logical block results and produce an analogue result depending upon their status.
In addition to the common parameters the input conde conversion block has the following

The output conde conversion block is used to convert an analogue result into a bit pattern and switch a continuous range of blocks.
In addition to the common parameters the output conde conversion block has the following
aa = 0 binary transferThis algorithm transfers the binary pattern of the measured variable
to the am flags of the specified range of blocks. The block specified
by sw is regarded as the least significant bit in the word, and
is represented by 1 in the measured variable, the next block by 2 then
by 4 etc. Should a bit be set in the measured variable then the corresponding
output block will be set auto, otherwise it will be set manual.

The control block is a multifunction block capable of many different
types of calculation, control functions, accumulation functions, and list
processing. The ab algorithm b parameter specifies the manner in
which the control block is processed. The algorithms are divided into three
main categories.
|
0 to
|
9
|
|
|
10 to
|
13
|
|
|
14 to
|
19
|
|
|
20 to
|
25
|
|
The block has the following parameters in addition to the common parameters
tg
sn ra am vn and ss.
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
result is the intermediate analogue result which is then process by aa.
| ab | description | calculation(s) performed |
|---|---|---|
| 0 | simple transfer | result = sp + in - mv (mv = ra of ia block) |
| 1 | simple ratio | result = (sp + in - mv) * k1 |
| 2 | flow rate conditioning | result = k2 * sqrt( (mv - k1)*(sp + hl)/(in + ll) ) |
| 3 | general mathamatics | result = k2 * (mv - k1) * (sp + hl)/(in + ll) |
| 4,5,6 | two term control | error = sp + in - mv (error is an internal variable) |
| result* = k1 * ( error - k2 * er ) | ||
| er = error | ||
| *Note | ||
| 4 | er is used for aa calculation | |
| 5 | ra is used for aa calculation | |
| 6 | sp is used for aa calculation | |
| 7 | natural logarithm | result = k2 * ln( (mv - k1)*(sp + hl)/(in + ll) ) |
| 8 | exponential | result = k2 * exp( (mv - k1)*(sp + hl)/(in + ll) ) |
These algorithms operate on the contiguous list of block defined as those blocks between is and ia. ia should refer to a block with higher block number than that pointed to by is.
result is the intermediate analogue result which is then process by aa.
| ab | description | calculation performed |
|---|---|---|
| 10 | sum | result = k2 + k1 * sum ( is .. ia ) |
| 11 | ave | result = k2 + k1 * ave ( is .. ia ) |
| 12 | max | result = k2 + k1 * max ( is .. ia ) |
| 13 | min | result = k2 + k1 * min ( is .. ia ) |
Algorithms are either pre-initialised or post-initialised.
Pre-initialisation involves resetting the accumulations and setting the result to zero the first time the block is processed after having been set auto.
Post-initialisation processes the accumulations to obtain the result prior to resetting the accumulations, on the first scan after the block has been set auto. This having the advantage that the block may be left manual whilst accumulating, it only being necessary to set it auto to obtain the result, and to reset the accumulations for the next period. (It is normal to set the single shot flag ss in this case.)
acc is an internal floating point variable which is incremented by the cascading block with its result each time it cascades.
| ab | description | calculation(s) performed |
|---|---|---|
| 14 | integration pre-initialised | result = acc / ( k1 * 100 ) |
| 15 | integration post-initialised | result = acc / ( k1 * 100 ) |
| 16 | average pre-initialised | result = acc / er (er = number of samples) |
| 17 | average post-initialised | result = acc / er (er = number of samples) |
| 18 | std. deviation pre-initialised | result = k1 * standard deviation (-1 if less than 10 samples) |
| 19 | std. deviation post-initialised | result = k1 * standard deviation (-1 if less than 10 samples) |
ia
The input a ia parameter specifies the first of a range of blocks to be used as inputs to these algorithms. During processing, the algorithm steps from the first input block to next, then the next etc., and at each step reads the result of the input block which then becomes the measured variable mv. If the input a ia parameter is zero then the measured variable is regarded as zero for all steps.
| ca | cascade a | block_number cascade_type or indirect_block_number cascade_type |
| cb | cascade b | block_number cascade_type or indirect_block_number cascade_type |
The ca parameter specifies the first block to receive a cascade from the list processing algorithm. The cb parameter specifies the last block to receive a cascade. The number of target blocks is thus defined by the cascades, and therefore the number of input blocks is the same. cb must point to a higher block number than ca.
The cascade type must be the same for both ca and cb, and must be consistent with the type of target block.
When the algorithm is processed the measured variable is taken from each input block in turn. The measured variable is processed and the result cascaded to the corresponding target block.
For each item of data thus processed, limits are checked to produce an intermediate violation status, and result which are taken into account by the cascades.
When the block specified by cb has been processed the algorithm is finished and the last calculated result and violation status are the final values for the block.
| ab | description | calculation(s) performed |
|---|---|---|
| 20 | simple transfer | result = mv |
| 21 | multiplication | result = (sp - mv) * k1 |
| 22 | division | result = (sp - mv) / k1 |
| 23 | division | result = k1 / (sp - mv) |
| 24 | multiply input | result = mv * A / k1 A = initial value of by output result to be cascaded to |
| 25 | simple transfer | result = mv mv = result of block whoseindirect input number is the result of the current input. If this number is invalid no cascade is performed at this stage. |
aa Logical algorithm
The analogue result of the block calculated by the various algorithms ( ab) is further processed by aa. (In the case where ab = 4 it is the value of er, where ab = 6 it is the value of sp) The list processing algorithms have the result processed by aa at each step.
These parameters are related to the final ra and vn values as in the following table.
|
|
ra hl
|
ll <= ra <= hl
|
ll ra
|
|||
|---|---|---|---|---|---|---|
|
ra
|
|
ra
|
|
ra
|
|
|
|
|
result
|
|
result
|
|
result
|
|
|
|
result
|
|
result
|
|
result
|
|
|
|
hl
|
|
result
|
|
ll
|
|
|
|
result
|
|
0
|
|
result
|
|
All blocks which have no other block type are classified as scratchpad blocks. Scratchpad blocks are nonexecutable, and only have the common parameters. They are used for analogue and data storage only.
The operator communicates with ABACUS4 via an operators station. This is usually a PC running the Linux operating system and the X window system. This may be the same system that is running ABACUS4 or another reachable over a network.
Text based operator interfaces may be constructed, but these are not documented here.
All normal operator access to the ABACUS4 block database is done via the Alarm Code Block, although all blocks are accesable to the Tck/tk language.
The Alarm Code Block permits the monitoring of the analogue or logical results of blocks, and the generation of process alarms when limits are violated, or upon changes.
The block permits the operator access to its high and low process limits,
and to the result, setpoint, auto/manual and auto/manual request flags
of the loop being monitored.

The Alarm Code Block permits the monitoring of the analogue or logical results of blocks, and the generation of process alarms when limits are violated, or upon changes.
The block permits the operator access to its high and low process limits, and to the result, setpoint, auto/manual and auto/manual request of the loop being monitored.
In addition to the common parameters the Alarm Code Block has the following
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
This is the loop name which is used in all ABACUS journaling. (It should be copied over the the descriptor of any Enterprise Server database points - see later.)
ia input a
The ra of the block referenced here is taken as the measured variable of the loop. Subject to the value of aa it is this block's result which is tested against the various limits.
is input setpoint
The ra of the block referenced here is taken as the setpoint of the loop.
ar auto/man request
The vn of the block referenced here is taken as the auto/man request flag of the loop. That is to say the flag which is set when the operator requests that the loop go into auto.
st status
The vn of the block referenced here is taken as the auto/man status flag of the loop. That is to say the flag which is set when the loop is in auto.
hl high limit
ll low limit
xh high high limit
xl low low limit
hy hysteresis value
Each time the measured variable passes one of the above limit values a message is recorded in the journal file, excepting that if the hy value is nonzero a return excursion is ignored until a movement greater than hy occurs. This can be used to avoid multiple alarms when a noisy signal goes into alarm.
For correct functioning of the limit test facilities the following should be true
xh > hl > ll > xl, and hy should be positive and less than the difference between any two of the other limits.
s1 status 1 (alarm) text
The text string written by the block processor here depends on the relationship between the measured value and the alarm limits. If hy = 0 the following is carried out
if ( measured value < xl ) then s1 = lx (low low alarm text)
else if ( measured value < ll ) then s1 = ml (low alarm text)
else if ( measured value > hl ) then s1 = mh (high alarm text)
else if ( measured value > xh ) then s1 = hx (high high alarm text)
else s1 = mo (ok text)
If however the hy value is nonzero the above becomes
if ( measured value < xl ) then s1 = lx (low low alarm text)
else if ( (xl + hy ) > measured value >= xl ) then s1 is unchanged
else if ( measured value < ll ) then s1 = ml (low alarm text)
else if ( (ll + hy ) > measured value >= ll ) then s1 is unchanged
else if ( measured value > hl ) then s1 = mh (high alarm text)
else if ( (hl - hy ) < measured value <= hl ) then s1 is unchanged
else if ( measured value > xh ) then s1 = hx (high high alarm text)
else if ( (xh - hy ) < measured value <= xh ) then s1 is unchanged
else s1 = mo (ok text)
aa algorithm
This algorithm determines which limits are used to define an alarm state and set the vn of the Alarm Code Block or if the st logical value should be used. The following tables shows the effects of alternative aa values. (aa values greater than 9 inhibit the printing/logging of setpoint changes)
Analogue alarms
| aa | mv<xl | mv < ll | mv>ll&mv<hl | mv>hl | mv>xh |
|---|---|---|---|---|---|
| 0,10 | vn = n | n | n | n | n |
| 1,11 | vn = v | v | n | v | v |
| 4,14 | vn = v | n | n | n | v |
Digital alarms
| aa | st -> vn = n | st -> vn = v |
|---|---|---|
| 2,12 | vn = n | v |
| 3,13 | vn = v | n |
s2 status 2 (hand/auto) text
The text string written by the block processor here depends on the vn of the block referred to in st. If this block's vn = v then ma is copied, otherwise mm.
All changes to limit values, setpoint value, auto/manual request flag, and status changes are logged in the journal file if the Alarm Code Block is auto. One line is written for each event, and has the following format
YYMMDD HH:MM:SS signal_name message ( old_value ) new_value
where
signal_name is the si of the Alarm Code Block
YYMMDD HH:MM:SS is the time and date of the event
message = "setpoint changed"
"hi-hi lim changed"
" high lim changed"
" low lim changed"
or "lo-lo lim changed" as appropriate.
When an alarm limit is exceeded the format is as follows
YYMMDD HH:MM:SS signal_name alarm_text value units
where alarm_text is the appropriate alarm text string ( ml mh lx hx or ok ), value is the measured value, and units is the text un.
The easiest way to get to see a list of the commands is to run the xman program, and look into the n section.
Displays are stored in a subdirectory of /home/abacus. This directory has the name of the application, and also contains the datadump.bin file(s). If the project is called smith for example then these files will reside in the directory /home/abacus/smith. It is usual to have one 'display manager' file which includes code for menus and a frame for the displays to be shown in, and a number of 'display files'. In addition the background diagrams and dynamic symbols are stored in gif format.
eng2 b1234,p
Here block 1234 is printed, something like the following being returned:
Block 1234 () type index B1234 () nn de nm tg spare;sn 0(0.0 sec);ra 0.000 am m ;vn n ;ss r en 0;dd 0 aa 0;ia 0( 0.000 m-rn) ab 0;ib 0( 0.000 m-rn) k1 0;hl 0;ll 0The tcl program is responsible for extracting the part of this printout which is of interest.
eng2 requires that all the commands come together in its first argument, so that if spaces are part of the syntax, then the argument should be enclosed in quote marks. If you use this program from an xterm window for example beware of the command line conversions that your shell does, in particular the * character is translated into all the filename of files in the current area, before being passed onto, in this case, the eng2 program. This can be avoided either by enclosing you arguments in quotes, or by prefixing the * with the \ character.
eng2 is sometimes used with a unix pipe. For example if we ish to list all the si paramters of the blocks in the range 8001 to 8099 we could use
eng2 b8001,xb8099,.si
This would produce something like
Block 8001 () type alarm code Xblock 8099 type alarm code b 8001;si b 8002;si# 02 GAUGE ON/OFF SHEET b 8003;si# 03 GAUGE STATIC b 8004;si# 04 GAUGE STANDARDIZE b 8005;si ...Whereas we might not want the 'b ' parts or the ';si'. We could use the unix program sed in a pipe like this
eng2 b8001,xb8099,.si | sed -e "s/^b //" -e "s/;si/ /"which would produce something like
Block 8001 () type alarm code Xblock 8099 type alarm code 8001 8002 # 02 GAUGE ON/OFF SHEET 8003 # 03 GAUGE STATIC 8004 # 04 GAUGE STANDARDIZE 8005 8006Removal of the top two lines could be achieved with grep
eng2 b8001,xb8099,.si | sed -e "s/^b //" -e "s/;si/ /" | \ grep -v "^B\|^X"The possibilities are endless, however there are some other programs to do the simpler things easier.
frank(abacus):~$ ra 14 0.250931frank(abacus):~$ frank(abacus):~$Note that there was no end of line printed.
frank(abacus):~$ ra2 14 51 52 53 0.15332 0.1 0.2 0.58 frank(abacus):~$The values are returned in the same order as the block numbers apear in the command line.
#!/bin/sh
# ./display.sh - ABACUS operator interface
# the next line restarts using wish \
exec wish "$0" "$@" -geometry +0+0
########################################################################
#
# Simulation
#
# Initial version 990603
#
#
########################################################################
####### Edit this bit, because there should bot be any more direct
####### path references refering to the local machine.
#cd /home/abacus/
set w .page
set NODE ast
set NODE localhost
#set NODE inco
############## TITLE set here ##########################################
#
wm title . [format "ABACUS4 Display Manager - Teachers ABACUS" ]
wm resizable . 0 0
############## BACKGROUND IMAGES DONE HERE ######
frame $w
canvas $w.p -height 425 -width 630
frame $w.menu -relief raised -bd 2
label $w.welcome -text "THE DISPLAY SYSTEM IS STARTING PLEASE WAIT"
pack $w $w.menu $w.p $w.welcome -side top -fill x
update idletasks
############## GIF Files defined here ###################################
# valves pumps and blobs
foreach blob {
vent_t_green vent_t_gray vent_t_red
vent_r_green vent_r_gray vent_r_red
vent_l_green vent_l_gray vent_l_red
pump_u_green pump_u_gray pump_u_red
pump_d_green pump_d_gray pump_d_red
pump_l_green pump_l_gray pump_l_red
pump_r_green pump_r_gray pump_r_red
blob_green blob_gray blob_red
fan_u_gray fan_u_green fan_u_red
fan_d_gray fan_d_green fan_d_red
LEFTFLAME NOLEFTFLAME NORIGHTFLAME RIGHTFLAME
reel
} {
$w.welcome configure -text "doing $blob"
update idletasks
image create photo $blob -file ./$blob.gif
}
$w.welcome configure -text "done the vent & pumps"
update idletasks
# Data pages
#image create photo Pic_opcodes -file ./opcodes.gif
image create photo Pic_dp3 -file ./datapage_3.gif
image create photo Pic_dp2 -file ./datapage_2.gif
image create photo Pic_dp1 -file ./datapage_1.gif
$w.welcome configure -text "done the datapage images"
update idletasks
# Mimic pages
foreach nr {1 2 3 4 5} {
$w.welcome configure -text "starting ./process_$nr.gif"
update idletasks
catch { image create photo Pic_mp$nr -file ./process_$nr.gif}
}
$w.welcome configure -text "done the mimic images"
update idletasks
image create photo Pic
$w.p create image 0 0 -image Pic -anchor nw
############################################################################
#cd /home/abacus/
if { [info exists NODE] } {
} else {
set NODE localhost
}
############## Symbols defined here ####################################
##
## Create an image for each symbol file that is in the directory
#foreach fil [ glob /home/abacus/shapes-ppm/*.ppm ] {
## catch { foreach fil [ glob /home/abacus/shapes/*.ppm ] {
## catch { set pic [file rootname [file tail $fil]] }
## catch { image create photo $pic }
## catch { $pic configure -file $fil }
##
## catch { image create photo ${pic}_black -palette 3 }
## catch { ${pic}_black configure -file $fil }
## } }
##################### bash-net substitute ############################
proc BashNetReader { sock } {
global BashNetforever BashNetReaderResult
gets $sock line
if { $line == "e17971e17971" } {
set BashNetforever 1
catch {close $sock}
#puts stdout "BashNetReader: close $sock"
catch {close $sock}
return line
}
append BashNetReaderResult "$line\n"
return line
}
proc BashNet { sock args } {
global BashNetforever BashNetReaderResult
set BashNetReaderResult ""
set sock [socket $sock 9000]
#puts stdout "BashNet: set sock \[socket $sock 9000\]"
fconfigure $sock -blocking 1 -buffering line -translation lf
puts $sock "[lrange $args 0 end];echo e17971e17971;"
flush $sock
fileevent $sock readable [list BashNetReader $sock]
vwait BashNetforever
return $BashNetReaderResult
}
############## Menu stuff defined here ################################
#frame $w.menu -relief raised -bd 2
set m $w.menu.file.m
menubutton $w.menu.file -text "DISPLAY" -menu $m -underline 0
menu $m -tearoff 0
proc clearup {} {
global w xx
foreach xx [split [after info] " "] { after cancel $xx }
foreach xx [winfo children $w.p] { destroy $xx }
}
proc change_to_org { the_page } {
global w xx the_page_
$w.p configure -height 425 -width 630
set the_page_ $the_page
foreach i [array names bar] { unset bar($i) }
foreach xx [split [after info] " "] { after cancel $xx }
foreach xx [winfo children $w.p] { destroy $xx }
catch { uplevel #0 { source ./${the_page_}.tcl } }
catch { update0 }
timdat
}
proc change_to { the_page } {
global w xx the_page_ bar
# $w.p configure -width 630 -height 425
set the_page_ $the_page
foreach i [array names bar] { unset bar($i) }
foreach xx [split [after info] " "] { after cancel $xx }
destroy $w.p
canvas $w.p -width 630 -height 425
$w.p create image 0 0 -image Pic -anchor nw
pack $w $w.menu $w.p -side top -fill x
catch { uplevel #0 { source ./${the_page_}.tcl } }
# catch { update0 }
timdat
}
proc mem_test {} {
#set self [open /proc/self/status r]
#puts stdout "[read $self]"
#close $self
#puts stdout "info cmdcount [info cmdcount]"
}
## $m add separator
## $m add command -label "C2_1 Vällkomstbild" -command {
## clearup
## catch { source ./C2_1.tcl }
## }
$m add separator
$m add command -label "Data Page 1 " -command { change_to dp1 }
$m add command -label "Data Page 2 " -command { change_to dp2 }
$m add command -label "Data Page 3 " -command { change_to dp3 }
$m add separator
$m add command -label "Reel Report " -command { change_to reel }
$m add separator
$m add command -label "Mimic 1 Machine Overview" -command { change_to mp1 }
$m add command -label "Mimic 2 Machine Overview and PIDs" -command { change_to mp2 }
$m add command -label "Mimic 3 " -command { change_to mp3 }
$m add command -label "Mimic 4 " -command { change_to mp4 }
$m add command -label "Mimic 5 " -command { change_to mp5 }
$m add separator
$m add command -label "Journal display " -command {
catch { exec ./kill.journal.sh }
exec nice ./journal_updating.sh { } &
}
$m add command -label "Alarm display" -command {
catch { exec ./kill.alarm_banner.sh }
exec ./alarm_banner.sh & }
set m $w.menu.file2.m
menubutton $w.menu.file2 -text "DISPLAYS 2 " -menu $m -underline 0
menu $m -tearoff 0
$m add command -label "phtrend1" -command {phtrend1}
$m add separator
$m add command -label "Start a new Engineers Mode" -command { exec xterm -e /home/abacus/bashnet $NODE /home/abacus/eng & } -underline 0
$m add separator
########## Start other displays with these routines ##########
proc start_abapic {} {\
global NODE
catch { exec ./kill.abapic.sh }
catch { exec nice ./abapic.sh -geometry +0+0 & }
after 1000 exit
}
proc C2_1 {} {\
global NODE
foreach xx [split [after info] " "] { after cancel $xx }
exec nice ./C2_1.sh -geometry +0+0 &
after 1000 exit
}
proc C2_tvatsek_1 {} {\
global NODE
exec nice ./C2_tvättsekvens_1.sh -geometry +0+0 &
}
proc jump_button { name x y text } {
global NODE
global w lfont bg fg
## button $w.p.ti$name -font $lfont -background $bg -foreground $fg \
## -activebackground $bg -activeforeground $fg \
## -pady 0 -padx 3 -relief flat -borderwidth 0 -text $text -command $name
button $w.p.ti$name -text $text -command $name -pady 0 -padx 0
place $w.p.ti$name -x $x -y $y -anchor sw
}
#proc bgerror { message } {
# bell
#}
############## Blinking stuff ########################
set fulltime 1000
set fulltime 500
set blinkon 0
proc blink_change { } {
global NODE
global blinkon fulltime
after cancel blink_change
if { $blinkon } then {
set blinkon 0
} else {
set blinkon 1
}
# after $fulltime blink_change
}
##blink_change
############## Time/Date stuff defined here ################################
button $w.menu.timdat -borderwidth 0 -width 20 -justify right
proc timdat {} {
global w blinkon fulltime
global NODE
catch { $w.menu.timdat configure -text [clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S" ] }
catch { after cancel timdat }
mem_test
blink_change
after $fulltime timdat
}
############## X/Y display stuff defined here ################################
#button $w.menu.xycontb -borderwidth 0 -width 15 -command bell
button $w.menu.xycontb -borderwidth 0 -width 25 -command bell
proc show_time { time_taken } {
global NODE
global w smoothed_time
set mili_secs [ expr [lindex $time_taken 0] / 1000]
## set smoothing_factor 0.80
## if { [info exists smoothed_time] == 0 } then {
set smoothed_time $mili_secs
## } else {
## set new_smoothed_time [expr ( $smoothed_time * $smoothing_factor ) + \
## $mili_secs * ( 1.0 - $smoothing_factor ) ]
## set smoothed_time $new_smoothed_time
## }
## get newest unack alarm if there is one
set alarm_1 "[BashNet $NODE /home/abacus/alarm | sort -r | head -1 ]"
if { [string index $alarm_1 0] == "U" } then {
$w.menu.xycontb configure -text [string range $alarm_1 28 46] \
-background red -activebackground red
} else {
$w.menu.xycontb configure -text [format "%5.0f mS" $smoothed_time ] \
-background grey85 -activebackground grey95
}
}
entry $w.menu.xycont -borderwidth 0 -width 15
##$w.menu.xycont insert end "Very new pumps proc !"
bind . { $w.menu.xycont delete 0 end
$w.menu.xycont insert end "x = %x y = %y"
set destination_display {}
}
############## X/Y display button 3 puts text available for copying ################################
button $w.menu.xy3b -width 25 -borderwidth 0 -command bell
entry $w.menu.xy3 -width 20 -borderwidth 0
bind . <3> { $w.menu.xy3 delete 0 end
$w.menu.xy3 insert end "-x %x -y %y %x %y" }
bind . <2> { $w.menu.xy3 delete 0 end }
$w.menu.xy3b configure -text "([clock format [clock seconds] -format "%Y-%m-%d %H:%M" ])"
############## This stuff puts the above defined stuff on the screen ##########
#pack $w $w.menu $w.p -side top -fill x
######## Choose between the following for the x/y coordinate display ####
#pack $w.menu.file $w.menu.special $w.menu.xycont $w.menu.xy3 $w.menu.timdat -side left
#pack $w.menu.file $w.menu.xycont $w.menu.xy3 $w.menu.timdat -side left
#pack $w.menu.file $w.menu.xycontb $w.menu.xycont $w.menu.xy3 $w.menu.timdat -side left
#pack $w.menu.file $w.menu.xycontb $w.menu.timdat -side left
pack $w.menu.file $w.menu.xycontb $w.menu.xy3 $w.menu.timdat -side left
###pack $w.menu.file $w.menu.special $w.menu.xycontb $w.menu.xy3b $w.menu.timdat -side left
##pack $w.menu.file $w.menu.xy3b $w.menu.timdat -side left
pack $w $w.p -side top
update idletasks
timdat
############## Set font and colour variables ##################################
set bg black
set fg yellow
set bg white
set fg black
set lfont -adobe-helvetica-medium-r-*-*-10-*-*-*-*-*-*-*
set lfont -adobe-helvetica-medium-r-*-*-8-*-*-*-*-*-*-*
set lfont "-windows-small fonts-medium-r-normal-*-*-100-*-*-p-*-ansi-*"
set lfont -*-clean-medium-r-normal--8-*-*-*-*-*-*-*
set lfont -adobe-courier-medium-r-*-*-10-*-*-*-*-*-*-*
set lfont {courier 10 normal}
############## Entry stuff defined here ################################
set logged_in 0
proc log_in {} {
global NODE logged_in
}
proc entry_open_shut { bno acb digo } {
global NODE
global w blkno
set blkno $bno
if { $acb > 8000 && $acb < 8999 } {
set text_list [BashNet $NODE /home/abacus/eng2 b$acb,ur,hr,ma,mm,si]
set ur [string range $text_list [expr [string first \nur $text_list] + 3] [expr [string first \nur $text_list] + 9]]
set hr [string range $text_list [expr [string first \nhr $text_list] + 3] [expr [string first \nhr $text_list] + 9]]
set ma [string range $text_list [expr [string first \nma $text_list] + 3] [expr [string first \nma $text_list] + 9]]
set mm [string range $text_list [expr [string first \nmm $text_list] + 3] [expr [string first \nmm $text_list] + 9]]
set si [string range $text_list [expr [string first \nsi $text_list] + 3] [expr [string first \nsi $text_list] + 34]]
#after 50 { wm geometry $w.open +50+50 }
after 50 { wm geometry $w.open +[winfo pointerx .]+[winfo pointery .] }
catch { destroy $w.open }
set ans [tk_dialog $w.open $si $si {} [vn $bno] $hr $ur "låt bli"]
if { $ans == 0 } { BashNet $NODE /home/abacus/eng2 b$digo,con,amm }
if { $ans == 1 } { BashNet $NODE /home/abacus/eng2 b$digo,con,ama }
}
}
proc entry_kviterar { acb } {
global NODE w
if { $acb > 8000 && $acb < 8200 } {
set ac [ac $acb] ; set vn [vn $acb] ; set si [si $acb] ; get_values ;
set ac [ac $acb] ; set vn [vn $acb] ; set si [si $acb] ; get_values ;
after 50 { wm geometry $w.open +[winfo pointerx .]+[winfo pointery .] }
catch { destroy $w.open }
set ans [tk_dialog $w.open $si $si {} $ac "låt bli" "KVITTERAR"]
if { $ans == 1 } { BashNet $NODE /home/abacus/eng2 b$acb,con,ama }
}
}
proc entry_error { message } {
global w blkno
after 50 { wm geometry $w.open +[winfo pointerx .]+[winfo pointery .] }
catch { destroy $w.open }
tk_dialog $w.open $message $message {} 0 "låt bli"
}
proc entry_stuff { bno str } {
global NODE
global w blkno
set blkno $bno
after 50 { wm geometry $w.new +[winfo pointerx .]+[winfo pointery .] }
catch { destroy $w.new } ; toplevel $w.new
wm title $w.new $str
# This is like this to stop the operator clicking on some other place
# and leaving this entry stuff open
update idletasks
#grab -global $w.new
button $w.new.b1
button $w.new.b3
$w.new.b1 configure -text "Cancel" -command {destroy $w.new}
$w.new.b3 configure -text [format "Enter: %s" $str] \
-command { BashNet $NODE /home/abacus/eng2 _$blkno\;con,dd777,ra[$w.new.e1 get]
destroy $w.new }
entry $w.new.e1
$w.new.e1 insert end [ra $blkno]
pack $w.new.e1 -side top
pack $w.new.b3 $w.new.b1 -side left
focus $w.new.e1
bind $w.new { BashNet $NODE /home/abacus/eng2 _$blkno\;con,ra[$w.new.e1 get]
destroy $w.new }
bind $w.new { BashNet $NODE /home/abacus/eng2 _$blkno\;con,ra[$w.new.e1 get]
destroy $w.new }
}
proc entry_stuff_2 { bno title_ str } {
global NODE
global w blkno
set blkno $bno
after 50 { wm geometry $w.new +[winfo pointerx .]+[winfo pointery .] }
catch { destroy $w.new } ; toplevel $w.new
wm title $w.new $title_
wm geometry $w.new +50+50
#
update idletasks
#grab -global $w.new
label $w.new.label -text $str
button $w.new.b1
button $w.new.b3
$w.new.b1 configure -text "Cancel" -command {destroy $w.new}
$w.new.b3 configure -text [format "ENTER: %s" ""] \
-command { BashNet $NODE /home/abacus/eng2 b$blkno,con,ra[$w.new.e1 get]
destroy $w.new }
entry $w.new.e1
$w.new.e1 insert end [BashNet $NODE /home/abacus/ra $blkno]
pack $w.new.label $w.new.e1 -side top
pack $w.new.b1 $w.new.b3 -side left
focus $w.new.e1
bind $w.new { BashNet $NODE /home/abacus/eng2 b$blkno,con,ra[$w.new.e1 get]
destroy $w.new }
bind $w.new { BashNet $NODE /home/abacus/eng2 b$blkno,con,ra[$w.new.e1 get]
destroy $w.new }
}
proc set_output { blk pcent } {
global NODE
# puts stdout "blk $blk pcent $pcent"
BashNet $NODE /home/abacus/eng2 \'b$blk,con,ra$pcent,sp$pcent\'
}
proc entry_stuff_multi_ut { blk_acb blk_sp blk_hl blk_ll blk_ar blk_st blk_ut } {
global NODE
global w blkno out_val
global str_ blk_acb_ blk_sp_ blk_hl_ blk_ll_ blk_ar_ blk_st_ mm blk_ut_ ma
set blk_acb_ $blk_acb
set blk_sp_ $blk_sp
set blk_hl_ $blk_hl
set blk_ll_ $blk_ll
set blk_ar_ $blk_ar
set blk_st_ $blk_st
set blk_ut_ $blk_ut
set eng4_pipe_multi [socket $NODE 9000]
fconfigure $eng4_pipe_multi -buffering line
puts $eng4_pipe_multi "/home/abacus/eng4 "
puts $eng4_pipe_multi "si$blk_acb"
catch { set str_ [gets $eng4_pipe_multi] }
catch { destroy $w.new } ; toplevel $w.new
wm title $w.new "CHANGE $str_"
wm geometry $w.new +50+50
#
after 50 { wm geometry $w.new +[winfo pointerx .]+[winfo pointery .] }
update idletasks
#grab -global $w.new
label $w.new.label -text $str_
label $w.new.spl -text "SETPOINT "
label $w.new.hll -text "HIGH ALARM"
label $w.new.lll -text "LOW ALARM"
label $w.new.utl -text " OUTPUT "
puts $eng4_pipe_multi ra$blk_sp ; gets $eng4_pipe_multi
puts $eng4_pipe_multi hl$blk_hl ; gets $eng4_pipe_multi
puts $eng4_pipe_multi ll$blk_ll ; gets $eng4_pipe_multi
puts $eng4_pipe_multi ra$blk_ut ; gets $eng4_pipe_multi
puts $eng4_pipe_multi ra$blk_sp ; entry $w.new.spe ; catch {$w.new.spe insert end [format "%g" [ gets $eng4_pipe_multi ]]}
puts $eng4_pipe_multi hl$blk_hl ; entry $w.new.hle ; catch {$w.new.hle insert end [format "%g" [ gets $eng4_pipe_multi ]]}
puts $eng4_pipe_multi ll$blk_ll ; entry $w.new.lle ; catch {$w.new.lle insert end [format "%g" [ gets $eng4_pipe_multi ]]}
scale $w.new.ute -orient horizontal -length 200 -from 0 -to 100 \
-tickinterval 20 -command "set_output $blk_ut " ;
set out_val 50
puts $eng4_pipe_multi ra$blk_ut ; set out_val [ gets $eng4_pipe_multi ]
$w.new.ute set $out_val
button $w.new.spb -text [format "change SETPOINT "]
button $w.new.hlb -text [format "change HIGH ALARM"]
button $w.new.llb -text [format "change LOW ALARM"]
label $w.new.aml -text "AUTO/HAND"
#set isauto [s2 $blk_acb_ ]
puts $eng4_pipe_multi s2$blk_acb_ ; set isauto [ gets $eng4_pipe_multi ]
label $w.new.isauto -text "$isauto"
puts $eng4_pipe_multi mm$blk_acb_ ; set mm [ gets $eng4_pipe_multi ]
puts $eng4_pipe_multi ma$blk_acb_ ; set ma [ gets $eng4_pipe_multi ]
button $w.new.rab -text [format "RAISE"]
button $w.new.lob -text [format "LOWER"]
$w.new.rab configure -command { BashNet $NODE /home/abacus/eng2 b$blk_ut_,con,sp5 }
$w.new.lob configure -command { BashNet $NODE /home/abacus/eng2 b$blk_ut_,con,sp-5 }
button $w.new.frab -text [format "FAST RAISE"]
button $w.new.flob -text [format "FAST LOWER"]
$w.new.frab configure -command { BashNet $NODE /home/abacus/eng2 b$blk_ut_,con,sp20 }
$w.new.flob configure -command { BashNet $NODE /home/abacus/eng2 b$blk_ut_,con,sp-20 }
$w.new.spb configure -command { BashNet $NODE /home/abacus/eng2 b$blk_sp_,con,ra[$w.new.spe get];destroy $w.new }
$w.new.hlb configure -command { BashNet $NODE /home/abacus/eng2 \'b$blk_hl_,con,hl[$w.new.hle get]\';destroy $w.new }
$w.new.llb configure -command { BashNet $NODE /home/abacus/eng2 \'b$blk_ll_,con,ll[$w.new.lle get]\';destroy $w.new }
button $w.new.ama -text "change to $ma" -command { BashNet $NODE /home/abacus/eng2 b$blk_ar_,con,ama ;destroy $w.new }
button $w.new.amm -text "change to $mm" -command { BashNet $NODE /home/abacus/eng2 b$blk_ar_,con,amm ;destroy $w.new }
button $w.new.amd -text "CLOSE" -command { destroy $w.new }
grid $w.new.label -row 0 -column 0 -rowspan 1 -columnspan 3 -sticky news
if { $blk_sp_ } {
grid $w.new.spl -row 1 -column 0 -rowspan 1 -columnspan 1 -sticky news
grid $w.new.spe -row 1 -column 1 -rowspan 1 -columnspan 1 -sticky news
grid $w.new.spb -row 1 -column 2 -rowspan 1 -columnspan 1 -sticky news
}
if { $blk_hl_ } {
grid $w.new.hll -row 2 -column 0 -rowspan 1 -columnspan 1 -sticky news
grid $w.new.hle -row 2 -column 1 -rowspan 1 -columnspan 1 -sticky news
grid $w.new.hlb -row 2 -column 2 -rowspan 1 -columnspan 1 -sticky news
}
if { $blk_ll_ } {
grid $w.new.lll -row 3 -column 0 -rowspan 1 -columnspan 1 -sticky news
grid $w.new.lle -row 3 -column 1 -rowspan 1 -columnspan 1 -sticky news
grid $w.new.llb -row 3 -column 2 -rowspan 1 -columnspan 1 -sticky news
}
if { $blk_ar_ } {
grid $w.new.aml -row 4 -column 0 -rowspan 1 -columnspan 1 -sticky news
grid $w.new.isauto -row 4 -column 1 -rowspan 1 -columnspan 1 -sticky news
if { [string trim $isauto] != [string trim $ma] } {
grid $w.new.ama -row 4 -column 2 -rowspan 1 -columnspan 1 -sticky news
} else {
grid $w.new.amm -row 4 -column 2 -rowspan 1 -columnspan 1 -sticky news
}
}
if { $blk_ut_ } {
if { $blk_ut_ > 6300 } { ;# analog output
grid $w.new.utl -row 5 -column 0 -rowspan 1 -columnspan 1 -sticky news
grid $w.new.ute -row 5 -column 1 -rowspan 1 -columnspan 2 -sticky news
#grid $w.new.utb -row 5 -column 2 -rowspan 1 -columnspan 1 -sticky news
}
if { $blk_ut_ < 6300 } { ;# PDO
grid $w.new.utl -row 5 -column 0 -rowspan 1 -columnspan 1 -sticky news
grid $w.new.lob -row 5 -column 1 -rowspan 1 -columnspan 1 -sticky news
grid $w.new.rab -row 5 -column 2 -rowspan 1 -columnspan 1 -sticky news
grid $w.new.flob -row 6 -column 1 -rowspan 1 -columnspan 1 -sticky news
grid $w.new.frab -row 6 -column 2 -rowspan 1 -columnspan 1 -sticky news
}
}
grid $w.new.amd -row 9 -column 2 -rowspan 1 -columnspan 1 -sticky news
catch { close $eng4_pipe_multi }
}
proc entry_stuff_multi { str blk_acb blk_sp blk_hl blk_ll blk_ar blk_st } {
global NODE
global w blkno
global str_ blk_acb_ blk_sp_ blk_hl_ blk_ll_ blk_ar_ blk_st_ mm ma
set blk_acb_ $blk_acb
set blk_sp_ $blk_sp
set blk_hl_ $blk_hl
set blk_ll_ $blk_ll
set blk_ar_ $blk_ar
set blk_st_ $blk_st
set eng4_pipe_multi [socket $NODE 9000]
fconfigure $eng4_pipe_multi -buffering line
puts $eng4_pipe_multi "/home/abacus/eng4 "
puts $eng4_pipe_multi "si$blk_acb"
catch { set str_ [gets $eng4_pipe_multi] }
# catch { set str_ $str }
after 50 { wm geometry $w.new +[winfo pointerx .]+[winfo pointery .] }
catch { destroy $w.new } ; toplevel $w.new
wm title $w.new "BYTA $str_"
wm geometry $w.new +50+50
#
update idletasks
#grab -global $w.new
label $w.new.label -text $str_
label $w.new.spl -text "SETPOINT "
label $w.new.hll -text "HIGH ALARM"
label $w.new.lll -text "LOW ALARM"
puts $eng4_pipe_multi ra$blk_sp ; catch { gets $eng4_pipe_multi }
puts $eng4_pipe_multi hl$blk_hl ; catch { gets $eng4_pipe_multi }
puts $eng4_pipe_multi ll$blk_ll ; catch { gets $eng4_pipe_multi }
puts $eng4_pipe_multi ra$blk_sp ; entry $w.new.spe ; catch {$w.new.spe insert end [format "%g" [ gets $eng4_pipe_multi ]]}
puts $eng4_pipe_multi hl$blk_hl ; entry $w.new.hle ; catch {$w.new.hle insert end [format "%g" [ gets $eng4_pipe_multi ]]}
puts $eng4_pipe_multi ll$blk_ll ; entry $w.new.lle ; catch {$w.new.lle insert end [format "%g" [ gets $eng4_pipe_multi ]]}
button $w.new.spb -text [format "change SETPOINT "]
button $w.new.hlb -text [format "change HIGH ALARM"]
button $w.new.llb -text [format "change LOW ALARM"]
$w.new.spb configure -command { BashNet $NODE /home/abacus/eng2 b$blk_sp_,con,ra[$w.new.spe get];destroy $w.new }
$w.new.hlb configure -command { BashNet $NODE /home/abacus/eng2 \'b$blk_hl_,con,hl[$w.new.hle get]\';destroy $w.new }
$w.new.llb configure -command { BashNet $NODE /home/abacus/eng2 \'b$blk_ll_,con,ll[$w.new.lle get]\';destroy $w.new }
label $w.new.aml -text "AUTO/HAND"
set isauto [s2 $blk_acb_ ] ; get_values ; set isauto [s2 $blk_acb_ ]
label $w.new.isauto -text "$isauto"
puts $eng4_pipe_multi mm$blk_acb_ ; set mm [ gets $eng4_pipe_multi ]
puts $eng4_pipe_multi ma$blk_acb_ ; set ma [ gets $eng4_pipe_multi ]
button $w.new.ama -text "change to $ma" -command { BashNet $NODE /home/abacus/eng2 b$blk_ar_,con,ama ;destroy $w.new }
button $w.new.amm -text "change to $mm" -command { BashNet $NODE /home/abacus/eng2 b$blk_ar_,con,amm ;destroy $w.new }
button $w.new.amd -text "CLOSE" -command { destroy $w.new }
grid $w.new.label -row 0 -column 0 -rowspan 1 -columnspan 3 -sticky news
if { $blk_sp_ } {
grid $w.new.spl -row 1 -column 0 -rowspan 1 -columnspan 1 -sticky news
grid $w.new.spe -row 1 -column 1 -rowspan 1 -columnspan 1 -sticky news
grid $w.new.spb -row 1 -column 2 -rowspan 1 -columnspan 1 -sticky news
}
if { $blk_hl_ } {
grid $w.new.hll -row 2 -column 0 -rowspan 1 -columnspan 1 -sticky news
grid $w.new.hle -row 2 -column 1 -rowspan 1 -columnspan 1 -sticky news
grid $w.new.hlb -row 2 -column 2 -rowspan 1 -columnspan 1 -sticky news
}
if { $blk_ll_ } {
grid $w.new.lll -row 3 -column 0 -rowspan 1 -columnspan 1 -sticky news
grid $w.new.lle -row 3 -column 1 -rowspan 1 -columnspan 1 -sticky news
grid $w.new.llb -row 3 -column 2 -rowspan 1 -columnspan 1 -sticky news
}
if { $blk_ar_ } {
grid $w.new.aml -row 4 -column 0 -rowspan 1 -columnspan 1 -sticky news
grid $w.new.isauto -row 4 -column 1 -rowspan 1 -columnspan 1 -sticky news
if { [string trim $isauto] != [string trim $ma] } {
grid $w.new.ama -row 4 -column 2 -rowspan 1 -columnspan 1 -sticky news
} else {
grid $w.new.amm -row 4 -column 2 -rowspan 1 -columnspan 1 -sticky news
}
}
grid $w.new.amd -row 5 -column 2 -rowspan 1 -columnspan 1 -sticky news
catch { close $eng4_pipe_multi }
}
################# Alarm blob proc ######################
proc blob3 { block name x1 y1 colour } {
global NODE
global w r2$name $name
global blob_data ra_data ra_block vn_data vn_block
set alarm 0
if { [info exists vn_block($block)] } then {
set alarm $vn_data($block)
} else {
set vn_block($block) 1
set vn_data($block) 1
}
set $name $alarm
if { [info exists r2$name] == 0} then {
catch { set r2$name [$w.p create oval $x1 $y1 \
[expr $x1 + 10] [expr $y1 + 10] \
-fill #E0E4E0 -width 1 ]}
}
set blob_name [eval set r2$name]
if { $alarm } { catch { $w.p itemconfigure $blob_name \
-fill $colour -width 1 }
} else { catch { $w.p itemconfigure $blob_name \
-fill #E0E4E0 -width 1 } }
update idletasks
}
proc sp { block } {
global NODE
global sp_data sp_block
set result ?
if { [info exists sp_block($block)] } then {
set result $sp_data($block)
}
set sp_block($block) 1
return $result
}
proc s1 { block } {
global NODE
global s1_data s1_block
set result ?
if { [info exists s1_block($block)] } then {
set result $s1_data($block)
}
set s1_block($block) 1
return $result
}
proc s2 { block } {
global NODE
global s2_data s2_block
set result ?
if { [info exists s2_block($block)] } then {
set result $s2_data($block)
}
set s2_block($block) 1
return $result
}
proc si { block } {
global NODE
global si_data si_block
set result "data kommer"
if { [info exists si_block($block)] } then {
set result $si_data($block)
}
set si_block($block) 1
return $result
}
proc un { block } {
global NODE
global un_data un_block
set result ?
if { [info exists un_block($block)] } then {
set result $un_data($block)
}
set un_block($block) 1
return $result
}
proc ra { block } {
global NODE
global ra_data ra_block
set result ?
if { [info exists ra_block($block)] } then {
set result $ra_data($block)
}
set ra_block($block) 1
return $result
}
proc de { block } {
global NODE
global de_data de_block
set result "data kommer"
if { [info exists de_block($block)] } then {
set result $de_data($block)
}
set de_block($block) 1
return $result
}
## proc de { block } {
## global NODE
## global de_data de_block
##
## set result "???"
## if { [info exists de_block($block)] } then {
## set result $de_data($block)
## }
## set de_block($block) 1
## return $result
##
## }
proc ac { block } {
global NODE
global ac_data ac_block
set result 0
if { [info exists ac_block($block)] } then {
set result $ac_data($block)
}
set ac_block($block) 1
return $result
}
proc ll { block } {
global NODE
global ll_data ll_block
set result 0
if { [info exists ll_block($block)] } then {
set result $ll_data($block)
}
set ll_block($block) 1
return $result
}
proc hl { block } {
global NODE
global hl_data hl_block
set result 0
if { [info exists hl_block($block)] } then {
set result $hl_data($block)
}
set hl_block($block) 1
return $result
}
proc am { block } {
global NODE
global am_data am_block
set result 0
if { [info exists am_block($block)] } then {
set result $am_data($block)
}
set am_block($block) 1
return $result
}
proc vn { block } {
global NODE
global vn_data vn_block
set result 0
if { [info exists vn_block($block)] } then {
set result $vn_data($block)
}
set vn_block($block) 1
return $result
}
proc bar_by_block { name block x1 y1 x2 height scale colour } {
global NODE
global w fulltime halftime blinkon
global $name
set valx [expr [ra $block] * $height / $scale ]
if { [expr $valx > ( $height + 5 )] || [expr $valx < -5 ] } then {
if { $blinkon } then {
set colour red
set valx $height
} else {
set colour yellow
set valx $height
}
}
if { $valx > $height } then { set valx $height }
if { $valx < 0 } then { set valx 0 }
if { [info exists $name ] } then {
$w.p coords $name $x1 $y1 $x2 [expr {$y1 - $valx} ]
} else {
set $name [$w.p create rectangle \
$x1 $y1 $x2 [expr {$y1 - $valx} ] \
-fill $colour -outline $colour -tags $name]
}
$w.p raise $name
}
proc bar_by_value { name value x1 y1 x2 height scale colour } {
global NODE
global w fulltime halftime blinkon
global bar
set valx [expr $value * $height / $scale ]
if { [expr $valx > ( $height + 2 )] || [expr $valx < -5 ] } then {
if { $blinkon } then {
set colour red
set valx $height
} else {
set colour yellow
set valx $height
}
}
if { $valx > $height } then { set valx $height }
if { $valx < 0 } then { set valx 0 }
if { [info exists bar($name) ] } then {
$w.p coords bar($name) $x1 $y1 $x2 [expr {$y1 - $valx} ]
} else {
set bar($name) [$w.p create rectangle \
$x1 $y1 $x2 [expr {$y1 - $valx} ] \
-fill $colour -outline $colour -tags bar($name)]
}
}
proc text_item_org { name x y format_ value_ } {
global NODE
global w lfont bg fg ti$name
catch {
if { [winfo exists $w.p.ti$name] == 0 } {
catch { button $w.p.ti$name -font $lfont -background $bg -foreground $fg \
-activebackground $bg -activeforeground $fg \
-pady 0 -padx 0 -relief raised -borderwidth 0 -highlightthickness 0 \
}
place $w.p.ti$name -x $x -y $y -anchor sw
}
$w.p.ti$name configure -text [format $format_ $value_]
}
}
proc clear_out {} {
global w
global blob_data ra_data ra_block vn_data vn_block am_data am_block
global ra3_pipe vn3_pipe sp3_pipe sp_data sp_block
global s13_pipe s23_pipe un3_pipe si3_pipe
global s1_block s2_block un_block si_block
global s1_data s2_data un_data si_data
foreach i [array names am_block] { unset am_data($i) ; unset am_block($i) }
foreach i [array names vn_block] { unset vn_data($i) ; unset vn_block($i) }
foreach i [array names ra_block] { unset ra_data($i) ; unset ra_block($i) }
foreach i [array names sp_block] { unset sp_data($i) ; unset sp_block($i) }
foreach i [array names s1_block] { unset s1_data($i) ; unset s1_block($i) }
foreach i [array names s2_block] { unset s2_data($i) ; unset s2_block($i) }
foreach i [array names si_block] { unset si_data($i) ; unset si_block($i) }
foreach i [array names un_block] { unset un_data($i) ; unset un_block($i) }
}
set bg yellow
proc text_item { name x y format_ value_ } {
global NODE
global w lfont bg fg ti$name
# puts stdout "text_item name=$name x=$x y=$y format_=$format_ value_=$value_ "
catch {
catch { button $w.p.ti$name -font $lfont -background $bg -foreground $fg \
-activebackground $bg -activeforeground $fg \
-pady 0 -padx 0 -relief raised -borderwidth 0 -highlightthickness 0 \
}
place $w.p.ti$name -x $x -y $y -anchor sw
}
$w.p.ti$name configure -text [format $format_ $value_]
}
proc state_text_2 { name x y value_ text_0 fg_0 bg_0 text_1 fg_1 bg_1 } {
global NODE
global w lfont bg fg ti$name
if { [winfo exists $w.p.ti$name] == 0 } {
catch { button $w.p.ti$name -font $lfont \
-activebackground $bg -activeforeground $fg \
-pady 0 -padx 3 -relief flat -borderwidth 0 \
}
place $w.p.ti$name -x $x -y $y
}
if { $value_ } {
$w.p.ti$name configure -background $bg_1 -foreground $fg_1 \
-activebackground $bg_1 -activeforeground $fg_1
$w.p.ti$name configure -text $text_1
} else {
$w.p.ti$name configure -background $bg_0 -foreground $fg_0\
-activebackground $bg_0 -activeforeground $fg_0
$w.p.ti$name configure -text $text_0
}
}
proc state_text_3 { name x y value_0 value_1 value_2 \
text_0 fg_0 bg_0 text_1 fg_1 bg_1 text_2 fg_2 bg_2 text_3 fg_3 bg_3 \
text_4 fg_4 bg_4 text_5 fg_5 bg_5 text_6 fg_6 bg_6 text_7 fg_7 bg_7 \
} {
global NODE
global w lfont bg fg ti$name
if { [winfo exists $w.p.ti$name] == 0 } {
catch { button $w.p.ti$name -font $lfont \
-activebackground $bg -activeforeground $fg \
-pady 0 -padx 3 -relief flat -borderwidth 0 \
}
place $w.p.ti$name -x $x -y $y -anchor sw
}
if { !$value_0 && !$value_1 && !$value_2 } {
$w.p.ti$name configure -background $bg_0 -foreground $fg_0 \
-activebackground $bg_0 -activeforeground $fg_0
$w.p.ti$name configure -text $text_0
} elseif { $value_0 && !$value_1 && !$value_2 } {
$w.p.ti$name configure -background $bg_1 -foreground $fg_1 \
-activebackground $bg_1 -activeforeground $fg_1
$w.p.ti$name configure -text $text_1
} elseif { !$value_0 && $value_1 && !$value_2 } {
$w.p.ti$name configure -background $bg_2 -foreground $fg_2 \
-activebackground $bg_2 -activeforeground $fg_2
$w.p.ti$name configure -text $text_2
} elseif { $value_0 && $value_1 && !$value_2 } {
$w.p.ti$name configure -background $bg_3 -foreground $fg_3 \
-activebackground $bg_3 -activeforeground $fg_3
$w.p.ti$name configure -text $text_3
}
if { !$value_0 && !$value_1 && $value_2 } {
$w.p.ti$name configure -background $bg_4 -foreground $fg_4 \
-activebackground $bg_4 -activeforeground $fg_4
$w.p.ti$name configure -text $text_4
} elseif { $value_0 && !$value_1 && $value_2 } {
$w.p.ti$name configure -background $bg_5 -foreground $fg_5 \
-activebackground $bg_5 -activeforeground $fg_5
$w.p.ti$name configure -text $text_5
} elseif { !$value_0 && $value_1 && $value_2 } {
$w.p.ti$name configure -background $bg_6 -foreground $fg_6 \
-activebackground $bg_6 -activeforeground $fg_6
$w.p.ti$name configure -text $text_6
} elseif { $value_0 && $value_1 && $value_2 } {
$w.p.ti$name configure -background $bg_7 -foreground $fg_7 \
-activebackground $bg_7 -activeforeground $fg_7
$w.p.ti$name configure -text $text_7
}
}
proc state_text_3_r { name x y value_0 \
text_0 fg_0 bg_0 text_1 fg_1 bg_1 text_2 fg_2 bg_2 text_3 fg_3 bg_3 \
text_4 fg_4 bg_4 text_5 fg_5 bg_5 text_6 fg_6 bg_6 text_7 fg_7 bg_7 \
} {
global NODE
global w lfont bg fg ti$name
if { [winfo exists $w.p.ti$name] == 0 } {
catch { button $w.p.ti$name -font $lfont \
-activebackground $bg -activeforeground $fg \
-pady 0 -padx 3 -relief flat -borderwidth 0 \
}
place $w.p.ti$name -x $x -y $y -anchor sw
}
switch -glob -- $value_0 {
0* { $w.p.ti$name configure -text "$text_0" -fg $fg_0 -bg $bg_0 -activeforeground $fg_0 -activebackground $bg_0}\
1* { $w.p.ti$name configure -text "$text_1" -fg $fg_1 -bg $bg_1 -activeforeground $fg_1 -activebackground $bg_1}\
2* { $w.p.ti$name configure -text "$text_2" -fg $fg_2 -bg $bg_2 -activeforeground $fg_2 -activebackground $bg_2}\
3* { $w.p.ti$name configure -text "$text_3" -fg $fg_3 -bg $bg_3 -activeforeground $fg_3 -activebackground $bg_3}\
4* { $w.p.ti$name configure -text "$text_4" -fg $fg_4 -bg $bg_4 -activeforeground $fg_4 -activebackground $bg_4}\
5* { $w.p.ti$name configure -text "$text_5" -fg $fg_5 -bg $bg_5 -activeforeground $fg_5 -activebackground $bg_5}\
6* { $w.p.ti$name configure -text "$text_6" -fg $fg_6 -bg $bg_6 -activeforeground $fg_6 -activebackground $bg_6}\
7* { $w.p.ti$name configure -text "$text_7" -fg $fg_7 -bg $bg_7 -activeforeground $fg_7 -activebackground $bg_7}\
default { $w.p.ti$name configure -text "??????" } }
}
proc shape_2 { name x y value_0 shape_0 shape_1 } {
global NODE
global w lfont bg fg ti$name
if { [winfo exists $w.p.ti$name] == 0 } {
catch { button $w.p.ti$name -font $lfont \
-background $bg -foreground $fg \
-activebackground $fg -activeforeground $bg \
-pady 0 -padx 0 -relief raised -borderwidth 0 -highlightthickness 0
}
## set cmd ""
## set cmd "$w.p.ti$name configure -command \{ entry_error \{ti$name\} \} \;"
## catch { puts stdout "shape_2: $cmd" }
## puts stdout "[catch { $cmd }]"
place $w.p.ti$name -x $x -y $y -anchor sw
}
if { !$value_0 } {
$w.p.ti$name configure -image $shape_0
} else {
$w.p.ti$name configure -image $shape_1
}
}
proc shape_2_flash { name x y value_0 shape_0 shape_1 } {
global NODE
global blinkon
global w lfont bg fg ti$name
if { [winfo exists $w.p.ti$name] == 0 } {
catch { button $w.p.ti$name -font $lfont \
-background $bg -foreground $fg \
-activebackground $fg -activeforeground $bg \
-pady 0 -padx 0 -relief raised -borderwidth 0 -highlightthickness 0 \
}
place $w.p.ti$name -x $x -y $y -anchor sw
}
if { !$value_0 && !$blinkon } {
$w.p.ti$name configure -image $shape_0
} elseif { $value_0 && !$blinkon } {
$w.p.ti$name configure -image $shape_1
} elseif { !$value_0 && $blinkon } {
$w.p.ti$name configure -image $shape_1
} elseif { $value_0 && $blinkon } {
$w.p.ti$name configure -image $shape_0
}
}
proc shape_4 { name x y value_0 value_1 shape_0 shape_1 shape_2 shape_3 } {
global NODE
global w lfont bg fg ti$name
if { [winfo exists $w.p.ti$name] == 0 } {
catch { button $w.p.ti$name -font $lfont \
-activebackground $bg -activeforeground $fg \
-pady 0 -padx 0 -relief raised -borderwidth 0 -highlightthickness 0 \
}
place $w.p.ti$name -x $x -y $y -anchor sw
}
if { !$value_0 && !$value_1 } {
$w.p.ti$name configure -image $shape_0
} elseif { $value_0 && !$value_1 } {
$w.p.ti$name configure -image $shape_1
} elseif { !$value_0 && $value_1 } {
$w.p.ti$name configure -image $shape_2
} elseif { $value_0 && $value_1 } {
$w.p.ti$name configure -image $shape_3
}
}
proc state_shape_3 { name x y value_0 value_1 value_2 \
shape_0 shape_1 shape_2 shape_3 \
shape_4 shape_5 shape_6 shape_7 \
} {
global NODE
global w lfont bg fg ti$name
if { [winfo exists $w.p.ti$name] == 0 } {
catch { button $w.p.ti$name -font $lfont \
-activebackground $bg -activeforeground $fg \
-pady 0 -padx 0 -relief raised -borderwidth 0 -highlightthickness 0 \
}
place $w.p.ti$name -x $x -y $y -anchor sw
}
if { !$value_0 && !$value_1 && !$value_2 } {
$w.p.ti$name configure -image $shape_0
} elseif { $value_0 && !$value_1 && !$value_2 } {
$w.p.ti$name configure -image $shape_1
} elseif { !$value_0 && $value_1 && !$value_2 } {
$w.p.ti$name configure -image $shape_2
} elseif { $value_0 && $value_1 && !$value_2 } {
$w.p.ti$name configure -image $shape_3
} elseif { !$value_0 && !$value_1 && $value_2 } {
$w.p.ti$name configure -image $shape_4
} elseif { $value_0 && !$value_1 && $value_2 } {
$w.p.ti$name configure -image $shape_5
} elseif { !$value_0 && $value_1 && $value_2 } {
$w.p.ti$name configure -image $shape_6
} elseif { $value_0 && $value_1 && $value_2 } {
$w.p.ti$name configure -image $shape_7
}
}
proc state_shape_3_r { name x y value_0 \
shape_0 shape_1 shape_2 shape_3 \
shape_4 shape_5 shape_6 shape_7 \
} {
global NODE
global w lfont bg fg ti$name
if { [winfo exists $w.p.ti$name] == 0 } {
catch { button $w.p.ti$name -font $lfont \
-activebackground $bg -activeforeground $fg \
-pady 0 -padx 0 -relief raised -borderwidth 0 -highlightthickness 0 \
}
place $w.p.ti$name -x $x -y $y -anchor sw
}
$w.p.ti$name configure -image question
switch -glob -- $value_0 {
0* { $w.p.ti$name configure -image $shape_0 }\
1* { $w.p.ti$name configure -image $shape_1 }\
2* { $w.p.ti$name configure -image $shape_2 }\
3* { $w.p.ti$name configure -image $shape_3 }\
4* { $w.p.ti$name configure -image $shape_4 }\
5* { $w.p.ti$name configure -image $shape_5 }\
6* { $w.p.ti$name configure -image $shape_6 }\
7* { $w.p.ti$name configure -image $shape_7 }\
default { $w.p.ti$name configure -image question } }
}
proc shape_update { name shape x y } {
global NODE
global w fulltime halftime blinkon
global pump_data blob_data ra_data ra_block vn_data vn_block
#catch { destroy $w.p.$name }
if [info exists pump_data($name)] {
if { $vn_data($trip) } then \
{
if { $blinkon } then {$w.p.$name configure -image pumpred -borderwidth 0
} else {$w.p.$name configure -image pumporg -borderwidth 0}
} else {
if { $vn_data($running) } then \
{ $w.p.$name configure -image pumpgreen -borderwidth 0
} else { $w.p.$name configure -image pumpyellow -borderwidth 0}
}
} else {
label $w.p.$name -image pumporg -borderwidth 0
place $w.p.$name -x $x -y $y
set pump_data($name) init
set vn_block($trip) 1
set vn_block($running) 1
set vn_data($trip) 0
set vn_data($running) 0
}
update idletasks
}
proc pump_update { pump trip running x y } {
global NODE
global w fulltime halftime blinkon
global pump_data blob_data ra_data ra_block vn_data vn_block
#catch { destroy $w.p.$pump }
if [info exists pump_data($pump)] {
if { $vn_data($trip) } then \
{
if { $blinkon } then {$w.p.$pump configure -image pumpred -borderwidth 0
} else {$w.p.$pump configure -image pumporg -borderwidth 0}
} else {
if { $vn_data($running) } then \
{ $w.p.$pump configure -image pumpgreen -borderwidth 0
} else { $w.p.$pump configure -image pumpyellow -borderwidth 0}
}
} else {
label $w.p.$pump -image pumporg -borderwidth 0
place $w.p.$pump -x $x -y $y
set pump_data($pump) init
set vn_block($trip) 1
set vn_block($running) 1
set vn_data($trip) 0
set vn_data($running) 0
}
update idletasks
}
proc omr_update { omr trip running x y } {
global NODE
global w fulltime halftime blinkon
global omr_data blob_data ra_data ra_block vn_data vn_block
#catch { destroy $w.p.$omr }
if [info exists omr_data($omr)] {
if { $vn_data($trip) } then \
{
$w.p.$omr configure -image omrred -borderwidth 0
} else {
if { $vn_data($running) } then \
{ $w.p.$omr configure -image omrgreen -borderwidth 0
} else { $w.p.$omr configure -image omryellow -borderwidth 0}
}
} else {
label $w.p.$omr -image omrorg -borderwidth 0
place $w.p.$omr -x $x -y $y
set omr_data($omr) init
set vn_block($trip) 1
set vn_block($running) 1
set vn_data($trip) 0
set vn_data($running) 0
}
update idletasks
}
set OLD_NODE "MaryHadALittleLamb"
set purge_1_0 1
proc get_values_org { } {
global NODE
global blob_data ra_data ra_block
global ac_data ac_block
global hl_data hl_block
global ll_data ll_block
global vn_data vn_block
global ra3_pipe eng4_pipe sp3_pipe sp_data sp_block
global s13_pipe s23_pipe un3_pipe si3_pipe
global s1_block s2_block un_block si_block
global s1_data s2_data un_data si_data
global OLD_NODE
if { $NODE != $OLD_NODE } {
if { [info exists eng4_pipe] } then {
catch { close $eng4_pipe }
unset eng4_pipe
}
}
set OLD_NODE $NODE
## if { [info exists eng4_pipe] } then {
##
## } else {
## set eng4_pipe [open "| hose $NODE 9000 -slave " {RDWR } ]
## fconfigure $eng4_pipe -buffering line
## puts $eng4_pipe /home/abacus/eng4
## }
if { [info exists eng4_pipe] } then {
} else {
set eng4_pipe [socket $NODE 9000]
fconfigure $eng4_pipe -buffering line
puts $eng4_pipe "/home/abacus/eng4 "
}
foreach i [array names ll_block] {
if { $ll_block($i) <= 2 } then {
puts $eng4_pipe ac$i
set ll_data($i) [ gets $eng4_pipe ]
incr ll_block($i) 1
} else { unset ll_block($i) ; unset ll_data($i) }
}
foreach i [array names hl_block] {
if { $hl_block($i) <= 2 } then {
puts $eng4_pipe ac$i
set hl_data($i) [ gets $eng4_pipe ]
incr hl_block($i) 1
} else { unset hl_block($i) ; unset hl_data($i) }
}
foreach i [array names ac_block] {
if { $ac_block($i) <= 2 } then {
puts $eng4_pipe ac$i
set ac_data($i) [ gets $eng4_pipe ]
incr ac_block($i) 1
} else { unset ac_block($i) ; unset ac_data($i) }
}
foreach i [array names vn_block] {
if { $vn_block($i) <= 2 } then {
puts $eng4_pipe vn$i
set vn_data($i) [ gets $eng4_pipe ]
incr vn_block($i) 1
} else { unset vn_block($i) ; unset vn_data($i) }
}
foreach i [array names ra_block] {
if { $ra_block($i) <= 2 } then {
puts $eng4_pipe ra$i
set ra_data($i) [ gets $eng4_pipe ]
incr ra_block($i) 1
} else { unset ra_block($i) ; unset ra_data($i) }
}
#; puts stdout "unset ra_($i)"
foreach i [array names sp_block] {
if { $sp_block($i) <= 2 } then {
puts $eng4_pipe sp$i
set sp_data($i) [ gets $eng4_pipe ]
incr sp_block($i) 1
} else { unset sp_block($i) ; unset sp_data($i) }
}
foreach i [array names s1_block] {
if { $s1_block($i) <= 2 } then {
puts $eng4_pipe s1$i
set s1_data($i) [ gets $eng4_pipe ]
incr s1_block($i) 1
} else { unset s1_block($i) ; unset s1_data($i) }
}
foreach i [array names s2_block] {
if { $s2_block($i) <= 2 } then {
puts $eng4_pipe s2$i
set s2_data($i) [ gets $eng4_pipe ]
incr s2_block($i) 1
} else { unset s2_block($i) ; unset s2_data($i) }
}
foreach i [array names si_block] {
if { $si_block($i) <= 2 } then {
puts $eng4_pipe si$i
set si_data($i) [ gets $eng4_pipe ]
incr si_block($i) 1
} else { unset si_block($i) ; unset si_data($i) }
}
foreach i [array names un_block] {
if { $un_block($i) <= 2 } then {
puts $eng4_pipe un$i
set un_data($i) [ gets $eng4_pipe ]
incr un_block($i) 1
} else { unset un_block($i) ; unset un_data($i) }
}
}
proc get_values { } {
global NODE
global blob_data ra_data ra_block
global de_data de_block
global ac_data ac_block
global hl_data hl_block
global ll_data ll_block
global am_data am_block
global vn_data vn_block
global ra3_pipe eng4_pipe eng4_pipe_de sp3_pipe sp_data sp_block
global s13_pipe s23_pipe un3_pipe si3_pipe
global s1_block s2_block un_block si_block
global s1_data s2_data un_data si_data
global OLD_NODE
global purge_1_0
if { $NODE != $OLD_NODE } {
if { [info exists eng4_pipe] } then {
catch { close $eng4_pipe }
unset eng4_pipe
}
}
set OLD_NODE $NODE
## if { [info exists eng4_pipe] } then {
##
## } else {
## set eng4_pipe [open "| hose $NODE 9000 -slave " {RDWR } ]
## fconfigure $eng4_pipe -buffering line
## puts $eng4_pipe /home/abacus/eng4
## }
if { [info exists eng4_pipe] } then {
} else {
set eng4_pipe [socket $NODE 9000]
######### fconfigure $eng4_pipe -buffering line
puts $eng4_pipe "/home/abacus/eng4 "
puts stdout "Opening \$eng4_pipe $eng4_pipe "
}
if { [info exists eng4_pipe_de] } then {
} else {
set eng4_pipe_de [socket $NODE 9000]
######### fconfigure $eng4_pipe_de -buffering line
puts $eng4_pipe_de "/home/abacus/eng4 "
}
foreach i [array names de_block] {
if { $de_block($i) <= 2 } then {
puts $eng4_pipe_de de$i } }
flush $eng4_pipe_de
foreach i [array names de_block] {
if { $de_block($i) <= 2 } then {
update idletasks
set de_data($i) [ gets $eng4_pipe_de ]
incr de_block($i) $purge_1_0
} else { unset de_block($i) ; unset de_data($i) }
}
## foreach i [array names de_block] {
## if { $de_block($i) <= 2 } then {
## puts $eng4_pipe de$i } }
## flush $eng4_pipe
## foreach i [array names de_block] {
## if { $de_block($i) <= 2 } then {
## update idletasks
## set de_data($i) [ gets $eng4_pipe ]
## incr de_block($i) $purge_1_0
## } else { unset de_block($i) ; unset de_data($i) }
## }
foreach i [array names ll_block] {
if { $ll_block($i) <= 2 } then {
puts $eng4_pipe ll$i } }
flush $eng4_pipe
foreach i [array names ll_block] {
if { $ll_block($i) <= 2 } then {
update idletasks
set ll_data($i) [ gets $eng4_pipe ]
incr ll_block($i) $purge_1_0
} else { unset ll_block($i) ; unset ll_data($i) }
}
foreach i [array names hl_block] {
if { $hl_block($i) <= 2 } then {
puts $eng4_pipe hl$i } }
flush $eng4_pipe
foreach i [array names hl_block] {
if { $hl_block($i) <= 2 } then {
update idletasks
set hl_data($i) [ gets $eng4_pipe ]
incr hl_block($i) $purge_1_0
} else { unset hl_block($i) ; unset hl_data($i) }
}
foreach i [array names ac_block] {
if { $ac_block($i) <= 2 } then {
puts $eng4_pipe ac$i } }
flush $eng4_pipe
foreach i [array names ac_block] {
if { $ac_block($i) <= 2 } then {
update idletasks
set ac_data($i) [ gets $eng4_pipe ]
incr ac_block($i) $purge_1_0
} else { unset ac_block($i) ; unset ac_data($i) }
}
foreach i [array names am_block] {
if { $am_block($i) <= 2 } then {
puts $eng4_pipe am$i } }
flush $eng4_pipe
foreach i [array names am_block] {
if { $am_block($i) <= 2 } then {
update idletasks
set am_data($i) [ gets $eng4_pipe ]
incr am_block($i) $purge_1_0
} else { unset am_block($i) ; unset am_data($i) }
}
foreach i [array names vn_block] {
if { $vn_block($i) <= 2 } then {
puts $eng4_pipe vn$i } }
flush $eng4_pipe
foreach i [array names vn_block] {
if { $vn_block($i) <= 2 } then {
update idletasks
set vn_data($i) [ gets $eng4_pipe ]
incr vn_block($i) $purge_1_0
} else { unset vn_block($i) ; unset vn_data($i) }
}
foreach i [array names ra_block] {
if { $ra_block($i) <= 2 } then {
puts $eng4_pipe ra$i } }
flush $eng4_pipe
foreach i [array names ra_block] {
if { $ra_block($i) <= 2 } then {
update idletasks
set ra_data($i) [ gets $eng4_pipe ]
incr ra_block($i) $purge_1_0
} else { unset ra_block($i) ; unset ra_data($i) }
}
#; puts stdout "unset ra_($i)"
foreach i [array names sp_block] {
if { $sp_block($i) <= 2 } then {
puts $eng4_pipe sp$i } }
flush $eng4_pipe
foreach i [array names sp_block] {
if { $sp_block($i) <= 2 } then {
update idletasks
set sp_data($i) [ gets $eng4_pipe ]
incr sp_block($i) $purge_1_0
} else { unset sp_block($i) ; unset sp_data($i) }
}
foreach i [array names s1_block] {
if { $s1_block($i) <= 2 } then {
puts $eng4_pipe s1$i } }
flush $eng4_pipe
foreach i [array names s1_block] {
if { $s1_block($i) <= 2 } then {
update idletasks
set s1_data($i) [ gets $eng4_pipe ]
incr s1_block($i) $purge_1_0
} else { unset s1_block($i) ; unset s1_data($i) }
}
foreach i [array names s2_block] {
if { $s2_block($i) <= 2 } then {
puts $eng4_pipe s2$i } }
flush $eng4_pipe
foreach i [array names s2_block] {
if { $s2_block($i) <= 2 } then {
update idletasks
set s2_data($i) [ gets $eng4_pipe ]
incr s2_block($i) $purge_1_0
} else { unset s2_block($i) ; unset s2_data($i) }
}
foreach i [array names si_block] {
if { $si_block($i) <= 2 } then {
puts $eng4_pipe si$i } }
flush $eng4_pipe
foreach i [array names si_block] {
if { $si_block($i) <= 2 } then {
update idletasks
set si_data($i) [ gets $eng4_pipe ]
incr si_block($i) $purge_1_0
} else { unset si_block($i) ; unset si_data($i) }
}
foreach i [array names un_block] {
if { $un_block($i) <= 2 } then {
puts $eng4_pipe un$i } }
flush $eng4_pipe
foreach i [array names un_block] {
if { $un_block($i) <= 2 } then {
update idletasks
set un_data($i) [ gets $eng4_pipe ]
incr un_block($i) $purge_1_0
} else { unset un_block($i) ; unset un_data($i) }
}
set purge_1_0 1
}
destroy $w.welcome
#source ./dp2.tcl
source ./mp1.tcl
set NODE inco sets the variable NODE to the value inco . This is the node name for the process control computer at Invercon.
############## GIF Files defined here ################
marks the start of the area which must be modified if a new picture is to be added.
Where the is a pattern to the file names a foreach construction has been used, as in the case for pump and other symbols. A line like
image create photo $blob -file /home/abacus/invercon/$blob.gif
must exist for each display background, and symbol. The name must be unique, and the gif file must exist, otherwise the program will fault.
Further down the file in the section starting
### Menu stuff defined here ###
the menus are defined.
$m add separator
$m add command -label "Data Page 1 " -command { change_to dp1 }
$m add command -label "Data Page 2 " -command { change_to dp2 }
$m add command -label "Data Page 3 " -command { change_to dp3 }
$m add separator
$m add command -label "Reel Report " -command { change_to reel }
$m add separator
The change_to procedure assumes that the page file to be sourced has the name /home/abacus/invercon/${the_page_}.tcl where ${the_page_} represents the argument to the procedure.
is the second mimic display. First this program must define the background to be used - this is done in the line
Pic copy Pic_mp2
Then buttons used to move to other displays follow
button $w.p.ti_hem -bitmap @/home/abacus/invercon/Fort-james.xbm \
-command { change_to mp1 }
place $w.p.ti_hem -x 0 -y 0
Notice that a bitmap is used, and that the command uses the change_to procedure.
The main updating procedure is called update0. It is here that all the dynamic points on the display are defined. It will be seen that the catch command is used for nearly every instruction. This is to ensure that the display continues even if there are programming errors, or if the called subroutines fail in any way.
After the update0 procedure comes the definitions of enterable points. When, from within update0 procedures like text_item are called they create, if one does not all ready exist, a new widget (in this case a button) with the name given as the first argument prefixed with $w.p.ti thus
catch { text_item b139 423 242 "%4.1f" [ra 139] }
creates $w.p.tib139. This can then be configured to allow operator entry
catch { $w.p.tib139 configure -command { entry_stuff_multi 8046 10046 8046 8046 15146 8046 6012 } } ;# P26
Here entry_stuff_multi will be called if the operator presses
on this item, thus allowing operator entry of setpoints etc. WARNING:
This block is subject to review, and possible retirement.
File Handling
This section of the ABACUS block language manual describes the disc block. This block allows data to be transmitted from the ABACUS database to and from data files, thus permitting recipes to be stored and retrieved.
Disc Block

The Disc Block controls the transfer of analogue and digital data between ABACUS blocks and data files in both directions.
In addition to the common parameters the disc block has the following
The data file's file name is [ABACUS.ABACUS]Bnnnnn.dat;1 where nnnnn is the integer part of the ra (with leading zeros) of the Disc Block.
The block reads from the file if aa = 0, otherwise it writes, creating a new file if one does not already exist. The previous contents of the data file are lost after a write operation.
All of the common parameters of the blocks specified by ds and dn i.e. tg, sn, ra, am, vn and ss, are either read from the file or written to it. ds defines the first block to be either read or written, and dn specifies the number of blocks.
Data dumping is discussed, as is logging in and out of the system.
ABACUS4 processes are listed with a short description of their function.
To start ABACUS manually, log in as abacus (initial password abacus) and enter the command abacus. You will be asked if you wish to stop and restart ABACUS, pressing enter with the yes field selected will first stop any running ABACUS processes, then after a short pause startup the ABACUS system.
To stop ABACUS manually, log in as abacus (initial password abacus) and enter the command kill.abacus.
On systems configured with the PI-Bus driver, and possibly others, you
may be asked for your password before ABACUS will start. This is because
the processes which access I/O ports on the PC must be run with root privileges.
This is the README.1ST file for abacus-4.9807 this first public version. Hello everyone, this is just a bit of information about ABACUS. ABACUS runs under Linux, the free Un*x operating system found on a large number of Internet servers around the world. The minimal hardware requirements are an IBM compatible 386 machine or better with at least 4 Mb RAM (preferably at least 8 Mb). A hard-disk with 30Mb has been used although >200Mb is required for the display system (X). On a network (Ethernet or even serial) a disk-less system should be possible, although this cannot be considered a secure arrangement. To install ABACUS 4 on your Intel based Linux machine you will need to consider the following. You need a user called abacus with his/her home at /home/abacus. He/She must have sudo rights (I put 'abacus ALL=ALL' at the end of /etc/sudoers, but you might want to work out something more sophisticated, let me know what you find works) As root you can install the package from the / directory with cd / tar -xzvf where_ever_it_is/abacus-4.version.tar.gz install/doinst.sh Or (if you are using Slackware) you can use the installpkg installpkg where_ever_it_is/abacus-4.version.tar.gz The ABACUS 4 manuals are in html format in the abacusmanual/ directory. To start the system log in as abacus, and start the command abacus. The file abacus is a bash shell, and is where the main configuration of which parts of abacus are started (i.e. which process I/O drivers, and which block scan processors) ABACUS 4 expects '.' to be in the PATH environment variable, other wise it won't find everything. Process I/O =========== Drivers exist is this version for pibus, indata and das08. The source for the das08 and a number of h files are stored in the src directory. It is expected that new drivers will appear in the not too distant future for MODBUS and COMLI protocols. These may however require modifications to the database structure (i.e. new block types). DISPLAYS ======== The displays are made using Tcl/tk. I've used version 8.0, some however will work with earlier versions. The tk_openfile type widgets have been used in the trend page, and 8.0 is required for that. LICENSING ========= ABACUS 4 is a commercial product and a license is required to run it. However it will run for an evaluation period of 24 hours before shutting down without a valid /home/abacus/abacus.computer.id.dat file. At the time of writing the pricing has not been fixed, so if you want to buy a license mail to abacusabacus@hotmail.com STARTUP ======= Here is a log of how it went when I started abacus frank(abacus):~$ abacus starting kill of abacus kill 8461: No such process kill_smem:mem_id 0, shmctl returned 0 Starting abacus Warning - id_check failed -1 The identity of your harddisk does not match that expected This ABACUS system will run in demonstration only The file /home/abacus/abacus.computer.id.dat contains a coded version of the identity of the disk for which this software is licensed. Please send the following information to the supplier of your ABACUS system, and arrange for a new /home/abacus/abacus.computer.id.dat file to be sent to you. MODEL="WDC AC31600H" FW_REV="23.16U23WDC AC31600H" SERIAL_NO="WD-WT2893535299" This information has been saved in /home/abacus/hard.disk.id.txt Abacus will start shortly in demonstration mode. It will require restarting after a period of 24 hours key = 0 shmget(key, TOTAL_SPACE , IPC_PRIVATE | IPC_CREAT ) errno = 0 mem_id = 134 Loading from datadump file ...Database load done system start 1, stop 20 pibus ai start 101, stop 420 i/p code start 801, stop 810 index start 1001, stop 1199 checklist start 2001, stop 2199 switch start 2501, stop 2699 pattern start 4001, stop 4199 sequencer start 9001, stop 9050 control start 5001, stop 5999 p.d.o. start 6001, stop 6080 analogue out start 6301, stop 6364 o/p code start 6501, stop 6550 alarm code start 8000, stop 8999 motor start 9501, stop 9699 dig input start 14001, stop 14320 dig output start 14501, stop 14820 disc start 17501, stop 17510 data link start 17901, stop 17910 scan control start 51, stop 65 p.i.d. start 7001, stop 7299 indata I/O start 18001, stop 18511 at: pluralization is wrong Job 68 will be executed using /bin/sh Subroutine start 7901, stop 7999 Date Owner Queue Job# 08:52:00 07/08/98 root c 62 10:10:00 07/08/98 root c 63 11:24:00 07/08/98 root c 64 11:28:00 07/08/98 root c 65 15:02:00 07/08/98 root c 68 Start journal program Start dcctsk ? Start X windows stuff Starting sxserv Starting blktsk ... Starting /home/abacus/dmptsk Starting /home/abacus/rep 1 Starting trendmem program /home/abacus/trendmem /home/abacus/trenddatafiles/trend.000.002.dat update datadump to be done every 300s approx /home/abacus/trendmem /home/abacus/trenddatafiles/trend.001.002.dat update /home/abacus/trendmem /home/abacus/trenddatafiles/trend.002.002.dat update /home/abacus/trendmem /home/abacus/trenddatafiles/trend.003.002.dat update /home/abacus/trendmem /home/abacus/trenddatafiles/trend.063.002.dat update /home/abacus/trendmem /home/abacus/trenddatafiles/trend.080.002.dat update /home/abacus/trendmem /home/abacus/trenddatafiles/trend.080.060.dat update Starting engdrawserver.sh If you get /home/abacus/faucet: Trying again . . . /home/abacus/faucet: Address 9000 in use, sleeping 10. /home/abacus/faucet: Trying again . . . /home/abacus/faucet: Address 9000 in use, sleeping 10. /home/abacus/faucet: Trying again . . . /home/abacus/faucet: Address 9000 in use, sleeping 10. then it means that there is still a faucet running in the system using address 9000. frank(abacus):~$ ps ax | grep fauc will find it, and then use kill -9 on it. Bugs, complaints, suggestions and complements to abacusabacus@hotmail.com please.
These blocks may be used to synchronise events with the system clock.
am is set by the dump command in engineers mode, the datadump
programme sets vn = v during the dump process. This only applies
if the dmptsk line in the startup shell script ABACUS was configured
with the -b 20 switch.
In addition to the common parameters the Scan Control Block has the following
Only blocks with number from f1 to l1 inclusive are processed.
The format of the text file /home/abacus/abacus.sys is as follows
20000 Max Block Number
1 20 system
0 0 PiBus ai
201 250 K48
401 410 N45
0 0 siox3
0 0
0 0 pulse counter
801 810 input code
..
The first line has the highest block number in the system. Each line after that has the first and then last of each successive block type. These are in the order as shown with the look command. Subsequent text is not used and only serves as commentary.
All blocks of a particular block type have contiguous block numbers. A block number cannot refer to two different blocks at the same time, and so first and last block ranges must not overlap. Since every block number from 1 up to the maximum block number is allocated the common parameters, and is designated a scratchpad if not of any defined block type, the higher the Max Block Number the more space consumed.
Unused block types are marked with first and last block numbers equal to zero.
To initiate a new block configuration the command /home/abacus/initsk i is used. This should olny be done on a system where ABACUS is NOT running.
After initialising the database initsk spawns engineers mode to load up the applications in file /home/abacus/abacus.eng. This file usually contains engineers mode commands to set up scan rate values etc.
The total size of the database may not exceed a predetermined amount. When INITSK initialises the database it prints the total size.
Datadump files are stored in binary format, and are a straight copy of the memory into the file. It is therefore impossible to convert directly from one shape of ABACUS system to another without using a 'symbolic' dunp. eng2 may be used to do this before you change the block configuration of a system. Something like
eng2 b1,xb999999,short,fp > /tmp/symbolic.dump
will create a file called /tmp/symbolic.dump with all the eng commands required to re-establish you database. Check with an editor that the file is complete, before you destroy your old system!
When you've got your new system up and running you might want to use something like
eng2 xb99,@/tmp/symbolic.dump
to resotre your data. (xb99 overides the requirement for connecting to each block's tag)
Data dumping
In order to preserve the applications programme the entire ABACUS database is saved periodically. This process may be automatic depending on the dmptsk line in /home/abacus/ABACUS.
. This section covers communications between ABACUS4 and other systems, and other ABACUS4 systems.
Each block which is intended for use as a MODBUS signal must have its nm setup with the following format
MODBUS <channel> <address> <R=register, or C=coil> <reg/coil reference> <IN/OUT>
Note that this software was developed against an ABB
controller (commander series) where <reg/coil reference> is one greater
than the 'offset address'.
Example: To send the ra of block 10002 to the 'Local Set
Point' register (42) of a Commander 100 controller whose address is 1 on
the modbus channel 1 the block should look like this...
This block may then be set to whatever value you want the controller to control to. Another block (10001 in this example) may be used to obtain the 'Process Variable Input' from the controller...Block 10002 () type scratchpad nn.b.name de.descr nm.name MODBUS 1 1 R 42 OUT tg.tag spare sn.scan 0(0.0 sec) ra.rslta 123.000 am.au/mn a vn.vltn v ss.sshot r en.A Entpr 0 dd.D Entpr 0
Not e that all numbers transferred are integer with ranges restricted by the modbus unit. Decimal point location for displays on controllers is possibly also accessible via MODBUS, see the handbook for the unit in question.Block 10001 () type scratchpad nn.b.name de.descr nm.name MODBUS 1 1 R 2 IN tg.tag spare sn.scan 0(0.0 sec) ra.rslta -18.000 am.au/mn a vn.vltn n ss.sshot r en.A Entpr 0 dd.D Entpr 0
where port is the special file name for the port (i.e. /dev/cua1) baudrate (9600 etc.) channel is the within ABACUS unique id. for just this MODBUS channel, and sys-block-number is the system block which will give running information about the link.modbus port baudrate channel sys-block-number
Here follows a trial run, using the above two blocks only. Note that the sys-block-number is left undefined, the default being 20+channel, i.e. 21 in this case.
The sys-block-number block is also updated with information in the de parameter. The value of ra is the number of cycles that the modbus program has executed.frank(abacus):~$ /home/abacus/modbus /dev/cua1 9600 1 stty sane ispeed 9600 < /dev/cua1 stty -ixon -ixoff -crtscts -parenb cs8 cstopb -echo raw ispeed 9600 < /dev/cua1 Starting cycle... MODBUS Block 10001 (n -18), chan 1, adr 1, creg R, cregnr 2, direction IN MODBUS Block 10002 (v 123), chan 1, adr 1, creg R, cregnr 42, direction OU Starting cycle... MODBUS Block 10001 (n -18), chan 1, adr 1, creg R, cregnr 2, direction IN MODBUS Block 10002 (v 123), chan 1, adr 1, creg R, cregnr 42, direction OU
For each channel a separate serial port is required, and a unique channel number. The /home/abacus/ABACUS file should include a line likefrank(abacus):~$ eng2 b21,p Block 21 () type scratchpad B21 () nn demodbus: Port /dev/cua1 at 9600 Baud, Channel 1. Found 2 blocks of interest nmmodbus: /dev/cua1 tg spare;sn 0(0.0 sec);ra 7.000 am m ;vn v ;ss r en 0;dd 0
The first argument to the modbus program is the special file for the serial port, the second argument is the baud rate, and the third is the channel number. The program prints a significant amount of diagnostic information which can be useful in the setting up phase, but is usually discarded by the ' > /dev/null 2>&1 ' in the above.$ABACUS_HOME/modbus /dev/cua1 9600 1 > /dev/null 2>&1 &
Any ABACUS4 block may be connected to any one signal reachable via a connected BSAP network. Which signal is defined in the nn parameter. The nm parameter is loaded (by the system) with a series of numbers representing the global address of the node, the MSD address of the signal, the MSD version number, and two status values obtained from the signal.
Data is transferred from the signal into the ABACUS4 block. In order to reduce the network load of continuously polling all the signals a count down timer is used on each block. This counter is stored in the en parameter, which can be seen to decrement. When either the value 0 has been reached the signal is read and the counter reset to 60.
If it is desired to prioritize one or more particular signals then set the am flag to a. This will have the effect of putting these signals at the top of the list of signals to be collected. For this reason it is not a good idea to use blocks other than scratchpads for BSAP signal collection.
In order to change a value at a remote signal the en parameter must be set to the magic value 777, and the result to the desired value. As confirmation that the new value has been sent to the BSAP node the value 999 is put into the en parameter.
The following shows some blocks with appropriate nn values and their generated nm values. The node name here is BIP1.
frank(abacus):~$ eng2 long,b10001,xb10019,.nn.nm.ra.en.am.vn Block 10001 (BIP1:#TIME.001.) type scratchpad Xblock 10019 type scratchpad b10001,nnBIP1:#TIME.001. ,nm0000 0968 B53A 0000 32 ,ra 65484.000,en 59,am m ,vn v b10002,nnBIP1:#TIME.002. ,nm0000 0971 B53A 0000 32 ,ra 1999.000,en 59,am m ,vn v b10003,nnBIP1:#TIME.003. ,nm0000 097A B53A 0000 32 ,ra 6.000,en 59,am m ,vn v b10004,nnBIP1:#TIME.004. ,nm0000 0983 B53A 0000 32 ,ra 28.000,en 59,am m ,vn v b10005,nnBIP1:#TIME.005. ,nm0000 098C B53A 0000 32 ,ra 18.000,en 59,am m ,vn v b10006,nnBIP1:#TIME.006. ,nm0000 0995 B53A 0000 32 ,ra 11.000,en 59,am m ,vn v b10007,nnBIP1:#TIME.007. ,nm0000 099E B53A 0000 32 ,ra 25.000,en 59,am m ,vn v b10008,nn ,nm ,ra 0.000,en 0,am m ,vn n b10009,nn ,nm ,ra 0.000,en 0,am m ,vn n b10010,nn ,nm ,ra 0.000,en 0,am m ,vn n b10011,nnBIP1:FTEST.001. ,nm0000 09A7 B53A 0000 02 ,ra 1105.000,en 59,am m ,vn v b10012,nnBIP1:FTEST.002. ,nm0000 0788 B53A 0000 00 ,ra 0.000,en 59,am m ,vn n b10013,nnBIP1:FTEST.003. ,nm0000 0A7E B53A F5F7 06 ,ra 1105.000,en 59,am m ,vn v b10014,nnBIP1:FTEST.LOLO. ,nm0000 09CA B53A 0000 02 ,ra 2.000,en 59,am m ,vn v b10015,nnBIP1:FTEST.LOW. ,nm0000 09D7 B53A 0000 02 ,ra 4.000,en 59,am m ,vn v b10016,nnBIP1:FTEST.HIGH. ,nm0000 09B0 B53A 0000 02 ,ra 95.000,en 59,am m ,vn v b10017,nnBIP1:FTEST.HIHI. ,nm0000 09BD B53A 0000 02 ,ra 99.000,en 59,am m ,vn v b10018,nn ,nm ,ra 0.000,en 0,am m ,vn n b10019,nn ,nm ,ra 0.000,en 0,am m ,vn n
Notice that this program executes one pass through the ABACUS database, and then exits. It is the responsibility of another script to repeatedly run bsap2. The standard script is called bsap-run.sh and looks something like this. It is here that you must edit so that the correct node name (in this example BIP1) and local address (1) are used.bsap2 [-a local_adr] [-p port] [-b baud-rate] [-L] [-1 startblock] [-2 stopblock] [-n node_gadr] -N node_string scans the blocks in the range startblock to stopblock to find nn's that match the node_string. Then tries to update the results of those blocks whose en == 1, decrementing all with en > 1 If -L is present the node will be interogated for signal names otherwise the msd adresses in the nm parameters will be used -a bsap local node address (default 0) -p port (default /dev/cua1) -b baud rate (default 9600) -1 first block (default 20000) -2 last block (default 39999) -s new_start (default 60) -n node global adr -N node_string
Attention should be made to the global address, which is a hex number (in this example 0 i.e. the local node). This can be obtained from the NETFILE.DOC file produced by the Bristol Babcock tools.#!/bin/sh # # This file runs the various bsap calls for tivoli and stations under # sudo chmod a+w /dev/cua0 # sudo chmod a+r /dev/cua0 export LOGFILE=/dev/null export LOGFILE=/home/abacus/tivoli/bsap-run.log stty 5:0:8bd:0:0:0:0:0:0:1:1:0:0:0:0:0:0:0:0:0:0:0:0 < /dev/cua1 echo " Detta program startar /home/abacus/bsap2 -1 10000 -2 10999 data hämntingprogrammet. This program starts /home/abacus/bsap2 data collection program." /home/abacus/bsap2 -1 10000 -2 10999 -a 1 -p /dev/cua1 -n 0 -N BIP1: -L >> $LOGFILE while sleep 0 do echo "Starting /home/abacus/bsap2 -1 10000 -2 10999 loop `date`" echo >> $LOGFILE echo /home/abacus/tivoli/bsap-run.sh `date` >> $LOGFILE echo /home/abacus/tivoli/bsap-run.sh Starting normal pass >> $LOGFILE echo >> $LOGFILE echo Ordinary pass on BIP1: >> $LOGFILE /home/abacus/bsap2 -1 10000 -2 10999 -w -a 1 -p /dev/cua1 -n 0 -N BIP1: >> $LOGFILE /home/abacus/bsap2 -1 10000 -2 10999 -w -a 1 -p /dev/cua1 -n 0 -N BIP1: >> $LOGFILE /home/abacus/bsap2 -1 10000 -2 10999 -w -a 1 -p /dev/cua1 -n 0 -N BIP1: >> $LOGFILE /home/abacus/bsap2 -1 10000 -2 10999 -w -a 1 -p /dev/cua1 -n 0 -N BIP1: >> $LOGFILE /home/abacus/bsap2 -1 10000 -2 10999 -w -a 1 -p /dev/cua1 -n 0 -N BIP1: >> $LOGFILE /home/abacus/bsap2 -1 10000 -2 10999 -a 1 -p /dev/cua1 -n 0 -N BIP1: -L >> $LOGFILE echo /home/abacus/tivoli/bsap-run.sh `date` >> $LOGFILE mv $LOGFILE $LOGFILE.tmp tail -1000 $LOGFILE.tmp > $LOGFILE rm $LOGFILE.tmp done
The -N argument specifies the search string used by the
program when it goes through all the ABACUS blocks to find suitable candidates
for communication. The normal syntax for BSAP signal names is of the form
XXXX:BASENAME.EXTNTN.ATTR where XXXX is the node name, the maximum length
of the remaining parts is 8.6.4.
In the Enterprise Server data base there are analog and logical signals. Each analog signal has a unique number know as its PTID (point ID), each logical also has a unique DIID (digital input ID). Each signal has a system unique name which usually is of the form XXXX:SIGNALNAME. For an ABACUS block to have its values sent to the Entprise system it must have a valid signal name in the nn parameter.
The following is an example of an analog input block...
In the case of all blocks excluding Alarm Code blocks, the system sets the en parameter to the corresponding PTID, and the dd parameter to the corresponding DIID number.frank(abacus):~$ eng2 b101,p Block 101 (UC71:F701..AI) type pibus ai B101 (UC71:F701..AI) nnUC71:F701..AI deFLODE INKOMMANDE GRUVVATTEN nmfms AI N:01 C:02 P:0 tg F701;sn 3(1.0 sec);ra -0.232 am a ;vn n ;ss r en 2101;dd 0 aa 91;rn 0;ds 2515513 rw 12864.000;sp 50.000;ze 0.000
Alarm Code Blocks (acb) may be associated with more than one Enterprise signal. If the acb is called, as in our example, UC71:A720.. then the following signals may also be present...
frank(abacus):~$ grep UC71:A720 analog.dat 2880 UC71:A720.. C 1 0 0 0 0 0.000 0.000 JARNHALTSMATARE - GRUVV. 2881 UC71:A720..HL C 0 0 0 0 0 0.000 0.000 JARNHALTSMATARE - GRUVV. HOG 2882 UC71:A720..LL C 0 0 0 0 0 0.000 0.000 JARNHALTSMATARE - GRUVV. LAG 2883 UC71:A720..XL C 0 0 0 0 0 0.000 0.000 JARNHALTSMATARE - GRUVV. INGET STROMNote that even XH is permitted, but not used in this case.
Alarms are generated by Entprise, which needs to be setup so that the base signal (console point) has the HL,LL XL etc as its alarm limits.
The status of the link program (entlnk4_client in ABACUS, usl:entlnk4_server running as ENTLNK4 in the Enterprise Server) can be seen in block 30. With heavily loaded Enterprise systems the server can have problems with the database, where is can no longer extract or insert data. This usually happens during start-up, and the observed number of PTIDs and DIIDs (shown in the en and dd parameters respectively) is less than the correct number. Blocks 28 and 29 are used to define minimum nos. of DIIDs and PTIDs respectively. If fewer than these are found, then the program exits and is restarted by the system.frank(abacus):~$ eng2 long,b8002,p Block 8002 (UC71:A720..) type alarm code Block 8002 (UC71:A720..) type alarm code nn.b.name UC71:A720.. de.descr JARNHALTSMATARE - GRUVV. nm.name NOT IN ALARM tg.tag A720 sn.scan 3(1.0 sec) ra.rslta -5.000 am.au/mn a vn.vltn n ss.sshot r en.A Entpr 0 dd.D Entpr 0 si.name aa.algra 1 hy.hyst 0.000 s1.status s2.status xl.limit -30.000 xh.limit 19.800 ll.limit -25.000 hl.limit 15.000 is.inputsp 0( 0.000 m-rn) ia.inputa 102(UC71:A720..AI -5.000 a+rv) st.status 0( 0.000 m-rn) ar.amreqst 0( 0.000 m-rn) un.unittx mo.ok tx ml.low tx mh.hi tx lx.xl tx hx.xh tx ma.autotx mm.handtx ur.areqtx hr.hreqtx dy.delay 0:00:30 Signal Value Monitor remote signal -+ alarm signal -+ | +- message suppr constant value -+| | |+- group suppr manual inhibit -+|| | ||+- unacknowledge control inhibit -+||| | |||+- in alarm alarm inhibit -+|||| | ||||++- alarm prio Signal Value questionable -+||||| | ||||||++- alm type ------------------------ --------- ---------------- |||||| | |||||||| -------- UC71:A720.. -5.000000 AV X L. A . U C 68010428 UC71:A720..HL 15.000000 AV X L. A . 68014000 UC71:A720..LL -25.00000 AV X L. A . 68014000 UC71:A720..XL -30.00000 AV X L. A . 68014000 ------------------------ --------- |||||||| | -------- -------- -------- updating -+||||||+- rbe +- logical value alarm change -+||||+- manual data value change -+||+- operator lock user change -++- aux change
In the above example the system has not yet found all the PTIDs and DIIDs corresponding to the names in the ABACUS data base.frank(abacus):~$ eng2 b28,xb30,fp Block 28 () type scratchpad Xblock 30 type scratchpad B28 () nn deentlnk4: minimum no of DIIDs nm tg entlnk4;sn 0(0.0 sec);ra 196.000 am m ;vn n ;ss r en 0;dd 0 B29 () nn deentlnk4: minimum no of PTIDs nm tg entlnk4;sn 0(0.0 sec);ra 355.000 am m ;vn n ;ss r en 0;dd 0 B30 () nn deentlnk4: Try and find all the ptid and diid numbers nm tg entlnk4;sn 0(0.0 sec);ra 0.000 am m ;vn n ;ss r en 326;dd 2
When used with the SMART-I/O subsystem, analog inputs may use the aa of 90 or 91. aa = 90 is for 0-20mA, and 91 is for 4-20mA. With these algorithms the sp corresponds to the desired ra for 20mA in and the ze corresponds to the desired ra for 0/4 mA input. The rw is the raw signal value from the SMART-I/O subsystem, in the range 0 - 65536. The ds parameter is used by the driver software to store the previous value of rw. If the difference between rw and ds is greater than 1024 the block is not updated, this prevent false readings causing undesirable effects.frank(abacus):~$ eng2 b101,p Block 101 (UC71:F701..AI) type pibus ai B101 (UC71:F701..AI) nnUC71:F701..AI deFLODE INKOMMANDE GRUVVATTEN nmfms AI N:01 C:02 P:0 tg F701;sn 3(1.0 sec);ra -0.232 am a ;vn n ;ss r en 2101;dd 0 aa 91;rn 0;ds 2515513 rw 12864.000;sp 50.000;ze 0.000
The nm parameter shows which point the block relates
to. In the above example N:01 refers to the first node, C:02 refers to
the card number 2, and P:0 is point 0. Points are numbered from 0 upwards,
as are slots. The nodes have a Profibus address which is shown after the
N:..
The nm parameter shows which point the block relates to. In the above example N:01 refers to the first node, C:05 refers to the card number 5, and P:0 is point 0. The nodes have a Profibus address which is shown after the N:..frank(abacus):~$ eng2 b6301,p Block 6301 (UC71:FV750.STYR.AO) type analogue out B6301 (UC71:FV750.STYR.AO) nnUC71:FV750.STYR.AO deREGLERVENTIL GRUVVATTEN nmfms AO N:01 C:05 P:0 tg FV750;sn 3(1.0 sec);ra 20.000 am a ;vn v ;ss r en 2134;dd 0 hl 40.000;ll 20.000;sp 20.000
WARNING: This block is not implemented yet in ABACUS4.
This section of the ABACUS block language manual describes the data link block. This block allows data to be transmitted from one ABACUS system to another via a variety of hardware including Ethernet and asynchronous ASCII.
Data Link Block

The Data Link Block controls the transfer of both analogue
and digital data between ABACUS systems, over Ethernet or asynchronous
ASCII links.